Snapshot 1c7e1e149d3dcf3949c76ae594ca9c1ca20392f9
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..8ab58e9
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,67 @@
+# Copyright (C) 2006 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+		libdex \
+		vm \
+		dalvikvm \
+		dexgen \
+		dexlist \
+		dexopt \
+		dexdump \
+		dvz \
+		dx \
+		libnativehelper \
+		tools \
+		unit-tests \
+	))
+
+include $(subdirs)
+
+
+.PHONY: dex dex-debug
+ifeq ($(DONT_INSTALL_DEX_FILES),true)
+dex:
+	@echo "Forcing a remake with DONT_INSTALL_DEX_FILES=false"
+	$(hide) $(MAKE) DONT_INSTALL_DEX_FILES=false
+else
+# DONT_INSTALL_DEX_FILES is already false, so a normal make takes care of it.
+dex: $(DEFAULT_GOAL)
+endif
+
+d :=
+ifneq ($(GENERATE_DEX_DEBUG),)
+d := debug
+endif
+ifneq ($(DONT_INSTALL_DEX_FILES),true)
+d := $(d)-install
+endif
+ifneq ($(d),debug-install)
+# generate the debug .dex files, with a copy in ./dalvik/DEBUG-FILES.
+# We need to rebuild the .dex files for the debug output to be generated.
+# The "touch -c $(DX)" is a hack that we know will force
+# a rebuild of the .dex files.  If $(DX) doesn't exist yet,
+# we won't touch it (-c) and the normal build will create
+# the .dex files naturally.
+dex-debug:
+	@echo "Forcing an app rebuild with GENERATE_DEX_DEBUG=true"
+	@touch -c $(DX)
+	$(hide) $(MAKE) DONT_INSTALL_DEX_FILES=false GENERATE_DEX_DEBUG=true
+else
+# GENERATE_DEX_DEBUG and DONT_INSTALL_DEX_FILES are already set properly,
+# so a normal make takes care of it.
+dex-debug: $(DEFAULT_GOAL)
+endif
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..3fbdc64
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,56 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+#$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..2969180
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,60 @@
+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
+---------------------------------------------
+
+Much of the code under this directory originally came from the Apache
+Harmony project, and as such contains the standard Apache header
+comment. Some of the code was written originally for the Android
+project, and as such contains the standard Android header comment.
+Some files contain code from both projects. In these cases, the header
+comment is a combination of the other two, and the portions of the
+code from Harmony are identified as indicated in the comment.
+
+Here is the combined header comment:
+
+/*
+ * Copyright (C) <year> 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.
+ *
+ * ----------
+ *
+ * Portions of the code surrounded by "// BEGIN Harmony code" and
+ * "// END Harmony code" are copyrighted and licensed separately, as
+ * follows:
+ *
+ * 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.
+ */
+
+
+Native SH call bridge
+---------------------
+
+Native SH call bridge is written by
+Shin-ichiro KAWASAKI <shinichiro.kawasaki.mg@hitachi.com>
+and Contributed to Android by Hitachi, Ltd. and Renesas Solutions Corp.
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
new file mode 100644
index 0000000..734f6f5
--- /dev/null
+++ b/dalvikvm/Android.mk
@@ -0,0 +1,75 @@
+# 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.
+
+
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Common definitions.
+#
+
+dalvikvm_src_files := \
+    Main.cpp
+
+dalvikvm_c_includes := \
+    $(JNI_H_INCLUDE) \
+    dalvik/include
+
+
+#
+# Build for the target (device).
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(dalvikvm_src_files)
+LOCAL_C_INCLUDES := $(dalvikvm_c_includes)
+
+LOCAL_SHARED_LIBRARIES := \
+    libdvm \
+    libssl \
+    libz
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := dalvikvm
+
+include $(BUILD_EXECUTABLE)
+
+
+#
+# Build for the host.
+#
+
+ifeq ($(WITH_HOST_DALVIK),true)
+
+    include $(CLEAR_VARS)
+    LOCAL_SRC_FILES := $(dalvikvm_src_files)
+    LOCAL_C_INCLUDES := $(dalvikvm_c_includes)
+
+    ifeq ($(HOST_OS)-$(HOST_ARCH),darwin-x86)
+        # OS X comes with all these libraries, so there is no need
+        # to build any of them. Note: OpenSSL consists of libssl
+        # and libcrypto.
+        LOCAL_LDLIBS := -lffi -lssl -lcrypto -lz
+    else
+        LOCAL_LDLIBS += -ldl -lpthread
+        LOCAL_SHARED_LIBRARIES += libdvm libcrypto libicuuc libicui18n libssl
+    endif
+
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_MODULE := dalvikvm
+
+    include $(BUILD_HOST_EXECUTABLE)
+
+endif
diff --git a/dalvikvm/Main.cpp b/dalvikvm/Main.cpp
new file mode 100644
index 0000000..4aa6e20
--- /dev/null
+++ b/dalvikvm/Main.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+/*
+ * Command-line invocation of the Dalvik VM.
+ */
+#include "jni.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+
+
+/*
+ * We want failed write() calls to just return with an error.
+ */
+static void blockSigpipe()
+{
+    sigset_t mask;
+
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGPIPE);
+    if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
+        fprintf(stderr, "WARNING: SIGPIPE not blocked\n");
+}
+
+/*
+ * Create a String[] and populate it with the contents of argv.
+ */
+static jobjectArray createStringArray(JNIEnv* env, char* const argv[], int argc)
+{
+    jclass stringClass = NULL;
+    jobjectArray strArray = NULL;
+    jobjectArray result = NULL;
+    int i;
+
+    stringClass = env->FindClass("java/lang/String");
+    if (env->ExceptionCheck()) {
+        fprintf(stderr, "Got exception while finding class String\n");
+        goto bail;
+    }
+    assert(stringClass != NULL);
+    strArray = env->NewObjectArray(argc, stringClass, NULL);
+    if (env->ExceptionCheck()) {
+        fprintf(stderr, "Got exception while creating String array\n");
+        goto bail;
+    }
+    assert(strArray != NULL);
+
+    for (i = 0; i < argc; i++) {
+        jstring argStr;
+
+        argStr = env->NewStringUTF(argv[i]);
+        if (env->ExceptionCheck()) {
+            fprintf(stderr, "Got exception while allocating Strings\n");
+            goto bail;
+        }
+        assert(argStr != NULL);
+        env->SetObjectArrayElement(strArray, i, argStr);
+        env->DeleteLocalRef(argStr);
+    }
+
+    /* return the array, and ensure we don't delete the local ref to it */
+    result = strArray;
+    strArray = NULL;
+
+bail:
+    env->DeleteLocalRef(stringClass);
+    env->DeleteLocalRef(strArray);
+    return result;
+}
+
+/*
+ * Determine whether or not the specified method is public.
+ *
+ * Returns JNI_TRUE on success, JNI_FALSE on failure.
+ */
+static int methodIsPublic(JNIEnv* env, jclass clazz, jmethodID methodId)
+{
+    static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
+    jobject refMethod = NULL;
+    jclass methodClass = NULL;
+    jmethodID getModifiersId;
+    int modifiers;
+    int result = JNI_FALSE;
+
+    refMethod = env->ToReflectedMethod(clazz, methodId, JNI_FALSE);
+    if (refMethod == NULL) {
+        fprintf(stderr, "Dalvik VM unable to get reflected method\n");
+        goto bail;
+    }
+
+    /*
+     * We now have a Method instance.  We need to call
+     * its getModifiers() method.
+     */
+    methodClass = env->FindClass("java/lang/reflect/Method");
+    if (methodClass == NULL) {
+        fprintf(stderr, "Dalvik VM unable to find class Method\n");
+        goto bail;
+    }
+    getModifiersId = env->GetMethodID(methodClass,
+                        "getModifiers", "()I");
+    if (getModifiersId == NULL) {
+        fprintf(stderr, "Dalvik VM unable to find reflect.Method.getModifiers\n");
+        goto bail;
+    }
+
+    modifiers = env->CallIntMethod(refMethod, getModifiersId);
+    if ((modifiers & PUBLIC) == 0) {
+        fprintf(stderr, "Dalvik VM: main() is not public\n");
+        goto bail;
+    }
+
+    result = JNI_TRUE;
+
+bail:
+    env->DeleteLocalRef(refMethod);
+    env->DeleteLocalRef(methodClass);
+    return result;
+}
+
+/*
+ * Parse arguments.  Most of it just gets passed through to the VM.  The
+ * JNI spec defines a handful of standard arguments.
+ */
+int main(int argc, char* const argv[])
+{
+    JavaVM* vm = NULL;
+    JNIEnv* env = NULL;
+    JavaVMInitArgs initArgs;
+    JavaVMOption* options = NULL;
+    char* slashClass = NULL;
+    int optionCount, curOpt, i, argIdx;
+    int needExtra = JNI_FALSE;
+    int result = 1;
+
+    setvbuf(stdout, NULL, _IONBF, 0);
+
+    /* ignore argv[0] */
+    argv++;
+    argc--;
+
+    /*
+     * If we're adding any additional stuff, e.g. function hook specifiers,
+     * add them to the count here.
+     *
+     * We're over-allocating, because this includes the options to the VM
+     * plus the options to the program.
+     */
+    optionCount = argc;
+
+    options = (JavaVMOption*) malloc(sizeof(JavaVMOption) * optionCount);
+    memset(options, 0, sizeof(JavaVMOption) * optionCount);
+
+    /*
+     * Copy options over.  Everything up to the name of the class starts
+     * with a '-' (the function hook stuff is strictly internal).
+     *
+     * [Do we need to catch & handle "-jar" here?]
+     */
+    for (curOpt = argIdx = 0; argIdx < argc; argIdx++) {
+        if (argv[argIdx][0] != '-' && !needExtra)
+            break;
+        options[curOpt++].optionString = strdup(argv[argIdx]);
+
+        /* some options require an additional arg */
+        needExtra = JNI_FALSE;
+        if (strcmp(argv[argIdx], "-classpath") == 0 ||
+            strcmp(argv[argIdx], "-cp") == 0)
+            /* others? */
+        {
+            needExtra = JNI_TRUE;
+        }
+    }
+
+    if (needExtra) {
+        fprintf(stderr, "Dalvik VM requires value after last option flag\n");
+        goto bail;
+    }
+
+    /* insert additional internal options here */
+
+    assert(curOpt <= optionCount);
+
+    initArgs.version = JNI_VERSION_1_4;
+    initArgs.options = options;
+    initArgs.nOptions = curOpt;
+    initArgs.ignoreUnrecognized = JNI_FALSE;
+
+    //printf("nOptions = %d\n", initArgs.nOptions);
+
+    blockSigpipe();
+
+    /*
+     * Start VM.  The current thread becomes the main thread of the VM.
+     */
+    if (JNI_CreateJavaVM(&vm, &env, &initArgs) < 0) {
+        fprintf(stderr, "Dalvik VM init failed (check log file)\n");
+        goto bail;
+    }
+
+    /*
+     * Make sure they provided a class name.  We do this after VM init
+     * so that things like "-Xrunjdwp:help" have the opportunity to emit
+     * a usage statement.
+     */
+    if (argIdx == argc) {
+        fprintf(stderr, "Dalvik VM requires a class name\n");
+        goto bail;
+    }
+
+    /*
+     * We want to call main() with a String array with our arguments in it.
+     * Create an array and populate it.  Note argv[0] is not included.
+     */
+    jobjectArray strArray;
+    strArray = createStringArray(env, &argv[argIdx+1], argc-argIdx-1);
+    if (strArray == NULL)
+        goto bail;
+
+    /*
+     * Find [class].main(String[]).
+     */
+    jclass startClass;
+    jmethodID startMeth;
+    char* cp;
+
+    /* convert "com.android.Blah" to "com/android/Blah" */
+    slashClass = strdup(argv[argIdx]);
+    for (cp = slashClass; *cp != '\0'; cp++)
+        if (*cp == '.')
+            *cp = '/';
+
+    startClass = env->FindClass(slashClass);
+    if (startClass == NULL) {
+        fprintf(stderr, "Dalvik VM unable to locate class '%s'\n", slashClass);
+        goto bail;
+    }
+
+    startMeth = env->GetStaticMethodID(startClass,
+                    "main", "([Ljava/lang/String;)V");
+    if (startMeth == NULL) {
+        fprintf(stderr, "Dalvik VM unable to find static main(String[]) in '%s'\n",
+            slashClass);
+        goto bail;
+    }
+
+    /*
+     * Make sure the method is public.  JNI doesn't prevent us from calling
+     * a private method, so we have to check it explicitly.
+     */
+    if (!methodIsPublic(env, startClass, startMeth))
+        goto bail;
+
+    /*
+     * Invoke main().
+     */
+    env->CallStaticVoidMethod(startClass, startMeth, strArray);
+
+    if (!env->ExceptionCheck())
+        result = 0;
+
+bail:
+    /*printf("Shutting down Dalvik VM\n");*/
+    if (vm != NULL) {
+        /*
+         * This allows join() and isAlive() on the main thread to work
+         * correctly, and also provides uncaught exception handling.
+         */
+        if (vm->DetachCurrentThread() != JNI_OK) {
+            fprintf(stderr, "Warning: unable to detach main thread\n");
+            result = 1;
+        }
+
+        if (vm->DestroyJavaVM() != 0)
+            fprintf(stderr, "Warning: Dalvik VM did not shut down cleanly\n");
+        /*printf("\nDalvik VM has exited\n");*/
+    }
+
+    for (i = 0; i < optionCount; i++)
+        free((char*) options[i].optionString);
+    free(options);
+    free(slashClass);
+    /*printf("--- VM is down, process exiting\n");*/
+    return result;
+}
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
new file mode 100644
index 0000000..7c22b60
--- /dev/null
+++ b/dexdump/Android.mk
@@ -0,0 +1,80 @@
+# 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.
+
+#
+# dexdump, similar in purpose to objdump.
+#
+LOCAL_PATH:= $(call my-dir)
+
+dexdump_src_files := \
+		DexDump.cpp
+
+dexdump_c_includes := \
+		dalvik \
+		$(JNI_H_INCLUDE)
+
+dexdump_shared_libraries :=
+
+dexdump_static_libraries := \
+		libdex
+
+##
+##
+## Build the device command line tool dexdump
+##
+##
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexdump
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries) libz liblog
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries)
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_LDLIBS +=
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdexdump_static
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries)
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_STATIC_LIBRARY)
+
+endif # !SDK_ONLY
+
+
+##
+##
+## Build the host command line tool dexdump
+##
+##
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexdump
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries)
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) liblog
+
+ifneq ($(strip $(USE_MINGW)),)
+LOCAL_STATIC_LIBRARIES += libz
+else
+LOCAL_LDLIBS += -lpthread -lz
+endif
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
new file mode 100644
index 0000000..59f149b
--- /dev/null
+++ b/dexdump/DexDump.cpp
@@ -0,0 +1,1916 @@
+/*
+ * 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 "dexdump" tool is intended to mimic "objdump".  When possible, use
+ * similar command-line arguments.
+ *
+ * TODO: rework the "plain" output format to be more regexp-friendly
+ *
+ * Differences between XML output and the "current.xml" file:
+ * - classes in same package are not all grouped together; generally speaking
+ *   nothing is sorted
+ * - no "deprecated" on fields and methods
+ * - no "value" on fields
+ * - no parameter names
+ * - no generic signatures on parameters, e.g. type="java.lang.Class&lt;?&gt;"
+ * - class shows declared fields and methods; does not show inherited fields
+ */
+
+#include "libdex/DexFile.h"
+
+#include "libdex/CmdUtils.h"
+#include "libdex/DexCatch.h"
+#include "libdex/DexClass.h"
+#include "libdex/DexDebugInfo.h"
+#include "libdex/DexOpcodes.h"
+#include "libdex/DexProto.h"
+#include "libdex/InstrUtils.h"
+#include "libdex/SysUtil.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+
+static const char* gProgName = "dexdump";
+
+enum OutputFormat {
+    OUTPUT_PLAIN = 0,               /* default */
+    OUTPUT_XML,                     /* fancy */
+};
+
+/* command-line options */
+struct Options {
+    bool checksumOnly;
+    bool disassemble;
+    bool showFileHeaders;
+    bool showSectionHeaders;
+    bool ignoreBadChecksum;
+    bool dumpRegisterMaps;
+    OutputFormat outputFormat;
+    const char* tempFileName;
+    bool exportsOnly;
+    bool verbose;
+};
+
+struct Options gOptions;
+
+/* basic info about a field or method */
+struct FieldMethodInfo {
+    const char* classDescriptor;
+    const char* name;
+    const char* signature;
+};
+
+/*
+ * Get 2 little-endian bytes.
+ */
+static inline u2 get2LE(unsigned char const* pSrc)
+{
+    return pSrc[0] | (pSrc[1] << 8);
+}
+
+/*
+ * 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.
+ */
+static const char* primitiveTypeLabel(char typeChar)
+{
+    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:
+                return "UNKNOWN";
+    }
+}
+
+/*
+ * Converts a type descriptor to human-readable "dotted" form.  For
+ * example, "Ljava/lang/String;" becomes "java.lang.String", and
+ * "[I" becomes "int[]".  Also converts '$' to '.', which means this
+ * form can't be converted back to a descriptor.
+ */
+static char* descriptorToDot(const char* str)
+{
+    int targetLen = strlen(str);
+    int offset = 0;
+    int arrayDepth = 0;
+    char* newStr;
+
+    /* strip leading [s; will be added to end */
+    while (targetLen > 1 && str[offset] == '[') {
+        offset++;
+        targetLen--;
+    }
+    arrayDepth = offset;
+
+    if (targetLen == 1) {
+        /* primitive type */
+        str = primitiveTypeLabel(str[offset]);
+        offset = 0;
+        targetLen = strlen(str);
+    } else {
+        /* account for leading 'L' and trailing ';' */
+        if (targetLen >= 2 && str[offset] == 'L' &&
+            str[offset+targetLen-1] == ';')
+        {
+            targetLen -= 2;
+            offset++;
+        }
+    }
+
+    newStr = (char*)malloc(targetLen + arrayDepth * 2 +1);
+
+    /* copy class name over */
+    int i;
+    for (i = 0; i < targetLen; i++) {
+        char ch = str[offset + i];
+        newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
+    }
+
+    /* add the appropriate number of brackets for arrays */
+    while (arrayDepth-- > 0) {
+        newStr[i++] = '[';
+        newStr[i++] = ']';
+    }
+    newStr[i] = '\0';
+    assert(i == targetLen + arrayDepth * 2);
+
+    return newStr;
+}
+
+/*
+ * Converts the class name portion of a type descriptor to human-readable
+ * "dotted" form.
+ *
+ * Returns a newly-allocated string.
+ */
+static char* descriptorClassToDot(const char* str)
+{
+    const char* lastSlash;
+    char* newStr;
+    char* cp;
+
+    /* reduce to just the class name, trimming trailing ';' */
+    lastSlash = strrchr(str, '/');
+    if (lastSlash == NULL)
+        lastSlash = str + 1;        /* start past 'L' */
+    else
+        lastSlash++;                /* start past '/' */
+
+    newStr = strdup(lastSlash);
+    newStr[strlen(lastSlash)-1] = '\0';
+    for (cp = newStr; *cp != '\0'; cp++) {
+        if (*cp == '$')
+            *cp = '.';
+    }
+
+    return newStr;
+}
+
+/*
+ * Returns a quoted string representing the boolean value.
+ */
+static const char* quotedBool(bool val)
+{
+    if (val)
+        return "\"true\"";
+    else
+        return "\"false\"";
+}
+
+static const char* quotedVisibility(u4 accessFlags)
+{
+    if ((accessFlags & ACC_PUBLIC) != 0)
+        return "\"public\"";
+    else if ((accessFlags & ACC_PROTECTED) != 0)
+        return "\"protected\"";
+    else if ((accessFlags & ACC_PRIVATE) != 0)
+        return "\"private\"";
+    else
+        return "\"package\"";
+}
+
+/*
+ * Count the number of '1' bits in a word.
+ */
+static int countOnes(u4 val)
+{
+    int count = 0;
+
+    val = val - ((val >> 1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+    count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+
+    return count;
+}
+
+/*
+ * Flag for use with createAccessFlagStr().
+ */
+enum AccessFor {
+    kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
+    kAccessForMAX
+};
+
+/*
+ * Create a new string with human-readable access flags.
+ *
+ * In the base language the access_flags fields are type u2; in Dalvik
+ * they're u4.
+ */
+static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
+{
+#define NUM_FLAGS   18
+    static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
+        {
+            /* class, inner class */
+            "PUBLIC",           /* 0x0001 */
+            "PRIVATE",          /* 0x0002 */
+            "PROTECTED",        /* 0x0004 */
+            "STATIC",           /* 0x0008 */
+            "FINAL",            /* 0x0010 */
+            "?",                /* 0x0020 */
+            "?",                /* 0x0040 */
+            "?",                /* 0x0080 */
+            "?",                /* 0x0100 */
+            "INTERFACE",        /* 0x0200 */
+            "ABSTRACT",         /* 0x0400 */
+            "?",                /* 0x0800 */
+            "SYNTHETIC",        /* 0x1000 */
+            "ANNOTATION",       /* 0x2000 */
+            "ENUM",             /* 0x4000 */
+            "?",                /* 0x8000 */
+            "VERIFIED",         /* 0x10000 */
+            "OPTIMIZED",        /* 0x20000 */
+        },
+        {
+            /* method */
+            "PUBLIC",           /* 0x0001 */
+            "PRIVATE",          /* 0x0002 */
+            "PROTECTED",        /* 0x0004 */
+            "STATIC",           /* 0x0008 */
+            "FINAL",            /* 0x0010 */
+            "SYNCHRONIZED",     /* 0x0020 */
+            "BRIDGE",           /* 0x0040 */
+            "VARARGS",          /* 0x0080 */
+            "NATIVE",           /* 0x0100 */
+            "?",                /* 0x0200 */
+            "ABSTRACT",         /* 0x0400 */
+            "STRICT",           /* 0x0800 */
+            "SYNTHETIC",        /* 0x1000 */
+            "?",                /* 0x2000 */
+            "?",                /* 0x4000 */
+            "MIRANDA",          /* 0x8000 */
+            "CONSTRUCTOR",      /* 0x10000 */
+            "DECLARED_SYNCHRONIZED", /* 0x20000 */
+        },
+        {
+            /* field */
+            "PUBLIC",           /* 0x0001 */
+            "PRIVATE",          /* 0x0002 */
+            "PROTECTED",        /* 0x0004 */
+            "STATIC",           /* 0x0008 */
+            "FINAL",            /* 0x0010 */
+            "?",                /* 0x0020 */
+            "VOLATILE",         /* 0x0040 */
+            "TRANSIENT",        /* 0x0080 */
+            "?",                /* 0x0100 */
+            "?",                /* 0x0200 */
+            "?",                /* 0x0400 */
+            "?",                /* 0x0800 */
+            "SYNTHETIC",        /* 0x1000 */
+            "?",                /* 0x2000 */
+            "ENUM",             /* 0x4000 */
+            "?",                /* 0x8000 */
+            "?",                /* 0x10000 */
+            "?",                /* 0x20000 */
+        },
+    };
+    const int kLongest = 21;        /* strlen of longest string above */
+    int i, count;
+    char* str;
+    char* cp;
+
+    /*
+     * Allocate enough storage to hold the expected number of strings,
+     * plus a space between each.  We over-allocate, using the longest
+     * string above as the base metric.
+     */
+    count = countOnes(flags);
+    cp = str = (char*) malloc(count * (kLongest+1) +1);
+
+    for (i = 0; i < NUM_FLAGS; i++) {
+        if (flags & 0x01) {
+            const char* accessStr = kAccessStrings[forWhat][i];
+            int len = strlen(accessStr);
+            if (cp != str)
+                *cp++ = ' ';
+
+            memcpy(cp, accessStr, len);
+            cp += len;
+        }
+        flags >>= 1;
+    }
+    *cp = '\0';
+
+    return str;
+}
+
+
+/*
+ * Copy character data from "data" to "out", converting non-ASCII values
+ * to printf format chars or an ASCII filler ('.' or '?').
+ *
+ * The output buffer must be able to hold (2*len)+1 bytes.  The result is
+ * NUL-terminated.
+ */
+static void asciify(char* out, const unsigned char* data, size_t len)
+{
+    while (len--) {
+        if (*data < 0x20) {
+            /* could do more here, but we don't need them yet */
+            switch (*data) {
+            case '\0':
+                *out++ = '\\';
+                *out++ = '0';
+                break;
+            case '\n':
+                *out++ = '\\';
+                *out++ = 'n';
+                break;
+            default:
+                *out++ = '.';
+                break;
+            }
+        } else if (*data >= 0x80) {
+            *out++ = '?';
+        } else {
+            *out++ = *data;
+        }
+        data++;
+    }
+    *out = '\0';
+}
+
+/*
+ * Dump the file header.
+ */
+void dumpFileHeader(const DexFile* pDexFile)
+{
+    const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+    const DexHeader* pHeader = pDexFile->pHeader;
+    char sanitized[sizeof(pHeader->magic)*2 +1];
+
+    assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
+
+    if (pOptHeader != NULL) {
+        printf("Optimized DEX file header:\n");
+
+        asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
+        printf("magic               : '%s'\n", sanitized);
+        printf("dex_offset          : %d (0x%06x)\n",
+            pOptHeader->dexOffset, pOptHeader->dexOffset);
+        printf("dex_length          : %d\n", pOptHeader->dexLength);
+        printf("deps_offset         : %d (0x%06x)\n",
+            pOptHeader->depsOffset, pOptHeader->depsOffset);
+        printf("deps_length         : %d\n", pOptHeader->depsLength);
+        printf("opt_offset          : %d (0x%06x)\n",
+            pOptHeader->optOffset, pOptHeader->optOffset);
+        printf("opt_length          : %d\n", pOptHeader->optLength);
+        printf("flags               : %08x\n", pOptHeader->flags);
+        printf("checksum            : %08x\n", pOptHeader->checksum);
+        printf("\n");
+    }
+
+    printf("DEX file header:\n");
+    asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
+    printf("magic               : '%s'\n", sanitized);
+    printf("checksum            : %08x\n", pHeader->checksum);
+    printf("signature           : %02x%02x...%02x%02x\n",
+        pHeader->signature[0], pHeader->signature[1],
+        pHeader->signature[kSHA1DigestLen-2],
+        pHeader->signature[kSHA1DigestLen-1]);
+    printf("file_size           : %d\n", pHeader->fileSize);
+    printf("header_size         : %d\n", pHeader->headerSize);
+    printf("link_size           : %d\n", pHeader->linkSize);
+    printf("link_off            : %d (0x%06x)\n",
+        pHeader->linkOff, pHeader->linkOff);
+    printf("string_ids_size     : %d\n", pHeader->stringIdsSize);
+    printf("string_ids_off      : %d (0x%06x)\n",
+        pHeader->stringIdsOff, pHeader->stringIdsOff);
+    printf("type_ids_size       : %d\n", pHeader->typeIdsSize);
+    printf("type_ids_off        : %d (0x%06x)\n",
+        pHeader->typeIdsOff, pHeader->typeIdsOff);
+    printf("field_ids_size      : %d\n", pHeader->fieldIdsSize);
+    printf("field_ids_off       : %d (0x%06x)\n",
+        pHeader->fieldIdsOff, pHeader->fieldIdsOff);
+    printf("method_ids_size     : %d\n", pHeader->methodIdsSize);
+    printf("method_ids_off      : %d (0x%06x)\n",
+        pHeader->methodIdsOff, pHeader->methodIdsOff);
+    printf("class_defs_size     : %d\n", pHeader->classDefsSize);
+    printf("class_defs_off      : %d (0x%06x)\n",
+        pHeader->classDefsOff, pHeader->classDefsOff);
+    printf("data_size           : %d\n", pHeader->dataSize);
+    printf("data_off            : %d (0x%06x)\n",
+        pHeader->dataOff, pHeader->dataOff);
+    printf("\n");
+}
+
+/*
+ * Dump the "table of contents" for the opt area.
+ */
+void dumpOptDirectory(const DexFile* pDexFile)
+{
+    const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+    if (pOptHeader == NULL)
+        return;
+
+    printf("OPT section contents:\n");
+
+    const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
+
+    if (*pOpt == 0) {
+        printf("(1.0 format, only class lookup table is present)\n\n");
+        return;
+    }
+
+    /*
+     * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
+     * length, then the data.  Chunks start on 64-bit boundaries.
+     */
+    while (*pOpt != kDexChunkEnd) {
+        const char* verboseStr;
+
+        u4 size = *(pOpt+1);
+
+        switch (*pOpt) {
+        case kDexChunkClassLookup:
+            verboseStr = "class lookup hash table";
+            break;
+        case kDexChunkRegisterMaps:
+            verboseStr = "register maps";
+            break;
+        default:
+            verboseStr = "(unknown chunk type)";
+            break;
+        }
+
+        printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
+            *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
+            verboseStr, size);
+
+        size = (size + 8 + 7) & ~7;
+        pOpt += size / sizeof(u4);
+    }
+    printf("\n");
+}
+
+/*
+ * Dump a class_def_item.
+ */
+void dumpClassDef(DexFile* pDexFile, int idx)
+{
+    const DexClassDef* pClassDef;
+    const u1* pEncodedData;
+    DexClassData* pClassData;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        fprintf(stderr, "Trouble reading class data\n");
+        return;
+    }
+
+    printf("Class #%d header:\n", idx);
+    printf("class_idx           : %d\n", pClassDef->classIdx);
+    printf("access_flags        : %d (0x%04x)\n",
+        pClassDef->accessFlags, pClassDef->accessFlags);
+    printf("superclass_idx      : %d\n", pClassDef->superclassIdx);
+    printf("interfaces_off      : %d (0x%06x)\n",
+        pClassDef->interfacesOff, pClassDef->interfacesOff);
+    printf("source_file_idx     : %d\n", pClassDef->sourceFileIdx);
+    printf("annotations_off     : %d (0x%06x)\n",
+        pClassDef->annotationsOff, pClassDef->annotationsOff);
+    printf("class_data_off      : %d (0x%06x)\n",
+        pClassDef->classDataOff, pClassDef->classDataOff);
+    printf("static_fields_size  : %d\n", pClassData->header.staticFieldsSize);
+    printf("instance_fields_size: %d\n",
+            pClassData->header.instanceFieldsSize);
+    printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
+    printf("virtual_methods_size: %d\n",
+            pClassData->header.virtualMethodsSize);
+    printf("\n");
+
+    free(pClassData);
+}
+
+/*
+ * Dump an interface that a class declares to implement.
+ */
+void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
+    int i)
+{
+    const char* interfaceName =
+        dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : '%s'\n", i, interfaceName);
+    } else {
+        char* dotted = descriptorToDot(interfaceName);
+        printf("<implements name=\"%s\">\n</implements>\n", dotted);
+        free(dotted);
+    }
+}
+
+/*
+ * Dump the catches table associated with the code.
+ */
+void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
+{
+    u4 triesSize = pCode->triesSize;
+
+    if (triesSize == 0) {
+        printf("      catches       : (none)\n");
+        return;
+    }
+
+    printf("      catches       : %d\n", triesSize);
+
+    const DexTry* pTries = dexGetTries(pCode);
+    u4 i;
+
+    for (i = 0; i < triesSize; i++) {
+        const DexTry* pTry = &pTries[i];
+        u4 start = pTry->startAddr;
+        u4 end = start + pTry->insnCount;
+        DexCatchIterator iterator;
+
+        printf("        0x%04x - 0x%04x\n", start, end);
+
+        dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
+
+        for (;;) {
+            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+            const char* descriptor;
+
+            if (handler == NULL) {
+                break;
+            }
+
+            descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
+                dexStringByTypeIdx(pDexFile, handler->typeIdx);
+
+            printf("          %s -> 0x%04x\n", descriptor,
+                    handler->address);
+        }
+    }
+}
+
+static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
+{
+    printf("        0x%04x line=%d\n", address, lineNum);
+    return 0;
+}
+
+/*
+ * Dump the positions list.
+ */
+void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
+        const DexMethod *pDexMethod)
+{
+    printf("      positions     : \n");
+    const DexMethodId *pMethodId
+            = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    const char *classDescriptor
+            = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
+            pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
+}
+
+static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
+        u4 endAddress, const char *name, const char *descriptor,
+        const char *signature)
+{
+    printf("        0x%04x - 0x%04x reg=%d %s %s %s\n",
+            startAddress, endAddress, reg, name, descriptor,
+            signature);
+}
+
+/*
+ * Dump the locals list.
+ */
+void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
+        const DexMethod *pDexMethod)
+{
+    printf("      locals        : \n");
+
+    const DexMethodId *pMethodId
+            = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    const char *classDescriptor
+            = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
+            pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
+}
+
+/*
+ * Get information about a method.
+ */
+bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
+{
+    const DexMethodId* pMethodId;
+
+    if (methodIdx >= pDexFile->pHeader->methodIdsSize)
+        return false;
+
+    pMethodId = dexGetMethodId(pDexFile, methodIdx);
+    pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
+    pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+
+    pMethInfo->classDescriptor =
+            dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+    return true;
+}
+
+/*
+ * Get information about a field.
+ */
+bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
+{
+    const DexFieldId* pFieldId;
+
+    if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
+        return false;
+
+    pFieldId = dexGetFieldId(pDexFile, fieldIdx);
+    pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
+    pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    pFieldInfo->classDescriptor =
+        dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
+    return true;
+}
+
+
+/*
+ * Look up a class' descriptor.
+ */
+const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
+{
+    return dexStringByTypeIdx(pDexFile, classIdx);
+}
+
+/*
+ * Helper for dumpInstruction(), which builds the string
+ * representation for the index in the given instruction. This will
+ * first try to use the given buffer, but if the result won't fit,
+ * then this will allocate a new buffer to hold the result. A pointer
+ * to the buffer which holds the full result is always returned, and
+ * this can be compared with the one passed in, to see if the result
+ * needs to be free()d.
+ */
+static char* indexString(DexFile* pDexFile,
+    const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
+{
+    int outSize;
+    u4 index;
+    u4 width;
+
+    /* TODO: Make the index *always* be in field B, to simplify this code. */
+    switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
+    case kFmt20bc:
+    case kFmt21c:
+    case kFmt35c:
+    case kFmt35ms:
+    case kFmt3rc:
+    case kFmt3rms:
+    case kFmt35mi:
+    case kFmt3rmi:
+        index = pDecInsn->vB;
+        width = 4;
+        break;
+    case kFmt31c:
+    case kFmt40sc:
+    case kFmt41c:
+    case kFmt5rc:
+        index = pDecInsn->vB;
+        width = 8;
+        break;
+    case kFmt22c:
+    case kFmt22cs:
+        index = pDecInsn->vC;
+        width = 4;
+        break;
+    case kFmt52c:
+        index = pDecInsn->vC;
+        width = 8;
+        break;
+    default:
+        index = 0;
+        width = 4;
+        break;
+    }
+
+    switch (pDecInsn->indexType) {
+    case kIndexUnknown:
+        /*
+         * This function shouldn't ever get called for this type, but do
+         * something sensible here, just to help with debugging.
+         */
+        outSize = snprintf(buf, bufSize, "<unknown-index>");
+        break;
+    case kIndexNone:
+        /*
+         * This function shouldn't ever get called for this type, but do
+         * something sensible here, just to help with debugging.
+         */
+        outSize = snprintf(buf, bufSize, "<no-index>");
+        break;
+    case kIndexVaries:
+        /*
+         * This one should never show up in a dexdump, so no need to try
+         * to get fancy here.
+         */
+        outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
+                width, index);
+        break;
+    case kIndexTypeRef:
+        outSize = snprintf(buf, bufSize, "%s // type@%0*x",
+                getClassDescriptor(pDexFile, index), width, index);
+        break;
+    case kIndexStringRef:
+        outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
+                dexStringById(pDexFile, index), width, index);
+        break;
+    case kIndexMethodRef:
+        {
+            FieldMethodInfo methInfo;
+            if (getMethodInfo(pDexFile, index, &methInfo)) {
+                outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
+                        methInfo.classDescriptor, methInfo.name,
+                        methInfo.signature, width, index);
+            } else {
+                outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
+                        width, index);
+            }
+        }
+        break;
+    case kIndexFieldRef:
+        {
+            FieldMethodInfo fieldInfo;
+            if (getFieldInfo(pDexFile, index, &fieldInfo)) {
+                outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
+                        fieldInfo.classDescriptor, fieldInfo.name,
+                        fieldInfo.signature, width, index);
+            } else {
+                outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
+                        width, index);
+            }
+        }
+        break;
+    case kIndexInlineMethod:
+        outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
+                width, index, width, index);
+        break;
+    case kIndexVtableOffset:
+        outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
+                width, index, width, index);
+        break;
+    case kIndexFieldOffset:
+        outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
+        break;
+    default:
+        outSize = snprintf(buf, bufSize, "<?>");
+        break;
+    }
+
+    if (outSize >= (int) bufSize) {
+        /*
+         * The buffer wasn't big enough; allocate and retry. Note:
+         * snprintf() doesn't count the '\0' as part of its returned
+         * size, so we add explicit space for it here.
+         */
+        outSize++;
+        buf = (char*)malloc(outSize);
+        if (buf == NULL) {
+            return NULL;
+        }
+        return indexString(pDexFile, pDecInsn, buf, outSize);
+    } else {
+        return buf;
+    }
+}
+
+/*
+ * Dump a single instruction.
+ */
+void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
+    int insnWidth, const DecodedInstruction* pDecInsn)
+{
+    char indexBufChars[200];
+    char *indexBuf = indexBufChars;
+    const u2* insns = pCode->insns;
+    int i;
+
+    printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
+    for (i = 0; i < 8; i++) {
+        if (i < insnWidth) {
+            if (i == 7) {
+                printf(" ... ");
+            } else {
+                /* print 16-bit value in little-endian order */
+                const u1* bytePtr = (const u1*) &insns[insnIdx+i];
+                printf(" %02x%02x", bytePtr[0], bytePtr[1]);
+            }
+        } else {
+            fputs("     ", stdout);
+        }
+    }
+
+    if (pDecInsn->opcode == OP_NOP) {
+        u2 instr = get2LE((const u1*) &insns[insnIdx]);
+        if (instr == kPackedSwitchSignature) {
+            printf("|%04x: packed-switch-data (%d units)",
+                insnIdx, insnWidth);
+        } else if (instr == kSparseSwitchSignature) {
+            printf("|%04x: sparse-switch-data (%d units)",
+                insnIdx, insnWidth);
+        } else if (instr == kArrayDataSignature) {
+            printf("|%04x: array-data (%d units)",
+                insnIdx, insnWidth);
+        } else {
+            printf("|%04x: nop // spacer", insnIdx);
+        }
+    } else {
+        printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
+    }
+
+    if (pDecInsn->indexType != kIndexNone) {
+        indexBuf = indexString(pDexFile, pDecInsn,
+                indexBufChars, sizeof(indexBufChars));
+    }
+
+    switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
+    case kFmt10x:        // op
+        break;
+    case kFmt12x:        // op vA, vB
+        printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
+        break;
+    case kFmt11n:        // op vA, #+B
+        printf(" v%d, #int %d // #%x",
+            pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
+        break;
+    case kFmt11x:        // op vAA
+        printf(" v%d", pDecInsn->vA);
+        break;
+    case kFmt10t:        // op +AA
+    case kFmt20t:        // op +AAAA
+        {
+            s4 targ = (s4) pDecInsn->vA;
+            printf(" %04x // %c%04x",
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+        }
+        break;
+    case kFmt22x:        // op vAA, vBBBB
+        printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
+        break;
+    case kFmt21t:        // op vAA, +BBBB
+        {
+            s4 targ = (s4) pDecInsn->vB;
+            printf(" v%d, %04x // %c%04x", pDecInsn->vA,
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+        }
+        break;
+    case kFmt21s:        // op vAA, #+BBBB
+        printf(" v%d, #int %d // #%x",
+            pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
+        break;
+    case kFmt21h:        // op vAA, #+BBBB0000[00000000]
+        // The printed format varies a bit based on the actual opcode.
+        if (pDecInsn->opcode == OP_CONST_HIGH16) {
+            s4 value = pDecInsn->vB << 16;
+            printf(" v%d, #int %d // #%x",
+                pDecInsn->vA, value, (u2)pDecInsn->vB);
+        } else {
+            s8 value = ((s8) pDecInsn->vB) << 48;
+            printf(" v%d, #long %lld // #%x",
+                pDecInsn->vA, value, (u2)pDecInsn->vB);
+        }
+        break;
+    case kFmt21c:        // op vAA, thing@BBBB
+    case kFmt31c:        // op vAA, thing@BBBBBBBB
+    case kFmt41c:        // exop vAAAA, thing@BBBBBBBB
+        printf(" v%d, %s", pDecInsn->vA, indexBuf);
+        break;
+    case kFmt23x:        // op vAA, vBB, vCC
+    case kFmt33x:        // exop vAA, vBB, vCCCC
+        printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
+        break;
+    case kFmt22b:        // op vAA, vBB, #+CC
+        printf(" v%d, v%d, #int %d // #%02x",
+            pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
+        break;
+    case kFmt22t:        // op vA, vB, +CCCC
+        {
+            s4 targ = (s4) pDecInsn->vC;
+            printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+        }
+        break;
+    case kFmt22s:        // op vA, vB, #+CCCC
+    case kFmt32s:        // exop vAA, vBB, #+CCCC
+        printf(" v%d, v%d, #int %d // #%04x",
+            pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
+        break;
+    case kFmt22c:        // op vA, vB, thing@CCCC
+    case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
+    case kFmt52c:        // exop vAAAA, vBBBB, thing@CCCCCCCC
+        printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
+        break;
+    case kFmt30t:
+        printf(" #%08x", pDecInsn->vA);
+        break;
+    case kFmt31i:        // op vAA, #+BBBBBBBB
+        {
+            /* this is often, but not always, a float */
+            union {
+                float f;
+                u4 i;
+            } conv;
+            conv.i = pDecInsn->vB;
+            printf(" v%d, #float %f // #%08x",
+                pDecInsn->vA, conv.f, pDecInsn->vB);
+        }
+        break;
+    case kFmt31t:       // op vAA, offset +BBBBBBBB
+        printf(" v%d, %08x // +%08x",
+            pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
+        break;
+    case kFmt32x:        // op vAAAA, vBBBB
+        printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
+        break;
+    case kFmt35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case kFmt35ms:       // [opt] invoke-virtual+super
+    case kFmt35mi:       // [opt] inline invoke
+        {
+            fputs(" {", stdout);
+            for (i = 0; i < (int) pDecInsn->vA; i++) {
+                if (i == 0)
+                    printf("v%d", pDecInsn->arg[i]);
+                else
+                    printf(", v%d", pDecInsn->arg[i]);
+            }
+            printf("}, %s", indexBuf);
+        }
+        break;
+    case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    case kFmt3rms:       // [opt] invoke-virtual+super/range
+    case kFmt3rmi:       // [opt] execute-inline/range
+    case kFmt5rc:        // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
+        {
+            /*
+             * This doesn't match the "dx" output when some of the args are
+             * 64-bit values -- dx only shows the first register.
+             */
+            fputs(" {", stdout);
+            for (i = 0; i < (int) pDecInsn->vA; i++) {
+                if (i == 0)
+                    printf("v%d", pDecInsn->vC + i);
+                else
+                    printf(", v%d", pDecInsn->vC + i);
+            }
+            printf("}, %s", indexBuf);
+        }
+        break;
+    case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB
+        {
+            /* this is often, but not always, a double */
+            union {
+                double d;
+                u8 j;
+            } conv;
+            conv.j = pDecInsn->vB_wide;
+            printf(" v%d, #double %f // #%016llx",
+                pDecInsn->vA, conv.d, pDecInsn->vB_wide);
+        }
+        break;
+    case kFmt00x:        // unknown op or breakpoint
+        break;
+    default:
+        printf(" ???");
+        break;
+    }
+
+    putchar('\n');
+
+    if (indexBuf != indexBufChars) {
+        free(indexBuf);
+    }
+}
+
+/*
+ * Dump a bytecode disassembly.
+ */
+void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
+{
+    const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
+    const u2* insns;
+    int insnIdx;
+    FieldMethodInfo methInfo;
+    int startAddr;
+    char* className = NULL;
+
+    assert(pCode->insnsSize > 0);
+    insns = pCode->insns;
+
+    getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
+    startAddr = ((u1*)pCode - pDexFile->baseAddr);
+    className = descriptorToDot(methInfo.classDescriptor);
+
+    printf("%06x:                                        |[%06x] %s.%s:%s\n",
+        startAddr, startAddr,
+        className, methInfo.name, methInfo.signature);
+
+    insnIdx = 0;
+    while (insnIdx < (int) pCode->insnsSize) {
+        int insnWidth;
+        DecodedInstruction decInsn;
+        u2 instr;
+
+        /*
+         * Note: This code parallels the function
+         * dexGetWidthFromInstruction() in InstrUtils.c, but this version
+         * can deal with data in either endianness.
+         *
+         * TODO: Figure out if this really matters, and possibly change
+         * this to just use dexGetWidthFromInstruction().
+         */
+        instr = get2LE((const u1*)insns);
+        if (instr == kPackedSwitchSignature) {
+            insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
+        } else if (instr == kSparseSwitchSignature) {
+            insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
+        } else if (instr == kArrayDataSignature) {
+            int width = get2LE((const u1*)(insns+1));
+            int size = get2LE((const u1*)(insns+2)) |
+                       (get2LE((const u1*)(insns+3))<<16);
+            // The plus 1 is to round up for odd size and width.
+            insnWidth = 4 + ((size * width) + 1) / 2;
+        } else {
+            Opcode opcode = dexOpcodeFromCodeUnit(instr);
+            insnWidth = dexGetWidthFromOpcode(opcode);
+            if (insnWidth == 0) {
+                fprintf(stderr,
+                    "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
+                break;
+            }
+        }
+
+        dexDecodeInstruction(insns, &decInsn);
+        dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
+
+        insns += insnWidth;
+        insnIdx += insnWidth;
+    }
+
+    free(className);
+}
+
+/*
+ * Dump a "code" struct.
+ */
+void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
+{
+    const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
+
+    printf("      registers     : %d\n", pCode->registersSize);
+    printf("      ins           : %d\n", pCode->insSize);
+    printf("      outs          : %d\n", pCode->outsSize);
+    printf("      insns size    : %d 16-bit code units\n", pCode->insnsSize);
+
+    if (gOptions.disassemble)
+        dumpBytecodes(pDexFile, pDexMethod);
+
+    dumpCatches(pDexFile, pCode);
+    /* both of these are encoded in debug info */
+    dumpPositions(pDexFile, pCode, pDexMethod);
+    dumpLocals(pDexFile, pCode, pDexMethod);
+}
+
+/*
+ * Dump a method.
+ */
+void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
+{
+    const DexMethodId* pMethodId;
+    const char* backDescriptor;
+    const char* name;
+    char* typeDescriptor = NULL;
+    char* accessStr = NULL;
+
+    if (gOptions.exportsOnly &&
+        (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    name = dexStringById(pDexFile, pMethodId->nameIdx);
+    typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+
+    backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    accessStr = createAccessFlagStr(pDexMethod->accessFlags,
+                    kAccessForMethod);
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pDexMethod->accessFlags, accessStr);
+
+        if (pDexMethod->codeOff == 0) {
+            printf("      code          : (none)\n");
+        } else {
+            printf("      code          -\n");
+            dumpCode(pDexFile, pDexMethod);
+        }
+
+        if (gOptions.disassemble)
+            putchar('\n');
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        bool constructor = (name[0] == '<');
+
+        if (constructor) {
+            char* tmp;
+
+            tmp = descriptorClassToDot(backDescriptor);
+            printf("<constructor name=\"%s\"\n", tmp);
+            free(tmp);
+
+            tmp = descriptorToDot(backDescriptor);
+            printf(" type=\"%s\"\n", tmp);
+            free(tmp);
+        } else {
+            printf("<method name=\"%s\"\n", name);
+
+            const char* returnType = strrchr(typeDescriptor, ')');
+            if (returnType == NULL) {
+                fprintf(stderr, "bad method type descriptor '%s'\n",
+                    typeDescriptor);
+                goto bail;
+            }
+
+            char* tmp = descriptorToDot(returnType+1);
+            printf(" return=\"%s\"\n", tmp);
+            free(tmp);
+
+            printf(" abstract=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
+            printf(" native=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
+
+            bool isSync =
+                (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
+                (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
+            printf(" synchronized=%s\n", quotedBool(isSync));
+        }
+
+        printf(" static=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pDexMethod->accessFlags));
+
+        printf(">\n");
+
+        /*
+         * Parameters.
+         */
+        if (typeDescriptor[0] != '(') {
+            fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
+            goto bail;
+        }
+
+        char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */
+        int argNum = 0;
+
+        const char* base = typeDescriptor+1;
+
+        while (*base != ')') {
+            char* cp = tmpBuf;
+
+            while (*base == '[')
+                *cp++ = *base++;
+
+            if (*base == 'L') {
+                /* copy through ';' */
+                do {
+                    *cp = *base++;
+                } while (*cp++ != ';');
+            } else {
+                /* primitive char, copy it */
+                if (strchr("ZBCSIFJD", *base) == NULL) {
+                    fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
+                    goto bail;
+                }
+                *cp++ = *base++;
+            }
+
+            /* null terminate and display */
+            *cp++ = '\0';
+
+            char* tmp = descriptorToDot(tmpBuf);
+            printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
+                argNum++, tmp);
+            free(tmp);
+        }
+
+        if (constructor)
+            printf("</constructor>\n");
+        else
+            printf("</method>\n");
+    }
+
+bail:
+    free(typeDescriptor);
+    free(accessStr);
+}
+
+/*
+ * Dump a static (class) field.
+ */
+void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
+{
+    const DexFieldId* pFieldId;
+    const char* backDescriptor;
+    const char* name;
+    const char* typeDescriptor;
+    char* accessStr;
+
+    if (gOptions.exportsOnly &&
+        (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
+
+    pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
+    name = dexStringById(pDexFile, pFieldId->nameIdx);
+    typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
+
+    accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pSField->accessFlags, accessStr);
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* tmp;
+
+        printf("<field name=\"%s\"\n", name);
+
+        tmp = descriptorToDot(typeDescriptor);
+        printf(" type=\"%s\"\n", tmp);
+        free(tmp);
+
+        printf(" transient=%s\n",
+            quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
+        printf(" volatile=%s\n",
+            quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
+        // "value=" not knowable w/o parsing annotations
+        printf(" static=%s\n",
+            quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pSField->accessFlags));
+        printf(">\n</field>\n");
+    }
+
+    free(accessStr);
+}
+
+/*
+ * Dump an instance field.
+ */
+void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
+{
+    dumpSField(pDexFile, pIField, i);
+}
+
+/*
+ * 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.
+ */
+void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
+{
+    const DexTypeList* pInterfaces;
+    const DexClassDef* pClassDef;
+    DexClassData* pClassData = NULL;
+    const u1* pEncodedData;
+    const char* fileName;
+    const char* classDescriptor;
+    const char* superclassDescriptor;
+    char* accessStr = NULL;
+    int i;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+
+    if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
+        //printf("<!-- omitting non-public class %s -->\n",
+        //    classDescriptor);
+        goto bail;
+    }
+
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        printf("Trouble reading class data (#%d)\n", idx);
+        goto bail;
+    }
+
+    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+    /*
+     * For the XML output, show the package name.  Ideally we'd gather
+     * up the classes, sort them, and dump them alphabetically so the
+     * package name wouldn't jump around, but that's not a great plan
+     * for something that needs to run on the device.
+     */
+    if (!(classDescriptor[0] == 'L' &&
+          classDescriptor[strlen(classDescriptor)-1] == ';'))
+    {
+        /* arrays and primitives should not be defined explicitly */
+        fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
+        /* keep going? */
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* mangle;
+        char* lastSlash;
+        char* cp;
+
+        mangle = strdup(classDescriptor + 1);
+        mangle[strlen(mangle)-1] = '\0';
+
+        /* reduce to just the package name */
+        lastSlash = strrchr(mangle, '/');
+        if (lastSlash != NULL) {
+            *lastSlash = '\0';
+        } else {
+            *mangle = '\0';
+        }
+
+        for (cp = mangle; *cp != '\0'; cp++) {
+            if (*cp == '/')
+                *cp = '.';
+        }
+
+        if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
+            /* start of a new package */
+            if (*pLastPackage != NULL)
+                printf("</package>\n");
+            printf("<package name=\"%s\"\n>\n", mangle);
+            free(*pLastPackage);
+            *pLastPackage = mangle;
+        } else {
+            free(mangle);
+        }
+    }
+
+    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
+
+    if (pClassDef->superclassIdx == kDexNoIndex) {
+        superclassDescriptor = NULL;
+    } else {
+        superclassDescriptor =
+            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("Class #%d            -\n", idx);
+        printf("  Class descriptor  : '%s'\n", classDescriptor);
+        printf("  Access flags      : 0x%04x (%s)\n",
+            pClassDef->accessFlags, accessStr);
+
+        if (superclassDescriptor != NULL)
+            printf("  Superclass        : '%s'\n", superclassDescriptor);
+
+        printf("  Interfaces        -\n");
+    } else {
+        char* tmp;
+
+        tmp = descriptorClassToDot(classDescriptor);
+        printf("<class name=\"%s\"\n", tmp);
+        free(tmp);
+
+        if (superclassDescriptor != NULL) {
+            tmp = descriptorToDot(superclassDescriptor);
+            printf(" extends=\"%s\"\n", tmp);
+            free(tmp);
+        }
+        printf(" abstract=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
+        printf(" static=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pClassDef->accessFlags));
+        printf(">\n");
+    }
+    pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
+    if (pInterfaces != NULL) {
+        for (i = 0; i < (int) pInterfaces->size; i++)
+            dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Static fields     -\n");
+    for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
+        dumpSField(pDexFile, &pClassData->staticFields[i], i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Instance fields   -\n");
+    for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
+        dumpIField(pDexFile, &pClassData->instanceFields[i], i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Direct methods    -\n");
+    for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+        dumpMethod(pDexFile, &pClassData->directMethods[i], i);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Virtual methods   -\n");
+    for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
+        dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
+    }
+
+    // TODO: Annotations.
+
+    if (pClassDef->sourceFileIdx != kDexNoIndex)
+        fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
+    else
+        fileName = "unknown";
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("  source_file_idx   : %d (%s)\n",
+            pClassDef->sourceFileIdx, fileName);
+        printf("\n");
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML) {
+        printf("</class>\n");
+    }
+
+bail:
+    free(pClassData);
+    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 = (const u1*)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.
+ */
+void processDexFile(const char* fileName, DexFile* pDexFile)
+{
+    char* package = NULL;
+    int i;
+
+    if (gOptions.verbose) {
+        printf("Opened '%s', DEX version '%.3s'\n", fileName,
+            pDexFile->pHeader->magic +4);
+    }
+
+    if (gOptions.dumpRegisterMaps) {
+        dumpRegisterMaps(pDexFile);
+        return;
+    }
+
+    if (gOptions.showFileHeaders) {
+        dumpFileHeader(pDexFile);
+        dumpOptDirectory(pDexFile);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("<api>\n");
+
+    for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
+        if (gOptions.showSectionHeaders)
+            dumpClassDef(pDexFile, i);
+
+        dumpClass(pDexFile, i, &package);
+    }
+
+    /* free the last one allocated */
+    if (package != NULL) {
+        printf("</package>\n");
+        free(package);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("</api>\n");
+}
+
+
+/*
+ * Process one file.
+ */
+int process(const char* fileName)
+{
+    DexFile* pDexFile = NULL;
+    MemMapping map;
+    bool mapped = false;
+    int result = -1;
+
+    if (gOptions.verbose)
+        printf("Processing '%s'...\n", fileName);
+
+    if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
+        return result;
+    }
+    mapped = true;
+
+    int flags = kDexParseVerifyChecksum;
+    if (gOptions.ignoreBadChecksum)
+        flags |= kDexParseContinueOnError;
+
+    pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
+    if (pDexFile == NULL) {
+        fprintf(stderr, "ERROR: DEX parse failed\n");
+        goto bail;
+    }
+
+    if (gOptions.checksumOnly) {
+        printf("Checksum verified\n");
+    } else {
+        processDexFile(fileName, pDexFile);
+    }
+
+    result = 0;
+
+bail:
+    if (mapped)
+        sysReleaseShmem(&map);
+    if (pDexFile != NULL)
+        dexFileFree(pDexFile);
+    return result;
+}
+
+
+/*
+ * Show usage.
+ */
+void usage(void)
+{
+    fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+    fprintf(stderr,
+        "%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");
+}
+
+/*
+ * Parse args.
+ *
+ * I'm not using getopt_long() because we may not have it in libc.
+ */
+int main(int argc, char* const argv[])
+{
+    bool wantUsage = false;
+    int ic;
+
+    memset(&gOptions, 0, sizeof(gOptions));
+    gOptions.verbose = true;
+
+    while (1) {
+        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;
+        case 'f':       // dump outer file header
+            gOptions.showFileHeaders = true;
+            break;
+        case 'h':       // dump section headers, i.e. all meta-data
+            gOptions.showSectionHeaders = true;
+            break;
+        case 'i':       // continue even if checksum is bad
+            gOptions.ignoreBadChecksum = true;
+            break;
+        case 'l':       // layout
+            if (strcmp(optarg, "plain") == 0) {
+                gOptions.outputFormat = OUTPUT_PLAIN;
+            } else if (strcmp(optarg, "xml") == 0) {
+                gOptions.outputFormat = OUTPUT_XML;
+                gOptions.verbose = false;
+                gOptions.exportsOnly = true;
+            } else {
+                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;
+        default:
+            wantUsage = true;
+            break;
+        }
+    }
+
+    if (optind == argc) {
+        fprintf(stderr, "%s: no file specified\n", gProgName);
+        wantUsage = true;
+    }
+
+    if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
+        fprintf(stderr, "Can't specify both -c and -i\n");
+        wantUsage = true;
+    }
+
+    if (wantUsage) {
+        usage();
+        return 2;
+    }
+
+    int result = 0;
+    while (optind < argc) {
+        result |= process(argv[optind++]);
+    }
+
+    return (result != 0);
+}
diff --git a/dexdump/NOTICE b/dexdump/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/dexdump/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/dexgen/Android.mk b/dexgen/Android.mk
new file mode 100644
index 0000000..59d623a
--- /dev/null
+++ b/dexgen/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SDK_VERSION := 4
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE := dexgen
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/dexgen/README.txt b/dexgen/README.txt
new file mode 100644
index 0000000..a542f04
--- /dev/null
+++ b/dexgen/README.txt
@@ -0,0 +1,3 @@
+Home of dexgen, the dex code generator project. It provides API for
+creating dex classes in runtime which is needed e.g. for class mocking.
+This solution is based on the dx tool and uses its classes extensively.
diff --git a/dexgen/src/com/android/dexgen/dex/code/ArrayData.java b/dexgen/src/com/android/dexgen/dex/code/ArrayData.java
new file mode 100644
index 0000000..d89a93f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/ArrayData.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.rop.cst.*;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.ArrayList;
+
+/**
+ * Pseudo-instruction which holds fill array data.
+ */
+public final class ArrayData extends VariableSizeInsn {
+    /**
+     * {@code non-null;} address representing the instruction that uses this
+     * instance
+     */
+    private final CodeAddress user;
+
+    /** {@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 */
+    private final Constant arrayType;
+
+    /** Width of the init value element */
+    private final int elemWidth;
+
+    /** Length of the init list */
+    private final int initLength;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param user {@code non-null;} address representing the instruction that
+     * uses this instance
+     * @param values {@code non-null;} initial values to be filled into an array
+     */
+    public ArrayData(SourcePosition position, CodeAddress user,
+                     ArrayList<Constant> values,
+                     Constant arrayType) {
+        super(position, RegisterSpecList.EMPTY);
+
+        if (user == null) {
+            throw new NullPointerException("user == null");
+        }
+
+        if (values == null) {
+            throw new NullPointerException("values == null");
+        }
+
+        int sz = values.size();
+
+        if (sz <= 0) {
+            throw new IllegalArgumentException("Illegal number of init values");
+        }
+
+        this.arrayType = arrayType;
+
+        if (arrayType == CstType.BYTE_ARRAY ||
+                arrayType == CstType.BOOLEAN_ARRAY) {
+            elemWidth = 1;
+        } else if (arrayType == CstType.SHORT_ARRAY ||
+                arrayType == CstType.CHAR_ARRAY) {
+            elemWidth = 2;
+        } else if (arrayType == CstType.INT_ARRAY ||
+                arrayType == CstType.FLOAT_ARRAY) {
+            elemWidth = 4;
+        } else if (arrayType == CstType.LONG_ARRAY ||
+                arrayType == CstType.DOUBLE_ARRAY) {
+            elemWidth = 8;
+        } else {
+            throw new IllegalArgumentException("Unexpected constant type");
+        }
+        this.user = user;
+        this.values = values;
+        initLength = values.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        int sz = initLength;
+        // Note: the unit here is 16-bit
+        return 4 + ((sz * elemWidth) + 1) / 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        int sz = values.size();
+
+        out.writeShort(0x300 | DalvOps.NOP);
+        out.writeShort(elemWidth);
+        out.writeInt(initLength);
+
+
+        // For speed reasons, replicate the for loop in each case
+        switch (elemWidth) {
+            case 1: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeByte((byte) ((CstLiteral32) cst).getIntBits());
+                }
+                break;
+            }
+            case 2: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeShort((short) ((CstLiteral32) cst).getIntBits());
+                }
+                break;
+            }
+            case 4: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeInt(((CstLiteral32) cst).getIntBits());
+                }
+                break;
+            }
+            case 8: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeLong(((CstLiteral64) cst).getLongBits());
+                }
+                break;
+            }
+            default:
+                break;
+        }
+
+        // Pad one byte to make the size of data table multiples of 16-bits
+        if (elemWidth == 1 && (sz % 2 != 0)) {
+            out.writeByte(0x00);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new ArrayData(getPosition(), user, values, arrayType);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        int sz = values.size();
+        for (int i = 0; i < sz; i++) {
+            sb.append("\n    ");
+            sb.append(i);
+            sb.append(": ");
+            sb.append(values.get(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        int baseAddress = user.getAddress();
+        StringBuffer sb = new StringBuffer(100);
+        int sz = values.size();
+
+        sb.append("array-data // for fill-array-data @ ");
+        sb.append(Hex.u2(baseAddress));
+
+        for (int i = 0; i < sz; i++) {
+            sb.append("\n  ");
+            sb.append(i);
+            sb.append(": ");
+            sb.append(values.get(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/BlockAddresses.java b/dexgen/src/com/android/dexgen/dex/code/BlockAddresses.java
new file mode 100644
index 0000000..fa8096e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/BlockAddresses.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.BasicBlock;
+import com.android.dexgen.rop.code.BasicBlockList;
+import com.android.dexgen.rop.code.Insn;
+import com.android.dexgen.rop.code.RopMethod;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Container for the set of {@link CodeAddress} instances associated with
+ * the blocks of a particular method. Each block has a corresponding
+ * start address, end address, and last instruction address.
+ */
+public final class BlockAddresses {
+    /** {@code non-null;} array containing addresses for the start of each basic
+     * block (indexed by basic block label) */
+    private final CodeAddress[] starts;
+
+    /** {@code non-null;} array containing addresses for the final instruction
+     * of each basic block (indexed by basic block label) */
+    private final CodeAddress[] lasts;
+
+    /** {@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;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method to have block addresses for
+     */
+    public BlockAddresses(RopMethod method) {
+        BasicBlockList blocks = method.getBlocks();
+        int maxLabel = blocks.getMaxLabel();
+
+        this.starts = new CodeAddress[maxLabel];
+        this.lasts = new CodeAddress[maxLabel];
+        this.ends = new CodeAddress[maxLabel];
+
+        setupArrays(method);
+    }
+
+    /**
+     * Gets the instance for the start of the given block.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getStart(BasicBlock block) {
+        return starts[block.getLabel()];
+    }
+
+    /**
+     * Gets the instance for the start of the block with the given label.
+     *
+     * @param label {@code non-null;} the label of the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getStart(int label) {
+        return starts[label];
+    }
+
+    /**
+     * Gets the instance for the final instruction of the given block.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getLast(BasicBlock block) {
+        return lasts[block.getLabel()];
+    }
+
+    /**
+     * Gets the instance for the final instruction of the block with
+     * the given label.
+     *
+     * @param label {@code non-null;} the label of the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getLast(int label) {
+        return lasts[label];
+    }
+
+    /**
+     * Gets the instance for the end (address after the final instruction)
+     * of the given block.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getEnd(BasicBlock block) {
+        return ends[block.getLabel()];
+    }
+
+    /**
+     * Gets the instance for the end (address after the final instruction)
+     * of the block with the given label.
+     *
+     * @param label {@code non-null;} the label of the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getEnd(int label) {
+        return ends[label];
+    }
+
+    /**
+     * Sets up the address arrays.
+     */
+    private void setupArrays(RopMethod method) {
+        BasicBlockList blocks = method.getBlocks();
+        int sz = blocks.size();
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = blocks.get(i);
+            int label = one.getLabel();
+            Insn insn = one.getInsns().get(0);
+
+            starts[label] = new CodeAddress(insn.getPosition());
+
+            SourcePosition pos = one.getLastInsn().getPosition();
+
+            lasts[label] = new CodeAddress(pos);
+            ends[label] = new CodeAddress(pos);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/CatchBuilder.java b/dexgen/src/com/android/dexgen/dex/code/CatchBuilder.java
new file mode 100644
index 0000000..adb119a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/CatchBuilder.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.type.Type;
+
+import java.util.HashSet;
+
+/**
+ * Interface for the construction of {@link CatchTable} instances.
+ */
+public interface CatchBuilder {
+    /**
+     * Builds and returns the catch table for this instance.
+     *
+     * @return {@code non-null;} the constructed table
+     */
+    public CatchTable build();
+
+    /**
+     * Gets whether this instance has any catches at all (either typed
+     * or catch-all).
+     *
+     * @return whether this instance has any catches at all
+     */
+    public boolean hasAnyCatches();
+
+    /**
+     * Gets the set of catch types associated with this instance.
+     *
+     * @return {@code non-null;} the set of catch types
+     */
+    public HashSet<Type> getCatchTypes();
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/CatchHandlerList.java b/dexgen/src/com/android/dexgen/dex/code/CatchHandlerList.java
new file mode 100644
index 0000000..54200ed
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/CatchHandlerList.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.FixedSizeList;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Ordered list of (exception type, handler address) entries.
+ */
+public final class CatchHandlerList extends FixedSizeList
+        implements Comparable<CatchHandlerList> {
+    /** {@code non-null;} empty instance */
+    public static final CatchHandlerList EMPTY = new CatchHandlerList(0);
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size {@code >= 0;} the size of the list
+     */
+    public CatchHandlerList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toHuman("", "");
+    }
+
+    /**
+     * Get the human form of this instance, prefixed on each line
+     * with the string.
+     *
+     * @param prefix {@code non-null;} the prefix for every line
+     * @param header {@code non-null;} the header for the first line (after the
+     * first prefix)
+     * @return {@code non-null;} the human form
+     */
+    public String toHuman(String prefix, String header) {
+        StringBuilder sb = new StringBuilder(100);
+        int size = size();
+
+        sb.append(prefix);
+        sb.append(header);
+        sb.append("catch ");
+
+        for (int i = 0; i < size; i++) {
+            Entry entry = get(i);
+
+            if (i != 0) {
+                sb.append(",\n");
+                sb.append(prefix);
+                sb.append("  ");
+            }
+
+            if ((i == (size - 1)) && catchesAll()) {
+                sb.append("<any>");
+            } else {
+                sb.append(entry.getExceptionType().toHuman());
+            }
+
+            sb.append(" -> ");
+            sb.append(Hex.u2or4(entry.getHandler()));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns whether or not this instance ends with a "catch-all"
+     * handler.
+     *
+     * @return {@code true} if this instance ends with a "catch-all"
+     * handler or {@code false} if not
+     */
+    public boolean catchesAll() {
+        int size = size();
+
+        if (size == 0) {
+            return false;
+        }
+
+        Entry last = get(size - 1);
+        return last.getExceptionType().equals(CstType.OBJECT);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @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));
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(CatchHandlerList other) {
+        if (this == other) {
+            // Easy out.
+            return 0;
+        }
+
+        int thisSize = size();
+        int otherSize = other.size();
+        int checkSize = Math.min(thisSize, otherSize);
+
+        for (int i = 0; i < checkSize; i++) {
+            Entry thisEntry = get(i);
+            Entry otherEntry = other.get(i);
+            int compare = thisEntry.compareTo(otherEntry);
+            if (compare != 0) {
+                return compare;
+            }
+        }
+
+        if (thisSize < otherSize) {
+            return -1;
+        } else if (thisSize > otherSize) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Entry in the list.
+     */
+    public static class Entry implements Comparable<Entry> {
+        /** {@code non-null;} type of exception handled */
+        private final CstType exceptionType;
+
+        /** {@code >= 0;} exception handler address */
+        private final int handler;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("handler < 0");
+            }
+
+            if (exceptionType == null) {
+                throw new NullPointerException("exceptionType == null");
+            }
+
+            this.handler = handler;
+            this.exceptionType = exceptionType;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            return (handler * 31) + exceptionType.hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof Entry) {
+                return (compareTo((Entry) other) == 0);
+            }
+
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(Entry other) {
+            if (handler < other.handler) {
+                return -1;
+            } else if (handler > other.handler) {
+                return 1;
+            }
+
+            return exceptionType.compareTo(other.exceptionType);
+        }
+
+        /**
+         * Gets the exception type handled.
+         *
+         * @return {@code non-null;} the exception type
+         */
+        public CstType getExceptionType() {
+            return exceptionType;
+        }
+
+        /**
+         * Gets the handler address.
+         *
+         * @return {@code >= 0;} the handler address
+         */
+        public int getHandler() {
+            return handler;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/CatchTable.java b/dexgen/src/com/android/dexgen/dex/code/CatchTable.java
new file mode 100644
index 0000000..4de0da0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/CatchTable.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * Table of catch entries. Each entry includes a range of code
+ * addresses for which it is valid and an associated {@link
+ * CatchHandlerList}.
+ */
+public final class CatchTable extends FixedSizeList
+        implements Comparable<CatchTable> {
+    /** {@code non-null;} empty instance */
+    public static final CatchTable EMPTY = new CatchTable(0);
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size {@code >= 0;} the size of the table
+     */
+    public CatchTable(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(CatchTable other) {
+        if (this == other) {
+            // Easy out.
+            return 0;
+        }
+
+        int thisSize = size();
+        int otherSize = other.size();
+        int checkSize = Math.min(thisSize, otherSize);
+
+        for (int i = 0; i < checkSize; i++) {
+            Entry thisEntry = get(i);
+            Entry otherEntry = other.get(i);
+            int compare = thisEntry.compareTo(otherEntry);
+            if (compare != 0) {
+                return compare;
+            }
+        }
+
+        if (thisSize < otherSize) {
+            return -1;
+        } else if (thisSize > otherSize) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Entry in a catch list.
+     */
+    public static class Entry implements Comparable<Entry> {
+        /** {@code >= 0;} start address */
+        private final int start;
+
+        /** {@code > start;} end address (exclusive) */
+        private final int end;
+
+        /** {@code non-null;} list of catch handlers */
+        private final CatchHandlerList handlers;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("start < 0");
+            }
+
+            if (end <= start) {
+                throw new IllegalArgumentException("end <= start");
+            }
+
+            if (handlers.isMutable()) {
+                throw new IllegalArgumentException("handlers.isMutable()");
+            }
+
+            this.start = start;
+            this.end = end;
+            this.handlers = handlers;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            int hash = (start * 31) + end;
+            hash = (hash * 31) + handlers.hashCode();
+            return hash;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof Entry) {
+                return (compareTo((Entry) other) == 0);
+            }
+
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(Entry other) {
+            if (start < other.start) {
+                return -1;
+            } else if (start > other.start) {
+                return 1;
+            }
+
+            if (end < other.end) {
+                return -1;
+            } else if (end > other.end) {
+                return 1;
+            }
+
+            return handlers.compareTo(other.handlers);
+        }
+
+        /**
+         * Gets the start address.
+         *
+         * @return {@code >= 0;} the start address
+         */
+        public int getStart() {
+            return start;
+        }
+
+        /**
+         * Gets the end address (exclusive).
+         *
+         * @return {@code > start;} the end address (exclusive)
+         */
+        public int getEnd() {
+            return end;
+        }
+
+        /**
+         * Gets the handlers.
+         *
+         * @return {@code non-null;} the handlers
+         */
+        public CatchHandlerList getHandlers() {
+            return handlers;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/CodeAddress.java b/dexgen/src/com/android/dexgen/dex/code/CodeAddress.java
new file mode 100644
index 0000000..b9600ee
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/CodeAddress.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to track an address within a code
+ * array. Instances are used for such things as branch targets and
+ * exception handler ranges. Its code size is zero, and so instances
+ * do not in general directly wind up in any output (either
+ * human-oriented or binary file).
+ */
+public final class CodeAddress extends ZeroSizeInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     */
+    public CodeAddress(SourcePosition position) {
+        super(position);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withRegisters(RegisterSpecList registers) {
+        return new CodeAddress(getPosition());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        return "code-address";
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/CstInsn.java b/dexgen/src/com/android/dexgen/dex/code/CstInsn.java
new file mode 100644
index 0000000..901266b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/CstInsn.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.rop.cst.Constant;
+
+/**
+ * Instruction which has a single constant argument in addition
+ * to all the normal instruction information.
+ */
+public final class CstInsn extends FixedSizeInsn {
+    /** {@code non-null;} the constant argument for this instruction */
+    private final Constant constant;
+
+    /**
+     * {@code >= -1;} the constant pool index for {@link #constant}, or
+     * {@code -1} if not yet set
+     */
+    private int index;
+
+    /**
+     * {@code >= -1;} the constant pool index for the class reference in
+     * {@link #constant} if any, or {@code -1} if not yet set
+     */
+    private int classIndex;
+
+    /**
+     * Constructs an instance. The output address of this instance is
+     * initially unknown ({@code -1}) as is the constant pool index.
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     * @param constant {@code non-null;} constant argument
+     */
+    public CstInsn(Dop opcode, SourcePosition position,
+                   RegisterSpecList registers, Constant constant) {
+        super(opcode, position, registers);
+
+        if (constant == null) {
+            throw new NullPointerException("constant == null");
+        }
+
+        this.constant = constant;
+        this.index = -1;
+        this.classIndex = -1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withOpcode(Dop opcode) {
+        CstInsn result =
+            new CstInsn(opcode, getPosition(), getRegisters(), constant);
+
+        if (index >= 0) {
+            result.setIndex(index);
+        }
+
+        if (classIndex >= 0) {
+            result.setClassIndex(classIndex);
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        CstInsn result =
+            new CstInsn(getOpcode(), getPosition(), registers, constant);
+
+        if (index >= 0) {
+            result.setIndex(index);
+        }
+
+        if (classIndex >= 0) {
+            result.setClassIndex(classIndex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the constant argument.
+     *
+     * @return {@code non-null;} the constant argument
+     */
+    public Constant getConstant() {
+        return constant;
+    }
+
+    /**
+     * Gets the constant's index. It is only valid to call this after
+     * {@link #setIndex} has been called.
+     *
+     * @return {@code >= 0;} the constant pool index
+     */
+    public int getIndex() {
+        if (index < 0) {
+            throw new RuntimeException("index not yet set for " + constant);
+        }
+
+        return index;
+    }
+
+    /**
+     * Returns whether the constant's index has been set for this instance.
+     *
+     * @see #setIndex
+     *
+     * @return {@code true} iff the index has been set
+     */
+    public boolean hasIndex() {
+        return (index >= 0);
+    }
+
+    /**
+     * Sets the constant's index. It is only valid to call this method once
+     * per instance.
+     *
+     * @param index {@code >= 0;} the constant pool index
+     */
+    public void setIndex(int index) {
+        if (index < 0) {
+            throw new IllegalArgumentException("index < 0");
+        }
+
+        if (this.index >= 0) {
+            throw new RuntimeException("index already set");
+        }
+
+        this.index = index;
+    }
+
+    /**
+     * Gets the constant's class index. It is only valid to call this after
+     * {@link #setClassIndex} has been called.
+     *
+     * @return {@code >= 0;} the constant's class's constant pool index
+     */
+    public int getClassIndex() {
+        if (classIndex < 0) {
+            throw new RuntimeException("class index not yet set");
+        }
+
+        return classIndex;
+    }
+
+    /**
+     * Returns whether the constant's class index has been set for this
+     * instance.
+     *
+     * @see #setClassIndex
+     *
+     * @return {@code true} iff the index has been set
+     */
+    public boolean hasClassIndex() {
+        return (classIndex >= 0);
+    }
+
+    /**
+     * Sets the constant's class index. This is the constant pool index
+     * for the class referred to by this instance's constant. Only
+     * reference constants have a class, so it is only on instances
+     * with reference constants that this method should ever be
+     * called. It is only valid to call this method once per instance.
+     *
+     * @param index {@code >= 0;} the constant's class's constant pool index
+     */
+    public void setClassIndex(int index) {
+        if (index < 0) {
+            throw new IllegalArgumentException("index < 0");
+        }
+
+        if (this.classIndex >= 0) {
+            throw new RuntimeException("class index already set");
+        }
+
+        this.classIndex = index;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return constant.toHuman();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/DalvCode.java b/dexgen/src/com/android/dexgen/dex/code/DalvCode.java
new file mode 100644
index 0000000..2df49ed
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/DalvCode.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.type.Type;
+
+import java.util.HashSet;
+
+/**
+ * Container for all the pieces of a concrete method. Each instance
+ * corresponds to a {@code code} structure in a {@code .dex} file.
+ */
+public final class DalvCode {
+    /**
+     * how much position info to preserve; one of the static
+     * constants in {@link PositionList}
+     */
+    private final int positionInfo;
+
+    /**
+     * {@code null-ok;} the instruction list, ready for final processing;
+     * nulled out in {@link #finishProcessingIfNecessary}
+     */
+    private OutputFinisher unprocessedInsns;
+
+    /**
+     * {@code non-null;} unprocessed catch table;
+     * nulled out in {@link #finishProcessingIfNecessary}
+     */
+    private CatchBuilder unprocessedCatches;
+
+    /**
+     * {@code null-ok;} catch table; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private CatchTable catches;
+
+    /**
+     * {@code null-ok;} source positions list; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private PositionList positions;
+
+    /**
+     * {@code null-ok;} local variable list; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private LocalList locals;
+
+    /**
+     * {@code null-ok;} the processed instruction list; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private DalvInsnList insns;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param positionInfo how much position info to preserve; one of the
+     * static constants in {@link PositionList}
+     * @param unprocessedInsns {@code non-null;} the instruction list, ready
+     * for final processing
+     * @param unprocessedCatches {@code non-null;} unprocessed catch
+     * (exception handler) table
+     */
+    public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
+            CatchBuilder unprocessedCatches) {
+        if (unprocessedInsns == null) {
+            throw new NullPointerException("unprocessedInsns == null");
+        }
+
+        if (unprocessedCatches == null) {
+            throw new NullPointerException("unprocessedCatches == null");
+        }
+
+        this.positionInfo = positionInfo;
+        this.unprocessedInsns = unprocessedInsns;
+        this.unprocessedCatches = unprocessedCatches;
+        this.catches = null;
+        this.positions = null;
+        this.locals = null;
+        this.insns = null;
+    }
+
+    /**
+     * Finish up processing of the method.
+     */
+    private void finishProcessingIfNecessary() {
+        if (insns != null) {
+            return;
+        }
+
+        insns = unprocessedInsns.finishProcessingAndGetList();
+        positions = PositionList.make(insns, positionInfo);
+        locals = LocalList.make(insns);
+        catches = unprocessedCatches.build();
+
+        // Let them be gc'ed.
+        unprocessedInsns = null;
+        unprocessedCatches = null;
+    }
+
+    /**
+     * Assign indices in all instructions that need them, using the
+     * given callback to perform lookups. This must be called before
+     * {@link #getInsns}.
+     *
+     * @param callback {@code non-null;} callback object
+     */
+    public void assignIndices(AssignIndicesCallback callback) {
+        unprocessedInsns.assignIndices(callback);
+    }
+
+    /**
+     * Gets whether this instance has any position data to represent.
+     *
+     * @return {@code true} iff this instance has any position
+     * data to represent
+     */
+    public boolean hasPositions() {
+        return (positionInfo != PositionList.NONE)
+            && unprocessedInsns.hasAnyPositionInfo();
+    }
+
+    /**
+     * Gets whether this instance has any local variable data to represent.
+     *
+     * @return {@code true} iff this instance has any local variable
+     * data to represent
+     */
+    public boolean hasLocals() {
+        return unprocessedInsns.hasAnyLocalInfo();
+    }
+
+    /**
+     * Gets whether this instance has any catches at all (either typed
+     * or catch-all).
+     *
+     * @return whether this instance has any catches at all
+     */
+    public boolean hasAnyCatches() {
+        return unprocessedCatches.hasAnyCatches();
+    }
+
+    /**
+     * Gets the set of catch types handled anywhere in the code.
+     *
+     * @return {@code non-null;} the set of catch types
+     */
+    public HashSet<Type> getCatchTypes() {
+        return unprocessedCatches.getCatchTypes();
+    }
+
+    /**
+     * Gets the set of all constants referred to by instructions in
+     * the code.
+     *
+     * @return {@code non-null;} the set of constants
+     */
+    public HashSet<Constant> getInsnConstants() {
+        return unprocessedInsns.getAllConstants();
+    }
+
+    /**
+     * Gets the list of instructions.
+     *
+     * @return {@code non-null;} the instruction list
+     */
+    public DalvInsnList getInsns() {
+        finishProcessingIfNecessary();
+        return insns;
+    }
+
+    /**
+     * Gets the catch (exception handler) table.
+     *
+     * @return {@code non-null;} the catch table
+     */
+    public CatchTable getCatches() {
+        finishProcessingIfNecessary();
+        return catches;
+    }
+
+    /**
+     * Gets the source positions list.
+     *
+     * @return {@code non-null;} the source positions list
+     */
+    public PositionList getPositions() {
+        finishProcessingIfNecessary();
+        return positions;
+    }
+
+    /**
+     * Gets the source positions list.
+     *
+     * @return {@code non-null;} the source positions list
+     */
+    public LocalList getLocals() {
+        finishProcessingIfNecessary();
+        return locals;
+    }
+
+    /**
+     * Class used as a callback for {@link #assignIndices}.
+     */
+    public static interface AssignIndicesCallback {
+        /**
+         * Gets the index for the given constant.
+         *
+         * @param cst {@code non-null;} the constant
+         * @return {@code >= -1;} the index or {@code -1} if the constant
+         * shouldn't actually be reified with an index
+         */
+        public int getIndex(Constant cst);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/DalvInsn.java b/dexgen/src/com/android/dexgen/dex/code/DalvInsn.java
new file mode 100644
index 0000000..95b5feb
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/DalvInsn.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.TwoColumnOutput;
+
+/**
+ * Base class for Dalvik instructions.
+ */
+public abstract class DalvInsn {
+    /**
+     * the actual output address of this instance, if known, or
+     * {@code -1} if not
+     */
+    private int address;
+
+    /** the opcode; one of the constants from {@link Dops} */
+    private final Dop opcode;
+
+    /** {@code non-null;} source position */
+    private final SourcePosition position;
+
+    /** {@code non-null;} list of register arguments */
+    private final RegisterSpecList registers;
+
+    /**
+     * Makes a move instruction, appropriate and ideal for the given arguments.
+     *
+     * @param position {@code non-null;} source position information
+     * @param dest {@code non-null;} destination register
+     * @param src {@code non-null;} source register
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static SimpleInsn makeMove(SourcePosition position,
+            RegisterSpec dest, RegisterSpec src) {
+        boolean category1 = dest.getCategory() == 1;
+        boolean reference = dest.getType().isReference();
+        int destReg = dest.getReg();
+        int srcReg = src.getReg();
+        Dop opcode;
+
+        if ((srcReg | destReg) < 16) {
+            opcode = reference ? Dops.MOVE_OBJECT :
+                (category1 ? Dops.MOVE : Dops.MOVE_WIDE);
+        } else if (destReg < 256) {
+            opcode = reference ? Dops.MOVE_OBJECT_FROM16 :
+                (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16);
+        } else {
+            opcode = reference ? Dops.MOVE_OBJECT_16 :
+                (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16);
+        }
+
+        return new SimpleInsn(opcode, position,
+                              RegisterSpecList.make(dest, src));
+    }
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * <p><b>Note:</b> In the unlikely event that an instruction takes
+     * absolutely no registers (e.g., a {@code nop} or a
+     * no-argument no-result static method call), then the given
+     * register list may be passed as {@link
+     * RegisterSpecList#EMPTY}.</p>
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins and outs)
+     */
+    public DalvInsn(Dop opcode, SourcePosition position,
+                    RegisterSpecList registers) {
+        if (opcode == null) {
+            throw new NullPointerException("opcode == null");
+        }
+
+        if (position == null) {
+            throw new NullPointerException("position == null");
+        }
+
+        if (registers == null) {
+            throw new NullPointerException("registers == null");
+        }
+
+        this.address = -1;
+        this.opcode = opcode;
+        this.position = position;
+        this.registers = registers;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(identifierString());
+        sb.append(' ');
+        sb.append(position);
+
+        sb.append(": ");
+        sb.append(opcode.getName());
+
+        boolean needComma = false;
+        if (registers.size() != 0) {
+            sb.append(registers.toHuman(" ", ", ", null));
+            needComma = true;
+        }
+
+        String extra = argString();
+        if (extra != null) {
+            if (needComma) {
+                sb.append(',');
+            }
+            sb.append(' ');
+            sb.append(extra);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets whether the address of this instruction is known.
+     *
+     * @see #getAddress
+     * @see #setAddress
+     */
+    public final boolean hasAddress() {
+        return (address >= 0);
+    }
+
+    /**
+     * Gets the output address of this instruction, if it is known. This throws
+     * a {@code RuntimeException} if it has not yet been set.
+     *
+     * @see #setAddress
+     *
+     * @return {@code >= 0;} the output address
+     */
+    public final int getAddress() {
+        if (address < 0) {
+            throw new RuntimeException("address not yet known");
+        }
+
+        return address;
+    }
+
+    /**
+     * Gets the opcode.
+     *
+     * @return {@code non-null;} the opcode
+     */
+    public final Dop getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the source position.
+     *
+     * @return {@code non-null;} the source position
+     */
+    public final SourcePosition getPosition() {
+        return position;
+    }
+
+    /**
+     * Gets the register list for this instruction.
+     *
+     * @return {@code non-null;} the registers
+     */
+    public final RegisterSpecList getRegisters() {
+        return registers;
+    }
+
+    /**
+     * Returns whether this instance's opcode uses a result register.
+     * This method is a convenient shorthand for
+     * {@code getOpcode().hasResult()}.
+     *
+     * @return {@code true} iff this opcode uses a result register
+     */
+    public final boolean hasResult() {
+        return opcode.hasResult();
+    }
+
+    /**
+     * Gets the minimum distinct registers required for this instruction.
+     * This assumes that the result (if any) can share registers with the
+     * sources (if any), that each source register is unique, and that
+     * (to be explicit here) category-2 values take up two consecutive
+     * registers.
+     *
+     * @return {@code >= 0;} the minimum distinct register requirement
+     */
+    public final int getMinimumRegisterRequirement() {
+        boolean hasResult = hasResult();
+        int regSz = registers.size();
+        int resultRequirement = hasResult ? registers.get(0).getCategory() : 0;
+        int sourceRequirement = 0;
+
+        for (int i = hasResult ? 1 : 0; i < regSz; i++) {
+            sourceRequirement += registers.get(i).getCategory();
+        }
+
+        return Math.max(sourceRequirement, resultRequirement);
+    }
+
+    /**
+     * Gets the instruction prefix required, if any, to use in a high
+     * register transformed version of this instance.
+     *
+     * @see #hrVersion
+     *
+     * @return {@code null-ok;} the prefix, if any
+     */
+    public DalvInsn hrPrefix() {
+        RegisterSpecList regs = registers;
+        int sz = regs.size();
+
+        if (hasResult()) {
+            if (sz == 1) {
+                return null;
+            }
+            regs = regs.withoutFirst();
+        } else if (sz == 0) {
+            return null;
+        }
+
+        return new HighRegisterPrefix(position, regs);
+    }
+
+    /**
+     * Gets the instruction suffix required, if any, to use in a high
+     * register transformed version of this instance.
+     *
+     * @see #hrVersion
+     *
+     * @return {@code null-ok;} the suffix, if any
+     */
+    public DalvInsn hrSuffix() {
+        if (hasResult()) {
+            RegisterSpec r = registers.get(0);
+            return makeMove(position, r, r.withReg(0));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the instruction that is equivalent to this one, except that
+     * 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
+     * instance, and it is guaranteed that the number of low registers
+     * used will be the number returned by {@link
+     * #getMinimumRegisterRequirement}.
+     *
+     * @return {@code non-null;} the replacement
+     */
+    public DalvInsn hrVersion() {
+        RegisterSpecList regs =
+            registers.withSequentialRegisters(0, hasResult());
+        return withRegisters(regs);
+    }
+
+    /**
+     * Gets the short identifier for this instruction. This is its
+     * address, if assigned, or its identity hashcode if not.
+     *
+     * @return {@code non-null;} the identifier
+     */
+    public final String identifierString() {
+        if (address != -1) {
+            return String.format("%04x", address);
+        }
+
+        return Hex.u4(System.identityHashCode(this));
+    }
+
+    /**
+     * Returns the string form of this instance suitable for inclusion in
+     * a human-oriented listing dump. This method will return {@code null}
+     * if this instance should not appear in a listing.
+     *
+     * @param prefix {@code non-null;} prefix before the address; each follow-on
+     * line will be indented to match as well
+     * @param width {@code >= 0;} the width of the output or {@code 0} for
+     * unlimited width
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @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,
+            boolean noteIndices) {
+        String insnPerSe = listingString0(noteIndices);
+
+        if (insnPerSe == null) {
+            return null;
+        }
+
+        String addr = prefix + identifierString() + ": ";
+        int w1 = addr.length();
+        int w2 = (width == 0) ? insnPerSe.length() : (width - w1);
+
+        return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2);
+    }
+
+    /**
+     * Sets the output address.
+     *
+     * @param address {@code >= 0;} the output address
+     */
+    public final void setAddress(int address) {
+        if (address < 0) {
+            throw new IllegalArgumentException("address < 0");
+        }
+
+        this.address = address;
+    }
+
+    /**
+     * Gets the address immediately after this instance. This is only
+     * calculable if this instance's address is known, and it is equal
+     * to the address plus the length of the instruction format of this
+     * instance's opcode.
+     *
+     * @return {@code >= 0;} the next address
+     */
+    public final int getNextAddress() {
+        return getAddress() + codeSize();
+    }
+
+    /**
+     * Gets the size of this instruction, in 16-bit code units.
+     *
+     * @return {@code >= 0;} the code size of this instruction
+     */
+    public abstract int codeSize();
+
+    /**
+     * Writes this instance to the given output. This method should
+     * never annotate the output.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public abstract void writeTo(AnnotatedOutput out);
+
+    /**
+     * Returns an instance that is just like this one, except that its
+     * opcode is replaced by the one given, and its address is reset.
+     *
+     * @param opcode {@code non-null;} the new opcode
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract DalvInsn withOpcode(Dop opcode);
+
+    /**
+     * Returns an instance that is just like this one, except that all
+     * register references have been offset by the given delta, and its
+     * address is reset.
+     *
+     * @param delta the amount to offset register references by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract DalvInsn withRegisterOffset(int delta);
+
+    /**
+     * Returns an instance that is just like this one, except that the
+     * register list is replaced by the given one, and its address is
+     * reset.
+     *
+     * @param registers {@code non-null;} new register list
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract DalvInsn withRegisters(RegisterSpecList registers);
+
+    /**
+     * Gets the string form for any arguments to this instance. Subclasses
+     * must override this.
+     *
+     * @return {@code null-ok;} the string version of any arguments or
+     * {@code null} if there are none
+     */
+    protected abstract String argString();
+
+    /**
+     * Helper for {@link #listingString}, which returns the string
+     * 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} if this instance should
+     * not appear in a listing.
+     *
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @return {@code null-ok;} the listing string
+     */
+    protected abstract String listingString0(boolean noteIndices);
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/DalvInsnList.java b/dexgen/src/com/android/dexgen/dex/code/DalvInsnList.java
new file mode 100644
index 0000000..15f82c1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/DalvInsnList.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstBaseMethodRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+import com.android.dexgen.util.FixedSizeList;
+import com.android.dexgen.util.IndentingWriter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+
+/**
+ * List of {@link DalvInsn} instances.
+ */
+public final class DalvInsnList extends FixedSizeList {
+
+    /**
+     * The amount of register space, in register units, required for this
+     * code block. This may be greater than the largest observed register+
+     * category because the method this code block exists in may
+     * specify arguments that are unused by the method.
+     */
+    private final int regCount;
+
+    /**
+     * Constructs and returns an immutable instance whose elements are
+     * identical to the ones in the given list, in the same order.
+     *
+     * @param list {@code non-null;} the list to use for elements
+     * @param regCount count, in register-units, of the number of registers
+     * this code block requires.
+     * @return {@code non-null;} an appropriately-constructed instance of this
+     * class
+     */
+    public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list,
+            int regCount) {
+        int size = list.size();
+        DalvInsnList result = new DalvInsnList(size, regCount);
+
+        for (int i = 0; i < size; i++) {
+            result.set(i, list.get(i));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public DalvInsnList(int size, int regCount) {
+        super(size);
+        this.regCount = regCount;
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public DalvInsn get(int n) {
+        return (DalvInsn) get0(n);
+    }
+
+    /**
+     * Sets the instruction at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param insn {@code non-null;} the instruction to set at {@code n}
+     */
+    public void set(int n, DalvInsn insn) {
+        set0(n, insn);
+    }
+
+    /**
+     * Gets the size of this instance, in 16-bit code units. This will only
+     * return a meaningful result if the instructions in this instance all
+     * have valid addresses.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int codeSize() {
+        int sz = size();
+
+        if (sz == 0) {
+            return 0;
+        }
+
+        DalvInsn last = get(sz - 1);
+        return last.getNextAddress();
+    }
+
+    /**
+     * Writes all the instructions in this instance to the given output
+     * destination.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public void writeTo(AnnotatedOutput out) {
+        int startCursor = out.getCursor();
+        int sz = size();
+
+        if (out.annotates()) {
+            boolean verbose = out.isVerbose();
+
+            for (int i = 0; i < sz; i++) {
+                DalvInsn insn = (DalvInsn) get0(i);
+                int codeBytes = insn.codeSize() * 2;
+                String s;
+
+                if ((codeBytes != 0) || verbose) {
+                    s = insn.listingString("  ", out.getAnnotationWidth(),
+                            true);
+                } else {
+                    s = null;
+                }
+
+                if (s != null) {
+                    out.annotate(codeBytes, s);
+                } else if (codeBytes != 0) {
+                    out.annotate(codeBytes, "");
+                }
+            }
+        }
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = (DalvInsn) get0(i);
+            try {
+                insn.writeTo(out);
+            } catch (RuntimeException ex) {
+                throw ExceptionWithContext.withContext(ex,
+                        "...while writing " + insn);
+            }
+        }
+
+        // Sanity check of the amount written.
+        int written = (out.getCursor() - startCursor) / 2;
+        if (written != codeSize()) {
+            throw new RuntimeException("write length mismatch; expected " +
+                    codeSize() + " but actually wrote " + written);
+        }
+    }
+
+    /**
+     * 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 {@code >= 0;} the required registers size
+     */
+    public int getRegistersSize() {
+        return regCount;
+    }
+
+    /**
+     * Gets the size of the outgoing arguments area required by this
+     * method. This is equal to the largest argument word count of any
+     * method referred to by this instance.
+     *
+     * @return {@code >= 0;} the required outgoing arguments size
+     */
+    public int getOutsSize() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = (DalvInsn) get0(i);
+
+            if (!(insn instanceof CstInsn)) {
+                continue;
+            }
+
+            Constant cst = ((CstInsn) insn).getConstant();
+
+            if (!(cst instanceof CstBaseMethodRef)) {
+                continue;
+            }
+
+            boolean isStatic =
+                (insn.getOpcode().getFamily() == DalvOps.INVOKE_STATIC);
+            int count =
+                ((CstBaseMethodRef) cst).getParameterWordCount(isStatic);
+
+            if (count > result) {
+                result = count;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     * @param verbose whether to be verbose; verbose output includes
+     * lines for zero-size instructions and explicit constant pool indices
+     */
+    public void debugPrint(Writer out, String prefix, boolean verbose) {
+        IndentingWriter iw = new IndentingWriter(out, 0, prefix);
+        int sz = size();
+
+        try {
+            for (int i = 0; i < sz; i++) {
+                DalvInsn insn = (DalvInsn) get0(i);
+                String s;
+
+                if ((insn.codeSize() != 0) || verbose) {
+                    s = insn.listingString("", 0, verbose);
+                } else {
+                    s = null;
+                }
+
+                if (s != null) {
+                    iw.write(s);
+                }
+            }
+
+            iw.flush();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     * @param verbose whether to be verbose; verbose output includes
+     * lines for zero-size instructions
+     */
+    public void debugPrint(OutputStream out, String prefix, boolean verbose) {
+        Writer w = new OutputStreamWriter(out);
+        debugPrint(w, prefix, verbose);
+
+        try {
+            w.flush();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/DalvOps.java b/dexgen/src/com/android/dexgen/dex/code/DalvOps.java
new file mode 100644
index 0000000..1d051ea
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/DalvOps.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+/**
+ * All the Dalvik opcode value constants. See the related spec
+ * document for the meaning and instruction format of each opcode.
+ */
+public final class DalvOps {
+    /** pseudo-opcode used for nonstandard format "instructions" */
+    public static final int SPECIAL_FORMAT = -1;
+
+    /** minimum valid opcode value */
+    public static final int MIN_VALUE = -1;
+
+    /** maximum valid opcode value */
+    public static final int MAX_VALUE = 0xff;
+
+    // BEGIN(opcodes); GENERATED AUTOMATICALLY BY opcode-gen
+    public static final int NOP = 0x00;
+    public static final int MOVE = 0x01;
+    public static final int MOVE_FROM16 = 0x02;
+    public static final int MOVE_16 = 0x03;
+    public static final int MOVE_WIDE = 0x04;
+    public static final int MOVE_WIDE_FROM16 = 0x05;
+    public static final int MOVE_WIDE_16 = 0x06;
+    public static final int MOVE_OBJECT = 0x07;
+    public static final int MOVE_OBJECT_FROM16 = 0x08;
+    public static final int MOVE_OBJECT_16 = 0x09;
+    public static final int MOVE_RESULT = 0x0a;
+    public static final int MOVE_RESULT_WIDE = 0x0b;
+    public static final int MOVE_RESULT_OBJECT = 0x0c;
+    public static final int MOVE_EXCEPTION = 0x0d;
+    public static final int RETURN_VOID = 0x0e;
+    public static final int RETURN = 0x0f;
+    public static final int RETURN_WIDE = 0x10;
+    public static final int RETURN_OBJECT = 0x11;
+    public static final int CONST_4 = 0x12;
+    public static final int CONST_16 = 0x13;
+    public static final int CONST = 0x14;
+    public static final int CONST_HIGH16 = 0x15;
+    public static final int CONST_WIDE_16 = 0x16;
+    public static final int CONST_WIDE_32 = 0x17;
+    public static final int CONST_WIDE = 0x18;
+    public static final int CONST_WIDE_HIGH16 = 0x19;
+    public static final int CONST_STRING = 0x1a;
+    public static final int CONST_STRING_JUMBO = 0x1b;
+    public static final int CONST_CLASS = 0x1c;
+    public static final int MONITOR_ENTER = 0x1d;
+    public static final int MONITOR_EXIT = 0x1e;
+    public static final int CHECK_CAST = 0x1f;
+    public static final int INSTANCE_OF = 0x20;
+    public static final int ARRAY_LENGTH = 0x21;
+    public static final int NEW_INSTANCE = 0x22;
+    public static final int NEW_ARRAY = 0x23;
+    public static final int FILLED_NEW_ARRAY = 0x24;
+    public static final int FILLED_NEW_ARRAY_RANGE = 0x25;
+    public static final int FILL_ARRAY_DATA = 0x26;
+    public static final int THROW = 0x27;
+    public static final int GOTO = 0x28;
+    public static final int GOTO_16 = 0x29;
+    public static final int GOTO_32 = 0x2a;
+    public static final int PACKED_SWITCH = 0x2b;
+    public static final int SPARSE_SWITCH = 0x2c;
+    public static final int CMPL_FLOAT = 0x2d;
+    public static final int CMPG_FLOAT = 0x2e;
+    public static final int CMPL_DOUBLE = 0x2f;
+    public static final int CMPG_DOUBLE = 0x30;
+    public static final int CMP_LONG = 0x31;
+    public static final int IF_EQ = 0x32;
+    public static final int IF_NE = 0x33;
+    public static final int IF_LT = 0x34;
+    public static final int IF_GE = 0x35;
+    public static final int IF_GT = 0x36;
+    public static final int IF_LE = 0x37;
+    public static final int IF_EQZ = 0x38;
+    public static final int IF_NEZ = 0x39;
+    public static final int IF_LTZ = 0x3a;
+    public static final int IF_GEZ = 0x3b;
+    public static final int IF_GTZ = 0x3c;
+    public static final int IF_LEZ = 0x3d;
+    public static final int UNUSED_3E = 0x3e;
+    public static final int UNUSED_3F = 0x3f;
+    public static final int UNUSED_40 = 0x40;
+    public static final int UNUSED_41 = 0x41;
+    public static final int UNUSED_42 = 0x42;
+    public static final int UNUSED_43 = 0x43;
+    public static final int AGET = 0x44;
+    public static final int AGET_WIDE = 0x45;
+    public static final int AGET_OBJECT = 0x46;
+    public static final int AGET_BOOLEAN = 0x47;
+    public static final int AGET_BYTE = 0x48;
+    public static final int AGET_CHAR = 0x49;
+    public static final int AGET_SHORT = 0x4a;
+    public static final int APUT = 0x4b;
+    public static final int APUT_WIDE = 0x4c;
+    public static final int APUT_OBJECT = 0x4d;
+    public static final int APUT_BOOLEAN = 0x4e;
+    public static final int APUT_BYTE = 0x4f;
+    public static final int APUT_CHAR = 0x50;
+    public static final int APUT_SHORT = 0x51;
+    public static final int IGET = 0x52;
+    public static final int IGET_WIDE = 0x53;
+    public static final int IGET_OBJECT = 0x54;
+    public static final int IGET_BOOLEAN = 0x55;
+    public static final int IGET_BYTE = 0x56;
+    public static final int IGET_CHAR = 0x57;
+    public static final int IGET_SHORT = 0x58;
+    public static final int IPUT = 0x59;
+    public static final int IPUT_WIDE = 0x5a;
+    public static final int IPUT_OBJECT = 0x5b;
+    public static final int IPUT_BOOLEAN = 0x5c;
+    public static final int IPUT_BYTE = 0x5d;
+    public static final int IPUT_CHAR = 0x5e;
+    public static final int IPUT_SHORT = 0x5f;
+    public static final int SGET = 0x60;
+    public static final int SGET_WIDE = 0x61;
+    public static final int SGET_OBJECT = 0x62;
+    public static final int SGET_BOOLEAN = 0x63;
+    public static final int SGET_BYTE = 0x64;
+    public static final int SGET_CHAR = 0x65;
+    public static final int SGET_SHORT = 0x66;
+    public static final int SPUT = 0x67;
+    public static final int SPUT_WIDE = 0x68;
+    public static final int SPUT_OBJECT = 0x69;
+    public static final int SPUT_BOOLEAN = 0x6a;
+    public static final int SPUT_BYTE = 0x6b;
+    public static final int SPUT_CHAR = 0x6c;
+    public static final int SPUT_SHORT = 0x6d;
+    public static final int INVOKE_VIRTUAL = 0x6e;
+    public static final int INVOKE_SUPER = 0x6f;
+    public static final int INVOKE_DIRECT = 0x70;
+    public static final int INVOKE_STATIC = 0x71;
+    public static final int INVOKE_INTERFACE = 0x72;
+    public static final int UNUSED_73 = 0x73;
+    public static final int INVOKE_VIRTUAL_RANGE = 0x74;
+    public static final int INVOKE_SUPER_RANGE = 0x75;
+    public static final int INVOKE_DIRECT_RANGE = 0x76;
+    public static final int INVOKE_STATIC_RANGE = 0x77;
+    public static final int INVOKE_INTERFACE_RANGE = 0x78;
+    public static final int UNUSED_79 = 0x79;
+    public static final int UNUSED_7A = 0x7a;
+    public static final int NEG_INT = 0x7b;
+    public static final int NOT_INT = 0x7c;
+    public static final int NEG_LONG = 0x7d;
+    public static final int NOT_LONG = 0x7e;
+    public static final int NEG_FLOAT = 0x7f;
+    public static final int NEG_DOUBLE = 0x80;
+    public static final int INT_TO_LONG = 0x81;
+    public static final int INT_TO_FLOAT = 0x82;
+    public static final int INT_TO_DOUBLE = 0x83;
+    public static final int LONG_TO_INT = 0x84;
+    public static final int LONG_TO_FLOAT = 0x85;
+    public static final int LONG_TO_DOUBLE = 0x86;
+    public static final int FLOAT_TO_INT = 0x87;
+    public static final int FLOAT_TO_LONG = 0x88;
+    public static final int FLOAT_TO_DOUBLE = 0x89;
+    public static final int DOUBLE_TO_INT = 0x8a;
+    public static final int DOUBLE_TO_LONG = 0x8b;
+    public static final int DOUBLE_TO_FLOAT = 0x8c;
+    public static final int INT_TO_BYTE = 0x8d;
+    public static final int INT_TO_CHAR = 0x8e;
+    public static final int INT_TO_SHORT = 0x8f;
+    public static final int ADD_INT = 0x90;
+    public static final int SUB_INT = 0x91;
+    public static final int MUL_INT = 0x92;
+    public static final int DIV_INT = 0x93;
+    public static final int REM_INT = 0x94;
+    public static final int AND_INT = 0x95;
+    public static final int OR_INT = 0x96;
+    public static final int XOR_INT = 0x97;
+    public static final int SHL_INT = 0x98;
+    public static final int SHR_INT = 0x99;
+    public static final int USHR_INT = 0x9a;
+    public static final int ADD_LONG = 0x9b;
+    public static final int SUB_LONG = 0x9c;
+    public static final int MUL_LONG = 0x9d;
+    public static final int DIV_LONG = 0x9e;
+    public static final int REM_LONG = 0x9f;
+    public static final int AND_LONG = 0xa0;
+    public static final int OR_LONG = 0xa1;
+    public static final int XOR_LONG = 0xa2;
+    public static final int SHL_LONG = 0xa3;
+    public static final int SHR_LONG = 0xa4;
+    public static final int USHR_LONG = 0xa5;
+    public static final int ADD_FLOAT = 0xa6;
+    public static final int SUB_FLOAT = 0xa7;
+    public static final int MUL_FLOAT = 0xa8;
+    public static final int DIV_FLOAT = 0xa9;
+    public static final int REM_FLOAT = 0xaa;
+    public static final int ADD_DOUBLE = 0xab;
+    public static final int SUB_DOUBLE = 0xac;
+    public static final int MUL_DOUBLE = 0xad;
+    public static final int DIV_DOUBLE = 0xae;
+    public static final int REM_DOUBLE = 0xaf;
+    public static final int ADD_INT_2ADDR = 0xb0;
+    public static final int SUB_INT_2ADDR = 0xb1;
+    public static final int MUL_INT_2ADDR = 0xb2;
+    public static final int DIV_INT_2ADDR = 0xb3;
+    public static final int REM_INT_2ADDR = 0xb4;
+    public static final int AND_INT_2ADDR = 0xb5;
+    public static final int OR_INT_2ADDR = 0xb6;
+    public static final int XOR_INT_2ADDR = 0xb7;
+    public static final int SHL_INT_2ADDR = 0xb8;
+    public static final int SHR_INT_2ADDR = 0xb9;
+    public static final int USHR_INT_2ADDR = 0xba;
+    public static final int ADD_LONG_2ADDR = 0xbb;
+    public static final int SUB_LONG_2ADDR = 0xbc;
+    public static final int MUL_LONG_2ADDR = 0xbd;
+    public static final int DIV_LONG_2ADDR = 0xbe;
+    public static final int REM_LONG_2ADDR = 0xbf;
+    public static final int AND_LONG_2ADDR = 0xc0;
+    public static final int OR_LONG_2ADDR = 0xc1;
+    public static final int XOR_LONG_2ADDR = 0xc2;
+    public static final int SHL_LONG_2ADDR = 0xc3;
+    public static final int SHR_LONG_2ADDR = 0xc4;
+    public static final int USHR_LONG_2ADDR = 0xc5;
+    public static final int ADD_FLOAT_2ADDR = 0xc6;
+    public static final int SUB_FLOAT_2ADDR = 0xc7;
+    public static final int MUL_FLOAT_2ADDR = 0xc8;
+    public static final int DIV_FLOAT_2ADDR = 0xc9;
+    public static final int REM_FLOAT_2ADDR = 0xca;
+    public static final int ADD_DOUBLE_2ADDR = 0xcb;
+    public static final int SUB_DOUBLE_2ADDR = 0xcc;
+    public static final int MUL_DOUBLE_2ADDR = 0xcd;
+    public static final int DIV_DOUBLE_2ADDR = 0xce;
+    public static final int REM_DOUBLE_2ADDR = 0xcf;
+    public static final int ADD_INT_LIT16 = 0xd0;
+    public static final int RSUB_INT = 0xd1;
+    public static final int MUL_INT_LIT16 = 0xd2;
+    public static final int DIV_INT_LIT16 = 0xd3;
+    public static final int REM_INT_LIT16 = 0xd4;
+    public static final int AND_INT_LIT16 = 0xd5;
+    public static final int OR_INT_LIT16 = 0xd6;
+    public static final int XOR_INT_LIT16 = 0xd7;
+    public static final int ADD_INT_LIT8 = 0xd8;
+    public static final int RSUB_INT_LIT8 = 0xd9;
+    public static final int MUL_INT_LIT8 = 0xda;
+    public static final int DIV_INT_LIT8 = 0xdb;
+    public static final int REM_INT_LIT8 = 0xdc;
+    public static final int AND_INT_LIT8 = 0xdd;
+    public static final int OR_INT_LIT8 = 0xde;
+    public static final int XOR_INT_LIT8 = 0xdf;
+    public static final int SHL_INT_LIT8 = 0xe0;
+    public static final int SHR_INT_LIT8 = 0xe1;
+    public static final int USHR_INT_LIT8 = 0xe2;
+    public static final int UNUSED_E3 = 0xe3;
+    public static final int UNUSED_E4 = 0xe4;
+    public static final int UNUSED_E5 = 0xe5;
+    public static final int UNUSED_E6 = 0xe6;
+    public static final int UNUSED_E7 = 0xe7;
+    public static final int UNUSED_E8 = 0xe8;
+    public static final int UNUSED_E9 = 0xe9;
+    public static final int UNUSED_EA = 0xea;
+    public static final int UNUSED_EB = 0xeb;
+    public static final int UNUSED_EC = 0xec;
+    public static final int UNUSED_ED = 0xed;
+    public static final int UNUSED_EE = 0xee;
+    public static final int UNUSED_EF = 0xef;
+    public static final int UNUSED_F0 = 0xf0;
+    public static final int UNUSED_F1 = 0xf1;
+    public static final int UNUSED_F2 = 0xf2;
+    public static final int UNUSED_F3 = 0xf3;
+    public static final int UNUSED_F4 = 0xf4;
+    public static final int UNUSED_F5 = 0xf5;
+    public static final int UNUSED_F6 = 0xf6;
+    public static final int UNUSED_F7 = 0xf7;
+    public static final int UNUSED_F8 = 0xf8;
+    public static final int UNUSED_F9 = 0xf9;
+    public static final int UNUSED_FA = 0xfa;
+    public static final int UNUSED_FB = 0xfb;
+    public static final int UNUSED_FC = 0xfc;
+    public static final int UNUSED_FD = 0xfd;
+    public static final int UNUSED_FE = 0xfe;
+    public static final int UNUSED_FF = 0xff;
+    // END(opcodes)
+
+    /**
+     * This class is uninstantiable.
+     */
+    private DalvOps() {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/Dop.java b/dexgen/src/com/android/dexgen/dex/code/Dop.java
new file mode 100644
index 0000000..dc788f1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/Dop.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+/**
+ * Representation of an opcode.
+ */
+public final class Dop {
+    /** DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode value itself */
+    private final int opcode;
+
+    /** DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family */
+    private final int family;
+
+    /** {@code non-null;} the instruction format */
+    private final InsnFormat format;
+
+    /** whether this opcode uses a result register */
+    private final boolean hasResult;
+
+    /** {@code non-null;} the name */
+    private final String name;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode
+     * value itself
+     * @param family {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
+     * @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 {@code non-null;} the name
+     */
+    public Dop(int opcode, int family, InsnFormat format,
+               boolean hasResult, String name) {
+        if ((opcode < DalvOps.MIN_VALUE) || (opcode > DalvOps.MAX_VALUE)) {
+            throw new IllegalArgumentException("bogus opcode");
+        }
+
+        if ((family < DalvOps.MIN_VALUE) || (family > DalvOps.MAX_VALUE)) {
+            throw new IllegalArgumentException("bogus family");
+        }
+
+        if (format == null) {
+            throw new NullPointerException("format == null");
+        }
+
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        this.opcode = opcode;
+        this.family = family;
+        this.format = format;
+        this.hasResult = hasResult;
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * Gets the opcode value.
+     *
+     * @return {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode value
+     */
+    public int getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the opcode family. The opcode family is the unmarked (no
+     * "/...") opcode that has equivalent semantics to this one.
+     *
+     * @return {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
+     */
+    public int getFamily() {
+        return family;
+    }
+
+    /**
+     * Gets the instruction format.
+     *
+     * @return {@code non-null;} the instruction format
+     */
+    public InsnFormat getFormat() {
+        return format;
+    }
+
+    /**
+     * Returns whether this opcode uses a result register.
+     *
+     * @return {@code true} iff this opcode uses a result register
+     */
+    public boolean hasResult() {
+        return hasResult;
+    }
+
+    /**
+     * Gets the opcode name.
+     *
+     * @return {@code non-null;} the opcode name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the opcode for the opposite test of this instance. This is only
+     * valid for opcodes which are in fact tests.
+     *
+     * @return {@code non-null;} the opposite test
+     */
+    public Dop getOppositeTest() {
+        switch (opcode) {
+            case DalvOps.IF_EQ:  return Dops.IF_NE;
+            case DalvOps.IF_NE:  return Dops.IF_EQ;
+            case DalvOps.IF_LT:  return Dops.IF_GE;
+            case DalvOps.IF_GE:  return Dops.IF_LT;
+            case DalvOps.IF_GT:  return Dops.IF_LE;
+            case DalvOps.IF_LE:  return Dops.IF_GT;
+            case DalvOps.IF_EQZ: return Dops.IF_NEZ;
+            case DalvOps.IF_NEZ: return Dops.IF_EQZ;
+            case DalvOps.IF_LTZ: return Dops.IF_GEZ;
+            case DalvOps.IF_GEZ: return Dops.IF_LTZ;
+            case DalvOps.IF_GTZ: return Dops.IF_LEZ;
+            case DalvOps.IF_LEZ: return Dops.IF_GTZ;
+        }
+
+        throw new IllegalArgumentException("bogus opcode: " + this);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/Dops.java b/dexgen/src/com/android/dexgen/dex/code/Dops.java
new file mode 100644
index 0000000..afd21e3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/Dops.java
@@ -0,0 +1,1231 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.dex.code.form.Form10t;
+import com.android.dexgen.dex.code.form.Form10x;
+import com.android.dexgen.dex.code.form.Form11n;
+import com.android.dexgen.dex.code.form.Form11x;
+import com.android.dexgen.dex.code.form.Form12x;
+import com.android.dexgen.dex.code.form.Form20t;
+import com.android.dexgen.dex.code.form.Form21c;
+import com.android.dexgen.dex.code.form.Form21h;
+import com.android.dexgen.dex.code.form.Form21s;
+import com.android.dexgen.dex.code.form.Form21t;
+import com.android.dexgen.dex.code.form.Form22b;
+import com.android.dexgen.dex.code.form.Form22c;
+import com.android.dexgen.dex.code.form.Form22s;
+import com.android.dexgen.dex.code.form.Form22t;
+import com.android.dexgen.dex.code.form.Form22x;
+import com.android.dexgen.dex.code.form.Form23x;
+import com.android.dexgen.dex.code.form.Form30t;
+import com.android.dexgen.dex.code.form.Form31c;
+import com.android.dexgen.dex.code.form.Form31i;
+import com.android.dexgen.dex.code.form.Form31t;
+import com.android.dexgen.dex.code.form.Form32x;
+import com.android.dexgen.dex.code.form.Form35c;
+import com.android.dexgen.dex.code.form.Form3rc;
+import com.android.dexgen.dex.code.form.Form51l;
+import com.android.dexgen.dex.code.form.SpecialFormat;
+
+/**
+ * Standard instances of {@link Dop} and utility methods for getting
+ * them.
+ */
+public final class Dops {
+    /** {@code non-null;} array containing all the standard instances */
+    private static final Dop[] DOPS;
+
+    /**
+     * pseudo-opcode used for nonstandard formatted "instructions"
+     * (which are mostly not actually instructions, though they do
+     * appear in instruction lists)
+     */
+    public static final Dop SPECIAL_FORMAT =
+        new Dop(DalvOps.SPECIAL_FORMAT, DalvOps.SPECIAL_FORMAT,
+                SpecialFormat.THE_ONE, false, "<special>");
+
+    // BEGIN(dops); GENERATED AUTOMATICALLY BY opcode-gen
+    public static final Dop NOP =
+        new Dop(DalvOps.NOP, DalvOps.NOP,
+            Form10x.THE_ONE, false, "nop");
+
+    public static final Dop MOVE =
+        new Dop(DalvOps.MOVE, DalvOps.MOVE,
+            Form12x.THE_ONE, true, "move");
+
+    public static final Dop MOVE_FROM16 =
+        new Dop(DalvOps.MOVE_FROM16, DalvOps.MOVE,
+            Form22x.THE_ONE, true, "move/from16");
+
+    public static final Dop MOVE_16 =
+        new Dop(DalvOps.MOVE_16, DalvOps.MOVE,
+            Form32x.THE_ONE, true, "move/16");
+
+    public static final Dop MOVE_WIDE =
+        new Dop(DalvOps.MOVE_WIDE, DalvOps.MOVE_WIDE,
+            Form12x.THE_ONE, true, "move-wide");
+
+    public static final Dop MOVE_WIDE_FROM16 =
+        new Dop(DalvOps.MOVE_WIDE_FROM16, DalvOps.MOVE_WIDE,
+            Form22x.THE_ONE, true, "move-wide/from16");
+
+    public static final Dop MOVE_WIDE_16 =
+        new Dop(DalvOps.MOVE_WIDE_16, DalvOps.MOVE_WIDE,
+            Form32x.THE_ONE, true, "move-wide/16");
+
+    public static final Dop MOVE_OBJECT =
+        new Dop(DalvOps.MOVE_OBJECT, DalvOps.MOVE_OBJECT,
+            Form12x.THE_ONE, true, "move-object");
+
+    public static final Dop MOVE_OBJECT_FROM16 =
+        new Dop(DalvOps.MOVE_OBJECT_FROM16, DalvOps.MOVE_OBJECT,
+            Form22x.THE_ONE, true, "move-object/from16");
+
+    public static final Dop MOVE_OBJECT_16 =
+        new Dop(DalvOps.MOVE_OBJECT_16, DalvOps.MOVE_OBJECT,
+            Form32x.THE_ONE, true, "move-object/16");
+
+    public static final Dop MOVE_RESULT =
+        new Dop(DalvOps.MOVE_RESULT, DalvOps.MOVE_RESULT,
+            Form11x.THE_ONE, true, "move-result");
+
+    public static final Dop MOVE_RESULT_WIDE =
+        new Dop(DalvOps.MOVE_RESULT_WIDE, DalvOps.MOVE_RESULT_WIDE,
+            Form11x.THE_ONE, true, "move-result-wide");
+
+    public static final Dop MOVE_RESULT_OBJECT =
+        new Dop(DalvOps.MOVE_RESULT_OBJECT, DalvOps.MOVE_RESULT_OBJECT,
+            Form11x.THE_ONE, true, "move-result-object");
+
+    public static final Dop MOVE_EXCEPTION =
+        new Dop(DalvOps.MOVE_EXCEPTION, DalvOps.MOVE_EXCEPTION,
+            Form11x.THE_ONE, true, "move-exception");
+
+    public static final Dop RETURN_VOID =
+        new Dop(DalvOps.RETURN_VOID, DalvOps.RETURN_VOID,
+            Form10x.THE_ONE, false, "return-void");
+
+    public static final Dop RETURN =
+        new Dop(DalvOps.RETURN, DalvOps.RETURN,
+            Form11x.THE_ONE, false, "return");
+
+    public static final Dop RETURN_WIDE =
+        new Dop(DalvOps.RETURN_WIDE, DalvOps.RETURN_WIDE,
+            Form11x.THE_ONE, false, "return-wide");
+
+    public static final Dop RETURN_OBJECT =
+        new Dop(DalvOps.RETURN_OBJECT, DalvOps.RETURN_OBJECT,
+            Form11x.THE_ONE, false, "return-object");
+
+    public static final Dop CONST_4 =
+        new Dop(DalvOps.CONST_4, DalvOps.CONST,
+            Form11n.THE_ONE, true, "const/4");
+
+    public static final Dop CONST_16 =
+        new Dop(DalvOps.CONST_16, DalvOps.CONST,
+            Form21s.THE_ONE, true, "const/16");
+
+    public static final Dop CONST =
+        new Dop(DalvOps.CONST, DalvOps.CONST,
+            Form31i.THE_ONE, true, "const");
+
+    public static final Dop CONST_HIGH16 =
+        new Dop(DalvOps.CONST_HIGH16, DalvOps.CONST,
+            Form21h.THE_ONE, true, "const/high16");
+
+    public static final Dop CONST_WIDE_16 =
+        new Dop(DalvOps.CONST_WIDE_16, DalvOps.CONST_WIDE,
+            Form21s.THE_ONE, true, "const-wide/16");
+
+    public static final Dop CONST_WIDE_32 =
+        new Dop(DalvOps.CONST_WIDE_32, DalvOps.CONST_WIDE,
+            Form31i.THE_ONE, true, "const-wide/32");
+
+    public static final Dop CONST_WIDE =
+        new Dop(DalvOps.CONST_WIDE, DalvOps.CONST_WIDE,
+            Form51l.THE_ONE, true, "const-wide");
+
+    public static final Dop CONST_WIDE_HIGH16 =
+        new Dop(DalvOps.CONST_WIDE_HIGH16, DalvOps.CONST_WIDE,
+            Form21h.THE_ONE, true, "const-wide/high16");
+
+    public static final Dop CONST_STRING =
+        new Dop(DalvOps.CONST_STRING, DalvOps.CONST_STRING,
+            Form21c.THE_ONE, true, "const-string");
+
+    public static final Dop CONST_STRING_JUMBO =
+        new Dop(DalvOps.CONST_STRING_JUMBO, DalvOps.CONST_STRING,
+            Form31c.THE_ONE, true, "const-string/jumbo");
+
+    public static final Dop CONST_CLASS =
+        new Dop(DalvOps.CONST_CLASS, DalvOps.CONST_CLASS,
+            Form21c.THE_ONE, true, "const-class");
+
+    public static final Dop MONITOR_ENTER =
+        new Dop(DalvOps.MONITOR_ENTER, DalvOps.MONITOR_ENTER,
+            Form11x.THE_ONE, false, "monitor-enter");
+
+    public static final Dop MONITOR_EXIT =
+        new Dop(DalvOps.MONITOR_EXIT, DalvOps.MONITOR_EXIT,
+            Form11x.THE_ONE, false, "monitor-exit");
+
+    public static final Dop CHECK_CAST =
+        new Dop(DalvOps.CHECK_CAST, DalvOps.CHECK_CAST,
+            Form21c.THE_ONE, true, "check-cast");
+
+    public static final Dop INSTANCE_OF =
+        new Dop(DalvOps.INSTANCE_OF, DalvOps.INSTANCE_OF,
+            Form22c.THE_ONE, true, "instance-of");
+
+    public static final Dop ARRAY_LENGTH =
+        new Dop(DalvOps.ARRAY_LENGTH, DalvOps.ARRAY_LENGTH,
+            Form12x.THE_ONE, true, "array-length");
+
+    public static final Dop NEW_INSTANCE =
+        new Dop(DalvOps.NEW_INSTANCE, DalvOps.NEW_INSTANCE,
+            Form21c.THE_ONE, true, "new-instance");
+
+    public static final Dop NEW_ARRAY =
+        new Dop(DalvOps.NEW_ARRAY, DalvOps.NEW_ARRAY,
+            Form22c.THE_ONE, true, "new-array");
+
+    public static final Dop FILLED_NEW_ARRAY =
+        new Dop(DalvOps.FILLED_NEW_ARRAY, DalvOps.FILLED_NEW_ARRAY,
+            Form35c.THE_ONE, false, "filled-new-array");
+
+    public static final Dop FILLED_NEW_ARRAY_RANGE =
+        new Dop(DalvOps.FILLED_NEW_ARRAY_RANGE, DalvOps.FILLED_NEW_ARRAY,
+            Form3rc.THE_ONE, false, "filled-new-array/range");
+
+    public static final Dop FILL_ARRAY_DATA =
+        new Dop(DalvOps.FILL_ARRAY_DATA, DalvOps.FILL_ARRAY_DATA,
+            Form31t.THE_ONE, false, "fill-array-data");
+
+    public static final Dop THROW =
+        new Dop(DalvOps.THROW, DalvOps.THROW,
+            Form11x.THE_ONE, false, "throw");
+
+    public static final Dop GOTO =
+        new Dop(DalvOps.GOTO, DalvOps.GOTO,
+            Form10t.THE_ONE, false, "goto");
+
+    public static final Dop GOTO_16 =
+        new Dop(DalvOps.GOTO_16, DalvOps.GOTO,
+            Form20t.THE_ONE, false, "goto/16");
+
+    public static final Dop GOTO_32 =
+        new Dop(DalvOps.GOTO_32, DalvOps.GOTO,
+            Form30t.THE_ONE, false, "goto/32");
+
+    public static final Dop PACKED_SWITCH =
+        new Dop(DalvOps.PACKED_SWITCH, DalvOps.PACKED_SWITCH,
+            Form31t.THE_ONE, false, "packed-switch");
+
+    public static final Dop SPARSE_SWITCH =
+        new Dop(DalvOps.SPARSE_SWITCH, DalvOps.SPARSE_SWITCH,
+            Form31t.THE_ONE, false, "sparse-switch");
+
+    public static final Dop CMPL_FLOAT =
+        new Dop(DalvOps.CMPL_FLOAT, DalvOps.CMPL_FLOAT,
+            Form23x.THE_ONE, true, "cmpl-float");
+
+    public static final Dop CMPG_FLOAT =
+        new Dop(DalvOps.CMPG_FLOAT, DalvOps.CMPG_FLOAT,
+            Form23x.THE_ONE, true, "cmpg-float");
+
+    public static final Dop CMPL_DOUBLE =
+        new Dop(DalvOps.CMPL_DOUBLE, DalvOps.CMPL_DOUBLE,
+            Form23x.THE_ONE, true, "cmpl-double");
+
+    public static final Dop CMPG_DOUBLE =
+        new Dop(DalvOps.CMPG_DOUBLE, DalvOps.CMPG_DOUBLE,
+            Form23x.THE_ONE, true, "cmpg-double");
+
+    public static final Dop CMP_LONG =
+        new Dop(DalvOps.CMP_LONG, DalvOps.CMP_LONG,
+            Form23x.THE_ONE, true, "cmp-long");
+
+    public static final Dop IF_EQ =
+        new Dop(DalvOps.IF_EQ, DalvOps.IF_EQ,
+            Form22t.THE_ONE, false, "if-eq");
+
+    public static final Dop IF_NE =
+        new Dop(DalvOps.IF_NE, DalvOps.IF_NE,
+            Form22t.THE_ONE, false, "if-ne");
+
+    public static final Dop IF_LT =
+        new Dop(DalvOps.IF_LT, DalvOps.IF_LT,
+            Form22t.THE_ONE, false, "if-lt");
+
+    public static final Dop IF_GE =
+        new Dop(DalvOps.IF_GE, DalvOps.IF_GE,
+            Form22t.THE_ONE, false, "if-ge");
+
+    public static final Dop IF_GT =
+        new Dop(DalvOps.IF_GT, DalvOps.IF_GT,
+            Form22t.THE_ONE, false, "if-gt");
+
+    public static final Dop IF_LE =
+        new Dop(DalvOps.IF_LE, DalvOps.IF_LE,
+            Form22t.THE_ONE, false, "if-le");
+
+    public static final Dop IF_EQZ =
+        new Dop(DalvOps.IF_EQZ, DalvOps.IF_EQZ,
+            Form21t.THE_ONE, false, "if-eqz");
+
+    public static final Dop IF_NEZ =
+        new Dop(DalvOps.IF_NEZ, DalvOps.IF_NEZ,
+            Form21t.THE_ONE, false, "if-nez");
+
+    public static final Dop IF_LTZ =
+        new Dop(DalvOps.IF_LTZ, DalvOps.IF_LTZ,
+            Form21t.THE_ONE, false, "if-ltz");
+
+    public static final Dop IF_GEZ =
+        new Dop(DalvOps.IF_GEZ, DalvOps.IF_GEZ,
+            Form21t.THE_ONE, false, "if-gez");
+
+    public static final Dop IF_GTZ =
+        new Dop(DalvOps.IF_GTZ, DalvOps.IF_GTZ,
+            Form21t.THE_ONE, false, "if-gtz");
+
+    public static final Dop IF_LEZ =
+        new Dop(DalvOps.IF_LEZ, DalvOps.IF_LEZ,
+            Form21t.THE_ONE, false, "if-lez");
+
+    public static final Dop AGET =
+        new Dop(DalvOps.AGET, DalvOps.AGET,
+            Form23x.THE_ONE, true, "aget");
+
+    public static final Dop AGET_WIDE =
+        new Dop(DalvOps.AGET_WIDE, DalvOps.AGET_WIDE,
+            Form23x.THE_ONE, true, "aget-wide");
+
+    public static final Dop AGET_OBJECT =
+        new Dop(DalvOps.AGET_OBJECT, DalvOps.AGET_OBJECT,
+            Form23x.THE_ONE, true, "aget-object");
+
+    public static final Dop AGET_BOOLEAN =
+        new Dop(DalvOps.AGET_BOOLEAN, DalvOps.AGET_BOOLEAN,
+            Form23x.THE_ONE, true, "aget-boolean");
+
+    public static final Dop AGET_BYTE =
+        new Dop(DalvOps.AGET_BYTE, DalvOps.AGET_BYTE,
+            Form23x.THE_ONE, true, "aget-byte");
+
+    public static final Dop AGET_CHAR =
+        new Dop(DalvOps.AGET_CHAR, DalvOps.AGET_CHAR,
+            Form23x.THE_ONE, true, "aget-char");
+
+    public static final Dop AGET_SHORT =
+        new Dop(DalvOps.AGET_SHORT, DalvOps.AGET_SHORT,
+            Form23x.THE_ONE, true, "aget-short");
+
+    public static final Dop APUT =
+        new Dop(DalvOps.APUT, DalvOps.APUT,
+            Form23x.THE_ONE, false, "aput");
+
+    public static final Dop APUT_WIDE =
+        new Dop(DalvOps.APUT_WIDE, DalvOps.APUT_WIDE,
+            Form23x.THE_ONE, false, "aput-wide");
+
+    public static final Dop APUT_OBJECT =
+        new Dop(DalvOps.APUT_OBJECT, DalvOps.APUT_OBJECT,
+            Form23x.THE_ONE, false, "aput-object");
+
+    public static final Dop APUT_BOOLEAN =
+        new Dop(DalvOps.APUT_BOOLEAN, DalvOps.APUT_BOOLEAN,
+            Form23x.THE_ONE, false, "aput-boolean");
+
+    public static final Dop APUT_BYTE =
+        new Dop(DalvOps.APUT_BYTE, DalvOps.APUT_BYTE,
+            Form23x.THE_ONE, false, "aput-byte");
+
+    public static final Dop APUT_CHAR =
+        new Dop(DalvOps.APUT_CHAR, DalvOps.APUT_CHAR,
+            Form23x.THE_ONE, false, "aput-char");
+
+    public static final Dop APUT_SHORT =
+        new Dop(DalvOps.APUT_SHORT, DalvOps.APUT_SHORT,
+            Form23x.THE_ONE, false, "aput-short");
+
+    public static final Dop IGET =
+        new Dop(DalvOps.IGET, DalvOps.IGET,
+            Form22c.THE_ONE, true, "iget");
+
+    public static final Dop IGET_WIDE =
+        new Dop(DalvOps.IGET_WIDE, DalvOps.IGET_WIDE,
+            Form22c.THE_ONE, true, "iget-wide");
+
+    public static final Dop IGET_OBJECT =
+        new Dop(DalvOps.IGET_OBJECT, DalvOps.IGET_OBJECT,
+            Form22c.THE_ONE, true, "iget-object");
+
+    public static final Dop IGET_BOOLEAN =
+        new Dop(DalvOps.IGET_BOOLEAN, DalvOps.IGET_BOOLEAN,
+            Form22c.THE_ONE, true, "iget-boolean");
+
+    public static final Dop IGET_BYTE =
+        new Dop(DalvOps.IGET_BYTE, DalvOps.IGET_BYTE,
+            Form22c.THE_ONE, true, "iget-byte");
+
+    public static final Dop IGET_CHAR =
+        new Dop(DalvOps.IGET_CHAR, DalvOps.IGET_CHAR,
+            Form22c.THE_ONE, true, "iget-char");
+
+    public static final Dop IGET_SHORT =
+        new Dop(DalvOps.IGET_SHORT, DalvOps.IGET_SHORT,
+            Form22c.THE_ONE, true, "iget-short");
+
+    public static final Dop IPUT =
+        new Dop(DalvOps.IPUT, DalvOps.IPUT,
+            Form22c.THE_ONE, false, "iput");
+
+    public static final Dop IPUT_WIDE =
+        new Dop(DalvOps.IPUT_WIDE, DalvOps.IPUT_WIDE,
+            Form22c.THE_ONE, false, "iput-wide");
+
+    public static final Dop IPUT_OBJECT =
+        new Dop(DalvOps.IPUT_OBJECT, DalvOps.IPUT_OBJECT,
+            Form22c.THE_ONE, false, "iput-object");
+
+    public static final Dop IPUT_BOOLEAN =
+        new Dop(DalvOps.IPUT_BOOLEAN, DalvOps.IPUT_BOOLEAN,
+            Form22c.THE_ONE, false, "iput-boolean");
+
+    public static final Dop IPUT_BYTE =
+        new Dop(DalvOps.IPUT_BYTE, DalvOps.IPUT_BYTE,
+            Form22c.THE_ONE, false, "iput-byte");
+
+    public static final Dop IPUT_CHAR =
+        new Dop(DalvOps.IPUT_CHAR, DalvOps.IPUT_CHAR,
+            Form22c.THE_ONE, false, "iput-char");
+
+    public static final Dop IPUT_SHORT =
+        new Dop(DalvOps.IPUT_SHORT, DalvOps.IPUT_SHORT,
+            Form22c.THE_ONE, false, "iput-short");
+
+    public static final Dop SGET =
+        new Dop(DalvOps.SGET, DalvOps.SGET,
+            Form21c.THE_ONE, true, "sget");
+
+    public static final Dop SGET_WIDE =
+        new Dop(DalvOps.SGET_WIDE, DalvOps.SGET_WIDE,
+            Form21c.THE_ONE, true, "sget-wide");
+
+    public static final Dop SGET_OBJECT =
+        new Dop(DalvOps.SGET_OBJECT, DalvOps.SGET_OBJECT,
+            Form21c.THE_ONE, true, "sget-object");
+
+    public static final Dop SGET_BOOLEAN =
+        new Dop(DalvOps.SGET_BOOLEAN, DalvOps.SGET_BOOLEAN,
+            Form21c.THE_ONE, true, "sget-boolean");
+
+    public static final Dop SGET_BYTE =
+        new Dop(DalvOps.SGET_BYTE, DalvOps.SGET_BYTE,
+            Form21c.THE_ONE, true, "sget-byte");
+
+    public static final Dop SGET_CHAR =
+        new Dop(DalvOps.SGET_CHAR, DalvOps.SGET_CHAR,
+            Form21c.THE_ONE, true, "sget-char");
+
+    public static final Dop SGET_SHORT =
+        new Dop(DalvOps.SGET_SHORT, DalvOps.SGET_SHORT,
+            Form21c.THE_ONE, true, "sget-short");
+
+    public static final Dop SPUT =
+        new Dop(DalvOps.SPUT, DalvOps.SPUT,
+            Form21c.THE_ONE, false, "sput");
+
+    public static final Dop SPUT_WIDE =
+        new Dop(DalvOps.SPUT_WIDE, DalvOps.SPUT_WIDE,
+            Form21c.THE_ONE, false, "sput-wide");
+
+    public static final Dop SPUT_OBJECT =
+        new Dop(DalvOps.SPUT_OBJECT, DalvOps.SPUT_OBJECT,
+            Form21c.THE_ONE, false, "sput-object");
+
+    public static final Dop SPUT_BOOLEAN =
+        new Dop(DalvOps.SPUT_BOOLEAN, DalvOps.SPUT_BOOLEAN,
+            Form21c.THE_ONE, false, "sput-boolean");
+
+    public static final Dop SPUT_BYTE =
+        new Dop(DalvOps.SPUT_BYTE, DalvOps.SPUT_BYTE,
+            Form21c.THE_ONE, false, "sput-byte");
+
+    public static final Dop SPUT_CHAR =
+        new Dop(DalvOps.SPUT_CHAR, DalvOps.SPUT_CHAR,
+            Form21c.THE_ONE, false, "sput-char");
+
+    public static final Dop SPUT_SHORT =
+        new Dop(DalvOps.SPUT_SHORT, DalvOps.SPUT_SHORT,
+            Form21c.THE_ONE, false, "sput-short");
+
+    public static final Dop INVOKE_VIRTUAL =
+        new Dop(DalvOps.INVOKE_VIRTUAL, DalvOps.INVOKE_VIRTUAL,
+            Form35c.THE_ONE, false, "invoke-virtual");
+
+    public static final Dop INVOKE_SUPER =
+        new Dop(DalvOps.INVOKE_SUPER, DalvOps.INVOKE_SUPER,
+            Form35c.THE_ONE, false, "invoke-super");
+
+    public static final Dop INVOKE_DIRECT =
+        new Dop(DalvOps.INVOKE_DIRECT, DalvOps.INVOKE_DIRECT,
+            Form35c.THE_ONE, false, "invoke-direct");
+
+    public static final Dop INVOKE_STATIC =
+        new Dop(DalvOps.INVOKE_STATIC, DalvOps.INVOKE_STATIC,
+            Form35c.THE_ONE, false, "invoke-static");
+
+    public static final Dop INVOKE_INTERFACE =
+        new Dop(DalvOps.INVOKE_INTERFACE, DalvOps.INVOKE_INTERFACE,
+            Form35c.THE_ONE, false, "invoke-interface");
+
+    public static final Dop INVOKE_VIRTUAL_RANGE =
+        new Dop(DalvOps.INVOKE_VIRTUAL_RANGE, DalvOps.INVOKE_VIRTUAL,
+            Form3rc.THE_ONE, false, "invoke-virtual/range");
+
+    public static final Dop INVOKE_SUPER_RANGE =
+        new Dop(DalvOps.INVOKE_SUPER_RANGE, DalvOps.INVOKE_SUPER,
+            Form3rc.THE_ONE, false, "invoke-super/range");
+
+    public static final Dop INVOKE_DIRECT_RANGE =
+        new Dop(DalvOps.INVOKE_DIRECT_RANGE, DalvOps.INVOKE_DIRECT,
+            Form3rc.THE_ONE, false, "invoke-direct/range");
+
+    public static final Dop INVOKE_STATIC_RANGE =
+        new Dop(DalvOps.INVOKE_STATIC_RANGE, DalvOps.INVOKE_STATIC,
+            Form3rc.THE_ONE, false, "invoke-static/range");
+
+    public static final Dop INVOKE_INTERFACE_RANGE =
+        new Dop(DalvOps.INVOKE_INTERFACE_RANGE, DalvOps.INVOKE_INTERFACE,
+            Form3rc.THE_ONE, false, "invoke-interface/range");
+
+    public static final Dop NEG_INT =
+        new Dop(DalvOps.NEG_INT, DalvOps.NEG_INT,
+            Form12x.THE_ONE, true, "neg-int");
+
+    public static final Dop NOT_INT =
+        new Dop(DalvOps.NOT_INT, DalvOps.NOT_INT,
+            Form12x.THE_ONE, true, "not-int");
+
+    public static final Dop NEG_LONG =
+        new Dop(DalvOps.NEG_LONG, DalvOps.NEG_LONG,
+            Form12x.THE_ONE, true, "neg-long");
+
+    public static final Dop NOT_LONG =
+        new Dop(DalvOps.NOT_LONG, DalvOps.NOT_LONG,
+            Form12x.THE_ONE, true, "not-long");
+
+    public static final Dop NEG_FLOAT =
+        new Dop(DalvOps.NEG_FLOAT, DalvOps.NEG_FLOAT,
+            Form12x.THE_ONE, true, "neg-float");
+
+    public static final Dop NEG_DOUBLE =
+        new Dop(DalvOps.NEG_DOUBLE, DalvOps.NEG_DOUBLE,
+            Form12x.THE_ONE, true, "neg-double");
+
+    public static final Dop INT_TO_LONG =
+        new Dop(DalvOps.INT_TO_LONG, DalvOps.INT_TO_LONG,
+            Form12x.THE_ONE, true, "int-to-long");
+
+    public static final Dop INT_TO_FLOAT =
+        new Dop(DalvOps.INT_TO_FLOAT, DalvOps.INT_TO_FLOAT,
+            Form12x.THE_ONE, true, "int-to-float");
+
+    public static final Dop INT_TO_DOUBLE =
+        new Dop(DalvOps.INT_TO_DOUBLE, DalvOps.INT_TO_DOUBLE,
+            Form12x.THE_ONE, true, "int-to-double");
+
+    public static final Dop LONG_TO_INT =
+        new Dop(DalvOps.LONG_TO_INT, DalvOps.LONG_TO_INT,
+            Form12x.THE_ONE, true, "long-to-int");
+
+    public static final Dop LONG_TO_FLOAT =
+        new Dop(DalvOps.LONG_TO_FLOAT, DalvOps.LONG_TO_FLOAT,
+            Form12x.THE_ONE, true, "long-to-float");
+
+    public static final Dop LONG_TO_DOUBLE =
+        new Dop(DalvOps.LONG_TO_DOUBLE, DalvOps.LONG_TO_DOUBLE,
+            Form12x.THE_ONE, true, "long-to-double");
+
+    public static final Dop FLOAT_TO_INT =
+        new Dop(DalvOps.FLOAT_TO_INT, DalvOps.FLOAT_TO_INT,
+            Form12x.THE_ONE, true, "float-to-int");
+
+    public static final Dop FLOAT_TO_LONG =
+        new Dop(DalvOps.FLOAT_TO_LONG, DalvOps.FLOAT_TO_LONG,
+            Form12x.THE_ONE, true, "float-to-long");
+
+    public static final Dop FLOAT_TO_DOUBLE =
+        new Dop(DalvOps.FLOAT_TO_DOUBLE, DalvOps.FLOAT_TO_DOUBLE,
+            Form12x.THE_ONE, true, "float-to-double");
+
+    public static final Dop DOUBLE_TO_INT =
+        new Dop(DalvOps.DOUBLE_TO_INT, DalvOps.DOUBLE_TO_INT,
+            Form12x.THE_ONE, true, "double-to-int");
+
+    public static final Dop DOUBLE_TO_LONG =
+        new Dop(DalvOps.DOUBLE_TO_LONG, DalvOps.DOUBLE_TO_LONG,
+            Form12x.THE_ONE, true, "double-to-long");
+
+    public static final Dop DOUBLE_TO_FLOAT =
+        new Dop(DalvOps.DOUBLE_TO_FLOAT, DalvOps.DOUBLE_TO_FLOAT,
+            Form12x.THE_ONE, true, "double-to-float");
+
+    public static final Dop INT_TO_BYTE =
+        new Dop(DalvOps.INT_TO_BYTE, DalvOps.INT_TO_BYTE,
+            Form12x.THE_ONE, true, "int-to-byte");
+
+    public static final Dop INT_TO_CHAR =
+        new Dop(DalvOps.INT_TO_CHAR, DalvOps.INT_TO_CHAR,
+            Form12x.THE_ONE, true, "int-to-char");
+
+    public static final Dop INT_TO_SHORT =
+        new Dop(DalvOps.INT_TO_SHORT, DalvOps.INT_TO_SHORT,
+            Form12x.THE_ONE, true, "int-to-short");
+
+    public static final Dop ADD_INT =
+        new Dop(DalvOps.ADD_INT, DalvOps.ADD_INT,
+            Form23x.THE_ONE, true, "add-int");
+
+    public static final Dop SUB_INT =
+        new Dop(DalvOps.SUB_INT, DalvOps.SUB_INT,
+            Form23x.THE_ONE, true, "sub-int");
+
+    public static final Dop MUL_INT =
+        new Dop(DalvOps.MUL_INT, DalvOps.MUL_INT,
+            Form23x.THE_ONE, true, "mul-int");
+
+    public static final Dop DIV_INT =
+        new Dop(DalvOps.DIV_INT, DalvOps.DIV_INT,
+            Form23x.THE_ONE, true, "div-int");
+
+    public static final Dop REM_INT =
+        new Dop(DalvOps.REM_INT, DalvOps.REM_INT,
+            Form23x.THE_ONE, true, "rem-int");
+
+    public static final Dop AND_INT =
+        new Dop(DalvOps.AND_INT, DalvOps.AND_INT,
+            Form23x.THE_ONE, true, "and-int");
+
+    public static final Dop OR_INT =
+        new Dop(DalvOps.OR_INT, DalvOps.OR_INT,
+            Form23x.THE_ONE, true, "or-int");
+
+    public static final Dop XOR_INT =
+        new Dop(DalvOps.XOR_INT, DalvOps.XOR_INT,
+            Form23x.THE_ONE, true, "xor-int");
+
+    public static final Dop SHL_INT =
+        new Dop(DalvOps.SHL_INT, DalvOps.SHL_INT,
+            Form23x.THE_ONE, true, "shl-int");
+
+    public static final Dop SHR_INT =
+        new Dop(DalvOps.SHR_INT, DalvOps.SHR_INT,
+            Form23x.THE_ONE, true, "shr-int");
+
+    public static final Dop USHR_INT =
+        new Dop(DalvOps.USHR_INT, DalvOps.USHR_INT,
+            Form23x.THE_ONE, true, "ushr-int");
+
+    public static final Dop ADD_LONG =
+        new Dop(DalvOps.ADD_LONG, DalvOps.ADD_LONG,
+            Form23x.THE_ONE, true, "add-long");
+
+    public static final Dop SUB_LONG =
+        new Dop(DalvOps.SUB_LONG, DalvOps.SUB_LONG,
+            Form23x.THE_ONE, true, "sub-long");
+
+    public static final Dop MUL_LONG =
+        new Dop(DalvOps.MUL_LONG, DalvOps.MUL_LONG,
+            Form23x.THE_ONE, true, "mul-long");
+
+    public static final Dop DIV_LONG =
+        new Dop(DalvOps.DIV_LONG, DalvOps.DIV_LONG,
+            Form23x.THE_ONE, true, "div-long");
+
+    public static final Dop REM_LONG =
+        new Dop(DalvOps.REM_LONG, DalvOps.REM_LONG,
+            Form23x.THE_ONE, true, "rem-long");
+
+    public static final Dop AND_LONG =
+        new Dop(DalvOps.AND_LONG, DalvOps.AND_LONG,
+            Form23x.THE_ONE, true, "and-long");
+
+    public static final Dop OR_LONG =
+        new Dop(DalvOps.OR_LONG, DalvOps.OR_LONG,
+            Form23x.THE_ONE, true, "or-long");
+
+    public static final Dop XOR_LONG =
+        new Dop(DalvOps.XOR_LONG, DalvOps.XOR_LONG,
+            Form23x.THE_ONE, true, "xor-long");
+
+    public static final Dop SHL_LONG =
+        new Dop(DalvOps.SHL_LONG, DalvOps.SHL_LONG,
+            Form23x.THE_ONE, true, "shl-long");
+
+    public static final Dop SHR_LONG =
+        new Dop(DalvOps.SHR_LONG, DalvOps.SHR_LONG,
+            Form23x.THE_ONE, true, "shr-long");
+
+    public static final Dop USHR_LONG =
+        new Dop(DalvOps.USHR_LONG, DalvOps.USHR_LONG,
+            Form23x.THE_ONE, true, "ushr-long");
+
+    public static final Dop ADD_FLOAT =
+        new Dop(DalvOps.ADD_FLOAT, DalvOps.ADD_FLOAT,
+            Form23x.THE_ONE, true, "add-float");
+
+    public static final Dop SUB_FLOAT =
+        new Dop(DalvOps.SUB_FLOAT, DalvOps.SUB_FLOAT,
+            Form23x.THE_ONE, true, "sub-float");
+
+    public static final Dop MUL_FLOAT =
+        new Dop(DalvOps.MUL_FLOAT, DalvOps.MUL_FLOAT,
+            Form23x.THE_ONE, true, "mul-float");
+
+    public static final Dop DIV_FLOAT =
+        new Dop(DalvOps.DIV_FLOAT, DalvOps.DIV_FLOAT,
+            Form23x.THE_ONE, true, "div-float");
+
+    public static final Dop REM_FLOAT =
+        new Dop(DalvOps.REM_FLOAT, DalvOps.REM_FLOAT,
+            Form23x.THE_ONE, true, "rem-float");
+
+    public static final Dop ADD_DOUBLE =
+        new Dop(DalvOps.ADD_DOUBLE, DalvOps.ADD_DOUBLE,
+            Form23x.THE_ONE, true, "add-double");
+
+    public static final Dop SUB_DOUBLE =
+        new Dop(DalvOps.SUB_DOUBLE, DalvOps.SUB_DOUBLE,
+            Form23x.THE_ONE, true, "sub-double");
+
+    public static final Dop MUL_DOUBLE =
+        new Dop(DalvOps.MUL_DOUBLE, DalvOps.MUL_DOUBLE,
+            Form23x.THE_ONE, true, "mul-double");
+
+    public static final Dop DIV_DOUBLE =
+        new Dop(DalvOps.DIV_DOUBLE, DalvOps.DIV_DOUBLE,
+            Form23x.THE_ONE, true, "div-double");
+
+    public static final Dop REM_DOUBLE =
+        new Dop(DalvOps.REM_DOUBLE, DalvOps.REM_DOUBLE,
+            Form23x.THE_ONE, true, "rem-double");
+
+    public static final Dop ADD_INT_2ADDR =
+        new Dop(DalvOps.ADD_INT_2ADDR, DalvOps.ADD_INT,
+            Form12x.THE_ONE, true, "add-int/2addr");
+
+    public static final Dop SUB_INT_2ADDR =
+        new Dop(DalvOps.SUB_INT_2ADDR, DalvOps.SUB_INT,
+            Form12x.THE_ONE, true, "sub-int/2addr");
+
+    public static final Dop MUL_INT_2ADDR =
+        new Dop(DalvOps.MUL_INT_2ADDR, DalvOps.MUL_INT,
+            Form12x.THE_ONE, true, "mul-int/2addr");
+
+    public static final Dop DIV_INT_2ADDR =
+        new Dop(DalvOps.DIV_INT_2ADDR, DalvOps.DIV_INT,
+            Form12x.THE_ONE, true, "div-int/2addr");
+
+    public static final Dop REM_INT_2ADDR =
+        new Dop(DalvOps.REM_INT_2ADDR, DalvOps.REM_INT,
+            Form12x.THE_ONE, true, "rem-int/2addr");
+
+    public static final Dop AND_INT_2ADDR =
+        new Dop(DalvOps.AND_INT_2ADDR, DalvOps.AND_INT,
+            Form12x.THE_ONE, true, "and-int/2addr");
+
+    public static final Dop OR_INT_2ADDR =
+        new Dop(DalvOps.OR_INT_2ADDR, DalvOps.OR_INT,
+            Form12x.THE_ONE, true, "or-int/2addr");
+
+    public static final Dop XOR_INT_2ADDR =
+        new Dop(DalvOps.XOR_INT_2ADDR, DalvOps.XOR_INT,
+            Form12x.THE_ONE, true, "xor-int/2addr");
+
+    public static final Dop SHL_INT_2ADDR =
+        new Dop(DalvOps.SHL_INT_2ADDR, DalvOps.SHL_INT,
+            Form12x.THE_ONE, true, "shl-int/2addr");
+
+    public static final Dop SHR_INT_2ADDR =
+        new Dop(DalvOps.SHR_INT_2ADDR, DalvOps.SHR_INT,
+            Form12x.THE_ONE, true, "shr-int/2addr");
+
+    public static final Dop USHR_INT_2ADDR =
+        new Dop(DalvOps.USHR_INT_2ADDR, DalvOps.USHR_INT,
+            Form12x.THE_ONE, true, "ushr-int/2addr");
+
+    public static final Dop ADD_LONG_2ADDR =
+        new Dop(DalvOps.ADD_LONG_2ADDR, DalvOps.ADD_LONG,
+            Form12x.THE_ONE, true, "add-long/2addr");
+
+    public static final Dop SUB_LONG_2ADDR =
+        new Dop(DalvOps.SUB_LONG_2ADDR, DalvOps.SUB_LONG,
+            Form12x.THE_ONE, true, "sub-long/2addr");
+
+    public static final Dop MUL_LONG_2ADDR =
+        new Dop(DalvOps.MUL_LONG_2ADDR, DalvOps.MUL_LONG,
+            Form12x.THE_ONE, true, "mul-long/2addr");
+
+    public static final Dop DIV_LONG_2ADDR =
+        new Dop(DalvOps.DIV_LONG_2ADDR, DalvOps.DIV_LONG,
+            Form12x.THE_ONE, true, "div-long/2addr");
+
+    public static final Dop REM_LONG_2ADDR =
+        new Dop(DalvOps.REM_LONG_2ADDR, DalvOps.REM_LONG,
+            Form12x.THE_ONE, true, "rem-long/2addr");
+
+    public static final Dop AND_LONG_2ADDR =
+        new Dop(DalvOps.AND_LONG_2ADDR, DalvOps.AND_LONG,
+            Form12x.THE_ONE, true, "and-long/2addr");
+
+    public static final Dop OR_LONG_2ADDR =
+        new Dop(DalvOps.OR_LONG_2ADDR, DalvOps.OR_LONG,
+            Form12x.THE_ONE, true, "or-long/2addr");
+
+    public static final Dop XOR_LONG_2ADDR =
+        new Dop(DalvOps.XOR_LONG_2ADDR, DalvOps.XOR_LONG,
+            Form12x.THE_ONE, true, "xor-long/2addr");
+
+    public static final Dop SHL_LONG_2ADDR =
+        new Dop(DalvOps.SHL_LONG_2ADDR, DalvOps.SHL_LONG,
+            Form12x.THE_ONE, true, "shl-long/2addr");
+
+    public static final Dop SHR_LONG_2ADDR =
+        new Dop(DalvOps.SHR_LONG_2ADDR, DalvOps.SHR_LONG,
+            Form12x.THE_ONE, true, "shr-long/2addr");
+
+    public static final Dop USHR_LONG_2ADDR =
+        new Dop(DalvOps.USHR_LONG_2ADDR, DalvOps.USHR_LONG,
+            Form12x.THE_ONE, true, "ushr-long/2addr");
+
+    public static final Dop ADD_FLOAT_2ADDR =
+        new Dop(DalvOps.ADD_FLOAT_2ADDR, DalvOps.ADD_FLOAT,
+            Form12x.THE_ONE, true, "add-float/2addr");
+
+    public static final Dop SUB_FLOAT_2ADDR =
+        new Dop(DalvOps.SUB_FLOAT_2ADDR, DalvOps.SUB_FLOAT,
+            Form12x.THE_ONE, true, "sub-float/2addr");
+
+    public static final Dop MUL_FLOAT_2ADDR =
+        new Dop(DalvOps.MUL_FLOAT_2ADDR, DalvOps.MUL_FLOAT,
+            Form12x.THE_ONE, true, "mul-float/2addr");
+
+    public static final Dop DIV_FLOAT_2ADDR =
+        new Dop(DalvOps.DIV_FLOAT_2ADDR, DalvOps.DIV_FLOAT,
+            Form12x.THE_ONE, true, "div-float/2addr");
+
+    public static final Dop REM_FLOAT_2ADDR =
+        new Dop(DalvOps.REM_FLOAT_2ADDR, DalvOps.REM_FLOAT,
+            Form12x.THE_ONE, true, "rem-float/2addr");
+
+    public static final Dop ADD_DOUBLE_2ADDR =
+        new Dop(DalvOps.ADD_DOUBLE_2ADDR, DalvOps.ADD_DOUBLE,
+            Form12x.THE_ONE, true, "add-double/2addr");
+
+    public static final Dop SUB_DOUBLE_2ADDR =
+        new Dop(DalvOps.SUB_DOUBLE_2ADDR, DalvOps.SUB_DOUBLE,
+            Form12x.THE_ONE, true, "sub-double/2addr");
+
+    public static final Dop MUL_DOUBLE_2ADDR =
+        new Dop(DalvOps.MUL_DOUBLE_2ADDR, DalvOps.MUL_DOUBLE,
+            Form12x.THE_ONE, true, "mul-double/2addr");
+
+    public static final Dop DIV_DOUBLE_2ADDR =
+        new Dop(DalvOps.DIV_DOUBLE_2ADDR, DalvOps.DIV_DOUBLE,
+            Form12x.THE_ONE, true, "div-double/2addr");
+
+    public static final Dop REM_DOUBLE_2ADDR =
+        new Dop(DalvOps.REM_DOUBLE_2ADDR, DalvOps.REM_DOUBLE,
+            Form12x.THE_ONE, true, "rem-double/2addr");
+
+    public static final Dop ADD_INT_LIT16 =
+        new Dop(DalvOps.ADD_INT_LIT16, DalvOps.ADD_INT,
+            Form22s.THE_ONE, true, "add-int/lit16");
+
+    public static final Dop RSUB_INT =
+        new Dop(DalvOps.RSUB_INT, DalvOps.RSUB_INT,
+            Form22s.THE_ONE, true, "rsub-int");
+
+    public static final Dop MUL_INT_LIT16 =
+        new Dop(DalvOps.MUL_INT_LIT16, DalvOps.MUL_INT,
+            Form22s.THE_ONE, true, "mul-int/lit16");
+
+    public static final Dop DIV_INT_LIT16 =
+        new Dop(DalvOps.DIV_INT_LIT16, DalvOps.DIV_INT,
+            Form22s.THE_ONE, true, "div-int/lit16");
+
+    public static final Dop REM_INT_LIT16 =
+        new Dop(DalvOps.REM_INT_LIT16, DalvOps.REM_INT,
+            Form22s.THE_ONE, true, "rem-int/lit16");
+
+    public static final Dop AND_INT_LIT16 =
+        new Dop(DalvOps.AND_INT_LIT16, DalvOps.AND_INT,
+            Form22s.THE_ONE, true, "and-int/lit16");
+
+    public static final Dop OR_INT_LIT16 =
+        new Dop(DalvOps.OR_INT_LIT16, DalvOps.OR_INT,
+            Form22s.THE_ONE, true, "or-int/lit16");
+
+    public static final Dop XOR_INT_LIT16 =
+        new Dop(DalvOps.XOR_INT_LIT16, DalvOps.XOR_INT,
+            Form22s.THE_ONE, true, "xor-int/lit16");
+
+    public static final Dop ADD_INT_LIT8 =
+        new Dop(DalvOps.ADD_INT_LIT8, DalvOps.ADD_INT,
+            Form22b.THE_ONE, true, "add-int/lit8");
+
+    public static final Dop RSUB_INT_LIT8 =
+        new Dop(DalvOps.RSUB_INT_LIT8, DalvOps.RSUB_INT,
+            Form22b.THE_ONE, true, "rsub-int/lit8");
+
+    public static final Dop MUL_INT_LIT8 =
+        new Dop(DalvOps.MUL_INT_LIT8, DalvOps.MUL_INT,
+            Form22b.THE_ONE, true, "mul-int/lit8");
+
+    public static final Dop DIV_INT_LIT8 =
+        new Dop(DalvOps.DIV_INT_LIT8, DalvOps.DIV_INT,
+            Form22b.THE_ONE, true, "div-int/lit8");
+
+    public static final Dop REM_INT_LIT8 =
+        new Dop(DalvOps.REM_INT_LIT8, DalvOps.REM_INT,
+            Form22b.THE_ONE, true, "rem-int/lit8");
+
+    public static final Dop AND_INT_LIT8 =
+        new Dop(DalvOps.AND_INT_LIT8, DalvOps.AND_INT,
+            Form22b.THE_ONE, true, "and-int/lit8");
+
+    public static final Dop OR_INT_LIT8 =
+        new Dop(DalvOps.OR_INT_LIT8, DalvOps.OR_INT,
+            Form22b.THE_ONE, true, "or-int/lit8");
+
+    public static final Dop XOR_INT_LIT8 =
+        new Dop(DalvOps.XOR_INT_LIT8, DalvOps.XOR_INT,
+            Form22b.THE_ONE, true, "xor-int/lit8");
+
+    public static final Dop SHL_INT_LIT8 =
+        new Dop(DalvOps.SHL_INT_LIT8, DalvOps.SHL_INT,
+            Form22b.THE_ONE, true, "shl-int/lit8");
+
+    public static final Dop SHR_INT_LIT8 =
+        new Dop(DalvOps.SHR_INT_LIT8, DalvOps.SHR_INT,
+            Form22b.THE_ONE, true, "shr-int/lit8");
+
+    public static final Dop USHR_INT_LIT8 =
+        new Dop(DalvOps.USHR_INT_LIT8, DalvOps.USHR_INT,
+            Form22b.THE_ONE, true, "ushr-int/lit8");
+
+    // END(dops)
+
+    // Static initialization.
+    static {
+        DOPS = new Dop[DalvOps.MAX_VALUE - DalvOps.MIN_VALUE + 1];
+
+        set(SPECIAL_FORMAT);
+
+        // BEGIN(dops-init); GENERATED AUTOMATICALLY BY opcode-gen
+        set(NOP);
+        set(MOVE);
+        set(MOVE_FROM16);
+        set(MOVE_16);
+        set(MOVE_WIDE);
+        set(MOVE_WIDE_FROM16);
+        set(MOVE_WIDE_16);
+        set(MOVE_OBJECT);
+        set(MOVE_OBJECT_FROM16);
+        set(MOVE_OBJECT_16);
+        set(MOVE_RESULT);
+        set(MOVE_RESULT_WIDE);
+        set(MOVE_RESULT_OBJECT);
+        set(MOVE_EXCEPTION);
+        set(RETURN_VOID);
+        set(RETURN);
+        set(RETURN_WIDE);
+        set(RETURN_OBJECT);
+        set(CONST_4);
+        set(CONST_16);
+        set(CONST);
+        set(CONST_HIGH16);
+        set(CONST_WIDE_16);
+        set(CONST_WIDE_32);
+        set(CONST_WIDE);
+        set(CONST_WIDE_HIGH16);
+        set(CONST_STRING);
+        set(CONST_STRING_JUMBO);
+        set(CONST_CLASS);
+        set(MONITOR_ENTER);
+        set(MONITOR_EXIT);
+        set(CHECK_CAST);
+        set(INSTANCE_OF);
+        set(ARRAY_LENGTH);
+        set(NEW_INSTANCE);
+        set(NEW_ARRAY);
+        set(FILLED_NEW_ARRAY);
+        set(FILLED_NEW_ARRAY_RANGE);
+        set(FILL_ARRAY_DATA);
+        set(THROW);
+        set(GOTO);
+        set(GOTO_16);
+        set(GOTO_32);
+        set(PACKED_SWITCH);
+        set(SPARSE_SWITCH);
+        set(CMPL_FLOAT);
+        set(CMPG_FLOAT);
+        set(CMPL_DOUBLE);
+        set(CMPG_DOUBLE);
+        set(CMP_LONG);
+        set(IF_EQ);
+        set(IF_NE);
+        set(IF_LT);
+        set(IF_GE);
+        set(IF_GT);
+        set(IF_LE);
+        set(IF_EQZ);
+        set(IF_NEZ);
+        set(IF_LTZ);
+        set(IF_GEZ);
+        set(IF_GTZ);
+        set(IF_LEZ);
+        set(AGET);
+        set(AGET_WIDE);
+        set(AGET_OBJECT);
+        set(AGET_BOOLEAN);
+        set(AGET_BYTE);
+        set(AGET_CHAR);
+        set(AGET_SHORT);
+        set(APUT);
+        set(APUT_WIDE);
+        set(APUT_OBJECT);
+        set(APUT_BOOLEAN);
+        set(APUT_BYTE);
+        set(APUT_CHAR);
+        set(APUT_SHORT);
+        set(IGET);
+        set(IGET_WIDE);
+        set(IGET_OBJECT);
+        set(IGET_BOOLEAN);
+        set(IGET_BYTE);
+        set(IGET_CHAR);
+        set(IGET_SHORT);
+        set(IPUT);
+        set(IPUT_WIDE);
+        set(IPUT_OBJECT);
+        set(IPUT_BOOLEAN);
+        set(IPUT_BYTE);
+        set(IPUT_CHAR);
+        set(IPUT_SHORT);
+        set(SGET);
+        set(SGET_WIDE);
+        set(SGET_OBJECT);
+        set(SGET_BOOLEAN);
+        set(SGET_BYTE);
+        set(SGET_CHAR);
+        set(SGET_SHORT);
+        set(SPUT);
+        set(SPUT_WIDE);
+        set(SPUT_OBJECT);
+        set(SPUT_BOOLEAN);
+        set(SPUT_BYTE);
+        set(SPUT_CHAR);
+        set(SPUT_SHORT);
+        set(INVOKE_VIRTUAL);
+        set(INVOKE_SUPER);
+        set(INVOKE_DIRECT);
+        set(INVOKE_STATIC);
+        set(INVOKE_INTERFACE);
+        set(INVOKE_VIRTUAL_RANGE);
+        set(INVOKE_SUPER_RANGE);
+        set(INVOKE_DIRECT_RANGE);
+        set(INVOKE_STATIC_RANGE);
+        set(INVOKE_INTERFACE_RANGE);
+        set(NEG_INT);
+        set(NOT_INT);
+        set(NEG_LONG);
+        set(NOT_LONG);
+        set(NEG_FLOAT);
+        set(NEG_DOUBLE);
+        set(INT_TO_LONG);
+        set(INT_TO_FLOAT);
+        set(INT_TO_DOUBLE);
+        set(LONG_TO_INT);
+        set(LONG_TO_FLOAT);
+        set(LONG_TO_DOUBLE);
+        set(FLOAT_TO_INT);
+        set(FLOAT_TO_LONG);
+        set(FLOAT_TO_DOUBLE);
+        set(DOUBLE_TO_INT);
+        set(DOUBLE_TO_LONG);
+        set(DOUBLE_TO_FLOAT);
+        set(INT_TO_BYTE);
+        set(INT_TO_CHAR);
+        set(INT_TO_SHORT);
+        set(ADD_INT);
+        set(SUB_INT);
+        set(MUL_INT);
+        set(DIV_INT);
+        set(REM_INT);
+        set(AND_INT);
+        set(OR_INT);
+        set(XOR_INT);
+        set(SHL_INT);
+        set(SHR_INT);
+        set(USHR_INT);
+        set(ADD_LONG);
+        set(SUB_LONG);
+        set(MUL_LONG);
+        set(DIV_LONG);
+        set(REM_LONG);
+        set(AND_LONG);
+        set(OR_LONG);
+        set(XOR_LONG);
+        set(SHL_LONG);
+        set(SHR_LONG);
+        set(USHR_LONG);
+        set(ADD_FLOAT);
+        set(SUB_FLOAT);
+        set(MUL_FLOAT);
+        set(DIV_FLOAT);
+        set(REM_FLOAT);
+        set(ADD_DOUBLE);
+        set(SUB_DOUBLE);
+        set(MUL_DOUBLE);
+        set(DIV_DOUBLE);
+        set(REM_DOUBLE);
+        set(ADD_INT_2ADDR);
+        set(SUB_INT_2ADDR);
+        set(MUL_INT_2ADDR);
+        set(DIV_INT_2ADDR);
+        set(REM_INT_2ADDR);
+        set(AND_INT_2ADDR);
+        set(OR_INT_2ADDR);
+        set(XOR_INT_2ADDR);
+        set(SHL_INT_2ADDR);
+        set(SHR_INT_2ADDR);
+        set(USHR_INT_2ADDR);
+        set(ADD_LONG_2ADDR);
+        set(SUB_LONG_2ADDR);
+        set(MUL_LONG_2ADDR);
+        set(DIV_LONG_2ADDR);
+        set(REM_LONG_2ADDR);
+        set(AND_LONG_2ADDR);
+        set(OR_LONG_2ADDR);
+        set(XOR_LONG_2ADDR);
+        set(SHL_LONG_2ADDR);
+        set(SHR_LONG_2ADDR);
+        set(USHR_LONG_2ADDR);
+        set(ADD_FLOAT_2ADDR);
+        set(SUB_FLOAT_2ADDR);
+        set(MUL_FLOAT_2ADDR);
+        set(DIV_FLOAT_2ADDR);
+        set(REM_FLOAT_2ADDR);
+        set(ADD_DOUBLE_2ADDR);
+        set(SUB_DOUBLE_2ADDR);
+        set(MUL_DOUBLE_2ADDR);
+        set(DIV_DOUBLE_2ADDR);
+        set(REM_DOUBLE_2ADDR);
+        set(ADD_INT_LIT16);
+        set(RSUB_INT);
+        set(MUL_INT_LIT16);
+        set(DIV_INT_LIT16);
+        set(REM_INT_LIT16);
+        set(AND_INT_LIT16);
+        set(OR_INT_LIT16);
+        set(XOR_INT_LIT16);
+        set(ADD_INT_LIT8);
+        set(RSUB_INT_LIT8);
+        set(MUL_INT_LIT8);
+        set(DIV_INT_LIT8);
+        set(REM_INT_LIT8);
+        set(AND_INT_LIT8);
+        set(OR_INT_LIT8);
+        set(XOR_INT_LIT8);
+        set(SHL_INT_LIT8);
+        set(SHR_INT_LIT8);
+        set(USHR_INT_LIT8);
+        // END(dops-init)
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Dops() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the {@link Dop} for the given opcode value.
+     *
+     * @param opcode {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode value
+     * @return {@code non-null;} the associated opcode instance
+     */
+    public static Dop get(int opcode) {
+        int idx = opcode - DalvOps.MIN_VALUE;
+
+        try {
+            Dop result = DOPS[idx];
+            if (result != null) {
+                return result;
+            }
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Fall through.
+        }
+
+        throw new IllegalArgumentException("bogus opcode");
+    }
+
+    /**
+     * Gets the {@link Dop} with the given family/format combination, if
+     * any.
+     *
+     * @param family {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
+     * @param format {@code non-null;} the opcode's instruction format
+     * @return {@code null-ok;} the corresponding opcode, or {@code null} if
+     * there is none
+     */
+    public static Dop getOrNull(int family, InsnFormat format) {
+        if (format == null) {
+            throw new NullPointerException("format == null");
+        }
+
+        int len = DOPS.length;
+
+        // TODO: Linear search is bad.
+        for (int i = 0; i < len; i++) {
+            Dop dop = DOPS[i];
+            if ((dop != null) &&
+                (dop.getFamily() == family) &&
+                (dop.getFormat() == format)) {
+                return dop;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Puts the given opcode into the table of all ops.
+     *
+     * @param opcode {@code non-null;} the opcode
+     */
+    private static void set(Dop opcode) {
+        int idx = opcode.getOpcode() - DalvOps.MIN_VALUE;
+        DOPS[idx] = opcode;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/FixedSizeInsn.java b/dexgen/src/com/android/dexgen/dex/code/FixedSizeInsn.java
new file mode 100644
index 0000000..28d8986
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/FixedSizeInsn.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Base class for instructions which are of a fixed code size and which use {@link InsnFormat} methods to write themselves. This
+ * includes most &mdash; but not all &mdash; instructions.
+ */
+public abstract class FixedSizeInsn extends DalvInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * <p><b>Note:</b> In the unlikely event that an instruction takes
+     * absolutely no registers (e.g., a {@code nop} or a
+     * no-argument no-result * static method call), then the given
+     * register list may be passed as {@link
+     * RegisterSpecList#EMPTY}.</p>
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     */
+    public FixedSizeInsn(Dop opcode, SourcePosition position,
+                         RegisterSpecList registers) {
+        super(opcode, position, registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int codeSize() {
+        return getOpcode().getFormat().codeSize();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(AnnotatedOutput out) {
+        getOpcode().getFormat().writeTo(out, this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withRegisterOffset(int delta) {
+        return withRegisters(getRegisters().withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected final String listingString0(boolean noteIndices) {
+        return getOpcode().getFormat().listingString(this, noteIndices);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/HighRegisterPrefix.java b/dexgen/src/com/android/dexgen/dex/code/HighRegisterPrefix.java
new file mode 100644
index 0000000..08794ff
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/HighRegisterPrefix.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Combination instruction which turns into a variable number of
+ * {@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 {
+    /** {@code null-ok;} cached instructions, if constructed */
+    private SimpleInsn[] insns;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} source registers
+     */
+    public HighRegisterPrefix(SourcePosition position,
+                              RegisterSpecList registers) {
+        super(position, registers);
+
+        if (registers.size() == 0) {
+            throw new IllegalArgumentException("registers.size() == 0");
+        }
+
+        insns = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        int result = 0;
+
+        calculateInsnsIfNecessary();
+
+        for (SimpleInsn insn : insns) {
+            result += insn.codeSize();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        calculateInsnsIfNecessary();
+
+        for (SimpleInsn insn : insns) {
+            insn.writeTo(out);
+        }
+    }
+
+    /**
+     * Helper for {@link #codeSize} and {@link #writeTo} which sets up
+     * {@link #insns} if not already done.
+     */
+    private void calculateInsnsIfNecessary() {
+        if (insns != null) {
+            return;
+        }
+
+        RegisterSpecList registers = getRegisters();
+        int sz = registers.size();
+
+        insns = new SimpleInsn[sz];
+
+        for (int i = 0, outAt = 0; i < sz; i++) {
+            RegisterSpec src = registers.get(i);
+            insns[i] = moveInsnFor(src, outAt);
+            outAt += src.getCategory();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new HighRegisterPrefix(getPosition(), registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        RegisterSpecList registers = getRegisters();
+        int sz = registers.size();
+        StringBuffer sb = new StringBuffer(100);
+
+        for (int i = 0, outAt = 0; i < sz; i++) {
+            RegisterSpec src = registers.get(i);
+            SimpleInsn insn = moveInsnFor(src, outAt);
+
+            if (i != 0) {
+                sb.append('\n');
+            }
+
+            sb.append(insn.listingString0(noteIndices));
+
+            outAt += src.getCategory();
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns the proper move instruction for the given source spec
+     * and destination index.
+     *
+     * @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,
+                RegisterSpec.make(destIndex, src.getType()),
+                src);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/InsnFormat.java b/dexgen/src/com/android/dexgen/dex/code/InsnFormat.java
new file mode 100644
index 0000000..bd5b60d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/InsnFormat.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstInteger;
+import com.android.dexgen.rop.cst.CstKnownNull;
+import com.android.dexgen.rop.cst.CstLiteral64;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Base class for all instruction format handlers. Instruction format
+ * handlers know how to translate {@link DalvInsn} instances into
+ * streams of code words, as well as human-oriented listing strings
+ * representing such translations.
+ */
+public abstract class InsnFormat {
+    /**
+     * Returns the string form, suitable for inclusion in a listing
+     * dump, of the given instruction. The instruction must be of this
+     * instance's format for proper operation.
+     *
+     * @param insn {@code non-null;} the instruction
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @return {@code non-null;} the string form
+     */
+    public final String listingString(DalvInsn insn, boolean noteIndices) {
+        String op = insn.getOpcode().getName();
+        String arg = insnArgString(insn);
+        String comment = insnCommentString(insn, noteIndices);
+        StringBuilder sb = new StringBuilder(100);
+
+        sb.append(op);
+
+        if (arg.length() != 0) {
+            sb.append(' ');
+            sb.append(arg);
+        }
+
+        if (comment.length() != 0) {
+            sb.append(" // ");
+            sb.append(comment);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 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 ""}, not
+     * {@code null}.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @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 ""}, not
+     * {@code null}.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @param insn {@code non-null;} the instruction
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @return {@code non-null;} the string form
+     */
+    public abstract String insnCommentString(DalvInsn insn,
+            boolean noteIndices);
+
+    /**
+     * Gets the code size of instructions that use this format. The
+     * size is a number of 16-bit code units, not bytes. This should
+     * throw an exception if this format is of variable size.
+     *
+     * @return {@code >= 0;} the instruction length in 16-bit code units
+     */
+    public abstract int codeSize();
+
+    /**
+     * Returns whether or not the given instruction's arguments will
+     * fit in this instance's format. This includes such things as
+     * counting register arguments, checking register ranges, and
+     * making sure that additional arguments are of appropriate types
+     * and are in-range. If this format has a branch target but the
+     * instruction's branch offset is unknown, this method will simply
+     * not check the offset.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @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}
+     * for formats that don't include a branch offset.
+     *
+     * <p>The default implementation of this method always returns
+     * {@code false}. Subclasses must override this method if they
+     * include branch offsets.</p>
+     *
+     * @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;
+    }
+
+    /**
+     * Returns the next instruction format to try to match an instruction
+     * with, presuming that this instance isn't compatible, if any.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @return {@code null-ok;} the next format to try, or {@code null} if
+     * there are no suitable alternatives
+     */
+    public abstract InsnFormat nextUp();
+
+    /**
+     * Writes the code units for the given instruction to the given
+     * output destination. The instruction must be of this instance's format.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @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 {@code non-null;} the list of registers
+     * @return {@code non-null;} the string form
+     */
+    protected static String regListString(RegisterSpecList list) {
+        int sz = list.size();
+        StringBuffer sb = new StringBuffer(sz * 5 + 2);
+
+        sb.append('{');
+
+        for (int i = 0; i < sz; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(list.get(i).regString());
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a literal bits argument string.
+     *
+     * @param value the value
+     * @return {@code non-null;} the string form
+     */
+    protected static String literalBitsString(CstLiteralBits value) {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append('#');
+
+        if (value instanceof CstKnownNull) {
+            sb.append("null");
+        } else {
+            sb.append(value.typeName());
+            sb.append(' ');
+            sb.append(value.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a literal bits comment string.
+     *
+     * @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}
+     * @return {@code non-null;} the comment
+     */
+    protected static String literalBitsComment(CstLiteralBits value,
+            int width) {
+        StringBuffer sb = new StringBuffer(20);
+
+        sb.append("#");
+
+        long bits;
+
+        if (value instanceof CstLiteral64) {
+            bits = ((CstLiteral64) value).getLongBits();
+        } else {
+            bits = value.getIntBits();
+        }
+
+        switch (width) {
+            case 4:  sb.append(Hex.uNibble((int) bits)); break;
+            case 8:  sb.append(Hex.u1((int) bits));      break;
+            case 16: sb.append(Hex.u2((int) bits));      break;
+            case 32: sb.append(Hex.u4((int) bits));      break;
+            case 64: sb.append(Hex.u8(bits));            break;
+            default: {
+                throw new RuntimeException("shouldn't happen");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a branch address string.
+     *
+     * @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;
+        int address = ti.getTargetAddress();
+
+        return (address == (char) address) ? Hex.u2(address) : Hex.u4(address);
+    }
+
+    /**
+     * Helper method to return the comment for a branch.
+     *
+     * @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;
+        int offset = ti.getTargetOffset();
+
+        return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset);
+    }
+
+    /**
+     * Helper method to return a constant string.
+     *
+     * @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;
+        Constant cst = ci.getConstant();
+
+        return cst.toHuman();
+    }
+
+    /**
+     * Helper method to return an instruction comment for a 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;
+
+        if (! ci.hasIndex()) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder(20);
+        int index = ci.getIndex();
+
+        sb.append(ci.getConstant().typeName());
+        sb.append('@');
+
+        if (index < 65536) {
+            sb.append(Hex.u2(index));
+        } else {
+            sb.append(Hex.u4(index));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in a nibble.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -8..+7
+     */
+    protected static boolean signedFitsInNibble(int value) {
+        return (value >= -8) && (value <= 7);
+    }
+
+    /**
+     * Helper method to determine if an unsigned int value fits in a nibble.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range 0..0xf
+     */
+    protected static boolean unsignedFitsInNibble(int value) {
+        return value == (value & 0xf);
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in a byte.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -0x80..+0x7f
+     */
+    protected static boolean signedFitsInByte(int value) {
+        return (byte) value == value;
+    }
+
+    /**
+     * Helper method to determine if an unsigned int value fits in a byte.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range 0..0xff
+     */
+    protected static boolean unsignedFitsInByte(int value) {
+        return value == (value & 0xff);
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in a short.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -0x8000..+0x7fff
+     */
+    protected static boolean signedFitsInShort(int value) {
+        return (short) value == value;
+    }
+
+    /**
+     * Helper method to determine if an unsigned int value fits in a short.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range 0..0xffff
+     */
+    protected static boolean unsignedFitsInShort(int value) {
+        return value == (value & 0xffff);
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in three bytes.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -0x800000..+0x7fffff
+     */
+    protected static boolean signedFitsIn3Bytes(int value) {
+        return value == ((value << 8) >> 8);
+    }
+
+    /**
+     * Helper method to extract the callout-argument index from an
+     * appropriate instruction.
+     *
+     * @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();
+
+        if (arg < 0) {
+            throw new IllegalArgumentException("bogus insn");
+        }
+
+        return arg;
+    }
+
+    /**
+     * Helper method to combine an opcode and a second byte of data into
+     * the appropriate form for emitting into a code buffer.
+     *
+     * @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) {
+        if ((arg & 0xff) != arg) {
+            throw new IllegalArgumentException("arg out of range 0..255");
+        }
+
+        int opcode = insn.getOpcode().getOpcode();
+
+        if ((opcode & 0xff) != opcode) {
+            throw new IllegalArgumentException("opcode out of range 0..255");
+        }
+
+        return (short) (opcode | (arg << 8));
+    }
+
+    /**
+     * Helper method to combine two bytes into a code unit.
+     *
+     * @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) {
+        if ((low & 0xff) != low) {
+            throw new IllegalArgumentException("low out of range 0..255");
+        }
+
+        if ((high & 0xff) != high) {
+            throw new IllegalArgumentException("high out of range 0..255");
+        }
+
+        return (short) (low | (high << 8));
+    }
+
+    /**
+     * Helper method to combine four nibbles into a code unit.
+     *
+     * @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) {
+        if ((n0 & 0xf) != n0) {
+            throw new IllegalArgumentException("n0 out of range 0..15");
+        }
+
+        if ((n1 & 0xf) != n1) {
+            throw new IllegalArgumentException("n1 out of range 0..15");
+        }
+
+        if ((n2 & 0xf) != n2) {
+            throw new IllegalArgumentException("n2 out of range 0..15");
+        }
+
+        if ((n3 & 0xf) != n3) {
+            throw new IllegalArgumentException("n3 out of range 0..15");
+        }
+
+        return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12));
+    }
+
+    /**
+     * Helper method to combine two nibbles into a byte.
+     *
+     * @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) {
+            throw new IllegalArgumentException("low out of range 0..15");
+        }
+
+        if ((high & 0xf) != high) {
+            throw new IllegalArgumentException("high out of range 0..15");
+        }
+
+        return low | (high << 4);
+    }
+
+    /**
+     * Writes one code unit to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0) {
+        out.writeShort(c0);
+    }
+
+    /**
+     * Writes two code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+    }
+
+    /**
+     * Writes three code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+                                short c2) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+    }
+
+    /**
+     * Writes four code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     * @param c3 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+                                short c2, short c3) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+        out.writeShort(c3);
+    }
+
+    /**
+     * Writes five code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     * @param c3 code unit to write
+     * @param c4 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+                                short c2, short c3, short c4) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+        out.writeShort(c3);
+        out.writeShort(c4);
+    }
+
+    /**
+     * Writes six code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     * @param c3 code unit to write
+     * @param c4 code unit to write
+     * @param c5 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+                                short c2, short c3, short c4, short c5) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+        out.writeShort(c3);
+        out.writeShort(c4);
+        out.writeShort(c5);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/LocalEnd.java b/dexgen/src/com/android/dexgen/dex/code/LocalEnd.java
new file mode 100644
index 0000000..130b08b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/LocalEnd.java
@@ -0,0 +1,90 @@
+/*
+ * 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.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to explicitly end the mapping of a
+ * register to a named local variable. That is, an instance of this
+ * class in an instruction stream indicates that starting with the
+ * subsequent instruction, the indicated variable is no longer valid.
+ */
+public final class LocalEnd extends ZeroSizeInsn {
+    /**
+     * {@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
+     * will check the other info for consistency.
+     */
+    private final RegisterSpec local;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param local {@code non-null;} register spec representing the local
+     * variable introduced by this instance
+     */
+    public LocalEnd(SourcePosition position, RegisterSpec local) {
+        super(position);
+
+        if (local == null) {
+            throw new NullPointerException("local == null");
+        }
+
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return new LocalEnd(getPosition(), local.withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new LocalEnd(getPosition(), local);
+    }
+
+    /**
+     * Gets the register spec representing the local variable ended
+     * by this instance.
+     *
+     * @return {@code non-null;} the register spec
+     */
+    public RegisterSpec getLocal() {
+        return local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return local.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        return "local-end " + LocalStart.localString(local);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/LocalList.java b/dexgen/src/com/android/dexgen/dex/code/LocalList.java
new file mode 100644
index 0000000..c1c3921
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/LocalList.java
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecSet;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.FixedSizeList;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * List of local variables. Each local variable entry indicates a
+ * range of code which it is valid for, a register number, a name,
+ * and a type.
+ */
+public final class LocalList extends FixedSizeList {
+    /** {@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}.
+     *
+     * @param size {@code >= 0;} the size of the list
+     */
+    public LocalList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     */
+    public void debugPrint(PrintStream out, String prefix) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            out.print(prefix);
+            out.println(get(i));
+        }
+    }
+
+    /**
+     * Disposition of a local entry.
+     */
+    public static enum Disposition {
+        /** local started (introduced) */
+        START,
+
+        /** local ended without being replaced */
+        END_SIMPLY,
+
+        /** local ended because it was directly replaced */
+        END_REPLACED,
+
+        /** local ended because it was moved to a different register */
+        END_MOVED,
+
+        /**
+         * local ended because the previous local clobbered this one
+         * (because it is category-2)
+         */
+        END_CLOBBERED_BY_PREV,
+
+        /**
+         * local ended because the next local clobbered this one
+         * (because this one is a category-2)
+         */
+        END_CLOBBERED_BY_NEXT;
+    }
+
+    /**
+     * Entry in a local list.
+     */
+    public static class Entry implements Comparable<Entry> {
+        /** {@code >= 0;} address */
+        private final int address;
+
+        /** {@code non-null;} disposition of the local */
+        private final Disposition disposition;
+
+        /** {@code non-null;} register spec representing the variable */
+        private final RegisterSpec spec;
+
+        /** {@code non-null;} variable type (derived from {@code spec}) */
+        private final CstType type;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("address < 0");
+            }
+
+            if (disposition == null) {
+                throw new NullPointerException("disposition == null");
+            }
+
+            try {
+                if (spec.getLocalItem() == null) {
+                    throw new NullPointerException(
+                            "spec.getLocalItem() == null");
+                }
+            } catch (NullPointerException ex) {
+                // Elucidate the exception.
+                throw new NullPointerException("spec == null");
+            }
+
+            this.address = address;
+            this.disposition = disposition;
+            this.spec = spec;
+            this.type = CstType.intern(spec.getType());
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            return Integer.toHexString(address) + " " + disposition + " " +
+                spec;
+        }
+
+        /** {@inheritDoc} */
+        public boolean equals(Object other) {
+            if (!(other instanceof Entry)) {
+                return false;
+            }
+
+            return (compareTo((Entry) other) == 0);
+        }
+
+        /**
+         * Compares by (in priority order) address, end then start
+         * disposition (variants of end are all consistered
+         * equivalent), and spec.
+         *
+         * @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) {
+                return -1;
+            } else if (address > other.address) {
+                return 1;
+            }
+
+            boolean thisIsStart = isStart();
+            boolean otherIsStart = other.isStart();
+
+            if (thisIsStart != otherIsStart) {
+                return thisIsStart ? 1 : -1;
+            }
+
+            return spec.compareTo(other.spec);
+        }
+
+        /**
+         * Gets the address.
+         *
+         * @return {@code >= 0;} the address
+         */
+        public int getAddress() {
+            return address;
+        }
+
+        /**
+         * Gets the disposition.
+         *
+         * @return {@code non-null;} the disposition
+         */
+        public Disposition getDisposition() {
+            return disposition;
+        }
+
+        /**
+         * 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() {
+            return disposition == Disposition.START;
+        }
+
+        /**
+         * Gets the variable name.
+         *
+         * @return {@code null-ok;} the variable name
+         */
+        public CstUtf8 getName() {
+            return spec.getLocalItem().getName();
+        }
+
+        /**
+         * Gets the variable signature.
+         *
+         * @return {@code null-ok;} the variable signature
+         */
+        public CstUtf8 getSignature() {
+            return spec.getLocalItem().getSignature();
+        }
+
+        /**
+         * Gets the variable's type.
+         *
+         * @return {@code non-null;} the type
+         */
+        public CstType getType() {
+            return type;
+        }
+
+        /**
+         * Gets the number of the register holding the variable.
+         *
+         * @return {@code >= 0;} the number of the register holding
+         * the variable
+         */
+        public int getRegister() {
+            return spec.getReg();
+        }
+
+        /**
+         * Gets the RegisterSpec of the register holding the variable.
+         *
+         * @return {@code non-null;} RegisterSpec of the holding register.
+         */
+        public RegisterSpec getRegisterSpec() {
+            return spec;
+        }
+
+        /**
+         * Returns whether or not this instance matches the given spec.
+         *
+         * @param otherSpec {@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);
+        }
+
+        /**
+         * Returns whether or not this instance matches the spec in
+         * the given instance.
+         *
+         * @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);
+        }
+
+        /**
+         * Returns an instance just like this one but with the disposition
+         * 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 {@code non-null;} instructions to convert
+     * @return {@code non-null;} the constructed list
+     */
+    public static LocalList make(DalvInsnList insns) {
+        int sz = insns.size();
+
+        /*
+         * Go through the insn list, looking for all the local
+         * variable pseudoinstructions, splitting out LocalSnapshots
+         * 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).
+         *
+         * 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
+         * info explicitly into the rop layer rather than only trying
+         * to infer it. So, given that expectation, this code is
+         * written to deal with them.
+         */
+
+        MakeState state = new MakeState(sz);
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = insns.get(i);
+
+            if (insn instanceof LocalSnapshot) {
+                RegisterSpecSet snapshot =
+                    ((LocalSnapshot) insn).getLocals();
+                state.snapshot(insn.getAddress(), snapshot);
+            } else if (insn instanceof LocalStart) {
+                RegisterSpec local = ((LocalStart) insn).getLocal();
+                state.startLocal(insn.getAddress(), local);
+            } else if (insn instanceof LocalEnd) {
+                RegisterSpec local = ((LocalEnd) insn).getLocal();
+                state.endLocal(insn.getAddress(), local);
+            }
+        }
+
+        LocalList result = state.finish();
+
+        if (DEBUG) {
+            debugVerify(result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Debugging helper that verifies the constraint that a list doesn't
+     * contain any redundant local starts and that local ends that are
+     * due to replacements are properly annotated.
+     */
+    private static void debugVerify(LocalList locals) {
+        try {
+            debugVerify0(locals);
+        } catch (RuntimeException ex) {
+            int sz = locals.size();
+            for (int i = 0; i < sz; i++) {
+                System.err.println(locals.get(i));
+            }
+            throw ex;
+        }
+
+    }
+
+    /**
+     * Helper for {@link #debugVerify} which does most of the work.
+     */
+    private static void debugVerify0(LocalList locals) {
+        int sz = locals.size();
+        Entry[] active = new Entry[65536];
+
+        for (int i = 0; i < sz; i++) {
+            Entry e = locals.get(i);
+            int reg = e.getRegister();
+
+            if (e.isStart()) {
+                Entry already = active[reg];
+
+                if ((already != null) && e.matches(already)) {
+                    throw new RuntimeException("redundant start at " +
+                            Integer.toHexString(e.getAddress()) + ": got " +
+                            e + "; had " + already);
+                }
+
+                active[reg] = e;
+            } else {
+                if (active[reg] == null) {
+                    throw new RuntimeException("redundant end at " +
+                            Integer.toHexString(e.getAddress()));
+                }
+
+                int addr = e.getAddress();
+                boolean foundStart = false;
+
+                for (int j = i + 1; j < sz; j++) {
+                    Entry test = locals.get(j);
+                    if (test.getAddress() != addr) {
+                        break;
+                    }
+                    if (test.getRegisterSpec().getReg() == reg) {
+                        if (test.isStart()) {
+                            if (e.getDisposition()
+                                    != Disposition.END_REPLACED) {
+                                throw new RuntimeException(
+                                        "improperly marked end at " +
+                                        Integer.toHexString(addr));
+                            }
+                            foundStart = true;
+                        } else {
+                            throw new RuntimeException(
+                                    "redundant end at " +
+                                    Integer.toHexString(addr));
+                        }
+                    }
+                }
+
+                if (!foundStart &&
+                        (e.getDisposition() == Disposition.END_REPLACED)) {
+                    throw new RuntimeException(
+                            "improper end replacement claim at " +
+                            Integer.toHexString(addr));
+                }
+
+                active[reg] = null;
+            }
+        }
+    }
+
+    /**
+     * Intermediate state when constructing a local list.
+     */
+    public static class MakeState {
+        /** {@code non-null;} result being collected */
+        private final ArrayList<Entry> result;
+
+        /**
+         * {@code >= 0;} running count of nulled result entries, to help with
+         * sizing the final list
+         */
+        private int nullResultCount;
+
+        /** {@code null-ok;} current register mappings */
+        private RegisterSpecSet regs;
+
+        /** {@code null-ok;} result indices where local ends are stored */
+        private int[] endIndices;
+
+        /** {@code >= 0;} last address seen */
+        private int lastAddress;
+
+        /**
+         * Constructs an instance.
+         */
+        public MakeState(int initialSize) {
+            result = new ArrayList<Entry>(initialSize);
+            nullResultCount = 0;
+            regs = null;
+            endIndices = null;
+            lastAddress = 0;
+        }
+
+        /**
+         * Checks the address and other vitals as a prerequisite to
+         * further processing.
+         *
+         * @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;
+            }
+
+            if (address < lastAddress) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            if (first || (reg >= endIndices.length)) {
+                /*
+                 * This is the first allocation of the state set and
+                 * index array, or we need to grow. (The latter doesn't
+                 * happen much; in fact, we have only ever observed
+                 * it happening in test cases, never in "real" code.)
+                 */
+                int newSz = reg + 1;
+                RegisterSpecSet newRegs = new RegisterSpecSet(newSz);
+                int[] newEnds = new int[newSz];
+                Arrays.fill(newEnds, -1);
+
+                if (!first) {
+                    newRegs.putAll(regs);
+                    System.arraycopy(endIndices, 0, newEnds, 0,
+                            endIndices.length);
+                }
+
+                regs = newRegs;
+                endIndices = newEnds;
+            }
+        }
+
+        /**
+         * 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 {@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);
+
+            for (int i = 0; i < sz; i++) {
+                RegisterSpec oldSpec = regs.get(i);
+                RegisterSpec newSpec = filterSpec(specs.get(i));
+
+                if (oldSpec == null) {
+                    if (newSpec != null) {
+                        startLocal(address, newSpec);
+                    }
+                } else if (newSpec == null) {
+                    endLocal(address, oldSpec);
+                } else if (! newSpec.equalsUsingSimpleType(oldSpec)) {
+                    endLocal(address, oldSpec);
+                    startLocal(address, newSpec);
+                }
+            }
+
+            if (DEBUG) {
+                System.err.printf("%04x snapshot done\n", address);
+            }
+        }
+
+        /**
+         * Starts a local at the given address.
+         *
+         * @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);
+            aboutToProcess(address, regNum);
+
+            RegisterSpec existingLocal = regs.get(regNum);
+
+            if (startedLocal.equalsUsingSimpleType(existingLocal)) {
+                // Silently ignore a redundant start.
+                return;
+            }
+
+            RegisterSpec movedLocal = regs.findMatchingLocal(startedLocal);
+            if (movedLocal != null) {
+                /*
+                 * The same variable was moved from one register to another.
+                 * So add an end for its old location.
+                 */
+                addOrUpdateEnd(address, Disposition.END_MOVED, movedLocal);
+            }
+
+            int endAt = endIndices[regNum];
+
+            if (existingLocal != null) {
+                /*
+                 * There is an existing (but non-matching) local.
+                 * Add an explicit end for it.
+                 */
+                add(address, Disposition.END_REPLACED, existingLocal);
+            } else if (endAt >= 0) {
+                /*
+                 * Look for an end local for the same register at the
+                 * same address. If found, then update it or delete
+                 * it, depending on whether or not it represents the
+                 * same variable as the one being started.
+                 */
+                Entry endEntry = result.get(endAt);
+                if (endEntry.getAddress() == address) {
+                    if (endEntry.matches(startedLocal)) {
+                        /*
+                         * There was already an end local for the same
+                         * variable at the same address. This turns
+                         * out to be superfluous, as we are starting
+                         * up the exact same local. This situation can
+                         * happen when a single local variable got
+                         * somehow "split up" during intermediate
+                         * processing. In any case, rather than represent
+                         * the end-then-start, just remove the old end.
+                         */
+                        result.set(endAt, null);
+                        nullResultCount++;
+                        regs.put(startedLocal);
+                        endIndices[regNum] = -1;
+                        return;
+                    } else {
+                        /*
+                         * There was a different variable ended at the
+                         * same address. Update it to indicate that
+                         * it was ended due to a replacement (rather than
+                         * ending for no particular reason).
+                         */
+                        endEntry = endEntry.withDisposition(
+                                Disposition.END_REPLACED);
+                        result.set(endAt, endEntry);
+                    }
+                }
+            }
+
+            /*
+             * 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.
+             */
+
+            /*
+             * If the local just below (in the register set at reg-1)
+             * is of category-2, then it is ended by this new start.
+             */
+            if (regNum > 0) {
+                RegisterSpec justBelow = regs.get(regNum - 1);
+                if ((justBelow != null) && justBelow.isCategory2()) {
+                    addOrUpdateEnd(address,
+                            Disposition.END_CLOBBERED_BY_NEXT,
+                            justBelow);
+                }
+            }
+
+            /*
+             * Similarly, if this local is category-2, then the local
+             * just above (if any) is ended by the start now being
+             * emitted.
+             */
+            if (startedLocal.isCategory2()) {
+                RegisterSpec justAbove = regs.get(regNum + 1);
+                if (justAbove != null) {
+                    addOrUpdateEnd(address,
+                            Disposition.END_CLOBBERED_BY_PREV,
+                            justAbove);
+                }
+            }
+
+            /*
+             * TODO: Add an end for the same local in a different reg,
+             * 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 {@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,
+                Disposition disposition) {
+            if (DEBUG) {
+                System.err.printf("%04x end %s\n", address, endedLocal);
+            }
+
+            int regNum = endedLocal.getReg();
+
+            endedLocal = filterSpec(endedLocal);
+            aboutToProcess(address, regNum);
+
+            int endAt = endIndices[regNum];
+
+            if (endAt >= 0) {
+                /*
+                 * The local in the given register is already ended.
+                 * Silently return without adding anything to the result.
+                 */
+                return;
+            }
+
+            // Check for start and end at the same address.
+            if (checkForEmptyRange(address, endedLocal)) {
+                return;
+            }
+
+            add(address, disposition, endedLocal);
+        }
+
+        /**
+         * Helper for {@link #endLocal}, which handles the cases where
+         * and end local is issued at the same address as a start local
+         * for the same register. If this case is found, then this
+         * method will remove the start (as the local was never actually
+         * active), update the {@link #endIndices} to be accurate, and
+         * if needed update the newly-active end to reflect an altered
+         * disposition.
+         *
+         * @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
+         */
+        private boolean checkForEmptyRange(int address,
+                RegisterSpec endedLocal) {
+            int at = result.size() - 1;
+            Entry entry;
+
+            // Look for a previous entry at the same address.
+            for (/*at*/; at >= 0; at--) {
+                entry = result.get(at);
+
+                if (entry == null) {
+                    continue;
+                }
+
+                if (entry.getAddress() != address) {
+                    // We didn't find any match at the same address.
+                    return false;
+                }
+
+                if (entry.matches(endedLocal)) {
+                    break;
+                }
+            }
+
+            /*
+             * 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++;
+
+            int regNum = endedLocal.getReg();
+            boolean found = false;
+            entry = null;
+
+            // Now look back further to update where the register ended.
+            for (at--; at >= 0; at--) {
+                entry = result.get(at);
+
+                if (entry == null) {
+                    continue;
+                }
+
+                if (entry.getRegisterSpec().getReg() == regNum) {
+                    found = true;
+                    break;
+                }
+            }
+
+            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
+                     * disposition.
+                     */
+                    result.set(at,
+                            entry.withDisposition(Disposition.END_SIMPLY));
+                }
+            }
+
+            return true;
+        }
+
+        /**
+         * Converts a given spec into the form acceptable for use in a
+         * local list. This, in particular, transforms the "known
+         * 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 {@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) {
+            if ((orig != null) && (orig.getType() == Type.KNOWN_NULL)) {
+                return orig.withType(Type.OBJECT);
+            }
+
+            return orig;
+        }
+
+        /**
+         * Adds an entry to the result, updating the adjunct tables
+         * accordingly.
+         *
+         * @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) {
+            int regNum = spec.getReg();
+
+            result.add(new Entry(address, disposition, spec));
+
+            if (disposition == Disposition.START) {
+                regs.put(spec);
+                endIndices[regNum] = -1;
+            } else {
+                regs.remove(spec);
+                endIndices[regNum] = result.size() - 1;
+            }
+        }
+
+        /**
+         * 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) {
+            if (disposition == Disposition.START) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            int regNum = spec.getReg();
+            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); // TODO: Is this line superfluous?
+                    return;
+                }
+            }
+
+            endLocal(address, spec, disposition);
+        }
+
+        /**
+         * Finishes processing altogether and gets the result.
+         *
+         * @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;
+            }
+
+            /*
+             * Collect an array of only the non-null entries, and then
+             * sort it to get a consistent order for everything: Local
+             * ends and starts for a given address could come in any
+             * order, but we want ends before starts as well as
+             * registers in order (within ends or starts).
+             */
+
+            Entry[] resultArr = new Entry[finalSz];
+
+            if (resultSz == finalSz) {
+                result.toArray(resultArr);
+            } else {
+                int at = 0;
+                for (Entry e : result) {
+                    if (e != null) {
+                        resultArr[at++] = e;
+                    }
+                }
+            }
+
+            Arrays.sort(resultArr);
+
+            LocalList resultList = new LocalList(finalSz);
+
+            for (int i = 0; i < finalSz; i++) {
+                resultList.set(i, resultArr[i]);
+            }
+
+            resultList.setImmutable();
+            return resultList;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/LocalSnapshot.java b/dexgen/src/com/android/dexgen/dex/code/LocalSnapshot.java
new file mode 100644
index 0000000..81b78c9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/LocalSnapshot.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.RegisterSpecSet;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to hold a snapshot of the
+ * state of local variable name mappings that exists immediately after
+ * the instance in an instruction array.
+ */
+public final class LocalSnapshot extends ZeroSizeInsn {
+    /** {@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}).
+     *
+     * @param position {@code non-null;} source position
+     * @param locals {@code non-null;} associated local variable state
+     */
+    public LocalSnapshot(SourcePosition position, RegisterSpecSet locals) {
+        super(position);
+
+        if (locals == null) {
+            throw new NullPointerException("locals == null");
+        }
+
+        this.locals = locals;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return new LocalSnapshot(getPosition(), locals.withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new LocalSnapshot(getPosition(), locals);
+    }
+
+    /**
+     * Gets the local state associated with this instance.
+     *
+     * @return {@code non-null;} the state
+     */
+    public RegisterSpecSet getLocals() {
+        return locals;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return locals.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        int sz = locals.size();
+        int max = locals.getMaxSize();
+        StringBuffer sb = new StringBuffer(100 + sz * 40);
+
+        sb.append("local-snapshot");
+
+        for (int i = 0; i < max; i++) {
+            RegisterSpec spec = locals.get(i);
+            if (spec != null) {
+                sb.append("\n  ");
+                sb.append(LocalStart.localString(spec));
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/LocalStart.java b/dexgen/src/com/android/dexgen/dex/code/LocalStart.java
new file mode 100644
index 0000000..ba426e8
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/LocalStart.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to introduce a new local variable. That
+ * is, an instance of this class in an instruction stream indicates that
+ * starting with the subsequent instruction, the indicated variable
+ * is bound.
+ */
+public final class LocalStart extends ZeroSizeInsn {
+    /**
+     * {@code non-null;} register spec representing the local variable introduced
+     * by this instance
+     */
+    private final RegisterSpec local;
+
+    /**
+     * Returns the local variable listing string for a single register spec.
+     *
+     * @param spec {@code non-null;} the spec to convert
+     * @return {@code non-null;} the string form
+     */
+    public static String localString(RegisterSpec spec) {
+        return spec.regString() + ' ' + spec.getLocalItem().toString() + ": " +
+            spec.getTypeBearer().toHuman();
+    }
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param local {@code non-null;} register spec representing the local
+     * variable introduced by this instance
+     */
+    public LocalStart(SourcePosition position, RegisterSpec local) {
+        super(position);
+
+        if (local == null) {
+            throw new NullPointerException("local == null");
+        }
+
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return new LocalStart(getPosition(), local.withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new LocalStart(getPosition(), local);
+    }
+
+    /**
+     * Gets the register spec representing the local variable introduced
+     * by this instance.
+     *
+     * @return {@code non-null;} the register spec
+     */
+    public RegisterSpec getLocal() {
+        return local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return local.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        return "local-start " + localString(local);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/OddSpacer.java b/dexgen/src/com/android/dexgen/dex/code/OddSpacer.java
new file mode 100644
index 0000000..8e2bab8
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/OddSpacer.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * 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.
+ */
+public final class OddSpacer extends VariableSizeInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     */
+    public OddSpacer(SourcePosition position) {
+        super(position, RegisterSpecList.EMPTY);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return (getAddress() & 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        if (codeSize() != 0) {
+            out.writeShort(InsnFormat.codeUnit(DalvOps.NOP, 0));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new OddSpacer(getPosition());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        if (codeSize() == 0) {
+            return null;
+        }
+
+        return "nop // spacer";
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/OutputCollector.java b/dexgen/src/com/android/dexgen/dex/code/OutputCollector.java
new file mode 100644
index 0000000..7f970eb
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/OutputCollector.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import java.util.ArrayList;
+
+/**
+ * Destination for {@link DalvInsn} instances being output. This class
+ * receives and collects instructions in two pieces &mdash; a primary
+ * list and a suffix (generally consisting of adjunct data referred to
+ * by the primary list, such as switch case tables) &mdash; which it
+ * merges and emits back out in the form of a {@link DalvInsnList}
+ * instance.
+ */
+public final class OutputCollector {
+    /**
+     * {@code non-null;} the associated finisher (which holds the instruction
+     * list in-progress)
+     */
+    private final OutputFinisher finisher;
+
+    /**
+     * {@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;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param initialCapacity {@code >= 0;} initial capacity of the output list
+     * @param suffixInitialCapacity {@code >= 0;} initial capacity of the output
+     * suffix
+     * @param regCount {@code >= 0;} register count for the method
+     */
+    public OutputCollector(int initialCapacity, int suffixInitialCapacity,
+            int regCount) {
+        this.finisher = new OutputFinisher(initialCapacity, regCount);
+        this.suffix = new ArrayList<DalvInsn>(suffixInitialCapacity);
+    }
+
+    /**
+     * Adds an instruction to the output.
+     *
+     * @param insn {@code non-null;} the instruction to add
+     */
+    public void add(DalvInsn insn) {
+        finisher.add(insn);
+    }
+
+    /**
+     * Reverses a branch which is buried a given number of instructions
+     * backward in the output. It is illegal to call this unless the
+     * indicated instruction really is a reversible branch.
+     *
+     * @param which how many instructions back to find the branch;
+     * {@code 0} is the most recently added instruction,
+     * {@code 1} is the instruction before that, etc.
+     * @param newTarget {@code non-null;} the new target for the reversed branch
+     */
+    public void reverseBranch(int which, CodeAddress newTarget) {
+        finisher.reverseBranch(which, newTarget);
+    }
+
+    /**
+     * Adds an instruction to the output suffix.
+     *
+     * @param insn {@code non-null;} the instruction to add
+     */
+    public void addSuffix(DalvInsn insn) {
+        suffix.add(insn);
+    }
+
+    /**
+     * Gets the results of all the calls on this instance, in the form of
+     * an {@link OutputFinisher}.
+     *
+     * @return {@code non-null;} the output finisher
+     * @throws UnsupportedOperationException if this method has
+     * already been called
+     */
+    public OutputFinisher getFinisher() {
+        if (suffix == null) {
+            throw new UnsupportedOperationException("already processed");
+        }
+
+        appendSuffixToOutput();
+        return finisher;
+    }
+
+    /**
+     * Helper for {@link #getFinisher}, which appends the suffix to
+     * the primary output.
+     */
+    private void appendSuffixToOutput() {
+        int size = suffix.size();
+
+        for (int i = 0; i < size; i++) {
+            finisher.add(suffix.get(i));
+        }
+
+        suffix = null;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/OutputFinisher.java b/dexgen/src/com/android/dexgen/dex/code/OutputFinisher.java
new file mode 100644
index 0000000..98c7e4e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/OutputFinisher.java
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.LocalItem;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.RegisterSpecSet;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstMemberRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Type;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * Processor for instruction lists, which takes a "first cut" of
+ * instruction selection as a basis and produces a "final cut" in the
+ * form of a {@link DalvInsnList} instance.
+ */
+public final class OutputFinisher {
+    /**
+     * {@code >= 0;} register count for the method, not including any extra
+     * "reserved" registers needed to translate "difficult" instructions
+     */
+    private final int unreservedRegCount;
+
+    /** {@code non-null;} the list of instructions, per se */
+    private ArrayList<DalvInsn> insns;
+
+    /** whether any instruction has position info */
+    private boolean hasAnyPositionInfo;
+
+    /** whether any instruction has local variable info */
+    private boolean hasAnyLocalInfo;
+
+    /**
+     * {@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}
+     */
+    private int reservedCount;
+
+    /**
+     * Constructs an instance. It initially contains no instructions.
+     *
+     * @param regCount {@code >= 0;} register count for the method
+     * @param initialCapacity {@code >= 0;} initial capacity of the instructions
+     * list
+     */
+    public OutputFinisher(int initialCapacity, int regCount) {
+        this.unreservedRegCount = regCount;
+        this.insns = new ArrayList<DalvInsn>(initialCapacity);
+        this.reservedCount = -1;
+        this.hasAnyPositionInfo = false;
+        this.hasAnyLocalInfo = false;
+    }
+
+    /**
+     * Returns whether any of the instructions added to this instance
+     * come with position info.
+     *
+     * @return whether any of the instructions added to this instance
+     * come with position info
+     */
+    public boolean hasAnyPositionInfo() {
+        return hasAnyPositionInfo;
+    }
+
+    /**
+     * Returns whether this instance has any local variable information.
+     *
+     * @return whether this instance has any local variable information
+     */
+    public boolean hasAnyLocalInfo() {
+        return hasAnyLocalInfo;
+    }
+
+    /**
+     * Helper for {@link #add} which scrutinizes a single
+     * instruction for local variable information.
+     *
+     * @param insn {@code non-null;} instruction to scrutinize
+     * @return {@code true} iff the instruction refers to any
+     * named locals
+     */
+    private static boolean hasLocalInfo(DalvInsn insn) {
+        if (insn instanceof LocalSnapshot) {
+            RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
+            int size = specs.size();
+            for (int i = 0; i < size; i++) {
+                if (hasLocalInfo(specs.get(i))) {
+                    return true;
+                }
+            }
+        } else if (insn instanceof LocalStart) {
+            RegisterSpec spec = ((LocalStart) insn).getLocal();
+            if (hasLocalInfo(spec)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
+     * register spec.
+     *
+     * @param spec {@code non-null;} spec to scrutinize
+     * @return {@code true} iff the spec refers to any
+     * named locals
+     */
+    private static boolean hasLocalInfo(RegisterSpec spec) {
+        return (spec != null)
+            && (spec.getLocalItem().getName() != null);
+    }
+
+    /**
+     * Returns the set of all constants referred to by instructions added
+     * to this instance.
+     *
+     * @return {@code non-null;} the set of constants
+     */
+    public HashSet<Constant> getAllConstants() {
+        HashSet<Constant> result = new HashSet<Constant>(20);
+
+        for (DalvInsn insn : insns) {
+            addConstants(result, insn);
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #getAllConstants} which adds all the info for
+     * a single instruction.
+     *
+     * @param result {@code non-null;} result set to add to
+     * @param insn {@code non-null;} instruction to scrutinize
+     */
+    private static void addConstants(HashSet<Constant> result,
+            DalvInsn insn) {
+        if (insn instanceof CstInsn) {
+            Constant cst = ((CstInsn) insn).getConstant();
+            result.add(cst);
+        } else if (insn instanceof LocalSnapshot) {
+            RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
+            int size = specs.size();
+            for (int i = 0; i < size; i++) {
+                addConstants(result, specs.get(i));
+            }
+        } else if (insn instanceof LocalStart) {
+            RegisterSpec spec = ((LocalStart) insn).getLocal();
+            addConstants(result, spec);
+        }
+    }
+
+    /**
+     * Helper for {@link #getAllConstants} which adds all the info for
+     * a single {@code RegisterSpec}.
+     *
+     * @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) {
+        if (spec == null) {
+            return;
+        }
+
+        LocalItem local = spec.getLocalItem();
+        CstUtf8 name = local.getName();
+        CstUtf8 signature = local.getSignature();
+        Type type = spec.getType();
+
+        if (type != Type.KNOWN_NULL) {
+            result.add(CstType.intern(type));
+        }
+
+        if (name != null) {
+            result.add(name);
+        }
+
+        if (signature != null) {
+            result.add(signature);
+        }
+    }
+
+    /**
+     * Adds an instruction to the output.
+     *
+     * @param insn {@code non-null;} the instruction to add
+     */
+    public void add(DalvInsn insn) {
+        insns.add(insn);
+        updateInfo(insn);
+    }
+
+    /**
+     * Inserts an instruction in the output at the given offset.
+     *
+     * @param at {@code >= 0;} what index to insert at
+     * @param insn {@code non-null;} the instruction to insert
+     */
+    public void insert(int at, DalvInsn insn) {
+        insns.add(at, insn);
+        updateInfo(insn);
+    }
+
+    /**
+     * Helper for {@link #add} and {@link #insert},
+     * which updates the position and local info flags.
+     *
+     * @param insn {@code non-null;} an instruction that was just introduced
+     */
+    private void updateInfo(DalvInsn insn) {
+        if (! hasAnyPositionInfo) {
+            SourcePosition pos = insn.getPosition();
+            if (pos.getLine() >= 0) {
+                hasAnyPositionInfo = true;
+            }
+        }
+
+        if (! hasAnyLocalInfo) {
+            if (hasLocalInfo(insn)) {
+                hasAnyLocalInfo = true;
+            }
+        }
+    }
+
+    /**
+     * Reverses a branch which is buried a given number of instructions
+     * backward in the output. It is illegal to call this unless the
+     * indicated instruction really is a reversible branch.
+     *
+     * @param which how many instructions back to find the branch;
+     * {@code 0} is the most recently added instruction,
+     * {@code 1} is the instruction before that, etc.
+     * @param newTarget {@code non-null;} the new target for the reversed branch
+     */
+    public void reverseBranch(int which, CodeAddress newTarget) {
+        int size = insns.size();
+        int index = size - which - 1;
+        TargetInsn targetInsn;
+
+        try {
+            targetInsn = (TargetInsn) insns.get(index);
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("too few instructions");
+        } catch (ClassCastException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("non-reversible instruction");
+        }
+
+        /*
+         * No need to call this.set(), since the format and other info
+         * are the same.
+         */
+        insns.set(index, targetInsn.withNewTargetAndReversed(newTarget));
+    }
+
+    /**
+     * Assigns indices in all instructions that need them, using the
+     * given callback to perform lookups. This should be called before
+     * calling {@link #finishProcessingAndGetList}.
+     *
+     * @param callback {@code non-null;} callback object
+     */
+    public void assignIndices(DalvCode.AssignIndicesCallback callback) {
+        for (DalvInsn insn : insns) {
+            if (insn instanceof CstInsn) {
+                assignIndices((CstInsn) insn, callback);
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #assignIndices} which does assignment for one
+     * instruction.
+     *
+     * @param insn {@code non-null;} the instruction
+     * @param callback {@code non-null;} the callback
+     */
+    private static void assignIndices(CstInsn insn,
+            DalvCode.AssignIndicesCallback callback) {
+        Constant cst = insn.getConstant();
+        int index = callback.getIndex(cst);
+
+        if (index >= 0) {
+            insn.setIndex(index);
+        }
+
+        if (cst instanceof CstMemberRef) {
+            CstMemberRef member = (CstMemberRef) cst;
+            CstType definer = member.getDefiningClass();
+            index = callback.getIndex(definer);
+            if (index >= 0) {
+                insn.setClassIndex(index);
+            }
+        }
+    }
+
+    /**
+     * Does final processing on this instance and gets the output as
+     * a {@link DalvInsnList}. Final processing consists of:
+     *
+     * <ul>
+     *   <li>optionally renumbering registers (to make room as needed for
+     *   expanded instructions)</li>
+     *   <li>picking a final opcode for each instruction</li>
+     *   <li>rewriting instructions, because of register number,
+     *   constant pool index, or branch target size issues</li>
+     *   <li>assigning final addresses</li>
+     * </ul>
+     *
+     * <p><b>Note:</b> This method may only be called once per instance
+     * of this class.</p>
+     *
+     * @return {@code non-null;} the output list
+     * @throws UnsupportedOperationException if this method has
+     * already been called
+     */
+    public DalvInsnList finishProcessingAndGetList() {
+        if (reservedCount >= 0) {
+            throw new UnsupportedOperationException("already processed");
+        }
+
+        InsnFormat[] formats = makeFormatsArray();
+        reserveRegisters(formats);
+        massageInstructions(formats);
+        assignAddressesAndFixBranches();
+
+        return DalvInsnList.makeImmutable(insns,
+                reservedCount + unreservedRegCount);
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which extracts
+     * the format out of each instruction into a separate array, to be
+     * further manipulated as things progress.
+     *
+     * @return {@code non-null;} the array of formats
+     */
+    private InsnFormat[] makeFormatsArray() {
+        int size = insns.size();
+        InsnFormat[] result = new InsnFormat[size];
+
+        for (int i = 0; i < size; i++) {
+            result[i] = insns.get(i).getOpcode().getFormat();
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which figures
+     * out how many reserved registers are required and then reserving
+     * them. It also updates the given {@code formats} array so
+     * as to avoid extra work when constructing the massaged
+     * instruction list.
+     *
+     * @param formats {@code non-null;} array of per-instruction format selections
+     */
+    private void reserveRegisters(InsnFormat[] formats) {
+        int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
+
+        /*
+         * Call calculateReservedCount() and then perform register
+         * reservation, repeatedly until no new reservations happen.
+         */
+        for (;;) {
+            int newReservedCount = calculateReservedCount(formats);
+            if (oldReservedCount >= newReservedCount) {
+                break;
+            }
+
+            int reservedDifference = newReservedCount - oldReservedCount;
+            int size = insns.size();
+
+            for (int i = 0; i < size; i++) {
+                /*
+                 * CodeAddress instance identity is used to link
+                 * TargetInsns to their targets, so it is
+                 * inappropriate to make replacements, and they don't
+                 * have registers in any case. Hence, the instanceof
+                 * test below.
+                 */
+                DalvInsn insn = insns.get(i);
+                if (!(insn instanceof CodeAddress)) {
+                    /*
+                     * No need to call this.set() since the format and
+                     * other info are the same.
+                     */
+                    insns.set(i, insn.withRegisterOffset(reservedDifference));
+                }
+            }
+
+            oldReservedCount = newReservedCount;
+        }
+
+        reservedCount = oldReservedCount;
+    }
+
+    /**
+     * 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} list to help avoid extra work in future
+     * register reservation passes.
+     *
+     * @param formats {@code non-null;} array of per-instruction format selections
+     * @return {@code >= 0;} the count of reserved registers
+     */
+    private int calculateReservedCount(InsnFormat[] formats) {
+        int size = insns.size();
+
+        /*
+         * Potential new value of reservedCount, which gets updated in the
+         * following loop. It starts out with the existing reservedCount
+         * and gets increased if it turns out that additional registers
+         * need to be reserved.
+         */
+        int newReservedCount = reservedCount;
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            InsnFormat originalFormat = formats[i];
+            InsnFormat newFormat = findFormatForInsn(insn, originalFormat);
+
+            if (originalFormat == newFormat) {
+                continue;
+            }
+
+            if (newFormat == null) {
+                /*
+                 * The instruction will need to be expanded, so reserve
+                 * registers for it.
+                 */
+                int reserve = insn.getMinimumRegisterRequirement();
+                if (reserve > newReservedCount) {
+                    newReservedCount = reserve;
+                }
+            }
+
+            formats[i] = newFormat;
+        }
+
+        return newReservedCount;
+    }
+
+    /**
+     * Attempts to fit the given instruction into a format, returning
+     * 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 {@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) {
+        if (format == null) {
+            // The instruction is already known not to fit any simple format.
+            return format;
+        }
+
+        if (format.isCompatible(insn)) {
+            // The instruction already fits in the current best-known format.
+            return format;
+        }
+
+        Dop dop = insn.getOpcode();
+        int family = dop.getFamily();
+
+        for (;;) {
+            format = format.nextUp();
+            if ((format == null) ||
+                    (format.isCompatible(insn) &&
+                     (Dops.getOrNull(family, format) != null))) {
+                break;
+            }
+        }
+
+        return format;
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which goes
+     * through each instruction in the output, making sure its opcode
+     * can accomodate its arguments. In cases where the opcode is
+     * unable to do so, this replaces the instruction with a larger
+     * instruction with identical semantics that <i>will</i> work.
+     *
+     * <p>This method may also reserve a number of low-numbered
+     * registers, renumbering the instructions' original registers, in
+     * order to have register space available in which to move
+     * very-high registers when expanding instructions into
+     * multi-instruction sequences. This expansion is done when no
+     * simple instruction format can be found for a given instruction that
+     * is able to accomodate that instruction's registers.</p>
+     *
+     * <p>This method ignores issues of branch target size, since
+     * final addresses aren't known at the point that this method is
+     * called.</p>
+     *
+     * @param formats {@code non-null;} array of per-instruction format selections
+     */
+    private void massageInstructions(InsnFormat[] formats) {
+        if (reservedCount == 0) {
+            /*
+             * The easy common case: No registers were reserved, so we
+             * merely need to replace any instructions whose format changed
+             * during the reservation pass, but all instructions will stay
+             * at their original indices, and the instruction list doesn't
+             * grow.
+             */
+            int size = insns.size();
+
+            for (int i = 0; i < size; i++) {
+                DalvInsn insn = insns.get(i);
+                Dop dop = insn.getOpcode();
+                InsnFormat format = formats[i];
+
+                if (format != dop.getFormat()) {
+                    dop = Dops.getOrNull(dop.getFamily(), format);
+                    insns.set(i, insn.withOpcode(dop));
+                }
+            }
+        } else {
+            /*
+             * The difficult uncommon case: Some instructions have to be
+             * expanded to deal with high registers.
+             */
+            insns = performExpansion(formats);
+        }
+    }
+
+    /**
+     * Helper for {@link #massageInstructions}, which constructs a
+     * replacement list, where each {link DalvInsn} instance that
+     * couldn't be represented simply (due to register representation
+     * problems) is expanded into a series of instances that together
+     * perform the proper function.
+     *
+     * @param formats {@code non-null;} array of per-instruction format selections
+     * @return {@code non-null;} the replacement list
+     */
+    private ArrayList<DalvInsn> performExpansion(InsnFormat[] formats) {
+        int size = insns.size();
+        ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            Dop dop = insn.getOpcode();
+            InsnFormat originalFormat = dop.getFormat();
+            InsnFormat currentFormat = formats[i];
+            DalvInsn prefix;
+            DalvInsn suffix;
+
+            if (currentFormat != null) {
+                // No expansion is necessary.
+                prefix = null;
+                suffix = null;
+            } else {
+                // Expansion is required.
+                prefix = insn.hrPrefix();
+                suffix = insn.hrSuffix();
+
+                /*
+                 * Get the initial guess as to the hr version, but then
+                 * let findFormatForInsn() pick a better format, if any.
+                 */
+                insn = insn.hrVersion();
+                originalFormat = insn.getOpcode().getFormat();
+                currentFormat = findFormatForInsn(insn, originalFormat);
+            }
+
+            if (prefix != null) {
+                result.add(prefix);
+            }
+
+            if (currentFormat != originalFormat) {
+                dop = Dops.getOrNull(dop.getFamily(), currentFormat);
+                insn = insn.withOpcode(dop);
+            }
+            result.add(insn);
+
+            if (suffix != null) {
+                result.add(suffix);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which assigns
+     * addresses to each instruction, possibly rewriting branches to
+     * fix ones that wouldn't otherwise be able to reach their
+     * targets.
+     */
+    private void assignAddressesAndFixBranches() {
+        for (;;) {
+            assignAddresses();
+            if (!fixBranches()) {
+                break;
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #assignAddressesAndFixBranches}, which
+     * assigns an address to each instruction, in order.
+     */
+    private void assignAddresses() {
+        int address = 0;
+        int size = insns.size();
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            insn.setAddress(address);
+            address += insn.codeSize();
+        }
+    }
+
+    /**
+     * 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} 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}
+     * to the original target.
+     *
+     * @return whether any branches had to be fixed
+     */
+    private boolean fixBranches() {
+        int size = insns.size();
+        boolean anyFixed = false;
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            if (!(insn instanceof TargetInsn)) {
+                // This loop only needs to inspect TargetInsns.
+                continue;
+            }
+
+            Dop dop = insn.getOpcode();
+            InsnFormat format = dop.getFormat();
+            TargetInsn target = (TargetInsn) insn;
+
+            if (format.branchFits(target)) {
+                continue;
+            }
+
+            if (dop.getFamily() == DalvOps.GOTO) {
+                // It is a goto; widen it if possible.
+                InsnFormat newFormat = findFormatForInsn(insn, format);
+                if (newFormat == null) {
+                    /*
+                     * The branch is already maximally large. This should
+                     * only be possible if a method somehow manages to have
+                     * more than 2^31 code units.
+                     */
+                    throw new UnsupportedOperationException("method too long");
+                }
+                dop = Dops.getOrNull(dop.getFamily(), newFormat);
+                insn = insn.withOpcode(dop);
+                insns.set(i, insn);
+            } else {
+                /*
+                 * It is a conditional: Reverse its sense, and arrange for
+                 * it to branch around an absolute goto to the original
+                 * branch target.
+                 *
+                 * Note: An invariant of the list being processed is
+                 * that every TargetInsn is followed by a CodeAddress.
+                 * Hence, it is always safe to get the next element
+                 * after a TargetInsn and cast it to CodeAddress, as
+                 * is happening a few lines down.
+                 *
+                 * Also note: Size gets incremented by one here, as we
+                 * have -- in the net -- added one additional element
+                 * to the list, so we increment i to match. The added
+                 * and changed elements will be inspected by a repeat
+                 * call to this method after this invocation returns.
+                 */
+                CodeAddress newTarget;
+                try {
+                    newTarget = (CodeAddress) insns.get(i + 1);
+                } catch (IndexOutOfBoundsException ex) {
+                    // The TargetInsn / CodeAddress invariant was violated.
+                    throw new IllegalStateException(
+                            "unpaired TargetInsn (dangling)");
+                } catch (ClassCastException ex) {
+                    // The TargetInsn / CodeAddress invariant was violated.
+                    throw new IllegalStateException("unpaired TargetInsn");
+                }
+                TargetInsn gotoInsn =
+                    new TargetInsn(Dops.GOTO, target.getPosition(),
+                            RegisterSpecList.EMPTY, target.getTarget());
+                insns.set(i, gotoInsn);
+                insns.add(i, target.withNewTargetAndReversed(newTarget));
+                size++;
+                i++;
+            }
+
+            anyFixed = true;
+        }
+
+        return anyFixed;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/PositionList.java b/dexgen/src/com/android/dexgen/dex/code/PositionList.java
new file mode 100644
index 0000000..8b52f26
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/PositionList.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * List of source position entries. This class includes a utility
+ * method to extract an instance out of a {@link DalvInsnList}.
+ */
+public final class PositionList extends FixedSizeList {
+    /** {@code non-null;} empty instance */
+    public static final PositionList EMPTY = new PositionList(0);
+
+    /**
+     * constant for {@link #make} to indicate that no actual position
+     * information should be returned
+     */
+    public static final int NONE = 1;
+
+    /**
+     * constant for {@link #make} to indicate that only line number
+     * transitions should be returned
+     */
+    public static final int LINES = 2;
+
+    /**
+     * constant for {@link #make} to indicate that only "important" position
+     * information should be returned. This includes block starts and
+     * instructions that might throw.
+     */
+    public static final int IMPORTANT = 3;
+
+    /**
+     * Extracts and returns the source position information out of an
+     * instruction list.
+     *
+     * @param insns {@code non-null;} instructions to convert
+     * @param howMuch how much information should be included; one of the
+     * static constants defined by this class
+     * @return {@code non-null;} the positions list
+     */
+    public static PositionList make(DalvInsnList insns, int howMuch) {
+        switch (howMuch) {
+            case NONE: {
+                return EMPTY;
+            }
+            case LINES:
+            case IMPORTANT: {
+                // Valid.
+                break;
+            }
+            default: {
+                throw new IllegalArgumentException("bogus howMuch");
+            }
+        }
+
+        SourcePosition noInfo = SourcePosition.NO_INFO;
+        SourcePosition cur = noInfo;
+        int sz = insns.size();
+        PositionList.Entry[] arr = new PositionList.Entry[sz];
+        boolean lastWasTarget = false;
+        int at = 0;
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = insns.get(i);
+
+            if (insn instanceof CodeAddress) {
+                lastWasTarget = true;;
+                continue;
+            }
+
+            SourcePosition pos = insn.getPosition();
+
+            if (pos.equals(noInfo) || pos.sameLine(cur)) {
+                continue;
+            }
+
+            if ((howMuch == IMPORTANT) && !lastWasTarget) {
+                continue;
+            }
+
+            cur = pos;
+            arr[at] = new PositionList.Entry(insn.getAddress(), pos);
+            at++;
+
+            lastWasTarget = false;
+        }
+
+        PositionList result = new PositionList(at);
+        for (int i = 0; i < at; i++) {
+            result.set(i, arr[i]);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size {@code >= 0;} the size of the list
+     */
+    public PositionList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /**
+     * Entry in a position list.
+     */
+    public static class Entry {
+        /** {@code >= 0;} address of this entry */
+        private final int address;
+
+        /** {@code non-null;} corresponding source position information */
+        private final SourcePosition position;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("address < 0");
+            }
+
+            if (position == null) {
+                throw new NullPointerException("position == null");
+            }
+
+            this.address = address;
+            this.position = position;
+        }
+
+        /**
+         * Gets the address.
+         *
+         * @return {@code >= 0;} the address
+         */
+        public int getAddress() {
+            return address;
+        }
+
+        /**
+         * Gets the source position information.
+         *
+         * @return {@code non-null;} the position information
+         */
+        public SourcePosition getPosition() {
+            return position;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/RopToDop.java b/dexgen/src/com/android/dexgen/dex/code/RopToDop.java
new file mode 100644
index 0000000..03d1de8
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/RopToDop.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.Insn;
+import com.android.dexgen.rop.code.RegOps;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.Rop;
+import com.android.dexgen.rop.code.Rops;
+import com.android.dexgen.rop.code.ThrowingCstInsn;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+
+import java.util.HashMap;
+
+/**
+ * Translator from rop-level {@link Insn} instances to corresponding
+ * {@link Dop} instances.
+ */
+public final class RopToDop {
+    /** {@code non-null;} map from all the common rops to dalvik opcodes */
+    private static final HashMap<Rop, Dop> MAP;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private RopToDop() {
+        // This space intentionally left blank.
+    }
+
+    static {
+        /*
+         * Note: The choices made here are to pick the optimistically
+         * smallest Dalvik opcode, and leave it to later processing to
+         * pessimize.
+         */
+        MAP = new HashMap<Rop, Dop>(400);
+        MAP.put(Rops.NOP,               Dops.NOP);
+        MAP.put(Rops.MOVE_INT,          Dops.MOVE);
+        MAP.put(Rops.MOVE_LONG,         Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_FLOAT,        Dops.MOVE);
+        MAP.put(Rops.MOVE_DOUBLE,       Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_OBJECT,       Dops.MOVE_OBJECT);
+        MAP.put(Rops.MOVE_PARAM_INT,    Dops.MOVE);
+        MAP.put(Rops.MOVE_PARAM_LONG,   Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_PARAM_FLOAT,  Dops.MOVE);
+        MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT);
+
+        /*
+         * Note: No entry for MOVE_EXCEPTION, since it varies by
+         * exception type. (That is, there is no unique instance to
+         * add to the map.)
+         */
+
+        MAP.put(Rops.CONST_INT,         Dops.CONST_4);
+        MAP.put(Rops.CONST_LONG,        Dops.CONST_WIDE_16);
+        MAP.put(Rops.CONST_FLOAT,       Dops.CONST_4);
+        MAP.put(Rops.CONST_DOUBLE,      Dops.CONST_WIDE_16);
+
+        /*
+         * Note: No entry for CONST_OBJECT, since it needs to turn
+         * into either CONST_STRING or CONST_CLASS.
+         */
+
+        /*
+         * TODO: I think the only case of this is for null, and
+         * const/4 should cover that.
+         */
+        MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
+
+        MAP.put(Rops.GOTO,                 Dops.GOTO);
+        MAP.put(Rops.IF_EQZ_INT,           Dops.IF_EQZ);
+        MAP.put(Rops.IF_NEZ_INT,           Dops.IF_NEZ);
+        MAP.put(Rops.IF_LTZ_INT,           Dops.IF_LTZ);
+        MAP.put(Rops.IF_GEZ_INT,           Dops.IF_GEZ);
+        MAP.put(Rops.IF_LEZ_INT,           Dops.IF_LEZ);
+        MAP.put(Rops.IF_GTZ_INT,           Dops.IF_GTZ);
+        MAP.put(Rops.IF_EQZ_OBJECT,        Dops.IF_EQZ);
+        MAP.put(Rops.IF_NEZ_OBJECT,        Dops.IF_NEZ);
+        MAP.put(Rops.IF_EQ_INT,            Dops.IF_EQ);
+        MAP.put(Rops.IF_NE_INT,            Dops.IF_NE);
+        MAP.put(Rops.IF_LT_INT,            Dops.IF_LT);
+        MAP.put(Rops.IF_GE_INT,            Dops.IF_GE);
+        MAP.put(Rops.IF_LE_INT,            Dops.IF_LE);
+        MAP.put(Rops.IF_GT_INT,            Dops.IF_GT);
+        MAP.put(Rops.IF_EQ_OBJECT,         Dops.IF_EQ);
+        MAP.put(Rops.IF_NE_OBJECT,         Dops.IF_NE);
+        MAP.put(Rops.SWITCH,               Dops.SPARSE_SWITCH);
+        MAP.put(Rops.ADD_INT,              Dops.ADD_INT_2ADDR);
+        MAP.put(Rops.ADD_LONG,             Dops.ADD_LONG_2ADDR);
+        MAP.put(Rops.ADD_FLOAT,            Dops.ADD_FLOAT_2ADDR);
+        MAP.put(Rops.ADD_DOUBLE,           Dops.ADD_DOUBLE_2ADDR);
+        MAP.put(Rops.SUB_INT,              Dops.SUB_INT_2ADDR);
+        MAP.put(Rops.SUB_LONG,             Dops.SUB_LONG_2ADDR);
+        MAP.put(Rops.SUB_FLOAT,            Dops.SUB_FLOAT_2ADDR);
+        MAP.put(Rops.SUB_DOUBLE,           Dops.SUB_DOUBLE_2ADDR);
+        MAP.put(Rops.MUL_INT,              Dops.MUL_INT_2ADDR);
+        MAP.put(Rops.MUL_LONG,             Dops.MUL_LONG_2ADDR);
+        MAP.put(Rops.MUL_FLOAT,            Dops.MUL_FLOAT_2ADDR);
+        MAP.put(Rops.MUL_DOUBLE,           Dops.MUL_DOUBLE_2ADDR);
+        MAP.put(Rops.DIV_INT,              Dops.DIV_INT_2ADDR);
+        MAP.put(Rops.DIV_LONG,             Dops.DIV_LONG_2ADDR);
+        MAP.put(Rops.DIV_FLOAT,            Dops.DIV_FLOAT_2ADDR);
+        MAP.put(Rops.DIV_DOUBLE,           Dops.DIV_DOUBLE_2ADDR);
+        MAP.put(Rops.REM_INT,              Dops.REM_INT_2ADDR);
+        MAP.put(Rops.REM_LONG,             Dops.REM_LONG_2ADDR);
+        MAP.put(Rops.REM_FLOAT,            Dops.REM_FLOAT_2ADDR);
+        MAP.put(Rops.REM_DOUBLE,           Dops.REM_DOUBLE_2ADDR);
+        MAP.put(Rops.NEG_INT,              Dops.NEG_INT);
+        MAP.put(Rops.NEG_LONG,             Dops.NEG_LONG);
+        MAP.put(Rops.NEG_FLOAT,            Dops.NEG_FLOAT);
+        MAP.put(Rops.NEG_DOUBLE,           Dops.NEG_DOUBLE);
+        MAP.put(Rops.AND_INT,              Dops.AND_INT_2ADDR);
+        MAP.put(Rops.AND_LONG,             Dops.AND_LONG_2ADDR);
+        MAP.put(Rops.OR_INT,               Dops.OR_INT_2ADDR);
+        MAP.put(Rops.OR_LONG,              Dops.OR_LONG_2ADDR);
+        MAP.put(Rops.XOR_INT,              Dops.XOR_INT_2ADDR);
+        MAP.put(Rops.XOR_LONG,             Dops.XOR_LONG_2ADDR);
+        MAP.put(Rops.SHL_INT,              Dops.SHL_INT_2ADDR);
+        MAP.put(Rops.SHL_LONG,             Dops.SHL_LONG_2ADDR);
+        MAP.put(Rops.SHR_INT,              Dops.SHR_INT_2ADDR);
+        MAP.put(Rops.SHR_LONG,             Dops.SHR_LONG_2ADDR);
+        MAP.put(Rops.USHR_INT,             Dops.USHR_INT_2ADDR);
+        MAP.put(Rops.USHR_LONG,            Dops.USHR_LONG_2ADDR);
+        MAP.put(Rops.NOT_INT,              Dops.NOT_INT);
+        MAP.put(Rops.NOT_LONG,             Dops.NOT_LONG);
+
+        MAP.put(Rops.ADD_CONST_INT,        Dops.ADD_INT_LIT8);
+        // Note: No dalvik ops for other types of add_const.
+
+        /*
+         * Note: No dalvik ops for any type of sub_const; there's a
+         * *reverse* sub (constant - reg) for ints, though, but that
+         * should end up getting handled at optimization time.
+         */
+
+        MAP.put(Rops.MUL_CONST_INT,        Dops.MUL_INT_LIT8);
+        // Note: No dalvik ops for other types of mul_const.
+
+        MAP.put(Rops.DIV_CONST_INT,        Dops.DIV_INT_LIT8);
+        // Note: No dalvik ops for other types of div_const.
+
+        MAP.put(Rops.REM_CONST_INT,        Dops.REM_INT_LIT8);
+        // Note: No dalvik ops for other types of rem_const.
+
+        MAP.put(Rops.AND_CONST_INT,        Dops.AND_INT_LIT8);
+        // Note: No dalvik op for and_const_long.
+
+        MAP.put(Rops.OR_CONST_INT,         Dops.OR_INT_LIT8);
+        // Note: No dalvik op for or_const_long.
+
+        MAP.put(Rops.XOR_CONST_INT,        Dops.XOR_INT_LIT8);
+        // Note: No dalvik op for xor_const_long.
+
+        MAP.put(Rops.SHL_CONST_INT,        Dops.SHL_INT_LIT8);
+        // Note: No dalvik op for shl_const_long.
+
+        MAP.put(Rops.SHR_CONST_INT,        Dops.SHR_INT_LIT8);
+        // Note: No dalvik op for shr_const_long.
+
+        MAP.put(Rops.USHR_CONST_INT,       Dops.USHR_INT_LIT8);
+        // Note: No dalvik op for shr_const_long.
+
+        MAP.put(Rops.CMPL_LONG,            Dops.CMP_LONG);
+        MAP.put(Rops.CMPL_FLOAT,           Dops.CMPL_FLOAT);
+        MAP.put(Rops.CMPL_DOUBLE,          Dops.CMPL_DOUBLE);
+        MAP.put(Rops.CMPG_FLOAT,           Dops.CMPG_FLOAT);
+        MAP.put(Rops.CMPG_DOUBLE,          Dops.CMPG_DOUBLE);
+        MAP.put(Rops.CONV_L2I,             Dops.LONG_TO_INT);
+        MAP.put(Rops.CONV_F2I,             Dops.FLOAT_TO_INT);
+        MAP.put(Rops.CONV_D2I,             Dops.DOUBLE_TO_INT);
+        MAP.put(Rops.CONV_I2L,             Dops.INT_TO_LONG);
+        MAP.put(Rops.CONV_F2L,             Dops.FLOAT_TO_LONG);
+        MAP.put(Rops.CONV_D2L,             Dops.DOUBLE_TO_LONG);
+        MAP.put(Rops.CONV_I2F,             Dops.INT_TO_FLOAT);
+        MAP.put(Rops.CONV_L2F,             Dops.LONG_TO_FLOAT);
+        MAP.put(Rops.CONV_D2F,             Dops.DOUBLE_TO_FLOAT);
+        MAP.put(Rops.CONV_I2D,             Dops.INT_TO_DOUBLE);
+        MAP.put(Rops.CONV_L2D,             Dops.LONG_TO_DOUBLE);
+        MAP.put(Rops.CONV_F2D,             Dops.FLOAT_TO_DOUBLE);
+        MAP.put(Rops.TO_BYTE,              Dops.INT_TO_BYTE);
+        MAP.put(Rops.TO_CHAR,              Dops.INT_TO_CHAR);
+        MAP.put(Rops.TO_SHORT,             Dops.INT_TO_SHORT);
+        MAP.put(Rops.RETURN_VOID,          Dops.RETURN_VOID);
+        MAP.put(Rops.RETURN_INT,           Dops.RETURN);
+        MAP.put(Rops.RETURN_LONG,          Dops.RETURN_WIDE);
+        MAP.put(Rops.RETURN_FLOAT,         Dops.RETURN);
+        MAP.put(Rops.RETURN_DOUBLE,        Dops.RETURN_WIDE);
+        MAP.put(Rops.RETURN_OBJECT,        Dops.RETURN_OBJECT);
+        MAP.put(Rops.ARRAY_LENGTH,         Dops.ARRAY_LENGTH);
+        MAP.put(Rops.THROW,                Dops.THROW);
+        MAP.put(Rops.MONITOR_ENTER,        Dops.MONITOR_ENTER);
+        MAP.put(Rops.MONITOR_EXIT,         Dops.MONITOR_EXIT);
+        MAP.put(Rops.AGET_INT,             Dops.AGET);
+        MAP.put(Rops.AGET_LONG,            Dops.AGET_WIDE);
+        MAP.put(Rops.AGET_FLOAT,           Dops.AGET);
+        MAP.put(Rops.AGET_DOUBLE,          Dops.AGET_WIDE);
+        MAP.put(Rops.AGET_OBJECT,          Dops.AGET_OBJECT);
+        MAP.put(Rops.AGET_BOOLEAN,         Dops.AGET_BOOLEAN);
+        MAP.put(Rops.AGET_BYTE,            Dops.AGET_BYTE);
+        MAP.put(Rops.AGET_CHAR,            Dops.AGET_CHAR);
+        MAP.put(Rops.AGET_SHORT,           Dops.AGET_SHORT);
+        MAP.put(Rops.APUT_INT,             Dops.APUT);
+        MAP.put(Rops.APUT_LONG,            Dops.APUT_WIDE);
+        MAP.put(Rops.APUT_FLOAT,           Dops.APUT);
+        MAP.put(Rops.APUT_DOUBLE,          Dops.APUT_WIDE);
+        MAP.put(Rops.APUT_OBJECT,          Dops.APUT_OBJECT);
+        MAP.put(Rops.APUT_BOOLEAN,         Dops.APUT_BOOLEAN);
+        MAP.put(Rops.APUT_BYTE,            Dops.APUT_BYTE);
+        MAP.put(Rops.APUT_CHAR,            Dops.APUT_CHAR);
+        MAP.put(Rops.APUT_SHORT,           Dops.APUT_SHORT);
+        MAP.put(Rops.NEW_INSTANCE,         Dops.NEW_INSTANCE);
+        MAP.put(Rops.CHECK_CAST,           Dops.CHECK_CAST);
+        MAP.put(Rops.INSTANCE_OF,          Dops.INSTANCE_OF);
+
+        MAP.put(Rops.GET_FIELD_LONG,       Dops.IGET_WIDE);
+        MAP.put(Rops.GET_FIELD_FLOAT,      Dops.IGET);
+        MAP.put(Rops.GET_FIELD_DOUBLE,     Dops.IGET_WIDE);
+        MAP.put(Rops.GET_FIELD_OBJECT,     Dops.IGET_OBJECT);
+        /*
+         * Note: No map entries for get_field_* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        MAP.put(Rops.GET_STATIC_LONG,      Dops.SGET_WIDE);
+        MAP.put(Rops.GET_STATIC_FLOAT,     Dops.SGET);
+        MAP.put(Rops.GET_STATIC_DOUBLE,    Dops.SGET_WIDE);
+        MAP.put(Rops.GET_STATIC_OBJECT,    Dops.SGET_OBJECT);
+        /*
+         * Note: No map entries for get_static* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        MAP.put(Rops.PUT_FIELD_LONG,       Dops.IPUT_WIDE);
+        MAP.put(Rops.PUT_FIELD_FLOAT,      Dops.IPUT);
+        MAP.put(Rops.PUT_FIELD_DOUBLE,     Dops.IPUT_WIDE);
+        MAP.put(Rops.PUT_FIELD_OBJECT,     Dops.IPUT_OBJECT);
+        /*
+         * Note: No map entries for put_field_* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        MAP.put(Rops.PUT_STATIC_LONG,      Dops.SPUT_WIDE);
+        MAP.put(Rops.PUT_STATIC_FLOAT,     Dops.SPUT);
+        MAP.put(Rops.PUT_STATIC_DOUBLE,    Dops.SPUT_WIDE);
+        MAP.put(Rops.PUT_STATIC_OBJECT,    Dops.SPUT_OBJECT);
+        /*
+         * Note: No map entries for put_static* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        /*
+         * Note: No map entries for invoke*, new_array, and
+         * filled_new_array, since they need to be handled specially
+         * (see dopFor() below).
+         */
+    }
+
+    /**
+     * Returns the dalvik opcode appropriate for the given register-based
+     * instruction.
+     *
+     * @param insn {@code non-null;} the original instruction
+     * @return the corresponding dalvik opcode; one of the constants in
+     * {@link Dops}
+     */
+    public static Dop dopFor(Insn insn) {
+        Rop rop = insn.getOpcode();
+
+        /*
+         * First, just try looking up the rop in the MAP of easy
+         * cases.
+         */
+        Dop result = MAP.get(rop);
+        if (result != null) {
+            return result;
+        }
+
+        /*
+         * There was no easy case for the rop, so look up the opcode, and
+         * do something special for each:
+         *
+         * The move_exception, new_array, filled_new_array, and
+         * invoke* opcodes won't be found in MAP, since they'll each
+         * have different source and/or result register types / lists.
+         *
+         * The get* and put* opcodes for (non-long) integral types
+         * aren't in the map, since the type signatures aren't
+         * sufficient to distinguish between the types (the salient
+         * source or result will always be just "int").
+         *
+         * And const instruction need to distinguish between strings and
+         * classes.
+         */
+
+        switch (rop.getOpcode()) {
+            case RegOps.MOVE_EXCEPTION:   return Dops.MOVE_EXCEPTION;
+            case RegOps.INVOKE_STATIC:    return Dops.INVOKE_STATIC;
+            case RegOps.INVOKE_VIRTUAL:   return Dops.INVOKE_VIRTUAL;
+            case RegOps.INVOKE_SUPER:     return Dops.INVOKE_SUPER;
+            case RegOps.INVOKE_DIRECT:    return Dops.INVOKE_DIRECT;
+            case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
+            case RegOps.NEW_ARRAY:        return Dops.NEW_ARRAY;
+            case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
+            case RegOps.FILL_ARRAY_DATA:  return Dops.FILL_ARRAY_DATA;
+            case RegOps.MOVE_RESULT: {
+                RegisterSpec resultReg = insn.getResult();
+
+                if (resultReg == null) {
+                    return Dops.NOP;
+                } else {
+                    switch (resultReg.getBasicType()) {
+                        case Type.BT_INT:
+                        case Type.BT_FLOAT:
+                        case Type.BT_BOOLEAN:
+                        case Type.BT_BYTE:
+                        case Type.BT_CHAR:
+                        case Type.BT_SHORT:
+                            return Dops.MOVE_RESULT;
+                        case Type.BT_LONG:
+                        case Type.BT_DOUBLE:
+                            return Dops.MOVE_RESULT_WIDE;
+                        case Type.BT_OBJECT:
+                            return Dops.MOVE_RESULT_OBJECT;
+                        default: {
+                            throw new RuntimeException("Unexpected basic type");
+                        }
+                    }
+                }
+            }
+
+            case RegOps.GET_FIELD: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.IGET_BYTE;
+                    case Type.BT_CHAR:    return Dops.IGET_CHAR;
+                    case Type.BT_SHORT:   return Dops.IGET_SHORT;
+                    case Type.BT_INT:     return Dops.IGET;
+                }
+                break;
+            }
+            case RegOps.PUT_FIELD: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.IPUT_BYTE;
+                    case Type.BT_CHAR:    return Dops.IPUT_CHAR;
+                    case Type.BT_SHORT:   return Dops.IPUT_SHORT;
+                    case Type.BT_INT:     return Dops.IPUT;
+                }
+                break;
+            }
+            case RegOps.GET_STATIC: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.SGET_BYTE;
+                    case Type.BT_CHAR:    return Dops.SGET_CHAR;
+                    case Type.BT_SHORT:   return Dops.SGET_SHORT;
+                    case Type.BT_INT:     return Dops.SGET;
+                }
+                break;
+            }
+            case RegOps.PUT_STATIC: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.SPUT_BYTE;
+                    case Type.BT_CHAR:    return Dops.SPUT_CHAR;
+                    case Type.BT_SHORT:   return Dops.SPUT_SHORT;
+                    case Type.BT_INT:     return Dops.SPUT;
+                }
+                break;
+            }
+            case RegOps.CONST: {
+                Constant cst = ((ThrowingCstInsn) insn).getConstant();
+                if (cst instanceof CstType) {
+                    return Dops.CONST_CLASS;
+                } else if (cst instanceof CstString) {
+                    return Dops.CONST_STRING;
+                }
+                break;
+            }
+        }
+
+        throw new RuntimeException("unknown rop: " + rop);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/RopTranslator.java b/dexgen/src/com/android/dexgen/dex/code/RopTranslator.java
new file mode 100644
index 0000000..ad05f2b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/RopTranslator.java
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.BasicBlock;
+import com.android.dexgen.rop.code.BasicBlockList;
+import com.android.dexgen.rop.code.FillArrayDataInsn;
+import com.android.dexgen.rop.code.Insn;
+import com.android.dexgen.rop.code.LocalVariableInfo;
+import com.android.dexgen.rop.code.PlainCstInsn;
+import com.android.dexgen.rop.code.PlainInsn;
+import com.android.dexgen.rop.code.RegOps;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.RegisterSpecSet;
+import com.android.dexgen.rop.code.Rop;
+import com.android.dexgen.rop.code.RopMethod;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.rop.code.SwitchInsn;
+import com.android.dexgen.rop.code.ThrowingCstInsn;
+import com.android.dexgen.rop.code.ThrowingInsn;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstInteger;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Bits;
+import com.android.dexgen.util.IntList;
+
+import java.util.ArrayList;
+
+/**
+ * Translator from {@link RopMethod} to {@link DalvCode}. The {@link
+ * #translate} method is the thing to call on this class.
+ */
+public final class RopTranslator {
+    /** {@code non-null;} method to translate */
+    private final RopMethod method;
+
+    /**
+     * how much position info to preserve; one of the static
+     * constants in {@link PositionList}
+     */
+    private final int positionInfo;
+
+    /** {@code null-ok;} local variable info to use */
+    private final LocalVariableInfo locals;
+
+    /** {@code non-null;} container for all the address objects for the method */
+    private final BlockAddresses addresses;
+
+    /** {@code non-null;} list of output instructions in-progress */
+    private final OutputCollector output;
+
+    /** {@code non-null;} visitor to use during translation */
+    private final TranslationVisitor translationVisitor;
+
+    /** {@code >= 0;} register count for the method */
+    private final int regCount;
+
+    /** {@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 */
+    private final int paramSize;
+
+    /**
+     * true if the parameters to this method happen to be in proper order
+     * at the end of the frame (as the optimizer emits them)
+     */
+    private boolean paramsAreInOrder;
+
+    /**
+     * Translates a {@link RopMethod}. This may modify the given
+     * input.
+     *
+     * @param method {@code non-null;} the original method
+     * @param positionInfo how much position info to preserve; one of the
+     * static constants in {@link PositionList}
+     * @param locals {@code null-ok;} local variable information to use
+     * @param paramSize size, in register units, of all the parameters to
+     * this method
+     * @return {@code non-null;} the translated version
+     */
+    public static DalvCode translate(RopMethod method, int positionInfo,
+                                     LocalVariableInfo locals, int paramSize) {
+        RopTranslator translator =
+            new RopTranslator(method, positionInfo, locals,
+                    paramSize);
+        return translator.translateAndGetResult();
+    }
+
+    /**
+     * Constructs an instance. This method is private. Use {@link #translate}.
+     *
+     * @param method {@code non-null;} the original method
+     * @param positionInfo how much position info to preserve; one of the
+     * static constants in {@link PositionList}
+     * @param locals {@code null-ok;} local variable information to use
+     * @param paramSize size, in register units, of all the parameters to
+     * this method
+     */
+    private RopTranslator(RopMethod method, int positionInfo,
+                          LocalVariableInfo locals, int paramSize) {
+        this.method = method;
+        this.positionInfo = positionInfo;
+        this.locals = locals;
+        this.addresses = new BlockAddresses(method);
+        this.paramSize = paramSize;
+        this.order = null;
+        this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize);
+
+        BasicBlockList blocks = method.getBlocks();
+        int bsz = blocks.size();
+
+        /*
+         * Max possible instructions includes three code address
+         * objects per basic block (to the first and last instruction,
+         * and just past the end of the block), and the possibility of
+         * an extra goto at the end of each basic block.
+         */
+        int maxInsns = (bsz * 3) + blocks.getInstructionCount();
+
+        if (locals != null) {
+            /*
+             * If we're tracking locals, then there's could be another
+             * extra instruction per block (for the locals state at the
+             * start of the block) as well as one for each interblock
+             * local introduction.
+             */
+            maxInsns += bsz + locals.getAssignmentCount();
+        }
+
+        /*
+         * If params are not in order, we will need register space
+         * for them before this is all over...
+         */
+        this.regCount = blocks.getRegCount()
+                + (paramsAreInOrder ? 0 : this.paramSize);
+
+        this.output = new OutputCollector(maxInsns, bsz * 3, regCount);
+
+        if (locals != null) {
+            this.translationVisitor =
+                new LocalVariableAwareTranslationVisitor(output, locals);
+        } else {
+            this.translationVisitor = new TranslationVisitor(output);
+        }
+    }
+
+    /**
+     * Checks to see if the move-param instructions that occur in this
+     * method happen to slot the params in an order at the top of the
+     * stack frame that matches dalvik's calling conventions. This will
+     * alway result in "true" for methods that have run through the
+     * SSA optimizer.
+     *
+     * @param paramSize size, in register units, of all the parameters
+     * to this method
+     */
+    private static boolean calculateParamsAreInOrder(RopMethod method,
+            final int paramSize) {
+        final boolean[] paramsAreInOrder = { true };
+        final int initialRegCount = method.getBlocks().getRegCount();
+
+        /*
+         * We almost could just check the first block here, but the
+         * {@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() {
+            public void visitPlainCstInsn(PlainCstInsn insn) {
+                if (insn.getOpcode().getOpcode()== RegOps.MOVE_PARAM) {
+                    int param =
+                        ((CstInteger) insn.getConstant()).getValue();
+
+                    paramsAreInOrder[0] = paramsAreInOrder[0]
+                            && ((initialRegCount - paramSize + param)
+                                == insn.getResult().getReg());
+                }
+            }
+        });
+
+        return paramsAreInOrder[0];
+    }
+
+    /**
+     * Does the translation and returns the result.
+     *
+     * @return {@code non-null;} the result
+     */
+    private DalvCode translateAndGetResult() {
+        pickOrder();
+        outputInstructions();
+
+        StdCatchBuilder catches =
+            new StdCatchBuilder(method, order, addresses);
+
+        return new DalvCode(positionInfo, output.getFinisher(), catches);
+    }
+
+    /**
+     * Performs initial creation of output instructions based on the
+     * original blocks.
+     */
+    private void outputInstructions() {
+        BasicBlockList blocks = method.getBlocks();
+        int[] order = this.order;
+        int len = order.length;
+
+        // Process the blocks in output order.
+        for (int i = 0; i < len; i++) {
+            int nextI = i + 1;
+            int nextLabel = (nextI == order.length) ? -1 : order[nextI];
+            outputBlock(blocks.labelToBlock(order[i]), nextLabel);
+        }
+    }
+
+    /**
+     * Helper for {@link #outputInstructions}, which does the processing
+     * and output of one block.
+     *
+     * @param block {@code non-null;} the block to process and output
+     * @param nextLabel {@code >= -1;} the next block that will be processed, or
+     * {@code -1} if there is no next block
+     */
+    private void outputBlock(BasicBlock block, int nextLabel) {
+        // Append the code address for this block.
+        CodeAddress startAddress = addresses.getStart(block);
+        output.add(startAddress);
+
+        // Append the local variable state for the block.
+        if (locals != null) {
+            RegisterSpecSet starts = locals.getStarts(block);
+            output.add(new LocalSnapshot(startAddress.getPosition(),
+                                         starts));
+        }
+
+        /*
+         * Choose and append an output instruction for each original
+         * instruction.
+         */
+        translationVisitor.setBlock(block, addresses.getLast(block));
+        block.getInsns().forEach(translationVisitor);
+
+        // Insert the block end code address.
+        output.add(addresses.getEnd(block));
+
+        // Set up for end-of-block activities.
+
+        int succ = block.getPrimarySuccessor();
+        Insn lastInsn = block.getLastInsn();
+
+        /*
+         * Check for (and possibly correct for) a non-optimal choice of
+         * which block will get output next.
+         */
+
+        if ((succ >= 0) && (succ != nextLabel)) {
+            /*
+             * The block has a "primary successor" and that primary
+             * successor isn't the next block to be output.
+             */
+            Rop lastRop = lastInsn.getOpcode();
+            if ((lastRop.getBranchingness() == Rop.BRANCH_IF) &&
+                    (block.getSecondarySuccessor() == nextLabel)) {
+                /*
+                 * The block ends with an "if" of some sort, and its
+                 * secondary successor (the "then") is in fact the
+                 * next block to output. So, reverse the sense of
+                 * the test, so that we can just emit the next block
+                 * without an interstitial goto.
+                 */
+                output.reverseBranch(1, addresses.getStart(succ));
+            } else {
+                /*
+                 * Our only recourse is to add a goto here to get the
+                 * flow to be correct.
+                 */
+                TargetInsn insn =
+                    new TargetInsn(Dops.GOTO, lastInsn.getPosition(),
+                            RegisterSpecList.EMPTY,
+                            addresses.getStart(succ));
+                output.add(insn);
+            }
+        }
+    }
+
+    /**
+     * Picks an order for the blocks by doing "trace" analysis.
+     */
+    private void pickOrder() {
+        BasicBlockList blocks = method.getBlocks();
+        int sz = blocks.size();
+        int maxLabel = blocks.getMaxLabel();
+        int[] workSet = Bits.makeBitSet(maxLabel);
+        int[] tracebackSet = Bits.makeBitSet(maxLabel);
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = blocks.get(i);
+            Bits.set(workSet, one.getLabel());
+        }
+
+        int[] order = new int[sz];
+        int at = 0;
+
+        /*
+         * Starting with the designated "first label" (that is, the
+         * first block of the method), add that label to the order,
+         * and then pick its first as-yet unordered successor to
+         * immediately follow it, giving top priority to the primary
+         * (aka default) successor (if any). Keep following successors
+         * until the trace runs out of possibilities. Then, continue
+         * by finding an unordered chain containing the first as-yet
+         * unordered block, and adding it to the order, and so on.
+         */
+        for (int label = method.getFirstLabel();
+             label != -1;
+             label = Bits.findFirst(workSet, 0)) {
+
+            /*
+             * Attempt to trace backward from the chosen block to an
+             * as-yet unordered predecessor which lists the chosen
+             * block as its primary successor, and so on, until we
+             * fail to find such an unordered predecessor. Start the
+             * trace with that block. Note that the first block in the
+             * method has no predecessors, so in that case this loop
+             * will simply terminate with zero iterations and without
+             * picking a new starter block.
+             */
+            traceBack:
+            for (;;) {
+                IntList preds = method.labelToPredecessors(label);
+                int psz = preds.size();
+
+                for (int i = 0; i < psz; i++) {
+                    int predLabel = preds.get(i);
+
+                    if (Bits.get(tracebackSet, predLabel)) {
+                        /*
+                         * We found a predecessor loop; stop tracing back
+                         * from here.
+                         */
+                        break;
+                    }
+
+                    if (!Bits.get(workSet, predLabel)) {
+                        // This one's already ordered.
+                        continue;
+                    }
+
+                    BasicBlock pred = blocks.labelToBlock(predLabel);
+                    if (pred.getPrimarySuccessor() == label) {
+                        // Found one!
+                        label = predLabel;
+                        Bits.set(tracebackSet, label);
+                        continue traceBack;
+                    }
+                }
+
+                // Failed to find a better block to start the trace.
+                break;
+            }
+
+            /*
+             * Trace a path from the chosen block to one of its
+             * unordered successors (hopefully the primary), and so
+             * on, until we run out of unordered successors.
+             */
+            while (label != -1) {
+                Bits.clear(workSet, label);
+                Bits.clear(tracebackSet, label);
+                order[at] = label;
+                at++;
+
+                BasicBlock one = blocks.labelToBlock(label);
+                BasicBlock preferredBlock = blocks.preferredSuccessorOf(one);
+
+                if (preferredBlock == null) {
+                    break;
+                }
+
+                int preferred = preferredBlock.getLabel();
+                int primary = one.getPrimarySuccessor();
+
+                if (Bits.get(workSet, preferred)) {
+                    /*
+                     * Order the current block's preferred successor
+                     * next, as it has yet to be scheduled.
+                     */
+                    label = preferred;
+                } else if ((primary != preferred) && (primary >= 0)
+                        && Bits.get(workSet, primary)) {
+                    /*
+                     * The primary is available, so use that.
+                     */
+                    label = primary;
+                } else {
+                    /*
+                     * There's no obvious candidate, so pick the first
+                     * one that's available, if any.
+                     */
+                    IntList successors = one.getSuccessors();
+                    int ssz = successors.size();
+                    label = -1;
+                    for (int i = 0; i < ssz; i++) {
+                        int candidate = successors.get(i);
+                        if (Bits.get(workSet, candidate)) {
+                            label = candidate;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (at != sz) {
+            // There was a duplicate block label.
+            throw new RuntimeException("shouldn't happen");
+        }
+
+        this.order = order;
+    }
+
+    /**
+     * Gets the complete register list (result and sources) out of a
+     * given rop instruction. For insns that are commutative, have
+     * two register sources, and have a source equal to the result,
+     * place that source first.
+     *
+     * @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());
+    }
+
+    /**
+     * Gets the complete register list (result and sources) out of a
+     * given rop instruction. For insns that are commutative, have
+     * two register sources, and have a source equal to the result,
+     * place that source first.
+     *
+     * @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) {
+        RegisterSpecList regs = insn.getSources();
+
+        if (insn.getOpcode().isCommutative()
+                && (regs.size() == 2)
+                && (resultReg.getReg() == regs.get(1).getReg())) {
+
+            /*
+             * For commutative ops which have two register sources,
+             * if the second source is the same register as the result,
+             * swap the sources so that an opcode of form 12x can be selected
+             * instead of one of form 23x
+             */
+
+            regs = RegisterSpecList.make(regs.get(1), regs.get(0));
+        }
+
+        if (resultReg == null) {
+            return regs;
+        }
+
+        return regs.withFirst(resultReg);
+    }
+
+    /**
+     * Instruction visitor class for doing the instruction translation per se.
+     */
+    private class TranslationVisitor implements Insn.Visitor {
+        /** {@code non-null;} list of output instructions in-progress */
+        private final OutputCollector output;
+
+        /** {@code non-null;} basic block being worked on */
+        private BasicBlock block;
+
+        /**
+         * {@code null-ok;} code address for the salient last instruction of the
+         * block (used before switches and throwing instructions)
+         */
+        private CodeAddress lastAddress;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param output {@code non-null;} destination for instruction output
+         */
+        public TranslationVisitor(OutputCollector output) {
+            this.output = output;
+        }
+
+        /**
+         * Sets the block currently being worked on.
+         *
+         * @param block {@code non-null;} the block
+         * @param lastAddress {@code non-null;} code address for the salient
+         * last instruction of the block
+         */
+        public void setBlock(BasicBlock block, CodeAddress lastAddress) {
+            this.block = block;
+            this.lastAddress = lastAddress;
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainInsn(PlainInsn insn) {
+            Rop rop = insn.getOpcode();
+            if (rop.getOpcode() == RegOps.MARK_LOCAL) {
+                /*
+                 * Ignore these. They're dealt with by
+                 * the LocalVariableAwareTranslationVisitor
+                 */
+                return;
+            }
+            if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+                // These get skipped
+                return;
+            }
+
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            DalvInsn di;
+
+            switch (rop.getBranchingness()) {
+                case Rop.BRANCH_NONE:
+                case Rop.BRANCH_RETURN:
+                case Rop.BRANCH_THROW: {
+                    di = new SimpleInsn(opcode, pos, getRegs(insn));
+                    break;
+                }
+                case Rop.BRANCH_GOTO: {
+                    /*
+                     * Code in the main translation loop will emit a
+                     * goto if necessary (if the branch isn't to the
+                     * immediately subsequent block).
+                     */
+                    return;
+                }
+                case Rop.BRANCH_IF: {
+                    int target = block.getSuccessors().get(1);
+                    di = new TargetInsn(opcode, pos, getRegs(insn),
+                                        addresses.getStart(target));
+                    break;
+                }
+                default: {
+                    throw new RuntimeException("shouldn't happen");
+                }
+            }
+
+            addOutput(di);
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            Rop rop = insn.getOpcode();
+            int ropOpcode = rop.getOpcode();
+            DalvInsn di;
+
+            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            if (ropOpcode == RegOps.MOVE_PARAM) {
+                if (!paramsAreInOrder) {
+                    /*
+                     * Parameters are not in order at the top of the reg space.
+                     * We need to add moves.
+                     */
+
+                    RegisterSpec dest = insn.getResult();
+                    int param =
+                        ((CstInteger) insn.getConstant()).getValue();
+                    RegisterSpec source =
+                        RegisterSpec.make(regCount - paramSize + param,
+                                dest.getType());
+                    di = new SimpleInsn(opcode, pos,
+                                        RegisterSpecList.make(dest, source));
+                    addOutput(di);
+                }
+            } else {
+                // No moves required for the parameters
+                RegisterSpecList regs = getRegs(insn);
+                di = new CstInsn(opcode, pos, regs, insn.getConstant());
+                addOutput(di);
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitchInsn(SwitchInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            IntList cases = insn.getCases();
+            IntList successors = block.getSuccessors();
+            int casesSz = cases.size();
+            int succSz = successors.size();
+            int primarySuccessor = block.getPrimarySuccessor();
+
+            /*
+             * Check the assumptions that the number of cases is one
+             * less than the number of successors and that the last
+             * successor in the list is the primary (in this case, the
+             * default). This test is here to guard against forgetting
+             * to change this code if the way switch instructions are
+             * constructed also gets changed.
+             */
+            if ((casesSz != (succSz - 1)) ||
+                (primarySuccessor != successors.get(casesSz))) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            CodeAddress[] switchTargets = new CodeAddress[casesSz];
+
+            for (int i = 0; i < casesSz; i++) {
+                int label = successors.get(i);
+                switchTargets[i] = addresses.getStart(label);
+            }
+
+            CodeAddress dataAddress = new CodeAddress(pos);
+            SwitchData dataInsn =
+                new SwitchData(pos, lastAddress, cases, switchTargets);
+            Dop opcode = dataInsn.isPacked() ?
+                Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
+            TargetInsn switchInsn =
+                new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
+
+            addOutput(lastAddress);
+            addOutput(switchInsn);
+
+            addOutputSuffix(new OddSpacer(pos));
+            addOutputSuffix(dataAddress);
+            addOutputSuffix(dataInsn);
+        }
+
+        /**
+         * Looks forward to the current block's primary successor, returning
+         * the RegisterSpec of the result of the move-result-pseudo at the
+         * top of that block or null if none.
+         *
+         * @return {@code null-ok;} result of move-result-pseudo at the beginning of
+         * primary successor
+         */
+        private RegisterSpec getNextMoveResultPseudo()
+        {
+            int label = block.getPrimarySuccessor();
+
+            if (label < 0) {
+                return null;
+            }
+
+            Insn insn
+                    = method.getBlocks().labelToBlock(label).getInsns().get(0);
+
+            if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) {
+                return null;
+            } else {
+                return insn.getResult();
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            Rop rop = insn.getOpcode();
+            Constant cst = insn.getConstant();
+
+            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            addOutput(lastAddress);
+
+            if (rop.isCallLike()) {
+                RegisterSpecList regs = insn.getSources();
+                DalvInsn di = new CstInsn(opcode, pos, regs, cst);
+
+                addOutput(di);
+            } else {
+                RegisterSpec realResult = getNextMoveResultPseudo();
+
+                RegisterSpecList regs = getRegs(insn, realResult);
+                DalvInsn di;
+
+                boolean hasResult = opcode.hasResult()
+                        || (rop.getOpcode() == RegOps.CHECK_CAST);
+
+                if (hasResult != (realResult != null)) {
+                    throw new RuntimeException(
+                            "Insn with result/move-result-pseudo mismatch " +
+                            insn);
+                }
+
+                if ((rop.getOpcode() == RegOps.NEW_ARRAY) &&
+                    (opcode.getOpcode() != DalvOps.NEW_ARRAY)) {
+                    /*
+                     * It's a type-specific new-array-<primitive>, and
+                     * so it should be turned into a SimpleInsn (no
+                     * constant ref as it's implicit).
+                     */
+                    di = new SimpleInsn(opcode, pos, regs);
+                } else {
+                    /*
+                     * This is the general case for constant-bearing
+                     * instructions.
+                     */
+                    di = new CstInsn(opcode, pos, regs, cst);
+                }
+
+                addOutput(di);
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            Rop rop = insn.getOpcode();
+            RegisterSpec realResult;
+
+            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            realResult = getNextMoveResultPseudo();
+
+            if (opcode.hasResult() != (realResult != null)) {
+                throw new RuntimeException(
+                        "Insn with result/move-result-pseudo mismatch" + insn);
+            }
+
+            addOutput(lastAddress);
+
+            DalvInsn di = new SimpleInsn(opcode, pos,
+                    getRegs(insn, realResult));
+
+            addOutput(di);
+        }
+
+        /** {@inheritDoc} */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Constant cst = insn.getConstant();
+            ArrayList<Constant> values = insn.getInitValues();
+            Rop rop = insn.getOpcode();
+
+            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
+                throw new RuntimeException("shouldn't happen");
+            }
+            CodeAddress dataAddress = new CodeAddress(pos);
+            ArrayData dataInsn =
+                new ArrayData(pos, lastAddress, values, cst);
+
+            TargetInsn fillArrayDataInsn =
+                new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn),
+                        dataAddress);
+
+            addOutput(lastAddress);
+            addOutput(fillArrayDataInsn);
+
+            addOutputSuffix(new OddSpacer(pos));
+            addOutputSuffix(dataAddress);
+            addOutputSuffix(dataInsn);
+        }
+
+        /**
+         * Adds to the output.
+         *
+         * @param insn {@code non-null;} instruction to add
+         */
+        protected void addOutput(DalvInsn insn) {
+            output.add(insn);
+        }
+
+        /**
+         * Adds to the output suffix.
+         *
+         * @param insn {@code non-null;} instruction to add
+         */
+        protected void addOutputSuffix(DalvInsn insn) {
+            output.addSuffix(insn);
+        }
+    }
+
+    /**
+     * Instruction visitor class for doing instruction translation with
+     * local variable tracking
+     */
+    private class LocalVariableAwareTranslationVisitor
+            extends TranslationVisitor {
+        /** {@code non-null;} local variable info */
+        private LocalVariableInfo locals;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param output {@code non-null;} destination for instruction output
+         * @param locals {@code non-null;} the local variable info
+         */
+        public LocalVariableAwareTranslationVisitor(OutputCollector output,
+                                                    LocalVariableInfo locals) {
+            super(output);
+            this.locals = locals;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitPlainInsn(PlainInsn insn) {
+            super.visitPlainInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            super.visitPlainCstInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitSwitchInsn(SwitchInsn insn) {
+            super.visitSwitchInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            super.visitThrowingCstInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            super.visitThrowingInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /**
+         * Adds a {@link LocalStart} to the output if the given
+         * instruction in fact introduces a local variable.
+         *
+         * @param insn {@code non-null;} instruction in question
+         */
+        public void addIntroductionIfNecessary(Insn insn) {
+            RegisterSpec spec = locals.getAssignment(insn);
+
+            if (spec != null) {
+                addOutput(new LocalStart(insn.getPosition(), spec));
+            }
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/SimpleInsn.java b/dexgen/src/com/android/dexgen/dex/code/SimpleInsn.java
new file mode 100644
index 0000000..abef242
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/SimpleInsn.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Instruction which has no extra info beyond the basics provided for in
+ * the base class.
+ */
+public final class SimpleInsn extends FixedSizeInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     */
+    public SimpleInsn(Dop opcode, SourcePosition position,
+                      RegisterSpecList registers) {
+        super(opcode, position, registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withOpcode(Dop opcode) {
+        return new SimpleInsn(opcode, getPosition(), getRegisters());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new SimpleInsn(getOpcode(), getPosition(), registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/StdCatchBuilder.java b/dexgen/src/com/android/dexgen/dex/code/StdCatchBuilder.java
new file mode 100644
index 0000000..ba149e7
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/StdCatchBuilder.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.BasicBlock;
+import com.android.dexgen.rop.code.BasicBlockList;
+import com.android.dexgen.rop.code.RopMethod;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.IntList;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * Constructor of {@link CatchTable} instances from {@link RopMethod}
+ * and associated data.
+ */
+public final class StdCatchBuilder implements CatchBuilder {
+    /** the maximum range of a single catch handler, in code units */
+    private static final int MAX_CATCH_RANGE = 65535;
+
+    /** {@code non-null;} method to build the list for */
+    private final RopMethod method;
+
+    /** {@code non-null;} block output order */
+    private final int[] order;
+
+    /** {@code non-null;} address objects for each block */
+    private final BlockAddresses addresses;
+
+    /**
+     * Constructs an instance. It merely holds onto its parameters for
+     * a subsequent call to {@link #build}.
+     *
+     * @param method {@code non-null;} method to build the list for
+     * @param order {@code non-null;} block output order
+     * @param addresses {@code non-null;} address objects for each block
+     */
+    public StdCatchBuilder(RopMethod method, int[] order,
+            BlockAddresses addresses) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (order == null) {
+            throw new NullPointerException("order == null");
+        }
+
+        if (addresses == null) {
+            throw new NullPointerException("addresses == null");
+        }
+
+        this.method = method;
+        this.order = order;
+        this.addresses = addresses;
+    }
+
+    /** {@inheritDoc} */
+    public CatchTable build() {
+        return build(method, order, addresses);
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasAnyCatches() {
+        BasicBlockList blocks = method.getBlocks();
+        int size = blocks.size();
+
+        for (int i = 0; i < size; i++) {
+            BasicBlock block = blocks.get(i);
+            TypeList catches = block.getLastInsn().getCatches();
+            if (catches.size() != 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public HashSet<Type> getCatchTypes() {
+        HashSet<Type> result = new HashSet<Type>(20);
+        BasicBlockList blocks = method.getBlocks();
+        int size = blocks.size();
+
+        for (int i = 0; i < size; i++) {
+            BasicBlock block = blocks.get(i);
+            TypeList catches = block.getLastInsn().getCatches();
+            int catchSize = catches.size();
+
+            for (int j = 0; j < catchSize; j++) {
+                result.add(catches.getType(j));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Builds and returns the catch table for a given method.
+     *
+     * @param method {@code non-null;} method to build the list for
+     * @param order {@code non-null;} block output order
+     * @param addresses {@code non-null;} address objects for each block
+     * @return {@code non-null;} the constructed table
+     */
+    public static CatchTable build(RopMethod method, int[] order,
+            BlockAddresses addresses) {
+        int len = order.length;
+        BasicBlockList blocks = method.getBlocks();
+        ArrayList<CatchTable.Entry> resultList =
+            new ArrayList<CatchTable.Entry>(len);
+        CatchHandlerList currentHandlers = CatchHandlerList.EMPTY;
+        BasicBlock currentStartBlock = null;
+        BasicBlock currentEndBlock = null;
+
+        for (int i = 0; i < len; i++) {
+            BasicBlock block = blocks.labelToBlock(order[i]);
+
+            if (!block.canThrow()) {
+                /*
+                 * There is no need to concern ourselves with the
+                 * placement of blocks that can't throw with respect
+                 * to the blocks that *can* throw.
+                 */
+                continue;
+            }
+
+            CatchHandlerList handlers = handlersFor(block, addresses);
+
+            if (currentHandlers.size() == 0) {
+                // This is the start of a new catch range.
+                currentStartBlock = block;
+                currentEndBlock = block;
+                currentHandlers = handlers;
+                continue;
+            }
+
+            if (currentHandlers.equals(handlers)
+                    && rangeIsValid(currentStartBlock, block, addresses)) {
+                /*
+                 * The block we are looking at now has the same handlers
+                 * as the block that started the currently open catch
+                 * range, and adding it to the currently open range won't
+                 * cause it to be too long.
+                 */
+                currentEndBlock = block;
+                continue;
+            }
+
+            /*
+             * The block we are looking at now has incompatible handlers,
+             * so we need to finish off the last entry and start a new
+             * one. Note: We only emit an entry if it has associated handlers.
+             */
+            if (currentHandlers.size() != 0) {
+                CatchTable.Entry entry =
+                    makeEntry(currentStartBlock, currentEndBlock,
+                            currentHandlers, addresses);
+                resultList.add(entry);
+            }
+
+            currentStartBlock = block;
+            currentEndBlock = block;
+            currentHandlers = handlers;
+        }
+
+        if (currentHandlers.size() != 0) {
+            // Emit an entry for the range that was left hanging.
+            CatchTable.Entry entry =
+                makeEntry(currentStartBlock, currentEndBlock,
+                        currentHandlers, addresses);
+            resultList.add(entry);
+        }
+
+        // Construct the final result.
+
+        int resultSz = resultList.size();
+
+        if (resultSz == 0) {
+            return CatchTable.EMPTY;
+        }
+
+        CatchTable result = new CatchTable(resultSz);
+
+        for (int i = 0; i < resultSz; i++) {
+            result.set(i, resultList.get(i));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Makes the {@link CatchHandlerList} for the given basic block.
+     *
+     * @param block {@code non-null;} block to get entries for
+     * @param addresses {@code non-null;} address objects for each block
+     * @return {@code non-null;} array of entries
+     */
+    private static CatchHandlerList handlersFor(BasicBlock block,
+            BlockAddresses addresses) {
+        IntList successors = block.getSuccessors();
+        int succSize = successors.size();
+        int primary = block.getPrimarySuccessor();
+        TypeList catches = block.getLastInsn().getCatches();
+        int catchSize = catches.size();
+
+        if (catchSize == 0) {
+            return CatchHandlerList.EMPTY;
+        }
+
+        if (((primary == -1) && (succSize != catchSize))
+                || ((primary != -1) &&
+                        ((succSize != (catchSize + 1))
+                                || (primary != successors.get(catchSize))))) {
+            /*
+             * Blocks that throw are supposed to list their primary
+             * successor -- if any -- last in the successors list, but
+             * that constraint appears to be violated here.
+             */
+            throw new RuntimeException(
+                    "shouldn't happen: weird successors list");
+        }
+
+        /*
+         * Reduce the effective catchSize if we spot a catch-all that
+         * isn't at the end.
+         */
+        for (int i = 0; i < catchSize; i++) {
+            Type type = catches.getType(i);
+            if (type.equals(Type.OBJECT)) {
+                catchSize = i + 1;
+                break;
+            }
+        }
+
+        CatchHandlerList result = new CatchHandlerList(catchSize);
+
+        for (int i = 0; i < catchSize; i++) {
+            CstType oneType = new CstType(catches.getType(i));
+            CodeAddress oneHandler = addresses.getStart(successors.get(i));
+            result.set(i, oneType, oneHandler.getAddress());
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Makes a {@link CatchTable#Entry} for the given block range and
+     * handlers.
+     *
+     * @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,
+            BlockAddresses addresses) {
+        /*
+         * We start at the *last* instruction of the start block, since
+         * that's the instruction that can throw...
+         */
+        CodeAddress startAddress = addresses.getLast(start);
+
+        // ...And we end *after* the last instruction of the end block.
+        CodeAddress endAddress = addresses.getEnd(end);
+
+        return new CatchTable.Entry(startAddress.getAddress(),
+                endAddress.getAddress(), handlers);
+    }
+
+    /**
+     * Gets whether the address range for the given two blocks is valid
+     * for a catch handler. This is true as long as the covered range is
+     * under 65536 code units.
+     *
+     * @param start {@code non-null;} the start block for the range (inclusive)
+     * @param end {@code non-null;} the start block for the range (also inclusive)
+     * @param addresses {@code non-null;} address objects for each block
+     * @return {@code true} if the range is valid as a catch range
+     */
+    private static boolean rangeIsValid(BasicBlock start, BasicBlock end,
+            BlockAddresses addresses) {
+        if (start == null) {
+            throw new NullPointerException("start == null");
+        }
+
+        if (end == null) {
+            throw new NullPointerException("end == null");
+        }
+
+        // See above about selection of instructions.
+        int startAddress = addresses.getLast(start).getAddress();
+        int endAddress = addresses.getEnd(end).getAddress();
+
+        return (endAddress - startAddress) <= MAX_CATCH_RANGE;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/SwitchData.java b/dexgen/src/com/android/dexgen/dex/code/SwitchData.java
new file mode 100644
index 0000000..a7d8465
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/SwitchData.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.IntList;
+
+/**
+ * Pseudo-instruction which holds switch data. The switch data is
+ * a map of values to target addresses, and this class writes the data
+ * in either a "packed" or "sparse" form.
+ */
+public final class SwitchData extends VariableSizeInsn {
+    /**
+     * {@code non-null;} address representing the instruction that uses this
+     * instance
+     */
+    private final CodeAddress user;
+
+    /** {@code non-null;} sorted list of switch cases (keys) */
+    private final IntList cases;
+
+    /**
+     * {@code non-null;} corresponding list of code addresses; the branch
+     * target for each case
+     */
+    private final CodeAddress[] targets;
+
+    /** whether the output table will be packed (vs. sparse) */
+    private final boolean packed;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param user {@code non-null;} address representing the instruction that
+     * uses this instance
+     * @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,
+                      IntList cases, CodeAddress[] targets) {
+        super(position, RegisterSpecList.EMPTY);
+
+        if (user == null) {
+            throw new NullPointerException("user == null");
+        }
+
+        if (cases == null) {
+            throw new NullPointerException("cases == null");
+        }
+
+        if (targets == null) {
+            throw new NullPointerException("targets == null");
+        }
+
+        int sz = cases.size();
+
+        if (sz != targets.length) {
+            throw new IllegalArgumentException("cases / targets mismatch");
+        }
+
+        if (sz > 65535) {
+            throw new IllegalArgumentException("too many cases");
+        }
+
+        this.user = user;
+        this.cases = cases;
+        this.targets = targets;
+        this.packed = shouldPack(cases);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return packed ? (int) packedCodeSize(cases) :
+            (int) sparseCodeSize(cases);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        int baseAddress = user.getAddress();
+        int defaultTarget = Dops.PACKED_SWITCH.getFormat().codeSize();
+        int sz = targets.length;
+
+        if (packed) {
+            int firstCase = (sz == 0) ? 0 : cases.get(0);
+            int lastCase = (sz == 0) ? 0 : cases.get(sz - 1);
+            int outSz = lastCase - firstCase + 1;
+
+            out.writeShort(0x100 | DalvOps.NOP);
+            out.writeShort(outSz);
+            out.writeInt(firstCase);
+
+            int caseAt = 0;
+            for (int i = 0; i < outSz; i++) {
+                int outCase = firstCase + i;
+                int oneCase = cases.get(caseAt);
+                int relTarget;
+
+                if (oneCase > outCase) {
+                    relTarget = defaultTarget;
+                } else {
+                    relTarget = targets[caseAt].getAddress() - baseAddress;
+                    caseAt++;
+                }
+
+                out.writeInt(relTarget);
+            }
+        } else {
+            out.writeShort(0x200 | DalvOps.NOP);
+            out.writeShort(sz);
+
+            for (int i = 0; i < sz; i++) {
+                out.writeInt(cases.get(i));
+            }
+
+            for (int i = 0; i < sz; i++) {
+                int relTarget = targets[i].getAddress() - baseAddress;
+                out.writeInt(relTarget);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new SwitchData(getPosition(), user, cases, targets);
+    }
+
+    /**
+     * Returns whether or not this instance's data will be output as packed.
+     *
+     * @return {@code true} iff the data is to be packed
+     */
+    public boolean isPacked() {
+        return packed;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        int sz = targets.length;
+        for (int i = 0; i < sz; i++) {
+            sb.append("\n    ");
+            sb.append(cases.get(i));
+            sb.append(": ");
+            sb.append(targets[i]);
+        }
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        int baseAddress = user.getAddress();
+        StringBuffer sb = new StringBuffer(100);
+        int sz = targets.length;
+
+        sb.append(packed ? "packed" : "sparse");
+        sb.append("-switch-data // for switch @ ");
+        sb.append(Hex.u2(baseAddress));
+
+        for (int i = 0; i < sz; i++) {
+            int absTarget = targets[i].getAddress();
+            int relTarget = absTarget - baseAddress;
+            sb.append("\n  ");
+            sb.append(cases.get(i));
+            sb.append(": ");
+            sb.append(Hex.u4(absTarget));
+            sb.append(" // ");
+            sb.append(Hex.s4(relTarget));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the size of a packed table for the given cases, in 16-bit code
+     * units.
+     *
+     * @param cases {@code non-null;} sorted list of cases
+     * @return {@code >= -1;} the packed table size or {@code -1} if the
+     * cases couldn't possibly be represented as a packed table
+     */
+    private static long packedCodeSize(IntList cases) {
+        int sz = cases.size();
+        long low = cases.get(0);
+        long high = cases.get(sz - 1);
+        long result = ((high - low + 1)) * 2 + 4;
+
+        return (result <= 0x7fffffff) ? result : -1;
+    }
+
+    /**
+     * Gets the size of a sparse table for the given cases, in 16-bit code
+     * units.
+     *
+     * @param cases {@code non-null;} sorted list of cases
+     * @return {@code > 0;} the sparse table size
+     */
+    private static long sparseCodeSize(IntList cases) {
+        int sz = cases.size();
+
+        return (sz * 4L) + 2;
+    }
+
+    /**
+     * Determines whether the given list of cases warrant being packed.
+     *
+     * @param cases {@code non-null;} sorted list of cases
+     * @return {@code true} iff the table encoding the cases
+     * should be packed
+     */
+    private static boolean shouldPack(IntList cases) {
+        int sz = cases.size();
+
+        if (sz < 2) {
+            return true;
+        }
+
+        long packedSize = packedCodeSize(cases);
+        long sparseSize = sparseCodeSize(cases);
+
+        /*
+         * We pick the packed representation if it is possible and
+         * would be as small or smaller than 5/4 of the sparse
+         * representation. That is, we accept some size overhead on
+         * the packed representation, since that format is faster to
+         * execute at runtime.
+         */
+        return (packedSize >= 0) && (packedSize <= ((sparseSize * 5) / 4));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/TargetInsn.java b/dexgen/src/com/android/dexgen/dex/code/TargetInsn.java
new file mode 100644
index 0000000..8e02255
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/TargetInsn.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Instruction which has a single branch target.
+ */
+public final class TargetInsn extends FixedSizeInsn {
+    /** {@code non-null;} the branch target */
+    private CodeAddress target;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}), and the target is initially
+     * {@code null}.
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     * @param target {@code non-null;} the branch target
+     */
+    public TargetInsn(Dop opcode, SourcePosition position,
+                      RegisterSpecList registers, CodeAddress target) {
+        super(opcode, position, registers);
+
+        if (target == null) {
+            throw new NullPointerException("target == null");
+        }
+
+        this.target = target;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withOpcode(Dop opcode) {
+        return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new TargetInsn(getOpcode(), getPosition(), registers, target);
+    }
+
+    /**
+     * 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} test becomes a {@code ge}), and its branch
+     * target is replaced by the one given, and all set-once values
+     * associated with the class (such as its address) are reset.
+     *
+     * @param target {@code non-null;} the new branch target
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public TargetInsn withNewTargetAndReversed(CodeAddress target) {
+        Dop opcode = getOpcode().getOppositeTest();
+
+        return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+    }
+
+    /**
+     * Gets the unique branch target of this instruction.
+     *
+     * @return {@code non-null;} the branch target
+     */
+    public CodeAddress getTarget() {
+        return target;
+    }
+
+    /**
+     * 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()}.
+     *
+     * @return {@code >= 0;} the target address
+     */
+    public int getTargetAddress() {
+        return target.getAddress();
+    }
+
+    /**
+     * 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()}.
+     *
+     * @return the branch offset
+     */
+    public int getTargetOffset() {
+        return target.getAddress() - getAddress();
+    }
+
+    /**
+     * Returns whether the target offset is known.
+     *
+     * @return {@code true} if the target offset is known or
+     * {@code false} if not
+     */
+    public boolean hasTargetOffset() {
+        return hasAddress() && target.hasAddress();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        if (target == null) {
+            return "????";
+        }
+
+        return target.identifierString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/VariableSizeInsn.java b/dexgen/src/com/android/dexgen/dex/code/VariableSizeInsn.java
new file mode 100644
index 0000000..baa62a3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/VariableSizeInsn.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction base class for variable-sized instructions.
+ */
+public abstract class VariableSizeInsn extends DalvInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} source registers
+     */
+    public VariableSizeInsn(SourcePosition position,
+                            RegisterSpecList registers) {
+        super(Dops.SPECIAL_FORMAT, position, registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withOpcode(Dop opcode) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withRegisterOffset(int delta) {
+        return withRegisters(getRegisters().withOffset(delta));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/ZeroSizeInsn.java b/dexgen/src/com/android/dexgen/dex/code/ZeroSizeInsn.java
new file mode 100644
index 0000000..3c8c94a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/ZeroSizeInsn.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code;
+
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Pseudo-instruction base class for zero-size (no code emitted)
+ * instructions, which are generally used for tracking metainformation
+ * about the code they are adjacent to.
+ */
+public abstract class ZeroSizeInsn extends DalvInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     */
+    public ZeroSizeInsn(SourcePosition position) {
+        super(Dops.SPECIAL_FORMAT, position, RegisterSpecList.EMPTY);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int codeSize() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(AnnotatedOutput out) {
+        // Nothing to do here, for this class.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withOpcode(Dop opcode) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return withRegisters(getRegisters().withOffset(delta));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form10t.java b/dexgen/src/com/android/dexgen/dex/code/form/Form10t.java
new file mode 100644
index 0000000..4784fc3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form10t.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.TargetInsn;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 10t}. See the instruction format spec
+ * for details.
+ */
+public final class Form10t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form10t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form10t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!((insn instanceof TargetInsn) &&
+              (insn.getRegisters().size() == 0))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInByte(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form20t.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, (offset & 0xff)));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form10x.java b/dexgen/src/com/android/dexgen/dex/code/form/Form10x.java
new file mode 100644
index 0000000..63c861c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form10x.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.SimpleInsn;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 10x}. See the instruction format spec
+ * for details.
+ */
+public final class Form10x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form10x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form10x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        // This format has no arguments.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        return (insn instanceof SimpleInsn) &&
+            (insn.getRegisters().size() == 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        write(out, opcodeUnit(insn, 0));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form11n.java b/dexgen/src/com/android/dexgen/dex/code/form/Form11n.java
new file mode 100644
index 0000000..511d7d1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form11n.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 11n}. See the instruction format spec
+ * for details.
+ */
+public final class Form11n extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form11n();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form11n() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 4);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInNibble(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInNibble(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form21s.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, makeByte(regs.get(0).getReg(), value & 0xf)));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form11x.java b/dexgen/src/com/android/dexgen/dex/code/form/Form11x.java
new file mode 100644
index 0000000..8bf9bba
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form11x.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.SimpleInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 11x}. See the instruction format spec
+ * for details.
+ */
+public final class Form11x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form11x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form11x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 1) &&
+            unsignedFitsInByte(regs.get(0).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out, opcodeUnit(insn, regs.get(0).getReg()));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form12x.java b/dexgen/src/com/android/dexgen/dex/code/form/Form12x.java
new file mode 100644
index 0000000..d55a66a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form12x.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.HighRegisterPrefix;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.SimpleInsn;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 12x}. See the instruction format spec
+ * for details.
+ */
+public final class Form12x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form12x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form12x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+
+        /*
+         * The (sz - 2) and (sz - 1) below makes this code work for
+         * both the two- and three-register ops. (See "case 3" in
+         * isCompatible(), below.)
+         */
+
+        return regs.get(sz - 2).regString() + ", " +
+            regs.get(sz - 1).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof SimpleInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec rs1;
+        RegisterSpec rs2;
+
+        switch (regs.size()) {
+            case 2: {
+                rs1 = regs.get(0);
+                rs2 = regs.get(1);
+                break;
+            }
+            case 3: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 3-arg but where the first two args are identical.
+                 */
+                rs1 = regs.get(1);
+                rs2 = regs.get(2);
+                if (rs1.getReg() != regs.get(0).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        return unsignedFitsInNibble(rs1.getReg()) &&
+            unsignedFitsInNibble(rs2.getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form22x.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+
+        /*
+         * The (sz - 2) and (sz - 1) below makes this code work for
+         * both the two- and three-register ops. (See "case 3" in
+         * isCompatible(), above.)
+         */
+
+        write(out, opcodeUnit(insn,
+                              makeByte(regs.get(sz - 2).getReg(),
+                                       regs.get(sz - 1).getReg())));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form20t.java b/dexgen/src/com/android/dexgen/dex/code/form/Form20t.java
new file mode 100644
index 0000000..2760606
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form20t.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.TargetInsn;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 20t}. See the instruction format spec
+ * for details.
+ */
+public final class Form20t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form20t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form20t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!((insn instanceof TargetInsn) &&
+              (insn.getRegisters().size() == 0))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInShort(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form30t.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, 0), (short) offset);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form21c.java b/dexgen/src/com/android/dexgen/dex/code/form/Form21c.java
new file mode 100644
index 0000000..33df3d6
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form21c.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 21c}. See the instruction format spec
+ * for details.
+ */
+public final class Form21c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec reg;
+
+        switch (regs.size()) {
+            case 1: {
+                reg = regs.get(0);
+                break;
+            }
+            case 2: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 2-arg but where the two args are identical.
+                 */
+                reg = regs.get(0);
+                if (reg.getReg() != regs.get(1).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        if (!unsignedFitsInByte(reg.getReg())) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef) ||
+            (cst instanceof CstString);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form31c.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) cpi);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form21h.java b/dexgen/src/com/android/dexgen/dex/code/form/Form21h.java
new file mode 100644
index 0000000..ee6ed3e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form21h.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 21h}. See the instruction format spec
+ * for details.
+ */
+public final class Form21h extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21h();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21h() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return
+            literalBitsComment(value,
+                    (regs.get(0).getCategory() == 1) ? 32 : 64);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        // Where the high bits are depends on the category of the target.
+        if (regs.get(0).getCategory() == 1) {
+            int bits = cb.getIntBits();
+            return ((bits & 0xffff) == 0);
+        } else {
+            long bits = cb.getLongBits();
+            return ((bits & 0xffffffffffffL) == 0);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form31i.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits cb = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        short bits;
+
+        // Where the high bits are depends on the category of the target.
+        if (regs.get(0).getCategory() == 1) {
+            bits = (short) (cb.getIntBits() >>> 16);
+        } else {
+            bits = (short) (cb.getLongBits() >>> 48);
+        }
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()), bits);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form21s.java b/dexgen/src/com/android/dexgen/dex/code/form/Form21s.java
new file mode 100644
index 0000000..4b853d0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form21s.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 21s}. See the instruction format spec
+ * for details.
+ */
+public final class Form21s extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21s();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21s() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form21h.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) value);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form21t.java b/dexgen/src/com/android/dexgen/dex/code/form/Form21t.java
new file mode 100644
index 0000000..61599f6
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form21t.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.TargetInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 21t}. See the instruction format spec
+ * for details.
+ */
+public final class Form21t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof TargetInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInShort(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form31t.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) offset);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form22b.java b/dexgen/src/com/android/dexgen/dex/code/form/Form22b.java
new file mode 100644
index 0000000..6c37d57
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form22b.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 22b}. See the instruction format spec
+ * for details.
+ */
+public final class Form22b extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22b();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22b() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 8);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInByte(regs.get(0).getReg()) &&
+              unsignedFitsInByte(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInByte(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form22s.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              codeUnit(regs.get(1).getReg(), value & 0xff));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form22c.java b/dexgen/src/com/android/dexgen/dex/code/form/Form22c.java
new file mode 100644
index 0000000..b089ec4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form22c.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 22c}. See the instruction format spec
+ * for details.
+ */
+public final class Form22c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInNibble(regs.get(0).getReg()) &&
+              unsignedFitsInNibble(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+              (short) cpi);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form22s.java b/dexgen/src/com/android/dexgen/dex/code/form/Form22s.java
new file mode 100644
index 0000000..0eca280
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form22s.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 22s}. See the instruction format spec
+ * for details.
+ */
+public final class Form22s extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22s();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22s() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + regs.get(1).regString()
+            + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInNibble(regs.get(0).getReg()) &&
+              unsignedFitsInNibble(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+              (short) value);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form22t.java b/dexgen/src/com/android/dexgen/dex/code/form/Form22t.java
new file mode 100644
index 0000000..707bb97
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form22t.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.TargetInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 22t}. See the instruction format spec
+ * for details.
+ */
+public final class Form22t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof TargetInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInNibble(regs.get(0).getReg()) &&
+              unsignedFitsInNibble(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInShort(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+              (short) offset);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form22x.java b/dexgen/src/com/android/dexgen/dex/code/form/Form22x.java
new file mode 100644
index 0000000..bd6a8df
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form22x.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.SimpleInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 22x}. See the instruction format spec
+ * for details.
+ */
+public final class Form22x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 2) &&
+            unsignedFitsInByte(regs.get(0).getReg()) &&
+            unsignedFitsInShort(regs.get(1).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form23x.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) regs.get(1).getReg());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form23x.java b/dexgen/src/com/android/dexgen/dex/code/form/Form23x.java
new file mode 100644
index 0000000..eaf1cee
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form23x.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.SimpleInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 23x}. See the instruction format spec
+ * for details.
+ */
+public final class Form23x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form23x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form23x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + regs.get(2).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 3) &&
+            unsignedFitsInByte(regs.get(0).getReg()) &&
+            unsignedFitsInByte(regs.get(1).getReg()) &&
+            unsignedFitsInByte(regs.get(2).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form32x.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              codeUnit(regs.get(1).getReg(), regs.get(2).getReg()));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form30t.java b/dexgen/src/com/android/dexgen/dex/code/form/Form30t.java
new file mode 100644
index 0000000..0909ec8
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form30t.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.TargetInsn;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 30t}. See the instruction format spec
+ * for details.
+ */
+public final class Form30t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form30t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form30t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!((insn instanceof TargetInsn) &&
+              (insn.getRegisters().size() == 0))) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, 0),
+                (short) offset,
+                (short) (offset >> 16));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form31c.java b/dexgen/src/com/android/dexgen/dex/code/form/Form31c.java
new file mode 100644
index 0000000..c87a451
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form31c.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 31c}. See the instruction format spec
+ * for details.
+ */
+public final class Form31c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form31c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form31c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec reg;
+
+        switch (regs.size()) {
+            case 1: {
+                reg = regs.get(0);
+                break;
+            }
+            case 2: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 2-arg but where the two args are identical.
+                 */
+                reg = regs.get(0);
+                if (reg.getReg() != regs.get(1).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        if (!unsignedFitsInByte(reg.getReg())) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return ((cst instanceof CstType) ||
+                (cst instanceof CstFieldRef) ||
+                (cst instanceof CstString));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+                opcodeUnit(insn, regs.get(0).getReg()),
+                (short) cpi,
+                (short) (cpi >> 16));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form31i.java b/dexgen/src/com/android/dexgen/dex/code/form/Form31i.java
new file mode 100644
index 0000000..e74ea86
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form31i.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 31i}. See the instruction format spec
+ * for details.
+ */
+public final class Form31i extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form31i();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form31i() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 32);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        return ((CstLiteralBits) cst).fitsInInt();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form51l.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) value,
+              (short) (value >> 16));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form31t.java b/dexgen/src/com/android/dexgen/dex/code/form/Form31t.java
new file mode 100644
index 0000000..212f93b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form31t.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.TargetInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 31t}. See the instruction format spec
+ * for details.
+ */
+public final class Form31t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form31t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form31t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof TargetInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()),
+                (short) offset,
+                (short) (offset >> 16));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form32x.java b/dexgen/src/com/android/dexgen/dex/code/form/Form32x.java
new file mode 100644
index 0000000..097fb65
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form32x.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.dex.code.SimpleInsn;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 32x}. See the instruction format spec
+ * for details.
+ */
+public final class Form32x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form32x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form32x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 2) &&
+            unsignedFitsInShort(regs.get(0).getReg()) &&
+            unsignedFitsInShort(regs.get(1).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        write(out,
+              opcodeUnit(insn, 0),
+              (short) regs.get(0).getReg(),
+              (short) regs.get(1).getReg());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form35c.java b/dexgen/src/com/android/dexgen/dex/code/form/Form35c.java
new file mode 100644
index 0000000..147aac1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form35c.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 35c}. See the instruction format spec
+ * for details.
+ */
+public final class Form35c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form35c();
+
+    /** Maximal number of operands */
+    private static final int MAX_NUM_OPS = 5;
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form35c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        return regListString(regs) + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        return (wordCount(regs) >= 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return Form3rc.THE_ONE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int cpi = ((CstInsn) insn).getIndex();
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        int sz = regs.size();
+        int r0 = (sz > 0) ? regs.get(0).getReg() : 0;
+        int r1 = (sz > 1) ? regs.get(1).getReg() : 0;
+        int r2 = (sz > 2) ? regs.get(2).getReg() : 0;
+        int r3 = (sz > 3) ? regs.get(3).getReg() : 0;
+        int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(r4, sz)), // encode the fifth operand here
+              (short) cpi,
+              codeUnit(r0, r1, r2, r3));
+    }
+
+    /**
+     * Gets the number of words required for the given register list, where
+     * category-2 values count as two words. Return {@code -1} if the
+     * list requires more than five words or contains registers that need
+     * more than a nibble to identify them.
+     *
+     * @param regs {@code non-null;} the register list in question
+     * @return {@code >= -1;} the number of words required, or {@code -1}
+     * if the list couldn't possibly fit in this format
+     */
+    private static int wordCount(RegisterSpecList regs) {
+        int sz = regs.size();
+
+        if (sz > MAX_NUM_OPS) {
+            // It can't possibly fit.
+            return -1;
+        }
+
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = regs.get(i);
+            result += one.getCategory();
+            /*
+             * The check below adds (category - 1) to the register, to
+             * account for the fact that the second half of a
+             * category-2 register has to be represented explicitly in
+             * the result.
+             */
+            if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) {
+                return -1;
+            }
+        }
+
+        return (result <= MAX_NUM_OPS) ? result : -1;
+    }
+
+    /**
+     * Returns a register list which is equivalent to the given one,
+     * except that it splits category-2 registers into two explicit
+     * entries. This returns the original list if no modification is
+     * required
+     *
+     * @param orig {@code non-null;} the original list
+     * @return {@code non-null;} the list with the described transformation
+     */
+    private static RegisterSpecList explicitize(RegisterSpecList orig) {
+        int wordCount = wordCount(orig);
+        int sz = orig.size();
+
+        if (wordCount == sz) {
+            return orig;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(wordCount);
+        int wordAt = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = orig.get(i);
+            result.set(wordAt, one);
+            if (one.getCategory() == 2) {
+                result.set(wordAt + 1,
+                           RegisterSpec.make(one.getReg() + 1, Type.VOID));
+                wordAt += 2;
+            } else {
+                wordAt++;
+            }
+        }
+
+        result.setImmutable();
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form3rc.java b/dexgen/src/com/android/dexgen/dex/code/form/Form3rc.java
new file mode 100644
index 0000000..a061c6f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form3rc.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 3rc}. See the instruction format spec
+ * for details.
+ */
+public final class Form3rc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form3rc();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form3rc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int size = regs.size();
+        StringBuilder sb = new StringBuilder(30);
+
+        sb.append("{");
+
+        switch (size) {
+            case 0: {
+                // Nothing to do.
+                break;
+            }
+            case 1: {
+                sb.append(regs.get(0).regString());
+                break;
+            }
+            default: {
+                RegisterSpec lastReg = regs.get(size - 1);
+                if (lastReg.getCategory() == 2) {
+                    /*
+                     * Add one to properly represent a list-final
+                     * category-2 register.
+                     */
+                    lastReg = lastReg.withOffset(1);
+                }
+
+                sb.append(regs.get(0).regString());
+                sb.append("..");
+                sb.append(lastReg.regString());
+            }
+        }
+
+        sb.append("}, ");
+        sb.append(cstString(insn));
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        int sz = regs.size();
+
+        if (sz == 0) {
+            return true;
+        }
+
+        int first = regs.get(0).getReg();
+        int next = first;
+
+        if (!unsignedFitsInShort(first)) {
+            return false;
+        }
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = regs.get(i);
+            if (one.getReg() != next) {
+                return false;
+            }
+            next += one.getCategory();
+        }
+
+        return unsignedFitsInByte(next - first);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+        int cpi = ((CstInsn) insn).getIndex();
+        int firstReg;
+        int count;
+
+        if (sz == 0) {
+            firstReg = 0;
+            count = 0;
+        } else {
+            int lastReg = regs.get(sz - 1).getNextReg();
+            firstReg = regs.get(0).getReg();
+            count = lastReg - firstReg;
+        }
+
+        write(out,
+              opcodeUnit(insn, count),
+              (short) cpi,
+              (short) firstReg);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/Form51l.java b/dexgen/src/com/android/dexgen/dex/code/form/Form51l.java
new file mode 100644
index 0000000..537eaa9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/Form51l.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.rop.code.RegisterSpecList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstLiteral64;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 51l}. See the instruction format spec
+ * for details.
+ */
+public final class Form51l extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form51l();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form51l() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 64);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstLiteral64);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        long value =
+            ((CstLiteral64) ((CstInsn) insn).getConstant()).getLongBits();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) value,
+              (short) (value >> 16),
+              (short) (value >> 32),
+              (short) (value >> 48));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/code/form/SpecialFormat.java b/dexgen/src/com/android/dexgen/dex/code/form/SpecialFormat.java
new file mode 100644
index 0000000..c75f18f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/code/form/SpecialFormat.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.code.form;
+
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.DalvOps;
+import com.android.dexgen.dex.code.InsnFormat;
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Instruction format for nonstandard format instructions, which aren't
+ * generally real instructions but do end up appearing in instruction
+ * 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}.
+ */
+public final class SpecialFormat extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new SpecialFormat();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private SpecialFormat() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public InsnFormat nextUp() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        throw new RuntimeException("unsupported");
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/AnnotationItem.java b/dexgen/src/com/android/dexgen/dex/file/AnnotationItem.java
new file mode 100644
index 0000000..a078bc0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/AnnotationItem.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotation;
+import com.android.dexgen.rop.annotation.AnnotationVisibility;
+import com.android.dexgen.rop.annotation.NameValuePair;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstAnnotation;
+import com.android.dexgen.rop.cst.CstArray;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ByteArrayAnnotatedOutput;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Single annotation, which consists of a type and a set of name-value
+ * element pairs.
+ */
+public final class AnnotationItem extends OffsettedItem {
+    /** annotation visibility constant: visible at build time only */
+    private static final int VISIBILITY_BUILD = 0;
+
+    /** annotation visibility constant: visible at runtime */
+    private static final int VISIBILITY_RUNTIME = 1;
+
+    /** annotation visibility constant: visible at runtime only to system */
+    private static final int VISIBILITY_SYSTEM = 2;
+
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 1;
+
+    /** {@code non-null;} unique instance of {@link #TypeIdSorter} */
+    private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
+
+    /** {@code non-null;} the annotation to represent */
+    private final Annotation annotation;
+
+    /**
+     * {@code null-ok;} type reference for the annotation type; set during
+     * {@link #addContents}
+     */
+    private TypeIdItem type;
+
+    /**
+     * {@code null-ok;} encoded form, ready for writing to a file; set during
+     * {@link #place0}
+     */
+    private byte[] encodedForm;
+
+    /**
+     * Comparator that sorts (outer) instances by type id index.
+     */
+    private static class TypeIdSorter implements Comparator<AnnotationItem> {
+        /** {@inheritDoc} */
+        public int compare(AnnotationItem item1, AnnotationItem item2) {
+            int index1 = item1.type.getIndex();
+            int index2 = item2.type.getIndex();
+
+            if (index1 < index2) {
+                return -1;
+            } else if (index1 > index2) {
+                return 1;
+            }
+
+            return 0;
+        }
+    }
+
+    /**
+     * Sorts an array of instances, in place, by type id index,
+     * ignoring all other aspects of the elements. This is only valid
+     * to use after type id indices are known.
+     *
+     * @param array {@code non-null;} array to sort
+     */
+    public static void sortByTypeIdIndex(AnnotationItem[] array) {
+        Arrays.sort(array, TYPE_ID_SORTER);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotation {@code non-null;} annotation to represent
+     */
+    public AnnotationItem(Annotation annotation) {
+        /*
+         * The write size isn't known up-front because (the variable-lengthed)
+         * leb128 type is used to represent some things.
+         */
+        super(ALIGNMENT, -1);
+
+        if (annotation == null) {
+            throw new NullPointerException("annotation == null");
+        }
+
+        this.annotation = annotation;
+        this.type = null;
+        this.encodedForm = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATION_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotation.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        AnnotationItem otherAnnotation = (AnnotationItem) other;
+
+        return annotation.compareTo(otherAnnotation.annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return annotation.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        type = file.getTypeIds().intern(annotation.getType());
+        ValueEncoder.addContents(file, annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+        ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
+
+        encoder.writeAnnotation(annotation, false);
+        encodedForm = out.toByteArray();
+
+        // Add one for the visibility byte in front of the encoded annotation.
+        setWriteSize(encodedForm.length + 1);
+    }
+
+    /**
+     * Write a (listing file) annotation for this instance to the given
+     * output, that consumes no bytes of output. This is for annotating
+     * a reference to this instance at the point of the reference.
+     *
+     * @param out {@code non-null;} where to output to
+     * @param prefix {@code non-null;} prefix for each line of output
+     */
+    public void annotateTo(AnnotatedOutput out, String prefix) {
+        out.annotate(0, prefix + "visibility: " +
+                annotation.getVisibility().toHuman());
+        out.annotate(0, prefix + "type: " + annotation.getType().toHuman());
+
+        for (NameValuePair pair : annotation.getNameValuePairs()) {
+            CstUtf8 name = pair.getName();
+            Constant value = pair.getValue();
+
+            out.annotate(0, prefix + name.toHuman() + ": " +
+                    ValueEncoder.constantToHuman(value));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        AnnotationVisibility visibility = annotation.getVisibility();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " annotation");
+            out.annotate(1, "  visibility: VISBILITY_" + visibility);
+        }
+
+        switch (visibility) {
+            case BUILD:   out.writeByte(VISIBILITY_BUILD); break;
+            case RUNTIME: out.writeByte(VISIBILITY_RUNTIME); break;
+            case SYSTEM:  out.writeByte(VISIBILITY_SYSTEM); break;
+            default: {
+                // EMBEDDED shouldn't appear at the top level.
+                throw new RuntimeException("shouldn't happen");
+            }
+        }
+
+        if (annotates) {
+            /*
+             * The output is to be annotated, so redo the work previously
+             * done by place0(), except this time annotations will actually
+             * get emitted.
+             */
+            ValueEncoder encoder = new ValueEncoder(file, out);
+            encoder.writeAnnotation(annotation, true);
+        } else {
+            out.write(encodedForm);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/AnnotationSetItem.java b/dexgen/src/com/android/dexgen/dex/file/AnnotationSetItem.java
new file mode 100644
index 0000000..46ea2f0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/AnnotationSetItem.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotation;
+import com.android.dexgen.rop.annotation.Annotations;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Set of annotations, where no annotation type appears more than once.
+ */
+public final class AnnotationSetItem extends OffsettedItem {
+    /** 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} */
+    private static final int ENTRY_WRITE_SIZE = 4;
+
+    /** {@code non-null;} the set of annotations */
+    private final Annotations annotations;
+
+    /**
+     * {@code non-null;} set of annotations as individual items in an array.
+     * <b>Note:</b> The contents have to get sorted by type id before
+     * writing.
+     */
+    private final AnnotationItem[] items;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} set of annotations
+     */
+    public AnnotationSetItem(Annotations annotations) {
+        super(ALIGNMENT, writeSize(annotations));
+
+        this.annotations = annotations;
+        this.items = new AnnotationItem[annotations.size()];
+
+        int at = 0;
+        for (Annotation a : annotations.getAnnotations()) {
+            items[at] = new AnnotationItem(a);
+            at++;
+        }
+    }
+
+    /**
+     * Gets the write size for the given set.
+     *
+     * @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.
+
+        try {
+            return (annotations.size() * ENTRY_WRITE_SIZE) + 4;
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("list == null");
+        }
+    }
+
+    /**
+     * Gets the underlying annotations of this instance
+     *
+     * @return {@code non-null;} the annotations
+     */
+    public Annotations getAnnotations() {
+        return annotations;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotations.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        AnnotationSetItem otherSet = (AnnotationSetItem) other;
+
+        return annotations.compareTo(otherSet.annotations);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATION_SET_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return annotations.toString();
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection byteData = file.getByteData();
+        int size = items.length;
+
+        for (int i = 0; i < size; i++) {
+            items[i] = byteData.intern(items[i]);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Sort the array to be in type id index order.
+        AnnotationItem.sortByTypeIdIndex(items);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        int size = items.length;
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " annotation set");
+            out.annotate(4, "  size: " + Hex.u4(size));
+        }
+
+        out.writeInt(size);
+
+        for (int i = 0; i < size; i++) {
+            AnnotationItem item = items[i];
+            int offset = item.getAbsoluteOffset();
+
+            if (annotates) {
+                out.annotate(4, "  entries[" + Integer.toHexString(i) + "]: " +
+                        Hex.u4(offset));
+                items[i].annotateTo(out, "    ");
+            }
+
+            out.writeInt(offset);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/AnnotationSetRefItem.java b/dexgen/src/com/android/dexgen/dex/file/AnnotationSetRefItem.java
new file mode 100644
index 0000000..b876ce0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/AnnotationSetRefItem.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Indirect reference to an {@link AnnotationSetItem}.
+ */
+public final class AnnotationSetRefItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of this class, in bytes */
+    private static final int WRITE_SIZE = 4;
+
+    /** {@code non-null;} the annotation set to refer to */
+    private AnnotationSetItem annotations;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} the annotation set to refer to
+     */
+    public AnnotationSetRefItem(AnnotationSetItem annotations) {
+        super(ALIGNMENT, WRITE_SIZE);
+
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.annotations = annotations;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATION_SET_REF_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection wordData = file.getWordData();
+
+        annotations = wordData.intern(annotations);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return annotations.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        int annotationsOff = annotations.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "  annotations_off: " + Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(annotationsOff);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/AnnotationUtils.java b/dexgen/src/com/android/dexgen/dex/file/AnnotationUtils.java
new file mode 100644
index 0000000..111ba8a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/AnnotationUtils.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotation;
+import com.android.dexgen.rop.annotation.NameValuePair;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstAnnotation;
+import com.android.dexgen.rop.cst.CstArray;
+import com.android.dexgen.rop.cst.CstInteger;
+import com.android.dexgen.rop.cst.CstKnownNull;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+
+import java.util.ArrayList;
+
+import static com.android.dexgen.rop.annotation.AnnotationVisibility.*;
+
+/**
+ * Utility class for dealing with annotations.
+ */
+public final class AnnotationUtils {
+    /** {@code non-null;} type for {@code AnnotationDefault} annotations */
+    private static final CstType ANNOTATION_DEFAULT_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
+
+    /** {@code non-null;} type for {@code EnclosingClass} annotations */
+    private static final CstType ENCLOSING_CLASS_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
+
+    /** {@code non-null;} type for {@code EnclosingMethod} annotations */
+    private static final CstType ENCLOSING_METHOD_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
+
+    /** {@code non-null;} type for {@code InnerClass} annotations */
+    private static final CstType INNER_CLASS_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
+
+    /** {@code non-null;} type for {@code MemberClasses} annotations */
+    private static final CstType MEMBER_CLASSES_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
+
+    /** {@code non-null;} type for {@code Signature} annotations */
+    private static final CstType SIGNATURE_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
+
+    /** {@code non-null;} type for {@code Throws} annotations */
+    private static final CstType THROWS_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
+
+    /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
+    private static final CstUtf8 ACCESS_FLAGS_UTF = new CstUtf8("accessFlags");
+
+    /** {@code non-null;} the UTF-8 constant {@code "name"} */
+    private static final CstUtf8 NAME_UTF = new CstUtf8("name");
+
+    /** {@code non-null;} the UTF-8 constant {@code "value"} */
+    private static final CstUtf8 VALUE_UTF = new CstUtf8("value");
+
+    /**
+     * This class is uninstantiable.
+     */
+    private AnnotationUtils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Constructs a standard {@code AnnotationDefault} 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);
+
+        result.put(new NameValuePair(VALUE_UTF, new CstAnnotation(defaults)));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code EnclosingClass} 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);
+
+        result.put(new NameValuePair(VALUE_UTF, clazz));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code EnclosingMethod} 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);
+
+        result.put(new NameValuePair(VALUE_UTF, method));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code InnerClass} annotation.
+     *
+     * @param name {@code null-ok;} the original name of the class, or
+     * {@code null} to represent an anonymous class
+     * @param accessFlags the original access flags
+     * @return {@code non-null;} the annotation
+     */
+    public static Annotation makeInnerClass(CstUtf8 name, int accessFlags) {
+        Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
+        Constant nameCst =
+            (name != null) ? new CstString(name) : CstKnownNull.THE_ONE;
+
+        result.put(new NameValuePair(NAME_UTF, nameCst));
+        result.put(new NameValuePair(ACCESS_FLAGS_UTF,
+                        CstInteger.make(accessFlags)));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code MemberClasses} annotation.
+     *
+     * @param types {@code non-null;} the list of (the types of) the member classes
+     * @return {@code non-null;} the annotation
+     */
+    public static Annotation makeMemberClasses(TypeList types) {
+        CstArray array = makeCstArray(types);
+        Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM);
+        result.put(new NameValuePair(VALUE_UTF, array));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code Signature} 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);
+
+        /*
+         * Split the string into pieces that are likely to be common
+         * across many signatures and the rest of the file.
+         */
+
+        String raw = signature.getString();
+        int rawLength = raw.length();
+        ArrayList<String> pieces = new ArrayList<String>(20);
+
+        for (int at = 0; at < rawLength; /*at*/) {
+            char c = raw.charAt(at);
+            int endAt = at + 1;
+            if (c == 'L') {
+                // Scan to ';' or '<'. Consume ';' but not '<'.
+                while (endAt < rawLength) {
+                    c = raw.charAt(endAt);
+                    if (c == ';') {
+                        endAt++;
+                        break;
+                    } else if (c == '<') {
+                        break;
+                    }
+                    endAt++;
+                }
+            } else {
+                // Scan to 'L' without consuming it.
+                while (endAt < rawLength) {
+                    c = raw.charAt(endAt);
+                    if (c == 'L') {
+                        break;
+                    }
+                    endAt++;
+                }
+            }
+
+            pieces.add(raw.substring(at, endAt));
+            at = endAt;
+        }
+
+        int size = pieces.size();
+        CstArray.List list = new CstArray.List(size);
+
+        for (int i = 0; i < size; i++) {
+            list.set(i, new CstString(pieces.get(i)));
+        }
+
+        list.setImmutable();
+
+        result.put(new NameValuePair(VALUE_UTF, new CstArray(list)));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code Throws} 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);
+        Annotation result = new Annotation(THROWS_TYPE, SYSTEM);
+        result.put(new NameValuePair(VALUE_UTF, array));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Converts a {@link TypeList} to a {@link CstArray}.
+     *
+     * @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();
+        CstArray.List list = new CstArray.List(size);
+
+        for (int i = 0; i < size; i++) {
+            list.set(i, CstType.intern(types.getType(i)));
+        }
+
+        list.setImmutable();
+        return new CstArray(list);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/AnnotationsDirectoryItem.java b/dexgen/src/com/android/dexgen/dex/file/AnnotationsDirectoryItem.java
new file mode 100644
index 0000000..860c16d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/AnnotationsDirectoryItem.java
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotations;
+import com.android.dexgen.rop.annotation.AnnotationsList;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Per-class directory of annotations.
+ */
+public final class AnnotationsDirectoryItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of this class's header, in bytes */
+    private static final int HEADER_SIZE = 16;
+
+    /** write size of a list element, in bytes */
+    private static final int ELEMENT_SIZE = 8;
+
+    /** {@code null-ok;} the class-level annotations, if any */
+    private AnnotationSetItem classAnnotations;
+
+    /** {@code null-ok;} the annotated fields, if any */
+    private ArrayList<FieldAnnotationStruct> fieldAnnotations;
+
+    /** {@code null-ok;} the annotated methods, if any */
+    private ArrayList<MethodAnnotationStruct> methodAnnotations;
+
+    /** {@code null-ok;} the annotated parameters, if any */
+    private ArrayList<ParameterAnnotationStruct> parameterAnnotations;
+
+    /**
+     * Constructs an empty instance.
+     */
+    public AnnotationsDirectoryItem() {
+        super(ALIGNMENT, -1);
+
+        classAnnotations = null;
+        fieldAnnotations = null;
+        methodAnnotations = null;
+        parameterAnnotations = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
+    }
+
+    /**
+     * Returns whether this item is empty (has no contents).
+     *
+     * @return {@code true} if this item is empty, or {@code false}
+     * if not
+     */
+    public boolean isEmpty() {
+        return (classAnnotations == null) &&
+            (fieldAnnotations == null) &&
+            (methodAnnotations == null) &&
+            (parameterAnnotations == null);
+    }
+
+    /**
+     * Returns whether this item is a candidate for interning. The only
+     * interning candidates are ones that <i>only</i> have a non-null
+     * set of class annotations, with no other lists.
+     *
+     * @return {@code true} if this is an interning candidate, or
+     * {@code false} if not
+     */
+    public boolean isInternable() {
+        return (classAnnotations != null) &&
+            (fieldAnnotations == null) &&
+            (methodAnnotations == null) &&
+            (parameterAnnotations == null);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        if (classAnnotations == null) {
+            return 0;
+        }
+
+        return classAnnotations.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b>: This throws an exception if this item is not
+     * internable.</p>
+     *
+     * @see #isInternable
+     */
+    @Override
+    public int compareTo0(OffsettedItem other) {
+        if (! isInternable()) {
+            throw new UnsupportedOperationException("uninternable instance");
+        }
+
+        AnnotationsDirectoryItem otherDirectory =
+            (AnnotationsDirectoryItem) other;
+        return classAnnotations.compareTo(otherDirectory.classAnnotations);
+    }
+
+    /**
+     * Sets the direct annotations on this instance. These are annotations
+     * made on the class, per se, as opposed to on one of its members.
+     * It is only valid to call this method at most once per instance.
+     *
+     * @param annotations {@code non-null;} annotations to set for this class
+     */
+    public void setClassAnnotations(Annotations annotations) {
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        if (classAnnotations != null) {
+            throw new UnsupportedOperationException(
+                    "class annotations already set");
+        }
+
+        classAnnotations = new AnnotationSetItem(annotations);
+    }
+
+    /**
+     * Adds a field annotations item to this instance.
+     *
+     * @param field {@code non-null;} field in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addFieldAnnotations(CstFieldRef field,
+            Annotations annotations) {
+        if (fieldAnnotations == null) {
+            fieldAnnotations = new ArrayList<FieldAnnotationStruct>();
+        }
+
+        fieldAnnotations.add(new FieldAnnotationStruct(field,
+                        new AnnotationSetItem(annotations)));
+    }
+
+    /**
+     * Adds a method annotations item to this instance.
+     *
+     * @param method {@code non-null;} method in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addMethodAnnotations(CstMethodRef method,
+            Annotations annotations) {
+        if (methodAnnotations == null) {
+            methodAnnotations = new ArrayList<MethodAnnotationStruct>();
+        }
+
+        methodAnnotations.add(new MethodAnnotationStruct(method,
+                        new AnnotationSetItem(annotations)));
+    }
+
+    /**
+     * Adds a parameter annotations item to this instance.
+     *
+     * @param method {@code non-null;} method in question
+     * @param list {@code non-null;} associated list of annotation sets to add
+     */
+    public void addParameterAnnotations(CstMethodRef method,
+            AnnotationsList list) {
+        if (parameterAnnotations == null) {
+            parameterAnnotations = new ArrayList<ParameterAnnotationStruct>();
+        }
+
+        parameterAnnotations.add(new ParameterAnnotationStruct(method, list));
+    }
+
+    /**
+     * Gets the method annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the method annotations, if any
+     */
+    public Annotations getMethodAnnotations(CstMethodRef method) {
+        if (methodAnnotations == null) {
+            return null;
+        }
+
+        for (MethodAnnotationStruct item : methodAnnotations) {
+            if (item.getMethod().equals(method)) {
+                return item.getAnnotations();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets the parameter annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the parameter annotations, if any
+     */
+    public AnnotationsList getParameterAnnotations(CstMethodRef method) {
+        if (parameterAnnotations == null) {
+            return null;
+        }
+
+        for (ParameterAnnotationStruct item : parameterAnnotations) {
+            if (item.getMethod().equals(method)) {
+                return item.getAnnotationsList();
+            }
+        }
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection wordData = file.getWordData();
+
+        if (classAnnotations != null) {
+            classAnnotations = wordData.intern(classAnnotations);
+        }
+
+        if (fieldAnnotations != null) {
+            for (FieldAnnotationStruct item : fieldAnnotations) {
+                item.addContents(file);
+            }
+        }
+
+        if (methodAnnotations != null) {
+            for (MethodAnnotationStruct item : methodAnnotations) {
+                item.addContents(file);
+            }
+        }
+
+        if (parameterAnnotations != null) {
+            for (ParameterAnnotationStruct item : parameterAnnotations) {
+                item.addContents(file);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // We just need to set the write size here.
+
+        int elementCount = listSize(fieldAnnotations)
+            + listSize(methodAnnotations) + listSize(parameterAnnotations);
+        setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations);
+        int fieldsSize = listSize(fieldAnnotations);
+        int methodsSize = listSize(methodAnnotations);
+        int parametersSize = listSize(parameterAnnotations);
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " annotations directory");
+            out.annotate(4, "  class_annotations_off: " + Hex.u4(classOff));
+            out.annotate(4, "  fields_size:           " +
+                    Hex.u4(fieldsSize));
+            out.annotate(4, "  methods_size:          " +
+                    Hex.u4(methodsSize));
+            out.annotate(4, "  parameters_size:       " +
+                    Hex.u4(parametersSize));
+        }
+
+        out.writeInt(classOff);
+        out.writeInt(fieldsSize);
+        out.writeInt(methodsSize);
+        out.writeInt(parametersSize);
+
+        if (fieldsSize != 0) {
+            Collections.sort(fieldAnnotations);
+            if (annotates) {
+                out.annotate(0, "  fields:");
+            }
+            for (FieldAnnotationStruct item : fieldAnnotations) {
+                item.writeTo(file, out);
+            }
+        }
+
+        if (methodsSize != 0) {
+            Collections.sort(methodAnnotations);
+            if (annotates) {
+                out.annotate(0, "  methods:");
+            }
+            for (MethodAnnotationStruct item : methodAnnotations) {
+                item.writeTo(file, out);
+            }
+        }
+
+        if (parametersSize != 0) {
+            Collections.sort(parameterAnnotations);
+            if (annotates) {
+                out.annotate(0, "  parameters:");
+            }
+            for (ParameterAnnotationStruct item : parameterAnnotations) {
+                item.writeTo(file, out);
+            }
+        }
+    }
+
+    /**
+     * Gets the list size of the given list, or {@code 0} if given
+     * {@code null}.
+     *
+     * @param list {@code null-ok;} the list in question
+     * @return {@code >= 0;} its size
+     */
+    private static int listSize(ArrayList<?> list) {
+        if (list == null) {
+            return 0;
+        }
+
+        return list.size();
+    }
+
+    /**
+     * Prints out the contents of this instance, in a debugging-friendly
+     * way. This is meant to be called from {@link ClassDefItem#debugPrint}.
+     *
+     * @param out {@code non-null;} where to output to
+     */
+    /*package*/ void debugPrint(PrintWriter out) {
+        if (classAnnotations != null) {
+            out.println("  class annotations: " + classAnnotations);
+        }
+
+        if (fieldAnnotations != null) {
+            out.println("  field annotations:");
+            for (FieldAnnotationStruct item : fieldAnnotations) {
+                out.println("    " + item.toHuman());
+            }
+        }
+
+        if (methodAnnotations != null) {
+            out.println("  method annotations:");
+            for (MethodAnnotationStruct item : methodAnnotations) {
+                out.println("    " + item.toHuman());
+            }
+        }
+
+        if (parameterAnnotations != null) {
+            out.println("  parameter annotations:");
+            for (ParameterAnnotationStruct item : parameterAnnotations) {
+                out.println("    " + item.toHuman());
+            }
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/CatchStructs.java b/dexgen/src/com/android/dexgen/dex/file/CatchStructs.java
new file mode 100644
index 0000000..df9a847
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/CatchStructs.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.code.CatchHandlerList;
+import com.android.dexgen.dex.code.CatchTable;
+import com.android.dexgen.dex.code.DalvCode;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ByteArrayAnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * 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[]} and a
+ * {@code catch_handler_item[]}.
+ */
+public final class CatchStructs {
+    /**
+     * 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);
+
+    /** {@code non-null;} code that contains the catches */
+    private final DalvCode code;
+
+    /**
+     * {@code null-ok;} the underlying table; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private CatchTable table;
+
+    /**
+     * {@code null-ok;} the encoded handler list, if calculated; set in
+     * {@link #encode}
+     */
+    private byte[] encodedHandlers;
+
+    /**
+     * length of the handlers header (encoded size), if known; used for
+     * annotation
+     */
+    private int encodedHandlerHeaderSize;
+
+    /**
+     * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
+     * {@link #encode}
+     */
+    private TreeMap<CatchHandlerList, Integer> handlerOffsets;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param code {@code non-null;} code that contains the catches
+     */
+    public CatchStructs(DalvCode code) {
+        this.code = code;
+        this.table = null;
+        this.encodedHandlers = null;
+        this.encodedHandlerHeaderSize = 0;
+        this.handlerOffsets = null;
+    }
+
+    /**
+     * Finish processing the catches, if necessary.
+     */
+    private void finishProcessingIfNecessary() {
+        if (table == null) {
+            table = code.getCatches();
+        }
+    }
+
+    /**
+     * Gets the size of the tries list, in entries.
+     *
+     * @return {@code >= 0;} the tries list size
+     */
+    public int triesSize() {
+        finishProcessingIfNecessary();
+        return table.size();
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     */
+    public void debugPrint(PrintWriter out, String prefix) {
+        annotateEntries(prefix, out, null);
+    }
+
+    /**
+     * Encodes the handler lists.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     */
+    public void encode(DexFile file) {
+        finishProcessingIfNecessary();
+
+        TypeIdsSection typeIds = file.getTypeIds();
+        int size = table.size();
+
+        handlerOffsets = new TreeMap<CatchHandlerList, Integer>();
+
+        /*
+         * First add a map entry for each unique list. The tree structure
+         * will ensure they are sorted when we reiterate later.
+         */
+        for (int i = 0; i < size; i++) {
+            handlerOffsets.put(table.get(i).getHandlers(), null);
+        }
+
+        if (handlerOffsets.size() > 65535) {
+            throw new UnsupportedOperationException(
+                    "too many catch handlers");
+        }
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+
+        // Write out the handlers "header" consisting of its size in entries.
+        encodedHandlerHeaderSize =
+            out.writeUnsignedLeb128(handlerOffsets.size());
+
+        // Now write the lists out in order, noting the offset of each.
+        for (Map.Entry<CatchHandlerList, Integer> mapping :
+                 handlerOffsets.entrySet()) {
+            CatchHandlerList list = mapping.getKey();
+            int listSize = list.size();
+            boolean catchesAll = list.catchesAll();
+
+            // Set the offset before we do any writing.
+            mapping.setValue(out.getCursor());
+
+            if (catchesAll) {
+                // A size <= 0 means that the list ends with a catch-all.
+                out.writeSignedLeb128(-(listSize - 1));
+                listSize--;
+            } else {
+                out.writeSignedLeb128(listSize);
+            }
+
+            for (int i = 0; i < listSize; i++) {
+                CatchHandlerList.Entry entry = list.get(i);
+                out.writeUnsignedLeb128(
+                        typeIds.indexOf(entry.getExceptionType()));
+                out.writeUnsignedLeb128(entry.getHandler());
+            }
+
+            if (catchesAll) {
+                out.writeUnsignedLeb128(list.get(listSize).getHandler());
+            }
+        }
+
+        encodedHandlers = out.toByteArray();
+    }
+
+    /**
+     * Gets the write size of this instance, in bytes.
+     *
+     * @return {@code >= 0;} the write size
+     */
+    public int writeSize() {
+        return (triesSize() * TRY_ITEM_WRITE_SIZE) +
+                + encodedHandlers.length;
+    }
+
+    /**
+     * Writes this instance to the given stream.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        finishProcessingIfNecessary();
+
+        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();
+            int end = one.getEnd();
+            int insnCount = end - start;
+
+            if (insnCount >= 65536) {
+                throw new UnsupportedOperationException(
+                        "bogus exception range: " + Hex.u4(start) + ".." +
+                        Hex.u4(end));
+            }
+
+            out.writeInt(start);
+            out.writeShort(insnCount);
+            out.writeShort(handlerOffsets.get(one.getHandlers()));
+        }
+
+        out.write(encodedHandlers);
+    }
+
+    /**
+     * Helper method to annotate or simply print the exception handlers.
+     * Only one of {@code printTo} or {@code annotateTo} should
+     * be non-null.
+     *
+     * @param prefix {@code non-null;} prefix for each line
+     * @param printTo {@code null-ok;} where to print to
+     * @param annotateTo {@code null-ok;} where to consume bytes and annotate to
+     */
+    private void annotateEntries(String prefix, PrintWriter printTo,
+            AnnotatedOutput annotateTo) {
+        finishProcessingIfNecessary();
+
+        boolean consume = (annotateTo != null);
+        int amt1 = consume ? 6 : 0;
+        int amt2 = consume ? 2 : 0;
+        int size = table.size();
+        String subPrefix = prefix + "  ";
+
+        if (consume) {
+            annotateTo.annotate(0, prefix + "tries:");
+        } else {
+            printTo.println(prefix + "tries:");
+        }
+
+        for (int i = 0; i < size; i++) {
+            CatchTable.Entry entry = table.get(i);
+            CatchHandlerList handlers = entry.getHandlers();
+            String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart())
+                + ".." + Hex.u2or4(entry.getEnd());
+            String s2 = handlers.toHuman(subPrefix, "");
+
+            if (consume) {
+                annotateTo.annotate(amt1, s1);
+                annotateTo.annotate(amt2, s2);
+            } else {
+                printTo.println(s1);
+                printTo.println(s2);
+            }
+        }
+
+        if (! consume) {
+            // Only emit the handler lists if we are consuming bytes.
+            return;
+        }
+
+        annotateTo.annotate(0, prefix + "handlers:");
+        annotateTo.annotate(encodedHandlerHeaderSize,
+                subPrefix + "size: " + Hex.u2(handlerOffsets.size()));
+
+        int lastOffset = 0;
+        CatchHandlerList lastList = null;
+
+        for (Map.Entry<CatchHandlerList, Integer> mapping :
+                 handlerOffsets.entrySet()) {
+            CatchHandlerList list = mapping.getKey();
+            int offset = mapping.getValue();
+
+            if (lastList != null) {
+                annotateAndConsumeHandlers(lastList, lastOffset,
+                        offset - lastOffset, subPrefix, printTo, annotateTo);
+            }
+
+            lastList = list;
+            lastOffset = offset;
+        }
+
+        annotateAndConsumeHandlers(lastList, lastOffset,
+                encodedHandlers.length - lastOffset,
+                subPrefix, printTo, annotateTo);
+    }
+
+    /**
+     * Helper for {@link #annotateEntries} to annotate a catch handler list
+     * while consuming it.
+     *
+     * @param handlers {@code non-null;} handlers to annotate
+     * @param offset {@code >= 0;} the offset of this handler
+     * @param size {@code >= 1;} the number of bytes the handlers consume
+     * @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,
+            AnnotatedOutput annotateTo) {
+        String s = handlers.toHuman(prefix, Hex.u2(offset) + ": ");
+
+        if (printTo != null) {
+            printTo.println(s);
+        }
+
+        annotateTo.annotate(size, s);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ClassDataItem.java b/dexgen/src/com/android/dexgen/dex/file/ClassDataItem.java
new file mode 100644
index 0000000..c46a4a5
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ClassDataItem.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstArray;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.Zeroes;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ByteArrayAnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.Writers;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.HashMap;
+
+/**
+ * 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} file, as opposed to a random-access form.
+ */
+public final class ClassDataItem extends OffsettedItem {
+    /** {@code non-null;} what class this data is for, just for listing generation */
+    private final CstType thisClass;
+
+    /** {@code non-null;} list of static fields */
+    private final ArrayList<EncodedField> staticFields;
+
+    /** {@code non-null;} list of initial values for static fields */
+    private final HashMap<EncodedField, Constant> staticValues;
+
+    /** {@code non-null;} list of instance fields */
+    private final ArrayList<EncodedField> instanceFields;
+
+    /** {@code non-null;} list of direct methods */
+    private final ArrayList<EncodedMethod> directMethods;
+
+    /** {@code non-null;} list of virtual methods */
+    private final ArrayList<EncodedMethod> virtualMethods;
+
+    /** {@code null-ok;} static initializer list; set in {@link #addContents} */
+    private CstArray staticValuesConstant;
+
+    /**
+     * {@code null-ok;} encoded form, ready for writing to a file; set during
+     * {@link #place0}
+     */
+    private byte[] encodedForm;
+
+    /**
+     * Constructs an instance. Its sets of members are initially
+     * empty.
+     *
+     * @param thisClass {@code non-null;} what class this data is for, just
+     * for listing generation
+     */
+    public ClassDataItem(CstType thisClass) {
+        super(1, -1);
+
+        if (thisClass == null) {
+            throw new NullPointerException("thisClass == null");
+        }
+
+        this.thisClass = thisClass;
+        this.staticFields = new ArrayList<EncodedField>(20);
+        this.staticValues = new HashMap<EncodedField, Constant>(40);
+        this.instanceFields = new ArrayList<EncodedField>(20);
+        this.directMethods = new ArrayList<EncodedMethod>(20);
+        this.virtualMethods = new ArrayList<EncodedMethod>(20);
+        this.staticValuesConstant = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_CLASS_DATA_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return toString();
+    }
+
+    /**
+     * Returns whether this instance is empty.
+     *
+     * @return {@code true} if this instance is empty or
+     * {@code false} if at least one element has been added to it
+     */
+    public boolean isEmpty() {
+        return staticFields.isEmpty() && instanceFields.isEmpty()
+            && directMethods.isEmpty() && virtualMethods.isEmpty();
+    }
+
+    /**
+     * Adds a static field.
+     *
+     * @param field {@code non-null;} the field to add
+     * @param value {@code null-ok;} initial value for the field, if any
+     */
+    public void addStaticField(EncodedField field, Constant value) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        if (staticValuesConstant != null) {
+            throw new UnsupportedOperationException(
+                    "static fields already sorted");
+        }
+
+        staticFields.add(field);
+        staticValues.put(field, value);
+    }
+
+    /**
+     * Adds an instance field.
+     *
+     * @param field {@code non-null;} the field to add
+     */
+    public void addInstanceField(EncodedField field) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        instanceFields.add(field);
+    }
+
+    /**
+     * Adds a direct ({@code static} and/or {@code private}) method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addDirectMethod(EncodedMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        directMethods.add(method);
+    }
+
+    /**
+     * Adds a virtual method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addVirtualMethod(EncodedMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        virtualMethods.add(method);
+    }
+
+    /**
+     * Gets all the methods in this class. The returned list is not linked
+     * in any way to the underlying lists contained in this instance, but
+     * the objects contained in the list are shared.
+     *
+     * @return {@code non-null;} list of all methods
+     */
+    public ArrayList<EncodedMethod> getMethods() {
+        int sz = directMethods.size() + virtualMethods.size();
+        ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz);
+
+        result.addAll(directMethods);
+        result.addAll(virtualMethods);
+
+        return result;
+    }
+
+
+    /**
+     * Prints out the contents of this instance, in a debugging-friendly
+     * way.
+     *
+     * @param out {@code non-null;} where to output to
+     * @param verbose whether to be verbose with the output
+     */
+    public void debugPrint(Writer out, boolean verbose) {
+        PrintWriter pw = Writers.printWriterFor(out);
+
+        int sz = staticFields.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  sfields[" + i + "]: " + staticFields.get(i));
+        }
+
+        sz = instanceFields.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  ifields[" + i + "]: " + instanceFields.get(i));
+        }
+
+        sz = directMethods.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  dmeths[" + i + "]:");
+            directMethods.get(i).debugPrint(pw, verbose);
+        }
+
+        sz = virtualMethods.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  vmeths[" + i + "]:");
+            virtualMethods.get(i).debugPrint(pw, verbose);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        if (!staticFields.isEmpty()) {
+            getStaticValuesConstant(); // Force the fields to be sorted.
+            for (EncodedField field : staticFields) {
+                field.addContents(file);
+            }
+        }
+
+        if (!instanceFields.isEmpty()) {
+            Collections.sort(instanceFields);
+            for (EncodedField field : instanceFields) {
+                field.addContents(file);
+            }
+        }
+
+        if (!directMethods.isEmpty()) {
+            Collections.sort(directMethods);
+            for (EncodedMethod method : directMethods) {
+                method.addContents(file);
+            }
+        }
+
+        if (!virtualMethods.isEmpty()) {
+            Collections.sort(virtualMethods);
+            for (EncodedMethod method : virtualMethods) {
+                method.addContents(file);
+            }
+        }
+    }
+
+    /**
+     * Gets a {@link CstArray} corresponding to {@link #staticValues} if
+     * it contains any non-zero non-{@code null} values.
+     *
+     * @return {@code null-ok;} the corresponding constant or {@code null} if
+     * there are no values to encode
+     */
+    public CstArray getStaticValuesConstant() {
+        if ((staticValuesConstant == null) && (staticFields.size() != 0)) {
+            staticValuesConstant = makeStaticValuesConstant();
+        }
+
+        return staticValuesConstant;
+    }
+
+    /**
+     * Gets a {@link CstArray} corresponding to {@link #staticValues} if
+     * it contains any non-zero non-{@code null} values.
+     *
+     * @return {@code null-ok;} the corresponding constant or {@code null} if
+     * there are no values to encode
+     */
+    private CstArray makeStaticValuesConstant() {
+        // First sort the statics into their final order.
+        Collections.sort(staticFields);
+
+        /*
+         * Get the size of staticValues minus any trailing zeros/nulls (both
+         * nulls per se as well as instances of CstKnownNull).
+         */
+
+        int size = staticFields.size();
+        while (size > 0) {
+            EncodedField field = staticFields.get(size - 1);
+            Constant cst = staticValues.get(field);
+            if (cst instanceof CstLiteralBits) {
+                // Note: CstKnownNull extends CstLiteralBits.
+                if (((CstLiteralBits) cst).getLongBits() != 0) {
+                    break;
+                }
+            } else if (cst != null) {
+                break;
+            }
+            size--;
+        }
+
+        if (size == 0) {
+            return null;
+        }
+
+        // There is something worth encoding, so build up a result.
+
+        CstArray.List list = new CstArray.List(size);
+        for (int i = 0; i < size; i++) {
+            EncodedField field = staticFields.get(i);
+            Constant cst = staticValues.get(field);
+            if (cst == null) {
+                cst = Zeroes.zeroFor(field.getRef().getType());
+            }
+            list.set(i, cst);
+        }
+        list.setImmutable();
+
+        return new CstArray(list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+
+        encodeOutput(addedTo.getFile(), out);
+        encodedForm = out.toByteArray();
+        setWriteSize(encodedForm.length);
+    }
+
+    /**
+     * Writes out the encoded form of this instance.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     */
+    private void encodeOutput(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " class data for " +
+                    thisClass.toHuman());
+        }
+
+        encodeSize(file, out, "static_fields", staticFields.size());
+        encodeSize(file, out, "instance_fields", instanceFields.size());
+        encodeSize(file, out, "direct_methods", directMethods.size());
+        encodeSize(file, out, "virtual_methods", virtualMethods.size());
+
+        encodeList(file, out, "static_fields", staticFields);
+        encodeList(file, out, "instance_fields", instanceFields);
+        encodeList(file, out, "direct_methods", directMethods);
+        encodeList(file, out, "virtual_methods", virtualMethods);
+
+        if (annotates) {
+            out.endAnnotation();
+        }
+    }
+
+    /**
+     * Helper for {@link #encodeOutput}, which writes out the given
+     * size value, annotating it as well (if annotations are enabled).
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     * @param label {@code non-null;} the label for the purposes of annotation
+     * @param size {@code >= 0;} the size to write
+     */
+    private static void encodeSize(DexFile file, AnnotatedOutput out,
+            String label, int size) {
+        if (out.annotates()) {
+            out.annotate(String.format("  %-21s %08x", label + "_size:",
+                            size));
+        }
+
+        out.writeUnsignedLeb128(size);
+    }
+
+    /**
+     * Helper for {@link #encodeOutput}, which writes out the given
+     * list. It also annotates the items (if any and if annotations
+     * are enabled).
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     * @param label {@code non-null;} the label for the purposes of annotation
+     * @param list {@code non-null;} the list in question
+     */
+    private static void encodeList(DexFile file, AnnotatedOutput out,
+            String label, ArrayList<? extends EncodedMember> list) {
+        int size = list.size();
+        int lastIndex = 0;
+
+        if (size == 0) {
+            return;
+        }
+
+        if (out.annotates()) {
+            out.annotate(0, "  " + label + ":");
+        }
+
+        for (int i = 0; i < size; i++) {
+            lastIndex = list.get(i).encode(file, out, lastIndex, i);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+
+        if (annotates) {
+            /*
+             * The output is to be annotated, so redo the work previously
+             * done by place0(), except this time annotations will actually
+             * get emitted.
+             */
+            encodeOutput(file, out);
+        } else {
+            out.write(encodedForm);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ClassDefItem.java b/dexgen/src/com/android/dexgen/dex/file/ClassDefItem.java
new file mode 100644
index 0000000..6177145
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ClassDefItem.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotations;
+import com.android.dexgen.rop.annotation.AnnotationsList;
+import com.android.dexgen.rop.code.AccessFlags;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstArray;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.Writers;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.TreeSet;
+
+/**
+ * Representation of a Dalvik class, which is basically a set of
+ * members (fields or methods) along with a few more pieces of
+ * information.
+ */
+public final class ClassDefItem extends IndexedItem {
+    /** size of instances when written out to a file, in bytes */
+    public static final int WRITE_SIZE = 32;
+
+    /** {@code non-null;} type constant for this class */
+    private final CstType thisClass;
+
+    /** access flags */
+    private final int accessFlags;
+
+    /**
+     * {@code null-ok;} superclass or {@code null} if this class is a/the
+     * root class
+     */
+    private final CstType superclass;
+
+    /** {@code null-ok;} list of implemented interfaces */
+    private TypeListItem interfaces;
+
+    /** {@code null-ok;} source file name or {@code null} if unknown */
+    private final CstUtf8 sourceFile;
+
+    /** {@code non-null;} associated class data object */
+    private final ClassDataItem classData;
+
+    /**
+     * {@code null-ok;} item wrapper for the static values, initialized
+     * in {@link #addContents}
+     */
+    private EncodedArrayItem staticValuesItem;
+
+    /** {@code non-null;} annotations directory */
+    private AnnotationsDirectoryItem annotationsDirectory;
+
+    /**
+     * Constructs an instance. Its sets of members and annotations are
+     * initially empty.
+     *
+     * @param thisClass {@code non-null;} type constant for this class
+     * @param accessFlags access flags
+     * @param superclass {@code null-ok;} superclass or {@code null} if
+     * this class is a/the root class
+     * @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) {
+        if (thisClass == null) {
+            throw new NullPointerException("thisClass == null");
+        }
+
+        /*
+         * TODO: Maybe check accessFlags and superclass, at
+         * least for easily-checked stuff?
+         */
+
+        if (interfaces == null) {
+            throw new NullPointerException("interfaces == null");
+        }
+
+        this.thisClass = thisClass;
+        this.accessFlags = accessFlags;
+        this.superclass = superclass;
+        this.interfaces =
+            (interfaces.size() == 0) ? null :  new TypeListItem(interfaces);
+        this.sourceFile = sourceFile;
+        this.classData = new ClassDataItem(thisClass);
+        this.staticValuesItem = null;
+        this.annotationsDirectory = new AnnotationsDirectoryItem();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_CLASS_DEF_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return WRITE_SIZE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        MixedItemSection byteData = file.getByteData();
+        MixedItemSection wordData = file.getWordData();
+        MixedItemSection typeLists = file.getTypeLists();
+        StringIdsSection stringIds = file.getStringIds();
+
+        typeIds.intern(thisClass);
+
+        if (!classData.isEmpty()) {
+            MixedItemSection classDataSection = file.getClassData();
+            classDataSection.add(classData);
+
+            CstArray staticValues = classData.getStaticValuesConstant();
+            if (staticValues != null) {
+                staticValuesItem =
+                    byteData.intern(new EncodedArrayItem(staticValues));
+            }
+        }
+
+        if (superclass != null) {
+            typeIds.intern(superclass);
+        }
+
+        if (interfaces != null) {
+            interfaces = typeLists.intern(interfaces);
+        }
+
+        if (sourceFile != null) {
+            stringIds.intern(sourceFile);
+        }
+
+        if (! annotationsDirectory.isEmpty()) {
+            if (annotationsDirectory.isInternable()) {
+                annotationsDirectory = wordData.intern(annotationsDirectory);
+            } else {
+                wordData.add(annotationsDirectory);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        TypeIdsSection typeIds = file.getTypeIds();
+        int classIdx = typeIds.indexOf(thisClass);
+        int superIdx = (superclass == null) ? -1 :
+            typeIds.indexOf(superclass);
+        int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces);
+        int annoOff = annotationsDirectory.isEmpty() ? 0 :
+            annotationsDirectory.getAbsoluteOffset();
+        int sourceFileIdx = (sourceFile == null) ? -1 :
+            file.getStringIds().indexOf(sourceFile);
+        int dataOff = classData.isEmpty()? 0 : classData.getAbsoluteOffset();
+        int staticValuesOff =
+            OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem);
+
+        if (annotates) {
+            out.annotate(0, indexString() + ' ' + thisClass.toHuman());
+            out.annotate(4, "  class_idx:           " + Hex.u4(classIdx));
+            out.annotate(4, "  access_flags:        " +
+                         AccessFlags.classString(accessFlags));
+            out.annotate(4, "  superclass_idx:      " + Hex.u4(superIdx) +
+                         " // " + ((superclass == null) ? "<none>" :
+                          superclass.toHuman()));
+            out.annotate(4, "  interfaces_off:      " + Hex.u4(interOff));
+            if (interOff != 0) {
+                TypeList list = interfaces.getList();
+                int sz = list.size();
+                for (int i = 0; i < sz; i++) {
+                    out.annotate(0, "    " + list.getType(i).toHuman());
+                }
+            }
+            out.annotate(4, "  source_file_idx:     " + Hex.u4(sourceFileIdx) +
+                         " // " + ((sourceFile == null) ? "<none>" :
+                          sourceFile.toHuman()));
+            out.annotate(4, "  annotations_off:     " + Hex.u4(annoOff));
+            out.annotate(4, "  class_data_off:      " + Hex.u4(dataOff));
+            out.annotate(4, "  static_values_off:   " +
+                    Hex.u4(staticValuesOff));
+        }
+
+        out.writeInt(classIdx);
+        out.writeInt(accessFlags);
+        out.writeInt(superIdx);
+        out.writeInt(interOff);
+        out.writeInt(sourceFileIdx);
+        out.writeInt(annoOff);
+        out.writeInt(dataOff);
+        out.writeInt(staticValuesOff);
+    }
+
+    /**
+     * Gets the constant corresponding to this class.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstType getThisClass() {
+        return thisClass;
+    }
+
+    /**
+     * Gets the access flags.
+     *
+     * @return the access flags
+     */
+    public int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /**
+     * Gets the superclass.
+     *
+     * @return {@code null-ok;} the superclass or {@code null} if
+     * this class is a/the root class
+     */
+    public CstType getSuperclass() {
+        return superclass;
+    }
+
+    /**
+     * Gets the list of interfaces implemented.
+     *
+     * @return {@code non-null;} the interfaces list
+     */
+    public TypeList getInterfaces() {
+        if (interfaces == null) {
+            return StdTypeList.EMPTY;
+        }
+
+        return interfaces.getList();
+    }
+
+    /**
+     * Gets the source file name.
+     *
+     * @return {@code null-ok;} the source file name or {@code null} if unknown
+     */
+    public CstUtf8 getSourceFile() {
+        return sourceFile;
+    }
+
+    /**
+     * Adds a static field.
+     *
+     * @param field {@code non-null;} the field to add
+     * @param value {@code null-ok;} initial value for the field, if any
+     */
+    public void addStaticField(EncodedField field, Constant value) {
+        classData.addStaticField(field, value);
+    }
+
+    /**
+     * Adds an instance field.
+     *
+     * @param field {@code non-null;} the field to add
+     */
+    public void addInstanceField(EncodedField field) {
+        classData.addInstanceField(field);
+    }
+
+    /**
+     * Adds a direct ({@code static} and/or {@code private}) method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addDirectMethod(EncodedMethod method) {
+        classData.addDirectMethod(method);
+    }
+
+    /**
+     * Adds a virtual method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addVirtualMethod(EncodedMethod method) {
+        classData.addVirtualMethod(method);
+    }
+
+    /**
+     * Gets all the methods in this class. The returned list is not linked
+     * in any way to the underlying lists contained in this instance, but
+     * the objects contained in the list are shared.
+     *
+     * @return {@code non-null;} list of all methods
+     */
+    public ArrayList<EncodedMethod> getMethods() {
+        return classData.getMethods();
+    }
+
+    /**
+     * Sets the direct annotations on this class. These are annotations
+     * made on the class, per se, as opposed to on one of its members.
+     * It is only valid to call this method at most once per instance.
+     *
+     * @param annotations {@code non-null;} annotations to set for this class
+     */
+    public void setClassAnnotations(Annotations annotations) {
+        annotationsDirectory.setClassAnnotations(annotations);
+    }
+
+    /**
+     * Adds a field annotations item to this class.
+     *
+     * @param field {@code non-null;} field in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addFieldAnnotations(CstFieldRef field,
+            Annotations annotations) {
+        annotationsDirectory.addFieldAnnotations(field, annotations);
+    }
+
+    /**
+     * Adds a method annotations item to this class.
+     *
+     * @param method {@code non-null;} method in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addMethodAnnotations(CstMethodRef method,
+            Annotations annotations) {
+        annotationsDirectory.addMethodAnnotations(method, annotations);
+    }
+
+    /**
+     * Adds a parameter annotations item to this class.
+     *
+     * @param method {@code non-null;} method in question
+     * @param list {@code non-null;} associated list of annotation sets to add
+     */
+    public void addParameterAnnotations(CstMethodRef method,
+            AnnotationsList list) {
+        annotationsDirectory.addParameterAnnotations(method, list);
+    }
+
+    /**
+     * Gets the method annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the method annotations, if any
+     */
+    public Annotations getMethodAnnotations(CstMethodRef method) {
+        return annotationsDirectory.getMethodAnnotations(method);
+    }
+
+    /**
+     * Gets the parameter annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the parameter annotations, if any
+     */
+    public AnnotationsList getParameterAnnotations(CstMethodRef method) {
+        return annotationsDirectory.getParameterAnnotations(method);
+    }
+
+    /**
+     * Prints out the contents of this instance, in a debugging-friendly
+     * way.
+     *
+     * @param out {@code non-null;} where to output to
+     * @param verbose whether to be verbose with the output
+     */
+    public void debugPrint(Writer out, boolean verbose) {
+        PrintWriter pw = Writers.printWriterFor(out);
+
+        pw.println(getClass().getName() + " {");
+        pw.println("  accessFlags: " + Hex.u2(accessFlags));
+        pw.println("  superclass: " + superclass);
+        pw.println("  interfaces: " +
+                ((interfaces == null) ? "<none>" : interfaces));
+        pw.println("  sourceFile: " +
+                ((sourceFile == null) ? "<none>" : sourceFile.toQuoted()));
+
+        classData.debugPrint(out, verbose);
+        annotationsDirectory.debugPrint(pw);
+
+        pw.println("}");
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ClassDefsSection.java b/dexgen/src/com/android/dexgen/dex/file/ClassDefsSection.java
new file mode 100644
index 0000000..a6392d4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ClassDefsSection.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Class definitions list section of a {@code .dex} file.
+ */
+public final class ClassDefsSection extends UniformItemSection {
+    /**
+     * {@code non-null;} map from type constants for classes to {@link
+     * ClassDefItem} instances that define those classes
+     */
+    private final TreeMap<Type, ClassDefItem> classDefs;
+
+    /** {@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 {@code non-null;} file that this instance is part of
+     */
+    public ClassDefsSection(DexFile file) {
+        super("class_defs", file, 4);
+
+        classDefs = new TreeMap<Type, ClassDefItem>();
+        orderedDefs = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        if (orderedDefs != null) {
+            return orderedDefs;
+        }
+
+        return classDefs.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        Type type = ((CstType) cst).getClassType();
+        IndexedItem result = classDefs.get(type);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = classDefs.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "class_defs_size: " + Hex.u4(sz));
+            out.annotate(4, "class_defs_off:  " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Adds an element to this instance. It is illegal to attempt to add more
+     * than one class with the same name.
+     *
+     * @param clazz {@code non-null;} the class def to add
+     */
+    public void add(ClassDefItem clazz) {
+        Type type;
+
+        try {
+            type = clazz.getThisClass().getClassType();
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("clazz == null");
+        }
+
+        throwIfPrepared();
+
+        if (classDefs.get(type) != null) {
+            throw new IllegalArgumentException("already added: " + type);
+        }
+
+        classDefs.put(type, clazz);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int sz = classDefs.size();
+        int idx = 0;
+
+        orderedDefs = new ArrayList<ClassDefItem>(sz);
+
+        /*
+         * Iterate over all the classes, recursively assigning an
+         * index to each, implicitly skipping the ones that have
+         * already been assigned by the time this (top-level)
+         * iteration reaches them.
+         */
+        for (Type type : classDefs.keySet()) {
+            idx = orderItems0(type, idx, sz - idx);
+        }
+    }
+
+    /**
+     * Helper for {@link #orderItems}, which recursively assigns indices
+     * to classes.
+     *
+     * @param type {@code null-ok;} type ref to assign, if any
+     * @param idx {@code >= 0;} the next index to assign
+     * @param maxDepth maximum recursion depth; if negative, this will
+     * throw an exception indicating class definition circularity
+     * @return {@code >= 0;} the next index to assign
+     */
+    private int orderItems0(Type type, int idx, int maxDepth) {
+        ClassDefItem c = classDefs.get(type);
+
+        if ((c == null) || (c.hasIndex())) {
+            return idx;
+        }
+
+        if (maxDepth < 0) {
+            throw new RuntimeException("class circularity with " + type);
+        }
+
+        maxDepth--;
+
+        CstType superclassCst = c.getSuperclass();
+        if (superclassCst != null) {
+            Type superclass = superclassCst.getClassType();
+            idx = orderItems0(superclass, idx, maxDepth);
+        }
+
+        TypeList interfaces = c.getInterfaces();
+        int sz = interfaces.size();
+        for (int i = 0; i < sz; i++) {
+            idx = orderItems0(interfaces.getType(i), idx, maxDepth);
+        }
+
+        c.setIndex(idx);
+        orderedDefs.add(c);
+        return idx + 1;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/CodeItem.java b/dexgen/src/com/android/dexgen/dex/file/CodeItem.java
new file mode 100644
index 0000000..1b305c7
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/CodeItem.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.code.CatchTable;
+import com.android.dexgen.dex.code.CstInsn;
+import com.android.dexgen.dex.code.DalvCode;
+import com.android.dexgen.dex.code.DalvInsn;
+import com.android.dexgen.dex.code.DalvInsnList;
+import com.android.dexgen.dex.code.LocalList;
+import com.android.dexgen.dex.code.PositionList;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstMemberRef;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+import com.android.dexgen.util.Hex;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+
+/**
+ * Representation of all the parts needed for concrete methods in a
+ * {@code dex} file.
+ */
+public final class CodeItem extends OffsettedItem {
+    /** file alignment of this class, in bytes */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of the header of this class, in bytes */
+    private static final int HEADER_SIZE = 16;
+
+    /** {@code non-null;} method that this code implements */
+    private final CstMethodRef ref;
+
+    /** {@code non-null;} the bytecode instructions and associated data */
+    private final DalvCode code;
+
+    /** {@code null-ok;} the catches, if needed; set in {@link #addContents} */
+    private CatchStructs catches;
+
+    /** whether this instance is for a {@code static} method */
+    private final boolean isStatic;
+
+    /**
+     * {@code non-null;} list of possibly-thrown exceptions; just used in
+     * generating debugging output (listings)
+     */
+    private final TypeList throwsList;
+
+    /**
+     * {@code null-ok;} the debug info or {@code null} if there is none;
+     * set in {@link #addContents}
+     */
+    private DebugInfoItem debugInfo;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param ref {@code non-null;} method that this code implements
+     * @param code {@code non-null;} the underlying code
+     * @param isStatic whether this instance is for a {@code static}
+     * method
+     * @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,
+            TypeList throwsList) {
+        super(ALIGNMENT, -1);
+
+        if (ref == null) {
+            throw new NullPointerException("ref == null");
+        }
+
+        if (code == null) {
+            throw new NullPointerException("code == null");
+        }
+
+        if (throwsList == null) {
+            throw new NullPointerException("throwsList == null");
+        }
+
+        this.ref = ref;
+        this.code = code;
+        this.isStatic = isStatic;
+        this.throwsList = throwsList;
+        this.catches = null;
+        this.debugInfo = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_CODE_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection byteData = file.getByteData();
+        TypeIdsSection typeIds = file.getTypeIds();
+
+        if (code.hasPositions() || code.hasLocals()) {
+            debugInfo = new DebugInfoItem(code, isStatic, ref);
+            byteData.add(debugInfo);
+        }
+
+        if (code.hasAnyCatches()) {
+            for (Type type : code.getCatchTypes()) {
+                typeIds.intern(type);
+            }
+            catches = new CatchStructs(code);
+        }
+
+        for (Constant c : code.getInsnConstants()) {
+            file.internIfAppropriate(c);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "CodeItem{" + toHuman() + "}";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return ref.toHuman();
+    }
+
+    /**
+     * Gets the reference to the method this instance implements.
+     *
+     * @return {@code non-null;} the method reference
+     */
+    public CstMethodRef getRef() {
+        return ref;
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} per-line prefix to use
+     * @param verbose whether to be verbose with the output
+     */
+    public void debugPrint(PrintWriter out, String prefix, boolean verbose) {
+        out.println(ref.toHuman() + ":");
+
+        DalvInsnList insns = code.getInsns();
+        out.println("regs: " + Hex.u2(getRegistersSize()) +
+                "; ins: " + Hex.u2(getInsSize()) + "; outs: " +
+                Hex.u2(getOutsSize()));
+
+        insns.debugPrint(out, prefix, verbose);
+
+        String prefix2 = prefix + "  ";
+
+        if (catches != null) {
+            out.print(prefix);
+            out.println("catches");
+            catches.debugPrint(out, prefix2);
+        }
+
+        if (debugInfo != null) {
+            out.print(prefix);
+            out.println("debug info");
+            debugInfo.debugPrint(out, prefix2);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        final DexFile file = addedTo.getFile();
+        int catchesSize;
+
+        /*
+         * In order to get the catches and insns, all the code's
+         * constants need to be assigned indices.
+         */
+        code.assignIndices(new DalvCode.AssignIndicesCallback() {
+                public int getIndex(Constant cst) {
+                    IndexedItem item = file.findItemOrNull(cst);
+                    if (item == null) {
+                        return -1;
+                    }
+                    return item.getIndex();
+                }
+            });
+
+        if (catches != null) {
+            catches.encode(file);
+            catchesSize = catches.writeSize();
+        } else {
+            catchesSize = 0;
+        }
+
+        /*
+         * The write size includes the header, two bytes per code
+         * unit, post-code padding if necessary, and however much
+         * space the catches need.
+         */
+
+        int insnsSize = code.getInsns().codeSize();
+        if ((insnsSize & 1) != 0) {
+            insnsSize++;
+        }
+
+        setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        int regSz = getRegistersSize();
+        int outsSz = getOutsSize();
+        int insSz = getInsSize();
+        int insnsSz = code.getInsns().codeSize();
+        boolean needPadding = (insnsSz & 1) != 0;
+        int triesSz = (catches == null) ? 0 : catches.triesSize();
+        int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + ' ' + ref.toHuman());
+            out.annotate(2, "  registers_size: " + Hex.u2(regSz));
+            out.annotate(2, "  ins_size:       " + Hex.u2(insSz));
+            out.annotate(2, "  outs_size:      " + Hex.u2(outsSz));
+            out.annotate(2, "  tries_size:     " + Hex.u2(triesSz));
+            out.annotate(4, "  debug_off:      " + Hex.u4(debugOff));
+            out.annotate(4, "  insns_size:     " + Hex.u4(insnsSz));
+
+            // This isn't represented directly here, but it is useful to see.
+            int size = throwsList.size();
+            if (size != 0) {
+                out.annotate(0, "  throws " + StdTypeList.toHuman(throwsList));
+            }
+        }
+
+        out.writeShort(regSz);
+        out.writeShort(insSz);
+        out.writeShort(outsSz);
+        out.writeShort(triesSz);
+        out.writeInt(debugOff);
+        out.writeInt(insnsSz);
+
+        writeCodes(file, out);
+
+        if (catches != null) {
+            if (needPadding) {
+                if (annotates) {
+                    out.annotate(2, "  padding: 0");
+                }
+                out.writeShort(0);
+            }
+
+            catches.writeTo(file, out);
+        }
+
+        if (annotates) {
+            /*
+             * These are pointed at in the code header (above), but it's less
+             * distracting to expand on them at the bottom of the code.
+             */
+            if (debugInfo != null) {
+                out.annotate(0, "  debug info");
+                debugInfo.annotateTo(file, out, "    ");
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #writeTo0} which writes out the actual bytecode.
+     *
+     * @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();
+
+        try {
+            insns.writeTo(out);
+        } catch (RuntimeException ex) {
+            throw ExceptionWithContext.withContext(ex, "...while writing " +
+                    "instructions for " + ref.toHuman());
+        }
+    }
+
+    /**
+     * Get the in registers count.
+     *
+     * @return the count
+     */
+    private int getInsSize() {
+        return ref.getParameterWordCount(isStatic);
+    }
+
+    /**
+     * Get the out registers count.
+     *
+     * @return the count
+     */
+    private int getOutsSize() {
+        return code.getInsns().getOutsSize();
+    }
+
+    /**
+     * Get the total registers count.
+     *
+     * @return the count
+     */
+    private int getRegistersSize() {
+        return code.getInsns().getRegistersSize();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/DebugInfoConstants.java b/dexgen/src/com/android/dexgen/dex/file/DebugInfoConstants.java
new file mode 100644
index 0000000..780f350
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/DebugInfoConstants.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+/**
+ * Constants for the dex debug info state machine format.
+ */
+public interface DebugInfoConstants {
+
+    /*
+     * normal opcodes
+     */
+
+    /**
+     * Terminates a debug info sequence for a method.<p>
+     * Args: none
+     *
+     */
+    static final int DBG_END_SEQUENCE = 0x00;
+
+    /**
+     * Advances the program counter/address register without emitting
+     * a positions entry.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; amount to advance pc by
+     * </ol>
+     */
+    static final int DBG_ADVANCE_PC = 0x01;
+
+    /**
+     * Advances the line register without emitting
+     * a positions entry.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Signed LEB128 &mdash; amount to change line register by.
+     * </ol>
+     */
+    static final int DBG_ADVANCE_LINE = 0x02;
+
+    /**
+     * Introduces a local variable at the current address.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register that will contain local.
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of local name.
+     * <li>Unsigned LEB128 &mdash; type index (shifted by 1) of type.
+     * </ol>
+     */
+    static final int DBG_START_LOCAL = 0x03;
+
+    /**
+     * Introduces a local variable at the current address with a type
+     * signature specified.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register that will contain local.
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of local name.
+     * <li>Unsigned LEB128 &mdash; type index (shifted by 1) of type.
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of
+     * type signature.
+     * </ol>
+     */
+    static final int DBG_START_LOCAL_EXTENDED = 0x04;
+
+    /**
+     * Marks a currently-live local variable as out of scope at the
+     * current address.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register that contained local
+     * </ol>
+     */
+    static final int DBG_END_LOCAL = 0x05;
+
+    /**
+     * Re-introduces a local variable at the current address. The name
+     * and type are the same as the last local that was live in the specified
+     * register.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register to re-start.
+     * </ol>
+     */
+    static final int DBG_RESTART_LOCAL = 0x06;
+
+
+    /**
+     * Sets the "prologue_end" state machine register, indicating that the
+     * next position entry that is added should be considered the end of
+     * a method prologue (an appropriate place for a method breakpoint).<p>
+     *
+     * The prologue_end register is cleared by any special
+     * ({@code >= OPCODE_BASE}) opcode.
+     */
+    static final int DBG_SET_PROLOGUE_END = 0x07;
+
+    /**
+     * Sets the "epilogue_begin" state machine register, indicating that the
+     * next position entry that is added should be considered the beginning of
+     * a method epilogue (an appropriate place to suspend execution before
+     * method exit).<p>
+     *
+     * The epilogue_begin register is cleared by any special
+     * ({@code >= OPCODE_BASE}) opcode.
+     */
+    static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
+
+    /**
+     * Sets the current file that that line numbers refer to. All subsequent
+     * line number entries make reference to this source file name, instead
+     * of the default name specified in code_item.
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of source
+     * file name.
+     * </ol>
+     */
+    static final int DBG_SET_FILE = 0x09;
+
+    /* IF YOU ADD A NEW OPCODE, increase OPCODE_BASE */
+
+    /*
+     * "special opcode" configuration, essentially what's found in
+     * the line number program header in DWARFv3, Section 6.2.4
+     */
+
+    /** the smallest value a special opcode can take */
+    static final int DBG_FIRST_SPECIAL = 0x0a;
+    static final int DBG_LINE_BASE = -4;
+    static final int DBG_LINE_RANGE = 15;
+    // MIN_INSN_LENGTH is always 1
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/DebugInfoDecoder.java b/dexgen/src/com/android/dexgen/dex/file/DebugInfoDecoder.java
new file mode 100644
index 0000000..da614d2
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/DebugInfoDecoder.java
@@ -0,0 +1,653 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.code.DalvCode;
+import com.android.dexgen.dex.code.DalvInsnList;
+import com.android.dexgen.dex.code.LocalList;
+import com.android.dexgen.dex.code.PositionList;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Prototype;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.ExceptionWithContext;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.dexgen.dex.file.DebugInfoConstants.*;
+
+/**
+ * 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}
+ */
+public class DebugInfoDecoder {
+    /** encoded debug info */
+    private final byte[] encoded;
+
+    /** positions decoded */
+    private final ArrayList<PositionEntry> positions;
+
+    /** locals decoded */
+    private final ArrayList<LocalEntry> locals;
+
+    /** size of code block in code units */
+    private final int codesize;
+
+    /** indexed by register, the last local variable live in a reg */
+    private final LocalEntry[] lastEntryForReg;
+
+    /** method descriptor of method this debug info is for */
+    private final Prototype desc;
+
+    /** true if method is static */
+    private final boolean isStatic;
+
+    /** dex file this debug info will be stored in */
+    private final DexFile file;
+
+    /**
+     * register size, in register units, of the register space
+     * used by this method
+     */
+    private final int regSize;
+
+    /** current decoding state: line number */
+    private int line = 1;
+
+    /** current decoding state: bytecode address */
+    private int address = 0;
+
+    /** string index of the string "this" */
+    private final int thisStringIdx;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param encoded encoded debug info
+     * @param codesize size of code block in code units
+     * @param regSize register size, in register units, of the register space
+     * used by this method
+     * @param isStatic true if method is static
+     * @param ref method descriptor of method this debug info is for
+     * @param file dex file this debug info will be stored in
+     */
+    DebugInfoDecoder(byte[] encoded, int codesize, int regSize,
+            boolean isStatic, CstMethodRef ref, DexFile file) {
+        if (encoded == null) {
+            throw new NullPointerException("encoded == null");
+        }
+
+        this.encoded = encoded;
+        this.isStatic = isStatic;
+        this.desc = ref.getPrototype();
+        this.file = file;
+        this.regSize = regSize;
+
+        positions = new ArrayList<PositionEntry>();
+        locals = new ArrayList<LocalEntry>();
+        this.codesize = codesize;
+        lastEntryForReg = new LocalEntry[regSize];
+
+        int idx = -1;
+
+        try {
+            idx = file.getStringIds().indexOf(new CstUtf8("this"));
+        } catch (IllegalArgumentException ex) {
+            /*
+             * Silently tolerate not finding "this". It just means that
+             * no method has local variable info that looks like
+             * a standard instance method.
+             */
+        }
+
+        thisStringIdx = idx;
+    }
+
+    /**
+     * An entry in the resulting postions table
+     */
+    static private class PositionEntry {
+        /** bytecode address */
+        public int address;
+
+        /** line number */
+        public int line;
+
+        public PositionEntry(int address, int line) {
+            this.address = address;
+            this.line = line;
+        }
+    }
+
+    /**
+     * An entry in the resulting locals table
+     */
+    static private class LocalEntry {
+        /** address of event */
+        public int address;
+
+        /** {@code true} iff it's a local start */
+        public boolean isStart;
+
+        /** register number */
+        public int reg;
+
+        /** index of name in strings table */
+        public int nameIndex;
+
+        /** index of type in types table */
+        public int typeIndex;
+
+        /** index of type signature in strings table */
+        public int signatureIndex;
+
+        public LocalEntry(int address, boolean isStart, int reg, int nameIndex,
+                int typeIndex, int signatureIndex) {
+            this.address        = address;
+            this.isStart        = isStart;
+            this.reg            = reg;
+            this.nameIndex      = nameIndex;
+            this.typeIndex      = typeIndex;
+            this.signatureIndex = signatureIndex;
+        }
+
+        public String toString() {
+            return String.format("[%x %s v%d %04x %04x %04x]",
+                    address, isStart ? "start" : "end", reg,
+                    nameIndex, typeIndex, signatureIndex);
+        }
+    }
+
+    /**
+     * Gets the decoded positions list.
+     * Valid after calling {@code decode}.
+     *
+     * @return positions list in ascending address order.
+     */
+    public List<PositionEntry> getPositionList() {
+        return positions;
+    }
+
+    /**
+     * Gets the decoded locals list, in ascending start-address order.
+     * Valid after calling {@code decode}.
+     *
+     * @return locals list in ascending address order.
+     */
+    public List<LocalEntry> getLocals() {
+        return locals;
+    }
+
+    /**
+     * Decodes the debug info sequence.
+     */
+    public void decode() {
+        try {
+            decode0();
+        } catch (Exception ex) {
+            throw ExceptionWithContext.withContext(ex,
+                    "...while decoding debug info");
+        }
+    }
+
+    /**
+     * Reads a string index. String indicies are offset by 1, and a 0 value
+     * in the stream (-1 as returned by this method) means "null"
+     *
+     * @param bs
+     * @return index into file's string ids table, -1 means null
+     * @throws IOException
+     */
+    private int readStringIndex(InputStream bs) throws IOException {
+        int offsetIndex = readUnsignedLeb128(bs);
+
+        return offsetIndex - 1;
+    }
+
+    /**
+     * Gets the register that begins the method's parameter range (including
+     * the 'this' parameter for non-static methods). The range continues until
+     * {@code regSize}
+     *
+     * @return register as noted above.
+     */
+    private int getParamBase() {
+        return regSize
+                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
+    }
+
+    private void decode0() throws IOException {
+        ByteArrayInputStream bs = new ByteArrayInputStream(encoded);
+
+        line = readUnsignedLeb128(bs);
+        int szParams = readUnsignedLeb128(bs);
+        StdTypeList params = desc.getParameterTypes();
+        int curReg = getParamBase();
+
+        if (szParams != params.size()) {
+            throw new RuntimeException(
+                    "Mismatch between parameters_size and prototype");
+        }
+
+        if (!isStatic) {
+            // Start off with implicit 'this' entry
+            LocalEntry thisEntry =
+                new LocalEntry(0, true, curReg, thisStringIdx, 0, 0);
+            locals.add(thisEntry);
+            lastEntryForReg[curReg] = thisEntry;
+            curReg++;
+        }
+
+        for (int i = 0; i < szParams; i++) {
+            Type paramType = params.getType(i);
+            LocalEntry le;
+
+            int nameIdx = readStringIndex(bs);
+
+            if (nameIdx == -1) {
+                /*
+                 * Unnamed parameter; often but not always filled in by an
+                 * extended start op after the prologue
+                 */
+                le = new LocalEntry(0, true, curReg, -1, 0, 0);
+            } else {
+                // TODO: Final 0 should be idx of paramType.getDescriptor().
+                le = new LocalEntry(0, true, curReg, nameIdx, 0, 0);
+            }
+
+            locals.add(le);
+            lastEntryForReg[curReg] = le;
+            curReg += paramType.getCategory();
+        }
+
+        for (;;) {
+            int opcode = bs.read();
+
+            if (opcode < 0) {
+                throw new RuntimeException
+                        ("Reached end of debug stream without "
+                                + "encountering end marker");
+            }
+
+            switch (opcode) {
+                case DBG_START_LOCAL: {
+                    int reg = readUnsignedLeb128(bs);
+                    int nameIdx = readStringIndex(bs);
+                    int typeIdx = readStringIndex(bs);
+                    LocalEntry le = new LocalEntry(
+                            address, true, reg, nameIdx, typeIdx, 0);
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_START_LOCAL_EXTENDED: {
+                    int reg = readUnsignedLeb128(bs);
+                    int nameIdx = readStringIndex(bs);
+                    int typeIdx = readStringIndex(bs);
+                    int sigIdx = readStringIndex(bs);
+                    LocalEntry le = new LocalEntry(
+                            address, true, reg, nameIdx, typeIdx, sigIdx);
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_RESTART_LOCAL: {
+                    int reg = readUnsignedLeb128(bs);
+                    LocalEntry prevle;
+                    LocalEntry le;
+
+                    try {
+                        prevle = lastEntryForReg[reg];
+
+                        if (prevle.isStart) {
+                            throw new RuntimeException("nonsensical "
+                                    + "RESTART_LOCAL on live register v"
+                                    + reg);
+                        }
+
+                        le = new LocalEntry(address, true, reg,
+                                prevle.nameIndex, prevle.typeIndex, 0);
+                    } catch (NullPointerException ex) {
+                        throw new RuntimeException(
+                                "Encountered RESTART_LOCAL on new v" + reg);
+                    }
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_END_LOCAL: {
+                    int reg = readUnsignedLeb128(bs);
+                    LocalEntry prevle;
+                    LocalEntry le;
+
+                    try {
+                        prevle = lastEntryForReg[reg];
+
+                        if (!prevle.isStart) {
+                            throw new RuntimeException("nonsensical "
+                                    + "END_LOCAL on dead register v" + reg);
+                        }
+
+                        le = new LocalEntry(address, false, reg,
+                                prevle.nameIndex, prevle.typeIndex,
+                                prevle.signatureIndex);
+                    } catch (NullPointerException ex) {
+                        throw new RuntimeException(
+                                "Encountered END_LOCAL on new v" + reg);
+                    }
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_END_SEQUENCE:
+                    // all done
+                return;
+
+                case DBG_ADVANCE_PC:
+                    address += readUnsignedLeb128(bs);
+                break;
+
+                case DBG_ADVANCE_LINE:
+                    line += readSignedLeb128(bs);
+                break;
+
+                case DBG_SET_PROLOGUE_END:
+                    //TODO do something with this.
+                break;
+
+                case DBG_SET_EPILOGUE_BEGIN:
+                    //TODO do something with this.
+                break;
+
+                case DBG_SET_FILE:
+                    //TODO do something with this.
+                break;
+
+                default:
+                    if (opcode < DBG_FIRST_SPECIAL) {
+                        throw new RuntimeException(
+                                "Invalid extended opcode encountered "
+                                        + opcode);
+                    }
+
+                    int adjopcode = opcode - DBG_FIRST_SPECIAL;
+
+                    address += adjopcode / DBG_LINE_RANGE;
+                    line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+
+                    positions.add(new PositionEntry(address, line));
+                break;
+
+            }
+        }
+    }
+
+    /**
+     * Validates an encoded debug info stream against data used to encode it,
+     * throwing an exception if they do not match. Used to validate the
+     * encoder.
+     *
+     * @param info encoded debug info
+     * @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,
+            CstMethodRef ref, DalvCode code, boolean isStatic) {
+        PositionList pl = code.getPositions();
+        LocalList ll = code.getLocals();
+        DalvInsnList insns = code.getInsns();
+        int codeSize = insns.codeSize();
+        int countRegisters = insns.getRegistersSize();
+
+        try {
+            validateEncode0(info, codeSize, countRegisters,
+                    isStatic, ref, file, pl, ll);
+        } catch (RuntimeException ex) {
+            System.err.println("instructions:");
+            insns.debugPrint(System.err, "  ", true);
+            System.err.println("local list:");
+            ll.debugPrint(System.err, "  ");
+            throw ExceptionWithContext.withContext(ex,
+                    "while processing " + ref.toHuman());
+        }
+    }
+
+    private static void validateEncode0(byte[] info, int codeSize,
+            int countRegisters, boolean isStatic, CstMethodRef ref,
+            DexFile file, PositionList pl, LocalList ll) {
+        DebugInfoDecoder decoder
+                = new DebugInfoDecoder(info, codeSize, countRegisters,
+                    isStatic, ref, file);
+
+        decoder.decode();
+
+        /*
+         * Go through the decoded position entries, matching up
+         * with original entries.
+         */
+
+        List<PositionEntry> decodedEntries = decoder.getPositionList();
+
+        if (decodedEntries.size() != pl.size()) {
+            throw new RuntimeException(
+                    "Decoded positions table not same size was "
+                    + decodedEntries.size() + " expected " + pl.size());
+        }
+
+        for (PositionEntry entry : decodedEntries) {
+            boolean found = false;
+            for (int i = pl.size() - 1; i >= 0; i--) {
+                PositionList.Entry ple = pl.get(i);
+
+                if (entry.line == ple.getPosition().getLine()
+                        && entry.address == ple.getAddress()) {
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found) {
+                throw new RuntimeException ("Could not match position entry: "
+                        + entry.address + ", " + entry.line);
+            }
+        }
+
+        /*
+         * Go through the original local list, in order, matching up
+         * with decoded entries.
+         */
+
+        List<LocalEntry> decodedLocals = decoder.getLocals();
+        int thisStringIdx = decoder.thisStringIdx;
+        int decodedSz = decodedLocals.size();
+        int paramBase = decoder.getParamBase();
+
+        /*
+         * Preflight to fill in any parameters that were skipped in
+         * the prologue (including an implied "this") but then
+         * identified by full signature.
+         */
+        for (int i = 0; i < decodedSz; i++) {
+            LocalEntry entry = decodedLocals.get(i);
+            int idx = entry.nameIndex;
+
+            if ((idx < 0) || (idx == thisStringIdx)) {
+                for (int j = i + 1; j < decodedSz; j++) {
+                    LocalEntry e2 = decodedLocals.get(j);
+                    if (e2.address != 0) {
+                        break;
+                    }
+                    if ((entry.reg == e2.reg) && e2.isStart) {
+                        decodedLocals.set(i, e2);
+                        decodedLocals.remove(j);
+                        decodedSz--;
+                        break;
+                    }
+                }
+            }
+        }
+
+        int origSz = ll.size();
+        int decodeAt = 0;
+        boolean problem = false;
+
+        for (int i = 0; i < origSz; i++) {
+            LocalList.Entry origEntry = ll.get(i);
+
+            if (origEntry.getDisposition()
+                    == LocalList.Disposition.END_REPLACED) {
+                /*
+                 * The encoded list doesn't represent replacements, so
+                 * ignore them for the sake of comparison.
+                 */
+                continue;
+            }
+
+            LocalEntry decodedEntry;
+
+            do {
+                decodedEntry = decodedLocals.get(decodeAt);
+                if (decodedEntry.nameIndex >= 0) {
+                    break;
+                }
+                /*
+                 * A negative name index means this is an anonymous
+                 * parameter, and we shouldn't expect to see it in the
+                 * original list. So, skip it.
+                 */
+                decodeAt++;
+            } while (decodeAt < decodedSz);
+
+            int decodedAddress = decodedEntry.address;
+
+            if (decodedEntry.reg != origEntry.getRegister()) {
+                System.err.println("local register mismatch at orig " + i +
+                        " / decoded " + decodeAt);
+                problem = true;
+                break;
+            }
+
+            if (decodedEntry.isStart != origEntry.isStart()) {
+                System.err.println("local start/end mismatch at orig " + i +
+                        " / decoded " + decodeAt);
+                problem = true;
+                break;
+            }
+
+            /*
+             * The secondary check here accounts for the fact that a
+             * parameter might not be marked as starting at 0 in the
+             * original list.
+             */
+            if ((decodedAddress != origEntry.getAddress())
+                    && !((decodedAddress == 0)
+                            && (decodedEntry.reg >= paramBase))) {
+                System.err.println("local address mismatch at orig " + i +
+                        " / decoded " + decodeAt);
+                problem = true;
+                break;
+            }
+
+            decodeAt++;
+        }
+
+        if (problem) {
+            System.err.println("decoded locals:");
+            for (LocalEntry e : decodedLocals) {
+                System.err.println("  " + e);
+            }
+            throw new RuntimeException("local table problem");
+        }
+    }
+
+    /**
+     * Reads a DWARFv3-style signed LEB128 integer to the specified stream.
+     * See DWARF v3 section 7.6. An invalid sequence produces an IOException.
+     *
+     * @param bs stream to input from
+     * @return read value
+     * @throws IOException on invalid sequence in addition to
+     * those caused by the InputStream
+     */
+    public static int readSignedLeb128(InputStream bs) throws IOException {
+        int result = 0;
+        int cur;
+        int count = 0;
+        int signBits = -1;
+
+        do {
+            cur = bs.read();
+            result |= (cur & 0x7f) << (count * 7);
+            signBits <<= 7;
+            count++;
+        } while (((cur & 0x80) == 0x80) && count < 5);
+
+        if ((cur & 0x80) == 0x80) {
+            throw new IOException ("invalid LEB128 sequence");
+        }
+
+        // Sign extend if appropriate
+        if (((signBits >> 1) & result) != 0 ) {
+            result |= signBits;
+        }
+
+        return result;
+    }
+
+    /**
+     * Reads a DWARFv3-style unsigned LEB128 integer to the specified stream.
+     * See DWARF v3 section 7.6. An invalid sequence produces an IOException.
+     *
+     * @param bs stream to input from
+     * @return read value, which should be treated as an unsigned value.
+     * @throws IOException on invalid sequence in addition to
+     * those caused by the InputStream
+     */
+    public static int readUnsignedLeb128(InputStream bs) throws IOException {
+        int result = 0;
+        int cur;
+        int count = 0;
+
+        do {
+            cur = bs.read();
+            result |= (cur & 0x7f) << (count * 7);
+            count++;
+        } while (((cur & 0x80) == 0x80) && count < 5);
+
+        if ((cur & 0x80) == 0x80) {
+            throw new IOException ("invalid LEB128 sequence");
+        }
+
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/DebugInfoEncoder.java b/dexgen/src/com/android/dexgen/dex/file/DebugInfoEncoder.java
new file mode 100644
index 0000000..663de7e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/DebugInfoEncoder.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.code.LocalList;
+import com.android.dexgen.dex.code.PositionList;
+import com.android.dexgen.rop.code.RegisterSpec;
+import com.android.dexgen.rop.code.SourcePosition;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Prototype;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ByteArrayAnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.BitSet;
+
+import static com.android.dexgen.dex.file.DebugInfoConstants.*;
+
+/**
+ * An encoder for the dex debug info state machine format. The format
+ * for each method enrty is as follows:
+ * <ol>
+ * <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} excluded. A value of '0' indicates "no name"
+ * <li> A sequence of special or normal opcodes as defined in
+ * {@code DebugInfoConstants}.
+ * <li> A single terminating {@code OP_END_SEQUENCE}
+ * </ol>
+ */
+public final class DebugInfoEncoder {
+    private static final boolean DEBUG = false;
+
+    /** {@code null-ok;} positions (line numbers) to encode */
+    private final PositionList positions;
+
+    /** {@code null-ok;} local variables to encode */
+    private final LocalList locals;
+
+    private final ByteArrayAnnotatedOutput output;
+    private final DexFile file;
+    private final int codeSize;
+    private final int regSize;
+
+    private final Prototype desc;
+    private final boolean isStatic;
+
+    /** current encoding state: bytecode address */
+    private int address = 0;
+
+    /** current encoding state: line number */
+    private int line = 1;
+
+    /**
+     * if non-null: the output to write annotations to. No normal
+     * output is written to this.
+     */
+    private AnnotatedOutput annotateTo;
+
+    /** if non-null: another possible output for annotations */
+    private PrintWriter debugPrint;
+
+    /** if non-null: the prefix for each annotation or debugPrint line */
+    private String prefix;
+
+    /** true if output should be consumed during annotation */
+    private boolean shouldConsume;
+
+    /** indexed by register; last local alive in register */
+    private final LocalList.Entry[] lastEntryForReg;
+
+    /**
+     * Creates an instance.
+     *
+     * @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 positions, LocalList locals,
+            DexFile file, int codeSize, int regSize,
+            boolean isStatic, CstMethodRef ref) {
+        this.positions = positions;
+        this.locals = locals;
+        this.file = file;
+        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} writer
+     * if applicable.
+     *
+     * @param length the number of bytes associated with this message
+     * @param message the message itself
+     */
+    private void annotate(int length, String message) {
+        if (prefix != null) {
+            message = prefix + message;
+        }
+
+        if (annotateTo != null) {
+            annotateTo.annotate(shouldConsume ? length : 0, message);
+        }
+
+        if (debugPrint != null) {
+            debugPrint.println(message);
+        }
+    }
+
+    /**
+     * Converts this (PositionList, LocalList) pair into a state machine
+     * sequence.
+     *
+     * @return {@code non-null;} encoded byte sequence without padding and
+     * terminated with a {@code 0x00} byte
+     */
+    public byte[] convert() {
+        try {
+            byte[] ret;
+            ret = convert0();
+
+            if (DEBUG) {
+                for (int i = 0 ; i < ret.length; i++) {
+                    System.err.printf("byte %02x\n", (0xff & ret[i]));
+                }
+            }
+
+            return ret;
+        } catch (IOException ex) {
+            throw ExceptionWithContext
+                    .withContext(ex, "...while encoding debug info");
+        }
+    }
+
+    /**
+     * Converts and produces annotations on a stream. Does not write
+     * actual bits to the {@code AnnotatedOutput}.
+     *
+     * @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 {@code null-ok;} if specified, where annotations should go
+     * @param consume whether to claim to have consumed output for
+     * {@code out}
+     * @return {@code non-null;} encoded output
+     */
+    public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint,
+            AnnotatedOutput out, boolean consume) {
+        this.prefix = prefix;
+        this.debugPrint = debugPrint;
+        annotateTo = out;
+        shouldConsume = consume;
+
+        byte[] result = convert();
+
+        return result;
+    }
+
+    private byte[] convert0() throws IOException {
+        ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions();
+        ArrayList<LocalList.Entry> methodArgs = extractMethodArguments();
+
+        emitHeader(sortedPositions, methodArgs);
+
+        // TODO: Make this mark be the actual prologue end.
+        output.writeByte(DBG_SET_PROLOGUE_END);
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(1, String.format("%04x: prologue end",address));
+        }
+
+        int positionsSz = sortedPositions.size();
+        int localsSz = locals.size();
+
+        // Current index in sortedPositions
+        int curPositionIdx = 0;
+        // Current index in locals
+        int curLocalIdx = 0;
+
+        for (;;) {
+            /*
+             * Emit any information for the current address.
+             */
+
+            curLocalIdx = emitLocalsAtAddress(curLocalIdx);
+            curPositionIdx =
+                emitPositionsAtAddress(curPositionIdx, sortedPositions);
+
+            /*
+             * Figure out what the next important address is.
+             */
+
+            int nextAddrL = Integer.MAX_VALUE; // local variable
+            int nextAddrP = Integer.MAX_VALUE; // position (line number)
+
+            if (curLocalIdx < localsSz) {
+                nextAddrL = locals.get(curLocalIdx).getAddress();
+            }
+
+            if (curPositionIdx < positionsSz) {
+                nextAddrP = sortedPositions.get(curPositionIdx).getAddress();
+            }
+
+            int next = Math.min(nextAddrP, nextAddrL);
+
+            // No next important address == done.
+            if (next == Integer.MAX_VALUE) {
+                break;
+            }
+
+            /*
+             * If the only work remaining are local ends at the end of the
+             * block, stop here. Those are implied anyway.
+             */
+            if (next == codeSize
+                    && nextAddrL == Integer.MAX_VALUE
+                    && nextAddrP == Integer.MAX_VALUE) {
+                break;
+            }
+
+            if (next == nextAddrP) {
+                // Combined advance PC + position entry
+                emitPosition(sortedPositions.get(curPositionIdx++));
+            } else {
+                emitAdvancePc(next - address);
+            }
+        }
+
+        emitEndSequence();
+
+        return output.toByteArray();
+    }
+
+    /**
+     * Emits all local variable activity that occurs at the current
+     * {@link #address} starting at the given index into {@code
+     * locals} and including all subsequent activity at the same
+     * address.
+     *
+     * @param curLocalIdx Current index in locals
+     * @return new value for {@code curLocalIdx}
+     * @throws IOException
+     */
+    private int emitLocalsAtAddress(int curLocalIdx)
+            throws IOException {
+        int sz = locals.size();
+
+        // TODO: Don't emit ends implied by starts.
+
+        while ((curLocalIdx < sz)
+                && (locals.get(curLocalIdx).getAddress() == address)) {
+            LocalList.Entry entry = locals.get(curLocalIdx++);
+            int reg = entry.getRegister();
+            LocalList.Entry prevEntry = lastEntryForReg[reg];
+
+            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] = entry;
+
+            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 (prevEntry.isStart()) {
+                        /*
+                         * We should never be handed a start when a
+                         * a matching local is already active.
+                         */
+                        throw new RuntimeException("shouldn't happen");
+                    }
+                    emitLocalRestart(entry);
+                } else {
+                    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 (entry.getDisposition()
+                        != LocalList.Disposition.END_REPLACED) {
+                    emitLocalEnd(entry);
+                }
+            }
+        }
+
+        return curLocalIdx;
+    }
+
+    /**
+     * Emits all positions that occur at the current {@code address}
+     *
+     * @param curPositionIdx Current index in sortedPositions
+     * @param sortedPositions positions, sorted by ascending address
+     * @return new value for {@code curPositionIdx}
+     * @throws IOException
+     */
+    private int emitPositionsAtAddress(int curPositionIdx,
+            ArrayList<PositionList.Entry> sortedPositions)
+            throws IOException {
+        int positionsSz = sortedPositions.size();
+        while ((curPositionIdx < positionsSz)
+                && (sortedPositions.get(curPositionIdx).getAddress()
+                        == address)) {
+            emitPosition(sortedPositions.get(curPositionIdx++));
+        }
+        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"
+     * @throws IOException
+     */
+    private void emitHeader(ArrayList<PositionList.Entry> sortedPositions,
+            ArrayList<LocalList.Entry> methodArgs) throws IOException {
+        boolean annotate = (annotateTo != null) || (debugPrint != null);
+        int mark = output.getCursor();
+
+        // Start by initializing the line number register.
+        if (sortedPositions.size() > 0) {
+            PositionList.Entry entry = sortedPositions.get(0);
+            line = entry.getPosition().getLine();
+        }
+        output.writeUnsignedLeb128(line);
+
+        if (annotate) {
+            annotate(output.getCursor() - mark, "line_start: " + line);
+        }
+
+        int curParam = getParamBase();
+        // paramTypes will not include 'this'
+        StdTypeList paramTypes = desc.getParameterTypes();
+        int szParamTypes = paramTypes.size();
+
+        /*
+         * Initialize lastEntryForReg to have an initial
+         * entry for the 'this' pointer.
+         */
+        if (!isStatic) {
+            for (LocalList.Entry arg : methodArgs) {
+                if (curParam == arg.getRegister()) {
+                    lastEntryForReg[curParam] = arg;
+                    break;
+                }
+            }
+            curParam++;
+        }
+
+        // Write out the number of parameter entries that will follow.
+        mark = output.getCursor();
+        output.writeUnsignedLeb128(szParamTypes);
+
+        if (annotate) {
+            annotate(output.getCursor() - mark,
+                    String.format("parameters_size: %04x", szParamTypes));
+        }
+
+        /*
+         * Then emit the string indicies of all the method parameters.
+         * Note that 'this', if applicable, is excluded.
+         */
+        for (int i = 0; i < szParamTypes; i++) {
+            Type pt = paramTypes.get(i);
+            LocalList.Entry found = null;
+
+            mark = output.getCursor();
+
+            for (LocalList.Entry arg : methodArgs) {
+                if (curParam == arg.getRegister()) {
+                    found = arg;
+
+                    if (arg.getSignature() != null) {
+                        /*
+                         * Parameters with signatures will be re-emitted
+                         * in complete as LOCAL_START_EXTENDED's below.
+                         */
+                        emitStringIndex(null);
+                    } else {
+                        emitStringIndex(arg.getName());
+                    }
+                    lastEntryForReg[curParam] = arg;
+
+                    break;
+                }
+            }
+
+            if (found == null) {
+                /*
+                 * Emit a null symbol for "unnamed." This is common
+                 * for, e.g., synthesized methods and inner-class
+                 * this$0 arguments.
+                 */
+                emitStringIndex(null);
+            }
+
+            if (annotate) {
+                String parameterName
+                        = (found == null || found.getSignature() != null)
+                                ? "<unnamed>" : found.getName().toHuman();
+                annotate(output.getCursor() - mark,
+                        "parameter " + parameterName + " "
+                                + RegisterSpec.PREFIX + curParam);
+            }
+
+            curParam += pt.getCategory();
+        }
+
+        /*
+         * If anything emitted above has a type signature, emit it again as
+         * a LOCAL_RESTART_EXTENDED
+         */
+
+        for (LocalList.Entry arg : lastEntryForReg) {
+            if (arg == null) {
+                continue;
+            }
+
+            CstUtf8 signature = arg.getSignature();
+
+            if (signature != null) {
+                emitLocalStartExtended(arg);
+            }
+        }
+    }
+
+    /**
+     * Builds a list of position entries, sorted by ascending address.
+     *
+     * @return A sorted positions list
+     */
+    private ArrayList<PositionList.Entry> buildSortedPositions() {
+        int sz = (positions == null) ? 0 : positions.size();
+        ArrayList<PositionList.Entry> result = new ArrayList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            result.add(positions.get(i));
+        }
+
+        // Sort ascending by address.
+        Collections.sort (result, new Comparator<PositionList.Entry>() {
+            public int compare (PositionList.Entry a, PositionList.Entry b) {
+                return a.getAddress() - b.getAddress();
+            }
+
+            public boolean equals (Object obj) {
+               return obj == this;
+            }
+        });
+        return result;
+    }
+
+    /**
+     * Gets the register that begins the method's parameter range (including
+     * the 'this' parameter for non-static methods). The range continues until
+     * {@code regSize}
+     *
+     * @return register as noted above
+     */
+    private int getParamBase() {
+        return regSize
+                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
+    }
+
+    /**
+     * Extracts method arguments from a locals list. These will be collected
+     * from the input list and sorted by ascending register in the
+     * returned list.
+     *
+     * @return list of non-{@code this} method argument locals,
+     * sorted by ascending register
+     */
+    private ArrayList<LocalList.Entry> extractMethodArguments() {
+        ArrayList<LocalList.Entry> result
+                = new ArrayList(desc.getParameterTypes().size());
+        int argBase = getParamBase();
+        BitSet seen = new BitSet(regSize - argBase);
+        int sz = locals.size();
+
+        for (int i = 0; i < sz; i++) {
+            LocalList.Entry e = locals.get(i);
+            int reg = e.getRegister();
+
+            if (reg < argBase) {
+                continue;
+            }
+
+            // only the lowest-start-address entry is included.
+            if (seen.get(reg - argBase)) {
+                continue;
+            }
+
+            seen.set(reg - argBase);
+            result.add(e);
+        }
+
+        // Sort by ascending register.
+        Collections.sort(result, new Comparator<LocalList.Entry>() {
+            public int compare(LocalList.Entry a, LocalList.Entry b) {
+                return a.getRegister() - b.getRegister();
+            }
+
+            public boolean equals(Object obj) {
+               return obj == this;
+            }
+        });
+
+        return result;
+    }
+
+    /**
+     * Returns a string representation of this LocalList entry that is
+     * appropriate for emitting as an annotation.
+     *
+     * @param e {@code non-null;} entry
+     * @return {@code non-null;} annotation string
+     */
+    private String entryAnnotationString(LocalList.Entry e) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(RegisterSpec.PREFIX);
+        sb.append(e.getRegister());
+        sb.append(' ');
+
+        CstUtf8 name = e.getName();
+        if (name == null) {
+            sb.append("null");
+        } else {
+            sb.append(name.toHuman());
+        }
+        sb.append(' ');
+
+        CstType type = e.getType();
+        if (type == null) {
+            sb.append("null");
+        } else {
+            sb.append(type.toHuman());
+        }
+
+        CstUtf8 signature = e.getSignature();
+
+        if (signature != null) {
+            sb.append(' ');
+            sb.append(signature.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL}
+     * sequence.
+     *
+     * @param entry entry associated with this restart
+     * @throws IOException
+     */
+    private void emitLocalRestart(LocalList.Entry entry)
+            throws IOException {
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_RESTART_LOCAL);
+        emitUnsignedLeb128(entry.getRegister());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: +local restart %s",
+                            address, entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local restart");
+        }
+    }
+
+    /**
+     * Emits a string index as an unsigned LEB128. The actual value written
+     * is shifted by 1, so that the '0' value is reserved for "null". The
+     * null symbol is used in some cases by the parameter name list
+     * at the beginning of the sequence.
+     *
+     * @param string {@code null-ok;} string to emit
+     * @throws IOException
+     */
+    private void emitStringIndex(CstUtf8 string) throws IOException {
+        if ((string == null) || (file == null)) {
+            output.writeUnsignedLeb128(0);
+        } else {
+            output.writeUnsignedLeb128(
+                1 + file.getStringIds().indexOf(string));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emit string %s\n",
+                    string == null ? "<null>" : string.toQuoted());
+        }
+    }
+
+    /**
+     * 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 {@code null-ok;} type to emit
+     * @throws IOException
+     */
+    private void emitTypeIndex(CstType type) throws IOException {
+        if ((type == null) || (file == null)) {
+            output.writeUnsignedLeb128(0);
+        } else {
+            output.writeUnsignedLeb128(
+                1 + file.getTypeIds().indexOf(type));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emit type %s\n",
+                    type == null ? "<null>" : type.toHuman());
+        }
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or
+     * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
+     * DBG_START_LOCAL_EXTENDED} sequence.
+     *
+     * @param entry entry to emit
+     * @throws IOException
+     */
+    private void emitLocalStart(LocalList.Entry entry)
+        throws IOException {
+
+        if (entry.getSignature() != null) {
+            emitLocalStartExtended(entry);
+            return;
+        }
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_START_LOCAL);
+
+        emitUnsignedLeb128(entry.getRegister());
+        emitStringIndex(entry.getName());
+        emitTypeIndex(entry.getType());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: +local %s", address,
+                            entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local start");
+        }
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
+     * DBG_START_LOCAL_EXTENDED} sequence.
+     *
+     * @param entry entry to emit
+     * @throws IOException
+     */
+    private void emitLocalStartExtended(LocalList.Entry entry)
+        throws IOException {
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_START_LOCAL_EXTENDED);
+
+        emitUnsignedLeb128(entry.getRegister());
+        emitStringIndex(entry.getName());
+        emitTypeIndex(entry.getType());
+        emitStringIndex(entry.getSignature());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: +localx %s", address,
+                            entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local start");
+        }
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence.
+     *
+     * @param entry {@code entry non-null;} entry associated with end.
+     * @throws IOException
+     */
+    private void emitLocalEnd(LocalList.Entry entry)
+            throws IOException {
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_END_LOCAL);
+        output.writeUnsignedLeb128(entry.getRegister());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: -local %s", address,
+                            entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local end");
+        }
+    }
+
+    /**
+     * Emits the necessary byte sequences to emit the given position table
+     * entry. This will typically be a single special opcode, although
+     * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
+     *
+     * @param entry position entry to emit.
+     * @throws IOException
+     */
+    private void emitPosition(PositionList.Entry entry)
+            throws IOException {
+
+        SourcePosition pos = entry.getPosition();
+        int newLine = pos.getLine();
+        int newAddress = entry.getAddress();
+
+        int opcode;
+
+        int deltaLines = newLine - line;
+        int deltaAddress = newAddress - address;
+
+        if (deltaAddress < 0) {
+            throw new RuntimeException(
+                    "Position entries must be in ascending address order");
+        }
+
+        if ((deltaLines < DBG_LINE_BASE)
+                || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1))) {
+            emitAdvanceLine(deltaLines);
+            deltaLines = 0;
+        }
+
+        opcode = computeOpcode (deltaLines, deltaAddress);
+
+        if ((opcode & ~0xff) > 0) {
+            emitAdvancePc(deltaAddress);
+            deltaAddress = 0;
+            opcode = computeOpcode (deltaLines, deltaAddress);
+
+            if ((opcode & ~0xff) > 0) {
+                emitAdvanceLine(deltaLines);
+                deltaLines = 0;
+                opcode = computeOpcode (deltaLines, deltaAddress);
+            }
+        }
+
+        output.writeByte(opcode);
+
+        line += deltaLines;
+        address += deltaAddress;
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(1,
+                    String.format("%04x: line %d", address, line));
+        }
+    }
+
+    /**
+     * Computes a special opcode that will encode the given position change.
+     * If the return value is > 0xff, then the request cannot be fulfilled.
+     * Essentially the same as described in "DWARF Debugging Format Version 3"
+     * section 6.2.5.1.
+     *
+     * @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");
+        }
+
+        return (deltaLines - DBG_LINE_BASE)
+            + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL;
+    }
+
+    /**
+     * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE}
+     * sequence.
+     *
+     * @param deltaLines amount to change line number register by
+     * @throws IOException
+     */
+    private void emitAdvanceLine(int deltaLines) throws IOException {
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_ADVANCE_LINE);
+        output.writeSignedLeb128(deltaLines);
+        line += deltaLines;
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("line = %d", line));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emitting advance_line for %d\n", deltaLines);
+        }
+    }
+
+    /**
+     * Emits an  {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
+     * sequence.
+     *
+     * @param deltaAddress {@code >= 0;} amount to change program counter by
+     * @throws IOException
+     */
+    private void emitAdvancePc(int deltaAddress) throws IOException {
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_ADVANCE_PC);
+        output.writeUnsignedLeb128(deltaAddress);
+        address += deltaAddress;
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: advance pc", address));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emitting advance_pc for %d\n", deltaAddress);
+        }
+    }
+
+    /**
+     * Emits an unsigned LEB128 value.
+     *
+     * @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 {
+        // We'll never need the top end of the unsigned range anyway.
+        if (n < 0) {
+            throw new RuntimeException(
+                    "Signed value where unsigned required: " + n);
+        }
+
+        output.writeUnsignedLeb128(n);
+    }
+
+    /**
+     * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE}
+     * bytecode.
+     */
+    private void emitEndSequence() {
+        output.writeByte(DBG_END_SEQUENCE);
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(1, "end sequence");
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/DebugInfoItem.java b/dexgen/src/com/android/dexgen/dex/file/DebugInfoItem.java
new file mode 100644
index 0000000..82ad444
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/DebugInfoItem.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.code.DalvCode;
+import com.android.dexgen.dex.code.DalvInsnList;
+import com.android.dexgen.dex.code.LocalList;
+import com.android.dexgen.dex.code.PositionList;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+
+import java.io.PrintWriter;
+
+public class DebugInfoItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 1;
+
+    private static final boolean ENABLE_ENCODER_SELF_CHECK = false;
+
+    /** {@code non-null;} the code this item represents */
+    private final DalvCode code;
+
+    private byte[] encoded;
+
+    private final boolean isStatic;
+    private final CstMethodRef ref;
+
+    public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) {
+        // We don't know the write size yet.
+        super (ALIGNMENT, -1);
+
+        if (code == null) {
+            throw new NullPointerException("code == null");
+        }
+
+        this.code = code;
+        this.isStatic = isStatic;
+        this.ref = ref;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_DEBUG_INFO_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // No contents to add.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        try {
+            encoded = encode(addedTo.getFile(), null, null, null, false);
+            setWriteSize(encoded.length);
+        } catch (RuntimeException ex) {
+            throw ExceptionWithContext.withContext(ex,
+                    "...while placing debug info for " + ref.toHuman());
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /**
+     * Writes annotations for the elements of this list, as
+     * zero-length. This is meant to be used for dumping this instance
+     * directly after a code dump (with the real local list actually
+     * existing elsewhere in the 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);
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     */
+    public void debugPrint(PrintWriter out, String prefix) {
+        encode(null, prefix, out, null, false);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        if (out.annotates()) {
+            /*
+             * Re-run the encoder to generate the annotations,
+             * but write the bits from the original encode
+             */
+
+            out.annotate(offsetString() + " debug info");
+            encode(file, null, null, out, true);
+        }
+
+        out.write(encoded);
+    }
+
+    /**
+     * Performs debug info encoding.
+     *
+     * @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 {@code null-ok;} if specified, where annotations should go
+     * @param consume whether to claim to have consumed output for
+     * {@code out}
+     * @return {@code non-null;} the encoded array
+     */
+    private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint,
+            AnnotatedOutput out, boolean consume) {
+        byte[] result = encode0(file, prefix, debugPrint, out, consume);
+
+        if (ENABLE_ENCODER_SELF_CHECK && (file != null)) {
+            try {
+                DebugInfoDecoder.validateEncode(result, file, ref, code,
+                        isStatic);
+            } catch (RuntimeException ex) {
+                // Reconvert, annotating to System.err.
+                encode0(file, "", new PrintWriter(System.err, true), null,
+                        false);
+                throw ex;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #encode} to do most of the work.
+     *
+     * @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 {@code null-ok;} if specified, where annotations should go
+     * @param consume whether to claim to have consumed output for
+     * {@code out}
+     * @return {@code non-null;} the encoded array
+     */
+    private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint,
+            AnnotatedOutput out, boolean consume) {
+        PositionList positions = code.getPositions();
+        LocalList locals = code.getLocals();
+        DalvInsnList insns = code.getInsns();
+        int codeSize = insns.codeSize();
+        int regSize = insns.getRegistersSize();
+
+        DebugInfoEncoder encoder =
+            new DebugInfoEncoder(positions, locals,
+                    file, codeSize, regSize, isStatic, ref);
+
+        byte[] result;
+
+        if ((debugPrint == null) && (out == null)) {
+            result = encoder.convert();
+        } else {
+            result = encoder.convertAndAnnotate(prefix, debugPrint, out,
+                    consume);
+        }
+
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/DexFile.java b/dexgen/src/com/android/dexgen/dex/file/DexFile.java
new file mode 100644
index 0000000..e92aa10
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/DexFile.java
@@ -0,0 +1,646 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.file.MixedItemSection.SortType;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstBaseMethodRef;
+import com.android.dexgen.rop.cst.CstEnumRef;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.ByteArrayAnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.zip.Adler32;
+
+/**
+ * Representation of an entire {@code .dex} (Dalvik EXecutable)
+ * file, which itself consists of a set of Dalvik classes.
+ */
+public final class DexFile {
+    /** {@code non-null;} word data section */
+    private final MixedItemSection wordData;
+
+    /**
+     * {@code non-null;} type lists section. This is word data, but separating
+     * it from {@link #wordData} helps break what would otherwise be a
+     * circular dependency between the that and {@link #protoIds}.
+     */
+    private final MixedItemSection typeLists;
+
+    /**
+     * {@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;
+
+    /** {@code non-null;} string data section */
+    private final MixedItemSection stringData;
+
+    /** {@code non-null;} string identifiers section */
+    private final StringIdsSection stringIds;
+
+    /** {@code non-null;} type identifiers section */
+    private final TypeIdsSection typeIds;
+
+    /** {@code non-null;} prototype identifiers section */
+    private final ProtoIdsSection protoIds;
+
+    /** {@code non-null;} field identifiers section */
+    private final FieldIdsSection fieldIds;
+
+    /** {@code non-null;} method identifiers section */
+    private final MethodIdsSection methodIds;
+
+    /** {@code non-null;} class definitions section */
+    private final ClassDefsSection classDefs;
+
+    /** {@code non-null;} class data section */
+    private final MixedItemSection classData;
+
+    /** {@code non-null;} byte data section */
+    private final MixedItemSection byteData;
+
+    /** {@code non-null;} file header */
+    private final HeaderSection header;
+
+    /**
+     * {@code non-null;} array of sections in the order they will appear in the
+     * final output file
+     */
+    private final Section[] sections;
+
+    /** {@code >= -1;} total file size or {@code -1} if unknown */
+    private int fileSize;
+
+    /** {@code >= 40;} maximum width of the file dump */
+    private int dumpWidth;
+
+    /**
+     * Constructs an instance. It is initially empty.
+     */
+    public DexFile() {
+        header = new HeaderSection(this);
+        typeLists = new MixedItemSection(null, this, 4, SortType.NONE);
+        wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE);
+        stringData =
+            new MixedItemSection("string_data", this, 1, SortType.INSTANCE);
+        classData = new MixedItemSection(null, this, 1, SortType.NONE);
+        byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE);
+        stringIds = new StringIdsSection(this);
+        typeIds = new TypeIdsSection(this);
+        protoIds = new ProtoIdsSection(this);
+        fieldIds = new FieldIdsSection(this);
+        methodIds = new MethodIdsSection(this);
+        classDefs = new ClassDefsSection(this);
+        map = new MixedItemSection("map", this, 4, SortType.NONE);
+
+        /*
+         * This is the list of sections in the order they appear in
+         * the final output.
+         */
+        sections = new Section[] {
+            header, stringIds, typeIds, protoIds, fieldIds, methodIds,
+            classDefs, wordData, typeLists, stringData, byteData,
+            classData, map };
+
+        fileSize = -1;
+        dumpWidth = 79;
+    }
+
+    /**
+     * Adds a class to this instance. It is illegal to attempt to add more
+     * than one class with the same name.
+     *
+     * @param clazz {@code non-null;} the class to add
+     */
+    public void add(ClassDefItem clazz) {
+        classDefs.add(clazz);
+    }
+
+    /**
+     * Gets the class definition with the given name, if any.
+     *
+     * @param name {@code non-null;} the class name to look for
+     * @return {@code null-ok;} the class with the given name, or {@code null}
+     * if there is no such class
+     */
+    public ClassDefItem getClassOrNull(String name) {
+        try {
+            Type type = Type.internClassName(name);
+            return (ClassDefItem) classDefs.get(new CstType(type));
+        } catch (IllegalArgumentException ex) {
+            // Translate exception, per contract.
+            return null;
+        }
+    }
+
+    /**
+     * Writes the contents of this instance as either a binary or a
+     * human-readable form, or both.
+     *
+     * @param out {@code null-ok;} where to write to
+     * @param humanOut {@code null-ok;} where to write human-oriented output to
+     * @param verbose whether to be verbose when writing human-oriented output
+     */
+    public void writeTo(OutputStream out, Writer humanOut, boolean verbose)
+        throws IOException {
+        boolean annotate = (humanOut != null);
+        ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
+
+        if (out != null) {
+            out.write(result.getArray());
+        }
+
+        if (annotate) {
+            result.writeAnnotationsTo(humanOut);
+        }
+    }
+
+    /**
+     * Returns the contents of this instance as a {@code .dex} file,
+     * in {@code byte[]} form.
+     *
+     * @param humanOut {@code null-ok;} where to write human-oriented output to
+     * @param verbose whether to be verbose when writing human-oriented output
+     * @return {@code non-null;} a {@code .dex} file for this instance
+     */
+    public byte[] toDex(Writer humanOut, boolean verbose)
+        throws IOException {
+        boolean annotate = (humanOut != null);
+        ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
+
+        if (annotate) {
+            result.writeAnnotationsTo(humanOut);
+        }
+
+        return result.getArray();
+    }
+
+    /**
+     * Sets the maximum width of the human-oriented dump of the instance.
+     *
+     * @param dumpWidth {@code >= 40;} the width
+     */
+    public void setDumpWidth(int dumpWidth) {
+        if (dumpWidth < 40) {
+            throw new IllegalArgumentException("dumpWidth < 40");
+        }
+
+        this.dumpWidth = dumpWidth;
+    }
+
+    /**
+     * Gets the total file size, if known.
+     *
+     * <p>This is package-scope in order to allow
+     * the {@link HeaderSection} to set itself up properly.</p>
+     *
+     * @return {@code >= 0;} the total file size
+     * @throws RuntimeException thrown if the file size is not yet known
+     */
+    /*package*/ int getFileSize() {
+        if (fileSize < 0) {
+            throw new RuntimeException("file size not yet known");
+        }
+
+        return fileSize;
+    }
+
+    /**
+     * Gets the string data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the string data section
+     */
+    /*package*/ MixedItemSection getStringData() {
+        return stringData;
+    }
+
+    /**
+     * Gets the word data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the word data section
+     */
+    /*package*/ MixedItemSection getWordData() {
+        return wordData;
+    }
+
+    /**
+     * Gets the type lists section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the word data section
+     */
+    /*package*/ MixedItemSection getTypeLists() {
+        return typeLists;
+    }
+
+    /**
+     * Gets the map section.
+     *
+     * <p>This is package-scope in order to allow the header section
+     * to query it.</p>
+     *
+     * @return {@code non-null;} the map section
+     */
+    /*package*/ MixedItemSection getMap() {
+        return map;
+    }
+
+    /**
+     * Gets the string identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the string identifiers section
+     */
+    /*package*/ StringIdsSection getStringIds() {
+        return stringIds;
+    }
+
+    /**
+     * Gets the class definitions section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the class definitions section
+     */
+    /*package*/ ClassDefsSection getClassDefs() {
+        return classDefs;
+    }
+
+    /**
+     * Gets the class data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the class data section
+     */
+    /*package*/ MixedItemSection getClassData() {
+        return classData;
+    }
+
+    /**
+     * Gets the type identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the class identifiers section
+     */
+    /*package*/ TypeIdsSection getTypeIds() {
+        return typeIds;
+    }
+
+    /**
+     * Gets the prototype identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the prototype identifiers section
+     */
+    /*package*/ ProtoIdsSection getProtoIds() {
+        return protoIds;
+    }
+
+    /**
+     * Gets the field identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the field identifiers section
+     */
+    /*package*/ FieldIdsSection getFieldIds() {
+        return fieldIds;
+    }
+
+    /**
+     * Gets the method identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the method identifiers section
+     */
+    /*package*/ MethodIdsSection getMethodIds() {
+        return methodIds;
+    }
+
+    /**
+     * Gets the byte data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the byte data section
+     */
+    /*package*/ MixedItemSection getByteData() {
+        return byteData;
+    }
+
+    /**
+     * Gets the first section of the file that is to be considered
+     * part of the data section.
+     *
+     * <p>This is package-scope in order to allow the header section
+     * to query it.</p>
+     *
+     * @return {@code non-null;} the section
+     */
+    /*package*/ Section getFirstDataSection() {
+        return wordData;
+    }
+
+    /**
+     * Gets the last section of the file that is to be considered
+     * part of the data section.
+     *
+     * <p>This is package-scope in order to allow the header section
+     * to query it.</p>
+     *
+     * @return {@code non-null;} the section
+     */
+    /*package*/ Section getLastDataSection() {
+        return map;
+    }
+
+    /**
+     * Interns the given constant in the appropriate section of this
+     * instance, or do nothing if the given constant isn't the sort
+     * that should be interned.
+     *
+     * @param cst {@code non-null;} constant to possibly intern
+     */
+    /*package*/ void internIfAppropriate(Constant cst) {
+        if (cst instanceof CstString) {
+            stringIds.intern((CstString) cst);
+        } else if (cst instanceof CstUtf8) {
+            stringIds.intern((CstUtf8) cst);
+        } else if (cst instanceof CstType) {
+            typeIds.intern((CstType) cst);
+        } else if (cst instanceof CstBaseMethodRef) {
+            methodIds.intern((CstBaseMethodRef) cst);
+        } else if (cst instanceof CstFieldRef) {
+            fieldIds.intern((CstFieldRef) cst);
+        } else if (cst instanceof CstEnumRef) {
+            fieldIds.intern(((CstEnumRef) cst).getFieldRef());
+        } else if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+    }
+
+    /**
+     * Gets the {@link IndexedItem} corresponding to the given constant,
+     * if it is a constant that has such a correspondence, or return
+     * {@code null} if it isn't such a constant. This will throw
+     * an exception if the given constant <i>should</i> have been found
+     * but wasn't.
+     *
+     * @param cst {@code non-null;} the constant to look up
+     * @return {@code null-ok;} its corresponding item, if it has a corresponding
+     * item, or {@code null} if it's not that sort of constant
+     */
+    /*package*/ IndexedItem findItemOrNull(Constant cst) {
+        IndexedItem item;
+
+        if (cst instanceof CstString) {
+            return stringIds.get(cst);
+        } else if (cst instanceof CstType) {
+            return typeIds.get(cst);
+        } else if (cst instanceof CstBaseMethodRef) {
+            return methodIds.get(cst);
+        } else if (cst instanceof CstFieldRef) {
+            return fieldIds.get(cst);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the contents of this instance as a {@code .dex} file,
+     * in a {@link ByteArrayAnnotatedOutput} instance.
+     *
+     * @param annotate whether or not to keep annotations
+     * @param verbose if annotating, whether to be verbose
+     * @return {@code non-null;} a {@code .dex} file for this instance
+     */
+    private ByteArrayAnnotatedOutput toDex0(boolean annotate,
+            boolean verbose) {
+        /*
+         * The following is ordered so that the prepare() calls which
+         * add items happen before the calls to the sections that get
+         * added to.
+         */
+
+        classDefs.prepare();
+        classData.prepare();
+        wordData.prepare();
+        byteData.prepare();
+        methodIds.prepare();
+        fieldIds.prepare();
+        protoIds.prepare();
+        typeLists.prepare();
+        typeIds.prepare();
+        stringIds.prepare();
+        stringData.prepare();
+        header.prepare();
+
+        // Place the sections within the file.
+
+        int count = sections.length;
+        int offset = 0;
+
+        for (int i = 0; i < count; i++) {
+            Section one = sections[i];
+            int placedAt = one.setFileOffset(offset);
+            if (placedAt < offset) {
+                throw new RuntimeException("bogus placement for section " + i);
+            }
+
+            try {
+                if (one == map) {
+                    /*
+                     * Inform the map of all the sections, and add it
+                     * to the file. This can only be done after all
+                     * the other items have been sorted and placed.
+                     */
+                    MapItem.addMap(sections, map);
+                    map.prepare();
+                }
+
+                if (one instanceof MixedItemSection) {
+                    /*
+                     * Place the items of a MixedItemSection that just
+                     * got placed.
+                     */
+                    ((MixedItemSection) one).placeItems();
+                }
+
+                offset = placedAt + one.writeSize();
+            } catch (RuntimeException ex) {
+                throw ExceptionWithContext.withContext(ex,
+                        "...while writing section " + i);
+            }
+        }
+
+        // Write out all the sections.
+
+        fileSize = offset;
+        byte[] barr = new byte[fileSize];
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr);
+
+        if (annotate) {
+            out.enableAnnotations(dumpWidth, verbose);
+        }
+
+        for (int i = 0; i < count; i++) {
+            try {
+                Section one = sections[i];
+                int zeroCount = one.getFileOffset() - out.getCursor();
+                if (zeroCount < 0) {
+                    throw new ExceptionWithContext("excess write of " +
+                            (-zeroCount));
+                }
+                out.writeZeroes(one.getFileOffset() - out.getCursor());
+                one.writeTo(out);
+            } catch (RuntimeException ex) {
+                ExceptionWithContext ec;
+                if (ex instanceof ExceptionWithContext) {
+                    ec = (ExceptionWithContext) ex;
+                } else {
+                    ec = new ExceptionWithContext(ex);
+                }
+                ec.addContext("...while writing section " + i);
+                throw ec;
+            }
+        }
+
+        if (out.getCursor() != fileSize) {
+            throw new RuntimeException("foreshortened write");
+        }
+
+        // Perform final bookkeeping.
+
+        calcSignature(barr);
+        calcChecksum(barr);
+
+        if (annotate) {
+            wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM,
+                    "\nmethod code index:\n\n");
+            getStatistics().writeAnnotation(out);
+            out.finishAnnotating();
+        }
+
+        return out;
+    }
+
+    /**
+     * Generates and returns statistics for all the items in the file.
+     *
+     * @return {@code non-null;} the statistics
+     */
+    public Statistics getStatistics() {
+        Statistics stats = new Statistics();
+
+        for (Section s : sections) {
+            stats.addAll(s);
+        }
+
+        return stats;
+    }
+
+    /**
+     * Calculates the signature for the {@code .dex} file in the
+     * given array, and modify the array to contain it.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     */
+    private static void calcSignature(byte[] bytes) {
+        MessageDigest md;
+
+        try {
+            md = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException ex) {
+            throw new RuntimeException(ex);
+        }
+
+        md.update(bytes, 32, bytes.length - 32);
+
+        try {
+            int amt = md.digest(bytes, 12, 20);
+            if (amt != 20) {
+                throw new RuntimeException("unexpected digest write: " + amt +
+                                           " bytes");
+            }
+        } catch (DigestException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Calculates the checksum for the {@code .dex} file in the
+     * given array, and modify the array to contain it.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     */
+    private static void calcChecksum(byte[] bytes) {
+        Adler32 a32 = new Adler32();
+
+        a32.update(bytes, 12, bytes.length - 12);
+
+        int sum = (int) a32.getValue();
+
+        bytes[8]  = (byte) sum;
+        bytes[9]  = (byte) (sum >> 8);
+        bytes[10] = (byte) (sum >> 16);
+        bytes[11] = (byte) (sum >> 24);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/EncodedArrayItem.java b/dexgen/src/com/android/dexgen/dex/file/EncodedArrayItem.java
new file mode 100644
index 0000000..cef2375
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/EncodedArrayItem.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotation;
+import com.android.dexgen.rop.annotation.AnnotationVisibility;
+import com.android.dexgen.rop.annotation.NameValuePair;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstAnnotation;
+import com.android.dexgen.rop.cst.CstArray;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ByteArrayAnnotatedOutput;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Encoded array of constant values.
+ */
+public final class EncodedArrayItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 1;
+
+    /** {@code non-null;} the array to represent */
+    private final CstArray array;
+
+    /**
+     * {@code null-ok;} encoded form, ready for writing to a file; set during
+     * {@link #place0}
+     */
+    private byte[] encodedForm;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param array {@code non-null;} array to represent
+     */
+    public EncodedArrayItem(CstArray array) {
+        /*
+         * The write size isn't known up-front because (the variable-lengthed)
+         * leb128 type is used to represent some things.
+         */
+        super(ALIGNMENT, -1);
+
+        if (array == null) {
+            throw new NullPointerException("array == null");
+        }
+
+        this.array = array;
+        this.encodedForm = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ENCODED_ARRAY_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return array.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        EncodedArrayItem otherArray = (EncodedArrayItem) other;
+
+        return array.compareTo(otherArray.array);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return array.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        ValueEncoder.addContents(file, array);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+        ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
+
+        encoder.writeArray(array, false);
+        encodedForm = out.toByteArray();
+        setWriteSize(encodedForm.length);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " encoded array");
+
+            /*
+             * The output is to be annotated, so redo the work previously
+             * done by place0(), except this time annotations will actually
+             * get emitted.
+             */
+            ValueEncoder encoder = new ValueEncoder(file, out);
+            encoder.writeArray(array, true);
+        } else {
+            out.write(encodedForm);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/EncodedField.java b/dexgen/src/com/android/dexgen/dex/file/EncodedField.java
new file mode 100644
index 0000000..5af2b1f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/EncodedField.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.code.AccessFlags;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.Leb128Utils;
+
+import java.io.PrintWriter;
+
+/**
+ * Representation of a field of a class, of any sort.
+ */
+public final class EncodedField extends EncodedMember
+        implements Comparable<EncodedField> {
+    /** {@code non-null;} constant for the field */
+    private final CstFieldRef field;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param field {@code non-null;} constant for the field
+     * @param accessFlags access flags
+     */
+    public EncodedField(CstFieldRef field, int accessFlags) {
+        super(accessFlags);
+
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        /*
+         * TODO: Maybe check accessFlags, at least for
+         * easily-checked stuff?
+         */
+
+        this.field = field;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return field.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof EncodedField)) {
+            return false;
+        }
+
+        return compareTo((EncodedField) other) == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> This compares the method constants only,
+     * ignoring any associated code, because it should never be the
+     * case that two different items with the same method constant
+     * ever appear in the same list (or same file, even).</p>
+     */
+    public int compareTo(EncodedField other) {
+        return field.compareTo(other.field);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(Hex.u2(getAccessFlags()));
+        sb.append(' ');
+        sb.append(field);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        FieldIdsSection fieldIds = file.getFieldIds();
+        fieldIds.intern(field);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public CstUtf8 getName() {
+        return field.getNat().getName();
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return field.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void debugPrint(PrintWriter out, boolean verbose) {
+        // TODO: Maybe put something better here?
+        out.println(toString());
+    }
+
+    /**
+     * Gets the constant for the field.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstFieldRef getRef() {
+        return field;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int encode(DexFile file, AnnotatedOutput out,
+            int lastIndex, int dumpSeq) {
+        int fieldIdx = file.getFieldIds().indexOf(field);
+        int diff = fieldIdx - lastIndex;
+        int accessFlags = getAccessFlags();
+
+        if (out.annotates()) {
+            out.annotate(0, String.format("  [%x] %s", dumpSeq,
+                            field.toHuman()));
+            out.annotate(Leb128Utils.unsignedLeb128Size(diff),
+                    "    field_idx:    " + Hex.u4(fieldIdx));
+            out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
+                    "    access_flags: " +
+                    AccessFlags.fieldString(accessFlags));
+        }
+
+        out.writeUnsignedLeb128(diff);
+        out.writeUnsignedLeb128(accessFlags);
+
+        return fieldIdx;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/EncodedMember.java b/dexgen/src/com/android/dexgen/dex/file/EncodedMember.java
new file mode 100644
index 0000000..6c31704
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/EncodedMember.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ToHuman;
+
+import java.io.PrintWriter;
+
+/**
+ * Representation of a member (field or method) of a class, for the
+ * purposes of encoding it inside a {@link ClassDataItem}.
+ */
+public abstract class EncodedMember implements ToHuman {
+    /** access flags */
+    private final int accessFlags;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param accessFlags access flags for the member
+     */
+    public EncodedMember(int accessFlags) {
+        this.accessFlags = accessFlags;
+    }
+
+    /**
+     * Gets the access flags.
+     *
+     * @return the access flags
+     */
+    public final int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /**
+     * Gets the name.
+     *
+     * @return {@code non-null;} the name
+     */
+    public abstract CstUtf8 getName();
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @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);
+
+    /**
+     * Populates a {@link DexFile} with items from within this instance.
+     *
+     * @param file {@code non-null;} the file to populate
+     */
+    public abstract void addContents(DexFile file);
+
+    /**
+     * Encodes this instance to the given output.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     * @param lastIndex {@code >= 0;} the previous member index value encoded, or
+     * {@code 0} if this is the first element to encode
+     * @param dumpSeq {@code >= 0;} sequence number of this instance for
+     * annotation purposes
+     * @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/dexgen/src/com/android/dexgen/dex/file/EncodedMethod.java b/dexgen/src/com/android/dexgen/dex/file/EncodedMethod.java
new file mode 100644
index 0000000..a35ca2c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/EncodedMethod.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.dex.code.DalvCode;
+import com.android.dexgen.rop.code.AccessFlags;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.Leb128Utils;
+
+import java.io.PrintWriter;
+
+/**
+ * Class that representats a method of a class.
+ */
+public final class EncodedMethod extends EncodedMember
+        implements Comparable<EncodedMethod> {
+    /** {@code non-null;} constant for the method */
+    private final CstMethodRef method;
+
+    /**
+     * {@code null-ok;} code for the method, if the method is neither
+     * {@code abstract} nor {@code native}
+     */
+    private final CodeItem code;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} constant for the method
+     * @param accessFlags access flags
+     * @param code {@code null-ok;} code for the method, if it is neither
+     * {@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,
+            DalvCode code, TypeList throwsList) {
+        super(accessFlags);
+
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        this.method = method;
+
+        if (code == null) {
+            this.code = null;
+        } else {
+            boolean isStatic = (accessFlags & AccessFlags.ACC_STATIC) != 0;
+            this.code = new CodeItem(method, code, isStatic, throwsList);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof EncodedMethod)) {
+            return false;
+        }
+
+        return compareTo((EncodedMethod) other) == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> This compares the method constants only,
+     * ignoring any associated code, because it should never be the
+     * case that two different items with the same method constant
+     * ever appear in the same list (or same file, even).</p>
+     */
+    public int compareTo(EncodedMethod other) {
+        return method.compareTo(other.method);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(Hex.u2(getAccessFlags()));
+        sb.append(' ');
+        sb.append(method);
+
+        if (code != null) {
+            sb.append(' ');
+            sb.append(code);
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        MethodIdsSection methodIds = file.getMethodIds();
+        MixedItemSection wordData = file.getWordData();
+
+        methodIds.intern(method);
+
+        if (code != null) {
+            wordData.add(code);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public final String toHuman() {
+        return method.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final CstUtf8 getName() {
+        return method.getNat().getName();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void debugPrint(PrintWriter out, boolean verbose) {
+        if (code == null) {
+            out.println(getRef().toHuman() + ": abstract or native");
+        } else {
+            code.debugPrint(out, "  ", verbose);
+        }
+    }
+
+    /**
+     * Gets the constant for the method.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public final CstMethodRef getRef() {
+        return method;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int encode(DexFile file, AnnotatedOutput out,
+            int lastIndex, int dumpSeq) {
+        int methodIdx = file.getMethodIds().indexOf(method);
+        int diff = methodIdx - lastIndex;
+        int accessFlags = getAccessFlags();
+        int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code);
+        boolean hasCode = (codeOff != 0);
+        boolean shouldHaveCode = (accessFlags &
+                (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0;
+
+        /*
+         * Verify that code appears if and only if a method is
+         * declared to have it.
+         */
+        if (hasCode != shouldHaveCode) {
+            throw new UnsupportedOperationException(
+                    "code vs. access_flags mismatch");
+        }
+
+        if (out.annotates()) {
+            out.annotate(0, String.format("  [%x] %s", dumpSeq,
+                            method.toHuman()));
+            out.annotate(Leb128Utils.unsignedLeb128Size(diff),
+                    "    method_idx:   " + Hex.u4(methodIdx));
+            out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
+                    "    access_flags: " +
+                    AccessFlags.methodString(accessFlags));
+            out.annotate(Leb128Utils.unsignedLeb128Size(codeOff),
+                    "    code_off:     " + Hex.u4(codeOff));
+        }
+
+        out.writeUnsignedLeb128(diff);
+        out.writeUnsignedLeb128(accessFlags);
+        out.writeUnsignedLeb128(codeOff);
+
+        return methodIdx;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/FieldAnnotationStruct.java b/dexgen/src/com/android/dexgen/dex/file/FieldAnnotationStruct.java
new file mode 100644
index 0000000..95e4dbc
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/FieldAnnotationStruct.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotations;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * Association of a field and its annotations.
+ */
+public final class FieldAnnotationStruct
+        implements ToHuman, Comparable<FieldAnnotationStruct> {
+    /** {@code non-null;} the field in question */
+    private final CstFieldRef field;
+
+    /** {@code non-null;} the associated annotations */
+    private AnnotationSetItem annotations;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param field {@code non-null;} the field in question
+     * @param annotations {@code non-null;} the associated annotations
+     */
+    public FieldAnnotationStruct(CstFieldRef field,
+            AnnotationSetItem annotations) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.field = field;
+        this.annotations = annotations;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return field.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof FieldAnnotationStruct)) {
+            return false;
+        }
+
+        return field.equals(((FieldAnnotationStruct) other).field);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(FieldAnnotationStruct other) {
+        return field.compareTo(other.field);
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        FieldIdsSection fieldIds = file.getFieldIds();
+        MixedItemSection wordData = file.getWordData();
+
+        fieldIds.intern(field);
+        annotations = wordData.intern(annotations);
+    }
+
+    /** {@inheritDoc} */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int fieldIdx = file.getFieldIds().indexOf(field);
+        int annotationsOff = annotations.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, "    " + field.toHuman());
+            out.annotate(4, "      field_idx:       " + Hex.u4(fieldIdx));
+            out.annotate(4, "      annotations_off: " +
+                    Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(fieldIdx);
+        out.writeInt(annotationsOff);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return field.toHuman() + ": " + annotations;
+    }
+
+    /**
+     * Gets the field this item is for.
+     *
+     * @return {@code non-null;} the field
+     */
+    public CstFieldRef getField() {
+        return field;
+    }
+
+    /**
+     * Gets the associated annotations.
+     *
+     * @return {@code non-null;} the annotations
+     */
+    public Annotations getAnnotations() {
+        return annotations.getAnnotations();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/FieldIdItem.java b/dexgen/src/com/android/dexgen/dex/file/FieldIdItem.java
new file mode 100644
index 0000000..4d3721e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/FieldIdItem.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstFieldRef;
+
+/**
+ * Representation of a field reference inside a Dalvik file.
+ */
+public final class FieldIdItem extends MemberIdItem {
+    /**
+     * Constructs an instance.
+     *
+     * @param field {@code non-null;} the constant for the field
+     */
+    public FieldIdItem(CstFieldRef field) {
+        super(field);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_FIELD_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        super.addContents(file);
+
+        TypeIdsSection typeIds = file.getTypeIds();
+        typeIds.intern(getFieldRef().getType());
+    }
+
+    /**
+     * Gets the field constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstFieldRef getFieldRef() {
+        return (CstFieldRef) getRef();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getTypoidIdx(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        return typeIds.indexOf(getFieldRef().getType());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String getTypoidName() {
+        return "type_idx";
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/FieldIdsSection.java b/dexgen/src/com/android/dexgen/dex/file/FieldIdsSection.java
new file mode 100644
index 0000000..65177e4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/FieldIdsSection.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Field refs list section of a {@code .dex} file.
+ */
+public final class FieldIdsSection extends MemberIdsSection {
+    /**
+     * {@code non-null;} map from field constants to {@link
+     * FieldIdItem} instances
+     */
+    private final TreeMap<CstFieldRef, FieldIdItem> fieldIds;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public FieldIdsSection(DexFile file) {
+        super("field_ids", file);
+
+        fieldIds = new TreeMap<CstFieldRef, FieldIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return fieldIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        IndexedItem result = fieldIds.get((CstFieldRef) cst);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = fieldIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "field_ids_size:  " + Hex.u4(sz));
+            out.annotate(4, "field_ids_off:   " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param field {@code non-null;} the reference to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public FieldIdItem intern(CstFieldRef field) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        throwIfPrepared();
+
+        FieldIdItem result = fieldIds.get(field);
+
+        if (result == null) {
+            result = new FieldIdItem(field);
+            fieldIds.put(field, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given reference, which must have been added
+     * to this instance.
+     *
+     * @param ref {@code non-null;} the reference to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(CstFieldRef ref) {
+        if (ref == null) {
+            throw new NullPointerException("ref == null");
+        }
+
+        throwIfNotPrepared();
+
+        FieldIdItem item = fieldIds.get(ref);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return item.getIndex();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/HeaderItem.java b/dexgen/src/com/android/dexgen/dex/file/HeaderItem.java
new file mode 100644
index 0000000..ed04e25
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/HeaderItem.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * File header section of a {@code .dex} file.
+ */
+public final class HeaderItem extends IndexedItem {
+    /**
+     * {@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";
+
+    /** size of this section, in bytes */
+    private static final int HEADER_SIZE = 0x70;
+
+    /** the endianness tag */
+    private static final int ENDIAN_TAG = 0x12345678;
+
+    /**
+     * Constructs an instance.
+     */
+    public HeaderItem() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_HEADER_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return HEADER_SIZE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // Nothing to do here.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int mapOff = file.getMap().getFileOffset();
+        Section firstDataSection = file.getFirstDataSection();
+        Section lastDataSection = file.getLastDataSection();
+        int dataOff = firstDataSection.getFileOffset();
+        int dataSize = lastDataSection.getFileOffset() +
+            lastDataSection.writeSize() - dataOff;
+
+        if (out.annotates()) {
+            out.annotate(8, "magic: " + new CstUtf8(MAGIC).toQuoted());
+            out.annotate(4, "checksum");
+            out.annotate(20, "signature");
+            out.annotate(4, "file_size:       " +
+                         Hex.u4(file.getFileSize()));
+            out.annotate(4, "header_size:     " + Hex.u4(HEADER_SIZE));
+            out.annotate(4, "endian_tag:      " + Hex.u4(ENDIAN_TAG));
+            out.annotate(4, "link_size:       0");
+            out.annotate(4, "link_off:        0");
+            out.annotate(4, "map_off:         " + Hex.u4(mapOff));
+        }
+
+        // Write the magic number.
+        for (int i = 0; i < 8; i++) {
+            out.writeByte(MAGIC.charAt(i));
+        }
+
+        // Leave space for the checksum and signature.
+        out.writeZeroes(24);
+
+        out.writeInt(file.getFileSize());
+        out.writeInt(HEADER_SIZE);
+        out.writeInt(ENDIAN_TAG);
+
+        /*
+         * Write zeroes for the link size and data, as the output
+         * isn't a staticly linked file.
+         */
+        out.writeZeroes(8);
+
+        out.writeInt(mapOff);
+
+        // Write out each section's respective header part.
+        file.getStringIds().writeHeaderPart(out);
+        file.getTypeIds().writeHeaderPart(out);
+        file.getProtoIds().writeHeaderPart(out);
+        file.getFieldIds().writeHeaderPart(out);
+        file.getMethodIds().writeHeaderPart(out);
+        file.getClassDefs().writeHeaderPart(out);
+
+        if (out.annotates()) {
+            out.annotate(4, "data_size:       " + Hex.u4(dataSize));
+            out.annotate(4, "data_off:        " + Hex.u4(dataOff));
+        }
+
+        out.writeInt(dataSize);
+        out.writeInt(dataOff);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/HeaderSection.java b/dexgen/src/com/android/dexgen/dex/file/HeaderSection.java
new file mode 100644
index 0000000..967a90a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/HeaderSection.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * File header section of a {@code .dex} file.
+ */
+public final class HeaderSection extends UniformItemSection {
+    /** {@code non-null;} the list of the one item in the section */
+    private final List<HeaderItem> list;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public HeaderSection(DexFile file) {
+        super(null, file, 4);
+
+        HeaderItem item = new HeaderItem();
+        item.setIndex(0);
+
+        this.list = Collections.singletonList(item);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        // Nothing to do here.
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/IdItem.java b/dexgen/src/com/android/dexgen/dex/file/IdItem.java
new file mode 100644
index 0000000..0f8301e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/IdItem.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstType;
+
+/**
+ * Representation of a reference to an item inside a Dalvik file.
+ */
+public abstract class IdItem extends IndexedItem {
+    /**
+     * {@code non-null;} the type constant for the defining class of
+     * the reference
+     */
+    private final CstType type;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the type constant for the defining
+     * class of the reference
+     */
+    public IdItem(CstType type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        this.type = type;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        typeIds.intern(type);
+    }
+
+    /**
+     * Gets the type constant for the defining class of the
+     * reference.
+     *
+     * @return {@code non-null;} the type constant
+     */
+    public final CstType getDefiningClass() {
+        return type;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/IndexedItem.java b/dexgen/src/com/android/dexgen/dex/file/IndexedItem.java
new file mode 100644
index 0000000..cdc73cb
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/IndexedItem.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+/**
+ * An item in a Dalvik file which is referenced by index.
+ */
+public abstract class IndexedItem extends Item {
+    /** {@code >= -1;} assigned index of the item, or {@code -1} if not
+     * yet assigned */
+    private int index;
+
+    /**
+     * Constructs an instance. The index is initially unassigned.
+     */
+    public IndexedItem() {
+        index = -1;
+    }
+
+    /**
+     * Gets whether or not this instance has been assigned an index.
+     *
+     * @return {@code true} iff this instance has been assigned an index
+     */
+    public final boolean hasIndex() {
+        return (index >= 0);
+    }
+
+    /**
+     * Gets the item index.
+     *
+     * @return {@code >= 0;} the index
+     * @throws RuntimeException thrown if the item index is not yet assigned
+     */
+    public final int getIndex() {
+        if (index < 0) {
+            throw new RuntimeException("index not yet set");
+        }
+
+        return index;
+    }
+
+    /**
+     * Sets the item index. This method may only ever be called once
+     * per instance, and this will throw a {@code RuntimeException} if
+     * called a second (or subsequent) time.
+     *
+     * @param index {@code >= 0;} the item index
+     */
+    public final void setIndex(int index) {
+        if (this.index != -1) {
+            throw new RuntimeException("index already set");
+        }
+
+        this.index = index;
+    }
+
+    /**
+     * Gets the index of this item as a string, suitable for including in
+     * annotations.
+     *
+     * @return {@code non-null;} the index string
+     */
+    public final String indexString() {
+        return '[' + Integer.toHexString(index) + ']';
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/Item.java b/dexgen/src/com/android/dexgen/dex/file/Item.java
new file mode 100644
index 0000000..45cdc94
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/Item.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+
+/**
+ * Base class for any structurally-significant and (potentially)
+ * repeated piece of a Dalvik file.
+ */
+public abstract class Item {
+    /**
+     * Constructs an instance.
+     */
+    public Item() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Returns the item type for this instance.
+     *
+     * @return {@code non-null;} the item type
+     */
+    public abstract ItemType itemType();
+
+    /**
+     * Returns the human name for the particular type of item this
+     * instance is.
+     *
+     * @return {@code non-null;} the name
+     */
+    public final String typeName() {
+        return itemType().toHuman();
+    }
+
+    /**
+     * Gets the size of this instance when written, in bytes.
+     *
+     * @return {@code >= 0;} the write size
+     */
+    public abstract int writeSize();
+
+    /**
+     * Populates a {@link DexFile} with items from within this instance.
+     * This will <i>not</i> add an item to the file for this instance itself
+     * (which should have been done by whatever refers to this instance).
+     *
+     * <p><b>Note:</b> Subclasses must override this to do something
+     * appropriate.</p>
+     *
+     * @param file {@code non-null;} the file to populate
+     */
+    public abstract void addContents(DexFile file);
+
+    /**
+     * Writes the representation of this instance to the given data section,
+     * using the given {@link DexFile} to look things up as needed.
+     * If this instance keeps track of its offset, then this method will
+     * note the written offset and will also throw an exception if this
+     * instance has already been written.
+     *
+     * @param file {@code non-null;} the file to use for reference
+     * @param out {@code non-null;} where to write to
+     */
+    public abstract void writeTo(DexFile file, AnnotatedOutput out);
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ItemType.java b/dexgen/src/com/android/dexgen/dex/file/ItemType.java
new file mode 100644
index 0000000..b3e32d0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ItemType.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * Enumeration of all the top-level item types.
+ */
+public enum ItemType implements ToHuman {
+    TYPE_HEADER_ITEM(               0x0000, "header_item"),
+    TYPE_STRING_ID_ITEM(            0x0001, "string_id_item"),
+    TYPE_TYPE_ID_ITEM(              0x0002, "type_id_item"),
+    TYPE_PROTO_ID_ITEM(             0x0003, "proto_id_item"),
+    TYPE_FIELD_ID_ITEM(             0x0004, "field_id_item"),
+    TYPE_METHOD_ID_ITEM(            0x0005, "method_id_item"),
+    TYPE_CLASS_DEF_ITEM(            0x0006, "class_def_item"),
+    TYPE_MAP_LIST(                  0x1000, "map_list"),
+    TYPE_TYPE_LIST(                 0x1001, "type_list"),
+    TYPE_ANNOTATION_SET_REF_LIST(   0x1002, "annotation_set_ref_list"),
+    TYPE_ANNOTATION_SET_ITEM(       0x1003, "annotation_set_item"),
+    TYPE_CLASS_DATA_ITEM(           0x2000, "class_data_item"),
+    TYPE_CODE_ITEM(                 0x2001, "code_item"),
+    TYPE_STRING_DATA_ITEM(          0x2002, "string_data_item"),
+    TYPE_DEBUG_INFO_ITEM(           0x2003, "debug_info_item"),
+    TYPE_ANNOTATION_ITEM(           0x2004, "annotation_item"),
+    TYPE_ENCODED_ARRAY_ITEM(        0x2005, "encoded_array_item"),
+    TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"),
+    TYPE_MAP_ITEM(                  -1,     "map_item"),
+    TYPE_TYPE_ITEM(                 -1,     "type_item"),
+    TYPE_EXCEPTION_HANDLER_ITEM(    -1,     "exception_handler_item"),
+    TYPE_ANNOTATION_SET_REF_ITEM(   -1,     "annotation_set_ref_item");
+
+    /** value when represented in a {@link MapItem} */
+    private final int mapValue;
+
+    /** {@code non-null;} name of the type */
+    private final String typeName;
+
+    /** {@code non-null;} the short human name */
+    private final String humanName;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param mapValue value when represented in a {@link MapItem}
+     * @param typeName {@code non-null;} name of the type
+     */
+    private ItemType(int mapValue, String typeName) {
+        this.mapValue = mapValue;
+        this.typeName = typeName;
+
+        // Make the human name.
+        String human = typeName;
+        if (human.endsWith("_item")) {
+            human = human.substring(0, human.length() - 5);
+        }
+        this.humanName = human.replace('_', ' ');
+    }
+
+    /**
+     * Gets the map value.
+     *
+     * @return the map value
+     */
+    public int getMapValue() {
+        return mapValue;
+    }
+
+    /**
+     * Gets the type name.
+     *
+     * @return {@code non-null;} the type name
+     */
+    public String getTypeName() {
+        return typeName;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return humanName;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MapItem.java b/dexgen/src/com/android/dexgen/dex/file/MapItem.java
new file mode 100644
index 0000000..02472d4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MapItem.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.ArrayList;
+
+/**
+ * Class that represents a map item.
+ */
+public final class MapItem extends OffsettedItem {
+    /** file alignment of this class, in bytes */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of this class, in bytes: three {@code uint}s */
+    private static final int WRITE_SIZE = (4 * 3);
+
+    /** {@code non-null;} item type this instance covers */
+    private final ItemType type;
+
+    /** {@code non-null;} section this instance covers */
+    private final Section section;
+
+    /**
+     * {@code null-ok;} first item covered or {@code null} if this is
+     * a self-reference
+     */
+    private final Item firstItem;
+
+    /**
+     * {@code null-ok;} last item covered or {@code null} if this is
+     * a self-reference
+     */
+    private final Item lastItem;
+
+    /**
+     * {@code > 0;} count of items covered; {@code 1} if this
+     * is a self-reference
+     */
+    private final int itemCount;
+
+    /**
+     * Constructs a list item with instances of this class representing
+     * the contents of the given array of sections, adding it to the
+     * given map section.
+     *
+     * @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,
+            MixedItemSection mapSection) {
+        if (sections == null) {
+            throw new NullPointerException("sections == null");
+        }
+
+        if (mapSection.items().size() != 0) {
+            throw new IllegalArgumentException(
+                    "mapSection.items().size() != 0");
+        }
+
+        ArrayList<MapItem> items = new ArrayList<MapItem>(50);
+
+        for (Section section : sections) {
+            ItemType currentType = null;
+            Item firstItem = null;
+            Item lastItem = null;
+            int count = 0;
+
+            for (Item item : section.items()) {
+                ItemType type = item.itemType();
+                if (type != currentType) {
+                    if (count != 0) {
+                        items.add(new MapItem(currentType, section,
+                                        firstItem, lastItem, count));
+                    }
+                    currentType = type;
+                    firstItem = item;
+                    count = 0;
+                }
+                lastItem = item;
+                count++;
+            }
+
+            if (count != 0) {
+                // Add a MapItem for the final items in the section.
+                items.add(new MapItem(currentType, section,
+                                firstItem, lastItem, count));
+            } else if (section == mapSection) {
+                // Add a MapItem for the self-referential section.
+                items.add(new MapItem(mapSection));
+            }
+        }
+
+        mapSection.add(
+                new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items));
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} item type this instance covers
+     * @param section {@code non-null;} section this instance covers
+     * @param firstItem {@code non-null;} first item covered
+     * @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) {
+        super(ALIGNMENT, WRITE_SIZE);
+
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (section == null) {
+            throw new NullPointerException("section == null");
+        }
+
+        if (firstItem == null) {
+            throw new NullPointerException("firstItem == null");
+        }
+
+        if (lastItem == null) {
+            throw new NullPointerException("lastItem == null");
+        }
+
+        if (itemCount <= 0) {
+            throw new IllegalArgumentException("itemCount <= 0");
+        }
+
+        this.type = type;
+        this.section = section;
+        this.firstItem = firstItem;
+        this.lastItem = lastItem;
+        this.itemCount = itemCount;
+    }
+
+    /**
+     * Constructs a self-referential instance. This instance is meant to
+     * represent the section containing the {@code map_list}.
+     *
+     * @param section {@code non-null;} section this instance covers
+     */
+    private MapItem(Section section) {
+        super(ALIGNMENT, WRITE_SIZE);
+
+        if (section == null) {
+            throw new NullPointerException("section == null");
+        }
+
+        this.type = ItemType.TYPE_MAP_LIST;
+        this.section = section;
+        this.firstItem = null;
+        this.lastItem = null;
+        this.itemCount = 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_MAP_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(section.toString());
+        sb.append(' ');
+        sb.append(type.toHuman());
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // We have nothing to add.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toHuman() {
+        return toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        int value = type.getMapValue();
+        int offset;
+
+        if (firstItem == null) {
+            offset = section.getFileOffset();
+        } else {
+            offset = section.getAbsoluteItemOffset(firstItem);
+        }
+
+        if (out.annotates()) {
+            out.annotate(0, offsetString() + ' ' + type.getTypeName() +
+                    " map");
+            out.annotate(2, "  type:   " + Hex.u2(value) + " // " +
+                    type.toString());
+            out.annotate(2, "  unused: 0");
+            out.annotate(4, "  size:   " + Hex.u4(itemCount));
+            out.annotate(4, "  offset: " + Hex.u4(offset));
+        }
+
+        out.writeShort(value);
+        out.writeShort(0); // unused
+        out.writeInt(itemCount);
+        out.writeInt(offset);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MemberIdItem.java b/dexgen/src/com/android/dexgen/dex/file/MemberIdItem.java
new file mode 100644
index 0000000..d638f07
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MemberIdItem.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstMemberRef;
+import com.android.dexgen.rop.cst.CstNat;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Representation of a member (field or method) reference inside a
+ * Dalvik file.
+ */
+public abstract class MemberIdItem extends IdItem {
+    /** size of instances when written out to a file, in bytes */
+    public static final int WRITE_SIZE = 8;
+
+    /** {@code non-null;} the constant for the member */
+    private final CstMemberRef cst;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cst {@code non-null;} the constant for the member
+     */
+    public MemberIdItem(CstMemberRef cst) {
+        super(cst.getDefiningClass());
+
+        this.cst = cst;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return WRITE_SIZE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        super.addContents(file);
+
+        StringIdsSection stringIds = file.getStringIds();
+        stringIds.intern(getRef().getNat().getName());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(DexFile file, AnnotatedOutput out) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        StringIdsSection stringIds = file.getStringIds();
+        CstNat nat = cst.getNat();
+        int classIdx = typeIds.indexOf(getDefiningClass());
+        int nameIdx = stringIds.indexOf(nat.getName());
+        int typoidIdx = getTypoidIdx(file);
+
+        if (out.annotates()) {
+            out.annotate(0, indexString() + ' ' + cst.toHuman());
+            out.annotate(2, "  class_idx: " + Hex.u2(classIdx));
+            out.annotate(2, String.format("  %-10s %s", getTypoidName() + ':',
+                            Hex.u2(typoidIdx)));
+            out.annotate(4, "  name_idx:  " + Hex.u4(nameIdx));
+        }
+
+        out.writeShort(classIdx);
+        out.writeShort(typoidIdx);
+        out.writeInt(nameIdx);
+    }
+
+    /**
+     * Returns the index of the type-like thing associated with
+     * this item, in order that it may be written out. Subclasses must
+     * override this to get whatever it is they need to store.
+     *
+     * @param file {@code non-null;} the file being written
+     * @return the index in question
+     */
+    protected abstract int getTypoidIdx(DexFile file);
+
+    /**
+     * Returns the field name of the type-like thing associated with
+     * this item, for listing-generating purposes. Subclasses must override
+     * this.
+     *
+     * @return {@code non-null;} the name in question
+     */
+    protected abstract String getTypoidName();
+
+    /**
+     * Gets the member constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public final CstMemberRef getRef() {
+        return cst;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MemberIdsSection.java b/dexgen/src/com/android/dexgen/dex/file/MemberIdsSection.java
new file mode 100644
index 0000000..dcfca30
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MemberIdsSection.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.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 {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public MemberIdsSection(String name, DexFile file) {
+        super(name, file, 4);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (Object i : items()) {
+            ((MemberIdItem) i).setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MethodAnnotationStruct.java b/dexgen/src/com/android/dexgen/dex/file/MethodAnnotationStruct.java
new file mode 100644
index 0000000..e511f10
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MethodAnnotationStruct.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotations;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * Association of a method and its annotations.
+ */
+public final class MethodAnnotationStruct
+        implements ToHuman, Comparable<MethodAnnotationStruct> {
+    /** {@code non-null;} the method in question */
+    private final CstMethodRef method;
+
+    /** {@code non-null;} the associated annotations */
+    private AnnotationSetItem annotations;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method in question
+     * @param annotations {@code non-null;} the associated annotations
+     */
+    public MethodAnnotationStruct(CstMethodRef method,
+            AnnotationSetItem annotations) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.method = method;
+        this.annotations = annotations;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return method.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof MethodAnnotationStruct)) {
+            return false;
+        }
+
+        return method.equals(((MethodAnnotationStruct) other).method);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(MethodAnnotationStruct other) {
+        return method.compareTo(other.method);
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MethodIdsSection methodIds = file.getMethodIds();
+        MixedItemSection wordData = file.getWordData();
+
+        methodIds.intern(method);
+        annotations = wordData.intern(annotations);
+    }
+
+    /** {@inheritDoc} */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int methodIdx = file.getMethodIds().indexOf(method);
+        int annotationsOff = annotations.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, "    " + method.toHuman());
+            out.annotate(4, "      method_idx:      " + Hex.u4(methodIdx));
+            out.annotate(4, "      annotations_off: " +
+                    Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(methodIdx);
+        out.writeInt(annotationsOff);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return method.toHuman() + ": " + annotations;
+    }
+
+    /**
+     * Gets the method this item is for.
+     *
+     * @return {@code non-null;} the method
+     */
+    public CstMethodRef getMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the associated annotations.
+     *
+     * @return {@code non-null;} the annotations
+     */
+    public Annotations getAnnotations() {
+        return annotations.getAnnotations();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MethodIdItem.java b/dexgen/src/com/android/dexgen/dex/file/MethodIdItem.java
new file mode 100644
index 0000000..da14e19
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MethodIdItem.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstBaseMethodRef;
+
+/**
+ * Representation of a method reference inside a Dalvik file.
+ */
+public final class MethodIdItem extends MemberIdItem {
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the constant for the method
+     */
+    public MethodIdItem(CstBaseMethodRef method) {
+        super(method);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_METHOD_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        super.addContents(file);
+
+        ProtoIdsSection protoIds = file.getProtoIds();
+        protoIds.intern(getMethodRef().getPrototype());
+    }
+
+    /**
+     * Gets the method constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstBaseMethodRef getMethodRef() {
+        return (CstBaseMethodRef) getRef();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getTypoidIdx(DexFile file) {
+        ProtoIdsSection protoIds = file.getProtoIds();
+        return protoIds.indexOf(getMethodRef().getPrototype());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String getTypoidName() {
+        return "proto_idx";
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MethodIdsSection.java b/dexgen/src/com/android/dexgen/dex/file/MethodIdsSection.java
new file mode 100644
index 0000000..3a06af7
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MethodIdsSection.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstBaseMethodRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Method refs list section of a {@code .dex} file.
+ */
+public final class MethodIdsSection extends MemberIdsSection {
+    /**
+     * {@code non-null;} map from method constants to {@link
+     * MethodIdItem} instances
+     */
+    private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public MethodIdsSection(DexFile file) {
+        super("method_ids", file);
+
+        methodIds = new TreeMap<CstBaseMethodRef, MethodIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return methodIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        IndexedItem result = methodIds.get((CstBaseMethodRef) cst);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = methodIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "method_ids_size: " + Hex.u4(sz));
+            out.annotate(4, "method_ids_off:  " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param method {@code non-null;} the reference to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public MethodIdItem intern(CstBaseMethodRef method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        throwIfPrepared();
+
+        MethodIdItem result = methodIds.get(method);
+
+        if (result == null) {
+            result = new MethodIdItem(method);
+            methodIds.put(method, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given reference, which must have been added
+     * to this instance.
+     *
+     * @param ref {@code non-null;} the reference to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(CstBaseMethodRef ref) {
+        if (ref == null) {
+            throw new NullPointerException("ref == null");
+        }
+
+        throwIfNotPrepared();
+
+        MethodIdItem item = methodIds.get(ref);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return item.getIndex();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/MixedItemSection.java b/dexgen/src/com/android/dexgen/dex/file/MixedItemSection.java
new file mode 100644
index 0000000..2fda33b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/MixedItemSection.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+import com.android.dexgen.util.Hex;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.TreeMap;
+
+/**
+ * A section of a {@code .dex} file which consists of a sequence of
+ * {@link OffsettedItem} objects, which may each be of a different concrete
+ * class and/or size.
+ *
+ * <b>Note:</b> It is invalid for an item in an instance of this class to
+ * have a larger alignment requirement than the alignment of this instance.
+ */
+public final class MixedItemSection extends Section {
+    static enum SortType {
+        /** no sorting */
+        NONE,
+
+        /** sort by type only */
+        TYPE,
+
+        /** sort in class-major order, with instances sorted per-class */
+        INSTANCE;
+    };
+
+    /** {@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) {
+            ItemType type1 = item1.itemType();
+            ItemType type2 = item2.itemType();
+            return type1.compareTo(type2);
+        }
+    };
+
+    /** {@code non-null;} the items in this part */
+    private final ArrayList<OffsettedItem> items;
+
+    /** {@code non-null;} items that have been explicitly interned */
+    private final HashMap<OffsettedItem, OffsettedItem> interns;
+
+    /** {@code non-null;} how to sort the items */
+    private final SortType sort;
+
+    /**
+     * {@code >= -1;} the current size of this part, in bytes, or {@code -1}
+     * if not yet calculated
+     */
+    private int writeSize;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param name {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     * @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
+     */
+    public MixedItemSection(String name, DexFile file, int alignment,
+            SortType sort) {
+        super(name, file, alignment);
+
+        this.items = new ArrayList<OffsettedItem>(100);
+        this.interns = new HashMap<OffsettedItem, OffsettedItem>(100);
+        this.sort = sort;
+        this.writeSize = -1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return items;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        throwIfNotPrepared();
+        return writeSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int getAbsoluteItemOffset(Item item) {
+        OffsettedItem oi = (OffsettedItem) item;
+        return oi.getAbsoluteOffset();
+    }
+
+    /**
+     * Gets the size of this instance, in items.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        return items.size();
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        if (writeSize == -1) {
+            throw new RuntimeException("write size not yet set");
+        }
+
+        int sz = writeSize;
+        int offset = (sz == 0) ? 0 : getFileOffset();
+        String name = getName();
+
+        if (name == null) {
+            name = "<unnamed>";
+        }
+
+        int spaceCount = 15 - name.length();
+        char[] spaceArr = new char[spaceCount];
+        Arrays.fill(spaceArr, ' ');
+        String spaces = new String(spaceArr);
+
+        if (out.annotates()) {
+            out.annotate(4, name + "_size:" + spaces + Hex.u4(sz));
+            out.annotate(4, name + "_off: " + spaces + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Adds an item to this instance. This will in turn tell the given item
+     * that it has been added to this instance. It is invalid to add the
+     * same item to more than one instance, nor to add the same items
+     * multiple times to a single instance.
+     *
+     * @param item {@code non-null;} the item to add
+     */
+    public void add(OffsettedItem item) {
+        throwIfPrepared();
+
+        try {
+            if (item.getAlignment() > getAlignment()) {
+                throw new IllegalArgumentException(
+                        "incompatible item alignment");
+            }
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("item == null");
+        }
+
+        items.add(item);
+    }
+
+    /**
+     * Interns an item in this instance, returning the interned instance
+     * (which may not be the one passed in). This will add the item if no
+     * equal item has been added.
+     *
+     * @param item {@code non-null;} the item to intern
+     * @return {@code non-null;} the equivalent interned instance
+     */
+    public <T extends OffsettedItem> T intern(T item) {
+        throwIfPrepared();
+
+        OffsettedItem result = interns.get(item);
+
+        if (result != null) {
+            return (T) result;
+        }
+
+        add(item);
+        interns.put(item, item);
+        return item;
+    }
+
+    /**
+     * Gets an item which was previously interned.
+     *
+     * @param item {@code non-null;} the item to look for
+     * @return {@code non-null;} the equivalent already-interned instance
+     */
+    public <T extends OffsettedItem> T get(T item) {
+        throwIfNotPrepared();
+
+        OffsettedItem result = interns.get(item);
+
+        if (result != null) {
+            return (T) result;
+        }
+
+        throw new NoSuchElementException(item.toString());
+    }
+
+    /**
+     * Writes an index of contents of the items in this instance of the
+     * given type. If there are none, this writes nothing. If there are any,
+     * then the index is preceded by the given intro string.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param itemType {@code non-null;} the item type of interest
+     * @param intro {@code non-null;} the introductory string for non-empty indices
+     */
+    public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType,
+            String intro) {
+        throwIfNotPrepared();
+
+        TreeMap<String, OffsettedItem> index =
+            new TreeMap<String, OffsettedItem>();
+
+        for (OffsettedItem item : items) {
+            if (item.itemType() == itemType) {
+                String label = item.toHuman();
+                index.put(label, item);
+            }
+        }
+
+        if (index.size() == 0) {
+            return;
+        }
+
+        out.annotate(0, intro);
+
+        for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
+            String label = entry.getKey();
+            OffsettedItem item = entry.getValue();
+            out.annotate(0, item.offsetString() + ' ' + label + '\n');
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void prepare0() {
+        DexFile file = getFile();
+
+        /*
+         * It's okay for new items to be added as a result of an
+         * addContents() call; we just have to deal with the possibility.
+         */
+
+        int i = 0;
+        for (;;) {
+            int sz = items.size();
+            if (i >= sz) {
+                break;
+            }
+
+            for (/*i*/; i < sz; i++) {
+                OffsettedItem one = items.get(i);
+                one.addContents(file);
+            }
+        }
+    }
+
+    /**
+     * 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},
+     * 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.
+     */
+    public void placeItems() {
+        throwIfNotPrepared();
+
+        switch (sort) {
+            case INSTANCE: {
+                Collections.sort(items);
+                break;
+            }
+            case TYPE: {
+                Collections.sort(items, TYPE_SORTER);
+                break;
+            }
+        }
+
+        int sz = items.size();
+        int outAt = 0;
+        for (int i = 0; i < sz; i++) {
+            OffsettedItem one = items.get(i);
+            try {
+                int placedAt = one.place(this, outAt);
+
+                if (placedAt < outAt) {
+                    throw new RuntimeException("bogus place() result for " +
+                            one);
+                }
+
+                outAt = placedAt + one.writeSize();
+            } catch (RuntimeException ex) {
+                throw ExceptionWithContext.withContext(ex,
+                        "...while placing " + one);
+            }
+        }
+
+        writeSize = outAt;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        boolean first = true;
+        DexFile file = getFile();
+        int at = 0;
+
+        for (OffsettedItem one : items) {
+            if (annotates) {
+                if (first) {
+                    first = false;
+                } else {
+                    out.annotate(0, "\n");
+                }
+            }
+
+            int alignMask = one.getAlignment() - 1;
+            int writeAt = (at + alignMask) & ~alignMask;
+
+            if (at != writeAt) {
+                out.writeZeroes(writeAt - at);
+                at = writeAt;
+            }
+
+            one.writeTo(file, out);
+            at += one.writeSize();
+        }
+
+        if (at != writeSize) {
+            throw new RuntimeException("output size mismatch");
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/OffsettedItem.java b/dexgen/src/com/android/dexgen/dex/file/OffsettedItem.java
new file mode 100644
index 0000000..246f903
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/OffsettedItem.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ExceptionWithContext;
+
+/**
+ * An item in a Dalvik file which is referenced by absolute offset.
+ */
+public abstract class OffsettedItem extends Item
+        implements Comparable<OffsettedItem> {
+    /** {@code > 0;} alignment requirement */
+    private final int alignment;
+
+    /** {@code >= -1;} the size of this instance when written, in bytes, or
+     * {@code -1} if not yet known */
+    private int writeSize;
+
+    /**
+     * {@code null-ok;} section the item was added to, or {@code null} if
+     * not yet added
+     */
+    private Section addedTo;
+
+    /**
+     * {@code >= -1;} assigned offset of the item from the start of its section,
+     * or {@code -1} if not yet assigned
+     */
+    private int offset;
+
+    /**
+     * Gets the absolute offset of the given item, returning {@code 0}
+     * if handed {@code null}.
+     *
+     * @param item {@code null-ok;} the item in question
+     * @return {@code >= 0;} the item's absolute offset, or {@code 0}
+     * if {@code item == null}
+     */
+    public static int getAbsoluteOffsetOr0(OffsettedItem item) {
+        if (item == null) {
+            return 0;
+        }
+
+        return item.getAbsoluteOffset();
+    }
+
+    /**
+     * Constructs an instance. The offset is initially unassigned.
+     *
+     * @param alignment {@code > 0;} output alignment requirement; must be a
+     * power of 2
+     * @param writeSize {@code >= -1;} the size of this instance when written,
+     * in bytes, or {@code -1} if not immediately known
+     */
+    public OffsettedItem(int alignment, int writeSize) {
+        Section.validateAlignment(alignment);
+
+        if (writeSize < -1) {
+            throw new IllegalArgumentException("writeSize < -1");
+        }
+
+        this.alignment = alignment;
+        this.writeSize = writeSize;
+        this.addedTo = null;
+        this.offset = -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Comparisons for this class are defined to be type-major (if the
+     * types don't match then the objects are not equal), with
+     * {@link #compareTo0} deciding same-type comparisons.
+     */
+    @Override
+    public final boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        OffsettedItem otherItem = (OffsettedItem) other;
+        ItemType thisType = itemType();
+        ItemType otherType = otherItem.itemType();
+
+        if (thisType != otherType) {
+            return false;
+        }
+
+        return (compareTo0(otherItem) == 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Comparisons for this class are defined to be class-major (if the
+     * classes don't match then the objects are not equal), with
+     * {@link #compareTo0} deciding same-class comparisons.
+     */
+    public final int compareTo(OffsettedItem other) {
+        if (this == other) {
+            return 0;
+        }
+
+        ItemType thisType = itemType();
+        ItemType otherType = other.itemType();
+
+        if (thisType != otherType) {
+            return thisType.compareTo(otherType);
+        }
+
+        return compareTo0(other);
+    }
+
+    /**
+     * Sets the write size of this item. This may only be called once
+     * per instance, and only if the size was unknown upon instance
+     * creation.
+     *
+     * @param writeSize {@code > 0;} the write size, in bytes
+     */
+    public final void setWriteSize(int writeSize) {
+        if (writeSize < 0) {
+            throw new IllegalArgumentException("writeSize < 0");
+        }
+
+        if (this.writeSize >= 0) {
+            throw new UnsupportedOperationException("writeSize already set");
+        }
+
+        this.writeSize = writeSize;
+    }
+
+    /** {@inheritDoc}
+     *
+     * @throws UnsupportedOperationException thrown if the write size
+     * is not yet known
+     */
+    @Override
+    public final int writeSize() {
+        if (writeSize < 0) {
+            throw new UnsupportedOperationException("writeSize is unknown");
+        }
+
+        return writeSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(DexFile file, AnnotatedOutput out) {
+        out.alignTo(alignment);
+
+        try {
+            if (writeSize < 0) {
+                throw new UnsupportedOperationException(
+                        "writeSize is unknown");
+            }
+            out.assertCursor(getAbsoluteOffset());
+        } catch (RuntimeException ex) {
+            throw ExceptionWithContext.withContext(ex,
+                    "...while writing " + this);
+        }
+
+        writeTo0(file, out);
+    }
+
+    /**
+     * Gets the relative item offset. The offset is from the start of
+     * the section which the instance was written to.
+     *
+     * @return {@code >= 0;} the offset
+     * @throws RuntimeException thrown if the offset is not yet known
+     */
+    public final int getRelativeOffset() {
+        if (offset < 0) {
+            throw new RuntimeException("offset not yet known");
+        }
+
+        return offset;
+    }
+
+    /**
+     * Gets the absolute item offset. The offset is from the start of
+     * the file which the instance was written to.
+     *
+     * @return {@code >= 0;} the offset
+     * @throws RuntimeException thrown if the offset is not yet known
+     */
+    public final int getAbsoluteOffset() {
+        if (offset < 0) {
+            throw new RuntimeException("offset not yet known");
+        }
+
+        return addedTo.getAbsoluteOffset(offset);
+    }
+
+    /**
+     * Indicates that this item has been added to the given section at
+     * the given offset. It is only valid to call this method once per
+     * instance.
+     *
+     * @param addedTo {@code non-null;} the section this instance has
+     * been added to
+     * @param offset {@code >= 0;} the desired offset from the start of the
+     * section where this instance was placed
+     * @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) {
+        if (addedTo == null) {
+            throw new NullPointerException("addedTo == null");
+        }
+
+        if (offset < 0) {
+            throw new IllegalArgumentException("offset < 0");
+        }
+
+        if (this.addedTo != null) {
+            throw new RuntimeException("already written");
+        }
+
+        int mask = alignment - 1;
+        offset = (offset + mask) & ~mask;
+
+        this.addedTo = addedTo;
+        this.offset = offset;
+
+        place0(addedTo, offset);
+
+        return offset;
+    }
+
+    /**
+     * Gets the alignment requirement of this instance. An instance should
+     * only be written when so aligned.
+     *
+     * @return {@code > 0;} the alignment requirement; must be a power of 2
+     */
+    public final int getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Gets the absolute offset of this item as a string, suitable for
+     * including in annotations.
+     *
+     * @return {@code non-null;} the offset string
+     */
+    public final String offsetString() {
+        return '[' + Integer.toHexString(getAbsoluteOffset()) + ']';
+    }
+
+    /**
+     * Gets a short human-readable string representing this instance.
+     *
+     * @return {@code non-null;} the human form
+     */
+    public abstract String toHuman();
+
+    /**
+     * Compares this instance to another which is guaranteed to be of
+     * the same class. The default implementation of this method is to
+     * throw an exception (unsupported operation). If a particular
+     * class needs to actually sort, then it should override this
+     * method.
+     *
+     * @param other {@code non-null;} instance to compare to
+     * @return {@code -1}, {@code 0}, or {@code 1}, depending
+     * on the sort order of this instance and the other
+     */
+    protected int compareTo0(OffsettedItem other) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /**
+     * Does additional work required when placing an instance. The
+     * default implementation of this method is a no-op. If a
+     * particular class needs to do something special, then it should
+     * override this method. In particular, if this instance did not
+     * know its write size up-front, then this method is responsible
+     * for setting it.
+     *
+     * @param addedTo {@code non-null;} the section this instance has been added to
+     * @param offset {@code >= 0;} the offset from the start of the
+     * section where this instance was placed
+     */
+    protected void place0(Section addedTo, int offset) {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Performs the actual write of the contents of this instance to
+     * the given data section. This is called by {@link #writeTo},
+     * which will have taken care of ensuring alignment.
+     *
+     * @param file {@code non-null;} the file to use for reference
+     * @param out {@code non-null;} where to write to
+     */
+    protected abstract void writeTo0(DexFile file, AnnotatedOutput out);
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ParameterAnnotationStruct.java b/dexgen/src/com/android/dexgen/dex/file/ParameterAnnotationStruct.java
new file mode 100644
index 0000000..440da1c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ParameterAnnotationStruct.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotations;
+import com.android.dexgen.rop.annotation.AnnotationsList;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.ToHuman;
+
+import java.util.ArrayList;
+
+/**
+ * Association of a method and its parameter annotations.
+ */
+public final class ParameterAnnotationStruct
+        implements ToHuman, Comparable<ParameterAnnotationStruct> {
+    /** {@code non-null;} the method in question */
+    private final CstMethodRef method;
+
+    /** {@code non-null;} the associated annotations list */
+    private final AnnotationsList annotationsList;
+
+    /** {@code non-null;} the associated annotations list, as an item */
+    private final UniformListItem<AnnotationSetRefItem> annotationsItem;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method in question
+     * @param annotationsList {@code non-null;} the associated annotations list
+     */
+    public ParameterAnnotationStruct(CstMethodRef method,
+            AnnotationsList annotationsList) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (annotationsList == null) {
+            throw new NullPointerException("annotationsList == null");
+        }
+
+        this.method = method;
+        this.annotationsList = annotationsList;
+
+        /*
+         * Construct an item for the annotations list. TODO: This
+         * requires way too much copying; fix it.
+         */
+
+        int size = annotationsList.size();
+        ArrayList<AnnotationSetRefItem> arrayList = new
+            ArrayList<AnnotationSetRefItem>(size);
+
+        for (int i = 0; i < size; i++) {
+            Annotations annotations = annotationsList.get(i);
+            AnnotationSetItem item = new AnnotationSetItem(annotations);
+            arrayList.add(new AnnotationSetRefItem(item));
+        }
+
+        this.annotationsItem = new UniformListItem<AnnotationSetRefItem>(
+                ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList);
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return method.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof ParameterAnnotationStruct)) {
+            return false;
+        }
+
+        return method.equals(((ParameterAnnotationStruct) other).method);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(ParameterAnnotationStruct other) {
+        return method.compareTo(other.method);
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MethodIdsSection methodIds = file.getMethodIds();
+        MixedItemSection wordData = file.getWordData();
+
+        methodIds.intern(method);
+        wordData.add(annotationsItem);
+    }
+
+    /** {@inheritDoc} */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int methodIdx = file.getMethodIds().indexOf(method);
+        int annotationsOff = annotationsItem.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, "    " + method.toHuman());
+            out.annotate(4, "      method_idx:      " + Hex.u4(methodIdx));
+            out.annotate(4, "      annotations_off: " +
+                    Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(methodIdx);
+        out.writeInt(annotationsOff);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(method.toHuman());
+        sb.append(": ");
+
+        boolean first = true;
+        for (AnnotationSetRefItem item : annotationsItem.getItems()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(item.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the method this item is for.
+     *
+     * @return {@code non-null;} the method
+     */
+    public CstMethodRef getMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the associated annotations list.
+     *
+     * @return {@code non-null;} the annotations list
+     */
+    public AnnotationsList getAnnotationsList() {
+        return annotationsList;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ProtoIdItem.java b/dexgen/src/com/android/dexgen/dex/file/ProtoIdItem.java
new file mode 100644
index 0000000..ef48cd4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ProtoIdItem.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Prototype;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Representation of a method prototype reference inside a Dalvik file.
+ */
+public final class ProtoIdItem extends IndexedItem {
+    /** size of instances when written out to a file, in bytes */
+    public static final int WRITE_SIZE = 12;
+
+    /** {@code non-null;} the wrapped prototype */
+    private final Prototype prototype;
+
+    /** {@code non-null;} the short-form of the prototype */
+    private final CstUtf8 shortForm;
+
+    /**
+     * {@code null-ok;} the list of parameter types or {@code null} if this
+     * prototype has no parameters
+     */
+    private TypeListItem parameterTypes;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param prototype {@code non-null;} the constant for the prototype
+     */
+    public ProtoIdItem(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        this.prototype = prototype;
+        this.shortForm = makeShortForm(prototype);
+
+        StdTypeList parameters = prototype.getParameterTypes();
+        this.parameterTypes = (parameters.size() == 0) ? null
+            : new TypeListItem(parameters);
+    }
+
+    /**
+     * Creates the short-form of the given prototype.
+     *
+     * @param prototype {@code non-null;} the prototype
+     * @return {@code non-null;} the short form
+     */
+    private static CstUtf8 makeShortForm(Prototype prototype) {
+        StdTypeList parameters = prototype.getParameterTypes();
+        int size = parameters.size();
+        StringBuilder sb = new StringBuilder(size + 1);
+
+        sb.append(shortFormCharFor(prototype.getReturnType()));
+
+        for (int i = 0; i < size; i++) {
+            sb.append(shortFormCharFor(parameters.getType(i)));
+        }
+
+        return new CstUtf8(sb.toString());
+    }
+
+    /**
+     * Gets the short-form character for the given type.
+     *
+     * @param type {@code non-null;} the type
+     * @return the corresponding short-form character
+     */
+    private static char shortFormCharFor(Type type) {
+        char descriptorChar = type.getDescriptor().charAt(0);
+
+        if (descriptorChar == '[') {
+            return 'L';
+        }
+
+        return descriptorChar;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_PROTO_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return WRITE_SIZE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        StringIdsSection stringIds = file.getStringIds();
+        TypeIdsSection typeIds = file.getTypeIds();
+        MixedItemSection typeLists = file.getTypeLists();
+
+        typeIds.intern(prototype.getReturnType());
+        stringIds.intern(shortForm);
+
+        if (parameterTypes != null) {
+            parameterTypes = typeLists.intern(parameterTypes);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int shortyIdx = file.getStringIds().indexOf(shortForm);
+        int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType());
+        int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes);
+
+        if (out.annotates()) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(prototype.getReturnType().toHuman());
+            sb.append(" proto(");
+
+            StdTypeList params = prototype.getParameterTypes();
+            int size = params.size();
+
+            for (int i = 0; i < size; i++) {
+                if (i != 0) {
+                    sb.append(", ");
+                }
+                sb.append(params.getType(i).toHuman());
+            }
+
+            sb.append(")");
+            out.annotate(0, indexString() + ' ' + sb.toString());
+            out.annotate(4, "  shorty_idx:      " + Hex.u4(shortyIdx) +
+                    " // " + shortForm.toQuoted());
+            out.annotate(4, "  return_type_idx: " + Hex.u4(returnIdx) +
+                    " // " + prototype.getReturnType().toHuman());
+            out.annotate(4, "  parameters_off:  " + Hex.u4(paramsOff));
+        }
+
+        out.writeInt(shortyIdx);
+        out.writeInt(returnIdx);
+        out.writeInt(paramsOff);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ProtoIdsSection.java b/dexgen/src/com/android/dexgen/dex/file/ProtoIdsSection.java
new file mode 100644
index 0000000..b2af84e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ProtoIdsSection.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.type.Prototype;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Proto (method prototype) identifiers list section of a
+ * {@code .dex} file.
+ */
+public final class ProtoIdsSection extends UniformItemSection {
+    /**
+     * {@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 {@code non-null;} file that this instance is part of
+     */
+    public ProtoIdsSection(DexFile file) {
+        super("proto_ids", file, 4);
+
+        protoIds = new TreeMap<Prototype, ProtoIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return protoIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = protoIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (sz > 65536) {
+            throw new UnsupportedOperationException("too many proto ids");
+        }
+
+        if (out.annotates()) {
+            out.annotate(4, "proto_ids_size:  " + Hex.u4(sz));
+            out.annotate(4, "proto_ids_off:   " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param prototype {@code non-null;} the prototype to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public ProtoIdItem intern(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        throwIfPrepared();
+
+        ProtoIdItem result = protoIds.get(prototype);
+
+        if (result == null) {
+            result = new ProtoIdItem(prototype);
+            protoIds.put(prototype, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given prototype, which must have
+     * been added to this instance.
+     *
+     * @param prototype {@code non-null;} the prototype to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        throwIfNotPrepared();
+
+        ProtoIdItem item = protoIds.get(prototype);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return item.getIndex();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (Object i : items()) {
+            ((ProtoIdItem) i).setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/Section.java b/dexgen/src/com/android/dexgen/dex/file/Section.java
new file mode 100644
index 0000000..7efaf6b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/Section.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+
+import java.util.Collection;
+
+/**
+ * A section of a {@code .dex} file. Each section consists of a list
+ * of items of some sort or other.
+ */
+public abstract class Section {
+    /** {@code null-ok;} name of this part, for annotation purposes */
+    private final String name;
+
+    /** {@code non-null;} file that this instance is part of */
+    private final DexFile file;
+
+    /** {@code > 0;} alignment requirement for the final output;
+     * must be a power of 2 */
+    private final int alignment;
+
+    /** {@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
+     * instance */
+    private boolean prepared;
+
+    /**
+     * Validates an alignment.
+     *
+     * @param alignment the alignment
+     * @throws IllegalArgumentException thrown if {@code alignment}
+     * isn't a positive power of 2
+     */
+    public static void validateAlignment(int alignment) {
+        if ((alignment <= 0) ||
+            (alignment & (alignment - 1)) != 0) {
+            throw new IllegalArgumentException("invalid alignment");
+        }
+    }
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param name {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     * @param alignment {@code > 0;} alignment requirement for the final output;
+     * must be a power of 2
+     */
+    public Section(String name, DexFile file, int alignment) {
+        if (file == null) {
+            throw new NullPointerException("file == null");
+        }
+
+        validateAlignment(alignment);
+
+        this.name = name;
+        this.file = file;
+        this.alignment = alignment;
+        this.fileOffset = -1;
+        this.prepared = false;
+    }
+
+    /**
+     * Gets the file that this instance is part of.
+     *
+     * @return {@code non-null;} the file
+     */
+    public final DexFile getFile() {
+        return file;
+    }
+
+    /**
+     * Gets the alignment for this instance's final output.
+     *
+     * @return {@code > 0;} the alignment
+     */
+    public final int getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * 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 {@code >= 0;} the file offset
+     */
+    public final int getFileOffset() {
+        if (fileOffset < 0) {
+            throw new RuntimeException("fileOffset not set");
+        }
+
+        return fileOffset;
+    }
+
+    /**
+     * Sets the file offset. It is only valid to call this method once
+     * once per instance.
+     *
+     * @param fileOffset {@code >= 0;} the desired offset from the start of the
+     * file where this for this instance
+     * @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) {
+        if (fileOffset < 0) {
+            throw new IllegalArgumentException("fileOffset < 0");
+        }
+
+        if (this.fileOffset >= 0) {
+            throw new RuntimeException("fileOffset already set");
+        }
+
+        int mask = alignment - 1;
+        fileOffset = (fileOffset + mask) & ~mask;
+
+        this.fileOffset = fileOffset;
+
+        return fileOffset;
+    }
+
+    /**
+     * Writes this instance to the given raw data object.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public final void writeTo(AnnotatedOutput out) {
+        throwIfNotPrepared();
+        align(out);
+
+        int cursor = out.getCursor();
+
+        if (fileOffset < 0) {
+            fileOffset = cursor;
+        } else if (fileOffset != cursor) {
+            throw new RuntimeException("alignment mismatch: for " + this +
+                                       ", at " + cursor +
+                                       ", but expected " + fileOffset);
+        }
+
+        if (out.annotates()) {
+            if (name != null) {
+                out.annotate(0, "\n" + name + ":");
+            } else if (cursor != 0) {
+                out.annotate(0, "\n");
+            }
+        }
+
+        writeTo0(out);
+    }
+
+    /**
+     * Returns the absolute file offset, given an offset from the
+     * start of this instance's output. This is only valid to call
+     * once this instance has been assigned a file offset (via {@link
+     * #setFileOffset}).
+     *
+     * @param relative {@code >= 0;} the relative offset
+     * @return {@code >= 0;} the corresponding absolute file offset
+     */
+    public final int getAbsoluteOffset(int relative) {
+        if (relative < 0) {
+            throw new IllegalArgumentException("relative < 0");
+        }
+
+        if (fileOffset < 0) {
+            throw new RuntimeException("fileOffset not yet set");
+        }
+
+        return fileOffset + relative;
+    }
+
+    /**
+     * Returns the absolute file offset of the given item which must
+     * be contained in this section. This is only valid to call
+     * once this instance has been assigned a file offset (via {@link
+     * #setFileOffset}).
+     *
+     * <p><b>Note:</b> Subclasses must implement this as appropriate for
+     * their contents.</p>
+     *
+     * @param item {@code non-null;} the item in question
+     * @return {@code >= 0;} the item's absolute file offset
+     */
+    public abstract int getAbsoluteItemOffset(Item item);
+
+    /**
+     * Prepares this instance for writing. This performs any necessary
+     * prerequisites, including particularly adding stuff to other
+     * sections. This method may only be called once per instance;
+     * subsequent calls will throw an exception.
+     */
+    public final void prepare() {
+        throwIfPrepared();
+        prepare0();
+        prepared = true;
+    }
+
+    /**
+     * Gets the collection of all the items in this section.
+     * It is not valid to attempt to change the returned list.
+     *
+     * @return {@code non-null;} the items
+     */
+    public abstract Collection<? extends Item> items();
+
+    /**
+     * Does the main work of {@link #prepare}.
+     */
+    protected abstract void prepare0();
+
+    /**
+     * Gets the size of this instance when output, in bytes.
+     *
+     * @return {@code >= 0;} the size of this instance, in bytes
+     */
+    public abstract int writeSize();
+
+    /**
+     * Throws an exception if {@link #prepare} has not been
+     * called on this instance.
+     */
+    protected final void throwIfNotPrepared() {
+        if (!prepared) {
+            throw new RuntimeException("not prepared");
+        }
+    }
+
+    /**
+     * Throws an exception if {@link #prepare} has already been called
+     * on this instance.
+     */
+    protected final void throwIfPrepared() {
+        if (prepared) {
+            throw new RuntimeException("already prepared");
+        }
+    }
+
+    /**
+     * Aligns the output of the given data to the alignment of this instance.
+     *
+     * @param out {@code non-null;} the output to align
+     */
+    protected final void align(AnnotatedOutput out) {
+        out.alignTo(alignment);
+    }
+
+    /**
+     * Writes this instance to the given raw data object. This gets
+     * called by {@link #writeTo} after aligning the cursor of
+     * {@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}'s cursor.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    protected abstract void writeTo0(AnnotatedOutput out);
+
+    /**
+     * Returns the name of this section, for annotation purposes.
+     *
+     * @return {@code null-ok;} name of this part, for annotation purposes
+     */
+    protected final String getName() {
+        return name;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/Statistics.java b/dexgen/src/com/android/dexgen/dex/file/Statistics.java
new file mode 100644
index 0000000..1ec2f93
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/Statistics.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.TreeMap;
+
+/**
+ * Statistics about the contents of a file.
+ */
+public final class Statistics {
+    /** {@code non-null;} data about each type of item */
+    private final HashMap<String, Data> dataMap;
+
+    /**
+     * Constructs an instance.
+     */
+    public Statistics() {
+        dataMap = new HashMap<String, Data>(50);
+    }
+
+    /**
+     * Adds the given item to the statistics.
+     *
+     * @param item {@code non-null;} the item to add
+     */
+    public void add(Item item) {
+        String typeName = item.typeName();
+        Data data = dataMap.get(typeName);
+
+        if (data == null) {
+            dataMap.put(typeName, new Data(item, typeName));
+        } else {
+            data.add(item);
+        }
+    }
+
+    /**
+     * Adds the given list of items to the statistics.
+     *
+     * @param list {@code non-null;} the list of items to add
+     */
+    public void addAll(Section list) {
+        Collection<? extends Item> items = list.items();
+        for (Item item : items) {
+            add(item);
+        }
+    }
+
+    /**
+     * Writes the statistics as an annotation.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public final void writeAnnotation(AnnotatedOutput out) {
+        if (dataMap.size() == 0) {
+            return;
+        }
+
+        out.annotate(0, "\nstatistics:\n");
+
+        TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
+
+        for (Data data : dataMap.values()) {
+            sortedData.put(data.name, data);
+        }
+
+        for (Data data : sortedData.values()) {
+            data.writeAnnotation(out);
+        }
+    }
+
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("Statistics:\n");
+
+        TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
+
+        for (Data data : dataMap.values()) {
+            sortedData.put(data.name, data);
+        }
+
+        for (Data data : sortedData.values()) {
+            sb.append(data.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Statistical data about a particular class.
+     */
+    private static class Data {
+        /** {@code non-null;} name to use as a label */
+        private final String name;
+
+        /** {@code >= 0;} number of instances */
+        private int count;
+
+        /** {@code >= 0;} total size of instances in bytes */
+        private int totalSize;
+
+        /** {@code >= 0;} largest size of any individual item */
+        private int largestSize;
+
+        /** {@code >= 0;} smallest size of any individual item */
+        private int smallestSize;
+
+        /**
+         * Constructs an instance for the given item.
+         *
+         * @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();
+
+            this.name = name;
+            this.count = 1;
+            this.totalSize = size;
+            this.largestSize = size;
+            this.smallestSize = size;
+        }
+
+        /**
+         * Incorporates a new item. This assumes the type name matches.
+         *
+         * @param item {@code non-null;} item to incorporate
+         */
+        public void add(Item item) {
+            int size = item.writeSize();
+
+            count++;
+            totalSize += size;
+
+            if (size > largestSize) {
+                largestSize = size;
+            }
+
+            if (size < smallestSize) {
+                smallestSize = size;
+            }
+        }
+
+        /**
+         * Writes this instance as an annotation.
+         *
+         * @param out {@code non-null;} where to write to
+         */
+        public void writeAnnotation(AnnotatedOutput out) {
+            out.annotate(toHuman());
+        }
+
+        /**
+         * Generates a human-readable string for this data item.
+         *
+         * @return string for human consumption.
+         */
+        public String toHuman() {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append("  " + name + ": " +
+                         count + " item" + (count == 1 ? "" : "s") + "; " +
+                         totalSize + " bytes total\n");
+
+            if (smallestSize == largestSize) {
+                sb.append("    " + smallestSize + " bytes/item\n");
+            } else {
+                int average = totalSize / count;
+                sb.append("    " + smallestSize + ".." + largestSize +
+                             " bytes/item; average " + average + "\n");
+            }
+
+            return sb.toString();
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/StringDataItem.java b/dexgen/src/com/android/dexgen/dex/file/StringDataItem.java
new file mode 100644
index 0000000..7e28323
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/StringDataItem.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.ByteArray;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.Leb128Utils;
+
+/**
+ * Representation of string data for a particular string, in a Dalvik file.
+ */
+public final class StringDataItem extends OffsettedItem {
+    /** {@code non-null;} the string value */
+    private final CstUtf8 value;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param value {@code non-null;} the string value
+     */
+    public StringDataItem(CstUtf8 value) {
+        super(1, writeSize(value));
+
+        this.value = value;
+    }
+
+    /**
+     * Gets the write size for a given value.
+     *
+     * @param value {@code non-null;} the string value
+     * @return {@code >= 2}; the write size, in bytes
+     */
+    private static int writeSize(CstUtf8 value) {
+        int utf16Size = value.getUtf16Size();
+
+        // The +1 is for the '\0' termination byte.
+        return Leb128Utils.unsignedLeb128Size(utf16Size)
+            + value.getUtf8Size() + 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_STRING_DATA_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // Nothing to do here.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo0(DexFile file, AnnotatedOutput out) {
+        ByteArray bytes = value.getBytes();
+        int utf16Size = value.getUtf16Size();
+
+        if (out.annotates()) {
+            out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size),
+                    "utf16_size: " + Hex.u4(utf16Size));
+            out.annotate(bytes.size() + 1, value.toQuoted());
+        }
+
+        out.writeUnsignedLeb128(utf16Size);
+        out.write(bytes);
+        out.writeByte(0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return value.toQuoted();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        StringDataItem otherData = (StringDataItem) other;
+
+        return value.compareTo(otherData.value);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/StringIdItem.java b/dexgen/src/com/android/dexgen/dex/file/StringIdItem.java
new file mode 100644
index 0000000..30f31d4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/StringIdItem.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Representation of a string inside a Dalvik file.
+ */
+public final class StringIdItem
+        extends IndexedItem implements Comparable {
+    /** size of instances when written out to a file, in bytes */
+    public static final int WRITE_SIZE = 4;
+
+    /** {@code non-null;} the string value */
+    private final CstUtf8 value;
+
+    /** {@code null-ok;} associated string data object, if known */
+    private StringDataItem data;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param value {@code non-null;} the string value
+     */
+    public StringIdItem(CstUtf8 value) {
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        this.value = value;
+        this.data = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof StringIdItem)) {
+            return false;
+        }
+
+        StringIdItem otherString = (StringIdItem) other;
+        return value.equals(otherString.value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return value.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Object other) {
+        StringIdItem otherString = (StringIdItem) other;
+        return value.compareTo(otherString.value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_STRING_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return WRITE_SIZE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        if (data == null) {
+            // The string data hasn't yet been added, so add it.
+            MixedItemSection stringData = file.getStringData();
+            data = new StringDataItem(value);
+            stringData.add(data);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int dataOff = data.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, indexString() + ' ' + value.toQuoted(100));
+            out.annotate(4, "  string_data_off: " + Hex.u4(dataOff));
+        }
+
+        out.writeInt(dataOff);
+    }
+
+    /**
+     * Gets the string value.
+     *
+     * @return {@code non-null;} the value
+     */
+    public CstUtf8 getValue() {
+        return value;
+    }
+
+    /**
+     * Gets the associated data object for this instance, if known.
+     *
+     * @return {@code null-ok;} the associated data object or {@code null}
+     * if not yet known
+     */
+    public StringDataItem getData() {
+        return data;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/StringIdsSection.java b/dexgen/src/com/android/dexgen/dex/file/StringIdsSection.java
new file mode 100644
index 0000000..9047fb9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/StringIdsSection.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstNat;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Strings list section of a {@code .dex} file.
+ */
+public final class StringIdsSection
+        extends UniformItemSection {
+    /**
+     * {@code non-null;} map from string constants to {@link
+     * StringIdItem} instances
+     */
+    private final TreeMap<CstUtf8, StringIdItem> strings;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public StringIdsSection(DexFile file) {
+        super("string_ids", file, 4);
+
+        strings = new TreeMap<CstUtf8, StringIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return strings.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        if (cst instanceof CstString) {
+            cst = ((CstString) cst).getString();
+        }
+
+        IndexedItem result = strings.get((CstUtf8) cst);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = strings.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "string_ids_size: " + Hex.u4(sz));
+            out.annotate(4, "string_ids_off:  " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern, as a regular Java
+     * {@code String}
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(String string) {
+        CstUtf8 utf8 = new CstUtf8(string);
+        return intern(new StringIdItem(utf8));
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern, as a {@link CstString}
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(CstString string) {
+        CstUtf8 utf8 = string.getString();
+        return intern(new StringIdItem(utf8));
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern, as a constant
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(CstUtf8 string) {
+        return intern(new StringIdItem(string));
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(StringIdItem string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        throwIfPrepared();
+
+        CstUtf8 value = string.getValue();
+        StringIdItem already = strings.get(value);
+
+        if (already != null) {
+            return already;
+        }
+
+        strings.put(value, string);
+        return string;
+    }
+
+    /**
+     * Interns the components of a name-and-type into this instance.
+     *
+     * @param nat {@code non-null;} the name-and-type
+     */
+    public void intern(CstNat nat) {
+        intern(nat.getName());
+        intern(nat.getDescriptor());
+    }
+
+    /**
+     * Gets the index of the given string, which must have been added
+     * to this instance.
+     *
+     * @param string {@code non-null;} the string to look up
+     * @return {@code >= 0;} the string's index
+     */
+    public int indexOf(CstUtf8 string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        throwIfNotPrepared();
+
+        StringIdItem s = strings.get(string);
+
+        if (s == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return s.getIndex();
+    }
+
+    /**
+     * Gets the index of the given string, which must have been added
+     * to this instance.
+     *
+     * @param string {@code non-null;} the string to look up
+     * @return {@code >= 0;} the string's index
+     */
+    public int indexOf(CstString string) {
+        return indexOf(string.getString());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (StringIdItem s : strings.values()) {
+            s.setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/TypeIdItem.java b/dexgen/src/com/android/dexgen/dex/file/TypeIdItem.java
new file mode 100644
index 0000000..2c029b0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/TypeIdItem.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Representation of a type reference inside a Dalvik file.
+ */
+public final class TypeIdItem extends IdItem {
+    /** size of instances when written out to a file, in bytes */
+    public static final int WRITE_SIZE = 4;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the constant for the type
+     */
+    public TypeIdItem(CstType type) {
+        super(type);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_TYPE_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return WRITE_SIZE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        file.getStringIds().intern(getDefiningClass().getDescriptor());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        CstType type = getDefiningClass();
+        CstUtf8 descriptor = type.getDescriptor();
+        int idx = file.getStringIds().indexOf(descriptor);
+
+        if (out.annotates()) {
+            out.annotate(0, indexString() + ' ' + descriptor.toHuman());
+            out.annotate(4, "  descriptor_idx: " + Hex.u4(idx));
+        }
+
+        out.writeInt(idx);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/TypeIdsSection.java b/dexgen/src/com/android/dexgen/dex/file/TypeIdsSection.java
new file mode 100644
index 0000000..b02b592
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/TypeIdsSection.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Type identifiers list section of a {@code .dex} file.
+ */
+public final class TypeIdsSection extends UniformItemSection {
+    /**
+     * {@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 {@code non-null;} file that this instance is part of
+     */
+    public TypeIdsSection(DexFile file) {
+        super("type_ids", file, 4);
+
+        typeIds = new TreeMap<Type, TypeIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return typeIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        Type type = ((CstType) cst).getClassType();
+        IndexedItem result = typeIds.get(type);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found: " + cst);
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = typeIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (sz > 65536) {
+            throw new UnsupportedOperationException("too many type ids");
+        }
+
+        if (out.annotates()) {
+            out.annotate(4, "type_ids_size:   " + Hex.u4(sz));
+            out.annotate(4, "type_ids_off:    " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param type {@code non-null;} the type to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public TypeIdItem intern(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        throwIfPrepared();
+
+        TypeIdItem result = typeIds.get(type);
+
+        if (result == null) {
+            result = new TypeIdItem(new CstType(type));
+            typeIds.put(type, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param type {@code non-null;} the type to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public TypeIdItem intern(CstType type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        throwIfPrepared();
+
+        Type typePerSe = type.getClassType();
+        TypeIdItem result = typeIds.get(typePerSe);
+
+        if (result == null) {
+            result = new TypeIdItem(type);
+            typeIds.put(typePerSe, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given type, which must have
+     * been added to this instance.
+     *
+     * @param type {@code non-null;} the type to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        throwIfNotPrepared();
+
+        TypeIdItem item = typeIds.get(type);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found: " + type);
+        }
+
+        return item.getIndex();
+    }
+
+    /**
+     * Gets the index of the given type, which must have
+     * been added to this instance.
+     *
+     * @param type {@code non-null;} the type to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(CstType type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        return indexOf(type.getClassType());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (Object i : items()) {
+            ((TypeIdItem) i).setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/TypeListItem.java b/dexgen/src/com/android/dexgen/dex/file/TypeListItem.java
new file mode 100644
index 0000000..a78c63d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/TypeListItem.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Representation of a list of class references.
+ */
+public final class TypeListItem extends OffsettedItem {
+    /** alignment requirement */
+    private static final int ALIGNMENT = 4;
+
+    /** element size in bytes */
+    private static final int ELEMENT_SIZE = 2;
+
+    /** header size in bytes */
+    private static final int HEADER_SIZE = 4;
+
+    /** {@code non-null;} the actual list */
+    private final TypeList list;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param list {@code non-null;} the actual list
+     */
+    public TypeListItem(TypeList list) {
+        super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE);
+
+        this.list = list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return StdTypeList.hashContents(list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_TYPE_LIST;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        int sz = list.size();
+
+        for (int i = 0; i < sz; i++) {
+            typeIds.intern(list.getType(i));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /**
+     * Gets the underlying list.
+     *
+     * @return {@code non-null;} the list
+     */
+    public TypeList getList() {
+        return list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        int sz = list.size();
+
+        if (out.annotates()) {
+            out.annotate(0, offsetString() + " type_list");
+            out.annotate(HEADER_SIZE, "  size: " + Hex.u4(sz));
+            for (int i = 0; i < sz; i++) {
+                Type one = list.getType(i);
+                int idx = typeIds.indexOf(one);
+                out.annotate(ELEMENT_SIZE,
+                             "  " + Hex.u2(idx) + " // " + one.toHuman());
+            }
+        }
+
+        out.writeInt(sz);
+
+        for (int i = 0; i < sz; i++) {
+            out.writeShort(typeIds.indexOf(list.getType(i)));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        TypeList thisList = this.list;
+        TypeList otherList = ((TypeListItem) other).list;
+
+        return StdTypeList.compareContents(thisList, otherList);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/UniformItemSection.java b/dexgen/src/com/android/dexgen/dex/file/UniformItemSection.java
new file mode 100644
index 0000000..63ba36b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/UniformItemSection.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.util.AnnotatedOutput;
+
+import java.util.Collection;
+
+/**
+ * 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.
+ */
+public abstract class UniformItemSection extends Section {
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param name {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     * @param alignment {@code > 0;} alignment requirement for the final output;
+     * must be a power of 2
+     */
+    public UniformItemSection(String name, DexFile file, int alignment) {
+        super(name, file, alignment);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int writeSize() {
+        Collection<? extends Item> items = items();
+        int sz = items.size();
+
+        if (sz == 0) {
+            return 0;
+        }
+
+        // Since each item has to be the same size, we can pick any.
+        return sz * items.iterator().next().writeSize();
+    }
+
+    /**
+     * Gets the item corresponding to the given {@link Constant}. This
+     * will throw an exception if the constant is not found, including
+     * if this instance isn't the sort that maps constants to {@link
+     * IndexedItem} instances.
+     *
+     * @param cst {@code non-null;} constant to look for
+     * @return {@code non-null;} the corresponding item found in this instance
+     */
+    public abstract IndexedItem get(Constant cst);
+
+    /** {@inheritDoc} */
+    @Override
+    protected final void prepare0() {
+        DexFile file = getFile();
+
+        orderItems();
+
+        for (Item one : items()) {
+            one.addContents(file);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected final void writeTo0(AnnotatedOutput out) {
+        DexFile file = getFile();
+        int alignment = getAlignment();
+
+        for (Item one : items()) {
+            one.writeTo(file, out);
+            out.alignTo(alignment);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int getAbsoluteItemOffset(Item item) {
+        /*
+         * Since all items must be the same size, we can use the size
+         * of the one we're given to calculate its offset.
+         */
+        IndexedItem ii = (IndexedItem) item;
+        int relativeOffset = ii.getIndex() * ii.writeSize();
+
+        return getAbsoluteOffset(relativeOffset);
+    }
+
+    /**
+     * Alters or picks the order for items in this instance if desired,
+     * so that subsequent calls to {@link #items} will yield a
+     * so-ordered collection. If the items in this instance are indexed,
+     * then this method should also assign indices.
+     */
+    protected abstract void orderItems();
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/UniformListItem.java b/dexgen/src/com/android/dexgen/dex/file/UniformListItem.java
new file mode 100644
index 0000000..88a120d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/UniformListItem.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Class that represents a contiguous list of uniform items. Each
+ * item in the list, in particular, must have the same write size and
+ * alignment.
+ *
+ * <p>This class inherits its alignment from its items, bumped up to
+ * {@code 4} if the items have a looser alignment requirement. If
+ * it is more than {@code 4}, then there will be a gap after the
+ * output list size (which is four bytes) and before the first item.</p>
+ *
+ * @param <T> type of element contained in an instance
+ */
+public final class UniformListItem<T extends OffsettedItem>
+        extends OffsettedItem {
+    /** the size of the list header */
+    private static final int HEADER_SIZE = 4;
+
+    /** {@code non-null;} the item type */
+    private final ItemType itemType;
+
+    /** {@code non-null;} the contents */
+    private final List<T> items;
+
+    /**
+     * Constructs an instance. It is illegal to modify the given list once
+     * it is used to construct an instance of this class.
+     *
+     * @param itemType {@code non-null;} the type of the item
+     * @param items {@code non-null and non-empty;} list of items to represent
+     */
+    public UniformListItem(ItemType itemType, List<T> items) {
+        super(getAlignment(items), writeSize(items));
+
+        if (itemType == null) {
+            throw new NullPointerException("itemType == null");
+        }
+
+        this.items = items;
+        this.itemType = itemType;
+    }
+
+    /**
+     * Helper for {@link #UniformListItem}, which returns the alignment
+     * requirement implied by the given list. See the header comment for
+     * more details.
+     *
+     * @param items {@code non-null;} list of items being represented
+     * @return {@code >= 4;} the alignment requirement
+     */
+    private static int getAlignment(List<? extends OffsettedItem> items) {
+        try {
+            // Since they all must have the same alignment, any one will do.
+            return Math.max(HEADER_SIZE, items.get(0).getAlignment());
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("items.size() == 0");
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("items == null");
+        }
+    }
+
+    /**
+     * Calculates the write size for the given list.
+     *
+     * @param items {@code non-null;} the list in question
+     * @return {@code >= 0;} the write size
+     */
+    private static int writeSize(List<? extends OffsettedItem> items) {
+        /*
+         * This class assumes all included items are the same size,
+         * an assumption which is verified in place0().
+         */
+        OffsettedItem first = items.get(0);
+        return (items.size() * first.writeSize()) + getAlignment(items);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return itemType;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append(items);
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        for (OffsettedItem i : items) {
+            i.addContents(file);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toHuman() {
+        StringBuffer sb = new StringBuffer(100);
+        boolean first = true;
+
+        sb.append("{");
+
+        for (OffsettedItem i : items) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(i.toHuman());
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Gets the underlying list of items.
+     *
+     * @return {@code non-null;} the list
+     */
+    public final List<T> getItems() {
+        return items;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        offset += headerSize();
+
+        boolean first = true;
+        int theSize = -1;
+        int theAlignment = -1;
+
+        for (OffsettedItem i : items) {
+            int size = i.writeSize();
+            if (first) {
+                theSize = size;
+                theAlignment = i.getAlignment();
+                first = false;
+            } else {
+                if (size != theSize) {
+                    throw new UnsupportedOperationException(
+                            "item size mismatch");
+                }
+                if (i.getAlignment() != theAlignment) {
+                    throw new UnsupportedOperationException(
+                            "item alignment mismatch");
+                }
+            }
+
+            offset = i.place(addedTo, offset) + size;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        int size = items.size();
+
+        if (out.annotates()) {
+            out.annotate(0, offsetString() + " " + typeName());
+            out.annotate(4, "  size: " + Hex.u4(size));
+        }
+
+        out.writeInt(size);
+
+        for (OffsettedItem i : items) {
+            i.writeTo(file, out);
+        }
+    }
+
+    /**
+     * Get the size of the header of this list.
+     *
+     * @return {@code >= 0;} the header size
+     */
+    private int headerSize() {
+        /*
+         * Because of how this instance was set up, this is the same
+         * as the alignment.
+         */
+        return getAlignment();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/dex/file/ValueEncoder.java b/dexgen/src/com/android/dexgen/dex/file/ValueEncoder.java
new file mode 100644
index 0000000..7f30779
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/dex/file/ValueEncoder.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.dex.file;
+
+import com.android.dexgen.rop.annotation.Annotation;
+import com.android.dexgen.rop.annotation.NameValuePair;
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstAnnotation;
+import com.android.dexgen.rop.cst.CstArray;
+import com.android.dexgen.rop.cst.CstBoolean;
+import com.android.dexgen.rop.cst.CstByte;
+import com.android.dexgen.rop.cst.CstChar;
+import com.android.dexgen.rop.cst.CstDouble;
+import com.android.dexgen.rop.cst.CstEnumRef;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstFloat;
+import com.android.dexgen.rop.cst.CstInteger;
+import com.android.dexgen.rop.cst.CstKnownNull;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.rop.cst.CstLong;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstShort;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.AnnotatedOutput;
+import com.android.dexgen.util.Hex;
+
+import java.util.Collection;
+
+/**
+ * Handler for writing out {@code encoded_values} and parts
+ * thereof.
+ */
+public final class ValueEncoder {
+    /** annotation value type constant: {@code byte} */
+    private static final int VALUE_BYTE = 0x00;
+
+    /** annotation value type constant: {@code short} */
+    private static final int VALUE_SHORT = 0x02;
+
+    /** annotation value type constant: {@code char} */
+    private static final int VALUE_CHAR = 0x03;
+
+    /** annotation value type constant: {@code int} */
+    private static final int VALUE_INT = 0x04;
+
+    /** annotation value type constant: {@code long} */
+    private static final int VALUE_LONG = 0x06;
+
+    /** annotation value type constant: {@code float} */
+    private static final int VALUE_FLOAT = 0x10;
+
+    /** annotation value type constant: {@code double} */
+    private static final int VALUE_DOUBLE = 0x11;
+
+    /** annotation value type constant: {@code string} */
+    private static final int VALUE_STRING = 0x17;
+
+    /** annotation value type constant: {@code type} */
+    private static final int VALUE_TYPE = 0x18;
+
+    /** annotation value type constant: {@code field} */
+    private static final int VALUE_FIELD = 0x19;
+
+    /** annotation value type constant: {@code method} */
+    private static final int VALUE_METHOD = 0x1a;
+
+    /** annotation value type constant: {@code enum} */
+    private static final int VALUE_ENUM = 0x1b;
+
+    /** annotation value type constant: {@code array} */
+    private static final int VALUE_ARRAY = 0x1c;
+
+    /** annotation value type constant: {@code annotation} */
+    private static final int VALUE_ANNOTATION = 0x1d;
+
+    /** annotation value type constant: {@code null} */
+    private static final int VALUE_NULL = 0x1e;
+
+    /** annotation value type constant: {@code boolean} */
+    private static final int VALUE_BOOLEAN = 0x1f;
+
+    /** {@code non-null;} file being written */
+    private final DexFile file;
+
+    /** {@code non-null;} output stream to write to */
+    private final AnnotatedOutput out;
+
+    /**
+     * Construct an instance.
+     *
+     * @param file {@code non-null;} file being written
+     * @param out {@code non-null;} output stream to write to
+     */
+    public ValueEncoder(DexFile file, AnnotatedOutput out) {
+        if (file == null) {
+            throw new NullPointerException("file == null");
+        }
+
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        }
+
+        this.file = file;
+        this.out = out;
+    }
+
+    /**
+     * Writes out the encoded form of the given constant.
+     *
+     * @param cst {@code non-null;} the constant to write
+     */
+    public void writeConstant(Constant cst) {
+        int type = constantToValueType(cst);
+        int arg;
+
+        switch (type) {
+            case VALUE_BYTE:
+            case VALUE_SHORT:
+            case VALUE_INT:
+            case VALUE_LONG: {
+                long value = ((CstLiteralBits) cst).getLongBits();
+                writeSignedIntegralValue(type, value);
+                break;
+            }
+            case VALUE_CHAR: {
+                long value = ((CstLiteralBits) cst).getLongBits();
+                writeUnsignedIntegralValue(type, value);
+                break;
+            }
+            case VALUE_FLOAT: {
+                // Shift value left 32 so that right-zero-extension works.
+                long value = ((CstFloat) cst).getLongBits() << 32;
+                writeRightZeroExtendedValue(type, value);
+                break;
+            }
+            case VALUE_DOUBLE: {
+                long value = ((CstDouble) cst).getLongBits();
+                writeRightZeroExtendedValue(type, value);
+                break;
+            }
+            case VALUE_STRING: {
+                int index = file.getStringIds().indexOf((CstString) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_TYPE: {
+                int index = file.getTypeIds().indexOf((CstType) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_FIELD: {
+                int index = file.getFieldIds().indexOf((CstFieldRef) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_METHOD: {
+                int index = file.getMethodIds().indexOf((CstMethodRef) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_ENUM: {
+                CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef();
+                int index = file.getFieldIds().indexOf(fieldRef);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_ARRAY: {
+                out.writeByte(type);
+                writeArray((CstArray) cst, false);
+                break;
+            }
+            case VALUE_ANNOTATION: {
+                out.writeByte(type);
+                writeAnnotation(((CstAnnotation) cst).getAnnotation(),
+                        false);
+                break;
+            }
+            case VALUE_NULL: {
+                out.writeByte(type);
+                break;
+            }
+            case VALUE_BOOLEAN: {
+                int value = ((CstBoolean) cst).getIntBits();
+                out.writeByte(type | (value << 5));
+                break;
+            }
+            default: {
+                throw new RuntimeException("Shouldn't happen");
+            }
+        }
+    }
+
+    /**
+     * Gets the value type for the given constant.
+     *
+     * @param cst {@code non-null;} the constant
+     * @return the value type; one of the {@code VALUE_*} constants
+     * defined by this class
+     */
+    private static int constantToValueType(Constant cst) {
+        /*
+         * TODO: Constant should probable have an associated enum, so this
+         * can be a switch().
+         */
+        if (cst instanceof CstByte) {
+            return VALUE_BYTE;
+        } else if (cst instanceof CstShort) {
+            return VALUE_SHORT;
+        } else if (cst instanceof CstChar) {
+            return VALUE_CHAR;
+        } else if (cst instanceof CstInteger) {
+            return VALUE_INT;
+        } else if (cst instanceof CstLong) {
+            return VALUE_LONG;
+        } else if (cst instanceof CstFloat) {
+            return VALUE_FLOAT;
+        } else if (cst instanceof CstDouble) {
+            return VALUE_DOUBLE;
+        } else if (cst instanceof CstString) {
+            return VALUE_STRING;
+        } else if (cst instanceof CstType) {
+            return VALUE_TYPE;
+        } else if (cst instanceof CstFieldRef) {
+            return VALUE_FIELD;
+        } else if (cst instanceof CstMethodRef) {
+            return VALUE_METHOD;
+        } else if (cst instanceof CstEnumRef) {
+            return VALUE_ENUM;
+        } else if (cst instanceof CstArray) {
+            return VALUE_ARRAY;
+        } else if (cst instanceof CstAnnotation) {
+            return VALUE_ANNOTATION;
+        } else if (cst instanceof CstKnownNull) {
+            return VALUE_NULL;
+        } else if (cst instanceof CstBoolean) {
+            return VALUE_BOOLEAN;
+        } else {
+            throw new RuntimeException("Shouldn't happen");
+        }
+    }
+
+    /**
+     * Writes out the encoded form of the given array, that is, as
+     * 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 {@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) {
+        boolean annotates = topLevel && out.annotates();
+        CstArray.List list = ((CstArray) array).getList();
+        int size = list.size();
+
+        if (annotates) {
+            out.annotate("  size: " + Hex.u4(size));
+        }
+
+        out.writeUnsignedLeb128(size);
+
+        for (int i = 0; i < size; i++) {
+            Constant cst = list.get(i);
+            if (annotates) {
+                out.annotate("  [" + Integer.toHexString(i) + "] " +
+                        constantToHuman(cst));
+            }
+            writeConstant(cst);
+        }
+
+        if (annotates) {
+            out.endAnnotation();
+        }
+    }
+
+    /**
+     * Writes out the encoded form of the given annotation, that is,
+     * 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 {@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) {
+        boolean annotates = topLevel && out.annotates();
+        StringIdsSection stringIds = file.getStringIds();
+        TypeIdsSection typeIds = file.getTypeIds();
+
+        CstType type = annotation.getType();
+        int typeIdx = typeIds.indexOf(type);
+
+        if (annotates) {
+            out.annotate("  type_idx: " + Hex.u4(typeIdx) + " // " +
+                    type.toHuman());
+        }
+
+        out.writeUnsignedLeb128(typeIds.indexOf(annotation.getType()));
+
+        Collection<NameValuePair> pairs = annotation.getNameValuePairs();
+        int size = pairs.size();
+
+        if (annotates) {
+            out.annotate("  size: " + Hex.u4(size));
+        }
+
+        out.writeUnsignedLeb128(size);
+
+        int at = 0;
+        for (NameValuePair pair : pairs) {
+            CstUtf8 name = pair.getName();
+            int nameIdx = stringIds.indexOf(name);
+            Constant value = pair.getValue();
+
+            if (annotates) {
+                out.annotate(0, "  elements[" + at + "]:");
+                at++;
+                out.annotate("    name_idx: " + Hex.u4(nameIdx) + " // " +
+                        name.toHuman());
+            }
+
+            out.writeUnsignedLeb128(nameIdx);
+
+            if (annotates) {
+                out.annotate("    value: " + constantToHuman(value));
+            }
+
+            writeConstant(value);
+        }
+
+        if (annotates) {
+            out.endAnnotation();
+        }
+    }
+
+    /**
+     * Gets the colloquial type name and human form of the type of the
+     * given constant, when used as an encoded value.
+     *
+     * @param cst {@code non-null;} the constant
+     * @return {@code non-null;} its type name and human form
+     */
+    public static String constantToHuman(Constant cst) {
+        int type = constantToValueType(cst);
+
+        if (type == VALUE_NULL) {
+            return "null";
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(cst.typeName());
+        sb.append(' ');
+        sb.append(cst.toHuman());
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper for {@link #writeConstant}, which writes out the value
+     * for any signed integral type.
+     *
+     * @param type the type constant
+     * @param value {@code long} bits of the value
+     */
+    private void writeSignedIntegralValue(int type, long value) {
+        /*
+         * Figure out how many bits are needed to represent the value,
+         * including a sign bit: The bit count is subtracted from 65
+         * and not 64 to account for the sign bit. The xor operation
+         * has the effect of leaving non-negative values alone and
+         * unary complementing negative values (so that a leading zero
+         * count always returns a useful number for our present
+         * purpose).
+         */
+        int requiredBits =
+            65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
+
+        // Round up the requiredBits to a number of bytes.
+        int requiredBytes = (requiredBits + 0x07) >> 3;
+
+        /*
+         * Write the header byte, which includes the type and
+         * requiredBytes - 1.
+         */
+        out.writeByte(type | ((requiredBytes - 1) << 5));
+
+        // Write the value, per se.
+        while (requiredBytes > 0) {
+            out.writeByte((byte) value);
+            value >>= 8;
+            requiredBytes--;
+        }
+    }
+
+    /**
+     * Helper for {@link #writeConstant}, which writes out the value
+     * for any unsigned integral type.
+     *
+     * @param type the type constant
+     * @param value {@code long} bits of the value
+     */
+    private void writeUnsignedIntegralValue(int type, long value) {
+        // Figure out how many bits are needed to represent the value.
+        int requiredBits = 64 - Long.numberOfLeadingZeros(value);
+        if (requiredBits == 0) {
+            requiredBits = 1;
+        }
+
+        // Round up the requiredBits to a number of bytes.
+        int requiredBytes = (requiredBits + 0x07) >> 3;
+
+        /*
+         * Write the header byte, which includes the type and
+         * requiredBytes - 1.
+         */
+        out.writeByte(type | ((requiredBytes - 1) << 5));
+
+        // Write the value, per se.
+        while (requiredBytes > 0) {
+            out.writeByte((byte) value);
+            value >>= 8;
+            requiredBytes--;
+        }
+    }
+
+    /**
+     * Helper for {@link #writeConstant}, which writes out a
+     * right-zero-extended value.
+     *
+     * @param type the type constant
+     * @param value {@code long} bits of the value
+     */
+    private void writeRightZeroExtendedValue(int type, long value) {
+        // Figure out how many bits are needed to represent the value.
+        int requiredBits = 64 - Long.numberOfTrailingZeros(value);
+        if (requiredBits == 0) {
+            requiredBits = 1;
+        }
+
+        // Round up the requiredBits to a number of bytes.
+        int requiredBytes = (requiredBits + 0x07) >> 3;
+
+        // Scootch the first bits to be written down to the low-order bits.
+        value >>= 64 - (requiredBytes * 8);
+
+        /*
+         * Write the header byte, which includes the type and
+         * requiredBytes - 1.
+         */
+        out.writeByte(type | ((requiredBytes - 1) << 5));
+
+        // Write the value, per se.
+        while (requiredBytes > 0) {
+            out.writeByte((byte) value);
+            value >>= 8;
+            requiredBytes--;
+        }
+    }
+
+
+    /**
+     * Helper for {@code addContents()} methods, which adds
+     * contents for a particular {@link Annotation}, calling itself
+     * recursively should it encounter a nested annotation.
+     *
+     * @param file {@code non-null;} the file to add to
+     * @param annotation {@code non-null;} the annotation to add contents for
+     */
+    public static void addContents(DexFile file, Annotation annotation) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        StringIdsSection stringIds = file.getStringIds();
+
+        typeIds.intern(annotation.getType());
+
+        for (NameValuePair pair : annotation.getNameValuePairs()) {
+            stringIds.intern(pair.getName());
+            addContents(file, pair.getValue());
+        }
+    }
+
+    /**
+     * 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 {@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) {
+        if (cst instanceof CstAnnotation) {
+            addContents(file, ((CstAnnotation) cst).getAnnotation());
+        } else if (cst instanceof CstArray) {
+            CstArray.List list = ((CstArray) cst).getList();
+            int size = list.size();
+            for (int i = 0; i < size; i++) {
+                addContents(file, list.get(i));
+            }
+        } else {
+            file.internIfAppropriate(cst);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/AttConstantValue.java b/dexgen/src/com/android/dexgen/rop/AttConstantValue.java
new file mode 100644
index 0000000..189dd75
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/AttConstantValue.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.rop.cst.CstDouble;
+import com.android.dexgen.rop.cst.CstFloat;
+import com.android.dexgen.rop.cst.CstInteger;
+import com.android.dexgen.rop.cst.CstLong;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.TypedConstant;
+
+/**
+ * Attribute class for standard {@code ConstantValue} attributes.
+ */
+public final class AttConstantValue extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "ConstantValue";
+
+    /** {@code non-null;} the constant value */
+    private final TypedConstant constantValue;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param constantValue {@code non-null;} the constant value, which must
+     * be an instance of one of: {@code CstString},
+     * {@code CstInteger}, {@code CstLong},
+     * {@code CstFloat}, or {@code CstDouble}
+     */
+    public AttConstantValue(TypedConstant constantValue) {
+        super(ATTRIBUTE_NAME);
+
+        if (!((constantValue instanceof CstString) ||
+               (constantValue instanceof CstInteger) ||
+               (constantValue instanceof CstLong) ||
+               (constantValue instanceof CstFloat) ||
+               (constantValue instanceof CstDouble))) {
+            if (constantValue == null) {
+                throw new NullPointerException("constantValue == null");
+            }
+            throw new IllegalArgumentException("bad type for constantValue");
+        }
+
+        this.constantValue = constantValue;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8;
+    }
+
+    /**
+     * Gets the constant value of this instance. The returned value
+     * is an instance of one of: {@code CstString},
+     * {@code CstInteger}, {@code CstLong},
+     * {@code CstFloat}, or {@code CstDouble}.
+     *
+     * @return {@code non-null;} the constant value
+     */
+    public TypedConstant getConstantValue() {
+        return constantValue;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/Attribute.java b/dexgen/src/com/android/dexgen/rop/Attribute.java
new file mode 100644
index 0000000..02f1e14
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/Attribute.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+/**
+ * Interface representing attributes of class files (directly or indirectly).
+ */
+public interface Attribute {
+    /**
+     * Get the name of the attribute.
+     *
+     * @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}.
+     *
+     * @return {@code >= 6;} the total length, in bytes
+     */
+    public int byteLength();
+}
diff --git a/dexgen/src/com/android/dexgen/rop/AttributeList.java b/dexgen/src/com/android/dexgen/rop/AttributeList.java
new file mode 100644
index 0000000..205b9b7
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/AttributeList.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+/**
+ * Interface for lists of attributes.
+ */
+public interface AttributeList {
+    /**
+     * Get whether this instance is mutable. Note that the
+     * {@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} iff this instance is somehow mutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Get the number of attributes in the list.
+     *
+     * @return the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th attribute.
+     *
+     * @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} length indicator.
+     *
+     * @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 {@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);
+
+    /**
+     * Get the next attribute in the list after the given one, with the same
+     * name, if any.
+     *
+     * @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/dexgen/src/com/android/dexgen/rop/BaseAttribute.java b/dexgen/src/com/android/dexgen/rop/BaseAttribute.java
new file mode 100644
index 0000000..7ce88c0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/BaseAttribute.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+
+/**
+ * Base implementation of {@link Attribute}, which directly stores
+ * the attribute name but leaves the rest up to subclasses.
+ */
+public abstract class BaseAttribute implements Attribute {
+    /** {@code non-null;} attribute name */
+    private final String name;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param name {@code non-null;} attribute name
+     */
+    public BaseAttribute(String name) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/ByteBlock.java b/dexgen/src/com/android/dexgen/rop/ByteBlock.java
new file mode 100644
index 0000000..bdeeb0b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/ByteBlock.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.IntList;
+import com.android.dexgen.util.LabeledItem;
+
+/**
+ * Representation of a basic block in a bytecode array.
+ */
+public final class ByteBlock implements LabeledItem {
+    /** {@code >= 0;} label for this block */
+    private final int label;
+
+    /** {@code >= 0;} bytecode offset (inclusive) of the start of the block */
+    private final int start;
+
+    /** {@code > start;} bytecode offset (exclusive) of the end of the block */
+    private final int end;
+
+    /** {@code non-null;} list of successors that this block may branch to */
+    private final IntList successors;
+
+    /** {@code non-null;} list of exceptions caught and their handler targets */
+    private final ByteCatchList catches;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param label {@code >= 0;} target label for this block
+     * @param start {@code >= 0;} bytecode offset (inclusive) of the start
+     * of the block
+     * @param end {@code > start;} bytecode offset (exclusive) of the end
+     * of the block
+     * @param successors {@code non-null;} list of successors that this block may
+     * branch to
+     * @param catches {@code non-null;} list of exceptions caught and their
+     * handler targets
+     */
+    public ByteBlock(int label, int start, int end, IntList successors,
+                     ByteCatchList catches) {
+        if (label < 0) {
+            throw new IllegalArgumentException("label < 0");
+        }
+
+        if (start < 0) {
+            throw new IllegalArgumentException("start < 0");
+        }
+
+        if (end <= start) {
+            throw new IllegalArgumentException("end <= start");
+        }
+
+        if (successors == null) {
+            throw new NullPointerException("targets == null");
+        }
+
+        int sz = successors.size();
+        for (int i = 0; i < sz; i++) {
+            if (successors.get(i) < 0) {
+                throw new IllegalArgumentException("successors[" + i +
+                                                   "] == " +
+                                                   successors.get(i));
+            }
+        }
+
+        if (catches == null) {
+            throw new NullPointerException("catches == null");
+        }
+
+        this.label = label;
+        this.start = start;
+        this.end = end;
+        this.successors = successors;
+        this.catches = catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return '{' + Hex.u2(label) + ": " + Hex.u2(start) + ".." +
+            Hex.u2(end) + '}';
+    }
+
+    /**
+     * Gets the label of this block.
+     *
+     * @return {@code >= 0;} the label
+     */
+    public int getLabel() {
+        return label;
+    }
+
+    /**
+     * Gets the bytecode offset (inclusive) of the start of this block.
+     *
+     * @return {@code >= 0;} the start offset
+     */
+    public int getStart() {
+        return start;
+    }
+
+    /**
+     * Gets the bytecode offset (exclusive) of the end of this block.
+     *
+     * @return {@code > getStart();} the end offset
+     */
+    public int getEnd() {
+        return end;
+    }
+
+    /**
+     * Gets the list of successors that this block may branch to
+     * non-exceptionally.
+     *
+     * @return {@code non-null;} the successor list
+     */
+    public IntList getSuccessors() {
+        return successors;
+    }
+
+    /**
+     * Gets the list of exceptions caught and their handler targets.
+     *
+     * @return {@code non-null;} the catch list
+     */
+    public ByteCatchList getCatches() {
+        return catches;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/ByteCatchList.java b/dexgen/src/com/android/dexgen/rop/ByteCatchList.java
new file mode 100644
index 0000000..d2a4857
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/ByteCatchList.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.FixedSizeList;
+import com.android.dexgen.util.IntList;
+
+/**
+ * List of catch entries, that is, the elements of an "exception table,"
+ * which is part of a standard {@code Code} attribute.
+ */
+public final class ByteCatchList extends FixedSizeList {
+    /** {@code non-null;} convenient zero-entry instance */
+    public static final ByteCatchList EMPTY = new ByteCatchList(0);
+
+    /**
+     * Constructs an instance.
+     *
+     * @param count the number of elements to be in the table
+     */
+    public ByteCatchList(int count) {
+        super(count);
+    }
+
+    /**
+     * Gets the total length of this structure in bytes, when included in
+     * a {@code Code} attribute. The returned value includes the
+     * two bytes for {@code exception_table_length}.
+     *
+     * @return {@code >= 2;} the total length, in bytes
+     */
+    public int byteLength() {
+        return 2 + size() * 8;
+    }
+
+    /**
+     * Gets 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);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @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) {
+            throw new NullPointerException("item == null");
+        }
+
+        set0(n, item);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @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 {@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) {
+        set0(n, new Item(startPc, endPc, handlerPc, exceptionClass));
+    }
+
+    /**
+     * Gets the list of items active at the given address. The result is
+     * automatically made immutable.
+     *
+     * @param pc which address
+     * @return {@code non-null;} list of exception handlers active at
+     * {@code pc}
+     */
+    public ByteCatchList listFor(int pc) {
+        int sz = size();
+        Item[] resultArr = new Item[sz];
+        int resultSz = 0;
+
+        for (int i = 0; i < sz; i++) {
+            Item one = get(i);
+            if (one.covers(pc) && typeNotFound(one, resultArr, resultSz)) {
+                resultArr[resultSz] = one;
+                resultSz++;
+            }
+        }
+
+        if (resultSz == 0) {
+            return EMPTY;
+        }
+
+        ByteCatchList result = new ByteCatchList(resultSz);
+        for (int i = 0; i < resultSz; i++) {
+            result.set(i, resultArr[i]);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * 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} which represents a catch-all.
+     *
+     * @param item {@code non-null;} item with the exception type to look for
+     * @param arr {@code non-null;} array to search in
+     * @param count {@code non-null;} maximum number of elements in the array to check
+     * @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();
+
+        for (int i = 0; i < count; i++) {
+            CstType one = arr[i].getExceptionClass();
+            if ((one == type) || (one == CstType.OBJECT)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns a target list corresponding to this instance. The result
+     * is a list of all the exception handler addresses, with the given
+     * {@code noException} address appended if appropriate. The
+     * result is automatically made immutable.
+     *
+     * @param noException {@code >= -1;} the no-exception address to append, or
+     * {@code -1} not to append anything
+     * @return {@code non-null;} list of exception targets, with
+     * {@code noException} appended if necessary
+     */
+    public IntList toTargetList(int noException) {
+        if (noException < -1) {
+            throw new IllegalArgumentException("noException < -1");
+        }
+
+        boolean hasDefault = (noException >= 0);
+        int sz = size();
+
+        if (sz == 0) {
+            if (hasDefault) {
+                /*
+                 * The list is empty, but there is a no-exception
+                 * address; so, the result is just that address.
+                 */
+                return IntList.makeImmutable(noException);
+            }
+            /*
+             * The list is empty and there isn't even a no-exception
+             * address.
+             */
+            return IntList.EMPTY;
+        }
+
+        IntList result = new IntList(sz + (hasDefault ? 1 : 0));
+
+        for (int i = 0; i < sz; i++) {
+            result.add(get(i).getHandlerPc());
+        }
+
+        if (hasDefault) {
+            result.add(noException);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Returns a rop-style catches list equivalent to this one.
+     *
+     * @return {@code non-null;} the converted instance
+     */
+    public TypeList toRopCatchList() {
+        int sz = size();
+        if (sz == 0) {
+            return StdTypeList.EMPTY;
+        }
+
+        StdTypeList result = new StdTypeList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            result.set(i, get(i).getExceptionClass().getClassType());
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Item in an exception handler list.
+     */
+    public static class Item {
+        /** {@code >= 0;} the start pc (inclusive) of the handler's range */
+        private final int startPc;
+
+        /** {@code >= startPc;} the end pc (exclusive) of the handler's range */
+        private final int endPc;
+
+        /** {@code >= 0;} the pc of the exception handler */
+        private final int handlerPc;
+
+        /** {@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 {@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 {@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) {
+            if (startPc < 0) {
+                throw new IllegalArgumentException("startPc < 0");
+            }
+
+            if (endPc < startPc) {
+                throw new IllegalArgumentException("endPc < startPc");
+            }
+
+            if (handlerPc < 0) {
+                throw new IllegalArgumentException("handlerPc < 0");
+            }
+
+            this.startPc = startPc;
+            this.endPc = endPc;
+            this.handlerPc = handlerPc;
+            this.exceptionClass = exceptionClass;
+        }
+
+        /**
+         * Gets 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;
+        }
+
+        /**
+         * Gets the end pc (exclusive) of the handler's range.
+         *
+         * @return {@code >= startPc;} the end pc (exclusive) of the
+         * handler's range.
+         */
+        public int getEndPc() {
+            return endPc;
+        }
+
+        /**
+         * Gets the pc of the exception handler.
+         *
+         * @return {@code >= 0;} the pc of the exception handler
+         */
+        public int getHandlerPc() {
+            return handlerPc;
+        }
+
+        /**
+         * Gets the class of exception handled.
+         *
+         * @return {@code non-null;} the exception class; {@link CstType#OBJECT}
+         * if this entry handles all possible exceptions
+         */
+        public CstType getExceptionClass() {
+            return (exceptionClass != null) ?
+                exceptionClass : CstType.OBJECT;
+        }
+
+        /**
+         * Returns whether the given address is in the range of this item.
+         *
+         * @param pc the address
+         * @return {@code true} iff this item covers {@code pc}
+         */
+        public boolean covers(int pc) {
+            return (pc >= startPc) && (pc < endPc);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/Field.java b/dexgen/src/com/android/dexgen/rop/Field.java
new file mode 100644
index 0000000..3e0364b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/Field.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.rop.cst.TypedConstant;
+
+/**
+ * Interface representing fields of class files.
+ */
+public interface Field
+        extends Member {
+    /**
+     * Get the constant value for this field, if any. This only returns
+     * non-{@code null} for a {@code static final} field which
+     * includes a {@code ConstantValue} attribute.
+     *
+     * @return {@code null-ok;} the constant value, or {@code null} if this
+     * field isn't a constant
+     */
+    public TypedConstant getConstantValue();
+}
diff --git a/dexgen/src/com/android/dexgen/rop/FieldList.java b/dexgen/src/com/android/dexgen/rop/FieldList.java
new file mode 100644
index 0000000..ab4f28f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/FieldList.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+/**
+ * Interface for lists of fields.
+ */
+public interface FieldList
+{
+    /**
+     * Get whether this instance is mutable. Note that the
+     * {@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} iff this instance is somehow mutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Get the number of fields in the list.
+     *
+     * @return the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th field.
+     *
+     * @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/dexgen/src/com/android/dexgen/rop/LineNumberList.java b/dexgen/src/com/android/dexgen/rop/LineNumberList.java
new file mode 100644
index 0000000..f780066
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/LineNumberList.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * List of "line number" entries, which are the contents of
+ * {@code LineNumberTable} attributes.
+ */
+public final class LineNumberList extends FixedSizeList {
+    /** {@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 {@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) {
+        if (list1 == EMPTY) {
+            // easy case
+            return list2;
+        }
+
+        int sz1 = list1.size();
+        int sz2 = list2.size();
+        LineNumberList result = new LineNumberList(sz1 + sz2);
+
+        for (int i = 0; i < sz1; i++) {
+            result.set(i, list1.get(i));
+        }
+
+        for (int i = 0; i < sz2; i++) {
+            result.set(sz1 + i, list2.get(i));
+        }
+
+        return result;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param count the number of elements to be in the list
+     */
+    public LineNumberList(int count) {
+        super(count);
+    }
+
+    /**
+     * Gets 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);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param item {@code non-null;} the item
+     */
+    public void set(int n, Item item) {
+        if (item == null) {
+            throw new NullPointerException("item == null");
+        }
+
+        set0(n, item);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param startPc {@code >= 0;} start pc of this item
+     * @param lineNumber {@code >= 0;} corresponding line number
+     */
+    public void set(int n, int startPc, int lineNumber) {
+        set0(n, new Item(startPc, lineNumber));
+    }
+
+    /**
+     * Gets the line number associated with the given address.
+     *
+     * @param pc {@code >= 0;} the address to look up
+     * @return {@code >= -1;} the associated line number, or {@code -1} if
+     * none is known
+     */
+    public int pcToLine(int pc) {
+        /*
+         * Line number entries don't have to appear in any particular
+         * order, so we have to do a linear search. TODO: If
+         * this turns out to be a bottleneck, consider sorting the
+         * list prior to use.
+         */
+        int sz = size();
+        int bestPc = -1;
+        int bestLine = -1;
+
+        for (int i = 0; i < sz; i++) {
+            Item one = get(i);
+            int onePc = one.getStartPc();
+            if ((onePc <= pc) && (onePc > bestPc)) {
+                bestPc = onePc;
+                bestLine = one.getLineNumber();
+                if (bestPc == pc) {
+                    // We can't do better than this
+                    break;
+                }
+            }
+        }
+
+        return bestLine;
+    }
+
+    /**
+     * Item in a line number table.
+     */
+    public static class Item {
+        /** {@code >= 0;} start pc of this item */
+        private final int startPc;
+
+        /** {@code >= 0;} corresponding line number */
+        private final int lineNumber;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("startPc < 0");
+            }
+
+            if (lineNumber < 0) {
+                throw new IllegalArgumentException("lineNumber < 0");
+            }
+
+            this.startPc = startPc;
+            this.lineNumber = lineNumber;
+        }
+
+        /**
+         * Gets the start pc of this item.
+         *
+         * @return the start pc
+         */
+        public int getStartPc() {
+            return startPc;
+        }
+
+        /**
+         * Gets the line number of this item.
+         *
+         * @return the line number
+         */
+        public int getLineNumber() {
+            return lineNumber;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/Member.java b/dexgen/src/com/android/dexgen/rop/Member.java
new file mode 100644
index 0000000..dfc17be
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/Member.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.rop.cst.CstNat;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+
+/**
+ * Interface representing members of class files (that is, fields and methods).
+ */
+public interface Member {
+    /**
+     * Get the defining class.
+     *
+     * @return {@code non-null;} the defining class
+     */
+    public CstType getDefiningClass();
+
+    /**
+     * Get the field {@code access_flags}.
+     *
+     * @return the access flags
+     */
+    public int getAccessFlags();
+
+    /**
+     * Get the field {@code name_index} of the member. This is
+     * just a convenient shorthand for {@code getNat().getName()}.
+     *
+     * @return {@code non-null;} the name
+     */
+    public CstUtf8 getName();
+
+    /**
+     * Get the field {@code descriptor_index} of the member. This is
+     * just a convenient shorthand for {@code getNat().getDescriptor()}.
+     *
+     * @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} and
+     * {@code descriptor_index} in the original classfile, interpreted
+     * via the constant pool.
+     *
+     * @return {@code non-null;} the name and type
+     */
+    public CstNat getNat();
+
+    /**
+     * Get the field {@code attributes} (along with
+     * {@code attributes_count}).
+     *
+     * @return {@code non-null;} the constant pool
+     */
+    public AttributeList getAttributes();
+}
diff --git a/dexgen/src/com/android/dexgen/rop/StdAttributeList.java b/dexgen/src/com/android/dexgen/rop/StdAttributeList.java
new file mode 100644
index 0000000..bebee21
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/StdAttributeList.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link AttributeList}, which directly stores
+ * an array of {@link Attribute} objects and can be made immutable.
+ */
+public final class StdAttributeList extends FixedSizeList
+        implements AttributeList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdAttributeList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Attribute get(int n) {
+        return (Attribute) get0(n);
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        int sz = size();
+        int result = 2; // u2 attributes_count
+
+        for (int i = 0; i < sz; i++) {
+            result += get(i).byteLength();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public Attribute findFirst(String name) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            Attribute att = get(i);
+            if (att.getName().equals(name)) {
+                return att;
+            }
+        }
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public Attribute findNext(Attribute attrib) {
+        int sz = size();
+        int at;
+
+        outer: {
+            for (at = 0; at < sz; at++) {
+                Attribute att = get(at);
+                if (att == attrib) {
+                    break outer;
+                }
+            }
+
+            return null;
+        }
+
+        String name = attrib.getName();
+
+        for (at++; at < sz; at++) {
+            Attribute att = get(at);
+            if (att.getName().equals(name)) {
+                return att;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets the attribute at the given index.
+     *
+     * @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/dexgen/src/com/android/dexgen/rop/StdField.java b/dexgen/src/com/android/dexgen/rop/StdField.java
new file mode 100644
index 0000000..9adcc30
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/StdField.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.rop.cst.CstNat;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.cst.TypedConstant;
+
+/**
+ * Standard implementation of {@link Field}, which directly stores
+ * all the associated data.
+ */
+public final class StdField extends StdMember implements Field {
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the defining class
+     * @param accessFlags access flags
+     * @param nat {@code non-null;} member name and type (descriptor)
+     * @param attributes {@code non-null;} list of associated attributes
+     */
+    public StdField(CstType definingClass, int accessFlags, CstNat nat,
+                    AttributeList attributes) {
+        super(definingClass, accessFlags, nat, attributes);
+    }
+
+    /**
+     * Constructs an instance having Java field as its pattern.
+     *
+     * @param field {@code non-null;} pattern for dex field
+     */
+    public StdField(java.lang.reflect.Field field) {
+        this(CstType.intern(field.getDeclaringClass()),
+                field.getModifiers(),
+                new CstNat(new CstUtf8(field.getName()),
+                        CstType.intern(field.getType()).getDescriptor()),
+                new StdAttributeList(0));
+    }
+
+    /**
+     * Constructs an instance taking field description as user-friendly arguments.
+     *
+     * @param declaringClass {@code non-null;} the class field belongs to
+     * @param type {@code non-null;} type of the field
+     * @param name {@code non-null;} name of the field
+     * @param modifiers access flags of the field
+     */
+    public StdField(Class definingClass, Class type, String name, int modifiers) {
+        this(CstType.intern(definingClass),
+                modifiers,
+                new CstNat(new CstUtf8(name), CstType.intern(type).getDescriptor()),
+                new StdAttributeList(0));
+    }
+
+    /** {@inheritDoc} */
+    public TypedConstant getConstantValue() {
+        AttributeList attribs = getAttributes();
+        AttConstantValue cval = (AttConstantValue)
+            attribs.findFirst(AttConstantValue.ATTRIBUTE_NAME);
+
+        if (cval == null) {
+            return null;
+        }
+
+        return cval.getConstantValue();
+    }
+}
\ No newline at end of file
diff --git a/dexgen/src/com/android/dexgen/rop/StdFieldList.java b/dexgen/src/com/android/dexgen/rop/StdFieldList.java
new file mode 100644
index 0000000..ccb7465
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/StdFieldList.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link FieldList}, which directly stores
+ * an array of {@link Field} objects and can be made immutable.
+ */
+public final class StdFieldList extends FixedSizeList implements FieldList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdFieldList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Field get(int n) {
+        return (Field) get0(n);
+    }
+
+    /**
+     * Sets the field at the given index.
+     *
+     * @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/dexgen/src/com/android/dexgen/rop/StdMember.java b/dexgen/src/com/android/dexgen/rop/StdMember.java
new file mode 100644
index 0000000..6c46051
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/StdMember.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop;
+
+import com.android.dexgen.rop.cst.CstNat;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+
+/**
+ * Standard implementation of {@link Member}, which directly stores
+ * all the associated data.
+ */
+public abstract class StdMember implements Member {
+    /** {@code non-null;} the defining class */
+    private final CstType definingClass;
+
+    /** access flags */
+    private final int accessFlags;
+
+    /** {@code non-null;} member name and type */
+    private final CstNat nat;
+
+    /** {@code non-null;} list of associated attributes */
+    private final AttributeList attributes;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the defining class
+     * @param accessFlags access flags
+     * @param nat {@code non-null;} member name and type (descriptor)
+     * @param attributes {@code non-null;} list of associated attributes
+     */
+    public StdMember(CstType definingClass, int accessFlags, CstNat nat,
+                     AttributeList attributes) {
+        if (definingClass == null) {
+            throw new NullPointerException("definingClass == null");
+        }
+
+        if (nat == null) {
+            throw new NullPointerException("nat == null");
+        }
+
+        if (attributes == null) {
+            throw new NullPointerException("attributes == null");
+        }
+
+        this.definingClass = definingClass;
+        this.accessFlags = accessFlags;
+        this.nat = nat;
+        this.attributes = attributes;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(nat.toHuman());
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    public final CstType getDefiningClass() {
+        return definingClass;
+    }
+
+    /** {@inheritDoc} */
+    public final int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /** {@inheritDoc} */
+    public final CstNat getNat() {
+        return nat;
+    }
+
+    /** {@inheritDoc} */
+    public final CstUtf8 getName() {
+        return nat.getName();
+    }
+
+    /** {@inheritDoc} */
+    public final CstUtf8 getDescriptor() {
+        return nat.getDescriptor();
+    }
+
+    /** {@inheritDoc} */
+    public final AttributeList getAttributes() {
+        return attributes;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/annotation/Annotation.java b/dexgen/src/com/android/dexgen/rop/annotation/Annotation.java
new file mode 100644
index 0000000..918d2bc
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/annotation/Annotation.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.annotation;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstAnnotation;
+import com.android.dexgen.rop.cst.CstFieldRef;
+import com.android.dexgen.rop.cst.CstLiteralBits;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstNat;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.cst.TypedConstant;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.MutabilityControl;
+import com.android.dexgen.util.ToHuman;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+/**
+ * An annotation on an element of a class. Annotations have an
+ * associated type and additionally consist of a set of (name, value)
+ * pairs, where the names are unique.
+ */
+public final class Annotation extends MutabilityControl
+        implements Comparable<Annotation>, ToHuman {
+    /** {@code non-null;} type of the annotation */
+    private final CstType type;
+
+    /** {@code non-null;} the visibility of the annotation */
+    private final AnnotationVisibility visibility;
+
+    /** {@code non-null;} map from names to {@link NameValuePair} instances */
+    private final TreeMap<CstUtf8, NameValuePair> elements;
+
+    /**
+     * Construct an instance. It initially contains no elements.
+     *
+     * @param type {@code non-null;} type of the annotation
+     * @param visibility {@code non-null;} the visibility of the annotation
+     */
+    public Annotation(CstType type, AnnotationVisibility visibility) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (visibility == null) {
+            throw new NullPointerException("visibility == null");
+        }
+
+        this.type = type;
+        this.visibility = visibility;
+        this.elements = new TreeMap<CstUtf8, NameValuePair>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof Annotation)) {
+            return false;
+        }
+
+        Annotation otherAnnotation = (Annotation) other;
+
+        if (! (type.equals(otherAnnotation.type)
+                        && (visibility == otherAnnotation.visibility))) {
+            return false;
+        }
+
+        return elements.equals(otherAnnotation.elements);
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        int hash = type.hashCode();
+        hash = (hash * 31) + elements.hashCode();
+        hash = (hash * 31) + visibility.hashCode();
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Annotation other) {
+        int result = type.compareTo(other.type);
+
+        if (result != 0) {
+            return result;
+        }
+
+        result = visibility.compareTo(other.visibility);
+
+        if (result != 0) {
+            return result;
+        }
+
+        Iterator<NameValuePair> thisIter = elements.values().iterator();
+        Iterator<NameValuePair> otherIter = other.elements.values().iterator();
+
+        while (thisIter.hasNext() && otherIter.hasNext()) {
+            NameValuePair thisOne = thisIter.next();
+            NameValuePair otherOne = otherIter.next();
+
+            result = thisOne.compareTo(otherOne);
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (thisIter.hasNext()) {
+            return 1;
+        } else if (otherIter.hasNext()) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toHuman();
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(visibility.toHuman());
+        sb.append("-annotation ");
+        sb.append(type.toHuman());
+        sb.append(" {");
+
+        boolean first = true;
+        for (NameValuePair pair : elements.values()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(pair.getName().toHuman());
+            sb.append(": ");
+            sb.append(pair.getValue().toHuman());
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Gets the type of this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public CstType getType() {
+        return type;
+    }
+
+    /**
+     * Gets the visibility of this instance.
+     *
+     * @return {@code non-null;} the visibility
+     */
+    public AnnotationVisibility getVisibility() {
+        return visibility;
+    }
+
+    /**
+     * Put an element into the set of (name, value) pairs for this instance.
+     * If there is a preexisting element with the same name, it will be
+     * replaced by this method.
+     *
+     * @param pair {@code non-null;} the (name, value) pair to place into this instance
+     */
+    public void put(NameValuePair pair) {
+        throwIfImmutable();
+
+        if (pair == null) {
+            throw new NullPointerException("pair == null");
+        }
+
+        elements.put(pair.getName(), pair);
+    }
+
+    /**
+     * Add an element to the set of (name, value) pairs for this instance.
+     * It is an error to call this method if there is a preexisting element
+     * with the same name.
+     *
+     * @param pair {@code non-null;} the (name, value) pair to add to this instance
+     */
+    public void add(NameValuePair pair) {
+        throwIfImmutable();
+
+        if (pair == null) {
+            throw new NullPointerException("pair == null");
+        }
+
+        CstUtf8 name = pair.getName();
+
+        if (elements.get(name) != null) {
+            throw new IllegalArgumentException("name already added: " + name);
+        }
+
+        elements.put(name, pair);
+    }
+
+    /**
+     * Gets the set of name-value pairs contained in this instance. The
+     * result is always unmodifiable.
+     *
+     * @return {@code non-null;} the set of name-value pairs
+     */
+    public Collection<NameValuePair> getNameValuePairs() {
+        return Collections.unmodifiableCollection(elements.values());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/annotation/AnnotationVisibility.java b/dexgen/src/com/android/dexgen/rop/annotation/AnnotationVisibility.java
new file mode 100644
index 0000000..5239164
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/annotation/AnnotationVisibility.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.annotation;
+
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * Visibility scope of an annotation.
+ */
+public enum AnnotationVisibility implements ToHuman {
+    RUNTIME("runtime"),
+    BUILD("build"),
+    SYSTEM("system"),
+    EMBEDDED("embedded");
+
+    /** {@code non-null;} the human-oriented string representation */
+    private final String human;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param human {@code non-null;} the human-oriented string representation
+     */
+    private AnnotationVisibility(String human) {
+        this.human = human;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return human;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/annotation/Annotations.java b/dexgen/src/com/android/dexgen/rop/annotation/Annotations.java
new file mode 100644
index 0000000..a7eca04
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/annotation/Annotations.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.annotation;
+
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.util.MutabilityControl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+/**
+ * List of {@link Annotation} instances.
+ */
+public final class Annotations extends MutabilityControl
+        implements Comparable<Annotations> {
+    /** {@code non-null;} immutable empty instance */
+    public static final Annotations EMPTY = new Annotations();
+
+    static {
+        EMPTY.setImmutable();
+    }
+
+    /** {@code non-null;} map from types to annotations */
+    private final TreeMap<CstType, Annotation> annotations;
+
+    /**
+     * Constructs an immutable instance which is the combination of the
+     * two given instances. The two instances must contain disjoint sets
+     * of types.
+     *
+     * @param a1 {@code non-null;} an instance
+     * @param a2 {@code non-null;} the other instance
+     * @return {@code non-null;} the combination
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public static Annotations combine(Annotations a1, Annotations a2) {
+        Annotations result = new Annotations();
+
+        result.addAll(a1);
+        result.addAll(a2);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs an immutable instance which is the combination of the
+     * given instance with the given additional annotation. The latter's
+     * type must not already appear in the former.
+     *
+     * @param annotations {@code non-null;} the instance to augment
+     * @param annotation {@code non-null;} the additional annotation
+     * @return {@code non-null;} the combination
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public static Annotations combine(Annotations annotations,
+            Annotation annotation) {
+        Annotations result = new Annotations();
+
+        result.addAll(annotations);
+        result.add(annotation);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs an empty instance.
+     */
+    public Annotations() {
+        annotations = new TreeMap<CstType, Annotation>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotations.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof Annotations)) {
+            return false;
+        }
+
+        Annotations otherAnnotations = (Annotations) other;
+
+        return annotations.equals(otherAnnotations.annotations);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Annotations other) {
+        Iterator<Annotation> thisIter = annotations.values().iterator();
+        Iterator<Annotation> otherIter = other.annotations.values().iterator();
+
+        while (thisIter.hasNext() && otherIter.hasNext()) {
+            Annotation thisOne = thisIter.next();
+            Annotation otherOne = otherIter.next();
+
+            int result = thisOne.compareTo(otherOne);
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (thisIter.hasNext()) {
+            return 1;
+        } else if (otherIter.hasNext()) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+
+        sb.append("annotations{");
+
+        for (Annotation a : annotations.values()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(a.toHuman());
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Gets the number of elements in this instance.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        return annotations.size();
+    }
+
+    /**
+     * Adds an element to this instance. There must not already be an
+     * element of the same type.
+     *
+     * @param annotation {@code non-null;} the element to add
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public void add(Annotation annotation) {
+        throwIfImmutable();
+
+        if (annotation == null) {
+            throw new NullPointerException("annotation == null");
+        }
+
+        CstType type = annotation.getType();
+
+        if (annotations.containsKey(type)) {
+            throw new IllegalArgumentException("duplicate type: " +
+                    type.toHuman());
+        }
+
+        annotations.put(type, annotation);
+    }
+
+    /**
+     * Adds all of the elements of the given instance to this one. The
+     * instances must not have any duplicate types.
+     *
+     * @param toAdd {@code non-null;} the annotations to add
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public void addAll(Annotations toAdd) {
+        throwIfImmutable();
+
+        if (toAdd == null) {
+            throw new NullPointerException("toAdd == null");
+        }
+
+        for (Annotation a : toAdd.annotations.values()) {
+            add(a);
+        }
+    }
+
+    /**
+     * Gets the set of annotations contained in this instance. The
+     * result is always unmodifiable.
+     *
+     * @return {@code non-null;} the set of annotations
+     */
+    public Collection<Annotation> getAnnotations() {
+        return Collections.unmodifiableCollection(annotations.values());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/annotation/AnnotationsList.java b/dexgen/src/com/android/dexgen/rop/annotation/AnnotationsList.java
new file mode 100644
index 0000000..1159932
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/annotation/AnnotationsList.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.annotation;
+
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * List of {@link Annotations} instances.
+ */
+public final class AnnotationsList
+        extends FixedSizeList {
+    /** {@code non-null;} immutable empty instance */
+    public static final AnnotationsList EMPTY = new AnnotationsList(0);
+
+    /**
+     * Constructs an immutable instance which is the combination of
+     * the two given instances. The two instances must each have the
+     * same number of elements, and each pair of elements must contain
+     * disjoint sets of types.
+     *
+     * @param list1 {@code non-null;} an instance
+     * @param list2 {@code non-null;} the other instance
+     * @return {@code non-null;} the combination
+     */
+    public static AnnotationsList combine(AnnotationsList list1,
+            AnnotationsList list2) {
+        int size = list1.size();
+
+        if (size != list2.size()) {
+            throw new IllegalArgumentException("list1.size() != list2.size()");
+        }
+
+        AnnotationsList result = new AnnotationsList(size);
+
+        for (int i = 0; i < size; i++) {
+            Annotations a1 = list1.get(i);
+            Annotations a2 = list2.get(i);
+            result.set(i, Annotations.combine(a1, a2));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public AnnotationsList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Annotations get(int n) {
+        return (Annotations) get0(n);
+    }
+
+    /**
+     * Sets the element at the given index. The given element must be
+     * immutable.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param a {@code null-ok;} the element to set at {@code n}
+     */
+    public void set(int n, Annotations a) {
+        a.throwIfMutable();
+        set0(n, a);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/annotation/NameValuePair.java b/dexgen/src/com/android/dexgen/rop/annotation/NameValuePair.java
new file mode 100644
index 0000000..9f96f14
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/annotation/NameValuePair.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.annotation;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstString;
+import com.android.dexgen.rop.cst.CstUtf8;
+
+/**
+ * A (name, value) pair. These are used as the contents of an annotation.
+ */
+public final class NameValuePair implements Comparable<NameValuePair> {
+    /** {@code non-null;} the name */
+    private final CstUtf8 name;
+
+    /** {@code non-null;} the value */
+    private final Constant value;
+
+    /**
+     * Construct an instance.
+     *
+     * @param name {@code non-null;} the name
+     * @param value {@code non-null;} the value
+     */
+    public NameValuePair(CstUtf8 name, Constant value) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        // Reject CstUtf8 values. (They should be CstStrings.)
+        if (value instanceof CstUtf8) {
+            throw new IllegalArgumentException("bad value: " + value);
+        }
+
+        this.name = name;
+        this.value = value;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return name.toHuman() + ":" + value;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return name.hashCode() * 31 + value.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof NameValuePair)) {
+            return false;
+        }
+
+        NameValuePair otherPair = (NameValuePair) other;
+
+        return name.equals(otherPair.name)
+            && value.equals(otherPair.value);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Instances of this class compare in name-major and value-minor
+     * order.</p>
+     */
+    public int compareTo(NameValuePair other) {
+        int result = name.compareTo(other.name);
+
+        if (result != 0) {
+            return result;
+        }
+
+        return value.compareTo(other.value);
+    }
+
+    /**
+     * Gets the name.
+     *
+     * @return {@code non-null;} the name
+     */
+    public CstUtf8 getName() {
+        return name;
+    }
+
+    /**
+     * Gets the value.
+     *
+     * @return {@code non-null;} the value
+     */
+    public Constant getValue() {
+        return value;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/AccessFlags.java b/dexgen/src/com/android/dexgen/rop/code/AccessFlags.java
new file mode 100644
index 0000000..4a8b435
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/AccessFlags.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants used as "access flags" in various places in classes, and
+ * 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} isn't
+ * used at all in translated code, and {@code ACC_SYNCHRONIZED}
+ * is only used in a very limited way.
+ */
+public final class AccessFlags {
+    /** public member / class */
+    public static final int ACC_PUBLIC = 0x0001;
+
+    /** private member */
+    public static final int ACC_PRIVATE = 0x0002;
+
+    /** protected member */
+    public static final int ACC_PROTECTED = 0x0004;
+
+    /** static member */
+    public static final int ACC_STATIC = 0x0008;
+
+    /** final member / class */
+    public static final int ACC_FINAL = 0x0010;
+
+    /**
+     * synchronized method; only valid in dex files for {@code native}
+     * methods
+     */
+    public static final int ACC_SYNCHRONIZED = 0x0020;
+
+    /**
+     * class with new-style {@code invokespecial} for superclass
+     * method access
+     */
+    public static final int ACC_SUPER = 0x0020;
+
+    /** volatile field */
+    public static final int ACC_VOLATILE = 0x0040;
+
+    /** bridge method (generated) */
+    public static final int ACC_BRIDGE = 0x0040;
+
+    /** transient field */
+    public static final int ACC_TRANSIENT = 0x0080;
+
+    /** varargs method */
+    public static final int ACC_VARARGS = 0x0080;
+
+    /** native method */
+    public static final int ACC_NATIVE = 0x0100;
+
+    /** "class" is in fact an public static final interface */
+    public static final int ACC_INTERFACE = 0x0200;
+
+    /** abstract method / class */
+    public static final int ACC_ABSTRACT = 0x0400;
+
+    /**
+     * method with strict floating point ({@code strictfp})
+     * behavior
+     */
+    public static final int ACC_STRICT = 0x0800;
+
+    /** synthetic member */
+    public static final int ACC_SYNTHETIC = 0x1000;
+
+    /** class is an annotation type */
+    public static final int ACC_ANNOTATION = 0x2000;
+
+    /**
+     * class is an enumerated type; field is an element of an enumerated
+     * type
+     */
+    public static final int ACC_ENUM = 0x4000;
+
+    /** method is a constructor */
+    public static final int ACC_CONSTRUCTOR = 0x10000;
+
+    /**
+     * 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;
+
+    /** flags defined on classes */
+    public static final int CLASS_FLAGS =
+        ACC_PUBLIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE | ACC_ABSTRACT |
+        ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM;
+
+    /** flags defined on inner classes */
+    public static final int INNER_CLASS_FLAGS =
+        ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
+        ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION |
+        ACC_ENUM;
+
+    /** flags defined on fields */
+    public static final int FIELD_FLAGS =
+        ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
+        ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM;
+
+    /** flags defined on methods */
+    public static final int METHOD_FLAGS =
+        ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
+        ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
+        ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR |
+        ACC_DECLARED_SYNCHRONIZED;
+
+    /** indicates conversion of class flags */
+    private static final int CONV_CLASS = 1;
+
+    /** indicates conversion of field flags */
+    private static final int CONV_FIELD = 2;
+
+    /** indicates conversion of method flags */
+    private static final int CONV_METHOD = 3;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private AccessFlags() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on classes (not fields or methods).
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String classString(int flags) {
+        return humanHelper(flags, CLASS_FLAGS, CONV_CLASS);
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on inner classes.
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String innerClassString(int flags) {
+        return humanHelper(flags, INNER_CLASS_FLAGS, CONV_CLASS);
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on fields (not classes or methods).
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String fieldString(int flags) {
+        return humanHelper(flags, FIELD_FLAGS, CONV_FIELD);
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on methods (not classes or fields).
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String methodString(int flags) {
+        return humanHelper(flags, METHOD_FLAGS, CONV_METHOD);
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_PUBLIC} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_PUBLIC} flag
+     */
+    public static boolean isPublic(int flags) {
+        return (flags & ACC_PUBLIC) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_PROTECTED} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_PROTECTED} flag
+     */
+    public static boolean isProtected(int flags) {
+        return (flags & ACC_PROTECTED) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_PRIVATE} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_PRIVATE} flag
+     */
+    public static boolean isPrivate(int flags) {
+        return (flags & ACC_PRIVATE) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_STATIC} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_STATIC} flag
+     */
+    public static boolean isStatic(int flags) {
+        return (flags & ACC_STATIC) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_SYNCHRONIZED} is on in
+     * the given flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_SYNCHRONIZED} flag
+     */
+    public static boolean isSynchronized(int flags) {
+        return (flags & ACC_SYNCHRONIZED) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_ABSTRACT} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_ABSTRACT} flag
+     */
+    public static boolean isAbstract(int flags) {
+        return (flags & ACC_ABSTRACT) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_NATIVE} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_NATIVE} flag
+     */
+    public static boolean isNative(int flags) {
+        return (flags & ACC_NATIVE) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_ANNOTATION} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_ANNOTATION} flag
+     */
+    public static boolean isAnnotation(int flags) {
+        return (flags & ACC_ANNOTATION) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_DECLARED_SYNCHRONIZED} is
+     * on in the given flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_DECLARED_SYNCHRONIZED} flag
+     */
+    public static boolean isDeclaredSynchronized(int flags) {
+        return (flags & ACC_DECLARED_SYNCHRONIZED) != 0;
+    }
+
+    /**
+     * Helper to return a human-oriented string representing the given
+     * access flags.
+     *
+     * @param flags the defined flags
+     * @param mask mask for the "defined" bits
+     * @param what what the flags represent (one of {@code CONV_*})
+     * @return {@code non-null;} human-oriented string
+     */
+    private static String humanHelper(int flags, int mask, int what) {
+        StringBuffer sb = new StringBuffer(80);
+        int extra = flags & ~mask;
+
+        flags &= mask;
+
+        if ((flags & ACC_PUBLIC) != 0) {
+            sb.append("|public");
+        }
+        if ((flags & ACC_PRIVATE) != 0) {
+            sb.append("|private");
+        }
+        if ((flags & ACC_PROTECTED) != 0) {
+            sb.append("|protected");
+        }
+        if ((flags & ACC_STATIC) != 0) {
+            sb.append("|static");
+        }
+        if ((flags & ACC_FINAL) != 0) {
+            sb.append("|final");
+        }
+        if ((flags & ACC_SYNCHRONIZED) != 0) {
+            if (what == CONV_CLASS) {
+                sb.append("|super");
+            } else {
+                sb.append("|synchronized");
+            }
+        }
+        if ((flags & ACC_VOLATILE) != 0) {
+            if (what == CONV_METHOD) {
+                sb.append("|bridge");
+            } else {
+                sb.append("|volatile");
+            }
+        }
+        if ((flags & ACC_TRANSIENT) != 0) {
+            if (what == CONV_METHOD) {
+                sb.append("|varargs");
+            } else {
+                sb.append("|transient");
+            }
+        }
+        if ((flags & ACC_NATIVE) != 0) {
+            sb.append("|native");
+        }
+        if ((flags & ACC_INTERFACE) != 0) {
+            sb.append("|interface");
+        }
+        if ((flags & ACC_ABSTRACT) != 0) {
+            sb.append("|abstract");
+        }
+        if ((flags & ACC_STRICT) != 0) {
+            sb.append("|strictfp");
+        }
+        if ((flags & ACC_SYNTHETIC) != 0) {
+            sb.append("|synthetic");
+        }
+        if ((flags & ACC_ANNOTATION) != 0) {
+            sb.append("|annotation");
+        }
+        if ((flags & ACC_ENUM) != 0) {
+            sb.append("|enum");
+        }
+        if ((flags & ACC_CONSTRUCTOR) != 0) {
+            sb.append("|constructor");
+        }
+        if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
+            sb.append("|declared_synchronized");
+        }
+
+        if ((extra != 0) || (sb.length() == 0)) {
+            sb.append('|');
+            sb.append(Hex.u2(extra));
+        }
+
+        return sb.substring(1);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/BasicBlock.java b/dexgen/src/com/android/dexgen/rop/code/BasicBlock.java
new file mode 100644
index 0000000..0f7a59e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/BasicBlock.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.IntList;
+import com.android.dexgen.util.LabeledItem;
+
+/**
+ * Basic block of register-based instructions.
+ */
+public final class BasicBlock implements LabeledItem {
+    /** {@code >= 0;} target label for this block */
+    private final int label;
+
+    /** {@code non-null;} list of instructions in this block */
+    private final InsnList insns;
+
+    /**
+     * {@code non-null;} full list of successors that this block may
+     * branch to
+     */
+    private final IntList successors;
+
+    /**
+     * {@code >= -1;} the primary / standard-flow / "default" successor, or
+     * {@code -1} if this block has no successors (that is, it
+     * exits the function/method)
+     */
+    private final int primarySuccessor;
+
+    /**
+     * Constructs an instance. The predecessor set is set to {@code null}.
+     *
+     * @param label {@code >= 0;} target label for this block
+     * @param insns {@code non-null;} list of instructions in this block
+     * @param successors {@code non-null;} full list of successors that this
+     * block may branch to
+     * @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)
+     */
+    public BasicBlock(int label, InsnList insns, IntList successors,
+                      int primarySuccessor) {
+        if (label < 0) {
+            throw new IllegalArgumentException("label < 0");
+        }
+
+        try {
+            insns.throwIfMutable();
+        } catch (NullPointerException ex) {
+            // Elucidate exception.
+            throw new NullPointerException("insns == null");
+        }
+
+        int sz = insns.size();
+
+        if (sz == 0) {
+            throw new IllegalArgumentException("insns.size() == 0");
+        }
+
+        for (int i = sz - 2; i >= 0; i--) {
+            Rop one = insns.get(i).getOpcode();
+            if (one.getBranchingness() != Rop.BRANCH_NONE) {
+                throw new IllegalArgumentException("insns[" + i + "] is a " +
+                                                   "branch or can throw");
+            }
+        }
+
+        Insn lastInsn = insns.get(sz - 1);
+        if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("insns does not end with " +
+                                               "a branch or throwing " +
+                                               "instruction");
+        }
+
+        try {
+            successors.throwIfMutable();
+        } catch (NullPointerException ex) {
+            // Elucidate exception.
+            throw new NullPointerException("successors == null");
+        }
+
+        if (primarySuccessor < -1) {
+            throw new IllegalArgumentException("primarySuccessor < -1");
+        }
+
+        if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) {
+            throw new IllegalArgumentException(
+                    "primarySuccessor not in successors");
+        }
+
+        this.label = label;
+        this.insns = insns;
+        this.successors = successors;
+        this.primarySuccessor = primarySuccessor;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Instances of this class compare by identity. That is,
+     * {@code x.equals(y)} is only true if {@code x == y}.
+     */
+    @Override
+    public boolean equals(Object other) {
+        return (this == other);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Return the identity hashcode of this instance. This is proper,
+     * since instances of this class compare by identity (see {@link #equals}).
+     */
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    /**
+     * Gets the target label of this block.
+     *
+     * @return {@code >= 0;} the label
+     */
+    public int getLabel() {
+        return label;
+    }
+
+    /**
+     * Gets the list of instructions inside this block.
+     *
+     * @return {@code non-null;} the instruction list
+     */
+    public InsnList getInsns() {
+        return insns;
+    }
+
+    /**
+     * Gets the list of successors that this block may branch to.
+     *
+     * @return {@code non-null;} the successors list
+     */
+    public IntList getSuccessors() {
+        return successors;
+    }
+
+    /**
+     * Gets the primary successor of this block.
+     *
+     * @return {@code >= -1;} the primary successor, or {@code -1} if this
+     * block has no successors at all
+     */
+    public int getPrimarySuccessor() {
+        return primarySuccessor;
+    }
+
+    /**
+     * Gets the secondary successor of this block. It is only valid to call
+     * this method on blocks that have exactly two successors.
+     *
+     * @return {@code >= 0;} the secondary successor
+     */
+    public int getSecondarySuccessor() {
+        if (successors.size() != 2) {
+            throw new UnsupportedOperationException(
+                    "block doesn't have exactly two successors");
+        }
+
+        int succ = successors.get(0);
+        if (succ == primarySuccessor) {
+            succ = successors.get(1);
+        }
+
+        return succ;
+    }
+
+    /**
+     * Gets the first instruction of this block. This is just a
+     * convenient shorthand for {@code getInsns().get(0)}.
+     *
+     * @return {@code non-null;} the first instruction
+     */
+    public Insn getFirstInsn() {
+        return insns.get(0);
+    }
+
+    /**
+     * Gets the last instruction of this block. This is just a
+     * convenient shorthand for {@code getInsns().getLast()}.
+     *
+     * @return {@code non-null;} the last instruction
+     */
+    public Insn getLastInsn() {
+        return insns.getLast();
+    }
+
+    /**
+     * Returns whether this block might throw an exception. This is
+     * just a convenient shorthand for {@code getLastInsn().canThrow()}.
+     *
+     * @return {@code true} iff this block might throw an
+     * exception
+     */
+    public boolean canThrow() {
+        return insns.getLast().canThrow();
+    }
+
+    /**
+     * Returns whether this block has any associated exception handlers.
+     * This is just a shorthand for inspecting the last instruction in
+     * the block to see if it could throw, and if so, whether it in fact
+     * has any associated handlers.
+     *
+     * @return {@code true} iff this block has any associated
+     * exception handlers
+     */
+    public boolean hasExceptionHandlers() {
+        Insn lastInsn = insns.getLast();
+        return lastInsn.getCatches().size() != 0;
+    }
+
+    /**
+     * Returns the exception handler types associated with this block,
+     * 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}).
+     *
+     * @return {@code non-null;} the exception handler types associated with
+     * this block
+     */
+    public TypeList getExceptionHandlerTypes() {
+        Insn lastInsn = insns.getLast();
+        return lastInsn.getCatches();
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public BasicBlock withRegisterOffset(int delta) {
+        return new BasicBlock(label, insns.withRegisterOffset(delta),
+                              successors, primarySuccessor);
+    }
+
+    public String toString() {
+        return '{' + Hex.u2(label) + '}';
+    }
+
+    /**
+     * BasicBlock visitor interface
+     */
+    public interface Visitor {
+        /**
+         * Visits a basic block
+         * @param b block visited
+         */
+        public void visitBlock (BasicBlock b);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/BasicBlockList.java b/dexgen/src/com/android/dexgen/rop/code/BasicBlockList.java
new file mode 100644
index 0000000..f01c588
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/BasicBlockList.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.IntList;
+import com.android.dexgen.util.LabeledList;
+
+/**
+ * List of {@link BasicBlock} instances.
+ */
+public final class BasicBlockList extends LabeledList {
+    /**
+     * {@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},
+     * and the first-block label is initially {@code -1}.
+     *
+     * @param size the size of the list
+     */
+    public BasicBlockList(int size) {
+        super(size);
+
+        regCount = -1;
+    }
+
+    /**
+     * Constructs a mutable copy for {@code getMutableCopy()}.
+     *
+     * @param old block to copy
+     */
+    private BasicBlockList (BasicBlockList old) {
+        super(old);
+        regCount = old.regCount;
+    }
+
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public BasicBlock get(int n) {
+        return (BasicBlock) get0(n);
+    }
+
+    /**
+     * Sets the basic block at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param bb {@code null-ok;} the element to set at {@code n}
+     */
+    public void set(int n, BasicBlock bb) {
+        super.set(n, bb);
+
+        // Reset regCount, since it will need to be recalculated.
+        regCount = -1;
+    }
+
+    /**
+     * Returns how many registers this method requires. This is simply
+     * the maximum of register-number-plus-category referred to by this
+     * instance's instructions (indirectly through {@link BasicBlock}
+     * instances).
+     *
+     * @return {@code >= 0;} the register count
+     */
+    public int getRegCount() {
+        if (regCount == -1) {
+            RegCountVisitor visitor = new RegCountVisitor();
+            forEachInsn(visitor);
+            regCount = visitor.getRegCount();
+        }
+
+        return regCount;
+    }
+
+    /**
+     * Gets the total instruction count for this instance. This is the
+     * sum of the instruction counts of each block.
+     *
+     * @return {@code >= 0;} the total instruction count
+     */
+    public int getInstructionCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = (BasicBlock) getOrNull0(i);
+            if (one != null) {
+                result += one.getInsns().size();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the total instruction count for this instance, ignoring
+     * mark-local instructions which are not actually emitted.
+     *
+     * @return {@code >= 0;} the total instruction count
+     */
+    public int getEffectiveInstructionCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = (BasicBlock) getOrNull0(i);
+            if (one != null) {
+                InsnList insns = one.getInsns();
+                int insnsSz = insns.size();
+
+                for (int j = 0; j < insnsSz; j++) {
+                    Insn insn = insns.get(j);
+
+                    if (insn.getOpcode().getOpcode() != RegOps.MARK_LOCAL) {
+                        result++;
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Gets the first block in the list with the given label, if any.
+     *
+     * @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) {
+        int idx = indexOfLabel(label);
+
+        if (idx < 0) {
+            throw new IllegalArgumentException("no such label: "
+                    + Hex.u2(label));
+        }
+
+        return get(idx);
+    }
+
+    /**
+     * Visits each instruction of each block in the list, in order.
+     *
+     * @param visitor {@code non-null;} visitor to use
+     */
+    public void forEachInsn(Insn.Visitor visitor) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = get(i);
+            InsnList insns = one.getInsns();
+            insns.forEach(visitor);
+        }
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount. Mutability of the result is inherited from the
+     * original.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public BasicBlockList withRegisterOffset(int delta) {
+        int sz = size();
+        BasicBlockList result = new BasicBlockList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = (BasicBlock) get0(i);
+            if (one != null) {
+                result.set(i, one.withRegisterOffset(delta));
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a mutable copy of this list.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public BasicBlockList getMutableCopy() {
+        return new BasicBlockList(this);
+    }
+
+    /**
+     * Gets the preferred successor for the given block. If the block
+     * 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}.
+     *
+     * @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();
+        IntList successors = block.getSuccessors();
+        int succSize = successors.size();
+
+        switch (succSize) {
+            case 0: {
+                return null;
+            }
+            case 1: {
+                return labelToBlock(successors.get(0));
+            }
+        }
+
+        if (primarySuccessor != -1) {
+            return labelToBlock(primarySuccessor);
+        } else {
+            return labelToBlock(successors.get(0));
+        }
+    }
+
+    /**
+     * Compares the catches of two blocks for equality. This includes
+     * both the catch types and target labels.
+     *
+     * @param block1 {@code non-null;} one block to compare
+     * @param block2 {@code non-null;} the other block to compare
+     * @return {@code true} if the two blocks' non-primary successors
+     * are identical
+     */
+    public boolean catchesEqual(BasicBlock block1,
+            BasicBlock block2) {
+        TypeList catches1 = block1.getExceptionHandlerTypes();
+        TypeList catches2 = block2.getExceptionHandlerTypes();
+
+        if (!StdTypeList.equalContents(catches1, catches2)) {
+            return false;
+        }
+
+        IntList succ1 = block1.getSuccessors();
+        IntList succ2 = block2.getSuccessors();
+        int size = succ1.size(); // Both are guaranteed to be the same size.
+
+        int primary1 = block1.getPrimarySuccessor();
+        int primary2 = block2.getPrimarySuccessor();
+
+        if (((primary1 == -1) || (primary2 == -1))
+                && (primary1 != primary2)) {
+            /*
+             * For the current purpose, both blocks in question must
+             * either both have a primary or both not have a primary to
+             * be considered equal, and it turns out here that that's not
+             * the case.
+             */
+            return false;
+        }
+
+        for (int i = 0; i < size; i++) {
+            int label1 = succ1.get(i);
+            int label2 = succ2.get(i);
+
+            if (label1 == primary1) {
+                /*
+                 * It should be the case that block2's primary is at the
+                 * same index. If not, we consider the blocks unequal for
+                 * the current purpose.
+                 */
+                if (label2 != primary2) {
+                    return false;
+                }
+                continue;
+            }
+
+            if (label1 != label2) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Instruction visitor class for counting registers used.
+     */
+    private static class RegCountVisitor
+            implements Insn.Visitor {
+        /** {@code >= 0;} register count in-progress */
+        private int regCount;
+
+        /**
+         * Constructs an instance.
+         */
+        public RegCountVisitor() {
+            regCount = 0;
+        }
+
+        /**
+         * Gets the register count.
+         *
+         * @return {@code >= 0;} the count
+         */
+        public int getRegCount() {
+            return regCount;
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainInsn(PlainInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitchInsn(SwitchInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+            visit(insn);
+        }
+
+        /**
+         * Helper for all the {@code visit*} methods.
+         *
+         * @param insn {@code non-null;} instruction being visited
+         */
+        private void visit(Insn insn) {
+            RegisterSpec result = insn.getResult();
+
+            if (result != null) {
+                processReg(result);
+            }
+
+            RegisterSpecList sources = insn.getSources();
+            int sz = sources.size();
+
+            for (int i = 0; i < sz; i++) {
+                processReg(sources.get(i));
+            }
+        }
+
+        /**
+         * Processes the given register spec.
+         *
+         * @param spec {@code non-null;} the register spec
+         */
+        private void processReg(RegisterSpec spec) {
+            int reg = spec.getNextReg();
+
+            if (reg > regCount) {
+                regCount = reg;
+            }
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/ConservativeTranslationAdvice.java b/dexgen/src/com/android/dexgen/rop/code/ConservativeTranslationAdvice.java
new file mode 100644
index 0000000..080432b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/ConservativeTranslationAdvice.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+/**
+ * Implementation of {@link TranslationAdvice} which conservatively answers
+ * {@code false} to all methods.
+ */
+public final class ConservativeTranslationAdvice
+        implements TranslationAdvice {
+    /** {@code non-null;} standard instance of this class */
+    public static final ConservativeTranslationAdvice THE_ONE =
+        new ConservativeTranslationAdvice();
+
+    /**
+     * This class is not publicly instantiable. Use {@link #THE_ONE}.
+     */
+    private ConservativeTranslationAdvice() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasConstantOperation(Rop opcode,
+            RegisterSpec sourceA, RegisterSpec sourceB) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public boolean requiresSourcesInOrder(Rop opcode,
+            RegisterSpecList sources) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public int getMaxOptimalRegisterCount() {
+        return Integer.MAX_VALUE;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/CstInsn.java b/dexgen/src/com/android/dexgen/rop/code/CstInsn.java
new file mode 100644
index 0000000..dc5ed39
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/CstInsn.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+
+/**
+ * Instruction which contains an explicit reference to a constant.
+ */
+public abstract class CstInsn
+        extends Insn {
+    /** {@code non-null;} the constant */
+    private final Constant cst;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @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) {
+        super(opcode, position, result, sources);
+
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        this.cst = cst;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return cst.toHuman();
+    }
+
+    /**
+     * Gets the constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public Constant getConstant() {
+        return cst;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean contentEquals(Insn b) {
+        /*
+         * The cast (CstInsn)b below should always succeed since
+         * Insn.contentEquals compares classes of this and b.
+         */
+        return super.contentEquals(b)
+                && cst.equals(((CstInsn)b).getConstant());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/DexTranslationAdvice.java b/dexgen/src/com/android/dexgen/rop/code/DexTranslationAdvice.java
new file mode 100644
index 0000000..b46182d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/DexTranslationAdvice.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.CstInteger;
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Implementation of {@link TranslationAdvice} which represents what
+ * the dex format will be able to represent.
+ */
+public final class DexTranslationAdvice
+        implements TranslationAdvice {
+    /** {@code non-null;} standard instance of this class */
+    public static final DexTranslationAdvice THE_ONE =
+        new DexTranslationAdvice();
+
+    /** debug advice for disabling invoke-range optimization */
+    public static final DexTranslationAdvice NO_SOURCES_IN_ORDER =
+        new DexTranslationAdvice(true);
+
+    /**
+     * The minimum source width, in register units, for an invoke
+     * instruction that requires its sources to be in order and contiguous.
+     */
+    private static final int MIN_INVOKE_IN_ORDER = 6;
+
+    /** when true: always returns false for requiresSourcesInOrder */
+    private final boolean disableSourcesInOrder;
+
+    /**
+     * This class is not publicly instantiable. Use {@link #THE_ONE}.
+     */
+    private DexTranslationAdvice() {
+        disableSourcesInOrder = false;
+    }
+
+    private DexTranslationAdvice(boolean disableInvokeRange) {
+        this.disableSourcesInOrder = disableInvokeRange;
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasConstantOperation(Rop opcode,
+            RegisterSpec sourceA, RegisterSpec sourceB) {
+        if (sourceA.getType() != Type.INT) {
+            return false;
+        }
+
+        if (! (sourceB.getTypeBearer() instanceof CstInteger)) {
+            return false;
+        }
+
+        CstInteger cst = (CstInteger) sourceB.getTypeBearer();
+
+        // TODO handle rsub
+        switch (opcode.getOpcode()) {
+            // These have 8 and 16 bit cst representations
+            case RegOps.REM:
+            case RegOps.ADD:
+            case RegOps.MUL:
+            case RegOps.DIV:
+            case RegOps.AND:
+            case RegOps.OR:
+            case RegOps.XOR:
+                return cst.fitsIn16Bits();
+            // These only have 8 bit cst reps
+            case RegOps.SHL:
+            case RegOps.SHR:
+            case RegOps.USHR:
+                return cst.fitsIn8Bits();
+            default:
+                return false;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public boolean requiresSourcesInOrder(Rop opcode,
+            RegisterSpecList sources) {
+
+        return !disableSourcesInOrder && opcode.isCallLike()
+                && totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER;
+    }
+
+    /**
+     * Calculates the total rop width of the list of SSA registers
+     *
+     * @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();
+        int total = 0;
+
+        for (int i = 0; i < sz; i++) {
+            total += sources.get(i).getCategory();
+        }
+
+        return total;
+    }
+
+    /** {@inheritDoc} */
+    public int getMaxOptimalRegisterCount() {
+        return 16;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/Exceptions.java b/dexgen/src/com/android/dexgen/rop/code/Exceptions.java
new file mode 100644
index 0000000..d6584d0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/Exceptions.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Common exception types.
+ */
+public final class Exceptions {
+    /** {@code non-null;} the type {@code java.lang.ArithmeticException} */
+    public static final Type TYPE_ArithmeticException =
+        Type.intern("Ljava/lang/ArithmeticException;");
+
+    /**
+     * {@code non-null;} the type
+     * {@code java.lang.ArrayIndexOutOfBoundsException}
+     */
+    public static final Type TYPE_ArrayIndexOutOfBoundsException =
+        Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;");
+
+    /** {@code non-null;} the type {@code java.lang.ArrayStoreException} */
+    public static final Type TYPE_ArrayStoreException =
+        Type.intern("Ljava/lang/ArrayStoreException;");
+
+    /** {@code non-null;} the type {@code java.lang.ClassCastException} */
+    public static final Type TYPE_ClassCastException =
+        Type.intern("Ljava/lang/ClassCastException;");
+
+    /** {@code non-null;} the type {@code java.lang.Error} */
+    public static final Type TYPE_Error = Type.intern("Ljava/lang/Error;");
+
+    /**
+     * {@code non-null;} the type
+     * {@code java.lang.IllegalMonitorStateException}
+     */
+    public static final Type TYPE_IllegalMonitorStateException =
+        Type.intern("Ljava/lang/IllegalMonitorStateException;");
+
+    /** {@code non-null;} the type {@code java.lang.NegativeArraySizeException} */
+    public static final Type TYPE_NegativeArraySizeException =
+        Type.intern("Ljava/lang/NegativeArraySizeException;");
+
+    /** {@code non-null;} the type {@code java.lang.NullPointerException} */
+    public static final Type TYPE_NullPointerException =
+        Type.intern("Ljava/lang/NullPointerException;");
+
+    /** {@code non-null;} the list {@code [java.lang.Error]} */
+    public static final StdTypeList LIST_Error = StdTypeList.make(TYPE_Error);
+
+    /**
+     * {@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);
+
+    /**
+     * {@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);
+
+    /**
+     * {@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);
+
+    /**
+     * {@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);
+
+    /**
+     * {@code non-null;} the list {@code [java.lang.Error,
+     * java.lang.NullPointerException,
+     * java.lang.ArrayIndexOutOfBoundsException]}
+     */
+    public static final StdTypeList LIST_Error_Null_ArrayIndexOutOfBounds =
+        StdTypeList.make(TYPE_Error,
+                      TYPE_NullPointerException,
+                      TYPE_ArrayIndexOutOfBoundsException);
+
+    /**
+     * {@code non-null;} the list {@code [java.lang.Error,
+     * java.lang.NullPointerException,
+     * java.lang.ArrayIndexOutOfBoundsException,
+     * java.lang.ArrayStoreException]}
+     */
+    public static final StdTypeList LIST_Error_Null_ArrayIndex_ArrayStore =
+        StdTypeList.make(TYPE_Error,
+                      TYPE_NullPointerException,
+                      TYPE_ArrayIndexOutOfBoundsException,
+                      TYPE_ArrayStoreException);
+
+    /**
+     * {@code non-null;} the list {@code [java.lang.Error,
+     * java.lang.NullPointerException,
+     * java.lang.IllegalMonitorStateException]}
+     */
+    public static final StdTypeList
+        LIST_Error_Null_IllegalMonitorStateException =
+        StdTypeList.make(TYPE_Error,
+                      TYPE_NullPointerException,
+                      TYPE_IllegalMonitorStateException);
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Exceptions() {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/FillArrayDataInsn.java b/dexgen/src/com/android/dexgen/rop/code/FillArrayDataInsn.java
new file mode 100644
index 0000000..3289b58
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/FillArrayDataInsn.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+
+import java.util.ArrayList;
+
+/**
+ * Instruction which fills a newly created array with a predefined list of
+ * constant values.
+ */
+public final class FillArrayDataInsn
+        extends Insn {
+
+    /** non-null: initial values to fill the newly created array */
+    private final ArrayList<Constant> initValues;
+
+    /**
+     * non-null: type of the array. Will be used to determine the width of
+     * elements in the array-data table.
+     */
+    private final Constant arrayType;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param sources {@code non-null;} specs for all the sources
+     * @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,
+                             ArrayList<Constant> initValues,
+                             Constant cst) {
+        super(opcode, position, null, sources);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        this.initValues = initValues;
+        this.arrayType = cst;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /**
+     * Return the list of init values
+     * @return {@code non-null;} list of init values
+     */
+    public ArrayList<Constant> getInitValues() {
+        return initValues;
+    }
+
+    /**
+     * Return the type of the newly created array
+     * @return {@code non-null;} array type
+     */
+    public Constant getConstant() {
+        return arrayType;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitFillArrayDataInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new  UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new FillArrayDataInsn(getOpcode(), getPosition(),
+                                     getSources().withOffset(delta),
+                                     initValues, arrayType);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new FillArrayDataInsn(getOpcode(), getPosition(),
+                                     sources, initValues, arrayType);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/Insn.java b/dexgen/src/com/android/dexgen/rop/code/Insn.java
new file mode 100644
index 0000000..4bb10d2
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/Insn.java
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * A register-based instruction. An instruction is the combination of
+ * an opcode (which specifies operation and source/result types), a
+ * list of actual sources and result registers/values, and additional
+ * information.
+ */
+public abstract class Insn implements ToHuman {
+    /** {@code non-null;} opcode */
+    private final Rop opcode;
+
+    /** {@code non-null;} source position */
+    private final SourcePosition position;
+
+    /** {@code null-ok;} spec for the result of this instruction, if any */
+    private final RegisterSpec result;
+
+    /** {@code non-null;} specs for all the sources of this instruction */
+    private final RegisterSpecList sources;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @param sources {@code non-null;} specs for all the sources
+     */
+    public Insn(Rop opcode, SourcePosition position, RegisterSpec result,
+                RegisterSpecList sources) {
+        if (opcode == null) {
+            throw new NullPointerException("opcode == null");
+        }
+
+        if (position == null) {
+            throw new NullPointerException("position == null");
+        }
+
+        if (sources == null) {
+            throw new NullPointerException("sources == null");
+        }
+
+        this.opcode = opcode;
+        this.position = position;
+        this.result = result;
+        this.sources = sources;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Instances of this class compare by identity. That is,
+     * {@code x.equals(y)} is only true if {@code x == y}.
+     */
+    @Override
+    public final boolean equals(Object other) {
+        return (this == other);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation returns the identity hashcode of this
+     * instance. This is proper, since instances of this class compare
+     * by identity (see {@link #equals}).
+     */
+    @Override
+    public final int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toStringWithInline(getInlineString());
+    }
+
+    /**
+     * Gets a human-oriented (and slightly lossy) string for this instance.
+     *
+     * @return {@code non-null;} the human string form
+     */
+    public String toHuman() {
+        return toHumanWithInline(getInlineString());
+    }
+
+    /**
+     * Gets an "inline" string portion for toHuman(), if available. This
+     * is the portion that appears after the Rop opcode
+     *
+     * @return {@code null-ok;} if non-null, the inline text for toHuman()
+     */
+    public String getInlineString() {
+        return null;
+    }
+
+    /**
+     * Gets the opcode.
+     *
+     * @return {@code non-null;} the opcode
+     */
+    public final Rop getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets 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}
+     * means this instruction returns nothing.
+     *
+     * @return {@code null-ok;} the result spec, if any
+     */
+    public final RegisterSpec getResult() {
+        return result;
+    }
+
+    /**
+     * 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} insns
+     * it may be the source.
+     *
+     * @return {@code null-ok;} a named register spec or null
+     */
+    public final RegisterSpec getLocalAssignment() {
+        RegisterSpec assignment;
+        if (opcode.getOpcode() == RegOps.MARK_LOCAL) {
+            assignment = sources.get(0);
+        } else {
+            assignment = result;
+        }
+
+        if (assignment == null) {
+            return null;
+        }
+
+        LocalItem localItem = assignment.getLocalItem();
+
+        if (localItem == null) {
+            return null;
+        }
+
+        return assignment;
+    }
+
+    /**
+     * Gets the source specs.
+     *
+     * @return {@code non-null;} the source specs
+     */
+    public final RegisterSpecList getSources() {
+        return sources;
+    }
+
+    /**
+     * Gets whether this instruction can possibly throw an exception. This
+     * is just a convenient wrapper for {@code getOpcode().canThrow()}.
+     *
+     * @return {@code true} iff this instruction can possibly throw
+     */
+    public final boolean canThrow() {
+        return opcode.canThrow();
+    }
+
+    /**
+     * Gets the list of possibly-caught exceptions. This returns {@link
+     * StdTypeList#EMPTY} if this instruction has no handlers,
+     * which can be <i>either</i> if this instruction can't possibly
+     * throw or if it merely doesn't handle any of its possible
+     * exceptions. To determine whether this instruction can throw,
+     * use {@link #canThrow}.
+     *
+     * @return {@code non-null;} the catches list
+     */
+    public abstract TypeList getCatches();
+
+    /**
+     * Calls the appropriate method on the given visitor, depending on the
+     * class of this instance. Subclasses must override this.
+     *
+     * @param visitor {@code non-null;} the visitor to call on
+     */
+    public abstract void accept(Visitor visitor);
+
+    /**
+     * Returns an instance that is just like this one, except that it
+     * has a catch list with the given item appended to the end. This
+     * method throws an exception if this instance can't possibly
+     * throw. To determine whether this instruction can throw, use
+     * {@link #canThrow}.
+     *
+     * @param type {@code non-null;} type to append to the catch list
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract Insn withAddedCatch(Type type);
+
+    /**
+     * Returns an instance that is just like this one, except that all
+     * register references have been offset by the given delta.
+     *
+     * @param delta the amount to offset register references by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract Insn withRegisterOffset(int delta);
+
+    /**
+     * 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} is returned in cases where
+     * the translation is not possible.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Insn withLastSourceLiteral() {
+        return this;
+    }
+
+    /**
+     * Returns an exact copy of this Insn
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Insn copy() {
+        return withRegisterOffset(0);
+    }
+
+
+    /**
+     * Compares, handling nulls safely
+     *
+     * @param a first object
+     * @param b second object
+     * @return true if they're equal or both null.
+     */
+    private static boolean equalsHandleNulls (Object a, Object b) {
+        return (a == b) || ((a != null) && a.equals(b));
+    }
+
+    /**
+     * 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.
+     *
+     * @return true in the case described above
+     */
+    public boolean contentEquals(Insn b) {
+        return opcode == b.getOpcode()
+                && position.equals(b.getPosition())
+                && (getClass() == b.getClass())
+                && equalsHandleNulls(result, b.getResult())
+                && equalsHandleNulls(sources, b.getSources())
+                && StdTypeList.equalContents(getCatches(), b.getCatches());
+    }
+
+    /**
+     * Returns an instance that is just like this one, except
+     * with new result and source registers.
+     *
+     * @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);
+
+    /**
+     * Returns the string form of this instance, with the given bit added in
+     * the standard location for an inline argument.
+     *
+     * @param extra {@code null-ok;} the inline argument string
+     * @return {@code non-null;} the string form
+     */
+    protected final String toStringWithInline(String extra) {
+        StringBuffer sb = new StringBuffer(80);
+
+        sb.append("Insn{");
+        sb.append(position);
+        sb.append(' ');
+        sb.append(opcode);
+
+        if (extra != null) {
+            sb.append(' ');
+            sb.append(extra);
+        }
+
+        sb.append(" :: ");
+
+        if (result != null) {
+            sb.append(result);
+            sb.append(" <- ");
+        }
+
+        sb.append(sources);
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns the human string form of this instance, with the given
+     * bit added in the standard location for an inline argument.
+     *
+     * @param extra {@code null-ok;} the inline argument string
+     * @return {@code non-null;} the human string form
+     */
+    protected final String toHumanWithInline(String extra) {
+        StringBuffer sb = new StringBuffer(80);
+
+        sb.append(position);
+        sb.append(": ");
+        sb.append(opcode.getNickname());
+
+        if (extra != null) {
+            sb.append("(");
+            sb.append(extra);
+            sb.append(")");
+        }
+
+        if (result == null) {
+            sb.append(" .");
+        } else {
+            sb.append(" ");
+            sb.append(result.toHuman());
+        }
+
+        sb.append(" <-");
+
+        int sz = sources.size();
+        if (sz == 0) {
+            sb.append(" .");
+        } else {
+            for (int i = 0; i < sz; i++) {
+                sb.append(" ");
+                sb.append(sources.get(i).toHuman());
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Visitor interface for this (outer) class.
+     */
+    public static interface Visitor {
+        /**
+         * Visits a {@link PlainInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitPlainInsn(PlainInsn insn);
+
+        /**
+         * Visits a {@link PlainCstInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitPlainCstInsn(PlainCstInsn insn);
+
+        /**
+         * Visits a {@link SwitchInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitSwitchInsn(SwitchInsn insn);
+
+        /**
+         * Visits a {@link ThrowingCstInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn);
+
+        /**
+         * Visits a {@link ThrowingInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitThrowingInsn(ThrowingInsn insn);
+
+        /**
+         * Visits a {@link FillArrayDataInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn);
+    }
+
+    /**
+     * Base implementation of {@link Visitor}, which has empty method
+     * bodies for all methods.
+     */
+    public static class BaseVisitor implements Visitor {
+        /** {@inheritDoc} */
+        public void visitPlainInsn(PlainInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitchInsn(SwitchInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+            // This space intentionally left blank.
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/InsnList.java b/dexgen/src/com/android/dexgen/rop/code/InsnList.java
new file mode 100644
index 0000000..0046972
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/InsnList.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * List of {@link Insn} instances.
+ */
+public final class InsnList
+        extends FixedSizeList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public InsnList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Insn get(int n) {
+        return (Insn) get0(n);
+    }
+
+    /**
+     * Sets the instruction at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param insn {@code non-null;} the instruction to set at {@code n}
+     */
+    public void set(int n, Insn insn) {
+        set0(n, insn);
+    }
+
+    /**
+     * Gets the last instruction. This is just a convenient shorthand for
+     * {@code get(size() - 1)}.
+     *
+     * @return {@code non-null;} the last instruction
+     */
+    public Insn getLast() {
+        return get(size() - 1);
+    }
+
+    /**
+     * Visits each instruction in the list, in order.
+     *
+     * @param visitor {@code non-null;} visitor to use
+     */
+    public void forEach(Insn.Visitor visitor) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            get(i).accept(visitor);
+        }
+    }
+
+    /**
+     * 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()}.
+     *
+     * @param b to compare
+     * @return true in the case described above.
+     */
+    public boolean contentEquals(InsnList b) {
+        if (b == null) return false;
+
+        int sz = size();
+
+        if (sz != b.size()) return false;
+
+        for (int i = 0; i < sz; i++) {
+            if (!get(i).contentEquals(b.get(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount. Mutability of the result is inherited from the
+     * original.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public InsnList withRegisterOffset(int delta) {
+        int sz = size();
+        InsnList result = new InsnList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            Insn one = (Insn) get0(i);
+            if (one != null) {
+                result.set0(i, one.withRegisterOffset(delta));
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/LocalItem.java b/dexgen/src/com/android/dexgen/rop/code/LocalItem.java
new file mode 100644
index 0000000..78386f1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/LocalItem.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+
+/**
+ * A local variable item: either a name or a signature or both.
+ */
+public class LocalItem implements Comparable<LocalItem> {
+    /** {@code null-ok;} local variable name */
+    private final CstUtf8 name;
+
+    /** {@code null-ok;} local variable signature */
+    private final CstUtf8 signature;
+
+    /**
+     * Make a new item. If both name and signature are null, null is returned.
+     *
+     * TODO: intern these
+     *
+     * @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) {
+            return null;
+        }
+
+        return new LocalItem (name, signature);
+    }
+
+    /**
+     * Constructs instance.
+     *
+     * @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;
+        this.signature = signature;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof LocalItem)) {
+            return false;
+        }
+
+        LocalItem local = (LocalItem) other;
+
+        return 0 == compareTo(local);
+    }
+
+    /**
+     * Compares two strings like String.compareTo(), excepts treats a null
+     * as the least-possible string value.
+     *
+     * @return negative integer, zero, or positive integer in accordance
+     * with Comparable.compareTo()
+     */
+    private static int compareHandlesNulls(CstUtf8 a, CstUtf8 b) {
+        if (a == b) {
+            return 0;
+        } else if (a == null) {
+            return -1;
+        } else if (b == null) {
+            return 1;
+        } else {
+            return a.compareTo(b);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(LocalItem local) {
+        int ret;
+
+        ret = compareHandlesNulls(name, local.name);
+
+        if (ret != 0) {
+            return ret;
+        }
+
+        ret = compareHandlesNulls(signature, local.signature);
+
+        return ret;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return (name == null ? 0 : name.hashCode()) * 31
+                + (signature == null ? 0 : signature.hashCode());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        if (name != null && signature == null) {
+            return name.toQuoted();
+        } else if (name == null && signature == null) {
+            return "";
+        }
+
+        return "[" + (name == null ? "" : name.toQuoted())
+                + "|" + (signature == null ? "" : signature.toQuoted());
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return {@code null-ok;} name
+     */
+    public CstUtf8 getName() {
+        return name;
+    }
+
+    /**
+     * Gets signature.
+     *
+     * @return {@code null-ok;} signature
+     */
+    public CstUtf8 getSignature() {
+        return signature;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/LocalVariableExtractor.java b/dexgen/src/com/android/dexgen/rop/code/LocalVariableExtractor.java
new file mode 100644
index 0000000..14f5f15
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/LocalVariableExtractor.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.util.Bits;
+import com.android.dexgen.util.IntList;
+
+/**
+ * Code to figure out which local variables are active at which points in
+ * a method.
+ */
+public final class LocalVariableExtractor {
+    /** {@code non-null;} method being extracted from */
+    private final RopMethod method;
+
+    /** {@code non-null;} block list for the method */
+    private final BasicBlockList blocks;
+
+    /** {@code non-null;} result in-progress */
+    private final LocalVariableInfo resultInfo;
+
+    /** {@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 {@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);
+        return lve.doit();
+    }
+
+    /**
+     * Constructs an instance. This method is private. Use {@link #extract}.
+     *
+     * @param method {@code non-null;} the method to extract from
+     */
+    private LocalVariableExtractor(RopMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        BasicBlockList blocks = method.getBlocks();
+        int maxLabel = blocks.getMaxLabel();
+
+        this.method = method;
+        this.blocks = blocks;
+        this.resultInfo = new LocalVariableInfo(method);
+        this.workSet = Bits.makeBitSet(maxLabel);
+    }
+
+    /**
+     * Does the extraction.
+     *
+     * @return {@code non-null;} the extracted information
+     */
+    private LocalVariableInfo doit() {
+        for (int label = method.getFirstLabel();
+             label >= 0;
+             label = Bits.findFirst(workSet, 0)) {
+            Bits.clear(workSet, label);
+            processBlock(label);
+        }
+
+        resultInfo.setImmutable();
+        return resultInfo;
+    }
+
+    /**
+     * Processes a single block.
+     *
+     * @param label {@code >= 0;} label of the block to process
+     */
+    private void processBlock(int label) {
+        RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label);
+        BasicBlock block = blocks.labelToBlock(label);
+        InsnList insns = block.getInsns();
+        int insnSz = insns.size();
+
+        /*
+         * We may have to treat the last instruction specially: If it
+         * can (but doesn't always) throw, and the exception can be
+         * caught within the same method, then we need to use the
+         * state *before* executing it to be what is merged into
+         * exception targets.
+         */
+        boolean canThrowDuringLastInsn = block.hasExceptionHandlers() &&
+            (insns.getLast().getResult() != null);
+        int freezeSecondaryStateAt = insnSz - 1;
+        RegisterSpecSet secondaryState = primaryState;
+
+        /*
+         * Iterate over the instructions, adding information for each place
+         * that the active variable set changes.
+         */
+
+        for (int i = 0; i < insnSz; i++) {
+            if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
+                // Until this point, primaryState == secondaryState.
+                primaryState.setImmutable();
+                primaryState = primaryState.mutableCopy();
+            }
+
+            Insn insn = insns.get(i);
+            RegisterSpec result;
+
+            result = insn.getLocalAssignment();
+
+            if (result == null) {
+                /*
+                 * If an assignment assigns over an existing local, make
+                 * sure to mark the local as going out of scope.
+                 */
+
+                result = insn.getResult();
+
+                if (result != null
+                        && primaryState.get(result.getReg()) != null) {
+                    primaryState.remove(primaryState.get(result.getReg()));
+                }
+                continue;
+            }
+
+            result = result.withSimpleType();
+
+            RegisterSpec already = primaryState.get(result);
+            /*
+             * The equals() check ensures we only add new info if
+             * the instruction causes a change to the set of
+             * active variables.
+             */
+            if (!result.equals(already)) {
+                /*
+                 * If this insn represents a local moving from one register
+                 * to another, remove the association between the old register
+                 * and the local.
+                 */
+                RegisterSpec previous
+                        = primaryState.localItemToSpec(result.getLocalItem());
+
+                if (previous != null
+                        && (previous.getReg() != result.getReg())) {
+
+                    primaryState.remove(previous);
+                }
+
+                resultInfo.addAssignment(insn, result);
+                primaryState.put(result);
+            }
+        }
+
+        primaryState.setImmutable();
+
+        /*
+         * Merge this state into the start state for each successor,
+         * and update the work set where required (that is, in cases
+         * where the start state for a block changes).
+         */
+
+        IntList successors = block.getSuccessors();
+        int succSz = successors.size();
+        int primarySuccessor = block.getPrimarySuccessor();
+
+        for (int i = 0; i < succSz; i++) {
+            int succ = successors.get(i);
+            RegisterSpecSet state = (succ == primarySuccessor) ?
+                primaryState : secondaryState;
+
+            if (resultInfo.mergeStarts(succ, state)) {
+                Bits.set(workSet, succ);
+            }
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/LocalVariableInfo.java b/dexgen/src/com/android/dexgen/rop/code/LocalVariableInfo.java
new file mode 100644
index 0000000..b126a4c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/LocalVariableInfo.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.TypeBearer;
+import com.android.dexgen.util.MutabilityControl;
+
+import java.util.HashMap;
+
+/**
+ * Container for local variable information for a particular {@link
+ * RopMethod}.
+ */
+public final class LocalVariableInfo
+        extends MutabilityControl {
+    /** {@code >= 0;} the register count for the method */
+    private final int regCount;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /** {@code non-null;} map from instructions to the variable each assigns */
+    private final HashMap<Insn, RegisterSpec> insnAssignments;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method being represented by this instance
+     */
+    public LocalVariableInfo(RopMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        BasicBlockList blocks = method.getBlocks();
+        int maxLabel = blocks.getMaxLabel();
+
+        this.regCount = blocks.getRegCount();
+        this.emptySet = new RegisterSpecSet(regCount);
+        this.blockStarts = new RegisterSpecSet[maxLabel];
+        this.insnAssignments =
+            new HashMap<Insn, RegisterSpec>(blocks.getInstructionCount());
+
+        emptySet.setImmutable();
+    }
+
+    /**
+     * Sets the register set associated with the start of the block with
+     * the given label.
+     *
+     * @param label {@code >= 0;} the block label
+     * @param specs {@code non-null;} the register set to associate with the block
+     */
+    public void setStarts(int label, RegisterSpecSet specs) {
+        throwIfImmutable();
+
+        if (specs == null) {
+            throw new NullPointerException("specs == null");
+        }
+
+        try {
+            blockStarts[label] = specs;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus label");
+        }
+    }
+
+    /**
+     * Merges the given register set into the set for the block with the
+     * given label. If there was not already an associated set, then this
+     * is the same as calling {@link #setStarts}. Otherwise, this will
+     * merge the two sets and call {@link #setStarts} on the result of the
+     * merge.
+     *
+     * @param label {@code >= 0;} the block label
+     * @param specs {@code non-null;} the register set to merge into the start set
+     * for the block
+     * @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} if there was no change
+     */
+    public boolean mergeStarts(int label, RegisterSpecSet specs) {
+        RegisterSpecSet start = getStarts0(label);
+        boolean changed = false;
+
+        if (start == null) {
+            setStarts(label, specs);
+            return true;
+        }
+
+        RegisterSpecSet newStart = start.mutableCopy();
+        newStart.intersect(specs, true);
+
+        if (start.equals(newStart)) {
+            return false;
+        }
+
+        newStart.setImmutable();
+        setStarts(label, newStart);
+
+        return true;
+    }
+
+    /**
+     * Gets the register set associated with the start of the block
+     * with the given label. This returns an empty set with the appropriate
+     * max size if no set was associated with the block in question.
+     *
+     * @param label {@code >= 0;} the block label
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet getStarts(int label) {
+        RegisterSpecSet result = getStarts0(label);
+
+        return (result != null) ? result : emptySet;
+    }
+
+    /**
+     * Gets the register set associated with the start of the given
+     * block. This is just convenient shorthand for
+     * {@code getStarts(block.getLabel())}.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet getStarts(BasicBlock block) {
+        return getStarts(block.getLabel());
+    }
+
+    /**
+     * Gets a mutable copy of the register set associated with the
+     * start of the block with the given label. This returns a
+     * newly-allocated empty {@link RegisterSpecSet} of appropriate
+     * max size if there is not yet any set associated with the block.
+     *
+     * @param label {@code >= 0;} the block label
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet mutableCopyOfStarts(int label) {
+        RegisterSpecSet result = getStarts0(label);
+
+        return (result != null) ?
+            result.mutableCopy() : new RegisterSpecSet(regCount);
+    }
+
+    /**
+     * Adds an assignment association for the given instruction and
+     * register spec. This throws an exception if the instruction
+     * doesn't actually perform a named variable assignment.
+     *
+     * <b>Note:</b> Although the instruction contains its own spec for
+     * the result, it still needs to be passed in explicitly to this
+     * method, since the spec that is stored here should always have a
+     * simple type and the one in the instruction can be an arbitrary
+     * {@link TypeBearer} (such as a constant value).
+     *
+     * @param insn {@code non-null;} the instruction in question
+     * @param spec {@code non-null;} the associated register spec
+     */
+    public void addAssignment(Insn insn, RegisterSpec spec) {
+        throwIfImmutable();
+
+        if (insn == null) {
+            throw new NullPointerException("insn == null");
+        }
+
+        if (spec == null) {
+            throw new NullPointerException("spec == null");
+        }
+
+        insnAssignments.put(insn, spec);
+    }
+
+    /**
+     * Gets the named register being assigned by the given instruction, if
+     * previously stored in this instance.
+     *
+     * @param insn {@code non-null;} instruction in question
+     * @return {@code null-ok;} the named register being assigned, if any
+     */
+    public RegisterSpec getAssignment(Insn insn) {
+        return insnAssignments.get(insn);
+    }
+
+    /**
+     * Gets the number of assignments recorded by this instance.
+     *
+     * @return {@code >= 0;} the number of assignments
+     */
+    public int getAssignmentCount() {
+        return insnAssignments.size();
+    }
+
+    public void debugDump() {
+        for (int label = 0 ; label < blockStarts.length; label++) {
+            if (blockStarts[label] == null) {
+                continue;
+            }
+
+            if (blockStarts[label] == emptySet) {
+                System.out.printf("%04x: empty set\n", label);
+            } else {
+                System.out.printf("%04x: %s\n", label, blockStarts[label]);
+            }
+        }
+    }
+
+    /**
+     * Helper method, to get the starts for a label, throwing the
+     * right exception for range problems.
+     *
+     * @param label {@code >= 0;} the block label
+     * @return {@code null-ok;} associated register set or {@code null} if there
+     * is none
+     */
+    private RegisterSpecSet getStarts0(int label) {
+        try {
+            return blockStarts[label];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus label");
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/PlainCstInsn.java b/dexgen/src/com/android/dexgen/rop/code/PlainCstInsn.java
new file mode 100644
index 0000000..5f8f753
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/PlainCstInsn.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+
+/**
+ * Instruction which contains an explicit reference to a constant
+ * but which cannot throw an exception.
+ */
+public final class PlainCstInsn
+        extends CstInsn {
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @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,
+                        Constant cst) {
+        super(opcode, position, result, sources, cst);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitPlainCstInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new PlainCstInsn(getOpcode(), getPosition(),
+                                getResult().withOffset(delta),
+                                getSources().withOffset(delta),
+                                getConstant());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new PlainCstInsn(getOpcode(), getPosition(),
+                                result,
+                                sources,
+                                getConstant());
+
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/PlainInsn.java b/dexgen/src/com/android/dexgen/rop/code/PlainInsn.java
new file mode 100644
index 0000000..c79e7c1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/PlainInsn.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeBearer;
+import com.android.dexgen.rop.type.TypeList;
+
+/**
+ * Plain instruction, which has no embedded data and which cannot possibly
+ * throw an exception.
+ */
+public final class PlainInsn
+        extends Insn {
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @param sources {@code non-null;} specs for all the sources
+     */
+    public PlainInsn(Rop opcode, SourcePosition position,
+                     RegisterSpec result, RegisterSpecList sources) {
+        super(opcode, position, result, sources);
+
+        switch (opcode.getBranchingness()) {
+            case Rop.BRANCH_SWITCH:
+            case Rop.BRANCH_THROW: {
+                throw new IllegalArgumentException("bogus branchingness");
+            }
+        }
+
+        if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            // move-result-pseudo is required here
+            throw new IllegalArgumentException
+                    ("can't mix branchingness with result");
+        }
+    }
+
+    /**
+     * Constructs a single-source instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @param source {@code non-null;} spec for the source
+     */
+    public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
+                     RegisterSpec source) {
+        this(opcode, position, result, RegisterSpecList.make(source));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitPlainInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new PlainInsn(getOpcode(), getPosition(),
+                             getResult().withOffset(delta),
+                             getSources().withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withLastSourceLiteral() {
+        RegisterSpecList sources = getSources();
+        int szSources = sources.size();
+
+        if (szSources == 0) {
+            return this;
+        }
+
+        TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
+
+        if (!lastType.isConstant()) {
+            return this;
+        }
+
+        Constant cst = (Constant) lastType;
+
+        RegisterSpecList newSources = sources.withoutLast();
+
+        Rop newRop;
+        try {
+            newRop = Rops.ropFor(getOpcode().getOpcode(),
+                    getResult(), newSources, (Constant)lastType);
+        } catch (IllegalArgumentException ex) {
+            // There's no rop for this case
+            return this;
+        }
+
+        return new PlainCstInsn(newRop, getPosition(),
+                getResult(), newSources, cst);
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new PlainInsn(getOpcode(), getPosition(),
+                             result,
+                             sources);
+
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/RegOps.java b/dexgen/src/com/android/dexgen/rop/code/RegOps.java
new file mode 100644
index 0000000..3af8b7d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/RegOps.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.util.Hex;
+
+/**
+ * All the register-based opcodes, and related utilities.
+ *
+ * <p><b>Note:</b> Opcode descriptions use a rough pseudocode. {@code r}
+ * is the result register, {@code x} is the first argument,
+ * {@code y} is the second argument, and {@code z} is the
+ * 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()} */
+    public static final int NOP = 1;
+
+    /** {@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)} */
+    public static final int MOVE_PARAM = 3;
+
+    /**
+     * {@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;} */
+    public static final int CONST = 5;
+
+    /** {@code goto label} */
+    public static final int GOTO = 6;
+
+    /**
+     * {@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
+     * label}
+     */
+    public static final int IF_NE = 8;
+
+    /** {@code x,y: int :: if (x < y) goto label} */
+    public static final int IF_LT = 9;
+
+    /** {@code x,y: int :: if (x >= y) goto label} */
+    public static final int IF_GE = 10;
+
+    /** {@code x,y: int :: if (x <= y) goto label} */
+    public static final int IF_LE = 11;
+
+    /** {@code x,y: int :: if (x > y) goto label} */
+    public static final int IF_GT = 12;
+
+    /** {@code x: int :: goto table[x]} */
+    public static final int SWITCH = 13;
+
+    /** {@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} */
+    public static final int SUB = 15;
+
+    /** {@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} */
+    public static final int DIV = 17;
+
+    /**
+     * {@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} */
+    public static final int NEG = 19;
+
+    /** {@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} */
+    public static final int OR = 21;
+
+    /** {@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}
+     */
+    public static final int SHL = 23;
+
+    /**
+     * {@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}
+     * (unsigned right-shift)
+     */
+    public static final int USHR = 25;
+
+    /** {@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} (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} (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} (numeric type conversion between the four
+     * "real" numeric types)
+     */
+    public static final int CONV = 29;
+
+    /**
+     * {@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} (Java-style convert int to char)
+     */
+    public static final int TO_CHAR = 31;
+
+    /**
+     * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
+     * convert int to short)
+     */
+    public static final int TO_SHORT = 32;
+
+    /** {@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} */
+    public static final int ARRAY_LENGTH = 34;
+
+    /** {@code x: Throwable :: throw(x)} */
+    public static final int THROW = 35;
+
+    /** {@code x: Object :: monitorenter(x)} */
+    public static final int MONITOR_ENTER = 36;
+
+    /** {@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]} */
+    public static final int AGET = 38;
+
+    /** {@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)} (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]} */
+    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}}
+     */
+    public static final int FILLED_NEW_ARRAY = 42;
+
+    /**
+     * {@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}
+     */
+    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}
+     */
+    public static final int GET_FIELD = 45;
+
+    /**
+     * {@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}
+     */
+    public static final int PUT_FIELD = 47;
+
+    /**
+     * {@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, ...)} (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, ...)} (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, ...)} (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, ...)} (call
+     * direct/special method)
+     */
+    public static final int INVOKE_DIRECT = 52;
+
+    /**
+     * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
+     * (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
+     * ...)} (call interface method)
+     */
+    public static final int INVOKE_INTERFACE = 53;
+
+    /**
+     * {@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}.
+     * <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}.
+     * <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}} */
+    public static final int FILL_ARRAY_DATA = 57;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private RegOps() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the name of the given opcode.
+     *
+     * @param opcode {@code >= 0, <= 255;} the opcode
+     * @return {@code non-null;} its name
+     */
+    public static String opName(int opcode) {
+        switch (opcode) {
+            case NOP: return "nop";
+            case MOVE: return "move";
+            case MOVE_PARAM: return "move-param";
+            case MOVE_EXCEPTION: return "move-exception";
+            case CONST: return "const";
+            case GOTO: return "goto";
+            case IF_EQ: return "if-eq";
+            case IF_NE: return "if-ne";
+            case IF_LT: return "if-lt";
+            case IF_GE: return "if-ge";
+            case IF_LE: return "if-le";
+            case IF_GT: return "if-gt";
+            case SWITCH: return "switch";
+            case ADD: return "add";
+            case SUB: return "sub";
+            case MUL: return "mul";
+            case DIV: return "div";
+            case REM: return "rem";
+            case NEG: return "neg";
+            case AND: return "and";
+            case OR: return "or";
+            case XOR: return "xor";
+            case SHL: return "shl";
+            case SHR: return "shr";
+            case USHR: return "ushr";
+            case NOT: return "not";
+            case CMPL: return "cmpl";
+            case CMPG: return "cmpg";
+            case CONV: return "conv";
+            case TO_BYTE: return "to-byte";
+            case TO_CHAR: return "to-char";
+            case TO_SHORT: return "to-short";
+            case RETURN: return "return";
+            case ARRAY_LENGTH: return "array-length";
+            case THROW: return "throw";
+            case MONITOR_ENTER: return "monitor-enter";
+            case MONITOR_EXIT: return "monitor-exit";
+            case AGET: return "aget";
+            case APUT: return "aput";
+            case NEW_INSTANCE: return "new-instance";
+            case NEW_ARRAY: return "new-array";
+            case FILLED_NEW_ARRAY: return "filled-new-array";
+            case CHECK_CAST: return "check-cast";
+            case INSTANCE_OF: return "instance-of";
+            case GET_FIELD: return "get-field";
+            case GET_STATIC: return "get-static";
+            case PUT_FIELD: return "put-field";
+            case PUT_STATIC: return "put-static";
+            case INVOKE_STATIC: return "invoke-static";
+            case INVOKE_VIRTUAL: return "invoke-virtual";
+            case INVOKE_SUPER: return "invoke-super";
+            case INVOKE_DIRECT: return "invoke-direct";
+            case INVOKE_INTERFACE: return "invoke-interface";
+            case MOVE_RESULT: return "move-result";
+            case MOVE_RESULT_PSEUDO: return "move-result-pseudo";
+            case FILL_ARRAY_DATA: return "fill-array-data";
+        }
+
+        return "unknown-" + Hex.u1(opcode);
+    }
+
+    /**
+     * Given an IF_* RegOp, returns the right-to-left flipped version. For
+     * example, IF_GT becomes IF_LT.
+     *
+     * @param opcode An IF_* RegOp
+     * @return flipped IF Regop
+     */
+    public static int flippedIfOpcode(final int opcode) {
+        switch (opcode) {
+            case RegOps.IF_EQ:
+            case RegOps.IF_NE:
+                return opcode;
+            case RegOps.IF_LT:
+                return RegOps.IF_GT;
+            case RegOps.IF_GE:
+                return RegOps.IF_LE;
+            case RegOps.IF_LE:
+                return RegOps.IF_GE;
+            case RegOps.IF_GT:
+                return RegOps.IF_LT;
+            default:
+                throw new RuntimeException("Unrecognized IF regop: " + opcode);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/RegisterSpec.java b/dexgen/src/com/android/dexgen/rop/code/RegisterSpec.java
new file mode 100644
index 0000000..30deeca
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/RegisterSpec.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeBearer;
+import com.android.dexgen.util.ToHuman;
+
+import java.util.HashMap;
+
+/**
+ * Combination of a register number and a type, used as the sources and
+ * destinations of register-based operations.
+ */
+public final class RegisterSpec
+        implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
+    /** {@code non-null;} string to prefix register numbers with */
+    public static final String PREFIX = "v";
+
+    /** {@code non-null;} intern table for instances */
+    private static final HashMap<Object, RegisterSpec> theInterns =
+        new HashMap<Object, RegisterSpec>(1000);
+
+    /** {@code non-null;} common comparison instance used while interning */
+    private static final ForComparison theInterningItem = new ForComparison();
+
+    /** {@code >= 0;} register number */
+    private final int reg;
+
+    /** {@code non-null;} type loaded or stored */
+    private final TypeBearer type;
+
+    /** {@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 {@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
+     */
+    private static RegisterSpec intern(int reg, TypeBearer type,
+            LocalItem local) {
+        theInterningItem.set(reg, type, local);
+        RegisterSpec found = theInterns.get(theInterningItem);
+
+        if (found != null) {
+            return found;
+        }
+
+        found = theInterningItem.toRegisterSpec();
+        theInterns.put(found, found);
+        return found;
+    }
+
+    /**
+     * Returns an instance for the given register number and type, with
+     * no variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec make(int reg, TypeBearer type) {
+        return intern(reg, type, null);
+    }
+
+    /**
+     * Returns an instance for the given register number, type, and
+     * variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @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) {
+        if (local == null) {
+            throw new NullPointerException("local  == null");
+        }
+
+        return intern(reg, type, local);
+    }
+
+    /**
+     * Returns an instance for the given register number, type, and
+     * variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated variable info or null for
+     * none
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec makeLocalOptional(
+            int reg, TypeBearer type, LocalItem local) {
+
+        return intern(reg, type, local);
+    }
+
+    /**
+     * Gets the string form for the given register number.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @return {@code non-null;} the string form
+     */
+    public static String regString(int reg) {
+        return PREFIX + reg;
+    }
+
+    /**
+     * Constructs an instance. This constructor is private. Use
+     * {@link #make}.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated local variable, if any
+     */
+    private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
+        if (reg < 0) {
+            throw new IllegalArgumentException("reg < 0");
+        }
+
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        this.reg = reg;
+        this.type = type;
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof RegisterSpec)) {
+            if (other instanceof ForComparison) {
+                ForComparison fc = (ForComparison) other;
+                return equals(fc.reg, fc.type, fc.local);
+            }
+            return false;
+        }
+
+        RegisterSpec spec = (RegisterSpec) other;
+        return equals(spec.reg, spec.type, spec.local);
+    }
+
+    /**
+     * Like {@code equals}, but only consider the simple types of the
+     * registers. That is, this compares {@code getType()} on the types
+     * to ignore whatever arbitrary extra stuff might be carried around
+     * by an outer {@link TypeBearer}.
+     *
+     * @param other {@code null-ok;} spec to compare to
+     * @return {@code true} iff {@code this} and {@code other} are equal
+     * in the stated way
+     */
+    public boolean equalsUsingSimpleType(RegisterSpec other) {
+        if (!matchesVariable(other)) {
+            return false;
+        }
+
+        return (reg == other.reg);
+    }
+
+    /**
+     * Like {@link #equalsUsingSimpleType} but ignoring the register number.
+     * This is useful to determine if two instances refer to the "same"
+     * local variable.
+     *
+     * @param other {@code null-ok;} spec to compare to
+     * @return {@code true} iff {@code this} and {@code other} are equal
+     * in the stated way
+     */
+    public boolean matchesVariable(RegisterSpec other) {
+        if (other == null) {
+            return false;
+        }
+
+        return type.getType().equals(other.type.getType())
+            && ((local == other.local)
+                    || ((local != null) && local.equals(other.local)));
+    }
+
+    /**
+     * Helper for {@link #equals} and {@link #ForComparison.equals},
+     * which actually does the test.
+     *
+     * @param reg value of the instance variable, for another instance
+     * @param type value of the instance variable, for another instance
+     * @param local value of the instance variable, for another instance
+     * @return whether this instance is equal to one with the given
+     * values
+     */
+    private boolean equals(int reg, TypeBearer type, LocalItem local) {
+        return (this.reg == reg)
+            && this.type.equals(type)
+            && ((this.local == local)
+                    || ((this.local != null) && this.local.equals(local)));
+    }
+
+    /**
+     * Compares by (in priority order) register number, unwrapped type
+     * (that is types not {@link TypeBearer}s, and local info.
+     *
+     * @param other {@code non-null;} spec to compare to
+     * @return {@code -1..1;} standard result of comparison
+     */
+    public int compareTo(RegisterSpec other) {
+        if (this.reg < other.reg) {
+            return -1;
+        } else if (this.reg > other.reg) {
+            return 1;
+        }
+
+        int compare = type.getType().compareTo(other.type.getType());
+
+        if (compare != 0) {
+            return compare;
+        }
+
+        if (this.local == null) {
+            return (other.local == null) ? 0 : -1;
+        } else if (other.local == null) {
+            return 1;
+        }
+
+        return this.local.compareTo(other.local);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return hashCodeOf(reg, type, local);
+    }
+
+    /**
+     * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
+     * which actually does the calculation.
+     *
+     * @param reg value of the instance variable
+     * @param type value of the instance variable
+     * @param local value of the instance variable
+     * @return the hash code
+     */
+    private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
+        int hash = (local != null) ? local.hashCode() : 0;
+
+        hash = (hash * 31 + type.hashCode()) * 31 + reg;
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toString0(false);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toString0(true);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return type.getType();
+    }
+
+    /** {@inheritDoc} */
+    public TypeBearer getFrameType() {
+        return type.getFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicType() {
+        return type.getBasicType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicFrameType() {
+        return type.getBasicFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final boolean isConstant() {
+        return false;
+    }
+
+    /**
+     * Gets the register number.
+     *
+     * @return {@code >= 0;} the register number
+     */
+    public int getReg() {
+        return reg;
+    }
+
+    /**
+     * Gets the type (or actual value) which is loaded from or stored
+     * to the register associated with this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public TypeBearer getTypeBearer() {
+        return type;
+    }
+
+    /**
+     * Gets the variable info associated with this instance, if any.
+     *
+     * @return {@code null-ok;} the variable info, or {@code null} if this
+     * instance has none
+     */
+    public LocalItem getLocalItem() {
+        return local;
+    }
+
+    /**
+     * Gets the next available register number after the one in this
+     * instance. This is equal to the register number plus the width
+     * (category) of the type used. Among other things, this may also
+     * be used to determine the minimum required register count
+     * implied by this instance.
+     *
+     * @return {@code >= 0;} the required registers size
+     */
+    public int getNextReg() {
+        return reg + getCategory();
+    }
+
+    /**
+     * Gets the category of this instance's type. This is just a convenient
+     * shorthand for {@code getType().getCategory()}.
+     *
+     * @see #isCategory1
+     * @see #isCategory2
+     * @return {@code 1..2;} the category of this instance's type
+     */
+    public int getCategory() {
+        return type.getType().getCategory();
+    }
+
+    /**
+     * Gets whether this instance's type is category 1. This is just a
+     * convenient shorthand for {@code getType().isCategory1()}.
+     *
+     * @see #getCategory
+     * @see #isCategory2
+     * @return whether or not this instance's type is of category 1
+     */
+    public boolean isCategory1() {
+        return type.getType().isCategory1();
+    }
+
+    /**
+     * Gets whether this instance's type is category 2. This is just a
+     * convenient shorthand for {@code getType().isCategory2()}.
+     *
+     * @see #getCategory
+     * @see #isCategory1
+     * @return whether or not this instance's type is of category 2
+     */
+    public boolean isCategory2() {
+        return type.getType().isCategory2();
+    }
+
+    /**
+     * Gets the string form for just the register number of this instance.
+     *
+     * @return {@code non-null;} the register string form
+     */
+    public String regString() {
+        return regString(reg);
+    }
+
+    /**
+     * Returns an instance that is the intersection between this instance
+     * and the given one, if any. The intersection is defined as follows:
+     *
+     * <ul>
+     *   <li>If {@code other} is {@code null}, then the result
+     *     is {@code null}.
+     *   <li>If the register numbers don't match, then the intersection
+     *     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()} 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()} 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}.</li>
+     * </ul>
+     *
+     * @param other {@code null-ok;} instance to intersect with (or {@code null})
+     * @param localPrimary whether local variables are primary to the
+     * intersection; if {@code true}, then the only non-null
+     * results occur when registers being intersected have equal local
+     * infos (or both have {@code null} local infos)
+     * @return {@code null-ok;} the intersection
+     */
+    public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
+        if (this == other) {
+            // Easy out.
+            return this;
+        }
+
+        if ((other == null) || (reg != other.getReg())) {
+            return null;
+        }
+
+        LocalItem resultLocal =
+            ((local == null) || !local.equals(other.getLocalItem()))
+            ? null : local;
+        boolean sameName = (resultLocal == local);
+
+        if (localPrimary && !sameName) {
+            return null;
+        }
+
+        Type thisType = getType();
+        Type otherType = other.getType();
+
+        // Note: Types are always interned.
+        if (thisType != otherType) {
+            return null;
+        }
+
+        TypeBearer resultTypeBearer =
+            type.equals(other.getTypeBearer()) ? type : thisType;
+
+        if ((resultTypeBearer == type) && sameName) {
+            // It turns out that the intersection is "this" after all.
+            return this;
+        }
+
+        return (resultLocal == null) ? make(reg, resultTypeBearer) :
+            make(reg, resultTypeBearer, resultLocal);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that the
+     * register number is replaced by the given one.
+     *
+     * @param newReg {@code >= 0;} the new register number
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withReg(int newReg) {
+        if (reg == newReg) {
+            return this;
+        }
+
+        return makeLocalOptional(newReg, type, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the type is replaced by the given one.
+     *
+     * @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);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that the
+     * register number is offset by the given amount.
+     *
+     * @param delta the amount to offset the register number by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withOffset(int delta) {
+        if (delta == 0) {
+            return this;
+        }
+
+        return withReg(reg + delta);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the type bearer is replaced by the actual underlying type
+     * (thereby stripping off non-type information) with any
+     * initialization information stripped away as well.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withSimpleType() {
+        TypeBearer orig = type;
+        Type newType;
+
+        if (orig instanceof Type) {
+            newType = (Type) orig;
+        } else {
+            newType = orig.getType();
+        }
+
+        if (newType.isUninitialized()) {
+            newType = newType.getInitializedType();
+        }
+
+        if (newType == orig) {
+            return this;
+        }
+
+        return makeLocalOptional(reg, newType, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one except that the
+     * local variable is as specified in the parameter.
+     *
+     * @param local {@code null-ok;} the local item or null for none
+     * @return an appropriate instance
+     */
+    public RegisterSpec withLocalItem(LocalItem local) {
+        if ((this.local== local)
+                    || ((this.local != null) && this.local.equals(local))) {
+
+            return this;
+        }
+
+        return makeLocalOptional(reg, type, local);
+    }
+
+
+    /**
+     * Helper for {@link #toString} and {@link #toHuman}.
+     *
+     * @param human whether to be human-oriented
+     * @return {@code non-null;} the string form
+     */
+    private String toString0(boolean human) {
+        StringBuffer sb = new StringBuffer(40);
+
+        sb.append(regString());
+        sb.append(":");
+
+        if (local != null) {
+            sb.append(local.toString());
+        }
+
+        Type justType = type.getType();
+        sb.append(justType);
+
+        if (justType != type) {
+            sb.append("=");
+            if (human && (type instanceof Constant)) {
+                sb.append(((Constant) type).toHuman());
+            } else {
+                sb.append(type);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Holder of register spec data for the purposes of comparison (so that
+     * {@code RegisterSpec} itself can still keep {@code final}
+     * instance variables.
+     */
+    private static class ForComparison {
+        /** {@code >= 0;} register number */
+        private int reg;
+
+        /** {@code non-null;} type loaded or stored */
+        private TypeBearer type;
+
+        /**
+         * {@code null-ok;} local variable associated with this
+         * register, if any
+         */
+        private LocalItem local;
+
+        /**
+         * Set all the instance variables.
+         *
+         * @param reg {@code >= 0;} the register number
+         * @param type {@code non-null;} the type (or possibly actual
+         * value) which is loaded from or stored to the indicated
+         * 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;
+            this.type = type;
+            this.local = local;
+        }
+
+        /**
+         * Construct a {@code RegisterSpec} of this instance's
+         * contents.
+         *
+         * @return {@code non-null;} an appropriately-constructed instance
+         */
+        public RegisterSpec toRegisterSpec() {
+            return new RegisterSpec(reg, type, local);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof RegisterSpec)) {
+                return false;
+            }
+
+            RegisterSpec spec = (RegisterSpec) other;
+            return spec.equals(reg, type, local);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            return hashCodeOf(reg, type, local);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/RegisterSpecList.java b/dexgen/src/com/android/dexgen/rop/code/RegisterSpecList.java
new file mode 100644
index 0000000..a0f7a24
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/RegisterSpecList.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * List of {@link RegisterSpec} instances.
+ */
+public final class RegisterSpecList
+        extends FixedSizeList implements TypeList {
+    /** {@code non-null;} no-element instance */
+    public static final RegisterSpecList EMPTY = new RegisterSpecList(0);
+
+    /**
+     * Makes a single-element 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);
+        result.set(0, spec);
+        return result;
+    }
+
+    /**
+     * Makes a two-element instance.
+     *
+     * @param spec0 {@code non-null;} the first element
+     * @param spec1 {@code non-null;} the second element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpecList make(RegisterSpec spec0,
+                                        RegisterSpec spec1) {
+        RegisterSpecList result = new RegisterSpecList(2);
+        result.set(0, spec0);
+        result.set(1, spec1);
+        return result;
+    }
+
+    /**
+     * Makes a three-element instance.
+     *
+     * @param spec0 {@code non-null;} the first element
+     * @param spec1 {@code non-null;} the second element
+     * @param spec2 {@code non-null;} the third element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
+                                        RegisterSpec spec2) {
+        RegisterSpecList result = new RegisterSpecList(3);
+        result.set(0, spec0);
+        result.set(1, spec1);
+        result.set(2, spec2);
+        return result;
+    }
+
+    /**
+     * Makes a four-element instance.
+     *
+     * @param spec0 {@code non-null;} the first element
+     * @param spec1 {@code non-null;} the second element
+     * @param spec2 {@code non-null;} the third element
+     * @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,
+                                        RegisterSpec spec3) {
+        RegisterSpecList result = new RegisterSpecList(4);
+        result.set(0, spec0);
+        result.set(1, spec1);
+        result.set(2, spec2);
+        result.set(3, spec3);
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public RegisterSpecList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType(int n) {
+        return get(n).getType().getType();
+    }
+
+    /** {@inheritDoc} */
+    public int getWordCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            result += getType(i).getCategory();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public TypeList withAddedType(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /**
+     * Gets the indicated element. It is an error to call this with the
+     * index for an element which was never set; if you do that, this
+     * will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public RegisterSpec get(int n) {
+        return (RegisterSpec) get0(n);
+    }
+
+    /**
+     * Returns a RegisterSpec in this list that uses the specified register,
+     * or null if there is none in this list.
+     * @param reg Register to find
+     * @return RegisterSpec that uses argument or null.
+     */
+    public RegisterSpec specForRegister(int reg) {
+        int sz = size();
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec rs;
+
+            rs = get(i);
+
+            if (rs.getReg() == reg) {
+                return rs;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the index of a RegisterSpec in this list that uses the specified
+     * register, or -1 if none in this list uses the register.
+     * @param reg Register to find
+     * @return index of RegisterSpec or -1
+     */
+    public int indexOfRegister(int reg) {
+        int sz = size();
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec rs;
+
+            rs = get(i);
+
+            if (rs.getReg() == reg) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Sets the element at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param spec {@code non-null;} the value to store
+     */
+    public void set(int n, RegisterSpec spec) {
+        set0(n, spec);
+    }
+
+    /**
+     * Gets the minimum required register count implied by this
+     * instance. This is equal to the highest register number referred
+     * to plus the widest width (largest category) of the type used in
+     * that register.
+     *
+     * @return {@code >= 0;} the required registers size
+     */
+    public int getRegistersSize() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec spec = (RegisterSpec) get0(i);
+            if (spec != null) {
+                int min = spec.getNextReg();
+                if (min > result) {
+                    result = min;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that it has an additional element prepended to the original.
+     * Mutability of the result is inherited from the original.
+     *
+     * @param spec {@code non-null;} the new first spec (to prepend)
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withFirst(RegisterSpec spec) {
+        int sz = size();
+        RegisterSpecList result = new RegisterSpecList(sz + 1);
+
+        for (int i = 0; i < sz; i++) {
+            result.set0(i + 1, get0(i));
+        }
+
+        result.set0(0, spec);
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that its first element is removed. Mutability of the
+     * result is inherited from the original.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withoutFirst() {
+        int newSize = size() - 1;
+
+        if (newSize == 0) {
+            return EMPTY;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(newSize);
+
+        for (int i = 0; i < newSize; i++) {
+            result.set0(i, get0(i + 1));
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that its last element is removed. Mutability of the
+     * result is inherited from the original.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withoutLast() {
+        int newSize = size() - 1;
+
+        if (newSize == 0) {
+            return EMPTY;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(newSize);
+
+        for (int i = 0; i < newSize; i++) {
+            result.set0(i, get0(i));
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * all register numbers are offset by the given amount. Mutability
+     * of the result is inherited from the original.
+     *
+     * @param delta the amount to offset the register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withOffset(int delta) {
+        int sz = size();
+
+        if (sz == 0) {
+            // Don't bother making a new zero-element instance.
+            return this;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = (RegisterSpec) get0(i);
+            if (one != null) {
+                result.set0(i, one.withOffset(delta));
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * all register numbers are renumbered sequentially from the given
+     * base, with the first number duplicated if indicated.
+     *
+     * @param base the base register number
+     * @param duplicateFirst whether to duplicate the first number
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withSequentialRegisters(int base,
+                                                    boolean duplicateFirst) {
+        int sz = size();
+
+        if (sz == 0) {
+            // Don't bother making a new zero-element instance.
+            return this;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = (RegisterSpec) get0(i);
+            result.set0(i, one.withReg(base));
+            if (duplicateFirst) {
+                duplicateFirst = false;
+            } else {
+                base += one.getCategory();
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/RegisterSpecSet.java b/dexgen/src/com/android/dexgen/rop/code/RegisterSpecSet.java
new file mode 100644
index 0000000..69e67e9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/RegisterSpecSet.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.MutabilityControl;
+
+/**
+ * Set of {@link RegisterSpec} instances, where a given register number
+ * may appear only once in the set.
+ */
+public final class RegisterSpecSet
+        extends MutabilityControl {
+    /** {@code non-null;} no-element instance */
+    public static final RegisterSpecSet EMPTY = new RegisterSpecSet(0);
+
+    /**
+     * {@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;
+
+    /** {@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 {@code >= 0;} the maximum register number (exclusive) that
+     * may be represented in this instance
+     */
+    public RegisterSpecSet(int maxSize) {
+        super(maxSize != 0);
+
+        this.specs = new RegisterSpec[maxSize];
+        this.size = 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof RegisterSpecSet)) {
+            return false;
+        }
+
+        RegisterSpecSet otherSet = (RegisterSpecSet) other;
+        RegisterSpec[] otherSpecs = otherSet.specs;
+        int len = specs.length;
+
+        if ((len != otherSpecs.length) || (size() != otherSet.size())) {
+            return false;
+        }
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec s1 = specs[i];
+            RegisterSpec s2 = otherSpecs[i];
+
+            if (s1 == s2) {
+                continue;
+            }
+
+            if ((s1 == null) || !s1.equals(s2)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int len = specs.length;
+        int hash = 0;
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            int oneHash = (spec == null) ? 0 : spec.hashCode();
+            hash = (hash * 31) + oneHash;
+        }
+
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int len = specs.length;
+        StringBuffer sb = new StringBuffer(len * 25);
+
+        sb.append('{');
+
+        boolean any = false;
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            if (spec != null) {
+                if (any) {
+                    sb.append(", ");
+                } else {
+                    any = true;
+                }
+                sb.append(spec);
+            }
+        }
+
+        sb.append('}');
+        return sb.toString();
+    }
+
+    /**
+     * Gets the maximum number of registers that may be in this instance, which
+     * is also the maximum-plus-one of register numbers that may be
+     * represented.
+     *
+     * @return {@code >= 0;} the maximum size
+     */
+    public int getMaxSize() {
+        return specs.length;
+    }
+
+    /**
+     * Gets the current size of this instance.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        int result = size;
+
+        if (result < 0) {
+            int len = specs.length;
+
+            result = 0;
+            for (int i = 0; i < len; i++) {
+                if (specs[i] != null) {
+                    result++;
+                }
+            }
+
+            size = result;
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the element with the given register number, if any.
+     *
+     * @param reg {@code >= 0;} the desired register number
+     * @return {@code null-ok;} the element with the given register number or
+     * {@code null} if there is none
+     */
+    public RegisterSpec get(int reg) {
+        try {
+            return specs[reg];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus reg");
+        }
+    }
+
+    /**
+     * Gets the element with the same register number as the given
+     * spec, if any. This is just a convenient shorthand for
+     * {@code get(spec.getReg())}.
+     *
+     * @param spec {@code non-null;} spec with the desired register number
+     * @return {@code null-ok;} the element with the matching register number or
+     * {@code null} if there is none
+     */
+    public RegisterSpec get(RegisterSpec spec) {
+        return get(spec.getReg());
+    }
+
+    /**
+     * Returns the spec in this set that's currently associated with a
+     * given local (type, name, and signature), or {@code null} if there is
+     * none. This ignores the register number of the given spec but
+     * matches on everything else.
+     *
+     * @param spec {@code non-null;} local to look for
+     * @return {@code null-ok;} first register found that matches, if any
+     */
+    public RegisterSpec findMatchingLocal(RegisterSpec spec) {
+        int length = specs.length;
+
+        for (int reg = 0; reg < length; reg++) {
+            RegisterSpec s = specs[reg];
+
+            if (s == null) {
+                continue;
+            }
+
+            if (spec.matchesVariable(s)) {
+                return s;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 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 {@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;
+
+        for (int reg = 0; reg < length; reg++) {
+            RegisterSpec spec = specs[reg];
+
+            if ((spec != null) && local.equals(spec.getLocalItem())) {
+                return spec;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Removes a spec from the set. Only the register number
+     * of the parameter is significant.
+     *
+     * @param toRemove {@code non-null;} register to remove.
+     */
+    public void remove(RegisterSpec toRemove) {
+        try {
+            specs[toRemove.getReg()] = null;
+            size = -1;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus reg");
+        }
+    }
+
+    /**
+     * Puts the given spec into the set. If there is already an element in
+     * the set with the same register number, it is replaced. Additionally,
+     * if the previous element is for a category-2 register, then that
+     * previous element is nullified. Finally, if the given spec is for
+     * a category-2 register, then the immediately subsequent element
+     * is nullified.
+     *
+     * @param spec {@code non-null;} the register spec to put in the instance
+     */
+    public void put(RegisterSpec spec) {
+        throwIfImmutable();
+
+        if (spec == null) {
+            throw new NullPointerException("spec == null");
+        }
+
+        size = -1;
+
+        try {
+            int reg = spec.getReg();
+            specs[reg] = spec;
+
+            if (reg > 0) {
+                int prevReg = reg - 1;
+                RegisterSpec prevSpec = specs[prevReg];
+                if ((prevSpec != null) && (prevSpec.getCategory() == 2)) {
+                    specs[prevReg] = null;
+                }
+            }
+
+            if (spec.getCategory() == 2) {
+                specs[reg + 1] = null;
+            }
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("spec.getReg() out of range");
+        }
+    }
+
+    /**
+     * Put the entire contents of the given set into this one.
+     *
+     * @param set {@code non-null;} the set to put into this instance
+     */
+    public void putAll(RegisterSpecSet set) {
+        int max = set.getMaxSize();
+
+        for (int i = 0; i < max; i++) {
+            RegisterSpec spec = set.get(i);
+            if (spec != null) {
+                put(spec);
+            }
+        }
+    }
+
+    /**
+     * Intersects this instance with the given one, modifying this
+     * instance. The intersection consists of the pairwise
+     * {@link RegisterSpec#intersect} of corresponding elements from
+     * this instance and the given one where both are non-null.
+     *
+     * @param other {@code non-null;} set to intersect with
+     * @param localPrimary whether local variables are primary to
+     * the intersection; if {@code true}, then the only non-null
+     * result elements occur when registers being intersected have
+     * equal names (or both have {@code null} names)
+     */
+    public void intersect(RegisterSpecSet other, boolean localPrimary) {
+        throwIfImmutable();
+
+        RegisterSpec[] otherSpecs = other.specs;
+        int thisLen = specs.length;
+        int len = Math.min(thisLen, otherSpecs.length);
+
+        size = -1;
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+
+            if (spec == null) {
+                continue;
+            }
+
+            RegisterSpec intersection =
+                spec.intersect(otherSpecs[i], localPrimary);
+            if (intersection != spec) {
+                specs[i] = intersection;
+            }
+        }
+
+        for (int i = len; i < thisLen; i++) {
+            specs[i] = null;
+        }
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * all register numbers are offset by the given amount. Mutability
+     * of the result is inherited from the original.
+     *
+     * @param delta the amount to offset the register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecSet withOffset(int delta) {
+        int len = specs.length;
+        RegisterSpecSet result = new RegisterSpecSet(len + delta);
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            if (spec != null) {
+                result.put(spec.withOffset(delta));
+            }
+        }
+
+        result.size = size;
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Makes and return a mutable copy of this instance.
+     *
+     * @return {@code non-null;} the mutable copy
+     */
+    public RegisterSpecSet mutableCopy() {
+        int len = specs.length;
+        RegisterSpecSet copy = new RegisterSpecSet(len);
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            if (spec != null) {
+                copy.put(spec);
+            }
+        }
+
+        copy.size = size;
+
+        return copy;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/Rop.java b/dexgen/src/com/android/dexgen/rop/code/Rop.java
new file mode 100644
index 0000000..db9a6c2
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/Rop.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Class that describes all the immutable parts of register-based operations.
+ */
+public final class Rop {
+    /** minimum {@code BRANCH_*} value */
+    public static final int BRANCH_MIN = 1;
+
+    /** indicates a non-branching op */
+    public static final int BRANCH_NONE = 1;
+
+    /** indicates a function/method return */
+    public static final int BRANCH_RETURN = 2;
+
+    /** indicates an unconditional goto */
+    public static final int BRANCH_GOTO = 3;
+
+    /** indicates a two-way branch */
+    public static final int BRANCH_IF = 4;
+
+    /** indicates a switch-style branch */
+    public static final int BRANCH_SWITCH = 5;
+
+    /** indicates a throw-style branch (both always-throws and may-throw) */
+    public static final int BRANCH_THROW = 6;
+
+    /** maximum {@code BRANCH_*} value */
+    public static final int BRANCH_MAX = 6;
+
+    /** the opcode; one of the constants in {@link RegOps} */
+    private final int opcode;
+
+    /**
+     * {@code non-null;} result type of this operation; {@link Type#VOID} for
+     * no-result operations
+     */
+    private final Type result;
+
+    /** {@code non-null;} types of all the sources of this operation */
+    private final TypeList sources;
+
+    /** {@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_*}
+     * constants in this class
+     */
+    private final int branchingness;
+
+    /** whether this is a function/method call op or similar */
+    private final boolean isCallLike;
+
+    /** {@code null-ok;} nickname, if specified (used for debugging) */
+    private final String nickname;
+
+    /**
+     * Constructs an instance. This method is private. Use one of the
+     * public constructors.
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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_*} constants
+     * @param isCallLike whether the op is a function/method call or similar
+     * @param nickname {@code null-ok;} optional nickname (used for debugging)
+     */
+    public Rop(int opcode, Type result, TypeList sources,
+               TypeList exceptions, int branchingness, boolean isCallLike,
+               String nickname) {
+        if (result == null) {
+            throw new NullPointerException("result == null");
+        }
+
+        if (sources == null) {
+            throw new NullPointerException("sources == null");
+        }
+
+        if (exceptions == null) {
+            throw new NullPointerException("exceptions == null");
+        }
+
+        if ((branchingness < BRANCH_MIN) || (branchingness > BRANCH_MAX)) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if ((exceptions.size() != 0) && (branchingness != BRANCH_THROW)) {
+            throw new IllegalArgumentException("exceptions / branchingness " +
+                                               "mismatch");
+        }
+
+        this.opcode = opcode;
+        this.result = result;
+        this.sources = sources;
+        this.exceptions = exceptions;
+        this.branchingness = branchingness;
+        this.isCallLike = isCallLike;
+        this.nickname = nickname;
+    }
+
+    /**
+     * Constructs an instance. The constructed instance is never a
+     * call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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_*} 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) {
+        this(opcode, result, sources, exceptions, branchingness, false,
+             nickname);
+    }
+
+    /**
+     * Constructs a no-exception instance. The constructed instance is never a
+     * call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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_*} constants
+     * @param nickname {@code null-ok;} optional nickname (used for debugging)
+     */
+    public Rop(int opcode, Type result, TypeList sources, int branchingness,
+               String nickname) {
+        this(opcode, result, sources, StdTypeList.EMPTY, branchingness, false,
+             nickname);
+    }
+
+    /**
+     * Constructs a non-branching no-exception instance. The
+     * {@code branchingness} is always {@code BRANCH_NONE},
+     * and it is never a call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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,
+             false, nickname);
+    }
+
+    /**
+     * Constructs a non-empty exceptions instance. Its
+     * {@code branchingness} is always {@code BRANCH_THROW},
+     * but it is never a call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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 {@code null-ok;} optional nickname (used for debugging)
+     */
+    public Rop(int opcode, Type result, TypeList sources, TypeList exceptions,
+               String nickname) {
+        this(opcode, result, sources, exceptions, Rop.BRANCH_THROW, false,
+             nickname);
+    }
+
+    /**
+     * Constructs a non-nicknamed instance with non-empty exceptions, which
+     * is always a call-like op (see {@link #isCallLike}). Its
+     * {@code branchingness} is always {@code BRANCH_THROW}.
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param sources {@code non-null;} types of all the sources of this operation
+     * @param exceptions {@code non-null;} list of possible types thrown by this
+     * operation
+     */
+    public Rop(int opcode, TypeList sources, TypeList exceptions) {
+        this(opcode, Type.VOID, sources, exceptions, Rop.BRANCH_THROW, true,
+             null);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            // Easy out.
+            return true;
+        }
+
+        if (!(other instanceof Rop)) {
+            return false;
+        }
+
+        Rop rop = (Rop) other;
+
+        return (opcode == rop.opcode) &&
+            (branchingness == rop.branchingness) &&
+            (result == rop.result) &&
+            sources.equals(rop.sources) &&
+            exceptions.equals(rop.exceptions);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int h = (opcode * 31) + branchingness;
+        h = (h * 31) + result.hashCode();
+        h = (h * 31) + sources.hashCode();
+        h = (h * 31) + exceptions.hashCode();
+
+        return h;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(40);
+
+        sb.append("Rop{");
+
+        sb.append(RegOps.opName(opcode));
+
+        if (result != Type.VOID) {
+            sb.append(" ");
+            sb.append(result);
+        } else {
+            sb.append(" .");
+        }
+
+        sb.append(" <-");
+
+        int sz = sources.size();
+        if (sz == 0) {
+            sb.append(" .");
+        } else {
+            for (int i = 0; i < sz; i++) {
+                sb.append(' ');
+                sb.append(sources.getType(i));
+            }
+        }
+
+        if (isCallLike) {
+            sb.append(" call");
+        }
+
+        sz = exceptions.size();
+        if (sz != 0) {
+            sb.append(" throws");
+            for (int i = 0; i < sz; i++) {
+                sb.append(' ');
+                Type one = exceptions.getType(i);
+                if (one == Type.THROWABLE) {
+                    sb.append("<any>");
+                } else {
+                    sb.append(exceptions.getType(i));
+                }
+            }
+        } else {
+            switch (branchingness) {
+                case BRANCH_NONE:   sb.append(" flows"); break;
+                case BRANCH_RETURN: sb.append(" returns"); break;
+                case BRANCH_GOTO:   sb.append(" gotos"); break;
+                case BRANCH_IF:     sb.append(" ifs"); break;
+                case BRANCH_SWITCH: sb.append(" switches"); break;
+                default: sb.append(" " + Hex.u1(branchingness)); break;
+            }
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the opcode.
+     *
+     * @return the opcode
+     */
+    public int getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the result type. A return value of {@link Type#VOID}
+     * means this operation returns nothing.
+     *
+     * @return {@code null-ok;} the result spec
+     */
+    public Type getResult() {
+        return result;
+    }
+
+    /**
+     * Gets the source types.
+     *
+     * @return {@code non-null;} the source types
+     */
+    public TypeList getSources() {
+        return sources;
+    }
+
+    /**
+     * Gets the list of exception types that might be thrown.
+     *
+     * @return {@code non-null;} the list of exception types
+     */
+    public TypeList getExceptions() {
+        return exceptions;
+    }
+
+    /**
+     * Gets the branchingness of this instance.
+     *
+     * @return the branchingness
+     */
+    public int getBranchingness() {
+        return branchingness;
+    }
+
+    /**
+     * Gets whether this opcode is a function/method call or similar.
+     *
+     * @return {@code true} iff this opcode is call-like
+     */
+    public boolean isCallLike() {
+        return isCallLike;
+    }
+
+
+    /**
+     * Gets whether this opcode is commutative (the order of its sources are
+     * unimportant) or not. All commutative Rops have exactly two sources and
+     * have no branchiness.
+     *
+     * @return true if rop is commutative
+     */
+    public boolean isCommutative() {
+        switch (opcode) {
+            case RegOps.AND:
+            case RegOps.OR:
+            case RegOps.XOR:
+            case RegOps.ADD:
+            case RegOps.MUL:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Gets the nickname. If this instance has no nickname, this returns
+     * the result of calling {@link #toString}.
+     *
+     * @return {@code non-null;} the nickname
+     */
+    public String getNickname() {
+        if (nickname != null) {
+            return nickname;
+        }
+
+        return toString();
+    }
+
+    /**
+     * Gets whether this operation can possibly throw an exception. This
+     * is just a convenient wrapper for
+     * {@code getExceptions().size() != 0}.
+     *
+     * @return {@code true} iff this operation can possibly throw
+     */
+    public final boolean canThrow() {
+        return (exceptions.size() != 0);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/RopMethod.java b/dexgen/src/com/android/dexgen/rop/code/RopMethod.java
new file mode 100644
index 0000000..ba65b3f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/RopMethod.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.util.Bits;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.IntList;
+
+/**
+ * All of the parts that make up a method at the rop layer.
+ */
+public final class RopMethod {
+    /** {@code non-null;} basic block list of the method */
+    private final BasicBlockList blocks;
+
+    /** {@code >= 0;} label for the block which starts the method */
+    private final int firstLabel;
+
+    /**
+     * {@code null-ok;} array of predecessors for each block, indexed by block
+     * label
+     */
+    private IntList[] predecessors;
+
+    /**
+     * {@code null-ok;} the predecessors for the implicit "exit" block, that is
+     * the labels for the blocks that return, if calculated
+     */
+    private IntList exitPredecessors;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param blocks {@code non-null;} basic block list of the method
+     * @param firstLabel {@code >= 0;} the label of the first block to execute
+     */
+    public RopMethod(BasicBlockList blocks, int firstLabel) {
+        if (blocks == null) {
+            throw new NullPointerException("blocks == null");
+        }
+
+        if (firstLabel < 0) {
+            throw new IllegalArgumentException("firstLabel < 0");
+        }
+
+        this.blocks = blocks;
+        this.firstLabel = firstLabel;
+
+        this.predecessors = null;
+        this.exitPredecessors = null;
+    }
+
+    /**
+     * Gets the basic block list for this method.
+     *
+     * @return {@code non-null;} the list
+     */
+    public BasicBlockList getBlocks() {
+        return blocks;
+    }
+
+    /**
+     * Gets the label for the first block in the method that this list
+     * represents.
+     *
+     * @return {@code >= 0;} the first-block label
+     */
+    public int getFirstLabel() {
+        return firstLabel;
+    }
+
+    /**
+     * Gets the predecessors associated with the given block. This throws
+     * an exception if there is no block with the given label.
+     *
+     * @param label {@code >= 0;} the label of the block in question
+     * @return {@code non-null;} the predecessors of that block
+     */
+    public IntList labelToPredecessors(int label) {
+        if (exitPredecessors == null) {
+            calcPredecessors();
+        }
+
+        IntList result = predecessors[label];
+
+        if (result == null) {
+            throw new RuntimeException("no such block: " + Hex.u2(label));
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the exit predecessors for this instance.
+     *
+     * @return {@code non-null;} the exit predecessors
+     */
+    public IntList getExitPredecessors() {
+        if (exitPredecessors == null) {
+            calcPredecessors();
+        }
+
+        return exitPredecessors;
+    }
+
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RopMethod withRegisterOffset(int delta) {
+        RopMethod result = new RopMethod(blocks.withRegisterOffset(delta),
+                                         firstLabel);
+
+        if (exitPredecessors != null) {
+            /*
+             * The predecessors have been calculated. It's safe to
+             * inject these into the new instance, since the
+             * transformation being applied doesn't affect the
+             * predecessors.
+             */
+            result.exitPredecessors = exitPredecessors;
+            result.predecessors = predecessors;
+        }
+
+        return result;
+    }
+
+    /**
+     * Calculates the predecessor sets for each block as well as for the
+     * exit.
+     */
+    private void calcPredecessors() {
+        int maxLabel = blocks.getMaxLabel();
+        IntList[] predecessors = new IntList[maxLabel];
+        IntList exitPredecessors = new IntList(10);
+        int sz = blocks.size();
+
+        /*
+         * For each block, find its successors, and add the block's label to
+         * the successor's predecessors.
+         */
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = blocks.get(i);
+            int label = one.getLabel();
+            IntList successors = one.getSuccessors();
+            int ssz = successors.size();
+            if (ssz == 0) {
+                // This block exits.
+                exitPredecessors.add(label);
+            } else {
+                for (int j = 0; j < ssz; j++) {
+                    int succLabel = successors.get(j);
+                    IntList succPreds = predecessors[succLabel];
+                    if (succPreds == null) {
+                        succPreds = new IntList(10);
+                        predecessors[succLabel] = succPreds;
+                    }
+                    succPreds.add(label);
+                }
+            }
+        }
+
+        // Sort and immutablize all the predecessor lists.
+        for (int i = 0; i < maxLabel; i++) {
+            IntList preds = predecessors[i];
+            if (preds != null) {
+                preds.sort();
+                preds.setImmutable();
+            }
+        }
+
+        exitPredecessors.sort();
+        exitPredecessors.setImmutable();
+
+        /*
+         * The start label might not ever have had any predecessors
+         * added to it (probably doesn't, because of how Java gets
+         * translated into rop form). So, check for this and rectify
+         * the situation if required.
+         */
+        if (predecessors[firstLabel] == null) {
+            predecessors[firstLabel] = IntList.EMPTY;
+        }
+
+        this.predecessors = predecessors;
+        this.exitPredecessors = exitPredecessors;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/Rops.java b/dexgen/src/com/android/dexgen/rop/code/Rops.java
new file mode 100644
index 0000000..ad9327e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/Rops.java
@@ -0,0 +1,2086 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstBaseMethodRef;
+import com.android.dexgen.rop.cst.CstMethodRef;
+import com.android.dexgen.rop.cst.CstType;
+import com.android.dexgen.rop.type.Prototype;
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeBearer;
+import com.android.dexgen.rop.type.TypeList;
+
+/**
+ * Standard instances of {@link Rop}.
+ */
+public final class Rops {
+    /** {@code nop()} */
+    public static final Rop NOP =
+        new Rop(RegOps.NOP, Type.VOID, StdTypeList.EMPTY, "nop");
+
+    /** {@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;} */
+    public static final Rop MOVE_LONG =
+        new Rop(RegOps.MOVE, Type.LONG, StdTypeList.LONG, "move-long");
+
+    /** {@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;} */
+    public static final Rop MOVE_DOUBLE =
+        new Rop(RegOps.MOVE, Type.DOUBLE, StdTypeList.DOUBLE, "move-double");
+
+    /** {@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;}
+     *
+     * Note that this rop-form instruction has no dex-form equivilent and
+     * must be removed before the dex conversion.
+     */
+    public static final Rop MOVE_RETURN_ADDRESS =
+        new Rop(RegOps.MOVE, Type.RETURN_ADDRESS,
+                StdTypeList.RETURN_ADDRESS, "move-return-address");
+
+    /** {@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);} */
+    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);} */
+    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);} */
+    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);} */
+    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;} */
+    public static final Rop CONST_INT =
+        new Rop(RegOps.CONST, Type.INT, StdTypeList.EMPTY, "const-int");
+
+    /** {@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;} */
+    public static final Rop CONST_FLOAT =
+        new Rop(RegOps.CONST, Type.FLOAT, StdTypeList.EMPTY, "const-float");
+
+    /** {@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;} */
+    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;} */
+    public static final Rop CONST_OBJECT_NOTHROW =
+        new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY,
+                "const-object-nothrow");
+
+    /** {@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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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]} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    public static final Rop REM_DOUBLE =
+        new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
+                "rem-double");
+
+    /** {@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;} */
+    public static final Rop NEG_LONG =
+        new Rop(RegOps.NEG, Type.LONG, StdTypeList.LONG, "neg-long");
+
+    /** {@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;} */
+    public static final Rop NEG_DOUBLE =
+        new Rop(RegOps.NEG, Type.DOUBLE, StdTypeList.DOUBLE, "neg-double");
+
+    /** {@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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    public static final Rop USHR_LONG =
+        new Rop(RegOps.USHR, Type.LONG, StdTypeList.LONG_INT, "ushr-long");
+
+    /** {@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;} */
+    public static final Rop NOT_LONG =
+        new Rop(RegOps.NOT, Type.LONG, StdTypeList.LONG, "not-long");
+
+    /** {@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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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);} */
+    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);} */
+    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);} */
+    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);} */
+    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);} */
+    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} */
+    public static final Rop CONV_L2I =
+        new Rop(RegOps.CONV, Type.INT, StdTypeList.LONG, "conv-l2i");
+
+    /** {@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} */
+    public static final Rop CONV_D2I =
+        new Rop(RegOps.CONV, Type.INT, StdTypeList.DOUBLE, "conv-d2i");
+
+    /** {@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} */
+    public static final Rop CONV_F2L =
+        new Rop(RegOps.CONV, Type.LONG, StdTypeList.FLOAT, "conv-f2l");
+
+    /** {@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} */
+    public static final Rop CONV_I2F =
+        new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.INT, "conv-i2f");
+
+    /** {@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} */
+    public static final Rop CONV_D2F =
+        new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.DOUBLE, "conv-d2f");
+
+    /** {@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} */
+    public static final Rop CONV_L2D =
+        new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.LONG, "conv-l2d");
+
+    /** {@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} (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} (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} (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} */
+    public static final Rop RETURN_VOID =
+        new Rop(RegOps.RETURN, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_RETURN,
+                "return-void");
+
+    /** {@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} */
+    public static final Rop RETURN_LONG =
+        new Rop(RegOps.RETURN, Type.VOID, StdTypeList.LONG, Rop.BRANCH_RETURN,
+                "return-long");
+
+    /** {@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} */
+    public static final Rop RETURN_DOUBLE =
+        new Rop(RegOps.RETURN, Type.VOID, StdTypeList.DOUBLE,
+                Rop.BRANCH_RETURN, "return-double");
+
+    /** {@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} */
+    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)} */
+    public static final Rop THROW =
+        new Rop(RegOps.THROW, Type.VOID, StdTypeList.THROWABLE,
+                StdTypeList.THROWABLE, "throw");
+
+    /** {@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)} */
+    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]} */
+    public static final Rop AGET_INT =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.INTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-int");
+
+    /** {@code r: long; x: long[]; y: int :: r = x[y]} */
+    public static final Rop AGET_LONG =
+        new Rop(RegOps.AGET, Type.LONG, StdTypeList.LONGARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-long");
+
+    /** {@code r: float; x: float[]; y: int :: r = x[y]} */
+    public static final Rop AGET_FLOAT =
+        new Rop(RegOps.AGET, Type.FLOAT, StdTypeList.FLOATARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-float");
+
+    /** {@code r: double; x: double[]; y: int :: r = x[y]} */
+    public static final Rop AGET_DOUBLE =
+        new Rop(RegOps.AGET, Type.DOUBLE, StdTypeList.DOUBLEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-double");
+
+    /** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
+    public static final Rop AGET_OBJECT =
+        new Rop(RegOps.AGET, Type.OBJECT, StdTypeList.OBJECTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-object");
+
+    /** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
+    public static final Rop AGET_BOOLEAN =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.BOOLEANARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-boolean");
+
+    /** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
+    public static final Rop AGET_BYTE =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.BYTEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte");
+
+    /** {@code r: char; x: char[]; y: int :: r = x[y]} */
+    public static final Rop AGET_CHAR =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.CHARARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char");
+
+    /** {@code r: short; x: short[]; y: int :: r = x[y]} */
+    public static final Rop AGET_SHORT =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.SHORTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-short");
+
+    /** {@code x,z: int; y: int[] :: y[z] = x} */
+    public static final Rop APUT_INT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_INTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int");
+
+    /** {@code x: long; y: long[]; z: int :: y[z] = x} */
+    public static final Rop APUT_LONG =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.LONG_LONGARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long");
+
+    /** {@code x: float; y: float[]; z: int :: y[z] = x} */
+    public static final Rop APUT_FLOAT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.FLOAT_FLOATARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aput-float");
+
+    /** {@code x: double; y: double[]; z: int :: y[z] = x} */
+    public static final Rop APUT_DOUBLE =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.DOUBLE_DOUBLEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aput-double");
+
+    /** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
+    public static final Rop APUT_OBJECT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.OBJECT_OBJECTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+                "aput-object");
+
+    /** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
+    public static final Rop APUT_BOOLEAN =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BOOLEANARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+                "aput-boolean");
+
+    /** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
+    public static final Rop APUT_BYTE =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BYTEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte");
+
+    /** {@code x: char; y: char[]; z: int :: y[z] = x} */
+    public static final Rop APUT_CHAR =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_CHARARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char");
+
+    /** {@code x: short; y: short[]; z: int :: y[z] = x} */
+    public static final Rop APUT_SHORT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_SHORTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+                "aput-short");
+
+    /**
+     * {@code T: any non-array object type :: r =
+     * alloc(T)} (allocate heap space for an object)
+     */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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} (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}. 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.
+     */
+    public static final Rop INSTANCE_OF =
+        new Rop(RegOps.INSTANCE_OF, Type.INT, StdTypeList.OBJECT,
+                Exceptions.LIST_Error, "instance-of");
+
+    /**
+     * {@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}
+     */
+    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}
+     */
+    public static final Rop GET_FIELD_FLOAT =
+        new Rop(RegOps.GET_FIELD, Type.FLOAT, StdTypeList.OBJECT,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-float");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-double");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-object");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-boolean");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-byte");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-char");
+
+    /**
+     * {@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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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}
+     */
+    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}
+     */
+    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}
+     */
+    public static final Rop PUT_FIELD_FLOAT =
+        new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.FLOAT_OBJECT,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-float");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-double");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-object");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-boolean");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-byte");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-char");
+
+    /**
+     * {@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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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}
+     */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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}} */
+    public static final Rop FILL_ARRAY_DATA =
+        new Rop(RegOps.FILL_ARRAY_DATA, Type.VOID, StdTypeList.EMPTY,
+                "fill-array-data");
+
+    /**
+     * Returns the appropriate rop for the given opcode, destination,
+     * and sources. The result is typically, but not necessarily, a
+     * shared instance.
+     *
+     * <p><b>Note:</b> This method does not do complete error checking on
+     * its arguments, and so it may return an instance which seemed "right
+     * enough" even though in actuality the passed arguments don't quite
+     * match what is returned. TODO: Revisit this issue.</p>
+     *
+     * @param opcode the opcode
+     * @param dest {@code non-null;} destination (result) type, or
+     * {@link Type#VOID} if none
+     * @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) {
+        switch (opcode) {
+            case RegOps.NOP: return NOP;
+            case RegOps.MOVE: return opMove(dest);
+            case RegOps.MOVE_PARAM: return opMoveParam(dest);
+            case RegOps.MOVE_EXCEPTION: return opMoveException(dest);
+            case RegOps.CONST: return opConst(dest);
+            case RegOps.GOTO: return GOTO;
+            case RegOps.IF_EQ: return opIfEq(sources);
+            case RegOps.IF_NE: return opIfNe(sources);
+            case RegOps.IF_LT: return opIfLt(sources);
+            case RegOps.IF_GE: return opIfGe(sources);
+            case RegOps.IF_LE: return opIfLe(sources);
+            case RegOps.IF_GT: return opIfGt(sources);
+            case RegOps.SWITCH: return SWITCH;
+            case RegOps.ADD: return opAdd(sources);
+            case RegOps.SUB: return opSub(sources);
+            case RegOps.MUL: return opMul(sources);
+            case RegOps.DIV: return opDiv(sources);
+            case RegOps.REM: return opRem(sources);
+            case RegOps.NEG: return opNeg(dest);
+            case RegOps.AND: return opAnd(sources);
+            case RegOps.OR: return opOr(sources);
+            case RegOps.XOR: return opXor(sources);
+            case RegOps.SHL: return opShl(sources);
+            case RegOps.SHR: return opShr(sources);
+            case RegOps.USHR: return opUshr(sources);
+            case RegOps.NOT: return opNot(dest);
+            case RegOps.CMPL: return opCmpl(sources.getType(0));
+            case RegOps.CMPG: return opCmpg(sources.getType(0));
+            case RegOps.CONV: return opConv(dest, sources.getType(0));
+            case RegOps.TO_BYTE: return TO_BYTE;
+            case RegOps.TO_CHAR: return TO_CHAR;
+            case RegOps.TO_SHORT: return TO_SHORT;
+            case RegOps.RETURN: {
+                if (sources.size() == 0) {
+                    return RETURN_VOID;
+                }
+                return opReturn(sources.getType(0));
+            }
+            case RegOps.ARRAY_LENGTH: return ARRAY_LENGTH;
+            case RegOps.THROW: return THROW;
+            case RegOps.MONITOR_ENTER: return MONITOR_ENTER;
+            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 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 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());
+            case RegOps.CHECK_CAST: return CHECK_CAST;
+            case RegOps.INSTANCE_OF: return INSTANCE_OF;
+            case RegOps.GET_FIELD: return opGetField(dest);
+            case RegOps.GET_STATIC: return opGetStatic(dest);
+            case RegOps.PUT_FIELD: return opPutField(sources.getType(0));
+            case RegOps.PUT_STATIC: return opPutStatic(sources.getType(0));
+            case RegOps.INVOKE_STATIC: {
+                return opInvokeStatic(((CstMethodRef) cst).getPrototype());
+            }
+            case RegOps.INVOKE_VIRTUAL: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeVirtual(meth);
+            }
+            case RegOps.INVOKE_SUPER: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeSuper(meth);
+            }
+            case RegOps.INVOKE_DIRECT: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeDirect(meth);
+            }
+            case RegOps.INVOKE_INTERFACE: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeInterface(meth);
+            }
+        }
+
+        throw new RuntimeException("unknown opcode " + RegOps.opName(opcode));
+    }
+
+    /**
+     * Returns the appropriate {@code move} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being moved
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMove(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return MOVE_INT;
+            case Type.BT_LONG:   return MOVE_LONG;
+            case Type.BT_FLOAT:  return MOVE_FLOAT;
+            case Type.BT_DOUBLE: return MOVE_DOUBLE;
+            case Type.BT_OBJECT: return MOVE_OBJECT;
+            case Type.BT_ADDR:   return MOVE_RETURN_ADDRESS;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code move-param} rop for the
+     * given type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being moved
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMoveParam(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return MOVE_PARAM_INT;
+            case Type.BT_LONG:   return MOVE_PARAM_LONG;
+            case Type.BT_FLOAT:  return MOVE_PARAM_FLOAT;
+            case Type.BT_DOUBLE: return MOVE_PARAM_DOUBLE;
+            case Type.BT_OBJECT: return MOVE_PARAM_OBJECT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code move-exception} rop for the
+     * given type. The result may be a shared instance.
+     *
+     * @param type {@code non-null;} type of the exception
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMoveException(TypeBearer type) {
+        return new Rop(RegOps.MOVE_EXCEPTION, type.getType(),
+                       StdTypeList.EMPTY, (String) null);
+    }
+
+    /**
+     * Returns the appropriate {@code move-result} rop for the
+     * given type. The result may be a shared 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(),
+                       StdTypeList.EMPTY, (String) null);
+    }
+
+    /**
+     * Returns the appropriate {@code move-result-pseudo} rop for the
+     * given type. The result may be a shared 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(),
+                       StdTypeList.EMPTY, (String) null);
+    }
+
+    /**
+     * Returns the appropriate {@code const} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the constant
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opConst(TypeBearer type) {
+        if (type.getType() == Type.KNOWN_NULL) {
+            return CONST_OBJECT_NOTHROW;
+        }
+
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return CONST_INT;
+            case Type.BT_LONG:   return CONST_LONG;
+            case Type.BT_FLOAT:  return CONST_FLOAT;
+            case Type.BT_DOUBLE: return CONST_DOUBLE;
+            case Type.BT_OBJECT: return CONST_OBJECT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code if-eq} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfEq(TypeList types) {
+        return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT,
+                      IF_EQ_INT, IF_EQ_OBJECT);
+    }
+
+    /**
+     * Returns the appropriate {@code if-ne} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfNe(TypeList types) {
+        return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT,
+                      IF_NE_INT, IF_NE_OBJECT);
+    }
+
+    /**
+     * Returns the appropriate {@code if-lt} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfLt(TypeList types) {
+        return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null);
+    }
+
+    /**
+     * Returns the appropriate {@code if-ge} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfGe(TypeList types) {
+        return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null);
+    }
+
+    /**
+     * Returns the appropriate {@code if-gt} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfGt(TypeList types) {
+        return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null);
+    }
+
+    /**
+     * Returns the appropriate {@code if-le} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfLe(TypeList types) {
+        return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null);
+    }
+
+    /**
+     * Helper for all the {@code if*}-related methods, which
+     * checks types and picks one of the four variants, throwing if
+     * there's a problem.
+     *
+     * @param types {@code non-null;} the types
+     * @param intZ {@code non-null;} the int-to-0 comparison
+     * @param objZ {@code null-ok;} the object-to-null comparison
+     * @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) {
+        switch(types.size()) {
+            case 1: {
+                switch (types.getType(0).getBasicFrameType()) {
+                    case Type.BT_INT: {
+                        return intZ;
+                    }
+                    case Type.BT_OBJECT: {
+                        if (objZ != null) {
+                            return objZ;
+                        }
+                    }
+                }
+                break;
+            }
+            case 2: {
+                int bt = types.getType(0).getBasicFrameType();
+                if (bt == types.getType(1).getBasicFrameType()) {
+                    switch (bt) {
+                        case Type.BT_INT: {
+                            return intInt;
+                        }
+                        case Type.BT_OBJECT: {
+                            if (objObj != null) {
+                                return objObj;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+
+        return throwBadTypes(types);
+    }
+
+    /**
+     * Returns the appropriate {@code add} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAdd(TypeList types) {
+        return pickBinaryOp(types, ADD_CONST_INT, ADD_CONST_LONG,
+                            ADD_CONST_FLOAT, ADD_CONST_DOUBLE, ADD_INT,
+                            ADD_LONG, ADD_FLOAT, ADD_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code sub} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opSub(TypeList types) {
+        return pickBinaryOp(types, SUB_CONST_INT, SUB_CONST_LONG,
+                            SUB_CONST_FLOAT, SUB_CONST_DOUBLE, SUB_INT,
+                            SUB_LONG, SUB_FLOAT, SUB_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code mul} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMul(TypeList types) {
+        return pickBinaryOp(types, MUL_CONST_INT, MUL_CONST_LONG,
+                            MUL_CONST_FLOAT, MUL_CONST_DOUBLE, MUL_INT,
+                            MUL_LONG, MUL_FLOAT, MUL_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code div} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opDiv(TypeList types) {
+        return pickBinaryOp(types, DIV_CONST_INT, DIV_CONST_LONG,
+                            DIV_CONST_FLOAT, DIV_CONST_DOUBLE, DIV_INT,
+                            DIV_LONG, DIV_FLOAT, DIV_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code rem} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opRem(TypeList types) {
+        return pickBinaryOp(types, REM_CONST_INT, REM_CONST_LONG,
+                            REM_CONST_FLOAT, REM_CONST_DOUBLE, REM_INT,
+                            REM_LONG, REM_FLOAT, REM_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code and} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAnd(TypeList types) {
+        return pickBinaryOp(types, AND_CONST_INT, AND_CONST_LONG, null, null,
+                            AND_INT, AND_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code or} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opOr(TypeList types) {
+        return pickBinaryOp(types, OR_CONST_INT, OR_CONST_LONG, null, null,
+                            OR_INT, OR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code xor} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opXor(TypeList types) {
+        return pickBinaryOp(types, XOR_CONST_INT, XOR_CONST_LONG, null, null,
+                            XOR_INT, XOR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code shl} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opShl(TypeList types) {
+        return pickBinaryOp(types, SHL_CONST_INT, SHL_CONST_LONG, null, null,
+                            SHL_INT, SHL_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code shr} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opShr(TypeList types) {
+        return pickBinaryOp(types, SHR_CONST_INT, SHR_CONST_LONG, null, null,
+                            SHR_INT, SHR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code ushr} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opUshr(TypeList types) {
+        return pickBinaryOp(types, USHR_CONST_INT, USHR_CONST_LONG, null, null,
+                            USHR_INT, USHR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate binary arithmetic rop for the given type
+     * and arguments. The result is a shared instance.
+     *
+     * @param types {@code non-null;} sources of the operation
+     * @param int1 {@code non-null;} the int-to-constant rop
+     * @param long1 {@code non-null;} the long-to-constant rop
+     * @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,
+                                    Rop long2, Rop float2, Rop double2) {
+        int bt1 = types.getType(0).getBasicFrameType();
+        Rop result = null;
+
+        switch (types.size()) {
+            case 1: {
+                switch(bt1) {
+                    case Type.BT_INT:    return int1;
+                    case Type.BT_LONG:   return long1;
+                    case Type.BT_FLOAT:  result = float1; break;
+                    case Type.BT_DOUBLE: result = double1; break;
+                }
+                break;
+            }
+            case 2: {
+                switch(bt1) {
+                    case Type.BT_INT:    return int2;
+                    case Type.BT_LONG:   return long2;
+                    case Type.BT_FLOAT:  result = float2; break;
+                    case Type.BT_DOUBLE: result = double2; break;
+                }
+                break;
+            }
+        }
+
+        if (result == null) {
+            return throwBadTypes(types);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the appropriate {@code neg} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being operated on
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opNeg(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return NEG_INT;
+            case Type.BT_LONG:   return NEG_LONG;
+            case Type.BT_FLOAT:  return NEG_FLOAT;
+            case Type.BT_DOUBLE: return NEG_DOUBLE;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code not} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being operated on
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opNot(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:  return NOT_INT;
+            case Type.BT_LONG: return NOT_LONG;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code cmpl} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being compared
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opCmpl(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_LONG:   return CMPL_LONG;
+            case Type.BT_FLOAT:  return CMPL_FLOAT;
+            case Type.BT_DOUBLE: return CMPL_DOUBLE;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code cmpg} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being compared
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opCmpg(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_FLOAT:  return CMPG_FLOAT;
+            case Type.BT_DOUBLE: return CMPG_DOUBLE;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code conv} rop for the given types. The
+     * result is a shared instance.
+     *
+     * @param dest {@code non-null;} target value type
+     * @param source {@code non-null;} source value type
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opConv(TypeBearer dest, TypeBearer source) {
+        int dbt = dest.getBasicFrameType();
+        switch (source.getBasicFrameType()) {
+            case Type.BT_INT: {
+                switch (dbt) {
+                    case Type.BT_LONG:   return CONV_I2L;
+                    case Type.BT_FLOAT:  return CONV_I2F;
+                    case Type.BT_DOUBLE: return CONV_I2D;
+                }
+            }
+            case Type.BT_LONG: {
+                switch (dbt) {
+                    case Type.BT_INT:    return CONV_L2I;
+                    case Type.BT_FLOAT:  return CONV_L2F;
+                    case Type.BT_DOUBLE: return CONV_L2D;
+                }
+            }
+            case Type.BT_FLOAT: {
+                switch (dbt) {
+                    case Type.BT_INT:    return CONV_F2I;
+                    case Type.BT_LONG:   return CONV_F2L;
+                    case Type.BT_DOUBLE: return CONV_F2D;
+                }
+            }
+            case Type.BT_DOUBLE: {
+                switch (dbt) {
+                    case Type.BT_INT:   return CONV_D2I;
+                    case Type.BT_LONG:  return CONV_D2L;
+                    case Type.BT_FLOAT: return CONV_D2F;
+                }
+            }
+        }
+
+        return throwBadTypes(StdTypeList.make(dest.getType(),
+                                              source.getType()));
+    }
+
+    /**
+     * Returns the appropriate {@code return} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being returned
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opReturn(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return RETURN_INT;
+            case Type.BT_LONG:   return RETURN_LONG;
+            case Type.BT_FLOAT:  return RETURN_FLOAT;
+            case Type.BT_DOUBLE: return RETURN_DOUBLE;
+            case Type.BT_OBJECT: return RETURN_OBJECT;
+            case Type.BT_VOID:   return RETURN_VOID;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code aget} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} element type of array being accessed
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAget(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return AGET_INT;
+            case Type.BT_LONG:    return AGET_LONG;
+            case Type.BT_FLOAT:   return AGET_FLOAT;
+            case Type.BT_DOUBLE:  return AGET_DOUBLE;
+            case Type.BT_OBJECT:  return AGET_OBJECT;
+            case Type.BT_BOOLEAN: return AGET_BOOLEAN;
+            case Type.BT_BYTE:    return AGET_BYTE;
+            case Type.BT_CHAR:    return AGET_CHAR;
+            case Type.BT_SHORT:   return AGET_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code aput} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} element type of array being accessed
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAput(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return APUT_INT;
+            case Type.BT_LONG:    return APUT_LONG;
+            case Type.BT_FLOAT:   return APUT_FLOAT;
+            case Type.BT_DOUBLE:  return APUT_DOUBLE;
+            case Type.BT_OBJECT:  return APUT_OBJECT;
+            case Type.BT_BOOLEAN: return APUT_BOOLEAN;
+            case Type.BT_BYTE:    return APUT_BYTE;
+            case Type.BT_CHAR:    return APUT_CHAR;
+            case Type.BT_SHORT:   return APUT_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code new-array} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param arrayType {@code non-null;} array type of array being created
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opNewArray(TypeBearer arrayType) {
+        Type type = arrayType.getType();
+        Type elementType = type.getComponentType();
+
+        switch (elementType.getBasicType()) {
+            case Type.BT_INT:     return NEW_ARRAY_INT;
+            case Type.BT_LONG:    return NEW_ARRAY_LONG;
+            case Type.BT_FLOAT:   return NEW_ARRAY_FLOAT;
+            case Type.BT_DOUBLE:  return NEW_ARRAY_DOUBLE;
+            case Type.BT_BOOLEAN: return NEW_ARRAY_BOOLEAN;
+            case Type.BT_BYTE:    return NEW_ARRAY_BYTE;
+            case Type.BT_CHAR:    return NEW_ARRAY_CHAR;
+            case Type.BT_SHORT:   return NEW_ARRAY_SHORT;
+            case Type.BT_OBJECT: {
+                return new Rop(RegOps.NEW_ARRAY, type, StdTypeList.INT,
+                        Exceptions.LIST_Error_NegativeArraySizeException,
+                        "new-array-object");
+            }
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code filled-new-array} rop for the given
+     * type. The result may be a shared instance.
+     *
+     * @param arrayType {@code non-null;} type of array being created
+     * @param count {@code >= 0;} number of elements that the array should have
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opFilledNewArray(TypeBearer arrayType, int count) {
+        Type type = arrayType.getType();
+        Type elementType = type.getComponentType();
+
+        if (elementType.isCategory2()) {
+            return throwBadType(arrayType);
+        }
+
+        if (count < 0) {
+            throw new IllegalArgumentException("count < 0");
+        }
+
+        StdTypeList sourceTypes = new StdTypeList(count);
+
+        for (int i = 0; i < count; i++) {
+            sourceTypes.set(i, elementType);
+        }
+
+        // Note: The resulting rop is considered call-like.
+        return new Rop(RegOps.FILLED_NEW_ARRAY,
+                       sourceTypes,
+                       Exceptions.LIST_Error);
+    }
+
+    /**
+     * Returns the appropriate {@code get-field} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opGetField(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return GET_FIELD_INT;
+            case Type.BT_LONG:    return GET_FIELD_LONG;
+            case Type.BT_FLOAT:   return GET_FIELD_FLOAT;
+            case Type.BT_DOUBLE:  return GET_FIELD_DOUBLE;
+            case Type.BT_OBJECT:  return GET_FIELD_OBJECT;
+            case Type.BT_BOOLEAN: return GET_FIELD_BOOLEAN;
+            case Type.BT_BYTE:    return GET_FIELD_BYTE;
+            case Type.BT_CHAR:    return GET_FIELD_CHAR;
+            case Type.BT_SHORT:   return GET_FIELD_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code put-field} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opPutField(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return PUT_FIELD_INT;
+            case Type.BT_LONG:    return PUT_FIELD_LONG;
+            case Type.BT_FLOAT:   return PUT_FIELD_FLOAT;
+            case Type.BT_DOUBLE:  return PUT_FIELD_DOUBLE;
+            case Type.BT_OBJECT:  return PUT_FIELD_OBJECT;
+            case Type.BT_BOOLEAN: return PUT_FIELD_BOOLEAN;
+            case Type.BT_BYTE:    return PUT_FIELD_BYTE;
+            case Type.BT_CHAR:    return PUT_FIELD_CHAR;
+            case Type.BT_SHORT:   return PUT_FIELD_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code get-static} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opGetStatic(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return GET_STATIC_INT;
+            case Type.BT_LONG:    return GET_STATIC_LONG;
+            case Type.BT_FLOAT:   return GET_STATIC_FLOAT;
+            case Type.BT_DOUBLE:  return GET_STATIC_DOUBLE;
+            case Type.BT_OBJECT:  return GET_STATIC_OBJECT;
+            case Type.BT_BOOLEAN: return GET_STATIC_BOOLEAN;
+            case Type.BT_BYTE:    return GET_STATIC_BYTE;
+            case Type.BT_CHAR:    return GET_STATIC_CHAR;
+            case Type.BT_SHORT:   return GET_STATIC_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code put-static} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opPutStatic(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return PUT_STATIC_INT;
+            case Type.BT_LONG:    return PUT_STATIC_LONG;
+            case Type.BT_FLOAT:   return PUT_STATIC_FLOAT;
+            case Type.BT_DOUBLE:  return PUT_STATIC_DOUBLE;
+            case Type.BT_OBJECT:  return PUT_STATIC_OBJECT;
+            case Type.BT_BOOLEAN: return PUT_STATIC_BOOLEAN;
+            case Type.BT_BYTE:    return PUT_STATIC_BYTE;
+            case Type.BT_CHAR:    return PUT_STATIC_CHAR;
+            case Type.BT_SHORT:   return PUT_STATIC_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-static} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeStatic(Prototype meth) {
+        return new Rop(RegOps.INVOKE_STATIC,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-virtual} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeVirtual(Prototype meth) {
+        return new Rop(RegOps.INVOKE_VIRTUAL,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-super} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeSuper(Prototype meth) {
+        return new Rop(RegOps.INVOKE_SUPER,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-direct} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeDirect(Prototype meth) {
+        return new Rop(RegOps.INVOKE_DIRECT,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-interface} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeInterface(Prototype meth) {
+        return new Rop(RegOps.INVOKE_INTERFACE,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code mark-local} rop for the given type.
+     * The result is a shared 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()) {
+            case Type.BT_INT:    return MARK_LOCAL_INT;
+            case Type.BT_LONG:   return MARK_LOCAL_LONG;
+            case Type.BT_FLOAT:  return MARK_LOCAL_FLOAT;
+            case Type.BT_DOUBLE: return MARK_LOCAL_DOUBLE;
+            case Type.BT_OBJECT: return MARK_LOCAL_OBJECT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Rops() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Throws the right exception to complain about a bogus type.
+     *
+     * @param type {@code non-null;} the bad type
+     * @return never
+     */
+    private static Rop throwBadType(TypeBearer type) {
+        throw new IllegalArgumentException("bad type: " + type);
+    }
+
+    /**
+     * Throws the right exception to complain about a bogus list of types.
+     *
+     * @param types {@code non-null;} the bad types
+     * @return never
+     */
+    private static Rop throwBadTypes(TypeList types) {
+        throw new IllegalArgumentException("bad types: " + types);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/SourcePosition.java b/dexgen/src/com/android/dexgen/rop/code/SourcePosition.java
new file mode 100644
index 0000000..cd0ea25
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/SourcePosition.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Information about a source position for code, which includes both a
+ * line number and original bytecode address.
+ */
+public final class SourcePosition {
+    /** {@code non-null;} convenient "no information known" instance */
+    public static final SourcePosition NO_INFO =
+        new SourcePosition(null, -1, -1);
+
+    /** {@code null-ok;} name of the file of origin or {@code null} if unknown */
+    private final CstUtf8 sourceFile;
+
+    /**
+     * {@code >= -1;} the bytecode address, or {@code -1} if that
+     * information is unknown
+     */
+    private final int address;
+
+    /**
+     * {@code >= -1;} the line number, or {@code -1} if that
+     * information is unknown
+     */
+    private final int line;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param sourceFile {@code null-ok;} name of the file of origin or
+     * {@code null} if unknown
+     * @param address {@code >= -1;} original bytecode address or {@code -1}
+     * if unknown
+     * @param line {@code >= -1;} original line number or {@code -1} if
+     * unknown
+     */
+    public SourcePosition(CstUtf8 sourceFile, int address, int line) {
+        if (address < -1) {
+            throw new IllegalArgumentException("address < -1");
+        }
+
+        if (line < -1) {
+            throw new IllegalArgumentException("line < -1");
+        }
+
+        this.sourceFile = sourceFile;
+        this.address = address;
+        this.line = line;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(50);
+
+        if (sourceFile != null) {
+            sb.append(sourceFile.toHuman());
+            sb.append(":");
+        }
+
+        if (line >= 0) {
+            sb.append(line);
+        }
+
+        sb.append('@');
+
+        if (address < 0) {
+            sb.append("????");
+        } else {
+            sb.append(Hex.u2(address));
+        }
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof SourcePosition)) {
+            return false;
+        }
+
+        if (this == other) {
+            return true;
+        }
+
+        SourcePosition pos = (SourcePosition) other;
+
+        return (address == pos.address) && sameLineAndFile(pos);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return sourceFile.hashCode() + address + line;
+    }
+
+    /**
+     * Returns whether the lines match between this instance and
+     * the one given.
+     *
+     * @param other {@code non-null;} the instance to compare to
+     * @return {@code true} iff the lines match
+     */
+    public boolean sameLine(SourcePosition other) {
+        return (line == other.line);
+    }
+
+    /**
+     * Returns whether the lines and files match between this instance and
+     * the one given.
+     *
+     * @param other {@code non-null;} the instance to compare to
+     * @return {@code true} iff the lines and files match
+     */
+    public boolean sameLineAndFile(SourcePosition other) {
+        return (line == other.line) &&
+            ((sourceFile == other.sourceFile) ||
+             ((sourceFile != null) && sourceFile.equals(other.sourceFile)));
+    }
+
+    /**
+     * Gets the source file, if known.
+     *
+     * @return {@code null-ok;} the source file or {@code null} if unknown
+     */
+    public CstUtf8 getSourceFile() {
+        return sourceFile;
+    }
+
+    /**
+     * Gets the original bytecode address.
+     *
+     * @return {@code >= -1;} the address or {@code -1} if unknown
+     */
+    public int getAddress() {
+        return address;
+    }
+
+    /**
+     * Gets the original line number.
+     *
+     * @return {@code >= -1;} the original line number or {@code -1} if
+     * unknown
+     */
+    public int getLine() {
+        return line;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/SwitchInsn.java b/dexgen/src/com/android/dexgen/rop/code/SwitchInsn.java
new file mode 100644
index 0000000..ee4f4b6
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/SwitchInsn.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.StdTypeList;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+import com.android.dexgen.util.IntList;
+
+/**
+ * Instruction which contains switch cases.
+ */
+public final class SwitchInsn
+        extends Insn {
+    /** {@code non-null;} list of switch cases */
+    private final IntList cases;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @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) {
+        super(opcode, position, result, sources);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_SWITCH) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if (cases == null) {
+            throw new NullPointerException("cases == null");
+        }
+
+        this.cases = cases;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return cases.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitSwitchInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new SwitchInsn(getOpcode(), getPosition(),
+                              getResult().withOffset(delta),
+                              getSources().withOffset(delta),
+                              cases);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p> SwitchInsn always compares false. The current use for this method
+     * never encounters {@code SwitchInsn}s
+     */
+    @Override
+    public boolean contentEquals(Insn b) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new SwitchInsn(getOpcode(), getPosition(),
+                              result,
+                              sources,
+                              cases);
+    }
+
+    /**
+     * Gets the list of switch cases.
+     *
+     * @return {@code non-null;} the case list
+     */
+    public IntList getCases() {
+        return cases;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/ThrowingCstInsn.java b/dexgen/src/com/android/dexgen/rop/code/ThrowingCstInsn.java
new file mode 100644
index 0000000..7262254
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/ThrowingCstInsn.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+
+/**
+ * Instruction which contains an explicit reference to a constant
+ * and which might throw an exception.
+ */
+public final class ThrowingCstInsn
+        extends CstInsn {
+    /** {@code non-null;} list of exceptions caught */
+    private final TypeList catches;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param sources {@code non-null;} specs for all the sources
+     * @param catches {@code non-null;} list of exceptions caught
+     * @param cst {@code non-null;} the constant
+     */
+    public ThrowingCstInsn(Rop opcode, SourcePosition position,
+                           RegisterSpecList sources,
+                           TypeList catches, Constant cst) {
+        super(opcode, position, null, sources, cst);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if (catches == null) {
+            throw new NullPointerException("catches == null");
+        }
+
+        this.catches = catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return getConstant().toHuman() + " " +
+                                 ThrowingInsn.toCatchString(catches);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitThrowingCstInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        return new ThrowingCstInsn(getOpcode(), getPosition(),
+                                   getSources(), catches.withAddedType(type),
+                                   getConstant());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new ThrowingCstInsn(getOpcode(), getPosition(),
+                                   getSources().withOffset(delta),
+                                   catches,
+                                   getConstant());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new ThrowingCstInsn(getOpcode(), getPosition(),
+                                   sources,
+                                   catches,
+                                   getConstant());
+    }
+
+
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/ThrowingInsn.java b/dexgen/src/com/android/dexgen/rop/code/ThrowingInsn.java
new file mode 100644
index 0000000..24611ad
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/ThrowingInsn.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeList;
+
+/**
+ * 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 {
+    /** {@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 {@code non-null;} the catches list
+     * @return {@code non-null;} the string form
+     */
+    public static String toCatchString(TypeList catches) {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append("catch");
+
+        int sz = catches.size();
+        for (int i = 0; i < sz; i++) {
+            sb.append(" ");
+            sb.append(catches.getType(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param sources {@code non-null;} specs for all the sources
+     * @param catches {@code non-null;} list of exceptions caught
+     */
+    public ThrowingInsn(Rop opcode, SourcePosition position,
+                        RegisterSpecList sources,
+                        TypeList catches) {
+        super(opcode, position, null, sources);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if (catches == null) {
+            throw new NullPointerException("catches == null");
+        }
+
+        this.catches = catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return toCatchString(catches);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitThrowingInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        return new ThrowingInsn(getOpcode(), getPosition(),
+                                getSources(), catches.withAddedType(type));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new ThrowingInsn(getOpcode(), getPosition(),
+                                getSources().withOffset(delta),
+                                catches);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new ThrowingInsn(getOpcode(), getPosition(),
+                                sources,
+                                catches);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/code/TranslationAdvice.java b/dexgen/src/com/android/dexgen/rop/code/TranslationAdvice.java
new file mode 100644
index 0000000..9edd248
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/code/TranslationAdvice.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+/**
+ * Interface for "advice" passed from the late stage of translation back
+ * to the early stage. This allows for the final target architecture to
+ * exert its influence early in the translation process without having
+ * the early stage code be explicitly tied to the target.
+ */
+public interface TranslationAdvice {
+    /**
+     * Returns an indication of whether the target can directly represent an
+     * instruction with the given opcode operating on the given arguments,
+     * where the last source argument is used as a constant. (That is, the
+     * last argument must have a type which indicates it is a known constant.)
+     * The instruction associated must have exactly two sources.
+     *
+     * @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,
+            RegisterSpec sourceA, RegisterSpec sourceB);
+
+    /**
+     * 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 {@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);
+
+    /**
+     * Gets the maximum register width that can be represented optimally.
+     * For example, Dex bytecode does not have instruction forms that take
+     * register numbers larger than 15 for all instructions so
+     * DexTranslationAdvice returns 15 here.
+     *
+     * @return register count noted above
+     */
+    public int getMaxOptimalRegisterCount();
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/Constant.java b/dexgen/src/com/android/dexgen/rop/cst/Constant.java
new file mode 100644
index 0000000..deaa5f4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/Constant.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * Base class for constants of all sorts.
+ */
+public abstract class Constant
+        implements ToHuman, Comparable<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} if this instance is category-1.
+     *
+     * @return {@code true} iff this instance is category-2
+     */
+    public abstract boolean isCategory2();
+
+    /**
+     * Returns the human name for the particular type of constant
+     * this instance is.
+     *
+     * @return {@code non-null;} the name
+     */
+    public abstract String typeName();
+
+    /**
+     * {@inheritDoc}
+     *
+     * This compares in class-major and value-minor order.
+     */
+    public final int compareTo(Constant other) {
+        Class clazz = getClass();
+        Class otherClazz = other.getClass();
+
+        if (clazz != otherClazz) {
+            return clazz.getName().compareTo(otherClazz.getName());
+        }
+
+        return compareTo0(other);
+    }
+
+    /**
+     * Compare the values of this and another instance, which are guaranteed
+     * to be of the same class. Subclasses must implement this.
+     *
+     * @param other {@code non-null;} the instance to compare to
+     * @return {@code -1}, {@code 0}, or {@code 1}, as usual
+     * for a comparison
+     */
+    protected abstract int compareTo0(Constant other);
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/ConstantPool.java b/dexgen/src/com/android/dexgen/rop/cst/ConstantPool.java
new file mode 100644
index 0000000..1ea188a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/ConstantPool.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Interface for constant pools, which are, more or less, just lists of
+ * {@link Constant} objects.
+ */
+public interface ConstantPool {
+    /**
+     * Get the "size" of the constant pool. This corresponds to the
+     * class file field {@code constant_pool_count}, and is in fact
+     * always at least one more than the actual size of the constant pool,
+     * as element {@code 0} is always invalid.
+     *
+     * @return {@code >= 1;} the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th entry in the constant pool, which must
+     * be valid.
+     *
+     * @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}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();} 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}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} and {@code Double}
+     * entries).
+     *
+     * @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/dexgen/src/com/android/dexgen/rop/cst/CstAnnotation.java b/dexgen/src/com/android/dexgen/rop/cst/CstAnnotation.java
new file mode 100644
index 0000000..89b4fd8
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstAnnotation.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.annotation.Annotation;
+
+/**
+ * Constant type that represents an annotation.
+ */
+public final class CstAnnotation extends Constant {
+    /** {@code non-null;} the actual annotation */
+    private final Annotation annotation;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotation {@code non-null;} the annotation to hold
+     */
+    public CstAnnotation(Annotation annotation) {
+        if (annotation == null) {
+            throw new NullPointerException("annotation == null");
+        }
+
+        annotation.throwIfMutable();
+
+        this.annotation = annotation;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof CstAnnotation)) {
+            return false;
+        }
+
+        return annotation.equals(((CstAnnotation) other).annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotation.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return annotation.compareTo(((CstAnnotation) other).annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return annotation.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "annotation";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return annotation.toString();
+    }
+
+    /**
+     * Get the underlying annotation.
+     *
+     * @return {@code non-null;} the annotation
+     */
+    public Annotation getAnnotation() {
+        return annotation;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstArray.java b/dexgen/src/com/android/dexgen/rop/cst/CstArray.java
new file mode 100644
index 0000000..2fad35e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstArray.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * Constant type to represent a fixed array of other constants. The contents
+ * may be of any type <i>other</i> than {@link CstUtf8}.
+ */
+public final class CstArray extends Constant {
+    /** {@code non-null;} the actual list of contents */
+    private final List list;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param list {@code non-null;} the actual list of contents
+     */
+    public CstArray(List list) {
+        if (list == null) {
+            throw new NullPointerException("list == null");
+        }
+
+        list.throwIfMutable();
+
+        this.list = list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof CstArray)) {
+            return false;
+        }
+
+        return list.equals(((CstArray) other).list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return list.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return list.compareTo(((CstArray) other).list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return list.toString("array{", ", ", "}");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "array";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return list.toHuman("{", ", ", "}");
+    }
+
+    /**
+     * Get the underlying list.
+     *
+     * @return {@code non-null;} the list
+     */
+    public List getList() {
+        return list;
+    }
+
+    /**
+     * List of {@link Constant} instances.
+     */
+    public static final class List
+            extends FixedSizeList implements Comparable<List> {
+        /**
+         * Constructs an instance. All indices initially contain
+         * {@code null}.
+         *
+         * @param size the size of the list
+         */
+        public List(int size) {
+            super(size);
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(List other) {
+            int thisSize = size();
+            int otherSize = other.size();
+            int compareSize = (thisSize < otherSize) ? thisSize : otherSize;
+
+            for (int i = 0; i < compareSize; i++) {
+                Constant thisItem = (Constant) get0(i);
+                Constant otherItem = (Constant) other.get0(i);
+                int compare = thisItem.compareTo(otherItem);
+                if (compare != 0) {
+                    return compare;
+                }
+            }
+
+            if (thisSize < otherSize) {
+                return -1;
+            } else if (thisSize > otherSize) {
+                return 1;
+            }
+
+            return 0;
+        }
+
+        /**
+         * Gets the element at the given index. It is an error to call
+         * this with the index for an element which was never set; if you
+         * do that, this will throw {@code NullPointerException}.
+         *
+         * @param n {@code >= 0, < size();} which index
+         * @return {@code non-null;} element at that index
+         */
+        public Constant get(int n) {
+            return (Constant) get0(n);
+        }
+
+        /**
+         * Sets the element at the given index.
+         *
+         * @param n {@code >= 0, < size();} which index
+         * @param a {@code null-ok;} the element to set at {@code n}
+         */
+        public void set(int n, Constant a) {
+            if (a instanceof CstUtf8) {
+                throw new IllegalArgumentException("bad value: " + a);
+            }
+
+            set0(n, a);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstBaseMethodRef.java b/dexgen/src/com/android/dexgen/rop/cst/CstBaseMethodRef.java
new file mode 100644
index 0000000..3914272
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstBaseMethodRef.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Prototype;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeBearer;
+
+/**
+ * Base class for constants of "methodish" type.
+ *
+ * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type
+ * of the method.</p>
+ */
+public abstract class CstBaseMethodRef
+        extends CstMemberRef {
+    /** {@code non-null;} the raw prototype for this method */
+    private final Prototype prototype;
+
+    /**
+     * {@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 {@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);
+
+        String descriptor = getNat().getDescriptor().getString();
+        this.prototype = Prototype.intern(descriptor);
+        this.instancePrototype = null;
+    }
+
+    /**
+     * Gets the raw prototype of this method. This doesn't include a
+     * {@code this} argument.
+     *
+     * @return {@code non-null;} the method prototype
+     */
+    public final Prototype getPrototype() {
+        return prototype;
+    }
+
+    /**
+     * Gets the prototype of this method as either a
+     * {@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} argument as the first
+     * one.
+     *
+     * @param isStatic whether the method should be considered static
+     * @return {@code non-null;} the method prototype
+     */
+    public final Prototype getPrototype(boolean isStatic) {
+        if (isStatic) {
+            return prototype;
+        } else {
+            if (instancePrototype == null) {
+                Type thisType = getDefiningClass().getClassType();
+                instancePrototype = prototype.withFirstParameter(thisType);
+            }
+            return instancePrototype;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected final int compareTo0(Constant other) {
+        int cmp = super.compareTo0(other);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        CstBaseMethodRef otherMethod = (CstBaseMethodRef) other;
+        return prototype.compareTo(otherMethod.prototype);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * In this case, this method returns the <i>return type</i> of this method.
+     *
+     * @return {@code non-null;} the method's return type
+     */
+    public final Type getType() {
+        return prototype.getReturnType();
+    }
+
+    /**
+     * 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} or
+     * instance context, one has to indicate this explicitly as an
+     * argument. This method is just a convenient shorthand for
+     * {@code getPrototype().getParameterTypes().getWordCount()},
+     * plus {@code 1} if the method is to be treated as an
+     * instance method.
+     *
+     * @param isStatic whether the method should be considered static
+     * @return {@code >= 0;} the argument word count
+     */
+    public final int getParameterWordCount(boolean isStatic) {
+        return getPrototype(isStatic).getParameterTypes().getWordCount();
+    }
+
+    /**
+     * Gets whether this is a reference to an instance initialization
+     * method. This is just a convenient shorthand for
+     * {@code getNat().isInstanceInit()}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isInstanceInit() {
+        return getNat().isInstanceInit();
+    }
+
+    /**
+     * Gets whether this is a reference to a class initialization
+     * method. This is just a convenient shorthand for
+     * {@code getNat().isClassInit()}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isClassInit() {
+        return getNat().isClassInit();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstBoolean.java b/dexgen/src/com/android/dexgen/rop/cst/CstBoolean.java
new file mode 100644
index 0000000..a7501e3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstBoolean.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Constants of type {@code boolean}.
+ */
+public final class CstBoolean
+        extends CstLiteral32 {
+    /** {@code non-null;} instance representing {@code false} */
+    public static final CstBoolean VALUE_FALSE = new CstBoolean(false);
+
+    /** {@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} 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} value. This
+     * will return an already-allocated instance.
+     *
+     * @param value must be either {@code 0} or {@code 1}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstBoolean make(int value) {
+        if (value == 0) {
+            return VALUE_FALSE;
+        } else if (value == 1) {
+            return VALUE_TRUE;
+        } else {
+            throw new IllegalArgumentException("bogus value: " + value);
+        }
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code boolean} value
+     */
+    private CstBoolean(boolean value) {
+        super(value ? 1 : 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return getValue() ? "boolean{true}" : "boolean{false}";
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.BOOLEAN;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "boolean";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return getValue() ? "true" : "false";
+    }
+
+    /**
+     * Gets the {@code boolean} value.
+     *
+     * @return the value
+     */
+    public boolean getValue() {
+        return (getIntBits() == 0) ? false : true;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstByte.java b/dexgen/src/com/android/dexgen/rop/cst/CstByte.java
new file mode 100644
index 0000000..f9b97cb
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstByte.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code byte}.
+ */
+public final class CstByte
+        extends CstLiteral32 {
+    /** {@code non-null;} the value {@code 0} as an instance of this class */
+    public static final CstByte VALUE_0 = make((byte) 0);
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param value the {@code byte} value
+     */
+    public static CstByte make(byte value) {
+        return new CstByte(value);
+    }
+
+    /**
+     * Makes an instance for the given {@code int} value. This
+     * may (but does not necessarily) return an already-allocated
+     * instance.
+     *
+     * @param value the value, which must be in range for a {@code byte}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstByte make(int value) {
+        byte cast = (byte) value;
+
+        if (cast != value) {
+            throw new IllegalArgumentException("bogus byte value: " +
+                    value);
+        }
+
+        return make(cast);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code byte} value
+     */
+    private CstByte(byte value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "byte{0x" + Hex.u1(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.BYTE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "byte";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code byte} value.
+     *
+     * @return the value
+     */
+    public byte getValue() {
+        return (byte) getIntBits();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstChar.java b/dexgen/src/com/android/dexgen/rop/cst/CstChar.java
new file mode 100644
index 0000000..d006525
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstChar.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code char}.
+ */
+public final class CstChar
+        extends CstLiteral32 {
+    /** {@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} value
+     */
+    public static CstChar make(char value) {
+        return new CstChar(value);
+    }
+
+    /**
+     * Makes an instance for the given {@code int} value. This
+     * may (but does not necessarily) return an already-allocated
+     * instance.
+     *
+     * @param value the value, which must be in range for a {@code char}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstChar make(int value) {
+        char cast = (char) value;
+
+        if (cast != value) {
+            throw new IllegalArgumentException("bogus char value: " +
+                    value);
+        }
+
+        return make(cast);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code char} value
+     */
+    private CstChar(char value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "char{0x" + Hex.u2(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.CHAR;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "char";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code char} value.
+     *
+     * @return the value
+     */
+    public char getValue() {
+        return (char) getIntBits();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstDouble.java b/dexgen/src/com/android/dexgen/rop/cst/CstDouble.java
new file mode 100644
index 0000000..84a53e6
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstDouble.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Double_info}.
+ */
+public final class CstDouble
+        extends CstLiteral64 {
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstDouble VALUE_0 =
+        new CstDouble(Double.doubleToLongBits(0.0));
+
+    /** {@code non-null;} instance representing {@code 1} */
+    public static final CstDouble VALUE_1 =
+        new CstDouble(Double.doubleToLongBits(1.0));
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param bits the {@code double} value as {@code long} bits
+     */
+    public static CstDouble make(long bits) {
+        /*
+         * Note: Javadoc notwithstanding, this implementation always
+         * allocates.
+         */
+        return new CstDouble(bits);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param bits the {@code double} value as {@code long} bits
+     */
+    private CstDouble(long bits) {
+        super(bits);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        long bits = getLongBits();
+        return "double{0x" + Hex.u8(bits) + " / " +
+            Double.longBitsToDouble(bits) + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.DOUBLE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "double";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Double.toString(Double.longBitsToDouble(getLongBits()));
+    }
+
+    /**
+     * Gets the {@code double} value.
+     *
+     * @return the value
+     */
+    public double getValue() {
+        return Double.longBitsToDouble(getLongBits());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstEnumRef.java b/dexgen/src/com/android/dexgen/rop/cst/CstEnumRef.java
new file mode 100644
index 0000000..d566946
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstEnumRef.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Constant type to represent a reference to a particular constant
+ * value of an enumerated type.
+ */
+public final class CstEnumRef extends CstMemberRef {
+    /** {@code null-ok;} the corresponding field ref, lazily initialized */
+    private CstFieldRef fieldRef;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param nat {@code non-null;} the name-and-type; the defining class is derived
+     * from this
+     */
+    public CstEnumRef(CstNat nat) {
+        super(new CstType(nat.getFieldType()), nat);
+
+        fieldRef = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "enum";
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <b>Note:</b> This returns the enumerated type.
+     */
+    public Type getType() {
+        return getDefiningClass().getClassType();
+    }
+
+    /**
+     * Get a {@link CstFieldRef} that corresponds with this instance.
+     *
+     * @return {@code non-null;} the corresponding field reference
+     */
+    public CstFieldRef getFieldRef() {
+        if (fieldRef == null) {
+            fieldRef = new CstFieldRef(getDefiningClass(), getNat());
+        }
+
+        return fieldRef;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstFieldRef.java b/dexgen/src/com/android/dexgen/rop/cst/CstFieldRef.java
new file mode 100644
index 0000000..6a6218c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstFieldRef.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Constants of type {@code CONSTANT_Fieldref_info}.
+ */
+public final class CstFieldRef extends CstMemberRef {
+    /**
+     * Returns an instance of this class that represents the static
+     * 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}.
+     *
+     * @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),
+                CstNat.PRIMITIVE_TYPE_NAT);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @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);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "field";
+    }
+
+    /**
+     * Returns the type of this field.
+     *
+     * @return {@code non-null;} the field's type
+     */
+    public Type getType() {
+        return getNat().getFieldType();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        int cmp = super.compareTo0(other);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        CstFieldRef otherField = (CstFieldRef) other;
+        CstUtf8 thisDescriptor = getNat().getDescriptor();
+        CstUtf8 otherDescriptor = otherField.getNat().getDescriptor();
+        return thisDescriptor.compareTo(otherDescriptor);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstFloat.java b/dexgen/src/com/android/dexgen/rop/cst/CstFloat.java
new file mode 100644
index 0000000..6490f8f
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstFloat.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Float_info}.
+ */
+public final class CstFloat
+        extends CstLiteral32 {
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f));
+
+    /** {@code non-null;} instance representing {@code 1} */
+    public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f));
+
+    /** {@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} value as {@code int} bits
+     */
+    public static CstFloat make(int bits) {
+        /*
+         * Note: Javadoc notwithstanding, this implementation always
+         * allocates.
+         */
+        return new CstFloat(bits);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param bits the {@code float} value as {@code int} bits
+     */
+    private CstFloat(int bits) {
+        super(bits);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int bits = getIntBits();
+        return "float{0x" + Hex.u4(bits) + " / " +
+            Float.intBitsToFloat(bits) + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.FLOAT;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "float";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Float.toString(Float.intBitsToFloat(getIntBits()));
+    }
+
+    /**
+     * Gets the {@code float} value.
+     *
+     * @return the value
+     */
+    public float getValue() {
+        return Float.intBitsToFloat(getIntBits());
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstInteger.java b/dexgen/src/com/android/dexgen/rop/cst/CstInteger.java
new file mode 100644
index 0000000..41ef0a6
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstInteger.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Integer_info}.
+ */
+public final class CstInteger
+        extends CstLiteral32 {
+    /** {@code non-null;} array of cached instances */
+    private static final CstInteger[] cache = new CstInteger[511];
+
+    /** {@code non-null;} instance representing {@code -1} */
+    public static final CstInteger VALUE_M1 = make(-1);
+
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstInteger VALUE_0 = make(0);
+
+    /** {@code non-null;} instance representing {@code 1} */
+    public static final CstInteger VALUE_1 = make(1);
+
+    /** {@code non-null;} instance representing {@code 2} */
+    public static final CstInteger VALUE_2 = make(2);
+
+    /** {@code non-null;} instance representing {@code 3} */
+    public static final CstInteger VALUE_3 = make(3);
+
+    /** {@code non-null;} instance representing {@code 4} */
+    public static final CstInteger VALUE_4 = make(4);
+
+    /** {@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} value
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstInteger make(int value) {
+        /*
+         * Note: No need to synchronize, since we don't make any sort
+         * of guarantee about ==, and it's okay to overwrite existing
+         * entries too.
+         */
+        int idx = (value & 0x7fffffff) % cache.length;
+        CstInteger obj = cache[idx];
+
+        if ((obj != null) && (obj.getValue() == value)) {
+            return obj;
+        }
+
+        obj = new CstInteger(value);
+        cache[idx] = obj;
+        return obj;
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code int} value
+     */
+    private CstInteger(int value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "int{0x" + Hex.u4(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.INT;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "int";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code int} value.
+     *
+     * @return the value
+     */
+    public int getValue() {
+        return getIntBits();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstInterfaceMethodRef.java b/dexgen/src/com/android/dexgen/rop/cst/CstInterfaceMethodRef.java
new file mode 100644
index 0000000..c514b84
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstInterfaceMethodRef.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Constants of type {@code CONSTANT_InterfaceMethodref_info}.
+ */
+public final class CstInterfaceMethodRef
+        extends CstBaseMethodRef {
+    /**
+     * {@code null-ok;} normal {@link CstMethodRef} that corresponds to this
+     * instance, if calculated
+     */
+    private CstMethodRef methodRef;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the type of the defining class
+     * @param nat {@code non-null;} the name-and-type
+     */
+    public CstInterfaceMethodRef(CstType definingClass, CstNat nat) {
+        super(definingClass, nat);
+        methodRef = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "ifaceMethod";
+    }
+
+    /**
+     * Gets a normal (non-interface) {@link CstMethodRef} that corresponds to
+     * this instance.
+     *
+     * @return {@code non-null;} an appropriate instance
+     */
+    public CstMethodRef toMethodRef() {
+        if (methodRef == null) {
+            methodRef = new CstMethodRef(getDefiningClass(), getNat());
+        }
+
+        return methodRef;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstKnownNull.java b/dexgen/src/com/android/dexgen/rop/cst/CstKnownNull.java
new file mode 100644
index 0000000..58d6933
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstKnownNull.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Constant type to represent a known-{@code null} value.
+ */
+public final class CstKnownNull extends CstLiteralBits {
+    /** {@code non-null;} unique instance of this class */
+    public static final CstKnownNull THE_ONE = new CstKnownNull();
+
+    /**
+     * Constructs an instance. This class is not publicly instantiable. Use
+     * {@link #THE_ONE}.
+     */
+    private CstKnownNull() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        return (other instanceof CstKnownNull);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return 0x4466757a;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "known-null";
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.KNOWN_NULL;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "known-null";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return "null";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean fitsInInt() {
+        // See comment in getIntBits().
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * As "literal bits," a known-null is always represented as the
+     * number zero.
+     */
+    @Override
+    public int getIntBits() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * As "literal bits," a known-null is always represented as the
+     * number zero.
+     */
+    @Override
+    public long getLongBits() {
+        return 0;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstLiteral32.java b/dexgen/src/com/android/dexgen/rop/cst/CstLiteral32.java
new file mode 100644
index 0000000..f7f9199
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstLiteral32.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Constants which are literal 32-bit values of some sort.
+ */
+public abstract class CstLiteral32
+        extends CstLiteralBits {
+    /** the value as {@code int} bits */
+    private final int bits;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bits the value as {@code int} bits
+     */
+    /*package*/ CstLiteral32(int bits) {
+        this.bits = bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean equals(Object other) {
+        return (other != null) &&
+            (getClass() == other.getClass()) &&
+            bits == ((CstLiteral32) other).bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int hashCode() {
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        int otherBits = ((CstLiteral32) other).bits;
+
+        if (bits < otherBits) {
+            return -1;
+        } else if (bits > otherBits) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean fitsInInt() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int getIntBits() {
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final long getLongBits() {
+        return (long) bits;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstLiteral64.java b/dexgen/src/com/android/dexgen/rop/cst/CstLiteral64.java
new file mode 100644
index 0000000..0bf3152
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstLiteral64.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Constants which are literal 64-bit values of some sort.
+ */
+public abstract class CstLiteral64
+        extends CstLiteralBits {
+    /** the value as {@code long} bits */
+    private final long bits;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bits the value as {@code long} bits
+     */
+    /*package*/ CstLiteral64(long bits) {
+        this.bits = bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean equals(Object other) {
+        return (other != null) &&
+            (getClass() == other.getClass()) &&
+            bits == ((CstLiteral64) other).bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int hashCode() {
+        return (int) bits ^ (int) (bits >> 32);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        long otherBits = ((CstLiteral64) other).bits;
+
+        if (bits < otherBits) {
+            return -1;
+        } else if (bits > otherBits) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean isCategory2() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean fitsInInt() {
+        return (int) bits == bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int getIntBits() {
+        return (int) bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final long getLongBits() {
+        return bits;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstLiteralBits.java b/dexgen/src/com/android/dexgen/rop/cst/CstLiteralBits.java
new file mode 100644
index 0000000..97e8bd1
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstLiteralBits.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Constants which are literal bitwise values of some sort.
+ */
+public abstract class CstLiteralBits
+        extends TypedConstant {
+    /**
+     * Returns whether or not this instance's value may be accurately
+     * 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} iff this instance fits in an {@code int}
+     */
+    public abstract boolean fitsInInt();
+
+    /**
+     * 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
+     */
+    public abstract int getIntBits();
+
+    /**
+     * Gets the value as {@code long} bits. If this instance contains
+     * fewer bits than fit in a {@code long}, then the result of this
+     * method is the sign extension of the value.
+     *
+     * @return the bits
+     */
+    public abstract long getLongBits();
+
+    /**
+     * Returns true if this value can fit in 16 bits with sign-extension.
+     *
+     * @return true if the sign-extended lower 16 bits are the same as
+     * the value.
+     */
+    public boolean fitsIn16Bits() {
+        if (! fitsInInt()) {
+            return false;
+        }
+
+        int bits = getIntBits();
+        return (short) bits == bits;
+    }
+
+    /**
+     * Returns true if this value can fit in 8 bits with sign-extension.
+     *
+     * @return true if the sign-extended lower 8 bits are the same as
+     * the value.
+     */
+    public boolean fitsIn8Bits() {
+        if (! fitsInInt()) {
+            return false;
+        }
+
+        int bits = getIntBits();
+        return (byte) bits == bits;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstLong.java b/dexgen/src/com/android/dexgen/rop/cst/CstLong.java
new file mode 100644
index 0000000..f737094
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstLong.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Long_info}.
+ */
+public final class CstLong
+        extends CstLiteral64 {
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstLong VALUE_0 = make(0);
+
+    /** {@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} value
+     */
+    public static CstLong make(long value) {
+        /*
+         * Note: Javadoc notwithstanding, this implementation always
+         * allocates.
+         */
+        return new CstLong(value);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code long} value
+     */
+    private CstLong(long value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        long value = getLongBits();
+        return "long{0x" + Hex.u8(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.LONG;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "long";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Long.toString(getLongBits());
+    }
+
+    /**
+     * Gets the {@code long} value.
+     *
+     * @return the value
+     */
+    public long getValue() {
+        return getLongBits();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstMemberRef.java b/dexgen/src/com/android/dexgen/rop/cst/CstMemberRef.java
new file mode 100644
index 0000000..5abca4b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstMemberRef.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Constants of type {@code CONSTANT_*ref_info}.
+ */
+public abstract class CstMemberRef extends TypedConstant {
+    /** {@code non-null;} the type of the defining class */
+    private final CstType definingClass;
+
+    /** {@code non-null;} the name-and-type */
+    private final CstNat nat;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+            throw new NullPointerException("definingClass == null");
+        }
+
+        if (nat == null) {
+            throw new NullPointerException("nat == null");
+        }
+
+        this.definingClass = definingClass;
+        this.nat = nat;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean equals(Object other) {
+        if ((other == null) || (getClass() != other.getClass())) {
+            return false;
+        }
+
+        CstMemberRef otherRef = (CstMemberRef) other;
+        return definingClass.equals(otherRef.definingClass) &&
+            nat.equals(otherRef.nat);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int hashCode() {
+        return (definingClass.hashCode() * 31) ^ nat.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <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()}.</p>
+     */
+    @Override
+    protected int compareTo0(Constant other) {
+        CstMemberRef otherMember = (CstMemberRef) other;
+        int cmp = definingClass.compareTo(otherMember.definingClass);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        CstUtf8 thisName = nat.getName();
+        CstUtf8 otherName = otherMember.nat.getName();
+
+        return thisName.compareTo(otherName);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toString() {
+        return typeName() + '{' + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public final String toHuman() {
+        return definingClass.toHuman() + '.' + nat.toHuman();
+    }
+
+    /**
+     * Gets the type of the defining class.
+     *
+     * @return {@code non-null;} the type of defining class
+     */
+    public final CstType getDefiningClass() {
+        return definingClass;
+    }
+
+    /**
+     * Gets the defining name-and-type.
+     *
+     * @return {@code non-null;} the name-and-type
+     */
+    public final CstNat getNat() {
+        return nat;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstMethodRef.java b/dexgen/src/com/android/dexgen/rop/cst/CstMethodRef.java
new file mode 100644
index 0000000..0bf3851
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstMethodRef.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+/**
+ * Constants of type {@code CONSTANT_Methodref_info}.
+ */
+public final class CstMethodRef
+        extends CstBaseMethodRef {
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the type of the defining class
+     * @param nat {@code non-null;} the name-and-type
+     */
+    public CstMethodRef(CstType definingClass, CstNat nat) {
+        super(definingClass, nat);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "method";
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstNat.java b/dexgen/src/com/android/dexgen/rop/cst/CstNat.java
new file mode 100644
index 0000000..34d2bfc
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstNat.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Constants of type {@code CONSTANT_NameAndType_info}.
+ */
+public final class CstNat extends Constant {
+    /**
+     * {@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;"));
+
+    /** {@code non-null;} the name */
+    private final CstUtf8 name;
+
+    /** {@code non-null;} the descriptor (type) */
+    private final CstUtf8 descriptor;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param name {@code non-null;} the name
+     * @param descriptor {@code non-null;} the descriptor
+     */
+    public CstNat(CstUtf8 name, CstUtf8 descriptor) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        this.name = name;
+        this.descriptor = descriptor;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstNat)) {
+            return false;
+        }
+
+        CstNat otherNat = (CstNat) other;
+        return name.equals(otherNat.name) &&
+            descriptor.equals(otherNat.descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return (name.hashCode() * 31) ^ descriptor.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        CstNat otherNat = (CstNat) other;
+        int cmp = name.compareTo(otherNat.name);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        return descriptor.compareTo(otherNat.descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "nat{" + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "nat";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /**
+     * Gets the name.
+     *
+     * @return {@code non-null;} the name
+     */
+    public CstUtf8 getName() {
+        return name;
+    }
+
+    /**
+     * Gets the descriptor.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public CstUtf8 getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Returns an unadorned but human-readable version of the name-and-type
+     * value.
+     *
+     * @return {@code non-null;} the human form
+     */
+    public String toHuman() {
+        return name.toHuman() + ':' + descriptor.toHuman();
+    }
+
+    /**
+     * Gets the field type corresponding to this instance's descriptor.
+     * This method is only valid to call if the descriptor in fact describes
+     * a field (and not a method).
+     *
+     * @return {@code non-null;} the field type
+     */
+    public Type getFieldType() {
+        return Type.intern(descriptor.getString());
+    }
+
+    /**
+     * Gets whether this instance has the name of a standard instance
+     * initialization method. This is just a convenient shorthand for
+     * {@code getName().getString().equals("<init>")}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isInstanceInit() {
+        return name.getString().equals("<init>");
+    }
+
+    /**
+     * Gets whether this instance has the name of a standard class
+     * initialization method. This is just a convenient shorthand for
+     * {@code getName().getString().equals("<clinit>")}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isClassInit() {
+        return name.getString().equals("<clinit>");
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstShort.java b/dexgen/src/com/android/dexgen/rop/cst/CstShort.java
new file mode 100644
index 0000000..c81a589
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstShort.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code short}.
+ */
+public final class CstShort
+        extends CstLiteral32 {
+    /** {@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} 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} value. This
+     * may (but does not necessarily) return an already-allocated
+     * instance.
+     *
+     * @param value the value, which must be in range for a {@code short}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstShort make(int value) {
+        short cast = (short) value;
+
+        if (cast != value) {
+            throw new IllegalArgumentException("bogus short value: " +
+                    value);
+        }
+
+        return make(cast);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code short} value
+     */
+    private CstShort(short value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "short{0x" + Hex.u2(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.SHORT;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "short";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code short} value.
+     *
+     * @return the value
+     */
+    public short getValue() {
+        return (short) getIntBits();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstString.java b/dexgen/src/com/android/dexgen/rop/cst/CstString.java
new file mode 100644
index 0000000..a2babf4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstString.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Constants of type {@code CONSTANT_String_info}.
+ */
+public final class CstString
+        extends TypedConstant {
+    /** {@code non-null;} the string value */
+    private final CstUtf8 string;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param string {@code non-null;} the string value
+     */
+    public CstString(CstUtf8 string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        this.string = string;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param string {@code non-null;} the string value
+     */
+    public CstString(String string) {
+        this(new CstUtf8(string));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstString)) {
+            return false;
+        }
+
+        return string.equals(((CstString) other).string);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return string.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return string.compareTo(((CstString) other).string);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "string{" + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.STRING;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "string";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return string.toQuoted();
+    }
+
+    /**
+     * Gets the string value.
+     *
+     * @return {@code non-null;} the string value
+     */
+    public CstUtf8 getString() {
+        return string;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstType.java b/dexgen/src/com/android/dexgen/rop/cst/CstType.java
new file mode 100644
index 0000000..8ad418b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstType.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+import java.util.HashMap;
+
+/**
+ * Constants that represent an arbitrary type (reference or primitive).
+ */
+public final class CstType extends TypedConstant {
+    /** {@code non-null;} map of interned types */
+    private static final HashMap<Type, CstType> interns =
+        new HashMap<Type, CstType>(100);
+
+    /** {@code non-null;} instance corresponding to the class {@code Object} */
+    public static final CstType OBJECT = intern(Type.OBJECT);
+
+    /** {@code non-null;} instance corresponding to the class {@code Boolean} */
+    public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Byte} */
+    public static final CstType BYTE = intern(Type.BYTE_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Character} */
+    public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Double} */
+    public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Float} */
+    public static final CstType FLOAT = intern(Type.FLOAT_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Long} */
+    public static final CstType LONG = intern(Type.LONG_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Integer} */
+    public static final CstType INTEGER = intern(Type.INTEGER_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Short} */
+    public static final CstType SHORT = intern(Type.SHORT_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Void} */
+    public static final CstType VOID = intern(Type.VOID_CLASS);
+
+    /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
+    public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code byte[]} */
+    public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code char[]} */
+    public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code double[]} */
+    public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code float[]} */
+    public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code long[]} */
+    public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code int[]} */
+    public static final CstType INT_ARRAY = intern(Type.INT_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code short[]} */
+    public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY);
+
+    /** {@code non-null;} the underlying type */
+    private final Type type;
+
+    /**
+     * {@code null-ok;} the type descriptor corresponding to this instance, if
+     * calculated
+     */
+    private CstUtf8 descriptor;
+
+    /**
+     * 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}.
+     *
+     * @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()) {
+            case Type.BT_BOOLEAN: return BOOLEAN;
+            case Type.BT_BYTE:    return BYTE;
+            case Type.BT_CHAR:    return CHARACTER;
+            case Type.BT_DOUBLE:  return DOUBLE;
+            case Type.BT_FLOAT:   return FLOAT;
+            case Type.BT_INT:     return INTEGER;
+            case Type.BT_LONG:    return LONG;
+            case Type.BT_SHORT:   return SHORT;
+            case Type.BT_VOID:    return VOID;
+        }
+
+        throw new IllegalArgumentException("not primitive: " + primitiveType);
+    }
+
+    /**
+     * Returns an interned instance of this class for the given type.
+     *
+     * @param type {@code non-null;} the underlying type
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static CstType intern(Type type) {
+        CstType cst = interns.get(type);
+
+        if (cst == null) {
+            cst = new CstType(type);
+            interns.put(type, cst);
+        }
+
+        return cst;
+    }
+
+    /**
+     * Returns an interned instance of this class for the given
+     * {@code Class} instance.
+     *
+     * @param clazz {@code non-null;} the underlying {@code Class} object
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static CstType intern(Class clazz) {
+        return intern(Type.intern(clazz));
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the underlying type
+     */
+    public CstType(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (type == type.KNOWN_NULL) {
+            throw new UnsupportedOperationException(
+                    "KNOWN_NULL is not representable");
+        }
+
+        this.type = type;
+        this.descriptor = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstType)) {
+            return false;
+        }
+
+        return type == ((CstType) other).type;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return type.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        String thisDescriptor = type.getDescriptor();
+        String otherDescriptor = ((CstType) other).type.getDescriptor();
+        return thisDescriptor.compareTo(otherDescriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "type{" + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.CLASS;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "type";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return type.toHuman();
+    }
+
+    /**
+     * Gets the underlying type (as opposed to the type corresponding
+     * to this instance as a constant, which is always
+     * {@code Class}).
+     *
+     * @return {@code non-null;} the type corresponding to the name
+     */
+    public Type getClassType() {
+        return type;
+    }
+
+    /**
+     * Gets the type descriptor for this instance.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public CstUtf8 getDescriptor() {
+        if (descriptor == null) {
+            descriptor = new CstUtf8(type.getDescriptor());
+        }
+
+        return descriptor;
+    }
+}
\ No newline at end of file
diff --git a/dexgen/src/com/android/dexgen/rop/cst/CstUtf8.java b/dexgen/src/com/android/dexgen/rop/cst/CstUtf8.java
new file mode 100644
index 0000000..161a57b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/CstUtf8.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.util.ByteArray;
+import com.android.dexgen.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Utf8_info}.
+ */
+public final class CstUtf8 extends Constant {
+    /**
+     * {@code non-null;} instance representing {@code ""}, that is, the
+     * empty string
+     */
+    public static final CstUtf8 EMPTY_STRING = new CstUtf8("");
+
+    /** {@code non-null;} the UTF-8 value as a string */
+    private final String string;
+
+    /** {@code non-null;} the UTF-8 value as bytes */
+    private final ByteArray bytes;
+
+    /**
+     * Converts a string into its Java-style UTF-8 form. Java-style UTF-8
+     * differs from normal UTF-8 in the handling of character '\0' and
+     * surrogate pairs.
+     *
+     * @param string {@code non-null;} the string to convert
+     * @return {@code non-null;} the UTF-8 bytes for it
+     */
+    public static byte[] stringToUtf8Bytes(String string) {
+        int len = string.length();
+        byte[] bytes = new byte[len * 3]; // Avoid having to reallocate.
+        int outAt = 0;
+
+        for (int i = 0; i < len; i++) {
+            char c = string.charAt(i);
+            if ((c != 0) && (c < 0x80)) {
+                bytes[outAt] = (byte) c;
+                outAt++;
+            } else if (c < 0x800) {
+                bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0);
+                bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80);
+                outAt += 2;
+            } else {
+                bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0);
+                bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80);
+                bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80);
+                outAt += 3;
+            }
+        }
+
+        byte[] result = new byte[outAt];
+        System.arraycopy(bytes, 0, result, 0, outAt);
+        return result;
+    }
+
+    /**
+     * Converts an array of UTF-8 bytes into a string.
+     *
+     * @param bytes {@code non-null;} the bytes to convert
+     * @return {@code non-null;} the converted string
+     */
+    public static String utf8BytesToString(ByteArray bytes) {
+        int length = bytes.size();
+        char[] chars = new char[length]; // This is sized to avoid a realloc.
+        int outAt = 0;
+
+        for (int at = 0; length > 0; /*at*/) {
+            int v0 = bytes.getUnsignedByte(at);
+            char out;
+            switch (v0 >> 4) {
+                case 0x00: case 0x01: case 0x02: case 0x03:
+                case 0x04: case 0x05: case 0x06: case 0x07: {
+                    // 0XXXXXXX -- single-byte encoding
+                    length--;
+                    if (v0 == 0) {
+                        // A single zero byte is illegal.
+                        return throwBadUtf8(v0, at);
+                    }
+                    out = (char) v0;
+                    at++;
+                    break;
+                }
+                case 0x0c: case 0x0d: {
+                    // 110XXXXX -- two-byte encoding
+                    length -= 2;
+                    if (length < 0) {
+                        return throwBadUtf8(v0, at);
+                    }
+                    int v1 = bytes.getUnsignedByte(at + 1);
+                    if ((v1 & 0xc0) != 0x80) {
+                        return throwBadUtf8(v1, at + 1);
+                    }
+                    int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f);
+                    if ((value != 0) && (value < 0x80)) {
+                        /*
+                         * This should have been represented with
+                         * one-byte encoding.
+                         */
+                        return throwBadUtf8(v1, at + 1);
+                    }
+                    out = (char) value;
+                    at += 2;
+                    break;
+                }
+                case 0x0e: {
+                    // 1110XXXX -- three-byte encoding
+                    length -= 3;
+                    if (length < 0) {
+                        return throwBadUtf8(v0, at);
+                    }
+                    int v1 = bytes.getUnsignedByte(at + 1);
+                    if ((v1 & 0xc0) != 0x80) {
+                        return throwBadUtf8(v1, at + 1);
+                    }
+                    int v2 = bytes.getUnsignedByte(at + 2);
+                    if ((v1 & 0xc0) != 0x80) {
+                        return throwBadUtf8(v2, at + 2);
+                    }
+                    int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) |
+                        (v2 & 0x3f);
+                    if (value < 0x800) {
+                        /*
+                         * This should have been represented with one- or
+                         * two-byte encoding.
+                         */
+                        return throwBadUtf8(v2, at + 2);
+                    }
+                    out = (char) value;
+                    at += 3;
+                    break;
+                }
+                default: {
+                    // 10XXXXXX, 1111XXXX -- illegal
+                    return throwBadUtf8(v0, at);
+                }
+            }
+            chars[outAt] = out;
+            outAt++;
+        }
+
+        return new String(chars, 0, outAt);
+    }
+
+    /**
+     * Helper for {@link #utf8BytesToString}, which throws the right
+     * exception for a bogus utf-8 byte.
+     *
+     * @param value the byte value
+     * @param offset the file offset
+     * @return never
+     * @throws IllegalArgumentException always thrown
+     */
+    private static String throwBadUtf8(int value, int offset) {
+        throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) +
+                                           " at offset " + Hex.u4(offset));
+    }
+
+    /**
+     * Constructs an instance from a {@code String}.
+     *
+     * @param string {@code non-null;} the UTF-8 value as a string
+     */
+    public CstUtf8(String string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        this.string = string.intern();
+        this.bytes = new ByteArray(stringToUtf8Bytes(string));
+    }
+
+    /**
+     * Constructs an instance from some UTF-8 bytes.
+     *
+     * @param bytes {@code non-null;} array of the UTF-8 bytes
+     */
+    public CstUtf8(ByteArray bytes) {
+        if (bytes == null) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        this.bytes = bytes;
+        this.string = utf8BytesToString(bytes).intern();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstUtf8)) {
+            return false;
+        }
+
+        return string.equals(((CstUtf8) other).string);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return string.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return string.compareTo(((CstUtf8) other).string);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "utf8{\"" + toHuman() + "\"}";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "utf8";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        int len = string.length();
+        StringBuilder sb = new StringBuilder(len * 3 / 2);
+
+        for (int i = 0; i < len; i++) {
+            char c = string.charAt(i);
+            if ((c >= ' ') && (c < 0x7f)) {
+                if ((c == '\'') || (c == '\"') || (c == '\\')) {
+                    sb.append('\\');
+                }
+                sb.append(c);
+            } else if (c <= 0x7f) {
+                switch (c) {
+                    case '\n': sb.append("\\n"); break;
+                    case '\r': sb.append("\\r"); break;
+                    case '\t': sb.append("\\t"); break;
+                    default: {
+                        /*
+                         * Represent the character as an octal escape.
+                         * If the next character is a valid octal
+                         * digit, disambiguate by using the
+                         * three-digit form.
+                         */
+                        char nextChar =
+                            (i < (len - 1)) ? string.charAt(i + 1) : 0;
+                        boolean displayZero =
+                            (nextChar >= '0') && (nextChar <= '7');
+                        sb.append('\\');
+                        for (int shift = 6; shift >= 0; shift -= 3) {
+                            char outChar = (char) (((c >> shift) & 7) + '0');
+                            if ((outChar != '0') || displayZero) {
+                                sb.append(outChar);
+                                displayZero = true;
+                            }
+                        }
+                        if (! displayZero) {
+                            // Ironic edge case: The original value was 0.
+                            sb.append('0');
+                        }
+                        break;
+                    }
+                }
+            } else {
+                sb.append("\\u");
+                sb.append(Character.forDigit(c >> 12, 16));
+                sb.append(Character.forDigit((c >> 8) & 0x0f, 16));
+                sb.append(Character.forDigit((c >> 4) & 0x0f, 16));
+                sb.append(Character.forDigit(c & 0x0f, 16));
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the value as a human-oriented string, surrounded by double
+     * quotes.
+     *
+     * @return {@code non-null;} the quoted string
+     */
+    public String toQuoted() {
+        return '\"' + toHuman() + '\"';
+    }
+
+    /**
+     * Gets the value as a human-oriented string, surrounded by double
+     * quotes, but ellipsizes the result if it is longer than the given
+     * maximum length
+     *
+     * @param maxLength {@code >= 5;} the maximum length of the string to return
+     * @return {@code non-null;} the quoted string
+     */
+    public String toQuoted(int maxLength) {
+        String string = toHuman();
+        int length = string.length();
+        String ellipses;
+
+        if (length <= (maxLength - 2)) {
+            ellipses = "";
+        } else {
+            string = string.substring(0, maxLength - 5);
+            ellipses = "...";
+        }
+
+        return '\"' + string + ellipses + '\"';
+    }
+
+    /**
+     * Gets the UTF-8 value as a string.
+     * The returned string is always already interned.
+     *
+     * @return {@code non-null;} the UTF-8 value as a string
+     */
+    public String getString() {
+        return string;
+    }
+
+    /**
+     * Gets the UTF-8 value as UTF-8 encoded bytes.
+     *
+     * @return {@code non-null;} an array of the UTF-8 bytes
+     */
+    public ByteArray getBytes() {
+        return bytes;
+    }
+
+    /**
+     * Gets the size of this instance as UTF-8 code points. That is,
+     * get the number of bytes in the UTF-8 encoding of this instance.
+     *
+     * @return {@code >= 0;} the UTF-8 size
+     */
+    public int getUtf8Size() {
+        return bytes.size();
+    }
+
+    /**
+     * 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} of the
+     * Java {@code String} representation of this instance.
+     *
+     * @return {@code >= 0;} the UTF-16 size
+     */
+    public int getUtf16Size() {
+        return string.length();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/StdConstantPool.java b/dexgen/src/com/android/dexgen/rop/cst/StdConstantPool.java
new file mode 100644
index 0000000..5f1728a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/StdConstantPool.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.util.ExceptionWithContext;
+import com.android.dexgen.util.Hex;
+import com.android.dexgen.util.MutabilityControl;
+
+/**
+ * Standard implementation of {@link ConstantPool}, which directly stores
+ * an array of {@link Constant} objects and can be made immutable.
+ */
+public final class StdConstantPool
+        extends MutabilityControl implements ConstantPool {
+    /** {@code non-null;} array of entries */
+    private final Constant[] entries;
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the pool; this corresponds to the
+     * class file field {@code constant_pool_count}, and is in fact
+     * always at least one more than the actual size of the constant pool,
+     * as element {@code 0} is always invalid.
+     */
+    public StdConstantPool(int size) {
+        super(size > 1);
+
+        if (size < 1) {
+            throw new IllegalArgumentException("size < 1");
+        }
+
+        entries = new Constant[size];
+    }
+
+    /** {@inheritDoc} */
+    public int size() {
+        return entries.length;
+    }
+
+    /** {@inheritDoc} */
+    public Constant getOrNull(int n) {
+        try {
+            return entries[n];
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            return throwInvalid(n);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public Constant get0Ok(int n) {
+        if (n == 0) {
+            return null;
+        }
+
+        return get(n);
+    }
+
+    /** {@inheritDoc} */
+    public Constant get(int n) {
+        try {
+            Constant result = entries[n];
+
+            if (result == null) {
+                throwInvalid(n);
+            }
+
+            return result;
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            return throwInvalid(n);
+        }
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 1, < size();} which entry
+     * @param cst {@code null-ok;} the constant to store
+     */
+    public void set(int n, Constant cst) {
+        throwIfImmutable();
+
+        boolean cat2 = (cst != null) && cst.isCategory2();
+
+        if (n < 1) {
+            throw new IllegalArgumentException("n < 1");
+        }
+
+        if (cat2) {
+            // Storing a category-2 entry nulls out the next index.
+            if (n == (entries.length - 1)) {
+                throw new IllegalArgumentException("(n == size - 1) && " +
+                                                   "cst.isCategory2()");
+            }
+            entries[n + 1] = null;
+        }
+
+        if ((cst != null) && (entries[n] == null)) {
+            /*
+             * Overwriting the second half of a category-2 entry nulls out
+             * the first half.
+             */
+            Constant prev = entries[n - 1];
+            if ((prev != null) && prev.isCategory2()) {
+                entries[n - 1] = null;
+            }
+        }
+
+        entries[n] = cst;
+    }
+
+    /**
+     * Throws the right exception for an invalid cpi.
+     *
+     * @param idx the bad cpi
+     * @return never
+     * @throws ExceptionWithContext always thrown
+     */
+    private static Constant throwInvalid(int idx) {
+        throw new ExceptionWithContext("invalid constant pool index " +
+                                       Hex.u2(idx));
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/TypedConstant.java b/dexgen/src/com/android/dexgen/rop/cst/TypedConstant.java
new file mode 100644
index 0000000..251f057
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/TypedConstant.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.TypeBearer;
+
+/**
+ * Base class for constants which implement {@link TypeBearer}.
+ */
+public abstract class TypedConstant
+        extends Constant implements TypeBearer {
+    /**
+     * {@inheritDoc}
+     *
+     * This implentation always returns {@code this}.
+     */
+    public final TypeBearer getFrameType() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicType() {
+        return getType().getBasicType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicFrameType() {
+        return getType().getBasicFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final boolean isConstant() {
+        return true;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/cst/Zeroes.java b/dexgen/src/com/android/dexgen/rop/cst/Zeroes.java
new file mode 100644
index 0000000..28da7db
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/cst/Zeroes.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+/**
+ * Utility for turning types into zeroes.
+ */
+public final class Zeroes {
+    /**
+     * This class is uninstantiable.
+     */
+    private Zeroes() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the "zero" (or {@code null}) value for the given type.
+     *
+     * @param type {@code non-null;} the type in question
+     * @return {@code non-null;} its "zero" value
+     */
+    public static Constant zeroFor(Type type) {
+        switch (type.getBasicType()) {
+            case Type.BT_BOOLEAN: return CstBoolean.VALUE_FALSE;
+            case Type.BT_BYTE:    return CstByte.VALUE_0;
+            case Type.BT_CHAR:    return CstChar.VALUE_0;
+            case Type.BT_DOUBLE:  return CstDouble.VALUE_0;
+            case Type.BT_FLOAT:   return CstFloat.VALUE_0;
+            case Type.BT_INT:     return CstInteger.VALUE_0;
+            case Type.BT_LONG:    return CstLong.VALUE_0;
+            case Type.BT_SHORT:   return CstShort.VALUE_0;
+            case Type.BT_OBJECT:  return CstKnownNull.THE_ONE;
+            default: {
+                throw new UnsupportedOperationException("no zero for type: " +
+                        type.toHuman());
+            }
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/type/Prototype.java b/dexgen/src/com/android/dexgen/rop/type/Prototype.java
new file mode 100644
index 0000000..33fa918
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/type/Prototype.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.type;
+
+import java.util.HashMap;
+
+/**
+ * Representation of a method decriptor. Instances of this class are
+ * generally interned and may be usefully compared with each other
+ * using {@code ==}.
+ */
+public final class Prototype implements Comparable<Prototype> {
+    /** {@code non-null;} intern table mapping string descriptors to instances */
+    private static final HashMap<String, Prototype> internTable =
+        new HashMap<String, Prototype>(500);
+
+    /** {@code non-null;} method descriptor */
+    private final String descriptor;
+
+    /** {@code non-null;} return type */
+    private final Type returnType;
+
+    /** {@code non-null;} list of parameter types */
+    private final StdTypeList parameterTypes;
+
+    /** {@code null-ok;} list of parameter frame types, if calculated */
+    private StdTypeList parameterFrameTypes;
+
+    /**
+     * Returns the unique instance corresponding to the
+     * given method descriptor. See vmspec-2 sec4.3.3 for details on the
+     * field descriptor syntax.
+     *
+     * @param descriptor {@code non-null;} the descriptor
+     * @return {@code non-null;} the corresponding instance
+     * @throws IllegalArgumentException thrown if the descriptor has
+     * invalid syntax
+     */
+    public static Prototype intern(String descriptor) {
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }     
+        Prototype result = internTable.get(descriptor);
+        if (result != null) {
+            return result;
+        }
+
+        Type[] params = makeParameterArray(descriptor);
+        int paramCount = 0;
+        int at = 1;
+
+        for (;;) {
+            int startAt = at;
+            char c = descriptor.charAt(at);
+            if (c == ')') {
+                at++;
+                break;
+            }
+
+            // Skip array markers.
+            while (c == '[') {
+                at++;
+                c = descriptor.charAt(at);
+            }
+
+            if (c == 'L') {
+                // It looks like the start of a class name; find the end.
+                int endAt = descriptor.indexOf(';', at);
+                if (endAt == -1) {
+                    throw new IllegalArgumentException("bad descriptor");
+                }
+                at = endAt + 1;
+            } else {
+                at++;
+            }
+
+            params[paramCount] =
+                Type.intern(descriptor.substring(startAt, at));
+            paramCount++;
+        }
+
+        Type returnType = Type.internReturnType(descriptor.substring(at));
+        StdTypeList parameterTypes = new StdTypeList(paramCount);
+
+        for (int i = 0; i < paramCount; i++) {
+            parameterTypes.set(i, params[i]);
+        }
+
+        result = new Prototype(descriptor, returnType, parameterTypes);
+        return putIntern(result);
+    }
+
+    /**
+     * Helper for {@link #intern} which returns an empty array to
+     * populate with parsed parameter types, and which also ensures
+     * that there is a '(' at the start of the descriptor and a
+     * single ')' somewhere before the end.
+     *
+     * @param descriptor {@code non-null;} the descriptor string
+     * @return {@code non-null;} array large enough to hold all parsed parameter
+     * types, but which is likely actually larger than needed
+     */
+    private static Type[] makeParameterArray(String descriptor) {
+        int length = descriptor.length();
+
+        if (descriptor.charAt(0) != '(') {
+            throw new IllegalArgumentException("bad descriptor");
+        }
+
+        /*
+         * This is a cheesy way to establish an upper bound on the
+         * number of parameters: Just count capital letters.
+         */
+        int closeAt = 0;
+        int maxParams = 0;
+        for (int i = 1; i < length; i++) {
+            char c = descriptor.charAt(i);
+            if (c == ')') {
+                closeAt = i;
+                break;
+            }
+            if ((c >= 'A') && (c <= 'Z')) {
+                maxParams++;
+            }
+        }
+
+        if ((closeAt == 0) || (closeAt == (length - 1))) {
+            throw new IllegalArgumentException("bad descriptor");
+        }
+
+        if (descriptor.indexOf(')', closeAt + 1) != -1) {
+            throw new IllegalArgumentException("bad descriptor");
+        }
+
+        return new Type[maxParams];
+    }
+
+    /**
+     * 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}
+     * as its first argument.
+     *
+     * @param descriptor {@code non-null;} the descriptor string
+     * @param definer {@code non-null;} class the method is defined on
+     * @param isStatic whether this is a static method
+     * @param isInit whether this is an init method
+     * @return {@code non-null;} the interned instance
+     */
+    public static Prototype intern(String descriptor, Type definer,
+            boolean isStatic, boolean isInit) {
+        Prototype base = intern(descriptor);
+
+        if (isStatic) {
+            return base;
+        }
+
+        if (isInit) {
+            definer = definer.asUninitialized(Integer.MAX_VALUE);
+        }
+
+        return base.withFirstParameter(definer);
+    }
+
+    /**
+     * Interns an instance which consists of the given number of
+     * {@code int}s along with the given return type
+     *
+     * @param returnType {@code non-null;} the return type
+     * @param count {@code > 0;} the number of elements in the prototype
+     * @return {@code non-null;} the interned instance
+     */
+    public static Prototype internInts(Type returnType, int count) {
+        // Make the descriptor...
+
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append('(');
+
+        for (int i = 0; i < count; i++) {
+            sb.append('I');
+        }
+
+        sb.append(')');
+        sb.append(returnType.getDescriptor());
+
+        // ...and intern it.
+        return intern(sb.toString());
+    }
+
+    /**
+     * Constructs an instance. This is a private constructor; use one
+     * of the public static methods to get instances.
+     *
+     * @param descriptor {@code non-null;} the descriptor string
+     */
+    private Prototype(String descriptor, Type returnType,
+            StdTypeList parameterTypes) {
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        if (returnType == null) {
+            throw new NullPointerException("returnType == null");
+        }
+
+        if (parameterTypes == null) {
+            throw new NullPointerException("parameterTypes == null");
+        }
+
+        this.descriptor = descriptor;
+        this.returnType = returnType;
+        this.parameterTypes = parameterTypes;
+        this.parameterFrameTypes = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            /*
+             * Since externally-visible instances are interned, this
+             * check helps weed out some easy cases.
+             */
+            return true;
+        }
+
+        if (!(other instanceof Prototype)) {
+            return false;
+        }
+
+        return descriptor.equals(((Prototype) other).descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return descriptor.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Prototype other) {
+        if (this == other) {
+            return 0;
+        }
+
+        /*
+         * The return type is the major order, and then args in order,
+         * and then the shorter list comes first (similar to string
+         * sorting).
+         */
+
+        int result = returnType.compareTo(other.returnType);
+
+        if (result != 0) {
+            return result;
+        }
+
+        int thisSize = parameterTypes.size();
+        int otherSize = other.parameterTypes.size();
+        int size = Math.min(thisSize, otherSize);
+
+        for (int i = 0; i < size; i++) {
+            Type thisType = parameterTypes.get(i);
+            Type otherType = other.parameterTypes.get(i);
+
+            result = thisType.compareTo(otherType);
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (thisSize < otherSize) {
+            return -1;
+        } else if (thisSize > otherSize) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the descriptor string.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public String getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the return type.
+     *
+     * @return {@code non-null;} the return type
+     */
+    public Type getReturnType() {
+        return returnType;
+    }
+
+    /**
+     * Gets the list of parameter types.
+     *
+     * @return {@code non-null;} the list of parameter types
+     */
+    public StdTypeList getParameterTypes() {
+        return parameterTypes;
+    }
+
+    /**
+     * Gets the list of frame types corresponding to the list of parameter
+     * types. The difference between the two lists (if any) is that all
+     * "intlike" types (see {@link Type#isIntlike}) are replaced by
+     * {@link Type#INT}.
+     *
+     * @return {@code non-null;} the list of parameter frame types
+     */
+    public StdTypeList getParameterFrameTypes() {
+        if (parameterFrameTypes == null) {
+            int sz = parameterTypes.size();
+            StdTypeList list = new StdTypeList(sz);
+            boolean any = false;
+            for (int i = 0; i < sz; i++) {
+                Type one = parameterTypes.get(i);
+                if (one.isIntlike()) {
+                    any = true;
+                    one = Type.INT;
+                }
+                list.set(i, one);
+            }
+            parameterFrameTypes = any ? list : parameterTypes;
+        }
+
+        return parameterFrameTypes;
+    }
+
+    /**
+     * Returns a new interned instance, which is the same as this instance,
+     * except that it has an additional parameter prepended to the original's
+     * argument list.
+     *
+     * @param param {@code non-null;} the new first parameter
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Prototype withFirstParameter(Type param) {
+        String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
+        StdTypeList newParams = parameterTypes.withFirst(param);
+
+        newParams.setImmutable();
+
+        Prototype result =
+            new Prototype(newDesc, returnType, newParams);
+
+        return putIntern(result);
+    }
+
+    /**
+     * Puts the given instance in the intern table if it's not already
+     * there. If a conflicting value is already in the table, then leave it.
+     * Return the interned value.
+     *
+     * @param desc {@code non-null;} instance to make interned
+     * @return {@code non-null;} the actual interned object
+     */
+    private static Prototype putIntern(Prototype desc) {
+        synchronized (internTable) {
+            String descriptor = desc.getDescriptor();
+            Prototype already = internTable.get(descriptor);
+            if (already != null) {
+                return already;
+            }
+            internTable.put(descriptor, desc);
+            return desc;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/type/StdTypeList.java b/dexgen/src/com/android/dexgen/rop/type/StdTypeList.java
new file mode 100644
index 0000000..a3e81ff
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/type/StdTypeList.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.type;
+
+import com.android.dexgen.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link TypeList}.
+ */
+public final class StdTypeList
+        extends FixedSizeList implements TypeList {
+    /** {@code non-null;} no-element instance */
+    public static final StdTypeList EMPTY = new StdTypeList(0);
+
+    /** {@code non-null;} the list {@code [int]} */
+    public static final StdTypeList INT = StdTypeList.make(Type.INT);
+
+    /** {@code non-null;} the list {@code [long]} */
+    public static final StdTypeList LONG = StdTypeList.make(Type.LONG);
+
+    /** {@code non-null;} the list {@code [float]} */
+    public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT);
+
+    /** {@code non-null;} the list {@code [double]} */
+    public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE);
+
+    /** {@code non-null;} the list {@code [Object]} */
+    public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [ReturnAddress]} */
+    public static final StdTypeList RETURN_ADDRESS
+            = StdTypeList.make(Type.RETURN_ADDRESS);
+
+    /** {@code non-null;} the list {@code [Throwable]} */
+    public static final StdTypeList THROWABLE =
+        StdTypeList.make(Type.THROWABLE);
+
+    /** {@code non-null;} the list {@code [int, int]} */
+    public static final StdTypeList INT_INT =
+        StdTypeList.make(Type.INT, Type.INT);
+
+    /** {@code non-null;} the list {@code [long, long]} */
+    public static final StdTypeList LONG_LONG =
+        StdTypeList.make(Type.LONG, Type.LONG);
+
+    /** {@code non-null;} the list {@code [float, float]} */
+    public static final StdTypeList FLOAT_FLOAT =
+        StdTypeList.make(Type.FLOAT, Type.FLOAT);
+
+    /** {@code non-null;} the list {@code [double, double]} */
+    public static final StdTypeList DOUBLE_DOUBLE =
+        StdTypeList.make(Type.DOUBLE, Type.DOUBLE);
+
+    /** {@code non-null;} the list {@code [Object, Object]} */
+    public static final StdTypeList OBJECT_OBJECT =
+        StdTypeList.make(Type.OBJECT, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [int, Object]} */
+    public static final StdTypeList INT_OBJECT =
+        StdTypeList.make(Type.INT, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [long, Object]} */
+    public static final StdTypeList LONG_OBJECT =
+        StdTypeList.make(Type.LONG, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [float, Object]} */
+    public static final StdTypeList FLOAT_OBJECT =
+        StdTypeList.make(Type.FLOAT, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [double, Object]} */
+    public static final StdTypeList DOUBLE_OBJECT =
+        StdTypeList.make(Type.DOUBLE, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [long, int]} */
+    public static final StdTypeList LONG_INT =
+        StdTypeList.make(Type.LONG, Type.INT);
+
+    /** {@code non-null;} the list {@code [int[], int]} */
+    public static final StdTypeList INTARR_INT =
+        StdTypeList.make(Type.INT_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [long[], int]} */
+    public static final StdTypeList LONGARR_INT =
+        StdTypeList.make(Type.LONG_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [float[], int]} */
+    public static final StdTypeList FLOATARR_INT =
+        StdTypeList.make(Type.FLOAT_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [double[], int]} */
+    public static final StdTypeList DOUBLEARR_INT =
+        StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [Object[], int]} */
+    public static final StdTypeList OBJECTARR_INT =
+        StdTypeList.make(Type.OBJECT_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [boolean[], int]} */
+    public static final StdTypeList BOOLEANARR_INT =
+        StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [byte[], int]} */
+    public static final StdTypeList BYTEARR_INT =
+        StdTypeList.make(Type.BYTE_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [char[], int]} */
+    public static final StdTypeList CHARARR_INT =
+        StdTypeList.make(Type.CHAR_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [short[], int]} */
+    public static final StdTypeList SHORTARR_INT =
+        StdTypeList.make(Type.SHORT_ARRAY, Type.INT);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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 {@code non-null;} the element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static StdTypeList make(Type type) {
+        StdTypeList result = new StdTypeList(1);
+        result.set(0, type);
+        return result;
+    }
+
+    /**
+     * Makes a two-element instance.
+     *
+     * @param type0 {@code non-null;} the first element
+     * @param type1 {@code non-null;} the second element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static StdTypeList make(Type type0, Type type1) {
+        StdTypeList result = new StdTypeList(2);
+        result.set(0, type0);
+        result.set(1, type1);
+        return result;
+    }
+
+    /**
+     * Makes a three-element instance.
+     *
+     * @param type0 {@code non-null;} the first element
+     * @param type1 {@code non-null;} the second element
+     * @param type2 {@code non-null;} the third element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static StdTypeList make(Type type0, Type type1, Type type2) {
+        StdTypeList result = new StdTypeList(3);
+        result.set(0, type0);
+        result.set(1, type1);
+        result.set(2, type2);
+        return result;
+    }
+
+    /**
+     * Makes a four-element instance.
+     *
+     * @param type0 {@code non-null;} the first element
+     * @param type1 {@code non-null;} the second element
+     * @param type2 {@code non-null;} the third element
+     * @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) {
+        StdTypeList result = new StdTypeList(4);
+        result.set(0, type0);
+        result.set(1, type1);
+        result.set(2, type2);
+        result.set(3, type3);
+        return result;
+    }
+
+    /**
+     * Returns the given list as a comma-separated list of human forms. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list {@code non-null;} the list to convert
+     * @return {@code non-null;} the human form
+     */
+    public static String toHuman(TypeList list) {
+        int size = list.size();
+
+        if (size == 0) {
+            return "<empty>";
+        }
+
+        StringBuffer sb = new StringBuffer(100);
+
+        for (int i = 0; i < size; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(list.getType(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns a hashcode of the contents of the given list. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list {@code non-null;} the list to inspect
+     * @return {@code non-null;} the hash code
+     */
+    public static int hashContents(TypeList list) {
+        int size = list.size();
+        int hash = 0;
+
+        for (int i = 0; i < size; i++) {
+            hash = (hash * 31) + list.getType(i).hashCode();
+        }
+
+        return hash;
+    }
+
+    /**
+     * Compares the contents of the given two instances for equality. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list1 {@code non-null;} one list to compare
+     * @param list2 {@code non-null;} another list to compare
+     * @return whether the two lists contain corresponding equal elements
+     */
+    public static boolean equalContents(TypeList list1, TypeList list2) {
+        int size = list1.size();
+
+        if (list2.size() != size) {
+            return false;
+        }
+
+        for (int i = 0; i < size; i++) {
+            if (! list1.getType(i).equals(list2.getType(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Compares the contents of the given two instances for ordering. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list1 {@code non-null;} one list to compare
+     * @param list2 {@code non-null;} another list to compare
+     * @return the order of the two lists
+     */
+    public static int compareContents(TypeList list1, TypeList list2) {
+        int size1 = list1.size();
+        int size2 = list2.size();
+        int size = Math.min(size1, size2);
+
+        for (int i = 0; i < size; i++) {
+            int comparison = list1.getType(i).compareTo(list2.getType(i));
+            if (comparison != 0) {
+                return comparison;
+            }
+        }
+
+        if (size1 == size2) {
+            return 0;
+        } else if (size1 < size2) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdTypeList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType(int n) {
+        return get(n);
+    }
+
+    /** {@inheritDoc} */
+    public int getWordCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            result += get(i).getCategory();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public TypeList withAddedType(Type type) {
+        int sz = size();
+        StdTypeList result = new StdTypeList(sz + 1);
+
+        for (int i = 0; i < sz; i++) {
+            result.set0(i, get0(i));
+        }
+
+        result.set(sz, type);
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Gets the indicated element. It is an error to call this with the
+     * index for an element which was never set; if you do that, this
+     * will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public Type get(int n) {
+        return (Type) get0(n);
+    }
+
+    /**
+     * Sets the type at the given index.
+     *
+     * @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);
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that it has an additional type prepended to the
+     * original.
+     *
+     * @param type {@code non-null;} the new first element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public StdTypeList withFirst(Type type) {
+        int sz = size();
+        StdTypeList result = new StdTypeList(sz + 1);
+
+        result.set0(0, type);
+        for (int i = 0; i < sz; i++) {
+            result.set0(i + 1, getOrNull0(i));
+        }
+
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/rop/type/Type.java b/dexgen/src/com/android/dexgen/rop/type/Type.java
new file mode 100644
index 0000000..365bd78
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/type/Type.java
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.type;
+
+import com.android.dexgen.util.Hex;
+
+import java.util.HashMap;
+
+/**
+ * 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 ==}.
+ */
+public final class Type implements TypeBearer, Comparable<Type> {
+    /** {@code non-null;} intern table mapping string descriptors to instances */
+    private static final HashMap<String, Type> internTable =
+        new HashMap<String, Type>(500);
+
+    /** {@code non-null;} table mapping types as {@code Class} objects to internal form */
+    private static final HashMap<Class, Type> CLASS_TYPE_MAP =
+        new HashMap<Class, Type>();
+
+    /** basic type constant for {@code void} */
+    public static final int BT_VOID = 0;
+
+    /** basic type constant for {@code boolean} */
+    public static final int BT_BOOLEAN = 1;
+
+    /** basic type constant for {@code byte} */
+    public static final int BT_BYTE = 2;
+
+    /** basic type constant for {@code char} */
+    public static final int BT_CHAR = 3;
+
+    /** basic type constant for {@code double} */
+    public static final int BT_DOUBLE = 4;
+
+    /** basic type constant for {@code float} */
+    public static final int BT_FLOAT = 5;
+
+    /** basic type constant for {@code int} */
+    public static final int BT_INT = 6;
+
+    /** basic type constant for {@code long} */
+    public static final int BT_LONG = 7;
+
+    /** basic type constant for {@code short} */
+    public static final int BT_SHORT = 8;
+
+    /** basic type constant for {@code Object} */
+    public static final int BT_OBJECT = 9;
+
+    /** basic type constant for a return address */
+    public static final int BT_ADDR = 10;
+
+    /** count of basic type constants */
+    public static final int BT_COUNT = 11;
+
+    /** {@code non-null;} instance representing {@code boolean} */
+    public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
+
+    /** {@code non-null;} instance representing {@code byte} */
+    public static final Type BYTE = new Type("B", BT_BYTE);
+
+    /** {@code non-null;} instance representing {@code char} */
+    public static final Type CHAR = new Type("C", BT_CHAR);
+
+    /** {@code non-null;} instance representing {@code double} */
+    public static final Type DOUBLE = new Type("D", BT_DOUBLE);
+
+    /** {@code non-null;} instance representing {@code float} */
+    public static final Type FLOAT = new Type("F", BT_FLOAT);
+
+    /** {@code non-null;} instance representing {@code int} */
+    public static final Type INT = new Type("I", BT_INT);
+
+    /** {@code non-null;} instance representing {@code long} */
+    public static final Type LONG = new Type("J", BT_LONG);
+
+    /** {@code non-null;} instance representing {@code short} */
+    public static final Type SHORT = new Type("S", BT_SHORT);
+
+    /** {@code non-null;} instance representing {@code void} */
+    public static final Type VOID = new Type("V", BT_VOID);
+
+    /** {@code non-null;} instance representing a known-{@code null} */
+    public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
+
+    /** {@code non-null;} instance representing a subroutine return address */
+    public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
+
+    static {
+        /*
+         * Put all the primitive types into the intern table. This needs
+         * to happen before the array types below get interned.
+         */
+        putIntern(BOOLEAN);
+        putIntern(BYTE);
+        putIntern(CHAR);
+        putIntern(DOUBLE);
+        putIntern(FLOAT);
+        putIntern(INT);
+        putIntern(LONG);
+        putIntern(SHORT);
+        /*
+         * Note: VOID isn't put in the intern table, since it's special and
+         * shouldn't be found by a normal call to intern().
+         */
+
+        /*
+         * Create a mapping between types as Java Class objects
+         * and types in dx internal format.
+         */
+        CLASS_TYPE_MAP.put(boolean.class, BOOLEAN);
+        CLASS_TYPE_MAP.put(short.class, SHORT);
+        CLASS_TYPE_MAP.put(int.class, INT);
+        CLASS_TYPE_MAP.put(long.class, LONG);
+        CLASS_TYPE_MAP.put(char.class, CHAR);
+        CLASS_TYPE_MAP.put(byte.class, BYTE);
+        CLASS_TYPE_MAP.put(float.class, FLOAT);
+        CLASS_TYPE_MAP.put(double.class, DOUBLE);
+        CLASS_TYPE_MAP.put(void.class, VOID);
+    }
+
+    /**
+     * {@code non-null;} instance representing
+     * {@code java.lang.annotation.Annotation}
+     */
+    public static final Type ANNOTATION =
+        intern("Ljava/lang/annotation/Annotation;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Class} */
+    public static final Type CLASS = intern("Ljava/lang/Class;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
+    public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Object} */
+    public static final Type OBJECT = intern("Ljava/lang/Object;");
+
+    /** {@code non-null;} instance representing {@code java.io.Serializable} */
+    public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
+
+    /** {@code non-null;} instance representing {@code java.lang.String} */
+    public static final Type STRING = intern("Ljava/lang/String;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Throwable} */
+    public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /** {@code non-null;} instance representing {@code boolean[]} */
+    public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
+
+    /** {@code non-null;} instance representing {@code byte[]} */
+    public static final Type BYTE_ARRAY = BYTE.getArrayType();
+
+    /** {@code non-null;} instance representing {@code char[]} */
+    public static final Type CHAR_ARRAY = CHAR.getArrayType();
+
+    /** {@code non-null;} instance representing {@code double[]} */
+    public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
+
+    /** {@code non-null;} instance representing {@code float[]} */
+    public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
+
+    /** {@code non-null;} instance representing {@code int[]} */
+    public static final Type INT_ARRAY = INT.getArrayType();
+
+    /** {@code non-null;} instance representing {@code long[]} */
+    public static final Type LONG_ARRAY = LONG.getArrayType();
+
+    /** {@code non-null;} instance representing {@code Object[]} */
+    public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
+
+    /** {@code non-null;} instance representing {@code short[]} */
+    public static final Type SHORT_ARRAY = SHORT.getArrayType();
+
+    /** {@code non-null;} field descriptor for the type */
+    private final String descriptor;
+
+    /**
+     * basic type corresponding to this type; one of the
+     * {@code BT_*} constants
+     */
+    private final int basicType;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /**
+     * {@code null-ok;} the type corresponding to an array of this type, if
+     * calculated
+     */
+    private Type arrayType;
+
+    /**
+     * {@code null-ok;} the type corresponding to elements of this type, if
+     * calculated; only valid if {@code this} is an array type
+     */
+    private Type componentType;
+
+    /**
+     * {@code null-ok;} the type corresponding to the initialized version of
+     * this type, if this instance is in fact an uninitialized type
+     */
+    private Type initializedType;
+
+    /**
+     * Returns the unique instance corresponding to the type represented by
+     * given {@code Class} object. See vmspec-2 sec4.3.2 for details on the
+     * field descriptor syntax. This method does <i>not</i> allow
+     * {@code "V"} (that is, type {@code void}) as a valid
+     * descriptor.
+     *
+     * @param clazz {@code non-null;} class whose descriptor
+     * will be internalized
+     * @return {@code non-null;} the corresponding instance
+     */
+    public static Type intern(Class clazz) {
+        return intern(getInternalTypeName(clazz));
+    }
+
+    /**
+     * 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"} (that is, type {@code void}) as a valid
+     * descriptor.
+     *
+     * @param descriptor {@code non-null;} the descriptor
+     * @return {@code non-null;} the corresponding instance
+     * @throws IllegalArgumentException thrown if the descriptor has
+     * invalid syntax
+     */
+    public static Type intern(String descriptor) {
+
+        Type result = internTable.get(descriptor);
+        if (result != null) {
+            return result;
+        }
+
+        char firstChar;
+        try {
+            firstChar = descriptor.charAt(0);
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("descriptor is empty");
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("descriptor == null");
+        }
+
+        if (firstChar == '[') {
+            /*
+             * Recursively strip away array markers to get at the underlying
+             * type, and build back on to form the result.
+             */
+            result = intern(descriptor.substring(1));
+            return result.getArrayType();
+        }
+
+        /*
+         * If the first character isn't '[' and it wasn't found in the
+         * intern cache, then it had better be the descriptor for a class.
+         */
+
+        int length = descriptor.length();
+        if ((firstChar != 'L') ||
+            (descriptor.charAt(length - 1) != ';')) {
+            throw new IllegalArgumentException("bad descriptor" + descriptor);
+        }
+
+        /*
+         * Validate the characters of the class name itself. Note that
+         * vmspec-2 does not have a coherent definition for valid
+         * internal-form class names, and the definition here is fairly
+         * liberal: A name is considered valid as long as it doesn't
+         * contain any of '[' ';' '.' '(' ')', and it has no more than one
+         * '/' in a row, and no '/' at either end.
+         */
+
+        int limit = (length - 1); // Skip the final ';'.
+        for (int i = 1; i < limit; i++) {
+            char c = descriptor.charAt(i);
+            switch (c) {
+                case '[':
+                case ';':
+                case '.':
+                case '(':
+                case ')': {
+                    throw new IllegalArgumentException("bad descriptor" + descriptor);
+                }
+                case '/': {
+                    if ((i == 1) ||
+                        (i == (length - 1)) ||
+                        (descriptor.charAt(i - 1) == '/')) {
+                        throw new IllegalArgumentException("bad descriptor");
+                    }
+                    break;
+                }
+            }
+        }
+
+        result = new Type(descriptor, BT_OBJECT);
+        return putIntern(result);
+    }
+
+    /**
+     * Returns the unique instance corresponding to the type represented by
+     * given {@code Class} object, allowing {@code "V"} to return the type
+     * for {@code void}. Other than that one caveat, this method
+     * is identical to {@link #intern}.
+     *
+     * @param clazz {@code non-null;} class which descriptor
+     * will be internalized
+     * @return {@code non-null;} the corresponding instance
+     */
+    public static Type internReturnType(Class clazz) {
+        return internReturnType(getInternalTypeName(clazz));
+    }
+
+    /**
+     * Returns the unique instance corresponding to the type with the
+     * given descriptor, allowing {@code "V"} to return the type
+     * for {@code void}. Other than that one caveat, this method
+     * is identical to {@link #intern}.
+     *
+     * @param descriptor {@code non-null;} the descriptor
+     * @return {@code non-null;} the corresponding instance
+     * @throws IllegalArgumentException thrown if the descriptor has
+     * invalid syntax
+     */
+    public static Type internReturnType(String descriptor) {
+        try {
+            if (descriptor.equals("V")) {
+                // This is the one special case where void may be returned.
+                return VOID;
+            }
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("descriptor == null");
+        }
+
+        return intern(descriptor);
+    }
+
+    /**
+     * 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)} if {@code name} begins
+     * with {@code "["} and calling {@code intern("L" + name + ";")}
+     * in all other cases.
+     *
+     * @param name {@code non-null;} the name of the class whose type is desired
+     * @return {@code non-null;} the corresponding type
+     * @throws IllegalArgumentException thrown if the name has
+     * invalid syntax
+     */
+    public static Type internClassName(String name) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        if (name.startsWith("[")) {
+            return intern(name);
+        }
+
+        return intern('L' + name + ';');
+    }
+
+    /**
+     * Converts type name in the format as returned by reflection
+     * into dex internal form.
+     *
+     * @param clazz {@code non-null;} class whose name will be internalized
+     * @return string with the type name in dex internal format
+     */
+    public static String getInternalTypeName(Class clazz) {
+        if (clazz == null) {
+            throw new NullPointerException("clazz == null");
+        }
+
+        if (clazz.isPrimitive()) {
+            return CLASS_TYPE_MAP.get(clazz).getDescriptor();
+        }
+
+        String slashed = clazz.getName().replace('.', '/');
+
+        if (clazz.isArray()) {
+            return slashed;
+        }
+
+        return 'L' + slashed + ';';
+    }
+
+    /**
+     * Constructs an instance corresponding to an "uninitialized type."
+     * This is a private constructor; use one of the public static
+     * methods to get instances.
+     *
+     * @param descriptor {@code non-null;} the field descriptor for the type
+     * @param basicType basic type corresponding to this type; one of the
+     * {@code BT_*} constants
+     * @param newAt {@code >= -1;} allocation bytecode index
+     */
+    private Type(String descriptor, int basicType, int newAt) {
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        if ((basicType < 0) || (basicType >= BT_COUNT)) {
+            throw new IllegalArgumentException("bad basicType");
+        }
+
+        if (newAt < -1) {
+            throw new IllegalArgumentException("newAt < -1");
+        }
+
+        this.descriptor = descriptor;
+        this.basicType = basicType;
+        this.newAt = newAt;
+        this.arrayType = null;
+        this.componentType = null;
+        this.initializedType = null;
+    }
+
+    /**
+     * Constructs an instance corresponding to an "initialized type."
+     * This is a private constructor; use one of the public static
+     * methods to get instances.
+     *
+     * @param descriptor {@code non-null;} the field descriptor for the type
+     * @param basicType basic type corresponding to this type; one of the
+     * {@code BT_*} constants
+     */
+    private Type(String descriptor, int basicType) {
+        this(descriptor, basicType, -1);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            /*
+             * Since externally-visible types are interned, this check
+             * helps weed out some easy cases.
+             */
+            return true;
+        }
+
+        if (!(other instanceof Type)) {
+            return false;
+        }
+
+        return descriptor.equals(((Type) other).descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return descriptor.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Type other) {
+        return descriptor.compareTo(other.descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return descriptor;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        switch (basicType) {
+            case BT_VOID:    return "void";
+            case BT_BOOLEAN: return "boolean";
+            case BT_BYTE:    return "byte";
+            case BT_CHAR:    return "char";
+            case BT_DOUBLE:  return "double";
+            case BT_FLOAT:   return "float";
+            case BT_INT:     return "int";
+            case BT_LONG:    return "long";
+            case BT_SHORT:   return "short";
+            case BT_OBJECT:  break;
+            default:         return descriptor;
+        }
+
+        if (isArray()) {
+            return getComponentType().toHuman() + "[]";
+        }
+
+        // Remove the "L...;" around the type and convert "/" to ".".
+        return getClassName().replace("/", ".");
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public Type getFrameType() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_INT:
+            case BT_SHORT: {
+                return INT;
+            }
+        }
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public int getBasicType() {
+        return basicType;
+    }
+
+    /** {@inheritDoc} */
+    public int getBasicFrameType() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_INT:
+            case BT_SHORT: {
+                return BT_INT;
+            }
+        }
+
+        return basicType;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isConstant() {
+        return false;
+    }
+
+    /**
+     * Gets the descriptor.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public String getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the name of the class this type corresponds to, in internal
+     * form. This method is only valid if this instance is for a
+     * normal reference type (that is, a reference type and
+     * additionally not a return address).
+     *
+     * @return {@code non-null;} the internal-form class name
+     */
+    public String getClassName() {
+        if (className == null) {
+            if (!isReference()) {
+                throw new IllegalArgumentException("not an object type: " +
+                                                   descriptor);
+            }
+
+            if (descriptor.charAt(0) == '[') {
+                className = descriptor;
+            } else {
+                className = descriptor.substring(1, descriptor.length() - 1);
+            }
+        }
+
+        return className;
+    }
+
+    /**
+     * Gets the category. Most instances are category 1. {@code long}
+     * and {@code double} are the only category 2 types.
+     *
+     * @see #isCategory1
+     * @see #isCategory2
+     * @return the category
+     */
+    public int getCategory() {
+        switch (basicType) {
+            case BT_LONG:
+            case BT_DOUBLE: {
+                return 2;
+            }
+        }
+
+        return 1;
+    }
+
+    /**
+     * Returns whether or not this is a category 1 type.
+     *
+     * @see #getCategory
+     * @see #isCategory2
+     * @return whether or not this is a category 1 type
+     */
+    public boolean isCategory1() {
+        switch (basicType) {
+            case BT_LONG:
+            case BT_DOUBLE: {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns whether or not this is a category 2 type.
+     *
+     * @see #getCategory
+     * @see #isCategory1
+     * @return whether or not this is a category 2 type
+     */
+    public boolean isCategory2() {
+        switch (basicType) {
+            case BT_LONG:
+            case BT_DOUBLE: {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets whether this type is "intlike." An intlike type is one which, when
+     * placed on a stack or in a local, is automatically converted to an
+     * {@code int}.
+     *
+     * @return whether this type is "intlike"
+     */
+    public boolean isIntlike() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_INT:
+            case BT_SHORT: {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets whether this type is a primitive type. All types are either
+     * primitive or reference types.
+     *
+     * @return whether this type is primitive
+     */
+    public boolean isPrimitive() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_DOUBLE:
+            case BT_FLOAT:
+            case BT_INT:
+            case BT_LONG:
+            case BT_SHORT:
+            case BT_VOID: {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 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}.
+     *
+     * @return whether this type is a normal reference type
+     */
+    public boolean isReference() {
+        return (basicType == BT_OBJECT);
+    }
+
+    /**
+     * Gets whether this type is an array type. If this method returns
+     * {@code true}, then it is safe to use {@link #getComponentType}
+     * to determine the component type.
+     *
+     * @return whether this type is an array type
+     */
+    public boolean isArray() {
+        return (descriptor.charAt(0) == '[');
+    }
+
+    /**
+     * Gets whether this type is an array type or is a known-null, and
+     * hence is compatible with array types.
+     *
+     * @return whether this type is an array type
+     */
+    public boolean isArrayOrKnownNull() {
+        return isArray() || equals(KNOWN_NULL);
+    }
+
+    /**
+     * Gets whether this type represents an uninitialized instance. An
+     * uninitialized instance is what one gets back from the {@code new}
+     * opcode, and remains uninitialized until a valid constructor is
+     * invoked on it.
+     *
+     * @return whether this type is "uninitialized"
+     */
+    public boolean isUninitialized() {
+        return (newAt >= 0);
+    }
+
+    /**
+     * Gets the bytecode index at which this uninitialized type was
+     * allocated.  This returns {@code Integer.MAX_VALUE} if this
+     * type is an uninitialized incoming parameter (i.e., the
+     * {@code this} of an {@code <init>} method) or
+     * {@code -1} if this type is in fact <i>initialized</i>.
+     *
+     * @return {@code >= -1;} the allocation bytecode index
+     */
+    public int getNewAt() {
+        return newAt;
+    }
+
+    /**
+     * Gets the initialized type corresponding to this instance, but only
+     * if this instance is in fact an uninitialized object type.
+     *
+     * @return {@code non-null;} the initialized type
+     */
+    public Type getInitializedType() {
+        if (initializedType == null) {
+            throw new IllegalArgumentException("initialized type: " +
+                                               descriptor);
+        }
+
+        return initializedType;
+    }
+
+    /**
+     * Gets the type corresponding to an array of this type.
+     *
+     * @return {@code non-null;} the array type
+     */
+    public Type getArrayType() {
+        if (arrayType == null) {
+            arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT));
+        }
+
+        return arrayType;
+    }
+
+    /**
+     * Gets the component type of this type. This method is only valid on
+     * array types.
+     *
+     * @return {@code non-null;} the component type
+     */
+    public Type getComponentType() {
+        if (componentType == null) {
+            if (descriptor.charAt(0) != '[') {
+                throw new IllegalArgumentException("not an array type: " +
+                                                   descriptor);
+            }
+            componentType = intern(descriptor.substring(1));
+        }
+
+        return componentType;
+    }
+
+    /**
+     * Returns a new interned instance which is identical to this one, except
+     * it is indicated as uninitialized and allocated at the given bytecode
+     * index. This instance must be an initialized object type.
+     *
+     * @param newAt {@code >= 0;} the allocation bytecode index
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Type asUninitialized(int newAt) {
+        if (newAt < 0) {
+            throw new IllegalArgumentException("newAt < 0");
+        }
+
+        if (!isReference()) {
+            throw new IllegalArgumentException("not a reference type: " +
+                                               descriptor);
+        }
+
+        if (isUninitialized()) {
+            /*
+             * Dealing with uninitialized types as a starting point is
+             * a pain, and it's not clear that it'd ever be used, so
+             * just disallow it.
+             */
+            throw new IllegalArgumentException("already uninitialized: " +
+                                               descriptor);
+        }
+
+        /*
+         * Create a new descriptor that is unique and shouldn't conflict
+         * with "normal" type descriptors
+         */
+        String newDesc = 'N' + Hex.u2(newAt) + descriptor;
+        Type result = new Type(newDesc, BT_OBJECT, newAt);
+        result.initializedType = this;
+        return putIntern(result);
+    }
+
+    /**
+     * Puts the given instance in the intern table if it's not already
+     * there. If a conflicting value is already in the table, then leave it.
+     * Return the interned value.
+     *
+     * @param type {@code non-null;} instance to make interned
+     * @return {@code non-null;} the actual interned object
+     */
+    private static Type putIntern(Type type) {
+        synchronized (internTable) {
+            String descriptor = type.getDescriptor();
+            Type already = internTable.get(descriptor);
+            if (already != null) {
+                return already;
+            }
+            internTable.put(descriptor, type);
+            return type;
+        }
+    }
+}
\ No newline at end of file
diff --git a/dexgen/src/com/android/dexgen/rop/type/TypeBearer.java b/dexgen/src/com/android/dexgen/rop/type/TypeBearer.java
new file mode 100644
index 0000000..da7a7ef
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/type/TypeBearer.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.type;
+
+import com.android.dexgen.util.ToHuman;
+
+/**
+ * Object which has an associated type, possibly itself.
+ */
+public interface TypeBearer
+        extends ToHuman {
+    /**
+     * Gets the type associated with this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public Type getType();
+
+    /**
+     * Gets the frame type corresponding to this type. This method returns
+     * {@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}.
+     *
+     * @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_*} 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()}, 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}.
+     *
+     * @see #getBasicType
+     * @see #getFrameType
+     *
+     * @return the basic frame type; one of the {@code BT_*} constants
+     * defined by {@link Type}
+     */
+    public int getBasicFrameType();
+
+    /**
+     * Returns whether this instance represents a constant value.
+     *
+     * @return {@code true} if this instance represents a constant value
+     * and {@code false} if not
+     */
+    public boolean isConstant();
+}
diff --git a/dexgen/src/com/android/dexgen/rop/type/TypeList.java b/dexgen/src/com/android/dexgen/rop/type/TypeList.java
new file mode 100644
index 0000000..dedcbc9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/rop/type/TypeList.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.type;
+
+/**
+ * List of {@link Type} instances (or of things that contain types).
+ */
+public interface TypeList {
+    /**
+     * Returns whether this instance is mutable. Note that the
+     * {@code TypeList} interface itself doesn't provide any
+     * means of mutation, but that doesn't mean that there isn't an
+     * extra-interface way of mutating an instance.
+     *
+     * @return {@code true} if this instance is mutable or
+     * {@code false} if it is immutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Gets the size of this list.
+     *
+     * @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}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public Type getType(int n);
+
+    /**
+     * Gets the number of 32-bit words required to hold instances of
+     * all the elements of this list. This is a sum of the widths (categories)
+     * of all the elements.
+     *
+     * @return {@code >= 0;} the required number of words
+     */
+    public int getWordCount();
+
+    /**
+     * Returns a new instance which is identical to this one, except that
+     * the given item is appended to the end and it is guaranteed to be
+     * immutable.
+     *
+     * @param type {@code non-null;} item to append
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public TypeList withAddedType(Type type);
+}
diff --git a/dexgen/src/com/android/dexgen/util/AnnotatedOutput.java b/dexgen/src/com/android/dexgen/util/AnnotatedOutput.java
new file mode 100644
index 0000000..3ff4cf5
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/AnnotatedOutput.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Interface for a binary output destination that may be augmented
+ * with textual annotations.
+ */
+public interface AnnotatedOutput
+        extends Output {
+    /**
+     * Get whether this instance will actually keep annotations.
+     *
+     * @return {@code true} iff annotations are being kept
+     */
+    public boolean annotates();
+
+    /**
+     * Get whether this instance is intended to keep verbose annotations.
+     * Annotators may use the result of calling this method to inform their
+     * annotation activity.
+     *
+     * @return {@code true} iff annotations are to be verbose
+     */
+    public boolean isVerbose();
+
+    /**
+     * Add an annotation for the subsequent output. Any previously
+     * open annotation will be closed by this call, and the new
+     * annotation marks all subsequent output until another annotation
+     * call.
+     *
+     * @param msg {@code non-null;} the annotation message
+     */
+    public void annotate(String msg);
+
+    /**
+     * Add an annotation for a specified amount of subsequent
+     * output. Any previously open annotation will be closed by this
+     * call. If there is already pending annotation from one or more
+     * previous calls to this method, the new call "consumes" output
+     * after all the output covered by the previous calls.
+     *
+     * @param amt {@code >= 0;} the amount of output for this annotation to
+     * cover
+     * @param msg {@code non-null;} the annotation message
+     */
+    public void annotate(int amt, String msg);
+
+    /**
+     * End the most recent annotation. Subsequent output will be unannotated,
+     * until the next call to {@link #annotate}.
+     */
+    public void endAnnotation();
+
+    /**
+     * Get the maximum width of the annotated output. This is advisory:
+     * Implementations of this interface are encouraged to deal with too-wide
+     * output, but annotaters are encouraged to attempt to avoid exceeding
+     * the indicated width.
+     *
+     * @return {@code >= 1;} the maximum width
+     */
+    public int getAnnotationWidth();
+}
diff --git a/dexgen/src/com/android/dexgen/util/BitIntSet.java b/dexgen/src/com/android/dexgen/util/BitIntSet.java
new file mode 100644
index 0000000..0cf9fc6
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/BitIntSet.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.util.NoSuchElementException;
+
+/**
+ * A set of integers, represented by a bit set
+ */
+public class BitIntSet implements IntSet {
+
+    /** also accessed in ListIntSet */
+    int[] bits;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param max the maximum value of ints in this set.
+     */
+    public BitIntSet(int max) {
+        bits = Bits.makeBitSet(max);
+    }
+
+    /** @inheritDoc */
+    public void add(int value) {
+        ensureCapacity(value);
+        Bits.set(bits, value, true);
+    }
+
+    /**
+     * Ensures that the bit set has the capacity to represent the given value.
+     *
+     * @param value {@code >= 0;} value to represent
+     */
+    private void ensureCapacity(int value) {
+        if (value >= Bits.getMax(bits)) {
+            int[] newBits = Bits.makeBitSet(
+                    Math.max(value + 1, 2 * Bits.getMax(bits)));
+            System.arraycopy(bits, 0, newBits, 0, bits.length);
+            bits = newBits;
+        }
+    }
+
+    /** @inheritDoc */
+    public void remove(int value) {
+        if (value < Bits.getMax(bits)) {
+            Bits.set(bits, value, false);
+        }
+    }
+
+    /** @inheritDoc */
+    public boolean has(int value) {
+        return (value < Bits.getMax(bits)) && Bits.get(bits, value);
+    }
+
+    /** @inheritDoc */
+    public void merge(IntSet other) {
+        if (other instanceof BitIntSet) {
+            BitIntSet o = (BitIntSet) other;
+            ensureCapacity(Bits.getMax(o.bits) + 1);
+            Bits.or(bits, o.bits);
+        } else if (other instanceof ListIntSet) {
+            ListIntSet o = (ListIntSet) other;
+            int sz = o.ints.size();
+
+            if (sz > 0) {
+                ensureCapacity(o.ints.get(sz - 1));
+            }
+            for (int i = 0; i < o.ints.size(); i++) {
+                Bits.set(bits, o.ints.get(i), true);
+            }
+        } else {
+            IntIterator iter = other.iterator();
+            while (iter.hasNext()) {
+                add(iter.next());
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    public int elements() {
+        return Bits.bitCount(bits);
+    }
+
+    /** @inheritDoc */
+    public IntIterator iterator() {
+        return new IntIterator() {
+            private int idx = Bits.findFirst(bits, 0);
+
+            /** @inheritDoc */
+            public boolean hasNext() {
+                return idx >= 0;
+            }
+
+            /** @inheritDoc */
+            public int next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                int ret = idx;
+
+                idx = Bits.findFirst(bits, idx+1);
+
+                return ret;
+            }
+        };
+    }
+
+    /** @inheritDoc */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append('{');
+
+        boolean first = true;
+        for (int i = Bits.findFirst(bits, 0)
+                ; i >= 0
+                ; i = Bits.findFirst(bits, i + 1)) {
+            if (!first) {
+                sb.append(", ");
+            }
+            first = false;
+            sb.append(i);
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/Bits.java b/dexgen/src/com/android/dexgen/util/Bits.java
new file mode 100644
index 0000000..5c97cc9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/Bits.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Utilities for treating {@code int[]}s as bit sets.
+ */
+public final class Bits {
+    /**
+     * This class is uninstantiable.
+     */
+    private Bits() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Constructs a bit set to contain bits up to the given index (exclusive).
+     *
+     * @param max {@code >= 0;} the maximum bit index (exclusive)
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static int[] makeBitSet(int max) {
+        int size = (max + 0x1f) >> 5;
+        return new int[size];
+    }
+
+    /**
+     * Gets the maximum index (exclusive) for the given bit set.
+     *
+     * @param bits {@code non-null;} bit set in question
+     * @return {@code >= 0;} the maximum index (exclusive) that may be set
+     */
+    public static int getMax(int[] bits) {
+        return bits.length * 0x20;
+    }
+
+    /**
+     * Gets the value of the bit at the given index.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     * @return the value of the indicated bit
+     */
+    public static boolean get(int[] bits, int idx) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+        return (bits[arrayIdx] & bit) != 0;
+    }
+
+    /**
+     * Sets the given bit to the given value.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     * @param value the new value for the bit
+     */
+    public static void set(int[] bits, int idx, boolean value) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+
+        if (value) {
+            bits[arrayIdx] |= bit;
+        } else {
+            bits[arrayIdx] &= ~bit;
+        }
+    }
+
+    /**
+     * Sets the given bit to {@code true}.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     */
+    public static void set(int[] bits, int idx) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+        bits[arrayIdx] |= bit;
+    }
+
+    /**
+     * Sets the given bit to {@code false}.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     */
+    public static void clear(int[] bits, int idx) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+        bits[arrayIdx] &= ~bit;
+    }
+
+    /**
+     * Returns whether or not the given bit set is empty, that is, whether
+     * no bit is set to {@code true}.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @return {@code true} iff all bits are {@code false}
+     */
+    public static boolean isEmpty(int[] bits) {
+        int len = bits.length;
+
+        for (int i = 0; i < len; i++) {
+            if (bits[i] != 0) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Gets the number of bits set to {@code true} in the given bit set.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @return {@code >= 0;} the bit count (aka population count) of the set
+     */
+    public static int bitCount(int[] bits) {
+        int len = bits.length;
+        int count = 0;
+
+        for (int i = 0; i < len; i++) {
+            count += Integer.bitCount(bits[i]);
+        }
+
+        return count;
+    }
+
+    /**
+     * Returns whether any bits are set to {@code true} in the
+     * specified range.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param start {@code >= 0;} index of the first bit in the range (inclusive)
+     * @param end {@code >= 0;} index of the last bit in the range (exclusive)
+     * @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) {
+        int idx = findFirst(bits, start);
+        return (idx >= 0) && (idx < end);
+    }
+
+    /**
+     * Finds the lowest-order bit set at or after the given index in the
+     * given bit set.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0;} minimum index to return
+     * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+     * or {@code -1} if there is no appropriate bit index to return
+     */
+    public static int findFirst(int[] bits, int idx) {
+        int len = bits.length;
+        int minBit = idx & 0x1f;
+
+        for (int arrayIdx = idx >> 5; arrayIdx < len; arrayIdx++) {
+            int word = bits[arrayIdx];
+            if (word != 0) {
+                int bitIdx = findFirst(word, minBit);
+                if (bitIdx >= 0) {
+                    return (arrayIdx << 5) + bitIdx;
+                }
+            }
+            minBit = 0;
+        }
+
+        return -1;
+    }
+
+    /**
+     * Finds the lowest-order bit set at or after the given index in the
+     * given {@code int}.
+     *
+     * @param value the value in question
+     * @param idx 0..31 the minimum bit index to return
+     * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+     * 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.
+        int result = Integer.numberOfTrailingZeros(value);
+        return (result == 32) ? -1 : result;
+    }
+
+    /**
+     * 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 {@code non-null;} int array to be ored with other argument. This
+     * argument is modified.
+     * @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) {
+        for (int i = 0; i < b.length; i++) {
+            a[i] |= b[i];
+        }
+    }
+
+    public static String toHuman(int[] bits) {
+        StringBuilder sb = new StringBuilder();
+
+        boolean needsComma = false;
+
+        sb.append('{');
+
+        int bitsLength = 32 * bits.length;
+        for (int i = 0; i < bitsLength; i++) {
+            if (Bits.get(bits, i)) {
+                if (needsComma) {
+                    sb.append(',');
+                }
+                needsComma = true;
+                sb.append(i);
+            }
+        }
+        sb.append('}');
+
+        return sb.toString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/ByteArray.java b/dexgen/src/com/android/dexgen/util/ByteArray.java
new file mode 100644
index 0000000..93144b3
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/ByteArray.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 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 {
+    /** {@code non-null;} underlying array */
+    private final byte[] bytes;
+
+    /** {@code >= 0}; start index of the slice (inclusive) */
+    private final int start;
+
+    /** {@code >= 0, <= bytes.length}; size computed as
+     * {@code end - start} (in the constructor) */
+    private final int size;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+        if (bytes == null) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        if (start < 0) {
+            throw new IllegalArgumentException("start < 0");
+        }
+
+        if (end < start) {
+            throw new IllegalArgumentException("end < start");
+        }
+
+        if (end > bytes.length) {
+            throw new IllegalArgumentException("end > bytes.length");
+        }
+
+        this.bytes = bytes;
+        this.start = start;
+        this.size = end - start;
+    }
+
+    /**
+     * Constructs an instance from an entire {@code byte[]}.
+     *
+     * @param bytes {@code non-null;} the underlying array
+     */
+    public ByteArray(byte[] bytes) {
+        this(bytes, 0, bytes.length);
+    }
+
+    /**
+     * Gets the size of the array, in bytes.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns a slice (that is, a sub-array) of this instance.
+     *
+     * @param start {@code >= 0;} start index of the slice (inclusive)
+     * @param end {@code >= start, <= size();} end index of
+     * the slice (exclusive)
+     * @return {@code non-null;} the slice
+     */
+    public ByteArray slice(int start, int end) {
+        checkOffsets(start, end);
+        return new ByteArray(bytes, start + this.start, end + this.start);
+    }
+
+    /**
+     * Returns the offset into the given array represented by the given
+     * offset into this instance.
+     *
+     * @param offset offset into this instance
+     * @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) {
+        if (bytes != this.bytes) {
+            throw new IllegalArgumentException("wrong bytes");
+        }
+
+        return start + offset;
+    }
+
+    /**
+     * Gets the {@code signed byte} value at a particular 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);
+        return getByte0(off);
+    }
+
+    /**
+     * Gets the {@code signed short} value at a particular 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);
+        return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
+    }
+
+    /**
+     * Gets the {@code signed int} value at a particular 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);
+        return (getByte0(off) << 24) |
+            (getUnsignedByte0(off + 1) << 16) |
+            (getUnsignedByte0(off + 2) << 8) |
+            getUnsignedByte0(off + 3);
+    }
+
+    /**
+     * Gets the {@code signed long} value at a particular 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);
+        int part1 = (getByte0(off) << 24) |
+            (getUnsignedByte0(off + 1) << 16) |
+            (getUnsignedByte0(off + 2) << 8) |
+            getUnsignedByte0(off + 3);
+        int part2 = (getByte0(off + 4) << 24) |
+            (getUnsignedByte0(off + 5) << 16) |
+            (getUnsignedByte0(off + 6) << 8) |
+            getUnsignedByte0(off + 7);
+
+        return (part2 & 0xffffffffL) | ((long) part1) << 32;
+    }
+
+    /**
+     * Gets the {@code unsigned byte} value at a particular 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);
+        return getUnsignedByte0(off);
+    }
+
+    /**
+     * Gets the {@code unsigned short} value at a particular 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);
+        return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
+    }
+
+    /**
+     * Copies the contents of this instance into the given raw
+     * {@code byte[]} at the given offset. The given array must be
+     * large enough.
+     *
+     * @param out {@code non-null;} array to hold the output
+     * @param offset {@code non-null;} index into {@code out} for the first
+     * byte of output
+     */
+    public void getBytes(byte[] out, int offset) {
+        if ((out.length - offset) < size) {
+            throw new IndexOutOfBoundsException("(out.length - offset) < " +
+                                                "size()");
+        }
+
+        System.arraycopy(bytes, start, out, offset, size);
+    }
+
+    /**
+     * Checks a range of offsets for validity, throwing if invalid.
+     *
+     * @param s start offset (inclusive)
+     * @param e end offset (exclusive)
+     */
+    private void checkOffsets(int s, int e) {
+        if ((s < 0) || (e < s) || (e > size)) {
+            throw new IllegalArgumentException("bad range: " + s + ".." + e +
+                                               "; actual size " + size);
+        }
+    }
+
+    /**
+     * Gets the {@code signed byte} value at the given offset,
+     * without doing any argument checking.
+     *
+     * @param off offset to fetch
+     * @return byte at that offset
+     */
+    private int getByte0(int off) {
+        return bytes[start + off];
+    }
+
+    /**
+     * Gets the {@code unsigned byte} value at the given offset,
+     * without doing any argument checking.
+     *
+     * @param off offset to fetch
+     * @return byte at that offset
+     */
+    private int getUnsignedByte0(int off) {
+        return bytes[start + off] & 0xff;
+    }
+
+    /**
+     * 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 {@code non-null;} an appropriately-constructed
+     * {@code DataInputStream} instance
+     */
+    public MyDataInputStream makeDataInputStream() {
+        return new MyDataInputStream(makeInputStream());
+    }
+
+    /**
+     * 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 {@code non-null;} an appropriately-constructed
+     * {@code InputStream} instancex
+     */
+    public MyInputStream makeInputStream() {
+        return new MyInputStream();
+    }
+
+    /**
+     * Helper interface that allows one to get the cursor (of a stream).
+     */
+    public interface GetCursor {
+        /**
+         * Gets the current cursor.
+         *
+         * @return {@code 0..size();} the cursor
+         */
+        public int getCursor();
+    }
+
+    /**
+     * Helper class for {@link #makeInputStream}, which implements the
+     * stream functionality.
+     */
+    public class MyInputStream extends InputStream {
+        /** 0..size; the cursor */
+        private int cursor;
+
+        /** 0..size; the mark */
+        private int mark;
+
+        public MyInputStream() {
+            cursor = 0;
+            mark = 0;
+        }
+
+        public int read() throws IOException {
+            if (cursor >= size) {
+                return -1;
+            }
+
+            int result = getUnsignedByte0(cursor);
+            cursor++;
+            return result;
+        }
+
+        public int read(byte[] arr, int offset, int length) {
+            if ((offset + length) > arr.length) {
+                length = arr.length - offset;
+            }
+
+            int maxLength = size - cursor;
+            if (length > maxLength) {
+                length = maxLength;
+            }
+
+            System.arraycopy(bytes, cursor + start, arr, offset, length);
+            cursor += length;
+            return length;
+        }
+
+        public int available() {
+            return size - cursor;
+        }
+
+        public void mark(int reserve) {
+            mark = cursor;
+        }
+
+        public void reset() {
+            cursor = mark;
+        }
+
+        public boolean markSupported() {
+            return true;
+        }
+    }
+
+    /**
+     * Helper class for {@link #makeDataInputStream}. This is used
+     * simply so that the cursor of a wrapped {@link #MyInputStream}
+     * instance may be easily determined.
+     */
+    public static class MyDataInputStream extends DataInputStream {
+        /** {@code non-null;} the underlying {@link #MyInputStream} */
+        private final MyInputStream wrapped;
+
+        public MyDataInputStream(MyInputStream wrapped) {
+            super(wrapped);
+
+            this.wrapped = wrapped;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/ByteArrayAnnotatedOutput.java b/dexgen/src/com/android/dexgen/util/ByteArrayAnnotatedOutput.java
new file mode 100644
index 0000000..5fad9a9
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/ByteArrayAnnotatedOutput.java
@@ -0,0 +1,639 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+
+/**
+ * Implementation of {@link AnnotatedOutput} which stores the written data
+ * into a {@code byte[]}.
+ *
+ * <p><b>Note:</b> As per the {@link Output} interface, multi-byte
+ * writes all use little-endian order.</p>
+ */
+public final class ByteArrayAnnotatedOutput
+        implements AnnotatedOutput {
+    /** default size for stretchy instances */
+    private static final int DEFAULT_SIZE = 1000;
+
+    /**
+     * whether the instance is stretchy, that is, whether its array
+     * may be resized to increase capacity
+     */
+    private final boolean stretchy;
+
+    /** {@code non-null;} the data itself */
+    private byte[] data;
+
+    /** {@code >= 0;} current output cursor */
+    private int cursor;
+
+    /** whether annotations are to be verbose */
+    private boolean verbose;
+
+    /**
+     * {@code null-ok;} list of annotations, or {@code null} if this instance
+     * isn't keeping them
+     */
+    private ArrayList<Annotation> annotations;
+
+    /** {@code >= 40 (if used);} the desired maximum annotation width */
+    private int annotationWidth;
+
+    /**
+     * {@code >= 8 (if used);} the number of bytes of hex output to use
+     * in annotations
+     */
+    private int hexCols;
+
+    /**
+     * Constructs an instance with a fixed maximum size. Note that the
+     * given array is the only one that will be used to store data. In
+     * particular, no reallocation will occur in order to expand the
+     * capacity of the resulting instance. Also, the constructed
+     * instance does not keep annotations by default.
+     *
+     * @param data {@code non-null;} data array to use for output
+     */
+    public ByteArrayAnnotatedOutput(byte[] data) {
+        this(data, false);
+    }
+
+    /**
+     * Constructs a "stretchy" instance. The underlying array may be
+     * reallocated. The constructed instance does not keep annotations
+     * by default.
+     */
+    public ByteArrayAnnotatedOutput() {
+        this(new byte[DEFAULT_SIZE], true);
+    }
+
+    /**
+     * Internal constructor.
+     *
+     * @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) {
+        if (data == null) {
+            throw new NullPointerException("data == null");
+        }
+
+        this.stretchy = stretchy;
+        this.data = data;
+        this.cursor = 0;
+        this.verbose = false;
+        this.annotations = null;
+        this.annotationWidth = 0;
+        this.hexCols = 0;
+    }
+
+    /**
+     * Gets the underlying {@code byte[]} of this instance, which
+     * may be larger than the number of bytes written
+     *
+     * @see #toByteArray
+     *
+     * @return {@code non-null;} the {@code byte[]}
+     */
+    public byte[] getArray() {
+        return data;
+    }
+
+    /**
+     * Constructs and returns a new {@code byte[]} that contains
+     * the written contents exactly (that is, with no extra unwritten
+     * bytes at the end).
+     *
+     * @see #getArray
+     *
+     * @return {@code non-null;} an appropriately-constructed array
+     */
+    public byte[] toByteArray() {
+        byte[] result = new byte[cursor];
+        System.arraycopy(data, 0, result, 0, cursor);
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public int getCursor() {
+        return cursor;
+    }
+
+    /** {@inheritDoc} */
+    public void assertCursor(int expectedCursor) {
+        if (cursor != expectedCursor) {
+            throw new ExceptionWithContext("expected cursor " +
+                    expectedCursor + "; actual value: " + cursor);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void writeByte(int value) {
+        int writeAt = cursor;
+        int end = writeAt + 1;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        data[writeAt] = (byte) value;
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void writeShort(int value) {
+        int writeAt = cursor;
+        int end = writeAt + 2;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        data[writeAt] = (byte) value;
+        data[writeAt + 1] = (byte) (value >> 8);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void writeInt(int value) {
+        int writeAt = cursor;
+        int end = writeAt + 4;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        data[writeAt] = (byte) value;
+        data[writeAt + 1] = (byte) (value >> 8);
+        data[writeAt + 2] = (byte) (value >> 16);
+        data[writeAt + 3] = (byte) (value >> 24);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void writeLong(long value) {
+        int writeAt = cursor;
+        int end = writeAt + 8;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        int half = (int) value;
+        data[writeAt] = (byte) half;
+        data[writeAt + 1] = (byte) (half >> 8);
+        data[writeAt + 2] = (byte) (half >> 16);
+        data[writeAt + 3] = (byte) (half >> 24);
+
+        half = (int) (value >> 32);
+        data[writeAt + 4] = (byte) half;
+        data[writeAt + 5] = (byte) (half >> 8);
+        data[writeAt + 6] = (byte) (half >> 16);
+        data[writeAt + 7] = (byte) (half >> 24);
+
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public int writeUnsignedLeb128(int value) {
+        int remaining = value >> 7;
+        int count = 0;
+
+        while (remaining != 0) {
+            writeByte((value & 0x7f) | 0x80);
+            value = remaining;
+            remaining >>= 7;
+            count++;
+        }
+
+        writeByte(value & 0x7f);
+        return count + 1;
+    }
+
+    /** {@inheritDoc} */
+    public int writeSignedLeb128(int value) {
+        int remaining = value >> 7;
+        int count = 0;
+        boolean hasMore = true;
+        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
+
+        while (hasMore) {
+            hasMore = (remaining != end)
+                || ((remaining & 1) != ((value >> 6) & 1));
+
+            writeByte((value & 0x7f) | (hasMore ? 0x80 : 0));
+            value = remaining;
+            remaining >>= 7;
+            count++;
+        }
+
+        return count;
+    }
+
+    /** {@inheritDoc} */
+    public void write(ByteArray bytes) {
+        int blen = bytes.size();
+        int writeAt = cursor;
+        int end = writeAt + blen;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        bytes.getBytes(data, writeAt);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void write(byte[] bytes, int offset, int length) {
+        int writeAt = cursor;
+        int end = writeAt + length;
+        int bytesEnd = offset + length;
+
+        // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+        if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
+            throw new IndexOutOfBoundsException("bytes.length " +
+                                                bytes.length + "; " +
+                                                offset + "..!" + end);
+        }
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        System.arraycopy(bytes, offset, data, writeAt, length);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void write(byte[] bytes) {
+        write(bytes, 0, bytes.length);
+    }
+
+    /** {@inheritDoc} */
+    public void writeZeroes(int count) {
+        if (count < 0) {
+            throw new IllegalArgumentException("count < 0");
+        }
+
+        int end = cursor + count;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        /*
+         * There is no need to actually write zeroes, since the array is
+         * already preinitialized with zeroes.
+         */
+
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void alignTo(int alignment) {
+        int mask = alignment - 1;
+
+        if ((alignment < 0) || ((mask & alignment) != 0)) {
+            throw new IllegalArgumentException("bogus alignment");
+        }
+
+        int end = (cursor + mask) & ~mask;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        /*
+         * There is no need to actually write zeroes, since the array is
+         * already preinitialized with zeroes.
+         */
+
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public boolean annotates() {
+        return (annotations != null);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isVerbose() {
+        return verbose;
+    }
+
+    /** {@inheritDoc} */
+    public void annotate(String msg) {
+        if (annotations == null) {
+            return;
+        }
+
+        endAnnotation();
+        annotations.add(new Annotation(cursor, msg));
+    }
+
+    /** {@inheritDoc} */
+    public void annotate(int amt, String msg) {
+        if (annotations == null) {
+            return;
+        }
+
+        endAnnotation();
+
+        int asz = annotations.size();
+        int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
+        int startAt;
+
+        if (lastEnd <= cursor) {
+            startAt = cursor;
+        } else {
+            startAt = lastEnd;
+        }
+
+        annotations.add(new Annotation(startAt, startAt + amt, msg));
+    }
+
+    /** {@inheritDoc} */
+    public void endAnnotation() {
+        if (annotations == null) {
+            return;
+        }
+
+        int sz = annotations.size();
+
+        if (sz != 0) {
+            annotations.get(sz - 1).setEndIfUnset(cursor);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int getAnnotationWidth() {
+        int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
+
+        return annotationWidth - leftWidth;
+    }
+
+    /**
+     * Indicates that this instance should keep annotations. This method may
+     * be called only once per instance, and only before any data has been
+     * written to the it.
+     *
+     * @param annotationWidth {@code >= 40;} the desired maximum annotation width
+     * @param verbose whether or not to indicate verbose annotations
+     */
+    public void enableAnnotations(int annotationWidth, boolean verbose) {
+        if ((annotations != null) || (cursor != 0)) {
+            throw new RuntimeException("cannot enable annotations");
+        }
+
+        if (annotationWidth < 40) {
+            throw new IllegalArgumentException("annotationWidth < 40");
+        }
+
+        int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
+        if (hexCols < 6) {
+            hexCols = 6;
+        } else if (hexCols > 10) {
+            hexCols = 10;
+        }
+
+        this.annotations = new ArrayList<Annotation>(1000);
+        this.annotationWidth = annotationWidth;
+        this.hexCols = hexCols;
+        this.verbose = verbose;
+    }
+
+    /**
+     * Finishes up annotation processing. This closes off any open
+     * annotations and removes annotations that don't refer to written
+     * data.
+     */
+    public void finishAnnotating() {
+        // Close off the final annotation, if any.
+        endAnnotation();
+
+        // Remove annotations that refer to unwritten data.
+        if (annotations != null) {
+            int asz = annotations.size();
+            while (asz > 0) {
+                Annotation last = annotations.get(asz - 1);
+                if (last.getStart() > cursor) {
+                    annotations.remove(asz - 1);
+                    asz--;
+                } else if (last.getEnd() > cursor) {
+                    last.setEnd(cursor);
+                    break;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Writes the annotated content of this instance to the given writer.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public void writeAnnotationsTo(Writer out) throws IOException {
+        int width2 = getAnnotationWidth();
+        int width1 = annotationWidth - width2 - 1;
+
+        TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
+        Writer left = twoc.getLeft();
+        Writer right = twoc.getRight();
+        int leftAt = 0; // left-hand byte output cursor
+        int rightAt = 0; // right-hand annotation index
+        int rightSz = annotations.size();
+
+        while ((leftAt < cursor) && (rightAt < rightSz)) {
+            Annotation a = annotations.get(rightAt);
+            int start = a.getStart();
+            int end;
+            String text;
+
+            if (leftAt < start) {
+                // This is an area with no annotation.
+                end = start;
+                start = leftAt;
+                text = "";
+            } else {
+                // This is an area with an annotation.
+                end = a.getEnd();
+                text = a.getText();
+                rightAt++;
+            }
+
+            left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
+            right.write(text);
+            twoc.flush();
+            leftAt = end;
+        }
+
+        if (leftAt < cursor) {
+            // There is unannotated output at the end.
+            left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt,
+                                hexCols, 6));
+        }
+
+        while (rightAt < rightSz) {
+            // There are zero-byte annotations at the end.
+            right.write(annotations.get(rightAt).getText());
+            rightAt++;
+        }
+
+        twoc.flush();
+    }
+
+    /**
+     * Throws the excpetion for when an attempt is made to write past the
+     * end of the instance.
+     */
+    private static void throwBounds() {
+        throw new IndexOutOfBoundsException("attempt to write past the end");
+    }
+
+    /**
+     * Reallocates the underlying array if necessary. Calls to this method
+     * should be guarded by a test of {@link #stretchy}.
+     *
+     * @param desiredSize {@code >= 0;} the desired minimum total size of the array
+     */
+    private void ensureCapacity(int desiredSize) {
+        if (data.length < desiredSize) {
+            byte[] newData = new byte[desiredSize * 2 + 1000];
+            System.arraycopy(data, 0, newData, 0, cursor);
+            data = newData;
+        }
+    }
+
+    /**
+     * Annotation on output.
+     */
+    private static class Annotation {
+        /** {@code >= 0;} start of annotated range (inclusive) */
+        private final int start;
+
+        /**
+         * {@code >= 0;} end of annotated range (exclusive);
+         * {@code Integer.MAX_VALUE} if unclosed
+         */
+        private int end;
+
+        /** {@code non-null;} annotation text */
+        private final String text;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param start {@code >= 0;} start of annotated range
+         * @param end {@code >= start;} end of annotated range (exclusive) or
+         * {@code Integer.MAX_VALUE} if unclosed
+         * @param text {@code non-null;} annotation text
+         */
+        public Annotation(int start, int end, String text) {
+            this.start = start;
+            this.end = end;
+            this.text = text;
+        }
+
+        /**
+         * Constructs an instance. It is initally unclosed.
+         *
+         * @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);
+        }
+
+        /**
+         * Sets the end as given, but only if the instance is unclosed;
+         * otherwise, do nothing.
+         *
+         * @param end {@code >= start;} the end
+         */
+        public void setEndIfUnset(int end) {
+            if (this.end == Integer.MAX_VALUE) {
+                this.end = end;
+            }
+        }
+
+        /**
+         * Sets the end as given.
+         *
+         * @param end {@code >= start;} the end
+         */
+        public void setEnd(int end) {
+            this.end = end;
+        }
+
+        /**
+         * Gets the start.
+         *
+         * @return the start
+         */
+        public int getStart() {
+            return start;
+        }
+
+        /**
+         * Gets the end.
+         *
+         * @return the end
+         */
+        public int getEnd() {
+            return end;
+        }
+
+        /**
+         * Gets the text.
+         *
+         * @return {@code non-null;} the text
+         */
+        public String getText() {
+            return text;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/DexClassLoaderHelper.java b/dexgen/src/com/android/dexgen/util/DexClassLoaderHelper.java
new file mode 100644
index 0000000..97118ea
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/DexClassLoaderHelper.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import dalvik.system.DexClassLoader;
+
+/**
+ * Class used indirectly for loading generated dex classes. It allows the caller
+ * to obtain appropriate {@code DexClassLoader} instance, which can be then used for
+ * loading classes.
+ */
+public class DexClassLoaderHelper {
+
+    private static class DexClassLoaderHelperHolder {
+        private static final DexClassLoaderHelper INSTANCE = new DexClassLoaderHelper();
+    }
+
+    private DexClassLoaderHelper() {
+        // intentionally empty to disable direct instantiation
+    }
+
+    /**
+     * Returns the sole instance of {@code DexClassLoaderHelper}.
+     *
+     * @return dex {@code DexClassLoaderHelper} sole instance
+     */
+    public static DexClassLoaderHelper getInstance() {
+        return DexClassLoaderHelperHolder.INSTANCE;
+    }
+
+    /**
+     * Creates and returns DexClassLoader instance with its classpath
+     * set to {@code pathHolder}.
+     *
+     * @param pathHolder {@code non-null;} location of jar archive containing dex
+     * classes canned into a working PathHolder instance.
+     * @return dex class loader instance with its classpath set to location
+     * indicated by {@code pathHolder}
+     */
+    public ClassLoader getDexClassLoader(PathHolder pathHolder) {
+        ClassLoader myLoader = DexClassLoaderHelper.class.getClassLoader();
+        return new DexClassLoader(pathHolder.getJarFilePath(), pathHolder.getDirLocation(),
+                null, myLoader);
+    }
+}
\ No newline at end of file
diff --git a/dexgen/src/com/android/dexgen/util/DexClassLoadingException.java b/dexgen/src/com/android/dexgen/util/DexClassLoadingException.java
new file mode 100644
index 0000000..ba4d350
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/DexClassLoadingException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * An exception type used to aggregate all the unexpected situations while
+ * trying to save dex file with generated class and load the class afterwards.
+ */
+public class DexClassLoadingException extends Exception {
+
+    /**
+     * Encapsulates any checked exception being thrown in time between saving
+     * generated dex class to a file and loading it via DexClassLoader with
+     * an user-friendly message and passing the original exception as well.
+     *
+     * @param thr {@code non-null;} lower level exception with more detailed
+     * error message
+     */
+    public DexClassLoadingException(Throwable thr) {
+        super("Loading generated dex class has failed", thr);
+    }
+}
\ No newline at end of file
diff --git a/dexgen/src/com/android/dexgen/util/DexJarMaker.java b/dexgen/src/com/android/dexgen/util/DexJarMaker.java
new file mode 100644
index 0000000..4fe5a56
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/DexJarMaker.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+/**
+ * Helper class used to encapsulate generated .dex file into .jar
+ * so that it fits {@code DexClassLoader} constructor.
+ */
+public class DexJarMaker {
+
+    /** indicates name of the dex file added to jar */
+    public static final String DEX_FILE_NAME_IN_JAR = "classes" + PathHolder.DEX_FILE_EXTENSION;
+
+    /** {@code non-null;} storage for all the paths related to current dex file */
+    private final PathHolder pathHolder;
+
+    public DexJarMaker(PathHolder pathHolder) {
+        this.pathHolder = pathHolder;
+    }
+
+    /** Packs previously added files into a single jar archive. */
+    public void create() throws DexClassLoadingException {
+        Manifest manifest = new Manifest();
+        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        JarOutputStream target = null;
+        try {
+            target = new JarOutputStream(
+                    new BufferedOutputStream(new FileOutputStream(pathHolder.getJarFilePath())),
+                    manifest);
+            add(new File(pathHolder.getDexFilePath()), target);
+
+        } catch (IOException e) {
+            throw new DexClassLoadingException(e);
+        }
+        finally {
+            try {
+                if (target != null) {
+                    target.close();
+                }
+            } catch(IOException e) {
+                // Ignoring deliberately in order to keep the original exception clear.
+            }
+        }
+    }
+
+    /**
+     * Adds indicated file to the requested archive.
+     *
+     * @param source {@code non-null;} dex file to add
+     * @param target {@code non-null;} target jar archive
+     * @throws IOException
+     */
+    private void add(File source, JarOutputStream target) throws IOException {
+
+        if (!source.isFile()) {
+            throw new IllegalArgumentException("Wrong source dex file provided");
+        }
+
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(source));
+        JarEntry entry = new JarEntry(DEX_FILE_NAME_IN_JAR);
+        entry.setTime(source.lastModified());
+        target.putNextEntry(entry);
+
+        int curr = -1;
+        while ((curr = in.read()) != -1) {
+            target.write(curr);
+        }
+        target.closeEntry();
+    }
+}
\ No newline at end of file
diff --git a/dexgen/src/com/android/dexgen/util/ExceptionWithContext.java b/dexgen/src/com/android/dexgen/util/ExceptionWithContext.java
new file mode 100644
index 0000000..67e7f72
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/ExceptionWithContext.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * Exception which carries around structured context.
+ */
+public class ExceptionWithContext
+        extends RuntimeException {
+    /** {@code non-null;} human-oriented context of the exception */
+    private StringBuffer context;
+
+    /**
+     * Augments the given exception with the given context, and return the
+     * result. The result is either the given exception if it was an
+     * {@link ExceptionWithContext}, or a newly-constructed exception if it
+     * was not.
+     *
+     * @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;
+
+        if (ex instanceof ExceptionWithContext) {
+            ewc = (ExceptionWithContext) ex;
+        } else {
+            ewc = new ExceptionWithContext(ex);
+        }
+
+        ewc.addContext(str);
+        return ewc;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param message human-oriented message
+     */
+    public ExceptionWithContext(String message) {
+        this(message, null);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cause {@code null-ok;} exception that caused this one
+     */
+    public ExceptionWithContext(Throwable cause) {
+        this(null, cause);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param message human-oriented message
+     * @param cause {@code null-ok;} exception that caused this one
+     */
+    public ExceptionWithContext(String message, Throwable cause) {
+        super((message != null) ? message :
+              (cause != null) ? cause.getMessage() : null,
+              cause);
+
+        if (cause instanceof ExceptionWithContext) {
+            String ctx = ((ExceptionWithContext) cause).context.toString();
+            context = new StringBuffer(ctx.length() + 200);
+            context.append(ctx);
+        } else {
+            context = new StringBuffer(200);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void printStackTrace(PrintStream out) {
+        super.printStackTrace(out);
+        out.println(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void printStackTrace(PrintWriter out) {
+        super.printStackTrace(out);
+        out.println(context);
+    }
+
+    /**
+     * Adds a line of context to this instance.
+     *
+     * @param str {@code non-null;} new context
+     */
+    public void addContext(String str) {
+        if (str == null) {
+            throw new NullPointerException("str == null");
+        }
+
+        context.append(str);
+        if (!str.endsWith("\n")) {
+            context.append('\n');
+        }
+    }
+
+    /**
+     * Gets the context.
+     *
+     * @return {@code non-null;} the context
+     */
+    public String getContext() {
+        return context.toString();
+    }
+
+    /**
+     * Prints the message and context.
+     *
+     * @param out {@code non-null;} where to print to
+     */
+    public void printContext(PrintStream out) {
+        out.println(getMessage());
+        out.print(context);
+    }
+
+    /**
+     * Prints the message and context.
+     *
+     * @param out {@code non-null;} where to print to
+     */
+    public void printContext(PrintWriter out) {
+        out.println(getMessage());
+        out.print(context);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/FileUtils.java b/dexgen/src/com/android/dexgen/util/FileUtils.java
new file mode 100644
index 0000000..a5bbff4
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/FileUtils.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * File I/O utilities.
+ */
+public final class FileUtils {
+    /**
+     * This class is uninstantiable.
+     */
+    private FileUtils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Reads the named file, translating {@link IOException} to a
+     * {@link RuntimeException} of some sort.
+     *
+     * @param fileName {@code non-null;} name of the file to read
+     * @return {@code non-null;} contents of the file
+     */
+    public static byte[] readFile(String fileName) {
+        File file = new File(fileName);
+        return readFile(file);
+    }
+
+    /**
+     * Reads the given file, translating {@link IOException} to a
+     * {@link RuntimeException} of some sort.
+     *
+     * @param file {@code non-null;} the file to read
+     * @return {@code non-null;} contents of the file
+     */
+    public static byte[] readFile(File file) {
+        if (!file.exists()) {
+            throw new RuntimeException(file + ": file not found");
+        }
+
+        if (!file.isFile()) {
+            throw new RuntimeException(file + ": not a file");
+        }
+
+        if (!file.canRead()) {
+            throw new RuntimeException(file + ": file not readable");
+        }
+
+        long longLength = file.length();
+        int length = (int) longLength;
+        if (length != longLength) {
+            throw new RuntimeException(file + ": file too long");
+        }
+
+        byte[] result = new byte[length];
+
+        try {
+            FileInputStream in = new FileInputStream(file);
+            int at = 0;
+            while (length > 0) {
+                int amt = in.read(result, at, length);
+                if (amt == -1) {
+                    throw new RuntimeException(file + ": unexpected EOF");
+                }
+                at += amt;
+                length -= amt;
+            }
+            in.close();
+        } catch (IOException ex) {
+            throw new RuntimeException(file + ": trouble reading", ex);
+        }
+
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/FixedSizeList.java b/dexgen/src/com/android/dexgen/util/FixedSizeList.java
new file mode 100644
index 0000000..039b5b0
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/FixedSizeList.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.util.Arrays;
+
+/**
+ * Simple (mostly) fixed-size list of objects, which may be made immutable.
+ */
+public class FixedSizeList
+        extends MutabilityControl implements ToHuman {
+    /** {@code non-null;} array of elements */
+    private Object[] arr;
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public FixedSizeList(int size) {
+        super(size != 0);
+
+        try {
+            arr = new Object[size];
+        } catch (NegativeArraySizeException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("size < 0");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            // Easy out.
+            return true;
+        }
+
+        if ((other == null) || (getClass() != other.getClass())) {
+            // Another easy out.
+            return false;
+        }
+
+        FixedSizeList list = (FixedSizeList) other;
+        return Arrays.equals(arr, list.arr);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(arr);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        String name = getClass().getName();
+
+        return toString0(name.substring(name.lastIndexOf('.') + 1) + '{',
+                         ", ",
+                         "}",
+                         false);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This method will only work if every element of the list
+     * implements {@link ToHuman}.
+     */
+    public String toHuman() {
+        String name = getClass().getName();
+
+        return toString0(name.substring(name.lastIndexOf('.') + 1) + '{',
+                         ", ",
+                         "}",
+                         true);
+    }
+
+    /**
+     * Gets a customized string form for this instance.
+     *
+     * @param prefix {@code null-ok;} prefix for the start of the result
+     * @param separator {@code null-ok;} separator to insert between each item
+     * @param suffix {@code null-ok;} suffix for the end of the result
+     * @return {@code non-null;} the custom string
+     */
+    public String toString(String prefix, String separator, String suffix) {
+        return toString0(prefix, separator, suffix, false);
+    }
+
+    /**
+     * Gets a customized human string for this instance. This method will
+     * only work if every element of the list implements {@link
+     * ToHuman}.
+     *
+     * @param prefix {@code null-ok;} prefix for the start of the result
+     * @param separator {@code null-ok;} separator to insert between each item
+     * @param suffix {@code null-ok;} suffix for the end of the result
+     * @return {@code non-null;} the custom string
+     */
+    public String toHuman(String prefix, String separator, String suffix) {
+        return toString0(prefix, separator, suffix, true);
+    }
+
+    /**
+     * Gets the number of elements in this list.
+     */
+    public final int size() {
+        return arr.length;
+    }
+
+    /**
+     * Shrinks this instance to fit, by removing any unset
+     * ({@code null}) elements, leaving the remaining elements in
+     * their original order.
+     */
+    public void shrinkToFit() {
+        int sz = arr.length;
+        int newSz = 0;
+
+        for (int i = 0; i < sz; i++) {
+            if (arr[i] != null) {
+                newSz++;
+            }
+        }
+
+        if (sz == newSz) {
+            return;
+        }
+
+        throwIfImmutable();
+
+        Object[] newa = new Object[newSz];
+        int at = 0;
+
+        for (int i = 0; i < sz; i++) {
+            Object one = arr[i];
+            if (one != null) {
+                newa[at] = one;
+                at++;
+            }
+        }
+
+        arr = newa;
+        if (newSz == 0) {
+            setImmutable();
+        }
+    }
+
+    /**
+     * 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}. This method is
+     * protected so that subclasses may offer a safe type-checked
+     * public interface to their clients.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    protected final Object get0(int n) {
+        try {
+            Object result = arr[n];
+
+            if (result == null) {
+                throw new NullPointerException("unset: " + n);
+            }
+
+            return result;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            return throwIndex(n);
+        }
+    }
+
+    /**
+     * 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 {@code >= 0, < size();} which element
+     * @return {@code null-ok;} the indicated element
+     */
+    protected final Object getOrNull0(int n) {
+        return arr[n];
+    }
+
+    /**
+     * Sets the element at the given index, but without doing any type
+     * checks on the element. This method is protected so that
+     * subclasses may offer a safe type-checked public interface to
+     * their clients.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param obj {@code null-ok;} the value to store
+     */
+    protected final void set0(int n, Object obj) {
+        throwIfImmutable();
+
+        try {
+            arr[n] = obj;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throwIndex(n);
+        }
+    }
+
+    /**
+     * Throws the appropriate exception for the given index value.
+     *
+     * @param n the index value
+     * @return never
+     * @throws IndexOutOfBoundsException always thrown
+     */
+    private Object throwIndex(int n) {
+        if (n < 0) {
+            throw new IndexOutOfBoundsException("n < 0");
+        }
+
+        throw new IndexOutOfBoundsException("n >= size()");
+    }
+
+    /**
+     * Helper for {@link #toString} and {@link #toHuman}, which both of
+     * those call to pretty much do everything.
+     *
+     * @param prefix {@code null-ok;} prefix for the start of the result
+     * @param separator {@code null-ok;} separator to insert between each item
+     * @param suffix {@code null-ok;} suffix for the end of the result
+     * @param human whether the output is to be human
+     * @return {@code non-null;} the custom string
+     */
+    private String toString0(String prefix, String separator, String suffix,
+                             boolean human) {
+        int len = arr.length;
+        StringBuffer sb = new StringBuffer(len * 10 + 10);
+
+        if (prefix != null) {
+            sb.append(prefix);
+        }
+
+        for (int i = 0; i < len; i++) {
+            if ((i != 0) && (separator != null)) {
+                sb.append(separator);
+            }
+
+            if (human) {
+                sb.append(((ToHuman) arr[i]).toHuman());
+            } else {
+                sb.append(arr[i]);
+            }
+        }
+
+        if (suffix != null) {
+            sb.append(suffix);
+        }
+
+        return sb.toString();
+    }
+
+}
diff --git a/dexgen/src/com/android/dexgen/util/Hex.java b/dexgen/src/com/android/dexgen/util/Hex.java
new file mode 100644
index 0000000..4dafb77
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/Hex.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Utilities for formatting numbers as hexadecimal.
+ */
+public final class Hex {
+    /**
+     * This class is uninstantiable.
+     */
+    private Hex() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Formats a {@code long} as an 8-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u8(long v) {
+        char[] result = new char[16];
+        for (int i = 0; i < 16; i++) {
+            result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 4-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u4(int v) {
+        char[] result = new char[8];
+        for (int i = 0; i < 8; i++) {
+            result[7 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 3-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u3(int v) {
+        char[] result = new char[6];
+        for (int i = 0; i < 6; i++) {
+            result[5 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 2-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u2(int v) {
+        char[] result = new char[4];
+        for (int i = 0; i < 4; i++) {
+            result[3 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as either a 2-byte unsigned hex value
+     * (if the value is small enough) or a 4-byte unsigned hex value (if
+     * not).
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u2or4(int v) {
+        if (v == (char) v) {
+            return u2(v);
+        } else {
+            return u4(v);
+        }
+    }
+
+    /**
+     * Formats an {@code int} as a 1-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u1(int v) {
+        char[] result = new char[2];
+        for (int i = 0; i < 2; i++) {
+            result[1 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 4-bit unsigned hex nibble.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String uNibble(int v) {
+        char[] result = new char[1];
+
+        result[0] = Character.forDigit(v & 0x0f, 16);
+        return new String(result);
+    }
+
+    /**
+     * Formats a {@code long} as an 8-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s8(long v) {
+        char[] result = new char[17];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 16; i++) {
+            result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 4-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s4(int v) {
+        char[] result = new char[9];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 8; i++) {
+            result[8 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 2-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s2(int v) {
+        char[] result = new char[5];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 4; i++) {
+            result[4 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 1-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s1(int v) {
+        char[] result = new char[3];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 2; i++) {
+            result[2 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(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 ""}).
+     *
+     * @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 {@code non-null;} a string of the dump
+     */
+    public static String dump(byte[] arr, int offset, int length,
+                              int outOffset, int bpl, int addressLength) {
+        int end = offset + length;
+
+        // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+        if (((offset | length | end) < 0) || (end > arr.length)) {
+            throw new IndexOutOfBoundsException("arr.length " +
+                                                arr.length + "; " +
+                                                offset + "..!" + end);
+        }
+
+        if (outOffset < 0) {
+            throw new IllegalArgumentException("outOffset < 0");
+        }
+
+        if (length == 0) {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer(length * 4 + 6);
+        boolean bol = true;
+        int col = 0;
+
+        while (length > 0) {
+            if (col == 0) {
+                String astr;
+                switch (addressLength) {
+                    case 2:  astr = Hex.u1(outOffset); break;
+                    case 4:  astr = Hex.u2(outOffset); break;
+                    case 6:  astr = Hex.u3(outOffset); break;
+                    default: astr = Hex.u4(outOffset); break;
+                }
+                sb.append(astr);
+                sb.append(": ");
+            } else if ((col & 1) == 0) {
+                sb.append(' ');
+            }
+            sb.append(Hex.u1(arr[offset]));
+            outOffset++;
+            offset++;
+            col++;
+            if (col == bpl) {
+                sb.append('\n');
+                col = 0;
+            }
+            length--;
+        }
+
+        if (col != 0) {
+            sb.append('\n');
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/HexParser.java b/dexgen/src/com/android/dexgen/util/HexParser.java
new file mode 100644
index 0000000..cc4f909
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/HexParser.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Utilities for parsing hexadecimal text.
+ */
+public final class HexParser {
+    /**
+     * This class is uninstantiable.
+     */
+    private HexParser() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * 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
+     * hex digits freely interspersed with whitespace. If a pound sign
+     * is encountered, it and the rest of the line are ignored as a
+     * comment. If a double quote is encountered, then the ASCII value
+     * of the subsequent characters is used, until the next double
+     * quote. Quoted strings may not span multiple lines.
+     *
+     * @param src {@code non-null;} the source string
+     * @return {@code non-null;} the parsed form
+     */
+    public static byte[] parse(String src) {
+        int len = src.length();
+        byte[] result = new byte[len / 2];
+        int at = 0;
+        int outAt = 0;
+
+        while (at < len) {
+            int nlAt = src.indexOf('\n', at);
+            if (nlAt < 0) {
+                nlAt = len;
+            }
+            int poundAt = src.indexOf('#', at);
+
+            String line;
+            if ((poundAt >= 0) && (poundAt < nlAt)) {
+                line = src.substring(at, poundAt);
+            } else {
+                line = src.substring(at, nlAt);
+            }
+            at = nlAt + 1;
+
+            int colonAt = line.indexOf(':');
+
+            atCheck:
+            if (colonAt != -1) {
+                int quoteAt = line.indexOf('\"');
+                if ((quoteAt != -1) && (quoteAt < colonAt)) {
+                    break atCheck;
+                }
+
+                String atStr = line.substring(0, colonAt).trim();
+                line = line.substring(colonAt + 1);
+                int alleged = Integer.parseInt(atStr, 16);
+                if (alleged != outAt) {
+                    throw new RuntimeException("bogus offset marker: " +
+                                               atStr);
+                }
+            }
+
+            int lineLen = line.length();
+            int value = -1;
+            boolean quoteMode = false;
+
+            for (int i = 0; i < lineLen; i++) {
+                char c = line.charAt(i);
+
+                if (quoteMode) {
+                    if (c == '\"') {
+                        quoteMode = false;
+                    } else {
+                        result[outAt] = (byte) c;
+                        outAt++;
+                    }
+                    continue;
+                }
+
+                if (c <= ' ') {
+                    continue;
+                }
+                if (c == '\"') {
+                    if (value != -1) {
+                        throw new RuntimeException("spare digit around " +
+                                                   "offset " + Hex.u4(outAt));
+                    }
+                    quoteMode = true;
+                    continue;
+                }
+
+                int digVal = Character.digit(c, 16);
+                if (digVal == -1) {
+                    throw new RuntimeException("bogus digit character: \"" +
+                                               c + "\"");
+                }
+                if (value == -1) {
+                    value = digVal;
+                } else {
+                    result[outAt] = (byte) ((value << 4) | digVal);
+                    outAt++;
+                    value = -1;
+                }
+            }
+
+            if (value != -1) {
+                throw new RuntimeException("spare digit around offset " +
+                                           Hex.u4(outAt));
+            }
+
+            if (quoteMode) {
+                throw new RuntimeException("unterminated quote around " +
+                                           "offset " + Hex.u4(outAt));
+            }
+        }
+
+        if (outAt < result.length) {
+            byte[] newr = new byte[outAt];
+            System.arraycopy(result, 0, newr, 0, outAt);
+            result = newr;
+        }
+
+        return result;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/IndentingWriter.java b/dexgen/src/com/android/dexgen/util/IndentingWriter.java
new file mode 100644
index 0000000..05d4b0c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/IndentingWriter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Writer that wraps another writer and passes width-limited and
+ * optionally-prefixed output to its subordinate. When lines are
+ * wrapped they are automatically indented based on the start of the
+ * line.
+ */
+public final class IndentingWriter extends FilterWriter {
+    /** {@code null-ok;} optional prefix for every line */
+    private final String prefix;
+
+    /** {@code > 0;} the maximum output width */
+    private final int width;
+
+    /** {@code > 0;} the maximum indent */
+    private final int maxIndent;
+
+    /** {@code >= 0;} current output column (zero-based) */
+    private int column;
+
+    /** whether indent spaces are currently being collected */
+    private boolean collectingIndent;
+
+    /** {@code >= 0;} current indent amount */
+    private int indent;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param out {@code non-null;} writer to send final output to
+     * @param width {@code >= 0;} the maximum output width (not including
+     * {@code prefix}), or {@code 0} for no maximum
+     * @param prefix {@code non-null;} the prefix for each line
+     */
+    public IndentingWriter(Writer out, int width, String prefix) {
+        super(out);
+
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        }
+
+        if (width < 0) {
+            throw new IllegalArgumentException("width < 0");
+        }
+
+        if (prefix == null) {
+            throw new NullPointerException("prefix == null");
+        }
+
+        this.width = (width != 0) ? width : Integer.MAX_VALUE;
+        this.maxIndent = width >> 1;
+        this.prefix = (prefix.length() == 0) ? null : prefix;
+
+        bol();
+    }
+
+    /**
+     * Constructs a no-prefix instance.
+     *
+     * @param out {@code non-null;} writer to send final output to
+     * @param width {@code >= 0;} the maximum output width (not including
+     * {@code prefix}), or {@code 0} for no maximum
+     */
+    public IndentingWriter(Writer out, int width) {
+        this(out, width, "");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(int c) throws IOException {
+        synchronized (lock) {
+            if (collectingIndent) {
+                if (c == ' ') {
+                    indent++;
+                    if (indent >= maxIndent) {
+                        indent = maxIndent;
+                        collectingIndent = false;
+                    }
+                } else {
+                    collectingIndent = false;
+                }
+            }
+
+            if ((column == width) && (c != '\n')) {
+                out.write('\n');
+                column = 0;
+                /*
+                 * Note: No else, so this should fall through to the next
+                 * if statement.
+                 */
+            }
+
+            if (column == 0) {
+                if (prefix != null) {
+                    out.write(prefix);
+                }
+
+                if (!collectingIndent) {
+                    for (int i = 0; i < indent; i++) {
+                        out.write(' ');
+                    }
+                    column = indent;
+                }
+            }
+
+            out.write(c);
+
+            if (c == '\n') {
+                bol();
+            } else {
+                column++;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        synchronized (lock) {
+            while (len > 0) {
+                write(cbuf[off]);
+                off++;
+                len--;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(String str, int off, int len) throws IOException {
+        synchronized (lock) {
+            while (len > 0) {
+                write(str.charAt(off));
+                off++;
+                len--;
+            }
+        }
+    }
+
+    /**
+     * Indicates that output is at the beginning of a line.
+     */
+    private void bol() {
+        column = 0;
+        collectingIndent = (maxIndent != 0);
+        indent = 0;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/IntIterator.java b/dexgen/src/com/android/dexgen/util/IntIterator.java
new file mode 100644
index 0000000..42d92fa
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/IntIterator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * An iterator for a list of ints.
+ */
+public interface IntIterator {
+
+    /**
+     * Checks to see if the iterator has a next value.
+     *
+     * @return true if next() will succeed
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next value in the iterator.
+     *
+     * @return next value
+     * @throws java.util.NoSuchElementException if no next element exists
+     */
+    int next();
+}
diff --git a/dexgen/src/com/android/dexgen/util/IntList.java b/dexgen/src/com/android/dexgen/util/IntList.java
new file mode 100644
index 0000000..ad29c0b
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/IntList.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.util.Arrays;
+
+/**
+ * Simple list of {@code int}s.
+ */
+public final class IntList extends MutabilityControl {
+    /** {@code non-null;} immutable, no-element instance */
+    public static final IntList EMPTY = new IntList(0);
+
+    /** {@code non-null;} array of elements */
+    private int[] values;
+
+    /** {@code >= 0;} current size of the list */
+    private int size;
+
+    /** whether the values are currently sorted */
+    private boolean sorted;
+
+    static {
+        EMPTY.setImmutable();
+    }
+
+    /**
+     * Constructs a new immutable instance with the given element.
+     *
+     * @param value the sole value in the list
+     */
+    public static IntList makeImmutable(int value) {
+        IntList result = new IntList(1);
+
+        result.add(value);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs a new immutable instance with the given elements.
+     *
+     * @param value0 the first value in the list
+     * @param value1 the second value in the list
+     */
+    public static IntList makeImmutable(int value0, int value1) {
+        IntList result = new IntList(2);
+
+        result.add(value0);
+        result.add(value1);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs an empty instance with a default initial capacity.
+     */
+    public IntList() {
+        this(4);
+    }
+
+    /**
+     * Constructs an empty instance.
+     *
+     * @param initialCapacity {@code >= 0;} initial capacity of the list
+     */
+    public IntList(int initialCapacity) {
+        super(true);
+
+        try {
+            values = new int[initialCapacity];
+        } catch (NegativeArraySizeException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("size < 0");
+        }
+
+        size = 0;
+        sorted = true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int result = 0;
+
+        for (int i = 0; i < size; i++) {
+            result = (result * 31) + values[i];
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+
+        if (! (other instanceof IntList)) {
+            return false;
+        }
+
+        IntList otherList = (IntList) other;
+
+        if (sorted != otherList.sorted) {
+            return false;
+        }
+
+        if (size != otherList.size) {
+            return false;
+        }
+
+        for (int i = 0; i < size; i++) {
+            if (values[i] != otherList.values[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(size * 5 + 10);
+
+        sb.append('{');
+
+        for (int i = 0; i < size; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(values[i]);
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the number of elements in this list.
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Gets the indicated value.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return the indicated element's value
+     */
+    public int get(int n) {
+        if (n >= size) {
+            throw new IndexOutOfBoundsException("n >= size()");
+        }
+
+        try {
+            return values[n];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate exception.
+            throw new IndexOutOfBoundsException("n < 0");
+        }
+    }
+
+    /**
+     * Sets the value at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param value value to store
+     */
+    public void set(int n, int value) {
+        throwIfImmutable();
+
+        if (n >= size) {
+            throw new IndexOutOfBoundsException("n >= size()");
+        }
+
+        try {
+            values[n] = value;
+            sorted = false;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            if (n < 0) {
+                throw new IllegalArgumentException("n < 0");
+            }
+        }
+    }
+
+    /**
+     * Adds an element to the end of the list. This will increase the
+     * list's capacity if necessary.
+     *
+     * @param value the value to add
+     */
+    public void add(int value) {
+        throwIfImmutable();
+
+        growIfNeeded();
+
+        values[size++] = value;
+
+        if (sorted && (size > 1)) {
+            sorted = (value >= values[size - 2]);
+        }
+    }
+
+    /**
+     * Inserts element into specified index, moving elements at and above
+     * that index up one. May not be used to insert at an index beyond the
+     * current size (that is, insertion as a last element is legal but
+     * no further).
+     *
+     * @param n {@code >= 0, <=size();} index of where to insert
+     * @param value value to insert
+     */
+    public void insert(int n, int value) {
+        if (n > size) {
+            throw new IndexOutOfBoundsException("n > size()");
+        }
+
+        growIfNeeded();
+
+        System.arraycopy (values, n, values, n+1, size - n);
+        values[n] = value;
+        size++;
+
+        sorted = sorted
+                && (n == 0 || value > values[n-1])
+                && (n == (size - 1) || value < values[n+1]);
+    }
+
+    /**
+     * Removes an element at a given index, shifting elements at greater
+     * indicies down one.
+     *
+     * @param n  {@code >=0, < size();} index of element to remove
+     */
+    public void removeIndex(int n) {
+        if (n >= size) {
+            throw new IndexOutOfBoundsException("n >= size()");
+        }
+
+        System.arraycopy (values, n + 1, values, n, size - n - 1);
+        size--;
+
+        // sort status is unchanged
+    }
+
+    /**
+     * Increases size of array if needed
+     */
+    private void growIfNeeded() {
+        if (size == values.length) {
+            // Resize.
+            int[] newv = new int[size * 3 / 2 + 10];
+            System.arraycopy(values, 0, newv, 0, size);
+            values = newv;
+        }
+    }
+
+    /**
+     * Returns the last element in the array without modifying the array
+     *
+     * @return last value in the array.
+     * @exception IndexOutOfBoundsException if stack is empty.
+     */
+    public int top() {
+        return get(size - 1);
+    }
+
+    /**
+     * Pops an element off the end of the list and decreasing the size by one.
+     *
+     * @return value from what was the last element.
+     * @exception IndexOutOfBoundsException if stack is empty.
+     */
+    public int pop() {
+        throwIfImmutable();
+
+        int result;
+
+        result = get(size-1);
+        size--;
+
+        return result;
+    }
+
+    /**
+     * Pops N elements off the end of the list and decreasing the size by N.
+     *
+     * @param n {@code >= 0;} number of elements to remove from end.
+     * @exception IndexOutOfBoundsException if stack is smaller than N
+     */
+    public void pop(int n) {
+        throwIfImmutable();
+
+        size -= n;
+    }
+
+    /**
+     * Shrinks the size of the list.
+     *
+     * @param newSize {@code >= 0;} the new size
+     */
+    public void shrink(int newSize) {
+        if (newSize < 0) {
+            throw new IllegalArgumentException("newSize < 0");
+        }
+
+        if (newSize > size) {
+            throw new IllegalArgumentException("newSize > size");
+        }
+
+        throwIfImmutable();
+
+        size = newSize;
+    }
+
+    /**
+     * Makes and returns a mutable copy of the list.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public IntList mutableCopy() {
+        int sz = size;
+        IntList result = new IntList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            result.add(values[i]);
+        }
+
+        return result;
+    }
+
+    /**
+     * Sorts the elements in the list in-place.
+     */
+    public void sort() {
+        throwIfImmutable();
+
+        if (!sorted) {
+            Arrays.sort(values, 0, size);
+            sorted = true;
+        }
+    }
+
+    /**
+     * Returns the index of the given value, or -1 if the value does not
+     * appear in the list.  This will do a binary search if the list is
+     * sorted or a linear search if not.
+     * @param value value to find
+     * @return index of value or -1
+     */
+    public int indexOf(int value) {
+        int ret = binarysearch(value);
+
+        return ret >= 0 ? ret : -1;
+
+    }
+
+    /**
+     * Performs a binary search on a sorted list, returning the index of
+     * the given value if it is present or
+     * {@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()} if the element is not found.
+     *
+     * @param value value to find
+     * @return index of value or {@code (-(insertion point) - 1)} if the
+     * value is not present
+     */
+    public int binarysearch(int value) {
+        int sz = size;
+
+        if (!sorted) {
+            // Linear search.
+            for (int i = 0; i < sz; i++) {
+                if (values[i] == value) {
+                    return i;
+                }
+            }
+
+            return -sz;
+        }
+
+        /*
+         * Binary search. This variant does only one value comparison
+         * per iteration but does one more iteration on average than
+         * the variant that includes a value equality check per
+         * iteration.
+         */
+
+        int min = -1;
+        int max = sz;
+
+        while (max > (min + 1)) {
+            /*
+             * The guessIdx calculation is equivalent to ((min + max)
+             * / 2) but won't go wonky when min and max are close to
+             * Integer.MAX_VALUE.
+             */
+            int guessIdx = min + ((max - min) >> 1);
+            int guess = values[guessIdx];
+
+            if (value <= guess) {
+                max = guessIdx;
+            } else {
+                min = guessIdx;
+            }
+        }
+
+        if ((max != sz)) {
+            return (value == values[max]) ? max : (-max - 1);
+        } else {
+            return -sz - 1;
+        }
+    }
+
+
+    /**
+     * Returns whether or not the given value appears in the list.
+     * This will do a binary search if the list is sorted or a linear
+     * search if not.
+     *
+     * @see #sort
+     *
+     * @param value value to look for
+     * @return whether the list contains the given value
+     */
+    public boolean contains(int value) {
+        return indexOf(value) >= 0;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/IntSet.java b/dexgen/src/com/android/dexgen/util/IntSet.java
new file mode 100644
index 0000000..4de7525
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/IntSet.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * A set of integers
+ */
+public interface IntSet {
+
+    /**
+     * Adds an int to a set
+     *
+     * @param value int to add
+     */
+    void add(int value);
+
+    /**
+     * Removes an int from a set.
+     *
+     * @param value int to remove
+     */
+    void remove(int value);
+
+    /**
+     * Checks to see if a value is in the set
+     *
+     * @param value int to check
+     * @return true if in set
+     */
+    boolean has(int value);
+
+    /**
+     * Merges {@code other} into this set, so this set becomes the
+     * union of the two.
+     *
+     * @param other {@code non-null;} other set to merge with.
+     */
+    void merge(IntSet other);
+
+    /**
+     * Returns the count of unique elements in this set.
+     *
+     * @return {@code > = 0;} count of unique elements
+     */
+    int elements();
+
+    /**
+     * Iterates the set
+     *
+     * @return {@code non-null;} a set iterator
+     */
+    IntIterator iterator();
+}
diff --git a/dexgen/src/com/android/dexgen/util/LabeledItem.java b/dexgen/src/com/android/dexgen/util/LabeledItem.java
new file mode 100644
index 0000000..63cd067
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/LabeledItem.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * An item that has an integer label.
+ */
+public interface LabeledItem {
+
+    /*
+     * Gets the label of this block.
+     *
+     * @return {@code >= 0;} the label
+     */
+    public int getLabel();
+}
diff --git a/dexgen/src/com/android/dexgen/util/LabeledList.java b/dexgen/src/com/android/dexgen/util/LabeledList.java
new file mode 100644
index 0000000..a59e87d
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/LabeledList.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import com.android.dexgen.rop.ByteBlock;
+
+/**
+ * A list of labeled items, allowing easy lookup by label.
+ */
+public class LabeledList extends FixedSizeList {
+
+    /**
+     * Sparse array indexed by label to FixedSizeList index.
+     * -1 = invalid label.
+     */
+    private final IntList labelToIndex;
+
+    /** @inheritDoc */
+    public LabeledList(int size) {
+        super(size);
+
+        labelToIndex = new IntList(size);
+    }
+
+    /**
+     * Constructs a new instance that is a copy of the old instance.
+     *
+     * @param old instance to copy
+     */
+    protected LabeledList(LabeledList old) {
+        super(old.size());
+        labelToIndex = old.labelToIndex.mutableCopy();
+
+        int sz = old.size();
+
+        for (int i = 0; i < sz; i++) {
+            Object one = old.get0(i);
+            if (one != null) {
+                set0(i, one);
+            }
+        }
+    }
+
+    /**
+     * Gets the maximum label (exclusive) of any block added to this instance.
+     *
+     * @return {@code >= 0;} the maximum label
+     */
+    public int getMaxLabel() {
+        int sz = labelToIndex.size();
+
+        // Gobble any deleted labels that may be at the end...
+        int i;
+        for (i = sz - 1; (i >= 0) && (labelToIndex.get(i) < 0); i--)
+            ;
+
+        int newSize = i+1;
+
+        labelToIndex.shrink(newSize);
+
+        return newSize;
+    }
+
+    /**
+     * Removes a label from the label-to-index mapping
+     * @param oldLabel label to remove
+     */
+    protected void removeLabel(int oldLabel) {
+        labelToIndex.set(oldLabel, -1);
+    }
+
+    /**
+     * Adds a label and index to the label-to-index mapping
+     * @param label new label
+     * @param index index of block.
+     */
+    protected void addLabelIndex(int label, int index) {
+        int origSz = labelToIndex.size();
+
+        for (int i = 0; i <= (label - origSz); i++) {
+            labelToIndex.add(-1);
+        }
+
+        labelToIndex.set(label, index);
+    }
+
+    /**
+     * Gets the index of the first item in the list with the given
+     * label, if any.
+     *
+     * @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) {
+        if (label >= labelToIndex.size()) {
+            return -1;
+        } else {
+            return labelToIndex.get(label);
+        }
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void shrinkToFit() {
+        super.shrinkToFit();
+
+        rebuildLabelToIndex();
+    }
+
+    /**
+     * Rebuilds the label-to-index mapping after a shrinkToFit().
+     * Note: assumes that the labels that are in the list are the same
+     * although the indicies may have changed.
+     */
+    protected void rebuildLabelToIndex() {
+        int szItems = size();
+
+        for (int i = 0; i < szItems; i++) {
+            LabeledItem li = (LabeledItem)get0(i);
+
+            if (li != null) {
+                labelToIndex.set(li.getLabel(), i);
+            }
+        }
+    }
+
+    /**
+     * Sets the element at the given index.
+     *
+     * @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);
+
+        set0(n, item);
+
+        if (old != null) {
+            removeLabel(old.getLabel());
+        }
+
+        if (item != null) {
+            addLabelIndex(item.getLabel(), n);
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/Leb128Utils.java b/dexgen/src/com/android/dexgen/util/Leb128Utils.java
new file mode 100644
index 0000000..05b38e2
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/Leb128Utils.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * LEB128 (little-endian base 128) utilities.
+ */
+public final class Leb128Utils {
+    /**
+     * This class is uninstantiable.
+     */
+    private Leb128Utils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the number of bytes in the unsigned LEB128 encoding of the
+     * given value.
+     *
+     * @param value the value in question
+     * @return its write size, in bytes
+     */
+    public static int unsignedLeb128Size(int value) {
+        // TODO: This could be much cleverer.
+
+        int remaining = value >> 7;
+        int count = 0;
+
+        while (remaining != 0) {
+            remaining >>= 7;
+            count++;
+        }
+
+        return count + 1;
+    }
+
+    /**
+     * Gets the number of bytes in the signed LEB128 encoding of the
+     * given value.
+     *
+     * @param value the value in question
+     * @return its write size, in bytes
+     */
+    public static int signedLeb128Size(int value) {
+        // TODO: This could be much cleverer.
+
+        int remaining = value >> 7;
+        int count = 0;
+        boolean hasMore = true;
+        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
+
+        while (hasMore) {
+            hasMore = (remaining != end)
+                || ((remaining & 1) != ((value >> 6) & 1));
+
+            value = remaining;
+            remaining >>= 7;
+            count++;
+        }
+
+        return count;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/ListIntSet.java b/dexgen/src/com/android/dexgen/util/ListIntSet.java
new file mode 100644
index 0000000..b262ebb
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/ListIntSet.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.util.NoSuchElementException;
+
+/**
+ * A set of integers, represented by a list
+ */
+public class ListIntSet implements IntSet {
+
+    /** also accessed in BitIntSet */
+    final IntList ints;
+
+    /**
+     * Constructs an instance
+     */
+    public ListIntSet() {
+        ints = new IntList();
+        ints.sort();
+    }
+
+    /** @inheritDoc */
+    public void add(int value) {
+        int index = ints.binarysearch(value);
+
+        if (index < 0) {
+            ints.insert(-(index + 1), value);
+        }
+    }
+
+    /** @inheritDoc */
+    public void remove(int value) {
+        int index = ints.indexOf(value);
+
+        if (index >= 0) {
+            ints.removeIndex(index);
+        }
+    }
+
+    /** @inheritDoc */
+    public boolean has(int value) {
+        return ints.indexOf(value) >= 0;
+    }
+
+    /** @inheritDoc */
+    public void merge(IntSet other) {
+        if (other instanceof ListIntSet) {
+            ListIntSet o = (ListIntSet) other;
+            int szThis = ints.size();
+            int szOther = o.ints.size();
+
+            int i = 0;
+            int j = 0;
+
+            while (j < szOther && i < szThis) {
+                while (j < szOther && o.ints.get(j) < ints.get(i)) {
+                    add(o.ints.get(j++));
+                }
+                if (j == szOther) {
+                    break;
+                }
+                while (i < szThis && o.ints.get(j) >= ints.get(i)) {
+                    i++;
+                }
+            }
+
+            while (j < szOther) {
+                add(o.ints.get(j++));
+            }
+
+            ints.sort();
+        } else if (other instanceof BitIntSet) {
+            BitIntSet o = (BitIntSet) other;
+
+            for (int i = 0; i >= 0; i = Bits.findFirst(o.bits, i + 1)) {
+                ints.add(i);
+            }
+            ints.sort();
+        } else {
+            IntIterator iter = other.iterator();
+            while (iter.hasNext()) {
+                add(iter.next());
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    public int elements() {
+        return ints.size();
+    }
+
+    /** @inheritDoc */
+    public IntIterator iterator() {
+        return new IntIterator() {
+            private int idx = 0;
+
+            /** @inheritDoc */
+            public boolean hasNext() {
+                return idx < ints.size();
+            }
+
+            /** @inheritDoc */
+            public int next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                return ints.get(idx++);
+            }
+        };
+    }
+
+    /** @inheritDoc */
+    public String toString() {
+        return ints.toString();
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/MutabilityControl.java b/dexgen/src/com/android/dexgen/util/MutabilityControl.java
new file mode 100644
index 0000000..b3ee691
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/MutabilityControl.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Very simple base class that implements a flag to control the mutability
+ * of instances. This class just provides the flag and a utility to check
+ * and throw the right exception, but it is up to subclasses to place calls
+ * to the checker in all the right places.
+ */
+public class MutabilityControl {
+    /** whether this instance is mutable */
+    private boolean mutable;
+
+    /**
+     * Constructs an instance. It is initially mutable.
+     */
+    public MutabilityControl() {
+        mutable = true;
+    }
+
+    /**
+     * Constructs an instance, explicitly indicating the mutability.
+     *
+     * @param mutable {@code true} iff this instance is mutable
+     */
+    public MutabilityControl(boolean mutable) {
+        this.mutable = mutable;
+    }
+
+    /**
+     * Makes this instance immutable.
+     */
+    public void setImmutable() {
+        mutable = false;
+    }
+
+    /**
+     * Checks to see whether or not this instance is immutable. This is the
+     * same as calling {@code !isMutable()}.
+     *
+     * @return {@code true} iff this instance is immutable
+     */
+    public final boolean isImmutable() {
+        return !mutable;
+    }
+
+    /**
+     * Checks to see whether or not this instance is mutable.
+     *
+     * @return {@code true} iff this instance is mutable
+     */
+    public final boolean isMutable() {
+        return mutable;
+    }
+
+    /**
+     * Throws {@link MutabilityException} if this instance is
+     * immutable.
+     */
+    public final void throwIfImmutable() {
+        if (!mutable) {
+            throw new MutabilityException("immutable instance");
+        }
+    }
+
+    /**
+     * Throws {@link MutabilityException} if this instance is mutable.
+     */
+    public final void throwIfMutable() {
+        if (mutable) {
+            throw new MutabilityException("mutable instance");
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/MutabilityException.java b/dexgen/src/com/android/dexgen/util/MutabilityException.java
new file mode 100644
index 0000000..2188fe5
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/MutabilityException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Exception due to a mutability problem.
+ */
+public class MutabilityException
+        extends ExceptionWithContext {
+    public MutabilityException(String message) {
+        super(message);
+    }
+
+    public MutabilityException(Throwable cause) {
+        super(cause);
+    }
+
+    public MutabilityException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/Output.java b/dexgen/src/com/android/dexgen/util/Output.java
new file mode 100644
index 0000000..469c66a
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/Output.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Interface for a sink for binary output. This is similar to
+ * {@code java.util.DataOutput}, but no {@code IOExceptions}
+ * are declared, and multibyte output is defined to be little-endian.
+ */
+public interface Output {
+    /**
+     * Gets the current cursor position. This is the same as the number of
+     * bytes written to this instance.
+     *
+     * @return {@code >= 0;} the cursor position
+     */
+    public int getCursor();
+
+    /**
+     * Asserts that the cursor is the given value.
+     *
+     * @param expectedCursor the expected cursor value
+     * @throws RuntimeException thrown if {@code getCursor() !=
+     * expectedCursor}
+     */
+    public void assertCursor(int expectedCursor);
+
+    /**
+     * Writes a {@code byte} to this instance.
+     *
+     * @param value the value to write; all but the low 8 bits are ignored
+     */
+    public void writeByte(int value);
+
+    /**
+     * Writes a {@code short} to this instance.
+     *
+     * @param value the value to write; all but the low 16 bits are ignored
+     */
+    public void writeShort(int value);
+
+    /**
+     * Writes an {@code int} to this instance.
+     *
+     * @param value the value to write
+     */
+    public void writeInt(int value);
+
+    /**
+     * Writes a {@code long} to this instance.
+     *
+     * @param value the value to write
+     */
+    public void writeLong(long value);
+
+    /**
+     * Writes a DWARFv3-style unsigned LEB128 integer. For details,
+     * see the "Dalvik Executable Format" document or DWARF v3 section
+     * 7.6.
+     *
+     * @param value value to write, treated as an unsigned value
+     * @return {@code 1..5;} the number of bytes actually written
+     */
+    public int writeUnsignedLeb128(int value);
+
+    /**
+     * Writes a DWARFv3-style unsigned LEB128 integer. For details,
+     * see the "Dalvik Executable Format" document or DWARF v3 section
+     * 7.6.
+     *
+     * @param value value to write
+     * @return {@code 1..5;} the number of bytes actually written
+     */
+    public int writeSignedLeb128(int value);
+
+    /**
+     * Writes a {@link ByteArray} to this instance.
+     *
+     * @param bytes {@code non-null;} the array to write
+     */
+    public void write(ByteArray bytes);
+
+    /**
+     * Writes a portion of a {@code byte[]} to this instance.
+     *
+     * @param bytes {@code non-null;} the array to write
+     * @param offset {@code >= 0;} offset into {@code bytes} for the first
+     * byte to write
+     * @param length {@code >= 0;} number of bytes to write
+     */
+    public void write(byte[] bytes, int offset, int length);
+
+    /**
+     * Writes a {@code byte[]} to this instance. This is just
+     * a convenient shorthand for {@code write(bytes, 0, bytes.length)}.
+     *
+     * @param bytes {@code non-null;} the array to write
+     */
+    public void write(byte[] bytes);
+
+    /**
+     * Writes the given number of {@code 0} bytes.
+     *
+     * @param count {@code >= 0;} the number of zeroes to write
+     */
+    public void writeZeroes(int count);
+
+    /**
+     * Adds extra bytes if necessary (with value {@code 0}) to
+     * force alignment of the output cursor as given.
+     *
+     * @param alignment {@code > 0;} the alignment; must be a power of two
+     */
+    public void alignTo(int alignment);
+}
diff --git a/dexgen/src/com/android/dexgen/util/PathHolder.java b/dexgen/src/com/android/dexgen/util/PathHolder.java
new file mode 100644
index 0000000..b23ce66
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/PathHolder.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.File;
+
+/**
+ *  Helper class used primarily for holding path on the device of different
+ *  files arising in the dex class generation process.
+ */
+public class PathHolder {
+
+    public static final String DEX_FILE_EXTENSION = ".dex";
+
+    public static final String JAR_FILE_EXTENSION = ".jar";
+
+    /** {@code non-null;} directory location of the dex-related files */
+    private final String dirLocation;
+
+    /** {@code non-null;} common file name prefix of the created files */
+    private final String fileNamePrefix;
+
+    /**
+     * Creates an instance of {@code PathHolder} initialized with the directory
+     * location for storage of temporary files and common file name prefix for these
+     * files.
+     *
+     * @param dirLocation {@code non-null;} path to directory used for storage of temporary files
+     * @param fileNamePrefix {@code non-null;} common file name prefix across all the temporary
+     * files involved in the dex class generation and loading process
+     */
+    public PathHolder(String dirLocation, String fileNamePrefix) {
+        if (dirLocation == null) {
+            throw new NullPointerException("dirLocation == null");
+        }
+        if (fileNamePrefix == null) {
+            throw new NullPointerException("fileNamePrefix == null");
+        }
+
+        this.dirLocation = dirLocation;
+        this.fileNamePrefix = fileNamePrefix;
+    }
+
+    public String getFileName() {
+        return fileNamePrefix;
+    }
+
+    public String getDexFilePath() {
+        return dirLocation + File.separator + fileNamePrefix + DEX_FILE_EXTENSION;
+    }
+
+    public String getDexFileName() {
+        return fileNamePrefix + DEX_FILE_EXTENSION;
+    }
+
+    public String getJarFilePath() {
+        return dirLocation + File.separator + fileNamePrefix + JAR_FILE_EXTENSION;
+    }
+
+    public String getJarFileName() {
+        return fileNamePrefix + JAR_FILE_EXTENSION;
+    }
+
+    public String getDirLocation() {
+        return dirLocation;
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/ToHuman.java b/dexgen/src/com/android/dexgen/util/ToHuman.java
new file mode 100644
index 0000000..bbf044c
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/ToHuman.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Simple interface for objects that can return a "human" (as opposed to
+ * a complete but often hard to read) string form.
+ */
+public interface ToHuman {
+    /**
+     * Return the "human" string form of this instance.  This is
+     * generally less "debuggy" than {@code toString()}.
+     *
+     * @return {@code non-null;} the human string form
+     */
+    public String toHuman();
+}
diff --git a/dexgen/src/com/android/dexgen/util/TwoColumnOutput.java b/dexgen/src/com/android/dexgen/util/TwoColumnOutput.java
new file mode 100644
index 0000000..17a4c42
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/TwoColumnOutput.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+
+/**
+ * Class that takes a combined output destination and provides two
+ * output writers, one of which ends up writing to the left column and
+ * one which goes on the right.
+ */
+public final class TwoColumnOutput {
+    /** {@code non-null;} underlying writer for final output */
+    private final Writer out;
+
+    /** {@code > 0;} the left column width */
+    private final int leftWidth;
+
+    /** {@code non-null;} pending left column output */
+    private final StringBuffer leftBuf;
+
+    /** {@code non-null;} pending right column output */
+    private final StringBuffer rightBuf;
+
+    /** {@code non-null;} left column writer */
+    private final IndentingWriter leftColumn;
+
+    /** {@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 {@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) {
+        int len1 = s1.length();
+        int len2 = s2.length();
+
+        StringWriter sw = new StringWriter((len1 + len2) * 3);
+        TwoColumnOutput twoOut =
+            new TwoColumnOutput(sw, width1, width2, spacer);
+
+        try {
+            twoOut.getLeft().write(s1);
+            twoOut.getRight().write(s2);
+        } catch (IOException ex) {
+            throw new RuntimeException("shouldn't happen", ex);
+        }
+
+        twoOut.flush();
+        return sw.toString();
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param out {@code non-null;} writer to send final output to
+     * @param leftWidth {@code > 0;} width of the left column, in characters
+     * @param rightWidth {@code > 0;} width of the right column, in characters
+     * @param spacer {@code non-null;} spacer string to sit between the two columns
+     */
+    public TwoColumnOutput(Writer out, int leftWidth, int rightWidth,
+                           String spacer) {
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        }
+
+        if (leftWidth < 1) {
+            throw new IllegalArgumentException("leftWidth < 1");
+        }
+
+        if (rightWidth < 1) {
+            throw new IllegalArgumentException("rightWidth < 1");
+        }
+
+        if (spacer == null) {
+            throw new NullPointerException("spacer == null");
+        }
+
+        StringWriter leftWriter = new StringWriter(1000);
+        StringWriter rightWriter = new StringWriter(1000);
+
+        this.out = out;
+        this.leftWidth = leftWidth;
+        this.leftBuf = leftWriter.getBuffer();
+        this.rightBuf = rightWriter.getBuffer();
+        this.leftColumn = new IndentingWriter(leftWriter, leftWidth);
+        this.rightColumn =
+            new IndentingWriter(rightWriter, rightWidth, spacer);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param out {@code non-null;} stream to send final output to
+     * @param leftWidth {@code >= 1;} width of the left column, in characters
+     * @param rightWidth {@code >= 1;} width of the right column, in characters
+     * @param spacer {@code non-null;} spacer string to sit between the two columns
+     */
+    public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth,
+                           String spacer) {
+        this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer);
+    }
+
+    /**
+     * Gets the writer to use to write to the left column.
+     *
+     * @return {@code non-null;} the left column writer
+     */
+    public Writer getLeft() {
+        return leftColumn;
+    }
+
+    /**
+     * Gets the writer to use to write to the right column.
+     *
+     * @return {@code non-null;} the right column writer
+     */
+    public Writer getRight() {
+        return rightColumn;
+    }
+
+    /**
+     * Flushes the output. If there are more lines of pending output in one
+     * column, then the other column will get filled with blank lines.
+     */
+    public void flush() {
+        try {
+            appendNewlineIfNecessary(leftBuf, leftColumn);
+            appendNewlineIfNecessary(rightBuf, rightColumn);
+            outputFullLines();
+            flushLeft();
+            flushRight();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Outputs to the final destination as many full line pairs as
+     * there are in the pending output, removing those lines from
+     * their respective buffers. This method terminates when at
+     * least one of the two column buffers is empty.
+     */
+    private void outputFullLines() throws IOException {
+        for (;;) {
+            int leftLen = leftBuf.indexOf("\n");
+            if (leftLen < 0) {
+                return;
+            }
+
+            int rightLen = rightBuf.indexOf("\n");
+            if (rightLen < 0) {
+                return;
+            }
+
+            if (leftLen != 0) {
+                out.write(leftBuf.substring(0, leftLen));
+            }
+
+            if (rightLen != 0) {
+                writeSpaces(out, leftWidth - leftLen);
+                out.write(rightBuf.substring(0, rightLen));
+            }
+
+            out.write('\n');
+
+            leftBuf.delete(0, leftLen + 1);
+            rightBuf.delete(0, rightLen + 1);
+        }
+    }
+
+    /**
+     * Flushes the left column buffer, printing it and clearing the buffer.
+     * If the buffer is already empty, this does nothing.
+     */
+    private void flushLeft() throws IOException {
+        appendNewlineIfNecessary(leftBuf, leftColumn);
+
+        while (leftBuf.length() != 0) {
+            rightColumn.write('\n');
+            outputFullLines();
+        }
+    }
+
+    /**
+     * Flushes the right column buffer, printing it and clearing the buffer.
+     * If the buffer is already empty, this does nothing.
+     */
+    private void flushRight() throws IOException {
+        appendNewlineIfNecessary(rightBuf, rightColumn);
+
+        while (rightBuf.length() != 0) {
+            leftColumn.write('\n');
+            outputFullLines();
+        }
+    }
+
+    /**
+     * Appends a newline to the given buffer via the given writer, but
+     * only if it isn't empty and doesn't already end with one.
+     *
+     * @param buf {@code non-null;} the buffer in question
+     * @param out {@code non-null;} the writer to use
+     */
+    private static void appendNewlineIfNecessary(StringBuffer buf,
+                                                 Writer out)
+            throws IOException {
+        int len = buf.length();
+
+        if ((len != 0) && (buf.charAt(len - 1) != '\n')) {
+            out.write('\n');
+        }
+    }
+
+    /**
+     * Writes the given number of spaces to the given writer.
+     *
+     * @param out {@code non-null;} where to write
+     * @param amt {@code >= 0;} the number of spaces to write
+     */
+    private static void writeSpaces(Writer out, int amt) throws IOException {
+        while (amt > 0) {
+            out.write(' ');
+            amt--;
+        }
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/Warning.java b/dexgen/src/com/android/dexgen/util/Warning.java
new file mode 100644
index 0000000..204d877
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/Warning.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Exception which is meant to indicate a non-fatal warning.
+ */
+public class Warning extends RuntimeException {
+    /**
+     * Constructs an instance.
+     *
+     * @param message human-oriented message
+     */
+    public Warning(String message) {
+        super(message);
+    }
+}
diff --git a/dexgen/src/com/android/dexgen/util/Writers.java b/dexgen/src/com/android/dexgen/util/Writers.java
new file mode 100644
index 0000000..046967e
--- /dev/null
+++ b/dexgen/src/com/android/dexgen/util/Writers.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Utilities for dealing with {@code Writer}s.
+ */
+public final class Writers {
+    /**
+     * This class is uninstantiable.
+     */
+    private Writers() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Makes a {@code PrintWriter} for the given {@code Writer},
+     * returning the given writer if it already happens to be the right
+     * class.
+     *
+     * @param writer {@code non-null;} writer to (possibly) wrap
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static PrintWriter printWriterFor(Writer writer) {
+        if (writer instanceof PrintWriter) {
+            return (PrintWriter) writer;
+        }
+
+        return new PrintWriter(writer);
+    }
+}
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
new file mode 100644
index 0000000..55602dd
--- /dev/null
+++ b/dexlist/Android.mk
@@ -0,0 +1,50 @@
+# 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.
+
+#
+# dexlist -- list all concrete methods found in a DEX file
+#
+LOCAL_PATH:= $(call my-dir)
+
+dexdump_src_files := \
+		DexList.cpp
+
+dexdump_c_includes := \
+		dalvik \
+		$(JNI_H_INCLUDE)
+
+dexdump_shared_libraries :=
+
+dexdump_static_libraries := \
+		libdex
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexlist
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries) libcutils libz
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries)
+LOCAL_LDLIBS +=
+#include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dexlist
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries)
+LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) libcutils
+LOCAL_LDLIBS += -lpthread -lz
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/DexList.cpp b/dexlist/DexList.cpp
new file mode 100644
index 0000000..03f0230
--- /dev/null
+++ b/dexlist/DexList.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ */
+
+/*
+ * List all methods in all concrete classes in one or more DEX files.
+ */
+
+#include "libdex/DexFile.h"
+
+#include "libdex/CmdUtils.h"
+#include "libdex/DexClass.h"
+#include "libdex/DexDebugInfo.h"
+#include "libdex/DexProto.h"
+#include "libdex/SysUtil.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+
+static const char* gProgName = "dexlist";
+
+/* command-line args */
+static struct {
+    char*       argCopy;
+    const char* classToFind;
+    const char* methodToFind;
+} gParms;
+
+
+/*
+ * Return a newly-allocated string for the "dot version" of the class
+ * name for the given type descriptor. That is, The initial "L" and
+ * final ";" (if any) have been removed and all occurrences of '/'
+ * have been changed to '.'.
+ */
+static char* descriptorToDot(const char* str)
+{
+    size_t at = strlen(str);
+    char* newStr;
+
+    if (str[0] == 'L') {
+        assert(str[at - 1] == ';');
+        at -= 2; /* Two fewer chars to copy. */
+        str++; /* Skip the 'L'. */
+    }
+
+    newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */
+    newStr[at] = '\0';
+
+    while (at > 0) {
+        at--;
+        newStr[at] = (str[at] == '/') ? '.' : str[at];
+    }
+
+    return newStr;
+}
+
+/*
+ * Position table callback; we just want to catch the number of the
+ * first line in the method, which *should* correspond to the first
+ * entry from the table.  (Could also use "min" here.)
+ */
+static int positionsCallback(void* cnxt, u4 address, u4 lineNum)
+{
+    int* pFirstLine = (int*) cnxt;
+    if (*pFirstLine == -1)
+        *pFirstLine = lineNum;
+    return 0;
+}
+
+
+/*
+ * Dump a method.
+ */
+void dumpMethod(DexFile* pDexFile, const char* fileName,
+    const DexMethod* pDexMethod, int i)
+{
+    const DexMethodId* pMethodId;
+    const DexCode* pCode;
+    const char* classDescriptor;
+    const char* methodName;
+    int firstLine;
+
+    /* abstract and native methods don't get listed */
+    if (pDexMethod->codeOff == 0)
+        return;
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+    methodName = dexStringById(pDexFile, pMethodId->nameIdx);
+
+    classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+    pCode = dexGetCode(pDexFile, pDexMethod);
+    assert(pCode != NULL);
+
+    /*
+     * If the filename is empty, then set it to something printable
+     * so that it is easier to parse.
+     *
+     * TODO: A method may override its class's default source file by
+     * specifying a different one in its debug info. This possibility
+     * should be handled here.
+     */
+    if (fileName == NULL || fileName[0] == 0) {
+        fileName = "(none)";
+    }
+
+    firstLine = -1;
+    dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
+        pDexMethod->accessFlags, positionsCallback, NULL, &firstLine);
+
+    char* className = descriptorToDot(classDescriptor);
+    char* desc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+    u4 insnsOff = pDexMethod->codeOff + offsetof(DexCode, insns);
+
+    if (gParms.methodToFind != NULL &&
+        (strcmp(gParms.classToFind, className) != 0 ||
+         strcmp(gParms.methodToFind, methodName) != 0))
+    {
+        goto skip;
+    }
+
+    printf("0x%08x %d %s %s %s %s %d\n",
+        insnsOff, pCode->insnsSize * 2,
+        className, methodName, desc,
+        fileName, firstLine);
+
+skip:
+    free(desc);
+    free(className);
+}
+
+/*
+ * Run through all direct and virtual methods in the class.
+ */
+void dumpClass(DexFile* pDexFile, int idx)
+{
+    const DexClassDef* pClassDef;
+    DexClassData* pClassData;
+    const u1* pEncodedData;
+    const char* fileName;
+    int i;
+
+    pClassDef = dexGetClassDef(pDexFile, idx);
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+    pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+
+    if (pClassData == NULL) {
+        fprintf(stderr, "Trouble reading class data\n");
+        return;
+    }
+
+    if (pClassDef->sourceFileIdx == 0xffffffff) {
+        fileName = NULL;
+    } else {
+        fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
+    }
+
+    /*
+     * TODO: Each class def points at a sourceFile, so maybe that
+     * should be printed out. However, this needs to be coordinated
+     * with the tools that parse this output.
+     */
+
+    for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+        dumpMethod(pDexFile, fileName, &pClassData->directMethods[i], i);
+    }
+
+    for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
+        dumpMethod(pDexFile, fileName, &pClassData->virtualMethods[i], i);
+    }
+
+    free(pClassData);
+}
+
+/*
+ * Process a file.
+ *
+ * Returns 0 on success.
+ */
+int process(const char* fileName)
+{
+    DexFile* pDexFile = NULL;
+    MemMapping map;
+    bool mapped = false;
+    int result = -1;
+    UnzipToFileResult utfr;
+
+    utfr = dexOpenAndMap(fileName, NULL, &map, true);
+    if (utfr != kUTFRSuccess) {
+        if (utfr == kUTFRNoClassesDex) {
+            /* no classes.dex in the APK; pretend we succeeded */
+            result = 0;
+            goto bail;
+        }
+        fprintf(stderr, "Unable to process '%s'\n", fileName);
+        goto bail;
+    }
+    mapped = true;
+
+    pDexFile = dexFileParse((u1*)map.addr, map.length, kDexParseDefault);
+    if (pDexFile == NULL) {
+        fprintf(stderr, "Warning: DEX parse failed for '%s'\n", fileName);
+        goto bail;
+    }
+
+    printf("#%s\n", fileName);
+
+    int i;
+    for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
+        dumpClass(pDexFile, i);
+    }
+
+    result = 0;
+
+bail:
+    if (mapped)
+        sysReleaseShmem(&map);
+    if (pDexFile != NULL)
+        dexFileFree(pDexFile);
+    return result;
+}
+
+
+/*
+ * Show usage.
+ */
+void usage(void)
+{
+    fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+    fprintf(stderr, "%s: dexfile [dexfile2 ...]\n", gProgName);
+    fprintf(stderr, "\n");
+}
+
+/*
+ * Parse args.
+ */
+int main(int argc, char* const argv[])
+{
+    int result = 0;
+    int i;
+
+    /*
+     * Find all instances of the fully-qualified method name.  This isn't
+     * really what dexlist is for, but it's easy to do it here.
+     */
+    if (argc > 3 && strcmp(argv[1], "--method") == 0) {
+        gParms.argCopy = strdup(argv[2]);
+        char* meth = strrchr(gParms.argCopy, '.');
+        if (meth == NULL) {
+            fprintf(stderr, "Expected package.Class.method\n");
+            free(gParms.argCopy);
+            return 2;
+        }
+        *meth = '\0';
+        gParms.classToFind = gParms.argCopy;
+        gParms.methodToFind = meth+1;
+        argv += 2;
+        argc -= 2;
+    }
+
+    if (argc < 2) {
+        fprintf(stderr, "%s: no file specified\n", gProgName);
+        usage();
+        return 2;
+    }
+
+    /*
+     * Run through the list of files.  If one of them fails we contine on,
+     * only returning a failure at the end.
+     */
+    for (i = 1; i < argc; i++)
+        result |= process(argv[i]);
+
+    free(gParms.argCopy);
+    return result;
+}
diff --git a/dexopt/Android.mk b/dexopt/Android.mk
new file mode 100644
index 0000000..d4831d1
--- /dev/null
+++ b/dexopt/Android.mk
@@ -0,0 +1,66 @@
+# 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.
+
+#
+# dexopt, the DEX file optimizer.  This is fully integrated with the VM,
+# so it must be linked against the full VM shared library.
+#
+LOCAL_PATH:= $(call my-dir)
+
+local_src_files := \
+		OptMain.cpp
+
+local_c_includes := \
+		dalvik \
+		dalvik/libdex \
+		dalvik/vm \
+		$(JNI_H_INCLUDE)
+
+local_shared_libraries := \
+		libssl \
+		libdvm \
+		libcrypto \
+		libicuuc \
+		libicui18n
+
+include $(CLEAR_VARS)
+ifeq ($(TARGET_CPU_SMP),true)
+    LOCAL_CFLAGS += -DANDROID_SMP=1
+else
+    LOCAL_CFLAGS += -DANDROID_SMP=0
+endif
+
+LOCAL_SRC_FILES := $(local_src_files)
+LOCAL_C_INCLUDES := $(local_c_includes)
+LOCAL_SHARED_LIBRARIES := $(local_shared_libraries) libcutils libexpat liblog libnativehelper libz
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := dexopt
+
+LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
+LOCAL_SHARED_LIBRARIES += libstlport
+
+include $(BUILD_EXECUTABLE)
+
+ifeq ($(WITH_HOST_DALVIK),true)
+    include $(CLEAR_VARS)
+    LOCAL_SRC_FILES := $(local_src_files)
+    LOCAL_C_INCLUDES := $(local_c_includes)
+    LOCAL_SHARED_LIBRARIES := $(local_shared_libraries)
+    LOCAL_STATIC_LIBRARIES :=  libcutils libexpat liblog libnativehelper libz
+    LOCAL_LDLIBS += -ldl -lpthread
+    LOCAL_CFLAGS += -DANDROID_SMP=1
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_MODULE := dexopt
+    include $(BUILD_HOST_EXECUTABLE)
+endif
diff --git a/dexopt/OptMain.cpp b/dexopt/OptMain.cpp
new file mode 100644
index 0000000..e59d674
--- /dev/null
+++ b/dexopt/OptMain.cpp
@@ -0,0 +1,579 @@
+/*
+ * 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.
+ */
+
+/*
+ * Command-line DEX optimization and verification entry point.
+ *
+ * There are three ways to launch this:
+ * (1) From the VM.  This takes a dozen args, one of which is a file
+ *     descriptor that acts as both input and output.  This allows us to
+ *     remain ignorant of where the DEX data originally came from.
+ * (2) From installd or another native application.  Pass in a file
+ *     descriptor for a zip file, a file descriptor for the output, and
+ *     a filename for debug messages.  Many assumptions are made about
+ *     what's going on (verification + optimization are enabled, boot
+ *     class path is in BOOTCLASSPATH, etc).
+ * (3) On the host during a build for preoptimization. This behaves
+ *     almost the same as (2), except it takes file names instead of
+ *     file descriptors.
+ *
+ * There are some fragile aspects around bootclasspath entries, owing
+ * largely to the VM's history of working on whenever it thought it needed
+ * instead of strictly doing what it was told.  If optimizing bootclasspath
+ * entries, always do them in the order in which they appear in the path.
+ */
+#include "Dalvik.h"
+#include "libdex/OptInvocation.h"
+
+#include "cutils/log.h"
+#include "cutils/process_name.h"
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char* kClassesDex = "classes.dex";
+
+
+/*
+ * Extract "classes.dex" from zipFd into "cacheFd", leaving a little space
+ * up front for the DEX optimization header.
+ */
+static int extractAndProcessZip(int zipFd, int cacheFd,
+    const char* debugFileName, bool isBootstrap, const char* bootClassPath,
+    const char* dexoptFlagStr)
+{
+    ZipArchive zippy;
+    ZipEntry zipEntry;
+    size_t uncompLen;
+    long modWhen, crc32;
+    off_t dexOffset;
+    int err;
+    int result = -1;
+    int dexoptFlags = 0;        /* bit flags, from enum DexoptFlags */
+    DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
+    DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
+
+    memset(&zippy, 0, sizeof(zippy));
+
+    /* make sure we're still at the start of an empty file */
+    if (lseek(cacheFd, 0, SEEK_END) != 0) {
+        LOGE("DexOptZ: new cache file '%s' is not empty", debugFileName);
+        goto bail;
+    }
+
+    /*
+     * Write a skeletal DEX optimization header.  We want the classes.dex
+     * to come just after it.
+     */
+    err = dexOptCreateEmptyHeader(cacheFd);
+    if (err != 0)
+        goto bail;
+
+    /* record the file position so we can get back here later */
+    dexOffset = lseek(cacheFd, 0, SEEK_CUR);
+    if (dexOffset < 0)
+        goto bail;
+
+    /*
+     * Open the zip archive, find the DEX entry.
+     */
+    if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
+        LOGW("DexOptZ: unable to open zip archive '%s'", debugFileName);
+        goto bail;
+    }
+
+    zipEntry = dexZipFindEntry(&zippy, kClassesDex);
+    if (zipEntry == NULL) {
+        LOGW("DexOptZ: zip archive '%s' does not include %s",
+            debugFileName, kClassesDex);
+        goto bail;
+    }
+
+    /*
+     * Extract some info about the zip entry.
+     */
+    if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
+            &modWhen, &crc32) != 0)
+    {
+        LOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName);
+        goto bail;
+    }
+
+    uncompLen = uncompLen;
+    modWhen = modWhen;
+    crc32 = crc32;
+
+    /*
+     * Extract the DEX data into the cache file at the current offset.
+     */
+    if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
+        LOGW("DexOptZ: extraction of %s from %s failed",
+            kClassesDex, debugFileName);
+        goto bail;
+    }
+
+    /* Parse the options. */
+    if (dexoptFlagStr[0] != '\0') {
+        const char* opc;
+        const char* val;
+
+        opc = strstr(dexoptFlagStr, "v=");      /* verification */
+        if (opc != NULL) {
+            switch (*(opc+2)) {
+            case 'n':   verifyMode = VERIFY_MODE_NONE;          break;
+            case 'r':   verifyMode = VERIFY_MODE_REMOTE;        break;
+            case 'a':   verifyMode = VERIFY_MODE_ALL;           break;
+            default:                                            break;
+            }
+        }
+
+        opc = strstr(dexoptFlagStr, "o=");      /* optimization */
+        if (opc != NULL) {
+            switch (*(opc+2)) {
+            case 'n':   dexOptMode = OPTIMIZE_MODE_NONE;        break;
+            case 'v':   dexOptMode = OPTIMIZE_MODE_VERIFIED;    break;
+            case 'a':   dexOptMode = OPTIMIZE_MODE_ALL;         break;
+            case 'f':   dexOptMode = OPTIMIZE_MODE_FULL;        break;
+            default:                                            break;
+            }
+        }
+
+        opc = strstr(dexoptFlagStr, "m=y");     /* register map */
+        if (opc != NULL) {
+            dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
+        }
+
+        opc = strstr(dexoptFlagStr, "u=");      /* uniprocessor target */
+        if (opc != NULL) {
+            switch (*(opc+2)) {
+            case 'y':   dexoptFlags |= DEXOPT_UNIPROCESSOR;     break;
+            case 'n':   dexoptFlags |= DEXOPT_SMP;              break;
+            default:                                            break;
+            }
+        }
+    }
+
+    /*
+     * Prep the VM and perform the optimization.
+     */
+
+    if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
+            dexoptFlags) != 0)
+    {
+        LOGE("DexOptZ: VM init failed");
+        goto bail;
+    }
+
+    //vmStarted = 1;
+
+    /* do the optimization */
+    if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
+            modWhen, crc32, isBootstrap))
+    {
+        LOGE("Optimization failed");
+        goto bail;
+    }
+
+    /* we don't shut the VM down -- process is about to exit */
+
+    result = 0;
+
+bail:
+    dexZipCloseArchive(&zippy);
+    return result;
+}
+
+/*
+ * Common functionality for normal device-side processing as well as
+ * preoptimization.
+ */
+static int processZipFile(int zipFd, int cacheFd, const char* zipName,
+        const char *dexoptFlags)
+{
+    char* bcpCopy = NULL;
+
+    /*
+     * Check to see if this is a bootstrap class entry. If so, truncate
+     * the path.
+     */
+    const char* bcp = getenv("BOOTCLASSPATH");
+    if (bcp == NULL) {
+        LOGE("DexOptZ: BOOTCLASSPATH not set");
+        return -1;
+    }
+
+    bool isBootstrap = false;
+    const char* match = strstr(bcp, zipName);
+    if (match != NULL) {
+        /*
+         * TODO: we have a partial string match, but that doesn't mean
+         * we've matched an entire path component. We should make sure
+         * that we're matching on the full zipName, and if not we
+         * should re-do the strstr starting at (match+1).
+         *
+         * The scenario would be a bootclasspath with something like
+         * "/system/framework/core.jar" while we're trying to optimize
+         * "/framework/core.jar". Not very likely since all paths are
+         * absolute and end with ".jar", but not impossible.
+         */
+        int matchOffset = match - bcp;
+        if (matchOffset > 0 && bcp[matchOffset-1] == ':')
+            matchOffset--;
+        LOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d",
+            zipName, matchOffset);
+        bcpCopy = strdup(bcp);
+        bcpCopy[matchOffset] = '\0';
+
+        bcp = bcpCopy;
+        LOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'", bcp);
+        isBootstrap = true;
+    }
+
+    int result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,
+            bcp, dexoptFlags);
+
+    free(bcpCopy);
+    return result;
+}
+
+/* advance to the next arg and extract it */
+#define GET_ARG(_var, _func, _msg)                                          \
+    {                                                                       \
+        char* endp;                                                         \
+        (_var) = _func(*++argv, &endp, 0);                                  \
+        if (*endp != '\0') {                                                \
+            LOGE("%s '%s'", _msg, *argv);                                   \
+            goto bail;                                                      \
+        }                                                                   \
+        --argc;                                                             \
+    }
+
+/*
+ * Parse arguments.  We want:
+ *   0. (name of dexopt command -- ignored)
+ *   1. "--zip"
+ *   2. zip fd (input, read-only)
+ *   3. cache fd (output, read-write, locked with flock)
+ *   4. filename of zipfile being optimized (used for debug messages and
+ *      for comparing against BOOTCLASSPATH; does not need to be
+ *      accessible or even exist)
+ *   5. dexopt flags
+ *
+ * The BOOTCLASSPATH environment variable is assumed to hold the correct
+ * boot class path.  If the filename provided appears in the boot class
+ * path, the path will be truncated just before that entry (so that, if
+ * you were to dexopt "core.jar", your bootclasspath would be empty).
+ *
+ * This does not try to normalize the boot class path name, so the
+ * filename test won't catch you if you get creative.
+ */
+static int fromZip(int argc, char* const argv[])
+{
+    int result = -1;
+    int zipFd, cacheFd;
+    const char* zipName;
+    char* bcpCopy = NULL;
+    const char* dexoptFlags;
+
+    if (argc != 6) {
+        LOGE("Wrong number of args for --zip (found %d)", argc);
+        goto bail;
+    }
+
+    /* skip "--zip" */
+    argc--;
+    argv++;
+
+    GET_ARG(zipFd, strtol, "bad zip fd");
+    GET_ARG(cacheFd, strtol, "bad cache fd");
+    zipName = *++argv;
+    --argc;
+    dexoptFlags = *++argv;
+    --argc;
+
+    result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);
+
+bail:
+    return result;
+}
+
+/*
+ * Parse arguments for a preoptimization run. This is when dalvikvm is run
+ * on a host to optimize dex files for eventual running on a (different)
+ * device. We want:
+ *   0. (name of dexopt command -- ignored)
+ *   1. "--preopt"
+ *   2. zipfile name
+ *   3. output file name
+ *   4. dexopt flags
+ *
+ * The BOOTCLASSPATH environment variable is assumed to hold the correct
+ * boot class path.  If the filename provided appears in the boot class
+ * path, the path will be truncated just before that entry (so that, if
+ * you were to dexopt "core.jar", your bootclasspath would be empty).
+ *
+ * This does not try to normalize the boot class path name, so the
+ * filename test won't catch you if you get creative.
+ */
+static int preopt(int argc, char* const argv[])
+{
+    int zipFd = -1;
+    int outFd = -1;
+    int result = -1;
+
+    if (argc != 5) {
+        /*
+         * Use stderr here, since this variant is meant to be called on
+         * the host side.
+         */
+        fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",
+                argc);
+        return -1;
+    }
+
+    const char* zipName = argv[2];
+    const char* outName = argv[3];
+    const char* dexoptFlags = argv[4];
+
+    if (strstr(dexoptFlags, "u=y") == NULL &&
+        strstr(dexoptFlags, "u=n") == NULL)
+    {
+        fprintf(stderr, "Either 'u=y' or 'u=n' must be specified\n");
+        return -1;
+    }
+
+    zipFd = open(zipName, O_RDONLY);
+    if (zipFd < 0) {
+        perror(argv[0]);
+        return -1;
+    }
+
+    outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);
+    if (outFd < 0) {
+        perror(argv[0]);
+        goto bail;
+    }
+
+    result = processZipFile(zipFd, outFd, zipName, dexoptFlags);
+
+bail:
+    if (zipFd >= 0) {
+        close(zipFd);
+    }
+
+    if (outFd >= 0) {
+        close(outFd);
+    }
+
+    return result;
+}
+
+/*
+ * Parse arguments for an "old-style" invocation directly from the VM.
+ *
+ * Here's what we want:
+ *   0. (name of dexopt command -- ignored)
+ *   1. "--dex"
+ *   2. DALVIK_VM_BUILD value, as a sanity check
+ *   3. file descriptor, locked with flock, for DEX file being optimized
+ *   4. DEX offset within file
+ *   5. DEX length
+ *   6. filename of file being optimized (for debug messages only)
+ *   7. modification date of source (goes into dependency section)
+ *   8. CRC of source (goes into dependency section)
+ *   9. flags (optimization level, isBootstrap)
+ *  10. bootclasspath entry #1
+ *  11. bootclasspath entry #2
+ *   ...
+ *
+ * dvmOptimizeDexFile() in dalvik/vm/analysis/DexOptimize.c builds the
+ * argument list and calls this executable.
+ *
+ * The bootclasspath entries become the dependencies for this DEX file.
+ *
+ * The open file descriptor MUST NOT be for one of the bootclasspath files.
+ * The parent has the descriptor locked, and we'll try to lock it again as
+ * part of processing the bootclasspath.  (We can catch this and return
+ * an error by comparing filenames or by opening the bootclasspath files
+ * and stat()ing them for inode numbers).
+ */
+static int fromDex(int argc, char* const argv[])
+{
+    int result = -1;
+    bool vmStarted = false;
+    char* bootClassPath = NULL;
+    int fd, flags, vmBuildVersion;
+    long offset, length;
+    const char* debugFileName;
+    u4 crc, modWhen;
+    char* endp;
+    bool onlyOptVerifiedDex = false;
+    DexClassVerifyMode verifyMode;
+    DexOptimizerMode dexOptMode;
+
+    if (argc < 10) {
+        /* don't have all mandatory args */
+        LOGE("Not enough arguments for --dex (found %d)", argc);
+        goto bail;
+    }
+
+    /* skip "--dex" */
+    argc--;
+    argv++;
+
+    /*
+     * Extract the args.
+     */
+    GET_ARG(vmBuildVersion, strtol, "bad vm build");
+    if (vmBuildVersion != DALVIK_VM_BUILD) {
+        LOGE("DexOpt: build rev does not match VM: %d vs %d",
+            vmBuildVersion, DALVIK_VM_BUILD);
+        goto bail;
+    }
+    GET_ARG(fd, strtol, "bad fd");
+    GET_ARG(offset, strtol, "bad offset");
+    GET_ARG(length, strtol, "bad length");
+    debugFileName = *++argv;
+    --argc;
+    GET_ARG(modWhen, strtoul, "bad modWhen");
+    GET_ARG(crc, strtoul, "bad crc");
+    GET_ARG(flags, strtol, "bad flags");
+
+    LOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=%#x crc=%#x flg=%d (argc=%d)",
+        fd, offset, length, debugFileName, modWhen, crc, flags, argc);
+    assert(argc > 0);
+
+    if (--argc == 0) {
+        bootClassPath = strdup("");
+    } else {
+        int i, bcpLen;
+        char* const* argp;
+        char* cp;
+
+        bcpLen = 0;
+        for (i = 0, argp = argv; i < argc; i++) {
+            ++argp;
+            LOGV("DEP: '%s'", *argp);
+            bcpLen += strlen(*argp) + 1;
+        }
+
+        cp = bootClassPath = (char*) malloc(bcpLen +1);
+        for (i = 0, argp = argv; i < argc; i++) {
+            int strLen;
+
+            ++argp;
+            strLen = strlen(*argp);
+            if (i != 0)
+                *cp++ = ':';
+            memcpy(cp, *argp, strLen);
+            cp += strLen;
+        }
+        *cp = '\0';
+
+        assert((int) strlen(bootClassPath) == bcpLen-1);
+    }
+    LOGV("  bootclasspath is '%s'", bootClassPath);
+
+    /* start the VM partway */
+
+    /* ugh -- upgrade these to a bit field if they get any more complex */
+    if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
+        if ((flags & DEXOPT_VERIFY_ALL) != 0)
+            verifyMode = VERIFY_MODE_ALL;
+        else
+            verifyMode = VERIFY_MODE_REMOTE;
+    } else {
+        verifyMode = VERIFY_MODE_NONE;
+    }
+    if ((flags & DEXOPT_OPT_ENABLED) != 0) {
+        if ((flags & DEXOPT_OPT_ALL) != 0)
+            dexOptMode = OPTIMIZE_MODE_ALL;
+        else
+            dexOptMode = OPTIMIZE_MODE_VERIFIED;
+    } else {
+        dexOptMode = OPTIMIZE_MODE_NONE;
+    }
+
+    if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
+        LOGE("VM init failed");
+        goto bail;
+    }
+
+    vmStarted = true;
+
+    /* do the optimization */
+    if (!dvmContinueOptimization(fd, offset, length, debugFileName,
+            modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
+    {
+        LOGE("Optimization failed");
+        goto bail;
+    }
+
+    result = 0;
+
+bail:
+    /*
+     * In theory we should gracefully shut the VM down at this point.  In
+     * practice that only matters if we're checking for memory leaks with
+     * valgrind -- simply exiting is much faster.
+     *
+     * As it turns out, the DEX optimizer plays a little fast and loose
+     * with class loading.  We load all of the classes from a partially-
+     * formed DEX file, which is unmapped when we're done.  If we want to
+     * do clean shutdown here, perhaps for testing with valgrind, we need
+     * to skip the munmap call there.
+     */
+#if 0
+    if (vmStarted) {
+        LOGI("DexOpt shutting down, result=%d", result);
+        dvmShutdown();
+    }
+#endif
+
+    free(bootClassPath);
+    LOGV("DexOpt command complete (result=%d)", result);
+    return result;
+}
+
+/*
+ * Main entry point.  Decide where to go.
+ */
+int main(int argc, char* const argv[])
+{
+    set_process_name("dexopt");
+
+    setvbuf(stdout, NULL, _IONBF, 0);
+
+    if (argc > 1) {
+        if (strcmp(argv[1], "--zip") == 0)
+            return fromZip(argc, argv);
+        else if (strcmp(argv[1], "--dex") == 0)
+            return fromDex(argc, argv);
+        else if (strcmp(argv[1], "--preopt") == 0)
+            return preopt(argc, argv);
+    }
+
+    fprintf(stderr,
+        "Usage:\n\n"
+        "Short version: Don't use this.\n\n"
+        "Slightly longer version: This system-internal tool is used to\n"
+        "produce optimized dex files. See the source code for details.\n");
+
+    return 1;
+}
diff --git a/docs/dalvik-bytecode.css b/docs/dalvik-bytecode.css
new file mode 100644
index 0000000..e4a5caa
--- /dev/null
+++ b/docs/dalvik-bytecode.css
@@ -0,0 +1,165 @@
+h1 {
+    font-family: serif;
+    color: #222266;
+}
+
+h2 {
+    font-family: serif;
+    border-top-style: solid;
+    border-top-width: 2px;
+    border-color: #ccccdd;
+    padding-top: 12px;
+    margin-top: 48px;
+    margin-bottom: 2px;
+    color: #222266;
+}
+
+@media print {
+    table {
+        font-size: 8pt;
+    }
+}
+
+@media screen {
+    table {
+        font-size: 10pt;
+    }
+}
+
+
+/* general for all tables */
+
+table {
+    border-collapse: collapse;
+    margin-top: 12px;
+}
+
+table th {
+    font-family: sans-serif;
+    background: #aabbff;
+}
+
+table td {
+    font-family: sans-serif;
+    border-top-style: solid;
+    border-bottom-style: solid;
+    border-width: 1px;
+    border-color: #aaaaff;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    padding-left: 4px;
+    padding-right: 6px;
+    background: #eeeeff;
+}
+
+table td p {
+    margin-top: 4pt;
+    margin-bottom: 0pt;
+}
+
+
+
+/* opcodes table */
+
+table.instruc {
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table.instruc td {
+    font-family: sans-serif;
+    border-top-style: solid;
+    border-bottom-style: solid;
+    border-width: 1px;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    padding-left: 2px;
+    padding-right: 2px;
+}
+
+table.instruc td:first-child {
+    font-family: monospace;
+    font-size: 90%;
+    vertical-align: top;
+    width: 12%;
+}
+
+table.instruc td:first-child + td {
+    font-family: monospace;
+    font-size: 90%;
+    vertical-align: top;
+    width: 23%;
+}
+
+table.instruc td:first-child + td i {
+    font-family: sans-serif;
+    font-size: 90%;
+}
+
+table.instruc td:first-child + td + td {
+    vertical-align: top;
+    width: 28%;
+}
+
+table.instruc td:first-child + td + td + td {
+    vertical-align: top;
+    width: 37%;
+}
+
+
+/* supplemental opcode format table */
+
+table.supplement {
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table.supplement td:first-child {
+    font-family: monospace;
+    vertical-align: top;
+    width: 20%;
+}
+
+table.supplement td:first-child + td {
+    font-family: monospace;
+    vertical-align: top;
+    width: 20%;
+}
+
+table.supplement td:first-child + td + td {
+    font-family: sans-serif;
+    vertical-align: top;
+    width: 60%;
+}
+
+
+/* math details table */
+
+table.math {
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table.math td:first-child {
+    font-family: monospace;
+    vertical-align: top;
+    width: 10%;
+}
+
+table.math td:first-child + td {
+    font-family: monospace;
+    vertical-align: top;
+    width: 30%;
+}
+
+table.math td:first-child + td + td {
+    font-family: sans-serif;
+    vertical-align: top;
+    width: 60%;
+}
diff --git a/docs/dalvik-bytecode.html b/docs/dalvik-bytecode.html
new file mode 100644
index 0000000..d4c0a77
--- /dev/null
+++ b/docs/dalvik-bytecode.html
@@ -0,0 +1,1715 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+
+<head>
+<title>Bytecode for the Dalvik VM</title>
+<link rel=stylesheet href="dalvik-bytecode.css">
+</head>
+
+<body>
+
+<h1>Bytecode for the Dalvik VM</h1>
+<p>Copyright &copy; 2007 The Android Open Source Project
+
+<h2>General Design</h2>
+
+<ul>
+<li>The machine model and calling conventions are meant to approximately
+  imitate common real architectures and C-style calling conventions:
+  <ul>
+  <li>The VM is register-based, and frames are fixed in size upon creation.
+    Each frame consists of a particular number of registers (specified by
+    the method) as well as any adjunct data needed to execute the method,
+    such as (but not limited to) the program counter and a reference to the
+    <code>.dex</code> file that contains the method.
+  </li>
+  <li>When used for bit values (such as integers and floating point
+    numbers), registers are considered 32 bits wide. Adjacent register
+    pairs are used for 64-bit values. There is no alignment requirement
+    for register pairs.
+  </li>
+  <li>When used for object references, registers are considered wide enough
+    to hold exactly one such reference.
+  </li>
+  <li>In terms of bitwise representation, <code>(Object) null == (int)
+    0</code>.
+  </li>
+  <li>The <i>N</i> arguments to a method land in the last <i>N</i> registers
+    of the method's invocation frame, in order. Wide arguments consume
+    two registers. Instance methods are passed a <code>this</code> reference
+    as their first argument.
+  </li>
+  </ul>
+<li>The storage unit in the instruction stream is a 16-bit unsigned quantity.
+  Some bits in some instructions are ignored / must-be-zero.
+</li>
+<li>Instructions aren't gratuitously limited to a particular type. For
+  example, instructions that move 32-bit register values without interpretation
+  don't have to specify whether they are moving ints or floats.
+</li>
+<li>There are separately enumerated and indexed constant pools for
+  references to strings, types, fields, and methods.
+</li>
+<li>Bitwise literal data is represented in-line in the instruction stream.</li>
+<li>Because, in practice, it is uncommon for a method to need more than
+  16 registers, and because needing more than eight registers <i>is</i>
+  reasonably common, many instructions are limited to only addressing
+  the first 16
+  registers. When reasonably possible, instructions allow references to
+  up to the first 256 registers. In addition, some instructions have variants
+  that allow for much larger register counts, including a pair of catch-all
+  <code>move</code> instructions that can address registers in the range
+  <code>v0</code> &ndash; <code>v65535</code>.
+  In cases where an instruction variant isn't
+  available to address a desired register, it is expected that the register
+  contents get moved from the original register to a low register (before the
+  operation) and/or moved from a low result register to a high register
+  (after the operation).
+</li>
+<li>There are several "pseudo-instructions" that are used to hold
+  variable-length data payloads, which are referred to by regular
+  instructions (for example,
+  <code>fill-array-data</code>). Such instructions must never be
+  encountered during the normal flow of execution. In addition, the
+  instructions must be located on even-numbered bytecode offsets (that is,
+  4-byte aligned). In order to meet this requirement, dex generation tools
+  must emit an extra <code>nop</code> instruction as a spacer if such an
+  instruction would otherwise be unaligned. Finally, though not required,
+  it is expected that most tools will choose to emit these instructions at
+  the ends of methods, since otherwise it would likely be the case that
+  additional instructions would be needed to branch around them.
+</li>
+<li>When installed on a running system, some instructions may be altered,
+  changing their format, as an install-time static linking optimization.
+  This is to allow for faster execution once linkage is known.
+  See the associated
+  <a href="instruction-formats.html">instruction formats document</a>
+  for the suggested variants. The word "suggested" is used advisedly;
+  it is not mandatory to implement these.
+</li>
+<li>Human-syntax and mnemonics:
+  <ul>
+  <li>Dest-then-source ordering for arguments.</li>
+  <li>Some opcodes have a disambiguating name suffix to indicate the type(s)
+    they operate on:
+    <ul>
+    <li>Type-general 32-bit opcodes are unmarked.</li>
+    <li>Type-general 64-bit opcodes are suffixed with <code>-wide</code>.</li>
+    <li>Type-specific opcodes are suffixed with their type (or a
+    straightforward abbreviation), one of: <code>-boolean</code>
+    <code>-byte</code> <code>-char</code> <code>-short</code>
+    <code>-int</code> <code>-long</code> <code>-float</code>
+    <code>-double</code> <code>-object</code> <code>-string</code>
+    <code>-class</code> <code>-void</code>.</li>
+    </ul>
+  </li>
+  <li>Some opcodes have a disambiguating suffix to distinguish
+    otherwise-identical operations that have different instruction layouts
+    or options. These suffixes are separated from the main names with a slash
+    ("<code>/</code>") and mainly exist at all to make there be a one-to-one
+    mapping with static constants in the code that generates and interprets
+    executables (that is, to reduce ambiguity for humans).
+  </li>
+  <li>In the descriptions here, the width of a value (indicating, e.g., the
+    range of a constant or the number of registers possibly addressed) is
+    emphasized by the use of a character per four bits of width.
+  </li>
+  <li>For example, in the instruction
+    "<code>move-wide/from16 vAA, vBBBB</code>":
+    <ul>
+    <li>"<code>move</code>" is the base opcode, indicating the base operation
+    (move a register's value).</li>
+    <li>"<code>wide</code>" is the name suffix, indicating that it operates
+    on wide (64 bit) data.</li>
+    <li>"<code>from16</code>" is the opcode suffix, indicating a variant
+    that has a 16-bit register reference as a source.</li>
+    <li>"<code>vAA</code>" is the destination register (implied by the
+    operation; again, the rule is that destination arguments always come
+    first), which must be in the range <code>v0</code> &ndash;
+    <code>v255</code>.</li>
+    <li>"<code>vBBBB</code>" is the source register, which must be in the
+    range <code>v0</code> &ndash; <code>v65535</code>.</li>
+    </ul>
+  </li>
+  </ul>
+</li>
+<li>See the <a href="instruction-formats.html">instruction formats
+  document</a> for more details about the various instruction formats
+  (listed under "Op &amp; Format") as well as details about the opcode
+  syntax.
+</li>
+<li>See the <a href="dex-format.html"><code>.dex</code> file format
+  document</a> for more details about where the bytecode fits into
+  the bigger picture.
+</li>
+</ul>
+
+<h2>Summary of Instruction Set</h2>
+
+<table class="instruc">
+<thead>
+<tr>
+  <th>Op &amp; Format</th>
+  <th>Mnemonic / Syntax</th>
+  <th>Arguments</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>00 10x</td>
+  <td>nop</td>
+  <td>&nbsp;</td>
+  <td>Waste cycles.
+    <p><b>Note:</b>
+    Data-bearing pseudo-instructions are tagged with this opcode, in which
+    case the high-order byte of the opcode unit indicates the nature of
+    the data. See "<code>packed-switch-payload</code> Format",
+    "<code>sparse-switch-payload</code> Format", and
+    "<code>fill-array-data-payload</code> Format" below.</p>
+  </td>
+</tr>
+<tr>
+  <td>01 12x</td>
+  <td>move vA, vB</td>
+  <td><code>A:</code> destination register (4 bits)<br/>
+    <code>B:</code> source register (4 bits)</td>
+  <td>Move the contents of one non-object register to another.</td>
+</tr>
+<tr>
+  <td>02 22x</td>
+  <td>move/from16 vAA, vBBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> source register (16 bits)</td>
+  <td>Move the contents of one non-object register to another.</td>
+</tr>
+<tr>
+  <td>03 32x</td>
+  <td>move/16 vAAAA, vBBBB</td>
+  <td><code>A:</code> destination register (16 bits)<br/>
+    <code>B:</code> source register (16 bits)</td>
+  <td>Move the contents of one non-object register to another.</td>
+</tr>
+<tr>
+  <td>04 12x</td>
+  <td>move-wide vA, vB</td>
+  <td><code>A:</code> destination register pair (4 bits)<br/>
+    <code>B:</code> source register pair (4 bits)</td>
+  <td>Move the contents of one register-pair to another.
+    <p><b>Note:</b>
+    It is legal to move from <code>v<i>N</i></code> to either
+    <code>v<i>N-1</i></code> or <code>v<i>N+1</i></code>, so implementations
+    must arrange for both halves of a register pair to be read before
+    anything is written.</p>
+  </td>
+</tr>
+<tr>
+  <td>05 22x</td>
+  <td>move-wide/from16 vAA, vBBBB</td>
+  <td><code>A:</code> destination register pair (8 bits)<br/>
+    <code>B:</code> source register pair (16 bits)</td>
+  <td>Move the contents of one register-pair to another.
+    <p><b>Note:</b>
+    Implementation considerations are the same as <code>move-wide</code>,
+    above.</p>
+  </td>
+</tr>
+<tr>
+  <td>06 32x</td>
+  <td>move-wide/16 vAAAA, vBBBB</td>
+  <td><code>A:</code> destination register pair (16 bits)<br/>
+    <code>B:</code> source register pair (16 bits)</td>
+  <td>Move the contents of one register-pair to another.
+    <p><b>Note:</b>
+    Implementation considerations are the same as <code>move-wide</code>,
+    above.</p>
+  </td>
+</tr>
+<tr>
+  <td>07 12x</td>
+  <td>move-object vA, vB</td>
+  <td><code>A:</code> destination register (4 bits)<br/>
+    <code>B:</code> source register (4 bits)</td>
+  <td>Move the contents of one object-bearing register to another.</td>
+</tr>
+<tr>
+  <td>08 22x</td>
+  <td>move-object/from16 vAA, vBBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> source register (16 bits)</td>
+  <td>Move the contents of one object-bearing register to another.</td>
+</tr>
+<tr>
+  <td>09 32x</td>
+  <td>move-object/16 vAAAA, vBBBB</td>
+  <td><code>A:</code> destination register (16 bits)<br/>
+    <code>B:</code> source register (16 bits)</td>
+  <td>Move the contents of one object-bearing register to another.</td>
+</tr>
+<tr>
+  <td>0a 11x</td>
+  <td>move-result vAA</td>
+  <td><code>A:</code> destination register (8 bits)</td>
+  <td>Move the single-word non-object result of the most recent
+    <code>invoke-<i>kind</i></code> into the indicated register.
+    This must be done as the instruction immediately after an
+    <code>invoke-<i>kind</i></code> whose (single-word, non-object) result
+    is not to be ignored; anywhere else is invalid.</td>
+</tr>
+<tr>
+  <td>0b 11x</td>
+  <td>move-result-wide vAA</td>
+  <td><code>A:</code> destination register pair (8 bits)</td>
+  <td>Move the double-word result of the most recent
+    <code>invoke-<i>kind</i></code> into the indicated register pair.
+    This must be done as the instruction immediately after an
+    <code>invoke-<i>kind</i></code> whose (double-word) result
+    is not to be ignored; anywhere else is invalid.</td>
+</tr>
+<tr>
+  <td>0c 11x</td>
+  <td>move-result-object vAA</td>
+  <td><code>A:</code> destination register (8 bits)</td>
+  <td>Move the object result of the most recent <code>invoke-<i>kind</i></code>
+    into the indicated register. This must be done as the instruction
+    immediately after an <code>invoke-<i>kind</i></code> or
+    <code>filled-new-array</code>
+    whose (object) result is not to be ignored; anywhere else is invalid.</td>
+</tr>
+<tr>
+  <td>0d 11x</td>
+  <td>move-exception vAA</td>
+  <td><code>A:</code> destination register (8 bits)</td>
+  <td>Save a just-caught exception into the given register. This must
+    be the first instruction of any exception handler whose caught
+    exception is not to be ignored, and this instruction must <i>only</i>
+    ever occur as the first instruction of an exception handler; anywhere
+    else is invalid.</td>
+</tr>
+<tr>
+  <td>0e 10x</td>
+  <td>return-void</td>
+  <td>&nbsp;</td>
+  <td>Return from a <code>void</code> method.</td>
+</tr>
+<tr>
+  <td>0f 11x</td>
+  <td>return vAA</td>
+  <td><code>A:</code> return value register (8 bits)</td>
+  <td>Return from a single-width (32-bit) non-object value-returning
+    method.
+  </td>
+</tr>
+<tr>
+  <td>10 11x</td>
+  <td>return-wide vAA</td>
+  <td><code>A:</code> return value register-pair (8 bits)</td>
+  <td>Return from a double-width (64-bit) value-returning method.</td>
+</tr>
+<tr>
+  <td>11 11x</td>
+  <td>return-object vAA</td>
+  <td><code>A:</code> return value register (8 bits)</td>
+  <td>Return from an object-returning method.</td>
+</tr>
+<tr>
+  <td>12 11n</td>
+  <td>const/4 vA, #+B</td>
+  <td><code>A:</code> destination register (4 bits)<br/>
+    <code>B:</code> signed int (4 bits)</td>
+  <td>Move the given literal value (sign-extended to 32 bits) into
+    the specified register.</td>
+</tr>
+<tr>
+  <td>13 21s</td>
+  <td>const/16 vAA, #+BBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> signed int (16 bits)</td>
+  <td>Move the given literal value (sign-extended to 32 bits) into
+    the specified register.</td>
+</tr>
+<tr>
+  <td>14 31i</td>
+  <td>const vAA, #+BBBBBBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> arbitrary 32-bit constant</td>
+  <td>Move the given literal value into the specified register.</td>
+</tr>
+<tr>
+  <td>15 21h</td>
+  <td>const/high16 vAA, #+BBBB0000</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> signed int (16 bits)</td>
+  <td>Move the given literal value (right-zero-extended to 32 bits) into
+    the specified register.</td>
+</tr>
+<tr>
+  <td>16 21s</td>
+  <td>const-wide/16 vAA, #+BBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> signed int (16 bits)</td>
+  <td>Move the given literal value (sign-extended to 64 bits) into
+    the specified register-pair.</td>
+</tr>
+<tr>
+  <td>17 31i</td>
+  <td>const-wide/32 vAA, #+BBBBBBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> signed int (32 bits)</td>
+  <td>Move the given literal value (sign-extended to 64 bits) into
+    the specified register-pair.</td>
+</tr>
+<tr>
+  <td>18 51l</td>
+  <td>const-wide vAA, #+BBBBBBBBBBBBBBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> arbitrary double-width (64-bit) constant</td>
+  <td>Move the given literal value into
+    the specified register-pair.</td>
+</tr>
+<tr>
+  <td>19 21h</td>
+  <td>const-wide/high16 vAA, #+BBBB000000000000</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> signed int (16 bits)</td>
+  <td>Move the given literal value (right-zero-extended to 64 bits) into
+    the specified register-pair.</td>
+</tr>
+<tr>
+  <td>1a 21c</td>
+  <td>const-string vAA, string@BBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> string index</td>
+  <td>Move a reference to the string specified by the given index into the
+    specified register.</td>
+</tr>
+<tr>
+  <td>1b 31c</td>
+  <td>const-string/jumbo vAA, string@BBBBBBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> string index</td>
+  <td>Move a reference to the string specified by the given index into the
+    specified register.</td>
+</tr>
+<tr>
+  <td>1c 21c</td>
+  <td>const-class vAA, type@BBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> type index</td>
+  <td>Move a reference to the class specified by the given index into the
+    specified register. In the case where the indicated type is primitive,
+    this will store a reference to the primitive type's degenerate
+    class.</td>
+</tr>
+<tr>
+  <td>1d 11x</td>
+  <td>monitor-enter vAA</td>
+  <td><code>A:</code> reference-bearing register (8 bits)</td>
+  <td>Acquire the monitor for the indicated object.</td>
+</tr>
+<tr>
+  <td>1e 11x</td>
+  <td>monitor-exit vAA</td>
+  <td><code>A:</code> reference-bearing register (8 bits)</td>
+  <td>Release the monitor for the indicated object.
+    <p><b>Note:</b>
+    If this instruction needs to throw an exception, it must do
+    so as if the pc has already advanced past the instruction.
+    It may be useful to think of this as the instruction successfully
+    executing (in a sense), and the exception getting thrown <i>after</i>
+    the instruction but <i>before</i> the next one gets a chance to
+    run. This definition makes it possible for a method to use
+    a monitor cleanup catch-all (e.g., <code>finally</code>) block as
+    the monitor cleanup for that block itself, as a way to handle the
+    arbitrary exceptions that might get thrown due to the historical
+    implementation of <code>Thread.stop()</code>, while still managing
+    to have proper monitor hygiene.</p>
+  </td>
+</tr>
+<tr>
+  <td>1f 21c</td>
+  <td>check-cast vAA, type@BBBB</td>
+  <td><code>A:</code> reference-bearing register (8 bits)<br/>
+    <code>B:</code> type index (16 bits)</td>
+  <td>Throw a <code>ClassCastException</code> if the reference in the
+    given register cannot be cast to the indicated type.
+    <p><b>Note:</b> Since <code>A</code> must always be a reference
+    (and not a primitive value), this will necessarily fail at runtime
+    (that is, it will throw an exception) if <code>B</code> refers to a
+    primitive type.</p>
+  </td>
+</tr>
+<tr>
+  <td>20 22c</td>
+  <td>instance-of vA, vB, type@CCCC</td>
+  <td><code>A:</code> destination register (4 bits)<br/>
+    <code>B:</code> reference-bearing register (4 bits)<br/>
+    <code>C:</code> type index (16 bits)</td>
+  <td>Store in the given destination register <code>1</code>
+    if the indicated reference is an instance of the given type,
+    or <code>0</code> if not.
+    <p><b>Note:</b> Since <code>B</code> must always be a reference
+    (and not a primitive value), this will always result
+    in <code>0</code> being stored if <code>C</code> refers to a primitive
+    type.</td>
+</tr>
+<tr>
+  <td>21 12x</td>
+  <td>array-length vA, vB</td>
+  <td><code>A:</code> destination register (4 bits)<br/>
+    <code>B:</code> array reference-bearing register (4 bits)</td>
+  <td>Store in the given destination register the length of the indicated
+    array, in entries</td>
+</tr>
+<tr>
+  <td>22 21c</td>
+  <td>new-instance vAA, type@BBBB</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> type index</td>
+  <td>Construct a new instance of the indicated type, storing a
+    reference to it in the destination. The type must refer to a
+    non-array class.</td>
+</tr>
+<tr>
+  <td>23 22c</td>
+  <td>new-array vA, vB, type@CCCC</td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> size register<br/>
+    <code>C:</code> type index</td>
+  <td>Construct a new array of the indicated type and size. The type
+    must be an array type.</td>
+</tr>
+<tr>
+  <td>24 35c</td>
+  <td>filled-new-array {vC, vD, vE, vF, vG}, type@BBBB</td>
+  <td>
+    <code>A:</code> array size and argument word count (4 bits)<br/>
+    <code>B:</code> type index (16 bits)<br/>
+    <code>C..G:</code> argument registers (4 bits each)
+  </td>
+  <td>Construct an array of the given type and size, filling it with the
+    supplied contents. The type must be an array type. The array's
+    contents must be single-word (that is,
+    no arrays of <code>long</code> or <code>double</code>, but reference
+    types are acceptable). The constructed
+    instance is stored as a "result" in the same way that the method invocation
+    instructions store their results, so the constructed instance must
+    be moved to a register with an immediately subsequent
+    <code>move-result-object</code> instruction (if it is to be used).</td>
+</tr>
+<tr>
+  <td>25 3rc</td>
+  <td>filled-new-array/range {vCCCC .. vNNNN}, type@BBBB</td>
+  <td><code>A:</code> array size and argument word count (8 bits)<br/>
+    <code>B:</code> type index (16 bits)<br/>
+    <code>C:</code> first argument register (16 bits)<br/>
+    <code>N = A + C - 1</code></td>
+  <td>Construct an array of the given type and size, filling it with
+    the supplied contents. Clarifications and restrictions are the same
+    as <code>filled-new-array</code>, described above.</td>
+</tr>
+<tr>
+  <td>26 31t</td>
+  <td>fill-array-data vAA, +BBBBBBBB <i>(with supplemental data as specified
+    below in "<code>fill-array-data-payload</code> Format")</i></td>
+  <td><code>A:</code> array reference (8 bits)<br/>
+    <code>B:</code> signed "branch" offset to table data pseudo-instruction
+    (32 bits)
+  </td>
+  <td>Fill the given array with the indicated data. The reference must be
+    to an array of primitives, and the data table must match it in type and
+    must contain no more elements than will fit in the array. That is,
+    the array may be larger than the table, and if so, only the initial
+    elements of the array are set, leaving the remainder alone.
+  </td>
+</tr>
+<tr>
+  <td>27 11x</td>
+  <td>throw vAA</td>
+  <td><code>A:</code> exception-bearing register (8 bits)<br/></td>
+  <td>Throw the indicated exception.</td>
+</tr>
+<tr>
+  <td>28 10t</td>
+  <td>goto +AA</td>
+  <td><code>A:</code> signed branch offset (8 bits)</td>
+  <td>Unconditionally jump to the indicated instruction.
+    <p><b>Note:</b>
+    The branch offset must not be <code>0</code>. (A spin
+    loop may be legally constructed either with <code>goto/32</code> or
+    by including a <code>nop</code> as a target before the branch.)</p>
+  </td>
+</tr>
+<tr>
+  <td>29 20t</td>
+  <td>goto/16 +AAAA</td>
+  <td><code>A:</code> signed branch offset (16 bits)<br/></td>
+  <td>Unconditionally jump to the indicated instruction.
+    <p><b>Note:</b>
+    The branch offset must not be <code>0</code>. (A spin
+    loop may be legally constructed either with <code>goto/32</code> or
+    by including a <code>nop</code> as a target before the branch.)</p>
+  </td>
+</tr>
+<tr>
+  <td>2a 30t</td>
+  <td>goto/32 +AAAAAAAA</td>
+  <td><code>A:</code> signed branch offset (32 bits)<br/></td>
+  <td>Unconditionally jump to the indicated instruction.</td>
+</tr>
+<tr>
+  <td>2b 31t</td>
+  <td>packed-switch vAA, +BBBBBBBB <i>(with supplemental data as
+    specified below in "<code>packed-switch-payload</code> Format")</i></td>
+  <td><code>A:</code> register to test<br/>
+    <code>B:</code> signed "branch" offset to table data pseudo-instruction
+    (32 bits)
+  </td>
+  <td>Jump to a new instruction based on the value in the
+    given register, using a table of offsets corresponding to each value
+    in a particular integral range, or fall through to the next
+    instruction if there is no match.
+  </td>
+</tr>
+<tr>
+  <td>2c 31t</td>
+  <td>sparse-switch vAA, +BBBBBBBB <i>(with supplemental data as
+    specified below in "<code>sparse-switch-payload</code> Format")</i></td>
+  <td><code>A:</code> register to test<br/>
+    <code>B:</code> signed "branch" offset to table data pseudo-instruction
+    (32 bits)
+  </td>
+  <td>Jump to a new instruction based on the value in the given
+    register, using an ordered table of value-offset pairs, or fall
+    through to the next instruction if there is no match.
+  </td>
+</tr>
+<tr>
+  <td>2d..31 23x</td>
+  <td>cmp<i>kind</i> vAA, vBB, vCC<br/>
+    2d: cmpl-float <i>(lt bias)</i><br/>
+    2e: cmpg-float <i>(gt bias)</i><br/>
+    2f: cmpl-double <i>(lt bias)</i><br/>
+    30: cmpg-double <i>(gt bias)</i><br/>
+    31: cmp-long
+  </td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> first source register or pair<br/>
+    <code>C:</code> second source register or pair</td>
+  <td>Perform the indicated floating point or <code>long</code> comparison,
+    storing <code>0</code> if the two arguments are equal, <code>1</code>
+    if the second argument is larger, or <code>-1</code> if the first
+    argument is larger. The "bias" listed for the floating point operations
+    indicates how <code>NaN</code> comparisons are treated: "Gt bias"
+    instructions return <code>1</code> for <code>NaN</code> comparisons,
+    and "lt bias" instructions return
+    <code>-1</code>.
+    <p>For example, to check to see if floating point
+    <code>a &lt; b</code>, then it is advisable to use
+    <code>cmpg-float</code>; a result of <code>-1</code> indicates that
+    the test was true, and the other values indicate it was false either
+    due to a valid comparison or because one or the other values was
+    <code>NaN</code>.</p>
+  </td>
+</tr>
+<tr>
+  <td>32..37 22t</td>
+  <td>if-<i>test</i> vA, vB, +CCCC<br/>
+    32: if-eq<br/>
+    33: if-ne<br/>
+    34: if-lt<br/>
+    35: if-ge<br/>
+    36: if-gt<br/>
+    37: if-le<br/>
+  </td>
+  <td><code>A:</code> first register to test (4 bits)<br/>
+    <code>B:</code> second register to test (4 bits)<br/>
+    <code>C:</code> signed branch offset (16 bits)</td>
+  <td>Branch to the given destination if the given two registers' values
+    compare as specified.
+    <p><b>Note:</b>
+    The branch offset must not be <code>0</code>. (A spin
+    loop may be legally constructed either by branching around a
+    backward <code>goto</code> or by including a <code>nop</code> as
+    a target before the branch.)</p>
+  </td>
+</tr>
+<tr>
+  <td>38..3d 21t</td>
+  <td>if-<i>test</i>z vAA, +BBBB<br/>
+    38: if-eqz<br/>
+    39: if-nez<br/>
+    3a: if-ltz<br/>
+    3b: if-gez<br/>
+    3c: if-gtz<br/>
+    3d: if-lez<br/>
+  </td>
+  <td><code>A:</code> register to test (8 bits)<br/>
+    <code>B:</code> signed branch offset (16 bits)</td>
+  <td>Branch to the given destination if the given register's value compares
+    with 0 as specified.
+    <p><b>Note:</b>
+    The branch offset must not be <code>0</code>. (A spin
+    loop may be legally constructed either by branching around a
+    backward <code>goto</code> or by including a <code>nop</code> as
+    a target before the branch.)</p>
+  </td>
+</tr>
+<tr>
+  <td>3e..43 10x</td>
+  <td><i>(unused)</i></td>
+  <td>&nbsp;</td>
+  <td><i>(unused)</i></td>
+</tr>
+<tr>
+  <td>44..51 23x</td>
+  <td><i>arrayop</i> vAA, vBB, vCC<br/>
+    44: aget<br/>
+    45: aget-wide<br/>
+    46: aget-object<br/>
+    47: aget-boolean<br/>
+    48: aget-byte<br/>
+    49: aget-char<br/>
+    4a: aget-short<br/>
+    4b: aput<br/>
+    4c: aput-wide<br/>
+    4d: aput-object<br/>
+    4e: aput-boolean<br/>
+    4f: aput-byte<br/>
+    50: aput-char<br/>
+    51: aput-short
+  </td>
+  <td><code>A:</code> value register or pair; may be source or dest
+      (8 bits)<br/>
+    <code>B:</code> array register (8 bits)<br/>
+    <code>C:</code> index register (8 bits)</td>
+  <td>Perform the identified array operation at the identified index of
+    the given array, loading or storing into the value register.</td>
+</tr>
+<tr>
+  <td>52..5f 22c</td>
+  <td>i<i>instanceop</i> vA, vB, field@CCCC<br/>
+    52: iget<br/>
+    53: iget-wide<br/>
+    54: iget-object<br/>
+    55: iget-boolean<br/>
+    56: iget-byte<br/>
+    57: iget-char<br/>
+    58: iget-short<br/>
+    59: iput<br/>
+    5a: iput-wide<br/>
+    5b: iput-object<br/>
+    5c: iput-boolean<br/>
+    5d: iput-byte<br/>
+    5e: iput-char<br/>
+    5f: iput-short
+  </td>
+  <td><code>A:</code> value register or pair; may be source or dest
+      (4 bits)<br/>
+    <code>B:</code> object register (4 bits)<br/>
+    <code>C:</code> instance field reference index (16 bits)</td>
+  <td>Perform the identified object instance field operation with
+    the identified field, loading or storing into the value register.
+    <p><b>Note:</b> These opcodes are reasonable candidates for static linking,
+    altering the field argument to be a more direct offset.</p>
+  </td>
+</tr>
+<tr>
+  <td>60..6d 21c</td>
+  <td>s<i>staticop</i> vAA, field@BBBB<br/>
+    60: sget<br/>
+    61: sget-wide<br/>
+    62: sget-object<br/>
+    63: sget-boolean<br/>
+    64: sget-byte<br/>
+    65: sget-char<br/>
+    66: sget-short<br/>
+    67: sput<br/>
+    68: sput-wide<br/>
+    69: sput-object<br/>
+    6a: sput-boolean<br/>
+    6b: sput-byte<br/>
+    6c: sput-char<br/>
+    6d: sput-short
+  </td>
+  <td><code>A:</code> value register or pair; may be source or dest
+      (8 bits)<br/>
+    <code>B:</code> static field reference index (16 bits)</td>
+  <td>Perform the identified object static field operation with the identified
+    static field, loading or storing into the value register.
+    <p><b>Note:</b> These opcodes are reasonable candidates for static linking,
+    altering the field argument to be a more direct offset.</p>
+  </td>
+</tr>
+<tr>
+  <td>6e..72 35c</td>
+  <td>invoke-<i>kind</i> {vC, vD, vE, vF, vG}, meth@BBBB<br/>
+    6e: invoke-virtual<br/>
+    6f: invoke-super<br/>
+    70: invoke-direct<br/>
+    71: invoke-static<br/>
+    72: invoke-interface
+  </td>
+  <td>
+    <code>A:</code> argument word count (4 bits)<br/>
+    <code>B:</code> method reference index (16 bits)<br/>
+    <code>C..G:</code> argument registers (4 bits each)
+  </td>
+  <td>Call the indicated method. The result (if any) may be stored
+    with an appropriate <code>move-result*</code> variant as the immediately
+    subsequent instruction.
+    <p><code>invoke-virtual</code> is used to invoke a normal virtual
+    method (a method that is not <code>private</code>, <code>static</code>,
+    or <code>final</code>, and is also not a constructor).</p>
+    <p><code>invoke-super</code> is used to invoke the closest superclass's
+    virtual method (as opposed to the one with the same <code>method_id</code>
+    in the calling class). The same method restrictions hold as for
+    <code>invoke-virtual</code>.</p>
+    <p><code>invoke-direct</code> is used to invoke a non-<code>static</code>
+    direct method (that is, an instance method that is by its nature
+    non-overridable, namely either a <code>private</code> instance method
+    or a constructor).</p>
+    <p><code>invoke-static</code> is used to invoke a <code>static</code>
+    method (which is always considered a direct method).</p>
+    <p><code>invoke-interface</code> is used to invoke an
+    <code>interface</code> method, that is, on an object whose concrete
+    class isn't known, using a <code>method_id</code> that refers to
+    an <code>interface</code>.</p>
+    <p><b>Note:</b> These opcodes are reasonable candidates for static linking,
+    altering the method argument to be a more direct offset
+    (or pair thereof).</p>
+  </td>
+</tr>
+<tr>
+  <td>73 10x</td>
+  <td><i>(unused)</i></td>
+  <td>&nbsp;</td>
+  <td><i>(unused)</i></td>
+</tr>
+<tr>
+  <td>74..78 3rc</td>
+  <td>invoke-<i>kind</i>/range {vCCCC .. vNNNN}, meth@BBBB<br/>
+    74: invoke-virtual/range<br/>
+    75: invoke-super/range<br/>
+    76: invoke-direct/range<br/>
+    77: invoke-static/range<br/>
+    78: invoke-interface/range
+  </td>
+  <td><code>A:</code> argument word count (8 bits)<br/>
+    <code>B:</code> method reference index (16 bits)<br/>
+    <code>C:</code> first argument register (16 bits)<br/>
+    <code>N = A + C - 1</code></td>
+  <td>Call the indicated method. See first <code>invoke-<i>kind</i></code>
+    description above for details, caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>79..7a 10x</td>
+  <td><i>(unused)</i></td>
+  <td>&nbsp;</td>
+  <td><i>(unused)</i></td>
+</tr>
+<tr>
+  <td>7b..8f 12x</td>
+  <td><i>unop</i> vA, vB<br/>
+    7b: neg-int<br/>
+    7c: not-int<br/>
+    7d: neg-long<br/>
+    7e: not-long<br/>
+    7f: neg-float<br/>
+    80: neg-double<br/>
+    81: int-to-long<br/>
+    82: int-to-float<br/>
+    83: int-to-double<br/>
+    84: long-to-int<br/>
+    85: long-to-float<br/>
+    86: long-to-double<br/>
+    87: float-to-int<br/>
+    88: float-to-long<br/>
+    89: float-to-double<br/>
+    8a: double-to-int<br/>
+    8b: double-to-long<br/>
+    8c: double-to-float<br/>
+    8d: int-to-byte<br/>
+    8e: int-to-char<br/>
+    8f: int-to-short
+  </td>
+  <td><code>A:</code> destination register or pair (4 bits)<br/>
+    <code>B:</code> source register or pair (4 bits)</td>
+  <td>Perform the identified unary operation on the source register,
+    storing the result in the destination register.</td>
+</tr>
+
+<tr>
+  <td>90..af 23x</td>
+  <td><i>binop</i> vAA, vBB, vCC<br/>
+    90: add-int<br/>
+    91: sub-int<br/>
+    92: mul-int<br/>
+    93: div-int<br/>
+    94: rem-int<br/>
+    95: and-int<br/>
+    96: or-int<br/>
+    97: xor-int<br/>
+    98: shl-int<br/>
+    99: shr-int<br/>
+    9a: ushr-int<br/>
+    9b: add-long<br/>
+    9c: sub-long<br/>
+    9d: mul-long<br/>
+    9e: div-long<br/>
+    9f: rem-long<br/>
+    a0: and-long<br/>
+    a1: or-long<br/>
+    a2: xor-long<br/>
+    a3: shl-long<br/>
+    a4: shr-long<br/>
+    a5: ushr-long<br/>
+    a6: add-float<br/>
+    a7: sub-float<br/>
+    a8: mul-float<br/>
+    a9: div-float<br/>
+    aa: rem-float<br/>
+    ab: add-double<br/>
+    ac: sub-double<br/>
+    ad: mul-double<br/>
+    ae: div-double<br/>
+    af: rem-double
+  </td>
+  <td><code>A:</code> destination register or pair (8 bits)<br/>
+    <code>B:</code> first source register or pair (8 bits)<br/>
+    <code>C:</code> second source register or pair (8 bits)</td>
+  <td>Perform the identified binary operation on the two source registers,
+    storing the result in the first source register.</td>
+</tr>
+<tr>
+  <td>b0..cf 12x</td>
+  <td><i>binop</i>/2addr vA, vB<br/>
+    b0: add-int/2addr<br/>
+    b1: sub-int/2addr<br/>
+    b2: mul-int/2addr<br/>
+    b3: div-int/2addr<br/>
+    b4: rem-int/2addr<br/>
+    b5: and-int/2addr<br/>
+    b6: or-int/2addr<br/>
+    b7: xor-int/2addr<br/>
+    b8: shl-int/2addr<br/>
+    b9: shr-int/2addr<br/>
+    ba: ushr-int/2addr<br/>
+    bb: add-long/2addr<br/>
+    bc: sub-long/2addr<br/>
+    bd: mul-long/2addr<br/>
+    be: div-long/2addr<br/>
+    bf: rem-long/2addr<br/>
+    c0: and-long/2addr<br/>
+    c1: or-long/2addr<br/>
+    c2: xor-long/2addr<br/>
+    c3: shl-long/2addr<br/>
+    c4: shr-long/2addr<br/>
+    c5: ushr-long/2addr<br/>
+    c6: add-float/2addr<br/>
+    c7: sub-float/2addr<br/>
+    c8: mul-float/2addr<br/>
+    c9: div-float/2addr<br/>
+    ca: rem-float/2addr<br/>
+    cb: add-double/2addr<br/>
+    cc: sub-double/2addr<br/>
+    cd: mul-double/2addr<br/>
+    ce: div-double/2addr<br/>
+    cf: rem-double/2addr
+  </td>
+  <td><code>A:</code> destination and first source register or pair
+      (4 bits)<br/>
+    <code>B:</code> second source register or pair (4 bits)</td>
+  <td>Perform the identified binary operation on the two source registers,
+    storing the result in the first source register.</td>
+</tr>
+<tr>
+  <td>d0..d7 22s</td>
+  <td><i>binop</i>/lit16 vA, vB, #+CCCC<br/>
+    d0: add-int/lit16<br/>
+    d1: rsub-int (reverse subtract)<br/>
+    d2: mul-int/lit16<br/>
+    d3: div-int/lit16<br/>
+    d4: rem-int/lit16<br/>
+    d5: and-int/lit16<br/>
+    d6: or-int/lit16<br/>
+    d7: xor-int/lit16
+  </td>
+  <td><code>A:</code> destination register (4 bits)<br/>
+    <code>B:</code> source register (4 bits)<br/>
+    <code>C:</code> signed int constant (16 bits)</td>
+  <td>Perform the indicated binary op on the indicated register (first
+    argument) and literal value (second argument), storing the result in
+    the destination register.
+    <p><b>Note:</b>
+    <code>rsub-int</code> does not have a suffix since this version is the
+    main opcode of its family. Also, see below for details on its semantics.
+    </p>
+  </td>
+</tr>
+<tr>
+  <td>d8..e2 22b</td>
+  <td><i>binop</i>/lit8 vAA, vBB, #+CC<br/>
+    d8: add-int/lit8<br/>
+    d9: rsub-int/lit8<br/>
+    da: mul-int/lit8<br/>
+    db: div-int/lit8<br/>
+    dc: rem-int/lit8<br/>
+    dd: and-int/lit8<br/>
+    de: or-int/lit8<br/>
+    df: xor-int/lit8<br/>
+    e0: shl-int/lit8<br/>
+    e1: shr-int/lit8<br/>
+    e2: ushr-int/lit8
+  </td>
+  <td><code>A:</code> destination register (8 bits)<br/>
+    <code>B:</code> source register (8 bits)<br/>
+    <code>C:</code> signed int constant (8 bits)</td>
+  <td>Perform the indicated binary op on the indicated register (first
+    argument) and literal value (second argument), storing the result
+    in the destination register.
+    <p><b>Note:</b> See below for details on the semantics of
+    <code>rsub-int</code>.</p>
+  </td>
+</tr>
+<tr>
+  <td>e3..fe 10x</td>
+  <td><i>(unused)</i></td>
+  <td>&nbsp;</td>
+  <td><i>(unused)</i></td>
+</tr>
+<tr>
+  <td>ff -</td>
+  <td><i>(expanded opcode)</i></td>
+  <td>&nbsp;</td>
+  <td>An <code>ff</code> in the primary opcode position indicates that there
+    is a secondary opcode in the high-order byte of the opcode code unit,
+    as opposed to an argument value. These expanded opcodes are detailed
+    immediately below.
+  </td>
+</tr>
+<tr>
+  <td>00ff 41c</td>
+  <td>const-class/jumbo vAAAA, type@BBBBBBBB</td>
+  <td>
+    <code>A:</code> destination register (16 bits)<br/>
+    <code>B:</code> type index (32 bits)
+  </td>
+  <td>Move a reference to the class specified by the given index into the
+    specified register. See <code>const-class</code> description above
+    for details, caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>01ff 41c</td>
+  <td>check-cast/jumbo vAAAA, type@BBBBBBBB</td>
+  <td>
+    <code>A:</code> reference-bearing register (16 bits)<br/>
+    <code>B:</code> type index (32 bits)
+  </td>
+  <td>Throw a <code>ClassCastException</code> if the reference in the
+    given register cannot be cast to the indicated type. See
+    <code>check-cast</code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>02ff 52c</td>
+  <td>instance-of/jumbo  vAAAA, vBBBB, type@CCCCCCCC</td>
+  <td>
+    <code>A:</code> destination register (16 bits)<br/>
+    <code>B:</code> reference-bearing register (16 bits)<br/>
+    <code>C:</code> type index (32 bits)
+  </td>
+  <td>Store in the given destination register <code>1</code>
+    if the indicated reference is an instance of the given type,
+    or <code>0</code> if not. See
+    <code>instance-of</code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>03ff 41c</td>
+  <td>new-instance/jumbo vAAAA, type@BBBBBBBB</td>
+  <td>
+    <code>A:</code> destination register (16 bits)<br/>
+    <code>B:</code> type index (32 bits)
+  </td>
+  <td>Construct a new instance of the indicated type. See
+    <code>new-instance</code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>04ff 52c</td>
+  <td>new-array/jumbo vAAAA, vBBBB, type@CCCCCCCC</td>
+  <td>
+    <code>A:</code> destination register (16 bits)<br/>
+    <code>B:</code> size register (16 bits)<br/>
+    <code>C:</code> type index (32 bits)
+  </td>
+  <td>Construct a new array of the indicated type and size. See
+    <code>new-array</code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>05ff 5rc</td>
+  <td>filled-new-array/jumbo {vCCCC .. vNNNN}, type@BBBBBBBB</td>
+  <td>
+    <code>A:</code> array size and argument word count (16 bits)<br/>
+    <code>B:</code> type index (32 bits)<br/>
+    <code>C:</code> first argument register (16 bits)<br/>
+    <code>N = A + C - 1</code>
+  </td>
+  <td>Construct an array of the given type and size, filling it with the
+    supplied contents. See first
+    <code>filled-new-array</code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>06ff..13ff 52c</td>
+  <td>i<i>instanceop</i>/jumbo vAAAA, vBBBB, field@CCCCCCCC<br/>
+    06ff: iget/jumbo<br/>
+    07ff: iget-wide/jumbo<br/>
+    08ff: iget-object/jumbo<br/>
+    09ff: iget-boolean/jumbo<br/>
+    0aff: iget-byte/jumbo<br/>
+    0bff: iget-char/jumbo<br/>
+    0cff: iget-short/jumbo<br/>
+    0dff: iput/jumbo<br/>
+    0eff: iput-wide/jumbo<br/>
+    0fff: iput-object/jumbo<br/>
+    10ff: iput-boolean/jumbo<br/>
+    11ff: iput-byte/jumbo<br/>
+    12ff: iput-char/jumbo<br/>
+    13ff: iput-short/jumbo
+  </td>
+  <td>
+    <code>A:</code> value register or pair; may be source or dest (16 bits)<br/>
+    <code>B:</code> object register (16 bits)<br/>
+    <code>C:</code> instance field reference index (32 bits)
+  </td>
+  <td>Perform the identified object instance field operation. See
+    <code>i<i>instanceop</i></code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>14ff..21ff 41c</td>
+  <td>s<i>staticop</i>/jumbo vAAAA, field@BBBBBBBB<br/>
+    14ff: sget/jumbo<br/>
+    15ff: sget-wide/jumbo<br/>
+    16ff: sget-object/jumbo<br/>
+    17ff: sget-boolean/jumbo<br/>
+    18ff: sget-byte/jumbo<br/>
+    19ff: sget-char/jumbo<br/>
+    1aff: sget-short/jumbo<br/>
+    1bff: sput/jumbo<br/>
+    1cff: sput-wide/jumbo<br/>
+    1dff: sput-object/jumbo<br/>
+    1eff: sput-boolean/jumbo<br/>
+    1fff: sput-byte/jumbo<br/>
+    20ff: sput-char/jumbo<br/>
+    21ff: sput-short/jumbo
+  </td>
+  <td>
+    <code>A:</code> value register or pair; may be source or dest (16 bits)<br/>
+    <code>B:</code> instance field reference index (32 bits)
+  </td>
+  <td>Perform the identified object static field operation. See
+    <code>s<i>staticop</i></code> description above for details,
+    caveats, and suggestions.
+  </td>
+</tr>
+<tr>
+  <td>22ff..26ff 5rc</td>
+  <td>invoke-<i>kind</i>/jumbo {vCCCC .. vNNNN}, meth@BBBBBBBB<br/>
+    22ff: invoke-virtual/jumbo<br/>
+    23ff: invoke-super/jumbo<br/>
+    24ff: invoke-direct/jumbo<br/>
+    25ff: invoke-static/jumbo<br/>
+    26ff: invoke-interface/jumbo
+  </td>
+  <td>
+    <code>A:</code> argument word count (16 bits)<br/>
+    <code>B:</code> method reference index (32 bits)<br/>
+    <code>C:</code> first argument register (16 bits)<br/>
+    <code>N = A + C - 1</code>
+  </td>
+  <td>Call the indicated method. See first <code>invoke-<i>kind</i></code>
+    description above for details, caveats, and suggestions.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>packed-switch-payload</code> Format</h2>
+
+<table class="supplement">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>ident</td>
+  <td>ushort = 0x0100</td>
+  <td>identifying pseudo-opcode</td>
+</tr>
+<tr>
+  <td>size</td>
+  <td>ushort</td>
+  <td>number of entries in the table</td>
+</tr>
+<tr>
+  <td>first_key</td>
+  <td>int</td>
+  <td>first (and lowest) switch case value</td>
+</tr>
+<tr>
+  <td>targets</td>
+  <td>int[]</td>
+  <td>list of <code>size</code> relative branch targets. The targets are
+    relative to the address of the switch opcode, not of this table.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<p><b>Note:</b> The total number of code units for an instance of this
+table is <code>(size * 2) + 4</code>.</p>
+
+<h2><code>sparse-switch-payload</code> Format</h2>
+
+<table class="supplement">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>ident</td>
+  <td>ushort = 0x0200</td>
+  <td>identifying pseudo-opcode</td>
+</tr>
+<tr>
+  <td>size</td>
+  <td>ushort</td>
+  <td>number of entries in the table</td>
+</tr>
+<tr>
+  <td>keys</td>
+  <td>int[]</td>
+  <td>list of <code>size</code> key values, sorted low-to-high</td>
+</tr>
+<tr>
+  <td>targets</td>
+  <td>int[]</td>
+  <td>list of <code>size</code> relative branch targets, each corresponding
+    to the key value at the same index. The targets are
+    relative to the address of the switch opcode, not of this table.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<p><b>Note:</b> The total number of code units for an instance of this
+table is <code>(size * 4) + 2</code>.</p>
+
+<h2><code>fill-array-data-payload</code> Format</h2>
+
+<table class="supplement">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>ident</td>
+  <td>ushort = 0x0300</td>
+  <td>identifying pseudo-opcode</td>
+</tr>
+<tr>
+  <td>element_width</td>
+  <td>ushort</td>
+  <td>number of bytes in each element</td>
+</tr>
+<tr>
+  <td>size</td>
+  <td>uint</td>
+  <td>number of elements in the table</td>
+</tr>
+<tr>
+  <td>data</td>
+  <td>ubyte[]</td>
+  <td>data values</td>
+</tr>
+</tbody>
+</table>
+
+<p><b>Note:</b> The total number of code units for an instance of this
+table is <code>(size * element_width + 1) / 2 + 4</code>.</p>
+
+
+<h2>Mathematical Operation Details</h2>
+
+<p><b>Note:</b> Floating point operations must follow IEEE 754 rules, using
+round-to-nearest and gradual underflow, except where stated otherwise.</p>
+
+<table class="math">
+<thead>
+<tr>
+  <th>Opcode</th>
+  <th>C Semantics</th>
+  <th>Notes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>neg-int</td>
+  <td>int32 a;<br/>
+    int32 result = -a;
+  </td>
+  <td>Unary twos-complement.</td>
+</tr>
+<tr>
+  <td>not-int</td>
+  <td>int32 a;<br/>
+    int32 result = ~a;
+  </td>
+  <td>Unary ones-complement.</td>
+</tr>
+<tr>
+  <td>neg-long</td>
+  <td>int64 a;<br/>
+    int64 result = -a;
+  </td>
+  <td>Unary twos-complement.</td>
+</tr>
+<tr>
+  <td>not-long</td>
+  <td>int64 a;<br/>
+    int64 result = ~a;
+  </td>
+  <td>Unary ones-complement.</td>
+</tr>
+<tr>
+  <td>neg-float</td>
+  <td>float a;<br/>
+    float result = -a;
+  </td>
+  <td>Floating point negation.</td>
+</tr>
+<tr>
+  <td>neg-double</td>
+  <td>double a;<br/>
+    double result = -a;
+  </td>
+  <td>Floating point negation.</td>
+</tr>
+<tr>
+  <td>int-to-long</td>
+  <td>int32 a;<br/>
+    int64 result = (int64) a;
+  </td>
+  <td>Sign extension of <code>int32</code> into <code>int64</code>.</td>
+</tr>
+<tr>
+  <td>int-to-float</td>
+  <td>int32 a;<br/>
+    float result = (float) a;
+  </td>
+  <td>Conversion of <code>int32</code> to <code>float</code>, using
+    round-to-nearest. This loses precision for some values.
+  </td>
+</tr>
+<tr>
+  <td>int-to-double</td>
+  <td>int32 a;<br/>
+    double result = (double) a;
+  </td>
+  <td>Conversion of <code>int32</code> to <code>double</code>.</td>
+</tr>
+<tr>
+  <td>long-to-int</td>
+  <td>int64 a;<br/>
+    int32 result = (int32) a;
+  </td>
+  <td>Truncation of <code>int64</code> into <code>int32</code>.</td>
+</tr>
+<tr>
+  <td>long-to-float</td>
+  <td>int64 a;<br/>
+    float result = (float) a;
+  </td>
+  <td>Conversion of <code>int64</code> to <code>float</code>, using
+    round-to-nearest. This loses precision for some values.
+  </td>
+</tr>
+<tr>
+  <td>long-to-double</td>
+  <td>int64 a;<br/>
+    double result = (double) a;
+  </td>
+  <td>Conversion of <code>int64</code> to <code>double</code>, using
+    round-to-nearest. This loses precision for some values.
+  </td>
+</tr>
+<tr>
+  <td>float-to-int</td>
+  <td>float a;<br/>
+    int32 result = (int32) a;
+  </td>
+  <td>Conversion of <code>float</code> to <code>int32</code>, using
+    round-toward-zero. <code>NaN</code> and <code>-0.0</code> (negative zero)
+    convert to the integer <code>0</code>. Infinities and values with
+    too large a magnitude to be represented get converted to either
+    <code>0x7fffffff</code> or <code>-0x80000000</code> depending on sign.
+  </td>
+</tr>
+<tr>
+  <td>float-to-long</td>
+  <td>float a;<br/>
+    int64 result = (int64) a;
+  </td>
+  <td>Conversion of <code>float</code> to <code>int64</code>, using
+    round-toward-zero. The same special case rules as for
+    <code>float-to-int</code> apply here, except that out-of-range values
+    get converted to either <code>0x7fffffffffffffff</code> or
+    <code>-0x8000000000000000</code> depending on sign.
+  </td>
+</tr>
+<tr>
+  <td>float-to-double</td>
+  <td>float a;<br/>
+    double result = (double) a;
+  </td>
+  <td>Conversion of <code>float</code> to <code>double</code>, preserving
+    the value exactly.
+  </td>
+</tr>
+<tr>
+  <td>double-to-int</td>
+  <td>double a;<br/>
+    int32 result = (int32) a;
+  </td>
+  <td>Conversion of <code>double</code> to <code>int32</code>, using
+    round-toward-zero. The same special case rules as for
+    <code>float-to-int</code> apply here.
+  </td>
+</tr>
+<tr>
+  <td>double-to-long</td>
+  <td>double a;<br/>
+    int64 result = (int64) a;
+  </td>
+  <td>Conversion of <code>double</code> to <code>int64</code>, using
+    round-toward-zero. The same special case rules as for
+    <code>float-to-long</code> apply here.
+  </td>
+</tr>
+<tr>
+  <td>double-to-float</td>
+  <td>double a;<br/>
+    float result = (float) a;
+  </td>
+  <td>Conversion of <code>double</code> to <code>float</code>, using
+    round-to-nearest. This loses precision for some values.
+  </td>
+</tr>
+<tr>
+  <td>int-to-byte</td>
+  <td>int32 a;<br/>
+    int32 result = (a &lt;&lt; 24) &gt;&gt; 24;
+  </td>
+  <td>Truncation of <code>int32</code> to <code>int8</code>, sign
+    extending the result.
+  </td>
+</tr>
+<tr>
+  <td>int-to-char</td>
+  <td>int32 a;<br/>
+    int32 result = a &amp; 0xffff;
+  </td>
+  <td>Truncation of <code>int32</code> to <code>uint16</code>, without
+    sign extension.
+  </td>
+</tr>
+<tr>
+  <td>int-to-short</td>
+  <td>int32 a;<br/>
+    int32 result = (a &lt;&lt; 16) &gt;&gt; 16;
+  </td>
+  <td>Truncation of <code>int32</code> to <code>int16</code>, sign
+    extending the result.
+  </td>
+</tr>
+<tr>
+  <td>add-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a + b;
+  </td>
+  <td>Twos-complement addition.</td>
+</tr>
+<tr>
+  <td>sub-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a - b;
+  </td>
+  <td>Twos-complement subtraction.</td>
+</tr>
+<tr>
+  <td>rsub-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = b - a;
+  </td>
+  <td>Twos-complement reverse subtraction.</td>
+</tr>
+<tr>
+  <td>mul-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a * b;
+  </td>
+  <td>Twos-complement multiplication.</td>
+</tr>
+<tr>
+  <td>div-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a / b;
+  </td>
+  <td>Twos-complement division, rounded towards zero (that is, truncated to
+    integer). This throws <code>ArithmeticException</code> if
+    <code>b == 0</code>.
+  </td>
+</tr>
+<tr>
+  <td>rem-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a % b;
+  </td>
+  <td>Twos-complement remainder after division. The sign of the result
+    is the same as that of <code>a</code>, and it is more precisely
+    defined as <code>result == a - (a / b) * b</code>. This throws
+    <code>ArithmeticException</code> if <code>b == 0</code>.
+  </td>
+</tr>
+<tr>
+  <td>and-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a &amp; b;
+  </td>
+  <td>Bitwise AND.</td>
+</tr>
+<tr>
+  <td>or-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a | b;
+  </td>
+  <td>Bitwise OR.</td>
+</tr>
+<tr>
+  <td>xor-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a ^ b;
+  </td>
+  <td>Bitwise XOR.</td>
+</tr>
+<tr>
+  <td>shl-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a &lt;&lt; (b &amp; 0x1f);
+  </td>
+  <td>Bitwise shift left (with masked argument).</td>
+</tr>
+<tr>
+  <td>shr-int</td>
+  <td>int32 a, b;<br/>
+    int32 result = a &gt;&gt; (b &amp; 0x1f);
+  </td>
+  <td>Bitwise signed shift right (with masked argument).</td>
+</tr>
+<tr>
+  <td>ushr-int</td>
+  <td>uint32 a, b;<br/>
+    int32 result = a &gt;&gt; (b &amp; 0x1f);
+  </td>
+  <td>Bitwise unsigned shift right (with masked argument).</td>
+</tr>
+<tr>
+  <td>add-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a + b;
+  </td>
+  <td>Twos-complement addition.</td>
+</tr>
+<tr>
+  <td>sub-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a - b;
+  </td>
+  <td>Twos-complement subtraction.</td>
+</tr>
+<tr>
+  <td>mul-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a * b;
+  </td>
+  <td>Twos-complement multiplication.</td>
+</tr>
+<tr>
+  <td>div-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a / b;
+  </td>
+  <td>Twos-complement division, rounded towards zero (that is, truncated to
+    integer). This throws <code>ArithmeticException</code> if
+    <code>b == 0</code>.
+  </td>
+</tr>
+<tr>
+  <td>rem-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a % b;
+  </td>
+  <td>Twos-complement remainder after division. The sign of the result
+    is the same as that of <code>a</code>, and it is more precisely
+    defined as <code>result == a - (a / b) * b</code>. This throws
+    <code>ArithmeticException</code> if <code>b == 0</code>.
+  </td>
+</tr>
+<tr>
+  <td>and-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a &amp; b;
+  </td>
+  <td>Bitwise AND.</td>
+</tr>
+<tr>
+  <td>or-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a | b;
+  </td>
+  <td>Bitwise OR.</td>
+</tr>
+<tr>
+  <td>xor-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a ^ b;
+  </td>
+  <td>Bitwise XOR.</td>
+</tr>
+<tr>
+  <td>shl-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a &lt;&lt; (b &amp; 0x3f);
+  </td>
+  <td>Bitwise shift left (with masked argument).</td>
+</tr>
+<tr>
+  <td>shr-long</td>
+  <td>int64 a, b;<br/>
+    int64 result = a &gt;&gt; (b &amp; 0x3f);
+  </td>
+  <td>Bitwise signed shift right (with masked argument).</td>
+</tr>
+<tr>
+  <td>ushr-long</td>
+  <td>uint64 a, b;<br/>
+    int64 result = a &gt;&gt; (b &amp; 0x3f);
+  </td>
+  <td>Bitwise unsigned shift right (with masked argument).</td>
+</tr>
+<tr>
+  <td>add-float</td>
+  <td>float a, b;<br/>
+    float result = a + b;
+  </td>
+  <td>Floating point addition.</td>
+</tr>
+<tr>
+  <td>sub-float</td>
+  <td>float a, b;<br/>
+    float result = a - b;
+  </td>
+  <td>Floating point subtraction.</td>
+</tr>
+<tr>
+  <td>mul-float</td>
+  <td>float a, b;<br/>
+    float result = a * b;
+  </td>
+  <td>Floating point multiplication.</td>
+</tr>
+<tr>
+  <td>div-float</td>
+  <td>float a, b;<br/>
+    float result = a / b;
+  </td>
+  <td>Floating point division.</td>
+</tr>
+<tr>
+  <td>rem-float</td>
+  <td>float a, b;<br/>
+    float result = a % b;
+  </td>
+  <td>Floating point remainder after division. This function is different
+    than IEEE 754 remainder and is defined as
+    <code>result == a - roundTowardZero(a / b) * b</code>.
+  </td>
+</tr>
+<tr>
+  <td>add-double</td>
+  <td>double a, b;<br/>
+    double result = a + b;
+  </td>
+  <td>Floating point addition.</td>
+</tr>
+<tr>
+  <td>sub-double</td>
+  <td>double a, b;<br/>
+    double result = a - b;
+  </td>
+  <td>Floating point subtraction.</td>
+</tr>
+<tr>
+  <td>mul-double</td>
+  <td>double a, b;<br/>
+    double result = a * b;
+  </td>
+  <td>Floating point multiplication.</td>
+</tr>
+<tr>
+  <td>div-double</td>
+  <td>double a, b;<br/>
+    double result = a / b;
+  </td>
+  <td>Floating point division.</td>
+</tr>
+<tr>
+  <td>rem-double</td>
+  <td>double a, b;<br/>
+    double result = a % b;
+  </td>
+  <td>Floating point remainder after division. This function is different
+    than IEEE 754 remainder and is defined as
+    <code>result == a - roundTowardZero(a / b) * b</code>.
+  </td>
+</tr>
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/docs/dalvik-constraints.css b/docs/dalvik-constraints.css
new file mode 100644
index 0000000..a315a73
--- /dev/null
+++ b/docs/dalvik-constraints.css
@@ -0,0 +1,59 @@
+h1 {
+    font-family: serif;
+    color: #222266;
+}
+
+h2 {
+    font-family: serif;
+    border-top-style: solid;
+    border-top-width: 2px;
+    border-color: #ccccdd;
+    padding-top: 12px;
+    margin-top: 48px;
+    margin-bottom: 2px;
+    color: #222266;
+}
+
+@media print {
+    table {
+        font-size: 8pt;
+    }
+}
+
+@media screen {
+    table {
+        font-size: 10pt;
+    }
+}
+
+
+/* general for all tables */
+
+table {
+    border-collapse: collapse;
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table th {
+    font-family: sans-serif;
+    background: #aabbff;
+    text-align: left;
+}
+
+table td {
+    font-family: sans-serif;
+    border-top-style: solid;
+    border-bottom-style: solid;
+    border-width: 1px;
+    border-color: #aaaaff;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    padding-left: 4px;
+    padding-right: 6px;
+    background: #eeeeff;
+    margin-top: 4pt;
+    margin-bottom: 0pt;
+}
diff --git a/docs/dalvik-constraints.html b/docs/dalvik-constraints.html
new file mode 100644
index 0000000..78ba945
--- /dev/null
+++ b/docs/dalvik-constraints.html
@@ -0,0 +1,897 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+  <head>
+    <title>Dalvik bytecode constraints</title>
+    <link rel=stylesheet href="dalvik-constraints.css">
+  </head>
+
+  <body>
+
+    <h1>Dalvik bytecode constraints</h1>
+
+<!--
+    <h1>General integrity constraints</h1>
+
+    <table>
+      <tr>
+        <th>
+          Identifier
+        </th>
+
+        <th>
+          Description
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          A1
+        </td>
+
+        <td>
+          The magic number of the DEX file must be "dex\n035\0".
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A1
+        </td>
+
+        <td>
+          The checksum must be an Adler-32 checksum of the whole file contents
+          except magic and checksum field.
+        </td>
+      </tr>
+
+
+The signature must be a SHA-1 hash of the whole file contents except magic,
+checksum, and signature.
+
+The file_size must match the actual file size in bytes.
+
+The header_size must have the value 0x70.
+
+The endian_tag must have either the value ENDIAN_CONSTANT or
+REVERSE_ENDIAN_CONSTANT.
+
+For each of the link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs
+and data sections, the offset and size fields must be either both zero or both
+non-zero. In the latter case, the offset must be four-byte-aligned.
+
+All offset fields in the header except map_off must be four-byte-aligned.
+
+The map_off field must be either zero or point into the data section. In the
+latter case, the data section must exist.
+
+None of the link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs
+and data sections must overlap each other or the header.
+
+If a map exists, then each map entry must have a valid type. Each type may
+appear at most once.
+
+If a map exists, then each map entry must have a nonzero offset and size. The
+offset must point into the corresponding section of the file (i.e. a
+string_id_item must point into the string_ids section) and the explicit or
+implicit size of the item must match the actual contents and size of the
+section.
+
+If a map exists, then the offset of map entry n+1 must be greater or equal to
+the offset of map entry n plus then size of map entry n. This implies
+non-overlapping entries and low-to-high ordering.
+
+The following types of entries must have an offset that is
+four-byte-aligned: string_id_item, type_id_item, proto_id_item, field_id_item,
+method_id_item, class_def_item, type_list, code_item,
+annotations_directory_item.
+
+For each string_id_item, the string_data_off field must contain a valid
+reference into the data section. For the referenced string_data_item, the data
+field must contain a valid MUTF-8 string, and the utf16_size must match the
+decoded length of the string.
+
+For each type_id_item, the desciptor_idx field must contain a valid reference
+into the string_ids list. The referenced string must be a valid type descriptor.
+
+For each proto_id_item, the shorty_idx field must contain a valid reference
+into the string_ids list. The referenced string must be a valid shorty descriptor.
+Also, the return_type_idx field must be a valid index into the type_ids section,
+and the parameters_off field must be either zero or a valid offset pointing
+into the data section. If nonzero, the parameter list must not contain any void
+entries.
+
+For each field_id_item, both the class_idx and type_idx fields must be a valid
+ indices into the
+type_ids list. The entry referenced by class_idx must be a non-array reference type.
+In addition, the name_idx field must be a valid reference into the string_ids
+section, and the contents of the referenced entry must conform to the MemberName
+specification.
+
+For each method_id_item, the class_idx field must be a valid index into the
+type_ids section, and the
+referenced entry must be a non-array reference type. The proto_id field must
+be a valid reference into the proto_ids list. The name_idx field must be a
+valid reference into the string_ids
+section, and the contents of the referenced entry must conform to the MemberName
+specification.
+
+For each class_def_item, ...
+
+For each field_id_item, the class_idx field must be a valid index into the
+type_ids list. The referenced entry must be a non-array reference type.
+
+...
+
+-->
+
+    <h2>
+      Static constraints
+    </h2>
+
+    <p>
+    Static constraints are constraints on individual elements of the bytecode.
+    They usually can be checked without employing control or data-flow analysis
+    techniques.
+    </p>
+
+    <table>
+      <tr>
+        <th>
+          Identifier
+        </th>
+
+        <th>
+          Description
+        </th>
+
+        <th>
+          Spec equivalent
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          A1
+        </td>
+
+        <td>
+          The <code>insns</code> array must not be empty.
+        </td>
+
+        <td>
+          4.8.1.1
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A2
+        </td>
+
+        <td>
+          The first opcode in the <code>insns</code> array must have index zero.
+        </td>
+
+        <td>
+          4.8.1.3
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A3
+        </td>
+
+        <td>
+          The <code>insns</code> array must only contain valid Dalvik opcodes.
+        </td>
+
+        <td>
+          4.8.1.4
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A4
+        </td>
+
+        <td>
+          The index of instruction <code>n+1</code> must equal the index of
+          instruction <code>n</code> plus the length of instruction
+          <code>n</code>, taking into account possible operands.
+        </td>
+
+        <td>
+          4.8.1.5
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A5
+        </td>
+
+        <td>
+          The last instruction in the <code>insns</code> array must end at index
+          <code>insns_size-1</code>.
+        </td>
+
+        <td>
+          4.8.1.6
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A6
+        </td>
+
+        <td>
+          All <code>goto</code> and <code>if-&lt;kind&gt;</code> targets must
+          be opcodes within in the same method.
+        </td>
+
+        <td>
+          4.8.1.7
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A7
+        </td>
+
+        <td>
+          All targets of a <code>packed-switch</code> instruction must be
+          opcodes within in the same method. The size and the list of targets
+          must be consistent.
+        </td>
+
+        <td>
+          4.8.1.8
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A8
+        </td>
+
+        <td>
+          All targets of a <code>sparse-switch</code> instruction must be
+          opcodes within in the same method. The corresponding table must be
+          consistent and sorted low-to-high.
+        </td>
+
+        <td>
+          4.8.1.9
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A9
+        </td>
+
+        <td>
+          The <code>B</code> operand of the <code>const-string</code> and
+          <code>const-string/jumbo</code> instructions must be a valid index
+          into the string constant pool.
+        </td>
+
+        <td>
+          4.8.1.10
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A10
+        </td>
+
+        <td>
+          The <code>C</code> operand of the <code>iget&lt;kind&gt;</code> and
+          <code>iput&lt;kind&gt;</code> instructions must be a valid index into
+          the field constant pool. The referenced entry must represent an
+          instance field.
+        </td>
+
+        <td>
+          4.8.1.12
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A11
+        </td>
+
+        <td>
+          The <code>C</code> operand of the <code>sget&lt;kind&gt;</code> and
+          <code>sput&lt;kind&gt;</code> instructions must be a valid index into
+          the field constant pool. The referenced entry must represent a static
+          field.
+        </td>
+
+        <td>
+          4.8.1.12
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A12
+        </td>
+
+        <td>
+          The <code>C</code> operand of the <code>invoke-virtual</code>,
+          <code>invoke-super</code>, <code<invoke-direct</code> and
+          <code>invoke-static</code> instructions must be a valid index into the
+          method constant pool. In all cases, the referenced
+          <code>method_id</code> must belong to a class (not an interface).
+        </td>
+
+        <td>
+          4.8.1.13
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A13
+        </td>
+
+        <td>
+          The <code>B</code> operand of the <code>invoke-virtual/range</code>,
+          <code>invoke-super/range</code>, <code>invoke-direct/range</code>, and
+          <code>invoke-static/range</code> instructions must be a valid index
+          into the method constant pool. In all cases, the referenced
+          <code>method_id</code> must belong to a class (not an interface).
+        </td>
+
+        <td>
+          4.8.1.13
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A14
+        </td>
+
+        <td>
+          A method the name of which starts with a '<' must only be invoked
+          implicitly by the VM, not by code originating from a Dex file. The
+          only exception is the instance initializer, which may be invoked by
+          <code>invoke-direct</code>.
+        </td>
+
+        <td>
+          4.8.1.14
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A15
+        </td>
+
+        <td>
+          The <code>C</code> operand of the <code>invoke-interface</code>
+          instruction must be a valid index into the method constant pool. The
+          referenced <code>method_id</code> must belong to an interface (not a
+          class).
+        </td>
+
+        <td>
+          4.8.1.15
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A16
+        </td>
+
+        <td>
+          The <code>B</code> operand of the <code>invoke-interface/range</code>
+          instruction must be a valid index into the method constant pool.
+          The referenced <code>method_id</code> must belong to an interface (not
+          a class).
+        </td>
+
+        <td>
+          4.8.1.15
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A17
+        </td>
+
+        <td>
+          The <code>B</code> operand of the <code>const-class</code>,
+          <code>check-cast</code>, <code>new-instance</code>, and
+          <code>filled-new-array/range</code> instructions must be a valid index
+          into the type constant pool.
+        </td>
+
+        <td>
+          4.8.1.16
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A18
+        </td>
+
+        <td>
+          The <code>C</code> operand of the <code>instance-of</code>,
+          <code>new-array</code>, and <code>filled-new-array</code>
+          instructions must be a valid index into the type constant pool.
+        </td>
+
+        <td>
+          4.8.1.16
+        </td>
+      </tr>
+
+     <tr>
+        <td>
+          A19
+        </td>
+
+        <td>
+          The dimensions of an array created by a <code>new-array</code>
+          instruction must be less than <code>256</code>.
+        </td>
+
+        <td>
+          4.8.1.17
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A20
+        </td>
+
+        <td>
+          The <code>new</code> instruction must not refer to array classes,
+          interfaces, or abstract classes.
+        </td>
+
+        <td>
+          4.8.1.18
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A21
+        </td>
+
+        <td>
+          The type referred to by a <code>new-array</code> instruction must be
+          a valid, non-reference type.
+        </td>
+
+        <td>
+          4.8.1.20
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A22
+        </td>
+
+        <td>
+          All registers referred to by an instruction in a single-width
+          (non-pair) fashion must be valid for the current method. That is,
+          their indices must be non-negative and smaller than
+          <code>registers_size</code>.
+        </td>
+
+        <td>
+          4.8.1.21
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A23
+        </td>
+
+        <td>
+          All registers referred to by an instruction in a double-width (pair)
+          fashion must be valid for the current method. That is, their indices
+          must be non-negative and smaller than <code>registers_size-1</code>.
+        </td>
+
+        <td>
+          4.8.1.23
+        </td>
+      </tr>
+    </table>
+
+    <h2>
+      Structural constraints
+    </h2>
+
+    <p>
+    Structural constraints are constraints on relationships between several
+    elements of the bytecode. They usually can't be checked without employing
+    control or data-flow analysis techniques.
+    </p>
+
+    <table>
+      <tr>
+        <th>
+          Identifier
+        </th>
+
+        <th>
+          Description
+        </th>
+
+        <th>
+          Spec equivalent
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          B1
+        </td>
+
+        <td>
+          The number and types of arguments (registers and immediate values)
+          must always match the instruction.
+        </td>
+
+        <td>
+          4.8.2.1
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B2
+        </td>
+
+        <td>
+          Register pairs must never be broken up.
+        </td>
+
+        <td>
+          4.8.2.3
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B3
+        </td>
+
+        <td>
+          A register (or pair) has to be assigned first before it can be
+          read.
+        </td>
+
+        <td>
+          4.8.2.4
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B4
+        </td>
+
+        <td>
+          An <code>invoke-direct</code> instruction must only invoke an instance
+          initializer or a method in the current class or one of its
+          superclasses.
+        </td>
+
+        <td>
+          4.8.2.7
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B5
+        </td>
+
+        <td>
+          An instance initializer must only be invoked on an uninitialized
+          instance.
+        </td>
+
+        <td>
+          4.8.2.8
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B6
+        </td>
+
+        <td>
+          Instance methods may only be invoked on and instance fields may only
+          be accessed on already initialized instances.
+        </td>
+
+        <td>
+          4.8.2.9
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B7
+        </td>
+
+        <td>
+          A register which holds the result of a <code>new-instance</code>
+          instruction must not be used if the same
+          <code>new-instance</code> instruction is again executed before
+          the instance is initialized.
+        </td>
+
+        <td>
+          4.8.2.10
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B8
+        </td>
+
+        <td>
+           An instance initializer must call another instance initializer (same
+           class or superclass) before any instance members can be accessed.
+           Exceptions are non-inherited instance fields, which can be assigned
+           before calling another initializer, and the <code>Object</code> class
+           in general.
+        </td>
+
+        <td>
+          4.8.2.11
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B9
+        </td>
+
+        <td>
+           All actual method arguments must be assignment-compatible with their
+           respective formal arguments.
+        </td>
+
+        <td>
+          4.8.2.12
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B10
+        </td>
+
+        <td>
+           For each instance method invocation, the actual instance must be
+           assignment-compatible with the class or interface specified in the
+           instruction.
+        </td>
+
+        <td>
+          4.8.2.13
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B11
+        </td>
+
+        <td>
+           A <code>return&lt;kind&gt;</code> instruction must match its
+           method's return type.
+        </td>
+
+        <td>
+          4.8.2.14
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B12
+        </td>
+
+        <td>
+           When accessing protected members of a superclass, the actual type of
+           the instance being accessed must be either the current class or one
+           of its subclasses.
+        </td>
+
+        <td>
+          4.8.2.15
+        </td>
+      </tr>
+
+     <tr>
+        <td>
+          B13
+        </td>
+
+        <td>
+           The type of a value stored into a static field must be
+           assignment-compatible with or convertible to the field's type.
+        </td>
+
+        <td>
+          4.8.2.16
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B14
+        </td>
+
+        <td>
+           The type of a value stored into a field must be assignment-compatible
+           with or convertible to the field's type.
+        </td>
+
+        <td>
+          4.8.2.17
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B15
+        </td>
+
+        <td>
+           The type of every value stored into an array must be
+           assignment-compatible with the array's component type.
+        </td>
+
+        <td>
+          4.8.2.18
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B16
+        </td>
+
+        <td>
+           The <code>A</code> operand of a <code>throw</code> instruction must
+           be assignment-compatible with <code>java.lang.Throwable</code>.
+        </td>
+
+        <td>
+          4.8.2.19
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B17
+        </td>
+
+        <td>
+           The last reachable instruction of a method must either be a backwards
+           <code>goto</code> or branch, a <code>return</code>, or a
+           <code>throw</code> instruction. It must not be possible to leave the
+           <code>insns</code> array at the bottom.
+        </td>
+
+        <td>
+          4.8.2.20
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B18
+        </td>
+
+        <td>
+          The unassigned half of a former register pair may not be read (is
+          considered invalid) until it has been re-assigned by some other
+          instruction.
+        </td>
+
+        <td>
+          4.8.2.3, 4.8.2.4
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B19
+        </td>
+
+        <td>
+          A <code>move-result&lt;kind&gt;</code> instruction must be immediately
+          preceded (in the <code>insns</code> array) by an
+          <code>invoke-&lt;kind&gt;</code> instruction. The only exception is
+          the <code>move-result-object</code> instruction, which may also be
+          preceded by a <code>filled-new-array</code> instruction.
+        </td>
+
+        <td>
+          -
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B20
+        </td>
+
+        <td>
+          A <code>move-result&lt;kind&gt;</code> instruction must be immediately
+          preceded (in actual control flow) by a matching
+          <code>return-&lt;kind&gt;</code> instruction (it must not be jumped
+          to). The only exception is the <code>move-result-object</code>
+          instruction, which may also be preceded by a
+          <code>filled-new-array</code> instruction.
+        </td>
+
+        <td>
+          -
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B21
+        </td>
+
+        <td>
+          A <code>move-exception</code> instruction must only appear as the
+          first instruction in an exception handler.
+        </td>
+
+        <td>
+          -
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B22
+        </td>
+
+        <td>
+          The <code>packed-switch-data</code>, <code>sparse-switch-data</code>,
+          and <code>fill-array-data</code> pseudo-instructions must not be
+          reachable by control flow.
+        </td>
+
+        <td>
+          -
+        </td>
+      </tr>
+    </table>
+
+  </body>
+</html>
diff --git a/docs/debugger.html b/docs/debugger.html
new file mode 100644
index 0000000..1c47c7a
--- /dev/null
+++ b/docs/debugger.html
@@ -0,0 +1,243 @@
+<html>
+<head>
+<title>Dalvik Debugger Support</title>
+</head>
+
+<body>
+<h1>Dalvik Debugger Support</h1>
+
+<p>
+The Dalvik virtual machine supports source-level debugging with many popular
+development environments.  Any tool that allows remote debugging over JDWP
+(the
+<a href="http://java.sun.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html">
+Java Debug Wire Protocol</a>) is expected work.  Supported debuggers
+include jdb, Eclipse, IntelliJ, and JSwat.
+</p><p>
+The VM does not support tools based on JVMTI (Java Virtual
+Machine Tool Interface).  This is a relatively intrusive approach that
+relies on bytecode insertion, something the Dalvik VM does not currently
+support.
+</p><p>
+Dalvik's implementation of JDWP also includes hooks for supporting
+DDM (Dalvik Debug Monitor) features, notably as implemented by DDMS
+(Dalvik Debug Monitor Server) and the Eclipse ADT plugin.  The protocol
+and VM interaction is described in some detail
+<a href="debugmon.html">here</a>.
+</p><p>
+All of the debugger support in the VM lives in the <code>dalvik/vm/jdwp</code>
+directory, and is almost entirely isolated from the rest of the VM sources.
+<code>dalvik/vm/Debugger.c</code> bridges the gap.  The goal in doing so
+was to make it easier to re-use the JDWP code in other projects.
+</p><p>
+
+
+<h2>Implementation</h2>
+
+<p>
+Every VM that has debugging enabled starts a "JDWP" thread.  The thread
+typically sits idle until DDMS or a debugger connects.  The thread is
+only responsible for handling requests from the debugger; VM-initated
+communication, such as notifying the debugger when the VM has stopped at
+a breakpoint, are sent from the affected thread.
+</p><p>
+When the VM is started from the Android app framework, debugging is enabled
+for all applications when the system property <code>ro.debuggable</code>
+is set to </code>1</code> (use <code>adb shell getprop ro.debuggable</code>
+to check it).  If it's zero, debugging can be enabled via the application's
+manifest, which must include <code>android:debuggable="true"</code> in the
+<code>&lt;application&gt;</code> element.
+
+</p><p>
+The VM recognizes the difference between a connection from DDMS and a
+connection from a debugger (either directly or in concert with DDMS).
+A connection from DDMS alone doesn't result in a change in VM behavior,
+but when the VM sees debugger packets it allocates additional data
+structures and may switch to a different implementation of the interpreter.
+</p><p>
+Pre-Froyo implementations of the Dalvik VM used read-only memory mappings
+for all bytecode, which made it necessary to scan for breakpoints by
+comparing the program counter to a set of addresses.  In Froyo this was
+changed to allow insertion of breakpoint opcodes.  This allows the VM
+to execute code more quickly, and does away with the hardcoded limit
+of 20 breakpoints.  Even with this change, however, the debug-enabled
+interpreter is much slower than the regular interpreter (perhaps 5x).
+</p><p>
+The JDWP protocol is stateless, so the VM handles individual debugger
+requests as they arrive, and posts events to the debugger as they happen.
+</p><p>
+
+
+<h2>Debug Data</h2>
+<p> Source code debug data, which includes mappings of source code to
+bytecode and lists describing which registers are used to hold method
+arguments and local variables, are optionally emitted by the Java compiler.
+When <code>dx</code> converts Java bytecode to Dalvik bytecode, it must
+also convert this debug data.
+</p><p>
+<code>dx</code> must also ensure that it doesn't perform operations
+that confuse the debugger.  For example, re-using registers that hold
+method arguments and the "<code>this</code>" pointer is allowed in
+Dalvik bytecode if the values are never used or no longer needed.
+This can be very confusing for the debugger (and the programmer)
+since the values have method scope and aren't expected to disappear.  For
+this reason, <code>dx</code> generates sub-optimal code in some situations
+when debugging support is enabled.
+</p><p>
+Some of the debug data is used for other purposes; in particular, having
+filename and line number data is necessary for generating useful exception
+stack traces.  This data can be omitted by <code>dx</code> to make the DEX
+file smaller.
+</p><p>
+
+
+<h2>Usage</h2>
+
+<p>
+The Dalvik VM supports many of the same command-line flags that other popular
+desktop VMs do.  To start a VM with debugging enabled, you add a command-line
+flag with some basic options.  The basic incantation looks something
+like this:
+
+<pre>-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y</pre>
+or
+<pre>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y</pre>
+
+</p><p>
+After the initial prefix, options are provided as name=value pairs.  The
+options currently supported by the Dalvik VM are:
+<dl>
+    <dt>transport (no default)</dt>
+    <dd>Communication transport mechanism to use.  Dalvik supports
+    TCP/IP sockets (<code>dt_socket</code>) and connection over USB
+    through ADB (<code>dt_android_adb</code>).
+    </dd>
+
+    <dt>server (default='n')</dt>
+    <dd>Determines whether the VM acts as a client or a server.  When
+    acting as a server, the VM waits for a debugger to connect to it.
+    When acting as a client, the VM attempts to connect to a waiting
+    debugger.
+    </dd>
+
+    <dt>suspend (default='n')</dt>
+    <dd>If set to 'y', the VM will wait for a debugger connection
+    before executing application code.  When the debugger connects (or
+    when the VM finishes connecting to the debugger), the VM tells the
+    debugger that it has suspended, and will not proceed until told
+    to resume.  If set to 'n', the VM just plows ahead.
+    </dd>
+
+    <dt>address (default="")</dt>
+    <dd>This must be <code>hostname:port</code> when <code>server=n</code>,
+    but can be just <code>port</code> when <code>server=y</code>.  This
+    specifies the IP address and port number to connect or listen to.
+    <br>
+    Listening on port 0 has a special meaning: try to
+    listen on port 8000; if that fails, try 8001, 8002, and so on.  (This
+    behavior is non-standard and may be removed from a future release.)
+    <br>This option has no meaning for <code>transport=dt_android_adb</code>.
+    </dd>
+
+    <dt>help (no arguments)</dt>
+    <dd>If this is the only option, a brief usage message is displayed.
+    </dd>
+
+    <dt>launch, onthrow, oncaught, timeout</dt>
+    <dd>These options are accepted but ignored.
+    </dd>
+</dl>
+
+</p><p>
+To debug a program on an Android device using DDMS over USB, you could
+use a command like this:
+<pre>% dalvikvm -agentlib:jdwp=transport=dt_android_adb,suspend=y,server=y -cp /data/foo.jar Foo</pre>
+
+This tells the Dalvik VM to run the program with debugging enabled, listening
+for a connection from DDMS, and waiting for a debugger.  The program will show
+up with an app name of "?" in the process list, because it wasn't started
+from the Android application framework.  From here you would connect your
+debugger to the appropriate DDMS listen port (e.g.
+<code>jdb -attach localhost:8700</code> after selecting it in the app list).
+
+</p><p>
+To debug a program on an Android device using TCP/IP bridged across ADB,
+you would first need to set up forwarding:
+<pre>% adb forward tcp:8000 tcp:8000
+% adb shell dalvikvm -agentlib:jdwp=transport=dt_socket,address=8000,suspend=y,server=y -cp /data/foo.jar Foo</pre>
+and then <code>jdb -attach localhost:8000</code>.
+</p><p>
+(In the above examples, the VM will be suspended when you attach.  In jdb,
+type <code>cont</code> to continue.)
+</p><p>
+The DDMS integration makes the <code>dt_android_adb</code> transport much
+more convenient when debugging on an Android device, but when working with
+Dalvik on the desktop it makes sense to use the TCP/IP transport.
+</p><p>
+
+
+<h2>Known Issues and Limitations</h2>
+
+</p><p>
+Most of the optional features JDWP allows are not implemented.  These
+include field access watchpoints and better tracking of monitors.
+</p><p>
+Not all JDWP requests are implemented.  In particular, anything that
+never gets emitted by the debuggers we've used is not supported and will
+result in error messages being logged.  Support will be added when a
+use case is uncovered.
+</p><p>
+&nbsp;
+</p><p>
+The debugger and garbage collector are somewhat loosely
+integrated at present.  The VM currently guarantees that any object the
+debugger is aware of will not be garbage collected until after the
+debugger disconnects.  This can result in a build-up over time while the
+debugger is connected.  For example, if the debugger sees a running
+thread, the associated Thread object will not be collected, even after
+the thread terminates.
+</p><p>
+The only way to "unlock" the references is to detach and reattach the
+debugger.
+</p><p>
+&nbsp;
+</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>
+&nbsp;
+</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 &copy; 2009 The Android Open Source Project</address>
+</p>
+
+</body>
+</html>
diff --git a/docs/debugmon.html b/docs/debugmon.html
new file mode 100644
index 0000000..8021145
--- /dev/null
+++ b/docs/debugmon.html
@@ -0,0 +1,736 @@
+<HTML>
+
+
+<head>
+  <title>Dalvik VM Debug Monitor</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <link href="http://www.google.com/favicon.ico" type="image/x-icon"
+ rel="shortcut icon">
+  <link href="../android.css" type="text/css" rel="stylesheet">
+  <script language="JavaScript1.2" type="text/javascript">
+function highlight(name) {
+  if (document.getElementById) {
+    tags              = [ 'span', 'div', 'tr', 'td' ];
+    for (i in tags) {
+      elements        = document.getElementsByTagName(tags[i]);
+      if (elements) {
+        for (j = 0; j < elements.length; j++) {
+          elementName = elements[j].getAttribute("id");
+          if (elementName == name) {
+            elements[j].style.backgroundColor = "#C0F0C0";
+          } else if (elementName && elementName.indexOf("rev") == 0) {
+            elements[j].style.backgroundColor = "#FFFFFF";
+          }
+        }
+      }
+    }
+  }
+}
+  </script>
+</head>
+<body onload="prettyPrint()">
+
+<h1><a name="My_Project_"></a>Dalvik VM<br>Debug Monitor</h1>
+
+<!-- Status is one of: Draft, Current, Needs Update, Obsolete -->
+<p style="text-align:center"><strong>Status:</strong><em>Draft</em> &nbsp;
+<small>(as of March 6, 2007)</small></p>
+<address>
+[authors]
+</address>
+
+<!-- last modified date can be different to the "Status date." It automatically
+updates
+whenever the file is modified. -->
+<i>Modified:</i>
+ <!-- this script automatically sets the modified date,you don't need to modify
+it -->
+    <script type=text/javascript>
+        <!--
+        var lm = new Date(document.lastModified);
+        document.write(lm.toDateString());
+        //-->
+        </script>
+</address>
+
+<p><br>
+<HR>
+
+<h2>Introduction</h2>
+
+<p>It's extremely useful to be able to monitor the live state of the
+VM.  For Android, we need to monitor multiple VMs running on a device
+connected through USB or a wireless network connection.  This document
+describes a debug monitor server that interacts with multiple VMs, and
+an API that VMs and applications can use to provide information
+to the monitor.
+
+<p>Some things we can monitor with the Dalvik Debug Monitor ("DDM"):
+<ul>
+    <li> Thread states.  Track thread creation/exit, busy/idle status.
+    <li> Overall heap status, useful for a heap bitmap display or
+    fragmentation analysis.
+</ul>
+
+<p>It is possible for something other than a VM to act as a DDM client, but
+that is a secondary goal.  Examples include "logcat" log extraction
+and system monitors for virtual memory usage and load average.
+
+<p>It's also possible for the DDM server to be run on the device, with
+the information presented through the device UI.  However, the initial goal
+is to provide a display tool that takes advantage of desktop tools and
+screen real estate.
+
+<p>This work is necessary because we are unable to use standard JVMTI-based
+tools with Dalvik.  JVMTI relies on bytecode insertion, which is not
+currently possible because Dalvik doesn't support Java bytecode.
+
+<p>The DDM server is written in the Java programming language
+for portability.  It uses a desktop
+UI toolkit (SWT) for its interface.
+
+
+<h2>Protocol</h2>
+
+<p>To take advantage of existing infrastructure we are piggy-backing the
+DDM protocol on top of JDWP (the Java Debug Wire Protocol, normally spoken
+between a VM and a debugger).  To a
+non-DDM client, the DDM server just looks like a debugger.
+
+<p>The JDWP protocol is very close to what we want to use.  In particular:
+<ul>
+    <li>It explicitly allows for vendor-defined packets, so there is no
+    need to "bend" the JDWP spec.
+    <li>Events may be posted from the VM at arbitrary points.  Such
+    events do not elicit a response from the debugger, meaning the client
+    can post data and immediately resume work without worrying about the
+    eventual response.
+    <li>The basic protocol is stateless and asynchronous.  Request packets
+    from the debugger side include a serial number, which the VM includes
+    in the response packet.  This allows multiple simultaneous
+    conversations, which means the DDM traffic can be interleaved with
+    debugger traffic.
+</ul>
+
+<p>There are a few issues with using JDWP for our purposes:
+<ul>
+    <li>The VM only expects one connection from a debugger, so you couldn't
+    attach the monitor and a debugger at the same time.  This will be
+    worked around by connecting the debugger to the monitor and passing the
+    traffic through.  (We're already doing the pass-through with "jdwpspy";
+    requires some management of our request IDs though.)  This should
+    be more convenient than the current "guess the port
+    number" system when we're attached to a device.
+    <li>The VM behaves differently when a debugger is attached.  It will
+    run more slowly, and any objects passed to the monitor or debugger are
+    immune to GC.  We can work around this by not enabling the slow path
+    until non-DDM traffic is observed.  We also want to have a "debugger
+    has connected/disconnected" message that allows the VM to release
+    debugger-related resources without dropping the net connection.
+    <li>Non-DDM VMs should not freak out when DDM connects.  There are
+    no guarantees here for 3rd-party VMs (e.g. a certain mainstream VM,
+    which crashes instantly), but our older JamVM can be
+    configured to reject the "hello" packet.
+</ul>
+
+
+<h3>Connection Establishment</h3>
+
+<p>There are two basic approaches: have the server contact the VMs, and
+have the VMs contact the server.  The former is less "precise" than the
+latter, because you have to scan for the clients, but it has some
+advantages.
+
+<p>There are three interesting scenarios:
+<ol>
+    <li>The DDM server is started, then the USB-attached device is booted
+    or the simulator is launched.
+    <li>The device or simulator is already running when the DDM server
+    is started.
+    <li>The DDM server is running when an already-started device is
+    attached to USB.
+</ol>
+<p>If we have the VMs connect to the DDM server on startup, we only handle
+case #1.  If the DDM server scans for VMs when it starts, we only handle
+case #2.  Neither handles case #3, which is probably the most important
+of the bunch as the device matures.
+<p>The plan is to have a drop-down menu with two entries,
+"scan workstation" and "scan device".
+The former causes the DDM server to search for VMs on "localhost", the
+latter causes it to search for VMs on the other side of an ADB connection.
+The DDM server will scan for VMs every few seconds, either checking a
+range of known VM ports (e.g. 8000-8040) or interacting with some sort
+of process database on the device.  Changing modes causes all existing
+connections to be dropped.
+<p>When the DDM server first starts, it will try to execute "adb usb"
+to ensure that the ADB server is running.  (Note it will be necessary
+to launch the DDM server from a shell with "adb" in the path.)  If this
+fails, talking to the device will still be possible so long as the ADB
+daemon is already running.
+
+<h4>Connecting a Debugger</h4>
+
+<p>With the DDM server sitting on the JDWP port of all VMs, it will be
+necessary to connect the debugger through the DDM server.  Each VM being
+debugged will have a separate port being listened to by the DDM server,
+allowing you to connect a debugger to one or more VMs simultaneously.
+
+<p>In the common case, however, the developer will only want to debug
+a single VM.  One port (say 8700) will be listened to by the DDM server,
+and anything connecting to it will be connected to the "current VM"
+(selected in the UI).  This should allow developers to focus on a
+single application, which may otherwise shift around in the ordering, without
+having to adjust their IDE settings to a different port every time they
+restart the device.
+
+
+<h3>Packet Format</h3>
+
+<p>Information is sent in chunks.  Each chunk starts with:
+<pre>
+u4   type
+u4   length
+</pre>
+and contains a variable amount of type-specific data.
+Unrecognized types cause an empty response from the client and
+are quietly ignored by the server.  [Should probably return an error;
+need an "error" chunk type and a handler on the server side.]
+
+<p>The same chunk type may have different meanings when sent in different
+directions.  For example, the same type may be used for both a query and
+a response to the query.  For sanity the type must always be used in
+related transactions.
+
+<p>This is somewhat redundant with the JDWP framing, which includes a
+4-byte length and a two-byte type code ("command set" and "command"; a
+range of command set values is designated for "vendor-defined commands
+and extensions").  Using the chunk format allows us to remain independent
+of the underlying transport, avoids intrusive integration
+with JDWP client code, and provides a way to send multiple chunks in a
+single transmission unit.  [I'm taking the multi-chunk packets into
+account in the design, but do not plan to implement them unless the need
+arises.]
+
+<p>Because we may be sending data over a slow USB link, the chunks may be
+compressed.  Compressed chunks are written as a chunk type that
+indicates the compression, followed by the compressed length, followed
+by the original chunk type and the uncompressed length.  For zlib's deflate
+algorithm, the chunk type is "ZLIB".
+
+<p>Following the JDWP model, packets sent from the server to the client
+are always acknowledged, but packets sent from client to server never are.
+The JDWP error code field is always set to "no error"; failure responses
+from specific requests must be encoded into the DDM messages.
+
+<p>In what follows "u4" is an unsigned 32-bit value and "u1" is an
+unsigned 8-bit value.  Values are written in big-endian order to match
+JDWP.
+
+
+<h3>Initial Handshake</h3>
+
+<p>After the JDWP handshake, the server sends a HELO chunk to the client.
+If the client's JDWP layer rejects it, the server assumes that the client
+is not a DDM-aware VM, and does not send it any further DDM queries.
+<p>On the client side, upon seeing a HELO it can know that a DDM server
+is attached and prepare accordingly.  The VM should not assume that a
+debugger is attached until a non-DDM packet arrives.
+
+<h4>Chunk HELO (server --&gt; client)</h4>
+<p>Basic "hello" message.
+<pre>
+u4   DDM server protocol version
+</pre>
+
+
+<h4>Chunk HELO (client --&gt; server, reply only)</h4>
+Information about the client.  Must be sent in response to the HELO message.
+<pre>
+u4   DDM client protocol version
+u4   pid
+u4   VM ident string len (in 16-bit units)
+u4   application name len (in 16-bit units)
+var  VM ident string (UTF-16)
+var  application name (UTF-16)
+</pre>
+
+<p>If the client does not wish to speak to the DDM server, it should respond
+with a JDWP error packet.  This is the same behavior you'd get from a VM
+that doesn't support DDM.
+
+
+<h3>Debugger Management</h3>
+<p>VMs usually prepare for debugging when a JDWP connection is established,
+and release debugger-related resources when the connection drops.  We want
+to open the JDWP connection early and hold it open after the debugger
+disconnects.
+<p>The VM can tell when a debugger attaches, because it will start seeing
+non-DDM JDWP traffic, but it can't identify the disconnect.  For this reason,
+we need to send a packet to the client when the debugger disconnects.
+<p>If the DDM server is talking to a non-DDM-aware client, it will be
+necessary to drop and re-establish the connection when the debugger goes away.
+(This also works with DDM-aware clients; this packet is an optimization.)
+
+<h4>Chunk DBGD (server --&gt; client)</h4>
+<p>Debugger has disconnected.  The client responds with a DBGD to acknowledge
+receipt.  No data in request, no response required.
+
+
+<h3>VM Info</h3>
+<p>Update the server's info about the client.
+
+<h4>Chunk APNM (client --&gt; server)</h4>
+
+<p>If a VM's application name changes -- possible in our environment because
+of the "pre-initialized" app processes -- it must send up one of these.
+<pre>
+u4   application name len (in 16-bit chars)
+var  application name (UTF-16)
+</pre>
+
+<h4>Chunk WAIT (client --&gt; server)</h4>
+
+<p>This tells DDMS that one or more threads are waiting on an external
+event.  The simplest use is to tell DDMS that the VM is waiting for a
+debugger to attach.
+<pre>
+u1   reason  (0 = wait for debugger)
+</pre>
+If DDMS is attached, the client VM sends this up when waitForDebugger()
+is called.  If waitForDebugger() is called before DDMS attaches, the WAIT
+chunk will be sent up at about the same time as the HELO response.
+
+
+<h3>Thread Status</h3>
+
+<p>The client can send updates when their status changes, or periodically
+send thread state info, e.g. 2x per
+second to allow a "blinkenlights" display of thread activity.
+
+<h4>Chunk THEN (server --&gt; client)</h4>
+
+<p>Enable thread creation/death notification.
+<pre>
+u1   boolean (true=enable, false=disable)
+</pre>
+<p>The response is empty.  The client generates THCR packets for all
+known threads.  (Note the THCR packets may arrive before the THEN
+response.)
+
+<h4>Chunk THCR (client --&gt; server)</h4>
+<p>Thread Creation notification.
+<pre>
+u4   VM-local thread ID (usually a small int)
+u4   thread name len (in 16-bit chars)
+var  thread name (UTF-16)
+</pre>
+
+<h4>Chunk THDE (client --&gt; server)</h4>
+<p>Thread Death notification.
+<pre>
+u4   VM-local thread ID
+</pre>
+
+<h4>Chunk THST (server --&gt; client)</h4>
+
+<p>Enable periodic thread activity updates.
+Threads in THCR messages are assumed to be in the "initializing" state.  A
+THST message should follow closely on the heels of THCR.
+<pre>
+u4   interval, in msec
+</pre>
+<p>An interval of 0 disables the updates.  This is done periodically,
+rather than every time the thread state changes, to reduce the amount
+of data that must be sent for an actively running VM.
+
+<h4>Chunk THST (client --&gt; server)</h4>
+<p>Thread Status, describing the state of one or more threads.  This is
+most useful when creation/death notifications are enabled first.  The
+overall layout is:
+<pre>
+u4   count
+var  thread data
+</pre>
+Then, for every thread:
+<pre>
+u4   VM-local thread ID
+u1   thread state
+u1   suspended
+</pre>
+<p>"thread state" must be one of:
+<ul>    <!-- don't use ol, we may need (-1) or sparse -->
+    <li> 1 - running (now executing or ready to do so)
+    <li> 2 - sleeping (in Thread.sleep())
+    <li> 3 - monitor (blocked on a monitor lock)
+    <li> 4 - waiting (in Object.wait())
+    <li> 5 - initializing
+    <li> 6 - starting
+    <li> 7 - native (executing native code)
+    <li> 8 - vmwait (waiting on a VM resource)
+</ul>
+<p>"suspended" will be 0 if the thread is running, 1 if not.
+<p>[Any reason not to make "suspended" be the high bit of "thread state"?
+Do we need to differentiate suspend-by-GC from suspend-by-debugger?]
+<p>[We might be able to send the currently-executing method.  This is a
+little risky in a running VM, and increases the size of the messages
+considerably, but might be handy.]
+
+
+<h3>Heap Status</h3>
+
+<p>The client sends what amounts to a color-coded bitmap to the server,
+indicating which stretches of memory are free and which are in use.  For
+compactness the bitmap is run-length encoded, and based on multi-byte
+"allocation units" rather than byte counts.
+
+<p>In the future the server will be able to correlate the bitmap with more
+detailed object data, so enough information is provided to associate the
+bitmap data with virtual addresses.
+
+<p>Heaps may be broken into segments within the VM, and due to memory
+constraints it may be desirable to send the bitmap in smaller pieces,
+so the protocol allows the heap data to be sent in several chunks.
+To avoid ambiguity, the client is required
+to send explicit "start" and "end" messages during an update.
+
+<p>All messages include a "heap ID" that can be used to differentiate
+between multiple independent virtual heaps or perhaps a native heap.  The
+client is allowed to send information about different heaps simultaneously,
+so all heap-specific information is tagged with a "heap ID".
+
+<h4>Chunk HPIF (server --&gt; client)</h4>
+<p>Request heap info.
+<pre>
+u1   when to send
+</pre>
+<p>The "when" values are:
+<pre>
+0: never
+1: immediately
+2: at the next GC
+3: at every GC
+</pre>
+
+<h4>Chunk HPIF (client --&gt; server, reply only)</h4>
+<p>Heap Info.  General information about the heap, suitable for a summary
+display.
+<pre>
+u4   number of heaps
+</pre>
+For each heap:
+<pre>
+u4   heap ID
+u8   timestamp in ms since Unix epoch
+u1   capture reason (same as 'when' value from server)
+u4   max heap size in bytes (-Xmx)
+u4   current heap size in bytes
+u4   current number of bytes allocated
+u4   current number of objects allocated
+</pre>
+<p>[We can get some of this from HPSG, more from HPSO.]
+<p>[Do we need a "heap overhead" stat here, indicating how much goes to
+waste?  e.g. (8 bytes per object * number of objects)]
+
+<h4>Chunk HPSG (server --&gt; client)</h4>
+<p>Request transmission of heap segment data.
+<pre>
+u1   when to send
+u1   what to send
+</pre>
+<p>The "when" to send will be zero to disable transmission, 1 to send
+during a GC.  Other values are currently undefined.  (Could use to pick
+which part of the GC to send it, or cause periodic transmissions.)
+<p>The "what" field is currently 0 for HPSG and 1 for HPSO.
+<p>No reply is expected.
+
+<h4>Chunk NHSG (server --&gt; client)</h4>
+<p>Request transmission of native heap segment data.
+<pre>
+u1   when to send
+u1   what to send
+</pre>
+<p>The "when" to send will be zero to disable transmission, 1 to send
+during a GC.  Other values are currently undefined.
+<p>The "what" field is currently ignored.
+<p>No reply is expected.
+
+<h4>Chunk HPST/NHST (client --&gt; server)</h4>
+<p>This is a Heap Start message.  It tells the server to discard any
+existing notion of what the client's heap looks like, and prepare for
+new information.  HPST indicates a virtual heap dump and must be followed
+by zero or more HPSG/HPSO messages and an HPEN.  NHST indicates a native
+heap dump and must be followed by zero or more NHSG messages and an NHEN.
+
+<p>The only data item is:
+<pre>
+u4   heap ID
+</pre>
+
+<h4>Chunk HPEN/NHEN (client --&gt; server)</h4>
+<p>Heap End, indicating that all information about the heap has been sent.
+A HPST will be paired with an HPEN and an NHST will be paired with an NHEN.
+
+<p>The only data item is:
+<pre>
+u4   heap ID
+</pre>
+
+<h4>Chunk HPSG (client --&gt; server)</h4>
+<p>Heap segment data.  Each chunk describes all or part of a contiguous
+stretch of heap memory.
+<pre>
+u4   heap ID
+u1   size of allocation unit, in bytes (e.g. 8 bytes)
+u4   virtual address of segment start
+u4   offset of this piece (relative to the virtual address)
+u4   length of piece, in allocation units
+var  usage data
+</pre>
+<p>The "usage data" indicates the status of each allocation unit.  The data
+is a stream of pairs of bytes, where the first byte indicates the state
+of the allocation unit, and the second byte indicates the number of
+consecutive allocation units with the same state.
+<p>The bits in the "state" byte have the following meaning:
+<pre>
++---------------------------------------+
+|  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
++---------------------------------------+
+|  P | U0 | K2 | K1 | K0 | S2 | S1 | S0 |
++---------------------------------------+
+</pre>
+<ul>
+    <li>'S': solidity
+    <ul>
+        <li>0=free
+        <li>1=has hard reference
+        <li>2=has soft reference
+        <li>3=has weak reference
+        <li>4=has phantom reference
+        <li>5=pending finalization
+        <li>6=marked, about to be swept
+    </ul>
+    <li>'K': kind
+    <ul>
+        <li>0=object
+        <li>1=class object
+        <li>2=array of byte/boolean
+        <li>3=array of char/short
+        <li>4=array of Object/int/float
+        <li>5=array of long/double
+    </ul>
+    <li>'P': partial flag (not used for HPSG)
+    <li>'U': unused, must be zero
+</ul>
+
+<p>The use of the various 'S' types depends on when the information is
+sent.  The current plan is to send it either immediately after a GC,
+or between the "mark" and "sweep" phases of the GC.  For a fancy generational
+collector, we may just want to send it up periodically.
+
+<p>The run-length byte indicates the number of allocation units minus one, so a
+length of 255 means there are 256 consecutive units with this state.  In
+some cases, e.g. arrays of bytes, the actual size of the data is rounded
+up the nearest allocation unit.
+<p>For HPSG, the runs do not end at object boundaries.  It is not possible
+to tell from this bitmap whether a run contains one or several objects.
+(But see HPSO, below.)
+<p>[If we find that we have many long runs, we can overload the 'P' flag
+or dedicate the 'U' flag to indicate that we have a 16-bit length instead
+of 8-bit.  We can also use a variable-width integer scheme for the length,
+encoding 1-128 in one byte, 1-16384 in two bytes, etc.]
+<p>[Alternate plan for 'K': array of byte, array of char, array of Object,
+array of miscellaneous primitive type]
+<p>To parse the data, the server runs through the usage data until either
+(a) the end of the chunk is reached, or (b) all allocation units have been
+accounted for.  (If these two things don't happen at the same time, the
+chunk is rejected.)
+<p>Example: suppose a VM has a heap at 0x10000 that is 0x2000 bytes long
+(with an 8-byte allocation unit size, that's 0x0400 units long).
+The client could send one chunk (allocSize=8, virtAddr=0x10000, offset=0,
+length=0x0400) or two (allocSize=8, virtAddr=0x10000, offset=0, length=0x300;
+then allocSize=8, virtAddr=0x10000, offset=0x300, length=0x100).
+<p>The client must encode the entire heap, including all free space at
+the end, or the server will not have an accurate impression of the amount
+of memory in the heap.  This refers to the current heap size, not the
+maximum heap size.
+
+<h4>Chunk HPSO (client --&gt; server)</h4>
+<p>This is essentially identical to HPSG, but the runs are terminated at
+object boundaries.  If an object is larger than 256 allocation units, the
+"partial" flag is set in all runs except the last.
+<p>The resulting unpacked bitmap is identical, but the object boundary
+information can be used to gain insights into heap layout.
+<p>[Do we want to have a separate message for this?  Maybe just include
+a "variant" flag in the HPST packet.  Another possible form of output
+would be one that indicates the age, in generations, of each block of
+memory.  That would provide a quick visual indication of "permanent vs.
+transient residents", perhaps with a 16-level grey scale.]
+
+<h4>Chunk NHSG (client --&gt; server)</h4>
+<p>Native heap segment data.  Each chunk describes all or part of a
+contiguous stretch of native heap memory.  The format is the same as
+for HPSG, except that only solidity values 0 (= free) and 1 (= hard
+reference) are used, and the kind value is always 0 for free chunks
+and 7 for allocated chunks, indicating a non-VM object.
+<pre>
+u4   heap ID
+u1   size of allocation unit, in bytes (e.g. 8 bytes)
+u4   virtual address of segment start
+u4   offset of this piece (relative to the virtual address)
+u4   length of piece, in allocation units
+var  usage data
+</pre>
+
+<h3>Generic Replies</h3>
+
+The client-side chunk handlers need a common way to report simple success
+or failure.  By convention, an empty reply packet indicates success.
+
+<h4>Chunk FAIL (client --&gt; server, reply only)</h4>
+<p>The chunk includes a machine-readable error code and a
+human-readable error message.  Server code can associate the failure
+with the original request by comparing the JDWP packet ID.
+<p>This allows a standard way of, for example, rejecting badly-formed
+request packets.
+<pre>
+u4   error code
+u4   error message len (in 16-bit chars)
+var  error message (UTF-16)
+</pre>
+
+<h3>Miscellaneous</h3>
+
+<h4>Chunk EXIT (server --&gt; client)</h4>
+<p>Cause the client to exit with the specified status, using System.exit().
+Useful for certain kinds of testing.
+<pre>
+u4   exit status
+</pre>
+
+<h4>Chunk DTRC (server --&gt; client)</h4>
+<p>[TBD] start/stop dmtrace; can send the results back over the wire.  For
+size reasons we probably need "sending", "data", "key", "finished" as
+4 separate chunks/packets rather than one glob.
+
+
+<h2>Client API</h2>
+
+<p>The API is written in the Java programming language
+for convenience.  The code is free to call native methods if appropriate.
+
+<h3>Chunk Handler API</h3>
+
+<p>The basic idea is that arbitrary code can register handlers for
+specific chunk types.  When a DDM chunk with that type arrives, the
+appropriate handler is invoked.  The handler's return value provides the
+response to the server.
+
+<p>There are two packages.  android.ddm lives in the "framework" library,
+and has all of the chunk handlers and registration code.  It can freely
+use Android classes.  org.apache.harmony.dalvik.ddmc lives in the "core"
+library, and has
+some base classes and features that interact with the VM.  Nothing should
+need to modify the org.apache.harmony.dalvik.ddmc classes.
+
+<p>The DDM classes pass chunks of data around with a simple class:
+
+<pre class=prettyprint>
+class Chunk {
+    int type;
+    byte[] data;
+    int offset, length;
+};
+</pre>
+
+<p>The chunk handlers accept and return them:
+<pre class=prettyprint>
+public Chunk handleChunk(Chunk request)
+</pre>
+<p>The code is free to parse the chunk and generate a response in any
+way it chooses.  Big-endian byte ordering is recommended but not mandatory.
+<p>Chunk handlers will be notified when a DDM server connects or disconnects,
+so that they can perform setup and cleanup operations:
+<pre class=prettyprint>
+public void connected()
+public void disconnected()
+</pre>
+
+<p>The method processes the request, formulates a response, and returns it.
+If the method returns null, an empty JDWP success message will be returned.
+<p>The request/response interaction is essentially asynchronous in the
+protocol.  The packets are linked together with the JDWP message ID.
+<p>[We could use ByteBuffer here instead of byte[], but it doesn't gain
+us much.  Wrapping a ByteBuffer around an array is easy.  We don't want
+to pass the full packet in because we could have multiple chunks in one
+request packet.  The DDM code needs to collect and aggregate the responses
+to all chunks into a single JDWP response packet.  Parties wanting to
+write multiple chunks in response to a single chunk should send a null
+response back and use "sendChunk()" to send the data independently.]
+
+<h3>Unsolicited event API</h3>
+
+<p>If a piece of code wants to send a chunk of data to the server at some
+arbitrary time, it may do so with a method provided by
+org.apache.harmony.dalvik.DdmServer:
+
+<pre class=prettyprint>
+public static void sendChunk(Chunk chunk)
+</pre>
+
+<p>There is no response or status code.  No exceptions are thrown.
+
+
+<h2>Server API</h2>
+
+<p>This is similar to the client side in many ways, but makes extensive
+use of ByteBuffer in a perhaps misguided attempt to use java.nio.channels
+and avoid excessive thread creation and unnecessary data copying.
+
+<p>Upon receipt of a packet, the server will identify it as one of:
+<ol>
+    <li>Message to be passed through to the debugger
+    <li>Response to an earlier request
+    <li>Unsolicited event packet
+</ol>
+<p>To handle (2), when messages are sent from the server to the client,
+the message must be paired with a callback method.  The response might be
+delayed for a while -- or might never arrive -- so the server can't block
+waiting for responses from the client.
+<p>The chunk handlers look like this:
+<pre class=prettyprint>
+public void handleChunk(Client client, int type,
+    ByteBuffer data, boolean isReply, int msgId)
+</pre>
+<p>The arguments are:
+<dl>
+    <dt>client
+    <dd>An object representing the client VM that send us the packet.
+    <dt>type
+    <dd>The 32-bit chunk type.
+    <dt>data
+    <dd>The data.  The data's length can be determined by calling data.limit().
+    <dt>isReply
+    <dd>Set to "true" if this was a reply to a message we sent earlier,
+    "false" if the client sent this unsolicited.
+    <dt>msgId
+    <dd>The JDWP message ID.  Useful for connecting replies with requests.
+</dl>
+<p>If a handler doesn't like the contents of a packet, it should log an
+error message and return.  If the handler doesn't recognize the packet at
+all, it can call the superclass' handleUnknownChunk() method.
+
+<p>As with the client, the server code can be notified when clients
+connect or disconnect.  This allows the handler to send initialization
+code immediately after a connect, or clean up after a disconnect.
+<p>Data associated with a client can be stored in a ClientData object,
+which acts as a general per-client dumping around for VM and UI state.
+
+
+<P><BR>
+
+<HR>
+
+<address>Copyright &copy; 2007 The Android Open Source Project</address>
+
+</body>
+</HTML>
diff --git a/docs/dex-format.css b/docs/dex-format.css
new file mode 100644
index 0000000..153dd4e
--- /dev/null
+++ b/docs/dex-format.css
@@ -0,0 +1,387 @@
+h1 {
+    font-family: serif;
+    border-top-style: solid;
+    border-top-width: 5px;
+    padding-top: 9pt;
+    margin-top: 40pt;
+    color: #222266;
+}
+
+h1.title {
+    border: none;
+}
+
+h2 {
+    font-family: serif;
+    border-top-style: solid;
+    border-top-width: 2px;
+    border-color: #ccccdd;
+    padding-top: 9pt;
+    margin-top: 40pt;
+    margin-bottom: 2pt;
+    color: #222266;
+}
+
+h3 {
+    font-family: serif;
+    font-style: bold;
+    margin-top: 20pt;
+    margin-bottom: 2pt;
+    color: #222266;
+}
+
+h4 {
+    font-family: serif;
+    font-style: italic;
+    margin-top: 2pt;
+    margin-bottom: 2pt;
+    color: #666688;
+}
+
+@media print {
+    table {
+        font-size: 8pt;
+    }
+}
+
+@media screen {
+    table {
+        font-size: 10pt;
+    }
+}
+
+pre {
+    background: #eeeeff;
+    border-color: #aaaaff;
+    border-style: solid;
+    border-width: 1px;
+    margin-left: 40pt;
+    margin-right: 40pt;
+    padding: 6pt;
+}
+
+table {
+    border-collapse: collapse;
+    margin-top: 10pt;
+    margin-left: 40pt;
+    margin-right: 40pt;
+}
+
+table th {
+    font-family: sans-serif;
+    background: #aabbff;
+}
+
+table td {
+    font-family: sans-serif;
+    border-top-style: solid;
+    border-bottom-style: solid;
+    border-width: 1px;
+    border-color: #aaaaff;
+    padding-top: 3pt;
+    padding-bottom: 3pt;
+    padding-left: 3pt;
+    padding-right: 4pt;
+    background: #eeeeff;
+}
+
+table p {
+    margin-bottom: 0pt;
+}
+
+/* for the bnf syntax sections */
+
+table.bnf {
+    background: #eeeeff;
+    border-color: #aaaaff;
+    border-style: solid;
+    border-width: 1px;
+    margin-top: 3pt;
+    margin-bottom: 3pt;
+    padding-top: 2pt;
+    padding-bottom: 6pt;
+    padding-left: 6pt;
+    padding-right: 6pt;
+}
+
+table.bnf td {
+    border: none;
+    padding-left: 6pt;
+    padding-right: 6pt;
+    padding-top: 1pt;
+    padding-bottom: 1pt;
+}
+
+table.bnf td:first-child {
+    padding-right: 0pt;
+    width: 8pt;
+}
+
+table.bnf td:first-child td {
+    padding-left: 0pt;
+}
+
+table.bnf td.def {
+    padding-top: 6pt;
+}
+
+table.bnf td.bar {
+    padding-left: 15pt;
+}
+
+table.bnf code {
+    font-weight: bold;
+}
+
+
+/* for the type name guide */
+
+table.guide {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.guide td:first-child {
+    font-family: monospace;
+    width: 15%;
+}
+
+table.guide td:first-child + td {
+    font-family: sans-serif;
+    width: 85%;
+}
+
+
+/* for the LEB128 example tables */
+
+table.leb128Bits {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.leb128Bits td {
+    border-left: solid #aaaaff 1px;
+    border-right: solid #aaaaff 1px;
+}
+
+table.leb128Bits td.start1 {
+    border-left: none;
+}
+
+table.leb128Bits td.start2 {
+    border-left: solid #000 2px;
+}
+
+table.leb128Bits td.end2 {
+    border-right: none;
+}
+
+table.leb128 {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.leb128 td:first-child {
+    font-family: monospace;
+    text-align: center;
+    width: 31%;
+}
+
+table.leb128 td:first-child + td {
+    font-family: monospace;
+    text-align: center;
+    width: 23%;
+}
+
+table.leb128 td:first-child + td + td {
+    font-family: monospace;
+    text-align: center;
+    width: 23%;
+}
+
+table.leb128 td:first-child + td + td + td {
+    font-family: monospace;
+    text-align: center;
+    width: 23%;
+}
+
+
+/* for the general format tables */
+
+table.format {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.format td:first-child {
+    font-family: monospace;
+    width: 20%;
+}
+
+table.format td:first-child + td {
+    font-family: monospace;
+    width: 20%;
+}
+
+table.format td:first-child + td + td {
+    width: 60%;
+}
+
+table.format td i {
+    font-family: sans-serif;
+}
+
+
+/* for the type code table */
+
+table.typeCodes {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.typeCodes td:first-child {
+    font-family: monospace;
+    width: 30%;
+}
+
+table.typeCodes td:first-child + td {
+    font-family: monospace;
+    width: 30%;
+}
+
+table.typeCodes td:first-child + td + td {
+    font-family: monospace;
+    width: 10%;
+}
+
+table.typeCodes td:first-child + td + td + td {
+    font-family: monospace;
+    width: 30%;
+}
+
+table.typeCodes td i {
+    font-family: sans-serif;
+}
+
+
+/* for the access flags table */
+
+table.accessFlags {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.accessFlags td:first-child {
+    font-family: monospace;
+    width: 10%;
+}
+
+table.accessFlags td:first-child + td {
+    font-family: monospace;
+    width: 6%;
+}
+
+table.accessFlags td:first-child + td + td {
+    width: 28%;
+}
+
+table.accessFlags td:first-child + td + td + td {
+    width: 28%;
+}
+
+table.accessFlags td:first-child + td + td + td + td {
+    width: 28%;
+}
+
+table.accessFlags i {
+    font-family: sans-serif;
+}
+
+
+/* for the descriptor table */
+
+table.descriptor {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.descriptor td:first-child {
+    font-family: monospace;
+    width: 25%;
+}
+
+table.descriptor td:first-child + td {
+    font-family: sans-serif;
+    width: 75%;
+}
+
+
+/* for the debug bytecode table */
+
+table.debugByteCode {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.debugByteCode td:first-child {
+    font-family: monospace;
+    width: 20%;
+}
+
+table.debugByteCode td:first-child + td {
+    font-family: monospace;
+    width: 5%;
+}
+
+table.debugByteCode td:first-child + td + td{
+    font-family: monospace;
+    width: 15%;
+}
+
+table.debugByteCode td:first-child + td + td + td {
+    width: 25%;
+}
+
+table.debugByteCode td:first-child + td + td + td + td {
+    width: 35%;
+}
+
+table.debugByteCode i {
+    font-family: sans-serif;
+}
+
+
+/* for the encoded value table */
+
+table.encodedValue {
+    margin-top: 20pt;
+    margin-bottom: 20pt;
+}
+
+table.encodedValue td:first-child {
+    font-family: monospace;
+    width: 12%;
+}
+
+table.encodedValue td:first-child + td {
+    font-family: monospace;
+    width: 10%;
+}
+
+table.encodedValue td:first-child + td + td {
+    font-family: monospace;
+    width: 15%;
+}
+
+table.encodedValue td:first-child + td + td + td {
+    font-family: monospace;
+    width: 15%;
+}
+
+table.encodedValue td:first-child + td + td + td + td {
+    width: 48%;
+}
+
+table.encodedValue td i {
+    font-family: sans-serif;
+}
diff --git a/docs/dex-format.html b/docs/dex-format.html
new file mode 100644
index 0000000..81c0b36
--- /dev/null
+++ b/docs/dex-format.html
@@ -0,0 +1,3049 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+
+<head>
+<title>.dex &mdash; Dalvik Executable Format</title>
+<link rel=stylesheet href="dex-format.css">
+</head>
+
+<body>
+
+<h1 class="title"><code>.dex</code> &mdash; Dalvik Executable Format</h1>
+<p>Copyright &copy; 2007 The Android Open Source Project
+
+<p>This document describes the layout and contents of <code>.dex</code>
+files, which are used to hold a set of class definitions and their associated
+adjunct data.</p>
+
+<h1>Guide To Types</h1>
+
+<table class="guide">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>byte</td>
+  <td>8-bit signed int</td>
+</tr>
+<tr>
+  <td>ubyte</td>
+  <td>8-bit unsigned int</td>
+</tr>
+<tr>
+  <td>short</td>
+  <td>16-bit signed int, little-endian</td>
+</tr>
+<tr>
+  <td>ushort</td>
+  <td>16-bit unsigned int, little-endian</td>
+</tr>
+<tr>
+  <td>int</td>
+  <td>32-bit signed int, little-endian</td>
+</tr>
+<tr>
+  <td>uint</td>
+  <td>32-bit unsigned int, little-endian</td>
+</tr>
+<tr>
+  <td>long</td>
+  <td>64-bit signed int, little-endian</td>
+</tr>
+<tr>
+  <td>ulong</td>
+  <td>64-bit unsigned int, little-endian</td>
+</tr>
+<tr>
+  <td>sleb128</td>
+  <td>signed LEB128, variable-length (see below)</td>
+</tr>
+<tr>
+  <td>uleb128</td>
+  <td>unsigned LEB128, variable-length (see below)</td>
+</tr>
+<tr>
+  <td>uleb128p1</td>
+  <td>unsigned LEB128 plus <code>1</code>, variable-length (see below)</td>
+</tr>
+</tbody>
+</table>
+
+<h3>LEB128</h3>
+
+<p>LEB128 ("<b>L</b>ittle-<b>E</b>ndian <b>B</b>ase <b>128</b>") is a
+variable-length encoding for
+arbitrary signed or unsigned integer quantities. The format was
+borrowed from the <a href="http://dwarfstd.org/Dwarf3Std.php">DWARF3</a>
+specification. In a <code>.dex</code> file, LEB128 is only ever used to
+encode 32-bit quantities.</p>
+
+<p>Each LEB128 encoded value consists of one to five
+bytes, which together represent a single 32-bit value. Each
+byte has its most significant bit set except for the final byte in the
+sequence, which has its most significant bit clear. The remaining
+seven bits of each byte are payload, with the least significant seven
+bits of the quantity in the first byte, the next seven in the second
+byte and so on. In the case of a signed LEB128 (<code>sleb128</code>),
+the most significant payload bit of the final byte in the sequence is
+sign-extended to produce the final value. In the unsigned case
+(<code>uleb128</code>), any bits not explicitly represented are
+interpreted as <code>0</code>.
+
+<table class="leb128Bits">
+<thead>
+<tr><th colspan="16">Bitwise diagram of a two-byte LEB128 value</th></tr>
+<tr>
+  <th colspan="8">First byte</td>
+  <th colspan="8">Second byte</td>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td class="start1"><code>1</code></td>
+  <td>bit<sub>6</sub></td>
+  <td>bit<sub>5</sub></td>
+  <td>bit<sub>4</sub></td>
+  <td>bit<sub>3</sub></td>
+  <td>bit<sub>2</sub></td>
+  <td>bit<sub>1</sub></td>
+  <td>bit<sub>0</sub></td>
+  <td class="start2"><code>0</code></td>
+  <td>bit<sub>13</sub></td>
+  <td>bit<sub>12</sub></td>
+  <td>bit<sub>11</sub></td>
+  <td>bit<sub>10</sub></td>
+  <td>bit<sub>9</sub></td>
+  <td>bit<sub>8</sub></td>
+  <td class="end2">bit<sub>7</sub></td>
+</tr>
+</tbody>
+</table>
+
+<p>The variant <code>uleb128p1</code> is used to represent a signed
+value, where the representation is of the value <i>plus one</i> encoded
+as a <code>uleb128</code>. This makes the encoding of <code>-1</code>
+(alternatively thought of as the unsigned value <code>0xffffffff</code>)
+&mdash; but no other negative number &mdash; a single byte, and is
+useful in exactly those cases where the represented number must either
+be non-negative or <code>-1</code> (or <code>0xffffffff</code>),
+and where no other negative values are allowed (or where large unsigned
+values are unlikely to be needed).</p>
+
+<p>Here are some examples of the formats:</p>
+
+<table class="leb128">
+<thead>
+<tr>
+  <th>Encoded Sequence</th>
+  <th>As <code>sleb128</code></th>
+  <th>As <code>uleb128</code></th>
+  <th>As <code>uleb128p1</code></th>
+</tr>
+</thead>
+<tbody>
+  <tr><td>00</td><td>0</td><td>0</td><td>-1</td></tr>
+  <tr><td>01</td><td>1</td><td>1</td><td>0</td></tr>
+  <tr><td>7f</td><td>-1</td><td>127</td><td>126</td></tr>
+  <tr><td>80 7f</td><td>-128</td><td>16256</td><td>16255</td></tr>
+</tbody>
+</table>
+
+<h1>Overall File Layout</h1>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>header</td>
+  <td>header_item</td>
+  <td>the header</td>
+</tr>
+<tr>
+  <td>string_ids</td>
+  <td>string_id_item[]</td>
+  <td>string identifiers list. These are identifiers for all the strings
+    used by this file, either for internal naming (e.g., type descriptors)
+    or as constant objects referred to by code. This list must be sorted
+    by string contents, using UTF-16 code point values (not in a
+    locale-sensitive manner), and it must not contain any duplicate entries.
+  </td>
+</tr>
+<tr>
+  <td>type_ids</td>
+  <td>type_id_item[]</td>
+  <td>type identifiers list. These are identifiers for all types (classes,
+    arrays, or primitive types) referred to by this file, whether defined
+    in the file or not. This list must be sorted by <code>string_id</code>
+    index, and it must not contain any duplicate entries.
+  </td>
+</tr>
+<tr>
+  <td>proto_ids</td>
+  <td>proto_id_item[]</td>
+  <td>method prototype identifiers list. These are identifiers for all
+    prototypes referred to by this file. This list must be sorted in
+    return-type (by <code>type_id</code> index) major order, and then
+    by arguments (also by <code>type_id</code> index). The list must not
+    contain any duplicate entries.
+  </td>
+</tr>
+<tr>
+  <td>field_ids</td>
+  <td>field_id_item[]</td>
+  <td>field identifiers list. These are identifiers for all fields
+    referred to by this file, whether defined in the file or not. This
+    list must be sorted, where the defining type (by <code>type_id</code>
+    index) is the major order, field name (by <code>string_id</code> index)
+    is the intermediate order, and type (by <code>type_id</code> index)
+    is the minor order. The list must not contain any duplicate entries.
+  </td>
+</tr>
+<tr>
+  <td>method_ids</td>
+  <td>method_id_item[]</td>
+  <td>method identifiers list. These are identifiers for all methods
+    referred to by this file, whether defined in the file or not. This
+    list must be sorted, where the defining type (by <code>type_id</code>
+    index) is the major order, method name (by <code>string_id</code>
+    index) is the intermediate order, and method prototype (by
+    <code>proto_id</code> index) is the minor order.  The list must not
+    contain any duplicate entries.
+  </td>
+</tr>
+<tr>
+  <td>class_defs</td>
+  <td>class_def_item[]</td>
+  <td>class definitions list. The classes must be ordered such that a given
+    class's superclass and implemented interfaces appear in the
+    list earlier than the referring class. Furthermore, it is invalid for
+    a definition for the same-named class to appear more than once in
+    the list.
+  </td>
+</tr>
+<tr>
+  <td>data</td>
+  <td>ubyte[]</td>
+  <td>data area, containing all the support data for the tables listed above.
+    Different items have different alignment requirements, and
+    padding bytes are inserted before each item if necessary to achieve
+    proper alignment.
+  </td>
+</tr>
+<tr>
+  <td>link_data</td>
+  <td>ubyte[]</td>
+  <td>data used in statically linked files. The format of the data in
+    this section is left unspecified by this document.
+    This section is empty in unlinked files, and runtime implementations
+    may use it as they see fit.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h1>Bitfield, String, and Constant Definitions</h1>
+
+<h2><code>DEX_FILE_MAGIC</code></h2>
+<h4>embedded in <code>header_item</code></h4>
+
+<p>The constant array/string <code>DEX_FILE_MAGIC</code> is the list of
+bytes that must appear at the beginning of a <code>.dex</code> file
+in order for it to be recognized as such. The value intentionally
+contains a newline (<code>"\n"</code> or <code>0x0a</code>) and a
+null byte (<code>"\0"</code> or <code>0x00</code>) in order to help
+in the detection of certain forms of corruption. The value also
+encodes a format version number as three decimal digits, which is
+expected to increase monotonically over time as the format evolves.</p>
+
+<pre>
+ubyte[8] DEX_FILE_MAGIC = { 0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00 }
+                        = "dex\n035\0"
+</pre>
+
+<p><b>Note:</b> At least a couple earlier versions of the format have
+been used in widely-available public software releases. For example,
+version <code>009</code> was used for the M3 releases of the
+Android platform (November&ndash;December 2007),
+and version <code>013</code> was used for the M5 releases of the Android
+platform (February&ndash;March 2008). In several respects, these earlier
+versions of the format differ significantly from the version described in this
+document.</p>
+
+<h2><code>ENDIAN_CONSTANT</code> and <code>REVERSE_ENDIAN_CONSTANT</code></h2>
+<h4>embedded in <code>header_item</code></h4>
+
+<p>The constant <code>ENDIAN_CONSTANT</code> is used to indicate the
+endianness of the file in which it is found. Although the standard
+<code>.dex</code> format is little-endian, implementations may choose
+to perform byte-swapping. Should an implementation come across a
+header whose <code>endian_tag</code> is <code>REVERSE_ENDIAN_CONSTANT</code>
+instead of <code>ENDIAN_CONSTANT</code>, it would know that the file
+has been byte-swapped from the expected form.</p>
+
+<pre>
+uint ENDIAN_CONSTANT = 0x12345678;
+uint REVERSE_ENDIAN_CONSTANT = 0x78563412;
+</pre>
+
+<h2><code>NO_INDEX</code></h2>
+<h4>embedded in <code>class_def_item</code> and
+<code>debug_info_item</code></h4>
+
+<p>The constant <code>NO_INDEX</code> is used to indicate that
+an index value is absent.</p>
+
+<p><b>Note:</b> This value isn't defined to be
+<code>0</code>, because that is in fact typically a valid index.</p>
+
+<p><b>Also Note:</b> The chosen value for <code>NO_INDEX</code> is
+representable as a single byte in the <code>uleb128p1</code> encoding.</p>
+
+<pre>
+uint NO_INDEX = 0xffffffff;    // == -1 if treated as a signed int
+</pre>
+
+<h2><code>access_flags</code> Definitions</h2>
+<h4>embedded in <code>class_def_item</code>,
+<code>encoded_field</code>, <code>encoded_method</code>, and
+<code>InnerClass</code></h4>
+
+<p>Bitfields of these flags are used to indicate the accessibility and
+overall properties of classes and class members.</p>
+
+<table class="accessFlags">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Value</th>
+  <th>For Classes (and <code>InnerClass</code> annotations)</th>
+  <th>For Fields</th>
+  <th>For Methods</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>ACC_PUBLIC</td>
+  <td>0x1</td>
+  <td><code>public</code>: visible everywhere</td>
+  <td><code>public</code>: visible everywhere</td>
+  <td><code>public</code>: visible everywhere</td>
+</tr>
+<tr>
+  <td>ACC_PRIVATE</td>
+  <td>0x2</td>
+  <td><super>*</super>
+    <code>private</code>: only visible to defining class
+  </td>
+  <td><code>private</code>: only visible to defining class</td>
+  <td><code>private</code>: only visible to defining class</td>
+</tr>
+<tr>
+  <td>ACC_PROTECTED</td>
+  <td>0x4</td>
+  <td><super>*</super>
+    <code>protected</code>: visible to package and subclasses
+  </td>
+  <td><code>protected</code>: visible to package and subclasses</td>
+  <td><code>protected</code>: visible to package and subclasses</td>
+</tr>
+<tr>
+  <td>ACC_STATIC</td>
+  <td>0x8</td>
+  <td><super>*</super>
+    <code>static</code>: is not constructed with an outer
+    <code>this</code> reference</td>
+  <td><code>static</code>: global to defining class</td>
+  <td><code>static</code>: does not take a <code>this</code> argument</td>
+</tr>
+<tr>
+  <td>ACC_FINAL</td>
+  <td>0x10</td>
+  <td><code>final</code>: not subclassable</td>
+  <td><code>final</code>: immutable after construction</td>
+  <td><code>final</code>: not overridable</td>
+</tr>
+<tr>
+  <td>ACC_SYNCHRONIZED</td>
+  <td>0x20</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><code>synchronized</code>: associated lock automatically acquired
+    around call to this method. <b>Note:</b> This is only valid to set when
+    <code>ACC_NATIVE</code> is also set.</td>
+</tr>
+<tr>
+  <td>ACC_VOLATILE</td>
+  <td>0x40</td>
+  <td>&nbsp;</td>
+  <td><code>volatile</code>: special access rules to help with thread
+    safety</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>ACC_BRIDGE</td>
+  <td>0x40</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td>bridge method, added automatically by compiler as a type-safe
+    bridge</td>
+</tr>
+<tr>
+  <td>ACC_TRANSIENT</td>
+  <td>0x80</td>
+  <td>&nbsp;</td>
+  <td><code>transient</code>: not to be saved by default serialization</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>ACC_VARARGS</td>
+  <td>0x80</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td>last argument should be treated as a "rest" argument by compiler</td>
+</tr>
+<tr>
+  <td>ACC_NATIVE</td>
+  <td>0x100</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><code>native</code>: implemented in native code</td>
+</tr>
+<tr>
+  <td>ACC_INTERFACE</td>
+  <td>0x200</td>
+  <td><code>interface</code>: multiply-implementable abstract class</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>ACC_ABSTRACT</td>
+  <td>0x400</td>
+  <td><code>abstract</code>: not directly instantiable</td>
+  <td>&nbsp;</td>
+  <td><code>abstract</code>: unimplemented by this class</td>
+</tr>
+<tr>
+  <td>ACC_STRICT</td>
+  <td>0x800</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><code>strictfp</code>: strict rules for floating-point arithmetic</td>
+</tr>
+<tr>
+  <td>ACC_SYNTHETIC</td>
+  <td>0x1000</td>
+  <td>not directly defined in source code</td>
+  <td>not directly defined in source code</td>
+  <td>not directly defined in source code</td>
+</tr>
+<tr>
+  <td>ACC_ANNOTATION</td>
+  <td>0x2000</td>
+  <td>declared as an annotation class</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>ACC_ENUM</td>
+  <td>0x4000</td>
+  <td>declared as an enumerated type</td>
+  <td>declared as an enumerated value</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><i>(unused)</i></td>
+  <td>0x8000</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>ACC_CONSTRUCTOR</td>
+  <td>0x10000</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td>constructor method (class or instance initializer)</td>
+</tr>
+<tr>
+  <td>ACC_DECLARED_<br/>SYNCHRONIZED</td>
+  <td>0x20000</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td>declared <code>synchronized</code>. <b>Note:</b> This has no effect on
+    execution (other than in reflection of this flag, per se).
+  </td>
+</tr>
+</tbody>
+</table>
+
+<p><super>*</super> Only allowed on for <code>InnerClass</code> annotations,
+and must not ever be on in a <code>class_def_item</code>.</p>
+
+<h2>MUTF-8 (Modified UTF-8) Encoding</h2>
+
+<p>As a concession to easier legacy support, the <code>.dex</code> format
+encodes its string data in a de facto standard modified UTF-8 form, hereafter
+referred to as MUTF-8. This form is identical to standard UTF-8, except:</p>
+
+<ul>
+  <li>Only the one-, two-, and three-byte encodings are used.</li>
+  <li>Code points in the range <code>U+10000</code> &hellip;
+    <code>U+10ffff</code> are encoded as a surrogate pair, each of
+    which is represented as a three-byte encoded value.</li>
+  <li>The code point <code>U+0000</code> is encoded in two-byte form.</li>
+  <li>A plain null byte (value <code>0</code>) indicates the end of
+    a string, as is the standard C language interpretation.</li>
+</ul>
+
+<p>The first two items above can be summarized as: MUTF-8
+is an encoding format for UTF-16, instead of being a more direct
+encoding format for Unicode characters.</p>
+
+<p>The final two items above make it simultaneously possible to include
+the code point <code>U+0000</code> in a string <i>and</i> still manipulate
+it as a C-style null-terminated string.</p>
+
+<p>However, the special encoding of <code>U+0000</code> means that, unlike
+normal UTF-8, the result of calling the standard C function
+<code>strcmp()</code> on a pair of MUTF-8 strings does not always
+indicate the properly signed result of comparison of <i>unequal</i> strings.
+When ordering (not just equality) is a concern, the most straightforward
+way to compare MUTF-8 strings is to decode them character by character,
+and compare the decoded values. (However, more clever implementations are
+also possible.)</p>
+
+<p>Please refer to <a href="http://unicode.org">The Unicode
+Standard</a> for further information about character encoding.
+MUTF-8 is actually closer to the (relatively less well-known) encoding
+<a href="http://www.unicode.org/reports/tr26/">CESU-8</a> than to UTF-8
+per se.</p>
+
+<h2><code>encoded_value</code> Encoding</h2>
+<h4>embedded in <code>annotation_element</code> and
+<code>encoded_array_item</code></h4>
+
+<p>An <code>encoded_value</code> is an encoded piece of (nearly)
+arbitrary hierarchically structured data. The encoding is meant to
+be both compact and straightforward to parse.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>(value_arg &lt;&lt; 5) | value_type</td>
+  <td>ubyte</td>
+  <td>byte indicating the type of the immediately subsequent
+    <code>value</code> along
+    with an optional clarifying argument in the high-order three bits.
+    See below for the various <code>value</code> definitions.
+    In most cases, <code>value_arg</code> encodes the length of
+    the immediately-subsequent <code>value</code> in bytes, as
+    <code>(size - 1)</code>, e.g., <code>0</code> means that
+    the value requires one byte, and <code>7</code> means it requires
+    eight bytes; however, there are exceptions as noted below.
+  </td>
+</tr>
+<tr>
+  <td>value</td>
+  <td>ubyte[]</td>
+  <td>bytes representing the value, variable in length and interpreted
+    differently for different <code>value_type</code> bytes, though
+    always little-endian. See the various value definitions below for
+    details.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3>Value Formats</h3>
+
+<table class="encodedValue">
+<thead>
+<tr>
+  <th>Type Name</th>
+  <th><code>value_type</code></th>
+  <th><code>value_arg</code> Format</th>
+  <th><code>value</code> Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>VALUE_BYTE</td>
+  <td>0x00</td>
+  <td><i>(none; must be <code>0</code>)</i></td>
+  <td>ubyte[1]</td>
+  <td>signed one-byte integer value</td>
+</tr>
+<tr>
+  <td>VALUE_SHORT</td>
+  <td>0x02</td>
+  <td>size - 1 (0&hellip;1)</td>
+  <td>ubyte[size]</td>
+  <td>signed two-byte integer value, sign-extended</td>
+</tr>
+<tr>
+  <td>VALUE_CHAR</td>
+  <td>0x03</td>
+  <td>size - 1 (0&hellip;1)</td>
+  <td>ubyte[size]</td>
+  <td>unsigned two-byte integer value, zero-extended</td>
+</tr>
+<tr>
+  <td>VALUE_INT</td>
+  <td>0x04</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>signed four-byte integer value, sign-extended</td>
+</tr>
+<tr>
+  <td>VALUE_LONG</td>
+  <td>0x06</td>
+  <td>size - 1 (0&hellip;7)</td>
+  <td>ubyte[size]</td>
+  <td>signed eight-byte integer value, sign-extended</td>
+</tr>
+<tr>
+  <td>VALUE_FLOAT</td>
+  <td>0x10</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>four-byte bit pattern, zero-extended <i>to the right</i>, and
+    interpreted as an IEEE754 32-bit floating point value
+  </td>
+</tr>
+<tr>
+  <td>VALUE_DOUBLE</td>
+  <td>0x11</td>
+  <td>size - 1 (0&hellip;7)</td>
+  <td>ubyte[size]</td>
+  <td>eight-byte bit pattern, zero-extended <i>to the right</i>, and
+    interpreted as an IEEE754 64-bit floating point value
+  </td>
+</tr>
+<tr>
+  <td>VALUE_STRING</td>
+  <td>0x17</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>unsigned (zero-extended) four-byte integer value,
+    interpreted as an index into
+    the <code>string_ids</code> section and representing a string value
+  </td>
+</tr>
+<tr>
+  <td>VALUE_TYPE</td>
+  <td>0x18</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>unsigned (zero-extended) four-byte integer value,
+    interpreted as an index into
+    the <code>type_ids</code> section and representing a reflective
+    type/class value
+  </td>
+</tr>
+<tr>
+  <td>VALUE_FIELD</td>
+  <td>0x19</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>unsigned (zero-extended) four-byte integer value,
+    interpreted as an index into
+    the <code>field_ids</code> section and representing a reflective
+    field value
+  </td>
+</tr>
+<tr>
+  <td>VALUE_METHOD</td>
+  <td>0x1a</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>unsigned (zero-extended) four-byte integer value,
+    interpreted as an index into
+    the <code>method_ids</code> section and representing a reflective
+    method value
+  </td>
+</tr>
+<tr>
+  <td>VALUE_ENUM</td>
+  <td>0x1b</td>
+  <td>size - 1 (0&hellip;3)</td>
+  <td>ubyte[size]</td>
+  <td>unsigned (zero-extended) four-byte integer value,
+    interpreted as an index into
+    the <code>field_ids</code> section and representing the value of
+    an enumerated type constant
+  </td>
+</tr>
+<tr>
+  <td>VALUE_ARRAY</td>
+  <td>0x1c</td>
+  <td><i>(none; must be <code>0</code>)</i></td>
+  <td>encoded_array</td>
+  <td>an array of values, in the format specified by
+    "<code>encoded_array</code> Format" below. The size
+    of the <code>value</code> is implicit in the encoding.
+  </td>
+</tr>
+<tr>
+  <td>VALUE_ANNOTATION</td>
+  <td>0x1d</td>
+  <td><i>(none; must be <code>0</code>)</i></td>
+  <td>encoded_annotation</td>
+  <td>a sub-annotation, in the format specified by
+    "<code>encoded_annotation</code> Format" below. The size
+    of the <code>value</code> is implicit in the encoding.
+  </td>
+</tr>
+<tr>
+  <td>VALUE_NULL</td>
+  <td>0x1e</td>
+  <td><i>(none; must be <code>0</code>)</i></td>
+  <td><i>(none)</i></td>
+  <td><code>null</code> reference value</td>
+</tr>
+<tr>
+  <td>VALUE_BOOLEAN</td>
+  <td>0x1f</td>
+  <td>boolean (0&hellip;1)</td>
+  <td><i>(none)</i></td>
+  <td>one-bit value; <code>0</code> for <code>false</code> and
+    <code>1</code> for <code>true</code>. The bit is represented in the
+    <code>value_arg</code>.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>encoded_array</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>uleb128</td>
+  <td>number of elements in the array</td>
+</tr>
+<tr>
+  <td>values</td>
+  <td>encoded_value[size]</td>
+  <td>a series of <code>size</code> <code>encoded_value</code> byte
+    sequences in the format specified by this section, concatenated
+    sequentially.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>encoded_annotation</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>type_idx</td>
+  <td>uleb128</td>
+  <td>type of the annotation. This must be a class (not array or primitive)
+    type.
+  </td>
+</tr>
+<tr>
+  <td>size</td>
+  <td>uleb128</td>
+  <td>number of name-value mappings in this annotation</td>
+</tr>
+<tr>
+  <td>elements</td>
+  <td>annotation_element[size]</td>
+  <td>elements of the annotataion, represented directly in-line (not as
+    offsets). Elements must be sorted in increasing order by
+    <code>string_id</code> index.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>annotation_element</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>name_idx</td>
+  <td>uleb128</td>
+  <td>element name, represented as an index into the
+    <code>string_ids</code> section. The string must conform to the
+    syntax for <i>MemberName</i>, defined above.
+  </td>
+</tr>
+<tr>
+  <td>value</td>
+  <td>encoded_value</td>
+  <td>element value</td>
+</tr>
+</tbody>
+</table>
+
+<h2>String Syntax</h2>
+
+<p>There are several kinds of item in a <code>.dex</code> file which
+ultimately refer to a string. The following BNF-style definitions
+indicate the acceptable syntax for these strings.</p>
+
+<h3><i>SimpleName</i></h3>
+
+<p>A <i>SimpleName</i> is the basis for the syntax of the names of other
+things. The <code>.dex</code> format allows a fair amount of latitude
+here (much more than most common source languages). In brief, a simple
+name consists of any low-ASCII alphabetic character or digit, a few
+specific low-ASCII symbols, and most non-ASCII code points that are not
+control, space, or special characters. Note that surrogate code points
+(in the range <code>U+d800</code> &hellip; <code>U+dfff</code>) are not
+considered valid name characters, per se, but Unicode supplemental
+characters <i>are</i> valid (which are represented by the final
+alternative of the rule for <i>SimpleNameChar</i>), and they should be
+represented in a file as pairs of surrogate code points in the MUTF-8
+encoding.</p>
+
+<table class="bnf">
+  <tr><td colspan="2" class="def"><i>SimpleName</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><i>SimpleNameChar</i> (<i>SimpleNameChar</i>)*</td>
+  </tr>
+
+  <tr><td colspan="2" class="def"><i>SimpleNameChar</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><code>'A'</code> &hellip; <code>'Z'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'a'</code> &hellip; <code>'z'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'0'</code> &hellip; <code>'9'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'$'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'-'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'_'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>U+00a1</code> &hellip; <code>U+1fff</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>U+2010</code> &hellip; <code>U+2027</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>U+2030</code> &hellip; <code>U+d7ff</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>U+e000</code> &hellip; <code>U+ffef</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>U+10000</code> &hellip; <code>U+10ffff</code></td>
+  </tr>
+</table>
+
+<h3><i>MemberName</i></h3>
+<h4>used by <code>field_id_item</code> and <code>method_id_item</code></h4>
+
+<p>A <i>MemberName</i> is the name of a member of a class, members being
+fields, methods, and inner classes.</p>
+
+<table class="bnf">
+  <tr><td colspan="2" class="def"><i>MemberName</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><i>SimpleName</i></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'&lt;'</code> <i>SimpleName</i> <code>'&gt;'</code></td>
+  </tr>
+</table>
+
+<h3><i>FullClassName</i></h3>
+
+<p>A <i>FullClassName</i> is a fully-qualified class name, including an
+optional package specifier followed by a required name.</p>
+
+<table class="bnf">
+  <tr><td colspan="2" class="def"><i>FullClassName</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><i>OptionalPackagePrefix</i> <i>SimpleName</i></td>
+  </tr>
+
+  <tr><td colspan="2" class="def"><i>OptionalPackagePrefix</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td>(<i>SimpleName</i> <code>'/'</code>)*</td>
+  </tr>
+</table>
+
+<h3><i>TypeDescriptor</i></h3>
+<h4>used by <code>type_id_item</code></h4>
+
+<p>A <i>TypeDescriptor</i> is the representation of any type, including
+primitives, classes, arrays, and <code>void</code>. See below for
+the meaning of the various versions.</p>
+
+<table class="bnf">
+  <tr><td colspan="2" class="def"><i>TypeDescriptor</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><code>'V'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><i>FieldTypeDescriptor</i></td>
+  </tr>
+
+  <tr><td colspan="2" class="def"><i>FieldTypeDescriptor</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><i>NonArrayFieldTypeDescriptor</i></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td>(<code>'['</code> * 1&hellip;255)
+      <i>NonArrayFieldTypeDescriptor</i></td>
+  </tr>
+
+  <tr>
+    <td colspan="2" class="def"><i>NonArrayFieldTypeDescriptor</i>&rarr;</td>
+  </tr>
+  <tr>
+    <td/>
+    <td><code>'Z'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'B'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'S'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'C'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'I'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'J'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'F'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'D'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'L'</code> <i>FullClassName</i> <code>';'</code></td>
+  </tr>
+</table>
+
+<h3><i>ShortyDescriptor</i></h3>
+<h4>used by <code>proto_id_item</code></h4>
+
+<p>A <i>ShortyDescriptor</i> is the short form representation of a method
+prototype, including return and parameter types, except that there is
+no distinction between various reference (class or array) types. Instead,
+all reference types are represented by a single <code>'L'</code> character.</p>
+
+<table class="bnf">
+  <tr><td colspan="2" class="def"><i>ShortyDescriptor</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><i>ShortyReturnType</i> (<i>ShortyFieldType</i>)*</td>
+  </tr>
+
+  <tr><td colspan="2" class="def"><i>ShortyReturnType</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><code>'V'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><i>ShortyFieldType</i></td>
+  </tr>
+
+  <tr><td colspan="2" class="def"><i>ShortyFieldType</i> &rarr;</td></tr>
+  <tr>
+    <td/>
+    <td><code>'Z'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'B'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'S'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'C'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'I'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'J'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'F'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'D'</code></td>
+  </tr>
+  <tr>
+    <td class="bar">|</td>
+    <td><code>'L'</code></td>
+  </tr>
+</table>
+
+<h2><i>TypeDescriptor</i> Semantics</h2>
+
+<p>This is the meaning of each of the variants of <i>TypeDescriptor</i>.</p>
+
+<table class="descriptor">
+<thead>
+<tr>
+  <th>Syntax</th>
+  <th>Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>V</td>
+  <td><code>void</code>; only valid for return types</td>
+</tr>
+<tr>
+  <td>Z</td>
+  <td><code>boolean</code></td>
+</tr>
+<tr>
+  <td>B</td>
+  <td><code>byte</code></td>
+</tr>
+<tr>
+  <td>S</td>
+  <td><code>short</code></td>
+</tr>
+<tr>
+  <td>C</td>
+  <td><code>char</code></td>
+</tr>
+<tr>
+  <td>I</td>
+  <td><code>int</code></td>
+</tr>
+<tr>
+  <td>J</td>
+  <td><code>long</code></td>
+</tr>
+<tr>
+  <td>F</td>
+  <td><code>float</code></td>
+</tr>
+<tr>
+  <td>D</td>
+  <td><code>double</code></td>
+</tr>
+<tr>
+  <td>L<i>fully/qualified/Name</i>;</td>
+  <td>the class <code><i>fully.qualified.Name</i></code></td>
+</tr>
+<tr>
+  <td>[<i>descriptor</i></td>
+  <td>array of <code><i>descriptor</i></code>, usable recursively for
+    arrays-of-arrays, though it is invalid to have more than 255
+    dimensions.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h1>Items and Related Structures</h1>
+
+<p>This section includes definitions for each of the top-level items that
+may appear in a <code>.dex</code> file.
+
+<h2><code>header_item</code></h2>
+<h4>appears in the <code>header</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>magic</td>
+  <td>ubyte[8] = DEX_FILE_MAGIC</td>
+  <td>magic value. See discussion above under "<code>DEX_FILE_MAGIC</code>"
+    for more details.
+  </td>
+</tr>
+<tr>
+  <td>checksum</td>
+  <td>uint</td>
+  <td>adler32 checksum of the rest of the file (everything but
+    <code>magic</code> and this field); used to detect file corruption
+  </td>
+</tr>
+<tr>
+  <td>signature</td>
+  <td>ubyte[20]</td>
+  <td>SHA-1 signature (hash) of the rest of the file (everything but
+    <code>magic</code>, <code>checksum</code>, and this field); used
+    to uniquely identify files
+  </td>
+</tr>
+<tr>
+  <td>file_size</td>
+  <td>uint</td>
+  <td>size of the entire file (including the header), in bytes
+</tr>
+<tr>
+  <td>header_size</td>
+  <td>uint = 0x70</td>
+  <td>size of the header (this entire section), in bytes. This allows for at
+    least a limited amount of backwards/forwards compatibility without
+    invalidating the format.
+  </td>
+</tr>
+<tr>
+  <td>endian_tag</td>
+  <td>uint = ENDIAN_CONSTANT</td>
+  <td>endianness tag. See discussion above under "<code>ENDIAN_CONSTANT</code>
+    and <code>REVERSE_ENDIAN_CONSTANT</code>" for more details.
+  </td>
+</tr>
+<tr>
+  <td>link_size</td>
+  <td>uint</td>
+  <td>size of the link section, or <code>0</code> if this file isn't
+    statically linked</td>
+</tr>
+<tr>
+  <td>link_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the link section, or
+    <code>0</code> if <code>link_size == 0</code>. The offset, if non-zero,
+    should be to an offset into the <code>link_data</code> section. The
+    format of the data pointed at is left unspecified by this document;
+    this header field (and the previous) are left as hooks for use by
+    runtime implementations.
+  </td>
+</tr>
+<tr>
+  <td>map_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the map item, or
+    <code>0</code> if this file has no map. The offset, if non-zero,
+    should be to an offset into the <code>data</code> section,
+    and the data should be in the format specified by "<code>map_list</code>"
+    below.
+  </td>
+</tr>
+<tr>
+  <td>string_ids_size</td>
+  <td>uint</td>
+  <td>count of strings in the string identifiers list</td>
+</tr>
+<tr>
+  <td>string_ids_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the string identifiers list, or
+    <code>0</code> if <code>string_ids_size == 0</code> (admittedly a
+    strange edge case). The offset, if non-zero,
+    should be to the start of the <code>string_ids</code> section.
+  </td>
+</tr>
+<tr>
+  <td>type_ids_size</td>
+  <td>uint</td>
+  <td>count of elements in the type identifiers list</td>
+</tr>
+<tr>
+  <td>type_ids_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the type identifiers list, or
+    <code>0</code> if <code>type_ids_size == 0</code> (admittedly a
+    strange edge case). The offset, if non-zero,
+    should be to the start of the <code>type_ids</code>
+    section.
+  </td>
+</tr>
+<tr>
+  <td>proto_ids_size</td>
+  <td>uint</td>
+  <td>count of elements in the prototype identifiers list</td>
+</tr>
+<tr>
+  <td>proto_ids_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the prototype identifiers list, or
+    <code>0</code> if <code>proto_ids_size == 0</code> (admittedly a
+    strange edge case). The offset, if non-zero,
+    should be to the start of the <code>proto_ids</code>
+    section.
+  </td>
+</tr>
+<tr>
+  <td>field_ids_size</td>
+  <td>uint</td>
+  <td>count of elements in the field identifiers list</td>
+</tr>
+<tr>
+  <td>field_ids_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the field identifiers list, or
+    <code>0</code> if <code>field_ids_size == 0</code>. The offset, if
+    non-zero, should be to the start of the <code>field_ids</code>
+    section.</td>
+</td>
+</tr>
+<tr>
+  <td>method_ids_size</td>
+  <td>uint</td>
+  <td>count of elements in the method identifiers list</td>
+</tr>
+<tr>
+  <td>method_ids_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the method identifiers list, or
+    <code>0</code> if <code>method_ids_size == 0</code>. The offset, if
+    non-zero, should be to the start of the <code>method_ids</code>
+    section.</td>
+</tr>
+<tr>
+  <td>class_defs_size</td>
+  <td>uint</td>
+  <td>count of elements in the class definitions list</td>
+</tr>
+<tr>
+  <td>class_defs_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the class definitions list, or
+    <code>0</code> if <code>class_defs_size == 0</code> (admittedly a
+    strange edge case). The offset, if non-zero,
+    should be to the start of the <code>class_defs</code> section.
+  </td>
+</tr>
+<tr>
+  <td>data_size</td>
+  <td>uint</td>
+  <td>Size of <code>data</code> section in bytes. Must be an even
+    multiple of sizeof(uint).</td>
+</tr>
+<tr>
+  <td>data_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the start of the
+   <code>data</code> section.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>map_list</code></h2>
+<h4>appears in the <code>data</code> section</h4>
+<h4>referenced from <code>header_item</code></h4>
+<h4>alignment: 4 bytes</h4>
+
+<p>This is a list of the entire contents of a file, in order. It
+contains some redundancy with respect to the <code>header_item</code>
+but is intended to be an easy form to use to iterate over an entire
+file. A given type must appear at most once in a map, but there is no
+restriction on what order types may appear in, other than the
+restrictions implied by the rest of the format (e.g., a
+<code>header</code> section must appear first, followed by a
+<code>string_ids</code> section, etc.). Additionally, the map entries must
+be ordered by initial offset and must not overlap.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>uint</td>
+  <td>size of the list, in entries</td>
+</tr>
+<tr>
+  <td>list</td>
+  <td>map_item[size]</td>
+  <td>elements of the list</td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>map_item</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>type</td>
+  <td>ushort</td>
+  <td>type of the items; see table below</td>
+</tr>
+<tr>
+  <td>unused</td>
+  <td>ushort</td>
+  <td><i>(unused)</i></td>
+</tr>
+<tr>
+  <td>size</td>
+  <td>uint</td>
+  <td>count of the number of items to be found at the indicated offset</td>
+</tr>
+<tr>
+  <td>offset</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the items in question</td>
+</tr>
+</tbody>
+</table>
+
+
+<h3>Type Codes</h3>
+
+<table class="typeCodes">
+<thead>
+<tr>
+  <th>Item Type</th>
+  <th>Constant</th>
+  <th>Value</th>
+  <th>Item Size In Bytes</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>header_item</td>
+  <td>TYPE_HEADER_ITEM</td>
+  <td>0x0000</td>
+  <td>0x70</td>
+</tr>
+<tr>
+  <td>string_id_item</td>
+  <td>TYPE_STRING_ID_ITEM</td>
+  <td>0x0001</td>
+  <td>0x04</td>
+</tr>
+<tr>
+  <td>type_id_item</td>
+  <td>TYPE_TYPE_ID_ITEM</td>
+  <td>0x0002</td>
+  <td>0x04</td>
+</tr>
+<tr>
+  <td>proto_id_item</td>
+  <td>TYPE_PROTO_ID_ITEM</td>
+  <td>0x0003</td>
+  <td>0x0c</td>
+</tr>
+<tr>
+  <td>field_id_item</td>
+  <td>TYPE_FIELD_ID_ITEM</td>
+  <td>0x0004</td>
+  <td>0x08</td>
+</tr>
+<tr>
+  <td>method_id_item</td>
+  <td>TYPE_METHOD_ID_ITEM</td>
+  <td>0x0005</td>
+  <td>0x08</td>
+</tr>
+<tr>
+  <td>class_def_item</td>
+  <td>TYPE_CLASS_DEF_ITEM</td>
+  <td>0x0006</td>
+  <td>0x20</td>
+</tr>
+<tr>
+  <td>map_list</td>
+  <td>TYPE_MAP_LIST</td>
+  <td>0x1000</td>
+  <td>4 + (item.size * 12)</td>
+</tr>
+<tr>
+  <td>type_list</td>
+  <td>TYPE_TYPE_LIST</td>
+  <td>0x1001</td>
+  <td>4 + (item.size * 2)</td>
+</tr>
+<tr>
+  <td>annotation_set_ref_list</td>
+  <td>TYPE_ANNOTATION_SET_REF_LIST</td>
+  <td>0x1002</td>
+  <td>4 + (item.size * 4)</td>
+</tr>
+<tr>
+  <td>annotation_set_item</td>
+  <td>TYPE_ANNOTATION_SET_ITEM</td>
+  <td>0x1003</td>
+  <td>4 + (item.size * 4)</td>
+</tr>
+<tr>
+  <td>class_data_item</td>
+  <td>TYPE_CLASS_DATA_ITEM</td>
+  <td>0x2000</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+<tr>
+  <td>code_item</td>
+  <td>TYPE_CODE_ITEM</td>
+  <td>0x2001</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+<tr>
+  <td>string_data_item</td>
+  <td>TYPE_STRING_DATA_ITEM</td>
+  <td>0x2002</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+<tr>
+  <td>debug_info_item</td>
+  <td>TYPE_DEBUG_INFO_ITEM</td>
+  <td>0x2003</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+<tr>
+  <td>annotation_item</td>
+  <td>TYPE_ANNOTATION_ITEM</td>
+  <td>0x2004</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+<tr>
+  <td>encoded_array_item</td>
+  <td>TYPE_ENCODED_ARRAY_ITEM</td>
+  <td>0x2005</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+<tr>
+  <td>annotations_directory_item</td>
+  <td>TYPE_ANNOTATIONS_DIRECTORY_ITEM</td>
+  <td>0x2006</td>
+  <td><i>implicit; must parse</i></td>
+</tr>
+</tbody>
+</table>
+
+
+<h2><code>string_id_item</code></h2>
+<h4>appears in the <code>string_ids</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>string_data_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the string data for this
+    item. The offset should be to a location
+    in the <code>data</code> section, and the data should be in the
+    format specified by "<code>string_data_item</code>" below.
+    There is no alignment requirement for the offset.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>string_data_item</code></h2>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: none (byte-aligned)</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>utf16_size</td>
+  <td>uleb128</td>
+  <td>size of this string, in UTF-16 code units (which is the "string
+    length" in many systems). That is, this is the decoded length of
+    the string. (The encoded length is implied by the position of
+    the <code>0</code> byte.)</td>
+</tr>
+<tr>
+  <td>data</td>
+  <td>ubyte[]</td>
+  <td>a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes)
+    followed by a byte of value <code>0</code>. See
+    "MUTF-8 (Modified UTF-8) Encoding" above for details and
+    discussion about the data format.
+    <p><b>Note:</b> It is acceptable to have a string which includes
+    (the encoded form of) UTF-16 surrogate code units (that is,
+    <code>U+d800</code> &hellip; <code>U+dfff</code>)
+    either in isolation or out-of-order with respect to the usual
+    encoding of Unicode into UTF-16. It is up to higher-level uses of
+    strings to reject such invalid encodings, if appropriate.</p>
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>type_id_item</code></h2>
+<h4>appears in the <code>type_ids</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>descriptor_idx</td>
+  <td>uint</td>
+  <td>index into the <code>string_ids</code> list for the descriptor
+    string of this type. The string must conform to the syntax for
+    <i>TypeDescriptor</i>, defined above.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>proto_id_item</code></h2>
+<h4>appears in the <code>proto_ids</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>shorty_idx</td>
+  <td>uint</td>
+  <td>index into the <code>string_ids</code> list for the short-form
+    descriptor string of this prototype. The string must conform to the
+    syntax for <i>ShortyDescriptor</i>, defined above, and must correspond
+    to the return type and parameters of this item.
+  </td>
+</tr>
+<tr>
+  <td>return_type_idx</td>
+  <td>uint</td>
+  <td>index into the <code>type_ids</code> list for the return type
+    of this prototype
+  </td>
+</tr>
+<tr>
+  <td>parameters_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the list of parameter types
+    for this prototype, or <code>0</code> if this prototype has no
+    parameters. This offset, if non-zero, should be in the
+    <code>data</code> section, and the data there should be in the
+    format specified by <code>"type_list"</code> below. Additionally, there
+    should be no reference to the type <code>void</code> in the list.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>field_id_item</code></h2>
+<h4>appears in the <code>field_ids</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>class_idx</td>
+  <td>ushort</td>
+  <td>index into the <code>type_ids</code> list for the definer of this
+    field. This must be a class type, and not an array or primitive type.
+  </td>
+</tr>
+<tr>
+  <td>type_idx</td>
+  <td>ushort</td>
+  <td>index into the <code>type_ids</code> list for the type of
+    this field
+  </td>
+</tr>
+<tr>
+  <td>name_idx</td>
+  <td>uint</td>
+  <td>index into the <code>string_ids</code> list for the name of this
+    field. The string must conform to the syntax for <i>MemberName</i>,
+    defined above.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>method_id_item</code></h2>
+<h4>appears in the <code>method_ids</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>class_idx</td>
+  <td>ushort</td>
+  <td>index into the <code>type_ids</code> list for the definer of this
+    method. This must be a class or array type, and not a primitive type.
+  </td>
+</tr>
+<tr>
+  <td>proto_idx</td>
+  <td>ushort</td>
+  <td>index into the <code>proto_ids</code> list for the prototype of
+    this method
+  </td>
+</tr>
+<tr>
+  <td>name_idx</td>
+  <td>uint</td>
+  <td>index into the <code>string_ids</code> list for the name of this
+    method. The string must conform to the syntax for <i>MemberName</i>,
+    defined above.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>class_def_item</code></h2>
+<h4>appears in the <code>class_defs</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>class_idx</td>
+  <td>uint</td>
+  <td>index into the <code>type_ids</code> list for this class.
+    This must be a class type, and not an array or primitive type.
+  </td>
+</tr>
+<tr>
+  <td>access_flags</td>
+  <td>uint</td>
+  <td>access flags for the class (<code>public</code>, <code>final</code>,
+    etc.). See "<code>access_flags</code> Definitions" for details.
+  </td>
+</tr>
+<tr>
+  <td>superclass_idx</td>
+  <td>uint</td>
+  <td>index into the <code>type_ids</code> list for the superclass, or
+    the constant value <code>NO_INDEX</code> if this class has no
+    superclass (i.e., it is a root class such as <code>Object</code>).
+    If present, this must be a class type, and not an array or primitive type.
+  </td>
+</tr>
+<tr>
+  <td>interfaces_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the list of interfaces, or
+    <code>0</code> if there are none. This offset
+    should be in the <code>data</code> section, and the data
+    there should be in the format specified by
+    "<code>type_list</code>" below. Each of the elements of the list
+    must be a class type (not an array or primitive type), and there
+    must not be any duplicates.
+  </td>
+</tr>
+<tr>
+  <td>source_file_idx</td>
+  <td>uint</td>
+  <td>index into the <code>string_ids</code> list for the name of the
+    file containing the original source for (at least most of) this class,
+    or the special value <code>NO_INDEX</code> to represent a lack of
+    this information. The <code>debug_info_item</code> of any given method
+    may override this source file, but the expectation is that most classes
+    will only come from one source file.
+  </td>
+</tr>
+<tr>
+  <td>annotations_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the annotations structure
+    for this class, or <code>0</code> if there are no annotations on
+    this class. This offset, if non-zero, should be in the
+    <code>data</code> section, and the data there should be in
+    the format specified by "<code>annotations_directory_item</code>" below,
+    with all items referring to this class as the definer.
+  </td>
+</tr>
+<tr>
+  <td>class_data_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the associated
+    class data for this item, or <code>0</code> if there is no class
+    data for this class. (This may be the case, for example, if this class
+    is a marker interface.) The offset, if non-zero, should be in the
+    <code>data</code> section, and the data there should be in the
+    format specified by "<code>class_data_item</code>" below, with all
+    items referring to this class as the definer.
+  </td>
+</tr>
+<tr>
+  <td>static_values_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the list of initial
+    values for <code>static</code> fields, or <code>0</code> if there
+    are none (and all <code>static</code> fields are to be initialized with
+    <code>0</code> or <code>null</code>). This offset should be in the
+    <code>data</code> section, and the data there should be in the
+    format specified by "<code>encoded_array_item</code>" below. The size
+    of the array must be no larger than the number of <code>static</code>
+    fields declared by this class, and the elements correspond to the
+    <code>static</code> fields in the same order as declared in the
+    corresponding <code>field_list</code>. The type of each array
+    element must match the declared type of its corresponding field.
+    If there are fewer elements in the array than there are
+    <code>static</code> fields, then the leftover fields are initialized
+    with a type-appropriate <code>0</code> or <code>null</code>.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>class_data_item</code></h2>
+<h4>referenced from <code>class_def_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: none (byte-aligned)</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>static_fields_size</td>
+  <td>uleb128</td>
+  <td>the number of static fields defined in this item</td>
+</tr>
+<tr>
+  <td>instance_fields_size</td>
+  <td>uleb128</td>
+  <td>the number of instance fields defined in this item</td>
+</tr>
+<tr>
+  <td>direct_methods_size</td>
+  <td>uleb128</td>
+  <td>the number of direct methods defined in this item</td>
+</tr>
+<tr>
+  <td>virtual_methods_size</td>
+  <td>uleb128</td>
+  <td>the number of virtual methods defined in this item</td>
+</tr>
+<tr>
+  <td>static_fields</td>
+  <td>encoded_field[static_fields_size]</td>
+  <td>the defined static fields, represented as a sequence of
+    encoded elements. The fields must be sorted by
+    <code>field_idx</code> in increasing order.
+  </td>
+</tr>
+<tr>
+  <td>instance_fields</td>
+  <td>encoded_field[instance_fields_size]</td>
+  <td>the defined instance fields, represented as a sequence of
+    encoded elements. The fields must be sorted by
+    <code>field_idx</code> in increasing order.
+  </td>
+</tr>
+<tr>
+  <td>direct_methods</td>
+  <td>encoded_method[direct_methods_size]</td>
+  <td>the defined direct (any of <code>static</code>, <code>private</code>,
+    or constructor) methods, represented as a sequence of
+    encoded elements. The methods must be sorted by
+    <code>method_idx</code> in increasing order.
+  </td>
+</tr>
+<tr>
+  <td>virtual_methods</td>
+  <td>encoded_method[virtual_methods_size]</td>
+  <td>the defined virtual (none of <code>static</code>, <code>private</code>,
+    or constructor) methods, represented as a sequence of
+    encoded elements. This list should <i>not</i> include inherited
+    methods unless overridden by the class that this item represents. The
+    methods must be sorted by <code>method_idx</code> in increasing order.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<p><b>Note:</b> All elements' <code>field_id</code>s and
+<code>method_id</code>s must refer to the same defining class.</p>
+
+<h3><code>encoded_field</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>field_idx_diff</td>
+  <td>uleb128</td>
+  <td>index into the <code>field_ids</code> list for the identity of this
+    field (includes the name and descriptor), represented as a difference
+    from the index of previous element in the list. The index of the
+    first element in a list is represented directly.
+  </td>
+</tr>
+<tr>
+  <td>access_flags</td>
+  <td>uleb128</td>
+  <td>access flags for the field (<code>public</code>, <code>final</code>,
+    etc.). See "<code>access_flags</code> Definitions" for details.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>encoded_method</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>method_idx_diff</td>
+  <td>uleb128</td>
+  <td>index into the <code>method_ids</code> list for the identity of this
+    method (includes the name and descriptor), represented as a difference
+    from the index of previous element in the list. The index of the
+    first element in a list is represented directly.
+  </td>
+</tr>
+<tr>
+  <td>access_flags</td>
+  <td>uleb128</td>
+  <td>access flags for the method (<code>public</code>, <code>final</code>,
+    etc.). See "<code>access_flags</code> Definitions" for details.
+  </td>
+</tr>
+<tr>
+  <td>code_off</td>
+  <td>uleb128</td>
+  <td>offset from the start of the file to the code structure for this
+    method, or <code>0</code> if this method is either <code>abstract</code>
+    or <code>native</code>. The offset should be to a location in the
+    <code>data</code> section. The format of the data is specified by
+    "<code>code_item</code>" below.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>type_list</code></h2>
+<h4>referenced from <code>class_def_item</code> and
+<code>proto_id_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>uint</td>
+  <td>size of the list, in entries</td>
+</tr>
+<tr>
+  <td>list</td>
+  <td>type_item[size]</td>
+  <td>elements of the list</td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>type_item</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>type_idx</td>
+  <td>ushort</td>
+  <td>index into the <code>type_ids</code> list</td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>code_item</code></h2>
+<h4>referenced from <code>encoded_method</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>registers_size</td>
+  <td>ushort</td>
+  <td>the number of registers used by this code</td>
+</tr>
+<tr>
+  <td>ins_size</td>
+  <td>ushort</td>
+  <td>the number of words of incoming arguments to the method that this
+    code is for</td>
+</tr>
+<tr>
+  <td>outs_size</td>
+  <td>ushort</td>
+  <td>the number of words of outgoing argument space required by this
+    code for method invocation
+  </td>
+</tr>
+<tr>
+  <td>tries_size</td>
+  <td>ushort</td>
+  <td>the number of <code>try_item</code>s for this instance. If non-zero,
+    then these appear as the <code>tries</code> array just after the
+    <code>insns</code> in this instance.
+  </td>
+</tr>
+<tr>
+  <td>debug_info_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the debug info (line numbers +
+    local variable info) sequence for this code, or <code>0</code> if
+    there simply is no information. The offset, if non-zero, should be
+    to a location in the <code>data</code> section. The format of
+    the data is specified by "<code>debug_info_item</code>" below.
+  </td>
+</tr>
+<tr>
+  <td>insns_size</td>
+  <td>uint</td>
+  <td>size of the instructions list, in 16-bit code units</td>
+</tr>
+<tr>
+  <td>insns</td>
+  <td>ushort[insns_size]</td>
+  <td>actual array of bytecode. The format of code in an <code>insns</code>
+    array is specified by the companion document
+    <a href="dalvik-bytecode.html">"Bytecode for the Dalvik VM"</a>. Note
+    that though this is defined as an array of <code>ushort</code>, there
+    are some internal structures that prefer four-byte alignment. Also,
+    if this happens to be in an endian-swapped file, then the swapping is
+    <i>only</i> done on individual <code>ushort</code>s and not on the
+    larger internal structures.
+  </td>
+</tr>
+<tr>
+  <td>padding</td>
+  <td>ushort <i>(optional)</i> = 0</td>
+  <td>two bytes of padding to make <code>tries</code> four-byte aligned.
+    This element is only present if <code>tries_size</code> is non-zero
+    and <code>insns_size</code> is odd.
+  </td>
+</tr>
+<tr>
+  <td>tries</td>
+  <td>try_item[tries_size] <i>(optional)</i></td>
+  <td>array indicating where in the code exceptions are caught and
+    how to handle them. Elements of the array must be non-overlapping in
+    range and in order from low to high address. This element is only
+    present if <code>tries_size</code> is non-zero.
+  </td>
+</tr>
+<tr>
+  <td>handlers</td>
+  <td>encoded_catch_handler_list <i>(optional)</i></td>
+  <td>bytes representing a list of lists of catch types and associated
+    handler addresses. Each <code>try_item</code> has a byte-wise offset
+    into this structure. This element is only present if
+    <code>tries_size</code> is non-zero.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>try_item</code> Format </h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>start_addr</td>
+  <td>uint</td>
+  <td>start address of the block of code covered by this entry. The address
+    is a count of 16-bit code units to the start of the first covered
+    instruction.
+  </td>
+</tr>
+<tr>
+  <td>insn_count</td>
+  <td>ushort</td>
+  <td>number of 16-bit code units covered by this entry. The last code
+    unit covered (inclusive) is <code>start_addr + insn_count - 1</code>.
+  </td>
+</tr>
+<tr>
+  <td>handler_off</td>
+  <td>ushort</td>
+  <td>offset in bytes from the start of the associated
+    <code>encoded_catch_hander_list</code> to the
+    <code>encoded_catch_handler</code> for this entry. This must be an
+    offset to the start of an <code>encoded_catch_handler</code>.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>encoded_catch_handler_list</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>uleb128</td>
+  <td>size of this list, in entries</td>
+</tr>
+<tr>
+  <td>list</td>
+  <td>encoded_catch_handler[handlers_size]</td>
+  <td>actual list of handler lists, represented directly (not as offsets),
+    and concatenated sequentially</td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>encoded_catch_handler</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>sleb128</td>
+  <td>number of catch types in this list. If non-positive, then this is
+    the negative of the number of catch types, and the catches are followed
+    by a catch-all handler. For example: A <code>size</code> of <code>0</code>
+    means that there is a catch-all but no explicitly typed catches.
+    A <code>size</code> of <code>2</code> means that there are two explicitly
+    typed catches and no catch-all. And a <code>size</code> of <code>-1</code>
+    means that there is one typed catch along with a catch-all.
+  </td>
+</tr>
+<tr>
+  <td>handlers</td>
+  <td>encoded_type_addr_pair[abs(size)]</td>
+  <td>stream of <code>abs(size)</code> encoded items, one for each caught
+    type, in the order that the types should be tested.
+  </td>
+</tr>
+<tr>
+  <td>catch_all_addr</td>
+  <td>uleb128 <i>(optional)</i></td>
+  <td>bytecode address of the catch-all handler. This element is only
+    present if <code>size</code> is non-positive.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>encoded_type_addr_pair</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>type_idx</td>
+  <td>uleb128</td>
+  <td>index into the <code>type_ids</code> list for the type of the
+    exception to catch
+  </td>
+</tr>
+<tr>
+  <td>addr</td>
+  <td>uleb128</td>
+  <td>bytecode address of the associated exception handler</td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>debug_info_item</code></h2>
+<h4>referenced from <code>code_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: none (byte-aligned)</h4>
+
+<p>Each <code>debug_info_item</code> defines a DWARF3-inspired byte-coded
+state machine that, when interpreted, emits the positions
+table and (potentially) the local variable information for a
+<code>code_item</code>. The sequence begins with a variable-length
+header (the length of which depends on the number of method
+parameters), is followed by the state machine bytecodes, and ends
+with an <code>DBG_END_SEQUENCE</code> byte.</p>
+
+<p>The state machine consists of five registers. The
+<code>address</code> register represents the instruction offset in the
+associated <code>insns_item</code> in 16-bit code units. The
+<code>address</code> register starts at <code>0</code> at the beginning of each
+<code>debug_info</code> sequence and must only monotonically increase.
+The <code>line</code> register represents what source line number
+should be associated with the next positions table entry emitted by
+the state machine. It is initialized in the sequence header, and may
+change in positive or negative directions but must never be less than
+<code>1</code>. The <code>source_file</code> register represents the
+source file that the line number entries refer to. It is initialized to
+the value of <code>source_file_idx</code> in <code>class_def_item</code>.
+The other two variables, <code>prologue_end</code> and
+<code>epilogue_begin</code>, are boolean flags (initialized to
+<code>false</code>) that indicate whether the next position emitted
+should be considered a method prologue or epilogue. The state machine
+must also track the name and type of the last local variable live in
+each register for the <code>DBG_RESTART_LOCAL</code> code.</p>
+
+<p>The header is as follows:</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>line_start</td>
+ <td>uleb128</td>
+ <td>the initial value for the state machine's <code>line</code> register.
+    Does not represent an actual positions entry.
+ </td>
+</tr>
+<tr>
+ <td>parameters_size</td>
+ <td>uleb128</td>
+ <td>the number of parameter names that are encoded. There should be
+   one per method parameter, excluding an instance method's <code>this</code>,
+   if any.
+ </td>
+</tr>
+<tr>
+ <td>parameter_names</td>
+ <td>uleb128p1[parameters_size]</td>
+ <td>string index of the method parameter name. An encoded value of
+   <code>NO_INDEX</code> indicates that no name
+   is available for the associated parameter. The type descriptor
+   and signature are implied from the method descriptor and signature.
+ </td>
+</tr>
+</tbody>
+</table>
+
+<p>The byte code values are as follows:</p>
+
+<table class="debugByteCode">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Value</th>
+  <th>Format</th>
+  <th>Arguments</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>DBG_END_SEQUENCE</td>
+  <td>0x00</td>
+  <td></td>
+  <td><i>(none)</i></td>
+  <td>terminates a debug info sequence for a <code>code_item</code></td>
+</tr>
+<tr>
+  <td>DBG_ADVANCE_PC</td>
+  <td>0x01</td>
+  <td>uleb128&nbsp;addr_diff</td>
+  <td><code>addr_diff</code>: amount to add to address register</td>
+  <td>advances the address register without emitting a positions entry</td>
+</tr>
+<tr>
+  <td>DBG_ADVANCE_LINE</td>
+  <td>0x02</td>
+  <td>sleb128&nbsp;line_diff</td>
+  <td><code>line_diff</code>: amount to change line register by</td>
+  <td>advances the line register without emitting a positions entry</td>
+</tr>
+<tr>
+  <td>DBG_START_LOCAL</td>
+  <td>0x03</td>
+  <td>uleb128&nbsp;register_num<br/>
+    uleb128p1&nbsp;name_idx<br/>
+    uleb128p1&nbsp;type_idx
+  </td>
+  <td><code>register_num</code>: register that will contain local<br/>
+    <code>name_idx</code>: string index of the name<br/>
+    <code>type_idx</code>: type index of the type
+  </td>
+  <td>introduces a local variable at the current address. Either
+    <code>name_idx</code> or <code>type_idx</code> may be
+    <code>NO_INDEX</code> to indicate that that value is unknown.
+  </td>
+</tr>
+<tr>
+  <td>DBG_START_LOCAL_EXTENDED</td>
+  <td>0x04</td>
+  <td>uleb128&nbsp;register_num<br/>
+    uleb128p1&nbsp;name_idx<br/>
+    uleb128p1&nbsp;type_idx<br/>
+    uleb128p1&nbsp;sig_idx
+  </td>
+  <td><code>register_num</code>: register that will contain local<br/>
+    <code>name_idx</code>: string index of the name<br/>
+    <code>type_idx</code>: type index of the type<br/>
+    <code>sig_idx</code>: string index of the type signature
+  </td>
+  <td>introduces a local with a type signature at the current address.
+    Any of <code>name_idx</code>, <code>type_idx</code>, or
+    <code>sig_idx</code> may be <code>NO_INDEX</code>
+    to indicate that that value is unknown. (If <code>sig_idx</code> is
+    <code>-1</code>, though, the same data could be represented more
+    efficiently using the opcode <code>DBG_START_LOCAL</code>.)
+    <p><b>Note:</b> See the discussion under
+    "<code>dalvik.annotation.Signature</code>" below for caveats about
+    handling signatures.</p>
+  </td>
+</tr>
+<tr>
+  <td>DBG_END_LOCAL</td>
+  <td>0x05</td>
+  <td>uleb128&nbsp;register_num</td>
+  <td><code>register_num</code>: register that contained local</td>
+  <td>marks a currently-live local variable as out of scope at the current
+    address
+  </td>
+</tr>
+<tr>
+  <td>DBG_RESTART_LOCAL</td>
+  <td>0x06</td>
+  <td>uleb128&nbsp;register_num</td>
+  <td><code>register_num</code>: register to restart</td>
+  <td>re-introduces a local variable at the current address. The name
+    and type are the same as the last local that was live in the specified
+    register.
+  </td>
+</tr>
+<tr>
+  <td>DBG_SET_PROLOGUE_END</td>
+  <td>0x07</td>
+  <td></td>
+  <td><i>(none)</i></td>
+  <td>sets the <code>prologue_end</code> state machine register,
+    indicating that the next position entry that is added should be
+    considered the end of a method prologue (an appropriate place for
+    a method breakpoint). The <code>prologue_end</code> register is
+    cleared by any special (<code>&gt;= 0x0a</code>) opcode.
+  </td>
+</tr>
+<tr>
+  <td>DBG_SET_EPILOGUE_BEGIN</td>
+  <td>0x08</td>
+  <td></td>
+  <td><i>(none)</i></td>
+  <td>sets the <code>epilogue_begin</code> state machine register,
+    indicating that the next position entry that is added should be
+    considered the beginning of a method epilogue (an appropriate place
+    to suspend execution before method exit).
+    The <code>epilogue_begin</code> register is cleared by any special
+    (<code>&gt;= 0x0a</code>) opcode.
+  </td>
+</tr>
+<tr>
+  <td>DBG_SET_FILE</td>
+  <td>0x09</td>
+  <td>uleb128p1&nbsp;name_idx</td>
+  <td><code>name_idx</code>: string index of source file name;
+    <code>NO_INDEX</code> if unknown
+  </td>
+  <td>indicates that all subsequent line number entries make reference to this
+    source file name, instead of the default name specified in
+    <code>code_item</code>
+  </td>
+</tr>
+<tr>
+  <td><i>Special Opcodes</i></td>
+  <!-- When updating the range below, make sure to search for other
+  instances of 0x0a in this section. -->
+  <td>0x0a&hellip;0xff</td>
+  <td></td>
+  <td><i>(none)</i></td>
+  <td>advances the <code>line</code> and <code>address</code> registers,
+    emits a position entry, and clears <code>prologue_end</code> and
+    <code>epilogue_begin</code>. See below for description.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3>Special Opcodes</h3>
+
+<p>Opcodes with values between <code>0x0a</code> and <code>0xff</code>
+(inclusive) move both the <code>line</code> and <code>address</code>
+registers by a small amount and then emit a new position table entry.
+The formula for the increments are as follows:</p>
+
+<pre>
+DBG_FIRST_SPECIAL = 0x0a  // the smallest special opcode
+DBG_LINE_BASE   = -4      // the smallest line number increment
+DBG_LINE_RANGE  = 15      // the number of line increments represented
+
+adjusted_opcode = opcode - DBG_FIRST_SPECIAL
+
+line += DBG_LINE_BASE + (adjusted_opcode % DBG_LINE_RANGE)
+address += (adjusted_opcode / DBG_LINE_RANGE)
+</pre>
+
+<h2><code>annotations_directory_item</code></h2>
+<h4>referenced from <code>class_def_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>class_annotations_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the annotations made directly
+    on the class, or <code>0</code> if the class has no direct annotations.
+    The offset, if non-zero, should be to a location in the
+    <code>data</code> section. The format of the data is specified
+    by "<code>annotation_set_item</code>" below.
+  </td>
+</tr>
+<tr>
+  <td>fields_size</td>
+  <td>uint</td>
+  <td>count of fields annotated by this item</td>
+</tr>
+<tr>
+  <td>annotated_methods_size</td>
+  <td>uint</td>
+  <td>count of methods annotated by this item</td>
+</tr>
+<tr>
+  <td>annotated_parameters_size</td>
+  <td>uint</td>
+  <td>count of method parameter lists annotated by this item</td>
+</tr>
+<tr>
+  <td>field_annotations</td>
+  <td>field_annotation[fields_size] <i>(optional)</i></td>
+  <td>list of associated field annotations. The elements of the list must
+    be sorted in increasing order, by <code>field_idx</code>.
+  </td>
+</tr>
+<tr>
+  <td>method_annotations</td>
+  <td>method_annotation[methods_size] <i>(optional)</i></td>
+  <td>list of associated method annotations. The elements of the list must
+    be sorted in increasing order, by <code>method_idx</code>.
+  </td>
+</tr>
+<tr>
+  <td>parameter_annotations</td>
+  <td>parameter_annotation[parameters_size] <i>(optional)</i></td>
+  <td>list of associated method parameter annotations. The elements of the
+    list must be sorted in increasing order, by <code>method_idx</code>.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<p><b>Note:</b> All elements' <code>field_id</code>s and
+<code>method_id</code>s must refer to the same defining class.</p>
+
+<h3><code>field_annotation</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>field_idx</td>
+  <td>uint</td>
+  <td>index into the <code>field_ids</code> list for the identity of the
+    field being annotated
+  </td>
+</tr>
+<tr>
+  <td>annotations_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the list of annotations for
+    the field. The offset should be to a location in the <code>data</code>
+    section. The format of the data is specified by
+    "<code>annotation_set_item</code>" below.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>method_annotation</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>method_idx</td>
+  <td>uint</td>
+  <td>index into the <code>method_ids</code> list for the identity of the
+    method being annotated
+  </td>
+</tr>
+<tr>
+  <td>annotations_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the list of annotations for
+    the method. The offset should be to a location in the
+    <code>data</code> section. The format of the data is specified by
+    "<code>annotation_set_item</code>" below.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>parameter_annotation</code> Format</h2>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>method_idx</td>
+  <td>uint</td>
+  <td>index into the <code>method_ids</code> list for the identity of the
+    method whose parameters are being annotated
+  </td>
+</tr>
+<tr>
+  <td>annotations_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the list of annotations for
+    the method parameters. The offset should be to a location in the
+    <code>data</code> section. The format of the data is specified by
+    "<code>annotation_set_ref_list</code>" below.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>annotation_set_ref_list</code></h2>
+<h4>referenced from <code>parameter_annotations_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>uint</td>
+  <td>size of the list, in entries</td>
+</tr>
+<tr>
+  <td>list</td>
+  <td>annotation_set_ref_item[size]</td>
+  <td>elements of the list</td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>annotation_set_ref_item</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>annotations_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to the referenced annotation set
+    or <code>0</code> if there are no annotations for this element.
+    The offset, if non-zero, should be to a location in the <code>data</code>
+    section. The format of the data is specified by
+    "<code>annotation_set_item</code>" below.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>annotation_set_item</code></h2>
+<h4>referenced from <code>annotations_directory_item</code>,
+<code>field_annotations_item</code>,
+<code>method_annotations_item</code>, and
+<code>annotation_set_ref_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: 4 bytes</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>size</td>
+  <td>uint</td>
+  <td>size of the set, in entries</td>
+</tr>
+<tr>
+  <td>entries</td>
+  <td>annotation_off_item[size]</td>
+  <td>elements of the set. The elements must be sorted in increasing order,
+    by <code>type_idx</code>.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3><code>annotation_off_item</code> Format</h3>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>annotation_off</td>
+  <td>uint</td>
+  <td>offset from the start of the file to an annotation.
+    The offset should be to a location in the <code>data</code> section,
+    and the format of the data at that location is specified by
+    "<code>annotation_item</code>" below.
+  </td>
+</tr>
+</tbody>
+</table>
+
+
+<h2><code>annotation_item</code></h2>
+<h4>referenced from <code>annotation_set_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: none (byte-aligned)</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>visibility</td>
+  <td>ubyte</td>
+  <td>intended visibility of this annotation (see below)</td>
+</tr>
+<tr>
+  <td>annotation</td>
+  <td>encoded_annotation</td>
+  <td>encoded annotation contents, in the format described by
+    "<code>encoded_annotation</code> Format" under
+    "<code>encoded_value</code> Encoding" above.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h3>Visibility values</h3>
+
+<p>These are the options for the <code>visibility</code> field in an
+<code>annotation_item</code>:</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Value</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>VISIBILITY_BUILD</td>
+  <td>0x00</td>
+  <td>intended only to be visible at build time (e.g., during compilation
+    of other code)
+  </td>
+</tr>
+<tr>
+  <td>VISIBILITY_RUNTIME</td>
+  <td>0x01</td>
+  <td>intended to visible at runtime</td>
+</tr>
+<tr>
+  <td>VISIBILITY_SYSTEM</td>
+  <td>0x02</td>
+  <td>intended to visible at runtime, but only to the underlying system
+    (and not to regular user code)
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>encoded_array_item</code></h2>
+<h4>referenced from <code>class_def_item</code></h4>
+<h4>appears in the <code>data</code> section</h4>
+<h4>alignment: none (byte-aligned)</h4>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>encoded_array</td>
+  <td>bytes representing the encoded array value, in the format specified
+    by "<code>encoded_array</code> Format" under "<code>encoded_value</code>
+    Encoding" above.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h1>System Annotations</h1>
+
+<p>System annotations are used to represent various pieces of reflective
+information about classes (and methods and fields). This information is
+generally only accessed indirectly by client (non-system) code.</p>
+
+<p>System annotations are represented in <code>.dex</code> files as
+annotations with visibility set to <code>VISIBILITY_SYSTEM</code>.
+
+<h2><code>dalvik.annotation.AnnotationDefault</code></h2>
+<h4>appears on methods in annotation interfaces</h4>
+
+<p>An <code>AnnotationDefault</code> annotation is attached to each
+annotation interface which wishes to indicate default bindings.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>Annotation</td>
+  <td>the default bindings for this annotation, represented as an annotation
+    of this type. The annotation need not include all names defined by the
+    annotation; missing names simply do not have defaults.
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>dalvik.annotation.EnclosingClass</code></h2>
+<h4>appears on classes</h4>
+
+<p>An <code>EnclosingClass</code> annotation is attached to each class
+which is either defined as a member of another class, per se, or is
+anonymous but not defined within a method body (e.g., a synthetic
+inner class). Every class that has this annotation must also have an
+<code>InnerClass</code> annotation. Additionally, a class must not have
+both an <code>EnclosingClass</code> and an
+<code>EnclosingMethod</code> annotation.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>Class</td>
+  <td>the class which most closely lexically scopes this class</td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>dalvik.annotation.EnclosingMethod</code></h2>
+<h4>appears on classes</h4>
+
+<p>An <code>EnclosingMethod</code> annotation is attached to each class
+which is defined inside a method body. Every class that has this
+annotation must also have an <code>InnerClass</code> annotation.
+Additionally, a class must not have both an <code>EnclosingClass</code>
+and an <code>EnclosingMethod</code> annotation.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>Method</td>
+  <td>the method which most closely lexically scopes this class</td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>dalvik.annotation.InnerClass</code></h2>
+<h4>appears on classes</h4>
+
+<p>An <code>InnerClass</code> annotation is attached to each class
+which is defined in the lexical scope of another class's definition.
+Any class which has this annotation must also have <i>either</i> an
+<code>EnclosingClass</code> annotation <i>or</i> an
+<code>EnclosingMethod</code> annotation.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>name</td>
+  <td>String</td>
+  <td>the originally declared simple name of this class (not including any
+    package prefix). If this class is anonymous, then the name is
+    <code>null</code>.
+  </td>
+</tr>
+<tr>
+  <td>accessFlags</td>
+  <td>int</td>
+  <td>the originally declared access flags of the class (which may differ
+    from the effective flags because of a mismatch between the execution
+    models of the source language and target virtual machine)
+  </td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>dalvik.annotation.MemberClasses</code></h2>
+<h4>appears on classes</h4>
+
+<p>A <code>MemberClasses</code> annotation is attached to each class
+which declares member classes. (A member class is a direct inner class
+that has a name.)</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>Class[]</td>
+  <td>array of the member classes</td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>dalvik.annotation.Signature</code></h2>
+<h4>appears on classes, fields, and methods</h4>
+
+<p>A <code>Signature</code> annotation is attached to each class,
+field, or method which is defined in terms of a more complicated type
+than is representable by a <code>type_id_item</code>. The
+<code>.dex</code> format does not define the format for signatures; it
+is merely meant to be able to represent whatever signatures a source
+language requires for successful implementation of that language's
+semantics. As such, signatures are not generally parsed (or verified)
+by virtual machine implementations. The signatures simply get handed
+off to higher-level APIs and tools (such as debuggers). Any use of a
+signature, therefore, should be written so as not to make any
+assumptions about only receiving valid signatures, explicitly guarding
+itself against the possibility of coming across a syntactically
+invalid signature.</p>
+
+<p>Because signature strings tend to have a lot of duplicated content,
+a <code>Signature</code> annotation is defined as an <i>array</i> of
+strings, where duplicated elements naturally refer to the same
+underlying data, and the signature is taken to be the concatenation of
+all the strings in the array. There are no rules about how to pull
+apart a signature into separate strings; that is entirely up to the
+tools that generate <code>.dex</code> files.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>String[]</td>
+  <td>the signature of this class or member, as an array of strings that
+    is to be concatenated together</td>
+</tr>
+</tbody>
+</table>
+
+<h2><code>dalvik.annotation.Throws</code></h2>
+<h4>appears on methods</h4>
+
+<p>A <code>Throws</code> annotation is attached to each method which is
+declared to throw one or more exception types.</p>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Name</th>
+  <th>Format</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>value</td>
+  <td>Class[]</td>
+  <td>the array of exception types thrown</td>
+</tr>
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/docs/dexopt.html b/docs/dexopt.html
new file mode 100644
index 0000000..7f0b4bc
--- /dev/null
+++ b/docs/dexopt.html
@@ -0,0 +1,326 @@
+<html>
+<head>
+    <title>Dalvik Optimization and Verification</title>
+</head>
+
+<body>
+<h1>Dalvik Optimization and Verification With <i>dexopt</i></h1>
+
+<p>
+The Dalvik virtual machine was designed specifically for the Android
+mobile platform.  The target systems have little RAM, store data on slow
+internal flash memory, and generally have the performance characteristics
+of decade-old desktop systems.  They also run Linux, which provides
+virtual memory, processes and threads, and UID-based security mechanisms.
+<p>
+The features and limitations caused us to focus on certain goals:
+
+<ul>
+    <li>Class data, notably bytecode, must be shared between multiple
+    processes to minimize total system memory usage.
+    <li>The overhead in launching a new app must be minimized to keep
+    the device responsive.
+    <li>Storing class data in individual files results in a lot of
+    redundancy, especially with respect to strings.  To conserve disk
+    space we need to factor this out.
+    <li>Parsing class data fields adds unnecessary overhead during
+    class loading.  Accessing data values (e.g. integers and strings)
+    directly as C types is better.
+    <li>Bytecode verification is necessary, but slow, so we want to verify
+    as much as possible outside app execution.
+    <li>Bytecode optimization (quickened instructions, method pruning) is
+    important for speed and battery life.
+    <li>For security reasons, processes may not edit shared code.
+</ul>
+
+<p>
+The typical VM implementation uncompresses individual classes from a
+compressed archive and stores them on the heap.  This implies a separate
+copy of each class in every process, and slows application startup because
+the code must be uncompressed (or at least read off disk in many small
+pieces).  On the other hand, having the bytecode on the local heap makes
+it easy to rewrite instructions on first use, facilitating a number of
+different optimizations.
+<p>
+The goals led us to make some fundamental decisions:
+
+<ul>
+    <li>Multiple classes are aggregated into a single "DEX" file.
+    <li>DEX files are mapped read-only and shared between processes.
+    <li>Byte ordering and word alignment are adjusted to suit the local
+    system.
+    <li>Bytecode verification is mandatory for all classes, but we want
+    to "pre-verify" whatever we can.
+    <li>Optimizations that require rewriting bytecode must be done ahead
+    of time.
+</ul>
+
+<p>
+The consequences of these decisions are explained in the following sections.
+
+
+<h2>VM Operation</h2>
+
+<p>
+Application code is delivered to the system in a <code>.jar</code>
+or <code>.apk</code> file.  These are really just <code>.zip</code>
+archives with some meta-data files added.  The Dalvik DEX data file
+is always called <code>classes.dex</code>.
+<p>
+The bytecode cannot be memory-mapped and executed directly from the zip
+file, because the data is compressed and the start of the file is not
+guaranteed to be word-aligned.  These problems could be addressed by
+storing <code>classes.dex</code> without compression and padding out the zip
+file, but that would increase the size of the package sent across the
+data network.
+<p>
+We need to extract <code>classes.dex</code> from the zip archive before
+we can use it.  While we have the file available, we might as well perform
+some of the other actions (realignment, optimization, verification) described
+earlier.  This raises a new question however: who is responsible for doing
+this, and where do we keep the output?
+
+<h3>Preparation</h3>
+
+<p>
+There are at least three different ways to create a "prepared" DEX file,
+sometimes known as "ODEX" (for Optimized DEX):
+<ol>
+    <li>The VM does it "just in time".  The output goes into a special
+    <code>dalvik-cache</code> directory.  This works on the desktop and
+    engineering-only device builds where the permissions on the
+    <code>dalvik-cache</code> directory are not restricted.  On production
+    devices, this is not allowed.
+    <li>The system installer does it when an application is first added.
+    It has the privileges required to write to <code>dalvik-cache</code>.
+    <li>The build system does it ahead of time.  The relevant <code>jar</code>
+    / <code>apk</code> files are present, but the <code>classes.dex</code>
+    is stripped out.  The optimized DEX is stored next to the original
+    zip archive, not in <code>dalvik-cache</code>, and is part of the
+    system image.
+</ol>
+<p>
+The <code>dalvik-cache</code> directory is more accurately
+<code>$ANDROID_DATA/data/dalvik-cache</code>.  The files inside it have
+names derived from the full path of the source DEX.  On the device the
+directory is owned by <code>system</code> / <code>system</code>
+and has 0771 permissions, and the optimized DEX files stored there are
+owned by <code>system</code> and the
+application's group, with 0644 permissions.  DRM-locked applications will
+use 640 permissions to prevent other user applications from examining them.
+The bottom line is that you can read your own DEX file and those of most
+other applications, but you cannot create, modify, or remove them.
+<p>
+Preparation of the DEX file for the "just in time" and "system installer"
+approaches proceeds in three steps:
+<p>
+First, the dalvik-cache file is created.  This must be done in a process
+with appropriate privileges, so for the "system installer" case this is
+done within <code>installd</code>, which runs as root.
+<p>
+Second, the <code>classes.dex</code> entry is extracted from the the zip
+archive.  A small amount of space is left at the start of the file for
+the ODEX header.
+<p>
+Third, the file is memory-mapped for easy access and tweaked for use on
+the current system.  This includes byte-swapping and structure realigning,
+but no meaningful changes to the DEX file.  We also do some basic
+structure checks, such as ensuring that file offsets and data indices
+fall within valid ranges.
+<p>
+The build system uses a hairy process that involves starting the
+emulator, forcing just-in-time optimization of all relevant DEX files,
+and then extracting the results from <code>dalvik-cache</code>.  The
+reasons for doing this, rather than using a tool that runs on the desktop,
+will become more apparent when the optimizations are explained.
+<p>
+Once the code is byte-swapped and aligned, we're ready to go.  We append
+some pre-computed data, fill in the ODEX header at the start of the file,
+and start executing.  (The header is filled in last, so that we don't
+try to use a partial file.)  If we're interested in verification and
+optimization, however, we need to insert a step after the initial prep.
+
+<h3>dexopt</h3>
+
+<p>
+We want to verify and optimize all of the classes in the DEX file.  The
+easiest and safest way to do this is to load all of the classes into
+the VM and run through them.  Anything that fails to load is simply not
+verified or optimized.  Unfortunately, this can cause allocation of some
+resources that are difficult to release (e.g. loading of native shared
+libraries), so we don't want to do it in the same virtual machine that
+we're running applications in.
+<p>
+The solution is to invoke a program called <code>dexopt</code>, which
+is really just a back door into the VM.  It performs an abbreviated VM
+initialization, loads zero or more DEX files from the bootstrap class
+path, and then sets about verifying and optimizing whatever it can from
+the target DEX.  On completion, the process exits, freeing all resources.
+<p>
+It is possible for multiple VMs to want the same DEX file at the same
+time.  File locking is used to ensure that dexopt is only run once.
+
+
+<h2>Verification</h2>
+
+<p>
+The bytecode verification process involves scanning through the instructions
+in every method in every class in a DEX file.  The goal is to identify
+illegal instruction sequences so that we don't have to check for them at
+run time.  Many of the computations involved are also necessary for "exact"
+garbage collection.  See
+<a href="verifier.html">Dalvik Bytecode Verifier Notes</a> for more
+information.
+<p>
+For performance reasons, the optimizer (described in the next section)
+assumes that the verifier has run successfully, and makes some potentially
+unsafe assumptions.  By default, Dalvik insists upon verifying all classes,
+and only optimizes classes that have been verified.  If you want to
+disable the verifier, you can use command-line flags to do so.  See also
+<a href="embedded-vm-control.html"> Controlling the Embedded VM</a>
+for instructions on controlling these
+features within the Android application framework.
+<p>
+Reporting of verification failures is a tricky issue.  For example,
+calling a package-scope method on a class in a different package is
+illegal and will be caught by the verifier.  We don't necessarily want
+to report it during verification though -- we actually want to throw
+an exception when the method call is attempted.  Checking the access
+flags on every method call is expensive though.  The
+<a href="verifier.html">Dalvik Bytecode Verifier Notes</a> document
+addresses this issue.
+<p>
+Classes that have been verified successfully have a flag set in the ODEX.
+They will not be re-verified when loaded.  The Linux access permissions
+are expected to prevent tampering; if you can get around those, installing
+faulty bytecode is far from the easiest line of attack.  The ODEX file has
+a 32-bit checksum, but that's chiefly present as a quick check for
+corrupted data.
+
+
+<h2>Optimization</h2>
+
+<p>
+Virtual machine interpreters typically perform certain optimizations the
+first time a piece of code is used.  Constant pool references are replaced
+with pointers to internal data structures, operations that always succeed
+or always work a certain way are replaced with simpler forms.  Some of
+these require information only available at runtime, others can be inferred
+statically when certain assumptions are made.
+<p>
+The Dalvik optimizer does the following:
+<ul>
+    <li>For virtual method calls, replace the method index with a
+    vtable index.
+    <li>For instance field get/put, replace the field index with
+    a byte offset.  Also, merge the boolean / byte / char / short
+    variants into a single 32-bit form (less code in the interpreter
+    means more room in the CPU I-cache).
+    <li>Replace a handful of high-volume calls, like String.length(),
+    with "inline" replacements.  This skips the usual method call
+    overhead, directly switching from the interpreter to a native
+    implementation.
+    <li>Prune empty methods.  The simplest example is
+    <code>Object.&lt;init&gt;</code>, which does nothing, but must be
+    called whenever any object is allocated.  The instruction is
+    replaced with a new version that acts as a no-op unless a debugger
+    is attached.
+    <li>Append pre-computed data.  For example, the VM wants to have a
+    hash table for lookups on class name.  Instead of computing this
+    when the DEX file is loaded, we can compute it now, saving heap
+    space and computation time in every VM where the DEX is loaded.
+</ul>
+
+<p>
+All of the instruction modifications involve replacing the opcode with
+one not defined by the Dalvik specification.  This allows us to freely
+mix optimized and unoptimized instructions.  The set of optimized
+instructions, and their exact representation, is tied closely to the VM
+version.
+<p>
+Most of the optimizations are obvious "wins".  The use of raw indices
+and offsets not only allows us to execute more quickly, we can also
+skip the initial symbolic resolution.  Pre-computation eats up
+disk space, and so must be done in moderation.
+<p>
+There are a couple of potential sources of trouble with these
+optimizations.  First, vtable indices and byte offsets are subject to
+change if the VM is updated.  Second, if a superclass is in a different
+DEX, and that other DEX is updated, we need to ensure that our optimized
+indices and offsets are updated as well.  A similar but more subtle
+problem emerges when user-defined class loaders are employed: the class
+we actually call may not be the one we expected to call.
+<p>These problems are addressed with dependency lists and some limitations
+on what can be optimized.
+
+
+<h2>Dependencies and Limitations</h2>
+
+<p>
+The optimized DEX file includes a list of dependencies on other DEX files,
+plus the CRC-32 and modification date from the originating
+<code>classes.dex</code> zip file entry.  The dependency list includes the
+full path to the <code>dalvik-cache</code> file, and the file's SHA-1
+signature.  The timestamps of files on the device are unreliable and
+not used.  The dependency area also includes the VM version number.
+<p>
+An optimized DEX is dependent upon all of the DEX files in the bootstrap
+class path.  DEX files that are part of the bootstrap class path depend
+upon the DEX files that appeared earlier.  To ensure that nothing outside
+the dependent DEX files is available, <code>dexopt</code> only loads the
+bootstrap classes.  References to classes in other DEX files fail, which
+causes class loading and/or verification to fail, and classes with
+external dependencies are simply not optimized.
+<p>
+This means that splitting code out into many separate DEX files has a
+disadvantage: virtual method calls and instance field lookups between
+non-boot DEX files can't be optimized.  Because verification is pass/fail
+with class granularity, no method in a class that has any reliance on
+classes in external DEX files can be optimized.  This may be a bit
+heavy-handed, but it's the only way to guarantee that nothing breaks
+when individual pieces are updated.
+<p>
+Another negative consequence: any change to a bootstrap DEX will result
+in rejection of all optimized DEX files.  This makes it hard to keep
+system updates small.
+<p>
+Despite our caution, there is still a possibility that a class in a DEX
+file loaded by a user-defined class loader could ask for a bootstrap class
+(say, String) and be given a different class with the same name.  If a
+class in the DEX file being processed has the same name as a class in the
+bootstrap DEX files, the class will be flagged as ambiguous and references
+to it will not be resolved during verification / optimization.  The class
+linking code in the VM does additional checks to plug another hole;
+see the verbose description in the VM sources for details (vm/oo/Class.c).
+<p>
+If one of the dependencies is updated, we need to re-verify and
+re-optimize the DEX file.  If we can do a just-in-time <code>dexopt</code>
+invocation, this is easy.  If we have to rely on the installer daemon, or
+the DEX was shipped only in ODEX, then the VM has to reject the DEX.
+<p>
+The output of <code>dexopt</code> is byte-swapped and struct-aligned
+for the host, and contains indices and offsets that are highly VM-specific
+(both version-wise and platform-wise).  For this reason it's tricky to
+write a version of <code>dexopt</code> that runs on the desktop but
+generates output suitable for a particular device.  The safest way to
+invoke it is on the target device, or on an emulator for that device.
+
+
+<h2>Generated DEX</h2>
+
+<p>
+Some languages and frameworks rely on the ability to generate bytecode
+and execute it.  The rather heavy <code>dexopt</code> verification and
+optimization model doesn't work well with that.
+<p>
+We intend to support this in a future release, but the exact method is
+to be determined.  We may allow individual classes to be added or whole
+DEX files; may allow Java bytecode or Dalvik bytecode in instructions;
+may perform the usual set of optimizations, or use a separate interpreter
+that performs on-first-use optimizations directly on the bytecode (which
+won't be mapped read-only, since it's locally defined).
+
+<address>Copyright &copy; 2008 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/docs/embedded-vm-control.html b/docs/embedded-vm-control.html
new file mode 100644
index 0000000..5c444de
--- /dev/null
+++ b/docs/embedded-vm-control.html
@@ -0,0 +1,271 @@
+<html>
+<head>
+    <title>Controlling the Embedded VM</title>
+    <link rel=stylesheet href="android.css">
+</head>
+
+<body>
+<h1>Controlling the Embedded VM</h1>
+
+<ul>
+    <li><a href="#introduction">Introduction</a> (read this first!)
+    <li><a href="#checkjni">Extended JNI Checks</a>
+    <li><a href="#assertions">Assertions</a>
+    <li><a href="#verifier">Bytecode Verification and Optimization</a>
+    <li><a href="#execmode">Execution Mode</a>
+    <li><a href="#stackdump">Stack Dumps</a>
+    <li><a href="#dexcheck">DEX File Checksums</a>
+    <li><a href="#general">General Flags</a>
+</ul>
+
+<h2><a name="introduction">Introduction (read this first!)</a></h2>
+
+<p>The Dalvik VM supports a variety of command-line arguments
+(use <code>adb shell dalvikvm -help</code> to get a summary), but
+it's not possible to pass arbitrary arguments through the
+Android application runtime.  It is, however, possible to affect the
+VM behavior through certain system properties.
+
+<p>For all of the features described below, you would set the system property
+with <code>setprop</code>,
+issuing a shell command on the device like this:
+<pre>adb shell setprop &lt;name&gt; &lt;value&gt;</pre>
+
+<p><strong>The Android runtime must be restarted before the changes will take
+effect</strong> (<code>adb shell stop; adb shell start</code>).  This is because the
+settings are processed in the "zygote" process, which starts early and stays
+around "forever".
+
+<p>You may not be able to set <code>dalvik.*</code> properties or restart
+the system as an unprivileged user.  You can use
+<code>adb root</code> or run the <code>su</code> command from the device
+shell on "userdebug" builds to become root first.  When in doubt,
+<pre>adb shell getprop &lt;name&gt;</pre>
+will tell you if the <code>setprop</code> took.
+
+<p>If you don't want the property to evaporate when the device reboots,
+add a line to <code>/data/local.prop</code> that looks like:
+<pre>&lt;name&gt; = &lt;value&gt;</pre>
+
+<p>Such changes will survive reboots, but will be lost if the data
+partition is wiped.  (Hint: create a <code>local.prop</code>
+on your workstation, then <code>adb push local.prop /data</code>.  Or,
+use one-liners like
+<code>adb shell "echo name = value &gt;&gt; /data/local.prop"</code> -- note
+the quotes are important.)
+
+
+<h2><a name="checkjni">Extended JNI Checks</a></h2>
+
+<p>JNI, the Java Native Interface, provides a way for code written in the
+Java programming language
+interact with native (C/C++) code.  The extended JNI checks will cause
+the system to run more slowly, but they can spot a variety of nasty bugs
+before they have a chance to cause problems.
+
+<p>There are two system properties that affect this feature, which is
+enabled with the <code>-Xcheck:jni</code> command-line argument.  The
+first is <code>ro.kernel.android.checkjni</code>.  This is set by the
+Android build system for development builds.  (It may also be set by
+the Android emulator unless the <code>-nojni</code> flag is provided on the
+emulator command line.)  Because this is an "ro." property, the value cannot
+be changed once the device has started.
+
+<p>To allow toggling of the CheckJNI flag, a second
+property, <code>dalvik.vm.checkjni</code>, is also checked.  The value
+of this overrides the value from <code>ro.kernel.android.checkjni</code>.
+
+<p>If neither property is defined, or <code>dalvik.vm.checkjni</code>
+is set to <code>false</code>, the <code>-Xcheck:jni</code> flag is
+not passed in, and JNI checks will be disabled.
+
+<p>To enable JNI checking:
+<pre>adb shell setprop dalvik.vm.checkjni true</pre>
+
+<p>You can also pass JNI-checking options into the VM through a system
+property.  The value set for <code>dalvik.vm.jniopts</code> will
+be passed in as the <code>-Xjniopts</code> argument.  For example:
+<pre>adb shell setprop dalvik.vm.jniopts forcecopy</pre>
+
+
+<h2><a name="assertions">Assertions</a></h2>
+
+<p>Dalvik VM supports the Java programming language "assert" statement.
+By default they are off, but the <code>dalvik.vm.enableassertions</code>
+property provides a way to set the value for a <code>-ea</code> argument.
+
+<p>The argument behaves the same as it does in other desktop VMs.  You
+can provide a class name, a package name (followed by "..."), or the
+special value "all".
+
+<p>For example, this:
+<pre>adb shell setprop dalvik.vm.enableassertions all</pre>
+enables assertions in all non-system classes.
+
+<p>The system property is much more limited than the full command line.
+It is not possible to specify more than one <code>-ea</code> entry, and there
+is no way to specify a <code>-da</code> entry.  There is presently no
+equivalent for <code>-esa</code>/<code>-dsa</code>.
+
+
+<h2><a name="verifier">Bytecode Verification and Optimization</a></h2>
+
+<p>The system tries to pre-verify all classes in a DEX file to reduce
+class load overhead, and performs a series of optimizations to improve
+runtime performance.  Both of these are done by the <code>dexopt</code>
+command, either in the build system or by the installer.  On a development
+device, <code>dexopt</code> may be run the first time a DEX file is used
+and whenever it or one of its dependencies is updated ("just-in-time"
+optimization and verification).
+
+<p>There are two command-line flags that control the just-in-time
+verification and optimization,
+<code>-Xverify</code> and <code>-Xdexopt</code>.  The Android framework
+configures these based on the <code>dalvik.vm.dexopt-flags</code>
+property.
+
+<p>If you set:
+<pre>adb shell setprop dalvik.vm.dexopt-flags v=a,o=v</pre>
+then the framework will pass <code>-Xverify:all -Xdexopt:verified</code>
+to the VM.  This enables verification, and only optimizes classes that
+successfully verified.  This is the safest setting, and is the default.
+<p>You could also set <code>dalvik.vm.dexopt-flags</code> to <code>v=n</code>
+to have the framework pass <code>-Xverify:none -Xdexopt:verified</code>
+to disable verification.  (We could pass in <code>-Xdexopt:all</code> to
+allow optimization, but that wouldn't necessarily optimize more of the
+code, since classes that fail verification may well be skipped by the
+optimizer for the same reasons.)  Classes will not be verified by
+<code>dexopt</code>, and unverified code will be loaded and executed.
+
+<p>Enabling verification will make the <code>dexopt</code> command
+take significantly longer, because the verification process is fairly slow.
+Once the verified and optimized DEX files have been prepared, verification
+incurs no additional overhead except when loading classes that failed
+to pre-verify.
+
+<p>If your DEX files are processed with verification disabled, and you
+later turn the verifier on, application loading will be noticeably
+slower (perhaps 40% or more) as classes are verified on first use.
+
+<p>For best results you should force a re-dexopt of all DEX files when
+this property changes.  You can do this with:
+<pre>adb shell "rm /data/dalvik-cache/*"</pre>
+This removes the cached versions of the DEX files.  Remember to
+stop and restart the runtime (<code>adb shell stop; adb shell start</code>).
+
+<p>(Previous version of the runtime supported the boolean
+<code>dalvik.vm.verify-bytecode</code> property, but that has been
+superceded by <code>dalvik.vm.dexopt-flags</code>.)</p>
+
+
+<h2><a name="execmode">Execution Mode</a></h2>
+
+<p>The current implementation of the Dalvik VM includes three distinct
+interpreter cores.  These are referred to as "fast", "portable", and
+"debug".  The "fast" interpreter is optimized for the current
+platform, and might consist of hand-optimized assembly routines.  In
+constrast, the "portable" interpreter is written in C and expected to
+run on a broad range of platforms.  The "debug" interpreter is a variant
+of "portable" that includes support for profiling and single-stepping.
+
+<p>The VM may also support just-in-time compilation.  While not strictly
+a different interpreter, the JIT compiler may be enabled or disabled
+with the same flag.  (Check the output of <code>dalvikvm -help</code> to
+see if JIT compilation is enabled in your VM.)
+
+<p>The VM allows you to choose between "fast", "portable", and "jit" with an
+extended form of the <code>-Xint</code> argument.  The value of this
+argument can be set through the <code>dalvik.vm.execution-mode</code>
+system property.
+
+<p>To select the "portable" interpreter, you would use:
+<pre>adb shell setprop dalvik.vm.execution-mode int:portable</pre>
+If the property is not specified, the most appropriate interpreter
+will be selected automatically.  At some point this mechanism may allow
+selection of other modes, such as JIT compilation.
+
+<p>Not all platforms have an optimized implementation.  In such cases,
+the "fast" interpreter is generated as a series of C stubs, and the
+result will be slower than the
+"portable" version.  (When we have optimized versions for all popular
+architectures the naming convention will be more accurate.)
+
+<p>If profiling is enabled or a debugger is attached, the VM
+switches to the "debug" interpreter.  When profiling ends or the debugger
+disconnects, the original interpreter is resumed.  (The "debug" interpreter
+is substantially slower, something to keep in mind when evaluating
+profiling data.)
+
+<p>The JIT compiler can be disabled on a per-application basis by adding
+<code>android:vmSafeMode="true"</code> in the <code>application</code>
+tag in <code>AndroidManifest.xml</code>.  This can be useful if you
+suspect that JIT compilation is causing your application to behave
+incorrectly.
+
+
+<h2><a name="stackdump">Stack Dumps</a></h2>
+
+<p>Like other desktop VMs, when the Dalvik VM receives a SIGQUIT
+(Ctrl-\ or <code>kill -3</code>), it dumps stack traces for all threads.
+By default this goes to the Android log, but it can also be written to a file.
+
+<p>The <code>dalvik.vm.stack-trace-file</code> property allows you to
+specify the name of the file where the thread stack traces will be written.
+The file will be created (world writable) if it doesn't exist, and the
+new information will be appended to the end of the file.  The filename
+is passed into the VM via the <code>-Xstacktracefile</code> argument.
+
+<p>For example:
+<pre>adb shell setprop dalvik.vm.stack-trace-file /tmp/stack-traces.txt</pre>
+
+<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.
+
+
+<h2><a name="general">General Flags</a></h2>
+
+<p>In the "Gingerbread" release, a general mechanism for passing flags to
+the VM was introduced:
+
+<pre>adb shell setprop dalvik.vm.extra-opts "flag1 flag2 ... flagN"</pre>
+
+<p>The flags are separated by spaces.  You can specify as many as you want
+so long as they all fit within the system property value length limit
+(currently 92 characters).
+
+<p>The extra-opts flags will be added at the end of the command line,
+which means they will override earlier settings.  This can be used, for
+example, to experiment with different values for <code>-Xmx</code> even
+though the Android framework is setting it explicitly.
+
+<address>Copyright &copy; 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..3707377
--- /dev/null
+++ b/docs/heap-profiling.html
@@ -0,0 +1,215 @@
+<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.
+</p><p>
+In what follows, the version number refers to the software release
+running on the phone.  To take advantage of the DDMS integration, you will
+also need a sufficiently recent version of DDMS.
+
+
+<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 &lt;pid&gt;
+</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 &gt; 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>Android 1.5 ("Cupcake")</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 &lt;dump-file&gt;</code> and <code>adb shell rm
+&lt;dump-file&gt;</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.
+
+
+<h3>Android 1.6 ("Donut")</h3>
+<p>
+No real change to the way profiling works.
+However, 1.6 introduced the <code>WRITE_EXTERNAL_STORAGE</code>
+permission, which is required to write data to the SD card.  If you're
+accustomed to writing profile data to <code>/sdcard</code>, you will
+need to enable the permission in your application's manifest.
+</p>
+
+
+<h3>Android 2.0 ("Eclair")</h3>
+<p>
+In 2.0, features were added that allow DDMS to request a heap dump on
+demand, and automatically pull the result across.  Select your application
+and click the "dump HPROF file" button in the top left.  This always
+writes files to the SD card, so
+you must have a card inserted and the permission enabled in your application.
+</p>
+
+
+<h3>Android 2.2 ("Froyo")</h3>
+<p>
+DDMS heap dump requests are now streamed directly out of the VM, removing
+the external storage requirement.
+</p>
+
+<h3>Android 2.3 ("Gingerbread")</h3>
+<p>
+The <code>kill -10</code> (<code>SIGUSR1</code>) method of generating heap
+dumps has been removed from the VM.
+</p>
+
+<h3>Android 3.0 ("Honeycomb")</h3>
+<p>
+A new command-line tool has been added:
+</p>
+<blockquote><pre>am dumpheap &lt;pid&gt; &lt;output-file-name&gt;</pre></blockquote>
+<p>
+Unlike the <code>SIGUSR1</code> approach, this does not require a rooted
+phone.  It's only necessary for the application to be debuggable (by setting
+<code>android:debuggable="true"</code> in the <code>&lt;application&gt;</code>
+element of the app manifest).  The output file is opened by "am", which
+means you can write the data to a file on <code>/sdcard</code> without
+needing the <code>WRITE_EXTERNAL_STORAGE</code> permission in your app.
+<p>
+The <code>runhat</code> shell function has been updated to use this.
+</p>
+
+<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 &copy; 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..7491a28
--- /dev/null
+++ b/docs/hello-world.html
@@ -0,0 +1,216 @@
+<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>
+&gt; <font color="green">'public static void main(String[] args) {'\</font><br>
+&gt; <font color="green">'System.out.println("Hello, world"); }}' &gt; 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>Using a debugger</h2>
+
+<p>
+You can debug stand-alone applications with any JDWP-compliant debugger.
+There are two basic approaches.
+</p><p>
+The first way is to connect directly through TCP.  Add, to the "dalvikvm"
+invocation line above, an argument like:
+</p><p>
+<code>&nbsp;&nbsp;-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y</code>
+</p><p>
+This tells the VM to wait for a debugger to connect to it on TCP port 8000.
+You need to tell adb to forward local port 8000 to device port 8000:
+</p><p>
+<code>% <font color="green">adb forward tcp:8000 tcp:8000</font></code>
+</p><p>
+and then connect to it with your favorite debugger (using <code>jdb</code>
+as an example here):
+</p><p>
+<code>% <font color="green">jdb -attach localhost:8000</font></code>
+</p><p>
+When the debugger attaches, the VM will be in a suspended state.  You can
+set breakpoints and then tell it to continue.
+
+
+</p><p>
+You can also connect through DDMS, like you would for an Android application.
+Add, to the "dalvikvm" command line:
+</p><p>
+<code>&nbsp;&nbsp;-agentlib:jdwp=transport=dt_android_adb,suspend=y,server=y</code>
+</p><p>
+Note the <code>transport</code> has changed, and you no longer need to
+specify a TCP port number.  When your application starts, it will appear
+in DDMS, with "?" as the application name.  Select it in DDMS, and connect
+to it as usual, e.g.:
+</p><p>
+<code>% <font color="green">jdb -attach localhost:8700</font></code>
+</p><p>
+Because command-line applications don't include the client-side
+DDM setup, features like thread monitoring and allocation tracking will not
+be available in DDMS.  It's strictly a debugger pass-through in this mode.
+</p><p>
+See <a href="debugger.html">Dalvik Debugger Support</a> for more information
+about using debuggers with Dalvik.
+
+
+
+<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 &gt; 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 &copy; 2009 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/docs/instruction-formats.css b/docs/instruction-formats.css
new file mode 100644
index 0000000..a2dc42f
--- /dev/null
+++ b/docs/instruction-formats.css
@@ -0,0 +1,129 @@
+h1 {
+    font-family: serif;
+    color: #222266;
+}
+
+h2 {
+    font-family: serif;
+    border-top-style: solid;
+    border-top-width: 2px;
+    border-color: #ccccdd;
+    padding-top: 12px;
+    margin-top: 48px;
+    margin-bottom: 2px;
+    color: #222266;
+}
+
+h3 {
+    font-family: serif;
+    color: #222266;
+}
+
+@media print {
+    table {
+        font-size: 8pt;
+    }
+}
+
+@media screen {
+    table {
+        font-size: 10pt;
+    }
+}
+
+table th {
+    font-family: sans-serif;
+    background: #aaaaff;
+}
+
+table {
+    border-collapse: collapse;
+}
+
+table td {
+    font-family: sans-serif;
+    border-top-style: solid;
+    border-bottom-style: solid;
+    border-width: 1px;
+    border-color: #aaaaff;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    padding-left: 2px;
+    padding-right: 2px;
+    background: #eeeeff;
+}
+
+
+/* the mnemonic guide */
+
+table.letters {
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table.letters td:first-child {
+    font-family: monospace;
+    width: 10%;
+    text-align: center;
+}
+
+table.letters td:first-child + td {
+    width: 10%;
+    text-align: center;
+}
+
+table.letters td:first-child + td + td {
+    width: 80%;
+}
+
+
+/* the formats, per se */
+
+table.format {
+    background: #aaaaaa;
+    border-collapse: collapse;
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table.format td {
+    font-family: monospace;
+}
+
+table.format td + td i {
+    font-family: sans-serif;
+}
+
+table.format td sub {
+    font-family: sans-serif;
+}
+
+table.format td sub {
+    font-family: sans-serif;
+    font-style: italic;
+    font-size: 70%
+}
+
+table.format th:first-child {
+    width: 28%;
+}
+
+table.format th:first-child + th {
+    width: 5%;
+}
+
+table.format th:first-child + th + th {
+    width: 45%;
+}
+
+table.format th:first-child + th + th + th {
+    width: 22%;
+}
+
+table.format p {
+    margin-bottom: 0pt;
+}
\ No newline at end of file
diff --git a/docs/instruction-formats.html b/docs/instruction-formats.html
new file mode 100644
index 0000000..ada1bb2
--- /dev/null
+++ b/docs/instruction-formats.html
@@ -0,0 +1,515 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+
+<head>
+<title>Dalvik VM Instruction Formats</title>
+<link rel=stylesheet href="instruction-formats.css">
+</head>
+
+<body>
+
+<h1>Dalvik VM Instruction Formats</h1>
+<p>Copyright &copy; 2007 The Android Open Source Project
+
+<h2>Introduction and Overview</h2>
+
+<p>This document lists the instruction formats used by Dalvik bytecode
+and is meant to be used in conjunction with the
+<a href="dalvik-bytecode.html">bytecode reference document</a>.</p>
+
+<h3>Bitwise descriptions</h3>
+
+<p>The first column in the format table lists the bitwise layout of
+the format. It consists of one or more space-separated "words" each of
+which describes a 16-bit code unit. Each character in a word
+represents four bits, read from high bits to low, with vertical bars
+("<code>|</code>") interspersed to aid in reading. Uppercase letters
+in sequence from "<code>A</code>" are used to indicate fields within
+the format (which then get defined further by the syntax column). The term
+"<code>op</code>" is used to indicate the position of an eight-bit
+opcode within the format, and similarly "<code>exop</code>" is used
+to indicate an extended sixteen-bit opcode. A slashed zero
+("<code>&Oslash;</code>") is used to indicate that all bits must be
+zero in the indicated position.</p>
+
+<p>For the most part, lettering proceeds from earlier code units to
+later code units, and low-order to high-order within a code unit.
+However, there are a few exceptions to this general rule, which are
+done in order to make the naming of similar-meaning parts be the same
+across different instruction formats. These cases are noted explicitly
+in the format descriptions.</p>
+
+<p>For example, the format "<code>B|A|<i>op</i> CCCC</code>" indicates
+that the format consists of two 16-bit code units. The first word
+consists of the opcode in the low eight bits and a pair of four-bit
+values in the high eight bits; and the second word consists of a single
+16-bit value.</p>
+
+<h3>Format IDs</h3>
+
+<p>The second column in the format table indicates the short identifier
+for the format, which is used in other documents and in code to identify
+the format.</p>
+
+<p>Most format IDs consist of three characters, two digits followed by a
+letter. The first digit indicates the number of 16-bit code units in the
+format. The second digit indicates the maximum number of registers that the
+format contains (maximum, since some formats can accomodate a variable
+number of registers), with the special designation "<code>r</code>" indicating
+that a range of registers is encoded. The final letter semi-mnemonically
+indicates the type of any extra data encoded by the format. For example,
+format "<code>21t</code>" is of length two, contains one register reference,
+and additionally contains a branch target.</p>
+
+<p>Suggested static linking formats have an additional
+"<code>s</code>" suffix, making them four characters total. Similarly,
+suggested "inline" linking formats have an additional "<code>i</code>"
+suffix. (In this context, inline linking is like static linking,
+except with more direct ties into a virtual machine's implementation.) 
+Finally, a couple oddball suggested formats (e.g.,
+"<code>20bc</code>") include two pieces of data which are both
+represented in its format ID.</p>
+
+<p>The full list of typecode letters are as follows. Note that some
+forms have different sizes, depending on the format:</p>
+
+<table class="letters">
+<thead>
+<tr>
+  <th>Mnemonic</th>
+  <th>Bit Sizes</th>
+  <th>Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td>b</td>
+  <td>8</td>
+  <td>immediate signed <b>b</b>yte</td>
+</tr>
+<tr>
+  <td>c</td>
+  <td>16, 32</td>
+  <td><b>c</b>onstant pool index</td>
+</tr>
+<tr>
+  <td>f</td>
+  <td>16</td>
+  <td>inter<b>f</b>ace constants (only used in statically linked formats)
+  </td>
+</tr>
+<tr>
+  <td>h</td>
+  <td>16</td>
+  <td>immediate signed <b>h</b>at (high-order bits of a 32- or 64-bit
+    value; low-order bits are all <code>0</code>)
+  </td>
+</tr>
+<tr>
+  <td>i</td>
+  <td>32</td>
+  <td>immediate signed <b>i</b>nt, or 32-bit float</td>
+</tr>
+<tr>
+  <td>l</td>
+  <td>64</td>
+  <td>immediate signed <b>l</b>ong, or 64-bit double</td>
+</tr>
+<tr>
+  <td>m</td>
+  <td>16</td>
+  <td><b>m</b>ethod constants (only used in statically linked formats)</td>
+</tr>
+<tr>
+  <td>n</td>
+  <td>4</td>
+  <td>immediate signed <b>n</b>ibble</td>
+</tr>
+<tr>
+  <td>s</td>
+  <td>16</td>
+  <td>immediate signed <b>s</b>hort</td>
+</tr>
+<tr>
+  <td>t</td>
+  <td>8, 16, 32</td>
+  <td>branch <b>t</b>arget</td>
+</tr>
+<tr>
+  <td>x</td>
+  <td>0</td>
+  <td>no additional data</td>
+</tr>
+</tbody>
+</table>
+
+<h3>Syntax</h3>
+
+<p>The third column of the format table indicates the human-oriented
+syntax for instructions which use the indicated format. Each instruction
+starts with the named opcode and is optionally followed by one or
+more arguments, themselves separated with commas.</p>
+
+<p>Wherever an argument refers to a field from the first column, the
+letter for that field is indicated in the syntax, repeated once for
+each four bits of the field. For example, an eight-bit field labeled
+"<code>BB</code>" in the first column would also be labeled
+"<code>BB</code>" in the syntax column.</p>
+
+<p>Arguments which name a register have the form "<code>v<i>X</i></code>".
+The prefix "<code>v</code>" was chosen instead of the more common
+"<code>r</code>" exactly to avoid conflicting with (non-virtual) architectures
+on which a Dalvik virtual machine might be implemented which themselves
+use the prefix "<code>r</code>" for their registers. (That is, this
+decision makes it possible to talk about both virtual and real registers
+together without the need for circumlocution.)</p>
+
+<p>Arguments which indicate a literal value have the form
+"<code>#+<i>X</i></code>". Some formats indicate literals that only
+have non-zero bits in their high-order bits; for these, the zeroes
+are represented explicitly in the syntax, even though they do not
+appear in the bitwise representation.</p>
+
+<p>Arguments which indicate a relative instruction address offset have the
+form "<code>+<i>X</i></code>".</p>
+
+<p>Arguments which indicate a literal constant pool index have the form
+"<code><i>kind</i>@<i>X</i></code>", where "<code><i>kind</i></code>"
+indicates which constant pool is being referred to. Each opcode that
+uses such a format explicitly allows only one kind of constant; see
+the opcode reference to figure out the correspondence. The four
+kinds of constant pool are "<code>string</code>" (string pool index),
+"<code>type</code>" (type pool index), "<code>field</code>" (field
+pool index), and "<code>meth</code>" (method pool index).</p>
+
+<p>Similar to the representation of constant pool indices, there are
+also suggested (optional) forms that indicate prelinked offsets or
+indices. There are two types of suggested prelinked value: vtable offsets
+(indicated as "<code>vtaboff</code>") and field offsets (indicated as
+"<code>fieldoff</code>").</p>
+
+<p>In the cases where a format value isn't explictly part of the syntax
+but instead picks a variant, each variant is listed with the prefix
+"<code>[<i>X</i>=<i>N</i>]</code>" (e.g., "<code>[A=2]</code>") to indicate
+the correspondence.</p>
+
+<h2>The Formats</h2>
+
+<table class="format">
+<thead>
+<tr>
+  <th>Format</th>
+  <th>ID</th>
+  <th>Syntax</th>
+  <th>Notable Opcodes Covered</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+  <td><i>N/A</i></td>
+  <td>00x</td>
+  <td><i><code>N/A</code></i></td>
+  <td><i>pseudo-format used for unused opcodes; suggested for use as the
+    nominal format for a breakpoint opcode</i></td>
+</tr>
+<tr>
+  <td>&Oslash;&Oslash;|<i>op</i></td>
+  <td>10x</td>
+  <td><i><code>op</code></i></td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td rowspan="2">B|A|<i>op</i></td>
+  <td>12x</td>
+  <td><i><code>op</code></i> vA, vB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>11n</td>
+  <td><i><code>op</code></i> vA, #+B</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td rowspan="2">AA|<i>op</i></td>
+  <td>11x</td>
+  <td><i><code>op</code></i> vAA</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>10t</td>
+  <td><i><code>op</code></i> +AA</td>
+  <td>goto</td>
+</tr>
+<tr>
+  <td>&Oslash;&Oslash;|<i>op</i> AAAA</td></td>
+  <td>20t</td>
+  <td><i><code>op</code></i> +AAAA</td>
+  <td>goto/16</td>
+</tr>
+<tr>
+  <td>AA|<i>op</i> BBBB</td></td>
+  <td>20bc</td>
+  <td><i><code>op</code></i> AA, kind@BBBB</td>
+  <td><i>suggested format for statically determined verification errors;
+    A is the type of error and B is an index into a type-appropriate
+    table (e.g. method references for a no-such-method error)</i></td>
+</tr>
+<tr>
+  <td rowspan="5">AA|<i>op</i> BBBB</td>
+  <td>22x</td>
+  <td><i><code>op</code></i> vAA, vBBBB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>21t</td>
+  <td><i><code>op</code></i> vAA, +BBBB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>21s</td>
+  <td><i><code>op</code></i> vAA, #+BBBB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>21h</td>
+  <td><i><code>op</code></i> vAA, #+BBBB0000<br/>
+    <i><code>op</code></i> vAA, #+BBBB000000000000
+  </td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>21c</td>
+  <td><i><code>op</code></i> vAA, type@BBBB<br/>
+    <i><code>op</code></i> vAA, field@BBBB<br/>
+    <i><code>op</code></i> vAA, string@BBBB
+  </td>
+  <td>check-cast<br/>
+    const-class<br/>
+    const-string
+  </td>
+</tr>
+<tr>
+  <td rowspan="2">AA|<i>op</i> CC|BB</td>
+  <td>23x</td>
+  <td><i><code>op</code></i> vAA, vBB, vCC</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>22b</td>
+  <td><i><code>op</code></i> vAA, vBB, #+CC</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td rowspan="4">B|A|<i>op</i> CCCC</td>
+  <td>22t</td>
+  <td><i><code>op</code></i> vA, vB, +CCCC</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>22s</td>
+  <td><i><code>op</code></i> vA, vB, #+CCCC</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>22c</td>
+  <td><i><code>op</code></i> vA, vB, type@CCCC<br/>
+    <i><code>op</code></i> vA, vB, field@CCCC
+  </td>
+  <td>instance-of</td>
+</tr>
+<tr>
+  <td>22cs</td>
+  <td><i><code>op</code></i> vA, vB, fieldoff@CCCC</td>
+  <td><i>suggested format for statically linked field access instructions of
+    format 22c</i>
+  </td>
+</tr>
+<tr>
+  <td>&Oslash;&Oslash;|<i>op</i> AAAA<sub>lo</sub> AAAA<sub>hi</sub></td></td>
+  <td>30t</td>
+  <td><i><code>op</code></i> +AAAAAAAA</td>
+  <td>goto/32</td>
+</tr>
+<tr>
+  <td>&Oslash;&Oslash;|<i>op</i> AAAA BBBB</td>
+  <td>32x</td>
+  <td><i><code>op</code></i> vAAAA, vBBBB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td rowspan="3">AA|<i>op</i> BBBB<sub>lo</sub> BBBB<sub>hi</sub></td>
+  <td>31i</td>
+  <td><i><code>op</code></i> vAA, #+BBBBBBBB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>31t</td>
+  <td><i><code>op</code></i> vAA, +BBBBBBBB</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>31c</td>
+  <td><i><code>op</code></i> vAA, string@BBBBBBBB</td>
+  <td>const-string/jumbo</td>
+</tr>
+<tr>
+  <td rowspan="3">A|G|<i>op</i> BBBB F|E|D|C</td>
+  <td>35c</td>
+  <td><i>[<code>A=5</code>] <code>op</code></i> {vC, vD, vE, vF, vG},
+    meth@BBBB<br/>
+    <i>[<code>A=5</code>] <code>op</code></i> {vC, vD, vE, vF, vG},
+    type@BBBB<br/>
+    <i>[<code>A=4</code>] <code>op</code></i> {vC, vD, vE, vF},
+    <i><code>kind</code></i>@BBBB<br/>
+    <i>[<code>A=3</code>] <code>op</code></i> {vC, vD, vE},
+    <i><code>kind</code></i>@BBBB<br/>
+    <i>[<code>A=2</code>] <code>op</code></i> {vC, vD},
+    <i><code>kind</code></i>@BBBB<br/>
+    <i>[<code>A=1</code>] <code>op</code></i> {vC},
+    <i><code>kind</code></i>@BBBB<br/>
+    <i>[<code>A=0</code>] <code>op</code></i> {},
+    <i><code>kind</code></i>@BBBB<br/>
+    <p><i>The unusual choice in lettering here reflects a desire to make
+    the count and the reference index have the same label as in format
+    3rc.</i></p>
+  </td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>35ms</td>
+  <td><i>[<code>A=5</code>] <code>op</code></i> {vC, vD, vE, vF, vG},
+    vtaboff@BBBB<br/>
+    <i>[<code>A=4</code>] <code>op</code></i> {vC, vD, vE, vF},
+    vtaboff@BBBB<br/>
+    <i>[<code>A=3</code>] <code>op</code></i> {vC, vD, vE},
+    vtaboff@BBBB<br/>
+    <i>[<code>A=2</code>] <code>op</code></i> {vC, vD},
+    vtaboff@BBBB<br/>
+    <i>[<code>A=1</code>] <code>op</code></i> {vC},
+    vtaboff@BBBB<br/>
+    <p><i>The unusual choice in lettering here reflects a desire to make
+    the count and the reference index have the same label as in format
+    3rms.</i></p>
+  </td>
+  <td><i>suggested format for statically linked <code>invoke-virtual</code>
+    and <code>invoke-super</code> instructions of format 35c</i>
+  </td>
+</tr>
+<tr>
+  <td>35mi</td>
+  <td><i>[<code>A=5</code>] <code>op</code></i> {vC, vD, vE, vF, vG},
+    inline@BBBB<br/>
+    <i>[<code>A=4</code>] <code>op</code></i> {vC, vD, vE, vF},
+    inline@BBBB<br/>
+    <i>[<code>A=3</code>] <code>op</code></i> {vC, vD, vE},
+    inline@BBBB<br/>
+    <i>[<code>A=2</code>] <code>op</code></i> {vC, vD},
+    inline@BBBB<br/>
+    <i>[<code>A=1</code>] <code>op</code></i> {vC},
+    inline@BBBB<br/>
+    <p><i>The unusual choice in lettering here reflects a desire to make
+    the count and the reference index have the same label as in format
+    3rmi.</i></p>
+  </td>
+  <td><i>suggested format for inline linked <code>invoke-static</code>
+    and <code>invoke-virtual</code> instructions of format 35c</i>
+  </td>
+</tr>
+<tr>
+  <td rowspan="3">AA|<i>op</i> BBBB CCCC</td>
+  <td>3rc</td>
+  <td><i><code>op</code></i> {vCCCC .. vNNNN}, meth@BBBB<br/>
+    <i><code>op</code></i> {vCCCC .. vNNNN}, type@BBBB<br/>
+    <p><i>where <code>NNNN = CCCC+AA-1</code>, that is <code>A</code>
+    determines the count <code>0..255</code>, and <code>C</code>
+    determines the first register</i></p>
+  </td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>3rms</td>
+  <td><i><code>op</code></i> {vCCCC .. vNNNN}, vtaboff@BBBB<br/>
+    <p><i>where <code>NNNN = CCCC+AA-1</code>, that is <code>A</code>
+    determines the count <code>0..255</code>, and <code>C</code>
+    determines the first register</i></p>
+  </td>
+  <td><i>suggested format for statically linked <code>invoke-virtual</code>
+    and <code>invoke-super</code> instructions of format <code>3rc</code></i>
+  </td>
+</tr>
+<tr>
+  <td>3rmi</td>
+  <td><i><code>op</code></i> {vCCCC .. vNNNN}, inline@BBBB<br/>
+    <p><i>where <code>NNNN = CCCC+AA-1</code>, that is <code>A</code>
+    determines the count <code>0..255</code>, and <code>C</code>
+    determines the first register</i></p>
+  </td>
+  <td><i>suggested format for inline linked <code>invoke-static</code>
+    and <code>invoke-virtual</code> instructions of format 3rc</i>
+  </td>
+</tr>
+<tr>
+  <td>AA|<i>op</i> BBBB<sub>lo</sub> BBBB BBBB BBBB<sub>hi</sub></td>
+  <td>51l</td>
+  <td><i><code>op</code></i> vAA, #+BBBBBBBBBBBBBBBB</td>
+  <td>const-wide</td>
+</tr>
+<tr>
+  <td rowspan="2"><i>exop</i> BB|AA CCCC</td>
+  <td>33x</td>
+  <td><i><code>exop</code></i> vAA, vBB, vCCCC</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td>32s</td>
+  <td><i><code>exop</code></i> vAA, vBB, #+CCCC</td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><i>exop</i> BBBB<sub>lo</sub> BBBB<sub>hi</sub> AAAA</td></td>
+  <td>40sc</td>
+  <td><i><code>exop</code></i> AAAA, kind@BBBBBBBB</td>
+  <td><i>suggested format for statically determined verification errors;
+    see <code>20bc</code>, above</i></td>
+</tr>
+<tr>
+  <td><i>exop</i> BBBB<sub>lo</sub> BBBB<sub>hi</sub> AAAA
+  <td>41c</td>
+  <td><i><code>exop</code></i> vAAAA, field@BBBBBBBB<br/>
+    <i><code>exop</code></i> vAAAA, type@BBBBBBBB
+    <p><i>The unusual choice in lettering here reflects a desire to make
+    the letters match their use in related formats 21c and 31c.</i></p>
+  </td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><i>exop</i> CCCC<sub>lo</sub> CCCC<sub>hi</sub>
+    AAAA BBBB</td>
+  <td>52c</td>
+  <td><i><code>exop</code></i> vAAAA, vBBBB, field@CCCCCCCC<br/>
+    <i><code>exop</code></i> vAAAA, vBBBB, type@CCCCCCCC
+    <p><i>The unusual choice in lettering here reflects a desire to make
+    the letters match their use in related formats 22c and 22cs.</i></p>
+  </td>
+  <td>&nbsp;</td>
+</tr>
+<tr>
+  <td><i>exop</i> BBBB<sub>lo</sub> BBBB<sub>hi</sub>
+    AAAA CCCC</td>
+  <td>5rc</td>
+  <td><i><code>exop</code></i> {vCCCC .. vNNNN}, meth@BBBBBBBB<br/>
+    <i><code>exop</code></i> {vCCCC .. vNNNN}, type@BBBBBBBB<br/>
+    <p><i>where <code>NNNN = CCCC+AAAA-1</code>, that is <code>A</code>
+    determines the count <code>0..65535</code>, and <code>C</code>
+    determines the first register</i></p>
+    <p><i>The unusual choice in lettering here reflects a desire to make
+    the letters match their use in related formats 3rc, 3rms, and 3rmi.</i></p>
+  </td>
+  <td>&nbsp;</td>
+</tr>
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/docs/java-bytecode.css b/docs/java-bytecode.css
new file mode 100644
index 0000000..48984b2
--- /dev/null
+++ b/docs/java-bytecode.css
@@ -0,0 +1,54 @@
+@media print {
+    table {
+        font-size: 8pt;
+    }
+}
+
+@media screen {
+    table {
+        font-size: 10pt;
+    }
+}
+
+h1 {
+    text-align: center;
+}
+
+table {
+    vertical-align: top;
+    border-collapse: collapse;
+    font-family: sans-serif;
+}
+
+td {
+    vertical-align: top;
+    background: #f8f8f8;
+    border-width: 0;
+}
+
+td.outer {
+    width: 25%;
+    padding: 0;
+}
+
+td.outer table {
+    width: 100%;
+}
+
+td.outer td {
+    border-width: 0;
+    background: #f8f8f8;
+    padding: 1pt;
+    padding-left: 10pt;
+    padding-right: 2pt;
+}
+
+tr.d td {
+    background: #dddddd;
+}
+
+td.outer td + td + td {
+    font-family: monospace;
+    font-weight: bold;
+    padding-right: 5pt;
+}
\ No newline at end of file
diff --git a/docs/java-bytecode.html b/docs/java-bytecode.html
new file mode 100644
index 0000000..691ae54
--- /dev/null
+++ b/docs/java-bytecode.html
@@ -0,0 +1,228 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+
+<head>
+<title>Java Bytecode At A Glance</title>
+<link rel="stylesheet" href="java-bytecode.css">
+</head>
+
+<body>
+
+<h1>Java Bytecode At A Glance</h1>
+
+<table align="center">
+<tr><td class="outer"><table>
+<tr><td>0x00</td><td>0</td><td>nop</td></tr>
+<tr><td>0x01</td><td>1</td><td>aconst_null</td></tr>
+<tr class="d"><td>0x02</td><td>2</td><td>iconst_m1</td></tr>
+<tr class="d"><td>0x03</td><td>3</td><td>iconst_0</td></tr>
+<tr><td>0x04</td><td>4</td><td>iconst_1</td></tr>
+<tr><td>0x05</td><td>5</td><td>iconst_2</td></tr>
+<tr class="d"><td>0x06</td><td>6</td><td>iconst_3</td></tr>
+<tr class="d"><td>0x07</td><td>7</td><td>iconst_4</td></tr>
+<tr><td>0x08</td><td>8</td><td>iconst_5</td></tr>
+<tr><td>0x09</td><td>9</td><td>lconst_0</td></tr>
+<tr class="d"><td>0x0a</td><td>10</td><td>lconst_1</td></tr>
+<tr class="d"><td>0x0b</td><td>11</td><td>fconst_0</td></tr>
+<tr><td>0x0c</td><td>12</td><td>fconst_1</td></tr>
+<tr><td>0x0d</td><td>13</td><td>fconst_2</td></tr>
+<tr class="d"><td>0x0e</td><td>14</td><td>dconst_0</td></tr>
+<tr class="d"><td>0x0f</td><td>15</td><td>dconst_1</td></tr>
+<tr><td>0x10</td><td>16</td><td>bipush</td></tr>
+<tr><td>0x11</td><td>17</td><td>sipush</td></tr>
+<tr class="d"><td>0x12</td><td>18</td><td>ldc</td></tr>
+<tr class="d"><td>0x13</td><td>19</td><td>ldc_w</td></tr>
+<tr><td>0x14</td><td>20</td><td>ldc2_w</td></tr>
+<tr><td>0x15</td><td>21</td><td>iload</td></tr>
+<tr class="d"><td>0x16</td><td>22</td><td>lload</td></tr>
+<tr class="d"><td>0x17</td><td>23</td><td>fload</td></tr>
+<tr><td>0x18</td><td>24</td><td>dload</td></tr>
+<tr><td>0x19</td><td>25</td><td>aload</td></tr>
+<tr class="d"><td>0x1a</td><td>26</td><td>iload_0</td></tr>
+<tr class="d"><td>0x1b</td><td>27</td><td>iload_1</td></tr>
+<tr><td>0x1c</td><td>28</td><td>iload_2</td></tr>
+<tr><td>0x1d</td><td>29</td><td>iload_3</td></tr>
+<tr class="d"><td>0x1e</td><td>30</td><td>lload_0</td></tr>
+<tr class="d"><td>0x1f</td><td>31</td><td>lload_1</td></tr>
+<tr><td>0x20</td><td>32</td><td>lload_2</td></tr>
+<tr><td>0x21</td><td>33</td><td>lload_3</td></tr>
+<tr class="d"><td>0x22</td><td>34</td><td>fload_0</td></tr>
+<tr class="d"><td>0x23</td><td>35</td><td>fload_1</td></tr>
+<tr><td>0x24</td><td>36</td><td>fload_2</td></tr>
+<tr><td>0x25</td><td>37</td><td>fload_3</td></tr>
+<tr class="d"><td>0x26</td><td>38</td><td>dload_0</td></tr>
+<tr class="d"><td>0x27</td><td>39</td><td>dload_1</td></tr>
+<tr><td>0x28</td><td>40</td><td>dload_2</td></tr>
+<tr><td>0x29</td><td>41</td><td>dload_3</td></tr>
+<tr class="d"><td>0x2a</td><td>42</td><td>aload_0</td></tr>
+<tr class="d"><td>0x2b</td><td>43</td><td>aload_1</td></tr>
+<tr><td>0x2c</td><td>44</td><td>aload_2</td></tr>
+<tr><td>0x2d</td><td>45</td><td>aload_3</td></tr>
+<tr class="d"><td>0x2e</td><td>46</td><td>iaload</td></tr>
+<tr class="d"><td>0x2f</td><td>47</td><td>laload</td></tr>
+<tr><td>0x30</td><td>48</td><td>faload</td></tr>
+<tr><td>0x31</td><td>49</td><td>daload</td></tr>
+<tr class="d"><td>0x32</td><td>50</td><td>aaload</td></tr>
+</table></td>
+<td class="outer"><table>
+<tr><td>0x33</td><td>51</td><td>baload</td></tr>
+<tr><td>0x34</td><td>52</td><td>caload</td></tr>
+<tr class="d"><td>0x35</td><td>53</td><td>saload</td></tr>
+<tr class="d"><td>0x36</td><td>54</td><td>istore</td></tr>
+<tr><td>0x37</td><td>55</td><td>lstore</td></tr>
+<tr><td>0x38</td><td>56</td><td>fstore</td></tr>
+<tr class="d"><td>0x39</td><td>57</td><td>dstore</td></tr>
+<tr class="d"><td>0x3a</td><td>58</td><td>astore</td></tr>
+<tr><td>0x3b</td><td>59</td><td>istore_0</td></tr>
+<tr><td>0x3c</td><td>60</td><td>istore_1</td></tr>
+<tr class="d"><td>0x3d</td><td>61</td><td>istore_2</td></tr>
+<tr class="d"><td>0x3e</td><td>62</td><td>istore_3</td></tr>
+<tr><td>0x3f</td><td>63</td><td>lstore_0</td></tr>
+<tr><td>0x40</td><td>64</td><td>lstore_1</td></tr>
+<tr class="d"><td>0x41</td><td>65</td><td>lstore_2</td></tr>
+<tr class="d"><td>0x42</td><td>66</td><td>lstore_3</td></tr>
+<tr><td>0x43</td><td>67</td><td>fstore_0</td></tr>
+<tr><td>0x44</td><td>68</td><td>fstore_1</td></tr>
+<tr class="d"><td>0x45</td><td>69</td><td>fstore_2</td></tr>
+<tr class="d"><td>0x46</td><td>70</td><td>fstore_3</td></tr>
+<tr><td>0x47</td><td>71</td><td>dstore_0</td></tr>
+<tr><td>0x48</td><td>72</td><td>dstore_1</td></tr>
+<tr class="d"><td>0x49</td><td>73</td><td>dstore_2</td></tr>
+<tr class="d"><td>0x4a</td><td>74</td><td>dstore_3</td></tr>
+<tr><td>0x4b</td><td>75</td><td>astore_0</td></tr>
+<tr><td>0x4c</td><td>76</td><td>astore_1</td></tr>
+<tr class="d"><td>0x4d</td><td>77</td><td>astore_2</td></tr>
+<tr class="d"><td>0x4e</td><td>78</td><td>astore_3</td></tr>
+<tr><td>0x4f</td><td>79</td><td>iastore</td></tr>
+<tr><td>0x50</td><td>80</td><td>lastore</td></tr>
+<tr class="d"><td>0x51</td><td>81</td><td>fastore</td></tr>
+<tr class="d"><td>0x52</td><td>82</td><td>dastore</td></tr>
+<tr><td>0x53</td><td>83</td><td>aastore</td></tr>
+<tr><td>0x54</td><td>84</td><td>bastore</td></tr>
+<tr class="d"><td>0x55</td><td>85</td><td>castore</td></tr>
+<tr class="d"><td>0x56</td><td>86</td><td>sastore</td></tr>
+<tr><td>0x57</td><td>87</td><td>pop</td></tr>
+<tr><td>0x58</td><td>88</td><td>pop2</td></tr>
+<tr class="d"><td>0x59</td><td>89</td><td>dup</td></tr>
+<tr class="d"><td>0x5a</td><td>90</td><td>dup_x1</td></tr>
+<tr><td>0x5b</td><td>91</td><td>dup_x2</td></tr>
+<tr><td>0x5c</td><td>92</td><td>dup2</td></tr>
+<tr class="d"><td>0x5d</td><td>93</td><td>dup2_x1</td></tr>
+<tr class="d"><td>0x5e</td><td>94</td><td>dup2_x2</td></tr>
+<tr><td>0x5f</td><td>95</td><td>swap</td></tr>
+<tr><td>0x60</td><td>96</td><td>iadd</td></tr>
+<tr class="d"><td>0x61</td><td>97</td><td>ladd</td></tr>
+<tr class="d"><td>0x62</td><td>98</td><td>fadd</td></tr>
+<tr><td>0x63</td><td>99</td><td>dadd</td></tr>
+<tr><td>0x64</td><td>100</td><td>isub</td></tr>
+<tr class="d"><td>0x65</td><td>101</td><td>lsub</td></tr>
+</table></td>
+<td class="outer"><table>
+<tr><td>0x66</td><td>102</td><td>fsub</td></tr>
+<tr><td>0x67</td><td>103</td><td>dsub</td></tr>
+<tr class="d"><td>0x68</td><td>104</td><td>imul</td></tr>
+<tr class="d"><td>0x69</td><td>105</td><td>lmul</td></tr>
+<tr><td>0x6a</td><td>106</td><td>fmul</td></tr>
+<tr><td>0x6b</td><td>107</td><td>dmul</td></tr>
+<tr class="d"><td>0x6c</td><td>108</td><td>idiv</td></tr>
+<tr class="d"><td>0x6d</td><td>109</td><td>ldiv</td></tr>
+<tr><td>0x6e</td><td>110</td><td>fdiv</td></tr>
+<tr><td>0x6f</td><td>111</td><td>ddiv</td></tr>
+<tr class="d"><td>0x70</td><td>112</td><td>irem</td></tr>
+<tr class="d"><td>0x71</td><td>113</td><td>lrem</td></tr>
+<tr><td>0x72</td><td>114</td><td>frem</td></tr>
+<tr><td>0x73</td><td>115</td><td>drem</td></tr>
+<tr class="d"><td>0x74</td><td>116</td><td>ineg</td></tr>
+<tr class="d"><td>0x75</td><td>117</td><td>lneg</td></tr>
+<tr><td>0x76</td><td>118</td><td>fneg</td></tr>
+<tr><td>0x77</td><td>119</td><td>dneg</td></tr>
+<tr class="d"><td>0x78</td><td>120</td><td>ishl</td></tr>
+<tr class="d"><td>0x79</td><td>121</td><td>lshl</td></tr>
+<tr><td>0x7a</td><td>122</td><td>ishr</td></tr>
+<tr><td>0x7b</td><td>123</td><td>lshr</td></tr>
+<tr class="d"><td>0x7c</td><td>124</td><td>iushr</td></tr>
+<tr class="d"><td>0x7d</td><td>125</td><td>lushr</td></tr>
+<tr><td>0x7e</td><td>126</td><td>iand</td></tr>
+<tr><td>0x7f</td><td>127</td><td>land</td></tr>
+<tr class="d"><td>0x80</td><td>128</td><td>ior</td></tr>
+<tr class="d"><td>0x81</td><td>129</td><td>lor</td></tr>
+<tr><td>0x82</td><td>130</td><td>ixor</td></tr>
+<tr><td>0x83</td><td>131</td><td>lxor</td></tr>
+<tr class="d"><td>0x84</td><td>132</td><td>iinc</td></tr>
+<tr class="d"><td>0x85</td><td>133</td><td>i2l</td></tr>
+<tr><td>0x86</td><td>134</td><td>i2f</td></tr>
+<tr><td>0x87</td><td>135</td><td>i2d</td></tr>
+<tr class="d"><td>0x88</td><td>136</td><td>l2i</td></tr>
+<tr class="d"><td>0x89</td><td>137</td><td>l2f</td></tr>
+<tr><td>0x8a</td><td>138</td><td>l2d</td></tr>
+<tr><td>0x8b</td><td>139</td><td>f2i</td></tr>
+<tr class="d"><td>0x8c</td><td>140</td><td>f2l</td></tr>
+<tr class="d"><td>0x8d</td><td>141</td><td>f2d</td></tr>
+<tr><td>0x8e</td><td>142</td><td>d2i</td></tr>
+<tr><td>0x8f</td><td>143</td><td>d2l</td></tr>
+<tr class="d"><td>0x90</td><td>144</td><td>d2f</td></tr>
+<tr class="d"><td>0x91</td><td>145</td><td>i2b</td></tr>
+<tr><td>0x92</td><td>146</td><td>i2c</td></tr>
+<tr><td>0x93</td><td>147</td><td>i2s</td></tr>
+<tr class="d"><td>0x94</td><td>148</td><td>lcmp</td></tr>
+<tr class="d"><td>0x95</td><td>149</td><td>fcmpl</td></tr>
+<tr><td>0x96</td><td>150</td><td>fcmpg</td></tr>
+<tr><td>0x97</td><td>151</td><td>dcmpl</td></tr>
+<tr class="d"><td>0x98</td><td>152</td><td>dcmpg</td></tr>
+</table></td>
+<td class="outer"><table>
+<tr><td>0x99</td><td>153</td><td>ifeq</td></tr>
+<tr><td>0x9a</td><td>154</td><td>ifne</td></tr>
+<tr class="d"><td>0x9b</td><td>155</td><td>iflt</td></tr>
+<tr class="d"><td>0x9c</td><td>156</td><td>ifge</td></tr>
+<tr><td>0x9d</td><td>157</td><td>ifgt</td></tr>
+<tr><td>0x9e</td><td>158</td><td>ifle</td></tr>
+<tr class="d"><td>0x9f</td><td>159</td><td>if_icmpeq</td></tr>
+<tr class="d"><td>0xa0</td><td>160</td><td>if_icmpne</td></tr>
+<tr><td>0xa1</td><td>161</td><td>if_icmplt</td></tr>
+<tr><td>0xa2</td><td>162</td><td>if_icmpge</td></tr>
+<tr class="d"><td>0xa3</td><td>163</td><td>if_icmpgt</td></tr>
+<tr class="d"><td>0xa4</td><td>164</td><td>if_icmple</td></tr>
+<tr><td>0xa5</td><td>165</td><td>if_acmpeq</td></tr>
+<tr><td>0xa6</td><td>166</td><td>if_acmpne</td></tr>
+<tr class="d"><td>0xa7</td><td>167</td><td>goto</td></tr>
+<tr class="d"><td>0xa8</td><td>168</td><td>jsr</td></tr>
+<tr><td>0xa9</td><td>169</td><td>ret</td></tr>
+<tr><td>0xaa</td><td>170</td><td>tableswitch</td></tr>
+<tr class="d"><td>0xab</td><td>171</td><td>lookupswitch</td></tr>
+<tr class="d"><td>0xac</td><td>172</td><td>ireturn</td></tr>
+<tr><td>0xad</td><td>173</td><td>lreturn</td></tr>
+<tr><td>0xae</td><td>174</td><td>freturn</td></tr>
+<tr class="d"><td>0xaf</td><td>175</td><td>dreturn</td></tr>
+<tr class="d"><td>0xb0</td><td>176</td><td>areturn</td></tr>
+<tr><td>0xb1</td><td>177</td><td>return</td></tr>
+<tr><td>0xb2</td><td>178</td><td>getstatic</td></tr>
+<tr class="d"><td>0xb3</td><td>179</td><td>putstatic</td></tr>
+<tr class="d"><td>0xb4</td><td>180</td><td>getfield</td></tr>
+<tr><td>0xb5</td><td>181</td><td>putfield</td></tr>
+<tr><td>0xb6</td><td>182</td><td>invokevirtual</td></tr>
+<tr class="d"><td>0xb7</td><td>183</td><td>invokespecial</td></tr>
+<tr class="d"><td>0xb8</td><td>184</td><td>invokestatic</td></tr>
+<tr><td>0xb9</td><td>185</td><td>invokeinterface</td></tr>
+<tr><td>0xba</td><td>186</td><td><i>(unused)</i></td></tr>
+<tr class="d"><td>0xbb</td><td>187</td><td>new</td></tr>
+<tr class="d"><td>0xbc</td><td>188</td><td>newarray</td></tr>
+<tr><td>0xbd</td><td>189</td><td>anewarray</td></tr>
+<tr><td>0xbe</td><td>190</td><td>arraylength</td></tr>
+<tr class="d"><td>0xbf</td><td>191</td><td>athrow</td></tr>
+<tr class="d"><td>0xc0</td><td>192</td><td>checkcast</td></tr>
+<tr><td>0xc1</td><td>193</td><td>instanceof</td></tr>
+<tr><td>0xc2</td><td>194</td><td>monitorenter</td></tr>
+<tr class="d"><td>0xc3</td><td>195</td><td>monitorexit</td></tr>
+<tr class="d"><td>0xc4</td><td>196</td><td>wide</td></tr>
+<tr><td>0xc5</td><td>197</td><td>multianewarray</td></tr>
+<tr><td>0xc6</td><td>198</td><td>ifnull</td></tr>
+<tr class="d"><td>0xc7</td><td>199</td><td>ifnonnull</td></tr>
+<tr class="d"><td>0xc8</td><td>200</td><td>goto_w</td></tr>
+<tr><td>0xc9</td><td>201</td><td>jsr_w</td></tr>
+</table></td></tr>
+</table>
+
+</body>
+</html>
diff --git a/docs/java-constraints.css b/docs/java-constraints.css
new file mode 100644
index 0000000..a315a73
--- /dev/null
+++ b/docs/java-constraints.css
@@ -0,0 +1,59 @@
+h1 {
+    font-family: serif;
+    color: #222266;
+}
+
+h2 {
+    font-family: serif;
+    border-top-style: solid;
+    border-top-width: 2px;
+    border-color: #ccccdd;
+    padding-top: 12px;
+    margin-top: 48px;
+    margin-bottom: 2px;
+    color: #222266;
+}
+
+@media print {
+    table {
+        font-size: 8pt;
+    }
+}
+
+@media screen {
+    table {
+        font-size: 10pt;
+    }
+}
+
+
+/* general for all tables */
+
+table {
+    border-collapse: collapse;
+    margin-top: 24px;
+    margin-bottom: 24px;
+    margin-left: 48px;
+    margin-right: 48px;
+}
+
+table th {
+    font-family: sans-serif;
+    background: #aabbff;
+    text-align: left;
+}
+
+table td {
+    font-family: sans-serif;
+    border-top-style: solid;
+    border-bottom-style: solid;
+    border-width: 1px;
+    border-color: #aaaaff;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    padding-left: 4px;
+    padding-right: 6px;
+    background: #eeeeff;
+    margin-top: 4pt;
+    margin-bottom: 0pt;
+}
diff --git a/docs/java-constraints.html b/docs/java-constraints.html
new file mode 100644
index 0000000..9d3c434
--- /dev/null
+++ b/docs/java-constraints.html
@@ -0,0 +1,1080 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+  <head>
+    <title>Java bytecode constraints</title>
+    <link rel=stylesheet href="java-constraints.css">
+  </head>
+
+  <body>
+    <h1>
+      Bytecode constraints
+    </h1>
+
+    <p>
+      From the point of view of a piece of code written in the Java
+      programming language or targeted in the same way to <code>.class</code>
+      files, the Dalvik VM aims to behave in a way
+      that is fully consistent with the language's definition.
+      That is, the code running in Dalvik will behave the same as it
+      would have running in any other virtual machine. This includes
+      verification failures.
+      The Dx/Dalvik system will check roughly the same
+      constraints that any other VM would, except as noted in the file
+      <a href="verifier.html">verifier.html</a>. The following table briefly
+      lists all Dx/Dalvik verification constraints together their analogs
+      from the book <i>The Java<super>TM</super> Language Specification</i>,
+      second edition. In the numbering scheme, the first three
+      elements refer to the specification chapter, the fourth one to the
+      bullet inside that chapter. The failure mode specifies whether the
+      constraint will fail during the Dx conversion or during verification in
+      the VM itself.
+    </p>
+
+    <h2>
+      Static constraints
+    </h2>
+
+    <p>
+    Static constraints are constraints on individual elements of the bytecode.
+    They usually can be checked without employing control or data-flow analysis
+    techniques.
+    </p>
+
+    <table>
+      <tr>
+        <th>
+          Identifier
+        </th>
+
+        <th>
+          Description
+        </th>
+
+        <th>
+          Spec equivalent
+        </th>
+
+        <th>
+          Failure mode
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          A1
+        </td>
+
+        <td>
+          The <code>code</code> array must not be empty.
+        </td>
+
+        <td>
+          4.8.1.1
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A2
+        </td>
+
+        <td>
+          The <code>code</code> array must not be larger than 65535 bytes.
+        </td>
+
+        <td>
+          4.8.1.2
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A3
+        </td>
+
+        <td>
+          The first opcode in <code>code</code> array must have index
+          <code>0</code>.
+        </td>
+
+        <td>
+          4.8.1.3
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A4
+        </td>
+
+        <td>
+          The <code>code</code> array must only contain valid opcodes.
+        </td>
+
+        <td>
+          4.8.1.4
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A5
+        </td>
+
+        <td>
+          The index of instruction <code>n+1</code> must equal the index of
+          instruction <code>n</code> plus the length of instruction
+          <code>n</code>, taking into account a possible <code>wide</code>
+          instruction. Opcodes modified by a <code>wide</code> instruction must
+          not be directly reachable.
+        </td>
+
+        <td>
+          4.8.1.5
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A6
+        </td>
+
+        <td>
+          The last instruction in <code>code</code> array must end at index
+          <code>code_length-1</code>.
+        </td>
+
+        <td>
+          4.8.1.6
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A7
+        </td>
+
+        <td>
+          All jump and branch targets must be opcodes within the same method.
+          Opcodes modified by a <code>wide</code> instruction must not be
+          directly reachable via a jump or branch instruction.
+        </td>
+
+        <td>
+          4.8.1.7
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A8
+        </td>
+
+        <td>
+          All targets of a <code>tableswitch</code> instruction must be opcodes
+          within the same method. Upper and lower bounds must be consistent.
+          Opcodes modified by a <code>wide</code> instruction must not be
+          directly reachable via a <code>tableswitch</code> instruction.
+        </td>
+
+        <td>
+          4.8.1.8
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A9
+        </td>
+
+        <td>
+          All targets of a <code>lookupswitch</code> instruction must be opcodes
+          within the same method. Its table must be consistent and sorted
+          low-to-high. Opcodes modified by a <code>wide</code> instruction must
+          not be directly reachable via a <code>lookupswitch</code> instruction.
+        </td>
+
+        <td>
+          4.8.1.9
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A10
+        </td>
+
+        <td>
+          The operands of <code>ldc</code> and <code>ldc_w</code> instructions
+          must be valid indices into the constant pool. The respective entries
+          must be of type <code>CONSTANT_Integer</code>,
+          <code>CONSTANT_Float</code>, or <code>CONSTANT_String</code>.
+        </td>
+
+        <td>
+          4.8.1.10
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A11
+        </td>
+
+        <td>
+          The operands of <code>ldc2_w</code> instructions must be valid indices
+          into the constant pool. The respective entries must be of type
+          <code>CONSTANT_Long</code> or <code>CONSTANT_Double</code>. The
+          subsequent constant pool entry must be valid and remain unused.
+        </td>
+
+        <td>
+          4.8.1.11
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A12
+        </td>
+
+        <td>
+          The Operands of <code>get&lt;kind&gt;</code> and
+          <code>put&lt;kind&gt;</code> instructions must be valid indices into
+          constant pool. The respective entries must be of type
+          <code>CONSTANT_Fieldref</code>.
+        </td>
+
+        <td>
+          4.8.1.12
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A13
+        </td>
+
+        <td>
+          The first two operands of <code>invokevirtual</code>,
+          <code>invokespecial</code>, and <code>invokestatic</code> must form a
+          valid 16-bit index into the constant pool. The respective entries must
+          be of type <code>CONSTANT_Methodref</code>.
+        </td>
+
+        <td>
+          4.8.1.13
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A14
+        </td>
+
+        <td>
+          Methods whose names start with '<' must only be invoked implicitly by
+          the VM, not by class file code. The only exception is the instance
+          initializer, which may be invoked by <code>invokespecial</code>.
+        </td>
+
+        <td>
+          4.8.1.14
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A15
+        </td>
+
+        <td>
+          The first two operands of <code>invokeinterface</code> must form a
+          valid 16-bit index into the constant pool. The entry must be of type
+          <code>CONSTANT_Interface_Methodref</code>. The third operand must
+          specify number of local variables and the fourth operand must always
+          be zero.
+        </td>
+
+        <td>
+          4.8.1.15
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A16
+        </td>
+
+        <td>
+          The operands of <code>instanceof</code>, <code>checkcast</code>,
+          <code>new</code>, and <code>anewarray</code> instructions must
+          be a valid index into the constant pool. The first two operands of
+          <code>multianewarray</code> instruction must form a valid 16-bit index
+          into the constant pool. All respective entries must be of type
+          <code>CONSTANT_Class</code>.
+        </td>
+
+        <td>
+          4.8.1.16
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+     <tr>
+        <td>
+          A17
+        </td>
+
+        <td>
+          The dimensions of an array created by <code>anewarray</code>
+          instructions must be less than <code>256</code>.
+        </td>
+
+        <td>
+          4.8.1.17
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A18
+        </td>
+
+        <td>
+          The <code>new</code> instruction must not reference array classes,
+          interfaces, or abstract classes.
+        </td>
+
+        <td>
+          4.8.1.18
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A19
+        </td>
+
+        <td>
+          The type referenced by a <code>multinewarray</code> instruction must
+          have at least as many dimensions as specified in the instruction. The
+          dimensions operand must not be <code>0</code>
+        </td>
+
+        <td>
+          4.8.1.19
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A20
+        </td>
+
+        <td>
+          The type referenced by a <code>newarray</code> instruction must be a
+          valid, non-reference type.
+        </td>
+
+        <td>
+          4.8.1.20
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A21
+        </td>
+
+        <td>
+          The index operand of instructions explicitly referencing single-width
+          local variables must be non-negative and smaller than
+          <code>max_locals</code>.
+        </td>
+
+        <td>
+          4.8.1.21
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A22
+        </td>
+
+        <td>
+          The index operand of instructions implicitly referencing single-width
+          local variables must be non-negative and smaller than
+          <code>max_locals</code>.
+        </td>
+
+        <td>
+          4.8.1.22
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A23
+        </td>
+
+        <td>
+          The index operand of instructions explicitly referencing double-width
+          local variables must be non-negative and smaller than
+          <code>max_locals-1</code>.
+        </td>
+
+        <td>
+          4.8.1.23
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A24
+        </td>
+
+        <td>
+          The index operand of instructions implicitly referencing double-width
+          local variables must be non-negative and smaller than
+          <code>max_locals-1</code>.
+        </td>
+
+        <td>
+          4.8.1.24
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A25
+        </td>
+
+        <td>
+          The index operand of <code>wide</code> instructions explicitly
+          referencing single-width local variables must be non-negative and
+          smaller than <code>max_locals</code>.
+        </td>
+
+        <td>
+          4.8.1.25
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          A26
+        </td>
+
+        <td>
+          The index operand of <code>wide</code> instructions explicitly
+          referencing double-width local variables must be non-negative and
+          smaller than <code>max_locals-1</code>.
+        </td>
+
+        <td>
+          4.8.1.25
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+    </table>
+
+    <h2>
+      Structural constraints
+    </h2>
+
+    <p>
+    Structural constraints are constraints on relationships between several
+    elements of the bytecode. They usually can't be checked without employing
+    control or data-flow analysis techniques.
+    </p>
+
+    <table>
+      <tr>
+        <th>
+          Identifier
+        </th>
+
+        <th>
+          Description
+        </th>
+
+        <th>
+          Spec equivalent
+        </th>
+
+        <th>
+          Failure mode
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          B1
+        </td>
+
+        <td>
+          The number and types of arguments (operands and local variables) must
+          always match the instruction.
+        </td>
+
+        <td>
+          4.8.2.1
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B2
+        </td>
+
+        <td>
+          The operand stack must have the same depth for all executions paths
+          leading to an instruction.
+        </td>
+
+        <td>
+          4.8.2.2
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B3
+        </td>
+
+        <td>
+          Local variable pairs must never be broken up.
+        </td>
+
+        <td>
+          4.8.2.3
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B4
+        </td>
+
+        <td>
+          A local variable (or pair) has to be assigned first before it can be
+          read.
+        </td>
+
+        <td>
+          4.8.2.4
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B5
+        </td>
+
+        <td>
+          The operand stack must never grow beyond <code>max_stack</code>.
+        </td>
+
+        <td>
+          4.8.2.5
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B6
+        </td>
+
+        <td>
+          The operand stack must never underflow.
+        </td>
+
+        <td>
+          4.8.2.6
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B7
+        </td>
+
+        <td>
+          An <code>invokespecial</code> instruction must only invoke an instance
+          initializer or a method in the current class or one of its
+          superclasses.
+        </td>
+
+        <td>
+          4.8.2.7
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B8
+        </td>
+
+        <td>
+          An instance initializer must only be invoked on an uninitialized
+          instance residing on the operand stack.
+        </td>
+
+        <td>
+          4.8.2.8
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B9
+        </td>
+
+        <td>
+          Instance methods may only be invoked on and instance fields may only
+          be accessed on already initialized instances.
+        </td>
+
+        <td>
+          4.8.2.9
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B10
+        </td>
+
+        <td>
+           The must be no backwards branches with uninitialized instances on the
+           operand stack or in local variables. There must be no code protected
+           by an exception handler that contains local variables with
+           uninitialized instances.
+        </td>
+
+        <td>
+          4.8.2.10
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B11
+        </td>
+
+        <td>
+           An instance initializer must call another instance initializer (same
+           class or superclass) before any instance members can be accessed.
+           Exceptions are non-inherited instance fields, which can be assigned
+           before calling another initializer, and the <code>Object</code> class
+           in general.
+        </td>
+
+        <td>
+          4.8.2.11
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B12
+        </td>
+
+        <td>
+           All actual method arguments must be assignment-compatible with formal
+           arguments.
+        </td>
+
+        <td>
+          4.8.2.12
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B13
+        </td>
+
+        <td>
+           For each instance method invocation, the actual instance must be
+           assignment-compatible with the class or interface specified in the
+           instruction.
+        </td>
+
+        <td>
+          4.8.2.13
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B14
+        </td>
+
+        <td>
+           A returns instruction must match its method's return type.
+        </td>
+
+        <td>
+          4.8.2.14
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B15
+        </td>
+
+        <td>
+           When accessing protected members of a superclass, the actual type of
+           the instance being accessed must be either the current class or one
+           of its subclasses.
+        </td>
+
+        <td>
+          4.8.2.15
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+     <tr>
+        <td>
+          B16
+        </td>
+
+        <td>
+           The type of a value stored into a static field must be
+           assignment-compatible with or convertible to the field's type.
+        </td>
+
+        <td>
+          4.8.2.16
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B17
+        </td>
+
+        <td>
+           The type of a value stored into a field must be assignment-compatible
+           with or convertible to the field's type.
+        </td>
+
+        <td>
+          4.8.2.17
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B18
+        </td>
+
+        <td>
+           The type of every value stored into an array must be
+           assignment-compatible with the array's component type.
+        </td>
+
+        <td>
+          4.8.2.18
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B19
+        </td>
+
+        <td>
+           The operand of an <code>athrow</code> instruction must be
+           assignment-compatible with <code>java.lang.Throwable</code>.
+        </td>
+
+        <td>
+          4.8.2.19
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B20
+        </td>
+
+        <td>
+           The last reachable instruction of a method must either be a backwards
+           jump or branch, a return, or an <code>athrow</code> instruction. It
+           must not be possible to leave the <code>code</code> array at the
+           bottom.
+        </td>
+
+        <td>
+          4.8.2.20
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B21
+        </td>
+
+        <td>
+           Local variable values must not be used as return addresses.
+        </td>
+
+        <td>
+          4.8.2.21
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B22
+        </td>
+
+        <td>
+          There must be a single, uniquely determined return instruction per
+          subroutine call.
+        </td>
+
+        <td>
+          4.8.2.22
+        </td>
+
+        <td>
+          VM
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B23
+        </td>
+
+        <td>
+          Subroutine calls must not be directly or indirectly self-recursive.
+        </td>
+
+        <td>
+          4.8.2.23
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          B24
+        </td>
+
+        <td>
+           <code>ReturnAddress</code> instances must not be reused. If a
+           subroutine returns to a <code>ReturnAddress</code> further up the
+           stack than where its original call instruction is located, then all
+           <code>ReturnAddress</code> instances further down the stack must
+           never be used.
+        </td>
+
+        <td>
+          4.8.2.24
+        </td>
+
+        <td>
+          DX
+        </td>
+      </tr>
+
+    </table>
+  </body>
+</html>
diff --git a/docs/libraries.html b/docs/libraries.html
new file mode 100644
index 0000000..ed2fa72
--- /dev/null
+++ b/docs/libraries.html
@@ -0,0 +1,165 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html>
+
+<head>
+
+<title>Dalvik Libraries</title>
+
+<link rel=stylesheet href="dex-format.css">
+<link href="prettify.css" type="text/css" rel="stylesheet" />
+<script type="text/javascript" src="prettify.js"></script>
+
+<style>
+ul.code li {
+  font-family: monospace;
+}
+</style>
+
+</head>
+
+<body onload="prettyPrint()">
+
+<h1 class="title">Dalvik Libraries</h1>
+
+<p>The Dalvik Libraries, also known as the <i>Android core libraries</i>,
+implement general purpose APIs used by code written in the Java programming
+language. While the libraries themselves don't depend on Android, they do form
+the foundation of the Android framework. Android applications use the Dalvik
+libraries both directly and indirectly for data structures, networking,
+concurrency, I/O, and more.</p>
+
+<p>The Dalvik libraries break down into two categories:</p>
+
+<ul>
+    <li><a href="#vm-specific">Dalvik VM-specific libraries</a></li>
+    <li><a href="#interop">Java programming language interoperability
+        libraries</a></li>
+</ul>
+
+<p>Any system claiming to be Android-compatible must implement these libraries.
+Unless otherwise noted, both the signatures and the behavior of such a system
+need to conform to the Android 1.0 reference implementation. Both types of
+conformance will be checked by the upcoming Android Compatibility Test Suite
+(CTS).</p>
+
+<a name="vm-specific"/><h2>Dalvik VM-specific libraries</h2>
+
+<p>The VM-specific libraries enable requesting or modifying VM-specific
+information. Code that uses these classes is only portable across Dalvik-based
+systems. The VM-specific Dalvik packages include:</p>
+
+<ul class="code">
+  <li>dalvik.annotation</li>
+  <li>dalvik.bytecode</li>
+  <li>dalvik.system</li>
+</ul>
+
+<a name="interop"/><h2>Java programming language interoperability libraries</h2>
+
+<p>This category of library provides a familiar environment for programmers
+writing code in the Java programming language. Much of the implementation of
+this code comes from <a href="http://harmony.apache.org/">Apache Harmony</a>.
+Sometimes, we have to change the Harmony code to make it more suitable for the
+memory and CPU-constrained environments targeted by Dalvik. We delineate
+Dalvik-specific changes like so:
+
+<pre class="prettyprint">
+    private static final long serialVersionUID = 8683452581122892189L;
+
+// BEGIN android-added
+    /** zero-element array */
+    private static final Object[] emptyArray = new Object[0];
+// END android-added
+
+    private transient int firstIndex;
+</pre>
+
+<p>If you change existing Harmony code instead of just inserting new code, use
+<code>android-changed</code> instead of <code>android-added</code>. These
+markers help us keep track of our own changes when we pull down updates from
+Harmony.</p>
+
+<p>Packages in this category include:</p>
+
+<ul class="code">
+  <li>java.io</li>
+  <li>java.lang</li>
+  <li>java.lang.annotation</li>
+  <li>java.lang.ref</li>
+  <li>java.lang.reflect</li>
+  <li>java.math</li>
+  <li>java.net</li>
+  <li>java.nio</li>
+  <li>java.nio.channels</li>
+  <li>java.nio.channels.spi</li>
+  <li>java.nio.charset</li>
+  <li>java.nio.charset.spi</li>
+  <li>java.security</li>
+  <li>java.security.acl</li>
+  <li>java.security.cert</li>
+  <li>java.security.interfaces</li>
+  <li>java.security.spec</li>
+  <li>java.sql</li>
+  <li>java.text</li>
+  <li>java.util</li>
+  <li>java.util.concurrent</li>
+  <li>java.util.concurrent.atomic</li>
+  <li>java.util.concurrent.locks</li>
+  <li>java.util.jar</li>
+  <li>java.util.logging</li>
+  <li>java.util.prefs</li>
+  <li>java.util.regex</li>
+  <li>java.util.zip</li>
+  <li>javax.crypto</li>
+  <li>javax.crypto.interfaces</li>
+  <li>javax.crypto.spec</li>
+  <li>javax.net</li>
+  <li>javax.net.ssl</li>
+  <li>javax.security.auth</li>
+  <li>javax.security.auth.callback</li>
+  <li>javax.security.auth.login</li>
+  <li>javax.security.auth.x500</li>
+  <li>javax.security.cert</li>
+  <li>javax.sql</li>
+  <li>javax.xml</li>
+  <li>javax.xml.parsers</li>
+  <li>org.w3c.dom</li>
+  <li>org.xml.sax</li>
+  <li>org.xml.sax.ext</li>
+  <li>org.xml.sax.helpers</li>
+</ul>
+
+<p>We only provide the core functionality of <code>XMLParser</code> and
+<code>DocumentBuilder</code> in the XML packages. Some methods dealing with XML
+schema were left out because we don't provide the corresponding packages.</p>
+
+<p>In addition to the aforementioned packages, we plan to support the following
+packages some time in the future. We currently have an unfinished
+implementation of 2D drawing and image processing.</p>
+
+<ul class="code">
+  <li>java.awt</li>
+  <li>java.awt.color</li>
+  <li>java.awt.event</li>
+  <li>java.awt.font</li>
+  <li>java.awt.geom</li>
+  <li>java.awt.im</li>
+  <li>java.awt.im.spi</li>
+  <li>java.awt.image</li>
+  <li>java.awt.image.renderable</li>
+  <li>javax.imageio</li>
+  <li>javax.imageio.event</li>
+  <li>javax.imageio.metadata</li>
+  <li>javax.imageio.plugins.bmp</li>
+  <li>javax.imageio.plugins.jpeg</li>
+  <li>javax.imageio.spi</li>
+  <li>javax.imageio.stream</li>
+</ul>
+
+<p style="margin-top: 50px">Copyright &copy; 2008 The Android Open Source
+Project</p>
+
+</body>
+</html>
diff --git a/docs/porting-guide.html b/docs/porting-guide.html
new file mode 100644
index 0000000..d1a1ea3
--- /dev/null
+++ b/docs/porting-guide.html
@@ -0,0 +1,374 @@
+<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>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.
+</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.
+<li>Disable the Dalvik JIT.  You can do this in the general device
+configuration, or by editing the initialization of WITH_JIT in
+<code>dalvik/vm/Dvm.mk</code> to always be <code>false</code>.
+</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>mmm dalvik/vm</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>vm/mterp/config-*</code> files
+for examples.
+</p>
+
+
+<h3>Replacing Stubs</h3>
+
+<p>
+There are roughly 250 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.  You may find it saves a little time to examine
+the output of your compiler for some of the operations.  The
+<a href="porting-proto.c.txt">porting-proto.c</a> sample code can be
+helpful here.
+</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>
+
+
+<h2>Other Performance Issues</h2>
+
+<p>
+The <code>System.arraycopy()</code> function is heavily used.  The
+implementation relies on the bionic C library to provide a fast,
+platform-optimized data copy function for arrays with elements wider
+than one byte.  If you're not using bionic, or your platform does not
+have an implementation of this method, Dalvik will use correct but
+sub-optimal algorithms instead.  For best performance you will want
+to provide your own version.
+</p><p>
+See the comments in <code>dalvik/vm/native/java_lang_System.c</code>
+for details.
+</p>
+
+<p>
+<address>Copyright &copy; 2009 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/docs/porting-proto.c.txt b/docs/porting-proto.c.txt
new file mode 100644
index 0000000..98c6fd3
--- /dev/null
+++ b/docs/porting-proto.c.txt
@@ -0,0 +1,244 @@
+/*
+ * 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 instruction fragments, useful when porting mterp.
+ *
+ * Compile this and examine the output to see what your compiler generates.
+ * This can give you a head start on some of the more complicated operations.
+ *
+ * Example:
+ *   % gcc -c -O2 -save-temps -fverbose-asm porting-proto.c
+ *   % less porting-proto.s
+ */
+#include <stdint.h>
+
+typedef int8_t s1;
+typedef uint8_t u1;
+typedef int16_t s2;
+typedef uint16_t u2;
+typedef int32_t s4;
+typedef uint32_t u4;
+typedef int64_t s8;
+typedef uint64_t u8;
+
+s4 iadd32(s4 x, s4 y) { return x + y; }
+s8 iadd64(s8 x, s8 y) { return x + y; }
+float fadd32(float x, float y) { return x + y; }
+double fadd64(double x, double y) { return x + y; }
+
+s4 isub32(s4 x, s4 y) { return x - y; }
+s8 isub64(s8 x, s8 y) { return x - y; }
+float fsub32(float x, float y) { return x - y; }
+double fsub64(double x, double y) { return x - y; }
+
+s4 irsub32lit8(s4 x) { return 25 - x; }
+
+s4 imul32(s4 x, s4 y) { return x * y; }
+s8 imul64(s8 x, s8 y) { return x * y; }
+float fmul32(float x, float y) { return x * y; }
+double fmul64(double x, double y) { return x * y; }
+
+s4 idiv32(s4 x, s4 y) { return x / y; }
+s8 idiv64(s8 x, s8 y) { return x / y; }
+float fdiv32(float x, float y) { return x / y; }
+double fdiv64(double x, double y) { return x / y; }
+
+s4 irem32(s4 x, s4 y) { return x % y; }
+s8 irem64(s8 x, s8 y) { return x % y; }
+
+s4 iand32(s4 x, s4 y) { return x & y; }
+s8 iand64(s8 x, s8 y) { return x & y; }
+
+s4 ior32(s4 x, s4 y) { return x | y; }
+s8 ior64(s8 x, s8 y) { return x | y; }
+
+s4 ixor32(s4 x, s4 y) { return x ^ y; }
+s8 ixor64(s8 x, s8 y) { return x ^ y; }
+
+s4 iasl32(s4 x, s4 count) { return x << (count & 0x1f); }
+s8 iasl64(s8 x, s4 count) { return x << (count & 0x3f); }
+
+s4 iasr32(s4 x, s4 count) { return x >> (count & 0x1f); }
+s8 iasr64(s8 x, s4 count) { return x >> (count & 0x3f); }
+
+s4 ilsr32(s4 x, s4 count) { return ((u4)x) >> (count & 0x1f); } // unsigned
+s8 ilsr64(s8 x, s4 count) { return ((u8)x) >> (count & 0x3f); } // unsigned
+
+s4 ineg32(s4 x) { return -x; }
+s8 ineg64(s8 x) { return -x; }
+float fneg32(float x) { return -x; }
+double fneg64(double x) { return -x; }
+
+s4 inot32(s4 x) { return x ^ -1; }
+s8 inot64(s8 x) { return x ^ -1LL; }
+
+s4 float2int(float x) { return (s4) x; }
+double float2double(float x) { return (double) x; }
+s4 double2int(double x) { return (s4) x; }
+float double2float(double x) { return (float) x; }
+
+/*
+ * ARM lib doesn't clamp large values or NaN the way we want on these two.
+ * If the simple version isn't correct, use the long version.  (You can use
+ * dalvik/tests/041-narrowing to verify.)
+ */
+s8 float2long(float x) { return (s8) x; }
+s8 float2long_clamp(float x)
+{
+    static const float kMaxLong = (float)0x7fffffffffffffffULL;
+    static const float kMinLong = (float)0x8000000000000000ULL;
+
+    if (x >= kMaxLong) {
+        return 0x7fffffffffffffffULL;
+    } else if (x <= kMinLong) {
+        return 0x8000000000000000ULL;
+    } else if (x != x) {
+        return 0;
+    } else {
+        return (s8) x;
+    }
+}
+s8 double2long(double x) { return (s8) x; }
+s8 double2long_clamp(double x)
+{
+    static const double kMaxLong = (double)0x7fffffffffffffffULL;
+    static const double kMinLong = (double)0x8000000000000000ULL;
+
+    if (x >= kMaxLong) {
+        return 0x7fffffffffffffffULL;
+    } else if (x <= kMinLong) {
+        return 0x8000000000000000ULL;
+    } else if (x != x) {
+        return 0;
+    } else {
+        return (s8) x;
+    }
+}
+
+s1 int2byte(s4 x) { return (s1) x; }
+s2 int2short(s4 x) { return (s2) x; }
+u2 int2char(s4 x) { return (u2) x; }
+s8 int2long(s4 x) { return (s8) x; }
+float int2float(s4 x) { return (float) x; }
+double int2double(s4 x) { return (double) x; }
+
+s4 long2int(s8 x) { return (s4) x; }
+float long2float(s8 x) { return (float) x; }
+double long2double(s8 x) { return (double) x; }
+
+int cmpl_float(float x, float y)
+{
+    int result;
+
+    if (x == y)
+        result = 0;
+    else if (x > y)
+        result = 1;
+    else /* (x < y) or NaN */
+        result = -1;
+    return result;
+}
+
+int cmpg_float(float x, float y)
+{
+    int result;
+
+    if (x == y)
+        result = 0;
+    else if (x < y)
+        result = -1;
+    else /* (x > y) or NaN */
+        result = 1;
+    return result;
+}
+
+int cmpl_double(double x, double y)
+{
+    int result;
+
+    if (x == y)
+        result = 0;
+    else if (x > y)
+        result = 1;
+    else /* (x < y) or NaN */
+        result = -1;
+    return result;
+}
+
+int cmpg_double(double x, double y)
+{
+    int result;
+
+    if (x == y)
+        result = 0;
+    else if (x < y)
+        result = -1;
+    else /* (x > y) or NaN */
+        result = 1;
+    return result;
+}
+
+int cmp_long(s8 x, s8 y)
+{
+    int result;
+
+    if (x == y)
+        result = 0;
+    else if (x < y)
+        result = -1;
+    else /* (x > y) */
+        result = 1;
+    return result;
+}
+
+/* instruction decoding fragments */
+u1 unsignedAA(u2 x) { return x >> 8; }
+s1 signedAA(u2 x) { return (s4)(x << 16) >> 24; }
+s2 signedBB(u2 x) { return (s2) x; }
+u1 unsignedA(u2 x) { return (x >> 8) & 0x0f; }
+u1 unsignedB(u2 x) { return x >> 12; }
+
+/* some handy immediate constants when working with float/double */
+u4 const_43e00000(u4 highword) { return 0x43e00000; }
+u4 const_c3e00000(u4 highword) { return 0xc3e00000; }
+u4 const_ffc00000(u4 highword) { return 0xffc00000; }
+u4 const_41dfffff(u4 highword) { return 0x41dfffff; }
+u4 const_c1e00000(u4 highword) { return 0xc1e00000; }
+
+/*
+ * Test for some gcc-defined symbols.  If you're frequently switching
+ * between different cross-compiler architectures or CPU feature sets,
+ * this can help you keep track of which one you're compiling for.
+ */
+#ifdef __arm__
+# warning "found __arm__"
+#endif
+#ifdef __ARM_EABI__
+# warning "found __ARM_EABI__"
+#endif
+#ifdef __VFP_FP__
+# warning "found __VFP_FP__"    /* VFP-format doubles used; may not have VFP */
+#endif
+#if defined(__VFP_FP__) && !defined(__SOFTFP__)
+# warning "VFP in use"
+#endif
+#ifdef __ARM_ARCH_5TE__
+# warning "found __ARM_ARCH_5TE__"
+#endif
+#ifdef __ARM_ARCH_7A__
+# warning "found __ARM_ARCH_7A__"
+#endif
diff --git a/docs/prettify.css b/docs/prettify.css
new file mode 100644
index 0000000..351152b
--- /dev/null
+++ b/docs/prettify.css
@@ -0,0 +1,27 @@
+/* Pretty printing styles. Used with prettify.js. */
+
+.str { color: #080; }
+.kwd { color: #008; }
+.com { color: #800; }
+.typ { color: #606; }
+.lit { color: #066; }
+.pun { color: #660; }
+.pln { color: #000; }
+.tag { color: #008; }
+.atn { color: #606; }
+.atv { color: #080; }
+.dec { color: #606; }
+pre.prettyprint { padding: 2px; border: 1px solid #888; }
+
+@media print {
+  .str { color: #060; }
+  .kwd { color: #006; font-weight: bold; }
+  .com { color: #600; font-style: italic; }
+  .typ { color: #404; font-weight: bold; }
+  .lit { color: #044; }
+  .pun { color: #440; }
+  .pln { color: #000; }
+  .tag { color: #006; font-weight: bold; }
+  .atn { color: #404; }
+  .atv { color: #060; }
+}
diff --git a/docs/prettify.js b/docs/prettify.js
new file mode 100644
index 0000000..9e99fc6
--- /dev/null
+++ b/docs/prettify.js
@@ -0,0 +1,1280 @@
+// Copyright (C) 2006 Google Inc.
+//
+// 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.
+
+
+/**
+ * @fileoverview
+ * some functions for browser-side pretty printing of code contained in html.
+ *
+ * The lexer should work on a number of languages including C and friends,
+ * Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles.
+ * It works passably on Ruby, PHP and Awk and a decent subset of Perl, but,
+ * because of commenting conventions, doesn't work on Smalltalk, Lisp-like, or
+ * CAML-like languages.
+ *
+ * If there's a language not mentioned here, then I don't know it, and don't
+ * know whether it works.  If it has a C-like, Bash-like, or XML-like syntax
+ * then it should work passably.
+ *
+ * Usage:
+ * 1) include this source file in an html page via
+ * <script type="text/javascript" src="/path/to/prettify.js"></script>
+ * 2) define style rules.  See the example page for examples.
+ * 3) mark the <pre> and <code> tags in your source with class=prettyprint.
+ *    You can also use the (html deprecated) <xmp> tag, but the pretty printer
+ *    needs to do more substantial DOM manipulations to support that, so some
+ *    css styles may not be preserved.
+ * That's it.  I wanted to keep the API as simple as possible, so there's no
+ * need to specify which language the code is in.
+ *
+ * Change log:
+ * cbeust, 2006/08/22
+ *   Java annotations (start with "@") are now captured as literals ("lit")
+ */
+
+// JSLint declarations
+/*global console, document, navigator, setTimeout, window */
+
+/**
+ * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
+ * UI events.
+ * If set to {@code false}, {@code prettyPrint()} is synchronous.
+ */
+var PR_SHOULD_USE_CONTINUATION = true;
+
+/** the number of characters between tab columns */
+var PR_TAB_WIDTH = 8;
+
+/** Walks the DOM returning a properly escaped version of innerHTML.
+  * @param {Node} node
+  * @param {Array.<string>} out output buffer that receives chunks of HTML.
+  */
+var PR_normalizedHtml;
+
+/** Contains functions for creating and registering new language handlers.
+  * @type {Object}
+  */
+var PR;
+
+/** Pretty print a chunk of code.
+  *
+  * @param {string} sourceCodeHtml code as html
+  * @return {string} code as html, but prettier
+  */
+var prettyPrintOne;
+/** find all the < pre > and < code > tags in the DOM with class=prettyprint
+  * and prettify them.
+  * @param {Function} opt_whenDone if specified, called when the last entry
+  *     has been finished.
+  */
+var prettyPrint;
+
+/** browser detection. @extern */
+function _pr_isIE6() {
+  var isIE6 = navigator && navigator.userAgent &&
+      /\bMSIE 6\./.test(navigator.userAgent);
+  _pr_isIE6 = function () { return isIE6; };
+  return isIE6;
+}
+
+
+(function () {
+  /** Splits input on space and returns an Object mapping each non-empty part to
+    * true.
+    */
+  function wordSet(words) {
+    words = words.split(/ /g);
+    var set = {};
+    for (var i = words.length; --i >= 0;) {
+      var w = words[i];
+      if (w) { set[w] = null; }
+    }
+    return set;
+  }
+
+  // Keyword lists for various languages.
+  var FLOW_CONTROL_KEYWORDS =
+      "break continue do else for if return while ";
+  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
+      "double enum extern float goto int long register short signed sizeof " +
+      "static struct switch typedef union unsigned void volatile ";
+  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
+      "new operator private protected public this throw true try ";
+  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
+      "concept concept_map const_cast constexpr decltype " +
+      "dynamic_cast explicit export friend inline late_check " +
+      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
+      "template typeid typename typeof using virtual wchar_t where ";
+  var JAVA_KEYWORDS = COMMON_KEYWORDS +
+      "boolean byte extends final finally implements import instanceof null " +
+      "native package strictfp super synchronized throws transient ";
+  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
+      "as base by checked decimal delegate descending event " +
+      "fixed foreach from group implicit in interface internal into is lock " +
+      "object out override orderby params readonly ref sbyte sealed " +
+      "stackalloc string select uint ulong unchecked unsafe ushort var ";
+  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
+      "debugger eval export function get null set undefined var with " +
+      "Infinity NaN ";
+  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
+      "goto if import last local my next no our print package redo require " +
+      "sub undef unless until use wantarray while BEGIN END ";
+  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
+      "elif except exec finally from global import in is lambda " +
+      "nonlocal not or pass print raise try with yield " +
+      "False True None ";
+  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
+      " defined elsif end ensure false in module next nil not or redo rescue " +
+      "retry self super then true undef unless until when yield BEGIN END ";
+  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
+      "function in local set then until ";
+  var ALL_KEYWORDS = (
+      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
+      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
+
+  // token style names.  correspond to css classes
+  /** token style for a string literal */
+  var PR_STRING = 'str';
+  /** token style for a keyword */
+  var PR_KEYWORD = 'kwd';
+  /** token style for a comment */
+  var PR_COMMENT = 'com';
+  /** token style for a type */
+  var PR_TYPE = 'typ';
+  /** token style for a literal value.  e.g. 1, null, true. */
+  var PR_LITERAL = 'lit';
+  /** token style for a punctuation string. */
+  var PR_PUNCTUATION = 'pun';
+  /** token style for a punctuation string. */
+  var PR_PLAIN = 'pln';
+
+  /** token style for an sgml tag. */
+  var PR_TAG = 'tag';
+  /** token style for a markup declaration such as a DOCTYPE. */
+  var PR_DECLARATION = 'dec';
+  /** token style for embedded source. */
+  var PR_SOURCE = 'src';
+  /** token style for an sgml attribute name. */
+  var PR_ATTRIB_NAME = 'atn';
+  /** token style for an sgml attribute value. */
+  var PR_ATTRIB_VALUE = 'atv';
+
+  /**
+   * A class that indicates a section of markup that is not code, e.g. to allow
+   * embedding of line numbers within code listings.
+   */
+  var PR_NOCODE = 'nocode';
+
+  function isWordChar(ch) {
+    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
+  }
+
+  /** Splice one array into another.
+    * Like the python <code>
+    * container[containerPosition:containerPosition + countReplaced] = inserted
+    * </code>
+    * @param {Array} inserted
+    * @param {Array} container modified in place
+    * @param {Number} containerPosition
+    * @param {Number} countReplaced
+    */
+  function spliceArrayInto(
+      inserted, container, containerPosition, countReplaced) {
+    inserted.unshift(containerPosition, countReplaced || 0);
+    try {
+      container.splice.apply(container, inserted);
+    } finally {
+      inserted.splice(0, 2);
+    }
+  }
+
+  /** A set of tokens that can precede a regular expression literal in
+    * javascript.
+    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
+    * list, but I've removed ones that might be problematic when seen in
+    * languages that don't support regular expression literals.
+    *
+    * <p>Specifically, I've removed any keywords that can't precede a regexp
+    * literal in a syntactically legal javascript program, and I've removed the
+    * "in" keyword since it's not a keyword in many languages, and might be used
+    * as a count of inches.
+    * @private
+    */
+  var REGEXP_PRECEDER_PATTERN = function () {
+      var preceders = [
+          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
+          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
+          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
+          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
+          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
+          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
+          "||=", "~" /* handles =~ and !~ */,
+          "break", "case", "continue", "delete",
+          "do", "else", "finally", "instanceof",
+          "return", "throw", "try", "typeof"
+          ];
+      var pattern = '(?:' +
+          '(?:(?:^|[^0-9.])\\.{1,3})|' +  // a dot that's not part of a number
+          '(?:(?:^|[^\\+])\\+)|' +  // allow + but not ++
+          '(?:(?:^|[^\\-])-)';  // allow - but not --
+      for (var i = 0; i < preceders.length; ++i) {
+        var preceder = preceders[i];
+        if (isWordChar(preceder.charAt(0))) {
+          pattern += '|\\b' + preceder;
+        } else {
+          pattern += '|' + preceder.replace(/([^=<>:&])/g, '\\$1');
+        }
+      }
+      pattern += '|^)\\s*$';  // matches at end, and matches empty string
+      return new RegExp(pattern);
+      // CAVEAT: this does not properly handle the case where a regular
+      // expression immediately follows another since a regular expression may
+      // have flags for case-sensitivity and the like.  Having regexp tokens
+      // adjacent is not
+      // valid in any language I'm aware of, so I'm punting.
+      // TODO: maybe style special characters inside a regexp as punctuation.
+    }();
+
+  // Define regexps here so that the interpreter doesn't have to create an
+  // object each time the function containing them is called.
+  // The language spec requires a new object created even if you don't access
+  // the $1 members.
+  var pr_amp = /&/g;
+  var pr_lt = /</g;
+  var pr_gt = />/g;
+  var pr_quot = /\"/g;
+  /** like textToHtml but escapes double quotes to be attribute safe. */
+  function attribToHtml(str) {
+    return str.replace(pr_amp, '&amp;')
+        .replace(pr_lt, '&lt;')
+        .replace(pr_gt, '&gt;')
+        .replace(pr_quot, '&quot;');
+  }
+
+  /** escapest html special characters to html. */
+  function textToHtml(str) {
+    return str.replace(pr_amp, '&amp;')
+        .replace(pr_lt, '&lt;')
+        .replace(pr_gt, '&gt;');
+  }
+
+
+  var pr_ltEnt = /&lt;/g;
+  var pr_gtEnt = /&gt;/g;
+  var pr_aposEnt = /&apos;/g;
+  var pr_quotEnt = /&quot;/g;
+  var pr_ampEnt = /&amp;/g;
+  var pr_nbspEnt = /&nbsp;/g;
+  /** unescapes html to plain text. */
+  function htmlToText(html) {
+    var pos = html.indexOf('&');
+    if (pos < 0) { return html; }
+    // Handle numeric entities specially.  We can't use functional substitution
+    // since that doesn't work in older versions of Safari.
+    // These should be rare since most browsers convert them to normal chars.
+    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
+      var end = html.indexOf(';', pos);
+      if (end >= 0) {
+        var num = html.substring(pos + 3, end);
+        var radix = 10;
+        if (num && num.charAt(0) === 'x') {
+          num = num.substring(1);
+          radix = 16;
+        }
+        var codePoint = parseInt(num, radix);
+        if (!isNaN(codePoint)) {
+          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
+                  html.substring(end + 1));
+        }
+      }
+    }
+
+    return html.replace(pr_ltEnt, '<')
+        .replace(pr_gtEnt, '>')
+        .replace(pr_aposEnt, "'")
+        .replace(pr_quotEnt, '"')
+        .replace(pr_ampEnt, '&')
+        .replace(pr_nbspEnt, ' ');
+  }
+
+  /** is the given node's innerHTML normally unescaped? */
+  function isRawContent(node) {
+    return 'XMP' === node.tagName;
+  }
+
+  function normalizedHtml(node, out) {
+    switch (node.nodeType) {
+      case 1:  // an element
+        var name = node.tagName.toLowerCase();
+        out.push('<', name);
+        for (var i = 0; i < node.attributes.length; ++i) {
+          var attr = node.attributes[i];
+          if (!attr.specified) { continue; }
+          out.push(' ');
+          normalizedHtml(attr, out);
+        }
+        out.push('>');
+        for (var child = node.firstChild; child; child = child.nextSibling) {
+          normalizedHtml(child, out);
+        }
+        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
+          out.push('<\/', name, '>');
+        }
+        break;
+      case 2: // an attribute
+        out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
+        break;
+      case 3: case 4: // text
+        out.push(textToHtml(node.nodeValue));
+        break;
+    }
+  }
+
+  var PR_innerHtmlWorks = null;
+  function getInnerHtml(node) {
+    // inner html is hopelessly broken in Safari 2.0.4 when the content is
+    // an html description of well formed XML and the containing tag is a PRE
+    // tag, so we detect that case and emulate innerHTML.
+    if (null === PR_innerHtmlWorks) {
+      var testNode = document.createElement('PRE');
+      testNode.appendChild(
+          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
+      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
+    }
+
+    if (PR_innerHtmlWorks) {
+      var content = node.innerHTML;
+      // XMP tags contain unescaped entities so require special handling.
+      if (isRawContent(node)) {
+        content = textToHtml(content);
+      }
+      return content;
+    }
+
+    var out = [];
+    for (var child = node.firstChild; child; child = child.nextSibling) {
+      normalizedHtml(child, out);
+    }
+    return out.join('');
+  }
+
+  /** returns a function that expand tabs to spaces.  This function can be fed
+    * successive chunks of text, and will maintain its own internal state to
+    * keep track of how tabs are expanded.
+    * @return {function (string) : string} a function that takes
+    *   plain text and return the text with tabs expanded.
+    * @private
+    */
+  function makeTabExpander(tabWidth) {
+    var SPACES = '                ';
+    var charInLine = 0;
+
+    return function (plainText) {
+      // walk over each character looking for tabs and newlines.
+      // On tabs, expand them.  On newlines, reset charInLine.
+      // Otherwise increment charInLine
+      var out = null;
+      var pos = 0;
+      for (var i = 0, n = plainText.length; i < n; ++i) {
+        var ch = plainText.charAt(i);
+
+        switch (ch) {
+          case '\t':
+            if (!out) { out = []; }
+            out.push(plainText.substring(pos, i));
+            // calculate how much space we need in front of this part
+            // nSpaces is the amount of padding -- the number of spaces needed
+            // to move us to the next column, where columns occur at factors of
+            // tabWidth.
+            var nSpaces = tabWidth - (charInLine % tabWidth);
+            charInLine += nSpaces;
+            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
+              out.push(SPACES.substring(0, nSpaces));
+            }
+            pos = i + 1;
+            break;
+          case '\n':
+            charInLine = 0;
+            break;
+          default:
+            ++charInLine;
+        }
+      }
+      if (!out) { return plainText; }
+      out.push(plainText.substring(pos));
+      return out.join('');
+    };
+  }
+
+  // The below pattern matches one of the following
+  // (1) /[^<]+/ : A run of characters other than '<'
+  // (2) /<!--.*?-->/: an HTML comment
+  // (3) /<!\[CDATA\[.*?\]\]>/: a cdata section
+  // (3) /<\/?[a-zA-Z][^>]*>/ : A probably tag that should not be highlighted
+  // (4) /</ : A '<' that does not begin a larger chunk.  Treated as 1
+  var pr_chunkPattern =
+  /(?:[^<]+|<!--[\s\S]*?-->|<!\[CDATA\[([\s\S]*?)\]\]>|<\/?[a-zA-Z][^>]*>|<)/g;
+  var pr_commentPrefix = /^<!--/;
+  var pr_cdataPrefix = /^<\[CDATA\[/;
+  var pr_brPrefix = /^<br\b/i;
+  var pr_tagNameRe = /^<(\/?)([a-zA-Z]+)/;
+
+  /** split markup into chunks of html tags (style null) and
+    * plain text (style {@link #PR_PLAIN}), converting tags which are
+    * significant for tokenization (<br>) into their textual equivalent.
+    *
+    * @param {string} s html where whitespace is considered significant.
+    * @return {Object} source code and extracted tags.
+    * @private
+    */
+  function extractTags(s) {
+    // since the pattern has the 'g' modifier and defines no capturing groups,
+    // this will return a list of all chunks which we then classify and wrap as
+    // PR_Tokens
+    var matches = s.match(pr_chunkPattern);
+    var sourceBuf = [];
+    var sourceBufLen = 0;
+    var extractedTags = [];
+    if (matches) {
+      for (var i = 0, n = matches.length; i < n; ++i) {
+        var match = matches[i];
+        if (match.length > 1 && match.charAt(0) === '<') {
+          if (pr_commentPrefix.test(match)) { continue; }
+          if (pr_cdataPrefix.test(match)) {
+            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
+            sourceBuf.push(match.substring(9, match.length - 3));
+            sourceBufLen += match.length - 12;
+          } else if (pr_brPrefix.test(match)) {
+            // <br> tags are lexically significant so convert them to text.
+            // This is undone later.
+            sourceBuf.push('\n');
+            ++sourceBufLen;
+          } else {
+            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
+              // A <span class="nocode"> will start a section that should be
+              // ignored.  Continue walking the list until we see a matching end
+              // tag.
+              var name = match.match(pr_tagNameRe)[2];
+              var depth = 1;
+              end_tag_loop:
+              for (var j = i + 1; j < n; ++j) {
+                var name2 = matches[j].match(pr_tagNameRe);
+                if (name2 && name2[2] === name) {
+                  if (name2[1] === '/') {
+                    if (--depth === 0) { break end_tag_loop; }
+                  } else {
+                    ++depth;
+                  }
+                }
+              }
+              if (j < n) {
+                extractedTags.push(
+                    sourceBufLen, matches.slice(i, j + 1).join(''));
+                i = j;
+              } else {  // Ignore unclosed sections.
+                extractedTags.push(sourceBufLen, match);
+              }
+            } else {
+              extractedTags.push(sourceBufLen, match);
+            }
+          }
+        } else {
+          var literalText = htmlToText(match);
+          sourceBuf.push(literalText);
+          sourceBufLen += literalText.length;
+        }
+      }
+    }
+    return { source: sourceBuf.join(''), tags: extractedTags };
+  }
+
+  /** True if the given tag contains a class attribute with the nocode class. */
+  function isNoCodeTag(tag) {
+    return !!tag
+        // First canonicalize the representation of attributes
+        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
+                 ' $1="$2$3$4"')
+        // Then look for the attribute we want.
+        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
+  }
+
+  /** Given triples of [style, pattern, context] returns a lexing function,
+    * The lexing function interprets the patterns to find token boundaries and
+    * returns a decoration list of the form
+    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
+    * where index_n is an index into the sourceCode, and style_n is a style
+    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
+    * all characters in sourceCode[index_n-1:index_n].
+    *
+    * The stylePatterns is a list whose elements have the form
+    * [style : string, pattern : RegExp, context : RegExp, shortcut : string].
+    &
+    * Style is a style constant like PR_PLAIN.
+    *
+    * Pattern must only match prefixes, and if it matches a prefix and context
+    * is null or matches the last non-comment token parsed, then that match is
+    * considered a token with the same style.
+    *
+    * Context is applied to the last non-whitespace, non-comment token
+    * recognized.
+    *
+    * Shortcut is an optional string of characters, any of which, if the first
+    * character, gurantee that this pattern and only this pattern matches.
+    *
+    * @param {Array} shortcutStylePatterns patterns that always start with
+    *   a known character.  Must have a shortcut string.
+    * @param {Array} fallthroughStylePatterns patterns that will be tried in
+    *   order if the shortcut ones fail.  May have shortcuts.
+    *
+    * @return {function (string, number?) : Array.<number|string>} a
+    *   function that takes source code and returns a list of decorations.
+    */
+  function createSimpleLexer(shortcutStylePatterns,
+                             fallthroughStylePatterns) {
+    var shortcuts = {};
+    (function () {
+      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
+      for (var i = allPatterns.length; --i >= 0;) {
+        var patternParts = allPatterns[i];
+        var shortcutChars = patternParts[3];
+        if (shortcutChars) {
+          for (var c = shortcutChars.length; --c >= 0;) {
+            shortcuts[shortcutChars.charAt(c)] = patternParts;
+          }
+        }
+      }
+    })();
+
+    var nPatterns = fallthroughStylePatterns.length;
+    var notWs = /\S/;
+
+    return function (sourceCode, opt_basePos) {
+      opt_basePos = opt_basePos || 0;
+      var decorations = [opt_basePos, PR_PLAIN];
+      var lastToken = '';
+      var pos = 0;  // index into sourceCode
+      var tail = sourceCode;
+
+      while (tail.length) {
+        var style;
+        var token = null;
+        var match;
+
+        var patternParts = shortcuts[tail.charAt(0)];
+        if (patternParts) {
+          match = tail.match(patternParts[1]);
+          token = match[0];
+          style = patternParts[0];
+        } else {
+          for (var i = 0; i < nPatterns; ++i) {
+            patternParts = fallthroughStylePatterns[i];
+            var contextPattern = patternParts[2];
+            if (contextPattern && !contextPattern.test(lastToken)) {
+              // rule can't be used
+              continue;
+            }
+            match = tail.match(patternParts[1]);
+            if (match) {
+              token = match[0];
+              style = patternParts[0];
+              break;
+            }
+          }
+
+          if (!token) {  // make sure that we make progress
+            style = PR_PLAIN;
+            token = tail.substring(0, 1);
+          }
+        }
+
+        decorations.push(opt_basePos + pos, style);
+        pos += token.length;
+        tail = tail.substring(token.length);
+        if (style !== PR_COMMENT && notWs.test(token)) { lastToken = token; }
+      }
+      return decorations;
+    };
+  }
+
+  var PR_MARKUP_LEXER = createSimpleLexer([], [
+      [PR_PLAIN,       /^[^<]+/, null],
+      [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/, null],
+      [PR_COMMENT,     /^<!--[\s\S]*?(?:-->|$)/, null],
+      [PR_SOURCE,      /^<\?[\s\S]*?(?:\?>|$)/, null],
+      [PR_SOURCE,      /^<%[\s\S]*?(?:%>|$)/, null],
+      [PR_SOURCE,
+       // Tags whose content is not escaped, and which contain source code.
+       /^<(script|style|xmp)\b[^>]*>[\s\S]*?<\/\1\b[^>]*>/i, null],
+      [PR_TAG,         /^<\/?\w[^<>]*>/, null]
+      ]);
+  // Splits any of the source|style|xmp entries above into a start tag,
+  // source content, and end tag.
+  var PR_SOURCE_CHUNK_PARTS = /^(<[^>]*>)([\s\S]*)(<\/[^>]*>)$/;
+  /** split markup on tags, comments, application directives, and other top
+    * level constructs.  Tags are returned as a single token - attributes are
+    * not yet broken out.
+    * @private
+    */
+  function tokenizeMarkup(source) {
+    var decorations = PR_MARKUP_LEXER(source);
+    for (var i = 0; i < decorations.length; i += 2) {
+      if (decorations[i + 1] === PR_SOURCE) {
+        var start, end;
+        start = decorations[i];
+        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+        // Split out start and end script tags as actual tags, and leave the
+        // body with style SCRIPT.
+        var sourceChunk = source.substring(start, end);
+        var match = sourceChunk.match(PR_SOURCE_CHUNK_PARTS);
+        if (match) {
+          decorations.splice(
+              i, 2,
+              start, PR_TAG,  // the open chunk
+              start + match[1].length, PR_SOURCE,
+              start + match[1].length + (match[2] || '').length, PR_TAG);
+        }
+      }
+    }
+    return decorations;
+  }
+
+  var PR_TAG_LEXER = createSimpleLexer([
+      [PR_ATTRIB_VALUE, /^\'[^\']*(?:\'|$)/, null, "'"],
+      [PR_ATTRIB_VALUE, /^\"[^\"]*(?:\"|$)/, null, '"'],
+      [PR_PUNCTUATION,  /^[<>\/=]+/, null, '<>/=']
+      ], [
+      [PR_TAG,          /^[\w:\-]+/, /^</],
+      [PR_ATTRIB_VALUE, /^[\w\-]+/, /^=/],
+      [PR_ATTRIB_NAME,  /^[\w:\-]+/, null],
+      [PR_PLAIN,        /^\s+/, null, ' \t\r\n']
+      ]);
+  /** split tags attributes and their values out from the tag name, and
+    * recursively lex source chunks.
+    * @private
+    */
+  function splitTagAttributes(source, decorations) {
+    for (var i = 0; i < decorations.length; i += 2) {
+      var style = decorations[i + 1];
+      if (style === PR_TAG) {
+        var start, end;
+        start = decorations[i];
+        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+        var chunk = source.substring(start, end);
+        var subDecorations = PR_TAG_LEXER(chunk, start);
+        spliceArrayInto(subDecorations, decorations, i, 2);
+        i += subDecorations.length - 2;
+      }
+    }
+    return decorations;
+  }
+
+  /** returns a function that produces a list of decorations from source text.
+    *
+    * This code treats ", ', and ` as string delimiters, and \ as a string
+    * escape.  It does not recognize perl's qq() style strings.
+    * It has no special handling for double delimiter escapes as in basic, or
+    * the tripled delimiters used in python, but should work on those regardless
+    * although in those cases a single string literal may be broken up into
+    * multiple adjacent string literals.
+    *
+    * It recognizes C, C++, and shell style comments.
+    *
+    * @param {Object} options a set of optional parameters.
+    * @return {function (string) : Array.<string|number>} a
+    *     decorator that takes sourceCode as plain text and that returns a
+    *     decoration list
+    */
+  function sourceDecorator(options) {
+    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
+    if (options.tripleQuotedStrings) {
+      // '''multi-line-string''', 'single-line-string', and double-quoted
+      shortcutStylePatterns.push(
+          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
+           null, '\'"']);
+    } else if (options.multiLineStrings) {
+      // 'multi-line-string', "multi-line-string"
+      shortcutStylePatterns.push(
+          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
+           null, '\'"`']);
+    } else {
+      // 'single-line-string', "single-line-string"
+      shortcutStylePatterns.push(
+          [PR_STRING,
+           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
+           null, '"\'']);
+    }
+    fallthroughStylePatterns.push(
+        [PR_PLAIN,   /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n']);
+    if (options.hashComments) {
+      shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
+    }
+    if (options.cStyleComments) {
+      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
+      fallthroughStylePatterns.push(
+          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
+    }
+    if (options.regexLiterals) {
+      var REGEX_LITERAL = (
+          // A regular expression literal starts with a slash that is
+          // not followed by * or / so that it is not confused with
+          // comments.
+          '^/(?=[^/*])'
+          // and then contains any number of raw characters,
+          + '(?:[^/\\x5B\\x5C]'
+          // escape sequences (\x5C),
+          +    '|\\x5C[\\s\\S]'
+          // or non-nesting character sets (\x5B\x5D);
+          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
+          // finally closed by a /.
+          + '(?:/|$)');
+      fallthroughStylePatterns.push(
+          [PR_STRING, new RegExp(REGEX_LITERAL), REGEXP_PRECEDER_PATTERN]);
+    }
+
+    var keywords = wordSet(options.keywords);
+
+    options = null;
+
+    /** splits the given string into comment, string, and "other" tokens.
+      * @param {string} sourceCode as plain text
+      * @return {Array.<number|string>} a decoration list.
+      * @private
+      */
+    var splitStringAndCommentTokens = createSimpleLexer(
+        shortcutStylePatterns, fallthroughStylePatterns);
+
+    var styleLiteralIdentifierPuncRecognizer = createSimpleLexer([], [
+        [PR_PLAIN,       /^\s+/, null, ' \r\n'],
+        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
+        [PR_PLAIN,       /^[a-z_$@][a-z_$@0-9]*/i, null],
+        // A hex number
+        [PR_LITERAL,     /^0x[a-f0-9]+[a-z]/i, null],
+        // An octal or decimal number, possibly in scientific notation
+        [PR_LITERAL,
+         /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i,
+         null, '123456789'],
+        [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null]
+        // Fallback will handle decimal points not adjacent to a digit
+      ]);
+
+    /** splits plain text tokens into more specific tokens, and then tries to
+      * recognize keywords, and types.
+      * @private
+      */
+    function splitNonStringNonCommentTokens(source, decorations) {
+      for (var i = 0; i < decorations.length; i += 2) {
+        var style = decorations[i + 1];
+        if (style === PR_PLAIN) {
+          var start, end, chunk, subDecs;
+          start = decorations[i];
+          end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+          chunk = source.substring(start, end);
+          subDecs = styleLiteralIdentifierPuncRecognizer(chunk, start);
+          for (var j = 0, m = subDecs.length; j < m; j += 2) {
+            var subStyle = subDecs[j + 1];
+            if (subStyle === PR_PLAIN) {
+              var subStart = subDecs[j];
+              var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length;
+              var token = source.substring(subStart, subEnd);
+              if (token === '.') {
+                subDecs[j + 1] = PR_PUNCTUATION;
+              } else if (token in keywords) {
+                subDecs[j + 1] = PR_KEYWORD;
+              } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) {
+                // classify types and annotations using Java's style conventions
+                subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE;
+              }
+            }
+          }
+          spliceArrayInto(subDecs, decorations, i, 2);
+          i += subDecs.length - 2;
+        }
+      }
+      return decorations;
+    }
+
+    return function (sourceCode) {
+      // Split into strings, comments, and other.
+      // We do this because strings and comments are easily recognizable and can
+      // contain stuff that looks like other tokens, so we want to mark those
+      // early so we don't recurse into them.
+      var decorations = splitStringAndCommentTokens(sourceCode);
+
+      // Split non comment|string tokens on whitespace and word boundaries
+      decorations = splitNonStringNonCommentTokens(sourceCode, decorations);
+
+      return decorations;
+    };
+  }
+
+  var decorateSource = sourceDecorator({
+        keywords: ALL_KEYWORDS,
+        hashComments: true,
+        cStyleComments: true,
+        multiLineStrings: true,
+        regexLiterals: true
+      });
+
+  /** identify regions of markup that are really source code, and recursivley
+    * lex them.
+    * @private
+    */
+  function splitSourceNodes(source, decorations) {
+    for (var i = 0; i < decorations.length; i += 2) {
+      var style = decorations[i + 1];
+      if (style === PR_SOURCE) {
+        // Recurse using the non-markup lexer
+        var start, end;
+        start = decorations[i];
+        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+        var subDecorations = decorateSource(source.substring(start, end));
+        for (var j = 0, m = subDecorations.length; j < m; j += 2) {
+          subDecorations[j] += start;
+        }
+        spliceArrayInto(subDecorations, decorations, i, 2);
+        i += subDecorations.length - 2;
+      }
+    }
+    return decorations;
+  }
+
+  /** identify attribute values that really contain source code and recursively
+    * lex them.
+    * @private
+    */
+  function splitSourceAttributes(source, decorations) {
+    var nextValueIsSource = false;
+    for (var i = 0; i < decorations.length; i += 2) {
+      var style = decorations[i + 1];
+      var start, end;
+      if (style === PR_ATTRIB_NAME) {
+        start = decorations[i];
+        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+        nextValueIsSource = /^on|^style$/i.test(source.substring(start, end));
+      } else if (style === PR_ATTRIB_VALUE) {
+        if (nextValueIsSource) {
+          start = decorations[i];
+          end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+          var attribValue = source.substring(start, end);
+          var attribLen = attribValue.length;
+          var quoted =
+              (attribLen >= 2 && /^[\"\']/.test(attribValue) &&
+               attribValue.charAt(0) === attribValue.charAt(attribLen - 1));
+
+          var attribSource;
+          var attribSourceStart;
+          var attribSourceEnd;
+          if (quoted) {
+            attribSourceStart = start + 1;
+            attribSourceEnd = end - 1;
+            attribSource = attribValue;
+          } else {
+            attribSourceStart = start + 1;
+            attribSourceEnd = end - 1;
+            attribSource = attribValue.substring(1, attribValue.length - 1);
+          }
+
+          var attribSourceDecorations = decorateSource(attribSource);
+          for (var j = 0, m = attribSourceDecorations.length; j < m; j += 2) {
+            attribSourceDecorations[j] += attribSourceStart;
+          }
+
+          if (quoted) {
+            attribSourceDecorations.push(attribSourceEnd, PR_ATTRIB_VALUE);
+            spliceArrayInto(attribSourceDecorations, decorations, i + 2, 0);
+          } else {
+            spliceArrayInto(attribSourceDecorations, decorations, i, 2);
+          }
+        }
+        nextValueIsSource = false;
+      }
+    }
+    return decorations;
+  }
+
+  /** returns a decoration list given a string of markup.
+    *
+    * This code recognizes a number of constructs.
+    * <!-- ... --> comment
+    * <!\w ... >   declaration
+    * <\w ... >    tag
+    * </\w ... >   tag
+    * <?...?>      embedded source
+    * <%...%>      embedded source
+    * &[#\w]...;   entity
+    *
+    * It does not recognizes %foo; doctype entities from  .
+    *
+    * It will recurse into any <style>, <script>, and on* attributes using
+    * PR_lexSource.
+    */
+  function decorateMarkup(sourceCode) {
+    // This function works as follows:
+    // 1) Start by splitting the markup into text and tag chunks
+    //    Input:  string s
+    //    Output: List<PR_Token> where style in (PR_PLAIN, null)
+    // 2) Then split the text chunks further into comments, declarations,
+    //    tags, etc.
+    //    After each split, consider whether the token is the start of an
+    //    embedded source section, i.e. is an open <script> tag.  If it is, find
+    //    the corresponding close token, and don't bother to lex in between.
+    //    Input:  List<string>
+    //    Output: List<PR_Token> with style in
+    //            (PR_TAG, PR_PLAIN, PR_SOURCE, null)
+    // 3) Finally go over each tag token and split out attribute names and
+    //    values.
+    //    Input:  List<PR_Token>
+    //    Output: List<PR_Token> where style in
+    //            (PR_TAG, PR_PLAIN, PR_SOURCE, NAME, VALUE, null)
+    var decorations = tokenizeMarkup(sourceCode);
+    decorations = splitTagAttributes(sourceCode, decorations);
+    decorations = splitSourceNodes(sourceCode, decorations);
+    decorations = splitSourceAttributes(sourceCode, decorations);
+    return decorations;
+  }
+
+  /**
+    * @param {string} sourceText plain text
+    * @param {Array.<number|string>} extractedTags chunks of raw html preceded
+    *   by their position in sourceText in order.
+    * @param {Array.<number|string>} decorations style classes preceded by their
+    *   position in sourceText in order.
+    * @return {string} html
+    * @private
+    */
+  function recombineTagsAndDecorations(sourceText, extractedTags, decorations) {
+    var html = [];
+    // index past the last char in sourceText written to html
+    var outputIdx = 0;
+
+    var openDecoration = null;
+    var currentDecoration = null;
+    var tagPos = 0;  // index into extractedTags
+    var decPos = 0;  // index into decorations
+    var tabExpander = makeTabExpander(PR_TAB_WIDTH);
+
+    var adjacentSpaceRe = /([\r\n ]) /g;
+    var startOrSpaceRe = /(^| ) /gm;
+    var newlineRe = /\r\n?|\n/g;
+    var trailingSpaceRe = /[ \r\n]$/;
+    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
+
+    // A helper function that is responsible for opening sections of decoration
+    // and outputing properly escaped chunks of source
+    function emitTextUpTo(sourceIdx) {
+      if (sourceIdx > outputIdx) {
+        if (openDecoration && openDecoration !== currentDecoration) {
+          // Close the current decoration
+          html.push('</span>');
+          openDecoration = null;
+        }
+        if (!openDecoration && currentDecoration) {
+          openDecoration = currentDecoration;
+          html.push('<span class="', openDecoration, '">');
+        }
+        // This interacts badly with some wikis which introduces paragraph tags
+        // into pre blocks for some strange reason.
+        // It's necessary for IE though which seems to lose the preformattedness
+        // of <pre> tags when their innerHTML is assigned.
+        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
+        // and it serves to undo the conversion of <br>s to newlines done in
+        // chunkify.
+        var htmlChunk = textToHtml(
+            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
+            .replace(lastWasSpace
+                     ? startOrSpaceRe
+                     : adjacentSpaceRe, '$1&nbsp;');
+        // Keep track of whether we need to escape space at the beginning of the
+        // next chunk.
+        lastWasSpace = trailingSpaceRe.test(htmlChunk);
+        html.push(htmlChunk.replace(newlineRe, '<br />'));
+        outputIdx = sourceIdx;
+      }
+    }
+
+    while (true) {
+      // Determine if we're going to consume a tag this time around.  Otherwise
+      // we consume a decoration or exit.
+      var outputTag;
+      if (tagPos < extractedTags.length) {
+        if (decPos < decorations.length) {
+          // Pick one giving preference to extractedTags since we shouldn't open
+          // a new style that we're going to have to immediately close in order
+          // to output a tag.
+          outputTag = extractedTags[tagPos] <= decorations[decPos];
+        } else {
+          outputTag = true;
+        }
+      } else {
+        outputTag = false;
+      }
+      // Consume either a decoration or a tag or exit.
+      if (outputTag) {
+        emitTextUpTo(extractedTags[tagPos]);
+        if (openDecoration) {
+          // Close the current decoration
+          html.push('</span>');
+          openDecoration = null;
+        }
+        html.push(extractedTags[tagPos + 1]);
+        tagPos += 2;
+      } else if (decPos < decorations.length) {
+        emitTextUpTo(decorations[decPos]);
+        currentDecoration = decorations[decPos + 1];
+        decPos += 2;
+      } else {
+        break;
+      }
+    }
+    emitTextUpTo(sourceText.length);
+    if (openDecoration) {
+      html.push('</span>');
+    }
+
+    return html.join('');
+  }
+
+  /** Maps language-specific file extensions to handlers. */
+  var langHandlerRegistry = {};
+  /** Register a language handler for the given file extensions.
+    * @param {function (string) : Array.<number|string>} handler
+    *     a function from source code to a list of decorations.
+    * @param {Array.<string>} fileExtensions
+    */
+  function registerLangHandler(handler, fileExtensions) {
+    for (var i = fileExtensions.length; --i >= 0;) {
+      var ext = fileExtensions[i];
+      if (!langHandlerRegistry.hasOwnProperty(ext)) {
+        langHandlerRegistry[ext] = handler;
+      } else if ('console' in window) {
+        console.log('cannot override language handler %s', ext);
+      }
+    }
+  }
+  registerLangHandler(decorateSource, ['default-code']);
+  registerLangHandler(decorateMarkup,
+                      ['default-markup', 'html', 'htm', 'xhtml', 'xml', 'xsl']);
+  registerLangHandler(sourceDecorator({
+          keywords: CPP_KEYWORDS,
+          hashComments: true,
+          cStyleComments: true
+        }), ['c', 'cc', 'cpp', 'cxx', 'cyc']);
+  registerLangHandler(sourceDecorator({
+          keywords: CSHARP_KEYWORDS,
+          hashComments: true,
+          cStyleComments: true
+        }), ['cs']);
+  registerLangHandler(sourceDecorator({
+          keywords: JAVA_KEYWORDS,
+          cStyleComments: true
+        }), ['java']);
+  registerLangHandler(sourceDecorator({
+          keywords: SH_KEYWORDS,
+          hashComments: true,
+          multiLineStrings: true
+        }), ['bsh', 'csh', 'sh']);
+  registerLangHandler(sourceDecorator({
+          keywords: PYTHON_KEYWORDS,
+          hashComments: true,
+          multiLineStrings: true,
+          tripleQuotedStrings: true
+        }), ['cv', 'py']);
+  registerLangHandler(sourceDecorator({
+          keywords: PERL_KEYWORDS,
+          hashComments: true,
+          multiLineStrings: true,
+          regexLiterals: true
+        }), ['perl', 'pl', 'pm']);
+  registerLangHandler(sourceDecorator({
+          keywords: RUBY_KEYWORDS,
+          hashComments: true,
+          multiLineStrings: true,
+          regexLiterals: true
+        }), ['rb']);
+  registerLangHandler(sourceDecorator({
+          keywords: JSCRIPT_KEYWORDS,
+          cStyleComments: true,
+          regexLiterals: true
+        }), ['js']);
+
+  function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
+    try {
+      // Extract tags, and convert the source code to plain text.
+      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
+      /** Plain text. @type {string} */
+      var source = sourceAndExtractedTags.source;
+
+      /** Even entries are positions in source in ascending order.  Odd entries
+        * are tags that were extracted at that position.
+        * @type {Array.<number|string>}
+        */
+      var extractedTags = sourceAndExtractedTags.tags;
+
+      // Pick a lexer and apply it.
+      if (!langHandlerRegistry.hasOwnProperty(opt_langExtension)) {
+        // Treat it as markup if the first non whitespace character is a < and
+        // the last non-whitespace character is a >.
+        opt_langExtension =
+            /^\s*</.test(source) ? 'default-markup' : 'default-code';
+      }
+
+      /** Even entries are positions in source in ascending order.  Odd enties
+        * are style markers (e.g., PR_COMMENT) that run from that position until
+        * the end.
+        * @type {Array.<number|string>}
+        */
+      var decorations = langHandlerRegistry[opt_langExtension].call({}, source);
+
+      // Integrate the decorations and tags back into the source code to produce
+      // a decorated html string.
+      return recombineTagsAndDecorations(source, extractedTags, decorations);
+    } catch (e) {
+      if ('console' in window) {
+        console.log(e);
+        console.trace();
+      }
+      return sourceCodeHtml;
+    }
+  }
+
+  function prettyPrint(opt_whenDone) {
+    var isIE6 = _pr_isIE6();
+
+    // fetch a list of nodes to rewrite
+    var codeSegments = [
+        document.getElementsByTagName('pre'),
+        document.getElementsByTagName('code'),
+        document.getElementsByTagName('xmp') ];
+    var elements = [];
+    for (var i = 0; i < codeSegments.length; ++i) {
+      for (var j = 0; j < codeSegments[i].length; ++j) {
+        elements.push(codeSegments[i][j]);
+      }
+    }
+    codeSegments = null;
+
+    // the loop is broken into a series of continuations to make sure that we
+    // don't make the browser unresponsive when rewriting a large page.
+    var k = 0;
+
+    function doWork() {
+      var endTime = (PR_SHOULD_USE_CONTINUATION ?
+                     new Date().getTime() + 250 /* ms */ :
+                     Infinity);
+      for (; k < elements.length && new Date().getTime() < endTime; k++) {
+        var cs = elements[k];
+        if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
+          // If the classes includes a language extensions, use it.
+          // Language extensions can be specified like
+          //     <pre class="prettyprint lang-cpp">
+          // the language extension "cpp" is used to find a language handler as
+          // passed to PR_registerLangHandler.
+          var langExtension = cs.className.match(/\blang-(\w+)\b/);
+          if (langExtension) { langExtension = langExtension[1]; }
+
+          // make sure this is not nested in an already prettified element
+          var nested = false;
+          for (var p = cs.parentNode; p; p = p.parentNode) {
+            if ((p.tagName === 'pre' || p.tagName === 'code' ||
+                 p.tagName === 'xmp') &&
+                p.className && p.className.indexOf('prettyprint') >= 0) {
+              nested = true;
+              break;
+            }
+          }
+          if (!nested) {
+            // fetch the content as a snippet of properly escaped HTML.
+            // Firefox adds newlines at the end.
+            var content = getInnerHtml(cs);
+            content = content.replace(/(?:\r\n?|\n)$/, '');
+
+            // do the pretty printing
+            var newContent = prettyPrintOne(content, langExtension);
+
+            // push the prettified html back into the tag.
+            if (!isRawContent(cs)) {
+              // just replace the old html with the new
+              cs.innerHTML = newContent;
+            } else {
+              // we need to change the tag to a <pre> since <xmp>s do not allow
+              // embedded tags such as the span tags used to attach styles to
+              // sections of source code.
+              var pre = document.createElement('PRE');
+              for (var i = 0; i < cs.attributes.length; ++i) {
+                var a = cs.attributes[i];
+                if (a.specified) {
+                  var aname = a.name.toLowerCase();
+                  if (aname === 'class') {
+                    pre.className = a.value;  // For IE 6
+                  } else {
+                    pre.setAttribute(a.name, a.value);
+                  }
+                }
+              }
+              pre.innerHTML = newContent;
+
+              // remove the old
+              cs.parentNode.replaceChild(pre, cs);
+              cs = pre;
+            }
+
+            // Replace <br>s with line-feeds so that copying and pasting works
+            // on IE 6.
+            // Doing this on other browsers breaks lots of stuff since \r\n is
+            // treated as two newlines on Firefox, and doing this also slows
+            // down rendering.
+            if (isIE6 && cs.tagName === 'PRE') {
+              var lineBreaks = cs.getElementsByTagName('br');
+              for (var j = lineBreaks.length; --j >= 0;) {
+                var lineBreak = lineBreaks[j];
+                lineBreak.parentNode.replaceChild(
+                    document.createTextNode('\r\n'), lineBreak);
+              }
+            }
+          }
+        }
+      }
+      if (k < elements.length) {
+        // finish up in a continuation
+        setTimeout(doWork, 250);
+      } else if (opt_whenDone) {
+        opt_whenDone();
+      }
+    }
+
+    doWork();
+  }
+
+  window['PR_normalizedHtml'] = normalizedHtml;
+  window['prettyPrintOne'] = prettyPrintOne;
+  window['prettyPrint'] = prettyPrint;
+  window['PR'] = {
+        'createSimpleLexer': createSimpleLexer,
+        'registerLangHandler': registerLangHandler,
+        'sourceDecorator': sourceDecorator,
+        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
+        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
+        'PR_COMMENT': PR_COMMENT,
+        'PR_DECLARATION': PR_DECLARATION,
+        'PR_KEYWORD': PR_KEYWORD,
+        'PR_LITERAL': PR_LITERAL,
+        'PR_NOCODE': PR_NOCODE,
+        'PR_PLAIN': PR_PLAIN,
+        'PR_PUNCTUATION': PR_PUNCTUATION,
+        'PR_SOURCE': PR_SOURCE,
+        'PR_STRING': PR_STRING,
+        'PR_TAG': PR_TAG,
+        'PR_TYPE': PR_TYPE
+      };
+})();
diff --git a/docs/verifier.html b/docs/verifier.html
new file mode 100644
index 0000000..276967f
--- /dev/null
+++ b/docs/verifier.html
@@ -0,0 +1,216 @@
+<html>
+<head>
+<title>Dalvik Bytecode Verifier Notes</title>
+</head>
+
+<body>
+<h1>Dalvik Bytecode Verifier Notes</h1>
+
+<p>
+The bytecode verifier in the Dalvik VM attempts to provide the same sorts
+of checks and guarantees that other popular virtual machines do.  We
+perform generally the same set of checks as are described in _The Java
+Virtual Machine Specification, Second Edition_, including the updates
+planned for the Third Edition.
+
+<p>
+Verification can be enabled for all classes, disabled for all, or enabled
+only for "remote" (non-bootstrap) classes.  It should be performed for any
+class that will be processed with the DEX optimizer, and in fact the
+default VM behavior is to only optimize verified classes.
+
+
+<h2>Why Verify?</h2>
+
+<p>
+The verification process adds additional time to the build and to
+the installation of new applications.  It's fairly quick for app-sized
+DEX files, but rather slow for the big "core" and "framework" files.
+Why do it all, when our system relies on UNIX processes for security?
+<p>
+<ol>
+    <li>Optimizations.  The interpreter can ignore a lot of potential
+    error cases because the verifier guarantees that they are impossible.
+    Also, we can optimize the DEX file more aggressively if we start
+    with a stronger set of assumptions about the bytecode.
+    <li>"Precise" GC.  The work peformed during verification has significant
+    overlap with the work required to compute register use maps for
+    type-precise GC.
+    <li>Intra-application security.  If an app wants to download bits
+    of interpreted code over the network and execute them, it can safely
+    do so using well-established security mechanisms.
+    <li>3rd party app failure analysis.  We have no way to control the
+    tools and post-processing utilities that external developers employ,
+    so when we get bug reports with a weird exception or native crash
+    it's very helpful to start with the assumption that the bytecode
+    is valid.
+</ol>
+<p>
+It's also a convenient framework to deal with certain situations, notably
+replacement of instructions that access volatile 64-bit fields with
+more rigorous versions that guarantee atomicity.
+
+
+<h2>Verifier Differences</h2>
+
+<p>
+There are a few checks that the Dalvik bytecode verifier does not perform,
+because they're not relevant.  For example:
+<ul>
+    <li>Type restrictions on constant pool references are not enforced,
+    because Dalvik does not have a pool of typed constants.  (Dalvik
+    uses a simple index into type-specific pools.)
+    <li>Verification of the operand stack size is not performed, because
+    Dalvik does not have an operand stack.
+    <li>Limitations on <code>jsr</code> and <code>ret</code> do not apply,
+    because Dalvik doesn't support subroutines.
+</ul>
+
+In some cases they are implemented differently, e.g.:
+<ul>
+    <li>In a conventional VM, backward branches and exceptions are
+    forbidden when a local variable holds an uninitialized reference.  The
+    restriction was changed to mark registers as invalid when they hold
+    references to the uninitialized result of a previous invocation of the
+    same <code>new-instance</code> instruction.
+    This solves the same problem -- trickery potentially allowing
+    uninitialized objects to slip past the verifier -- without unduly
+    limiting branches.
+</ul>
+
+There are also some new ones, such as:
+<ul>
+    <li>The <code>move-exception</code> instruction can only appear as
+    the first instruction in an exception handler.
+    <li>The <code>move-result*</code> instructions can only appear
+    immediately after an appropriate <code>invoke-*</code>
+    or <code>filled-new-array</code> instruction.
+</ul>
+
+<p>
+The VM is permitted but not required to enforce "structured locking"
+constraints, which are designed to ensure that, when a method returns, all
+monitors locked by the method have been unlocked an equal number of times.
+This is not currently implemented.
+
+<p>
+The Dalvik verifier is more restrictive than other VMs in one area:
+type safety on sub-32-bit integer widths.  These additional restrictions
+should make it impossible to, say, pass a value outside the range
+[-128, 127] to a function that takes a <code>byte</code> as an argument.
+
+
+<h2>Monitor Verification</h2>
+
+<p>
+If a method locks an object with a <code>synchronized</code> statement, the
+object must be unlocked before the method returns.  At the bytecode level,
+this means the method must execute a matching <code>monitor-exit</code>
+for every <code>monitor-enter</code> instruction, whether the function
+completes normally or abnormally.  The bytecode verifier optionally
+enforces this.
+
+<p>
+The verifier uses a fairly simple-minded model.  If you enter a monitor
+held in register N, you can exit the monitor using register N or any
+subsequently-made copies of register N.  The verifier does not attempt
+to identify previously-made copies, track loads and stores through
+fields, or recognize identical constant values (for example, the result
+values from two <code>const-class</code> instructions on the same class
+will be the same reference, but the verifier doesn't recognize this).
+
+<p>
+Further, you may only exit the monitor most recently entered.  "Hand
+over hand" locking techniques, e.g. "lock A; lock B; unlock A; unlock B",
+are not allowed.
+
+<p>
+This means that there are a number of situations in which the verifier
+will throw an exception on code that would execute correctly at run time.
+This is not expected to be an issue for compiler-generated bytecode.
+
+<p>
+For implementation convenience, the maximum nesting depth of
+<code>synchronized</code> statements has been set to 32.  This is not
+a limitation on the recursion count.  The only way to trip this would be
+to have a single method with more than 32 nested <code>synchronized</code>
+statements, something that is unlikely to occur.
+
+
+<h2>Verification Failures</h2>
+
+<p>
+The verifier may reject a class immediately, or it may defer throwing
+an exception until the code is actually used.  For example, if a class
+attempts to perform an illegal access on a field, the VM should throw
+an IllegalAccessError the first time the instruction is encountered.
+On the other hand, if a class contains an invalid bytecode, it should be
+rejected immediately with a VerifyError.
+
+<p>
+Immediate VerifyErrors are accompanied by detailed, if somewhat cryptic,
+information in the log file.  From this it's possible to determine the
+exact instruction that failed, and the reason for the failure.
+
+<p>
+It's a bit tricky to implement deferred verification errors in Dalvik.
+A few approaches were considered:
+
+<ol>
+<li>We could replace the invalid field access instruction with a special
+instruction that generates an illegal access error, and allow class
+verification to complete successfully.  This type of verification must
+be deferred to first class load, rather than be performed ahead of time
+during DEX optimization, because some failures will depend on the current
+execution environment (e.g. not all classes are available at dexopt time).
+At that point the bytecode instructions are mapped read-only during
+verification, so rewriting them isn't possible.
+</li>
+
+<li>We can perform the access checks when the field/method/class is
+resolved.  In a typical VM implementation we would do the check when the
+entry is resolved in the context of the current classfile, but our DEX
+files combine multiple classfiles together, merging the field/method/class
+resolution results into a single large table.  Once one class successfully
+resolves the field, every other class in the same DEX file would be able
+to access the field.  This is incorrect.
+</li>
+
+<li>Perform the access checks on every field/method/class access.
+This adds significant overhead.  This is mitigated somewhat by the DEX
+optimizer, which will convert many field/method/class accesses into a
+simpler form after performing the access check.  However, not all accesses
+can be optimized (e.g. accesses to classes unknown at dexopt time),
+and we don't currently have an optimized form of certain instructions
+(notably static field operations).
+</li>
+</ol>
+
+<p>
+In early versions of Dalvik (as found in Android 1.6 and earlier), the verifier
+simply regarded all problems as immediately fatal.  This generally worked,
+but in some cases the VM was rejecting classes because of bits of code
+that were never used.  The VerifyError itself was sometimes difficult to
+decipher, because it was thrown during verification rather than at the
+point where the problem was first noticed during execution.
+<p>
+The current version uses a variation of approach #1.  The dexopt
+command works the way it did before, leaving the code untouched and
+flagging fully-correct classes as "pre-verified".  When the VM loads a
+class that didn't pass pre-verification, the verifier is invoked.  If a
+"deferrable" problem is detected, a modifiable copy of the instructions
+in the problematic method is made.  In that copy, the troubled instruction
+is replaced with an "always throw" opcode, and verification continues.
+
+<p>
+In the example used earlier, an attempt to read from an inaccessible
+field would result in the "field get" instruction being replaced by
+"always throw IllegalAccessError on field X".  Creating copies of method
+bodies requires additional heap space, but since this affects very few
+methods overall the memory impact should be minor.
+
+<p>
+<address>Copyright &copy; 2008 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/dvz/Android.mk b/dvz/Android.mk
new file mode 100644
index 0000000..22d0950
--- /dev/null
+++ b/dvz/Android.mk
@@ -0,0 +1,19 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH := $(my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	dvz.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+LOCAL_C_INCLUDES :=
+
+LOCAL_CFLAGS :=
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := dvz
+
+include $(BUILD_EXECUTABLE)
diff --git a/dvz/dvz.cpp b/dvz/dvz.cpp
new file mode 100644
index 0000000..88fe086
--- /dev/null
+++ b/dvz/dvz.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include <cutils/zygote.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#ifndef NELEM
+# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#endif
+
+// pid of child process
+static pid_t g_pid = -1;
+
+static void signal_forwarder (int signal, siginfo_t *si, void *context)
+{
+    if (g_pid >= 0) {
+        kill(g_pid, signal);
+    }
+}
+
+static void post_run_func (int pid) {
+    int my_pgid;
+    int spawned_pgid;
+    int i;
+    int err;
+
+    g_pid = pid;
+
+    my_pgid = getpgid(0);
+    if (my_pgid < 0) {
+        perror ("error with getpgid()");
+        exit (-1);
+    }
+
+    spawned_pgid = getpgid(pid);
+    if (spawned_pgid < 0) {
+        perror ("error with getpgid()");
+        exit (-1);
+    }
+
+    if (my_pgid != spawned_pgid) {
+        // The zygote was unable to move this process into our pgid
+        // We have to forward signals
+
+        int forward_signals[]
+            = {SIGHUP, SIGINT, SIGTERM, SIGWINCH,
+            SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT};
+
+        struct sigaction sa;
+        memset(&sa, 0, sizeof(sa));
+
+        sa.sa_sigaction = signal_forwarder;
+        sa.sa_flags = SA_SIGINFO;
+
+        for (i = 0; i < NELEM(forward_signals); i++) {
+            err = sigaction(forward_signals[i], &sa, NULL);
+            if (err < 0) {
+                perror ("unexpected error");
+                exit (-1);
+            }
+        }
+    }
+}
+
+static void usage(const char *argv0) {
+    fprintf(stderr,"Usage: %s [--help] [-classpath <classpath>] \n"
+    "\t[additional zygote args] fully.qualified.java.ClassName [args]\n", argv0);
+    fprintf(stderr, "\nRequests a new Dalvik VM instance to be spawned from the zygote\n"
+    "process. stdin, stdout, and stderr are hooked up. This process remains\n"
+    "while the spawned VM instance is alive and forwards some signals.\n"
+    "The exit code of the spawned VM instance is dropped.\n");
+}
+
+int main (int argc, const char **argv) {
+    int err;
+
+    if (argc > 1 && 0 == strcmp(argv[1], "--help")) {
+        usage(argv[0]);
+        exit(0);
+    }
+
+    err = zygote_run_wait(argc - 1, argv + 1, post_run_func);
+
+    if (err < 0) {
+        fprintf(stderr, "%s error: no zygote process found\n", argv[0]);
+        exit(-1);
+    }
+    exit(0);
+}
diff --git a/dx/.classpath b/dx/.classpath
new file mode 100644
index 0000000..5b6d9c7
--- /dev/null
+++ b/dx/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3.8.1"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dx/.project b/dx/.project
new file mode 100644
index 0000000..bcae232
--- /dev/null
+++ b/dx/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>dx</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/dx/Android.mk b/dx/Android.mk
new file mode 100644
index 0000000..3abf21a
--- /dev/null
+++ b/dx/Android.mk
@@ -0,0 +1,73 @@
+# Copyright 2006 The Android Open Source Project
+#
+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.
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS),)
+
+# the dx script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := dx
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/dx$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/dx | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
+endif # TARGET_BUILD_APPS
+
+# the jasmin script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := jasmin
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/jasmin.jar
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/jasmin | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
+# the jasmin lib
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := jasmin.jar
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/jasmin.jar | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-target)
+	$(hide) chmod 644 $@
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+		src \
+	))
+
+include $(subdirs)
diff --git a/dx/NOTICE b/dx/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/dx/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/dx/README.txt b/dx/README.txt
new file mode 100644
index 0000000..6a20c82
--- /dev/null
+++ b/dx/README.txt
@@ -0,0 +1,3 @@
+Home of Dalvik eXchange, the thing that takes in class files and
+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
new file mode 100644
index 0000000..e5cedff
--- /dev/null
+++ b/dx/etc/dx
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# 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.
+
+# 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=dx.jar
+libdir="$progdir"
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    # set dx.jar location for the SDK case
+    libdir=`dirname "$progdir"`/platform-tools/lib
+fi
+
+
+if [ ! -r "$libdir/$jarfile" ]; then
+    # set dx.jar location for the Android tree case
+    libdir=`dirname "$progdir"`/framework
+fi
+
+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=""
+
+while expr "x$1" : 'x-J' >/dev/null; do
+    opt=`expr "x$1" : 'x-J\(.*\)'`
+    javaOpts="${javaOpts} -${opt}"
+    if expr "x${opt}" : "xXmx[0-9]" >/dev/null; then
+        defaultMx="no"
+    fi
+    shift
+done
+
+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"
+fi
+
+exec java $javaOpts -jar "$jarpath" "$@"
diff --git a/dx/etc/dx.bat b/dx/etc/dx.bat
new file mode 100755
index 0000000..ac14fe6
--- /dev/null
+++ b/dx/etc/dx.bat
@@ -0,0 +1,89 @@
+@echo off

+REM Copyright (C) 2007 The Android Open Source Project

+REM

+REM Licensed under the Apache License, Version 2.0 (the "License");

+REM you may not use this file except in compliance with the License.

+REM You may obtain a copy of the License at

+REM

+REM     http://www.apache.org/licenses/LICENSE-2.0

+REM

+REM Unless required by applicable law or agreed to in writing, software

+REM distributed under the License is distributed on an "AS IS" BASIS,

+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+REM See the License for the specific language governing permissions and

+REM limitations under the License.

+

+REM don't modify the caller's environment

+setlocal

+

+REM Locate dx.jar in the directory where dx.bat was found and start it.

+

+REM Set up prog to be the path of this script, including following symlinks,

+REM and set up progdir to be the fully-qualified pathname of its directory.

+set prog=%~f0

+

+REM Change current directory to where dx is, to avoid issues with directories

+REM containing whitespaces.

+cd /d %~dp0

+

+rem Check we have a valid Java.exe in the path.

+set java_exe=

+call ..\tools\lib\find_java.bat

+if not defined java_exe goto :EOF

+

+set jarfile=dx.jar

+set frameworkdir=

+

+if exist %frameworkdir%%jarfile% goto JarFileOk

+    set frameworkdir=lib\

+

+if exist %frameworkdir%%jarfile% goto JarFileOk

+    set frameworkdir=..\framework\

+

+:JarFileOk

+

+set jarpath=%frameworkdir%%jarfile%

+

+set javaOpts=

+set args=

+

+REM By default, give dx a max heap size of 1 gig and a stack size of 1meg.

+rem This can be overridden by using "-JXmx..." and "-JXss..." options below.

+set defaultXmx=-Xmx1024M

+set defaultXss=-Xss1m

+

+REM Capture all arguments that are not -J options.

+REM Note that when reading the input arguments with %1, the cmd.exe

+REM automagically converts --name=value arguments into 2 arguments "--name"

+REM followed by "value". Dx has been changed to know how to deal with that.

+set params=

+

+:firstArg

+if [%1]==[] goto endArgs

+set a=%~1

+

+    if [%defaultXmx%]==[] goto notXmx

+    if %a:~0,5% NEQ -JXmx goto notXmx

+        set defaultXmx=

+    :notXmx

+

+    if [%defaultXss%]==[] goto notXss

+    if %a:~0,5% NEQ -JXss goto notXss

+        set defaultXss=

+    :notXss

+

+    if %a:~0,2% NEQ -J goto notJ

+        set javaOpts=%javaOpts% -%a:~2%

+        shift /1

+        goto firstArg

+

+    :notJ

+    set params=%params% %1

+    shift /1

+    goto firstArg

+

+:endArgs

+

+set javaOpts=%javaOpts% %defaultXmx% %defaultXss%

+

+call %java_exe% %javaOpts% -Djava.ext.dirs=%frameworkdir% -jar %jarpath% %params%

diff --git a/dx/etc/jasmin b/dx/etc/jasmin
new file mode 100644
index 0000000..f44c16f
--- /dev/null
+++ b/dx/etc/jasmin
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# 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.
+
+# 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}"
+
+libdir=`dirname $progdir`/framework
+
+exec java -jar $libdir/jasmin.jar "$@"
diff --git a/dx/etc/jasmin.jar b/dx/etc/jasmin.jar
new file mode 100644
index 0000000..87db0d0
--- /dev/null
+++ b/dx/etc/jasmin.jar
Binary files differ
diff --git a/dx/etc/manifest.txt b/dx/etc/manifest.txt
new file mode 100644
index 0000000..46bbe63
--- /dev/null
+++ b/dx/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.dx.command.Main
diff --git a/dx/junit-tests/HelloWorldMaker.java b/dx/junit-tests/HelloWorldMaker.java
new file mode 100644
index 0000000..001f31a
--- /dev/null
+++ b/dx/junit-tests/HelloWorldMaker.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 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 com.android.dx.gen.BinaryOp;
+import com.android.dx.gen.Code;
+import com.android.dx.gen.DexGenerator;
+import com.android.dx.gen.FieldId;
+import com.android.dx.gen.Local;
+import com.android.dx.gen.MethodId;
+import com.android.dx.gen.Type;
+import com.android.dx.rop.code.AccessFlags;
+import java.io.PrintStream;
+
+public class HelloWorldMaker {
+    private static final Type<PrintStream> PRINT_STREAM = Type.get(PrintStream.class);
+    private static final FieldId<System, PrintStream> SYSTEM_OUT
+            = Type.get(System.class).getField(PRINT_STREAM, "out");
+    private static final MethodId<Integer, String> TO_HEX_STRING
+            = Type.get(Integer.class).getMethod(Type.STRING, "toHexString", Type.INT);
+    private static final MethodId<PrintStream, Void> PRINTLN
+            = PRINT_STREAM.getMethod(Type.VOID, "println", Type.STRING);
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * This code generates Dalvik bytecode equivalent to the following
+         * program.
+         *
+         *  public class HelloWorld {
+         *      public static void hello() {
+         *          int a = 0xabcd;
+         *          int b = 0xaaaa;
+         *          int c = a - b;
+         *          String s = Integer.toHexString(c);
+         *          System.out.println(s);
+         *      }
+         *  }
+         */
+
+        DexGenerator generator = new DexGenerator();
+
+        // lookup the symbols of interest
+        Type<?> helloWorld = Type.get("LHelloWorld;");
+        MethodId hello = helloWorld.getMethod(Type.VOID, "hello");
+
+        // create some registers
+        //    (I'd like a better syntax for this)
+        Code code = generator.declare(hello, AccessFlags.ACC_STATIC | AccessFlags.ACC_PUBLIC);
+        Local<Integer> a = code.newLocal(Type.INT);
+        Local<Integer> b = code.newLocal(Type.INT);
+        Local<Integer> c = code.newLocal(Type.INT);
+        Local<String> s = code.newLocal(Type.STRING);
+        Local<PrintStream> localSystemOut = code.newLocal(PRINT_STREAM);
+
+        // specify the code instruction-by-instruction (approximately)
+        code.loadConstant(a, 0xabcd);
+        code.loadConstant(b, 0xaaaa);
+        code.op(BinaryOp.SUBTRACT, c, a, b);
+        code.invokeStatic(TO_HEX_STRING, s, c);
+        code.sget(SYSTEM_OUT, localSystemOut);
+        code.invokeVirtual(PRINTLN, null, localSystemOut, s);
+        code.returnVoid();
+
+        // TODO: create the constructor
+
+        generator.declare(helloWorld, "Generated.java", AccessFlags.ACC_PUBLIC, Type.OBJECT);
+
+        // load the dex
+        ClassLoader loader = generator.load(HelloWorldMaker.class.getClassLoader());
+        Class<?> helloWorldClass = loader.loadClass("HelloWorld");
+        helloWorldClass.getMethod("hello").invoke(null);
+    }
+}
diff --git a/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java b/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java
new file mode 100644
index 0000000..99eea85
--- /dev/null
+++ b/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java
@@ -0,0 +1,1628 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
+import static com.android.dx.rop.code.AccessFlags.ACC_FINAL;
+import static com.android.dx.rop.code.AccessFlags.ACC_PRIVATE;
+import static com.android.dx.rop.code.AccessFlags.ACC_PROTECTED;
+import static com.android.dx.rop.code.AccessFlags.ACC_PUBLIC;
+import static com.android.dx.rop.code.AccessFlags.ACC_STATIC;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import junit.framework.TestCase;
+
+/**
+ * This generates a class named 'Generated' with one or more generated methods
+ * and fields. In loads the generated class into the current VM and uses
+ * reflection to invoke its methods.
+ *
+ * <p>This test must run on a Dalvik VM.
+ */
+public final class DexGeneratorTest extends TestCase {
+    private DexGenerator generator;
+    private static Type<DexGeneratorTest> TEST_TYPE = Type.get(DexGeneratorTest.class);
+    private static Type<?> INT_ARRAY = Type.get(int[].class);
+    private static Type<boolean[]> BOOLEAN_ARRAY = Type.get(boolean[].class);
+    private static Type<long[]> LONG_ARRAY = Type.get(long[].class);
+    private static Type<Object[]> OBJECT_ARRAY = Type.get(Object[].class);
+    private static Type<long[][]> LONG_2D_ARRAY = Type.get(long[][].class);
+    private static Type<?> GENERATED = Type.get("LGenerated;");
+    private static Type<Callable> CALLABLE = Type.get(Callable.class);
+    private static MethodId<Callable, Object> CALL = CALLABLE.getMethod(Type.OBJECT, "call");
+
+    @Override protected void setUp() throws Exception {
+        super.setUp();
+        reset();
+    }
+
+    /**
+     * The generator is mutable. Calling reset creates a new empty generator.
+     * This is necessary to generate multiple classes in the same test method.
+     */
+    private void reset() {
+        generator = new DexGenerator();
+        generator.declare(GENERATED, "Generated.java", ACC_PUBLIC, Type.OBJECT);
+    }
+
+    public void testNewInstance() throws Exception {
+        /*
+         * public static Constructable call(long a, boolean b) {
+         *   Constructable result = new Constructable(a, b);
+         *   return result;
+         * }
+         */
+        Type<Constructable> constructable = Type.get(Constructable.class);
+        MethodId<?, Constructable> methodId = GENERATED.getMethod(
+                constructable, "call", Type.LONG, Type.BOOLEAN);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Long> localA = code.getParameter(0, Type.LONG);
+        Local<Boolean> localB = code.getParameter(1, Type.BOOLEAN);
+        MethodId<Constructable, Void> constructor
+                = constructable.getConstructor(Type.LONG, Type.BOOLEAN);
+        Local<Constructable> localResult = code.newLocal(constructable);
+        code.newInstance(localResult, constructor, localA, localB);
+        code.returnValue(localResult);
+
+        Constructable constructed = (Constructable) getMethod().invoke(null, 5L, false);
+        assertEquals(5L, constructed.a);
+        assertEquals(false, constructed.b);
+    }
+
+    public static class Constructable {
+        private final long a;
+        private final boolean b;
+        public Constructable(long a, boolean b) {
+            this.a = a;
+            this.b = b;
+        }
+    }
+
+    public void testInvokeStatic() throws Exception {
+        /*
+         * public static int call(int a) {
+         *   int result = DexGeneratorTest.staticMethod(a);
+         *   return result;
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localA = code.getParameter(0, Type.INT);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        MethodId<?, Integer> staticMethod
+                = TEST_TYPE.getMethod(Type.INT, "staticMethod", Type.INT);
+        code.invokeStatic(staticMethod, localResult, localA);
+        code.returnValue(localResult);
+
+        assertEquals(10, getMethod().invoke(null, 4));
+    }
+
+    @SuppressWarnings("unused") // called by generated code
+    public static int staticMethod(int a) {
+        return a + 6;
+    }
+
+    public void testInvokeVirtual() throws Exception {
+        /*
+         * public static int call(DexGeneratorTest test, int a) {
+         *   int result = test.virtualMethod(a);
+         *   return result;
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", TEST_TYPE, Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<DexGeneratorTest> localInstance = code.getParameter(0, TEST_TYPE);
+        Local<Integer> localA = code.getParameter(1, Type.INT);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        MethodId<DexGeneratorTest, Integer> virtualMethod
+                = TEST_TYPE.getMethod(Type.INT, "virtualMethod", Type.INT);
+        code.invokeVirtual(virtualMethod, localResult, localInstance, localA);
+        code.returnValue(localResult);
+
+        assertEquals(9, getMethod().invoke(null, this, 4));
+    }
+
+    @SuppressWarnings("unused") // called by generated code
+    public int virtualMethod(int a) {
+        return a + 5;
+    }
+
+    public <G> void testInvokeDirect() throws Exception {
+        /*
+         * private int directMethod() {
+         *   int a = 5;
+         *   return a;
+         * }
+         *
+         * public static int call(Generated g) {
+         *   int b = g.directMethod();
+         *   return b;
+         * }
+         */
+        Type<G> generated = Type.get("LGenerated;");
+        MethodId<G, Integer> directMethodId = generated.getMethod(Type.INT, "directMethod");
+        Code directCode = generator.declare(directMethodId, ACC_PRIVATE);
+        directCode.getThis(generated); // 'this' is unused
+        Local<Integer> localA = directCode.newLocal(Type.INT);
+        directCode.loadConstant(localA, 5);
+        directCode.returnValue(localA);
+
+        MethodId<G, Integer> methodId = generated.getMethod(Type.INT, "call", generated);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localB = code.newLocal(Type.INT);
+        Local<G> localG = code.getParameter(0, generated);
+        code.invokeDirect(directMethodId, localB, localG);
+        code.returnValue(localB);
+
+        addDefaultConstructor();
+
+        Class<?> generatedClass = loadAndGenerate();
+        Object instance = generatedClass.newInstance();
+        Method method = generatedClass.getMethod("call", generatedClass);
+        assertEquals(5, method.invoke(null, instance));
+    }
+
+    public <G> void testInvokeSuper() throws Exception {
+        /*
+         * public int superHashCode() {
+         *   int result = super.hashCode();
+         *   return result;
+         * }
+         * public int hashCode() {
+         *   return 0;
+         * }
+         */
+        Type<G> generated = Type.get("LGenerated;");
+        MethodId<Object, Integer> objectHashCode = Type.OBJECT.getMethod(Type.INT, "hashCode");
+        Code superHashCode = generator.declare(
+                GENERATED.getMethod(Type.INT, "superHashCode"), ACC_PUBLIC);
+        Local<Integer> localResult = superHashCode.newLocal(Type.INT);
+        Local<G> localThis = superHashCode.getThis(generated);
+        superHashCode.invokeSuper(objectHashCode, localResult, localThis);
+        superHashCode.returnValue(localResult);
+
+        Code generatedHashCode = generator.declare(
+                GENERATED.getMethod(Type.INT, "hashCode"), ACC_PUBLIC);
+        Local<Integer> localZero = generatedHashCode.newLocal(Type.INT);
+        generatedHashCode.loadConstant(localZero, 0);
+        generatedHashCode.returnValue(localZero);
+
+        addDefaultConstructor();
+
+        Class<?> generatedClass = loadAndGenerate();
+        Object instance = generatedClass.newInstance();
+        Method method = generatedClass.getMethod("superHashCode");
+        assertEquals(System.identityHashCode(instance), method.invoke(instance));
+    }
+
+    @SuppressWarnings("unused") // called by generated code
+    public int superMethod(int a) {
+        return a + 4;
+    }
+
+    public void testInvokeInterface() throws Exception {
+        /*
+         * public static Object call(Callable c) {
+         *   Object result = c.call();
+         *   return result;
+         * }
+         */
+        MethodId<?, Object> methodId = GENERATED.getMethod(Type.OBJECT, "call", CALLABLE);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Callable> localC = code.getParameter(0, CALLABLE);
+        Local<Object> localResult = code.newLocal(Type.OBJECT);
+        code.invokeInterface(CALL, localResult, localC);
+        code.returnValue(localResult);
+
+        Callable<Object> callable = new Callable<Object>() {
+            public Object call() throws Exception {
+                return "abc";
+            }
+        };
+        assertEquals("abc", getMethod().invoke(null, callable));
+    }
+
+    public void testParameterMismatch() throws Exception {
+        Type<?>[] argTypes = {
+                Type.get(Integer.class), // should fail because the code specifies int
+                Type.OBJECT,
+        };
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", argTypes);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        try {
+            code.getParameter(0, Type.INT);
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            code.getParameter(2, Type.INT);
+        } catch (IndexOutOfBoundsException e) {
+        }
+    }
+
+    public void testInvokeTypeSafety() throws Exception {
+        /*
+         * public static boolean call(DexGeneratorTest test) {
+         *   CharSequence cs = test.toString();
+         *   boolean result = cs.equals(test);
+         *   return result;
+         * }
+         */
+        MethodId<?, Boolean> methodId = GENERATED.getMethod(Type.BOOLEAN, "call", TEST_TYPE);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<DexGeneratorTest> localTest = code.getParameter(0, TEST_TYPE);
+        Type<CharSequence> charSequenceType = Type.get(CharSequence.class);
+        MethodId<Object, String> objectToString = Type.OBJECT.getMethod(Type.STRING, "toString");
+        MethodId<Object, Boolean> objectEquals
+                = Type.OBJECT.getMethod(Type.BOOLEAN, "equals", Type.OBJECT);
+        Local<CharSequence> localCs = code.newLocal(charSequenceType);
+        Local<Boolean> localResult = code.newLocal(Type.BOOLEAN);
+        code.invokeVirtual(objectToString, localCs, localTest);
+        code.invokeVirtual(objectEquals, localResult, localCs, localTest);
+        code.returnValue(localResult);
+
+        assertEquals(false, getMethod().invoke(null, this));
+    }
+
+    public void testReturnTypeMismatch() {
+        MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call");
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        try {
+            code.returnValue(code.newLocal(Type.BOOLEAN));
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+        try {
+            code.returnVoid();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public void testDeclareStaticFields() throws Exception {
+        /*
+         * class Generated {
+         *   public static int a;
+         *   protected static Object b;
+         * }
+         */
+        generator.declare(GENERATED.getField(Type.INT, "a"), ACC_PUBLIC | ACC_STATIC, 3);
+        generator.declare(GENERATED.getField(Type.OBJECT, "b"), ACC_PROTECTED | ACC_STATIC, null);
+        Class<?> generatedClass = loadAndGenerate();
+
+        Field a = generatedClass.getField("a");
+        assertEquals(int.class, a.getType());
+        assertEquals(3, a.get(null));
+
+        Field b = generatedClass.getDeclaredField("b");
+        assertEquals(Object.class, b.getType());
+        b.setAccessible(true);
+        assertEquals(null, b.get(null));
+    }
+
+    public void testDeclareInstanceFields() throws Exception {
+        /*
+         * class Generated {
+         *   public int a;
+         *   protected Object b;
+         * }
+         */
+        generator.declare(GENERATED.getField(Type.INT, "a"), ACC_PUBLIC, null);
+        generator.declare(GENERATED.getField(Type.OBJECT, "b"), ACC_PROTECTED, null);
+
+        addDefaultConstructor();
+
+        Class<?> generatedClass = loadAndGenerate();
+        Object instance = generatedClass.newInstance();
+
+        Field a = generatedClass.getField("a");
+        assertEquals(int.class, a.getType());
+        assertEquals(0, a.get(instance));
+
+        Field b = generatedClass.getDeclaredField("b");
+        assertEquals(Object.class, b.getType());
+        b.setAccessible(true);
+        assertEquals(null, b.get(instance));
+    }
+
+    /**
+     * Declare a constructor that takes an int parameter and assigns it to a
+     * field.
+     */
+    public <G> void testDeclareConstructor() throws Exception {
+        /*
+         * class Generated {
+         *   public final int a;
+         *   public Generated(int a) {
+         *     this.a = a;
+         *   }
+         * }
+         */
+        Type<G> generated = Type.get("LGenerated;");
+        FieldId<G, Integer> fieldId = generated.getField(Type.INT, "a");
+        generator.declare(fieldId, ACC_PUBLIC | ACC_FINAL, null);
+        MethodId<?, Void> constructor = GENERATED.getConstructor(Type.INT);
+        Code code = generator.declare(constructor, ACC_PUBLIC | ACC_CONSTRUCTOR);
+        Local<G> thisRef = code.getThis(generated);
+        Local<Integer> parameter = code.getParameter(0, Type.INT);
+        code.invokeDirect(Type.OBJECT.getConstructor(), null, thisRef);
+        code.iput(fieldId, thisRef, parameter);
+        code.returnVoid();
+
+        Class<?> generatedClass = loadAndGenerate();
+        Field a = generatedClass.getField("a");
+        Object instance = generatedClass.getConstructor(int.class).newInstance(0xabcd);
+        assertEquals(0xabcd, a.get(instance));
+    }
+
+    public void testReturnBoolean() throws Exception {
+        testReturnType(boolean.class, true);
+        testReturnType(byte.class, (byte) 5);
+        testReturnType(char.class, 'E');
+        testReturnType(double.class, 5.0);
+        testReturnType(float.class, 5.0f);
+        testReturnType(int.class, 5);
+        testReturnType(long.class, 5L);
+        testReturnType(short.class, (short) 5);
+        testReturnType(void.class, null);
+        testReturnType(String.class, "foo");
+        testReturnType(Class.class, List.class);
+    }
+
+    private <T> void testReturnType(Class<T> javaType, T value) throws Exception {
+        /*
+         * public int call() {
+         *   int a = 5;
+         *   return a;
+         * }
+         */
+        reset();
+        Type<T> returnType = Type.get(javaType);
+        Code code = generator.declare(GENERATED.getMethod(returnType, "call"),
+                ACC_PUBLIC | ACC_STATIC);
+        if (value != null) {
+            Local<T> i = code.newLocal(returnType);
+            code.loadConstant(i, value);
+            code.returnValue(i);
+        } else {
+            code.returnVoid();
+        }
+
+        Class<?> generatedClass = loadAndGenerate();
+        Method method = generatedClass.getMethod("call");
+        assertEquals(javaType, method.getReturnType());
+        assertEquals(value, method.invoke(null));
+    }
+
+    public void testBranching() throws Exception {
+        Method lt = branchingMethod(Comparison.LT);
+        assertEquals(Boolean.TRUE, lt.invoke(null, 1, 2));
+        assertEquals(Boolean.FALSE, lt.invoke(null, 1, 1));
+        assertEquals(Boolean.FALSE, lt.invoke(null, 2, 1));
+
+        Method le = branchingMethod(Comparison.LE);
+        assertEquals(Boolean.TRUE, le.invoke(null, 1, 2));
+        assertEquals(Boolean.TRUE, le.invoke(null, 1, 1));
+        assertEquals(Boolean.FALSE, le.invoke(null, 2, 1));
+
+        Method eq = branchingMethod(Comparison.EQ);
+        assertEquals(Boolean.FALSE, eq.invoke(null, 1, 2));
+        assertEquals(Boolean.TRUE, eq.invoke(null, 1, 1));
+        assertEquals(Boolean.FALSE, eq.invoke(null, 2, 1));
+
+        Method ge = branchingMethod(Comparison.GE);
+        assertEquals(Boolean.FALSE, ge.invoke(null, 1, 2));
+        assertEquals(Boolean.TRUE, ge.invoke(null, 1, 1));
+        assertEquals(Boolean.TRUE, ge.invoke(null, 2, 1));
+
+        Method gt = branchingMethod(Comparison.GT);
+        assertEquals(Boolean.FALSE, gt.invoke(null, 1, 2));
+        assertEquals(Boolean.FALSE, gt.invoke(null, 1, 1));
+        assertEquals(Boolean.TRUE, gt.invoke(null, 2, 1));
+
+        Method ne = branchingMethod(Comparison.NE);
+        assertEquals(Boolean.TRUE, ne.invoke(null, 1, 2));
+        assertEquals(Boolean.FALSE, ne.invoke(null, 1, 1));
+        assertEquals(Boolean.TRUE, ne.invoke(null, 2, 1));
+    }
+
+    private Method branchingMethod(Comparison comparison) throws Exception {
+        /*
+         * public static boolean call(int localA, int localB) {
+         *   if (a comparison b) {
+         *     return true;
+         *   }
+         *   return false;
+         * }
+         */
+        reset();
+        MethodId<?, Boolean> methodId = GENERATED.getMethod(
+                Type.BOOLEAN, "call", Type.INT, Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localA = code.getParameter(0, Type.INT);
+        Local<Integer> localB = code.getParameter(1, Type.INT);
+        Local<Boolean> result = code.newLocal(Type.get(boolean.class));
+        Label afterIf = code.newLabel();
+        Label ifBody = code.newLabel();
+        code.compare(comparison, localA, localB, ifBody);
+        code.jump(afterIf);
+
+        code.mark(ifBody);
+        code.loadConstant(result, true);
+        code.returnValue(result);
+
+        code.mark(afterIf);
+        code.loadConstant(result, false);
+        code.returnValue(result);
+        return getMethod();
+    }
+
+    public void testCastIntegerToInteger() throws Exception {
+        Method intToLong = numericCastingMethod(int.class, long.class);
+        assertEquals(0x0000000000000000L, intToLong.invoke(null, 0x00000000));
+        assertEquals(0x000000007fffffffL, intToLong.invoke(null, 0x7fffffff));
+        assertEquals(0xffffffff80000000L, intToLong.invoke(null, 0x80000000));
+        assertEquals(0xffffffffffffffffL, intToLong.invoke(null, 0xffffffff));
+
+        Method longToInt = numericCastingMethod(long.class, int.class);
+        assertEquals(0x1234abcd, longToInt.invoke(null, 0x000000001234abcdL));
+        assertEquals(0x1234abcd, longToInt.invoke(null, 0x123456781234abcdL));
+        assertEquals(0x1234abcd, longToInt.invoke(null, 0xffffffff1234abcdL));
+
+        Method intToShort = numericCastingMethod(int.class, short.class);
+        assertEquals((short) 0x1234, intToShort.invoke(null, 0x00001234));
+        assertEquals((short) 0x1234, intToShort.invoke(null, 0xabcd1234));
+        assertEquals((short) 0x1234, intToShort.invoke(null, 0xffff1234));
+
+        Method intToChar = numericCastingMethod(int.class, char.class);
+        assertEquals((char) 0x1234, intToChar.invoke(null, 0x00001234));
+        assertEquals((char) 0x1234, intToChar.invoke(null, 0xabcd1234));
+        assertEquals((char) 0x1234, intToChar.invoke(null, 0xffff1234));
+
+        Method intToByte = numericCastingMethod(int.class, byte.class);
+        assertEquals((byte) 0x34, intToByte.invoke(null, 0x00000034));
+        assertEquals((byte) 0x34, intToByte.invoke(null, 0xabcd1234));
+        assertEquals((byte) 0x34, intToByte.invoke(null, 0xffffff34));
+    }
+
+    public void testCastIntegerToFloatingPoint() throws Exception {
+        Method intToFloat = numericCastingMethod(int.class, float.class);
+        assertEquals(0.0f, intToFloat.invoke(null, 0));
+        assertEquals(-1.0f, intToFloat.invoke(null, -1));
+        assertEquals(16777216f, intToFloat.invoke(null, 16777216));
+        assertEquals(16777216f, intToFloat.invoke(null, 16777217)); // precision
+
+        Method intToDouble = numericCastingMethod(int.class, double.class);
+        assertEquals(0.0, intToDouble.invoke(null, 0));
+        assertEquals(-1.0, intToDouble.invoke(null, -1));
+        assertEquals(16777216.0, intToDouble.invoke(null, 16777216));
+        assertEquals(16777217.0, intToDouble.invoke(null, 16777217));
+
+        Method longToFloat = numericCastingMethod(long.class, float.class);
+        assertEquals(0.0f, longToFloat.invoke(null, 0L));
+        assertEquals(-1.0f, longToFloat.invoke(null, -1L));
+        assertEquals(16777216f, longToFloat.invoke(null, 16777216L));
+        assertEquals(16777216f, longToFloat.invoke(null, 16777217L));
+
+        Method longToDouble = numericCastingMethod(long.class, double.class);
+        assertEquals(0.0, longToDouble.invoke(null, 0L));
+        assertEquals(-1.0, longToDouble.invoke(null, -1L));
+        assertEquals(9007199254740992.0, longToDouble.invoke(null, 9007199254740992L));
+        assertEquals(9007199254740992.0, longToDouble.invoke(null, 9007199254740993L)); // precision
+    }
+
+    public void testCastFloatingPointToInteger() throws Exception {
+        Method floatToInt = numericCastingMethod(float.class, int.class);
+        assertEquals(0, floatToInt.invoke(null, 0.0f));
+        assertEquals(-1, floatToInt.invoke(null, -1.0f));
+        assertEquals(Integer.MAX_VALUE, floatToInt.invoke(null, 10e15f));
+        assertEquals(0, floatToInt.invoke(null, 0.5f));
+        assertEquals(Integer.MIN_VALUE, floatToInt.invoke(null, Float.NEGATIVE_INFINITY));
+        assertEquals(0, floatToInt.invoke(null, Float.NaN));
+
+        Method floatToLong = numericCastingMethod(float.class, long.class);
+        assertEquals(0L, floatToLong.invoke(null, 0.0f));
+        assertEquals(-1L, floatToLong.invoke(null, -1.0f));
+        assertEquals(10000000272564224L, floatToLong.invoke(null, 10e15f));
+        assertEquals(0L, floatToLong.invoke(null, 0.5f));
+        assertEquals(Long.MIN_VALUE, floatToLong.invoke(null, Float.NEGATIVE_INFINITY));
+        assertEquals(0L, floatToLong.invoke(null, Float.NaN));
+
+        Method doubleToInt = numericCastingMethod(double.class, int.class);
+        assertEquals(0, doubleToInt.invoke(null, 0.0));
+        assertEquals(-1, doubleToInt.invoke(null, -1.0));
+        assertEquals(Integer.MAX_VALUE, doubleToInt.invoke(null, 10e15));
+        assertEquals(0, doubleToInt.invoke(null, 0.5));
+        assertEquals(Integer.MIN_VALUE, doubleToInt.invoke(null, Double.NEGATIVE_INFINITY));
+        assertEquals(0, doubleToInt.invoke(null, Double.NaN));
+
+        Method doubleToLong = numericCastingMethod(double.class, long.class);
+        assertEquals(0L, doubleToLong.invoke(null, 0.0));
+        assertEquals(-1L, doubleToLong.invoke(null, -1.0));
+        assertEquals(10000000000000000L, doubleToLong.invoke(null, 10e15));
+        assertEquals(0L, doubleToLong.invoke(null, 0.5));
+        assertEquals(Long.MIN_VALUE, doubleToLong.invoke(null, Double.NEGATIVE_INFINITY));
+        assertEquals(0L, doubleToLong.invoke(null, Double.NaN));
+    }
+
+    public void testCastFloatingPointToFloatingPoint() throws Exception {
+        Method floatToDouble = numericCastingMethod(float.class, double.class);
+        assertEquals(0.0, floatToDouble.invoke(null, 0.0f));
+        assertEquals(-1.0, floatToDouble.invoke(null, -1.0f));
+        assertEquals(0.5, floatToDouble.invoke(null, 0.5f));
+        assertEquals(Double.NEGATIVE_INFINITY, floatToDouble.invoke(null, Float.NEGATIVE_INFINITY));
+        assertEquals(Double.NaN, floatToDouble.invoke(null, Float.NaN));
+
+        Method doubleToFloat = numericCastingMethod(double.class, float.class);
+        assertEquals(0.0f, doubleToFloat.invoke(null, 0.0));
+        assertEquals(-1.0f, doubleToFloat.invoke(null, -1.0));
+        assertEquals(0.5f, doubleToFloat.invoke(null, 0.5));
+        assertEquals(Float.NEGATIVE_INFINITY, doubleToFloat.invoke(null, Double.NEGATIVE_INFINITY));
+        assertEquals(Float.NaN, doubleToFloat.invoke(null, Double.NaN));
+    }
+
+    private Method numericCastingMethod(Class<?> source, Class<?> target)
+            throws Exception {
+        /*
+         * public static short call(int source) {
+         *   short casted = (short) source;
+         *   return casted;
+         * }
+         */
+        reset();
+        Type<?> sourceType = Type.get(source);
+        Type<?> targetType = Type.get(target);
+        MethodId<?, ?> methodId = GENERATED.getMethod(targetType, "call", sourceType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<?> localSource = code.getParameter(0, sourceType);
+        Local<?> localCasted = code.newLocal(targetType);
+        code.numericCast(localSource, localCasted);
+        code.returnValue(localCasted);
+        return getMethod();
+    }
+
+    public void testNot() throws Exception {
+        Method notInteger = notMethod(int.class);
+        assertEquals(0xffffffff, notInteger.invoke(null, 0x00000000));
+        assertEquals(0x00000000, notInteger.invoke(null, 0xffffffff));
+        assertEquals(0xedcba987, notInteger.invoke(null, 0x12345678));
+
+        Method notLong = notMethod(long.class);
+        assertEquals(0xffffffffffffffffL, notLong.invoke(null, 0x0000000000000000L));
+        assertEquals(0x0000000000000000L, notLong.invoke(null, 0xffffffffffffffffL));
+        assertEquals(0x98765432edcba987L, notLong.invoke(null, 0x6789abcd12345678L));
+    }
+
+    private <T> Method notMethod(Class<T> source) throws Exception {
+        /*
+         * public static short call(int source) {
+         *   source = ~source;
+         *   return not;
+         * }
+         */
+        reset();
+        Type<T> valueType = Type.get(source);
+        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<T> localSource = code.getParameter(0, valueType);
+        code.not(localSource, localSource);
+        code.returnValue(localSource);
+        return getMethod();
+    }
+
+    public void testNegate() throws Exception {
+        Method negateInteger = negateMethod(int.class);
+        assertEquals(0, negateInteger.invoke(null, 0));
+        assertEquals(-1, negateInteger.invoke(null, 1));
+        assertEquals(Integer.MIN_VALUE, negateInteger.invoke(null, Integer.MIN_VALUE));
+
+        Method negateLong = negateMethod(long.class);
+        assertEquals(0L, negateLong.invoke(null, 0));
+        assertEquals(-1L, negateLong.invoke(null, 1));
+        assertEquals(Long.MIN_VALUE, negateLong.invoke(null, Long.MIN_VALUE));
+
+        Method negateFloat = negateMethod(float.class);
+        assertEquals(-0.0f, negateFloat.invoke(null, 0.0f));
+        assertEquals(-1.0f, negateFloat.invoke(null, 1.0f));
+        assertEquals(Float.NaN, negateFloat.invoke(null, Float.NaN));
+        assertEquals(Float.POSITIVE_INFINITY, negateFloat.invoke(null, Float.NEGATIVE_INFINITY));
+
+        Method negateDouble = negateMethod(double.class);
+        assertEquals(-0.0, negateDouble.invoke(null, 0.0));
+        assertEquals(-1.0, negateDouble.invoke(null, 1.0));
+        assertEquals(Double.NaN, negateDouble.invoke(null, Double.NaN));
+        assertEquals(Double.POSITIVE_INFINITY, negateDouble.invoke(null, Double.NEGATIVE_INFINITY));
+    }
+
+    private <T> Method negateMethod(Class<T> source) throws Exception {
+        /*
+         * public static short call(int source) {
+         *   source = -source;
+         *   return not;
+         * }
+         */
+        reset();
+        Type<T> valueType = Type.get(source);
+        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<T> localSource = code.getParameter(0, valueType);
+        code.negate(localSource, localSource);
+        code.returnValue(localSource);
+        return getMethod();
+    }
+
+    public void testIntBinaryOps() throws Exception {
+        Method add = binaryOpMethod(int.class, BinaryOp.ADD);
+        assertEquals(79, add.invoke(null, 75, 4));
+
+        Method subtract = binaryOpMethod(int.class, BinaryOp.SUBTRACT);
+        assertEquals(71, subtract.invoke(null, 75, 4));
+
+        Method multiply = binaryOpMethod(int.class, BinaryOp.MULTIPLY);
+        assertEquals(300, multiply.invoke(null, 75, 4));
+
+        Method divide = binaryOpMethod(int.class, BinaryOp.DIVIDE);
+        assertEquals(18, divide.invoke(null, 75, 4));
+        try {
+            divide.invoke(null, 75, 0);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(ArithmeticException.class, expected.getCause().getClass());
+        }
+
+        Method remainder = binaryOpMethod(int.class, BinaryOp.REMAINDER);
+        assertEquals(3, remainder.invoke(null, 75, 4));
+        try {
+            remainder.invoke(null, 75, 0);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(ArithmeticException.class, expected.getCause().getClass());
+        }
+
+        Method and = binaryOpMethod(int.class, BinaryOp.AND);
+        assertEquals(0xff000000, and.invoke(null, 0xff00ff00, 0xffff0000));
+
+        Method or = binaryOpMethod(int.class, BinaryOp.OR);
+        assertEquals(0xffffff00, or.invoke(null, 0xff00ff00, 0xffff0000));
+
+        Method xor = binaryOpMethod(int.class, BinaryOp.XOR);
+        assertEquals(0x00ffff00, xor.invoke(null, 0xff00ff00, 0xffff0000));
+
+        Method shiftLeft = binaryOpMethod(int.class, BinaryOp.SHIFT_LEFT);
+        assertEquals(0xcd123400, shiftLeft.invoke(null, 0xabcd1234, 8));
+
+        Method shiftRight = binaryOpMethod(int.class, BinaryOp.SHIFT_RIGHT);
+        assertEquals(0xffabcd12, shiftRight.invoke(null, 0xabcd1234, 8));
+
+        Method unsignedShiftRight = binaryOpMethod(int.class,
+                BinaryOp.UNSIGNED_SHIFT_RIGHT);
+        assertEquals(0x00abcd12, unsignedShiftRight.invoke(null, 0xabcd1234, 8));
+    }
+
+    public void testLongBinaryOps() throws Exception {
+        Method add = binaryOpMethod(long.class, BinaryOp.ADD);
+        assertEquals(79L, add.invoke(null, 75L, 4L));
+
+        Method subtract = binaryOpMethod(long.class, BinaryOp.SUBTRACT);
+        assertEquals(71L, subtract.invoke(null, 75L, 4L));
+
+        Method multiply = binaryOpMethod(long.class, BinaryOp.MULTIPLY);
+        assertEquals(300L, multiply.invoke(null, 75L, 4L));
+
+        Method divide = binaryOpMethod(long.class, BinaryOp.DIVIDE);
+        assertEquals(18L, divide.invoke(null, 75L, 4L));
+        try {
+            divide.invoke(null, 75L, 0L);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(ArithmeticException.class, expected.getCause().getClass());
+        }
+
+        Method remainder = binaryOpMethod(long.class, BinaryOp.REMAINDER);
+        assertEquals(3L, remainder.invoke(null, 75L, 4L));
+        try {
+            remainder.invoke(null, 75L, 0L);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(ArithmeticException.class, expected.getCause().getClass());
+        }
+
+        Method and = binaryOpMethod(long.class, BinaryOp.AND);
+        assertEquals(0xff00ff0000000000L,
+                and.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
+
+        Method or = binaryOpMethod(long.class, BinaryOp.OR);
+        assertEquals(0xffffffffff00ff00L,
+                or.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
+
+        Method xor = binaryOpMethod(long.class, BinaryOp.XOR);
+        assertEquals(0x00ff00ffff00ff00L,
+                xor.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
+
+        Method shiftLeft = binaryOpMethod(long.class, BinaryOp.SHIFT_LEFT);
+        assertEquals(0xcdef012345678900L, shiftLeft.invoke(null, 0xabcdef0123456789L, 8L));
+
+        Method shiftRight = binaryOpMethod(long.class, BinaryOp.SHIFT_RIGHT);
+        assertEquals(0xffabcdef01234567L, shiftRight.invoke(null, 0xabcdef0123456789L, 8L));
+
+        Method unsignedShiftRight = binaryOpMethod(long.class,
+                BinaryOp.UNSIGNED_SHIFT_RIGHT);
+        assertEquals(0x00abcdef01234567L, unsignedShiftRight.invoke(null, 0xabcdef0123456789L, 8L));
+    }
+
+    public void testFloatBinaryOps() throws Exception {
+        Method add = binaryOpMethod(float.class, BinaryOp.ADD);
+        assertEquals(6.75f, add.invoke(null, 5.5f, 1.25f));
+
+        Method subtract = binaryOpMethod(float.class, BinaryOp.SUBTRACT);
+        assertEquals(4.25f, subtract.invoke(null, 5.5f, 1.25f));
+
+        Method multiply = binaryOpMethod(float.class, BinaryOp.MULTIPLY);
+        assertEquals(6.875f, multiply.invoke(null, 5.5f, 1.25f));
+
+        Method divide = binaryOpMethod(float.class, BinaryOp.DIVIDE);
+        assertEquals(4.4f, divide.invoke(null, 5.5f, 1.25f));
+        assertEquals(Float.POSITIVE_INFINITY, divide.invoke(null, 5.5f, 0.0f));
+
+        Method remainder = binaryOpMethod(float.class, BinaryOp.REMAINDER);
+        assertEquals(0.5f, remainder.invoke(null, 5.5f, 1.25f));
+        assertEquals(Float.NaN, remainder.invoke(null, 5.5f, 0.0f));
+    }
+
+    public void testDoubleBinaryOps() throws Exception {
+        Method add = binaryOpMethod(double.class, BinaryOp.ADD);
+        assertEquals(6.75, add.invoke(null, 5.5, 1.25));
+
+        Method subtract = binaryOpMethod(double.class, BinaryOp.SUBTRACT);
+        assertEquals(4.25, subtract.invoke(null, 5.5, 1.25));
+
+        Method multiply = binaryOpMethod(double.class, BinaryOp.MULTIPLY);
+        assertEquals(6.875, multiply.invoke(null, 5.5, 1.25));
+
+        Method divide = binaryOpMethod(double.class, BinaryOp.DIVIDE);
+        assertEquals(4.4, divide.invoke(null, 5.5, 1.25));
+        assertEquals(Double.POSITIVE_INFINITY, divide.invoke(null, 5.5, 0.0));
+
+        Method remainder = binaryOpMethod(double.class, BinaryOp.REMAINDER);
+        assertEquals(0.5, remainder.invoke(null, 5.5, 1.25));
+        assertEquals(Double.NaN, remainder.invoke(null, 5.5, 0.0));
+    }
+
+    private <T> Method binaryOpMethod(Class<T> valueClass, BinaryOp op)
+            throws Exception {
+        /*
+         * public static int binaryOp(int a, int b) {
+         *   int result = a + b;
+         *   return result;
+         * }
+         */
+        reset();
+        Type<T> valueType = Type.get(valueClass);
+        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType, valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<T> localA = code.getParameter(0, valueType);
+        Local<T> localB = code.getParameter(1, valueType);
+        Local<T> localResult = code.newLocal(valueType);
+        code.op(op, localResult, localA, localB);
+        code.returnValue(localResult);
+        return getMethod();
+    }
+
+    public void testReadAndWriteInstanceFields() throws Exception {
+        Instance instance = new Instance();
+
+        Method intSwap = instanceSwapMethod(int.class, "intValue");
+        instance.intValue = 5;
+        assertEquals(5, intSwap.invoke(null, instance, 10));
+        assertEquals(10, instance.intValue);
+
+        Method longSwap = instanceSwapMethod(long.class, "longValue");
+        instance.longValue = 500L;
+        assertEquals(500L, longSwap.invoke(null, instance, 1234L));
+        assertEquals(1234L, instance.longValue);
+
+        Method booleanSwap = instanceSwapMethod(boolean.class, "booleanValue");
+        instance.booleanValue = false;
+        assertEquals(false, booleanSwap.invoke(null, instance, true));
+        assertEquals(true, instance.booleanValue);
+
+        Method floatSwap = instanceSwapMethod(float.class, "floatValue");
+        instance.floatValue = 1.5f;
+        assertEquals(1.5f, floatSwap.invoke(null, instance, 0.5f));
+        assertEquals(0.5f, instance.floatValue);
+
+        Method doubleSwap = instanceSwapMethod(double.class, "doubleValue");
+        instance.doubleValue = 155.5;
+        assertEquals(155.5, doubleSwap.invoke(null, instance, 266.6));
+        assertEquals(266.6, instance.doubleValue);
+
+        Method objectSwap = instanceSwapMethod(Object.class, "objectValue");
+        instance.objectValue = "before";
+        assertEquals("before", objectSwap.invoke(null, instance, "after"));
+        assertEquals("after", instance.objectValue);
+
+        Method byteSwap = instanceSwapMethod(byte.class, "byteValue");
+        instance.byteValue = 0x35;
+        assertEquals((byte) 0x35, byteSwap.invoke(null, instance, (byte) 0x64));
+        assertEquals((byte) 0x64, instance.byteValue);
+
+        Method charSwap = instanceSwapMethod(char.class, "charValue");
+        instance.charValue = 'A';
+        assertEquals('A', charSwap.invoke(null, instance, 'B'));
+        assertEquals('B', instance.charValue);
+
+        Method shortSwap = instanceSwapMethod(short.class, "shortValue");
+        instance.shortValue = (short) 0xabcd;
+        assertEquals((short) 0xabcd, shortSwap.invoke(null, instance, (short) 0x1234));
+        assertEquals((short) 0x1234, instance.shortValue);
+    }
+
+    public class Instance {
+        public int intValue;
+        public long longValue;
+        public float floatValue;
+        public double doubleValue;
+        public Object objectValue;
+        public boolean booleanValue;
+        public byte byteValue;
+        public char charValue;
+        public short shortValue;
+    }
+
+    private <V> Method instanceSwapMethod(
+            Class<V> valueClass, String fieldName) throws Exception {
+        /*
+         * public static int call(Instance instance, int newValue) {
+         *   int oldValue = instance.intValue;
+         *   instance.intValue = newValue;
+         *   return oldValue;
+         * }
+         */
+        reset();
+        Type<V> valueType = Type.get(valueClass);
+        Type<Instance> objectType = Type.get(Instance.class);
+        FieldId<Instance, V> fieldId = objectType.getField(valueType, fieldName);
+        MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", objectType, valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Instance> localInstance = code.getParameter(0, objectType);
+        Local<V> localNewValue = code.getParameter(1, valueType);
+        Local<V> localOldValue = code.newLocal(valueType);
+        code.iget(fieldId, localInstance, localOldValue);
+        code.iput(fieldId, localInstance, localNewValue);
+        code.returnValue(localOldValue);
+        return getMethod();
+    }
+
+    public void testReadAndWriteStaticFields() throws Exception {
+        Method intSwap = staticSwapMethod(int.class, "intValue");
+        Static.intValue = 5;
+        assertEquals(5, intSwap.invoke(null, 10));
+        assertEquals(10, Static.intValue);
+
+        Method longSwap = staticSwapMethod(long.class, "longValue");
+        Static.longValue = 500L;
+        assertEquals(500L, longSwap.invoke(null, 1234L));
+        assertEquals(1234L, Static.longValue);
+
+        Method booleanSwap = staticSwapMethod(boolean.class, "booleanValue");
+        Static.booleanValue = false;
+        assertEquals(false, booleanSwap.invoke(null, true));
+        assertEquals(true, Static.booleanValue);
+
+        Method floatSwap = staticSwapMethod(float.class, "floatValue");
+        Static.floatValue = 1.5f;
+        assertEquals(1.5f, floatSwap.invoke(null, 0.5f));
+        assertEquals(0.5f, Static.floatValue);
+
+        Method doubleSwap = staticSwapMethod(double.class, "doubleValue");
+        Static.doubleValue = 155.5;
+        assertEquals(155.5, doubleSwap.invoke(null, 266.6));
+        assertEquals(266.6, Static.doubleValue);
+
+        Method objectSwap = staticSwapMethod(Object.class, "objectValue");
+        Static.objectValue = "before";
+        assertEquals("before", objectSwap.invoke(null, "after"));
+        assertEquals("after", Static.objectValue);
+
+        Method byteSwap = staticSwapMethod(byte.class, "byteValue");
+        Static.byteValue = 0x35;
+        assertEquals((byte) 0x35, byteSwap.invoke(null, (byte) 0x64));
+        assertEquals((byte) 0x64, Static.byteValue);
+
+        Method charSwap = staticSwapMethod(char.class, "charValue");
+        Static.charValue = 'A';
+        assertEquals('A', charSwap.invoke(null, 'B'));
+        assertEquals('B', Static.charValue);
+
+        Method shortSwap = staticSwapMethod(short.class, "shortValue");
+        Static.shortValue = (short) 0xabcd;
+        assertEquals((short) 0xabcd, shortSwap.invoke(null, (short) 0x1234));
+        assertEquals((short) 0x1234, Static.shortValue);
+    }
+
+    public static class Static {
+        public static int intValue;
+        public static long longValue;
+        public static float floatValue;
+        public static double doubleValue;
+        public static Object objectValue;
+        public static boolean booleanValue;
+        public static byte byteValue;
+        public static char charValue;
+        public static short shortValue;
+    }
+
+    private <V> Method staticSwapMethod(Class<V> valueClass, String fieldName)
+            throws Exception {
+        /*
+         * public static int call(int newValue) {
+         *   int oldValue = Static.intValue;
+         *   Static.intValue = newValue;
+         *   return oldValue;
+         * }
+         */
+        reset();
+        Type<V> valueType = Type.get(valueClass);
+        Type<Static> objectType = Type.get(Static.class);
+        FieldId<Static, V> fieldId = objectType.getField(valueType, fieldName);
+        MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<V> localNewValue = code.getParameter(0, valueType);
+        Local<V> localOldValue = code.newLocal(valueType);
+        code.sget(fieldId, localOldValue);
+        code.sput(fieldId, localNewValue);
+        code.returnValue(localOldValue);
+        return getMethod();
+    }
+
+    public void testTypeCast() throws Exception {
+        /*
+         * public static String call(Object o) {
+         *   String s = (String) o;
+         * }
+         */
+        MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call", Type.OBJECT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Object> localObject = code.getParameter(0, Type.OBJECT);
+        Local<String> localString = code.newLocal(Type.STRING);
+        code.typeCast(localObject, localString);
+        code.returnValue(localString);
+
+        Method method = getMethod();
+        assertEquals("s", method.invoke(null, "s"));
+        assertEquals(null, method.invoke(null, (String) null));
+        try {
+            method.invoke(null, 5);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(ClassCastException.class, expected.getCause().getClass());
+        }
+    }
+
+    public void testInstanceOf() throws Exception {
+        /*
+         * public static boolean call(Object o) {
+         *   boolean result = o instanceof String;
+         *   return result;
+         * }
+         */
+        MethodId<?, Boolean> methodId = GENERATED.getMethod(Type.BOOLEAN, "call", Type.OBJECT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Object> localObject = code.getParameter(0, Type.OBJECT);
+        Local<Boolean> localResult = code.newLocal(Type.BOOLEAN);
+        code.instanceOfType(localResult, localObject, Type.STRING);
+        code.returnValue(localResult);
+
+        Method method = getMethod();
+        assertEquals(true, method.invoke(null, "s"));
+        assertEquals(false, method.invoke(null, (String) null));
+        assertEquals(false, method.invoke(null, 5));
+    }
+
+    /**
+     * Tests that we can construct a for loop.
+     */
+    public void testForLoop() throws Exception {
+        /*
+         * public static int call(int count) {
+         *   int result = 1;
+         *   for (int i = 0; i < count; i += 1) {
+         *     result = result * 2;
+         *   }
+         *   return result;
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localCount = code.getParameter(0, Type.INT);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        Local<Integer> localI = code.newLocal(Type.INT);
+        Local<Integer> local1 = code.newLocal(Type.INT);
+        Local<Integer> local2 = code.newLocal(Type.INT);
+        code.loadConstant(local1, 1);
+        code.loadConstant(local2, 2);
+        code.loadConstant(localResult, 1);
+        code.loadConstant(localI, 0);
+        Label loopCondition = code.newLabel();
+        Label loopBody = code.newLabel();
+        Label afterLoop = code.newLabel();
+        code.mark(loopCondition);
+        code.compare(Comparison.LT, localI, localCount, loopBody);
+        code.jump(afterLoop);
+        code.mark(loopBody);
+        code.op(BinaryOp.MULTIPLY, localResult, localResult, local2);
+        code.op(BinaryOp.ADD, localI, localI, local1);
+        code.jump(loopCondition);
+        code.mark(afterLoop);
+        code.returnValue(localResult);
+
+        Method pow2 = getMethod();
+        assertEquals(1, pow2.invoke(null, 0));
+        assertEquals(2, pow2.invoke(null, 1));
+        assertEquals(4, pow2.invoke(null, 2));
+        assertEquals(8, pow2.invoke(null, 3));
+        assertEquals(16, pow2.invoke(null, 4));
+    }
+
+    /**
+     * Tests that we can construct a while loop.
+     */
+    public void testWhileLoop() throws Exception {
+        /*
+         * public static int call(int max) {
+         *   int result = 1;
+         *   while (result < max) {
+         *     result = result * 2;
+         *   }
+         *   return result;
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localMax = code.getParameter(0, Type.INT);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        Local<Integer> local2 = code.newLocal(Type.INT);
+        code.loadConstant(localResult, 1);
+        code.loadConstant(local2, 2);
+        Label loopCondition = code.newLabel();
+        Label loopBody = code.newLabel();
+        Label afterLoop = code.newLabel();
+        code.mark(loopCondition);
+        code.compare(Comparison.LT, localResult, localMax, loopBody);
+        code.jump(afterLoop);
+        code.mark(loopBody);
+        code.op(BinaryOp.MULTIPLY, localResult, localResult, local2);
+        code.jump(loopCondition);
+        code.mark(afterLoop);
+        code.returnValue(localResult);
+
+        Method ceilPow2 = getMethod();
+        assertEquals(1, ceilPow2.invoke(null, 1));
+        assertEquals(2, ceilPow2.invoke(null, 2));
+        assertEquals(4, ceilPow2.invoke(null, 3));
+        assertEquals(16, ceilPow2.invoke(null, 10));
+        assertEquals(128, ceilPow2.invoke(null, 100));
+        assertEquals(1024, ceilPow2.invoke(null, 1000));
+    }
+
+    public void testIfElseBlock() throws Exception {
+        /*
+         * public static int call(int a, int b, int c) {
+         *   if (a < b) {
+         *     if (a < c) {
+         *       return a;
+         *     } else {
+         *       return c;
+         *     }
+         *   } else if (b < c) {
+         *     return b;
+         *   } else {
+         *     return c;
+         *   }
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(
+                Type.INT, "call", Type.INT, Type.INT, Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localA = code.getParameter(0, Type.INT);
+        Local<Integer> localB = code.getParameter(1, Type.INT);
+        Local<Integer> localC = code.getParameter(2, Type.INT);
+        Label aLessThanB = code.newLabel();
+        Label aLessThanC = code.newLabel();
+        Label bLessThanC = code.newLabel();
+        code.compare(Comparison.LT, localA, localB, aLessThanB);
+        code.compare(Comparison.LT, localB, localC, bLessThanC);
+        code.returnValue(localC);
+        // (a < b)
+        code.mark(aLessThanB);
+        code.compare(Comparison.LT, localA, localC, aLessThanC);
+        code.returnValue(localC);
+        // (a < c)
+        code.mark(aLessThanC);
+        code.returnValue(localA);
+        // (b < c)
+        code.mark(bLessThanC);
+        code.returnValue(localB);
+
+        Method min = getMethod();
+        assertEquals(1, min.invoke(null, 1, 2, 3));
+        assertEquals(1, min.invoke(null, 2, 3, 1));
+        assertEquals(1, min.invoke(null, 2, 1, 3));
+        assertEquals(1, min.invoke(null, 3, 2, 1));
+    }
+
+    public void testRecursion() throws Exception {
+        /*
+         * public static int call(int a) {
+         *   if (a < 2) {
+         *     return a;
+         *   }
+         *   a -= 1;
+         *   int x = call(a)
+         *   a -= 1;
+         *   int y = call(a);
+         *   int result = x + y;
+         *   return result;
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localA = code.getParameter(0, Type.INT);
+        Local<Integer> local1 = code.newLocal(Type.INT);
+        Local<Integer> local2 = code.newLocal(Type.INT);
+        Local<Integer> localX = code.newLocal(Type.INT);
+        Local<Integer> localY = code.newLocal(Type.INT);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        Label baseCase = code.newLabel();
+        code.loadConstant(local1, 1);
+        code.loadConstant(local2, 2);
+        code.compare(Comparison.LT, localA, local2, baseCase);
+        code.op(BinaryOp.SUBTRACT, localA, localA, local1);
+        code.invokeStatic(methodId, localX, localA);
+        code.op(BinaryOp.SUBTRACT, localA, localA, local1);
+        code.invokeStatic(methodId, localY, localA);
+        code.op(BinaryOp.ADD, localResult, localX, localY);
+        code.returnValue(localResult);
+        code.mark(baseCase);
+        code.returnValue(localA);
+
+        Method fib = getMethod();
+        assertEquals(0, fib.invoke(null, 0));
+        assertEquals(1, fib.invoke(null, 1));
+        assertEquals(1, fib.invoke(null, 2));
+        assertEquals(2, fib.invoke(null, 3));
+        assertEquals(3, fib.invoke(null, 4));
+        assertEquals(5, fib.invoke(null, 5));
+        assertEquals(8, fib.invoke(null, 6));
+    }
+
+    public void testCatchExceptions() throws Exception {
+        /*
+         * public static String call(int i) {
+         *   try {
+         *     DexGeneratorTest.thrower(i);
+         *     return "NONE";
+         *   } catch (IllegalArgumentException e) {
+         *     return "IAE";
+         *   } catch (IllegalStateException e) {
+         *     return "ISE";
+         *   } catch (RuntimeException e) {
+         *     return "RE";
+         *   }
+         */
+        MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call", Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localI = code.getParameter(0, Type.INT);
+        Local<String> result = code.newLocal(Type.STRING);
+        Label catchIae = code.newLabel();
+        Label catchIse = code.newLabel();
+        Label catchRe = code.newLabel();
+
+        code.addCatchClause(Type.get(IllegalArgumentException.class), catchIae);
+        code.addCatchClause(Type.get(IllegalStateException.class), catchIse);
+        code.addCatchClause(Type.get(RuntimeException.class), catchRe);
+        MethodId<?, ?> thrower = TEST_TYPE.getMethod(Type.VOID, "thrower", Type.INT);
+        code.invokeStatic(thrower, null, localI);
+        code.loadConstant(result, "NONE");
+        code.returnValue(result);
+
+        code.mark(catchIae);
+        code.loadConstant(result, "IAE");
+        code.returnValue(result);
+
+        code.mark(catchIse);
+        code.loadConstant(result, "ISE");
+        code.returnValue(result);
+
+        code.mark(catchRe);
+        code.loadConstant(result, "RE");
+        code.returnValue(result);
+
+        Method method = getMethod();
+        assertEquals("NONE", method.invoke(null, 0));
+        assertEquals("IAE", method.invoke(null, 1));
+        assertEquals("ISE", method.invoke(null, 2));
+        assertEquals("RE", method.invoke(null, 3));
+        try {
+            method.invoke(null, 4);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(IOException.class, expected.getCause().getClass());
+        }
+    }
+
+    @SuppressWarnings("unused") // called by generated code
+    public static void thrower(int a) throws Exception {
+        switch (a) {
+        case 0:
+            return;
+        case 1:
+            throw new IllegalArgumentException();
+        case 2:
+            throw new IllegalStateException();
+        case 3:
+            throw new UnsupportedOperationException();
+        case 4:
+            throw new IOException();
+        default:
+            throw new AssertionError();
+        }
+    }
+
+    public void testNestedCatchClauses() throws Exception {
+        /*
+         * public static String call(int a, int b, int c) {
+         *   try {
+         *     DexGeneratorTest.thrower(a);
+         *     try {
+         *       DexGeneratorTest.thrower(b);
+         *     } catch (IllegalArgumentException) {
+         *       return "INNER";
+         *     }
+         *     DexGeneratorTest.thrower(c);
+         *     return "NONE";
+         *   } catch (IllegalArgumentException e) {
+         *     return "OUTER";
+         *   }
+         */
+        MethodId<?, String> methodId = GENERATED.getMethod(
+                Type.STRING, "call", Type.INT, Type.INT, Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localA = code.getParameter(0, Type.INT);
+        Local<Integer> localB = code.getParameter(1, Type.INT);
+        Local<Integer> localC = code.getParameter(2, Type.INT);
+        Local<String> localResult = code.newLocal(Type.STRING);
+        Label catchInner = code.newLabel();
+        Label catchOuter = code.newLabel();
+
+        Type<IllegalArgumentException> iaeType = Type.get(IllegalArgumentException.class);
+        code.addCatchClause(iaeType, catchOuter);
+
+        MethodId<?, ?> thrower = TEST_TYPE.getMethod(Type.VOID, "thrower", Type.INT);
+        code.invokeStatic(thrower, null, localA);
+
+        // for the inner catch clause, we stash the old label and put it back afterwards.
+        Label previousLabel = code.removeCatchClause(iaeType);
+        code.addCatchClause(iaeType, catchInner);
+        code.invokeStatic(thrower, null, localB);
+        code.removeCatchClause(iaeType);
+        code.addCatchClause(iaeType, previousLabel);
+        code.invokeStatic(thrower, null, localC);
+        code.loadConstant(localResult, "NONE");
+        code.returnValue(localResult);
+
+        code.mark(catchInner);
+        code.loadConstant(localResult, "INNER");
+        code.returnValue(localResult);
+
+        code.mark(catchOuter);
+        code.loadConstant(localResult, "OUTER");
+        code.returnValue(localResult);
+
+        Method method = getMethod();
+        assertEquals("OUTER", method.invoke(null, 1, 0, 0));
+        assertEquals("INNER", method.invoke(null, 0, 1, 0));
+        assertEquals("OUTER", method.invoke(null, 0, 0, 1));
+        assertEquals("NONE", method.invoke(null, 0, 0, 0));
+    }
+
+    public void testThrow() throws Exception {
+        /*
+         * public static void call() {
+         *   throw new IllegalStateException();
+         * }
+         */
+        MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call");
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Type<IllegalStateException> iseType = Type.get(IllegalStateException.class);
+        MethodId<IllegalStateException, Void> iseConstructor = iseType.getConstructor();
+        Local<IllegalStateException> localIse = code.newLocal(iseType);
+        code.newInstance(localIse, iseConstructor);
+        code.throwValue(localIse);
+
+        try {
+            getMethod().invoke(null);
+            fail();
+        } catch (InvocationTargetException expected) {
+            assertEquals(IllegalStateException.class, expected.getCause().getClass());
+        }
+    }
+
+    public void testUnusedParameters() throws Exception {
+        /*
+         * public static void call(int unused1, long unused2, long unused3) {}
+         */
+        MethodId<?, Void> methodId = GENERATED.getMethod(
+                Type.VOID, "call", Type.INT, Type.LONG, Type.LONG);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        code.returnVoid();
+        getMethod().invoke(null, 1, 2, 3);
+    }
+
+    public void testFloatingPointCompare() throws Exception {
+        Method floatG = floatingPointCompareMethod(Type.FLOAT, 1);
+        assertEquals(-1, floatG.invoke(null, 1.0f, Float.POSITIVE_INFINITY));
+        assertEquals(-1, floatG.invoke(null, 1.0f, 2.0f));
+        assertEquals(0, floatG.invoke(null, 1.0f, 1.0f));
+        assertEquals(1, floatG.invoke(null, 2.0f, 1.0f));
+        assertEquals(1, floatG.invoke(null, 1.0f, Float.NaN));
+        assertEquals(1, floatG.invoke(null, Float.NaN, 1.0f));
+        assertEquals(1, floatG.invoke(null, Float.NaN, Float.NaN));
+        assertEquals(1, floatG.invoke(null, Float.NaN, Float.POSITIVE_INFINITY));
+
+        Method floatL = floatingPointCompareMethod(Type.FLOAT, -1);
+        assertEquals(-1, floatG.invoke(null, 1.0f, Float.POSITIVE_INFINITY));
+        assertEquals(-1, floatL.invoke(null, 1.0f, 2.0f));
+        assertEquals(0, floatL.invoke(null, 1.0f, 1.0f));
+        assertEquals(1, floatL.invoke(null, 2.0f, 1.0f));
+        assertEquals(-1, floatL.invoke(null, 1.0f, Float.NaN));
+        assertEquals(-1, floatL.invoke(null, Float.NaN, 1.0f));
+        assertEquals(-1, floatL.invoke(null, Float.NaN, Float.NaN));
+        assertEquals(-1, floatL.invoke(null, Float.NaN, Float.POSITIVE_INFINITY));
+
+        Method doubleG = floatingPointCompareMethod(Type.DOUBLE, 1);
+        assertEquals(-1, doubleG.invoke(null, 1.0, Double.POSITIVE_INFINITY));
+        assertEquals(-1, doubleG.invoke(null, 1.0, 2.0));
+        assertEquals(0, doubleG.invoke(null, 1.0, 1.0));
+        assertEquals(1, doubleG.invoke(null, 2.0, 1.0));
+        assertEquals(1, doubleG.invoke(null, 1.0, Double.NaN));
+        assertEquals(1, doubleG.invoke(null, Double.NaN, 1.0));
+        assertEquals(1, doubleG.invoke(null, Double.NaN, Double.NaN));
+        assertEquals(1, doubleG.invoke(null, Double.NaN, Double.POSITIVE_INFINITY));
+
+        Method doubleL = floatingPointCompareMethod(Type.DOUBLE, -1);
+        assertEquals(-1, doubleL.invoke(null, 1.0, Double.POSITIVE_INFINITY));
+        assertEquals(-1, doubleL.invoke(null, 1.0, 2.0));
+        assertEquals(0, doubleL.invoke(null, 1.0, 1.0));
+        assertEquals(1, doubleL.invoke(null, 2.0, 1.0));
+        assertEquals(-1, doubleL.invoke(null, 1.0, Double.NaN));
+        assertEquals(-1, doubleL.invoke(null, Double.NaN, 1.0));
+        assertEquals(-1, doubleL.invoke(null, Double.NaN, Double.NaN));
+        assertEquals(-1, doubleL.invoke(null, Double.NaN, Double.POSITIVE_INFINITY));
+    }
+
+    private <T extends Number> Method floatingPointCompareMethod(
+            Type<T> valueType, int nanValue) throws Exception {
+        /*
+         * public static int call(float a, float b) {
+         *     int result = a <=> b;
+         *     return result;
+         * }
+         */
+        reset();
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", valueType, valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<T> localA = code.getParameter(0, valueType);
+        Local<T> localB = code.getParameter(1, valueType);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        code.compare(localA, localB, localResult, nanValue);
+        code.returnValue(localResult);
+        return getMethod();
+    }
+
+    public void testLongCompare() throws Exception {
+        /*
+         * public static int call(long a, long b) {
+         *   int result = a <=> b;
+         *   return result;
+         * }
+         */
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.LONG, Type.LONG);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Long> localA = code.getParameter(0, Type.LONG);
+        Local<Long> localB = code.getParameter(1, Type.LONG);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        code.compare(localA, localB, localResult);
+        code.returnValue(localResult);
+
+        Method method = getMethod();
+        assertEquals(0, method.invoke(null, Long.MIN_VALUE, Long.MIN_VALUE));
+        assertEquals(-1, method.invoke(null, Long.MIN_VALUE, 0));
+        assertEquals(-1, method.invoke(null, Long.MIN_VALUE, Long.MAX_VALUE));
+        assertEquals(1, method.invoke(null, 0, Long.MIN_VALUE));
+        assertEquals(0, method.invoke(null, 0, 0));
+        assertEquals(-1, method.invoke(null, 0, Long.MAX_VALUE));
+        assertEquals(1, method.invoke(null, Long.MAX_VALUE, Long.MIN_VALUE));
+        assertEquals(1, method.invoke(null, Long.MAX_VALUE, 0));
+        assertEquals(0, method.invoke(null, Long.MAX_VALUE, Long.MAX_VALUE));
+    }
+
+    public void testArrayLength() throws Exception {
+        Method booleanArrayLength = arrayLengthMethod(BOOLEAN_ARRAY);
+        assertEquals(0, booleanArrayLength.invoke(null, new Object[] { new boolean[0] }));
+        assertEquals(5, booleanArrayLength.invoke(null, new Object[] { new boolean[5] }));
+
+        Method intArrayLength = arrayLengthMethod(INT_ARRAY);
+        assertEquals(0, intArrayLength.invoke(null, new Object[] { new int[0] }));
+        assertEquals(5, intArrayLength.invoke(null, new Object[] { new int[5] }));
+
+        Method longArrayLength = arrayLengthMethod(LONG_ARRAY);
+        assertEquals(0, longArrayLength.invoke(null, new Object[] { new long[0] }));
+        assertEquals(5, longArrayLength.invoke(null, new Object[] { new long[5] }));
+
+        Method objectArrayLength = arrayLengthMethod(OBJECT_ARRAY);
+        assertEquals(0, objectArrayLength.invoke(null, new Object[] { new Object[0] }));
+        assertEquals(5, objectArrayLength.invoke(null, new Object[] { new Object[5] }));
+
+        Method long2dArrayLength = arrayLengthMethod(LONG_2D_ARRAY);
+        assertEquals(0, long2dArrayLength.invoke(null, new Object[] { new long[0][0] }));
+        assertEquals(5, long2dArrayLength.invoke(null, new Object[] { new long[5][10] }));
+    }
+
+    private <T> Method arrayLengthMethod(Type<T> valueType) throws Exception {
+        /*
+         * public static int call(long[] array) {
+         *   int result = array.length;
+         *   return result;
+         * }
+         */
+        reset();
+        MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", valueType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<T> localArray = code.getParameter(0, valueType);
+        Local<Integer> localResult = code.newLocal(Type.INT);
+        code.arrayLength(localArray, localResult);
+        code.returnValue(localResult);
+        return getMethod();
+    }
+
+    public void testNewArray() throws Exception {
+        Method newBooleanArray = newArrayMethod(BOOLEAN_ARRAY);
+        assertEquals("[]", Arrays.toString((boolean[]) newBooleanArray.invoke(null, 0)));
+        assertEquals("[false, false, false]",
+                Arrays.toString((boolean[]) newBooleanArray.invoke(null, 3)));
+
+        Method newIntArray = newArrayMethod(INT_ARRAY);
+        assertEquals("[]", Arrays.toString((int[]) newIntArray.invoke(null, 0)));
+        assertEquals("[0, 0, 0]", Arrays.toString((int[]) newIntArray.invoke(null, 3)));
+
+        Method newLongArray = newArrayMethod(LONG_ARRAY);
+        assertEquals("[]", Arrays.toString((long[]) newLongArray.invoke(null, 0)));
+        assertEquals("[0, 0, 0]", Arrays.toString((long[]) newLongArray.invoke(null, 3)));
+
+        Method newObjectArray = newArrayMethod(OBJECT_ARRAY);
+        assertEquals("[]", Arrays.toString((Object[]) newObjectArray.invoke(null, 0)));
+        assertEquals("[null, null, null]",
+                Arrays.toString((Object[]) newObjectArray.invoke(null, 3)));
+
+        Method new2dLongArray = newArrayMethod(LONG_2D_ARRAY);
+        assertEquals("[]", Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 0)));
+        assertEquals("[null, null, null]",
+                Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 3)));
+    }
+
+    private <T> Method newArrayMethod(Type<T> valueType) throws Exception {
+        /*
+         * public static long[] call(int length) {
+         *   long[] result = new long[length];
+         *   return result;
+         * }
+         */
+        reset();
+        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", Type.INT);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<Integer> localLength = code.getParameter(0, Type.INT);
+        Local<T> localResult = code.newLocal(valueType);
+        code.newArray(localLength, localResult);
+        code.returnValue(localResult);
+        return getMethod();
+    }
+
+    public void testReadAndWriteArray() throws Exception {
+        Method swapBooleanArray = arraySwapMethod(BOOLEAN_ARRAY, Type.BOOLEAN);
+        boolean[] booleans = new boolean[3];
+        assertEquals(false, swapBooleanArray.invoke(null, booleans, 1, true));
+        assertEquals("[false, true, false]", Arrays.toString(booleans));
+
+        Method swapIntArray = arraySwapMethod(INT_ARRAY, Type.INT);
+        int[] ints = new int[3];
+        assertEquals(0, swapIntArray.invoke(null, ints, 1, 5));
+        assertEquals("[0, 5, 0]", Arrays.toString(ints));
+
+        Method swapLongArray = arraySwapMethod(LONG_ARRAY, Type.LONG);
+        long[] longs = new long[3];
+        assertEquals(0L, swapLongArray.invoke(null, longs, 1, 6L));
+        assertEquals("[0, 6, 0]", Arrays.toString(longs));
+
+        Method swapObjectArray = arraySwapMethod(OBJECT_ARRAY, Type.OBJECT);
+        Object[] objects = new Object[3];
+        assertEquals(null, swapObjectArray.invoke(null, objects, 1, "X"));
+        assertEquals("[null, X, null]", Arrays.toString(objects));
+
+        Method swapLong2dArray = arraySwapMethod(LONG_2D_ARRAY, LONG_ARRAY);
+        long[][] longs2d = new long[3][];
+        assertEquals(null, swapLong2dArray.invoke(null, longs2d, 1, new long[] { 7 }));
+        assertEquals("[null, [7], null]", Arrays.deepToString(longs2d));
+    }
+
+    private <A, T> Method arraySwapMethod(Type<A> arrayType, Type<T> singleType)
+            throws Exception {
+        /*
+         * public static long swap(long[] array, int index, long newValue) {
+         *   long result = array[index];
+         *   array[index] = newValue;
+         *   return result;
+         * }
+         */
+        reset();
+        MethodId<?, T> methodId = GENERATED.getMethod(
+                singleType, "call", arrayType, Type.INT, singleType);
+        Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
+        Local<A> localArray = code.getParameter(0, arrayType);
+        Local<Integer> localIndex = code.getParameter(1, Type.INT);
+        Local<T> localNewValue = code.getParameter(2, singleType);
+        Local<T> localResult = code.newLocal(singleType);
+        code.aget(localArray, localIndex, localResult);
+        code.aput(localArray, localIndex, localNewValue);
+        code.returnValue(localResult);
+        return getMethod();
+    }
+
+    // TODO: fail if a label is unreachable (never navigated to)
+
+    // TODO: more strict type parameters: Integer on methods
+
+    // TODO: don't generate multiple times (?)
+
+    private void addDefaultConstructor() {
+        Code code = generator.declare(GENERATED.getConstructor(), ACC_PUBLIC | ACC_CONSTRUCTOR);
+        Local<?> thisRef = code.getThis(GENERATED);
+        code.invokeDirect(Type.OBJECT.getConstructor(), null, thisRef);
+        code.returnVoid();
+    }
+
+    /**
+     * Returns the generated method.
+     */
+    private Method getMethod() throws Exception {
+        Class<?> generated = loadAndGenerate();
+        for (Method method : generated.getMethods()) {
+            if (method.getName().equals("call")) {
+                return method;
+            }
+        }
+        throw new IllegalStateException("no call() method");
+    }
+
+    private Class<?> loadAndGenerate() throws IOException, ClassNotFoundException {
+        return generator.load(DexGeneratorTest.class.getClassLoader()).loadClass("Generated");
+    }
+}
diff --git a/dx/junit-tests/com/android/dx/gen/TypeTest.java b/dx/junit-tests/com/android/dx/gen/TypeTest.java
new file mode 100644
index 0000000..c2f4f04
--- /dev/null
+++ b/dx/junit-tests/com/android/dx/gen/TypeTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import junit.framework.TestCase;
+
+public final class TypeTest extends TestCase {
+
+    private final DexGenerator generator = new DexGenerator();
+
+    public void testGetType() {
+        assertEquals("Ljava/lang/String;", Type.get(String.class).getName());
+        assertEquals("[Ljava/lang/String;", Type.get(String[].class).getName());
+        assertEquals("[[Ljava/lang/String;", Type.get(String[][].class).getName());
+        assertEquals("I", Type.get(int.class).getName());
+        assertEquals("[I", Type.get(int[].class).getName());
+        assertEquals("[[I", Type.get(int[][].class).getName());
+    }
+}
diff --git a/dx/src/Android.mk b/dx/src/Android.mk
new file mode 100644
index 0000000..80d1b85
--- /dev/null
+++ b/dx/src/Android.mk
@@ -0,0 +1,34 @@
+# Copyright 2006 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS),)
+
+# dx java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= dx
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
+endif # TARGET_BUILD_APPS
+
+# the documentation
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files) $(call all-subdir-html-files)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= dx
+LOCAL_DROIDDOC_OPTIONS := -hidden
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_IS_HOST_MODULE := true
+
+include $(BUILD_DROIDDOC)
diff --git a/dx/src/com/android/dx/Version.java b/dx/src/com/android/dx/Version.java
new file mode 100644
index 0000000..130025a
--- /dev/null
+++ b/dx/src/com/android/dx/Version.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx;
+
+/**
+ * Version number for dx.
+ */
+public class Version {
+    /** {@code non-null;} version string */
+    public static final String VERSION = "1.7";
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
new file mode 100644
index 0000000..fe0b3ab
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.Constant;
+
+/**
+ * Attribute class for {@code AnnotationDefault} attributes.
+ */
+public final class AttAnnotationDefault extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "AnnotationDefault";
+
+    /** {@code non-null;} the annotation default value */
+    private final Constant value;
+
+    /** {@code >= 0;} attribute data length in the original classfile (not
+     * including the attribute header) */
+    private final int byteLength;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param value {@code non-null;} the annotation default value
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public AttAnnotationDefault(Constant value, int byteLength) {
+        super(ATTRIBUTE_NAME);
+
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        this.value = value;
+        this.byteLength = byteLength;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        // Add six for the standard attribute header.
+        return byteLength + 6;
+    }
+
+    /**
+     * Gets the annotation default 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
new file mode 100644
index 0000000..8d34c69
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttCode.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.cf.code.ByteCatchList;
+import com.android.dx.cf.code.BytecodeArray;
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Attribute class for standard {@code Code} attributes.
+ */
+public final class AttCode extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "Code";
+
+    /** {@code >= 0;} the stack size */
+    private final int maxStack;
+
+    /** {@code >= 0;} the number of locals */
+    private final int maxLocals;
+
+    /** {@code non-null;} array containing the bytecode per se */
+    private final BytecodeArray code;
+
+    /** {@code non-null;} the exception table */
+    private final ByteCatchList catches;
+
+    /** {@code non-null;} the associated list of attributes */
+    private final AttributeList attributes;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param maxStack {@code >= 0;} the stack size
+     * @param maxLocals {@code >= 0;} the number of locals
+     * @param code {@code non-null;} array containing the bytecode per se
+     * @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) {
+        super(ATTRIBUTE_NAME);
+
+        if (maxStack < 0) {
+            throw new IllegalArgumentException("maxStack < 0");
+        }
+
+        if (maxLocals < 0) {
+            throw new IllegalArgumentException("maxLocals < 0");
+        }
+
+        if (code == null) {
+            throw new NullPointerException("code == null");
+        }
+
+        try {
+            if (catches.isMutable()) {
+                throw new MutabilityException("catches.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("catches == null");
+        }
+
+        try {
+            if (attributes.isMutable()) {
+                throw new MutabilityException("attributes.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("attributes == null");
+        }
+
+        this.maxStack = maxStack;
+        this.maxLocals = maxLocals;
+        this.code = code;
+        this.catches = catches;
+        this.attributes = attributes;
+    }
+
+    public int byteLength() {
+        return 10 + code.byteLength() + catches.byteLength() +
+            attributes.byteLength();
+    }
+
+    /**
+     * Gets the maximum stack size.
+     *
+     * @return {@code >= 0;} the maximum stack size
+     */
+    public int getMaxStack() {
+        return maxStack;
+    }
+
+    /**
+     * Gets the number of locals.
+     *
+     * @return {@code >= 0;} the number of locals
+     */
+    public int getMaxLocals() {
+        return maxLocals;
+    }
+
+    /**
+     * Gets the bytecode array.
+     *
+     * @return {@code non-null;} the bytecode array
+     */
+    public BytecodeArray getCode() {
+        return code;
+    }
+
+    /**
+     * Gets the exception table.
+     *
+     * @return {@code non-null;} the exception table
+     */
+    public ByteCatchList getCatches() {
+        return catches;
+    }
+
+    /**
+     * Gets the associated 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
new file mode 100644
index 0000000..aa6d1b3
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.TypedConstant;
+
+/**
+ * Attribute class for standard {@code ConstantValue} attributes.
+ */
+public final class AttConstantValue extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "ConstantValue";
+
+    /** {@code non-null;} the constant value */
+    private final TypedConstant constantValue;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param constantValue {@code non-null;} the constant value, which must
+     * be an instance of one of: {@code CstString},
+     * {@code CstInteger}, {@code CstLong},
+     * {@code CstFloat}, or {@code CstDouble}
+     */
+    public AttConstantValue(TypedConstant constantValue) {
+        super(ATTRIBUTE_NAME);
+
+        if (!((constantValue instanceof CstString) ||
+               (constantValue instanceof CstInteger) ||
+               (constantValue instanceof CstLong) ||
+               (constantValue instanceof CstFloat) ||
+               (constantValue instanceof CstDouble))) {
+            if (constantValue == null) {
+                throw new NullPointerException("constantValue == null");
+            }
+            throw new IllegalArgumentException("bad type for constantValue");
+        }
+
+        this.constantValue = constantValue;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8;
+    }
+
+    /**
+     * Gets the constant value of this instance. The returned value
+     * is an instance of one of: {@code CstString},
+     * {@code CstInteger}, {@code CstLong},
+     * {@code CstFloat}, or {@code CstDouble}.
+     *
+     * @return {@code non-null;} the constant value
+     */
+    public TypedConstant getConstantValue() {
+        return constantValue;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttDeprecated.java b/dx/src/com/android/dx/cf/attrib/AttDeprecated.java
new file mode 100644
index 0000000..d440aae
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttDeprecated.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+/**
+ * Attribute class for standard {@code Deprecated} attributes.
+ */
+public final class AttDeprecated extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "Deprecated";
+
+    /**
+     * Constructs an instance.
+     */
+    public AttDeprecated() {
+        super(ATTRIBUTE_NAME);
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 6;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
new file mode 100644
index 0000000..6717e15
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+
+/**
+ * Attribute class for standards-track {@code EnclosingMethod}
+ * attributes.
+ */
+public final class AttEnclosingMethod extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "EnclosingMethod";
+
+    /** {@code non-null;} the innermost enclosing class */
+    private final CstType type;
+
+    /** {@code null-ok;} the name-and-type of the innermost enclosing method, if any */
+    private final CstNat method;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the innermost enclosing class
+     * @param method {@code null-ok;} the name-and-type of the innermost enclosing
+     * method, if any
+     */
+    public AttEnclosingMethod(CstType type, CstNat method) {
+        super(ATTRIBUTE_NAME);
+
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        this.type = type;
+        this.method = method;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 10;
+    }
+
+    /**
+     * Gets the innermost enclosing class.
+     *
+     * @return {@code non-null;} the innermost enclosing class
+     */
+    public CstType getEnclosingClass() {
+        return type;
+    }
+
+    /**
+     * Gets the name-and-type of the innermost enclosing method, if
+     * any.
+     *
+     * @return {@code null-ok;} the name-and-type of the innermost enclosing
+     * method, if any
+     */
+    public CstNat getMethod() {
+        return method;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttExceptions.java b/dx/src/com/android/dx/cf/attrib/AttExceptions.java
new file mode 100644
index 0000000..a17e009
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttExceptions.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Attribute class for standard {@code Exceptions} attributes.
+ */
+public final class AttExceptions extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "Exceptions";
+
+    /** {@code non-null;} list of exception classes */
+    private final TypeList exceptions;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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);
+
+        try {
+            if (exceptions.isMutable()) {
+                throw new MutabilityException("exceptions.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("exceptions == null");
+        }
+
+        this.exceptions = exceptions;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8 + exceptions.size() * 2;
+    }
+
+    /**
+     * Gets the list of classes associated with this instance. In
+     * general, these classes are not pre-verified to be subclasses of
+     * {@code Throwable}.
+     *
+     * @return {@code non-null;} the list of classes
+     */
+    public TypeList getExceptions() {
+        return exceptions;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
new file mode 100644
index 0000000..77a4b08
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Attribute class for standard {@code InnerClasses} attributes.
+ */
+public final class AttInnerClasses extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "InnerClasses";
+
+    /** {@code non-null;} list of inner class entries */
+    private final InnerClassList innerClasses;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param innerClasses {@code non-null;} list of inner class entries
+     */
+    public AttInnerClasses(InnerClassList innerClasses) {
+        super(ATTRIBUTE_NAME);
+
+        try {
+            if (innerClasses.isMutable()) {
+                throw new MutabilityException("innerClasses.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("innerClasses == null");
+        }
+
+        this.innerClasses = innerClasses;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8 + innerClasses.size() * 8;
+    }
+
+    /**
+     * Gets the list of "inner class" entries associated with this instance.
+     *
+     * @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
new file mode 100644
index 0000000..5eac8cb
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.cf.code.LineNumberList;
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Attribute class for standard {@code LineNumberTable} attributes.
+ */
+public final class AttLineNumberTable extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "LineNumberTable";
+
+    /** {@code non-null;} list of line number entries */
+    private final LineNumberList lineNumbers;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param lineNumbers {@code non-null;} list of line number entries
+     */
+    public AttLineNumberTable(LineNumberList lineNumbers) {
+        super(ATTRIBUTE_NAME);
+
+        try {
+            if (lineNumbers.isMutable()) {
+                throw new MutabilityException("lineNumbers.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("lineNumbers == null");
+        }
+
+        this.lineNumbers = lineNumbers;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8 + 4 * lineNumbers.size();
+    }
+
+    /**
+     * Gets the list of "line number" entries associated with this instance.
+     *
+     * @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
new file mode 100644
index 0000000..1d2b4aa
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.cf.code.LocalVariableList;
+
+/**
+ * Attribute class for standard {@code LocalVariableTable} attributes.
+ */
+public final class AttLocalVariableTable extends BaseLocalVariables {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "LocalVariableTable";
+
+    /**
+     * Constructs an instance.
+     *
+     * @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
new file mode 100644
index 0000000..2520bf6
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.cf.code.LocalVariableList;
+
+/**
+ * Attribute class for standard {@code LocalVariableTypeTable} attributes.
+ */
+public final class AttLocalVariableTypeTable extends BaseLocalVariables {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "LocalVariableTypeTable";
+
+    /**
+     * Constructs an instance.
+     *
+     * @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
new file mode 100644
index 0000000..d3afe27
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.annotation.Annotations;
+
+/**
+ * Attribute class for standard {@code RuntimeInvisibleAnnotations}
+ * attributes.
+ */
+public final class AttRuntimeInvisibleAnnotations extends BaseAnnotations {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "RuntimeInvisibleAnnotations";
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} the list of annotations
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public AttRuntimeInvisibleAnnotations(Annotations annotations,
+            int byteLength) {
+        super(ATTRIBUTE_NAME, annotations, byteLength);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
new file mode 100644
index 0000000..c9c5136
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.annotation.AnnotationsList;
+
+/**
+ * Attribute class for standard
+ * {@code RuntimeInvisibleParameterAnnotations} attributes.
+ */
+public final class AttRuntimeInvisibleParameterAnnotations
+        extends BaseParameterAnnotations {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME =
+        "RuntimeInvisibleParameterAnnotations";
+
+    /**
+     * Constructs an instance.
+     *
+     * @param parameterAnnotations {@code non-null;} the parameter annotations
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public AttRuntimeInvisibleParameterAnnotations(
+            AnnotationsList parameterAnnotations, int byteLength) {
+        super(ATTRIBUTE_NAME, parameterAnnotations, byteLength);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
new file mode 100644
index 0000000..a6a640d
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.annotation.Annotations;
+
+/**
+ * Attribute class for standard {@code RuntimeVisibleAnnotations}
+ * attributes.
+ */
+public final class AttRuntimeVisibleAnnotations extends BaseAnnotations {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "RuntimeVisibleAnnotations";
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} the list of annotations
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public AttRuntimeVisibleAnnotations(Annotations annotations,
+            int byteLength) {
+        super(ATTRIBUTE_NAME, annotations, byteLength);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
new file mode 100644
index 0000000..177eb4c
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.annotation.AnnotationsList;
+
+/**
+ * Attribute class for standard {@code RuntimeVisibleParameterAnnotations}
+ * attributes.
+ */
+public final class AttRuntimeVisibleParameterAnnotations
+        extends BaseParameterAnnotations {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME =
+        "RuntimeVisibleParameterAnnotations";
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} the parameter annotations
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public AttRuntimeVisibleParameterAnnotations(
+            AnnotationsList annotations, int byteLength) {
+        super(ATTRIBUTE_NAME, annotations, byteLength);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/AttSignature.java b/dx/src/com/android/dx/cf/attrib/AttSignature.java
new file mode 100644
index 0000000..52def9c
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttSignature.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.CstString;
+
+/**
+ * Attribute class for standards-track {@code Signature} attributes.
+ */
+public final class AttSignature extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "Signature";
+
+    /** {@code non-null;} the signature string */
+    private final CstString signature;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param signature {@code non-null;} the signature string
+     */
+    public AttSignature(CstString signature) {
+        super(ATTRIBUTE_NAME);
+
+        if (signature == null) {
+            throw new NullPointerException("signature == null");
+        }
+
+        this.signature = signature;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8;
+    }
+
+    /**
+     * Gets the signature string.
+     *
+     * @return {@code non-null;} the signature string
+     */
+    public CstString 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
new file mode 100644
index 0000000..cc19d27
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.CstString;
+
+/**
+ * Attribute class for standard {@code SourceFile} attributes.
+ */
+public final class AttSourceFile extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "SourceFile";
+
+    /** {@code non-null;} name of the source file */
+    private final CstString sourceFile;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param sourceFile {@code non-null;} the name of the source file
+     */
+    public AttSourceFile(CstString sourceFile) {
+        super(ATTRIBUTE_NAME);
+
+        if (sourceFile == null) {
+            throw new NullPointerException("sourceFile == null");
+        }
+
+        this.sourceFile = sourceFile;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 8;
+    }
+
+    /**
+     * Gets the source file name of this instance.
+     *
+     * @return {@code non-null;} the source file
+     */
+    public CstString 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
new file mode 100644
index 0000000..e3841eb
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttSynthetic.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+/**
+ * Attribute class for standard {@code Synthetic} attributes.
+ */
+public final class AttSynthetic extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "Synthetic";
+
+    /**
+     * Constructs an instance.
+     */
+    public AttSynthetic() {
+        super(ATTRIBUTE_NAME);
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return 6;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
new file mode 100644
index 0000000..bc138af
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Base class for annotations attributes.
+ */
+public abstract class BaseAnnotations extends BaseAttribute {
+    /** {@code non-null;} list of annotations */
+    private final Annotations annotations;
+
+    /** {@code >= 0;} attribute data length in the original classfile (not
+     * including the attribute header) */
+    private final int byteLength;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param attributeName {@code non-null;} the name of the attribute
+     * @param annotations {@code non-null;} the list of annotations
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public BaseAnnotations(String attributeName, Annotations annotations,
+            int byteLength) {
+        super(attributeName);
+
+        try {
+            if (annotations.isMutable()) {
+                throw new MutabilityException("annotations.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.annotations = annotations;
+        this.byteLength = byteLength;
+    }
+
+    /** {@inheritDoc} */
+    public final int byteLength() {
+        // Add six for the standard attribute header.
+        return byteLength + 6;
+    }
+
+    /**
+     * Gets the list of annotations associated with this instance.
+     *
+     * @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
new file mode 100644
index 0000000..9961725
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.cf.iface.Attribute;
+
+/**
+ * Base implementation of {@link Attribute}, which directly stores
+ * the attribute name but leaves the rest up to subclasses.
+ */
+public abstract class BaseAttribute implements Attribute {
+    /** {@code non-null;} attribute name */
+    private final String name;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param name {@code non-null;} attribute name
+     */
+    public BaseAttribute(String name) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
new file mode 100644
index 0000000..27cd6fb
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.cf.code.LocalVariableList;
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Base attribute class for standard {@code LocalVariableTable}
+ * and {@code LocalVariableTypeTable} attributes.
+ */
+public abstract class BaseLocalVariables extends BaseAttribute {
+    /** {@code non-null;} list of local variable entries */
+    private final LocalVariableList localVariables;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param name {@code non-null;} attribute name
+     * @param localVariables {@code non-null;} list of local variable entries
+     */
+    public BaseLocalVariables(String name,
+            LocalVariableList localVariables) {
+        super(name);
+
+        try {
+            if (localVariables.isMutable()) {
+                throw new MutabilityException("localVariables.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("localVariables == null");
+        }
+
+        this.localVariables = localVariables;
+    }
+
+    /** {@inheritDoc} */
+    public final int byteLength() {
+        return 8 + localVariables.size() * 10;
+    }
+
+    /**
+     * Gets the list of "local variable" entries associated with this instance.
+     *
+     * @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
new file mode 100644
index 0000000..791f8cd
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.util.MutabilityException;
+
+/**
+ * Base class for parameter annotation list attributes.
+ */
+public abstract class BaseParameterAnnotations extends BaseAttribute {
+    /** {@code non-null;} list of annotations */
+    private final AnnotationsList parameterAnnotations;
+
+    /** {@code >= 0;} attribute data length in the original classfile (not
+     * including the attribute header) */
+    private final int byteLength;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param attributeName {@code non-null;} the name of the attribute
+     * @param parameterAnnotations {@code non-null;} the annotations
+     * @param byteLength {@code >= 0;} attribute data length in the original
+     * classfile (not including the attribute header)
+     */
+    public BaseParameterAnnotations(String attributeName,
+            AnnotationsList parameterAnnotations, int byteLength) {
+        super(attributeName);
+
+        try {
+            if (parameterAnnotations.isMutable()) {
+                throw new MutabilityException(
+                        "parameterAnnotations.isMutable()");
+            }
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("parameterAnnotations == null");
+        }
+
+        this.parameterAnnotations = parameterAnnotations;
+        this.byteLength = byteLength;
+    }
+
+    /** {@inheritDoc} */
+    public final int byteLength() {
+        // Add six for the standard attribute header.
+        return byteLength + 6;
+    }
+
+    /**
+     * Gets the list of annotation lists associated with this instance.
+     *
+     * @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
new file mode 100644
index 0000000..830118c
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/InnerClassList.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * List of "inner class" entries, which are the contents of
+ * {@code InnerClasses} attributes.
+ */
+public final class InnerClassList extends FixedSizeList {
+    /**
+     * Constructs an instance.
+     *
+     * @param count the number of elements to be in the list of inner classes
+     */
+    public InnerClassList(int count) {
+        super(count);
+    }
+
+    /**
+     * Gets 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);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @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 {@code null-ok;} original simple name of this class,
+     * if not anonymous
+     * @param accessFlags original declared access flags
+     */
+    public void set(int n, CstType innerClass, CstType outerClass,
+                    CstString innerName, int accessFlags) {
+        set0(n, new Item(innerClass, outerClass, innerName, accessFlags));
+    }
+
+    /**
+     * Item in an inner classes list.
+     */
+    public static class Item {
+        /** {@code non-null;} class this item refers to */
+        private final CstType innerClass;
+
+        /** {@code null-ok;} outer class that this class is a member of, if any */
+        private final CstType outerClass;
+
+        /** {@code null-ok;} original simple name of this class, if not anonymous */
+        private final CstString innerName;
+
+        /** original declared access flags */
+        private final int accessFlags;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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 {@code null-ok;} original simple name of this
+         * class, if not anonymous
+         * @param accessFlags original declared access flags
+         */
+        public Item(CstType innerClass, CstType outerClass,
+                    CstString innerName, int accessFlags) {
+            if (innerClass == null) {
+                throw new NullPointerException("innerClass == null");
+            }
+
+            this.innerClass = innerClass;
+            this.outerClass = outerClass;
+            this.innerName = innerName;
+            this.accessFlags = accessFlags;
+        }
+
+        /**
+         * Gets the class this item refers to.
+         *
+         * @return {@code non-null;} the class
+         */
+        public CstType getInnerClass() {
+            return innerClass;
+        }
+
+        /**
+         * Gets the outer class that this item's class is a member of, if any.
+         *
+         * @return {@code null-ok;} the class
+         */
+        public CstType getOuterClass() {
+            return outerClass;
+        }
+
+        /**
+         * Gets the original name of this item's class, if not anonymous.
+         *
+         * @return {@code null-ok;} the name
+         */
+        public CstString getInnerName() {
+            return innerName;
+        }
+
+        /**
+         * Gets the original declared access flags.
+         *
+         * @return the access flags
+         */
+        public int getAccessFlags() {
+            return accessFlags;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/RawAttribute.java b/dx/src/com/android/dx/cf/attrib/RawAttribute.java
new file mode 100644
index 0000000..e905dd1
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/RawAttribute.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.attrib;
+
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.util.ByteArray;
+
+/**
+ * Raw attribute, for holding onto attributes that are unrecognized.
+ */
+public final class RawAttribute extends BaseAttribute {
+    /** {@code non-null;} attribute data */
+    private final ByteArray data;
+
+    /**
+     * {@code null-ok;} constant pool to use for resolution of cpis in {@link
+     * #data}
+     */
+    private final ConstantPool pool;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param name {@code non-null;} attribute name
+     * @param data {@code non-null;} attribute data
+     * @param pool {@code null-ok;} constant pool to use for cpi resolution
+     */
+    public RawAttribute(String name, ByteArray data, ConstantPool pool) {
+        super(name);
+
+        if (data == null) {
+            throw new NullPointerException("data == null");
+        }
+
+        this.data = data;
+        this.pool = pool;
+    }
+
+    /**
+     * Constructs an instance from a sub-array of a {@link ByteArray}.
+     *
+     * @param name {@code non-null;} attribute name
+     * @param data {@code non-null;} array containing the attribute data
+     * @param offset offset in {@code data} to the attribute data
+     * @param length length of the attribute data, in bytes
+     * @param pool {@code null-ok;} constant pool to use for cpi resolution
+     */
+    public RawAttribute(String name, ByteArray data, int offset,
+                        int length, ConstantPool pool) {
+        this(name, data.slice(offset, offset + length), pool);
+    }
+
+    /**
+     * Get the raw data of the attribute.
+     *
+     * @return {@code non-null;} the data
+     */
+    public ByteArray getData() {
+        return data;
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        return data.size() + 6;
+    }
+
+    /**
+     * Gets the constant pool to use for cpi resolution, if any. It
+     * presumably came from the class file that this attribute came
+     * from.
+     *
+     * @return {@code null-ok;} the constant pool
+     */
+    public ConstantPool getPool() {
+        return pool;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/attrib/package.html b/dx/src/com/android/dx/cf/attrib/package.html
new file mode 100644
index 0000000..8125079
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/package.html
@@ -0,0 +1,11 @@
+<body>
+<p>Implementation of containers and utilities for all the standard Java
+attribute types.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.cf.iface</code></li>
+<li><code>com.android.dx.rop.pool</code></li>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/cf/code/BaseMachine.java b/dx/src/com/android/dx/cf/code/BaseMachine.java
new file mode 100644
index 0000000..c56dd3e
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/BaseMachine.java
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import java.util.ArrayList;
+
+/**
+ * Base implementation of {@link Machine}.
+ *
+ * <p><b>Note:</b> For the most part, the documentation for this class
+ * ignores the distinction between {@link Type} and {@link
+ * TypeBearer}.</p>
+ */
+public abstract class BaseMachine implements Machine {
+    /* {@code non-null;} the prototype for the associated method */
+    private final Prototype prototype;
+
+    /** {@code non-null;} primary arguments */
+    private TypeBearer[] args;
+
+    /** {@code >= 0;} number of primary arguments */
+    private int argCount;
+
+    /** {@code null-ok;} type of the operation, if salient */
+    private Type auxType;
+
+    /** auxiliary {@code int} argument */
+    private int auxInt;
+
+    /** {@code null-ok;} auxiliary constant argument */
+    private Constant auxCst;
+
+    /** auxiliary branch target argument */
+    private int auxTarget;
+
+    /** {@code null-ok;} auxiliary switch cases argument */
+    private SwitchList auxCases;
+
+    /** {@code null-ok;} auxiliary initial value list for newarray */
+    private ArrayList<Constant> auxInitValues;
+
+    /** {@code >= -1;} last local accessed */
+    private int localIndex;
+
+    /** specifies if local has info in the local variable table */
+    private boolean localInfo;
+
+    /** {@code null-ok;} local target spec, if salient and calculated */
+    private RegisterSpec localTarget;
+
+    /** {@code non-null;} results */
+    private TypeBearer[] results;
+
+    /**
+     * {@code >= -1;} count of the results, or {@code -1} if no results
+     * have been set
+     */
+    private int resultCount;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param prototype {@code non-null;} the prototype for the
+     * associated method
+     */
+    public BaseMachine(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        this.prototype = prototype;
+        args = new TypeBearer[10];
+        results = new TypeBearer[6];
+        clearArgs();
+    }
+
+    /** {@inheritDoc} */
+    public Prototype getPrototype() {
+        return prototype;
+    }
+
+    /** {@inheritDoc} */
+    public final void clearArgs() {
+        argCount = 0;
+        auxType = null;
+        auxInt = 0;
+        auxCst = null;
+        auxTarget = 0;
+        auxCases = null;
+        auxInitValues = null;
+        localIndex = -1;
+        localInfo = false;
+        localTarget = null;
+        resultCount = -1;
+    }
+
+    /** {@inheritDoc} */
+    public final void popArgs(Frame frame, int count) {
+        ExecutionStack stack = frame.getStack();
+
+        clearArgs();
+
+        if (count > args.length) {
+            // Grow args, and add a little extra room to grow even more.
+            args = new TypeBearer[count + 10];
+        }
+
+        for (int i = count - 1; i >= 0; i--) {
+            args[i] = stack.pop();
+        }
+
+        argCount = count;
+    }
+
+    /** {@inheritDoc} */
+    public void popArgs(Frame frame, Prototype prototype) {
+        StdTypeList types = prototype.getParameterTypes();
+        int size = types.size();
+
+        // Use the above method to do the actual popping...
+        popArgs(frame, size);
+
+        // ...and then verify the popped types.
+
+        for (int i = 0; i < size; i++) {
+            if (! Merger.isPossiblyAssignableFrom(types.getType(i), args[i])) {
+                throw new SimException("at stack depth " + (size - 1 - i) +
+                        ", expected type " + types.getType(i).toHuman() +
+                        " but found " + args[i].getType().toHuman());
+            }
+        }
+    }
+
+    public final void popArgs(Frame frame, Type type) {
+        // Use the above method to do the actual popping...
+        popArgs(frame, 1);
+
+        // ...and then verify the popped type.
+        if (! Merger.isPossiblyAssignableFrom(type, args[0])) {
+            throw new SimException("expected type " + type.toHuman() +
+                    " but found " + args[0].getType().toHuman());
+        }
+    }
+
+    /** {@inheritDoc} */
+    public final void popArgs(Frame frame, Type type1, Type type2) {
+        // Use the above method to do the actual popping...
+        popArgs(frame, 2);
+
+        // ...and then verify the popped types.
+
+        if (! Merger.isPossiblyAssignableFrom(type1, args[0])) {
+            throw new SimException("expected type " + type1.toHuman() +
+                    " but found " + args[0].getType().toHuman());
+        }
+
+        if (! Merger.isPossiblyAssignableFrom(type2, args[1])) {
+            throw new SimException("expected type " + type2.toHuman() +
+                    " but found " + args[1].getType().toHuman());
+        }
+    }
+
+    /** {@inheritDoc} */
+    public final void popArgs(Frame frame, Type type1, Type type2,
+            Type type3) {
+        // Use the above method to do the actual popping...
+        popArgs(frame, 3);
+
+        // ...and then verify the popped types.
+
+        if (! Merger.isPossiblyAssignableFrom(type1, args[0])) {
+            throw new SimException("expected type " + type1.toHuman() +
+                    " but found " + args[0].getType().toHuman());
+        }
+
+        if (! Merger.isPossiblyAssignableFrom(type2, args[1])) {
+            throw new SimException("expected type " + type2.toHuman() +
+                    " but found " + args[1].getType().toHuman());
+        }
+
+        if (! Merger.isPossiblyAssignableFrom(type3, args[2])) {
+            throw new SimException("expected type " + type3.toHuman() +
+                    " but found " + args[2].getType().toHuman());
+        }
+    }
+
+    /** {@inheritDoc} */
+    public final void localArg(Frame frame, int idx) {
+        clearArgs();
+        args[0] = frame.getLocals().get(idx);
+        argCount = 1;
+        localIndex = idx;
+    }
+
+    /** {@inheritDoc} */
+    public final void localInfo(boolean local) {
+        localInfo = local;
+    }
+
+    /** {@inheritDoc} */
+    public final void auxType(Type type) {
+        auxType = type;
+    }
+
+    /** {@inheritDoc} */
+    public final void auxIntArg(int value) {
+        auxInt = value;
+    }
+
+    /** {@inheritDoc} */
+    public final void auxCstArg(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        auxCst = cst;
+    }
+
+    /** {@inheritDoc} */
+    public final void auxTargetArg(int target) {
+        auxTarget = target;
+    }
+
+    /** {@inheritDoc} */
+    public final void auxSwitchArg(SwitchList cases) {
+        if (cases == null) {
+            throw new NullPointerException("cases == null");
+        }
+
+        auxCases = cases;
+    }
+
+    /** {@inheritDoc} */
+    public final void auxInitValues(ArrayList<Constant> initValues) {
+        auxInitValues = initValues;
+    }
+
+    /** {@inheritDoc} */
+    public final void localTarget(int idx, Type type, LocalItem local) {
+        localTarget = RegisterSpec.makeLocalOptional(idx, type, local);
+    }
+
+    /**
+     * Gets the number of primary arguments.
+     *
+     * @return {@code >= 0;} the number of primary arguments
+     */
+    protected final int argCount() {
+        return argCount;
+    }
+
+    /**
+     * Gets the width of the arguments (where a category-2 value counts as
+     * two).
+     *
+     * @return {@code >= 0;} the argument width
+     */
+    protected final int argWidth() {
+        int result = 0;
+
+        for (int i = 0; i < argCount; i++) {
+            result += args[i].getType().getCategory();
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the {@code n}th primary argument.
+     *
+     * @param n {@code >= 0, < argCount();} which argument
+     * @return {@code non-null;} the indicated argument
+     */
+    protected final TypeBearer arg(int n) {
+        if (n >= argCount) {
+            throw new IllegalArgumentException("n >= argCount");
+        }
+
+        try {
+            return args[n];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("n < 0");
+        }
+    }
+
+    /**
+     * Gets the type auxiliary argument.
+     *
+     * @return {@code null-ok;} the salient type
+     */
+    protected final Type getAuxType() {
+        return auxType;
+    }
+
+    /**
+     * Gets the {@code int} auxiliary argument.
+     *
+     * @return the argument value
+     */
+    protected final int getAuxInt() {
+        return auxInt;
+    }
+
+    /**
+     * Gets the constant auxiliary argument.
+     *
+     * @return {@code null-ok;} the argument value
+     */
+    protected final Constant getAuxCst() {
+        return auxCst;
+    }
+
+    /**
+     * Gets the branch target auxiliary argument.
+     *
+     * @return the argument value
+     */
+    protected final int getAuxTarget() {
+        return auxTarget;
+    }
+
+    /**
+     * Gets the switch cases auxiliary argument.
+     *
+     * @return {@code null-ok;} the argument value
+     */
+    protected final SwitchList getAuxCases() {
+        return auxCases;
+    }
+
+    /**
+     * Gets the init values auxiliary argument.
+     *
+     * @return {@code null-ok;} the argument value
+     */
+    protected final ArrayList<Constant> getInitValues() {
+        return auxInitValues;
+    }
+    /**
+     * Gets the last local index accessed.
+     *
+     * @return {@code >= -1;} the salient local index or {@code -1} if none
+     * was set since the last time {@link #clearArgs} was called
+     */
+    protected final int getLocalIndex() {
+        return localIndex;
+    }
+
+    /**
+     * Gets whether the loaded local has info in the local variable table.
+     *
+     * @return {@code true} if local arg has info in the local variable table
+     */
+    protected final boolean getLocalInfo() {
+        return localInfo;
+    }
+
+    /**
+     * Gets the target local register spec of the current operation, if any.
+     * The local target spec is the combination of the values indicated
+     * by a previous call to {@link #localTarget} with the type of what
+     * should be the sole result set by a call to {@link #setResult} (or
+     * the combination {@link #clearResult} then {@link #addResult}.
+     *
+     * @param isMove {@code true} if the operation being performed on the
+     * local is a move. This will cause constant values to be propagated
+     * to the returned local
+     * @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
+     */
+    protected final RegisterSpec getLocalTarget(boolean isMove) {
+        if (localTarget == null) {
+            return null;
+        }
+
+        if (resultCount != 1) {
+            throw new SimException("local target with " +
+                    ((resultCount == 0) ? "no" : "multiple") + " results");
+        }
+
+        TypeBearer result = results[0];
+        Type resultType = result.getType();
+        Type localType = localTarget.getType();
+
+        if (resultType == localType) {
+            /*
+             * If this is to be a move operation and the result is a
+             * known value, make the returned localTarget embody that
+             * value.
+             */
+            if (isMove) {
+                return localTarget.withType(result);
+            } else {
+                return localTarget;
+            }
+        }
+
+        if (! Merger.isPossiblyAssignableFrom(localType, resultType)) {
+            // The result and local types are inconsistent. Complain!
+            throwLocalMismatch(resultType, localType);
+            return null;
+        }
+
+        if (localType == Type.OBJECT) {
+            /*
+             * The result type is more specific than the local type,
+             * so use that instead.
+             */
+            localTarget = localTarget.withType(result);
+        }
+
+        return localTarget;
+    }
+
+    /**
+     * Clears the results.
+     */
+    protected final void clearResult() {
+        resultCount = 0;
+    }
+
+    /**
+     * Sets the results list to be the given single value.
+     *
+     * <p><b>Note:</b> If there is more than one result value, the
+     * others may be added by using {@link #addResult}.</p>
+     *
+     * @param result {@code non-null;} result value
+     */
+    protected final void setResult(TypeBearer result) {
+        if (result == null) {
+            throw new NullPointerException("result == null");
+        }
+
+        results[0] = result;
+        resultCount = 1;
+    }
+
+    /**
+     * Adds an additional element to the list of results.
+     *
+     * @see #setResult
+     *
+     * @param result {@code non-null;} result value
+     */
+    protected final void addResult(TypeBearer result) {
+        if (result == null) {
+            throw new NullPointerException("result == null");
+        }
+
+        results[resultCount] = result;
+        resultCount++;
+    }
+
+    /**
+     * Gets the count of results. This throws an exception if results were
+     * never set. (Explicitly clearing the results counts as setting them.)
+     *
+     * @return {@code >= 0;} the count
+     */
+    protected final int resultCount() {
+        if (resultCount < 0) {
+            throw new SimException("results never set");
+        }
+
+        return resultCount;
+    }
+
+    /**
+     * Gets the width of the results (where a category-2 value counts as
+     * two).
+     *
+     * @return {@code >= 0;} the result width
+     */
+    protected final int resultWidth() {
+        int width = 0;
+
+        for (int i = 0; i < resultCount; i++) {
+            width += results[i].getType().getCategory();
+        }
+
+        return width;
+    }
+
+    /**
+     * Gets the {@code n}th 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) {
+            throw new IllegalArgumentException("n >= resultCount");
+        }
+
+        try {
+            return results[n];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("n < 0");
+        }
+    }
+
+    /**
+     * Stores the results of the latest operation into the given frame. If
+     * there is a local target (see {@link #localTarget}), then the sole
+     * result is stored to that target; otherwise any results are pushed
+     * onto the stack.
+     *
+     * @param frame {@code non-null;} frame to operate on
+     */
+    protected final void storeResults(Frame frame) {
+        if (resultCount < 0) {
+            throw new SimException("results never set");
+        }
+
+        if (resultCount == 0) {
+            // Nothing to do.
+            return;
+        }
+
+        if (localTarget != null) {
+            /*
+             * Note: getLocalTarget() doesn't necessarily return
+             * localTarget directly.
+             */
+            frame.getLocals().set(getLocalTarget(false));
+        } else {
+            ExecutionStack stack = frame.getStack();
+            for (int i = 0; i < resultCount; i++) {
+                if (localInfo) {
+                    stack.setLocal();
+                }
+                stack.push(results[i]);
+            }
+        }
+    }
+
+    /**
+     * Throws an exception that indicates a mismatch in local variable
+     * types.
+     *
+     * @param found {@code non-null;} the encountered type
+     * @param local {@code non-null;} the local variable's claimed type
+     */
+    public static void throwLocalMismatch(TypeBearer found,
+            TypeBearer local) {
+        throw new SimException("local variable type mismatch: " +
+                "attempt to set or access a value of type " +
+                found.toHuman() +
+                " using a local variable of type " +
+                local.toHuman() +
+                ". This is symptomatic of .class transformation tools " +
+                "that ignore local variable information.");
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/BasicBlocker.java b/dx/src/com/android/dx/cf/code/BasicBlocker.java
new file mode 100644
index 0000000..56d3991
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/BasicBlocker.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMemberRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Bits;
+import com.android.dx.util.IntList;
+import java.util.ArrayList;
+
+/**
+ * Utility that identifies basic blocks in bytecode.
+ */
+public final class BasicBlocker implements BytecodeArray.Visitor {
+    /** {@code non-null;} method being converted */
+    private final ConcreteMethod method;
+
+    /**
+     * {@code non-null;} work set; bits indicate offsets in need of
+     * examination
+     */
+    private final int[] workSet;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /**
+     * {@code non-null, sparse;} for each instruction offset to a throwing
+     * instruction, the list of exception handlers for that instruction
+     */
+    private final ByteCatchList[] catchLists;
+
+    /** offset of the previously parsed bytecode */
+    private int previousOffset;
+
+    /**
+     * Identifies and enumerates the basic blocks in the given method,
+     * returning a list of them. The returned list notably omits any
+     * definitely-dead code that is identified in the process.
+     *
+     * @param method {@code non-null;} method to convert
+     * @return {@code non-null;} list of basic blocks
+     */
+    public static ByteBlockList identifyBlocks(ConcreteMethod method) {
+        BasicBlocker bb = new BasicBlocker(method);
+
+        bb.doit();
+        return bb.getBlockList();
+    }
+
+    /**
+     * Constructs an instance. This class is not publicly instantiable; use
+     * {@link #identifyBlocks}.
+     *
+     * @param method {@code non-null;} method to convert
+     */
+    private BasicBlocker(ConcreteMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        this.method = method;
+
+        /*
+         * The "+1" below is so the idx-past-end is also valid,
+         * avoiding a special case, but without preventing
+         * flow-of-control falling past the end of the method from
+         * getting properly reported.
+         */
+        int sz = method.getCode().size() + 1;
+
+        workSet = Bits.makeBitSet(sz);
+        liveSet = Bits.makeBitSet(sz);
+        blockSet = Bits.makeBitSet(sz);
+        targetLists = new IntList[sz];
+        catchLists = new ByteCatchList[sz];
+        previousOffset = -1;
+    }
+
+    /*
+     * Note: These methods are defined implementation of the interface
+     * BytecodeArray.Visitor; since the class isn't publicly
+     * instantiable, no external code ever gets a chance to actually
+     * call these methods.
+     */
+
+    /** {@inheritDoc} */
+    public void visitInvalid(int opcode, int offset, int length) {
+        visitCommon(offset, length, true);
+    }
+
+    /** {@inheritDoc} */
+    public void visitNoArgs(int opcode, int offset, int length, Type type) {
+        switch (opcode) {
+            case ByteOps.IRETURN:
+            case ByteOps.RETURN: {
+                visitCommon(offset, length, false);
+                targetLists[offset] = IntList.EMPTY;
+                break;
+            }
+            case ByteOps.ATHROW: {
+                visitCommon(offset, length, false);
+                visitThrowing(offset, length, false);
+                break;
+            }
+            case ByteOps.IALOAD:
+            case ByteOps.LALOAD:
+            case ByteOps.FALOAD:
+            case ByteOps.DALOAD:
+            case ByteOps.AALOAD:
+            case ByteOps.BALOAD:
+            case ByteOps.CALOAD:
+            case ByteOps.SALOAD:
+            case ByteOps.IASTORE:
+            case ByteOps.LASTORE:
+            case ByteOps.FASTORE:
+            case ByteOps.DASTORE:
+            case ByteOps.AASTORE:
+            case ByteOps.BASTORE:
+            case ByteOps.CASTORE:
+            case ByteOps.SASTORE:
+            case ByteOps.ARRAYLENGTH:
+            case ByteOps.MONITORENTER:
+            case ByteOps.MONITOREXIT: {
+                /*
+                 * These instructions can all throw, so they have to end
+                 * the block they appear in (since throws are branches).
+                 */
+                visitCommon(offset, length, true);
+                visitThrowing(offset, length, true);
+                break;
+            }
+            case ByteOps.IDIV:
+            case ByteOps.IREM: {
+                /*
+                 * The int and long versions of division and remainder may
+                 * throw, but not the other types.
+                 */
+                visitCommon(offset, length, true);
+                if ((type == Type.INT) || (type == Type.LONG)) {
+                    visitThrowing(offset, length, true);
+                }
+                break;
+            }
+            default: {
+                visitCommon(offset, length, true);
+                break;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void visitLocal(int opcode, int offset, int length,
+            int idx, Type type, int value) {
+        if (opcode == ByteOps.RET) {
+            visitCommon(offset, length, false);
+            targetLists[offset] = IntList.EMPTY;
+        } else {
+            visitCommon(offset, length, true);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void visitConstant(int opcode, int offset, int length,
+            Constant cst, int value) {
+        visitCommon(offset, length, true);
+
+        if ((cst instanceof CstMemberRef) || (cst instanceof CstType) ||
+            (cst instanceof CstString)) {
+            /*
+             * Instructions with these sorts of constants have the
+             * possibility of throwing, so this instruction needs to
+             * end its block (since it can throw, and possible-throws
+             * are branch points).
+             */
+            visitThrowing(offset, length, true);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void visitBranch(int opcode, int offset, int length,
+            int target) {
+        switch (opcode) {
+            case ByteOps.GOTO: {
+                visitCommon(offset, length, false);
+                targetLists[offset] = IntList.makeImmutable(target);
+                break;
+            }
+            case ByteOps.JSR: {
+                /*
+                 * Each jsr is quarantined into a separate block (containing
+                 * only the jsr instruction) but is otherwise treated
+                 * as a conditional branch. (That is to say, both its
+                 * target and next instruction begin new blocks.)
+                 */
+                addWorkIfNecessary(offset, true);
+                // Fall through to next case...
+            }
+            default: {
+                int next = offset + length;
+                visitCommon(offset, length, true);
+                addWorkIfNecessary(next, true);
+                targetLists[offset] = IntList.makeImmutable(next, target);
+                break;
+            }
+        }
+
+        addWorkIfNecessary(target, true);
+    }
+
+    /** {@inheritDoc} */
+    public void visitSwitch(int opcode, int offset, int length,
+            SwitchList cases, int padding) {
+        visitCommon(offset, length, false);
+        addWorkIfNecessary(cases.getDefaultTarget(), true);
+
+        int sz = cases.size();
+        for (int i = 0; i < sz; i++) {
+            addWorkIfNecessary(cases.getTarget(i), true);
+        }
+
+        targetLists[offset] = cases.getTargets();
+    }
+
+    /** {@inheritDoc} */
+    public void visitNewarray(int offset, int length, CstType type,
+            ArrayList<Constant> intVals) {
+        visitCommon(offset, length, true);
+        visitThrowing(offset, length, true);
+    }
+
+    /**
+     * Extracts the list of basic blocks from the bit sets.
+     *
+     * @return {@code non-null;} the list of basic blocks
+     */
+    private ByteBlockList getBlockList() {
+        BytecodeArray bytes = method.getCode();
+        ByteBlock[] bbs = new ByteBlock[bytes.size()];
+        int count = 0;
+
+        for (int at = 0, next; /*at*/; at = next) {
+            next = Bits.findFirst(blockSet, at + 1);
+            if (next < 0) {
+                break;
+            }
+
+            if (Bits.get(liveSet, at)) {
+                /*
+                 * Search backward for the branch or throwing
+                 * instruction at the end of this block, if any. If
+                 * there isn't any, then "next" is the sole target.
+                 */
+                IntList targets = null;
+                int targetsAt = -1;
+                ByteCatchList blockCatches;
+
+                for (int i = next - 1; i >= at; i--) {
+                    targets = targetLists[i];
+                    if (targets != null) {
+                        targetsAt = i;
+                        break;
+                    }
+                }
+
+                if (targets == null) {
+                    targets = IntList.makeImmutable(next);
+                    blockCatches = ByteCatchList.EMPTY;
+                } else {
+                    blockCatches = catchLists[targetsAt];
+                    if (blockCatches == null) {
+                        blockCatches = ByteCatchList.EMPTY;
+                    }
+                }
+
+                bbs[count] =
+                    new ByteBlock(at, at, next, targets, blockCatches);
+                count++;
+            }
+        }
+
+        ByteBlockList result = new ByteBlockList(count);
+        for (int i = 0; i < count; i++) {
+            result.set(i, bbs[i]);
+        }
+
+        return result;
+    }
+
+    /**
+     * Does basic block identification.
+     */
+    private void doit() {
+        BytecodeArray bytes = method.getCode();
+        ByteCatchList catches = method.getCatches();
+        int catchSz = catches.size();
+
+        /*
+         * Start by setting offset 0 as the start of a block and in need
+         * of work...
+         */
+        Bits.set(workSet, 0);
+        Bits.set(blockSet, 0);
+
+        /*
+         * And then process the work set, add new work based on
+         * exception ranges that are active, and iterate until there's
+         * nothing left to work on.
+         */
+        while (!Bits.isEmpty(workSet)) {
+            try {
+                bytes.processWorkSet(workSet, this);
+            } catch (IllegalArgumentException ex) {
+                // Translate the exception.
+                throw new SimException("flow of control falls off " +
+                                       "end of method",
+                                       ex);
+            }
+
+            for (int i = 0; i < catchSz; i++) {
+                ByteCatchList.Item item = catches.get(i);
+                int start = item.getStartPc();
+                int end = item.getEndPc();
+                if (Bits.anyInRange(liveSet, start, end)) {
+                    Bits.set(blockSet, start);
+                    Bits.set(blockSet, end);
+                    addWorkIfNecessary(item.getHandlerPc(), true);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets a bit in the work set, but only if the instruction in question
+     * isn't yet known to be possibly-live.
+     *
+     * @param offset offset to the instruction in question
+     * @param blockStart {@code true} iff this instruction starts a
+     * basic block
+     */
+    private void addWorkIfNecessary(int offset, boolean blockStart) {
+        if (!Bits.get(liveSet, offset)) {
+            Bits.set(workSet, offset);
+        }
+
+        if (blockStart) {
+            Bits.set(blockSet, offset);
+        }
+    }
+
+    /**
+     * Helper method used by all the visitor methods.
+     *
+     * @param offset offset to the instruction
+     * @param length length of the instruction, in bytes
+     * @param nextIsLive {@code true} iff the instruction after
+     * the indicated one is possibly-live (because this one isn't an
+     * unconditional branch, a return, or a switch)
+     */
+    private void visitCommon(int offset, int length, boolean nextIsLive) {
+        Bits.set(liveSet, offset);
+
+        if (nextIsLive) {
+            /*
+             * If the next instruction is flowed to by this one, just
+             * add it to the work set, and then a subsequent visit*()
+             * will deal with it as appropriate.
+             */
+            addWorkIfNecessary(offset + length, false);
+        } else {
+            /*
+             * If the next instruction isn't flowed to by this one,
+             * then mark it as a start of a block but *don't* add it
+             * to the work set, so that in the final phase we can know
+             * dead code blocks as those marked as blocks but not also marked
+             * live.
+             */
+            Bits.set(blockSet, offset + length);
+        }
+    }
+
+    /**
+     * Helper method used by all the visitor methods that deal with
+     * opcodes that possibly throw. This method should be called after calling
+     * {@link #visitCommon}.
+     *
+     * @param offset offset to the instruction
+     * @param length length of the instruction, in bytes
+     * @param nextIsLive {@code true} iff the instruction after
+     * the indicated one is possibly-live (because this one isn't an
+     * unconditional throw)
+     */
+    private void visitThrowing(int offset, int length, boolean nextIsLive) {
+        int next = offset + length;
+
+        if (nextIsLive) {
+            addWorkIfNecessary(next, true);
+        }
+
+        ByteCatchList catches = method.getCatches().listFor(offset);
+        catchLists[offset] = catches;
+        targetLists[offset] = catches.toTargetList(nextIsLive ? next : -1);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setPreviousOffset(int offset) {
+        previousOffset = offset;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getPreviousOffset() {
+        return previousOffset;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/ByteBlock.java b/dx/src/com/android/dx/cf/code/ByteBlock.java
new file mode 100644
index 0000000..73bbbab
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ByteBlock.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+import com.android.dx.util.LabeledItem;
+
+/**
+ * Representation of a basic block in a bytecode array.
+ */
+public final class ByteBlock implements LabeledItem {
+    /** {@code >= 0;} label for this block */
+    private final int label;
+
+    /** {@code >= 0;} bytecode offset (inclusive) of the start of the block */
+    private final int start;
+
+    /** {@code > start;} bytecode offset (exclusive) of the end of the block */
+    private final int end;
+
+    /** {@code non-null;} list of successors that this block may branch to */
+    private final IntList successors;
+
+    /** {@code non-null;} list of exceptions caught and their handler targets */
+    private final ByteCatchList catches;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param label {@code >= 0;} target label for this block
+     * @param start {@code >= 0;} bytecode offset (inclusive) of the start
+     * of the block
+     * @param end {@code > start;} bytecode offset (exclusive) of the end
+     * of the block
+     * @param successors {@code non-null;} list of successors that this block may
+     * branch to
+     * @param catches {@code non-null;} list of exceptions caught and their
+     * handler targets
+     */
+    public ByteBlock(int label, int start, int end, IntList successors,
+                     ByteCatchList catches) {
+        if (label < 0) {
+            throw new IllegalArgumentException("label < 0");
+        }
+
+        if (start < 0) {
+            throw new IllegalArgumentException("start < 0");
+        }
+
+        if (end <= start) {
+            throw new IllegalArgumentException("end <= start");
+        }
+
+        if (successors == null) {
+            throw new NullPointerException("targets == null");
+        }
+
+        int sz = successors.size();
+        for (int i = 0; i < sz; i++) {
+            if (successors.get(i) < 0) {
+                throw new IllegalArgumentException("successors[" + i +
+                                                   "] == " +
+                                                   successors.get(i));
+            }
+        }
+
+        if (catches == null) {
+            throw new NullPointerException("catches == null");
+        }
+
+        this.label = label;
+        this.start = start;
+        this.end = end;
+        this.successors = successors;
+        this.catches = catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return '{' + Hex.u2(label) + ": " + Hex.u2(start) + ".." +
+            Hex.u2(end) + '}';
+    }
+
+    /**
+     * Gets the label of this block.
+     *
+     * @return {@code >= 0;} the label
+     */
+    public int getLabel() {
+        return label;
+    }
+
+    /**
+     * Gets the bytecode offset (inclusive) of the start of this block.
+     *
+     * @return {@code >= 0;} the start offset
+     */
+    public int getStart() {
+        return start;
+    }
+
+    /**
+     * Gets the bytecode offset (exclusive) of the end of this block.
+     *
+     * @return {@code > getStart();} the end offset
+     */
+    public int getEnd() {
+        return end;
+    }
+
+    /**
+     * Gets the list of successors that this block may branch to
+     * non-exceptionally.
+     *
+     * @return {@code non-null;} the successor list
+     */
+    public IntList getSuccessors() {
+        return successors;
+    }
+
+    /**
+     * Gets the list of exceptions caught and their handler targets.
+     *
+     * @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
new file mode 100644
index 0000000..412dfc3
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ByteBlockList.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.util.FixedSizeList;
+import com.android.dx.util.Hex;
+import com.android.dx.util.LabeledList;
+
+/**
+ * List of {@link ByteBlock} instances.
+ */
+public final class ByteBlockList extends LabeledList {
+
+    /**
+     * Constructs an instance.
+     *
+     * @param size {@code >= 0;} the number of elements to be in the list
+     */
+    public ByteBlockList(int size) {
+        super(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}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public ByteBlock get(int n) {
+        return (ByteBlock) get0(n);
+    }
+
+    /**
+     * Gets the block with the given label.
+     *
+     * @param label the label to look for
+     * @return {@code non-null;} the block with the given label
+     */
+    public ByteBlock labelToBlock(int label) {
+        int idx = indexOfLabel(label);
+
+        if (idx < 0) {
+            throw new IllegalArgumentException("no such label: "
+                    + Hex.u2(label));
+        }
+
+        return get(idx);
+    }
+
+    /**
+     * Sets the element at the given index.
+     *
+     * @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
new file mode 100644
index 0000000..36c37af
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ByteCatchList.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.FixedSizeList;
+import com.android.dx.util.IntList;
+
+/**
+ * List of catch entries, that is, the elements of an "exception table,"
+ * which is part of a standard {@code Code} attribute.
+ */
+public final class ByteCatchList extends FixedSizeList {
+    /** {@code non-null;} convenient zero-entry instance */
+    public static final ByteCatchList EMPTY = new ByteCatchList(0);
+
+    /**
+     * Constructs an instance.
+     *
+     * @param count the number of elements to be in the table
+     */
+    public ByteCatchList(int count) {
+        super(count);
+    }
+
+    /**
+     * Gets the total length of this structure in bytes, when included in
+     * a {@code Code} attribute. The returned value includes the
+     * two bytes for {@code exception_table_length}.
+     *
+     * @return {@code >= 2;} the total length, in bytes
+     */
+    public int byteLength() {
+        return 2 + size() * 8;
+    }
+
+    /**
+     * Gets 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);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @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) {
+            throw new NullPointerException("item == null");
+        }
+
+        set0(n, item);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @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 {@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) {
+        set0(n, new Item(startPc, endPc, handlerPc, exceptionClass));
+    }
+
+    /**
+     * Gets the list of items active at the given address. The result is
+     * automatically made immutable.
+     *
+     * @param pc which address
+     * @return {@code non-null;} list of exception handlers active at
+     * {@code pc}
+     */
+    public ByteCatchList listFor(int pc) {
+        int sz = size();
+        Item[] resultArr = new Item[sz];
+        int resultSz = 0;
+
+        for (int i = 0; i < sz; i++) {
+            Item one = get(i);
+            if (one.covers(pc) && typeNotFound(one, resultArr, resultSz)) {
+                resultArr[resultSz] = one;
+                resultSz++;
+            }
+        }
+
+        if (resultSz == 0) {
+            return EMPTY;
+        }
+
+        ByteCatchList result = new ByteCatchList(resultSz);
+        for (int i = 0; i < resultSz; i++) {
+            result.set(i, resultArr[i]);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * 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} which represents a catch-all.
+     *
+     * @param item {@code non-null;} item with the exception type to look for
+     * @param arr {@code non-null;} array to search in
+     * @param count {@code non-null;} maximum number of elements in the array to check
+     * @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();
+
+        for (int i = 0; i < count; i++) {
+            CstType one = arr[i].getExceptionClass();
+            if ((one == type) || (one == CstType.OBJECT)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns a target list corresponding to this instance. The result
+     * is a list of all the exception handler addresses, with the given
+     * {@code noException} address appended if appropriate. The
+     * result is automatically made immutable.
+     *
+     * @param noException {@code >= -1;} the no-exception address to append, or
+     * {@code -1} not to append anything
+     * @return {@code non-null;} list of exception targets, with
+     * {@code noException} appended if necessary
+     */
+    public IntList toTargetList(int noException) {
+        if (noException < -1) {
+            throw new IllegalArgumentException("noException < -1");
+        }
+
+        boolean hasDefault = (noException >= 0);
+        int sz = size();
+
+        if (sz == 0) {
+            if (hasDefault) {
+                /*
+                 * The list is empty, but there is a no-exception
+                 * address; so, the result is just that address.
+                 */
+                return IntList.makeImmutable(noException);
+            }
+            /*
+             * The list is empty and there isn't even a no-exception
+             * address.
+             */
+            return IntList.EMPTY;
+        }
+
+        IntList result = new IntList(sz + (hasDefault ? 1 : 0));
+
+        for (int i = 0; i < sz; i++) {
+            result.add(get(i).getHandlerPc());
+        }
+
+        if (hasDefault) {
+            result.add(noException);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Returns a rop-style catches list equivalent to this one.
+     *
+     * @return {@code non-null;} the converted instance
+     */
+    public TypeList toRopCatchList() {
+        int sz = size();
+        if (sz == 0) {
+            return StdTypeList.EMPTY;
+        }
+
+        StdTypeList result = new StdTypeList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            result.set(i, get(i).getExceptionClass().getClassType());
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Item in an exception handler list.
+     */
+    public static class Item {
+        /** {@code >= 0;} the start pc (inclusive) of the handler's range */
+        private final int startPc;
+
+        /** {@code >= startPc;} the end pc (exclusive) of the handler's range */
+        private final int endPc;
+
+        /** {@code >= 0;} the pc of the exception handler */
+        private final int handlerPc;
+
+        /** {@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 {@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 {@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) {
+            if (startPc < 0) {
+                throw new IllegalArgumentException("startPc < 0");
+            }
+
+            if (endPc < startPc) {
+                throw new IllegalArgumentException("endPc < startPc");
+            }
+
+            if (handlerPc < 0) {
+                throw new IllegalArgumentException("handlerPc < 0");
+            }
+
+            this.startPc = startPc;
+            this.endPc = endPc;
+            this.handlerPc = handlerPc;
+            this.exceptionClass = exceptionClass;
+        }
+
+        /**
+         * Gets 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;
+        }
+
+        /**
+         * Gets the end pc (exclusive) of the handler's range.
+         *
+         * @return {@code >= startPc;} the end pc (exclusive) of the
+         * handler's range.
+         */
+        public int getEndPc() {
+            return endPc;
+        }
+
+        /**
+         * Gets the pc of the exception handler.
+         *
+         * @return {@code >= 0;} the pc of the exception handler
+         */
+        public int getHandlerPc() {
+            return handlerPc;
+        }
+
+        /**
+         * Gets the class of exception handled.
+         *
+         * @return {@code non-null;} the exception class; {@link CstType#OBJECT}
+         * if this entry handles all possible exceptions
+         */
+        public CstType getExceptionClass() {
+            return (exceptionClass != null) ?
+                exceptionClass : CstType.OBJECT;
+        }
+
+        /**
+         * Returns whether the given address is in the range of this item.
+         *
+         * @param pc the address
+         * @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
new file mode 100644
index 0000000..1376008
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ByteOps.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.util.Hex;
+
+/**
+ * Constants and utility methods for dealing with bytecode arrays at an
+ * opcode level.
+ */
+public class ByteOps {
+    // one constant per opcode
+    public static final int NOP = 0x00;
+    public static final int ACONST_NULL = 0x01;
+    public static final int ICONST_M1 = 0x02;
+    public static final int ICONST_0 = 0x03;
+    public static final int ICONST_1 = 0x04;
+    public static final int ICONST_2 = 0x05;
+    public static final int ICONST_3 = 0x06;
+    public static final int ICONST_4 = 0x07;
+    public static final int ICONST_5 = 0x08;
+    public static final int LCONST_0 = 0x09;
+    public static final int LCONST_1 = 0x0a;
+    public static final int FCONST_0 = 0x0b;
+    public static final int FCONST_1 = 0x0c;
+    public static final int FCONST_2 = 0x0d;
+    public static final int DCONST_0 = 0x0e;
+    public static final int DCONST_1 = 0x0f;
+    public static final int BIPUSH = 0x10;
+    public static final int SIPUSH = 0x11;
+    public static final int LDC = 0x12;
+    public static final int LDC_W = 0x13;
+    public static final int LDC2_W = 0x14;
+    public static final int ILOAD = 0x15;
+    public static final int LLOAD = 0x16;
+    public static final int FLOAD = 0x17;
+    public static final int DLOAD = 0x18;
+    public static final int ALOAD = 0x19;
+    public static final int ILOAD_0 = 0x1a;
+    public static final int ILOAD_1 = 0x1b;
+    public static final int ILOAD_2 = 0x1c;
+    public static final int ILOAD_3 = 0x1d;
+    public static final int LLOAD_0 = 0x1e;
+    public static final int LLOAD_1 = 0x1f;
+    public static final int LLOAD_2 = 0x20;
+    public static final int LLOAD_3 = 0x21;
+    public static final int FLOAD_0 = 0x22;
+    public static final int FLOAD_1 = 0x23;
+    public static final int FLOAD_2 = 0x24;
+    public static final int FLOAD_3 = 0x25;
+    public static final int DLOAD_0 = 0x26;
+    public static final int DLOAD_1 = 0x27;
+    public static final int DLOAD_2 = 0x28;
+    public static final int DLOAD_3 = 0x29;
+    public static final int ALOAD_0 = 0x2a;
+    public static final int ALOAD_1 = 0x2b;
+    public static final int ALOAD_2 = 0x2c;
+    public static final int ALOAD_3 = 0x2d;
+    public static final int IALOAD = 0x2e;
+    public static final int LALOAD = 0x2f;
+    public static final int FALOAD = 0x30;
+    public static final int DALOAD = 0x31;
+    public static final int AALOAD = 0x32;
+    public static final int BALOAD = 0x33;
+    public static final int CALOAD = 0x34;
+    public static final int SALOAD = 0x35;
+    public static final int ISTORE = 0x36;
+    public static final int LSTORE = 0x37;
+    public static final int FSTORE = 0x38;
+    public static final int DSTORE = 0x39;
+    public static final int ASTORE = 0x3a;
+    public static final int ISTORE_0 = 0x3b;
+    public static final int ISTORE_1 = 0x3c;
+    public static final int ISTORE_2 = 0x3d;
+    public static final int ISTORE_3 = 0x3e;
+    public static final int LSTORE_0 = 0x3f;
+    public static final int LSTORE_1 = 0x40;
+    public static final int LSTORE_2 = 0x41;
+    public static final int LSTORE_3 = 0x42;
+    public static final int FSTORE_0 = 0x43;
+    public static final int FSTORE_1 = 0x44;
+    public static final int FSTORE_2 = 0x45;
+    public static final int FSTORE_3 = 0x46;
+    public static final int DSTORE_0 = 0x47;
+    public static final int DSTORE_1 = 0x48;
+    public static final int DSTORE_2 = 0x49;
+    public static final int DSTORE_3 = 0x4a;
+    public static final int ASTORE_0 = 0x4b;
+    public static final int ASTORE_1 = 0x4c;
+    public static final int ASTORE_2 = 0x4d;
+    public static final int ASTORE_3 = 0x4e;
+    public static final int IASTORE = 0x4f;
+    public static final int LASTORE = 0x50;
+    public static final int FASTORE = 0x51;
+    public static final int DASTORE = 0x52;
+    public static final int AASTORE = 0x53;
+    public static final int BASTORE = 0x54;
+    public static final int CASTORE = 0x55;
+    public static final int SASTORE = 0x56;
+    public static final int POP = 0x57;
+    public static final int POP2 = 0x58;
+    public static final int DUP = 0x59;
+    public static final int DUP_X1 = 0x5a;
+    public static final int DUP_X2 = 0x5b;
+    public static final int DUP2 = 0x5c;
+    public static final int DUP2_X1 = 0x5d;
+    public static final int DUP2_X2 = 0x5e;
+    public static final int SWAP = 0x5f;
+    public static final int IADD = 0x60;
+    public static final int LADD = 0x61;
+    public static final int FADD = 0x62;
+    public static final int DADD = 0x63;
+    public static final int ISUB = 0x64;
+    public static final int LSUB = 0x65;
+    public static final int FSUB = 0x66;
+    public static final int DSUB = 0x67;
+    public static final int IMUL = 0x68;
+    public static final int LMUL = 0x69;
+    public static final int FMUL = 0x6a;
+    public static final int DMUL = 0x6b;
+    public static final int IDIV = 0x6c;
+    public static final int LDIV = 0x6d;
+    public static final int FDIV = 0x6e;
+    public static final int DDIV = 0x6f;
+    public static final int IREM = 0x70;
+    public static final int LREM = 0x71;
+    public static final int FREM = 0x72;
+    public static final int DREM = 0x73;
+    public static final int INEG = 0x74;
+    public static final int LNEG = 0x75;
+    public static final int FNEG = 0x76;
+    public static final int DNEG = 0x77;
+    public static final int ISHL = 0x78;
+    public static final int LSHL = 0x79;
+    public static final int ISHR = 0x7a;
+    public static final int LSHR = 0x7b;
+    public static final int IUSHR = 0x7c;
+    public static final int LUSHR = 0x7d;
+    public static final int IAND = 0x7e;
+    public static final int LAND = 0x7f;
+    public static final int IOR = 0x80;
+    public static final int LOR = 0x81;
+    public static final int IXOR = 0x82;
+    public static final int LXOR = 0x83;
+    public static final int IINC = 0x84;
+    public static final int I2L = 0x85;
+    public static final int I2F = 0x86;
+    public static final int I2D = 0x87;
+    public static final int L2I = 0x88;
+    public static final int L2F = 0x89;
+    public static final int L2D = 0x8a;
+    public static final int F2I = 0x8b;
+    public static final int F2L = 0x8c;
+    public static final int F2D = 0x8d;
+    public static final int D2I = 0x8e;
+    public static final int D2L = 0x8f;
+    public static final int D2F = 0x90;
+    public static final int I2B = 0x91;
+    public static final int I2C = 0x92;
+    public static final int I2S = 0x93;
+    public static final int LCMP = 0x94;
+    public static final int FCMPL = 0x95;
+    public static final int FCMPG = 0x96;
+    public static final int DCMPL = 0x97;
+    public static final int DCMPG = 0x98;
+    public static final int IFEQ = 0x99;
+    public static final int IFNE = 0x9a;
+    public static final int IFLT = 0x9b;
+    public static final int IFGE = 0x9c;
+    public static final int IFGT = 0x9d;
+    public static final int IFLE = 0x9e;
+    public static final int IF_ICMPEQ = 0x9f;
+    public static final int IF_ICMPNE = 0xa0;
+    public static final int IF_ICMPLT = 0xa1;
+    public static final int IF_ICMPGE = 0xa2;
+    public static final int IF_ICMPGT = 0xa3;
+    public static final int IF_ICMPLE = 0xa4;
+    public static final int IF_ACMPEQ = 0xa5;
+    public static final int IF_ACMPNE = 0xa6;
+    public static final int GOTO = 0xa7;
+    public static final int JSR = 0xa8;
+    public static final int RET = 0xa9;
+    public static final int TABLESWITCH = 0xaa;
+    public static final int LOOKUPSWITCH = 0xab;
+    public static final int IRETURN = 0xac;
+    public static final int LRETURN = 0xad;
+    public static final int FRETURN = 0xae;
+    public static final int DRETURN = 0xaf;
+    public static final int ARETURN = 0xb0;
+    public static final int RETURN = 0xb1;
+    public static final int GETSTATIC = 0xb2;
+    public static final int PUTSTATIC = 0xb3;
+    public static final int GETFIELD = 0xb4;
+    public static final int PUTFIELD = 0xb5;
+    public static final int INVOKEVIRTUAL = 0xb6;
+    public static final int INVOKESPECIAL = 0xb7;
+    public static final int INVOKESTATIC = 0xb8;
+    public static final int INVOKEINTERFACE = 0xb9;
+    public static final int NEW = 0xbb;
+    public static final int NEWARRAY = 0xbc;
+    public static final int ANEWARRAY = 0xbd;
+    public static final int ARRAYLENGTH = 0xbe;
+    public static final int ATHROW = 0xbf;
+    public static final int CHECKCAST = 0xc0;
+    public static final int INSTANCEOF = 0xc1;
+    public static final int MONITORENTER = 0xc2;
+    public static final int MONITOREXIT = 0xc3;
+    public static final int WIDE = 0xc4;
+    public static final int MULTIANEWARRAY = 0xc5;
+    public static final int IFNULL = 0xc6;
+    public static final int IFNONNULL = 0xc7;
+    public static final int GOTO_W = 0xc8;
+    public static final int JSR_W = 0xc9;
+
+    // a constant for each valid argument to "newarray"
+
+    public static final int NEWARRAY_BOOLEAN = 4;
+    public static final int NEWARRAY_CHAR = 5;
+    public static final int NEWARRAY_FLOAT = 6;
+    public static final int NEWARRAY_DOUBLE = 7;
+    public static final int NEWARRAY_BYTE = 8;
+    public static final int NEWARRAY_SHORT = 9;
+    public static final int NEWARRAY_INT = 10;
+    public static final int NEWARRAY_LONG = 11;
+
+    // a constant for each possible instruction format
+
+    /** invalid */
+    public static final int FMT_INVALID = 0;
+
+    /** "-": {@code op} */
+    public static final int FMT_NO_ARGS = 1;
+
+    /** "0": {@code op}; implies {@code max_locals >= 1} */
+    public static final int FMT_NO_ARGS_LOCALS_1 = 2;
+
+    /** "1": {@code op}; implies {@code max_locals >= 2} */
+    public static final int FMT_NO_ARGS_LOCALS_2 = 3;
+
+    /** "2": {@code op}; implies {@code max_locals >= 3} */
+    public static final int FMT_NO_ARGS_LOCALS_3 = 4;
+
+    /** "3": {@code op}; implies {@code max_locals >= 4} */
+    public static final int FMT_NO_ARGS_LOCALS_4 = 5;
+
+    /** "4": {@code op}; implies {@code max_locals >= 5} */
+    public static final int FMT_NO_ARGS_LOCALS_5 = 6;
+
+    /** "b": {@code op target target} */
+    public static final int FMT_BRANCH = 7;
+
+    /** "c": {@code op target target target target} */
+    public static final int FMT_WIDE_BRANCH = 8;
+
+    /** "p": {@code op #cpi #cpi}; constant restricted as specified */
+    public static final int FMT_CPI = 9;
+
+    /**
+     * "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}; 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 bipush} and
+     * {@code newarray})
+     */
+    public static final int FMT_LITERAL_BYTE = 12;
+
+    /** "I": {@code invokeinterface cpi cpi count 0} */
+    public static final int FMT_INVOKEINTERFACE = 13;
+
+    /** "L": {@code ldc #cpi}; constant restricted as specified */
+    public static final int FMT_LDC = 14;
+
+    /** "S": {@code sipush #byte #byte} */
+    public static final int FMT_SIPUSH = 15;
+
+    /** "T": {@code tableswitch ...} */
+    public static final int FMT_TABLESWITCH = 16;
+
+    /** "U": {@code lookupswitch ...} */
+    public static final int FMT_LOOKUPSWITCH = 17;
+
+    /** "M": {@code multianewarray cpi cpi dims} */
+    public static final int FMT_MULTIANEWARRAY = 18;
+
+    /** "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} */
+    public static final int CPOK_Integer = 0x20;
+
+    /** "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} */
+    public static final int CPOK_Long = 0x80;
+
+    /** "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} */
+    public static final int CPOK_Class = 0x200;
+
+    /** "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} */
+    public static final int CPOK_Fieldref = 0x800;
+
+    /** "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} */
+    public static final int CPOK_InterfaceMethodref = 0x2000;
+
+    /**
+     * {@code non-null;} map from opcodes to format or'ed with allowed constant
+     * pool types
+     */
+    private static final int[] OPCODE_INFO = new int[256];
+
+    /** {@code non-null;} map from opcodes to their names */
+    private static final String[] OPCODE_NAMES = new String[256];
+
+    /** {@code non-null;} bigass string describing all the opcodes */
+    private static final String OPCODE_DETAILS =
+        "00 - nop;" +
+        "01 - aconst_null;" +
+        "02 - iconst_m1;" +
+        "03 - iconst_0;" +
+        "04 - iconst_1;" +
+        "05 - iconst_2;" +
+        "06 - iconst_3;" +
+        "07 - iconst_4;" +
+        "08 - iconst_5;" +
+        "09 - lconst_0;" +
+        "0a - lconst_1;" +
+        "0b - fconst_0;" +
+        "0c - fconst_1;" +
+        "0d - fconst_2;" +
+        "0e - dconst_0;" +
+        "0f - dconst_1;" +
+        "10 y bipush;" +
+        "11 S sipush;" +
+        "12 L:IFcs ldc;" +
+        "13 p:IFcs ldc_w;" +
+        "14 p:DJ ldc2_w;" +
+        "15 l iload;" +
+        "16 m lload;" +
+        "17 l fload;" +
+        "18 m dload;" +
+        "19 l aload;" +
+        "1a 0 iload_0;" +
+        "1b 1 iload_1;" +
+        "1c 2 iload_2;" +
+        "1d 3 iload_3;" +
+        "1e 1 lload_0;" +
+        "1f 2 lload_1;" +
+        "20 3 lload_2;" +
+        "21 4 lload_3;" +
+        "22 0 fload_0;" +
+        "23 1 fload_1;" +
+        "24 2 fload_2;" +
+        "25 3 fload_3;" +
+        "26 1 dload_0;" +
+        "27 2 dload_1;" +
+        "28 3 dload_2;" +
+        "29 4 dload_3;" +
+        "2a 0 aload_0;" +
+        "2b 1 aload_1;" +
+        "2c 2 aload_2;" +
+        "2d 3 aload_3;" +
+        "2e - iaload;" +
+        "2f - laload;" +
+        "30 - faload;" +
+        "31 - daload;" +
+        "32 - aaload;" +
+        "33 - baload;" +
+        "34 - caload;" +
+        "35 - saload;" +
+        "36 - istore;" +
+        "37 - lstore;" +
+        "38 - fstore;" +
+        "39 - dstore;" +
+        "3a - astore;" +
+        "3b 0 istore_0;" +
+        "3c 1 istore_1;" +
+        "3d 2 istore_2;" +
+        "3e 3 istore_3;" +
+        "3f 1 lstore_0;" +
+        "40 2 lstore_1;" +
+        "41 3 lstore_2;" +
+        "42 4 lstore_3;" +
+        "43 0 fstore_0;" +
+        "44 1 fstore_1;" +
+        "45 2 fstore_2;" +
+        "46 3 fstore_3;" +
+        "47 1 dstore_0;" +
+        "48 2 dstore_1;" +
+        "49 3 dstore_2;" +
+        "4a 4 dstore_3;" +
+        "4b 0 astore_0;" +
+        "4c 1 astore_1;" +
+        "4d 2 astore_2;" +
+        "4e 3 astore_3;" +
+        "4f - iastore;" +
+        "50 - lastore;" +
+        "51 - fastore;" +
+        "52 - dastore;" +
+        "53 - aastore;" +
+        "54 - bastore;" +
+        "55 - castore;" +
+        "56 - sastore;" +
+        "57 - pop;" +
+        "58 - pop2;" +
+        "59 - dup;" +
+        "5a - dup_x1;" +
+        "5b - dup_x2;" +
+        "5c - dup2;" +
+        "5d - dup2_x1;" +
+        "5e - dup2_x2;" +
+        "5f - swap;" +
+        "60 - iadd;" +
+        "61 - ladd;" +
+        "62 - fadd;" +
+        "63 - dadd;" +
+        "64 - isub;" +
+        "65 - lsub;" +
+        "66 - fsub;" +
+        "67 - dsub;" +
+        "68 - imul;" +
+        "69 - lmul;" +
+        "6a - fmul;" +
+        "6b - dmul;" +
+        "6c - idiv;" +
+        "6d - ldiv;" +
+        "6e - fdiv;" +
+        "6f - ddiv;" +
+        "70 - irem;" +
+        "71 - lrem;" +
+        "72 - frem;" +
+        "73 - drem;" +
+        "74 - ineg;" +
+        "75 - lneg;" +
+        "76 - fneg;" +
+        "77 - dneg;" +
+        "78 - ishl;" +
+        "79 - lshl;" +
+        "7a - ishr;" +
+        "7b - lshr;" +
+        "7c - iushr;" +
+        "7d - lushr;" +
+        "7e - iand;" +
+        "7f - land;" +
+        "80 - ior;" +
+        "81 - lor;" +
+        "82 - ixor;" +
+        "83 - lxor;" +
+        "84 l iinc;" +
+        "85 - i2l;" +
+        "86 - i2f;" +
+        "87 - i2d;" +
+        "88 - l2i;" +
+        "89 - l2f;" +
+        "8a - l2d;" +
+        "8b - f2i;" +
+        "8c - f2l;" +
+        "8d - f2d;" +
+        "8e - d2i;" +
+        "8f - d2l;" +
+        "90 - d2f;" +
+        "91 - i2b;" +
+        "92 - i2c;" +
+        "93 - i2s;" +
+        "94 - lcmp;" +
+        "95 - fcmpl;" +
+        "96 - fcmpg;" +
+        "97 - dcmpl;" +
+        "98 - dcmpg;" +
+        "99 b ifeq;" +
+        "9a b ifne;" +
+        "9b b iflt;" +
+        "9c b ifge;" +
+        "9d b ifgt;" +
+        "9e b ifle;" +
+        "9f b if_icmpeq;" +
+        "a0 b if_icmpne;" +
+        "a1 b if_icmplt;" +
+        "a2 b if_icmpge;" +
+        "a3 b if_icmpgt;" +
+        "a4 b if_icmple;" +
+        "a5 b if_acmpeq;" +
+        "a6 b if_acmpne;" +
+        "a7 b goto;" +
+        "a8 b jsr;" +
+        "a9 l ret;" +
+        "aa T tableswitch;" +
+        "ab U lookupswitch;" +
+        "ac - ireturn;" +
+        "ad - lreturn;" +
+        "ae - freturn;" +
+        "af - dreturn;" +
+        "b0 - areturn;" +
+        "b1 - return;" +
+        "b2 p:f getstatic;" +
+        "b3 p:f putstatic;" +
+        "b4 p:f getfield;" +
+        "b5 p:f putfield;" +
+        "b6 p:m invokevirtual;" +
+        "b7 p:m invokespecial;" +
+        "b8 p:m invokestatic;" +
+        "b9 I:i invokeinterface;" +
+        "bb p:c new;" +
+        "bc y newarray;" +
+        "bd p:c anewarray;" +
+        "be - arraylength;" +
+        "bf - athrow;" +
+        "c0 p:c checkcast;" +
+        "c1 p:c instanceof;" +
+        "c2 - monitorenter;" +
+        "c3 - monitorexit;" +
+        "c4 W wide;" +
+        "c5 M:c multianewarray;" +
+        "c6 b ifnull;" +
+        "c7 b ifnonnull;" +
+        "c8 c goto_w;" +
+        "c9 c jsr_w;";
+
+    static {
+        // Set up OPCODE_INFO and OPCODE_NAMES.
+        String s = OPCODE_DETAILS;
+        int len = s.length();
+
+        for (int i = 0; i < len; /*i*/) {
+            int idx = (Character.digit(s.charAt(i), 16) << 4) |
+                Character.digit(s.charAt(i + 1), 16);
+            int info;
+            switch (s.charAt(i + 3)) {
+                case '-': info = FMT_NO_ARGS; break;
+                case '0': info = FMT_NO_ARGS_LOCALS_1; break;
+                case '1': info = FMT_NO_ARGS_LOCALS_2; break;
+                case '2': info = FMT_NO_ARGS_LOCALS_3; break;
+                case '3': info = FMT_NO_ARGS_LOCALS_4; break;
+                case '4': info = FMT_NO_ARGS_LOCALS_5; break;
+                case 'b': info = FMT_BRANCH; break;
+                case 'c': info = FMT_WIDE_BRANCH; break;
+                case 'p': info = FMT_CPI; break;
+                case 'l': info = FMT_LOCAL_1; break;
+                case 'm': info = FMT_LOCAL_2; break;
+                case 'y': info = FMT_LITERAL_BYTE; break;
+                case 'I': info = FMT_INVOKEINTERFACE; break;
+                case 'L': info = FMT_LDC; break;
+                case 'S': info = FMT_SIPUSH; break;
+                case 'T': info = FMT_TABLESWITCH; break;
+                case 'U': info = FMT_LOOKUPSWITCH; break;
+                case 'M': info = FMT_MULTIANEWARRAY; break;
+                case 'W': info = FMT_WIDE; break;
+                default: info = FMT_INVALID; break;
+            }
+
+            i += 5;
+            if (s.charAt(i - 1) == ':') {
+                inner:
+                for (;;) {
+                    switch (s.charAt(i)) {
+                        case 'I': info |= CPOK_Integer; break;
+                        case 'F': info |= CPOK_Float; break;
+                        case 'J': info |= CPOK_Long; break;
+                        case 'D': info |= CPOK_Double; break;
+                        case 'c': info |= CPOK_Class; break;
+                        case 's': info |= CPOK_String; break;
+                        case 'f': info |= CPOK_Fieldref; break;
+                        case 'm': info |= CPOK_Methodref; break;
+                        case 'i': info |= CPOK_InterfaceMethodref; break;
+                        default: break inner;
+                    }
+                    i++;
+                }
+                i++;
+            }
+
+            int endAt = s.indexOf(';', i);
+            OPCODE_INFO[idx] = info;
+            OPCODE_NAMES[idx] = s.substring(i, endAt);
+            i = endAt + 1;
+        }
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private ByteOps() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the name of the given opcode.
+     *
+     * @param opcode {@code >= 0, <= 255;} the opcode
+     * @return {@code non-null;} its name
+     */
+    public static String opName(int opcode) {
+        String result = OPCODE_NAMES[opcode];
+
+        if (result == null) {
+            result = "unused_" + Hex.u1(opcode);
+            OPCODE_NAMES[opcode] = result;
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the format and allowed cp types of the given opcode.
+     *
+     * @param opcode {@code >= 0, <= 255;} the opcode
+     * @return its format and allowed cp types
+     */
+    public static int opInfo(int opcode) {
+        return OPCODE_INFO[opcode];
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/BytecodeArray.java b/dx/src/com/android/dx/cf/code/BytecodeArray.java
new file mode 100644
index 0000000..f4ea007
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/BytecodeArray.java
@@ -0,0 +1,1422 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstKnownNull;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Bits;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import java.util.ArrayList;
+
+/**
+ * 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();
+
+    /** {@code non-null;} underlying bytes */
+    private final ByteArray bytes;
+
+    /**
+     * {@code non-null;} constant pool to use when resolving constant
+     * pool indices
+     */
+    private final ConstantPool pool;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+        if (bytes == null) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        if (pool == null) {
+            throw new NullPointerException("pool == null");
+        }
+
+        this.bytes = bytes;
+        this.pool = pool;
+    }
+
+    /**
+     * Gets the underlying byte array.
+     *
+     * @return {@code non-null;} the byte array
+     */
+    public ByteArray getBytes() {
+        return bytes;
+    }
+
+    /**
+     * Gets the size of the bytecode array, per se.
+     *
+     * @return {@code >= 0;} the length of the bytecode array
+     */
+    public int size() {
+        return bytes.size();
+    }
+
+    /**
+     * Gets the total length of this structure in bytes, when included in
+     * a {@code Code} attribute. The returned value includes the
+     * array size plus four bytes for {@code code_length}.
+     *
+     * @return {@code >= 4;} the total length, in bytes
+     */
+    public int byteLength() {
+        return 4 + bytes.size();
+    }
+
+    /**
+     * Parses each instruction in the array, in order.
+     *
+     * @param visitor {@code null-ok;} visitor to call back to for
+     * each instruction
+     */
+    public void forEach(Visitor visitor) {
+        int sz = bytes.size();
+        int at = 0;
+
+        while (at < sz) {
+            /*
+             * Don't record the previous offset here, so that we get to see the
+             * raw code that initializes the array
+             */
+            at += parseInstruction(at, visitor);
+        }
+    }
+
+    /**
+     * Finds the offset to each instruction in the bytecode array. The
+     * result is a bit set with the offset of each opcode-per-se flipped on.
+     *
+     * @see Bits
+     * @return {@code non-null;} appropriately constructed bit set
+     */
+    public int[] getInstructionOffsets() {
+        int sz = bytes.size();
+        int[] result = Bits.makeBitSet(sz);
+        int at = 0;
+
+        while (at < sz) {
+            Bits.set(result, at, true);
+            int length = parseInstruction(at, null);
+            at += length;
+        }
+
+        return result;
+    }
+
+    /**
+     * Processes the given "work set" by repeatedly finding the lowest bit
+     * in the set, clearing it, and parsing and visiting the instruction at
+     * the indicated offset (that is, the bit index), repeating until the
+     * work set is empty. It is expected that the visitor will regularly
+     * set new bits in the work set during the process.
+     *
+     * @param workSet {@code non-null;} the work set to process
+     * @param visitor {@code non-null;} visitor to call back to for
+     * each instruction
+     */
+    public void processWorkSet(int[] workSet, Visitor visitor) {
+        if (visitor == null) {
+            throw new NullPointerException("visitor == null");
+        }
+
+        for (;;) {
+            int offset = Bits.findFirst(workSet, 0);
+            if (offset < 0) {
+                break;
+            }
+            Bits.clear(workSet, offset);
+            parseInstruction(offset, visitor);
+            visitor.setPreviousOffset(offset);
+        }
+    }
+
+    /**
+     * Parses the instruction at the indicated offset. Indicate the
+     * result by calling the visitor if supplied and by returning the
+     * number of bytes consumed by the instruction.
+     *
+     * <p>In order to simplify further processing, the opcodes passed
+     * to the visitor are canonicalized, altering the opcode to a more
+     * universal one and making formerly implicit arguments
+     * explicit. In particular:</p>
+     *
+     * <ul>
+     * <li>The opcodes to push literal constants of primitive types all become
+     *   {@code ldc}.
+     *   E.g., {@code fconst_0}, {@code sipush}, and
+     *   {@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} 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} variant opcode, with the {@code type}
+     *   argument set to indicate the actual type. E.g.,
+     *   {@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}
+     *   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}, 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 {@code >= 0, < bytes.size();} offset to the start of the
+     * instruction
+     * @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) {
+        if (visitor == null) {
+            visitor = EMPTY_VISITOR;
+        }
+
+        try {
+            int opcode = bytes.getUnsignedByte(offset);
+            int info = ByteOps.opInfo(opcode);
+            int fmt = info & ByteOps.FMT_MASK;
+
+            switch (opcode) {
+                case ByteOps.NOP: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
+                    return 1;
+                }
+                case ByteOps.ACONST_NULL: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstKnownNull.THE_ONE, 0);
+                    return 1;
+                }
+                case ByteOps.ICONST_M1: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_M1, -1);
+                    return 1;
+                }
+                case ByteOps.ICONST_0: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_0, 0);
+                    return 1;
+                }
+                case ByteOps.ICONST_1: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_1, 1);
+                    return 1;
+                }
+                case ByteOps.ICONST_2: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_2, 2);
+                    return 1;
+                }
+                case ByteOps.ICONST_3: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_3, 3);
+                    return 1;
+                }
+                case ByteOps.ICONST_4: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_4, 4);
+                    return 1;
+                }
+                case ByteOps.ICONST_5:  {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstInteger.VALUE_5, 5);
+                    return 1;
+                }
+                case ByteOps.LCONST_0: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstLong.VALUE_0, 0);
+                    return 1;
+                }
+                case ByteOps.LCONST_1: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstLong.VALUE_1, 0);
+                    return 1;
+                }
+                case ByteOps.FCONST_0: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstFloat.VALUE_0, 0);
+                    return 1;
+                }
+                case ByteOps.FCONST_1: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstFloat.VALUE_1, 0);
+                    return 1;
+                }
+                case ByteOps.FCONST_2:  {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstFloat.VALUE_2, 0);
+                    return 1;
+                }
+                case ByteOps.DCONST_0: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstDouble.VALUE_0, 0);
+                    return 1;
+                }
+                case ByteOps.DCONST_1: {
+                    visitor.visitConstant(ByteOps.LDC, offset, 1,
+                                          CstDouble.VALUE_1, 0);
+                    return 1;
+                }
+                case ByteOps.BIPUSH: {
+                    int value = bytes.getByte(offset + 1);
+                    visitor.visitConstant(ByteOps.LDC, offset, 2,
+                                          CstInteger.make(value), value);
+                    return 2;
+                }
+                case ByteOps.SIPUSH: {
+                    int value = bytes.getShort(offset + 1);
+                    visitor.visitConstant(ByteOps.LDC, offset, 3,
+                                          CstInteger.make(value), value);
+                    return 3;
+                }
+                case ByteOps.LDC: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    Constant cst = pool.get(idx);
+                    int value = (cst instanceof CstInteger) ?
+                        ((CstInteger) cst).getValue() : 0;
+                    visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value);
+                    return 2;
+                }
+                case ByteOps.LDC_W: {
+                    int idx = bytes.getUnsignedShort(offset + 1);
+                    Constant cst = pool.get(idx);
+                    int value = (cst instanceof CstInteger) ?
+                        ((CstInteger) cst).getValue() : 0;
+                    visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value);
+                    return 3;
+                }
+                case ByteOps.LDC2_W: {
+                    int idx = bytes.getUnsignedShort(offset + 1);
+                    Constant cst = pool.get(idx);
+                    visitor.visitConstant(ByteOps.LDC2_W, offset, 3, cst, 0);
+                    return 3;
+                }
+                case ByteOps.ILOAD: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
+                                       Type.INT, 0);
+                    return 2;
+                }
+                case ByteOps.LLOAD: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
+                                       Type.LONG, 0);
+                    return 2;
+                }
+                case ByteOps.FLOAD: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
+                                       Type.FLOAT, 0);
+                    return 2;
+                }
+                case ByteOps.DLOAD: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
+                                       Type.DOUBLE, 0);
+                    return 2;
+                }
+                case ByteOps.ALOAD: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
+                                       Type.OBJECT, 0);
+                    return 2;
+                }
+                case ByteOps.ILOAD_0:
+                case ByteOps.ILOAD_1:
+                case ByteOps.ILOAD_2:
+                case ByteOps.ILOAD_3: {
+                    int idx = opcode - ByteOps.ILOAD_0;
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
+                                       Type.INT, 0);
+                    return 1;
+                }
+                case ByteOps.LLOAD_0:
+                case ByteOps.LLOAD_1:
+                case ByteOps.LLOAD_2:
+                case ByteOps.LLOAD_3: {
+                    int idx = opcode - ByteOps.LLOAD_0;
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
+                                       Type.LONG, 0);
+                    return 1;
+                }
+                case ByteOps.FLOAD_0:
+                case ByteOps.FLOAD_1:
+                case ByteOps.FLOAD_2:
+                case ByteOps.FLOAD_3: {
+                    int idx = opcode - ByteOps.FLOAD_0;
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
+                                       Type.FLOAT, 0);
+                    return 1;
+                }
+                case ByteOps.DLOAD_0:
+                case ByteOps.DLOAD_1:
+                case ByteOps.DLOAD_2:
+                case ByteOps.DLOAD_3: {
+                    int idx = opcode - ByteOps.DLOAD_0;
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
+                                       Type.DOUBLE, 0);
+                    return 1;
+                }
+                case ByteOps.ALOAD_0:
+                case ByteOps.ALOAD_1:
+                case ByteOps.ALOAD_2:
+                case ByteOps.ALOAD_3: {
+                    int idx = opcode - ByteOps.ALOAD_0;
+                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
+                                       Type.OBJECT, 0);
+                    return 1;
+                }
+                case ByteOps.IALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.INT);
+                    return 1;
+                }
+                case ByteOps.LALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.LONG);
+                    return 1;
+                }
+                case ByteOps.FALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
+                                        Type.FLOAT);
+                    return 1;
+                }
+                case ByteOps.DALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
+                                        Type.DOUBLE);
+                    return 1;
+                }
+                case ByteOps.AALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
+                                        Type.OBJECT);
+                    return 1;
+                }
+                case ByteOps.BALOAD: {
+                    /*
+                     * Note: This is a load from either a byte[] or a
+                     * boolean[].
+                     */
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.BYTE);
+                    return 1;
+                }
+                case ByteOps.CALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.CHAR);
+                    return 1;
+                }
+                case ByteOps.SALOAD: {
+                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
+                                        Type.SHORT);
+                    return 1;
+                }
+                case ByteOps.ISTORE: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
+                                       Type.INT, 0);
+                    return 2;
+                }
+                case ByteOps.LSTORE: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
+                                       Type.LONG, 0);
+                    return 2;
+                }
+                case ByteOps.FSTORE: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
+                                       Type.FLOAT, 0);
+                    return 2;
+                }
+                case ByteOps.DSTORE: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
+                                       Type.DOUBLE, 0);
+                    return 2;
+                }
+                case ByteOps.ASTORE: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
+                                       Type.OBJECT, 0);
+                    return 2;
+                }
+                case ByteOps.ISTORE_0:
+                case ByteOps.ISTORE_1:
+                case ByteOps.ISTORE_2:
+                case ByteOps.ISTORE_3: {
+                    int idx = opcode - ByteOps.ISTORE_0;
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
+                                       Type.INT, 0);
+                    return 1;
+                }
+                case ByteOps.LSTORE_0:
+                case ByteOps.LSTORE_1:
+                case ByteOps.LSTORE_2:
+                case ByteOps.LSTORE_3: {
+                    int idx = opcode - ByteOps.LSTORE_0;
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
+                                       Type.LONG, 0);
+                    return 1;
+                }
+                case ByteOps.FSTORE_0:
+                case ByteOps.FSTORE_1:
+                case ByteOps.FSTORE_2:
+                case ByteOps.FSTORE_3: {
+                    int idx = opcode - ByteOps.FSTORE_0;
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
+                                       Type.FLOAT, 0);
+                    return 1;
+                }
+                case ByteOps.DSTORE_0:
+                case ByteOps.DSTORE_1:
+                case ByteOps.DSTORE_2:
+                case ByteOps.DSTORE_3: {
+                    int idx = opcode - ByteOps.DSTORE_0;
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
+                                       Type.DOUBLE, 0);
+                    return 1;
+                }
+                case ByteOps.ASTORE_0:
+                case ByteOps.ASTORE_1:
+                case ByteOps.ASTORE_2:
+                case ByteOps.ASTORE_3: {
+                    int idx = opcode - ByteOps.ASTORE_0;
+                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
+                                       Type.OBJECT, 0);
+                    return 1;
+                }
+                case ByteOps.IASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.INT);
+                    return 1;
+                }
+                case ByteOps.LASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.LONG);
+                    return 1;
+                }
+                case ByteOps.FASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.FLOAT);
+                    return 1;
+                }
+                case ByteOps.DASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.DOUBLE);
+                    return 1;
+                }
+                case ByteOps.AASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.OBJECT);
+                    return 1;
+                }
+                case ByteOps.BASTORE: {
+                    /*
+                     * Note: This is a load from either a byte[] or a
+                     * boolean[].
+                     */
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.BYTE);
+                    return 1;
+                }
+                case ByteOps.CASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.CHAR);
+                    return 1;
+                }
+                case ByteOps.SASTORE: {
+                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
+                                        Type.SHORT);
+                    return 1;
+                }
+                case ByteOps.POP:
+                case ByteOps.POP2:
+                case ByteOps.DUP:
+                case ByteOps.DUP_X1:
+                case ByteOps.DUP_X2:
+                case ByteOps.DUP2:
+                case ByteOps.DUP2_X1:
+                case ByteOps.DUP2_X2:
+                case ByteOps.SWAP: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
+                    return 1;
+                }
+                case ByteOps.IADD:
+                case ByteOps.ISUB:
+                case ByteOps.IMUL:
+                case ByteOps.IDIV:
+                case ByteOps.IREM:
+                case ByteOps.INEG:
+                case ByteOps.ISHL:
+                case ByteOps.ISHR:
+                case ByteOps.IUSHR:
+                case ByteOps.IAND:
+                case ByteOps.IOR:
+                case ByteOps.IXOR: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.INT);
+                    return 1;
+                }
+                case ByteOps.LADD:
+                case ByteOps.LSUB:
+                case ByteOps.LMUL:
+                case ByteOps.LDIV:
+                case ByteOps.LREM:
+                case ByteOps.LNEG:
+                case ByteOps.LSHL:
+                case ByteOps.LSHR:
+                case ByteOps.LUSHR:
+                case ByteOps.LAND:
+                case ByteOps.LOR:
+                case ByteOps.LXOR: {
+                    /*
+                     * It's "opcode - 1" because, conveniently enough, all
+                     * these long ops are one past the int variants.
+                     */
+                    visitor.visitNoArgs(opcode - 1, offset, 1, Type.LONG);
+                    return 1;
+                }
+                case ByteOps.FADD:
+                case ByteOps.FSUB:
+                case ByteOps.FMUL:
+                case ByteOps.FDIV:
+                case ByteOps.FREM:
+                case ByteOps.FNEG: {
+                    /*
+                     * It's "opcode - 2" because, conveniently enough, all
+                     * these float ops are two past the int variants.
+                     */
+                    visitor.visitNoArgs(opcode - 2, offset, 1, Type.FLOAT);
+                    return 1;
+                }
+                case ByteOps.DADD:
+                case ByteOps.DSUB:
+                case ByteOps.DMUL:
+                case ByteOps.DDIV:
+                case ByteOps.DREM:
+                case ByteOps.DNEG: {
+                    /*
+                     * It's "opcode - 3" because, conveniently enough, all
+                     * these double ops are three past the int variants.
+                     */
+                    visitor.visitNoArgs(opcode - 3, offset, 1, Type.DOUBLE);
+                    return 1;
+                }
+                case ByteOps.IINC: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    int value = bytes.getByte(offset + 2);
+                    visitor.visitLocal(opcode, offset, 3, idx,
+                                       Type.INT, value);
+                    return 3;
+                }
+                case ByteOps.I2L:
+                case ByteOps.F2L:
+                case ByteOps.D2L: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.LONG);
+                    return 1;
+                }
+                case ByteOps.I2F:
+                case ByteOps.L2F:
+                case ByteOps.D2F: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.FLOAT);
+                    return 1;
+                }
+                case ByteOps.I2D:
+                case ByteOps.L2D:
+                case ByteOps.F2D: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.DOUBLE);
+                    return 1;
+                }
+                case ByteOps.L2I:
+                case ByteOps.F2I:
+                case ByteOps.D2I:
+                case ByteOps.I2B:
+                case ByteOps.I2C:
+                case ByteOps.I2S:
+                case ByteOps.LCMP:
+                case ByteOps.FCMPL:
+                case ByteOps.FCMPG:
+                case ByteOps.DCMPL:
+                case ByteOps.DCMPG:
+                case ByteOps.ARRAYLENGTH: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.INT);
+                    return 1;
+                }
+                case ByteOps.IFEQ:
+                case ByteOps.IFNE:
+                case ByteOps.IFLT:
+                case ByteOps.IFGE:
+                case ByteOps.IFGT:
+                case ByteOps.IFLE:
+                case ByteOps.IF_ICMPEQ:
+                case ByteOps.IF_ICMPNE:
+                case ByteOps.IF_ICMPLT:
+                case ByteOps.IF_ICMPGE:
+                case ByteOps.IF_ICMPGT:
+                case ByteOps.IF_ICMPLE:
+                case ByteOps.IF_ACMPEQ:
+                case ByteOps.IF_ACMPNE:
+                case ByteOps.GOTO:
+                case ByteOps.JSR:
+                case ByteOps.IFNULL:
+                case ByteOps.IFNONNULL: {
+                    int target = offset + bytes.getShort(offset + 1);
+                    visitor.visitBranch(opcode, offset, 3, target);
+                    return 3;
+                }
+                case ByteOps.RET: {
+                    int idx = bytes.getUnsignedByte(offset + 1);
+                    visitor.visitLocal(opcode, offset, 2, idx,
+                                       Type.RETURN_ADDRESS, 0);
+                    return 2;
+                }
+                case ByteOps.TABLESWITCH: {
+                    return parseTableswitch(offset, visitor);
+                }
+                case ByteOps.LOOKUPSWITCH: {
+                    return parseLookupswitch(offset, visitor);
+                }
+                case ByteOps.IRETURN: {
+                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.INT);
+                    return 1;
+                }
+                case ByteOps.LRETURN: {
+                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
+                                        Type.LONG);
+                    return 1;
+                }
+                case ByteOps.FRETURN: {
+                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
+                                        Type.FLOAT);
+                    return 1;
+                }
+                case ByteOps.DRETURN: {
+                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
+                                        Type.DOUBLE);
+                    return 1;
+                }
+                case ByteOps.ARETURN: {
+                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
+                                        Type.OBJECT);
+                    return 1;
+                }
+                case ByteOps.RETURN:
+                case ByteOps.ATHROW:
+                case ByteOps.MONITORENTER:
+                case ByteOps.MONITOREXIT: {
+                    visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
+                    return 1;
+                }
+                case ByteOps.GETSTATIC:
+                case ByteOps.PUTSTATIC:
+                case ByteOps.GETFIELD:
+                case ByteOps.PUTFIELD:
+                case ByteOps.INVOKEVIRTUAL:
+                case ByteOps.INVOKESPECIAL:
+                case ByteOps.INVOKESTATIC:
+                case ByteOps.NEW:
+                case ByteOps.ANEWARRAY:
+                case ByteOps.CHECKCAST:
+                case ByteOps.INSTANCEOF: {
+                    int idx = bytes.getUnsignedShort(offset + 1);
+                    Constant cst = pool.get(idx);
+                    visitor.visitConstant(opcode, offset, 3, cst, 0);
+                    return 3;
+                }
+                case ByteOps.INVOKEINTERFACE: {
+                    int idx = bytes.getUnsignedShort(offset + 1);
+                    int count = bytes.getUnsignedByte(offset + 3);
+                    int expectZero = bytes.getUnsignedByte(offset + 4);
+                    Constant cst = pool.get(idx);
+                    visitor.visitConstant(opcode, offset, 5, cst,
+                                          count | (expectZero << 8));
+                    return 5;
+                }
+                case ByteOps.NEWARRAY: {
+                    return parseNewarray(offset, visitor);
+                }
+                case ByteOps.WIDE: {
+                    return parseWide(offset, visitor);
+                }
+                case ByteOps.MULTIANEWARRAY: {
+                    int idx = bytes.getUnsignedShort(offset + 1);
+                    int dimensions = bytes.getUnsignedByte(offset + 3);
+                    Constant cst = pool.get(idx);
+                    visitor.visitConstant(opcode, offset, 4, cst, dimensions);
+                    return 4;
+                }
+                case ByteOps.GOTO_W:
+                case ByteOps.JSR_W: {
+                    int target = offset + bytes.getInt(offset + 1);
+                    int newop =
+                        (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO :
+                        ByteOps.JSR;
+                    visitor.visitBranch(newop, offset, 5, target);
+                    return 5;
+                }
+                default: {
+                    visitor.visitInvalid(opcode, offset, 1);
+                    return 1;
+                }
+            }
+        } catch (SimException ex) {
+            ex.addContext("...at bytecode offset " + Hex.u4(offset));
+            throw ex;
+        } catch (RuntimeException ex) {
+            SimException se = new SimException(ex);
+            se.addContext("...at bytecode offset " + Hex.u4(offset));
+            throw se;
+        }
+    }
+
+    /**
+     * Helper to deal with {@code tableswitch}.
+     *
+     * @param offset the offset to the {@code tableswitch} opcode itself
+     * @param visitor {@code non-null;} visitor to use
+     * @return instruction length, in bytes
+     */
+    private int parseTableswitch(int offset, Visitor visitor) {
+        int at = (offset + 4) & ~3; // "at" skips the padding.
+
+        // Collect the padding.
+        int padding = 0;
+        for (int i = offset + 1; i < at; i++) {
+            padding = (padding << 8) | bytes.getUnsignedByte(i);
+        }
+
+        int defaultTarget = offset + bytes.getInt(at);
+        int low = bytes.getInt(at + 4);
+        int high = bytes.getInt(at + 8);
+        int count = high - low + 1;
+        at += 12;
+
+        if (low > high) {
+            throw new SimException("low / high inversion");
+        }
+
+        SwitchList cases = new SwitchList(count);
+        for (int i = 0; i < count; i++) {
+            int target = offset + bytes.getInt(at);
+            at += 4;
+            cases.add(low + i, target);
+        }
+        cases.setDefaultTarget(defaultTarget);
+        cases.removeSuperfluousDefaults();
+        cases.setImmutable();
+
+        int length = at - offset;
+        visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases,
+                            padding);
+
+        return length;
+    }
+
+    /**
+     * Helper to deal with {@code lookupswitch}.
+     *
+     * @param offset the offset to the {@code lookupswitch} opcode itself
+     * @param visitor {@code non-null;} visitor to use
+     * @return instruction length, in bytes
+     */
+    private int parseLookupswitch(int offset, Visitor visitor) {
+        int at = (offset + 4) & ~3; // "at" skips the padding.
+
+        // Collect the padding.
+        int padding = 0;
+        for (int i = offset + 1; i < at; i++) {
+            padding = (padding << 8) | bytes.getUnsignedByte(i);
+        }
+
+        int defaultTarget = offset + bytes.getInt(at);
+        int npairs = bytes.getInt(at + 4);
+        at += 8;
+
+        SwitchList cases = new SwitchList(npairs);
+        for (int i = 0; i < npairs; i++) {
+            int match = bytes.getInt(at);
+            int target = offset + bytes.getInt(at + 4);
+            at += 8;
+            cases.add(match, target);
+        }
+        cases.setDefaultTarget(defaultTarget);
+        cases.removeSuperfluousDefaults();
+        cases.setImmutable();
+
+        int length = at - offset;
+        visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases,
+                            padding);
+
+        return length;
+    }
+
+    /**
+     * Helper to deal with {@code newarray}.
+     *
+     * @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) {
+        int value = bytes.getUnsignedByte(offset + 1);
+        CstType type;
+        switch (value) {
+            case ByteOps.NEWARRAY_BOOLEAN: {
+                type = CstType.BOOLEAN_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_CHAR: {
+                type = CstType.CHAR_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_DOUBLE: {
+                type = CstType.DOUBLE_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_FLOAT: {
+                type = CstType.FLOAT_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_BYTE: {
+                type = CstType.BYTE_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_SHORT: {
+                type = CstType.SHORT_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_INT: {
+                type = CstType.INT_ARRAY;
+                break;
+            }
+            case ByteOps.NEWARRAY_LONG: {
+                type = CstType.LONG_ARRAY;
+                break;
+            }
+            default: {
+                throw new SimException("bad newarray code " +
+                        Hex.u1(value));
+            }
+        }
+
+        // Revisit the previous bytecode to find out the length of the array
+        int previousOffset = visitor.getPreviousOffset();
+        ConstantParserVisitor constantVisitor = new ConstantParserVisitor();
+        int arrayLength = 0;
+
+        /*
+         * For visitors that don't record the previous offset, -1 will be
+         * seen here
+         */
+        if (previousOffset >= 0) {
+            parseInstruction(previousOffset, constantVisitor);
+            if (constantVisitor.cst instanceof CstInteger &&
+                    constantVisitor.length + previousOffset == offset) {
+                arrayLength = constantVisitor.value;
+
+            }
+        }
+
+        /*
+         * Try to match the array initialization idiom. For example, if the
+         * subsequent code is initializing an int array, we are expecting the
+         * following pattern repeatedly:
+         *  dup
+         *  push index
+         *  push value
+         *  *astore
+         *
+         * where the index value will be incrimented sequentially from 0 up.
+         */
+        int nInit = 0;
+        int curOffset = offset+2;
+        int lastOffset = curOffset;
+        ArrayList<Constant> initVals = new ArrayList<Constant>();
+
+        if (arrayLength != 0) {
+            while (true) {
+                boolean punt = false;
+
+                // First, check if the next bytecode is dup.
+                int nextByte = bytes.getUnsignedByte(curOffset++);
+                if (nextByte != ByteOps.DUP)
+                    break;
+
+                /*
+                 * Next, check if the expected array index is pushed to
+                 * the stack.
+                 */
+                parseInstruction(curOffset, constantVisitor);
+                if (constantVisitor.length == 0 ||
+                        !(constantVisitor.cst instanceof CstInteger) ||
+                        constantVisitor.value != nInit)
+                    break;
+
+                // Next, fetch the init value and record it.
+                curOffset += constantVisitor.length;
+
+                /*
+                 * Next, find out what kind of constant is pushed onto
+                 * the stack.
+                 */
+                parseInstruction(curOffset, constantVisitor);
+                if (constantVisitor.length == 0 ||
+                        !(constantVisitor.cst instanceof CstLiteralBits))
+                    break;
+
+                curOffset += constantVisitor.length;
+                initVals.add(constantVisitor.cst);
+
+                nextByte = bytes.getUnsignedByte(curOffset++);
+                // Now, check if the value is stored to the array properly.
+                switch (value) {
+                    case ByteOps.NEWARRAY_BYTE:
+                    case ByteOps.NEWARRAY_BOOLEAN: {
+                        if (nextByte != ByteOps.BASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    case ByteOps.NEWARRAY_CHAR: {
+                        if (nextByte != ByteOps.CASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    case ByteOps.NEWARRAY_DOUBLE: {
+                        if (nextByte != ByteOps.DASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    case ByteOps.NEWARRAY_FLOAT: {
+                        if (nextByte != ByteOps.FASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    case ByteOps.NEWARRAY_SHORT: {
+                        if (nextByte != ByteOps.SASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    case ByteOps.NEWARRAY_INT: {
+                        if (nextByte != ByteOps.IASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    case ByteOps.NEWARRAY_LONG: {
+                        if (nextByte != ByteOps.LASTORE) {
+                            punt = true;
+                        }
+                        break;
+                    }
+                    default:
+                        punt = true;
+                        break;
+                }
+                if (punt) {
+                    break;
+                }
+                lastOffset = curOffset;
+                nInit++;
+            }
+        }
+
+        /*
+         * For singleton arrays it is still more economical to
+         * generate the aput.
+         */
+        if (nInit < 2 || nInit != arrayLength) {
+            visitor.visitNewarray(offset, 2, type, null);
+            return 2;
+        } else {
+            visitor.visitNewarray(offset, lastOffset - offset, type, initVals);
+            return lastOffset - offset;
+        }
+     }
+
+
+    /**
+     * Helper to deal with {@code wide}.
+     *
+     * @param offset the offset to the {@code wide} opcode itself
+     * @param visitor {@code non-null;} visitor to use
+     * @return instruction length, in bytes
+     */
+    private int parseWide(int offset, Visitor visitor) {
+        int opcode = bytes.getUnsignedByte(offset + 1);
+        int idx = bytes.getUnsignedShort(offset + 2);
+        switch (opcode) {
+            case ByteOps.ILOAD: {
+                visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
+                                   Type.INT, 0);
+                return 4;
+            }
+            case ByteOps.LLOAD: {
+                visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
+                                   Type.LONG, 0);
+                return 4;
+            }
+            case ByteOps.FLOAD: {
+                visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
+                                   Type.FLOAT, 0);
+                return 4;
+            }
+            case ByteOps.DLOAD: {
+                visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
+                                   Type.DOUBLE, 0);
+                return 4;
+            }
+            case ByteOps.ALOAD: {
+                visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
+                                   Type.OBJECT, 0);
+                return 4;
+            }
+            case ByteOps.ISTORE: {
+                visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
+                                   Type.INT, 0);
+                return 4;
+            }
+            case ByteOps.LSTORE: {
+                visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
+                                   Type.LONG, 0);
+                return 4;
+            }
+            case ByteOps.FSTORE: {
+                visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
+                                   Type.FLOAT, 0);
+                return 4;
+            }
+            case ByteOps.DSTORE: {
+                visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
+                                   Type.DOUBLE, 0);
+                return 4;
+            }
+            case ByteOps.ASTORE: {
+                visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
+                                   Type.OBJECT, 0);
+                return 4;
+            }
+            case ByteOps.RET: {
+                visitor.visitLocal(opcode, offset, 4, idx,
+                                   Type.RETURN_ADDRESS, 0);
+                return 4;
+            }
+            case ByteOps.IINC: {
+                int value = bytes.getShort(offset + 4);
+                visitor.visitLocal(opcode, offset, 6, idx,
+                                   Type.INT, value);
+                return 6;
+            }
+            default: {
+                visitor.visitInvalid(ByteOps.WIDE, offset, 1);
+                return 1;
+            }
+        }
+    }
+
+    /**
+     * Instruction visitor interface.
+     */
+    public interface Visitor {
+        /**
+         * Visits an invalid instruction.
+         *
+         * @param opcode the opcode
+         * @param offset offset to the instruction
+         * @param length length of the instruction, in bytes
+         */
+        public void visitInvalid(int opcode, int offset, int length);
+
+        /**
+         * Visits an instruction which has no inline arguments
+         * (implicit or explicit).
+         *
+         * @param opcode the opcode
+         * @param offset offset to the instruction
+         * @param length length of the instruction, in bytes
+         * @param type {@code non-null;} type the instruction operates on
+         */
+        public void visitNoArgs(int opcode, int offset, int length,
+                Type type);
+
+        /**
+         * Visits an instruction which has a local variable index argument.
+         *
+         * @param opcode the opcode
+         * @param offset offset to the instruction
+         * @param length length of the instruction, in bytes
+         * @param idx the local variable index
+         * @param type {@code non-null;} the type of the accessed value
+         * @param value additional literal integer argument, if salient (i.e.,
+         * for {@code iinc})
+         */
+        public void visitLocal(int opcode, int offset, int length,
+                int idx, Type type, int value);
+
+        /**
+         * Visits an instruction which has a (possibly synthetic)
+         * constant argument, and possibly also an
+         * additional literal integer argument. In the case of
+         * {@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}, the {@code value} field always
+         * holds the raw value (for convenience of clients).
+         *
+         * <p><b>Note:</b> In order to avoid giving it a barely-useful
+         * visitor all its own, {@code newarray} also uses this
+         * form, passing {@code value} as the array type code and
+         * {@code cst} as a {@link CstType} instance
+         * corresponding to the array type.</p>
+         *
+         * @param opcode the opcode
+         * @param offset offset to the instruction
+         * @param length length of the instruction, in bytes
+         * @param cst {@code non-null;} the constant
+         * @param value additional literal integer argument, if salient
+         * (ignore if not)
+         */
+        public void visitConstant(int opcode, int offset, int length,
+                Constant cst, int value);
+
+        /**
+         * Visits an instruction which has a branch target argument.
+         *
+         * @param opcode the opcode
+         * @param offset offset to the instruction
+         * @param length length of the instruction, in bytes
+         * @param target the absolute (not relative) branch target
+         */
+        public void visitBranch(int opcode, int offset, int length,
+                int target);
+
+        /**
+         * Visits a switch instruction.
+         *
+         * @param opcode the opcode
+         * @param offset offset to the instruction
+         * @param length length of the instruction, in bytes
+         * @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
+         */
+        public void visitSwitch(int opcode, int offset, int length,
+                SwitchList cases, int padding);
+
+        /**
+         * Visits a newarray instruction.
+         *
+         * @param offset   offset to the instruction
+         * @param length   length of the instruction, in bytes
+         * @param type {@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);
+
+        /**
+         * Set previous bytecode offset
+         * @param offset    offset of the previous fully parsed bytecode
+         */
+        public void setPreviousOffset(int offset);
+
+        /**
+         * Get previous bytecode offset
+         * @return return the recored offset of the previous bytecode
+         */
+        public int getPreviousOffset();
+    }
+
+    /**
+     * Base implementation of {@link Visitor}, which has empty method
+     * bodies for all methods.
+     */
+    public static class BaseVisitor implements Visitor {
+
+        /** offset of the previously parsed bytecode */
+        private int previousOffset;
+
+        BaseVisitor() {
+            previousOffset = -1;
+        }
+
+        /** {@inheritDoc} */
+        public void visitInvalid(int opcode, int offset, int length) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitNoArgs(int opcode, int offset, int length,
+                Type type) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitLocal(int opcode, int offset, int length,
+                int idx, Type type, int value) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitConstant(int opcode, int offset, int length,
+                Constant cst, int value) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitBranch(int opcode, int offset, int length,
+                int target) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitch(int opcode, int offset, int length,
+                SwitchList cases, int padding) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitNewarray(int offset, int length, CstType type,
+                ArrayList<Constant> initValues) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void setPreviousOffset(int offset) {
+            previousOffset = offset;
+        }
+
+        /** {@inheritDoc} */
+        public int getPreviousOffset() {
+            return previousOffset;
+        }
+    }
+
+    /**
+     * Implementation of {@link Visitor}, which just pays attention
+     * to constant values.
+     */
+    class ConstantParserVisitor extends BaseVisitor {
+        Constant cst;
+        int length;
+        int value;
+
+        /** Empty constructor */
+        ConstantParserVisitor() {
+        }
+
+        private void clear() {
+            length = 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitInvalid(int opcode, int offset, int length) {
+            clear();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitNoArgs(int opcode, int offset, int length,
+                Type type) {
+            clear();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitLocal(int opcode, int offset, int length,
+                int idx, Type type, int value) {
+            clear();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitConstant(int opcode, int offset, int length,
+                Constant cst, int value) {
+            this.cst = cst;
+            this.length = length;
+            this.value = value;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitBranch(int opcode, int offset, int length,
+                int target) {
+            clear();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitSwitch(int opcode, int offset, int length,
+                SwitchList cases, int padding) {
+            clear();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitNewarray(int offset, int length, CstType type,
+                ArrayList<Constant> initVals) {
+            clear();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void setPreviousOffset(int offset) {
+            // Intentionally left empty
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int getPreviousOffset() {
+            // Intentionally left empty
+            return -1;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/ConcreteMethod.java b/dx/src/com/android/dx/cf/code/ConcreteMethod.java
new file mode 100644
index 0000000..39c2399
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ConcreteMethod.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.cf.attrib.AttCode;
+import com.android.dx.cf.attrib.AttLineNumberTable;
+import com.android.dx.cf.attrib.AttLocalVariableTable;
+import com.android.dx.cf.attrib.AttLocalVariableTypeTable;
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.ClassFile;
+import com.android.dx.cf.iface.Method;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+
+/**
+ * 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} attribute.
+ */
+public final class ConcreteMethod implements Method {
+    /** {@code non-null;} method being wrapped */
+    private final Method method;
+
+    /**
+     * {@code null-ok;} the class's {@code SourceFile} attribute value,
+     * if any
+     */
+    private final CstString sourceFile;
+
+    /**
+     * whether the class that this method is part of is defined with
+     * {@code ACC_SUPER}
+     */
+    private final boolean accSuper;
+
+    /** {@code non-null;} the code attribute */
+    private final AttCode attCode;
+
+    /** {@code non-null;} line number list */
+    private final LineNumberList lineNumbers;
+
+    /** {@code non-null;} local variable list */
+    private final LocalVariableList localVariables;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method to be based on
+     * @param cf {@code non-null;} the class file that contains this method
+     * @param keepLines whether to keep the line number information
+     * (if any)
+     * @param keepLocals whether to keep the local variable
+     * information (if any)
+     */
+    public ConcreteMethod(Method method, ClassFile cf, boolean keepLines, boolean keepLocals) {
+        this(method, cf.getAccessFlags(), cf.getSourceFile(), keepLines, keepLocals);
+    }
+
+    public ConcreteMethod(Method method, int accessFlags, CstString sourceFile,
+            boolean keepLines, boolean keepLocals) {
+        this.method = method;
+        this.accSuper = (accessFlags & AccessFlags.ACC_SUPER) != 0;
+        this.sourceFile = sourceFile;
+
+        AttributeList attribs = method.getAttributes();
+        this.attCode = (AttCode) attribs.findFirst(AttCode.ATTRIBUTE_NAME);
+
+        AttributeList codeAttribs = attCode.getAttributes();
+
+        /*
+         * Combine all LineNumberTable attributes into one, with the
+         * combined result saved into the instance. The following code
+         * isn't particularly efficient for doing merges, but as far
+         * as I know, this situation rarely occurs "in the
+         * wild," so there's not much point in optimizing for it.
+         */
+        LineNumberList lineNumbers = LineNumberList.EMPTY;
+        if (keepLines) {
+            for (AttLineNumberTable lnt = (AttLineNumberTable)
+                     codeAttribs.findFirst(AttLineNumberTable.ATTRIBUTE_NAME);
+                 lnt != null;
+                 lnt = (AttLineNumberTable) codeAttribs.findNext(lnt)) {
+                lineNumbers = LineNumberList.concat(lineNumbers,
+                        lnt.getLineNumbers());
+            }
+        }
+        this.lineNumbers = lineNumbers;
+
+        LocalVariableList localVariables = LocalVariableList.EMPTY;
+        if (keepLocals) {
+            /*
+             * Do likewise (and with the same caveat) for
+             * LocalVariableTable and LocalVariableTypeTable attributes.
+             * This combines both of these kinds of attribute into a
+             * single LocalVariableList.
+             */
+            for (AttLocalVariableTable lvt = (AttLocalVariableTable)
+                     codeAttribs.findFirst(
+                             AttLocalVariableTable.ATTRIBUTE_NAME);
+                 lvt != null;
+                 lvt = (AttLocalVariableTable) codeAttribs.findNext(lvt)) {
+                localVariables =
+                    LocalVariableList.concat(localVariables,
+                            lvt.getLocalVariables());
+            }
+
+            LocalVariableList typeList = LocalVariableList.EMPTY;
+            for (AttLocalVariableTypeTable lvtt = (AttLocalVariableTypeTable)
+                     codeAttribs.findFirst(
+                             AttLocalVariableTypeTable.ATTRIBUTE_NAME);
+                 lvtt != null;
+                 lvtt =
+                     (AttLocalVariableTypeTable) codeAttribs.findNext(lvtt)) {
+                typeList =
+                    LocalVariableList.concat(typeList,
+                            lvtt.getLocalVariables());
+            }
+
+            if (typeList.size() != 0) {
+                localVariables =
+                    LocalVariableList.mergeDescriptorsAndSignatures(
+                            localVariables, typeList);
+            }
+        }
+        this.localVariables = localVariables;
+    }
+
+    /** {@inheritDoc} */
+    public CstNat getNat() {
+        return method.getNat();
+    }
+
+    /** {@inheritDoc} */
+    public CstString getName() {
+        return method.getName();
+    }
+
+    /** {@inheritDoc} */
+    public CstString getDescriptor() {
+        return method.getDescriptor();
+    }
+
+    /** {@inheritDoc} */
+    public int getAccessFlags() {
+        return method.getAccessFlags();
+    }
+
+    /** {@inheritDoc} */
+    public AttributeList getAttributes() {
+        return method.getAttributes();
+    }
+
+    /** {@inheritDoc} */
+    public CstType getDefiningClass() {
+        return method.getDefiningClass();
+    }
+
+    /** {@inheritDoc} */
+    public Prototype getEffectiveDescriptor() {
+        return method.getEffectiveDescriptor();
+    }
+
+    /**
+     * Gets whether the class that this method is part of is defined with
+     * {@code ACC_SUPER}.
+     *
+     * @return the {@code ACC_SUPER} value
+     */
+    public boolean getAccSuper() {
+        return accSuper;
+    }
+
+    /**
+     * Gets the maximum stack size.
+     *
+     * @return {@code >= 0;} the maximum stack size
+     */
+    public int getMaxStack() {
+        return attCode.getMaxStack();
+    }
+
+    /**
+     * Gets the number of locals.
+     *
+     * @return {@code >= 0;} the number of locals
+     */
+    public int getMaxLocals() {
+        return attCode.getMaxLocals();
+    }
+
+    /**
+     * Gets the bytecode array.
+     *
+     * @return {@code non-null;} the bytecode array
+     */
+    public BytecodeArray getCode() {
+        return attCode.getCode();
+    }
+
+    /**
+     * Gets the exception table.
+     *
+     * @return {@code non-null;} the exception table
+     */
+    public ByteCatchList getCatches() {
+        return attCode.getCatches();
+    }
+
+    /**
+     * Gets the line number list.
+     *
+     * @return {@code non-null;} the line number list
+     */
+    public LineNumberList getLineNumbers() {
+        return lineNumbers;
+    }
+
+    /**
+     * Gets the local variable list.
+     *
+     * @return {@code non-null;} the local variable list
+     */
+    public LocalVariableList getLocalVariables() {
+        return localVariables;
+    }
+
+    /**
+     * Returns a {@link SourcePosition} instance corresponding to the
+     * given bytecode offset.
+     *
+     * @param offset {@code >= 0;} the bytecode offset
+     * @return {@code non-null;} an appropriate instance
+     */
+    public SourcePosition makeSourcePosistion(int offset) {
+        return new SourcePosition(sourceFile, offset,
+                                  lineNumbers.pcToLine(offset));
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/ExecutionStack.java b/dx/src/com/android/dx/cf/code/ExecutionStack.java
new file mode 100644
index 0000000..51f6334
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ExecutionStack.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+import com.android.dx.util.MutabilityControl;
+
+/**
+ * Representation of a Java method execution stack.
+ *
+ * <p><b>Note:</b> For the most part, the documentation for this class
+ * ignores the distinction between {@link Type} and {@link
+ * TypeBearer}.</p>
+ */
+public final class ExecutionStack extends MutabilityControl {
+    /** {@code non-null;} array of stack contents */
+    private final TypeBearer[] stack;
+
+    /**
+     * {@code non-null;} array specifying whether stack contents have entries
+     * in the local variable table
+     */
+    private final boolean[] local;
+    /**
+     * {@code >= 0;} stack pointer (points one past the end) / current stack
+     * size
+     */
+    private int stackPtr;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param maxStack {@code >= 0;} the maximum size of the stack for this
+     * instance
+     */
+    public ExecutionStack(int maxStack) {
+        super(maxStack != 0);
+        stack = new TypeBearer[maxStack];
+        local = new boolean[maxStack];
+        stackPtr = 0;
+    }
+
+    /**
+     * Makes and returns a mutable copy of this instance.
+     *
+     * @return {@code non-null;} the copy
+     */
+    public ExecutionStack copy() {
+        ExecutionStack result = new ExecutionStack(stack.length);
+
+        System.arraycopy(stack, 0, result.stack, 0, stack.length);
+        System.arraycopy(local, 0, result.local, 0, local.length);
+        result.stackPtr = stackPtr;
+
+        return result;
+    }
+
+    /**
+     * Annotates (adds context to) the given exception with information
+     * about this instance.
+     *
+     * @param ex {@code non-null;} the exception to annotate
+     */
+    public void annotate(ExceptionWithContext ex) {
+        int limit = stackPtr - 1;
+
+        for (int i = 0; i <= limit; i++) {
+            String idx = (i == limit) ? "top0" : Hex.u2(limit - i);
+
+            ex.addContext("stack[" + idx + "]: " +
+                          stackElementString(stack[i]));
+        }
+    }
+
+    /**
+     * Replaces all the occurrences of the given uninitialized type in
+     * this stack with its initialized equivalent.
+     *
+     * @param type {@code non-null;} type to replace
+     */
+    public void makeInitialized(Type type) {
+        if (stackPtr == 0) {
+            // We have to check for this before checking for immutability.
+            return;
+        }
+
+        throwIfImmutable();
+
+        Type initializedType = type.getInitializedType();
+
+        for (int i = 0; i < stackPtr; i++) {
+            if (stack[i] == type) {
+                stack[i] = initializedType;
+            }
+        }
+    }
+
+    /**
+     * Gets the maximum stack size for this instance.
+     *
+     * @return {@code >= 0;} the max stack size
+     */
+    public int getMaxStack() {
+        return stack.length;
+    }
+
+    /**
+     * Gets the current stack size.
+     *
+     * @return {@code >= 0, < getMaxStack();} the current stack size
+     */
+    public int size() {
+        return stackPtr;
+    }
+
+    /**
+     * Clears the stack. (That is, this method pops everything off.)
+     */
+    public void clear() {
+        throwIfImmutable();
+
+        for (int i = 0; i < stackPtr; i++) {
+            stack[i] = null;
+            local[i] = false;
+        }
+
+        stackPtr = 0;
+    }
+
+    /**
+     * Pushes a value of the given type onto the stack.
+     *
+     * @param type {@code non-null;} type of the value
+     * @throws SimException thrown if there is insufficient room on the
+     * stack for the value
+     */
+    public void push(TypeBearer type) {
+        throwIfImmutable();
+
+        int category;
+
+        try {
+            type = type.getFrameType();
+            category = type.getType().getCategory();
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("type == null");
+        }
+
+        if ((stackPtr + category) > stack.length) {
+            throwSimException("overflow");
+            return;
+        }
+
+        if (category == 2) {
+            stack[stackPtr] = null;
+            stackPtr++;
+        }
+
+        stack[stackPtr] = type;
+        stackPtr++;
+    }
+
+    /**
+     * Flags the next value pushed onto the stack as having local info.
+     */
+    public void setLocal() {
+        throwIfImmutable();
+
+        local[stackPtr] = true;
+    }
+
+    /**
+     * 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 {@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) {
+            throw new IllegalArgumentException("n < 0");
+        }
+
+        if (n >= stackPtr) {
+            return throwSimException("underflow");
+        }
+
+        return stack[stackPtr - n - 1];
+    }
+
+    /**
+     * Peeks at the {@code n}th element down from the top of the
+     * stack, returning whether or not it has local info.
+     *
+     * @param n {@code >= 0;} which element to peek at
+     * @return {@code true} if the value has local info, {@code false} otherwise
+     * @throws SimException thrown if {@code n >= size()}
+     */
+    public boolean peekLocal(int n) {
+        if (n < 0) {
+            throw new IllegalArgumentException("n < 0");
+        }
+
+        if (n >= stackPtr) {
+            throw new SimException("stack: underflow");
+        }
+
+        return local[stackPtr - n - 1];
+    }
+
+    /**
+     * 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()}.
+     *
+     * @see #peek
+     */
+    public Type peekType(int n) {
+        return peek(n).getType();
+    }
+
+    /**
+     * Pops the top element off of the stack.
+     *
+     * @return {@code non-null;} the type formerly on the top of the stack
+     * @throws SimException thrown if the stack is empty
+     */
+    public TypeBearer pop() {
+        throwIfImmutable();
+
+        TypeBearer result = peek(0);
+
+        stack[stackPtr - 1] = null;
+        local[stackPtr - 1] = false;
+        stackPtr -= result.getType().getCategory();
+
+        return result;
+    }
+
+    /**
+     * Changes an element already on a stack. This method is useful in limited
+     * contexts, particularly when merging two instances. As such, it places
+     * the following restriction on its behavior: You may only replace
+     * values with other values of the same category.
+     *
+     * @param n {@code >= 0;} which element to change, where {@code 0} is
+     * the top element of the stack
+     * @param type {@code non-null;} type of the new value
+     * @throws SimException thrown if {@code n >= size()} or
+     * the action is otherwise prohibited
+     */
+    public void change(int n, TypeBearer type) {
+        throwIfImmutable();
+
+        try {
+            type = type.getFrameType();
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("type == null");
+        }
+
+        int idx = stackPtr - n - 1;
+        TypeBearer orig = stack[idx];
+
+        if ((orig == null) ||
+            (orig.getType().getCategory() != type.getType().getCategory())) {
+            throwSimException("incompatible substitution: " +
+                              stackElementString(orig) + " -> " +
+                              stackElementString(type));
+        }
+
+        stack[idx] = type;
+    }
+
+    /**
+     * Merges this stack with another stack. A new instance is returned if
+     * this merge results in a change. If no change results, this instance is
+     * returned.  See {@link Merger#mergeStack(ExecutionStack,ExecutionStack)
+     * Merger.mergeStack()}
+     *
+     * @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 {
+            return Merger.mergeStack(this, other);
+        } catch (SimException ex) {
+            ex.addContext("underlay stack:");
+            this.annotate(ex);
+            ex.addContext("overlay stack:");
+            other.annotate(ex);
+            throw ex;
+        }
+    }
+
+    /**
+     * Gets the string form for a stack element. This is the same as
+     * {@code toString()} except that {@code null} is converted
+     * to {@code "<invalid>"}.
+     *
+     * @param type {@code null-ok;} the stack element
+     * @return {@code non-null;} the string form
+     */
+    private static String stackElementString(TypeBearer type) {
+        if (type == null) {
+            return "<invalid>";
+        }
+
+        return type.toString();
+    }
+
+    /**
+     * Throws a properly-formatted exception.
+     *
+     * @param msg {@code non-null;} useful message
+     * @return never (keeps compiler happy)
+     */
+    private static TypeBearer throwSimException(String msg) {
+        throw new SimException("stack: " + msg);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/Frame.java b/dx/src/com/android/dx/cf/code/Frame.java
new file mode 100644
index 0000000..002a4fb
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/Frame.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.IntList;
+
+/**
+ * Representation of a Java method execution frame. A frame consists
+ * of a set of locals and a value stack, and it can be told to act on
+ * them to load and store values between them and an "arguments /
+ * results" area.
+ */
+public final class Frame {
+    /** {@code non-null;} the locals */
+    private final LocalsArray locals;
+
+    /** {@code non-null;} the stack */
+    private final ExecutionStack stack;
+
+    /** {@code null-ok;} stack of labels of subroutines that this block is nested in */
+    private final IntList subroutines;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @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,
+            ExecutionStack stack, IntList subroutines) {
+        if (locals == null) {
+            throw new NullPointerException("locals == null");
+        }
+
+        if (stack == null) {
+            throw new NullPointerException("stack == null");
+        }
+
+        subroutines.throwIfMutable();
+
+        this.locals = locals;
+        this.stack = stack;
+        this.subroutines = subroutines;
+    }
+
+    /**
+     * Constructs an instance. The locals array initially consists of
+     * all-uninitialized values (represented as {@code null}s) and
+     * the stack starts out empty.
+     *
+     * @param maxLocals {@code >= 0;} the maximum number of locals this instance
+     * can refer to
+     * @param maxStack {@code >= 0;} the maximum size of the stack for this
+     * instance
+     */
+    public Frame(int maxLocals, int maxStack) {
+        this(new OneLocalsArray(maxLocals), new ExecutionStack(maxStack));
+    }
+
+    /**
+     * Makes and returns a mutable copy of this instance. The copy
+     * contains copies of the locals and stack (that is, it doesn't
+     * share them with the original).
+     *
+     * @return {@code non-null;} the copy
+     */
+    public Frame copy() {
+        return new Frame(locals.copy(), stack.copy(), subroutines);
+    }
+
+    /**
+     * Makes this instance immutable.
+     */
+    public void setImmutable() {
+        locals.setImmutable();
+        stack.setImmutable();
+        // "subroutines" is always immutable
+    }
+
+    /**
+     * Replaces all the occurrences of the given uninitialized type in
+     * this frame with its initialized equivalent.
+     *
+     * @param type {@code non-null;} type to replace
+     */
+    public void makeInitialized(Type type) {
+        locals.makeInitialized(type);
+        stack.makeInitialized(type);
+    }
+
+    /**
+     * Gets the locals array for this instance.
+     *
+     * @return {@code non-null;} the locals array
+     */
+    public LocalsArray getLocals() {
+        return locals;
+    }
+
+    /**
+     * Gets the execution stack for this instance.
+     *
+     * @return {@code non-null;} the execution stack
+     */
+    public ExecutionStack getStack() {
+        return stack;
+    }
+
+    /**
+     * Returns the largest subroutine nesting this block may be in. An
+     * empty list is returned if this block is not in any subroutine.
+     * Subroutines are identified by the label of their start block. The
+     * list is ordered such that the deepest nesting (the actual subroutine
+     * this block is in) is the last label in the list.
+     *
+     * @return {@code non-null;} list as noted above
+     */
+    public IntList getSubroutines() {
+        return subroutines;
+    }
+
+    /**
+     * Initialize this frame with the method's parameters. Used for the first
+     * frame.
+     *
+     * @param params Type list of method parameters.
+     */
+    public void initializeWithParameters(StdTypeList params) {
+        int at = 0;
+        int sz = params.size();
+
+        for (int i = 0; i < sz; i++) {
+             Type one = params.get(i);
+             locals.set(at, one);
+             at += one.getCategory();
+        }
+    }
+
+    /**
+     * Returns a Frame instance representing the frame state that should
+     * be used when returning from a subroutine. The stack state of all
+     * subroutine invocations is identical, but the locals state may differ.
+     *
+     * @param startLabel {@code >=0;} The label of the returning subroutine's
+     * start block
+     * @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) {
+        LocalsArray subLocals = null;
+
+        if (locals instanceof LocalsArraySet) {
+            subLocals = ((LocalsArraySet)locals).subArrayForLabel(subLabel);
+        }
+
+        IntList newSubroutines;
+        try {
+            newSubroutines = subroutines.mutableCopy();
+
+            if (newSubroutines.pop() != startLabel) {
+                throw new RuntimeException("returning from invalid subroutine");
+            }
+            newSubroutines.setImmutable();
+        } catch (IndexOutOfBoundsException ex) {
+            throw new RuntimeException("returning from invalid subroutine");
+        } catch (NullPointerException ex) {
+            throw new NullPointerException("can't return from non-subroutine");
+        }
+
+        return (subLocals == null) ? null
+                : new Frame(subLocals, stack, newSubroutines);
+    }
+
+    /**
+     * Merges two frames. If the merged result is the same as this frame,
+     * then this instance is returned.
+     *
+     * @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;
+        ExecutionStack resultStack;
+        IntList resultSubroutines;
+
+        resultLocals = getLocals().merge(other.getLocals());
+        resultStack = getStack().merge(other.getStack());
+        resultSubroutines = mergeSubroutineLists(other.subroutines);
+
+        resultLocals = adjustLocalsForSubroutines(
+                resultLocals, resultSubroutines);
+
+        if ((resultLocals == getLocals())
+                && (resultStack == getStack())
+                && subroutines == resultSubroutines) {
+            return this;
+        }
+
+        return new Frame(resultLocals, resultStack, resultSubroutines);
+    }
+
+    /**
+     * Merges this frame's subroutine lists with another. The result
+     * is the deepest common nesting (effectively, the common prefix of the
+     * two lists).
+     *
+     * @param otherSubroutines label list of subroutine start blocks, from
+     * least-nested to most-nested.
+     * @return {@code non-null;} merged subroutine nest list as described above
+     */
+    private IntList mergeSubroutineLists(IntList otherSubroutines) {
+        if (subroutines.equals(otherSubroutines)) {
+            return subroutines;
+        }
+
+        IntList resultSubroutines = new IntList();
+
+        int szSubroutines = subroutines.size();
+        int szOthers = otherSubroutines.size();
+        for (int i = 0; i < szSubroutines && i < szOthers
+                && (subroutines.get(i) == otherSubroutines.get(i)); i++) {
+            resultSubroutines.add(i);
+        }
+
+        resultSubroutines.setImmutable();
+
+        return resultSubroutines;
+    }
+
+    /**
+     * Adjusts a locals array to account for a merged subroutines list.
+     * If a frame merge results in, effectively, a subroutine return through
+     * a throw then the current locals will be a LocalsArraySet that will
+     * need to be trimmed of all OneLocalsArray elements that relevent to
+     * the subroutine that is returning.
+     *
+     * @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 {@code non-null;} locals set appropriate for merge
+     */
+    private static LocalsArray adjustLocalsForSubroutines(
+            LocalsArray locals, IntList subroutines) {
+        if (! (locals instanceof LocalsArraySet)) {
+            // nothing to see here
+            return locals;
+        }
+
+        LocalsArraySet laSet = (LocalsArraySet)locals;
+
+        if (subroutines.size() == 0) {
+            /*
+             * We've merged from a subroutine context to a non-subroutine
+             * context, likely via a throw. Our successor will only need
+             * to consider the primary locals state, not the state of
+             * all possible subroutine paths.
+             */
+
+            return laSet.getPrimary();
+        }
+
+        /*
+         * It's unclear to me if the locals set needs to be trimmed here.
+         * If it does, then I believe it is all of the calling blocks
+         * in the subroutine at the end of "subroutines" passed into
+         * this method that should be removed.
+         */
+        return laSet;
+    }
+
+    /**
+     * Merges this frame with the frame of a subroutine caller at
+     * {@code predLabel}. Only called on the frame at the first
+     * block of a subroutine.
+     *
+     * @param other {@code non-null;} another frame
+     * @param subLabel label of subroutine start block
+     * @param predLabel label of calling block
+     * @return {@code non-null;} the result of merging the two frames
+     */
+    public Frame mergeWithSubroutineCaller(Frame other, int subLabel,
+            int predLabel) {
+        LocalsArray resultLocals;
+        ExecutionStack resultStack;
+
+        resultLocals = getLocals().mergeWithSubroutineCaller(
+                other.getLocals(), predLabel);
+        resultStack = getStack().merge(other.getStack());
+
+        IntList newOtherSubroutines = other.subroutines.mutableCopy();
+        newOtherSubroutines.add(subLabel);
+        newOtherSubroutines.setImmutable();
+
+        if ((resultLocals == getLocals())
+                && (resultStack == getStack())
+                && subroutines.equals(newOtherSubroutines)) {
+            return this;
+        }
+
+        IntList resultSubroutines;
+
+        if (subroutines.equals(newOtherSubroutines)) {
+            resultSubroutines = subroutines;
+        } else {
+            /*
+             * The new subroutines list should be the deepest of the two
+             * lists being merged, but the postfix of the resultant list
+             * must be equal to the shorter list.
+             */
+            IntList nonResultSubroutines;
+
+            if (subroutines.size() > newOtherSubroutines.size()) {
+                resultSubroutines = subroutines;
+                nonResultSubroutines = newOtherSubroutines;
+            } else {
+                resultSubroutines = newOtherSubroutines;
+                nonResultSubroutines = subroutines;
+            }
+
+            int szResult = resultSubroutines.size();
+            int szNonResult = nonResultSubroutines.size();
+
+            for (int i = szNonResult - 1; i >=0; i-- ) {
+                if (nonResultSubroutines.get(i)
+                        != resultSubroutines.get(
+                        i + (szResult - szNonResult))) {
+                    throw new
+                            RuntimeException("Incompatible merged subroutines");
+                }
+            }
+
+        }
+
+        return new Frame(resultLocals, resultStack, resultSubroutines);
+    }
+
+    /**
+     * Makes a frame for a subroutine start block, given that this is the
+     * ending frame of one of the subroutine's calling blocks. Subroutine
+     * calls may be nested and thus may have nested locals state, so we
+     * start with an initial state as seen by the subroutine, but keep track
+     * of the individual locals states that will be expected when the individual
+     * subroutine calls return.
+     *
+     * @param subLabel label of subroutine start block
+     * @param callerLabel {@code >=0;} label of the caller block where this frame
+     * came from.
+     * @return a new instance to begin a called subroutine.
+     */
+    public Frame makeNewSubroutineStartFrame(int subLabel, int callerLabel) {
+        IntList newSubroutines = subroutines.mutableCopy();
+        newSubroutines.add(subLabel);
+        Frame newFrame = new Frame(locals.getPrimary(), stack,
+                IntList.makeImmutable(subLabel));
+        return newFrame.mergeWithSubroutineCaller(this, subLabel, callerLabel);
+    }
+
+    /**
+     * Makes a new frame for an exception handler block invoked from this
+     * frame.
+     *
+     * @param exceptionClass exception that the handler block will handle
+     * @return new frame
+     */
+    public Frame makeExceptionHandlerStartFrame(CstType exceptionClass) {
+        ExecutionStack newStack = getStack().copy();
+
+        newStack.clear();
+        newStack.push(exceptionClass);
+
+        return new Frame(getLocals(), newStack, subroutines);
+    }
+
+    /**
+     * Annotates (adds context to) the given exception with information
+     * about this frame.
+     *
+     * @param ex {@code non-null;} the exception to annotate
+     */
+    public void annotate(ExceptionWithContext ex) {
+        locals.annotate(ex);
+        stack.annotate(ex);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/LineNumberList.java b/dx/src/com/android/dx/cf/code/LineNumberList.java
new file mode 100644
index 0000000..f54f8b5
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/LineNumberList.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * List of "line number" entries, which are the contents of
+ * {@code LineNumberTable} attributes.
+ */
+public final class LineNumberList extends FixedSizeList {
+    /** {@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 {@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) {
+        if (list1 == EMPTY) {
+            // easy case
+            return list2;
+        }
+
+        int sz1 = list1.size();
+        int sz2 = list2.size();
+        LineNumberList result = new LineNumberList(sz1 + sz2);
+
+        for (int i = 0; i < sz1; i++) {
+            result.set(i, list1.get(i));
+        }
+
+        for (int i = 0; i < sz2; i++) {
+            result.set(sz1 + i, list2.get(i));
+        }
+
+        return result;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param count the number of elements to be in the list
+     */
+    public LineNumberList(int count) {
+        super(count);
+    }
+
+    /**
+     * Gets 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);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param item {@code non-null;} the item
+     */
+    public void set(int n, Item item) {
+        if (item == null) {
+            throw new NullPointerException("item == null");
+        }
+
+        set0(n, item);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param startPc {@code >= 0;} start pc of this item
+     * @param lineNumber {@code >= 0;} corresponding line number
+     */
+    public void set(int n, int startPc, int lineNumber) {
+        set0(n, new Item(startPc, lineNumber));
+    }
+
+    /**
+     * Gets the line number associated with the given address.
+     *
+     * @param pc {@code >= 0;} the address to look up
+     * @return {@code >= -1;} the associated line number, or {@code -1} if
+     * none is known
+     */
+    public int pcToLine(int pc) {
+        /*
+         * Line number entries don't have to appear in any particular
+         * order, so we have to do a linear search. TODO: If
+         * this turns out to be a bottleneck, consider sorting the
+         * list prior to use.
+         */
+        int sz = size();
+        int bestPc = -1;
+        int bestLine = -1;
+
+        for (int i = 0; i < sz; i++) {
+            Item one = get(i);
+            int onePc = one.getStartPc();
+            if ((onePc <= pc) && (onePc > bestPc)) {
+                bestPc = onePc;
+                bestLine = one.getLineNumber();
+                if (bestPc == pc) {
+                    // We can't do better than this
+                    break;
+                }
+            }
+        }
+
+        return bestLine;
+    }
+
+    /**
+     * Item in a line number table.
+     */
+    public static class Item {
+        /** {@code >= 0;} start pc of this item */
+        private final int startPc;
+
+        /** {@code >= 0;} corresponding line number */
+        private final int lineNumber;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("startPc < 0");
+            }
+
+            if (lineNumber < 0) {
+                throw new IllegalArgumentException("lineNumber < 0");
+            }
+
+            this.startPc = startPc;
+            this.lineNumber = lineNumber;
+        }
+
+        /**
+         * Gets the start pc of this item.
+         *
+         * @return the start pc
+         */
+        public int getStartPc() {
+            return startPc;
+        }
+
+        /**
+         * Gets the line number of this item.
+         *
+         * @return the line number
+         */
+        public int getLineNumber() {
+            return lineNumber;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/LocalVariableList.java b/dx/src/com/android/dx/cf/code/LocalVariableList.java
new file mode 100644
index 0000000..2962698
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/LocalVariableList.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * List of "local variable" entries, which are the contents of
+ * {@code LocalVariableTable} and {@code LocalVariableTypeTable}
+ * attributes, as well as combinations of the two.
+ */
+public final class LocalVariableList extends FixedSizeList {
+    /** {@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 {@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) {
+        if (list1 == EMPTY) {
+            // easy case
+            return list2;
+        }
+
+        int sz1 = list1.size();
+        int sz2 = list2.size();
+        LocalVariableList result = new LocalVariableList(sz1 + sz2);
+
+        for (int i = 0; i < sz1; i++) {
+            result.set(i, list1.get(i));
+        }
+
+        for (int i = 0; i < sz2; i++) {
+            result.set(sz1 + i, list2.get(i));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Returns an instance which is the result of merging the two
+     * given instances, where one instance should have only type
+     * descriptors and the other only type signatures. The merged
+     * result is identical to the one with descriptors, except that
+     * any element whose {name, index, start, length} matches an
+     * element in the signature list gets augmented with the
+     * corresponding signature. The result is immutable.
+     *
+     * @param descriptorList {@code non-null;} list with descriptors
+     * @param signatureList {@code non-null;} list with signatures
+     * @return {@code non-null;} the merged result
+     */
+    public static LocalVariableList mergeDescriptorsAndSignatures(
+            LocalVariableList descriptorList,
+            LocalVariableList signatureList) {
+        int descriptorSize = descriptorList.size();
+        LocalVariableList result = new LocalVariableList(descriptorSize);
+
+        for (int i = 0; i < descriptorSize; i++) {
+            Item item = descriptorList.get(i);
+            Item signatureItem = signatureList.itemToLocal(item);
+            if (signatureItem != null) {
+                CstString signature = signatureItem.getSignature();
+                item = item.withSignature(signature);
+            }
+            result.set(i, item);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param count the number of elements to be in the list
+     */
+    public LocalVariableList(int count) {
+        super(count);
+    }
+
+    /**
+     * Gets 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);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param item {@code non-null;} the item
+     */
+    public void set(int n, Item item) {
+        if (item == null) {
+            throw new NullPointerException("item == null");
+        }
+
+        set0(n, item);
+    }
+
+    /**
+     * Sets the item at the given index.
+     *
+     * <p><b>Note:</b> At least one of {@code descriptor} or
+     * {@code signature} must be passed as non-null.</p>
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param startPc {@code >= 0;} the start pc of this variable's scope
+     * @param length {@code >= 0;} the length (in bytecodes) of this variable's
+     * scope
+     * @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, CstString name,
+            CstString descriptor, CstString signature, int index) {
+        set0(n, new Item(startPc, length, name, descriptor, signature, index));
+    }
+
+    /**
+     * Gets the local variable information in this instance which matches
+     * the given {@link com.android.dx.cf.code.LocalVariableList.Item}
+     * in all respects but the type descriptor and signature, if any.
+     *
+     * @param item {@code non-null;} local variable information to match
+     * @return {@code null-ok;} the corresponding local variable information stored
+     * in this instance, or {@code null} if there is no matching
+     * information
+     */
+    public Item itemToLocal(Item item) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            Item one = (Item) get0(i);
+
+            if ((one != null) && one.matchesAllButType(item)) {
+                return one;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets the local variable information associated with a given address
+     * and local index, if any. <b>Note:</b> In standard classfiles, a
+     * variable's start point is listed as the address of the instruction
+     * <i>just past</i> the one that sets the variable.
+     *
+     * @param pc {@code >= 0;} the address to look up
+     * @param index {@code >= 0;} the local variable index
+     * @return {@code null-ok;} the associated local variable information, or
+     * {@code null} if none is known
+     */
+    public Item pcAndIndexToLocal(int pc, int index) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            Item one = (Item) get0(i);
+
+            if ((one != null) && one.matchesPcAndIndex(pc, index)) {
+                return one;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Item in a local variable table.
+     */
+    public static class Item {
+        /** {@code >= 0;} the start pc of this variable's scope */
+        private final int startPc;
+
+        /** {@code >= 0;} the length (in bytecodes) of this variable's scope */
+        private final int length;
+
+        /** {@code non-null;} the variable's name */
+        private final CstString name;
+
+        /** {@code null-ok;} the variable's type descriptor */
+        private final CstString descriptor;
+
+        /** {@code null-ok;} the variable's type signature */
+        private final CstString signature;
+
+        /** {@code >= 0;} the variable's local index */
+        private final int index;
+
+        /**
+         * Constructs an instance.
+         *
+         * <p><b>Note:</b> At least one of {@code descriptor} or
+         * {@code signature} must be passed as non-null.</p>
+         *
+         * @param startPc {@code >= 0;} the start pc of this variable's scope
+         * @param length {@code >= 0;} the length (in bytecodes) of this variable's
+         * scope
+         * @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, CstString name,
+                CstString descriptor, CstString signature, int index) {
+            if (startPc < 0) {
+                throw new IllegalArgumentException("startPc < 0");
+            }
+
+            if (length < 0) {
+                throw new IllegalArgumentException("length < 0");
+            }
+
+            if (name == null) {
+                throw new NullPointerException("name == null");
+            }
+
+            if ((descriptor == null) && (signature == null)) {
+                throw new NullPointerException(
+                        "(descriptor == null) && (signature == null)");
+            }
+
+            if (index < 0) {
+                throw new IllegalArgumentException("index < 0");
+            }
+
+            this.startPc = startPc;
+            this.length = length;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.index = index;
+        }
+
+        /**
+         * Gets the start pc of this variable's scope.
+         *
+         * @return {@code >= 0;} the start pc of this variable's scope
+         */
+        public int getStartPc() {
+            return startPc;
+        }
+
+        /**
+         * Gets the length (in bytecodes) of this variable's scope.
+         *
+         * @return {@code >= 0;} the length (in bytecodes) of this variable's scope
+         */
+        public int getLength() {
+            return length;
+        }
+
+        /**
+         * Gets the variable's type descriptor.
+         *
+         * @return {@code null-ok;} the variable's type descriptor
+         */
+        public CstString getDescriptor() {
+            return descriptor;
+        }
+
+        /**
+         * Gets the variable's LocalItem, a (name, signature) tuple
+         *
+         * @return {@code null-ok;} the variable's type descriptor
+         */
+        public LocalItem getLocalItem() {
+            return LocalItem.make(name, signature);
+        }
+
+        /**
+         * Gets the variable's type signature. Private because if you need this,
+         * you want getLocalItem() instead.
+         *
+         * @return {@code null-ok;} the variable's type signature
+         */
+        private CstString getSignature() {
+            return signature;
+        }
+
+        /**
+         * Gets the variable's local index.
+         *
+         * @return {@code >= 0;} the variable's local index
+         */
+        public int getIndex() {
+            return index;
+        }
+
+        /**
+         * Gets the variable's type descriptor. This is a convenient shorthand
+         * for {@code Type.intern(getDescriptor().getString())}.
+         *
+         * @return {@code non-null;} the variable's type
+         */
+        public Type getType() {
+            return Type.intern(descriptor.getString());
+        }
+
+        /**
+         * Constructs and returns an instance which is identical to this
+         * one, except that the signature is changed to the given value.
+         *
+         * @param newSignature {@code non-null;} the new signature
+         * @return {@code non-null;} an appropriately-constructed instance
+         */
+        public Item withSignature(CstString newSignature) {
+            return new Item(startPc, length, name, descriptor, newSignature,
+                    index);
+        }
+
+        /**
+         * Gets whether this instance matches (describes) the given
+         * address and index.
+         *
+         * @param pc {@code >= 0;} the address in question
+         * @param index {@code >= 0;} the local variable index in question
+         * @return {@code true} iff this instance matches {@code pc}
+         * and {@code index}
+         */
+        public boolean matchesPcAndIndex(int pc, int index) {
+            return (index == this.index) &&
+                (pc >= startPc) &&
+                (pc < (startPc + length));
+        }
+
+        /**
+         * Gets whether this instance matches (describes) the given
+         * other instance exactly in all fields except type descriptor and
+         * type signature.
+         *
+         * @param other {@code non-null;} the instance to compare to
+         * @return {@code true} iff this instance matches
+         */
+        public boolean matchesAllButType(Item other) {
+            return (startPc == other.startPc)
+                && (length == other.length)
+                && (index == other.index)
+                && name.equals(other.name);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/LocalsArray.java b/dx/src/com/android/dx/cf/code/LocalsArray.java
new file mode 100644
index 0000000..75af047
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/LocalsArray.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+import com.android.dx.util.MutabilityControl;
+import com.android.dx.util.ToHuman;
+
+/**
+ * Representation of an array of local variables, with Java semantics.
+ *
+ * <p><b>Note:</b> For the most part, the documentation for this class
+ * ignores the distinction between {@link Type} and {@link
+ * TypeBearer}.</p>
+ */
+public abstract class LocalsArray extends MutabilityControl implements ToHuman {
+
+    /**
+     * Constructs an instance, explicitly indicating the mutability.
+     *
+     * @param mutable {@code true} if this instance is mutable
+     */
+    protected LocalsArray(boolean mutable) {
+        super(mutable);
+    }
+
+    /**
+     * Makes and returns a mutable copy of this instance.
+     *
+     * @return {@code non-null;} the copy
+     */
+    public abstract LocalsArray copy();
+
+    /**
+     * Annotates (adds context to) the given exception with information
+     * about this instance.
+     *
+     * @param ex {@code non-null;} the exception to annotate
+     */
+    public abstract void annotate(ExceptionWithContext ex);
+
+    /**
+     * Replaces all the occurrences of the given uninitialized type in
+     * this array with its initialized equivalent.
+     *
+     * @param type {@code non-null;} type to replace
+     */
+    public abstract void makeInitialized(Type type);
+
+    /**
+     * Gets the maximum number of locals this instance can refer to.
+     *
+     * @return the max locals
+     */
+    public abstract int getMaxLocals();
+
+    /**
+     * 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
+     * {@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 {@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);
+
+    /**
+     * 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)}.
+     *
+     * @param spec {@code non-null;} register spec to use as the basis for the update
+     */
+    public abstract void set(RegisterSpec spec);
+
+    /**
+     * Invalidates the local at the given index.
+     *
+     * @param idx {@code >= 0, < getMaxLocals();} which local
+     */
+    public abstract void invalidate(int idx);
+
+    /**
+     * Gets the type stored at the given local index, or {@code null}
+     * if the given local is uninitialized / invalid.
+     *
+     * @param idx {@code >= 0, < getMaxLocals();} which local
+     * @return {@code null-ok;} the type of value stored in that local
+     */
+    public abstract TypeBearer getOrNull(int idx);
+
+    /**
+     * Gets the type stored at the given local index, only succeeding if
+     * the given local contains a valid type (though it is allowed to
+     * be an uninitialized instance).
+     *
+     * @param idx {@code >= 0, < getMaxLocals();} which local
+     * @return {@code non-null;} the type of value stored in that local
+     * @throws SimException thrown if {@code idx} is valid, but
+     * the contents are invalid
+     */
+    public abstract TypeBearer get(int idx);
+
+    /**
+     * Gets the type stored at the given local index, which is expected
+     * to be an initialized category-1 value.
+     *
+     * @param idx {@code >= 0, < getMaxLocals();} which local
+     * @return {@code non-null;} the type of value stored in that local
+     * @throws SimException thrown if {@code idx} is valid, but
+     * 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
+     */
+    public abstract TypeBearer getCategory1(int idx);
+
+    /**
+     * Gets the type stored at the given local index, which is expected
+     * to be a category-2 value.
+     *
+     * @param idx {@code >= 0, < getMaxLocals();} which local
+     * @return {@code non-null;} the type of value stored in that local
+     * @throws SimException thrown if {@code idx} is valid, but
+     * 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}. If the merged result is
+     * the same as this instance, then this is returned (not a copy).
+     *
+     * @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} from a subroutine
+     * caller. To be used when merging in the first block of a subroutine.
+     *
+     * @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 {@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} instance, then return
+     * {@code this}, otherwise return {@code LocalsArraySet}'s
+     * primary.
+     *
+     * @return locals for this execution context.
+     */
+    protected abstract OneLocalsArray getPrimary();
+
+}
diff --git a/dx/src/com/android/dx/cf/code/LocalsArraySet.java b/dx/src/com/android/dx/cf/code/LocalsArraySet.java
new file mode 100644
index 0000000..5d03055
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/LocalsArraySet.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+import com.android.dx.util.MutabilityControl;
+
+import java.util.ArrayList;
+
+/**
+ * Representation of a set of local variable arrays, with Java semantics.
+ * This peculiar case is to support in-method subroutines, which can
+ * have different locals sets for each caller.
+ *
+ * <p><b>Note:</b> For the most part, the documentation for this class
+ * ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link
+ * com.android.dx.rop.type.TypeBearer}.</p>
+ */
+public class LocalsArraySet extends LocalsArray {
+
+    /**
+     * The primary LocalsArray represents the locals as seen from
+     * the subroutine itself, which is the merged representation of all the
+     * individual locals states.
+     */
+    private final OneLocalsArray primary;
+
+    /**
+     * Indexed by label of caller block: the locals specific to each caller's
+     * invocation of the subroutine.
+     */
+    private final ArrayList<LocalsArray> secondaries;
+
+    /**
+     * Constructs an instance. The locals array initially consists of
+     * all-uninitialized values (represented as {@code null}s).
+     *
+     * @param maxLocals {@code >= 0;} the maximum number of locals this instance
+     * can refer to
+     */
+    public LocalsArraySet(int maxLocals) {
+        super(maxLocals != 0);
+        primary = new OneLocalsArray(maxLocals);
+        secondaries = new ArrayList();
+    }
+
+    /**
+     * Constructs an instance with the specified primary and secondaries set.
+     *
+     * @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,
+            ArrayList<LocalsArray> secondaries) {
+        super(primary.getMaxLocals() > 0);
+
+        this.primary = primary;
+        this.secondaries = secondaries;
+    }
+
+    /**
+     * Constructs an instance which is a copy of another.
+     *
+     * @param toCopy {@code non-null;} instance to copy.
+     */
+    private LocalsArraySet(LocalsArraySet toCopy) {
+        super(toCopy.getMaxLocals() > 0);
+
+        primary = toCopy.primary.copy();
+        secondaries = new ArrayList(toCopy.secondaries.size());
+
+        int sz = toCopy.secondaries.size();
+        for (int i = 0; i < sz; i++) {
+            LocalsArray la = toCopy.secondaries.get(i);
+
+            if (la == null) {
+                secondaries.add(null);
+            } else {
+                secondaries.add(la.copy());
+            }
+        }
+    }
+
+
+    /** @inheritDoc */
+    @Override
+    public void setImmutable() {
+        primary.setImmutable();
+
+        for (LocalsArray la : secondaries) {
+            if (la != null) {
+                la.setImmutable();
+            }
+        }
+        super.setImmutable();
+    }
+
+    /** @inheritDoc */
+    @Override
+    public LocalsArray copy() {
+        return new LocalsArraySet(this);
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void annotate(ExceptionWithContext ex) {
+        ex.addContext("(locals array set; primary)");
+        primary.annotate(ex);
+
+        int sz = secondaries.size();
+        for (int label = 0; label < sz; label++) {
+            LocalsArray la = secondaries.get(label);
+
+            if (la != null) {
+                ex.addContext("(locals array set: primary for caller "
+                        + Hex.u2(label) + ')');
+
+                la.getPrimary().annotate(ex);
+            }
+        }
+    }
+
+    /** {@inheritDoc*/
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("(locals array set; primary)\n");
+
+        sb.append(getPrimary().toHuman());
+        sb.append('\n');
+
+        int sz = secondaries.size();
+        for (int label = 0; label < sz; label++) {
+            LocalsArray la = secondaries.get(label);
+
+            if (la != null) {
+                sb.append("(locals array set: primary for caller "
+                        + Hex.u2(label) + ")\n");
+
+                sb.append(la.getPrimary().toHuman());
+                sb.append('\n');
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void makeInitialized(Type type) {
+        int len = primary.getMaxLocals();
+
+        if (len == 0) {
+            // We have to check for this before checking for immutability.
+            return;
+        }
+
+        throwIfImmutable();
+
+        primary.makeInitialized(type);
+
+        for (LocalsArray la : secondaries) {
+            if (la != null) {
+                la.makeInitialized(type);
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    @Override
+    public int getMaxLocals() {
+        return primary.getMaxLocals();
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void set(int idx, TypeBearer type) {
+        throwIfImmutable();
+
+        primary.set(idx, type);
+
+        for (LocalsArray la : secondaries) {
+            if (la != null) {
+                la.set(idx, type);
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void set(RegisterSpec spec) {
+        set(spec.getReg(), spec);
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void invalidate(int idx) {
+        throwIfImmutable();
+
+        primary.invalidate(idx);
+
+        for (LocalsArray la : secondaries) {
+            if (la != null) {
+                la.invalidate(idx);
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    @Override
+    public TypeBearer getOrNull(int idx) {
+        return primary.getOrNull(idx);
+    }
+
+    /** @inheritDoc */
+    @Override
+    public TypeBearer get(int idx) {
+        return primary.get(idx);
+    }
+
+    /** @inheritDoc */
+    @Override
+    public TypeBearer getCategory1(int idx) {
+        return primary.getCategory1(idx);
+    }
+
+    /** @inheritDoc */
+    @Override
+    public TypeBearer getCategory2(int idx) {
+        return primary.getCategory2(idx);
+    }
+
+    /**
+     * Merges this set with another {@code LocalsArraySet} instance.
+     *
+     * @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) {
+        OneLocalsArray newPrimary;
+        ArrayList<LocalsArray> newSecondaries;
+        boolean secondariesChanged = false;
+
+        newPrimary = primary.merge(other.getPrimary());
+
+        int sz1 = secondaries.size();
+        int sz2 = other.secondaries.size();
+        int sz = Math.max(sz1, sz2);
+        newSecondaries = new ArrayList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            LocalsArray la1 = (i < sz1 ? secondaries.get(i) : null);
+            LocalsArray la2 = (i < sz2 ? other.secondaries.get(i) : null);
+            LocalsArray resultla = null;
+
+            if (la1 == la2) {
+                resultla = la1;
+            } else if (la1 == null) {
+                resultla = la2;
+            } else if (la2 == null) {
+                resultla = la1;
+            } else {
+                try {
+                    resultla = la1.merge(la2);
+                } catch (SimException ex) {
+                    ex.addContext(
+                            "Merging locals set for caller block " + Hex.u2(i));
+                }
+            }
+
+            secondariesChanged = secondariesChanged || (la1 != resultla);
+
+            newSecondaries.add(resultla);
+        }
+
+        if ((primary == newPrimary) && ! secondariesChanged ) {
+            return this;
+        }
+
+        return new LocalsArraySet(newPrimary, newSecondaries);
+    }
+
+    /**
+     * Merges this set with a {@code OneLocalsArray} instance.
+     *
+     * @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) {
+        OneLocalsArray newPrimary;
+        ArrayList<LocalsArray> newSecondaries;
+        boolean secondariesChanged = false;
+
+        newPrimary = primary.merge(other.getPrimary());
+        newSecondaries = new ArrayList(secondaries.size());
+
+        int sz = secondaries.size();
+        for (int i = 0; i < sz; i++) {
+            LocalsArray la = secondaries.get(i);
+            LocalsArray resultla = null;
+
+            if (la != null) {
+                try {
+                    resultla = la.merge(other);
+                } catch (SimException ex) {
+                    ex.addContext("Merging one locals against caller block "
+                                    + Hex.u2(i));
+                }
+            }
+
+            secondariesChanged = secondariesChanged || (la != resultla);
+
+            newSecondaries.add(resultla);
+        }
+
+        if ((primary == newPrimary) && ! secondariesChanged ) {
+            return this;
+        }
+
+        return new LocalsArraySet(newPrimary, newSecondaries);
+    }
+
+    /** @inheritDoc */
+    @Override
+    public LocalsArraySet merge(LocalsArray other) {
+        LocalsArraySet result;
+
+        try {
+            if (other instanceof LocalsArraySet) {
+                result = mergeWithSet((LocalsArraySet) other);
+            } else {
+                result = mergeWithOne((OneLocalsArray) other);
+            }
+        } catch (SimException ex) {
+            ex.addContext("underlay locals:");
+            annotate(ex);
+            ex.addContext("overlay locals:");
+            other.annotate(ex);
+            throw ex;
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Gets the {@code LocalsArray} instance for a specified subroutine
+     * caller label, or null if label has no locals associated with it.
+     *
+     * @param label {@code >= 0;} subroutine caller label
+     * @return {@code null-ok;} locals if available.
+     */
+    private LocalsArray getSecondaryForLabel(int label) {
+        if (label >= secondaries.size()) {
+            return null;
+        }
+
+        return secondaries.get(label);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public LocalsArraySet mergeWithSubroutineCaller
+            (LocalsArray other, int predLabel) {
+
+        LocalsArray mine = getSecondaryForLabel(predLabel);
+        LocalsArray newSecondary;
+        OneLocalsArray newPrimary;
+
+        newPrimary = primary.merge(other.getPrimary());
+
+        if (mine == other) {
+            newSecondary = mine;
+        } else if (mine == null) {
+            newSecondary = other;
+        } else {
+            newSecondary = mine.merge(other);
+        }
+
+        if ((newSecondary == mine) && (newPrimary == primary)) {
+            return this;
+        } else {
+            /*
+             * We're going to re-build a primary as a merge of all the
+             * secondaries.
+             */
+            newPrimary = null;
+
+            int szSecondaries = secondaries.size();
+            int sz = Math.max(predLabel + 1, szSecondaries);
+            ArrayList<LocalsArray> newSecondaries = new ArrayList(sz);
+            for (int i = 0; i < sz; i++) {
+                LocalsArray la = null;
+
+                if (i == predLabel) {
+                    /*
+                     * This LocalsArray always replaces any existing one,
+                     * since this is the result of a refined iteration.
+                     */
+                    la = newSecondary;
+                } else if (i < szSecondaries) {
+                    la = secondaries.get(i);
+                }
+
+                if (la != null) {
+                    if (newPrimary == null) {
+                        newPrimary = la.getPrimary();
+                    } else {
+                        newPrimary = newPrimary.merge(la.getPrimary());
+                    }
+                }
+
+                newSecondaries.add(la);
+            }
+
+            LocalsArraySet result
+                    = new LocalsArraySet(newPrimary, newSecondaries);
+            result.setImmutable();
+            return result;
+        }
+    }
+
+    /**
+     * Returns a LocalsArray instance representing the locals state that should
+     * be used when returning to a subroutine caller.
+     *
+     * @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) {
+        LocalsArray result = getSecondaryForLabel(subLabel);
+        return result;
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    protected OneLocalsArray getPrimary() {
+        return primary;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/Machine.java b/dx/src/com/android/dx/cf/code/Machine.java
new file mode 100644
index 0000000..a81feaf
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/Machine.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.code.LocalItem;
+import java.util.ArrayList;
+
+/**
+ * Interface for machines capable of executing bytecode by acting
+ * upon a {@link Frame}. A machine conceptually contains four arbitrary-value
+ * argument slots, slots for several literal-value arguments, and slots for
+ * branch target information.
+ */
+public interface Machine {
+    /**
+     * Gets the effective prototype of the method that this instance is
+     * being used for. The <i>effective</i> prototype includes an initial
+     * {@code this} argument for instance methods.
+     *
+     * @return {@code non-null;} the method prototype
+     */
+    public Prototype getPrototype();
+
+    /**
+     * Clears the regular and auxiliary arguments area.
+     */
+    public void clearArgs();
+
+    /**
+     * Pops the given number of values from the stack (of either category),
+     * and store them in the arguments area, indicating that there are now
+     * that many arguments. Also, clear the auxiliary arguments.
+     *
+     * @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} (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 {@code non-null;} frame to operate on
+     * @param prototype {@code non-null;} prototype indicating arguments to pop
+     */
+    public void popArgs(Frame frame, Prototype prototype);
+
+    /**
+     * Pops a value from the stack of the indicated type, and store it
+     * in the arguments area, indicating that there are now that many
+     * arguments. Also, clear the auxiliary arguments.
+     *
+     * @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);
+
+    /**
+     * Pops values from the stack of the indicated types (popped in
+     * reverse argument order, so the first indicated 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 {@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);
+
+    /**
+     * Pops values from the stack of the indicated types (popped in
+     * reverse argument order, so the first indicated 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 {@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);
+
+    /**
+     * Loads the local variable with the given index as the sole argument in
+     * the arguments area. Also, clear the auxiliary arguments.
+     *
+     * @param frame {@code non-null;} frame to operate on
+     * @param idx {@code >= 0;} the local variable index
+     */
+    public void localArg(Frame frame, int idx);
+
+    /**
+     * Used to specify if a loaded local variable has info in the local
+     * variable table.
+     *
+     * @param local {@code true} if local arg has info in local variable table
+     */
+    public void localInfo(boolean local);
+
+    /**
+     * 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} are collapsed to the {@code int}
+     * variant. (See {@link BytecodeArray#parseInstruction} for
+     * details.)
+     *
+     * @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}, with the given value.
+     *
+     * <p><b>Note:</b> Perhaps unintuitively, the stack manipulation
+     * 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} sets this to {@code 0x12312}, and the
+     * other form of that op sets this to
+     * {@code 0x121}.</p>
+     *
+     * <p><b>Also Note:</b> For {@code switch*} instructions, this is
+     * used to indicate the padding value (which is only useful for
+     * verification).</p>
+     *
+     * @param value the argument value
+     */
+    public void auxIntArg(int value);
+
+    /**
+     * 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} and
+     * constant auxiliary arguments.</p>
+     *
+     * @param cst {@code non-null;} the constant containing / referencing
+     * the value
+     */
+    public void auxCstArg(Constant cst);
+
+    /**
+     * Indicates that there is an auxiliary (inline, not stack) argument
+     * indicating a branch target.
+     *
+     * @param target the argument value
+     */
+    public void auxTargetArg(int target);
+
+    /**
+     * Indicates that there is an auxiliary (inline, not stack) argument
+     * 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 {@code non-null;} the list of key-target pairs, plus the default
+     * target
+     */
+    public void auxSwitchArg(SwitchList cases);
+
+    /**
+     * Indicates that there is an auxiliary (inline, not stack) argument
+     * consisting of a list of initial values for a newly created array.
+     *
+     * @param initValues {@code non-null;} the list of constant values to initialize
+     * the array
+     */
+    public void auxInitValues(ArrayList<Constant> initValues);
+
+    /**
+     * Indicates that the target of this operation is the given local.
+     *
+     * @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);
+
+    /**
+     * "Runs" the indicated opcode in an appropriate way, using the arguments
+     * area as appropriate, and modifying the given frame in response.
+     *
+     * @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 {@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
new file mode 100644
index 0000000..51c31c3
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/Merger.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.Hex;
+
+/**
+ * Utility methods to merge various frame information.
+ */
+public final class Merger {
+    /**
+     * This class is uninstantiable.
+     */
+    private Merger() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Merges two locals arrays. If the merged result is the same as the first
+     * argument, then return the first argument (not a copy).
+     *
+     * @param locals1 {@code non-null;} a locals array
+     * @param locals2 {@code non-null;} another locals array
+     * @return {@code non-null;} the result of merging the two locals arrays
+     */
+    public static OneLocalsArray mergeLocals(OneLocalsArray locals1,
+                                          OneLocalsArray locals2) {
+        if (locals1 == locals2) {
+            // Easy out.
+            return locals1;
+        }
+
+        int sz = locals1.getMaxLocals();
+        OneLocalsArray result = null;
+
+        if (locals2.getMaxLocals() != sz) {
+            throw new SimException("mismatched maxLocals values");
+        }
+
+        for (int i = 0; i < sz; i++) {
+            TypeBearer tb1 = locals1.getOrNull(i);
+            TypeBearer tb2 = locals2.getOrNull(i);
+            TypeBearer resultType = mergeType(tb1, tb2);
+            if (resultType != tb1) {
+                /*
+                 * We only need to do anything when the result differs
+                 * from what is in the first array, since that's what the
+                 * result gets initialized to.
+                 */
+                if (result == null) {
+                    result = locals1.copy();
+                }
+
+                if (resultType == null) {
+                    result.invalidate(i);
+                } else {
+                    result.set(i, resultType);
+                }
+            }
+        }
+
+        if (result == null) {
+            return locals1;
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Merges two stacks. If the merged result is the same as the first
+     * argument, then return the first argument (not a copy).
+     *
+     * @param stack1 {@code non-null;} a stack
+     * @param stack2 {@code non-null;} another stack
+     * @return {@code non-null;} the result of merging the two stacks
+     */
+    public static ExecutionStack mergeStack(ExecutionStack stack1,
+                                            ExecutionStack stack2) {
+        if (stack1 == stack2) {
+            // Easy out.
+            return stack1;
+        }
+
+        int sz = stack1.size();
+        ExecutionStack result = null;
+
+        if (stack2.size() != sz) {
+            throw new SimException("mismatched stack depths");
+        }
+
+        for (int i = 0; i < sz; i++) {
+            TypeBearer tb1 = stack1.peek(i);
+            TypeBearer tb2 = stack2.peek(i);
+            TypeBearer resultType = mergeType(tb1, tb2);
+            if (resultType != tb1) {
+                /*
+                 * We only need to do anything when the result differs
+                 * from what is in the first stack, since that's what the
+                 * result gets initialized to.
+                 */
+                if (result == null) {
+                    result = stack1.copy();
+                }
+
+                try {
+                    if (resultType == null) {
+                        throw new SimException("incompatible: " + tb1 + ", " +
+                                               tb2);
+                    } else {
+                        result.change(i, resultType);
+                    }
+                } catch (SimException ex) {
+                    ex.addContext("...while merging stack[" + Hex.u2(i) + "]");
+                    throw ex;
+                }
+            }
+        }
+
+        if (result == null) {
+            return stack1;
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Merges two frame types.
+     *
+     * @param ft1 {@code non-null;} a frame type
+     * @param ft2 {@code non-null;} another frame type
+     * @return {@code non-null;} the result of merging the two types
+     */
+    public static TypeBearer mergeType(TypeBearer ft1, TypeBearer ft2) {
+        if ((ft1 == null) || ft1.equals(ft2)) {
+            return ft1;
+        } else if (ft2 == null) {
+            return null;
+        } else {
+            Type type1 = ft1.getType();
+            Type type2 = ft2.getType();
+
+            if (type1 == type2) {
+                return type1;
+            } else if (type1.isReference() && type2.isReference()) {
+                if (type1 == Type.KNOWN_NULL) {
+                    /*
+                     * A known-null merges with any other reference type to
+                     * be that reference type.
+                     */
+                    return type2;
+                } else if (type2 == Type.KNOWN_NULL) {
+                    /*
+                     * The same as above, but this time it's type2 that's
+                     * the known-null.
+                     */
+                    return type1;
+                } else if (type1.isArray() && type2.isArray()) {
+                    TypeBearer componentUnion =
+                        mergeType(type1.getComponentType(),
+                                type2.getComponentType());
+                    if (componentUnion == null) {
+                        /*
+                         * At least one of the types is a primitive type,
+                         * so the merged result is just Object.
+                         */
+                        return Type.OBJECT;
+                    }
+                    return ((Type) componentUnion).getArrayType();
+                } else {
+                    /*
+                     * All other unequal reference types get merged to be
+                     * Object in this phase. This is fine here, but it
+                     * won't be the right thing to do in the verifier.
+                     */
+                    return Type.OBJECT;
+                }
+            } else if (type1.isIntlike() && type2.isIntlike()) {
+                /*
+                 * Merging two non-identical int-like types results in
+                 * the type int.
+                 */
+                return Type.INT;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Returns whether the given supertype is possibly assignable from
+     * 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} is the supertype of all reference
+     * types and all arrays are assignable to
+     * {@code Serializable} and {@code Cloneable}.
+     *
+     * @param supertypeBearer {@code non-null;} the supertype
+     * @param subtypeBearer {@code non-null;} the subtype
+     */
+    public static boolean isPossiblyAssignableFrom(TypeBearer supertypeBearer,
+            TypeBearer subtypeBearer) {
+        Type supertype = supertypeBearer.getType();
+        Type subtype = subtypeBearer.getType();
+
+        if (supertype.equals(subtype)) {
+            // Easy out.
+            return true;
+        }
+
+        int superBt = supertype.getBasicType();
+        int subBt = subtype.getBasicType();
+
+        // Treat return types as Object for the purposes of this method.
+
+        if (superBt == Type.BT_ADDR) {
+            supertype = Type.OBJECT;
+            superBt = Type.BT_OBJECT;
+        }
+
+        if (subBt == Type.BT_ADDR) {
+            subtype = Type.OBJECT;
+            subBt = Type.BT_OBJECT;
+        }
+
+        if ((superBt != Type.BT_OBJECT) || (subBt != Type.BT_OBJECT)) {
+            /*
+             * No two distinct primitive types are assignable in this sense,
+             * unless they are both int-like.
+             */
+            return supertype.isIntlike() && subtype.isIntlike();
+        }
+
+        // At this point, we know both types are reference types.
+
+        if (supertype == Type.KNOWN_NULL) {
+            /*
+             * A known-null supertype is only assignable from another
+             * known-null (handled in the easy out at the top of the
+             * method).
+             */
+            return false;
+        } else if (subtype == Type.KNOWN_NULL) {
+            /*
+             * A known-null subtype is in fact assignable to any
+             * reference type.
+             */
+            return true;
+        } else if (supertype == Type.OBJECT) {
+            /*
+             * Object is assignable from any reference type.
+             */
+            return true;
+        } else if (supertype.isArray()) {
+            // The supertype is an array type.
+            if (! subtype.isArray()) {
+                // The subtype isn't an array, and so can't be assignable.
+                return false;
+            }
+
+            /*
+             * Strip off as many matched component types from both
+             * types as possible, and check the assignability of the
+             * results.
+             */
+            do {
+                supertype = supertype.getComponentType();
+                subtype = subtype.getComponentType();
+            } while (supertype.isArray() && subtype.isArray());
+
+            return isPossiblyAssignableFrom(supertype, subtype);
+        } else if (subtype.isArray()) {
+            /*
+             * Other than Object (handled above), array types are
+             * assignable only to Serializable and Cloneable.
+             */
+            return (supertype == Type.SERIALIZABLE) ||
+                (supertype == Type.CLONEABLE);
+        } else {
+            /*
+             * All other unequal reference types are considered at
+             * least possibly assignable.
+             */
+            return true;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/OneLocalsArray.java b/dx/src/com/android/dx/cf/code/OneLocalsArray.java
new file mode 100644
index 0000000..cafd177
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/OneLocalsArray.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+import com.android.dx.util.MutabilityControl;
+
+/**
+ * Representation of an array of local variables, with Java semantics.
+ *
+ * <p><b>Note:</b> For the most part, the documentation for this class
+ * ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link
+ * com.android.dx.rop.type.TypeBearer}.</p>
+ */
+public class OneLocalsArray extends LocalsArray {
+    /** {@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}s).
+     *
+     * @param maxLocals {@code >= 0;} the maximum number of locals this instance
+     * can refer to
+     */
+    public OneLocalsArray(int maxLocals) {
+        super(maxLocals != 0);
+        locals = new TypeBearer[maxLocals];
+    }
+
+    /** @inheritDoc */
+    public OneLocalsArray copy() {
+        OneLocalsArray result = new OneLocalsArray(locals.length);
+
+        System.arraycopy(locals, 0, result.locals, 0, locals.length);
+
+        return result;
+    }
+
+    /** @inheritDoc */
+    public void annotate(ExceptionWithContext ex) {
+        for (int i = 0; i < locals.length; i++) {
+            TypeBearer type = locals[i];
+            String s = (type == null) ? "<invalid>" : type.toString();
+            ex.addContext("locals[" + Hex.u2(i) + "]: " + s);
+        }
+    }
+
+    /** {@inheritDoc*/
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < locals.length; i++) {
+            TypeBearer type = locals[i];
+            String s = (type == null) ? "<invalid>" : type.toString();
+            sb.append("locals[" + Hex.u2(i) + "]: " + s + "\n");
+        }
+
+        return sb.toString();
+    }
+
+    /** @inheritDoc */
+    public void makeInitialized(Type type) {
+        int len = locals.length;
+
+        if (len == 0) {
+            // We have to check for this before checking for immutability.
+            return;
+        }
+
+        throwIfImmutable();
+
+        Type initializedType = type.getInitializedType();
+
+        for (int i = 0; i < len; i++) {
+            if (locals[i] == type) {
+                locals[i] = initializedType;
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    public int getMaxLocals() {
+        return locals.length;
+    }
+
+    /** @inheritDoc */
+    public void set(int idx, TypeBearer type) {
+        throwIfImmutable();
+
+        try {
+            type = type.getFrameType();
+        } catch (NullPointerException ex) {
+            // Elucidate the exception
+            throw new NullPointerException("type == null");
+        }
+
+        if (idx < 0) {
+            throw new IndexOutOfBoundsException("idx < 0");
+        }
+
+        // Make highest possible out-of-bounds check happen first.
+        if (type.getType().isCategory2()) {
+            locals[idx + 1] = null;
+        }
+
+        locals[idx] = type;
+
+        if (idx != 0) {
+            TypeBearer prev = locals[idx - 1];
+            if ((prev != null) && prev.getType().isCategory2()) {
+                locals[idx - 1] = null;
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    public void set(RegisterSpec spec) {
+        set(spec.getReg(), spec);
+    }
+
+    /** @inheritDoc */
+    public void invalidate(int idx) {
+        throwIfImmutable();
+        locals[idx] = null;
+    }
+
+    /** @inheritDoc */
+    public TypeBearer getOrNull(int idx) {
+        return locals[idx];
+    }
+
+    /** @inheritDoc */
+    public TypeBearer get(int idx) {
+        TypeBearer result = locals[idx];
+
+        if (result == null) {
+            return throwSimException(idx, "invalid");
+        }
+
+        return result;
+    }
+
+    /** @inheritDoc */
+    public TypeBearer getCategory1(int idx) {
+        TypeBearer result = get(idx);
+        Type type = result.getType();
+
+        if (type.isUninitialized()) {
+            return throwSimException(idx, "uninitialized instance");
+        }
+
+        if (type.isCategory2()) {
+            return throwSimException(idx, "category-2");
+        }
+
+        return result;
+    }
+
+    /** @inheritDoc */
+    public TypeBearer getCategory2(int idx) {
+        TypeBearer result = get(idx);
+
+        if (result.getType().isCategory1()) {
+            return throwSimException(idx, "category-1");
+        }
+
+        return result;
+    }
+
+    /** @inheritDoc */
+    @Override
+    public LocalsArray merge(LocalsArray other) {
+        if (other instanceof OneLocalsArray) {
+            return merge((OneLocalsArray)other);
+        } else { //LocalsArraySet
+            // LocalsArraySet knows how to merge me.
+            return other.merge(this);
+        }
+    }
+
+    /**
+     * Merges this OneLocalsArray instance with another OneLocalsArray
+     * instance. A more-refined version of {@link #merge(LocalsArray) merge}
+     * which is called by that method when appropriate.
+     *
+     * @param other locals array with which to merge
+     * @return this instance if merge was a no-op, or a new instance if
+     * the merge resulted in a change.
+     */
+    public OneLocalsArray merge(OneLocalsArray other) {
+        try {
+            return Merger.mergeLocals(this, other);
+        } catch (SimException ex) {
+            ex.addContext("underlay locals:");
+            annotate(ex);
+            ex.addContext("overlay locals:");
+            other.annotate(ex);
+            throw ex;
+        }
+    }
+
+    /** @inheritDoc */
+    @Override
+    public LocalsArraySet mergeWithSubroutineCaller
+            (LocalsArray other, int predLabel) {
+
+        LocalsArraySet result = new LocalsArraySet(getMaxLocals());
+        return result.mergeWithSubroutineCaller(other, predLabel);
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    protected OneLocalsArray getPrimary() {
+        return this;
+    }
+
+    /**
+     * Throws a properly-formatted exception.
+     *
+     * @param idx the salient local index
+     * @param msg {@code non-null;} useful message
+     * @return never (keeps compiler happy)
+     */
+    private static TypeBearer throwSimException(int idx, String msg) {
+        throw new SimException("local " + Hex.u2(idx) + ": " + msg);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/ReturnAddress.java b/dx/src/com/android/dx/cf/code/ReturnAddress.java
new file mode 100644
index 0000000..ee36450
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ReturnAddress.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.Hex;
+
+/**
+ * Representation of a subroutine return address. In Java verification,
+ * somewhat counterintuitively, the salient bit of information you need to
+ * know about a return address is the <i>start address</i> of the subroutine
+ * being returned from, not the address being returned <i>to</i>, so that's
+ * what instances of this class hang onto.
+ */
+public final class ReturnAddress implements TypeBearer {
+    /** {@code >= 0;} the start address of the subroutine being returned from */
+    private final int subroutineAddress;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param subroutineAddress {@code >= 0;} the start address of the
+     * subroutine being returned from
+     */
+    public ReturnAddress(int subroutineAddress) {
+        if (subroutineAddress < 0) {
+            throw new IllegalArgumentException("subroutineAddress < 0");
+        }
+
+        this.subroutineAddress = subroutineAddress;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return ("<addr:" + Hex.u2(subroutineAddress) + ">");
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toString();
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.RETURN_ADDRESS;
+    }
+
+    /** {@inheritDoc} */
+    public TypeBearer getFrameType() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public int getBasicType() {
+        return Type.RETURN_ADDRESS.getBasicType();
+    }
+
+    /** {@inheritDoc} */
+    public int getBasicFrameType() {
+        return Type.RETURN_ADDRESS.getBasicFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isConstant() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof ReturnAddress)) {
+            return false;
+        }
+
+        return subroutineAddress == ((ReturnAddress) other).subroutineAddress;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return subroutineAddress;
+    }
+
+    /**
+     * Gets 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
new file mode 100644
index 0000000..715cfd8
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/Ropper.java
@@ -0,0 +1,1675 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.code.*;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.Bits;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+
+/**
+ * Utility that converts a basic block list into a list of register-oriented
+ * blocks.
+ */
+public final class Ropper {
+    /** label offset for the parameter assignment block */
+    private static final int PARAM_ASSIGNMENT = -1;
+
+    /** label offset for the return block */
+    private static final int RETURN = -2;
+
+    /** label offset for the synchronized method final return block */
+    private static final int SYNCH_RETURN = -3;
+
+    /** label offset for the first synchronized method setup block */
+    private static final int SYNCH_SETUP_1 = -4;
+
+    /** label offset for the second synchronized method setup block */
+    private static final int SYNCH_SETUP_2 = -5;
+
+    /**
+     * label offset for the first synchronized method exception
+     * handler block
+     */
+    private static final int SYNCH_CATCH_1 = -6;
+
+    /**
+     * label offset for the second synchronized method exception
+     * handler block
+     */
+    private static final int SYNCH_CATCH_2 = -7;
+
+    /** number of special label offsets */
+    private static final int SPECIAL_LABEL_COUNT = 7;
+
+    /** {@code non-null;} method being converted */
+    private final ConcreteMethod method;
+
+    /** {@code non-null;} original block list */
+    private final ByteBlockList blocks;
+
+    /** max locals of the method */
+    private final int maxLocals;
+
+    /** max label (exclusive) of any original bytecode block */
+    private final int maxLabel;
+
+    /** {@code non-null;} simulation machine to use */
+    private final RopperMachine machine;
+
+    /** {@code non-null;} simulator to use */
+    private final Simulator sim;
+
+    /**
+     * {@code non-null;} sparse array mapping block labels to initial frame
+     * contents, if known
+     */
+    private final Frame[] startFrames;
+
+    /** {@code non-null;} output block list in-progress */
+    private final ArrayList<BasicBlock> result;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /**
+     * whether an exception-handler block for a synchronized method was
+     * ever required
+     */
+    private boolean synchNeedsExceptionHandler;
+
+    /**
+     * {@code non-null;} list of subroutines indexed by label of start
+     * address */
+    private final Subroutine[] subroutines;
+
+    /** true if {@code subroutines} is non-empty */
+    private boolean hasSubroutines;
+
+    /**
+     * Keeps track of subroutines that exist in java form and are inlined in
+     * Rop form.
+     */
+    private class Subroutine {
+        /** list of all blocks that jsr to this subroutine */
+        private BitSet callerBlocks;
+        /** List of all blocks that return from this subroutine */
+        private BitSet retBlocks;
+        /** first block in this subroutine */
+        private int startBlock;
+
+        /**
+         * Constructs instance.
+         *
+         * @param startBlock First block of the subroutine.
+         */
+        Subroutine(int startBlock) {
+            this.startBlock = startBlock;
+            retBlocks = new BitSet(maxLabel);
+            callerBlocks = new BitSet(maxLabel);
+            hasSubroutines = true;
+        }
+
+        /**
+         * Constructs instance.
+         *
+         * @param startBlock First block of the subroutine.
+         * @param retBlock one of the ret blocks (final blocks) of this
+         * subroutine.
+         */
+        Subroutine(int startBlock, int retBlock) {
+            this(startBlock);
+            addRetBlock(retBlock);
+        }
+
+        /**
+         * @return {@code >= 0;} the label of the subroutine's start block.
+         */
+        int getStartBlock() {
+            return startBlock;
+        }
+
+        /**
+         * Adds a label to the list of ret blocks (final blocks) for this
+         * subroutine.
+         *
+         * @param retBlock ret block label
+         */
+        void addRetBlock(int retBlock) {
+            retBlocks.set(retBlock);
+        }
+
+        /**
+         * Adds a label to the list of caller blocks for this subroutine.
+         *
+         * @param label a block that invokes this subroutine.
+         */
+        void addCallerBlock(int label) {
+            callerBlocks.set(label);
+        }
+
+        /**
+         * Generates a list of subroutine successors. Note: successor blocks
+         * could be listed more than once. This is ok, because this successor
+         * list (and the block it's associated with) will be copied and inlined
+         * before we leave the ropper. Redundent successors will result in
+         * redundent (no-op) merges.
+         *
+         * @return all currently known successors
+         * (return destinations) for that subroutine
+         */
+        IntList getSuccessors() {
+            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 (int label = callerBlocks.nextSetBit(0); label >= 0;
+                 label = callerBlocks.nextSetBit(label+1)) {
+                BasicBlock subCaller = labelToBlock(label);
+                successors.add(subCaller.getSuccessors().get(0));
+            }
+
+            successors.setImmutable();
+
+            return successors;
+        }
+
+        /**
+         * Merges the specified frame into this subroutine's successors,
+         * setting {@code workSet} as appropriate. To be called with
+         * the frame of a subroutine ret block.
+         *
+         * @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) {
+            for (int label = callerBlocks.nextSetBit(0); label >= 0;
+                 label = callerBlocks.nextSetBit(label+1)) {
+                BasicBlock subCaller = labelToBlock(label);
+                int succLabel = subCaller.getSuccessors().get(0);
+
+                Frame subFrame = frame.subFrameForLabel(startBlock, label);
+
+                if (subFrame != null) {
+                    mergeAndWorkAsNecessary(succLabel, -1, null,
+                            subFrame, workSet);
+                } else {
+                    Bits.set(workSet, label);
+                }
+            }
+        }
+    }
+
+    /**
+     * Converts a {@link ConcreteMethod} to a {@link RopMethod}.
+     *
+     * @param method {@code non-null;} method to convert
+     * @param advice {@code non-null;} translation advice to use
+     * @return {@code non-null;} the converted instance
+     */
+    public static RopMethod convert(ConcreteMethod method,
+            TranslationAdvice advice) {
+        try {
+            Ropper r = new Ropper(method, advice);
+            r.doit();
+            return r.getRopMethod();
+        } catch (SimException ex) {
+            ex.addContext("...while working on method " +
+                          method.getNat().toHuman());
+            throw ex;
+        }
+    }
+
+    /**
+     * Constructs an instance. This class is not publicly instantiable; use
+     * {@link #convert}.
+     *
+     * @param method {@code non-null;} method to convert
+     * @param advice {@code non-null;} translation advice to use
+     */
+    private Ropper(ConcreteMethod method, TranslationAdvice advice) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (advice == null) {
+            throw new NullPointerException("advice == null");
+        }
+
+        this.method = method;
+        this.blocks = BasicBlocker.identifyBlocks(method);
+        this.maxLabel = blocks.getMaxLabel();
+        this.maxLocals = method.getMaxLocals();
+        this.machine = new RopperMachine(this, method, advice);
+        this.sim = new Simulator(machine, method);
+        this.startFrames = new Frame[maxLabel];
+        this.subroutines = new Subroutine[maxLabel];
+
+        /*
+         * The "* 2 + 10" below is to conservatively believe that every
+         * block is an exception handler target and should also
+         * take care of enough other possible extra overhead such that
+         * the underlying array is unlikely to need resizing.
+         */
+        this.result = new ArrayList<BasicBlock>(blocks.size() * 2 + 10);
+        this.resultSubroutines =
+            new ArrayList<IntList>(blocks.size() * 2 + 10);
+
+        this.catchTypes = new Type[maxLabel];
+        this.synchNeedsExceptionHandler = false;
+
+        /*
+         * Set up the first stack frame with the right limits, but leave it
+         * empty here (to be filled in outside of the constructor).
+         */
+        startFrames[0] = new Frame(maxLocals, method.getMaxStack());
+    }
+
+    /**
+     * Gets the first (lowest) register number to use as the temporary
+     * area when unwinding stack manipulation ops.
+     *
+     * @return {@code >= 0;} the first register to use
+     */
+    /*package*/ int getFirstTempStackReg() {
+        /*
+         * We use the register that is just past the deepest possible
+         * stack element, plus one if the method is synchronized to
+         * avoid overlapping with the synch register. We don't need to
+         * do anything else special at this level, since later passes
+         * will merely notice the highest register used by explicit
+         * inspection.
+         */
+        int regCount = getNormalRegCount();
+        return isSynchronized() ? regCount + 1 : regCount;
+    }
+
+    /**
+     * Gets the label for the exception handler setup block corresponding
+     * to the given label.
+     *
+     * @param label {@code >= 0;} the original label
+     * @return {@code >= 0;} the corresponding exception handler setup label
+     */
+    private int getExceptionSetupLabel(int label) {
+        return maxLabel + label;
+    }
+
+    /**
+     * Gets the label for the given special-purpose block. The given label
+     * should be one of the static constants defined by this class.
+     *
+     * @param label {@code < 0;} the special label constant
+     * @return {@code >= 0;} the actual label value to use
+     */
+    private int getSpecialLabel(int label) {
+        /*
+         * The label is bitwise-complemented so that mistakes where
+         * LABEL is used instead of getSpecialLabel(LABEL) cause a
+         * failure at block construction time, since negative labels
+         * are illegal. We multiply maxLabel by 2 since 0..maxLabel
+         * (exclusive) are the original blocks and
+         * maxLabel..(maxLabel*2) are reserved for exception handler
+         * setup blocks (see getExceptionSetupLabel(), above).
+         */
+        return (maxLabel * 2) + ~label;
+    }
+
+    /**
+     * Gets the minimum label for unreserved use.
+     *
+     * @return {@code >= 0;} the minimum label
+     */
+    private int getMinimumUnreservedLabel() {
+        /*
+         * The labels below ((maxLabel * 2) + SPECIAL_LABEL_COUNT) are
+         * reserved for particular uses.
+         */
+
+        return (maxLabel * 2) + SPECIAL_LABEL_COUNT;
+    }
+
+    /**
+     * Gets an arbitrary unreserved and available label.
+     *
+     * @return {@code >= 0;} the label
+     */
+    private int getAvailableLabel() {
+        int candidate = getMinimumUnreservedLabel();
+
+        for (BasicBlock bb : result) {
+            int label = bb.getLabel();
+            if (label >= candidate) {
+                candidate = label + 1;
+            }
+        }
+
+        return candidate;
+    }
+
+    /**
+     * Gets whether the method being translated is synchronized.
+     *
+     * @return whether the method being translated is synchronized
+     */
+    private boolean isSynchronized() {
+        int accessFlags = method.getAccessFlags();
+        return (accessFlags & AccessFlags.ACC_SYNCHRONIZED) != 0;
+    }
+
+    /**
+     * Gets whether the method being translated is static.
+     *
+     * @return whether the method being translated is static
+     */
+    private boolean isStatic() {
+        int accessFlags = method.getAccessFlags();
+        return (accessFlags & AccessFlags.ACC_STATIC) != 0;
+    }
+
+    /**
+     * Gets the total number of registers used for "normal" purposes (i.e.,
+     * for the straightforward translation from the original Java).
+     *
+     * @return {@code >= 0;} the total number of registers used
+     */
+    private int getNormalRegCount() {
+        return maxLocals + method.getMaxStack();
+    }
+
+    /**
+     * Gets the register spec to use to hold the object to synchronize on,
+     * for a synchronized method.
+     *
+     * @return {@code non-null;} the register spec
+     */
+    private RegisterSpec getSynchReg() {
+        /*
+         * We use the register that is just past the deepest possible
+         * stack element, with a minimum of v1 since v0 is what's
+         * always used to hold the caught exception when unwinding. We
+         * don't need to do anything else special at this level, since
+         * later passes will merely notice the highest register used
+         * by explicit inspection.
+         */
+        int reg = getNormalRegCount();
+        return RegisterSpec.make((reg < 1) ? 1 : reg, Type.OBJECT);
+    }
+
+    /**
+     * Searches {@link #result} for a block with the given label. Returns its
+     * index if found, or returns {@code -1} if there is no such block.
+     *
+     * @param label the label to look for
+     * @return {@code >= -1;} the index for the block with the given label or
+     * {@code -1} if there is no such block
+     */
+    private int labelToResultIndex(int label) {
+        int sz = result.size();
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = result.get(i);
+            if (one.getLabel() == label) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Searches {@link #result} for a block with the given label. Returns it if
+     * found, or throws an exception if there is no such block.
+     *
+     * @param label the label to look for
+     * @return {@code non-null;} the block with the given label
+     */
+    private BasicBlock labelToBlock(int label) {
+        int idx = labelToResultIndex(label);
+
+        if (idx < 0) {
+            throw new IllegalArgumentException("no such label " +
+                    Hex.u2(label));
+        }
+
+        return result.get(idx);
+    }
+
+    /**
+     * Adds a block to the output result.
+     *
+     * @param block {@code non-null;} the block to add
+     * @param subroutines {@code non-null;} subroutine label list
+     * as described in {@link Frame#getSubroutines}
+     */
+    private void addBlock(BasicBlock block, IntList subroutines) {
+        if (block == null) {
+            throw new NullPointerException("block == null");
+        }
+
+        result.add(block);
+        subroutines.throwIfMutable();
+        resultSubroutines.add(subroutines);
+    }
+
+    /**
+     * Adds or replace a block in the output result. If this is a
+     * replacement, then any extra blocks that got added with the
+     * original get removed as a result of calling this method.
+     *
+     * @param block {@code non-null;} the block to add or replace
+     * @param subroutines {@code non-null;} subroutine label list
+     * as described in {@link Frame#getSubroutines}
+     * @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) {
+            throw new NullPointerException("block == null");
+        }
+
+        int idx = labelToResultIndex(block.getLabel());
+        boolean ret;
+
+        if (idx < 0) {
+            ret = false;
+        } else {
+            /*
+             * We are replacing a pre-existing block, so find any
+             * blocks that got added as part of the original and
+             * remove those too. Such blocks are (possibly indirect)
+             * successors of this block which are out of the range of
+             * normally-translated blocks.
+             */
+            removeBlockAndSpecialSuccessors(idx);
+            ret = true;
+        }
+
+        result.add(block);
+        subroutines.throwIfMutable();
+        resultSubroutines.add(subroutines);
+        return ret;
+    }
+
+    /**
+     * Adds or replaces a block in the output result. Do not delete
+     * any successors.
+     *
+     * @param block {@code non-null;} the block to add or replace
+     * @param subroutines {@code non-null;} subroutine label list
+     * as described in {@link Frame#getSubroutines}
+     * @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) {
+        if (block == null) {
+            throw new NullPointerException("block == null");
+        }
+
+        int idx = labelToResultIndex(block.getLabel());
+        boolean ret;
+
+        if (idx < 0) {
+            ret = false;
+        } else {
+            result.remove(idx);
+            resultSubroutines.remove(idx);
+            ret = true;
+        }
+
+        result.add(block);
+        subroutines.throwIfMutable();
+        resultSubroutines.add(subroutines);
+        return ret;
+    }
+
+    /**
+     * Helper for {@link #addOrReplaceBlock} which recursively removes
+     * the given block and all blocks that are (direct and indirect)
+     * successors of it whose labels indicate that they are not in the
+     * normally-translated range.
+     *
+     * @param idx {@code non-null;} block to remove (etc.)
+     */
+    private void removeBlockAndSpecialSuccessors(int idx) {
+        int minLabel = getMinimumUnreservedLabel();
+        BasicBlock block = result.get(idx);
+        IntList successors = block.getSuccessors();
+        int sz = successors.size();
+
+        result.remove(idx);
+        resultSubroutines.remove(idx);
+
+        for (int i = 0; i < sz; i++) {
+            int label = successors.get(i);
+            if (label >= minLabel) {
+                idx = labelToResultIndex(label);
+                if (idx < 0) {
+                    throw new RuntimeException("Invalid label "
+                            + Hex.u2(label));
+                }
+                removeBlockAndSpecialSuccessors(idx);
+            }
+        }
+    }
+
+    /**
+     * Extracts the resulting {@link RopMethod} from the instance.
+     *
+     * @return {@code non-null;} the method object
+     */
+    private RopMethod getRopMethod() {
+
+        // Construct the final list of blocks.
+
+        int sz = result.size();
+        BasicBlockList bbl = new BasicBlockList(sz);
+        for (int i = 0; i < sz; i++) {
+            bbl.set(i, result.get(i));
+        }
+        bbl.setImmutable();
+
+        // Construct the method object to wrap it all up.
+
+        /*
+         * Note: The parameter assignment block is always the first
+         * that should be executed, hence the second argument to the
+         * constructor.
+         */
+        return new RopMethod(bbl, getSpecialLabel(PARAM_ASSIGNMENT));
+    }
+
+    /**
+     * Does the conversion.
+     */
+    private void doit() {
+        int[] workSet = Bits.makeBitSet(maxLabel);
+
+        Bits.set(workSet, 0);
+        addSetupBlocks();
+        setFirstFrame();
+
+        for (;;) {
+            int offset = Bits.findFirst(workSet, 0);
+            if (offset < 0) {
+                break;
+            }
+            Bits.clear(workSet, offset);
+            ByteBlock block = blocks.labelToBlock(offset);
+            Frame frame = startFrames[offset];
+            try {
+                processBlock(block, frame, workSet);
+            } catch (SimException ex) {
+                ex.addContext("...while working on block " + Hex.u2(offset));
+                throw ex;
+            }
+        }
+
+        addReturnBlock();
+        addSynchExceptionHandlerBlock();
+        addExceptionSetupBlocks();
+
+        if (hasSubroutines) {
+            // Subroutines are very rare, so skip this step if it's n/a
+            inlineSubroutines();
+        }
+    }
+
+    /**
+     * Sets up the first frame to contain all the incoming parameters in
+     * locals.
+     */
+    private void setFirstFrame() {
+        Prototype desc = method.getEffectiveDescriptor();
+        startFrames[0].initializeWithParameters(desc.getParameterTypes());
+        startFrames[0].setImmutable();
+    }
+
+    /**
+     * Processes the given block.
+     *
+     * @param block {@code non-null;} block to process
+     * @param frame {@code non-null;} start frame for the block
+     * @param workSet {@code non-null;} bits representing work to do,
+     * which this method may add to
+     */
+    private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
+        // Prepare the list of caught exceptions for this block.
+        ByteCatchList catches = block.getCatches();
+        machine.startBlock(catches.toRopCatchList());
+
+        /*
+         * Using a copy of the given frame, simulate each instruction,
+         * calling into machine for each.
+         */
+        frame = frame.copy();
+        sim.simulate(block, frame);
+        frame.setImmutable();
+
+        int extraBlockCount = machine.getExtraBlockCount();
+        ArrayList<Insn> insns = machine.getInsns();
+        int insnSz = insns.size();
+
+        /*
+         * Merge the frame into each possible non-exceptional
+         * successor.
+         */
+
+        int catchSz = catches.size();
+        IntList successors = block.getSuccessors();
+
+        int startSuccessorIndex;
+
+        Subroutine calledSubroutine = null;
+        if (machine.hasJsr()) {
+            /*
+             * If this frame ends in a JSR, only merge our frame with
+             * the subroutine start, not the subroutine's return target.
+             */
+            startSuccessorIndex = 1;
+
+            int subroutineLabel = successors.get(1);
+
+            if (subroutines[subroutineLabel] == null) {
+                subroutines[subroutineLabel] =
+                    new Subroutine (subroutineLabel);
+            }
+
+            subroutines[subroutineLabel].addCallerBlock(block.getLabel());
+
+            calledSubroutine = subroutines[subroutineLabel];
+        } else if (machine.hasRet()) {
+            /*
+             * This block ends in a ret, which means it's the final block
+             * in some subroutine. Ultimately, this block will be copied
+             * and inlined for each call and then disposed of.
+             */
+
+            ReturnAddress ra = machine.getReturnAddress();
+            int subroutineLabel = ra.getSubroutineAddress();
+
+            if (subroutines[subroutineLabel] == null) {
+                subroutines[subroutineLabel]
+                        = new Subroutine (subroutineLabel, block.getLabel());
+            } else {
+                subroutines[subroutineLabel].addRetBlock(block.getLabel());
+            }
+
+            successors = subroutines[subroutineLabel].getSuccessors();
+            subroutines[subroutineLabel]
+                    .mergeToSuccessors(frame, workSet);
+            // Skip processing below since we just did it.
+            startSuccessorIndex = successors.size();
+        } else if (machine.wereCatchesUsed()) {
+            /*
+             * If there are catches, then the first successors
+             * (which will either be all of them or all but the last one)
+             * are catch targets.
+             */
+            startSuccessorIndex = catchSz;
+        } else {
+            startSuccessorIndex = 0;
+        }
+
+        int succSz = successors.size();
+        for (int i = startSuccessorIndex; i < succSz;
+             i++) {
+            int succ = successors.get(i);
+            try {
+                mergeAndWorkAsNecessary(succ, block.getLabel(),
+                        calledSubroutine, frame, workSet);
+            } catch (SimException ex) {
+                ex.addContext("...while merging to block " + Hex.u2(succ));
+                throw ex;
+            }
+        }
+
+        if ((succSz == 0) && machine.returns()) {
+            /*
+             * The block originally contained a return, but it has
+             * been made to instead end with a goto, and we need to
+             * tell it at this point that its sole successor is the
+             * return block. This has to happen after the merge loop
+             * above, since, at this point, the return block doesn't
+             * actually exist; it gets synthesized at the end of
+             * processing the original blocks.
+             */
+            successors = IntList.makeImmutable(getSpecialLabel(RETURN));
+            succSz = 1;
+        }
+
+        int primarySucc;
+
+        if (succSz == 0) {
+            primarySucc = -1;
+        } else {
+            primarySucc = machine.getPrimarySuccessorIndex();
+            if (primarySucc >= 0) {
+                primarySucc = successors.get(primarySucc);
+            }
+        }
+
+        /*
+         * This variable is true only when the method is synchronized and
+         * the block being processed can possibly throw an exception.
+         */
+        boolean synch = isSynchronized() && machine.canThrow();
+
+        if (synch || (catchSz != 0)) {
+            /*
+             * Deal with exception handlers: Merge an exception-catch
+             * frame into each possible exception handler, and
+             * construct a new set of successors to point at the
+             * exception handler setup blocks (which get synthesized
+             * at the very end of processing).
+             */
+            boolean catchesAny = false;
+            IntList newSucc = new IntList(succSz);
+            for (int i = 0; i < catchSz; i++) {
+                ByteCatchList.Item one = catches.get(i);
+                CstType exceptionClass = one.getExceptionClass();
+                int targ = one.getHandlerPc();
+
+                catchesAny |= (exceptionClass == CstType.OBJECT);
+
+                Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
+
+                try {
+                    mergeAndWorkAsNecessary(targ, block.getLabel(),
+                            null, f, workSet);
+                } catch (SimException ex) {
+                    ex.addContext("...while merging exception to block " +
+                                  Hex.u2(targ));
+                    throw ex;
+                }
+
+                /*
+                 * Set up the exception handler type, by setting it if
+                 * the given handler has yet to be encountered, or by
+                 * conservatively unioning if it has.
+                 */
+                Type already = catchTypes[targ];
+                if (already == null) {
+                    catchTypes[targ] = exceptionClass.getClassType();
+                } else if (already != exceptionClass.getClassType()) {
+                    catchTypes[targ] = Type.OBJECT;
+                }
+
+                /*
+                 * The synthesized exception setup block will have the
+                 * label getExceptionSetupLabel(targ).
+                 */
+                newSucc.add(getExceptionSetupLabel(targ));
+            }
+
+            if (synch && !catchesAny) {
+                /*
+                 * The method is synchronized and this block doesn't
+                 * already have a catch-all handler, so add one to the
+                 * end, both in the successors and in the throwing
+                 * instruction(s) at the end of the block (which is where
+                 * the caught classes live).
+                 */
+                newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
+                synchNeedsExceptionHandler = true;
+
+                for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
+                    Insn insn = insns.get(i);
+                    if (insn.canThrow()) {
+                        insn = insn.withAddedCatch(Type.OBJECT);
+                        insns.set(i, insn);
+                    }
+                }
+            }
+
+            if (primarySucc >= 0) {
+                newSucc.add(primarySucc);
+            }
+
+            newSucc.setImmutable();
+            successors = newSucc;
+        }
+
+        // Construct the final resulting block(s), and store it (them).
+
+        int primarySuccListIndex = successors.indexOf(primarySucc);
+
+        /*
+         * If there are any extra blocks, work backwards through the
+         * list of instructions, adding single-instruction blocks, and
+         * resetting the successors variables as appropriate.
+         */
+        for (/*extraBlockCount*/; extraBlockCount > 0; extraBlockCount--) {
+            /*
+             * Some of the blocks that the RopperMachine wants added
+             * are for move-result insns, and these need goto insns as well.
+             */
+            Insn extraInsn = insns.get(--insnSz);
+            boolean needsGoto
+                    = extraInsn.getOpcode().getBranchingness()
+                        == Rop.BRANCH_NONE;
+            InsnList il = new InsnList(needsGoto ? 2 : 1);
+            IntList extraBlockSuccessors = successors;
+
+            il.set(0, extraInsn);
+
+            if (needsGoto) {
+                il.set(1, new PlainInsn(Rops.GOTO,
+                        extraInsn.getPosition(), null,
+                        RegisterSpecList.EMPTY));
+                /*
+                 * Obviously, this block won't be throwing an exception
+                 * so it should only have one successor.
+                 */
+                extraBlockSuccessors = IntList.makeImmutable(primarySucc);
+            }
+            il.setImmutable();
+
+            int label = getAvailableLabel();
+            BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors,
+                    primarySucc);
+            // All of these extra blocks will be in the same subroutine
+            addBlock(bb, frame.getSubroutines());
+
+            successors = successors.mutableCopy();
+            successors.set(primarySuccListIndex, label);
+            successors.setImmutable();
+            primarySucc = label;
+        }
+
+        Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
+
+        /*
+         * Add a goto to the end of the block if it doesn't already
+         * end with a branch, to maintain the invariant that all
+         * blocks end with a branch of some sort or other. Note that
+         * it is possible for there to be blocks for which no
+         * instructions were ever output (e.g., only consist of pop*
+         * in the original Java bytecode).
+         */
+        if ((lastInsn == null) ||
+            (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
+            SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO :
+                lastInsn.getPosition();
+            insns.add(new PlainInsn(Rops.GOTO, pos, null,
+                                    RegisterSpecList.EMPTY));
+            insnSz++;
+        }
+
+        /*
+         * Construct a block for the remaining instructions (which in
+         * the usual case is all of them).
+         */
+
+        InsnList il = new InsnList(insnSz);
+        for (int i = 0; i < insnSz; i++) {
+            il.set(i, insns.get(i));
+        }
+        il.setImmutable();
+
+        BasicBlock bb =
+            new BasicBlock(block.getLabel(), il, successors, primarySucc);
+        addOrReplaceBlock(bb, frame.getSubroutines());
+    }
+
+    /**
+     * Helper for {@link #processBlock}, which merges frames and
+     * adds to the work set, as necessary.
+     *
+     * @param label {@code >= 0;} label to work on
+     * @param pred  predecessor label; must be {@code >= 0} when
+     * {@code label} is a subroutine start block and calledSubroutine
+     * is non-null. Otherwise, may be -1.
+     * @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,
+            Subroutine calledSubroutine, Frame frame, int[] workSet) {
+        Frame existing = startFrames[label];
+        Frame merged;
+
+        if (existing != null) {
+            /*
+             * Some other block also continues at this label. Merge
+             * the frames, and re-set the bit in the work set if there
+             * was a change.
+             */
+            if (calledSubroutine != null) {
+                merged = existing.mergeWithSubroutineCaller(frame,
+                        calledSubroutine.getStartBlock(), pred);
+            } else {
+                merged = existing.mergeWith(frame);
+            }
+            if (merged != existing) {
+                startFrames[label] = merged;
+                Bits.set(workSet, label);
+            }
+        } else {
+            // This is the first time this label has been encountered.
+            if (calledSubroutine != null) {
+                startFrames[label]
+                        = frame.makeNewSubroutineStartFrame(label, pred);
+            } else {
+                startFrames[label] = frame;
+            }
+            Bits.set(workSet, label);
+        }
+    }
+
+    /**
+     * Constructs and adds the blocks that perform setup for the rest of
+     * the method. This includes a first block which merely contains
+     * assignments from parameters to the same-numbered registers and
+     * a possible second block which deals with synchronization.
+     */
+    private void addSetupBlocks() {
+        LocalVariableList localVariables = method.getLocalVariables();
+        SourcePosition pos = method.makeSourcePosistion(0);
+        Prototype desc = method.getEffectiveDescriptor();
+        StdTypeList params = desc.getParameterTypes();
+        int sz = params.size();
+        InsnList insns = new InsnList(sz + 1);
+        int at = 0;
+
+        for (int i = 0; i < sz; i++) {
+            Type one = params.get(i);
+            LocalVariableList.Item local =
+                localVariables.pcAndIndexToLocal(0, at);
+            RegisterSpec result = (local == null) ?
+                RegisterSpec.make(at, one) :
+                RegisterSpec.makeLocalOptional(at, one, local.getLocalItem());
+
+            Insn insn = new PlainCstInsn(Rops.opMoveParam(one), pos, result,
+                                         RegisterSpecList.EMPTY,
+                                         CstInteger.make(at));
+            insns.set(i, insn);
+            at += one.getCategory();
+        }
+
+        insns.set(sz, new PlainInsn(Rops.GOTO, pos, null,
+                                    RegisterSpecList.EMPTY));
+        insns.setImmutable();
+
+        boolean synch = isSynchronized();
+        int label = synch ? getSpecialLabel(SYNCH_SETUP_1) : 0;
+        BasicBlock bb =
+            new BasicBlock(getSpecialLabel(PARAM_ASSIGNMENT), insns,
+                           IntList.makeImmutable(label), label);
+        addBlock(bb, IntList.EMPTY);
+
+        if (synch) {
+            RegisterSpec synchReg = getSynchReg();
+            Insn insn;
+            if (isStatic()) {
+                insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos,
+                                           RegisterSpecList.EMPTY,
+                                           StdTypeList.EMPTY,
+                                           method.getDefiningClass());
+                insns = new InsnList(1);
+                insns.set(0, insn);
+            } else {
+                insns = new InsnList(2);
+                insn = new PlainCstInsn(Rops.MOVE_PARAM_OBJECT, pos,
+                                        synchReg, RegisterSpecList.EMPTY,
+                                        CstInteger.VALUE_0);
+                insns.set(0, insn);
+                insns.set(1, new PlainInsn(Rops.GOTO, pos, null,
+                                           RegisterSpecList.EMPTY));
+            }
+
+            int label2 = getSpecialLabel(SYNCH_SETUP_2);
+            insns.setImmutable();
+            bb = new BasicBlock(label, insns,
+                                IntList.makeImmutable(label2), label2);
+            addBlock(bb, IntList.EMPTY);
+
+            insns = new InsnList(isStatic() ? 2 : 1);
+
+            if (isStatic()) {
+                insns.set(0, new PlainInsn(Rops.opMoveResultPseudo(synchReg),
+                        pos, synchReg, RegisterSpecList.EMPTY));
+            }
+
+            insn = new ThrowingInsn(Rops.MONITOR_ENTER, pos,
+                                    RegisterSpecList.make(synchReg),
+                                    StdTypeList.EMPTY);
+            insns.set(isStatic() ? 1 :0, insn);
+            insns.setImmutable();
+            bb = new BasicBlock(label2, insns, IntList.makeImmutable(0), 0);
+            addBlock(bb, IntList.EMPTY);
+        }
+    }
+
+    /**
+     * Constructs and adds the return block, if necessary. The return
+     * block merely contains an appropriate {@code return}
+     * instruction.
+     */
+    private void addReturnBlock() {
+        Rop returnOp = machine.getReturnOp();
+
+        if (returnOp == null) {
+            /*
+             * The method being converted never returns normally, so there's
+             * no need for a return block.
+             */
+            return;
+        }
+
+        SourcePosition returnPos = machine.getReturnPosition();
+        int label = getSpecialLabel(RETURN);
+
+        if (isSynchronized()) {
+            InsnList insns = new InsnList(1);
+            Insn insn = new ThrowingInsn(Rops.MONITOR_EXIT, returnPos,
+                                         RegisterSpecList.make(getSynchReg()),
+                                         StdTypeList.EMPTY);
+            insns.set(0, insn);
+            insns.setImmutable();
+
+            int nextLabel = getSpecialLabel(SYNCH_RETURN);
+            BasicBlock bb =
+                new BasicBlock(label, insns,
+                               IntList.makeImmutable(nextLabel), nextLabel);
+            addBlock(bb, IntList.EMPTY);
+
+            label = nextLabel;
+        }
+
+        InsnList insns = new InsnList(1);
+        TypeList sourceTypes = returnOp.getSources();
+        RegisterSpecList sources;
+
+        if (sourceTypes.size() == 0) {
+            sources = RegisterSpecList.EMPTY;
+        } else {
+            RegisterSpec source = RegisterSpec.make(0, sourceTypes.getType(0));
+            sources = RegisterSpecList.make(source);
+        }
+
+        Insn insn = new PlainInsn(returnOp, returnPos, null, sources);
+        insns.set(0, insn);
+        insns.setImmutable();
+
+        BasicBlock bb = new BasicBlock(label, insns, IntList.EMPTY, -1);
+        addBlock(bb, IntList.EMPTY);
+    }
+
+    /**
+     * Constructs and adds, if necessary, the catch-all exception handler
+     * block to deal with unwinding the lock taken on entry to a synchronized
+     * method.
+     */
+    private void addSynchExceptionHandlerBlock() {
+        if (!synchNeedsExceptionHandler) {
+            /*
+             * The method being converted either isn't synchronized or
+             * can't possibly throw exceptions in its main body, so
+             * there's no need for a synchronized method exception
+             * handler.
+             */
+            return;
+        }
+
+        SourcePosition pos = method.makeSourcePosistion(0);
+        RegisterSpec exReg = RegisterSpec.make(0, Type.THROWABLE);
+        BasicBlock bb;
+        Insn insn;
+
+        InsnList insns = new InsnList(2);
+        insn = new PlainInsn(Rops.opMoveException(Type.THROWABLE), pos,
+                             exReg, RegisterSpecList.EMPTY);
+        insns.set(0, insn);
+        insn = new ThrowingInsn(Rops.MONITOR_EXIT, pos,
+                                RegisterSpecList.make(getSynchReg()),
+                                StdTypeList.EMPTY);
+        insns.set(1, insn);
+        insns.setImmutable();
+
+        int label2 = getSpecialLabel(SYNCH_CATCH_2);
+        bb = new BasicBlock(getSpecialLabel(SYNCH_CATCH_1), insns,
+                            IntList.makeImmutable(label2), label2);
+        addBlock(bb, IntList.EMPTY);
+
+        insns = new InsnList(1);
+        insn = new ThrowingInsn(Rops.THROW, pos,
+                                RegisterSpecList.make(exReg),
+                                StdTypeList.EMPTY);
+        insns.set(0, insn);
+        insns.setImmutable();
+
+        bb = new BasicBlock(label2, insns, IntList.EMPTY, -1);
+        addBlock(bb, IntList.EMPTY);
+    }
+
+    /**
+     * Creates the exception handler setup blocks. "maxLocals"
+     * below is because that's the register number corresponding
+     * to the sole element on a one-deep stack (which is the
+     * situation at the start of an exception handler block).
+     */
+    private void addExceptionSetupBlocks() {
+
+        int len = catchTypes.length;
+        for (int i = 0; i < len; i++) {
+            Type one = catchTypes[i];
+            if (one != null) {
+                Insn proto = labelToBlock(i).getFirstInsn();
+                SourcePosition pos = proto.getPosition();
+                InsnList il = new InsnList(2);
+
+                Insn insn = new PlainInsn(Rops.opMoveException(one),
+                                          pos,
+                                          RegisterSpec.make(maxLocals, one),
+                                          RegisterSpecList.EMPTY);
+                il.set(0, insn);
+
+                insn = new PlainInsn(Rops.GOTO, pos, null,
+                                     RegisterSpecList.EMPTY);
+                il.set(1, insn);
+                il.setImmutable();
+
+                BasicBlock bb = new BasicBlock(getExceptionSetupLabel(i),
+                                               il,
+                                               IntList.makeImmutable(i),
+                                               i);
+                addBlock(bb, startFrames[i].getSubroutines());
+            }
+        }
+    }
+
+    /**
+     * Checks to see if the basic block is a subroutine caller block.
+     *
+     * @param bb {@code non-null;} the basic block in question
+     * @return true if this block calls a subroutine
+     */
+    private boolean isSubroutineCaller(BasicBlock bb) {
+        IntList successors = bb.getSuccessors();
+        if (successors.size() < 2) return false;
+
+        int subLabel = successors.get(1);
+
+        return (subLabel < subroutines.length)
+                && (subroutines[subLabel] != null);
+    }
+
+    /**
+     * Inlines any subroutine calls.
+     */
+    private void inlineSubroutines() {
+        final IntList reachableSubroutineCallerLabels = new IntList(4);
+
+        /*
+         * Compile a list of all subroutine calls reachable
+         * through the normal (non-subroutine) flow.  We do this first, since
+         * we'll be affecting the call flow as we go.
+         *
+         * Start at label 0 --  the param assignment block has nothing for us
+         */
+        forEachNonSubBlockDepthFirst(0, new BasicBlock.Visitor() {
+            public void visitBlock(BasicBlock b) {
+                if (isSubroutineCaller(b)) {
+                    reachableSubroutineCallerLabels.add(b.getLabel());
+                }
+            }
+        });
+
+        /*
+         * Convert the resultSubroutines list, indexed by block index,
+         * to a label-to-subroutines mapping used by the inliner.
+         */
+        int largestAllocedLabel = getAvailableLabel();
+        ArrayList<IntList> labelToSubroutines
+                = new ArrayList<IntList>(largestAllocedLabel);
+        for (int i = 0; i < largestAllocedLabel; i++) {
+            labelToSubroutines.add(null);
+        }
+
+        for (int i = 0; i < result.size(); i++) {
+            BasicBlock b = result.get(i);
+            if (b == null) {
+                continue;
+            }
+            IntList subroutineList = resultSubroutines.get(i);
+            labelToSubroutines.set(b.getLabel(), subroutineList);
+        }
+
+        /*
+         * Inline all reachable subroutines.
+         * Inner subroutines will be inlined as they are encountered.
+         */
+        int sz = reachableSubroutineCallerLabels.size();
+        for (int i = 0 ; i < sz ; i++) {
+            int label = reachableSubroutineCallerLabels.get(i);
+            new SubroutineInliner(
+                    new LabelAllocator(getAvailableLabel()),
+                    labelToSubroutines)
+                    .inlineSubroutineCalledFrom(labelToBlock(label));
+        }
+
+        // Now find the blocks that aren't reachable and remove them
+        deleteUnreachableBlocks();
+    }
+
+    /**
+     * Deletes all blocks that cannot be reached. This is run to delete
+     * original subroutine blocks after subroutine inlining.
+     */
+    private void deleteUnreachableBlocks() {
+        final IntList reachableLabels = new IntList(result.size());
+
+        // subroutine inlining is done now and we won't update this list here
+        resultSubroutines.clear();
+
+        forEachNonSubBlockDepthFirst(getSpecialLabel(PARAM_ASSIGNMENT),
+                new BasicBlock.Visitor() {
+
+            public void visitBlock(BasicBlock b) {
+                reachableLabels.add(b.getLabel());
+            }
+        });
+
+        reachableLabels.sort();
+
+        for (int i = result.size() - 1 ; i >= 0 ; i--) {
+            if (reachableLabels.indexOf(result.get(i).getLabel()) < 0) {
+                result.remove(i);
+                // unnecessary here really, since subroutine inlining is done
+                //resultSubroutines.remove(i);
+            }
+        }
+    }
+
+    /**
+     * Allocates labels, without requiring previously allocated labels
+     * to have been added to the blocks list.
+     */
+    private static class LabelAllocator {
+        int nextAvailableLabel;
+
+        /**
+         * @param startLabel available label to start allocating from
+         */
+        LabelAllocator(int startLabel) {
+            nextAvailableLabel = startLabel;
+        }
+
+        /**
+         * @return next available label
+         */
+        int getNextLabel() {
+            return nextAvailableLabel++;
+        }
+    }
+
+    /**
+     * Inlines a subroutine. Start by calling
+     * {@link #inlineSubroutineCalledFrom}.
+     */
+    private class SubroutineInliner {
+        /**
+         * maps original label to the label that will be used by the
+         * inlined version
+         */
+        private final HashMap<Integer, Integer> origLabelToCopiedLabel;
+
+        /** set of original labels that need to be copied */
+        private final BitSet workList;
+
+        /** the label of the original start block for this subroutine */
+        private int subroutineStart;
+
+        /** the label of the ultimate return block */
+        private int subroutineSuccessor;
+
+        /** used for generating new labels for copied blocks */
+        private final LabelAllocator labelAllocator;
+
+        /**
+         * A mapping, indexed by label, to subroutine nesting list.
+         * The subroutine nest list is as returned by
+         * {@link Frame#getSubroutines}.
+         */
+        private final ArrayList<IntList> labelToSubroutines;
+
+        SubroutineInliner(final LabelAllocator labelAllocator,
+                ArrayList<IntList> labelToSubroutines) {
+            origLabelToCopiedLabel = new HashMap<Integer, Integer>();
+
+            workList = new BitSet(maxLabel);
+
+            this.labelAllocator = labelAllocator;
+            this.labelToSubroutines = labelToSubroutines;
+        }
+
+        /**
+         * Inlines a subroutine.
+         *
+         * @param b block where {@code jsr} occurred in the original bytecode
+         */
+        void inlineSubroutineCalledFrom(final BasicBlock b) {
+            /*
+             * The 0th successor of a subroutine caller block is where
+             * the subroutine should return to. The 1st successor is
+             * the start block of the subroutine.
+             */
+            subroutineSuccessor = b.getSuccessors().get(0);
+            subroutineStart = b.getSuccessors().get(1);
+
+            /*
+             * This allocates an initial label and adds the first
+             * block to the worklist.
+             */
+            int newSubStartLabel = mapOrAllocateLabel(subroutineStart);
+
+            for (int label = workList.nextSetBit(0); label >= 0;
+                 label = workList.nextSetBit(0)) {
+                workList.clear(label);
+                int newLabel = origLabelToCopiedLabel.get(label);
+
+                copyBlock(label, newLabel);
+
+                if (isSubroutineCaller(labelToBlock(label))) {
+                    new SubroutineInliner(labelAllocator, labelToSubroutines)
+                        .inlineSubroutineCalledFrom(labelToBlock(newLabel));
+                }
+            }
+
+            /*
+             * Replace the original caller block, since we now have a
+             * new successor
+             */
+
+            addOrReplaceBlockNoDelete(
+                new BasicBlock(b.getLabel(), b.getInsns(),
+                    IntList.makeImmutable (newSubStartLabel),
+                            newSubStartLabel),
+                labelToSubroutines.get(b.getLabel()));
+        }
+
+        /**
+         * Copies a basic block, mapping its successors along the way.
+         *
+         * @param origLabel original block label
+         * @param newLabel label that the new block should have
+         */
+        private void copyBlock(int origLabel, int newLabel) {
+
+            BasicBlock origBlock = labelToBlock(origLabel);
+
+            final IntList origSuccessors = origBlock.getSuccessors();
+            IntList successors;
+            int primarySuccessor = -1;
+            Subroutine subroutine;
+
+            if (isSubroutineCaller(origBlock)) {
+                /*
+                 * A subroutine call inside a subroutine call.
+                 * Set up so we can recurse. The caller block should have
+                 * it's first successor be a copied block that will be
+                 * the subroutine's return point. It's second successor will
+                 * be copied when we recurse, and remains as the original
+                 * label of the start of the inner subroutine.
+                 */
+
+                successors = IntList.makeImmutable(
+                        mapOrAllocateLabel(origSuccessors.get(0)),
+                        origSuccessors.get(1));
+                // primary successor will be set when this block is replaced
+            } else if (null
+                    != (subroutine = subroutineFromRetBlock(origLabel))) {
+                /*
+                 * this is a ret block -- its successor
+                 * should be subroutineSuccessor
+                 */
+
+                // Sanity check
+                if (subroutine.startBlock != subroutineStart) {
+                    throw new RuntimeException (
+                            "ret instruction returns to label "
+                            + Hex.u2 (subroutine.startBlock)
+                            + " expected: " + Hex.u2(subroutineStart));
+                }
+
+                successors = IntList.makeImmutable(subroutineSuccessor);
+                primarySuccessor = subroutineSuccessor;
+            } else {
+                // Map all the successor labels
+
+                int origPrimary = origBlock.getPrimarySuccessor();
+                int sz = origSuccessors.size();
+
+                successors = new IntList(sz);
+
+                for (int i = 0 ; i < sz ; i++) {
+                    int origSuccLabel = origSuccessors.get(i);
+                    int newSuccLabel =  mapOrAllocateLabel(origSuccLabel);
+
+                    successors.add(newSuccLabel);
+
+                    if (origPrimary == origSuccLabel) {
+                        primarySuccessor = newSuccLabel;
+                    }
+                }
+
+                successors.setImmutable();
+            }
+
+            addBlock (
+                new BasicBlock(newLabel,
+                    filterMoveReturnAddressInsns(origBlock.getInsns()),
+                    successors, primarySuccessor),
+                    labelToSubroutines.get(newLabel));
+        }
+
+        /**
+         * Checks to see if a specified label is involved in a specified
+         * subroutine.
+         *
+         * @param label {@code >= 0;} a basic block label
+         * @param subroutineStart {@code >= 0;} a subroutine as identified
+         * by the label of its start block
+         * @return true if the block is dominated by the subroutine call
+         */
+        private boolean involvedInSubroutine(int label, int subroutineStart) {
+            IntList subroutinesList = labelToSubroutines.get(label);
+            return (subroutinesList != null && subroutinesList.size() > 0
+                    && subroutinesList.top() == subroutineStart);
+        }
+
+        /**
+         * Maps the label of a pre-copied block to the label of the inlined
+         * block, allocating a new label and adding it to the worklist
+         * if necessary.  If the origLabel is a "special" label, it
+         * is returned exactly and not scheduled for duplication: copying
+         * never proceeds past a special label, which likely is the function
+         * return block or an immediate predecessor.
+         *
+         * @param origLabel label of original, pre-copied block
+         * @return label for new, inlined block
+         */
+        private int mapOrAllocateLabel(int origLabel) {
+            int resultLabel;
+            Integer mappedLabel = origLabelToCopiedLabel.get(origLabel);
+
+            if (mappedLabel != null) {
+                resultLabel = mappedLabel;
+            } else if (!involvedInSubroutine(origLabel,subroutineStart)) {
+                /*
+                 * A subroutine has ended by some means other than a "ret"
+                 * (which really means a throw caught later).
+                 */
+                resultLabel = origLabel;
+            } else {
+                resultLabel = labelAllocator.getNextLabel();
+                workList.set(origLabel);
+                origLabelToCopiedLabel.put(origLabel, resultLabel);
+
+                // The new label has the same frame as the original label
+                while (labelToSubroutines.size() <= resultLabel) {
+                    labelToSubroutines.add(null);
+                }
+                labelToSubroutines.set(resultLabel,
+                        labelToSubroutines.get(origLabel));
+            }
+
+            return resultLabel;
+        }
+    }
+
+    /**
+     * Finds a {@code Subroutine} that is returned from by a {@code ret} in
+     * a given block.
+     *
+     * @param label A block that originally contained a {@code ret} instruction
+     * @return {@code null-ok;} found subroutine or {@code null} if none
+     * was found
+     */
+    private Subroutine subroutineFromRetBlock(int label) {
+        for (int i = subroutines.length - 1 ; i >= 0 ; i--) {
+            if (subroutines[i] != null) {
+                Subroutine subroutine = subroutines[i];
+
+                if (subroutine.retBlocks.get(label)) {
+                    return subroutine;
+                }
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Removes all {@code move-return-address} instructions, returning a new
+     * {@code InsnList} if necessary. The {@code move-return-address}
+     * insns are dead code after subroutines have been inlined.
+     *
+     * @param insns {@code InsnList} that may contain
+     * {@code move-return-address} insns
+     * @return {@code InsnList} with {@code move-return-address} removed
+     */
+    private InsnList filterMoveReturnAddressInsns(InsnList insns) {
+        int sz;
+        int newSz = 0;
+
+        // First see if we need to filter, and if so what the new size will be
+        sz = insns.size();
+        for (int i = 0; i < sz; i++) {
+            if (insns.get(i).getOpcode() != Rops.MOVE_RETURN_ADDRESS) {
+                newSz++;
+            }
+        }
+
+        if (newSz == sz) {
+            return insns;
+        }
+
+        // Make a new list without the MOVE_RETURN_ADDRESS insns
+        InsnList newInsns = new InsnList(newSz);
+
+        int newIndex = 0;
+        for (int i = 0; i < sz; i++) {
+            Insn insn = insns.get(i);
+            if (insn.getOpcode() != Rops.MOVE_RETURN_ADDRESS) {
+                newInsns.set(newIndex++, insn);
+            }
+        }
+
+        newInsns.setImmutable();
+        return newInsns;
+    }
+
+    /**
+     * Visits each non-subroutine block once in depth-first successor order.
+     *
+     * @param firstLabel label of start block
+     * @param v callback interface
+     */
+    private void forEachNonSubBlockDepthFirst(int firstLabel,
+            BasicBlock.Visitor v) {
+        forEachNonSubBlockDepthFirst0(labelToBlock(firstLabel),
+                v, new BitSet(maxLabel));
+    }
+
+    /**
+     * Visits each block once in depth-first successor order, ignoring
+     * {@code jsr} targets. Worker for {@link #forEachNonSubBlockDepthFirst}.
+     *
+     * @param next next block to visit
+     * @param v callback interface
+     * @param visited set of blocks already visited
+     */
+    private void forEachNonSubBlockDepthFirst0(
+            BasicBlock next, BasicBlock.Visitor v, BitSet visited) {
+        v.visitBlock(next);
+        visited.set(next.getLabel());
+
+        IntList successors = next.getSuccessors();
+        int sz = successors.size();
+
+        for (int i = 0; i < sz; i++) {
+            int succ = successors.get(i);
+
+            if (visited.get(succ)) {
+                continue;
+            }
+
+            if (isSubroutineCaller(next) && i > 0) {
+                // ignore jsr targets
+                continue;
+            }
+
+            /*
+             * Ignore missing labels: they're successors of
+             * subroutines that never invoke a ret.
+             */
+            int idx = labelToResultIndex(succ);
+            if (idx >= 0) {
+                forEachNonSubBlockDepthFirst0(result.get(idx), v, visited);
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/RopperMachine.java b/dx/src/com/android/dx/cf/code/RopperMachine.java
new file mode 100644
index 0000000..f45bc1f
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/RopperMachine.java
@@ -0,0 +1,963 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.code.FillArrayDataInsn;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.code.SwitchInsn;
+import com.android.dx.rop.code.ThrowingCstInsn;
+import com.android.dx.rop.code.ThrowingInsn;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+
+/**
+ * Machine implementation for use by {@link Ropper}.
+ */
+/*package*/ final class RopperMachine extends ValueAwareMachine {
+    /** {@code non-null;} array reflection class */
+    private static final CstType ARRAY_REFLECT_TYPE =
+        new CstType(Type.internClassName("java/lang/reflect/Array"));
+
+    /**
+     * {@code non-null;} method constant for use in converting
+     * {@code multianewarray} instructions
+     */
+    private static final CstMethodRef MULTIANEWARRAY_METHOD =
+        new CstMethodRef(ARRAY_REFLECT_TYPE,
+                         new CstNat(new CstString("newInstance"),
+                                    new CstString("(Ljava/lang/Class;[I)" +
+                                                "Ljava/lang/Object;")));
+
+    /** {@code non-null;} {@link Ropper} controlling this instance */
+    private final Ropper ropper;
+
+    /** {@code non-null;} method being converted */
+    private final ConcreteMethod method;
+
+    /** {@code non-null;} translation advice */
+    private final TranslationAdvice advice;
+
+    /** max locals of the method */
+    private final int maxLocals;
+
+    /** {@code non-null;} instructions for the rop basic block in-progress */
+    private final ArrayList<Insn> insns;
+
+    /** {@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} */
+    private boolean returns;
+
+    /** primary successor index */
+    private int primarySuccessorIndex;
+
+    /** {@code >= 0;} number of extra basic blocks required */
+    private int extraBlockCount;
+
+    /** true if last processed block ends with a jsr or jsr_W*/
+    private boolean hasJsr;
+
+    /** true if an exception can be thrown by the last block processed */
+    private boolean blockCanThrow;
+
+    /**
+     * If non-null, the ReturnAddress that was used by the terminating ret
+     * instruction. If null, there was no ret instruction encountered.
+     */
+
+    private ReturnAddress returnAddress;
+
+    /**
+     * {@code null-ok;} the appropriate {@code return} op or {@code null}
+     * if it is not yet known
+     */
+    private Rop returnOp;
+
+    /**
+     * {@code null-ok;} the source position for the return block or {@code null}
+     * if it is not yet known
+     */
+    private SourcePosition returnPosition;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param ropper {@code non-null;} ropper controlling this instance
+     * @param method {@code non-null;} method being converted
+     * @param advice {@code non-null;} translation advice to use
+     */
+    public RopperMachine(Ropper ropper, ConcreteMethod method,
+            TranslationAdvice advice) {
+        super(method.getEffectiveDescriptor());
+
+        if (ropper == null) {
+            throw new NullPointerException("ropper == null");
+        }
+
+        if (advice == null) {
+            throw new NullPointerException("advice == null");
+        }
+
+        this.ropper = ropper;
+        this.method = method;
+        this.advice = advice;
+        this.maxLocals = method.getMaxLocals();
+        this.insns = new ArrayList<Insn>(25);
+        this.catches = null;
+        this.catchesUsed = false;
+        this.returns = false;
+        this.primarySuccessorIndex = -1;
+        this.extraBlockCount = 0;
+        this.blockCanThrow = false;
+        this.returnOp = null;
+        this.returnPosition = null;
+    }
+
+    /**
+     * Gets the instructions array. It is shared and gets modified by
+     * subsequent calls to this instance.
+     *
+     * @return {@code non-null;} the instructions array
+     */
+    public ArrayList<Insn> getInsns() {
+        return insns;
+    }
+
+    /**
+     * Gets the return opcode encountered, if any.
+     *
+     * @return {@code null-ok;} the return opcode
+     */
+    public Rop getReturnOp() {
+        return returnOp;
+    }
+
+    /**
+     * Gets the return position, if known.
+     *
+     * @return {@code null-ok;} the return position
+     */
+    public SourcePosition getReturnPosition() {
+        return returnPosition;
+    }
+
+    /**
+     * 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}, and reset {@link #primarySuccessorIndex}.
+     */
+    public void startBlock(TypeList catches) {
+        this.catches = catches;
+
+        insns.clear();
+        catchesUsed = false;
+        returns = false;
+        primarySuccessorIndex = 0;
+        extraBlockCount = 0;
+        blockCanThrow = false;
+        hasJsr = false;
+        returnAddress = null;
+    }
+
+    /**
+     * Gets whether {@link #catches} was used. This indicates that the
+     * last instruction in the block is one of the ones that can throw.
+     *
+     * @return whether {@code catches} has been used
+     */
+    public boolean wereCatchesUsed() {
+        return catchesUsed;
+    }
+
+    /**
+     * Gets whether the block just processed ended with a
+     * {@code return}.
+     *
+     * @return whether the block returns
+     */
+    public boolean returns() {
+        return returns;
+    }
+
+    /**
+     * Gets the primary successor index. This is the index into the
+     * successors list where the primary may be found or
+     * {@code -1} if there are successors but no primary
+     * successor. This may return something other than
+     * {@code -1} in the case of an instruction with no
+     * successors at all (primary or otherwise).
+     *
+     * @return {@code >= -1;} the primary successor index
+     */
+    public int getPrimarySuccessorIndex() {
+        return primarySuccessorIndex;
+    }
+
+    /**
+     * Gets how many extra blocks will be needed to represent the
+     * block currently being translated. Each extra block should consist
+     * of one instruction from the end of the original block.
+     *
+     * @return {@code >= 0;} the number of extra blocks needed
+     */
+    public int getExtraBlockCount() {
+        return extraBlockCount;
+    }
+
+    /**
+     * @return true if at least one of the insn processed since the last
+     * call to startBlock() can throw.
+     */
+    public boolean canThrow() {
+        return blockCanThrow;
+    }
+
+    /**
+     * @return true if a JSR has ben encountered since the last call to
+     * startBlock()
+     */
+    public boolean hasJsr() {
+        return hasJsr;
+    }
+
+    /**
+     * @return {@code true} if a {@code ret} has ben encountered since
+     * the last call to {@code startBlock()}
+     */
+    public boolean hasRet() {
+        return returnAddress != null;
+    }
+
+    /**
+     * @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;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void run(Frame frame, int offset, int opcode) {
+        /*
+         * This is the stack pointer after the opcode's arguments have been
+         * popped.
+         */
+        int stackPointer = maxLocals + frame.getStack().size();
+
+        // The sources have to be retrieved before super.run() gets called.
+        RegisterSpecList sources = getSources(opcode, stackPointer);
+        int sourceCount = sources.size();
+
+        super.run(frame, offset, opcode);
+
+        SourcePosition pos = method.makeSourcePosistion(offset);
+        RegisterSpec localTarget = getLocalTarget(opcode == ByteOps.ISTORE);
+        int destCount = resultCount();
+        RegisterSpec dest;
+
+        if (destCount == 0) {
+            dest = null;
+            switch (opcode) {
+                case ByteOps.POP:
+                case ByteOps.POP2: {
+                    // These simply don't appear in the rop form.
+                    return;
+                }
+            }
+        } else if (localTarget != null) {
+            dest = localTarget;
+        } else if (destCount == 1) {
+            dest = RegisterSpec.make(stackPointer, result(0));
+        } else {
+            /*
+             * This clause only ever applies to the stack manipulation
+             * ops that have results (that is, dup* and swap but not
+             * pop*).
+             *
+             * What we do is first move all the source registers into
+             * the "temporary stack" area defined for the method, and
+             * then move stuff back down onto the main "stack" in the
+             * arrangement specified by the stack op pattern.
+             *
+             * Note: This code ends up emitting a lot of what will
+             * turn out to be superfluous moves (e.g., moving back and
+             * forth to the same local when doing a dup); however,
+             * that makes this code a bit easier (and goodness knows
+             * it doesn't need any extra complexity), and all the SSA
+             * stuff is going to want to deal with this sort of
+             * superfluous assignment anyway, so it should be a wash
+             * in the end.
+             */
+            int scratchAt = ropper.getFirstTempStackReg();
+            RegisterSpec[] scratchRegs = new RegisterSpec[sourceCount];
+
+            for (int i = 0; i < sourceCount; i++) {
+                RegisterSpec src = sources.get(i);
+                TypeBearer type = src.getTypeBearer();
+                RegisterSpec scratch = src.withReg(scratchAt);
+                insns.add(new PlainInsn(Rops.opMove(type), pos, scratch, src));
+                scratchRegs[i] = scratch;
+                scratchAt += src.getCategory();
+            }
+
+            for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) {
+                int which = (pattern & 0x0f) - 1;
+                RegisterSpec scratch = scratchRegs[which];
+                TypeBearer type = scratch.getTypeBearer();
+                insns.add(new PlainInsn(Rops.opMove(type), pos,
+                                        scratch.withReg(stackPointer),
+                                        scratch));
+                stackPointer += type.getType().getCategory();
+            }
+            return;
+        }
+
+        TypeBearer destType = (dest != null) ? dest : Type.VOID;
+        Constant cst = getAuxCst();
+        int ropOpcode;
+        Rop rop;
+        Insn insn;
+
+        if (opcode == ByteOps.MULTIANEWARRAY) {
+            blockCanThrow = true;
+
+            // Add the extra instructions for handling multianewarray.
+
+            extraBlockCount = 6;
+
+            /*
+             * Add an array constructor for the int[] containing all the
+             * dimensions.
+             */
+            RegisterSpec dimsReg =
+                RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY);
+            rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount);
+            insn = new ThrowingCstInsn(rop, pos, sources, catches,
+                    CstType.INT_ARRAY);
+            insns.add(insn);
+
+            // Add a move-result for the new-filled-array
+            rop = Rops.opMoveResult(Type.INT_ARRAY);
+            insn = new PlainInsn(rop, pos, dimsReg, RegisterSpecList.EMPTY);
+            insns.add(insn);
+
+            /*
+             * Add a const-class instruction for the specified array
+             * class.
+             */
+
+            /*
+             * Remove as many dimensions from the originally specified
+             * class as are given in the explicit list of dimensions,
+             * so as to pass the right component class to the standard
+             * Java library array constructor.
+             */
+            Type componentType = ((CstType) cst).getClassType();
+            for (int i = 0; i < sourceCount; i++) {
+                componentType = componentType.getComponentType();
+            }
+
+            RegisterSpec classReg =
+                RegisterSpec.make(dest.getReg(), Type.CLASS);
+
+            if (componentType.isPrimitive()) {
+                /*
+                 * The component type is primitive (e.g., int as opposed
+                 * to Integer), so we have to fetch the corresponding
+                 * TYPE class.
+                 */
+                CstFieldRef typeField =
+                    CstFieldRef.forPrimitiveType(componentType);
+                insn = new ThrowingCstInsn(Rops.GET_STATIC_OBJECT, pos,
+                                           RegisterSpecList.EMPTY,
+                                           catches, typeField);
+            } else {
+                /*
+                 * The component type is an object type, so just make a
+                 * normal class reference.
+                 */
+                insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos,
+                                           RegisterSpecList.EMPTY, catches,
+                                           new CstType(componentType));
+            }
+
+            insns.add(insn);
+
+            // Add a move-result-pseudo for the get-static or const
+            rop = Rops.opMoveResultPseudo(classReg.getType());
+            insn = new PlainInsn(rop, pos, classReg, RegisterSpecList.EMPTY);
+            insns.add(insn);
+
+            /*
+             * Add a call to the "multianewarray method," that is,
+             * Array.newInstance(class, dims). Note: The result type
+             * of newInstance() is Object, which is why the last
+             * instruction in this sequence is a cast to the right
+             * type for the original instruction.
+             */
+
+            RegisterSpec objectReg =
+                RegisterSpec.make(dest.getReg(), Type.OBJECT);
+
+            insn = new ThrowingCstInsn(
+                    Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()),
+                    pos, RegisterSpecList.make(classReg, dimsReg),
+                    catches, MULTIANEWARRAY_METHOD);
+            insns.add(insn);
+
+            // Add a move-result.
+            rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype()
+                    .getReturnType());
+            insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY);
+            insns.add(insn);
+
+            /*
+             * And finally, set up for the remainder of this method to
+             * add an appropriate cast.
+             */
+
+            opcode = ByteOps.CHECKCAST;
+            sources = RegisterSpecList.make(objectReg);
+        } else if (opcode == ByteOps.JSR) {
+            // JSR has no Rop instruction
+            hasJsr = true;
+            return;
+        } else if (opcode == ByteOps.RET) {
+            try {
+                returnAddress = (ReturnAddress)arg(0);
+            } catch (ClassCastException ex) {
+                throw new RuntimeException(
+                        "Argument to RET was not a ReturnAddress", ex);
+            }
+            // RET has no Rop instruction.
+            return;
+        }
+
+        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.
+             */
+            extraBlockCount++;
+
+            moveResult = new PlainInsn(
+                    Rops.opMoveResult(((CstMethodRef) cst).getPrototype()
+                    .getReturnType()), pos, dest, RegisterSpecList.EMPTY);
+
+            dest = null;
+        } else if (dest != null && rop.canThrow()) {
+            /*
+             * We're going to want to have a move-result-pseudo in the
+             * next basic block.
+             */
+            extraBlockCount++;
+
+            moveResult = new PlainInsn(
+                    Rops.opMoveResultPseudo(dest.getTypeBearer()),
+                    pos, dest, RegisterSpecList.EMPTY);
+
+            dest = null;
+        }
+        if (ropOpcode == RegOps.NEW_ARRAY) {
+            /*
+             * In the original bytecode, this was either a primitive
+             * array constructor "newarray" or an object array
+             * constructor "anewarray". In the former case, there is
+             * no explicit constant, and in the latter, the constant
+             * is for the element type and not the array type. The rop
+             * instruction form for both of these is supposed to be
+             * the resulting array type, so we initialize / alter
+             * "cst" here, accordingly. Conveniently enough, the rop
+             * opcode already gets constructed with the proper array
+             * type.
+             */
+            cst = CstType.intern(rop.getResult());
+        } else if ((cst == null) && (sourceCount == 2)) {
+            TypeBearer firstType = sources.get(0).getTypeBearer();
+            TypeBearer lastType = sources.get(1).getTypeBearer();
+
+            if ((lastType.isConstant() || firstType.isConstant()) &&
+                 advice.hasConstantOperation(rop, sources.get(0),
+                                             sources.get(1))) {
+
+                if (lastType.isConstant()) {
+                    /*
+                     * The target architecture has an instruction that can
+                     * build in the constant found in the second argument,
+                     * so pull it out of the sources and just use it as a
+                     * constant here.
+                     */
+                    cst = (Constant) lastType;
+                    sources = sources.withoutLast();
+
+                    // For subtraction, change to addition and invert constant
+                    if (rop.getOpcode() == RegOps.SUB) {
+                        ropOpcode = RegOps.ADD;
+                        CstInteger cstInt = (CstInteger) lastType;
+                        cst = CstInteger.make(-cstInt.getValue());
+                    }
+                } else {
+                    /*
+                     * The target architecture has an instruction that can
+                     * build in the constant found in the first argument,
+                     * so pull it out of the sources and just use it as a
+                     * constant here.
+                     */
+                    cst = (Constant) firstType;
+                    sources = sources.withoutFirst();
+                }
+
+                rop = Rops.ropFor(ropOpcode, destType, sources, cst);
+            }
+        }
+
+        SwitchList cases = getAuxCases();
+        ArrayList<Constant> initValues = getInitValues();
+        boolean canThrow = rop.canThrow();
+
+        blockCanThrow |= canThrow;
+
+        if (cases != null) {
+            if (cases.size() == 0) {
+                // It's a default-only switch statement. It can happen!
+                insn = new PlainInsn(Rops.GOTO, pos, null,
+                                     RegisterSpecList.EMPTY);
+                primarySuccessorIndex = 0;
+            } else {
+                IntList values = cases.getValues();
+                insn = new SwitchInsn(rop, pos, dest, sources, values);
+                primarySuccessorIndex = values.size();
+            }
+        } else if (ropOpcode == RegOps.RETURN) {
+            /*
+             * Returns get turned into the combination of a move (if
+             * non-void and if the return doesn't already mention
+             * register 0) and a goto (to the return block).
+             */
+            if (sources.size() != 0) {
+                RegisterSpec source = sources.get(0);
+                TypeBearer type = source.getTypeBearer();
+                if (source.getReg() != 0) {
+                    insns.add(new PlainInsn(Rops.opMove(type), pos,
+                                            RegisterSpec.make(0, type),
+                                            source));
+                }
+            }
+            insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
+            primarySuccessorIndex = 0;
+            updateReturnOp(rop, pos);
+            returns = true;
+        } else if (cst != null) {
+            if (canThrow) {
+                insn =
+                    new ThrowingCstInsn(rop, pos, sources, catches, cst);
+                catchesUsed = true;
+                primarySuccessorIndex = catches.size();
+            } else {
+                insn = new PlainCstInsn(rop, pos, dest, sources, cst);
+            }
+        } else if (canThrow) {
+            insn = new ThrowingInsn(rop, pos, sources, catches);
+            catchesUsed = true;
+            if (opcode == ByteOps.ATHROW) {
+                /*
+                 * The op athrow is the only one where it's possible
+                 * to have non-empty successors and yet not have a
+                 * primary successor.
+                 */
+                primarySuccessorIndex = -1;
+            } else {
+                primarySuccessorIndex = catches.size();
+            }
+        } else {
+            insn = new PlainInsn(rop, pos, dest, sources);
+        }
+
+        insns.add(insn);
+
+        if (moveResult != null) {
+            insns.add(moveResult);
+        }
+
+        /*
+         * 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++;
+            insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos,
+                    RegisterSpecList.make(moveResult.getResult()), initValues,
+                    cst);
+            insns.add(insn);
+        }
+    }
+
+    /**
+     * Helper for {@link #run}, which gets the list of sources for the.
+     * instruction.
+     *
+     * @param opcode the opcode being translated
+     * @param stackPointer {@code >= 0;} the stack pointer after the
+     * instruction's arguments have been popped
+     * @return {@code non-null;} the sources
+     */
+    private RegisterSpecList getSources(int opcode, int stackPointer) {
+        int count = argCount();
+
+        if (count == 0) {
+            // We get an easy out if there aren't any sources.
+            return RegisterSpecList.EMPTY;
+        }
+
+        int localIndex = getLocalIndex();
+        RegisterSpecList sources;
+
+        if (localIndex >= 0) {
+            // The instruction is operating on a local variable.
+            sources = new RegisterSpecList(1);
+            sources.set(0, RegisterSpec.make(localIndex, arg(0)));
+        } else {
+            sources = new RegisterSpecList(count);
+            int regAt = stackPointer;
+            for (int i = 0; i < count; i++) {
+                RegisterSpec spec = RegisterSpec.make(regAt, arg(i));
+                sources.set(i, spec);
+                regAt += spec.getCategory();
+            }
+
+            switch (opcode) {
+                case ByteOps.IASTORE: {
+                    /*
+                     * The Java argument order for array stores is
+                     * (array, index, value), but the rop argument
+                     * order is (value, array, index). The following
+                     * code gets the right arguments in the right
+                     * places.
+                     */
+                    if (count != 3) {
+                        throw new RuntimeException("shouldn't happen");
+                    }
+                    RegisterSpec array = sources.get(0);
+                    RegisterSpec index = sources.get(1);
+                    RegisterSpec value = sources.get(2);
+                    sources.set(0, value);
+                    sources.set(1, array);
+                    sources.set(2, index);
+                    break;
+                }
+                case ByteOps.PUTFIELD: {
+                    /*
+                     * Similar to above: The Java argument order for
+                     * putfield is (object, value), but the rop
+                     * argument order is (value, object).
+                     */
+                    if (count != 2) {
+                        throw new RuntimeException("shouldn't happen");
+                    }
+                    RegisterSpec obj = sources.get(0);
+                    RegisterSpec value = sources.get(1);
+                    sources.set(0, value);
+                    sources.set(1, obj);
+                    break;
+                }
+            }
+        }
+
+        sources.setImmutable();
+        return sources;
+    }
+
+    /**
+     * Sets or updates the information about the return block.
+     *
+     * @param op {@code non-null;} the opcode to use
+     * @param pos {@code non-null;} the position to use
+     */
+    private void updateReturnOp(Rop op, SourcePosition pos) {
+        if (op == null) {
+            throw new NullPointerException("op == null");
+        }
+
+        if (pos == null) {
+            throw new NullPointerException("pos == null");
+        }
+
+        if (returnOp == null) {
+            returnOp = op;
+            returnPosition = pos;
+        } else {
+            if (returnOp != op) {
+                throw new SimException("return op mismatch: " + op + ", " +
+                                       returnOp);
+            }
+
+            if (pos.getLine() > returnPosition.getLine()) {
+                // Pick the largest line number to be the "canonical" return.
+                returnPosition = pos;
+            }
+        }
+    }
+
+    /**
+     * Gets the register opcode for the given Java opcode.
+     *
+     * @param jop {@code >= 0;} the Java opcode
+     * @param cst {@code null-ok;} the constant argument, if any
+     * @return {@code >= 0;} the corresponding register opcode
+     */
+    private int jopToRopOpcode(int jop, Constant cst) {
+        switch (jop) {
+            case ByteOps.POP:
+            case ByteOps.POP2:
+            case ByteOps.DUP:
+            case ByteOps.DUP_X1:
+            case ByteOps.DUP_X2:
+            case ByteOps.DUP2:
+            case ByteOps.DUP2_X1:
+            case ByteOps.DUP2_X2:
+            case ByteOps.SWAP:
+            case ByteOps.JSR:
+            case ByteOps.RET:
+            case ByteOps.MULTIANEWARRAY: {
+                // These need to be taken care of specially.
+                break;
+            }
+            case ByteOps.NOP: {
+                return RegOps.NOP;
+            }
+            case ByteOps.LDC:
+            case ByteOps.LDC2_W: {
+                return RegOps.CONST;
+            }
+            case ByteOps.ILOAD:
+            case ByteOps.ISTORE: {
+                return RegOps.MOVE;
+            }
+            case ByteOps.IALOAD: {
+                return RegOps.AGET;
+            }
+            case ByteOps.IASTORE: {
+                return RegOps.APUT;
+            }
+            case ByteOps.IADD:
+            case ByteOps.IINC: {
+                return RegOps.ADD;
+            }
+            case ByteOps.ISUB: {
+                return RegOps.SUB;
+            }
+            case ByteOps.IMUL: {
+                return RegOps.MUL;
+            }
+            case ByteOps.IDIV: {
+                return RegOps.DIV;
+            }
+            case ByteOps.IREM: {
+                return RegOps.REM;
+            }
+            case ByteOps.INEG: {
+                return RegOps.NEG;
+            }
+            case ByteOps.ISHL: {
+                return RegOps.SHL;
+            }
+            case ByteOps.ISHR: {
+                return RegOps.SHR;
+            }
+            case ByteOps.IUSHR: {
+                return RegOps.USHR;
+            }
+            case ByteOps.IAND: {
+                return RegOps.AND;
+            }
+            case ByteOps.IOR: {
+                return RegOps.OR;
+            }
+            case ByteOps.IXOR: {
+                return RegOps.XOR;
+            }
+            case ByteOps.I2L:
+            case ByteOps.I2F:
+            case ByteOps.I2D:
+            case ByteOps.L2I:
+            case ByteOps.L2F:
+            case ByteOps.L2D:
+            case ByteOps.F2I:
+            case ByteOps.F2L:
+            case ByteOps.F2D:
+            case ByteOps.D2I:
+            case ByteOps.D2L:
+            case ByteOps.D2F: {
+                return RegOps.CONV;
+            }
+            case ByteOps.I2B: {
+                return RegOps.TO_BYTE;
+            }
+            case ByteOps.I2C: {
+                return RegOps.TO_CHAR;
+            }
+            case ByteOps.I2S: {
+                return RegOps.TO_SHORT;
+            }
+            case ByteOps.LCMP:
+            case ByteOps.FCMPL:
+            case ByteOps.DCMPL: {
+                return RegOps.CMPL;
+            }
+            case ByteOps.FCMPG:
+            case ByteOps.DCMPG: {
+                return RegOps.CMPG;
+            }
+            case ByteOps.IFEQ:
+            case ByteOps.IF_ICMPEQ:
+            case ByteOps.IF_ACMPEQ:
+            case ByteOps.IFNULL: {
+                return RegOps.IF_EQ;
+            }
+            case ByteOps.IFNE:
+            case ByteOps.IF_ICMPNE:
+            case ByteOps.IF_ACMPNE:
+            case ByteOps.IFNONNULL: {
+                return RegOps.IF_NE;
+            }
+            case ByteOps.IFLT:
+            case ByteOps.IF_ICMPLT: {
+                return RegOps.IF_LT;
+            }
+            case ByteOps.IFGE:
+            case ByteOps.IF_ICMPGE: {
+                return RegOps.IF_GE;
+            }
+            case ByteOps.IFGT:
+            case ByteOps.IF_ICMPGT: {
+                return RegOps.IF_GT;
+            }
+            case ByteOps.IFLE:
+            case ByteOps.IF_ICMPLE: {
+                return RegOps.IF_LE;
+            }
+            case ByteOps.GOTO: {
+                return RegOps.GOTO;
+            }
+            case ByteOps.LOOKUPSWITCH: {
+                return RegOps.SWITCH;
+            }
+            case ByteOps.IRETURN:
+            case ByteOps.RETURN: {
+                return RegOps.RETURN;
+            }
+            case ByteOps.GETSTATIC: {
+                return RegOps.GET_STATIC;
+            }
+            case ByteOps.PUTSTATIC: {
+                return RegOps.PUT_STATIC;
+            }
+            case ByteOps.GETFIELD: {
+                return RegOps.GET_FIELD;
+            }
+            case ByteOps.PUTFIELD: {
+                return RegOps.PUT_FIELD;
+            }
+            case ByteOps.INVOKEVIRTUAL: {
+                return RegOps.INVOKE_VIRTUAL;
+            }
+            case ByteOps.INVOKESPECIAL: {
+                /*
+                 * Determine whether the opcode should be
+                 * INVOKE_DIRECT or INVOKE_SUPER. See vmspec-2 section 6
+                 * on "invokespecial" as well as section 4.8.2 (7th
+                 * bullet point) for the gory details.
+                 */
+                CstMethodRef ref = (CstMethodRef) cst;
+                if (ref.isInstanceInit() ||
+                    (ref.getDefiningClass() == method.getDefiningClass()) ||
+                    !method.getAccSuper()) {
+                    return RegOps.INVOKE_DIRECT;
+                }
+                return RegOps.INVOKE_SUPER;
+            }
+            case ByteOps.INVOKESTATIC: {
+                return RegOps.INVOKE_STATIC;
+            }
+            case ByteOps.INVOKEINTERFACE: {
+                return RegOps.INVOKE_INTERFACE;
+            }
+            case ByteOps.NEW: {
+                return RegOps.NEW_INSTANCE;
+            }
+            case ByteOps.NEWARRAY:
+            case ByteOps.ANEWARRAY: {
+                return RegOps.NEW_ARRAY;
+            }
+            case ByteOps.ARRAYLENGTH: {
+                return RegOps.ARRAY_LENGTH;
+            }
+            case ByteOps.ATHROW: {
+                return RegOps.THROW;
+            }
+            case ByteOps.CHECKCAST: {
+                return RegOps.CHECK_CAST;
+            }
+            case ByteOps.INSTANCEOF: {
+                return RegOps.INSTANCE_OF;
+            }
+            case ByteOps.MONITORENTER: {
+                return RegOps.MONITOR_ENTER;
+            }
+            case ByteOps.MONITOREXIT: {
+                return RegOps.MONITOR_EXIT;
+            }
+        }
+
+        throw new RuntimeException("shouldn't happen");
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/SimException.java b/dx/src/com/android/dx/cf/code/SimException.java
new file mode 100644
index 0000000..220f281
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/SimException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.util.ExceptionWithContext;
+
+/**
+ * Exception from simulation.
+ */
+public class SimException
+        extends ExceptionWithContext {
+    public SimException(String message) {
+        super(message);
+    }
+
+    public SimException(Throwable cause) {
+        super(cause);
+    }
+
+    public SimException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
new file mode 100644
index 0000000..c097831
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstInterfaceMethodRef;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.util.Hex;
+
+import java.util.ArrayList;
+
+/**
+ * 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 {
+    /**
+     * {@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.";
+
+    /** {@code non-null;} machine to use when simulating */
+    private final Machine machine;
+
+    /** {@code non-null;} array of bytecode */
+    private final BytecodeArray code;
+
+    /** {@code non-null;} local variable information */
+    private final LocalVariableList localVariables;
+
+    /** {@code non-null;} visitor instance to use */
+    private final SimVisitor visitor;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+            throw new NullPointerException("machine == null");
+        }
+
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        this.machine = machine;
+        this.code = method.getCode();
+        this.localVariables = method.getLocalVariables();
+        this.visitor = new SimVisitor();
+    }
+
+    /**
+     * Simulates the effect of executing the given basic block. This modifies
+     * the passed-in frame to represent the end result.
+     *
+     * @param bb {@code non-null;} the basic block
+     * @param frame {@code non-null;} frame to operate on
+     */
+    public void simulate(ByteBlock bb, Frame frame) {
+        int end = bb.getEnd();
+
+        visitor.setFrame(frame);
+
+        try {
+            for (int off = bb.getStart(); off < end; /*off*/) {
+                int length = code.parseInstruction(off, visitor);
+                visitor.setPreviousOffset(off);
+                off += length;
+            }
+        } catch (SimException ex) {
+            frame.annotate(ex);
+            throw ex;
+        }
+    }
+
+    /**
+     * Simulates the effect of the instruction at the given offset, by
+     * making appropriate calls on the given frame.
+     *
+     * @param offset {@code >= 0;} offset of the instruction to simulate
+     * @param frame {@code non-null;} frame to operate on
+     * @return the length of the instruction, in bytes
+     */
+    public int simulate(int offset, Frame frame) {
+        visitor.setFrame(frame);
+        return code.parseInstruction(offset, visitor);
+    }
+
+    /**
+     * Constructs an "illegal top-of-stack" exception, for the stack
+     * manipulation opcodes.
+     */
+    private static SimException illegalTos() {
+        return new SimException("stack mismatch: illegal " +
+                "top-of-stack for opcode");
+    }
+
+    /**
+     * Returns the required array type for an array load or store
+     * instruction, based on a given implied type and an observed
+     * actual array type.
+     *
+     * <p>The interesting cases here have to do with object arrays,
+     * <code>byte[]</code>s, <code>boolean[]</code>s, and
+     * known-nulls.</p>
+     *
+     * <p>In the case of arrays of objects, we want to narrow the type
+     * to the actual array present on the stack, as long as what is
+     * present is an object type. Similarly, due to a quirk of the
+     * original bytecode representation, the instructions for dealing
+     * with <code>byte[]</code> and <code>boolean[]</code> are
+     * undifferentiated, and we aim here to return whichever one was
+     * actually present on the stack.</p>
+     *
+     * <p>In the case where there is a known-null on the stack where
+     * an array is expected, we just fall back to the implied type of
+     * the instruction. Due to the quirk described above, this means
+     * that source code that uses <code>boolean[]</code> might get
+     * translated surprisingly -- but correctly -- into an instruction
+     * that specifies a <code>byte[]</code>. It will be correct,
+     * because should the code actually execute, it will necessarily
+     * throw a <code>NullPointerException</code>, and it won't matter
+     * what opcode variant is used to achieve that result.</p>
+     *
+     * @param impliedType {@code non-null;} type implied by the
+     * instruction; is <i>not</i> an array type
+     * @param foundArrayType {@code non-null;} type found on the
+     * stack; is either an array type or a known-null
+     * @return {@code non-null;} the array type that should be
+     * required in this context
+     */
+    private static Type requiredArrayTypeFor(Type impliedType,
+            Type foundArrayType) {
+        if (foundArrayType == Type.KNOWN_NULL) {
+            return impliedType.getArrayType();
+        }
+
+        if ((impliedType == Type.OBJECT)
+                && foundArrayType.isArray()
+                && foundArrayType.getComponentType().isReference()) {
+            return foundArrayType;
+        }
+
+        if ((impliedType == Type.BYTE)
+                && (foundArrayType == Type.BOOLEAN_ARRAY)) {
+            /*
+             * Per above, an instruction with implied byte[] is also
+             * allowed to be used on boolean[].
+             */
+            return Type.BOOLEAN_ARRAY;
+        }
+
+        return impliedType.getArrayType();
+    }
+
+    /**
+     * Bytecode visitor used during simulation.
+     */
+    private class SimVisitor implements BytecodeArray.Visitor {
+        /**
+         * {@code non-null;} machine instance to use (just to avoid excessive
+         * cross-object field access)
+         */
+        private final Machine machine;
+
+        /**
+         * {@code null-ok;} frame to use; set with each call to
+         * {@link Simulator#simulate}
+         */
+        private Frame frame;
+
+        /** offset of the previous bytecode */
+        private int previousOffset;
+
+        /**
+         * Constructs an instance.
+         */
+        public SimVisitor() {
+            this.machine = Simulator.this.machine;
+            this.frame = null;
+        }
+
+        /**
+         * Sets the frame to act on.
+         *
+         * @param frame {@code non-null;} the frame
+         */
+        public void setFrame(Frame frame) {
+            if (frame == null) {
+                throw new NullPointerException("frame == null");
+            }
+
+            this.frame = frame;
+        }
+
+        /** {@inheritDoc} */
+        public void visitInvalid(int opcode, int offset, int length) {
+            throw new SimException("invalid opcode " + Hex.u1(opcode));
+        }
+
+        /** {@inheritDoc} */
+        public void visitNoArgs(int opcode, int offset, int length,
+                Type type) {
+            switch (opcode) {
+                case ByteOps.NOP: {
+                    machine.clearArgs();
+                    break;
+                }
+                case ByteOps.INEG: {
+                    machine.popArgs(frame, type);
+                    break;
+                }
+                case ByteOps.I2L:
+                case ByteOps.I2F:
+                case ByteOps.I2D:
+                case ByteOps.I2B:
+                case ByteOps.I2C:
+                case ByteOps.I2S: {
+                    machine.popArgs(frame, Type.INT);
+                    break;
+                }
+                case ByteOps.L2I:
+                case ByteOps.L2F:
+                case ByteOps.L2D: {
+                    machine.popArgs(frame, Type.LONG);
+                    break;
+                }
+                case ByteOps.F2I:
+                case ByteOps.F2L:
+                case ByteOps.F2D: {
+                    machine.popArgs(frame, Type.FLOAT);
+                    break;
+                }
+                case ByteOps.D2I:
+                case ByteOps.D2L:
+                case ByteOps.D2F: {
+                    machine.popArgs(frame, Type.DOUBLE);
+                    break;
+                }
+                case ByteOps.RETURN: {
+                    machine.clearArgs();
+                    checkReturnType(Type.VOID);
+                    break;
+                }
+                case ByteOps.IRETURN: {
+                    Type checkType = type;
+                    if (type == Type.OBJECT) {
+                        /*
+                         * For an object return, use the best-known
+                         * type of the popped value.
+                         */
+                        checkType = frame.getStack().peekType(0);
+                    }
+                    machine.popArgs(frame, type);
+                    checkReturnType(checkType);
+                    break;
+                }
+                case ByteOps.POP: {
+                    Type peekType = frame.getStack().peekType(0);
+                    if (peekType.isCategory2()) {
+                        throw illegalTos();
+                    }
+                    machine.popArgs(frame, 1);
+                    break;
+                }
+                case ByteOps.ARRAYLENGTH: {
+                    Type arrayType = frame.getStack().peekType(0);
+                    if (!arrayType.isArrayOrKnownNull()) {
+                        throw new SimException("type mismatch: expected " +
+                                "array type but encountered " +
+                                arrayType.toHuman());
+                    }
+                    machine.popArgs(frame, Type.OBJECT);
+                    break;
+                }
+                case ByteOps.ATHROW:
+                case ByteOps.MONITORENTER:
+                case ByteOps.MONITOREXIT: {
+                    machine.popArgs(frame, Type.OBJECT);
+                    break;
+                }
+                case ByteOps.IALOAD: {
+                    /*
+                     * See comment on requiredArrayTypeFor() for explanation
+                     * about what's going on here.
+                     */
+                    Type foundArrayType = frame.getStack().peekType(1);
+                    Type requiredArrayType =
+                        requiredArrayTypeFor(type, foundArrayType);
+
+                    // Make type agree with the discovered requiredArrayType.
+                    type = requiredArrayType.getComponentType();
+
+                    machine.popArgs(frame, requiredArrayType, Type.INT);
+                    break;
+                }
+                case ByteOps.IADD:
+                case ByteOps.ISUB:
+                case ByteOps.IMUL:
+                case ByteOps.IDIV:
+                case ByteOps.IREM:
+                case ByteOps.IAND:
+                case ByteOps.IOR:
+                case ByteOps.IXOR: {
+                    machine.popArgs(frame, type, type);
+                    break;
+                }
+                case ByteOps.ISHL:
+                case ByteOps.ISHR:
+                case ByteOps.IUSHR: {
+                    machine.popArgs(frame, type, Type.INT);
+                    break;
+                }
+                case ByteOps.LCMP: {
+                    machine.popArgs(frame, Type.LONG, Type.LONG);
+                    break;
+                }
+                case ByteOps.FCMPL:
+                case ByteOps.FCMPG: {
+                    machine.popArgs(frame, Type.FLOAT, Type.FLOAT);
+                    break;
+                }
+                case ByteOps.DCMPL:
+                case ByteOps.DCMPG: {
+                    machine.popArgs(frame, Type.DOUBLE, Type.DOUBLE);
+                    break;
+                }
+                case ByteOps.IASTORE: {
+                    /*
+                     * See comment on requiredArrayTypeFor() for
+                     * explanation about what's going on here. In
+                     * addition to that, the category 1 vs. 2 thing
+                     * below is to deal with the fact that, if the
+                     * element type is category 2, we have to skip
+                     * over one extra stack slot to find the array.
+                     */
+                    ExecutionStack stack = frame.getStack();
+                    int peekDepth = type.isCategory1() ? 2 : 3;
+                    Type foundArrayType = stack.peekType(peekDepth);
+                    boolean foundArrayLocal = stack.peekLocal(peekDepth);
+
+                    Type requiredArrayType =
+                        requiredArrayTypeFor(type, foundArrayType);
+
+                    /*
+                     * Make type agree with the discovered requiredArrayType
+                     * if it has local info.
+                     */
+                    if (foundArrayLocal) {
+                        type = requiredArrayType.getComponentType();
+                    }
+
+                    machine.popArgs(frame, requiredArrayType, Type.INT, type);
+                    break;
+                }
+                case ByteOps.POP2:
+                case ByteOps.DUP2: {
+                    ExecutionStack stack = frame.getStack();
+                    int pattern;
+
+                    if (stack.peekType(0).isCategory2()) {
+                        // "form 2" in vmspec-2
+                        machine.popArgs(frame, 1);
+                        pattern = 0x11;
+                    } else if (stack.peekType(1).isCategory1()) {
+                        // "form 1"
+                        machine.popArgs(frame, 2);
+                        pattern = 0x2121;
+                    } else {
+                        throw illegalTos();
+                    }
+
+                    if (opcode == ByteOps.DUP2) {
+                        machine.auxIntArg(pattern);
+                    }
+                    break;
+                }
+                case ByteOps.DUP: {
+                    Type peekType = frame.getStack().peekType(0);
+
+                    if (peekType.isCategory2()) {
+                        throw illegalTos();
+                    }
+
+                    machine.popArgs(frame, 1);
+                    machine.auxIntArg(0x11);
+                    break;
+                }
+                case ByteOps.DUP_X1: {
+                    ExecutionStack stack = frame.getStack();
+
+                    if (!(stack.peekType(0).isCategory1() &&
+                          stack.peekType(1).isCategory1())) {
+                        throw illegalTos();
+                    }
+
+                    machine.popArgs(frame, 2);
+                    machine.auxIntArg(0x212);
+                    break;
+                }
+                case ByteOps.DUP_X2: {
+                    ExecutionStack stack = frame.getStack();
+
+                    if (stack.peekType(0).isCategory2()) {
+                        throw illegalTos();
+                    }
+
+                    if (stack.peekType(1).isCategory2()) {
+                        // "form 2" in vmspec-2
+                        machine.popArgs(frame, 2);
+                        machine.auxIntArg(0x212);
+                    } else if (stack.peekType(2).isCategory1()) {
+                        // "form 1"
+                        machine.popArgs(frame, 3);
+                        machine.auxIntArg(0x3213);
+                    } else {
+                        throw illegalTos();
+                    }
+                    break;
+                }
+                case ByteOps.DUP2_X1: {
+                    ExecutionStack stack = frame.getStack();
+
+                    if (stack.peekType(0).isCategory2()) {
+                        // "form 2" in vmspec-2
+                        if (stack.peekType(2).isCategory2()) {
+                            throw illegalTos();
+                        }
+                        machine.popArgs(frame, 2);
+                        machine.auxIntArg(0x212);
+                    } else {
+                        // "form 1"
+                        if (stack.peekType(1).isCategory2() ||
+                            stack.peekType(2).isCategory2()) {
+                            throw illegalTos();
+                        }
+                        machine.popArgs(frame, 3);
+                        machine.auxIntArg(0x32132);
+                    }
+                    break;
+                }
+                case ByteOps.DUP2_X2: {
+                    ExecutionStack stack = frame.getStack();
+
+                    if (stack.peekType(0).isCategory2()) {
+                        if (stack.peekType(2).isCategory2()) {
+                            // "form 4" in vmspec-2
+                            machine.popArgs(frame, 2);
+                            machine.auxIntArg(0x212);
+                        } else if (stack.peekType(3).isCategory1()) {
+                            // "form 2"
+                            machine.popArgs(frame, 3);
+                            machine.auxIntArg(0x3213);
+                        } else {
+                            throw illegalTos();
+                        }
+                    } else if (stack.peekType(1).isCategory1()) {
+                        if (stack.peekType(2).isCategory2()) {
+                            // "form 3"
+                            machine.popArgs(frame, 3);
+                            machine.auxIntArg(0x32132);
+                        } else if (stack.peekType(3).isCategory1()) {
+                            // "form 1"
+                            machine.popArgs(frame, 4);
+                            machine.auxIntArg(0x432143);
+                        } else {
+                            throw illegalTos();
+                        }
+                    } else {
+                        throw illegalTos();
+                    }
+                    break;
+                }
+                case ByteOps.SWAP: {
+                    ExecutionStack stack = frame.getStack();
+
+                    if (!(stack.peekType(0).isCategory1() &&
+                          stack.peekType(1).isCategory1())) {
+                        throw illegalTos();
+                    }
+
+                    machine.popArgs(frame, 2);
+                    machine.auxIntArg(0x12);
+                    break;
+                }
+                default: {
+                    visitInvalid(opcode, offset, length);
+                    return;
+                }
+            }
+
+            machine.auxType(type);
+            machine.run(frame, offset, opcode);
+        }
+
+        /**
+         * Checks whether the prototype is compatible with returning the
+         * given type, and throws if not.
+         *
+         * @param encountered {@code non-null;} the encountered return type
+         */
+        private void checkReturnType(Type encountered) {
+            Type returnType = machine.getPrototype().getReturnType();
+
+            /*
+             * Check to see if the prototype's return type is
+             * possibly assignable from the type we encountered. This
+             * takes care of all the salient cases (types are the same,
+             * they're compatible primitive types, etc.).
+             */
+            if (!Merger.isPossiblyAssignableFrom(returnType, encountered)) {
+                throw new SimException("return type mismatch: prototype " +
+                        "indicates " + returnType.toHuman() +
+                        ", but encountered type " + encountered.toHuman());
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitLocal(int opcode, int offset, int length,
+                int idx, Type type, int value) {
+            /*
+             * Note that the "type" parameter is always the simplest
+             * type based on the original opcode, e.g., "int" for
+             * "iload" (per se) and "Object" for "aload". So, when
+             * possible, we replace the type with the one indicated in
+             * the local variable table, though we still need to check
+             * to make sure it's valid for the opcode.
+             *
+             * The reason we use (offset + length) for the localOffset
+             * for a store is because it is only after the store that
+             * the local type becomes valid. On the other hand, the
+             * type associated with a load is valid at the start of
+             * the instruction.
+             */
+            int localOffset =
+                (opcode == ByteOps.ISTORE) ? (offset + length) : offset;
+            LocalVariableList.Item local =
+                localVariables.pcAndIndexToLocal(localOffset, idx);
+            Type localType;
+
+            if (local != null) {
+                localType = local.getType();
+                if (localType.getBasicFrameType() !=
+                        type.getBasicFrameType()) {
+                    BaseMachine.throwLocalMismatch(type, localType);
+                    return;
+                }
+            } else {
+                localType = type;
+            }
+
+            switch (opcode) {
+                case ByteOps.ILOAD:
+                case ByteOps.RET: {
+                    machine.localArg(frame, idx);
+                    machine.localInfo(local != null);
+                    machine.auxType(type);
+                    break;
+                }
+                case ByteOps.ISTORE: {
+                    LocalItem item
+                            = (local == null) ? null : local.getLocalItem();
+                    machine.popArgs(frame, type);
+                    machine.auxType(type);
+                    machine.localTarget(idx, localType, item);
+                    break;
+                }
+                case ByteOps.IINC: {
+                    LocalItem item
+                            = (local == null) ? null : local.getLocalItem();
+                    machine.localArg(frame, idx);
+                    machine.localTarget(idx, localType, item);
+                    machine.auxType(type);
+                    machine.auxIntArg(value);
+                    machine.auxCstArg(CstInteger.make(value));
+                    break;
+                }
+                default: {
+                    visitInvalid(opcode, offset, length);
+                    return;
+                }
+            }
+
+            machine.run(frame, offset, opcode);
+        }
+
+        /** {@inheritDoc} */
+        public void visitConstant(int opcode, int offset, int length,
+                Constant cst, int value) {
+            switch (opcode) {
+                case ByteOps.ANEWARRAY: {
+                    machine.popArgs(frame, Type.INT);
+                    break;
+                }
+                case ByteOps.PUTSTATIC: {
+                    Type fieldType = ((CstFieldRef) cst).getType();
+                    machine.popArgs(frame, fieldType);
+                    break;
+                }
+                case ByteOps.GETFIELD:
+                case ByteOps.CHECKCAST:
+                case ByteOps.INSTANCEOF: {
+                    machine.popArgs(frame, Type.OBJECT);
+                    break;
+                }
+                case ByteOps.PUTFIELD: {
+                    Type fieldType = ((CstFieldRef) cst).getType();
+                    machine.popArgs(frame, Type.OBJECT, fieldType);
+                    break;
+                }
+                case ByteOps.INVOKEINTERFACE: {
+                    /*
+                     * Convert the interface method ref into a normal
+                     * method ref.
+                     */
+                    cst = ((CstInterfaceMethodRef) cst).toMethodRef();
+                    // and fall through...
+                }
+                case ByteOps.INVOKEVIRTUAL:
+                case ByteOps.INVOKESPECIAL: {
+                    /*
+                     * Get the instance prototype, and use it to direct
+                     * the machine.
+                     */
+                    Prototype prototype =
+                        ((CstMethodRef) cst).getPrototype(false);
+                    machine.popArgs(frame, prototype);
+                    break;
+                }
+                case ByteOps.INVOKESTATIC: {
+                    /*
+                     * Get the static prototype, and use it to direct
+                     * the machine.
+                     */
+                    Prototype prototype =
+                        ((CstMethodRef) cst).getPrototype(true);
+                    machine.popArgs(frame, prototype);
+                    break;
+                }
+                case ByteOps.MULTIANEWARRAY: {
+                    /*
+                     * The "value" here is the count of dimensions to
+                     * create. Make a prototype of that many "int"
+                     * types, and tell the machine to pop them. This
+                     * isn't the most efficient way in the world to do
+                     * this, but then again, multianewarray is pretty
+                     * darn rare and so not worth much effort
+                     * optimizing for.
+                     */
+                    Prototype prototype =
+                        Prototype.internInts(Type.VOID, value);
+                    machine.popArgs(frame, prototype);
+                    break;
+                }
+                default: {
+                    machine.clearArgs();
+                    break;
+                }
+            }
+
+            machine.auxIntArg(value);
+            machine.auxCstArg(cst);
+            machine.run(frame, offset, opcode);
+        }
+
+        /** {@inheritDoc} */
+        public void visitBranch(int opcode, int offset, int length,
+                int target) {
+            switch (opcode) {
+                case ByteOps.IFEQ:
+                case ByteOps.IFNE:
+                case ByteOps.IFLT:
+                case ByteOps.IFGE:
+                case ByteOps.IFGT:
+                case ByteOps.IFLE: {
+                    machine.popArgs(frame, Type.INT);
+                    break;
+                }
+                case ByteOps.IFNULL:
+                case ByteOps.IFNONNULL: {
+                    machine.popArgs(frame, Type.OBJECT);
+                    break;
+                }
+                case ByteOps.IF_ICMPEQ:
+                case ByteOps.IF_ICMPNE:
+                case ByteOps.IF_ICMPLT:
+                case ByteOps.IF_ICMPGE:
+                case ByteOps.IF_ICMPGT:
+                case ByteOps.IF_ICMPLE: {
+                    machine.popArgs(frame, Type.INT, Type.INT);
+                    break;
+                }
+                case ByteOps.IF_ACMPEQ:
+                case ByteOps.IF_ACMPNE: {
+                    machine.popArgs(frame, Type.OBJECT, Type.OBJECT);
+                    break;
+                }
+                case ByteOps.GOTO:
+                case ByteOps.JSR:
+                case ByteOps.GOTO_W:
+                case ByteOps.JSR_W: {
+                    machine.clearArgs();
+                    break;
+                }
+                default: {
+                    visitInvalid(opcode, offset, length);
+                    return;
+                }
+            }
+
+            machine.auxTargetArg(target);
+            machine.run(frame, offset, opcode);
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitch(int opcode, int offset, int length,
+                SwitchList cases, int padding) {
+            machine.popArgs(frame, Type.INT);
+            machine.auxIntArg(padding);
+            machine.auxSwitchArg(cases);
+            machine.run(frame, offset, opcode);
+        }
+
+        /** {@inheritDoc} */
+        public void visitNewarray(int offset, int length, CstType type,
+                ArrayList<Constant> initValues) {
+            machine.popArgs(frame, Type.INT);
+            machine.auxInitValues(initValues);
+            machine.auxCstArg(type);
+            machine.run(frame, offset, ByteOps.NEWARRAY);
+        }
+
+        /** {@inheritDoc} */
+        public void setPreviousOffset(int offset) {
+            previousOffset = offset;
+        }
+
+        /** {@inheritDoc} */
+        public int getPreviousOffset() {
+            return previousOffset;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/SwitchList.java b/dx/src/com/android/dx/cf/code/SwitchList.java
new file mode 100644
index 0000000..621d728
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/SwitchList.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.util.IntList;
+import com.android.dx.util.MutabilityControl;
+
+/**
+ * List of (value, target) mappings representing the choices of a
+ * {@code tableswitch} or {@code lookupswitch} instruction. It
+ * also holds the default target for the switch.
+ */
+public final class SwitchList extends MutabilityControl {
+    /** {@code non-null;} list of test values */
+    private final IntList values;
+
+    /**
+     * {@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
+     */
+    private final IntList targets;
+
+    /** ultimate size of the list */
+    private int size;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param size {@code >= 0;} the number of elements to be in the table
+     */
+    public SwitchList(int size) {
+        super(true);
+        this.values = new IntList(size);
+        this.targets = new IntList(size + 1);
+        this.size = size;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void setImmutable() {
+        values.setImmutable();
+        targets.setImmutable();
+        super.setImmutable();
+    }
+
+    /**
+     * Gets the size of the list.
+     *
+     * @return {@code >= 0;} the list size
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Gets the indicated test value.
+     *
+     * @param n {@code >= 0;}, &lt; size(); which index
+     * @return the test value
+     */
+    public int getValue(int n) {
+        return values.get(n);
+    }
+
+    /**
+     * Gets the indicated target. Asking for the target at {@code size()}
+     * returns the default target.
+     *
+     * @param n {@code >= 0, <= size();} which index
+     * @return {@code >= 0;} the target
+     */
+    public int getTarget(int n) {
+        return targets.get(n);
+    }
+
+    /**
+     * Gets the default target. This is just a shorthand for
+     * {@code getTarget(size())}.
+     *
+     * @return {@code >= 0;} the default target
+     */
+    public int getDefaultTarget() {
+        return targets.get(size);
+    }
+
+    /**
+     * Gets the list of all targets. This includes one extra element at the
+     * end of the list, which holds the default target.
+     *
+     * @return {@code non-null;} the target list
+     */
+    public IntList getTargets() {
+        return targets;
+    }
+
+    /**
+     * Gets the list of all case values.
+     *
+     * @return {@code non-null;} the case value list
+     */
+    public IntList getValues() {
+        return values;
+    }
+
+    /**
+     * Sets the default target. It is only valid to call this method
+     * when all the non-default elements have been set.
+     *
+     * @param target {@code >= 0;} the absolute (not relative) default target
+     * address
+     */
+    public void setDefaultTarget(int target) {
+        throwIfImmutable();
+
+        if (target < 0) {
+            throw new IllegalArgumentException("target < 0");
+        }
+
+        if (targets.size() != size) {
+            throw new RuntimeException("non-default elements not all set");
+        }
+
+        targets.add(target);
+    }
+
+    /**
+     * Adds the given item.
+     *
+     * @param value the test value
+     * @param target {@code >= 0;} the absolute (not relative) target address
+     */
+    public void add(int value, int target) {
+        throwIfImmutable();
+
+        if (target < 0) {
+            throw new IllegalArgumentException("target < 0");
+        }
+
+        values.add(value);
+        targets.add(target);
+    }
+
+    /**
+     * Shrinks this instance if possible, removing test elements that
+     * refer to the default target. This is only valid after the instance
+     * is fully populated, including the default target (naturally).
+     */
+    public void removeSuperfluousDefaults() {
+        throwIfImmutable();
+
+        int sz = size;
+
+        if (sz != (targets.size() - 1)) {
+            throw new IllegalArgumentException("incomplete instance");
+        }
+
+        int defaultTarget = targets.get(sz);
+        int at = 0;
+
+        for (int i = 0; i < sz; i++) {
+            int target = targets.get(i);
+            if (target != defaultTarget) {
+                if (i != at) {
+                    targets.set(at, target);
+                    values.set(at, values.get(i));
+                }
+                at++;
+            }
+        }
+
+        if (at != sz) {
+            values.shrink(at);
+            targets.set(at, defaultTarget);
+            targets.shrink(at + 1);
+            size = at;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/ValueAwareMachine.java b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
new file mode 100644
index 0000000..de75db5
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.code;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.Hex;
+
+/**
+ * {@link Machine} which keeps track of known values but does not do
+ * smart/realistic reference type calculations.
+ */
+public class ValueAwareMachine extends BaseMachine {
+    /**
+     * Constructs an instance.
+     *
+     * @param prototype {@code non-null;} the prototype for the associated
+     * method
+     */
+    public ValueAwareMachine(Prototype prototype) {
+        super(prototype);
+    }
+
+    /** {@inheritDoc} */
+    public void run(Frame frame, int offset, int opcode) {
+        switch (opcode) {
+            case ByteOps.NOP:
+            case ByteOps.IASTORE:
+            case ByteOps.POP:
+            case ByteOps.POP2:
+            case ByteOps.IFEQ:
+            case ByteOps.IFNE:
+            case ByteOps.IFLT:
+            case ByteOps.IFGE:
+            case ByteOps.IFGT:
+            case ByteOps.IFLE:
+            case ByteOps.IF_ICMPEQ:
+            case ByteOps.IF_ICMPNE:
+            case ByteOps.IF_ICMPLT:
+            case ByteOps.IF_ICMPGE:
+            case ByteOps.IF_ICMPGT:
+            case ByteOps.IF_ICMPLE:
+            case ByteOps.IF_ACMPEQ:
+            case ByteOps.IF_ACMPNE:
+            case ByteOps.GOTO:
+            case ByteOps.RET:
+            case ByteOps.LOOKUPSWITCH:
+            case ByteOps.IRETURN:
+            case ByteOps.RETURN:
+            case ByteOps.PUTSTATIC:
+            case ByteOps.PUTFIELD:
+            case ByteOps.ATHROW:
+            case ByteOps.MONITORENTER:
+            case ByteOps.MONITOREXIT:
+            case ByteOps.IFNULL:
+            case ByteOps.IFNONNULL: {
+                // Nothing to do for these ops in this class.
+                clearResult();
+                break;
+            }
+            case ByteOps.LDC:
+            case ByteOps.LDC2_W: {
+                setResult((TypeBearer) getAuxCst());
+                break;
+            }
+            case ByteOps.ILOAD:
+            case ByteOps.ISTORE: {
+                setResult(arg(0));
+                break;
+            }
+            case ByteOps.IALOAD:
+            case ByteOps.IADD:
+            case ByteOps.ISUB:
+            case ByteOps.IMUL:
+            case ByteOps.IDIV:
+            case ByteOps.IREM:
+            case ByteOps.INEG:
+            case ByteOps.ISHL:
+            case ByteOps.ISHR:
+            case ByteOps.IUSHR:
+            case ByteOps.IAND:
+            case ByteOps.IOR:
+            case ByteOps.IXOR:
+            case ByteOps.IINC:
+            case ByteOps.I2L:
+            case ByteOps.I2F:
+            case ByteOps.I2D:
+            case ByteOps.L2I:
+            case ByteOps.L2F:
+            case ByteOps.L2D:
+            case ByteOps.F2I:
+            case ByteOps.F2L:
+            case ByteOps.F2D:
+            case ByteOps.D2I:
+            case ByteOps.D2L:
+            case ByteOps.D2F:
+            case ByteOps.I2B:
+            case ByteOps.I2C:
+            case ByteOps.I2S:
+            case ByteOps.LCMP:
+            case ByteOps.FCMPL:
+            case ByteOps.FCMPG:
+            case ByteOps.DCMPL:
+            case ByteOps.DCMPG:
+            case ByteOps.ARRAYLENGTH: {
+                setResult(getAuxType());
+                break;
+            }
+            case ByteOps.DUP:
+            case ByteOps.DUP_X1:
+            case ByteOps.DUP_X2:
+            case ByteOps.DUP2:
+            case ByteOps.DUP2_X1:
+            case ByteOps.DUP2_X2:
+            case ByteOps.SWAP: {
+                clearResult();
+                for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) {
+                    int which = (pattern & 0x0f) - 1;
+                    addResult(arg(which));
+                }
+                break;
+            }
+
+            case ByteOps.JSR: {
+                setResult(new ReturnAddress(getAuxTarget()));
+                break;
+            }
+            case ByteOps.GETSTATIC:
+            case ByteOps.GETFIELD:
+            case ByteOps.INVOKEVIRTUAL:
+            case ByteOps.INVOKESTATIC:
+            case ByteOps.INVOKEINTERFACE: {
+                Type type = ((TypeBearer) getAuxCst()).getType();
+                if (type == Type.VOID) {
+                    clearResult();
+                } else {
+                    setResult(type);
+                }
+                break;
+            }
+            case ByteOps.INVOKESPECIAL: {
+                Type thisType = arg(0).getType();
+                if (thisType.isUninitialized()) {
+                    frame.makeInitialized(thisType);
+                }
+                Type type = ((TypeBearer) getAuxCst()).getType();
+                if (type == Type.VOID) {
+                    clearResult();
+                } else {
+                    setResult(type);
+                }
+                break;
+            }
+            case ByteOps.NEW: {
+                Type type = ((CstType) getAuxCst()).getClassType();
+                setResult(type.asUninitialized(offset));
+                break;
+            }
+            case ByteOps.NEWARRAY:
+            case ByteOps.CHECKCAST:
+            case ByteOps.MULTIANEWARRAY: {
+                Type type = ((CstType) getAuxCst()).getClassType();
+                setResult(type);
+                break;
+            }
+            case ByteOps.ANEWARRAY: {
+                Type type = ((CstType) getAuxCst()).getClassType();
+                setResult(type.getArrayType());
+                break;
+            }
+            case ByteOps.INSTANCEOF: {
+                setResult(Type.INT);
+                break;
+            }
+            default: {
+                throw new RuntimeException("shouldn't happen: " +
+                                           Hex.u1(opcode));
+            }
+        }
+
+        storeResults(frame);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/code/package.html b/dx/src/com/android/dx/cf/code/package.html
new file mode 100644
index 0000000..abd4e9b
--- /dev/null
+++ b/dx/src/com/android/dx/cf/code/package.html
@@ -0,0 +1,10 @@
+<body>
+<p>Implementation of classes having to do with Java simulation, such as
+is needed for verification or stack-to-register conversion.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.rop.pool</code></li>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
new file mode 100644
index 0000000..7ec2fba
--- /dev/null
+++ b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.cst;
+
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Class;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Double;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Fieldref;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Float;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Integer;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_InterfaceMethodref;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Long;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Methodref;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_NameAndType;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_String;
+import static com.android.dx.cf.cst.ConstantTags.CONSTANT_Utf8;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstInterfaceMethodRef;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.StdConstantPool;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import java.util.BitSet;
+
+/**
+ * Parser for a constant pool embedded in a class file.
+ */
+public final class ConstantPoolParser {
+    /** {@code non-null;} the bytes of the constant pool */
+    private final ByteArray bytes;
+
+    /** {@code non-null;} actual parsed constant pool contents */
+    private final StdConstantPool pool;
+
+    /** {@code non-null;} byte offsets to each cst */
+    private final int[] offsets;
+
+    /**
+     * -1 || &gt;= 10; the end offset of this constant pool in the
+     * {@code byte[]} which it came from or {@code -1} if not
+     * yet parsed
+     */
+    private int endOffset;
+
+    /** {@code null-ok;} parse observer, if any */
+    private ParseObserver observer;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     */
+    public ConstantPoolParser(ByteArray bytes) {
+        int size = bytes.getUnsignedShort(8); // constant_pool_count
+
+        this.bytes = bytes;
+        this.pool = new StdConstantPool(size);
+        this.offsets = new int[size];
+        this.endOffset = -1;
+    }
+
+    /**
+     * Sets the parse observer for this instance.
+     *
+     * @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[]}
+     * which it came from.
+     *
+     * @return {@code >= 10;} the end offset
+     */
+    public int getEndOffset() {
+        parseIfNecessary();
+        return endOffset;
+    }
+
+    /**
+     * Gets the actual constant pool.
+     *
+     * @return {@code non-null;} the constant pool
+     */
+    public StdConstantPool getPool() {
+        parseIfNecessary();
+        return pool;
+    }
+
+    /**
+     * Runs {@link #parse} if it has not yet been run successfully.
+     */
+    private void parseIfNecessary() {
+        if (endOffset < 0) {
+            parse();
+        }
+    }
+
+    /**
+     * Does the actual parsing.
+     */
+    private void parse() {
+        determineOffsets();
+
+        if (observer != null) {
+            observer.parsed(bytes, 8, 2,
+                            "constant_pool_count: " + Hex.u2(offsets.length));
+            observer.parsed(bytes, 10, 0, "\nconstant_pool:");
+            observer.changeIndent(1);
+        }
+
+        /*
+         * Track the constant value's original string type. True if constants[i] was
+         * a CONSTANT_Utf8, false for any other type including CONSTANT_string.
+         */
+        BitSet wasUtf8 = new BitSet(offsets.length);
+
+        for (int i = 1; i < offsets.length; i++) {
+            int offset = offsets[i];
+            if ((offset != 0) && (pool.getOrNull(i) == null)) {
+                parse0(i, wasUtf8);
+            }
+        }
+
+        if (observer != null) {
+            for (int i = 1; i < offsets.length; i++) {
+                Constant cst = pool.getOrNull(i);
+                if (cst == null) {
+                    continue;
+                }
+                int offset = offsets[i];
+                int nextOffset = endOffset;
+                for (int j = i + 1; j < offsets.length; j++) {
+                    int off = offsets[j];
+                    if (off != 0) {
+                        nextOffset = off;
+                        break;
+                    }
+                }
+                String human = wasUtf8.get(i)
+                        ? Hex.u2(i) + ": utf8{\"" + cst.toHuman() + "\"}"
+                        : Hex.u2(i) + ": " + cst.toString();
+                observer.parsed(bytes, offset, nextOffset - offset, human);
+            }
+
+            observer.changeIndent(-1);
+            observer.parsed(bytes, endOffset, 0, "end constant_pool");
+        }
+    }
+
+    /**
+     * Populates {@link #offsets} and also completely parse utf8 constants.
+     */
+    private void determineOffsets() {
+        int at = 10; // offset from the start of the file to the first cst
+        int lastCategory;
+
+        for (int i = 1; i < offsets.length; i += lastCategory) {
+            offsets[i] = at;
+            int tag = bytes.getUnsignedByte(at);
+            switch (tag) {
+                case CONSTANT_Integer:
+                case CONSTANT_Float:
+                case CONSTANT_Fieldref:
+                case CONSTANT_Methodref:
+                case CONSTANT_InterfaceMethodref:
+                case CONSTANT_NameAndType: {
+                    lastCategory = 1;
+                    at += 5;
+                    break;
+                }
+                case CONSTANT_Long:
+                case CONSTANT_Double: {
+                    lastCategory = 2;
+                    at += 9;
+                    break;
+                }
+                case CONSTANT_Class:
+                case CONSTANT_String: {
+                    lastCategory = 1;
+                    at += 3;
+                    break;
+                }
+                case CONSTANT_Utf8: {
+                    lastCategory = 1;
+                    at += bytes.getUnsignedShort(at + 1) + 3;
+                    break;
+                }
+                default: {
+                    ParseException ex =
+                        new ParseException("unknown tag byte: " + Hex.u1(tag));
+                    ex.addContext("...while preparsing cst " + Hex.u2(i) +
+                                  " at offset " + Hex.u4(at));
+                    throw ex;
+                }
+            }
+        }
+
+        endOffset = at;
+    }
+
+    /**
+     * Parses the constant for the given index if it hasn't already been
+     * parsed, also storing it in the constant pool. This will also
+     * have the side effect of parsing any entries the indicated one
+     * depends on.
+     *
+     * @param idx which constant
+     * @return {@code non-null;} the parsed constant
+     */
+    private Constant parse0(int idx, BitSet wasUtf8) {
+        Constant cst = pool.getOrNull(idx);
+        if (cst != null) {
+            return cst;
+        }
+
+        int at = offsets[idx];
+
+        try {
+            int tag = bytes.getUnsignedByte(at);
+            switch (tag) {
+                case CONSTANT_Utf8: {
+                    cst = parseUtf8(at);
+                    wasUtf8.set(idx);
+                    break;
+                }
+                case CONSTANT_Integer: {
+                    int value = bytes.getInt(at + 1);
+                    cst = CstInteger.make(value);
+                    break;
+                }
+                case CONSTANT_Float: {
+                    int bits = bytes.getInt(at + 1);
+                    cst = CstFloat.make(bits);
+                    break;
+                }
+                case CONSTANT_Long: {
+                    long value = bytes.getLong(at + 1);
+                    cst = CstLong.make(value);
+                    break;
+                }
+                case CONSTANT_Double: {
+                    long bits = bytes.getLong(at + 1);
+                    cst = CstDouble.make(bits);
+                    break;
+                }
+                case CONSTANT_Class: {
+                    int nameIndex = bytes.getUnsignedShort(at + 1);
+                    CstString name = (CstString) parse0(nameIndex, wasUtf8);
+                    cst = new CstType(Type.internClassName(name.getString()));
+                    break;
+                }
+                case CONSTANT_String: {
+                    int stringIndex = bytes.getUnsignedShort(at + 1);
+                    cst = parse0(stringIndex, wasUtf8);
+                    break;
+                }
+                case CONSTANT_Fieldref: {
+                    int classIndex = bytes.getUnsignedShort(at + 1);
+                    CstType type = (CstType) parse0(classIndex, wasUtf8);
+                    int natIndex = bytes.getUnsignedShort(at + 3);
+                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
+                    cst = new CstFieldRef(type, nat);
+                    break;
+                }
+                case CONSTANT_Methodref: {
+                    int classIndex = bytes.getUnsignedShort(at + 1);
+                    CstType type = (CstType) parse0(classIndex, wasUtf8);
+                    int natIndex = bytes.getUnsignedShort(at + 3);
+                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
+                    cst = new CstMethodRef(type, nat);
+                    break;
+                }
+                case CONSTANT_InterfaceMethodref: {
+                    int classIndex = bytes.getUnsignedShort(at + 1);
+                    CstType type = (CstType) parse0(classIndex, wasUtf8);
+                    int natIndex = bytes.getUnsignedShort(at + 3);
+                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
+                    cst = new CstInterfaceMethodRef(type, nat);
+                    break;
+                }
+                case CONSTANT_NameAndType: {
+                    int nameIndex = bytes.getUnsignedShort(at + 1);
+                    CstString name = (CstString) parse0(nameIndex, wasUtf8);
+                    int descriptorIndex = bytes.getUnsignedShort(at + 3);
+                    CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8);
+                    cst = new CstNat(name, descriptor);
+                    break;
+                }
+            }
+        } catch (ParseException ex) {
+            ex.addContext("...while parsing cst " + Hex.u2(idx) +
+                          " at offset " + Hex.u4(at));
+            throw ex;
+        } catch (RuntimeException ex) {
+            ParseException pe = new ParseException(ex);
+            pe.addContext("...while parsing cst " + Hex.u2(idx) +
+                          " at offset " + Hex.u4(at));
+            throw pe;
+        }
+
+        pool.set(idx, cst);
+        return cst;
+    }
+
+    /**
+     * Parses a utf8 constant.
+     *
+     * @param at offset to the start of the constant (where the tag byte is)
+     * @return {@code non-null;} the parsed value
+     */
+    private CstString parseUtf8(int at) {
+        int length = bytes.getUnsignedShort(at + 1);
+
+        at += 3; // Skip to the data.
+
+        ByteArray ubytes = bytes.slice(at, at + length);
+
+        try {
+            return new CstString(ubytes);
+        } catch (IllegalArgumentException ex) {
+            // Translate the exception
+            throw new ParseException(ex);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/cst/ConstantTags.java b/dx/src/com/android/dx/cf/cst/ConstantTags.java
new file mode 100644
index 0000000..9febbdf
--- /dev/null
+++ b/dx/src/com/android/dx/cf/cst/ConstantTags.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.cst;
+
+/**
+ * Tags for constant pool constants.
+ */
+public interface ConstantTags {
+    /** tag for a {@code CONSTANT_Utf8_info} */
+    int CONSTANT_Utf8 = 1;
+
+    /** tag for a {@code CONSTANT_Integer_info} */
+    int CONSTANT_Integer = 3;
+
+    /** tag for a {@code CONSTANT_Float_info} */
+    int CONSTANT_Float = 4;
+
+    /** tag for a {@code CONSTANT_Long_info} */
+    int CONSTANT_Long = 5;
+
+    /** tag for a {@code CONSTANT_Double_info} */
+    int CONSTANT_Double = 6;
+
+    /** tag for a {@code CONSTANT_Class_info} */
+    int CONSTANT_Class = 7;
+
+    /** tag for a {@code CONSTANT_String_info} */
+    int CONSTANT_String = 8;
+
+    /** tag for a {@code CONSTANT_Fieldref_info} */
+    int CONSTANT_Fieldref = 9;
+
+    /** tag for a {@code CONSTANT_Methodref_info} */
+    int CONSTANT_Methodref = 10;
+
+    /** tag for a {@code CONSTANT_InterfaceMethodref_info} */
+    int CONSTANT_InterfaceMethodref = 11;
+
+    /** 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
new file mode 100644
index 0000000..fdbc990
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/AnnotationParser.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.rop.annotation.AnnotationVisibility;
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.annotation.NameValuePair;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstAnnotation;
+import com.android.dx.rop.cst.CstArray;
+import com.android.dx.rop.cst.CstBoolean;
+import com.android.dx.rop.cst.CstByte;
+import com.android.dx.rop.cst.CstChar;
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstEnumRef;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstShort;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+import java.io.IOException;
+
+/**
+ * Parser for annotations.
+ */
+public final class AnnotationParser {
+    /** {@code non-null;} class file being parsed */
+    private final DirectClassFile cf;
+
+    /** {@code non-null;} constant pool to use */
+    private final ConstantPool pool;
+
+    /** {@code non-null;} bytes of the attribute data */
+    private final ByteArray bytes;
+
+    /** {@code null-ok;} parse observer, if any */
+    private final ParseObserver observer;
+
+    /** {@code non-null;} input stream to parse from */
+    private final ByteArray.MyDataInputStream input;
+
+    /**
+     * {@code non-null;} cursor for use when informing the observer of what
+     * was parsed
+     */
+    private int parseCursor;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cf {@code non-null;} class file to parse from
+     * @param offset {@code >= 0;} offset into the class file data to parse at
+     * @param length {@code >= 0;} number of bytes left in the attribute data
+     * @param observer {@code null-ok;} parse observer to notify, if any
+     */
+    public AnnotationParser(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (cf == null) {
+            throw new NullPointerException("cf == null");
+        }
+
+        this.cf = cf;
+        this.pool = cf.getConstantPool();
+        this.observer = observer;
+        this.bytes = cf.getBytes().slice(offset, offset + length);
+        this.input = bytes.makeDataInputStream();
+        this.parseCursor = 0;
+    }
+
+    /**
+     * Parses an annotation value ({@code element_value}) attribute.
+     *
+     * @return {@code non-null;} the parsed constant value
+     */
+    public Constant parseValueAttribute() {
+        Constant result;
+
+        try {
+            result = parseValue();
+
+            if (input.available() != 0) {
+                throw new ParseException("extra data in attribute");
+            }
+        } catch (IOException ex) {
+            // ByteArray.MyDataInputStream should never throw.
+            throw new RuntimeException("shouldn't happen", ex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses a parameter annotation attribute.
+     *
+     * @param visibility {@code non-null;} visibility of the parsed annotations
+     * @return {@code non-null;} the parsed list of lists of annotations
+     */
+    public AnnotationsList parseParameterAttribute(
+            AnnotationVisibility visibility) {
+        AnnotationsList result;
+
+        try {
+            result = parseAnnotationsList(visibility);
+
+            if (input.available() != 0) {
+                throw new ParseException("extra data in attribute");
+            }
+        } catch (IOException ex) {
+            // ByteArray.MyDataInputStream should never throw.
+            throw new RuntimeException("shouldn't happen", ex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses an annotation attribute, per se.
+     *
+     * @param visibility {@code non-null;} visibility of the parsed annotations
+     * @return {@code non-null;} the list of annotations read from the attribute
+     * data
+     */
+    public Annotations parseAnnotationAttribute(
+            AnnotationVisibility visibility) {
+        Annotations result;
+
+        try {
+            result = parseAnnotations(visibility);
+
+            if (input.available() != 0) {
+                throw new ParseException("extra data in attribute");
+            }
+        } catch (IOException ex) {
+            // ByteArray.MyDataInputStream should never throw.
+            throw new RuntimeException("shouldn't happen", ex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses a list of annotation lists.
+     *
+     * @param visibility {@code non-null;} visibility of the parsed annotations
+     * @return {@code non-null;} the list of annotation lists read from the attribute
+     * data
+     */
+    private AnnotationsList parseAnnotationsList(
+            AnnotationVisibility visibility) throws IOException {
+        int count = input.readUnsignedByte();
+
+        if (observer != null) {
+            parsed(1, "num_parameters: " + Hex.u1(count));
+        }
+
+        AnnotationsList outerList = new AnnotationsList(count);
+
+        for (int i = 0; i < count; i++) {
+            if (observer != null) {
+                parsed(0, "parameter_annotations[" + i + "]:");
+                changeIndent(1);
+            }
+
+            Annotations annotations = parseAnnotations(visibility);
+            outerList.set(i, annotations);
+
+            if (observer != null) {
+                observer.changeIndent(-1);
+            }
+        }
+
+        outerList.setImmutable();
+        return outerList;
+    }
+
+    /**
+     * Parses an annotation list.
+     *
+     * @param visibility {@code non-null;} visibility of the parsed annotations
+     * @return {@code non-null;} the list of annotations read from the attribute
+     * data
+     */
+    private Annotations parseAnnotations(AnnotationVisibility visibility)
+            throws IOException {
+        int count = input.readUnsignedShort();
+
+        if (observer != null) {
+            parsed(2, "num_annotations: " + Hex.u2(count));
+        }
+
+        Annotations annotations = new Annotations();
+
+        for (int i = 0; i < count; i++) {
+            if (observer != null) {
+                parsed(0, "annotations[" + i + "]:");
+                changeIndent(1);
+            }
+
+            Annotation annotation = parseAnnotation(visibility);
+            annotations.add(annotation);
+
+            if (observer != null) {
+                observer.changeIndent(-1);
+            }
+        }
+
+        annotations.setImmutable();
+        return annotations;
+    }
+
+    /**
+     * Parses a single 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 {
+        requireLength(4);
+
+        int typeIndex = input.readUnsignedShort();
+        int numElements = input.readUnsignedShort();
+        CstString typeString = (CstString) pool.get(typeIndex);
+        CstType type = new CstType(Type.intern(typeString.getString()));
+
+        if (observer != null) {
+            parsed(2, "type: " + type.toHuman());
+            parsed(2, "num_elements: " + numElements);
+        }
+
+        Annotation annotation = new Annotation(type, visibility);
+
+        for (int i = 0; i < numElements; i++) {
+            if (observer != null) {
+                parsed(0, "elements[" + i + "]:");
+                changeIndent(1);
+            }
+
+            NameValuePair element = parseElement();
+            annotation.add(element);
+
+            if (observer != null) {
+                changeIndent(-1);
+            }
+        }
+
+        annotation.setImmutable();
+        return annotation;
+    }
+
+    /**
+     * Parses a {@link NameValuePair}.
+     *
+     * @return {@code non-null;} the parsed element
+     */
+    private NameValuePair parseElement() throws IOException {
+        requireLength(5);
+
+        int elementNameIndex = input.readUnsignedShort();
+        CstString elementName = (CstString) pool.get(elementNameIndex);
+
+        if (observer != null) {
+            parsed(2, "element_name: " + elementName.toHuman());
+            parsed(0, "value: ");
+            changeIndent(1);
+        }
+
+        Constant value = parseValue();
+
+        if (observer != null) {
+            changeIndent(-1);
+        }
+
+        return new NameValuePair(elementName, value);
+    }
+
+    /**
+     * Parses an annotation value.
+     *
+     * @return {@code non-null;} the parsed value
+     */
+    private Constant parseValue() throws IOException {
+        int tag = input.readUnsignedByte();
+
+        if (observer != null) {
+            CstString humanTag = new CstString(Character.toString((char) tag));
+            parsed(1, "tag: " + humanTag.toQuoted());
+        }
+
+        switch (tag) {
+            case 'B': {
+                CstInteger value = (CstInteger) parseConstant();
+                return CstByte.make(value.getValue());
+            }
+            case 'C': {
+                CstInteger value = (CstInteger) parseConstant();
+                int intValue = value.getValue();
+                return CstChar.make(value.getValue());
+            }
+            case 'D': {
+                CstDouble value = (CstDouble) parseConstant();
+                return value;
+            }
+            case 'F': {
+                CstFloat value = (CstFloat) parseConstant();
+                return value;
+            }
+            case 'I': {
+                CstInteger value = (CstInteger) parseConstant();
+                return value;
+            }
+            case 'J': {
+                CstLong value = (CstLong) parseConstant();
+                return value;
+            }
+            case 'S': {
+                CstInteger value = (CstInteger) parseConstant();
+                return CstShort.make(value.getValue());
+            }
+            case 'Z': {
+                CstInteger value = (CstInteger) parseConstant();
+                return CstBoolean.make(value.getValue());
+            }
+            case 'c': {
+                int classInfoIndex = input.readUnsignedShort();
+                CstString value = (CstString) pool.get(classInfoIndex);
+                Type type = Type.internReturnType(value.getString());
+
+                if (observer != null) {
+                    parsed(2, "class_info: " + type.toHuman());
+                }
+
+                return new CstType(type);
+            }
+            case 's': {
+                return parseConstant();
+            }
+            case 'e': {
+                requireLength(4);
+
+                int typeNameIndex = input.readUnsignedShort();
+                int constNameIndex = input.readUnsignedShort();
+                CstString typeName = (CstString) pool.get(typeNameIndex);
+                CstString constName = (CstString) pool.get(constNameIndex);
+
+                if (observer != null) {
+                    parsed(2, "type_name: " + typeName.toHuman());
+                    parsed(2, "const_name: " + constName.toHuman());
+                }
+
+                return new CstEnumRef(new CstNat(constName, typeName));
+            }
+            case '@': {
+                Annotation annotation =
+                    parseAnnotation(AnnotationVisibility.EMBEDDED);
+                return new CstAnnotation(annotation);
+            }
+            case '[': {
+                requireLength(2);
+
+                int numValues = input.readUnsignedShort();
+                CstArray.List list = new CstArray.List(numValues);
+
+                if (observer != null) {
+                    parsed(2, "num_values: " + numValues);
+                    changeIndent(1);
+                }
+
+                for (int i = 0; i < numValues; i++) {
+                    if (observer != null) {
+                        changeIndent(-1);
+                        parsed(0, "element_value[" + i + "]:");
+                        changeIndent(1);
+                    }
+                    list.set(i, parseValue());
+                }
+
+                if (observer != null) {
+                    changeIndent(-1);
+                }
+
+                list.setImmutable();
+                return new CstArray(list);
+            }
+            default: {
+                throw new ParseException("unknown annotation tag: " +
+                        Hex.u1(tag));
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #parseValue}, which parses a constant reference
+     * and returns the referred-to constant value.
+     *
+     * @return {@code non-null;} the parsed value
+     */
+    private Constant parseConstant() throws IOException {
+        int constValueIndex = input.readUnsignedShort();
+        Constant value = (Constant) pool.get(constValueIndex);
+
+        if (observer != null) {
+            String human = (value instanceof CstString)
+                ? ((CstString) value).toQuoted()
+                : value.toHuman();
+            parsed(2, "constant_value: " + human);
+        }
+
+        return value;
+    }
+
+    /**
+     * Helper which will throw an exception if the given number of bytes
+     * is not available to be read.
+     *
+     * @param requiredLength the number of required bytes
+     */
+    private void requireLength(int requiredLength) throws IOException {
+        if (input.available() < requiredLength) {
+            throw new ParseException("truncated annotation attribute");
+        }
+    }
+
+    /**
+     * Helper which indicates that some bytes were just parsed. This should
+     * only be used (for efficiency sake) if the parse is known to be
+     * observed.
+     *
+     * @param length {@code >= 0;} number of bytes parsed
+     * @param message {@code non-null;} associated message
+     */
+    private void parsed(int length, String message) {
+        observer.parsed(bytes, parseCursor, length, message);
+        parseCursor += length;
+    }
+
+    /**
+     * Convenience wrapper that simply calls through to
+     * {@code observer.changeIndent()}.
+     *
+     * @param indent the amount to change the indent by
+     */
+    private void changeIndent(int indent) {
+        observer.changeIndent(indent);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/AttributeFactory.java b/dx/src/com/android/dx/cf/direct/AttributeFactory.java
new file mode 100644
index 0000000..f7486eb
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/AttributeFactory.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.attrib.RawAttribute;
+import com.android.dx.cf.iface.Attribute;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+/**
+ * Factory capable of instantiating various {@link Attribute} subclasses
+ * depending on the context and name.
+ */
+public class AttributeFactory {
+    /** context for attributes on class files */
+    public static final int CTX_CLASS = 0;
+
+    /** context for attributes on fields */
+    public static final int CTX_FIELD = 1;
+
+    /** context for attributes on methods */
+    public static final int CTX_METHOD = 2;
+
+    /** context for attributes on code attributes */
+    public static final int CTX_CODE = 3;
+
+    /** number of contexts */
+    public static final int CTX_COUNT = 4;
+
+    /**
+     * Constructs an instance.
+     */
+    public AttributeFactory() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Parses and makes an attribute based on the bytes at the
+     * indicated position in the given array. This method figures out
+     * the name, and then does all the setup to call on to {@link #parse0},
+     * which does the actual construction.
+     *
+     * @param cf {@code non-null;} class file to parse from
+     * @param context context to parse in; one of the {@code CTX_*}
+     * constants
+     * @param offset offset into {@code dcf}'s {@code bytes}
+     * to start parsing at
+     * @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) {
+        if (cf == null) {
+            throw new NullPointerException("cf == null");
+        }
+
+        if ((context < 0) || (context >= CTX_COUNT)) {
+            throw new IllegalArgumentException("bad context");
+        }
+
+        CstString name = null;
+
+        try {
+            ByteArray bytes = cf.getBytes();
+            ConstantPool pool = cf.getConstantPool();
+            int nameIdx = bytes.getUnsignedShort(offset);
+            int length = bytes.getInt(offset + 2);
+
+            name = (CstString) pool.get(nameIdx);
+
+            if (observer != null) {
+                observer.parsed(bytes, offset, 2,
+                                "name: " + name.toHuman());
+                observer.parsed(bytes, offset + 2, 4,
+                                "length: " + Hex.u4(length));
+            }
+
+            return parse0(cf, context, name.getString(), offset + 6, length,
+                          observer);
+        } catch (ParseException ex) {
+            ex.addContext("...while parsing " +
+                    ((name != null) ? (name.toHuman() + " ") : "") +
+                    "attribute at offset " + Hex.u4(offset));
+            throw ex;
+        }
+    }
+
+    /**
+     * Parses attribute content. The base class implements this by constructing
+     * an instance of {@link RawAttribute}. Subclasses are expected to
+     * override this to do something better in most cases.
+     *
+     * @param cf {@code non-null;} class file to parse from
+     * @param context context to parse in; one of the {@code CTX_*}
+     * constants
+     * @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 {@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,
+                               ParseObserver observer) {
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+        Attribute result = new RawAttribute(name, bytes, offset, length, pool);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, length, "attribute data");
+        }
+
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/AttributeListParser.java b/dx/src/com/android/dx/cf/direct/AttributeListParser.java
new file mode 100644
index 0000000..2715e6a
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/AttributeListParser.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.iface.Attribute;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.cf.iface.StdAttributeList;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+/**
+ * Parser for lists of attributes.
+ */
+final /*package*/ class AttributeListParser {
+    /** {@code non-null;} the class file to parse from */
+    private final DirectClassFile cf;
+
+    /** attribute parsing context */
+    private final int context;
+
+    /** offset in the byte array of the classfile to the start of the list */
+    private final int offset;
+
+    /** {@code non-null;} attribute factory to use */
+    private final AttributeFactory attributeFactory;
+
+    /** {@code non-null;} list of parsed attributes */
+    private final StdAttributeList list;
+
+    /** {@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;
+
+    /** {@code null-ok;} parse observer, if any */
+    private ParseObserver observer;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cf {@code non-null;} class file to parse from
+     * @param context attribute parsing context (see {@link AttributeFactory})
+     * @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) {
+        if (cf == null) {
+            throw new NullPointerException("cf == null");
+        }
+
+        if (attributeFactory == null) {
+            throw new NullPointerException("attributeFactory == null");
+        }
+
+        int size = cf.getBytes().getUnsignedShort(offset);
+
+        this.cf = cf;
+        this.context = context;
+        this.offset = offset;
+        this.attributeFactory = attributeFactory;
+        this.list = new StdAttributeList(size);
+        this.endOffset = -1;
+    }
+
+    /**
+     * Sets the parse observer for this instance.
+     *
+     * @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[]}
+     * which it came from.
+     *
+     * @return {@code >= 0;} the end offset
+     */
+    public int getEndOffset() {
+        parseIfNecessary();
+        return endOffset;
+    }
+
+    /**
+     * Gets the parsed list.
+     *
+     * @return {@code non-null;} the list
+     */
+    public StdAttributeList getList() {
+        parseIfNecessary();
+        return list;
+    }
+
+    /**
+     * Runs {@link #parse} if it has not yet been run successfully.
+     */
+    private void parseIfNecessary() {
+        if (endOffset < 0) {
+            parse();
+        }
+    }
+
+    /**
+     * Does the actual parsing.
+     */
+    private void parse() {
+        int sz = list.size();
+        int at = offset + 2; // Skip the count.
+
+        ByteArray bytes = cf.getBytes();
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            "attributes_count: " + Hex.u2(sz));
+        }
+
+        for (int i = 0; i < sz; i++) {
+            try {
+                if (observer != null) {
+                    observer.parsed(bytes, at, 0,
+                                    "\nattributes[" + i + "]:\n");
+                    observer.changeIndent(1);
+                }
+
+                Attribute attrib =
+                    attributeFactory.parse(cf, context, at, observer);
+
+                at += attrib.byteLength();
+                list.set(i, attrib);
+
+                if (observer != null) {
+                    observer.changeIndent(-1);
+                    observer.parsed(bytes, at, 0,
+                                    "end attributes[" + i + "]\n");
+                }
+            } catch (ParseException ex) {
+                ex.addContext("...while parsing attributes[" + i + "]");
+                throw ex;
+            } catch (RuntimeException ex) {
+                ParseException pe = new ParseException(ex);
+                pe.addContext("...while parsing attributes[" + i + "]");
+                throw pe;
+            }
+        }
+
+        endOffset = at;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/ClassPathOpener.java b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
new file mode 100644
index 0000000..7621bf7
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Opens all the class files found in a class path element. Path elements
+ * can point to class files, {jar,zip,apk} files, or directories containing
+ * class files.
+ */
+public class ClassPathOpener {
+
+    /** {@code non-null;} pathname to start with */
+    private final String pathname;
+    /** {@code non-null;} callback interface */
+    private final Consumer consumer;
+    /**
+     * If true, sort such that classes appear before their inner
+     * classes and "package-info" occurs before all other classes in that
+     * package.
+     */
+    private final boolean sort;
+
+    /**
+     * Callback interface for {@code ClassOpener}.
+     */
+    public interface Consumer {
+
+        /**
+         * Provides the file name and byte array for a class path element.
+         *
+         * @param name {@code non-null;} filename of element. May not be a valid
+         * filesystem path.
+         *
+         * @param lastModified milliseconds since 1970-Jan-1 00:00:00 GMT
+         * @param bytes {@code non-null;} file data
+         * @return true on success. Result is or'd with all other results
+         * from {@code processFileBytes} and returned to the caller
+         * of {@code process()}.
+         */
+        boolean processFileBytes(String name, long lastModified, byte[] bytes);
+
+        /**
+         * Informs consumer that an exception occurred while processing
+         * this path element. Processing will continue if possible.
+         *
+         * @param ex {@code non-null;} exception
+         */
+        void onException(Exception ex);
+
+        /**
+         * Informs consumer that processing of an archive file has begun.
+         *
+         * @param file {@code non-null;} archive file being processed
+         */
+        void onProcessArchiveStart(File file);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @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 {@code non-null;} callback interface
+     */
+    public ClassPathOpener(String pathname, boolean sort, Consumer consumer) {
+        this.pathname = pathname;
+        this.sort = sort;
+        this.consumer = consumer;
+    }
+
+    /**
+     * Processes a path element.
+     *
+     * @return the OR of all return values
+     * from {@code Consumer.processFileBytes()}.
+     */
+    public boolean process() {
+        File file = new File(pathname);
+
+        return processOne(file, true);
+    }
+
+    /**
+     * Processes one file.
+     *
+     * @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
+     */
+    private boolean processOne(File file, boolean topLevel) {
+        try {
+            if (file.isDirectory()) {
+                return processDirectory(file, topLevel);
+            }
+
+            String path = file.getPath();
+
+            if (path.endsWith(".zip") ||
+                    path.endsWith(".jar") ||
+                    path.endsWith(".apk")) {
+                return processArchive(file);
+            }
+
+            byte[] bytes = FileUtils.readFile(file);
+            return consumer.processFileBytes(path, file.lastModified(), bytes);
+        } catch (Exception ex) {
+            consumer.onException(ex);
+            return false;
+        }
+    }
+
+    /**
+     * Sorts java class names such that outer classes preceed their inner
+     * classes and "package-info" preceeds all other classes in its package.
+     *
+     * @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
+        a = a.replace('$','0');
+        b = b.replace('$','0');
+
+        /*
+         * Assuming "package-info" only occurs at the end, ensures package-info
+         * sorts first.
+         */
+        a = a.replace("package-info", "");
+        b = b.replace("package-info", "");
+
+        return a.compareTo(b);
+    }
+
+    /**
+     * Processes a directory recursively.
+     *
+     * @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
+     */
+    private boolean processDirectory(File dir, boolean topLevel) {
+        if (topLevel) {
+            dir = new File(dir, ".");
+        }
+
+        File[] files = dir.listFiles();
+        int len = files.length;
+        boolean any = false;
+
+        if (sort) {
+            Arrays.sort(files, new Comparator<File>() {
+                public int compare(File a, File b) {
+                    return compareClassNames(a.getName(), b.getName());
+                }
+            });
+        }
+
+        for (int i = 0; i < len; i++) {
+            any |= processOne(files[i], false);
+        }
+
+        return any;
+    }
+
+    /**
+     * Processes the contents of an archive ({@code .zip},
+     * {@code .jar}, or {@code .apk}).
+     *
+     * @param file {@code non-null;} archive file to process
+     * @return whether any processing actually happened
+     * @throws IOException on i/o problem
+     */
+    private boolean processArchive(File file) throws IOException {
+        ZipFile zip = new ZipFile(file);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(40000);
+        byte[] buf = new byte[20000];
+        boolean any = false;
+
+        ArrayList<? extends java.util.zip.ZipEntry> entriesList
+                = Collections.list(zip.entries());
+
+        if (sort) {
+            Collections.sort(entriesList, new Comparator<ZipEntry>() {
+               public int compare (ZipEntry a, ZipEntry b) {
+                   return compareClassNames(a.getName(), b.getName());
+               }
+            });
+        }
+
+        consumer.onProcessArchiveStart(file);
+
+        for (ZipEntry one : entriesList) {
+            if (one.isDirectory()) {
+                continue;
+            }
+
+            String path = one.getName();
+            InputStream in = zip.getInputStream(one);
+
+            baos.reset();
+            for (;;) {
+                int amt = in.read(buf);
+                if (amt < 0) {
+                    break;
+                }
+
+                baos.write(buf, 0, amt);
+            }
+
+            in.close();
+
+            byte[] bytes = baos.toByteArray();
+            any |= consumer.processFileBytes(path, one.getTime(), bytes);
+        }
+
+        zip.close();
+        return any;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/CodeObserver.java b/dx/src/com/android/dx/cf/direct/CodeObserver.java
new file mode 100644
index 0000000..efcc80b
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/CodeObserver.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.code.ByteOps;
+import com.android.dx.cf.code.BytecodeArray;
+import com.android.dx.cf.code.SwitchList;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstKnownNull;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Bytecode visitor to use when "observing" bytecode getting parsed.
+ */
+public class CodeObserver implements BytecodeArray.Visitor {
+    /** {@code non-null;} actual array of bytecode */
+    private final ByteArray bytes;
+
+    /** {@code non-null;} observer to inform of parsing */
+    private final ParseObserver observer;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        if (observer == null) {
+            throw new NullPointerException("observer == null");
+        }
+
+        this.bytes = bytes;
+        this.observer = observer;
+    }
+
+    /** {@inheritDoc} */
+    public void visitInvalid(int opcode, int offset, int length) {
+        observer.parsed(bytes, offset, length, header(offset));
+    }
+
+    /** {@inheritDoc} */
+    public void visitNoArgs(int opcode, int offset, int length, Type type) {
+        observer.parsed(bytes, offset, length, header(offset));
+    }
+
+    /** {@inheritDoc} */
+    public void visitLocal(int opcode, int offset, int length,
+            int idx, Type type, int value) {
+        String idxStr = (length <= 3) ? Hex.u1(idx) : Hex.u2(idx);
+        boolean argComment = (length == 1);
+        String valueStr = "";
+
+        if (opcode == ByteOps.IINC) {
+            valueStr = ", #" +
+                ((length <= 3) ? Hex.s1(value) : Hex.s2(value));
+        }
+
+        String catStr = "";
+        if (type.isCategory2()) {
+            catStr = (argComment ? "," : " //") + " category-2";
+        }
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + (argComment ? " // " : " ") +
+                        idxStr + valueStr + catStr);
+    }
+
+    /** {@inheritDoc} */
+    public void visitConstant(int opcode, int offset, int length,
+            Constant cst, int value) {
+        if (cst instanceof CstKnownNull) {
+            // This is aconst_null.
+            visitNoArgs(opcode, offset, length, null);
+            return;
+        }
+
+        if (cst instanceof CstInteger) {
+            visitLiteralInt(opcode, offset, length, value);
+            return;
+        }
+
+        if (cst instanceof CstLong) {
+            visitLiteralLong(opcode, offset, length,
+                             ((CstLong) cst).getValue());
+            return;
+        }
+
+        if (cst instanceof CstFloat) {
+            visitLiteralFloat(opcode, offset, length,
+                              ((CstFloat) cst).getIntBits());
+            return;
+        }
+
+        if (cst instanceof CstDouble) {
+            visitLiteralDouble(opcode, offset, length,
+                             ((CstDouble) cst).getLongBits());
+            return;
+        }
+
+        String valueStr = "";
+        if (value != 0) {
+            valueStr = ", ";
+            if (opcode == ByteOps.MULTIANEWARRAY) {
+                valueStr += Hex.u1(value);
+            } else {
+                valueStr += Hex.u2(value);
+            }
+        }
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + " " + cst + valueStr);
+    }
+
+    /** {@inheritDoc} */
+    public void visitBranch(int opcode, int offset, int length,
+                            int target) {
+        String targetStr = (length <= 3) ? Hex.u2(target) : Hex.u4(target);
+        observer.parsed(bytes, offset, length,
+                        header(offset) + " " + targetStr);
+    }
+
+    /** {@inheritDoc} */
+    public void visitSwitch(int opcode, int offset, int length,
+            SwitchList cases, int padding) {
+        int sz = cases.size();
+        StringBuffer sb = new StringBuffer(sz * 20 + 100);
+
+        sb.append(header(offset));
+        if (padding != 0) {
+            sb.append(" // padding: " + Hex.u4(padding));
+        }
+        sb.append('\n');
+
+        for (int i = 0; i < sz; i++) {
+            sb.append("  ");
+            sb.append(Hex.s4(cases.getValue(i)));
+            sb.append(": ");
+            sb.append(Hex.u2(cases.getTarget(i)));
+            sb.append('\n');
+        }
+
+        sb.append("  default: ");
+        sb.append(Hex.u2(cases.getDefaultTarget()));
+
+        observer.parsed(bytes, offset, length, sb.toString());
+    }
+
+    /** {@inheritDoc} */
+    public void visitNewarray(int offset, int length, CstType cst,
+            ArrayList<Constant> intVals) {
+        String commentOrSpace = (length == 1) ? " // " : " ";
+        String typeName = cst.getClassType().getComponentType().toHuman();
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + commentOrSpace + typeName);
+    }
+
+    /** {@inheritDoc} */
+    public void setPreviousOffset(int offset) {
+        // Do nothing
+    }
+
+    /** {@inheritDoc} */
+    public int getPreviousOffset() {
+        return -1;
+    }
+
+    /**
+     * Helper to produce the first bit of output for each instruction.
+     *
+     * @param offset the offset to the start of the instruction
+     */
+    private String header(int offset) {
+        /*
+         * Note: This uses the original bytecode, not the
+         * possibly-transformed one.
+         */
+        int opcode = bytes.getUnsignedByte(offset);
+        String name = ByteOps.opName(opcode);
+
+        if (opcode == ByteOps.WIDE) {
+            opcode = bytes.getUnsignedByte(offset + 1);
+            name += " " + ByteOps.opName(opcode);
+        }
+
+        return Hex.u2(offset) + ": " + name;
+    }
+
+    /**
+     * Helper for {@link #visitConstant} where the constant is an
+     * {@code int}.
+     *
+     * @param opcode the opcode
+     * @param offset offset to the instruction
+     * @param length instruction length
+     * @param value constant value
+     */
+    private void visitLiteralInt(int opcode, int offset, int length,
+            int value) {
+        String commentOrSpace = (length == 1) ? " // " : " ";
+        String valueStr;
+
+        opcode = bytes.getUnsignedByte(offset); // Compare with orig op below.
+        if ((length == 1) || (opcode == ByteOps.BIPUSH)) {
+            valueStr = "#" + Hex.s1(value);
+        } else if (opcode == ByteOps.SIPUSH) {
+            valueStr = "#" + Hex.s2(value);
+        } else {
+            valueStr = "#" + Hex.s4(value);
+        }
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + commentOrSpace + valueStr);
+    }
+
+    /**
+     * Helper for {@link #visitConstant} where the constant is a
+     * {@code long}.
+     *
+     * @param opcode the opcode
+     * @param offset offset to the instruction
+     * @param length instruction length
+     * @param value constant value
+     */
+    private void visitLiteralLong(int opcode, int offset, int length,
+            long value) {
+        String commentOrLit = (length == 1) ? " // " : " #";
+        String valueStr;
+
+        if (length == 1) {
+            valueStr = Hex.s1((int) value);
+        } else {
+            valueStr = Hex.s8(value);
+        }
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + commentOrLit + valueStr);
+    }
+
+    /**
+     * Helper for {@link #visitConstant} where the constant is a
+     * {@code float}.
+     *
+     * @param opcode the opcode
+     * @param offset offset to the instruction
+     * @param length instruction length
+     * @param bits constant value, as float-bits
+     */
+    private void visitLiteralFloat(int opcode, int offset, int length,
+            int bits) {
+        String optArg = (length != 1) ? " #" + Hex.u4(bits) : "";
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + optArg + " // " +
+                        Float.intBitsToFloat(bits));
+    }
+
+    /**
+     * Helper for {@link #visitConstant} where the constant is a
+     * {@code double}.
+     *
+     * @param opcode the opcode
+     * @param offset offset to the instruction
+     * @param length instruction length
+     * @param bits constant value, as double-bits
+     */
+    private void visitLiteralDouble(int opcode, int offset, int length,
+            long bits) {
+        String optArg = (length != 1) ? " #" + Hex.u8(bits) : "";
+
+        observer.parsed(bytes, offset, length,
+                        header(offset) + optArg + " // " +
+                        Double.longBitsToDouble(bits));
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/DirectClassFile.java b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
new file mode 100644
index 0000000..4f1c85d
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.attrib.AttSourceFile;
+import com.android.dx.cf.cst.ConstantPoolParser;
+import com.android.dx.cf.iface.Attribute;
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.ClassFile;
+import com.android.dx.cf.iface.FieldList;
+import com.android.dx.cf.iface.MethodList;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.cf.iface.StdAttributeList;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.StdConstantPool;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+/**
+ * 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} file major version
+     *
+     * See http://en.wikipedia.org/wiki/Java_class_file for an up-to-date
+     * list of version numbers. Currently known (taken from that table) are:
+     *
+     *     J2SE 6.0 = 50 (0x32 hex),
+     *     J2SE 5.0 = 49 (0x31 hex),
+     *     JDK 1.4 = 48 (0x30 hex),
+     *     JDK 1.3 = 47 (0x2F hex),
+     *     JDK 1.2 = 46 (0x2E hex),
+     *     JDK 1.1 = 45 (0x2D hex).
+     *
+     * Valid ranges are typically of the form
+     * "A.0 through B.C inclusive" where A <= B and C >= 0,
+     * which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION.
+     */
+    private static final int CLASS_FILE_MIN_MAJOR_VERSION = 45;
+
+    /**
+     * maximum {@code .class} file major version
+     *
+     * Note: if you change this, please change "java.class.version" in System.java.
+     */
+    private static final int CLASS_FILE_MAX_MAJOR_VERSION = 50;
+
+    /** maximum {@code .class} file minor version */
+    private static final int CLASS_FILE_MAX_MINOR_VERSION = 0;
+
+    /**
+     * {@code non-null;} the file path for the class, excluding any base directory
+     * specification
+     */
+    private final String filePath;
+
+    /** {@code non-null;} the bytes of the file */
+    private final ByteArray bytes;
+
+    /**
+     * whether to be strict about parsing; if
+     * {@code false}, this avoids doing checks that only exist
+     * for purposes of verification (such as magic number matching and
+     * path-package consistency checking)
+     */
+    private final boolean strictParse;
+
+    /**
+     * {@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}; will be {@code -1}
+     * before the file is successfully parsed
+     */
+    private int accessFlags;
+
+    /**
+     * {@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;
+
+    /**
+     * {@code null-ok;} the class file field {@code super_class}, interpreted
+     * as a type constant if non-zero
+     */
+    private CstType superClass;
+
+    /**
+     * {@code null-ok;} the class file field {@code interfaces}; only
+     * ever {@code null} before the file is successfully
+     * parsed
+     */
+    private TypeList interfaces;
+
+    /**
+     * {@code null-ok;} the class file field {@code fields}; only ever
+     * {@code null} before the file is successfully parsed
+     */
+    private FieldList fields;
+
+    /**
+     * {@code null-ok;} the class file field {@code methods}; only ever
+     * {@code null} before the file is successfully parsed
+     */
+    private MethodList methods;
+
+    /**
+     * {@code null-ok;} the class file field {@code attributes}; only
+     * ever {@code null} before the file is successfully
+     * parsed
+     */
+    private StdAttributeList attributes;
+
+    /** {@code null-ok;} attribute factory, if any */
+    private AttributeFactory attributeFactory;
+
+    /** {@code null-ok;} parse observer, if any */
+    private ParseObserver observer;
+
+    /**
+     * Returns the string form of an object or {@code "(none)"}
+     * (rather than {@code "null"}) for {@code null}.
+     *
+     * @param obj {@code null-ok;} the object to stringify
+     * @return {@code non-null;} the appropriate string form
+     */
+    public static String stringOrNone(Object obj) {
+        if (obj == null) {
+            return "(none)";
+        }
+
+        return obj.toString();
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     * @param filePath {@code non-null;} the file path for the class,
+     * excluding any base directory specification
+     * @param strictParse whether to be strict about parsing; if
+     * {@code false}, this avoids doing checks that only exist
+     * for purposes of verification (such as magic number matching and
+     * path-package consistency checking)
+     */
+    public DirectClassFile(ByteArray bytes, String filePath,
+                           boolean strictParse) {
+        if (bytes == null) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        if (filePath == null) {
+            throw new NullPointerException("filePath == null");
+        }
+
+        this.filePath = filePath;
+        this.bytes = bytes;
+        this.strictParse = strictParse;
+        this.accessFlags = -1;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     * @param filePath {@code non-null;} the file path for the class,
+     * excluding any base directory specification
+     * @param strictParse whether to be strict about parsing; if
+     * {@code false}, this avoids doing checks that only exist
+     * for purposes of verification (such as magic number matching and
+     * path-package consistency checking)
+     */
+    public DirectClassFile(byte[] bytes, String filePath,
+                           boolean strictParse) {
+        this(new ByteArray(bytes), filePath, strictParse);
+    }
+
+    /**
+     * Sets the parse observer for this instance.
+     *
+     * @param observer {@code null-ok;} the observer
+     */
+    public void setObserver(ParseObserver observer) {
+        this.observer = observer;
+    }
+
+    /**
+     * Sets the attribute factory to use.
+     *
+     * @param attributeFactory {@code non-null;} the attribute factory
+     */
+    public void setAttributeFactory(AttributeFactory attributeFactory) {
+        if (attributeFactory == null) {
+            throw new NullPointerException("attributeFactory == null");
+        }
+
+        this.attributeFactory = attributeFactory;
+    }
+
+    /**
+     * Gets the {@link ByteArray} that this instance's data comes from.
+     *
+     * @return {@code non-null;} the bytes
+     */
+    public ByteArray getBytes() {
+        return bytes;
+    }
+
+    /** {@inheritDoc} */
+    public int getMagic() {
+        parseToInterfacesIfNecessary();
+        return getMagic0();
+    }
+
+    /** {@inheritDoc} */
+    public int getMinorVersion() {
+        parseToInterfacesIfNecessary();
+        return getMinorVersion0();
+    }
+
+    /** {@inheritDoc} */
+    public int getMajorVersion() {
+        parseToInterfacesIfNecessary();
+        return getMajorVersion0();
+    }
+
+    /** {@inheritDoc} */
+    public int getAccessFlags() {
+        parseToInterfacesIfNecessary();
+        return accessFlags;
+    }
+
+    /** {@inheritDoc} */
+    public CstType getThisClass() {
+        parseToInterfacesIfNecessary();
+        return thisClass;
+    }
+
+    /** {@inheritDoc} */
+    public CstType getSuperclass() {
+        parseToInterfacesIfNecessary();
+        return superClass;
+    }
+
+    /** {@inheritDoc} */
+    public ConstantPool getConstantPool() {
+        parseToInterfacesIfNecessary();
+        return pool;
+    }
+
+    /** {@inheritDoc} */
+    public TypeList getInterfaces() {
+        parseToInterfacesIfNecessary();
+        return interfaces;
+    }
+
+    /** {@inheritDoc} */
+    public FieldList getFields() {
+        parseToEndIfNecessary();
+        return fields;
+    }
+
+    /** {@inheritDoc} */
+    public MethodList getMethods() {
+        parseToEndIfNecessary();
+        return methods;
+    }
+
+    /** {@inheritDoc} */
+    public AttributeList getAttributes() {
+        parseToEndIfNecessary();
+        return attributes;
+    }
+
+    /** {@inheritDoc} */
+    public CstString getSourceFile() {
+        AttributeList attribs = getAttributes();
+        Attribute attSf = attribs.findFirst(AttSourceFile.ATTRIBUTE_NAME);
+
+        if (attSf instanceof AttSourceFile) {
+            return ((AttSourceFile) attSf).getSourceFile();
+        }
+
+        return null;
+    }
+
+    /**
+     * Constructs and returns an instance of {@link TypeList} whose
+     * data comes from the bytes of this instance, interpreted as a
+     * 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}.
+     *
+     * @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 {@code non-null;} an appropriately-constructed class list
+     */
+    public TypeList makeTypeList(int offset, int size) {
+        if (size == 0) {
+            return StdTypeList.EMPTY;
+        }
+
+        if (pool == null) {
+            throw new IllegalStateException("pool not yet initialized");
+        }
+
+        return new DcfTypeList(bytes, offset, size, pool, observer);
+    }
+
+    /**
+     * Gets the class file field {@code magic}, but without doing any
+     * checks or parsing first.
+     *
+     * @return the magic value
+     */
+    public int getMagic0() {
+        return bytes.getInt(0);
+    }
+
+    /**
+     * Gets the class file field {@code minor_version}, but
+     * without doing any checks or parsing first.
+     *
+     * @return the minor version
+     */
+    public int getMinorVersion0() {
+        return bytes.getUnsignedShort(4);
+    }
+
+    /**
+     * Gets the class file field {@code major_version}, but
+     * without doing any checks or parsing first.
+     *
+     * @return the major version
+     */
+    public int getMajorVersion0() {
+        return bytes.getUnsignedShort(6);
+    }
+
+    /**
+     * Runs {@link #parse} if it has not yet been run to cover up to
+     * the interfaces list.
+     */
+    private void parseToInterfacesIfNecessary() {
+        if (accessFlags == -1) {
+            parse();
+        }
+    }
+
+    /**
+     * Runs {@link #parse} if it has not yet been run successfully.
+     */
+    private void parseToEndIfNecessary() {
+        if (attributes == null) {
+            parse();
+        }
+    }
+
+    /**
+     * Does the parsing, handing exceptions.
+     */
+    private void parse() {
+        try {
+            parse0();
+        } catch (ParseException ex) {
+            ex.addContext("...while parsing " + filePath);
+            throw ex;
+        } catch (RuntimeException ex) {
+            ParseException pe = new ParseException(ex);
+            pe.addContext("...while parsing " + filePath);
+            throw pe;
+        }
+    }
+
+    /**
+     * Sees if the .class file header magic/version are within
+     * range.
+     *
+     * @param magic the value of a classfile "magic" field
+     * @param minorVersion the value of a classfile "minor_version" field
+     * @param majorVersion the value of a classfile "major_version" field
+     * @return true iff the parameters are valid and within range
+     */
+    private boolean isGoodVersion(int magic, int minorVersion,
+            int majorVersion) {
+        /* Valid version ranges are typically of the form
+         * "A.0 through B.C inclusive" where A <= B and C >= 0,
+         * which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION.
+         */
+        if (magic == CLASS_FILE_MAGIC && minorVersion >= 0) {
+            /* Check against max first to handle the case where
+             * MIN_MAJOR == MAX_MAJOR.
+             */
+            if (majorVersion == CLASS_FILE_MAX_MAJOR_VERSION) {
+                if (minorVersion <= CLASS_FILE_MAX_MINOR_VERSION) {
+                    return true;
+                }
+            } else if (majorVersion < CLASS_FILE_MAX_MAJOR_VERSION &&
+                       majorVersion >= CLASS_FILE_MIN_MAJOR_VERSION) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Does the actual parsing.
+     */
+    private void parse0() {
+        if (bytes.size() < 10) {
+            throw new ParseException("severely truncated class file");
+        }
+
+        if (observer != null) {
+            observer.parsed(bytes, 0, 0, "begin classfile");
+            observer.parsed(bytes, 0, 4, "magic: " + Hex.u4(getMagic0()));
+            observer.parsed(bytes, 4, 2,
+                            "minor_version: " + Hex.u2(getMinorVersion0()));
+            observer.parsed(bytes, 6, 2,
+                            "major_version: " + Hex.u2(getMajorVersion0()));
+        }
+
+        if (strictParse) {
+            /* Make sure that this looks like a valid class file with a
+             * version that we can handle.
+             */
+            if (!isGoodVersion(getMagic0(), getMinorVersion0(),
+                               getMajorVersion0())) {
+                throw new ParseException("bad class file magic (" +
+                                         Hex.u4(getMagic0()) +
+                                         ") or version (" +
+                                         Hex.u2(getMajorVersion0()) + "." +
+                                         Hex.u2(getMinorVersion0()) + ")");
+            }
+        }
+
+        ConstantPoolParser cpParser = new ConstantPoolParser(bytes);
+        cpParser.setObserver(observer);
+        pool = cpParser.getPool();
+        pool.setImmutable();
+
+        int at = cpParser.getEndOffset();
+        int accessFlags = bytes.getUnsignedShort(at); // u2 access_flags;
+        int cpi = bytes.getUnsignedShort(at + 2); // u2 this_class;
+        thisClass = (CstType) pool.get(cpi);
+        cpi = bytes.getUnsignedShort(at + 4); // u2 super_class;
+        superClass = (CstType) pool.get0Ok(cpi);
+        int count = bytes.getUnsignedShort(at + 6); // u2 interfaces_count
+
+        if (observer != null) {
+            observer.parsed(bytes, at, 2,
+                            "access_flags: " +
+                            AccessFlags.classString(accessFlags));
+            observer.parsed(bytes, at + 2, 2, "this_class: " + thisClass);
+            observer.parsed(bytes, at + 4, 2, "super_class: " +
+                            stringOrNone(superClass));
+            observer.parsed(bytes, at + 6, 2,
+                            "interfaces_count: " + Hex.u2(count));
+            if (count != 0) {
+                observer.parsed(bytes, at + 8, 0, "interfaces:");
+            }
+        }
+
+        at += 8;
+        interfaces = makeTypeList(at, count);
+        at += count * 2;
+
+        if (strictParse) {
+            /*
+             * Make sure that the file/jar path matches the declared
+             * package/class name.
+             */
+            String thisClassName = thisClass.getClassType().getClassName();
+            if (!(filePath.endsWith(".class") &&
+                  filePath.startsWith(thisClassName) &&
+                  (filePath.length() == (thisClassName.length() + 6)))) {
+                throw new ParseException("class name (" + thisClassName +
+                                         ") does not match path (" +
+                                         filePath + ")");
+            }
+        }
+
+        /*
+         * Only set the instance variable accessFlags here, since
+         * that's what signals a successful parse of the first part of
+         * the file (through the interfaces list).
+         */
+        this.accessFlags = accessFlags;
+
+        FieldListParser flParser =
+            new FieldListParser(this, thisClass, at, attributeFactory);
+        flParser.setObserver(observer);
+        fields = flParser.getList();
+        at = flParser.getEndOffset();
+
+        MethodListParser mlParser =
+            new MethodListParser(this, thisClass, at, attributeFactory);
+        mlParser.setObserver(observer);
+        methods = mlParser.getList();
+        at = mlParser.getEndOffset();
+
+        AttributeListParser alParser =
+            new AttributeListParser(this, AttributeFactory.CTX_CLASS, at,
+                                    attributeFactory);
+        alParser.setObserver(observer);
+        attributes = alParser.getList();
+        attributes.setImmutable();
+        at = alParser.getEndOffset();
+
+        if (at != bytes.size()) {
+            throw new ParseException("extra bytes at end of class file, " +
+                                     "at offset " + Hex.u4(at));
+        }
+
+        if (observer != null) {
+            observer.parsed(bytes, at, 0, "end classfile");
+        }
+    }
+
+    /**
+     * Implementation of {@link TypeList} whose data comes directly
+     * from the bytes of an instance of this (outer) class,
+     * interpreted as a list of constant pool indices for classes
+     * 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}.
+     */
+    private static class DcfTypeList implements TypeList {
+        /** {@code non-null;} array containing the data */
+        private final ByteArray bytes;
+
+        /** number of elements in the list (not number of bytes) */
+        private final int size;
+
+        /** {@code non-null;} the constant pool */
+        private final StdConstantPool pool;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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 {@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) {
+            if (size < 0) {
+                throw new IllegalArgumentException("size < 0");
+            }
+
+            bytes = bytes.slice(offset, offset + size * 2);
+            this.bytes = bytes;
+            this.size = size;
+            this.pool = pool;
+
+            for (int i = 0; i < size; i++) {
+                offset = i * 2;
+                int idx = bytes.getUnsignedShort(offset);
+                CstType type;
+                try {
+                    type = (CstType) pool.get(idx);
+                } catch (ClassCastException ex) {
+                    // Translate the exception.
+                    throw new RuntimeException("bogus class cpi", ex);
+                }
+                if (observer != null) {
+                    observer.parsed(bytes, offset, 2, "  " + type);
+                }
+            }
+        }
+
+        /** {@inheritDoc} */
+        public boolean isMutable() {
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        public int size() {
+            return size;
+        }
+
+        /** {@inheritDoc} */
+        public int getWordCount() {
+            // It is the same as size because all elements are classes.
+            return size;
+        }
+
+        /** {@inheritDoc} */
+        public Type getType(int n) {
+            int idx = bytes.getUnsignedShort(n * 2);
+            return ((CstType) pool.get(idx)).getClassType();
+        }
+
+        /** {@inheritDoc} */
+        public TypeList withAddedType(Type type) {
+            throw new UnsupportedOperationException("unsupported");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/FieldListParser.java b/dx/src/com/android/dx/cf/direct/FieldListParser.java
new file mode 100644
index 0000000..2d8280d
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/FieldListParser.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.StdField;
+import com.android.dx.cf.iface.StdFieldList;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+
+/**
+ * Parser for lists of fields in a class file.
+ */
+final /*package*/ class FieldListParser extends MemberListParser {
+    /** {@code non-null;} list in progress */
+    private final StdFieldList fields;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cf {@code non-null;} the class file to parse from
+     * @param definer {@code non-null;} class being defined
+     * @param offset offset in {@code bytes} to the start of the list
+     * @param attributeFactory {@code non-null;} attribute factory to use
+     */
+    public FieldListParser(DirectClassFile cf, CstType definer, int offset,
+            AttributeFactory attributeFactory) {
+        super(cf, definer, offset, attributeFactory);
+        fields = new StdFieldList(getCount());
+    }
+
+    /**
+     * Gets the parsed list.
+     *
+     * @return {@code non-null;} the parsed list
+     */
+    public StdFieldList getList() {
+        parseIfNecessary();
+        return fields;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String humanName() {
+        return "field";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String humanAccessFlags(int accessFlags) {
+        return AccessFlags.fieldString(accessFlags);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getAttributeContext() {
+        return AttributeFactory.CTX_FIELD;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Member set(int n, int accessFlags, CstNat nat,
+                         AttributeList attributes) {
+        StdField field =
+            new StdField(getDefiner(), accessFlags, nat, attributes);
+
+        fields.set(n, field);
+        return field;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/MemberListParser.java b/dx/src/com/android/dx/cf/direct/MemberListParser.java
new file mode 100644
index 0000000..605bab8
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/MemberListParser.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.cf.iface.StdAttributeList;
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+/**
+ * Parser for lists of class file members (that is, fields and methods).
+ */
+abstract /*package*/ class MemberListParser {
+    /** {@code non-null;} the class file to parse from */
+    private final DirectClassFile cf;
+
+    /** {@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;
+
+    /** {@code non-null;} attribute factory to use */
+    private final AttributeFactory attributeFactory;
+
+    /** {@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;
+
+    /** {@code null-ok;} parse observer, if any */
+    private ParseObserver observer;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cf {@code non-null;} the class file to parse from
+     * @param definer {@code non-null;} class being defined
+     * @param offset offset in {@code bytes} to the start of the list
+     * @param attributeFactory {@code non-null;} attribute factory to use
+     */
+    public MemberListParser(DirectClassFile cf, CstType definer,
+            int offset, AttributeFactory attributeFactory) {
+        if (cf == null) {
+            throw new NullPointerException("cf == null");
+        }
+
+        if (offset < 0) {
+            throw new IllegalArgumentException("offset < 0");
+        }
+
+        if (attributeFactory == null) {
+            throw new NullPointerException("attributeFactory == null");
+        }
+
+        this.cf = cf;
+        this.definer = definer;
+        this.offset = offset;
+        this.attributeFactory = attributeFactory;
+        this.endOffset = -1;
+    }
+
+    /**
+     * Gets the end offset of this constant pool in the {@code byte[]}
+     * which it came from.
+     *
+     * @return {@code >= 0;} the end offset
+     */
+    public int getEndOffset() {
+        parseIfNecessary();
+        return endOffset;
+    }
+
+    /**
+     * Sets the parse observer for this instance.
+     *
+     * @param observer {@code null-ok;} the observer
+     */
+    public final void setObserver(ParseObserver observer) {
+        this.observer = observer;
+    }
+
+    /**
+     * Runs {@link #parse} if it has not yet been run successfully.
+     */
+    protected final void parseIfNecessary() {
+        if (endOffset < 0) {
+            parse();
+        }
+    }
+
+    /**
+     * Gets the count of elements in the list.
+     *
+     * @return the count
+     */
+    protected final int getCount() {
+        ByteArray bytes = cf.getBytes();
+        return bytes.getUnsignedShort(offset);
+    }
+
+    /**
+     * Gets the class file being defined.
+     *
+     * @return {@code non-null;} the class
+     */
+    protected final CstType getDefiner() {
+        return definer;
+    }
+
+    /**
+     * Gets the human-oriented name for what this instance is parsing.
+     * Subclasses must override this method.
+     *
+     * @return {@code non-null;} the human oriented name
+     */
+    protected abstract String humanName();
+
+    /**
+     * Gets the human-oriented string for the given access flags.
+     * Subclasses must override this method.
+     *
+     * @param accessFlags the flags
+     * @return {@code non-null;} the string form
+     */
+    protected abstract String humanAccessFlags(int accessFlags);
+
+    /**
+     * Gets the {@code CTX_*} constant to use when parsing attributes.
+     * Subclasses must override this method.
+     *
+     * @return {@code non-null;} the human oriented name
+     */
+    protected abstract int getAttributeContext();
+
+    /**
+     * Sets an element in the list. Subclasses must override this method.
+     *
+     * @param n which element
+     * @param accessFlags the {@code access_flags}
+     * @param nat the interpreted name and type (based on the two
+     * {@code *_index} fields)
+     * @param attributes list of parsed attributes
+     * @return {@code non-null;} the constructed member
+     */
+    protected abstract Member set(int n, int accessFlags, CstNat nat,
+            AttributeList attributes);
+
+    /**
+     * Does the actual parsing.
+     */
+    private void parse() {
+        int attributeContext = getAttributeContext();
+        int count = getCount();
+        int at = offset + 2; // Skip the count.
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            humanName() + "s_count: " + Hex.u2(count));
+        }
+
+        for (int i = 0; i < count; i++) {
+            try {
+                int accessFlags = bytes.getUnsignedShort(at);
+                int nameIdx = bytes.getUnsignedShort(at + 2);
+                int descIdx = bytes.getUnsignedShort(at + 4);
+                CstString name = (CstString) pool.get(nameIdx);
+                CstString desc = (CstString) pool.get(descIdx);
+
+                if (observer != null) {
+                    observer.startParsingMember(bytes, at, name.getString(),
+                                                desc.getString());
+                    observer.parsed(bytes, at, 0, "\n" + humanName() +
+                                    "s[" + i + "]:\n");
+                    observer.changeIndent(1);
+                    observer.parsed(bytes, at, 2,
+                                    "access_flags: " +
+                                    humanAccessFlags(accessFlags));
+                    observer.parsed(bytes, at + 2, 2,
+                                    "name: " + name.toHuman());
+                    observer.parsed(bytes, at + 4, 2,
+                                    "descriptor: " + desc.toHuman());
+                }
+
+                at += 6;
+                AttributeListParser parser =
+                    new AttributeListParser(cf, attributeContext, at,
+                                            attributeFactory);
+                parser.setObserver(observer);
+                at = parser.getEndOffset();
+                StdAttributeList attributes = parser.getList();
+                attributes.setImmutable();
+                CstNat nat = new CstNat(name, desc);
+                Member member = set(i, accessFlags, nat, attributes);
+
+                if (observer != null) {
+                    observer.changeIndent(-1);
+                    observer.parsed(bytes, at, 0, "end " + humanName() +
+                                    "s[" + i + "]\n");
+                    observer.endParsingMember(bytes, at, name.getString(),
+                                              desc.getString(), member);
+                }
+            } catch (ParseException ex) {
+                ex.addContext("...while parsing " + humanName() + "s[" + i +
+                              "]");
+                throw ex;
+            } catch (RuntimeException ex) {
+                ParseException pe = new ParseException(ex);
+                pe.addContext("...while parsing " + humanName() + "s[" + i +
+                              "]");
+                throw pe;
+            }
+        }
+
+        endOffset = at;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/MethodListParser.java b/dx/src/com/android/dx/cf/direct/MethodListParser.java
new file mode 100644
index 0000000..9e3494e
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/MethodListParser.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.StdMethod;
+import com.android.dx.cf.iface.StdMethodList;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+
+/**
+ * Parser for lists of methods in a class file.
+ */
+final /*package*/ class MethodListParser extends MemberListParser {
+    /** {@code non-null;} list in progress */
+    final private StdMethodList methods;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cf {@code non-null;} the class file to parse from
+     * @param definer {@code non-null;} class being defined
+     * @param offset offset in {@code bytes} to the start of the list
+     * @param attributeFactory {@code non-null;} attribute factory to use
+     */
+    public MethodListParser(DirectClassFile cf, CstType definer,
+            int offset, AttributeFactory attributeFactory) {
+        super(cf, definer, offset, attributeFactory);
+        methods = new StdMethodList(getCount());
+    }
+
+    /**
+     * Gets the parsed list.
+     *
+     * @return {@code non-null;} the parsed list
+     */
+    public StdMethodList getList() {
+        parseIfNecessary();
+        return methods;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String humanName() {
+        return "method";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String humanAccessFlags(int accessFlags) {
+        return AccessFlags.methodString(accessFlags);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getAttributeContext() {
+        return AttributeFactory.CTX_METHOD;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Member set(int n, int accessFlags, CstNat nat,
+                         AttributeList attributes) {
+        StdMethod meth =
+            new StdMethod(getDefiner(), accessFlags, nat, attributes);
+
+        methods.set(n, meth);
+        return meth;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
new file mode 100644
index 0000000..ae04a13
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
@@ -0,0 +1,763 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.direct;
+
+import com.android.dx.cf.attrib.AttAnnotationDefault;
+import com.android.dx.cf.attrib.AttCode;
+import com.android.dx.cf.attrib.AttConstantValue;
+import com.android.dx.cf.attrib.AttDeprecated;
+import com.android.dx.cf.attrib.AttEnclosingMethod;
+import com.android.dx.cf.attrib.AttExceptions;
+import com.android.dx.cf.attrib.AttInnerClasses;
+import com.android.dx.cf.attrib.AttLineNumberTable;
+import com.android.dx.cf.attrib.AttLocalVariableTable;
+import com.android.dx.cf.attrib.AttLocalVariableTypeTable;
+import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations;
+import com.android.dx.cf.attrib.AttSignature;
+import com.android.dx.cf.attrib.AttSourceFile;
+import com.android.dx.cf.attrib.AttSynthetic;
+import com.android.dx.cf.attrib.InnerClassList;
+import com.android.dx.cf.code.ByteCatchList;
+import com.android.dx.cf.code.BytecodeArray;
+import com.android.dx.cf.code.LineNumberList;
+import com.android.dx.cf.code.LocalVariableList;
+import com.android.dx.cf.iface.Attribute;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.cf.iface.StdAttributeList;
+import com.android.dx.rop.annotation.AnnotationVisibility;
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.TypedConstant;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+import java.io.IOException;
+
+/**
+ * Standard subclass of {@link AttributeFactory}, which knows how to parse
+ * all the standard attribute types.
+ */
+public class StdAttributeFactory
+    extends AttributeFactory {
+    /** {@code non-null;} shared instance of this class */
+    public static final StdAttributeFactory THE_ONE =
+        new StdAttributeFactory();
+
+    /**
+     * Constructs an instance.
+     */
+    public StdAttributeFactory() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected Attribute parse0(DirectClassFile cf, int context, String name,
+            int offset, int length, ParseObserver observer) {
+        switch (context) {
+            case CTX_CLASS: {
+                if (name == AttDeprecated.ATTRIBUTE_NAME) {
+                    return deprecated(cf, offset, length, observer);
+                }
+                if (name == AttEnclosingMethod.ATTRIBUTE_NAME) {
+                    return enclosingMethod(cf, offset, length, observer);
+                }
+                if (name == AttInnerClasses.ATTRIBUTE_NAME) {
+                    return innerClasses(cf, offset, length, observer);
+                }
+                if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) {
+                    return runtimeInvisibleAnnotations(cf, offset, length,
+                            observer);
+                }
+                if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) {
+                    return runtimeVisibleAnnotations(cf, offset, length,
+                            observer);
+                }
+                if (name == AttSynthetic.ATTRIBUTE_NAME) {
+                    return synthetic(cf, offset, length, observer);
+                }
+                if (name == AttSignature.ATTRIBUTE_NAME) {
+                    return signature(cf, offset, length, observer);
+                }
+                if (name == AttSourceFile.ATTRIBUTE_NAME) {
+                    return sourceFile(cf, offset, length, observer);
+                }
+                break;
+            }
+            case CTX_FIELD: {
+                if (name == AttConstantValue.ATTRIBUTE_NAME) {
+                    return constantValue(cf, offset, length, observer);
+                }
+                if (name == AttDeprecated.ATTRIBUTE_NAME) {
+                    return deprecated(cf, offset, length, observer);
+                }
+                if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) {
+                    return runtimeInvisibleAnnotations(cf, offset, length,
+                            observer);
+                }
+                if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) {
+                    return runtimeVisibleAnnotations(cf, offset, length,
+                            observer);
+                }
+                if (name == AttSignature.ATTRIBUTE_NAME) {
+                    return signature(cf, offset, length, observer);
+                }
+                if (name == AttSynthetic.ATTRIBUTE_NAME) {
+                    return synthetic(cf, offset, length, observer);
+                }
+                break;
+            }
+            case CTX_METHOD: {
+                if (name == AttAnnotationDefault.ATTRIBUTE_NAME) {
+                    return annotationDefault(cf, offset, length, observer);
+                }
+                if (name == AttCode.ATTRIBUTE_NAME) {
+                    return code(cf, offset, length, observer);
+                }
+                if (name == AttDeprecated.ATTRIBUTE_NAME) {
+                    return deprecated(cf, offset, length, observer);
+                }
+                if (name == AttExceptions.ATTRIBUTE_NAME) {
+                    return exceptions(cf, offset, length, observer);
+                }
+                if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) {
+                    return runtimeInvisibleAnnotations(cf, offset, length,
+                            observer);
+                }
+                if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) {
+                    return runtimeVisibleAnnotations(cf, offset, length,
+                            observer);
+                }
+                if (name == AttRuntimeInvisibleParameterAnnotations.
+                        ATTRIBUTE_NAME) {
+                    return runtimeInvisibleParameterAnnotations(
+                            cf, offset, length, observer);
+                }
+                if (name == AttRuntimeVisibleParameterAnnotations.
+                        ATTRIBUTE_NAME) {
+                    return runtimeVisibleParameterAnnotations(
+                            cf, offset, length, observer);
+                }
+                if (name == AttSignature.ATTRIBUTE_NAME) {
+                    return signature(cf, offset, length, observer);
+                }
+                if (name == AttSynthetic.ATTRIBUTE_NAME) {
+                    return synthetic(cf, offset, length, observer);
+                }
+                break;
+            }
+            case CTX_CODE: {
+                if (name == AttLineNumberTable.ATTRIBUTE_NAME) {
+                    return lineNumberTable(cf, offset, length, observer);
+                }
+                if (name == AttLocalVariableTable.ATTRIBUTE_NAME) {
+                    return localVariableTable(cf, offset, length, observer);
+                }
+                if (name == AttLocalVariableTypeTable.ATTRIBUTE_NAME) {
+                    return localVariableTypeTable(cf, offset, length,
+                            observer);
+                }
+                break;
+            }
+        }
+
+        return super.parse0(cf, context, name, offset, length, observer);
+    }
+
+    /**
+     * Parses an {@code AnnotationDefault} attribute.
+     */
+    private Attribute annotationDefault(DirectClassFile cf,
+            int offset, int length, ParseObserver observer) {
+        if (length < 2) {
+            throwSeverelyTruncated();
+        }
+
+        AnnotationParser ap =
+            new AnnotationParser(cf, offset, length, observer);
+        Constant cst = ap.parseValueAttribute();
+
+        return new AttAnnotationDefault(cst, length);
+    }
+
+    /**
+     * Parses a {@code Code} attribute.
+     */
+    private Attribute code(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length < 12) {
+            return throwSeverelyTruncated();
+        }
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+        int maxStack = bytes.getUnsignedShort(offset); // u2 max_stack
+        int maxLocals = bytes.getUnsignedShort(offset + 2); // u2 max_locals
+        int codeLength = bytes.getInt(offset + 4); // u4 code_length
+        int origOffset = offset;
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            "max_stack: " + Hex.u2(maxStack));
+            observer.parsed(bytes, offset + 2, 2,
+                            "max_locals: " + Hex.u2(maxLocals));
+            observer.parsed(bytes, offset + 4, 4,
+                            "code_length: " + Hex.u4(codeLength));
+        }
+
+        offset += 8;
+        length -= 8;
+
+        if (length < (codeLength + 4)) {
+            return throwTruncated();
+        }
+
+        int codeOffset = offset;
+        offset += codeLength;
+        length -= codeLength;
+        BytecodeArray code =
+            new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength),
+                              pool);
+        if (observer != null) {
+            code.forEach(new CodeObserver(code.getBytes(), observer));
+        }
+
+        // u2 exception_table_length
+        int exceptionTableLength = bytes.getUnsignedShort(offset);
+        ByteCatchList catches = (exceptionTableLength == 0) ?
+            ByteCatchList.EMPTY :
+            new ByteCatchList(exceptionTableLength);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            "exception_table_length: " +
+                            Hex.u2(exceptionTableLength));
+        }
+
+        offset += 2;
+        length -= 2;
+
+        if (length < (exceptionTableLength * 8 + 2)) {
+            return throwTruncated();
+        }
+
+        for (int i = 0; i < exceptionTableLength; i++) {
+            if (observer != null) {
+                observer.changeIndent(1);
+            }
+
+            int startPc = bytes.getUnsignedShort(offset);
+            int endPc = bytes.getUnsignedShort(offset + 2);
+            int handlerPc = bytes.getUnsignedShort(offset + 4);
+            int catchTypeIdx = bytes.getUnsignedShort(offset + 6);
+            CstType catchType = (CstType) pool.get0Ok(catchTypeIdx);
+            catches.set(i, startPc, endPc, handlerPc, catchType);
+            if (observer != null) {
+                observer.parsed(bytes, offset, 8,
+                                Hex.u2(startPc) + ".." + Hex.u2(endPc) +
+                                " -> " + Hex.u2(handlerPc) + " " +
+                                ((catchType == null) ? "<any>" :
+                                 catchType.toHuman()));
+            }
+            offset += 8;
+            length -= 8;
+
+            if (observer != null) {
+                observer.changeIndent(-1);
+            }
+        }
+
+        catches.setImmutable();
+
+        AttributeListParser parser =
+            new AttributeListParser(cf, CTX_CODE, offset, this);
+        parser.setObserver(observer);
+
+        StdAttributeList attributes = parser.getList();
+        attributes.setImmutable();
+
+        int attributeByteCount = parser.getEndOffset() - offset;
+        if (attributeByteCount != length) {
+            return throwBadLength(attributeByteCount + (offset - origOffset));
+        }
+
+        return new AttCode(maxStack, maxLocals, code, catches, attributes);
+    }
+
+    /**
+     * Parses a {@code ConstantValue} attribute.
+     */
+    private Attribute constantValue(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length != 2) {
+            return throwBadLength(2);
+        }
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+        int idx = bytes.getUnsignedShort(offset);
+        TypedConstant cst = (TypedConstant) pool.get(idx);
+        Attribute result = new AttConstantValue(cst);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2, "value: " + cst);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses a {@code Deprecated} attribute.
+     */
+    private Attribute deprecated(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length != 0) {
+            return throwBadLength(0);
+        }
+
+        return new AttDeprecated();
+    }
+
+    /**
+     * Parses an {@code EnclosingMethod} attribute.
+     */
+    private Attribute enclosingMethod(DirectClassFile cf, int offset,
+            int length, ParseObserver observer) {
+        if (length != 4) {
+            throwBadLength(4);
+        }
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+
+        int idx = bytes.getUnsignedShort(offset);
+        CstType type = (CstType) pool.get(idx);
+
+        idx = bytes.getUnsignedShort(offset + 2);
+        CstNat method = (CstNat) pool.get0Ok(idx);
+
+        Attribute result = new AttEnclosingMethod(type, method);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2, "class: " + type);
+            observer.parsed(bytes, offset + 2, 2, "method: " +
+                            DirectClassFile.stringOrNone(method));
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses an {@code Exceptions} attribute.
+     */
+    private Attribute exceptions(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length < 2) {
+            return throwSeverelyTruncated();
+        }
+
+        ByteArray bytes = cf.getBytes();
+        int count = bytes.getUnsignedShort(offset); // number_of_exceptions
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            "number_of_exceptions: " + Hex.u2(count));
+        }
+
+        offset += 2;
+        length -= 2;
+
+        if (length != (count * 2)) {
+            throwBadLength((count * 2) + 2);
+        }
+
+        TypeList list = cf.makeTypeList(offset, count);
+        return new AttExceptions(list);
+    }
+
+    /**
+     * Parses an {@code InnerClasses} attribute.
+     */
+    private Attribute innerClasses(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length < 2) {
+            return throwSeverelyTruncated();
+        }
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+        int count = bytes.getUnsignedShort(offset); // number_of_classes
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            "number_of_classes: " + Hex.u2(count));
+        }
+
+        offset += 2;
+        length -= 2;
+
+        if (length != (count * 8)) {
+            throwBadLength((count * 8) + 2);
+        }
+
+        InnerClassList list = new InnerClassList(count);
+
+        for (int i = 0; i < count; i++) {
+            int innerClassIdx = bytes.getUnsignedShort(offset);
+            int outerClassIdx = bytes.getUnsignedShort(offset + 2);
+            int nameIdx = bytes.getUnsignedShort(offset + 4);
+            int accessFlags = bytes.getUnsignedShort(offset + 6);
+            CstType innerClass = (CstType) pool.get(innerClassIdx);
+            CstType outerClass = (CstType) pool.get0Ok(outerClassIdx);
+            CstString name = (CstString) pool.get0Ok(nameIdx);
+            list.set(i, innerClass, outerClass, name, accessFlags);
+            if (observer != null) {
+                observer.parsed(bytes, offset, 2,
+                                "inner_class: " +
+                                DirectClassFile.stringOrNone(innerClass));
+                observer.parsed(bytes, offset + 2, 2,
+                                "  outer_class: " +
+                                DirectClassFile.stringOrNone(outerClass));
+                observer.parsed(bytes, offset + 4, 2,
+                                "  name: " +
+                                DirectClassFile.stringOrNone(name));
+                observer.parsed(bytes, offset + 6, 2,
+                                "  access_flags: " +
+                                AccessFlags.innerClassString(accessFlags));
+            }
+            offset += 8;
+        }
+
+        list.setImmutable();
+        return new AttInnerClasses(list);
+    }
+
+    /**
+     * Parses a {@code LineNumberTable} attribute.
+     */
+    private Attribute lineNumberTable(DirectClassFile cf, int offset,
+            int length, ParseObserver observer) {
+        if (length < 2) {
+            return throwSeverelyTruncated();
+        }
+
+        ByteArray bytes = cf.getBytes();
+        int count = bytes.getUnsignedShort(offset); // line_number_table_length
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                            "line_number_table_length: " + Hex.u2(count));
+        }
+
+        offset += 2;
+        length -= 2;
+
+        if (length != (count * 4)) {
+            throwBadLength((count * 4) + 2);
+        }
+
+        LineNumberList list = new LineNumberList(count);
+
+        for (int i = 0; i < count; i++) {
+            int startPc = bytes.getUnsignedShort(offset);
+            int lineNumber = bytes.getUnsignedShort(offset + 2);
+            list.set(i, startPc, lineNumber);
+            if (observer != null) {
+                observer.parsed(bytes, offset, 4,
+                                Hex.u2(startPc) + " " + lineNumber);
+            }
+            offset += 4;
+        }
+
+        list.setImmutable();
+        return new AttLineNumberTable(list);
+    }
+
+    /**
+     * Parses a {@code LocalVariableTable} attribute.
+     */
+    private Attribute localVariableTable(DirectClassFile cf, int offset,
+            int length, ParseObserver observer) {
+        if (length < 2) {
+            return throwSeverelyTruncated();
+        }
+
+        ByteArray bytes = cf.getBytes();
+        int count = bytes.getUnsignedShort(offset);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                    "local_variable_table_length: " + Hex.u2(count));
+        }
+
+        LocalVariableList list = parseLocalVariables(
+                bytes.slice(offset + 2, offset + length), cf.getConstantPool(),
+                observer, count, false);
+        return new AttLocalVariableTable(list);
+    }
+
+    /**
+     * Parses a {@code LocalVariableTypeTable} attribute.
+     */
+    private Attribute localVariableTypeTable(DirectClassFile cf, int offset,
+            int length, ParseObserver observer) {
+        if (length < 2) {
+            return throwSeverelyTruncated();
+        }
+
+        ByteArray bytes = cf.getBytes();
+        int count = bytes.getUnsignedShort(offset);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2,
+                    "local_variable_type_table_length: " + Hex.u2(count));
+        }
+
+        LocalVariableList list = parseLocalVariables(
+                bytes.slice(offset + 2, offset + length), cf.getConstantPool(),
+                observer, count, true);
+        return new AttLocalVariableTypeTable(list);
+    }
+
+    /**
+     * Parse the table part of either a {@code LocalVariableTable}
+     * or a {@code LocalVariableTypeTable}.
+     *
+     * @param bytes {@code non-null;} bytes to parse, which should <i>only</i>
+     * contain the table data (no header)
+     * @param pool {@code non-null;} constant pool to use
+     * @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,
+            boolean typeTable) {
+        if (bytes.size() != (count * 10)) {
+            // "+ 2" is for the count.
+            throwBadLength((count * 10) + 2);
+        }
+
+        ByteArray.MyDataInputStream in = bytes.makeDataInputStream();
+        LocalVariableList list = new LocalVariableList(count);
+
+        try {
+            for (int i = 0; i < count; i++) {
+                int startPc = in.readUnsignedShort();
+                int length = in.readUnsignedShort();
+                int nameIdx = in.readUnsignedShort();
+                int typeIdx = in.readUnsignedShort();
+                int index = in.readUnsignedShort();
+                CstString name = (CstString) pool.get(nameIdx);
+                CstString type = (CstString) pool.get(typeIdx);
+                CstString descriptor = null;
+                CstString signature = null;
+
+                if (typeTable) {
+                    signature = type;
+                } else {
+                    descriptor = type;
+                }
+
+                list.set(i, startPc, length, name,
+                        descriptor, signature, index);
+
+                if (observer != null) {
+                    observer.parsed(bytes, i * 10, 10, Hex.u2(startPc) +
+                            ".." + Hex.u2(startPc + length) + " " +
+                            Hex.u2(index) + " " + name.toHuman() + " " +
+                            type.toHuman());
+                }
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException("shouldn't happen", ex);
+        }
+
+        list.setImmutable();
+        return list;
+    }
+
+    /**
+     * Parses a {@code RuntimeInvisibleAnnotations} attribute.
+     */
+    private Attribute runtimeInvisibleAnnotations(DirectClassFile cf,
+            int offset, int length, ParseObserver observer) {
+        if (length < 2) {
+            throwSeverelyTruncated();
+        }
+
+        AnnotationParser ap =
+            new AnnotationParser(cf, offset, length, observer);
+        Annotations annotations =
+            ap.parseAnnotationAttribute(AnnotationVisibility.BUILD);
+
+        return new AttRuntimeInvisibleAnnotations(annotations, length);
+    }
+
+    /**
+     * Parses a {@code RuntimeVisibleAnnotations} attribute.
+     */
+    private Attribute runtimeVisibleAnnotations(DirectClassFile cf,
+            int offset, int length, ParseObserver observer) {
+        if (length < 2) {
+            throwSeverelyTruncated();
+        }
+
+        AnnotationParser ap =
+            new AnnotationParser(cf, offset, length, observer);
+        Annotations annotations =
+            ap.parseAnnotationAttribute(AnnotationVisibility.RUNTIME);
+
+        return new AttRuntimeVisibleAnnotations(annotations, length);
+    }
+
+    /**
+     * Parses a {@code RuntimeInvisibleParameterAnnotations} attribute.
+     */
+    private Attribute runtimeInvisibleParameterAnnotations(DirectClassFile cf,
+            int offset, int length, ParseObserver observer) {
+        if (length < 2) {
+            throwSeverelyTruncated();
+        }
+
+        AnnotationParser ap =
+            new AnnotationParser(cf, offset, length, observer);
+        AnnotationsList list =
+            ap.parseParameterAttribute(AnnotationVisibility.BUILD);
+
+        return new AttRuntimeInvisibleParameterAnnotations(list, length);
+    }
+
+    /**
+     * Parses a {@code RuntimeVisibleParameterAnnotations} attribute.
+     */
+    private Attribute runtimeVisibleParameterAnnotations(DirectClassFile cf,
+            int offset, int length, ParseObserver observer) {
+        if (length < 2) {
+            throwSeverelyTruncated();
+        }
+
+        AnnotationParser ap =
+            new AnnotationParser(cf, offset, length, observer);
+        AnnotationsList list =
+            ap.parseParameterAttribute(AnnotationVisibility.RUNTIME);
+
+        return new AttRuntimeVisibleParameterAnnotations(list, length);
+    }
+
+    /**
+     * Parses a {@code Signature} attribute.
+     */
+    private Attribute signature(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length != 2) {
+            throwBadLength(2);
+        }
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+        int idx = bytes.getUnsignedShort(offset);
+        CstString cst = (CstString) pool.get(idx);
+        Attribute result = new AttSignature(cst);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2, "signature: " + cst);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses a {@code SourceFile} attribute.
+     */
+    private Attribute sourceFile(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length != 2) {
+            throwBadLength(2);
+        }
+
+        ByteArray bytes = cf.getBytes();
+        ConstantPool pool = cf.getConstantPool();
+        int idx = bytes.getUnsignedShort(offset);
+        CstString cst = (CstString) pool.get(idx);
+        Attribute result = new AttSourceFile(cst);
+
+        if (observer != null) {
+            observer.parsed(bytes, offset, 2, "source: " + cst);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses a {@code Synthetic} attribute.
+     */
+    private Attribute synthetic(DirectClassFile cf, int offset, int length,
+            ParseObserver observer) {
+        if (length != 0) {
+            return throwBadLength(0);
+        }
+
+        return new AttSynthetic();
+    }
+
+    /**
+     * Throws the right exception when a known attribute has a way too short
+     * length.
+     *
+     * @return never
+     * @throws ParseException always thrown
+     */
+    private static Attribute throwSeverelyTruncated() {
+        throw new ParseException("severely truncated attribute");
+    }
+
+    /**
+     * Throws the right exception when a known attribute has a too short
+     * length.
+     *
+     * @return never
+     * @throws ParseException always thrown
+     */
+    private static Attribute throwTruncated() {
+        throw new ParseException("truncated attribute");
+    }
+
+    /**
+     * Throws the right exception when an attribute has an unexpected length
+     * (given its contents).
+     *
+     * @param expected expected length
+     * @return never
+     * @throws ParseException always thrown
+     */
+    private static Attribute throwBadLength(int expected) {
+        throw new ParseException("bad attribute length; expected length " +
+                                 Hex.u4(expected));
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/package.html b/dx/src/com/android/dx/cf/direct/package.html
new file mode 100644
index 0000000..2a46198
--- /dev/null
+++ b/dx/src/com/android/dx/cf/direct/package.html
@@ -0,0 +1,12 @@
+<body>
+<p>Implementation of <code>cf.iface.*</code> based on a direct representation
+of class files as <code>byte[]</code>s.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.cf.attrib</code></li>
+<li><code>com.android.dx.cf.iface</code></li>
+<li><code>com.android.dx.rop.pool</code></li>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/cf/iface/Attribute.java b/dx/src/com/android/dx/cf/iface/Attribute.java
new file mode 100644
index 0000000..b075251
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/Attribute.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+/**
+ * Interface representing attributes of class files (directly or indirectly).
+ */
+public interface Attribute {
+    /**
+     * Get the name of the attribute.
+     *
+     * @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}.
+     *
+     * @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
new file mode 100644
index 0000000..f7a1d27
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/AttributeList.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+/**
+ * Interface for lists of attributes.
+ */
+public interface AttributeList {
+    /**
+     * Get whether this instance is mutable. Note that the
+     * {@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} iff this instance is somehow mutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Get the number of attributes in the list.
+     *
+     * @return the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th attribute.
+     *
+     * @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} length indicator.
+     *
+     * @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 {@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);
+
+    /**
+     * Get the next attribute in the list after the given one, with the same
+     * name, if any.
+     *
+     * @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
new file mode 100644
index 0000000..cb5237a
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/ClassFile.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.rop.cst.ConstantPool;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * Interface for things which purport to be class files or reasonable
+ * facsimiles thereof.
+ *
+ * <p><b>Note:</b> The fields referred to in this documentation are of the
+ * {@code ClassFile} structure defined in vmspec-2 sec4.1.
+ */
+public interface ClassFile {
+    /**
+     * Gets the field {@code magic}.
+     *
+     * @return the value in question
+     */
+    public int getMagic();
+
+    /**
+     * Gets the field {@code minor_version}.
+     *
+     * @return the value in question
+     */
+    public int getMinorVersion();
+
+    /**
+     * Gets the field {@code major_version}.
+     *
+     * @return the value in question
+     */
+    public int getMajorVersion();
+
+    /**
+     * Gets the field {@code access_flags}.
+     *
+     * @return the value in question
+     */
+    public int getAccessFlags();
+
+    /**
+     * Gets the field {@code this_class}, interpreted as a type constant.
+     *
+     * @return {@code non-null;} the value in question
+     */
+    public CstType getThisClass();
+
+    /**
+     * Gets the field {@code super_class}, interpreted as a type constant
+     * if non-zero.
+     *
+     * @return {@code null-ok;} the value in question
+     */
+    public CstType getSuperclass();
+
+    /**
+     * Gets the field {@code constant_pool} (along with
+     * {@code constant_pool_count}).
+     *
+     * @return {@code non-null;} the constant pool
+     */
+    public ConstantPool getConstantPool();
+
+    /**
+     * Gets the field {@code interfaces} (along with
+     * {@code interfaces_count}).
+     *
+     * @return {@code non-null;} the list of interfaces
+     */
+    public TypeList getInterfaces();
+
+    /**
+     * Gets the field {@code fields} (along with
+     * {@code fields_count}).
+     *
+     * @return {@code non-null;} the list of fields
+     */
+    public FieldList getFields();
+
+    /**
+     * Gets the field {@code methods} (along with
+     * {@code methods_count}).
+     *
+     * @return {@code non-null;} the list of fields
+     */
+    public MethodList getMethods();
+
+    /**
+     * Gets the field {@code attributes} (along with
+     * {@code attributes_count}).
+     *
+     * @return {@code non-null;} the list of attributes
+     */
+    public AttributeList getAttributes();
+
+    /**
+     * 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 {@code non-null;} the constant pool
+     */
+    public CstString getSourceFile();
+}
diff --git a/dx/src/com/android/dx/cf/iface/Field.java b/dx/src/com/android/dx/cf/iface/Field.java
new file mode 100644
index 0000000..e3002bc
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/Field.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.rop.cst.TypedConstant;
+
+/**
+ * Interface representing fields of class files.
+ */
+public interface Field
+        extends Member {
+    /**
+     * Get the constant value for this field, if any. This only returns
+     * non-{@code null} for a {@code static final} field which
+     * includes a {@code ConstantValue} attribute.
+     *
+     * @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
new file mode 100644
index 0000000..9cd27a3
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/FieldList.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+/**
+ * Interface for lists of fields.
+ */
+public interface FieldList
+{
+    /**
+     * Get whether this instance is mutable. Note that the
+     * {@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} iff this instance is somehow mutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Get the number of fields in the list.
+     *
+     * @return the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th field.
+     *
+     * @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
new file mode 100644
index 0000000..b346de4
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/Member.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+
+/**
+ * Interface representing members of class files (that is, fields and methods).
+ */
+public interface Member {
+    /**
+     * Get the defining class.
+     *
+     * @return {@code non-null;} the defining class
+     */
+    public CstType getDefiningClass();
+
+    /**
+     * Get the field {@code access_flags}.
+     *
+     * @return the access flags
+     */
+    public int getAccessFlags();
+
+    /**
+     * Get the field {@code name_index} of the member. This is
+     * just a convenient shorthand for {@code getNat().getName()}.
+     *
+     * @return {@code non-null;} the name
+     */
+    public CstString getName();
+
+    /**
+     * Get the field {@code descriptor_index} of the member. This is
+     * just a convenient shorthand for {@code getNat().getDescriptor()}.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public CstString getDescriptor();
+
+    /**
+     * Get the name and type associated with this member. This is a
+     * combination of the fields {@code name_index} and
+     * {@code descriptor_index} in the original classfile, interpreted
+     * via the constant pool.
+     *
+     * @return {@code non-null;} the name and type
+     */
+    public CstNat getNat();
+
+    /**
+     * Get the field {@code attributes} (along with
+     * {@code attributes_count}).
+     *
+     * @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
new file mode 100644
index 0000000..18b9af6
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/Method.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.rop.type.Prototype;
+
+/**
+ * Interface representing methods of class files.
+ */
+public interface Method
+    extends Member
+{
+    /**
+     * Get the <i>effective</i> method descriptor, which includes, if
+     * necessary, a first {@code this} parameter.
+     *
+     * @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
new file mode 100644
index 0000000..dfa6528
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/MethodList.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+/**
+ * Interface for lists of methods.
+ */
+public interface MethodList {
+    /**
+     * Get whether this instance is mutable. Note that the
+     * {@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} iff this instance is somehow mutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Get the number of methods in the list.
+     *
+     * @return the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th method.
+     *
+     * @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/ParseException.java b/dx/src/com/android/dx/cf/iface/ParseException.java
new file mode 100644
index 0000000..18a9d0e
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/ParseException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.util.ExceptionWithContext;
+
+/**
+ * Exception from parsing.
+ */
+public class ParseException
+        extends ExceptionWithContext {
+    public ParseException(String message) {
+        super(message);
+    }
+
+    public ParseException(Throwable cause) {
+        super(cause);
+    }
+
+    public ParseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/dx/src/com/android/dx/cf/iface/ParseObserver.java b/dx/src/com/android/dx/cf/iface/ParseObserver.java
new file mode 100644
index 0000000..98d5a75
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/ParseObserver.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.util.ByteArray;
+
+/**
+ * Observer of parsing in action. This is used to supply feedback from
+ * the various things that parse particularly to the dumping utilities.
+ */
+public interface ParseObserver {
+    /**
+     * Indicate that the level of indentation for a dump should increase
+     * or decrease (positive or negative argument, respectively).
+     *
+     * @param indentDelta the amount to change indentation
+     */
+    public void changeIndent(int indentDelta);
+
+    /**
+     * Indicate that a particular member is now being parsed.
+     *
+     * @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 {@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);
+
+    /**
+     * Indicate that a particular member is no longer being parsed.
+     *
+     * @param bytes {@code non-null;} the source that was parsed
+     * @param offset offset into {@code bytes} for the end of the
+     * member
+     * @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);
+
+    /**
+     * Indicate that some parsing happened.
+     *
+     * @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 {@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
new file mode 100644
index 0000000..287b8c7
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/StdAttributeList.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link AttributeList}, which directly stores
+ * an array of {@link Attribute} objects and can be made immutable.
+ */
+public final class StdAttributeList extends FixedSizeList
+        implements AttributeList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdAttributeList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Attribute get(int n) {
+        return (Attribute) get0(n);
+    }
+
+    /** {@inheritDoc} */
+    public int byteLength() {
+        int sz = size();
+        int result = 2; // u2 attributes_count
+
+        for (int i = 0; i < sz; i++) {
+            result += get(i).byteLength();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public Attribute findFirst(String name) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            Attribute att = get(i);
+            if (att.getName().equals(name)) {
+                return att;
+            }
+        }
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public Attribute findNext(Attribute attrib) {
+        int sz = size();
+        int at;
+
+        outer: {
+            for (at = 0; at < sz; at++) {
+                Attribute att = get(at);
+                if (att == attrib) {
+                    break outer;
+                }
+            }
+
+            return null;
+        }
+
+        String name = attrib.getName();
+
+        for (at++; at < sz; at++) {
+            Attribute att = get(at);
+            if (att.getName().equals(name)) {
+                return att;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets the attribute at the given index.
+     *
+     * @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
new file mode 100644
index 0000000..ef9873d
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/StdField.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.cf.attrib.AttConstantValue;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.TypedConstant;
+
+/**
+ * Standard implementation of {@link Field}, which directly stores
+ * all the associated data.
+ */
+public final class StdField extends StdMember implements Field {
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the defining class
+     * @param accessFlags access flags
+     * @param nat {@code non-null;} member name and type (descriptor)
+     * @param attributes {@code non-null;} list of associated attributes
+     */
+    public StdField(CstType definingClass, int accessFlags, CstNat nat,
+                    AttributeList attributes) {
+        super(definingClass, accessFlags, nat, attributes);
+    }
+
+    /** {@inheritDoc} */
+    public TypedConstant getConstantValue() {
+        AttributeList attribs = getAttributes();
+        AttConstantValue cval = (AttConstantValue)
+            attribs.findFirst(AttConstantValue.ATTRIBUTE_NAME);
+
+        if (cval == null) {
+            return null;
+        }
+
+        return cval.getConstantValue();
+    }
+}
diff --git a/dx/src/com/android/dx/cf/iface/StdFieldList.java b/dx/src/com/android/dx/cf/iface/StdFieldList.java
new file mode 100644
index 0000000..f27bd22
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/StdFieldList.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link FieldList}, which directly stores
+ * an array of {@link Field} objects and can be made immutable.
+ */
+public final class StdFieldList extends FixedSizeList implements FieldList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdFieldList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Field get(int n) {
+        return (Field) get0(n);
+    }
+
+    /**
+     * Sets the field at the given index.
+     *
+     * @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
new file mode 100644
index 0000000..e67b216
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/StdMember.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+
+/**
+ * Standard implementation of {@link Member}, which directly stores
+ * all the associated data.
+ */
+public abstract class StdMember implements Member {
+    /** {@code non-null;} the defining class */
+    private final CstType definingClass;
+
+    /** access flags */
+    private final int accessFlags;
+
+    /** {@code non-null;} member name and type */
+    private final CstNat nat;
+
+    /** {@code non-null;} list of associated attributes */
+    private final AttributeList attributes;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the defining class
+     * @param accessFlags access flags
+     * @param nat {@code non-null;} member name and type (descriptor)
+     * @param attributes {@code non-null;} list of associated attributes
+     */
+    public StdMember(CstType definingClass, int accessFlags, CstNat nat,
+                     AttributeList attributes) {
+        if (definingClass == null) {
+            throw new NullPointerException("definingClass == null");
+        }
+
+        if (nat == null) {
+            throw new NullPointerException("nat == null");
+        }
+
+        if (attributes == null) {
+            throw new NullPointerException("attributes == null");
+        }
+
+        this.definingClass = definingClass;
+        this.accessFlags = accessFlags;
+        this.nat = nat;
+        this.attributes = attributes;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(nat.toHuman());
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    public final CstType getDefiningClass() {
+        return definingClass;
+    }
+
+    /** {@inheritDoc} */
+    public final int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /** {@inheritDoc} */
+    public final CstNat getNat() {
+        return nat;
+    }
+
+    /** {@inheritDoc} */
+    public final CstString getName() {
+        return nat.getName();
+    }
+
+    /** {@inheritDoc} */
+    public final CstString getDescriptor() {
+        return nat.getDescriptor();
+    }
+
+    /** {@inheritDoc} */
+    public final AttributeList getAttributes() {
+        return attributes;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/iface/StdMethod.java b/dx/src/com/android/dx/cf/iface/StdMethod.java
new file mode 100644
index 0000000..c511d7d
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/StdMethod.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+
+/**
+ * Standard implementation of {@link Method}, which directly stores
+ * all the associated data.
+ */
+public final class StdMethod extends StdMember implements Method {
+    /** {@code non-null;} the effective method descriptor */
+    private final Prototype effectiveDescriptor;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the defining class
+     * @param accessFlags access flags
+     * @param nat {@code non-null;} member name and type (descriptor)
+     * @param attributes {@code non-null;} list of associated attributes
+     */
+    public StdMethod(CstType definingClass, int accessFlags, CstNat nat,
+            AttributeList attributes) {
+        super(definingClass, accessFlags, nat, attributes);
+
+        String descStr = getDescriptor().getString();
+        effectiveDescriptor =
+            Prototype.intern(descStr, definingClass.getClassType(),
+                                    AccessFlags.isStatic(accessFlags),
+                                    nat.isInstanceInit());
+    }
+
+    /** {@inheritDoc} */
+    public Prototype getEffectiveDescriptor() {
+        return effectiveDescriptor;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/iface/StdMethodList.java b/dx/src/com/android/dx/cf/iface/StdMethodList.java
new file mode 100644
index 0000000..417cdee
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/StdMethodList.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.cf.iface;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link MethodList}, which directly stores
+ * an array of {@link Method} objects and can be made immutable.
+ */
+public final class StdMethodList extends FixedSizeList implements MethodList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdMethodList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Method get(int n) {
+        return (Method) get0(n);
+    }
+
+    /**
+     * Sets the method at the given index.
+     *
+     * @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/cf/iface/package.html b/dx/src/com/android/dx/cf/iface/package.html
new file mode 100644
index 0000000..c734552
--- /dev/null
+++ b/dx/src/com/android/dx/cf/iface/package.html
@@ -0,0 +1,10 @@
+<body>
+<p>Interfaces and base classes for dealing with class files. This package
+doesn't have any parsing but does have basic container implementations.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.rop.pool</code></li>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/command/DxConsole.java b/dx/src/com/android/dx/command/DxConsole.java
new file mode 100644
index 0000000..9ce9836
--- /dev/null
+++ b/dx/src/com/android/dx/command/DxConsole.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command;
+
+import java.io.PrintStream;
+
+/**
+ * Provides standard and error PrintStream object to output information.<br>
+ * 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} by default.
+     */
+    public static PrintStream out = System.out;
+
+    /**
+     * 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
new file mode 100644
index 0000000..d0bbbe2
--- /dev/null
+++ b/dx/src/com/android/dx/command/Main.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command;
+
+import com.android.dx.Version;
+
+import junit.textui.TestRunner;
+
+/**
+ * Main class for dx. It recognizes enough options to be able to dispatch
+ * to the right "actual" main.
+ */
+public class Main {
+    private static String USAGE_MESSAGE =
+        "usage:\n" +
+        "  dx --dex [--debug] [--verbose] [--positions=<style>] " +
+        "[--no-locals]\n" +
+        "  [--no-optimize] [--statistics] [--[no-]optimize-list=<file>] " +
+        "[--no-strict]\n" +
+        "  [--keep-classes] [--output=<file>] [--dump-to=<file>] " +
+        "[--dump-width=<n>]\n" +
+        "  [--dump-method=<name>[*]] [--verbose-dump] [--no-files] " +
+        "[--core-library]\n" +
+        "  [--num-threads=<n>]\n" +
+        "  [<file>.class | <file>.{zip,jar,apk} | <directory>] ...\n" +
+        "    Convert a set of classfiles into a dex file, optionally " +
+        "embedded in a\n" +
+        "    jar/zip. Output name must end with one of: .dex .jar " +
+        ".zip .apk. Positions\n" +
+        "    options: none, important, lines.\n" +
+        "  dx --annotool --annotation=<class> [--element=<element types>]\n" +
+        "  [--print=<print types>]\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, or transformations thereof, in a " +
+        "human-oriented format.\n" +
+        "  dx --junit [-wait] <TestClass>\n" +
+        "    Run the indicated unit test.\n" +
+        "  dx --find-usages <file.dex> <declaring type> <member>\n" +
+        "    Find references and declarations to a field or method.\n" +
+        "    declaring type: a class name in internal form, like " +
+        "Ljava/lang/Object;\n" +
+        "    member: a field or method name, like hashCode\n" +
+        "  dx -J<option> ... <arguments, in one of the above " +
+        "forms>\n" +
+        "    Pass VM-specific options to the virtual machine that " +
+        "runs dx.\n" +
+        "  dx --version\n" +
+        "    Print the version of this tool (" + Version.VERSION +
+        ").\n" +
+        "  dx --help\n" +
+        "    Print this message.";
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Main() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Run!
+     */
+    public static void main(String[] args) {
+        boolean gotCmd = false;
+        boolean showUsage = false;
+
+        try {
+            for (int i = 0; i < args.length; i++) {
+                String arg = args[i];
+                if (arg.equals("--") || !arg.startsWith("--")) {
+                    gotCmd = false;
+                    showUsage = true;
+                    break;
+                }
+
+                gotCmd = true;
+                if (arg.equals("--dex")) {
+                    com.android.dx.command.dexer.Main.main(without(args, i));
+                    break;
+                } else if (arg.equals("--dump")) {
+                    com.android.dx.command.dump.Main.main(without(args, i));
+                    break;
+                } else if (arg.equals("--annotool")) {
+                    com.android.dx.command.annotool.Main.main(
+                            without(args, i));
+                    break;
+                } else if (arg.equals("--junit")) {
+                    TestRunner.main(without(args, i));
+                    break;
+                } else if (arg.equals("--find-usages")) {
+                    com.android.dx.command.findusages.Main.main(without(args, i));
+                    break;
+                } else if (arg.equals("--version")) {
+                    version();
+                    break;
+                } else if (arg.equals("--help")) {
+                    showUsage = true;
+                    break;
+                } else {
+                    gotCmd = false;
+                }
+            }
+        } catch (UsageException ex) {
+            showUsage = true;
+        } catch (RuntimeException ex) {
+            System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
+            ex.printStackTrace();
+            System.exit(2);
+        } catch (Throwable ex) {
+            System.err.println("\nUNEXPECTED TOP-LEVEL ERROR:");
+            ex.printStackTrace();
+            if ((ex instanceof NoClassDefFoundError)
+                    || (ex instanceof NoSuchMethodError)) {
+                System.err.println(
+                        "Note: You may be using an incompatible " +
+                        "virtual machine or class library.\n" +
+                        "(This program is known to be incompatible " +
+                        "with recent releases of GCJ.)");
+            }
+            System.exit(3);
+        }
+
+        if (!gotCmd) {
+            System.err.println("error: no command specified");
+            showUsage = true;
+        }
+
+        if (showUsage) {
+            usage();
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Prints the version message.
+     */
+    private static void version() {
+        System.err.println("dx version " + Version.VERSION);
+        System.exit(0);
+    }
+
+    /**
+     * Prints the usage message.
+     */
+    private static void usage() {
+        System.err.println(USAGE_MESSAGE);
+    }
+
+    /**
+     * Returns a copy of the given args array, but without the indicated
+     * element.
+     *
+     * @param orig {@code non-null;} original array
+     * @param n which element to omit
+     * @return {@code non-null;} new array
+     */
+    private static String[] without(String[] orig, int n) {
+        int len = orig.length - 1;
+        String[] newa = new String[len];
+        System.arraycopy(orig, 0, newa, 0, n);
+        System.arraycopy(orig, n + 1, newa, n, len - n);
+        return newa;
+    }
+}
diff --git a/dx/src/com/android/dx/command/UsageException.java b/dx/src/com/android/dx/command/UsageException.java
new file mode 100644
index 0000000..6809bf4
--- /dev/null
+++ b/dx/src/com/android/dx/command/UsageException.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command;
+
+/**
+ * Simple exception class used to communicate that the command-line tool
+ * should print the usage message.
+ */
+public class UsageException extends RuntimeException {
+    // This space intentionally left blank.
+}
diff --git a/dx/src/com/android/dx/command/annotool/AnnotationLister.java b/dx/src/com/android/dx/command/annotool/AnnotationLister.java
new file mode 100644
index 0000000..6584b60
--- /dev/null
+++ b/dx/src/com/android/dx/command/annotool/AnnotationLister.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.annotool;
+
+import com.android.dx.cf.direct.ClassPathOpener;
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.direct.StdAttributeFactory;
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.Attribute;
+import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations;
+import com.android.dx.cf.attrib.BaseAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
+import com.android.dx.util.ByteArray;
+import com.android.dx.rop.annotation.Annotation;
+
+import java.io.File;
+import java.lang.annotation.ElementType;
+import java.util.HashSet;
+
+/**
+ * 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} instance.
+ */
+class AnnotationLister {
+    /**
+     * The string name of the pseudo-class that
+     * contains package-wide annotations
+     */
+    private static final String PACKAGE_INFO = "package-info";
+
+    /** current match configuration */
+    private final Main.Arguments args;
+
+    /** Set of classes whose inner classes should be considered matched */
+    HashSet<String> matchInnerClassesOf = new HashSet<String>();
+
+    /** set of packages whose classes should be considered matched */
+    HashSet<String> matchPackages = new HashSet<String>();
+
+    AnnotationLister (Main.Arguments args) {
+        this.args = args;
+    }
+
+    /** Processes based on configuration specified in constructor. */
+    void process() {
+        for (String path : args.files) {
+            ClassPathOpener opener;
+
+            opener = new ClassPathOpener(path, true,
+                    new ClassPathOpener.Consumer() {
+                public boolean processFileBytes(String name, long lastModified, byte[] bytes) {
+                    if (!name.endsWith(".class")) {
+                        return true;
+                    }
+
+                    ByteArray ba = new ByteArray(bytes);
+                    DirectClassFile cf
+                        = new DirectClassFile(ba, name, true);
+
+                    cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
+                    AttributeList attributes = cf.getAttributes();
+                    Attribute att;
+
+                    String cfClassName
+                            = cf.getThisClass().getClassType().getClassName();
+
+                    if (cfClassName.endsWith(PACKAGE_INFO)) {
+                        att = attributes.findFirst(
+                                AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME);
+
+                        for (;att != null; att = attributes.findNext(att)) {
+                            BaseAnnotations ann = (BaseAnnotations)att;
+                            visitPackageAnnotation(cf, ann);
+                        }
+
+                        att = attributes.findFirst(
+                                AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME);
+
+                        for (;att != null; att = attributes.findNext(att)) {
+                            BaseAnnotations ann = (BaseAnnotations)att;
+                            visitPackageAnnotation(cf, ann);
+                        }
+                    } else if (isMatchingInnerClass(cfClassName)
+                            || isMatchingPackage(cfClassName)) {
+                        printMatch(cf);
+                    } else {
+                        att = attributes.findFirst(
+                                AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME);
+
+                        for (;att != null; att = attributes.findNext(att)) {
+                            BaseAnnotations ann = (BaseAnnotations)att;
+                            visitClassAnnotation(cf, ann);
+                        }
+
+                        att = attributes.findFirst(
+                                AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME);
+
+                        for (;att != null; att = attributes.findNext(att)) {
+                            BaseAnnotations ann = (BaseAnnotations)att;
+                            visitClassAnnotation(cf, ann);
+                        }
+                    }
+
+                    return true;
+                }
+
+                public void onException(Exception ex) {
+                    throw new RuntimeException(ex);
+                }
+
+                public void onProcessArchiveStart(File file) {
+
+                }
+
+            });
+
+            opener.process();
+        }
+    }
+
+    /**
+     * Inspects a class annotation.
+     *
+     * @param cf {@code non-null;} class file
+     * @param ann {@code non-null;} annotation
+     */
+    private void visitClassAnnotation(DirectClassFile cf,
+            BaseAnnotations ann) {
+
+        if (!args.eTypes.contains(ElementType.TYPE)) {
+            return;
+        }
+
+        for (Annotation anAnn : ann.getAnnotations().getAnnotations()) {
+            String annClassName
+                    = anAnn.getType().getClassType().getClassName();
+            if (args.aclass.equals(annClassName)) {
+                printMatch(cf);
+            }
+        }
+    }
+
+    /**
+     * Inspects a package 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) {
+
+        if (!args.eTypes.contains(ElementType.PACKAGE)) {
+            return;
+        }
+
+        String packageName = cf.getThisClass().getClassType().getClassName();
+
+        int slashIndex = packageName.lastIndexOf('/');
+
+        if (slashIndex == -1) {
+            packageName = "";
+        } else {
+            packageName
+                    = packageName.substring(0, slashIndex);
+        }
+
+
+        for (Annotation anAnn : ann.getAnnotations().getAnnotations()) {
+            String annClassName
+                    = anAnn.getType().getClassType().getClassName();
+            if (args.aclass.equals(annClassName)) {
+                printMatchPackage(packageName);
+            }
+        }
+    }
+
+
+    /**
+     * Prints, or schedules for printing, elements related to a
+     * matching package.
+     *
+     * @param packageName {@code non-null;} name of package
+     */
+    private void printMatchPackage(String packageName) {
+        for (Main.PrintType pt : args.printTypes) {
+            switch (pt) {
+                case CLASS:
+                case INNERCLASS:
+                case METHOD:
+                    matchPackages.add(packageName);
+                    break;
+                case PACKAGE:
+                    System.out.println(packageName.replace('/','.'));
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Prints, or schedules for printing, elements related to a matching
+     * class.
+     *
+     * @param cf {@code non-null;} matching class
+     */
+    private void printMatch(DirectClassFile cf) {
+        for (Main.PrintType pt : args.printTypes) {
+            switch (pt) {
+                case CLASS:
+                    String classname;
+                    classname =
+                        cf.getThisClass().getClassType().getClassName();
+                    classname = classname.replace('/','.');
+                    System.out.println(classname);
+                    break;
+                case INNERCLASS:
+                    matchInnerClassesOf.add(
+                            cf.getThisClass().getClassType().getClassName());
+                    break;
+                case METHOD:
+                    //TODO
+                    break;
+                case PACKAGE:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Checks to see if a specified class name should be considered a match
+     * due to previous matches.
+     *
+     * @param s {@code non-null;} class name
+     * @return true if this class should be considered a match
+     */
+    private boolean isMatchingInnerClass(String s) {
+        int i;
+
+        while (0 < (i = s.lastIndexOf('$'))) {
+            s = s.substring(0, i);
+            if (matchInnerClassesOf.contains(s)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks to see if a specified package should be considered a match due
+     * to previous matches.
+     *
+     * @param s {@code non-null;} package name
+     * @return true if this package should be considered a match
+     */
+    private boolean isMatchingPackage(String s) {
+        int slashIndex = s.lastIndexOf('/');
+
+        String packageName;
+        if (slashIndex == -1) {
+            packageName = "";
+        } else {
+            packageName
+                    = s.substring(0, slashIndex);
+        }
+
+        return matchPackages.contains(packageName);
+    }
+}
diff --git a/dx/src/com/android/dx/command/annotool/Main.java b/dx/src/com/android/dx/command/annotool/Main.java
new file mode 100644
index 0000000..7661c3d
--- /dev/null
+++ b/dx/src/com/android/dx/command/annotool/Main.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.annotool;
+
+import com.android.dx.cf.direct.ClassPathOpener;
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.direct.StdAttributeFactory;
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.Attribute;
+import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations;
+import com.android.dx.cf.attrib.BaseAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
+import com.android.dx.util.ByteArray;
+import com.android.dx.rop.annotation.Annotation;
+
+import java.io.File;
+import java.lang.annotation.ElementType;
+import java.util.EnumSet;
+import java.util.Arrays;
+
+
+public class Main {
+
+    private static class InvalidArgumentException extends Exception {
+        InvalidArgumentException() {
+            super();
+        }
+
+        InvalidArgumentException(String s) {
+            super(s);
+        }
+    }
+
+    enum PrintType {
+        CLASS,
+        INNERCLASS,
+        METHOD,
+        PACKAGE
+    }
+
+
+    static class Arguments {
+        /**
+         * from --annotation, dot-seperated classname
+         * of annotation to look for
+         */
+        String aclass;
+
+        /** from --eTypes */
+        EnumSet<ElementType> eTypes = EnumSet.noneOf(ElementType.class);
+
+        /** from --print */
+        EnumSet<PrintType> printTypes = EnumSet.noneOf(PrintType.class);
+
+        /** remaining positional arguments */
+        String[] files;
+
+        Arguments() {
+        }
+
+        void parse (String[] argArray) throws InvalidArgumentException {
+            for (int i = 0; i < argArray.length; i++) {
+                String arg = argArray[i];
+
+                if (arg.startsWith("--annotation=")) {
+                    String argParam = arg.substring(arg.indexOf('=') + 1);
+                    if (aclass != null) {
+                        throw new InvalidArgumentException(
+                                "--annotation can only be specified once.");
+                    }
+                    aclass = argParam.replace('.','/');
+                } else if (arg.startsWith("--element=")) {
+                    String argParam = arg.substring(arg.indexOf('=') + 1);
+
+                    try {
+                        for (String p : argParam.split(",")) {
+                            eTypes.add(ElementType.valueOf(p.toUpperCase()));
+                        }
+                    } catch (IllegalArgumentException ex) {
+                        throw new InvalidArgumentException(
+                                "invalid --element");
+                    }
+                } else if (arg.startsWith("--print=")) {
+                    String argParam = arg.substring(arg.indexOf('=') + 1);
+
+                    try {
+                        for (String p : argParam.split(",")) {
+                            printTypes.add(PrintType.valueOf(p.toUpperCase()));
+                        }
+                    } catch (IllegalArgumentException ex) {
+                        throw new InvalidArgumentException("invalid --print");
+                    }
+                } else {
+                    files = new String[argArray.length - i];
+                    System.arraycopy(argArray, i, files, 0, files.length);
+                    break;
+                }
+            }
+
+            if (aclass == null) {
+                throw new InvalidArgumentException(
+                        "--annotation must be specified");
+            }
+
+            if (printTypes.isEmpty()) {
+                printTypes.add(PrintType.CLASS);
+            }
+
+            if (eTypes.isEmpty()) {
+                eTypes.add(ElementType.TYPE);
+            }
+
+            EnumSet<ElementType> set = eTypes.clone();
+
+            set.remove(ElementType.TYPE);
+            set.remove(ElementType.PACKAGE);
+            if (!set.isEmpty()) {
+                throw new InvalidArgumentException(
+                        "only --element parameters 'type' and 'package' "
+                                + "supported");
+            }
+        }
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Main() {
+        // This space intentionally left blank.
+    }
+
+    public static void main(String[] argArray) {
+
+        final Arguments args = new Arguments();
+
+        try {
+            args.parse(argArray);
+        } catch (InvalidArgumentException ex) {
+            System.err.println(ex.getMessage());
+
+            throw new RuntimeException("usage");
+        }
+
+        new AnnotationLister(args).process();
+    }
+}
diff --git a/dx/src/com/android/dx/command/dexer/Main.java b/dx/src/com/android/dx/command/dexer/Main.java
new file mode 100644
index 0000000..d127550
--- /dev/null
+++ b/dx/src/com/android/dx/command/dexer/Main.java
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dexer;
+
+import com.android.dx.Version;
+import com.android.dx.cf.code.SimException;
+import com.android.dx.cf.direct.ClassPathOpener;
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.command.DxConsole;
+import com.android.dx.command.UsageException;
+import com.android.dx.dex.DexFormat;
+import com.android.dx.dex.DexOptions;
+import com.android.dx.dex.cf.CfOptions;
+import com.android.dx.dex.cf.CfTranslator;
+import com.android.dx.dex.cf.CodeStatistics;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.dex.file.ClassDefItem;
+import com.android.dx.dex.file.DexFile;
+import com.android.dx.dex.file.EncodedMethod;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.merge.CollisionPolicy;
+import com.android.dx.merge.DexMerger;
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.FileUtils;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+/**
+ * Main class for the class file translator.
+ */
+public class Main {
+    /**
+     * {@code non-null;} the lengthy message that tries to discourage
+     * people from defining core classes in applications
+     */
+    private static final String IN_RE_CORE_CLASSES =
+        "Ill-advised or mistaken usage of a core class (java.* or javax.*)\n" +
+        "when not building a core library.\n\n" +
+        "This is often due to inadvertently including a core library file\n" +
+        "in your application's project, when using an IDE (such as\n" +
+        "Eclipse). If you are sure you're not intentionally defining a\n" +
+        "core class, then this is the most likely explanation of what's\n" +
+        "going on.\n\n" +
+        "However, you might actually be trying to define a class in a core\n" +
+        "namespace, the source of which you may have taken, for example,\n" +
+        "from a non-Android virtual machine project. This will most\n" +
+        "assuredly not work. At a minimum, it jeopardizes the\n" +
+        "compatibility of your app with future versions of the platform.\n" +
+        "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\n" +
+        "distribution, as opposed to compiling an application -- then use\n" +
+        "the \"--core-library\" option to suppress this error message.\n\n" +
+        "If you go ahead and use \"--core-library\" but are in fact\n" +
+        "building an application, then be forewarned that your application\n" +
+        "will still fail to build or run, at some point. Please be\n" +
+        "prepared for angry customers who find, for example, that your\n" +
+        "application ceases to function once they upgrade their operating\n" +
+        "system. You will be to blame for this problem.\n\n" +
+        "If you are legitimately using some code that happens to be in a\n" +
+        "core package, then the easiest safe alternative you have is to\n" +
+        "repackage that code. That is, move the classes in question into\n" +
+        "your own package namespace. This means that they will never be in\n" +
+        "conflict with core system classes. JarJar is a tool that may help\n" +
+        "you in this endeavor. If you find that you cannot do this, then\n" +
+        "that is an indication that the path you are on will ultimately\n" +
+        "lead to pain, suffering, grief, and lamentation.\n";
+
+    /**
+     * {@code non-null;} name of the standard manifest file in {@code .jar}
+     * files
+     */
+    private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+
+    /**
+     * {@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");
+
+    /**
+     * {@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.
+     */
+    private static final String[] JAVAX_CORE = {
+        "accessibility", "crypto", "imageio", "management", "naming", "net",
+        "print", "rmi", "security", "sip", "sound", "sql", "swing",
+        "transaction", "xml"
+    };
+
+    /** number of warnings during processing */
+    private static int warnings = 0;
+
+    /** number of errors during processing */
+    private static int errors = 0;
+
+    /** {@code non-null;} parsed command-line arguments */
+    private static Arguments args;
+
+    /** {@code non-null;} output file in-progress */
+    private static DexFile outputDex;
+
+    /**
+     * {@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;
+
+    /** Library .dex files to merge into the output .dex. */
+    private static final List<byte[]> libraryDexBuffers = new ArrayList<byte[]>();
+
+    /** thread pool object used for multi-threaded file processing */
+    private static ExecutorService threadPool;
+
+    /** true if any files are successfully processed */
+    private static boolean anyFilesProcessed;
+
+    /** class files older than this must be defined in the target dex file. */
+    private static long minimumFileAge = 0;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Main() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Run and exit if something unexpected happened.
+     * @param argArray the command line arguments
+     */
+    public static void main(String[] argArray) throws IOException {
+        Arguments arguments = new Arguments();
+        arguments.parse(argArray);
+
+        int result = run(arguments);
+        if (result != 0) {
+            System.exit(result);
+        }
+    }
+
+    /**
+     * Run and return a result code.
+     * @param arguments the data + parameters for the conversion
+     * @return 0 if success > 0 otherwise.
+     */
+    public static int run(Arguments arguments) throws IOException {
+        // Reset the error/warning count to start fresh.
+        warnings = 0;
+        errors = 0;
+
+        args = arguments;
+        args.makeOptionsObjects();
+
+        File incrementalOutFile = null;
+        if (args.incremental) {
+            if (args.outName == null) {
+                System.err.println(
+                        "error: no incremental output name specified");
+                return -1;
+            }
+            incrementalOutFile = new File(args.outName);
+            if (incrementalOutFile.exists()) {
+                minimumFileAge = incrementalOutFile.lastModified();
+            }
+        }
+
+        if (!processAllFiles()) {
+            return 1;
+        }
+
+        if (args.incremental && !anyFilesProcessed) {
+            return 0; // this was a no-op incremental build
+        }
+
+        // this array is null if no classes were defined
+        byte[] outArray = null;
+
+        if (!outputDex.isEmpty()) {
+            outArray = writeDex();
+
+            if (outArray == null) {
+                return 2;
+            }
+        }
+
+        if (args.incremental) {
+            outArray = mergeIncremental(outArray, incrementalOutFile);
+        }
+
+        outArray = mergeLibraryDexBuffers(outArray);
+
+        if (args.jarOutput) {
+            // Effectively free up the (often massive) DexFile memory.
+            outputDex = null;
+
+            if (!createJar(args.outName, outArray)) {
+                return 3;
+            }
+        } else if (outArray != null && args.outName != null) {
+            OutputStream out = openOutput(args.outName);
+            out.write(outArray);
+            closeOutput(out);
+        }
+
+        return 0;
+    }
+
+    /**
+     * Merges the dex files {@code update} and {@code base}, preferring
+     * {@code update}'s definition for types defined in both dex files.
+     *
+     * @param base a file to find the previous dex file. May be a .dex file, a
+     *     jar file possibly containing a .dex file, or null.
+     * @return the bytes of the merged dex file, or null if both the update
+     *     and the base dex do not exist.
+     */
+    private static byte[] mergeIncremental(byte[] update, File base) throws IOException {
+        DexBuffer dexA = null;
+        DexBuffer dexB = null;
+
+        if (update != null) {
+            dexA = new DexBuffer(update);
+        }
+
+        if (base.exists()) {
+            dexB = new DexBuffer(base);
+        }
+
+        DexBuffer result;
+        if (dexA == null && dexB == null) {
+            return null;
+        } else if (dexA == null) {
+            result = dexB;
+        } else if (dexB == null) {
+            result = dexA;
+        } else {
+            result = new DexMerger(dexA, dexB, CollisionPolicy.KEEP_FIRST).merge();
+        }
+
+        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+        result.writeTo(bytesOut);
+        return bytesOut.toByteArray();
+    }
+
+    /**
+     * Merges the dex files in library jars. If multiple dex files define the
+     * same type, this fails with an exception.
+     */
+    private static byte[] mergeLibraryDexBuffers(byte[] outArray) throws IOException {
+        for (byte[] libraryDexBuffer : libraryDexBuffers) {
+            if (outArray == null) {
+                outArray = libraryDexBuffer;
+                continue;
+            }
+
+            DexBuffer a = new DexBuffer(outArray);
+            DexBuffer b = new DexBuffer(libraryDexBuffer);
+            DexBuffer ab = new DexMerger(a, b, CollisionPolicy.FAIL).merge();
+            outArray = ab.getBytes();
+        }
+        return outArray;
+    }
+
+    /**
+     * Constructs the output {@link DexFile}, fill it in with all the
+     * specified classes, and populate the resources map if required.
+     *
+     * @return whether processing was successful
+     */
+    private static boolean processAllFiles() {
+        outputDex = new DexFile(args.dexOptions);
+
+        if (args.jarOutput) {
+            outputResources = new TreeMap<String, byte[]>();
+        }
+
+        if (args.dumpWidth != 0) {
+            outputDex.setDumpWidth(args.dumpWidth);
+        }
+
+        anyFilesProcessed = false;
+        String[] fileNames = args.fileNames;
+
+        if (args.numThreads > 1) {
+            threadPool = Executors.newFixedThreadPool(args.numThreads);
+        }
+
+        try {
+            for (int i = 0; i < fileNames.length; i++) {
+                if (processOne(fileNames[i])) {
+                    anyFilesProcessed = true;
+                }
+            }
+        } catch (StopProcessing ex) {
+            /*
+             * Ignore it and just let the warning/error reporting do
+             * their things.
+             */
+        }
+
+        if (args.numThreads > 1) {
+            try {
+                threadPool.shutdown();
+                threadPool.awaitTermination(600L, TimeUnit.SECONDS);
+            } catch (InterruptedException ex) {
+                throw new RuntimeException("Timed out waiting for threads.");
+            }
+        }
+
+        if (warnings != 0) {
+            DxConsole.err.println(warnings + " warning" +
+                               ((warnings == 1) ? "" : "s"));
+        }
+
+        if (errors != 0) {
+            DxConsole.err.println(errors + " error" +
+                    ((errors == 1) ? "" : "s") + "; aborting");
+            return false;
+        }
+
+        if (args.incremental && !anyFilesProcessed) {
+            return true;
+        }
+
+        if (!(anyFilesProcessed || args.emptyOk)) {
+            DxConsole.err.println("no classfiles specified");
+            return false;
+        }
+
+        if (args.optimize && args.statistics) {
+            CodeStatistics.dumpStatistics(DxConsole.out);
+        }
+
+        return true;
+    }
+
+    /**
+     * Processes one pathname element.
+     *
+     * @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) {
+        ClassPathOpener opener;
+
+        opener = new ClassPathOpener(pathname, false,
+                new ClassPathOpener.Consumer() {
+            public boolean processFileBytes(String name, long lastModified, byte[] bytes) {
+                if (args.numThreads > 1) {
+                    threadPool.execute(new ParallelProcessor(name, lastModified, bytes));
+                    return false;
+                } else {
+                    return Main.processFileBytes(name, lastModified, bytes);
+                }
+            }
+            public void onException(Exception ex) {
+                if (ex instanceof StopProcessing) {
+                    throw (StopProcessing) ex;
+                } else if (ex instanceof SimException) {
+                    DxConsole.err.println("\nEXCEPTION FROM SIMULATION:");
+                    DxConsole.err.println(ex.getMessage() + "\n");
+                    DxConsole.err.println(((SimException) ex).getContext());
+                } else {
+                    DxConsole.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
+                    ex.printStackTrace(DxConsole.err);
+                }
+                errors++;
+            }
+            public void onProcessArchiveStart(File file) {
+                if (args.verbose) {
+                    DxConsole.out.println("processing archive " + file +
+                            "...");
+                }
+            }
+        });
+
+        return opener.process();
+    }
+
+    /**
+     * Processes one file, which may be either a class or a resource.
+     *
+     * @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, long lastModified, byte[] bytes) {
+        boolean isClass = name.endsWith(".class");
+        boolean isClassesDex = name.equals(DexFormat.DEX_IN_JAR_NAME);
+        boolean keepResources = (outputResources != null);
+
+        if (!isClass && !isClassesDex && !keepResources) {
+            if (args.verbose) {
+                DxConsole.out.println("ignored resource " + name);
+            }
+            return false;
+        }
+
+        if (args.verbose) {
+            DxConsole.out.println("processing " + name + "...");
+        }
+
+        String fixedName = fixPath(name);
+
+        if (isClass) {
+            if (keepResources && args.keepClassesInJar) {
+                synchronized (outputResources) {
+                    outputResources.put(fixedName, bytes);
+                }
+            }
+            if (lastModified < minimumFileAge) {
+                return true;
+            }
+            return processClass(fixedName, bytes);
+        } else if (isClassesDex) {
+            synchronized (libraryDexBuffers) {
+                libraryDexBuffers.add(bytes);
+            }
+            return true;
+        } else {
+            synchronized (outputResources) {
+                outputResources.put(fixedName, bytes);
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Processes one classfile.
+     *
+     * @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 {@code non-null;} contents of the file
+     * @return whether processing was successful
+     */
+    private static boolean processClass(String name, byte[] bytes) {
+        if (! args.coreLibrary) {
+            checkClassName(name);
+        }
+
+        try {
+            ClassDefItem clazz =
+                CfTranslator.translate(name, bytes, args.cfOptions, args.dexOptions);
+            synchronized (outputDex) {
+                outputDex.add(clazz);
+            }
+            return true;
+        } catch (ParseException ex) {
+            DxConsole.err.println("\ntrouble processing:");
+            if (args.debug) {
+                ex.printStackTrace(DxConsole.err);
+            } else {
+                ex.printContext(DxConsole.err);
+            }
+        }
+
+        warnings++;
+        return false;
+    }
+
+    /**
+     * Check the class name to make sure it's not a "core library"
+     * class. If there is a problem, this updates the error count and
+     * throws an exception to stop processing.
+     *
+     * @param name {@code non-null;} the fully-qualified internal-form
+     * class name
+     */
+    private static void checkClassName(String name) {
+        boolean bogus = false;
+
+        if (name.startsWith("java/")) {
+            bogus = true;
+        } else if (name.startsWith("javax/")) {
+            int slashAt = name.indexOf('/', 6);
+            if (slashAt == -1) {
+                // Top-level javax classes are verboten.
+                bogus = true;
+            } else {
+                String pkg = name.substring(6, slashAt);
+                bogus = (Arrays.binarySearch(JAVAX_CORE, pkg) >= 0);
+            }
+        }
+
+        if (! bogus) {
+            return;
+        }
+
+        /*
+         * The user is probably trying to include an entire desktop
+         * core library in a misguided attempt to get their application
+         * working. Try to help them understand what's happening.
+         */
+
+        DxConsole.err.println("\ntrouble processing \"" + name + "\":\n\n" +
+                IN_RE_CORE_CLASSES);
+        errors++;
+        throw new StopProcessing();
+    }
+
+    /**
+     * Converts {@link #outputDex} into a {@code byte[]} and do whatever
+     * human-oriented dumping is required.
+     *
+     * @return {@code null-ok;} the converted {@code byte[]} or {@code null}
+     * if there was a problem
+     */
+    private static byte[] writeDex() {
+        byte[] outArray = null;
+
+        try {
+            OutputStream humanOutRaw = null;
+            OutputStreamWriter humanOut = null;
+            try {
+                if (args.humanOutName != null) {
+                    humanOutRaw = openOutput(args.humanOutName);
+                    humanOut = new OutputStreamWriter(humanOutRaw);
+                }
+
+                if (args.methodToDump != null) {
+                    /*
+                     * Simply dump the requested method. Note: The call
+                     * to toDex() is required just to get the underlying
+                     * structures ready.
+                     */
+                    outputDex.toDex(null, false);
+                    dumpMethod(outputDex, args.methodToDump, humanOut);
+                } else {
+                    /*
+                     * This is the usual case: Create an output .dex file,
+                     * and write it, dump it, etc.
+                     */
+                    outArray = outputDex.toDex(humanOut, args.verboseDump);
+                }
+
+                if (args.statistics) {
+                    DxConsole.out.println(outputDex.getStatistics().toHuman());
+                }
+            } finally {
+                if (humanOut != null) {
+                    humanOut.flush();
+                }
+                closeOutput(humanOutRaw);
+            }
+        } catch (Exception ex) {
+            if (args.debug) {
+                DxConsole.err.println("\ntrouble writing output:");
+                ex.printStackTrace(DxConsole.err);
+            } else {
+                DxConsole.err.println("\ntrouble writing output: " +
+                                   ex.getMessage());
+            }
+            return null;
+        }
+
+        return outArray;
+    }
+
+    /**
+     * Creates a jar file from the resources and given dex file array.
+     *
+     * @param fileName {@code non-null;} name of the file
+     * @param dexArray array containing the dex file to include, or null if the
+     *     output contains no class defs.
+     * @return whether the creation was successful
+     */
+    private static boolean createJar(String fileName, byte[] dexArray) {
+        /*
+         * Make or modify the manifest (as appropriate), put the dex
+         * array into the resources map, and then process the entire
+         * resources map in a uniform manner.
+         */
+
+        try {
+            Manifest manifest = makeManifest();
+            OutputStream out = openOutput(fileName);
+            JarOutputStream jarOut = new JarOutputStream(out, manifest);
+
+            if (dexArray != null) {
+                outputResources.put(DexFormat.DEX_IN_JAR_NAME, dexArray);
+            }
+
+            try {
+                for (Map.Entry<String, byte[]> e :
+                         outputResources.entrySet()) {
+                    String name = e.getKey();
+                    byte[] contents = e.getValue();
+                    JarEntry entry = new JarEntry(name);
+
+                    if (args.verbose) {
+                        DxConsole.out.println("writing " + name + "; size " +
+                                           contents.length + "...");
+                    }
+
+                    entry.setSize(contents.length);
+                    jarOut.putNextEntry(entry);
+                    jarOut.write(contents);
+                    jarOut.closeEntry();
+                }
+            } finally {
+                jarOut.finish();
+                jarOut.flush();
+                closeOutput(out);
+            }
+        } catch (Exception ex) {
+            if (args.debug) {
+                DxConsole.err.println("\ntrouble writing output:");
+                ex.printStackTrace(DxConsole.err);
+            } else {
+                DxConsole.err.println("\ntrouble writing output: " +
+                                   ex.getMessage());
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Creates and returns the manifest to use for the output. This may
+     * modify {@link #outputResources} (removing the pre-existing manifest).
+     *
+     * @return {@code non-null;} the manifest
+     */
+    private static Manifest makeManifest() throws IOException {
+        byte[] manifestBytes = outputResources.get(MANIFEST_NAME);
+        Manifest manifest;
+        Attributes attribs;
+
+        if (manifestBytes == null) {
+            // We need to construct an entirely new manifest.
+            manifest = new Manifest();
+            attribs = manifest.getMainAttributes();
+            attribs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        } else {
+            manifest = new Manifest(new ByteArrayInputStream(manifestBytes));
+            attribs = manifest.getMainAttributes();
+            outputResources.remove(MANIFEST_NAME);
+        }
+
+        String createdBy = attribs.getValue(CREATED_BY);
+        if (createdBy == null) {
+            createdBy = "";
+        } else {
+            createdBy += " + ";
+        }
+        createdBy += "dx " + Version.VERSION;
+
+        attribs.put(CREATED_BY, createdBy);
+        attribs.putValue("Dex-Location", DexFormat.DEX_IN_JAR_NAME);
+
+        return manifest;
+    }
+
+    /**
+     * Opens and returns the named file for writing, treating "-" specially.
+     *
+     * @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("-") ||
+                name.startsWith("-.")) {
+            return System.out;
+        }
+
+        return new FileOutputStream(name);
+    }
+
+    /**
+     * 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} argument.
+     *
+     * @param stream {@code null-ok;} what to close
+     */
+    private static void closeOutput(OutputStream stream) throws IOException {
+        if (stream == null) {
+            return;
+        }
+
+        stream.flush();
+
+        if (stream != System.out) {
+            stream.close();
+        }
+    }
+
+    /**
+     * Returns the "fixed" version of a given file path, suitable for
+     * 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 "/./"} 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 "./"}, then that prefix is removed and the rest is
+     * return. If neither of these is the case, this method returns
+     * its argument.
+     *
+     * @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) {
+        /*
+         * If the path separator is \ (like on windows), we convert the
+         * path to a standard '/' separated path.
+         */
+        if (File.separatorChar == '\\') {
+            path = path.replace('\\', '/');
+        }
+
+        int index = path.lastIndexOf("/./");
+
+        if (index != -1) {
+            return path.substring(index + 3);
+        }
+
+        if (path.startsWith("./")) {
+            return path.substring(2);
+        }
+
+        return path;
+    }
+
+    /**
+     * Dumps any method with the given name in the given file.
+     *
+     * @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) {
+        boolean wildcard = fqName.endsWith("*");
+        int lastDot = fqName.lastIndexOf('.');
+
+        if ((lastDot <= 0) || (lastDot == (fqName.length() - 1))) {
+            DxConsole.err.println("bogus fully-qualified method name: " +
+                               fqName);
+            return;
+        }
+
+        String className = fqName.substring(0, lastDot).replace('.', '/');
+        String methodName = fqName.substring(lastDot + 1);
+        ClassDefItem clazz = dex.getClassOrNull(className);
+
+        if (clazz == null) {
+            DxConsole.err.println("no such class: " + className);
+            return;
+        }
+
+        if (wildcard) {
+            methodName = methodName.substring(0, methodName.length() - 1);
+        }
+
+        ArrayList<EncodedMethod> allMeths = clazz.getMethods();
+        TreeMap<CstNat, EncodedMethod> meths =
+            new TreeMap<CstNat, EncodedMethod>();
+
+        /*
+         * Figure out which methods to include in the output, and get them
+         * all sorted, so that the printout code is robust with respect to
+         * changes in the underlying order.
+         */
+        for (EncodedMethod meth : allMeths) {
+            String methName = meth.getName().getString();
+            if ((wildcard && methName.startsWith(methodName)) ||
+                (!wildcard && methName.equals(methodName))) {
+                meths.put(meth.getRef().getNat(), meth);
+            }
+        }
+
+        if (meths.size() == 0) {
+            DxConsole.err.println("no such method: " + fqName);
+            return;
+        }
+
+        PrintWriter pw = new PrintWriter(out);
+
+        for (EncodedMethod meth : meths.values()) {
+            // TODO: Better stuff goes here, perhaps.
+            meth.debugPrint(pw, args.verboseDump);
+
+            /*
+             * The (default) source file is an attribute of the class, but
+             * it's useful to see it in method dumps.
+             */
+            CstString sourceFile = clazz.getSourceFile();
+            if (sourceFile != null) {
+                pw.println("  source file: " + sourceFile.toQuoted());
+            }
+
+            Annotations methodAnnotations =
+                clazz.getMethodAnnotations(meth.getRef());
+            AnnotationsList parameterAnnotations =
+                clazz.getParameterAnnotations(meth.getRef());
+
+            if (methodAnnotations != null) {
+                pw.println("  method annotations:");
+                for (Annotation a : methodAnnotations.getAnnotations()) {
+                    pw.println("    " + a);
+                }
+            }
+
+            if (parameterAnnotations != null) {
+                pw.println("  parameter annotations:");
+                int sz = parameterAnnotations.size();
+                for (int i = 0; i < sz; i++) {
+                    pw.println("    parameter " + i);
+                    Annotations annotations = parameterAnnotations.get(i);
+                    for (Annotation a : annotations.getAnnotations()) {
+                        pw.println("      " + a);
+                    }
+                }
+            }
+        }
+
+        pw.flush();
+    }
+
+    /**
+     * Exception class used to halt processing prematurely.
+     */
+    private static class StopProcessing extends RuntimeException {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Command-line argument parser and access.
+     */
+    public static class Arguments {
+        /** whether to run in debug mode */
+        public boolean debug = false;
+
+        /** whether to emit high-level verbose human-oriented output */
+        public boolean verbose = false;
+
+        /** whether to emit verbose human-oriented output in the dump file */
+        public boolean verboseDump = false;
+
+        /** whether we are constructing a core library */
+        public boolean coreLibrary = false;
+
+        /** {@code null-ok;} particular method to dump */
+        public String methodToDump = null;
+
+        /** max width for columnar output */
+        public int dumpWidth = 0;
+
+        /** {@code null-ok;} output file name for binary file */
+        public String outName = null;
+
+        /** {@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} files
+         * to process
+         */
+        public boolean emptyOk = false;
+
+        /**
+         * 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} file, whether to still
+         * keep the {@code .class} files
+         */
+        public boolean keepClassesInJar = false;
+
+        /** what API level to target */
+        public int targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
+
+        /** how much source position info to preserve */
+        public int positionInfo = PositionList.LINES;
+
+        /** whether to keep local variable information */
+        public boolean localInfo = true;
+
+        /** whether to merge with the output dex file if it exists. */
+        public boolean incremental = false;
+
+        /** {@code non-null} after {@link #parse}; file name arguments */
+        public String[] fileNames;
+
+        /** whether to do SSA/register optimization */
+        public boolean optimize = true;
+
+        /** Filename containg list of methods to optimize */
+        public String optimizeListFile = null;
+
+        /** Filename containing list of methods to NOT optimize */
+        public String dontOptimizeListFile = null;
+
+        /** Whether to print statistics to stdout at end of compile cycle */
+        public boolean statistics;
+
+        /** Options for class file transformation */
+        public CfOptions cfOptions;
+
+        /** Options for dex file output */
+        public DexOptions dexOptions;
+
+        /** number of threads to run with */
+        public int numThreads = 1;
+
+        private static class ArgumentsParser {
+
+            /** The arguments to process. */
+            private final String[] arguments;
+            /** The index of the next argument to process. */
+            private int index;
+            /** The current argument being processed after a {@link #getNext()} call. */
+            private String current;
+            /** The last value of an argument processed by {@link #isArg(String)}. */
+            private String lastValue;
+
+            public ArgumentsParser(String[] arguments) {
+                this.arguments = arguments;
+                index = 0;
+            }
+
+            public String getCurrent() {
+                return current;
+            }
+
+            public String getLastValue() {
+                return lastValue;
+            }
+
+            /**
+             * Moves on to the next argument.
+             * Returns false when we ran out of arguments that start with --.
+             */
+            public boolean getNext() {
+                if (index >= arguments.length) {
+                    return false;
+                }
+                current = arguments[index];
+                if (current.equals("--") || !current.startsWith("--")) {
+                    return false;
+                }
+                index++;
+                return true;
+            }
+
+            /**
+             * Similar to {@link #getNext()}, this moves on the to next argument.
+             * It does not check however whether the argument starts with --
+             * and thus can be used to retrieve values.
+             */
+            private boolean getNextValue() {
+                if (index >= arguments.length) {
+                    return false;
+                }
+                current = arguments[index];
+                index++;
+                return true;
+            }
+
+            /**
+             * Returns all the arguments that have not been processed yet.
+             */
+            public String[] getRemaining() {
+                int n = arguments.length - index;
+                String[] remaining = new String[n];
+                if (n > 0) {
+                    System.arraycopy(arguments, index, remaining, 0, n);
+                }
+                return remaining;
+            }
+
+            /**
+             * Checks the current argument against the given prefix.
+             * If prefix is in the form '--name=', an extra value is expected.
+             * The argument can then be in the form '--name=value' or as a 2-argument
+             * form '--name value'.
+             */
+            public boolean isArg(String prefix) {
+                int n = prefix.length();
+                if (n > 0 && prefix.charAt(n-1) == '=') {
+                    // Argument accepts a value. Capture it.
+                    if (current.startsWith(prefix)) {
+                        // Argument is in the form --name=value, split the value out
+                        lastValue = current.substring(n);
+                        return true;
+                    } else {
+                        // Check whether we have "--name value" as 2 arguments
+                        prefix = prefix.substring(0, n-1);
+                        if (current.equals(prefix)) {
+                            if (getNextValue()) {
+                                lastValue = current;
+                                return true;
+                            } else {
+                                System.err.println("Missing value after parameter " + prefix);
+                                throw new UsageException();
+                            }
+                        }
+                        return false;
+                    }
+                } else {
+                    // Argument does not accept a value.
+                    return current.equals(prefix);
+                }
+            }
+        }
+
+        /**
+         * Parses the given command-line arguments.
+         *
+         * @param args {@code non-null;} the arguments
+         */
+        public void parse(String[] args) {
+            ArgumentsParser parser = new ArgumentsParser(args);
+
+            while(parser.getNext()) {
+                if (parser.isArg("--debug")) {
+                    debug = true;
+                } else if (parser.isArg("--verbose")) {
+                    verbose = true;
+                } else if (parser.isArg("--verbose-dump")) {
+                    verboseDump = true;
+                } else if (parser.isArg("--no-files")) {
+                    emptyOk = true;
+                } else if (parser.isArg("--no-optimize")) {
+                    optimize = false;
+                } else if (parser.isArg("--no-strict")) {
+                    strictNameCheck = false;
+                } else if (parser.isArg("--core-library")) {
+                    coreLibrary = true;
+                } else if (parser.isArg("--statistics")) {
+                    statistics = true;
+                } else if (parser.isArg("--optimize-list=")) {
+                    if (dontOptimizeListFile != null) {
+                        System.err.println("--optimize-list and "
+                                + "--no-optimize-list are incompatible.");
+                        throw new UsageException();
+                    }
+                    optimize = true;
+                    optimizeListFile = parser.getLastValue();
+                } else if (parser.isArg("--no-optimize-list=")) {
+                    if (dontOptimizeListFile != null) {
+                        System.err.println("--optimize-list and "
+                                + "--no-optimize-list are incompatible.");
+                        throw new UsageException();
+                    }
+                    optimize = true;
+                    dontOptimizeListFile = parser.getLastValue();
+                } else if (parser.isArg("--keep-classes")) {
+                    keepClassesInJar = true;
+                } else if (parser.isArg("--output=")) {
+                    outName = parser.getLastValue();
+                    if (FileUtils.hasArchiveSuffix(outName)) {
+                        jarOutput = true;
+                    } else if (outName.endsWith(".dex") ||
+                               outName.equals("-")) {
+                        jarOutput = false;
+                    } else {
+                        System.err.println("unknown output extension: " +
+                                           outName);
+                        throw new UsageException();
+                    }
+                } else if (parser.isArg("--dump-to=")) {
+                    humanOutName = parser.getLastValue();
+                } else if (parser.isArg("--dump-width=")) {
+                    dumpWidth = Integer.parseInt(parser.getLastValue());
+                } else if (parser.isArg("--dump-method=")) {
+                    methodToDump = parser.getLastValue();
+                    jarOutput = false;
+                } else if (parser.isArg("--positions=")) {
+                    String pstr = parser.getLastValue().intern();
+                    if (pstr == "none") {
+                        positionInfo = PositionList.NONE;
+                    } else if (pstr == "important") {
+                        positionInfo = PositionList.IMPORTANT;
+                    } else if (pstr == "lines") {
+                        positionInfo = PositionList.LINES;
+                    } else {
+                        System.err.println("unknown positions option: " +
+                                           pstr);
+                        throw new UsageException();
+                    }
+                } else if (parser.isArg("--no-locals")) {
+                    localInfo = false;
+                } else if (parser.isArg("--num-threads=")) {
+                    numThreads = Integer.parseInt(parser.getLastValue());
+                } else if (parser.isArg("--incremental")) {
+                    incremental = true;
+                } else {
+                    System.err.println("unknown option: " + parser.getCurrent());
+                    throw new UsageException();
+                }
+            }
+
+            fileNames = parser.getRemaining();
+            if (fileNames.length == 0) {
+                if (!emptyOk) {
+                    System.err.println("no input files specified");
+                    throw new UsageException();
+                }
+            } else if (emptyOk) {
+                System.out.println("ignoring input files");
+            }
+
+            if ((humanOutName == null) && (methodToDump != null)) {
+                humanOutName = "-";
+            }
+
+            makeOptionsObjects();
+        }
+
+        /**
+         * Copies relevent arguments over into CfOptions and
+         * DexOptions instances.
+         */
+        private void makeOptionsObjects() {
+            cfOptions = new CfOptions();
+            cfOptions.positionInfo = positionInfo;
+            cfOptions.localInfo = localInfo;
+            cfOptions.strictNameCheck = strictNameCheck;
+            cfOptions.optimize = optimize;
+            cfOptions.optimizeListFile = optimizeListFile;
+            cfOptions.dontOptimizeListFile = dontOptimizeListFile;
+            cfOptions.statistics = statistics;
+            cfOptions.warn = DxConsole.err;
+
+            dexOptions = new DexOptions();
+            dexOptions.targetApiLevel = targetApiLevel;
+        }
+    }
+
+    /** Runnable helper class to process files in multiple threads */
+    private static class ParallelProcessor implements Runnable {
+
+        String path;
+        long lastModified;
+        byte[] bytes;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param path {@code non-null;} filename of element. May not be a valid
+         * filesystem path.
+         * @param bytes {@code non-null;} file data
+         */
+        private ParallelProcessor(String path, long lastModified, byte bytes[]) {
+            this.path = path;
+            this.lastModified = lastModified;
+            this.bytes = bytes;
+        }
+
+        /**
+         * Task run by each thread in the thread pool. Runs processFileBytes
+         * with the given path and bytes.
+         */
+        public void run() {
+            if (Main.processFileBytes(path, lastModified, bytes)) {
+                anyFilesProcessed = true;
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/command/dump/Args.java b/dx/src/com/android/dx/command/dump/Args.java
new file mode 100644
index 0000000..042fae2
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/Args.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+/**
+ * contains command line parsedArgs values
+ */
+class Args {
+    /** whether to run in debug mode */
+    boolean debug = false;
+
+    /** whether to dump raw bytes where salient */
+    boolean rawBytes = false;
+
+    /** whether to dump information about basic blocks */
+    boolean basicBlocks = false;
+
+    /** whether to dump regiserized blocks */
+    boolean ropBlocks = false;
+
+    /** whether to dump SSA-form blocks */
+    boolean ssaBlocks = false;
+
+    /** Step in SSA processing to stop at, or null for all */
+    String ssaStep = null;
+
+    /** whether to run SSA optimizations */
+    boolean optimize = false;
+
+    /** whether to be strict about parsing classfiles*/
+    boolean strictParse = false;
+
+    /** max width for columnar output */
+    int width = 0;
+
+    /** whether to dump flow-graph in "dot" format */
+    boolean dotDump = false;
+
+    /** if non-null, an explicit method to dump */
+    String method;
+
+}
diff --git a/dx/src/com/android/dx/command/dump/BaseDumper.java b/dx/src/com/android/dx/command/dump/BaseDumper.java
new file mode 100644
index 0000000..ad6540b
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/BaseDumper.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+import com.android.dx.cf.code.ConcreteMethod;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IndentingWriter;
+import com.android.dx.util.TwoColumnOutput;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.StringWriter;
+
+/**
+ * Base class for the various human-friendly dumpers.
+ */
+public abstract class BaseDumper
+        implements ParseObserver {
+    /** {@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;
+
+    /** {@code non-null;} where to dump to */
+    private final PrintStream out;
+
+    /** width of the output in columns */
+    private final int width;
+
+    /**
+     * {@code non-null;} the file path for the class, excluding any base
+     * directory specification
+     */
+    private final String filePath;
+
+    /** whether to be strict about parsing */
+    private final boolean strictParse;
+
+     /** number of bytes per line in hex dumps */
+    private final int hexCols;
+
+    /** the current level of indentation */
+    private int indent;
+
+    /** {@code non-null;} the current column separator string */
+    private String separator;
+
+    /** the offset of the next byte to dump */
+    private int at;
+
+    /** commandline parsedArgs */
+    protected Args args;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bytes {@code non-null;} bytes of the (alleged) class file
+     * on the left)
+     * @param out {@code non-null;} where to dump to
+     * @param filePath the file path for the class, excluding any base
+     * directory specification
+     */
+    public BaseDumper(byte[] bytes, PrintStream out,
+                      String filePath, Args args) {
+        this.bytes = bytes;
+        this.rawBytes = args.rawBytes;
+        this.out = out;
+        this.width = (args.width <= 0) ? 79 : args.width;
+        this.filePath = filePath;
+        this.strictParse = args.strictParse;
+        this.indent = 0;
+        this.separator = rawBytes ? "|" : "";
+        this.at = 0;
+        this.args = args;
+
+        int hexCols = (((width - 5) / 15) + 1) & ~1;
+        if (hexCols < 6) {
+            hexCols = 6;
+        } else if (hexCols > 10) {
+            hexCols = 10;
+        }
+        this.hexCols = hexCols;
+    }
+
+    /**
+     * Computes the total width, in register-units, of the parameters for
+     * this method.
+     * @param meth method to process
+     * @return width in register-units
+     */
+    static int computeParamWidth(ConcreteMethod meth, boolean isStatic) {
+        return meth.getEffectiveDescriptor().getParameterTypes().
+            getWordCount();
+    }
+
+    /** {@inheritDoc} */
+    public void changeIndent(int indentDelta) {
+        indent += indentDelta;
+
+        separator = rawBytes ? "|" : "";
+        for (int i = 0; i < indent; i++) {
+            separator += "  ";
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void parsed(ByteArray bytes, int offset, int len, String human) {
+        offset = bytes.underlyingOffset(offset, getBytes());
+
+        boolean rawBytes = getRawBytes();
+
+        if (offset < at) {
+            println("<dump skipped backwards to " + Hex.u4(offset) + ">");
+            at = offset;
+        } else if (offset > at) {
+            String hex = rawBytes ? hexDump(at, offset - at) : "";
+            print(twoColumns(hex, "<skipped to " + Hex.u4(offset) + ">"));
+            at = offset;
+        }
+
+        String hex = rawBytes ? hexDump(offset, len) : "";
+        print(twoColumns(hex, human));
+        at += len;
+    }
+
+    /** {@inheritDoc} */
+    public void startParsingMember(ByteArray bytes, int offset, String name,
+                                   String descriptor) {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    public void endParsingMember(ByteArray bytes, int offset, String name,
+                                 String descriptor, Member member) {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the current dump cursor (that is, the offset of the expected
+     * next byte to dump).
+     *
+     * @return {@code >= 0;} the dump cursor
+     */
+    protected final int getAt() {
+        return at;
+    }
+
+    /**
+     * Sets the dump cursor to the indicated offset in the given array.
+     *
+     * @param arr {@code non-null;} array in question
+     * @param offset {@code >= 0;} offset into the array
+     */
+    protected final void setAt(ByteArray arr, int offset) {
+        at = arr.underlyingOffset(offset, bytes);
+    }
+
+    /**
+     * Gets the array of {@code byte}s to process.
+     *
+     * @return {@code non-null;} the bytes
+     */
+    protected final byte[] getBytes() {
+        return bytes;
+    }
+
+    /**
+     * Gets the filesystem/jar path of the file being dumped.
+     *
+     * @return {@code non-null;} the path
+     */
+    protected final String getFilePath() {
+        return filePath;
+    }
+
+    /**
+     * Gets whether to be strict about parsing.
+     *
+     * @return whether to be strict about parsing
+     */
+    protected final boolean getStrictParse() {
+        return strictParse;
+    }
+
+    /**
+     * Prints the given string to this instance's output stream.
+     *
+     * @param s {@code null-ok;} string to print
+     */
+    protected final void print(String s) {
+        out.print(s);
+    }
+
+    /**
+     * Prints the given string to this instance's output stream, followed
+     * by a newline.
+     *
+     * @param s {@code null-ok;} string to print
+     */
+    protected final void println(String s) {
+        out.println(s);
+    }
+
+    /**
+     * Gets whether this dump is to include raw bytes.
+     *
+     * @return the raw bytes flag
+     */
+    protected final boolean getRawBytes() {
+        return rawBytes;
+    }
+
+    /**
+     * Gets the width of the first column of output. This is {@code 0}
+     * unless raw bytes are being included in the output.
+     *
+     * @return {@code >= 0;} the width of the first column
+     */
+    protected final int getWidth1() {
+        if (rawBytes) {
+            return 5 + (hexCols * 2) + (hexCols / 2);
+        }
+
+        return 0;
+    }
+
+    /**
+     * Gets the width of the second column of output.
+     *
+     * @return {@code >= 0;} the width of the second column
+     */
+    protected final int getWidth2() {
+        int w1 = rawBytes ? (getWidth1() + 1) : 0;
+        return width - w1 - (indent * 2);
+    }
+
+    /**
+     * Constructs a hex data dump of the given portion of {@link #bytes}.
+     *
+     * @param offset offset to start dumping at
+     * @param len length to dump
+     * @return {@code non-null;} the dump
+     */
+    protected final String hexDump(int offset, int len) {
+        return Hex.dump(bytes, offset, len, offset, hexCols, 4);
+    }
+
+    /**
+     * Combines a pair of strings as two columns, or if this is one-column
+     * output, format the otherwise-second column.
+     *
+     * @param s1 {@code non-null;} the first column's string
+     * @param s2 {@code non-null;} the second column's string
+     * @return {@code non-null;} the combined output
+     */
+    protected final String twoColumns(String s1, String s2) {
+        int w1 = getWidth1();
+        int w2 = getWidth2();
+
+        try {
+            if (w1 == 0) {
+                int len2 = s2.length();
+                StringWriter sw = new StringWriter(len2 * 2);
+                IndentingWriter iw = new IndentingWriter(sw, w2, separator);
+
+                iw.write(s2);
+                if ((len2 == 0) || (s2.charAt(len2 - 1) != '\n')) {
+                    iw.write('\n');
+                }
+                iw.flush();
+
+                return sw.toString();
+            } else {
+                return TwoColumnOutput.toString(s1, w1, separator, s2, w2);
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/command/dump/BlockDumper.java b/dx/src/com/android/dx/command/dump/BlockDumper.java
new file mode 100644
index 0000000..6919b09
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/BlockDumper.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+import com.android.dx.cf.attrib.AttCode;
+import com.android.dx.cf.code.BasicBlocker;
+import com.android.dx.cf.code.ByteBlock;
+import com.android.dx.cf.code.ByteBlockList;
+import com.android.dx.cf.code.ByteCatchList;
+import com.android.dx.cf.code.BytecodeArray;
+import com.android.dx.cf.code.ConcreteMethod;
+import com.android.dx.cf.code.Ropper;
+import com.android.dx.cf.direct.CodeObserver;
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.direct.StdAttributeFactory;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.Method;
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.InsnList;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.DexTranslationAdvice;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.ssa.Optimizer;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+import java.io.PrintStream;
+
+/**
+ * Utility to dump basic block info from methods in a human-friendly form.
+ */
+public class BlockDumper
+        extends BaseDumper {
+    /** whether or not to registerize (make rop blocks) */
+    private boolean rop;
+
+    /**
+     * {@code null-ok;} the class file object being constructed;
+     * becomes non-null during {@link #dump}
+     */
+    protected DirectClassFile classFile;
+
+    /** whether or not to suppress dumping */
+    protected boolean suppressDump;
+
+    /** whether this is the first method being dumped */
+    private boolean first;
+
+    /** whether or not to run the ssa optimziations */
+    private boolean optimize;
+
+    /**
+     * Dumps the given array, interpreting it as a class file and dumping
+     * methods with indications of block-level stuff.
+     *
+     * @param bytes {@code non-null;} bytes of the (alleged) class file
+     * @param out {@code non-null;} where to dump to
+     * @param filePath the file path for the class, excluding any base
+     * directory specification
+     * @param rop whether or not to registerize (make rop blocks)
+     * @param args commandline parsedArgs
+     */
+    public static void dump(byte[] bytes, PrintStream out,
+            String filePath, boolean rop, Args args) {
+        BlockDumper bd = new BlockDumper(bytes, out, filePath,
+                rop, args);
+        bd.dump();
+    }
+
+    /**
+     * Constructs an instance. This class is not publicly instantiable.
+     * Use {@link #dump}.
+     */
+    BlockDumper(byte[] bytes, PrintStream out, String filePath,
+            boolean rop, Args args) {
+        super(bytes, out, filePath, args);
+
+        this.rop = rop;
+        this.classFile = null;
+        this.suppressDump = true;
+        this.first = true;
+        this.optimize = args.optimize;
+    }
+
+    /**
+     * Does the dumping.
+     */
+    public void dump() {
+        byte[] bytes = getBytes();
+        ByteArray ba = new ByteArray(bytes);
+
+        /*
+         * First, parse the file completely, so we can safely refer to
+         * attributes, etc.
+         */
+        classFile = new DirectClassFile(ba, getFilePath(), getStrictParse());
+        classFile.setAttributeFactory(StdAttributeFactory.THE_ONE);
+        classFile.getMagic(); // Force parsing to happen.
+
+        // Next, reparse it and observe the process.
+        DirectClassFile liveCf =
+            new DirectClassFile(ba, getFilePath(), getStrictParse());
+        liveCf.setAttributeFactory(StdAttributeFactory.THE_ONE);
+        liveCf.setObserver(this);
+        liveCf.getMagic(); // Force parsing to happen.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void changeIndent(int indentDelta) {
+        if (!suppressDump) {
+            super.changeIndent(indentDelta);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void parsed(ByteArray bytes, int offset, int len, String human) {
+        if (!suppressDump) {
+            super.parsed(bytes, offset, len, human);
+        }
+    }
+
+    /**
+     * @param name method name
+     * @return true if this method should be dumped
+     */
+    protected boolean shouldDumpMethod(String name) {
+        return args.method == null || args.method.equals(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void startParsingMember(ByteArray bytes, int offset, String name,
+            String descriptor) {
+        if (descriptor.indexOf('(') < 0) {
+            // It's a field, not a method
+            return;
+        }
+
+        if (!shouldDumpMethod(name)) {
+            return;
+        }
+
+        // Reset the dump cursor to the start of the method.
+        setAt(bytes, offset);
+
+        suppressDump = false;
+
+        if (first) {
+            first = false;
+        } else {
+            parsed(bytes, offset, 0, "\n");
+        }
+
+        parsed(bytes, offset, 0, "method " + name + " " + descriptor);
+        suppressDump = true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void endParsingMember(ByteArray bytes, int offset, String name,
+            String descriptor, Member member) {
+        if (!(member instanceof Method)) {
+            return;
+        }
+
+        if (!shouldDumpMethod(name)) {
+            return;
+        }
+
+        if ((member.getAccessFlags() & (AccessFlags.ACC_ABSTRACT |
+                AccessFlags.ACC_NATIVE)) != 0) {
+            return;
+        }
+
+        ConcreteMethod meth =
+            new ConcreteMethod((Method) member, classFile, true, true);
+
+        if (rop) {
+            ropDump(meth);
+        } else {
+            regularDump(meth);
+        }
+    }
+
+    /**
+     * Does a regular basic block dump.
+     *
+     * @param meth {@code non-null;} method data to dump
+     */
+    private void regularDump(ConcreteMethod meth) {
+        BytecodeArray code = meth.getCode();
+        ByteArray bytes = code.getBytes();
+        ByteBlockList list = BasicBlocker.identifyBlocks(meth);
+        int sz = list.size();
+        CodeObserver codeObserver = new CodeObserver(bytes, BlockDumper.this);
+
+        // Reset the dump cursor to the start of the bytecode.
+        setAt(bytes, 0);
+
+        suppressDump = false;
+
+        int byteAt = 0;
+        for (int i = 0; i < sz; i++) {
+            ByteBlock bb = list.get(i);
+            int start = bb.getStart();
+            int end = bb.getEnd();
+
+            if (byteAt < start) {
+                parsed(bytes, byteAt, start - byteAt,
+                       "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(start));
+            }
+
+            parsed(bytes, start, 0,
+                    "block " + Hex.u2(bb.getLabel()) + ": " +
+                    Hex.u2(start) + ".." + Hex.u2(end));
+            changeIndent(1);
+
+            int len;
+            for (int j = start; j < end; j += len) {
+                len = code.parseInstruction(j, codeObserver);
+                codeObserver.setPreviousOffset(j);
+            }
+
+            IntList successors = bb.getSuccessors();
+            int ssz = successors.size();
+            if (ssz == 0) {
+                parsed(bytes, end, 0, "returns");
+            } else {
+                for (int j = 0; j < ssz; j++) {
+                    int succ = successors.get(j);
+                    parsed(bytes, end, 0, "next " + Hex.u2(succ));
+                }
+            }
+
+            ByteCatchList catches = bb.getCatches();
+            int csz = catches.size();
+            for (int j = 0; j < csz; j++) {
+                ByteCatchList.Item one = catches.get(j);
+                CstType exceptionClass = one.getExceptionClass();
+                parsed(bytes, end, 0,
+                       "catch " +
+                       ((exceptionClass == CstType.OBJECT) ? "<any>" :
+                        exceptionClass.toHuman()) + " -> " +
+                       Hex.u2(one.getHandlerPc()));
+            }
+
+            changeIndent(-1);
+            byteAt = end;
+        }
+
+        int end = bytes.size();
+        if (byteAt < end) {
+            parsed(bytes, byteAt, end - byteAt,
+                    "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(end));
+        }
+
+        suppressDump = true;
+    }
+
+    /**
+     * Does a registerizing dump.
+     *
+     * @param meth {@code non-null;} method data to dump
+     */
+    private void ropDump(ConcreteMethod meth) {
+        TranslationAdvice advice = DexTranslationAdvice.THE_ONE;
+        BytecodeArray code = meth.getCode();
+        ByteArray bytes = code.getBytes();
+        RopMethod rmeth = Ropper.convert(meth, advice);
+        StringBuffer sb = new StringBuffer(2000);
+
+        if (optimize) {
+            boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());
+            int paramWidth = computeParamWidth(meth, isStatic);
+            rmeth =
+                Optimizer.optimize(rmeth, paramWidth, isStatic, true, advice);
+        }
+
+        BasicBlockList blocks = rmeth.getBlocks();
+        int[] order = blocks.getLabelsInOrder();
+
+        sb.append("first " + Hex.u2(rmeth.getFirstLabel()) + "\n");
+
+        for (int label : order) {
+            BasicBlock bb = blocks.get(blocks.indexOfLabel(label));
+            sb.append("block ");
+            sb.append(Hex.u2(label));
+            sb.append("\n");
+
+            IntList preds = rmeth.labelToPredecessors(label);
+            int psz = preds.size();
+            for (int i = 0; i < psz; i++) {
+                sb.append("  pred ");
+                sb.append(Hex.u2(preds.get(i)));
+                sb.append("\n");
+            }
+
+            InsnList il = bb.getInsns();
+            int ilsz = il.size();
+            for (int i = 0; i < ilsz; i++) {
+                Insn one = il.get(i);
+                sb.append("  ");
+                sb.append(il.get(i).toHuman());
+                sb.append("\n");
+            }
+
+            IntList successors = bb.getSuccessors();
+            int ssz = successors.size();
+            if (ssz == 0) {
+                sb.append("  returns\n");
+            } else {
+                int primary = bb.getPrimarySuccessor();
+                for (int i = 0; i < ssz; i++) {
+                    int succ = successors.get(i);
+                    sb.append("  next ");
+                    sb.append(Hex.u2(succ));
+
+                    if ((ssz != 1) && (succ == primary)) {
+                        sb.append(" *");
+                    }
+
+                    sb.append("\n");
+                }
+            }
+        }
+
+        suppressDump = false;
+        setAt(bytes, 0);
+        parsed(bytes, 0, bytes.size(), sb.toString());
+        suppressDump = true;
+    }
+}
diff --git a/dx/src/com/android/dx/command/dump/ClassDumper.java b/dx/src/com/android/dx/command/dump/ClassDumper.java
new file mode 100644
index 0000000..e98b6d6
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/ClassDumper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.direct.StdAttributeFactory;
+import com.android.dx.util.ByteArray;
+
+import java.io.PrintStream;
+
+/**
+ * Utility to dump the contents of class files in a human-friendly form.
+ */
+public final class ClassDumper
+        extends BaseDumper {
+    /**
+     * Dumps the given array, interpreting it as a class file.
+     *
+     * @param bytes {@code non-null;} bytes of the (alleged) class file
+     * @param out {@code non-null;} where to dump to
+     * passed in as &lt;= 0
+     * @param filePath the file path for the class, excluding any base
+     * directory specification
+     * @param args bag of commandline arguments
+     */
+    public static void dump(byte[] bytes, PrintStream out,
+                            String filePath, Args args) {
+        ClassDumper cd =
+            new ClassDumper(bytes, out, filePath, args);
+        cd.dump();
+    }
+
+    /**
+     * Constructs an instance. This class is not publicly instantiable.
+     * Use {@link #dump}.
+     */
+    private ClassDumper(byte[] bytes, PrintStream out,
+                        String filePath, Args args) {
+        super(bytes, out, filePath, args);
+    }
+
+    /**
+     * Does the dumping.
+     */
+    public void dump() {
+        byte[] bytes = getBytes();
+        ByteArray ba = new ByteArray(bytes);
+        DirectClassFile cf =
+            new DirectClassFile(ba, getFilePath(), getStrictParse());
+
+        cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
+        cf.setObserver(this);
+        cf.getMagic(); // Force parsing to happen.
+
+        int at = getAt();
+        if (at != bytes.length) {
+            parsed(ba, at, bytes.length - at, "<extra data at end of file>");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/command/dump/DotDumper.java b/dx/src/com/android/dx/command/dump/DotDumper.java
new file mode 100644
index 0000000..9de48fc
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/DotDumper.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+import com.android.dx.cf.code.ConcreteMethod;
+import com.android.dx.cf.code.Ropper;
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.direct.StdAttributeFactory;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.Method;
+import com.android.dx.cf.iface.ParseObserver;
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.DexTranslationAdvice;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.ssa.Optimizer;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+/**
+ * Dumps the pred/succ graph of methods into a format compatible
+ * with the popular graph utility "dot".
+ */
+public class DotDumper implements ParseObserver {
+    private DirectClassFile classFile;
+
+    private final byte[] bytes;
+    private final String filePath;
+    private final boolean strictParse;
+    private final boolean optimize;
+    private final Args args;
+
+    static void dump(byte[] bytes, String filePath, Args args) {
+        new DotDumper(bytes, filePath, args).run();
+    }
+
+    DotDumper(byte[] bytes, String filePath, Args args) {
+        this.bytes = bytes;
+        this.filePath = filePath;
+        this.strictParse = args.strictParse;
+        this.optimize = args.optimize;
+        this.args = args;
+    }
+
+    private void run() {
+        ByteArray ba = new ByteArray(bytes);
+
+        /*
+         * First, parse the file completely, so we can safely refer to
+         * attributes, etc.
+         */
+        classFile = new DirectClassFile(ba, filePath, strictParse);
+        classFile.setAttributeFactory(StdAttributeFactory.THE_ONE);
+        classFile.getMagic(); // Force parsing to happen.
+
+        // Next, reparse it and observe the process.
+        DirectClassFile liveCf =
+            new DirectClassFile(ba, filePath, strictParse);
+        liveCf.setAttributeFactory(StdAttributeFactory.THE_ONE);
+        liveCf.setObserver(this);
+        liveCf.getMagic(); // Force parsing to happen.
+    }
+
+    /**
+     * @param name method name
+     * @return true if this method should be dumped
+     */
+    protected boolean shouldDumpMethod(String name) {
+        return args.method == null || args.method.equals(name);
+    }
+
+    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,
+                                 String descriptor, Member member) {
+        if (!(member instanceof Method)) {
+            return;
+        }
+
+        if (!shouldDumpMethod(name)) {
+            return;
+        }
+
+        ConcreteMethod meth = new ConcreteMethod((Method) member, classFile,
+                                                 true, true);
+
+        TranslationAdvice advice = DexTranslationAdvice.THE_ONE;
+        RopMethod rmeth =
+            Ropper.convert(meth, advice);
+
+        if (optimize) {
+            boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());
+            rmeth = Optimizer.optimize(rmeth,
+                    BaseDumper.computeParamWidth(meth, isStatic), isStatic,
+                    true, advice);
+        }
+
+        System.out.println("digraph "  + name + "{");
+
+        System.out.println("\tfirst -> n"
+                + Hex.u2(rmeth.getFirstLabel()) + ";");
+
+        BasicBlockList blocks = rmeth.getBlocks();
+
+        int sz = blocks.size();
+        for (int i = 0; i < sz; i++) {
+            BasicBlock bb = blocks.get(i);
+            int label = bb.getLabel();
+            IntList successors = bb.getSuccessors();
+
+            if (successors.size() == 0) {
+                System.out.println("\tn" + Hex.u2(label) + " -> returns;");
+            } else if (successors.size() == 1) {
+                System.out.println("\tn" + Hex.u2(label) + " -> n"
+                        + Hex.u2(successors.get(0)) + ";");
+            } else {
+                System.out.print("\tn" + Hex.u2(label) + " -> {");
+                for (int j = 0; j < successors.size(); j++ ) {
+                    int successor = successors.get(j);
+
+                    if (successor != bb.getPrimarySuccessor()) {
+                        System.out.print(" n" + Hex.u2(successor) + " ");
+                    }
+
+                }
+                System.out.println("};");
+
+                System.out.println("\tn" + Hex.u2(label) + " -> n"
+                        + Hex.u2(bb.getPrimarySuccessor())
+                        + " [label=\"primary\"];");
+
+
+            }
+        }
+
+        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
new file mode 100644
index 0000000..d6ba374
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/Main.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+import com.android.dx.cf.iface.ParseException;
+import com.android.dx.util.FileUtils;
+import com.android.dx.util.HexParser;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Main class for the class file dumper.
+ */
+public class Main {
+
+    static Args parsedArgs = new Args();
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Main() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Run!
+     */
+    public static void main(String[] args) {
+        int at = 0;
+
+        for (/*at*/; at < args.length; at++) {
+            String arg = args[at];
+            if (arg.equals("--") || !arg.startsWith("--")) {
+                break;
+            } else if (arg.equals("--bytes")) {
+                parsedArgs.rawBytes = true;
+            } else if (arg.equals("--basic-blocks")) {
+                parsedArgs.basicBlocks = true;
+            } else if (arg.equals("--rop-blocks")) {
+                parsedArgs.ropBlocks = true;
+            } else if (arg.equals("--optimize")) {
+                parsedArgs.optimize = true;
+            } else if (arg.equals("--ssa-blocks")) {
+                parsedArgs.ssaBlocks = true;
+            } else if (arg.startsWith("--ssa-step=")) {
+                parsedArgs.ssaStep = arg.substring(arg.indexOf('=') + 1);
+            } else if (arg.equals("--debug")) {
+                parsedArgs.debug = true;
+            } else if (arg.equals("--dot")) {
+                parsedArgs.dotDump = true;
+            } else if (arg.equals("--strict")) {
+                parsedArgs.strictParse = true;
+            } else if (arg.startsWith("--width=")) {
+                arg = arg.substring(arg.indexOf('=') + 1);
+                parsedArgs.width = Integer.parseInt(arg);
+            } else if (arg.startsWith("--method=")) {
+                arg = arg.substring(arg.indexOf('=') + 1);
+                parsedArgs.method = arg;
+            } else {
+                System.err.println("unknown option: " + arg);
+                throw new RuntimeException("usage");
+            }
+        }
+
+        if (at == args.length) {
+            System.err.println("no input files specified");
+            throw new RuntimeException("usage");
+        }
+
+        for (/*at*/; at < args.length; at++) {
+            try {
+                String name = args[at];
+                System.out.println("reading " + name + "...");
+                byte[] bytes = FileUtils.readFile(name);
+                if (!name.endsWith(".class")) {
+                    String src;
+                    try {
+                        src = new String(bytes, "utf-8");
+                    } catch (UnsupportedEncodingException ex) {
+                        throw new RuntimeException("shouldn't happen", ex);
+                    }
+                    bytes = HexParser.parse(src);
+                }
+                processOne(name, bytes);
+            } catch (ParseException ex) {
+                System.err.println("\ntrouble parsing:");
+                if (parsedArgs.debug) {
+                    ex.printStackTrace();
+                } else {
+                    ex.printContext(System.err);
+                }
+            }
+        }
+    }
+
+    /**
+     * Processes one 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) {
+            DotDumper.dump(bytes, name, parsedArgs);
+        } else if (parsedArgs.basicBlocks) {
+            BlockDumper.dump(bytes, System.out, name, false, parsedArgs);
+        } else if (parsedArgs.ropBlocks) {
+            BlockDumper.dump(bytes, System.out, name, true, parsedArgs);
+        } else if (parsedArgs.ssaBlocks) {
+            // --optimize ignored with --ssa-blocks
+            parsedArgs.optimize = false;
+            SsaDumper.dump(bytes, System.out, name, parsedArgs);
+        } else {
+            ClassDumper.dump(bytes, System.out, name, parsedArgs);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/command/dump/SsaDumper.java b/dx/src/com/android/dx/command/dump/SsaDumper.java
new file mode 100644
index 0000000..0572a30
--- /dev/null
+++ b/dx/src/com/android/dx/command/dump/SsaDumper.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.dump;
+
+import com.android.dx.cf.code.ConcreteMethod;
+import com.android.dx.cf.code.Ropper;
+import com.android.dx.cf.iface.Member;
+import com.android.dx.cf.iface.Method;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.rop.code.DexTranslationAdvice;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.ssa.DeadCodeRemover;
+import com.android.dx.ssa.PhiTypeResolver;
+import com.android.dx.ssa.SsaBasicBlock;
+import com.android.dx.ssa.SsaConverter;
+import com.android.dx.ssa.SsaInsn;
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.ssa.Optimizer;
+import com.android.dx.ssa.ConstCollector;
+import com.android.dx.ssa.SCCP;
+import com.android.dx.ssa.LiteralOpUpgrader;
+import com.android.dx.ssa.back.SsaToRop;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+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);
+        sd.dump();
+    }
+
+    /**
+     * 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) {
+        if (!(member instanceof Method)) {
+            return;
+        }
+
+        if (!shouldDumpMethod(name)) {
+            return;
+        }
+
+        if ((member.getAccessFlags() & (AccessFlags.ACC_ABSTRACT |
+                AccessFlags.ACC_NATIVE)) != 0) {
+            return;
+        }
+
+        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,
+                    EnumSet.allOf(Optimizer.OptionalStep.class));
+        } else if ("edge-split".equals(args.ssaStep)) {
+            ssaMeth = Optimizer.debugEdgeSplit(rmeth, paramWidth,
+                    isStatic, true, advice);
+        } else if ("phi-placement".equals(args.ssaStep)) {
+            ssaMeth = Optimizer.debugPhiPlacement(
+                    rmeth, paramWidth, isStatic, true, advice);
+        } else if ("renaming".equals(args.ssaStep)) {
+            ssaMeth = Optimizer.debugRenaming(
+                    rmeth, paramWidth, isStatic, true, advice);
+        } else if ("dead-code".equals(args.ssaStep)) {
+            ssaMeth = Optimizer.debugDeadCodeRemover(
+                    rmeth, paramWidth, isStatic,true, advice);
+        }
+
+        StringBuffer sb = new StringBuffer(2000);
+
+        sb.append("first ");
+        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 : 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)));
+                sb.append('\n');
+            }
+
+            sb.append("  live in:" + block.getLiveInRegs());
+            sb.append("\n");
+
+            for (SsaInsn insn : block.getInsns()) {
+                sb.append("  ");
+                sb.append(insn.toHuman());
+                sb.append('\n');
+            }
+
+            if (block.getSuccessors().cardinality() == 0) {
+                sb.append("  returns\n");
+            } else {
+                int primary = block.getPrimarySuccessorRopLabel();
+
+                IntList succLabelList = block.getRopLabelSuccessorList();
+
+                int szSuccLabels = succLabelList.size();
+
+                for (int i = 0; i < szSuccLabels; i++) {
+                    sb.append("  next ");
+                    sb.append(Hex.u2(succLabelList.get(i)));
+
+                    if (szSuccLabels != 1 && primary == succLabelList.get(i)) {
+                        sb.append(" *");
+                    }
+                    sb.append('\n');
+                }
+            }
+
+            sb.append("  live out:" + block.getLiveOutRegs());
+            sb.append("\n");
+        }
+
+        suppressDump = false;
+        setAt(bytes, 0);
+        parsed(bytes, 0, bytes.size(), sb.toString());
+        suppressDump = true;
+    }
+}
diff --git a/dx/src/com/android/dx/command/findusages/FindUsages.java b/dx/src/com/android/dx/command/findusages/FindUsages.java
new file mode 100644
index 0000000..6651f53
--- /dev/null
+++ b/dx/src/com/android/dx/command/findusages/FindUsages.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.findusages;
+
+import com.android.dx.io.ClassData;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.CodeReader;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.io.FieldId;
+import com.android.dx.io.MethodId;
+import com.android.dx.io.OpcodeInfo;
+import com.android.dx.io.instructions.DecodedInstruction;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public final class FindUsages {
+    private final DexBuffer dex;
+    private final Set<Integer> methodIds;
+    private final Set<Integer> fieldIds;
+    private final CodeReader codeReader = new CodeReader();
+    private final PrintWriter out;
+
+    private ClassDef currentClass;
+    private ClassData.Method currentMethod;
+
+    public FindUsages(final DexBuffer dex, String declaredBy, String memberName, final PrintWriter out) {
+        this.dex = dex;
+        this.out = out;
+
+        Set<Integer> typeStringIndexes = new HashSet<Integer>();
+        Set<Integer> memberNameIndexes = new HashSet<Integer>();
+        Pattern declaredByPattern = Pattern.compile(declaredBy);
+        Pattern memberNamePattern = Pattern.compile(memberName);
+        List<String> strings = dex.strings();
+        for (int i = 0; i < strings.size(); ++i) {
+            String string = strings.get(i);
+            if (declaredByPattern.matcher(string).matches()) {
+                typeStringIndexes.add(i);
+            }
+            if (memberNamePattern.matcher(string).matches()) {
+                memberNameIndexes.add(i);
+            }
+        }
+        if (typeStringIndexes.isEmpty() || memberNameIndexes.isEmpty()) {
+            methodIds = fieldIds = null;
+            return; // these symbols are not mentioned in this dex
+        }
+
+        methodIds = new HashSet<Integer>();
+        fieldIds = new HashSet<Integer>();
+        for (int typeStringIndex : typeStringIndexes) {
+            int typeIndex = Collections.binarySearch(dex.typeIds(), typeStringIndex);
+            if (typeIndex < 0) {
+                continue; // this type name isn't used as a type in this dex
+            }
+            methodIds.addAll(getMethodIds(dex, memberNameIndexes, typeIndex));
+            fieldIds.addAll(getFieldIds(dex, memberNameIndexes, typeIndex));
+        }
+
+        codeReader.setFieldVisitor(new CodeReader.Visitor() {
+            public void visit(DecodedInstruction[] all,
+                    DecodedInstruction one) {
+                int fieldId = one.getIndex();
+                if (fieldIds.contains(fieldId)) {
+                    out.println(location() + ": field reference " + dex.fieldIds().get(fieldId)
+                            + " (" + OpcodeInfo.getName(one.getOpcode()) + ")");
+                }
+            }
+        });
+
+        codeReader.setMethodVisitor(new CodeReader.Visitor() {
+            public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+                int methodId = one.getIndex();
+                if (methodIds.contains(methodId)) {
+                    out.println(location() + ": method reference " + dex.methodIds().get(methodId)
+                            + " (" + OpcodeInfo.getName(one.getOpcode()) + ")");
+                }
+            }
+        });
+    }
+
+    private String location() {
+        String className = dex.typeNames().get(currentClass.getTypeIndex());
+        if (currentMethod != null) {
+            MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex());
+            return className + "." + dex.strings().get(methodId.getNameIndex());
+        } else {
+            return className;
+        }
+    }
+
+    /**
+     * Prints usages to out.
+     */
+    public void findUsages() {
+        if (fieldIds == null || methodIds == null) {
+            return;
+        }
+
+        for (ClassDef classDef : dex.classDefs()) {
+            currentClass = classDef;
+            currentMethod = null;
+
+            if (classDef.getClassDataOffset() == 0) {
+                continue;
+            }
+
+            ClassData classData = dex.readClassData(classDef);
+            for (ClassData.Field field : classData.allFields()) {
+                int fieldIndex = field.getFieldIndex();
+                if (fieldIds.contains(fieldIndex)) {
+                    out.println(location() + " field declared " + dex.fieldIds().get(fieldIndex));
+                }
+            }
+
+            for (ClassData.Method method : classData.allMethods()) {
+                currentMethod = method;
+                int methodIndex = method.getMethodIndex();
+                if (methodIds.contains(methodIndex)) {
+                    out.println(location() + " method declared " + dex.methodIds().get(methodIndex));
+                }
+                if (method.getCodeOffset() != 0) {
+                    codeReader.visitAll(dex.readCode(method).getInstructions());
+                }
+            }
+        }
+
+        currentClass = null;
+        currentMethod = null;
+    }
+
+    /**
+     * Returns the fields with {@code memberNameIndex} declared by {@code
+     * declaringType}.
+     */
+    private Set<Integer> getFieldIds(DexBuffer dex, Set<Integer> memberNameIndexes, int declaringType) {
+        Set<Integer> fields = new HashSet<Integer>();
+        int fieldIndex = 0;
+        for (FieldId fieldId : dex.fieldIds()) {
+            if (memberNameIndexes.contains(fieldId.getNameIndex())
+                    && declaringType == fieldId.getDeclaringClassIndex()) {
+                fields.add(fieldIndex);
+            }
+            fieldIndex++;
+        }
+        return fields;
+    }
+
+    /**
+     * Returns the methods with {@code memberNameIndex} declared by {@code
+     * declaringType} and its subtypes.
+     */
+    private Set<Integer> getMethodIds(DexBuffer dex, Set<Integer> memberNameIndexes, int declaringType) {
+        Set<Integer> subtypes = findAssignableTypes(dex, declaringType);
+
+        Set<Integer> methods = new HashSet<Integer>();
+        int methodIndex = 0;
+        for (MethodId method : dex.methodIds()) {
+            if (memberNameIndexes.contains(method.getNameIndex())
+                    && subtypes.contains(method.getDeclaringClassIndex())) {
+                methods.add(methodIndex);
+            }
+            methodIndex++;
+        }
+        return methods;
+    }
+
+    /**
+     * Returns the set of types that can be assigned to {@code typeIndex}.
+     */
+    private Set<Integer> findAssignableTypes(DexBuffer dex, int typeIndex) {
+        Set<Integer> assignableTypes = new HashSet<Integer>();
+        assignableTypes.add(typeIndex);
+
+        for (ClassDef classDef : dex.classDefs()) {
+            if (assignableTypes.contains(classDef.getSupertypeIndex())) {
+                assignableTypes.add(classDef.getTypeIndex());
+                continue;
+            }
+
+            for (int implemented : classDef.getInterfaces()) {
+                if (assignableTypes.contains(implemented)) {
+                    assignableTypes.add(classDef.getTypeIndex());
+                    break;
+                }
+            }
+        }
+
+        return assignableTypes;
+    }
+}
diff --git a/dx/src/com/android/dx/command/findusages/Main.java b/dx/src/com/android/dx/command/findusages/Main.java
new file mode 100644
index 0000000..ba29787
--- /dev/null
+++ b/dx/src/com/android/dx/command/findusages/Main.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.findusages;
+
+import com.android.dx.io.DexBuffer;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public final class Main {
+    public static void main(String[] args) throws IOException {
+        String dexFile = args[0];
+        String declaredBy = args[1];
+        String memberName = args[2];
+
+        DexBuffer dex = new DexBuffer(new File(dexFile));
+        PrintWriter out = new PrintWriter(System.out);
+        new FindUsages(dex, declaredBy, memberName, out).findUsages();
+        out.flush();
+    }
+}
diff --git a/dx/src/com/android/dx/command/grep/Grep.java b/dx/src/com/android/dx/command/grep/Grep.java
new file mode 100644
index 0000000..741de97
--- /dev/null
+++ b/dx/src/com/android/dx/command/grep/Grep.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.grep;
+
+import com.android.dx.io.ClassData;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.CodeReader;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.io.EncodedValueReader;
+import com.android.dx.io.MethodId;
+import com.android.dx.io.instructions.DecodedInstruction;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public final class Grep {
+    private final DexBuffer dex;
+    private final CodeReader codeReader = new CodeReader();
+    private final Set<Integer> stringIds;
+
+    private final PrintWriter out;
+    private int count = 0;
+
+    private ClassDef currentClass;
+    private ClassData.Method currentMethod;
+
+    public Grep(final DexBuffer dex, Pattern pattern, final PrintWriter out) {
+        this.dex = dex;
+        this.out = out;
+
+        stringIds = getStringIds(dex, pattern);
+
+        codeReader.setStringVisitor(new CodeReader.Visitor() {
+            public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+                encounterString(one.getIndex());
+            }
+        });
+    }
+
+    private EncodedValueReader newEncodedValueReader(DexBuffer.Section section) {
+        return new EncodedValueReader(section) {
+            @Override protected void visitString(int type, int index) {
+                encounterString(index);
+            }
+        };
+    }
+
+    private void encounterString(int index) {
+        if (stringIds.contains(index)) {
+            out.println(location() + " " + dex.strings().get(index));
+            count++;
+        }
+    }
+
+    private String location() {
+        String className = dex.typeNames().get(currentClass.getTypeIndex());
+        if (currentMethod != null) {
+            MethodId methodId = dex.methodIds().get(currentMethod.getMethodIndex());
+            return className + "." + dex.strings().get(methodId.getNameIndex());
+        } else {
+            return className;
+        }
+    }
+
+    /**
+     * Prints usages to out. Returns the number of matches found.
+     */
+    public int grep() {
+        for (ClassDef classDef : dex.classDefs()) {
+            currentClass = classDef;
+            currentMethod = null;
+
+            if (classDef.getClassDataOffset() == 0) {
+                continue;
+            }
+
+            ClassData classData = dex.readClassData(classDef);
+
+            // find the strings in encoded constants
+            int staticValuesOffset = classDef.getStaticValuesOffset();
+            if (staticValuesOffset != 0) {
+                newEncodedValueReader(dex.open(staticValuesOffset)).readArray();
+            }
+
+            // find the strings in method bodies
+            for (ClassData.Method method : classData.allMethods()) {
+                currentMethod = method;
+                if (method.getCodeOffset() != 0) {
+                    codeReader.visitAll(dex.readCode(method).getInstructions());
+                }
+            }
+        }
+
+        currentClass = null;
+        currentMethod = null;
+        return count;
+    }
+
+    private Set<Integer> getStringIds(DexBuffer dex, Pattern pattern) {
+        Set<Integer> stringIds = new HashSet<Integer>();
+        int stringIndex = 0;
+        for (String s : dex.strings()) {
+            if (pattern.matcher(s).find()) {
+                stringIds.add(stringIndex);
+            }
+            stringIndex++;
+        }
+        return stringIds;
+    }
+}
diff --git a/dx/src/com/android/dx/command/grep/Main.java b/dx/src/com/android/dx/command/grep/Main.java
new file mode 100644
index 0000000..e3b119a
--- /dev/null
+++ b/dx/src/com/android/dx/command/grep/Main.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.command.grep;
+
+import com.android.dx.io.DexBuffer;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.regex.Pattern;
+
+public final class Main {
+    public static void main(String[] args) throws IOException {
+        String dexFile = args[0];
+        String pattern = args[1];
+
+        DexBuffer dex = new DexBuffer(new File(dexFile));
+        int count = new Grep(dex, Pattern.compile(pattern), new PrintWriter(System.out)).grep();
+        System.exit((count > 0) ? 0 : 1);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/DexFormat.java b/dx/src/com/android/dx/dex/DexFormat.java
new file mode 100644
index 0000000..3543b35
--- /dev/null
+++ b/dx/src/com/android/dx/dex/DexFormat.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex;
+
+/**
+ * Constants that show up in and are otherwise related to {@code .dex}
+ * files, and helper methods for same.
+ */
+public final class DexFormat {
+    private DexFormat() {}
+
+    /**
+     * API level to target in order to produce the most modern file
+     * format
+     */
+    public static final int API_CURRENT = 14;
+
+    /** API level to target in order to suppress extended opcode usage */
+    public static final int API_NO_EXTENDED_OPCODES = 13;
+
+    /**
+     * file name of the primary {@code .dex} file inside an
+     * application or library {@code .jar} file
+     */
+    public static final String DEX_IN_JAR_NAME = "classes.dex";
+
+    /** common prefix for all dex file "magic numbers" */
+    public static final String MAGIC_PREFIX = "dex\n";
+
+    /** common suffix for all dex file "magic numbers" */
+    public static final String MAGIC_SUFFIX = "\0";
+
+    /** dex file version number for the current format variant */
+    public static final String VERSION_CURRENT = "036";
+
+    /** dex file version number for API level 13 and earlier */
+    public static final String VERSION_FOR_API_13 = "035";
+
+    /**
+     * value used to indicate endianness of file contents
+     */
+    public static final int ENDIAN_TAG = 0x12345678;
+
+    /**
+     * Returns the API level corresponding to the given magic number,
+     * or {@code -1} if the given array is not a well-formed dex file
+     * magic number.
+     */
+    public static int magicToApi(byte[] magic) {
+        if (magic.length != 8) {
+            return -1;
+        }
+
+        if ((magic[0] != 'd') || (magic[1] != 'e') || (magic[2] != 'x') || (magic[3] != '\n') ||
+                (magic[7] != '\0')) {
+            return -1;
+        }
+
+        String version = "" + ((char) magic[4]) + ((char) magic[5]) +((char) magic[6]);
+
+        if (version.equals(VERSION_CURRENT)) {
+            return API_CURRENT;
+        } else if (version.equals(VERSION_FOR_API_13)) {
+            return 13;
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns the magic number corresponding to the given target API level.
+     */
+    public static String apiToMagic(int targetApiLevel) {
+        String version;
+
+        if (targetApiLevel >= API_CURRENT) {
+            version = VERSION_CURRENT;
+        } else {
+            version = VERSION_FOR_API_13;
+        }
+
+        return MAGIC_PREFIX + version + MAGIC_SUFFIX;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/DexOptions.java b/dx/src/com/android/dx/dex/DexOptions.java
new file mode 100644
index 0000000..a725325
--- /dev/null
+++ b/dx/src/com/android/dx/dex/DexOptions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex;
+
+/**
+ * Container for options used to control details of dex file generation.
+ */
+public class DexOptions {
+    /** target API level */
+    public int targetApiLevel = DexFormat.API_CURRENT;
+
+    /**
+     * Gets the dex file magic number corresponding to this instance.
+     */
+    public String getMagic() {
+        return DexFormat.apiToMagic(targetApiLevel);
+    }
+
+    /**
+     * Returns whether extended opcodes are allowed. This became
+     * allowed as of Ice Cream Sandwich.
+     */
+    public boolean canUseExtendedOpcodes() {
+        return targetApiLevel >= DexFormat.API_CURRENT;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/SizeOf.java b/dx/src/com/android/dx/dex/SizeOf.java
new file mode 100644
index 0000000..476f7bb
--- /dev/null
+++ b/dx/src/com/android/dx/dex/SizeOf.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex;
+
+public final class SizeOf {
+    private SizeOf() {}
+
+    public static final int UBYTE = 1;
+    public static final int USHORT = 2;
+    public static final int UINT = 4;
+
+    public static final int SIGNATURE = UBYTE * 20;
+
+    /**
+     * magic ubyte[8]
+     * checksum uint
+     * signature ubyte[20]
+     * file_size uint
+     * header_size uint
+     * endian_tag uint
+     * link_size uint
+     * link_off uint
+     * map_off uint
+     * string_ids_size uint
+     * string_ids_off uint
+     * type_ids_size uint
+     * type_ids_off uint
+     * proto_ids_size uint
+     * proto_ids_off uint
+     * field_ids_size uint
+     * field_ids_off uint
+     * method_ids_size uint
+     * method_ids_off uint
+     * class_defs_size uint
+     * class_defs_off uint
+     * data_size uint
+     * data_off uint
+     */
+    public static final int HEADER_ITEM = (8 * UBYTE) + UINT + SIGNATURE + (20 * UINT); // 0x70
+
+    /**
+     * string_data_off uint
+     */
+    public static final int STRING_ID_ITEM = UINT;
+
+    /**
+     * descriptor_idx uint
+     */
+    public static final int TYPE_ID_ITEM = UINT;
+
+    /**
+     * type_idx ushort
+     */
+    public static final int TYPE_ITEM = USHORT;
+
+    /**
+     * shorty_idx uint
+     * return_type_idx uint
+     * return_type_idx uint
+     */
+    public static final int PROTO_ID_ITEM = UINT + UINT + UINT;
+
+    /**
+     * class_idx ushort
+     * type_idx/proto_idx ushort
+     * name_idx uint
+     */
+    public static final int MEMBER_ID_ITEM = USHORT + USHORT + UINT;
+
+    /**
+     * class_idx uint
+     * access_flags uint
+     * superclass_idx uint
+     * interfaces_off uint
+     * source_file_idx uint
+     * annotations_off uint
+     * class_data_off uint
+     * static_values_off uint
+     */
+    public static final int CLASS_DEF_ITEM = 8 * UINT;
+
+    /**
+     * type ushort
+     * unused ushort
+     * size uint
+     * offset uint
+     */
+    public static final int MAP_ITEM = USHORT + USHORT + UINT + UINT;
+}
diff --git a/dx/src/com/android/dx/dex/TableOfContents.java b/dx/src/com/android/dx/dex/TableOfContents.java
new file mode 100644
index 0000000..877dddb
--- /dev/null
+++ b/dx/src/com/android/dx/dex/TableOfContents.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex;
+
+import com.android.dx.io.DexBuffer;
+import com.android.dx.util.DexException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+/**
+ * The file header and map.
+ */
+public final class TableOfContents {
+
+    /*
+     * TODO: factor out ID constants.
+     */
+
+    public final Section header = new Section(0x0000);
+    public final Section stringIds = new Section(0x0001);
+    public final Section typeIds = new Section(0x0002);
+    public final Section protoIds = new Section(0x0003);
+    public final Section fieldIds = new Section(0x0004);
+    public final Section methodIds = new Section(0x0005);
+    public final Section classDefs = new Section(0x0006);
+    public final Section mapList = new Section(0x1000);
+    public final Section typeLists = new Section(0x1001);
+    public final Section annotationSetRefLists = new Section(0x1002);
+    public final Section annotationSets = new Section(0x1003);
+    public final Section classDatas = new Section(0x2000);
+    public final Section codes = new Section(0x2001);
+    public final Section stringDatas = new Section(0x2002);
+    public final Section debugInfos = new Section(0x2003);
+    public final Section annotations = new Section(0x2004);
+    public final Section encodedArrays = new Section(0x2005);
+    public final Section annotationsDirectories = new Section(0x2006);
+    public final Section[] sections = {
+            header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList,
+            typeLists, annotationSetRefLists, annotationSets, classDatas, codes, stringDatas,
+            debugInfos, annotations, encodedArrays, annotationsDirectories
+    };
+
+    public int checksum;
+    public byte[] signature;
+    public int fileSize;
+    public int linkSize;
+    public int linkOff;
+    public int dataSize;
+    public int dataOff;
+
+    public TableOfContents() {
+        signature = new byte[20];
+    }
+
+    public void readFrom(DexBuffer buffer) throws IOException {
+        readHeader(buffer.open(0));
+        readMap(buffer.open(mapList.off));
+        computeSizesFromOffsets();
+    }
+
+    private void readHeader(DexBuffer.Section headerIn) throws UnsupportedEncodingException {
+        byte[] magic = headerIn.readByteArray(8);
+        int apiTarget = DexFormat.magicToApi(magic);
+
+        if (apiTarget < 0) {
+            throw new DexException("Unexpected magic: " + Arrays.toString(magic));
+        }
+
+        checksum = headerIn.readInt();
+        signature = headerIn.readByteArray(20);
+        fileSize = headerIn.readInt();
+        int headerSize = headerIn.readInt();
+        if (headerSize != SizeOf.HEADER_ITEM) {
+            throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
+        }
+        int endianTag = headerIn.readInt();
+        if (endianTag != DexFormat.ENDIAN_TAG) {
+            throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
+        }
+        linkSize = headerIn.readInt();
+        linkOff = headerIn.readInt();
+        mapList.off = headerIn.readInt();
+        if (mapList.off == 0) {
+            throw new DexException("Cannot merge dex files that do not contain a map");
+        }
+        stringIds.size = headerIn.readInt();
+        stringIds.off = headerIn.readInt();
+        typeIds.size = headerIn.readInt();
+        typeIds.off = headerIn.readInt();
+        protoIds.size = headerIn.readInt();
+        protoIds.off = headerIn.readInt();
+        fieldIds.size = headerIn.readInt();
+        fieldIds.off = headerIn.readInt();
+        methodIds.size = headerIn.readInt();
+        methodIds.off = headerIn.readInt();
+        classDefs.size = headerIn.readInt();
+        classDefs.off = headerIn.readInt();
+        dataSize = headerIn.readInt();
+        dataOff = headerIn.readInt();
+    }
+
+    private void readMap(DexBuffer.Section in) throws IOException {
+        int mapSize = in.readInt();
+        Section previous = null;
+        for (int i = 0; i < mapSize; i++) {
+            short type = in.readShort();
+            in.readShort(); // unused
+            Section section = getSection(type);
+            int size = in.readInt();
+            int offset = in.readInt();
+
+            if ((section.size != 0 && section.size != size)
+                    || (section.off != -1 && section.off != offset)) {
+                throw new DexException("Unexpected map value for 0x" + Integer.toHexString(type));
+            }
+
+            section.size = size;
+            section.off = offset;
+
+            if (previous != null && previous.off > section.off) {
+                throw new DexException("Map is unsorted at " + previous + ", " + section);
+            }
+
+            previous = section;
+        }
+        Arrays.sort(sections);
+    }
+
+    public void computeSizesFromOffsets() {
+        int end = dataOff + dataSize;
+        for (int i = sections.length - 1; i >= 0; i--) {
+            Section section = sections[i];
+            if (section.off == -1) {
+                continue;
+            }
+            if (section.off > end) {
+                throw new DexException("Map is unsorted at " + section);
+            }
+            section.byteCount = end - section.off;
+            end = section.off;
+        }
+    }
+
+    private Section getSection(short type) {
+        for (Section section : sections) {
+            if (section.type == type) {
+                return section;
+            }
+        }
+        throw new IllegalArgumentException("No such map item: " + type);
+    }
+
+    public void writeHeader(DexBuffer.Section out) throws IOException {
+        out.write(DexFormat.apiToMagic(DexFormat.API_CURRENT).getBytes("UTF-8"));
+        out.writeInt(checksum);
+        out.write(signature);
+        out.writeInt(fileSize);
+        out.writeInt(SizeOf.HEADER_ITEM);
+        out.writeInt(DexFormat.ENDIAN_TAG);
+        out.writeInt(linkSize);
+        out.writeInt(linkOff);
+        out.writeInt(mapList.off);
+        out.writeInt(stringIds.size);
+        out.writeInt(stringIds.off);
+        out.writeInt(typeIds.size);
+        out.writeInt(typeIds.off);
+        out.writeInt(protoIds.size);
+        out.writeInt(protoIds.off);
+        out.writeInt(fieldIds.size);
+        out.writeInt(fieldIds.off);
+        out.writeInt(methodIds.size);
+        out.writeInt(methodIds.off);
+        out.writeInt(classDefs.size);
+        out.writeInt(classDefs.off);
+        out.writeInt(dataSize);
+        out.writeInt(dataOff);
+    }
+
+    public void writeMap(DexBuffer.Section out) throws IOException {
+        int count = 0;
+        for (Section section : sections) {
+            if (section.exists()) {
+                count++;
+            }
+        }
+
+        out.writeInt(count);
+        for (Section section : sections) {
+            if (section.exists()) {
+                out.writeShort(section.type);
+                out.writeShort((short) 0);
+                out.writeInt(section.size);
+                out.writeInt(section.off);
+            }
+        }
+    }
+
+    public static class Section implements Comparable<Section> {
+        public final short type;
+        public int size = 0;
+        public int off = -1;
+        public int byteCount = 0;
+
+        public Section(int type) {
+            this.type = (short) type;
+        }
+
+        public boolean exists() {
+            return size > 0;
+        }
+
+        public int compareTo(Section section) {
+            if (off != section.off) {
+                return off < section.off ? -1 : 1;
+            }
+            return 0;
+        }
+
+        @Override public String toString() {
+            return String.format("Section[type=%#x,off=%#x,size=%#x]", type, off, size);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
new file mode 100644
index 0000000..8dc8b92
--- /dev/null
+++ b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.cf;
+
+import com.android.dx.cf.attrib.AttAnnotationDefault;
+import com.android.dx.cf.attrib.AttEnclosingMethod;
+import com.android.dx.cf.attrib.AttExceptions;
+import com.android.dx.cf.attrib.AttInnerClasses;
+import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
+import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations;
+import com.android.dx.cf.attrib.AttSignature;
+import com.android.dx.cf.attrib.InnerClassList;
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.iface.AttributeList;
+import com.android.dx.cf.iface.Method;
+import com.android.dx.cf.iface.MethodList;
+import com.android.dx.dex.file.AnnotationUtils;
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.rop.annotation.AnnotationVisibility;
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.annotation.NameValuePair;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.Warning;
+
+import java.util.ArrayList;
+
+/**
+ * Utility methods that translate various classfile attributes
+ * into forms suitable for use in creating {@code dex} files.
+ */
+/*package*/ class AttributeTranslator {
+    /**
+     * This class is uninstantiable.
+     */
+    private AttributeTranslator() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the list of thrown exceptions for a given method.
+     *
+     * @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();
+        AttExceptions exceptions = (AttExceptions)
+            attribs.findFirst(AttExceptions.ATTRIBUTE_NAME);
+
+        if (exceptions == null) {
+            return StdTypeList.EMPTY;
+        }
+
+        return exceptions.getExceptions();
+    }
+
+    /**
+     * 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} attribute if present.
+     *
+     * @param attribs {@code non-null;} the attributes list to search in
+     * @return {@code non-null;} the set of annotations, which may be empty
+     */
+    public static Annotations getAnnotations(AttributeList attribs) {
+        Annotations result = getAnnotations0(attribs);
+        Annotation signature = getSignature(attribs);
+
+        if (signature != null) {
+            result = Annotations.combine(result, signature);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the annotations out of a given class, similar to {@link
+     * #getAnnotations}, also including annotations for translations
+     * 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}
+     * values.
+     *
+     * @param cf {@code non-null;} the class in question
+     * @param args {@code non-null;} the high-level options
+     * @return {@code non-null;} the set of annotations, which may be empty
+     */
+    public static Annotations getClassAnnotations(DirectClassFile cf,
+            CfOptions args) {
+        CstType thisClass = cf.getThisClass();
+        AttributeList attribs = cf.getAttributes();
+        Annotations result = getAnnotations(attribs);
+        Annotation enclosingMethod = translateEnclosingMethod(attribs);
+
+        try {
+            Annotations innerClassAnnotations =
+                translateInnerClasses(thisClass, attribs,
+                        enclosingMethod == null);
+            if (innerClassAnnotations != null) {
+                result = Annotations.combine(result, innerClassAnnotations);
+            }
+        } catch (Warning warn) {
+            args.warn.println("warning: " + warn.getMessage());
+        }
+
+        if (enclosingMethod != null) {
+            result = Annotations.combine(result, enclosingMethod);
+        }
+
+        if (AccessFlags.isAnnotation(cf.getAccessFlags())) {
+            Annotation annotationDefault =
+                translateAnnotationDefaults(cf);
+            if (annotationDefault != null) {
+                result = Annotations.combine(result, annotationDefault);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the annotations out of a given method, similar to {@link
+     * #getAnnotations}, also including an annotation for the translation
+     * of the method-specific attribute {@code Exceptions}.
+     *
+     * @param method {@code non-null;} the method in question
+     * @return {@code non-null;} the set of annotations, which may be empty
+     */
+    public static Annotations getMethodAnnotations(Method method) {
+        Annotations result = getAnnotations(method.getAttributes());
+        TypeList exceptions = getExceptions(method);
+
+        if (exceptions.size() != 0) {
+            Annotation throwsAnnotation =
+                AnnotationUtils.makeThrows(exceptions);
+            result = Annotations.combine(result, throwsAnnotation);
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper method for {@link #getAnnotations} which just gets the
+     * existing annotations, per se.
+     *
+     * @param attribs {@code non-null;} the attributes list to search in
+     * @return {@code non-null;} the set of annotations, which may be empty
+     */
+    private static Annotations getAnnotations0(AttributeList attribs) {
+        AttRuntimeVisibleAnnotations visible =
+            (AttRuntimeVisibleAnnotations)
+            attribs.findFirst(AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME);
+        AttRuntimeInvisibleAnnotations invisible =
+            (AttRuntimeInvisibleAnnotations)
+            attribs.findFirst(AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME);
+
+        if (visible == null) {
+            if (invisible == null) {
+                return Annotations.EMPTY;
+            }
+            return invisible.getAnnotations();
+        }
+
+        if (invisible == null) {
+            return visible.getAnnotations();
+        }
+
+        // Both are non-null, so combine them.
+
+        return Annotations.combine(visible.getAnnotations(),
+                invisible.getAnnotations());
+    }
+
+    /**
+     * Gets the {@code Signature} attribute out of a given
+     * {@link AttributeList}, if any, translating it to an annotation.
+     *
+     * @param attribs {@code non-null;} the attributes list to search in
+     * @return {@code null-ok;} the converted {@code Signature} annotation,
+     * if there was an attribute to translate
+     */
+    private static Annotation getSignature(AttributeList attribs) {
+        AttSignature signature = (AttSignature)
+            attribs.findFirst(AttSignature.ATTRIBUTE_NAME);
+
+        if (signature == null) {
+            return null;
+        }
+
+        return AnnotationUtils.makeSignature(signature.getSignature());
+    }
+
+    /**
+     * 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} annotation; if not, this returns
+     * an {@code EnclosingClass} annotation.
+     *
+     * @param attribs {@code non-null;} the attributes list to search in
+     * @return {@code null-ok;} the converted {@code EnclosingMethod} or
+     * {@code EnclosingClass} annotation, if there was an
+     * attribute to translate
+     */
+    private static Annotation translateEnclosingMethod(AttributeList attribs) {
+        AttEnclosingMethod enclosingMethod = (AttEnclosingMethod)
+            attribs.findFirst(AttEnclosingMethod.ATTRIBUTE_NAME);
+
+        if (enclosingMethod == null) {
+            return null;
+        }
+
+        CstType enclosingClass = enclosingMethod.getEnclosingClass();
+        CstNat nat = enclosingMethod.getMethod();
+
+        if (nat == null) {
+            /*
+             * Dalvik doesn't use EnclosingMethod annotations unless
+             * there really is an enclosing method. Anonymous classes
+             * are unambiguously identified by having an InnerClass
+             * annotation with an empty name along with an appropriate
+             * EnclosingClass.
+             */
+            return AnnotationUtils.makeEnclosingClass(enclosingClass);
+        }
+
+        return AnnotationUtils.makeEnclosingMethod(
+                new CstMethodRef(enclosingClass, nat));
+    }
+
+    /**
+     * Gets the {@code InnerClasses} attribute out of a given
+     * {@link AttributeList}, if any, translating it to one or more of an
+     * {@code InnerClass}, {@code EnclosingClass}, or
+     * {@code MemberClasses} annotation.
+     *
+     * @param thisClass {@code non-null;} type representing the class being
+     * processed
+     * @param attribs {@code non-null;} the attributes list to search in
+     * @param needEnclosingClass whether to include an
+     * {@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,
+            AttributeList attribs, boolean needEnclosingClass) {
+        AttInnerClasses innerClasses = (AttInnerClasses)
+            attribs.findFirst(AttInnerClasses.ATTRIBUTE_NAME);
+
+        if (innerClasses == null) {
+            return null;
+        }
+
+        /*
+         * Search the list for the element representing the current class
+         * as well as for any named member classes.
+         */
+
+        InnerClassList list = innerClasses.getInnerClasses();
+        int size = list.size();
+        InnerClassList.Item foundThisClass = null;
+        ArrayList<Type> membersList = new ArrayList<Type>();
+
+        for (int i = 0; i < size; i++) {
+            InnerClassList.Item item = list.get(i);
+            CstType innerClass = item.getInnerClass();
+            if (innerClass.equals(thisClass)) {
+                foundThisClass = item;
+            } else if (thisClass.equals(item.getOuterClass())) {
+                membersList.add(innerClass.getClassType());
+            }
+        }
+
+        int membersSize = membersList.size();
+
+        if ((foundThisClass == null) && (membersSize == 0)) {
+            return null;
+        }
+
+        Annotations result = new Annotations();
+
+        if (foundThisClass != null) {
+            result.add(AnnotationUtils.makeInnerClass(
+                               foundThisClass.getInnerName(),
+                               foundThisClass.getAccessFlags()));
+            if (needEnclosingClass) {
+                CstType outer = foundThisClass.getOuterClass();
+                if (outer == null) {
+                    throw new Warning(
+                            "Ignoring InnerClasses attribute for an " +
+                            "anonymous inner class\n" +
+                            "(" + thisClass.toHuman() +
+                            ") that doesn't come with an\n" +
+                            "associated EnclosingMethod attribute. " +
+                            "This class was probably produced by a\n" +
+                            "compiler that did not target the modern " +
+                            ".class file format. The recommended\n" +
+                            "solution is to recompile the class from " +
+                            "source, using an up-to-date compiler\n" +
+                            "and without specifying any \"-target\" type " +
+                            "options. The consequence of ignoring\n" +
+                            "this warning is that reflective operations " +
+                            "on this class will incorrectly\n" +
+                            "indicate that it is *not* an inner class.");
+                }
+                result.add(AnnotationUtils.makeEnclosingClass(
+                                   foundThisClass.getOuterClass()));
+            }
+        }
+
+        if (membersSize != 0) {
+            StdTypeList typeList = new StdTypeList(membersSize);
+            for (int i = 0; i < membersSize; i++) {
+                typeList.set(i, membersList.get(i));
+            }
+            typeList.setImmutable();
+            result.add(AnnotationUtils.makeMemberClasses(typeList));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Gets the parameter annotations out of a given method. This
+     * combines both visible and invisible annotations into a single
+     * result set.
+     *
+     * @param method {@code non-null;} the method in question
+     * @return {@code non-null;} the list of annotation sets, which may be
+     * empty
+     */
+    public static AnnotationsList getParameterAnnotations(Method method) {
+        AttributeList attribs = method.getAttributes();
+        AttRuntimeVisibleParameterAnnotations visible =
+            (AttRuntimeVisibleParameterAnnotations)
+            attribs.findFirst(
+                    AttRuntimeVisibleParameterAnnotations.ATTRIBUTE_NAME);
+        AttRuntimeInvisibleParameterAnnotations invisible =
+            (AttRuntimeInvisibleParameterAnnotations)
+            attribs.findFirst(
+                    AttRuntimeInvisibleParameterAnnotations.ATTRIBUTE_NAME);
+
+        if (visible == null) {
+            if (invisible == null) {
+                return AnnotationsList.EMPTY;
+            }
+            return invisible.getParameterAnnotations();
+        }
+
+        if (invisible == null) {
+            return visible.getParameterAnnotations();
+        }
+
+        // Both are non-null, so combine them.
+
+        return AnnotationsList.combine(visible.getParameterAnnotations(),
+                invisible.getParameterAnnotations());
+    }
+
+    /**
+     * Gets the {@code AnnotationDefault} attributes out of a
+     * given class, if any, reforming them as an
+     * {@code AnnotationDefault} annotation.
+     *
+     * @param cf {@code non-null;} the class in question
+     * @return {@code null-ok;} an appropriately-constructed
+     * {@code AnnotationDefault} annotation, if there were any
+     * annotation defaults in the class, or {@code null} if not
+     */
+    private static Annotation translateAnnotationDefaults(DirectClassFile cf) {
+        CstType thisClass = cf.getThisClass();
+        MethodList methods = cf.getMethods();
+        int sz = methods.size();
+        Annotation result =
+            new Annotation(thisClass, AnnotationVisibility.EMBEDDED);
+        boolean any = false;
+
+        for (int i = 0; i < sz; i++) {
+            Method one = methods.get(i);
+            AttributeList attribs = one.getAttributes();
+            AttAnnotationDefault oneDefault = (AttAnnotationDefault)
+                attribs.findFirst(AttAnnotationDefault.ATTRIBUTE_NAME);
+
+            if (oneDefault != null) {
+                NameValuePair pair = new NameValuePair(
+                        one.getNat().getName(),
+                        oneDefault.getValue());
+                result.add(pair);
+                any = true;
+            }
+        }
+
+        if (! any) {
+            return null;
+        }
+
+        result.setImmutable();
+        return AnnotationUtils.makeAnnotationDefault(result);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/cf/CfOptions.java b/dx/src/com/android/dx/dex/cf/CfOptions.java
new file mode 100644
index 0000000..468f0be
--- /dev/null
+++ b/dx/src/com/android/dx/dex/cf/CfOptions.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.cf;
+
+import com.android.dx.dex.code.PositionList;
+
+import java.io.PrintStream;
+
+/**
+ * A class to contain options passed into dex.cf
+ */
+public class CfOptions {
+    /** how much source position info to preserve */
+    public int positionInfo = PositionList.LINES;
+
+    /** whether to keep local variable information */
+    public boolean localInfo = false;
+
+    /** whether strict file-name-vs-class-name checking should be done */
+    public boolean strictNameCheck = true;
+
+    /** whether to do SSA/register optimization */
+    public boolean optimize = false;
+
+    /** filename containing list of methods to optimize */
+    public String optimizeListFile = null;
+
+    /** filename containing list of methods <i>not</i> to optimize */
+    public String dontOptimizeListFile = null;
+
+    /** whether to print statistics to stdout at end of compile cycle */
+    public boolean statistics;
+
+    /** where to issue warnings to */
+    public PrintStream warn = System.err;
+}
diff --git a/dx/src/com/android/dx/dex/cf/CfTranslator.java b/dx/src/com/android/dx/dex/cf/CfTranslator.java
new file mode 100644
index 0000000..8b94f91
--- /dev/null
+++ b/dx/src/com/android/dx/dex/cf/CfTranslator.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.cf;
+
+import com.android.dx.cf.code.ConcreteMethod;
+import com.android.dx.cf.code.Ropper;
+import com.android.dx.cf.direct.DirectClassFile;
+import com.android.dx.cf.direct.StdAttributeFactory;
+import com.android.dx.cf.iface.Field;
+import com.android.dx.cf.iface.FieldList;
+import com.android.dx.cf.iface.Method;
+import com.android.dx.cf.iface.MethodList;
+import com.android.dx.dex.DexOptions;
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.dex.code.RopTranslator;
+import com.android.dx.dex.file.ClassDefItem;
+import com.android.dx.dex.file.EncodedField;
+import com.android.dx.dex.file.EncodedMethod;
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.code.LocalVariableExtractor;
+import com.android.dx.rop.code.LocalVariableInfo;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.DexTranslationAdvice;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstBoolean;
+import com.android.dx.rop.cst.CstByte;
+import com.android.dx.rop.cst.CstChar;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstShort;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.TypedConstant;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.ssa.Optimizer;
+import com.android.dx.util.ExceptionWithContext;
+
+/**
+ * Static method that turns {@code byte[]}s containing Java
+ * classfiles into {@link ClassDefItem} instances.
+ */
+public class CfTranslator {
+    /** set to {@code true} to enable development-time debugging code */
+    private static final boolean DEBUG = false;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private CfTranslator() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Takes a {@code byte[]}, interprets it as a Java classfile, and
+     * translates it into a {@link ClassDefItem}.
+     *
+     * @param filePath {@code non-null;} the file path for the class,
+     * excluding any base directory specification
+     * @param bytes {@code non-null;} contents of the file
+     * @param cfOptions options for class translation
+     * @param dexOptions options for dex output
+     * @return {@code non-null;} the translated class
+     */
+    public static ClassDefItem translate(String filePath, byte[] bytes,
+            CfOptions cfOptions, DexOptions dexOptions) {
+        try {
+            return translate0(filePath, bytes, cfOptions, dexOptions);
+        } catch (RuntimeException ex) {
+            String msg = "...while processing " + filePath;
+            throw ExceptionWithContext.withContext(ex, msg);
+        }
+    }
+
+    /**
+     * Performs the main act of translation. This method is separated
+     * from {@link #translate} just to keep things a bit simpler in
+     * terms of exception handling.
+     *
+     * @param filePath {@code non-null;} the file path for the class,
+     * excluding any base directory specification
+     * @param bytes {@code non-null;} contents of the file
+     * @param cfOptions options for class translation
+     * @param dexOptions options for dex output
+     * @return {@code non-null;} the translated class
+     */
+    private static ClassDefItem translate0(String filePath, byte[] bytes,
+            CfOptions cfOptions, DexOptions dexOptions) {
+        DirectClassFile cf =
+            new DirectClassFile(bytes, filePath, cfOptions.strictNameCheck);
+
+        cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
+        cf.getMagic();
+
+        OptimizerOptions.loadOptimizeLists(cfOptions.optimizeListFile,
+                cfOptions.dontOptimizeListFile);
+
+        // Build up a class to output.
+
+        CstType thisClass = cf.getThisClass();
+        int classAccessFlags = cf.getAccessFlags() & ~AccessFlags.ACC_SUPER;
+        CstString sourceFile = (cfOptions.positionInfo == PositionList.NONE) ? null :
+            cf.getSourceFile();
+        ClassDefItem out =
+            new ClassDefItem(thisClass, classAccessFlags,
+                    cf.getSuperclass(), cf.getInterfaces(), sourceFile);
+
+        Annotations classAnnotations =
+            AttributeTranslator.getClassAnnotations(cf, cfOptions);
+        if (classAnnotations.size() != 0) {
+            out.setClassAnnotations(classAnnotations);
+        }
+
+        processFields(cf, out);
+        processMethods(cf, cfOptions, dexOptions, out);
+
+        return out;
+    }
+
+    /**
+     * Processes the fields of the given 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();
+        FieldList fields = cf.getFields();
+        int sz = fields.size();
+
+        for (int i = 0; i < sz; i++) {
+            Field one = fields.get(i);
+            try {
+                CstFieldRef field = new CstFieldRef(thisClass, one.getNat());
+                int accessFlags = one.getAccessFlags();
+
+                if (AccessFlags.isStatic(accessFlags)) {
+                    TypedConstant constVal = one.getConstantValue();
+                    EncodedField fi = new EncodedField(field, accessFlags);
+                    if (constVal != null) {
+                        constVal = coerceConstant(constVal, field.getType());
+                    }
+                    out.addStaticField(fi, constVal);
+                } else {
+                    EncodedField fi = new EncodedField(field, accessFlags);
+                    out.addInstanceField(fi);
+                }
+
+                Annotations annotations =
+                    AttributeTranslator.getAnnotations(one.getAttributes());
+                if (annotations.size() != 0) {
+                    out.addFieldAnnotations(field, annotations);
+                }
+            } catch (RuntimeException ex) {
+                String msg = "...while processing " + one.getName().toHuman() +
+                    " " + one.getDescriptor().toHuman();
+                throw ExceptionWithContext.withContext(ex, msg);
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #processFields}, which translates constants into
+     * more specific types if necessary.
+     *
+     * @param constant {@code non-null;} the constant in question
+     * @param type {@code non-null;} the desired type
+     */
+    private static TypedConstant coerceConstant(TypedConstant constant,
+            Type type) {
+        Type constantType = constant.getType();
+
+        if (constantType.equals(type)) {
+            return constant;
+        }
+
+        switch (type.getBasicType()) {
+            case Type.BT_BOOLEAN: {
+                return CstBoolean.make(((CstInteger) constant).getValue());
+            }
+            case Type.BT_BYTE: {
+                return CstByte.make(((CstInteger) constant).getValue());
+            }
+            case Type.BT_CHAR: {
+                return CstChar.make(((CstInteger) constant).getValue());
+            }
+            case Type.BT_SHORT: {
+                return CstShort.make(((CstInteger) constant).getValue());
+            }
+            default: {
+                throw new UnsupportedOperationException("can't coerce " +
+                        constant + " to " + type);
+            }
+        }
+    }
+
+    /**
+     * Processes the methods of the given class.
+     *
+     * @param cf {@code non-null;} class being translated
+     * @param cfOptions {@code non-null;} options for class translation
+     * @param dexOptions {@code non-null;} options for dex output
+     * @param out {@code non-null;} output class
+     */
+    private static void processMethods(DirectClassFile cf, CfOptions cfOptions,
+            DexOptions dexOptions, ClassDefItem out) {
+        CstType thisClass = cf.getThisClass();
+        MethodList methods = cf.getMethods();
+        int sz = methods.size();
+
+        for (int i = 0; i < sz; i++) {
+            Method one = methods.get(i);
+            try {
+                CstMethodRef meth = new CstMethodRef(thisClass, one.getNat());
+                int accessFlags = one.getAccessFlags();
+                boolean isStatic = AccessFlags.isStatic(accessFlags);
+                boolean isPrivate = AccessFlags.isPrivate(accessFlags);
+                boolean isNative = AccessFlags.isNative(accessFlags);
+                boolean isAbstract = AccessFlags.isAbstract(accessFlags);
+                boolean isConstructor = meth.isInstanceInit() ||
+                    meth.isClassInit();
+                DalvCode code;
+
+                if (isNative || isAbstract) {
+                    // There's no code for native or abstract methods.
+                    code = null;
+                } else {
+                    ConcreteMethod concrete =
+                        new ConcreteMethod(one, cf,
+                                (cfOptions.positionInfo != PositionList.NONE),
+                                cfOptions.localInfo);
+
+                    TranslationAdvice advice;
+
+                    advice = DexTranslationAdvice.THE_ONE;
+
+                    RopMethod rmeth = Ropper.convert(concrete, advice);
+                    RopMethod nonOptRmeth = null;
+                    int paramSize;
+
+                    paramSize = meth.getParameterWordCount(isStatic);
+
+                    String canonicalName
+                            = thisClass.getClassType().getDescriptor()
+                                + "." + one.getName().getString();
+
+                    if (cfOptions.optimize &&
+                            OptimizerOptions.shouldOptimize(canonicalName)) {
+                        if (DEBUG) {
+                            System.err.println("Optimizing " + canonicalName);
+                        }
+
+                        nonOptRmeth = rmeth;
+                        rmeth = Optimizer.optimize(rmeth,
+                                paramSize, isStatic, cfOptions.localInfo, advice);
+
+                        if (DEBUG) {
+                            OptimizerOptions.compareOptimizerStep(nonOptRmeth,
+                                    paramSize, isStatic, cfOptions, advice, rmeth);
+                        }
+
+                        if (cfOptions.statistics) {
+                            CodeStatistics.updateRopStatistics(
+                                    nonOptRmeth, rmeth);
+                        }
+                    }
+
+                    LocalVariableInfo locals = null;
+
+                    if (cfOptions.localInfo) {
+                        locals = LocalVariableExtractor.extract(rmeth);
+                    }
+
+                    code = RopTranslator.translate(rmeth, cfOptions.positionInfo,
+                            locals, paramSize, dexOptions);
+
+                    if (cfOptions.statistics && nonOptRmeth != null) {
+                        updateDexStatistics(cfOptions, dexOptions, rmeth, nonOptRmeth, locals,
+                                paramSize, concrete.getCode().size());
+                    }
+                }
+
+                // Preserve the synchronized flag as its "declared" variant...
+                if (AccessFlags.isSynchronized(accessFlags)) {
+                    accessFlags |= AccessFlags.ACC_DECLARED_SYNCHRONIZED;
+
+                    /*
+                     * ...but only native methods are actually allowed to be
+                     * synchronized.
+                     */
+                    if (!isNative) {
+                        accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED;
+                    }
+                }
+
+                if (isConstructor) {
+                    accessFlags |= AccessFlags.ACC_CONSTRUCTOR;
+                }
+
+                TypeList exceptions = AttributeTranslator.getExceptions(one);
+                EncodedMethod mi =
+                    new EncodedMethod(meth, accessFlags, code, exceptions);
+
+                if (meth.isInstanceInit() || meth.isClassInit() ||
+                    isStatic || isPrivate) {
+                    out.addDirectMethod(mi);
+                } else {
+                    out.addVirtualMethod(mi);
+                }
+
+                Annotations annotations =
+                    AttributeTranslator.getMethodAnnotations(one);
+                if (annotations.size() != 0) {
+                    out.addMethodAnnotations(meth, annotations);
+                }
+
+                AnnotationsList list =
+                    AttributeTranslator.getParameterAnnotations(one);
+                if (list.size() != 0) {
+                    out.addParameterAnnotations(meth, list);
+                }
+            } catch (RuntimeException ex) {
+                String msg = "...while processing " + one.getName().toHuman() +
+                    " " + one.getDescriptor().toHuman();
+                throw ExceptionWithContext.withContext(ex, msg);
+            }
+        }
+    }
+
+    /**
+     * Helper that updates the dex statistics.
+     */
+    private static void updateDexStatistics(CfOptions cfOptions, DexOptions dexOptions,
+            RopMethod optRmeth, RopMethod nonOptRmeth,
+            LocalVariableInfo locals, int paramSize, int originalByteCount) {
+        /*
+         * Run rop->dex again on optimized vs. non-optimized method to
+         * collect statistics. We have to totally convert both ways,
+         * since converting the "real" method getting added to the
+         * file would corrupt it (by messing with its constant pool
+         * indices).
+         */
+
+        DalvCode optCode = RopTranslator.translate(optRmeth,
+                cfOptions.positionInfo, locals, paramSize, dexOptions);
+        DalvCode nonOptCode = RopTranslator.translate(nonOptRmeth,
+                cfOptions.positionInfo, locals, paramSize, dexOptions);
+
+        /*
+         * Fake out the indices, so code.getInsns() can work well enough
+         * for the current purpose.
+         */
+
+        DalvCode.AssignIndicesCallback callback =
+            new DalvCode.AssignIndicesCallback() {
+                public int getIndex(Constant cst) {
+                    // Everything is at index 0!
+                    return 0;
+                }
+            };
+
+        optCode.assignIndices(callback);
+        nonOptCode.assignIndices(callback);
+
+        CodeStatistics.updateDexStatistics(nonOptCode, optCode);
+        CodeStatistics.updateOriginalByteCount(originalByteCount);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/cf/CodeStatistics.java b/dx/src/com/android/dx/dex/cf/CodeStatistics.java
new file mode 100644
index 0000000..33d03fd
--- /dev/null
+++ b/dx/src/com/android/dx/dex/cf/CodeStatistics.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.cf;
+
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.rop.code.RopMethod;
+
+import java.io.PrintStream;
+
+/**
+ * Static methods and variables for collecting statistics on generated
+ * code.
+ */
+public final class CodeStatistics {
+    /** set to {@code true} to enable development-time debugging code */
+    private static final boolean DEBUG = false;
+
+    /**
+     * running sum of the number of registers added/removed in
+     * SSA form by the optimizer
+     */
+    public static int runningDeltaRegisters = 0;
+
+    /**
+     * running sum of the number of insns added/removed in
+     * SSA form by the optimizer
+     */
+    public static int runningDeltaInsns = 0;
+
+    /** running sum of the total number of Rop insns processed */
+    public static int runningTotalInsns = 0;
+
+    /**
+     * running sum of the number of dex-form registers added/removed in
+     * SSA form by the optimizer. Only valid if args.statistics is true.
+     */
+    public static int dexRunningDeltaRegisters = 0;
+
+    /**
+     * running sum of the number of dex-form insns (actually code
+     * units) added/removed in SSA form by the optimizer. Only valid
+     * if args.statistics is true.
+     */
+    public static int dexRunningDeltaInsns = 0;
+
+    /**
+     * running sum of the total number of dex insns (actually code
+     * units) processed
+     */
+    public static int dexRunningTotalInsns = 0;
+
+    /** running sum of original class bytecode bytes */
+    public static int runningOriginalBytes = 0;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private CodeStatistics() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Updates the number of original bytecode bytes processed.
+     *
+     * @param count {@code >= 0;} the number of bytes to add
+     */
+    public static void updateOriginalByteCount(int count) {
+        runningOriginalBytes += count;
+    }
+
+    /**
+     * Updates the dex statistics.
+     *
+     * @param nonOptCode non-optimized code block
+     * @param code optimized code block
+     */
+    public static void updateDexStatistics(DalvCode nonOptCode,
+            DalvCode code) {
+        if (DEBUG) {
+            System.err.println("dex insns (old/new) "
+                    + nonOptCode.getInsns().codeSize()
+                    + "/" + code.getInsns().codeSize()
+                    + " regs (o/n) "
+                    + nonOptCode.getInsns().getRegistersSize()
+                    + "/" + code.getInsns().getRegistersSize()
+            );
+        }
+
+        dexRunningDeltaInsns
+            += (code.getInsns().codeSize()
+                - nonOptCode.getInsns().codeSize());
+
+        dexRunningDeltaRegisters
+            += (code.getInsns().getRegistersSize()
+                - nonOptCode.getInsns().getRegistersSize());
+
+        dexRunningTotalInsns += code.getInsns().codeSize();
+    }
+
+    /**
+     * Updates the ROP statistics.
+     *
+     * @param nonOptRmeth non-optimized method
+     * @param rmeth optimized method
+     */
+    public static void updateRopStatistics(RopMethod nonOptRmeth,
+            RopMethod rmeth) {
+        int oldCountInsns
+                = nonOptRmeth.getBlocks().getEffectiveInstructionCount();
+        int oldCountRegs = nonOptRmeth.getBlocks().getRegCount();
+
+        if (DEBUG) {
+            System.err.println("insns (old/new): "
+                    + oldCountInsns + "/"
+                    + rmeth.getBlocks().getEffectiveInstructionCount()
+                    + " regs (o/n):" + oldCountRegs
+                    + "/"  +  rmeth.getBlocks().getRegCount());
+        }
+
+        int newCountInsns
+                = rmeth.getBlocks().getEffectiveInstructionCount();
+
+        runningDeltaInsns
+            += (newCountInsns - oldCountInsns);
+
+        runningDeltaRegisters
+            += (rmeth.getBlocks().getRegCount() - oldCountRegs);
+
+        runningTotalInsns += newCountInsns;
+    }
+
+    /**
+     * Prints out the collected statistics.
+     *
+     * @param out {@code non-null;} where to output to
+     */
+    public static void dumpStatistics(PrintStream out) {
+        out.printf("Optimizer Delta Rop Insns: %d total: %d "
+                + "(%.2f%%) Delta Registers: %d\n",
+                runningDeltaInsns,
+                runningTotalInsns,
+                (100.0 * (((float) runningDeltaInsns)
+                        / (runningTotalInsns + Math.abs(runningDeltaInsns)))),
+                runningDeltaRegisters);
+
+        out.printf("Optimizer Delta Dex Insns: Insns: %d total: %d "
+                + "(%.2f%%) Delta Registers: %d\n",
+                dexRunningDeltaInsns,
+                dexRunningTotalInsns,
+                (100.0 * (((float) dexRunningDeltaInsns)
+                        / (dexRunningTotalInsns
+                                + Math.abs(dexRunningDeltaInsns)))),
+                dexRunningDeltaRegisters);
+
+        out.printf("Original bytecode byte count: %d\n",
+                runningOriginalBytes);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
new file mode 100644
index 0000000..a66421e
--- /dev/null
+++ b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.cf;
+
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.ssa.Optimizer;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.HashSet;
+
+/**
+ * Settings for optimization of code.
+ */
+public class OptimizerOptions {
+    /**
+     * {@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;
+
+    /**
+     * {@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
+     */
+    private static HashSet<String> dontOptimizeList;
+
+    /** true if the above lists have been loaded */
+    private static boolean optimizeListsLoaded;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private OptimizerOptions() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Loads the optimize/don't optimize lists from files.
+     *
+     * @param optimizeListFile Pathname
+     * @param dontOptimizeListFile Pathname
+     */
+    public static void loadOptimizeLists(String optimizeListFile,
+            String dontOptimizeListFile) {
+        if (optimizeListsLoaded) {
+            return;
+        }
+
+        if (optimizeListFile != null && dontOptimizeListFile != null) {
+            /*
+             * We shouldn't get this far. The condition should have
+             * been caught in the arg processor.
+             */
+            throw new RuntimeException("optimize and don't optimize lists "
+                    + " are mutually exclusive.");
+        }
+
+        if (optimizeListFile != null) {
+            optimizeList = loadStringsFromFile(optimizeListFile);
+        }
+
+        if (dontOptimizeListFile != null) {
+            dontOptimizeList = loadStringsFromFile(dontOptimizeListFile);
+        }
+
+        optimizeListsLoaded = true;
+    }
+
+    /**
+     * Loads a list of newline-separated strings into a new HashSet and returns
+     * the HashSet.
+     *
+     * @param filename filename to process
+     * @return set of all unique lines in the file
+     */
+    private static HashSet<String> loadStringsFromFile(String filename) {
+        HashSet<String> result = new HashSet<String>();
+
+        try {
+            FileReader fr = new FileReader(filename);
+            BufferedReader bfr = new BufferedReader(fr);
+
+            String line;
+
+            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: " +
+                    filename, ex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Compares the output of the optimizer run normally with a run skipping
+     * some optional steps. Results are printed to stderr.
+     *
+     * @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 {@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,
+            TranslationAdvice advice, RopMethod rmeth) {
+        EnumSet<Optimizer.OptionalStep> steps;
+
+        steps = EnumSet.allOf(Optimizer.OptionalStep.class);
+
+        // This is the step to skip.
+        steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR);
+
+        RopMethod skipRopMethod
+                = Optimizer.optimize(nonOptRmeth,
+                        paramSize, isStatic, args.localInfo, advice, steps);
+
+        int normalInsns
+                = rmeth.getBlocks().getEffectiveInstructionCount();
+        int skipInsns
+                = skipRopMethod.getBlocks().getEffectiveInstructionCount();
+
+        System.err.printf(
+                "optimize step regs:(%d/%d/%.2f%%)"
+                + " insns:(%d/%d/%.2f%%)\n",
+                rmeth.getBlocks().getRegCount(),
+                skipRopMethod.getBlocks().getRegCount(),
+                100.0 * ((skipRopMethod.getBlocks().getRegCount()
+                        - rmeth.getBlocks().getRegCount())
+                        / (float) skipRopMethod.getBlocks().getRegCount()),
+                normalInsns, skipInsns,
+                100.0 * ((skipInsns - normalInsns) / (float) skipInsns));
+    }
+
+    /**
+     * Checks whether the specified method should be optimized
+     *
+     * @param canonicalMethodName name of method being considered
+     * @return true if it should be optimized
+     */
+    public static boolean shouldOptimize(String canonicalMethodName) {
+        // Optimize only what's in the optimize list.
+        if (optimizeList != null) {
+            return optimizeList.contains(canonicalMethodName);
+        }
+
+        /*
+         * Or don't optimize what's listed here. (The two lists are
+         * mutually exclusive.
+         */
+
+        if (dontOptimizeList != null) {
+            return !dontOptimizeList.contains(canonicalMethodName);
+        }
+
+        // If neither list has been specified, then optimize everything.
+        return true;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/cf/package.html b/dx/src/com/android/dx/dex/cf/package.html
new file mode 100644
index 0000000..d56e8a7
--- /dev/null
+++ b/dx/src/com/android/dx/dex/cf/package.html
@@ -0,0 +1,15 @@
+<body>
+<p>Classes for translating Java classfiles into Dalvik classes.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.cf.code</code></li>
+<li><code>com.android.dx.cf.direct</code></li>
+<li><code>com.android.dx.cf.iface</code></li>
+<li><code>com.android.dx.dex.code</code></li>
+<li><code>com.android.dx.dex.file</code></li>
+<li><code>com.android.dx.rop.code</code></li>
+<li><code>com.android.dx.rop.cst</code></li>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/dex/code/ArrayData.java b/dx/src/com/android/dx/dex/code/ArrayData.java
new file mode 100644
index 0000000..6674b75
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/ArrayData.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.io.Opcodes;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.cst.*;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.rop.type.Type;
+import java.util.ArrayList;
+
+/**
+ * Pseudo-instruction which holds fill array data.
+ */
+public final class ArrayData extends VariableSizeInsn {
+    /**
+     * {@code non-null;} address representing the instruction that uses this
+     * instance
+     */
+    private final CodeAddress user;
+
+    /** {@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 */
+    private final Constant arrayType;
+
+    /** Width of the init value element */
+    private final int elemWidth;
+
+    /** Length of the init list */
+    private final int initLength;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param user {@code non-null;} address representing the instruction that
+     * uses this instance
+     * @param values {@code non-null;} initial values to be filled into an array
+     */
+    public ArrayData(SourcePosition position, CodeAddress user,
+                     ArrayList<Constant> values,
+                     Constant arrayType) {
+        super(position, RegisterSpecList.EMPTY);
+
+        if (user == null) {
+            throw new NullPointerException("user == null");
+        }
+
+        if (values == null) {
+            throw new NullPointerException("values == null");
+        }
+
+        int sz = values.size();
+
+        if (sz <= 0) {
+            throw new IllegalArgumentException("Illegal number of init values");
+        }
+
+        this.arrayType = arrayType;
+
+        if (arrayType == CstType.BYTE_ARRAY ||
+                arrayType == CstType.BOOLEAN_ARRAY) {
+            elemWidth = 1;
+        } else if (arrayType == CstType.SHORT_ARRAY ||
+                arrayType == CstType.CHAR_ARRAY) {
+            elemWidth = 2;
+        } else if (arrayType == CstType.INT_ARRAY ||
+                arrayType == CstType.FLOAT_ARRAY) {
+            elemWidth = 4;
+        } else if (arrayType == CstType.LONG_ARRAY ||
+                arrayType == CstType.DOUBLE_ARRAY) {
+            elemWidth = 8;
+        } else {
+            throw new IllegalArgumentException("Unexpected constant type");
+        }
+        this.user = user;
+        this.values = values;
+        initLength = values.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        int sz = initLength;
+        // Note: the unit here is 16-bit
+        return 4 + ((sz * elemWidth) + 1) / 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        int sz = values.size();
+
+        out.writeShort(Opcodes.FILL_ARRAY_DATA_PAYLOAD);
+        out.writeShort(elemWidth);
+        out.writeInt(initLength);
+
+
+        // For speed reasons, replicate the for loop in each case
+        switch (elemWidth) {
+            case 1: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeByte((byte) ((CstLiteral32) cst).getIntBits());
+                }
+                break;
+            }
+            case 2: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeShort((short) ((CstLiteral32) cst).getIntBits());
+                }
+                break;
+            }
+            case 4: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeInt(((CstLiteral32) cst).getIntBits());
+                }
+                break;
+            }
+            case 8: {
+                for (int i = 0; i < sz; i++) {
+                    Constant cst = values.get(i);
+                    out.writeLong(((CstLiteral64) cst).getLongBits());
+                }
+                break;
+            }
+            default:
+                break;
+        }
+
+        // Pad one byte to make the size of data table multiples of 16-bits
+        if (elemWidth == 1 && (sz % 2 != 0)) {
+            out.writeByte(0x00);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new ArrayData(getPosition(), user, values, arrayType);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        int sz = values.size();
+        for (int i = 0; i < sz; i++) {
+            sb.append("\n    ");
+            sb.append(i);
+            sb.append(": ");
+            sb.append(values.get(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        int baseAddress = user.getAddress();
+        StringBuffer sb = new StringBuffer(100);
+        int sz = values.size();
+
+        sb.append("fill-array-data-payload // for fill-array-data @ ");
+        sb.append(Hex.u2(baseAddress));
+
+        for (int i = 0; i < sz; i++) {
+            sb.append("\n  ");
+            sb.append(i);
+            sb.append(": ");
+            sb.append(values.get(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/BlockAddresses.java b/dx/src/com/android/dx/dex/code/BlockAddresses.java
new file mode 100644
index 0000000..1a1d184
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/BlockAddresses.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Container for the set of {@link CodeAddress} instances associated with
+ * the blocks of a particular method. Each block has a corresponding
+ * start address, end address, and last instruction address.
+ */
+public final class BlockAddresses {
+    /** {@code non-null;} array containing addresses for the start of each basic
+     * block (indexed by basic block label) */
+    private final CodeAddress[] starts;
+
+    /** {@code non-null;} array containing addresses for the final instruction
+     * of each basic block (indexed by basic block label) */
+    private final CodeAddress[] lasts;
+
+    /** {@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;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method to have block addresses for
+     */
+    public BlockAddresses(RopMethod method) {
+        BasicBlockList blocks = method.getBlocks();
+        int maxLabel = blocks.getMaxLabel();
+
+        this.starts = new CodeAddress[maxLabel];
+        this.lasts = new CodeAddress[maxLabel];
+        this.ends = new CodeAddress[maxLabel];
+
+        setupArrays(method);
+    }
+
+    /**
+     * Gets the instance for the start of the given block.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getStart(BasicBlock block) {
+        return starts[block.getLabel()];
+    }
+
+    /**
+     * Gets the instance for the start of the block with the given label.
+     *
+     * @param label {@code non-null;} the label of the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getStart(int label) {
+        return starts[label];
+    }
+
+    /**
+     * Gets the instance for the final instruction of the given block.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getLast(BasicBlock block) {
+        return lasts[block.getLabel()];
+    }
+
+    /**
+     * Gets the instance for the final instruction of the block with
+     * the given label.
+     *
+     * @param label {@code non-null;} the label of the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getLast(int label) {
+        return lasts[label];
+    }
+
+    /**
+     * Gets the instance for the end (address after the final instruction)
+     * of the given block.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getEnd(BasicBlock block) {
+        return ends[block.getLabel()];
+    }
+
+    /**
+     * Gets the instance for the end (address after the final instruction)
+     * of the block with the given label.
+     *
+     * @param label {@code non-null;} the label of the block in question
+     * @return {@code non-null;} the appropriate instance
+     */
+    public CodeAddress getEnd(int label) {
+        return ends[label];
+    }
+
+    /**
+     * Sets up the address arrays.
+     */
+    private void setupArrays(RopMethod method) {
+        BasicBlockList blocks = method.getBlocks();
+        int sz = blocks.size();
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = blocks.get(i);
+            int label = one.getLabel();
+            Insn insn = one.getInsns().get(0);
+
+            starts[label] = new CodeAddress(insn.getPosition());
+
+            SourcePosition pos = one.getLastInsn().getPosition();
+
+            lasts[label] = new CodeAddress(pos);
+            ends[label] = new CodeAddress(pos);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/CatchBuilder.java b/dx/src/com/android/dx/dex/code/CatchBuilder.java
new file mode 100644
index 0000000..90d2e8d
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/CatchBuilder.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.type.Type;
+
+import java.util.HashSet;
+
+/**
+ * Interface for the construction of {@link CatchTable} instances.
+ */
+public interface CatchBuilder {
+    /**
+     * Builds and returns the catch table for this instance.
+     *
+     * @return {@code non-null;} the constructed table
+     */
+    public CatchTable build();
+
+    /**
+     * Gets whether this instance has any catches at all (either typed
+     * or catch-all).
+     *
+     * @return whether this instance has any catches at all
+     */
+    public boolean hasAnyCatches();
+
+    /**
+     * Gets the set of catch types associated with this instance.
+     *
+     * @return {@code non-null;} the set of catch types
+     */
+    public HashSet<Type> getCatchTypes();
+}
diff --git a/dx/src/com/android/dx/dex/code/CatchHandlerList.java b/dx/src/com/android/dx/dex/code/CatchHandlerList.java
new file mode 100644
index 0000000..8472584
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/CatchHandlerList.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.FixedSizeList;
+import com.android.dx.util.Hex;
+
+/**
+ * Ordered list of (exception type, handler address) entries.
+ */
+public final class CatchHandlerList extends FixedSizeList
+        implements Comparable<CatchHandlerList> {
+    /** {@code non-null;} empty instance */
+    public static final CatchHandlerList EMPTY = new CatchHandlerList(0);
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size {@code >= 0;} the size of the list
+     */
+    public CatchHandlerList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toHuman("", "");
+    }
+
+    /**
+     * Get the human form of this instance, prefixed on each line
+     * with the string.
+     *
+     * @param prefix {@code non-null;} the prefix for every line
+     * @param header {@code non-null;} the header for the first line (after the
+     * first prefix)
+     * @return {@code non-null;} the human form
+     */
+    public String toHuman(String prefix, String header) {
+        StringBuilder sb = new StringBuilder(100);
+        int size = size();
+
+        sb.append(prefix);
+        sb.append(header);
+        sb.append("catch ");
+
+        for (int i = 0; i < size; i++) {
+            Entry entry = get(i);
+
+            if (i != 0) {
+                sb.append(",\n");
+                sb.append(prefix);
+                sb.append("  ");
+            }
+
+            if ((i == (size - 1)) && catchesAll()) {
+                sb.append("<any>");
+            } else {
+                sb.append(entry.getExceptionType().toHuman());
+            }
+
+            sb.append(" -> ");
+            sb.append(Hex.u2or4(entry.getHandler()));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns whether or not this instance ends with a "catch-all"
+     * handler.
+     *
+     * @return {@code true} if this instance ends with a "catch-all"
+     * handler or {@code false} if not
+     */
+    public boolean catchesAll() {
+        int size = size();
+
+        if (size == 0) {
+            return false;
+        }
+
+        Entry last = get(size - 1);
+        return last.getExceptionType().equals(CstType.OBJECT);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @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));
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(CatchHandlerList other) {
+        if (this == other) {
+            // Easy out.
+            return 0;
+        }
+
+        int thisSize = size();
+        int otherSize = other.size();
+        int checkSize = Math.min(thisSize, otherSize);
+
+        for (int i = 0; i < checkSize; i++) {
+            Entry thisEntry = get(i);
+            Entry otherEntry = other.get(i);
+            int compare = thisEntry.compareTo(otherEntry);
+            if (compare != 0) {
+                return compare;
+            }
+        }
+
+        if (thisSize < otherSize) {
+            return -1;
+        } else if (thisSize > otherSize) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Entry in the list.
+     */
+    public static class Entry implements Comparable<Entry> {
+        /** {@code non-null;} type of exception handled */
+        private final CstType exceptionType;
+
+        /** {@code >= 0;} exception handler address */
+        private final int handler;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("handler < 0");
+            }
+
+            if (exceptionType == null) {
+                throw new NullPointerException("exceptionType == null");
+            }
+
+            this.handler = handler;
+            this.exceptionType = exceptionType;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            return (handler * 31) + exceptionType.hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof Entry) {
+                return (compareTo((Entry) other) == 0);
+            }
+
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(Entry other) {
+            if (handler < other.handler) {
+                return -1;
+            } else if (handler > other.handler) {
+                return 1;
+            }
+
+            return exceptionType.compareTo(other.exceptionType);
+        }
+
+        /**
+         * Gets the exception type handled.
+         *
+         * @return {@code non-null;} the exception type
+         */
+        public CstType getExceptionType() {
+            return exceptionType;
+        }
+
+        /**
+         * Gets 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
new file mode 100644
index 0000000..0ee890f
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/CatchTable.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * Table of catch entries. Each entry includes a range of code
+ * addresses for which it is valid and an associated {@link
+ * CatchHandlerList}.
+ */
+public final class CatchTable extends FixedSizeList
+        implements Comparable<CatchTable> {
+    /** {@code non-null;} empty instance */
+    public static final CatchTable EMPTY = new CatchTable(0);
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size {@code >= 0;} the size of the table
+     */
+    public CatchTable(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(CatchTable other) {
+        if (this == other) {
+            // Easy out.
+            return 0;
+        }
+
+        int thisSize = size();
+        int otherSize = other.size();
+        int checkSize = Math.min(thisSize, otherSize);
+
+        for (int i = 0; i < checkSize; i++) {
+            Entry thisEntry = get(i);
+            Entry otherEntry = other.get(i);
+            int compare = thisEntry.compareTo(otherEntry);
+            if (compare != 0) {
+                return compare;
+            }
+        }
+
+        if (thisSize < otherSize) {
+            return -1;
+        } else if (thisSize > otherSize) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Entry in a catch list.
+     */
+    public static class Entry implements Comparable<Entry> {
+        /** {@code >= 0;} start address */
+        private final int start;
+
+        /** {@code > start;} end address (exclusive) */
+        private final int end;
+
+        /** {@code non-null;} list of catch handlers */
+        private final CatchHandlerList handlers;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("start < 0");
+            }
+
+            if (end <= start) {
+                throw new IllegalArgumentException("end <= start");
+            }
+
+            if (handlers.isMutable()) {
+                throw new IllegalArgumentException("handlers.isMutable()");
+            }
+
+            this.start = start;
+            this.end = end;
+            this.handlers = handlers;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            int hash = (start * 31) + end;
+            hash = (hash * 31) + handlers.hashCode();
+            return hash;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof Entry) {
+                return (compareTo((Entry) other) == 0);
+            }
+
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(Entry other) {
+            if (start < other.start) {
+                return -1;
+            } else if (start > other.start) {
+                return 1;
+            }
+
+            if (end < other.end) {
+                return -1;
+            } else if (end > other.end) {
+                return 1;
+            }
+
+            return handlers.compareTo(other.handlers);
+        }
+
+        /**
+         * Gets the start address.
+         *
+         * @return {@code >= 0;} the start address
+         */
+        public int getStart() {
+            return start;
+        }
+
+        /**
+         * Gets the end address (exclusive).
+         *
+         * @return {@code > start;} the end address (exclusive)
+         */
+        public int getEnd() {
+            return end;
+        }
+
+        /**
+         * Gets 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
new file mode 100644
index 0000000..5d26bd1
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/CodeAddress.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to track an address within a code
+ * array. Instances are used for such things as branch targets and
+ * exception handler ranges. Its code size is zero, and so instances
+ * do not in general directly wind up in any output (either
+ * human-oriented or binary file).
+ */
+public final class CodeAddress extends ZeroSizeInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     */
+    public CodeAddress(SourcePosition position) {
+        super(position);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withRegisters(RegisterSpecList registers) {
+        return new CodeAddress(getPosition());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        return "code-address";
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/CstInsn.java b/dx/src/com/android/dx/dex/code/CstInsn.java
new file mode 100644
index 0000000..3f848c0
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/CstInsn.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.cst.Constant;
+
+/**
+ * Instruction which has a single constant argument in addition
+ * to all the normal instruction information.
+ */
+public final class CstInsn extends FixedSizeInsn {
+    /** {@code non-null;} the constant argument for this instruction */
+    private final Constant constant;
+
+    /**
+     * {@code >= -1;} the constant pool index for {@link #constant}, or
+     * {@code -1} if not yet set
+     */
+    private int index;
+
+    /**
+     * {@code >= -1;} the constant pool index for the class reference in
+     * {@link #constant} if any, or {@code -1} if not yet set
+     */
+    private int classIndex;
+
+    /**
+     * Constructs an instance. The output address of this instance is
+     * initially unknown ({@code -1}) as is the constant pool index.
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     * @param constant {@code non-null;} constant argument
+     */
+    public CstInsn(Dop opcode, SourcePosition position,
+                   RegisterSpecList registers, Constant constant) {
+        super(opcode, position, registers);
+
+        if (constant == null) {
+            throw new NullPointerException("constant == null");
+        }
+
+        this.constant = constant;
+        this.index = -1;
+        this.classIndex = -1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withOpcode(Dop opcode) {
+        CstInsn result =
+            new CstInsn(opcode, getPosition(), getRegisters(), constant);
+
+        if (index >= 0) {
+            result.setIndex(index);
+        }
+
+        if (classIndex >= 0) {
+            result.setClassIndex(classIndex);
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        CstInsn result =
+            new CstInsn(getOpcode(), getPosition(), registers, constant);
+
+        if (index >= 0) {
+            result.setIndex(index);
+        }
+
+        if (classIndex >= 0) {
+            result.setClassIndex(classIndex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the constant argument.
+     *
+     * @return {@code non-null;} the constant argument
+     */
+    public Constant getConstant() {
+        return constant;
+    }
+
+    /**
+     * Gets the constant's index. It is only valid to call this after
+     * {@link #setIndex} has been called.
+     *
+     * @return {@code >= 0;} the constant pool index
+     */
+    public int getIndex() {
+        if (index < 0) {
+            throw new RuntimeException("index not yet set for " + constant);
+        }
+
+        return index;
+    }
+
+    /**
+     * Returns whether the constant's index has been set for this instance.
+     *
+     * @see #setIndex
+     *
+     * @return {@code true} iff the index has been set
+     */
+    public boolean hasIndex() {
+        return (index >= 0);
+    }
+
+    /**
+     * Sets the constant's index. It is only valid to call this method once
+     * per instance.
+     *
+     * @param index {@code >= 0;} the constant pool index
+     */
+    public void setIndex(int index) {
+        if (index < 0) {
+            throw new IllegalArgumentException("index < 0");
+        }
+
+        if (this.index >= 0) {
+            throw new RuntimeException("index already set");
+        }
+
+        this.index = index;
+    }
+
+    /**
+     * Gets the constant's class index. It is only valid to call this after
+     * {@link #setClassIndex} has been called.
+     *
+     * @return {@code >= 0;} the constant's class's constant pool index
+     */
+    public int getClassIndex() {
+        if (classIndex < 0) {
+            throw new RuntimeException("class index not yet set");
+        }
+
+        return classIndex;
+    }
+
+    /**
+     * Returns whether the constant's class index has been set for this
+     * instance.
+     *
+     * @see #setClassIndex
+     *
+     * @return {@code true} iff the index has been set
+     */
+    public boolean hasClassIndex() {
+        return (classIndex >= 0);
+    }
+
+    /**
+     * Sets the constant's class index. This is the constant pool index
+     * for the class referred to by this instance's constant. Only
+     * reference constants have a class, so it is only on instances
+     * with reference constants that this method should ever be
+     * called. It is only valid to call this method once per instance.
+     *
+     * @param index {@code >= 0;} the constant's class's constant pool index
+     */
+    public void setClassIndex(int index) {
+        if (index < 0) {
+            throw new IllegalArgumentException("index < 0");
+        }
+
+        if (this.classIndex >= 0) {
+            throw new RuntimeException("class index already set");
+        }
+
+        this.classIndex = index;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return constant.toHuman();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/DalvCode.java b/dx/src/com/android/dx/dex/code/DalvCode.java
new file mode 100644
index 0000000..58f191b
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/DalvCode.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.type.Type;
+
+import java.util.HashSet;
+
+/**
+ * Container for all the pieces of a concrete method. Each instance
+ * corresponds to a {@code code} structure in a {@code .dex} file.
+ */
+public final class DalvCode {
+    /**
+     * how much position info to preserve; one of the static
+     * constants in {@link PositionList}
+     */
+    private final int positionInfo;
+
+    /**
+     * {@code null-ok;} the instruction list, ready for final processing;
+     * nulled out in {@link #finishProcessingIfNecessary}
+     */
+    private OutputFinisher unprocessedInsns;
+
+    /**
+     * {@code non-null;} unprocessed catch table;
+     * nulled out in {@link #finishProcessingIfNecessary}
+     */
+    private CatchBuilder unprocessedCatches;
+
+    /**
+     * {@code null-ok;} catch table; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private CatchTable catches;
+
+    /**
+     * {@code null-ok;} source positions list; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private PositionList positions;
+
+    /**
+     * {@code null-ok;} local variable list; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private LocalList locals;
+
+    /**
+     * {@code null-ok;} the processed instruction list; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private DalvInsnList insns;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param positionInfo how much position info to preserve; one of the
+     * static constants in {@link PositionList}
+     * @param unprocessedInsns {@code non-null;} the instruction list, ready
+     * for final processing
+     * @param unprocessedCatches {@code non-null;} unprocessed catch
+     * (exception handler) table
+     */
+    public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
+            CatchBuilder unprocessedCatches) {
+        if (unprocessedInsns == null) {
+            throw new NullPointerException("unprocessedInsns == null");
+        }
+
+        if (unprocessedCatches == null) {
+            throw new NullPointerException("unprocessedCatches == null");
+        }
+
+        this.positionInfo = positionInfo;
+        this.unprocessedInsns = unprocessedInsns;
+        this.unprocessedCatches = unprocessedCatches;
+        this.catches = null;
+        this.positions = null;
+        this.locals = null;
+        this.insns = null;
+    }
+
+    /**
+     * Finish up processing of the method.
+     */
+    private void finishProcessingIfNecessary() {
+        if (insns != null) {
+            return;
+        }
+
+        insns = unprocessedInsns.finishProcessingAndGetList();
+        positions = PositionList.make(insns, positionInfo);
+        locals = LocalList.make(insns);
+        catches = unprocessedCatches.build();
+
+        // Let them be gc'ed.
+        unprocessedInsns = null;
+        unprocessedCatches = null;
+    }
+
+    /**
+     * Assign indices in all instructions that need them, using the
+     * given callback to perform lookups. This must be called before
+     * {@link #getInsns}.
+     *
+     * @param callback {@code non-null;} callback object
+     */
+    public void assignIndices(AssignIndicesCallback callback) {
+        unprocessedInsns.assignIndices(callback);
+    }
+
+    /**
+     * Gets whether this instance has any position data to represent.
+     *
+     * @return {@code true} iff this instance has any position
+     * data to represent
+     */
+    public boolean hasPositions() {
+        return (positionInfo != PositionList.NONE)
+            && unprocessedInsns.hasAnyPositionInfo();
+    }
+
+    /**
+     * Gets whether this instance has any local variable data to represent.
+     *
+     * @return {@code true} iff this instance has any local variable
+     * data to represent
+     */
+    public boolean hasLocals() {
+        return unprocessedInsns.hasAnyLocalInfo();
+    }
+
+    /**
+     * Gets whether this instance has any catches at all (either typed
+     * or catch-all).
+     *
+     * @return whether this instance has any catches at all
+     */
+    public boolean hasAnyCatches() {
+        return unprocessedCatches.hasAnyCatches();
+    }
+
+    /**
+     * Gets the set of catch types handled anywhere in the code.
+     *
+     * @return {@code non-null;} the set of catch types
+     */
+    public HashSet<Type> getCatchTypes() {
+        return unprocessedCatches.getCatchTypes();
+    }
+
+    /**
+     * Gets the set of all constants referred to by instructions in
+     * the code.
+     *
+     * @return {@code non-null;} the set of constants
+     */
+    public HashSet<Constant> getInsnConstants() {
+        return unprocessedInsns.getAllConstants();
+    }
+
+    /**
+     * Gets the list of instructions.
+     *
+     * @return {@code non-null;} the instruction list
+     */
+    public DalvInsnList getInsns() {
+        finishProcessingIfNecessary();
+        return insns;
+    }
+
+    /**
+     * Gets the catch (exception handler) table.
+     *
+     * @return {@code non-null;} the catch table
+     */
+    public CatchTable getCatches() {
+        finishProcessingIfNecessary();
+        return catches;
+    }
+
+    /**
+     * Gets the source positions list.
+     *
+     * @return {@code non-null;} the source positions list
+     */
+    public PositionList getPositions() {
+        finishProcessingIfNecessary();
+        return positions;
+    }
+
+    /**
+     * Gets the source positions list.
+     *
+     * @return {@code non-null;} the source positions list
+     */
+    public LocalList getLocals() {
+        finishProcessingIfNecessary();
+        return locals;
+    }
+
+    /**
+     * Class used as a callback for {@link #assignIndices}.
+     */
+    public static interface AssignIndicesCallback {
+        /**
+         * Gets the index for the given constant.
+         *
+         * @param cst {@code non-null;} the constant
+         * @return {@code >= -1;} the index or {@code -1} if the constant
+         * shouldn't actually be reified with an index
+         */
+        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
new file mode 100644
index 0000000..d0cf395
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/DalvInsn.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.TwoColumnOutput;
+
+import java.util.BitSet;
+
+/**
+ * Base class for Dalvik instructions.
+ */
+public abstract class DalvInsn {
+    /**
+     * the actual output address of this instance, if known, or
+     * {@code -1} if not
+     */
+    private int address;
+
+    /** the opcode; one of the constants from {@link Dops} */
+    private final Dop opcode;
+
+    /** {@code non-null;} source position */
+    private final SourcePosition position;
+
+    /** {@code non-null;} list of register arguments */
+    private final RegisterSpecList registers;
+
+    /**
+     * Makes a move instruction, appropriate and ideal for the given arguments.
+     *
+     * @param position {@code non-null;} source position information
+     * @param dest {@code non-null;} destination register
+     * @param src {@code non-null;} source register
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static SimpleInsn makeMove(SourcePosition position,
+            RegisterSpec dest, RegisterSpec src) {
+        boolean category1 = dest.getCategory() == 1;
+        boolean reference = dest.getType().isReference();
+        int destReg = dest.getReg();
+        int srcReg = src.getReg();
+        Dop opcode;
+
+        if ((srcReg | destReg) < 16) {
+            opcode = reference ? Dops.MOVE_OBJECT :
+                (category1 ? Dops.MOVE : Dops.MOVE_WIDE);
+        } else if (destReg < 256) {
+            opcode = reference ? Dops.MOVE_OBJECT_FROM16 :
+                (category1 ? Dops.MOVE_FROM16 : Dops.MOVE_WIDE_FROM16);
+        } else {
+            opcode = reference ? Dops.MOVE_OBJECT_16 :
+                (category1 ? Dops.MOVE_16 : Dops.MOVE_WIDE_16);
+        }
+
+        return new SimpleInsn(opcode, position,
+                              RegisterSpecList.make(dest, src));
+    }
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * <p><b>Note:</b> In the unlikely event that an instruction takes
+     * absolutely no registers (e.g., a {@code nop} or a
+     * no-argument no-result static method call), then the given
+     * register list may be passed as {@link
+     * RegisterSpecList#EMPTY}.</p>
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins and outs)
+     */
+    public DalvInsn(Dop opcode, SourcePosition position,
+                    RegisterSpecList registers) {
+        if (opcode == null) {
+            throw new NullPointerException("opcode == null");
+        }
+
+        if (position == null) {
+            throw new NullPointerException("position == null");
+        }
+
+        if (registers == null) {
+            throw new NullPointerException("registers == null");
+        }
+
+        this.address = -1;
+        this.opcode = opcode;
+        this.position = position;
+        this.registers = registers;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(identifierString());
+        sb.append(' ');
+        sb.append(position);
+
+        sb.append(": ");
+        sb.append(opcode.getName());
+
+        boolean needComma = false;
+        if (registers.size() != 0) {
+            sb.append(registers.toHuman(" ", ", ", null));
+            needComma = true;
+        }
+
+        String extra = argString();
+        if (extra != null) {
+            if (needComma) {
+                sb.append(',');
+            }
+            sb.append(' ');
+            sb.append(extra);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets whether the address of this instruction is known.
+     *
+     * @see #getAddress
+     * @see #setAddress
+     */
+    public final boolean hasAddress() {
+        return (address >= 0);
+    }
+
+    /**
+     * Gets the output address of this instruction, if it is known. This throws
+     * a {@code RuntimeException} if it has not yet been set.
+     *
+     * @see #setAddress
+     *
+     * @return {@code >= 0;} the output address
+     */
+    public final int getAddress() {
+        if (address < 0) {
+            throw new RuntimeException("address not yet known");
+        }
+
+        return address;
+    }
+
+    /**
+     * Gets the opcode.
+     *
+     * @return {@code non-null;} the opcode
+     */
+    public final Dop getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the source position.
+     *
+     * @return {@code non-null;} the source position
+     */
+    public final SourcePosition getPosition() {
+        return position;
+    }
+
+    /**
+     * Gets the register list for this instruction.
+     *
+     * @return {@code non-null;} the registers
+     */
+    public final RegisterSpecList getRegisters() {
+        return registers;
+    }
+
+    /**
+     * Returns whether this instance's opcode uses a result register.
+     * This method is a convenient shorthand for
+     * {@code getOpcode().hasResult()}.
+     *
+     * @return {@code true} iff this opcode uses a result register
+     */
+    public final boolean hasResult() {
+        return opcode.hasResult();
+    }
+
+    /**
+     * Gets the minimum distinct registers required for this instruction.
+     * Uses the given BitSet to determine which registers require
+     * replacement, and ignores registers that are already compatible.
+     * This assumes that the result (if any) can share registers with the
+     * sources (if any), that each source register is unique, and that
+     * (to be explicit here) category-2 values take up two consecutive
+     * registers.
+     *
+     * @param compatRegs {@code non-null;} set of compatible registers
+     * @return {@code >= 0;} the minimum distinct register requirement
+     */
+    public final int getMinimumRegisterRequirement(BitSet compatRegs) {
+        boolean hasResult = hasResult();
+        int regSz = registers.size();
+        int resultRequirement = 0;
+        int sourceRequirement = 0;
+
+        if (hasResult && !compatRegs.get(0)) {
+            resultRequirement = registers.get(0).getCategory();
+        }
+
+        for (int i = hasResult ? 1 : 0; i < regSz; i++) {
+            if (!compatRegs.get(i)) {
+                sourceRequirement += registers.get(i).getCategory();
+            }
+        }
+
+        return Math.max(sourceRequirement, resultRequirement);
+    }
+
+    /**
+     * Gets the instruction that is equivalent to this one, except that
+     * it uses sequential registers starting at {@code 0} (storing
+     * the result, if any, in register {@code 0} as well).
+     *
+     * @return {@code non-null;} the replacement
+     */
+    public DalvInsn getLowRegVersion() {
+        RegisterSpecList regs =
+            registers.withExpandedRegisters(0, hasResult(), null);
+        return withRegisters(regs);
+    }
+
+    /**
+     * Gets the instruction prefix required, if any, to use in an expanded
+     * version of this instance. Will not generate moves for registers
+     * marked compatible to the format by the given BitSet.
+     *
+     * @see #expandedVersion
+     *
+     * @param compatRegs {@code non-null;} set of compatible registers
+     * @return {@code null-ok;} the prefix, if any
+     */
+    public DalvInsn expandedPrefix(BitSet compatRegs) {
+        RegisterSpecList regs = registers;
+        boolean firstBit = compatRegs.get(0);
+
+        if (hasResult()) compatRegs.set(0);
+
+        regs = regs.subset(compatRegs);
+
+        if (hasResult()) compatRegs.set(0, firstBit);
+
+        if (regs.size() == 0) return null;
+
+        return new HighRegisterPrefix(position, regs);
+    }
+
+    /**
+     * Gets the instruction suffix required, if any, to use in an expanded
+     * version of this instance. Will not generate a move for a register
+     * marked compatible to the format by the given BitSet.
+     *
+     * @see #expandedVersion
+     *
+     * @param compatRegs {@code non-null;} set of compatible registers
+     * @return {@code null-ok;} the suffix, if any
+     */
+    public DalvInsn expandedSuffix(BitSet compatRegs) {
+        if (hasResult() && !compatRegs.get(0)) {
+            RegisterSpec r = registers.get(0);
+            return makeMove(position, r, r.withReg(0));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the instruction that is equivalent to this one, except that
+     * it replaces incompatible registers with sequential registers
+     * starting at {@code 0} (storing the result, if any, in register
+     * {@code 0} as well). The sequence of instructions from
+     * {@link #expandedPrefix} and {@link #expandedSuffix} (if non-null)
+     * surrounding the result of a call to this method are the expanded
+     * transformation of this instance, and it is guaranteed that the
+     * number of low registers used will be the number returned by
+     * {@link #getMinimumRegisterRequirement}.
+     *
+     * @param compatRegs {@code non-null;} set of compatible registers
+     * @return {@code non-null;} the replacement
+     */
+    public DalvInsn expandedVersion(BitSet compatRegs) {
+        RegisterSpecList regs =
+            registers.withExpandedRegisters(0, hasResult(), compatRegs);
+        return withRegisters(regs);
+    }
+
+    /**
+     * Gets the short identifier for this instruction. This is its
+     * address, if assigned, or its identity hashcode if not.
+     *
+     * @return {@code non-null;} the identifier
+     */
+    public final String identifierString() {
+        if (address != -1) {
+            return String.format("%04x", address);
+        }
+
+        return Hex.u4(System.identityHashCode(this));
+    }
+
+    /**
+     * Returns the string form of this instance suitable for inclusion in
+     * a human-oriented listing dump. This method will return {@code null}
+     * if this instance should not appear in a listing.
+     *
+     * @param prefix {@code non-null;} prefix before the address; each follow-on
+     * line will be indented to match as well
+     * @param width {@code >= 0;} the width of the output or {@code 0} for
+     * unlimited width
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @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,
+            boolean noteIndices) {
+        String insnPerSe = listingString0(noteIndices);
+
+        if (insnPerSe == null) {
+            return null;
+        }
+
+        String addr = prefix + identifierString() + ": ";
+        int w1 = addr.length();
+        int w2 = (width == 0) ? insnPerSe.length() : (width - w1);
+
+        return TwoColumnOutput.toString(addr, w1, "", insnPerSe, w2);
+    }
+
+    /**
+     * Sets the output address.
+     *
+     * @param address {@code >= 0;} the output address
+     */
+    public final void setAddress(int address) {
+        if (address < 0) {
+            throw new IllegalArgumentException("address < 0");
+        }
+
+        this.address = address;
+    }
+
+    /**
+     * Gets the address immediately after this instance. This is only
+     * calculable if this instance's address is known, and it is equal
+     * to the address plus the length of the instruction format of this
+     * instance's opcode.
+     *
+     * @return {@code >= 0;} the next address
+     */
+    public final int getNextAddress() {
+        return getAddress() + codeSize();
+    }
+
+    /**
+     * Gets the size of this instruction, in 16-bit code units.
+     *
+     * @return {@code >= 0;} the code size of this instruction
+     */
+    public abstract int codeSize();
+
+    /**
+     * Writes this instance to the given output. This method should
+     * never annotate the output.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public abstract void writeTo(AnnotatedOutput out);
+
+    /**
+     * Returns an instance that is just like this one, except that its
+     * opcode is replaced by the one given, and its address is reset.
+     *
+     * @param opcode {@code non-null;} the new opcode
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract DalvInsn withOpcode(Dop opcode);
+
+    /**
+     * Returns an instance that is just like this one, except that all
+     * register references have been offset by the given delta, and its
+     * address is reset.
+     *
+     * @param delta the amount to offset register references by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract DalvInsn withRegisterOffset(int delta);
+
+    /**
+     * Returns an instance that is just like this one, except that the
+     * register list is replaced by the given one, and its address is
+     * reset.
+     *
+     * @param registers {@code non-null;} new register list
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract DalvInsn withRegisters(RegisterSpecList registers);
+
+    /**
+     * Gets the string form for any arguments to this instance. Subclasses
+     * must override this.
+     *
+     * @return {@code null-ok;} the string version of any arguments or
+     * {@code null} if there are none
+     */
+    protected abstract String argString();
+
+    /**
+     * Helper for {@link #listingString}, which returns the string
+     * 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} if this instance should
+     * not appear in a listing.
+     *
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @return {@code null-ok;} the listing string
+     */
+    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
new file mode 100644
index 0000000..e856cb4
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/DalvInsnList.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.io.Opcodes;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstBaseMethodRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.FixedSizeList;
+import com.android.dx.util.IndentingWriter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+
+/**
+ * List of {@link DalvInsn} instances.
+ */
+public final class DalvInsnList extends FixedSizeList {
+
+    /**
+     * The amount of register space, in register units, required for this
+     * code block. This may be greater than the largest observed register+
+     * category because the method this code block exists in may
+     * specify arguments that are unused by the method.
+     */
+    private final int regCount;
+
+    /**
+     * Constructs and returns an immutable instance whose elements are
+     * identical to the ones in the given list, in the same order.
+     *
+     * @param list {@code non-null;} the list to use for elements
+     * @param regCount count, in register-units, of the number of registers
+     * this code block requires.
+     * @return {@code non-null;} an appropriately-constructed instance of this
+     * class
+     */
+    public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list,
+            int regCount) {
+        int size = list.size();
+        DalvInsnList result = new DalvInsnList(size, regCount);
+
+        for (int i = 0; i < size; i++) {
+            result.set(i, list.get(i));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public DalvInsnList(int size, int regCount) {
+        super(size);
+        this.regCount = regCount;
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public DalvInsn get(int n) {
+        return (DalvInsn) get0(n);
+    }
+
+    /**
+     * Sets the instruction at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param insn {@code non-null;} the instruction to set at {@code n}
+     */
+    public void set(int n, DalvInsn insn) {
+        set0(n, insn);
+    }
+
+    /**
+     * Gets the size of this instance, in 16-bit code units. This will only
+     * return a meaningful result if the instructions in this instance all
+     * have valid addresses.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int codeSize() {
+        int sz = size();
+
+        if (sz == 0) {
+            return 0;
+        }
+
+        DalvInsn last = get(sz - 1);
+        return last.getNextAddress();
+    }
+
+    /**
+     * Writes all the instructions in this instance to the given output
+     * destination.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public void writeTo(AnnotatedOutput out) {
+        int startCursor = out.getCursor();
+        int sz = size();
+
+        if (out.annotates()) {
+            boolean verbose = out.isVerbose();
+
+            for (int i = 0; i < sz; i++) {
+                DalvInsn insn = (DalvInsn) get0(i);
+                int codeBytes = insn.codeSize() * 2;
+                String s;
+
+                if ((codeBytes != 0) || verbose) {
+                    s = insn.listingString("  ", out.getAnnotationWidth(),
+                            true);
+                } else {
+                    s = null;
+                }
+
+                if (s != null) {
+                    out.annotate(codeBytes, s);
+                } else if (codeBytes != 0) {
+                    out.annotate(codeBytes, "");
+                }
+            }
+        }
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = (DalvInsn) get0(i);
+            try {
+                insn.writeTo(out);
+            } catch (RuntimeException ex) {
+                throw ExceptionWithContext.withContext(ex,
+                        "...while writing " + insn);
+            }
+        }
+
+        // Sanity check of the amount written.
+        int written = (out.getCursor() - startCursor) / 2;
+        if (written != codeSize()) {
+            throw new RuntimeException("write length mismatch; expected " +
+                    codeSize() + " but actually wrote " + written);
+        }
+    }
+
+    /**
+     * 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 {@code >= 0;} the required registers size
+     */
+    public int getRegistersSize() {
+        return regCount;
+    }
+
+    /**
+     * Gets the size of the outgoing arguments area required by this
+     * method. This is equal to the largest argument word count of any
+     * method referred to by this instance.
+     *
+     * @return {@code >= 0;} the required outgoing arguments size
+     */
+    public int getOutsSize() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = (DalvInsn) get0(i);
+
+            if (!(insn instanceof CstInsn)) {
+                continue;
+            }
+
+            Constant cst = ((CstInsn) insn).getConstant();
+
+            if (!(cst instanceof CstBaseMethodRef)) {
+                continue;
+            }
+
+            boolean isStatic =
+                (insn.getOpcode().getFamily() == Opcodes.INVOKE_STATIC);
+            int count =
+                ((CstBaseMethodRef) cst).getParameterWordCount(isStatic);
+
+            if (count > result) {
+                result = count;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     * @param verbose whether to be verbose; verbose output includes
+     * lines for zero-size instructions and explicit constant pool indices
+     */
+    public void debugPrint(Writer out, String prefix, boolean verbose) {
+        IndentingWriter iw = new IndentingWriter(out, 0, prefix);
+        int sz = size();
+
+        try {
+            for (int i = 0; i < sz; i++) {
+                DalvInsn insn = (DalvInsn) get0(i);
+                String s;
+
+                if ((insn.codeSize() != 0) || verbose) {
+                    s = insn.listingString("", 0, verbose);
+                } else {
+                    s = null;
+                }
+
+                if (s != null) {
+                    iw.write(s);
+                }
+            }
+
+            iw.flush();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     * @param verbose whether to be verbose; verbose output includes
+     * lines for zero-size instructions
+     */
+    public void debugPrint(OutputStream out, String prefix, boolean verbose) {
+        Writer w = new OutputStreamWriter(out);
+        debugPrint(w, prefix, verbose);
+
+        try {
+            w.flush();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/Dop.java b/dx/src/com/android/dx/dex/code/Dop.java
new file mode 100644
index 0000000..51d1b51
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/Dop.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.io.OpcodeInfo;
+import com.android.dx.io.Opcodes;
+
+/**
+ * Representation of an opcode.
+ */
+public final class Dop {
+    /** {@code Opcodes.isValid();} the opcode value itself */
+    private final int opcode;
+
+    /** {@code Opcodes.isValid();} the opcode family */
+    private final int family;
+
+    /**
+     * {@code Opcodes.isValid();} what opcode (by number) to try next
+     * when attempting to match an opcode to particular arguments;
+     * {@code Opcodes.NO_NEXT} to indicate that this is the last
+     * opcode to try in a particular chain
+     */
+    private final int nextOpcode;
+
+    /** {@code non-null;} the instruction format */
+    private final InsnFormat format;
+
+    /** whether this opcode uses a result register */
+    private final boolean hasResult;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code Opcodes.isValid();} the opcode value
+     * itself
+     * @param family {@code Opcodes.isValid();} the opcode family
+     * @param nextOpcode {@code Opcodes.isValid();} what opcode (by
+     * number) to try next when attempting to match an opcode to
+     * particular arguments; {@code Opcodes.NO_NEXT} to indicate that
+     * this is the last opcode to try in a particular chain
+     * @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
+     */
+    public Dop(int opcode, int family, int nextOpcode, InsnFormat format,
+            boolean hasResult) {
+        if (!Opcodes.isValidShape(opcode)) {
+            throw new IllegalArgumentException("bogus opcode");
+        }
+
+        if (!Opcodes.isValidShape(family)) {
+            throw new IllegalArgumentException("bogus family");
+        }
+
+        if (!Opcodes.isValidShape(nextOpcode)) {
+            throw new IllegalArgumentException("bogus nextOpcode");
+        }
+
+        if (format == null) {
+            throw new NullPointerException("format == null");
+        }
+
+        this.opcode = opcode;
+        this.family = family;
+        this.nextOpcode = nextOpcode;
+        this.format = format;
+        this.hasResult = hasResult;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+    /**
+     * Gets the opcode value.
+     *
+     * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value
+     */
+    public int getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the opcode family. The opcode family is the unmarked (no
+     * "/...") opcode that has equivalent semantics to this one.
+     *
+     * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode family
+     */
+    public int getFamily() {
+        return family;
+    }
+
+    /**
+     * Gets the instruction format.
+     *
+     * @return {@code non-null;} the instruction format
+     */
+    public InsnFormat getFormat() {
+        return format;
+    }
+
+    /**
+     * Returns whether this opcode uses a result register.
+     *
+     * @return {@code true} iff this opcode uses a result register
+     */
+    public boolean hasResult() {
+        return hasResult;
+    }
+
+    /**
+     * Gets the opcode name.
+     *
+     * @return {@code non-null;} the opcode name
+     */
+    public String getName() {
+        return OpcodeInfo.getName(opcode);
+    }
+
+    /**
+     * Gets the opcode value to try next when attempting to match an
+     * opcode to particular arguments. This returns {@code
+     * Opcodes.NO_NEXT} to indicate that this is the last opcode to
+     * try in a particular chain.
+     *
+     * @return {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the opcode value
+     */
+    public int getNextOpcode() {
+        return nextOpcode;
+    }
+
+    /**
+     * Gets the opcode for the opposite test of this instance. This is only
+     * valid for opcodes which are in fact tests.
+     *
+     * @return {@code non-null;} the opposite test
+     */
+    public Dop getOppositeTest() {
+        switch (opcode) {
+            case Opcodes.IF_EQ:  return Dops.IF_NE;
+            case Opcodes.IF_NE:  return Dops.IF_EQ;
+            case Opcodes.IF_LT:  return Dops.IF_GE;
+            case Opcodes.IF_GE:  return Dops.IF_LT;
+            case Opcodes.IF_GT:  return Dops.IF_LE;
+            case Opcodes.IF_LE:  return Dops.IF_GT;
+            case Opcodes.IF_EQZ: return Dops.IF_NEZ;
+            case Opcodes.IF_NEZ: return Dops.IF_EQZ;
+            case Opcodes.IF_LTZ: return Dops.IF_GEZ;
+            case Opcodes.IF_GEZ: return Dops.IF_LTZ;
+            case Opcodes.IF_GTZ: return Dops.IF_LEZ;
+            case Opcodes.IF_LEZ: return Dops.IF_GTZ;
+        }
+
+        throw new IllegalArgumentException("bogus opcode: " + this);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
new file mode 100644
index 0000000..c066252
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -0,0 +1,1441 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.dex.DexOptions;
+import com.android.dx.dex.code.form.Form10t;
+import com.android.dx.dex.code.form.Form10x;
+import com.android.dx.dex.code.form.Form11n;
+import com.android.dx.dex.code.form.Form11x;
+import com.android.dx.dex.code.form.Form12x;
+import com.android.dx.dex.code.form.Form20t;
+import com.android.dx.dex.code.form.Form21c;
+import com.android.dx.dex.code.form.Form21h;
+import com.android.dx.dex.code.form.Form21s;
+import com.android.dx.dex.code.form.Form21t;
+import com.android.dx.dex.code.form.Form22b;
+import com.android.dx.dex.code.form.Form22c;
+import com.android.dx.dex.code.form.Form22s;
+import com.android.dx.dex.code.form.Form22t;
+import com.android.dx.dex.code.form.Form22x;
+import com.android.dx.dex.code.form.Form23x;
+import com.android.dx.dex.code.form.Form30t;
+import com.android.dx.dex.code.form.Form31c;
+import com.android.dx.dex.code.form.Form31i;
+import com.android.dx.dex.code.form.Form31t;
+import com.android.dx.dex.code.form.Form32x;
+import com.android.dx.dex.code.form.Form35c;
+import com.android.dx.dex.code.form.Form3rc;
+import com.android.dx.dex.code.form.Form41c;
+import com.android.dx.dex.code.form.Form51l;
+import com.android.dx.dex.code.form.Form52c;
+import com.android.dx.dex.code.form.Form5rc;
+import com.android.dx.dex.code.form.SpecialFormat;
+import com.android.dx.io.Opcodes;
+
+/**
+ * Standard instances of {@link Dop} and utility methods for getting
+ * them.
+ */
+public final class Dops {
+    /** {@code non-null;} array containing all the standard instances */
+    private static final Dop[] DOPS;
+
+    /**
+     * pseudo-opcode used for nonstandard formatted "instructions"
+     * (which are mostly not actually instructions, though they do
+     * appear in instruction lists). TODO: Retire the usage of this
+     * constant.
+     */
+    public static final Dop SPECIAL_FORMAT =
+        new Dop(Opcodes.SPECIAL_FORMAT, Opcodes.SPECIAL_FORMAT,
+                Opcodes.NO_NEXT, SpecialFormat.THE_ONE, false);
+
+    // BEGIN(dops); GENERATED AUTOMATICALLY BY opcode-gen
+    public static final Dop NOP =
+        new Dop(Opcodes.NOP, Opcodes.NOP,
+            Opcodes.NO_NEXT, Form10x.THE_ONE, false);
+
+    public static final Dop MOVE =
+        new Dop(Opcodes.MOVE, Opcodes.MOVE,
+            Opcodes.MOVE_FROM16, Form12x.THE_ONE, true);
+
+    public static final Dop MOVE_FROM16 =
+        new Dop(Opcodes.MOVE_FROM16, Opcodes.MOVE,
+            Opcodes.MOVE_16, Form22x.THE_ONE, true);
+
+    public static final Dop MOVE_16 =
+        new Dop(Opcodes.MOVE_16, Opcodes.MOVE,
+            Opcodes.NO_NEXT, Form32x.THE_ONE, true);
+
+    public static final Dop MOVE_WIDE =
+        new Dop(Opcodes.MOVE_WIDE, Opcodes.MOVE_WIDE,
+            Opcodes.MOVE_WIDE_FROM16, Form12x.THE_ONE, true);
+
+    public static final Dop MOVE_WIDE_FROM16 =
+        new Dop(Opcodes.MOVE_WIDE_FROM16, Opcodes.MOVE_WIDE,
+            Opcodes.MOVE_WIDE_16, Form22x.THE_ONE, true);
+
+    public static final Dop MOVE_WIDE_16 =
+        new Dop(Opcodes.MOVE_WIDE_16, Opcodes.MOVE_WIDE,
+            Opcodes.NO_NEXT, Form32x.THE_ONE, true);
+
+    public static final Dop MOVE_OBJECT =
+        new Dop(Opcodes.MOVE_OBJECT, Opcodes.MOVE_OBJECT,
+            Opcodes.MOVE_OBJECT_FROM16, Form12x.THE_ONE, true);
+
+    public static final Dop MOVE_OBJECT_FROM16 =
+        new Dop(Opcodes.MOVE_OBJECT_FROM16, Opcodes.MOVE_OBJECT,
+            Opcodes.MOVE_OBJECT_16, Form22x.THE_ONE, true);
+
+    public static final Dop MOVE_OBJECT_16 =
+        new Dop(Opcodes.MOVE_OBJECT_16, Opcodes.MOVE_OBJECT,
+            Opcodes.NO_NEXT, Form32x.THE_ONE, true);
+
+    public static final Dop MOVE_RESULT =
+        new Dop(Opcodes.MOVE_RESULT, Opcodes.MOVE_RESULT,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+
+    public static final Dop MOVE_RESULT_WIDE =
+        new Dop(Opcodes.MOVE_RESULT_WIDE, Opcodes.MOVE_RESULT_WIDE,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+
+    public static final Dop MOVE_RESULT_OBJECT =
+        new Dop(Opcodes.MOVE_RESULT_OBJECT, Opcodes.MOVE_RESULT_OBJECT,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+
+    public static final Dop MOVE_EXCEPTION =
+        new Dop(Opcodes.MOVE_EXCEPTION, Opcodes.MOVE_EXCEPTION,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, true);
+
+    public static final Dop RETURN_VOID =
+        new Dop(Opcodes.RETURN_VOID, Opcodes.RETURN_VOID,
+            Opcodes.NO_NEXT, Form10x.THE_ONE, false);
+
+    public static final Dop RETURN =
+        new Dop(Opcodes.RETURN, Opcodes.RETURN,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+
+    public static final Dop RETURN_WIDE =
+        new Dop(Opcodes.RETURN_WIDE, Opcodes.RETURN_WIDE,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+
+    public static final Dop RETURN_OBJECT =
+        new Dop(Opcodes.RETURN_OBJECT, Opcodes.RETURN_OBJECT,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+
+    public static final Dop CONST_4 =
+        new Dop(Opcodes.CONST_4, Opcodes.CONST,
+            Opcodes.CONST_16, Form11n.THE_ONE, true);
+
+    public static final Dop CONST_16 =
+        new Dop(Opcodes.CONST_16, Opcodes.CONST,
+            Opcodes.CONST_HIGH16, Form21s.THE_ONE, true);
+
+    public static final Dop CONST =
+        new Dop(Opcodes.CONST, Opcodes.CONST,
+            Opcodes.NO_NEXT, Form31i.THE_ONE, true);
+
+    public static final Dop CONST_HIGH16 =
+        new Dop(Opcodes.CONST_HIGH16, Opcodes.CONST,
+            Opcodes.CONST, Form21h.THE_ONE, true);
+
+    public static final Dop CONST_WIDE_16 =
+        new Dop(Opcodes.CONST_WIDE_16, Opcodes.CONST_WIDE,
+            Opcodes.CONST_WIDE_HIGH16, Form21s.THE_ONE, true);
+
+    public static final Dop CONST_WIDE_32 =
+        new Dop(Opcodes.CONST_WIDE_32, Opcodes.CONST_WIDE,
+            Opcodes.CONST_WIDE, Form31i.THE_ONE, true);
+
+    public static final Dop CONST_WIDE =
+        new Dop(Opcodes.CONST_WIDE, Opcodes.CONST_WIDE,
+            Opcodes.NO_NEXT, Form51l.THE_ONE, true);
+
+    public static final Dop CONST_WIDE_HIGH16 =
+        new Dop(Opcodes.CONST_WIDE_HIGH16, Opcodes.CONST_WIDE,
+            Opcodes.CONST_WIDE_32, Form21h.THE_ONE, true);
+
+    public static final Dop CONST_STRING =
+        new Dop(Opcodes.CONST_STRING, Opcodes.CONST_STRING,
+            Opcodes.CONST_STRING_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop CONST_STRING_JUMBO =
+        new Dop(Opcodes.CONST_STRING_JUMBO, Opcodes.CONST_STRING,
+            Opcodes.NO_NEXT, Form31c.THE_ONE, true);
+
+    public static final Dop CONST_CLASS =
+        new Dop(Opcodes.CONST_CLASS, Opcodes.CONST_CLASS,
+            Opcodes.CONST_CLASS_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop MONITOR_ENTER =
+        new Dop(Opcodes.MONITOR_ENTER, Opcodes.MONITOR_ENTER,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+
+    public static final Dop MONITOR_EXIT =
+        new Dop(Opcodes.MONITOR_EXIT, Opcodes.MONITOR_EXIT,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+
+    public static final Dop CHECK_CAST =
+        new Dop(Opcodes.CHECK_CAST, Opcodes.CHECK_CAST,
+            Opcodes.CHECK_CAST_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop INSTANCE_OF =
+        new Dop(Opcodes.INSTANCE_OF, Opcodes.INSTANCE_OF,
+            Opcodes.INSTANCE_OF_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop ARRAY_LENGTH =
+        new Dop(Opcodes.ARRAY_LENGTH, Opcodes.ARRAY_LENGTH,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop NEW_INSTANCE =
+        new Dop(Opcodes.NEW_INSTANCE, Opcodes.NEW_INSTANCE,
+            Opcodes.NEW_INSTANCE_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop NEW_ARRAY =
+        new Dop(Opcodes.NEW_ARRAY, Opcodes.NEW_ARRAY,
+            Opcodes.NEW_ARRAY_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop FILLED_NEW_ARRAY =
+        new Dop(Opcodes.FILLED_NEW_ARRAY, Opcodes.FILLED_NEW_ARRAY,
+            Opcodes.FILLED_NEW_ARRAY_RANGE, Form35c.THE_ONE, false);
+
+    public static final Dop FILLED_NEW_ARRAY_RANGE =
+        new Dop(Opcodes.FILLED_NEW_ARRAY_RANGE, Opcodes.FILLED_NEW_ARRAY,
+            Opcodes.FILLED_NEW_ARRAY_JUMBO, Form3rc.THE_ONE, false);
+
+    public static final Dop FILL_ARRAY_DATA =
+        new Dop(Opcodes.FILL_ARRAY_DATA, Opcodes.FILL_ARRAY_DATA,
+            Opcodes.NO_NEXT, Form31t.THE_ONE, false);
+
+    public static final Dop THROW =
+        new Dop(Opcodes.THROW, Opcodes.THROW,
+            Opcodes.NO_NEXT, Form11x.THE_ONE, false);
+
+    public static final Dop GOTO =
+        new Dop(Opcodes.GOTO, Opcodes.GOTO,
+            Opcodes.GOTO_16, Form10t.THE_ONE, false);
+
+    public static final Dop GOTO_16 =
+        new Dop(Opcodes.GOTO_16, Opcodes.GOTO,
+            Opcodes.GOTO_32, Form20t.THE_ONE, false);
+
+    public static final Dop GOTO_32 =
+        new Dop(Opcodes.GOTO_32, Opcodes.GOTO,
+            Opcodes.NO_NEXT, Form30t.THE_ONE, false);
+
+    public static final Dop PACKED_SWITCH =
+        new Dop(Opcodes.PACKED_SWITCH, Opcodes.PACKED_SWITCH,
+            Opcodes.NO_NEXT, Form31t.THE_ONE, false);
+
+    public static final Dop SPARSE_SWITCH =
+        new Dop(Opcodes.SPARSE_SWITCH, Opcodes.SPARSE_SWITCH,
+            Opcodes.NO_NEXT, Form31t.THE_ONE, false);
+
+    public static final Dop CMPL_FLOAT =
+        new Dop(Opcodes.CMPL_FLOAT, Opcodes.CMPL_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop CMPG_FLOAT =
+        new Dop(Opcodes.CMPG_FLOAT, Opcodes.CMPG_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop CMPL_DOUBLE =
+        new Dop(Opcodes.CMPL_DOUBLE, Opcodes.CMPL_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop CMPG_DOUBLE =
+        new Dop(Opcodes.CMPG_DOUBLE, Opcodes.CMPG_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop CMP_LONG =
+        new Dop(Opcodes.CMP_LONG, Opcodes.CMP_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop IF_EQ =
+        new Dop(Opcodes.IF_EQ, Opcodes.IF_EQ,
+            Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+
+    public static final Dop IF_NE =
+        new Dop(Opcodes.IF_NE, Opcodes.IF_NE,
+            Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+
+    public static final Dop IF_LT =
+        new Dop(Opcodes.IF_LT, Opcodes.IF_LT,
+            Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+
+    public static final Dop IF_GE =
+        new Dop(Opcodes.IF_GE, Opcodes.IF_GE,
+            Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+
+    public static final Dop IF_GT =
+        new Dop(Opcodes.IF_GT, Opcodes.IF_GT,
+            Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+
+    public static final Dop IF_LE =
+        new Dop(Opcodes.IF_LE, Opcodes.IF_LE,
+            Opcodes.NO_NEXT, Form22t.THE_ONE, false);
+
+    public static final Dop IF_EQZ =
+        new Dop(Opcodes.IF_EQZ, Opcodes.IF_EQZ,
+            Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+
+    public static final Dop IF_NEZ =
+        new Dop(Opcodes.IF_NEZ, Opcodes.IF_NEZ,
+            Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+
+    public static final Dop IF_LTZ =
+        new Dop(Opcodes.IF_LTZ, Opcodes.IF_LTZ,
+            Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+
+    public static final Dop IF_GEZ =
+        new Dop(Opcodes.IF_GEZ, Opcodes.IF_GEZ,
+            Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+
+    public static final Dop IF_GTZ =
+        new Dop(Opcodes.IF_GTZ, Opcodes.IF_GTZ,
+            Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+
+    public static final Dop IF_LEZ =
+        new Dop(Opcodes.IF_LEZ, Opcodes.IF_LEZ,
+            Opcodes.NO_NEXT, Form21t.THE_ONE, false);
+
+    public static final Dop AGET =
+        new Dop(Opcodes.AGET, Opcodes.AGET,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AGET_WIDE =
+        new Dop(Opcodes.AGET_WIDE, Opcodes.AGET_WIDE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AGET_OBJECT =
+        new Dop(Opcodes.AGET_OBJECT, Opcodes.AGET_OBJECT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AGET_BOOLEAN =
+        new Dop(Opcodes.AGET_BOOLEAN, Opcodes.AGET_BOOLEAN,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AGET_BYTE =
+        new Dop(Opcodes.AGET_BYTE, Opcodes.AGET_BYTE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AGET_CHAR =
+        new Dop(Opcodes.AGET_CHAR, Opcodes.AGET_CHAR,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AGET_SHORT =
+        new Dop(Opcodes.AGET_SHORT, Opcodes.AGET_SHORT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop APUT =
+        new Dop(Opcodes.APUT, Opcodes.APUT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop APUT_WIDE =
+        new Dop(Opcodes.APUT_WIDE, Opcodes.APUT_WIDE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop APUT_OBJECT =
+        new Dop(Opcodes.APUT_OBJECT, Opcodes.APUT_OBJECT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop APUT_BOOLEAN =
+        new Dop(Opcodes.APUT_BOOLEAN, Opcodes.APUT_BOOLEAN,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop APUT_BYTE =
+        new Dop(Opcodes.APUT_BYTE, Opcodes.APUT_BYTE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop APUT_CHAR =
+        new Dop(Opcodes.APUT_CHAR, Opcodes.APUT_CHAR,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop APUT_SHORT =
+        new Dop(Opcodes.APUT_SHORT, Opcodes.APUT_SHORT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, false);
+
+    public static final Dop IGET =
+        new Dop(Opcodes.IGET, Opcodes.IGET,
+            Opcodes.IGET_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IGET_WIDE =
+        new Dop(Opcodes.IGET_WIDE, Opcodes.IGET_WIDE,
+            Opcodes.IGET_WIDE_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IGET_OBJECT =
+        new Dop(Opcodes.IGET_OBJECT, Opcodes.IGET_OBJECT,
+            Opcodes.IGET_OBJECT_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IGET_BOOLEAN =
+        new Dop(Opcodes.IGET_BOOLEAN, Opcodes.IGET_BOOLEAN,
+            Opcodes.IGET_BOOLEAN_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IGET_BYTE =
+        new Dop(Opcodes.IGET_BYTE, Opcodes.IGET_BYTE,
+            Opcodes.IGET_BYTE_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IGET_CHAR =
+        new Dop(Opcodes.IGET_CHAR, Opcodes.IGET_CHAR,
+            Opcodes.IGET_CHAR_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IGET_SHORT =
+        new Dop(Opcodes.IGET_SHORT, Opcodes.IGET_SHORT,
+            Opcodes.IGET_SHORT_JUMBO, Form22c.THE_ONE, true);
+
+    public static final Dop IPUT =
+        new Dop(Opcodes.IPUT, Opcodes.IPUT,
+            Opcodes.IPUT_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop IPUT_WIDE =
+        new Dop(Opcodes.IPUT_WIDE, Opcodes.IPUT_WIDE,
+            Opcodes.IPUT_WIDE_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop IPUT_OBJECT =
+        new Dop(Opcodes.IPUT_OBJECT, Opcodes.IPUT_OBJECT,
+            Opcodes.IPUT_OBJECT_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop IPUT_BOOLEAN =
+        new Dop(Opcodes.IPUT_BOOLEAN, Opcodes.IPUT_BOOLEAN,
+            Opcodes.IPUT_BOOLEAN_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop IPUT_BYTE =
+        new Dop(Opcodes.IPUT_BYTE, Opcodes.IPUT_BYTE,
+            Opcodes.IPUT_BYTE_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop IPUT_CHAR =
+        new Dop(Opcodes.IPUT_CHAR, Opcodes.IPUT_CHAR,
+            Opcodes.IPUT_CHAR_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop IPUT_SHORT =
+        new Dop(Opcodes.IPUT_SHORT, Opcodes.IPUT_SHORT,
+            Opcodes.IPUT_SHORT_JUMBO, Form22c.THE_ONE, false);
+
+    public static final Dop SGET =
+        new Dop(Opcodes.SGET, Opcodes.SGET,
+            Opcodes.SGET_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SGET_WIDE =
+        new Dop(Opcodes.SGET_WIDE, Opcodes.SGET_WIDE,
+            Opcodes.SGET_WIDE_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SGET_OBJECT =
+        new Dop(Opcodes.SGET_OBJECT, Opcodes.SGET_OBJECT,
+            Opcodes.SGET_OBJECT_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SGET_BOOLEAN =
+        new Dop(Opcodes.SGET_BOOLEAN, Opcodes.SGET_BOOLEAN,
+            Opcodes.SGET_BOOLEAN_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SGET_BYTE =
+        new Dop(Opcodes.SGET_BYTE, Opcodes.SGET_BYTE,
+            Opcodes.SGET_BYTE_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SGET_CHAR =
+        new Dop(Opcodes.SGET_CHAR, Opcodes.SGET_CHAR,
+            Opcodes.SGET_CHAR_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SGET_SHORT =
+        new Dop(Opcodes.SGET_SHORT, Opcodes.SGET_SHORT,
+            Opcodes.SGET_SHORT_JUMBO, Form21c.THE_ONE, true);
+
+    public static final Dop SPUT =
+        new Dop(Opcodes.SPUT, Opcodes.SPUT,
+            Opcodes.SPUT_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop SPUT_WIDE =
+        new Dop(Opcodes.SPUT_WIDE, Opcodes.SPUT_WIDE,
+            Opcodes.SPUT_WIDE_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop SPUT_OBJECT =
+        new Dop(Opcodes.SPUT_OBJECT, Opcodes.SPUT_OBJECT,
+            Opcodes.SPUT_OBJECT_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop SPUT_BOOLEAN =
+        new Dop(Opcodes.SPUT_BOOLEAN, Opcodes.SPUT_BOOLEAN,
+            Opcodes.SPUT_BOOLEAN_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop SPUT_BYTE =
+        new Dop(Opcodes.SPUT_BYTE, Opcodes.SPUT_BYTE,
+            Opcodes.SPUT_BYTE_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop SPUT_CHAR =
+        new Dop(Opcodes.SPUT_CHAR, Opcodes.SPUT_CHAR,
+            Opcodes.SPUT_CHAR_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop SPUT_SHORT =
+        new Dop(Opcodes.SPUT_SHORT, Opcodes.SPUT_SHORT,
+            Opcodes.SPUT_SHORT_JUMBO, Form21c.THE_ONE, false);
+
+    public static final Dop INVOKE_VIRTUAL =
+        new Dop(Opcodes.INVOKE_VIRTUAL, Opcodes.INVOKE_VIRTUAL,
+            Opcodes.INVOKE_VIRTUAL_RANGE, Form35c.THE_ONE, false);
+
+    public static final Dop INVOKE_SUPER =
+        new Dop(Opcodes.INVOKE_SUPER, Opcodes.INVOKE_SUPER,
+            Opcodes.INVOKE_SUPER_RANGE, Form35c.THE_ONE, false);
+
+    public static final Dop INVOKE_DIRECT =
+        new Dop(Opcodes.INVOKE_DIRECT, Opcodes.INVOKE_DIRECT,
+            Opcodes.INVOKE_DIRECT_RANGE, Form35c.THE_ONE, false);
+
+    public static final Dop INVOKE_STATIC =
+        new Dop(Opcodes.INVOKE_STATIC, Opcodes.INVOKE_STATIC,
+            Opcodes.INVOKE_STATIC_RANGE, Form35c.THE_ONE, false);
+
+    public static final Dop INVOKE_INTERFACE =
+        new Dop(Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE,
+            Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false);
+
+    public static final Dop INVOKE_VIRTUAL_RANGE =
+        new Dop(Opcodes.INVOKE_VIRTUAL_RANGE, Opcodes.INVOKE_VIRTUAL,
+            Opcodes.INVOKE_VIRTUAL_JUMBO, Form3rc.THE_ONE, false);
+
+    public static final Dop INVOKE_SUPER_RANGE =
+        new Dop(Opcodes.INVOKE_SUPER_RANGE, Opcodes.INVOKE_SUPER,
+            Opcodes.INVOKE_SUPER_JUMBO, Form3rc.THE_ONE, false);
+
+    public static final Dop INVOKE_DIRECT_RANGE =
+        new Dop(Opcodes.INVOKE_DIRECT_RANGE, Opcodes.INVOKE_DIRECT,
+            Opcodes.INVOKE_DIRECT_JUMBO, Form3rc.THE_ONE, false);
+
+    public static final Dop INVOKE_STATIC_RANGE =
+        new Dop(Opcodes.INVOKE_STATIC_RANGE, Opcodes.INVOKE_STATIC,
+            Opcodes.INVOKE_STATIC_JUMBO, Form3rc.THE_ONE, false);
+
+    public static final Dop INVOKE_INTERFACE_RANGE =
+        new Dop(Opcodes.INVOKE_INTERFACE_RANGE, Opcodes.INVOKE_INTERFACE,
+            Opcodes.INVOKE_INTERFACE_JUMBO, Form3rc.THE_ONE, false);
+
+    public static final Dop NEG_INT =
+        new Dop(Opcodes.NEG_INT, Opcodes.NEG_INT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop NOT_INT =
+        new Dop(Opcodes.NOT_INT, Opcodes.NOT_INT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop NEG_LONG =
+        new Dop(Opcodes.NEG_LONG, Opcodes.NEG_LONG,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop NOT_LONG =
+        new Dop(Opcodes.NOT_LONG, Opcodes.NOT_LONG,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop NEG_FLOAT =
+        new Dop(Opcodes.NEG_FLOAT, Opcodes.NEG_FLOAT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop NEG_DOUBLE =
+        new Dop(Opcodes.NEG_DOUBLE, Opcodes.NEG_DOUBLE,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop INT_TO_LONG =
+        new Dop(Opcodes.INT_TO_LONG, Opcodes.INT_TO_LONG,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop INT_TO_FLOAT =
+        new Dop(Opcodes.INT_TO_FLOAT, Opcodes.INT_TO_FLOAT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop INT_TO_DOUBLE =
+        new Dop(Opcodes.INT_TO_DOUBLE, Opcodes.INT_TO_DOUBLE,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop LONG_TO_INT =
+        new Dop(Opcodes.LONG_TO_INT, Opcodes.LONG_TO_INT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop LONG_TO_FLOAT =
+        new Dop(Opcodes.LONG_TO_FLOAT, Opcodes.LONG_TO_FLOAT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop LONG_TO_DOUBLE =
+        new Dop(Opcodes.LONG_TO_DOUBLE, Opcodes.LONG_TO_DOUBLE,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop FLOAT_TO_INT =
+        new Dop(Opcodes.FLOAT_TO_INT, Opcodes.FLOAT_TO_INT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop FLOAT_TO_LONG =
+        new Dop(Opcodes.FLOAT_TO_LONG, Opcodes.FLOAT_TO_LONG,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop FLOAT_TO_DOUBLE =
+        new Dop(Opcodes.FLOAT_TO_DOUBLE, Opcodes.FLOAT_TO_DOUBLE,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop DOUBLE_TO_INT =
+        new Dop(Opcodes.DOUBLE_TO_INT, Opcodes.DOUBLE_TO_INT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop DOUBLE_TO_LONG =
+        new Dop(Opcodes.DOUBLE_TO_LONG, Opcodes.DOUBLE_TO_LONG,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop DOUBLE_TO_FLOAT =
+        new Dop(Opcodes.DOUBLE_TO_FLOAT, Opcodes.DOUBLE_TO_FLOAT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop INT_TO_BYTE =
+        new Dop(Opcodes.INT_TO_BYTE, Opcodes.INT_TO_BYTE,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop INT_TO_CHAR =
+        new Dop(Opcodes.INT_TO_CHAR, Opcodes.INT_TO_CHAR,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop INT_TO_SHORT =
+        new Dop(Opcodes.INT_TO_SHORT, Opcodes.INT_TO_SHORT,
+            Opcodes.NO_NEXT, Form12x.THE_ONE, true);
+
+    public static final Dop ADD_INT =
+        new Dop(Opcodes.ADD_INT, Opcodes.ADD_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SUB_INT =
+        new Dop(Opcodes.SUB_INT, Opcodes.SUB_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop MUL_INT =
+        new Dop(Opcodes.MUL_INT, Opcodes.MUL_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop DIV_INT =
+        new Dop(Opcodes.DIV_INT, Opcodes.DIV_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop REM_INT =
+        new Dop(Opcodes.REM_INT, Opcodes.REM_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AND_INT =
+        new Dop(Opcodes.AND_INT, Opcodes.AND_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop OR_INT =
+        new Dop(Opcodes.OR_INT, Opcodes.OR_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop XOR_INT =
+        new Dop(Opcodes.XOR_INT, Opcodes.XOR_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SHL_INT =
+        new Dop(Opcodes.SHL_INT, Opcodes.SHL_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SHR_INT =
+        new Dop(Opcodes.SHR_INT, Opcodes.SHR_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop USHR_INT =
+        new Dop(Opcodes.USHR_INT, Opcodes.USHR_INT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop ADD_LONG =
+        new Dop(Opcodes.ADD_LONG, Opcodes.ADD_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SUB_LONG =
+        new Dop(Opcodes.SUB_LONG, Opcodes.SUB_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop MUL_LONG =
+        new Dop(Opcodes.MUL_LONG, Opcodes.MUL_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop DIV_LONG =
+        new Dop(Opcodes.DIV_LONG, Opcodes.DIV_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop REM_LONG =
+        new Dop(Opcodes.REM_LONG, Opcodes.REM_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop AND_LONG =
+        new Dop(Opcodes.AND_LONG, Opcodes.AND_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop OR_LONG =
+        new Dop(Opcodes.OR_LONG, Opcodes.OR_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop XOR_LONG =
+        new Dop(Opcodes.XOR_LONG, Opcodes.XOR_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SHL_LONG =
+        new Dop(Opcodes.SHL_LONG, Opcodes.SHL_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SHR_LONG =
+        new Dop(Opcodes.SHR_LONG, Opcodes.SHR_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop USHR_LONG =
+        new Dop(Opcodes.USHR_LONG, Opcodes.USHR_LONG,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop ADD_FLOAT =
+        new Dop(Opcodes.ADD_FLOAT, Opcodes.ADD_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SUB_FLOAT =
+        new Dop(Opcodes.SUB_FLOAT, Opcodes.SUB_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop MUL_FLOAT =
+        new Dop(Opcodes.MUL_FLOAT, Opcodes.MUL_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop DIV_FLOAT =
+        new Dop(Opcodes.DIV_FLOAT, Opcodes.DIV_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop REM_FLOAT =
+        new Dop(Opcodes.REM_FLOAT, Opcodes.REM_FLOAT,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop ADD_DOUBLE =
+        new Dop(Opcodes.ADD_DOUBLE, Opcodes.ADD_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop SUB_DOUBLE =
+        new Dop(Opcodes.SUB_DOUBLE, Opcodes.SUB_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop MUL_DOUBLE =
+        new Dop(Opcodes.MUL_DOUBLE, Opcodes.MUL_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop DIV_DOUBLE =
+        new Dop(Opcodes.DIV_DOUBLE, Opcodes.DIV_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop REM_DOUBLE =
+        new Dop(Opcodes.REM_DOUBLE, Opcodes.REM_DOUBLE,
+            Opcodes.NO_NEXT, Form23x.THE_ONE, true);
+
+    public static final Dop ADD_INT_2ADDR =
+        new Dop(Opcodes.ADD_INT_2ADDR, Opcodes.ADD_INT,
+            Opcodes.ADD_INT, Form12x.THE_ONE, true);
+
+    public static final Dop SUB_INT_2ADDR =
+        new Dop(Opcodes.SUB_INT_2ADDR, Opcodes.SUB_INT,
+            Opcodes.SUB_INT, Form12x.THE_ONE, true);
+
+    public static final Dop MUL_INT_2ADDR =
+        new Dop(Opcodes.MUL_INT_2ADDR, Opcodes.MUL_INT,
+            Opcodes.MUL_INT, Form12x.THE_ONE, true);
+
+    public static final Dop DIV_INT_2ADDR =
+        new Dop(Opcodes.DIV_INT_2ADDR, Opcodes.DIV_INT,
+            Opcodes.DIV_INT, Form12x.THE_ONE, true);
+
+    public static final Dop REM_INT_2ADDR =
+        new Dop(Opcodes.REM_INT_2ADDR, Opcodes.REM_INT,
+            Opcodes.REM_INT, Form12x.THE_ONE, true);
+
+    public static final Dop AND_INT_2ADDR =
+        new Dop(Opcodes.AND_INT_2ADDR, Opcodes.AND_INT,
+            Opcodes.AND_INT, Form12x.THE_ONE, true);
+
+    public static final Dop OR_INT_2ADDR =
+        new Dop(Opcodes.OR_INT_2ADDR, Opcodes.OR_INT,
+            Opcodes.OR_INT, Form12x.THE_ONE, true);
+
+    public static final Dop XOR_INT_2ADDR =
+        new Dop(Opcodes.XOR_INT_2ADDR, Opcodes.XOR_INT,
+            Opcodes.XOR_INT, Form12x.THE_ONE, true);
+
+    public static final Dop SHL_INT_2ADDR =
+        new Dop(Opcodes.SHL_INT_2ADDR, Opcodes.SHL_INT,
+            Opcodes.SHL_INT, Form12x.THE_ONE, true);
+
+    public static final Dop SHR_INT_2ADDR =
+        new Dop(Opcodes.SHR_INT_2ADDR, Opcodes.SHR_INT,
+            Opcodes.SHR_INT, Form12x.THE_ONE, true);
+
+    public static final Dop USHR_INT_2ADDR =
+        new Dop(Opcodes.USHR_INT_2ADDR, Opcodes.USHR_INT,
+            Opcodes.USHR_INT, Form12x.THE_ONE, true);
+
+    public static final Dop ADD_LONG_2ADDR =
+        new Dop(Opcodes.ADD_LONG_2ADDR, Opcodes.ADD_LONG,
+            Opcodes.ADD_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop SUB_LONG_2ADDR =
+        new Dop(Opcodes.SUB_LONG_2ADDR, Opcodes.SUB_LONG,
+            Opcodes.SUB_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop MUL_LONG_2ADDR =
+        new Dop(Opcodes.MUL_LONG_2ADDR, Opcodes.MUL_LONG,
+            Opcodes.MUL_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop DIV_LONG_2ADDR =
+        new Dop(Opcodes.DIV_LONG_2ADDR, Opcodes.DIV_LONG,
+            Opcodes.DIV_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop REM_LONG_2ADDR =
+        new Dop(Opcodes.REM_LONG_2ADDR, Opcodes.REM_LONG,
+            Opcodes.REM_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop AND_LONG_2ADDR =
+        new Dop(Opcodes.AND_LONG_2ADDR, Opcodes.AND_LONG,
+            Opcodes.AND_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop OR_LONG_2ADDR =
+        new Dop(Opcodes.OR_LONG_2ADDR, Opcodes.OR_LONG,
+            Opcodes.OR_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop XOR_LONG_2ADDR =
+        new Dop(Opcodes.XOR_LONG_2ADDR, Opcodes.XOR_LONG,
+            Opcodes.XOR_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop SHL_LONG_2ADDR =
+        new Dop(Opcodes.SHL_LONG_2ADDR, Opcodes.SHL_LONG,
+            Opcodes.SHL_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop SHR_LONG_2ADDR =
+        new Dop(Opcodes.SHR_LONG_2ADDR, Opcodes.SHR_LONG,
+            Opcodes.SHR_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop USHR_LONG_2ADDR =
+        new Dop(Opcodes.USHR_LONG_2ADDR, Opcodes.USHR_LONG,
+            Opcodes.USHR_LONG, Form12x.THE_ONE, true);
+
+    public static final Dop ADD_FLOAT_2ADDR =
+        new Dop(Opcodes.ADD_FLOAT_2ADDR, Opcodes.ADD_FLOAT,
+            Opcodes.ADD_FLOAT, Form12x.THE_ONE, true);
+
+    public static final Dop SUB_FLOAT_2ADDR =
+        new Dop(Opcodes.SUB_FLOAT_2ADDR, Opcodes.SUB_FLOAT,
+            Opcodes.SUB_FLOAT, Form12x.THE_ONE, true);
+
+    public static final Dop MUL_FLOAT_2ADDR =
+        new Dop(Opcodes.MUL_FLOAT_2ADDR, Opcodes.MUL_FLOAT,
+            Opcodes.MUL_FLOAT, Form12x.THE_ONE, true);
+
+    public static final Dop DIV_FLOAT_2ADDR =
+        new Dop(Opcodes.DIV_FLOAT_2ADDR, Opcodes.DIV_FLOAT,
+            Opcodes.DIV_FLOAT, Form12x.THE_ONE, true);
+
+    public static final Dop REM_FLOAT_2ADDR =
+        new Dop(Opcodes.REM_FLOAT_2ADDR, Opcodes.REM_FLOAT,
+            Opcodes.REM_FLOAT, Form12x.THE_ONE, true);
+
+    public static final Dop ADD_DOUBLE_2ADDR =
+        new Dop(Opcodes.ADD_DOUBLE_2ADDR, Opcodes.ADD_DOUBLE,
+            Opcodes.ADD_DOUBLE, Form12x.THE_ONE, true);
+
+    public static final Dop SUB_DOUBLE_2ADDR =
+        new Dop(Opcodes.SUB_DOUBLE_2ADDR, Opcodes.SUB_DOUBLE,
+            Opcodes.SUB_DOUBLE, Form12x.THE_ONE, true);
+
+    public static final Dop MUL_DOUBLE_2ADDR =
+        new Dop(Opcodes.MUL_DOUBLE_2ADDR, Opcodes.MUL_DOUBLE,
+            Opcodes.MUL_DOUBLE, Form12x.THE_ONE, true);
+
+    public static final Dop DIV_DOUBLE_2ADDR =
+        new Dop(Opcodes.DIV_DOUBLE_2ADDR, Opcodes.DIV_DOUBLE,
+            Opcodes.DIV_DOUBLE, Form12x.THE_ONE, true);
+
+    public static final Dop REM_DOUBLE_2ADDR =
+        new Dop(Opcodes.REM_DOUBLE_2ADDR, Opcodes.REM_DOUBLE,
+            Opcodes.REM_DOUBLE, Form12x.THE_ONE, true);
+
+    public static final Dop ADD_INT_LIT16 =
+        new Dop(Opcodes.ADD_INT_LIT16, Opcodes.ADD_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop RSUB_INT =
+        new Dop(Opcodes.RSUB_INT, Opcodes.RSUB_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop MUL_INT_LIT16 =
+        new Dop(Opcodes.MUL_INT_LIT16, Opcodes.MUL_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop DIV_INT_LIT16 =
+        new Dop(Opcodes.DIV_INT_LIT16, Opcodes.DIV_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop REM_INT_LIT16 =
+        new Dop(Opcodes.REM_INT_LIT16, Opcodes.REM_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop AND_INT_LIT16 =
+        new Dop(Opcodes.AND_INT_LIT16, Opcodes.AND_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop OR_INT_LIT16 =
+        new Dop(Opcodes.OR_INT_LIT16, Opcodes.OR_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop XOR_INT_LIT16 =
+        new Dop(Opcodes.XOR_INT_LIT16, Opcodes.XOR_INT,
+            Opcodes.NO_NEXT, Form22s.THE_ONE, true);
+
+    public static final Dop ADD_INT_LIT8 =
+        new Dop(Opcodes.ADD_INT_LIT8, Opcodes.ADD_INT,
+            Opcodes.ADD_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop RSUB_INT_LIT8 =
+        new Dop(Opcodes.RSUB_INT_LIT8, Opcodes.RSUB_INT,
+            Opcodes.RSUB_INT, Form22b.THE_ONE, true);
+
+    public static final Dop MUL_INT_LIT8 =
+        new Dop(Opcodes.MUL_INT_LIT8, Opcodes.MUL_INT,
+            Opcodes.MUL_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop DIV_INT_LIT8 =
+        new Dop(Opcodes.DIV_INT_LIT8, Opcodes.DIV_INT,
+            Opcodes.DIV_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop REM_INT_LIT8 =
+        new Dop(Opcodes.REM_INT_LIT8, Opcodes.REM_INT,
+            Opcodes.REM_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop AND_INT_LIT8 =
+        new Dop(Opcodes.AND_INT_LIT8, Opcodes.AND_INT,
+            Opcodes.AND_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop OR_INT_LIT8 =
+        new Dop(Opcodes.OR_INT_LIT8, Opcodes.OR_INT,
+            Opcodes.OR_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop XOR_INT_LIT8 =
+        new Dop(Opcodes.XOR_INT_LIT8, Opcodes.XOR_INT,
+            Opcodes.XOR_INT_LIT16, Form22b.THE_ONE, true);
+
+    public static final Dop SHL_INT_LIT8 =
+        new Dop(Opcodes.SHL_INT_LIT8, Opcodes.SHL_INT,
+            Opcodes.NO_NEXT, Form22b.THE_ONE, true);
+
+    public static final Dop SHR_INT_LIT8 =
+        new Dop(Opcodes.SHR_INT_LIT8, Opcodes.SHR_INT,
+            Opcodes.NO_NEXT, Form22b.THE_ONE, true);
+
+    public static final Dop USHR_INT_LIT8 =
+        new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT,
+            Opcodes.NO_NEXT, Form22b.THE_ONE, true);
+
+    public static final Dop CONST_CLASS_JUMBO =
+        new Dop(Opcodes.CONST_CLASS_JUMBO, Opcodes.CONST_CLASS,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop CHECK_CAST_JUMBO =
+        new Dop(Opcodes.CHECK_CAST_JUMBO, Opcodes.CHECK_CAST,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop INSTANCE_OF_JUMBO =
+        new Dop(Opcodes.INSTANCE_OF_JUMBO, Opcodes.INSTANCE_OF,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop NEW_INSTANCE_JUMBO =
+        new Dop(Opcodes.NEW_INSTANCE_JUMBO, Opcodes.NEW_INSTANCE,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop NEW_ARRAY_JUMBO =
+        new Dop(Opcodes.NEW_ARRAY_JUMBO, Opcodes.NEW_ARRAY,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop FILLED_NEW_ARRAY_JUMBO =
+        new Dop(Opcodes.FILLED_NEW_ARRAY_JUMBO, Opcodes.FILLED_NEW_ARRAY,
+            Opcodes.NO_NEXT, Form5rc.THE_ONE, false);
+
+    public static final Dop IGET_JUMBO =
+        new Dop(Opcodes.IGET_JUMBO, Opcodes.IGET,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IGET_WIDE_JUMBO =
+        new Dop(Opcodes.IGET_WIDE_JUMBO, Opcodes.IGET_WIDE,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IGET_OBJECT_JUMBO =
+        new Dop(Opcodes.IGET_OBJECT_JUMBO, Opcodes.IGET_OBJECT,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IGET_BOOLEAN_JUMBO =
+        new Dop(Opcodes.IGET_BOOLEAN_JUMBO, Opcodes.IGET_BOOLEAN,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IGET_BYTE_JUMBO =
+        new Dop(Opcodes.IGET_BYTE_JUMBO, Opcodes.IGET_BYTE,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IGET_CHAR_JUMBO =
+        new Dop(Opcodes.IGET_CHAR_JUMBO, Opcodes.IGET_CHAR,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IGET_SHORT_JUMBO =
+        new Dop(Opcodes.IGET_SHORT_JUMBO, Opcodes.IGET_SHORT,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, true);
+
+    public static final Dop IPUT_JUMBO =
+        new Dop(Opcodes.IPUT_JUMBO, Opcodes.IPUT,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop IPUT_WIDE_JUMBO =
+        new Dop(Opcodes.IPUT_WIDE_JUMBO, Opcodes.IPUT_WIDE,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop IPUT_OBJECT_JUMBO =
+        new Dop(Opcodes.IPUT_OBJECT_JUMBO, Opcodes.IPUT_OBJECT,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop IPUT_BOOLEAN_JUMBO =
+        new Dop(Opcodes.IPUT_BOOLEAN_JUMBO, Opcodes.IPUT_BOOLEAN,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop IPUT_BYTE_JUMBO =
+        new Dop(Opcodes.IPUT_BYTE_JUMBO, Opcodes.IPUT_BYTE,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop IPUT_CHAR_JUMBO =
+        new Dop(Opcodes.IPUT_CHAR_JUMBO, Opcodes.IPUT_CHAR,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop IPUT_SHORT_JUMBO =
+        new Dop(Opcodes.IPUT_SHORT_JUMBO, Opcodes.IPUT_SHORT,
+            Opcodes.NO_NEXT, Form52c.THE_ONE, false);
+
+    public static final Dop SGET_JUMBO =
+        new Dop(Opcodes.SGET_JUMBO, Opcodes.SGET,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SGET_WIDE_JUMBO =
+        new Dop(Opcodes.SGET_WIDE_JUMBO, Opcodes.SGET_WIDE,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SGET_OBJECT_JUMBO =
+        new Dop(Opcodes.SGET_OBJECT_JUMBO, Opcodes.SGET_OBJECT,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SGET_BOOLEAN_JUMBO =
+        new Dop(Opcodes.SGET_BOOLEAN_JUMBO, Opcodes.SGET_BOOLEAN,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SGET_BYTE_JUMBO =
+        new Dop(Opcodes.SGET_BYTE_JUMBO, Opcodes.SGET_BYTE,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SGET_CHAR_JUMBO =
+        new Dop(Opcodes.SGET_CHAR_JUMBO, Opcodes.SGET_CHAR,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SGET_SHORT_JUMBO =
+        new Dop(Opcodes.SGET_SHORT_JUMBO, Opcodes.SGET_SHORT,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, true);
+
+    public static final Dop SPUT_JUMBO =
+        new Dop(Opcodes.SPUT_JUMBO, Opcodes.SPUT,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop SPUT_WIDE_JUMBO =
+        new Dop(Opcodes.SPUT_WIDE_JUMBO, Opcodes.SPUT_WIDE,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop SPUT_OBJECT_JUMBO =
+        new Dop(Opcodes.SPUT_OBJECT_JUMBO, Opcodes.SPUT_OBJECT,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop SPUT_BOOLEAN_JUMBO =
+        new Dop(Opcodes.SPUT_BOOLEAN_JUMBO, Opcodes.SPUT_BOOLEAN,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop SPUT_BYTE_JUMBO =
+        new Dop(Opcodes.SPUT_BYTE_JUMBO, Opcodes.SPUT_BYTE,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop SPUT_CHAR_JUMBO =
+        new Dop(Opcodes.SPUT_CHAR_JUMBO, Opcodes.SPUT_CHAR,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop SPUT_SHORT_JUMBO =
+        new Dop(Opcodes.SPUT_SHORT_JUMBO, Opcodes.SPUT_SHORT,
+            Opcodes.NO_NEXT, Form41c.THE_ONE, false);
+
+    public static final Dop INVOKE_VIRTUAL_JUMBO =
+        new Dop(Opcodes.INVOKE_VIRTUAL_JUMBO, Opcodes.INVOKE_VIRTUAL,
+            Opcodes.NO_NEXT, Form5rc.THE_ONE, false);
+
+    public static final Dop INVOKE_SUPER_JUMBO =
+        new Dop(Opcodes.INVOKE_SUPER_JUMBO, Opcodes.INVOKE_SUPER,
+            Opcodes.NO_NEXT, Form5rc.THE_ONE, false);
+
+    public static final Dop INVOKE_DIRECT_JUMBO =
+        new Dop(Opcodes.INVOKE_DIRECT_JUMBO, Opcodes.INVOKE_DIRECT,
+            Opcodes.NO_NEXT, Form5rc.THE_ONE, false);
+
+    public static final Dop INVOKE_STATIC_JUMBO =
+        new Dop(Opcodes.INVOKE_STATIC_JUMBO, Opcodes.INVOKE_STATIC,
+            Opcodes.NO_NEXT, Form5rc.THE_ONE, false);
+
+    public static final Dop INVOKE_INTERFACE_JUMBO =
+        new Dop(Opcodes.INVOKE_INTERFACE_JUMBO, Opcodes.INVOKE_INTERFACE,
+            Opcodes.NO_NEXT, Form5rc.THE_ONE, false);
+
+    // END(dops)
+
+    // Static initialization.
+    static {
+        DOPS = new Dop[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
+
+        set(SPECIAL_FORMAT);
+
+        // BEGIN(dops-init); GENERATED AUTOMATICALLY BY opcode-gen
+        set(NOP);
+        set(MOVE);
+        set(MOVE_FROM16);
+        set(MOVE_16);
+        set(MOVE_WIDE);
+        set(MOVE_WIDE_FROM16);
+        set(MOVE_WIDE_16);
+        set(MOVE_OBJECT);
+        set(MOVE_OBJECT_FROM16);
+        set(MOVE_OBJECT_16);
+        set(MOVE_RESULT);
+        set(MOVE_RESULT_WIDE);
+        set(MOVE_RESULT_OBJECT);
+        set(MOVE_EXCEPTION);
+        set(RETURN_VOID);
+        set(RETURN);
+        set(RETURN_WIDE);
+        set(RETURN_OBJECT);
+        set(CONST_4);
+        set(CONST_16);
+        set(CONST);
+        set(CONST_HIGH16);
+        set(CONST_WIDE_16);
+        set(CONST_WIDE_32);
+        set(CONST_WIDE);
+        set(CONST_WIDE_HIGH16);
+        set(CONST_STRING);
+        set(CONST_STRING_JUMBO);
+        set(CONST_CLASS);
+        set(MONITOR_ENTER);
+        set(MONITOR_EXIT);
+        set(CHECK_CAST);
+        set(INSTANCE_OF);
+        set(ARRAY_LENGTH);
+        set(NEW_INSTANCE);
+        set(NEW_ARRAY);
+        set(FILLED_NEW_ARRAY);
+        set(FILLED_NEW_ARRAY_RANGE);
+        set(FILL_ARRAY_DATA);
+        set(THROW);
+        set(GOTO);
+        set(GOTO_16);
+        set(GOTO_32);
+        set(PACKED_SWITCH);
+        set(SPARSE_SWITCH);
+        set(CMPL_FLOAT);
+        set(CMPG_FLOAT);
+        set(CMPL_DOUBLE);
+        set(CMPG_DOUBLE);
+        set(CMP_LONG);
+        set(IF_EQ);
+        set(IF_NE);
+        set(IF_LT);
+        set(IF_GE);
+        set(IF_GT);
+        set(IF_LE);
+        set(IF_EQZ);
+        set(IF_NEZ);
+        set(IF_LTZ);
+        set(IF_GEZ);
+        set(IF_GTZ);
+        set(IF_LEZ);
+        set(AGET);
+        set(AGET_WIDE);
+        set(AGET_OBJECT);
+        set(AGET_BOOLEAN);
+        set(AGET_BYTE);
+        set(AGET_CHAR);
+        set(AGET_SHORT);
+        set(APUT);
+        set(APUT_WIDE);
+        set(APUT_OBJECT);
+        set(APUT_BOOLEAN);
+        set(APUT_BYTE);
+        set(APUT_CHAR);
+        set(APUT_SHORT);
+        set(IGET);
+        set(IGET_WIDE);
+        set(IGET_OBJECT);
+        set(IGET_BOOLEAN);
+        set(IGET_BYTE);
+        set(IGET_CHAR);
+        set(IGET_SHORT);
+        set(IPUT);
+        set(IPUT_WIDE);
+        set(IPUT_OBJECT);
+        set(IPUT_BOOLEAN);
+        set(IPUT_BYTE);
+        set(IPUT_CHAR);
+        set(IPUT_SHORT);
+        set(SGET);
+        set(SGET_WIDE);
+        set(SGET_OBJECT);
+        set(SGET_BOOLEAN);
+        set(SGET_BYTE);
+        set(SGET_CHAR);
+        set(SGET_SHORT);
+        set(SPUT);
+        set(SPUT_WIDE);
+        set(SPUT_OBJECT);
+        set(SPUT_BOOLEAN);
+        set(SPUT_BYTE);
+        set(SPUT_CHAR);
+        set(SPUT_SHORT);
+        set(INVOKE_VIRTUAL);
+        set(INVOKE_SUPER);
+        set(INVOKE_DIRECT);
+        set(INVOKE_STATIC);
+        set(INVOKE_INTERFACE);
+        set(INVOKE_VIRTUAL_RANGE);
+        set(INVOKE_SUPER_RANGE);
+        set(INVOKE_DIRECT_RANGE);
+        set(INVOKE_STATIC_RANGE);
+        set(INVOKE_INTERFACE_RANGE);
+        set(NEG_INT);
+        set(NOT_INT);
+        set(NEG_LONG);
+        set(NOT_LONG);
+        set(NEG_FLOAT);
+        set(NEG_DOUBLE);
+        set(INT_TO_LONG);
+        set(INT_TO_FLOAT);
+        set(INT_TO_DOUBLE);
+        set(LONG_TO_INT);
+        set(LONG_TO_FLOAT);
+        set(LONG_TO_DOUBLE);
+        set(FLOAT_TO_INT);
+        set(FLOAT_TO_LONG);
+        set(FLOAT_TO_DOUBLE);
+        set(DOUBLE_TO_INT);
+        set(DOUBLE_TO_LONG);
+        set(DOUBLE_TO_FLOAT);
+        set(INT_TO_BYTE);
+        set(INT_TO_CHAR);
+        set(INT_TO_SHORT);
+        set(ADD_INT);
+        set(SUB_INT);
+        set(MUL_INT);
+        set(DIV_INT);
+        set(REM_INT);
+        set(AND_INT);
+        set(OR_INT);
+        set(XOR_INT);
+        set(SHL_INT);
+        set(SHR_INT);
+        set(USHR_INT);
+        set(ADD_LONG);
+        set(SUB_LONG);
+        set(MUL_LONG);
+        set(DIV_LONG);
+        set(REM_LONG);
+        set(AND_LONG);
+        set(OR_LONG);
+        set(XOR_LONG);
+        set(SHL_LONG);
+        set(SHR_LONG);
+        set(USHR_LONG);
+        set(ADD_FLOAT);
+        set(SUB_FLOAT);
+        set(MUL_FLOAT);
+        set(DIV_FLOAT);
+        set(REM_FLOAT);
+        set(ADD_DOUBLE);
+        set(SUB_DOUBLE);
+        set(MUL_DOUBLE);
+        set(DIV_DOUBLE);
+        set(REM_DOUBLE);
+        set(ADD_INT_2ADDR);
+        set(SUB_INT_2ADDR);
+        set(MUL_INT_2ADDR);
+        set(DIV_INT_2ADDR);
+        set(REM_INT_2ADDR);
+        set(AND_INT_2ADDR);
+        set(OR_INT_2ADDR);
+        set(XOR_INT_2ADDR);
+        set(SHL_INT_2ADDR);
+        set(SHR_INT_2ADDR);
+        set(USHR_INT_2ADDR);
+        set(ADD_LONG_2ADDR);
+        set(SUB_LONG_2ADDR);
+        set(MUL_LONG_2ADDR);
+        set(DIV_LONG_2ADDR);
+        set(REM_LONG_2ADDR);
+        set(AND_LONG_2ADDR);
+        set(OR_LONG_2ADDR);
+        set(XOR_LONG_2ADDR);
+        set(SHL_LONG_2ADDR);
+        set(SHR_LONG_2ADDR);
+        set(USHR_LONG_2ADDR);
+        set(ADD_FLOAT_2ADDR);
+        set(SUB_FLOAT_2ADDR);
+        set(MUL_FLOAT_2ADDR);
+        set(DIV_FLOAT_2ADDR);
+        set(REM_FLOAT_2ADDR);
+        set(ADD_DOUBLE_2ADDR);
+        set(SUB_DOUBLE_2ADDR);
+        set(MUL_DOUBLE_2ADDR);
+        set(DIV_DOUBLE_2ADDR);
+        set(REM_DOUBLE_2ADDR);
+        set(ADD_INT_LIT16);
+        set(RSUB_INT);
+        set(MUL_INT_LIT16);
+        set(DIV_INT_LIT16);
+        set(REM_INT_LIT16);
+        set(AND_INT_LIT16);
+        set(OR_INT_LIT16);
+        set(XOR_INT_LIT16);
+        set(ADD_INT_LIT8);
+        set(RSUB_INT_LIT8);
+        set(MUL_INT_LIT8);
+        set(DIV_INT_LIT8);
+        set(REM_INT_LIT8);
+        set(AND_INT_LIT8);
+        set(OR_INT_LIT8);
+        set(XOR_INT_LIT8);
+        set(SHL_INT_LIT8);
+        set(SHR_INT_LIT8);
+        set(USHR_INT_LIT8);
+        set(CONST_CLASS_JUMBO);
+        set(CHECK_CAST_JUMBO);
+        set(INSTANCE_OF_JUMBO);
+        set(NEW_INSTANCE_JUMBO);
+        set(NEW_ARRAY_JUMBO);
+        set(FILLED_NEW_ARRAY_JUMBO);
+        set(IGET_JUMBO);
+        set(IGET_WIDE_JUMBO);
+        set(IGET_OBJECT_JUMBO);
+        set(IGET_BOOLEAN_JUMBO);
+        set(IGET_BYTE_JUMBO);
+        set(IGET_CHAR_JUMBO);
+        set(IGET_SHORT_JUMBO);
+        set(IPUT_JUMBO);
+        set(IPUT_WIDE_JUMBO);
+        set(IPUT_OBJECT_JUMBO);
+        set(IPUT_BOOLEAN_JUMBO);
+        set(IPUT_BYTE_JUMBO);
+        set(IPUT_CHAR_JUMBO);
+        set(IPUT_SHORT_JUMBO);
+        set(SGET_JUMBO);
+        set(SGET_WIDE_JUMBO);
+        set(SGET_OBJECT_JUMBO);
+        set(SGET_BOOLEAN_JUMBO);
+        set(SGET_BYTE_JUMBO);
+        set(SGET_CHAR_JUMBO);
+        set(SGET_SHORT_JUMBO);
+        set(SPUT_JUMBO);
+        set(SPUT_WIDE_JUMBO);
+        set(SPUT_OBJECT_JUMBO);
+        set(SPUT_BOOLEAN_JUMBO);
+        set(SPUT_BYTE_JUMBO);
+        set(SPUT_CHAR_JUMBO);
+        set(SPUT_SHORT_JUMBO);
+        set(INVOKE_VIRTUAL_JUMBO);
+        set(INVOKE_SUPER_JUMBO);
+        set(INVOKE_DIRECT_JUMBO);
+        set(INVOKE_STATIC_JUMBO);
+        set(INVOKE_INTERFACE_JUMBO);
+        // END(dops-init)
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Dops() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the {@link Dop} for the given opcode value.
+     *
+     * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the
+     * opcode value
+     * @return {@code non-null;} the associated opcode instance
+     */
+    public static Dop get(int opcode) {
+        int idx = opcode - Opcodes.MIN_VALUE;
+
+        try {
+            Dop result = DOPS[idx];
+            if (result != null) {
+                return result;
+            }
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Fall through.
+        }
+
+        throw new IllegalArgumentException("bogus opcode");
+    }
+
+    /**
+     * Gets the next {@link Dop} in the instruction fitting chain after the
+     * given instance, if any.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param options {@code non-null;} options, used to determine
+     * which opcodes are potentially off-limits
+     * @return {@code null-ok;} the next opcode in the same family, in the
+     * chain of opcodes to try, or {@code null} if the given opcode is
+     * the last in its chain
+     */
+    public static Dop getNextOrNull(Dop opcode, DexOptions options) {
+        boolean suppressExtendedOpcodes = !options.canUseExtendedOpcodes();
+
+        for (;;) {
+            int nextOpcode = opcode.getNextOpcode();
+
+            if (nextOpcode == Opcodes.NO_NEXT) {
+                return null;
+            }
+
+            opcode = get(nextOpcode);
+
+            if (suppressExtendedOpcodes && Opcodes.isExtended(nextOpcode)) {
+                /*
+                 * Continuing rather than just returning null here
+                 * protects against the possibility that an
+                 * instruction fitting chain might list non-extended
+                 * opcodes after extended ones.
+                 */
+                continue;
+            }
+
+            return opcode;
+        }
+    }
+
+    /**
+     * Puts the given opcode into the table of all ops.
+     *
+     * @param opcode {@code non-null;} the opcode
+     */
+    private static void set(Dop opcode) {
+        int idx = opcode.getOpcode() - Opcodes.MIN_VALUE;
+        DOPS[idx] = opcode;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/FixedSizeInsn.java b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
new file mode 100644
index 0000000..faed530
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Base class for instructions which are of a fixed code size and
+ * which use {@link InsnFormat} methods to write themselves. This
+ * includes most &mdash; but not all &mdash; instructions.
+ */
+public abstract class FixedSizeInsn extends DalvInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * <p><b>Note:</b> In the unlikely event that an instruction takes
+     * absolutely no registers (e.g., a {@code nop} or a
+     * no-argument no-result * static method call), then the given
+     * register list may be passed as {@link
+     * RegisterSpecList#EMPTY}.</p>
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     */
+    public FixedSizeInsn(Dop opcode, SourcePosition position,
+                         RegisterSpecList registers) {
+        super(opcode, position, registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int codeSize() {
+        return getOpcode().getFormat().codeSize();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(AnnotatedOutput out) {
+        getOpcode().getFormat().writeTo(out, this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withRegisterOffset(int delta) {
+        return withRegisters(getRegisters().withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected final String listingString0(boolean noteIndices) {
+        return getOpcode().getFormat().listingString(this, noteIndices);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
new file mode 100644
index 0000000..6fab094
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Combination instruction which turns into a variable number of
+ * {@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 {
+    /** {@code null-ok;} cached instructions, if constructed */
+    private SimpleInsn[] insns;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} source registers
+     */
+    public HighRegisterPrefix(SourcePosition position,
+                              RegisterSpecList registers) {
+        super(position, registers);
+
+        if (registers.size() == 0) {
+            throw new IllegalArgumentException("registers.size() == 0");
+        }
+
+        insns = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        int result = 0;
+
+        calculateInsnsIfNecessary();
+
+        for (SimpleInsn insn : insns) {
+            result += insn.codeSize();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        calculateInsnsIfNecessary();
+
+        for (SimpleInsn insn : insns) {
+            insn.writeTo(out);
+        }
+    }
+
+    /**
+     * Helper for {@link #codeSize} and {@link #writeTo} which sets up
+     * {@link #insns} if not already done.
+     */
+    private void calculateInsnsIfNecessary() {
+        if (insns != null) {
+            return;
+        }
+
+        RegisterSpecList registers = getRegisters();
+        int sz = registers.size();
+
+        insns = new SimpleInsn[sz];
+
+        for (int i = 0, outAt = 0; i < sz; i++) {
+            RegisterSpec src = registers.get(i);
+            insns[i] = moveInsnFor(src, outAt);
+            outAt += src.getCategory();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new HighRegisterPrefix(getPosition(), registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        RegisterSpecList registers = getRegisters();
+        int sz = registers.size();
+        StringBuffer sb = new StringBuffer(100);
+
+        for (int i = 0, outAt = 0; i < sz; i++) {
+            RegisterSpec src = registers.get(i);
+            SimpleInsn insn = moveInsnFor(src, outAt);
+
+            if (i != 0) {
+                sb.append('\n');
+            }
+
+            sb.append(insn.listingString0(noteIndices));
+
+            outAt += src.getCategory();
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns the proper move instruction for the given source spec
+     * and destination index.
+     *
+     * @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,
+                RegisterSpec.make(destIndex, src.getType()),
+                src);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/InsnFormat.java b/dx/src/com/android/dx/dex/code/InsnFormat.java
new file mode 100644
index 0000000..bf9f08e
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/InsnFormat.java
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstKnownNull;
+import com.android.dx.rop.cst.CstLiteral64;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.BitSet;
+
+/**
+ * Base class for all instruction format handlers. Instruction format
+ * handlers know how to translate {@link DalvInsn} instances into
+ * streams of code units, as well as human-oriented listing strings
+ * representing such translations.
+ */
+public abstract class InsnFormat {
+    /**
+     * flag to enable/disable the new extended opcode formats; meant as a
+     * temporary measure until VM support for the salient opcodes is
+     * added. TODO: Remove this declaration when the VM can deal.
+     */
+    public static boolean ALLOW_EXTENDED_OPCODES = true;
+
+    /**
+     * Returns the string form, suitable for inclusion in a listing
+     * dump, of the given instruction. The instruction must be of this
+     * instance's format for proper operation.
+     *
+     * @param insn {@code non-null;} the instruction
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @return {@code non-null;} the string form
+     */
+    public final String listingString(DalvInsn insn, boolean noteIndices) {
+        String op = insn.getOpcode().getName();
+        String arg = insnArgString(insn);
+        String comment = insnCommentString(insn, noteIndices);
+        StringBuilder sb = new StringBuilder(100);
+
+        sb.append(op);
+
+        if (arg.length() != 0) {
+            sb.append(' ');
+            sb.append(arg);
+        }
+
+        if (comment.length() != 0) {
+            sb.append(" // ");
+            sb.append(comment);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 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 ""}, not
+     * {@code null}.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @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 ""}, not
+     * {@code null}.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @param insn {@code non-null;} the instruction
+     * @param noteIndices whether to include an explicit notation of
+     * constant pool indices
+     * @return {@code non-null;} the string form
+     */
+    public abstract String insnCommentString(DalvInsn insn,
+            boolean noteIndices);
+
+    /**
+     * Gets the code size of instructions that use this format. The
+     * size is a number of 16-bit code units, not bytes. This should
+     * throw an exception if this format is of variable size.
+     *
+     * @return {@code >= 0;} the instruction length in 16-bit code units
+     */
+    public abstract int codeSize();
+
+    /**
+     * Returns whether or not the given instruction's arguments will
+     * fit in this instance's format. This includes such things as
+     * counting register arguments, checking register ranges, and
+     * making sure that additional arguments are of appropriate types
+     * and are in-range. If this format has a branch target but the
+     * instruction's branch offset is unknown, this method will simply
+     * not check the offset.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @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 which of a given instruction's registers will fit in
+     * this instance's format.
+     *
+     * <p>The default implementation of this method always returns
+     * an empty BitSet. Subclasses must override this method if they
+     * have registers.</p>
+     *
+     * @param insn {@code non-null;} the instruction to check
+     * @return {@code non-null;} a BitSet flagging registers in the
+     * register list that are compatible to this format
+     */
+    public BitSet compatibleRegs(DalvInsn insn) {
+        return new BitSet();
+    }
+
+    /**
+     * Returns whether or not the given instruction's branch offset will
+     * 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}. Subclasses must override this method if they
+     * include branch offsets.</p>
+     *
+     * @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;
+    }
+
+    /**
+     * Writes the code units for the given instruction to the given
+     * output destination. The instruction must be of this instance's format.
+     *
+     * <p>Subclasses must override this method.</p>
+     *
+     * @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 {@code non-null;} the list of registers
+     * @return {@code non-null;} the string form
+     */
+    protected static String regListString(RegisterSpecList list) {
+        int sz = list.size();
+        StringBuffer sb = new StringBuffer(sz * 5 + 2);
+
+        sb.append('{');
+
+        for (int i = 0; i < sz; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(list.get(i).regString());
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a register range string.
+     *
+     * @param list {@code non-null;} the list of registers (which must be
+     * sequential)
+     * @return {@code non-null;} the string form
+     */
+    protected static String regRangeString(RegisterSpecList list) {
+        int size = list.size();
+        StringBuilder sb = new StringBuilder(30);
+
+        sb.append("{");
+
+        switch (size) {
+            case 0: {
+                // Nothing to do.
+                break;
+            }
+            case 1: {
+                sb.append(list.get(0).regString());
+                break;
+            }
+            default: {
+                RegisterSpec lastReg = list.get(size - 1);
+                if (lastReg.getCategory() == 2) {
+                    /*
+                     * Add one to properly represent a list-final
+                     * category-2 register.
+                     */
+                    lastReg = lastReg.withOffset(1);
+                }
+
+                sb.append(list.get(0).regString());
+                sb.append("..");
+                sb.append(lastReg.regString());
+            }
+        }
+
+        sb.append("}");
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a literal bits argument string.
+     *
+     * @param value the value
+     * @return {@code non-null;} the string form
+     */
+    protected static String literalBitsString(CstLiteralBits value) {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append('#');
+
+        if (value instanceof CstKnownNull) {
+            sb.append("null");
+        } else {
+            sb.append(value.typeName());
+            sb.append(' ');
+            sb.append(value.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a literal bits comment string.
+     *
+     * @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}
+     * @return {@code non-null;} the comment
+     */
+    protected static String literalBitsComment(CstLiteralBits value,
+            int width) {
+        StringBuffer sb = new StringBuffer(20);
+
+        sb.append("#");
+
+        long bits;
+
+        if (value instanceof CstLiteral64) {
+            bits = ((CstLiteral64) value).getLongBits();
+        } else {
+            bits = value.getIntBits();
+        }
+
+        switch (width) {
+            case 4:  sb.append(Hex.uNibble((int) bits)); break;
+            case 8:  sb.append(Hex.u1((int) bits));      break;
+            case 16: sb.append(Hex.u2((int) bits));      break;
+            case 32: sb.append(Hex.u4((int) bits));      break;
+            case 64: sb.append(Hex.u8(bits));            break;
+            default: {
+                throw new RuntimeException("shouldn't happen");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to return a branch address string.
+     *
+     * @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;
+        int address = ti.getTargetAddress();
+
+        return (address == (char) address) ? Hex.u2(address) : Hex.u4(address);
+    }
+
+    /**
+     * Helper method to return the comment for a branch.
+     *
+     * @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;
+        int offset = ti.getTargetOffset();
+
+        return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset);
+    }
+
+    /**
+     * Helper method to return the constant string for a {@link CstInsn}
+     * in human form.
+     *
+     * @param insn {@code non-null;} a constant-bearing instruction
+     * @return {@code non-null;} the human string form of the contained
+     * constant
+     */
+    protected static String cstString(DalvInsn insn) {
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return cst instanceof CstString ? ((CstString) cst).toQuoted() : cst.toHuman();
+    }
+
+    /**
+     * Helper method to return an instruction comment for a 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;
+
+        if (! ci.hasIndex()) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder(20);
+        int index = ci.getIndex();
+
+        sb.append(ci.getConstant().typeName());
+        sb.append('@');
+
+        if (index < 65536) {
+            sb.append(Hex.u2(index));
+        } else {
+            sb.append(Hex.u4(index));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in a nibble.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -8..+7
+     */
+    protected static boolean signedFitsInNibble(int value) {
+        return (value >= -8) && (value <= 7);
+    }
+
+    /**
+     * Helper method to determine if an unsigned int value fits in a nibble.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range 0..0xf
+     */
+    protected static boolean unsignedFitsInNibble(int value) {
+        return value == (value & 0xf);
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in a byte.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -0x80..+0x7f
+     */
+    protected static boolean signedFitsInByte(int value) {
+        return (byte) value == value;
+    }
+
+    /**
+     * Helper method to determine if an unsigned int value fits in a byte.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range 0..0xff
+     */
+    protected static boolean unsignedFitsInByte(int value) {
+        return value == (value & 0xff);
+    }
+
+    /**
+     * Helper method to determine if a signed int value fits in a short.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range -0x8000..+0x7fff
+     */
+    protected static boolean signedFitsInShort(int value) {
+        return (short) value == value;
+    }
+
+    /**
+     * Helper method to determine if an unsigned int value fits in a short.
+     *
+     * @param value the value in question
+     * @return {@code true} iff it's in the range 0..0xffff
+     */
+    protected static boolean unsignedFitsInShort(int value) {
+        return value == (value & 0xffff);
+    }
+
+    /**
+     * Helper method to determine if a list of registers are sequential,
+     * including degenerate cases for empty or single-element lists.
+     *
+     * @param list {@code non-null;} the list of registers
+     * @return {@code true} iff the list is sequentially ordered
+     */
+    protected static boolean isRegListSequential(RegisterSpecList list) {
+        int sz = list.size();
+
+        if (sz < 2) {
+            return true;
+        }
+
+        int first = list.get(0).getReg();
+        int next = first;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = list.get(i);
+            if (one.getReg() != next) {
+                return false;
+            }
+            next += one.getCategory();
+        }
+
+        return true;
+    }
+
+    /**
+     * Helper method to extract the callout-argument index from an
+     * appropriate instruction.
+     *
+     * @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();
+
+        if (arg < 0) {
+            throw new IllegalArgumentException("bogus insn");
+        }
+
+        return arg;
+    }
+
+    /**
+     * Helper method to combine an opcode and a second byte of data into
+     * the appropriate form for emitting into a code buffer.
+     *
+     * @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) {
+        if ((arg & 0xff) != arg) {
+            throw new IllegalArgumentException("arg out of range 0..255");
+        }
+
+        int opcode = insn.getOpcode().getOpcode();
+
+        if ((opcode & 0xff) != opcode) {
+            throw new IllegalArgumentException("opcode out of range 0..255");
+        }
+
+        return (short) (opcode | (arg << 8));
+    }
+
+    /**
+     * Helper method to get an extended (16-bit) opcode out of an
+     * instruction, returning it as a code unit. The opcode
+     * <i>must</i> be an extended opcode.
+     *
+     * @param insn {@code non-null;} the instruction containing the
+     * extended opcode
+     * @return the opcode as a code unit
+     */
+    protected static short opcodeUnit(DalvInsn insn) {
+        int opcode = insn.getOpcode().getOpcode();
+
+        if ((opcode < 0xff) || (opcode > 0xffff)) {
+            throw new IllegalArgumentException(
+                "extended opcode out of range 255..65535");
+        }
+
+        return (short) opcode;
+    }
+
+    /**
+     * Helper method to combine two bytes into a code unit.
+     *
+     * @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) {
+        if ((low & 0xff) != low) {
+            throw new IllegalArgumentException("low out of range 0..255");
+        }
+
+        if ((high & 0xff) != high) {
+            throw new IllegalArgumentException("high out of range 0..255");
+        }
+
+        return (short) (low | (high << 8));
+    }
+
+    /**
+     * Helper method to combine four nibbles into a code unit.
+     *
+     * @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) {
+        if ((n0 & 0xf) != n0) {
+            throw new IllegalArgumentException("n0 out of range 0..15");
+        }
+
+        if ((n1 & 0xf) != n1) {
+            throw new IllegalArgumentException("n1 out of range 0..15");
+        }
+
+        if ((n2 & 0xf) != n2) {
+            throw new IllegalArgumentException("n2 out of range 0..15");
+        }
+
+        if ((n3 & 0xf) != n3) {
+            throw new IllegalArgumentException("n3 out of range 0..15");
+        }
+
+        return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12));
+    }
+
+    /**
+     * Helper method to combine two nibbles into a byte.
+     *
+     * @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) {
+            throw new IllegalArgumentException("low out of range 0..15");
+        }
+
+        if ((high & 0xf) != high) {
+            throw new IllegalArgumentException("high out of range 0..15");
+        }
+
+        return low | (high << 4);
+    }
+
+    /**
+     * Writes one code unit to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0) {
+        out.writeShort(c0);
+    }
+
+    /**
+     * Writes two code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+    }
+
+    /**
+     * Writes three code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+            short c2) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+    }
+
+    /**
+     * Writes four code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     * @param c3 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+            short c2, short c3) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+        out.writeShort(c3);
+    }
+
+    /**
+     * Writes five code units to the given output destination.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1 code unit to write
+     * @param c2 code unit to write
+     * @param c3 code unit to write
+     * @param c4 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, short c1,
+            short c2, short c3, short c4) {
+        out.writeShort(c0);
+        out.writeShort(c1);
+        out.writeShort(c2);
+        out.writeShort(c3);
+        out.writeShort(c4);
+    }
+
+    /**
+     * Writes three code units to the given output destination, where the
+     * second and third are represented as single <code>int</code> and emitted
+     * in little-endian order.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1c2 code unit pair to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, int c1c2) {
+        write(out, c0, (short) c1c2, (short) (c1c2 >> 16));
+    }
+
+    /**
+     * Writes four code units to the given output destination, where the
+     * second and third are represented as single <code>int</code> and emitted
+     * in little-endian order.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1c2 code unit pair to write
+     * @param c3 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, int c1c2,
+            short c3) {
+        write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3);
+    }
+
+    /**
+     * Writes five code units to the given output destination, where the
+     * second and third are represented as single <code>int</code> and emitted
+     * in little-endian order.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1c2 code unit pair to write
+     * @param c3 code unit to write
+     * @param c4 code unit to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, int c1c2,
+            short c3, short c4) {
+        write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3, c4);
+    }
+
+    /**
+     * Writes five code units to the given output destination, where the
+     * second through fifth are represented as single <code>long</code>
+     * and emitted in little-endian order.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param c0 code unit to write
+     * @param c1c2c3c4 code unit quad to write
+     */
+    protected static void write(AnnotatedOutput out, short c0, long c1c2c3c4) {
+        write(out, c0, (short) c1c2c3c4, (short) (c1c2c3c4 >> 16),
+                (short) (c1c2c3c4 >> 32), (short) (c1c2c3c4 >> 48));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/LocalEnd.java b/dx/src/com/android/dx/dex/code/LocalEnd.java
new file mode 100644
index 0000000..1c2bf89
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/LocalEnd.java
@@ -0,0 +1,90 @@
+/*
+ * 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.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to explicitly end the mapping of a
+ * register to a named local variable. That is, an instance of this
+ * class in an instruction stream indicates that starting with the
+ * subsequent instruction, the indicated variable is no longer valid.
+ */
+public final class LocalEnd extends ZeroSizeInsn {
+    /**
+     * {@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
+     * will check the other info for consistency.
+     */
+    private final RegisterSpec local;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param local {@code non-null;} register spec representing the local
+     * variable introduced by this instance
+     */
+    public LocalEnd(SourcePosition position, RegisterSpec local) {
+        super(position);
+
+        if (local == null) {
+            throw new NullPointerException("local == null");
+        }
+
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return new LocalEnd(getPosition(), local.withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new LocalEnd(getPosition(), local);
+    }
+
+    /**
+     * Gets the register spec representing the local variable ended
+     * by this instance.
+     *
+     * @return {@code non-null;} the register spec
+     */
+    public RegisterSpec getLocal() {
+        return local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return local.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        return "local-end " + LocalStart.localString(local);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/LocalList.java b/dx/src/com/android/dx/dex/code/LocalList.java
new file mode 100644
index 0000000..ab8343a
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/LocalList.java
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecSet;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.FixedSizeList;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * List of local variables. Each local variable entry indicates a
+ * range of code which it is valid for, a register number, a name,
+ * and a type.
+ */
+public final class LocalList extends FixedSizeList {
+    /** {@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}.
+     *
+     * @param size {@code >= 0;} the size of the list
+     */
+    public LocalList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     */
+    public void debugPrint(PrintStream out, String prefix) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            out.print(prefix);
+            out.println(get(i));
+        }
+    }
+
+    /**
+     * Disposition of a local entry.
+     */
+    public static enum Disposition {
+        /** local started (introduced) */
+        START,
+
+        /** local ended without being replaced */
+        END_SIMPLY,
+
+        /** local ended because it was directly replaced */
+        END_REPLACED,
+
+        /** local ended because it was moved to a different register */
+        END_MOVED,
+
+        /**
+         * local ended because the previous local clobbered this one
+         * (because it is category-2)
+         */
+        END_CLOBBERED_BY_PREV,
+
+        /**
+         * local ended because the next local clobbered this one
+         * (because this one is a category-2)
+         */
+        END_CLOBBERED_BY_NEXT;
+    }
+
+    /**
+     * Entry in a local list.
+     */
+    public static class Entry implements Comparable<Entry> {
+        /** {@code >= 0;} address */
+        private final int address;
+
+        /** {@code non-null;} disposition of the local */
+        private final Disposition disposition;
+
+        /** {@code non-null;} register spec representing the variable */
+        private final RegisterSpec spec;
+
+        /** {@code non-null;} variable type (derived from {@code spec}) */
+        private final CstType type;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("address < 0");
+            }
+
+            if (disposition == null) {
+                throw new NullPointerException("disposition == null");
+            }
+
+            try {
+                if (spec.getLocalItem() == null) {
+                    throw new NullPointerException(
+                            "spec.getLocalItem() == null");
+                }
+            } catch (NullPointerException ex) {
+                // Elucidate the exception.
+                throw new NullPointerException("spec == null");
+            }
+
+            this.address = address;
+            this.disposition = disposition;
+            this.spec = spec;
+            this.type = CstType.intern(spec.getType());
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            return Integer.toHexString(address) + " " + disposition + " " +
+                spec;
+        }
+
+        /** {@inheritDoc} */
+        public boolean equals(Object other) {
+            if (!(other instanceof Entry)) {
+                return false;
+            }
+
+            return (compareTo((Entry) other) == 0);
+        }
+
+        /**
+         * Compares by (in priority order) address, end then start
+         * disposition (variants of end are all consistered
+         * equivalent), and spec.
+         *
+         * @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) {
+                return -1;
+            } else if (address > other.address) {
+                return 1;
+            }
+
+            boolean thisIsStart = isStart();
+            boolean otherIsStart = other.isStart();
+
+            if (thisIsStart != otherIsStart) {
+                return thisIsStart ? 1 : -1;
+            }
+
+            return spec.compareTo(other.spec);
+        }
+
+        /**
+         * Gets the address.
+         *
+         * @return {@code >= 0;} the address
+         */
+        public int getAddress() {
+            return address;
+        }
+
+        /**
+         * Gets the disposition.
+         *
+         * @return {@code non-null;} the disposition
+         */
+        public Disposition getDisposition() {
+            return disposition;
+        }
+
+        /**
+         * 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() {
+            return disposition == Disposition.START;
+        }
+
+        /**
+         * Gets the variable name.
+         *
+         * @return {@code null-ok;} the variable name
+         */
+        public CstString getName() {
+            return spec.getLocalItem().getName();
+        }
+
+        /**
+         * Gets the variable signature.
+         *
+         * @return {@code null-ok;} the variable signature
+         */
+        public CstString getSignature() {
+            return spec.getLocalItem().getSignature();
+        }
+
+        /**
+         * Gets the variable's type.
+         *
+         * @return {@code non-null;} the type
+         */
+        public CstType getType() {
+            return type;
+        }
+
+        /**
+         * Gets the number of the register holding the variable.
+         *
+         * @return {@code >= 0;} the number of the register holding
+         * the variable
+         */
+        public int getRegister() {
+            return spec.getReg();
+        }
+
+        /**
+         * Gets the RegisterSpec of the register holding the variable.
+         *
+         * @return {@code non-null;} RegisterSpec of the holding register.
+         */
+        public RegisterSpec getRegisterSpec() {
+            return spec;
+        }
+
+        /**
+         * Returns whether or not this instance matches the given spec.
+         *
+         * @param otherSpec {@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);
+        }
+
+        /**
+         * Returns whether or not this instance matches the spec in
+         * the given instance.
+         *
+         * @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);
+        }
+
+        /**
+         * Returns an instance just like this one but with the disposition
+         * 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 {@code non-null;} instructions to convert
+     * @return {@code non-null;} the constructed list
+     */
+    public static LocalList make(DalvInsnList insns) {
+        int sz = insns.size();
+
+        /*
+         * Go through the insn list, looking for all the local
+         * variable pseudoinstructions, splitting out LocalSnapshots
+         * 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).
+         *
+         * 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
+         * info explicitly into the rop layer rather than only trying
+         * to infer it. So, given that expectation, this code is
+         * written to deal with them.
+         */
+
+        MakeState state = new MakeState(sz);
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = insns.get(i);
+
+            if (insn instanceof LocalSnapshot) {
+                RegisterSpecSet snapshot =
+                    ((LocalSnapshot) insn).getLocals();
+                state.snapshot(insn.getAddress(), snapshot);
+            } else if (insn instanceof LocalStart) {
+                RegisterSpec local = ((LocalStart) insn).getLocal();
+                state.startLocal(insn.getAddress(), local);
+            } else if (insn instanceof LocalEnd) {
+                RegisterSpec local = ((LocalEnd) insn).getLocal();
+                state.endLocal(insn.getAddress(), local);
+            }
+        }
+
+        LocalList result = state.finish();
+
+        if (DEBUG) {
+            debugVerify(result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Debugging helper that verifies the constraint that a list doesn't
+     * contain any redundant local starts and that local ends that are
+     * due to replacements are properly annotated.
+     */
+    private static void debugVerify(LocalList locals) {
+        try {
+            debugVerify0(locals);
+        } catch (RuntimeException ex) {
+            int sz = locals.size();
+            for (int i = 0; i < sz; i++) {
+                System.err.println(locals.get(i));
+            }
+            throw ex;
+        }
+
+    }
+
+    /**
+     * Helper for {@link #debugVerify} which does most of the work.
+     */
+    private static void debugVerify0(LocalList locals) {
+        int sz = locals.size();
+        Entry[] active = new Entry[65536];
+
+        for (int i = 0; i < sz; i++) {
+            Entry e = locals.get(i);
+            int reg = e.getRegister();
+
+            if (e.isStart()) {
+                Entry already = active[reg];
+
+                if ((already != null) && e.matches(already)) {
+                    throw new RuntimeException("redundant start at " +
+                            Integer.toHexString(e.getAddress()) + ": got " +
+                            e + "; had " + already);
+                }
+
+                active[reg] = e;
+            } else {
+                if (active[reg] == null) {
+                    throw new RuntimeException("redundant end at " +
+                            Integer.toHexString(e.getAddress()));
+                }
+
+                int addr = e.getAddress();
+                boolean foundStart = false;
+
+                for (int j = i + 1; j < sz; j++) {
+                    Entry test = locals.get(j);
+                    if (test.getAddress() != addr) {
+                        break;
+                    }
+                    if (test.getRegisterSpec().getReg() == reg) {
+                        if (test.isStart()) {
+                            if (e.getDisposition()
+                                    != Disposition.END_REPLACED) {
+                                throw new RuntimeException(
+                                        "improperly marked end at " +
+                                        Integer.toHexString(addr));
+                            }
+                            foundStart = true;
+                        } else {
+                            throw new RuntimeException(
+                                    "redundant end at " +
+                                    Integer.toHexString(addr));
+                        }
+                    }
+                }
+
+                if (!foundStart &&
+                        (e.getDisposition() == Disposition.END_REPLACED)) {
+                    throw new RuntimeException(
+                            "improper end replacement claim at " +
+                            Integer.toHexString(addr));
+                }
+
+                active[reg] = null;
+            }
+        }
+    }
+
+    /**
+     * Intermediate state when constructing a local list.
+     */
+    public static class MakeState {
+        /** {@code non-null;} result being collected */
+        private final ArrayList<Entry> result;
+
+        /**
+         * {@code >= 0;} running count of nulled result entries, to help with
+         * sizing the final list
+         */
+        private int nullResultCount;
+
+        /** {@code null-ok;} current register mappings */
+        private RegisterSpecSet regs;
+
+        /** {@code null-ok;} result indices where local ends are stored */
+        private int[] endIndices;
+
+        /** {@code >= 0;} last address seen */
+        private int lastAddress;
+
+        /**
+         * Constructs an instance.
+         */
+        public MakeState(int initialSize) {
+            result = new ArrayList<Entry>(initialSize);
+            nullResultCount = 0;
+            regs = null;
+            endIndices = null;
+            lastAddress = 0;
+        }
+
+        /**
+         * Checks the address and other vitals as a prerequisite to
+         * further processing.
+         *
+         * @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;
+            }
+
+            if (address < lastAddress) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            if (first || (reg >= endIndices.length)) {
+                /*
+                 * This is the first allocation of the state set and
+                 * index array, or we need to grow. (The latter doesn't
+                 * happen much; in fact, we have only ever observed
+                 * it happening in test cases, never in "real" code.)
+                 */
+                int newSz = reg + 1;
+                RegisterSpecSet newRegs = new RegisterSpecSet(newSz);
+                int[] newEnds = new int[newSz];
+                Arrays.fill(newEnds, -1);
+
+                if (!first) {
+                    newRegs.putAll(regs);
+                    System.arraycopy(endIndices, 0, newEnds, 0,
+                            endIndices.length);
+                }
+
+                regs = newRegs;
+                endIndices = newEnds;
+            }
+        }
+
+        /**
+         * 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 {@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);
+
+            for (int i = 0; i < sz; i++) {
+                RegisterSpec oldSpec = regs.get(i);
+                RegisterSpec newSpec = filterSpec(specs.get(i));
+
+                if (oldSpec == null) {
+                    if (newSpec != null) {
+                        startLocal(address, newSpec);
+                    }
+                } else if (newSpec == null) {
+                    endLocal(address, oldSpec);
+                } else if (! newSpec.equalsUsingSimpleType(oldSpec)) {
+                    endLocal(address, oldSpec);
+                    startLocal(address, newSpec);
+                }
+            }
+
+            if (DEBUG) {
+                System.err.printf("%04x snapshot done\n", address);
+            }
+        }
+
+        /**
+         * Starts a local at the given address.
+         *
+         * @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);
+            aboutToProcess(address, regNum);
+
+            RegisterSpec existingLocal = regs.get(regNum);
+
+            if (startedLocal.equalsUsingSimpleType(existingLocal)) {
+                // Silently ignore a redundant start.
+                return;
+            }
+
+            RegisterSpec movedLocal = regs.findMatchingLocal(startedLocal);
+            if (movedLocal != null) {
+                /*
+                 * The same variable was moved from one register to another.
+                 * So add an end for its old location.
+                 */
+                addOrUpdateEnd(address, Disposition.END_MOVED, movedLocal);
+            }
+
+            int endAt = endIndices[regNum];
+
+            if (existingLocal != null) {
+                /*
+                 * There is an existing (but non-matching) local.
+                 * Add an explicit end for it.
+                 */
+                add(address, Disposition.END_REPLACED, existingLocal);
+            } else if (endAt >= 0) {
+                /*
+                 * Look for an end local for the same register at the
+                 * same address. If found, then update it or delete
+                 * it, depending on whether or not it represents the
+                 * same variable as the one being started.
+                 */
+                Entry endEntry = result.get(endAt);
+                if (endEntry.getAddress() == address) {
+                    if (endEntry.matches(startedLocal)) {
+                        /*
+                         * There was already an end local for the same
+                         * variable at the same address. This turns
+                         * out to be superfluous, as we are starting
+                         * up the exact same local. This situation can
+                         * happen when a single local variable got
+                         * somehow "split up" during intermediate
+                         * processing. In any case, rather than represent
+                         * the end-then-start, just remove the old end.
+                         */
+                        result.set(endAt, null);
+                        nullResultCount++;
+                        regs.put(startedLocal);
+                        endIndices[regNum] = -1;
+                        return;
+                    } else {
+                        /*
+                         * There was a different variable ended at the
+                         * same address. Update it to indicate that
+                         * it was ended due to a replacement (rather than
+                         * ending for no particular reason).
+                         */
+                        endEntry = endEntry.withDisposition(
+                                Disposition.END_REPLACED);
+                        result.set(endAt, endEntry);
+                    }
+                }
+            }
+
+            /*
+             * 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.
+             */
+
+            /*
+             * If the local just below (in the register set at reg-1)
+             * is of category-2, then it is ended by this new start.
+             */
+            if (regNum > 0) {
+                RegisterSpec justBelow = regs.get(regNum - 1);
+                if ((justBelow != null) && justBelow.isCategory2()) {
+                    addOrUpdateEnd(address,
+                            Disposition.END_CLOBBERED_BY_NEXT,
+                            justBelow);
+                }
+            }
+
+            /*
+             * Similarly, if this local is category-2, then the local
+             * just above (if any) is ended by the start now being
+             * emitted.
+             */
+            if (startedLocal.isCategory2()) {
+                RegisterSpec justAbove = regs.get(regNum + 1);
+                if (justAbove != null) {
+                    addOrUpdateEnd(address,
+                            Disposition.END_CLOBBERED_BY_PREV,
+                            justAbove);
+                }
+            }
+
+            /*
+             * TODO: Add an end for the same local in a different reg,
+             * 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 {@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,
+                Disposition disposition) {
+            if (DEBUG) {
+                System.err.printf("%04x end %s\n", address, endedLocal);
+            }
+
+            int regNum = endedLocal.getReg();
+
+            endedLocal = filterSpec(endedLocal);
+            aboutToProcess(address, regNum);
+
+            int endAt = endIndices[regNum];
+
+            if (endAt >= 0) {
+                /*
+                 * The local in the given register is already ended.
+                 * Silently return without adding anything to the result.
+                 */
+                return;
+            }
+
+            // Check for start and end at the same address.
+            if (checkForEmptyRange(address, endedLocal)) {
+                return;
+            }
+
+            add(address, disposition, endedLocal);
+        }
+
+        /**
+         * Helper for {@link #endLocal}, which handles the cases where
+         * and end local is issued at the same address as a start local
+         * for the same register. If this case is found, then this
+         * method will remove the start (as the local was never actually
+         * active), update the {@link #endIndices} to be accurate, and
+         * if needed update the newly-active end to reflect an altered
+         * disposition.
+         *
+         * @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
+         */
+        private boolean checkForEmptyRange(int address,
+                RegisterSpec endedLocal) {
+            int at = result.size() - 1;
+            Entry entry;
+
+            // Look for a previous entry at the same address.
+            for (/*at*/; at >= 0; at--) {
+                entry = result.get(at);
+
+                if (entry == null) {
+                    continue;
+                }
+
+                if (entry.getAddress() != address) {
+                    // We didn't find any match at the same address.
+                    return false;
+                }
+
+                if (entry.matches(endedLocal)) {
+                    break;
+                }
+            }
+
+            /*
+             * 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++;
+
+            int regNum = endedLocal.getReg();
+            boolean found = false;
+            entry = null;
+
+            // Now look back further to update where the register ended.
+            for (at--; at >= 0; at--) {
+                entry = result.get(at);
+
+                if (entry == null) {
+                    continue;
+                }
+
+                if (entry.getRegisterSpec().getReg() == regNum) {
+                    found = true;
+                    break;
+                }
+            }
+
+            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
+                     * disposition.
+                     */
+                    result.set(at,
+                            entry.withDisposition(Disposition.END_SIMPLY));
+                }
+            }
+
+            return true;
+        }
+
+        /**
+         * Converts a given spec into the form acceptable for use in a
+         * local list. This, in particular, transforms the "known
+         * 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 {@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) {
+            if ((orig != null) && (orig.getType() == Type.KNOWN_NULL)) {
+                return orig.withType(Type.OBJECT);
+            }
+
+            return orig;
+        }
+
+        /**
+         * Adds an entry to the result, updating the adjunct tables
+         * accordingly.
+         *
+         * @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) {
+            int regNum = spec.getReg();
+
+            result.add(new Entry(address, disposition, spec));
+
+            if (disposition == Disposition.START) {
+                regs.put(spec);
+                endIndices[regNum] = -1;
+            } else {
+                regs.remove(spec);
+                endIndices[regNum] = result.size() - 1;
+            }
+        }
+
+        /**
+         * 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) {
+            if (disposition == Disposition.START) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            int regNum = spec.getReg();
+            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); // TODO: Is this line superfluous?
+                    return;
+                }
+            }
+
+            endLocal(address, spec, disposition);
+        }
+
+        /**
+         * Finishes processing altogether and gets the result.
+         *
+         * @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;
+            }
+
+            /*
+             * Collect an array of only the non-null entries, and then
+             * sort it to get a consistent order for everything: Local
+             * ends and starts for a given address could come in any
+             * order, but we want ends before starts as well as
+             * registers in order (within ends or starts).
+             */
+
+            Entry[] resultArr = new Entry[finalSz];
+
+            if (resultSz == finalSz) {
+                result.toArray(resultArr);
+            } else {
+                int at = 0;
+                for (Entry e : result) {
+                    if (e != null) {
+                        resultArr[at++] = e;
+                    }
+                }
+            }
+
+            Arrays.sort(resultArr);
+
+            LocalList resultList = new LocalList(finalSz);
+
+            for (int i = 0; i < finalSz; i++) {
+                resultList.set(i, resultArr[i]);
+            }
+
+            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
new file mode 100644
index 0000000..baeab4c
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/LocalSnapshot.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.RegisterSpecSet;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to hold a snapshot of the
+ * state of local variable name mappings that exists immediately after
+ * the instance in an instruction array.
+ */
+public final class LocalSnapshot extends ZeroSizeInsn {
+    /** {@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}).
+     *
+     * @param position {@code non-null;} source position
+     * @param locals {@code non-null;} associated local variable state
+     */
+    public LocalSnapshot(SourcePosition position, RegisterSpecSet locals) {
+        super(position);
+
+        if (locals == null) {
+            throw new NullPointerException("locals == null");
+        }
+
+        this.locals = locals;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return new LocalSnapshot(getPosition(), locals.withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new LocalSnapshot(getPosition(), locals);
+    }
+
+    /**
+     * Gets the local state associated with this instance.
+     *
+     * @return {@code non-null;} the state
+     */
+    public RegisterSpecSet getLocals() {
+        return locals;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return locals.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        int sz = locals.size();
+        int max = locals.getMaxSize();
+        StringBuffer sb = new StringBuffer(100 + sz * 40);
+
+        sb.append("local-snapshot");
+
+        for (int i = 0; i < max; i++) {
+            RegisterSpec spec = locals.get(i);
+            if (spec != null) {
+                sb.append("\n  ");
+                sb.append(LocalStart.localString(spec));
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/LocalStart.java b/dx/src/com/android/dx/dex/code/LocalStart.java
new file mode 100644
index 0000000..9a17c5b
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/LocalStart.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction which is used to introduce a new local variable. That
+ * is, an instance of this class in an instruction stream indicates that
+ * starting with the subsequent instruction, the indicated variable
+ * is bound.
+ */
+public final class LocalStart extends ZeroSizeInsn {
+    /**
+     * {@code non-null;} register spec representing the local variable introduced
+     * by this instance
+     */
+    private final RegisterSpec local;
+
+    /**
+     * Returns the local variable listing string for a single register spec.
+     *
+     * @param spec {@code non-null;} the spec to convert
+     * @return {@code non-null;} the string form
+     */
+    public static String localString(RegisterSpec spec) {
+        return spec.regString() + ' ' + spec.getLocalItem().toString() + ": " +
+            spec.getTypeBearer().toHuman();
+    }
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param local {@code non-null;} register spec representing the local
+     * variable introduced by this instance
+     */
+    public LocalStart(SourcePosition position, RegisterSpec local) {
+        super(position);
+
+        if (local == null) {
+            throw new NullPointerException("local == null");
+        }
+
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return new LocalStart(getPosition(), local.withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new LocalStart(getPosition(), local);
+    }
+
+    /**
+     * Gets the register spec representing the local variable introduced
+     * by this instance.
+     *
+     * @return {@code non-null;} the register spec
+     */
+    public RegisterSpec getLocal() {
+        return local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return local.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        return "local-start " + localString(local);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/OddSpacer.java b/dx/src/com/android/dx/dex/code/OddSpacer.java
new file mode 100644
index 0000000..f44f9cc
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/OddSpacer.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.io.Opcodes;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * 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.
+ */
+public final class OddSpacer extends VariableSizeInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     */
+    public OddSpacer(SourcePosition position) {
+        super(position, RegisterSpecList.EMPTY);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return (getAddress() & 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        if (codeSize() != 0) {
+            out.writeShort(InsnFormat.codeUnit(Opcodes.NOP, 0));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new OddSpacer(getPosition());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        if (codeSize() == 0) {
+            return null;
+        }
+
+        return "nop // spacer";
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/OutputCollector.java b/dx/src/com/android/dx/dex/code/OutputCollector.java
new file mode 100644
index 0000000..a5e54a8
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/OutputCollector.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.dex.DexOptions;
+
+import java.util.ArrayList;
+
+/**
+ * Destination for {@link DalvInsn} instances being output. This class
+ * receives and collects instructions in two pieces &mdash; a primary
+ * list and a suffix (generally consisting of adjunct data referred to
+ * by the primary list, such as switch case tables) &mdash; which it
+ * merges and emits back out in the form of a {@link DalvInsnList}
+ * instance.
+ */
+public final class OutputCollector {
+    /**
+     * {@code non-null;} the associated finisher (which holds the instruction
+     * list in-progress)
+     */
+    private final OutputFinisher finisher;
+
+    /**
+     * {@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;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param dexOptions {@code non-null;} options for dex output
+     * @param initialCapacity {@code >= 0;} initial capacity of the output list
+     * @param suffixInitialCapacity {@code >= 0;} initial capacity of the output
+     * suffix
+     * @param regCount {@code >= 0;} register count for the method
+     */
+    public OutputCollector(DexOptions dexOptions, int initialCapacity, int suffixInitialCapacity,
+            int regCount) {
+        this.finisher = new OutputFinisher(dexOptions, initialCapacity, regCount);
+        this.suffix = new ArrayList<DalvInsn>(suffixInitialCapacity);
+    }
+
+    /**
+     * Adds an instruction to the output.
+     *
+     * @param insn {@code non-null;} the instruction to add
+     */
+    public void add(DalvInsn insn) {
+        finisher.add(insn);
+    }
+
+    /**
+     * Reverses a branch which is buried a given number of instructions
+     * backward in the output. It is illegal to call this unless the
+     * indicated instruction really is a reversible branch.
+     *
+     * @param which how many instructions back to find the branch;
+     * {@code 0} is the most recently added instruction,
+     * {@code 1} is the instruction before that, etc.
+     * @param newTarget {@code non-null;} the new target for the reversed branch
+     */
+    public void reverseBranch(int which, CodeAddress newTarget) {
+        finisher.reverseBranch(which, newTarget);
+    }
+
+    /**
+     * Adds an instruction to the output suffix.
+     *
+     * @param insn {@code non-null;} the instruction to add
+     */
+    public void addSuffix(DalvInsn insn) {
+        suffix.add(insn);
+    }
+
+    /**
+     * Gets the results of all the calls on this instance, in the form of
+     * an {@link OutputFinisher}.
+     *
+     * @return {@code non-null;} the output finisher
+     * @throws UnsupportedOperationException if this method has
+     * already been called
+     */
+    public OutputFinisher getFinisher() {
+        if (suffix == null) {
+            throw new UnsupportedOperationException("already processed");
+        }
+
+        appendSuffixToOutput();
+        return finisher;
+    }
+
+    /**
+     * Helper for {@link #getFinisher}, which appends the suffix to
+     * the primary output.
+     */
+    private void appendSuffixToOutput() {
+        int size = suffix.size();
+
+        for (int i = 0; i < size; i++) {
+            finisher.add(suffix.get(i));
+        }
+
+        suffix = null;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java
new file mode 100644
index 0000000..19b5634
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/OutputFinisher.java
@@ -0,0 +1,751 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.dex.DexOptions;
+import com.android.dx.io.Opcodes;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.RegisterSpecSet;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMemberRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+
+import com.android.dx.util.DexException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashSet;
+
+/**
+ * Processor for instruction lists, which takes a "first cut" of
+ * instruction selection as a basis and produces a "final cut" in the
+ * form of a {@link DalvInsnList} instance.
+ */
+public final class OutputFinisher {
+    /** {@code non-null;} options for dex output */
+    private final DexOptions dexOptions;
+
+    /**
+     * {@code >= 0;} register count for the method, not including any extra
+     * "reserved" registers needed to translate "difficult" instructions
+     */
+    private final int unreservedRegCount;
+
+    /** {@code non-null;} the list of instructions, per se */
+    private ArrayList<DalvInsn> insns;
+
+    /** whether any instruction has position info */
+    private boolean hasAnyPositionInfo;
+
+    /** whether any instruction has local variable info */
+    private boolean hasAnyLocalInfo;
+
+    /**
+     * {@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}
+     */
+    private int reservedCount;
+
+    /**
+     * Constructs an instance. It initially contains no instructions.
+     *
+     * @param dexOptions {@code non-null;} options for dex output
+     * @param regCount {@code >= 0;} register count for the method
+     * @param initialCapacity {@code >= 0;} initial capacity of the
+     * instructions list
+     */
+    public OutputFinisher(DexOptions dexOptions, int initialCapacity, int regCount) {
+        this.dexOptions = dexOptions;
+        this.unreservedRegCount = regCount;
+        this.insns = new ArrayList<DalvInsn>(initialCapacity);
+        this.reservedCount = -1;
+        this.hasAnyPositionInfo = false;
+        this.hasAnyLocalInfo = false;
+    }
+
+    /**
+     * Returns whether any of the instructions added to this instance
+     * come with position info.
+     *
+     * @return whether any of the instructions added to this instance
+     * come with position info
+     */
+    public boolean hasAnyPositionInfo() {
+        return hasAnyPositionInfo;
+    }
+
+    /**
+     * Returns whether this instance has any local variable information.
+     *
+     * @return whether this instance has any local variable information
+     */
+    public boolean hasAnyLocalInfo() {
+        return hasAnyLocalInfo;
+    }
+
+    /**
+     * Helper for {@link #add} which scrutinizes a single
+     * instruction for local variable information.
+     *
+     * @param insn {@code non-null;} instruction to scrutinize
+     * @return {@code true} iff the instruction refers to any
+     * named locals
+     */
+    private static boolean hasLocalInfo(DalvInsn insn) {
+        if (insn instanceof LocalSnapshot) {
+            RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
+            int size = specs.size();
+            for (int i = 0; i < size; i++) {
+                if (hasLocalInfo(specs.get(i))) {
+                    return true;
+                }
+            }
+        } else if (insn instanceof LocalStart) {
+            RegisterSpec spec = ((LocalStart) insn).getLocal();
+            if (hasLocalInfo(spec)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
+     * register spec.
+     *
+     * @param spec {@code non-null;} spec to scrutinize
+     * @return {@code true} iff the spec refers to any
+     * named locals
+     */
+    private static boolean hasLocalInfo(RegisterSpec spec) {
+        return (spec != null)
+            && (spec.getLocalItem().getName() != null);
+    }
+
+    /**
+     * Returns the set of all constants referred to by instructions added
+     * to this instance.
+     *
+     * @return {@code non-null;} the set of constants
+     */
+    public HashSet<Constant> getAllConstants() {
+        HashSet<Constant> result = new HashSet<Constant>(20);
+
+        for (DalvInsn insn : insns) {
+            addConstants(result, insn);
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #getAllConstants} which adds all the info for
+     * a single instruction.
+     *
+     * @param result {@code non-null;} result set to add to
+     * @param insn {@code non-null;} instruction to scrutinize
+     */
+    private static void addConstants(HashSet<Constant> result,
+            DalvInsn insn) {
+        if (insn instanceof CstInsn) {
+            Constant cst = ((CstInsn) insn).getConstant();
+            result.add(cst);
+        } else if (insn instanceof LocalSnapshot) {
+            RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
+            int size = specs.size();
+            for (int i = 0; i < size; i++) {
+                addConstants(result, specs.get(i));
+            }
+        } else if (insn instanceof LocalStart) {
+            RegisterSpec spec = ((LocalStart) insn).getLocal();
+            addConstants(result, spec);
+        }
+    }
+
+    /**
+     * Helper for {@link #getAllConstants} which adds all the info for
+     * a single {@code RegisterSpec}.
+     *
+     * @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) {
+        if (spec == null) {
+            return;
+        }
+
+        LocalItem local = spec.getLocalItem();
+        CstString name = local.getName();
+        CstString signature = local.getSignature();
+        Type type = spec.getType();
+
+        if (type != Type.KNOWN_NULL) {
+            result.add(CstType.intern(type));
+        }
+
+        if (name != null) {
+            result.add(name);
+        }
+
+        if (signature != null) {
+            result.add(signature);
+        }
+    }
+
+    /**
+     * Adds an instruction to the output.
+     *
+     * @param insn {@code non-null;} the instruction to add
+     */
+    public void add(DalvInsn insn) {
+        insns.add(insn);
+        updateInfo(insn);
+    }
+
+    /**
+     * Inserts an instruction in the output at the given offset.
+     *
+     * @param at {@code >= 0;} what index to insert at
+     * @param insn {@code non-null;} the instruction to insert
+     */
+    public void insert(int at, DalvInsn insn) {
+        insns.add(at, insn);
+        updateInfo(insn);
+    }
+
+    /**
+     * Helper for {@link #add} and {@link #insert},
+     * which updates the position and local info flags.
+     *
+     * @param insn {@code non-null;} an instruction that was just introduced
+     */
+    private void updateInfo(DalvInsn insn) {
+        if (! hasAnyPositionInfo) {
+            SourcePosition pos = insn.getPosition();
+            if (pos.getLine() >= 0) {
+                hasAnyPositionInfo = true;
+            }
+        }
+
+        if (! hasAnyLocalInfo) {
+            if (hasLocalInfo(insn)) {
+                hasAnyLocalInfo = true;
+            }
+        }
+    }
+
+    /**
+     * Reverses a branch which is buried a given number of instructions
+     * backward in the output. It is illegal to call this unless the
+     * indicated instruction really is a reversible branch.
+     *
+     * @param which how many instructions back to find the branch;
+     * {@code 0} is the most recently added instruction,
+     * {@code 1} is the instruction before that, etc.
+     * @param newTarget {@code non-null;} the new target for the
+     * reversed branch
+     */
+    public void reverseBranch(int which, CodeAddress newTarget) {
+        int size = insns.size();
+        int index = size - which - 1;
+        TargetInsn targetInsn;
+
+        try {
+            targetInsn = (TargetInsn) insns.get(index);
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("too few instructions");
+        } catch (ClassCastException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("non-reversible instruction");
+        }
+
+        /*
+         * No need to call this.set(), since the format and other info
+         * are the same.
+         */
+        insns.set(index, targetInsn.withNewTargetAndReversed(newTarget));
+    }
+
+    /**
+     * Assigns indices in all instructions that need them, using the
+     * given callback to perform lookups. This should be called before
+     * calling {@link #finishProcessingAndGetList}.
+     *
+     * @param callback {@code non-null;} callback object
+     */
+    public void assignIndices(DalvCode.AssignIndicesCallback callback) {
+        for (DalvInsn insn : insns) {
+            if (insn instanceof CstInsn) {
+                assignIndices((CstInsn) insn, callback);
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #assignIndices} which does assignment for one
+     * instruction.
+     *
+     * @param insn {@code non-null;} the instruction
+     * @param callback {@code non-null;} the callback
+     */
+    private static void assignIndices(CstInsn insn,
+            DalvCode.AssignIndicesCallback callback) {
+        Constant cst = insn.getConstant();
+        int index = callback.getIndex(cst);
+
+        if (index >= 0) {
+            insn.setIndex(index);
+        }
+
+        if (cst instanceof CstMemberRef) {
+            CstMemberRef member = (CstMemberRef) cst;
+            CstType definer = member.getDefiningClass();
+            index = callback.getIndex(definer);
+            if (index >= 0) {
+                insn.setClassIndex(index);
+            }
+        }
+    }
+
+    /**
+     * Does final processing on this instance and gets the output as
+     * a {@link DalvInsnList}. Final processing consists of:
+     *
+     * <ul>
+     *   <li>optionally renumbering registers (to make room as needed for
+     *   expanded instructions)</li>
+     *   <li>picking a final opcode for each instruction</li>
+     *   <li>rewriting instructions, because of register number,
+     *   constant pool index, or branch target size issues</li>
+     *   <li>assigning final addresses</li>
+     * </ul>
+     *
+     * <p><b>Note:</b> This method may only be called once per instance
+     * of this class.</p>
+     *
+     * @return {@code non-null;} the output list
+     * @throws UnsupportedOperationException if this method has
+     * already been called
+     */
+    public DalvInsnList finishProcessingAndGetList() {
+        if (reservedCount >= 0) {
+            throw new UnsupportedOperationException("already processed");
+        }
+
+        Dop[] opcodes = makeOpcodesArray();
+        reserveRegisters(opcodes);
+        massageInstructions(opcodes);
+        assignAddressesAndFixBranches();
+
+        return DalvInsnList.makeImmutable(insns,
+                reservedCount + unreservedRegCount);
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which extracts
+     * the opcode out of each instruction into a separate array, to be
+     * further manipulated as things progress.
+     *
+     * @return {@code non-null;} the array of opcodes
+     */
+    private Dop[] makeOpcodesArray() {
+        int size = insns.size();
+        Dop[] result = new Dop[size];
+
+        for (int i = 0; i < size; i++) {
+            result[i] = insns.get(i).getOpcode();
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which figures
+     * out how many reserved registers are required and then reserving
+     * them. It also updates the given {@code opcodes} array so
+     * as to avoid extra work when constructing the massaged
+     * instruction list.
+     *
+     * @param opcodes {@code non-null;} array of per-instruction
+     * opcode selections
+     */
+    private void reserveRegisters(Dop[] opcodes) {
+        int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
+
+        /*
+         * Call calculateReservedCount() and then perform register
+         * reservation, repeatedly until no new reservations happen.
+         */
+        for (;;) {
+            int newReservedCount = calculateReservedCount(opcodes);
+            if (oldReservedCount >= newReservedCount) {
+                break;
+            }
+
+            int reservedDifference = newReservedCount - oldReservedCount;
+            int size = insns.size();
+
+            for (int i = 0; i < size; i++) {
+                /*
+                 * CodeAddress instance identity is used to link
+                 * TargetInsns to their targets, so it is
+                 * inappropriate to make replacements, and they don't
+                 * have registers in any case. Hence, the instanceof
+                 * test below.
+                 */
+                DalvInsn insn = insns.get(i);
+                if (!(insn instanceof CodeAddress)) {
+                    /*
+                     * No need to call this.set() since the format and
+                     * other info are the same.
+                     */
+                    insns.set(i, insn.withRegisterOffset(reservedDifference));
+                }
+            }
+
+            oldReservedCount = newReservedCount;
+        }
+
+        reservedCount = oldReservedCount;
+    }
+
+    /**
+     * 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 opcodes} list to help avoid extra work in future
+     * register reservation passes.
+     *
+     * @param opcodes {@code non-null;} array of per-instruction
+     * opcode selections
+     * @return {@code >= 0;} the count of reserved registers
+     */
+    private int calculateReservedCount(Dop[] opcodes) {
+        int size = insns.size();
+
+        /*
+         * Potential new value of reservedCount, which gets updated in the
+         * following loop. It starts out with the existing reservedCount
+         * and gets increased if it turns out that additional registers
+         * need to be reserved.
+         */
+        int newReservedCount = reservedCount;
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            Dop originalOpcode = opcodes[i];
+            Dop newOpcode = findOpcodeForInsn(insn, originalOpcode);
+
+            if (newOpcode == null) {
+                /*
+                 * The instruction will need to be expanded, so find the
+                 * expanded opcode and reserve registers for it.
+                 */
+                Dop expandedOp = findExpandedOpcodeForInsn(insn);
+                BitSet compatRegs = expandedOp.getFormat().compatibleRegs(insn);
+                int reserve = insn.getMinimumRegisterRequirement(compatRegs);
+                if (reserve > newReservedCount) {
+                    newReservedCount = reserve;
+                }
+            } else if (originalOpcode == newOpcode) {
+                continue;
+            }
+
+            opcodes[i] = newOpcode;
+        }
+
+        return newReservedCount;
+    }
+
+    /**
+     * Attempts to fit the given instruction into a specific opcode,
+     * returning the opcode whose 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
+     * opcode as a first "best guess" and then pessimizes from there
+     * if necessary.
+     *
+     * @param insn {@code non-null;} the instruction in question
+     * @param guess {@code null-ok;} the current guess as to the best
+     * opcode; {@code null} means that no simple opcode fits
+     * @return {@code null-ok;} a possibly-different opcode; either a
+     * {@code non-null} good fit or {@code null} to indicate that no
+     * simple opcode fits
+     */
+    private Dop findOpcodeForInsn(DalvInsn insn, Dop guess) {
+        /*
+         * Note: The initial guess might be null, meaning that an
+         * earlier call to this method already determined that there
+         * was no possible simple opcode fit.
+         */
+
+        while (guess != null) {
+            if (guess.getFormat().isCompatible(insn)) {
+                break;
+            }
+
+            guess = Dops.getNextOrNull(guess, dexOptions);
+        }
+
+        return guess;
+    }
+
+    /**
+     * Finds the proper opcode for the given instruction, ignoring
+     * register constraints.
+     *
+     * @param insn {@code non-null;} the instruction in question
+     * @return {@code non-null;} the opcode that fits
+     */
+    private Dop findExpandedOpcodeForInsn(DalvInsn insn) {
+        Dop result = findOpcodeForInsn(insn.getLowRegVersion(), insn.getOpcode());
+        if (result == null) {
+            throw new DexException("No expanded opcode for " + insn);
+        }
+        return result;
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which goes
+     * through each instruction in the output, making sure its opcode
+     * can accomodate its arguments. In cases where the opcode is
+     * unable to do so, this replaces the instruction with a larger
+     * instruction with identical semantics that <i>will</i> work.
+     *
+     * <p>This method may also reserve a number of low-numbered
+     * registers, renumbering the instructions' original registers, in
+     * order to have register space available in which to move
+     * very-high registers when expanding instructions into
+     * multi-instruction sequences. This expansion is done when no
+     * simple instruction format can be found for a given instruction that
+     * is able to accomodate that instruction's registers.</p>
+     *
+     * <p>This method ignores issues of branch target size, since
+     * final addresses aren't known at the point that this method is
+     * called.</p>
+     *
+     * @param opcodes {@code non-null;} array of per-instruction
+     * opcode selections
+     */
+    private void massageInstructions(Dop[] opcodes) {
+        if (reservedCount == 0) {
+            /*
+             * The easy common case: No registers were reserved, so we
+             * merely need to replace any instructions whose format
+             * (and hence whose opcode) changed during the reservation
+             * pass, but all instructions will stay at their original
+             * indices, and the instruction list doesn't grow.
+             */
+            int size = insns.size();
+
+            for (int i = 0; i < size; i++) {
+                DalvInsn insn = insns.get(i);
+                Dop originalOpcode = insn.getOpcode();
+                Dop currentOpcode = opcodes[i];
+
+                if (originalOpcode != currentOpcode) {
+                    insns.set(i, insn.withOpcode(currentOpcode));
+                }
+            }
+        } else {
+            /*
+             * The difficult uncommon case: Some instructions have to be
+             * expanded to deal with high registers.
+             */
+            insns = performExpansion(opcodes);
+        }
+    }
+
+    /**
+     * Helper for {@link #massageInstructions}, which constructs a
+     * replacement list, where each {link DalvInsn} instance that
+     * couldn't be represented simply (due to register representation
+     * problems) is expanded into a series of instances that together
+     * perform the proper function.
+     *
+     * @param opcodes {@code non-null;} array of per-instruction
+     * opcode selections
+     * @return {@code non-null;} the replacement list
+     */
+    private ArrayList<DalvInsn> performExpansion(Dop[] opcodes) {
+        int size = insns.size();
+        ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            Dop originalOpcode = insn.getOpcode();
+            Dop currentOpcode = opcodes[i];
+            DalvInsn prefix;
+            DalvInsn suffix;
+
+            if (currentOpcode != null) {
+                // No expansion is necessary.
+                prefix = null;
+                suffix = null;
+            } else {
+                // Expansion is required.
+                currentOpcode = findExpandedOpcodeForInsn(insn);
+                BitSet compatRegs =
+                    currentOpcode.getFormat().compatibleRegs(insn);
+                prefix = insn.expandedPrefix(compatRegs);
+                suffix = insn.expandedSuffix(compatRegs);
+
+                // Expand necessary registers to fit the new format
+                insn = insn.expandedVersion(compatRegs);
+            }
+
+            if (prefix != null) {
+                result.add(prefix);
+            }
+
+            if (currentOpcode != originalOpcode) {
+                insn = insn.withOpcode(currentOpcode);
+            }
+            result.add(insn);
+
+            if (suffix != null) {
+                result.add(suffix);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #finishProcessingAndGetList}, which assigns
+     * addresses to each instruction, possibly rewriting branches to
+     * fix ones that wouldn't otherwise be able to reach their
+     * targets.
+     */
+    private void assignAddressesAndFixBranches() {
+        for (;;) {
+            assignAddresses();
+            if (!fixBranches()) {
+                break;
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #assignAddressesAndFixBranches}, which
+     * assigns an address to each instruction, in order.
+     */
+    private void assignAddresses() {
+        int address = 0;
+        int size = insns.size();
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            insn.setAddress(address);
+            address += insn.codeSize();
+        }
+    }
+
+    /**
+     * 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} 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}
+     * to the original target.
+     *
+     * @return whether any branches had to be fixed
+     */
+    private boolean fixBranches() {
+        int size = insns.size();
+        boolean anyFixed = false;
+
+        for (int i = 0; i < size; i++) {
+            DalvInsn insn = insns.get(i);
+            if (!(insn instanceof TargetInsn)) {
+                // This loop only needs to inspect TargetInsns.
+                continue;
+            }
+
+            Dop opcode = insn.getOpcode();
+            TargetInsn target = (TargetInsn) insn;
+
+            if (opcode.getFormat().branchFits(target)) {
+                continue;
+            }
+
+            if (opcode.getFamily() == Opcodes.GOTO) {
+                // It is a goto; widen it if possible.
+                opcode = findOpcodeForInsn(insn, opcode);
+                if (opcode == null) {
+                    /*
+                     * The branch is already maximally large. This should
+                     * only be possible if a method somehow manages to have
+                     * more than 2^31 code units.
+                     */
+                    throw new UnsupportedOperationException("method too long");
+                }
+                insns.set(i, insn.withOpcode(opcode));
+            } else {
+                /*
+                 * It is a conditional: Reverse its sense, and arrange for
+                 * it to branch around an absolute goto to the original
+                 * branch target.
+                 *
+                 * Note: An invariant of the list being processed is
+                 * that every TargetInsn is followed by a CodeAddress.
+                 * Hence, it is always safe to get the next element
+                 * after a TargetInsn and cast it to CodeAddress, as
+                 * is happening a few lines down.
+                 *
+                 * Also note: Size gets incremented by one here, as we
+                 * have -- in the net -- added one additional element
+                 * to the list, so we increment i to match. The added
+                 * and changed elements will be inspected by a repeat
+                 * call to this method after this invocation returns.
+                 */
+                CodeAddress newTarget;
+                try {
+                    newTarget = (CodeAddress) insns.get(i + 1);
+                } catch (IndexOutOfBoundsException ex) {
+                    // The TargetInsn / CodeAddress invariant was violated.
+                    throw new IllegalStateException(
+                            "unpaired TargetInsn (dangling)");
+                } catch (ClassCastException ex) {
+                    // The TargetInsn / CodeAddress invariant was violated.
+                    throw new IllegalStateException("unpaired TargetInsn");
+                }
+                TargetInsn gotoInsn =
+                    new TargetInsn(Dops.GOTO, target.getPosition(),
+                            RegisterSpecList.EMPTY, target.getTarget());
+                insns.set(i, gotoInsn);
+                insns.add(i, target.withNewTargetAndReversed(newTarget));
+                size++;
+                i++;
+            }
+
+            anyFixed = true;
+        }
+
+        return anyFixed;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/PositionList.java b/dx/src/com/android/dx/dex/code/PositionList.java
new file mode 100644
index 0000000..1e07e46
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/PositionList.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * List of source position entries. This class includes a utility
+ * method to extract an instance out of a {@link DalvInsnList}.
+ */
+public final class PositionList extends FixedSizeList {
+    /** {@code non-null;} empty instance */
+    public static final PositionList EMPTY = new PositionList(0);
+
+    /**
+     * constant for {@link #make} to indicate that no actual position
+     * information should be returned
+     */
+    public static final int NONE = 1;
+
+    /**
+     * constant for {@link #make} to indicate that only line number
+     * transitions should be returned
+     */
+    public static final int LINES = 2;
+
+    /**
+     * constant for {@link #make} to indicate that only "important" position
+     * information should be returned. This includes block starts and
+     * instructions that might throw.
+     */
+    public static final int IMPORTANT = 3;
+
+    /**
+     * Extracts and returns the source position information out of an
+     * instruction list.
+     *
+     * @param insns {@code non-null;} instructions to convert
+     * @param howMuch how much information should be included; one of the
+     * static constants defined by this class
+     * @return {@code non-null;} the positions list
+     */
+    public static PositionList make(DalvInsnList insns, int howMuch) {
+        switch (howMuch) {
+            case NONE: {
+                return EMPTY;
+            }
+            case LINES:
+            case IMPORTANT: {
+                // Valid.
+                break;
+            }
+            default: {
+                throw new IllegalArgumentException("bogus howMuch");
+            }
+        }
+
+        SourcePosition noInfo = SourcePosition.NO_INFO;
+        SourcePosition cur = noInfo;
+        int sz = insns.size();
+        PositionList.Entry[] arr = new PositionList.Entry[sz];
+        boolean lastWasTarget = false;
+        int at = 0;
+
+        for (int i = 0; i < sz; i++) {
+            DalvInsn insn = insns.get(i);
+
+            if (insn instanceof CodeAddress) {
+                lastWasTarget = true;;
+                continue;
+            }
+
+            SourcePosition pos = insn.getPosition();
+
+            if (pos.equals(noInfo) || pos.sameLine(cur)) {
+                continue;
+            }
+
+            if ((howMuch == IMPORTANT) && !lastWasTarget) {
+                continue;
+            }
+
+            cur = pos;
+            arr[at] = new PositionList.Entry(insn.getAddress(), pos);
+            at++;
+
+            lastWasTarget = false;
+        }
+
+        PositionList result = new PositionList(at);
+        for (int i = 0; i < at; i++) {
+            result.set(i, arr[i]);
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size {@code >= 0;} the size of the list
+     */
+    public PositionList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Entry get(int n) {
+        return (Entry) get0(n);
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param entry {@code non-null;} the entry to set at {@code n}
+     */
+    public void set(int n, Entry entry) {
+        set0(n, entry);
+    }
+
+    /**
+     * Entry in a position list.
+     */
+    public static class Entry {
+        /** {@code >= 0;} address of this entry */
+        private final int address;
+
+        /** {@code non-null;} corresponding source position information */
+        private final SourcePosition position;
+
+        /**
+         * Constructs an instance.
+         *
+         * @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) {
+                throw new IllegalArgumentException("address < 0");
+            }
+
+            if (position == null) {
+                throw new NullPointerException("position == null");
+            }
+
+            this.address = address;
+            this.position = position;
+        }
+
+        /**
+         * Gets the address.
+         *
+         * @return {@code >= 0;} the address
+         */
+        public int getAddress() {
+            return address;
+        }
+
+        /**
+         * Gets the source 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
new file mode 100644
index 0000000..0330113
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.ThrowingCstInsn;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+
+import java.util.HashMap;
+
+/**
+ * Translator from rop-level {@link Insn} instances to corresponding
+ * {@link Dop} instances.
+ */
+public final class RopToDop {
+    /** {@code non-null;} map from all the common rops to dalvik opcodes */
+    private static final HashMap<Rop, Dop> MAP;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private RopToDop() {
+        // This space intentionally left blank.
+    }
+
+    /*
+     * The following comment lists each opcode that should be considered
+     * the "head" of an opcode chain, in terms of the process of fitting
+     * an instruction's arguments to an actual opcode. This list is
+     * automatically generated and may be of use in double-checking the
+     * manually-generated static initialization code for this class.
+     *
+     * TODO: Make opcode-gen produce useful code in this case instead
+     * of just a comment.
+     */
+
+    // BEGIN(first-opcodes); GENERATED AUTOMATICALLY BY opcode-gen
+    //     Opcodes.NOP
+    //     Opcodes.MOVE
+    //     Opcodes.MOVE_WIDE
+    //     Opcodes.MOVE_OBJECT
+    //     Opcodes.MOVE_RESULT
+    //     Opcodes.MOVE_RESULT_WIDE
+    //     Opcodes.MOVE_RESULT_OBJECT
+    //     Opcodes.MOVE_EXCEPTION
+    //     Opcodes.RETURN_VOID
+    //     Opcodes.RETURN
+    //     Opcodes.RETURN_WIDE
+    //     Opcodes.RETURN_OBJECT
+    //     Opcodes.CONST_4
+    //     Opcodes.CONST_WIDE_16
+    //     Opcodes.CONST_STRING
+    //     Opcodes.CONST_CLASS
+    //     Opcodes.MONITOR_ENTER
+    //     Opcodes.MONITOR_EXIT
+    //     Opcodes.CHECK_CAST
+    //     Opcodes.INSTANCE_OF
+    //     Opcodes.ARRAY_LENGTH
+    //     Opcodes.NEW_INSTANCE
+    //     Opcodes.NEW_ARRAY
+    //     Opcodes.FILLED_NEW_ARRAY
+    //     Opcodes.FILL_ARRAY_DATA
+    //     Opcodes.THROW
+    //     Opcodes.GOTO
+    //     Opcodes.PACKED_SWITCH
+    //     Opcodes.SPARSE_SWITCH
+    //     Opcodes.CMPL_FLOAT
+    //     Opcodes.CMPG_FLOAT
+    //     Opcodes.CMPL_DOUBLE
+    //     Opcodes.CMPG_DOUBLE
+    //     Opcodes.CMP_LONG
+    //     Opcodes.IF_EQ
+    //     Opcodes.IF_NE
+    //     Opcodes.IF_LT
+    //     Opcodes.IF_GE
+    //     Opcodes.IF_GT
+    //     Opcodes.IF_LE
+    //     Opcodes.IF_EQZ
+    //     Opcodes.IF_NEZ
+    //     Opcodes.IF_LTZ
+    //     Opcodes.IF_GEZ
+    //     Opcodes.IF_GTZ
+    //     Opcodes.IF_LEZ
+    //     Opcodes.AGET
+    //     Opcodes.AGET_WIDE
+    //     Opcodes.AGET_OBJECT
+    //     Opcodes.AGET_BOOLEAN
+    //     Opcodes.AGET_BYTE
+    //     Opcodes.AGET_CHAR
+    //     Opcodes.AGET_SHORT
+    //     Opcodes.APUT
+    //     Opcodes.APUT_WIDE
+    //     Opcodes.APUT_OBJECT
+    //     Opcodes.APUT_BOOLEAN
+    //     Opcodes.APUT_BYTE
+    //     Opcodes.APUT_CHAR
+    //     Opcodes.APUT_SHORT
+    //     Opcodes.IGET
+    //     Opcodes.IGET_WIDE
+    //     Opcodes.IGET_OBJECT
+    //     Opcodes.IGET_BOOLEAN
+    //     Opcodes.IGET_BYTE
+    //     Opcodes.IGET_CHAR
+    //     Opcodes.IGET_SHORT
+    //     Opcodes.IPUT
+    //     Opcodes.IPUT_WIDE
+    //     Opcodes.IPUT_OBJECT
+    //     Opcodes.IPUT_BOOLEAN
+    //     Opcodes.IPUT_BYTE
+    //     Opcodes.IPUT_CHAR
+    //     Opcodes.IPUT_SHORT
+    //     Opcodes.SGET
+    //     Opcodes.SGET_WIDE
+    //     Opcodes.SGET_OBJECT
+    //     Opcodes.SGET_BOOLEAN
+    //     Opcodes.SGET_BYTE
+    //     Opcodes.SGET_CHAR
+    //     Opcodes.SGET_SHORT
+    //     Opcodes.SPUT
+    //     Opcodes.SPUT_WIDE
+    //     Opcodes.SPUT_OBJECT
+    //     Opcodes.SPUT_BOOLEAN
+    //     Opcodes.SPUT_BYTE
+    //     Opcodes.SPUT_CHAR
+    //     Opcodes.SPUT_SHORT
+    //     Opcodes.INVOKE_VIRTUAL
+    //     Opcodes.INVOKE_SUPER
+    //     Opcodes.INVOKE_DIRECT
+    //     Opcodes.INVOKE_STATIC
+    //     Opcodes.INVOKE_INTERFACE
+    //     Opcodes.NEG_INT
+    //     Opcodes.NOT_INT
+    //     Opcodes.NEG_LONG
+    //     Opcodes.NOT_LONG
+    //     Opcodes.NEG_FLOAT
+    //     Opcodes.NEG_DOUBLE
+    //     Opcodes.INT_TO_LONG
+    //     Opcodes.INT_TO_FLOAT
+    //     Opcodes.INT_TO_DOUBLE
+    //     Opcodes.LONG_TO_INT
+    //     Opcodes.LONG_TO_FLOAT
+    //     Opcodes.LONG_TO_DOUBLE
+    //     Opcodes.FLOAT_TO_INT
+    //     Opcodes.FLOAT_TO_LONG
+    //     Opcodes.FLOAT_TO_DOUBLE
+    //     Opcodes.DOUBLE_TO_INT
+    //     Opcodes.DOUBLE_TO_LONG
+    //     Opcodes.DOUBLE_TO_FLOAT
+    //     Opcodes.INT_TO_BYTE
+    //     Opcodes.INT_TO_CHAR
+    //     Opcodes.INT_TO_SHORT
+    //     Opcodes.ADD_INT_2ADDR
+    //     Opcodes.SUB_INT_2ADDR
+    //     Opcodes.MUL_INT_2ADDR
+    //     Opcodes.DIV_INT_2ADDR
+    //     Opcodes.REM_INT_2ADDR
+    //     Opcodes.AND_INT_2ADDR
+    //     Opcodes.OR_INT_2ADDR
+    //     Opcodes.XOR_INT_2ADDR
+    //     Opcodes.SHL_INT_2ADDR
+    //     Opcodes.SHR_INT_2ADDR
+    //     Opcodes.USHR_INT_2ADDR
+    //     Opcodes.ADD_LONG_2ADDR
+    //     Opcodes.SUB_LONG_2ADDR
+    //     Opcodes.MUL_LONG_2ADDR
+    //     Opcodes.DIV_LONG_2ADDR
+    //     Opcodes.REM_LONG_2ADDR
+    //     Opcodes.AND_LONG_2ADDR
+    //     Opcodes.OR_LONG_2ADDR
+    //     Opcodes.XOR_LONG_2ADDR
+    //     Opcodes.SHL_LONG_2ADDR
+    //     Opcodes.SHR_LONG_2ADDR
+    //     Opcodes.USHR_LONG_2ADDR
+    //     Opcodes.ADD_FLOAT_2ADDR
+    //     Opcodes.SUB_FLOAT_2ADDR
+    //     Opcodes.MUL_FLOAT_2ADDR
+    //     Opcodes.DIV_FLOAT_2ADDR
+    //     Opcodes.REM_FLOAT_2ADDR
+    //     Opcodes.ADD_DOUBLE_2ADDR
+    //     Opcodes.SUB_DOUBLE_2ADDR
+    //     Opcodes.MUL_DOUBLE_2ADDR
+    //     Opcodes.DIV_DOUBLE_2ADDR
+    //     Opcodes.REM_DOUBLE_2ADDR
+    //     Opcodes.ADD_INT_LIT8
+    //     Opcodes.RSUB_INT_LIT8
+    //     Opcodes.MUL_INT_LIT8
+    //     Opcodes.DIV_INT_LIT8
+    //     Opcodes.REM_INT_LIT8
+    //     Opcodes.AND_INT_LIT8
+    //     Opcodes.OR_INT_LIT8
+    //     Opcodes.XOR_INT_LIT8
+    //     Opcodes.SHL_INT_LIT8
+    //     Opcodes.SHR_INT_LIT8
+    //     Opcodes.USHR_INT_LIT8
+    // END(first-opcodes)
+
+    static {
+        /*
+         * Note: The choices made here are to pick the optimistically
+         * smallest Dalvik opcode, and leave it to later processing to
+         * pessimize. See the automatically-generated comment above
+         * for reference.
+         */
+        MAP = new HashMap<Rop, Dop>(400);
+        MAP.put(Rops.NOP,               Dops.NOP);
+        MAP.put(Rops.MOVE_INT,          Dops.MOVE);
+        MAP.put(Rops.MOVE_LONG,         Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_FLOAT,        Dops.MOVE);
+        MAP.put(Rops.MOVE_DOUBLE,       Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_OBJECT,       Dops.MOVE_OBJECT);
+        MAP.put(Rops.MOVE_PARAM_INT,    Dops.MOVE);
+        MAP.put(Rops.MOVE_PARAM_LONG,   Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_PARAM_FLOAT,  Dops.MOVE);
+        MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
+        MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT);
+
+        /*
+         * Note: No entry for MOVE_EXCEPTION, since it varies by
+         * exception type. (That is, there is no unique instance to
+         * add to the map.)
+         */
+
+        MAP.put(Rops.CONST_INT,         Dops.CONST_4);
+        MAP.put(Rops.CONST_LONG,        Dops.CONST_WIDE_16);
+        MAP.put(Rops.CONST_FLOAT,       Dops.CONST_4);
+        MAP.put(Rops.CONST_DOUBLE,      Dops.CONST_WIDE_16);
+
+        /*
+         * Note: No entry for CONST_OBJECT, since it needs to turn
+         * into either CONST_STRING or CONST_CLASS.
+         */
+
+        /*
+         * TODO: I think the only case of this is for null, and
+         * const/4 should cover that.
+         */
+        MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
+
+        MAP.put(Rops.GOTO,                 Dops.GOTO);
+        MAP.put(Rops.IF_EQZ_INT,           Dops.IF_EQZ);
+        MAP.put(Rops.IF_NEZ_INT,           Dops.IF_NEZ);
+        MAP.put(Rops.IF_LTZ_INT,           Dops.IF_LTZ);
+        MAP.put(Rops.IF_GEZ_INT,           Dops.IF_GEZ);
+        MAP.put(Rops.IF_LEZ_INT,           Dops.IF_LEZ);
+        MAP.put(Rops.IF_GTZ_INT,           Dops.IF_GTZ);
+        MAP.put(Rops.IF_EQZ_OBJECT,        Dops.IF_EQZ);
+        MAP.put(Rops.IF_NEZ_OBJECT,        Dops.IF_NEZ);
+        MAP.put(Rops.IF_EQ_INT,            Dops.IF_EQ);
+        MAP.put(Rops.IF_NE_INT,            Dops.IF_NE);
+        MAP.put(Rops.IF_LT_INT,            Dops.IF_LT);
+        MAP.put(Rops.IF_GE_INT,            Dops.IF_GE);
+        MAP.put(Rops.IF_LE_INT,            Dops.IF_LE);
+        MAP.put(Rops.IF_GT_INT,            Dops.IF_GT);
+        MAP.put(Rops.IF_EQ_OBJECT,         Dops.IF_EQ);
+        MAP.put(Rops.IF_NE_OBJECT,         Dops.IF_NE);
+        MAP.put(Rops.SWITCH,               Dops.SPARSE_SWITCH);
+        MAP.put(Rops.ADD_INT,              Dops.ADD_INT_2ADDR);
+        MAP.put(Rops.ADD_LONG,             Dops.ADD_LONG_2ADDR);
+        MAP.put(Rops.ADD_FLOAT,            Dops.ADD_FLOAT_2ADDR);
+        MAP.put(Rops.ADD_DOUBLE,           Dops.ADD_DOUBLE_2ADDR);
+        MAP.put(Rops.SUB_INT,              Dops.SUB_INT_2ADDR);
+        MAP.put(Rops.SUB_LONG,             Dops.SUB_LONG_2ADDR);
+        MAP.put(Rops.SUB_FLOAT,            Dops.SUB_FLOAT_2ADDR);
+        MAP.put(Rops.SUB_DOUBLE,           Dops.SUB_DOUBLE_2ADDR);
+        MAP.put(Rops.MUL_INT,              Dops.MUL_INT_2ADDR);
+        MAP.put(Rops.MUL_LONG,             Dops.MUL_LONG_2ADDR);
+        MAP.put(Rops.MUL_FLOAT,            Dops.MUL_FLOAT_2ADDR);
+        MAP.put(Rops.MUL_DOUBLE,           Dops.MUL_DOUBLE_2ADDR);
+        MAP.put(Rops.DIV_INT,              Dops.DIV_INT_2ADDR);
+        MAP.put(Rops.DIV_LONG,             Dops.DIV_LONG_2ADDR);
+        MAP.put(Rops.DIV_FLOAT,            Dops.DIV_FLOAT_2ADDR);
+        MAP.put(Rops.DIV_DOUBLE,           Dops.DIV_DOUBLE_2ADDR);
+        MAP.put(Rops.REM_INT,              Dops.REM_INT_2ADDR);
+        MAP.put(Rops.REM_LONG,             Dops.REM_LONG_2ADDR);
+        MAP.put(Rops.REM_FLOAT,            Dops.REM_FLOAT_2ADDR);
+        MAP.put(Rops.REM_DOUBLE,           Dops.REM_DOUBLE_2ADDR);
+        MAP.put(Rops.NEG_INT,              Dops.NEG_INT);
+        MAP.put(Rops.NEG_LONG,             Dops.NEG_LONG);
+        MAP.put(Rops.NEG_FLOAT,            Dops.NEG_FLOAT);
+        MAP.put(Rops.NEG_DOUBLE,           Dops.NEG_DOUBLE);
+        MAP.put(Rops.AND_INT,              Dops.AND_INT_2ADDR);
+        MAP.put(Rops.AND_LONG,             Dops.AND_LONG_2ADDR);
+        MAP.put(Rops.OR_INT,               Dops.OR_INT_2ADDR);
+        MAP.put(Rops.OR_LONG,              Dops.OR_LONG_2ADDR);
+        MAP.put(Rops.XOR_INT,              Dops.XOR_INT_2ADDR);
+        MAP.put(Rops.XOR_LONG,             Dops.XOR_LONG_2ADDR);
+        MAP.put(Rops.SHL_INT,              Dops.SHL_INT_2ADDR);
+        MAP.put(Rops.SHL_LONG,             Dops.SHL_LONG_2ADDR);
+        MAP.put(Rops.SHR_INT,              Dops.SHR_INT_2ADDR);
+        MAP.put(Rops.SHR_LONG,             Dops.SHR_LONG_2ADDR);
+        MAP.put(Rops.USHR_INT,             Dops.USHR_INT_2ADDR);
+        MAP.put(Rops.USHR_LONG,            Dops.USHR_LONG_2ADDR);
+        MAP.put(Rops.NOT_INT,              Dops.NOT_INT);
+        MAP.put(Rops.NOT_LONG,             Dops.NOT_LONG);
+
+        MAP.put(Rops.ADD_CONST_INT,        Dops.ADD_INT_LIT8);
+        // Note: No dalvik ops for other types of add_const.
+
+        MAP.put(Rops.SUB_CONST_INT,        Dops.RSUB_INT_LIT8);
+        /*
+         * Note: No dalvik ops for any type of sub_const; instead
+         * there's a *reverse* sub (constant - reg) for ints only.
+         */
+
+        MAP.put(Rops.MUL_CONST_INT,        Dops.MUL_INT_LIT8);
+        // Note: No dalvik ops for other types of mul_const.
+
+        MAP.put(Rops.DIV_CONST_INT,        Dops.DIV_INT_LIT8);
+        // Note: No dalvik ops for other types of div_const.
+
+        MAP.put(Rops.REM_CONST_INT,        Dops.REM_INT_LIT8);
+        // Note: No dalvik ops for other types of rem_const.
+
+        MAP.put(Rops.AND_CONST_INT,        Dops.AND_INT_LIT8);
+        // Note: No dalvik op for and_const_long.
+
+        MAP.put(Rops.OR_CONST_INT,         Dops.OR_INT_LIT8);
+        // Note: No dalvik op for or_const_long.
+
+        MAP.put(Rops.XOR_CONST_INT,        Dops.XOR_INT_LIT8);
+        // Note: No dalvik op for xor_const_long.
+
+        MAP.put(Rops.SHL_CONST_INT,        Dops.SHL_INT_LIT8);
+        // Note: No dalvik op for shl_const_long.
+
+        MAP.put(Rops.SHR_CONST_INT,        Dops.SHR_INT_LIT8);
+        // Note: No dalvik op for shr_const_long.
+
+        MAP.put(Rops.USHR_CONST_INT,       Dops.USHR_INT_LIT8);
+        // Note: No dalvik op for shr_const_long.
+
+        MAP.put(Rops.CMPL_LONG,            Dops.CMP_LONG);
+        MAP.put(Rops.CMPL_FLOAT,           Dops.CMPL_FLOAT);
+        MAP.put(Rops.CMPL_DOUBLE,          Dops.CMPL_DOUBLE);
+        MAP.put(Rops.CMPG_FLOAT,           Dops.CMPG_FLOAT);
+        MAP.put(Rops.CMPG_DOUBLE,          Dops.CMPG_DOUBLE);
+        MAP.put(Rops.CONV_L2I,             Dops.LONG_TO_INT);
+        MAP.put(Rops.CONV_F2I,             Dops.FLOAT_TO_INT);
+        MAP.put(Rops.CONV_D2I,             Dops.DOUBLE_TO_INT);
+        MAP.put(Rops.CONV_I2L,             Dops.INT_TO_LONG);
+        MAP.put(Rops.CONV_F2L,             Dops.FLOAT_TO_LONG);
+        MAP.put(Rops.CONV_D2L,             Dops.DOUBLE_TO_LONG);
+        MAP.put(Rops.CONV_I2F,             Dops.INT_TO_FLOAT);
+        MAP.put(Rops.CONV_L2F,             Dops.LONG_TO_FLOAT);
+        MAP.put(Rops.CONV_D2F,             Dops.DOUBLE_TO_FLOAT);
+        MAP.put(Rops.CONV_I2D,             Dops.INT_TO_DOUBLE);
+        MAP.put(Rops.CONV_L2D,             Dops.LONG_TO_DOUBLE);
+        MAP.put(Rops.CONV_F2D,             Dops.FLOAT_TO_DOUBLE);
+        MAP.put(Rops.TO_BYTE,              Dops.INT_TO_BYTE);
+        MAP.put(Rops.TO_CHAR,              Dops.INT_TO_CHAR);
+        MAP.put(Rops.TO_SHORT,             Dops.INT_TO_SHORT);
+        MAP.put(Rops.RETURN_VOID,          Dops.RETURN_VOID);
+        MAP.put(Rops.RETURN_INT,           Dops.RETURN);
+        MAP.put(Rops.RETURN_LONG,          Dops.RETURN_WIDE);
+        MAP.put(Rops.RETURN_FLOAT,         Dops.RETURN);
+        MAP.put(Rops.RETURN_DOUBLE,        Dops.RETURN_WIDE);
+        MAP.put(Rops.RETURN_OBJECT,        Dops.RETURN_OBJECT);
+        MAP.put(Rops.ARRAY_LENGTH,         Dops.ARRAY_LENGTH);
+        MAP.put(Rops.THROW,                Dops.THROW);
+        MAP.put(Rops.MONITOR_ENTER,        Dops.MONITOR_ENTER);
+        MAP.put(Rops.MONITOR_EXIT,         Dops.MONITOR_EXIT);
+        MAP.put(Rops.AGET_INT,             Dops.AGET);
+        MAP.put(Rops.AGET_LONG,            Dops.AGET_WIDE);
+        MAP.put(Rops.AGET_FLOAT,           Dops.AGET);
+        MAP.put(Rops.AGET_DOUBLE,          Dops.AGET_WIDE);
+        MAP.put(Rops.AGET_OBJECT,          Dops.AGET_OBJECT);
+        MAP.put(Rops.AGET_BOOLEAN,         Dops.AGET_BOOLEAN);
+        MAP.put(Rops.AGET_BYTE,            Dops.AGET_BYTE);
+        MAP.put(Rops.AGET_CHAR,            Dops.AGET_CHAR);
+        MAP.put(Rops.AGET_SHORT,           Dops.AGET_SHORT);
+        MAP.put(Rops.APUT_INT,             Dops.APUT);
+        MAP.put(Rops.APUT_LONG,            Dops.APUT_WIDE);
+        MAP.put(Rops.APUT_FLOAT,           Dops.APUT);
+        MAP.put(Rops.APUT_DOUBLE,          Dops.APUT_WIDE);
+        MAP.put(Rops.APUT_OBJECT,          Dops.APUT_OBJECT);
+        MAP.put(Rops.APUT_BOOLEAN,         Dops.APUT_BOOLEAN);
+        MAP.put(Rops.APUT_BYTE,            Dops.APUT_BYTE);
+        MAP.put(Rops.APUT_CHAR,            Dops.APUT_CHAR);
+        MAP.put(Rops.APUT_SHORT,           Dops.APUT_SHORT);
+        MAP.put(Rops.NEW_INSTANCE,         Dops.NEW_INSTANCE);
+        MAP.put(Rops.CHECK_CAST,           Dops.CHECK_CAST);
+        MAP.put(Rops.INSTANCE_OF,          Dops.INSTANCE_OF);
+
+        MAP.put(Rops.GET_FIELD_LONG,       Dops.IGET_WIDE);
+        MAP.put(Rops.GET_FIELD_FLOAT,      Dops.IGET);
+        MAP.put(Rops.GET_FIELD_DOUBLE,     Dops.IGET_WIDE);
+        MAP.put(Rops.GET_FIELD_OBJECT,     Dops.IGET_OBJECT);
+        /*
+         * Note: No map entries for get_field_* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        MAP.put(Rops.GET_STATIC_LONG,      Dops.SGET_WIDE);
+        MAP.put(Rops.GET_STATIC_FLOAT,     Dops.SGET);
+        MAP.put(Rops.GET_STATIC_DOUBLE,    Dops.SGET_WIDE);
+        MAP.put(Rops.GET_STATIC_OBJECT,    Dops.SGET_OBJECT);
+        /*
+         * Note: No map entries for get_static* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        MAP.put(Rops.PUT_FIELD_LONG,       Dops.IPUT_WIDE);
+        MAP.put(Rops.PUT_FIELD_FLOAT,      Dops.IPUT);
+        MAP.put(Rops.PUT_FIELD_DOUBLE,     Dops.IPUT_WIDE);
+        MAP.put(Rops.PUT_FIELD_OBJECT,     Dops.IPUT_OBJECT);
+        /*
+         * Note: No map entries for put_field_* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        MAP.put(Rops.PUT_STATIC_LONG,      Dops.SPUT_WIDE);
+        MAP.put(Rops.PUT_STATIC_FLOAT,     Dops.SPUT);
+        MAP.put(Rops.PUT_STATIC_DOUBLE,    Dops.SPUT_WIDE);
+        MAP.put(Rops.PUT_STATIC_OBJECT,    Dops.SPUT_OBJECT);
+        /*
+         * Note: No map entries for put_static* for non-long integral types,
+         * since they need to be handled specially (see dopFor() below).
+         */
+
+        /*
+         * Note: No map entries for invoke*, new_array, and
+         * filled_new_array, since they need to be handled specially
+         * (see dopFor() below).
+         */
+    }
+
+    /**
+     * Returns the dalvik opcode appropriate for the given register-based
+     * instruction.
+     *
+     * @param insn {@code non-null;} the original instruction
+     * @return the corresponding dalvik opcode; one of the constants in
+     * {@link Dops}
+     */
+    public static Dop dopFor(Insn insn) {
+        Rop rop = insn.getOpcode();
+
+        /*
+         * First, just try looking up the rop in the MAP of easy
+         * cases.
+         */
+        Dop result = MAP.get(rop);
+        if (result != null) {
+            return result;
+        }
+
+        /*
+         * There was no easy case for the rop, so look up the opcode, and
+         * do something special for each:
+         *
+         * The move_exception, new_array, filled_new_array, and
+         * invoke* opcodes won't be found in MAP, since they'll each
+         * have different source and/or result register types / lists.
+         *
+         * The get* and put* opcodes for (non-long) integral types
+         * aren't in the map, since the type signatures aren't
+         * sufficient to distinguish between the types (the salient
+         * source or result will always be just "int").
+         *
+         * And const instruction need to distinguish between strings and
+         * classes.
+         */
+
+        switch (rop.getOpcode()) {
+            case RegOps.MOVE_EXCEPTION:   return Dops.MOVE_EXCEPTION;
+            case RegOps.INVOKE_STATIC:    return Dops.INVOKE_STATIC;
+            case RegOps.INVOKE_VIRTUAL:   return Dops.INVOKE_VIRTUAL;
+            case RegOps.INVOKE_SUPER:     return Dops.INVOKE_SUPER;
+            case RegOps.INVOKE_DIRECT:    return Dops.INVOKE_DIRECT;
+            case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
+            case RegOps.NEW_ARRAY:        return Dops.NEW_ARRAY;
+            case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
+            case RegOps.FILL_ARRAY_DATA:  return Dops.FILL_ARRAY_DATA;
+            case RegOps.MOVE_RESULT: {
+                RegisterSpec resultReg = insn.getResult();
+
+                if (resultReg == null) {
+                    return Dops.NOP;
+                } else {
+                    switch (resultReg.getBasicType()) {
+                        case Type.BT_INT:
+                        case Type.BT_FLOAT:
+                        case Type.BT_BOOLEAN:
+                        case Type.BT_BYTE:
+                        case Type.BT_CHAR:
+                        case Type.BT_SHORT:
+                            return Dops.MOVE_RESULT;
+                        case Type.BT_LONG:
+                        case Type.BT_DOUBLE:
+                            return Dops.MOVE_RESULT_WIDE;
+                        case Type.BT_OBJECT:
+                            return Dops.MOVE_RESULT_OBJECT;
+                        default: {
+                            throw new RuntimeException("Unexpected basic type");
+                        }
+                    }
+                }
+            }
+
+            case RegOps.GET_FIELD: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.IGET_BYTE;
+                    case Type.BT_CHAR:    return Dops.IGET_CHAR;
+                    case Type.BT_SHORT:   return Dops.IGET_SHORT;
+                    case Type.BT_INT:     return Dops.IGET;
+                }
+                break;
+            }
+            case RegOps.PUT_FIELD: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.IPUT_BYTE;
+                    case Type.BT_CHAR:    return Dops.IPUT_CHAR;
+                    case Type.BT_SHORT:   return Dops.IPUT_SHORT;
+                    case Type.BT_INT:     return Dops.IPUT;
+                }
+                break;
+            }
+            case RegOps.GET_STATIC: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.SGET_BYTE;
+                    case Type.BT_CHAR:    return Dops.SGET_CHAR;
+                    case Type.BT_SHORT:   return Dops.SGET_SHORT;
+                    case Type.BT_INT:     return Dops.SGET;
+                }
+                break;
+            }
+            case RegOps.PUT_STATIC: {
+                CstFieldRef ref =
+                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
+                int basicType = ref.getBasicType();
+                switch (basicType) {
+                    case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN;
+                    case Type.BT_BYTE:    return Dops.SPUT_BYTE;
+                    case Type.BT_CHAR:    return Dops.SPUT_CHAR;
+                    case Type.BT_SHORT:   return Dops.SPUT_SHORT;
+                    case Type.BT_INT:     return Dops.SPUT;
+                }
+                break;
+            }
+            case RegOps.CONST: {
+                Constant cst = ((ThrowingCstInsn) insn).getConstant();
+                if (cst instanceof CstType) {
+                    return Dops.CONST_CLASS;
+                } else if (cst instanceof CstString) {
+                    return Dops.CONST_STRING;
+                }
+                break;
+            }
+        }
+
+        throw new RuntimeException("unknown rop: " + rop);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/RopTranslator.java b/dx/src/com/android/dx/dex/code/RopTranslator.java
new file mode 100644
index 0000000..3d24c4f
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/RopTranslator.java
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.dex.DexOptions;
+import com.android.dx.io.Opcodes;
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.FillArrayDataInsn;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.LocalVariableInfo;
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.RegisterSpecSet;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.code.SwitchInsn;
+import com.android.dx.rop.code.ThrowingCstInsn;
+import com.android.dx.rop.code.ThrowingInsn;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.util.Bits;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+
+/**
+ * Translator from {@link RopMethod} to {@link DalvCode}. The {@link
+ * #translate} method is the thing to call on this class.
+ */
+public final class RopTranslator {
+    /** {@code non-null;} options for dex output */
+    private final DexOptions dexOptions;
+
+    /** {@code non-null;} method to translate */
+    private final RopMethod method;
+
+    /**
+     * how much position info to preserve; one of the static
+     * constants in {@link PositionList}
+     */
+    private final int positionInfo;
+
+    /** {@code null-ok;} local variable info to use */
+    private final LocalVariableInfo locals;
+
+    /** {@code non-null;} container for all the address objects for the method */
+    private final BlockAddresses addresses;
+
+    /** {@code non-null;} list of output instructions in-progress */
+    private final OutputCollector output;
+
+    /** {@code non-null;} visitor to use during translation */
+    private final TranslationVisitor translationVisitor;
+
+    /** {@code >= 0;} register count for the method */
+    private final int regCount;
+
+    /** {@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 */
+    private final int paramSize;
+
+    /**
+     * true if the parameters to this method happen to be in proper order
+     * at the end of the frame (as the optimizer emits them)
+     */
+    private boolean paramsAreInOrder;
+
+    /**
+     * Translates a {@link RopMethod}. This may modify the given
+     * input.
+     *
+     * @param method {@code non-null;} the original method
+     * @param positionInfo how much position info to preserve; one of the
+     * static constants in {@link PositionList}
+     * @param locals {@code null-ok;} local variable information to use
+     * @param paramSize size, in register units, of all the parameters to
+     * this method
+     * @param dexOptions {@code non-null;} options for dex output
+     * @return {@code non-null;} the translated version
+     */
+    public static DalvCode translate(RopMethod method, int positionInfo,
+            LocalVariableInfo locals, int paramSize, DexOptions dexOptions) {
+        RopTranslator translator =
+            new RopTranslator(method, positionInfo, locals, paramSize, dexOptions);
+        return translator.translateAndGetResult();
+    }
+
+    /**
+     * Constructs an instance. This method is private. Use {@link #translate}.
+     *
+     * @param method {@code non-null;} the original method
+     * @param positionInfo how much position info to preserve; one of the
+     * static constants in {@link PositionList}
+     * @param locals {@code null-ok;} local variable information to use
+     * @param paramSize size, in register units, of all the parameters to
+     * this method
+     * @param dexOptions {@code non-null;} options for dex output
+     */
+    private RopTranslator(RopMethod method, int positionInfo, LocalVariableInfo locals,
+            int paramSize, DexOptions dexOptions) {
+        this.dexOptions = dexOptions;
+        this.method = method;
+        this.positionInfo = positionInfo;
+        this.locals = locals;
+        this.addresses = new BlockAddresses(method);
+        this.paramSize = paramSize;
+        this.order = null;
+        this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize);
+
+        BasicBlockList blocks = method.getBlocks();
+        int bsz = blocks.size();
+
+        /*
+         * Max possible instructions includes three code address
+         * objects per basic block (to the first and last instruction,
+         * and just past the end of the block), and the possibility of
+         * an extra goto at the end of each basic block.
+         */
+        int maxInsns = (bsz * 3) + blocks.getInstructionCount();
+
+        if (locals != null) {
+            /*
+             * If we're tracking locals, then there's could be another
+             * extra instruction per block (for the locals state at the
+             * start of the block) as well as one for each interblock
+             * local introduction.
+             */
+            maxInsns += bsz + locals.getAssignmentCount();
+        }
+
+        /*
+         * If params are not in order, we will need register space
+         * for them before this is all over...
+         */
+        this.regCount = blocks.getRegCount()
+                + (paramsAreInOrder ? 0 : this.paramSize);
+
+        this.output = new OutputCollector(dexOptions, maxInsns, bsz * 3, regCount);
+
+        if (locals != null) {
+            this.translationVisitor =
+                new LocalVariableAwareTranslationVisitor(output, locals);
+        } else {
+            this.translationVisitor = new TranslationVisitor(output);
+        }
+    }
+
+    /**
+     * Checks to see if the move-param instructions that occur in this
+     * method happen to slot the params in an order at the top of the
+     * stack frame that matches dalvik's calling conventions. This will
+     * alway result in "true" for methods that have run through the
+     * SSA optimizer.
+     *
+     * @param paramSize size, in register units, of all the parameters
+     * to this method
+     */
+    private static boolean calculateParamsAreInOrder(RopMethod method,
+            final int paramSize) {
+        final boolean[] paramsAreInOrder = { true };
+        final int initialRegCount = method.getBlocks().getRegCount();
+
+        /*
+         * We almost could just check the first block here, but the
+         * {@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() {
+            @Override
+            public void visitPlainCstInsn(PlainCstInsn insn) {
+                if (insn.getOpcode().getOpcode()== RegOps.MOVE_PARAM) {
+                    int param =
+                        ((CstInteger) insn.getConstant()).getValue();
+
+                    paramsAreInOrder[0] = paramsAreInOrder[0]
+                            && ((initialRegCount - paramSize + param)
+                                == insn.getResult().getReg());
+                }
+            }
+        });
+
+        return paramsAreInOrder[0];
+    }
+
+    /**
+     * Does the translation and returns the result.
+     *
+     * @return {@code non-null;} the result
+     */
+    private DalvCode translateAndGetResult() {
+        pickOrder();
+        outputInstructions();
+
+        StdCatchBuilder catches =
+            new StdCatchBuilder(method, order, addresses);
+
+        return new DalvCode(positionInfo, output.getFinisher(), catches);
+    }
+
+    /**
+     * Performs initial creation of output instructions based on the
+     * original blocks.
+     */
+    private void outputInstructions() {
+        BasicBlockList blocks = method.getBlocks();
+        int[] order = this.order;
+        int len = order.length;
+
+        // Process the blocks in output order.
+        for (int i = 0; i < len; i++) {
+            int nextI = i + 1;
+            int nextLabel = (nextI == order.length) ? -1 : order[nextI];
+            outputBlock(blocks.labelToBlock(order[i]), nextLabel);
+        }
+    }
+
+    /**
+     * Helper for {@link #outputInstructions}, which does the processing
+     * and output of one block.
+     *
+     * @param block {@code non-null;} the block to process and output
+     * @param nextLabel {@code >= -1;} the next block that will be processed, or
+     * {@code -1} if there is no next block
+     */
+    private void outputBlock(BasicBlock block, int nextLabel) {
+        // Append the code address for this block.
+        CodeAddress startAddress = addresses.getStart(block);
+        output.add(startAddress);
+
+        // Append the local variable state for the block.
+        if (locals != null) {
+            RegisterSpecSet starts = locals.getStarts(block);
+            output.add(new LocalSnapshot(startAddress.getPosition(),
+                                         starts));
+        }
+
+        /*
+         * Choose and append an output instruction for each original
+         * instruction.
+         */
+        translationVisitor.setBlock(block, addresses.getLast(block));
+        block.getInsns().forEach(translationVisitor);
+
+        // Insert the block end code address.
+        output.add(addresses.getEnd(block));
+
+        // Set up for end-of-block activities.
+
+        int succ = block.getPrimarySuccessor();
+        Insn lastInsn = block.getLastInsn();
+
+        /*
+         * Check for (and possibly correct for) a non-optimal choice of
+         * which block will get output next.
+         */
+
+        if ((succ >= 0) && (succ != nextLabel)) {
+            /*
+             * The block has a "primary successor" and that primary
+             * successor isn't the next block to be output.
+             */
+            Rop lastRop = lastInsn.getOpcode();
+            if ((lastRop.getBranchingness() == Rop.BRANCH_IF) &&
+                    (block.getSecondarySuccessor() == nextLabel)) {
+                /*
+                 * The block ends with an "if" of some sort, and its
+                 * secondary successor (the "then") is in fact the
+                 * next block to output. So, reverse the sense of
+                 * the test, so that we can just emit the next block
+                 * without an interstitial goto.
+                 */
+                output.reverseBranch(1, addresses.getStart(succ));
+            } else {
+                /*
+                 * Our only recourse is to add a goto here to get the
+                 * flow to be correct.
+                 */
+                TargetInsn insn =
+                    new TargetInsn(Dops.GOTO, lastInsn.getPosition(),
+                            RegisterSpecList.EMPTY,
+                            addresses.getStart(succ));
+                output.add(insn);
+            }
+        }
+    }
+
+    /**
+     * Picks an order for the blocks by doing "trace" analysis.
+     */
+    private void pickOrder() {
+        BasicBlockList blocks = method.getBlocks();
+        int sz = blocks.size();
+        int maxLabel = blocks.getMaxLabel();
+        int[] workSet = Bits.makeBitSet(maxLabel);
+        int[] tracebackSet = Bits.makeBitSet(maxLabel);
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = blocks.get(i);
+            Bits.set(workSet, one.getLabel());
+        }
+
+        int[] order = new int[sz];
+        int at = 0;
+
+        /*
+         * Starting with the designated "first label" (that is, the
+         * first block of the method), add that label to the order,
+         * and then pick its first as-yet unordered successor to
+         * immediately follow it, giving top priority to the primary
+         * (aka default) successor (if any). Keep following successors
+         * until the trace runs out of possibilities. Then, continue
+         * by finding an unordered chain containing the first as-yet
+         * unordered block, and adding it to the order, and so on.
+         */
+        for (int label = method.getFirstLabel();
+             label != -1;
+             label = Bits.findFirst(workSet, 0)) {
+
+            /*
+             * Attempt to trace backward from the chosen block to an
+             * as-yet unordered predecessor which lists the chosen
+             * block as its primary successor, and so on, until we
+             * fail to find such an unordered predecessor. Start the
+             * trace with that block. Note that the first block in the
+             * method has no predecessors, so in that case this loop
+             * will simply terminate with zero iterations and without
+             * picking a new starter block.
+             */
+            traceBack:
+            for (;;) {
+                IntList preds = method.labelToPredecessors(label);
+                int psz = preds.size();
+
+                for (int i = 0; i < psz; i++) {
+                    int predLabel = preds.get(i);
+
+                    if (Bits.get(tracebackSet, predLabel)) {
+                        /*
+                         * We found a predecessor loop; stop tracing back
+                         * from here.
+                         */
+                        break;
+                    }
+
+                    if (!Bits.get(workSet, predLabel)) {
+                        // This one's already ordered.
+                        continue;
+                    }
+
+                    BasicBlock pred = blocks.labelToBlock(predLabel);
+                    if (pred.getPrimarySuccessor() == label) {
+                        // Found one!
+                        label = predLabel;
+                        Bits.set(tracebackSet, label);
+                        continue traceBack;
+                    }
+                }
+
+                // Failed to find a better block to start the trace.
+                break;
+            }
+
+            /*
+             * Trace a path from the chosen block to one of its
+             * unordered successors (hopefully the primary), and so
+             * on, until we run out of unordered successors.
+             */
+            while (label != -1) {
+                Bits.clear(workSet, label);
+                Bits.clear(tracebackSet, label);
+                order[at] = label;
+                at++;
+
+                BasicBlock one = blocks.labelToBlock(label);
+                BasicBlock preferredBlock = blocks.preferredSuccessorOf(one);
+
+                if (preferredBlock == null) {
+                    break;
+                }
+
+                int preferred = preferredBlock.getLabel();
+                int primary = one.getPrimarySuccessor();
+
+                if (Bits.get(workSet, preferred)) {
+                    /*
+                     * Order the current block's preferred successor
+                     * next, as it has yet to be scheduled.
+                     */
+                    label = preferred;
+                } else if ((primary != preferred) && (primary >= 0)
+                        && Bits.get(workSet, primary)) {
+                    /*
+                     * The primary is available, so use that.
+                     */
+                    label = primary;
+                } else {
+                    /*
+                     * There's no obvious candidate, so pick the first
+                     * one that's available, if any.
+                     */
+                    IntList successors = one.getSuccessors();
+                    int ssz = successors.size();
+                    label = -1;
+                    for (int i = 0; i < ssz; i++) {
+                        int candidate = successors.get(i);
+                        if (Bits.get(workSet, candidate)) {
+                            label = candidate;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (at != sz) {
+            // There was a duplicate block label.
+            throw new RuntimeException("shouldn't happen");
+        }
+
+        this.order = order;
+    }
+
+    /**
+     * Gets the complete register list (result and sources) out of a
+     * given rop instruction. For insns that are commutative, have
+     * two register sources, and have a source equal to the result,
+     * place that source first.
+     *
+     * @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());
+    }
+
+    /**
+     * Gets the complete register list (result and sources) out of a
+     * given rop instruction. For insns that are commutative, have
+     * two register sources, and have a source equal to the result,
+     * place that source first.
+     *
+     * @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) {
+        RegisterSpecList regs = insn.getSources();
+
+        if (insn.getOpcode().isCommutative()
+                && (regs.size() == 2)
+                && (resultReg.getReg() == regs.get(1).getReg())) {
+
+            /*
+             * For commutative ops which have two register sources,
+             * if the second source is the same register as the result,
+             * swap the sources so that an opcode of form 12x can be selected
+             * instead of one of form 23x
+             */
+
+            regs = RegisterSpecList.make(regs.get(1), regs.get(0));
+        }
+
+        if (resultReg == null) {
+            return regs;
+        }
+
+        return regs.withFirst(resultReg);
+    }
+
+    /**
+     * Instruction visitor class for doing the instruction translation per se.
+     */
+    private class TranslationVisitor implements Insn.Visitor {
+        /** {@code non-null;} list of output instructions in-progress */
+        private final OutputCollector output;
+
+        /** {@code non-null;} basic block being worked on */
+        private BasicBlock block;
+
+        /**
+         * {@code null-ok;} code address for the salient last instruction of the
+         * block (used before switches and throwing instructions)
+         */
+        private CodeAddress lastAddress;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param output {@code non-null;} destination for instruction output
+         */
+        public TranslationVisitor(OutputCollector output) {
+            this.output = output;
+        }
+
+        /**
+         * Sets the block currently being worked on.
+         *
+         * @param block {@code non-null;} the block
+         * @param lastAddress {@code non-null;} code address for the salient
+         * last instruction of the block
+         */
+        public void setBlock(BasicBlock block, CodeAddress lastAddress) {
+            this.block = block;
+            this.lastAddress = lastAddress;
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainInsn(PlainInsn insn) {
+            Rop rop = insn.getOpcode();
+            if (rop.getOpcode() == RegOps.MARK_LOCAL) {
+                /*
+                 * Ignore these. They're dealt with by
+                 * the LocalVariableAwareTranslationVisitor
+                 */
+                return;
+            }
+            if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+                // These get skipped
+                return;
+            }
+
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            DalvInsn di;
+
+            switch (rop.getBranchingness()) {
+                case Rop.BRANCH_NONE:
+                case Rop.BRANCH_RETURN:
+                case Rop.BRANCH_THROW: {
+                    di = new SimpleInsn(opcode, pos, getRegs(insn));
+                    break;
+                }
+                case Rop.BRANCH_GOTO: {
+                    /*
+                     * Code in the main translation loop will emit a
+                     * goto if necessary (if the branch isn't to the
+                     * immediately subsequent block).
+                     */
+                    return;
+                }
+                case Rop.BRANCH_IF: {
+                    int target = block.getSuccessors().get(1);
+                    di = new TargetInsn(opcode, pos, getRegs(insn),
+                                        addresses.getStart(target));
+                    break;
+                }
+                default: {
+                    throw new RuntimeException("shouldn't happen");
+                }
+            }
+
+            addOutput(di);
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            Rop rop = insn.getOpcode();
+            int ropOpcode = rop.getOpcode();
+            DalvInsn di;
+
+            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            if (ropOpcode == RegOps.MOVE_PARAM) {
+                if (!paramsAreInOrder) {
+                    /*
+                     * Parameters are not in order at the top of the reg space.
+                     * We need to add moves.
+                     */
+
+                    RegisterSpec dest = insn.getResult();
+                    int param =
+                        ((CstInteger) insn.getConstant()).getValue();
+                    RegisterSpec source =
+                        RegisterSpec.make(regCount - paramSize + param,
+                                dest.getType());
+                    di = new SimpleInsn(opcode, pos,
+                                        RegisterSpecList.make(dest, source));
+                    addOutput(di);
+                }
+            } else {
+                // No moves required for the parameters
+                RegisterSpecList regs = getRegs(insn);
+                di = new CstInsn(opcode, pos, regs, insn.getConstant());
+                addOutput(di);
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitchInsn(SwitchInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            IntList cases = insn.getCases();
+            IntList successors = block.getSuccessors();
+            int casesSz = cases.size();
+            int succSz = successors.size();
+            int primarySuccessor = block.getPrimarySuccessor();
+
+            /*
+             * Check the assumptions that the number of cases is one
+             * less than the number of successors and that the last
+             * successor in the list is the primary (in this case, the
+             * default). This test is here to guard against forgetting
+             * to change this code if the way switch instructions are
+             * constructed also gets changed.
+             */
+            if ((casesSz != (succSz - 1)) ||
+                (primarySuccessor != successors.get(casesSz))) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            CodeAddress[] switchTargets = new CodeAddress[casesSz];
+
+            for (int i = 0; i < casesSz; i++) {
+                int label = successors.get(i);
+                switchTargets[i] = addresses.getStart(label);
+            }
+
+            CodeAddress dataAddress = new CodeAddress(pos);
+            SwitchData dataInsn =
+                new SwitchData(pos, lastAddress, cases, switchTargets);
+            Dop opcode = dataInsn.isPacked() ?
+                Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
+            TargetInsn switchInsn =
+                new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
+
+            addOutput(lastAddress);
+            addOutput(switchInsn);
+
+            addOutputSuffix(new OddSpacer(pos));
+            addOutputSuffix(dataAddress);
+            addOutputSuffix(dataInsn);
+        }
+
+        /**
+         * Looks forward to the current block's primary successor, returning
+         * the RegisterSpec of the result of the move-result-pseudo at the
+         * top of that block or null if none.
+         *
+         * @return {@code null-ok;} result of move-result-pseudo at the beginning of
+         * primary successor
+         */
+        private RegisterSpec getNextMoveResultPseudo()
+        {
+            int label = block.getPrimarySuccessor();
+
+            if (label < 0) {
+                return null;
+            }
+
+            Insn insn
+                    = method.getBlocks().labelToBlock(label).getInsns().get(0);
+
+            if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) {
+                return null;
+            } else {
+                return insn.getResult();
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            Rop rop = insn.getOpcode();
+            Constant cst = insn.getConstant();
+
+            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            addOutput(lastAddress);
+
+            if (rop.isCallLike()) {
+                RegisterSpecList regs = insn.getSources();
+                DalvInsn di = new CstInsn(opcode, pos, regs, cst);
+
+                addOutput(di);
+            } else {
+                RegisterSpec realResult = getNextMoveResultPseudo();
+
+                RegisterSpecList regs = getRegs(insn, realResult);
+                DalvInsn di;
+
+                boolean hasResult = opcode.hasResult()
+                        || (rop.getOpcode() == RegOps.CHECK_CAST);
+
+                if (hasResult != (realResult != null)) {
+                    throw new RuntimeException(
+                            "Insn with result/move-result-pseudo mismatch " +
+                            insn);
+                }
+
+                if ((rop.getOpcode() == RegOps.NEW_ARRAY) &&
+                    (opcode.getOpcode() != Opcodes.NEW_ARRAY)) {
+                    /*
+                     * It's a type-specific new-array-<primitive>, and
+                     * so it should be turned into a SimpleInsn (no
+                     * constant ref as it's implicit).
+                     */
+                    di = new SimpleInsn(opcode, pos, regs);
+                } else {
+                    /*
+                     * This is the general case for constant-bearing
+                     * instructions.
+                     */
+                    di = new CstInsn(opcode, pos, regs, cst);
+                }
+
+                addOutput(di);
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Dop opcode = RopToDop.dopFor(insn);
+            Rop rop = insn.getOpcode();
+            RegisterSpec realResult;
+
+            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
+                throw new RuntimeException("shouldn't happen");
+            }
+
+            realResult = getNextMoveResultPseudo();
+
+            if (opcode.hasResult() != (realResult != null)) {
+                throw new RuntimeException(
+                        "Insn with result/move-result-pseudo mismatch" + insn);
+            }
+
+            addOutput(lastAddress);
+
+            DalvInsn di = new SimpleInsn(opcode, pos,
+                    getRegs(insn, realResult));
+
+            addOutput(di);
+        }
+
+        /** {@inheritDoc} */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+            SourcePosition pos = insn.getPosition();
+            Constant cst = insn.getConstant();
+            ArrayList<Constant> values = insn.getInitValues();
+            Rop rop = insn.getOpcode();
+
+            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
+                throw new RuntimeException("shouldn't happen");
+            }
+            CodeAddress dataAddress = new CodeAddress(pos);
+            ArrayData dataInsn =
+                new ArrayData(pos, lastAddress, values, cst);
+
+            TargetInsn fillArrayDataInsn =
+                new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn),
+                        dataAddress);
+
+            addOutput(lastAddress);
+            addOutput(fillArrayDataInsn);
+
+            addOutputSuffix(new OddSpacer(pos));
+            addOutputSuffix(dataAddress);
+            addOutputSuffix(dataInsn);
+        }
+
+        /**
+         * Adds to the output.
+         *
+         * @param insn {@code non-null;} instruction to add
+         */
+        protected void addOutput(DalvInsn insn) {
+            output.add(insn);
+        }
+
+        /**
+         * Adds to the output suffix.
+         *
+         * @param insn {@code non-null;} instruction to add
+         */
+        protected void addOutputSuffix(DalvInsn insn) {
+            output.addSuffix(insn);
+        }
+    }
+
+    /**
+     * Instruction visitor class for doing instruction translation with
+     * local variable tracking
+     */
+    private class LocalVariableAwareTranslationVisitor
+            extends TranslationVisitor {
+        /** {@code non-null;} local variable info */
+        private LocalVariableInfo locals;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param output {@code non-null;} destination for instruction output
+         * @param locals {@code non-null;} the local variable info
+         */
+        public LocalVariableAwareTranslationVisitor(OutputCollector output,
+                                                    LocalVariableInfo locals) {
+            super(output);
+            this.locals = locals;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitPlainInsn(PlainInsn insn) {
+            super.visitPlainInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            super.visitPlainCstInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitSwitchInsn(SwitchInsn insn) {
+            super.visitSwitchInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            super.visitThrowingCstInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            super.visitThrowingInsn(insn);
+            addIntroductionIfNecessary(insn);
+        }
+
+        /**
+         * Adds a {@link LocalStart} to the output if the given
+         * instruction in fact introduces a local variable.
+         *
+         * @param insn {@code non-null;} instruction in question
+         */
+        public void addIntroductionIfNecessary(Insn insn) {
+            RegisterSpec spec = locals.getAssignment(insn);
+
+            if (spec != null) {
+                addOutput(new LocalStart(insn.getPosition(), spec));
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/SimpleInsn.java b/dx/src/com/android/dx/dex/code/SimpleInsn.java
new file mode 100644
index 0000000..8cdcc55
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/SimpleInsn.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Instruction which has no extra info beyond the basics provided for in
+ * the base class.
+ */
+public final class SimpleInsn extends FixedSizeInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     */
+    public SimpleInsn(Dop opcode, SourcePosition position,
+                      RegisterSpecList registers) {
+        super(opcode, position, registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withOpcode(Dop opcode) {
+        return new SimpleInsn(opcode, getPosition(), getRegisters());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new SimpleInsn(getOpcode(), getPosition(), registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        return null;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
new file mode 100644
index 0000000..1e7612e
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * Constructor of {@link CatchTable} instances from {@link RopMethod}
+ * and associated data.
+ */
+public final class StdCatchBuilder implements CatchBuilder {
+    /** the maximum range of a single catch handler, in code units */
+    private static final int MAX_CATCH_RANGE = 65535;
+
+    /** {@code non-null;} method to build the list for */
+    private final RopMethod method;
+
+    /** {@code non-null;} block output order */
+    private final int[] order;
+
+    /** {@code non-null;} address objects for each block */
+    private final BlockAddresses addresses;
+
+    /**
+     * Constructs an instance. It merely holds onto its parameters for
+     * a subsequent call to {@link #build}.
+     *
+     * @param method {@code non-null;} method to build the list for
+     * @param order {@code non-null;} block output order
+     * @param addresses {@code non-null;} address objects for each block
+     */
+    public StdCatchBuilder(RopMethod method, int[] order,
+            BlockAddresses addresses) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (order == null) {
+            throw new NullPointerException("order == null");
+        }
+
+        if (addresses == null) {
+            throw new NullPointerException("addresses == null");
+        }
+
+        this.method = method;
+        this.order = order;
+        this.addresses = addresses;
+    }
+
+    /** {@inheritDoc} */
+    public CatchTable build() {
+        return build(method, order, addresses);
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasAnyCatches() {
+        BasicBlockList blocks = method.getBlocks();
+        int size = blocks.size();
+
+        for (int i = 0; i < size; i++) {
+            BasicBlock block = blocks.get(i);
+            TypeList catches = block.getLastInsn().getCatches();
+            if (catches.size() != 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public HashSet<Type> getCatchTypes() {
+        HashSet<Type> result = new HashSet<Type>(20);
+        BasicBlockList blocks = method.getBlocks();
+        int size = blocks.size();
+
+        for (int i = 0; i < size; i++) {
+            BasicBlock block = blocks.get(i);
+            TypeList catches = block.getLastInsn().getCatches();
+            int catchSize = catches.size();
+
+            for (int j = 0; j < catchSize; j++) {
+                result.add(catches.getType(j));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Builds and returns the catch table for a given method.
+     *
+     * @param method {@code non-null;} method to build the list for
+     * @param order {@code non-null;} block output order
+     * @param addresses {@code non-null;} address objects for each block
+     * @return {@code non-null;} the constructed table
+     */
+    public static CatchTable build(RopMethod method, int[] order,
+            BlockAddresses addresses) {
+        int len = order.length;
+        BasicBlockList blocks = method.getBlocks();
+        ArrayList<CatchTable.Entry> resultList =
+            new ArrayList<CatchTable.Entry>(len);
+        CatchHandlerList currentHandlers = CatchHandlerList.EMPTY;
+        BasicBlock currentStartBlock = null;
+        BasicBlock currentEndBlock = null;
+
+        for (int i = 0; i < len; i++) {
+            BasicBlock block = blocks.labelToBlock(order[i]);
+
+            if (!block.canThrow()) {
+                /*
+                 * There is no need to concern ourselves with the
+                 * placement of blocks that can't throw with respect
+                 * to the blocks that *can* throw.
+                 */
+                continue;
+            }
+
+            CatchHandlerList handlers = handlersFor(block, addresses);
+
+            if (currentHandlers.size() == 0) {
+                // This is the start of a new catch range.
+                currentStartBlock = block;
+                currentEndBlock = block;
+                currentHandlers = handlers;
+                continue;
+            }
+
+            if (currentHandlers.equals(handlers)
+                    && rangeIsValid(currentStartBlock, block, addresses)) {
+                /*
+                 * The block we are looking at now has the same handlers
+                 * as the block that started the currently open catch
+                 * range, and adding it to the currently open range won't
+                 * cause it to be too long.
+                 */
+                currentEndBlock = block;
+                continue;
+            }
+
+            /*
+             * The block we are looking at now has incompatible handlers,
+             * so we need to finish off the last entry and start a new
+             * one. Note: We only emit an entry if it has associated handlers.
+             */
+            if (currentHandlers.size() != 0) {
+                CatchTable.Entry entry =
+                    makeEntry(currentStartBlock, currentEndBlock,
+                            currentHandlers, addresses);
+                resultList.add(entry);
+            }
+
+            currentStartBlock = block;
+            currentEndBlock = block;
+            currentHandlers = handlers;
+        }
+
+        if (currentHandlers.size() != 0) {
+            // Emit an entry for the range that was left hanging.
+            CatchTable.Entry entry =
+                makeEntry(currentStartBlock, currentEndBlock,
+                        currentHandlers, addresses);
+            resultList.add(entry);
+        }
+
+        // Construct the final result.
+
+        int resultSz = resultList.size();
+
+        if (resultSz == 0) {
+            return CatchTable.EMPTY;
+        }
+
+        CatchTable result = new CatchTable(resultSz);
+
+        for (int i = 0; i < resultSz; i++) {
+            result.set(i, resultList.get(i));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Makes the {@link CatchHandlerList} for the given basic block.
+     *
+     * @param block {@code non-null;} block to get entries for
+     * @param addresses {@code non-null;} address objects for each block
+     * @return {@code non-null;} array of entries
+     */
+    private static CatchHandlerList handlersFor(BasicBlock block,
+            BlockAddresses addresses) {
+        IntList successors = block.getSuccessors();
+        int succSize = successors.size();
+        int primary = block.getPrimarySuccessor();
+        TypeList catches = block.getLastInsn().getCatches();
+        int catchSize = catches.size();
+
+        if (catchSize == 0) {
+            return CatchHandlerList.EMPTY;
+        }
+
+        if (((primary == -1) && (succSize != catchSize))
+                || ((primary != -1) &&
+                        ((succSize != (catchSize + 1))
+                                || (primary != successors.get(catchSize))))) {
+            /*
+             * Blocks that throw are supposed to list their primary
+             * successor -- if any -- last in the successors list, but
+             * that constraint appears to be violated here.
+             */
+            throw new RuntimeException(
+                    "shouldn't happen: weird successors list");
+        }
+
+        /*
+         * Reduce the effective catchSize if we spot a catch-all that
+         * isn't at the end.
+         */
+        for (int i = 0; i < catchSize; i++) {
+            Type type = catches.getType(i);
+            if (type.equals(Type.OBJECT)) {
+                catchSize = i + 1;
+                break;
+            }
+        }
+
+        CatchHandlerList result = new CatchHandlerList(catchSize);
+
+        for (int i = 0; i < catchSize; i++) {
+            CstType oneType = new CstType(catches.getType(i));
+            CodeAddress oneHandler = addresses.getStart(successors.get(i));
+            result.set(i, oneType, oneHandler.getAddress());
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Makes a {@link CatchTable#Entry} for the given block range and
+     * handlers.
+     *
+     * @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,
+            BlockAddresses addresses) {
+        /*
+         * We start at the *last* instruction of the start block, since
+         * that's the instruction that can throw...
+         */
+        CodeAddress startAddress = addresses.getLast(start);
+
+        // ...And we end *after* the last instruction of the end block.
+        CodeAddress endAddress = addresses.getEnd(end);
+
+        return new CatchTable.Entry(startAddress.getAddress(),
+                endAddress.getAddress(), handlers);
+    }
+
+    /**
+     * Gets whether the address range for the given two blocks is valid
+     * for a catch handler. This is true as long as the covered range is
+     * under 65536 code units.
+     *
+     * @param start {@code non-null;} the start block for the range (inclusive)
+     * @param end {@code non-null;} the start block for the range (also inclusive)
+     * @param addresses {@code non-null;} address objects for each block
+     * @return {@code true} if the range is valid as a catch range
+     */
+    private static boolean rangeIsValid(BasicBlock start, BasicBlock end,
+            BlockAddresses addresses) {
+        if (start == null) {
+            throw new NullPointerException("start == null");
+        }
+
+        if (end == null) {
+            throw new NullPointerException("end == null");
+        }
+
+        // See above about selection of instructions.
+        int startAddress = addresses.getLast(start).getAddress();
+        int endAddress = addresses.getEnd(end).getAddress();
+
+        return (endAddress - startAddress) <= MAX_CATCH_RANGE;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/SwitchData.java b/dx/src/com/android/dx/dex/code/SwitchData.java
new file mode 100644
index 0000000..8fc80b1
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/SwitchData.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.io.Opcodes;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+/**
+ * Pseudo-instruction which holds switch data. The switch data is
+ * a map of values to target addresses, and this class writes the data
+ * in either a "packed" or "sparse" form.
+ */
+public final class SwitchData extends VariableSizeInsn {
+    /**
+     * {@code non-null;} address representing the instruction that uses this
+     * instance
+     */
+    private final CodeAddress user;
+
+    /** {@code non-null;} sorted list of switch cases (keys) */
+    private final IntList cases;
+
+    /**
+     * {@code non-null;} corresponding list of code addresses; the branch
+     * target for each case
+     */
+    private final CodeAddress[] targets;
+
+    /** whether the output table will be packed (vs. sparse) */
+    private final boolean packed;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param user {@code non-null;} address representing the instruction that
+     * uses this instance
+     * @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,
+                      IntList cases, CodeAddress[] targets) {
+        super(position, RegisterSpecList.EMPTY);
+
+        if (user == null) {
+            throw new NullPointerException("user == null");
+        }
+
+        if (cases == null) {
+            throw new NullPointerException("cases == null");
+        }
+
+        if (targets == null) {
+            throw new NullPointerException("targets == null");
+        }
+
+        int sz = cases.size();
+
+        if (sz != targets.length) {
+            throw new IllegalArgumentException("cases / targets mismatch");
+        }
+
+        if (sz > 65535) {
+            throw new IllegalArgumentException("too many cases");
+        }
+
+        this.user = user;
+        this.cases = cases;
+        this.targets = targets;
+        this.packed = shouldPack(cases);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return packed ? (int) packedCodeSize(cases) :
+            (int) sparseCodeSize(cases);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out) {
+        int baseAddress = user.getAddress();
+        int defaultTarget = Dops.PACKED_SWITCH.getFormat().codeSize();
+        int sz = targets.length;
+
+        if (packed) {
+            int firstCase = (sz == 0) ? 0 : cases.get(0);
+            int lastCase = (sz == 0) ? 0 : cases.get(sz - 1);
+            int outSz = lastCase - firstCase + 1;
+
+            out.writeShort(Opcodes.PACKED_SWITCH_PAYLOAD);
+            out.writeShort(outSz);
+            out.writeInt(firstCase);
+
+            int caseAt = 0;
+            for (int i = 0; i < outSz; i++) {
+                int outCase = firstCase + i;
+                int oneCase = cases.get(caseAt);
+                int relTarget;
+
+                if (oneCase > outCase) {
+                    relTarget = defaultTarget;
+                } else {
+                    relTarget = targets[caseAt].getAddress() - baseAddress;
+                    caseAt++;
+                }
+
+                out.writeInt(relTarget);
+            }
+        } else {
+            out.writeShort(Opcodes.SPARSE_SWITCH_PAYLOAD);
+            out.writeShort(sz);
+
+            for (int i = 0; i < sz; i++) {
+                out.writeInt(cases.get(i));
+            }
+
+            for (int i = 0; i < sz; i++) {
+                int relTarget = targets[i].getAddress() - baseAddress;
+                out.writeInt(relTarget);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new SwitchData(getPosition(), user, cases, targets);
+    }
+
+    /**
+     * Returns whether or not this instance's data will be output as packed.
+     *
+     * @return {@code true} iff the data is to be packed
+     */
+    public boolean isPacked() {
+        return packed;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        int sz = targets.length;
+        for (int i = 0; i < sz; i++) {
+            sb.append("\n    ");
+            sb.append(cases.get(i));
+            sb.append(": ");
+            sb.append(targets[i]);
+        }
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String listingString0(boolean noteIndices) {
+        int baseAddress = user.getAddress();
+        StringBuffer sb = new StringBuffer(100);
+        int sz = targets.length;
+
+        sb.append(packed ? "packed" : "sparse");
+        sb.append("-switch-payload // for switch @ ");
+        sb.append(Hex.u2(baseAddress));
+
+        for (int i = 0; i < sz; i++) {
+            int absTarget = targets[i].getAddress();
+            int relTarget = absTarget - baseAddress;
+            sb.append("\n  ");
+            sb.append(cases.get(i));
+            sb.append(": ");
+            sb.append(Hex.u4(absTarget));
+            sb.append(" // ");
+            sb.append(Hex.s4(relTarget));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the size of a packed table for the given cases, in 16-bit code
+     * units.
+     *
+     * @param cases {@code non-null;} sorted list of cases
+     * @return {@code >= -1;} the packed table size or {@code -1} if the
+     * cases couldn't possibly be represented as a packed table
+     */
+    private static long packedCodeSize(IntList cases) {
+        int sz = cases.size();
+        long low = cases.get(0);
+        long high = cases.get(sz - 1);
+        long result = ((high - low + 1)) * 2 + 4;
+
+        return (result <= 0x7fffffff) ? result : -1;
+    }
+
+    /**
+     * Gets the size of a sparse table for the given cases, in 16-bit code
+     * units.
+     *
+     * @param cases {@code non-null;} sorted list of cases
+     * @return {@code > 0;} the sparse table size
+     */
+    private static long sparseCodeSize(IntList cases) {
+        int sz = cases.size();
+
+        return (sz * 4L) + 2;
+    }
+
+    /**
+     * Determines whether the given list of cases warrant being packed.
+     *
+     * @param cases {@code non-null;} sorted list of cases
+     * @return {@code true} iff the table encoding the cases
+     * should be packed
+     */
+    private static boolean shouldPack(IntList cases) {
+        int sz = cases.size();
+
+        if (sz < 2) {
+            return true;
+        }
+
+        long packedSize = packedCodeSize(cases);
+        long sparseSize = sparseCodeSize(cases);
+
+        /*
+         * We pick the packed representation if it is possible and
+         * would be as small or smaller than 5/4 of the sparse
+         * representation. That is, we accept some size overhead on
+         * the packed representation, since that format is faster to
+         * execute at runtime.
+         */
+        return (packedSize >= 0) && (packedSize <= ((sparseSize * 5) / 4));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/TargetInsn.java b/dx/src/com/android/dx/dex/code/TargetInsn.java
new file mode 100644
index 0000000..cbb5ff9
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/TargetInsn.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Instruction which has a single branch target.
+ */
+public final class TargetInsn extends FixedSizeInsn {
+    /** {@code non-null;} the branch target */
+    private CodeAddress target;
+
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}), and the target is initially
+     * {@code null}.
+     *
+     * @param opcode the opcode; one of the constants from {@link Dops}
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} register list, including a
+     * result register if appropriate (that is, registers may be either
+     * ins or outs)
+     * @param target {@code non-null;} the branch target
+     */
+    public TargetInsn(Dop opcode, SourcePosition position,
+                      RegisterSpecList registers, CodeAddress target) {
+        super(opcode, position, registers);
+
+        if (target == null) {
+            throw new NullPointerException("target == null");
+        }
+
+        this.target = target;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withOpcode(Dop opcode) {
+        return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisters(RegisterSpecList registers) {
+        return new TargetInsn(getOpcode(), getPosition(), registers, target);
+    }
+
+    /**
+     * 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} test becomes a {@code ge}), and its branch
+     * target is replaced by the one given, and all set-once values
+     * associated with the class (such as its address) are reset.
+     *
+     * @param target {@code non-null;} the new branch target
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public TargetInsn withNewTargetAndReversed(CodeAddress target) {
+        Dop opcode = getOpcode().getOppositeTest();
+
+        return new TargetInsn(opcode, getPosition(), getRegisters(), target);
+    }
+
+    /**
+     * Gets the unique branch target of this instruction.
+     *
+     * @return {@code non-null;} the branch target
+     */
+    public CodeAddress getTarget() {
+        return target;
+    }
+
+    /**
+     * 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()}.
+     *
+     * @return {@code >= 0;} the target address
+     */
+    public int getTargetAddress() {
+        return target.getAddress();
+    }
+
+    /**
+     * 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()}.
+     *
+     * @return the branch offset
+     */
+    public int getTargetOffset() {
+        return target.getAddress() - getAddress();
+    }
+
+    /**
+     * Returns whether the target offset is known.
+     *
+     * @return {@code true} if the target offset is known or
+     * {@code false} if not
+     */
+    public boolean hasTargetOffset() {
+        return hasAddress() && target.hasAddress();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String argString() {
+        if (target == null) {
+            return "????";
+        }
+
+        return target.identifierString();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
new file mode 100644
index 0000000..06b40f7
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+
+/**
+ * Pseudo-instruction base class for variable-sized instructions.
+ */
+public abstract class VariableSizeInsn extends DalvInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     * @param registers {@code non-null;} source registers
+     */
+    public VariableSizeInsn(SourcePosition position,
+                            RegisterSpecList registers) {
+        super(Dops.SPECIAL_FORMAT, position, registers);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withOpcode(Dop opcode) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withRegisterOffset(int delta) {
+        return withRegisters(getRegisters().withOffset(delta));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
new file mode 100644
index 0000000..2cc157b
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Pseudo-instruction base class for zero-size (no code emitted)
+ * instructions, which are generally used for tracking metainformation
+ * about the code they are adjacent to.
+ */
+public abstract class ZeroSizeInsn extends DalvInsn {
+    /**
+     * Constructs an instance. The output address of this instance is initially
+     * unknown ({@code -1}).
+     *
+     * @param position {@code non-null;} source position
+     */
+    public ZeroSizeInsn(SourcePosition position) {
+        super(Dops.SPECIAL_FORMAT, position, RegisterSpecList.EMPTY);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int codeSize() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(AnnotatedOutput out) {
+        // Nothing to do here, for this class.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final DalvInsn withOpcode(Dop opcode) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DalvInsn withRegisterOffset(int delta) {
+        return withRegisters(getRegisters().withOffset(delta));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form10t.java b/dx/src/com/android/dx/dex/code/form/Form10t.java
new file mode 100644
index 0000000..ced4a64
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form10t.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.TargetInsn;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 10t}. See the instruction format spec
+ * for details.
+ */
+public final class Form10t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form10t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form10t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!((insn instanceof TargetInsn) &&
+              (insn.getRegisters().size() == 0))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInByte(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, (offset & 0xff)));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form10x.java b/dx/src/com/android/dx/dex/code/form/Form10x.java
new file mode 100644
index 0000000..4be3aa0
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form10x.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 10x}. See the instruction format spec
+ * for details.
+ */
+public final class Form10x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form10x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form10x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        // This format has no arguments.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        return (insn instanceof SimpleInsn) &&
+            (insn.getRegisters().size() == 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        write(out, opcodeUnit(insn, 0));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form11n.java b/dx/src/com/android/dx/dex/code/form/Form11n.java
new file mode 100644
index 0000000..479af6e
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form11n.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 11n}. See the instruction format spec
+ * for details.
+ */
+public final class Form11n extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form11n();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form11n() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 4);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInNibble(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInNibble(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, makeByte(regs.get(0).getReg(), value & 0xf)));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form11x.java b/dx/src/com/android/dx/dex/code/form/Form11x.java
new file mode 100644
index 0000000..82dda65
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form11x.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 11x}. See the instruction format spec
+ * for details.
+ */
+public final class Form11x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form11x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form11x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 1) &&
+            unsignedFitsInByte(regs.get(0).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out, opcodeUnit(insn, regs.get(0).getReg()));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form12x.java b/dx/src/com/android/dx/dex/code/form/Form12x.java
new file mode 100644
index 0000000..aabab8a
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form12x.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 12x}. See the instruction format spec
+ * for details.
+ */
+public final class Form12x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form12x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form12x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+
+        /*
+         * The (sz - 2) and (sz - 1) below makes this code work for
+         * both the two- and three-register ops. (See "case 3" in
+         * isCompatible(), below.)
+         */
+
+        return regs.get(sz - 2).regString() + ", " +
+            regs.get(sz - 1).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof SimpleInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec rs1;
+        RegisterSpec rs2;
+
+        switch (regs.size()) {
+            case 2: {
+                rs1 = regs.get(0);
+                rs2 = regs.get(1);
+                break;
+            }
+            case 3: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 3-arg but where the first two args are identical.
+                 */
+                rs1 = regs.get(1);
+                rs2 = regs.get(2);
+                if (rs1.getReg() != regs.get(0).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        return unsignedFitsInNibble(rs1.getReg()) &&
+            unsignedFitsInNibble(rs2.getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+
+        /*
+         * The (sz - 2) and (sz - 1) below makes this code work for
+         * both the two- and three-register ops. (See "case 3" in
+         * isCompatible(), above.)
+         */
+
+        write(out, opcodeUnit(insn,
+                              makeByte(regs.get(sz - 2).getReg(),
+                                       regs.get(sz - 1).getReg())));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form20t.java b/dx/src/com/android/dx/dex/code/form/Form20t.java
new file mode 100644
index 0000000..a19ed28
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form20t.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.TargetInsn;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 20t}. See the instruction format spec
+ * for details.
+ */
+public final class Form20t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form20t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form20t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!((insn instanceof TargetInsn) &&
+              (insn.getRegisters().size() == 0))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInShort(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, 0), (short) offset);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form21c.java b/dx/src/com/android/dx/dex/code/form/Form21c.java
new file mode 100644
index 0000000..0335dc7
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form21c.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 21c}. See the instruction format spec
+ * for details.
+ */
+public final class Form21c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec reg;
+
+        switch (regs.size()) {
+            case 1: {
+                reg = regs.get(0);
+                break;
+            }
+            case 2: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 2-arg but where the two args are identical.
+                 */
+                reg = regs.get(0);
+                if (reg.getReg() != regs.get(1).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        if (!unsignedFitsInByte(reg.getReg())) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+        Constant cst = ci.getConstant();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef) ||
+            (cst instanceof CstString);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+        BitSet bits = new BitSet(sz);
+        boolean compat = unsignedFitsInByte(regs.get(0).getReg());
+
+        if (sz == 1) {
+            bits.set(0, compat);
+        } else {
+            if (regs.get(0).getReg() == regs.get(1).getReg()) {
+                bits.set(0, compat);
+                bits.set(1, compat);
+            }
+        }
+
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) cpi);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form21h.java b/dx/src/com/android/dx/dex/code/form/Form21h.java
new file mode 100644
index 0000000..02cc0fd
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form21h.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 21h}. See the instruction format spec
+ * for details.
+ */
+public final class Form21h extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21h();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21h() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return
+            literalBitsComment(value,
+                    (regs.get(0).getCategory() == 1) ? 32 : 64);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        // Where the high bits are depends on the category of the target.
+        if (regs.get(0).getCategory() == 1) {
+            int bits = cb.getIntBits();
+            return ((bits & 0xffff) == 0);
+        } else {
+            long bits = cb.getLongBits();
+            return ((bits & 0xffffffffffffL) == 0);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits cb = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        short bits;
+
+        // Where the high bits are depends on the category of the target.
+        if (regs.get(0).getCategory() == 1) {
+            bits = (short) (cb.getIntBits() >>> 16);
+        } else {
+            bits = (short) (cb.getLongBits() >>> 48);
+        }
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()), bits);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form21s.java b/dx/src/com/android/dx/dex/code/form/Form21s.java
new file mode 100644
index 0000000..9264ec0
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form21s.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 21s}. See the instruction format spec
+ * for details.
+ */
+public final class Form21s extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21s();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21s() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form21t.java b/dx/src/com/android/dx/dex/code/form/Form21t.java
new file mode 100644
index 0000000..8adb668
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form21t.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.TargetInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 21t}. See the instruction format spec
+ * for details.
+ */
+public final class Form21t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form21t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form21t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof TargetInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInShort(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) offset);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form22b.java b/dx/src/com/android/dx/dex/code/form/Form22b.java
new file mode 100644
index 0000000..e5a8b5d
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form22b.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 22b}. See the instruction format spec
+ * for details.
+ */
+public final class Form22b extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22b();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22b() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 8);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInByte(regs.get(0).getReg()) &&
+              unsignedFitsInByte(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInByte(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              codeUnit(regs.get(1).getReg(), value & 0xff));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form22c.java b/dx/src/com/android/dx/dex/code/form/Form22c.java
new file mode 100644
index 0000000..5ffdb86
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form22c.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 22c}. See the instruction format spec
+ * for details.
+ */
+public final class Form22c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInNibble(regs.get(0).getReg()) &&
+              unsignedFitsInNibble(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+              (short) cpi);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form22s.java b/dx/src/com/android/dx/dex/code/form/Form22s.java
new file mode 100644
index 0000000..03d180a
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form22s.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 22s}. See the instruction format spec
+ * for details.
+ */
+public final class Form22s extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22s();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22s() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + regs.get(1).regString()
+            + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInNibble(regs.get(0).getReg()) &&
+              unsignedFitsInNibble(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+              (short) value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form22t.java b/dx/src/com/android/dx/dex/code/form/Form22t.java
new file mode 100644
index 0000000..15ce0f8
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form22t.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.TargetInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 22t}. See the instruction format spec
+ * for details.
+ */
+public final class Form22t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof TargetInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInNibble(regs.get(0).getReg()) &&
+              unsignedFitsInNibble(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        TargetInsn ti = (TargetInsn) insn;
+        return ti.hasTargetOffset() ? branchFits(ti) : true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInNibble(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInNibble(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        int offset = insn.getTargetOffset();
+
+        // Note: A zero offset would fit, but it is prohibited by the spec.
+        return (offset != 0) && signedFitsInShort(offset);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(regs.get(0).getReg(), regs.get(1).getReg())),
+              (short) offset);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form22x.java b/dx/src/com/android/dx/dex/code/form/Form22x.java
new file mode 100644
index 0000000..01eec0b
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form22x.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 22x}. See the instruction format spec
+ * for details.
+ */
+public final class Form22x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form22x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form22x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 2) &&
+            unsignedFitsInByte(regs.get(0).getReg()) &&
+            unsignedFitsInShort(regs.get(1).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              (short) regs.get(1).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form23x.java b/dx/src/com/android/dx/dex/code/form/Form23x.java
new file mode 100644
index 0000000..9164482
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form23x.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 23x}. See the instruction format spec
+ * for details.
+ */
+public final class Form23x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form23x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form23x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + regs.get(2).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 3) &&
+            unsignedFitsInByte(regs.get(0).getReg()) &&
+            unsignedFitsInByte(regs.get(1).getReg()) &&
+            unsignedFitsInByte(regs.get(2).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(3);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
+        bits.set(2, unsignedFitsInByte(regs.get(2).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out,
+              opcodeUnit(insn, regs.get(0).getReg()),
+              codeUnit(regs.get(1).getReg(), regs.get(2).getReg()));
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form30t.java b/dx/src/com/android/dx/dex/code/form/Form30t.java
new file mode 100644
index 0000000..86a3e82
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form30t.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.TargetInsn;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 30t}. See the instruction format spec
+ * for details.
+ */
+public final class Form30t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form30t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form30t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!((insn instanceof TargetInsn) &&
+              (insn.getRegisters().size() == 0))) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, 0), offset);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form31c.java b/dx/src/com/android/dx/dex/code/form/Form31c.java
new file mode 100644
index 0000000..3295fda
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form31c.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 31c}. See the instruction format spec
+ * for details.
+ */
+public final class Form31c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form31c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form31c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec reg;
+
+        switch (regs.size()) {
+            case 1: {
+                reg = regs.get(0);
+                break;
+            }
+            case 2: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 2-arg but where the two args are identical.
+                 */
+                reg = regs.get(0);
+                if (reg.getReg() != regs.get(1).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        if (!unsignedFitsInByte(reg.getReg())) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef) ||
+            (cst instanceof CstString);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+        BitSet bits = new BitSet(sz);
+        boolean compat = unsignedFitsInByte(regs.get(0).getReg());
+
+        if (sz == 1) {
+            bits.set(0, compat);
+        } else {
+            if (regs.get(0).getReg() == regs.get(1).getReg()) {
+                bits.set(0, compat);
+                bits.set(1, compat);
+            }
+        }
+
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()), cpi);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form31i.java b/dx/src/com/android/dx/dex/code/form/Form31i.java
new file mode 100644
index 0000000..b52341d
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form31i.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 31i}. See the instruction format spec
+ * for details.
+ */
+public final class Form31i extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form31i();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form31i() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 32);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        return ((CstLiteralBits) cst).fitsInInt();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()), value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form31t.java b/dx/src/com/android/dx/dex/code/form/Form31t.java
new file mode 100644
index 0000000..1999bba
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form31t.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.TargetInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 31t}. See the instruction format spec
+ * for details.
+ */
+public final class Form31t extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form31t();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form31t() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + branchString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        return branchComment(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        if (!((insn instanceof TargetInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean branchFits(TargetInsn insn) {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int offset = ((TargetInsn) insn).getTargetOffset();
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()), offset);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form32s.java b/dx/src/com/android/dx/dex/code/form/Form32s.java
new file mode 100644
index 0000000..e081470
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form32s.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 32s}. See the instruction format spec
+ * for details.
+ */
+public final class Form32s extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form32s();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form32s() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + regs.get(1).regString()
+            + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 16);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (! ALLOW_EXTENDED_OPCODES) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInByte(regs.get(0).getReg()) &&
+              unsignedFitsInByte(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!(cst instanceof CstLiteralBits)) {
+            return false;
+        }
+
+        CstLiteralBits cb = (CstLiteralBits) cst;
+
+        return cb.fitsInInt() && signedFitsInShort(cb.getIntBits());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int value =
+            ((CstLiteralBits) ((CstInsn) insn).getConstant()).getIntBits();
+
+        write(out,
+                opcodeUnit(insn),
+                codeUnit(regs.get(0).getReg(), regs.get(1).getReg()),
+                (short) value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form32x.java b/dx/src/com/android/dx/dex/code/form/Form32x.java
new file mode 100644
index 0000000..abed0e9
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form32x.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 32x}. See the instruction format spec
+ * for details.
+ */
+public final class Form32x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form32x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form32x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 2) &&
+            unsignedFitsInShort(regs.get(0).getReg()) &&
+            unsignedFitsInShort(regs.get(1).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInShort(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+
+        write(out,
+              opcodeUnit(insn, 0),
+              (short) regs.get(0).getReg(),
+              (short) regs.get(1).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form33x.java b/dx/src/com/android/dx/dex/code/form/Form33x.java
new file mode 100644
index 0000000..9a569a0
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form33x.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.dex.code.SimpleInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 33x}. See the instruction format spec
+ * for details.
+ */
+public final class Form33x extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form33x();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form33x() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + regs.get(2).regString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        // This format has no comment.
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (! ALLOW_EXTENDED_OPCODES) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+
+        return (insn instanceof SimpleInsn) &&
+            (regs.size() == 3) &&
+            unsignedFitsInByte(regs.get(0).getReg()) &&
+            unsignedFitsInByte(regs.get(1).getReg()) &&
+            unsignedFitsInShort(regs.get(2).getReg());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(3);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInByte(regs.get(1).getReg()));
+        bits.set(2, unsignedFitsInShort(regs.get(2).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        write(out,
+                opcodeUnit(insn),
+                codeUnit(regs.get(0).getReg(), regs.get(1).getReg()),
+                (short) regs.get(2).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form35c.java b/dx/src/com/android/dx/dex/code/form/Form35c.java
new file mode 100644
index 0000000..b9c12c6
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form35c.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 35c}. See the instruction format spec
+ * for details.
+ */
+public final class Form35c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form35c();
+
+    /** Maximal number of operands */
+    private static final int MAX_NUM_OPS = 5;
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form35c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        return regListString(regs) + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        Constant cst = ci.getConstant();
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        return (wordCount(regs) >= 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+        BitSet bits = new BitSet(sz);
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec reg = regs.get(i);
+            /*
+             * The check below adds (category - 1) to the register, to
+             * account for the fact that the second half of a
+             * category-2 register has to be represented explicitly in
+             * the result.
+             */
+            bits.set(i, unsignedFitsInNibble(reg.getReg() +
+                                             reg.getCategory() - 1));
+        }
+
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        int cpi = ((CstInsn) insn).getIndex();
+        RegisterSpecList regs = explicitize(insn.getRegisters());
+        int sz = regs.size();
+        int r0 = (sz > 0) ? regs.get(0).getReg() : 0;
+        int r1 = (sz > 1) ? regs.get(1).getReg() : 0;
+        int r2 = (sz > 2) ? regs.get(2).getReg() : 0;
+        int r3 = (sz > 3) ? regs.get(3).getReg() : 0;
+        int r4 = (sz > 4) ? regs.get(4).getReg() : 0;
+
+        write(out,
+              opcodeUnit(insn,
+                         makeByte(r4, sz)), // encode the fifth operand here
+              (short) cpi,
+              codeUnit(r0, r1, r2, r3));
+    }
+
+    /**
+     * Gets the number of words required for the given register list, where
+     * category-2 values count as two words. Return {@code -1} if the
+     * list requires more than five words or contains registers that need
+     * more than a nibble to identify them.
+     *
+     * @param regs {@code non-null;} the register list in question
+     * @return {@code >= -1;} the number of words required, or {@code -1}
+     * if the list couldn't possibly fit in this format
+     */
+    private static int wordCount(RegisterSpecList regs) {
+        int sz = regs.size();
+
+        if (sz > MAX_NUM_OPS) {
+            // It can't possibly fit.
+            return -1;
+        }
+
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = regs.get(i);
+            result += one.getCategory();
+            /*
+             * The check below adds (category - 1) to the register, to
+             * account for the fact that the second half of a
+             * category-2 register has to be represented explicitly in
+             * the result.
+             */
+            if (!unsignedFitsInNibble(one.getReg() + one.getCategory() - 1)) {
+                return -1;
+            }
+        }
+
+        return (result <= MAX_NUM_OPS) ? result : -1;
+    }
+
+    /**
+     * Returns a register list which is equivalent to the given one,
+     * except that it splits category-2 registers into two explicit
+     * entries. This returns the original list if no modification is
+     * required
+     *
+     * @param orig {@code non-null;} the original list
+     * @return {@code non-null;} the list with the described transformation
+     */
+    private static RegisterSpecList explicitize(RegisterSpecList orig) {
+        int wordCount = wordCount(orig);
+        int sz = orig.size();
+
+        if (wordCount == sz) {
+            return orig;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(wordCount);
+        int wordAt = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = orig.get(i);
+            result.set(wordAt, one);
+            if (one.getCategory() == 2) {
+                result.set(wordAt + 1,
+                           RegisterSpec.make(one.getReg() + 1, Type.VOID));
+                wordAt += 2;
+            } else {
+                wordAt++;
+            }
+        }
+
+        result.setImmutable();
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form3rc.java b/dx/src/com/android/dx/dex/code/form/Form3rc.java
new file mode 100644
index 0000000..1727af5
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form3rc.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 3rc}. See the instruction format spec
+ * for details.
+ */
+public final class Form3rc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form3rc();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form3rc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return regRangeString(insn.getRegisters()) + ", " +
+            cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        int cpi = ci.getIndex();
+        Constant cst = ci.getConstant();
+
+        if (! unsignedFitsInShort(cpi)) {
+            return false;
+        }
+
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        int sz = regs.size();
+
+        return (regs.size() == 0) ||
+            (isRegListSequential(regs) &&
+             unsignedFitsInShort(regs.get(0).getReg()) &&
+             unsignedFitsInByte(regs.getWordCount()));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+        int firstReg = (regs.size() == 0) ? 0 : regs.get(0).getReg();
+        int count = regs.getWordCount();
+
+        write(out, opcodeUnit(insn, count), (short) cpi, (short) firstReg);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form41c.java b/dx/src/com/android/dx/dex/code/form/Form41c.java
new file mode 100644
index 0000000..24067bc
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form41c.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 41c}. See the instruction format spec
+ * for details.
+ */
+public final class Form41c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form41c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form41c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 4;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (! ALLOW_EXTENDED_OPCODES) {
+            return false;
+        }
+
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        RegisterSpec reg;
+
+        switch (regs.size()) {
+            case 1: {
+                reg = regs.get(0);
+                break;
+            }
+            case 2: {
+                /*
+                 * This format is allowed for ops that are effectively
+                 * 2-arg but where the two args are identical.
+                 */
+                reg = regs.get(0);
+                if (reg.getReg() != regs.get(1).getReg()) {
+                    return false;
+                }
+                break;
+            }
+            default: {
+                return false;
+            }
+        }
+
+        if (!unsignedFitsInShort(reg.getReg())) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int sz = regs.size();
+        BitSet bits = new BitSet(sz);
+        boolean compat = unsignedFitsInByte(regs.get(0).getReg());
+
+        if (sz == 1) {
+            bits.set(0, compat);
+        } else {
+            if (regs.get(0).getReg() == regs.get(1).getReg()) {
+                bits.set(0, compat);
+                bits.set(1, compat);
+            }
+        }
+
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out, opcodeUnit(insn), cpi, (short) regs.get(0).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form51l.java b/dx/src/com/android/dx/dex/code/form/Form51l.java
new file mode 100644
index 0000000..4dc7bcd
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form51l.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteral64;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 51l}. See the instruction format spec
+ * for details.
+ */
+public final class Form51l extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form51l();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form51l() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+
+        return regs.get(0).regString() + ", " + literalBitsString(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        CstLiteralBits value = (CstLiteralBits) ((CstInsn) insn).getConstant();
+        return literalBitsComment(value, 64);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 1) &&
+              unsignedFitsInByte(regs.get(0).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstLiteral64);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(1);
+
+        bits.set(0, unsignedFitsInByte(regs.get(0).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        long value =
+            ((CstLiteral64) ((CstInsn) insn).getConstant()).getLongBits();
+
+        write(out, opcodeUnit(insn, regs.get(0).getReg()), value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form52c.java b/dx/src/com/android/dx/dex/code/form/Form52c.java
new file mode 100644
index 0000000..acd2124
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form52c.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.BitSet;
+
+/**
+ * Instruction format {@code 52c}. See the instruction format spec
+ * for details.
+ */
+public final class Form52c extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form52c();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form52c() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        return regs.get(0).regString() + ", " + regs.get(1).regString() +
+            ", " + cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (! ALLOW_EXTENDED_OPCODES) {
+            return false;
+        }
+
+        RegisterSpecList regs = insn.getRegisters();
+        if (!((insn instanceof CstInsn) &&
+              (regs.size() == 2) &&
+              unsignedFitsInShort(regs.get(0).getReg()) &&
+              unsignedFitsInShort(regs.get(1).getReg()))) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        return (cst instanceof CstType) ||
+            (cst instanceof CstFieldRef);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public BitSet compatibleRegs(DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        BitSet bits = new BitSet(2);
+
+        bits.set(0, unsignedFitsInShort(regs.get(0).getReg()));
+        bits.set(1, unsignedFitsInShort(regs.get(1).getReg()));
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+
+        write(out,
+                opcodeUnit(insn),
+                cpi,
+                (short) regs.get(0).getReg(),
+                (short) regs.get(1).getReg());
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/Form5rc.java b/dx/src/com/android/dx/dex/code/form/Form5rc.java
new file mode 100644
index 0000000..0c54702
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/Form5rc.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format {@code 5rc}. See the instruction format spec
+ * for details.
+ */
+public final class Form5rc extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new Form5rc();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private Form5rc() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        return regRangeString(insn.getRegisters()) + ", " +
+            cstString(insn);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        if (noteIndices) {
+            return cstComment(insn);
+        } else {
+            return "";
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        return 5;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        if (! ALLOW_EXTENDED_OPCODES) {
+            return false;
+        }
+
+        if (!(insn instanceof CstInsn)) {
+            return false;
+        }
+
+        CstInsn ci = (CstInsn) insn;
+        Constant cst = ci.getConstant();
+
+        if (!((cst instanceof CstMethodRef) ||
+              (cst instanceof CstType))) {
+            return false;
+        }
+
+        RegisterSpecList regs = ci.getRegisters();
+        int sz = regs.size();
+
+        return (regs.size() == 0) ||
+            (isRegListSequential(regs) &&
+             unsignedFitsInShort(regs.get(0).getReg()) &&
+             unsignedFitsInShort(regs.getWordCount()));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        RegisterSpecList regs = insn.getRegisters();
+        int cpi = ((CstInsn) insn).getIndex();
+        int firstReg = (regs.size() == 0) ? 0 : regs.get(0).getReg();
+        int count = regs.getWordCount();
+
+        write(out, opcodeUnit(insn), cpi, (short) count, (short) firstReg);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/code/form/SpecialFormat.java b/dx/src/com/android/dx/dex/code/form/SpecialFormat.java
new file mode 100644
index 0000000..87091b5
--- /dev/null
+++ b/dx/src/com/android/dx/dex/code/form/SpecialFormat.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.code.form;
+
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.InsnFormat;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Instruction format for nonstandard format instructions, which aren't
+ * generally real instructions but do end up appearing in instruction
+ * 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}.
+ */
+public final class SpecialFormat extends InsnFormat {
+    /** {@code non-null;} unique instance of this class */
+    public static final InsnFormat THE_ONE = new SpecialFormat();
+
+    /**
+     * Constructs an instance. This class is not publicly
+     * instantiable. Use {@link #THE_ONE}.
+     */
+    private SpecialFormat() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnArgString(DalvInsn insn) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int codeSize() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCompatible(DalvInsn insn) {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
+        throw new RuntimeException("unsupported");
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/AnnotationItem.java b/dx/src/com/android/dx/dex/file/AnnotationItem.java
new file mode 100644
index 0000000..1d92247
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/AnnotationItem.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.rop.annotation.AnnotationVisibility;
+import com.android.dx.rop.annotation.NameValuePair;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Single annotation, which consists of a type and a set of name-value
+ * element pairs.
+ */
+public final class AnnotationItem extends OffsettedItem {
+    /** annotation visibility constant: visible at build time only */
+    private static final int VISIBILITY_BUILD = 0;
+
+    /** annotation visibility constant: visible at runtime */
+    private static final int VISIBILITY_RUNTIME = 1;
+
+    /** annotation visibility constant: visible at runtime only to system */
+    private static final int VISIBILITY_SYSTEM = 2;
+
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 1;
+
+    /** {@code non-null;} unique instance of {@link #TypeIdSorter} */
+    private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
+
+    /** {@code non-null;} the annotation to represent */
+    private final Annotation annotation;
+
+    /**
+     * {@code null-ok;} type reference for the annotation type; set during
+     * {@link #addContents}
+     */
+    private TypeIdItem type;
+
+    /**
+     * {@code null-ok;} encoded form, ready for writing to a file; set during
+     * {@link #place0}
+     */
+    private byte[] encodedForm;
+
+    /**
+     * Comparator that sorts (outer) instances by type id index.
+     */
+    private static class TypeIdSorter implements Comparator<AnnotationItem> {
+        /** {@inheritDoc} */
+        public int compare(AnnotationItem item1, AnnotationItem item2) {
+            int index1 = item1.type.getIndex();
+            int index2 = item2.type.getIndex();
+
+            if (index1 < index2) {
+                return -1;
+            } else if (index1 > index2) {
+                return 1;
+            }
+
+            return 0;
+        }
+    }
+
+    /**
+     * Sorts an array of instances, in place, by type id index,
+     * ignoring all other aspects of the elements. This is only valid
+     * to use after type id indices are known.
+     *
+     * @param array {@code non-null;} array to sort
+     */
+    public static void sortByTypeIdIndex(AnnotationItem[] array) {
+        Arrays.sort(array, TYPE_ID_SORTER);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotation {@code non-null;} annotation to represent
+     */
+    public AnnotationItem(Annotation annotation) {
+        /*
+         * The write size isn't known up-front because (the variable-lengthed)
+         * leb128 type is used to represent some things.
+         */
+        super(ALIGNMENT, -1);
+
+        if (annotation == null) {
+            throw new NullPointerException("annotation == null");
+        }
+
+        this.annotation = annotation;
+        this.type = null;
+        this.encodedForm = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATION_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotation.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        AnnotationItem otherAnnotation = (AnnotationItem) other;
+
+        return annotation.compareTo(otherAnnotation.annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return annotation.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        type = file.getTypeIds().intern(annotation.getType());
+        ValueEncoder.addContents(file, annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+        ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
+
+        encoder.writeAnnotation(annotation, false);
+        encodedForm = out.toByteArray();
+
+        // Add one for the visibility byte in front of the encoded annotation.
+        setWriteSize(encodedForm.length + 1);
+    }
+
+    /**
+     * Write a (listing file) annotation for this instance to the given
+     * output, that consumes no bytes of output. This is for annotating
+     * a reference to this instance at the point of the reference.
+     *
+     * @param out {@code non-null;} where to output to
+     * @param prefix {@code non-null;} prefix for each line of output
+     */
+    public void annotateTo(AnnotatedOutput out, String prefix) {
+        out.annotate(0, prefix + "visibility: " +
+                annotation.getVisibility().toHuman());
+        out.annotate(0, prefix + "type: " + annotation.getType().toHuman());
+
+        for (NameValuePair pair : annotation.getNameValuePairs()) {
+            CstString name = pair.getName();
+            Constant value = pair.getValue();
+
+            out.annotate(0, prefix + name.toHuman() + ": " +
+                    ValueEncoder.constantToHuman(value));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        AnnotationVisibility visibility = annotation.getVisibility();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " annotation");
+            out.annotate(1, "  visibility: VISBILITY_" + visibility);
+        }
+
+        switch (visibility) {
+            case BUILD:   out.writeByte(VISIBILITY_BUILD); break;
+            case RUNTIME: out.writeByte(VISIBILITY_RUNTIME); break;
+            case SYSTEM:  out.writeByte(VISIBILITY_SYSTEM); break;
+            default: {
+                // EMBEDDED shouldn't appear at the top level.
+                throw new RuntimeException("shouldn't happen");
+            }
+        }
+
+        if (annotates) {
+            /*
+             * The output is to be annotated, so redo the work previously
+             * done by place0(), except this time annotations will actually
+             * get emitted.
+             */
+            ValueEncoder encoder = new ValueEncoder(file, out);
+            encoder.writeAnnotation(annotation, true);
+        } else {
+            out.write(encodedForm);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
new file mode 100644
index 0000000..2187700
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * Set of annotations, where no annotation type appears more than once.
+ */
+public final class AnnotationSetItem extends OffsettedItem {
+    /** 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} */
+    private static final int ENTRY_WRITE_SIZE = 4;
+
+    /** {@code non-null;} the set of annotations */
+    private final Annotations annotations;
+
+    /**
+     * {@code non-null;} set of annotations as individual items in an array.
+     * <b>Note:</b> The contents have to get sorted by type id before
+     * writing.
+     */
+    private final AnnotationItem[] items;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} set of annotations
+     */
+    public AnnotationSetItem(Annotations annotations) {
+        super(ALIGNMENT, writeSize(annotations));
+
+        this.annotations = annotations;
+        this.items = new AnnotationItem[annotations.size()];
+
+        int at = 0;
+        for (Annotation a : annotations.getAnnotations()) {
+            items[at] = new AnnotationItem(a);
+            at++;
+        }
+    }
+
+    /**
+     * Gets the write size for the given set.
+     *
+     * @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.
+
+        try {
+            return (annotations.size() * ENTRY_WRITE_SIZE) + 4;
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("list == null");
+        }
+    }
+
+    /**
+     * Gets the underlying annotations of this instance
+     *
+     * @return {@code non-null;} the annotations
+     */
+    public Annotations getAnnotations() {
+        return annotations;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotations.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        AnnotationSetItem otherSet = (AnnotationSetItem) other;
+
+        return annotations.compareTo(otherSet.annotations);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATION_SET_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return annotations.toString();
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection byteData = file.getByteData();
+        int size = items.length;
+
+        for (int i = 0; i < size; i++) {
+            items[i] = byteData.intern(items[i]);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Sort the array to be in type id index order.
+        AnnotationItem.sortByTypeIdIndex(items);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        int size = items.length;
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " annotation set");
+            out.annotate(4, "  size: " + Hex.u4(size));
+        }
+
+        out.writeInt(size);
+
+        for (int i = 0; i < size; i++) {
+            AnnotationItem item = items[i];
+            int offset = item.getAbsoluteOffset();
+
+            if (annotates) {
+                out.annotate(4, "  entries[" + Integer.toHexString(i) + "]: " +
+                        Hex.u4(offset));
+                items[i].annotateTo(out, "    ");
+            }
+
+            out.writeInt(offset);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
new file mode 100644
index 0000000..53072d8
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * Indirect reference to an {@link AnnotationSetItem}.
+ */
+public final class AnnotationSetRefItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of this class, in bytes */
+    private static final int WRITE_SIZE = 4;
+
+    /** {@code non-null;} the annotation set to refer to */
+    private AnnotationSetItem annotations;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotations {@code non-null;} the annotation set to refer to
+     */
+    public AnnotationSetRefItem(AnnotationSetItem annotations) {
+        super(ALIGNMENT, WRITE_SIZE);
+
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.annotations = annotations;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATION_SET_REF_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection wordData = file.getWordData();
+
+        annotations = wordData.intern(annotations);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return annotations.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        int annotationsOff = annotations.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "  annotations_off: " + Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(annotationsOff);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
new file mode 100644
index 0000000..350ed9a
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.rop.annotation.NameValuePair;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstAnnotation;
+import com.android.dx.rop.cst.CstArray;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstKnownNull;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+
+import java.util.ArrayList;
+
+import static com.android.dx.rop.annotation.AnnotationVisibility.*;
+
+/**
+ * Utility class for dealing with annotations.
+ */
+public final class AnnotationUtils {
+    /** {@code non-null;} type for {@code AnnotationDefault} annotations */
+    private static final CstType ANNOTATION_DEFAULT_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
+
+    /** {@code non-null;} type for {@code EnclosingClass} annotations */
+    private static final CstType ENCLOSING_CLASS_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
+
+    /** {@code non-null;} type for {@code EnclosingMethod} annotations */
+    private static final CstType ENCLOSING_METHOD_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
+
+    /** {@code non-null;} type for {@code InnerClass} annotations */
+    private static final CstType INNER_CLASS_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
+
+    /** {@code non-null;} type for {@code MemberClasses} annotations */
+    private static final CstType MEMBER_CLASSES_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
+
+    /** {@code non-null;} type for {@code Signature} annotations */
+    private static final CstType SIGNATURE_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
+
+    /** {@code non-null;} type for {@code Throws} annotations */
+    private static final CstType THROWS_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
+
+    /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
+    private static final CstString ACCESS_FLAGS_STRING = new CstString("accessFlags");
+
+    /** {@code non-null;} the UTF-8 constant {@code "name"} */
+    private static final CstString NAME_STRING = new CstString("name");
+
+    /** {@code non-null;} the UTF-8 constant {@code "value"} */
+    private static final CstString VALUE_STRING = new CstString("value");
+
+    /**
+     * This class is uninstantiable.
+     */
+    private AnnotationUtils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Constructs a standard {@code AnnotationDefault} 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);
+
+        result.put(new NameValuePair(VALUE_STRING, new CstAnnotation(defaults)));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code EnclosingClass} 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);
+
+        result.put(new NameValuePair(VALUE_STRING, clazz));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code EnclosingMethod} 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);
+
+        result.put(new NameValuePair(VALUE_STRING, method));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code InnerClass} annotation.
+     *
+     * @param name {@code null-ok;} the original name of the class, or
+     * {@code null} to represent an anonymous class
+     * @param accessFlags the original access flags
+     * @return {@code non-null;} the annotation
+     */
+    public static Annotation makeInnerClass(CstString name, int accessFlags) {
+        Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
+        Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE;
+
+        result.put(new NameValuePair(NAME_STRING, nameCst));
+        result.put(new NameValuePair(ACCESS_FLAGS_STRING,
+                        CstInteger.make(accessFlags)));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code MemberClasses} annotation.
+     *
+     * @param types {@code non-null;} the list of (the types of) the member classes
+     * @return {@code non-null;} the annotation
+     */
+    public static Annotation makeMemberClasses(TypeList types) {
+        CstArray array = makeCstArray(types);
+        Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM);
+        result.put(new NameValuePair(VALUE_STRING, array));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code Signature} annotation.
+     *
+     * @param signature {@code non-null;} the signature string
+     * @return {@code non-null;} the annotation
+     */
+    public static Annotation makeSignature(CstString signature) {
+        Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM);
+
+        /*
+         * Split the string into pieces that are likely to be common
+         * across many signatures and the rest of the file.
+         */
+
+        String raw = signature.getString();
+        int rawLength = raw.length();
+        ArrayList<String> pieces = new ArrayList<String>(20);
+
+        for (int at = 0; at < rawLength; /*at*/) {
+            char c = raw.charAt(at);
+            int endAt = at + 1;
+            if (c == 'L') {
+                // Scan to ';' or '<'. Consume ';' but not '<'.
+                while (endAt < rawLength) {
+                    c = raw.charAt(endAt);
+                    if (c == ';') {
+                        endAt++;
+                        break;
+                    } else if (c == '<') {
+                        break;
+                    }
+                    endAt++;
+                }
+            } else {
+                // Scan to 'L' without consuming it.
+                while (endAt < rawLength) {
+                    c = raw.charAt(endAt);
+                    if (c == 'L') {
+                        break;
+                    }
+                    endAt++;
+                }
+            }
+
+            pieces.add(raw.substring(at, endAt));
+            at = endAt;
+        }
+
+        int size = pieces.size();
+        CstArray.List list = new CstArray.List(size);
+
+        for (int i = 0; i < size; i++) {
+            list.set(i, new CstString(pieces.get(i)));
+        }
+
+        list.setImmutable();
+
+        result.put(new NameValuePair(VALUE_STRING, new CstArray(list)));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs a standard {@code Throws} 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);
+        Annotation result = new Annotation(THROWS_TYPE, SYSTEM);
+        result.put(new NameValuePair(VALUE_STRING, array));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Converts a {@link TypeList} to a {@link CstArray}.
+     *
+     * @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();
+        CstArray.List list = new CstArray.List(size);
+
+        for (int i = 0; i < size; i++) {
+            list.set(i, CstType.intern(types.getType(i)));
+        }
+
+        list.setImmutable();
+        return new CstArray(list);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
new file mode 100644
index 0000000..972d4e6
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Per-class directory of annotations.
+ */
+public final class AnnotationsDirectoryItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of this class's header, in bytes */
+    private static final int HEADER_SIZE = 16;
+
+    /** write size of a list element, in bytes */
+    private static final int ELEMENT_SIZE = 8;
+
+    /** {@code null-ok;} the class-level annotations, if any */
+    private AnnotationSetItem classAnnotations;
+
+    /** {@code null-ok;} the annotated fields, if any */
+    private ArrayList<FieldAnnotationStruct> fieldAnnotations;
+
+    /** {@code null-ok;} the annotated methods, if any */
+    private ArrayList<MethodAnnotationStruct> methodAnnotations;
+
+    /** {@code null-ok;} the annotated parameters, if any */
+    private ArrayList<ParameterAnnotationStruct> parameterAnnotations;
+
+    /**
+     * Constructs an empty instance.
+     */
+    public AnnotationsDirectoryItem() {
+        super(ALIGNMENT, -1);
+
+        classAnnotations = null;
+        fieldAnnotations = null;
+        methodAnnotations = null;
+        parameterAnnotations = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
+    }
+
+    /**
+     * Returns whether this item is empty (has no contents).
+     *
+     * @return {@code true} if this item is empty, or {@code false}
+     * if not
+     */
+    public boolean isEmpty() {
+        return (classAnnotations == null) &&
+            (fieldAnnotations == null) &&
+            (methodAnnotations == null) &&
+            (parameterAnnotations == null);
+    }
+
+    /**
+     * Returns whether this item is a candidate for interning. The only
+     * interning candidates are ones that <i>only</i> have a non-null
+     * set of class annotations, with no other lists.
+     *
+     * @return {@code true} if this is an interning candidate, or
+     * {@code false} if not
+     */
+    public boolean isInternable() {
+        return (classAnnotations != null) &&
+            (fieldAnnotations == null) &&
+            (methodAnnotations == null) &&
+            (parameterAnnotations == null);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        if (classAnnotations == null) {
+            return 0;
+        }
+
+        return classAnnotations.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b>: This throws an exception if this item is not
+     * internable.</p>
+     *
+     * @see #isInternable
+     */
+    @Override
+    public int compareTo0(OffsettedItem other) {
+        if (! isInternable()) {
+            throw new UnsupportedOperationException("uninternable instance");
+        }
+
+        AnnotationsDirectoryItem otherDirectory =
+            (AnnotationsDirectoryItem) other;
+        return classAnnotations.compareTo(otherDirectory.classAnnotations);
+    }
+
+    /**
+     * Sets the direct annotations on this instance. These are annotations
+     * made on the class, per se, as opposed to on one of its members.
+     * It is only valid to call this method at most once per instance.
+     *
+     * @param annotations {@code non-null;} annotations to set for this class
+     */
+    public void setClassAnnotations(Annotations annotations) {
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        if (classAnnotations != null) {
+            throw new UnsupportedOperationException(
+                    "class annotations already set");
+        }
+
+        classAnnotations = new AnnotationSetItem(annotations);
+    }
+
+    /**
+     * Adds a field annotations item to this instance.
+     *
+     * @param field {@code non-null;} field in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addFieldAnnotations(CstFieldRef field,
+            Annotations annotations) {
+        if (fieldAnnotations == null) {
+            fieldAnnotations = new ArrayList<FieldAnnotationStruct>();
+        }
+
+        fieldAnnotations.add(new FieldAnnotationStruct(field,
+                        new AnnotationSetItem(annotations)));
+    }
+
+    /**
+     * Adds a method annotations item to this instance.
+     *
+     * @param method {@code non-null;} method in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addMethodAnnotations(CstMethodRef method,
+            Annotations annotations) {
+        if (methodAnnotations == null) {
+            methodAnnotations = new ArrayList<MethodAnnotationStruct>();
+        }
+
+        methodAnnotations.add(new MethodAnnotationStruct(method,
+                        new AnnotationSetItem(annotations)));
+    }
+
+    /**
+     * Adds a parameter annotations item to this instance.
+     *
+     * @param method {@code non-null;} method in question
+     * @param list {@code non-null;} associated list of annotation sets to add
+     */
+    public void addParameterAnnotations(CstMethodRef method,
+            AnnotationsList list) {
+        if (parameterAnnotations == null) {
+            parameterAnnotations = new ArrayList<ParameterAnnotationStruct>();
+        }
+
+        parameterAnnotations.add(new ParameterAnnotationStruct(method, list));
+    }
+
+    /**
+     * Gets the method annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the method annotations, if any
+     */
+    public Annotations getMethodAnnotations(CstMethodRef method) {
+        if (methodAnnotations == null) {
+            return null;
+        }
+
+        for (MethodAnnotationStruct item : methodAnnotations) {
+            if (item.getMethod().equals(method)) {
+                return item.getAnnotations();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets the parameter annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the parameter annotations, if any
+     */
+    public AnnotationsList getParameterAnnotations(CstMethodRef method) {
+        if (parameterAnnotations == null) {
+            return null;
+        }
+
+        for (ParameterAnnotationStruct item : parameterAnnotations) {
+            if (item.getMethod().equals(method)) {
+                return item.getAnnotationsList();
+            }
+        }
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection wordData = file.getWordData();
+
+        if (classAnnotations != null) {
+            classAnnotations = wordData.intern(classAnnotations);
+        }
+
+        if (fieldAnnotations != null) {
+            for (FieldAnnotationStruct item : fieldAnnotations) {
+                item.addContents(file);
+            }
+        }
+
+        if (methodAnnotations != null) {
+            for (MethodAnnotationStruct item : methodAnnotations) {
+                item.addContents(file);
+            }
+        }
+
+        if (parameterAnnotations != null) {
+            for (ParameterAnnotationStruct item : parameterAnnotations) {
+                item.addContents(file);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // We just need to set the write size here.
+
+        int elementCount = listSize(fieldAnnotations)
+            + listSize(methodAnnotations) + listSize(parameterAnnotations);
+        setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations);
+        int fieldsSize = listSize(fieldAnnotations);
+        int methodsSize = listSize(methodAnnotations);
+        int parametersSize = listSize(parameterAnnotations);
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " annotations directory");
+            out.annotate(4, "  class_annotations_off: " + Hex.u4(classOff));
+            out.annotate(4, "  fields_size:           " +
+                    Hex.u4(fieldsSize));
+            out.annotate(4, "  methods_size:          " +
+                    Hex.u4(methodsSize));
+            out.annotate(4, "  parameters_size:       " +
+                    Hex.u4(parametersSize));
+        }
+
+        out.writeInt(classOff);
+        out.writeInt(fieldsSize);
+        out.writeInt(methodsSize);
+        out.writeInt(parametersSize);
+
+        if (fieldsSize != 0) {
+            Collections.sort(fieldAnnotations);
+            if (annotates) {
+                out.annotate(0, "  fields:");
+            }
+            for (FieldAnnotationStruct item : fieldAnnotations) {
+                item.writeTo(file, out);
+            }
+        }
+
+        if (methodsSize != 0) {
+            Collections.sort(methodAnnotations);
+            if (annotates) {
+                out.annotate(0, "  methods:");
+            }
+            for (MethodAnnotationStruct item : methodAnnotations) {
+                item.writeTo(file, out);
+            }
+        }
+
+        if (parametersSize != 0) {
+            Collections.sort(parameterAnnotations);
+            if (annotates) {
+                out.annotate(0, "  parameters:");
+            }
+            for (ParameterAnnotationStruct item : parameterAnnotations) {
+                item.writeTo(file, out);
+            }
+        }
+    }
+
+    /**
+     * Gets the list size of the given list, or {@code 0} if given
+     * {@code null}.
+     *
+     * @param list {@code null-ok;} the list in question
+     * @return {@code >= 0;} its size
+     */
+    private static int listSize(ArrayList<?> list) {
+        if (list == null) {
+            return 0;
+        }
+
+        return list.size();
+    }
+
+    /**
+     * Prints out the contents of this instance, in a debugging-friendly
+     * way. This is meant to be called from {@link ClassDefItem#debugPrint}.
+     *
+     * @param out {@code non-null;} where to output to
+     */
+    /*package*/ void debugPrint(PrintWriter out) {
+        if (classAnnotations != null) {
+            out.println("  class annotations: " + classAnnotations);
+        }
+
+        if (fieldAnnotations != null) {
+            out.println("  field annotations:");
+            for (FieldAnnotationStruct item : fieldAnnotations) {
+                out.println("    " + item.toHuman());
+            }
+        }
+
+        if (methodAnnotations != null) {
+            out.println("  method annotations:");
+            for (MethodAnnotationStruct item : methodAnnotations) {
+                out.println("    " + item.toHuman());
+            }
+        }
+
+        if (parameterAnnotations != null) {
+            out.println("  parameter annotations:");
+            for (ParameterAnnotationStruct item : parameterAnnotations) {
+                out.println("    " + item.toHuman());
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/CatchStructs.java b/dx/src/com/android/dx/dex/file/CatchStructs.java
new file mode 100644
index 0000000..8b0f1bd
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/CatchStructs.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.code.CatchHandlerList;
+import com.android.dx.dex.code.CatchTable;
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * 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[]} and a
+ * {@code catch_handler_item[]}.
+ */
+public final class CatchStructs {
+    /**
+     * 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);
+
+    /** {@code non-null;} code that contains the catches */
+    private final DalvCode code;
+
+    /**
+     * {@code null-ok;} the underlying table; set in
+     * {@link #finishProcessingIfNecessary}
+     */
+    private CatchTable table;
+
+    /**
+     * {@code null-ok;} the encoded handler list, if calculated; set in
+     * {@link #encode}
+     */
+    private byte[] encodedHandlers;
+
+    /**
+     * length of the handlers header (encoded size), if known; used for
+     * annotation
+     */
+    private int encodedHandlerHeaderSize;
+
+    /**
+     * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
+     * {@link #encode}
+     */
+    private TreeMap<CatchHandlerList, Integer> handlerOffsets;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param code {@code non-null;} code that contains the catches
+     */
+    public CatchStructs(DalvCode code) {
+        this.code = code;
+        this.table = null;
+        this.encodedHandlers = null;
+        this.encodedHandlerHeaderSize = 0;
+        this.handlerOffsets = null;
+    }
+
+    /**
+     * Finish processing the catches, if necessary.
+     */
+    private void finishProcessingIfNecessary() {
+        if (table == null) {
+            table = code.getCatches();
+        }
+    }
+
+    /**
+     * Gets the size of the tries list, in entries.
+     *
+     * @return {@code >= 0;} the tries list size
+     */
+    public int triesSize() {
+        finishProcessingIfNecessary();
+        return table.size();
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     */
+    public void debugPrint(PrintWriter out, String prefix) {
+        annotateEntries(prefix, out, null);
+    }
+
+    /**
+     * Encodes the handler lists.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     */
+    public void encode(DexFile file) {
+        finishProcessingIfNecessary();
+
+        TypeIdsSection typeIds = file.getTypeIds();
+        int size = table.size();
+
+        handlerOffsets = new TreeMap<CatchHandlerList, Integer>();
+
+        /*
+         * First add a map entry for each unique list. The tree structure
+         * will ensure they are sorted when we reiterate later.
+         */
+        for (int i = 0; i < size; i++) {
+            handlerOffsets.put(table.get(i).getHandlers(), null);
+        }
+
+        if (handlerOffsets.size() > 65535) {
+            throw new UnsupportedOperationException(
+                    "too many catch handlers");
+        }
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+
+        // Write out the handlers "header" consisting of its size in entries.
+        encodedHandlerHeaderSize =
+            out.writeUleb128(handlerOffsets.size());
+
+        // Now write the lists out in order, noting the offset of each.
+        for (Map.Entry<CatchHandlerList, Integer> mapping :
+                 handlerOffsets.entrySet()) {
+            CatchHandlerList list = mapping.getKey();
+            int listSize = list.size();
+            boolean catchesAll = list.catchesAll();
+
+            // Set the offset before we do any writing.
+            mapping.setValue(out.getCursor());
+
+            if (catchesAll) {
+                // A size <= 0 means that the list ends with a catch-all.
+                out.writeSleb128(-(listSize - 1));
+                listSize--;
+            } else {
+                out.writeSleb128(listSize);
+            }
+
+            for (int i = 0; i < listSize; i++) {
+                CatchHandlerList.Entry entry = list.get(i);
+                out.writeUleb128(
+                        typeIds.indexOf(entry.getExceptionType()));
+                out.writeUleb128(entry.getHandler());
+            }
+
+            if (catchesAll) {
+                out.writeUleb128(list.get(listSize).getHandler());
+            }
+        }
+
+        encodedHandlers = out.toByteArray();
+    }
+
+    /**
+     * Gets the write size of this instance, in bytes.
+     *
+     * @return {@code >= 0;} the write size
+     */
+    public int writeSize() {
+        return (triesSize() * TRY_ITEM_WRITE_SIZE) +
+                + encodedHandlers.length;
+    }
+
+    /**
+     * Writes this instance to the given stream.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        finishProcessingIfNecessary();
+
+        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();
+            int end = one.getEnd();
+            int insnCount = end - start;
+
+            if (insnCount >= 65536) {
+                throw new UnsupportedOperationException(
+                        "bogus exception range: " + Hex.u4(start) + ".." +
+                        Hex.u4(end));
+            }
+
+            out.writeInt(start);
+            out.writeShort(insnCount);
+            out.writeShort(handlerOffsets.get(one.getHandlers()));
+        }
+
+        out.write(encodedHandlers);
+    }
+
+    /**
+     * Helper method to annotate or simply print the exception handlers.
+     * Only one of {@code printTo} or {@code annotateTo} should
+     * be non-null.
+     *
+     * @param prefix {@code non-null;} prefix for each line
+     * @param printTo {@code null-ok;} where to print to
+     * @param annotateTo {@code null-ok;} where to consume bytes and annotate to
+     */
+    private void annotateEntries(String prefix, PrintWriter printTo,
+            AnnotatedOutput annotateTo) {
+        finishProcessingIfNecessary();
+
+        boolean consume = (annotateTo != null);
+        int amt1 = consume ? 6 : 0;
+        int amt2 = consume ? 2 : 0;
+        int size = table.size();
+        String subPrefix = prefix + "  ";
+
+        if (consume) {
+            annotateTo.annotate(0, prefix + "tries:");
+        } else {
+            printTo.println(prefix + "tries:");
+        }
+
+        for (int i = 0; i < size; i++) {
+            CatchTable.Entry entry = table.get(i);
+            CatchHandlerList handlers = entry.getHandlers();
+            String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart())
+                + ".." + Hex.u2or4(entry.getEnd());
+            String s2 = handlers.toHuman(subPrefix, "");
+
+            if (consume) {
+                annotateTo.annotate(amt1, s1);
+                annotateTo.annotate(amt2, s2);
+            } else {
+                printTo.println(s1);
+                printTo.println(s2);
+            }
+        }
+
+        if (! consume) {
+            // Only emit the handler lists if we are consuming bytes.
+            return;
+        }
+
+        annotateTo.annotate(0, prefix + "handlers:");
+        annotateTo.annotate(encodedHandlerHeaderSize,
+                subPrefix + "size: " + Hex.u2(handlerOffsets.size()));
+
+        int lastOffset = 0;
+        CatchHandlerList lastList = null;
+
+        for (Map.Entry<CatchHandlerList, Integer> mapping :
+                 handlerOffsets.entrySet()) {
+            CatchHandlerList list = mapping.getKey();
+            int offset = mapping.getValue();
+
+            if (lastList != null) {
+                annotateAndConsumeHandlers(lastList, lastOffset,
+                        offset - lastOffset, subPrefix, printTo, annotateTo);
+            }
+
+            lastList = list;
+            lastOffset = offset;
+        }
+
+        annotateAndConsumeHandlers(lastList, lastOffset,
+                encodedHandlers.length - lastOffset,
+                subPrefix, printTo, annotateTo);
+    }
+
+    /**
+     * Helper for {@link #annotateEntries} to annotate a catch handler list
+     * while consuming it.
+     *
+     * @param handlers {@code non-null;} handlers to annotate
+     * @param offset {@code >= 0;} the offset of this handler
+     * @param size {@code >= 1;} the number of bytes the handlers consume
+     * @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,
+            AnnotatedOutput annotateTo) {
+        String s = handlers.toHuman(prefix, Hex.u2(offset) + ": ");
+
+        if (printTo != null) {
+            printTo.println(s);
+        }
+
+        annotateTo.annotate(size, s);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/ClassDataItem.java b/dx/src/com/android/dx/dex/file/ClassDataItem.java
new file mode 100644
index 0000000..e9ae18b
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ClassDataItem.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstArray;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.Zeroes;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Writers;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+
+/**
+ * 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} file, as opposed to a random-access form.
+ */
+public final class ClassDataItem extends OffsettedItem {
+    /** {@code non-null;} what class this data is for, just for listing generation */
+    private final CstType thisClass;
+
+    /** {@code non-null;} list of static fields */
+    private final ArrayList<EncodedField> staticFields;
+
+    /** {@code non-null;} list of initial values for static fields */
+    private final HashMap<EncodedField, Constant> staticValues;
+
+    /** {@code non-null;} list of instance fields */
+    private final ArrayList<EncodedField> instanceFields;
+
+    /** {@code non-null;} list of direct methods */
+    private final ArrayList<EncodedMethod> directMethods;
+
+    /** {@code non-null;} list of virtual methods */
+    private final ArrayList<EncodedMethod> virtualMethods;
+
+    /** {@code null-ok;} static initializer list; set in {@link #addContents} */
+    private CstArray staticValuesConstant;
+
+    /**
+     * {@code null-ok;} encoded form, ready for writing to a file; set during
+     * {@link #place0}
+     */
+    private byte[] encodedForm;
+
+    /**
+     * Constructs an instance. Its sets of members are initially
+     * empty.
+     *
+     * @param thisClass {@code non-null;} what class this data is for, just
+     * for listing generation
+     */
+    public ClassDataItem(CstType thisClass) {
+        super(1, -1);
+
+        if (thisClass == null) {
+            throw new NullPointerException("thisClass == null");
+        }
+
+        this.thisClass = thisClass;
+        this.staticFields = new ArrayList<EncodedField>(20);
+        this.staticValues = new HashMap<EncodedField, Constant>(40);
+        this.instanceFields = new ArrayList<EncodedField>(20);
+        this.directMethods = new ArrayList<EncodedMethod>(20);
+        this.virtualMethods = new ArrayList<EncodedMethod>(20);
+        this.staticValuesConstant = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_CLASS_DATA_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return toString();
+    }
+
+    /**
+     * Returns whether this instance is empty.
+     *
+     * @return {@code true} if this instance is empty or
+     * {@code false} if at least one element has been added to it
+     */
+    public boolean isEmpty() {
+        return staticFields.isEmpty() && instanceFields.isEmpty()
+            && directMethods.isEmpty() && virtualMethods.isEmpty();
+    }
+
+    /**
+     * Adds a static field.
+     *
+     * @param field {@code non-null;} the field to add
+     * @param value {@code null-ok;} initial value for the field, if any
+     */
+    public void addStaticField(EncodedField field, Constant value) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        if (staticValuesConstant != null) {
+            throw new UnsupportedOperationException(
+                    "static fields already sorted");
+        }
+
+        staticFields.add(field);
+        staticValues.put(field, value);
+    }
+
+    /**
+     * Adds an instance field.
+     *
+     * @param field {@code non-null;} the field to add
+     */
+    public void addInstanceField(EncodedField field) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        instanceFields.add(field);
+    }
+
+    /**
+     * Adds a direct ({@code static} and/or {@code private}) method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addDirectMethod(EncodedMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        directMethods.add(method);
+    }
+
+    /**
+     * Adds a virtual method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addVirtualMethod(EncodedMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        virtualMethods.add(method);
+    }
+
+    /**
+     * Gets all the methods in this class. The returned list is not linked
+     * in any way to the underlying lists contained in this instance, but
+     * the objects contained in the list are shared.
+     *
+     * @return {@code non-null;} list of all methods
+     */
+    public ArrayList<EncodedMethod> getMethods() {
+        int sz = directMethods.size() + virtualMethods.size();
+        ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz);
+
+        result.addAll(directMethods);
+        result.addAll(virtualMethods);
+
+        return result;
+    }
+
+
+    /**
+     * Prints out the contents of this instance, in a debugging-friendly
+     * way.
+     *
+     * @param out {@code non-null;} where to output to
+     * @param verbose whether to be verbose with the output
+     */
+    public void debugPrint(Writer out, boolean verbose) {
+        PrintWriter pw = Writers.printWriterFor(out);
+
+        int sz = staticFields.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  sfields[" + i + "]: " + staticFields.get(i));
+        }
+
+        sz = instanceFields.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  ifields[" + i + "]: " + instanceFields.get(i));
+        }
+
+        sz = directMethods.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  dmeths[" + i + "]:");
+            directMethods.get(i).debugPrint(pw, verbose);
+        }
+
+        sz = virtualMethods.size();
+        for (int i = 0; i < sz; i++) {
+            pw.println("  vmeths[" + i + "]:");
+            virtualMethods.get(i).debugPrint(pw, verbose);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        if (!staticFields.isEmpty()) {
+            getStaticValuesConstant(); // Force the fields to be sorted.
+            for (EncodedField field : staticFields) {
+                field.addContents(file);
+            }
+        }
+
+        if (!instanceFields.isEmpty()) {
+            Collections.sort(instanceFields);
+            for (EncodedField field : instanceFields) {
+                field.addContents(file);
+            }
+        }
+
+        if (!directMethods.isEmpty()) {
+            Collections.sort(directMethods);
+            for (EncodedMethod method : directMethods) {
+                method.addContents(file);
+            }
+        }
+
+        if (!virtualMethods.isEmpty()) {
+            Collections.sort(virtualMethods);
+            for (EncodedMethod method : virtualMethods) {
+                method.addContents(file);
+            }
+        }
+    }
+
+    /**
+     * Gets a {@link CstArray} corresponding to {@link #staticValues} if
+     * it contains any non-zero non-{@code null} values.
+     *
+     * @return {@code null-ok;} the corresponding constant or {@code null} if
+     * there are no values to encode
+     */
+    public CstArray getStaticValuesConstant() {
+        if ((staticValuesConstant == null) && (staticFields.size() != 0)) {
+            staticValuesConstant = makeStaticValuesConstant();
+        }
+
+        return staticValuesConstant;
+    }
+
+    /**
+     * Gets a {@link CstArray} corresponding to {@link #staticValues} if
+     * it contains any non-zero non-{@code null} values.
+     *
+     * @return {@code null-ok;} the corresponding constant or {@code null} if
+     * there are no values to encode
+     */
+    private CstArray makeStaticValuesConstant() {
+        // First sort the statics into their final order.
+        Collections.sort(staticFields);
+
+        /*
+         * Get the size of staticValues minus any trailing zeros/nulls (both
+         * nulls per se as well as instances of CstKnownNull).
+         */
+
+        int size = staticFields.size();
+        while (size > 0) {
+            EncodedField field = staticFields.get(size - 1);
+            Constant cst = staticValues.get(field);
+            if (cst instanceof CstLiteralBits) {
+                // Note: CstKnownNull extends CstLiteralBits.
+                if (((CstLiteralBits) cst).getLongBits() != 0) {
+                    break;
+                }
+            } else if (cst != null) {
+                break;
+            }
+            size--;
+        }
+
+        if (size == 0) {
+            return null;
+        }
+
+        // There is something worth encoding, so build up a result.
+
+        CstArray.List list = new CstArray.List(size);
+        for (int i = 0; i < size; i++) {
+            EncodedField field = staticFields.get(i);
+            Constant cst = staticValues.get(field);
+            if (cst == null) {
+                cst = Zeroes.zeroFor(field.getRef().getType());
+            }
+            list.set(i, cst);
+        }
+        list.setImmutable();
+
+        return new CstArray(list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+
+        encodeOutput(addedTo.getFile(), out);
+        encodedForm = out.toByteArray();
+        setWriteSize(encodedForm.length);
+    }
+
+    /**
+     * Writes out the encoded form of this instance.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     */
+    private void encodeOutput(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " class data for " +
+                    thisClass.toHuman());
+        }
+
+        encodeSize(file, out, "static_fields", staticFields.size());
+        encodeSize(file, out, "instance_fields", instanceFields.size());
+        encodeSize(file, out, "direct_methods", directMethods.size());
+        encodeSize(file, out, "virtual_methods", virtualMethods.size());
+
+        encodeList(file, out, "static_fields", staticFields);
+        encodeList(file, out, "instance_fields", instanceFields);
+        encodeList(file, out, "direct_methods", directMethods);
+        encodeList(file, out, "virtual_methods", virtualMethods);
+
+        if (annotates) {
+            out.endAnnotation();
+        }
+    }
+
+    /**
+     * Helper for {@link #encodeOutput}, which writes out the given
+     * size value, annotating it as well (if annotations are enabled).
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     * @param label {@code non-null;} the label for the purposes of annotation
+     * @param size {@code >= 0;} the size to write
+     */
+    private static void encodeSize(DexFile file, AnnotatedOutput out,
+            String label, int size) {
+        if (out.annotates()) {
+            out.annotate(String.format("  %-21s %08x", label + "_size:",
+                            size));
+        }
+
+        out.writeUleb128(size);
+    }
+
+    /**
+     * Helper for {@link #encodeOutput}, which writes out the given
+     * list. It also annotates the items (if any and if annotations
+     * are enabled).
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     * @param label {@code non-null;} the label for the purposes of annotation
+     * @param list {@code non-null;} the list in question
+     */
+    private static void encodeList(DexFile file, AnnotatedOutput out,
+            String label, ArrayList<? extends EncodedMember> list) {
+        int size = list.size();
+        int lastIndex = 0;
+
+        if (size == 0) {
+            return;
+        }
+
+        if (out.annotates()) {
+            out.annotate(0, "  " + label + ":");
+        }
+
+        for (int i = 0; i < size; i++) {
+            lastIndex = list.get(i).encode(file, out, lastIndex, i);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+
+        if (annotates) {
+            /*
+             * The output is to be annotated, so redo the work previously
+             * done by place0(), except this time annotations will actually
+             * get emitted.
+             */
+            encodeOutput(file, out);
+        } else {
+            out.write(encodedForm);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/ClassDefItem.java b/dx/src/com/android/dx/dex/file/ClassDefItem.java
new file mode 100644
index 0000000..df3945a
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ClassDefItem.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.SizeOf;
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstArray;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.Writers;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+
+/**
+ * Representation of a Dalvik class, which is basically a set of
+ * members (fields or methods) along with a few more pieces of
+ * information.
+ */
+public final class ClassDefItem extends IndexedItem {
+
+    /** {@code non-null;} type constant for this class */
+    private final CstType thisClass;
+
+    /** access flags */
+    private final int accessFlags;
+
+    /**
+     * {@code null-ok;} superclass or {@code null} if this class is a/the
+     * root class
+     */
+    private final CstType superclass;
+
+    /** {@code null-ok;} list of implemented interfaces */
+    private TypeListItem interfaces;
+
+    /** {@code null-ok;} source file name or {@code null} if unknown */
+    private final CstString sourceFile;
+
+    /** {@code non-null;} associated class data object */
+    private final ClassDataItem classData;
+
+    /**
+     * {@code null-ok;} item wrapper for the static values, initialized
+     * in {@link #addContents}
+     */
+    private EncodedArrayItem staticValuesItem;
+
+    /** {@code non-null;} annotations directory */
+    private AnnotationsDirectoryItem annotationsDirectory;
+
+    /**
+     * Constructs an instance. Its sets of members and annotations are
+     * initially empty.
+     *
+     * @param thisClass {@code non-null;} type constant for this class
+     * @param accessFlags access flags
+     * @param superclass {@code null-ok;} superclass or {@code null} if
+     * this class is a/the root class
+     * @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, CstString sourceFile) {
+        if (thisClass == null) {
+            throw new NullPointerException("thisClass == null");
+        }
+
+        /*
+         * TODO: Maybe check accessFlags and superclass, at
+         * least for easily-checked stuff?
+         */
+
+        if (interfaces == null) {
+            throw new NullPointerException("interfaces == null");
+        }
+
+        this.thisClass = thisClass;
+        this.accessFlags = accessFlags;
+        this.superclass = superclass;
+        this.interfaces =
+            (interfaces.size() == 0) ? null :  new TypeListItem(interfaces);
+        this.sourceFile = sourceFile;
+        this.classData = new ClassDataItem(thisClass);
+        this.staticValuesItem = null;
+        this.annotationsDirectory = new AnnotationsDirectoryItem();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_CLASS_DEF_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return SizeOf.CLASS_DEF_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        MixedItemSection byteData = file.getByteData();
+        MixedItemSection wordData = file.getWordData();
+        MixedItemSection typeLists = file.getTypeLists();
+        StringIdsSection stringIds = file.getStringIds();
+
+        typeIds.intern(thisClass);
+
+        if (!classData.isEmpty()) {
+            MixedItemSection classDataSection = file.getClassData();
+            classDataSection.add(classData);
+
+            CstArray staticValues = classData.getStaticValuesConstant();
+            if (staticValues != null) {
+                staticValuesItem =
+                    byteData.intern(new EncodedArrayItem(staticValues));
+            }
+        }
+
+        if (superclass != null) {
+            typeIds.intern(superclass);
+        }
+
+        if (interfaces != null) {
+            interfaces = typeLists.intern(interfaces);
+        }
+
+        if (sourceFile != null) {
+            stringIds.intern(sourceFile);
+        }
+
+        if (! annotationsDirectory.isEmpty()) {
+            if (annotationsDirectory.isInternable()) {
+                annotationsDirectory = wordData.intern(annotationsDirectory);
+            } else {
+                wordData.add(annotationsDirectory);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        TypeIdsSection typeIds = file.getTypeIds();
+        int classIdx = typeIds.indexOf(thisClass);
+        int superIdx = (superclass == null) ? -1 :
+            typeIds.indexOf(superclass);
+        int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces);
+        int annoOff = annotationsDirectory.isEmpty() ? 0 :
+            annotationsDirectory.getAbsoluteOffset();
+        int sourceFileIdx = (sourceFile == null) ? -1 :
+            file.getStringIds().indexOf(sourceFile);
+        int dataOff = classData.isEmpty()? 0 : classData.getAbsoluteOffset();
+        int staticValuesOff =
+            OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem);
+
+        if (annotates) {
+            out.annotate(0, indexString() + ' ' + thisClass.toHuman());
+            out.annotate(4, "  class_idx:           " + Hex.u4(classIdx));
+            out.annotate(4, "  access_flags:        " +
+                         AccessFlags.classString(accessFlags));
+            out.annotate(4, "  superclass_idx:      " + Hex.u4(superIdx) +
+                         " // " + ((superclass == null) ? "<none>" :
+                          superclass.toHuman()));
+            out.annotate(4, "  interfaces_off:      " + Hex.u4(interOff));
+            if (interOff != 0) {
+                TypeList list = interfaces.getList();
+                int sz = list.size();
+                for (int i = 0; i < sz; i++) {
+                    out.annotate(0, "    " + list.getType(i).toHuman());
+                }
+            }
+            out.annotate(4, "  source_file_idx:     " + Hex.u4(sourceFileIdx) +
+                         " // " + ((sourceFile == null) ? "<none>" :
+                          sourceFile.toHuman()));
+            out.annotate(4, "  annotations_off:     " + Hex.u4(annoOff));
+            out.annotate(4, "  class_data_off:      " + Hex.u4(dataOff));
+            out.annotate(4, "  static_values_off:   " +
+                    Hex.u4(staticValuesOff));
+        }
+
+        out.writeInt(classIdx);
+        out.writeInt(accessFlags);
+        out.writeInt(superIdx);
+        out.writeInt(interOff);
+        out.writeInt(sourceFileIdx);
+        out.writeInt(annoOff);
+        out.writeInt(dataOff);
+        out.writeInt(staticValuesOff);
+    }
+
+    /**
+     * Gets the constant corresponding to this class.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstType getThisClass() {
+        return thisClass;
+    }
+
+    /**
+     * Gets the access flags.
+     *
+     * @return the access flags
+     */
+    public int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /**
+     * Gets the superclass.
+     *
+     * @return {@code null-ok;} the superclass or {@code null} if
+     * this class is a/the root class
+     */
+    public CstType getSuperclass() {
+        return superclass;
+    }
+
+    /**
+     * Gets the list of interfaces implemented.
+     *
+     * @return {@code non-null;} the interfaces list
+     */
+    public TypeList getInterfaces() {
+        if (interfaces == null) {
+            return StdTypeList.EMPTY;
+        }
+
+        return interfaces.getList();
+    }
+
+    /**
+     * Gets the source file name.
+     *
+     * @return {@code null-ok;} the source file name or {@code null} if unknown
+     */
+    public CstString getSourceFile() {
+        return sourceFile;
+    }
+
+    /**
+     * Adds a static field.
+     *
+     * @param field {@code non-null;} the field to add
+     * @param value {@code null-ok;} initial value for the field, if any
+     */
+    public void addStaticField(EncodedField field, Constant value) {
+        classData.addStaticField(field, value);
+    }
+
+    /**
+     * Adds an instance field.
+     *
+     * @param field {@code non-null;} the field to add
+     */
+    public void addInstanceField(EncodedField field) {
+        classData.addInstanceField(field);
+    }
+
+    /**
+     * Adds a direct ({@code static} and/or {@code private}) method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addDirectMethod(EncodedMethod method) {
+        classData.addDirectMethod(method);
+    }
+
+    /**
+     * Adds a virtual method.
+     *
+     * @param method {@code non-null;} the method to add
+     */
+    public void addVirtualMethod(EncodedMethod method) {
+        classData.addVirtualMethod(method);
+    }
+
+    /**
+     * Gets all the methods in this class. The returned list is not linked
+     * in any way to the underlying lists contained in this instance, but
+     * the objects contained in the list are shared.
+     *
+     * @return {@code non-null;} list of all methods
+     */
+    public ArrayList<EncodedMethod> getMethods() {
+        return classData.getMethods();
+    }
+
+    /**
+     * Sets the direct annotations on this class. These are annotations
+     * made on the class, per se, as opposed to on one of its members.
+     * It is only valid to call this method at most once per instance.
+     *
+     * @param annotations {@code non-null;} annotations to set for this class
+     */
+    public void setClassAnnotations(Annotations annotations) {
+        annotationsDirectory.setClassAnnotations(annotations);
+    }
+
+    /**
+     * Adds a field annotations item to this class.
+     *
+     * @param field {@code non-null;} field in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addFieldAnnotations(CstFieldRef field,
+            Annotations annotations) {
+        annotationsDirectory.addFieldAnnotations(field, annotations);
+    }
+
+    /**
+     * Adds a method annotations item to this class.
+     *
+     * @param method {@code non-null;} method in question
+     * @param annotations {@code non-null;} associated annotations to add
+     */
+    public void addMethodAnnotations(CstMethodRef method,
+            Annotations annotations) {
+        annotationsDirectory.addMethodAnnotations(method, annotations);
+    }
+
+    /**
+     * Adds a parameter annotations item to this class.
+     *
+     * @param method {@code non-null;} method in question
+     * @param list {@code non-null;} associated list of annotation sets to add
+     */
+    public void addParameterAnnotations(CstMethodRef method,
+            AnnotationsList list) {
+        annotationsDirectory.addParameterAnnotations(method, list);
+    }
+
+    /**
+     * Gets the method annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the method annotations, if any
+     */
+    public Annotations getMethodAnnotations(CstMethodRef method) {
+        return annotationsDirectory.getMethodAnnotations(method);
+    }
+
+    /**
+     * Gets the parameter annotations for a given method, if any. This is
+     * meant for use by debugging / dumping code.
+     *
+     * @param method {@code non-null;} the method
+     * @return {@code null-ok;} the parameter annotations, if any
+     */
+    public AnnotationsList getParameterAnnotations(CstMethodRef method) {
+        return annotationsDirectory.getParameterAnnotations(method);
+    }
+
+    /**
+     * Prints out the contents of this instance, in a debugging-friendly
+     * way.
+     *
+     * @param out {@code non-null;} where to output to
+     * @param verbose whether to be verbose with the output
+     */
+    public void debugPrint(Writer out, boolean verbose) {
+        PrintWriter pw = Writers.printWriterFor(out);
+
+        pw.println(getClass().getName() + " {");
+        pw.println("  accessFlags: " + Hex.u2(accessFlags));
+        pw.println("  superclass: " + superclass);
+        pw.println("  interfaces: " +
+                ((interfaces == null) ? "<none>" : interfaces));
+        pw.println("  sourceFile: " +
+                ((sourceFile == null) ? "<none>" : sourceFile.toQuoted()));
+
+        classData.debugPrint(out, verbose);
+        annotationsDirectory.debugPrint(pw);
+
+        pw.println("}");
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/ClassDefsSection.java b/dx/src/com/android/dx/dex/file/ClassDefsSection.java
new file mode 100644
index 0000000..1ca391f
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ClassDefsSection.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Class definitions list section of a {@code .dex} file.
+ */
+public final class ClassDefsSection extends UniformItemSection {
+    /**
+     * {@code non-null;} map from type constants for classes to {@link
+     * ClassDefItem} instances that define those classes
+     */
+    private final TreeMap<Type, ClassDefItem> classDefs;
+
+    /** {@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 {@code non-null;} file that this instance is part of
+     */
+    public ClassDefsSection(DexFile file) {
+        super("class_defs", file, 4);
+
+        classDefs = new TreeMap<Type, ClassDefItem>();
+        orderedDefs = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        if (orderedDefs != null) {
+            return orderedDefs;
+        }
+
+        return classDefs.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        Type type = ((CstType) cst).getClassType();
+        IndexedItem result = classDefs.get(type);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = classDefs.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "class_defs_size: " + Hex.u4(sz));
+            out.annotate(4, "class_defs_off:  " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Adds an element to this instance. It is illegal to attempt to add more
+     * than one class with the same name.
+     *
+     * @param clazz {@code non-null;} the class def to add
+     */
+    public void add(ClassDefItem clazz) {
+        Type type;
+
+        try {
+            type = clazz.getThisClass().getClassType();
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("clazz == null");
+        }
+
+        throwIfPrepared();
+
+        if (classDefs.get(type) != null) {
+            throw new IllegalArgumentException("already added: " + type);
+        }
+
+        classDefs.put(type, clazz);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int sz = classDefs.size();
+        int idx = 0;
+
+        orderedDefs = new ArrayList<ClassDefItem>(sz);
+
+        /*
+         * Iterate over all the classes, recursively assigning an
+         * index to each, implicitly skipping the ones that have
+         * already been assigned by the time this (top-level)
+         * iteration reaches them.
+         */
+        for (Type type : classDefs.keySet()) {
+            idx = orderItems0(type, idx, sz - idx);
+        }
+    }
+
+    /**
+     * Helper for {@link #orderItems}, which recursively assigns indices
+     * to classes.
+     *
+     * @param type {@code null-ok;} type ref to assign, if any
+     * @param idx {@code >= 0;} the next index to assign
+     * @param maxDepth maximum recursion depth; if negative, this will
+     * throw an exception indicating class definition circularity
+     * @return {@code >= 0;} the next index to assign
+     */
+    private int orderItems0(Type type, int idx, int maxDepth) {
+        ClassDefItem c = classDefs.get(type);
+
+        if ((c == null) || (c.hasIndex())) {
+            return idx;
+        }
+
+        if (maxDepth < 0) {
+            throw new RuntimeException("class circularity with " + type);
+        }
+
+        maxDepth--;
+
+        CstType superclassCst = c.getSuperclass();
+        if (superclassCst != null) {
+            Type superclass = superclassCst.getClassType();
+            idx = orderItems0(superclass, idx, maxDepth);
+        }
+
+        TypeList interfaces = c.getInterfaces();
+        int sz = interfaces.size();
+        for (int i = 0; i < sz; i++) {
+            idx = orderItems0(interfaces.getType(i), idx, maxDepth);
+        }
+
+        c.setIndex(idx);
+        orderedDefs.add(c);
+        return idx + 1;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/CodeItem.java b/dx/src/com/android/dx/dex/file/CodeItem.java
new file mode 100644
index 0000000..a47f68a
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/CodeItem.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.code.CstInsn;
+import com.android.dx.dex.code.CatchTable;
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.dex.code.DalvInsn;
+import com.android.dx.dex.code.DalvInsnList;
+import com.android.dx.dex.code.LocalList;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstMemberRef;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+
+/**
+ * Representation of all the parts needed for concrete methods in a
+ * {@code dex} file.
+ */
+public final class CodeItem extends OffsettedItem {
+    /** file alignment of this class, in bytes */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of the header of this class, in bytes */
+    private static final int HEADER_SIZE = 16;
+
+    /** {@code non-null;} method that this code implements */
+    private final CstMethodRef ref;
+
+    /** {@code non-null;} the bytecode instructions and associated data */
+    private final DalvCode code;
+
+    /** {@code null-ok;} the catches, if needed; set in {@link #addContents} */
+    private CatchStructs catches;
+
+    /** whether this instance is for a {@code static} method */
+    private final boolean isStatic;
+
+    /**
+     * {@code non-null;} list of possibly-thrown exceptions; just used in
+     * generating debugging output (listings)
+     */
+    private final TypeList throwsList;
+
+    /**
+     * {@code null-ok;} the debug info or {@code null} if there is none;
+     * set in {@link #addContents}
+     */
+    private DebugInfoItem debugInfo;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param ref {@code non-null;} method that this code implements
+     * @param code {@code non-null;} the underlying code
+     * @param isStatic whether this instance is for a {@code static}
+     * method
+     * @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,
+            TypeList throwsList) {
+        super(ALIGNMENT, -1);
+
+        if (ref == null) {
+            throw new NullPointerException("ref == null");
+        }
+
+        if (code == null) {
+            throw new NullPointerException("code == null");
+        }
+
+        if (throwsList == null) {
+            throw new NullPointerException("throwsList == null");
+        }
+
+        this.ref = ref;
+        this.code = code;
+        this.isStatic = isStatic;
+        this.throwsList = throwsList;
+        this.catches = null;
+        this.debugInfo = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_CODE_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MixedItemSection byteData = file.getByteData();
+        TypeIdsSection typeIds = file.getTypeIds();
+
+        if (code.hasPositions() || code.hasLocals()) {
+            debugInfo = new DebugInfoItem(code, isStatic, ref);
+            byteData.add(debugInfo);
+        }
+
+        if (code.hasAnyCatches()) {
+            for (Type type : code.getCatchTypes()) {
+                typeIds.intern(type);
+            }
+            catches = new CatchStructs(code);
+        }
+
+        for (Constant c : code.getInsnConstants()) {
+            file.internIfAppropriate(c);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "CodeItem{" + toHuman() + "}";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return ref.toHuman();
+    }
+
+    /**
+     * Gets the reference to the method this instance implements.
+     *
+     * @return {@code non-null;} the method reference
+     */
+    public CstMethodRef getRef() {
+        return ref;
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} per-line prefix to use
+     * @param verbose whether to be verbose with the output
+     */
+    public void debugPrint(PrintWriter out, String prefix, boolean verbose) {
+        out.println(ref.toHuman() + ":");
+
+        DalvInsnList insns = code.getInsns();
+        out.println("regs: " + Hex.u2(getRegistersSize()) +
+                "; ins: " + Hex.u2(getInsSize()) + "; outs: " +
+                Hex.u2(getOutsSize()));
+
+        insns.debugPrint(out, prefix, verbose);
+
+        String prefix2 = prefix + "  ";
+
+        if (catches != null) {
+            out.print(prefix);
+            out.println("catches");
+            catches.debugPrint(out, prefix2);
+        }
+
+        if (debugInfo != null) {
+            out.print(prefix);
+            out.println("debug info");
+            debugInfo.debugPrint(out, prefix2);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        final DexFile file = addedTo.getFile();
+        int catchesSize;
+
+        /*
+         * In order to get the catches and insns, all the code's
+         * constants need to be assigned indices.
+         */
+        code.assignIndices(new DalvCode.AssignIndicesCallback() {
+                public int getIndex(Constant cst) {
+                    IndexedItem item = file.findItemOrNull(cst);
+                    if (item == null) {
+                        return -1;
+                    }
+                    return item.getIndex();
+                }
+            });
+
+        if (catches != null) {
+            catches.encode(file);
+            catchesSize = catches.writeSize();
+        } else {
+            catchesSize = 0;
+        }
+
+        /*
+         * The write size includes the header, two bytes per code
+         * unit, post-code padding if necessary, and however much
+         * space the catches need.
+         */
+
+        int insnsSize = code.getInsns().codeSize();
+        if ((insnsSize & 1) != 0) {
+            insnsSize++;
+        }
+
+        setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        int regSz = getRegistersSize();
+        int outsSz = getOutsSize();
+        int insSz = getInsSize();
+        int insnsSz = code.getInsns().codeSize();
+        boolean needPadding = (insnsSz & 1) != 0;
+        int triesSz = (catches == null) ? 0 : catches.triesSize();
+        int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + ' ' + ref.toHuman());
+            out.annotate(2, "  registers_size: " + Hex.u2(regSz));
+            out.annotate(2, "  ins_size:       " + Hex.u2(insSz));
+            out.annotate(2, "  outs_size:      " + Hex.u2(outsSz));
+            out.annotate(2, "  tries_size:     " + Hex.u2(triesSz));
+            out.annotate(4, "  debug_off:      " + Hex.u4(debugOff));
+            out.annotate(4, "  insns_size:     " + Hex.u4(insnsSz));
+
+            // This isn't represented directly here, but it is useful to see.
+            int size = throwsList.size();
+            if (size != 0) {
+                out.annotate(0, "  throws " + StdTypeList.toHuman(throwsList));
+            }
+        }
+
+        out.writeShort(regSz);
+        out.writeShort(insSz);
+        out.writeShort(outsSz);
+        out.writeShort(triesSz);
+        out.writeInt(debugOff);
+        out.writeInt(insnsSz);
+
+        writeCodes(file, out);
+
+        if (catches != null) {
+            if (needPadding) {
+                if (annotates) {
+                    out.annotate(2, "  padding: 0");
+                }
+                out.writeShort(0);
+            }
+
+            catches.writeTo(file, out);
+        }
+
+        if (annotates) {
+            /*
+             * These are pointed at in the code header (above), but it's less
+             * distracting to expand on them at the bottom of the code.
+             */
+            if (debugInfo != null) {
+                out.annotate(0, "  debug info");
+                debugInfo.annotateTo(file, out, "    ");
+            }
+        }
+    }
+
+    /**
+     * Helper for {@link #writeTo0} which writes out the actual bytecode.
+     *
+     * @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();
+
+        try {
+            insns.writeTo(out);
+        } catch (RuntimeException ex) {
+            throw ExceptionWithContext.withContext(ex, "...while writing " +
+                    "instructions for " + ref.toHuman());
+        }
+    }
+
+    /**
+     * Get the in registers count.
+     *
+     * @return the count
+     */
+    private int getInsSize() {
+        return ref.getParameterWordCount(isStatic);
+    }
+
+    /**
+     * Get the out registers count.
+     *
+     * @return the count
+     */
+    private int getOutsSize() {
+        return code.getInsns().getOutsSize();
+    }
+
+    /**
+     * Get the total registers count.
+     *
+     * @return the count
+     */
+    private int getRegistersSize() {
+        return code.getInsns().getRegistersSize();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java b/dx/src/com/android/dx/dex/file/DebugInfoConstants.java
new file mode 100644
index 0000000..78b6b04
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/DebugInfoConstants.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+/**
+ * Constants for the dex debug info state machine format.
+ */
+public interface DebugInfoConstants {
+
+    /*
+     * normal opcodes
+     */
+
+    /**
+     * Terminates a debug info sequence for a method.<p>
+     * Args: none
+     *
+     */
+    static final int DBG_END_SEQUENCE = 0x00;
+
+    /**
+     * Advances the program counter/address register without emitting
+     * a positions entry.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; amount to advance pc by
+     * </ol>
+     */
+    static final int DBG_ADVANCE_PC = 0x01;
+
+    /**
+     * Advances the line register without emitting
+     * a positions entry.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Signed LEB128 &mdash; amount to change line register by.
+     * </ol>
+     */
+    static final int DBG_ADVANCE_LINE = 0x02;
+
+    /**
+     * Introduces a local variable at the current address.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register that will contain local.
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of local name.
+     * <li>Unsigned LEB128 &mdash; type index (shifted by 1) of type.
+     * </ol>
+     */
+    static final int DBG_START_LOCAL = 0x03;
+
+    /**
+     * Introduces a local variable at the current address with a type
+     * signature specified.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register that will contain local.
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of local name.
+     * <li>Unsigned LEB128 &mdash; type index (shifted by 1) of type.
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of
+     * type signature.
+     * </ol>
+     */
+    static final int DBG_START_LOCAL_EXTENDED = 0x04;
+
+    /**
+     * Marks a currently-live local variable as out of scope at the
+     * current address.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register that contained local
+     * </ol>
+     */
+    static final int DBG_END_LOCAL = 0x05;
+
+    /**
+     * Re-introduces a local variable at the current address. The name
+     * and type are the same as the last local that was live in the specified
+     * register.<p>
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; register to re-start.
+     * </ol>
+     */
+    static final int DBG_RESTART_LOCAL = 0x06;
+
+
+    /**
+     * Sets the "prologue_end" state machine register, indicating that the
+     * next position entry that is added should be considered the end of
+     * a method prologue (an appropriate place for a method breakpoint).<p>
+     *
+     * The prologue_end register is cleared by any special
+     * ({@code >= OPCODE_BASE}) opcode.
+     */
+    static final int DBG_SET_PROLOGUE_END = 0x07;
+
+    /**
+     * Sets the "epilogue_begin" state machine register, indicating that the
+     * next position entry that is added should be considered the beginning of
+     * a method epilogue (an appropriate place to suspend execution before
+     * method exit).<p>
+     *
+     * The epilogue_begin register is cleared by any special
+     * ({@code >= OPCODE_BASE}) opcode.
+     */
+    static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
+
+    /**
+     * Sets the current file that that line numbers refer to. All subsequent
+     * line number entries make reference to this source file name, instead
+     * of the default name specified in code_item.
+     *
+     * Args:
+     * <ol>
+     * <li>Unsigned LEB128 &mdash; string index (shifted by 1) of source
+     * file name.
+     * </ol>
+     */
+    static final int DBG_SET_FILE = 0x09;
+
+    /* IF YOU ADD A NEW OPCODE, increase OPCODE_BASE */
+
+    /*
+     * "special opcode" configuration, essentially what's found in
+     * the line number program header in DWARFv3, Section 6.2.4
+     */
+
+    /** the smallest value a special opcode can take */
+    static final int DBG_FIRST_SPECIAL = 0x0a;
+    static final int DBG_LINE_BASE = -4;
+    static final int DBG_LINE_RANGE = 15;
+    // MIN_INSN_LENGTH is always 1
+}
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
new file mode 100644
index 0000000..9fb4845
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.dex.code.DalvInsnList;
+import com.android.dx.dex.code.LocalList;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArrayByteInput;
+import com.android.dx.util.ByteInput;
+import com.android.dx.util.ExceptionWithContext;
+
+import com.android.dx.util.Leb128Utils;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.dx.dex.file.DebugInfoConstants.*;
+
+/**
+ * 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}
+ */
+public class DebugInfoDecoder {
+    /** encoded debug info */
+    private final byte[] encoded;
+
+    /** positions decoded */
+    private final ArrayList<PositionEntry> positions;
+
+    /** locals decoded */
+    private final ArrayList<LocalEntry> locals;
+
+    /** size of code block in code units */
+    private final int codesize;
+
+    /** indexed by register, the last local variable live in a reg */
+    private final LocalEntry[] lastEntryForReg;
+
+    /** method descriptor of method this debug info is for */
+    private final Prototype desc;
+
+    /** true if method is static */
+    private final boolean isStatic;
+
+    /** dex file this debug info will be stored in */
+    private final DexFile file;
+
+    /**
+     * register size, in register units, of the register space
+     * used by this method
+     */
+    private final int regSize;
+
+    /** current decoding state: line number */
+    private int line = 1;
+
+    /** current decoding state: bytecode address */
+    private int address = 0;
+
+    /** string index of the string "this" */
+    private final int thisStringIdx;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param encoded encoded debug info
+     * @param codesize size of code block in code units
+     * @param regSize register size, in register units, of the register space
+     * used by this method
+     * @param isStatic true if method is static
+     * @param ref method descriptor of method this debug info is for
+     * @param file dex file this debug info will be stored in
+     */
+    DebugInfoDecoder(byte[] encoded, int codesize, int regSize,
+            boolean isStatic, CstMethodRef ref, DexFile file) {
+        if (encoded == null) {
+            throw new NullPointerException("encoded == null");
+        }
+
+        this.encoded = encoded;
+        this.isStatic = isStatic;
+        this.desc = ref.getPrototype();
+        this.file = file;
+        this.regSize = regSize;
+
+        positions = new ArrayList<PositionEntry>();
+        locals = new ArrayList<LocalEntry>();
+        this.codesize = codesize;
+        lastEntryForReg = new LocalEntry[regSize];
+
+        int idx = -1;
+
+        try {
+            idx = file.getStringIds().indexOf(new CstString("this"));
+        } catch (IllegalArgumentException ex) {
+            /*
+             * Silently tolerate not finding "this". It just means that
+             * no method has local variable info that looks like
+             * a standard instance method.
+             */
+        }
+
+        thisStringIdx = idx;
+    }
+
+    /**
+     * An entry in the resulting postions table
+     */
+    static private class PositionEntry {
+        /** bytecode address */
+        public int address;
+
+        /** line number */
+        public int line;
+
+        public PositionEntry(int address, int line) {
+            this.address = address;
+            this.line = line;
+        }
+    }
+
+    /**
+     * An entry in the resulting locals table
+     */
+    static private class LocalEntry {
+        /** address of event */
+        public int address;
+
+        /** {@code true} iff it's a local start */
+        public boolean isStart;
+
+        /** register number */
+        public int reg;
+
+        /** index of name in strings table */
+        public int nameIndex;
+
+        /** index of type in types table */
+        public int typeIndex;
+
+        /** index of type signature in strings table */
+        public int signatureIndex;
+
+        public LocalEntry(int address, boolean isStart, int reg, int nameIndex,
+                int typeIndex, int signatureIndex) {
+            this.address        = address;
+            this.isStart        = isStart;
+            this.reg            = reg;
+            this.nameIndex      = nameIndex;
+            this.typeIndex      = typeIndex;
+            this.signatureIndex = signatureIndex;
+        }
+
+        public String toString() {
+            return String.format("[%x %s v%d %04x %04x %04x]",
+                    address, isStart ? "start" : "end", reg,
+                    nameIndex, typeIndex, signatureIndex);
+        }
+    }
+
+    /**
+     * Gets the decoded positions list.
+     * Valid after calling {@code decode}.
+     *
+     * @return positions list in ascending address order.
+     */
+    public List<PositionEntry> getPositionList() {
+        return positions;
+    }
+
+    /**
+     * Gets the decoded locals list, in ascending start-address order.
+     * Valid after calling {@code decode}.
+     *
+     * @return locals list in ascending address order.
+     */
+    public List<LocalEntry> getLocals() {
+        return locals;
+    }
+
+    /**
+     * Decodes the debug info sequence.
+     */
+    public void decode() {
+        try {
+            decode0();
+        } catch (Exception ex) {
+            throw ExceptionWithContext.withContext(ex,
+                    "...while decoding debug info");
+        }
+    }
+
+    /**
+     * Reads a string index. String indicies are offset by 1, and a 0 value
+     * in the stream (-1 as returned by this method) means "null"
+     *
+     * @return index into file's string ids table, -1 means null
+     * @throws IOException
+     */
+    private int readStringIndex(ByteInput bs) throws IOException {
+        int offsetIndex = Leb128Utils.readUnsignedLeb128(bs);
+
+        return offsetIndex - 1;
+    }
+
+    /**
+     * Gets the register that begins the method's parameter range (including
+     * the 'this' parameter for non-static methods). The range continues until
+     * {@code regSize}
+     *
+     * @return register as noted above.
+     */
+    private int getParamBase() {
+        return regSize
+                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
+    }
+
+    private void decode0() throws IOException {
+        ByteInput bs = new ByteArrayByteInput(encoded);
+
+        line = Leb128Utils.readUnsignedLeb128(bs);
+        int szParams = Leb128Utils.readUnsignedLeb128(bs);
+        StdTypeList params = desc.getParameterTypes();
+        int curReg = getParamBase();
+
+        if (szParams != params.size()) {
+            throw new RuntimeException(
+                    "Mismatch between parameters_size and prototype");
+        }
+
+        if (!isStatic) {
+            // Start off with implicit 'this' entry
+            LocalEntry thisEntry =
+                new LocalEntry(0, true, curReg, thisStringIdx, 0, 0);
+            locals.add(thisEntry);
+            lastEntryForReg[curReg] = thisEntry;
+            curReg++;
+        }
+
+        for (int i = 0; i < szParams; i++) {
+            Type paramType = params.getType(i);
+            LocalEntry le;
+
+            int nameIdx = readStringIndex(bs);
+
+            if (nameIdx == -1) {
+                /*
+                 * Unnamed parameter; often but not always filled in by an
+                 * extended start op after the prologue
+                 */
+                le = new LocalEntry(0, true, curReg, -1, 0, 0);
+            } else {
+                // TODO: Final 0 should be idx of paramType.getDescriptor().
+                le = new LocalEntry(0, true, curReg, nameIdx, 0, 0);
+            }
+
+            locals.add(le);
+            lastEntryForReg[curReg] = le;
+            curReg += paramType.getCategory();
+        }
+
+        for (;;) {
+            int opcode = bs.readByte() & 0xff;
+
+            switch (opcode) {
+                case DBG_START_LOCAL: {
+                    int reg = Leb128Utils.readUnsignedLeb128(bs);
+                    int nameIdx = readStringIndex(bs);
+                    int typeIdx = readStringIndex(bs);
+                    LocalEntry le = new LocalEntry(
+                            address, true, reg, nameIdx, typeIdx, 0);
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_START_LOCAL_EXTENDED: {
+                    int reg = Leb128Utils.readUnsignedLeb128(bs);
+                    int nameIdx = readStringIndex(bs);
+                    int typeIdx = readStringIndex(bs);
+                    int sigIdx = readStringIndex(bs);
+                    LocalEntry le = new LocalEntry(
+                            address, true, reg, nameIdx, typeIdx, sigIdx);
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_RESTART_LOCAL: {
+                    int reg = Leb128Utils.readUnsignedLeb128(bs);
+                    LocalEntry prevle;
+                    LocalEntry le;
+
+                    try {
+                        prevle = lastEntryForReg[reg];
+
+                        if (prevle.isStart) {
+                            throw new RuntimeException("nonsensical "
+                                    + "RESTART_LOCAL on live register v"
+                                    + reg);
+                        }
+
+                        le = new LocalEntry(address, true, reg,
+                                prevle.nameIndex, prevle.typeIndex, 0);
+                    } catch (NullPointerException ex) {
+                        throw new RuntimeException(
+                                "Encountered RESTART_LOCAL on new v" + reg);
+                    }
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_END_LOCAL: {
+                    int reg = Leb128Utils.readUnsignedLeb128(bs);
+                    LocalEntry prevle;
+                    LocalEntry le;
+
+                    try {
+                        prevle = lastEntryForReg[reg];
+
+                        if (!prevle.isStart) {
+                            throw new RuntimeException("nonsensical "
+                                    + "END_LOCAL on dead register v" + reg);
+                        }
+
+                        le = new LocalEntry(address, false, reg,
+                                prevle.nameIndex, prevle.typeIndex,
+                                prevle.signatureIndex);
+                    } catch (NullPointerException ex) {
+                        throw new RuntimeException(
+                                "Encountered END_LOCAL on new v" + reg);
+                    }
+
+                    locals.add(le);
+                    lastEntryForReg[reg] = le;
+                }
+                break;
+
+                case DBG_END_SEQUENCE:
+                    // all done
+                return;
+
+                case DBG_ADVANCE_PC:
+                    address += Leb128Utils.readUnsignedLeb128(bs);
+                break;
+
+                case DBG_ADVANCE_LINE:
+                    line += Leb128Utils.readSignedLeb128(bs);
+                break;
+
+                case DBG_SET_PROLOGUE_END:
+                    //TODO do something with this.
+                break;
+
+                case DBG_SET_EPILOGUE_BEGIN:
+                    //TODO do something with this.
+                break;
+
+                case DBG_SET_FILE:
+                    //TODO do something with this.
+                break;
+
+                default:
+                    if (opcode < DBG_FIRST_SPECIAL) {
+                        throw new RuntimeException(
+                                "Invalid extended opcode encountered "
+                                        + opcode);
+                    }
+
+                    int adjopcode = opcode - DBG_FIRST_SPECIAL;
+
+                    address += adjopcode / DBG_LINE_RANGE;
+                    line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+
+                    positions.add(new PositionEntry(address, line));
+                break;
+
+            }
+        }
+    }
+
+    /**
+     * Validates an encoded debug info stream against data used to encode it,
+     * throwing an exception if they do not match. Used to validate the
+     * encoder.
+     *
+     * @param info encoded debug info
+     * @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,
+            CstMethodRef ref, DalvCode code, boolean isStatic) {
+        PositionList pl = code.getPositions();
+        LocalList ll = code.getLocals();
+        DalvInsnList insns = code.getInsns();
+        int codeSize = insns.codeSize();
+        int countRegisters = insns.getRegistersSize();
+
+        try {
+            validateEncode0(info, codeSize, countRegisters,
+                    isStatic, ref, file, pl, ll);
+        } catch (RuntimeException ex) {
+            System.err.println("instructions:");
+            insns.debugPrint(System.err, "  ", true);
+            System.err.println("local list:");
+            ll.debugPrint(System.err, "  ");
+            throw ExceptionWithContext.withContext(ex,
+                    "while processing " + ref.toHuman());
+        }
+    }
+
+    private static void validateEncode0(byte[] info, int codeSize,
+            int countRegisters, boolean isStatic, CstMethodRef ref,
+            DexFile file, PositionList pl, LocalList ll) {
+        DebugInfoDecoder decoder
+                = new DebugInfoDecoder(info, codeSize, countRegisters,
+                    isStatic, ref, file);
+
+        decoder.decode();
+
+        /*
+         * Go through the decoded position entries, matching up
+         * with original entries.
+         */
+
+        List<PositionEntry> decodedEntries = decoder.getPositionList();
+
+        if (decodedEntries.size() != pl.size()) {
+            throw new RuntimeException(
+                    "Decoded positions table not same size was "
+                    + decodedEntries.size() + " expected " + pl.size());
+        }
+
+        for (PositionEntry entry : decodedEntries) {
+            boolean found = false;
+            for (int i = pl.size() - 1; i >= 0; i--) {
+                PositionList.Entry ple = pl.get(i);
+
+                if (entry.line == ple.getPosition().getLine()
+                        && entry.address == ple.getAddress()) {
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found) {
+                throw new RuntimeException ("Could not match position entry: "
+                        + entry.address + ", " + entry.line);
+            }
+        }
+
+        /*
+         * Go through the original local list, in order, matching up
+         * with decoded entries.
+         */
+
+        List<LocalEntry> decodedLocals = decoder.getLocals();
+        int thisStringIdx = decoder.thisStringIdx;
+        int decodedSz = decodedLocals.size();
+        int paramBase = decoder.getParamBase();
+
+        /*
+         * Preflight to fill in any parameters that were skipped in
+         * the prologue (including an implied "this") but then
+         * identified by full signature.
+         */
+        for (int i = 0; i < decodedSz; i++) {
+            LocalEntry entry = decodedLocals.get(i);
+            int idx = entry.nameIndex;
+
+            if ((idx < 0) || (idx == thisStringIdx)) {
+                for (int j = i + 1; j < decodedSz; j++) {
+                    LocalEntry e2 = decodedLocals.get(j);
+                    if (e2.address != 0) {
+                        break;
+                    }
+                    if ((entry.reg == e2.reg) && e2.isStart) {
+                        decodedLocals.set(i, e2);
+                        decodedLocals.remove(j);
+                        decodedSz--;
+                        break;
+                    }
+                }
+            }
+        }
+
+        int origSz = ll.size();
+        int decodeAt = 0;
+        boolean problem = false;
+
+        for (int i = 0; i < origSz; i++) {
+            LocalList.Entry origEntry = ll.get(i);
+
+            if (origEntry.getDisposition()
+                    == LocalList.Disposition.END_REPLACED) {
+                /*
+                 * The encoded list doesn't represent replacements, so
+                 * ignore them for the sake of comparison.
+                 */
+                continue;
+            }
+
+            LocalEntry decodedEntry;
+
+            do {
+                decodedEntry = decodedLocals.get(decodeAt);
+                if (decodedEntry.nameIndex >= 0) {
+                    break;
+                }
+                /*
+                 * A negative name index means this is an anonymous
+                 * parameter, and we shouldn't expect to see it in the
+                 * original list. So, skip it.
+                 */
+                decodeAt++;
+            } while (decodeAt < decodedSz);
+
+            int decodedAddress = decodedEntry.address;
+
+            if (decodedEntry.reg != origEntry.getRegister()) {
+                System.err.println("local register mismatch at orig " + i +
+                        " / decoded " + decodeAt);
+                problem = true;
+                break;
+            }
+
+            if (decodedEntry.isStart != origEntry.isStart()) {
+                System.err.println("local start/end mismatch at orig " + i +
+                        " / decoded " + decodeAt);
+                problem = true;
+                break;
+            }
+
+            /*
+             * The secondary check here accounts for the fact that a
+             * parameter might not be marked as starting at 0 in the
+             * original list.
+             */
+            if ((decodedAddress != origEntry.getAddress())
+                    && !((decodedAddress == 0)
+                            && (decodedEntry.reg >= paramBase))) {
+                System.err.println("local address mismatch at orig " + i +
+                        " / decoded " + decodeAt);
+                problem = true;
+                break;
+            }
+
+            decodeAt++;
+        }
+
+        if (problem) {
+            System.err.println("decoded locals:");
+            for (LocalEntry e : decodedLocals) {
+                System.err.println("  " + e);
+            }
+            throw new RuntimeException("local table problem");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java b/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java
new file mode 100644
index 0000000..ae87fc3
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.code.LocalList;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.BitSet;
+
+import static com.android.dx.dex.file.DebugInfoConstants.*;
+
+/**
+ * An encoder for the dex debug info state machine format. The format
+ * for each method enrty is as follows:
+ * <ol>
+ * <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} excluded. A value of '0' indicates "no name"
+ * <li> A sequence of special or normal opcodes as defined in
+ * {@code DebugInfoConstants}.
+ * <li> A single terminating {@code OP_END_SEQUENCE}
+ * </ol>
+ */
+public final class DebugInfoEncoder {
+    private static final boolean DEBUG = false;
+
+    /** {@code null-ok;} positions (line numbers) to encode */
+    private final PositionList positions;
+
+    /** {@code null-ok;} local variables to encode */
+    private final LocalList locals;
+
+    private final ByteArrayAnnotatedOutput output;
+    private final DexFile file;
+    private final int codeSize;
+    private final int regSize;
+
+    private final Prototype desc;
+    private final boolean isStatic;
+
+    /** current encoding state: bytecode address */
+    private int address = 0;
+
+    /** current encoding state: line number */
+    private int line = 1;
+
+    /**
+     * if non-null: the output to write annotations to. No normal
+     * output is written to this.
+     */
+    private AnnotatedOutput annotateTo;
+
+    /** if non-null: another possible output for annotations */
+    private PrintWriter debugPrint;
+
+    /** if non-null: the prefix for each annotation or debugPrint line */
+    private String prefix;
+
+    /** true if output should be consumed during annotation */
+    private boolean shouldConsume;
+
+    /** indexed by register; last local alive in register */
+    private final LocalList.Entry[] lastEntryForReg;
+
+    /**
+     * Creates an instance.
+     *
+     * @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 positions, LocalList locals,
+            DexFile file, int codeSize, int regSize,
+            boolean isStatic, CstMethodRef ref) {
+        this.positions = positions;
+        this.locals = locals;
+        this.file = file;
+        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} writer
+     * if applicable.
+     *
+     * @param length the number of bytes associated with this message
+     * @param message the message itself
+     */
+    private void annotate(int length, String message) {
+        if (prefix != null) {
+            message = prefix + message;
+        }
+
+        if (annotateTo != null) {
+            annotateTo.annotate(shouldConsume ? length : 0, message);
+        }
+
+        if (debugPrint != null) {
+            debugPrint.println(message);
+        }
+    }
+
+    /**
+     * Converts this (PositionList, LocalList) pair into a state machine
+     * sequence.
+     *
+     * @return {@code non-null;} encoded byte sequence without padding and
+     * terminated with a {@code 0x00} byte
+     */
+    public byte[] convert() {
+        try {
+            byte[] ret;
+            ret = convert0();
+
+            if (DEBUG) {
+                for (int i = 0 ; i < ret.length; i++) {
+                    System.err.printf("byte %02x\n", (0xff & ret[i]));
+                }
+            }
+
+            return ret;
+        } catch (IOException ex) {
+            throw ExceptionWithContext
+                    .withContext(ex, "...while encoding debug info");
+        }
+    }
+
+    /**
+     * Converts and produces annotations on a stream. Does not write
+     * actual bits to the {@code AnnotatedOutput}.
+     *
+     * @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 {@code null-ok;} if specified, where annotations should go
+     * @param consume whether to claim to have consumed output for
+     * {@code out}
+     * @return {@code non-null;} encoded output
+     */
+    public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint,
+            AnnotatedOutput out, boolean consume) {
+        this.prefix = prefix;
+        this.debugPrint = debugPrint;
+        annotateTo = out;
+        shouldConsume = consume;
+
+        byte[] result = convert();
+
+        return result;
+    }
+
+    private byte[] convert0() throws IOException {
+        ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions();
+        ArrayList<LocalList.Entry> methodArgs = extractMethodArguments();
+
+        emitHeader(sortedPositions, methodArgs);
+
+        // TODO: Make this mark be the actual prologue end.
+        output.writeByte(DBG_SET_PROLOGUE_END);
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(1, String.format("%04x: prologue end",address));
+        }
+
+        int positionsSz = sortedPositions.size();
+        int localsSz = locals.size();
+
+        // Current index in sortedPositions
+        int curPositionIdx = 0;
+        // Current index in locals
+        int curLocalIdx = 0;
+
+        for (;;) {
+            /*
+             * Emit any information for the current address.
+             */
+
+            curLocalIdx = emitLocalsAtAddress(curLocalIdx);
+            curPositionIdx =
+                emitPositionsAtAddress(curPositionIdx, sortedPositions);
+
+            /*
+             * Figure out what the next important address is.
+             */
+
+            int nextAddrL = Integer.MAX_VALUE; // local variable
+            int nextAddrP = Integer.MAX_VALUE; // position (line number)
+
+            if (curLocalIdx < localsSz) {
+                nextAddrL = locals.get(curLocalIdx).getAddress();
+            }
+
+            if (curPositionIdx < positionsSz) {
+                nextAddrP = sortedPositions.get(curPositionIdx).getAddress();
+            }
+
+            int next = Math.min(nextAddrP, nextAddrL);
+
+            // No next important address == done.
+            if (next == Integer.MAX_VALUE) {
+                break;
+            }
+
+            /*
+             * If the only work remaining are local ends at the end of the
+             * block, stop here. Those are implied anyway.
+             */
+            if (next == codeSize
+                    && nextAddrL == Integer.MAX_VALUE
+                    && nextAddrP == Integer.MAX_VALUE) {
+                break;
+            }
+
+            if (next == nextAddrP) {
+                // Combined advance PC + position entry
+                emitPosition(sortedPositions.get(curPositionIdx++));
+            } else {
+                emitAdvancePc(next - address);
+            }
+        }
+
+        emitEndSequence();
+
+        return output.toByteArray();
+    }
+
+    /**
+     * Emits all local variable activity that occurs at the current
+     * {@link #address} starting at the given index into {@code
+     * locals} and including all subsequent activity at the same
+     * address.
+     *
+     * @param curLocalIdx Current index in locals
+     * @return new value for {@code curLocalIdx}
+     * @throws IOException
+     */
+    private int emitLocalsAtAddress(int curLocalIdx)
+            throws IOException {
+        int sz = locals.size();
+
+        // TODO: Don't emit ends implied by starts.
+
+        while ((curLocalIdx < sz)
+                && (locals.get(curLocalIdx).getAddress() == address)) {
+            LocalList.Entry entry = locals.get(curLocalIdx++);
+            int reg = entry.getRegister();
+            LocalList.Entry prevEntry = lastEntryForReg[reg];
+
+            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] = entry;
+
+            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 (prevEntry.isStart()) {
+                        /*
+                         * We should never be handed a start when a
+                         * a matching local is already active.
+                         */
+                        throw new RuntimeException("shouldn't happen");
+                    }
+                    emitLocalRestart(entry);
+                } else {
+                    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 (entry.getDisposition()
+                        != LocalList.Disposition.END_REPLACED) {
+                    emitLocalEnd(entry);
+                }
+            }
+        }
+
+        return curLocalIdx;
+    }
+
+    /**
+     * Emits all positions that occur at the current {@code address}
+     *
+     * @param curPositionIdx Current index in sortedPositions
+     * @param sortedPositions positions, sorted by ascending address
+     * @return new value for {@code curPositionIdx}
+     * @throws IOException
+     */
+    private int emitPositionsAtAddress(int curPositionIdx,
+            ArrayList<PositionList.Entry> sortedPositions)
+            throws IOException {
+        int positionsSz = sortedPositions.size();
+        while ((curPositionIdx < positionsSz)
+                && (sortedPositions.get(curPositionIdx).getAddress()
+                        == address)) {
+            emitPosition(sortedPositions.get(curPositionIdx++));
+        }
+        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"
+     * @throws IOException
+     */
+    private void emitHeader(ArrayList<PositionList.Entry> sortedPositions,
+            ArrayList<LocalList.Entry> methodArgs) throws IOException {
+        boolean annotate = (annotateTo != null) || (debugPrint != null);
+        int mark = output.getCursor();
+
+        // Start by initializing the line number register.
+        if (sortedPositions.size() > 0) {
+            PositionList.Entry entry = sortedPositions.get(0);
+            line = entry.getPosition().getLine();
+        }
+        output.writeUleb128(line);
+
+        if (annotate) {
+            annotate(output.getCursor() - mark, "line_start: " + line);
+        }
+
+        int curParam = getParamBase();
+        // paramTypes will not include 'this'
+        StdTypeList paramTypes = desc.getParameterTypes();
+        int szParamTypes = paramTypes.size();
+
+        /*
+         * Initialize lastEntryForReg to have an initial
+         * entry for the 'this' pointer.
+         */
+        if (!isStatic) {
+            for (LocalList.Entry arg : methodArgs) {
+                if (curParam == arg.getRegister()) {
+                    lastEntryForReg[curParam] = arg;
+                    break;
+                }
+            }
+            curParam++;
+        }
+
+        // Write out the number of parameter entries that will follow.
+        mark = output.getCursor();
+        output.writeUleb128(szParamTypes);
+
+        if (annotate) {
+            annotate(output.getCursor() - mark,
+                    String.format("parameters_size: %04x", szParamTypes));
+        }
+
+        /*
+         * Then emit the string indicies of all the method parameters.
+         * Note that 'this', if applicable, is excluded.
+         */
+        for (int i = 0; i < szParamTypes; i++) {
+            Type pt = paramTypes.get(i);
+            LocalList.Entry found = null;
+
+            mark = output.getCursor();
+
+            for (LocalList.Entry arg : methodArgs) {
+                if (curParam == arg.getRegister()) {
+                    found = arg;
+
+                    if (arg.getSignature() != null) {
+                        /*
+                         * Parameters with signatures will be re-emitted
+                         * in complete as LOCAL_START_EXTENDED's below.
+                         */
+                        emitStringIndex(null);
+                    } else {
+                        emitStringIndex(arg.getName());
+                    }
+                    lastEntryForReg[curParam] = arg;
+
+                    break;
+                }
+            }
+
+            if (found == null) {
+                /*
+                 * Emit a null symbol for "unnamed." This is common
+                 * for, e.g., synthesized methods and inner-class
+                 * this$0 arguments.
+                 */
+                emitStringIndex(null);
+            }
+
+            if (annotate) {
+                String parameterName
+                        = (found == null || found.getSignature() != null)
+                                ? "<unnamed>" : found.getName().toHuman();
+                annotate(output.getCursor() - mark,
+                        "parameter " + parameterName + " "
+                                + RegisterSpec.PREFIX + curParam);
+            }
+
+            curParam += pt.getCategory();
+        }
+
+        /*
+         * If anything emitted above has a type signature, emit it again as
+         * a LOCAL_RESTART_EXTENDED
+         */
+
+        for (LocalList.Entry arg : lastEntryForReg) {
+            if (arg == null) {
+                continue;
+            }
+
+            CstString signature = arg.getSignature();
+
+            if (signature != null) {
+                emitLocalStartExtended(arg);
+            }
+        }
+    }
+
+    /**
+     * Builds a list of position entries, sorted by ascending address.
+     *
+     * @return A sorted positions list
+     */
+    private ArrayList<PositionList.Entry> buildSortedPositions() {
+        int sz = (positions == null) ? 0 : positions.size();
+        ArrayList<PositionList.Entry> result = new ArrayList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            result.add(positions.get(i));
+        }
+
+        // Sort ascending by address.
+        Collections.sort (result, new Comparator<PositionList.Entry>() {
+            public int compare (PositionList.Entry a, PositionList.Entry b) {
+                return a.getAddress() - b.getAddress();
+            }
+
+            public boolean equals (Object obj) {
+               return obj == this;
+            }
+        });
+        return result;
+    }
+
+    /**
+     * Gets the register that begins the method's parameter range (including
+     * the 'this' parameter for non-static methods). The range continues until
+     * {@code regSize}
+     *
+     * @return register as noted above
+     */
+    private int getParamBase() {
+        return regSize
+                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
+    }
+
+    /**
+     * Extracts method arguments from a locals list. These will be collected
+     * from the input list and sorted by ascending register in the
+     * returned list.
+     *
+     * @return list of non-{@code this} method argument locals,
+     * sorted by ascending register
+     */
+    private ArrayList<LocalList.Entry> extractMethodArguments() {
+        ArrayList<LocalList.Entry> result
+                = new ArrayList(desc.getParameterTypes().size());
+        int argBase = getParamBase();
+        BitSet seen = new BitSet(regSize - argBase);
+        int sz = locals.size();
+
+        for (int i = 0; i < sz; i++) {
+            LocalList.Entry e = locals.get(i);
+            int reg = e.getRegister();
+
+            if (reg < argBase) {
+                continue;
+            }
+
+            // only the lowest-start-address entry is included.
+            if (seen.get(reg - argBase)) {
+                continue;
+            }
+
+            seen.set(reg - argBase);
+            result.add(e);
+        }
+
+        // Sort by ascending register.
+        Collections.sort(result, new Comparator<LocalList.Entry>() {
+            public int compare(LocalList.Entry a, LocalList.Entry b) {
+                return a.getRegister() - b.getRegister();
+            }
+
+            public boolean equals(Object obj) {
+               return obj == this;
+            }
+        });
+
+        return result;
+    }
+
+    /**
+     * Returns a string representation of this LocalList entry that is
+     * appropriate for emitting as an annotation.
+     *
+     * @param e {@code non-null;} entry
+     * @return {@code non-null;} annotation string
+     */
+    private String entryAnnotationString(LocalList.Entry e) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(RegisterSpec.PREFIX);
+        sb.append(e.getRegister());
+        sb.append(' ');
+
+        CstString name = e.getName();
+        if (name == null) {
+            sb.append("null");
+        } else {
+            sb.append(name.toHuman());
+        }
+        sb.append(' ');
+
+        CstType type = e.getType();
+        if (type == null) {
+            sb.append("null");
+        } else {
+            sb.append(type.toHuman());
+        }
+
+        CstString signature = e.getSignature();
+
+        if (signature != null) {
+            sb.append(' ');
+            sb.append(signature.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL}
+     * sequence.
+     *
+     * @param entry entry associated with this restart
+     * @throws IOException
+     */
+    private void emitLocalRestart(LocalList.Entry entry)
+            throws IOException {
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_RESTART_LOCAL);
+        emitUnsignedLeb128(entry.getRegister());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: +local restart %s",
+                            address, entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local restart");
+        }
+    }
+
+    /**
+     * Emits a string index as an unsigned LEB128. The actual value written
+     * is shifted by 1, so that the '0' value is reserved for "null". The
+     * null symbol is used in some cases by the parameter name list
+     * at the beginning of the sequence.
+     *
+     * @param string {@code null-ok;} string to emit
+     * @throws IOException
+     */
+    private void emitStringIndex(CstString string) throws IOException {
+        if ((string == null) || (file == null)) {
+            output.writeUleb128(0);
+        } else {
+            output.writeUleb128(
+                    1 + file.getStringIds().indexOf(string));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emit string %s\n",
+                    string == null ? "<null>" : string.toQuoted());
+        }
+    }
+
+    /**
+     * 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 {@code null-ok;} type to emit
+     * @throws IOException
+     */
+    private void emitTypeIndex(CstType type) throws IOException {
+        if ((type == null) || (file == null)) {
+            output.writeUleb128(0);
+        } else {
+            output.writeUleb128(
+                    1 + file.getTypeIds().indexOf(type));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emit type %s\n",
+                    type == null ? "<null>" : type.toHuman());
+        }
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or
+     * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
+     * DBG_START_LOCAL_EXTENDED} sequence.
+     *
+     * @param entry entry to emit
+     * @throws IOException
+     */
+    private void emitLocalStart(LocalList.Entry entry)
+        throws IOException {
+
+        if (entry.getSignature() != null) {
+            emitLocalStartExtended(entry);
+            return;
+        }
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_START_LOCAL);
+
+        emitUnsignedLeb128(entry.getRegister());
+        emitStringIndex(entry.getName());
+        emitTypeIndex(entry.getType());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: +local %s", address,
+                            entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local start");
+        }
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
+     * DBG_START_LOCAL_EXTENDED} sequence.
+     *
+     * @param entry entry to emit
+     * @throws IOException
+     */
+    private void emitLocalStartExtended(LocalList.Entry entry)
+        throws IOException {
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_START_LOCAL_EXTENDED);
+
+        emitUnsignedLeb128(entry.getRegister());
+        emitStringIndex(entry.getName());
+        emitTypeIndex(entry.getType());
+        emitStringIndex(entry.getSignature());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: +localx %s", address,
+                            entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local start");
+        }
+    }
+
+    /**
+     * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence.
+     *
+     * @param entry {@code entry non-null;} entry associated with end.
+     * @throws IOException
+     */
+    private void emitLocalEnd(LocalList.Entry entry)
+            throws IOException {
+
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_END_LOCAL);
+        output.writeUleb128(entry.getRegister());
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: -local %s", address,
+                            entryAnnotationString(entry)));
+        }
+
+        if (DEBUG) {
+            System.err.println("emit local end");
+        }
+    }
+
+    /**
+     * Emits the necessary byte sequences to emit the given position table
+     * entry. This will typically be a single special opcode, although
+     * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
+     *
+     * @param entry position entry to emit.
+     * @throws IOException
+     */
+    private void emitPosition(PositionList.Entry entry)
+            throws IOException {
+
+        SourcePosition pos = entry.getPosition();
+        int newLine = pos.getLine();
+        int newAddress = entry.getAddress();
+
+        int opcode;
+
+        int deltaLines = newLine - line;
+        int deltaAddress = newAddress - address;
+
+        if (deltaAddress < 0) {
+            throw new RuntimeException(
+                    "Position entries must be in ascending address order");
+        }
+
+        if ((deltaLines < DBG_LINE_BASE)
+                || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1))) {
+            emitAdvanceLine(deltaLines);
+            deltaLines = 0;
+        }
+
+        opcode = computeOpcode (deltaLines, deltaAddress);
+
+        if ((opcode & ~0xff) > 0) {
+            emitAdvancePc(deltaAddress);
+            deltaAddress = 0;
+            opcode = computeOpcode (deltaLines, deltaAddress);
+
+            if ((opcode & ~0xff) > 0) {
+                emitAdvanceLine(deltaLines);
+                deltaLines = 0;
+                opcode = computeOpcode (deltaLines, deltaAddress);
+            }
+        }
+
+        output.writeByte(opcode);
+
+        line += deltaLines;
+        address += deltaAddress;
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(1,
+                    String.format("%04x: line %d", address, line));
+        }
+    }
+
+    /**
+     * Computes a special opcode that will encode the given position change.
+     * If the return value is > 0xff, then the request cannot be fulfilled.
+     * Essentially the same as described in "DWARF Debugging Format Version 3"
+     * section 6.2.5.1.
+     *
+     * @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");
+        }
+
+        return (deltaLines - DBG_LINE_BASE)
+            + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL;
+    }
+
+    /**
+     * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE}
+     * sequence.
+     *
+     * @param deltaLines amount to change line number register by
+     * @throws IOException
+     */
+    private void emitAdvanceLine(int deltaLines) throws IOException {
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_ADVANCE_LINE);
+        output.writeSleb128(deltaLines);
+        line += deltaLines;
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("line = %d", line));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emitting advance_line for %d\n", deltaLines);
+        }
+    }
+
+    /**
+     * Emits an  {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
+     * sequence.
+     *
+     * @param deltaAddress {@code >= 0;} amount to change program counter by
+     * @throws IOException
+     */
+    private void emitAdvancePc(int deltaAddress) throws IOException {
+        int mark = output.getCursor();
+
+        output.writeByte(DBG_ADVANCE_PC);
+        output.writeUleb128(deltaAddress);
+        address += deltaAddress;
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(output.getCursor() - mark,
+                    String.format("%04x: advance pc", address));
+        }
+
+        if (DEBUG) {
+            System.err.printf("Emitting advance_pc for %d\n", deltaAddress);
+        }
+    }
+
+    /**
+     * Emits an unsigned LEB128 value.
+     *
+     * @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 {
+        // We'll never need the top end of the unsigned range anyway.
+        if (n < 0) {
+            throw new RuntimeException(
+                    "Signed value where unsigned required: " + n);
+        }
+
+        output.writeUleb128(n);
+    }
+
+    /**
+     * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE}
+     * bytecode.
+     */
+    private void emitEndSequence() {
+        output.writeByte(DBG_END_SEQUENCE);
+
+        if (annotateTo != null || debugPrint != null) {
+            annotate(1, "end sequence");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoItem.java b/dx/src/com/android/dx/dex/file/DebugInfoItem.java
new file mode 100644
index 0000000..09b2712
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/DebugInfoItem.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.dex.code.DalvInsnList;
+import com.android.dx.dex.code.LocalList;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+
+import java.io.PrintWriter;
+
+public class DebugInfoItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 1;
+
+    private static final boolean ENABLE_ENCODER_SELF_CHECK = false;
+
+    /** {@code non-null;} the code this item represents */
+    private final DalvCode code;
+
+    private byte[] encoded;
+
+    private final boolean isStatic;
+    private final CstMethodRef ref;
+
+    public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) {
+        // We don't know the write size yet.
+        super (ALIGNMENT, -1);
+
+        if (code == null) {
+            throw new NullPointerException("code == null");
+        }
+
+        this.code = code;
+        this.isStatic = isStatic;
+        this.ref = ref;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_DEBUG_INFO_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // No contents to add.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        try {
+            encoded = encode(addedTo.getFile(), null, null, null, false);
+            setWriteSize(encoded.length);
+        } catch (RuntimeException ex) {
+            throw ExceptionWithContext.withContext(ex,
+                    "...while placing debug info for " + ref.toHuman());
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /**
+     * Writes annotations for the elements of this list, as
+     * zero-length. This is meant to be used for dumping this instance
+     * directly after a code dump (with the real local list actually
+     * existing elsewhere in the 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);
+    }
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @param out {@code non-null;} where to dump
+     * @param prefix {@code non-null;} prefix to attach to each line of output
+     */
+    public void debugPrint(PrintWriter out, String prefix) {
+        encode(null, prefix, out, null, false);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        if (out.annotates()) {
+            /*
+             * Re-run the encoder to generate the annotations,
+             * but write the bits from the original encode
+             */
+
+            out.annotate(offsetString() + " debug info");
+            encode(file, null, null, out, true);
+        }
+
+        out.write(encoded);
+    }
+
+    /**
+     * Performs debug info encoding.
+     *
+     * @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 {@code null-ok;} if specified, where annotations should go
+     * @param consume whether to claim to have consumed output for
+     * {@code out}
+     * @return {@code non-null;} the encoded array
+     */
+    private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint,
+            AnnotatedOutput out, boolean consume) {
+        byte[] result = encode0(file, prefix, debugPrint, out, consume);
+
+        if (ENABLE_ENCODER_SELF_CHECK && (file != null)) {
+            try {
+                DebugInfoDecoder.validateEncode(result, file, ref, code,
+                        isStatic);
+            } catch (RuntimeException ex) {
+                // Reconvert, annotating to System.err.
+                encode0(file, "", new PrintWriter(System.err, true), null,
+                        false);
+                throw ex;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Helper for {@link #encode} to do most of the work.
+     *
+     * @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 {@code null-ok;} if specified, where annotations should go
+     * @param consume whether to claim to have consumed output for
+     * {@code out}
+     * @return {@code non-null;} the encoded array
+     */
+    private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint,
+            AnnotatedOutput out, boolean consume) {
+        PositionList positions = code.getPositions();
+        LocalList locals = code.getLocals();
+        DalvInsnList insns = code.getInsns();
+        int codeSize = insns.codeSize();
+        int regSize = insns.getRegistersSize();
+
+        DebugInfoEncoder encoder =
+            new DebugInfoEncoder(positions, locals,
+                    file, codeSize, regSize, isStatic, ref);
+
+        byte[] result;
+
+        if ((debugPrint == null) && (out == null)) {
+            result = encoder.convert();
+        } else {
+            result = encoder.convertAndAnnotate(prefix, debugPrint, out,
+                    consume);
+        }
+
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/DexFile.java b/dx/src/com/android/dx/dex/file/DexFile.java
new file mode 100644
index 0000000..6a9882c
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/DexFile.java
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.DexFormat;
+import com.android.dx.dex.DexOptions;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstBaseMethodRef;
+import com.android.dx.rop.cst.CstEnumRef;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.zip.Adler32;
+
+import static com.android.dx.dex.file.MixedItemSection.SortType;
+
+/**
+ * Representation of an entire {@code .dex} (Dalvik EXecutable)
+ * file, which itself consists of a set of Dalvik classes.
+ */
+public final class DexFile {
+    /** options controlling the creation of the file */
+    private DexOptions dexOptions;
+
+    /** {@code non-null;} word data section */
+    private final MixedItemSection wordData;
+
+    /**
+     * {@code non-null;} type lists section. This is word data, but separating
+     * it from {@link #wordData} helps break what would otherwise be a
+     * circular dependency between the that and {@link #protoIds}.
+     */
+    private final MixedItemSection typeLists;
+
+    /**
+     * {@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;
+
+    /** {@code non-null;} string data section */
+    private final MixedItemSection stringData;
+
+    /** {@code non-null;} string identifiers section */
+    private final StringIdsSection stringIds;
+
+    /** {@code non-null;} type identifiers section */
+    private final TypeIdsSection typeIds;
+
+    /** {@code non-null;} prototype identifiers section */
+    private final ProtoIdsSection protoIds;
+
+    /** {@code non-null;} field identifiers section */
+    private final FieldIdsSection fieldIds;
+
+    /** {@code non-null;} method identifiers section */
+    private final MethodIdsSection methodIds;
+
+    /** {@code non-null;} class definitions section */
+    private final ClassDefsSection classDefs;
+
+    /** {@code non-null;} class data section */
+    private final MixedItemSection classData;
+
+    /** {@code non-null;} byte data section */
+    private final MixedItemSection byteData;
+
+    /** {@code non-null;} file header */
+    private final HeaderSection header;
+
+    /**
+     * {@code non-null;} array of sections in the order they will appear in the
+     * final output file
+     */
+    private final Section[] sections;
+
+    /** {@code >= -1;} total file size or {@code -1} if unknown */
+    private int fileSize;
+
+    /** {@code >= 40;} maximum width of the file dump */
+    private int dumpWidth;
+
+    /**
+     * Constructs an instance. It is initially empty.
+     */
+    public DexFile(DexOptions dexOptions) {
+        this.dexOptions = dexOptions;
+
+        header = new HeaderSection(this);
+        typeLists = new MixedItemSection(null, this, 4, SortType.NONE);
+        wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE);
+        stringData =
+            new MixedItemSection("string_data", this, 1, SortType.INSTANCE);
+        classData = new MixedItemSection(null, this, 1, SortType.NONE);
+        byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE);
+        stringIds = new StringIdsSection(this);
+        typeIds = new TypeIdsSection(this);
+        protoIds = new ProtoIdsSection(this);
+        fieldIds = new FieldIdsSection(this);
+        methodIds = new MethodIdsSection(this);
+        classDefs = new ClassDefsSection(this);
+        map = new MixedItemSection("map", this, 4, SortType.NONE);
+
+        /*
+         * This is the list of sections in the order they appear in
+         * the final output.
+         */
+        sections = new Section[] {
+            header, stringIds, typeIds, protoIds, fieldIds, methodIds,
+            classDefs, wordData, typeLists, stringData, byteData,
+            classData, map };
+
+        fileSize = -1;
+        dumpWidth = 79;
+    }
+
+    /**
+     * Returns true if this dex doesn't contain any class defs.
+     */
+    public boolean isEmpty() {
+        return classDefs.items().isEmpty();
+    }
+
+    /**
+     * Gets the dex-creation options object.
+     */
+    public DexOptions getDexOptions() {
+        return dexOptions;
+    }
+
+    /**
+     * Adds a class to this instance. It is illegal to attempt to add more
+     * than one class with the same name.
+     *
+     * @param clazz {@code non-null;} the class to add
+     */
+    public void add(ClassDefItem clazz) {
+        classDefs.add(clazz);
+    }
+
+    /**
+     * Gets the class definition with the given name, if any.
+     *
+     * @param name {@code non-null;} the class name to look for
+     * @return {@code null-ok;} the class with the given name, or {@code null}
+     * if there is no such class
+     */
+    public ClassDefItem getClassOrNull(String name) {
+        try {
+            Type type = Type.internClassName(name);
+            return (ClassDefItem) classDefs.get(new CstType(type));
+        } catch (IllegalArgumentException ex) {
+            // Translate exception, per contract.
+            return null;
+        }
+    }
+
+    /**
+     * Writes the contents of this instance as either a binary or a
+     * human-readable form, or both.
+     *
+     * @param out {@code null-ok;} where to write to
+     * @param humanOut {@code null-ok;} where to write human-oriented output to
+     * @param verbose whether to be verbose when writing human-oriented output
+     */
+    public void writeTo(OutputStream out, Writer humanOut, boolean verbose)
+        throws IOException {
+        boolean annotate = (humanOut != null);
+        ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
+
+        if (out != null) {
+            out.write(result.getArray());
+        }
+
+        if (annotate) {
+            result.writeAnnotationsTo(humanOut);
+        }
+    }
+
+    /**
+     * Returns the contents of this instance as a {@code .dex} file,
+     * in {@code byte[]} form.
+     *
+     * @param humanOut {@code null-ok;} where to write human-oriented output to
+     * @param verbose whether to be verbose when writing human-oriented output
+     * @return {@code non-null;} a {@code .dex} file for this instance
+     */
+    public byte[] toDex(Writer humanOut, boolean verbose)
+        throws IOException {
+        boolean annotate = (humanOut != null);
+        ByteArrayAnnotatedOutput result = toDex0(annotate, verbose);
+
+        if (annotate) {
+            result.writeAnnotationsTo(humanOut);
+        }
+
+        return result.getArray();
+    }
+
+    /**
+     * Sets the maximum width of the human-oriented dump of the instance.
+     *
+     * @param dumpWidth {@code >= 40;} the width
+     */
+    public void setDumpWidth(int dumpWidth) {
+        if (dumpWidth < 40) {
+            throw new IllegalArgumentException("dumpWidth < 40");
+        }
+
+        this.dumpWidth = dumpWidth;
+    }
+
+    /**
+     * Gets the total file size, if known.
+     *
+     * <p>This is package-scope in order to allow
+     * the {@link HeaderSection} to set itself up properly.</p>
+     *
+     * @return {@code >= 0;} the total file size
+     * @throws RuntimeException thrown if the file size is not yet known
+     */
+    /*package*/ int getFileSize() {
+        if (fileSize < 0) {
+            throw new RuntimeException("file size not yet known");
+        }
+
+        return fileSize;
+    }
+
+    /**
+     * Gets the string data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the string data section
+     */
+    /*package*/ MixedItemSection getStringData() {
+        return stringData;
+    }
+
+    /**
+     * Gets the word data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the word data section
+     */
+    /*package*/ MixedItemSection getWordData() {
+        return wordData;
+    }
+
+    /**
+     * Gets the type lists section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the word data section
+     */
+    /*package*/ MixedItemSection getTypeLists() {
+        return typeLists;
+    }
+
+    /**
+     * Gets the map section.
+     *
+     * <p>This is package-scope in order to allow the header section
+     * to query it.</p>
+     *
+     * @return {@code non-null;} the map section
+     */
+    /*package*/ MixedItemSection getMap() {
+        return map;
+    }
+
+    /**
+     * Gets the string identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the string identifiers section
+     */
+    /*package*/ StringIdsSection getStringIds() {
+        return stringIds;
+    }
+
+    /**
+     * Gets the class definitions section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the class definitions section
+     */
+    /*package*/ ClassDefsSection getClassDefs() {
+        return classDefs;
+    }
+
+    /**
+     * Gets the class data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the class data section
+     */
+    /*package*/ MixedItemSection getClassData() {
+        return classData;
+    }
+
+    /**
+     * Gets the type identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the class identifiers section
+     */
+    /*package*/ TypeIdsSection getTypeIds() {
+        return typeIds;
+    }
+
+    /**
+     * Gets the prototype identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the prototype identifiers section
+     */
+    /*package*/ ProtoIdsSection getProtoIds() {
+        return protoIds;
+    }
+
+    /**
+     * Gets the field identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the field identifiers section
+     */
+    /*package*/ FieldIdsSection getFieldIds() {
+        return fieldIds;
+    }
+
+    /**
+     * Gets the method identifiers section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the method identifiers section
+     */
+    /*package*/ MethodIdsSection getMethodIds() {
+        return methodIds;
+    }
+
+    /**
+     * Gets the byte data section.
+     *
+     * <p>This is package-scope in order to allow
+     * the various {@link Item} instances to add items to the
+     * instance.</p>
+     *
+     * @return {@code non-null;} the byte data section
+     */
+    /*package*/ MixedItemSection getByteData() {
+        return byteData;
+    }
+
+    /**
+     * Gets the first section of the file that is to be considered
+     * part of the data section.
+     *
+     * <p>This is package-scope in order to allow the header section
+     * to query it.</p>
+     *
+     * @return {@code non-null;} the section
+     */
+    /*package*/ Section getFirstDataSection() {
+        return wordData;
+    }
+
+    /**
+     * Gets the last section of the file that is to be considered
+     * part of the data section.
+     *
+     * <p>This is package-scope in order to allow the header section
+     * to query it.</p>
+     *
+     * @return {@code non-null;} the section
+     */
+    /*package*/ Section getLastDataSection() {
+        return map;
+    }
+
+    /**
+     * Interns the given constant in the appropriate section of this
+     * instance, or do nothing if the given constant isn't the sort
+     * that should be interned.
+     *
+     * @param cst {@code non-null;} constant to possibly intern
+     */
+    /*package*/ void internIfAppropriate(Constant cst) {
+        if (cst instanceof CstString) {
+            stringIds.intern((CstString) cst);
+        } else if (cst instanceof CstType) {
+            typeIds.intern((CstType) cst);
+        } else if (cst instanceof CstBaseMethodRef) {
+            methodIds.intern((CstBaseMethodRef) cst);
+        } else if (cst instanceof CstFieldRef) {
+            fieldIds.intern((CstFieldRef) cst);
+        } else if (cst instanceof CstEnumRef) {
+            fieldIds.intern(((CstEnumRef) cst).getFieldRef());
+        } else if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+    }
+
+    /**
+     * Gets the {@link IndexedItem} corresponding to the given constant,
+     * if it is a constant that has such a correspondence, or return
+     * {@code null} if it isn't such a constant. This will throw
+     * an exception if the given constant <i>should</i> have been found
+     * but wasn't.
+     *
+     * @param cst {@code non-null;} the constant to look up
+     * @return {@code null-ok;} its corresponding item, if it has a corresponding
+     * item, or {@code null} if it's not that sort of constant
+     */
+    /*package*/ IndexedItem findItemOrNull(Constant cst) {
+        IndexedItem item;
+
+        if (cst instanceof CstString) {
+            return stringIds.get(cst);
+        } else if (cst instanceof CstType) {
+            return typeIds.get(cst);
+        } else if (cst instanceof CstBaseMethodRef) {
+            return methodIds.get(cst);
+        } else if (cst instanceof CstFieldRef) {
+            return fieldIds.get(cst);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the contents of this instance as a {@code .dex} file,
+     * in a {@link ByteArrayAnnotatedOutput} instance.
+     *
+     * @param annotate whether or not to keep annotations
+     * @param verbose if annotating, whether to be verbose
+     * @return {@code non-null;} a {@code .dex} file for this instance
+     */
+    private ByteArrayAnnotatedOutput toDex0(boolean annotate,
+            boolean verbose) {
+        /*
+         * The following is ordered so that the prepare() calls which
+         * add items happen before the calls to the sections that get
+         * added to.
+         */
+
+        classDefs.prepare();
+        classData.prepare();
+        wordData.prepare();
+        byteData.prepare();
+        methodIds.prepare();
+        fieldIds.prepare();
+        protoIds.prepare();
+        typeLists.prepare();
+        typeIds.prepare();
+        stringIds.prepare();
+        stringData.prepare();
+        header.prepare();
+
+        // Place the sections within the file.
+
+        int count = sections.length;
+        int offset = 0;
+
+        for (int i = 0; i < count; i++) {
+            Section one = sections[i];
+            int placedAt = one.setFileOffset(offset);
+            if (placedAt < offset) {
+                throw new RuntimeException("bogus placement for section " + i);
+            }
+
+            try {
+                if (one == map) {
+                    /*
+                     * Inform the map of all the sections, and add it
+                     * to the file. This can only be done after all
+                     * the other items have been sorted and placed.
+                     */
+                    MapItem.addMap(sections, map);
+                    map.prepare();
+                }
+
+                if (one instanceof MixedItemSection) {
+                    /*
+                     * Place the items of a MixedItemSection that just
+                     * got placed.
+                     */
+                    ((MixedItemSection) one).placeItems();
+                }
+
+                offset = placedAt + one.writeSize();
+            } catch (RuntimeException ex) {
+                throw ExceptionWithContext.withContext(ex,
+                        "...while writing section " + i);
+            }
+        }
+
+        // Write out all the sections.
+
+        fileSize = offset;
+        byte[] barr = new byte[fileSize];
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr);
+
+        if (annotate) {
+            out.enableAnnotations(dumpWidth, verbose);
+        }
+
+        for (int i = 0; i < count; i++) {
+            try {
+                Section one = sections[i];
+                int zeroCount = one.getFileOffset() - out.getCursor();
+                if (zeroCount < 0) {
+                    throw new ExceptionWithContext("excess write of " +
+                            (-zeroCount));
+                }
+                out.writeZeroes(one.getFileOffset() - out.getCursor());
+                one.writeTo(out);
+            } catch (RuntimeException ex) {
+                ExceptionWithContext ec;
+                if (ex instanceof ExceptionWithContext) {
+                    ec = (ExceptionWithContext) ex;
+                } else {
+                    ec = new ExceptionWithContext(ex);
+                }
+                ec.addContext("...while writing section " + i);
+                throw ec;
+            }
+        }
+
+        if (out.getCursor() != fileSize) {
+            throw new RuntimeException("foreshortened write");
+        }
+
+        // Perform final bookkeeping.
+
+        calcSignature(barr);
+        calcChecksum(barr);
+
+        if (annotate) {
+            wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM,
+                    "\nmethod code index:\n\n");
+            getStatistics().writeAnnotation(out);
+            out.finishAnnotating();
+        }
+
+        return out;
+    }
+
+    /**
+     * Generates and returns statistics for all the items in the file.
+     *
+     * @return {@code non-null;} the statistics
+     */
+    public Statistics getStatistics() {
+        Statistics stats = new Statistics();
+
+        for (Section s : sections) {
+            stats.addAll(s);
+        }
+
+        return stats;
+    }
+
+    /**
+     * Calculates the signature for the {@code .dex} file in the
+     * given array, and modify the array to contain it.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     */
+    private static void calcSignature(byte[] bytes) {
+        MessageDigest md;
+
+        try {
+            md = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException ex) {
+            throw new RuntimeException(ex);
+        }
+
+        md.update(bytes, 32, bytes.length - 32);
+
+        try {
+            int amt = md.digest(bytes, 12, 20);
+            if (amt != 20) {
+                throw new RuntimeException("unexpected digest write: " + amt +
+                                           " bytes");
+            }
+        } catch (DigestException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Calculates the checksum for the {@code .dex} file in the
+     * given array, and modify the array to contain it.
+     *
+     * @param bytes {@code non-null;} the bytes of the file
+     */
+    private static void calcChecksum(byte[] bytes) {
+        Adler32 a32 = new Adler32();
+
+        a32.update(bytes, 12, bytes.length - 12);
+
+        int sum = (int) a32.getValue();
+
+        bytes[8]  = (byte) sum;
+        bytes[9]  = (byte) (sum >> 8);
+        bytes[10] = (byte) (sum >> 16);
+        bytes[11] = (byte) (sum >> 24);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
new file mode 100644
index 0000000..3d05ab3
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstArray;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Encoded array of constant values.
+ */
+public final class EncodedArrayItem extends OffsettedItem {
+    /** the required alignment for instances of this class */
+    private static final int ALIGNMENT = 1;
+
+    /** {@code non-null;} the array to represent */
+    private final CstArray array;
+
+    /**
+     * {@code null-ok;} encoded form, ready for writing to a file; set during
+     * {@link #place0}
+     */
+    private byte[] encodedForm;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param array {@code non-null;} array to represent
+     */
+    public EncodedArrayItem(CstArray array) {
+        /*
+         * The write size isn't known up-front because (the variable-lengthed)
+         * leb128 type is used to represent some things.
+         */
+        super(ALIGNMENT, -1);
+
+        if (array == null) {
+            throw new NullPointerException("array == null");
+        }
+
+        this.array = array;
+        this.encodedForm = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_ENCODED_ARRAY_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return array.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        EncodedArrayItem otherArray = (EncodedArrayItem) other;
+
+        return array.compareTo(otherArray.array);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return array.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        ValueEncoder.addContents(file, array);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        // Encode the data and note the size.
+
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
+        ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
+
+        encoder.writeArray(array, false);
+        encodedForm = out.toByteArray();
+        setWriteSize(encodedForm.length);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+
+        if (annotates) {
+            out.annotate(0, offsetString() + " encoded array");
+
+            /*
+             * The output is to be annotated, so redo the work previously
+             * done by place0(), except this time annotations will actually
+             * get emitted.
+             */
+            ValueEncoder encoder = new ValueEncoder(file, out);
+            encoder.writeArray(array, true);
+        } else {
+            out.write(encodedForm);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/EncodedField.java b/dx/src/com/android/dx/dex/file/EncodedField.java
new file mode 100644
index 0000000..fdfa5d2
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/EncodedField.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.Leb128Utils;
+
+import java.io.PrintWriter;
+
+/**
+ * Representation of a field of a class, of any sort.
+ */
+public final class EncodedField extends EncodedMember
+        implements Comparable<EncodedField> {
+    /** {@code non-null;} constant for the field */
+    private final CstFieldRef field;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param field {@code non-null;} constant for the field
+     * @param accessFlags access flags
+     */
+    public EncodedField(CstFieldRef field, int accessFlags) {
+        super(accessFlags);
+
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        /*
+         * TODO: Maybe check accessFlags, at least for
+         * easily-checked stuff?
+         */
+
+        this.field = field;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return field.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof EncodedField)) {
+            return false;
+        }
+
+        return compareTo((EncodedField) other) == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> This compares the method constants only,
+     * ignoring any associated code, because it should never be the
+     * case that two different items with the same method constant
+     * ever appear in the same list (or same file, even).</p>
+     */
+    public int compareTo(EncodedField other) {
+        return field.compareTo(other.field);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(Hex.u2(getAccessFlags()));
+        sb.append(' ');
+        sb.append(field);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        FieldIdsSection fieldIds = file.getFieldIds();
+        fieldIds.intern(field);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public CstString getName() {
+        return field.getNat().getName();
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return field.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void debugPrint(PrintWriter out, boolean verbose) {
+        // TODO: Maybe put something better here?
+        out.println(toString());
+    }
+
+    /**
+     * Gets the constant for the field.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstFieldRef getRef() {
+        return field;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int encode(DexFile file, AnnotatedOutput out,
+            int lastIndex, int dumpSeq) {
+        int fieldIdx = file.getFieldIds().indexOf(field);
+        int diff = fieldIdx - lastIndex;
+        int accessFlags = getAccessFlags();
+
+        if (out.annotates()) {
+            out.annotate(0, String.format("  [%x] %s", dumpSeq,
+                            field.toHuman()));
+            out.annotate(Leb128Utils.unsignedLeb128Size(diff),
+                    "    field_idx:    " + Hex.u4(fieldIdx));
+            out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
+                    "    access_flags: " +
+                    AccessFlags.fieldString(accessFlags));
+        }
+
+        out.writeUleb128(diff);
+        out.writeUleb128(accessFlags);
+
+        return fieldIdx;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/EncodedMember.java b/dx/src/com/android/dx/dex/file/EncodedMember.java
new file mode 100644
index 0000000..6277646
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/EncodedMember.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ToHuman;
+
+import java.io.PrintWriter;
+
+/**
+ * Representation of a member (field or method) of a class, for the
+ * purposes of encoding it inside a {@link ClassDataItem}.
+ */
+public abstract class EncodedMember implements ToHuman {
+    /** access flags */
+    private final int accessFlags;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param accessFlags access flags for the member
+     */
+    public EncodedMember(int accessFlags) {
+        this.accessFlags = accessFlags;
+    }
+
+    /**
+     * Gets the access flags.
+     *
+     * @return the access flags
+     */
+    public final int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /**
+     * Gets the name.
+     *
+     * @return {@code non-null;} the name
+     */
+    public abstract CstString getName();
+
+    /**
+     * Does a human-friendly dump of this instance.
+     *
+     * @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);
+
+    /**
+     * Populates a {@link DexFile} with items from within this instance.
+     *
+     * @param file {@code non-null;} the file to populate
+     */
+    public abstract void addContents(DexFile file);
+
+    /**
+     * Encodes this instance to the given output.
+     *
+     * @param file {@code non-null;} file this instance is part of
+     * @param out {@code non-null;} where to write to
+     * @param lastIndex {@code >= 0;} the previous member index value encoded, or
+     * {@code 0} if this is the first element to encode
+     * @param dumpSeq {@code >= 0;} sequence number of this instance for
+     * annotation purposes
+     * @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
new file mode 100644
index 0000000..c3f71b7
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/EncodedMethod.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.rop.code.AccessFlags;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.Leb128Utils;
+
+import java.io.PrintWriter;
+
+/**
+ * Class that representats a method of a class.
+ */
+public final class EncodedMethod extends EncodedMember
+        implements Comparable<EncodedMethod> {
+    /** {@code non-null;} constant for the method */
+    private final CstMethodRef method;
+
+    /**
+     * {@code null-ok;} code for the method, if the method is neither
+     * {@code abstract} nor {@code native}
+     */
+    private final CodeItem code;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} constant for the method
+     * @param accessFlags access flags
+     * @param code {@code null-ok;} code for the method, if it is neither
+     * {@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,
+            DalvCode code, TypeList throwsList) {
+        super(accessFlags);
+
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        this.method = method;
+
+        if (code == null) {
+            this.code = null;
+        } else {
+            boolean isStatic = (accessFlags & AccessFlags.ACC_STATIC) != 0;
+            this.code = new CodeItem(method, code, isStatic, throwsList);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof EncodedMethod)) {
+            return false;
+        }
+
+        return compareTo((EncodedMethod) other) == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p><b>Note:</b> This compares the method constants only,
+     * ignoring any associated code, because it should never be the
+     * case that two different items with the same method constant
+     * ever appear in the same list (or same file, even).</p>
+     */
+    public int compareTo(EncodedMethod other) {
+        return method.compareTo(other.method);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(Hex.u2(getAccessFlags()));
+        sb.append(' ');
+        sb.append(method);
+
+        if (code != null) {
+            sb.append(' ');
+            sb.append(code);
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        MethodIdsSection methodIds = file.getMethodIds();
+        MixedItemSection wordData = file.getWordData();
+
+        methodIds.intern(method);
+
+        if (code != null) {
+            wordData.add(code);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public final String toHuman() {
+        return method.toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final CstString getName() {
+        return method.getNat().getName();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void debugPrint(PrintWriter out, boolean verbose) {
+        if (code == null) {
+            out.println(getRef().toHuman() + ": abstract or native");
+        } else {
+            code.debugPrint(out, "  ", verbose);
+        }
+    }
+
+    /**
+     * Gets the constant for the method.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public final CstMethodRef getRef() {
+        return method;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int encode(DexFile file, AnnotatedOutput out,
+            int lastIndex, int dumpSeq) {
+        int methodIdx = file.getMethodIds().indexOf(method);
+        int diff = methodIdx - lastIndex;
+        int accessFlags = getAccessFlags();
+        int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code);
+        boolean hasCode = (codeOff != 0);
+        boolean shouldHaveCode = (accessFlags &
+                (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0;
+
+        /*
+         * Verify that code appears if and only if a method is
+         * declared to have it.
+         */
+        if (hasCode != shouldHaveCode) {
+            throw new UnsupportedOperationException(
+                    "code vs. access_flags mismatch");
+        }
+
+        if (out.annotates()) {
+            out.annotate(0, String.format("  [%x] %s", dumpSeq,
+                            method.toHuman()));
+            out.annotate(Leb128Utils.unsignedLeb128Size(diff),
+                    "    method_idx:   " + Hex.u4(methodIdx));
+            out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags),
+                    "    access_flags: " +
+                    AccessFlags.methodString(accessFlags));
+            out.annotate(Leb128Utils.unsignedLeb128Size(codeOff),
+                    "    code_off:     " + Hex.u4(codeOff));
+        }
+
+        out.writeUleb128(diff);
+        out.writeUleb128(accessFlags);
+        out.writeUleb128(codeOff);
+
+        return methodIdx;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
new file mode 100644
index 0000000..f363d41
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.ToHuman;
+
+/**
+ * Association of a field and its annotations.
+ */
+public final class FieldAnnotationStruct
+        implements ToHuman, Comparable<FieldAnnotationStruct> {
+    /** {@code non-null;} the field in question */
+    private final CstFieldRef field;
+
+    /** {@code non-null;} the associated annotations */
+    private AnnotationSetItem annotations;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param field {@code non-null;} the field in question
+     * @param annotations {@code non-null;} the associated annotations
+     */
+    public FieldAnnotationStruct(CstFieldRef field,
+            AnnotationSetItem annotations) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.field = field;
+        this.annotations = annotations;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return field.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof FieldAnnotationStruct)) {
+            return false;
+        }
+
+        return field.equals(((FieldAnnotationStruct) other).field);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(FieldAnnotationStruct other) {
+        return field.compareTo(other.field);
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        FieldIdsSection fieldIds = file.getFieldIds();
+        MixedItemSection wordData = file.getWordData();
+
+        fieldIds.intern(field);
+        annotations = wordData.intern(annotations);
+    }
+
+    /** {@inheritDoc} */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int fieldIdx = file.getFieldIds().indexOf(field);
+        int annotationsOff = annotations.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, "    " + field.toHuman());
+            out.annotate(4, "      field_idx:       " + Hex.u4(fieldIdx));
+            out.annotate(4, "      annotations_off: " +
+                    Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(fieldIdx);
+        out.writeInt(annotationsOff);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return field.toHuman() + ": " + annotations;
+    }
+
+    /**
+     * Gets the field this item is for.
+     *
+     * @return {@code non-null;} the field
+     */
+    public CstFieldRef getField() {
+        return field;
+    }
+
+    /**
+     * Gets the associated 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
new file mode 100644
index 0000000..ecb1d3d
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/FieldIdItem.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstFieldRef;
+
+/**
+ * Representation of a field reference inside a Dalvik file.
+ */
+public final class FieldIdItem extends MemberIdItem {
+    /**
+     * Constructs an instance.
+     *
+     * @param field {@code non-null;} the constant for the field
+     */
+    public FieldIdItem(CstFieldRef field) {
+        super(field);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_FIELD_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        super.addContents(file);
+
+        TypeIdsSection typeIds = file.getTypeIds();
+        typeIds.intern(getFieldRef().getType());
+    }
+
+    /**
+     * Gets the field constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstFieldRef getFieldRef() {
+        return (CstFieldRef) getRef();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getTypoidIdx(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        return typeIds.indexOf(getFieldRef().getType());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String getTypoidName() {
+        return "type_idx";
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/FieldIdsSection.java b/dx/src/com/android/dx/dex/file/FieldIdsSection.java
new file mode 100644
index 0000000..c320731
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/FieldIdsSection.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Field refs list section of a {@code .dex} file.
+ */
+public final class FieldIdsSection extends MemberIdsSection {
+    /**
+     * {@code non-null;} map from field constants to {@link
+     * FieldIdItem} instances
+     */
+    private final TreeMap<CstFieldRef, FieldIdItem> fieldIds;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public FieldIdsSection(DexFile file) {
+        super("field_ids", file);
+
+        fieldIds = new TreeMap<CstFieldRef, FieldIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return fieldIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        IndexedItem result = fieldIds.get((CstFieldRef) cst);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = fieldIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "field_ids_size:  " + Hex.u4(sz));
+            out.annotate(4, "field_ids_off:   " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param field {@code non-null;} the reference to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public FieldIdItem intern(CstFieldRef field) {
+        if (field == null) {
+            throw new NullPointerException("field == null");
+        }
+
+        throwIfPrepared();
+
+        FieldIdItem result = fieldIds.get(field);
+
+        if (result == null) {
+            result = new FieldIdItem(field);
+            fieldIds.put(field, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given reference, which must have been added
+     * to this instance.
+     *
+     * @param ref {@code non-null;} the reference to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(CstFieldRef ref) {
+        if (ref == null) {
+            throw new NullPointerException("ref == null");
+        }
+
+        throwIfNotPrepared();
+
+        FieldIdItem item = fieldIds.get(ref);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return item.getIndex();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/HeaderItem.java b/dx/src/com/android/dx/dex/file/HeaderItem.java
new file mode 100644
index 0000000..3816eb8
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/HeaderItem.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.DexFormat;
+import com.android.dx.dex.SizeOf;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * File header section of a {@code .dex} file.
+ */
+public final class HeaderItem extends IndexedItem {
+    /**
+     * Constructs an instance.
+     */
+    public HeaderItem() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_HEADER_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return SizeOf.HEADER_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // Nothing to do here.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int mapOff = file.getMap().getFileOffset();
+        Section firstDataSection = file.getFirstDataSection();
+        Section lastDataSection = file.getLastDataSection();
+        int dataOff = firstDataSection.getFileOffset();
+        int dataSize = lastDataSection.getFileOffset() +
+            lastDataSection.writeSize() - dataOff;
+
+        String magic = file.getDexOptions().getMagic();
+
+        if (out.annotates()) {
+            out.annotate(8, "magic: " + new CstString(magic).toQuoted());
+            out.annotate(4, "checksum");
+            out.annotate(20, "signature");
+            out.annotate(4, "file_size:       " +
+                         Hex.u4(file.getFileSize()));
+            out.annotate(4, "header_size:     " + Hex.u4(SizeOf.HEADER_ITEM));
+            out.annotate(4, "endian_tag:      " + Hex.u4(DexFormat.ENDIAN_TAG));
+            out.annotate(4, "link_size:       0");
+            out.annotate(4, "link_off:        0");
+            out.annotate(4, "map_off:         " + Hex.u4(mapOff));
+        }
+
+        // Write the magic number.
+        for (int i = 0; i < 8; i++) {
+            out.writeByte(magic.charAt(i));
+        }
+
+        // Leave space for the checksum and signature.
+        out.writeZeroes(24);
+
+        out.writeInt(file.getFileSize());
+        out.writeInt(SizeOf.HEADER_ITEM);
+        out.writeInt(DexFormat.ENDIAN_TAG);
+
+        /*
+         * Write zeroes for the link size and data, as the output
+         * isn't a staticly linked file.
+         */
+        out.writeZeroes(8);
+
+        out.writeInt(mapOff);
+
+        // Write out each section's respective header part.
+        file.getStringIds().writeHeaderPart(out);
+        file.getTypeIds().writeHeaderPart(out);
+        file.getProtoIds().writeHeaderPart(out);
+        file.getFieldIds().writeHeaderPart(out);
+        file.getMethodIds().writeHeaderPart(out);
+        file.getClassDefs().writeHeaderPart(out);
+
+        if (out.annotates()) {
+            out.annotate(4, "data_size:       " + Hex.u4(dataSize));
+            out.annotate(4, "data_off:        " + Hex.u4(dataOff));
+        }
+
+        out.writeInt(dataSize);
+        out.writeInt(dataOff);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/HeaderSection.java b/dx/src/com/android/dx/dex/file/HeaderSection.java
new file mode 100644
index 0000000..21da488
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/HeaderSection.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * File header section of a {@code .dex} file.
+ */
+public final class HeaderSection extends UniformItemSection {
+    /** {@code non-null;} the list of the one item in the section */
+    private final List<HeaderItem> list;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public HeaderSection(DexFile file) {
+        super(null, file, 4);
+
+        HeaderItem item = new HeaderItem();
+        item.setIndex(0);
+
+        this.list = Collections.singletonList(item);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        // Nothing to do here.
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/IdItem.java b/dx/src/com/android/dx/dex/file/IdItem.java
new file mode 100644
index 0000000..1bd2b5f
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/IdItem.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstType;
+
+/**
+ * Representation of a reference to an item inside a Dalvik file.
+ */
+public abstract class IdItem extends IndexedItem {
+    /**
+     * {@code non-null;} the type constant for the defining class of
+     * the reference
+     */
+    private final CstType type;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the type constant for the defining
+     * class of the reference
+     */
+    public IdItem(CstType type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        this.type = type;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        typeIds.intern(type);
+    }
+
+    /**
+     * Gets the type constant for the defining class of the
+     * reference.
+     *
+     * @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
new file mode 100644
index 0000000..9ba4783
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/IndexedItem.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+/**
+ * An item in a Dalvik file which is referenced by index.
+ */
+public abstract class IndexedItem extends Item {
+    /** {@code >= -1;} assigned index of the item, or {@code -1} if not
+     * yet assigned */
+    private int index;
+
+    /**
+     * Constructs an instance. The index is initially unassigned.
+     */
+    public IndexedItem() {
+        index = -1;
+    }
+
+    /**
+     * Gets whether or not this instance has been assigned an index.
+     *
+     * @return {@code true} iff this instance has been assigned an index
+     */
+    public final boolean hasIndex() {
+        return (index >= 0);
+    }
+
+    /**
+     * Gets the item index.
+     *
+     * @return {@code >= 0;} the index
+     * @throws RuntimeException thrown if the item index is not yet assigned
+     */
+    public final int getIndex() {
+        if (index < 0) {
+            throw new RuntimeException("index not yet set");
+        }
+
+        return index;
+    }
+
+    /**
+     * Sets the item index. This method may only ever be called once
+     * per instance, and this will throw a {@code RuntimeException} if
+     * called a second (or subsequent) time.
+     *
+     * @param index {@code >= 0;} the item index
+     */
+    public final void setIndex(int index) {
+        if (this.index != -1) {
+            throw new RuntimeException("index already set");
+        }
+
+        this.index = index;
+    }
+
+    /**
+     * Gets the index of this item as a string, suitable for including in
+     * annotations.
+     *
+     * @return {@code non-null;} the index string
+     */
+    public final String indexString() {
+        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
new file mode 100644
index 0000000..cf2b380
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/Item.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+
+/**
+ * Base class for any structurally-significant and (potentially)
+ * repeated piece of a Dalvik file.
+ */
+public abstract class Item {
+    /**
+     * Constructs an instance.
+     */
+    public Item() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Returns the item type for this instance.
+     *
+     * @return {@code non-null;} the item type
+     */
+    public abstract ItemType itemType();
+
+    /**
+     * Returns the human name for the particular type of item this
+     * instance is.
+     *
+     * @return {@code non-null;} the name
+     */
+    public final String typeName() {
+        return itemType().toHuman();
+    }
+
+    /**
+     * Gets the size of this instance when written, in bytes.
+     *
+     * @return {@code >= 0;} the write size
+     */
+    public abstract int writeSize();
+
+    /**
+     * Populates a {@link DexFile} with items from within this instance.
+     * This will <i>not</i> add an item to the file for this instance itself
+     * (which should have been done by whatever refers to this instance).
+     *
+     * <p><b>Note:</b> Subclasses must override this to do something
+     * appropriate.</p>
+     *
+     * @param file {@code non-null;} the file to populate
+     */
+    public abstract void addContents(DexFile file);
+
+    /**
+     * Writes the representation of this instance to the given data section,
+     * using the given {@link DexFile} to look things up as needed.
+     * If this instance keeps track of its offset, then this method will
+     * note the written offset and will also throw an exception if this
+     * instance has already been written.
+     *
+     * @param file {@code non-null;} the file to use for reference
+     * @param out {@code non-null;} where to write to
+     */
+    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
new file mode 100644
index 0000000..2fe97ab
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ItemType.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.ToHuman;
+
+/**
+ * Enumeration of all the top-level item types.
+ */
+public enum ItemType implements ToHuman {
+    TYPE_HEADER_ITEM(               0x0000, "header_item"),
+    TYPE_STRING_ID_ITEM(            0x0001, "string_id_item"),
+    TYPE_TYPE_ID_ITEM(              0x0002, "type_id_item"),
+    TYPE_PROTO_ID_ITEM(             0x0003, "proto_id_item"),
+    TYPE_FIELD_ID_ITEM(             0x0004, "field_id_item"),
+    TYPE_METHOD_ID_ITEM(            0x0005, "method_id_item"),
+    TYPE_CLASS_DEF_ITEM(            0x0006, "class_def_item"),
+    TYPE_MAP_LIST(                  0x1000, "map_list"),
+    TYPE_TYPE_LIST(                 0x1001, "type_list"),
+    TYPE_ANNOTATION_SET_REF_LIST(   0x1002, "annotation_set_ref_list"),
+    TYPE_ANNOTATION_SET_ITEM(       0x1003, "annotation_set_item"),
+    TYPE_CLASS_DATA_ITEM(           0x2000, "class_data_item"),
+    TYPE_CODE_ITEM(                 0x2001, "code_item"),
+    TYPE_STRING_DATA_ITEM(          0x2002, "string_data_item"),
+    TYPE_DEBUG_INFO_ITEM(           0x2003, "debug_info_item"),
+    TYPE_ANNOTATION_ITEM(           0x2004, "annotation_item"),
+    TYPE_ENCODED_ARRAY_ITEM(        0x2005, "encoded_array_item"),
+    TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"),
+    TYPE_MAP_ITEM(                  -1,     "map_item"),
+    TYPE_TYPE_ITEM(                 -1,     "type_item"),
+    TYPE_EXCEPTION_HANDLER_ITEM(    -1,     "exception_handler_item"),
+    TYPE_ANNOTATION_SET_REF_ITEM(   -1,     "annotation_set_ref_item");
+
+    /** value when represented in a {@link MapItem} */
+    private final int mapValue;
+
+    /** {@code non-null;} name of the type */
+    private final String typeName;
+
+    /** {@code non-null;} the short human name */
+    private final String humanName;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param mapValue value when represented in a {@link MapItem}
+     * @param typeName {@code non-null;} name of the type
+     */
+    private ItemType(int mapValue, String typeName) {
+        this.mapValue = mapValue;
+        this.typeName = typeName;
+
+        // Make the human name.
+        String human = typeName;
+        if (human.endsWith("_item")) {
+            human = human.substring(0, human.length() - 5);
+        }
+        this.humanName = human.replace('_', ' ');
+    }
+
+    /**
+     * Gets the map value.
+     *
+     * @return the map value
+     */
+    public int getMapValue() {
+        return mapValue;
+    }
+
+    /**
+     * Gets the type name.
+     *
+     * @return {@code non-null;} the type name
+     */
+    public String getTypeName() {
+        return typeName;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return humanName;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/MapItem.java b/dx/src/com/android/dx/dex/file/MapItem.java
new file mode 100644
index 0000000..d78dc91
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MapItem.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.ArrayList;
+
+/**
+ * Class that represents a map item.
+ */
+public final class MapItem extends OffsettedItem {
+    /** file alignment of this class, in bytes */
+    private static final int ALIGNMENT = 4;
+
+    /** write size of this class, in bytes: three {@code uint}s */
+    private static final int WRITE_SIZE = (4 * 3);
+
+    /** {@code non-null;} item type this instance covers */
+    private final ItemType type;
+
+    /** {@code non-null;} section this instance covers */
+    private final Section section;
+
+    /**
+     * {@code null-ok;} first item covered or {@code null} if this is
+     * a self-reference
+     */
+    private final Item firstItem;
+
+    /**
+     * {@code null-ok;} last item covered or {@code null} if this is
+     * a self-reference
+     */
+    private final Item lastItem;
+
+    /**
+     * {@code > 0;} count of items covered; {@code 1} if this
+     * is a self-reference
+     */
+    private final int itemCount;
+
+    /**
+     * Constructs a list item with instances of this class representing
+     * the contents of the given array of sections, adding it to the
+     * given map section.
+     *
+     * @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,
+            MixedItemSection mapSection) {
+        if (sections == null) {
+            throw new NullPointerException("sections == null");
+        }
+
+        if (mapSection.items().size() != 0) {
+            throw new IllegalArgumentException(
+                    "mapSection.items().size() != 0");
+        }
+
+        ArrayList<MapItem> items = new ArrayList<MapItem>(50);
+
+        for (Section section : sections) {
+            ItemType currentType = null;
+            Item firstItem = null;
+            Item lastItem = null;
+            int count = 0;
+
+            for (Item item : section.items()) {
+                ItemType type = item.itemType();
+                if (type != currentType) {
+                    if (count != 0) {
+                        items.add(new MapItem(currentType, section,
+                                        firstItem, lastItem, count));
+                    }
+                    currentType = type;
+                    firstItem = item;
+                    count = 0;
+                }
+                lastItem = item;
+                count++;
+            }
+
+            if (count != 0) {
+                // Add a MapItem for the final items in the section.
+                items.add(new MapItem(currentType, section,
+                                firstItem, lastItem, count));
+            } else if (section == mapSection) {
+                // Add a MapItem for the self-referential section.
+                items.add(new MapItem(mapSection));
+            }
+        }
+
+        mapSection.add(
+                new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items));
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} item type this instance covers
+     * @param section {@code non-null;} section this instance covers
+     * @param firstItem {@code non-null;} first item covered
+     * @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) {
+        super(ALIGNMENT, WRITE_SIZE);
+
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (section == null) {
+            throw new NullPointerException("section == null");
+        }
+
+        if (firstItem == null) {
+            throw new NullPointerException("firstItem == null");
+        }
+
+        if (lastItem == null) {
+            throw new NullPointerException("lastItem == null");
+        }
+
+        if (itemCount <= 0) {
+            throw new IllegalArgumentException("itemCount <= 0");
+        }
+
+        this.type = type;
+        this.section = section;
+        this.firstItem = firstItem;
+        this.lastItem = lastItem;
+        this.itemCount = itemCount;
+    }
+
+    /**
+     * Constructs a self-referential instance. This instance is meant to
+     * represent the section containing the {@code map_list}.
+     *
+     * @param section {@code non-null;} section this instance covers
+     */
+    private MapItem(Section section) {
+        super(ALIGNMENT, WRITE_SIZE);
+
+        if (section == null) {
+            throw new NullPointerException("section == null");
+        }
+
+        this.type = ItemType.TYPE_MAP_LIST;
+        this.section = section;
+        this.firstItem = null;
+        this.lastItem = null;
+        this.itemCount = 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_MAP_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append('{');
+        sb.append(section.toString());
+        sb.append(' ');
+        sb.append(type.toHuman());
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // We have nothing to add.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toHuman() {
+        return toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        int value = type.getMapValue();
+        int offset;
+
+        if (firstItem == null) {
+            offset = section.getFileOffset();
+        } else {
+            offset = section.getAbsoluteItemOffset(firstItem);
+        }
+
+        if (out.annotates()) {
+            out.annotate(0, offsetString() + ' ' + type.getTypeName() +
+                    " map");
+            out.annotate(2, "  type:   " + Hex.u2(value) + " // " +
+                    type.toString());
+            out.annotate(2, "  unused: 0");
+            out.annotate(4, "  size:   " + Hex.u4(itemCount));
+            out.annotate(4, "  offset: " + Hex.u4(offset));
+        }
+
+        out.writeShort(value);
+        out.writeShort(0); // unused
+        out.writeInt(itemCount);
+        out.writeInt(offset);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/MemberIdItem.java b/dx/src/com/android/dx/dex/file/MemberIdItem.java
new file mode 100644
index 0000000..08a3123
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MemberIdItem.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstMemberRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.dex.SizeOf;
+
+/**
+ * Representation of a member (field or method) reference inside a
+ * Dalvik file.
+ */
+public abstract class MemberIdItem extends IdItem {
+    /** {@code non-null;} the constant for the member */
+    private final CstMemberRef cst;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cst {@code non-null;} the constant for the member
+     */
+    public MemberIdItem(CstMemberRef cst) {
+        super(cst.getDefiningClass());
+
+        this.cst = cst;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return SizeOf.MEMBER_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        super.addContents(file);
+
+        StringIdsSection stringIds = file.getStringIds();
+        stringIds.intern(getRef().getNat().getName());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(DexFile file, AnnotatedOutput out) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        StringIdsSection stringIds = file.getStringIds();
+        CstNat nat = cst.getNat();
+        int classIdx = typeIds.indexOf(getDefiningClass());
+        int nameIdx = stringIds.indexOf(nat.getName());
+        int typoidIdx = getTypoidIdx(file);
+
+        if (out.annotates()) {
+            out.annotate(0, indexString() + ' ' + cst.toHuman());
+            out.annotate(2, "  class_idx: " + Hex.u2(classIdx));
+            out.annotate(2, String.format("  %-10s %s", getTypoidName() + ':',
+                            Hex.u2(typoidIdx)));
+            out.annotate(4, "  name_idx:  " + Hex.u4(nameIdx));
+        }
+
+        out.writeShort(classIdx);
+        out.writeShort(typoidIdx);
+        out.writeInt(nameIdx);
+    }
+
+    /**
+     * Returns the index of the type-like thing associated with
+     * this item, in order that it may be written out. Subclasses must
+     * override this to get whatever it is they need to store.
+     *
+     * @param file {@code non-null;} the file being written
+     * @return the index in question
+     */
+    protected abstract int getTypoidIdx(DexFile file);
+
+    /**
+     * Returns the field name of the type-like thing associated with
+     * this item, for listing-generating purposes. Subclasses must override
+     * this.
+     *
+     * @return {@code non-null;} the name in question
+     */
+    protected abstract String getTypoidName();
+
+    /**
+     * Gets the member constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public final CstMemberRef getRef() {
+        return cst;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/MemberIdsSection.java b/dx/src/com/android/dx/dex/file/MemberIdsSection.java
new file mode 100644
index 0000000..ef0d8cd
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MemberIdsSection.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.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 {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public MemberIdsSection(String name, DexFile file) {
+        super(name, file, 4);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (Object i : items()) {
+            ((MemberIdItem) i).setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
new file mode 100644
index 0000000..38f7ce4
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.ToHuman;
+
+/**
+ * Association of a method and its annotations.
+ */
+public final class MethodAnnotationStruct
+        implements ToHuman, Comparable<MethodAnnotationStruct> {
+    /** {@code non-null;} the method in question */
+    private final CstMethodRef method;
+
+    /** {@code non-null;} the associated annotations */
+    private AnnotationSetItem annotations;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method in question
+     * @param annotations {@code non-null;} the associated annotations
+     */
+    public MethodAnnotationStruct(CstMethodRef method,
+            AnnotationSetItem annotations) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (annotations == null) {
+            throw new NullPointerException("annotations == null");
+        }
+
+        this.method = method;
+        this.annotations = annotations;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return method.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof MethodAnnotationStruct)) {
+            return false;
+        }
+
+        return method.equals(((MethodAnnotationStruct) other).method);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(MethodAnnotationStruct other) {
+        return method.compareTo(other.method);
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MethodIdsSection methodIds = file.getMethodIds();
+        MixedItemSection wordData = file.getWordData();
+
+        methodIds.intern(method);
+        annotations = wordData.intern(annotations);
+    }
+
+    /** {@inheritDoc} */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int methodIdx = file.getMethodIds().indexOf(method);
+        int annotationsOff = annotations.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, "    " + method.toHuman());
+            out.annotate(4, "      method_idx:      " + Hex.u4(methodIdx));
+            out.annotate(4, "      annotations_off: " +
+                    Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(methodIdx);
+        out.writeInt(annotationsOff);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return method.toHuman() + ": " + annotations;
+    }
+
+    /**
+     * Gets the method this item is for.
+     *
+     * @return {@code non-null;} the method
+     */
+    public CstMethodRef getMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the associated 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
new file mode 100644
index 0000000..f2ff4f9
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MethodIdItem.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstBaseMethodRef;
+
+/**
+ * Representation of a method reference inside a Dalvik file.
+ */
+public final class MethodIdItem extends MemberIdItem {
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the constant for the method
+     */
+    public MethodIdItem(CstBaseMethodRef method) {
+        super(method);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_METHOD_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        super.addContents(file);
+
+        ProtoIdsSection protoIds = file.getProtoIds();
+        protoIds.intern(getMethodRef().getPrototype());
+    }
+
+    /**
+     * Gets the method constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public CstBaseMethodRef getMethodRef() {
+        return (CstBaseMethodRef) getRef();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int getTypoidIdx(DexFile file) {
+        ProtoIdsSection protoIds = file.getProtoIds();
+        return protoIds.indexOf(getMethodRef().getPrototype());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected String getTypoidName() {
+        return "proto_idx";
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/MethodIdsSection.java b/dx/src/com/android/dx/dex/file/MethodIdsSection.java
new file mode 100644
index 0000000..fa0cd3c
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MethodIdsSection.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstBaseMethodRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Method refs list section of a {@code .dex} file.
+ */
+public final class MethodIdsSection extends MemberIdsSection {
+    /**
+     * {@code non-null;} map from method constants to {@link
+     * MethodIdItem} instances
+     */
+    private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public MethodIdsSection(DexFile file) {
+        super("method_ids", file);
+
+        methodIds = new TreeMap<CstBaseMethodRef, MethodIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return methodIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        IndexedItem result = methodIds.get((CstBaseMethodRef) cst);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = methodIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "method_ids_size: " + Hex.u4(sz));
+            out.annotate(4, "method_ids_off:  " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param method {@code non-null;} the reference to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public MethodIdItem intern(CstBaseMethodRef method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        throwIfPrepared();
+
+        MethodIdItem result = methodIds.get(method);
+
+        if (result == null) {
+            result = new MethodIdItem(method);
+            methodIds.put(method, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given reference, which must have been added
+     * to this instance.
+     *
+     * @param ref {@code non-null;} the reference to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(CstBaseMethodRef ref) {
+        if (ref == null) {
+            throw new NullPointerException("ref == null");
+        }
+
+        throwIfNotPrepared();
+
+        MethodIdItem item = methodIds.get(ref);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return item.getIndex();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/MixedItemSection.java b/dx/src/com/android/dx/dex/file/MixedItemSection.java
new file mode 100644
index 0000000..b885306
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/MixedItemSection.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.TreeMap;
+
+/**
+ * A section of a {@code .dex} file which consists of a sequence of
+ * {@link OffsettedItem} objects, which may each be of a different concrete
+ * class and/or size.
+ *
+ * <b>Note:</b> It is invalid for an item in an instance of this class to
+ * have a larger alignment requirement than the alignment of this instance.
+ */
+public final class MixedItemSection extends Section {
+    static enum SortType {
+        /** no sorting */
+        NONE,
+
+        /** sort by type only */
+        TYPE,
+
+        /** sort in class-major order, with instances sorted per-class */
+        INSTANCE;
+    };
+
+    /** {@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) {
+            ItemType type1 = item1.itemType();
+            ItemType type2 = item2.itemType();
+            return type1.compareTo(type2);
+        }
+    };
+
+    /** {@code non-null;} the items in this part */
+    private final ArrayList<OffsettedItem> items;
+
+    /** {@code non-null;} items that have been explicitly interned */
+    private final HashMap<OffsettedItem, OffsettedItem> interns;
+
+    /** {@code non-null;} how to sort the items */
+    private final SortType sort;
+
+    /**
+     * {@code >= -1;} the current size of this part, in bytes, or {@code -1}
+     * if not yet calculated
+     */
+    private int writeSize;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param name {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     * @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
+     */
+    public MixedItemSection(String name, DexFile file, int alignment,
+            SortType sort) {
+        super(name, file, alignment);
+
+        this.items = new ArrayList<OffsettedItem>(100);
+        this.interns = new HashMap<OffsettedItem, OffsettedItem>(100);
+        this.sort = sort;
+        this.writeSize = -1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return items;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        throwIfNotPrepared();
+        return writeSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int getAbsoluteItemOffset(Item item) {
+        OffsettedItem oi = (OffsettedItem) item;
+        return oi.getAbsoluteOffset();
+    }
+
+    /**
+     * Gets the size of this instance, in items.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        return items.size();
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        if (writeSize == -1) {
+            throw new RuntimeException("write size not yet set");
+        }
+
+        int sz = writeSize;
+        int offset = (sz == 0) ? 0 : getFileOffset();
+        String name = getName();
+
+        if (name == null) {
+            name = "<unnamed>";
+        }
+
+        int spaceCount = 15 - name.length();
+        char[] spaceArr = new char[spaceCount];
+        Arrays.fill(spaceArr, ' ');
+        String spaces = new String(spaceArr);
+
+        if (out.annotates()) {
+            out.annotate(4, name + "_size:" + spaces + Hex.u4(sz));
+            out.annotate(4, name + "_off: " + spaces + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Adds an item to this instance. This will in turn tell the given item
+     * that it has been added to this instance. It is invalid to add the
+     * same item to more than one instance, nor to add the same items
+     * multiple times to a single instance.
+     *
+     * @param item {@code non-null;} the item to add
+     */
+    public void add(OffsettedItem item) {
+        throwIfPrepared();
+
+        try {
+            if (item.getAlignment() > getAlignment()) {
+                throw new IllegalArgumentException(
+                        "incompatible item alignment");
+            }
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("item == null");
+        }
+
+        items.add(item);
+    }
+
+    /**
+     * Interns an item in this instance, returning the interned instance
+     * (which may not be the one passed in). This will add the item if no
+     * equal item has been added.
+     *
+     * @param item {@code non-null;} the item to intern
+     * @return {@code non-null;} the equivalent interned instance
+     */
+    public <T extends OffsettedItem> T intern(T item) {
+        throwIfPrepared();
+
+        OffsettedItem result = interns.get(item);
+
+        if (result != null) {
+            return (T) result;
+        }
+
+        add(item);
+        interns.put(item, item);
+        return item;
+    }
+
+    /**
+     * Gets an item which was previously interned.
+     *
+     * @param item {@code non-null;} the item to look for
+     * @return {@code non-null;} the equivalent already-interned instance
+     */
+    public <T extends OffsettedItem> T get(T item) {
+        throwIfNotPrepared();
+
+        OffsettedItem result = interns.get(item);
+
+        if (result != null) {
+            return (T) result;
+        }
+
+        throw new NoSuchElementException(item.toString());
+    }
+
+    /**
+     * Writes an index of contents of the items in this instance of the
+     * given type. If there are none, this writes nothing. If there are any,
+     * then the index is preceded by the given intro string.
+     *
+     * @param out {@code non-null;} where to write to
+     * @param itemType {@code non-null;} the item type of interest
+     * @param intro {@code non-null;} the introductory string for non-empty indices
+     */
+    public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType,
+            String intro) {
+        throwIfNotPrepared();
+
+        TreeMap<String, OffsettedItem> index =
+            new TreeMap<String, OffsettedItem>();
+
+        for (OffsettedItem item : items) {
+            if (item.itemType() == itemType) {
+                String label = item.toHuman();
+                index.put(label, item);
+            }
+        }
+
+        if (index.size() == 0) {
+            return;
+        }
+
+        out.annotate(0, intro);
+
+        for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
+            String label = entry.getKey();
+            OffsettedItem item = entry.getValue();
+            out.annotate(0, item.offsetString() + ' ' + label + '\n');
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void prepare0() {
+        DexFile file = getFile();
+
+        /*
+         * It's okay for new items to be added as a result of an
+         * addContents() call; we just have to deal with the possibility.
+         */
+
+        int i = 0;
+        for (;;) {
+            int sz = items.size();
+            if (i >= sz) {
+                break;
+            }
+
+            for (/*i*/; i < sz; i++) {
+                OffsettedItem one = items.get(i);
+                one.addContents(file);
+            }
+        }
+    }
+
+    /**
+     * 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},
+     * 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.
+     */
+    public void placeItems() {
+        throwIfNotPrepared();
+
+        switch (sort) {
+            case INSTANCE: {
+                Collections.sort(items);
+                break;
+            }
+            case TYPE: {
+                Collections.sort(items, TYPE_SORTER);
+                break;
+            }
+        }
+
+        int sz = items.size();
+        int outAt = 0;
+        for (int i = 0; i < sz; i++) {
+            OffsettedItem one = items.get(i);
+            try {
+                int placedAt = one.place(this, outAt);
+
+                if (placedAt < outAt) {
+                    throw new RuntimeException("bogus place() result for " +
+                            one);
+                }
+
+                outAt = placedAt + one.writeSize();
+            } catch (RuntimeException ex) {
+                throw ExceptionWithContext.withContext(ex,
+                        "...while placing " + one);
+            }
+        }
+
+        writeSize = outAt;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(AnnotatedOutput out) {
+        boolean annotates = out.annotates();
+        boolean first = true;
+        DexFile file = getFile();
+        int at = 0;
+
+        for (OffsettedItem one : items) {
+            if (annotates) {
+                if (first) {
+                    first = false;
+                } else {
+                    out.annotate(0, "\n");
+                }
+            }
+
+            int alignMask = one.getAlignment() - 1;
+            int writeAt = (at + alignMask) & ~alignMask;
+
+            if (at != writeAt) {
+                out.writeZeroes(writeAt - at);
+                at = writeAt;
+            }
+
+            one.writeTo(file, out);
+            at += one.writeSize();
+        }
+
+        if (at != writeSize) {
+            throw new RuntimeException("output size mismatch");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/OffsettedItem.java b/dx/src/com/android/dx/dex/file/OffsettedItem.java
new file mode 100644
index 0000000..7721470
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/OffsettedItem.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ExceptionWithContext;
+
+/**
+ * An item in a Dalvik file which is referenced by absolute offset.
+ */
+public abstract class OffsettedItem extends Item
+        implements Comparable<OffsettedItem> {
+    /** {@code > 0;} alignment requirement */
+    private final int alignment;
+
+    /** {@code >= -1;} the size of this instance when written, in bytes, or
+     * {@code -1} if not yet known */
+    private int writeSize;
+
+    /**
+     * {@code null-ok;} section the item was added to, or {@code null} if
+     * not yet added
+     */
+    private Section addedTo;
+
+    /**
+     * {@code >= -1;} assigned offset of the item from the start of its section,
+     * or {@code -1} if not yet assigned
+     */
+    private int offset;
+
+    /**
+     * Gets the absolute offset of the given item, returning {@code 0}
+     * if handed {@code null}.
+     *
+     * @param item {@code null-ok;} the item in question
+     * @return {@code >= 0;} the item's absolute offset, or {@code 0}
+     * if {@code item == null}
+     */
+    public static int getAbsoluteOffsetOr0(OffsettedItem item) {
+        if (item == null) {
+            return 0;
+        }
+
+        return item.getAbsoluteOffset();
+    }
+
+    /**
+     * Constructs an instance. The offset is initially unassigned.
+     *
+     * @param alignment {@code > 0;} output alignment requirement; must be a
+     * power of 2
+     * @param writeSize {@code >= -1;} the size of this instance when written,
+     * in bytes, or {@code -1} if not immediately known
+     */
+    public OffsettedItem(int alignment, int writeSize) {
+        Section.validateAlignment(alignment);
+
+        if (writeSize < -1) {
+            throw new IllegalArgumentException("writeSize < -1");
+        }
+
+        this.alignment = alignment;
+        this.writeSize = writeSize;
+        this.addedTo = null;
+        this.offset = -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Comparisons for this class are defined to be type-major (if the
+     * types don't match then the objects are not equal), with
+     * {@link #compareTo0} deciding same-type comparisons.
+     */
+    @Override
+    public final boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        OffsettedItem otherItem = (OffsettedItem) other;
+        ItemType thisType = itemType();
+        ItemType otherType = otherItem.itemType();
+
+        if (thisType != otherType) {
+            return false;
+        }
+
+        return (compareTo0(otherItem) == 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Comparisons for this class are defined to be class-major (if the
+     * classes don't match then the objects are not equal), with
+     * {@link #compareTo0} deciding same-class comparisons.
+     */
+    public final int compareTo(OffsettedItem other) {
+        if (this == other) {
+            return 0;
+        }
+
+        ItemType thisType = itemType();
+        ItemType otherType = other.itemType();
+
+        if (thisType != otherType) {
+            return thisType.compareTo(otherType);
+        }
+
+        return compareTo0(other);
+    }
+
+    /**
+     * Sets the write size of this item. This may only be called once
+     * per instance, and only if the size was unknown upon instance
+     * creation.
+     *
+     * @param writeSize {@code > 0;} the write size, in bytes
+     */
+    public final void setWriteSize(int writeSize) {
+        if (writeSize < 0) {
+            throw new IllegalArgumentException("writeSize < 0");
+        }
+
+        if (this.writeSize >= 0) {
+            throw new UnsupportedOperationException("writeSize already set");
+        }
+
+        this.writeSize = writeSize;
+    }
+
+    /** {@inheritDoc}
+     *
+     * @throws UnsupportedOperationException thrown if the write size
+     * is not yet known
+     */
+    @Override
+    public final int writeSize() {
+        if (writeSize < 0) {
+            throw new UnsupportedOperationException("writeSize is unknown");
+        }
+
+        return writeSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void writeTo(DexFile file, AnnotatedOutput out) {
+        out.alignTo(alignment);
+
+        try {
+            if (writeSize < 0) {
+                throw new UnsupportedOperationException(
+                        "writeSize is unknown");
+            }
+            out.assertCursor(getAbsoluteOffset());
+        } catch (RuntimeException ex) {
+            throw ExceptionWithContext.withContext(ex,
+                    "...while writing " + this);
+        }
+
+        writeTo0(file, out);
+    }
+
+    /**
+     * Gets the relative item offset. The offset is from the start of
+     * the section which the instance was written to.
+     *
+     * @return {@code >= 0;} the offset
+     * @throws RuntimeException thrown if the offset is not yet known
+     */
+    public final int getRelativeOffset() {
+        if (offset < 0) {
+            throw new RuntimeException("offset not yet known");
+        }
+
+        return offset;
+    }
+
+    /**
+     * Gets the absolute item offset. The offset is from the start of
+     * the file which the instance was written to.
+     *
+     * @return {@code >= 0;} the offset
+     * @throws RuntimeException thrown if the offset is not yet known
+     */
+    public final int getAbsoluteOffset() {
+        if (offset < 0) {
+            throw new RuntimeException("offset not yet known");
+        }
+
+        return addedTo.getAbsoluteOffset(offset);
+    }
+
+    /**
+     * Indicates that this item has been added to the given section at
+     * the given offset. It is only valid to call this method once per
+     * instance.
+     *
+     * @param addedTo {@code non-null;} the section this instance has
+     * been added to
+     * @param offset {@code >= 0;} the desired offset from the start of the
+     * section where this instance was placed
+     * @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) {
+        if (addedTo == null) {
+            throw new NullPointerException("addedTo == null");
+        }
+
+        if (offset < 0) {
+            throw new IllegalArgumentException("offset < 0");
+        }
+
+        if (this.addedTo != null) {
+            throw new RuntimeException("already written");
+        }
+
+        int mask = alignment - 1;
+        offset = (offset + mask) & ~mask;
+
+        this.addedTo = addedTo;
+        this.offset = offset;
+
+        place0(addedTo, offset);
+
+        return offset;
+    }
+
+    /**
+     * Gets the alignment requirement of this instance. An instance should
+     * only be written when so aligned.
+     *
+     * @return {@code > 0;} the alignment requirement; must be a power of 2
+     */
+    public final int getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Gets the absolute offset of this item as a string, suitable for
+     * including in annotations.
+     *
+     * @return {@code non-null;} the offset string
+     */
+    public final String offsetString() {
+        return '[' + Integer.toHexString(getAbsoluteOffset()) + ']';
+    }
+
+    /**
+     * Gets a short human-readable string representing this instance.
+     *
+     * @return {@code non-null;} the human form
+     */
+    public abstract String toHuman();
+
+    /**
+     * Compares this instance to another which is guaranteed to be of
+     * the same class. The default implementation of this method is to
+     * throw an exception (unsupported operation). If a particular
+     * class needs to actually sort, then it should override this
+     * method.
+     *
+     * @param other {@code non-null;} instance to compare to
+     * @return {@code -1}, {@code 0}, or {@code 1}, depending
+     * on the sort order of this instance and the other
+     */
+    protected int compareTo0(OffsettedItem other) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /**
+     * Does additional work required when placing an instance. The
+     * default implementation of this method is a no-op. If a
+     * particular class needs to do something special, then it should
+     * override this method. In particular, if this instance did not
+     * know its write size up-front, then this method is responsible
+     * for setting it.
+     *
+     * @param addedTo {@code non-null;} the section this instance has been added to
+     * @param offset {@code >= 0;} the offset from the start of the
+     * section where this instance was placed
+     */
+    protected void place0(Section addedTo, int offset) {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Performs the actual write of the contents of this instance to
+     * the given data section. This is called by {@link #writeTo},
+     * which will have taken care of ensuring alignment.
+     *
+     * @param file {@code non-null;} the file to use for reference
+     * @param out {@code non-null;} where to write to
+     */
+    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
new file mode 100644
index 0000000..078c219
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotations;
+import com.android.dx.rop.annotation.AnnotationsList;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import com.android.dx.util.ToHuman;
+
+import java.util.ArrayList;
+
+/**
+ * Association of a method and its parameter annotations.
+ */
+public final class ParameterAnnotationStruct
+        implements ToHuman, Comparable<ParameterAnnotationStruct> {
+    /** {@code non-null;} the method in question */
+    private final CstMethodRef method;
+
+    /** {@code non-null;} the associated annotations list */
+    private final AnnotationsList annotationsList;
+
+    /** {@code non-null;} the associated annotations list, as an item */
+    private final UniformListItem<AnnotationSetRefItem> annotationsItem;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method in question
+     * @param annotationsList {@code non-null;} the associated annotations list
+     */
+    public ParameterAnnotationStruct(CstMethodRef method,
+            AnnotationsList annotationsList) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        if (annotationsList == null) {
+            throw new NullPointerException("annotationsList == null");
+        }
+
+        this.method = method;
+        this.annotationsList = annotationsList;
+
+        /*
+         * Construct an item for the annotations list. TODO: This
+         * requires way too much copying; fix it.
+         */
+
+        int size = annotationsList.size();
+        ArrayList<AnnotationSetRefItem> arrayList = new
+            ArrayList<AnnotationSetRefItem>(size);
+
+        for (int i = 0; i < size; i++) {
+            Annotations annotations = annotationsList.get(i);
+            AnnotationSetItem item = new AnnotationSetItem(annotations);
+            arrayList.add(new AnnotationSetRefItem(item));
+        }
+
+        this.annotationsItem = new UniformListItem<AnnotationSetRefItem>(
+                ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList);
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return method.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof ParameterAnnotationStruct)) {
+            return false;
+        }
+
+        return method.equals(((ParameterAnnotationStruct) other).method);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(ParameterAnnotationStruct other) {
+        return method.compareTo(other.method);
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        MethodIdsSection methodIds = file.getMethodIds();
+        MixedItemSection wordData = file.getWordData();
+
+        methodIds.intern(method);
+        wordData.add(annotationsItem);
+    }
+
+    /** {@inheritDoc} */
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int methodIdx = file.getMethodIds().indexOf(method);
+        int annotationsOff = annotationsItem.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, "    " + method.toHuman());
+            out.annotate(4, "      method_idx:      " + Hex.u4(methodIdx));
+            out.annotate(4, "      annotations_off: " +
+                    Hex.u4(annotationsOff));
+        }
+
+        out.writeInt(methodIdx);
+        out.writeInt(annotationsOff);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(method.toHuman());
+        sb.append(": ");
+
+        boolean first = true;
+        for (AnnotationSetRefItem item : annotationsItem.getItems()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(item.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the method this item is for.
+     *
+     * @return {@code non-null;} the method
+     */
+    public CstMethodRef getMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the associated 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
new file mode 100644
index 0000000..235a8c8
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ProtoIdItem.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.SizeOf;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * Representation of a method prototype reference inside a Dalvik file.
+ */
+public final class ProtoIdItem extends IndexedItem {
+    /** {@code non-null;} the wrapped prototype */
+    private final Prototype prototype;
+
+    /** {@code non-null;} the short-form of the prototype */
+    private final CstString shortForm;
+
+    /**
+     * {@code null-ok;} the list of parameter types or {@code null} if this
+     * prototype has no parameters
+     */
+    private TypeListItem parameterTypes;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param prototype {@code non-null;} the constant for the prototype
+     */
+    public ProtoIdItem(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        this.prototype = prototype;
+        this.shortForm = makeShortForm(prototype);
+
+        StdTypeList parameters = prototype.getParameterTypes();
+        this.parameterTypes = (parameters.size() == 0) ? null
+            : new TypeListItem(parameters);
+    }
+
+    /**
+     * Creates the short-form of the given prototype.
+     *
+     * @param prototype {@code non-null;} the prototype
+     * @return {@code non-null;} the short form
+     */
+    private static CstString makeShortForm(Prototype prototype) {
+        StdTypeList parameters = prototype.getParameterTypes();
+        int size = parameters.size();
+        StringBuilder sb = new StringBuilder(size + 1);
+
+        sb.append(shortFormCharFor(prototype.getReturnType()));
+
+        for (int i = 0; i < size; i++) {
+            sb.append(shortFormCharFor(parameters.getType(i)));
+        }
+
+        return new CstString(sb.toString());
+    }
+
+    /**
+     * Gets the short-form character for the given type.
+     *
+     * @param type {@code non-null;} the type
+     * @return the corresponding short-form character
+     */
+    private static char shortFormCharFor(Type type) {
+        char descriptorChar = type.getDescriptor().charAt(0);
+
+        if (descriptorChar == '[') {
+            return 'L';
+        }
+
+        return descriptorChar;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_PROTO_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return SizeOf.PROTO_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        StringIdsSection stringIds = file.getStringIds();
+        TypeIdsSection typeIds = file.getTypeIds();
+        MixedItemSection typeLists = file.getTypeLists();
+
+        typeIds.intern(prototype.getReturnType());
+        stringIds.intern(shortForm);
+
+        if (parameterTypes != null) {
+            parameterTypes = typeLists.intern(parameterTypes);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int shortyIdx = file.getStringIds().indexOf(shortForm);
+        int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType());
+        int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes);
+
+        if (out.annotates()) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(prototype.getReturnType().toHuman());
+            sb.append(" proto(");
+
+            StdTypeList params = prototype.getParameterTypes();
+            int size = params.size();
+
+            for (int i = 0; i < size; i++) {
+                if (i != 0) {
+                    sb.append(", ");
+                }
+                sb.append(params.getType(i).toHuman());
+            }
+
+            sb.append(")");
+            out.annotate(0, indexString() + ' ' + sb.toString());
+            out.annotate(4, "  shorty_idx:      " + Hex.u4(shortyIdx) +
+                    " // " + shortForm.toQuoted());
+            out.annotate(4, "  return_type_idx: " + Hex.u4(returnIdx) +
+                    " // " + prototype.getReturnType().toHuman());
+            out.annotate(4, "  parameters_off:  " + Hex.u4(paramsOff));
+        }
+
+        out.writeInt(shortyIdx);
+        out.writeInt(returnIdx);
+        out.writeInt(paramsOff);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
new file mode 100644
index 0000000..dc6e8ad
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Proto (method prototype) identifiers list section of a
+ * {@code .dex} file.
+ */
+public final class ProtoIdsSection extends UniformItemSection {
+    /**
+     * {@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 {@code non-null;} file that this instance is part of
+     */
+    public ProtoIdsSection(DexFile file) {
+        super("proto_ids", file, 4);
+
+        protoIds = new TreeMap<Prototype, ProtoIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return protoIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = protoIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (sz > 65536) {
+            throw new UnsupportedOperationException("too many proto ids");
+        }
+
+        if (out.annotates()) {
+            out.annotate(4, "proto_ids_size:  " + Hex.u4(sz));
+            out.annotate(4, "proto_ids_off:   " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param prototype {@code non-null;} the prototype to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public ProtoIdItem intern(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        throwIfPrepared();
+
+        ProtoIdItem result = protoIds.get(prototype);
+
+        if (result == null) {
+            result = new ProtoIdItem(prototype);
+            protoIds.put(prototype, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given prototype, which must have
+     * been added to this instance.
+     *
+     * @param prototype {@code non-null;} the prototype to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(Prototype prototype) {
+        if (prototype == null) {
+            throw new NullPointerException("prototype == null");
+        }
+
+        throwIfNotPrepared();
+
+        ProtoIdItem item = protoIds.get(prototype);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return item.getIndex();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (Object i : items()) {
+            ((ProtoIdItem) i).setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/Section.java b/dx/src/com/android/dx/dex/file/Section.java
new file mode 100644
index 0000000..3f04216
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/Section.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.Collection;
+
+/**
+ * A section of a {@code .dex} file. Each section consists of a list
+ * of items of some sort or other.
+ */
+public abstract class Section {
+    /** {@code null-ok;} name of this part, for annotation purposes */
+    private final String name;
+
+    /** {@code non-null;} file that this instance is part of */
+    private final DexFile file;
+
+    /** {@code > 0;} alignment requirement for the final output;
+     * must be a power of 2 */
+    private final int alignment;
+
+    /** {@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
+     * instance */
+    private boolean prepared;
+
+    /**
+     * Validates an alignment.
+     *
+     * @param alignment the alignment
+     * @throws IllegalArgumentException thrown if {@code alignment}
+     * isn't a positive power of 2
+     */
+    public static void validateAlignment(int alignment) {
+        if ((alignment <= 0) ||
+            (alignment & (alignment - 1)) != 0) {
+            throw new IllegalArgumentException("invalid alignment");
+        }
+    }
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param name {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     * @param alignment {@code > 0;} alignment requirement for the final output;
+     * must be a power of 2
+     */
+    public Section(String name, DexFile file, int alignment) {
+        if (file == null) {
+            throw new NullPointerException("file == null");
+        }
+
+        validateAlignment(alignment);
+
+        this.name = name;
+        this.file = file;
+        this.alignment = alignment;
+        this.fileOffset = -1;
+        this.prepared = false;
+    }
+
+    /**
+     * Gets the file that this instance is part of.
+     *
+     * @return {@code non-null;} the file
+     */
+    public final DexFile getFile() {
+        return file;
+    }
+
+    /**
+     * Gets the alignment for this instance's final output.
+     *
+     * @return {@code > 0;} the alignment
+     */
+    public final int getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * 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 {@code >= 0;} the file offset
+     */
+    public final int getFileOffset() {
+        if (fileOffset < 0) {
+            throw new RuntimeException("fileOffset not set");
+        }
+
+        return fileOffset;
+    }
+
+    /**
+     * Sets the file offset. It is only valid to call this method once
+     * once per instance.
+     *
+     * @param fileOffset {@code >= 0;} the desired offset from the start of the
+     * file where this for this instance
+     * @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) {
+        if (fileOffset < 0) {
+            throw new IllegalArgumentException("fileOffset < 0");
+        }
+
+        if (this.fileOffset >= 0) {
+            throw new RuntimeException("fileOffset already set");
+        }
+
+        int mask = alignment - 1;
+        fileOffset = (fileOffset + mask) & ~mask;
+
+        this.fileOffset = fileOffset;
+
+        return fileOffset;
+    }
+
+    /**
+     * Writes this instance to the given raw data object.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public final void writeTo(AnnotatedOutput out) {
+        throwIfNotPrepared();
+        align(out);
+
+        int cursor = out.getCursor();
+
+        if (fileOffset < 0) {
+            fileOffset = cursor;
+        } else if (fileOffset != cursor) {
+            throw new RuntimeException("alignment mismatch: for " + this +
+                                       ", at " + cursor +
+                                       ", but expected " + fileOffset);
+        }
+
+        if (out.annotates()) {
+            if (name != null) {
+                out.annotate(0, "\n" + name + ":");
+            } else if (cursor != 0) {
+                out.annotate(0, "\n");
+            }
+        }
+
+        writeTo0(out);
+    }
+
+    /**
+     * Returns the absolute file offset, given an offset from the
+     * start of this instance's output. This is only valid to call
+     * once this instance has been assigned a file offset (via {@link
+     * #setFileOffset}).
+     *
+     * @param relative {@code >= 0;} the relative offset
+     * @return {@code >= 0;} the corresponding absolute file offset
+     */
+    public final int getAbsoluteOffset(int relative) {
+        if (relative < 0) {
+            throw new IllegalArgumentException("relative < 0");
+        }
+
+        if (fileOffset < 0) {
+            throw new RuntimeException("fileOffset not yet set");
+        }
+
+        return fileOffset + relative;
+    }
+
+    /**
+     * Returns the absolute file offset of the given item which must
+     * be contained in this section. This is only valid to call
+     * once this instance has been assigned a file offset (via {@link
+     * #setFileOffset}).
+     *
+     * <p><b>Note:</b> Subclasses must implement this as appropriate for
+     * their contents.</p>
+     *
+     * @param item {@code non-null;} the item in question
+     * @return {@code >= 0;} the item's absolute file offset
+     */
+    public abstract int getAbsoluteItemOffset(Item item);
+
+    /**
+     * Prepares this instance for writing. This performs any necessary
+     * prerequisites, including particularly adding stuff to other
+     * sections. This method may only be called once per instance;
+     * subsequent calls will throw an exception.
+     */
+    public final void prepare() {
+        throwIfPrepared();
+        prepare0();
+        prepared = true;
+    }
+
+    /**
+     * Gets the collection of all the items in this section.
+     * It is not valid to attempt to change the returned list.
+     *
+     * @return {@code non-null;} the items
+     */
+    public abstract Collection<? extends Item> items();
+
+    /**
+     * Does the main work of {@link #prepare}.
+     */
+    protected abstract void prepare0();
+
+    /**
+     * Gets the size of this instance when output, in bytes.
+     *
+     * @return {@code >= 0;} the size of this instance, in bytes
+     */
+    public abstract int writeSize();
+
+    /**
+     * Throws an exception if {@link #prepare} has not been
+     * called on this instance.
+     */
+    protected final void throwIfNotPrepared() {
+        if (!prepared) {
+            throw new RuntimeException("not prepared");
+        }
+    }
+
+    /**
+     * Throws an exception if {@link #prepare} has already been called
+     * on this instance.
+     */
+    protected final void throwIfPrepared() {
+        if (prepared) {
+            throw new RuntimeException("already prepared");
+        }
+    }
+
+    /**
+     * Aligns the output of the given data to the alignment of this instance.
+     *
+     * @param out {@code non-null;} the output to align
+     */
+    protected final void align(AnnotatedOutput out) {
+        out.alignTo(alignment);
+    }
+
+    /**
+     * Writes this instance to the given raw data object. This gets
+     * called by {@link #writeTo} after aligning the cursor of
+     * {@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}'s cursor.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    protected abstract void writeTo0(AnnotatedOutput out);
+
+    /**
+     * Returns the name of this section, for annotation purposes.
+     *
+     * @return {@code null-ok;} name of this part, for annotation purposes
+     */
+    protected final String getName() {
+        return name;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/Statistics.java b/dx/src/com/android/dx/dex/file/Statistics.java
new file mode 100644
index 0000000..62e1832
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/Statistics.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.TreeMap;
+
+/**
+ * Statistics about the contents of a file.
+ */
+public final class Statistics {
+    /** {@code non-null;} data about each type of item */
+    private final HashMap<String, Data> dataMap;
+
+    /**
+     * Constructs an instance.
+     */
+    public Statistics() {
+        dataMap = new HashMap<String, Data>(50);
+    }
+
+    /**
+     * Adds the given item to the statistics.
+     *
+     * @param item {@code non-null;} the item to add
+     */
+    public void add(Item item) {
+        String typeName = item.typeName();
+        Data data = dataMap.get(typeName);
+
+        if (data == null) {
+            dataMap.put(typeName, new Data(item, typeName));
+        } else {
+            data.add(item);
+        }
+    }
+
+    /**
+     * Adds the given list of items to the statistics.
+     *
+     * @param list {@code non-null;} the list of items to add
+     */
+    public void addAll(Section list) {
+        Collection<? extends Item> items = list.items();
+        for (Item item : items) {
+            add(item);
+        }
+    }
+
+    /**
+     * Writes the statistics as an annotation.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public final void writeAnnotation(AnnotatedOutput out) {
+        if (dataMap.size() == 0) {
+            return;
+        }
+
+        out.annotate(0, "\nstatistics:\n");
+
+        TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
+
+        for (Data data : dataMap.values()) {
+            sortedData.put(data.name, data);
+        }
+
+        for (Data data : sortedData.values()) {
+            data.writeAnnotation(out);
+        }
+    }
+
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("Statistics:\n");
+
+        TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
+
+        for (Data data : dataMap.values()) {
+            sortedData.put(data.name, data);
+        }
+
+        for (Data data : sortedData.values()) {
+            sb.append(data.toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Statistical data about a particular class.
+     */
+    private static class Data {
+        /** {@code non-null;} name to use as a label */
+        private final String name;
+
+        /** {@code >= 0;} number of instances */
+        private int count;
+
+        /** {@code >= 0;} total size of instances in bytes */
+        private int totalSize;
+
+        /** {@code >= 0;} largest size of any individual item */
+        private int largestSize;
+
+        /** {@code >= 0;} smallest size of any individual item */
+        private int smallestSize;
+
+        /**
+         * Constructs an instance for the given item.
+         *
+         * @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();
+
+            this.name = name;
+            this.count = 1;
+            this.totalSize = size;
+            this.largestSize = size;
+            this.smallestSize = size;
+        }
+
+        /**
+         * Incorporates a new item. This assumes the type name matches.
+         *
+         * @param item {@code non-null;} item to incorporate
+         */
+        public void add(Item item) {
+            int size = item.writeSize();
+
+            count++;
+            totalSize += size;
+
+            if (size > largestSize) {
+                largestSize = size;
+            }
+
+            if (size < smallestSize) {
+                smallestSize = size;
+            }
+        }
+
+        /**
+         * Writes this instance as an annotation.
+         *
+         * @param out {@code non-null;} where to write to
+         */
+        public void writeAnnotation(AnnotatedOutput out) {
+            out.annotate(toHuman());
+        }
+
+        /**
+         * Generates a human-readable string for this data item.
+         *
+         * @return string for human consumption.
+         */
+        public String toHuman() {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append("  " + name + ": " +
+                         count + " item" + (count == 1 ? "" : "s") + "; " +
+                         totalSize + " bytes total\n");
+
+            if (smallestSize == largestSize) {
+                sb.append("    " + smallestSize + " bytes/item\n");
+            } else {
+                int average = totalSize / count;
+                sb.append("    " + smallestSize + ".." + largestSize +
+                             " bytes/item; average " + average + "\n");
+            }
+
+            return sb.toString();
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/StringDataItem.java b/dx/src/com/android/dx/dex/file/StringDataItem.java
new file mode 100644
index 0000000..e85a823
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/StringDataItem.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+import com.android.dx.util.Leb128Utils;
+
+/**
+ * Representation of string data for a particular string, in a Dalvik file.
+ */
+public final class StringDataItem extends OffsettedItem {
+    /** {@code non-null;} the string value */
+    private final CstString value;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param value {@code non-null;} the string value
+     */
+    public StringDataItem(CstString value) {
+        super(1, writeSize(value));
+
+        this.value = value;
+    }
+
+    /**
+     * Gets the write size for a given value.
+     *
+     * @param value {@code non-null;} the string value
+     * @return {@code >= 2}; the write size, in bytes
+     */
+    private static int writeSize(CstString value) {
+        int utf16Size = value.getUtf16Size();
+
+        // The +1 is for the '\0' termination byte.
+        return Leb128Utils.unsignedLeb128Size(utf16Size)
+            + value.getUtf8Size() + 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_STRING_DATA_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        // Nothing to do here.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo0(DexFile file, AnnotatedOutput out) {
+        ByteArray bytes = value.getBytes();
+        int utf16Size = value.getUtf16Size();
+
+        if (out.annotates()) {
+            out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size),
+                    "utf16_size: " + Hex.u4(utf16Size));
+            out.annotate(bytes.size() + 1, value.toQuoted());
+        }
+
+        out.writeUleb128(utf16Size);
+        out.write(bytes);
+        out.writeByte(0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return value.toQuoted();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        StringDataItem otherData = (StringDataItem) other;
+
+        return value.compareTo(otherData.value);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/StringIdItem.java b/dx/src/com/android/dx/dex/file/StringIdItem.java
new file mode 100644
index 0000000..533427d
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/StringIdItem.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.SizeOf;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * Representation of a string inside a Dalvik file.
+ */
+public final class StringIdItem
+        extends IndexedItem implements Comparable {
+    /** {@code non-null;} the string value */
+    private final CstString value;
+
+    /** {@code null-ok;} associated string data object, if known */
+    private StringDataItem data;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param value {@code non-null;} the string value
+     */
+    public StringIdItem(CstString value) {
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        this.value = value;
+        this.data = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof StringIdItem)) {
+            return false;
+        }
+
+        StringIdItem otherString = (StringIdItem) other;
+        return value.equals(otherString.value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return value.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Object other) {
+        StringIdItem otherString = (StringIdItem) other;
+        return value.compareTo(otherString.value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_STRING_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return SizeOf.STRING_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        if (data == null) {
+            // The string data hasn't yet been added, so add it.
+            MixedItemSection stringData = file.getStringData();
+            data = new StringDataItem(value);
+            stringData.add(data);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        int dataOff = data.getAbsoluteOffset();
+
+        if (out.annotates()) {
+            out.annotate(0, indexString() + ' ' + value.toQuoted(100));
+            out.annotate(4, "  string_data_off: " + Hex.u4(dataOff));
+        }
+
+        out.writeInt(dataOff);
+    }
+
+    /**
+     * Gets the string value.
+     *
+     * @return {@code non-null;} the value
+     */
+    public CstString getValue() {
+        return value;
+    }
+
+    /**
+     * Gets the associated data object for this instance, if known.
+     *
+     * @return {@code null-ok;} the associated data object or {@code null}
+     * if not yet known
+     */
+    public StringDataItem getData() {
+        return data;
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/StringIdsSection.java b/dx/src/com/android/dx/dex/file/StringIdsSection.java
new file mode 100644
index 0000000..2f7c40b
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/StringIdsSection.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Strings list section of a {@code .dex} file.
+ */
+public final class StringIdsSection
+        extends UniformItemSection {
+    /**
+     * {@code non-null;} map from string constants to {@link
+     * StringIdItem} instances
+     */
+    private final TreeMap<CstString, StringIdItem> strings;
+
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param file {@code non-null;} file that this instance is part of
+     */
+    public StringIdsSection(DexFile file) {
+        super("string_ids", file, 4);
+
+        strings = new TreeMap<CstString, StringIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return strings.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        IndexedItem result = strings.get((CstString) cst);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = strings.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (out.annotates()) {
+            out.annotate(4, "string_ids_size: " + Hex.u4(sz));
+            out.annotate(4, "string_ids_off:  " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern, as a regular Java
+     * {@code String}
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(String string) {
+        return intern(new StringIdItem(new CstString(string)));
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern, as a constant
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(CstString string) {
+        return intern(new StringIdItem(string));
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param string {@code non-null;} the string to intern
+     * @return {@code non-null;} the interned string
+     */
+    public StringIdItem intern(StringIdItem string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        throwIfPrepared();
+
+        CstString value = string.getValue();
+        StringIdItem already = strings.get(value);
+
+        if (already != null) {
+            return already;
+        }
+
+        strings.put(value, string);
+        return string;
+    }
+
+    /**
+     * Interns the components of a name-and-type into this instance.
+     *
+     * @param nat {@code non-null;} the name-and-type
+     */
+    public void intern(CstNat nat) {
+        intern(nat.getName());
+        intern(nat.getDescriptor());
+    }
+
+    /**
+     * Gets the index of the given string, which must have been added
+     * to this instance.
+     *
+     * @param string {@code non-null;} the string to look up
+     * @return {@code >= 0;} the string's index
+     */
+    public int indexOf(CstString string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        throwIfNotPrepared();
+
+        StringIdItem s = strings.get(string);
+
+        if (s == null) {
+            throw new IllegalArgumentException("not found");
+        }
+
+        return s.getIndex();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (StringIdItem s : strings.values()) {
+            s.setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/TypeIdItem.java b/dx/src/com/android/dx/dex/file/TypeIdItem.java
new file mode 100644
index 0000000..04be2a1
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/TypeIdItem.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.dex.SizeOf;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * Representation of a type reference inside a Dalvik file.
+ */
+public final class TypeIdItem extends IdItem {
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the constant for the type
+     */
+    public TypeIdItem(CstType type) {
+        super(type);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_TYPE_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int writeSize() {
+        return SizeOf.TYPE_ID_ITEM;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        file.getStringIds().intern(getDefiningClass().getDescriptor());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeTo(DexFile file, AnnotatedOutput out) {
+        CstType type = getDefiningClass();
+        CstString descriptor = type.getDescriptor();
+        int idx = file.getStringIds().indexOf(descriptor);
+
+        if (out.annotates()) {
+            out.annotate(0, indexString() + ' ' + descriptor.toHuman());
+            out.annotate(4, "  descriptor_idx: " + Hex.u4(idx));
+        }
+
+        out.writeInt(idx);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/TypeIdsSection.java b/dx/src/com/android/dx/dex/file/TypeIdsSection.java
new file mode 100644
index 0000000..bcc8250
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/TypeIdsSection.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.Collection;
+import java.util.TreeMap;
+
+/**
+ * Type identifiers list section of a {@code .dex} file.
+ */
+public final class TypeIdsSection extends UniformItemSection {
+    /**
+     * {@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 {@code non-null;} file that this instance is part of
+     */
+    public TypeIdsSection(DexFile file) {
+        super("type_ids", file, 4);
+
+        typeIds = new TreeMap<Type, TypeIdItem>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<? extends Item> items() {
+        return typeIds.values();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IndexedItem get(Constant cst) {
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        throwIfNotPrepared();
+
+        Type type = ((CstType) cst).getClassType();
+        IndexedItem result = typeIds.get(type);
+
+        if (result == null) {
+            throw new IllegalArgumentException("not found: " + cst);
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes the portion of the file header that refers to this instance.
+     *
+     * @param out {@code non-null;} where to write
+     */
+    public void writeHeaderPart(AnnotatedOutput out) {
+        throwIfNotPrepared();
+
+        int sz = typeIds.size();
+        int offset = (sz == 0) ? 0 : getFileOffset();
+
+        if (sz > 65536) {
+            throw new UnsupportedOperationException("too many type ids");
+        }
+
+        if (out.annotates()) {
+            out.annotate(4, "type_ids_size:   " + Hex.u4(sz));
+            out.annotate(4, "type_ids_off:    " + Hex.u4(offset));
+        }
+
+        out.writeInt(sz);
+        out.writeInt(offset);
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param type {@code non-null;} the type to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public TypeIdItem intern(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        throwIfPrepared();
+
+        TypeIdItem result = typeIds.get(type);
+
+        if (result == null) {
+            result = new TypeIdItem(new CstType(type));
+            typeIds.put(type, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Interns an element into this instance.
+     *
+     * @param type {@code non-null;} the type to intern
+     * @return {@code non-null;} the interned reference
+     */
+    public TypeIdItem intern(CstType type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        throwIfPrepared();
+
+        Type typePerSe = type.getClassType();
+        TypeIdItem result = typeIds.get(typePerSe);
+
+        if (result == null) {
+            result = new TypeIdItem(type);
+            typeIds.put(typePerSe, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the index of the given type, which must have
+     * been added to this instance.
+     *
+     * @param type {@code non-null;} the type to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        throwIfNotPrepared();
+
+        TypeIdItem item = typeIds.get(type);
+
+        if (item == null) {
+            throw new IllegalArgumentException("not found: " + type);
+        }
+
+        return item.getIndex();
+    }
+
+    /**
+     * Gets the index of the given type, which must have
+     * been added to this instance.
+     *
+     * @param type {@code non-null;} the type to look up
+     * @return {@code >= 0;} the reference's index
+     */
+    public int indexOf(CstType type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        return indexOf(type.getClassType());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void orderItems() {
+        int idx = 0;
+
+        for (Object i : items()) {
+            ((TypeIdItem) i).setIndex(idx);
+            idx++;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/TypeListItem.java b/dx/src/com/android/dx/dex/file/TypeListItem.java
new file mode 100644
index 0000000..b815dd3
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/TypeListItem.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+/**
+ * Representation of a list of class references.
+ */
+public final class TypeListItem extends OffsettedItem {
+    /** alignment requirement */
+    private static final int ALIGNMENT = 4;
+
+    /** element size in bytes */
+    private static final int ELEMENT_SIZE = 2;
+
+    /** header size in bytes */
+    private static final int HEADER_SIZE = 4;
+
+    /** {@code non-null;} the actual list */
+    private final TypeList list;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param list {@code non-null;} the actual list
+     */
+    public TypeListItem(TypeList list) {
+        super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE);
+
+        this.list = list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return StdTypeList.hashContents(list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return ItemType.TYPE_TYPE_LIST;
+    }
+
+    /** {@inheritDoc} */
+    public void addContents(DexFile file) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        int sz = list.size();
+
+        for (int i = 0; i < sz; i++) {
+            typeIds.intern(list.getType(i));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        throw new RuntimeException("unsupported");
+    }
+
+    /**
+     * Gets the underlying list.
+     *
+     * @return {@code non-null;} the list
+     */
+    public TypeList getList() {
+        return list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        int sz = list.size();
+
+        if (out.annotates()) {
+            out.annotate(0, offsetString() + " type_list");
+            out.annotate(HEADER_SIZE, "  size: " + Hex.u4(sz));
+            for (int i = 0; i < sz; i++) {
+                Type one = list.getType(i);
+                int idx = typeIds.indexOf(one);
+                out.annotate(ELEMENT_SIZE,
+                             "  " + Hex.u2(idx) + " // " + one.toHuman());
+            }
+        }
+
+        out.writeInt(sz);
+
+        for (int i = 0; i < sz; i++) {
+            out.writeShort(typeIds.indexOf(list.getType(i)));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(OffsettedItem other) {
+        TypeList thisList = this.list;
+        TypeList otherList = ((TypeListItem) other).list;
+
+        return StdTypeList.compareContents(thisList, otherList);
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/UniformItemSection.java b/dx/src/com/android/dx/dex/file/UniformItemSection.java
new file mode 100644
index 0000000..d8c09ab
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/UniformItemSection.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.util.AnnotatedOutput;
+
+import java.util.Collection;
+
+/**
+ * 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.
+ */
+public abstract class UniformItemSection extends Section {
+    /**
+     * Constructs an instance. The file offset is initially unknown.
+     *
+     * @param name {@code null-ok;} the name of this instance, for annotation
+     * purposes
+     * @param file {@code non-null;} file that this instance is part of
+     * @param alignment {@code > 0;} alignment requirement for the final output;
+     * must be a power of 2
+     */
+    public UniformItemSection(String name, DexFile file, int alignment) {
+        super(name, file, alignment);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int writeSize() {
+        Collection<? extends Item> items = items();
+        int sz = items.size();
+
+        if (sz == 0) {
+            return 0;
+        }
+
+        // Since each item has to be the same size, we can pick any.
+        return sz * items.iterator().next().writeSize();
+    }
+
+    /**
+     * Gets the item corresponding to the given {@link Constant}. This
+     * will throw an exception if the constant is not found, including
+     * if this instance isn't the sort that maps constants to {@link
+     * IndexedItem} instances.
+     *
+     * @param cst {@code non-null;} constant to look for
+     * @return {@code non-null;} the corresponding item found in this instance
+     */
+    public abstract IndexedItem get(Constant cst);
+
+    /** {@inheritDoc} */
+    @Override
+    protected final void prepare0() {
+        DexFile file = getFile();
+
+        orderItems();
+
+        for (Item one : items()) {
+            one.addContents(file);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected final void writeTo0(AnnotatedOutput out) {
+        DexFile file = getFile();
+        int alignment = getAlignment();
+
+        for (Item one : items()) {
+            one.writeTo(file, out);
+            out.alignTo(alignment);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int getAbsoluteItemOffset(Item item) {
+        /*
+         * Since all items must be the same size, we can use the size
+         * of the one we're given to calculate its offset.
+         */
+        IndexedItem ii = (IndexedItem) item;
+        int relativeOffset = ii.getIndex() * ii.writeSize();
+
+        return getAbsoluteOffset(relativeOffset);
+    }
+
+    /**
+     * Alters or picks the order for items in this instance if desired,
+     * so that subsequent calls to {@link #items} will yield a
+     * so-ordered collection. If the items in this instance are indexed,
+     * then this method should also assign indices.
+     */
+    protected abstract void orderItems();
+}
diff --git a/dx/src/com/android/dx/dex/file/UniformListItem.java b/dx/src/com/android/dx/dex/file/UniformListItem.java
new file mode 100644
index 0000000..88919c7
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/UniformListItem.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Class that represents a contiguous list of uniform items. Each
+ * item in the list, in particular, must have the same write size and
+ * alignment.
+ *
+ * <p>This class inherits its alignment from its items, bumped up to
+ * {@code 4} if the items have a looser alignment requirement. If
+ * it is more than {@code 4}, then there will be a gap after the
+ * output list size (which is four bytes) and before the first item.</p>
+ *
+ * @param <T> type of element contained in an instance
+ */
+public final class UniformListItem<T extends OffsettedItem>
+        extends OffsettedItem {
+    /** the size of the list header */
+    private static final int HEADER_SIZE = 4;
+
+    /** {@code non-null;} the item type */
+    private final ItemType itemType;
+
+    /** {@code non-null;} the contents */
+    private final List<T> items;
+
+    /**
+     * Constructs an instance. It is illegal to modify the given list once
+     * it is used to construct an instance of this class.
+     *
+     * @param itemType {@code non-null;} the type of the item
+     * @param items {@code non-null and non-empty;} list of items to represent
+     */
+    public UniformListItem(ItemType itemType, List<T> items) {
+        super(getAlignment(items), writeSize(items));
+
+        if (itemType == null) {
+            throw new NullPointerException("itemType == null");
+        }
+
+        this.items = items;
+        this.itemType = itemType;
+    }
+
+    /**
+     * Helper for {@link #UniformListItem}, which returns the alignment
+     * requirement implied by the given list. See the header comment for
+     * more details.
+     *
+     * @param items {@code non-null;} list of items being represented
+     * @return {@code >= 4;} the alignment requirement
+     */
+    private static int getAlignment(List<? extends OffsettedItem> items) {
+        try {
+            // Since they all must have the same alignment, any one will do.
+            return Math.max(HEADER_SIZE, items.get(0).getAlignment());
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("items.size() == 0");
+        } catch (NullPointerException ex) {
+            // Translate the exception.
+            throw new NullPointerException("items == null");
+        }
+    }
+
+    /**
+     * Calculates the write size for the given list.
+     *
+     * @param items {@code non-null;} the list in question
+     * @return {@code >= 0;} the write size
+     */
+    private static int writeSize(List<? extends OffsettedItem> items) {
+        /*
+         * This class assumes all included items are the same size,
+         * an assumption which is verified in place0().
+         */
+        OffsettedItem first = items.get(0);
+        return (items.size() * first.writeSize()) + getAlignment(items);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public ItemType itemType() {
+        return itemType;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append(getClass().getName());
+        sb.append(items);
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addContents(DexFile file) {
+        for (OffsettedItem i : items) {
+            i.addContents(file);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toHuman() {
+        StringBuffer sb = new StringBuffer(100);
+        boolean first = true;
+
+        sb.append("{");
+
+        for (OffsettedItem i : items) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(i.toHuman());
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Gets the underlying list of items.
+     *
+     * @return {@code non-null;} the list
+     */
+    public final List<T> getItems() {
+        return items;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void place0(Section addedTo, int offset) {
+        offset += headerSize();
+
+        boolean first = true;
+        int theSize = -1;
+        int theAlignment = -1;
+
+        for (OffsettedItem i : items) {
+            int size = i.writeSize();
+            if (first) {
+                theSize = size;
+                theAlignment = i.getAlignment();
+                first = false;
+            } else {
+                if (size != theSize) {
+                    throw new UnsupportedOperationException(
+                            "item size mismatch");
+                }
+                if (i.getAlignment() != theAlignment) {
+                    throw new UnsupportedOperationException(
+                            "item alignment mismatch");
+                }
+            }
+
+            offset = i.place(addedTo, offset) + size;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void writeTo0(DexFile file, AnnotatedOutput out) {
+        int size = items.size();
+
+        if (out.annotates()) {
+            out.annotate(0, offsetString() + " " + typeName());
+            out.annotate(4, "  size: " + Hex.u4(size));
+        }
+
+        out.writeInt(size);
+
+        for (OffsettedItem i : items) {
+            i.writeTo(file, out);
+        }
+    }
+
+    /**
+     * Get the size of the header of this list.
+     *
+     * @return {@code >= 0;} the header size
+     */
+    private int headerSize() {
+        /*
+         * Because of how this instance was set up, this is the same
+         * as the alignment.
+         */
+        return getAlignment();
+    }
+}
diff --git a/dx/src/com/android/dx/dex/file/ValueEncoder.java b/dx/src/com/android/dx/dex/file/ValueEncoder.java
new file mode 100644
index 0000000..9c433a3
--- /dev/null
+++ b/dx/src/com/android/dx/dex/file/ValueEncoder.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.dex.file;
+
+import com.android.dx.rop.annotation.Annotation;
+import com.android.dx.rop.annotation.NameValuePair;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstAnnotation;
+import com.android.dx.rop.cst.CstArray;
+import com.android.dx.rop.cst.CstBoolean;
+import com.android.dx.rop.cst.CstByte;
+import com.android.dx.rop.cst.CstChar;
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstEnumRef;
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstKnownNull;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstShort;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.AnnotatedOutput;
+import com.android.dx.util.Hex;
+import java.util.Collection;
+
+/**
+ * Handler for writing out {@code encoded_values} and parts
+ * thereof.
+ */
+public final class ValueEncoder {
+    /** annotation value type constant: {@code byte} */
+    private static final int VALUE_BYTE = 0x00;
+
+    /** annotation value type constant: {@code short} */
+    private static final int VALUE_SHORT = 0x02;
+
+    /** annotation value type constant: {@code char} */
+    private static final int VALUE_CHAR = 0x03;
+
+    /** annotation value type constant: {@code int} */
+    private static final int VALUE_INT = 0x04;
+
+    /** annotation value type constant: {@code long} */
+    private static final int VALUE_LONG = 0x06;
+
+    /** annotation value type constant: {@code float} */
+    private static final int VALUE_FLOAT = 0x10;
+
+    /** annotation value type constant: {@code double} */
+    private static final int VALUE_DOUBLE = 0x11;
+
+    /** annotation value type constant: {@code string} */
+    private static final int VALUE_STRING = 0x17;
+
+    /** annotation value type constant: {@code type} */
+    private static final int VALUE_TYPE = 0x18;
+
+    /** annotation value type constant: {@code field} */
+    private static final int VALUE_FIELD = 0x19;
+
+    /** annotation value type constant: {@code method} */
+    private static final int VALUE_METHOD = 0x1a;
+
+    /** annotation value type constant: {@code enum} */
+    private static final int VALUE_ENUM = 0x1b;
+
+    /** annotation value type constant: {@code array} */
+    private static final int VALUE_ARRAY = 0x1c;
+
+    /** annotation value type constant: {@code annotation} */
+    private static final int VALUE_ANNOTATION = 0x1d;
+
+    /** annotation value type constant: {@code null} */
+    private static final int VALUE_NULL = 0x1e;
+
+    /** annotation value type constant: {@code boolean} */
+    private static final int VALUE_BOOLEAN = 0x1f;
+
+    /** {@code non-null;} file being written */
+    private final DexFile file;
+
+    /** {@code non-null;} output stream to write to */
+    private final AnnotatedOutput out;
+
+    /**
+     * Construct an instance.
+     *
+     * @param file {@code non-null;} file being written
+     * @param out {@code non-null;} output stream to write to
+     */
+    public ValueEncoder(DexFile file, AnnotatedOutput out) {
+        if (file == null) {
+            throw new NullPointerException("file == null");
+        }
+
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        }
+
+        this.file = file;
+        this.out = out;
+    }
+
+    /**
+     * Writes out the encoded form of the given constant.
+     *
+     * @param cst {@code non-null;} the constant to write
+     */
+    public void writeConstant(Constant cst) {
+        int type = constantToValueType(cst);
+        int arg;
+
+        switch (type) {
+            case VALUE_BYTE:
+            case VALUE_SHORT:
+            case VALUE_INT:
+            case VALUE_LONG: {
+                long value = ((CstLiteralBits) cst).getLongBits();
+                writeSignedIntegralValue(type, value);
+                break;
+            }
+            case VALUE_CHAR: {
+                long value = ((CstLiteralBits) cst).getLongBits();
+                writeUnsignedIntegralValue(type, value);
+                break;
+            }
+            case VALUE_FLOAT: {
+                // Shift value left 32 so that right-zero-extension works.
+                long value = ((CstFloat) cst).getLongBits() << 32;
+                writeRightZeroExtendedValue(type, value);
+                break;
+            }
+            case VALUE_DOUBLE: {
+                long value = ((CstDouble) cst).getLongBits();
+                writeRightZeroExtendedValue(type, value);
+                break;
+            }
+            case VALUE_STRING: {
+                int index = file.getStringIds().indexOf((CstString) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_TYPE: {
+                int index = file.getTypeIds().indexOf((CstType) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_FIELD: {
+                int index = file.getFieldIds().indexOf((CstFieldRef) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_METHOD: {
+                int index = file.getMethodIds().indexOf((CstMethodRef) cst);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_ENUM: {
+                CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef();
+                int index = file.getFieldIds().indexOf(fieldRef);
+                writeUnsignedIntegralValue(type, (long) index);
+                break;
+            }
+            case VALUE_ARRAY: {
+                out.writeByte(type);
+                writeArray((CstArray) cst, false);
+                break;
+            }
+            case VALUE_ANNOTATION: {
+                out.writeByte(type);
+                writeAnnotation(((CstAnnotation) cst).getAnnotation(),
+                        false);
+                break;
+            }
+            case VALUE_NULL: {
+                out.writeByte(type);
+                break;
+            }
+            case VALUE_BOOLEAN: {
+                int value = ((CstBoolean) cst).getIntBits();
+                out.writeByte(type | (value << 5));
+                break;
+            }
+            default: {
+                throw new RuntimeException("Shouldn't happen");
+            }
+        }
+    }
+
+    /**
+     * Gets the value type for the given constant.
+     *
+     * @param cst {@code non-null;} the constant
+     * @return the value type; one of the {@code VALUE_*} constants
+     * defined by this class
+     */
+    private static int constantToValueType(Constant cst) {
+        /*
+         * TODO: Constant should probable have an associated enum, so this
+         * can be a switch().
+         */
+        if (cst instanceof CstByte) {
+            return VALUE_BYTE;
+        } else if (cst instanceof CstShort) {
+            return VALUE_SHORT;
+        } else if (cst instanceof CstChar) {
+            return VALUE_CHAR;
+        } else if (cst instanceof CstInteger) {
+            return VALUE_INT;
+        } else if (cst instanceof CstLong) {
+            return VALUE_LONG;
+        } else if (cst instanceof CstFloat) {
+            return VALUE_FLOAT;
+        } else if (cst instanceof CstDouble) {
+            return VALUE_DOUBLE;
+        } else if (cst instanceof CstString) {
+            return VALUE_STRING;
+        } else if (cst instanceof CstType) {
+            return VALUE_TYPE;
+        } else if (cst instanceof CstFieldRef) {
+            return VALUE_FIELD;
+        } else if (cst instanceof CstMethodRef) {
+            return VALUE_METHOD;
+        } else if (cst instanceof CstEnumRef) {
+            return VALUE_ENUM;
+        } else if (cst instanceof CstArray) {
+            return VALUE_ARRAY;
+        } else if (cst instanceof CstAnnotation) {
+            return VALUE_ANNOTATION;
+        } else if (cst instanceof CstKnownNull) {
+            return VALUE_NULL;
+        } else if (cst instanceof CstBoolean) {
+            return VALUE_BOOLEAN;
+        } else {
+            throw new RuntimeException("Shouldn't happen");
+        }
+    }
+
+    /**
+     * Writes out the encoded form of the given array, that is, as
+     * 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 {@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) {
+        boolean annotates = topLevel && out.annotates();
+        CstArray.List list = ((CstArray) array).getList();
+        int size = list.size();
+
+        if (annotates) {
+            out.annotate("  size: " + Hex.u4(size));
+        }
+
+        out.writeUleb128(size);
+
+        for (int i = 0; i < size; i++) {
+            Constant cst = list.get(i);
+            if (annotates) {
+                out.annotate("  [" + Integer.toHexString(i) + "] " +
+                        constantToHuman(cst));
+            }
+            writeConstant(cst);
+        }
+
+        if (annotates) {
+            out.endAnnotation();
+        }
+    }
+
+    /**
+     * Writes out the encoded form of the given annotation, that is,
+     * 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 {@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) {
+        boolean annotates = topLevel && out.annotates();
+        StringIdsSection stringIds = file.getStringIds();
+        TypeIdsSection typeIds = file.getTypeIds();
+
+        CstType type = annotation.getType();
+        int typeIdx = typeIds.indexOf(type);
+
+        if (annotates) {
+            out.annotate("  type_idx: " + Hex.u4(typeIdx) + " // " +
+                    type.toHuman());
+        }
+
+        out.writeUleb128(typeIds.indexOf(annotation.getType()));
+
+        Collection<NameValuePair> pairs = annotation.getNameValuePairs();
+        int size = pairs.size();
+
+        if (annotates) {
+            out.annotate("  size: " + Hex.u4(size));
+        }
+
+        out.writeUleb128(size);
+
+        int at = 0;
+        for (NameValuePair pair : pairs) {
+            CstString name = pair.getName();
+            int nameIdx = stringIds.indexOf(name);
+            Constant value = pair.getValue();
+
+            if (annotates) {
+                out.annotate(0, "  elements[" + at + "]:");
+                at++;
+                out.annotate("    name_idx: " + Hex.u4(nameIdx) + " // " +
+                        name.toHuman());
+            }
+
+            out.writeUleb128(nameIdx);
+
+            if (annotates) {
+                out.annotate("    value: " + constantToHuman(value));
+            }
+
+            writeConstant(value);
+        }
+
+        if (annotates) {
+            out.endAnnotation();
+        }
+    }
+
+    /**
+     * Gets the colloquial type name and human form of the type of the
+     * given constant, when used as an encoded value.
+     *
+     * @param cst {@code non-null;} the constant
+     * @return {@code non-null;} its type name and human form
+     */
+    public static String constantToHuman(Constant cst) {
+        int type = constantToValueType(cst);
+
+        if (type == VALUE_NULL) {
+            return "null";
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(cst.typeName());
+        sb.append(' ');
+        sb.append(cst.toHuman());
+
+        return sb.toString();
+    }
+
+    /**
+     * Helper for {@link #writeConstant}, which writes out the value
+     * for any signed integral type.
+     *
+     * @param type the type constant
+     * @param value {@code long} bits of the value
+     */
+    private void writeSignedIntegralValue(int type, long value) {
+        /*
+         * Figure out how many bits are needed to represent the value,
+         * including a sign bit: The bit count is subtracted from 65
+         * and not 64 to account for the sign bit. The xor operation
+         * has the effect of leaving non-negative values alone and
+         * unary complementing negative values (so that a leading zero
+         * count always returns a useful number for our present
+         * purpose).
+         */
+        int requiredBits =
+            65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
+
+        // Round up the requiredBits to a number of bytes.
+        int requiredBytes = (requiredBits + 0x07) >> 3;
+
+        /*
+         * Write the header byte, which includes the type and
+         * requiredBytes - 1.
+         */
+        out.writeByte(type | ((requiredBytes - 1) << 5));
+
+        // Write the value, per se.
+        while (requiredBytes > 0) {
+            out.writeByte((byte) value);
+            value >>= 8;
+            requiredBytes--;
+        }
+    }
+
+    /**
+     * Helper for {@link #writeConstant}, which writes out the value
+     * for any unsigned integral type.
+     *
+     * @param type the type constant
+     * @param value {@code long} bits of the value
+     */
+    private void writeUnsignedIntegralValue(int type, long value) {
+        // Figure out how many bits are needed to represent the value.
+        int requiredBits = 64 - Long.numberOfLeadingZeros(value);
+        if (requiredBits == 0) {
+            requiredBits = 1;
+        }
+
+        // Round up the requiredBits to a number of bytes.
+        int requiredBytes = (requiredBits + 0x07) >> 3;
+
+        /*
+         * Write the header byte, which includes the type and
+         * requiredBytes - 1.
+         */
+        out.writeByte(type | ((requiredBytes - 1) << 5));
+
+        // Write the value, per se.
+        while (requiredBytes > 0) {
+            out.writeByte((byte) value);
+            value >>= 8;
+            requiredBytes--;
+        }
+    }
+
+    /**
+     * Helper for {@link #writeConstant}, which writes out a
+     * right-zero-extended value.
+     *
+     * @param type the type constant
+     * @param value {@code long} bits of the value
+     */
+    private void writeRightZeroExtendedValue(int type, long value) {
+        // Figure out how many bits are needed to represent the value.
+        int requiredBits = 64 - Long.numberOfTrailingZeros(value);
+        if (requiredBits == 0) {
+            requiredBits = 1;
+        }
+
+        // Round up the requiredBits to a number of bytes.
+        int requiredBytes = (requiredBits + 0x07) >> 3;
+
+        // Scootch the first bits to be written down to the low-order bits.
+        value >>= 64 - (requiredBytes * 8);
+
+        /*
+         * Write the header byte, which includes the type and
+         * requiredBytes - 1.
+         */
+        out.writeByte(type | ((requiredBytes - 1) << 5));
+
+        // Write the value, per se.
+        while (requiredBytes > 0) {
+            out.writeByte((byte) value);
+            value >>= 8;
+            requiredBytes--;
+        }
+    }
+
+
+    /**
+     * Helper for {@code addContents()} methods, which adds
+     * contents for a particular {@link Annotation}, calling itself
+     * recursively should it encounter a nested annotation.
+     *
+     * @param file {@code non-null;} the file to add to
+     * @param annotation {@code non-null;} the annotation to add contents for
+     */
+    public static void addContents(DexFile file, Annotation annotation) {
+        TypeIdsSection typeIds = file.getTypeIds();
+        StringIdsSection stringIds = file.getStringIds();
+
+        typeIds.intern(annotation.getType());
+
+        for (NameValuePair pair : annotation.getNameValuePairs()) {
+            stringIds.intern(pair.getName());
+            addContents(file, pair.getValue());
+        }
+    }
+
+    /**
+     * 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 {@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) {
+        if (cst instanceof CstAnnotation) {
+            addContents(file, ((CstAnnotation) cst).getAnnotation());
+        } else if (cst instanceof CstArray) {
+            CstArray.List list = ((CstArray) cst).getList();
+            int size = list.size();
+            for (int i = 0; i < size; i++) {
+                addContents(file, list.get(i));
+            }
+        } else {
+            file.internIfAppropriate(cst);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/gen/BinaryOp.java b/dx/src/com/android/dx/gen/BinaryOp.java
new file mode 100644
index 0000000..65a2998
--- /dev/null
+++ b/dx/src/com/android/dx/gen/BinaryOp.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * An operation on two values of the same type.
+ *
+ * <p>Math operations ({@link #ADD}, {@link #SUBTRACT}, {@link #MULTIPLY},
+ * {@link #DIVIDE}, and {@link #REMAINDER}) support ints, longs, floats and
+ * doubles.
+ *
+ * <p>Bit operations ({@link #AND}, {@link #OR}, {@link #XOR}, {@link
+ * #SHIFT_LEFT}, {@link #SHIFT_RIGHT}, {@link #UNSIGNED_SHIFT_RIGHT}) support
+ * ints and longs.
+ *
+ * <p>Division by zero behaves differently depending on the operand type.
+ * For int and long operands, {@link #DIVIDE} and {@link #REMAINDER} throw
+ * {@link ArithmeticException} if {@code b == 0}. For float and double operands,
+ * the operations return {@code NaN}.
+ */
+public enum BinaryOp {
+    /** {@code a + b} */
+    ADD() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opAdd(types);
+        }
+    },
+
+    /** {@code a - b} */
+    SUBTRACT() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opSub(types);
+        }
+    },
+
+    /** {@code a * b} */
+    MULTIPLY() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opMul(types);
+        }
+    },
+
+    /** {@code a / b} */
+    DIVIDE() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opDiv(types);
+        }
+    },
+
+    /** {@code a % b} */
+    REMAINDER() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opRem(types);
+        }
+    },
+
+    /** {@code a & b} */
+    AND() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opAnd(types);
+        }
+    },
+
+    /** {@code a | b} */
+    OR() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opOr(types);
+        }
+    },
+
+    /** {@code a ^ b} */
+    XOR() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opXor(types);
+        }
+    },
+
+    /** {@code a << b} */
+    SHIFT_LEFT() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opShl(types);
+        }
+    },
+
+    /** {@code a >> b} */
+    SHIFT_RIGHT() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opShr(types);
+        }
+    },
+
+    /** {@code a >>> b} */
+    UNSIGNED_SHIFT_RIGHT() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opUshr(types);
+        }
+    };
+
+    abstract Rop rop(com.android.dx.rop.type.TypeList types);
+}
diff --git a/dx/src/com/android/dx/gen/Code.java b/dx/src/com/android/dx/gen/Code.java
new file mode 100644
index 0000000..b44d01c
--- /dev/null
+++ b/dx/src/com/android/dx/gen/Code.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import static com.android.dx.rop.code.Rop.BRANCH_GOTO;
+import static com.android.dx.rop.code.Rop.BRANCH_NONE;
+import static com.android.dx.rop.code.Rop.BRANCH_RETURN;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.code.ThrowingCstInsn;
+import com.android.dx.rop.code.ThrowingInsn;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.type.StdTypeList;
+import static com.android.dx.rop.type.Type.BT_BYTE;
+import static com.android.dx.rop.type.Type.BT_CHAR;
+import static com.android.dx.rop.type.Type.BT_INT;
+import static com.android.dx.rop.type.Type.BT_SHORT;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Builds a sequence of instructions.
+ */
+public final class Code {
+    private final MethodId<?, ?> method;
+    /**
+     * All allocated labels. Although the order of the labels in this list
+     * shouldn't impact behavior, it is used to determine basic block indices.
+     */
+    private final List<Label> labels = new ArrayList<Label>();
+
+    /**
+     * The label currently receiving instructions. This is null if the most
+     * recent instruction was a return or goto.
+     */
+    private Label currentLabel;
+
+    /** true once we've fixed the positions of the parameter registers */
+    private boolean localsInitialized;
+
+    private final Local<?> thisLocal;
+    private final List<Local<?>> parameters = new ArrayList<Local<?>>();
+    private final List<Local<?>> locals = new ArrayList<Local<?>>();
+    private SourcePosition sourcePosition = SourcePosition.NO_INFO;
+    private final List<Type<?>> catchTypes = new ArrayList<Type<?>>();
+    private final List<Label> catchLabels = new ArrayList<Label>();
+    private StdTypeList catches = StdTypeList.EMPTY;
+
+    Code(DexGenerator.MethodDeclaration methodDeclaration) {
+        this.method = methodDeclaration.method;
+        this.thisLocal = methodDeclaration.isStatic()
+                ? null
+                : Local.get(this, method.declaringType);
+        for (Type<?> parameter : method.parameters.types) {
+            parameters.add(Local.get(this, parameter));
+        }
+        this.currentLabel = newLabel();
+        this.currentLabel.marked = true;
+    }
+
+    public <T> Local<T> newLocal(Type<T> type) {
+        if (localsInitialized) {
+            throw new IllegalStateException("Cannot allocate locals after adding instructions");
+        }
+        Local<T> result = Local.get(this, type);
+        locals.add(result);
+        return result;
+    }
+
+    public <T> Local<T> getParameter(int index, Type<T> type) {
+        return coerce(parameters.get(index), type);
+    }
+
+    public <T> Local<T> getThis(Type<T> type) {
+        if (thisLocal == null) {
+            throw new IllegalStateException("static methods cannot access 'this'");
+        }
+        return coerce(thisLocal, type);
+    }
+
+    @SuppressWarnings("unchecked") // guarded by an equals check
+    private <T> Local<T> coerce(Local<?> local, Type<T> expectedType) {
+        if (!local.type.equals(expectedType)) {
+            throw new IllegalArgumentException(
+                    "requested " + expectedType + " but was " + local.type);
+        }
+        return (Local<T>) local;
+    }
+
+    /**
+     * Assigns registers to locals. From the spec:
+     *  "the N arguments to a method land in the last N registers of the
+     *   method's invocation frame, in order. Wide arguments consume two
+     *   registers. Instance methods are passed a this reference as their
+     *   first argument."
+     *
+     * In addition to assigning registers to each of the locals, this creates
+     * instructions to move parameters into their initial registers. These
+     * instructions are inserted before the code's first real instruction.
+     */
+    void initializeLocals() {
+        if (localsInitialized) {
+            throw new AssertionError();
+        }
+        localsInitialized = true;
+
+        int reg = 0;
+        for (Local<?> local : locals) {
+            reg += local.initialize(reg);
+        }
+        if (thisLocal != null) {
+            reg += thisLocal.initialize(reg);
+        }
+        int firstParamReg = reg;
+
+        List<Insn> moveParameterInstructions = new ArrayList<Insn>();
+        for (Local<?> local : parameters) {
+            CstInteger paramConstant = CstInteger.make(reg - firstParamReg);
+            reg += local.initialize(reg);
+            moveParameterInstructions.add(new PlainCstInsn(Rops.opMoveParam(local.type.ropType),
+                    sourcePosition, local.spec(), RegisterSpecList.EMPTY, paramConstant));
+        }
+        labels.get(0).instructions.addAll(0, moveParameterInstructions);
+    }
+
+    int paramSize() {
+        int result = 0;
+        for (Local<?> local : parameters) {
+            result += local.size();
+        }
+        return result;
+    }
+
+    // labels
+
+    /**
+     * Creates a new label for use as a branch target. The new label must have
+     * code attached to it later by calling {@link #mark(Label)}.
+     */
+    public Label newLabel() {
+        Label result = new Label();
+        labels.add(result);
+        return result;
+    }
+
+    /**
+     * Start defining instructions for the named label.
+     */
+    public void mark(Label label) {
+        if (label.marked) {
+            throw new IllegalStateException("already marked");
+        }
+        label.marked = true;
+        if (currentLabel != null) {
+            jump(label); // blocks must end with a branch, return or throw
+        }
+        currentLabel = label;
+    }
+
+    public void jump(Label target) {
+        addInstruction(new PlainInsn(Rops.GOTO, sourcePosition, null, RegisterSpecList.EMPTY),
+                target);
+    }
+
+    public void addCatchClause(Type<?> throwable, Label catchClause) {
+        if (catchTypes.contains(throwable)) {
+            throw new IllegalArgumentException("Already caught: " + throwable);
+        }
+        catchTypes.add(throwable);
+        catches = toTypeList(catchTypes);
+        catchLabels.add(catchClause);
+    }
+
+    public Label removeCatchClause(Type<?> throwable) {
+        int index = catchTypes.indexOf(throwable);
+        if (index == -1) {
+            throw new IllegalArgumentException("No catch clause: " + throwable);
+        }
+        catchTypes.remove(index);
+        catches = toTypeList(catchTypes);
+        return catchLabels.remove(index);
+    }
+
+    public void throwValue(Local<?> throwable) {
+        addInstruction(new ThrowingInsn(Rops.THROW, sourcePosition,
+                RegisterSpecList.make(throwable.spec()), catches));
+    }
+
+    private StdTypeList toTypeList(List<Type<?>> types) {
+        StdTypeList result = new StdTypeList(types.size());
+        for (int i = 0; i < types.size(); i++) {
+            result.set(i, types.get(i).ropType);
+        }
+        return result;
+    }
+
+    private void addInstruction(Insn insn) {
+        addInstruction(insn, null);
+    }
+
+    /**
+     * @param branch the branches to follow; interpretation depends on the
+     *     instruction's branchingness.
+     */
+    private void addInstruction(Insn insn, Label branch) {
+        if (currentLabel == null || !currentLabel.marked) {
+            throw new IllegalStateException("no current label");
+        }
+        currentLabel.instructions.add(insn);
+
+        switch (insn.getOpcode().getBranchingness()) {
+        case BRANCH_NONE:
+            if (branch != null) {
+                throw new IllegalArgumentException("unexpected branch: " + branch);
+            }
+            return;
+
+        case BRANCH_RETURN:
+            if (branch != null) {
+                throw new IllegalArgumentException("unexpected branch: " + branch);
+            }
+            currentLabel = null;
+            break;
+
+        case BRANCH_GOTO:
+            if (branch == null) {
+                throw new IllegalArgumentException("branch == null");
+            }
+            currentLabel.primarySuccessor = branch;
+            currentLabel = null;
+            break;
+
+        case Rop.BRANCH_IF:
+            if (branch == null) {
+                throw new IllegalArgumentException("branch == null");
+            }
+            splitCurrentLabel(branch, Collections.<Label>emptyList());
+            break;
+
+        case Rop.BRANCH_THROW:
+            if (branch != null) {
+                throw new IllegalArgumentException("unexpected branch: " + branch);
+            }
+            splitCurrentLabel(null, new ArrayList<Label>(catchLabels));
+            break;
+
+        default:
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Closes the current label and starts a new one.
+     *
+     * @param catchLabels an immutable list of catch labels
+     */
+    private void splitCurrentLabel(Label alternateSuccessor, List<Label> catchLabels) {
+        Label newLabel = newLabel();
+        currentLabel.primarySuccessor = newLabel;
+        currentLabel.alternateSuccessor = alternateSuccessor;
+        currentLabel.catchLabels = catchLabels;
+        currentLabel = newLabel;
+        currentLabel.marked = true;
+    }
+
+    // instructions: constants
+
+    public <T> void loadConstant(Local<T> target, T value) {
+        Rop rop = Rops.opConst(target.type.ropType);
+        if (rop.getBranchingness() == BRANCH_NONE) {
+            addInstruction(new PlainCstInsn(rop, sourcePosition, target.spec(),
+                    RegisterSpecList.EMPTY, Constants.getConstant(value)));
+        } else {
+            addInstruction(new ThrowingCstInsn(rop, sourcePosition,
+                    RegisterSpecList.EMPTY, catches, Constants.getConstant(value)));
+            moveResult(target, true);
+        }
+    }
+
+    // instructions: unary
+
+    public <T> void negate(Local<T> source, Local<T> target) {
+        unary(Rops.opNeg(source.type.ropType), source, target);
+    }
+
+    public <T> void not(Local<T> source, Local<T> target) {
+        unary(Rops.opNot(source.type.ropType), source, target);
+    }
+
+    public void numericCast(Local<?> source, Local<?> target) {
+        unary(getCastRop(source.type.ropType, target.type.ropType), source, target);
+    }
+
+    private Rop getCastRop(com.android.dx.rop.type.Type sourceType,
+            com.android.dx.rop.type.Type targetType) {
+        if (sourceType.getBasicType() == BT_INT) {
+            switch (targetType.getBasicType()) {
+            case BT_SHORT:
+                return Rops.TO_SHORT;
+            case BT_CHAR:
+                return Rops.TO_CHAR;
+            case BT_BYTE:
+                return Rops.TO_BYTE;
+            }
+        }
+        return Rops.opConv(targetType, sourceType);
+    }
+
+    private void unary(Rop rop, Local<?> source, Local<?> target) {
+        addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), source.spec()));
+    }
+
+    // instructions: binary
+
+    public <T> void op(BinaryOp op, Local<T> target, Local<T> a, Local<T> b) {
+        Rop rop = op.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
+        RegisterSpecList sources = RegisterSpecList.make(a.spec(), b.spec());
+
+        if (rop.getBranchingness() == BRANCH_NONE) {
+            addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), sources));
+        } else {
+            addInstruction(new ThrowingInsn(rop, sourcePosition, sources, catches));
+            moveResult(target, true);
+        }
+    }
+
+    // instructions: branches
+
+    /**
+     * Compare ints. If the comparison is true, execution jumps to {@code
+     * trueLabel}. If it is false, execution continues to the next instruction.
+     */
+    public <T> void compare(Comparison comparison, Local<T> a, Local<T> b, Label trueLabel) {
+        if (trueLabel == null) {
+            throw new IllegalArgumentException();
+        }
+        Rop rop = comparison.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
+        addInstruction(new PlainInsn(rop, sourcePosition, null,
+                RegisterSpecList.make(a.spec(), b.spec())), trueLabel);
+    }
+
+    /**
+     * Compare floats or doubles.
+     */
+    public <T extends Number> void compare(Local<T> a, Local<T> b, Local<Integer> target,
+            int nanValue) {
+        Rop rop;
+        if (nanValue == 1) {
+            rop = Rops.opCmpg(a.type.ropType);
+        } else if (nanValue == -1) {
+            rop = Rops.opCmpl(a.type.ropType);
+        } else {
+            throw new IllegalArgumentException("expected 1 or -1 but was " + nanValue);
+        }
+        addInstruction(new PlainInsn(rop, sourcePosition, target.spec(),
+                RegisterSpecList.make(a.spec(), b.spec())));
+    }
+
+    /**
+     * Compare longs.
+     */
+    public <T> void compare(Local<T> a, Local<T> b, Local<?> target) {
+        addInstruction(new PlainInsn(Rops.CMPL_LONG, sourcePosition, target.spec(),
+                RegisterSpecList.make(a.spec(), b.spec())));
+    }
+
+    // instructions: fields
+
+    public <D, V> void iget(FieldId<D, V> fieldId, Local<D> instance, Local<V> target) {
+        addInstruction(new ThrowingCstInsn(Rops.opGetField(target.type.ropType), sourcePosition,
+                RegisterSpecList.make(instance.spec()), catches, fieldId.constant));
+        moveResult(target, true);
+    }
+
+    public <D, V> void iput(FieldId<D, V> fieldId, Local<D> instance, Local<V> source) {
+        addInstruction(new ThrowingCstInsn(Rops.opPutField(source.type.ropType), sourcePosition,
+                RegisterSpecList.make(source.spec(), instance.spec()), catches, fieldId.constant));
+    }
+
+    public <V> void sget(FieldId<?, V> fieldId, Local<V> target) {
+        addInstruction(new ThrowingCstInsn(Rops.opGetStatic(target.type.ropType), sourcePosition,
+                RegisterSpecList.EMPTY, catches, fieldId.constant));
+        moveResult(target, true);
+    }
+
+    public <V> void sput(FieldId<?, V> fieldId, Local<V> source) {
+        addInstruction(new ThrowingCstInsn(Rops.opPutStatic(source.type.ropType), sourcePosition,
+                RegisterSpecList.make(source.spec()), catches, fieldId.constant));
+    }
+
+    // instructions: invoke
+
+    public <T> void newInstance(Local<T> target, MethodId<T, Void> constructor, Local<?>... args) {
+        if (target == null) {
+            throw new IllegalArgumentException();
+        }
+        addInstruction(new ThrowingCstInsn(Rops.NEW_INSTANCE, sourcePosition,
+                RegisterSpecList.EMPTY, catches, constructor.declaringType.constant));
+        moveResult(target, true);
+        invokeDirect(constructor, null, target, args);
+    }
+
+    public <R> void invokeStatic(MethodId<?, R> method, Local<? super R> target, Local<?>... args) {
+        invoke(Rops.opInvokeStatic(method.prototype(true)), method, target, null, args);
+    }
+
+    public <D, R> void invokeVirtual(MethodId<D, R> method, Local<? super R> target,
+            Local<? extends D> object, Local<?>... args) {
+        invoke(Rops.opInvokeVirtual(method.prototype(true)), method, target, object, args);
+    }
+
+    public <D, R> void invokeDirect(MethodId<D, R> method, Local<? super R> target,
+            Local<? extends D> object, Local<?>... args) {
+        invoke(Rops.opInvokeDirect(method.prototype(true)), method, target, object, args);
+    }
+
+    public <D, R> void invokeSuper(MethodId<D, R> method, Local<? super R> target,
+            Local<? extends D> object, Local<?>... args) {
+        invoke(Rops.opInvokeSuper(method.prototype(true)), method, target, object, args);
+    }
+
+    public <D, R> void invokeInterface(MethodId<D, R> method, Local<? super R> target,
+            Local<? extends D> object, Local<?>... args) {
+        invoke(Rops.opInvokeInterface(method.prototype(true)), method, target, object, args);
+    }
+
+    private <D, R> void invoke(Rop rop, MethodId<D, R> method, Local<? super R> target,
+            Local<? extends D> object, Local<?>... args) {
+        addInstruction(new ThrowingCstInsn(rop, sourcePosition, concatenate(object, args),
+                catches, method.constant));
+        if (target != null) {
+            moveResult(target, false);
+        }
+    }
+
+    // instructions: types
+
+    public void instanceOfType(Local<?> target, Local<?> source, Type<?> type) {
+        addInstruction(new ThrowingCstInsn(Rops.INSTANCE_OF, sourcePosition,
+                RegisterSpecList.make(source.spec()), catches, type.constant));
+        moveResult(target, true);
+    }
+
+    public void typeCast(Local<?> source, Local<?> target) {
+        addInstruction(new ThrowingCstInsn(Rops.CHECK_CAST, sourcePosition,
+                RegisterSpecList.make(source.spec()), catches, target.type.constant));
+        moveResult(target, true);
+    }
+
+    // instructions: arrays
+
+    public <T> void arrayLength(Local<T> array, Local<Integer> target) {
+        addInstruction(new ThrowingInsn(Rops.ARRAY_LENGTH, sourcePosition,
+                RegisterSpecList.make(array.spec()), catches));
+        moveResult(target, true);
+    }
+
+    public <T> void newArray(Local<Integer> length, Local<T> target) {
+        addInstruction(new ThrowingCstInsn(Rops.opNewArray(target.type.ropType), sourcePosition,
+                RegisterSpecList.make(length.spec()), catches, target.type.constant));
+        moveResult(target, true);
+    }
+
+    public void aget(Local<?> array, Local<Integer> index, Local<?> target) {
+        addInstruction(new ThrowingInsn(Rops.opAget(target.type.ropType), sourcePosition,
+                RegisterSpecList.make(array.spec(), index.spec()), catches));
+        moveResult(target, true);
+    }
+
+    public void aput(Local<?> array, Local<Integer> index, Local<?> source) {
+        addInstruction(new ThrowingInsn(Rops.opAput(source.type.ropType), sourcePosition,
+                RegisterSpecList.make(source.spec(), array.spec(), index.spec()), catches));
+    }
+
+    // instructions: return
+
+    public void returnVoid() {
+        if (!method.returnType.equals(Type.VOID)) {
+            throw new IllegalArgumentException("declared " + method.returnType
+                    + " but returned void");
+        }
+        addInstruction(new PlainInsn(Rops.RETURN_VOID, sourcePosition, null,
+                RegisterSpecList.EMPTY));
+    }
+
+    public void returnValue(Local<?> result) {
+        if (!result.type.equals(method.returnType)) {
+            // TODO: this is probably too strict.
+            throw new IllegalArgumentException("declared " + method.returnType
+                    + " but returned " + result.type);
+        }
+        addInstruction(new PlainInsn(Rops.opReturn(result.type.ropType), sourcePosition,
+                null, RegisterSpecList.make(result.spec())));
+    }
+
+    private void moveResult(Local<?> target, boolean afterNonInvokeThrowingInsn) {
+        Rop rop = afterNonInvokeThrowingInsn
+                ? Rops.opMoveResultPseudo(target.type.ropType)
+                : Rops.opMoveResult(target.type.ropType);
+        addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), RegisterSpecList.EMPTY));
+    }
+
+    // produce BasicBlocks for dex
+
+    BasicBlockList toBasicBlocks() {
+        if (!localsInitialized) {
+            initializeLocals();
+        }
+
+        cleanUpLabels();
+
+        BasicBlockList result = new BasicBlockList(labels.size());
+        for (int i = 0; i < labels.size(); i++) {
+            result.set(i, labels.get(i).toBasicBlock());
+        }
+        return result;
+    }
+
+    /**
+     * Removes empty labels and assigns IDs to non-empty labels.
+     */
+    private void cleanUpLabels() {
+        int id = 0;
+        for (Iterator<Label> i = labels.iterator(); i.hasNext();) {
+            Label label = i.next();
+            if (label.isEmpty()) {
+                i.remove();
+            } else {
+                label.compact();
+                label.id = id++;
+            }
+        }
+    }
+
+    private static RegisterSpecList concatenate(Local<?> first, Local<?>[] rest) {
+        int offset = (first != null) ? 1 : 0;
+        RegisterSpecList result = new RegisterSpecList(offset + rest.length);
+        if (first != null) {
+            result.set(0, first.spec());
+        }
+        for (int i = 0; i < rest.length; i++) {
+            result.set(i + offset, rest[i].spec());
+        }
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/gen/Comparison.java b/dx/src/com/android/dx/gen/Comparison.java
new file mode 100644
index 0000000..40a6e97
--- /dev/null
+++ b/dx/src/com/android/dx/gen/Comparison.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * A comparison between two values of the same type.
+ */
+public enum Comparison {
+
+    /** {@code a < b} */
+    LT() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opIfLt(types);
+        }
+    },
+
+    /** {@code a <= b} */
+    LE() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opIfLe(types);
+        }
+    },
+
+    /** {@code a == b} */
+    EQ() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opIfEq(types);
+        }
+    },
+
+    /** {@code a >= b} */
+    GE() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opIfGe(types);
+        }
+    },
+
+    /** {@code a > b} */
+    GT() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opIfGt(types);
+        }
+    },
+
+    /** {@code a != b} */
+    NE() {
+        @Override Rop rop(TypeList types) {
+            return Rops.opIfNe(types);
+        }
+    };
+
+    abstract Rop rop(TypeList types);
+}
diff --git a/dx/src/com/android/dx/gen/Constants.java b/dx/src/com/android/dx/gen/Constants.java
new file mode 100644
index 0000000..255c2e4
--- /dev/null
+++ b/dx/src/com/android/dx/gen/Constants.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.cst.CstBoolean;
+import com.android.dx.rop.cst.CstByte;
+import com.android.dx.rop.cst.CstChar;
+import com.android.dx.rop.cst.CstDouble;
+import com.android.dx.rop.cst.CstFloat;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.CstKnownNull;
+import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstShort;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.TypedConstant;
+
+/**
+ * Factory for rop constants.
+ */
+final class Constants {
+    private Constants() {}
+
+    /**
+     * Returns a rop constant for the specified value.
+     *
+     * @param value null, a boxed primitive, String, Class, or Type.
+     */
+    static TypedConstant getConstant(Object value) {
+        if (value == null) {
+            return CstKnownNull.THE_ONE;
+        } else if (value instanceof Boolean) {
+            return CstBoolean.make((Boolean) value);
+        } else if (value instanceof Byte) {
+            return CstByte.make((Byte) value);
+        } else if (value instanceof Character) {
+            return CstChar.make((Character) value);
+        } else if (value instanceof Double) {
+            return CstDouble.make(Double.doubleToLongBits((Double) value));
+        } else if (value instanceof Float) {
+            return CstFloat.make(Float.floatToIntBits((Float) value));
+        } else if (value instanceof Integer) {
+            return CstInteger.make((Integer) value);
+        } else if (value instanceof Long) {
+            return CstLong.make((Long) value);
+        } else if (value instanceof Short) {
+            return CstShort.make((Short) value);
+        } else if (value instanceof String) {
+            return new CstString((String) value);
+        } else if (value instanceof Class) {
+            return new CstType(Type.get((Class<?>) value).ropType);
+        } else if (value instanceof Type) {
+            return new CstType(((Type) value).ropType);
+        } else {
+            throw new UnsupportedOperationException("Not a constant: " + value);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/gen/DexGenerator.java b/dx/src/com/android/dx/gen/DexGenerator.java
new file mode 100644
index 0000000..7cde9a9
--- /dev/null
+++ b/dx/src/com/android/dx/gen/DexGenerator.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.dex.DexFormat;
+import com.android.dx.dex.DexOptions;
+import com.android.dx.dex.code.DalvCode;
+import com.android.dx.dex.code.PositionList;
+import com.android.dx.dex.code.RopTranslator;
+import com.android.dx.dex.file.ClassDefItem;
+import com.android.dx.dex.file.DexFile;
+import com.android.dx.dex.file.EncodedField;
+import com.android.dx.dex.file.EncodedMethod;
+import com.android.dx.rop.code.AccessFlags;
+import static com.android.dx.rop.code.AccessFlags.*;
+import com.android.dx.rop.code.LocalVariableInfo;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.StdTypeList;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+
+/**
+ * Define types, fields and methods.
+ */
+public final class DexGenerator {
+    private final Map<Type<?>, TypeDeclaration> types
+            = new LinkedHashMap<Type<?>, TypeDeclaration>();
+
+    private TypeDeclaration getTypeDeclaration(Type<?> type) {
+        TypeDeclaration result = types.get(type);
+        if (result == null) {
+            result = new TypeDeclaration(type);
+            types.put(type, result);
+        }
+        return result;
+    }
+
+    /**
+     * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#CLASS_FLAGS}.
+     */
+    public void declare(Type<?> type, String sourceFile, int flags,
+            Type<?> supertype, Type<?>... interfaces) {
+        TypeDeclaration declaration = getTypeDeclaration(type);
+        if (declaration.declared) {
+            throw new IllegalStateException("already declared: " + type);
+        }
+        declaration.declared = true;
+        declaration.flags = flags;
+        declaration.supertype = supertype;
+        declaration.sourceFile = sourceFile;
+        declaration.interfaces = new TypeList(interfaces);
+    }
+
+    /**
+     * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#METHOD_FLAGS}.
+     */
+    public Code declare(MethodId<?, ?> method, int flags) {
+        TypeDeclaration typeDeclaration = getTypeDeclaration(method.declaringType);
+        if (typeDeclaration.methods.containsKey(method)) {
+            throw new IllegalStateException("already declared: " + method);
+        }
+        MethodDeclaration methodDeclaration = new MethodDeclaration(method, flags);
+        typeDeclaration.methods.put(method, methodDeclaration);
+        return methodDeclaration.code;
+    }
+
+    /**
+     * @param flags any flags masked by {@link AccessFlags#FIELD_FLAGS}.
+     */
+    public void declare(FieldId<?, ?> fieldId, int flags, Object staticValue) {
+        TypeDeclaration typeDeclaration = getTypeDeclaration(fieldId.declaringType);
+        if (typeDeclaration.fields.containsKey(fieldId)) {
+            throw new IllegalStateException("already declared: " + fieldId);
+        }
+        FieldDeclaration fieldDeclaration = new FieldDeclaration(fieldId, flags, staticValue);
+        typeDeclaration.fields.put(fieldId, fieldDeclaration);
+    }
+
+    /**
+     * Returns a .dex formatted file.
+     */
+    public byte[] generate() {
+        DexFile outputDex = new DexFile(new DexOptions());
+
+        for (TypeDeclaration typeDeclaration : types.values()) {
+            outputDex.add(typeDeclaration.toClassDefItem());
+        }
+
+        try {
+            return outputDex.toDex(null, false);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Loads the generated types into the current dalvikvm process.
+     */
+    public ClassLoader load(ClassLoader parent) throws IOException {
+        byte[] dex = generate();
+
+        /*
+         * This implementation currently dumps the dex to the filesystem. It
+         * jars the emitted .dex for the benefit of Gingerbread and earlier
+         * devices, which can't load .dex files directly.
+         *
+         * TODO: load the dex from memory where supported.
+         */
+        File result = File.createTempFile("Generated", ".jar");
+        result.deleteOnExit();
+        JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
+        jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME));
+        jarOut.write(dex);
+        jarOut.closeEntry();
+        jarOut.close();
+        try {
+            Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
+            return (ClassLoader) pathClassLoader.getConstructor(String.class, ClassLoader.class)
+                    .newInstance(result.getPath(), parent);
+        } catch (ClassNotFoundException e) {
+            throw new UnsupportedOperationException("load() requires a Dalvik VM", e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e.getCause());
+        } catch (InstantiationException e) {
+            throw new AssertionError();
+        } catch (NoSuchMethodException e) {
+            throw new AssertionError();
+        } catch (IllegalAccessException e) {
+            throw new AssertionError();
+        }
+    }
+
+    private static class TypeDeclaration {
+        private final Type<?> type;
+
+        /** declared state */
+        private boolean declared;
+        private int flags;
+        private Type<?> supertype;
+        private String sourceFile;
+        private TypeList interfaces;
+
+        private final Map<FieldId, FieldDeclaration> fields
+                = new LinkedHashMap<FieldId, FieldDeclaration>();
+        private final Map<MethodId, MethodDeclaration> methods
+                = new LinkedHashMap<MethodId, MethodDeclaration>();
+
+        TypeDeclaration(Type<?> type) {
+            this.type = type;
+        }
+
+        ClassDefItem toClassDefItem() {
+            if (!declared) {
+                throw new IllegalStateException("Undeclared type " + type + " declares members: "
+                        + fields.keySet() + " " + methods.keySet());
+            }
+
+            DexOptions dexOptions = new DexOptions();
+            dexOptions.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
+
+            CstType thisType = type.constant;
+
+            ClassDefItem out = new ClassDefItem(thisType, flags, supertype.constant,
+                    interfaces.ropTypes, new CstString(sourceFile));
+
+            for (MethodDeclaration method : methods.values()) {
+                EncodedMethod encoded = method.toEncodedMethod(dexOptions);
+                if (method.isDirect()) {
+                    out.addDirectMethod(encoded);
+                } else {
+                    out.addVirtualMethod(encoded);
+                }
+            }
+            for (FieldDeclaration field : fields.values()) {
+                EncodedField encoded = field.toEncodedField();
+                if (field.isStatic()) {
+                    out.addStaticField(encoded, Constants.getConstant(field.staticValue));
+                } else {
+                    out.addInstanceField(encoded);
+                }
+            }
+
+            return out;
+        }
+    }
+
+    static class FieldDeclaration {
+        final FieldId<?, ?> fieldId;
+        private final int accessFlags;
+        private final Object staticValue;
+
+        FieldDeclaration(FieldId<?, ?> fieldId, int accessFlags, Object staticValue) {
+            if ((accessFlags & (AccessFlags.ACC_STATIC)) == 0 && staticValue != null) {
+                throw new IllegalArgumentException("instance fields may not have a value");
+            }
+            this.fieldId = fieldId;
+            this.accessFlags = accessFlags;
+            this.staticValue = staticValue;
+        }
+
+        EncodedField toEncodedField() {
+            return new EncodedField(fieldId.constant, accessFlags);
+        }
+
+        public boolean isStatic() {
+            return (accessFlags & (AccessFlags.ACC_STATIC)) != 0;
+        }
+    }
+
+    static class MethodDeclaration {
+        final MethodId<?, ?> method;
+        private final int flags;
+        private final Code code;
+
+        public MethodDeclaration(MethodId<?, ?> method, int flags) {
+            this.method = method;
+            this.flags = flags;
+            this.code = new Code(this);
+        }
+
+        boolean isStatic() {
+            return (flags & ACC_STATIC) != 0;
+        }
+
+        boolean isDirect() {
+            return (flags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
+        }
+
+        EncodedMethod toEncodedMethod(DexOptions dexOptions) {
+            RopMethod ropMethod = new RopMethod(code.toBasicBlocks(), 0);
+            LocalVariableInfo locals = null;
+            DalvCode dalvCode = RopTranslator.translate(
+                    ropMethod, PositionList.NONE, locals, code.paramSize(), dexOptions);
+            return new EncodedMethod(method.constant, flags, dalvCode, StdTypeList.EMPTY);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/gen/FieldId.java b/dx/src/com/android/dx/gen/FieldId.java
new file mode 100644
index 0000000..62ef73b
--- /dev/null
+++ b/dx/src/com/android/dx/gen/FieldId.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+
+/**
+ * A field.
+ */
+public final class FieldId<D, V> {
+    final Type<D> declaringType;
+    final Type<V> type;
+    final String name;
+
+    /** cached converted state */
+    final CstNat nat;
+    final CstFieldRef constant;
+
+    FieldId(Type<D> declaringType, Type<V> type, String name) {
+        if (declaringType == null || type == null || name == null) {
+            throw new NullPointerException();
+        }
+        this.declaringType = declaringType;
+        this.type = type;
+        this.name = name;
+        this.nat = new CstNat(new CstString(name), new CstString(type.name));
+        this.constant = new CstFieldRef(declaringType.constant, nat);
+    }
+
+    public Type<D> getDeclaringType() {
+        return declaringType;
+    }
+
+    public Type<V> getType() {
+        return type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override public boolean equals(Object o) {
+        return o instanceof FieldId
+                && ((FieldId<?, ?>) o).declaringType.equals(declaringType)
+                && ((FieldId<?, ?>) o).name.equals(name);
+    }
+
+    @Override public int hashCode() {
+        return declaringType.hashCode() + 37 * name.hashCode();
+    }
+
+    @Override public String toString() {
+        return declaringType + "." + name;
+    }
+}
diff --git a/dx/src/com/android/dx/gen/Label.java b/dx/src/com/android/dx/gen/Label.java
new file mode 100644
index 0000000..633b5f1
--- /dev/null
+++ b/dx/src/com/android/dx/gen/Label.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.InsnList;
+import com.android.dx.util.IntList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A branch target in a list of instructions.
+ */
+public final class Label {
+
+    final List<Insn> instructions = new ArrayList<Insn>();
+
+    boolean marked = false;
+
+    /** an immutable list of labels corresponding to the types in the catch list */
+    List<Label> catchLabels = Collections.emptyList();
+
+    /** contains the next instruction if no branch occurs */
+    Label primarySuccessor;
+
+    /** contains the instruction to jump to if the if is true */
+    Label alternateSuccessor;
+
+    int id = -1;
+
+    Label() {}
+
+    boolean isEmpty() {
+        return instructions.isEmpty();
+    }
+
+    void compact() {
+        for (int i = 0; i < catchLabels.size(); i++) {
+            while (catchLabels.get(i).isEmpty()) {
+                catchLabels.set(i, catchLabels.get(i).primarySuccessor);
+            }
+        }
+        while (primarySuccessor != null && primarySuccessor.isEmpty()) {
+            primarySuccessor = primarySuccessor.primarySuccessor;
+        }
+        while (alternateSuccessor != null && alternateSuccessor.isEmpty()) {
+            alternateSuccessor = alternateSuccessor.primarySuccessor;
+        }
+    }
+
+    BasicBlock toBasicBlock() {
+        InsnList result = new InsnList(instructions.size());
+        for (int i = 0; i < instructions.size(); i++) {
+            result.set(i, instructions.get(i));
+        }
+        result.setImmutable();
+
+        int primarySuccessorIndex = -1;
+        IntList successors = new IntList();
+        for (Label catchLabel : catchLabels) {
+            successors.add(catchLabel.id);
+        }
+        if (primarySuccessor != null) {
+            primarySuccessorIndex = primarySuccessor.id;
+            successors.add(primarySuccessorIndex);
+        }
+        if (alternateSuccessor != null) {
+            successors.add(alternateSuccessor.id);
+        }
+        successors.setImmutable();
+
+        return new BasicBlock(id, result, successors, primarySuccessorIndex);
+    }
+}
diff --git a/dx/src/com/android/dx/gen/Local.java b/dx/src/com/android/dx/gen/Local.java
new file mode 100644
index 0000000..b98759c
--- /dev/null
+++ b/dx/src/com/android/dx/gen/Local.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.code.RegisterSpec;
+
+/**
+ * A temporary variable that holds a single value.
+ */
+public final class Local<T> {
+    private final Code code;
+    final Type<T> type;
+    private int reg = -1;
+    private RegisterSpec spec;
+
+    private Local(Code code, Type<T> type) {
+        this.code = code;
+        this.type = type;
+    }
+
+    static <T> Local<T> get(Code code, Type<T> type) {
+        return new Local<T>(code, type);
+    }
+
+    /**
+     * Assigns registers to this local.
+     *
+     * @return the number of registers required.
+     */
+    int initialize(int reg) {
+        this.reg = reg;
+        this.spec = RegisterSpec.make(reg, type.ropType);
+        return size();
+    }
+
+    int size() {
+        return type.ropType.getCategory();
+    }
+
+    RegisterSpec spec() {
+        if (spec == null) {
+            code.initializeLocals();
+            if (spec == null) {
+                throw new AssertionError();
+            }
+        }
+        return spec;
+    }
+
+    public Type getType() {
+        return type;
+    }
+
+    @Override public String toString() {
+        return "v" + reg + "(" + type + ")";
+    }
+}
diff --git a/dx/src/com/android/dx/gen/MethodId.java b/dx/src/com/android/dx/gen/MethodId.java
new file mode 100644
index 0000000..29d088a
--- /dev/null
+++ b/dx/src/com/android/dx/gen/MethodId.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Prototype;
+import java.util.List;
+
+/**
+ * A method or constructor.
+ */
+public final class MethodId<D, R> {
+    final Type<D> declaringType;
+    final Type<R> returnType;
+    final String name;
+    final TypeList parameters;
+
+    /** cached converted state */
+    final CstNat nat;
+    final CstMethodRef constant;
+
+    MethodId(Type<D> declaringType, Type<R> returnType, String name, TypeList parameters) {
+        if (declaringType == null || returnType == null || name == null || parameters == null) {
+            throw new NullPointerException();
+        }
+        this.declaringType = declaringType;
+        this.returnType = returnType;
+        this.name = name;
+        this.parameters = parameters;
+        this.nat = new CstNat(new CstString(name), new CstString(descriptor(false)));
+        this.constant = new CstMethodRef(declaringType.constant, nat);
+    }
+
+    public Type<D> getDeclaringType() {
+        return declaringType;
+    }
+
+    public Type<R> getReturnType() {
+        return returnType;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<Type<?>> getParameters() {
+        return parameters.asList();
+    }
+
+    /**
+     * Returns a descriptor like "(Ljava/lang/Class;[I)Ljava/lang/Object;".
+     */
+    String descriptor(boolean includeThis) {
+        StringBuilder result = new StringBuilder();
+        result.append("(");
+        if (includeThis) {
+            result.append(declaringType.name);
+        }
+        for (Type t : parameters.types) {
+            result.append(t.name);
+        }
+        result.append(")");
+        result.append(returnType.name);
+        return result.toString();
+    }
+
+    Prototype prototype(boolean includeThis) {
+        return Prototype.intern(descriptor(includeThis));
+    }
+
+    @Override public boolean equals(Object o) {
+        return o instanceof MethodId
+                && ((MethodId<?, ?>) o).declaringType.equals(declaringType)
+                && ((MethodId<?, ?>) o).name.equals(name)
+                && ((MethodId<?, ?>) o).parameters.equals(parameters)
+                && ((MethodId<?, ?>) o).returnType.equals(returnType);
+    }
+
+    @Override public int hashCode() {
+        int result = 17;
+        result = 31 * result + declaringType.hashCode();
+        result = 31 * result + name.hashCode();
+        result = 31 * result + parameters.hashCode();
+        result = 31 * result + returnType.hashCode();
+        return result;
+    }
+
+    @Override public String toString() {
+        return declaringType + "." + name + "(" + parameters + ")";
+    }
+}
diff --git a/dx/src/com/android/dx/gen/Type.java b/dx/src/com/android/dx/gen/Type.java
new file mode 100644
index 0000000..3b81f6d
--- /dev/null
+++ b/dx/src/com/android/dx/gen/Type.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.cst.CstType;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A primitive type, interface or class.
+ */
+public final class Type<T> {
+    /** The {@code boolean} primitive type. */
+    public static final Type<Boolean> BOOLEAN
+            = new Type<Boolean>(com.android.dx.rop.type.Type.BOOLEAN);
+
+    /** The {@code byte} primitive type. */
+    public static final Type<Byte> BYTE = new Type<Byte>(com.android.dx.rop.type.Type.BYTE);
+
+    /** The {@code char} primitive type. */
+    public static final Type<Character> CHAR
+            = new Type<Character>(com.android.dx.rop.type.Type.CHAR);
+
+    /** The {@code double} primitive type. */
+    public static final Type<Double> DOUBLE = new Type<Double>(com.android.dx.rop.type.Type.DOUBLE);
+
+    /** The {@code float} primitive type. */
+    public static final Type<Float> FLOAT = new Type<Float>(com.android.dx.rop.type.Type.FLOAT);
+
+    /** The {@code int} primitive type. */
+    public static final Type<Integer> INT = new Type<Integer>(com.android.dx.rop.type.Type.INT);
+
+    /** The {@code long} primitive type. */
+    public static final Type<Long> LONG = new Type<Long>(com.android.dx.rop.type.Type.LONG);
+
+    /** The {@code short} primitive type. */
+    public static final Type<Short> SHORT = new Type<Short>(com.android.dx.rop.type.Type.SHORT);
+
+    /** The {@code void} primitive type. Only used as a return type. */
+    public static final Type<Void> VOID = new Type<Void>(com.android.dx.rop.type.Type.VOID);
+
+    /** The {@code Object} type. */
+    public static final Type<Object> OBJECT = new Type<Object>(com.android.dx.rop.type.Type.OBJECT);
+
+    /** The {@code String} type. */
+    public static final Type<String> STRING = new Type<String>(com.android.dx.rop.type.Type.STRING);
+
+    private static final Map<Class<?>, Type<?>> PRIMITIVE_TO_TYPE
+            = new HashMap<Class<?>, Type<?>>();
+    static {
+        PRIMITIVE_TO_TYPE.put(boolean.class, BOOLEAN);
+        PRIMITIVE_TO_TYPE.put(byte.class, BYTE);
+        PRIMITIVE_TO_TYPE.put(char.class, CHAR);
+        PRIMITIVE_TO_TYPE.put(double.class, DOUBLE);
+        PRIMITIVE_TO_TYPE.put(float.class, FLOAT);
+        PRIMITIVE_TO_TYPE.put(int.class, INT);
+        PRIMITIVE_TO_TYPE.put(long.class, LONG);
+        PRIMITIVE_TO_TYPE.put(short.class, SHORT);
+        PRIMITIVE_TO_TYPE.put(void.class, VOID);
+    }
+
+    final String name;
+
+    /** cached converted values */
+    final com.android.dx.rop.type.Type ropType;
+    final CstType constant;
+
+    Type(com.android.dx.rop.type.Type ropType) {
+        this(ropType.getDescriptor(), ropType);
+    }
+
+    Type(String name, com.android.dx.rop.type.Type ropType) {
+        if (name == null || ropType == null) {
+            throw new NullPointerException();
+        }
+        this.name = name;
+        this.ropType = ropType;
+        this.constant = CstType.intern(ropType);
+    }
+
+    /**
+     * @param name a descriptor like "Ljava/lang/Class;".
+     */
+    public static <T> Type<T> get(String name) {
+        return new Type<T>(name, com.android.dx.rop.type.Type.internReturnType(name));
+    }
+
+    public static <T> Type<T> get(Class<T> type) {
+        if (type.isPrimitive()) {
+            @SuppressWarnings("unchecked") // guarded by equals
+            Type<T> result = (Type<T>) PRIMITIVE_TO_TYPE.get(type);
+            return result;
+        }
+        String name = type.getName().replace('.', '/');
+        return get(type.isArray() ? name : 'L' + name + ';');
+    }
+
+    public <V> FieldId<T, V> getField(Type<V> type, String name) {
+        return new FieldId<T, V>(this, type, name);
+    }
+
+    public MethodId<T, Void> getConstructor(Type<?>... parameters) {
+        return new MethodId<T, Void>(this, VOID, "<init>", new TypeList(parameters));
+    }
+
+    public <R> MethodId<T, R> getMethod(Type<R> returnType, String name, Type<?>... parameters) {
+        return new MethodId<T, R>(this, returnType, name, new TypeList(parameters));
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override public boolean equals(Object o) {
+        return o instanceof Type
+                && ((Type) o).name.equals(name);
+    }
+
+    @Override public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override public String toString() {
+        return name;
+    }
+}
diff --git a/dx/src/com/android/dx/gen/TypeList.java b/dx/src/com/android/dx/gen/TypeList.java
new file mode 100644
index 0000000..e18ed4a
--- /dev/null
+++ b/dx/src/com/android/dx/gen/TypeList.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.gen;
+
+import com.android.dx.rop.type.StdTypeList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An immutable of types.
+ */
+final class TypeList {
+    final Type<?>[] types;
+    final StdTypeList ropTypes;
+
+    TypeList(Type<?>[] types) {
+        this.types = types.clone();
+        this.ropTypes = new StdTypeList(types.length);
+        for (int i = 0; i < types.length; i++) {
+            ropTypes.set(i, types[i].ropType);
+        }
+    }
+
+    /**
+     * Returns an immutable list.
+     */
+    public List<Type<?>> asList() {
+        return Collections.unmodifiableList(Arrays.asList(types));
+    }
+
+    @Override public boolean equals(Object o) {
+        return o instanceof TypeList && Arrays.equals(((TypeList) o).types, types);
+    }
+
+    @Override public int hashCode() {
+        return Arrays.hashCode(types);
+    }
+
+    @Override public String toString() {
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < types.length; i++) {
+            if (i > 0) {
+                result.append(", ");
+            }
+            result.append(types[i]);
+        }
+        return result.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/io/Annotation.java b/dx/src/com/android/dx/io/Annotation.java
new file mode 100644
index 0000000..d3be592
--- /dev/null
+++ b/dx/src/com/android/dx/io/Annotation.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+
+/**
+ * An annotation.
+ */
+public final class Annotation implements Comparable<Annotation> {
+    private final DexBuffer buffer;
+    private final byte visibility;
+    private final int typeIndex;
+    private final int[] names;
+    private final EncodedValue[] values;
+
+    public Annotation(DexBuffer buffer, byte visibility, int typeIndex, int[] names,
+            EncodedValue[] values) {
+        this.buffer = buffer;
+        this.visibility = visibility;
+        this.typeIndex = typeIndex;
+        this.names = names;
+        this.values = values;
+    }
+
+    public byte getVisibility() {
+        return visibility;
+    }
+
+    public int getTypeIndex() {
+        return typeIndex;
+    }
+
+    public int[] getNames() {
+        return names;
+    }
+
+    public EncodedValue[] getValues() {
+        return values;
+    }
+
+    public void writeTo(DexBuffer.Section out) {
+        out.writeByte(visibility);
+        out.writeUleb128(typeIndex);
+        out.writeUleb128(names.length);
+        for (int i = 0; i < names.length; i++) {
+            out.writeUleb128(names[i]);
+            values[i].writeTo(out);
+        }
+    }
+
+    @Override public int compareTo(Annotation other) {
+        if (typeIndex != other.typeIndex) {
+            return Unsigned.compare(typeIndex, other.typeIndex);
+        }
+        int size = Math.min(names.length, other.names.length);
+        for (int i = 0; i < size; i++) {
+            if (names[i] != other.names[i]) {
+                return Unsigned.compare(names[i], other.names[i]);
+            }
+            int compare = values[i].compareTo(other.values[i]);
+            if (compare != 0) {
+                return compare;
+            }
+        }
+        return names.length - other.names.length;
+    }
+
+    @Override public String toString() {
+        if (buffer == null) {
+            return visibility + " " + typeIndex;
+        }
+
+        StringBuilder result = new StringBuilder();
+        result.append(visibility);
+        result.append(" ");
+        result.append(buffer.typeNames().get(typeIndex));
+        result.append("[");
+        for (int i = 0; i < names.length; i++) {
+            if (i > 0) {
+                result.append(", ");
+            }
+            result.append(buffer.strings().get(names[i]));
+            result.append("=");
+            result.append(values[i]);
+        }
+        result.append("]");
+        return result.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/io/ClassData.java b/dx/src/com/android/dx/io/ClassData.java
new file mode 100644
index 0000000..5da7ddd
--- /dev/null
+++ b/dx/src/com/android/dx/io/ClassData.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+public final class ClassData {
+    private final Field[] staticFields;
+    private final Field[] instanceFields;
+    private final Method[] directMethods;
+    private final Method[] virtualMethods;
+
+    public ClassData(Field[] staticFields, Field[] instanceFields,
+            Method[] directMethods, Method[] virtualMethods) {
+        this.staticFields = staticFields;
+        this.instanceFields = instanceFields;
+        this.directMethods = directMethods;
+        this.virtualMethods = virtualMethods;
+    }
+
+    public Field[] getStaticFields() {
+        return staticFields;
+    }
+
+    public Field[] getInstanceFields() {
+        return instanceFields;
+    }
+
+    public Method[] getDirectMethods() {
+        return directMethods;
+    }
+
+    public Method[] getVirtualMethods() {
+        return virtualMethods;
+    }
+
+    public Field[] allFields() {
+        Field[] result = new Field[staticFields.length + instanceFields.length];
+        System.arraycopy(staticFields, 0, result, 0, staticFields.length);
+        System.arraycopy(instanceFields, 0, result, staticFields.length, instanceFields.length);
+        return result;
+    }
+
+    public Method[] allMethods() {
+        Method[] result = new Method[directMethods.length + virtualMethods.length];
+        System.arraycopy(directMethods, 0, result, 0, directMethods.length);
+        System.arraycopy(virtualMethods, 0, result, directMethods.length, virtualMethods.length);
+        return result;
+    }
+
+    public static class Field {
+        private final int fieldIndex;
+        private final int accessFlags;
+
+        public Field(int fieldIndex, int accessFlags) {
+            this.fieldIndex = fieldIndex;
+            this.accessFlags = accessFlags;
+        }
+
+        public int getFieldIndex() {
+            return fieldIndex;
+        }
+
+        public int getAccessFlags() {
+            return accessFlags;
+        }
+    }
+
+    public static class Method {
+        private final int methodIndex;
+        private final int accessFlags;
+        private final int codeOffset;
+
+        public Method(int methodIndex, int accessFlags, int codeOffset) {
+            this.methodIndex = methodIndex;
+            this.accessFlags = accessFlags;
+            this.codeOffset = codeOffset;
+        }
+
+        public int getMethodIndex() {
+            return methodIndex;
+        }
+
+        public int getAccessFlags() {
+            return accessFlags;
+        }
+
+        public int getCodeOffset() {
+            return codeOffset;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/io/ClassDef.java b/dx/src/com/android/dx/io/ClassDef.java
new file mode 100644
index 0000000..5c8d10b
--- /dev/null
+++ b/dx/src/com/android/dx/io/ClassDef.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+/**
+ * A type definition.
+ */
+public final class ClassDef {
+    public static final int NO_INDEX = -1;
+    private final DexBuffer buffer;
+    private final int offset;
+    private final int typeIndex;
+    private final int accessFlags;
+    private final int supertypeIndex;
+    private final int interfacesOffset;
+    private final int sourceFileIndex;
+    private final int annotationsOffset;
+    private final int classDataOffset;
+    private final int staticValuesOffset;
+
+    public ClassDef(DexBuffer buffer, int offset, int typeIndex, int accessFlags,
+            int supertypeIndex, int interfacesOffset, int sourceFileIndex,
+            int annotationsOffset, int classDataOffset, int staticValuesOffset) {
+        this.buffer = buffer;
+        this.offset = offset;
+        this.typeIndex = typeIndex;
+        this.accessFlags = accessFlags;
+        this.supertypeIndex = supertypeIndex;
+        this.interfacesOffset = interfacesOffset;
+        this.sourceFileIndex = sourceFileIndex;
+        this.annotationsOffset = annotationsOffset;
+        this.classDataOffset = classDataOffset;
+        this.staticValuesOffset = staticValuesOffset;
+    }
+
+    public int getOffset() {
+        return offset;
+    }
+
+    public int getTypeIndex() {
+        return typeIndex;
+    }
+
+    public int getSupertypeIndex() {
+        return supertypeIndex;
+    }
+
+    public int getInterfacesOffset() {
+        return interfacesOffset;
+    }
+
+    public short[] getInterfaces() {
+        return buffer.readTypeList(interfacesOffset).getTypes();
+    }
+
+    public int getAccessFlags() {
+        return accessFlags;
+    }
+
+    public int getSourceFileIndex() {
+        return sourceFileIndex;
+    }
+
+    public int getAnnotationsOffset() {
+        return annotationsOffset;
+    }
+
+    public int getClassDataOffset() {
+        return classDataOffset;
+    }
+
+    public int getStaticValuesOffset() {
+        return staticValuesOffset;
+    }
+
+    @Override public String toString() {
+        if (buffer == null) {
+            return typeIndex + " " + supertypeIndex;
+        }
+
+        StringBuilder result = new StringBuilder();
+        result.append(buffer.typeNames().get(typeIndex));
+        if (supertypeIndex != NO_INDEX) {
+            result.append(" extends ").append(buffer.typeNames().get(supertypeIndex));
+        }
+        return result.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/io/Code.java b/dx/src/com/android/dx/io/Code.java
new file mode 100644
index 0000000..ba95d1b
--- /dev/null
+++ b/dx/src/com/android/dx/io/Code.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+public final class Code {
+    private final int registersSize;
+    private final int insSize;
+    private final int outsSize;
+    private final int debugInfoOffset;
+    private final short[] instructions;
+    private final Try[] tries;
+    private final CatchHandler[] catchHandlers;
+
+    public Code(int registersSize, int insSize, int outsSize, int debugInfoOffset,
+            short[] instructions, Try[] tries, CatchHandler[] catchHandlers) {
+        this.registersSize = registersSize;
+        this.insSize = insSize;
+        this.outsSize = outsSize;
+        this.debugInfoOffset = debugInfoOffset;
+        this.instructions = instructions;
+        this.tries = tries;
+        this.catchHandlers = catchHandlers;
+    }
+
+    public int getRegistersSize() {
+        return registersSize;
+    }
+
+    public int getInsSize() {
+        return insSize;
+    }
+
+    public int getOutsSize() {
+        return outsSize;
+    }
+
+    public int getDebugInfoOffset() {
+        return debugInfoOffset;
+    }
+
+    public short[] getInstructions() {
+        return instructions;
+    }
+
+    public Try[] getTries() {
+        return tries;
+    }
+
+    public CatchHandler[] getCatchHandlers() {
+        return catchHandlers;
+    }
+
+    public static class Try {
+        final int startAddress;
+        final int instructionCount;
+        final int handlerOffset;
+
+        Try(int startAddress, int instructionCount, int handlerOffset) {
+            this.startAddress = startAddress;
+            this.instructionCount = instructionCount;
+            this.handlerOffset = handlerOffset;
+        }
+
+        public int getStartAddress() {
+            return startAddress;
+        }
+
+        public int getInstructionCount() {
+            return instructionCount;
+        }
+
+        public int getHandlerOffset() {
+            return handlerOffset;
+        }
+    }
+
+    public static class CatchHandler {
+        final int[] typeIndexes;
+        final int[] addresses;
+        final int catchAllAddress;
+
+        public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress) {
+            this.typeIndexes = typeIndexes;
+            this.addresses = addresses;
+            this.catchAllAddress = catchAllAddress;
+        }
+
+        public int[] getTypeIndexes() {
+            return typeIndexes;
+        }
+
+        public int[] getAddresses() {
+            return addresses;
+        }
+
+        public int getCatchAllAddress() {
+            return catchAllAddress;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/io/CodeReader.java b/dx/src/com/android/dx/io/CodeReader.java
new file mode 100644
index 0000000..cab1063
--- /dev/null
+++ b/dx/src/com/android/dx/io/CodeReader.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.io.instructions.DecodedInstruction;
+import com.android.dx.util.DexException;
+
+/**
+ * Walks through a block of code and calls visitor call backs.
+ */
+public final class CodeReader {
+    private Visitor fallbackVisitor = null;
+    private Visitor stringVisitor = null;
+    private Visitor typeVisitor = null;
+    private Visitor fieldVisitor = null;
+    private Visitor methodVisitor = null;
+
+    /**
+     * Sets {@code visitor} as the visitor for all instructions.
+     */
+    public void setAllVisitors(Visitor visitor) {
+        fallbackVisitor = visitor;
+        stringVisitor = visitor;
+        typeVisitor = visitor;
+        fieldVisitor = visitor;
+        methodVisitor = visitor;
+    }
+
+    /**
+     * Sets {@code visitor} as the visitor for all instructions not
+     * otherwise handled.
+     */
+    public void setFallbackVisitor(Visitor visitor) {
+        fallbackVisitor = visitor;
+    }
+
+    /**
+     * Sets {@code visitor} as the visitor for all string instructions.
+     */
+    public void setStringVisitor(Visitor visitor) {
+        stringVisitor = visitor;
+    }
+
+    /**
+     * Sets {@code visitor} as the visitor for all type instructions.
+     */
+    public void setTypeVisitor(Visitor visitor) {
+        typeVisitor = visitor;
+    }
+
+    /**
+     * Sets {@code visitor} as the visitor for all field instructions.
+     */
+    public void setFieldVisitor(Visitor visitor) {
+        fieldVisitor = visitor;
+    }
+
+    /**
+     * Sets {@code visitor} as the visitor for all method instructions.
+     */
+    public void setMethodVisitor(Visitor visitor) {
+        methodVisitor = visitor;
+    }
+
+    public void visitAll(DecodedInstruction[] decodedInstructions)
+            throws DexException {
+        int size = decodedInstructions.length;
+
+        for (int i = 0; i < size; i++) {
+            DecodedInstruction one = decodedInstructions[i];
+            if (one == null) {
+                continue;
+            }
+
+            callVisit(decodedInstructions, one);
+        }
+    }
+
+    public void visitAll(short[] encodedInstructions) throws DexException {
+        DecodedInstruction[] decodedInstructions =
+            DecodedInstruction.decodeAll(encodedInstructions);
+        visitAll(decodedInstructions);
+    }
+
+    private void callVisit(DecodedInstruction[] all, DecodedInstruction one) {
+        Visitor visitor = null;
+
+        switch (OpcodeInfo.getIndexType(one.getOpcode())) {
+            case STRING_REF: visitor = stringVisitor; break;
+            case TYPE_REF:   visitor = typeVisitor;   break;
+            case FIELD_REF:  visitor = fieldVisitor;  break;
+            case METHOD_REF: visitor = methodVisitor; break;
+        }
+
+        if (visitor == null) {
+            visitor = fallbackVisitor;
+        }
+
+        if (visitor != null) {
+            visitor.visit(all, one);
+        }
+    }
+
+    public interface Visitor {
+        void visit(DecodedInstruction[] all, DecodedInstruction one);
+    }
+}
diff --git a/dx/src/com/android/dx/io/DexBuffer.java b/dx/src/com/android/dx/io/DexBuffer.java
new file mode 100644
index 0000000..d10b08c
--- /dev/null
+++ b/dx/src/com/android/dx/io/DexBuffer.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.dex.DexFormat;
+import com.android.dx.dex.SizeOf;
+import com.android.dx.dex.TableOfContents;
+import com.android.dx.merge.TypeList;
+import com.android.dx.util.ByteInput;
+import com.android.dx.util.ByteOutput;
+import com.android.dx.util.DexException;
+import com.android.dx.util.FileUtils;
+import com.android.dx.util.Leb128Utils;
+import com.android.dx.util.Mutf8;
+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.io.OutputStream;
+import java.io.UTFDataFormatException;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * The bytes of a dex file in memory for reading and writing. All int offsets
+ * are unsigned.
+ */
+public final class DexBuffer {
+    private byte[] data;
+    private final TableOfContents tableOfContents = new TableOfContents();
+    private int length = 0;
+
+    private final List<String> strings = new AbstractList<String>() {
+        @Override public String get(int index) {
+            checkBounds(index, tableOfContents.stringIds.size);
+            return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM))
+                    .readString();
+        }
+        @Override public int size() {
+            return tableOfContents.stringIds.size;
+        }
+    };
+
+    private final List<Integer> typeIds = new AbstractList<Integer>() {
+        @Override public Integer get(int index) {
+            checkBounds(index, tableOfContents.typeIds.size);
+            return open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();
+        }
+        @Override public int size() {
+            return tableOfContents.typeIds.size;
+        }
+    };
+
+    private final List<String> typeNames = new AbstractList<String>() {
+        @Override public String get(int index) {
+            checkBounds(index, tableOfContents.typeIds.size);
+            return strings.get(typeIds.get(index));
+        }
+        @Override public int size() {
+            return tableOfContents.typeIds.size;
+        }
+    };
+
+    private final List<ProtoId> protoIds = new AbstractList<ProtoId>() {
+        @Override public ProtoId get(int index) {
+            checkBounds(index, tableOfContents.protoIds.size);
+            return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index))
+                    .readProtoId();
+        }
+        @Override public int size() {
+            return tableOfContents.protoIds.size;
+        }
+    };
+
+    private final List<FieldId> fieldIds = new AbstractList<FieldId>() {
+        @Override public FieldId get(int index) {
+            checkBounds(index, tableOfContents.fieldIds.size);
+            return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index))
+                    .readFieldId();
+        }
+        @Override public int size() {
+            return tableOfContents.fieldIds.size;
+        }
+    };
+
+    private final List<MethodId> methodIds = new AbstractList<MethodId>() {
+        @Override public MethodId get(int index) {
+            checkBounds(index, tableOfContents.methodIds.size);
+            return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index))
+                    .readMethodId();
+        }
+        @Override public int size() {
+            return tableOfContents.methodIds.size;
+        }
+    };
+
+    /**
+     * Creates a new dex buffer defining no classes.
+     */
+    public DexBuffer() {
+        this.data = new byte[0];
+    }
+
+    /**
+     * Creates a new dex buffer that reads from {@code data}. It is an error to
+     * modify {@code data} after using it to create a dex buffer.
+     */
+    public DexBuffer(byte[] data) throws IOException {
+        this.data = data;
+        this.length = data.length;
+        this.tableOfContents.readFrom(this);
+    }
+
+    /**
+     * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
+     */
+    public DexBuffer(InputStream in) throws IOException {
+        loadFrom(in);
+    }
+
+    /**
+     * Creates a new dex buffer from the dex file {@code file}.
+     */
+    public DexBuffer(File file) throws IOException {
+        if (FileUtils.hasArchiveSuffix(file.getName())) {
+            ZipFile zipFile = new ZipFile(file);
+            ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
+            if (entry != null) {
+                loadFrom(zipFile.getInputStream(entry));
+                zipFile.close();
+            } else {
+                throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
+            }
+        } else if (file.getName().endsWith(".dex")) {
+            loadFrom(new FileInputStream(file));
+        } else {
+            throw new DexException("unknown output extension: " + file);
+        }
+    }
+
+    private void loadFrom(InputStream in) throws IOException {
+        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+        byte[] buffer = new byte[8192];
+
+        int count;
+        while ((count = in.read(buffer)) != -1) {
+            bytesOut.write(buffer, 0, count);
+        }
+        in.close();
+
+        this.data = bytesOut.toByteArray();
+        this.length = data.length;
+        this.tableOfContents.readFrom(this);
+    }
+
+    private static void checkBounds(int index, int length) {
+        if (index < 0 || index >= length) {
+            throw new IndexOutOfBoundsException("index:" + index + ", length=" + length);
+        }
+    }
+
+    public void writeTo(OutputStream out) throws IOException {
+        out.write(data);
+    }
+
+    public void writeTo(File dexOut) throws IOException {
+        OutputStream out = new FileOutputStream(dexOut);
+        writeTo(out);
+        out.close();
+    }
+
+    public TableOfContents getTableOfContents() {
+        return tableOfContents;
+    }
+
+    public Section open(int position) {
+        if (position < 0 || position > length) {
+            throw new IllegalArgumentException("position=" + position + " length=" + length);
+        }
+        return new Section(position);
+    }
+
+    public Section appendSection(int maxByteCount, String name) {
+        int limit = fourByteAlign(length + maxByteCount);
+        Section result = new Section(name, length, limit);
+        length = limit;
+        return result;
+    }
+
+    public void noMoreSections() {
+        data = new byte[length];
+    }
+
+    public int getLength() {
+        return length;
+    }
+
+    private static int fourByteAlign(int position) {
+        return (position + 3) & ~3;
+    }
+
+    public byte[] getBytes() {
+        return data;
+    }
+
+    public List<String> strings() {
+        return strings;
+    }
+
+    public List<Integer> typeIds() {
+        return typeIds;
+    }
+
+    public List<String> typeNames() {
+        return typeNames;
+    }
+
+    public List<ProtoId> protoIds() {
+        return protoIds;
+    }
+
+    public List<FieldId> fieldIds() {
+        return fieldIds;
+    }
+
+    public List<MethodId> methodIds() {
+        return methodIds;
+    }
+
+    public Iterable<ClassDef> classDefs() {
+        return new Iterable<ClassDef>() {
+            public Iterator<ClassDef> iterator() {
+                if (!tableOfContents.classDefs.exists()) {
+                    return Collections.<ClassDef>emptySet().iterator();
+                }
+                return new Iterator<ClassDef>() {
+                    private DexBuffer.Section in = open(tableOfContents.classDefs.off);
+                    private int count = 0;
+
+                    public boolean hasNext() {
+                        return count < tableOfContents.classDefs.size;
+                    }
+                    public ClassDef next() {
+                        if (!hasNext()) {
+                            throw new NoSuchElementException();
+                        }
+                        count++;
+                        return in.readClassDef();
+                    }
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+
+    public TypeList readTypeList(int offset) {
+        if (offset == 0) {
+            return TypeList.EMPTY;
+        }
+        return open(offset).readTypeList();
+    }
+
+    public ClassData readClassData(ClassDef classDef) {
+        int offset = classDef.getClassDataOffset();
+        if (offset == 0) {
+            throw new IllegalArgumentException("offset == 0");
+        }
+        return open(offset).readClassData();
+    }
+
+    public Code readCode(ClassData.Method method) {
+        int offset = method.getCodeOffset();
+        if (offset == 0) {
+            throw new IllegalArgumentException("offset == 0");
+        }
+        return open(offset).readCode();
+    }
+
+    public final class Section implements ByteInput, ByteOutput {
+        private final String name;
+        private int position;
+        private final int limit;
+
+        private Section(String name, int position, int limit) {
+            this.name = name;
+            this.position = position;
+            this.limit = limit;
+        }
+
+        private Section(int position) {
+            this("section", position, data.length);
+        }
+
+        public int getPosition() {
+            return position;
+        }
+
+        public int readInt() {
+            int result = (data[position] & 0xff)
+                    | (data[position + 1] & 0xff) << 8
+                    | (data[position + 2] & 0xff) << 16
+                    | (data[position + 3] & 0xff) << 24;
+            position += 4;
+            return result;
+        }
+
+        public short readShort() {
+            int result = (data[position] & 0xff)
+                    | (data[position + 1] & 0xff) << 8;
+            position += 2;
+            return (short) result;
+        }
+
+        public int readUnsignedShort() {
+            return readShort() & 0xffff;
+        }
+
+        public byte readByte() {
+            return (byte) (data[position++] & 0xff);
+        }
+
+        public byte[] readByteArray(int length) {
+            byte[] result = Arrays.copyOfRange(data, position, position + length);
+            position += length;
+            return result;
+        }
+
+        public short[] readShortArray(int length) {
+            short[] result = new short[length];
+            for (int i = 0; i < length; i++) {
+                result[i] = readShort();
+            }
+            return result;
+        }
+
+        public int readUleb128() {
+            return Leb128Utils.readUnsignedLeb128(this);
+        }
+
+        public int readSleb128() {
+            return Leb128Utils.readSignedLeb128(this);
+        }
+
+        public TypeList readTypeList() {
+            int size = readInt();
+            short[] types = new short[size];
+            for (int i = 0; i < size; i++) {
+                types[i] = readShort();
+            }
+            alignToFourBytes();
+            return new TypeList(DexBuffer.this, types);
+        }
+
+        public String readString() {
+            int offset = readInt();
+            int savedPosition = position;
+            position = offset;
+            try {
+                int expectedLength = readUleb128();
+                String result = Mutf8.decode(this, new char[expectedLength]);
+                if (result.length() != expectedLength) {
+                    throw new DexException("Declared length " + expectedLength
+                            + " doesn't match decoded length of " + result.length());
+                }
+                return result;
+            } catch (UTFDataFormatException e) {
+                throw new DexException(e);
+            } finally {
+                position = savedPosition;
+            }
+        }
+
+        public FieldId readFieldId() {
+            int declaringClassIndex = readUnsignedShort();
+            int typeIndex = readUnsignedShort();
+            int nameIndex = readInt();
+            return new FieldId(DexBuffer.this, declaringClassIndex, typeIndex, nameIndex);
+        }
+
+        public MethodId readMethodId() {
+            int declaringClassIndex = readUnsignedShort();
+            int protoIndex = readUnsignedShort();
+            int nameIndex = readInt();
+            return new MethodId(DexBuffer.this, declaringClassIndex, protoIndex, nameIndex);
+        }
+
+        public ProtoId readProtoId() {
+            int shortyIndex = readInt();
+            int returnTypeIndex = readInt();
+            int parametersOffset = readInt();
+            return new ProtoId(DexBuffer.this, shortyIndex, returnTypeIndex, parametersOffset);
+        }
+
+        public ClassDef readClassDef() {
+            int offset = getPosition();
+            int type = readInt();
+            int accessFlags = readInt();
+            int supertype = readInt();
+            int interfacesOffset = readInt();
+            int sourceFileIndex = readInt();
+            int annotationsOffset = readInt();
+            int classDataOffset = readInt();
+            int staticValuesOffset = readInt();
+            return new ClassDef(DexBuffer.this, offset, type, accessFlags, supertype,
+                    interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset,
+                    staticValuesOffset);
+        }
+
+        private Code readCode() {
+            int registersSize = readUnsignedShort();
+            int insSize = readUnsignedShort();
+            int outsSize = readUnsignedShort();
+            int triesSize = readUnsignedShort();
+            int debugInfoOffset = readInt();
+            int instructionsSize = readInt();
+            short[] instructions = readShortArray(instructionsSize);
+            Code.Try[] tries = new Code.Try[triesSize];
+            Code.CatchHandler[] catchHandlers = new Code.CatchHandler[0];
+            if (triesSize > 0) {
+                if (instructions.length % 2 == 1) {
+                    readShort(); // padding
+                }
+
+                for (int i = 0; i < triesSize; i++) {
+                    int startAddress = readInt();
+                    int instructionCount = readUnsignedShort();
+                    int handlerOffset = readUnsignedShort();
+                    tries[i] = new Code.Try(startAddress, instructionCount, handlerOffset);
+                }
+
+                int catchHandlersSize = readUleb128();
+                catchHandlers = new Code.CatchHandler[catchHandlersSize];
+                for (int i = 0; i < catchHandlersSize; i++) {
+                    catchHandlers[i] = readCatchHandler();
+                }
+            }
+            return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
+                    tries, catchHandlers);
+        }
+
+        private Code.CatchHandler readCatchHandler() {
+            int size = readSleb128();
+            int handlersCount = Math.abs(size);
+            int[] typeIndexes = new int[handlersCount];
+            int[] addresses = new int[handlersCount];
+            for (int i = 0; i < handlersCount; i++) {
+                typeIndexes[i] = readUleb128();
+                addresses[i] = readUleb128();
+            }
+            int catchAllAddress = size <= 0 ? readUleb128() : -1;
+            return new Code.CatchHandler(typeIndexes, addresses, catchAllAddress);
+        }
+
+        private ClassData readClassData() {
+            int staticFieldsSize = readUleb128();
+            int instanceFieldsSize = readUleb128();
+            int directMethodsSize = readUleb128();
+            int virtualMethodsSize = readUleb128();
+            ClassData.Field[] staticFields = readFields(staticFieldsSize);
+            ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
+            ClassData.Method[] directMethods = readMethods(directMethodsSize);
+            ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
+            return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
+        }
+
+        private ClassData.Field[] readFields(int count) {
+            ClassData.Field[] result = new ClassData.Field[count];
+            int fieldIndex = 0;
+            for (int i = 0; i < count; i++) {
+                fieldIndex += readUleb128(); // field index diff
+                int accessFlags = readUleb128();
+                result[i] = new ClassData.Field(fieldIndex, accessFlags);
+            }
+            return result;
+        }
+
+        private ClassData.Method[] readMethods(int count) {
+            ClassData.Method[] result = new ClassData.Method[count];
+            int methodIndex = 0;
+            for (int i = 0; i < count; i++) {
+                methodIndex += readUleb128(); // method index diff
+                int accessFlags = readUleb128();
+                int codeOff = readUleb128();
+                result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff);
+            }
+            return result;
+        }
+
+        public Annotation readAnnotation() {
+            byte visibility = readByte();
+            int typeIndex = readUleb128();
+            int size = readUleb128();
+            int[] names = new int[size];
+            EncodedValue[] values = new EncodedValue[size];
+            for (int i = 0; i < size; i++) {
+                names[i] = readUleb128();
+                values[i] = readEncodedValue();
+            }
+            return new Annotation(DexBuffer.this, visibility, typeIndex, names, values);
+        }
+
+        public EncodedValue readEncodedValue() {
+            int start = position;
+            new EncodedValueReader(this).readValue();
+            int end = position;
+            return new EncodedValue(Arrays.copyOfRange(data, start, end));
+        }
+
+        public EncodedValue readEncodedArray() {
+            int start = position;
+            new EncodedValueReader(this).readArray();
+            int end = position;
+            return new EncodedValue(Arrays.copyOfRange(data, start, end));
+        }
+
+        private void ensureCapacity(int size) {
+            if (position + size > limit) {
+                throw new DexException("Section limit " + limit + " exceeded by " + name);
+            }
+        }
+
+        /**
+         * Writes 0x00 until the position is aligned to a multiple of 4.
+         */
+        public void alignToFourBytes() {
+            int unalignedCount = position;
+            position = DexBuffer.fourByteAlign(position);
+            for (int i = unalignedCount; i < position; i++) {
+                data[i] = 0;
+            }
+        }
+
+        public void assertFourByteAligned() {
+            if ((position & 3) != 0) {
+                throw new IllegalStateException("Not four byte aligned!");
+            }
+        }
+
+        public void write(byte[] bytes) {
+            ensureCapacity(bytes.length);
+            System.arraycopy(bytes, 0, data, position, bytes.length);
+            position += bytes.length;
+        }
+
+        public void writeByte(int b) {
+            ensureCapacity(1);
+            data[position++] = (byte) b;
+        }
+
+        public void writeShort(short i) {
+            ensureCapacity(2);
+            data[position    ] = (byte) i;
+            data[position + 1] = (byte) (i >>> 8);
+            position += 2;
+        }
+
+        public void writeUnsignedShort(int i) {
+            short s = (short) i;
+            if (i != (s & 0xffff)) {
+                throw new IllegalArgumentException("Expected an unsigned short: " + i);
+            }
+            writeShort(s);
+        }
+
+        public void write(short[] shorts) {
+            for (short s : shorts) {
+                writeShort(s);
+            }
+        }
+
+        public void writeInt(int i) {
+            ensureCapacity(4);
+            data[position    ] = (byte) i;
+            data[position + 1] = (byte) (i >>>  8);
+            data[position + 2] = (byte) (i >>> 16);
+            data[position + 3] = (byte) (i >>> 24);
+            position += 4;
+        }
+
+        public void writeUleb128(int i) {
+            try {
+                Leb128Utils.writeUnsignedLeb128(this, i);
+                ensureCapacity(0);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                throw new DexException("Section limit " + limit + " exceeded by " + name);
+            }
+        }
+
+        public void writeSleb128(int i) {
+            try {
+                Leb128Utils.writeSignedLeb128(this, i);
+                ensureCapacity(0);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                throw new DexException("Section limit " + limit + " exceeded by " + name);
+            }
+        }
+
+        public void writeStringData(String value) {
+            try {
+                int length = value.length();
+                writeUleb128(length);
+                write(Mutf8.encode(value));
+                writeByte(0);
+            } catch (UTFDataFormatException e) {
+                throw new AssertionError();
+            }
+        }
+
+        public void writeTypeList(TypeList typeList) {
+            short[] types = typeList.getTypes();
+            writeInt(types.length);
+            for (short type : types) {
+                writeShort(type);
+            }
+            alignToFourBytes();
+        }
+
+        /**
+         * Returns the number of bytes remaining in this section.
+         */
+        public int remaining() {
+            return limit - position;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/io/DexHasher.java b/dx/src/com/android/dx/io/DexHasher.java
new file mode 100644
index 0000000..416b3e2
--- /dev/null
+++ b/dx/src/com/android/dx/io/DexHasher.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.zip.Adler32;
+
+/**
+ * Generates and stores the checksum and signature of a dex file.
+ */
+public final class DexHasher {
+    private static final int CHECKSUM_OFFSET = 8;
+    private static final int CHECKSUM_SIZE = 4;
+    private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;
+    private static final int SIGNATURE_SIZE = 20;
+
+    /**
+     * Returns the signature of all but the first 32 bytes of {@code dex}. The
+     * first 32 bytes of dex files are not specified to be included in the
+     * signature.
+     */
+    public byte[] computeSignature(DexBuffer dex) throws IOException {
+        MessageDigest digest;
+        try {
+            digest = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError();
+        }
+        int offset = SIGNATURE_OFFSET + SIGNATURE_SIZE;
+
+        byte[] bytes = dex.getBytes();
+        digest.update(bytes, offset, bytes.length - offset);
+        return digest.digest();
+    }
+
+    /**
+     * Returns the checksum of all but the first 12 bytes of {@code dex}.
+     */
+    public int computeChecksum(DexBuffer dex) throws IOException {
+        Adler32 adler32 = new Adler32();
+        int offset = CHECKSUM_OFFSET + CHECKSUM_SIZE;
+
+        byte[] bytes = dex.getBytes();
+        adler32.update(bytes, offset, bytes.length - offset);
+        return (int) adler32.getValue();
+    }
+
+    /**
+     * Generates the signature and checksum of the dex file {@code out} and
+     * writes them to the file.
+     */
+    public void writeHashes(DexBuffer dex) throws IOException {
+        byte[] signature = computeSignature(dex);
+        dex.open(SIGNATURE_OFFSET).write(signature);
+
+        int checksum = computeChecksum(dex);
+        dex.open(CHECKSUM_OFFSET).writeInt(checksum);
+    }
+}
diff --git a/dx/src/com/android/dx/io/DexIndexPrinter.java b/dx/src/com/android/dx/io/DexIndexPrinter.java
new file mode 100644
index 0000000..85c2015
--- /dev/null
+++ b/dx/src/com/android/dx/io/DexIndexPrinter.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.dex.TableOfContents;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Executable that prints all indices of a dex file.
+ */
+public final class DexIndexPrinter {
+    private final DexBuffer dexBuffer;
+    private final TableOfContents tableOfContents;
+
+    public DexIndexPrinter(File file) throws IOException {
+        this.dexBuffer = new DexBuffer(file);
+        this.tableOfContents = dexBuffer.getTableOfContents();
+    }
+
+    private void printMap() {
+        for (TableOfContents.Section section : tableOfContents.sections) {
+            if (section.off != -1) {
+                System.out.println("section " + Integer.toHexString(section.type)
+                        + " off=" + Integer.toHexString(section.off)
+                        + " size=" + Integer.toHexString(section.size)
+                        + " byteCount=" + Integer.toHexString(section.byteCount));
+            }
+        }
+    }
+
+    private void printStrings() throws IOException {
+        int index = 0;
+        for (String string : dexBuffer.strings()) {
+            System.out.println("string " + index + ": " + string);
+            index++;
+        }
+    }
+
+    private void printTypeIds() throws IOException {
+        int index = 0;
+        for (Integer type : dexBuffer.typeIds()) {
+            System.out.println("type " + index + ": " + dexBuffer.strings().get(type));
+            index++;
+        }
+    }
+
+    private void printProtoIds() throws IOException {
+        int index = 0;
+        for (ProtoId protoId : dexBuffer.protoIds()) {
+            System.out.println("proto " + index + ": " + protoId);
+            index++;
+        }
+    }
+
+    private void printFieldIds() throws IOException {
+        int index = 0;
+        for (FieldId fieldId : dexBuffer.fieldIds()) {
+            System.out.println("field " + index + ": " + fieldId);
+            index++;
+        }
+    }
+
+    private void printMethodIds() throws IOException {
+        int index = 0;
+        for (MethodId methodId : dexBuffer.methodIds()) {
+            System.out.println("methodId " + index + ": " + methodId);
+            index++;
+        }
+    }
+
+    private void printTypeLists() throws IOException {
+        if (tableOfContents.typeLists.off == -1) {
+            System.out.println("No type lists");
+            return;
+        }
+        DexBuffer.Section in = dexBuffer.open(tableOfContents.typeLists.off);
+        for (int i = 0; i < tableOfContents.typeLists.size; i++) {
+            int size = in.readInt();
+            System.out.print("Type list i=" + i + ", size=" + size + ", elements=");
+            for (int t = 0; t < size; t++) {
+                System.out.print(" " + dexBuffer.typeNames().get((int) in.readShort()));
+            }
+            if (size % 2 == 1) {
+                in.readShort(); // retain alignment
+            }
+            System.out.println();
+        }
+    }
+
+    private void printClassDefs() {
+        int index = 0;
+        for (ClassDef classDef : dexBuffer.classDefs()) {
+            System.out.println("class def " + index + ": " + classDef);
+            index++;
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        DexIndexPrinter indexPrinter = new DexIndexPrinter(new File(args[0]));
+        indexPrinter.printMap();
+        indexPrinter.printStrings();
+        indexPrinter.printTypeIds();
+        indexPrinter.printProtoIds();
+        indexPrinter.printFieldIds();
+        indexPrinter.printMethodIds();
+        indexPrinter.printTypeLists();
+        indexPrinter.printClassDefs();
+    }
+}
diff --git a/dx/src/com/android/dx/io/EncodedValue.java b/dx/src/com/android/dx/io/EncodedValue.java
new file mode 100644
index 0000000..c83c364
--- /dev/null
+++ b/dx/src/com/android/dx/io/EncodedValue.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.ByteArrayByteInput;
+import com.android.dx.util.ByteInput;
+
+/**
+ * An encoded value or array.
+ */
+public final class EncodedValue implements Comparable<EncodedValue> {
+    private final byte[] data;
+
+    public EncodedValue(byte[] data) {
+        this.data = data;
+    }
+
+    public ByteInput asByteInput() {
+        return new ByteArrayByteInput(data);
+    }
+
+    public byte[] getBytes() {
+        return data;
+    }
+
+    public void writeTo(DexBuffer.Section out) {
+        out.write(data);
+    }
+
+    @Override public int compareTo(EncodedValue other) {
+        int size = Math.min(data.length, other.data.length);
+        for (int i = 0; i < size; i++) {
+            if (data[i] != other.data[i]) {
+                return (data[i] & 0xff) - (other.data[i] & 0xff);
+            }
+        }
+        return data.length - other.data.length;
+    }
+
+    @Override public String toString() {
+        return Integer.toHexString(data[0] & 0xff) + "...(" + data.length + ")";
+    }
+}
diff --git a/dx/src/com/android/dx/io/EncodedValueReader.java b/dx/src/com/android/dx/io/EncodedValueReader.java
new file mode 100644
index 0000000..ec84898
--- /dev/null
+++ b/dx/src/com/android/dx/io/EncodedValueReader.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.ByteInput;
+import com.android.dx.util.Leb128Utils;
+
+/**
+ * SAX-style reader for encoded values.
+ * TODO: convert this to a pull-style reader
+ */
+public class EncodedValueReader {
+    public static final int ENCODED_BYTE = 0x00;
+    public static final int ENCODED_SHORT = 0x02;
+    public static final int ENCODED_CHAR = 0x03;
+    public static final int ENCODED_INT = 0x04;
+    public static final int ENCODED_LONG = 0x06;
+    public static final int ENCODED_FLOAT = 0x10;
+    public static final int ENCODED_DOUBLE = 0x11;
+    public static final int ENCODED_STRING = 0x17;
+    public static final int ENCODED_TYPE = 0x18;
+    public static final int ENCODED_FIELD = 0x19;
+    public static final int ENCODED_ENUM = 0x1b;
+    public static final int ENCODED_METHOD = 0x1a;
+    public static final int ENCODED_ARRAY = 0x1c;
+    public static final int ENCODED_ANNOTATION = 0x1d;
+    public static final int ENCODED_NULL = 0x1e;
+    public static final int ENCODED_BOOLEAN = 0x1f;
+
+    protected final ByteInput in;
+
+    public EncodedValueReader(ByteInput in) {
+        this.in = in;
+    }
+
+    public EncodedValueReader(EncodedValue in) {
+        this(in.asByteInput());
+    }
+
+    public final void readArray() {
+        int size = Leb128Utils.readUnsignedLeb128(in);
+        visitArray(size);
+
+        for (int i = 0; i < size; i++) {
+            readValue();
+        }
+    }
+
+    public final void readAnnotation() {
+        int typeIndex = Leb128Utils.readUnsignedLeb128(in);
+        int size = Leb128Utils.readUnsignedLeb128(in);
+        visitAnnotation(typeIndex, size);
+
+        for (int i = 0; i < size; i++) {
+            visitAnnotationName(Leb128Utils.readUnsignedLeb128(in));
+            readValue();
+        }
+    }
+
+    public final void readValue() {
+        int argAndType = in.readByte() & 0xff;
+        int type = argAndType & 0x1f;
+        int arg = (argAndType & 0xe0) >> 5;
+        int size = arg + 1;
+
+        switch (type) {
+        case ENCODED_BYTE:
+        case ENCODED_SHORT:
+        case ENCODED_CHAR:
+        case ENCODED_INT:
+        case ENCODED_LONG:
+        case ENCODED_FLOAT:
+        case ENCODED_DOUBLE:
+            visitPrimitive(argAndType, type, arg, size);
+            break;
+        case ENCODED_STRING:
+            visitString(type, readIndex(in, size));
+            break;
+        case ENCODED_TYPE:
+            visitType(type, readIndex(in, size));
+            break;
+        case ENCODED_FIELD:
+        case ENCODED_ENUM:
+            visitField(type, readIndex(in, size));
+            break;
+        case ENCODED_METHOD:
+            visitMethod(type, readIndex(in, size));
+            break;
+        case ENCODED_ARRAY:
+            visitArrayValue(argAndType);
+            readArray();
+            break;
+        case ENCODED_ANNOTATION:
+            visitAnnotationValue(argAndType);
+            readAnnotation();
+            break;
+        case ENCODED_NULL:
+            visitEncodedNull(argAndType);
+            break;
+        case ENCODED_BOOLEAN:
+            visitEncodedBoolean(argAndType);
+            break;
+        }
+    }
+
+    protected void visitArray(int size) {}
+    protected void visitAnnotation(int typeIndex, int size) {}
+    protected void visitAnnotationName(int nameIndex) {}
+    protected void visitPrimitive(int argAndType, int type, int arg, int size) {
+        for (int i = 0; i < size; i++) {
+            in.readByte();
+        }
+    }
+    protected void visitString(int type, int index) {}
+    protected void visitType(int type, int index) {}
+    protected void visitField(int type, int index) {}
+    protected void visitMethod(int type, int index) {}
+    protected void visitArrayValue(int argAndType) {}
+    protected void visitAnnotationValue(int argAndType) {}
+    protected void visitEncodedBoolean(int argAndType) {}
+    protected void visitEncodedNull(int argAndType) {}
+
+    private int readIndex(ByteInput in, int byteCount) {
+        int result = 0;
+        int shift = 0;
+        for (int i = 0; i < byteCount; i++) {
+            result += (in.readByte() & 0xff) << shift;
+            shift += 8;
+        }
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/io/FieldId.java b/dx/src/com/android/dx/io/FieldId.java
new file mode 100644
index 0000000..da409fa
--- /dev/null
+++ b/dx/src/com/android/dx/io/FieldId.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+
+public final class FieldId implements Comparable<FieldId> {
+    private final DexBuffer buffer;
+    private final int declaringClassIndex;
+    private final int typeIndex;
+    private final int nameIndex;
+
+    public FieldId(DexBuffer buffer, int declaringClassIndex, int typeIndex, int nameIndex) {
+        this.buffer = buffer;
+        this.declaringClassIndex = declaringClassIndex;
+        this.typeIndex = typeIndex;
+        this.nameIndex = nameIndex;
+    }
+
+    public int getDeclaringClassIndex() {
+        return declaringClassIndex;
+    }
+
+    public int getTypeIndex() {
+        return typeIndex;
+    }
+
+    public int getNameIndex() {
+        return nameIndex;
+    }
+
+    public int compareTo(FieldId other) {
+        if (declaringClassIndex != other.declaringClassIndex) {
+            return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
+        }
+        if (nameIndex != other.nameIndex) {
+            return Unsigned.compare(nameIndex, other.nameIndex);
+        }
+        return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0
+    }
+
+    public void writeTo(DexBuffer.Section out) {
+        out.writeUnsignedShort(declaringClassIndex);
+        out.writeUnsignedShort(typeIndex);
+        out.writeInt(nameIndex);
+    }
+
+    @Override public String toString() {
+        if (buffer == null) {
+            return declaringClassIndex + " " + typeIndex + " " + nameIndex;
+        }
+        return buffer.typeNames().get(typeIndex) + "." + buffer.strings().get(nameIndex);
+    }
+}
diff --git a/dx/src/com/android/dx/io/IndexType.java b/dx/src/com/android/dx/io/IndexType.java
new file mode 100644
index 0000000..bbddfa8
--- /dev/null
+++ b/dx/src/com/android/dx/io/IndexType.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+/**
+ * The various types that an index in a Dalvik instruction might refer to.
+ */
+public enum IndexType {
+    /** "Unknown." Used for undefined opcodes. */
+    UNKNOWN,
+
+    /** no index used */
+    NONE,
+
+    /** "It depends." Used for {@code throw-verification-error}. */
+    VARIES,
+
+    /** type reference index */
+    TYPE_REF,
+
+    /** string reference index */
+    STRING_REF,
+
+    /** method reference index */
+    METHOD_REF,
+
+    /** field reference index */
+    FIELD_REF,
+
+    /** inline method index (for inline linked method invocations) */
+    INLINE_METHOD,
+
+    /** direct vtable offset (for static linked method invocations) */
+    VTABLE_OFFSET,
+
+    /** direct field offset (for static linked field accesses) */
+    FIELD_OFFSET;
+}
diff --git a/dx/src/com/android/dx/io/MethodId.java b/dx/src/com/android/dx/io/MethodId.java
new file mode 100644
index 0000000..e653661
--- /dev/null
+++ b/dx/src/com/android/dx/io/MethodId.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+
+public final class MethodId implements Comparable<MethodId> {
+    private final DexBuffer buffer;
+    private final int declaringClassIndex;
+    private final int protoIndex;
+    private final int nameIndex;
+
+    public MethodId(DexBuffer buffer, int declaringClassIndex, int protoIndex, int nameIndex) {
+        this.buffer = buffer;
+        this.declaringClassIndex = declaringClassIndex;
+        this.protoIndex = protoIndex;
+        this.nameIndex = nameIndex;
+    }
+
+    public int getDeclaringClassIndex() {
+        return declaringClassIndex;
+    }
+
+    public int getProtoIndex() {
+        return protoIndex;
+    }
+
+    public int getNameIndex() {
+        return nameIndex;
+    }
+
+    public int compareTo(MethodId other) {
+        if (declaringClassIndex != other.declaringClassIndex) {
+            return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
+        }
+        if (nameIndex != other.nameIndex) {
+            return Unsigned.compare(nameIndex, other.nameIndex);
+        }
+        return Unsigned.compare(protoIndex, other.protoIndex);
+    }
+
+    public void writeTo(DexBuffer.Section out) {
+        out.writeUnsignedShort(declaringClassIndex);
+        out.writeUnsignedShort(protoIndex);
+        out.writeInt(nameIndex);
+    }
+
+    @Override public String toString() {
+        if (buffer == null) {
+            return declaringClassIndex + " " + protoIndex + " " + nameIndex;
+        }
+        return buffer.typeNames().get(declaringClassIndex)
+                + "." + buffer.strings().get(nameIndex)
+                + buffer.readTypeList(buffer.protoIds().get(protoIndex).getParametersOffset());
+    }
+}
diff --git a/dx/src/com/android/dx/io/OpcodeInfo.java b/dx/src/com/android/dx/io/OpcodeInfo.java
new file mode 100644
index 0000000..c8fcf25
--- /dev/null
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -0,0 +1,1460 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.io.instructions.InstructionCodec;
+import com.android.dx.util.Hex;
+
+/**
+ * Information about each Dalvik opcode.
+ */
+public final class OpcodeInfo {
+    /*
+     * TODO: Merge at least most of the info from the Dops class into
+     * this one.
+     */
+
+    /** non-null; array containing all the information */
+    private static final Info[] INFO;
+
+    /**
+     * pseudo-opcode used for nonstandard formatted "instructions"
+     * (which are mostly not actually instructions, though they do
+     * appear in instruction lists). TODO: Retire the usage of this
+     * constant.
+     */
+    public static final Info SPECIAL_FORMAT =
+        new Info(Opcodes.SPECIAL_FORMAT, "<special>",
+                InstructionCodec.FORMAT_00X, IndexType.NONE);
+
+    // TODO: These payload opcodes should be generated by opcode-gen.
+
+    public static final Info PACKED_SWITCH_PAYLOAD =
+        new Info(Opcodes.PACKED_SWITCH_PAYLOAD, "packed-switch-payload",
+                InstructionCodec.FORMAT_PACKED_SWITCH_PAYLOAD,
+                IndexType.NONE);
+
+    public static final Info SPARSE_SWITCH_PAYLOAD =
+        new Info(Opcodes.SPARSE_SWITCH_PAYLOAD, "sparse-switch-payload",
+                InstructionCodec.FORMAT_SPARSE_SWITCH_PAYLOAD,
+                IndexType.NONE);
+
+    public static final Info FILL_ARRAY_DATA_PAYLOAD =
+        new Info(Opcodes.FILL_ARRAY_DATA_PAYLOAD, "fill-array-data-payload",
+                InstructionCodec.FORMAT_FILL_ARRAY_DATA_PAYLOAD,
+                IndexType.NONE);
+
+    // BEGIN(opcode-info-defs); GENERATED AUTOMATICALLY BY opcode-gen
+    public static final Info NOP =
+        new Info(Opcodes.NOP, "nop",
+            InstructionCodec.FORMAT_10X, IndexType.NONE);
+
+    public static final Info MOVE =
+        new Info(Opcodes.MOVE, "move",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MOVE_FROM16 =
+        new Info(Opcodes.MOVE_FROM16, "move/from16",
+            InstructionCodec.FORMAT_22X, IndexType.NONE);
+
+    public static final Info MOVE_16 =
+        new Info(Opcodes.MOVE_16, "move/16",
+            InstructionCodec.FORMAT_32X, IndexType.NONE);
+
+    public static final Info MOVE_WIDE =
+        new Info(Opcodes.MOVE_WIDE, "move-wide",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MOVE_WIDE_FROM16 =
+        new Info(Opcodes.MOVE_WIDE_FROM16, "move-wide/from16",
+            InstructionCodec.FORMAT_22X, IndexType.NONE);
+
+    public static final Info MOVE_WIDE_16 =
+        new Info(Opcodes.MOVE_WIDE_16, "move-wide/16",
+            InstructionCodec.FORMAT_32X, IndexType.NONE);
+
+    public static final Info MOVE_OBJECT =
+        new Info(Opcodes.MOVE_OBJECT, "move-object",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MOVE_OBJECT_FROM16 =
+        new Info(Opcodes.MOVE_OBJECT_FROM16, "move-object/from16",
+            InstructionCodec.FORMAT_22X, IndexType.NONE);
+
+    public static final Info MOVE_OBJECT_16 =
+        new Info(Opcodes.MOVE_OBJECT_16, "move-object/16",
+            InstructionCodec.FORMAT_32X, IndexType.NONE);
+
+    public static final Info MOVE_RESULT =
+        new Info(Opcodes.MOVE_RESULT, "move-result",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info MOVE_RESULT_WIDE =
+        new Info(Opcodes.MOVE_RESULT_WIDE, "move-result-wide",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info MOVE_RESULT_OBJECT =
+        new Info(Opcodes.MOVE_RESULT_OBJECT, "move-result-object",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info MOVE_EXCEPTION =
+        new Info(Opcodes.MOVE_EXCEPTION, "move-exception",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info RETURN_VOID =
+        new Info(Opcodes.RETURN_VOID, "return-void",
+            InstructionCodec.FORMAT_10X, IndexType.NONE);
+
+    public static final Info RETURN =
+        new Info(Opcodes.RETURN, "return",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info RETURN_WIDE =
+        new Info(Opcodes.RETURN_WIDE, "return-wide",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info RETURN_OBJECT =
+        new Info(Opcodes.RETURN_OBJECT, "return-object",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info CONST_4 =
+        new Info(Opcodes.CONST_4, "const/4",
+            InstructionCodec.FORMAT_11N, IndexType.NONE);
+
+    public static final Info CONST_16 =
+        new Info(Opcodes.CONST_16, "const/16",
+            InstructionCodec.FORMAT_21S, IndexType.NONE);
+
+    public static final Info CONST =
+        new Info(Opcodes.CONST, "const",
+            InstructionCodec.FORMAT_31I, IndexType.NONE);
+
+    public static final Info CONST_HIGH16 =
+        new Info(Opcodes.CONST_HIGH16, "const/high16",
+            InstructionCodec.FORMAT_21H, IndexType.NONE);
+
+    public static final Info CONST_WIDE_16 =
+        new Info(Opcodes.CONST_WIDE_16, "const-wide/16",
+            InstructionCodec.FORMAT_21S, IndexType.NONE);
+
+    public static final Info CONST_WIDE_32 =
+        new Info(Opcodes.CONST_WIDE_32, "const-wide/32",
+            InstructionCodec.FORMAT_31I, IndexType.NONE);
+
+    public static final Info CONST_WIDE =
+        new Info(Opcodes.CONST_WIDE, "const-wide",
+            InstructionCodec.FORMAT_51L, IndexType.NONE);
+
+    public static final Info CONST_WIDE_HIGH16 =
+        new Info(Opcodes.CONST_WIDE_HIGH16, "const-wide/high16",
+            InstructionCodec.FORMAT_21H, IndexType.NONE);
+
+    public static final Info CONST_STRING =
+        new Info(Opcodes.CONST_STRING, "const-string",
+            InstructionCodec.FORMAT_21C, IndexType.STRING_REF);
+
+    public static final Info CONST_STRING_JUMBO =
+        new Info(Opcodes.CONST_STRING_JUMBO, "const-string/jumbo",
+            InstructionCodec.FORMAT_31C, IndexType.STRING_REF);
+
+    public static final Info CONST_CLASS =
+        new Info(Opcodes.CONST_CLASS, "const-class",
+            InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
+
+    public static final Info MONITOR_ENTER =
+        new Info(Opcodes.MONITOR_ENTER, "monitor-enter",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info MONITOR_EXIT =
+        new Info(Opcodes.MONITOR_EXIT, "monitor-exit",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info CHECK_CAST =
+        new Info(Opcodes.CHECK_CAST, "check-cast",
+            InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
+
+    public static final Info INSTANCE_OF =
+        new Info(Opcodes.INSTANCE_OF, "instance-of",
+            InstructionCodec.FORMAT_22C, IndexType.TYPE_REF);
+
+    public static final Info ARRAY_LENGTH =
+        new Info(Opcodes.ARRAY_LENGTH, "array-length",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info NEW_INSTANCE =
+        new Info(Opcodes.NEW_INSTANCE, "new-instance",
+            InstructionCodec.FORMAT_21C, IndexType.TYPE_REF);
+
+    public static final Info NEW_ARRAY =
+        new Info(Opcodes.NEW_ARRAY, "new-array",
+            InstructionCodec.FORMAT_22C, IndexType.TYPE_REF);
+
+    public static final Info FILLED_NEW_ARRAY =
+        new Info(Opcodes.FILLED_NEW_ARRAY, "filled-new-array",
+            InstructionCodec.FORMAT_35C, IndexType.TYPE_REF);
+
+    public static final Info FILLED_NEW_ARRAY_RANGE =
+        new Info(Opcodes.FILLED_NEW_ARRAY_RANGE, "filled-new-array/range",
+            InstructionCodec.FORMAT_3RC, IndexType.TYPE_REF);
+
+    public static final Info FILL_ARRAY_DATA =
+        new Info(Opcodes.FILL_ARRAY_DATA, "fill-array-data",
+            InstructionCodec.FORMAT_31T, IndexType.NONE);
+
+    public static final Info THROW =
+        new Info(Opcodes.THROW, "throw",
+            InstructionCodec.FORMAT_11X, IndexType.NONE);
+
+    public static final Info GOTO =
+        new Info(Opcodes.GOTO, "goto",
+            InstructionCodec.FORMAT_10T, IndexType.NONE);
+
+    public static final Info GOTO_16 =
+        new Info(Opcodes.GOTO_16, "goto/16",
+            InstructionCodec.FORMAT_20T, IndexType.NONE);
+
+    public static final Info GOTO_32 =
+        new Info(Opcodes.GOTO_32, "goto/32",
+            InstructionCodec.FORMAT_30T, IndexType.NONE);
+
+    public static final Info PACKED_SWITCH =
+        new Info(Opcodes.PACKED_SWITCH, "packed-switch",
+            InstructionCodec.FORMAT_31T, IndexType.NONE);
+
+    public static final Info SPARSE_SWITCH =
+        new Info(Opcodes.SPARSE_SWITCH, "sparse-switch",
+            InstructionCodec.FORMAT_31T, IndexType.NONE);
+
+    public static final Info CMPL_FLOAT =
+        new Info(Opcodes.CMPL_FLOAT, "cmpl-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info CMPG_FLOAT =
+        new Info(Opcodes.CMPG_FLOAT, "cmpg-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info CMPL_DOUBLE =
+        new Info(Opcodes.CMPL_DOUBLE, "cmpl-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info CMPG_DOUBLE =
+        new Info(Opcodes.CMPG_DOUBLE, "cmpg-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info CMP_LONG =
+        new Info(Opcodes.CMP_LONG, "cmp-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info IF_EQ =
+        new Info(Opcodes.IF_EQ, "if-eq",
+            InstructionCodec.FORMAT_22T, IndexType.NONE);
+
+    public static final Info IF_NE =
+        new Info(Opcodes.IF_NE, "if-ne",
+            InstructionCodec.FORMAT_22T, IndexType.NONE);
+
+    public static final Info IF_LT =
+        new Info(Opcodes.IF_LT, "if-lt",
+            InstructionCodec.FORMAT_22T, IndexType.NONE);
+
+    public static final Info IF_GE =
+        new Info(Opcodes.IF_GE, "if-ge",
+            InstructionCodec.FORMAT_22T, IndexType.NONE);
+
+    public static final Info IF_GT =
+        new Info(Opcodes.IF_GT, "if-gt",
+            InstructionCodec.FORMAT_22T, IndexType.NONE);
+
+    public static final Info IF_LE =
+        new Info(Opcodes.IF_LE, "if-le",
+            InstructionCodec.FORMAT_22T, IndexType.NONE);
+
+    public static final Info IF_EQZ =
+        new Info(Opcodes.IF_EQZ, "if-eqz",
+            InstructionCodec.FORMAT_21T, IndexType.NONE);
+
+    public static final Info IF_NEZ =
+        new Info(Opcodes.IF_NEZ, "if-nez",
+            InstructionCodec.FORMAT_21T, IndexType.NONE);
+
+    public static final Info IF_LTZ =
+        new Info(Opcodes.IF_LTZ, "if-ltz",
+            InstructionCodec.FORMAT_21T, IndexType.NONE);
+
+    public static final Info IF_GEZ =
+        new Info(Opcodes.IF_GEZ, "if-gez",
+            InstructionCodec.FORMAT_21T, IndexType.NONE);
+
+    public static final Info IF_GTZ =
+        new Info(Opcodes.IF_GTZ, "if-gtz",
+            InstructionCodec.FORMAT_21T, IndexType.NONE);
+
+    public static final Info IF_LEZ =
+        new Info(Opcodes.IF_LEZ, "if-lez",
+            InstructionCodec.FORMAT_21T, IndexType.NONE);
+
+    public static final Info AGET =
+        new Info(Opcodes.AGET, "aget",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AGET_WIDE =
+        new Info(Opcodes.AGET_WIDE, "aget-wide",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AGET_OBJECT =
+        new Info(Opcodes.AGET_OBJECT, "aget-object",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AGET_BOOLEAN =
+        new Info(Opcodes.AGET_BOOLEAN, "aget-boolean",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AGET_BYTE =
+        new Info(Opcodes.AGET_BYTE, "aget-byte",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AGET_CHAR =
+        new Info(Opcodes.AGET_CHAR, "aget-char",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AGET_SHORT =
+        new Info(Opcodes.AGET_SHORT, "aget-short",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT =
+        new Info(Opcodes.APUT, "aput",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT_WIDE =
+        new Info(Opcodes.APUT_WIDE, "aput-wide",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT_OBJECT =
+        new Info(Opcodes.APUT_OBJECT, "aput-object",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT_BOOLEAN =
+        new Info(Opcodes.APUT_BOOLEAN, "aput-boolean",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT_BYTE =
+        new Info(Opcodes.APUT_BYTE, "aput-byte",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT_CHAR =
+        new Info(Opcodes.APUT_CHAR, "aput-char",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info APUT_SHORT =
+        new Info(Opcodes.APUT_SHORT, "aput-short",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info IGET =
+        new Info(Opcodes.IGET, "iget",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IGET_WIDE =
+        new Info(Opcodes.IGET_WIDE, "iget-wide",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IGET_OBJECT =
+        new Info(Opcodes.IGET_OBJECT, "iget-object",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IGET_BOOLEAN =
+        new Info(Opcodes.IGET_BOOLEAN, "iget-boolean",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IGET_BYTE =
+        new Info(Opcodes.IGET_BYTE, "iget-byte",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IGET_CHAR =
+        new Info(Opcodes.IGET_CHAR, "iget-char",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IGET_SHORT =
+        new Info(Opcodes.IGET_SHORT, "iget-short",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT =
+        new Info(Opcodes.IPUT, "iput",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_WIDE =
+        new Info(Opcodes.IPUT_WIDE, "iput-wide",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_OBJECT =
+        new Info(Opcodes.IPUT_OBJECT, "iput-object",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_BOOLEAN =
+        new Info(Opcodes.IPUT_BOOLEAN, "iput-boolean",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_BYTE =
+        new Info(Opcodes.IPUT_BYTE, "iput-byte",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_CHAR =
+        new Info(Opcodes.IPUT_CHAR, "iput-char",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_SHORT =
+        new Info(Opcodes.IPUT_SHORT, "iput-short",
+            InstructionCodec.FORMAT_22C, IndexType.FIELD_REF);
+
+    public static final Info SGET =
+        new Info(Opcodes.SGET, "sget",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SGET_WIDE =
+        new Info(Opcodes.SGET_WIDE, "sget-wide",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SGET_OBJECT =
+        new Info(Opcodes.SGET_OBJECT, "sget-object",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SGET_BOOLEAN =
+        new Info(Opcodes.SGET_BOOLEAN, "sget-boolean",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SGET_BYTE =
+        new Info(Opcodes.SGET_BYTE, "sget-byte",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SGET_CHAR =
+        new Info(Opcodes.SGET_CHAR, "sget-char",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SGET_SHORT =
+        new Info(Opcodes.SGET_SHORT, "sget-short",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT =
+        new Info(Opcodes.SPUT, "sput",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_WIDE =
+        new Info(Opcodes.SPUT_WIDE, "sput-wide",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_OBJECT =
+        new Info(Opcodes.SPUT_OBJECT, "sput-object",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_BOOLEAN =
+        new Info(Opcodes.SPUT_BOOLEAN, "sput-boolean",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_BYTE =
+        new Info(Opcodes.SPUT_BYTE, "sput-byte",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_CHAR =
+        new Info(Opcodes.SPUT_CHAR, "sput-char",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_SHORT =
+        new Info(Opcodes.SPUT_SHORT, "sput-short",
+            InstructionCodec.FORMAT_21C, IndexType.FIELD_REF);
+
+    public static final Info INVOKE_VIRTUAL =
+        new Info(Opcodes.INVOKE_VIRTUAL, "invoke-virtual",
+            InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_SUPER =
+        new Info(Opcodes.INVOKE_SUPER, "invoke-super",
+            InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_DIRECT =
+        new Info(Opcodes.INVOKE_DIRECT, "invoke-direct",
+            InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_STATIC =
+        new Info(Opcodes.INVOKE_STATIC, "invoke-static",
+            InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_INTERFACE =
+        new Info(Opcodes.INVOKE_INTERFACE, "invoke-interface",
+            InstructionCodec.FORMAT_35C, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_VIRTUAL_RANGE =
+        new Info(Opcodes.INVOKE_VIRTUAL_RANGE, "invoke-virtual/range",
+            InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_SUPER_RANGE =
+        new Info(Opcodes.INVOKE_SUPER_RANGE, "invoke-super/range",
+            InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_DIRECT_RANGE =
+        new Info(Opcodes.INVOKE_DIRECT_RANGE, "invoke-direct/range",
+            InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_STATIC_RANGE =
+        new Info(Opcodes.INVOKE_STATIC_RANGE, "invoke-static/range",
+            InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_INTERFACE_RANGE =
+        new Info(Opcodes.INVOKE_INTERFACE_RANGE, "invoke-interface/range",
+            InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF);
+
+    public static final Info NEG_INT =
+        new Info(Opcodes.NEG_INT, "neg-int",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info NOT_INT =
+        new Info(Opcodes.NOT_INT, "not-int",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info NEG_LONG =
+        new Info(Opcodes.NEG_LONG, "neg-long",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info NOT_LONG =
+        new Info(Opcodes.NOT_LONG, "not-long",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info NEG_FLOAT =
+        new Info(Opcodes.NEG_FLOAT, "neg-float",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info NEG_DOUBLE =
+        new Info(Opcodes.NEG_DOUBLE, "neg-double",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info INT_TO_LONG =
+        new Info(Opcodes.INT_TO_LONG, "int-to-long",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info INT_TO_FLOAT =
+        new Info(Opcodes.INT_TO_FLOAT, "int-to-float",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info INT_TO_DOUBLE =
+        new Info(Opcodes.INT_TO_DOUBLE, "int-to-double",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info LONG_TO_INT =
+        new Info(Opcodes.LONG_TO_INT, "long-to-int",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info LONG_TO_FLOAT =
+        new Info(Opcodes.LONG_TO_FLOAT, "long-to-float",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info LONG_TO_DOUBLE =
+        new Info(Opcodes.LONG_TO_DOUBLE, "long-to-double",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info FLOAT_TO_INT =
+        new Info(Opcodes.FLOAT_TO_INT, "float-to-int",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info FLOAT_TO_LONG =
+        new Info(Opcodes.FLOAT_TO_LONG, "float-to-long",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info FLOAT_TO_DOUBLE =
+        new Info(Opcodes.FLOAT_TO_DOUBLE, "float-to-double",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DOUBLE_TO_INT =
+        new Info(Opcodes.DOUBLE_TO_INT, "double-to-int",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DOUBLE_TO_LONG =
+        new Info(Opcodes.DOUBLE_TO_LONG, "double-to-long",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DOUBLE_TO_FLOAT =
+        new Info(Opcodes.DOUBLE_TO_FLOAT, "double-to-float",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info INT_TO_BYTE =
+        new Info(Opcodes.INT_TO_BYTE, "int-to-byte",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info INT_TO_CHAR =
+        new Info(Opcodes.INT_TO_CHAR, "int-to-char",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info INT_TO_SHORT =
+        new Info(Opcodes.INT_TO_SHORT, "int-to-short",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info ADD_INT =
+        new Info(Opcodes.ADD_INT, "add-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SUB_INT =
+        new Info(Opcodes.SUB_INT, "sub-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info MUL_INT =
+        new Info(Opcodes.MUL_INT, "mul-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info DIV_INT =
+        new Info(Opcodes.DIV_INT, "div-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info REM_INT =
+        new Info(Opcodes.REM_INT, "rem-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AND_INT =
+        new Info(Opcodes.AND_INT, "and-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info OR_INT =
+        new Info(Opcodes.OR_INT, "or-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info XOR_INT =
+        new Info(Opcodes.XOR_INT, "xor-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SHL_INT =
+        new Info(Opcodes.SHL_INT, "shl-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SHR_INT =
+        new Info(Opcodes.SHR_INT, "shr-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info USHR_INT =
+        new Info(Opcodes.USHR_INT, "ushr-int",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info ADD_LONG =
+        new Info(Opcodes.ADD_LONG, "add-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SUB_LONG =
+        new Info(Opcodes.SUB_LONG, "sub-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info MUL_LONG =
+        new Info(Opcodes.MUL_LONG, "mul-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info DIV_LONG =
+        new Info(Opcodes.DIV_LONG, "div-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info REM_LONG =
+        new Info(Opcodes.REM_LONG, "rem-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info AND_LONG =
+        new Info(Opcodes.AND_LONG, "and-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info OR_LONG =
+        new Info(Opcodes.OR_LONG, "or-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info XOR_LONG =
+        new Info(Opcodes.XOR_LONG, "xor-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SHL_LONG =
+        new Info(Opcodes.SHL_LONG, "shl-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SHR_LONG =
+        new Info(Opcodes.SHR_LONG, "shr-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info USHR_LONG =
+        new Info(Opcodes.USHR_LONG, "ushr-long",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info ADD_FLOAT =
+        new Info(Opcodes.ADD_FLOAT, "add-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SUB_FLOAT =
+        new Info(Opcodes.SUB_FLOAT, "sub-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info MUL_FLOAT =
+        new Info(Opcodes.MUL_FLOAT, "mul-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info DIV_FLOAT =
+        new Info(Opcodes.DIV_FLOAT, "div-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info REM_FLOAT =
+        new Info(Opcodes.REM_FLOAT, "rem-float",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info ADD_DOUBLE =
+        new Info(Opcodes.ADD_DOUBLE, "add-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info SUB_DOUBLE =
+        new Info(Opcodes.SUB_DOUBLE, "sub-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info MUL_DOUBLE =
+        new Info(Opcodes.MUL_DOUBLE, "mul-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info DIV_DOUBLE =
+        new Info(Opcodes.DIV_DOUBLE, "div-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info REM_DOUBLE =
+        new Info(Opcodes.REM_DOUBLE, "rem-double",
+            InstructionCodec.FORMAT_23X, IndexType.NONE);
+
+    public static final Info ADD_INT_2ADDR =
+        new Info(Opcodes.ADD_INT_2ADDR, "add-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SUB_INT_2ADDR =
+        new Info(Opcodes.SUB_INT_2ADDR, "sub-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MUL_INT_2ADDR =
+        new Info(Opcodes.MUL_INT_2ADDR, "mul-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DIV_INT_2ADDR =
+        new Info(Opcodes.DIV_INT_2ADDR, "div-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info REM_INT_2ADDR =
+        new Info(Opcodes.REM_INT_2ADDR, "rem-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info AND_INT_2ADDR =
+        new Info(Opcodes.AND_INT_2ADDR, "and-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info OR_INT_2ADDR =
+        new Info(Opcodes.OR_INT_2ADDR, "or-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info XOR_INT_2ADDR =
+        new Info(Opcodes.XOR_INT_2ADDR, "xor-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SHL_INT_2ADDR =
+        new Info(Opcodes.SHL_INT_2ADDR, "shl-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SHR_INT_2ADDR =
+        new Info(Opcodes.SHR_INT_2ADDR, "shr-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info USHR_INT_2ADDR =
+        new Info(Opcodes.USHR_INT_2ADDR, "ushr-int/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info ADD_LONG_2ADDR =
+        new Info(Opcodes.ADD_LONG_2ADDR, "add-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SUB_LONG_2ADDR =
+        new Info(Opcodes.SUB_LONG_2ADDR, "sub-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MUL_LONG_2ADDR =
+        new Info(Opcodes.MUL_LONG_2ADDR, "mul-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DIV_LONG_2ADDR =
+        new Info(Opcodes.DIV_LONG_2ADDR, "div-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info REM_LONG_2ADDR =
+        new Info(Opcodes.REM_LONG_2ADDR, "rem-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info AND_LONG_2ADDR =
+        new Info(Opcodes.AND_LONG_2ADDR, "and-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info OR_LONG_2ADDR =
+        new Info(Opcodes.OR_LONG_2ADDR, "or-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info XOR_LONG_2ADDR =
+        new Info(Opcodes.XOR_LONG_2ADDR, "xor-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SHL_LONG_2ADDR =
+        new Info(Opcodes.SHL_LONG_2ADDR, "shl-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SHR_LONG_2ADDR =
+        new Info(Opcodes.SHR_LONG_2ADDR, "shr-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info USHR_LONG_2ADDR =
+        new Info(Opcodes.USHR_LONG_2ADDR, "ushr-long/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info ADD_FLOAT_2ADDR =
+        new Info(Opcodes.ADD_FLOAT_2ADDR, "add-float/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SUB_FLOAT_2ADDR =
+        new Info(Opcodes.SUB_FLOAT_2ADDR, "sub-float/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MUL_FLOAT_2ADDR =
+        new Info(Opcodes.MUL_FLOAT_2ADDR, "mul-float/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DIV_FLOAT_2ADDR =
+        new Info(Opcodes.DIV_FLOAT_2ADDR, "div-float/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info REM_FLOAT_2ADDR =
+        new Info(Opcodes.REM_FLOAT_2ADDR, "rem-float/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info ADD_DOUBLE_2ADDR =
+        new Info(Opcodes.ADD_DOUBLE_2ADDR, "add-double/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info SUB_DOUBLE_2ADDR =
+        new Info(Opcodes.SUB_DOUBLE_2ADDR, "sub-double/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info MUL_DOUBLE_2ADDR =
+        new Info(Opcodes.MUL_DOUBLE_2ADDR, "mul-double/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info DIV_DOUBLE_2ADDR =
+        new Info(Opcodes.DIV_DOUBLE_2ADDR, "div-double/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info REM_DOUBLE_2ADDR =
+        new Info(Opcodes.REM_DOUBLE_2ADDR, "rem-double/2addr",
+            InstructionCodec.FORMAT_12X, IndexType.NONE);
+
+    public static final Info ADD_INT_LIT16 =
+        new Info(Opcodes.ADD_INT_LIT16, "add-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info RSUB_INT =
+        new Info(Opcodes.RSUB_INT, "rsub-int",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info MUL_INT_LIT16 =
+        new Info(Opcodes.MUL_INT_LIT16, "mul-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info DIV_INT_LIT16 =
+        new Info(Opcodes.DIV_INT_LIT16, "div-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info REM_INT_LIT16 =
+        new Info(Opcodes.REM_INT_LIT16, "rem-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info AND_INT_LIT16 =
+        new Info(Opcodes.AND_INT_LIT16, "and-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info OR_INT_LIT16 =
+        new Info(Opcodes.OR_INT_LIT16, "or-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info XOR_INT_LIT16 =
+        new Info(Opcodes.XOR_INT_LIT16, "xor-int/lit16",
+            InstructionCodec.FORMAT_22S, IndexType.NONE);
+
+    public static final Info ADD_INT_LIT8 =
+        new Info(Opcodes.ADD_INT_LIT8, "add-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info RSUB_INT_LIT8 =
+        new Info(Opcodes.RSUB_INT_LIT8, "rsub-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info MUL_INT_LIT8 =
+        new Info(Opcodes.MUL_INT_LIT8, "mul-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info DIV_INT_LIT8 =
+        new Info(Opcodes.DIV_INT_LIT8, "div-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info REM_INT_LIT8 =
+        new Info(Opcodes.REM_INT_LIT8, "rem-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info AND_INT_LIT8 =
+        new Info(Opcodes.AND_INT_LIT8, "and-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info OR_INT_LIT8 =
+        new Info(Opcodes.OR_INT_LIT8, "or-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info XOR_INT_LIT8 =
+        new Info(Opcodes.XOR_INT_LIT8, "xor-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info SHL_INT_LIT8 =
+        new Info(Opcodes.SHL_INT_LIT8, "shl-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info SHR_INT_LIT8 =
+        new Info(Opcodes.SHR_INT_LIT8, "shr-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info USHR_INT_LIT8 =
+        new Info(Opcodes.USHR_INT_LIT8, "ushr-int/lit8",
+            InstructionCodec.FORMAT_22B, IndexType.NONE);
+
+    public static final Info CONST_CLASS_JUMBO =
+        new Info(Opcodes.CONST_CLASS_JUMBO, "const-class/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.TYPE_REF);
+
+    public static final Info CHECK_CAST_JUMBO =
+        new Info(Opcodes.CHECK_CAST_JUMBO, "check-cast/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.TYPE_REF);
+
+    public static final Info INSTANCE_OF_JUMBO =
+        new Info(Opcodes.INSTANCE_OF_JUMBO, "instance-of/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.TYPE_REF);
+
+    public static final Info NEW_INSTANCE_JUMBO =
+        new Info(Opcodes.NEW_INSTANCE_JUMBO, "new-instance/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.TYPE_REF);
+
+    public static final Info NEW_ARRAY_JUMBO =
+        new Info(Opcodes.NEW_ARRAY_JUMBO, "new-array/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.TYPE_REF);
+
+    public static final Info FILLED_NEW_ARRAY_JUMBO =
+        new Info(Opcodes.FILLED_NEW_ARRAY_JUMBO, "filled-new-array/jumbo",
+            InstructionCodec.FORMAT_5RC, IndexType.TYPE_REF);
+
+    public static final Info IGET_JUMBO =
+        new Info(Opcodes.IGET_JUMBO, "iget/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IGET_WIDE_JUMBO =
+        new Info(Opcodes.IGET_WIDE_JUMBO, "iget-wide/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IGET_OBJECT_JUMBO =
+        new Info(Opcodes.IGET_OBJECT_JUMBO, "iget-object/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IGET_BOOLEAN_JUMBO =
+        new Info(Opcodes.IGET_BOOLEAN_JUMBO, "iget-boolean/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IGET_BYTE_JUMBO =
+        new Info(Opcodes.IGET_BYTE_JUMBO, "iget-byte/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IGET_CHAR_JUMBO =
+        new Info(Opcodes.IGET_CHAR_JUMBO, "iget-char/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IGET_SHORT_JUMBO =
+        new Info(Opcodes.IGET_SHORT_JUMBO, "iget-short/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_JUMBO =
+        new Info(Opcodes.IPUT_JUMBO, "iput/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_WIDE_JUMBO =
+        new Info(Opcodes.IPUT_WIDE_JUMBO, "iput-wide/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_OBJECT_JUMBO =
+        new Info(Opcodes.IPUT_OBJECT_JUMBO, "iput-object/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_BOOLEAN_JUMBO =
+        new Info(Opcodes.IPUT_BOOLEAN_JUMBO, "iput-boolean/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_BYTE_JUMBO =
+        new Info(Opcodes.IPUT_BYTE_JUMBO, "iput-byte/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_CHAR_JUMBO =
+        new Info(Opcodes.IPUT_CHAR_JUMBO, "iput-char/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info IPUT_SHORT_JUMBO =
+        new Info(Opcodes.IPUT_SHORT_JUMBO, "iput-short/jumbo",
+            InstructionCodec.FORMAT_52C, IndexType.FIELD_REF);
+
+    public static final Info SGET_JUMBO =
+        new Info(Opcodes.SGET_JUMBO, "sget/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SGET_WIDE_JUMBO =
+        new Info(Opcodes.SGET_WIDE_JUMBO, "sget-wide/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SGET_OBJECT_JUMBO =
+        new Info(Opcodes.SGET_OBJECT_JUMBO, "sget-object/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SGET_BOOLEAN_JUMBO =
+        new Info(Opcodes.SGET_BOOLEAN_JUMBO, "sget-boolean/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SGET_BYTE_JUMBO =
+        new Info(Opcodes.SGET_BYTE_JUMBO, "sget-byte/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SGET_CHAR_JUMBO =
+        new Info(Opcodes.SGET_CHAR_JUMBO, "sget-char/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SGET_SHORT_JUMBO =
+        new Info(Opcodes.SGET_SHORT_JUMBO, "sget-short/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_JUMBO =
+        new Info(Opcodes.SPUT_JUMBO, "sput/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_WIDE_JUMBO =
+        new Info(Opcodes.SPUT_WIDE_JUMBO, "sput-wide/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_OBJECT_JUMBO =
+        new Info(Opcodes.SPUT_OBJECT_JUMBO, "sput-object/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_BOOLEAN_JUMBO =
+        new Info(Opcodes.SPUT_BOOLEAN_JUMBO, "sput-boolean/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_BYTE_JUMBO =
+        new Info(Opcodes.SPUT_BYTE_JUMBO, "sput-byte/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_CHAR_JUMBO =
+        new Info(Opcodes.SPUT_CHAR_JUMBO, "sput-char/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info SPUT_SHORT_JUMBO =
+        new Info(Opcodes.SPUT_SHORT_JUMBO, "sput-short/jumbo",
+            InstructionCodec.FORMAT_41C, IndexType.FIELD_REF);
+
+    public static final Info INVOKE_VIRTUAL_JUMBO =
+        new Info(Opcodes.INVOKE_VIRTUAL_JUMBO, "invoke-virtual/jumbo",
+            InstructionCodec.FORMAT_5RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_SUPER_JUMBO =
+        new Info(Opcodes.INVOKE_SUPER_JUMBO, "invoke-super/jumbo",
+            InstructionCodec.FORMAT_5RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_DIRECT_JUMBO =
+        new Info(Opcodes.INVOKE_DIRECT_JUMBO, "invoke-direct/jumbo",
+            InstructionCodec.FORMAT_5RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_STATIC_JUMBO =
+        new Info(Opcodes.INVOKE_STATIC_JUMBO, "invoke-static/jumbo",
+            InstructionCodec.FORMAT_5RC, IndexType.METHOD_REF);
+
+    public static final Info INVOKE_INTERFACE_JUMBO =
+        new Info(Opcodes.INVOKE_INTERFACE_JUMBO, "invoke-interface/jumbo",
+            InstructionCodec.FORMAT_5RC, IndexType.METHOD_REF);
+
+    // END(opcode-info-defs)
+
+    // Static initialization.
+    static {
+        INFO = new Info[Opcodes.MAX_VALUE - Opcodes.MIN_VALUE + 1];
+
+        // TODO: Stop using this constant.
+        set(SPECIAL_FORMAT);
+
+        // TODO: These payload opcodes should be generated by opcode-gen.
+        set(PACKED_SWITCH_PAYLOAD);
+        set(SPARSE_SWITCH_PAYLOAD);
+        set(FILL_ARRAY_DATA_PAYLOAD);
+
+        // BEGIN(opcode-info-init); GENERATED AUTOMATICALLY BY opcode-gen
+        set(NOP);
+        set(MOVE);
+        set(MOVE_FROM16);
+        set(MOVE_16);
+        set(MOVE_WIDE);
+        set(MOVE_WIDE_FROM16);
+        set(MOVE_WIDE_16);
+        set(MOVE_OBJECT);
+        set(MOVE_OBJECT_FROM16);
+        set(MOVE_OBJECT_16);
+        set(MOVE_RESULT);
+        set(MOVE_RESULT_WIDE);
+        set(MOVE_RESULT_OBJECT);
+        set(MOVE_EXCEPTION);
+        set(RETURN_VOID);
+        set(RETURN);
+        set(RETURN_WIDE);
+        set(RETURN_OBJECT);
+        set(CONST_4);
+        set(CONST_16);
+        set(CONST);
+        set(CONST_HIGH16);
+        set(CONST_WIDE_16);
+        set(CONST_WIDE_32);
+        set(CONST_WIDE);
+        set(CONST_WIDE_HIGH16);
+        set(CONST_STRING);
+        set(CONST_STRING_JUMBO);
+        set(CONST_CLASS);
+        set(MONITOR_ENTER);
+        set(MONITOR_EXIT);
+        set(CHECK_CAST);
+        set(INSTANCE_OF);
+        set(ARRAY_LENGTH);
+        set(NEW_INSTANCE);
+        set(NEW_ARRAY);
+        set(FILLED_NEW_ARRAY);
+        set(FILLED_NEW_ARRAY_RANGE);
+        set(FILL_ARRAY_DATA);
+        set(THROW);
+        set(GOTO);
+        set(GOTO_16);
+        set(GOTO_32);
+        set(PACKED_SWITCH);
+        set(SPARSE_SWITCH);
+        set(CMPL_FLOAT);
+        set(CMPG_FLOAT);
+        set(CMPL_DOUBLE);
+        set(CMPG_DOUBLE);
+        set(CMP_LONG);
+        set(IF_EQ);
+        set(IF_NE);
+        set(IF_LT);
+        set(IF_GE);
+        set(IF_GT);
+        set(IF_LE);
+        set(IF_EQZ);
+        set(IF_NEZ);
+        set(IF_LTZ);
+        set(IF_GEZ);
+        set(IF_GTZ);
+        set(IF_LEZ);
+        set(AGET);
+        set(AGET_WIDE);
+        set(AGET_OBJECT);
+        set(AGET_BOOLEAN);
+        set(AGET_BYTE);
+        set(AGET_CHAR);
+        set(AGET_SHORT);
+        set(APUT);
+        set(APUT_WIDE);
+        set(APUT_OBJECT);
+        set(APUT_BOOLEAN);
+        set(APUT_BYTE);
+        set(APUT_CHAR);
+        set(APUT_SHORT);
+        set(IGET);
+        set(IGET_WIDE);
+        set(IGET_OBJECT);
+        set(IGET_BOOLEAN);
+        set(IGET_BYTE);
+        set(IGET_CHAR);
+        set(IGET_SHORT);
+        set(IPUT);
+        set(IPUT_WIDE);
+        set(IPUT_OBJECT);
+        set(IPUT_BOOLEAN);
+        set(IPUT_BYTE);
+        set(IPUT_CHAR);
+        set(IPUT_SHORT);
+        set(SGET);
+        set(SGET_WIDE);
+        set(SGET_OBJECT);
+        set(SGET_BOOLEAN);
+        set(SGET_BYTE);
+        set(SGET_CHAR);
+        set(SGET_SHORT);
+        set(SPUT);
+        set(SPUT_WIDE);
+        set(SPUT_OBJECT);
+        set(SPUT_BOOLEAN);
+        set(SPUT_BYTE);
+        set(SPUT_CHAR);
+        set(SPUT_SHORT);
+        set(INVOKE_VIRTUAL);
+        set(INVOKE_SUPER);
+        set(INVOKE_DIRECT);
+        set(INVOKE_STATIC);
+        set(INVOKE_INTERFACE);
+        set(INVOKE_VIRTUAL_RANGE);
+        set(INVOKE_SUPER_RANGE);
+        set(INVOKE_DIRECT_RANGE);
+        set(INVOKE_STATIC_RANGE);
+        set(INVOKE_INTERFACE_RANGE);
+        set(NEG_INT);
+        set(NOT_INT);
+        set(NEG_LONG);
+        set(NOT_LONG);
+        set(NEG_FLOAT);
+        set(NEG_DOUBLE);
+        set(INT_TO_LONG);
+        set(INT_TO_FLOAT);
+        set(INT_TO_DOUBLE);
+        set(LONG_TO_INT);
+        set(LONG_TO_FLOAT);
+        set(LONG_TO_DOUBLE);
+        set(FLOAT_TO_INT);
+        set(FLOAT_TO_LONG);
+        set(FLOAT_TO_DOUBLE);
+        set(DOUBLE_TO_INT);
+        set(DOUBLE_TO_LONG);
+        set(DOUBLE_TO_FLOAT);
+        set(INT_TO_BYTE);
+        set(INT_TO_CHAR);
+        set(INT_TO_SHORT);
+        set(ADD_INT);
+        set(SUB_INT);
+        set(MUL_INT);
+        set(DIV_INT);
+        set(REM_INT);
+        set(AND_INT);
+        set(OR_INT);
+        set(XOR_INT);
+        set(SHL_INT);
+        set(SHR_INT);
+        set(USHR_INT);
+        set(ADD_LONG);
+        set(SUB_LONG);
+        set(MUL_LONG);
+        set(DIV_LONG);
+        set(REM_LONG);
+        set(AND_LONG);
+        set(OR_LONG);
+        set(XOR_LONG);
+        set(SHL_LONG);
+        set(SHR_LONG);
+        set(USHR_LONG);
+        set(ADD_FLOAT);
+        set(SUB_FLOAT);
+        set(MUL_FLOAT);
+        set(DIV_FLOAT);
+        set(REM_FLOAT);
+        set(ADD_DOUBLE);
+        set(SUB_DOUBLE);
+        set(MUL_DOUBLE);
+        set(DIV_DOUBLE);
+        set(REM_DOUBLE);
+        set(ADD_INT_2ADDR);
+        set(SUB_INT_2ADDR);
+        set(MUL_INT_2ADDR);
+        set(DIV_INT_2ADDR);
+        set(REM_INT_2ADDR);
+        set(AND_INT_2ADDR);
+        set(OR_INT_2ADDR);
+        set(XOR_INT_2ADDR);
+        set(SHL_INT_2ADDR);
+        set(SHR_INT_2ADDR);
+        set(USHR_INT_2ADDR);
+        set(ADD_LONG_2ADDR);
+        set(SUB_LONG_2ADDR);
+        set(MUL_LONG_2ADDR);
+        set(DIV_LONG_2ADDR);
+        set(REM_LONG_2ADDR);
+        set(AND_LONG_2ADDR);
+        set(OR_LONG_2ADDR);
+        set(XOR_LONG_2ADDR);
+        set(SHL_LONG_2ADDR);
+        set(SHR_LONG_2ADDR);
+        set(USHR_LONG_2ADDR);
+        set(ADD_FLOAT_2ADDR);
+        set(SUB_FLOAT_2ADDR);
+        set(MUL_FLOAT_2ADDR);
+        set(DIV_FLOAT_2ADDR);
+        set(REM_FLOAT_2ADDR);
+        set(ADD_DOUBLE_2ADDR);
+        set(SUB_DOUBLE_2ADDR);
+        set(MUL_DOUBLE_2ADDR);
+        set(DIV_DOUBLE_2ADDR);
+        set(REM_DOUBLE_2ADDR);
+        set(ADD_INT_LIT16);
+        set(RSUB_INT);
+        set(MUL_INT_LIT16);
+        set(DIV_INT_LIT16);
+        set(REM_INT_LIT16);
+        set(AND_INT_LIT16);
+        set(OR_INT_LIT16);
+        set(XOR_INT_LIT16);
+        set(ADD_INT_LIT8);
+        set(RSUB_INT_LIT8);
+        set(MUL_INT_LIT8);
+        set(DIV_INT_LIT8);
+        set(REM_INT_LIT8);
+        set(AND_INT_LIT8);
+        set(OR_INT_LIT8);
+        set(XOR_INT_LIT8);
+        set(SHL_INT_LIT8);
+        set(SHR_INT_LIT8);
+        set(USHR_INT_LIT8);
+        set(CONST_CLASS_JUMBO);
+        set(CHECK_CAST_JUMBO);
+        set(INSTANCE_OF_JUMBO);
+        set(NEW_INSTANCE_JUMBO);
+        set(NEW_ARRAY_JUMBO);
+        set(FILLED_NEW_ARRAY_JUMBO);
+        set(IGET_JUMBO);
+        set(IGET_WIDE_JUMBO);
+        set(IGET_OBJECT_JUMBO);
+        set(IGET_BOOLEAN_JUMBO);
+        set(IGET_BYTE_JUMBO);
+        set(IGET_CHAR_JUMBO);
+        set(IGET_SHORT_JUMBO);
+        set(IPUT_JUMBO);
+        set(IPUT_WIDE_JUMBO);
+        set(IPUT_OBJECT_JUMBO);
+        set(IPUT_BOOLEAN_JUMBO);
+        set(IPUT_BYTE_JUMBO);
+        set(IPUT_CHAR_JUMBO);
+        set(IPUT_SHORT_JUMBO);
+        set(SGET_JUMBO);
+        set(SGET_WIDE_JUMBO);
+        set(SGET_OBJECT_JUMBO);
+        set(SGET_BOOLEAN_JUMBO);
+        set(SGET_BYTE_JUMBO);
+        set(SGET_CHAR_JUMBO);
+        set(SGET_SHORT_JUMBO);
+        set(SPUT_JUMBO);
+        set(SPUT_WIDE_JUMBO);
+        set(SPUT_OBJECT_JUMBO);
+        set(SPUT_BOOLEAN_JUMBO);
+        set(SPUT_BYTE_JUMBO);
+        set(SPUT_CHAR_JUMBO);
+        set(SPUT_SHORT_JUMBO);
+        set(INVOKE_VIRTUAL_JUMBO);
+        set(INVOKE_SUPER_JUMBO);
+        set(INVOKE_DIRECT_JUMBO);
+        set(INVOKE_STATIC_JUMBO);
+        set(INVOKE_INTERFACE_JUMBO);
+        // END(opcode-info-init)
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private OpcodeInfo() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the {@link @Info} for the given opcode value.
+     *
+     * @param opcode {@code Opcodes.MIN_VALUE..Opcodes.MAX_VALUE;} the
+     * opcode value
+     * @return non-null; the associated opcode information instance
+     */
+    public static Info get(int opcode) {
+        int idx = opcode - Opcodes.MIN_VALUE;
+
+        try {
+            Info result = INFO[idx];
+            if (result != null) {
+                return result;
+            }
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Fall through.
+        }
+
+        throw new IllegalArgumentException("bogus opcode: "
+                + Hex.u2or4(opcode));
+    }
+
+    /**
+     * Gets the name of the given opcode.
+     */
+    public static String getName(int opcode) {
+        return get(opcode).getName();
+    }
+
+    /**
+     * Gets the format (an {@link InstructionCodec}) for the given opcode
+     * value.
+     */
+    public static InstructionCodec getFormat(int opcode) {
+        return get(opcode).getFormat();
+    }
+
+    /**
+     * Gets the {@link IndexType} for the given opcode value.
+     */
+    public static IndexType getIndexType(int opcode) {
+        return get(opcode).getIndexType();
+    }
+
+    /**
+     * Puts the given opcode into the table of all ops.
+     *
+     * @param opcode non-null; the opcode
+     */
+    private static void set(Info opcode) {
+        int idx = opcode.getOpcode() - Opcodes.MIN_VALUE;
+        INFO[idx] = opcode;
+    }
+
+    /**
+     * Information about an opcode.
+     */
+    public static class Info {
+        private final int opcode;
+        private final String name;
+        private final InstructionCodec format;
+        private final IndexType indexType;
+
+        public Info(int opcode, String name, InstructionCodec format,
+                IndexType indexType) {
+            this.opcode = opcode;
+            this.name = name;
+            this.format = format;
+            this.indexType = indexType;
+        }
+
+        public int getOpcode() {
+            return opcode;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public InstructionCodec getFormat() {
+            return format;
+        }
+
+        public IndexType getIndexType() {
+            return indexType;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/io/Opcodes.java b/dx/src/com/android/dx/io/Opcodes.java
new file mode 100644
index 0000000..4a255f7
--- /dev/null
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+/**
+ * All the Dalvik opcode value constants. See the related spec
+ * document for the meaning and instruction format of each opcode.
+ */
+public final class Opcodes {
+    /**
+     * pseudo-opcode used for nonstandard format payload "instructions". TODO:
+     * Retire this concept, and start treating the payload instructions
+     * more like the rest.
+     */
+    public static final int SPECIAL_FORMAT = -1;
+
+    /**
+     * pseudo-opcode used to indicate there is no next opcode; used
+     * in opcode chaining lists
+     */
+    public static final int NO_NEXT = -1;
+
+    /** minimum valid opcode value */
+    public static final int MIN_VALUE = -1;
+
+    /** maximum valid opcode value */
+    public static final int MAX_VALUE = 0xffff;
+
+    // BEGIN(opcodes); GENERATED AUTOMATICALLY BY opcode-gen
+    public static final int NOP = 0x00;
+    public static final int MOVE = 0x01;
+    public static final int MOVE_FROM16 = 0x02;
+    public static final int MOVE_16 = 0x03;
+    public static final int MOVE_WIDE = 0x04;
+    public static final int MOVE_WIDE_FROM16 = 0x05;
+    public static final int MOVE_WIDE_16 = 0x06;
+    public static final int MOVE_OBJECT = 0x07;
+    public static final int MOVE_OBJECT_FROM16 = 0x08;
+    public static final int MOVE_OBJECT_16 = 0x09;
+    public static final int MOVE_RESULT = 0x0a;
+    public static final int MOVE_RESULT_WIDE = 0x0b;
+    public static final int MOVE_RESULT_OBJECT = 0x0c;
+    public static final int MOVE_EXCEPTION = 0x0d;
+    public static final int RETURN_VOID = 0x0e;
+    public static final int RETURN = 0x0f;
+    public static final int RETURN_WIDE = 0x10;
+    public static final int RETURN_OBJECT = 0x11;
+    public static final int CONST_4 = 0x12;
+    public static final int CONST_16 = 0x13;
+    public static final int CONST = 0x14;
+    public static final int CONST_HIGH16 = 0x15;
+    public static final int CONST_WIDE_16 = 0x16;
+    public static final int CONST_WIDE_32 = 0x17;
+    public static final int CONST_WIDE = 0x18;
+    public static final int CONST_WIDE_HIGH16 = 0x19;
+    public static final int CONST_STRING = 0x1a;
+    public static final int CONST_STRING_JUMBO = 0x1b;
+    public static final int CONST_CLASS = 0x1c;
+    public static final int MONITOR_ENTER = 0x1d;
+    public static final int MONITOR_EXIT = 0x1e;
+    public static final int CHECK_CAST = 0x1f;
+    public static final int INSTANCE_OF = 0x20;
+    public static final int ARRAY_LENGTH = 0x21;
+    public static final int NEW_INSTANCE = 0x22;
+    public static final int NEW_ARRAY = 0x23;
+    public static final int FILLED_NEW_ARRAY = 0x24;
+    public static final int FILLED_NEW_ARRAY_RANGE = 0x25;
+    public static final int FILL_ARRAY_DATA = 0x26;
+    public static final int THROW = 0x27;
+    public static final int GOTO = 0x28;
+    public static final int GOTO_16 = 0x29;
+    public static final int GOTO_32 = 0x2a;
+    public static final int PACKED_SWITCH = 0x2b;
+    public static final int SPARSE_SWITCH = 0x2c;
+    public static final int CMPL_FLOAT = 0x2d;
+    public static final int CMPG_FLOAT = 0x2e;
+    public static final int CMPL_DOUBLE = 0x2f;
+    public static final int CMPG_DOUBLE = 0x30;
+    public static final int CMP_LONG = 0x31;
+    public static final int IF_EQ = 0x32;
+    public static final int IF_NE = 0x33;
+    public static final int IF_LT = 0x34;
+    public static final int IF_GE = 0x35;
+    public static final int IF_GT = 0x36;
+    public static final int IF_LE = 0x37;
+    public static final int IF_EQZ = 0x38;
+    public static final int IF_NEZ = 0x39;
+    public static final int IF_LTZ = 0x3a;
+    public static final int IF_GEZ = 0x3b;
+    public static final int IF_GTZ = 0x3c;
+    public static final int IF_LEZ = 0x3d;
+    public static final int AGET = 0x44;
+    public static final int AGET_WIDE = 0x45;
+    public static final int AGET_OBJECT = 0x46;
+    public static final int AGET_BOOLEAN = 0x47;
+    public static final int AGET_BYTE = 0x48;
+    public static final int AGET_CHAR = 0x49;
+    public static final int AGET_SHORT = 0x4a;
+    public static final int APUT = 0x4b;
+    public static final int APUT_WIDE = 0x4c;
+    public static final int APUT_OBJECT = 0x4d;
+    public static final int APUT_BOOLEAN = 0x4e;
+    public static final int APUT_BYTE = 0x4f;
+    public static final int APUT_CHAR = 0x50;
+    public static final int APUT_SHORT = 0x51;
+    public static final int IGET = 0x52;
+    public static final int IGET_WIDE = 0x53;
+    public static final int IGET_OBJECT = 0x54;
+    public static final int IGET_BOOLEAN = 0x55;
+    public static final int IGET_BYTE = 0x56;
+    public static final int IGET_CHAR = 0x57;
+    public static final int IGET_SHORT = 0x58;
+    public static final int IPUT = 0x59;
+    public static final int IPUT_WIDE = 0x5a;
+    public static final int IPUT_OBJECT = 0x5b;
+    public static final int IPUT_BOOLEAN = 0x5c;
+    public static final int IPUT_BYTE = 0x5d;
+    public static final int IPUT_CHAR = 0x5e;
+    public static final int IPUT_SHORT = 0x5f;
+    public static final int SGET = 0x60;
+    public static final int SGET_WIDE = 0x61;
+    public static final int SGET_OBJECT = 0x62;
+    public static final int SGET_BOOLEAN = 0x63;
+    public static final int SGET_BYTE = 0x64;
+    public static final int SGET_CHAR = 0x65;
+    public static final int SGET_SHORT = 0x66;
+    public static final int SPUT = 0x67;
+    public static final int SPUT_WIDE = 0x68;
+    public static final int SPUT_OBJECT = 0x69;
+    public static final int SPUT_BOOLEAN = 0x6a;
+    public static final int SPUT_BYTE = 0x6b;
+    public static final int SPUT_CHAR = 0x6c;
+    public static final int SPUT_SHORT = 0x6d;
+    public static final int INVOKE_VIRTUAL = 0x6e;
+    public static final int INVOKE_SUPER = 0x6f;
+    public static final int INVOKE_DIRECT = 0x70;
+    public static final int INVOKE_STATIC = 0x71;
+    public static final int INVOKE_INTERFACE = 0x72;
+    public static final int INVOKE_VIRTUAL_RANGE = 0x74;
+    public static final int INVOKE_SUPER_RANGE = 0x75;
+    public static final int INVOKE_DIRECT_RANGE = 0x76;
+    public static final int INVOKE_STATIC_RANGE = 0x77;
+    public static final int INVOKE_INTERFACE_RANGE = 0x78;
+    public static final int NEG_INT = 0x7b;
+    public static final int NOT_INT = 0x7c;
+    public static final int NEG_LONG = 0x7d;
+    public static final int NOT_LONG = 0x7e;
+    public static final int NEG_FLOAT = 0x7f;
+    public static final int NEG_DOUBLE = 0x80;
+    public static final int INT_TO_LONG = 0x81;
+    public static final int INT_TO_FLOAT = 0x82;
+    public static final int INT_TO_DOUBLE = 0x83;
+    public static final int LONG_TO_INT = 0x84;
+    public static final int LONG_TO_FLOAT = 0x85;
+    public static final int LONG_TO_DOUBLE = 0x86;
+    public static final int FLOAT_TO_INT = 0x87;
+    public static final int FLOAT_TO_LONG = 0x88;
+    public static final int FLOAT_TO_DOUBLE = 0x89;
+    public static final int DOUBLE_TO_INT = 0x8a;
+    public static final int DOUBLE_TO_LONG = 0x8b;
+    public static final int DOUBLE_TO_FLOAT = 0x8c;
+    public static final int INT_TO_BYTE = 0x8d;
+    public static final int INT_TO_CHAR = 0x8e;
+    public static final int INT_TO_SHORT = 0x8f;
+    public static final int ADD_INT = 0x90;
+    public static final int SUB_INT = 0x91;
+    public static final int MUL_INT = 0x92;
+    public static final int DIV_INT = 0x93;
+    public static final int REM_INT = 0x94;
+    public static final int AND_INT = 0x95;
+    public static final int OR_INT = 0x96;
+    public static final int XOR_INT = 0x97;
+    public static final int SHL_INT = 0x98;
+    public static final int SHR_INT = 0x99;
+    public static final int USHR_INT = 0x9a;
+    public static final int ADD_LONG = 0x9b;
+    public static final int SUB_LONG = 0x9c;
+    public static final int MUL_LONG = 0x9d;
+    public static final int DIV_LONG = 0x9e;
+    public static final int REM_LONG = 0x9f;
+    public static final int AND_LONG = 0xa0;
+    public static final int OR_LONG = 0xa1;
+    public static final int XOR_LONG = 0xa2;
+    public static final int SHL_LONG = 0xa3;
+    public static final int SHR_LONG = 0xa4;
+    public static final int USHR_LONG = 0xa5;
+    public static final int ADD_FLOAT = 0xa6;
+    public static final int SUB_FLOAT = 0xa7;
+    public static final int MUL_FLOAT = 0xa8;
+    public static final int DIV_FLOAT = 0xa9;
+    public static final int REM_FLOAT = 0xaa;
+    public static final int ADD_DOUBLE = 0xab;
+    public static final int SUB_DOUBLE = 0xac;
+    public static final int MUL_DOUBLE = 0xad;
+    public static final int DIV_DOUBLE = 0xae;
+    public static final int REM_DOUBLE = 0xaf;
+    public static final int ADD_INT_2ADDR = 0xb0;
+    public static final int SUB_INT_2ADDR = 0xb1;
+    public static final int MUL_INT_2ADDR = 0xb2;
+    public static final int DIV_INT_2ADDR = 0xb3;
+    public static final int REM_INT_2ADDR = 0xb4;
+    public static final int AND_INT_2ADDR = 0xb5;
+    public static final int OR_INT_2ADDR = 0xb6;
+    public static final int XOR_INT_2ADDR = 0xb7;
+    public static final int SHL_INT_2ADDR = 0xb8;
+    public static final int SHR_INT_2ADDR = 0xb9;
+    public static final int USHR_INT_2ADDR = 0xba;
+    public static final int ADD_LONG_2ADDR = 0xbb;
+    public static final int SUB_LONG_2ADDR = 0xbc;
+    public static final int MUL_LONG_2ADDR = 0xbd;
+    public static final int DIV_LONG_2ADDR = 0xbe;
+    public static final int REM_LONG_2ADDR = 0xbf;
+    public static final int AND_LONG_2ADDR = 0xc0;
+    public static final int OR_LONG_2ADDR = 0xc1;
+    public static final int XOR_LONG_2ADDR = 0xc2;
+    public static final int SHL_LONG_2ADDR = 0xc3;
+    public static final int SHR_LONG_2ADDR = 0xc4;
+    public static final int USHR_LONG_2ADDR = 0xc5;
+    public static final int ADD_FLOAT_2ADDR = 0xc6;
+    public static final int SUB_FLOAT_2ADDR = 0xc7;
+    public static final int MUL_FLOAT_2ADDR = 0xc8;
+    public static final int DIV_FLOAT_2ADDR = 0xc9;
+    public static final int REM_FLOAT_2ADDR = 0xca;
+    public static final int ADD_DOUBLE_2ADDR = 0xcb;
+    public static final int SUB_DOUBLE_2ADDR = 0xcc;
+    public static final int MUL_DOUBLE_2ADDR = 0xcd;
+    public static final int DIV_DOUBLE_2ADDR = 0xce;
+    public static final int REM_DOUBLE_2ADDR = 0xcf;
+    public static final int ADD_INT_LIT16 = 0xd0;
+    public static final int RSUB_INT = 0xd1;
+    public static final int MUL_INT_LIT16 = 0xd2;
+    public static final int DIV_INT_LIT16 = 0xd3;
+    public static final int REM_INT_LIT16 = 0xd4;
+    public static final int AND_INT_LIT16 = 0xd5;
+    public static final int OR_INT_LIT16 = 0xd6;
+    public static final int XOR_INT_LIT16 = 0xd7;
+    public static final int ADD_INT_LIT8 = 0xd8;
+    public static final int RSUB_INT_LIT8 = 0xd9;
+    public static final int MUL_INT_LIT8 = 0xda;
+    public static final int DIV_INT_LIT8 = 0xdb;
+    public static final int REM_INT_LIT8 = 0xdc;
+    public static final int AND_INT_LIT8 = 0xdd;
+    public static final int OR_INT_LIT8 = 0xde;
+    public static final int XOR_INT_LIT8 = 0xdf;
+    public static final int SHL_INT_LIT8 = 0xe0;
+    public static final int SHR_INT_LIT8 = 0xe1;
+    public static final int USHR_INT_LIT8 = 0xe2;
+    public static final int CONST_CLASS_JUMBO = 0x00ff;
+    public static final int CHECK_CAST_JUMBO = 0x01ff;
+    public static final int INSTANCE_OF_JUMBO = 0x02ff;
+    public static final int NEW_INSTANCE_JUMBO = 0x03ff;
+    public static final int NEW_ARRAY_JUMBO = 0x04ff;
+    public static final int FILLED_NEW_ARRAY_JUMBO = 0x05ff;
+    public static final int IGET_JUMBO = 0x06ff;
+    public static final int IGET_WIDE_JUMBO = 0x07ff;
+    public static final int IGET_OBJECT_JUMBO = 0x08ff;
+    public static final int IGET_BOOLEAN_JUMBO = 0x09ff;
+    public static final int IGET_BYTE_JUMBO = 0x0aff;
+    public static final int IGET_CHAR_JUMBO = 0x0bff;
+    public static final int IGET_SHORT_JUMBO = 0x0cff;
+    public static final int IPUT_JUMBO = 0x0dff;
+    public static final int IPUT_WIDE_JUMBO = 0x0eff;
+    public static final int IPUT_OBJECT_JUMBO = 0x0fff;
+    public static final int IPUT_BOOLEAN_JUMBO = 0x10ff;
+    public static final int IPUT_BYTE_JUMBO = 0x11ff;
+    public static final int IPUT_CHAR_JUMBO = 0x12ff;
+    public static final int IPUT_SHORT_JUMBO = 0x13ff;
+    public static final int SGET_JUMBO = 0x14ff;
+    public static final int SGET_WIDE_JUMBO = 0x15ff;
+    public static final int SGET_OBJECT_JUMBO = 0x16ff;
+    public static final int SGET_BOOLEAN_JUMBO = 0x17ff;
+    public static final int SGET_BYTE_JUMBO = 0x18ff;
+    public static final int SGET_CHAR_JUMBO = 0x19ff;
+    public static final int SGET_SHORT_JUMBO = 0x1aff;
+    public static final int SPUT_JUMBO = 0x1bff;
+    public static final int SPUT_WIDE_JUMBO = 0x1cff;
+    public static final int SPUT_OBJECT_JUMBO = 0x1dff;
+    public static final int SPUT_BOOLEAN_JUMBO = 0x1eff;
+    public static final int SPUT_BYTE_JUMBO = 0x1fff;
+    public static final int SPUT_CHAR_JUMBO = 0x20ff;
+    public static final int SPUT_SHORT_JUMBO = 0x21ff;
+    public static final int INVOKE_VIRTUAL_JUMBO = 0x22ff;
+    public static final int INVOKE_SUPER_JUMBO = 0x23ff;
+    public static final int INVOKE_DIRECT_JUMBO = 0x24ff;
+    public static final int INVOKE_STATIC_JUMBO = 0x25ff;
+    public static final int INVOKE_INTERFACE_JUMBO = 0x26ff;
+    // END(opcodes)
+
+    // TODO: Generate these payload opcodes with opcode-gen.
+
+    /**
+     * special pseudo-opcode value for packed-switch data payload
+     * instructions
+     */
+    public static final int PACKED_SWITCH_PAYLOAD = 0x100;
+
+    /** special pseudo-opcode value for packed-switch data payload
+     * instructions
+     */
+    public static final int SPARSE_SWITCH_PAYLOAD = 0x200;
+
+    /** special pseudo-opcode value for fill-array-data data payload
+     * instructions
+     */
+    public static final int FILL_ARRAY_DATA_PAYLOAD = 0x300;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Opcodes() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Determines if the given opcode has the right "shape" to be
+     * valid. This includes the range {@code 0x01..0xfe}, the range
+     * {@code 0x00ff..0xffff} where the low-order byte is either
+     * {@code 0} or {@code 0xff}, and the special opcode values {@code
+     * SPECIAL_FORMAT} and {@code NO_NEXT}. Note that not all of the
+     * opcode values that pass this test are in fact used. This method
+     * is meant to perform a quick check to reject blatantly wrong
+     * values (e.g. when validating arguments).
+     *
+     * @param opcode the opcode value
+     * @return {@code true} iff the value has the right "shape" to be
+     * possibly valid
+     */
+    public static boolean isValidShape(int opcode) {
+        /*
+         * Note: This method bakes in knowledge that all opcodes are
+         * one of the forms:
+         *
+         *   * single byte in range 0x01..0xfe -- normal opcodes
+         *   * (byteValue << 8) -- nop and data payload opcodes
+         *   * ((byteValue << 8) | 0xff) -- 16-bit extended opcodes
+         *   * SPECIAL_FORMAT or NO_NEXT -- pseudo-opcodes
+         */
+
+        // Note: SPECIAL_FORMAT == NO_NEXT.
+        if (opcode < SPECIAL_FORMAT) {
+            return false;
+        } else if (opcode == SPECIAL_FORMAT) {
+            return true;
+        }
+
+        int lowByte = opcode & 0xff;
+        if ((lowByte == 0) || (lowByte == 0xff)) {
+            return true;
+        }
+
+        return (opcode & 0xff00) == 0;
+    }
+
+    /**
+     * Gets whether ({@code true}) or not ({@code false}) the given
+     * opcode value is an "extended" opcode (not counting the nop-like
+     * payload opcodes). Extended opcodes require a full 16-bit code
+     * unit to represent, without leaving space for an argument byte.
+     * 
+     * @param opcode the opcode value
+     * @return {@code true} iff the opcode is an "extended" opcode
+     */
+    public static boolean isExtended(int opcode) {
+        /*
+         * Note: Extended opcodes all have the form ((byteValue << 8)
+         * | 0xff).
+         */
+        return (opcode >= 0x00ff);
+    }
+
+    /**
+     * Gets the opcode out of an opcode unit, the latter of which may also
+     * include one or more argument values.
+     *
+     * @param opcodeUnit the opcode-containing code unit
+     * @return the extracted opcode
+     */
+    public static int extractOpcodeFromUnit(int opcodeUnit) {
+        /*
+         * Note: This method bakes in knowledge that all opcodes are
+         * either single-byte or of the forms (byteValue << 8) or
+         * ((byteValue << 8) | 0xff).
+         */
+
+        int lowByte = opcodeUnit & 0xff;
+        return ((lowByte == 0) || (lowByte == 0xff)) ? opcodeUnit : lowByte;
+    }
+}
diff --git a/dx/src/com/android/dx/io/ProtoId.java b/dx/src/com/android/dx/io/ProtoId.java
new file mode 100644
index 0000000..98c0777
--- /dev/null
+++ b/dx/src/com/android/dx/io/ProtoId.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io;
+
+import com.android.dx.util.Unsigned;
+
+public final class ProtoId implements Comparable<ProtoId> {
+    private final DexBuffer buffer;
+    private final int shortyIndex;
+    private final int returnTypeIndex;
+    private final int parametersOffset;
+
+    public ProtoId(DexBuffer buffer, int shortyIndex, int returnTypeIndex, int parametersOffset) {
+        this.buffer = buffer;
+        this.shortyIndex = shortyIndex;
+        this.returnTypeIndex = returnTypeIndex;
+        this.parametersOffset = parametersOffset;
+    }
+
+    public int compareTo(ProtoId other) {
+        if (returnTypeIndex != other.returnTypeIndex) {
+            return Unsigned.compare(returnTypeIndex, other.returnTypeIndex);
+        }
+        return Unsigned.compare(parametersOffset, other.parametersOffset);
+    }
+
+    public int getShortyIndex() {
+        return shortyIndex;
+    }
+
+    public int getReturnTypeIndex() {
+        return returnTypeIndex;
+    }
+
+    public int getParametersOffset() {
+        return parametersOffset;
+    }
+
+    public void writeTo(DexBuffer.Section out) {
+        out.writeInt(shortyIndex);
+        out.writeInt(returnTypeIndex);
+        out.writeInt(parametersOffset);
+    }
+
+    @Override public String toString() {
+        if (buffer == null) {
+            return shortyIndex + " " + returnTypeIndex + " " + parametersOffset;
+        }
+
+        return buffer.strings().get(shortyIndex)
+                + ": " + buffer.typeNames().get(returnTypeIndex)
+                + " " + buffer.readTypeList(parametersOffset);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/AddressMap.java b/dx/src/com/android/dx/io/instructions/AddressMap.java
new file mode 100644
index 0000000..a8dbe0b
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/AddressMap.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import java.io.EOFException;
+import java.util.HashMap;
+
+/**
+ * Map from addresses to addresses, where addresses are all
+ * {@code int}s.
+ */
+public final class AddressMap {
+    /** underlying map. TODO: This might be too inefficient. */
+    private final HashMap<Integer,Integer> map;
+
+    /**
+     * Constructs an instance.
+     */
+    public AddressMap() {
+        map = new HashMap<Integer,Integer>();
+    }
+
+    /**
+     * Gets the value address corresponding to the given key address. Returns
+     * {@code -1} if there is no mapping.
+     */
+    public int get(int keyAddress) {
+        Integer value = map.get(keyAddress);
+        return (value == null) ? -1 : value;
+    }
+
+    /**
+     * Sets the value address associated with the given key address.
+     */
+    public void put(int keyAddress, int valueAddress) {
+        map.put(keyAddress, valueAddress);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/BaseCodeCursor.java b/dx/src/com/android/dx/io/instructions/BaseCodeCursor.java
new file mode 100644
index 0000000..6915fa8
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/BaseCodeCursor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import java.io.EOFException;
+
+/**
+ * Base implementation of {@link CodeCursor}.
+ */
+public abstract class BaseCodeCursor implements CodeCursor {
+    /** base address map */
+    private final AddressMap baseAddressMap;
+
+    /** next index within {@link #array} to read from or write to */
+    private int cursor;
+
+    /**
+     * Constructs an instance.
+     */
+    public BaseCodeCursor() {
+        this.baseAddressMap = new AddressMap();
+        this.cursor = 0;
+    }
+
+    /** @inheritDoc */
+    public final int cursor() {
+        return cursor;
+    }
+
+    /** @inheritDoc */
+    public final int baseAddressForCursor() {
+        int mapped = baseAddressMap.get(cursor);
+        return (mapped >= 0) ? mapped : cursor;
+    }
+
+    /** @inheritDoc */
+    public final void setBaseAddress(int targetAddress, int baseAddress) {
+        baseAddressMap.put(targetAddress, baseAddress);
+    }
+
+    /**
+     * Advance the cursor by the indicated amount.
+     */
+    protected final void advance(int amount) {
+        cursor += amount;
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/CodeCursor.java b/dx/src/com/android/dx/io/instructions/CodeCursor.java
new file mode 100644
index 0000000..68eb9c9
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/CodeCursor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+/**
+ * Cursor over code units, for reading or writing out Dalvik bytecode.
+ */
+public interface CodeCursor {
+    /**
+     * Gets the cursor. The cursor is the offset in code units from
+     * the start of the input of the next code unit to be read or
+     * written, where the input generally consists of the code for a
+     * single method.
+     */
+    public int cursor();
+
+    /**
+     * Gets the base address associated with the current cursor. This
+     * differs from the cursor value when explicitly set (by {@link
+     * #setBaseAddress). This is used, in particular, to convey base
+     * addresses to switch data payload instructions, whose relative
+     * addresses are relative to the address of a dependant switch
+     * instruction.
+     */
+    public int baseAddressForCursor();
+
+    /**
+     * Sets the base address for the given target address to be as indicated.
+     *
+     * @see #baseAddressForCursor
+     */
+    public void setBaseAddress(int targetAddress, int baseAddress);
+}
diff --git a/dx/src/com/android/dx/io/instructions/CodeInput.java b/dx/src/com/android/dx/io/instructions/CodeInput.java
new file mode 100644
index 0000000..41a5ef7
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/CodeInput.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import java.io.EOFException;
+
+/**
+ * Input stream of code units, for reading in Dalvik bytecode.
+ */
+public interface CodeInput extends CodeCursor {
+    /**
+     * Returns whether there are any more code units to read. This
+     * is analogous to {@code hasNext()} on an interator.
+     */
+    public boolean hasMore();
+
+    /**
+     * Reads a code unit.
+     */
+    public int read() throws EOFException;
+
+    /**
+     * Reads two code units, treating them as a little-endian {@code int}.
+     */
+    public int readInt() throws EOFException;
+
+    /**
+     * Reads four code units, treating them as a little-endian {@code long}.
+     */
+    public long readLong() throws EOFException;
+}
diff --git a/dx/src/com/android/dx/io/instructions/CodeOutput.java b/dx/src/com/android/dx/io/instructions/CodeOutput.java
new file mode 100644
index 0000000..7d0077e
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/CodeOutput.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+/**
+ * Output stream of code units, for writing out Dalvik bytecode.
+ */
+public interface CodeOutput extends CodeCursor {
+    /**
+     * Writes a code unit.
+     */
+    public void write(short codeUnit);
+
+    /**
+     * Writes two code units.
+     */
+    public void write(short u0, short u1);
+
+    /**
+     * Writes three code units.
+     */
+    public void write(short u0, short u1, short u2);
+
+    /**
+     * Writes four code units.
+     */
+    public void write(short u0, short u1, short u2, short u3);
+
+    /**
+     * Writes five code units.
+     */
+    public void write(short u0, short u1, short u2, short u3, short u4);
+
+    /**
+     * Writes an {@code int}, little-endian.
+     */
+    public void writeInt(int value);
+
+    /**
+     * Writes a {@code long}, little-endian.
+     */
+    public void writeLong(long value);
+
+    /**
+     * Writes the contents of the given array.
+     */
+    public void write(byte[] data);
+
+    /**
+     * Writes the contents of the given array.
+     */
+    public void write(short[] data);
+
+    /**
+     * Writes the contents of the given array.
+     */
+    public void write(int[] data);
+
+    /**
+     * Writes the contents of the given array.
+     */
+    public void write(long[] data);
+}
diff --git a/dx/src/com/android/dx/io/instructions/DecodedInstruction.java b/dx/src/com/android/dx/io/instructions/DecodedInstruction.java
new file mode 100644
index 0000000..e418a1c
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/DecodedInstruction.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+import com.android.dx.io.OpcodeInfo;
+import com.android.dx.io.Opcodes;
+import com.android.dx.util.DexException;
+import com.android.dx.util.Hex;
+
+import java.io.EOFException;
+
+/**
+ * A decoded Dalvik instruction. This consists of a format codec, a
+ * numeric opcode, an optional index type, and any additional
+ * arguments of the instruction. The additional arguments (if any) are
+ * represented as uninterpreted data.
+ *
+ * <p><b>Note:</b> The names of the arguments are <i>not</i> meant to
+ * match the names given in the Dalvik instruction format
+ * specification, specification which just names fields (somewhat)
+ * arbitrarily alphabetically from A. In this class, non-register
+ * fields are given descriptive names and register fields are
+ * consistently named alphabetically.</p>
+ */
+public abstract class DecodedInstruction {
+    /** non-null; instruction format / codec */
+    private final InstructionCodec format;
+
+    /** opcode number */
+    private final int opcode;
+
+    /** constant index argument */
+    private final int index;
+
+    /** null-ok; index type */
+    private final IndexType indexType;
+
+    /**
+     * target address argument. This is an absolute address, not just
+     * a signed offset. <b>Note:</b> The address is unsigned, even
+     * though it is stored in an {@code int}.
+     */
+    private final int target;
+
+    /**
+     * literal value argument; also used for special verification error
+     * constants (formats 20bc and 40sc) as well as should-be-zero values
+     * (formats 10x, 20t, 30t, and 32x)
+     */
+    private final long literal;
+
+    /**
+     * Decodes an instruction from the given input source.
+     */
+    public static DecodedInstruction decode(CodeInput in) throws EOFException {
+        int opcodeUnit = in.read();
+        int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
+        InstructionCodec format = OpcodeInfo.getFormat(opcode);
+
+        return format.decode(opcodeUnit, in);
+    }
+
+    /**
+     * Decodes an array of instructions. The result has non-null
+     * elements at each offset that represents the start of an
+     * instruction.
+     */
+    public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
+        int size = encodedInstructions.length;
+        DecodedInstruction[] decoded = new DecodedInstruction[size];
+        ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
+
+        try {
+            while (in.hasMore()) {
+                decoded[in.cursor()] = DecodedInstruction.decode(in);
+            }
+        } catch (EOFException ex) {
+            throw new AssertionError("shouldn't happen");
+        }
+
+        return decoded;
+    }
+
+    /**
+     * Constructs an instance.
+     */
+    public DecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal) {
+        if (format == null) {
+            throw new NullPointerException("format == null");
+        }
+
+        if (!Opcodes.isValidShape(opcode)) {
+            throw new IllegalArgumentException("invalid opcode");
+        }
+
+        this.format = format;
+        this.opcode = opcode;
+        this.index = index;
+        this.indexType = indexType;
+        this.target = target;
+        this.literal = literal;
+    }
+
+    public final InstructionCodec getFormat() {
+        return format;
+    }
+
+    public final int getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the opcode, as a code unit.
+     */
+    public final short getOpcodeUnit() {
+        return (short) opcode;
+    }
+
+    public final int getIndex() {
+        return index;
+    }
+
+    /**
+     * Gets the index, as a code unit.
+     */
+    public final short getIndexUnit() {
+        return (short) index;
+    }
+
+    public final IndexType getIndexType() {
+        return indexType;
+    }
+
+    /**
+     * Gets the raw target.
+     */
+    public final int getTarget() {
+        return target;
+    }
+
+    /**
+     * Gets the target as a relative offset from the given address.
+     */
+    public final int getTarget(int baseAddress) {
+        return target - baseAddress;
+    }
+
+    /**
+     * Gets the target as a relative offset from the given base
+     * address, as a code unit. This will throw if the value is out of
+     * the range of a signed code unit.
+     */
+    public final short getTargetUnit(int baseAddress) {
+        int relativeTarget = getTarget(baseAddress);
+
+        if (relativeTarget != (short) relativeTarget) {
+            throw new DexException("Target out of range: "
+                    + Hex.s4(relativeTarget));
+        }
+
+        return (short) relativeTarget;
+    }
+
+    /**
+     * Gets the target as a relative offset from the given base
+     * address, masked to be a byte in size. This will throw if the
+     * value is out of the range of a signed byte.
+     */
+    public final int getTargetByte(int baseAddress) {
+        int relativeTarget = getTarget(baseAddress);
+
+        if (relativeTarget != (byte) relativeTarget) {
+            throw new DexException("Target out of range: "
+                    + Hex.s4(relativeTarget));
+        }
+
+        return relativeTarget & 0xff;
+    }
+
+    public final long getLiteral() {
+        return literal;
+    }
+
+    /**
+     * Gets the literal value, masked to be an int in size. This will
+     * throw if the value is out of the range of a signed int.
+     */
+    public final int getLiteralInt() {
+        if (literal != (int) literal) {
+            throw new DexException("Literal out of range: " + Hex.u8(literal));
+        }
+
+        return (int) literal;
+    }
+
+    /**
+     * Gets the literal value, as a code unit. This will throw if the
+     * value is out of the range of a signed code unit.
+     */
+    public final short getLiteralUnit() {
+        if (literal != (short) literal) {
+            throw new DexException("Literal out of range: " + Hex.u8(literal));
+        }
+
+        return (short) literal;
+    }
+
+    /**
+     * Gets the literal value, masked to be a byte in size. This will
+     * throw if the value is out of the range of a signed byte.
+     */
+    public final int getLiteralByte() {
+        if (literal != (byte) literal) {
+            throw new DexException("Literal out of range: " + Hex.u8(literal));
+        }
+
+        return (int) literal & 0xff;
+    }
+
+    /**
+     * Gets the literal value, masked to be a nibble in size. This
+     * will throw if the value is out of the range of a signed nibble.
+     */
+    public final int getLiteralNibble() {
+        if ((literal < -8) || (literal > 7)) {
+            throw new DexException("Literal out of range: " + Hex.u8(literal));
+        }
+
+        return (int) literal & 0xf;
+    }
+
+    public abstract int getRegisterCount();
+
+    public int getA() {
+        return 0;
+    }
+
+    public int getB() {
+        return 0;
+    }
+
+    public int getC() {
+        return 0;
+    }
+
+    public int getD() {
+        return 0;
+    }
+
+    public int getE() {
+        return 0;
+    }
+
+    /**
+     * Gets the register count, as a code unit. This will throw if the
+     * value is out of the range of an unsigned code unit.
+     */
+    public final short getRegisterCountUnit() {
+        int registerCount = getRegisterCount();
+
+        if ((registerCount & ~0xffff) != 0) {
+            throw new DexException("Register count out of range: "
+                    + Hex.u8(registerCount));
+        }
+
+        return (short) registerCount;
+    }
+
+    /**
+     * Gets the A register number, as a code unit. This will throw if the
+     * value is out of the range of an unsigned code unit.
+     */
+    public final short getAUnit() {
+        int a = getA();
+
+        if ((a & ~0xffff) != 0) {
+            throw new DexException("Register A out of range: " + Hex.u8(a));
+        }
+
+        return (short) a;
+    }
+
+    /**
+     * Gets the A register number, as a byte. This will throw if the
+     * value is out of the range of an unsigned byte.
+     */
+    public final short getAByte() {
+        int a = getA();
+
+        if ((a & ~0xff) != 0) {
+            throw new DexException("Register A out of range: " + Hex.u8(a));
+        }
+
+        return (short) a;
+    }
+
+    /**
+     * Gets the A register number, as a nibble. This will throw if the
+     * value is out of the range of an unsigned nibble.
+     */
+    public final short getANibble() {
+        int a = getA();
+
+        if ((a & ~0xf) != 0) {
+            throw new DexException("Register A out of range: " + Hex.u8(a));
+        }
+
+        return (short) a;
+    }
+
+    /**
+     * Gets the B register number, as a code unit. This will throw if the
+     * value is out of the range of an unsigned code unit.
+     */
+    public final short getBUnit() {
+        int b = getB();
+
+        if ((b & ~0xffff) != 0) {
+            throw new DexException("Register B out of range: " + Hex.u8(b));
+        }
+
+        return (short) b;
+    }
+
+    /**
+     * Gets the B register number, as a byte. This will throw if the
+     * value is out of the range of an unsigned byte.
+     */
+    public final short getBByte() {
+        int b = getB();
+
+        if ((b & ~0xff) != 0) {
+            throw new DexException("Register B out of range: " + Hex.u8(b));
+        }
+
+        return (short) b;
+    }
+
+    /**
+     * Gets the B register number, as a nibble. This will throw if the
+     * value is out of the range of an unsigned nibble.
+     */
+    public final short getBNibble() {
+        int b = getB();
+
+        if ((b & ~0xf) != 0) {
+            throw new DexException("Register B out of range: " + Hex.u8(b));
+        }
+
+        return (short) b;
+    }
+
+    /**
+     * Gets the C register number, as a code unit. This will throw if the
+     * value is out of the range of an unsigned code unit.
+     */
+    public final short getCUnit() {
+        int c = getC();
+
+        if ((c & ~0xffff) != 0) {
+            throw new DexException("Register C out of range: " + Hex.u8(c));
+        }
+
+        return (short) c;
+    }
+
+    /**
+     * Gets the C register number, as a byte. This will throw if the
+     * value is out of the range of an unsigned byte.
+     */
+    public final short getCByte() {
+        int c = getC();
+
+        if ((c & ~0xff) != 0) {
+            throw new DexException("Register C out of range: " + Hex.u8(c));
+        }
+
+        return (short) c;
+    }
+
+    /**
+     * Gets the C register number, as a nibble. This will throw if the
+     * value is out of the range of an unsigned nibble.
+     */
+    public final short getCNibble() {
+        int c = getC();
+
+        if ((c & ~0xf) != 0) {
+            throw new DexException("Register C out of range: " + Hex.u8(c));
+        }
+
+        return (short) c;
+    }
+
+    /**
+     * Gets the D register number, as a code unit. This will throw if the
+     * value is out of the range of an unsigned code unit.
+     */
+    public final short getDUnit() {
+        int d = getD();
+
+        if ((d & ~0xffff) != 0) {
+            throw new DexException("Register D out of range: " + Hex.u8(d));
+        }
+
+        return (short) d;
+    }
+
+    /**
+     * Gets the D register number, as a byte. This will throw if the
+     * value is out of the range of an unsigned byte.
+     */
+    public final short getDByte() {
+        int d = getD();
+
+        if ((d & ~0xff) != 0) {
+            throw new DexException("Register D out of range: " + Hex.u8(d));
+        }
+
+        return (short) d;
+    }
+
+    /**
+     * Gets the D register number, as a nibble. This will throw if the
+     * value is out of the range of an unsigned nibble.
+     */
+    public final short getDNibble() {
+        int d = getD();
+
+        if ((d & ~0xf) != 0) {
+            throw new DexException("Register D out of range: " + Hex.u8(d));
+        }
+
+        return (short) d;
+    }
+
+    /**
+     * Gets the E register number, as a nibble. This will throw if the
+     * value is out of the range of an unsigned nibble.
+     */
+    public final short getENibble() {
+        int e = getE();
+
+        if ((e & ~0xf) != 0) {
+            throw new DexException("Register E out of range: " + Hex.u8(e));
+        }
+
+        return (short) e;
+    }
+
+    /**
+     * Encodes this instance to the given output.
+     */
+    public final void encode(CodeOutput out) {
+        format.encode(this, out);
+    }
+
+    /**
+     * Returns an instance just like this one, except with the index replaced
+     * with the given one.
+     */
+    public abstract DecodedInstruction withIndex(int newIndex);
+}
diff --git a/dx/src/com/android/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java
new file mode 100644
index 0000000..64fc55b
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/FillArrayDataPayloadDecodedInstruction.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+/**
+ * A decoded Dalvik instruction which contains the payload for
+ * a {@code packed-switch} instruction.
+ */
+public final class FillArrayDataPayloadDecodedInstruction
+        extends DecodedInstruction {
+    /** data array */
+    private final Object data;
+
+    /** number of elements */
+    private final int size;
+
+    /** element width */
+    private final int elementWidth;
+
+    /**
+     * Constructs an instance. This private instance doesn't check the
+     * type of the data array.
+     */
+    private FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, Object data, int size, int elementWidth) {
+        super(format, opcode, 0, null, 0, 0L);
+
+        this.data = data;
+        this.size = size;
+        this.elementWidth = elementWidth;
+    }
+
+    /**
+     * Constructs an instance.
+     */
+    public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, byte[] data) {
+        this(format, opcode, data, data.length, 1);
+    }
+
+    /**
+     * Constructs an instance.
+     */
+    public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, short[] data) {
+        this(format, opcode, data, data.length, 2);
+    }
+
+    /**
+     * Constructs an instance.
+     */
+    public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, int[] data) {
+        this(format, opcode, data, data.length, 4);
+    }
+
+    /**
+     * Constructs an instance.
+     */
+    public FillArrayDataPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, long[] data) {
+        this(format, opcode, data, data.length, 8);
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 0;
+    }
+
+    public short getElementWidthUnit() {
+        return (short) elementWidth;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        throw new UnsupportedOperationException("no index in instruction");
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/FiveRegisterDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/FiveRegisterDecodedInstruction.java
new file mode 100644
index 0000000..6e14d34
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/FiveRegisterDecodedInstruction.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has five register arguments.
+ */
+public final class FiveRegisterDecodedInstruction extends DecodedInstruction {
+    /** register argument "A" */
+    private final int a;
+
+    /** register argument "B" */
+    private final int b;
+
+    /** register argument "C" */
+    private final int c;
+
+    /** register argument "D" */
+    private final int d;
+
+    /** register argument "E" */
+    private final int e;
+
+    /**
+     * Constructs an instance.
+     */
+    public FiveRegisterDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal,
+            int a, int b, int c, int d, int e) {
+        super(format, opcode, index, indexType, target, literal);
+
+        this.a = a;
+        this.b = b;
+        this.c = c;
+        this.d = d;
+        this.e = e;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 5;
+    }
+
+    /** @inheritDoc */
+    public int getA() {
+        return a;
+    }
+
+    /** @inheritDoc */
+    public int getB() {
+        return b;
+    }
+
+    /** @inheritDoc */
+    public int getC() {
+        return c;
+    }
+
+    /** @inheritDoc */
+    public int getD() {
+        return d;
+    }
+
+    /** @inheritDoc */
+    public int getE() {
+        return e;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new FiveRegisterDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral(), a, b, c, d, e);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/FourRegisterDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/FourRegisterDecodedInstruction.java
new file mode 100644
index 0000000..29836d0
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/FourRegisterDecodedInstruction.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has five register arguments.
+ */
+public final class FourRegisterDecodedInstruction extends DecodedInstruction {
+    /** register argument "A" */
+    private final int a;
+
+    /** register argument "B" */
+    private final int b;
+
+    /** register argument "C" */
+    private final int c;
+
+    /** register argument "D" */
+    private final int d;
+
+    /**
+     * Constructs an instance.
+     */
+    public FourRegisterDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal,
+            int a, int b, int c, int d) {
+        super(format, opcode, index, indexType, target, literal);
+
+        this.a = a;
+        this.b = b;
+        this.c = c;
+        this.d = d;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 4;
+    }
+
+    /** @inheritDoc */
+    public int getA() {
+        return a;
+    }
+
+    /** @inheritDoc */
+    public int getB() {
+        return b;
+    }
+
+    /** @inheritDoc */
+    public int getC() {
+        return c;
+    }
+
+    /** @inheritDoc */
+    public int getD() {
+        return d;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new FourRegisterDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral(), a, b, c, d);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/InstructionCodec.java b/dx/src/com/android/dx/io/instructions/InstructionCodec.java
new file mode 100644
index 0000000..b864b83
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/InstructionCodec.java
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+import com.android.dx.io.OpcodeInfo;
+import com.android.dx.io.Opcodes;
+import com.android.dx.util.DexException;
+import com.android.dx.util.Hex;
+
+import java.io.EOFException;
+
+/**
+ * Representation of an instruction format, which knows how to decode into
+ * and encode from instances of {@link DecodedInstruction}.
+ */
+public enum InstructionCodec {
+    FORMAT_00X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcodeUnit, 0, null,
+                    0, 0L);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(insn.getOpcodeUnit());
+        }
+    },
+
+    FORMAT_10X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int literal = byte1(opcodeUnit); // should be zero
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(insn.getOpcodeUnit());
+        }
+    },
+
+    FORMAT_12X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = nibble2(opcodeUnit);
+            int b = nibble3(opcodeUnit);
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, 0L,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcodeUnit(),
+                             makeByte(insn.getA(), insn.getB())));
+        }
+    },
+
+    FORMAT_11N() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = nibble2(opcodeUnit);
+            int literal = (nibble3(opcodeUnit) << 28) >> 28; // sign-extend
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcodeUnit(),
+                             makeByte(insn.getA(), insn.getLiteralNibble())));
+        }
+    },
+
+    FORMAT_11X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, 0L,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(codeUnit(insn.getOpcode(), insn.getA()));
+        }
+    },
+
+    FORMAT_10T() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.cursor() - 1;
+            int opcode = byte0(opcodeUnit);
+            int target = (byte) byte1(opcodeUnit); // sign-extend
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    baseAddress + target, 0L);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int relativeTarget = insn.getTargetByte(out.cursor());
+            out.write(codeUnit(insn.getOpcode(), relativeTarget));
+        }
+    },
+
+    FORMAT_20T() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.cursor() - 1;
+            int opcode = byte0(opcodeUnit);
+            int literal = byte1(opcodeUnit); // should be zero
+            int target = (short) in.read(); // sign-extend
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    baseAddress + target, literal);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            short relativeTarget = insn.getTargetUnit(out.cursor());
+            out.write(insn.getOpcodeUnit(), relativeTarget);
+        }
+    },
+
+    FORMAT_20BC() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            // Note: We use the literal field to hold the decoded AA value.
+            int opcode = byte0(opcodeUnit);
+            int literal = byte1(opcodeUnit);
+            int index = in.read();
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcode, index, IndexType.VARIES,
+                    0, literal);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getLiteralByte()),
+                    insn.getIndexUnit());
+        }
+    },
+
+    FORMAT_22X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int b = in.read();
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, 0L,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    insn.getBUnit());
+        }
+    },
+
+    FORMAT_21T() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.cursor() - 1;
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int target = (short) in.read(); // sign-extend
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    baseAddress + target, 0L,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            short relativeTarget = insn.getTargetUnit(out.cursor());
+            out.write(codeUnit(insn.getOpcode(), insn.getA()), relativeTarget);
+        }
+    },
+
+    FORMAT_21S() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int literal = (short) in.read(); // sign-extend
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    insn.getLiteralUnit());
+        }
+    },
+
+    FORMAT_21H() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            long literal = (short) in.read(); // sign-extend
+
+            /*
+             * Format 21h decodes differently depending on the opcode,
+             * because the "signed hat" might represent either a 32-
+             * or 64- bit value.
+             */
+            literal <<= (opcode == Opcodes.CONST_HIGH16) ? 16 : 48;
+
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            // See above.
+            int opcode = insn.getOpcode();
+            int shift = (opcode == Opcodes.CONST_HIGH16) ? 16 : 48;
+            short literal = (short) (insn.getLiteral() >> shift);
+
+            out.write(codeUnit(opcode, insn.getA()), literal);
+        }
+    },
+
+    FORMAT_21C() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int index = in.read();
+            IndexType indexType = OpcodeInfo.getIndexType(opcode);
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, index, indexType,
+                    0, 0L,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    insn.getIndexUnit());
+        }
+    },
+
+    FORMAT_23X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int bc = in.read();
+            int b = byte0(bc);
+            int c = byte1(bc);
+            return new ThreeRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, 0L,
+                    a, b, c);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    codeUnit(insn.getB(), insn.getC()));
+        }
+    },
+
+    FORMAT_22B() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int bc = in.read();
+            int b = byte0(bc);
+            int literal = (byte) byte1(bc); // sign-extend
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    codeUnit(insn.getB(),
+                             insn.getLiteralByte()));
+        }
+    },
+
+    FORMAT_22T() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.cursor() - 1;
+            int opcode = byte0(opcodeUnit);
+            int a = nibble2(opcodeUnit);
+            int b = nibble3(opcodeUnit);
+            int target = (short) in.read(); // sign-extend
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    baseAddress + target, 0L,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            short relativeTarget = insn.getTargetUnit(out.cursor());
+            out.write(
+                    codeUnit(insn.getOpcode(),
+                             makeByte(insn.getA(), insn.getB())),
+                    relativeTarget);
+        }
+    },
+
+    FORMAT_22S() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = nibble2(opcodeUnit);
+            int b = nibble3(opcodeUnit);
+            int literal = (short) in.read(); // sign-extend
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(),
+                             makeByte(insn.getA(), insn.getB())),
+                    insn.getLiteralUnit());
+        }
+    },
+
+    FORMAT_22C() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = nibble2(opcodeUnit);
+            int b = nibble3(opcodeUnit);
+            int index = in.read();
+            IndexType indexType = OpcodeInfo.getIndexType(opcode);
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, index, indexType,
+                    0, 0L,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(),
+                             makeByte(insn.getA(), insn.getB())),
+                    insn.getIndexUnit());
+        }
+    },
+
+    FORMAT_22CS() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = nibble2(opcodeUnit);
+            int b = nibble3(opcodeUnit);
+            int index = in.read();
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, index, IndexType.FIELD_OFFSET,
+                    0, 0L,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    codeUnit(insn.getOpcode(),
+                             makeByte(insn.getA(), insn.getB())),
+                    insn.getIndexUnit());
+        }
+    },
+
+    FORMAT_30T() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.cursor() - 1;
+            int opcode = byte0(opcodeUnit);
+            int literal = byte1(opcodeUnit); // should be zero
+            int target = in.readInt();
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    baseAddress + target, literal);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int relativeTarget = insn.getTarget(out.cursor());
+            out.write(insn.getOpcodeUnit(),
+                    unit0(relativeTarget), unit1(relativeTarget));
+        }
+    },
+
+    FORMAT_32X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int literal = byte1(opcodeUnit); // should be zero
+            int a = in.read();
+            int b = in.read();
+            return new TwoRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(insn.getOpcodeUnit(), insn.getAUnit(), insn.getBUnit());
+        }
+    },
+
+    FORMAT_31I() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int literal = in.readInt();
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int literal = insn.getLiteralInt();
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    unit0(literal),
+                    unit1(literal));
+        }
+    },
+
+    FORMAT_31T() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.cursor() - 1;
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int target = baseAddress + in.readInt();
+
+            /*
+             * Switch instructions need to "forward" their addresses to their
+             * payload target instructions.
+             */
+            switch (opcode) {
+                case Opcodes.PACKED_SWITCH:
+                case Opcodes.SPARSE_SWITCH: {
+                    in.setBaseAddress(target, baseAddress);
+                    break;
+                }
+            }
+
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    target, 0L,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int relativeTarget = insn.getTarget(out.cursor());
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    unit0(relativeTarget), unit1(relativeTarget));
+        }
+    },
+
+    FORMAT_31C() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            int index = in.readInt();
+            IndexType indexType = OpcodeInfo.getIndexType(opcode);
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, index, indexType,
+                    0, 0L,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int index = insn.getIndex();
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    unit0(index),
+                    unit1(index));
+        }
+    },
+
+    FORMAT_35C() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterList(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterList(insn, out);
+        }
+    },
+
+    FORMAT_35MS() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterList(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterList(insn, out);
+        }
+    },
+
+    FORMAT_35MI() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterList(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterList(insn, out);
+        }
+    },
+
+    FORMAT_3RC() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterRange(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterRange(insn, out);
+        }
+    },
+
+    FORMAT_3RMS() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterRange(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterRange(insn, out);
+        }
+    },
+
+    FORMAT_3RMI() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            return decodeRegisterRange(this, opcodeUnit, in);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            encodeRegisterRange(insn, out);
+        }
+    },
+
+    FORMAT_51L() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int opcode = byte0(opcodeUnit);
+            int a = byte1(opcodeUnit);
+            long literal = in.readLong();
+            return new OneRegisterDecodedInstruction(
+                    this, opcode, 0, null,
+                    0, literal,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            long literal = insn.getLiteral();
+            out.write(
+                    codeUnit(insn.getOpcode(), insn.getA()),
+                    unit0(literal),
+                    unit1(literal),
+                    unit2(literal),
+                    unit3(literal));
+        }
+    },
+
+    FORMAT_33X() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int ab = in.read();
+            int a = byte0(ab);
+            int b = byte1(ab);
+            int c = in.read();
+            return new ThreeRegisterDecodedInstruction(
+                    this, opcodeUnit, 0, null,
+                    0, 0L,
+                    a, b, c);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    insn.getOpcodeUnit(),
+                    codeUnit(insn.getA(), insn.getB()),
+                    insn.getCUnit());
+        }
+    },
+
+    FORMAT_32S() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int ab = in.read();
+            int a = byte0(ab);
+            int b = byte1(ab);
+            int literal = (short) in.read(); // sign-extend
+            return new TwoRegisterDecodedInstruction(
+                    this, opcodeUnit, 0, null,
+                    0, literal,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            out.write(
+                    insn.getOpcodeUnit(),
+                    codeUnit(insn.getA(), insn.getB()),
+                    insn.getLiteralUnit());
+        }
+    },
+
+    FORMAT_40SC() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            // Note: We use the literal field to hold the decoded AA value.
+            int index = in.readInt();
+            int literal = in.read();
+            return new ZeroRegisterDecodedInstruction(
+                    this, opcodeUnit, index, IndexType.VARIES,
+                    0, literal);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int index = insn.getIndex();
+            out.write(
+                    insn.getOpcodeUnit(),
+                    unit0(index),
+                    unit1(index),
+                    insn.getLiteralUnit());
+        }
+    },
+
+    FORMAT_41C() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int index = in.readInt();
+            int a = in.read();
+            IndexType indexType = OpcodeInfo.getIndexType(opcodeUnit);
+            return new OneRegisterDecodedInstruction(
+                    this, opcodeUnit, index, indexType,
+                    0, 0L,
+                    a);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int index = insn.getIndex();
+            out.write(
+                    insn.getOpcodeUnit(),
+                    unit0(index),
+                    unit1(index),
+                    insn.getAUnit());
+        }
+    },
+
+    FORMAT_52C() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int index = in.readInt();
+            int a = in.read();
+            int b = in.read();
+            IndexType indexType = OpcodeInfo.getIndexType(opcodeUnit);
+            return new TwoRegisterDecodedInstruction(
+                    this, opcodeUnit, index, indexType,
+                    0, 0L,
+                    a, b);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int index = insn.getIndex();
+            out.write(
+                    insn.getOpcodeUnit(),
+                    unit0(index),
+                    unit1(index),
+                    insn.getAUnit(),
+                    insn.getBUnit());
+        }
+    },
+
+    FORMAT_5RC() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int index = in.readInt();
+            int registerCount = in.read();
+            int a = in.read();
+            IndexType indexType = OpcodeInfo.getIndexType(opcodeUnit);
+            return new RegisterRangeDecodedInstruction(
+                    this, opcodeUnit, index, indexType,
+                    0, 0L,
+                    a, registerCount);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            int index = insn.getIndex();
+            out.write(
+                    insn.getOpcodeUnit(),
+                    unit0(index),
+                    unit1(index),
+                    insn.getRegisterCountUnit(),
+                    insn.getAUnit());
+        }
+    },
+
+    FORMAT_PACKED_SWITCH_PAYLOAD() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.baseAddressForCursor() - 1; // already read opcode
+            int size = in.read();
+            int firstKey = in.readInt();
+            int[] targets = new int[size];
+
+            for (int i = 0; i < size; i++) {
+                targets[i] = baseAddress + in.readInt();
+            }
+
+            return new PackedSwitchPayloadDecodedInstruction(
+                    this, opcodeUnit, firstKey, targets);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            PackedSwitchPayloadDecodedInstruction payload =
+                (PackedSwitchPayloadDecodedInstruction) insn;
+            int[] targets = payload.getTargets();
+            int baseAddress = out.baseAddressForCursor();
+
+            out.write(payload.getOpcodeUnit());
+            out.write(asUnsignedUnit(targets.length));
+            out.writeInt(payload.getFirstKey());
+
+            for (int target : targets) {
+                out.writeInt(target - baseAddress);
+            }
+        }
+    },
+
+    FORMAT_SPARSE_SWITCH_PAYLOAD() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int baseAddress = in.baseAddressForCursor() - 1; // already read opcode
+            int size = in.read();
+            int[] keys = new int[size];
+            int[] targets = new int[size];
+
+            for (int i = 0; i < size; i++) {
+                keys[i] = in.readInt();
+            }
+
+            for (int i = 0; i < size; i++) {
+                targets[i] = baseAddress + in.readInt();
+            }
+
+            return new SparseSwitchPayloadDecodedInstruction(
+                    this, opcodeUnit, keys, targets);
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            SparseSwitchPayloadDecodedInstruction payload =
+                (SparseSwitchPayloadDecodedInstruction) insn;
+            int[] keys = payload.getKeys();
+            int[] targets = payload.getTargets();
+            int baseAddress = out.baseAddressForCursor();
+
+            out.write(payload.getOpcodeUnit());
+            out.write(asUnsignedUnit(targets.length));
+
+            for (int key : keys) {
+                out.writeInt(key);
+            }
+
+            for (int target : targets) {
+                out.writeInt(target - baseAddress);
+            }
+        }
+    },
+
+    FORMAT_FILL_ARRAY_DATA_PAYLOAD() {
+        @Override public DecodedInstruction decode(int opcodeUnit,
+                CodeInput in) throws EOFException {
+            int elementWidth = in.read();
+            int size = in.readInt();
+
+            switch (elementWidth) {
+                case 1: {
+                    byte[] array = new byte[size];
+                    boolean even = true;
+                    for (int i = 0, value = 0; i < size; i++, even = !even) {
+                        if (even) {
+                            value = in.read();
+                        }
+                        array[i] = (byte) (value & 0xff);
+                        value >>= 8;
+                    }
+                    return new FillArrayDataPayloadDecodedInstruction(
+                            this, opcodeUnit, array);
+                }
+                case 2: {
+                    short[] array = new short[size];
+                    for (int i = 0; i < size; i++) {
+                        array[i] = (short) in.read();
+                    }
+                    return new FillArrayDataPayloadDecodedInstruction(
+                            this, opcodeUnit, array);
+                }
+                case 4: {
+                    int[] array = new int[size];
+                    for (int i = 0; i < size; i++) {
+                        array[i] = in.readInt();
+                    }
+                    return new FillArrayDataPayloadDecodedInstruction(
+                            this, opcodeUnit, array);
+                }
+                case 8: {
+                    long[] array = new long[size];
+                    for (int i = 0; i < size; i++) {
+                        array[i] = in.readLong();
+                    }
+                    return new FillArrayDataPayloadDecodedInstruction(
+                            this, opcodeUnit, array);
+                }
+            }
+
+            throw new DexException("bogus element_width: "
+                    + Hex.u2(elementWidth));
+        }
+
+        @Override public void encode(DecodedInstruction insn, CodeOutput out) {
+            FillArrayDataPayloadDecodedInstruction payload =
+                (FillArrayDataPayloadDecodedInstruction) insn;
+            short elementWidth = payload.getElementWidthUnit();
+            Object data = payload.getData();
+
+            out.write(payload.getOpcodeUnit());
+            out.write(elementWidth);
+            out.writeInt(payload.getSize());
+
+            switch (elementWidth) {
+                case 1: out.write((byte[]) data);  break;
+                case 2: out.write((short[]) data); break;
+                case 4: out.write((int[]) data);   break;
+                case 8: out.write((long[]) data);  break;
+                default: {
+                    throw new DexException("bogus element_width: "
+                            + Hex.u2(elementWidth));
+                }
+            }
+        }
+    };
+
+    /**
+     * Decodes an instruction specified by the given opcode unit, reading
+     * any required additional code units from the given input source.
+     */
+    public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in)
+        throws EOFException;
+
+    /**
+     * Encodes the given instruction.
+     */
+    public abstract void encode(DecodedInstruction insn, CodeOutput out);
+
+    /**
+     * Helper method that decodes any of the register-list formats.
+     */
+    private static DecodedInstruction decodeRegisterList(
+            InstructionCodec format, int opcodeUnit, CodeInput in)
+            throws EOFException {
+        int opcode = byte0(opcodeUnit);
+        int e = nibble2(opcodeUnit);
+        int registerCount = nibble3(opcodeUnit);
+        int index = in.read();
+        int abcd = in.read();
+        int a = nibble0(abcd);
+        int b = nibble1(abcd);
+        int c = nibble2(abcd);
+        int d = nibble3(abcd);
+        IndexType indexType = OpcodeInfo.getIndexType(opcode);
+
+        // TODO: Having to switch like this is less than ideal.
+        switch (registerCount) {
+            case 0:
+                return new ZeroRegisterDecodedInstruction(
+                        format, opcode, index, indexType,
+                        0, 0L);
+            case 1:
+                return new OneRegisterDecodedInstruction(
+                        format, opcode, index, indexType,
+                        0, 0L,
+                        a);
+            case 2:
+                return new TwoRegisterDecodedInstruction(
+                        format, opcode, index, indexType,
+                        0, 0L,
+                        a, b);
+            case 3:
+                return new ThreeRegisterDecodedInstruction(
+                        format, opcode, index, indexType,
+                        0, 0L,
+                        a, b, c);
+            case 4:
+                return new FourRegisterDecodedInstruction(
+                        format, opcode, index, indexType,
+                        0, 0L,
+                        a, b, c, d);
+            case 5:
+                return new FiveRegisterDecodedInstruction(
+                        format, opcode, index, indexType,
+                        0, 0L,
+                        a, b, c, d, e);
+        }
+
+        throw new DexException("bogus registerCount: "
+                + Hex.uNibble(registerCount));
+    }
+
+    /**
+     * Helper method that encodes any of the register-list formats.
+     */
+    private static void encodeRegisterList(DecodedInstruction insn,
+            CodeOutput out) {
+        out.write(codeUnit(insn.getOpcode(),
+                        makeByte(insn.getE(), insn.getRegisterCount())),
+                insn.getIndexUnit(),
+                codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD()));
+    }
+
+    /**
+     * Helper method that decodes any of the three-unit register-range formats.
+     */
+    private static DecodedInstruction decodeRegisterRange(
+            InstructionCodec format, int opcodeUnit, CodeInput in)
+            throws EOFException {
+        int opcode = byte0(opcodeUnit);
+        int registerCount = byte1(opcodeUnit);
+        int index = in.read();
+        int a = in.read();
+        IndexType indexType = OpcodeInfo.getIndexType(opcode);
+        return new RegisterRangeDecodedInstruction(
+                format, opcode, index, indexType,
+                0, 0L,
+                a, registerCount);
+    }
+
+    /**
+     * Helper method that encodes any of the three-unit register-range formats.
+     */
+    private static void encodeRegisterRange(DecodedInstruction insn,
+            CodeOutput out) {
+        out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()),
+                insn.getIndexUnit(),
+                insn.getAUnit());
+    }
+
+    private static short codeUnit(int lowByte, int highByte) {
+        if ((lowByte & ~0xff) != 0) {
+            throw new IllegalArgumentException("bogus lowByte");
+        }
+
+        if ((highByte & ~0xff) != 0) {
+            throw new IllegalArgumentException("bogus highByte");
+        }
+
+        return (short) (lowByte | (highByte << 8));
+    }
+
+    private static short codeUnit(int nibble0, int nibble1, int nibble2,
+            int nibble3) {
+        if ((nibble0 & ~0xf) != 0) {
+            throw new IllegalArgumentException("bogus nibble0");
+        }
+
+        if ((nibble1 & ~0xf) != 0) {
+            throw new IllegalArgumentException("bogus nibble1");
+        }
+
+        if ((nibble2 & ~0xf) != 0) {
+            throw new IllegalArgumentException("bogus nibble2");
+        }
+
+        if ((nibble3 & ~0xf) != 0) {
+            throw new IllegalArgumentException("bogus nibble3");
+        }
+
+        return (short) (nibble0 | (nibble1 << 4)
+                | (nibble2 << 8) | (nibble3 << 12));
+    }
+
+    private static int makeByte(int lowNibble, int highNibble) {
+        if ((lowNibble & ~0xf) != 0) {
+            throw new IllegalArgumentException("bogus lowNibble");
+        }
+
+        if ((highNibble & ~0xf) != 0) {
+            throw new IllegalArgumentException("bogus highNibble");
+        }
+
+        return lowNibble | (highNibble << 4);
+    }
+
+    private static short asUnsignedUnit(int value) {
+        if ((value & ~0xffff) != 0) {
+            throw new IllegalArgumentException("bogus unsigned code unit");
+        }
+
+        return (short) value;
+    }
+
+    private static short unit0(int value) {
+        return (short) value;
+    }
+
+    private static short unit1(int value) {
+        return (short) (value >> 16);
+    }
+
+    private static short unit0(long value) {
+        return (short) value;
+    }
+
+    private static short unit1(long value) {
+        return (short) (value >> 16);
+    }
+
+    private static short unit2(long value) {
+        return (short) (value >> 32);
+    }
+
+    private static short unit3(long value) {
+        return (short) (value >> 48);
+    }
+
+    private static int byte0(int value) {
+        return value & 0xff;
+    }
+
+    private static int byte1(int value) {
+        return (value >> 8) & 0xff;
+    }
+
+    private static int byte2(int value) {
+        return (value >> 16) & 0xff;
+    }
+
+    private static int byte3(int value) {
+        return value >>> 24;
+    }
+
+    private static int nibble0(int value) {
+        return value & 0xf;
+    }
+
+    private static int nibble1(int value) {
+        return (value >> 4) & 0xf;
+    }
+
+    private static int nibble2(int value) {
+        return (value >> 8) & 0xf;
+    }
+
+    private static int nibble3(int value) {
+        return (value >> 12) & 0xf;
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/OneRegisterDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/OneRegisterDecodedInstruction.java
new file mode 100644
index 0000000..fd38e3b
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/OneRegisterDecodedInstruction.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has one register argument.
+ */
+public final class OneRegisterDecodedInstruction extends DecodedInstruction {
+    /** register argument "A" */
+    private final int a;
+
+    /**
+     * Constructs an instance.
+     */
+    public OneRegisterDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal,
+            int a) {
+        super(format, opcode, index, indexType, target, literal);
+
+        this.a = a;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 1;
+    }
+
+    /** @inheritDoc */
+    public int getA() {
+        return a;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new OneRegisterDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral(), a);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java
new file mode 100644
index 0000000..c31d319
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/PackedSwitchPayloadDecodedInstruction.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+/**
+ * A decoded Dalvik instruction which contains the payload for
+ * a {@code packed-switch} instruction.
+ */
+public final class PackedSwitchPayloadDecodedInstruction
+        extends DecodedInstruction {
+    /** first key value */
+    private final int firstKey;
+
+    /**
+     * array of target addresses. These are absolute, not relative,
+     * addresses.
+     */
+    private final int[] targets;
+
+    /**
+     * Constructs an instance.
+     */
+    public PackedSwitchPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, int firstKey, int[] targets) {
+        super(format, opcode, 0, null, 0, 0L);
+
+        this.firstKey = firstKey;
+        this.targets = targets;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 0;
+    }
+
+    public int getFirstKey() {
+        return firstKey;
+    }
+
+    public int[] getTargets() {
+        return targets;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        throw new UnsupportedOperationException("no index in instruction");
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/RegisterRangeDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/RegisterRangeDecodedInstruction.java
new file mode 100644
index 0000000..f294f63
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/RegisterRangeDecodedInstruction.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has register range arguments (an
+ * "A" start register and a register count).
+ */
+public final class RegisterRangeDecodedInstruction extends DecodedInstruction {
+    /** register argument "A" */
+    private final int a;
+
+    /** register count */
+    private final int registerCount;
+
+    /**
+     * Constructs an instance.
+     */
+    public RegisterRangeDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal,
+            int a, int registerCount) {
+        super(format, opcode, index, indexType, target, literal);
+
+        this.a = a;
+        this.registerCount = registerCount;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return registerCount;
+    }
+
+    /** @inheritDoc */
+    public int getA() {
+        return a;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new RegisterRangeDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral(), a, registerCount);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/ShortArrayCodeInput.java b/dx/src/com/android/dx/io/instructions/ShortArrayCodeInput.java
new file mode 100644
index 0000000..49ce473
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/ShortArrayCodeInput.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import java.io.EOFException;
+
+/**
+ * Implementation of {@code CodeInput} that reads from a {@code short[]}.
+ */
+public final class ShortArrayCodeInput extends BaseCodeCursor
+        implements CodeInput {
+    /** source array to read from */
+    private final short[] array;
+
+    /**
+     * Constructs an instance.
+     */
+    public ShortArrayCodeInput(short[] array) {
+        if (array == null) {
+            throw new NullPointerException("array == null");
+        }
+
+        this.array = array;
+    }
+
+    /** @inheritDoc */
+    public boolean hasMore() {
+        return cursor() < array.length;
+    }
+
+    /** @inheritDoc */
+    public int read() throws EOFException {
+        try {
+            int value = array[cursor()];
+            advance(1);
+            return value & 0xffff;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            throw new EOFException();
+        }
+    }
+
+    /** @inheritDoc */
+    public int readInt() throws EOFException {
+        int short0 = read();
+        int short1 = read();
+
+        return short0 | (short1 << 16);
+    }
+
+    /** @inheritDoc */
+    public long readLong() throws EOFException {
+        long short0 = read();
+        long short1 = read();
+        long short2 = read();
+        long short3 = read();
+
+        return short0 | (short1 << 16) | (short2 << 32) | (short3 << 48);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/ShortArrayCodeOutput.java b/dx/src/com/android/dx/io/instructions/ShortArrayCodeOutput.java
new file mode 100644
index 0000000..efa7ddd
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/ShortArrayCodeOutput.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+/**
+ * Implementation of {@code CodeOutput} that writes to a {@code short[]}.
+ */
+public final class ShortArrayCodeOutput extends BaseCodeCursor
+        implements CodeOutput {
+    /** array to write to */
+    private final short[] array;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param maxSize the maximum number of code units that will be written
+     */
+    public ShortArrayCodeOutput(int maxSize) {
+        if (maxSize < 0) {
+            throw new IllegalArgumentException("maxSize < 0");
+        }
+
+        this.array = new short[maxSize];
+    }
+
+    /**
+     * Gets the array. The returned array contains exactly the data
+     * written (e.g. no leftover space at the end).
+     */
+    public short[] getArray() {
+        int cursor = cursor();
+
+        if (cursor == array.length) {
+            return array;
+        }
+
+        short[] result = new short[cursor];
+        System.arraycopy(array, 0, result, 0, cursor);
+        return result;
+    }
+
+    /** @inheritDoc */
+    public void write(short codeUnit) {
+        array[cursor()] = codeUnit;
+        advance(1);
+    }
+
+    /** @inheritDoc */
+    public void write(short u0, short u1) {
+        write(u0);
+        write(u1);
+    }
+
+    /** @inheritDoc */
+    public void write(short u0, short u1, short u2) {
+        write(u0);
+        write(u1);
+        write(u2);
+    }
+
+    /** @inheritDoc */
+    public void write(short u0, short u1, short u2, short u3) {
+        write(u0);
+        write(u1);
+        write(u2);
+        write(u3);
+    }
+
+    /** @inheritDoc */
+    public void write(short u0, short u1, short u2, short u3, short u4) {
+        write(u0);
+        write(u1);
+        write(u2);
+        write(u3);
+        write(u4);
+    }
+
+    /** @inheritDoc */
+    public void writeInt(int value) {
+        write((short) value);
+        write((short) (value >> 16));
+    }
+
+    /** @inheritDoc */
+    public void writeLong(long value) {
+        write((short) value);
+        write((short) (value >> 16));
+        write((short) (value >> 32));
+        write((short) (value >> 48));
+    }
+
+    /** @inheritDoc */
+    public void write(byte[] data) {
+        int value = 0;
+        boolean even = true;
+        for (byte b : data) {
+            if (even) {
+                value = b & 0xff;
+                even = false;
+            } else {
+                value |= b << 8;
+                write((short) value);
+                even = true;
+            }
+        }
+
+        if (!even) {
+            write((short) value);
+        }
+    }
+
+    /** @inheritDoc */
+    public void write(short[] data) {
+        for (short unit : data) {
+            write(unit);
+        }
+    }
+
+    /** @inheritDoc */
+    public void write(int[] data) {
+        for (int i : data) {
+            writeInt(i);
+        }
+    }
+
+    /** @inheritDoc */
+    public void write(long[] data) {
+        for (long l : data) {
+            writeLong(l);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java
new file mode 100644
index 0000000..bfc47c9
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/SparseSwitchPayloadDecodedInstruction.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+/**
+ * A decoded Dalvik instruction which contains the payload for
+ * a {@code packed-switch} instruction.
+ */
+public final class SparseSwitchPayloadDecodedInstruction
+        extends DecodedInstruction {
+    /** array of key values */
+    private final int[] keys;
+
+    /**
+     * array of target addresses. These are absolute, not relative,
+     * addresses.
+     */
+    private final int[] targets;
+
+    /**
+     * Constructs an instance.
+     */
+    public SparseSwitchPayloadDecodedInstruction(InstructionCodec format,
+            int opcode, int[] keys, int[] targets) {
+        super(format, opcode, 0, null, 0, 0L);
+
+        if (keys.length != targets.length) {
+            throw new IllegalArgumentException("keys/targets length mismatch");
+        }
+
+        this.keys = keys;
+        this.targets = targets;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 0;
+    }
+
+    public int[] getKeys() {
+        return keys;
+    }
+
+    public int[] getTargets() {
+        return targets;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        throw new UnsupportedOperationException("no index in instruction");
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/ThreeRegisterDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/ThreeRegisterDecodedInstruction.java
new file mode 100644
index 0000000..a463677
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/ThreeRegisterDecodedInstruction.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has three register arguments.
+ */
+public final class ThreeRegisterDecodedInstruction extends DecodedInstruction {
+    /** register argument "A" */
+    private final int a;
+
+    /** register argument "B" */
+    private final int b;
+
+    /** register argument "C" */
+    private final int c;
+
+    /**
+     * Constructs an instance.
+     */
+    public ThreeRegisterDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal,
+            int a, int b, int c) {
+        super(format, opcode, index, indexType, target, literal);
+
+        this.a = a;
+        this.b = b;
+        this.c = c;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 3;
+    }
+
+    /** @inheritDoc */
+    public int getA() {
+        return a;
+    }
+
+    /** @inheritDoc */
+    public int getB() {
+        return b;
+    }
+
+    /** @inheritDoc */
+    public int getC() {
+        return c;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new ThreeRegisterDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral(), a, b, c);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/TwoRegisterDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/TwoRegisterDecodedInstruction.java
new file mode 100644
index 0000000..acb77ba
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/TwoRegisterDecodedInstruction.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has two register arguments.
+ */
+public final class TwoRegisterDecodedInstruction extends DecodedInstruction {
+    /** register argument "A" */
+    private final int a;
+
+    /** register argument "B" */
+    private final int b;
+
+    /**
+     * Constructs an instance.
+     */
+    public TwoRegisterDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal,
+            int a, int b) {
+        super(format, opcode, index, indexType, target, literal);
+
+        this.a = a;
+        this.b = b;
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 2;
+    }
+
+    /** @inheritDoc */
+    public int getA() {
+        return a;
+    }
+
+    /** @inheritDoc */
+    public int getB() {
+        return b;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new TwoRegisterDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral(), a, b);
+    }
+}
diff --git a/dx/src/com/android/dx/io/instructions/ZeroRegisterDecodedInstruction.java b/dx/src/com/android/dx/io/instructions/ZeroRegisterDecodedInstruction.java
new file mode 100644
index 0000000..172caa4
--- /dev/null
+++ b/dx/src/com/android/dx/io/instructions/ZeroRegisterDecodedInstruction.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.io.instructions;
+
+import com.android.dx.io.IndexType;
+
+/**
+ * A decoded Dalvik instruction which has no register arguments.
+ */
+public final class ZeroRegisterDecodedInstruction extends DecodedInstruction {
+    /**
+     * Constructs an instance.
+     */
+    public ZeroRegisterDecodedInstruction(InstructionCodec format, int opcode,
+            int index, IndexType indexType, int target, long literal) {
+        super(format, opcode, index, indexType, target, literal);
+    }
+
+    /** @inheritDoc */
+    public int getRegisterCount() {
+        return 0;
+    }
+
+    /** @inheritDoc */
+    public DecodedInstruction withIndex(int newIndex) {
+        return new ZeroRegisterDecodedInstruction(
+                getFormat(), getOpcode(), newIndex, getIndexType(),
+                getTarget(), getLiteral());
+    }
+}
diff --git a/dx/src/com/android/dx/merge/CollisionPolicy.java b/dx/src/com/android/dx/merge/CollisionPolicy.java
new file mode 100644
index 0000000..95e9835
--- /dev/null
+++ b/dx/src/com/android/dx/merge/CollisionPolicy.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+/**
+ * What to do when two dex files define the same class.
+ */
+public enum CollisionPolicy {
+
+    /**
+     * Keep the class def from the first dex file and discard the def from the
+     * second dex file. This policy is appropriate for incremental builds.
+     */
+    KEEP_FIRST,
+
+    /**
+     * Forbid collisions. This policy is appropriate for merging libraries.
+     */
+    FAIL
+}
diff --git a/dx/src/com/android/dx/merge/DexMerger.java b/dx/src/com/android/dx/merge/DexMerger.java
new file mode 100644
index 0000000..b807117
--- /dev/null
+++ b/dx/src/com/android/dx/merge/DexMerger.java
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.dex.SizeOf;
+import com.android.dx.dex.TableOfContents;
+import com.android.dx.io.Annotation;
+import com.android.dx.io.ClassData;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.Code;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.io.DexHasher;
+import com.android.dx.io.FieldId;
+import com.android.dx.io.MethodId;
+import com.android.dx.io.ProtoId;
+import com.android.dx.util.DexException;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Combine two dex files into one.
+ */
+public final class DexMerger {
+    private final DexBuffer dexA;
+    private final DexBuffer dexB;
+    private final CollisionPolicy collisionPolicy;
+    private final WriterSizes writerSizes;
+
+    private final DexBuffer dexOut = new DexBuffer();
+
+    private final DexBuffer.Section headerOut;
+
+    /** All IDs and definitions sections */
+    private final DexBuffer.Section idsDefsOut;
+
+    private final DexBuffer.Section mapListOut;
+
+    private final DexBuffer.Section typeListOut;
+
+    private final DexBuffer.Section classDataOut;
+
+    private final DexBuffer.Section codeOut;
+
+    private final DexBuffer.Section stringDataOut;
+
+    private final DexBuffer.Section debugInfoOut;
+
+    private final DexBuffer.Section encodedArrayOut;
+
+    /** annotations directory on a type */
+    private final DexBuffer.Section annotationsDirectoryOut;
+
+    /** sets of annotations on a member, parameter or type */
+    private final DexBuffer.Section annotationSetOut;
+
+    /** parameter lists */
+    private final DexBuffer.Section annotationSetRefListOut;
+
+    /** individual annotations, each containing zero or more fields */
+    private final DexBuffer.Section annotationOut;
+
+    private final TableOfContents contentsOut;
+
+    private final IndexMap aIndexMap;
+    private final IndexMap bIndexMap;
+    private final InstructionTransformer aInstructionTransformer;
+    private final InstructionTransformer bInstructionTransformer;
+
+    /** minimum number of wasted bytes before it's worthwhile to compact the result */
+    private int compactWasteThreshold = 1024 * 1024; // 1MiB
+
+    public DexMerger(DexBuffer dexA, DexBuffer dexB, CollisionPolicy collisionPolicy)
+            throws IOException {
+        this(dexA, dexB, collisionPolicy, new WriterSizes(dexA, dexB));
+    }
+
+    private DexMerger(DexBuffer dexA, DexBuffer dexB, CollisionPolicy collisionPolicy,
+            WriterSizes writerSizes) throws IOException {
+        this.dexA = dexA;
+        this.dexB = dexB;
+        this.collisionPolicy = collisionPolicy;
+        this.writerSizes = writerSizes;
+
+        TableOfContents aContents = dexA.getTableOfContents();
+        TableOfContents bContents = dexB.getTableOfContents();
+        aIndexMap = new IndexMap(dexOut, aContents);
+        bIndexMap = new IndexMap(dexOut, bContents);
+        aInstructionTransformer = new InstructionTransformer(aIndexMap);
+        bInstructionTransformer = new InstructionTransformer(bIndexMap);
+
+        headerOut = dexOut.appendSection(writerSizes.header, "header");
+        idsDefsOut = dexOut.appendSection(writerSizes.idsDefs, "ids defs");
+
+        contentsOut = dexOut.getTableOfContents();
+        contentsOut.dataOff = dexOut.getLength();
+
+        contentsOut.mapList.off = dexOut.getLength();
+        contentsOut.mapList.size = 1;
+        mapListOut = dexOut.appendSection(writerSizes.mapList, "map list");
+
+        contentsOut.typeLists.off = dexOut.getLength();
+        typeListOut = dexOut.appendSection(writerSizes.typeList, "type list");
+
+        contentsOut.annotationSetRefLists.off = dexOut.getLength();
+        annotationSetRefListOut = dexOut.appendSection(
+                writerSizes.annotationsSetRefList, "annotation set ref list");
+
+        contentsOut.annotationSets.off = dexOut.getLength();
+        annotationSetOut = dexOut.appendSection(writerSizes.annotationsSet, "annotation sets");
+
+        contentsOut.classDatas.off = dexOut.getLength();
+        classDataOut = dexOut.appendSection(writerSizes.classData, "class data");
+
+        contentsOut.codes.off = dexOut.getLength();
+        codeOut = dexOut.appendSection(writerSizes.code, "code");
+
+        contentsOut.stringDatas.off = dexOut.getLength();
+        stringDataOut = dexOut.appendSection(writerSizes.stringData, "string data");
+
+        contentsOut.debugInfos.off = dexOut.getLength();
+        debugInfoOut = dexOut.appendSection(writerSizes.debugInfo, "debug info");
+
+        contentsOut.annotations.off = dexOut.getLength();
+        annotationOut = dexOut.appendSection(writerSizes.annotation, "annotation");
+
+        contentsOut.encodedArrays.off = dexOut.getLength();
+        encodedArrayOut = dexOut.appendSection(writerSizes.encodedArray, "encoded array");
+
+        contentsOut.annotationsDirectories.off = dexOut.getLength();
+        annotationsDirectoryOut = dexOut.appendSection(
+                writerSizes.annotationsDirectory, "annotations directory");
+
+        dexOut.noMoreSections();
+        contentsOut.dataSize = dexOut.getLength() - contentsOut.dataOff;
+    }
+
+    public void setCompactWasteThreshold(int compactWasteThreshold) {
+        this.compactWasteThreshold = compactWasteThreshold;
+    }
+
+    private DexBuffer mergeDexBuffers() throws IOException {
+        mergeStringIds();
+        mergeTypeIds();
+        mergeTypeLists();
+        mergeProtoIds();
+        mergeFieldIds();
+        mergeMethodIds();
+        mergeAnnotations();
+        unionAnnotationSetsAndDirectories();
+        mergeClassDefs();
+
+        // write the header
+        contentsOut.header.off = 0;
+        contentsOut.header.size = 1;
+        contentsOut.fileSize = dexOut.getLength();
+        contentsOut.computeSizesFromOffsets();
+        contentsOut.writeHeader(headerOut);
+        contentsOut.writeMap(mapListOut);
+
+        // generate and write the hashes
+        new DexHasher().writeHashes(dexOut);
+
+        return dexOut;
+    }
+
+    public DexBuffer merge() throws IOException {
+        long start = System.nanoTime();
+        DexBuffer result = mergeDexBuffers();
+
+        /*
+         * We use pessimistic sizes when merging dex files. If those sizes
+         * result in too many bytes wasted, compact the result. To compact,
+         * simply merge the result with itself.
+         */
+        WriterSizes compactedSizes = writerSizes.clone();
+        compactedSizes.minusWaste(this);
+        int wastedByteCount = writerSizes.size() - compactedSizes.size();
+        if (wastedByteCount >  + compactWasteThreshold) {
+            DexMerger compacter = new DexMerger(
+                    dexOut, new DexBuffer(), CollisionPolicy.FAIL, compactedSizes);
+            result = compacter.mergeDexBuffers();
+            System.out.printf("Result compacted from %.1fKiB to %.1fKiB to save %.1fKiB%n",
+                    dexOut.getLength() / 1024f,
+                    result.getLength() / 1024f,
+                    wastedByteCount / 1024f);
+        }
+
+        long elapsed = System.nanoTime() - start;
+        System.out.printf("Merged dex A (%d defs/%.1fKiB) with dex B "
+                + "(%d defs/%.1fKiB). Result is %d defs/%.1fKiB. Took %.1fs%n",
+                dexA.getTableOfContents().classDefs.size,
+                dexA.getLength() / 1024f,
+                dexB.getTableOfContents().classDefs.size,
+                dexB.getLength() / 1024f,
+                result.getTableOfContents().classDefs.size,
+                result.getLength() / 1024f,
+                elapsed / 1000000000f);
+
+        return result;
+    }
+
+    /**
+     * Reads an IDs section of two dex files and writes an IDs section of a
+     * merged dex file. Populates maps from old to new indices in the process.
+     */
+    abstract class IdMerger<T extends Comparable<T>> {
+        private final DexBuffer.Section out;
+
+        protected IdMerger(DexBuffer.Section out) {
+            this.out = out;
+        }
+
+        /**
+         * Merges already-sorted sections, reading only two values into memory
+         * at a time.
+         */
+        public final void mergeSorted() {
+            TableOfContents.Section aSection = getSection(dexA.getTableOfContents());
+            TableOfContents.Section bSection = getSection(dexB.getTableOfContents());
+            getSection(contentsOut).off = out.getPosition();
+
+            DexBuffer.Section inA = aSection.exists() ? dexA.open(aSection.off) : null;
+            DexBuffer.Section inB = bSection.exists() ? dexB.open(bSection.off) : null;
+            int aOffset = -1;
+            int bOffset = -1;
+            int aIndex = 0;
+            int bIndex = 0;
+            int outCount = 0;
+            T a = null;
+            T b = null;
+
+            while (true) {
+                if (a == null && aIndex < aSection.size) {
+                    aOffset = inA.getPosition();
+                    a = read(inA, aIndexMap, aIndex);
+                }
+                if (b == null && bIndex < bSection.size) {
+                    bOffset = inB.getPosition();
+                    b = read(inB, bIndexMap, bIndex);
+                }
+
+                // Write the smaller of a and b. If they're equal, write only once
+                boolean advanceA;
+                boolean advanceB;
+                if (a != null && b != null) {
+                    int compare = a.compareTo(b);
+                    advanceA = compare <= 0;
+                    advanceB = compare >= 0;
+                } else {
+                    advanceA = (a != null);
+                    advanceB = (b != null);
+                }
+
+                T toWrite = null;
+                if (advanceA) {
+                    toWrite = a;
+                    updateIndex(aOffset, aIndexMap, aIndex++, outCount);
+                    a = null;
+                    aOffset = -1;
+                }
+                if (advanceB) {
+                    toWrite = b;
+                    updateIndex(bOffset, bIndexMap, bIndex++, outCount);
+                    b = null;
+                    bOffset = -1;
+                }
+                if (toWrite == null) {
+                    break; // advanceA == false && advanceB == false
+                }
+                write(toWrite);
+                outCount++;
+            }
+
+            getSection(contentsOut).size = outCount;
+        }
+
+        /**
+         * Merges unsorted sections by reading them completely into memory and
+         * sorting in memory.
+         */
+        public final void mergeUnsorted() {
+            getSection(contentsOut).off = out.getPosition();
+
+            List<UnsortedValue> all = new ArrayList<UnsortedValue>();
+            all.addAll(readUnsortedValues(dexA, aIndexMap));
+            all.addAll(readUnsortedValues(dexB, bIndexMap));
+            Collections.sort(all);
+
+            int outCount = 0;
+            for (int i = 0; i < all.size(); ) {
+                UnsortedValue e1 = all.get(i++);
+                updateIndex(e1.offset, getIndexMap(e1.source), e1.index, outCount - 1);
+
+                while (i < all.size() && e1.compareTo(all.get(i)) == 0) {
+                    UnsortedValue e2 = all.get(i++);
+                    updateIndex(e2.offset, getIndexMap(e2.source), e2.index, outCount - 1);
+                }
+
+                write(e1.value);
+                outCount++;
+            }
+
+            getSection(contentsOut).size = outCount;
+        }
+
+        private List<UnsortedValue> readUnsortedValues(DexBuffer source, IndexMap indexMap) {
+            TableOfContents.Section section = getSection(source.getTableOfContents());
+            if (!section.exists()) {
+                return Collections.emptyList();
+            }
+
+            List<UnsortedValue> result = new ArrayList<UnsortedValue>();
+            DexBuffer.Section in = source.open(section.off);
+            for (int i = 0; i < section.size; i++) {
+                int offset = in.getPosition();
+                T value = read(in, indexMap, 0);
+                result.add(new UnsortedValue(source, indexMap, value, i, offset));
+            }
+            return result;
+        }
+
+        abstract TableOfContents.Section getSection(TableOfContents tableOfContents);
+        abstract T read(DexBuffer.Section in, IndexMap indexMap, int index);
+        abstract void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex);
+        abstract void write(T value);
+
+        class UnsortedValue implements Comparable<UnsortedValue> {
+            final DexBuffer source;
+            final IndexMap indexMap;
+            final T value;
+            final int index;
+            final int offset;
+
+            UnsortedValue(DexBuffer source, IndexMap indexMap, T value, int index, int offset) {
+                this.source = source;
+                this.indexMap = indexMap;
+                this.value = value;
+                this.index = index;
+                this.offset = offset;
+            }
+
+            public int compareTo(UnsortedValue unsortedValue) {
+                return value.compareTo(unsortedValue.value);
+            }
+        }
+    }
+
+    private IndexMap getIndexMap(DexBuffer dexBuffer) {
+        if (dexBuffer == dexA) {
+            return aIndexMap;
+        } else if (dexBuffer == dexB) {
+            return bIndexMap;
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private void mergeStringIds() {
+        new IdMerger<String>(idsDefsOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.stringIds;
+            }
+
+            @Override String read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                return in.readString();
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.stringIds[oldIndex] = newIndex;
+            }
+
+            @Override void write(String value) {
+                contentsOut.stringDatas.size++;
+                idsDefsOut.writeInt(stringDataOut.getPosition());
+                stringDataOut.writeStringData(value);
+            }
+        }.mergeSorted();
+    }
+
+    private void mergeTypeIds() {
+        new IdMerger<Integer>(idsDefsOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.typeIds;
+            }
+
+            @Override Integer read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                int stringIndex = in.readInt();
+                return indexMap.adjustString(stringIndex);
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.typeIds[oldIndex] = (short) newIndex;
+            }
+
+            @Override void write(Integer value) {
+                idsDefsOut.writeInt(value);
+            }
+        }.mergeSorted();
+    }
+
+    private void mergeTypeLists() {
+        new IdMerger<TypeList>(typeListOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.typeLists;
+            }
+
+            @Override TypeList read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                return indexMap.adjustTypeList(in.readTypeList());
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.putTypeListOffset(offset, typeListOut.getPosition());
+            }
+
+            @Override void write(TypeList value) {
+                typeListOut.writeTypeList(value);
+            }
+        }.mergeUnsorted();
+    }
+
+    private void mergeProtoIds() {
+        new IdMerger<ProtoId>(idsDefsOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.protoIds;
+            }
+
+            @Override ProtoId read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                return indexMap.adjust(in.readProtoId());
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.protoIds[oldIndex] = (short) newIndex;
+            }
+
+            @Override void write(ProtoId value) {
+                value.writeTo(idsDefsOut);
+            }
+        }.mergeSorted();
+    }
+
+    private void mergeFieldIds() {
+        new IdMerger<FieldId>(idsDefsOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.fieldIds;
+            }
+
+            @Override FieldId read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                return indexMap.adjust(in.readFieldId());
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.fieldIds[oldIndex] = (short) newIndex;
+            }
+
+            @Override void write(FieldId value) {
+                value.writeTo(idsDefsOut);
+            }
+        }.mergeSorted();
+    }
+
+    private void mergeMethodIds() {
+        new IdMerger<MethodId>(idsDefsOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.methodIds;
+            }
+
+            @Override MethodId read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                return indexMap.adjust(in.readMethodId());
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.methodIds[oldIndex] = (short) newIndex;
+            }
+
+            @Override void write(MethodId methodId) {
+                methodId.writeTo(idsDefsOut);
+            }
+        }.mergeSorted();
+    }
+
+    private void mergeAnnotations() {
+        new IdMerger<Annotation>(annotationOut) {
+            @Override TableOfContents.Section getSection(TableOfContents tableOfContents) {
+                return tableOfContents.annotations;
+            }
+
+            @Override Annotation read(DexBuffer.Section in, IndexMap indexMap, int index) {
+                return indexMap.adjust(in.readAnnotation());
+            }
+
+            @Override void updateIndex(int offset, IndexMap indexMap, int oldIndex, int newIndex) {
+                indexMap.putAnnotationOffset(offset, annotationOut.getPosition());
+            }
+
+            @Override void write(Annotation value) {
+                value.writeTo(annotationOut);
+            }
+        }.mergeUnsorted();
+    }
+
+    private void mergeClassDefs() {
+        SortableType[] types = getSortedTypes();
+        contentsOut.classDefs.off = idsDefsOut.getPosition();
+        contentsOut.classDefs.size = types.length;
+
+        for (SortableType type : types) {
+            DexBuffer in = type.getBuffer();
+            IndexMap indexMap = (in == dexA) ? aIndexMap : bIndexMap;
+            transformClassDef(in, type.getClassDef(), indexMap);
+        }
+    }
+
+    /**
+     * Returns the union of classes from both files, sorted in order such that
+     * a class is always preceded by its supertype and implemented interfaces.
+     */
+    private SortableType[] getSortedTypes() {
+        // size is pessimistic; doesn't include arrays
+        SortableType[] sortableTypes = new SortableType[contentsOut.typeIds.size];
+        readSortableTypes(sortableTypes, dexA, aIndexMap);
+        readSortableTypes(sortableTypes, dexB, bIndexMap);
+
+        /*
+         * Populate the depths of each sortable type. This makes D iterations
+         * through all N types, where 'D' is the depth of the deepest type. For
+         * example, the deepest class in libcore is Xalan's KeyIterator, which
+         * is 11 types deep.
+         */
+        while (true) {
+            boolean allDone = true;
+            for (SortableType sortableType : sortableTypes) {
+                if (sortableType != null && !sortableType.isDepthAssigned()) {
+                    allDone &= sortableType.tryAssignDepth(sortableTypes);
+                }
+            }
+            if (allDone) {
+                break;
+            }
+        }
+
+        // Now that all types have depth information, the result can be sorted
+        Arrays.sort(sortableTypes, SortableType.NULLS_LAST_ORDER);
+
+        // Strip nulls from the end
+        int firstNull = Arrays.asList(sortableTypes).indexOf(null);
+        return firstNull != -1
+                ? Arrays.copyOfRange(sortableTypes, 0, firstNull)
+                : sortableTypes;
+    }
+
+    /**
+     * Reads just enough data on each class so that we can sort it and then find
+     * it later.
+     */
+    private void readSortableTypes(SortableType[] sortableTypes, DexBuffer buffer,
+            IndexMap indexMap) {
+        for (ClassDef classDef : buffer.classDefs()) {
+            SortableType sortableType = indexMap.adjust(new SortableType(buffer, classDef));
+            int t = sortableType.getTypeIndex();
+            if (sortableTypes[t] == null) {
+                sortableTypes[t] = sortableType;
+            } else if (collisionPolicy != CollisionPolicy.KEEP_FIRST) {
+                throw new DexException("Multiple dex files define "
+                        + buffer.typeNames().get(classDef.getTypeIndex()));
+            }
+        }
+    }
+
+    /**
+     * Copy annotation sets from each input to the output.
+     *
+     * TODO: this may write multiple copies of the same annotation set.
+     * We should shrink the output by merging rather than unioning
+     */
+    private void unionAnnotationSetsAndDirectories() {
+        transformAnnotationSets(dexA, aIndexMap);
+        transformAnnotationSets(dexB, bIndexMap);
+        transformAnnotationDirectories(dexA, aIndexMap);
+        transformAnnotationDirectories(dexB, bIndexMap);
+    }
+
+    private void transformAnnotationSets(DexBuffer in, IndexMap indexMap) {
+        TableOfContents.Section section = in.getTableOfContents().annotationSets;
+        if (section.exists()) {
+            DexBuffer.Section setIn = in.open(section.off);
+            for (int i = 0; i < section.size; i++) {
+                transformAnnotationSet(indexMap, setIn);
+            }
+        }
+    }
+
+    private void transformAnnotationDirectories(DexBuffer in, IndexMap indexMap) {
+        TableOfContents.Section section = in.getTableOfContents().annotationsDirectories;
+        if (section.exists()) {
+            DexBuffer.Section directoryIn = in.open(section.off);
+            for (int i = 0; i < section.size; i++) {
+                transformAnnotationDirectory(in, directoryIn, indexMap);
+            }
+        }
+    }
+
+    /**
+     * Reads a class_def_item beginning at {@code in} and writes the index and
+     * data.
+     */
+    private void transformClassDef(DexBuffer in, ClassDef classDef, IndexMap indexMap) {
+        idsDefsOut.assertFourByteAligned();
+        idsDefsOut.writeInt(classDef.getTypeIndex());
+        idsDefsOut.writeInt(classDef.getAccessFlags());
+        idsDefsOut.writeInt(classDef.getSupertypeIndex());
+        idsDefsOut.writeInt(classDef.getInterfacesOffset());
+
+        int sourceFileIndex = indexMap.adjustString(classDef.getSourceFileIndex());
+        idsDefsOut.writeInt(sourceFileIndex);
+
+        int annotationsOff = classDef.getAnnotationsOffset();
+        idsDefsOut.writeInt(indexMap.adjustAnnotationDirectory(annotationsOff));
+
+        int classDataOff = classDef.getClassDataOffset();
+        if (classDataOff == 0) {
+            idsDefsOut.writeInt(0);
+        } else {
+            idsDefsOut.writeInt(classDataOut.getPosition());
+            ClassData classData = in.readClassData(classDef);
+            transformClassData(in, classData, indexMap);
+        }
+
+        int staticValuesOff = classDef.getStaticValuesOffset();
+        if (staticValuesOff == 0) {
+            idsDefsOut.writeInt(0);
+        } else {
+            DexBuffer.Section staticValuesIn = in.open(staticValuesOff);
+            idsDefsOut.writeInt(encodedArrayOut.getPosition());
+            transformStaticValues(staticValuesIn, indexMap);
+        }
+    }
+
+    /**
+     * Transform all annotations on a class.
+     */
+    private void transformAnnotationDirectory(
+            DexBuffer in, DexBuffer.Section directoryIn, IndexMap indexMap) {
+        contentsOut.annotationsDirectories.size++;
+        annotationsDirectoryOut.assertFourByteAligned();
+        indexMap.putAnnotationDirectoryOffset(
+                directoryIn.getPosition(), annotationsDirectoryOut.getPosition());
+
+        int classAnnotationsOffset = indexMap.adjustAnnotationSet(directoryIn.readInt());
+        annotationsDirectoryOut.writeInt(classAnnotationsOffset);
+
+        int fieldsSize = directoryIn.readInt();
+        annotationsDirectoryOut.writeInt(fieldsSize);
+
+        int methodsSize = directoryIn.readInt();
+        annotationsDirectoryOut.writeInt(methodsSize);
+
+        int parameterListSize = directoryIn.readInt();
+        annotationsDirectoryOut.writeInt(parameterListSize);
+
+        for (int i = 0; i < fieldsSize; i++) {
+            // field index
+            annotationsDirectoryOut.writeInt(indexMap.adjustField(directoryIn.readInt()));
+
+            // annotations offset
+            annotationsDirectoryOut.writeInt(indexMap.adjustAnnotationSet(directoryIn.readInt()));
+        }
+
+        for (int i = 0; i < methodsSize; i++) {
+            // method index
+            annotationsDirectoryOut.writeInt(indexMap.adjustMethod(directoryIn.readInt()));
+
+            // annotation set offset
+            annotationsDirectoryOut.writeInt(
+                    indexMap.adjustAnnotationSet(directoryIn.readInt()));
+        }
+
+        for (int i = 0; i < parameterListSize; i++) {
+            contentsOut.annotationSetRefLists.size++;
+            annotationSetRefListOut.assertFourByteAligned();
+
+            // method index
+            annotationsDirectoryOut.writeInt(indexMap.adjustMethod(directoryIn.readInt()));
+
+            // annotations offset
+            annotationsDirectoryOut.writeInt(annotationSetRefListOut.getPosition());
+            DexBuffer.Section refListIn = in.open(directoryIn.readInt());
+
+            // parameters
+            int parameterCount = refListIn.readInt();
+            annotationSetRefListOut.writeInt(parameterCount);
+            for (int p = 0; p < parameterCount; p++) {
+                annotationSetRefListOut.writeInt(indexMap.adjustAnnotationSet(refListIn.readInt()));
+            }
+        }
+    }
+
+    /**
+     * Transform all annotations on a single type, member or parameter.
+     */
+    private void transformAnnotationSet(IndexMap indexMap, DexBuffer.Section setIn) {
+        contentsOut.annotationSets.size++;
+        annotationSetOut.assertFourByteAligned();
+        indexMap.putAnnotationSetOffset(setIn.getPosition(), annotationSetOut.getPosition());
+
+        int size = setIn.readInt();
+        annotationSetOut.writeInt(size);
+
+        for (int j = 0; j < size; j++) {
+            annotationSetOut.writeInt(indexMap.adjustAnnotation(setIn.readInt()));
+        }
+    }
+
+    private void transformClassData(DexBuffer in, ClassData classData, IndexMap indexMap) {
+        contentsOut.classDatas.size++;
+
+        ClassData.Field[] staticFields = classData.getStaticFields();
+        ClassData.Field[] instanceFields = classData.getInstanceFields();
+        ClassData.Method[] directMethods = classData.getDirectMethods();
+        ClassData.Method[] virtualMethods = classData.getVirtualMethods();
+
+        classDataOut.writeUleb128(staticFields.length);
+        classDataOut.writeUleb128(instanceFields.length);
+        classDataOut.writeUleb128(directMethods.length);
+        classDataOut.writeUleb128(virtualMethods.length);
+
+        transformFields(indexMap, staticFields);
+        transformFields(indexMap, instanceFields);
+        transformMethods(in, indexMap, directMethods);
+        transformMethods(in, indexMap, virtualMethods);
+    }
+
+    private void transformFields(IndexMap indexMap, ClassData.Field[] fields) {
+        int lastOutFieldIndex = 0;
+        for (ClassData.Field field : fields) {
+            int outFieldIndex = indexMap.adjustField(field.getFieldIndex());
+            classDataOut.writeUleb128(outFieldIndex - lastOutFieldIndex);
+            lastOutFieldIndex = outFieldIndex;
+            classDataOut.writeUleb128(field.getAccessFlags());
+        }
+    }
+
+    private void transformMethods(DexBuffer in, IndexMap indexMap, ClassData.Method[] methods) {
+        int lastOutMethodIndex = 0;
+        for (ClassData.Method method : methods) {
+            int outMethodIndex = indexMap.adjustMethod(method.getMethodIndex());
+            classDataOut.writeUleb128(outMethodIndex - lastOutMethodIndex);
+            lastOutMethodIndex = outMethodIndex;
+
+            classDataOut.writeUleb128(method.getAccessFlags());
+
+            if (method.getCodeOffset() == 0) {
+                classDataOut.writeUleb128(0);
+            } else {
+                codeOut.alignToFourBytes();
+                classDataOut.writeUleb128(codeOut.getPosition());
+                transformCode(in, in.readCode(method), indexMap);
+            }
+        }
+    }
+
+    private void transformCode(DexBuffer in, Code code, IndexMap indexMap) {
+        contentsOut.codes.size++;
+        codeOut.assertFourByteAligned();
+
+        codeOut.writeUnsignedShort(code.getRegistersSize());
+        codeOut.writeUnsignedShort(code.getInsSize());
+        codeOut.writeUnsignedShort(code.getOutsSize());
+
+        Code.Try[] tries = code.getTries();
+        codeOut.writeUnsignedShort(tries.length);
+
+        // TODO: retain debug info
+        // code.getDebugInfoOffset();
+        codeOut.writeInt(0);
+
+        short[] instructions = code.getInstructions();
+        InstructionTransformer transformer = (in == dexA)
+                ? aInstructionTransformer
+                : bInstructionTransformer;
+        short[] newInstructions = transformer.transform(instructions);
+        codeOut.writeInt(newInstructions.length);
+        codeOut.write(newInstructions);
+
+        if (tries.length > 0) {
+            if (newInstructions.length % 2 == 1) {
+                codeOut.writeShort((short) 0); // padding
+            }
+            for (Code.Try tryItem : tries) {
+                codeOut.writeInt(tryItem.getStartAddress());
+                codeOut.writeUnsignedShort(tryItem.getInstructionCount());
+                codeOut.writeUnsignedShort(tryItem.getHandlerOffset());
+            }
+            Code.CatchHandler[] catchHandlers = code.getCatchHandlers();
+            codeOut.writeUleb128(catchHandlers.length);
+            for (Code.CatchHandler catchHandler : catchHandlers) {
+                transformEncodedCatchHandler(catchHandler, indexMap);
+            }
+        }
+    }
+
+    private void transformEncodedCatchHandler(Code.CatchHandler catchHandler, IndexMap indexMap) {
+        int catchAllAddress = catchHandler.getCatchAllAddress();
+        int[] typeIndexes = catchHandler.getTypeIndexes();
+        int[] addresses = catchHandler.getAddresses();
+
+        if (catchAllAddress != -1) {
+            codeOut.writeSleb128(-typeIndexes.length);
+        } else {
+            codeOut.writeSleb128(typeIndexes.length);
+        }
+
+        for (int i = 0; i < typeIndexes.length; i++) {
+            codeOut.writeUleb128(indexMap.adjustType(typeIndexes[i]));
+            codeOut.writeUleb128(addresses[i]);
+        }
+
+        if (catchAllAddress != -1) {
+            codeOut.writeUleb128(catchAllAddress);
+        }
+    }
+
+    private void transformStaticValues(DexBuffer.Section in, IndexMap indexMap) {
+        contentsOut.encodedArrays.size++;
+        indexMap.adjustEncodedArray(in.readEncodedArray()).writeTo(encodedArrayOut);
+    }
+
+    /**
+     * Byte counts for the sections written when creating a dex. Target sizes
+     * are defined in one of two ways:
+     * <ul>
+     * <li>By pessimistically guessing how large the union of dex files will be.
+     *     We're pessimistic because we can't predict the amount of duplication
+     *     between dex files, nor can we predict the length of ULEB-encoded
+     *     offsets or indices.
+     * <li>By exactly measuring an existing dex.
+     * </ul>
+     */
+    private static class WriterSizes implements Cloneable {
+        private int header = SizeOf.HEADER_ITEM;
+        private int idsDefs;
+        private int mapList;
+        private int typeList;
+        private int classData;
+        private int code;
+        private int stringData;
+        private int debugInfo;
+        private int encodedArray;
+        private int annotationsDirectory;
+        private int annotationsSet;
+        private int annotationsSetRefList;
+        private int annotation;
+
+        /**
+         * Compute sizes for merging a and b.
+         */
+        public WriterSizes(DexBuffer a, DexBuffer b) {
+            plus(a.getTableOfContents(), false);
+            plus(b.getTableOfContents(), false);
+        }
+
+        @Override public WriterSizes clone() {
+            try {
+                return (WriterSizes) super.clone();
+            } catch (CloneNotSupportedException e) {
+                throw new AssertionError();
+            }
+        }
+
+        public void plus(TableOfContents contents, boolean exact) {
+            idsDefs += contents.stringIds.size * SizeOf.STRING_ID_ITEM
+                    + contents.typeIds.size * SizeOf.TYPE_ID_ITEM
+                    + contents.protoIds.size * SizeOf.PROTO_ID_ITEM
+                    + contents.fieldIds.size * SizeOf.MEMBER_ID_ITEM
+                    + contents.methodIds.size * SizeOf.MEMBER_ID_ITEM
+                    + contents.classDefs.size * SizeOf.CLASS_DEF_ITEM;
+            mapList = SizeOf.UINT + (contents.sections.length * SizeOf.MAP_ITEM);
+            typeList += contents.typeLists.byteCount;
+            stringData += contents.stringDatas.byteCount;
+            debugInfo += contents.debugInfos.byteCount;
+            annotationsDirectory += contents.annotationsDirectories.byteCount;
+            annotationsSet += contents.annotationSets.byteCount;
+            annotationsSetRefList += contents.annotationSetRefLists.byteCount;
+
+            if (exact) {
+                code += contents.codes.byteCount;
+                classData += contents.classDatas.byteCount;
+                encodedArray += contents.encodedArrays.byteCount;
+                annotation += contents.annotations.byteCount;
+            } else {
+                // at most 1/4 of the bytes in a code section are uleb/sleb
+                code += (int) Math.ceil(contents.codes.byteCount * 1.25);
+                // at most 1/3 of the bytes in a class data section are uleb/sleb
+                classData += (int) Math.ceil(contents.classDatas.byteCount * 1.34);
+                // all of the bytes in an encoding arrays section may be uleb/sleb
+                encodedArray += contents.encodedArrays.byteCount * 2;
+                // at most 1/3 of the bytes in an encoding arrays section are uleb/sleb
+                annotation += (int) Math.ceil(contents.annotations.byteCount * 1.34);
+            }
+        }
+
+        public void minusWaste(DexMerger dexMerger) {
+            header -= dexMerger.headerOut.remaining();
+            idsDefs -= dexMerger.idsDefsOut.remaining();
+            mapList -= dexMerger.mapListOut.remaining();
+            typeList -= dexMerger.typeListOut.remaining();
+            classData -= dexMerger.classDataOut.remaining();
+            code -= dexMerger.codeOut.remaining();
+            stringData -= dexMerger.stringDataOut.remaining();
+            debugInfo -= dexMerger.debugInfoOut.remaining();
+            encodedArray -= dexMerger.encodedArrayOut.remaining();
+            annotationsDirectory -= dexMerger.annotationsDirectoryOut.remaining();
+            annotationsSet -= dexMerger.annotationSetOut.remaining();
+            annotationsSetRefList -= dexMerger.annotationSetRefListOut.remaining();
+            annotation -= dexMerger.annotationOut.remaining();
+        }
+
+        public int size() {
+            return header + idsDefs + mapList + typeList + classData + code + stringData + debugInfo
+                    + encodedArray + annotationsDirectory + annotationsSet + annotationsSetRefList
+                    + annotation;
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        if (args.length != 3) {
+            printUsage();
+            return;
+        }
+
+        DexBuffer dexA = new DexBuffer(new File(args[1]));
+        DexBuffer dexB = new DexBuffer(new File(args[2]));
+        DexBuffer merged = new DexMerger(dexA, dexB, CollisionPolicy.KEEP_FIRST).merge();
+        merged.writeTo(new File(args[0]));
+    }
+
+    private static void printUsage() {
+        System.out.println("Usage: DexMerger <out.dex> <a.dex> <b.dex>");
+        System.out.println();
+        System.out.println("If both a and b define the same classes, a's copy will be used.");
+    }
+}
diff --git a/dx/src/com/android/dx/merge/IndexMap.java b/dx/src/com/android/dx/merge/IndexMap.java
new file mode 100644
index 0000000..a7b20be
--- /dev/null
+++ b/dx/src/com/android/dx/merge/IndexMap.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.dex.TableOfContents;
+import com.android.dx.io.Annotation;
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.DexBuffer;
+import com.android.dx.io.EncodedValue;
+import com.android.dx.io.EncodedValueReader;
+import com.android.dx.io.FieldId;
+import com.android.dx.io.MethodId;
+import com.android.dx.io.ProtoId;
+import com.android.dx.util.ByteArrayAnnotatedOutput;
+import com.android.dx.util.ByteInput;
+import com.android.dx.util.ByteOutput;
+import com.android.dx.util.Leb128Utils;
+import com.android.dx.util.Unsigned;
+import java.util.HashMap;
+
+/**
+ * Maps the index offsets from one dex file to those in another. For example, if
+ * you have string #5 in the old dex file, its position in the new dex file is
+ * {@code strings[5]}.
+ */
+public final class IndexMap {
+    private final DexBuffer target;
+    public final int[] stringIds;
+    public final short[] typeIds;
+    public final short[] protoIds;
+    public final short[] fieldIds;
+    public final short[] methodIds;
+    private final HashMap<Integer, Integer> typeListOffsets;
+    private final HashMap<Integer, Integer> annotationOffsets;
+    private final HashMap<Integer, Integer> annotationSetOffsets;
+    private final HashMap<Integer, Integer> annotationDirectoryOffsets;
+
+    public IndexMap(DexBuffer target, TableOfContents tableOfContents) {
+        this.target = target;
+        this.stringIds = new int[tableOfContents.stringIds.size];
+        this.typeIds = new short[tableOfContents.typeIds.size];
+        this.protoIds = new short[tableOfContents.protoIds.size];
+        this.fieldIds = new short[tableOfContents.fieldIds.size];
+        this.methodIds = new short[tableOfContents.methodIds.size];
+        this.typeListOffsets = new HashMap<Integer, Integer>();
+        this.annotationOffsets = new HashMap<Integer, Integer>();
+        this.annotationSetOffsets = new HashMap<Integer, Integer>();
+        this.annotationDirectoryOffsets = new HashMap<Integer, Integer>();
+
+        /*
+         * A type list, annotation set, or annotation directory at offset 0 is
+         * always empty. Always map offset 0 to 0.
+         */
+        this.typeListOffsets.put(0, 0);
+        this.annotationSetOffsets.put(0, 0);
+        this.annotationDirectoryOffsets.put(0, 0);
+    }
+
+    public void putTypeListOffset(int oldOffset, int newOffset) {
+        if (oldOffset <= 0 || newOffset <= 0) {
+            throw new IllegalArgumentException();
+        }
+        typeListOffsets.put(oldOffset, newOffset);
+    }
+
+    public void putAnnotationOffset(int oldOffset, int newOffset) {
+        if (oldOffset <= 0 || newOffset <= 0) {
+            throw new IllegalArgumentException();
+        }
+        annotationOffsets.put(oldOffset, newOffset);
+    }
+
+    public void putAnnotationSetOffset(int oldOffset, int newOffset) {
+        if (oldOffset <= 0 || newOffset <= 0) {
+            throw new IllegalArgumentException();
+        }
+        annotationSetOffsets.put(oldOffset, newOffset);
+    }
+
+    public void putAnnotationDirectoryOffset(int oldOffset, int newOffset) {
+        if (oldOffset <= 0 || newOffset <= 0) {
+            throw new IllegalArgumentException();
+        }
+        annotationDirectoryOffsets.put(oldOffset, newOffset);
+    }
+
+    public int adjustString(int stringIndex) {
+        return stringIndex == ClassDef.NO_INDEX ? ClassDef.NO_INDEX : stringIds[stringIndex];
+    }
+
+    public int adjustType(int typeIndex) {
+        return (typeIndex == ClassDef.NO_INDEX) ? ClassDef.NO_INDEX : (typeIds[typeIndex] & 0xffff);
+    }
+
+    public TypeList adjustTypeList(TypeList typeList) {
+        if (typeList == TypeList.EMPTY) {
+            return typeList;
+        }
+        short[] types = typeList.getTypes().clone();
+        for (int i = 0; i < types.length; i++) {
+            types[i] = (short) adjustType(types[i]);
+        }
+        return new TypeList(target, types);
+    }
+
+    public int adjustProto(int protoIndex) {
+        return protoIds[protoIndex] & 0xffff;
+    }
+
+    public int adjustField(int fieldIndex) {
+        return fieldIds[fieldIndex] & 0xffff;
+    }
+
+    public int adjustMethod(int methodIndex) {
+        return methodIds[methodIndex] & 0xffff;
+    }
+
+    public int adjustTypeListOffset(int typeListOffset) {
+        return typeListOffsets.get(typeListOffset);
+    }
+
+    public int adjustAnnotation(int annotationOffset) {
+        return annotationOffsets.get(annotationOffset);
+    }
+
+    public int adjustAnnotationSet(int annotationSetOffset) {
+        return annotationSetOffsets.get(annotationSetOffset);
+    }
+
+    public int adjustAnnotationDirectory(int annotationDirectoryOffset) {
+        return annotationDirectoryOffsets.get(annotationDirectoryOffset);
+    }
+
+    public MethodId adjust(MethodId methodId) {
+        return new MethodId(target,
+                adjustType(methodId.getDeclaringClassIndex()),
+                adjustProto(methodId.getProtoIndex()),
+                adjustString(methodId.getNameIndex()));
+    }
+
+    public FieldId adjust(FieldId fieldId) {
+        return new FieldId(target,
+                adjustType(fieldId.getDeclaringClassIndex()),
+                adjustType(fieldId.getTypeIndex()),
+                adjustString(fieldId.getNameIndex()));
+
+    }
+
+    public ProtoId adjust(ProtoId protoId) {
+        return new ProtoId(target,
+                adjustString(protoId.getShortyIndex()),
+                adjustType(protoId.getReturnTypeIndex()),
+                adjustTypeListOffset(protoId.getParametersOffset()));
+    }
+
+    public ClassDef adjust(ClassDef classDef) {
+        return new ClassDef(target, classDef.getOffset(), adjustType(classDef.getTypeIndex()),
+                classDef.getAccessFlags(), adjustType(classDef.getSupertypeIndex()),
+                adjustTypeListOffset(classDef.getInterfacesOffset()), classDef.getSourceFileIndex(),
+                classDef.getAnnotationsOffset(), classDef.getClassDataOffset(),
+                classDef.getStaticValuesOffset());
+    }
+
+    public SortableType adjust(SortableType sortableType) {
+        return new SortableType(sortableType.getBuffer(), adjust(sortableType.getClassDef()));
+    }
+
+    public EncodedValue adjustEncodedValue(EncodedValue encodedValue) {
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
+        new EncodedValueTransformer(encodedValue, out).readValue();
+        return new EncodedValue(out.toByteArray());
+    }
+
+    public EncodedValue adjustEncodedArray(EncodedValue encodedArray) {
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
+        new EncodedValueTransformer(encodedArray, out).readArray();
+        return new EncodedValue(out.toByteArray());
+    }
+
+    public Annotation adjust(Annotation annotation) {
+        int[] names = annotation.getNames().clone();
+        EncodedValue[] values = annotation.getValues().clone();
+        for (int i = 0; i < names.length; i++) {
+            names[i] = adjustString(names[i]);
+            values[i] = adjustEncodedValue(values[i]);
+        }
+        return new Annotation(target, annotation.getVisibility(),
+                adjustType(annotation.getTypeIndex()), names, values);
+    }
+
+    /**
+     * Adjust an encoded value or array.
+     */
+    private final class EncodedValueTransformer extends EncodedValueReader {
+        private final ByteOutput out;
+
+        public EncodedValueTransformer(EncodedValue encodedValue, ByteOutput out) {
+            super(encodedValue);
+            this.out = out;
+        }
+
+        protected void visitArray(int size) {
+            Leb128Utils.writeUnsignedLeb128(out, size);
+        }
+
+        protected void visitAnnotation(int typeIndex, int size) {
+            Leb128Utils.writeUnsignedLeb128(out, adjustType(typeIndex));
+            Leb128Utils.writeUnsignedLeb128(out, size);
+        }
+
+        protected void visitAnnotationName(int index) {
+            Leb128Utils.writeUnsignedLeb128(out, adjustString(index));
+        }
+
+        protected void visitPrimitive(int argAndType, int type, int arg, int size) {
+            out.writeByte(argAndType);
+            copyBytes(in, out, size);
+        }
+
+        protected void visitString(int type, int index) {
+            writeTypeAndSizeAndIndex(type, adjustString(index));
+        }
+
+        protected void visitType(int type, int index) {
+            writeTypeAndSizeAndIndex(type, adjustType(index));
+        }
+
+        protected void visitField(int type, int index) {
+            writeTypeAndSizeAndIndex(type, adjustField(index));
+        }
+
+        protected void visitMethod(int type, int index) {
+            writeTypeAndSizeAndIndex(type, adjustMethod(index));
+        }
+
+        protected void visitArrayValue(int argAndType) {
+            out.writeByte(argAndType);
+        }
+
+        protected void visitAnnotationValue(int argAndType) {
+            out.writeByte(argAndType);
+        }
+
+        protected void visitEncodedBoolean(int argAndType) {
+            out.writeByte(argAndType);
+        }
+
+        protected void visitEncodedNull(int argAndType) {
+            out.writeByte(argAndType);
+        }
+
+        private void writeTypeAndSizeAndIndex(int type, int index) {
+            int byteCount;
+            if (Unsigned.compare(index, 0xff) <= 0) {
+                byteCount = 1;
+            } else if (Unsigned.compare(index, 0xffff) <= 0) {
+                byteCount = 2;
+            } else if (Unsigned.compare(index, 0xffffff) <= 0) {
+                byteCount = 3;
+            } else {
+                byteCount = 4;
+            }
+            int argAndType = ((byteCount - 1) << 5) | type;
+            out.writeByte(argAndType);
+
+            for (int i = 0; i < byteCount; i++) {
+                out.writeByte(index & 0xff);
+                index >>>= 8;
+            }
+        }
+
+        private void copyBytes(ByteInput in, ByteOutput out, int size) {
+            for (int i = 0; i < size; i++) {
+                out.writeByte(in.readByte());
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/merge/InstructionTransformer.java b/dx/src/com/android/dx/merge/InstructionTransformer.java
new file mode 100644
index 0000000..62c3a49
--- /dev/null
+++ b/dx/src/com/android/dx/merge/InstructionTransformer.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.io.CodeReader;
+import com.android.dx.io.instructions.DecodedInstruction;
+import com.android.dx.io.instructions.ShortArrayCodeOutput;
+import com.android.dx.util.DexException;
+
+final class InstructionTransformer {
+    private final IndexMap indexMap;
+    private final CodeReader reader;
+    private DecodedInstruction[] mappedInstructions;
+    private int mappedAt;
+
+    public InstructionTransformer(IndexMap indexMap) {
+        this.indexMap = indexMap;
+        this.reader = new CodeReader();
+        this.reader.setAllVisitors(new GenericVisitor());
+        this.reader.setStringVisitor(new StringVisitor());
+        this.reader.setTypeVisitor(new TypeVisitor());
+        this.reader.setFieldVisitor(new FieldVisitor());
+        this.reader.setMethodVisitor(new MethodVisitor());
+    }
+
+    public short[] transform(short[] encodedInstructions) throws DexException {
+        DecodedInstruction[] decodedInstructions =
+            DecodedInstruction.decodeAll(encodedInstructions);
+        int size = decodedInstructions.length;
+
+        mappedInstructions = new DecodedInstruction[size];
+        mappedAt = 0;
+        reader.visitAll(decodedInstructions);
+
+        ShortArrayCodeOutput out = new ShortArrayCodeOutput(size);
+        for (DecodedInstruction instruction : mappedInstructions) {
+            if (instruction != null) {
+                instruction.encode(out);
+            }
+        }
+
+        return out.getArray();
+    }
+
+    private class GenericVisitor implements CodeReader.Visitor {
+        public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+            mappedInstructions[mappedAt++] = one;
+        }
+    }
+
+    private class StringVisitor implements CodeReader.Visitor {
+        public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+            int stringId = one.getIndex();
+            int mappedId = indexMap.adjustString(stringId);
+            jumboCheck(stringId, mappedId);
+            mappedInstructions[mappedAt++] = one.withIndex(mappedId);
+        }
+    }
+
+    private class FieldVisitor implements CodeReader.Visitor {
+        public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+            int fieldId = one.getIndex();
+            int mappedId = indexMap.adjustField(fieldId);
+            jumboCheck(fieldId, mappedId);
+            mappedInstructions[mappedAt++] = one.withIndex(mappedId);
+        }
+    }
+
+    private class TypeVisitor implements CodeReader.Visitor {
+        public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+            int typeId = one.getIndex();
+            int mappedId = indexMap.adjustType(typeId);
+            jumboCheck(typeId, mappedId);
+            mappedInstructions[mappedAt++] = one.withIndex(mappedId);
+        }
+    }
+
+    private class MethodVisitor implements CodeReader.Visitor {
+        public void visit(DecodedInstruction[] all, DecodedInstruction one) {
+            int methodId = one.getIndex();
+            int mappedId = indexMap.adjustMethod(methodId);
+            jumboCheck(methodId, mappedId);
+            mappedInstructions[mappedAt++] = one.withIndex(mappedId);
+        }
+    }
+
+    private static void jumboCheck(int oldIndex, int newIndex) {
+        if ((oldIndex <= 0xffff) && (newIndex > 0xffff)) {
+            throw new DexException("Cannot handle conversion to jumbo index!");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/merge/SortableType.java b/dx/src/com/android/dx/merge/SortableType.java
new file mode 100644
index 0000000..838ea28
--- /dev/null
+++ b/dx/src/com/android/dx/merge/SortableType.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.io.ClassDef;
+import com.android.dx.io.DexBuffer;
+import java.util.Comparator;
+
+/**
+ * Name and structure of a type. Used to order types such that each type is
+ * preceded by its supertype and implemented interfaces.
+ */
+final class SortableType {
+    public static final Comparator<SortableType> NULLS_LAST_ORDER = new Comparator<SortableType>() {
+        public int compare(SortableType a, SortableType b) {
+            if (a == b) {
+                return 0;
+            }
+            if (b == null) {
+                return -1;
+            }
+            if (a == null) {
+                return 1;
+            }
+            if (a.depth != b.depth) {
+                return a.depth - b.depth;
+            }
+            return a.getTypeIndex() - b.getTypeIndex();
+        }
+    };
+
+    private final DexBuffer buffer;
+    private ClassDef classDef;
+    private int depth = -1;
+
+    public SortableType(DexBuffer buffer, ClassDef classDef) {
+        this.buffer = buffer;
+        this.classDef = classDef;
+    }
+
+    public DexBuffer getBuffer() {
+        return buffer;
+    }
+
+    public ClassDef getClassDef() {
+        return classDef;
+    }
+
+    public int getTypeIndex() {
+        return classDef.getTypeIndex();
+    }
+
+    /**
+     * Assigns this type's depth if the depths of its supertype and implemented
+     * interfaces are known. Returns false if the depth couldn't be computed
+     * yet.
+     */
+    public boolean tryAssignDepth(SortableType[] types) {
+        int max;
+        if (classDef.getSupertypeIndex() == ClassDef.NO_INDEX) {
+            max = 0; // this is Object.class or an interface
+        } else {
+            SortableType sortableSupertype = types[classDef.getSupertypeIndex()];
+            if (sortableSupertype == null) {
+                max = 1; // unknown, so assume it's a root.
+            } else if (sortableSupertype.depth == -1) {
+                return false;
+            } else {
+                max = sortableSupertype.depth;
+            }
+        }
+
+        for (short interfaceIndex : classDef.getInterfaces()) {
+            SortableType implemented = types[interfaceIndex];
+            if (implemented == null) {
+                max = Math.max(max, 1); // unknown, so assume it's a root.
+            } else if (implemented.depth == -1) {
+                return false;
+            } else {
+                max = Math.max(max, implemented.depth);
+            }
+        }
+
+        depth = max + 1;
+        return true;
+    }
+
+    public boolean isDepthAssigned() {
+        return depth != -1;
+    }
+}
diff --git a/dx/src/com/android/dx/merge/TypeList.java b/dx/src/com/android/dx/merge/TypeList.java
new file mode 100644
index 0000000..62984e2
--- /dev/null
+++ b/dx/src/com/android/dx/merge/TypeList.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.io.DexBuffer;
+import com.android.dx.util.Unsigned;
+import java.util.Arrays;
+
+public final class TypeList implements Comparable<TypeList> {
+
+    public static final TypeList EMPTY = new TypeList(null, new short[0]);
+
+    private final DexBuffer buffer;
+    private final short[] types;
+
+    public TypeList(DexBuffer buffer, short[] types) {
+        this.buffer = buffer;
+        this.types = types;
+    }
+
+    public short[] getTypes() {
+        return types;
+    }
+
+    public int compareTo(TypeList other) {
+        for (int i = 0; i < types.length && i < other.types.length; i++) {
+            if (types[i] != other.types[i]) {
+                return Unsigned.compare(types[i], other.types[i]);
+            }
+        }
+        return Unsigned.compare(types.length, other.types.length);
+    }
+
+    @Override public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("(");
+        for (int i = 0, typesLength = types.length; i < typesLength; i++) {
+            result.append(buffer != null ? buffer.typeNames().get(types[i]) : types[i]);
+        }
+        result.append(")");
+        return result.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/annotation/Annotation.java b/dx/src/com/android/dx/rop/annotation/Annotation.java
new file mode 100644
index 0000000..8f9e976
--- /dev/null
+++ b/dx/src/com/android/dx/rop/annotation/Annotation.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.annotation;
+
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.MutabilityControl;
+import com.android.dx.util.ToHuman;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+/**
+ * An annotation on an element of a class. Annotations have an
+ * associated type and additionally consist of a set of (name, value)
+ * pairs, where the names are unique.
+ */
+public final class Annotation extends MutabilityControl
+        implements Comparable<Annotation>, ToHuman {
+    /** {@code non-null;} type of the annotation */
+    private final CstType type;
+
+    /** {@code non-null;} the visibility of the annotation */
+    private final AnnotationVisibility visibility;
+
+    /** {@code non-null;} map from names to {@link NameValuePair} instances */
+    private final TreeMap<CstString, NameValuePair> elements;
+
+    /**
+     * Construct an instance. It initially contains no elements.
+     *
+     * @param type {@code non-null;} type of the annotation
+     * @param visibility {@code non-null;} the visibility of the annotation
+     */
+    public Annotation(CstType type, AnnotationVisibility visibility) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (visibility == null) {
+            throw new NullPointerException("visibility == null");
+        }
+
+        this.type = type;
+        this.visibility = visibility;
+        this.elements = new TreeMap<CstString, NameValuePair>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof Annotation)) {
+            return false;
+        }
+
+        Annotation otherAnnotation = (Annotation) other;
+
+        if (! (type.equals(otherAnnotation.type)
+                        && (visibility == otherAnnotation.visibility))) {
+            return false;
+        }
+
+        return elements.equals(otherAnnotation.elements);
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        int hash = type.hashCode();
+        hash = (hash * 31) + elements.hashCode();
+        hash = (hash * 31) + visibility.hashCode();
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Annotation other) {
+        int result = type.compareTo(other.type);
+
+        if (result != 0) {
+            return result;
+        }
+
+        result = visibility.compareTo(other.visibility);
+
+        if (result != 0) {
+            return result;
+        }
+
+        Iterator<NameValuePair> thisIter = elements.values().iterator();
+        Iterator<NameValuePair> otherIter = other.elements.values().iterator();
+
+        while (thisIter.hasNext() && otherIter.hasNext()) {
+            NameValuePair thisOne = thisIter.next();
+            NameValuePair otherOne = otherIter.next();
+
+            result = thisOne.compareTo(otherOne);
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (thisIter.hasNext()) {
+            return 1;
+        } else if (otherIter.hasNext()) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toHuman();
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(visibility.toHuman());
+        sb.append("-annotation ");
+        sb.append(type.toHuman());
+        sb.append(" {");
+
+        boolean first = true;
+        for (NameValuePair pair : elements.values()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(pair.getName().toHuman());
+            sb.append(": ");
+            sb.append(pair.getValue().toHuman());
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Gets the type of this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public CstType getType() {
+        return type;
+    }
+
+    /**
+     * Gets the visibility of this instance.
+     *
+     * @return {@code non-null;} the visibility
+     */
+    public AnnotationVisibility getVisibility() {
+        return visibility;
+    }
+
+    /**
+     * Put an element into the set of (name, value) pairs for this instance.
+     * If there is a preexisting element with the same name, it will be
+     * replaced by this method.
+     *
+     * @param pair {@code non-null;} the (name, value) pair to place into this instance
+     */
+    public void put(NameValuePair pair) {
+        throwIfImmutable();
+
+        if (pair == null) {
+            throw new NullPointerException("pair == null");
+        }
+
+        elements.put(pair.getName(), pair);
+    }
+
+    /**
+     * Add an element to the set of (name, value) pairs for this instance.
+     * It is an error to call this method if there is a preexisting element
+     * with the same name.
+     *
+     * @param pair {@code non-null;} the (name, value) pair to add to this instance
+     */
+    public void add(NameValuePair pair) {
+        throwIfImmutable();
+
+        if (pair == null) {
+            throw new NullPointerException("pair == null");
+        }
+
+        CstString name = pair.getName();
+
+        if (elements.get(name) != null) {
+            throw new IllegalArgumentException("name already added: " + name);
+        }
+
+        elements.put(name, pair);
+    }
+
+    /**
+     * Gets the set of name-value pairs contained in this instance. The
+     * result is always unmodifiable.
+     *
+     * @return {@code non-null;} the set of name-value pairs
+     */
+    public Collection<NameValuePair> getNameValuePairs() {
+        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
new file mode 100644
index 0000000..c717b8c
--- /dev/null
+++ b/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.annotation;
+
+import com.android.dx.util.ToHuman;
+
+/**
+ * Visibility scope of an annotation.
+ */
+public enum AnnotationVisibility implements ToHuman {
+    RUNTIME("runtime"),
+    BUILD("build"),
+    SYSTEM("system"),
+    EMBEDDED("embedded");
+
+    /** {@code non-null;} the human-oriented string representation */
+    private final String human;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param human {@code non-null;} the human-oriented string representation
+     */
+    private AnnotationVisibility(String human) {
+        this.human = human;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return human;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/annotation/Annotations.java b/dx/src/com/android/dx/rop/annotation/Annotations.java
new file mode 100644
index 0000000..807d5d4
--- /dev/null
+++ b/dx/src/com/android/dx/rop/annotation/Annotations.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.annotation;
+
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.util.MutabilityControl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+/**
+ * List of {@link Annotation} instances.
+ */
+public final class Annotations extends MutabilityControl
+        implements Comparable<Annotations> {
+    /** {@code non-null;} immutable empty instance */
+    public static final Annotations EMPTY = new Annotations();
+
+    static {
+        EMPTY.setImmutable();
+    }
+
+    /** {@code non-null;} map from types to annotations */
+    private final TreeMap<CstType, Annotation> annotations;
+
+    /**
+     * Constructs an immutable instance which is the combination of the
+     * two given instances. The two instances must contain disjoint sets
+     * of types.
+     *
+     * @param a1 {@code non-null;} an instance
+     * @param a2 {@code non-null;} the other instance
+     * @return {@code non-null;} the combination
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public static Annotations combine(Annotations a1, Annotations a2) {
+        Annotations result = new Annotations();
+
+        result.addAll(a1);
+        result.addAll(a2);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs an immutable instance which is the combination of the
+     * given instance with the given additional annotation. The latter's
+     * type must not already appear in the former.
+     *
+     * @param annotations {@code non-null;} the instance to augment
+     * @param annotation {@code non-null;} the additional annotation
+     * @return {@code non-null;} the combination
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public static Annotations combine(Annotations annotations,
+            Annotation annotation) {
+        Annotations result = new Annotations();
+
+        result.addAll(annotations);
+        result.add(annotation);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs an empty instance.
+     */
+    public Annotations() {
+        annotations = new TreeMap<CstType, Annotation>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotations.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof Annotations)) {
+            return false;
+        }
+
+        Annotations otherAnnotations = (Annotations) other;
+
+        return annotations.equals(otherAnnotations.annotations);
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Annotations other) {
+        Iterator<Annotation> thisIter = annotations.values().iterator();
+        Iterator<Annotation> otherIter = other.annotations.values().iterator();
+
+        while (thisIter.hasNext() && otherIter.hasNext()) {
+            Annotation thisOne = thisIter.next();
+            Annotation otherOne = otherIter.next();
+
+            int result = thisOne.compareTo(otherOne);
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (thisIter.hasNext()) {
+            return 1;
+        } else if (otherIter.hasNext()) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+
+        sb.append("annotations{");
+
+        for (Annotation a : annotations.values()) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(a.toHuman());
+        }
+
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Gets the number of elements in this instance.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        return annotations.size();
+    }
+
+    /**
+     * Adds an element to this instance. There must not already be an
+     * element of the same type.
+     *
+     * @param annotation {@code non-null;} the element to add
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public void add(Annotation annotation) {
+        throwIfImmutable();
+
+        if (annotation == null) {
+            throw new NullPointerException("annotation == null");
+        }
+
+        CstType type = annotation.getType();
+
+        if (annotations.containsKey(type)) {
+            throw new IllegalArgumentException("duplicate type: " +
+                    type.toHuman());
+        }
+
+        annotations.put(type, annotation);
+    }
+
+    /**
+     * Adds all of the elements of the given instance to this one. The
+     * instances must not have any duplicate types.
+     *
+     * @param toAdd {@code non-null;} the annotations to add
+     * @throws IllegalArgumentException thrown if there is a duplicate type
+     */
+    public void addAll(Annotations toAdd) {
+        throwIfImmutable();
+
+        if (toAdd == null) {
+            throw new NullPointerException("toAdd == null");
+        }
+
+        for (Annotation a : toAdd.annotations.values()) {
+            add(a);
+        }
+    }
+
+    /**
+     * Gets the set of annotations contained in this instance. The
+     * result is always unmodifiable.
+     *
+     * @return {@code non-null;} the set of annotations
+     */
+    public Collection<Annotation> getAnnotations() {
+        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
new file mode 100644
index 0000000..b97b385
--- /dev/null
+++ b/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.annotation;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * List of {@link Annotations} instances.
+ */
+public final class AnnotationsList
+        extends FixedSizeList {
+    /** {@code non-null;} immutable empty instance */
+    public static final AnnotationsList EMPTY = new AnnotationsList(0);
+
+    /**
+     * Constructs an immutable instance which is the combination of
+     * the two given instances. The two instances must each have the
+     * same number of elements, and each pair of elements must contain
+     * disjoint sets of types.
+     *
+     * @param list1 {@code non-null;} an instance
+     * @param list2 {@code non-null;} the other instance
+     * @return {@code non-null;} the combination
+     */
+    public static AnnotationsList combine(AnnotationsList list1,
+            AnnotationsList list2) {
+        int size = list1.size();
+
+        if (size != list2.size()) {
+            throw new IllegalArgumentException("list1.size() != list2.size()");
+        }
+
+        AnnotationsList result = new AnnotationsList(size);
+
+        for (int i = 0; i < size; i++) {
+            Annotations a1 = list1.get(i);
+            Annotations a2 = list2.get(i);
+            result.set(i, Annotations.combine(a1, a2));
+        }
+
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public AnnotationsList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Annotations get(int n) {
+        return (Annotations) get0(n);
+    }
+
+    /**
+     * Sets the element at the given index. The given element must be
+     * immutable.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param a {@code null-ok;} the element to set at {@code n}
+     */
+    public void set(int n, Annotations a) {
+        a.throwIfMutable();
+        set0(n, a);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/annotation/NameValuePair.java b/dx/src/com/android/dx/rop/annotation/NameValuePair.java
new file mode 100644
index 0000000..56c4936
--- /dev/null
+++ b/dx/src/com/android/dx/rop/annotation/NameValuePair.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.annotation;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstString;
+
+/**
+ * A (name, value) pair. These are used as the contents of an annotation.
+ */
+public final class NameValuePair implements Comparable<NameValuePair> {
+    /** {@code non-null;} the name */
+    private final CstString name;
+
+    /** {@code non-null;} the value */
+    private final Constant value;
+
+    /**
+     * Construct an instance.
+     *
+     * @param name {@code non-null;} the name
+     * @param value {@code non-null;} the value
+     */
+    public NameValuePair(CstString name, Constant value) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        this.name = name;
+        this.value = value;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return name.toHuman() + ":" + value;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return name.hashCode() * 31 + value.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (! (other instanceof NameValuePair)) {
+            return false;
+        }
+
+        NameValuePair otherPair = (NameValuePair) other;
+
+        return name.equals(otherPair.name)
+            && value.equals(otherPair.value);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Instances of this class compare in name-major and value-minor
+     * order.</p>
+     */
+    public int compareTo(NameValuePair other) {
+        int result = name.compareTo(other.name);
+
+        if (result != 0) {
+            return result;
+        }
+
+        return value.compareTo(other.value);
+    }
+
+    /**
+     * Gets the name.
+     *
+     * @return {@code non-null;} the name
+     */
+    public CstString getName() {
+        return name;
+    }
+
+    /**
+     * Gets the value.
+     *
+     * @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
new file mode 100644
index 0000000..2d84fe8
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/AccessFlags.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.util.Hex;
+
+/**
+ * Constants used as "access flags" in various places in classes, and
+ * 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} isn't
+ * used at all in translated code, and {@code ACC_SYNCHRONIZED}
+ * is only used in a very limited way.
+ */
+public final class AccessFlags {
+    /** public member / class */
+    public static final int ACC_PUBLIC = 0x0001;
+
+    /** private member */
+    public static final int ACC_PRIVATE = 0x0002;
+
+    /** protected member */
+    public static final int ACC_PROTECTED = 0x0004;
+
+    /** static member */
+    public static final int ACC_STATIC = 0x0008;
+
+    /** final member / class */
+    public static final int ACC_FINAL = 0x0010;
+
+    /**
+     * synchronized method; only valid in dex files for {@code native}
+     * methods
+     */
+    public static final int ACC_SYNCHRONIZED = 0x0020;
+
+    /**
+     * class with new-style {@code invokespecial} for superclass
+     * method access
+     */
+    public static final int ACC_SUPER = 0x0020;
+
+    /** volatile field */
+    public static final int ACC_VOLATILE = 0x0040;
+
+    /** bridge method (generated) */
+    public static final int ACC_BRIDGE = 0x0040;
+
+    /** transient field */
+    public static final int ACC_TRANSIENT = 0x0080;
+
+    /** varargs method */
+    public static final int ACC_VARARGS = 0x0080;
+
+    /** native method */
+    public static final int ACC_NATIVE = 0x0100;
+
+    /** "class" is in fact an public static final interface */
+    public static final int ACC_INTERFACE = 0x0200;
+
+    /** abstract method / class */
+    public static final int ACC_ABSTRACT = 0x0400;
+
+    /**
+     * method with strict floating point ({@code strictfp})
+     * behavior
+     */
+    public static final int ACC_STRICT = 0x0800;
+
+    /** synthetic member */
+    public static final int ACC_SYNTHETIC = 0x1000;
+
+    /** class is an annotation type */
+    public static final int ACC_ANNOTATION = 0x2000;
+
+    /**
+     * class is an enumerated type; field is an element of an enumerated
+     * type
+     */
+    public static final int ACC_ENUM = 0x4000;
+
+    /** method is a constructor */
+    public static final int ACC_CONSTRUCTOR = 0x10000;
+
+    /**
+     * 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;
+
+    /** flags defined on classes */
+    public static final int CLASS_FLAGS =
+        ACC_PUBLIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE | ACC_ABSTRACT |
+        ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM;
+
+    /** flags defined on inner classes */
+    public static final int INNER_CLASS_FLAGS =
+        ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
+        ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION |
+        ACC_ENUM;
+
+    /** flags defined on fields */
+    public static final int FIELD_FLAGS =
+        ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
+        ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM;
+
+    /** flags defined on methods */
+    public static final int METHOD_FLAGS =
+        ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL |
+        ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
+        ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR |
+        ACC_DECLARED_SYNCHRONIZED;
+
+    /** indicates conversion of class flags */
+    private static final int CONV_CLASS = 1;
+
+    /** indicates conversion of field flags */
+    private static final int CONV_FIELD = 2;
+
+    /** indicates conversion of method flags */
+    private static final int CONV_METHOD = 3;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private AccessFlags() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on classes (not fields or methods).
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String classString(int flags) {
+        return humanHelper(flags, CLASS_FLAGS, CONV_CLASS);
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on inner classes.
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String innerClassString(int flags) {
+        return humanHelper(flags, INNER_CLASS_FLAGS, CONV_CLASS);
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on fields (not classes or methods).
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String fieldString(int flags) {
+        return humanHelper(flags, FIELD_FLAGS, CONV_FIELD);
+    }
+
+    /**
+     * Returns a human-oriented string representing the given access flags,
+     * as defined on methods (not classes or fields).
+     *
+     * @param flags the flags
+     * @return {@code non-null;} human-oriented string
+     */
+    public static String methodString(int flags) {
+        return humanHelper(flags, METHOD_FLAGS, CONV_METHOD);
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_PUBLIC} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_PUBLIC} flag
+     */
+    public static boolean isPublic(int flags) {
+        return (flags & ACC_PUBLIC) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_PROTECTED} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_PROTECTED} flag
+     */
+    public static boolean isProtected(int flags) {
+        return (flags & ACC_PROTECTED) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_PRIVATE} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_PRIVATE} flag
+     */
+    public static boolean isPrivate(int flags) {
+        return (flags & ACC_PRIVATE) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_STATIC} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_STATIC} flag
+     */
+    public static boolean isStatic(int flags) {
+        return (flags & ACC_STATIC) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_SYNCHRONIZED} is on in
+     * the given flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_SYNCHRONIZED} flag
+     */
+    public static boolean isSynchronized(int flags) {
+        return (flags & ACC_SYNCHRONIZED) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_ABSTRACT} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_ABSTRACT} flag
+     */
+    public static boolean isAbstract(int flags) {
+        return (flags & ACC_ABSTRACT) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_NATIVE} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_NATIVE} flag
+     */
+    public static boolean isNative(int flags) {
+        return (flags & ACC_NATIVE) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_ANNOTATION} is on in the given
+     * flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_ANNOTATION} flag
+     */
+    public static boolean isAnnotation(int flags) {
+        return (flags & ACC_ANNOTATION) != 0;
+    }
+
+    /**
+     * Returns whether the flag {@code ACC_DECLARED_SYNCHRONIZED} is
+     * on in the given flags.
+     *
+     * @param flags the flags to check
+     * @return the value of the {@code ACC_DECLARED_SYNCHRONIZED} flag
+     */
+    public static boolean isDeclaredSynchronized(int flags) {
+        return (flags & ACC_DECLARED_SYNCHRONIZED) != 0;
+    }
+
+    /**
+     * Helper to return a human-oriented string representing the given
+     * access flags.
+     *
+     * @param flags the defined flags
+     * @param mask mask for the "defined" bits
+     * @param what what the flags represent (one of {@code CONV_*})
+     * @return {@code non-null;} human-oriented string
+     */
+    private static String humanHelper(int flags, int mask, int what) {
+        StringBuffer sb = new StringBuffer(80);
+        int extra = flags & ~mask;
+
+        flags &= mask;
+
+        if ((flags & ACC_PUBLIC) != 0) {
+            sb.append("|public");
+        }
+        if ((flags & ACC_PRIVATE) != 0) {
+            sb.append("|private");
+        }
+        if ((flags & ACC_PROTECTED) != 0) {
+            sb.append("|protected");
+        }
+        if ((flags & ACC_STATIC) != 0) {
+            sb.append("|static");
+        }
+        if ((flags & ACC_FINAL) != 0) {
+            sb.append("|final");
+        }
+        if ((flags & ACC_SYNCHRONIZED) != 0) {
+            if (what == CONV_CLASS) {
+                sb.append("|super");
+            } else {
+                sb.append("|synchronized");
+            }
+        }
+        if ((flags & ACC_VOLATILE) != 0) {
+            if (what == CONV_METHOD) {
+                sb.append("|bridge");
+            } else {
+                sb.append("|volatile");
+            }
+        }
+        if ((flags & ACC_TRANSIENT) != 0) {
+            if (what == CONV_METHOD) {
+                sb.append("|varargs");
+            } else {
+                sb.append("|transient");
+            }
+        }
+        if ((flags & ACC_NATIVE) != 0) {
+            sb.append("|native");
+        }
+        if ((flags & ACC_INTERFACE) != 0) {
+            sb.append("|interface");
+        }
+        if ((flags & ACC_ABSTRACT) != 0) {
+            sb.append("|abstract");
+        }
+        if ((flags & ACC_STRICT) != 0) {
+            sb.append("|strictfp");
+        }
+        if ((flags & ACC_SYNTHETIC) != 0) {
+            sb.append("|synthetic");
+        }
+        if ((flags & ACC_ANNOTATION) != 0) {
+            sb.append("|annotation");
+        }
+        if ((flags & ACC_ENUM) != 0) {
+            sb.append("|enum");
+        }
+        if ((flags & ACC_CONSTRUCTOR) != 0) {
+            sb.append("|constructor");
+        }
+        if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
+            sb.append("|declared_synchronized");
+        }
+
+        if ((extra != 0) || (sb.length() == 0)) {
+            sb.append('|');
+            sb.append(Hex.u2(extra));
+        }
+
+        return sb.substring(1);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/BasicBlock.java b/dx/src/com/android/dx/rop/code/BasicBlock.java
new file mode 100644
index 0000000..9d99833
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/BasicBlock.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+import com.android.dx.util.LabeledItem;
+
+/**
+ * Basic block of register-based instructions.
+ */
+public final class BasicBlock implements LabeledItem {
+    /** {@code >= 0;} target label for this block */
+    private final int label;
+
+    /** {@code non-null;} list of instructions in this block */
+    private final InsnList insns;
+
+    /**
+     * {@code non-null;} full list of successors that this block may
+     * branch to
+     */
+    private final IntList successors;
+
+    /**
+     * {@code >= -1;} the primary / standard-flow / "default" successor, or
+     * {@code -1} if this block has no successors (that is, it
+     * exits the function/method)
+     */
+    private final int primarySuccessor;
+
+    /**
+     * Constructs an instance. The predecessor set is set to {@code null}.
+     *
+     * @param label {@code >= 0;} target label for this block
+     * @param insns {@code non-null;} list of instructions in this block
+     * @param successors {@code non-null;} full list of successors that this
+     * block may branch to
+     * @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)
+     */
+    public BasicBlock(int label, InsnList insns, IntList successors,
+                      int primarySuccessor) {
+        if (label < 0) {
+            throw new IllegalArgumentException("label < 0");
+        }
+
+        try {
+            insns.throwIfMutable();
+        } catch (NullPointerException ex) {
+            // Elucidate exception.
+            throw new NullPointerException("insns == null");
+        }
+
+        int sz = insns.size();
+
+        if (sz == 0) {
+            throw new IllegalArgumentException("insns.size() == 0");
+        }
+
+        for (int i = sz - 2; i >= 0; i--) {
+            Rop one = insns.get(i).getOpcode();
+            if (one.getBranchingness() != Rop.BRANCH_NONE) {
+                throw new IllegalArgumentException("insns[" + i + "] is a " +
+                                                   "branch or can throw");
+            }
+        }
+
+        Insn lastInsn = insns.get(sz - 1);
+        if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("insns does not end with " +
+                                               "a branch or throwing " +
+                                               "instruction");
+        }
+
+        try {
+            successors.throwIfMutable();
+        } catch (NullPointerException ex) {
+            // Elucidate exception.
+            throw new NullPointerException("successors == null");
+        }
+
+        if (primarySuccessor < -1) {
+            throw new IllegalArgumentException("primarySuccessor < -1");
+        }
+
+        if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) {
+            throw new IllegalArgumentException(
+                    "primarySuccessor " + primarySuccessor + " not in successors " + successors);
+        }
+
+        this.label = label;
+        this.insns = insns;
+        this.successors = successors;
+        this.primarySuccessor = primarySuccessor;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Instances of this class compare by identity. That is,
+     * {@code x.equals(y)} is only true if {@code x == y}.
+     */
+    @Override
+    public boolean equals(Object other) {
+        return (this == other);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Return the identity hashcode of this instance. This is proper,
+     * since instances of this class compare by identity (see {@link #equals}).
+     */
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    /**
+     * Gets the target label of this block.
+     *
+     * @return {@code >= 0;} the label
+     */
+    public int getLabel() {
+        return label;
+    }
+
+    /**
+     * Gets the list of instructions inside this block.
+     *
+     * @return {@code non-null;} the instruction list
+     */
+    public InsnList getInsns() {
+        return insns;
+    }
+
+    /**
+     * Gets the list of successors that this block may branch to.
+     *
+     * @return {@code non-null;} the successors list
+     */
+    public IntList getSuccessors() {
+        return successors;
+    }
+
+    /**
+     * Gets the primary successor of this block.
+     *
+     * @return {@code >= -1;} the primary successor, or {@code -1} if this
+     * block has no successors at all
+     */
+    public int getPrimarySuccessor() {
+        return primarySuccessor;
+    }
+
+    /**
+     * Gets the secondary successor of this block. It is only valid to call
+     * this method on blocks that have exactly two successors.
+     *
+     * @return {@code >= 0;} the secondary successor
+     */
+    public int getSecondarySuccessor() {
+        if (successors.size() != 2) {
+            throw new UnsupportedOperationException(
+                    "block doesn't have exactly two successors");
+        }
+
+        int succ = successors.get(0);
+        if (succ == primarySuccessor) {
+            succ = successors.get(1);
+        }
+
+        return succ;
+    }
+
+    /**
+     * Gets the first instruction of this block. This is just a
+     * convenient shorthand for {@code getInsns().get(0)}.
+     *
+     * @return {@code non-null;} the first instruction
+     */
+    public Insn getFirstInsn() {
+        return insns.get(0);
+    }
+
+    /**
+     * Gets the last instruction of this block. This is just a
+     * convenient shorthand for {@code getInsns().getLast()}.
+     *
+     * @return {@code non-null;} the last instruction
+     */
+    public Insn getLastInsn() {
+        return insns.getLast();
+    }
+
+    /**
+     * Returns whether this block might throw an exception. This is
+     * just a convenient shorthand for {@code getLastInsn().canThrow()}.
+     *
+     * @return {@code true} iff this block might throw an
+     * exception
+     */
+    public boolean canThrow() {
+        return insns.getLast().canThrow();
+    }
+
+    /**
+     * Returns whether this block has any associated exception handlers.
+     * This is just a shorthand for inspecting the last instruction in
+     * the block to see if it could throw, and if so, whether it in fact
+     * has any associated handlers.
+     *
+     * @return {@code true} iff this block has any associated
+     * exception handlers
+     */
+    public boolean hasExceptionHandlers() {
+        Insn lastInsn = insns.getLast();
+        return lastInsn.getCatches().size() != 0;
+    }
+
+    /**
+     * Returns the exception handler types associated with this block,
+     * 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}).
+     *
+     * @return {@code non-null;} the exception handler types associated with
+     * this block
+     */
+    public TypeList getExceptionHandlerTypes() {
+        Insn lastInsn = insns.getLast();
+        return lastInsn.getCatches();
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public BasicBlock withRegisterOffset(int delta) {
+        return new BasicBlock(label, insns.withRegisterOffset(delta),
+                              successors, primarySuccessor);
+    }
+
+    public String toString() {
+        return '{' + Hex.u2(label) + '}';
+    }
+
+    /**
+     * BasicBlock visitor interface
+     */
+    public interface Visitor {
+        /**
+         * Visits a basic block
+         * @param b block visited
+         */
+        public void visitBlock (BasicBlock b);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/BasicBlockList.java b/dx/src/com/android/dx/rop/code/BasicBlockList.java
new file mode 100644
index 0000000..ef79075
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/BasicBlockList.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+import com.android.dx.util.LabeledList;
+
+/**
+ * List of {@link BasicBlock} instances.
+ */
+public final class BasicBlockList extends LabeledList {
+    /**
+     * {@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},
+     * and the first-block label is initially {@code -1}.
+     *
+     * @param size the size of the list
+     */
+    public BasicBlockList(int size) {
+        super(size);
+
+        regCount = -1;
+    }
+
+    /**
+     * Constructs a mutable copy for {@code getMutableCopy()}.
+     *
+     * @param old block to copy
+     */
+    private BasicBlockList(BasicBlockList old) {
+        super(old);
+        regCount = old.regCount;
+    }
+
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public BasicBlock get(int n) {
+        return (BasicBlock) get0(n);
+    }
+
+    /**
+     * Sets the basic block at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param bb {@code null-ok;} the element to set at {@code n}
+     */
+    public void set(int n, BasicBlock bb) {
+        super.set(n, bb);
+
+        // Reset regCount, since it will need to be recalculated.
+        regCount = -1;
+    }
+
+    /**
+     * Returns how many registers this method requires. This is simply
+     * the maximum of register-number-plus-category referred to by this
+     * instance's instructions (indirectly through {@link BasicBlock}
+     * instances).
+     *
+     * @return {@code >= 0;} the register count
+     */
+    public int getRegCount() {
+        if (regCount == -1) {
+            RegCountVisitor visitor = new RegCountVisitor();
+            forEachInsn(visitor);
+            regCount = visitor.getRegCount();
+        }
+
+        return regCount;
+    }
+
+    /**
+     * Gets the total instruction count for this instance. This is the
+     * sum of the instruction counts of each block.
+     *
+     * @return {@code >= 0;} the total instruction count
+     */
+    public int getInstructionCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = (BasicBlock) getOrNull0(i);
+            if (one != null) {
+                result += one.getInsns().size();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the total instruction count for this instance, ignoring
+     * mark-local instructions which are not actually emitted.
+     *
+     * @return {@code >= 0;} the total instruction count
+     */
+    public int getEffectiveInstructionCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = (BasicBlock) getOrNull0(i);
+            if (one != null) {
+                InsnList insns = one.getInsns();
+                int insnsSz = insns.size();
+
+                for (int j = 0; j < insnsSz; j++) {
+                    Insn insn = insns.get(j);
+
+                    if (insn.getOpcode().getOpcode() != RegOps.MARK_LOCAL) {
+                        result++;
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the first block in the list with the given label, if any.
+     *
+     * @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) {
+        int idx = indexOfLabel(label);
+
+        if (idx < 0) {
+            throw new IllegalArgumentException("no such label: "
+                    + Hex.u2(label));
+        }
+
+        return get(idx);
+    }
+
+    /**
+     * Visits each instruction of each block in the list, in order.
+     *
+     * @param visitor {@code non-null;} visitor to use
+     */
+    public void forEachInsn(Insn.Visitor visitor) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = get(i);
+            InsnList insns = one.getInsns();
+            insns.forEach(visitor);
+        }
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount. Mutability of the result is inherited from the
+     * original.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public BasicBlockList withRegisterOffset(int delta) {
+        int sz = size();
+        BasicBlockList result = new BasicBlockList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = (BasicBlock) get0(i);
+            if (one != null) {
+                result.set(i, one.withRegisterOffset(delta));
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a mutable copy of this list.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public BasicBlockList getMutableCopy() {
+        return new BasicBlockList(this);
+    }
+
+    /**
+     * Gets the preferred successor for the given block. If the block
+     * 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}.
+     *
+     * @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();
+        IntList successors = block.getSuccessors();
+        int succSize = successors.size();
+
+        switch (succSize) {
+            case 0: {
+                return null;
+            }
+            case 1: {
+                return labelToBlock(successors.get(0));
+            }
+        }
+
+        if (primarySuccessor != -1) {
+            return labelToBlock(primarySuccessor);
+        } else {
+            return labelToBlock(successors.get(0));
+        }
+    }
+
+    /**
+     * Compares the catches of two blocks for equality. This includes
+     * both the catch types and target labels.
+     *
+     * @param block1 {@code non-null;} one block to compare
+     * @param block2 {@code non-null;} the other block to compare
+     * @return {@code true} if the two blocks' non-primary successors
+     * are identical
+     */
+    public boolean catchesEqual(BasicBlock block1, BasicBlock block2) {
+        TypeList catches1 = block1.getExceptionHandlerTypes();
+        TypeList catches2 = block2.getExceptionHandlerTypes();
+
+        if (!StdTypeList.equalContents(catches1, catches2)) {
+            return false;
+        }
+
+        IntList succ1 = block1.getSuccessors();
+        IntList succ2 = block2.getSuccessors();
+        int size = succ1.size(); // Both are guaranteed to be the same size.
+
+        int primary1 = block1.getPrimarySuccessor();
+        int primary2 = block2.getPrimarySuccessor();
+
+        if (((primary1 == -1) || (primary2 == -1))
+                && (primary1 != primary2)) {
+            /*
+             * For the current purpose, both blocks in question must
+             * either both have a primary or both not have a primary to
+             * be considered equal, and it turns out here that that's not
+             * the case.
+             */
+            return false;
+        }
+
+        for (int i = 0; i < size; i++) {
+            int label1 = succ1.get(i);
+            int label2 = succ2.get(i);
+
+            if (label1 == primary1) {
+                /*
+                 * It should be the case that block2's primary is at the
+                 * same index. If not, we consider the blocks unequal for
+                 * the current purpose.
+                 */
+                if (label2 != primary2) {
+                    return false;
+                }
+                continue;
+            }
+
+            if (label1 != label2) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Instruction visitor class for counting registers used.
+     */
+    private static class RegCountVisitor
+            implements Insn.Visitor {
+        /** {@code >= 0;} register count in-progress */
+        private int regCount;
+
+        /**
+         * Constructs an instance.
+         */
+        public RegCountVisitor() {
+            regCount = 0;
+        }
+
+        /**
+         * Gets the register count.
+         *
+         * @return {@code >= 0;} the count
+         */
+        public int getRegCount() {
+            return regCount;
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainInsn(PlainInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitchInsn(SwitchInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            visit(insn);
+        }
+
+        /** {@inheritDoc} */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+            visit(insn);
+        }
+
+        /**
+         * Helper for all the {@code visit*} methods.
+         *
+         * @param insn {@code non-null;} instruction being visited
+         */
+        private void visit(Insn insn) {
+            RegisterSpec result = insn.getResult();
+
+            if (result != null) {
+                processReg(result);
+            }
+
+            RegisterSpecList sources = insn.getSources();
+            int sz = sources.size();
+
+            for (int i = 0; i < sz; i++) {
+                processReg(sources.get(i));
+            }
+        }
+
+        /**
+         * Processes the given register spec.
+         *
+         * @param spec {@code non-null;} the register spec
+         */
+        private void processReg(RegisterSpec spec) {
+            int reg = spec.getNextReg();
+
+            if (reg > regCount) {
+                regCount = reg;
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
new file mode 100644
index 0000000..6c48acf
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+/**
+ * Implementation of {@link TranslationAdvice} which conservatively answers
+ * {@code false} to all methods.
+ */
+public final class ConservativeTranslationAdvice
+        implements TranslationAdvice {
+    /** {@code non-null;} standard instance of this class */
+    public static final ConservativeTranslationAdvice THE_ONE =
+        new ConservativeTranslationAdvice();
+
+    /**
+     * This class is not publicly instantiable. Use {@link #THE_ONE}.
+     */
+    private ConservativeTranslationAdvice() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasConstantOperation(Rop opcode,
+            RegisterSpec sourceA, RegisterSpec sourceB) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public boolean requiresSourcesInOrder(Rop opcode,
+            RegisterSpecList sources) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public int getMaxOptimalRegisterCount() {
+        return Integer.MAX_VALUE;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/CstInsn.java b/dx/src/com/android/dx/rop/code/CstInsn.java
new file mode 100644
index 0000000..d7de2f4
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/CstInsn.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.Constant;
+
+/**
+ * Instruction which contains an explicit reference to a constant.
+ */
+public abstract class CstInsn
+        extends Insn {
+    /** {@code non-null;} the constant */
+    private final Constant cst;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @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) {
+        super(opcode, position, result, sources);
+
+        if (cst == null) {
+            throw new NullPointerException("cst == null");
+        }
+
+        this.cst = cst;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return cst.toHuman();
+    }
+
+    /**
+     * Gets the constant.
+     *
+     * @return {@code non-null;} the constant
+     */
+    public Constant getConstant() {
+        return cst;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean contentEquals(Insn b) {
+        /*
+         * The cast (CstInsn)b below should always succeed since
+         * Insn.contentEquals compares classes of this and b.
+         */
+        return super.contentEquals(b)
+                && cst.equals(((CstInsn)b).getConstant());
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
new file mode 100644
index 0000000..35ce2f2
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.type.Type;
+
+/**
+ * Implementation of {@link TranslationAdvice} which represents what
+ * the dex format will be able to represent.
+ */
+public final class DexTranslationAdvice
+        implements TranslationAdvice {
+    /** {@code non-null;} standard instance of this class */
+    public static final DexTranslationAdvice THE_ONE =
+        new DexTranslationAdvice();
+
+    /** debug advice for disabling invoke-range optimization */
+    public static final DexTranslationAdvice NO_SOURCES_IN_ORDER =
+        new DexTranslationAdvice(true);
+
+    /**
+     * The minimum source width, in register units, for an invoke
+     * instruction that requires its sources to be in order and contiguous.
+     */
+    private static final int MIN_INVOKE_IN_ORDER = 6;
+
+    /** when true: always returns false for requiresSourcesInOrder */
+    private final boolean disableSourcesInOrder;
+
+    /**
+     * This class is not publicly instantiable. Use {@link #THE_ONE}.
+     */
+    private DexTranslationAdvice() {
+        disableSourcesInOrder = false;
+    }
+
+    private DexTranslationAdvice(boolean disableInvokeRange) {
+        this.disableSourcesInOrder = disableInvokeRange;
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasConstantOperation(Rop opcode,
+            RegisterSpec sourceA, RegisterSpec sourceB) {
+        if (sourceA.getType() != Type.INT) {
+            return false;
+        }
+
+        // Return false if second source isn't a constant
+        if (! (sourceB.getTypeBearer() instanceof CstInteger)) {
+            // Except for rsub-int (reverse sub) where first source is constant
+            if (sourceA.getTypeBearer() instanceof CstInteger &&
+                    opcode.getOpcode() == RegOps.SUB) {
+                CstInteger cst = (CstInteger) sourceA.getTypeBearer();
+                return cst.fitsIn16Bits();
+            } else {
+                return false;
+            }
+        }
+
+        CstInteger cst = (CstInteger) sourceB.getTypeBearer();
+
+        switch (opcode.getOpcode()) {
+            // These have 8 and 16 bit cst representations
+            case RegOps.REM:
+            case RegOps.ADD:
+            case RegOps.MUL:
+            case RegOps.DIV:
+            case RegOps.AND:
+            case RegOps.OR:
+            case RegOps.XOR:
+                return cst.fitsIn16Bits();
+            // These only have 8 bit cst reps
+            case RegOps.SHL:
+            case RegOps.SHR:
+            case RegOps.USHR:
+                return cst.fitsIn8Bits();
+            // No sub-const insn, so check if equivalent add-const fits
+            case RegOps.SUB:
+                CstInteger cst2 = CstInteger.make(-cst.getValue());
+                return cst2.fitsIn16Bits();
+            default:
+                return false;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public boolean requiresSourcesInOrder(Rop opcode,
+            RegisterSpecList sources) {
+
+        return !disableSourcesInOrder && opcode.isCallLike()
+                && totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER;
+    }
+
+    /**
+     * Calculates the total rop width of the list of SSA registers
+     *
+     * @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();
+        int total = 0;
+
+        for (int i = 0; i < sz; i++) {
+            total += sources.get(i).getCategory();
+        }
+
+        return total;
+    }
+
+    /** {@inheritDoc} */
+    public int getMaxOptimalRegisterCount() {
+        return 16;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/Exceptions.java b/dx/src/com/android/dx/rop/code/Exceptions.java
new file mode 100644
index 0000000..1e27a8c
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/Exceptions.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+
+/**
+ * Common exception types.
+ */
+public final class Exceptions {
+    /** {@code non-null;} the type {@code java.lang.ArithmeticException} */
+    public static final Type TYPE_ArithmeticException =
+        Type.intern("Ljava/lang/ArithmeticException;");
+
+    /**
+     * {@code non-null;} the type
+     * {@code java.lang.ArrayIndexOutOfBoundsException}
+     */
+    public static final Type TYPE_ArrayIndexOutOfBoundsException =
+        Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;");
+
+    /** {@code non-null;} the type {@code java.lang.ArrayStoreException} */
+    public static final Type TYPE_ArrayStoreException =
+        Type.intern("Ljava/lang/ArrayStoreException;");
+
+    /** {@code non-null;} the type {@code java.lang.ClassCastException} */
+    public static final Type TYPE_ClassCastException =
+        Type.intern("Ljava/lang/ClassCastException;");
+
+    /** {@code non-null;} the type {@code java.lang.Error} */
+    public static final Type TYPE_Error = Type.intern("Ljava/lang/Error;");
+
+    /**
+     * {@code non-null;} the type
+     * {@code java.lang.IllegalMonitorStateException}
+     */
+    public static final Type TYPE_IllegalMonitorStateException =
+        Type.intern("Ljava/lang/IllegalMonitorStateException;");
+
+    /** {@code non-null;} the type {@code java.lang.NegativeArraySizeException} */
+    public static final Type TYPE_NegativeArraySizeException =
+        Type.intern("Ljava/lang/NegativeArraySizeException;");
+
+    /** {@code non-null;} the type {@code java.lang.NullPointerException} */
+    public static final Type TYPE_NullPointerException =
+        Type.intern("Ljava/lang/NullPointerException;");
+
+    /** {@code non-null;} the list {@code [java.lang.Error]} */
+    public static final StdTypeList LIST_Error = StdTypeList.make(TYPE_Error);
+
+    /**
+     * {@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);
+
+    /**
+     * {@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);
+
+    /**
+     * {@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);
+
+    /**
+     * {@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);
+
+    /**
+     * {@code non-null;} the list {@code [java.lang.Error,
+     * java.lang.NullPointerException,
+     * java.lang.ArrayIndexOutOfBoundsException]}
+     */
+    public static final StdTypeList LIST_Error_Null_ArrayIndexOutOfBounds =
+        StdTypeList.make(TYPE_Error,
+                      TYPE_NullPointerException,
+                      TYPE_ArrayIndexOutOfBoundsException);
+
+    /**
+     * {@code non-null;} the list {@code [java.lang.Error,
+     * java.lang.NullPointerException,
+     * java.lang.ArrayIndexOutOfBoundsException,
+     * java.lang.ArrayStoreException]}
+     */
+    public static final StdTypeList LIST_Error_Null_ArrayIndex_ArrayStore =
+        StdTypeList.make(TYPE_Error,
+                      TYPE_NullPointerException,
+                      TYPE_ArrayIndexOutOfBoundsException,
+                      TYPE_ArrayStoreException);
+
+    /**
+     * {@code non-null;} the list {@code [java.lang.Error,
+     * java.lang.NullPointerException,
+     * java.lang.IllegalMonitorStateException]}
+     */
+    public static final StdTypeList
+        LIST_Error_Null_IllegalMonitorStateException =
+        StdTypeList.make(TYPE_Error,
+                      TYPE_NullPointerException,
+                      TYPE_IllegalMonitorStateException);
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Exceptions() {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
new file mode 100644
index 0000000..ed9345d
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.rop.type.StdTypeList;
+
+import java.util.ArrayList;
+
+/**
+ * Instruction which fills a newly created array with a predefined list of
+ * constant values.
+ */
+public final class FillArrayDataInsn
+        extends Insn {
+
+    /** non-null: initial values to fill the newly created array */
+    private final ArrayList<Constant> initValues;
+
+    /**
+     * non-null: type of the array. Will be used to determine the width of
+     * elements in the array-data table.
+     */
+    private final Constant arrayType;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param sources {@code non-null;} specs for all the sources
+     * @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,
+                             ArrayList<Constant> initValues,
+                             Constant cst) {
+        super(opcode, position, null, sources);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        this.initValues = initValues;
+        this.arrayType = cst;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /**
+     * Return the list of init values
+     * @return {@code non-null;} list of init values
+     */
+    public ArrayList<Constant> getInitValues() {
+        return initValues;
+    }
+
+    /**
+     * Return the type of the newly created array
+     * @return {@code non-null;} array type
+     */
+    public Constant getConstant() {
+        return arrayType;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitFillArrayDataInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new  UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new FillArrayDataInsn(getOpcode(), getPosition(),
+                                     getSources().withOffset(delta),
+                                     initValues, arrayType);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new FillArrayDataInsn(getOpcode(), getPosition(),
+                                     sources, initValues, arrayType);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/Insn.java b/dx/src/com/android/dx/rop/code/Insn.java
new file mode 100644
index 0000000..5031f89
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/Insn.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.ToHuman;
+
+/**
+ * A register-based instruction. An instruction is the combination of
+ * an opcode (which specifies operation and source/result types), a
+ * list of actual sources and result registers/values, and additional
+ * information.
+ */
+public abstract class Insn implements ToHuman {
+    /** {@code non-null;} opcode */
+    private final Rop opcode;
+
+    /** {@code non-null;} source position */
+    private final SourcePosition position;
+
+    /** {@code null-ok;} spec for the result of this instruction, if any */
+    private final RegisterSpec result;
+
+    /** {@code non-null;} specs for all the sources of this instruction */
+    private final RegisterSpecList sources;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @param sources {@code non-null;} specs for all the sources
+     */
+    public Insn(Rop opcode, SourcePosition position, RegisterSpec result,
+                RegisterSpecList sources) {
+        if (opcode == null) {
+            throw new NullPointerException("opcode == null");
+        }
+
+        if (position == null) {
+            throw new NullPointerException("position == null");
+        }
+
+        if (sources == null) {
+            throw new NullPointerException("sources == null");
+        }
+
+        this.opcode = opcode;
+        this.position = position;
+        this.result = result;
+        this.sources = sources;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Instances of this class compare by identity. That is,
+     * {@code x.equals(y)} is only true if {@code x == y}.
+     */
+    @Override
+    public final boolean equals(Object other) {
+        return (this == other);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation returns the identity hashcode of this
+     * instance. This is proper, since instances of this class compare
+     * by identity (see {@link #equals}).
+     */
+    @Override
+    public final int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toStringWithInline(getInlineString());
+    }
+
+    /**
+     * Gets a human-oriented (and slightly lossy) string for this instance.
+     *
+     * @return {@code non-null;} the human string form
+     */
+    public String toHuman() {
+        return toHumanWithInline(getInlineString());
+    }
+
+    /**
+     * Gets an "inline" string portion for toHuman(), if available. This
+     * is the portion that appears after the Rop opcode
+     *
+     * @return {@code null-ok;} if non-null, the inline text for toHuman()
+     */
+    public String getInlineString() {
+        return null;
+    }
+
+    /**
+     * Gets the opcode.
+     *
+     * @return {@code non-null;} the opcode
+     */
+    public final Rop getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets 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}
+     * means this instruction returns nothing.
+     *
+     * @return {@code null-ok;} the result spec, if any
+     */
+    public final RegisterSpec getResult() {
+        return result;
+    }
+
+    /**
+     * 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} insns
+     * it may be the source.
+     *
+     * @return {@code null-ok;} a named register spec or null
+     */
+    public final RegisterSpec getLocalAssignment() {
+        RegisterSpec assignment;
+        if (opcode.getOpcode() == RegOps.MARK_LOCAL) {
+            assignment = sources.get(0);
+        } else {
+            assignment = result;
+        }
+
+        if (assignment == null) {
+            return null;
+        }
+
+        LocalItem localItem = assignment.getLocalItem();
+
+        if (localItem == null) {
+            return null;
+        }
+
+        return assignment;
+    }
+
+    /**
+     * Gets the source specs.
+     *
+     * @return {@code non-null;} the source specs
+     */
+    public final RegisterSpecList getSources() {
+        return sources;
+    }
+
+    /**
+     * Gets whether this instruction can possibly throw an exception. This
+     * is just a convenient wrapper for {@code getOpcode().canThrow()}.
+     *
+     * @return {@code true} iff this instruction can possibly throw
+     */
+    public final boolean canThrow() {
+        return opcode.canThrow();
+    }
+
+    /**
+     * Gets the list of possibly-caught exceptions. This returns {@link
+     * StdTypeList#EMPTY} if this instruction has no handlers,
+     * which can be <i>either</i> if this instruction can't possibly
+     * throw or if it merely doesn't handle any of its possible
+     * exceptions. To determine whether this instruction can throw,
+     * use {@link #canThrow}.
+     *
+     * @return {@code non-null;} the catches list
+     */
+    public abstract TypeList getCatches();
+
+    /**
+     * Calls the appropriate method on the given visitor, depending on the
+     * class of this instance. Subclasses must override this.
+     *
+     * @param visitor {@code non-null;} the visitor to call on
+     */
+    public abstract void accept(Visitor visitor);
+
+    /**
+     * Returns an instance that is just like this one, except that it
+     * has a catch list with the given item appended to the end. This
+     * method throws an exception if this instance can't possibly
+     * throw. To determine whether this instruction can throw, use
+     * {@link #canThrow}.
+     *
+     * @param type {@code non-null;} type to append to the catch list
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract Insn withAddedCatch(Type type);
+
+    /**
+     * Returns an instance that is just like this one, except that all
+     * register references have been offset by the given delta.
+     *
+     * @param delta the amount to offset register references by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public abstract Insn withRegisterOffset(int delta);
+
+    /**
+     * Returns an instance that is just like this one, except that, if
+     * possible, the insn is converted into a version in which a source
+     * (if it is a constant) is represented directly rather than as a
+     * register reference. {@code this} is returned in cases where the
+     * translation is not possible.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Insn withSourceLiteral() {
+        return this;
+    }
+
+    /**
+     * Returns an exact copy of this Insn
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Insn copy() {
+        return withRegisterOffset(0);
+    }
+
+
+    /**
+     * Compares, handling nulls safely
+     *
+     * @param a first object
+     * @param b second object
+     * @return true if they're equal or both null.
+     */
+    private static boolean equalsHandleNulls (Object a, Object b) {
+        return (a == b) || ((a != null) && a.equals(b));
+    }
+
+    /**
+     * 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.
+     *
+     * @return true in the case described above
+     */
+    public boolean contentEquals(Insn b) {
+        return opcode == b.getOpcode()
+                && position.equals(b.getPosition())
+                && (getClass() == b.getClass())
+                && equalsHandleNulls(result, b.getResult())
+                && equalsHandleNulls(sources, b.getSources())
+                && StdTypeList.equalContents(getCatches(), b.getCatches());
+    }
+
+    /**
+     * Returns an instance that is just like this one, except
+     * with new result and source registers.
+     *
+     * @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);
+
+    /**
+     * Returns the string form of this instance, with the given bit added in
+     * the standard location for an inline argument.
+     *
+     * @param extra {@code null-ok;} the inline argument string
+     * @return {@code non-null;} the string form
+     */
+    protected final String toStringWithInline(String extra) {
+        StringBuffer sb = new StringBuffer(80);
+
+        sb.append("Insn{");
+        sb.append(position);
+        sb.append(' ');
+        sb.append(opcode);
+
+        if (extra != null) {
+            sb.append(' ');
+            sb.append(extra);
+        }
+
+        sb.append(" :: ");
+
+        if (result != null) {
+            sb.append(result);
+            sb.append(" <- ");
+        }
+
+        sb.append(sources);
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns the human string form of this instance, with the given
+     * bit added in the standard location for an inline argument.
+     *
+     * @param extra {@code null-ok;} the inline argument string
+     * @return {@code non-null;} the human string form
+     */
+    protected final String toHumanWithInline(String extra) {
+        StringBuffer sb = new StringBuffer(80);
+
+        sb.append(position);
+        sb.append(": ");
+        sb.append(opcode.getNickname());
+
+        if (extra != null) {
+            sb.append("(");
+            sb.append(extra);
+            sb.append(")");
+        }
+
+        if (result == null) {
+            sb.append(" .");
+        } else {
+            sb.append(" ");
+            sb.append(result.toHuman());
+        }
+
+        sb.append(" <-");
+
+        int sz = sources.size();
+        if (sz == 0) {
+            sb.append(" .");
+        } else {
+            for (int i = 0; i < sz; i++) {
+                sb.append(" ");
+                sb.append(sources.get(i).toHuman());
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Visitor interface for this (outer) class.
+     */
+    public static interface Visitor {
+        /**
+         * Visits a {@link PlainInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitPlainInsn(PlainInsn insn);
+
+        /**
+         * Visits a {@link PlainCstInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitPlainCstInsn(PlainCstInsn insn);
+
+        /**
+         * Visits a {@link SwitchInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitSwitchInsn(SwitchInsn insn);
+
+        /**
+         * Visits a {@link ThrowingCstInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn);
+
+        /**
+         * Visits a {@link ThrowingInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitThrowingInsn(ThrowingInsn insn);
+
+        /**
+         * Visits a {@link FillArrayDataInsn}.
+         *
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn);
+    }
+
+    /**
+     * Base implementation of {@link Visitor}, which has empty method
+     * bodies for all methods.
+     */
+    public static class BaseVisitor implements Visitor {
+        /** {@inheritDoc} */
+        public void visitPlainInsn(PlainInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitPlainCstInsn(PlainCstInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitSwitchInsn(SwitchInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitThrowingInsn(ThrowingInsn insn) {
+            // This space intentionally left blank.
+        }
+
+        /** {@inheritDoc} */
+        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
+            // This space intentionally left blank.
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/InsnList.java b/dx/src/com/android/dx/rop/code/InsnList.java
new file mode 100644
index 0000000..88abd72
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/InsnList.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * List of {@link Insn} instances.
+ */
+public final class InsnList
+        extends FixedSizeList {
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public InsnList(int size) {
+        super(size);
+    }
+
+    /**
+     * Gets the element at the given index. It is an error to call
+     * this with the index for an element which was never set; if you
+     * do that, this will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @return {@code non-null;} element at that index
+     */
+    public Insn get(int n) {
+        return (Insn) get0(n);
+    }
+
+    /**
+     * Sets the instruction at the given index.
+     *
+     * @param n {@code >= 0, < size();} which index
+     * @param insn {@code non-null;} the instruction to set at {@code n}
+     */
+    public void set(int n, Insn insn) {
+        set0(n, insn);
+    }
+
+    /**
+     * Gets the last instruction. This is just a convenient shorthand for
+     * {@code get(size() - 1)}.
+     *
+     * @return {@code non-null;} the last instruction
+     */
+    public Insn getLast() {
+        return get(size() - 1);
+    }
+
+    /**
+     * Visits each instruction in the list, in order.
+     *
+     * @param visitor {@code non-null;} visitor to use
+     */
+    public void forEach(Insn.Visitor visitor) {
+        int sz = size();
+
+        for (int i = 0; i < sz; i++) {
+            get(i).accept(visitor);
+        }
+    }
+
+    /**
+     * 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()}.
+     *
+     * @param b to compare
+     * @return true in the case described above.
+     */
+    public boolean contentEquals(InsnList b) {
+        if (b == null) return false;
+
+        int sz = size();
+
+        if (sz != b.size()) return false;
+
+        for (int i = 0; i < sz; i++) {
+            if (!get(i).contentEquals(b.get(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount. Mutability of the result is inherited from the
+     * original.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public InsnList withRegisterOffset(int delta) {
+        int sz = size();
+        InsnList result = new InsnList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            Insn one = (Insn) get0(i);
+            if (one != null) {
+                result.set0(i, one.withRegisterOffset(delta));
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/LocalItem.java b/dx/src/com/android/dx/rop/code/LocalItem.java
new file mode 100644
index 0000000..d238f21
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/LocalItem.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.CstString;
+
+/**
+ * A local variable item: either a name or a signature or both.
+ */
+public class LocalItem implements Comparable<LocalItem> {
+    /** {@code null-ok;} local variable name */
+    private final CstString name;
+
+    /** {@code null-ok;} local variable signature */
+    private final CstString signature;
+
+    /**
+     * Make a new item. If both name and signature are null, null is returned.
+     *
+     * TODO: intern these
+     *
+     * @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(CstString name, CstString signature) {
+        if (name == null && signature == null) {
+            return null;
+        }
+
+        return new LocalItem (name, signature);
+    }
+
+    /**
+     * Constructs instance.
+     *
+     * @param name {@code null-ok;} local variable name
+     * @param signature {@code null-ok;} local variable signature
+     */
+    private LocalItem(CstString name, CstString signature) {
+        this.name = name;
+        this.signature = signature;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof LocalItem)) {
+            return false;
+        }
+
+        LocalItem local = (LocalItem) other;
+
+        return 0 == compareTo(local);
+    }
+
+    /**
+     * Compares two strings like String.compareTo(), excepts treats a null
+     * as the least-possible string value.
+     *
+     * @return negative integer, zero, or positive integer in accordance
+     * with Comparable.compareTo()
+     */
+    private static int compareHandlesNulls(CstString a, CstString b) {
+        if (a == b) {
+            return 0;
+        } else if (a == null) {
+            return -1;
+        } else if (b == null) {
+            return 1;
+        } else {
+            return a.compareTo(b);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(LocalItem local) {
+        int ret;
+
+        ret = compareHandlesNulls(name, local.name);
+
+        if (ret != 0) {
+            return ret;
+        }
+
+        ret = compareHandlesNulls(signature, local.signature);
+
+        return ret;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return (name == null ? 0 : name.hashCode()) * 31
+                + (signature == null ? 0 : signature.hashCode());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        if (name != null && signature == null) {
+            return name.toQuoted();
+        } else if (name == null && signature == null) {
+            return "";
+        }
+
+        return "[" + (name == null ? "" : name.toQuoted())
+                + "|" + (signature == null ? "" : signature.toQuoted());
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return {@code null-ok;} name
+     */
+    public CstString getName() {
+        return name;
+    }
+
+    /**
+     * Gets signature.
+     *
+     * @return {@code null-ok;} signature
+     */
+    public CstString 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
new file mode 100644
index 0000000..c2c4021
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.util.Bits;
+import com.android.dx.util.IntList;
+
+/**
+ * Code to figure out which local variables are active at which points in
+ * a method.
+ */
+public final class LocalVariableExtractor {
+    /** {@code non-null;} method being extracted from */
+    private final RopMethod method;
+
+    /** {@code non-null;} block list for the method */
+    private final BasicBlockList blocks;
+
+    /** {@code non-null;} result in-progress */
+    private final LocalVariableInfo resultInfo;
+
+    /** {@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 {@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);
+        return lve.doit();
+    }
+
+    /**
+     * Constructs an instance. This method is private. Use {@link #extract}.
+     *
+     * @param method {@code non-null;} the method to extract from
+     */
+    private LocalVariableExtractor(RopMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        BasicBlockList blocks = method.getBlocks();
+        int maxLabel = blocks.getMaxLabel();
+
+        this.method = method;
+        this.blocks = blocks;
+        this.resultInfo = new LocalVariableInfo(method);
+        this.workSet = Bits.makeBitSet(maxLabel);
+    }
+
+    /**
+     * Does the extraction.
+     *
+     * @return {@code non-null;} the extracted information
+     */
+    private LocalVariableInfo doit() {
+        for (int label = method.getFirstLabel();
+             label >= 0;
+             label = Bits.findFirst(workSet, 0)) {
+            Bits.clear(workSet, label);
+            processBlock(label);
+        }
+
+        resultInfo.setImmutable();
+        return resultInfo;
+    }
+
+    /**
+     * Processes a single block.
+     *
+     * @param label {@code >= 0;} label of the block to process
+     */
+    private void processBlock(int label) {
+        RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label);
+        BasicBlock block = blocks.labelToBlock(label);
+        InsnList insns = block.getInsns();
+        int insnSz = insns.size();
+
+        /*
+         * We may have to treat the last instruction specially: If it
+         * can (but doesn't always) throw, and the exception can be
+         * caught within the same method, then we need to use the
+         * state *before* executing it to be what is merged into
+         * exception targets.
+         */
+        boolean canThrowDuringLastInsn = block.hasExceptionHandlers() &&
+            (insns.getLast().getResult() != null);
+        int freezeSecondaryStateAt = insnSz - 1;
+        RegisterSpecSet secondaryState = primaryState;
+
+        /*
+         * Iterate over the instructions, adding information for each place
+         * that the active variable set changes.
+         */
+
+        for (int i = 0; i < insnSz; i++) {
+            if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
+                // Until this point, primaryState == secondaryState.
+                primaryState.setImmutable();
+                primaryState = primaryState.mutableCopy();
+            }
+
+            Insn insn = insns.get(i);
+            RegisterSpec result;
+
+            result = insn.getLocalAssignment();
+
+            if (result == null) {
+                /*
+                 * If an assignment assigns over an existing local, make
+                 * sure to mark the local as going out of scope.
+                 */
+
+                result = insn.getResult();
+
+                if (result != null
+                        && primaryState.get(result.getReg()) != null) {
+                    primaryState.remove(primaryState.get(result.getReg()));
+                }
+                continue;
+            }
+
+            result = result.withSimpleType();
+
+            RegisterSpec already = primaryState.get(result);
+            /*
+             * The equals() check ensures we only add new info if
+             * the instruction causes a change to the set of
+             * active variables.
+             */
+            if (!result.equals(already)) {
+                /*
+                 * If this insn represents a local moving from one register
+                 * to another, remove the association between the old register
+                 * and the local.
+                 */
+                RegisterSpec previous
+                        = primaryState.localItemToSpec(result.getLocalItem());
+
+                if (previous != null
+                        && (previous.getReg() != result.getReg())) {
+
+                    primaryState.remove(previous);
+                }
+
+                resultInfo.addAssignment(insn, result);
+                primaryState.put(result);
+            }
+        }
+
+        primaryState.setImmutable();
+
+        /*
+         * Merge this state into the start state for each successor,
+         * and update the work set where required (that is, in cases
+         * where the start state for a block changes).
+         */
+
+        IntList successors = block.getSuccessors();
+        int succSz = successors.size();
+        int primarySuccessor = block.getPrimarySuccessor();
+
+        for (int i = 0; i < succSz; i++) {
+            int succ = successors.get(i);
+            RegisterSpecSet state = (succ == primarySuccessor) ?
+                primaryState : secondaryState;
+
+            if (resultInfo.mergeStarts(succ, state)) {
+                Bits.set(workSet, succ);
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
new file mode 100644
index 0000000..5d2b995
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.MutabilityControl;
+
+import java.util.HashMap;
+
+/**
+ * Container for local variable information for a particular {@link
+ * RopMethod}.
+ */
+public final class LocalVariableInfo
+        extends MutabilityControl {
+    /** {@code >= 0;} the register count for the method */
+    private final int regCount;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /** {@code non-null;} map from instructions to the variable each assigns */
+    private final HashMap<Insn, RegisterSpec> insnAssignments;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method being represented by this instance
+     */
+    public LocalVariableInfo(RopMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        BasicBlockList blocks = method.getBlocks();
+        int maxLabel = blocks.getMaxLabel();
+
+        this.regCount = blocks.getRegCount();
+        this.emptySet = new RegisterSpecSet(regCount);
+        this.blockStarts = new RegisterSpecSet[maxLabel];
+        this.insnAssignments =
+            new HashMap<Insn, RegisterSpec>(blocks.getInstructionCount());
+
+        emptySet.setImmutable();
+    }
+
+    /**
+     * Sets the register set associated with the start of the block with
+     * the given label.
+     *
+     * @param label {@code >= 0;} the block label
+     * @param specs {@code non-null;} the register set to associate with the block
+     */
+    public void setStarts(int label, RegisterSpecSet specs) {
+        throwIfImmutable();
+
+        if (specs == null) {
+            throw new NullPointerException("specs == null");
+        }
+
+        try {
+            blockStarts[label] = specs;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus label");
+        }
+    }
+
+    /**
+     * Merges the given register set into the set for the block with the
+     * given label. If there was not already an associated set, then this
+     * is the same as calling {@link #setStarts}. Otherwise, this will
+     * merge the two sets and call {@link #setStarts} on the result of the
+     * merge.
+     *
+     * @param label {@code >= 0;} the block label
+     * @param specs {@code non-null;} the register set to merge into the start set
+     * for the block
+     * @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} if there was no change
+     */
+    public boolean mergeStarts(int label, RegisterSpecSet specs) {
+        RegisterSpecSet start = getStarts0(label);
+        boolean changed = false;
+
+        if (start == null) {
+            setStarts(label, specs);
+            return true;
+        }
+
+        RegisterSpecSet newStart = start.mutableCopy();
+        if (start.size() != 0) {
+            newStart.intersect(specs, true);
+        } else {
+            newStart = specs.mutableCopy();
+        }
+
+        if (start.equals(newStart)) {
+            return false;
+        }
+
+        newStart.setImmutable();
+        setStarts(label, newStart);
+
+        return true;
+    }
+
+    /**
+     * Gets the register set associated with the start of the block
+     * with the given label. This returns an empty set with the appropriate
+     * max size if no set was associated with the block in question.
+     *
+     * @param label {@code >= 0;} the block label
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet getStarts(int label) {
+        RegisterSpecSet result = getStarts0(label);
+
+        return (result != null) ? result : emptySet;
+    }
+
+    /**
+     * Gets the register set associated with the start of the given
+     * block. This is just convenient shorthand for
+     * {@code getStarts(block.getLabel())}.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet getStarts(BasicBlock block) {
+        return getStarts(block.getLabel());
+    }
+
+    /**
+     * Gets a mutable copy of the register set associated with the
+     * start of the block with the given label. This returns a
+     * newly-allocated empty {@link RegisterSpecSet} of appropriate
+     * max size if there is not yet any set associated with the block.
+     *
+     * @param label {@code >= 0;} the block label
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet mutableCopyOfStarts(int label) {
+        RegisterSpecSet result = getStarts0(label);
+
+        return (result != null) ?
+            result.mutableCopy() : new RegisterSpecSet(regCount);
+    }
+
+    /**
+     * Adds an assignment association for the given instruction and
+     * register spec. This throws an exception if the instruction
+     * doesn't actually perform a named variable assignment.
+     *
+     * <b>Note:</b> Although the instruction contains its own spec for
+     * the result, it still needs to be passed in explicitly to this
+     * method, since the spec that is stored here should always have a
+     * simple type and the one in the instruction can be an arbitrary
+     * {@link TypeBearer} (such as a constant value).
+     *
+     * @param insn {@code non-null;} the instruction in question
+     * @param spec {@code non-null;} the associated register spec
+     */
+    public void addAssignment(Insn insn, RegisterSpec spec) {
+        throwIfImmutable();
+
+        if (insn == null) {
+            throw new NullPointerException("insn == null");
+        }
+
+        if (spec == null) {
+            throw new NullPointerException("spec == null");
+        }
+
+        insnAssignments.put(insn, spec);
+    }
+
+    /**
+     * Gets the named register being assigned by the given instruction, if
+     * previously stored in this instance.
+     *
+     * @param insn {@code non-null;} instruction in question
+     * @return {@code null-ok;} the named register being assigned, if any
+     */
+    public RegisterSpec getAssignment(Insn insn) {
+        return insnAssignments.get(insn);
+    }
+
+    /**
+     * Gets the number of assignments recorded by this instance.
+     *
+     * @return {@code >= 0;} the number of assignments
+     */
+    public int getAssignmentCount() {
+        return insnAssignments.size();
+    }
+
+    public void debugDump() {
+        for (int label = 0 ; label < blockStarts.length; label++) {
+            if (blockStarts[label] == null) {
+                continue;
+            }
+
+            if (blockStarts[label] == emptySet) {
+                System.out.printf("%04x: empty set\n", label);
+            } else {
+                System.out.printf("%04x: %s\n", label, blockStarts[label]);
+            }
+        }
+    }
+
+    /**
+     * Helper method, to get the starts for a label, throwing the
+     * right exception for range problems.
+     *
+     * @param label {@code >= 0;} the block label
+     * @return {@code null-ok;} associated register set or {@code null} if there
+     * is none
+     */
+    private RegisterSpecSet getStarts0(int label) {
+        try {
+            return blockStarts[label];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus label");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/PlainCstInsn.java b/dx/src/com/android/dx/rop/code/PlainCstInsn.java
new file mode 100644
index 0000000..fffa76b
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/PlainCstInsn.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * Instruction which contains an explicit reference to a constant
+ * but which cannot throw an exception.
+ */
+public final class PlainCstInsn
+        extends CstInsn {
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @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,
+                        Constant cst) {
+        super(opcode, position, result, sources, cst);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitPlainCstInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new PlainCstInsn(getOpcode(), getPosition(),
+                                getResult().withOffset(delta),
+                                getSources().withOffset(delta),
+                                getConstant());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new PlainCstInsn(getOpcode(), getPosition(),
+                                result,
+                                sources,
+                                getConstant());
+
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/PlainInsn.java b/dx/src/com/android/dx/rop/code/PlainInsn.java
new file mode 100644
index 0000000..3b52efa
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/PlainInsn.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstInteger;
+
+/**
+ * Plain instruction, which has no embedded data and which cannot possibly
+ * throw an exception.
+ */
+public final class PlainInsn
+        extends Insn {
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @param sources {@code non-null;} specs for all the sources
+     */
+    public PlainInsn(Rop opcode, SourcePosition position,
+                     RegisterSpec result, RegisterSpecList sources) {
+        super(opcode, position, result, sources);
+
+        switch (opcode.getBranchingness()) {
+            case Rop.BRANCH_SWITCH:
+            case Rop.BRANCH_THROW: {
+                throw new IllegalArgumentException("bogus branchingness");
+            }
+        }
+
+        if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            // move-result-pseudo is required here
+            throw new IllegalArgumentException
+                    ("can't mix branchingness with result");
+        }
+    }
+
+    /**
+     * Constructs a single-source instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @param source {@code non-null;} spec for the source
+     */
+    public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
+                     RegisterSpec source) {
+        this(opcode, position, result, RegisterSpecList.make(source));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitPlainInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new PlainInsn(getOpcode(), getPosition(),
+                             getResult().withOffset(delta),
+                             getSources().withOffset(delta));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withSourceLiteral() {
+        RegisterSpecList sources = getSources();
+        int szSources = sources.size();
+
+        if (szSources == 0) {
+            return this;
+        }
+
+        TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
+
+        if (!lastType.isConstant()) {
+            // Check for reverse subtraction, where first source is constant
+            TypeBearer firstType = sources.get(0).getTypeBearer();
+            if (szSources == 2 && firstType.isConstant()) {
+                Constant cst = (Constant) firstType;
+                RegisterSpecList newSources = sources.withoutFirst();
+                Rop newRop = Rops.ropFor(getOpcode().getOpcode(), getResult(),
+                                             newSources, cst);
+                return new PlainCstInsn(newRop, getPosition(), getResult(),
+                                            newSources, cst);
+            }
+            return this;
+        } else {
+
+            Constant cst = (Constant) lastType;
+
+            RegisterSpecList newSources = sources.withoutLast();
+
+            Rop newRop;
+            try {
+                // Check for constant subtraction and flip it to be addition
+                int opcode = getOpcode().getOpcode();
+                if (opcode == RegOps.SUB && cst instanceof CstInteger) {
+                    opcode = RegOps.ADD;
+                    cst = CstInteger.make(-((CstInteger)cst).getValue());
+                }
+                newRop = Rops.ropFor(opcode, getResult(), newSources, cst);
+            } catch (IllegalArgumentException ex) {
+                // There's no rop for this case
+                return this;
+            }
+
+            return new PlainCstInsn(newRop, getPosition(),
+                    getResult(), newSources, cst);
+        }
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new PlainInsn(getOpcode(), getPosition(),
+                             result,
+                             sources);
+
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/RegOps.java b/dx/src/com/android/dx/rop/code/RegOps.java
new file mode 100644
index 0000000..c81398d
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/RegOps.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.util.Hex;
+
+/**
+ * All the register-based opcodes, and related utilities.
+ *
+ * <p><b>Note:</b> Opcode descriptions use a rough pseudocode. {@code r}
+ * is the result register, {@code x} is the first argument,
+ * {@code y} is the second argument, and {@code z} is the
+ * 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()} */
+    public static final int NOP = 1;
+
+    /** {@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)} */
+    public static final int MOVE_PARAM = 3;
+
+    /**
+     * {@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;} */
+    public static final int CONST = 5;
+
+    /** {@code goto label} */
+    public static final int GOTO = 6;
+
+    /**
+     * {@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
+     * label}
+     */
+    public static final int IF_NE = 8;
+
+    /** {@code x,y: int :: if (x < y) goto label} */
+    public static final int IF_LT = 9;
+
+    /** {@code x,y: int :: if (x >= y) goto label} */
+    public static final int IF_GE = 10;
+
+    /** {@code x,y: int :: if (x <= y) goto label} */
+    public static final int IF_LE = 11;
+
+    /** {@code x,y: int :: if (x > y) goto label} */
+    public static final int IF_GT = 12;
+
+    /** {@code x: int :: goto table[x]} */
+    public static final int SWITCH = 13;
+
+    /** {@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} */
+    public static final int SUB = 15;
+
+    /** {@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} */
+    public static final int DIV = 17;
+
+    /**
+     * {@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} */
+    public static final int NEG = 19;
+
+    /** {@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} */
+    public static final int OR = 21;
+
+    /** {@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}
+     */
+    public static final int SHL = 23;
+
+    /**
+     * {@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}
+     * (unsigned right-shift)
+     */
+    public static final int USHR = 25;
+
+    /** {@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} (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} (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} (numeric type conversion between the four
+     * "real" numeric types)
+     */
+    public static final int CONV = 29;
+
+    /**
+     * {@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} (Java-style convert int to char)
+     */
+    public static final int TO_CHAR = 31;
+
+    /**
+     * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
+     * convert int to short)
+     */
+    public static final int TO_SHORT = 32;
+
+    /** {@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} */
+    public static final int ARRAY_LENGTH = 34;
+
+    /** {@code x: Throwable :: throw(x)} */
+    public static final int THROW = 35;
+
+    /** {@code x: Object :: monitorenter(x)} */
+    public static final int MONITOR_ENTER = 36;
+
+    /** {@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]} */
+    public static final int AGET = 38;
+
+    /** {@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)} (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]} */
+    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}}
+     */
+    public static final int FILLED_NEW_ARRAY = 42;
+
+    /**
+     * {@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}
+     */
+    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}
+     */
+    public static final int GET_FIELD = 45;
+
+    /**
+     * {@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}
+     */
+    public static final int PUT_FIELD = 47;
+
+    /**
+     * {@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, ...)} (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, ...)} (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, ...)} (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, ...)} (call
+     * direct/special method)
+     */
+    public static final int INVOKE_DIRECT = 52;
+
+    /**
+     * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
+     * (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
+     * ...)} (call interface method)
+     */
+    public static final int INVOKE_INTERFACE = 53;
+
+    /**
+     * {@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}.
+     * <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}.
+     * <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}} */
+    public static final int FILL_ARRAY_DATA = 57;
+
+    /**
+     * This class is uninstantiable.
+     */
+    private RegOps() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the name of the given opcode.
+     *
+     * @param opcode the opcode
+     * @return {@code non-null;} its name
+     */
+    public static String opName(int opcode) {
+        switch (opcode) {
+            case NOP: return "nop";
+            case MOVE: return "move";
+            case MOVE_PARAM: return "move-param";
+            case MOVE_EXCEPTION: return "move-exception";
+            case CONST: return "const";
+            case GOTO: return "goto";
+            case IF_EQ: return "if-eq";
+            case IF_NE: return "if-ne";
+            case IF_LT: return "if-lt";
+            case IF_GE: return "if-ge";
+            case IF_LE: return "if-le";
+            case IF_GT: return "if-gt";
+            case SWITCH: return "switch";
+            case ADD: return "add";
+            case SUB: return "sub";
+            case MUL: return "mul";
+            case DIV: return "div";
+            case REM: return "rem";
+            case NEG: return "neg";
+            case AND: return "and";
+            case OR: return "or";
+            case XOR: return "xor";
+            case SHL: return "shl";
+            case SHR: return "shr";
+            case USHR: return "ushr";
+            case NOT: return "not";
+            case CMPL: return "cmpl";
+            case CMPG: return "cmpg";
+            case CONV: return "conv";
+            case TO_BYTE: return "to-byte";
+            case TO_CHAR: return "to-char";
+            case TO_SHORT: return "to-short";
+            case RETURN: return "return";
+            case ARRAY_LENGTH: return "array-length";
+            case THROW: return "throw";
+            case MONITOR_ENTER: return "monitor-enter";
+            case MONITOR_EXIT: return "monitor-exit";
+            case AGET: return "aget";
+            case APUT: return "aput";
+            case NEW_INSTANCE: return "new-instance";
+            case NEW_ARRAY: return "new-array";
+            case FILLED_NEW_ARRAY: return "filled-new-array";
+            case CHECK_CAST: return "check-cast";
+            case INSTANCE_OF: return "instance-of";
+            case GET_FIELD: return "get-field";
+            case GET_STATIC: return "get-static";
+            case PUT_FIELD: return "put-field";
+            case PUT_STATIC: return "put-static";
+            case INVOKE_STATIC: return "invoke-static";
+            case INVOKE_VIRTUAL: return "invoke-virtual";
+            case INVOKE_SUPER: return "invoke-super";
+            case INVOKE_DIRECT: return "invoke-direct";
+            case INVOKE_INTERFACE: return "invoke-interface";
+            case MOVE_RESULT: return "move-result";
+            case MOVE_RESULT_PSEUDO: return "move-result-pseudo";
+            case FILL_ARRAY_DATA: return "fill-array-data";
+        }
+
+        return "unknown-" + Hex.u1(opcode);
+    }
+
+    /**
+     * Given an IF_* RegOp, returns the right-to-left flipped version. For
+     * example, IF_GT becomes IF_LT.
+     *
+     * @param opcode An IF_* RegOp
+     * @return flipped IF Regop
+     */
+    public static int flippedIfOpcode(final int opcode) {
+        switch (opcode) {
+            case RegOps.IF_EQ:
+            case RegOps.IF_NE:
+                return opcode;
+            case RegOps.IF_LT:
+                return RegOps.IF_GT;
+            case RegOps.IF_GE:
+                return RegOps.IF_LE;
+            case RegOps.IF_LE:
+                return RegOps.IF_GE;
+            case RegOps.IF_GT:
+                return RegOps.IF_LT;
+            default:
+                throw new RuntimeException("Unrecognized IF regop: " + opcode);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpec.java b/dx/src/com/android/dx/rop/code/RegisterSpec.java
new file mode 100644
index 0000000..e5f908b
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/RegisterSpec.java
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.ToHuman;
+
+import java.util.HashMap;
+
+/**
+ * Combination of a register number and a type, used as the sources and
+ * destinations of register-based operations.
+ */
+public final class RegisterSpec
+        implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
+    /** {@code non-null;} string to prefix register numbers with */
+    public static final String PREFIX = "v";
+
+    /** {@code non-null;} intern table for instances */
+    private static final HashMap<Object, RegisterSpec> theInterns =
+        new HashMap<Object, RegisterSpec>(1000);
+
+    /** {@code non-null;} common comparison instance used while interning */
+    private static final ForComparison theInterningItem = new ForComparison();
+
+    /** {@code >= 0;} register number */
+    private final int reg;
+
+    /** {@code non-null;} type loaded or stored */
+    private final TypeBearer type;
+
+    /**
+     * {@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 {@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
+     */
+    private static RegisterSpec intern(int reg, TypeBearer type,
+            LocalItem local) {
+        synchronized (theInterns) {
+            theInterningItem.set(reg, type, local);
+            RegisterSpec found = theInterns.get(theInterningItem);
+
+            if (found != null) {
+                return found;
+            }
+
+            found = theInterningItem.toRegisterSpec();
+            theInterns.put(found, found);
+            return found;
+        }
+    }
+
+    /**
+     * Returns an instance for the given register number and type, with
+     * no variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec make(int reg, TypeBearer type) {
+        return intern(reg, type, null);
+    }
+
+    /**
+     * Returns an instance for the given register number, type, and
+     * variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @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) {
+        if (local == null) {
+            throw new NullPointerException("local  == null");
+        }
+
+        return intern(reg, type, local);
+    }
+
+    /**
+     * Returns an instance for the given register number, type, and
+     * variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated variable info or null for
+     * none
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec makeLocalOptional(
+            int reg, TypeBearer type, LocalItem local) {
+
+        return intern(reg, type, local);
+    }
+
+    /**
+     * Gets the string form for the given register number.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @return {@code non-null;} the string form
+     */
+    public static String regString(int reg) {
+        return PREFIX + reg;
+    }
+
+    /**
+     * Constructs an instance. This constructor is private. Use
+     * {@link #make}.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated local variable, if any
+     */
+    private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
+        if (reg < 0) {
+            throw new IllegalArgumentException("reg < 0");
+        }
+
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        this.reg = reg;
+        this.type = type;
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof RegisterSpec)) {
+            if (other instanceof ForComparison) {
+                ForComparison fc = (ForComparison) other;
+                return equals(fc.reg, fc.type, fc.local);
+            }
+            return false;
+        }
+
+        RegisterSpec spec = (RegisterSpec) other;
+        return equals(spec.reg, spec.type, spec.local);
+    }
+
+    /**
+     * Like {@code equals}, but only consider the simple types of the
+     * registers. That is, this compares {@code getType()} on the types
+     * to ignore whatever arbitrary extra stuff might be carried around
+     * by an outer {@link TypeBearer}.
+     *
+     * @param other {@code null-ok;} spec to compare to
+     * @return {@code true} iff {@code this} and {@code other} are equal
+     * in the stated way
+     */
+    public boolean equalsUsingSimpleType(RegisterSpec other) {
+        if (!matchesVariable(other)) {
+            return false;
+        }
+
+        return (reg == other.reg);
+    }
+
+    /**
+     * Like {@link #equalsUsingSimpleType} but ignoring the register number.
+     * This is useful to determine if two instances refer to the "same"
+     * local variable.
+     *
+     * @param other {@code null-ok;} spec to compare to
+     * @return {@code true} iff {@code this} and {@code other} are equal
+     * in the stated way
+     */
+    public boolean matchesVariable(RegisterSpec other) {
+        if (other == null) {
+            return false;
+        }
+
+        return type.getType().equals(other.type.getType())
+            && ((local == other.local)
+                    || ((local != null) && local.equals(other.local)));
+    }
+
+    /**
+     * Helper for {@link #equals} and {@link #ForComparison.equals},
+     * which actually does the test.
+     *
+     * @param reg value of the instance variable, for another instance
+     * @param type value of the instance variable, for another instance
+     * @param local value of the instance variable, for another instance
+     * @return whether this instance is equal to one with the given
+     * values
+     */
+    private boolean equals(int reg, TypeBearer type, LocalItem local) {
+        return (this.reg == reg)
+            && this.type.equals(type)
+            && ((this.local == local)
+                    || ((this.local != null) && this.local.equals(local)));
+    }
+
+    /**
+     * Compares by (in priority order) register number, unwrapped type
+     * (that is types not {@link TypeBearer}s, and local info.
+     *
+     * @param other {@code non-null;} spec to compare to
+     * @return {@code -1..1;} standard result of comparison
+     */
+    public int compareTo(RegisterSpec other) {
+        if (this.reg < other.reg) {
+            return -1;
+        } else if (this.reg > other.reg) {
+            return 1;
+        }
+
+        int compare = type.getType().compareTo(other.type.getType());
+
+        if (compare != 0) {
+            return compare;
+        }
+
+        if (this.local == null) {
+            return (other.local == null) ? 0 : -1;
+        } else if (other.local == null) {
+            return 1;
+        }
+
+        return this.local.compareTo(other.local);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return hashCodeOf(reg, type, local);
+    }
+
+    /**
+     * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
+     * which actually does the calculation.
+     *
+     * @param reg value of the instance variable
+     * @param type value of the instance variable
+     * @param local value of the instance variable
+     * @return the hash code
+     */
+    private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
+        int hash = (local != null) ? local.hashCode() : 0;
+
+        hash = (hash * 31 + type.hashCode()) * 31 + reg;
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toString0(false);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toString0(true);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return type.getType();
+    }
+
+    /** {@inheritDoc} */
+    public TypeBearer getFrameType() {
+        return type.getFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicType() {
+        return type.getBasicType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicFrameType() {
+        return type.getBasicFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final boolean isConstant() {
+        return false;
+    }
+
+    /**
+     * Gets the register number.
+     *
+     * @return {@code >= 0;} the register number
+     */
+    public int getReg() {
+        return reg;
+    }
+
+    /**
+     * Gets the type (or actual value) which is loaded from or stored
+     * to the register associated with this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public TypeBearer getTypeBearer() {
+        return type;
+    }
+
+    /**
+     * Gets the variable info associated with this instance, if any.
+     *
+     * @return {@code null-ok;} the variable info, or {@code null} if this
+     * instance has none
+     */
+    public LocalItem getLocalItem() {
+        return local;
+    }
+
+    /**
+     * Gets the next available register number after the one in this
+     * instance. This is equal to the register number plus the width
+     * (category) of the type used. Among other things, this may also
+     * be used to determine the minimum required register count
+     * implied by this instance.
+     *
+     * @return {@code >= 0;} the required registers size
+     */
+    public int getNextReg() {
+        return reg + getCategory();
+    }
+
+    /**
+     * Gets the category of this instance's type. This is just a convenient
+     * shorthand for {@code getType().getCategory()}.
+     *
+     * @see #isCategory1
+     * @see #isCategory2
+     * @return {@code 1..2;} the category of this instance's type
+     */
+    public int getCategory() {
+        return type.getType().getCategory();
+    }
+
+    /**
+     * Gets whether this instance's type is category 1. This is just a
+     * convenient shorthand for {@code getType().isCategory1()}.
+     *
+     * @see #getCategory
+     * @see #isCategory2
+     * @return whether or not this instance's type is of category 1
+     */
+    public boolean isCategory1() {
+        return type.getType().isCategory1();
+    }
+
+    /**
+     * Gets whether this instance's type is category 2. This is just a
+     * convenient shorthand for {@code getType().isCategory2()}.
+     *
+     * @see #getCategory
+     * @see #isCategory1
+     * @return whether or not this instance's type is of category 2
+     */
+    public boolean isCategory2() {
+        return type.getType().isCategory2();
+    }
+
+    /**
+     * Gets the string form for just the register number of this instance.
+     *
+     * @return {@code non-null;} the register string form
+     */
+    public String regString() {
+        return regString(reg);
+    }
+
+    /**
+     * Returns an instance that is the intersection between this instance
+     * and the given one, if any. The intersection is defined as follows:
+     *
+     * <ul>
+     *   <li>If {@code other} is {@code null}, then the result
+     *     is {@code null}.
+     *   <li>If the register numbers don't match, then the intersection
+     *     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()} 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()} 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}.</li>
+     * </ul>
+     *
+     * @param other {@code null-ok;} instance to intersect with (or {@code null})
+     * @param localPrimary whether local variables are primary to the
+     * intersection; if {@code true}, then the only non-null
+     * results occur when registers being intersected have equal local
+     * infos (or both have {@code null} local infos)
+     * @return {@code null-ok;} the intersection
+     */
+    public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
+        if (this == other) {
+            // Easy out.
+            return this;
+        }
+
+        if ((other == null) || (reg != other.getReg())) {
+            return null;
+        }
+
+        LocalItem resultLocal =
+            ((local == null) || !local.equals(other.getLocalItem()))
+            ? null : local;
+        boolean sameName = (resultLocal == local);
+
+        if (localPrimary && !sameName) {
+            return null;
+        }
+
+        Type thisType = getType();
+        Type otherType = other.getType();
+
+        // Note: Types are always interned.
+        if (thisType != otherType) {
+            return null;
+        }
+
+        TypeBearer resultTypeBearer =
+            type.equals(other.getTypeBearer()) ? type : thisType;
+
+        if ((resultTypeBearer == type) && sameName) {
+            // It turns out that the intersection is "this" after all.
+            return this;
+        }
+
+        return (resultLocal == null) ? make(reg, resultTypeBearer) :
+            make(reg, resultTypeBearer, resultLocal);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that the
+     * register number is replaced by the given one.
+     *
+     * @param newReg {@code >= 0;} the new register number
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withReg(int newReg) {
+        if (reg == newReg) {
+            return this;
+        }
+
+        return makeLocalOptional(newReg, type, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the type is replaced by the given one.
+     *
+     * @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);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that the
+     * register number is offset by the given amount.
+     *
+     * @param delta the amount to offset the register number by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withOffset(int delta) {
+        if (delta == 0) {
+            return this;
+        }
+
+        return withReg(reg + delta);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the type bearer is replaced by the actual underlying type
+     * (thereby stripping off non-type information) with any
+     * initialization information stripped away as well.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withSimpleType() {
+        TypeBearer orig = type;
+        Type newType;
+
+        if (orig instanceof Type) {
+            newType = (Type) orig;
+        } else {
+            newType = orig.getType();
+        }
+
+        if (newType.isUninitialized()) {
+            newType = newType.getInitializedType();
+        }
+
+        if (newType == orig) {
+            return this;
+        }
+
+        return makeLocalOptional(reg, newType, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one except that the
+     * local variable is as specified in the parameter.
+     *
+     * @param local {@code null-ok;} the local item or null for none
+     * @return an appropriate instance
+     */
+    public RegisterSpec withLocalItem(LocalItem local) {
+        if ((this.local== local)
+                    || ((this.local != null) && this.local.equals(local))) {
+
+            return this;
+        }
+
+        return makeLocalOptional(reg, type, local);
+    }
+
+
+    /**
+     * Helper for {@link #toString} and {@link #toHuman}.
+     *
+     * @param human whether to be human-oriented
+     * @return {@code non-null;} the string form
+     */
+    private String toString0(boolean human) {
+        StringBuffer sb = new StringBuffer(40);
+
+        sb.append(regString());
+        sb.append(":");
+
+        if (local != null) {
+            sb.append(local.toString());
+        }
+
+        Type justType = type.getType();
+        sb.append(justType);
+
+        if (justType != type) {
+            sb.append("=");
+            if (human && (type instanceof CstString)) {
+                sb.append(((CstString) type).toQuoted());
+            } else if (human && (type instanceof Constant)) {
+                sb.append(type.toHuman());
+            } else {
+                sb.append(type);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Holder of register spec data for the purposes of comparison (so that
+     * {@code RegisterSpec} itself can still keep {@code final}
+     * instance variables.
+     */
+    private static class ForComparison {
+        /** {@code >= 0;} register number */
+        private int reg;
+
+        /** {@code non-null;} type loaded or stored */
+        private TypeBearer type;
+
+        /**
+         * {@code null-ok;} local variable associated with this
+         * register, if any
+         */
+        private LocalItem local;
+
+        /**
+         * Set all the instance variables.
+         *
+         * @param reg {@code >= 0;} the register number
+         * @param type {@code non-null;} the type (or possibly actual
+         * value) which is loaded from or stored to the indicated
+         * 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;
+            this.type = type;
+            this.local = local;
+        }
+
+        /**
+         * Construct a {@code RegisterSpec} of this instance's
+         * contents.
+         *
+         * @return {@code non-null;} an appropriately-constructed instance
+         */
+        public RegisterSpec toRegisterSpec() {
+            return new RegisterSpec(reg, type, local);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof RegisterSpec)) {
+                return false;
+            }
+
+            RegisterSpec spec = (RegisterSpec) other;
+            return spec.equals(reg, type, local);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            return hashCodeOf(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
new file mode 100644
index 0000000..3d891fd
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/RegisterSpecList.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.FixedSizeList;
+
+import java.util.BitSet;
+
+/**
+ * List of {@link RegisterSpec} instances.
+ */
+public final class RegisterSpecList
+        extends FixedSizeList implements TypeList {
+    /** {@code non-null;} no-element instance */
+    public static final RegisterSpecList EMPTY = new RegisterSpecList(0);
+
+    /**
+     * Makes a single-element 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);
+        result.set(0, spec);
+        return result;
+    }
+
+    /**
+     * Makes a two-element instance.
+     *
+     * @param spec0 {@code non-null;} the first element
+     * @param spec1 {@code non-null;} the second element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpecList make(RegisterSpec spec0,
+                                        RegisterSpec spec1) {
+        RegisterSpecList result = new RegisterSpecList(2);
+        result.set(0, spec0);
+        result.set(1, spec1);
+        return result;
+    }
+
+    /**
+     * Makes a three-element instance.
+     *
+     * @param spec0 {@code non-null;} the first element
+     * @param spec1 {@code non-null;} the second element
+     * @param spec2 {@code non-null;} the third element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
+                                        RegisterSpec spec2) {
+        RegisterSpecList result = new RegisterSpecList(3);
+        result.set(0, spec0);
+        result.set(1, spec1);
+        result.set(2, spec2);
+        return result;
+    }
+
+    /**
+     * Makes a four-element instance.
+     *
+     * @param spec0 {@code non-null;} the first element
+     * @param spec1 {@code non-null;} the second element
+     * @param spec2 {@code non-null;} the third element
+     * @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,
+                                        RegisterSpec spec3) {
+        RegisterSpecList result = new RegisterSpecList(4);
+        result.set(0, spec0);
+        result.set(1, spec1);
+        result.set(2, spec2);
+        result.set(3, spec3);
+        return result;
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public RegisterSpecList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType(int n) {
+        return get(n).getType().getType();
+    }
+
+    /** {@inheritDoc} */
+    public int getWordCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            result += getType(i).getCategory();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public TypeList withAddedType(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /**
+     * Gets the indicated element. It is an error to call this with the
+     * index for an element which was never set; if you do that, this
+     * will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public RegisterSpec get(int n) {
+        return (RegisterSpec) get0(n);
+    }
+
+    /**
+     * Returns a RegisterSpec in this list that uses the specified register,
+     * or null if there is none in this list.
+     * @param reg Register to find
+     * @return RegisterSpec that uses argument or null.
+     */
+    public RegisterSpec specForRegister(int reg) {
+        int sz = size();
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec rs;
+
+            rs = get(i);
+
+            if (rs.getReg() == reg) {
+                return rs;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the index of a RegisterSpec in this list that uses the specified
+     * register, or -1 if none in this list uses the register.
+     * @param reg Register to find
+     * @return index of RegisterSpec or -1
+     */
+    public int indexOfRegister(int reg) {
+        int sz = size();
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec rs;
+
+            rs = get(i);
+
+            if (rs.getReg() == reg) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Sets the element at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param spec {@code non-null;} the value to store
+     */
+    public void set(int n, RegisterSpec spec) {
+        set0(n, spec);
+    }
+
+    /**
+     * Gets the minimum required register count implied by this
+     * instance. This is equal to the highest register number referred
+     * to plus the widest width (largest category) of the type used in
+     * that register.
+     *
+     * @return {@code >= 0;} the required registers size
+     */
+    public int getRegistersSize() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec spec = (RegisterSpec) get0(i);
+            if (spec != null) {
+                int min = spec.getNextReg();
+                if (min > result) {
+                    result = min;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that it has an additional element prepended to the original.
+     * Mutability of the result is inherited from the original.
+     *
+     * @param spec {@code non-null;} the new first spec (to prepend)
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withFirst(RegisterSpec spec) {
+        int sz = size();
+        RegisterSpecList result = new RegisterSpecList(sz + 1);
+
+        for (int i = 0; i < sz; i++) {
+            result.set0(i + 1, get0(i));
+        }
+
+        result.set0(0, spec);
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that its first element is removed. Mutability of the
+     * result is inherited from the original.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withoutFirst() {
+        int newSize = size() - 1;
+
+        if (newSize == 0) {
+            return EMPTY;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(newSize);
+
+        for (int i = 0; i < newSize; i++) {
+            result.set0(i, get0(i + 1));
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that its last element is removed. Mutability of the
+     * result is inherited from the original.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withoutLast() {
+        int newSize = size() - 1;
+
+        if (newSize == 0) {
+            return EMPTY;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(newSize);
+
+        for (int i = 0; i < newSize; i++) {
+            result.set0(i, get0(i));
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a new instance, which contains a subset of the elements
+     * specified by the given BitSet. Indexes in the BitSet with a zero
+     * are included, while indexes with a one are excluded. Mutability
+     * of the result is inherited from the original.
+     *
+     * @param exclusionSet {@code non-null;} set of registers to exclude
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList subset(BitSet exclusionSet) {
+        int newSize = size() - exclusionSet.cardinality();
+
+        if (newSize == 0) {
+            return EMPTY;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(newSize);
+
+        int newIndex = 0;
+        for (int oldIndex = 0; oldIndex < size(); oldIndex++) {
+            if (!exclusionSet.get(oldIndex)) {
+                result.set0(newIndex, get0(oldIndex));
+                newIndex++;
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * all register numbers are offset by the given amount. Mutability
+     * of the result is inherited from the original.
+     *
+     * @param delta the amount to offset the register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withOffset(int delta) {
+        int sz = size();
+
+        if (sz == 0) {
+            // Don't bother making a new zero-element instance.
+            return this;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = (RegisterSpec) get0(i);
+            if (one != null) {
+                result.set0(i, one.withOffset(delta));
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * all incompatible register numbers are renumbered sequentially from
+     * the given base, with the first number duplicated if indicated. If
+     * a null BitSet is given, it indicates all registers are compatible.
+     *
+     * @param base the base register number
+     * @param duplicateFirst whether to duplicate the first number
+     * @param compatRegs {@code null-ok;} either a {@code non-null} set of
+     * compatible registers, or {@code null} to indicate all registers are
+     * compatible
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecList withExpandedRegisters(int base,
+                                                  boolean duplicateFirst,
+                                                  BitSet compatRegs) {
+        int sz = size();
+
+        if (sz == 0) {
+            // Don't bother making a new zero-element instance.
+            return this;
+        }
+
+        RegisterSpecList result = new RegisterSpecList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            RegisterSpec one = (RegisterSpec) get0(i);
+            boolean replace = (compatRegs == null) ? true : !compatRegs.get(i);
+
+            if (replace) {
+                result.set0(i, one.withReg(base));
+                if (!duplicateFirst) {
+                    base += one.getCategory();
+                }
+            } else {
+                result.set0(i, one);
+            }
+
+            if (duplicateFirst) {
+                duplicateFirst = false;
+            }
+        }
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
new file mode 100644
index 0000000..14ef778
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.util.MutabilityControl;
+
+/**
+ * Set of {@link RegisterSpec} instances, where a given register number
+ * may appear only once in the set.
+ */
+public final class RegisterSpecSet
+        extends MutabilityControl {
+    /** {@code non-null;} no-element instance */
+    public static final RegisterSpecSet EMPTY = new RegisterSpecSet(0);
+
+    /**
+     * {@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;
+
+    /** {@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 {@code >= 0;} the maximum register number (exclusive) that
+     * may be represented in this instance
+     */
+    public RegisterSpecSet(int maxSize) {
+        super(maxSize != 0);
+
+        this.specs = new RegisterSpec[maxSize];
+        this.size = 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof RegisterSpecSet)) {
+            return false;
+        }
+
+        RegisterSpecSet otherSet = (RegisterSpecSet) other;
+        RegisterSpec[] otherSpecs = otherSet.specs;
+        int len = specs.length;
+
+        if ((len != otherSpecs.length) || (size() != otherSet.size())) {
+            return false;
+        }
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec s1 = specs[i];
+            RegisterSpec s2 = otherSpecs[i];
+
+            if (s1 == s2) {
+                continue;
+            }
+
+            if ((s1 == null) || !s1.equals(s2)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int len = specs.length;
+        int hash = 0;
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            int oneHash = (spec == null) ? 0 : spec.hashCode();
+            hash = (hash * 31) + oneHash;
+        }
+
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int len = specs.length;
+        StringBuffer sb = new StringBuffer(len * 25);
+
+        sb.append('{');
+
+        boolean any = false;
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            if (spec != null) {
+                if (any) {
+                    sb.append(", ");
+                } else {
+                    any = true;
+                }
+                sb.append(spec);
+            }
+        }
+
+        sb.append('}');
+        return sb.toString();
+    }
+
+    /**
+     * Gets the maximum number of registers that may be in this instance, which
+     * is also the maximum-plus-one of register numbers that may be
+     * represented.
+     *
+     * @return {@code >= 0;} the maximum size
+     */
+    public int getMaxSize() {
+        return specs.length;
+    }
+
+    /**
+     * Gets the current size of this instance.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        int result = size;
+
+        if (result < 0) {
+            int len = specs.length;
+
+            result = 0;
+            for (int i = 0; i < len; i++) {
+                if (specs[i] != null) {
+                    result++;
+                }
+            }
+
+            size = result;
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the element with the given register number, if any.
+     *
+     * @param reg {@code >= 0;} the desired register number
+     * @return {@code null-ok;} the element with the given register number or
+     * {@code null} if there is none
+     */
+    public RegisterSpec get(int reg) {
+        try {
+            return specs[reg];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus reg");
+        }
+    }
+
+    /**
+     * Gets the element with the same register number as the given
+     * spec, if any. This is just a convenient shorthand for
+     * {@code get(spec.getReg())}.
+     *
+     * @param spec {@code non-null;} spec with the desired register number
+     * @return {@code null-ok;} the element with the matching register number or
+     * {@code null} if there is none
+     */
+    public RegisterSpec get(RegisterSpec spec) {
+        return get(spec.getReg());
+    }
+
+    /**
+     * Returns the spec in this set that's currently associated with a
+     * given local (type, name, and signature), or {@code null} if there is
+     * none. This ignores the register number of the given spec but
+     * matches on everything else.
+     *
+     * @param spec {@code non-null;} local to look for
+     * @return {@code null-ok;} first register found that matches, if any
+     */
+    public RegisterSpec findMatchingLocal(RegisterSpec spec) {
+        int length = specs.length;
+
+        for (int reg = 0; reg < length; reg++) {
+            RegisterSpec s = specs[reg];
+
+            if (s == null) {
+                continue;
+            }
+
+            if (spec.matchesVariable(s)) {
+                return s;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 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 {@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;
+
+        for (int reg = 0; reg < length; reg++) {
+            RegisterSpec spec = specs[reg];
+
+            if ((spec != null) && local.equals(spec.getLocalItem())) {
+                return spec;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Removes a spec from the set. Only the register number
+     * of the parameter is significant.
+     *
+     * @param toRemove {@code non-null;} register to remove.
+     */
+    public void remove(RegisterSpec toRemove) {
+        try {
+            specs[toRemove.getReg()] = null;
+            size = -1;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus reg");
+        }
+    }
+
+    /**
+     * Puts the given spec into the set. If there is already an element in
+     * the set with the same register number, it is replaced. Additionally,
+     * if the previous element is for a category-2 register, then that
+     * previous element is nullified. Finally, if the given spec is for
+     * a category-2 register, then the immediately subsequent element
+     * is nullified.
+     *
+     * @param spec {@code non-null;} the register spec to put in the instance
+     */
+    public void put(RegisterSpec spec) {
+        throwIfImmutable();
+
+        if (spec == null) {
+            throw new NullPointerException("spec == null");
+        }
+
+        size = -1;
+
+        try {
+            int reg = spec.getReg();
+            specs[reg] = spec;
+
+            if (reg > 0) {
+                int prevReg = reg - 1;
+                RegisterSpec prevSpec = specs[prevReg];
+                if ((prevSpec != null) && (prevSpec.getCategory() == 2)) {
+                    specs[prevReg] = null;
+                }
+            }
+
+            if (spec.getCategory() == 2) {
+                specs[reg + 1] = null;
+            }
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("spec.getReg() out of range");
+        }
+    }
+
+    /**
+     * Put the entire contents of the given set into this one.
+     *
+     * @param set {@code non-null;} the set to put into this instance
+     */
+    public void putAll(RegisterSpecSet set) {
+        int max = set.getMaxSize();
+
+        for (int i = 0; i < max; i++) {
+            RegisterSpec spec = set.get(i);
+            if (spec != null) {
+                put(spec);
+            }
+        }
+    }
+
+    /**
+     * Intersects this instance with the given one, modifying this
+     * instance. The intersection consists of the pairwise
+     * {@link RegisterSpec#intersect} of corresponding elements from
+     * this instance and the given one where both are non-null.
+     *
+     * @param other {@code non-null;} set to intersect with
+     * @param localPrimary whether local variables are primary to
+     * the intersection; if {@code true}, then the only non-null
+     * result elements occur when registers being intersected have
+     * equal names (or both have {@code null} names)
+     */
+    public void intersect(RegisterSpecSet other, boolean localPrimary) {
+        throwIfImmutable();
+
+        RegisterSpec[] otherSpecs = other.specs;
+        int thisLen = specs.length;
+        int len = Math.min(thisLen, otherSpecs.length);
+
+        size = -1;
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+
+            if (spec == null) {
+                continue;
+            }
+
+            RegisterSpec intersection =
+                spec.intersect(otherSpecs[i], localPrimary);
+            if (intersection != spec) {
+                specs[i] = intersection;
+            }
+        }
+
+        for (int i = len; i < thisLen; i++) {
+            specs[i] = null;
+        }
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * all register numbers are offset by the given amount. Mutability
+     * of the result is inherited from the original.
+     *
+     * @param delta the amount to offset the register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpecSet withOffset(int delta) {
+        int len = specs.length;
+        RegisterSpecSet result = new RegisterSpecSet(len + delta);
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            if (spec != null) {
+                result.put(spec.withOffset(delta));
+            }
+        }
+
+        result.size = size;
+
+        if (isImmutable()) {
+            result.setImmutable();
+        }
+
+        return result;
+    }
+
+    /**
+     * Makes and return a mutable copy of this instance.
+     *
+     * @return {@code non-null;} the mutable copy
+     */
+    public RegisterSpecSet mutableCopy() {
+        int len = specs.length;
+        RegisterSpecSet copy = new RegisterSpecSet(len);
+
+        for (int i = 0; i < len; i++) {
+            RegisterSpec spec = specs[i];
+            if (spec != null) {
+                copy.put(spec);
+            }
+        }
+
+        copy.size = size;
+
+        return copy;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/Rop.java b/dx/src/com/android/dx/rop/code/Rop.java
new file mode 100644
index 0000000..8224584
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/Rop.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.Hex;
+
+/**
+ * Class that describes all the immutable parts of register-based operations.
+ */
+public final class Rop {
+    /** minimum {@code BRANCH_*} value */
+    public static final int BRANCH_MIN = 1;
+
+    /** indicates a non-branching op */
+    public static final int BRANCH_NONE = 1;
+
+    /** indicates a function/method return */
+    public static final int BRANCH_RETURN = 2;
+
+    /** indicates an unconditional goto */
+    public static final int BRANCH_GOTO = 3;
+
+    /** indicates a two-way branch */
+    public static final int BRANCH_IF = 4;
+
+    /** indicates a switch-style branch */
+    public static final int BRANCH_SWITCH = 5;
+
+    /** indicates a throw-style branch (both always-throws and may-throw) */
+    public static final int BRANCH_THROW = 6;
+
+    /** maximum {@code BRANCH_*} value */
+    public static final int BRANCH_MAX = 6;
+
+    /** the opcode; one of the constants in {@link RegOps} */
+    private final int opcode;
+
+    /**
+     * {@code non-null;} result type of this operation; {@link Type#VOID} for
+     * no-result operations
+     */
+    private final Type result;
+
+    /** {@code non-null;} types of all the sources of this operation */
+    private final TypeList sources;
+
+    /** {@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_*}
+     * constants in this class
+     */
+    private final int branchingness;
+
+    /** whether this is a function/method call op or similar */
+    private final boolean isCallLike;
+
+    /** {@code null-ok;} nickname, if specified (used for debugging) */
+    private final String nickname;
+
+    /**
+     * Constructs an instance. This method is private. Use one of the
+     * public constructors.
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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_*} constants
+     * @param isCallLike whether the op is a function/method call or similar
+     * @param nickname {@code null-ok;} optional nickname (used for debugging)
+     */
+    public Rop(int opcode, Type result, TypeList sources,
+               TypeList exceptions, int branchingness, boolean isCallLike,
+               String nickname) {
+        if (result == null) {
+            throw new NullPointerException("result == null");
+        }
+
+        if (sources == null) {
+            throw new NullPointerException("sources == null");
+        }
+
+        if (exceptions == null) {
+            throw new NullPointerException("exceptions == null");
+        }
+
+        if ((branchingness < BRANCH_MIN) || (branchingness > BRANCH_MAX)) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if ((exceptions.size() != 0) && (branchingness != BRANCH_THROW)) {
+            throw new IllegalArgumentException("exceptions / branchingness " +
+                                               "mismatch");
+        }
+
+        this.opcode = opcode;
+        this.result = result;
+        this.sources = sources;
+        this.exceptions = exceptions;
+        this.branchingness = branchingness;
+        this.isCallLike = isCallLike;
+        this.nickname = nickname;
+    }
+
+    /**
+     * Constructs an instance. The constructed instance is never a
+     * call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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_*} 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) {
+        this(opcode, result, sources, exceptions, branchingness, false,
+             nickname);
+    }
+
+    /**
+     * Constructs a no-exception instance. The constructed instance is never a
+     * call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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_*} constants
+     * @param nickname {@code null-ok;} optional nickname (used for debugging)
+     */
+    public Rop(int opcode, Type result, TypeList sources, int branchingness,
+               String nickname) {
+        this(opcode, result, sources, StdTypeList.EMPTY, branchingness, false,
+             nickname);
+    }
+
+    /**
+     * Constructs a non-branching no-exception instance. The
+     * {@code branchingness} is always {@code BRANCH_NONE},
+     * and it is never a call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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,
+             false, nickname);
+    }
+
+    /**
+     * Constructs a non-empty exceptions instance. Its
+     * {@code branchingness} is always {@code BRANCH_THROW},
+     * but it is never a call-like op (see {@link #isCallLike}).
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param result {@code non-null;} result type of this operation; {@link
+     * Type#VOID} for no-result operations
+     * @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 {@code null-ok;} optional nickname (used for debugging)
+     */
+    public Rop(int opcode, Type result, TypeList sources, TypeList exceptions,
+               String nickname) {
+        this(opcode, result, sources, exceptions, Rop.BRANCH_THROW, false,
+             nickname);
+    }
+
+    /**
+     * Constructs a non-nicknamed instance with non-empty exceptions, which
+     * is always a call-like op (see {@link #isCallLike}). Its
+     * {@code branchingness} is always {@code BRANCH_THROW}.
+     *
+     * @param opcode the opcode; one of the constants in {@link RegOps}
+     * @param sources {@code non-null;} types of all the sources of this operation
+     * @param exceptions {@code non-null;} list of possible types thrown by this
+     * operation
+     */
+    public Rop(int opcode, TypeList sources, TypeList exceptions) {
+        this(opcode, Type.VOID, sources, exceptions, Rop.BRANCH_THROW, true,
+             null);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            // Easy out.
+            return true;
+        }
+
+        if (!(other instanceof Rop)) {
+            return false;
+        }
+
+        Rop rop = (Rop) other;
+
+        return (opcode == rop.opcode) &&
+            (branchingness == rop.branchingness) &&
+            (result == rop.result) &&
+            sources.equals(rop.sources) &&
+            exceptions.equals(rop.exceptions);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int h = (opcode * 31) + branchingness;
+        h = (h * 31) + result.hashCode();
+        h = (h * 31) + sources.hashCode();
+        h = (h * 31) + exceptions.hashCode();
+
+        return h;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(40);
+
+        sb.append("Rop{");
+
+        sb.append(RegOps.opName(opcode));
+
+        if (result != Type.VOID) {
+            sb.append(" ");
+            sb.append(result);
+        } else {
+            sb.append(" .");
+        }
+
+        sb.append(" <-");
+
+        int sz = sources.size();
+        if (sz == 0) {
+            sb.append(" .");
+        } else {
+            for (int i = 0; i < sz; i++) {
+                sb.append(' ');
+                sb.append(sources.getType(i));
+            }
+        }
+
+        if (isCallLike) {
+            sb.append(" call");
+        }
+
+        sz = exceptions.size();
+        if (sz != 0) {
+            sb.append(" throws");
+            for (int i = 0; i < sz; i++) {
+                sb.append(' ');
+                Type one = exceptions.getType(i);
+                if (one == Type.THROWABLE) {
+                    sb.append("<any>");
+                } else {
+                    sb.append(exceptions.getType(i));
+                }
+            }
+        } else {
+            switch (branchingness) {
+                case BRANCH_NONE:   sb.append(" flows"); break;
+                case BRANCH_RETURN: sb.append(" returns"); break;
+                case BRANCH_GOTO:   sb.append(" gotos"); break;
+                case BRANCH_IF:     sb.append(" ifs"); break;
+                case BRANCH_SWITCH: sb.append(" switches"); break;
+                default: sb.append(" " + Hex.u1(branchingness)); break;
+            }
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the opcode.
+     *
+     * @return the opcode
+     */
+    public int getOpcode() {
+        return opcode;
+    }
+
+    /**
+     * Gets the result type. A return value of {@link Type#VOID}
+     * means this operation returns nothing.
+     *
+     * @return {@code null-ok;} the result spec
+     */
+    public Type getResult() {
+        return result;
+    }
+
+    /**
+     * Gets the source types.
+     *
+     * @return {@code non-null;} the source types
+     */
+    public TypeList getSources() {
+        return sources;
+    }
+
+    /**
+     * Gets the list of exception types that might be thrown.
+     *
+     * @return {@code non-null;} the list of exception types
+     */
+    public TypeList getExceptions() {
+        return exceptions;
+    }
+
+    /**
+     * Gets the branchingness of this instance.
+     *
+     * @return the branchingness
+     */
+    public int getBranchingness() {
+        return branchingness;
+    }
+
+    /**
+     * Gets whether this opcode is a function/method call or similar.
+     *
+     * @return {@code true} iff this opcode is call-like
+     */
+    public boolean isCallLike() {
+        return isCallLike;
+    }
+
+
+    /**
+     * Gets whether this opcode is commutative (the order of its sources are
+     * unimportant) or not. All commutative Rops have exactly two sources and
+     * have no branchiness.
+     *
+     * @return true if rop is commutative
+     */
+    public boolean isCommutative() {
+        switch (opcode) {
+            case RegOps.AND:
+            case RegOps.OR:
+            case RegOps.XOR:
+            case RegOps.ADD:
+            case RegOps.MUL:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Gets the nickname. If this instance has no nickname, this returns
+     * the result of calling {@link #toString}.
+     *
+     * @return {@code non-null;} the nickname
+     */
+    public String getNickname() {
+        if (nickname != null) {
+            return nickname;
+        }
+
+        return toString();
+    }
+
+    /**
+     * Gets whether this operation can possibly throw an exception. This
+     * is just a convenient wrapper for
+     * {@code getExceptions().size() != 0}.
+     *
+     * @return {@code true} iff this operation can possibly throw
+     */
+    public final boolean canThrow() {
+        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
new file mode 100644
index 0000000..591d325
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/RopMethod.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.util.Bits;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+/**
+ * All of the parts that make up a method at the rop layer.
+ */
+public final class RopMethod {
+    /** {@code non-null;} basic block list of the method */
+    private final BasicBlockList blocks;
+
+    /** {@code >= 0;} label for the block which starts the method */
+    private final int firstLabel;
+
+    /**
+     * {@code null-ok;} array of predecessors for each block, indexed by block
+     * label
+     */
+    private IntList[] predecessors;
+
+    /**
+     * {@code null-ok;} the predecessors for the implicit "exit" block, that is
+     * the labels for the blocks that return, if calculated
+     */
+    private IntList exitPredecessors;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param blocks {@code non-null;} basic block list of the method
+     * @param firstLabel {@code >= 0;} the label of the first block to execute
+     */
+    public RopMethod(BasicBlockList blocks, int firstLabel) {
+        if (blocks == null) {
+            throw new NullPointerException("blocks == null");
+        }
+
+        if (firstLabel < 0) {
+            throw new IllegalArgumentException("firstLabel < 0");
+        }
+
+        this.blocks = blocks;
+        this.firstLabel = firstLabel;
+
+        this.predecessors = null;
+        this.exitPredecessors = null;
+    }
+
+    /**
+     * Gets the basic block list for this method.
+     *
+     * @return {@code non-null;} the list
+     */
+    public BasicBlockList getBlocks() {
+        return blocks;
+    }
+
+    /**
+     * Gets the label for the first block in the method that this list
+     * represents.
+     *
+     * @return {@code >= 0;} the first-block label
+     */
+    public int getFirstLabel() {
+        return firstLabel;
+    }
+
+    /**
+     * Gets the predecessors associated with the given block. This throws
+     * an exception if there is no block with the given label.
+     *
+     * @param label {@code >= 0;} the label of the block in question
+     * @return {@code non-null;} the predecessors of that block
+     */
+    public IntList labelToPredecessors(int label) {
+        if (exitPredecessors == null) {
+            calcPredecessors();
+        }
+
+        IntList result = predecessors[label];
+
+        if (result == null) {
+            throw new RuntimeException("no such block: " + Hex.u2(label));
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the exit predecessors for this instance.
+     *
+     * @return {@code non-null;} the exit predecessors
+     */
+    public IntList getExitPredecessors() {
+        if (exitPredecessors == null) {
+            calcPredecessors();
+        }
+
+        return exitPredecessors;
+    }
+
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the registers in each instruction are offset by the given
+     * amount.
+     *
+     * @param delta the amount to offset register numbers by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RopMethod withRegisterOffset(int delta) {
+        RopMethod result = new RopMethod(blocks.withRegisterOffset(delta),
+                                         firstLabel);
+
+        if (exitPredecessors != null) {
+            /*
+             * The predecessors have been calculated. It's safe to
+             * inject these into the new instance, since the
+             * transformation being applied doesn't affect the
+             * predecessors.
+             */
+            result.exitPredecessors = exitPredecessors;
+            result.predecessors = predecessors;
+        }
+
+        return result;
+    }
+
+    /**
+     * Calculates the predecessor sets for each block as well as for the
+     * exit.
+     */
+    private void calcPredecessors() {
+        int maxLabel = blocks.getMaxLabel();
+        IntList[] predecessors = new IntList[maxLabel];
+        IntList exitPredecessors = new IntList(10);
+        int sz = blocks.size();
+
+        /*
+         * For each block, find its successors, and add the block's label to
+         * the successor's predecessors.
+         */
+        for (int i = 0; i < sz; i++) {
+            BasicBlock one = blocks.get(i);
+            int label = one.getLabel();
+            IntList successors = one.getSuccessors();
+            int ssz = successors.size();
+            if (ssz == 0) {
+                // This block exits.
+                exitPredecessors.add(label);
+            } else {
+                for (int j = 0; j < ssz; j++) {
+                    int succLabel = successors.get(j);
+                    IntList succPreds = predecessors[succLabel];
+                    if (succPreds == null) {
+                        succPreds = new IntList(10);
+                        predecessors[succLabel] = succPreds;
+                    }
+                    succPreds.add(label);
+                }
+            }
+        }
+
+        // Sort and immutablize all the predecessor lists.
+        for (int i = 0; i < maxLabel; i++) {
+            IntList preds = predecessors[i];
+            if (preds != null) {
+                preds.sort();
+                preds.setImmutable();
+            }
+        }
+
+        exitPredecessors.sort();
+        exitPredecessors.setImmutable();
+
+        /*
+         * The start label might not ever have had any predecessors
+         * added to it (probably doesn't, because of how Java gets
+         * translated into rop form). So, check for this and rectify
+         * the situation if required.
+         */
+        if (predecessors[firstLabel] == null) {
+            predecessors[firstLabel] = IntList.EMPTY;
+        }
+
+        this.predecessors = predecessors;
+        this.exitPredecessors = exitPredecessors;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/Rops.java b/dx/src/com/android/dx/rop/code/Rops.java
new file mode 100644
index 0000000..c1f4f46
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/Rops.java
@@ -0,0 +1,2090 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstBaseMethodRef;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * Standard instances of {@link Rop}.
+ */
+public final class Rops {
+    /** {@code nop()} */
+    public static final Rop NOP =
+        new Rop(RegOps.NOP, Type.VOID, StdTypeList.EMPTY, "nop");
+
+    /** {@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;} */
+    public static final Rop MOVE_LONG =
+        new Rop(RegOps.MOVE, Type.LONG, StdTypeList.LONG, "move-long");
+
+    /** {@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;} */
+    public static final Rop MOVE_DOUBLE =
+        new Rop(RegOps.MOVE, Type.DOUBLE, StdTypeList.DOUBLE, "move-double");
+
+    /** {@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;}
+     *
+     * Note that this rop-form instruction has no dex-form equivilent and
+     * must be removed before the dex conversion.
+     */
+    public static final Rop MOVE_RETURN_ADDRESS =
+        new Rop(RegOps.MOVE, Type.RETURN_ADDRESS,
+                StdTypeList.RETURN_ADDRESS, "move-return-address");
+
+    /** {@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);} */
+    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);} */
+    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);} */
+    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);} */
+    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;} */
+    public static final Rop CONST_INT =
+        new Rop(RegOps.CONST, Type.INT, StdTypeList.EMPTY, "const-int");
+
+    /** {@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;} */
+    public static final Rop CONST_FLOAT =
+        new Rop(RegOps.CONST, Type.FLOAT, StdTypeList.EMPTY, "const-float");
+
+    /** {@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;} */
+    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;} */
+    public static final Rop CONST_OBJECT_NOTHROW =
+        new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY,
+                "const-object-nothrow");
+
+    /** {@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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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]} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    public static final Rop REM_DOUBLE =
+        new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
+                "rem-double");
+
+    /** {@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;} */
+    public static final Rop NEG_LONG =
+        new Rop(RegOps.NEG, Type.LONG, StdTypeList.LONG, "neg-long");
+
+    /** {@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;} */
+    public static final Rop NEG_DOUBLE =
+        new Rop(RegOps.NEG, Type.DOUBLE, StdTypeList.DOUBLE, "neg-double");
+
+    /** {@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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    public static final Rop USHR_LONG =
+        new Rop(RegOps.USHR, Type.LONG, StdTypeList.LONG_INT, "ushr-long");
+
+    /** {@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;} */
+    public static final Rop NOT_LONG =
+        new Rop(RegOps.NOT, Type.LONG, StdTypeList.LONG, "not-long");
+
+    /** {@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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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;} */
+    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);} */
+    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);} */
+    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);} */
+    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);} */
+    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);} */
+    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} */
+    public static final Rop CONV_L2I =
+        new Rop(RegOps.CONV, Type.INT, StdTypeList.LONG, "conv-l2i");
+
+    /** {@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} */
+    public static final Rop CONV_D2I =
+        new Rop(RegOps.CONV, Type.INT, StdTypeList.DOUBLE, "conv-d2i");
+
+    /** {@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} */
+    public static final Rop CONV_F2L =
+        new Rop(RegOps.CONV, Type.LONG, StdTypeList.FLOAT, "conv-f2l");
+
+    /** {@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} */
+    public static final Rop CONV_I2F =
+        new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.INT, "conv-i2f");
+
+    /** {@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} */
+    public static final Rop CONV_D2F =
+        new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.DOUBLE, "conv-d2f");
+
+    /** {@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} */
+    public static final Rop CONV_L2D =
+        new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.LONG, "conv-l2d");
+
+    /** {@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} (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} (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} (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} */
+    public static final Rop RETURN_VOID =
+        new Rop(RegOps.RETURN, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_RETURN,
+                "return-void");
+
+    /** {@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} */
+    public static final Rop RETURN_LONG =
+        new Rop(RegOps.RETURN, Type.VOID, StdTypeList.LONG, Rop.BRANCH_RETURN,
+                "return-long");
+
+    /** {@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} */
+    public static final Rop RETURN_DOUBLE =
+        new Rop(RegOps.RETURN, Type.VOID, StdTypeList.DOUBLE,
+                Rop.BRANCH_RETURN, "return-double");
+
+    /** {@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} */
+    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)} */
+    public static final Rop THROW =
+        new Rop(RegOps.THROW, Type.VOID, StdTypeList.THROWABLE,
+                StdTypeList.THROWABLE, "throw");
+
+    /** {@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)} */
+    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]} */
+    public static final Rop AGET_INT =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.INTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-int");
+
+    /** {@code r: long; x: long[]; y: int :: r = x[y]} */
+    public static final Rop AGET_LONG =
+        new Rop(RegOps.AGET, Type.LONG, StdTypeList.LONGARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-long");
+
+    /** {@code r: float; x: float[]; y: int :: r = x[y]} */
+    public static final Rop AGET_FLOAT =
+        new Rop(RegOps.AGET, Type.FLOAT, StdTypeList.FLOATARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-float");
+
+    /** {@code r: double; x: double[]; y: int :: r = x[y]} */
+    public static final Rop AGET_DOUBLE =
+        new Rop(RegOps.AGET, Type.DOUBLE, StdTypeList.DOUBLEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-double");
+
+    /** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
+    public static final Rop AGET_OBJECT =
+        new Rop(RegOps.AGET, Type.OBJECT, StdTypeList.OBJECTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-object");
+
+    /** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
+    public static final Rop AGET_BOOLEAN =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.BOOLEANARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-boolean");
+
+    /** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
+    public static final Rop AGET_BYTE =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.BYTEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte");
+
+    /** {@code r: char; x: char[]; y: int :: r = x[y]} */
+    public static final Rop AGET_CHAR =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.CHARARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char");
+
+    /** {@code r: short; x: short[]; y: int :: r = x[y]} */
+    public static final Rop AGET_SHORT =
+        new Rop(RegOps.AGET, Type.INT, StdTypeList.SHORTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aget-short");
+
+    /** {@code x,z: int; y: int[] :: y[z] = x} */
+    public static final Rop APUT_INT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_INTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int");
+
+    /** {@code x: long; y: long[]; z: int :: y[z] = x} */
+    public static final Rop APUT_LONG =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.LONG_LONGARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long");
+
+    /** {@code x: float; y: float[]; z: int :: y[z] = x} */
+    public static final Rop APUT_FLOAT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.FLOAT_FLOATARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aput-float");
+
+    /** {@code x: double; y: double[]; z: int :: y[z] = x} */
+    public static final Rop APUT_DOUBLE =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.DOUBLE_DOUBLEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds,
+                "aput-double");
+
+    /** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
+    public static final Rop APUT_OBJECT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.OBJECT_OBJECTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+                "aput-object");
+
+    /** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
+    public static final Rop APUT_BOOLEAN =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BOOLEANARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+                "aput-boolean");
+
+    /** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
+    public static final Rop APUT_BYTE =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_BYTEARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte");
+
+    /** {@code x: char; y: char[]; z: int :: y[z] = x} */
+    public static final Rop APUT_CHAR =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_CHARARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char");
+
+    /** {@code x: short; y: short[]; z: int :: y[z] = x} */
+    public static final Rop APUT_SHORT =
+        new Rop(RegOps.APUT, Type.VOID, StdTypeList.INT_SHORTARR_INT,
+                Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore,
+                "aput-short");
+
+    /**
+     * {@code T: any non-array object type :: r =
+     * alloc(T)} (allocate heap space for an object)
+     */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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]} */
+    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} (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}. 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.
+     */
+    public static final Rop INSTANCE_OF =
+        new Rop(RegOps.INSTANCE_OF, Type.INT, StdTypeList.OBJECT,
+                Exceptions.LIST_Error, "instance-of");
+
+    /**
+     * {@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}
+     */
+    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}
+     */
+    public static final Rop GET_FIELD_FLOAT =
+        new Rop(RegOps.GET_FIELD, Type.FLOAT, StdTypeList.OBJECT,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-float");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-double");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-object");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-boolean");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-byte");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "get-field-char");
+
+    /**
+     * {@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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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}
+     */
+    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}
+     */
+    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}
+     */
+    public static final Rop PUT_FIELD_FLOAT =
+        new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.FLOAT_OBJECT,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-float");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-double");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-object");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-boolean");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-byte");
+
+    /**
+     * {@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,
+                Exceptions.LIST_Error_NullPointerException,
+                "put-field-char");
+
+    /**
+     * {@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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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}
+     */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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} */
+    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}} */
+    public static final Rop FILL_ARRAY_DATA =
+        new Rop(RegOps.FILL_ARRAY_DATA, Type.VOID, StdTypeList.EMPTY,
+                "fill-array-data");
+
+    /**
+     * Returns the appropriate rop for the given opcode, destination,
+     * and sources. The result is typically, but not necessarily, a
+     * shared instance.
+     *
+     * <p><b>Note:</b> This method does not do complete error checking on
+     * its arguments, and so it may return an instance which seemed "right
+     * enough" even though in actuality the passed arguments don't quite
+     * match what is returned. TODO: Revisit this issue.</p>
+     *
+     * @param opcode the opcode
+     * @param dest {@code non-null;} destination (result) type, or
+     * {@link Type#VOID} if none
+     * @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) {
+        switch (opcode) {
+            case RegOps.NOP: return NOP;
+            case RegOps.MOVE: return opMove(dest);
+            case RegOps.MOVE_PARAM: return opMoveParam(dest);
+            case RegOps.MOVE_EXCEPTION: return opMoveException(dest);
+            case RegOps.CONST: return opConst(dest);
+            case RegOps.GOTO: return GOTO;
+            case RegOps.IF_EQ: return opIfEq(sources);
+            case RegOps.IF_NE: return opIfNe(sources);
+            case RegOps.IF_LT: return opIfLt(sources);
+            case RegOps.IF_GE: return opIfGe(sources);
+            case RegOps.IF_LE: return opIfLe(sources);
+            case RegOps.IF_GT: return opIfGt(sources);
+            case RegOps.SWITCH: return SWITCH;
+            case RegOps.ADD: return opAdd(sources);
+            case RegOps.SUB: return opSub(sources);
+            case RegOps.MUL: return opMul(sources);
+            case RegOps.DIV: return opDiv(sources);
+            case RegOps.REM: return opRem(sources);
+            case RegOps.NEG: return opNeg(dest);
+            case RegOps.AND: return opAnd(sources);
+            case RegOps.OR: return opOr(sources);
+            case RegOps.XOR: return opXor(sources);
+            case RegOps.SHL: return opShl(sources);
+            case RegOps.SHR: return opShr(sources);
+            case RegOps.USHR: return opUshr(sources);
+            case RegOps.NOT: return opNot(dest);
+            case RegOps.CMPL: return opCmpl(sources.getType(0));
+            case RegOps.CMPG: return opCmpg(sources.getType(0));
+            case RegOps.CONV: return opConv(dest, sources.getType(0));
+            case RegOps.TO_BYTE: return TO_BYTE;
+            case RegOps.TO_CHAR: return TO_CHAR;
+            case RegOps.TO_SHORT: return TO_SHORT;
+            case RegOps.RETURN: {
+                if (sources.size() == 0) {
+                    return RETURN_VOID;
+                }
+                return opReturn(sources.getType(0));
+            }
+            case RegOps.ARRAY_LENGTH: return ARRAY_LENGTH;
+            case RegOps.THROW: return THROW;
+            case RegOps.MONITOR_ENTER: return MONITOR_ENTER;
+            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 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 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());
+            case RegOps.CHECK_CAST: return CHECK_CAST;
+            case RegOps.INSTANCE_OF: return INSTANCE_OF;
+            case RegOps.GET_FIELD: return opGetField(dest);
+            case RegOps.GET_STATIC: return opGetStatic(dest);
+            case RegOps.PUT_FIELD: return opPutField(sources.getType(0));
+            case RegOps.PUT_STATIC: return opPutStatic(sources.getType(0));
+            case RegOps.INVOKE_STATIC: {
+                return opInvokeStatic(((CstMethodRef) cst).getPrototype());
+            }
+            case RegOps.INVOKE_VIRTUAL: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeVirtual(meth);
+            }
+            case RegOps.INVOKE_SUPER: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeSuper(meth);
+            }
+            case RegOps.INVOKE_DIRECT: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeDirect(meth);
+            }
+            case RegOps.INVOKE_INTERFACE: {
+                CstBaseMethodRef cstMeth = (CstMethodRef) cst;
+                Prototype meth = cstMeth.getPrototype();
+                CstType definer = cstMeth.getDefiningClass();
+                meth = meth.withFirstParameter(definer.getClassType());
+                return opInvokeInterface(meth);
+            }
+        }
+
+        throw new RuntimeException("unknown opcode " + RegOps.opName(opcode));
+    }
+
+    /**
+     * Returns the appropriate {@code move} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being moved
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMove(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return MOVE_INT;
+            case Type.BT_LONG:   return MOVE_LONG;
+            case Type.BT_FLOAT:  return MOVE_FLOAT;
+            case Type.BT_DOUBLE: return MOVE_DOUBLE;
+            case Type.BT_OBJECT: return MOVE_OBJECT;
+            case Type.BT_ADDR:   return MOVE_RETURN_ADDRESS;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code move-param} rop for the
+     * given type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being moved
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMoveParam(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return MOVE_PARAM_INT;
+            case Type.BT_LONG:   return MOVE_PARAM_LONG;
+            case Type.BT_FLOAT:  return MOVE_PARAM_FLOAT;
+            case Type.BT_DOUBLE: return MOVE_PARAM_DOUBLE;
+            case Type.BT_OBJECT: return MOVE_PARAM_OBJECT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code move-exception} rop for the
+     * given type. The result may be a shared instance.
+     *
+     * @param type {@code non-null;} type of the exception
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMoveException(TypeBearer type) {
+        return new Rop(RegOps.MOVE_EXCEPTION, type.getType(),
+                       StdTypeList.EMPTY, (String) null);
+    }
+
+    /**
+     * Returns the appropriate {@code move-result} rop for the
+     * given type. The result may be a shared 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(),
+                       StdTypeList.EMPTY, (String) null);
+    }
+
+    /**
+     * Returns the appropriate {@code move-result-pseudo} rop for the
+     * given type. The result may be a shared 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(),
+                       StdTypeList.EMPTY, (String) null);
+    }
+
+    /**
+     * Returns the appropriate {@code const} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the constant
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opConst(TypeBearer type) {
+        if (type.getType() == Type.KNOWN_NULL) {
+            return CONST_OBJECT_NOTHROW;
+        }
+
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return CONST_INT;
+            case Type.BT_LONG:   return CONST_LONG;
+            case Type.BT_FLOAT:  return CONST_FLOAT;
+            case Type.BT_DOUBLE: return CONST_DOUBLE;
+            case Type.BT_OBJECT: return CONST_OBJECT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code if-eq} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfEq(TypeList types) {
+        return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT,
+                      IF_EQ_INT, IF_EQ_OBJECT);
+    }
+
+    /**
+     * Returns the appropriate {@code if-ne} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfNe(TypeList types) {
+        return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT,
+                      IF_NE_INT, IF_NE_OBJECT);
+    }
+
+    /**
+     * Returns the appropriate {@code if-lt} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfLt(TypeList types) {
+        return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null);
+    }
+
+    /**
+     * Returns the appropriate {@code if-ge} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfGe(TypeList types) {
+        return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null);
+    }
+
+    /**
+     * Returns the appropriate {@code if-gt} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfGt(TypeList types) {
+        return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null);
+    }
+
+    /**
+     * Returns the appropriate {@code if-le} rop for the given
+     * sources. The result is a shared instance.
+     *
+     * @param types {@code non-null;} source types
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opIfLe(TypeList types) {
+        return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null);
+    }
+
+    /**
+     * Helper for all the {@code if*}-related methods, which
+     * checks types and picks one of the four variants, throwing if
+     * there's a problem.
+     *
+     * @param types {@code non-null;} the types
+     * @param intZ {@code non-null;} the int-to-0 comparison
+     * @param objZ {@code null-ok;} the object-to-null comparison
+     * @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) {
+        switch(types.size()) {
+            case 1: {
+                switch (types.getType(0).getBasicFrameType()) {
+                    case Type.BT_INT: {
+                        return intZ;
+                    }
+                    case Type.BT_OBJECT: {
+                        if (objZ != null) {
+                            return objZ;
+                        }
+                    }
+                }
+                break;
+            }
+            case 2: {
+                int bt = types.getType(0).getBasicFrameType();
+                if (bt == types.getType(1).getBasicFrameType()) {
+                    switch (bt) {
+                        case Type.BT_INT: {
+                            return intInt;
+                        }
+                        case Type.BT_OBJECT: {
+                            if (objObj != null) {
+                                return objObj;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+
+        return throwBadTypes(types);
+    }
+
+    /**
+     * Returns the appropriate {@code add} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAdd(TypeList types) {
+        return pickBinaryOp(types, ADD_CONST_INT, ADD_CONST_LONG,
+                            ADD_CONST_FLOAT, ADD_CONST_DOUBLE, ADD_INT,
+                            ADD_LONG, ADD_FLOAT, ADD_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code sub} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opSub(TypeList types) {
+        return pickBinaryOp(types, SUB_CONST_INT, SUB_CONST_LONG,
+                            SUB_CONST_FLOAT, SUB_CONST_DOUBLE, SUB_INT,
+                            SUB_LONG, SUB_FLOAT, SUB_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code mul} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opMul(TypeList types) {
+        return pickBinaryOp(types, MUL_CONST_INT, MUL_CONST_LONG,
+                            MUL_CONST_FLOAT, MUL_CONST_DOUBLE, MUL_INT,
+                            MUL_LONG, MUL_FLOAT, MUL_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code div} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opDiv(TypeList types) {
+        return pickBinaryOp(types, DIV_CONST_INT, DIV_CONST_LONG,
+                            DIV_CONST_FLOAT, DIV_CONST_DOUBLE, DIV_INT,
+                            DIV_LONG, DIV_FLOAT, DIV_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code rem} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opRem(TypeList types) {
+        return pickBinaryOp(types, REM_CONST_INT, REM_CONST_LONG,
+                            REM_CONST_FLOAT, REM_CONST_DOUBLE, REM_INT,
+                            REM_LONG, REM_FLOAT, REM_DOUBLE);
+    }
+
+    /**
+     * Returns the appropriate {@code and} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAnd(TypeList types) {
+        return pickBinaryOp(types, AND_CONST_INT, AND_CONST_LONG, null, null,
+                            AND_INT, AND_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code or} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opOr(TypeList types) {
+        return pickBinaryOp(types, OR_CONST_INT, OR_CONST_LONG, null, null,
+                            OR_INT, OR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code xor} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opXor(TypeList types) {
+        return pickBinaryOp(types, XOR_CONST_INT, XOR_CONST_LONG, null, null,
+                            XOR_INT, XOR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code shl} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opShl(TypeList types) {
+        return pickBinaryOp(types, SHL_CONST_INT, SHL_CONST_LONG, null, null,
+                            SHL_INT, SHL_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code shr} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opShr(TypeList types) {
+        return pickBinaryOp(types, SHR_CONST_INT, SHR_CONST_LONG, null, null,
+                            SHR_INT, SHR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate {@code ushr} rop for the given
+     * types. The result is a shared instance.
+     *
+     * @param types {@code non-null;} types of the sources
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opUshr(TypeList types) {
+        return pickBinaryOp(types, USHR_CONST_INT, USHR_CONST_LONG, null, null,
+                            USHR_INT, USHR_LONG, null, null);
+    }
+
+    /**
+     * Returns the appropriate binary arithmetic rop for the given type
+     * and arguments. The result is a shared instance.
+     *
+     * @param types {@code non-null;} sources of the operation
+     * @param int1 {@code non-null;} the int-to-constant rop
+     * @param long1 {@code non-null;} the long-to-constant rop
+     * @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,
+                                    Rop long2, Rop float2, Rop double2) {
+        int bt1 = types.getType(0).getBasicFrameType();
+        Rop result = null;
+
+        switch (types.size()) {
+            case 1: {
+                switch(bt1) {
+                    case Type.BT_INT:    return int1;
+                    case Type.BT_LONG:   return long1;
+                    case Type.BT_FLOAT:  result = float1; break;
+                    case Type.BT_DOUBLE: result = double1; break;
+                }
+                break;
+            }
+            case 2: {
+                switch(bt1) {
+                    case Type.BT_INT:    return int2;
+                    case Type.BT_LONG:   return long2;
+                    case Type.BT_FLOAT:  result = float2; break;
+                    case Type.BT_DOUBLE: result = double2; break;
+                }
+                break;
+            }
+        }
+
+        if (result == null) {
+            return throwBadTypes(types);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the appropriate {@code neg} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being operated on
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opNeg(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return NEG_INT;
+            case Type.BT_LONG:   return NEG_LONG;
+            case Type.BT_FLOAT:  return NEG_FLOAT;
+            case Type.BT_DOUBLE: return NEG_DOUBLE;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code not} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being operated on
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opNot(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:  return NOT_INT;
+            case Type.BT_LONG: return NOT_LONG;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code cmpl} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being compared
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opCmpl(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_LONG:   return CMPL_LONG;
+            case Type.BT_FLOAT:  return CMPL_FLOAT;
+            case Type.BT_DOUBLE: return CMPL_DOUBLE;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code cmpg} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being compared
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opCmpg(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_FLOAT:  return CMPG_FLOAT;
+            case Type.BT_DOUBLE: return CMPG_DOUBLE;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code conv} rop for the given types. The
+     * result is a shared instance.
+     *
+     * @param dest {@code non-null;} target value type
+     * @param source {@code non-null;} source value type
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opConv(TypeBearer dest, TypeBearer source) {
+        int dbt = dest.getBasicFrameType();
+        switch (source.getBasicFrameType()) {
+            case Type.BT_INT: {
+                switch (dbt) {
+                    case Type.BT_LONG:   return CONV_I2L;
+                    case Type.BT_FLOAT:  return CONV_I2F;
+                    case Type.BT_DOUBLE: return CONV_I2D;
+                    default:             break;
+                }
+            }
+            case Type.BT_LONG: {
+                switch (dbt) {
+                    case Type.BT_INT:    return CONV_L2I;
+                    case Type.BT_FLOAT:  return CONV_L2F;
+                    case Type.BT_DOUBLE: return CONV_L2D;
+                    default:             break;
+                }
+            }
+            case Type.BT_FLOAT: {
+                switch (dbt) {
+                    case Type.BT_INT:    return CONV_F2I;
+                    case Type.BT_LONG:   return CONV_F2L;
+                    case Type.BT_DOUBLE: return CONV_F2D;
+                    default:             break;
+                }
+            }
+            case Type.BT_DOUBLE: {
+                switch (dbt) {
+                    case Type.BT_INT:    return CONV_D2I;
+                    case Type.BT_LONG:   return CONV_D2L;
+                    case Type.BT_FLOAT:  return CONV_D2F;
+                    default:             break;
+                }
+            }
+        }
+
+        return throwBadTypes(StdTypeList.make(dest.getType(),
+                                              source.getType()));
+    }
+
+    /**
+     * Returns the appropriate {@code return} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} type of value being returned
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opReturn(TypeBearer type) {
+        switch (type.getBasicFrameType()) {
+            case Type.BT_INT:    return RETURN_INT;
+            case Type.BT_LONG:   return RETURN_LONG;
+            case Type.BT_FLOAT:  return RETURN_FLOAT;
+            case Type.BT_DOUBLE: return RETURN_DOUBLE;
+            case Type.BT_OBJECT: return RETURN_OBJECT;
+            case Type.BT_VOID:   return RETURN_VOID;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code aget} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} element type of array being accessed
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAget(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return AGET_INT;
+            case Type.BT_LONG:    return AGET_LONG;
+            case Type.BT_FLOAT:   return AGET_FLOAT;
+            case Type.BT_DOUBLE:  return AGET_DOUBLE;
+            case Type.BT_OBJECT:  return AGET_OBJECT;
+            case Type.BT_BOOLEAN: return AGET_BOOLEAN;
+            case Type.BT_BYTE:    return AGET_BYTE;
+            case Type.BT_CHAR:    return AGET_CHAR;
+            case Type.BT_SHORT:   return AGET_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code aput} rop for the given type. The
+     * result is a shared instance.
+     *
+     * @param type {@code non-null;} element type of array being accessed
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opAput(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return APUT_INT;
+            case Type.BT_LONG:    return APUT_LONG;
+            case Type.BT_FLOAT:   return APUT_FLOAT;
+            case Type.BT_DOUBLE:  return APUT_DOUBLE;
+            case Type.BT_OBJECT:  return APUT_OBJECT;
+            case Type.BT_BOOLEAN: return APUT_BOOLEAN;
+            case Type.BT_BYTE:    return APUT_BYTE;
+            case Type.BT_CHAR:    return APUT_CHAR;
+            case Type.BT_SHORT:   return APUT_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code new-array} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param arrayType {@code non-null;} array type of array being created
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opNewArray(TypeBearer arrayType) {
+        Type type = arrayType.getType();
+        Type elementType = type.getComponentType();
+
+        switch (elementType.getBasicType()) {
+            case Type.BT_INT:     return NEW_ARRAY_INT;
+            case Type.BT_LONG:    return NEW_ARRAY_LONG;
+            case Type.BT_FLOAT:   return NEW_ARRAY_FLOAT;
+            case Type.BT_DOUBLE:  return NEW_ARRAY_DOUBLE;
+            case Type.BT_BOOLEAN: return NEW_ARRAY_BOOLEAN;
+            case Type.BT_BYTE:    return NEW_ARRAY_BYTE;
+            case Type.BT_CHAR:    return NEW_ARRAY_CHAR;
+            case Type.BT_SHORT:   return NEW_ARRAY_SHORT;
+            case Type.BT_OBJECT: {
+                return new Rop(RegOps.NEW_ARRAY, type, StdTypeList.INT,
+                        Exceptions.LIST_Error_NegativeArraySizeException,
+                        "new-array-object");
+            }
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code filled-new-array} rop for the given
+     * type. The result may be a shared instance.
+     *
+     * @param arrayType {@code non-null;} type of array being created
+     * @param count {@code >= 0;} number of elements that the array should have
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opFilledNewArray(TypeBearer arrayType, int count) {
+        Type type = arrayType.getType();
+        Type elementType = type.getComponentType();
+
+        if (elementType.isCategory2()) {
+            return throwBadType(arrayType);
+        }
+
+        if (count < 0) {
+            throw new IllegalArgumentException("count < 0");
+        }
+
+        StdTypeList sourceTypes = new StdTypeList(count);
+
+        for (int i = 0; i < count; i++) {
+            sourceTypes.set(i, elementType);
+        }
+
+        // Note: The resulting rop is considered call-like.
+        return new Rop(RegOps.FILLED_NEW_ARRAY,
+                       sourceTypes,
+                       Exceptions.LIST_Error);
+    }
+
+    /**
+     * Returns the appropriate {@code get-field} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opGetField(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return GET_FIELD_INT;
+            case Type.BT_LONG:    return GET_FIELD_LONG;
+            case Type.BT_FLOAT:   return GET_FIELD_FLOAT;
+            case Type.BT_DOUBLE:  return GET_FIELD_DOUBLE;
+            case Type.BT_OBJECT:  return GET_FIELD_OBJECT;
+            case Type.BT_BOOLEAN: return GET_FIELD_BOOLEAN;
+            case Type.BT_BYTE:    return GET_FIELD_BYTE;
+            case Type.BT_CHAR:    return GET_FIELD_CHAR;
+            case Type.BT_SHORT:   return GET_FIELD_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code put-field} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opPutField(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return PUT_FIELD_INT;
+            case Type.BT_LONG:    return PUT_FIELD_LONG;
+            case Type.BT_FLOAT:   return PUT_FIELD_FLOAT;
+            case Type.BT_DOUBLE:  return PUT_FIELD_DOUBLE;
+            case Type.BT_OBJECT:  return PUT_FIELD_OBJECT;
+            case Type.BT_BOOLEAN: return PUT_FIELD_BOOLEAN;
+            case Type.BT_BYTE:    return PUT_FIELD_BYTE;
+            case Type.BT_CHAR:    return PUT_FIELD_CHAR;
+            case Type.BT_SHORT:   return PUT_FIELD_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code get-static} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opGetStatic(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return GET_STATIC_INT;
+            case Type.BT_LONG:    return GET_STATIC_LONG;
+            case Type.BT_FLOAT:   return GET_STATIC_FLOAT;
+            case Type.BT_DOUBLE:  return GET_STATIC_DOUBLE;
+            case Type.BT_OBJECT:  return GET_STATIC_OBJECT;
+            case Type.BT_BOOLEAN: return GET_STATIC_BOOLEAN;
+            case Type.BT_BYTE:    return GET_STATIC_BYTE;
+            case Type.BT_CHAR:    return GET_STATIC_CHAR;
+            case Type.BT_SHORT:   return GET_STATIC_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code put-static} rop for the given
+     * type. The result is a shared instance.
+     *
+     * @param type {@code non-null;} type of the field in question
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opPutStatic(TypeBearer type) {
+        switch (type.getBasicType()) {
+            case Type.BT_INT:     return PUT_STATIC_INT;
+            case Type.BT_LONG:    return PUT_STATIC_LONG;
+            case Type.BT_FLOAT:   return PUT_STATIC_FLOAT;
+            case Type.BT_DOUBLE:  return PUT_STATIC_DOUBLE;
+            case Type.BT_OBJECT:  return PUT_STATIC_OBJECT;
+            case Type.BT_BOOLEAN: return PUT_STATIC_BOOLEAN;
+            case Type.BT_BYTE:    return PUT_STATIC_BYTE;
+            case Type.BT_CHAR:    return PUT_STATIC_CHAR;
+            case Type.BT_SHORT:   return PUT_STATIC_SHORT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-static} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeStatic(Prototype meth) {
+        return new Rop(RegOps.INVOKE_STATIC,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-virtual} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeVirtual(Prototype meth) {
+        return new Rop(RegOps.INVOKE_VIRTUAL,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-super} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeSuper(Prototype meth) {
+        return new Rop(RegOps.INVOKE_SUPER,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-direct} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeDirect(Prototype meth) {
+        return new Rop(RegOps.INVOKE_DIRECT,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code invoke-interface} rop for the
+     * given type. The result is typically a newly-allocated instance.
+     *
+     * @param meth {@code non-null;} descriptor of the method, including the
+     * {@code this} parameter
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static Rop opInvokeInterface(Prototype meth) {
+        return new Rop(RegOps.INVOKE_INTERFACE,
+                       meth.getParameterFrameTypes(),
+                       StdTypeList.THROWABLE);
+    }
+
+    /**
+     * Returns the appropriate {@code mark-local} rop for the given type.
+     * The result is a shared 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()) {
+            case Type.BT_INT:    return MARK_LOCAL_INT;
+            case Type.BT_LONG:   return MARK_LOCAL_LONG;
+            case Type.BT_FLOAT:  return MARK_LOCAL_FLOAT;
+            case Type.BT_DOUBLE: return MARK_LOCAL_DOUBLE;
+            case Type.BT_OBJECT: return MARK_LOCAL_OBJECT;
+        }
+
+        return throwBadType(type);
+    }
+
+    /**
+     * This class is uninstantiable.
+     */
+    private Rops() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Throws the right exception to complain about a bogus type.
+     *
+     * @param type {@code non-null;} the bad type
+     * @return never
+     */
+    private static Rop throwBadType(TypeBearer type) {
+        throw new IllegalArgumentException("bad type: " + type);
+    }
+
+    /**
+     * Throws the right exception to complain about a bogus list of types.
+     *
+     * @param types {@code non-null;} the bad types
+     * @return never
+     */
+    private static Rop throwBadTypes(TypeList types) {
+        throw new IllegalArgumentException("bad types: " + types);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/SourcePosition.java b/dx/src/com/android/dx/rop/code/SourcePosition.java
new file mode 100644
index 0000000..11ac992
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/SourcePosition.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.util.Hex;
+
+/**
+ * Information about a source position for code, which includes both a
+ * line number and original bytecode address.
+ */
+public final class SourcePosition {
+    /** {@code non-null;} convenient "no information known" instance */
+    public static final SourcePosition NO_INFO =
+        new SourcePosition(null, -1, -1);
+
+    /** {@code null-ok;} name of the file of origin or {@code null} if unknown */
+    private final CstString sourceFile;
+
+    /**
+     * {@code >= -1;} the bytecode address, or {@code -1} if that
+     * information is unknown
+     */
+    private final int address;
+
+    /**
+     * {@code >= -1;} the line number, or {@code -1} if that
+     * information is unknown
+     */
+    private final int line;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param sourceFile {@code null-ok;} name of the file of origin or
+     * {@code null} if unknown
+     * @param address {@code >= -1;} original bytecode address or {@code -1}
+     * if unknown
+     * @param line {@code >= -1;} original line number or {@code -1} if
+     * unknown
+     */
+    public SourcePosition(CstString sourceFile, int address, int line) {
+        if (address < -1) {
+            throw new IllegalArgumentException("address < -1");
+        }
+
+        if (line < -1) {
+            throw new IllegalArgumentException("line < -1");
+        }
+
+        this.sourceFile = sourceFile;
+        this.address = address;
+        this.line = line;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(50);
+
+        if (sourceFile != null) {
+            sb.append(sourceFile.toHuman());
+            sb.append(":");
+        }
+
+        if (line >= 0) {
+            sb.append(line);
+        }
+
+        sb.append('@');
+
+        if (address < 0) {
+            sb.append("????");
+        } else {
+            sb.append(Hex.u2(address));
+        }
+
+        return sb.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof SourcePosition)) {
+            return false;
+        }
+
+        if (this == other) {
+            return true;
+        }
+
+        SourcePosition pos = (SourcePosition) other;
+
+        return (address == pos.address) && sameLineAndFile(pos);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return sourceFile.hashCode() + address + line;
+    }
+
+    /**
+     * Returns whether the lines match between this instance and
+     * the one given.
+     *
+     * @param other {@code non-null;} the instance to compare to
+     * @return {@code true} iff the lines match
+     */
+    public boolean sameLine(SourcePosition other) {
+        return (line == other.line);
+    }
+
+    /**
+     * Returns whether the lines and files match between this instance and
+     * the one given.
+     *
+     * @param other {@code non-null;} the instance to compare to
+     * @return {@code true} iff the lines and files match
+     */
+    public boolean sameLineAndFile(SourcePosition other) {
+        return (line == other.line) &&
+            ((sourceFile == other.sourceFile) ||
+             ((sourceFile != null) && sourceFile.equals(other.sourceFile)));
+    }
+
+    /**
+     * Gets the source file, if known.
+     *
+     * @return {@code null-ok;} the source file or {@code null} if unknown
+     */
+    public CstString getSourceFile() {
+        return sourceFile;
+    }
+
+    /**
+     * Gets the original bytecode address.
+     *
+     * @return {@code >= -1;} the address or {@code -1} if unknown
+     */
+    public int getAddress() {
+        return address;
+    }
+
+    /**
+     * Gets the original line number.
+     *
+     * @return {@code >= -1;} the original line number or {@code -1} if
+     * unknown
+     */
+    public int getLine() {
+        return line;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/SwitchInsn.java b/dx/src/com/android/dx/rop/code/SwitchInsn.java
new file mode 100644
index 0000000..31bb94d
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/SwitchInsn.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+import com.android.dx.util.IntList;
+
+/**
+ * Instruction which contains switch cases.
+ */
+public final class SwitchInsn
+        extends Insn {
+    /** {@code non-null;} list of switch cases */
+    private final IntList cases;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param result {@code null-ok;} spec for the result, if any
+     * @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) {
+        super(opcode, position, result, sources);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_SWITCH) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if (cases == null) {
+            throw new NullPointerException("cases == null");
+        }
+
+        this.cases = cases;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return cases.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return StdTypeList.EMPTY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitSwitchInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        throw new UnsupportedOperationException("unsupported");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new SwitchInsn(getOpcode(), getPosition(),
+                              getResult().withOffset(delta),
+                              getSources().withOffset(delta),
+                              cases);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p> SwitchInsn always compares false. The current use for this method
+     * never encounters {@code SwitchInsn}s
+     */
+    @Override
+    public boolean contentEquals(Insn b) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new SwitchInsn(getOpcode(), getPosition(),
+                              result,
+                              sources,
+                              cases);
+    }
+
+    /**
+     * Gets the list of switch cases.
+     *
+     * @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
new file mode 100644
index 0000000..dee01b5
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * Instruction which contains an explicit reference to a constant
+ * and which might throw an exception.
+ */
+public final class ThrowingCstInsn
+        extends CstInsn {
+    /** {@code non-null;} list of exceptions caught */
+    private final TypeList catches;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param sources {@code non-null;} specs for all the sources
+     * @param catches {@code non-null;} list of exceptions caught
+     * @param cst {@code non-null;} the constant
+     */
+    public ThrowingCstInsn(Rop opcode, SourcePosition position,
+                           RegisterSpecList sources,
+                           TypeList catches, Constant cst) {
+        super(opcode, position, null, sources, cst);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if (catches == null) {
+            throw new NullPointerException("catches == null");
+        }
+
+        this.catches = catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        Constant cst = getConstant();
+        String constantString = cst.toHuman();
+        if (cst instanceof CstString) {
+            constantString = ((CstString) cst).toQuoted();
+        }
+        return constantString + " " + ThrowingInsn.toCatchString(catches);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitThrowingCstInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        return new ThrowingCstInsn(getOpcode(), getPosition(),
+                                   getSources(), catches.withAddedType(type),
+                                   getConstant());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new ThrowingCstInsn(getOpcode(), getPosition(),
+                                   getSources().withOffset(delta),
+                                   catches,
+                                   getConstant());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new ThrowingCstInsn(getOpcode(), getPosition(),
+                                   sources,
+                                   catches,
+                                   getConstant());
+    }
+
+
+}
diff --git a/dx/src/com/android/dx/rop/code/ThrowingInsn.java b/dx/src/com/android/dx/rop/code/ThrowingInsn.java
new file mode 100644
index 0000000..6561d41
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/ThrowingInsn.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeList;
+
+/**
+ * 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 {
+    /** {@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 {@code non-null;} the catches list
+     * @return {@code non-null;} the string form
+     */
+    public static String toCatchString(TypeList catches) {
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append("catch");
+
+        int sz = catches.size();
+        for (int i = 0; i < sz; i++) {
+            sb.append(" ");
+            sb.append(catches.getType(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param opcode {@code non-null;} the opcode
+     * @param position {@code non-null;} source position
+     * @param sources {@code non-null;} specs for all the sources
+     * @param catches {@code non-null;} list of exceptions caught
+     */
+    public ThrowingInsn(Rop opcode, SourcePosition position,
+                        RegisterSpecList sources,
+                        TypeList catches) {
+        super(opcode, position, null, sources);
+
+        if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
+            throw new IllegalArgumentException("bogus branchingness");
+        }
+
+        if (catches == null) {
+            throw new NullPointerException("catches == null");
+        }
+
+        this.catches = catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getInlineString() {
+        return toCatchString(catches);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TypeList getCatches() {
+        return catches;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor visitor) {
+        visitor.visitThrowingInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withAddedCatch(Type type) {
+        return new ThrowingInsn(getOpcode(), getPosition(),
+                                getSources(), catches.withAddedType(type));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withRegisterOffset(int delta) {
+        return new ThrowingInsn(getOpcode(), getPosition(),
+                                getSources().withOffset(delta),
+                                catches);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn withNewRegisters(RegisterSpec result,
+            RegisterSpecList sources) {
+
+        return new ThrowingInsn(getOpcode(), getPosition(),
+                                sources,
+                                catches);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/code/TranslationAdvice.java b/dx/src/com/android/dx/rop/code/TranslationAdvice.java
new file mode 100644
index 0000000..832d84d
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/TranslationAdvice.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.code;
+
+/**
+ * Interface for "advice" passed from the late stage of translation back
+ * to the early stage. This allows for the final target architecture to
+ * exert its influence early in the translation process without having
+ * the early stage code be explicitly tied to the target.
+ */
+public interface TranslationAdvice {
+    /**
+     * Returns an indication of whether the target can directly represent an
+     * instruction with the given opcode operating on the given arguments,
+     * where the last source argument is used as a constant. (That is, the
+     * last argument must have a type which indicates it is a known constant.)
+     * The instruction associated must have exactly two sources.
+     *
+     * @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,
+            RegisterSpec sourceA, RegisterSpec sourceB);
+
+    /**
+     * 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 {@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);
+
+    /**
+     * Gets the maximum register width that can be represented optimally.
+     * For example, Dex bytecode does not have instruction forms that take
+     * register numbers larger than 15 for all instructions so
+     * DexTranslationAdvice returns 15 here.
+     *
+     * @return register count noted above
+     */
+    public int getMaxOptimalRegisterCount();
+}
diff --git a/dx/src/com/android/dx/rop/code/package.html b/dx/src/com/android/dx/rop/code/package.html
new file mode 100644
index 0000000..86566b4
--- /dev/null
+++ b/dx/src/com/android/dx/rop/code/package.html
@@ -0,0 +1,8 @@
+<body>
+<p>Classes relating to a register-based opcode system.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/rop/cst/Constant.java b/dx/src/com/android/dx/rop/cst/Constant.java
new file mode 100644
index 0000000..3ef035e
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/Constant.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.util.ToHuman;
+
+/**
+ * Base class for constants of all sorts.
+ */
+public abstract class Constant
+        implements ToHuman, Comparable<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} if this instance is category-1.
+     *
+     * @return {@code true} iff this instance is category-2
+     */
+    public abstract boolean isCategory2();
+
+    /**
+     * Returns the human name for the particular type of constant
+     * this instance is.
+     *
+     * @return {@code non-null;} the name
+     */
+    public abstract String typeName();
+
+    /**
+     * {@inheritDoc}
+     *
+     * This compares in class-major and value-minor order.
+     */
+    public final int compareTo(Constant other) {
+        Class clazz = getClass();
+        Class otherClazz = other.getClass();
+
+        if (clazz != otherClazz) {
+            return clazz.getName().compareTo(otherClazz.getName());
+        }
+
+        return compareTo0(other);
+    }
+
+    /**
+     * Compare the values of this and another instance, which are guaranteed
+     * to be of the same class. Subclasses must implement this.
+     *
+     * @param other {@code non-null;} the instance to compare to
+     * @return {@code -1}, {@code 0}, or {@code 1}, as usual
+     * for a comparison
+     */
+    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
new file mode 100644
index 0000000..efc394d
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/ConstantPool.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Interface for constant pools, which are, more or less, just lists of
+ * {@link Constant} objects.
+ */
+public interface ConstantPool {
+    /**
+     * Get the "size" of the constant pool. This corresponds to the
+     * class file field {@code constant_pool_count}, and is in fact
+     * always at least one more than the actual size of the constant pool,
+     * as element {@code 0} is always invalid.
+     *
+     * @return {@code >= 1;} the size
+     */
+    public int size();
+
+    /**
+     * Get the {@code n}th entry in the constant pool, which must
+     * be valid.
+     *
+     * @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}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();} 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}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} and {@code Double}
+     * entries).
+     *
+     * @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
new file mode 100644
index 0000000..8cdf1df
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstAnnotation.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.annotation.Annotation;
+
+/**
+ * Constant type that represents an annotation.
+ */
+public final class CstAnnotation extends Constant {
+    /** {@code non-null;} the actual annotation */
+    private final Annotation annotation;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param annotation {@code non-null;} the annotation to hold
+     */
+    public CstAnnotation(Annotation annotation) {
+        if (annotation == null) {
+            throw new NullPointerException("annotation == null");
+        }
+
+        annotation.throwIfMutable();
+
+        this.annotation = annotation;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof CstAnnotation)) {
+            return false;
+        }
+
+        return annotation.equals(((CstAnnotation) other).annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return annotation.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return annotation.compareTo(((CstAnnotation) other).annotation);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return annotation.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "annotation";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return annotation.toString();
+    }
+
+    /**
+     * Get the underlying 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
new file mode 100644
index 0000000..2766b5f
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstArray.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * Constant type to represent a fixed array of other constants.
+ */
+public final class CstArray extends Constant {
+    /** {@code non-null;} the actual list of contents */
+    private final List list;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param list {@code non-null;} the actual list of contents
+     */
+    public CstArray(List list) {
+        if (list == null) {
+            throw new NullPointerException("list == null");
+        }
+
+        list.throwIfMutable();
+
+        this.list = list;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (! (other instanceof CstArray)) {
+            return false;
+        }
+
+        return list.equals(((CstArray) other).list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return list.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return list.compareTo(((CstArray) other).list);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return list.toString("array{", ", ", "}");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "array";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return list.toHuman("{", ", ", "}");
+    }
+
+    /**
+     * Get the underlying list.
+     *
+     * @return {@code non-null;} the list
+     */
+    public List getList() {
+        return list;
+    }
+
+    /**
+     * List of {@link Constant} instances.
+     */
+    public static final class List
+            extends FixedSizeList implements Comparable<List> {
+        /**
+         * Constructs an instance. All indices initially contain
+         * {@code null}.
+         *
+         * @param size the size of the list
+         */
+        public List(int size) {
+            super(size);
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(List other) {
+            int thisSize = size();
+            int otherSize = other.size();
+            int compareSize = (thisSize < otherSize) ? thisSize : otherSize;
+
+            for (int i = 0; i < compareSize; i++) {
+                Constant thisItem = (Constant) get0(i);
+                Constant otherItem = (Constant) other.get0(i);
+                int compare = thisItem.compareTo(otherItem);
+                if (compare != 0) {
+                    return compare;
+                }
+            }
+
+            if (thisSize < otherSize) {
+                return -1;
+            } else if (thisSize > otherSize) {
+                return 1;
+            }
+
+            return 0;
+        }
+
+        /**
+         * Gets the element at the given index. It is an error to call
+         * this with the index for an element which was never set; if you
+         * do that, this will throw {@code NullPointerException}.
+         *
+         * @param n {@code >= 0, < size();} which index
+         * @return {@code non-null;} element at that index
+         */
+        public Constant get(int n) {
+            return (Constant) get0(n);
+        }
+
+        /**
+         * Sets the element at the given index.
+         *
+         * @param n {@code >= 0, < size();} which index
+         * @param a {@code null-ok;} the element to set at {@code n}
+         */
+        public void set(int n, Constant a) {
+            set0(n, a);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
new file mode 100644
index 0000000..5b0aeb6
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Prototype;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+
+/**
+ * Base class for constants of "methodish" type.
+ *
+ * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type
+ * of the method.</p>
+ */
+public abstract class CstBaseMethodRef
+        extends CstMemberRef {
+    /** {@code non-null;} the raw prototype for this method */
+    private final Prototype prototype;
+
+    /**
+     * {@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 {@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);
+
+        String descriptor = getNat().getDescriptor().getString();
+        this.prototype = Prototype.intern(descriptor);
+        this.instancePrototype = null;
+    }
+
+    /**
+     * Gets the raw prototype of this method. This doesn't include a
+     * {@code this} argument.
+     *
+     * @return {@code non-null;} the method prototype
+     */
+    public final Prototype getPrototype() {
+        return prototype;
+    }
+
+    /**
+     * Gets the prototype of this method as either a
+     * {@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} argument as the first
+     * one.
+     *
+     * @param isStatic whether the method should be considered static
+     * @return {@code non-null;} the method prototype
+     */
+    public final Prototype getPrototype(boolean isStatic) {
+        if (isStatic) {
+            return prototype;
+        } else {
+            if (instancePrototype == null) {
+                Type thisType = getDefiningClass().getClassType();
+                instancePrototype = prototype.withFirstParameter(thisType);
+            }
+            return instancePrototype;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected final int compareTo0(Constant other) {
+        int cmp = super.compareTo0(other);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        CstBaseMethodRef otherMethod = (CstBaseMethodRef) other;
+        return prototype.compareTo(otherMethod.prototype);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * In this case, this method returns the <i>return type</i> of this method.
+     *
+     * @return {@code non-null;} the method's return type
+     */
+    public final Type getType() {
+        return prototype.getReturnType();
+    }
+
+    /**
+     * 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} or
+     * instance context, one has to indicate this explicitly as an
+     * argument. This method is just a convenient shorthand for
+     * {@code getPrototype().getParameterTypes().getWordCount()},
+     * plus {@code 1} if the method is to be treated as an
+     * instance method.
+     *
+     * @param isStatic whether the method should be considered static
+     * @return {@code >= 0;} the argument word count
+     */
+    public final int getParameterWordCount(boolean isStatic) {
+        return getPrototype(isStatic).getParameterTypes().getWordCount();
+    }
+
+    /**
+     * Gets whether this is a reference to an instance initialization
+     * method. This is just a convenient shorthand for
+     * {@code getNat().isInstanceInit()}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isInstanceInit() {
+        return getNat().isInstanceInit();
+    }
+
+    /**
+     * Gets whether this is a reference to a class initialization
+     * method. This is just a convenient shorthand for
+     * {@code getNat().isClassInit()}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isClassInit() {
+        return getNat().isClassInit();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstBoolean.java b/dx/src/com/android/dx/rop/cst/CstBoolean.java
new file mode 100644
index 0000000..5ff858a
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstBoolean.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+/**
+ * Constants of type {@code boolean}.
+ */
+public final class CstBoolean
+        extends CstLiteral32 {
+    /** {@code non-null;} instance representing {@code false} */
+    public static final CstBoolean VALUE_FALSE = new CstBoolean(false);
+
+    /** {@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} 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} value. This
+     * will return an already-allocated instance.
+     *
+     * @param value must be either {@code 0} or {@code 1}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstBoolean make(int value) {
+        if (value == 0) {
+            return VALUE_FALSE;
+        } else if (value == 1) {
+            return VALUE_TRUE;
+        } else {
+            throw new IllegalArgumentException("bogus value: " + value);
+        }
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code boolean} value
+     */
+    private CstBoolean(boolean value) {
+        super(value ? 1 : 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return getValue() ? "boolean{true}" : "boolean{false}";
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.BOOLEAN;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "boolean";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return getValue() ? "true" : "false";
+    }
+
+    /**
+     * Gets the {@code boolean} value.
+     *
+     * @return the value
+     */
+    public boolean getValue() {
+        return (getIntBits() == 0) ? false : true;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstByte.java b/dx/src/com/android/dx/rop/cst/CstByte.java
new file mode 100644
index 0000000..fc8f58f
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstByte.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code byte}.
+ */
+public final class CstByte
+        extends CstLiteral32 {
+    /** {@code non-null;} the value {@code 0} as an instance of this class */
+    public static final CstByte VALUE_0 = make((byte) 0);
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param value the {@code byte} value
+     */
+    public static CstByte make(byte value) {
+        return new CstByte(value);
+    }
+
+    /**
+     * Makes an instance for the given {@code int} value. This
+     * may (but does not necessarily) return an already-allocated
+     * instance.
+     *
+     * @param value the value, which must be in range for a {@code byte}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstByte make(int value) {
+        byte cast = (byte) value;
+
+        if (cast != value) {
+            throw new IllegalArgumentException("bogus byte value: " +
+                    value);
+        }
+
+        return make(cast);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code byte} value
+     */
+    private CstByte(byte value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "byte{0x" + Hex.u1(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.BYTE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "byte";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code byte} value.
+     *
+     * @return the value
+     */
+    public byte getValue() {
+        return (byte) getIntBits();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstChar.java b/dx/src/com/android/dx/rop/cst/CstChar.java
new file mode 100644
index 0000000..21d8b67
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstChar.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code char}.
+ */
+public final class CstChar
+        extends CstLiteral32 {
+    /** {@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} value
+     */
+    public static CstChar make(char value) {
+        return new CstChar(value);
+    }
+
+    /**
+     * Makes an instance for the given {@code int} value. This
+     * may (but does not necessarily) return an already-allocated
+     * instance.
+     *
+     * @param value the value, which must be in range for a {@code char}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstChar make(int value) {
+        char cast = (char) value;
+
+        if (cast != value) {
+            throw new IllegalArgumentException("bogus char value: " +
+                    value);
+        }
+
+        return make(cast);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code char} value
+     */
+    private CstChar(char value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "char{0x" + Hex.u2(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.CHAR;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "char";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code char} value.
+     *
+     * @return the value
+     */
+    public char getValue() {
+        return (char) getIntBits();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstDouble.java b/dx/src/com/android/dx/rop/cst/CstDouble.java
new file mode 100644
index 0000000..8f1766f
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstDouble.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Double_info}.
+ */
+public final class CstDouble
+        extends CstLiteral64 {
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstDouble VALUE_0 =
+        new CstDouble(Double.doubleToLongBits(0.0));
+
+    /** {@code non-null;} instance representing {@code 1} */
+    public static final CstDouble VALUE_1 =
+        new CstDouble(Double.doubleToLongBits(1.0));
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param bits the {@code double} value as {@code long} bits
+     */
+    public static CstDouble make(long bits) {
+        /*
+         * Note: Javadoc notwithstanding, this implementation always
+         * allocates.
+         */
+        return new CstDouble(bits);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param bits the {@code double} value as {@code long} bits
+     */
+    private CstDouble(long bits) {
+        super(bits);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        long bits = getLongBits();
+        return "double{0x" + Hex.u8(bits) + " / " +
+            Double.longBitsToDouble(bits) + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.DOUBLE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "double";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Double.toString(Double.longBitsToDouble(getLongBits()));
+    }
+
+    /**
+     * Gets the {@code double} value.
+     *
+     * @return the value
+     */
+    public double getValue() {
+        return Double.longBitsToDouble(getLongBits());
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstEnumRef.java b/dx/src/com/android/dx/rop/cst/CstEnumRef.java
new file mode 100644
index 0000000..641ab3f
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstEnumRef.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+/**
+ * Constant type to represent a reference to a particular constant
+ * value of an enumerated type.
+ */
+public final class CstEnumRef extends CstMemberRef {
+    /** {@code null-ok;} the corresponding field ref, lazily initialized */
+    private CstFieldRef fieldRef;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param nat {@code non-null;} the name-and-type; the defining class is derived
+     * from this
+     */
+    public CstEnumRef(CstNat nat) {
+        super(new CstType(nat.getFieldType()), nat);
+
+        fieldRef = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "enum";
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <b>Note:</b> This returns the enumerated type.
+     */
+    public Type getType() {
+        return getDefiningClass().getClassType();
+    }
+
+    /**
+     * Get a {@link CstFieldRef} that corresponds with this instance.
+     *
+     * @return {@code non-null;} the corresponding field reference
+     */
+    public CstFieldRef getFieldRef() {
+        if (fieldRef == null) {
+            fieldRef = new CstFieldRef(getDefiningClass(), getNat());
+        }
+
+        return fieldRef;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstFieldRef.java b/dx/src/com/android/dx/rop/cst/CstFieldRef.java
new file mode 100644
index 0000000..a4d7180
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstFieldRef.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+/**
+ * Constants of type {@code CONSTANT_Fieldref_info}.
+ */
+public final class CstFieldRef extends CstMemberRef {
+    /**
+     * Returns an instance of this class that represents the static
+     * 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}.
+     *
+     * @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),
+                CstNat.PRIMITIVE_TYPE_NAT);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @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);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "field";
+    }
+
+    /**
+     * Returns the type of this field.
+     *
+     * @return {@code non-null;} the field's type
+     */
+    public Type getType() {
+        return getNat().getFieldType();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        int cmp = super.compareTo0(other);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        CstFieldRef otherField = (CstFieldRef) other;
+        CstString thisDescriptor = getNat().getDescriptor();
+        CstString otherDescriptor = otherField.getNat().getDescriptor();
+        return thisDescriptor.compareTo(otherDescriptor);
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstFloat.java b/dx/src/com/android/dx/rop/cst/CstFloat.java
new file mode 100644
index 0000000..0a2354a
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstFloat.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Float_info}.
+ */
+public final class CstFloat
+        extends CstLiteral32 {
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f));
+
+    /** {@code non-null;} instance representing {@code 1} */
+    public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f));
+
+    /** {@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} value as {@code int} bits
+     */
+    public static CstFloat make(int bits) {
+        /*
+         * Note: Javadoc notwithstanding, this implementation always
+         * allocates.
+         */
+        return new CstFloat(bits);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param bits the {@code float} value as {@code int} bits
+     */
+    private CstFloat(int bits) {
+        super(bits);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int bits = getIntBits();
+        return "float{0x" + Hex.u4(bits) + " / " +
+            Float.intBitsToFloat(bits) + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.FLOAT;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "float";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Float.toString(Float.intBitsToFloat(getIntBits()));
+    }
+
+    /**
+     * Gets the {@code float} value.
+     *
+     * @return the value
+     */
+    public float getValue() {
+        return Float.intBitsToFloat(getIntBits());
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstInteger.java b/dx/src/com/android/dx/rop/cst/CstInteger.java
new file mode 100644
index 0000000..3691fc0
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstInteger.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Integer_info}.
+ */
+public final class CstInteger
+        extends CstLiteral32 {
+    /** {@code non-null;} array of cached instances */
+    private static final CstInteger[] cache = new CstInteger[511];
+
+    /** {@code non-null;} instance representing {@code -1} */
+    public static final CstInteger VALUE_M1 = make(-1);
+
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstInteger VALUE_0 = make(0);
+
+    /** {@code non-null;} instance representing {@code 1} */
+    public static final CstInteger VALUE_1 = make(1);
+
+    /** {@code non-null;} instance representing {@code 2} */
+    public static final CstInteger VALUE_2 = make(2);
+
+    /** {@code non-null;} instance representing {@code 3} */
+    public static final CstInteger VALUE_3 = make(3);
+
+    /** {@code non-null;} instance representing {@code 4} */
+    public static final CstInteger VALUE_4 = make(4);
+
+    /** {@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} value
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstInteger make(int value) {
+        /*
+         * Note: No need to synchronize, since we don't make any sort
+         * of guarantee about ==, and it's okay to overwrite existing
+         * entries too.
+         */
+        int idx = (value & 0x7fffffff) % cache.length;
+        CstInteger obj = cache[idx];
+
+        if ((obj != null) && (obj.getValue() == value)) {
+            return obj;
+        }
+
+        obj = new CstInteger(value);
+        cache[idx] = obj;
+        return obj;
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code int} value
+     */
+    private CstInteger(int value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "int{0x" + Hex.u4(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.INT;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "int";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code int} value.
+     *
+     * @return the value
+     */
+    public int getValue() {
+        return getIntBits();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
new file mode 100644
index 0000000..8b8cb30
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants of type {@code CONSTANT_InterfaceMethodref_info}.
+ */
+public final class CstInterfaceMethodRef
+        extends CstBaseMethodRef {
+    /**
+     * {@code null-ok;} normal {@link CstMethodRef} that corresponds to this
+     * instance, if calculated
+     */
+    private CstMethodRef methodRef;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the type of the defining class
+     * @param nat {@code non-null;} the name-and-type
+     */
+    public CstInterfaceMethodRef(CstType definingClass, CstNat nat) {
+        super(definingClass, nat);
+        methodRef = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "ifaceMethod";
+    }
+
+    /**
+     * Gets a normal (non-interface) {@link CstMethodRef} that corresponds to
+     * this instance.
+     *
+     * @return {@code non-null;} an appropriate instance
+     */
+    public CstMethodRef toMethodRef() {
+        if (methodRef == null) {
+            methodRef = new CstMethodRef(getDefiningClass(), getNat());
+        }
+
+        return methodRef;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstKnownNull.java b/dx/src/com/android/dx/rop/cst/CstKnownNull.java
new file mode 100644
index 0000000..a80322c
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstKnownNull.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+/**
+ * Constant type to represent a known-{@code null} value.
+ */
+public final class CstKnownNull extends CstLiteralBits {
+    /** {@code non-null;} unique instance of this class */
+    public static final CstKnownNull THE_ONE = new CstKnownNull();
+
+    /**
+     * Constructs an instance. This class is not publicly instantiable. Use
+     * {@link #THE_ONE}.
+     */
+    private CstKnownNull() {
+        // This space intentionally left blank.
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        return (other instanceof CstKnownNull);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return 0x4466757a;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "known-null";
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.KNOWN_NULL;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "known-null";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return "null";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean fitsInInt() {
+        // See comment in getIntBits().
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * As "literal bits," a known-null is always represented as the
+     * number zero.
+     */
+    @Override
+    public int getIntBits() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * As "literal bits," a known-null is always represented as the
+     * number zero.
+     */
+    @Override
+    public long getLongBits() {
+        return 0;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral32.java b/dx/src/com/android/dx/rop/cst/CstLiteral32.java
new file mode 100644
index 0000000..042cbd9
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstLiteral32.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants which are literal 32-bit values of some sort.
+ */
+public abstract class CstLiteral32
+        extends CstLiteralBits {
+    /** the value as {@code int} bits */
+    private final int bits;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bits the value as {@code int} bits
+     */
+    /*package*/ CstLiteral32(int bits) {
+        this.bits = bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean equals(Object other) {
+        return (other != null) &&
+            (getClass() == other.getClass()) &&
+            bits == ((CstLiteral32) other).bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int hashCode() {
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        int otherBits = ((CstLiteral32) other).bits;
+
+        if (bits < otherBits) {
+            return -1;
+        } else if (bits > otherBits) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean fitsInInt() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int getIntBits() {
+        return bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final long getLongBits() {
+        return (long) bits;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral64.java b/dx/src/com/android/dx/rop/cst/CstLiteral64.java
new file mode 100644
index 0000000..94cfa8c
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstLiteral64.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants which are literal 64-bit values of some sort.
+ */
+public abstract class CstLiteral64
+        extends CstLiteralBits {
+    /** the value as {@code long} bits */
+    private final long bits;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param bits the value as {@code long} bits
+     */
+    /*package*/ CstLiteral64(long bits) {
+        this.bits = bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean equals(Object other) {
+        return (other != null) &&
+            (getClass() == other.getClass()) &&
+            bits == ((CstLiteral64) other).bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int hashCode() {
+        return (int) bits ^ (int) (bits >> 32);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        long otherBits = ((CstLiteral64) other).bits;
+
+        if (bits < otherBits) {
+            return -1;
+        } else if (bits > otherBits) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean isCategory2() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean fitsInInt() {
+        return (int) bits == bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int getIntBits() {
+        return (int) bits;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final long getLongBits() {
+        return bits;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
new file mode 100644
index 0000000..8bf13a2
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants which are literal bitwise values of some sort.
+ */
+public abstract class CstLiteralBits
+        extends TypedConstant {
+    /**
+     * Returns whether or not this instance's value may be accurately
+     * 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} iff this instance fits in an {@code int}
+     */
+    public abstract boolean fitsInInt();
+
+    /**
+     * 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
+     */
+    public abstract int getIntBits();
+
+    /**
+     * Gets the value as {@code long} bits. If this instance contains
+     * fewer bits than fit in a {@code long}, then the result of this
+     * method is the sign extension of the value.
+     *
+     * @return the bits
+     */
+    public abstract long getLongBits();
+
+    /**
+     * Returns true if this value can fit in 16 bits with sign-extension.
+     *
+     * @return true if the sign-extended lower 16 bits are the same as
+     * the value.
+     */
+    public boolean fitsIn16Bits() {
+        if (! fitsInInt()) {
+            return false;
+        }
+
+        int bits = getIntBits();
+        return (short) bits == bits;
+    }
+
+    /**
+     * Returns true if this value can fit in 8 bits with sign-extension.
+     *
+     * @return true if the sign-extended lower 8 bits are the same as
+     * the value.
+     */
+    public boolean fitsIn8Bits() {
+        if (! fitsInInt()) {
+            return false;
+        }
+
+        int bits = getIntBits();
+        return (byte) bits == bits;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstLong.java b/dx/src/com/android/dx/rop/cst/CstLong.java
new file mode 100644
index 0000000..d159529
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstLong.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Long_info}.
+ */
+public final class CstLong
+        extends CstLiteral64 {
+    /** {@code non-null;} instance representing {@code 0} */
+    public static final CstLong VALUE_0 = make(0);
+
+    /** {@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} value
+     */
+    public static CstLong make(long value) {
+        /*
+         * Note: Javadoc notwithstanding, this implementation always
+         * allocates.
+         */
+        return new CstLong(value);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code long} value
+     */
+    private CstLong(long value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        long value = getLongBits();
+        return "long{0x" + Hex.u8(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.LONG;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "long";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Long.toString(getLongBits());
+    }
+
+    /**
+     * Gets the {@code long} value.
+     *
+     * @return the value
+     */
+    public long getValue() {
+        return getLongBits();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstMemberRef.java b/dx/src/com/android/dx/rop/cst/CstMemberRef.java
new file mode 100644
index 0000000..1775398
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstMemberRef.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants of type {@code CONSTANT_*ref_info}.
+ */
+public abstract class CstMemberRef extends TypedConstant {
+    /** {@code non-null;} the type of the defining class */
+    private final CstType definingClass;
+
+    /** {@code non-null;} the name-and-type */
+    private final CstNat nat;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+            throw new NullPointerException("definingClass == null");
+        }
+
+        if (nat == null) {
+            throw new NullPointerException("nat == null");
+        }
+
+        this.definingClass = definingClass;
+        this.nat = nat;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean equals(Object other) {
+        if ((other == null) || (getClass() != other.getClass())) {
+            return false;
+        }
+
+        CstMemberRef otherRef = (CstMemberRef) other;
+        return definingClass.equals(otherRef.definingClass) &&
+            nat.equals(otherRef.nat);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final int hashCode() {
+        return (definingClass.hashCode() * 31) ^ nat.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <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()}.</p>
+     */
+    @Override
+    protected int compareTo0(Constant other) {
+        CstMemberRef otherMember = (CstMemberRef) other;
+        int cmp = definingClass.compareTo(otherMember.definingClass);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        CstString thisName = nat.getName();
+        CstString otherName = otherMember.nat.getName();
+
+        return thisName.compareTo(otherName);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final String toString() {
+        return typeName() + '{' + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public final String toHuman() {
+        return definingClass.toHuman() + '.' + nat.toHuman();
+    }
+
+    /**
+     * Gets the type of the defining class.
+     *
+     * @return {@code non-null;} the type of defining class
+     */
+    public final CstType getDefiningClass() {
+        return definingClass;
+    }
+
+    /**
+     * Gets the defining 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
new file mode 100644
index 0000000..075bc7c
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstMethodRef.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants of type {@code CONSTANT_Methodref_info}.
+ */
+public final class CstMethodRef
+        extends CstBaseMethodRef {
+    /**
+     * Constructs an instance.
+     *
+     * @param definingClass {@code non-null;} the type of the defining class
+     * @param nat {@code non-null;} the name-and-type
+     */
+    public CstMethodRef(CstType definingClass, CstNat nat) {
+        super(definingClass, nat);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "method";
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstNat.java b/dx/src/com/android/dx/rop/cst/CstNat.java
new file mode 100644
index 0000000..cd067e9
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstNat.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+/**
+ * Constants of type {@code CONSTANT_NameAndType_info}.
+ */
+public final class CstNat extends Constant {
+    /**
+     * {@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 CstString("TYPE"),
+                   new CstString("Ljava/lang/Class;"));
+
+    /** {@code non-null;} the name */
+    private final CstString name;
+
+    /** {@code non-null;} the descriptor (type) */
+    private final CstString descriptor;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param name {@code non-null;} the name
+     * @param descriptor {@code non-null;} the descriptor
+     */
+    public CstNat(CstString name, CstString descriptor) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        this.name = name;
+        this.descriptor = descriptor;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstNat)) {
+            return false;
+        }
+
+        CstNat otherNat = (CstNat) other;
+        return name.equals(otherNat.name) &&
+            descriptor.equals(otherNat.descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return (name.hashCode() * 31) ^ descriptor.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        CstNat otherNat = (CstNat) other;
+        int cmp = name.compareTo(otherNat.name);
+
+        if (cmp != 0) {
+            return cmp;
+        }
+
+        return descriptor.compareTo(otherNat.descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "nat{" + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "nat";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /**
+     * Gets the name.
+     *
+     * @return {@code non-null;} the name
+     */
+    public CstString getName() {
+        return name;
+    }
+
+    /**
+     * Gets the descriptor.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public CstString getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Returns an unadorned but human-readable version of the name-and-type
+     * value.
+     *
+     * @return {@code non-null;} the human form
+     */
+    public String toHuman() {
+        return name.toHuman() + ':' + descriptor.toHuman();
+    }
+
+    /**
+     * Gets the field type corresponding to this instance's descriptor.
+     * This method is only valid to call if the descriptor in fact describes
+     * a field (and not a method).
+     *
+     * @return {@code non-null;} the field type
+     */
+    public Type getFieldType() {
+        return Type.intern(descriptor.getString());
+    }
+
+    /**
+     * Gets whether this instance has the name of a standard instance
+     * initialization method. This is just a convenient shorthand for
+     * {@code getName().getString().equals("<init>")}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isInstanceInit() {
+        return name.getString().equals("<init>");
+    }
+
+    /**
+     * Gets whether this instance has the name of a standard class
+     * initialization method. This is just a convenient shorthand for
+     * {@code getName().getString().equals("<clinit>")}.
+     *
+     * @return {@code true} iff this is a reference to an
+     * instance initialization method
+     */
+    public final boolean isClassInit() {
+        return name.getString().equals("<clinit>");
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstShort.java b/dx/src/com/android/dx/rop/cst/CstShort.java
new file mode 100644
index 0000000..5be1022
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstShort.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code short}.
+ */
+public final class CstShort
+        extends CstLiteral32 {
+    /** {@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} 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} value. This
+     * may (but does not necessarily) return an already-allocated
+     * instance.
+     *
+     * @param value the value, which must be in range for a {@code short}
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstShort make(int value) {
+        short cast = (short) value;
+
+        if (cast != value) {
+            throw new IllegalArgumentException("bogus short value: " +
+                    value);
+        }
+
+        return make(cast);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param value the {@code short} value
+     */
+    private CstShort(short value) {
+        super(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        int value = getIntBits();
+        return "short{0x" + Hex.u2(value) + " / " + value + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.SHORT;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "short";
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return Integer.toString(getIntBits());
+    }
+
+    /**
+     * Gets the {@code short} value.
+     *
+     * @return the value
+     */
+    public short getValue() {
+        return (short) getIntBits();
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstString.java b/dx/src/com/android/dx/rop/cst/CstString.java
new file mode 100644
index 0000000..a778e97
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstString.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.ByteArray;
+import com.android.dx.util.Hex;
+
+/**
+ * Constants of type {@code CONSTANT_Utf8_info} or {@code CONSTANT_String_info}.
+ */
+public final class CstString extends TypedConstant {
+    /**
+     * {@code non-null;} instance representing {@code ""}, that is, the
+     * empty string
+     */
+    public static final CstString EMPTY_STRING = new CstString("");
+
+    /** {@code non-null;} the UTF-8 value as a string */
+    private final String string;
+
+    /** {@code non-null;} the UTF-8 value as bytes */
+    private final ByteArray bytes;
+
+    /**
+     * Converts a string into its MUTF-8 form. MUTF-8 differs from normal UTF-8
+     * in the handling of character '\0' and surrogate pairs.
+     *
+     * @param string {@code non-null;} the string to convert
+     * @return {@code non-null;} the UTF-8 bytes for it
+     */
+    public static byte[] stringToUtf8Bytes(String string) {
+        int len = string.length();
+        byte[] bytes = new byte[len * 3]; // Avoid having to reallocate.
+        int outAt = 0;
+
+        for (int i = 0; i < len; i++) {
+            char c = string.charAt(i);
+            if ((c != 0) && (c < 0x80)) {
+                bytes[outAt] = (byte) c;
+                outAt++;
+            } else if (c < 0x800) {
+                bytes[outAt] = (byte) (((c >> 6) & 0x1f) | 0xc0);
+                bytes[outAt + 1] = (byte) ((c & 0x3f) | 0x80);
+                outAt += 2;
+            } else {
+                bytes[outAt] = (byte) (((c >> 12) & 0x0f) | 0xe0);
+                bytes[outAt + 1] = (byte) (((c >> 6) & 0x3f) | 0x80);
+                bytes[outAt + 2] = (byte) ((c & 0x3f) | 0x80);
+                outAt += 3;
+            }
+        }
+
+        byte[] result = new byte[outAt];
+        System.arraycopy(bytes, 0, result, 0, outAt);
+        return result;
+    }
+
+    /**
+     * Converts an array of UTF-8 bytes into a string.
+     *
+     * @param bytes {@code non-null;} the bytes to convert
+     * @return {@code non-null;} the converted string
+     */
+    public static String utf8BytesToString(ByteArray bytes) {
+        int length = bytes.size();
+        char[] chars = new char[length]; // This is sized to avoid a realloc.
+        int outAt = 0;
+
+        for (int at = 0; length > 0; /*at*/) {
+            int v0 = bytes.getUnsignedByte(at);
+            char out;
+            switch (v0 >> 4) {
+                case 0x00: case 0x01: case 0x02: case 0x03:
+                case 0x04: case 0x05: case 0x06: case 0x07: {
+                    // 0XXXXXXX -- single-byte encoding
+                    length--;
+                    if (v0 == 0) {
+                        // A single zero byte is illegal.
+                        return throwBadUtf8(v0, at);
+                    }
+                    out = (char) v0;
+                    at++;
+                    break;
+                }
+                case 0x0c: case 0x0d: {
+                    // 110XXXXX -- two-byte encoding
+                    length -= 2;
+                    if (length < 0) {
+                        return throwBadUtf8(v0, at);
+                    }
+                    int v1 = bytes.getUnsignedByte(at + 1);
+                    if ((v1 & 0xc0) != 0x80) {
+                        return throwBadUtf8(v1, at + 1);
+                    }
+                    int value = ((v0 & 0x1f) << 6) | (v1 & 0x3f);
+                    if ((value != 0) && (value < 0x80)) {
+                        /*
+                         * This should have been represented with
+                         * one-byte encoding.
+                         */
+                        return throwBadUtf8(v1, at + 1);
+                    }
+                    out = (char) value;
+                    at += 2;
+                    break;
+                }
+                case 0x0e: {
+                    // 1110XXXX -- three-byte encoding
+                    length -= 3;
+                    if (length < 0) {
+                        return throwBadUtf8(v0, at);
+                    }
+                    int v1 = bytes.getUnsignedByte(at + 1);
+                    if ((v1 & 0xc0) != 0x80) {
+                        return throwBadUtf8(v1, at + 1);
+                    }
+                    int v2 = bytes.getUnsignedByte(at + 2);
+                    if ((v1 & 0xc0) != 0x80) {
+                        return throwBadUtf8(v2, at + 2);
+                    }
+                    int value = ((v0 & 0x0f) << 12) | ((v1 & 0x3f) << 6) |
+                        (v2 & 0x3f);
+                    if (value < 0x800) {
+                        /*
+                         * This should have been represented with one- or
+                         * two-byte encoding.
+                         */
+                        return throwBadUtf8(v2, at + 2);
+                    }
+                    out = (char) value;
+                    at += 3;
+                    break;
+                }
+                default: {
+                    // 10XXXXXX, 1111XXXX -- illegal
+                    return throwBadUtf8(v0, at);
+                }
+            }
+            chars[outAt] = out;
+            outAt++;
+        }
+
+        return new String(chars, 0, outAt);
+    }
+
+    /**
+     * Helper for {@link #utf8BytesToString}, which throws the right
+     * exception for a bogus utf-8 byte.
+     *
+     * @param value the byte value
+     * @param offset the file offset
+     * @return never
+     * @throws IllegalArgumentException always thrown
+     */
+    private static String throwBadUtf8(int value, int offset) {
+        throw new IllegalArgumentException("bad utf-8 byte " + Hex.u1(value) +
+                                           " at offset " + Hex.u4(offset));
+    }
+
+    /**
+     * Constructs an instance from a {@code String}.
+     *
+     * @param string {@code non-null;} the UTF-8 value as a string
+     */
+    public CstString(String string) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        this.string = string.intern();
+        this.bytes = new ByteArray(stringToUtf8Bytes(string));
+    }
+
+    /**
+     * Constructs an instance from some UTF-8 bytes.
+     *
+     * @param bytes {@code non-null;} array of the UTF-8 bytes
+     */
+    public CstString(ByteArray bytes) {
+        if (bytes == null) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        this.bytes = bytes;
+        this.string = utf8BytesToString(bytes).intern();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstString)) {
+            return false;
+        }
+
+        return string.equals(((CstString) other).string);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return string.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        return string.compareTo(((CstString) other).string);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "string{\"" + toHuman() + "\"}";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "utf8";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        int len = string.length();
+        StringBuilder sb = new StringBuilder(len * 3 / 2);
+
+        for (int i = 0; i < len; i++) {
+            char c = string.charAt(i);
+            if ((c >= ' ') && (c < 0x7f)) {
+                if ((c == '\'') || (c == '\"') || (c == '\\')) {
+                    sb.append('\\');
+                }
+                sb.append(c);
+            } else if (c <= 0x7f) {
+                switch (c) {
+                    case '\n': sb.append("\\n"); break;
+                    case '\r': sb.append("\\r"); break;
+                    case '\t': sb.append("\\t"); break;
+                    default: {
+                        /*
+                         * Represent the character as an octal escape.
+                         * If the next character is a valid octal
+                         * digit, disambiguate by using the
+                         * three-digit form.
+                         */
+                        char nextChar =
+                            (i < (len - 1)) ? string.charAt(i + 1) : 0;
+                        boolean displayZero =
+                            (nextChar >= '0') && (nextChar <= '7');
+                        sb.append('\\');
+                        for (int shift = 6; shift >= 0; shift -= 3) {
+                            char outChar = (char) (((c >> shift) & 7) + '0');
+                            if ((outChar != '0') || displayZero) {
+                                sb.append(outChar);
+                                displayZero = true;
+                            }
+                        }
+                        if (! displayZero) {
+                            // Ironic edge case: The original value was 0.
+                            sb.append('0');
+                        }
+                        break;
+                    }
+                }
+            } else {
+                sb.append("\\u");
+                sb.append(Character.forDigit(c >> 12, 16));
+                sb.append(Character.forDigit((c >> 8) & 0x0f, 16));
+                sb.append(Character.forDigit((c >> 4) & 0x0f, 16));
+                sb.append(Character.forDigit(c & 0x0f, 16));
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the value as a human-oriented string, surrounded by double
+     * quotes.
+     *
+     * @return {@code non-null;} the quoted string
+     */
+    public String toQuoted() {
+        return '\"' + toHuman() + '\"';
+    }
+
+    /**
+     * Gets the value as a human-oriented string, surrounded by double
+     * quotes, but ellipsizes the result if it is longer than the given
+     * maximum length
+     *
+     * @param maxLength {@code >= 5;} the maximum length of the string to return
+     * @return {@code non-null;} the quoted string
+     */
+    public String toQuoted(int maxLength) {
+        String string = toHuman();
+        int length = string.length();
+        String ellipses;
+
+        if (length <= (maxLength - 2)) {
+            ellipses = "";
+        } else {
+            string = string.substring(0, maxLength - 5);
+            ellipses = "...";
+        }
+
+        return '\"' + string + ellipses + '\"';
+    }
+
+    /**
+     * Gets the UTF-8 value as a string.
+     * The returned string is always already interned.
+     *
+     * @return {@code non-null;} the UTF-8 value as a string
+     */
+    public String getString() {
+        return string;
+    }
+
+    /**
+     * Gets the UTF-8 value as UTF-8 encoded bytes.
+     *
+     * @return {@code non-null;} an array of the UTF-8 bytes
+     */
+    public ByteArray getBytes() {
+        return bytes;
+    }
+
+    /**
+     * Gets the size of this instance as UTF-8 code points. That is,
+     * get the number of bytes in the UTF-8 encoding of this instance.
+     *
+     * @return {@code >= 0;} the UTF-8 size
+     */
+    public int getUtf8Size() {
+        return bytes.size();
+    }
+
+    /**
+     * 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} of the
+     * Java {@code String} representation of this instance.
+     *
+     * @return {@code >= 0;} the UTF-16 size
+     */
+    public int getUtf16Size() {
+        return string.length();
+    }
+
+    public Type getType() {
+        return Type.STRING;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstType.java b/dx/src/com/android/dx/rop/cst/CstType.java
new file mode 100644
index 0000000..8624028
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstType.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+import java.util.HashMap;
+
+/**
+ * Constants that represent an arbitrary type (reference or primitive).
+ */
+public final class CstType extends TypedConstant {
+    /** {@code non-null;} map of interned types */
+    private static final HashMap<Type, CstType> interns =
+        new HashMap<Type, CstType>(100);
+
+    /** {@code non-null;} instance corresponding to the class {@code Object} */
+    public static final CstType OBJECT = intern(Type.OBJECT);
+
+    /** {@code non-null;} instance corresponding to the class {@code Boolean} */
+    public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Byte} */
+    public static final CstType BYTE = intern(Type.BYTE_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Character} */
+    public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Double} */
+    public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Float} */
+    public static final CstType FLOAT = intern(Type.FLOAT_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Long} */
+    public static final CstType LONG = intern(Type.LONG_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Integer} */
+    public static final CstType INTEGER = intern(Type.INTEGER_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Short} */
+    public static final CstType SHORT = intern(Type.SHORT_CLASS);
+
+    /** {@code non-null;} instance corresponding to the class {@code Void} */
+    public static final CstType VOID = intern(Type.VOID_CLASS);
+
+    /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
+    public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code byte[]} */
+    public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code char[]} */
+    public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code double[]} */
+    public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code float[]} */
+    public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code long[]} */
+    public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code int[]} */
+    public static final CstType INT_ARRAY = intern(Type.INT_ARRAY);
+
+    /** {@code non-null;} instance corresponding to the type {@code short[]} */
+    public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY);
+
+    /** {@code non-null;} the underlying type */
+    private final Type type;
+
+    /**
+     * {@code null-ok;} the type descriptor corresponding to this instance, if
+     * calculated
+     */
+    private CstString descriptor;
+
+    /**
+     * 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}.
+     *
+     * @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()) {
+            case Type.BT_BOOLEAN: return BOOLEAN;
+            case Type.BT_BYTE:    return BYTE;
+            case Type.BT_CHAR:    return CHARACTER;
+            case Type.BT_DOUBLE:  return DOUBLE;
+            case Type.BT_FLOAT:   return FLOAT;
+            case Type.BT_INT:     return INTEGER;
+            case Type.BT_LONG:    return LONG;
+            case Type.BT_SHORT:   return SHORT;
+            case Type.BT_VOID:    return VOID;
+        }
+
+        throw new IllegalArgumentException("not primitive: " + primitiveType);
+    }
+
+    /**
+     * Returns an interned instance of this class for the given type.
+     *
+     * @param type {@code non-null;} the underlying type
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static CstType intern(Type type) {
+        synchronized (interns) {
+            CstType cst = interns.get(type);
+
+            if (cst == null) {
+                cst = new CstType(type);
+                interns.put(type, cst);
+            }
+
+            return cst;
+        }
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param type {@code non-null;} the underlying type
+     */
+    public CstType(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (type == type.KNOWN_NULL) {
+            throw new UnsupportedOperationException(
+                    "KNOWN_NULL is not representable");
+        }
+
+        this.type = type;
+        this.descriptor = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof CstType)) {
+            return false;
+        }
+
+        return type == ((CstType) other).type;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return type.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected int compareTo0(Constant other) {
+        String thisDescriptor = type.getDescriptor();
+        String otherDescriptor = ((CstType) other).type.getDescriptor();
+        return thisDescriptor.compareTo(otherDescriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "type{" + toHuman() + '}';
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return Type.CLASS;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "type";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return type.toHuman();
+    }
+
+    /**
+     * Gets the underlying type (as opposed to the type corresponding
+     * to this instance as a constant, which is always
+     * {@code Class}).
+     *
+     * @return {@code non-null;} the type corresponding to the name
+     */
+    public Type getClassType() {
+        return type;
+    }
+
+    /**
+     * Gets the type descriptor for this instance.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public CstString getDescriptor() {
+        if (descriptor == null) {
+            descriptor = new CstString(type.getDescriptor());
+        }
+
+        return descriptor;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/StdConstantPool.java b/dx/src/com/android/dx/rop/cst/StdConstantPool.java
new file mode 100644
index 0000000..244395d
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/StdConstantPool.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.util.ExceptionWithContext;
+import com.android.dx.util.Hex;
+import com.android.dx.util.MutabilityControl;
+
+/**
+ * Standard implementation of {@link ConstantPool}, which directly stores
+ * an array of {@link Constant} objects and can be made immutable.
+ */
+public final class StdConstantPool
+        extends MutabilityControl implements ConstantPool {
+    /** {@code non-null;} array of entries */
+    private final Constant[] entries;
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the pool; this corresponds to the
+     * class file field {@code constant_pool_count}, and is in fact
+     * always at least one more than the actual size of the constant pool,
+     * as element {@code 0} is always invalid.
+     */
+    public StdConstantPool(int size) {
+        super(size > 1);
+
+        if (size < 1) {
+            throw new IllegalArgumentException("size < 1");
+        }
+
+        entries = new Constant[size];
+    }
+
+    /** {@inheritDoc} */
+    public int size() {
+        return entries.length;
+    }
+
+    /** {@inheritDoc} */
+    public Constant getOrNull(int n) {
+        try {
+            return entries[n];
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            return throwInvalid(n);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public Constant get0Ok(int n) {
+        if (n == 0) {
+            return null;
+        }
+
+        return get(n);
+    }
+
+    /** {@inheritDoc} */
+    public Constant get(int n) {
+        try {
+            Constant result = entries[n];
+
+            if (result == null) {
+                throwInvalid(n);
+            }
+
+            return result;
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            return throwInvalid(n);
+        }
+    }
+
+    /**
+     * Sets the entry at the given index.
+     *
+     * @param n {@code >= 1, < size();} which entry
+     * @param cst {@code null-ok;} the constant to store
+     */
+    public void set(int n, Constant cst) {
+        throwIfImmutable();
+
+        boolean cat2 = (cst != null) && cst.isCategory2();
+
+        if (n < 1) {
+            throw new IllegalArgumentException("n < 1");
+        }
+
+        if (cat2) {
+            // Storing a category-2 entry nulls out the next index.
+            if (n == (entries.length - 1)) {
+                throw new IllegalArgumentException("(n == size - 1) && " +
+                                                   "cst.isCategory2()");
+            }
+            entries[n + 1] = null;
+        }
+
+        if ((cst != null) && (entries[n] == null)) {
+            /*
+             * Overwriting the second half of a category-2 entry nulls out
+             * the first half.
+             */
+            Constant prev = entries[n - 1];
+            if ((prev != null) && prev.isCategory2()) {
+                entries[n - 1] = null;
+            }
+        }
+
+        entries[n] = cst;
+    }
+
+    /**
+     * Throws the right exception for an invalid cpi.
+     *
+     * @param idx the bad cpi
+     * @return never
+     * @throws ExceptionWithContext always thrown
+     */
+    private static Constant throwInvalid(int idx) {
+        throw new ExceptionWithContext("invalid constant pool index " +
+                                       Hex.u2(idx));
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/TypedConstant.java b/dx/src/com/android/dx/rop/cst/TypedConstant.java
new file mode 100644
index 0000000..1c738ee
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/TypedConstant.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.TypeBearer;
+
+/**
+ * Base class for constants which implement {@link TypeBearer}.
+ */
+public abstract class TypedConstant
+        extends Constant implements TypeBearer {
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation always returns {@code this}.
+     */
+    public final TypeBearer getFrameType() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicType() {
+        return getType().getBasicType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicFrameType() {
+        return getType().getBasicFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final boolean isConstant() {
+        return true;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/Zeroes.java b/dx/src/com/android/dx/rop/cst/Zeroes.java
new file mode 100644
index 0000000..7250b5a
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/Zeroes.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Type;
+
+/**
+ * Utility for turning types into zeroes.
+ */
+public final class Zeroes {
+    /**
+     * This class is uninstantiable.
+     */
+    private Zeroes() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the "zero" (or {@code null}) value for the given type.
+     *
+     * @param type {@code non-null;} the type in question
+     * @return {@code non-null;} its "zero" value
+     */
+    public static Constant zeroFor(Type type) {
+        switch (type.getBasicType()) {
+            case Type.BT_BOOLEAN: return CstBoolean.VALUE_FALSE;
+            case Type.BT_BYTE:    return CstByte.VALUE_0;
+            case Type.BT_CHAR:    return CstChar.VALUE_0;
+            case Type.BT_DOUBLE:  return CstDouble.VALUE_0;
+            case Type.BT_FLOAT:   return CstFloat.VALUE_0;
+            case Type.BT_INT:     return CstInteger.VALUE_0;
+            case Type.BT_LONG:    return CstLong.VALUE_0;
+            case Type.BT_SHORT:   return CstShort.VALUE_0;
+            case Type.BT_OBJECT:  return CstKnownNull.THE_ONE;
+            default: {
+                throw new UnsupportedOperationException("no zero for type: " +
+                        type.toHuman());
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/package.html b/dx/src/com/android/dx/rop/cst/package.html
new file mode 100644
index 0000000..c784d16
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/package.html
@@ -0,0 +1,9 @@
+<body>
+<p>Interfaces and implementation of things related to the constant pool.</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.rop.type</code></li>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/rop/package-info.java b/dx/src/com/android/dx/rop/package-info.java
new file mode 100644
index 0000000..aaf21ee
--- /dev/null
+++ b/dx/src/com/android/dx/rop/package-info.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop;
+
+/**
+ * <h1>An Introduction to Rop Form</h1>
+ *
+ * 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
+ * graph in a reasonably programmatically useful form while closely mirroring
+ * the dex instruction set.<p>
+ *
+ * <h2>Key Classes</h2>
+ *
+ * <ul>
+ * <li> {@link RopMethod}, the representation of an individual method
+ * <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} 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} instances are singletons defined in static fields in
+ * {@link Rops}. The rest are constructed dynamically using static methods
+ * 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.
+ * <li> {@link Type} instances represent the core data types that can be
+ * handled by the abstract machine.
+ * <li> The {@link TypeBearer} interface is implemented by classes that
+ * represent a core data type, but may also have secondary information
+ * (such as constant value) associated with them.
+ * <ul>
+ *
+ * <h2>Control-Flow Graph</h2>
+ *
+ * Each method is separated into a list of basic blocks. For the most part,
+ * basic blocks are referred to by a positive integer
+ * {@link BasicBlock#getLabel label}, which is always unique per method. The
+ * label value is typically derived from a bytecode address from the source
+ * 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} 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>
+ *
+ * A method has a single {@link RopMethod#getFirstLabel entry block} and 0
+ * to N {@link RopMethod#getExitPredecessors exit predecessor blocks} which
+ * will return. All blocks that are not the entry block will have at least
+ * one predecessor (or are unreachable and should be removed from the block
+ * list). All blocks that are not exit predecessors must have at least one
+ * successor.<p>
+ *
+ * Since all blocks must branch, all blocks must have, as their final
+ * instruction, an instruction whose opcode has a {@link Rop#getBranchingness
+ * branchingness} other than {@link Rop.BRANCH_NONE}. Furthermore, branching
+ * instructions may only be the final instruction in any basic block. If
+ * no other terminating opcode is appropriate, use a {@link Rops#GOTO GOTO}.<p>
+ *
+ * Typically a block will have a {@link BasicBlock#getPrimarySuccessor
+ * primary successor} which distinguishes a particular control flow path.
+ * For {Rops#isCallLike}call or call-like} opcodes, this is the path taken
+ * in the non-exceptional case, where all other successors represent
+ * various exception paths. For comparison operators such as
+ * {@link Rops#IF_EQZ_INT}, the primary successor represents the path taken
+ * if the <b>condition evaluates to false</b>. For {@link SwitchInsn switch
+ * instructions}, the primary successor is the default case.<p>
+ *
+ * A basic block's successor list is ordered and may refer to unique labels
+ * multiple times. For example, if a switch statement contains multiple case
+ * statements for the same code path, a single basic block will likely
+ * appear in the successor list multiple times. In general, the
+ * significance of the successor list's order (like the significance of
+ * the primary successor) is a property of the final instruction of the basic
+ * block. A basic block containing a {@link ThrowingInsn}, for example, has
+ * its successor list in an order identical to the
+ * {@link ThrowingInsn#getCatches} instruction's catches list, with the
+ * primary successor (the no-exception case) listed at the end.
+ *
+ * It is legal for a basic block to have no primary successor. An obvious
+ * example of this is a block that terminates in a {@link Rops#THROW throw}
+ * 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}.
+ *
+ * <h2>Rop Instructions</h2>
+ *
+ * <h3>move-result and move-result-pseudo</h3>
+ *
+ * An instruction that may throw an exception may not specify a result. This
+ * is necessary because the result register will not be assigned to if an
+ * exception occurs while processing said instruction and a result assignment
+ * may not occur. Since result assignments only occur in the non-exceptional
+ * case,  the result assignments for throwing instructions can be said to occur
+ * at the beginning of the primary successor block rather than at the end of
+ * the current block. The Rop form represents the result assignments this way.
+ * Throwing instructions may not directly specify results. Instead, result
+ * assignments are represented by {@link
+ * 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} 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} 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} 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} instruction is not found
+ * during conversion to dex bytecode, an exception will be thrown.
+ *
+ * <h3>move-exception</h3>
+ *
+ * A {@link RegOps.MOVE_EXCEPTION move-exception} instruction may appear at
+ * the start of a catch block, and represents the obtaining of the thrown
+ * exception instance. It may only occur as the first instruction in a
+ * basic block, and any basic block in which it occurs must be reachable only
+ * as an exception successor.
+ *
+ * <h3>move-param</h3>
+ *
+ * A {@link RegOps.MOVE_PARAM move-param} instruction represents a method
+ * 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} 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}
+ * 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} 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>
+ *
+ * In a typical case, a local variable's lifetime begins with an
+ * assignment. The local variable whose information is present in a result's
+ * {@link RegisterSpec#getLocalItem LocalItem} is considered to begin (or move
+ * between registers) when the instruction is executed.<p>
+ *
+ * However, sometimes a local variable can begin its life or move without
+ * an assignment occurring. A common example of this is occurs in the Rop
+ * representation of the following code:<p>
+ *
+ * <pre>
+ * try {
+ *     Object foo = null;
+ *     foo = new Object();
+ * } catch (Throwable ex) { }
+ * </pre>
+ *
+ * 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}
+ * 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
new file mode 100644
index 0000000..3fc5d82
--- /dev/null
+++ b/dx/src/com/android/dx/rop/type/Prototype.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.type;
+
+import java.util.HashMap;
+
+/**
+ * Representation of a method descriptor. Instances of this class are
+ * generally interned and may be usefully compared with each other
+ * using {@code ==}.
+ */
+public final class Prototype implements Comparable<Prototype> {
+    /** {@code non-null;} intern table mapping string descriptors to instances */
+    private static final HashMap<String, Prototype> internTable =
+        new HashMap<String, Prototype>(500);
+
+    /** {@code non-null;} method descriptor */
+    private final String descriptor;
+
+    /** {@code non-null;} return type */
+    private final Type returnType;
+
+    /** {@code non-null;} list of parameter types */
+    private final StdTypeList parameterTypes;
+
+    /** {@code null-ok;} list of parameter frame types, if calculated */
+    private StdTypeList parameterFrameTypes;
+
+    /**
+     * Returns the unique instance corresponding to the
+     * given method descriptor. See vmspec-2 sec4.3.3 for details on the
+     * field descriptor syntax.
+     *
+     * @param descriptor {@code non-null;} the descriptor
+     * @return {@code non-null;} the corresponding instance
+     * @throws IllegalArgumentException thrown if the descriptor has
+     * invalid syntax
+     */
+    public static Prototype intern(String descriptor) {
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        Prototype result;
+        synchronized (internTable) {
+            result = internTable.get(descriptor);
+        }
+        if (result != null) {
+            return result;
+        }
+
+        Type[] params = makeParameterArray(descriptor);
+        int paramCount = 0;
+        int at = 1;
+
+        for (;;) {
+            int startAt = at;
+            char c = descriptor.charAt(at);
+            if (c == ')') {
+                at++;
+                break;
+            }
+
+            // Skip array markers.
+            while (c == '[') {
+                at++;
+                c = descriptor.charAt(at);
+            }
+
+            if (c == 'L') {
+                // It looks like the start of a class name; find the end.
+                int endAt = descriptor.indexOf(';', at);
+                if (endAt == -1) {
+                    throw new IllegalArgumentException("bad descriptor");
+                }
+                at = endAt + 1;
+            } else {
+                at++;
+            }
+
+            params[paramCount] =
+                Type.intern(descriptor.substring(startAt, at));
+            paramCount++;
+        }
+
+        Type returnType = Type.internReturnType(descriptor.substring(at));
+        StdTypeList parameterTypes = new StdTypeList(paramCount);
+
+        for (int i = 0; i < paramCount; i++) {
+            parameterTypes.set(i, params[i]);
+        }
+
+        result = new Prototype(descriptor, returnType, parameterTypes);
+        return putIntern(result);
+    }
+
+    /**
+     * Helper for {@link #intern} which returns an empty array to
+     * populate with parsed parameter types, and which also ensures
+     * that there is a '(' at the start of the descriptor and a
+     * single ')' somewhere before the end.
+     *
+     * @param descriptor {@code non-null;} the descriptor string
+     * @return {@code non-null;} array large enough to hold all parsed parameter
+     * types, but which is likely actually larger than needed
+     */
+    private static Type[] makeParameterArray(String descriptor) {
+        int length = descriptor.length();
+
+        if (descriptor.charAt(0) != '(') {
+            throw new IllegalArgumentException("bad descriptor");
+        }
+
+        /*
+         * This is a cheesy way to establish an upper bound on the
+         * number of parameters: Just count capital letters.
+         */
+        int closeAt = 0;
+        int maxParams = 0;
+        for (int i = 1; i < length; i++) {
+            char c = descriptor.charAt(i);
+            if (c == ')') {
+                closeAt = i;
+                break;
+            }
+            if ((c >= 'A') && (c <= 'Z')) {
+                maxParams++;
+            }
+        }
+
+        if ((closeAt == 0) || (closeAt == (length - 1))) {
+            throw new IllegalArgumentException("bad descriptor");
+        }
+
+        if (descriptor.indexOf(')', closeAt + 1) != -1) {
+            throw new IllegalArgumentException("bad descriptor");
+        }
+
+        return new Type[maxParams];
+    }
+
+    /**
+     * 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}
+     * as its first argument.
+     *
+     * @param descriptor {@code non-null;} the descriptor string
+     * @param definer {@code non-null;} class the method is defined on
+     * @param isStatic whether this is a static method
+     * @param isInit whether this is an init method
+     * @return {@code non-null;} the interned instance
+     */
+    public static Prototype intern(String descriptor, Type definer,
+            boolean isStatic, boolean isInit) {
+        Prototype base = intern(descriptor);
+
+        if (isStatic) {
+            return base;
+        }
+
+        if (isInit) {
+            definer = definer.asUninitialized(Integer.MAX_VALUE);
+        }
+
+        return base.withFirstParameter(definer);
+    }
+
+    /**
+     * Interns an instance which consists of the given number of
+     * {@code int}s along with the given return type
+     *
+     * @param returnType {@code non-null;} the return type
+     * @param count {@code > 0;} the number of elements in the prototype
+     * @return {@code non-null;} the interned instance
+     */
+    public static Prototype internInts(Type returnType, int count) {
+        // Make the descriptor...
+
+        StringBuffer sb = new StringBuffer(100);
+
+        sb.append('(');
+
+        for (int i = 0; i < count; i++) {
+            sb.append('I');
+        }
+
+        sb.append(')');
+        sb.append(returnType.getDescriptor());
+
+        // ...and intern it.
+        return intern(sb.toString());
+    }
+
+    /**
+     * Constructs an instance. This is a private constructor; use one
+     * of the public static methods to get instances.
+     *
+     * @param descriptor {@code non-null;} the descriptor string
+     */
+    private Prototype(String descriptor, Type returnType,
+            StdTypeList parameterTypes) {
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        if (returnType == null) {
+            throw new NullPointerException("returnType == null");
+        }
+
+        if (parameterTypes == null) {
+            throw new NullPointerException("parameterTypes == null");
+        }
+
+        this.descriptor = descriptor;
+        this.returnType = returnType;
+        this.parameterTypes = parameterTypes;
+        this.parameterFrameTypes = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            /*
+             * Since externally-visible instances are interned, this
+             * check helps weed out some easy cases.
+             */
+            return true;
+        }
+
+        if (!(other instanceof Prototype)) {
+            return false;
+        }
+
+        return descriptor.equals(((Prototype) other).descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return descriptor.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Prototype other) {
+        if (this == other) {
+            return 0;
+        }
+
+        /*
+         * The return type is the major order, and then args in order,
+         * and then the shorter list comes first (similar to string
+         * sorting).
+         */
+
+        int result = returnType.compareTo(other.returnType);
+
+        if (result != 0) {
+            return result;
+        }
+
+        int thisSize = parameterTypes.size();
+        int otherSize = other.parameterTypes.size();
+        int size = Math.min(thisSize, otherSize);
+
+        for (int i = 0; i < size; i++) {
+            Type thisType = parameterTypes.get(i);
+            Type otherType = other.parameterTypes.get(i);
+
+            result = thisType.compareTo(otherType);
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (thisSize < otherSize) {
+            return -1;
+        } else if (thisSize > otherSize) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the descriptor string.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public String getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the return type.
+     *
+     * @return {@code non-null;} the return type
+     */
+    public Type getReturnType() {
+        return returnType;
+    }
+
+    /**
+     * Gets the list of parameter types.
+     *
+     * @return {@code non-null;} the list of parameter types
+     */
+    public StdTypeList getParameterTypes() {
+        return parameterTypes;
+    }
+
+    /**
+     * Gets the list of frame types corresponding to the list of parameter
+     * types. The difference between the two lists (if any) is that all
+     * "intlike" types (see {@link Type#isIntlike}) are replaced by
+     * {@link Type#INT}.
+     *
+     * @return {@code non-null;} the list of parameter frame types
+     */
+    public StdTypeList getParameterFrameTypes() {
+        if (parameterFrameTypes == null) {
+            int sz = parameterTypes.size();
+            StdTypeList list = new StdTypeList(sz);
+            boolean any = false;
+            for (int i = 0; i < sz; i++) {
+                Type one = parameterTypes.get(i);
+                if (one.isIntlike()) {
+                    any = true;
+                    one = Type.INT;
+                }
+                list.set(i, one);
+            }
+            parameterFrameTypes = any ? list : parameterTypes;
+        }
+
+        return parameterFrameTypes;
+    }
+
+    /**
+     * Returns a new interned instance, which is the same as this instance,
+     * except that it has an additional parameter prepended to the original's
+     * argument list.
+     *
+     * @param param {@code non-null;} the new first parameter
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Prototype withFirstParameter(Type param) {
+        String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
+        StdTypeList newParams = parameterTypes.withFirst(param);
+
+        newParams.setImmutable();
+
+        Prototype result =
+            new Prototype(newDesc, returnType, newParams);
+
+        return putIntern(result);
+    }
+
+    /**
+     * Puts the given instance in the intern table if it's not already
+     * there. If a conflicting value is already in the table, then leave it.
+     * Return the interned value.
+     *
+     * @param desc {@code non-null;} instance to make interned
+     * @return {@code non-null;} the actual interned object
+     */
+    private static Prototype putIntern(Prototype desc) {
+        synchronized (internTable) {
+            String descriptor = desc.getDescriptor();
+            Prototype already = internTable.get(descriptor);
+            if (already != null) {
+                return already;
+            }
+            internTable.put(descriptor, desc);
+            return desc;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/type/StdTypeList.java b/dx/src/com/android/dx/rop/type/StdTypeList.java
new file mode 100644
index 0000000..fe6647c
--- /dev/null
+++ b/dx/src/com/android/dx/rop/type/StdTypeList.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.type;
+
+import com.android.dx.util.FixedSizeList;
+
+/**
+ * Standard implementation of {@link TypeList}.
+ */
+public final class StdTypeList
+        extends FixedSizeList implements TypeList {
+    /** {@code non-null;} no-element instance */
+    public static final StdTypeList EMPTY = new StdTypeList(0);
+
+    /** {@code non-null;} the list {@code [int]} */
+    public static final StdTypeList INT = StdTypeList.make(Type.INT);
+
+    /** {@code non-null;} the list {@code [long]} */
+    public static final StdTypeList LONG = StdTypeList.make(Type.LONG);
+
+    /** {@code non-null;} the list {@code [float]} */
+    public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT);
+
+    /** {@code non-null;} the list {@code [double]} */
+    public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE);
+
+    /** {@code non-null;} the list {@code [Object]} */
+    public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [ReturnAddress]} */
+    public static final StdTypeList RETURN_ADDRESS
+            = StdTypeList.make(Type.RETURN_ADDRESS);
+
+    /** {@code non-null;} the list {@code [Throwable]} */
+    public static final StdTypeList THROWABLE =
+        StdTypeList.make(Type.THROWABLE);
+
+    /** {@code non-null;} the list {@code [int, int]} */
+    public static final StdTypeList INT_INT =
+        StdTypeList.make(Type.INT, Type.INT);
+
+    /** {@code non-null;} the list {@code [long, long]} */
+    public static final StdTypeList LONG_LONG =
+        StdTypeList.make(Type.LONG, Type.LONG);
+
+    /** {@code non-null;} the list {@code [float, float]} */
+    public static final StdTypeList FLOAT_FLOAT =
+        StdTypeList.make(Type.FLOAT, Type.FLOAT);
+
+    /** {@code non-null;} the list {@code [double, double]} */
+    public static final StdTypeList DOUBLE_DOUBLE =
+        StdTypeList.make(Type.DOUBLE, Type.DOUBLE);
+
+    /** {@code non-null;} the list {@code [Object, Object]} */
+    public static final StdTypeList OBJECT_OBJECT =
+        StdTypeList.make(Type.OBJECT, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [int, Object]} */
+    public static final StdTypeList INT_OBJECT =
+        StdTypeList.make(Type.INT, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [long, Object]} */
+    public static final StdTypeList LONG_OBJECT =
+        StdTypeList.make(Type.LONG, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [float, Object]} */
+    public static final StdTypeList FLOAT_OBJECT =
+        StdTypeList.make(Type.FLOAT, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [double, Object]} */
+    public static final StdTypeList DOUBLE_OBJECT =
+        StdTypeList.make(Type.DOUBLE, Type.OBJECT);
+
+    /** {@code non-null;} the list {@code [long, int]} */
+    public static final StdTypeList LONG_INT =
+        StdTypeList.make(Type.LONG, Type.INT);
+
+    /** {@code non-null;} the list {@code [int[], int]} */
+    public static final StdTypeList INTARR_INT =
+        StdTypeList.make(Type.INT_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [long[], int]} */
+    public static final StdTypeList LONGARR_INT =
+        StdTypeList.make(Type.LONG_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [float[], int]} */
+    public static final StdTypeList FLOATARR_INT =
+        StdTypeList.make(Type.FLOAT_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [double[], int]} */
+    public static final StdTypeList DOUBLEARR_INT =
+        StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [Object[], int]} */
+    public static final StdTypeList OBJECTARR_INT =
+        StdTypeList.make(Type.OBJECT_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [boolean[], int]} */
+    public static final StdTypeList BOOLEANARR_INT =
+        StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [byte[], int]} */
+    public static final StdTypeList BYTEARR_INT =
+        StdTypeList.make(Type.BYTE_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [char[], int]} */
+    public static final StdTypeList CHARARR_INT =
+        StdTypeList.make(Type.CHAR_ARRAY, Type.INT);
+
+    /** {@code non-null;} the list {@code [short[], int]} */
+    public static final StdTypeList SHORTARR_INT =
+        StdTypeList.make(Type.SHORT_ARRAY, Type.INT);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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);
+
+    /** {@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 {@code non-null;} the element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static StdTypeList make(Type type) {
+        StdTypeList result = new StdTypeList(1);
+        result.set(0, type);
+        return result;
+    }
+
+    /**
+     * Makes a two-element instance.
+     *
+     * @param type0 {@code non-null;} the first element
+     * @param type1 {@code non-null;} the second element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static StdTypeList make(Type type0, Type type1) {
+        StdTypeList result = new StdTypeList(2);
+        result.set(0, type0);
+        result.set(1, type1);
+        return result;
+    }
+
+    /**
+     * Makes a three-element instance.
+     *
+     * @param type0 {@code non-null;} the first element
+     * @param type1 {@code non-null;} the second element
+     * @param type2 {@code non-null;} the third element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static StdTypeList make(Type type0, Type type1, Type type2) {
+        StdTypeList result = new StdTypeList(3);
+        result.set(0, type0);
+        result.set(1, type1);
+        result.set(2, type2);
+        return result;
+    }
+
+    /**
+     * Makes a four-element instance.
+     *
+     * @param type0 {@code non-null;} the first element
+     * @param type1 {@code non-null;} the second element
+     * @param type2 {@code non-null;} the third element
+     * @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) {
+        StdTypeList result = new StdTypeList(4);
+        result.set(0, type0);
+        result.set(1, type1);
+        result.set(2, type2);
+        result.set(3, type3);
+        return result;
+    }
+
+    /**
+     * Returns the given list as a comma-separated list of human forms. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list {@code non-null;} the list to convert
+     * @return {@code non-null;} the human form
+     */
+    public static String toHuman(TypeList list) {
+        int size = list.size();
+
+        if (size == 0) {
+            return "<empty>";
+        }
+
+        StringBuffer sb = new StringBuffer(100);
+
+        for (int i = 0; i < size; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(list.getType(i).toHuman());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns a hashcode of the contents of the given list. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list {@code non-null;} the list to inspect
+     * @return {@code non-null;} the hash code
+     */
+    public static int hashContents(TypeList list) {
+        int size = list.size();
+        int hash = 0;
+
+        for (int i = 0; i < size; i++) {
+            hash = (hash * 31) + list.getType(i).hashCode();
+        }
+
+        return hash;
+    }
+
+    /**
+     * Compares the contents of the given two instances for equality. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list1 {@code non-null;} one list to compare
+     * @param list2 {@code non-null;} another list to compare
+     * @return whether the two lists contain corresponding equal elements
+     */
+    public static boolean equalContents(TypeList list1, TypeList list2) {
+        int size = list1.size();
+
+        if (list2.size() != size) {
+            return false;
+        }
+
+        for (int i = 0; i < size; i++) {
+            if (! list1.getType(i).equals(list2.getType(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Compares the contents of the given two instances for ordering. This
+     * is a static method so as to work on arbitrary {@link TypeList}
+     * instances.
+     *
+     * @param list1 {@code non-null;} one list to compare
+     * @param list2 {@code non-null;} another list to compare
+     * @return the order of the two lists
+     */
+    public static int compareContents(TypeList list1, TypeList list2) {
+        int size1 = list1.size();
+        int size2 = list2.size();
+        int size = Math.min(size1, size2);
+
+        for (int i = 0; i < size; i++) {
+            int comparison = list1.getType(i).compareTo(list2.getType(i));
+            if (comparison != 0) {
+                return comparison;
+            }
+        }
+
+        if (size1 == size2) {
+            return 0;
+        } else if (size1 < size2) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public StdTypeList(int size) {
+        super(size);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType(int n) {
+        return get(n);
+    }
+
+    /** {@inheritDoc} */
+    public int getWordCount() {
+        int sz = size();
+        int result = 0;
+
+        for (int i = 0; i < sz; i++) {
+            result += get(i).getCategory();
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public TypeList withAddedType(Type type) {
+        int sz = size();
+        StdTypeList result = new StdTypeList(sz + 1);
+
+        for (int i = 0; i < sz; i++) {
+            result.set0(i, get0(i));
+        }
+
+        result.set(sz, type);
+        result.setImmutable();
+        return result;
+    }
+
+    /**
+     * Gets the indicated element. It is an error to call this with the
+     * index for an element which was never set; if you do that, this
+     * will throw {@code NullPointerException}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public Type get(int n) {
+        return (Type) get0(n);
+    }
+
+    /**
+     * Sets the type at the given index.
+     *
+     * @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);
+    }
+
+    /**
+     * Returns a new instance, which is the same as this instance,
+     * except that it has an additional type prepended to the
+     * original.
+     *
+     * @param type {@code non-null;} the new first element
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public StdTypeList withFirst(Type type) {
+        int sz = size();
+        StdTypeList result = new StdTypeList(sz + 1);
+
+        result.set0(0, type);
+        for (int i = 0; i < sz; i++) {
+            result.set0(i + 1, getOrNull0(i));
+        }
+
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/rop/type/Type.java b/dx/src/com/android/dx/rop/type/Type.java
new file mode 100644
index 0000000..c564fab
--- /dev/null
+++ b/dx/src/com/android/dx/rop/type/Type.java
@@ -0,0 +1,862 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.type;
+
+import com.android.dx.util.Hex;
+
+import java.util.HashMap;
+
+/**
+ * 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 ==}.
+ */
+public final class Type implements TypeBearer, Comparable<Type> {
+    /**
+     * {@code non-null;} intern table mapping string descriptors to
+     * instances
+     */
+    private static final HashMap<String, Type> internTable =
+        new HashMap<String, Type>(500);
+
+    /** basic type constant for {@code void} */
+    public static final int BT_VOID = 0;
+
+    /** basic type constant for {@code boolean} */
+    public static final int BT_BOOLEAN = 1;
+
+    /** basic type constant for {@code byte} */
+    public static final int BT_BYTE = 2;
+
+    /** basic type constant for {@code char} */
+    public static final int BT_CHAR = 3;
+
+    /** basic type constant for {@code double} */
+    public static final int BT_DOUBLE = 4;
+
+    /** basic type constant for {@code float} */
+    public static final int BT_FLOAT = 5;
+
+    /** basic type constant for {@code int} */
+    public static final int BT_INT = 6;
+
+    /** basic type constant for {@code long} */
+    public static final int BT_LONG = 7;
+
+    /** basic type constant for {@code short} */
+    public static final int BT_SHORT = 8;
+
+    /** basic type constant for {@code Object} */
+    public static final int BT_OBJECT = 9;
+
+    /** basic type constant for a return address */
+    public static final int BT_ADDR = 10;
+
+    /** count of basic type constants */
+    public static final int BT_COUNT = 11;
+
+    /** {@code non-null;} instance representing {@code boolean} */
+    public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
+
+    /** {@code non-null;} instance representing {@code byte} */
+    public static final Type BYTE = new Type("B", BT_BYTE);
+
+    /** {@code non-null;} instance representing {@code char} */
+    public static final Type CHAR = new Type("C", BT_CHAR);
+
+    /** {@code non-null;} instance representing {@code double} */
+    public static final Type DOUBLE = new Type("D", BT_DOUBLE);
+
+    /** {@code non-null;} instance representing {@code float} */
+    public static final Type FLOAT = new Type("F", BT_FLOAT);
+
+    /** {@code non-null;} instance representing {@code int} */
+    public static final Type INT = new Type("I", BT_INT);
+
+    /** {@code non-null;} instance representing {@code long} */
+    public static final Type LONG = new Type("J", BT_LONG);
+
+    /** {@code non-null;} instance representing {@code short} */
+    public static final Type SHORT = new Type("S", BT_SHORT);
+
+    /** {@code non-null;} instance representing {@code void} */
+    public static final Type VOID = new Type("V", BT_VOID);
+
+    /** {@code non-null;} instance representing a known-{@code null} */
+    public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
+
+    /** {@code non-null;} instance representing a subroutine return address */
+    public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
+
+    static {
+        /*
+         * Put all the primitive types into the intern table. This needs
+         * to happen before the array types below get interned.
+         */
+        putIntern(BOOLEAN);
+        putIntern(BYTE);
+        putIntern(CHAR);
+        putIntern(DOUBLE);
+        putIntern(FLOAT);
+        putIntern(INT);
+        putIntern(LONG);
+        putIntern(SHORT);
+        /*
+         * Note: VOID isn't put in the intern table, since it's special and
+         * shouldn't be found by a normal call to intern().
+         */
+    }
+
+    /**
+     * {@code non-null;} instance representing
+     * {@code java.lang.annotation.Annotation}
+     */
+    public static final Type ANNOTATION =
+        intern("Ljava/lang/annotation/Annotation;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Class} */
+    public static final Type CLASS = intern("Ljava/lang/Class;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
+    public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Object} */
+    public static final Type OBJECT = intern("Ljava/lang/Object;");
+
+    /** {@code non-null;} instance representing {@code java.io.Serializable} */
+    public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
+
+    /** {@code non-null;} instance representing {@code java.lang.String} */
+    public static final Type STRING = intern("Ljava/lang/String;");
+
+    /** {@code non-null;} instance representing {@code java.lang.Throwable} */
+    public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /**
+     * {@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;");
+
+    /** {@code non-null;} instance representing {@code boolean[]} */
+    public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
+
+    /** {@code non-null;} instance representing {@code byte[]} */
+    public static final Type BYTE_ARRAY = BYTE.getArrayType();
+
+    /** {@code non-null;} instance representing {@code char[]} */
+    public static final Type CHAR_ARRAY = CHAR.getArrayType();
+
+    /** {@code non-null;} instance representing {@code double[]} */
+    public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
+
+    /** {@code non-null;} instance representing {@code float[]} */
+    public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
+
+    /** {@code non-null;} instance representing {@code int[]} */
+    public static final Type INT_ARRAY = INT.getArrayType();
+
+    /** {@code non-null;} instance representing {@code long[]} */
+    public static final Type LONG_ARRAY = LONG.getArrayType();
+
+    /** {@code non-null;} instance representing {@code Object[]} */
+    public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
+
+    /** {@code non-null;} instance representing {@code short[]} */
+    public static final Type SHORT_ARRAY = SHORT.getArrayType();
+
+    /** {@code non-null;} field descriptor for the type */
+    private final String descriptor;
+
+    /**
+     * basic type corresponding to this type; one of the
+     * {@code BT_*} constants
+     */
+    private final int basicType;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /**
+     * {@code null-ok;} the type corresponding to an array of this type, if
+     * calculated
+     */
+    private Type arrayType;
+
+    /**
+     * {@code null-ok;} the type corresponding to elements of this type, if
+     * calculated; only valid if {@code this} is an array type
+     */
+    private Type componentType;
+
+    /**
+     * {@code null-ok;} the type corresponding to the initialized version of
+     * this type, if this instance is in fact an uninitialized type
+     */
+    private Type initializedType;
+
+    /**
+     * 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"} (that is, type {@code void}) as a valid
+     * descriptor.
+     *
+     * @param descriptor {@code non-null;} the descriptor
+     * @return {@code non-null;} the corresponding instance
+     * @throws IllegalArgumentException thrown if the descriptor has
+     * invalid syntax
+     */
+    public static Type intern(String descriptor) {
+        Type result;
+        synchronized (internTable) {
+            result = internTable.get(descriptor);
+        }
+        if (result != null) {
+            return result;
+        }
+
+        char firstChar;
+        try {
+            firstChar = descriptor.charAt(0);
+        } catch (IndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("descriptor is empty");
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("descriptor == null");
+        }
+
+        if (firstChar == '[') {
+            /*
+             * Recursively strip away array markers to get at the underlying
+             * type, and build back on to form the result.
+             */
+            result = intern(descriptor.substring(1));
+            return result.getArrayType();
+        }
+
+        /*
+         * If the first character isn't '[' and it wasn't found in the
+         * intern cache, then it had better be the descriptor for a class.
+         */
+
+        int length = descriptor.length();
+        if ((firstChar != 'L') ||
+            (descriptor.charAt(length - 1) != ';')) {
+            throw new IllegalArgumentException("bad descriptor: " + descriptor);
+        }
+
+        /*
+         * Validate the characters of the class name itself. Note that
+         * vmspec-2 does not have a coherent definition for valid
+         * internal-form class names, and the definition here is fairly
+         * liberal: A name is considered valid as long as it doesn't
+         * contain any of '[' ';' '.' '(' ')', and it has no more than one
+         * '/' in a row, and no '/' at either end.
+         */
+
+        int limit = (length - 1); // Skip the final ';'.
+        for (int i = 1; i < limit; i++) {
+            char c = descriptor.charAt(i);
+            switch (c) {
+                case '[':
+                case ';':
+                case '.':
+                case '(':
+                case ')': {
+                    throw new IllegalArgumentException("bad descriptor: " + descriptor);
+                }
+                case '/': {
+                    if ((i == 1) ||
+                        (i == (length - 1)) ||
+                        (descriptor.charAt(i - 1) == '/')) {
+                        throw new IllegalArgumentException("bad descriptor: " + descriptor);
+                    }
+                    break;
+                }
+            }
+        }
+
+        result = new Type(descriptor, BT_OBJECT);
+        return putIntern(result);
+    }
+
+    /**
+     * Returns the unique instance corresponding to the type with the
+     * given descriptor, allowing {@code "V"} to return the type
+     * for {@code void}. Other than that one caveat, this method
+     * is identical to {@link #intern}.
+     *
+     * @param descriptor {@code non-null;} the descriptor
+     * @return {@code non-null;} the corresponding instance
+     * @throws IllegalArgumentException thrown if the descriptor has
+     * invalid syntax
+     */
+    public static Type internReturnType(String descriptor) {
+        try {
+            if (descriptor.equals("V")) {
+                // This is the one special case where void may be returned.
+                return VOID;
+            }
+        } catch (NullPointerException ex) {
+            // Elucidate the exception.
+            throw new NullPointerException("descriptor == null");
+        }
+
+        return intern(descriptor);
+    }
+
+    /**
+     * 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)} if {@code name} begins
+     * with {@code "["} and calling {@code intern("L" + name + ";")}
+     * in all other cases.
+     *
+     * @param name {@code non-null;} the name of the class whose type
+     * is desired
+     * @return {@code non-null;} the corresponding type
+     * @throws IllegalArgumentException thrown if the name has
+     * invalid syntax
+     */
+    public static Type internClassName(String name) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        if (name.startsWith("[")) {
+            return intern(name);
+        }
+
+        return intern('L' + name + ';');
+    }
+
+    /**
+     * Constructs an instance corresponding to an "uninitialized type."
+     * This is a private constructor; use one of the public static
+     * methods to get instances.
+     *
+     * @param descriptor {@code non-null;} the field descriptor for the type
+     * @param basicType basic type corresponding to this type; one of the
+     * {@code BT_*} constants
+     * @param newAt {@code >= -1;} allocation bytecode index
+     */
+    private Type(String descriptor, int basicType, int newAt) {
+        if (descriptor == null) {
+            throw new NullPointerException("descriptor == null");
+        }
+
+        if ((basicType < 0) || (basicType >= BT_COUNT)) {
+            throw new IllegalArgumentException("bad basicType");
+        }
+
+        if (newAt < -1) {
+            throw new IllegalArgumentException("newAt < -1");
+        }
+
+        this.descriptor = descriptor;
+        this.basicType = basicType;
+        this.newAt = newAt;
+        this.arrayType = null;
+        this.componentType = null;
+        this.initializedType = null;
+    }
+
+    /**
+     * Constructs an instance corresponding to an "initialized type."
+     * This is a private constructor; use one of the public static
+     * methods to get instances.
+     *
+     * @param descriptor {@code non-null;} the field descriptor for the type
+     * @param basicType basic type corresponding to this type; one of the
+     * {@code BT_*} constants
+     */
+    private Type(String descriptor, int basicType) {
+        this(descriptor, basicType, -1);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            /*
+             * Since externally-visible types are interned, this check
+             * helps weed out some easy cases.
+             */
+            return true;
+        }
+
+        if (!(other instanceof Type)) {
+            return false;
+        }
+
+        return descriptor.equals(((Type) other).descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return descriptor.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Type other) {
+        return descriptor.compareTo(other.descriptor);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return descriptor;
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        switch (basicType) {
+            case BT_VOID:    return "void";
+            case BT_BOOLEAN: return "boolean";
+            case BT_BYTE:    return "byte";
+            case BT_CHAR:    return "char";
+            case BT_DOUBLE:  return "double";
+            case BT_FLOAT:   return "float";
+            case BT_INT:     return "int";
+            case BT_LONG:    return "long";
+            case BT_SHORT:   return "short";
+            case BT_OBJECT:  break;
+            default:         return descriptor;
+        }
+
+        if (isArray()) {
+            return getComponentType().toHuman() + "[]";
+        }
+
+        // Remove the "L...;" around the type and convert "/" to ".".
+        return getClassName().replace("/", ".");
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public Type getFrameType() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_INT:
+            case BT_SHORT: {
+                return INT;
+            }
+        }
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    public int getBasicType() {
+        return basicType;
+    }
+
+    /** {@inheritDoc} */
+    public int getBasicFrameType() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_INT:
+            case BT_SHORT: {
+                return BT_INT;
+            }
+        }
+
+        return basicType;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isConstant() {
+        return false;
+    }
+
+    /**
+     * Gets the descriptor.
+     *
+     * @return {@code non-null;} the descriptor
+     */
+    public String getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the name of the class this type corresponds to, in internal
+     * form. This method is only valid if this instance is for a
+     * normal reference type (that is, a reference type and
+     * additionally not a return address).
+     *
+     * @return {@code non-null;} the internal-form class name
+     */
+    public String getClassName() {
+        if (className == null) {
+            if (!isReference()) {
+                throw new IllegalArgumentException("not an object type: " +
+                                                   descriptor);
+            }
+
+            if (descriptor.charAt(0) == '[') {
+                className = descriptor;
+            } else {
+                className = descriptor.substring(1, descriptor.length() - 1);
+            }
+        }
+
+        return className;
+    }
+
+    /**
+     * Gets the category. Most instances are category 1. {@code long}
+     * and {@code double} are the only category 2 types.
+     *
+     * @see #isCategory1
+     * @see #isCategory2
+     * @return the category
+     */
+    public int getCategory() {
+        switch (basicType) {
+            case BT_LONG:
+            case BT_DOUBLE: {
+                return 2;
+            }
+        }
+
+        return 1;
+    }
+
+    /**
+     * Returns whether or not this is a category 1 type.
+     *
+     * @see #getCategory
+     * @see #isCategory2
+     * @return whether or not this is a category 1 type
+     */
+    public boolean isCategory1() {
+        switch (basicType) {
+            case BT_LONG:
+            case BT_DOUBLE: {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns whether or not this is a category 2 type.
+     *
+     * @see #getCategory
+     * @see #isCategory1
+     * @return whether or not this is a category 2 type
+     */
+    public boolean isCategory2() {
+        switch (basicType) {
+            case BT_LONG:
+            case BT_DOUBLE: {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets whether this type is "intlike." An intlike type is one which, when
+     * placed on a stack or in a local, is automatically converted to an
+     * {@code int}.
+     *
+     * @return whether this type is "intlike"
+     */
+    public boolean isIntlike() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_INT:
+            case BT_SHORT: {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets whether this type is a primitive type. All types are either
+     * primitive or reference types.
+     *
+     * @return whether this type is primitive
+     */
+    public boolean isPrimitive() {
+        switch (basicType) {
+            case BT_BOOLEAN:
+            case BT_BYTE:
+            case BT_CHAR:
+            case BT_DOUBLE:
+            case BT_FLOAT:
+            case BT_INT:
+            case BT_LONG:
+            case BT_SHORT:
+            case BT_VOID: {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 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}.
+     *
+     * @return whether this type is a normal reference type
+     */
+    public boolean isReference() {
+        return (basicType == BT_OBJECT);
+    }
+
+    /**
+     * Gets whether this type is an array type. If this method returns
+     * {@code true}, then it is safe to use {@link #getComponentType}
+     * to determine the component type.
+     *
+     * @return whether this type is an array type
+     */
+    public boolean isArray() {
+        return (descriptor.charAt(0) == '[');
+    }
+
+    /**
+     * Gets whether this type is an array type or is a known-null, and
+     * hence is compatible with array types.
+     *
+     * @return whether this type is an array type
+     */
+    public boolean isArrayOrKnownNull() {
+        return isArray() || equals(KNOWN_NULL);
+    }
+
+    /**
+     * Gets whether this type represents an uninitialized instance. An
+     * uninitialized instance is what one gets back from the {@code new}
+     * opcode, and remains uninitialized until a valid constructor is
+     * invoked on it.
+     *
+     * @return whether this type is "uninitialized"
+     */
+    public boolean isUninitialized() {
+        return (newAt >= 0);
+    }
+
+    /**
+     * Gets the bytecode index at which this uninitialized type was
+     * allocated.  This returns {@code Integer.MAX_VALUE} if this
+     * type is an uninitialized incoming parameter (i.e., the
+     * {@code this} of an {@code <init>} method) or
+     * {@code -1} if this type is in fact <i>initialized</i>.
+     *
+     * @return {@code >= -1;} the allocation bytecode index
+     */
+    public int getNewAt() {
+        return newAt;
+    }
+
+    /**
+     * Gets the initialized type corresponding to this instance, but only
+     * if this instance is in fact an uninitialized object type.
+     *
+     * @return {@code non-null;} the initialized type
+     */
+    public Type getInitializedType() {
+        if (initializedType == null) {
+            throw new IllegalArgumentException("initialized type: " +
+                                               descriptor);
+        }
+
+        return initializedType;
+    }
+
+    /**
+     * Gets the type corresponding to an array of this type.
+     *
+     * @return {@code non-null;} the array type
+     */
+    public Type getArrayType() {
+        if (arrayType == null) {
+            arrayType = putIntern(new Type('[' + descriptor, BT_OBJECT));
+        }
+
+        return arrayType;
+    }
+
+    /**
+     * Gets the component type of this type. This method is only valid on
+     * array types.
+     *
+     * @return {@code non-null;} the component type
+     */
+    public Type getComponentType() {
+        if (componentType == null) {
+            if (descriptor.charAt(0) != '[') {
+                throw new IllegalArgumentException("not an array type: " +
+                                                   descriptor);
+            }
+            componentType = intern(descriptor.substring(1));
+        }
+
+        return componentType;
+    }
+
+    /**
+     * Returns a new interned instance which is identical to this one, except
+     * it is indicated as uninitialized and allocated at the given bytecode
+     * index. This instance must be an initialized object type.
+     *
+     * @param newAt {@code >= 0;} the allocation bytecode index
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public Type asUninitialized(int newAt) {
+        if (newAt < 0) {
+            throw new IllegalArgumentException("newAt < 0");
+        }
+
+        if (!isReference()) {
+            throw new IllegalArgumentException("not a reference type: " +
+                                               descriptor);
+        }
+
+        if (isUninitialized()) {
+            /*
+             * Dealing with uninitialized types as a starting point is
+             * a pain, and it's not clear that it'd ever be used, so
+             * just disallow it.
+             */
+            throw new IllegalArgumentException("already uninitialized: " +
+                                               descriptor);
+        }
+
+        /*
+         * Create a new descriptor that is unique and shouldn't conflict
+         * with "normal" type descriptors
+         */
+        String newDesc = 'N' + Hex.u2(newAt) + descriptor;
+        Type result = new Type(newDesc, BT_OBJECT, newAt);
+        result.initializedType = this;
+        return putIntern(result);
+    }
+
+    /**
+     * Puts the given instance in the intern table if it's not already
+     * there. If a conflicting value is already in the table, then leave it.
+     * Return the interned value.
+     *
+     * @param type {@code non-null;} instance to make interned
+     * @return {@code non-null;} the actual interned object
+     */
+    private static Type putIntern(Type type) {
+        synchronized (internTable) {
+            String descriptor = type.getDescriptor();
+            Type already = internTable.get(descriptor);
+            if (already != null) {
+                return already;
+            }
+            internTable.put(descriptor, type);
+            return type;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/type/TypeBearer.java b/dx/src/com/android/dx/rop/type/TypeBearer.java
new file mode 100644
index 0000000..b03dbaf
--- /dev/null
+++ b/dx/src/com/android/dx/rop/type/TypeBearer.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.type;
+
+import com.android.dx.util.ToHuman;
+
+/**
+ * Object which has an associated type, possibly itself.
+ */
+public interface TypeBearer
+        extends ToHuman {
+    /**
+     * Gets the type associated with this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public Type getType();
+
+    /**
+     * Gets the frame type corresponding to this type. This method returns
+     * {@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}.
+     *
+     * @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_*} 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()}, 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}.
+     *
+     * @see #getBasicType
+     * @see #getFrameType
+     *
+     * @return the basic frame type; one of the {@code BT_*} constants
+     * defined by {@link Type}
+     */
+    public int getBasicFrameType();
+
+    /**
+     * Returns whether this instance represents a constant value.
+     *
+     * @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
new file mode 100644
index 0000000..de2d62e
--- /dev/null
+++ b/dx/src/com/android/dx/rop/type/TypeList.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.type;
+
+/**
+ * List of {@link Type} instances (or of things that contain types).
+ */
+public interface TypeList {
+    /**
+     * Returns whether this instance is mutable. Note that the
+     * {@code TypeList} interface itself doesn't provide any
+     * means of mutation, but that doesn't mean that there isn't an
+     * extra-interface way of mutating an instance.
+     *
+     * @return {@code true} if this instance is mutable or
+     * {@code false} if it is immutable
+     */
+    public boolean isMutable();
+
+    /**
+     * Gets the size of this list.
+     *
+     * @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}.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    public Type getType(int n);
+
+    /**
+     * Gets the number of 32-bit words required to hold instances of
+     * all the elements of this list. This is a sum of the widths (categories)
+     * of all the elements.
+     *
+     * @return {@code >= 0;} the required number of words
+     */
+    public int getWordCount();
+
+    /**
+     * Returns a new instance which is identical to this one, except that
+     * the given item is appended to the end and it is guaranteed to be
+     * immutable.
+     *
+     * @param type {@code non-null;} item to append
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public TypeList withAddedType(Type type);
+}
diff --git a/dx/src/com/android/dx/rop/type/package.html b/dx/src/com/android/dx/rop/type/package.html
new file mode 100644
index 0000000..93d9d5f
--- /dev/null
+++ b/dx/src/com/android/dx/rop/type/package.html
@@ -0,0 +1,8 @@
+<body>
+<p>Implementation of classes that represent types (classes or primitives).</p>
+
+<p><b>PACKAGES USED:</b>
+<ul>
+<li><code>com.android.dx.util</code></li>
+</ul>
+</body>
diff --git a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
new file mode 100644
index 0000000..83045b2
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.util.IntList;
+
+/**
+ * This class maps one register space into another, with
+ * each mapping built up individually and added via addMapping()
+ */
+public class BasicRegisterMapper extends RegisterMapper {
+    /** indexed by old register, containing new name */
+    private IntList oldToNew;
+
+    /** running count of used registers in new namespace */
+    private int runningCountNewRegisters;
+
+    /**
+     * Creates a new OneToOneRegisterMapper.
+     *
+     * @param countOldRegisters the number of registers in the old name space
+     */
+    public BasicRegisterMapper(int countOldRegisters) {
+        oldToNew = new IntList(countOldRegisters);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int getNewRegisterCount() {
+        return runningCountNewRegisters;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RegisterSpec map(RegisterSpec registerSpec) {
+        if (registerSpec == null) {
+            return null;
+        }
+
+        int newReg;
+        try {
+            newReg = oldToNew.get(registerSpec.getReg());
+        } catch (IndexOutOfBoundsException ex) {
+            newReg = -1;
+        }
+
+        if (newReg < 0) {
+            throw new RuntimeException("no mapping specified for register");
+        }
+
+        return registerSpec.withReg(newReg);
+    }
+
+    /**
+     * Returns the new-namespace mapping for the specified
+     * old-namespace register, or -1 if one exists.
+     *
+     * @param oldReg {@code >= 0;} old-namespace register
+     * @return new-namespace register or -1 if none
+     */
+    public int oldToNew(int oldReg) {
+        if (oldReg >= oldToNew.size()) {
+            return -1;
+        }
+
+        return oldToNew.get(oldReg);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("Old\tNew\n");
+        int sz = oldToNew.size();
+
+        for (int i = 0; i < sz; i++) {
+            sb.append(i);
+            sb.append('\t');
+            sb.append(oldToNew.get(i));
+            sb.append('\n');
+        }
+
+        sb.append("new reg count:");
+
+        sb.append(runningCountNewRegisters);
+        sb.append('\n');
+
+        return sb.toString();
+    }
+
+    /**
+     * Adds a mapping to the mapper. If oldReg has already been mapped,
+     * overwrites previous mapping with new mapping.
+     *
+     * @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()) {
+            // expand the array as necessary
+            for (int i = oldReg - oldToNew.size(); i >= 0; i--) {
+                oldToNew.add(-1);
+            }
+        }
+
+        oldToNew.set(oldReg, newReg);
+
+        if (runningCountNewRegisters < (newReg + category)) {
+            runningCountNewRegisters = newReg + category;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/ConstCollector.java b/dx/src/com/android/dx/ssa/ConstCollector.java
new file mode 100644
index 0000000..62d629f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/ConstCollector.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.code.ThrowingCstInsn;
+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.TypeBearer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Collects constants that are used more than once at the top of the
+ * method block. This increases register usage by about 5% but decreases
+ * 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;
+
+    /**
+     * Also collect string consts, although they can throw exceptions.
+     * This is off now because it just doesn't seem to gain a whole lot.
+     * TODO if you turn this on, you must change SsaInsn.hasSideEffect()
+     * to return false for const-string insns whose exceptions are not
+     * caught in the current method.
+     */
+    private static boolean COLLECT_STRINGS = false;
+
+    /**
+     * If true, allow one local var to be involved with a collected const.
+     * Turned off because it mostly just inserts more moves.
+     */
+    private static boolean COLLECT_ONE_LOCAL = false;
+
+    /** method we're processing */
+    private final SsaMethod ssaMeth;
+
+    /**
+     * Processes a method.
+     *
+     * @param ssaMethod {@code non-null;} method to process
+     */
+    public static void process(SsaMethod ssaMethod) {
+        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;
+    }
+
+    /**
+     * Applies the optimization.
+     */
+    private void run() {
+        int regSz = ssaMeth.getRegCount();
+
+        ArrayList<TypedConstant> constantList
+                = getConstsSortedByCountUse();
+
+        int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS);
+
+        SsaBasicBlock start = ssaMeth.getEntryBlock();
+
+        // Constant to new register containing the constant
+        HashMap<TypedConstant, RegisterSpec> newRegs
+                = new HashMap<TypedConstant, RegisterSpec> (toCollect);
+
+        for (int i = 0; i < toCollect; i++) {
+            TypedConstant cst = constantList.get(i);
+            RegisterSpec result
+                    = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst);
+
+            Rop constRop = Rops.opConst(cst);
+
+            if (constRop.getBranchingness() == Rop.BRANCH_NONE) {
+                start.addInsnToHead(
+                        new PlainCstInsn(Rops.opConst(cst),
+                                SourcePosition.NO_INFO, result,
+                                RegisterSpecList.EMPTY, cst));
+            } else {
+                // We need two new basic blocks along with the new insn
+                SsaBasicBlock entryBlock = ssaMeth.getEntryBlock();
+                SsaBasicBlock successorBlock
+                        = entryBlock.getPrimarySuccessor();
+
+                // Insert a block containing the const insn.
+                SsaBasicBlock constBlock
+                        = entryBlock.insertNewSuccessor(successorBlock);
+
+                constBlock.replaceLastInsn(
+                        new ThrowingCstInsn(constRop, SourcePosition.NO_INFO,
+                                RegisterSpecList.EMPTY,
+                                StdTypeList.EMPTY, cst));
+
+                // 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(insn);
+            }
+
+            newRegs.put(cst, result);
+        }
+
+        updateConstUses(newRegs, regSz);
+    }
+
+    /**
+     * Gets all of the collectable constant values used in this method,
+     * sorted by most used first. Skips non-collectable consts, such as
+     * non-string object constants
+     *
+     * @return {@code non-null;} list of constants in most-to-least used order
+     */
+    private ArrayList<TypedConstant> getConstsSortedByCountUse() {
+        int regSz = ssaMeth.getRegCount();
+
+        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).
+         */
+        final HashSet<TypedConstant> usedByLocal
+                = new HashSet<TypedConstant>();
+
+        // Count how many times each const value is used.
+        for (int i = 0; i < regSz; i++) {
+            SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
+
+            if (insn == null || insn.getOpcode() == null) continue;
+
+            RegisterSpec result = insn.getResult();
+            TypeBearer typeBearer = result.getTypeBearer();
+
+            if (!typeBearer.isConstant()) continue;
+
+            TypedConstant cst = (TypedConstant) typeBearer;
+
+            // Find defining instruction for move-result-pseudo instructions
+            if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+                int pred = insn.getBlock().getPredecessors().nextSetBit(0);
+                ArrayList<SsaInsn> predInsns;
+                predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+                insn = predInsns.get(predInsns.size()-1);
+            }
+
+            if (insn.canThrow()) {
+                /*
+                 * Don't move anything other than strings -- the risk
+                 * 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.
+                 */
+                if (insn.getBlock().getSuccessors().cardinality() > 1) {
+                    continue;
+                }
+            }
+
+            /*
+             * 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.
+                        continue;
+                    } else {
+                        usedByLocal.add(cst);
+                    }
+                }
+            }
+
+            Integer has = countUses.get(cst);
+            if (has == null) {
+                countUses.put(cst, 1);
+            } else {
+                countUses.put(cst, has + 1);
+            }
+        }
+
+        // Collect constants that have been reused.
+        ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
+        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.
+        Collections.sort(constantList, new Comparator<Constant>() {
+            public int compare(Constant a, Constant b) {
+                int ret;
+                ret = countUses.get(b) - countUses.get(a);
+
+                if (ret == 0) {
+                    /*
+                     * Provide sorting determinisim for constants with same
+                     * usage count.
+                     */
+                    ret = a.compareTo(b);
+                }
+
+                return ret;
+            }
+
+            @Override
+            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} 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 {@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())) {
+            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.
+                 */
+                continue;
+            }
+
+            LocalItem local = localAssignment.getLocalItem();
+
+            // Un-associate original use.
+            use.setResultLocal(null);
+
+            // Now add a mark-local to the new reg immediately after.
+            newReg = newReg.withLocalItem(local);
+
+            SsaInsn newInsn
+                    = SsaInsn.makeFromRop(
+                        new PlainInsn(Rops.opMarkLocal(newReg),
+                        SourcePosition.NO_INFO, null,
+                                RegisterSpecList.make(newReg)),
+                    use.getBlock());
+
+            ArrayList<SsaInsn> insns = use.getBlock().getInsns();
+
+            insns.add(insns.indexOf(use) + 1, newInsn);
+        }
+    }
+
+    /**
+     * Updates all uses of various consts to use the values in the newly
+     * assigned registers.
+     *
+     * @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.
+         */
+        final HashSet<TypedConstant> usedByLocal
+                = new HashSet<TypedConstant>();
+
+        final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
+
+        for (int i = 0; i < origRegCount; i++) {
+            SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
+
+            if (insn == null) {
+                continue;
+            }
+
+            final RegisterSpec origReg = insn.getResult();
+            TypeBearer typeBearer = insn.getResult().getTypeBearer();
+
+            if (!typeBearer.isConstant()) continue;
+
+            TypedConstant cst = (TypedConstant) typeBearer;
+            final RegisterSpec newReg = newRegs.get(cst);
+
+            if (newReg == null) {
+                continue;
+            }
+
+            if (ssaMeth.isRegALocal(origReg)) {
+                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.
+                     */
+                    if (usedByLocal.contains(cst)) {
+                        continue;
+                    } else {
+                        usedByLocal.add(cst);
+                        fixLocalAssignment(origReg, newRegs.get(cst));
+                    }
+                }
+            }
+
+            // maps an original const register to the new collected register
+            RegisterMapper mapper = new RegisterMapper() {
+                @Override
+                public int getNewRegisterCount() {
+                    return ssaMeth.getRegCount();
+                }
+
+                @Override
+                public RegisterSpec map(RegisterSpec registerSpec) {
+                    if (registerSpec.getReg() == origReg.getReg()) {
+                        return newReg.withLocalItem(
+                                registerSpec.getLocalItem());
+                    }
+
+                    return registerSpec;
+                }
+            };
+
+            for (SsaInsn use : useList[origReg.getReg()]) {
+                if (use.canThrow()
+                        && use.getBlock().getSuccessors().cardinality() > 1) {
+                    continue;
+                }
+                use.mapSourceRegisters(mapper);
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/DeadCodeRemover.java b/dx/src/com/android/dx/ssa/DeadCodeRemover.java
new file mode 100644
index 0000000..07fb553
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/DeadCodeRemover.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.code.Insn;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashSet;
+
+/**
+ * A variation on Appel Algorithm 19.12 "Dead code elimination in SSA form".
+ *
+ * TODO this algorithm is more efficient if run in reverse from exit
+ * block to entry block.
+ */
+public class DeadCodeRemover {
+    /** method we're processing */
+    private final SsaMethod ssaMeth;
+
+    /** ssaMeth.getRegCount() */
+    private final int regCount;
+
+    /**
+     * indexed by register: whether reg should be examined
+     * (does it correspond to a no-side-effect insn?)
+     */
+    private final BitSet worklist;
+
+    /** use list indexed by register; modified during operation */
+    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 = 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();
+    }
+
+    /**
+     * Runs the dead code remover.
+     */
+    private void run() {
+        pruneDeadInstructions();
+
+        HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+        ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist));
+
+        int regV;
+
+        while ( 0 <= (regV = worklist.nextSetBit(0)) ) {
+            worklist.clear(regV);
+
+            if (useList[regV].size() == 0
+                    || isCircularNoSideEffect(regV, null)) {
+
+                SsaInsn insnS = ssaMeth.getDefinitionForRegister(regV);
+
+                // This insn has already been deleted.
+                if (deletedInsns.contains(insnS)) {
+                    continue;
+                }
+
+                RegisterSpecList sources = insnS.getSources();
+
+                int sz = sources.size();
+                for (int i = 0; i < sz; i++) {
+                    // Delete this insn from all usage lists.
+                    RegisterSpec source = sources.get(i);
+                    useList[source.getReg()].remove(insnS);
+
+                    if (!hasSideEffect(
+                            ssaMeth.getDefinitionForRegister(
+                                    source.getReg()))) {
+                        /*
+                         * 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.
+                deletedInsns.add(insnS);
+            }
+        }
+
+        ssaMeth.deleteInsns(deletedInsns);
+    }
+
+    /**
+     * Removes all instructions from every unreachable block.
+     */
+    private void pruneDeadInstructions() {
+        HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+        ssaMeth.computeReachability();
+
+        for (SsaBasicBlock block : ssaMeth.getBlocks()) {
+            if (block.isReachable()) continue;
+
+            // Prune instructions from unreachable blocks
+            for (int i = 0; i < block.getInsns().size(); i++) {
+                SsaInsn insn = block.getInsns().get(i);
+                RegisterSpecList sources = insn.getSources();
+                int sourcesSize = sources.size();
+
+                // Delete this instruction completely if it has sources
+                if (sourcesSize != 0) {
+                    deletedInsns.add(insn);
+                }
+
+                // Delete this instruction from all usage lists.
+                for (int j = 0; j < sourcesSize; j++) {
+                    RegisterSpec source = sources.get(j);
+                    useList[source.getReg()].remove(insn);
+                }
+
+                // Remove this instruction result from the sources of any phis
+                RegisterSpec result = insn.getResult();
+                if (result == null) continue;
+                for (SsaInsn use : useList[result.getReg()]) {
+                    if (use instanceof PhiInsn) {
+                        PhiInsn phiUse = (PhiInsn) use;
+                        phiUse.removePhiRegister(result);
+                    }
+                }
+            }
+        }
+
+        ssaMeth.deleteInsns(deletedInsns);
+    }
+
+    /**
+     * Returns true if the only uses of this register form a circle of
+     * operations with no side effects.
+     *
+     * @param regV register to examine
+     * @param set a set of registers that we've already determined
+     * are only used as sources in operations with no side effect or null
+     * if this is the first recursion
+     * @return true if usage is circular without side effect
+     */
+    private boolean isCircularNoSideEffect(int regV, BitSet set) {
+        if ((set != null) && set.get(regV)) {
+            return true;
+        }
+
+        for (SsaInsn use : useList[regV]) {
+            if (hasSideEffect(use)) {
+                return false;
+            }
+        }
+
+        if (set == null) {
+            set = new BitSet(regCount);
+        }
+
+        // This register is only used in operations that have no side effect.
+        set.set(regV);
+
+        for (SsaInsn use : useList[regV]) {
+            RegisterSpec result = use.getResult();
+
+            if (result == null
+                    || !isCircularNoSideEffect(result.getReg(), set)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 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 {@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.
+             */
+            return true;
+        }
+
+        return insn.hasSideEffect();
+    }
+
+    /**
+     * A callback class used to build up the initial worklist of
+     * registers defined by an instruction with no side effect.
+     */
+    static private class NoSideEffectVisitor implements SsaInsn.Visitor {
+        BitSet noSideEffectRegs;
+
+        /**
+         * Passes in data structures that will be filled out after
+         * ssaMeth.forEachInsn() is called with this instance.
+         *
+         * @param noSideEffectRegs to-build bitset of regs that are
+         * results of regs with no side effects
+         */
+        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 (!hasSideEffect(insn)) {
+                noSideEffectRegs.set(insn.getResult().getReg());
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitPhiInsn (PhiInsn phi) {
+            // If we're tracking local vars, then some phis have side effects.
+            if (!hasSideEffect(phi)) {
+                noSideEffectRegs.set(phi.getResult().getReg());
+            }
+        }
+
+        /** {@inheritDoc} */
+        public void visitNonMoveInsn (NormalSsaInsn insn) {
+            RegisterSpec result = insn.getResult();
+            if (!hasSideEffect(insn) && result != null) {
+                noSideEffectRegs.set(result.getReg());
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/DomFront.java b/dx/src/com/android/dx/ssa/DomFront.java
new file mode 100644
index 0000000..941a317
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/DomFront.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.util.IntSet;
+import com.android.dx.util.BitIntSet;
+import com.android.dx.util.ListIntSet;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+
+/**
+ * Calculates the dominance-frontiers of a methot's basic blocks.
+ * Algorithm from "A Simple, Fast Dominance Algorithm" by Cooper,
+ * 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 {
+        /**
+         * {@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 {@code non-null;} method to process
+     */
+    public DomFront(SsaMethod meth) {
+        this.meth = meth;
+        nodes = meth.getBlocks();
+
+        int szNodes = nodes.size();
+        domInfos = new DomInfo[szNodes];
+
+        for (int i = 0; i < szNodes; i++) {
+            domInfos[i] = new DomInfo();
+        }
+    }
+
+    /**
+     * Calculates the dominance frontier information for the method.
+     *
+     * @return {@code non-null;} an array of DomInfo structures
+     */
+    public DomInfo[] run() {
+        int szNodes = nodes.size();
+
+        if (DEBUG) {
+            for (int i = 0; i < szNodes; i++) {
+                SsaBasicBlock node = nodes.get(i);
+                System.out.println("pred[" + i + "]: "
+                        + node.getPredecessors());
+            }
+        }
+
+        Dominators methDom = Dominators.make(meth, domInfos, false);
+
+        if (DEBUG) {
+            for (int i = 0; i < szNodes; i++) {
+                DomInfo info = domInfos[i];
+                System.out.println("idom[" + i + "]: "
+                        + info.idom);
+            }
+        }
+
+        buildDomTree();
+
+        if (DEBUG) {
+            debugPrintDomChildren();
+        }
+
+        for (int i = 0; i < szNodes; i++) {
+            domInfos[i].dominanceFrontiers
+                    = SetFactory.makeDomFrontSet(szNodes);
+        }
+
+        calcDomFronts();
+
+        if (DEBUG) {
+            for (int i = 0; i < szNodes; i++) {
+                System.out.println("df[" + i + "]: "
+                        + domInfos[i].dominanceFrontiers);
+            }
+        }
+
+        return domInfos;
+    }
+
+    private void debugPrintDomChildren() {
+        int szNodes = nodes.size();
+
+        for (int i = 0; i < szNodes; i++) {
+            SsaBasicBlock node = nodes.get(i);
+            StringBuffer sb = new StringBuffer();
+
+            sb.append('{');
+            boolean comma = false;
+            for (SsaBasicBlock child : node.getDomChildren()) {
+                if (comma) {
+                    sb.append(',');
+                }
+                sb.append(child);
+                comma = true;
+            }
+            sb.append('}');
+
+            System.out.println("domChildren[" + node + "]: "
+                    + sb);
+        }
+    }
+
+    /**
+     * The dominators algorithm leaves us knowing who the immediate dominator
+     * is for each node. This sweeps the node list and builds the proper
+     * dominance tree.
+     */
+    private void buildDomTree() {
+        int szNodes = nodes.size();
+
+        for (int i = 0; i < szNodes; i++) {
+            DomInfo info = domInfos[i];
+
+            if (info.idom == -1) continue;
+
+            SsaBasicBlock domParent = nodes.get(info.idom);
+            domParent.addDomChild(nodes.get(i));
+        }
+    }
+
+    /**
+     * Calculates the dominance-frontier set.
+     * from "A Simple, Fast Dominance Algorithm" by Cooper,
+     * Harvey, and Kennedy; transliterated to Java.
+     */
+    private void calcDomFronts() {
+        int szNodes = nodes.size();
+
+        for (int b = 0; b < szNodes; b++) {
+            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; /* 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.
+                         */
+                        if (runnerIndex == -1) break;
+
+                        DomInfo runnerInfo = domInfos[runnerIndex];
+
+                        if (runnerInfo.dominanceFrontiers.has(b)) {
+                            break;
+                        }
+
+                        // 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
new file mode 100644
index 0000000..503e857
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/Dominators.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashSet;
+
+/**
+ * This class computes dominator and post-dominator information using the
+ * Lengauer-Tarjan method.
+ *
+ * See A Fast Algorithm for Finding Dominators in a Flowgraph
+ * T. Lengauer & R. Tarjan, ACM TOPLAS July 1979, pgs 121-141.
+ *
+ * This implementation runs in time O(n log n).  The time bound
+ * could be changed to O(n * ack(n)) with a small change to the link and eval,
+ * and an addition of a child field to the DFS info. In reality, the constant
+ * overheads are high enough that the current method is faster in all but the
+ * strangest artificially constructed examples.
+ *
+ * The basic idea behind this algorithm is to perform a DFS walk, keeping track
+ * of various info about parents.  We then use this info to calculate the
+ * dominators, using union-find structures to link together the DFS info,
+ * then finally evaluate the union-find results to get the dominators.
+ * This implementation is m log n because it does not perform union by
+ * rank to keep the union-find tree balanced.
+ */
+public final class Dominators {
+    /* 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 final ArrayList<SsaBasicBlock> blocks;
+
+    /** indexed by basic block index */
+    private final DFSInfo[] info;
+
+    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>();
+    }
+
+    /**
+     * 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);
+
+        result.run();
+        return result;
+    }
+
+    private BitSet getSuccs(SsaBasicBlock block) {
+        if (postdom) {
+            return block.getPredecessors();
+        } else {
+            return block.getSuccessors();
+        }
+    }
+
+    private BitSet getPreds(SsaBasicBlock block) {
+        if (postdom) {
+            return block.getSuccessors();
+        } else {
+            return block.getPredecessors();
+        }
+    }
+
+    /**
+     * Performs path compress on the DFS info.
+     *
+     * @param in Basic block whose DFS info we are path compressing.
+     */
+    private void compress(SsaBasicBlock in) {
+        DFSInfo bbInfo = info[in.getIndex()];
+        DFSInfo ancestorbbInfo = info[bbInfo.ancestor.getIndex()];
+
+        if (ancestorbbInfo.ancestor != null) {
+            ArrayList<SsaBasicBlock> worklist = new ArrayList<SsaBasicBlock>();
+            HashSet<SsaBasicBlock> visited = new HashSet<SsaBasicBlock>();
+            worklist.add(in);
+
+            while (!worklist.isEmpty()) {
+                int wsize = worklist.size();
+                SsaBasicBlock v = worklist.get(wsize - 1);
+                DFSInfo vbbInfo = info[v.getIndex()];
+                SsaBasicBlock vAncestor = vbbInfo.ancestor;
+                DFSInfo vabbInfo = info[vAncestor.getIndex()];
+
+                // Make sure we process our ancestor before ourselves.
+                if (visited.add(vAncestor) && vabbInfo.ancestor != null) {
+                    worklist.add(vAncestor);
+                    continue;
+                }
+                worklist.remove(wsize - 1);
+
+                // Update based on ancestor info.
+                if (vabbInfo.ancestor == null) {
+                    continue;
+                }
+                SsaBasicBlock vAncestorRep = vabbInfo.rep;
+                SsaBasicBlock vRep = vbbInfo.rep;
+                if (info[vAncestorRep.getIndex()].semidom
+                        < info[vRep.getIndex()].semidom) {
+                    vbbInfo.rep = vAncestorRep;
+                }
+                vbbInfo.ancestor = vabbInfo.ancestor;
+            }
+        }
+    }
+
+    private SsaBasicBlock eval(SsaBasicBlock v) {
+        DFSInfo bbInfo = info[v.getIndex()];
+
+        if (bbInfo.ancestor == null) {
+            return v;
+        }
+
+        compress(v);
+        return bbInfo.rep;
+    }
+
+    /**
+     * Performs dominator/post-dominator calculation for the control
+     * flow graph.
+     *
+     * @param meth {@code non-null;} method to analyze
+     */
+    private void run() {
+        SsaBasicBlock root = postdom
+                ? meth.getExitBlock() : meth.getEntryBlock();
+
+        if (root != null) {
+            vertex.add(root);
+            domInfos[root.getIndex()].idom = root.getIndex();
+        }
+
+        /*
+         * First we perform a DFS numbering of the blocks, by
+         * numbering the dfs tree roots.
+         */
+
+        DfsWalker walker = new DfsWalker();
+        meth.forEachBlockDepthFirst(postdom, walker);
+
+        // the largest semidom number assigned
+        int dfsMax = vertex.size() - 1;
+
+        // Now calculate semidominators.
+        for (int i = dfsMax; i >= 2; --i) {
+            SsaBasicBlock w = vertex.get(i);
+            DFSInfo wInfo = info[w.getIndex()];
+
+            BitSet preds = getPreds(w);
+            for (int j = preds.nextSetBit(0);
+                 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.
+                 */
+                if (predInfo != null) {
+                    int predSemidom = info[eval(predBlock).getIndex()].semidom;
+                    if (predSemidom < wInfo.semidom) {
+                        wInfo.semidom = predSemidom;
+                    }
+                }
+            }
+            info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w);
+
+            /*
+             * 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.
+            ArrayList<SsaBasicBlock> wParentBucket;
+            wParentBucket = info[wInfo.parent.getIndex()].bucket;
+
+            while (!wParentBucket.isEmpty()) {
+                int lastItem = wParentBucket.size() - 1;
+                SsaBasicBlock last = wParentBucket.remove(lastItem);
+                SsaBasicBlock U = eval(last);
+                if (info[U.getIndex()].semidom
+                        < info[last.getIndex()].semidom) {
+                    domInfos[last.getIndex()].idom = U.getIndex();
+                } else {
+                    domInfos[last.getIndex()].idom = wInfo.parent.getIndex();
+                }
+            }
+        }
+
+        // Now explicitly define the immediate dominator of each vertex
+        for (int i =  2; i <= dfsMax; ++i) {
+            SsaBasicBlock w = vertex.get(i);
+            if (domInfos[w.getIndex()].idom
+                    != vertex.get(info[w.getIndex()].semidom).getIndex()) {
+                domInfos[w.getIndex()].idom
+                        = domInfos[domInfos[w.getIndex()].idom].idom;
+            }
+        }
+    }
+
+    /**
+     * 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.
+     */
+    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/EscapeAnalysis.java b/dx/src/com/android/dx/ssa/EscapeAnalysis.java
new file mode 100644
index 0000000..b02c929
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/EscapeAnalysis.java
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.Exceptions;
+import com.android.dx.rop.code.FillArrayDataInsn;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.ThrowingCstInsn;
+import com.android.dx.rop.code.ThrowingInsn;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstNat;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.CstType;
+import com.android.dx.rop.cst.TypedConstant;
+import com.android.dx.rop.cst.Zeroes;
+import com.android.dx.rop.type.StdTypeList;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Simple intraprocedural escape analysis. Finds new arrays that don't escape
+ * the method they are created in and replaces the array values with registers.
+ */
+public class EscapeAnalysis {
+    /**
+     * Struct used to generate and maintain escape analysis results.
+     */
+    static class EscapeSet {
+        /** set containing all registers related to an object */
+        BitSet regSet;
+        /** escape state of the object */
+        EscapeState escape;
+        /** list of objects that are put into this object */
+        ArrayList<EscapeSet> childSets;
+        /** list of objects that this object is put into */
+        ArrayList<EscapeSet> parentSets;
+        /** flag to indicate this object is a scalar replaceable array */
+        boolean replaceableArray;
+
+        /**
+         * Constructs an instance of an EscapeSet
+         *
+         * @param reg the SSA register that defines the object
+         * @param size the number of registers in the method
+         * @param escState the lattice value to initially set this to
+         */
+        EscapeSet(int reg, int size, EscapeState escState) {
+            regSet = new BitSet(size);
+            regSet.set(reg);
+            escape = escState;
+            childSets = new ArrayList<EscapeSet>();
+            parentSets = new ArrayList<EscapeSet>();
+            replaceableArray = false;
+        }
+    }
+
+    /**
+     * Lattice values used to indicate escape state for an object. Analysis can
+     * only raise escape state values, not lower them.
+     *
+     * TOP - Used for objects that haven't been analyzed yet
+     * NONE - Object does not escape, and is eligible for scalar replacement.
+     * METHOD - Object remains local to method, but can't be scalar replaced.
+     * INTER - Object is passed between methods. (treated as globally escaping
+     *         since this is an intraprocedural analysis)
+     * GLOBAL - Object escapes globally.
+     */
+    public enum EscapeState {
+        TOP, NONE, METHOD, INTER, GLOBAL
+    }
+
+    /** method we're processing */
+    private SsaMethod ssaMeth;
+    /** ssaMeth.getRegCount() */
+    private int regCount;
+    /** Lattice values for each object register group */
+    private ArrayList<EscapeSet> latticeValues;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param ssaMeth method to process
+     */
+    private EscapeAnalysis(SsaMethod ssaMeth) {
+        this.ssaMeth = ssaMeth;
+        this.regCount = ssaMeth.getRegCount();
+        this.latticeValues = new ArrayList<EscapeSet>();
+    }
+
+    /**
+     * Finds the index in the lattice for a particular register.
+     * Returns the size of the lattice if the register wasn't found.
+     *
+     * @param reg {@code non-null;} register being looked up
+     * @return index of the register or size of the lattice if it wasn't found.
+     */
+    private int findSetIndex(RegisterSpec reg) {
+        int i;
+        for (i = 0; i < latticeValues.size(); i++) {
+            EscapeSet e = latticeValues.get(i);
+            if (e.regSet.get(reg.getReg())) {
+                return i;
+            }
+        }
+        return i;
+    }
+
+    /**
+     * Finds the corresponding instruction for a given move result
+     *
+     * @param moveInsn {@code non-null;} a move result instruction
+     * @return {@code non-null;} the instruction that produces the result for
+     * the move
+     */
+    private SsaInsn getInsnForMove(SsaInsn moveInsn) {
+        int pred = moveInsn.getBlock().getPredecessors().nextSetBit(0);
+        ArrayList<SsaInsn> predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+        return predInsns.get(predInsns.size()-1);
+    }
+
+    /**
+     * Finds the corresponding move result for a given instruction
+     *
+     * @param insn {@code non-null;} an instruction that must always be
+     * followed by a move result
+     * @return {@code non-null;} the move result for the given instruction
+     */
+    private SsaInsn getMoveForInsn(SsaInsn insn) {
+        int succ = insn.getBlock().getSuccessors().nextSetBit(0);
+        ArrayList<SsaInsn> succInsns = ssaMeth.getBlocks().get(succ).getInsns();
+        return succInsns.get(0);
+    }
+
+    /**
+     * Creates a link in the lattice between two EscapeSets due to a put
+     * instruction. The object being put is the child and the object being put
+     * into is the parent. A child set must always have an escape state at
+     * least as high as its parent.
+     *
+     * @param parentSet {@code non-null;} the EscapeSet for the object being put
+     * into
+     * @param childSet {@code non-null;} the EscapeSet for the object being put
+     */
+    private void addEdge(EscapeSet parentSet, EscapeSet childSet) {
+        if (!childSet.parentSets.contains(parentSet)) {
+            childSet.parentSets.add(parentSet);
+        }
+        if (!parentSet.childSets.contains(childSet)) {
+            parentSet.childSets.add(childSet);
+        }
+    }
+
+    /**
+     * Merges all links in the lattice among two EscapeSets. On return, the
+     * newNode will have its old links as well as all links from the oldNode.
+     * The oldNode has all its links removed.
+     *
+     * @param newNode {@code non-null;} the EscapeSet to merge all links into
+     * @param oldNode {@code non-null;} the EscapeSet to remove all links from
+     */
+    private void replaceNode(EscapeSet newNode, EscapeSet oldNode) {
+        for (EscapeSet e : oldNode.parentSets) {
+            e.childSets.remove(oldNode);
+            e.childSets.add(newNode);
+            newNode.parentSets.add(e);
+        }
+        for (EscapeSet e : oldNode.childSets) {
+            e.parentSets.remove(oldNode);
+            e.parentSets.add(newNode);
+            newNode.childSets.add(e);
+        }
+    }
+
+    /**
+     * Performs escape analysis on a method. Finds scalar replaceable arrays and
+     * replaces them with equivalent registers.
+     *
+     * @param ssaMethod {@code non-null;} method to process
+     */
+    public static void process(SsaMethod ssaMethod) {
+        new EscapeAnalysis(ssaMethod).run();
+    }
+
+    /**
+     * Process a single instruction, looking for new objects resulting from
+     * move result or move param.
+     *
+     * @param insn {@code non-null;} instruction to process
+     */
+    private void processInsn(SsaInsn insn) {
+        int op = insn.getOpcode().getOpcode();
+        RegisterSpec result = insn.getResult();
+        EscapeSet escSet;
+
+        // Identify new objects
+        if (op == RegOps.MOVE_RESULT_PSEUDO &&
+                result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+            // Handle objects generated through move_result_pseudo
+            escSet = processMoveResultPseudoInsn(insn);
+            processRegister(result, escSet);
+        } else if (op == RegOps.MOVE_PARAM &&
+                      result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+            // Track method arguments that are objects
+            escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+            latticeValues.add(escSet);
+            processRegister(result, escSet);
+        } else if (op == RegOps.MOVE_RESULT &&
+                result.getTypeBearer().getBasicType() == Type.BT_OBJECT) {
+            // Track method return values that are objects
+            escSet = new EscapeSet(result.getReg(), regCount, EscapeState.NONE);
+            latticeValues.add(escSet);
+            processRegister(result, escSet);
+        }
+    }
+
+    /**
+     * Determine the origin of a move result pseudo instruction that generates
+     * an object. Creates a new EscapeSet for the new object accordingly.
+     *
+     * @param insn {@code non-null;} move result pseudo instruction to process
+     * @return {@code non-null;} an EscapeSet for the object referred to by the
+     * move result pseudo instruction
+     */
+    private EscapeSet processMoveResultPseudoInsn(SsaInsn insn) {
+        RegisterSpec result = insn.getResult();
+        SsaInsn prevSsaInsn = getInsnForMove(insn);
+        int prevOpcode = prevSsaInsn.getOpcode().getOpcode();
+        EscapeSet escSet;
+        RegisterSpec prevSource;
+
+        switch(prevOpcode) {
+           // New instance / Constant
+            case RegOps.NEW_INSTANCE:
+            case RegOps.CONST:
+                escSet = new EscapeSet(result.getReg(), regCount,
+                                           EscapeState.NONE);
+                break;
+            // New array
+            case RegOps.NEW_ARRAY:
+            case RegOps.FILLED_NEW_ARRAY:
+                prevSource = prevSsaInsn.getSources().get(0);
+                if (prevSource.getTypeBearer().isConstant()) {
+                    // New fixed array
+                    escSet = new EscapeSet(result.getReg(), regCount,
+                                               EscapeState.NONE);
+                    escSet.replaceableArray = true;
+                } else {
+                    // New variable array
+                    escSet = new EscapeSet(result.getReg(), regCount,
+                                               EscapeState.GLOBAL);
+                }
+                break;
+            // Loading a static object
+            case RegOps.GET_STATIC:
+                escSet = new EscapeSet(result.getReg(), regCount,
+                                           EscapeState.GLOBAL);
+                break;
+            // Type cast / load an object from a field or array
+            case RegOps.CHECK_CAST:
+            case RegOps.GET_FIELD:
+            case RegOps.AGET:
+                prevSource = prevSsaInsn.getSources().get(0);
+                int setIndex = findSetIndex(prevSource);
+
+                // Set should already exist, try to find it
+                if (setIndex != latticeValues.size()) {
+                    escSet = latticeValues.get(setIndex);
+                    escSet.regSet.set(result.getReg());
+                    return escSet;
+                }
+
+                // Set not found, must be either null or unknown
+                if (prevSource.getType() == Type.KNOWN_NULL) {
+                    escSet = new EscapeSet(result.getReg(), regCount,
+                                               EscapeState.NONE);
+               } else {
+                    escSet = new EscapeSet(result.getReg(), regCount,
+                                               EscapeState.GLOBAL);
+                }
+                break;
+            default:
+                return null;
+        }
+
+        // Add the newly created escSet to the lattice and return it
+        latticeValues.add(escSet);
+        return escSet;
+    }
+
+    /**
+     * Iterate through all the uses of a new object.
+     *
+     * @param result {@code non-null;} register where new object is stored
+     * @param escSet {@code non-null;} EscapeSet for the new object
+     */
+    private void processRegister(RegisterSpec result, EscapeSet escSet) {
+        ArrayList<RegisterSpec> regWorklist = new ArrayList<RegisterSpec>();
+        regWorklist.add(result);
+
+        // Go through the worklist
+        while (!regWorklist.isEmpty()) {
+            int listSize = regWorklist.size() - 1;
+            RegisterSpec def = regWorklist.remove(listSize);
+            List<SsaInsn> useList = ssaMeth.getUseListForRegister(def.getReg());
+
+            // Handle all the uses of this register
+            for (SsaInsn use : useList) {
+                Rop useOpcode = use.getOpcode();
+
+                if (useOpcode == null) {
+                    // Handle phis
+                    processPhiUse(use, escSet, regWorklist);
+                } else {
+                    // Handle other opcodes
+                    processUse(def, use, escSet, regWorklist);
+                }
+            }
+        }
+    }
+
+    /**
+     * Handles phi uses of new objects. Will merge together the sources of a phi
+     * into a single EscapeSet. Adds the result of the phi to the worklist so
+     * its uses can be followed.
+     *
+     * @param use {@code non-null;} phi use being processed
+     * @param escSet {@code non-null;} EscapeSet for the object
+     * @param regWorklist {@code non-null;} worklist of instructions left to
+     * process for this object
+     */
+    private void processPhiUse(SsaInsn use, EscapeSet escSet,
+                                   ArrayList<RegisterSpec> regWorklist) {
+        int setIndex = findSetIndex(use.getResult());
+        if (setIndex != latticeValues.size()) {
+            // Check if result is in a set already
+            EscapeSet mergeSet = latticeValues.get(setIndex);
+            if (mergeSet != escSet) {
+                // If it is, merge the sets and states, then delete the copy
+                escSet.replaceableArray = false;
+                escSet.regSet.or(mergeSet.regSet);
+                if (escSet.escape.compareTo(mergeSet.escape) < 0) {
+                    escSet.escape = mergeSet.escape;
+                }
+                replaceNode(escSet, mergeSet);
+                latticeValues.remove(setIndex);
+            }
+        } else {
+            // If no set is found, add it to this escSet and the worklist
+            escSet.regSet.set(use.getResult().getReg());
+            regWorklist.add(use.getResult());
+        }
+    }
+
+    /**
+     * Handles non-phi uses of new objects. Checks to see how instruction is
+     * used and updates the escape state accordingly.
+     *
+     * @param def {@code non-null;} register holding definition of new object
+     * @param use {@code non-null;} use of object being processed
+     * @param escSet {@code non-null;} EscapeSet for the object
+     * @param regWorklist {@code non-null;} worklist of instructions left to
+     * process for this object
+     */
+    private void processUse(RegisterSpec def, SsaInsn use, EscapeSet escSet,
+                                ArrayList<RegisterSpec> regWorklist) {
+        int useOpcode = use.getOpcode().getOpcode();
+        switch (useOpcode) {
+            case RegOps.MOVE:
+                // Follow uses of the move by adding it to the worklist
+                escSet.regSet.set(use.getResult().getReg());
+                regWorklist.add(use.getResult());
+                break;
+            case RegOps.IF_EQ:
+            case RegOps.IF_NE:
+            case RegOps.CHECK_CAST:
+                // Compared objects can't be replaced, so promote if necessary
+                if (escSet.escape.compareTo(EscapeState.METHOD) < 0) {
+                    escSet.escape = EscapeState.METHOD;
+                }
+                break;
+            case RegOps.APUT:
+                // For array puts, check for a constant array index
+                RegisterSpec putIndex = use.getSources().get(2);
+                if (!putIndex.getTypeBearer().isConstant()) {
+                    // If not constant, array can't be replaced
+                    escSet.replaceableArray = false;
+                }
+                // Intentional fallthrough
+            case RegOps.PUT_FIELD:
+                // Skip non-object puts
+                RegisterSpec putValue = use.getSources().get(0);
+                if (putValue.getTypeBearer().getBasicType() != Type.BT_OBJECT) {
+                    break;
+                }
+                escSet.replaceableArray = false;
+
+                // Raise 1st object's escape state to 2nd if 2nd is higher
+                RegisterSpecList sources = use.getSources();
+                if (sources.get(0).getReg() == def.getReg()) {
+                    int setIndex = findSetIndex(sources.get(1));
+                    if (setIndex != latticeValues.size()) {
+                        EscapeSet parentSet = latticeValues.get(setIndex);
+                        addEdge(parentSet, escSet);
+                        if (escSet.escape.compareTo(parentSet.escape) < 0) {
+                            escSet.escape = parentSet.escape;
+                        }
+                    }
+                } else {
+                    int setIndex = findSetIndex(sources.get(0));
+                    if (setIndex != latticeValues.size()) {
+                        EscapeSet childSet = latticeValues.get(setIndex);
+                        addEdge(escSet, childSet);
+                        if (childSet.escape.compareTo(escSet.escape) < 0) {
+                            childSet.escape = escSet.escape;
+                        }
+                    }
+                }
+                break;
+            case RegOps.AGET:
+                // For array gets, check for a constant array index
+                RegisterSpec getIndex = use.getSources().get(1);
+                if (!getIndex.getTypeBearer().isConstant()) {
+                    // If not constant, array can't be replaced
+                    escSet.replaceableArray = false;
+                }
+                break;
+            case RegOps.PUT_STATIC:
+                // Static puts cause an object to escape globally
+                escSet.escape = EscapeState.GLOBAL;
+                break;
+            case RegOps.INVOKE_STATIC:
+            case RegOps.INVOKE_VIRTUAL:
+            case RegOps.INVOKE_SUPER:
+            case RegOps.INVOKE_DIRECT:
+            case RegOps.INVOKE_INTERFACE:
+            case RegOps.RETURN:
+            case RegOps.THROW:
+                // These operations cause an object to escape interprocedurally
+                escSet.escape = EscapeState.INTER;
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Performs scalar replacement on all eligible arrays.
+     */
+    private void scalarReplacement() {
+        // Iterate through lattice, looking for non-escaping replaceable arrays
+        for (EscapeSet escSet : latticeValues) {
+            if (!escSet.replaceableArray || escSet.escape != EscapeState.NONE) {
+                continue;
+            }
+
+            // Get the instructions for the definition and move of the array
+            int e = escSet.regSet.nextSetBit(0);
+            SsaInsn def = ssaMeth.getDefinitionForRegister(e);
+            SsaInsn prev = getInsnForMove(def);
+
+            // Create a map for the new registers that will be created
+            TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
+            int length = ((CstLiteralBits) lengthReg).getIntBits();
+            ArrayList<RegisterSpec> newRegs =
+                new ArrayList<RegisterSpec>(length);
+            HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+            // Replace the definition of the array with registers
+            replaceDef(def, prev, length, newRegs);
+
+            // Mark definition instructions for deletion
+            deletedInsns.add(prev);
+            deletedInsns.add(def);
+
+            // Go through all uses of the array
+            List<SsaInsn> useList = ssaMeth.getUseListForRegister(e);
+            for (SsaInsn use : useList) {
+                // Replace the use with scalars and then mark it for deletion
+                replaceUse(use, prev, newRegs, deletedInsns);
+                deletedInsns.add(use);
+            }
+
+            // Delete all marked instructions
+            ssaMeth.deleteInsns(deletedInsns);
+            ssaMeth.onInsnsChanged();
+
+            // Convert the method back to SSA form
+            SsaConverter.updateSsaMethod(ssaMeth, regCount);
+
+            // Propagate and remove extra moves added by scalar replacement
+            movePropagate();
+        }
+    }
+
+    /**
+     * Replaces the instructions that define an array with equivalent registers.
+     * For each entry in the array, a register is created, initialized to zero.
+     * A mapping between this register and the corresponding array index is
+     * added.
+     *
+     * @param def {@code non-null;} move result instruction for array
+     * @param prev {@code non-null;} instruction for instantiating new array
+     * @param length size of the new array
+     * @param newRegs {@code non-null;} mapping of array indices to new
+     * registers to be populated
+     */
+    private void replaceDef(SsaInsn def, SsaInsn prev, int length,
+                                ArrayList<RegisterSpec> newRegs) {
+        Type resultType = def.getResult().getType();
+
+        // Create new zeroed out registers for each element in the array
+        for (int i = 0; i < length; i++) {
+            Constant newZero = Zeroes.zeroFor(resultType.getComponentType());
+            TypedConstant typedZero = (TypedConstant) newZero;
+            RegisterSpec newReg =
+                RegisterSpec.make(ssaMeth.makeNewSsaReg(), typedZero);
+            newRegs.add(newReg);
+            insertPlainInsnBefore(def, RegisterSpecList.EMPTY, newReg,
+                                      RegOps.CONST, newZero);
+        }
+    }
+
+    /**
+     * Replaces the use for a scalar replaceable array. Gets and puts become
+     * move instructions, and array lengths and fills are handled. Can also
+     * identify ArrayIndexOutOfBounds exceptions and throw them if detected.
+     *
+     * @param use {@code non-null;} move result instruction for array
+     * @param prev {@code non-null;} instruction for instantiating new array
+     * @param newRegs {@code non-null;} mapping of array indices to new
+     * registers
+     * @param deletedInsns {@code non-null;} set of instructions marked for
+     * deletion
+     */
+    private void replaceUse(SsaInsn use, SsaInsn prev,
+                                ArrayList<RegisterSpec> newRegs,
+                                HashSet<SsaInsn> deletedInsns) {
+        int index;
+        int length = newRegs.size();
+        SsaInsn next;
+        RegisterSpecList sources;
+        RegisterSpec source, result;
+        CstLiteralBits indexReg;
+
+        switch (use.getOpcode().getOpcode()) {
+            case RegOps.AGET:
+                // Replace array gets with moves
+                next = getMoveForInsn(use);
+                sources = use.getSources();
+                indexReg = ((CstLiteralBits) sources.get(1).getTypeBearer());
+                index = indexReg.getIntBits();
+                if (index < length) {
+                    source = newRegs.get(index);
+                    result = source.withReg(next.getResult().getReg());
+                    insertPlainInsnBefore(next, RegisterSpecList.make(source),
+                                              result, RegOps.MOVE, null);
+                } else {
+                    // Throw an exception if the index is out of bounds
+                    insertExceptionThrow(next, sources.get(1), deletedInsns);
+                    deletedInsns.add(next.getBlock().getInsns().get(2));
+                }
+                deletedInsns.add(next);
+                break;
+            case RegOps.APUT:
+                // Replace array puts with moves
+                sources = use.getSources();
+                indexReg = ((CstLiteralBits) sources.get(2).getTypeBearer());
+                index = indexReg.getIntBits();
+                if (index < length) {
+                    source = sources.get(0);
+                    result = source.withReg(newRegs.get(index).getReg());
+                    insertPlainInsnBefore(use, RegisterSpecList.make(source),
+                                              result, RegOps.MOVE, null);
+                    // Update the newReg entry to mark value as unknown now
+                    newRegs.set(index, result.withSimpleType());
+                } else {
+                    // Throw an exception if the index is out of bounds
+                    insertExceptionThrow(use, sources.get(2), deletedInsns);
+                }
+                break;
+            case RegOps.ARRAY_LENGTH:
+                // Replace array lengths with const instructions
+                TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
+                //CstInteger lengthReg = CstInteger.make(length);
+                next = getMoveForInsn(use);
+                insertPlainInsnBefore(next, RegisterSpecList.EMPTY,
+                                          next.getResult(), RegOps.CONST,
+                                          (Constant) lengthReg);
+                deletedInsns.add(next);
+                break;
+            case RegOps.MARK_LOCAL:
+                // Remove mark local instructions
+                break;
+            case RegOps.FILL_ARRAY_DATA:
+                // Create const instructions for each fill value
+                Insn ropUse = use.getOriginalRopInsn();
+                FillArrayDataInsn fill = (FillArrayDataInsn) ropUse;
+                ArrayList<Constant> constList = fill.getInitValues();
+                for (int i = 0; i < length; i++) {
+                    RegisterSpec newFill =
+                        RegisterSpec.make(newRegs.get(i).getReg(),
+                                              (TypeBearer) constList.get(i));
+                    insertPlainInsnBefore(use, RegisterSpecList.EMPTY, newFill,
+                                              RegOps.CONST, constList.get(i));
+                    // Update the newRegs to hold the new const value
+                    newRegs.set(i, newFill);
+                }
+                break;
+            default:
+        }
+    }
+
+    /**
+     * Identifies extra moves added by scalar replacement and propagates the
+     * source of the move to any users of the result.
+     */
+    private void movePropagate() {
+        for (int i = 0; i < ssaMeth.getRegCount(); i++) {
+            SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
+
+            // Look for move instructions only
+            if (insn == null || insn.getOpcode() == null ||
+                insn.getOpcode().getOpcode() != RegOps.MOVE) {
+                continue;
+            }
+
+            final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
+            final RegisterSpec source = insn.getSources().get(0);
+            final RegisterSpec result = insn.getResult();
+
+            // Ignore moves that weren't added due to scalar replacement
+            if (source.getReg() < regCount && result.getReg() < regCount) {
+                continue;
+            }
+
+            // Create a mapping from source to result
+            RegisterMapper mapper = new RegisterMapper() {
+                @Override
+                public int getNewRegisterCount() {
+                    return ssaMeth.getRegCount();
+                }
+
+                @Override
+                public RegisterSpec map(RegisterSpec registerSpec) {
+                    if (registerSpec.getReg() == result.getReg()) {
+                        return source;
+                    }
+
+                    return registerSpec;
+                }
+            };
+
+            // Modify all uses of the move to use the source of the move instead
+            for (SsaInsn use : useList[result.getReg()]) {
+                use.mapSourceRegisters(mapper);
+            }
+        }
+    }
+
+    /**
+     * Runs escape analysis and scalar replacement of arrays.
+     */
+    private void run() {
+        ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
+            public void visitBlock (SsaBasicBlock block,
+                    SsaBasicBlock unused) {
+                block.forEachInsn(new SsaInsn.Visitor() {
+                    public void visitMoveInsn(NormalSsaInsn insn) {
+                        // do nothing
+                    }
+
+                    public void visitPhiInsn(PhiInsn insn) {
+                        // do nothing
+                    }
+
+                    public void visitNonMoveInsn(NormalSsaInsn insn) {
+                        processInsn(insn);
+                    }
+                });
+            }
+        });
+
+        // Go through lattice and promote fieldSets as necessary
+        for (EscapeSet e : latticeValues) {
+            if (e.escape != EscapeState.NONE) {
+                for (EscapeSet field : e.childSets) {
+                    if (e.escape.compareTo(field.escape) > 0) {
+                        field.escape = e.escape;
+                    }
+                }
+            }
+        }
+
+        // Perform scalar replacement for arrays
+        scalarReplacement();
+    }
+
+    /**
+     * Replaces instructions that trigger an ArrayIndexOutofBounds exception
+     * with an actual throw of the exception.
+     *
+     * @param insn {@code non-null;} instruction causing the exception
+     * @param index {@code non-null;} index value that is out of bounds
+     * @param deletedInsns {@code non-null;} set of instructions marked for
+     * deletion
+     */
+    private void insertExceptionThrow(SsaInsn insn, RegisterSpec index,
+                                          HashSet<SsaInsn> deletedInsns) {
+        // Create a new ArrayIndexOutOfBoundsException
+        CstType exception =
+            new CstType(Exceptions.TYPE_ArrayIndexOutOfBoundsException);
+        insertThrowingInsnBefore(insn, RegisterSpecList.EMPTY, null,
+                                     RegOps.NEW_INSTANCE, exception);
+
+        // Add a successor block with a move result pseudo for the exception
+        SsaBasicBlock currBlock = insn.getBlock();
+        SsaBasicBlock newBlock =
+            currBlock.insertNewSuccessor(currBlock.getPrimarySuccessor());
+        SsaInsn newInsn = newBlock.getInsns().get(0);
+        RegisterSpec newReg =
+            RegisterSpec.make(ssaMeth.makeNewSsaReg(), exception);
+        insertPlainInsnBefore(newInsn, RegisterSpecList.EMPTY, newReg,
+                                  RegOps.MOVE_RESULT_PSEUDO, null);
+
+        // Add another successor block to initialize the exception
+        SsaBasicBlock newBlock2 =
+            newBlock.insertNewSuccessor(newBlock.getPrimarySuccessor());
+        SsaInsn newInsn2 = newBlock2.getInsns().get(0);
+        CstNat newNat = new CstNat(new CstString("<init>"), new CstString("(I)V"));
+        CstMethodRef newRef = new CstMethodRef(exception, newNat);
+        insertThrowingInsnBefore(newInsn2, RegisterSpecList.make(newReg, index),
+                                     null, RegOps.INVOKE_DIRECT, newRef);
+        deletedInsns.add(newInsn2);
+
+        // Add another successor block to throw the new exception
+        SsaBasicBlock newBlock3 =
+            newBlock2.insertNewSuccessor(newBlock2.getPrimarySuccessor());
+        SsaInsn newInsn3 = newBlock3.getInsns().get(0);
+        insertThrowingInsnBefore(newInsn3, RegisterSpecList.make(newReg), null,
+                                     RegOps.THROW, null);
+        newBlock3.replaceSuccessor(newBlock3.getPrimarySuccessorIndex(),
+                                       ssaMeth.getExitBlock().getIndex());
+        deletedInsns.add(newInsn3);
+    }
+
+    /**
+     * Inserts a new PlainInsn before the given instruction.
+     * TODO: move this somewhere more appropriate
+     *
+     * @param insn {@code non-null;} instruction to insert before
+     * @param newSources {@code non-null;} sources of new instruction
+     * @param newResult {@code non-null;} result of new instruction
+     * @param newOpcode opcode of new instruction
+     * @param cst {@code null-ok;} constant for new instruction, if any
+     */
+    private void insertPlainInsnBefore(SsaInsn insn,
+        RegisterSpecList newSources, RegisterSpec newResult, int newOpcode,
+        Constant cst) {
+
+        Insn originalRopInsn = insn.getOriginalRopInsn();
+        Rop newRop;
+        if (newOpcode == RegOps.MOVE_RESULT_PSEUDO) {
+            newRop = Rops.opMoveResultPseudo(newResult.getType());
+        } else {
+            newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
+        }
+
+        Insn newRopInsn;
+        if (cst == null) {
+            newRopInsn = new PlainInsn(newRop,
+                    originalRopInsn.getPosition(), newResult, newSources);
+        } else {
+            newRopInsn = new PlainCstInsn(newRop,
+                originalRopInsn.getPosition(), newResult, newSources, cst);
+        }
+
+        NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+        List<SsaInsn> insns = insn.getBlock().getInsns();
+
+        insns.add(insns.lastIndexOf(insn), newInsn);
+        ssaMeth.onInsnAdded(newInsn);
+    }
+
+    /**
+     * Inserts a new ThrowingInsn before the given instruction.
+     * TODO: move this somewhere more appropriate
+     *
+     * @param insn {@code non-null;} instruction to insert before
+     * @param newSources {@code non-null;} sources of new instruction
+     * @param newResult {@code non-null;} result of new instruction
+     * @param newOpcode opcode of new instruction
+     * @param cst {@code null-ok;} constant for new instruction, if any
+     */
+    private void insertThrowingInsnBefore(SsaInsn insn,
+        RegisterSpecList newSources, RegisterSpec newResult, int newOpcode,
+        Constant cst) {
+
+        Insn origRopInsn = insn.getOriginalRopInsn();
+        Rop newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
+        Insn newRopInsn;
+        if (cst == null) {
+            newRopInsn = new ThrowingInsn(newRop,
+                origRopInsn.getPosition(), newSources, StdTypeList.EMPTY);
+        } else {
+            newRopInsn = new ThrowingCstInsn(newRop,
+                origRopInsn.getPosition(), newSources, StdTypeList.EMPTY, cst);
+        }
+
+        NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+        List<SsaInsn> insns = insn.getBlock().getInsns();
+
+        insns.add(insns.lastIndexOf(insn), newInsn);
+        ssaMeth.onInsnAdded(newInsn);
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
new file mode 100644
index 0000000..851249b
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.ssa.back.InterferenceGraph;
+import com.android.dx.util.IntSet;
+import com.android.dx.util.BitIntSet;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+/**
+ * A register mapper that keeps track of the accumulated interference
+ * information for the registers in the new namespace.
+ *
+ * Please note that this mapper requires that the old namespace does not
+ * 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
+     * as needed and missing items are assumed to interfere with nothing.
+     *
+     * Bit sets are always used here, unlike elsewhere, because the max
+     * size of this matrix will be (countSsaRegs * countRopRegs), which may
+     * grow to hundreds of K but not megabytes.
+     */
+    private final ArrayList<BitIntSet> newRegInterference;
+
+    /** the interference graph for the old namespace */
+    private final InterferenceGraph oldRegInterference;
+
+    /**
+     * Constructs an instance
+     *
+     * @param countOldRegisters number of registers in old namespace
+     */
+    public InterferenceRegisterMapper(InterferenceGraph oldRegInterference,
+            int countOldRegisters) {
+        super(countOldRegisters);
+
+        newRegInterference = new ArrayList<BitIntSet>();
+        this.oldRegInterference = oldRegInterference;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void addMapping(int oldReg, int newReg, int category) {
+        super.addMapping(oldReg, newReg, category);
+
+        addInterfence(newReg, oldReg);
+
+        if (category == 2) {
+            addInterfence(newReg + 1, oldReg);
+        }
+    }
+
+    /**
+     * 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
+     * @param category category of old namespace register
+     * @return true if oldReg will interfere with newReg
+     */
+    public boolean interferes(int oldReg, int newReg, int category) {
+        if (newReg >= newRegInterference.size()) {
+            return false;
+        } else {
+            IntSet existing = newRegInterference.get(newReg);
+
+            if (existing == null) {
+                return false;
+            } else if (category == 1) {
+                return existing.has(oldReg);
+            } else {
+                return existing.has(oldReg)
+                        || (interferes(oldReg, newReg+1, category-1));
+            }
+        }
+    }
+
+    /**
+     * Checks to see if old namespace reg {@code oldReg} interferes
+     * with what currently maps to {@code newReg}.
+     *
+     * @param oldSpec {@code non-null;} old namespace register
+     * @param newReg new namespace register
+     * @return true if oldReg will interfere with newReg
+     */
+    public boolean interferes(RegisterSpec oldSpec, int newReg) {
+        return interferes(oldSpec.getReg(), newReg, oldSpec.getCategory());
+    }
+
+    /**
+     * 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
+     */
+    private void addInterfence(int newReg, int oldReg) {
+        newRegInterference.ensureCapacity(newReg + 1);
+
+        while (newReg >= newRegInterference.size()) {
+            newRegInterference.add(new BitIntSet(newReg +1));
+        }
+
+        oldRegInterference.mergeInterferenceSet(
+                oldReg, newRegInterference.get(newReg));
+    }
+
+    /**
+     * Checks to see if any of a set of old-namespace registers are
+     * pinned to the specified new-namespace reg + category. Takes into
+     * account the category of the old-namespace registers.
+     *
+     * @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());
+
+            /*
+             * If oldSpec is a category-2 register, then check both newReg
+             * and newReg - 1.
+             */
+            if (r == newReg
+                || (oldSpec.getCategory() == 2 && (r + 1) == newReg)
+                || (targetCategory == 2 && (r == newReg + 1))) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
new file mode 100644
index 0000000..f3976f2
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.PlainCstInsn;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Upgrades insn to their literal (constant-immediate) equivalent if possible.
+ * Also switches IF instructions that compare with a constant zero or null
+ * to be their IF_*Z equivalents.
+ */
+public class LiteralOpUpgrader {
+
+    /** method we're processing */
+    private final SsaMethod ssaMeth;
+
+    /**
+     * Process a method.
+     *
+     * @param ssaMethod {@code non-null;} method to process
+     */
+    public static void process(SsaMethod ssaMethod) {
+        LiteralOpUpgrader dc;
+
+        dc = new LiteralOpUpgrader(ssaMethod);
+
+        dc.run();
+    }
+
+    private LiteralOpUpgrader(SsaMethod ssaMethod) {
+        this.ssaMeth = ssaMethod;
+    }
+
+    /**
+     * Returns true if the register contains an integer 0 or a known-null
+     * object reference
+     *
+     * @param spec non-null spec
+     * @return true for 0 or null type bearers
+     */
+    private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) {
+        TypeBearer tb = spec.getTypeBearer();
+        if (tb instanceof CstLiteralBits) {
+            CstLiteralBits clb = (CstLiteralBits) tb;
+            return (clb.getLongBits() == 0);
+        }
+        return false;
+    }
+
+    /**
+     * Run the literal op upgrader
+     */
+    private void run() {
+        final TranslationAdvice advice = Optimizer.getAdvice();
+
+        ssaMeth.forEachInsn(new SsaInsn.Visitor() {
+            public void visitMoveInsn(NormalSsaInsn insn) {
+                // do nothing
+            }
+
+            public void visitPhiInsn(PhiInsn insn) {
+                // do nothing
+            }
+
+            public void visitNonMoveInsn(NormalSsaInsn insn) {
+
+                Insn originalRopInsn = insn.getOriginalRopInsn();
+                Rop opcode = originalRopInsn.getOpcode();
+                RegisterSpecList sources = insn.getSources();
+
+                // Replace insns with constant results with const insns
+                if (tryReplacingWithConstant(insn)) return;
+
+                if (sources.size() != 2 ) {
+                    // We're only dealing with two-source insns here.
+                    return;
+                }
+
+                if (opcode.getBranchingness() == Rop.BRANCH_IF) {
+                    /*
+                     * An if instruction can become an if-*z instruction.
+                     */
+                    if (isConstIntZeroOrKnownNull(sources.get(0))) {
+                        replacePlainInsn(insn, sources.withoutFirst(),
+                              RegOps.flippedIfOpcode(opcode.getOpcode()), null);
+                    } else if (isConstIntZeroOrKnownNull(sources.get(1))) {
+                        replacePlainInsn(insn, sources.withoutLast(),
+                              opcode.getOpcode(), null);
+                    }
+                } else if (advice.hasConstantOperation(
+                        opcode, sources.get(0), sources.get(1))) {
+                    insn.upgradeToLiteral();
+                } else  if (opcode.isCommutative()
+                        && advice.hasConstantOperation(
+                        opcode, sources.get(1), sources.get(0))) {
+                    /*
+                     * An instruction can be commuted to a literal operation
+                     */
+
+                    insn.setNewSources(
+                            RegisterSpecList.make(
+                                    sources.get(1), sources.get(0)));
+
+                    insn.upgradeToLiteral();
+                }
+            }
+        });
+    }
+
+    /**
+     * Tries to replace an instruction with a const instruction. The given
+     * instruction must have a constant result for it to be replaced.
+     *
+     * @param insn {@code non-null;} instruction to try to replace
+     * @return true if the instruction was replaced
+     */
+    private boolean tryReplacingWithConstant(NormalSsaInsn insn) {
+        Insn originalRopInsn = insn.getOriginalRopInsn();
+        Rop opcode = originalRopInsn.getOpcode();
+        RegisterSpec result = insn.getResult();
+
+        if (result != null && !ssaMeth.isRegALocal(result) &&
+                opcode.getOpcode() != RegOps.CONST) {
+            TypeBearer type = insn.getResult().getTypeBearer();
+            if (type.isConstant() && type.getBasicType() == Type.BT_INT) {
+                // Replace the instruction with a constant
+                replacePlainInsn(insn, RegisterSpecList.EMPTY,
+                        RegOps.CONST, (Constant) type);
+
+                // Remove the source as well if this is a move-result-pseudo
+                if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+                    int pred = insn.getBlock().getPredecessors().nextSetBit(0);
+                    ArrayList<SsaInsn> predInsns =
+                            ssaMeth.getBlocks().get(pred).getInsns();
+                    NormalSsaInsn sourceInsn =
+                            (NormalSsaInsn) predInsns.get(predInsns.size()-1);
+                    replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY,
+                            RegOps.GOTO, null);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
+     * new PlainInsn is constructed with a new RegOp and new sources.
+     *
+     * TODO move this somewhere else.
+     *
+     * @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}
+     * @param cst {@code null-ok;} constant for new instruction, if any
+     */
+    private void replacePlainInsn(NormalSsaInsn insn,
+            RegisterSpecList newSources, int newOpcode, Constant cst) {
+
+        Insn originalRopInsn = insn.getOriginalRopInsn();
+        Rop newRop = Rops.ropFor(newOpcode, insn.getResult(), newSources, cst);
+        Insn newRopInsn;
+        if (cst == null) {
+            newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(),
+                    insn.getResult(), newSources);
+        } else {
+            newRopInsn = new PlainCstInsn(newRop, originalRopInsn.getPosition(),
+                    insn.getResult(), newSources, cst);
+        }
+        NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
+
+        List<SsaInsn> insns = insn.getBlock().getInsns();
+
+        ssaMeth.onInsnRemoved(insn);
+        insns.set(insns.lastIndexOf(insn), newInsn);
+        ssaMeth.onInsnAdded(newInsn);
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/LocalVariableExtractor.java b/dx/src/com/android/dx/ssa/LocalVariableExtractor.java
new file mode 100644
index 0000000..11d53cf
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/LocalVariableExtractor.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpecSet;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Code to figure out which local variables are active at which points in
+ * a method. Stolen and retrofitted from
+ * com.android.dx.rop.code.LocalVariableExtractor
+ *
+ * TODO remove this. Allow Rop-form LocalVariableInfo to be passed in,
+ * converted, and adapted through edge-splitting.
+ */
+public class LocalVariableExtractor {
+    /** {@code non-null;} method being extracted from */
+    private final SsaMethod method;
+
+    /** {@code non-null;} block list for the method */
+    private final ArrayList<SsaBasicBlock> blocks;
+
+    /** {@code non-null;} result in-progress */
+    private final LocalVariableInfo resultInfo;
+
+    /** {@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 {@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);
+        return lve.doit();
+    }
+
+    /**
+     * Constructs an instance. This method is private. Use {@link #extract}.
+     *
+     * @param method {@code non-null;} the method to extract from
+     */
+    private LocalVariableExtractor(SsaMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        ArrayList<SsaBasicBlock> blocks = method.getBlocks();
+
+        this.method = method;
+        this.blocks = blocks;
+        this.resultInfo = new LocalVariableInfo(method);
+        this.workSet = new BitSet(blocks.size());
+    }
+
+    /**
+     * Does the extraction.
+     *
+     * @return {@code non-null;} the extracted information
+     */
+    private LocalVariableInfo doit() {
+
+        //FIXME why is this needed here?
+        if (method.getRegCount() > 0 ) {
+            for (int bi = method.getEntryBlockIndex();
+                 bi >= 0;
+                 bi = workSet.nextSetBit(0)) {
+                workSet.clear(bi);
+                processBlock(bi);
+            }
+        }
+
+        resultInfo.setImmutable();
+        return resultInfo;
+    }
+
+    /**
+     * Processes a single block.
+     *
+     * @param blockIndex {@code >= 0;} block index of the block to process
+     */
+    private void processBlock(int blockIndex) {
+        RegisterSpecSet primaryState
+                = resultInfo.mutableCopyOfStarts(blockIndex);
+        SsaBasicBlock block = blocks.get(blockIndex);
+        List<SsaInsn> insns = block.getInsns();
+        int insnSz = insns.size();
+
+        // The exit block has no insns and no successors
+        if (blockIndex == method.getExitBlockIndex()) {
+            return;
+        }
+
+        /*
+         * We may have to treat the last instruction specially: If it
+         * can (but doesn't always) throw, and the exception can be
+         * caught within the same method, then we need to use the
+         * state *before* executing it to be what is merged into
+         * exception targets.
+         */
+        SsaInsn lastInsn = insns.get(insnSz - 1);
+        boolean hasExceptionHandlers
+                = lastInsn.getOriginalRopInsn().getCatches().size() !=0 ;
+        boolean canThrowDuringLastInsn = hasExceptionHandlers
+                && (lastInsn.getResult() != null);
+        int freezeSecondaryStateAt = insnSz - 1;
+        RegisterSpecSet secondaryState = primaryState;
+
+        /*
+         * Iterate over the instructions, adding information for each place
+         * that the active variable set changes.
+         */
+
+        for (int i = 0; i < insnSz; i++) {
+            if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
+                // Until this point, primaryState == secondaryState.
+                primaryState.setImmutable();
+                primaryState = primaryState.mutableCopy();
+            }
+
+            SsaInsn insn = insns.get(i);
+            RegisterSpec result;
+
+            result = insn.getLocalAssignment();
+
+            if (result == null) {
+                // We may be nuking an existing local
+
+                result = insn.getResult();
+
+                if (result != null && primaryState.get(result.getReg()) != null) {
+                    primaryState.remove(primaryState.get(result.getReg()));
+                }
+                continue;
+            }
+
+            result = result.withSimpleType();
+
+            RegisterSpec already = primaryState.get(result);
+            /*
+             * The equals() check ensures we only add new info if
+             * the instruction causes a change to the set of
+             * active variables.
+             */
+            if (!result.equals(already)) {
+                /*
+                 * If this insn represents a local moving from one register
+                 * to another, remove the association between the old register
+                 * and the local.
+                 */
+                RegisterSpec previous
+                        = primaryState.localItemToSpec(result.getLocalItem());
+
+                if (previous != null
+                        && (previous.getReg() != result.getReg())) {
+
+                    primaryState.remove(previous);
+                }
+
+                resultInfo.addAssignment(insn, result);
+                primaryState.put(result);
+            }
+        }
+
+        primaryState.setImmutable();
+
+        /*
+         * Merge this state into the start state for each successor,
+         * and update the work set where required (that is, in cases
+         * where the start state for a block changes).
+         */
+
+        IntList successors = block.getSuccessorList();
+        int succSz = successors.size();
+        int primarySuccessor = block.getPrimarySuccessorIndex();
+
+        for (int i = 0; i < succSz; i++) {
+            int succ = successors.get(i);
+            RegisterSpecSet state = (succ == primarySuccessor) ?
+                primaryState : secondaryState;
+
+            if (resultInfo.mergeStarts(succ, state)) {
+                workSet.set(succ);
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/LocalVariableInfo.java b/dx/src/com/android/dx/ssa/LocalVariableInfo.java
new file mode 100644
index 0000000..8845270
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/LocalVariableInfo.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.util.MutabilityControl;
+import com.android.dx.rop.code.RegisterSpecSet;
+import com.android.dx.rop.code.RegisterSpec;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Container for local variable information for a particular {@link
+ * com.android.dx.ssa.SsaMethod}.
+ * Stolen from {@link com.android.dx.rop.code.LocalVariableInfo}.
+ */
+public class LocalVariableInfo         extends MutabilityControl {
+    /** {@code >= 0;} the register count for the method */
+    private final int regCount;
+
+    /**
+     * {@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;
+
+    /**
+     * {@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;
+
+    /** {@code non-null;} map from instructions to the variable each assigns */
+    private final HashMap<SsaInsn, RegisterSpec> insnAssignments;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param method {@code non-null;} the method being represented by this instance
+     */
+    public LocalVariableInfo(SsaMethod method) {
+        if (method == null) {
+            throw new NullPointerException("method == null");
+        }
+
+        List<SsaBasicBlock> blocks = method.getBlocks();
+
+        this.regCount = method.getRegCount();
+        this.emptySet = new RegisterSpecSet(regCount);
+        this.blockStarts = new RegisterSpecSet[blocks.size()];
+        this.insnAssignments =
+            new HashMap<SsaInsn, RegisterSpec>(/*hint here*/);
+
+        emptySet.setImmutable();
+    }
+
+    /**
+     * Sets the register set associated with the start of the block with
+     * the given index.
+     *
+     * @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();
+
+        if (specs == null) {
+            throw new NullPointerException("specs == null");
+        }
+
+        try {
+            blockStarts[index] = specs;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus index");
+        }
+    }
+
+    /**
+     * Merges the given register set into the set for the block with the
+     * given index. If there was not already an associated set, then this
+     * is the same as calling {@link #setStarts}. Otherwise, this will
+     * merge the two sets and call {@link #setStarts} on the result of the
+     * merge.
+     *
+     * @param 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} if the merge resulted in an actual change
+     * to the associated set (including storing one for the first time) or
+     * {@code false} if there was no change
+     */
+    public boolean mergeStarts(int index, RegisterSpecSet specs) {
+        RegisterSpecSet start = getStarts0(index);
+        boolean changed = false;
+
+        if (start == null) {
+            setStarts(index, specs);
+            return true;
+        }
+
+        RegisterSpecSet newStart = start.mutableCopy();
+        newStart.intersect(specs, true);
+
+        if (start.equals(newStart)) {
+            return false;
+        }
+
+        newStart.setImmutable();
+        setStarts(index, newStart);
+
+        return true;
+    }
+
+    /**
+     * Gets the register set associated with the start of the block
+     * 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 {@code >= 0;} the block index
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet getStarts(int index) {
+        RegisterSpecSet result = getStarts0(index);
+
+        return (result != null) ? result : emptySet;
+    }
+
+    /**
+     * Gets the register set associated with the start of the given
+     * block. This is just convenient shorthand for
+     * {@code getStarts(block.getLabel())}.
+     *
+     * @param block {@code non-null;} the block in question
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet getStarts(SsaBasicBlock block) {
+        return getStarts(block.getIndex());
+    }
+
+    /**
+     * Gets a mutable copy of the register set associated with the
+     * start of the block with the given index. This returns a
+     * newly-allocated empty {@link RegisterSpecSet} of appropriate
+     * max size if there is not yet any set associated with the block.
+     *
+     * @param index {@code >= 0;} the block index
+     * @return {@code non-null;} the associated register set
+     */
+    public RegisterSpecSet mutableCopyOfStarts(int index) {
+        RegisterSpecSet result = getStarts0(index);
+
+        return (result != null) ?
+            result.mutableCopy() : new RegisterSpecSet(regCount);
+    }
+
+    /**
+     * Adds an assignment association for the given instruction and
+     * register spec. This throws an exception if the instruction
+     * doesn't actually perform a named variable assignment.
+     *
+     * <b>Note:</b> Although the instruction contains its own spec for
+     * the result, it still needs to be passed in explicitly to this
+     * method, since the spec that is stored here should always have a
+     * simple type and the one in the instruction can be an arbitrary
+     * {@link com.android.dx.rop.type.TypeBearer} (such as a constant value).
+     *
+     * @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();
+
+        if (insn == null) {
+            throw new NullPointerException("insn == null");
+        }
+
+        if (spec == null) {
+            throw new NullPointerException("spec == null");
+        }
+
+        insnAssignments.put(insn, spec);
+    }
+
+    /**
+     * Gets the named register being assigned by the given instruction, if
+     * previously stored in this instance.
+     *
+     * @param insn {@code non-null;} instruction in question
+     * @return {@code null-ok;} the named register being assigned, if any
+     */
+    public RegisterSpec getAssignment(SsaInsn insn) {
+        return insnAssignments.get(insn);
+    }
+
+    /**
+     * Gets the number of assignments recorded by this instance.
+     *
+     * @return {@code >= 0;} the number of assignments
+     */
+    public int getAssignmentCount() {
+        return insnAssignments.size();
+    }
+
+    public void debugDump() {
+        for (int index = 0 ; index < blockStarts.length; index++) {
+            if (blockStarts[index] == null) {
+                continue;
+            }
+
+            if (blockStarts[index] == emptySet) {
+                System.out.printf("%04x: empty set\n", index);
+            } else {
+                System.out.printf("%04x: %s\n", index, blockStarts[index]);
+            }
+        }
+    }
+
+    /**
+     * Helper method, to get the starts for a index, throwing the
+     * right exception for range problems.
+     *
+     * @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) {
+        try {
+            return blockStarts[index];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("bogus index");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/MoveParamCombiner.java b/dx/src/com/android/dx/ssa/MoveParamCombiner.java
new file mode 100644
index 0000000..41660d2
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/MoveParamCombiner.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.CstInsn;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.cst.CstInteger;
+
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Combine identical move-param insns, which may result from Ropper's
+ * handling of synchronized methods.
+ */
+public class MoveParamCombiner {
+
+    /** method to process */
+    private final SsaMethod ssaMeth;
+
+    /**
+     * Processes a method with this optimization step.
+     *
+     * @param ssaMethod method to process
+     */
+    public static void process(SsaMethod ssaMethod) {
+        new MoveParamCombiner(ssaMethod).run();
+    }
+
+    private MoveParamCombiner(SsaMethod ssaMeth) {
+        this.ssaMeth = ssaMeth;
+    }
+
+    /**
+     * Runs this optimization step.
+     */
+    private void run() {
+        // This will contain the definition specs for each parameter
+        final RegisterSpec[] paramSpecs
+                = new RegisterSpec[ssaMeth.getParamWidth()];
+
+        // Insns to delete when all done
+        final HashSet<SsaInsn> deletedInsns = new HashSet();
+
+        ssaMeth.forEachInsn(new SsaInsn.Visitor() {
+            public void visitMoveInsn (NormalSsaInsn insn) {
+            }
+            public void visitPhiInsn (PhiInsn phi) {
+            }
+            public void visitNonMoveInsn (NormalSsaInsn insn) {
+                if (insn.getOpcode().getOpcode() != RegOps.MOVE_PARAM) {
+                    return;
+                }
+
+                int param = getParamIndex(insn);
+
+                if (paramSpecs[param] == null) {
+                    paramSpecs[param] = insn.getResult();
+                } else {
+                    final RegisterSpec specA = paramSpecs[param];
+                    final RegisterSpec specB = insn.getResult();
+                    LocalItem localA = specA.getLocalItem();
+                    LocalItem localB = specB.getLocalItem();
+                    LocalItem newLocal;
+
+                    /*
+                     * Is there local information to preserve?
+                     */
+
+                    if (localA == null) {
+                        newLocal = localB;
+                    } else if (localB == null) {
+                        newLocal = localA;
+                    } else if (localA.equals(localB)) {
+                        newLocal = localA;
+                    } else {
+                        /*
+                         * Oddly, these two identical move-params have distinct
+                         * debug info. We'll just keep them distinct.
+                         */
+                        return;
+                    }
+
+                    ssaMeth.getDefinitionForRegister(specA.getReg())
+                            .setResultLocal(newLocal);
+
+                    /*
+                     * Map all uses of specB to specA
+                     */
+
+                    RegisterMapper mapper = new RegisterMapper() {
+                        /** @inheritDoc */
+                        public int getNewRegisterCount() {
+                            return ssaMeth.getRegCount();
+                        }
+
+                        /** @inheritDoc */
+                        public RegisterSpec map(RegisterSpec registerSpec) {
+                            if (registerSpec.getReg() == specB.getReg()) {
+                                return specA;
+                            }
+
+                            return registerSpec;
+                        }
+                    };
+
+                    List<SsaInsn> uses
+                            = ssaMeth.getUseListForRegister(specB.getReg());
+
+                    // Use list is modified by mapSourceRegisters
+                    for (int i = uses.size() - 1; i >= 0; i--) {
+                        SsaInsn use = uses.get(i);
+                        use.mapSourceRegisters(mapper);
+                    }
+
+                    deletedInsns.add(insn);
+                }
+
+            }
+        });
+
+        ssaMeth.deleteInsns(deletedInsns);
+    }
+
+    /**
+     * Returns the parameter index associated with a move-param insn. Does
+     * not verify that the insn is a move-param insn.
+     *
+     * @param insn {@code non-null;} a move-param insn
+     * @return {@code >=0;} parameter index
+     */
+    private int getParamIndex(NormalSsaInsn insn) {
+        CstInsn cstInsn = (CstInsn)(insn.getOriginalRopInsn());
+
+        int param = ((CstInteger)cstInsn.getConstant()).getValue();
+        return param;
+    }
+
+}
diff --git a/dx/src/com/android/dx/ssa/NormalSsaInsn.java b/dx/src/com/android/dx/ssa/NormalSsaInsn.java
new file mode 100644
index 0000000..cfef400
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/NormalSsaInsn.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.*;
+
+/**
+ * A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn.
+ */
+public final class NormalSsaInsn extends SsaInsn implements Cloneable {
+    /** {@code non-null;} rop insn that we're wrapping */
+    private Insn insn;
+
+    /**
+     * Creates an instance.
+     *
+     * @param insn Rop insn to wrap
+     * @param block block that contains this insn
+     */
+    NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
+        super(insn.getResult(), block);
+        this.insn = insn;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void mapSourceRegisters(RegisterMapper mapper) {
+        RegisterSpecList oldSources = insn.getSources();
+        RegisterSpecList newSources = mapper.map(oldSources);
+
+        if (newSources != oldSources) {
+            insn = insn.withNewRegisters(getResult(), newSources);
+            getBlock().getParent().onSourcesChanged(this, oldSources);
+        }
+    }
+
+    /**
+     * Changes one of the insn's sources. New source should be of same type
+     * and category.
+     *
+     * @param index {@code >=0;} index of source to change
+     * @param newSpec spec for new source
+     */
+    public final void changeOneSource(int index, RegisterSpec newSpec) {
+        RegisterSpecList origSources = insn.getSources();
+        int sz = origSources.size();
+        RegisterSpecList newSources = new RegisterSpecList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            newSources.set(i, i == index ? newSpec : origSources.get(i));
+        }
+
+        newSources.setImmutable();
+
+        RegisterSpec origSpec = origSources.get(index);
+        if (origSpec.getReg() != newSpec.getReg()) {
+            /*
+             * If the register remains unchanged, we're only changing
+             * the type or local var name so don't update use list
+             */
+            getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
+        }
+
+        insn = insn.withNewRegisters(getResult(), newSources);
+    }
+
+    /**
+     * Changes the source list of the insn. New source list should be the
+     * same size and consist of sources of identical types.
+     *
+     * @param newSources non-null new sources list.
+     */
+    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(getResult(), newSources);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NormalSsaInsn clone() {
+        return (NormalSsaInsn) super.clone();
+    }
+
+    /**
+     * Like rop.Insn.getSources().
+     *
+     * @return {@code null-ok;} sources list
+     */
+    @Override
+    public RegisterSpecList getSources() {
+        return insn.getSources();
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toRopInsn().toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn toRopInsn() {
+        return insn.withNewRegisters(getResult(), insn.getSources());
+    }
+
+    /**
+     * @return the Rop opcode for this insn
+     */
+    @Override
+    public Rop getOpcode() {
+        return insn.getOpcode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Insn getOriginalRopInsn() {
+        return insn;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RegisterSpec getLocalAssignment() {
+        RegisterSpec assignment;
+
+        if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
+            assignment = insn.getSources().get(0);
+        } else {
+            assignment = getResult();
+        }
+
+        if (assignment == null) {
+            return null;
+        }
+
+        LocalItem local = assignment.getLocalItem();
+
+        if (local == null) {
+            return null;
+        }
+
+        return assignment;
+    }
+
+    /**
+     * Upgrades this insn to a version that represents the constant source
+     * literally. If the upgrade is not possible, this does nothing.
+     *
+     * @see Insn#withSourceLiteral
+     */
+    public void upgradeToLiteral() {
+        RegisterSpecList oldSources = insn.getSources();
+
+        insn = insn.withSourceLiteral();
+        getBlock().getParent().onSourcesChanged(this, oldSources);
+    }
+
+    /**
+     * @return true if this is a move (but not a move-operand) instruction
+     */
+    @Override
+    public boolean isNormalMoveInsn() {
+        return insn.getOpcode().getOpcode() == RegOps.MOVE;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isMoveException() {
+        return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean canThrow() {
+        return insn.canThrow();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(Visitor v) {
+        if (isNormalMoveInsn()) {
+            v.visitMoveInsn(this);
+        } else {
+            v.visitNonMoveInsn(this);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public  boolean isPhiOrMove() {
+        return isNormalMoveInsn();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * TODO: Increase the scope of this.
+     */
+    @Override
+    public boolean hasSideEffect() {
+        Rop opcode = getOpcode();
+
+        if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
+            return true;
+        }
+
+        boolean hasLocalSideEffect
+            = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
+
+        switch (opcode.getOpcode()) {
+            case RegOps.MOVE_RESULT:
+            case RegOps.MOVE:
+            case RegOps.CONST:
+                return hasLocalSideEffect;
+            default:
+                return true;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/Optimizer.java b/dx/src/com/android/dx/ssa/Optimizer.java
new file mode 100644
index 0000000..42ae166
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/Optimizer.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.TranslationAdvice;
+import com.android.dx.ssa.back.LivenessAnalyzer;
+import com.android.dx.ssa.back.SsaToRop;
+
+import java.util.EnumSet;
+
+/**
+ * Runs a method through the SSA form conversion, any optimization algorithms,
+ * and returns it to rop form.
+ */
+public class Optimizer {
+    private static boolean preserveLocals = true;
+
+    private static TranslationAdvice advice;
+
+    /** optional optimizer steps */
+    public enum OptionalStep {
+        MOVE_PARAM_COMBINER, SCCP, LITERAL_UPGRADE, CONST_COLLECTOR,
+            ESCAPE_ANALYSIS
+    }
+
+    /**
+     * @return true if local variable information should be preserved, even
+     * at code size/register size cost
+     */
+    public static boolean getPreserveLocals() {
+        return preserveLocals;
+    }
+
+    /**
+     * @return {@code non-null;} translation advice
+     */
+    public static TranslationAdvice getAdvice() {
+        return advice;
+    }
+
+    /**
+     * Runs optimization algorthims over this method, and returns a new
+     * instance of RopMethod with the changes.
+     *
+     * @param rmeth method to process
+     * @param paramWidth the total width, in register-units, of this method's
+     * parameters
+     * @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 {@code non-null;} translation advice
+     * @return optimized method
+     */
+    public static RopMethod optimize(RopMethod rmeth, int paramWidth,
+            boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice) {
+
+        return optimize(rmeth, paramWidth, isStatic, inPreserveLocals, inAdvice,
+                EnumSet.allOf(OptionalStep.class));
+    }
+
+    /**
+     * Runs optimization algorthims over this method, and returns a new
+     * instance of RopMethod with the changes.
+     *
+     * @param rmeth method to process
+     * @param paramWidth the total width, in register-units, of this method's
+     * parameters
+     * @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 {@code non-null;} translation advice
+     * @param steps set of optional optimization steps to run
+     * @return optimized method
+     */
+    public static RopMethod optimize(RopMethod rmeth, int paramWidth,
+            boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) {
+        SsaMethod ssaMeth = null;
+
+        preserveLocals = inPreserveLocals;
+        advice = inAdvice;
+
+        ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+        runSsaFormSteps(ssaMeth, steps);
+
+        RopMethod resultMeth = SsaToRop.convertToRopMethod(ssaMeth, false);
+
+        if (resultMeth.getBlocks().getRegCount()
+                > advice.getMaxOptimalRegisterCount()) {
+            // Try to see if we can squeeze it under the register count bar
+            resultMeth = optimizeMinimizeRegisters(rmeth, paramWidth, isStatic,
+                    steps);
+        }
+        return resultMeth;
+    }
+
+    /**
+     * Runs the optimizer with a strategy to minimize the number of rop-form
+     * registers used by the end result. Dex bytecode does not have instruction
+     * forms that take register numbers larger than 15 for all instructions.
+     * If we've produced a method that uses more than 16 registers, try again
+     * with a different strategy to see if we can get under the bar. The end
+     * result will be much more efficient.
+     *
+     * @param rmeth method to process
+     * @param paramWidth the total width, in register-units, of this method's
+     * parameters
+     * @param isStatic true if this method has no 'this' pointer argument.
+     * @param steps set of optional optimization steps to run
+     * @return optimized method
+     */
+    private static RopMethod optimizeMinimizeRegisters(RopMethod rmeth,
+            int paramWidth, boolean isStatic,
+            EnumSet<OptionalStep> steps) {
+        SsaMethod ssaMeth;
+        RopMethod resultMeth;
+
+        ssaMeth = SsaConverter.convertToSsaMethod(
+                rmeth, paramWidth, isStatic);
+
+        EnumSet<OptionalStep> newSteps = steps.clone();
+
+        /*
+         * CONST_COLLECTOR trades insns for registers, which is not an
+         * appropriate strategy here.
+         */
+        newSteps.remove(OptionalStep.CONST_COLLECTOR);
+
+        runSsaFormSteps(ssaMeth, newSteps);
+
+        resultMeth = SsaToRop.convertToRopMethod(ssaMeth, true);
+        return resultMeth;
+    }
+
+    private static void runSsaFormSteps(SsaMethod ssaMeth,
+            EnumSet<OptionalStep> steps) {
+        boolean needsDeadCodeRemover = true;
+
+        if (steps.contains(OptionalStep.MOVE_PARAM_COMBINER)) {
+            MoveParamCombiner.process(ssaMeth);
+        }
+
+        if (steps.contains(OptionalStep.SCCP)) {
+            SCCP.process(ssaMeth);
+            DeadCodeRemover.process(ssaMeth);
+            needsDeadCodeRemover = false;
+        }
+
+        if (steps.contains(OptionalStep.LITERAL_UPGRADE)) {
+            LiteralOpUpgrader.process(ssaMeth);
+            DeadCodeRemover.process(ssaMeth);
+            needsDeadCodeRemover = false;
+        }
+
+        /*
+         * ESCAPE_ANALYSIS impacts debuggability, so left off by default
+         */
+        steps.remove(OptionalStep.ESCAPE_ANALYSIS);
+        if (steps.contains(OptionalStep.ESCAPE_ANALYSIS)) {
+            EscapeAnalysis.process(ssaMeth);
+            DeadCodeRemover.process(ssaMeth);
+            needsDeadCodeRemover = false;
+        }
+
+        if (steps.contains(OptionalStep.CONST_COLLECTOR)) {
+            ConstCollector.process(ssaMeth);
+            DeadCodeRemover.process(ssaMeth);
+            needsDeadCodeRemover = false;
+        }
+
+        // dead code remover must be run before phi type resolver
+        if (needsDeadCodeRemover) {
+            DeadCodeRemover.process(ssaMeth);
+        }
+
+        PhiTypeResolver.process(ssaMeth);
+    }
+
+    public static SsaMethod debugEdgeSplit(RopMethod rmeth, int paramWidth,
+            boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice) {
+
+        preserveLocals = inPreserveLocals;
+        advice = inAdvice;
+
+        return SsaConverter.testEdgeSplit(rmeth, paramWidth, isStatic);
+    }
+
+    public static SsaMethod debugPhiPlacement(RopMethod rmeth, int paramWidth,
+            boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice) {
+
+        preserveLocals = inPreserveLocals;
+        advice = inAdvice;
+
+        return SsaConverter.testPhiPlacement(rmeth, paramWidth, isStatic);
+    }
+
+    public static SsaMethod debugRenaming(RopMethod rmeth, int paramWidth,
+            boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice) {
+
+        preserveLocals = inPreserveLocals;
+        advice = inAdvice;
+
+        return SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+    }
+
+    public static SsaMethod debugDeadCodeRemover(RopMethod rmeth,
+            int paramWidth, boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice) {
+
+        SsaMethod ssaMeth;
+
+        preserveLocals = inPreserveLocals;
+        advice = inAdvice;
+
+        ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+        DeadCodeRemover.process(ssaMeth);
+
+        return ssaMeth;
+    }
+
+    public static SsaMethod debugNoRegisterAllocation(RopMethod rmeth,
+            int paramWidth, boolean isStatic, boolean inPreserveLocals,
+            TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) {
+
+        SsaMethod ssaMeth;
+
+        preserveLocals = inPreserveLocals;
+        advice = inAdvice;
+
+        ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
+
+        runSsaFormSteps(ssaMeth, steps);
+
+        LivenessAnalyzer.constructInterferenceGraph(ssaMeth);
+
+        return ssaMeth;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/PhiInsn.java b/dx/src/com/android/dx/ssa/PhiInsn.java
new file mode 100644
index 0000000..bc9c4b0
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/PhiInsn.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.*;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.util.Hex;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Phi instruction (magical post-control-flow-merge) instruction
+ * in SSA form. Will be converted to moves in predecessor blocks before
+ * 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;
+
+    /**
+     * {@code non-null;} operands of the instruction; built up by
+     * {@link #addPhiOperand}
+     */
+    private final ArrayList<Operand> operands = new ArrayList<Operand>();
+
+    /** {@code null-ok;} source registers; constructed lazily */
+    private RegisterSpecList sources;
+
+    /**
+     * Constructs a new phi insn with no operands.
+     *
+     * @param resultReg the result reg for this phi insn
+     * @param block block containing this insn.
+     */
+    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.
+     */
+    public PhiInsn(final int resultReg, final SsaBasicBlock block) {
+        /*
+         * The result type here is bogus: The type depends on the
+         * operand and will be derived later.
+         */
+        super(RegisterSpec.make(resultReg, Type.VOID), block);
+        ropResultReg = resultReg;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    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.
+     * This is used during phi-type resolution.<p>
+     *
+     * Note that local association of operands are preserved in this step.
+     *
+     * @param ssaMeth method that contains this insn
+     */
+    public void updateSourcesToDefinitions(SsaMethod ssaMeth) {
+        for (Operand o : operands) {
+            RegisterSpec def
+                = ssaMeth.getDefinitionForRegister(
+                    o.regSpec.getReg()).getResult();
+
+            o.regSpec = o.regSpec.withType(def.getType());
+        }
+
+        sources = null;
+    }
+
+    /**
+     * Changes the result type. Used during phi type resolution
+     *
+     * @param type {@code non-null;} new TypeBearer
+     * @param local {@code null-ok;} new local info, if available
+     */
+    public void changeResultType(TypeBearer type, LocalItem local) {
+        setResult(RegisterSpec.makeLocalOptional(
+                          getResult().getReg(), type, local));
+    }
+
+    /**
+     * Gets the original rop-form result reg. This is useful during renaming.
+     *
+     * @return the original rop-form result reg
+     */
+    public int getRopResultReg() {
+        return ropResultReg;
+    }
+
+    /**
+     * 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
+     */
+    public void addPhiOperand(RegisterSpec registerSpec,
+            SsaBasicBlock predBlock) {
+        operands.add(new Operand(registerSpec, predBlock.getIndex(),
+                predBlock.getRopLabel()));
+
+        // Un-cache sources, in case someone has already called getSources().
+        sources = null;
+    }
+
+    /**
+     * Removes all operand uses of a register from this phi instruction.
+     *
+     * @param registerSpec register spec, including type and reg of operand
+     */
+    public void removePhiRegister(RegisterSpec registerSpec) {
+        ArrayList<Operand> operandsToRemove = new ArrayList<Operand>();
+        for (Operand o : operands) {
+            if (o.regSpec.getReg() == registerSpec.getReg()) {
+                operandsToRemove.add(o);
+            }
+        }
+
+        operands.removeAll(operandsToRemove);
+
+        // 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
+     */
+    public int predBlockIndexForSourcesIndex(int sourcesIndex) {
+        return operands.get(sourcesIndex).blockIndex;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Always returns null for {@code PhiInsn}s.
+     */
+    @Override
+    public Rop getOpcode() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Always returns null for {@code PhiInsn}s.
+     */
+    @Override
+    public Insn getOriginalRopInsn() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Always returns false for {@code PhiInsn}s.
+     */
+    @Override
+    public boolean canThrow() {
+        return false;
+    }
+
+    /**
+     * Gets sources. Constructed lazily from phi operand data structures and
+     * then cached.
+     *
+     * @return {@code non-null;} sources list
+     */
+    @Override
+    public RegisterSpecList getSources() {
+        if (sources != null) {
+            return sources;
+        }
+
+        if (operands.size() == 0) {
+            // How'd this happen? A phi insn with no operand?
+            return RegisterSpecList.EMPTY;
+        }
+
+        int szSources = operands.size();
+        sources = new RegisterSpecList(szSources);
+
+        for (int i = 0; i < szSources; i++) {
+            Operand o = operands.get(i);
+
+            sources.set(i, o.regSpec);
+        }
+
+        sources.setImmutable();
+        return sources;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isRegASource(int reg) {
+        /*
+         * Avoid creating a sources list in case it has not already been
+         * created.
+         */
+
+        for (Operand o : operands) {
+            if (o.regSpec.getReg() == reg) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @return true if all operands use the same register
+     */
+    public boolean areAllOperandsEqual() {
+        if (operands.size() == 0 ) {
+            // This should never happen.
+            return true;
+        }
+
+        int firstReg = operands.get(0).regSpec.getReg();
+        for (Operand o : operands) {
+            if (firstReg != o.regSpec.getReg()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void mapSourceRegisters(RegisterMapper mapper) {
+        for (Operand o : operands) {
+            RegisterSpec old = o.regSpec;
+            o.regSpec = mapper.map(old);
+            if (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.
+     *
+     * @return always throws exception
+     */
+    @Override
+    public Insn toRopInsn() {
+        throw new IllegalArgumentException(
+                "Cannot convert phi insns to rop form");
+    }
+
+    /**
+     * Returns the list of predecessor blocks associated with all operands
+     * 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
+     */
+    public List<SsaBasicBlock> predBlocksForReg(int reg, SsaMethod ssaMeth) {
+        ArrayList<SsaBasicBlock> ret = new ArrayList<SsaBasicBlock>();
+
+        for (Operand o : operands) {
+            if (o.regSpec.getReg() == reg) {
+                ret.add(ssaMeth.getBlocks().get(o.blockIndex));
+            }
+        }
+
+        return ret;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isPhiOrMove() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean hasSideEffect() {
+        return Optimizer.getPreserveLocals() && getLocalAssignment() != null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void accept(SsaInsn.Visitor v) {
+        v.visitPhiInsn(this);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toHumanWithInline(null);
+    }
+
+    /**
+     * 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(": phi");
+
+        if (extra != null) {
+            sb.append("(");
+            sb.append(extra);
+            sb.append(")");
+        }
+
+        RegisterSpec result = getResult();
+
+        if (result == null) {
+            sb.append(" .");
+        } else {
+            sb.append(" ");
+            sb.append(result.toHuman());
+        }
+
+        sb.append(" <-");
+
+        int sz = getSources().size();
+        if (sz == 0) {
+            sb.append(" .");
+        } else {
+            for (int i = 0; i < sz; i++) {
+                sb.append(" ");
+                sb.append(sources.get(i).toHuman()
+                        + "[b="
+                        + Hex.u2(operands.get(i).ropLabel)  + "]");
+            }
+        }
+
+        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/PhiTypeResolver.java b/dx/src/com/android/dx/ssa/PhiTypeResolver.java
new file mode 100644
index 0000000..4b8b4e3
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/PhiTypeResolver.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.cf.code.Merger;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.type.Type;
+import com.android.dx.rop.type.TypeBearer;
+
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Resolves the result types of phi instructions. When phi instructions
+ * are inserted, their result types are set to BT_VOID (which is a nonsensical
+ * type for a register) but must be resolve to a real type before converting
+ * out of SSA form.<p>
+ *
+ * The resolve is done as an iterative merge of each phi's operand types.
+ * Phi operands may be themselves be the result of unresolved phis,
+ * and the algorithm tries to find the most-fit type (for example, if every
+ * operand is the same constant value or the same local variable info, we want
+ * that to be reflected).<p>
+ *
+ * This algorithm assumes a dead-code remover has already removed all
+ * circular-only phis that may have been inserted.
+ */
+public class PhiTypeResolver {
+
+    SsaMethod ssaMeth;
+    /** indexed by register; all registers still defined by unresolved phis */
+    private final BitSet worklist;
+
+    /**
+     * Resolves all phi types in the method
+     * @param ssaMeth method to process
+     */
+    public static void process (SsaMethod ssaMeth) {
+        new PhiTypeResolver(ssaMeth).run();
+    }
+
+    private PhiTypeResolver(SsaMethod ssaMeth) {
+        this.ssaMeth = ssaMeth;
+        worklist = new BitSet(ssaMeth.getRegCount());
+    }
+
+    /**
+     * Runs the phi-type resolver.
+     */
+    private void run() {
+
+        int regCount = ssaMeth.getRegCount();
+
+        for (int reg = 0; reg < regCount; reg++) {
+            SsaInsn definsn = ssaMeth.getDefinitionForRegister(reg);
+
+            if (definsn != null
+                    && (definsn.getResult().getBasicType() == Type.BT_VOID)) {
+                worklist.set(reg);
+            }
+        }
+
+        int reg;
+        while ( 0 <= (reg = worklist.nextSetBit(0))) {
+            worklist.clear(reg);
+
+            /*
+             * definitions on the worklist have a type of BT_VOID, which
+             * must have originated from a PhiInsn.
+             */
+            PhiInsn definsn = (PhiInsn)ssaMeth.getDefinitionForRegister(reg);
+
+            if (resolveResultType(definsn)) {
+                /*
+                 * If the result type has changed, re-resolve all phis
+                 * that use this.
+                 */
+
+                List<SsaInsn> useList = ssaMeth.getUseListForRegister(reg);
+
+                int sz = useList.size();
+                for (int i = 0; i < sz; i++ ) {
+                    SsaInsn useInsn = useList.get(i);
+                    RegisterSpec resultReg = useInsn.getResult();
+                    if (resultReg != null && useInsn instanceof PhiInsn) {
+                        worklist.set(resultReg.getReg());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns true if a and b are equal, whether
+     * or not either of them are null.
+     * @param a
+     * @param b
+     * @return true if equal
+     */
+    private static boolean equalsHandlesNulls(LocalItem a, LocalItem b) {
+        return (a == b) || ((a != null) && a.equals(b));
+    }
+
+    /**
+     * Resolves the result of a phi insn based on its operands. The "void"
+     * type, which is a nonsensical type for a register, is used for
+     * registers defined by as-of-yet-unresolved phi operations.
+     *
+     * @return true if the result type changed, false if no change
+     */
+    boolean resolveResultType(PhiInsn insn) {
+        insn.updateSourcesToDefinitions(ssaMeth);
+
+        RegisterSpecList sources = insn.getSources();
+
+        // Start by finding the first non-void operand
+        RegisterSpec first = null;
+        int firstIndex = -1;
+
+        int szSources = sources.size();
+        for (int i = 0 ; i <szSources ; i++) {
+            RegisterSpec rs = sources.get(i);
+
+            if (rs.getBasicType() != Type.BT_VOID) {
+                first = rs;
+                firstIndex = i;
+            }
+        }
+
+        if (first == null) {
+            // All operands are void -- we're not ready to resolve yet
+            return false;
+        }
+
+        LocalItem firstLocal = first.getLocalItem();
+        TypeBearer mergedType = first.getType();
+        boolean sameLocals = true;
+        for (int i = 0 ; i < szSources ; i++) {
+            if (i == firstIndex) {
+                continue;
+            }
+
+            RegisterSpec rs = sources.get(i);
+
+            // Just skip void (unresolved phi results) for now
+            if (rs.getBasicType() == Type.BT_VOID){
+                continue;
+            }
+
+            sameLocals = sameLocals
+                    && equalsHandlesNulls(firstLocal, rs.getLocalItem());
+
+            mergedType = Merger.mergeType(mergedType, rs.getType());
+        }
+
+        TypeBearer newResultType;
+
+        if (mergedType != null) {
+            newResultType = mergedType;
+        } else {
+            StringBuilder sb = new StringBuilder();
+
+            for (int i = 0; i < szSources; i++) {
+                sb.append(sources.get(i).toString());
+                sb.append(' ');
+            }
+
+            throw new RuntimeException ("Couldn't map types in phi insn:" + sb);
+        }
+
+        LocalItem newLocal = sameLocals ? firstLocal : null;
+
+        RegisterSpec result = insn.getResult();
+
+        if ((result.getTypeBearer() == newResultType)
+                && equalsHandlesNulls(newLocal, result.getLocalItem())) {
+            return false;
+        }
+
+        insn.changeResultType(newResultType, newLocal);
+
+        return true;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/RegisterMapper.java b/dx/src/com/android/dx/ssa/RegisterMapper.java
new file mode 100644
index 0000000..bef941f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/RegisterMapper.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+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.
+ */
+public abstract class RegisterMapper {
+    /**
+     * Gets the count of registers (really, the total register width, since
+     * category width is counted) in the new namespace.
+     * @return >= 0 width of new namespace.
+     */
+    public abstract int getNewRegisterCount();
+
+    /**
+     * @param registerSpec old register
+     * @return register in new space
+     */
+    public abstract RegisterSpec map(RegisterSpec registerSpec);
+
+    /**
+     *
+     * @param sources old register list
+     * @return new mapped register list, or old if nothing has changed.
+     */
+    public final RegisterSpecList map(RegisterSpecList sources) {
+        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;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/SCCP.java b/dx/src/com/android/dx/ssa/SCCP.java
new file mode 100644
index 0000000..1c869e1
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SCCP.java
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.CstInsn;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.rop.cst.TypedConstant;
+import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.rop.type.Type;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+/**
+ * A small variant of Wegman and Zadeck's Sparse Conditional Constant
+ * Propagation algorithm.
+ */
+public class SCCP {
+    /** Lattice values  */
+    private static final int TOP = 0;
+    private static final int CONSTANT = 1;
+    private static final int VARYING = 2;
+    /** method we're processing */
+    private SsaMethod ssaMeth;
+    /** ssaMeth.getRegCount() */
+    private int regCount;
+    /** Lattice values for each SSA register */
+    private int[] latticeValues;
+    /** For those registers that are constant, this is the constant value */
+    private Constant[] latticeConstants;
+    /** Worklist of basic blocks to be processed */
+    private ArrayList<SsaBasicBlock> cfgWorklist;
+    /** Worklist of executed basic blocks with phis to be processed */
+    private ArrayList<SsaBasicBlock> cfgPhiWorklist;
+    /** Bitset containing bits for each block that has been found executable */
+    private BitSet executableBlocks;
+    /** Worklist for SSA edges.  This is a list of registers to process */
+    private ArrayList<SsaInsn> ssaWorklist;
+    /**
+     * Worklist for SSA edges that represent varying values.  It makes the
+     * algorithm much faster if you move all values to VARYING as fast as
+     * possible.
+     */
+    private ArrayList<SsaInsn> varyingWorklist;
+    /** Worklist of potential branches to convert to gotos */
+    private ArrayList<SsaInsn> branchWorklist;
+
+    private SCCP(SsaMethod ssaMeth) {
+        this.ssaMeth = ssaMeth;
+        this.regCount = ssaMeth.getRegCount();
+        this.latticeValues = new int[this.regCount];
+        this.latticeConstants = new Constant[this.regCount];
+        this.cfgWorklist = new ArrayList<SsaBasicBlock>();
+        this.cfgPhiWorklist = new ArrayList<SsaBasicBlock>();
+        this.executableBlocks = new BitSet(ssaMeth.getBlocks().size());
+        this.ssaWorklist = new ArrayList<SsaInsn>();
+        this.varyingWorklist = new ArrayList<SsaInsn>();
+        this.branchWorklist = new ArrayList<SsaInsn>();
+        for (int i = 0; i < this.regCount; i++) {
+            latticeValues[i] = TOP;
+            latticeConstants[i] = null;
+        }
+    }
+
+    /**
+     * Performs sparse conditional constant propagation on a method.
+     * @param ssaMethod Method to process
+     */
+    public static void process (SsaMethod ssaMethod) {
+        new SCCP(ssaMethod).run();
+    }
+
+    /**
+     * Adds a SSA basic block to the CFG worklist if it's unexecuted, or
+     * to the CFG phi worklist if it's already executed.
+     * @param ssaBlock Block to add
+     */
+    private void addBlockToWorklist(SsaBasicBlock ssaBlock) {
+        if (!executableBlocks.get(ssaBlock.getIndex())) {
+            cfgWorklist.add(ssaBlock);
+            executableBlocks.set(ssaBlock.getIndex());
+        } else {
+            cfgPhiWorklist.add(ssaBlock);
+        }
+    }
+
+    /**
+     * Adds an SSA register's uses to the SSA worklist.
+     * @param reg SSA register
+     * @param latticeValue new lattice value for @param reg.
+     */
+    private void addUsersToWorklist(int reg, int latticeValue) {
+        if (latticeValue == VARYING) {
+            for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
+                varyingWorklist.add(insn);
+            }
+        } else {
+            for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
+                ssaWorklist.add(insn);
+            }
+        }
+    }
+
+    /**
+     * Sets a lattice value for a register to value.
+     * @param reg SSA register
+     * @param value Lattice value
+     * @param cst Constant value (may be null)
+     * @return true if the lattice value changed.
+     */
+    private boolean setLatticeValueTo(int reg, int value, Constant cst) {
+        if (value != CONSTANT) {
+            if (latticeValues[reg] != value) {
+                latticeValues[reg] = value;
+                return true;
+            }
+            return false;
+        } else {
+            if (latticeValues[reg] != value
+                    || !latticeConstants[reg].equals(cst)) {
+                latticeValues[reg] = value;
+                latticeConstants[reg] = cst;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Simulates a PHI node and set the lattice for the result
+     * to the appropriate value.
+     * Meet values:
+     * TOP x anything = TOP
+     * VARYING x anything = VARYING
+     * CONSTANT x CONSTANT = CONSTANT if equal constants, VARYING otherwise
+     * @param insn PHI to simulate.
+     */
+    private void simulatePhi(PhiInsn insn) {
+        int phiResultReg = insn.getResult().getReg();
+
+        if (latticeValues[phiResultReg] == VARYING) {
+            return;
+        }
+
+        RegisterSpecList sources = insn.getSources();
+        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();
+            int sourceRegValue = latticeValues[sourceReg];
+
+            if (!executableBlocks.get(predBlockIndex)) {
+                continue;
+            }
+
+            if (sourceRegValue == CONSTANT) {
+                if (phiConstant == null) {
+                    phiConstant = latticeConstants[sourceReg];
+                    phiResultValue = CONSTANT;
+                 } else if (!latticeConstants[sourceReg].equals(phiConstant)){
+                    phiResultValue = VARYING;
+                    break;
+                }
+            } else {
+                phiResultValue = sourceRegValue;
+                break;
+            }
+        }
+        if (setLatticeValueTo(phiResultReg, phiResultValue, phiConstant)) {
+            addUsersToWorklist(phiResultReg, phiResultValue);
+        }
+    }
+
+    /**
+     * Simulate a block and note the results in the lattice.
+     * @param block Block to visit
+     */
+    private void simulateBlock(SsaBasicBlock block) {
+        for (SsaInsn insn : block.getInsns()) {
+            if (insn instanceof PhiInsn) {
+                simulatePhi((PhiInsn) insn);
+            } else {
+                simulateStmt(insn);
+            }
+        }
+    }
+
+    /**
+     * Simulate the phis in a block and note the results in the lattice.
+     * @param block Block to visit
+     */
+    private void simulatePhiBlock(SsaBasicBlock block) {
+        for (SsaInsn insn : block.getInsns()) {
+            if (insn instanceof PhiInsn) {
+                simulatePhi((PhiInsn) insn);
+            } else {
+                return;
+            }
+        }
+    }
+
+    private static String latticeValName(int latticeVal) {
+        switch (latticeVal) {
+            case TOP: return "TOP";
+            case CONSTANT: return "CONSTANT";
+            case VARYING: return "VARYING";
+            default: return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Simulates branch insns, if possible. Adds reachable successor blocks
+     * to the CFG worklists.
+     * @param insn branch to simulate
+     */
+    private void simulateBranch(SsaInsn insn) {
+        Rop opcode = insn.getOpcode();
+        RegisterSpecList sources = insn.getSources();
+
+        boolean constantBranch = false;
+        boolean constantSuccessor = false;
+
+        // Check if the insn is a branch with a constant condition
+        if (opcode.getBranchingness() == Rop.BRANCH_IF) {
+            Constant cA = null;
+            Constant cB = null;
+
+            RegisterSpec specA = sources.get(0);
+            int regA = specA.getReg();
+            if (!ssaMeth.isRegALocal(specA) &&
+                    latticeValues[regA] == CONSTANT) {
+                cA = latticeConstants[regA];
+            }
+
+            if (sources.size() == 2) {
+                RegisterSpec specB = sources.get(1);
+                int regB = specB.getReg();
+                if (!ssaMeth.isRegALocal(specB) &&
+                        latticeValues[regB] == CONSTANT) {
+                    cB = latticeConstants[regB];
+                }
+            }
+
+            // Calculate the result of the condition
+            if (cA != null && sources.size() == 1) {
+                switch (((TypedConstant) cA).getBasicType()) {
+                    case Type.BT_INT:
+                        constantBranch = true;
+                        int vA = ((CstInteger) cA).getValue();
+                        switch (opcode.getOpcode()) {
+                            case RegOps.IF_EQ:
+                                constantSuccessor = (vA == 0);
+                                break;
+                            case RegOps.IF_NE:
+                                constantSuccessor = (vA != 0);
+                                break;
+                            case RegOps.IF_LT:
+                                constantSuccessor = (vA < 0);
+                                break;
+                            case RegOps.IF_GE:
+                                constantSuccessor = (vA >= 0);
+                                break;
+                            case RegOps.IF_LE:
+                                constantSuccessor = (vA <= 0);
+                                break;
+                            case RegOps.IF_GT:
+                                constantSuccessor = (vA > 0);
+                                break;
+                            default:
+                                throw new RuntimeException("Unexpected op");
+                        }
+                        break;
+                    default:
+                        // not yet supported
+                }
+            } else if (cA != null && cB != null) {
+                switch (((TypedConstant) cA).getBasicType()) {
+                    case Type.BT_INT:
+                        constantBranch = true;
+                        int vA = ((CstInteger) cA).getValue();
+                        int vB = ((CstInteger) cB).getValue();
+                        switch (opcode.getOpcode()) {
+                            case RegOps.IF_EQ:
+                                constantSuccessor = (vA == vB);
+                                break;
+                            case RegOps.IF_NE:
+                                constantSuccessor = (vA != vB);
+                                break;
+                            case RegOps.IF_LT:
+                                constantSuccessor = (vA < vB);
+                                break;
+                            case RegOps.IF_GE:
+                                constantSuccessor = (vA >= vB);
+                                break;
+                            case RegOps.IF_LE:
+                                constantSuccessor = (vA <= vB);
+                                break;
+                            case RegOps.IF_GT:
+                                constantSuccessor = (vA > vB);
+                                break;
+                            default:
+                                throw new RuntimeException("Unexpected op");
+                        }
+                        break;
+                    default:
+                        // not yet supported
+                }
+            }
+        }
+
+        /*
+         * If condition is constant, add only the target block to the
+         * worklist. Otherwise, add all successors to the worklist.
+         */
+        SsaBasicBlock block = insn.getBlock();
+
+        if (constantBranch) {
+            int successorBlock;
+            if (constantSuccessor) {
+                successorBlock = block.getSuccessorList().get(1);
+            } else {
+                successorBlock = block.getSuccessorList().get(0);
+            }
+            addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
+            branchWorklist.add(insn);
+        } else {
+            for (int i = 0; i < block.getSuccessorList().size(); i++) {
+                int successorBlock = block.getSuccessorList().get(i);
+                addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
+            }
+        }
+    }
+
+    /**
+     * Simulates math insns, if possible.
+     *
+     * @param insn non-null insn to simulate
+     * @param resultType basic type of the result
+     * @return constant result or null if not simulatable.
+     */
+    private Constant simulateMath(SsaInsn insn, int resultType) {
+        Insn ropInsn = insn.getOriginalRopInsn();
+        int opcode = insn.getOpcode().getOpcode();
+        RegisterSpecList sources = insn.getSources();
+        int regA = sources.get(0).getReg();
+        Constant cA;
+        Constant cB;
+
+        if (latticeValues[regA] != CONSTANT) {
+            cA = null;
+        } else {
+            cA = latticeConstants[regA];
+        }
+
+        if (sources.size() == 1) {
+            CstInsn cstInsn = (CstInsn) ropInsn;
+            cB = cstInsn.getConstant();
+        } else { /* sources.size() == 2 */
+            int regB = sources.get(1).getReg();
+            if (latticeValues[regB] != CONSTANT) {
+                cB = null;
+            } else {
+                cB = latticeConstants[regB];
+            }
+        }
+
+        if (cA == null || cB == null) {
+            //TODO handle a constant of 0 with MUL or AND
+            return null;
+        }
+
+        switch (resultType) {
+            case Type.BT_INT:
+                int vR;
+                boolean skip=false;
+
+                int vA = ((CstInteger) cA).getValue();
+                int vB = ((CstInteger) cB).getValue();
+
+                switch (opcode) {
+                    case RegOps.ADD:
+                        vR = vA + vB;
+                        break;
+                    case RegOps.SUB:
+                        // 1 source for reverse sub, 2 sources for regular sub
+                        if (sources.size() == 1) {
+                            vR = vB - vA;
+                        } else {
+                            vR = vA - vB;
+                        }
+                        break;
+                    case RegOps.MUL:
+                        vR = vA * vB;
+                        break;
+                    case RegOps.DIV:
+                        if (vB == 0) {
+                            skip = true;
+                            vR = 0; // just to hide a warning
+                        } else {
+                            vR = vA / vB;
+                        }
+                        break;
+                    case RegOps.AND:
+                        vR = vA & vB;
+                        break;
+                    case RegOps.OR:
+                        vR = vA | vB;
+                        break;
+                    case RegOps.XOR:
+                        vR = vA ^ vB;
+                        break;
+                    case RegOps.SHL:
+                        vR = vA << vB;
+                        break;
+                    case RegOps.SHR:
+                        vR = vA >> vB;
+                        break;
+                    case RegOps.USHR:
+                        vR = vA >>> vB;
+                        break;
+                    case RegOps.REM:
+                        if (vB == 0) {
+                            skip = true;
+                            vR = 0; // just to hide a warning
+                        } else {
+                            vR = vA % vB;
+                        }
+                        break;
+                    default:
+                        throw new RuntimeException("Unexpected op");
+                }
+
+                return skip ? null : CstInteger.make(vR);
+
+            default:
+                // not yet supported
+                return null;
+        }
+    }
+
+    /**
+     * Simulates a statement and set the result lattice value.
+     * @param insn instruction to simulate
+     */
+    private void simulateStmt(SsaInsn insn) {
+        Insn ropInsn = insn.getOriginalRopInsn();
+        if (ropInsn.getOpcode().getBranchingness() != Rop.BRANCH_NONE
+                || ropInsn.getOpcode().isCallLike()) {
+            simulateBranch(insn);
+        }
+
+        int opcode = insn.getOpcode().getOpcode();
+        RegisterSpec result = insn.getResult();
+
+        if (result == null) {
+            // Find move-result-pseudo result for int div and int rem
+            if (opcode == RegOps.DIV || opcode == RegOps.REM) {
+                SsaBasicBlock succ = insn.getBlock().getPrimarySuccessor();
+                result = succ.getInsns().get(0).getResult();
+            } else {
+                return;
+            }
+        }
+
+        int resultReg = result.getReg();
+        int resultValue = VARYING;
+        Constant resultConstant = null;
+
+        switch (opcode) {
+            case RegOps.CONST: {
+                CstInsn cstInsn = (CstInsn)ropInsn;
+                resultValue = CONSTANT;
+                resultConstant = cstInsn.getConstant();
+                break;
+            }
+            case RegOps.MOVE: {
+                if (insn.getSources().size() == 1) {
+                    int sourceReg = insn.getSources().get(0).getReg();
+                    resultValue = latticeValues[sourceReg];
+                    resultConstant = latticeConstants[sourceReg];
+                }
+                break;
+            }
+            case RegOps.ADD:
+            case RegOps.SUB:
+            case RegOps.MUL:
+            case RegOps.DIV:
+            case RegOps.AND:
+            case RegOps.OR:
+            case RegOps.XOR:
+            case RegOps.SHL:
+            case RegOps.SHR:
+            case RegOps.USHR:
+            case RegOps.REM: {
+                resultConstant = simulateMath(insn, result.getBasicType());
+                if (resultConstant != null) {
+                    resultValue = CONSTANT;
+                }
+                break;
+            }
+            case RegOps.MOVE_RESULT_PSEUDO: {
+                if (latticeValues[resultReg] == CONSTANT) {
+                    resultValue = latticeValues[resultReg];
+                    resultConstant = latticeConstants[resultReg];
+                }
+                break;
+            }
+            // TODO: Handle non-int arithmetic.
+            // TODO: Eliminate check casts that we can prove the type of.
+            default: {}
+        }
+        if (setLatticeValueTo(resultReg, resultValue, resultConstant)) {
+            addUsersToWorklist(resultReg, resultValue);
+        }
+    }
+
+    private void run() {
+        SsaBasicBlock firstBlock = ssaMeth.getEntryBlock();
+        addBlockToWorklist(firstBlock);
+
+        /* Empty all the worklists by propagating our values */
+        while (!cfgWorklist.isEmpty()
+                || !cfgPhiWorklist.isEmpty()
+                || !ssaWorklist.isEmpty()
+                || !varyingWorklist.isEmpty()) {
+            while (!cfgWorklist.isEmpty()) {
+                int listSize = cfgWorklist.size() - 1;
+                SsaBasicBlock block = cfgWorklist.remove(listSize);
+                simulateBlock(block);
+            }
+
+            while (!cfgPhiWorklist.isEmpty()) {
+                int listSize = cfgPhiWorklist.size() - 1;
+                SsaBasicBlock block = cfgPhiWorklist.remove(listSize);
+                simulatePhiBlock(block);
+            }
+
+            while (!varyingWorklist.isEmpty()) {
+                int listSize = varyingWorklist.size() - 1;
+                SsaInsn insn = varyingWorklist.remove(listSize);
+
+                if (!executableBlocks.get(insn.getBlock().getIndex())) {
+                    continue;
+                }
+
+                if (insn instanceof PhiInsn) {
+                    simulatePhi((PhiInsn)insn);
+                } else {
+                    simulateStmt(insn);
+                }
+            }
+            while (!ssaWorklist.isEmpty()) {
+                int listSize = ssaWorklist.size() - 1;
+                SsaInsn insn = ssaWorklist.remove(listSize);
+
+                if (!executableBlocks.get(insn.getBlock().getIndex())) {
+                    continue;
+                }
+
+                if (insn instanceof PhiInsn) {
+                    simulatePhi((PhiInsn)insn);
+                } else {
+                    simulateStmt(insn);
+                }
+            }
+        }
+
+        replaceConstants();
+        replaceBranches();
+    }
+
+    /**
+     * Replaces TypeBearers in source register specs with constant type
+     * bearers if possible. These are then referenced in later optimization
+     * steps.
+     */
+    private void replaceConstants() {
+        for (int reg = 0; reg < regCount; reg++) {
+            if (latticeValues[reg] != CONSTANT) {
+                continue;
+            }
+            if (!(latticeConstants[reg] instanceof TypedConstant)) {
+                // We can't do much with these
+                continue;
+            }
+
+            SsaInsn defn = ssaMeth.getDefinitionForRegister(reg);
+            TypeBearer typeBearer = defn.getResult().getTypeBearer();
+
+            if (typeBearer.isConstant()) {
+                /*
+                 * The definition was a constant already.
+                 * The uses should be as well.
+                 */
+                continue;
+            }
+
+            // Update the destination RegisterSpec with the constant value
+            RegisterSpec dest = defn.getResult();
+            RegisterSpec newDest
+                    = dest.withType((TypedConstant)latticeConstants[reg]);
+            defn.setResult(newDest);
+
+            /*
+             * Update the sources RegisterSpec's of all non-move uses.
+             * These will be used in later steps.
+             */
+            for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
+                if (insn.isPhiOrMove()) {
+                    continue;
+                }
+
+                NormalSsaInsn nInsn = (NormalSsaInsn) insn;
+                RegisterSpecList sources = insn.getSources();
+
+                int index = sources.indexOfRegister(reg);
+
+                RegisterSpec spec = sources.get(index);
+                RegisterSpec newSpec
+                        = spec.withType((TypedConstant)latticeConstants[reg]);
+
+                nInsn.changeOneSource(index, newSpec);
+            }
+        }
+    }
+
+    /**
+     * Replaces branches that have constant conditions with gotos
+     */
+    private void replaceBranches() {
+        for (SsaInsn insn : branchWorklist) {
+            // Find if a successor block is never executed
+            int oldSuccessor = -1;
+            SsaBasicBlock block = insn.getBlock();
+            int successorSize = block.getSuccessorList().size();
+            for (int i = 0; i < successorSize; i++) {
+                int successorBlock = block.getSuccessorList().get(i);
+                if (!executableBlocks.get(successorBlock)) {
+                    oldSuccessor = successorBlock;
+                }
+            }
+
+            /*
+             * Prune branches that have already been handled and ones that no
+             * longer have constant conditions (no nonexecutable successors)
+             */
+            if (successorSize != 2 || oldSuccessor == -1) continue;
+
+            // Replace branch with goto
+            Insn originalRopInsn = insn.getOriginalRopInsn();
+            block.replaceLastInsn(new PlainInsn(Rops.GOTO,
+                originalRopInsn.getPosition(), null, RegisterSpecList.EMPTY));
+            block.removeSuccessor(oldSuccessor);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/SetFactory.java b/dx/src/com/android/dx/ssa/SetFactory.java
new file mode 100644
index 0000000..92e965f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SetFactory.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.util.BitIntSet;
+import com.android.dx.util.IntSet;
+import com.android.dx.util.ListIntSet;
+
+
+/**
+ * Makes int sets for various parts of the optimizer.
+ */
+public final class SetFactory {
+
+    /**
+     * BitIntSet/ListIntSet threshold for dominance frontier sets. These
+     * sets are kept per basic block until phi placement and tend to be,
+     * like the CFG itself, very sparse at large sizes.
+     *
+     * A value of 3072 here is somewhere around 1.125mb of total bitset size.
+     */
+    private static final int DOMFRONT_SET_THRESHOLD_SIZE = 3072;
+
+    /**
+     * BitIntSet/ListIntSet threshold for interference graph sets. These
+     * sets are kept per register until register allocation is done.
+     *
+     * A value of 3072 here is somewhere around 1.125mb of total bitset size.
+     */
+    private static final int INTERFERENCE_SET_THRESHOLD_SIZE = 3072;
+
+    /**
+     * BitIntSet/ListIntSet threshold for the live in/out sets kept by
+     * {@link SsaBasicBlock}. These are sets of SSA registers kept per basic
+     * block during register allocation.
+     *
+     * The total size of a bitset for this would be the count of blocks
+     * times the size of registers. The threshold value here is merely
+     * the register count, which is typically on the order of the block
+     * count as well.
+     */
+    private static final int LIVENESS_SET_THRESHOLD_SIZE = 3072;
+
+
+    /**
+     * Make IntSet for the dominance-frontier sets.
+     *
+     * @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
+                ? new BitIntSet(szBlocks)
+                : new ListIntSet();
+    }
+
+    /**
+     * Make IntSet for the interference graph sets. Public because
+     * InterferenceGraph is in another package.
+     *
+     * @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
+                ? new BitIntSet(countRegs)
+                : new ListIntSet();
+    }
+
+    /**
+     * Make IntSet for register live in/out sets.
+     *
+     * @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
+                ? new BitIntSet(countRegs)
+                : new ListIntSet();
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/SsaBasicBlock.java b/dx/src/com/android/dx/ssa/SsaBasicBlock.java
new file mode 100644
index 0000000..499f59f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SsaBasicBlock.java
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.InsnList;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+import com.android.dx.util.IntSet;
+
+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 {
+    /**
+     * {@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 {@code -1} for no primary
+     * successor
+     */
+    private int primarySuccessor = -1;
+
+    /** label of block in rop form */
+    private int ropLabel;
+
+    /** {@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
+     * 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
+     * phi-removal process. Retained for subsequent move scheduling.
+     */
+    private int movesFromPhisAtBeginning = 0;
+
+    /**
+     * contains last computed value of reachability of this block, or -1
+     * if reachability hasn't been calculated yet
+     */
+    private int reachable = -1;
+
+    /**
+     * {@code null-ok;} indexed by reg: the regs that are live-in at
+     * this block
+     */
+    private IntSet liveIn;
+
+    /**
+     * {@code null-ok;} indexed by reg: the regs that are live-out at
+     * this block
+     */
+    private IntSet liveOut;
+
+    /**
+     * 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
+     */
+    public SsaBasicBlock(final int basicBlockIndex, final int ropLabel,
+            final SsaMethod parent) {
+        this.parent = parent;
+        this.index = basicBlockIndex;
+        this.insns = new ArrayList<SsaInsn>();
+        this.ropLabel = ropLabel;
+
+        this.predecessors = new BitSet(parent.getBlocks().size());
+        this.successors = new BitSet(parent.getBlocks().size());
+        this.successorList = new IntList();
+
+        domChildren = new ArrayList<SsaBasicBlock>();
+    }
+
+    /**
+     * Creates a new SSA basic block from a ROP form basic block.
+     *
+     * @param rmeth original method
+     * @param basicBlockIndex index this block will have
+     * @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 = 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));
+        }
+
+        result.predecessors = SsaMethod.bitSetFromLabelList(
+                ropBlocks,
+                rmeth.labelToPredecessors(bb.getLabel()));
+
+        result.successors
+                = SsaMethod.bitSetFromLabelList(ropBlocks, bb.getSuccessors());
+
+        result.successorList
+                = SsaMethod.indexListFromLabelList(ropBlocks,
+                    bb.getSuccessors());
+
+        if (result.successorList.size() != 0) {
+            int primarySuccessor = bb.getPrimarySuccessor();
+
+            result.primarySuccessor = (primarySuccessor < 0)
+                    ? -1 : ropBlocks.indexOfLabel(primarySuccessor);
+        }
+
+        return result;
+    }
+
+    /**
+     * Adds a basic block as a dom child for this block. Used when constructing
+     * the dom tree.
+     *
+     * @param child {@code non-null;} new dom child
+     */
+    public void addDomChild(SsaBasicBlock child) {
+        domChildren.add(child);
+    }
+
+    /**
+     * Gets the dom children for this node. Don't modify this list.
+     *
+     * @return {@code non-null;} list of dom children
+     */
+    public ArrayList<SsaBasicBlock> getDomChildren() {
+        return domChildren;
+    }
+
+    /**
+     * 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 {@code >=0;} result reg
+     */
+    public void addPhiInsnForReg(int reg) {
+        insns.add(0, new PhiInsn(reg, this));
+    }
+
+    /**
+     * Adds a phi insn to the beginning of this block. This is to be used
+     * when the result type or local-association can be determined at phi
+     * insert time.
+     *
+     * @param resultSpec {@code non-null;} reg
+     */
+    public void addPhiInsnForReg(RegisterSpec resultSpec) {
+        insns.add(0, new PhiInsn(resultSpec, this));
+    }
+
+    /**
+     * Adds an insn to the head of this basic block, just after any phi
+     * insns.
+     *
+     * @param insn {@code non-null;} rop-form insn to add
+     */
+    public void addInsnToHead(Insn insn) {
+        SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
+        insns.add(getCountPhiInsns(), newInsn);
+        parent.onInsnAdded(newInsn);
+    }
+
+    /**
+     * Replaces the last insn in this block. The provided insn must have
+     * some branchingness.
+     *
+     * @param insn {@code non-null;} rop-form insn to add, which must branch.
+     */
+    public void replaceLastInsn(Insn insn) {
+        if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
+            throw new IllegalArgumentException("last insn must branch");
+        }
+
+        SsaInsn oldInsn = insns.get(insns.size() - 1);
+        SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
+
+        insns.set(insns.size() - 1, newInsn);
+
+        parent.onInsnRemoved(oldInsn);
+        parent.onInsnAdded(newInsn);
+    }
+
+    /**
+     * 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) {
+                v.visitPhiInsn((PhiInsn) insn);
+            } else {
+                /*
+                 * Presently we assume PhiInsn's are in a continuous
+                 * block at the top of the list
+                 */
+                break;
+            }
+        }
+    }
+
+    /**
+     * Deletes all phi insns. Do this after adding appropriate move insns.
+     */
+    public void removeAllPhiInsns() {
+        /*
+         * Presently we assume PhiInsn's are in a continuous
+         * block at the top of the list.
+         */
+
+        insns.subList(0, getCountPhiInsns()).clear();
+    }
+
+    /**
+     * Gets the number of phi insns at the top of this basic block.
+     *
+     * @return count of phi insns
+     */
+    private int getCountPhiInsns() {
+        int countPhiInsns;
+
+        int sz = insns.size();
+        for (countPhiInsns = 0; countPhiInsns < sz; countPhiInsns++) {
+            SsaInsn insn = insns.get(countPhiInsns);
+            if (!(insn instanceof PhiInsn)) {
+                break;
+            }
+        }
+
+        return countPhiInsns;
+    }
+
+    /**
+     * @return {@code non-null;} the (mutable) instruction list for this block,
+     * with phi insns at the beginning
+     */
+    public ArrayList<SsaInsn> getInsns() {
+        return insns;
+    }
+
+    /**
+     * @return {@code non-null;} the (mutable) list of phi insns for this block
+     */
+    public List<SsaInsn> getPhiInsns() {
+        return insns.subList(0, getCountPhiInsns());
+    }
+
+    /**
+     * @return the block index of this block
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * @return the label of this block in rop form
+     */
+    public int getRopLabel() {
+        return ropLabel;
+    }
+
+    /**
+     * @return the label of this block in rop form as a hex string
+     */
+    public String getRopLabelString() {
+        return Hex.u2(ropLabel);
+    }
+
+    /**
+     * @return {@code non-null;} predecessors set, indexed by block index
+     */
+    public BitSet getPredecessors() {
+        return predecessors;
+    }
+
+    /**
+     * @return {@code non-null;} successors set, indexed by block index
+     */
+    public BitSet getSuccessors() {
+        return successors;
+    }
+
+    /**
+     * @return {@code non-null;} ordered successor list, containing block
+     * indicies
+     */
+    public IntList getSuccessorList() {
+        return successorList;
+    }
+
+    /**
+     * @return {@code >= -1;} block index of primary successor or
+     * {@code -1} if no primary successor
+     */
+    public int getPrimarySuccessorIndex() {
+        return primarySuccessor;
+    }
+
+    /**
+     * @return rop label of primary successor
+     */
+    public int getPrimarySuccessorRopLabel() {
+        return parent.blockIndexToRopLabel(primarySuccessor);
+    }
+
+    /**
+     * @return {@code null-ok;} the primary successor block or {@code null}
+     * if there is none
+     */
+    public SsaBasicBlock getPrimarySuccessor() {
+        if (primarySuccessor < 0) {
+            return null;
+        } else {
+            return parent.getBlocks().get(primarySuccessor);
+        }
+    }
+
+    /**
+     * @return successor list of rop labels
+     */
+    public IntList getRopLabelSuccessorList() {
+        IntList result = new IntList(successorList.size());
+
+        int sz = successorList.size();
+
+        for (int i = 0; i < sz; i++) {
+            result.add(parent.blockIndexToRopLabel(successorList.get(i)));
+        }
+        return result;
+    }
+
+    /**
+     * @return {@code non-null;} method that contains this block
+     */
+    public SsaMethod getParent() {
+        return parent;
+    }
+
+    /**
+     * Inserts a new empty GOTO block as a predecessor to this block.
+     * All previous predecessors will be predecessors to the new block.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public SsaBasicBlock insertNewPredecessor() {
+        SsaBasicBlock newPred = parent.makeNewGotoBlock();
+
+        // Update the new block.
+        newPred.predecessors = predecessors;
+        newPred.successors.set(index) ;
+        newPred.successorList.add(index);
+        newPred.primarySuccessor = index;
+
+
+        // Update us.
+        predecessors = new BitSet(parent.getBlocks().size());
+        predecessors.set(newPred.index);
+
+        // Update our (soon-to-be) old predecessors.
+        for (int i = newPred.predecessors.nextSetBit(0); i >= 0;
+                i = newPred.predecessors.nextSetBit(i + 1)) {
+
+            SsaBasicBlock predBlock = parent.getBlocks().get(i);
+
+            predBlock.replaceSuccessor(index, newPred.index);
+        }
+
+        return newPred;
+    }
+
+    /**
+     * 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 {@code non-null;} an appropriately-constructed instance
+     */
+    public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) {
+        SsaBasicBlock newSucc = parent.makeNewGotoBlock();
+
+        if (!successors.get(other.index)) {
+            throw new RuntimeException("Block " + other.getRopLabelString()
+                    + " not successor of " + getRopLabelString());
+        }
+
+        // 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.
+        for (int i = successorList.size() - 1 ;  i >= 0; i--) {
+            if (successorList.get(i) == other.index) {
+                successorList.set(i, newSucc.index);
+            }
+        }
+
+        if (primarySuccessor == other.index) {
+            primarySuccessor = newSucc.index;
+        }
+        successors.clear(other.index);
+        successors.set(newSucc.index);
+
+        // Update "other".
+        other.predecessors.set(newSucc.index);
+        other.predecessors.set(index, successors.get(other.index));
+
+        return newSucc;
+    }
+
+    /**
+     * 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
+     */
+    public void replaceSuccessor(int oldIndex, int newIndex) {
+        if (oldIndex == newIndex) {
+            return;
+        }
+
+        // Update us.
+        successors.set(newIndex);
+
+        if (primarySuccessor == oldIndex) {
+            primarySuccessor = newIndex;
+        }
+
+        for (int i = successorList.size() - 1 ;  i >= 0; i--) {
+            if (successorList.get(i) == oldIndex) {
+                successorList.set(i, newIndex);
+            }
+        }
+
+        successors.clear(oldIndex);
+
+        // Update new successor.
+        parent.getBlocks().get(newIndex).predecessors.set(index);
+
+        // Update old successor.
+        parent.getBlocks().get(oldIndex).predecessors.clear(index);
+    }
+
+    /**
+     * Removes a successor from this block's successor list.
+     *
+     * @param oldIndex index of successor block to remove
+     */
+    public void removeSuccessor(int oldIndex) {
+        int removeIndex = 0;
+
+        for (int i = successorList.size() - 1; i >= 0; i--) {
+            if (successorList.get(i) == oldIndex) {
+                removeIndex = i;
+            } else {
+                primarySuccessor = successorList.get(i);
+            }
+        }
+
+        successorList.removeIndex(removeIndex);
+        successors.clear(oldIndex);
+        parent.getBlocks().get(oldIndex).predecessors.clear(index);
+    }
+
+    /**
+     * Attaches block to an exit block if necessary. If this block
+     * 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 {@code non-null;} exit block
+     */
+    public void exitBlockFixup(SsaBasicBlock exitBlock) {
+        if (this == exitBlock) {
+            return;
+        }
+
+        if (successorList.size() == 0) {
+            /*
+             * This is an exit predecessor.
+             * Set the successor to the exit block
+             */
+            successors.set(exitBlock.index);
+            successorList.add(exitBlock.index);
+            primarySuccessor = exitBlock.index;
+            exitBlock.predecessors.set(this.index);
+        }
+    }
+
+    /**
+     * Adds a move instruction to the end of this basic block, just
+     * 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
+     */
+    public void addMoveToEnd(RegisterSpec result, RegisterSpec source) {
+
+        if (result.getReg() == source.getReg()) {
+            // Sometimes we end up with no-op moves. Ignore them here.
+            return;
+        }
+
+        /*
+         * The last Insn has to be a normal SSA insn: a phi can't branch
+         * or return or cause an exception, etc.
+         */
+        NormalSsaInsn lastInsn;
+        lastInsn = (NormalSsaInsn)insns.get(insns.size()-1);
+
+        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.
+             */
+
+            for (int i = successors.nextSetBit(0)
+                    ; i >= 0
+                    ; i = successors.nextSetBit(i + 1)) {
+
+                SsaBasicBlock succ;
+
+                succ = parent.getBlocks().get(i);
+                succ.addMoveToBeginning(result, source);
+            }
+        } 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.
+             */
+            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);
+
+            movesFromPhisAtEnd++;
+        }
+    }
+
+    /**
+     * 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 = RegisterSpecList.make(source);
+        NormalSsaInsn toAdd = new NormalSsaInsn(
+                new PlainInsn(Rops.opMove(result.getType()),
+                        SourcePosition.NO_INFO, result, sources), this);
+
+        insns.add(getCountPhiInsns(), toAdd);
+        movesFromPhisAtBeginning++;
+    }
+
+    /**
+     * Sets the register as used in a bitset, taking into account its
+     * category/width.
+     *
+     * @param regsUsed set, indexed by register number
+     * @param rs register to mark as used
+     */
+    private static void setRegsUsed (BitSet regsUsed, RegisterSpec rs) {
+        regsUsed.set(rs.getReg());
+        if (rs.getCategory() > 1) {
+            regsUsed.set(rs.getReg() + 1);
+        }
+    }
+
+    /**
+     * Checks to see if the register is used in a bitset, taking
+     * into account its category/width.
+     *
+     * @param regsUsed set, indexed by register number
+     * @param rs register to mark as used
+     * @return true if register is fully or partially (for the case of wide
+     * registers) used.
+     */
+    private static boolean checkRegUsed (BitSet regsUsed, RegisterSpec rs) {
+        int reg = rs.getReg();
+        int category = rs.getCategory();
+
+        return regsUsed.get(reg)
+                || (category == 2 ? regsUsed.get(reg + 1) : false);
+    }
+
+    /**
+     * Ensures that all move operations in this block occur such that
+     * 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
+     * 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.
+        BitSet regsUsedAsResults = new BitSet(parent.getRegCount());
+
+        int sz = toSchedule.size();
+
+        int insertPlace = 0;
+
+        while (insertPlace < sz) {
+            int oldInsertPlace = insertPlace;
+
+            // Record all registers used as sources in this block.
+            for (int i = insertPlace; i < sz; i++) {
+                setRegsUsed(regsUsedAsSources,
+                        toSchedule.get(i).getSources().get(0));
+
+                setRegsUsed(regsUsedAsResults,
+                        toSchedule.get(i).getResult());
+            }
+
+            /*
+             * If there are no circular dependencies, then there exists
+             * n instructions where n > 1 whose result is not used as a source.
+             */
+            for (int i = insertPlace; i <sz; i++) {
+                SsaInsn insn = toSchedule.get(i);
+
+                /*
+                 * Move these n registers to the front, since they overwrite
+                 * nothing.
+                 */
+                if (!checkRegUsed(regsUsedAsSources, insn.getResult())) {
+                    Collections.swap(toSchedule, i, insertPlace++);
+                }
+            }
+
+            /*
+             * 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;
+
+                // Find an insn whose result is used as a source.
+                for (int i = insertPlace; i < sz; i++) {
+                    SsaInsn insn = toSchedule.get(i);
+                    if (checkRegUsed(regsUsedAsSources, insn.getResult())
+                            && checkRegUsed(regsUsedAsResults,
+                                insn.getSources().get(0))) {
+
+                        insnToSplit = insn;
+                        /*
+                         * 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.
+
+                RegisterSpec result = insnToSplit.getResult();
+                RegisterSpec tempSpec = result.withReg(
+                        parent.borrowSpareRegister(result.getCategory()));
+
+                NormalSsaInsn toAdd = new NormalSsaInsn(
+                        new PlainInsn(Rops.opMove(result.getType()),
+                                SourcePosition.NO_INFO,
+                                tempSpec,
+                                insnToSplit.getSources()), this);
+
+                toSchedule.add(insertPlace++, toAdd);
+
+                RegisterSpecList newSources = RegisterSpecList.make(tempSpec);
+
+                NormalSsaInsn toReplace = new NormalSsaInsn(
+                        new PlainInsn(Rops.opMove(result.getType()),
+                                SourcePosition.NO_INFO,
+                                result,
+                                newSources), this);
+
+                toSchedule.set(insertPlace, toReplace);
+
+                // The size changed.
+                sz = toSchedule.size();
+            }
+
+            regsUsedAsSources.clear();
+            regsUsedAsResults.clear();
+        }
+    }
+
+    /**
+     * 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) {
+        if (liveOut == null) {
+            liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
+        }
+
+        liveOut.add(regV);
+    }
+
+    /**
+     * 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) {
+        if (liveIn == null) {
+            liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
+        }
+
+        liveIn.add(regV);
+    }
+
+    /**
+     * Returns the set of live-in registers. Valid after register
+     * interference graph has been generated, otherwise empty.
+     *
+     * @return {@code non-null;} live-in register set.
+     */
+    public IntSet getLiveInRegs() {
+        if (liveIn == null) {
+            liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
+        }
+        return liveIn;
+    }
+
+    /**
+     * Returns the set of live-out registers. Valid after register
+     * interference graph has been generated, otherwise empty.
+     *
+     * @return {@code non-null;} live-out register set
+     */
+    public IntSet getLiveOutRegs() {
+        if (liveOut == null) {
+            liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
+        }
+        return liveOut;
+    }
+
+    /**
+     * @return true if this is the one-and-only exit block for this method
+     */
+    public boolean isExitBlock() {
+        return index == parent.getExitBlockIndex();
+    }
+
+    /**
+     * Returns true if this block was last calculated to be reachable.
+     * Recalculates reachability if value has never been computed.
+     *
+     * @return {@code true} if reachable
+     */
+    public boolean isReachable() {
+        if (reachable == -1) {
+            parent.computeReachability();
+        }
+        return (reachable == 1);
+    }
+
+    /**
+     * Sets reachability of block to specified value
+     *
+     * @param reach new value of reachability for block
+     */
+    public void setReachable(int reach) {
+        reachable = reach;
+    }
+
+    /**
+     * 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>
+     *
+     * This is necessary because copy-propogation may have left us in a state
+     * where the same basic block has the same register as a phi operand
+     * and a result. In this case, the register in the phi operand always
+     * refers value before any other phis have executed.
+     */
+    public void scheduleMovesFromPhis() {
+        if (movesFromPhisAtBeginning > 1) {
+            List<SsaInsn> toSchedule;
+
+            toSchedule = insns.subList(0, movesFromPhisAtBeginning);
+
+            scheduleUseBeforeAssigned(toSchedule);
+
+            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.
+             */
+            if (firstNonPhiMoveInsn.isMoveException()) {
+                if (true) {
+                    /*
+                     * We've yet to observe this case, and if it can
+                     * 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.
+                     */
+                    boolean moveExceptionInterferes = false;
+
+                    int moveExceptionResult
+                            = firstNonPhiMoveInsn.getResult().getReg();
+
+                    /*
+                     * Does the move-exception result reg interfere with the
+                     * phi moves?
+                     */
+                    for (SsaInsn insn : toSchedule) {
+                        if (insn.isResultReg(moveExceptionResult)
+                                || insn.isRegASource(moveExceptionResult)) {
+                            moveExceptionInterferes = true;
+                            break;
+                        }
+                    }
+
+                    if (!moveExceptionInterferes) {
+                        // 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.
+                         */
+                        RegisterSpec originalResultSpec
+                            = firstNonPhiMoveInsn.getResult();
+                        int spareRegister = parent.borrowSpareRegister(
+                                originalResultSpec.getCategory());
+
+                        // We now move it to a spare register.
+                        firstNonPhiMoveInsn.changeResultReg(spareRegister);
+                        RegisterSpec tempSpec =
+                            firstNonPhiMoveInsn.getResult();
+
+                        insns.add(0, firstNonPhiMoveInsn);
+
+                        // And here we move it back.
+
+                        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.
+                         */
+                        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().
+        parent.returnSpareRegisters();
+
+    }
+
+    /**
+     * Visits all insns in this block.
+     *
+     * @param visitor {@code non-null;} callback interface
+     */
+    public void forEachInsn(SsaInsn.Visitor 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} */
+    @Override
+    public String toString() {
+        return "{" + index + ":" + Hex.u2(ropLabel) + '}';
+    }
+
+    /**
+     * Visitor interface for basic blocks.
+     */
+    public interface Visitor {
+        /**
+         * Indicates a block has been visited by an iterator method.
+         *
+         * @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
new file mode 100644
index 0000000..5cd8b6f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SsaConverter.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.util.IntIterator;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+/**
+ * Converts ROP methods to SSA Methods
+ */
+public class SsaConverter {
+    public static final boolean DEBUG = false;
+
+    /**
+     * 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 {@code true} if this method has no {@code this}
+     * pointer argument
+     * @return output in SSA form
+     */
+    public static SsaMethod convertToSsaMethod(RopMethod rmeth,
+            int paramWidth, boolean isStatic) {
+        SsaMethod result
+            = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+        edgeSplit(result);
+
+        LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+
+        placePhiFunctions(result, localInfo, 0);
+        new SsaRenamer(result).run();
+
+        /*
+         * The exit block, added here, is not considered for edge splitting
+         * or phi placement since no actual control flows to it.
+         */
+        result.makeExitBlock();
+
+        return result;
+    }
+
+    /**
+     * Updates an SSA representation, placing phi functions and renaming all
+     * registers above a certain threshold number.
+     *
+     * @param ssaMeth input
+     * @param threshold registers below this number are unchanged
+     */
+    public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
+        LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
+        placePhiFunctions(ssaMeth, localInfo, threshold);
+        new SsaRenamer(ssaMeth, threshold).run();
+    }
+
+    /**
+     * Returns an SSA represention with only the edge-splitter run.
+     *
+     * @param rmeth method to process
+     * @param paramWidth width of all arguments in the method
+     * @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) {
+        SsaMethod result;
+
+        result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+        edgeSplit(result);
+        return result;
+    }
+
+    /**
+     * 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 {@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) {
+        SsaMethod result;
+
+        result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+        edgeSplit(result);
+
+        LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+
+        placePhiFunctions(result, localInfo, 0);
+        return result;
+    }
+
+    /**
+     * See Appel section 19.1:
+     *
+     * Converts CFG into "edge-split" form, such that each node either a
+     * unique successor or unique predecessor.<p>
+     *
+     * In addition, the SSA form we use enforces a further constraint,
+     * requiring each block with a final instruction that returns a
+     * 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);
+    }
+
+    /**
+     * Inserts Z nodes as new predecessors for every node that has multiple
+     * successors and multiple predecessors.
+     *
+     * @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.
+         */
+        for (int i = blocks.size() - 1; i >= 0; i-- ) {
+            SsaBasicBlock block = blocks.get(i);
+            if (nodeNeedsUniquePredecessor(block)) {
+                block.insertNewPredecessor();
+            }
+        }
+    }
+
+    /**
+     * @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.
+         */
+
+        int countPredecessors = block.getPredecessors().cardinality();
+        int countSuccessors = block.getSuccessors().cardinality();
+
+        return  (countPredecessors > 1 && countSuccessors > 1);
+    }
+
+    /**
+     * In ROP form, move-exception must occur as the first insn in a block
+     * immediately succeeding the insn that could thrown an exception.
+     * 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.
+         */
+        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...
+             */
+            if (!block.isExitBlock()
+                    && block.getPredecessors().cardinality() > 1
+                    && block.getInsns().get(0).isMoveException()) {
+
+                // 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)) {
+                    SsaBasicBlock predecessor = blocks.get(j);
+                    SsaBasicBlock zNode
+                        = predecessor.insertNewSuccessor(block);
+
+                    /*
+                     * 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.
+                block.getInsns().remove(0);
+            }
+        }
+    }
+
+    /**
+     * Inserts Z nodes for every node that needs a new
+     * successor.
+     *
+     * @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.
+         */
+        for (int i = blocks.size() - 1; i >= 0; i-- ) {
+            SsaBasicBlock block = blocks.get(i);
+
+            // 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)) {
+
+                SsaBasicBlock succ = blocks.get(j);
+
+                if (needsNewSuccessor(block, succ)) {
+                    block.insertNewSuccessor(succ);
+                }
+            }
+        }
+    }
+
+    /**
+     * 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 {@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);
+
+        return ((lastInsn.getResult() != null)
+                    || (lastInsn.getSources().size() > 0))
+                && succ.getPredecessors().cardinality() > 1;
+    }
+
+    /**
+     * See Appel algorithm 19.6:
+     *
+     * Place Phi functions in appropriate locations.
+     *
+     * @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
+     * @param threshold registers below this number are ignored
+     */
+    private static void placePhiFunctions (SsaMethod ssaMeth,
+            LocalVariableInfo localInfo, int threshold) {
+        ArrayList<SsaBasicBlock> ssaBlocks;
+        int regCount;
+        int blockCount;
+
+        ssaBlocks = ssaMeth.getBlocks();
+        blockCount = ssaBlocks.size();
+        regCount = ssaMeth.getRegCount() - threshold;
+
+        DomFront df = new DomFront(ssaMeth);
+        DomFront.DomInfo[] domInfos = df.run();
+
+        // Bit set of registers vs block index "definition sites"
+        BitSet[] defsites = new BitSet[regCount];
+
+        // Bit set of registers vs block index "phi placement sites"
+        BitSet[] phisites = new BitSet[regCount];
+
+        for (int i = 0; i < regCount; i++) {
+            defsites[i] = new BitSet(blockCount);
+            phisites[i] = new BitSet(blockCount);
+        }
+
+        /*
+         * For each register, build a set of all basic blocks where
+         * containing an assignment to that register.
+         */
+        for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
+            SsaBasicBlock b = ssaBlocks.get(bi);
+
+            for (SsaInsn insn : b.getInsns()) {
+                RegisterSpec rs = insn.getResult();
+
+                if (rs != null && rs.getReg() - threshold >= 0) {
+                    defsites[rs.getReg() - threshold].set(bi);
+                }
+            }
+        }
+
+        if (DEBUG) {
+            System.out.println("defsites");
+
+            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);
+            }
+        }
+
+        BitSet worklist;
+
+        /*
+         * For each register, compute all locations for phi placement
+         * based on dominance-frontier algorithm.
+         */
+        for (int reg = 0, s = regCount; reg < s; reg++) {
+            int workBlockIndex;
+
+            /* Worklist set starts out with each node where reg is assigned. */
+
+            worklist = (BitSet) (defsites[reg].clone());
+
+            while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
+                worklist.clear(workBlockIndex);
+                IntIterator dfIterator
+                    = domInfos[workBlockIndex].dominanceFrontiers.iterator();
+
+                while (dfIterator.hasNext()) {
+                    int dfBlockIndex = dfIterator.next();
+
+                    if (!phisites[reg].get(dfBlockIndex)) {
+                        phisites[reg].set(dfBlockIndex);
+
+                        int tReg = reg + threshold;
+                        RegisterSpec rs
+                            = localInfo.getStarts(dfBlockIndex).get(tReg);
+
+                        if (rs == null) {
+                            ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
+                        } else {
+                            ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
+                        }
+
+                        if (!defsites[reg].get(dfBlockIndex)) {
+                            worklist.set(dfBlockIndex);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (DEBUG) {
+            System.out.println("phisites");
+
+            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
new file mode 100644
index 0000000..ca7a1a2
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SsaInsn.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.*;
+import com.android.dx.util.ToHuman;
+
+/**
+ * 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;
+
+    /** {@code null-ok;} result register */
+    private RegisterSpec result;
+
+    /**
+     * 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(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.
+     *
+     * @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);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public SsaInsn clone() {
+        try {
+            return (SsaInsn)super.clone();
+        } catch (CloneNotSupportedException ex) {
+            throw new RuntimeException ("unexpected", ex);
+        }
+    }
+
+    /**
+     * Like {@link com.android.dx.rop.code.Insn getResult()}.
+     *
+     * @return result register
+     */
+    public RegisterSpec getResult() {
+        return result;
+    }
+
+    /**
+     * 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 {@code non-null;} sources list
+     */
+    abstract public RegisterSpecList getSources();
+
+    /**
+     * Gets the block to which this insn instance belongs.
+     *
+     * @return owning block
+     */
+    public SsaBasicBlock getBlock() {
+        return block;
+    }
+
+    /**
+     * 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
+     */
+    public boolean isResultReg(int reg) {
+        return result != null && result.getReg() == reg;
+    }
+
+
+    /**
+     * 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) {
+            result = result.withReg(reg);
+        }
+    }
+
+    /**
+     * Sets the local association for the result of this insn. This is
+     * sometimes updated during the SsaRenamer process.
+     *
+     * @param local {@code null-ok;} new debug/local variable info
+     */
+    public final void setResultLocal(LocalItem local) {
+        LocalItem oldItem = result.getLocalItem();
+
+        if (local != oldItem && (local == null
+                || !local.equals(result.getLocalItem()))) {
+            result = RegisterSpec.makeLocalOptional(
+                    result.getReg(), result.getType(), local);
+        }
+    }
+
+    /**
+     * Map registers after register allocation.
+     *
+     * @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);
+    }
+
+    /**
+     * Maps only source registers.
+     *
+     * @param mapper new mapping
+     */
+    abstract public void mapSourceRegisters(RegisterMapper mapper);
+
+    /**
+     * Returns the Rop opcode for this insn, or null if this is a phi insn.
+     *
+     * TODO: Move this up into NormalSsaInsn.
+     *
+     * @return {@code null-ok;} Rop opcode if there is one.
+     */
+    abstract public Rop getOpcode();
+
+    /**
+     * Returns the original Rop insn for this insn, or null if this is
+     * a phi insn.
+     *
+     * TODO: Move this up into NormalSsaInsn.
+     *
+     * @return {@code null-ok;} Rop insn if there is one.
+     */
+    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} insns
+     * it may be the source.
+     *
+     * @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) {
+            return result;
+        }
+
+        return null;
+    }
+
+    /**
+     * Indicates whether the specified register is amongst the registers
+     * used as sources for this instruction.
+     *
+     * @param reg the register in question
+     * @return true if the reg is a source
+     */
+    public boolean isRegASource(int reg) {
+        return null != getSources().specForRegister(reg);
+    }
+
+    /**
+     * Transform back to ROP form.
+     *
+     * TODO: Move this up into NormalSsaInsn.
+     *
+     * @return {@code non-null;} a ROP representation of this instruction, with
+     * updated registers.
+     */
+    public abstract Insn toRopInsn();
+
+    /**
+     * @return true if this is a PhiInsn or a normal move insn
+     */
+    public abstract boolean isPhiOrMove();
+
+    /**
+     * Returns true if this insn is considered to have a side effect beyond
+     * that of assigning to the result reg.
+     *
+     * @return true if this insn is considered to have a side effect beyond
+     * that of assigning to the result reg.
+     */
+    public abstract boolean hasSideEffect();
+
+    /**
+     * @return true if this is a move (but not a move-operand or
+     * move-exception) instruction
+     */
+    public boolean isNormalMoveInsn() {
+        return false;
+    }
+
+    /**
+     * @return true if this is a move-exception instruction.
+     * These instructions must immediately follow a preceeding invoke*
+     */
+    public boolean isMoveException() {
+        return false;
+    }
+
+    /**
+     * @return true if this instruction can throw.
+     */
+    abstract public boolean canThrow();
+
+    /**
+     * Accepts a visitor.
+     *
+     * @param v {@code non-null} the visitor
+     */
+    public abstract void accept(Visitor v);
+
+    /**
+     * Visitor interface for this class.
+     */
+    public static interface Visitor {
+        /**
+         * Any non-phi move instruction
+         * @param insn {@code non-null;} the instruction to visit
+         */
+        public void visitMoveInsn(NormalSsaInsn insn);
+
+        /**
+         * Any phi insn
+         * @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 {@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
new file mode 100644
index 0000000..4c2bd85
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SsaMethod.java
@@ -0,0 +1,873 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * A method in SSA form.
+ */
+public final class SsaMethod {
+    /** basic blocks, indexed by block index */
+    private ArrayList<SsaBasicBlock> blocks;
+
+    /** Index of first executed block in method */
+    private int entryBlockIndex;
+
+    /**
+     * Index of exit block, which exists only in SSA form,
+     * 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 */
+    private int maxLabel;
+
+    /** the total width, in register-units, of the method's parameters */
+    private final int paramWidth;
+
+    /** true if this method has no {@code this} pointer argument */
+    private final boolean isStatic;
+
+    /**
+     * indexed by register: the insn where said register is defined or null
+     * if undefined. null until (lazily) created.
+     */
+    private SsaInsn[] definitionList;
+
+    /** 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;
+
+    /**
+     * "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.
+     *
+     * TODO: Remove this mode, and place the functionality elsewhere
+     */
+    private boolean backMode;
+
+    /**
+     * @param ropMethod rop-form method to convert from
+     * @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
+     */
+    public static SsaMethod newFromRopMethod(RopMethod ropMethod,
+            int paramWidth, boolean isStatic) {
+        SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic);
+
+        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.
+     *
+     * @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());
+
+        for (int i = 0, sz = labelList.size(); i < sz; i++) {
+            result.set(blocks.indexOfLabel(labelList.get(i)));
+        }
+
+        return result;
+    }
+
+    /**
+     * Builds an IntList of block indices from a basic block list and a list
+     * of labels taken from Rop form.
+     *
+     * @param ropBlocks Rop blocks
+     * @param labelList list of rop block labels
+     * @return IntList of block indices
+     */
+    public static IntList indexListFromLabelList(BasicBlockList ropBlocks,
+            IntList labelList) {
+
+        IntList result = new IntList(labelList.size());
+
+        for (int i = 0, sz = labelList.size(); i < sz; i++) {
+            result.add(ropBlocks.indexOfLabel(labelList.get(i)));
+        }
+
+        return result;
+    }
+
+    private void convertRopToSsaBlocks(RopMethod rmeth) {
+        BasicBlockList ropBlocks = rmeth.getBlocks();
+        int sz = ropBlocks.size();
+
+        blocks = new ArrayList<SsaBasicBlock>(sz + 2);
+
+        for (int i = 0; i < sz; i++) {
+            SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
+            blocks.add(sbb);
+        }
+
+        // Add an no-op entry block.
+        int origEntryBlockIndex = rmeth.getBlocks()
+                .indexOfLabel(rmeth.getFirstLabel());
+
+        SsaBasicBlock entryBlock
+                = blocks.get(origEntryBlockIndex).insertNewPredecessor();
+
+        entryBlockIndex = entryBlock.getIndex();
+        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.
+     */
+    /*package*/ void makeExitBlock() {
+        if (exitBlockIndex >= 0) {
+            throw new RuntimeException("must be called at most once");
+        }
+
+        exitBlockIndex = blocks.size();
+        SsaBasicBlock exitBlock
+                = new SsaBasicBlock(exitBlockIndex, maxLabel++, this);
+
+        blocks.add(exitBlock);
+
+        for (SsaBasicBlock block : blocks) {
+            block.exitBlockFixup(exitBlock);
+        }
+
+        if (exitBlock.getPredecessors().cardinality() == 0) {
+            // In cases where there is no exit...
+            blocks.remove(exitBlockIndex);
+            exitBlockIndex = -1;
+            maxLabel--;
+        }
+    }
+
+    /**
+     * Gets a new {@code GOTO} insn.
+     *
+     * @param block block to which this GOTO will be added
+     * (not it's destination!)
+     * @return an appropriately-constructed instance.
+     */
+    private static SsaInsn getGoto(SsaBasicBlock block) {
+        return new NormalSsaInsn (
+                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}. Successors and predecessors are not yet
+     * set.
+     *
+     * @return new block
+     */
+    public SsaBasicBlock makeNewGotoBlock() {
+        int newIndex = blocks.size();
+        SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this);
+
+        newBlock.getInsns().add(getGoto(newBlock));
+        blocks.add(newBlock);
+
+        return newBlock;
+    }
+
+    /**
+     * @return block index of first execution block
+     */
+    public int getEntryBlockIndex() {
+        return entryBlockIndex;
+    }
+
+    /**
+     * @return first execution block
+     */
+    public SsaBasicBlock getEntryBlock() {
+        return blocks.get(entryBlockIndex);
+    }
+
+    /**
+     * @return block index of exit block or {@code -1} if there is none
+     */
+    public int getExitBlockIndex() {
+        return exitBlockIndex;
+    }
+
+    /**
+     * @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 {@code -1} for none
+     * @return rop label or {code -1} if {@code bi} was {@code -1}
+     */
+    public int blockIndexToRopLabel(int bi) {
+        if (bi < 0) {
+            return -1;
+        }
+        return blocks.get(bi).getRopLabel();
+    }
+
+    /**
+     * @return count of registers used in this method
+     */
+    public int getRegCount() {
+        return registerCount;
+    }
+
+    /**
+     * @return the total width, in register units, of the method's
+     * parameters
+     */
+    public int getParamWidth() {
+        return paramWidth;
+    }
+
+    /**
+     * Returns {@code true} if this is a static method.
+     *
+     * @return {@code true} if this is a static method
+     */
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    /**
+     * 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 = spareRegisterBase + borrowedSpareRegisters;
+
+        borrowedSpareRegisters += category;
+        registerCount = Math.max(registerCount, result + category);
+
+        return result;
+    }
+
+    /**
+     * Returns all borrowed registers.
+     */
+    public void returnSpareRegisters() {
+        borrowedSpareRegisters = 0;
+    }
+
+    /**
+     * @return {@code non-null;} basic block list. Do not modify.
+     */
+    public ArrayList<SsaBasicBlock> getBlocks() {
+        return blocks;
+    }
+
+    /**
+     * Returns the count of reachable blocks in this method: blocks that have
+     * predecessors (or are the start block)
+     *
+     * @return {@code >= 0;} number of reachable basic blocks
+     */
+    public int getCountReachableBlocks() {
+        int ret = 0;
+
+        for (SsaBasicBlock b : blocks) {
+            // Blocks that have been disconnected don't count.
+            if (b.isReachable()) {
+                ret++;
+            }
+        }
+
+        return ret;
+    }
+
+    /**
+     * Computes reachability for all blocks in the method. First clears old
+     * values from all blocks, then starts with the entry block and walks down
+     * the control flow graph, marking all blocks it finds as reachable.
+     */
+    public void computeReachability() {
+        for (SsaBasicBlock block : blocks) {
+            block.setReachable(0);
+        }
+
+        ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>();
+        blockList.add(this.getEntryBlock());
+
+        while (!blockList.isEmpty()) {
+            SsaBasicBlock block = blockList.remove(0);
+            if (block.isReachable()) continue;
+
+            block.setReachable(1);
+            BitSet succs = block.getSuccessors();
+            for (int i = succs.nextSetBit(0); i >= 0;
+                     i = succs.nextSetBit(i + 1)) {
+                blockList.add(blocks.get(i));
+            }
+        }
+    }
+
+    /**
+     * Remaps unversioned registers.
+     *
+     * @param mapper maps old registers to new.
+     */
+    public void mapRegisters(RegisterMapper mapper) {
+        for (SsaBasicBlock block : getBlocks()) {
+            for (SsaInsn insn : block.getInsns()) {
+                insn.mapRegisters(mapper);
+            }
+        }
+
+        registerCount = mapper.getNewRegisterCount();
+        spareRegisterBase = registerCount;
+    }
+
+    /**
+     * Returns the insn that defines the given register
+     * @param reg register in question
+     * @return insn (actual instance from code) that defined this reg or null
+     * if reg is not defined.
+     */
+    public SsaInsn getDefinitionForRegister(int reg) {
+        if (backMode) {
+            throw new RuntimeException("No def list in back mode");
+        }
+
+        if (definitionList != null) {
+            return definitionList[reg];
+        }
+
+        definitionList = new SsaInsn[getRegCount()];
+
+        forEachInsn(new SsaInsn.Visitor() {
+            public void visitMoveInsn (NormalSsaInsn insn) {
+                definitionList[insn.getResult().getReg()] = insn;
+            }
+            public void visitPhiInsn (PhiInsn phi) {
+                definitionList[phi.getResult().getReg()] = phi;
+            }
+            public void visitNonMoveInsn (NormalSsaInsn insn) {
+                RegisterSpec result = insn.getResult();
+                if (result != null) {
+                    definitionList[insn.getResult().getReg()] = insn;
+                }
+            }
+        });
+
+        return definitionList[reg];
+    }
+
+    /**
+     * Builds useList and unmodifiableUseList.
+     */
+    private void buildUseList() {
+        if (backMode) {
+            throw new RuntimeException("No use list in back mode");
+        }
+
+        useList = new ArrayList[registerCount];
+
+        for (int i = 0; i < registerCount; i++) {
+            useList[i] = new ArrayList();
+        }
+
+        forEachInsn(new SsaInsn.Visitor() {
+            /** {@inheritDoc} */
+            public void visitMoveInsn (NormalSsaInsn insn) {
+                addToUses(insn);
+            }
+            /** {@inheritDoc} */
+            public void visitPhiInsn (PhiInsn phi) {
+                addToUses(phi);
+            }
+            /** {@inheritDoc} */
+            public void visitNonMoveInsn (NormalSsaInsn insn) {
+                addToUses(insn);
+            }
+            /**
+             * Adds specified insn to the uses list for all of its sources.
+             * @param insn {@code non-null;} insn to process
+             */
+            private void addToUses(SsaInsn insn) {
+                RegisterSpecList rl = insn.getSources();
+                int sz = rl.size();
+
+                for (int i = 0; i < sz; i++) {
+                    useList[rl.get(i).getReg()].add(insn);
+                }
+            }
+        });
+
+        unmodifiableUseList = new List[registerCount];
+
+        for (int i = 0; i < registerCount; i++) {
+            unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
+        }
+    }
+
+    /**
+     * Updates the use list for a single change in source register.
+     *
+     * @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
+     */
+    /*package*/ void onSourceChanged(SsaInsn insn,
+            RegisterSpec oldSource, RegisterSpec newSource) {
+        if (useList == null) return;
+
+        if (oldSource != null) {
+            int reg = oldSource.getReg();
+            useList[reg].remove(insn);
+        }
+
+        int reg = newSource.getReg();
+        if (useList.length <= reg) {
+            useList = null;
+            return;
+        }
+        useList[reg].add(insn);
+    }
+
+    /**
+     * Updates the use list for a source list change.
+     *
+     * @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
+     */
+    /*package*/ void onSourcesChanged(SsaInsn insn,
+            RegisterSpecList oldSources) {
+        if (useList == null) return;
+
+        if (oldSources != null) {
+            removeFromUseList(insn, oldSources);
+        }
+
+        RegisterSpecList sources = insn.getSources();
+        int szNew = sources.size();
+
+        for (int i = 0; i < szNew; i++) {
+            int reg = sources.get(i).getReg();
+            useList[reg].add(insn);
+        }
+    }
+
+    /**
+     * 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 {@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++) {
+            if (!useList[oldSources.get(i).getReg()].remove(insn)) {
+                throw new RuntimeException("use not found");
+            }
+        }
+    }
+
+    /**
+     * Adds an insn to both the use and def lists. For use when adding
+     * a new insn to the method.
+     *
+     * @param insn {@code non-null;} insn to add
+     */
+    /*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 {@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;
+        }
+    }
+
+    /**
+     * 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
+     * applicable.
+     */
+    public void onInsnsChanged() {
+        // Definition list will need to be recomputed
+        definitionList = null;
+
+        // Use list will need to be recomputed
+        useList = null;
+        unmodifiableUseList = null;
+    }
+
+    /**
+     * Updates a single definition.
+     *
+     * @param insn {@code non-null;} insn who's result should be recorded as
+     * a definition
+     * @param oldResult {@code null-ok;} a previous result that should
+     * be no longer considered a definition by this insn
+     */
+    /*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();
+
+            if (definitionList[reg] != null) {
+                throw new RuntimeException("Duplicate add of insn");
+            } else {
+                definitionList[resultReg.getReg()] = insn;
+            }
+        }
+    }
+
+    /**
+     * Returns the list of all source uses (not results) for a register.
+     *
+     * @param reg register in question
+     * @return unmodifiable instruction list
+     */
+    public List<SsaInsn> getUseListForRegister(int reg) {
+
+        if (unmodifiableUseList == null) {
+            buildUseList();
+        }
+
+        return unmodifiableUseList[reg];
+    }
+
+    /**
+     * Returns a modifiable copy of the register use list.
+     *
+     * @return modifiable copy of the use-list, indexed by register
+     */
+    public ArrayList<SsaInsn>[] getUseListCopy() {
+        if (useList == null) {
+            buildUseList();
+        }
+
+        ArrayList<SsaInsn>[] useListCopy
+                = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]);
+
+        for (int i = 0; i < registerCount; i++) {
+            useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i]));
+        }
+
+        return useListCopy;
+    }
+
+    /**
+     * Checks to see if the given SSA reg is ever associated with a local
+     * local variable. Each SSA reg may be associated with at most one
+     * local var.
+     *
+     * @param spec {@code non-null;} ssa reg
+     * @return true if reg is ever associated with a local
+     */
+    public boolean isRegALocal(RegisterSpec spec) {
+        SsaInsn defn = getDefinitionForRegister(spec.getReg());
+
+        if (defn == null) {
+            // version 0 registers are never used as locals
+            return false;
+        }
+
+        // Does the definition have a local associated with it?
+        if (defn.getLocalAssignment() != null) return true;
+
+        // If not, is there a mark-local insn?
+        for (SsaInsn use : getUseListForRegister(spec.getReg())) {
+            Insn insn = use.getOriginalRopInsn();
+
+            if (insn != null
+                    && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Sets the new register count after renaming.
+     *
+     * @param newRegCount new register count
+     */
+    /*package*/ void setNewRegCount(int newRegCount) {
+        registerCount = newRegCount;
+        spareRegisterBase = registerCount;
+        onInsnsChanged();
+    }
+
+    /**
+     * Makes a new SSA register. For use after renaming has completed.
+     *
+     * @return {@code >=0;} new SSA register.
+     */
+    public int makeNewSsaReg() {
+        int reg = registerCount++;
+        spareRegisterBase = registerCount;
+        onInsnsChanged();
+        return reg;
+    }
+
+    /**
+     * Visits all insns in this method.
+     *
+     * @param visitor {@code non-null;} callback interface
+     */
+    public void forEachInsn(SsaInsn.Visitor visitor) {
+        for (SsaBasicBlock block : blocks) {
+            block.forEachInsn(visitor);
+        }
+    }
+
+    /**
+     * Visits each phi insn in this method
+     * @param v {@code non-null;} callback.
+     *
+     */
+    public void forEachPhiInsn(PhiInsn.Visitor v) {
+        for (SsaBasicBlock block : blocks) {
+            block.forEachPhiInsn(v);
+        }
+    }
+
+
+    /**
+     * 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 {@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.
+        Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
+
+        SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
+
+        if (rootBlock == null) {
+            // in the case there's no exit block
+            return;
+        }
+
+        stack.add(null);    // Start with null parent.
+        stack.add(rootBlock);
+
+        while (stack.size() > 0) {
+            SsaBasicBlock cur = stack.pop();
+            SsaBasicBlock parent = stack.pop();
+
+            if (!visited.get(cur.getIndex())) {
+                BitSet children
+                    = reverse ? cur.getPredecessors() : cur.getSuccessors();
+                for (int i = children.nextSetBit(0); i >= 0
+                        ; i = children.nextSetBit(i + 1)) {
+                    stack.add(cur);
+                    stack.add(blocks.get(i));
+                }
+                visited.set(cur.getIndex());
+                v.visitBlock(cur, parent);
+            }
+        }
+    }
+
+    /**
+     * Visits blocks in dom-tree order, starting at the current node.
+     * The {@code parent} parameter of the Visitor.visitBlock callback
+     * is currently always set to null.
+     *
+     * @param v {@code non-null;} callback interface
+     */
+    public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) {
+        BitSet visited = new BitSet(getBlocks().size());
+        Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
+
+        stack.add(getEntryBlock());
+
+        while (stack.size() > 0) {
+            SsaBasicBlock cur = stack.pop();
+            ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren();
+
+            if (!visited.get(cur.getIndex())) {
+                // We walk the tree this way for historical reasons...
+                for (int i = curDomChildren.size() - 1; i >= 0; i--) {
+                    SsaBasicBlock child = curDomChildren.get(i);
+                    stack.add(child);
+                }
+                visited.set(cur.getIndex());
+                v.visitBlock(cur, null);
+            }
+        }
+    }
+
+    /**
+     * Deletes all insns in the set from this method.
+     *
+     * @param deletedInsns {@code non-null;} insns to delete
+     */
+    public void deleteInsns(Set<SsaInsn> deletedInsns) {
+        for (SsaBasicBlock block : getBlocks()) {
+            ArrayList<SsaInsn> insns = block.getInsns();
+
+            for (int i = insns.size() - 1; i >= 0; i--) {
+                SsaInsn insn = insns.get(i);
+
+                if (deletedInsns.contains(insn)) {
+                    onInsnRemoved(insn);
+                    insns.remove(i);
+                }
+            }
+
+            // Check to see if we need to add a GOTO
+
+            int insnsSz = insns.size();
+            SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1);
+
+            if (block != getExitBlock() && (insnsSz == 0
+                    || lastInsn.getOriginalRopInsn() == null
+                    || lastInsn.getOriginalRopInsn().getOpcode()
+                        .getBranchingness() == Rop.BRANCH_NONE)) {
+                // We managed to eat a throwable insn
+
+                Insn gotoInsn = new PlainInsn(Rops.GOTO,
+                        SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
+                insns.add(SsaInsn.makeFromRop(gotoInsn, block));
+
+                // Remove secondary successors from this block
+                BitSet succs = block.getSuccessors();
+                for (int i = succs.nextSetBit(0); i >= 0;
+                         i = succs.nextSetBit(i + 1)) {
+                    if (i != block.getPrimarySuccessorIndex()) {
+                        block.removeSuccessor(i);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public void setBackMode() {
+        backMode = true;
+        useList = null;
+        definitionList = null;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/SsaRenamer.java b/dx/src/com/android/dx/ssa/SsaRenamer.java
new file mode 100644
index 0000000..58e4142
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SsaRenamer.java
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.LocalItem;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.type.Type;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * Complete transformation to SSA form by renaming all registers accessed.<p>
+ *
+ * See Appel algorithm 19.7<p>
+ *
+ * Unlike the original algorithm presented in Appel, this renamer converts
+ * to a new flat (versionless) register space. The "version 0" registers,
+ * which represent the initial state of the Rop registers and should never
+ * actually be meaningfully accessed in a legal program, are represented
+ * as the first N registers in the SSA namespace. Subsequent assignments
+ * are assigned new unique names. Note that the incoming Rop representation
+ * has a concept of register widths, where 64-bit values are stored into
+ * two adjoining Rop registers. This adjoining register representation is
+ * ignored in SSA form conversion and while in SSA form, each register can be e
+ * either 32 or 64 bits wide depending on use. The adjoining-register
+ * represention is re-created later when converting back to Rop form. <p>
+ *
+ * But, please note, the SSA Renamer's ignoring of the adjoining-register ROP
+ * representation means that unaligned accesses to 64-bit registers are not
+ * supported. For example, you cannot do a 32-bit operation on a portion of
+ * a 64-bit register. This will never be observed to happen when coming
+ * from Java code, of course.<p>
+ *
+ * The implementation here, rather than keeping a single register version
+ * stack for the entire method as the dom tree is walked, instead keeps
+ * a mapping table for the current block being processed. Once the
+ * current block has been processed, this mapping table is then copied
+ * and used as the initial state for child blocks.<p>
+ */
+public class SsaRenamer implements Runnable {
+    /** debug flag */
+    private static final boolean DEBUG = false;
+
+    /** method we're processing */
+    private final SsaMethod ssaMeth;
+
+    /** next available SSA register */
+    private int nextSsaReg;
+
+    /** the number of original rop registers */
+    private final int ropRegCount;
+
+    /** work only on registers above this value */
+    private int threshold;
+
+    /**
+     * indexed by block index; register version state for each block start.
+     * This list is updated by each dom parent for its children. The only
+     * sub-arrays that exist at any one time are the start states for blocks
+     * yet to be processed by a {@code BlockRenamer} instance.
+     */
+    private final RegisterSpec[][] startsForBlocks;
+
+    /** map of SSA register number to debug (local var names) or null of n/a */
+    private final ArrayList<LocalItem> ssaRegToLocalItems;
+
+    /**
+     * maps SSA registers back to the original rop number. Used for
+     * debug only.
+     */
+    private IntList ssaRegToRopReg;
+
+    /**
+     * Constructs an instance of the renamer
+     *
+     * @param ssaMeth {@code non-null;} un-renamed SSA method that will
+     * be renamed.
+     */
+    public SsaRenamer(SsaMethod ssaMeth) {
+        ropRegCount = ssaMeth.getRegCount();
+
+        this.ssaMeth = ssaMeth;
+
+        /*
+         * Reserve the first N registers in the SSA register space for
+         * "version 0" registers.
+         */
+        nextSsaReg = ropRegCount;
+        threshold = 0;
+        startsForBlocks = new RegisterSpec[ssaMeth.getBlocks().size()][];
+
+        ssaRegToLocalItems = new ArrayList<LocalItem>();
+
+        if (DEBUG) {
+            ssaRegToRopReg = new IntList(ropRegCount);
+        }
+
+        /*
+         * Appel 19.7
+         *
+         * Initialization:
+         *   for each variable a        // register i
+         *      Count[a] <- 0           // nextSsaReg, flattened
+         *      Stack[a] <- 0           // versionStack
+         *      push 0 onto Stack[a]
+         *
+         */
+
+        // top entry for the version stack is version 0
+        RegisterSpec[] initialRegMapping = new RegisterSpec[ropRegCount];
+        for (int i = 0; i < ropRegCount; i++) {
+            // everyone starts with a version 0 register
+            initialRegMapping[i] = RegisterSpec.make(i, Type.VOID);
+
+            if (DEBUG) {
+                ssaRegToRopReg.add(i);
+            }
+        }
+
+        // Initial state for entry block
+        startsForBlocks[ssaMeth.getEntryBlockIndex()] = initialRegMapping;
+    }
+
+    /**
+    * Constructs an instance of the renamer with threshold set
+    *
+    * @param ssaMeth {@code non-null;} un-renamed SSA method that will
+    * be renamed.
+    * @param thresh registers below this number are unchanged
+    */
+   public SsaRenamer(SsaMethod ssaMeth, int thresh) {
+       this(ssaMeth);
+       threshold = thresh;
+   }
+
+    /**
+     * Performs renaming transformation, modifying the method's instructions
+     * in-place.
+     */
+    public void run() {
+        // Rename each block in dom-tree DFS order.
+        ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
+            public void visitBlock (SsaBasicBlock block,
+                    SsaBasicBlock unused) {
+                new BlockRenamer(block).process();
+            }
+        });
+
+        ssaMeth.setNewRegCount(nextSsaReg);
+        ssaMeth.onInsnsChanged();
+
+        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.
+             */
+            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 + "["
+                        + versions[ropReg] + "]");
+                versions[ropReg]++;
+            }
+        }
+    }
+
+    /**
+     * 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];
+
+        System.arraycopy(orig, 0, copy, 0, orig.length);
+
+        return copy;
+    }
+
+    /**
+     * Gets a local variable item for a specified register.
+     *
+     * @param ssaReg register in SSA name space
+     * @return {@code null-ok;} Local variable name or null if none
+     */
+    private LocalItem getLocalForNewReg(int ssaReg) {
+        if (ssaReg < ssaRegToLocalItems.size()) {
+            return ssaRegToLocalItems.get(ssaReg);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Records a debug (local variable) name for a specified register.
+     *
+     * @param ssaReg non-null named register spec in SSA name space
+     */
+    private void setNameForSsaReg(RegisterSpec ssaReg) {
+        int reg = ssaReg.getReg();
+        LocalItem local = ssaReg.getLocalItem();
+
+        ssaRegToLocalItems.ensureCapacity(reg + 1);
+        while (ssaRegToLocalItems.size() <= reg) {
+            ssaRegToLocalItems.add(null);
+        }
+
+        ssaRegToLocalItems.set(reg, local);
+    }
+
+    /**
+     * Returns true if this SSA register is below the specified threshold.
+     * Used when most code is already in SSA form, and renaming is needed only
+     * for registers above a certain threshold.
+     *
+     * @param ssaReg the SSA register in question
+     * @return {@code true} if its register number is below the threshold
+     */
+    private boolean isBelowThresholdRegister(int ssaReg) {
+        return ssaReg < threshold;
+    }
+
+    /**
+     * Returns true if this SSA register is a "version 0"
+     * register. All version 0 registers are assigned the first N register
+     * numbers, where N is the count of original rop registers.
+     *
+     * @param ssaReg the SSA register in question
+     * @return true if it is a version 0 register.
+     */
+    private boolean isVersionZeroRegister(int ssaReg) {
+        return ssaReg < ropRegCount;
+    }
+
+    /**
+     * 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
+     */
+    private static boolean equalsHandlesNulls(Object a, Object b) {
+        return a == b ||  (a != null && a.equals(b));
+    }
+
+    /**
+     * Processes all insns in a block and renames their registers
+     * as appropriate.
+     */
+    private class BlockRenamer implements SsaInsn.Visitor{
+        /** {@code non-null;} block we're processing. */
+        private final SsaBasicBlock block;
+
+        /**
+         * {@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.
+         */
+        private final HashSet<SsaInsn> movesToKeep;
+
+        /**
+         * maps the set of insns to replace after renaming is finished
+         * on the block.
+         */
+        private final HashMap<SsaInsn, SsaInsn> insnsToReplace;
+
+        private final RenamingMapper mapper;
+
+        /**
+         * Constructs a block renamer instance. Call {@code process}
+         * to process.
+         *
+         * @param block {@code non-null;} block to process
+         */
+        BlockRenamer(final SsaBasicBlock block) {
+            this.block = block;
+            currentMapping = startsForBlocks[block.getIndex()];
+            movesToKeep = new HashSet<SsaInsn>();
+            insnsToReplace = new HashMap<SsaInsn, SsaInsn>();
+            mapper =  new RenamingMapper();
+
+            // We don't need our own start state anymore
+            startsForBlocks[block.getIndex()] = null;
+        }
+
+        /**
+         * Provides a register mapping between the old register space
+         * and the current renaming mapping. The mapping is updated
+         * as the current block's instructions are processed.
+         */
+        private class RenamingMapper extends RegisterMapper {
+            public RenamingMapper() {
+                // This space intentionally left blank.
+            }
+
+            /** {@inheritDoc} */
+            @Override
+            public int getNewRegisterCount() {
+                return nextSsaReg;
+            }
+
+            /** {@inheritDoc} */
+            @Override
+            public RegisterSpec map(RegisterSpec registerSpec) {
+                if (registerSpec == null) return null;
+
+                int reg = registerSpec.getReg();
+
+                // For debugging: assert that the mapped types are compatible.
+                if (DEBUG) {
+                    RegisterSpec newVersion = currentMapping[reg];
+                    if (newVersion.getBasicType() != Type.BT_VOID
+                            && registerSpec.getBasicFrameType()
+                                != newVersion.getBasicFrameType()) {
+
+                        throw new RuntimeException(
+                                "mapping registers of incompatible types! "
+                                + registerSpec
+                                + " " + currentMapping[reg]);
+                    }
+                }
+
+                return registerSpec.withReg(currentMapping[reg].getReg());
+            }
+        }
+
+        /**
+         * Renames all the variables in this block and inserts appriopriate
+         * phis in successor blocks.
+         */
+        public void process() {
+            /*
+             * From Appel:
+             *
+             * Rename(n) =
+             *   for each statement S in block n   // 'statement' in 'block'
+             */
+
+            block.forEachInsn(this);
+
+            updateSuccessorPhis();
+
+            // Delete all move insns in this block.
+            ArrayList<SsaInsn> insns = block.getInsns();
+            int szInsns = insns.size();
+
+            for (int i = szInsns - 1; i >= 0 ; i--) {
+                SsaInsn insn = insns.get(i);
+                SsaInsn replaceInsn;
+
+                replaceInsn = insnsToReplace.get(insn);
+
+                if (replaceInsn != null) {
+                    insns.set(i, replaceInsn);
+                } else if (insn.isNormalMoveInsn()
+                        && !movesToKeep.contains(insn)) {
+                    insns.remove(i);
+                }
+            }
+
+            // Store the start states for our dom children.
+            boolean first = true;
+            for (SsaBasicBlock child : block.getDomChildren()) {
+                if (child != block) {
+                    // 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.
+        }
+
+        /**
+         * Enforces a few contraints when a register mapping is added.
+         *
+         * <ol>
+         * <li> Ensures that all new SSA registers specs in the mapping
+         * table with the same register number are identical. In effect, once
+         * an SSA register spec has received or lost a local variable name,
+         * then every old-namespace register that maps to it should gain or
+         * lose its local variable name as well.
+         * <li> Records the local name associated with the
+         * register so that a register is never associated with more than one
+         * local.
+         * <li> ensures that only one SSA register
+         * at a time is considered to be associated with a local variable. When
+         * {@code currentMapping} is updated and the newly added element
+         * is named, strip that name from any other SSA registers.
+         * </ol>
+         *
+         * @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();
+            LocalItem ssaRegLocal = ssaReg.getLocalItem();
+
+            currentMapping[ropReg] = ssaReg;
+
+            /*
+             * Ensure all SSA register specs with the same reg are identical.
+             */
+            for (int i = currentMapping.length - 1; i >= 0; i--) {
+                RegisterSpec cur = currentMapping[i];
+
+                if (ssaRegNum == cur.getReg()) {
+                    currentMapping[i] = ssaReg;
+                }
+            }
+
+            // All further steps are for registers with local information.
+            if (ssaRegLocal == null) {
+                return;
+            }
+
+            // Record that this SSA reg has been associated with a local.
+            setNameForSsaReg(ssaReg);
+
+            // Ensure that no other SSA regs are associated with this local.
+            for (int i = currentMapping.length - 1; i >= 0; i--) {
+                RegisterSpec cur = currentMapping[i];
+
+                if (ssaRegNum != cur.getReg()
+                        && ssaRegLocal.equals(cur.getLocalItem())) {
+                    currentMapping[i] = cur.withLocalItem(null);
+                }
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * Phi insns have their result registers renamed.
+         */
+        public void visitPhiInsn(PhiInsn phi) {
+            /* don't process sources for phi's */
+            processResultReg(phi);
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * Move insns are treated as a simple mapping operation, and
+         * will later be removed unless they represent a local variable
+         * assignment. If they represent a local variable assignement, they
+         * are preserved.
+         */
+        public void visitMoveInsn(NormalSsaInsn insn) {
+            /*
+             * 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.
+             */
+
+            RegisterSpec ropResult = insn.getResult();
+            int ropResultReg = ropResult.getReg();
+            int ropSourceReg = insn.getSources().get(0).getReg();
+
+            insn.mapSourceRegisters(mapper);
+            int ssaSourceReg = insn.getSources().get(0).getReg();
+
+            LocalItem sourceLocal
+                = currentMapping[ropSourceReg].getLocalItem();
+            LocalItem resultLocal = ropResult.getLocalItem();
+
+            /*
+             * A move from a register that's currently associated with a local
+             * to one that will not be associated with a local does not need
+             * to be preserved, but the local association should remain.
+             * Hence, we inherit the sourceLocal where the resultLocal is null.
+             */
+
+            LocalItem newLocal
+                = (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?
+             */
+            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
+             * 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.
+             */
+            RegisterSpec ssaReg
+                    = RegisterSpec.makeLocalOptional(
+                        ssaSourceReg, ropResult.getType(), newLocal);
+
+            if (!Optimizer.getPreserveLocals() || (onlyOneAssociatedLocal
+                    && equalsHandlesNulls(newLocal, sourceLocal)) &&
+                    threshold == 0) {
+                /*
+                 * We don't have to keep this move to preserve local
+                 * information. Either the name is the same, or the result
+                 * register spec is unnamed.
+                 */
+
+                addMapping(ropResultReg, ssaReg);
+            } else if (onlyOneAssociatedLocal && sourceLocal == null &&
+                    threshold == 0) {
+                /*
+                 * The register was previously unnamed. This means that a
+                 * local starts after it's first assignment in SSA form
+                 */
+
+                RegisterSpecList ssaSources = RegisterSpecList.make(
+                        RegisterSpec.make(ssaReg.getReg(),
+                                ssaReg.getType(), newLocal));
+
+                SsaInsn newInsn
+                        = SsaInsn.makeFromRop(
+                            new PlainInsn(Rops.opMarkLocal(ssaReg),
+                            SourcePosition.NO_INFO, null, ssaSources),block);
+
+                insnsToReplace.put(insn, newInsn);
+
+                // Just map as above.
+                addMapping(ropResultReg, ssaReg);
+            } else {
+                /*
+                 * Do not copy-propogate, since the two registers have
+                 * two different local-variable names.
+                 */
+                processResultReg(insn);
+
+                movesToKeep.add(insn);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * All insns that are not move or phi insns have their source registers
+         * mapped ot the current mapping. Their result registers are then
+         * renamed to a new SSA register which is then added to the current
+         * register mapping.
+         */
+        public void visitNonMoveInsn(NormalSsaInsn insn) {
+            /* for each use of some variable X in S */
+            insn.mapSourceRegisters(mapper);
+
+            processResultReg(insn);
+        }
+
+        /**
+         * Renames the result register of this insn and updates the
+         * current register mapping. Does nothing if this insn has no result.
+         * Applied to all non-move insns.
+         *
+         * @param insn insn to process.
+         */
+        void processResultReg(SsaInsn insn) {
+            RegisterSpec ropResult = insn.getResult();
+
+            if (ropResult == null) {
+                return;
+            }
+
+            int ropReg = ropResult.getReg();
+            if (isBelowThresholdRegister(ropReg)) {
+                return;
+            }
+
+            insn.changeResultReg(nextSsaReg);
+            addMapping(ropReg, insn.getResult());
+
+            if (DEBUG) {
+                ssaRegToRopReg.add(ropReg);
+            }
+
+            nextSsaReg++;
+        }
+
+        /**
+         * Updates the phi insns in successor blocks with operands based
+         * on the current mapping of the rop register the phis represent.
+         */
+        private void updateSuccessorPhis() {
+            PhiInsn.Visitor visitor = new PhiInsn.Visitor() {
+                public void visitPhiInsn (PhiInsn insn) {
+                    int ropReg;
+
+                    ropReg = insn.getRopResultReg();
+                    if (isBelowThresholdRegister(ropReg)) {
+                        return;
+                    }
+
+                    /*
+                     * 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];
+                    if (!isVersionZeroRegister(stackTop.getReg())) {
+                        insn.addPhiOperand(stackTop, block);
+                    }
+                }
+            };
+
+            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
new file mode 100644
index 0000000..3d891c9
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/_tests/_DomFront.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa._tests;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the class {@code com.android.dx.ssa.DomFront}.
+ */
+public class _DomFront
+        extends TestCase {
+
+    public void test_one() {
+
+    }
+
+
+}
diff --git a/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java b/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java
new file mode 100644
index 0000000..6416e84
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.rop.code.CstInsn;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.ssa.NormalSsaInsn;
+import com.android.dx.ssa.BasicRegisterMapper;
+import com.android.dx.ssa.RegisterMapper;
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.util.IntSet;
+import com.android.dx.util.BitIntSet;
+
+import java.util.BitSet;
+import java.util.ArrayList;
+
+/**
+ * Allocates registers via a naive n^2 register allocator.
+ * This allocator does not try to co-locate local variables or deal
+ * intelligently with different size register uses.
+ */
+public class FirstFitAllocator extends RegisterAllocator {
+    /**
+     * If true, allocator places parameters at the top of the frame
+     * in calling-convention order.
+     */
+    private static final boolean PRESLOT_PARAMS = true;
+
+    /** indexed by old reg; the set of old regs we've mapped */
+    private final BitSet mapped;
+
+    /** {@inheritDoc} */
+    public FirstFitAllocator(
+            final SsaMethod ssaMeth, final InterferenceGraph interference) {
+        super(ssaMeth, interference);
+
+        mapped = new BitSet(ssaMeth.getRegCount());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean wantsParamsMovedHigh() {
+        return PRESLOT_PARAMS;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RegisterMapper allocateRegisters() {
+        int oldRegCount = ssaMeth.getRegCount();
+
+        BasicRegisterMapper mapper
+                = new BasicRegisterMapper(oldRegCount);
+
+        int nextNewRegister = 0;
+
+        if (PRESLOT_PARAMS) {
+            /*
+             * Reserve space for the params at the bottom of the register
+             * space. Later, we'll flip the params to the end of the register
+             * space.
+             */
+
+            nextNewRegister = ssaMeth.getParamWidth();
+        }
+
+        for (int i = 0; i < oldRegCount; i++) {
+            if (mapped.get(i)) {
+                // we already got this one
+                continue;
+            }
+
+            int maxCategory = getCategoryForSsaReg(i);
+            IntSet current = new BitIntSet(oldRegCount);
+
+            interference.mergeInterferenceSet(i, current);
+
+            boolean isPreslotted = false;
+            int newReg = 0;
+
+            if (PRESLOT_PARAMS && isDefinitionMoveParam(i)) {
+                // Any move-param definition must be a NormalSsaInsn
+                NormalSsaInsn defInsn = (NormalSsaInsn)
+                       ssaMeth.getDefinitionForRegister(i);
+
+                newReg = paramNumberFromMoveParam(defInsn);
+
+                mapper.addMapping(i, newReg, maxCategory);
+                isPreslotted = true;
+            } else {
+                mapper.addMapping(i, nextNewRegister, maxCategory);
+                newReg = nextNewRegister;
+            }
+
+            for (int j = i + 1; j < oldRegCount; j++) {
+                if (mapped.get(j) || isDefinitionMoveParam(j)) {
+                    continue;
+                }
+
+                /*
+                 * If reg j doesn't interfere with the current mapping.
+                 * Also, if this is a pre-slotted method parameter, we
+                 * can't use more than the original param width.
+                 */
+                if (!current.has(j)
+                        && !(isPreslotted
+                            && (maxCategory < getCategoryForSsaReg(j)))) {
+
+                    interference.mergeInterferenceSet(j, current);
+
+                    maxCategory = Math.max(maxCategory,
+                            getCategoryForSsaReg(j));
+
+                    mapper.addMapping(j, newReg, maxCategory);
+                    mapped.set(j);
+                }
+            }
+
+            mapped.set(i);
+            if (!isPreslotted) {
+                nextNewRegister += maxCategory;
+            }
+        }
+
+        return mapper;
+    }
+
+    /**
+     * Returns the parameter number that this move-param insn refers to
+     * @param ndefInsn a move-param insn (otherwise, exceptions will be thrown)
+     * @return parameter number (offset in the total parameter width)
+     */
+    private int paramNumberFromMoveParam(NormalSsaInsn ndefInsn) {
+        CstInsn origInsn = (CstInsn) ndefInsn.getOriginalRopInsn();
+
+        return ((CstInteger) origInsn.getConstant()).getValue();
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java b/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java
new file mode 100644
index 0000000..9ef95a7
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java
@@ -0,0 +1,1139 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.rop.code.*;
+import com.android.dx.rop.cst.CstInteger;
+import com.android.dx.ssa.InterferenceRegisterMapper;
+import com.android.dx.ssa.RegisterMapper;
+import com.android.dx.ssa.SsaInsn;
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.ssa.NormalSsaInsn;
+import com.android.dx.ssa.PhiInsn;
+import com.android.dx.ssa.Optimizer;
+import com.android.dx.ssa.SsaBasicBlock;
+import com.android.dx.util.IntSet;
+import com.android.dx.util.IntIterator;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Allocates registers in a first-fit fashion, with the bottom reserved for
+ * method parameters and all SSAregisters representing the same local variable
+ * 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 */
+    private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables;
+
+    /** list of move-result-pesudo instructions seen in this method */
+    private final ArrayList<NormalSsaInsn> moveResultPseudoInsns;
+
+    /** list of invoke-range instructions seen in this method */
+    private final ArrayList<NormalSsaInsn> invokeRangeInsns;
+
+    /** list of phi instructions seen in this method */
+    private final ArrayList<PhiInsn> phiInsns;
+
+    /** indexed by SSA reg; the set of SSA regs we've mapped */
+    private final BitSet ssaRegsMapped;
+
+    /** Register mapper which will be our result */
+    private final InterferenceRegisterMapper mapper;
+
+    /** 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 */
+    private final BitSet reservedRopRegs;
+
+    /** 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 */
+    private final boolean minimizeRegisters;
+
+    /**
+     * Constructs instance.
+     *
+     * @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(
+            SsaMethod ssaMeth, InterferenceGraph interference,
+            boolean minimizeRegisters) {
+        super(ssaMeth, interference);
+
+        ssaRegsMapped = new BitSet(ssaMeth.getRegCount());
+
+        mapper = new InterferenceRegisterMapper(
+                interference, ssaMeth.getRegCount());
+
+        this.minimizeRegisters = minimizeRegisters;
+
+        /*
+         * Reserve space for the params at the bottom of the register
+         * space. Later, we'll flip the params to the end of the register
+         * space.
+         */
+
+        paramRangeEnd = ssaMeth.getParamWidth();
+
+        reservedRopRegs = new BitSet(paramRangeEnd * 2);
+        reservedRopRegs.set(0, paramRangeEnd);
+        usedRopRegs = new BitSet(paramRangeEnd * 2);
+        localVariables = new TreeMap<LocalItem, ArrayList<RegisterSpec>>();
+        moveResultPseudoInsns = new ArrayList<NormalSsaInsn>();
+        invokeRangeInsns = new ArrayList<NormalSsaInsn>();
+        phiInsns = new ArrayList<PhiInsn>();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean wantsParamsMovedHigh() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RegisterMapper allocateRegisters() {
+
+        analyzeInstructions();
+
+        if (DEBUG) {
+            printLocalVars();
+        }
+
+        if (DEBUG) System.out.println("--->Mapping local-associated params");
+        handleLocalAssociatedParams();
+
+        if (DEBUG) System.out.println("--->Mapping other params");
+        handleUnassociatedParameters();
+
+        if (DEBUG) System.out.println("--->Mapping invoke-range");
+        handleInvokeRangeInsns();
+
+        if (DEBUG) {
+            System.out.println("--->Mapping local-associated non-params");
+        }
+        handleLocalAssociatedOther();
+
+        if (DEBUG) System.out.println("--->Mapping check-cast results");
+        handleCheckCastResults();
+
+        if (DEBUG) System.out.println("--->Mapping phis");
+        handlePhiInsns();
+
+        if (DEBUG) System.out.println("--->Mapping others");
+        handleNormalUnassociated();
+
+        return mapper;
+    }
+
+    /**
+     * Dumps local variable table to stdout for debugging.
+     */
+    private void printLocalVars() {
+        System.out.println("Printing local vars");
+        for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e :
+                localVariables.entrySet()) {
+            StringBuilder regs = new StringBuilder();
+
+            regs.append('{');
+            regs.append(' ');
+            for (RegisterSpec reg : e.getValue()) {
+                regs.append('v');
+                regs.append(reg.getReg());
+                regs.append(' ');
+            }
+            regs.append('}');
+            System.out.printf("Local: %s Registers: %s\n", e.getKey(), regs);
+        }
+    }
+
+    /**
+     * Maps all local-associated parameters to rop registers.
+     */
+    private void handleLocalAssociatedParams() {
+        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++) {
+                RegisterSpec ssaSpec = ssaRegs.get(i);
+                int ssaReg = ssaSpec.getReg();
+
+                paramIndex = getParameterIndexForReg(ssaReg);
+
+                if (paramIndex >= 0) {
+                    paramCategory = ssaSpec.getCategory();
+                    addMapping(ssaSpec, paramIndex);
+                    break;
+                }
+            }
+
+            if (paramIndex < 0) {
+                // This local wasn't a parameter.
+                continue;
+            }
+
+            // 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.
+     * {@code -1} is returned for non-parameter registers.
+     *
+     * @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.
+        if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
+            CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
+            return  ((CstInteger) origInsn.getConstant()).getValue();
+        }
+
+        return -1;
+    }
+
+    /**
+     * 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()) {
+            int ropReg = paramRangeEnd;
+
+            boolean done = false;
+            do {
+                int maxCategory = 1;
+
+                // Compute max category for remaining unmapped registers.
+                int sz = specs.size();
+                for (int i = 0; i < sz; i++) {
+                    RegisterSpec ssaSpec = specs.get(i);
+                    int category = ssaSpec.getCategory();
+                    if (!ssaRegsMapped.get(ssaSpec.getReg())
+                            && category > maxCategory) {
+                        maxCategory = category;
+                    }
+                }
+
+                ropReg = findRopRegForLocal(ropReg, maxCategory);
+                if (canMapRegs(specs, ropReg)) {
+                    done = tryMapRegs(specs, ropReg, maxCategory, true);
+                }
+
+                // Increment for next call to findRopRegForLocal.
+                ropReg++;
+            } while (!done);
+        }
+    }
+
+    /**
+     * Tries to map a list of SSA registers into the a rop reg, marking
+     * used rop space as reserved. SSA registers that don't fit are left
+     * 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) {
+            if (ssaRegsMapped.get(spec.getReg())) {
+                continue;
+            }
+
+            boolean succeeded;
+            succeeded = tryMapReg(spec, ropReg, maxAllowedCategory);
+            remaining = !succeeded || remaining;
+            if (succeeded && markReserved) {
+                // This only needs to be called once really with
+                // the widest category used, but <shrug>
+                markReserved(ropReg, spec.getCategory());
+            }
+        }
+        return !remaining;
+    }
+
+    /**
+     * Tries to map an SSA register to a rop register.
+     *
+     * @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) {
+        if (ssaSpec.getCategory() <= maxAllowedCategory
+                && !ssaRegsMapped.get(ssaSpec.getReg())
+                && canMapReg(ssaSpec, ropReg)) {
+            addMapping(ssaSpec, ropReg);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Marks a range of rop registers as "reserved for a local variable."
+     *
+     * @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.
+     *
+     * @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++) {
+            if (reservedRopRegs.get(i)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 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.
+        return startReg == 0 && !ssaMeth.isStatic();
+    }
+
+    /**
+     * Finds a range of unreserved rop registers.
+     *
+     * @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) {
+        int reg;
+
+        reg = reservedRopRegs.nextClearBit(startReg);
+
+        while (true) {
+            int i = 1;
+
+            while (i < width && !reservedRopRegs.get(reg + i)) {
+                i++;
+            }
+
+            if (i == width) {
+                return reg;
+            }
+
+            reg = reservedRopRegs.nextClearBit(reg + i);
+        }
+    }
+
+    /**
+     * Finds a range of rop regs that can be used for local variables.
+     * If {@code MIX_LOCALS_AND_OTHER} is {@code false}, this means any
+     * rop register that has not yet been used.
+     *
+     * @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) {
+        int reg;
+
+        reg = usedRopRegs.nextClearBit(startReg);
+
+        while (true) {
+            int i = 1;
+
+            while (i < width && !usedRopRegs.get(reg + i)) {
+                i++;
+            }
+
+            if (i == width) {
+                return reg;
+            }
+
+            reg = usedRopRegs.nextClearBit(reg + i);
+        }
+    }
+
+    /**
+     * Maps any parameter that isn't local-associated, which can happen
+     * in the case where there is no java debug info.
+     */
+    private void handleUnassociatedParameters() {
+        int szSsaRegs = ssaMeth.getRegCount();
+
+        for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
+            if (ssaRegsMapped.get(ssaReg)) {
+                // We already did this one above
+                continue;
+            }
+
+            int paramIndex = getParameterIndexForReg(ssaReg);
+
+            RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
+            if (paramIndex >= 0) {
+                addMapping(ssaSpec, paramIndex);
+            }
+        }
+    }
+
+    /**
+     * Handles all insns that want a register range for their sources.
+     */
+    private void handleInvokeRangeInsns() {
+        for (NormalSsaInsn insn : invokeRangeInsns) {
+            adjustAndMapSourceRangeRange(insn);
+        }
+    }
+
+    /**
+     * Handles check cast results to reuse the same source register.
+     * Inserts a move if it can't map the same register to both and the
+     * check cast is not caught.
+     */
+    private void handleCheckCastResults() {
+        for (NormalSsaInsn insn : moveResultPseudoInsns) {
+            RegisterSpec moveRegSpec = insn.getResult();
+            int moveReg = moveRegSpec.getReg();
+            BitSet predBlocks = insn.getBlock().getPredecessors();
+
+            // Expect one predecessor block only
+            if (predBlocks.cardinality() != 1) {
+                continue;
+            }
+
+            SsaBasicBlock predBlock =
+                    ssaMeth.getBlocks().get(predBlocks.nextSetBit(0));
+            ArrayList<SsaInsn> insnList = predBlock.getInsns();
+
+            /**
+             * If the predecessor block has a check-cast, it will be the last
+             * instruction
+             */
+            SsaInsn checkCastInsn = insnList.get(insnList.size() - 1);
+            if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) {
+                continue;
+            }
+
+            RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0);
+            int checkReg = checkRegSpec.getReg();
+
+            /**
+             * See if either register is already mapped. Most likely the move
+             * result will be mapped already since the cast result is stored
+             * in a local variable.
+             */
+            int category = checkRegSpec.getCategory();
+            boolean moveMapped = ssaRegsMapped.get(moveReg);
+            boolean checkMapped = ssaRegsMapped.get(checkReg);
+            if (moveMapped & !checkMapped) {
+                int moveRopReg = mapper.oldToNew(moveReg);
+                checkMapped = tryMapReg(checkRegSpec, moveRopReg, category);
+            }
+            if (checkMapped & !moveMapped) {
+                int checkRopReg = mapper.oldToNew(checkReg);
+                moveMapped = tryMapReg(moveRegSpec, checkRopReg, category);
+            }
+
+            // Map any unmapped registers to anything available
+            if (!moveMapped || !checkMapped) {
+                int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
+                ArrayList<RegisterSpec> ssaRegs =
+                    new ArrayList<RegisterSpec>(2);
+                ssaRegs.add(moveRegSpec);
+                ssaRegs.add(checkRegSpec);
+
+                while (!tryMapRegs(ssaRegs, ropReg, category, false)) {
+                    ropReg = findNextUnreservedRopReg(ropReg + 1, category);
+                }
+            }
+
+            /*
+             * If source and result have a different mapping, insert a move so
+             * they can have the same mapping. Don't do this if the check cast
+             * is caught, since it will overwrite a potentially live value.
+             */
+            boolean hasExceptionHandlers =
+                checkCastInsn.getOriginalRopInsn().getCatches().size() != 0;
+            int moveRopReg = mapper.oldToNew(moveReg);
+            int checkRopReg = mapper.oldToNew(checkReg);
+            if (moveRopReg != checkRopReg && !hasExceptionHandlers) {
+                ((NormalSsaInsn) checkCastInsn).changeOneSource(0,
+                        insertMoveBefore(checkCastInsn, checkRegSpec));
+                addMapping(checkCastInsn.getSources().get(0), moveRopReg);
+            }
+        }
+    }
+
+    /**
+    * Handles all phi instructions, trying to map them to a common register.
+    */
+    private void handlePhiInsns() {
+        for (PhiInsn insn : phiInsns) {
+            processPhiInsn(insn);
+        }
+    }
+
+    /**
+     * 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
+                continue;
+            }
+
+            RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
+
+            if (ssaSpec == null) continue;
+
+            int category = ssaSpec.getCategory();
+            // Find a rop reg that does not interfere
+            int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
+            while (!canMapReg(ssaSpec, ropReg)) {
+                ropReg = findNextUnreservedRopReg(ropReg + 1, category);
+            }
+
+            addMapping(ssaSpec, ropReg);
+        }
+    }
+
+    /**
+     * Checks to see if a list of SSA registers can all be mapped into
+     * the same rop reg. Ignores registers that have already been mapped,
+     * and checks the interference graph and ensures the range does not
+     * cross the parameter range.
+     *
+     * @param specs {@code non-null;} SSA registers to check
+     * @param ropReg {@code >=0;} rop register to check mapping to
+     * @return {@code true} if all unmapped registers can be mapped
+     */
+    private boolean canMapRegs(ArrayList<RegisterSpec> specs, int ropReg) {
+        for (RegisterSpec spec : specs) {
+            if (ssaRegsMapped.get(spec.getReg())) continue;
+            if (!canMapReg(spec, ropReg)) return false;
+        }
+        return true;
+    }
+
+    /**
+     * 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 {@code non-null;} SSA spec
+     * @param ropReg prosepctive new-namespace reg
+     * @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}
+     * 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 {@code true} in the case noted above
+     */
+    private boolean spansParamRange(int ssaReg, int category) {
+        return ((ssaReg < paramRangeEnd)
+                && ((ssaReg + category) > paramRangeEnd));
+    }
+
+    /**
+     * Analyze each instruction and find out all the local variable assignments
+     * and move-result-pseudo/invoke-range instrucitons.
+     */
+    private void analyzeInstructions() {
+        ssaMeth.forEachInsn(new SsaInsn.Visitor() {
+            /** {@inheritDoc} */
+            public void visitMoveInsn(NormalSsaInsn insn) {
+                processInsn(insn);
+            }
+
+            /** {@inheritDoc} */
+            public void visitPhiInsn(PhiInsn insn) {
+                processInsn(insn);
+            }
+
+            /** {@inheritDoc} */
+            public void visitNonMoveInsn(NormalSsaInsn insn) {
+                processInsn(insn);
+            }
+
+            /**
+             * This method collects three types of instructions:
+             *
+             * 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;
+                assignment = insn.getLocalAssignment();
+
+                if (assignment != null) {
+                    LocalItem local = assignment.getLocalItem();
+
+                    ArrayList<RegisterSpec> regList
+                        = localVariables.get(local);
+
+                    if (regList == null) {
+                        regList = new ArrayList<RegisterSpec>();
+                        localVariables.put(local, regList);
+                    }
+
+                    regList.add(assignment);
+                }
+
+                if (insn instanceof NormalSsaInsn) {
+                    if (insn.getOpcode().getOpcode() ==
+                            RegOps.MOVE_RESULT_PSEUDO) {
+                        moveResultPseudoInsns.add((NormalSsaInsn) insn);
+                    } else if (Optimizer.getAdvice().requiresSourcesInOrder(
+                            insn.getOriginalRopInsn().getOpcode(),
+                            insn.getSources())) {
+                        invokeRangeInsns.add((NormalSsaInsn) insn);
+                    }
+                } else if (insn instanceof PhiInsn) {
+                    phiInsns.add((PhiInsn) insn);
+                }
+
+            }
+        });
+    }
+
+    /**
+     * Adds a mapping from an SSA register to a rop register.
+     * {@link #canMapReg} should have already been called.
+     *
+     * @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.
+        if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) {
+            throw new RuntimeException(
+                    "attempt to add invalid register mapping");
+        }
+
+        if (DEBUG) {
+            System.out.printf("Add mapping s%d -> v%d c:%d\n",
+                    ssaSpec.getReg(), ropReg, ssaSpec.getCategory());
+        }
+
+        int category = ssaSpec.getCategory();
+        mapper.addMapping(ssaSpec.getReg(), ropReg, category);
+        ssaRegsMapped.set(ssaReg);
+        usedRopRegs.set(ropReg, ropReg + category);
+    }
+
+
+    /**
+     * Maps the source registers of the specified instruction such that they
+     * will fall in a contiguous range in rop form. Moves are inserted as
+     * necessary to allow the range to be allocated.
+     *
+     * @param insn {@code non-null;} insn whos sources to process
+     */
+    private void adjustAndMapSourceRangeRange(NormalSsaInsn 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();
+            int category = source.getCategory();
+            int curRopReg = nextRopReg;
+            nextRopReg += category;
+
+            if (ssaRegsMapped.get(sourceReg)) {
+                continue;
+            }
+
+            LocalItem localItem = getLocalItemForReg(sourceReg);
+            addMapping(source, curRopReg);
+
+            if (localItem != null) {
+                markReserved(curRopReg, category);
+                ArrayList<RegisterSpec> similarRegisters
+                        = localVariables.get(localItem);
+
+                int szSimilar = similarRegisters.size();
+
+                /*
+                 * 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();
+
+                    // Don't map anything that's also a source.
+                    if (-1 != sources.indexOfRegister(similarReg)) {
+                        continue;
+                    }
+
+                    // Registers left unmapped will get handled later.
+                    tryMapReg(similarSpec, curRopReg, category);
+                }
+            }
+        }
+    }
+
+    /**
+     * 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,
+     * just find a new contiguous range that doesn't interfere.
+     *
+     * @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();
+        int szSources = sources.size();
+        // the category for each source index
+        int categoriesForIndex[] = new int[szSources];
+        int rangeLength = 0;
+
+        // Compute rangeLength and categoriesForIndex
+        for (int i = 0; i < szSources; i++) {
+            int category = sources.get(i).getCategory();
+            categoriesForIndex[i] = category;
+            rangeLength += categoriesForIndex[i];
+        }
+
+        // the highest score of fits tried so far
+        int maxScore = Integer.MIN_VALUE;
+        // the high scoring range's start
+        int resultRangeStart = -1;
+        // by source index: set of sources needing moves in high scoring plan
+        BitSet resultMovesRequired = null;
+
+        /*
+         * First, go through each source that's already been mapped. Try
+         * to center the range around the rop register this source is mapped
+         * to.
+         */
+        int rangeStartOffset = 0;
+        for (int i = 0; i < szSources; i++) {
+            int ssaCenterReg = sources.get(i).getReg();
+
+            if (i != 0) {
+                rangeStartOffset -= categoriesForIndex[i - 1];
+            }
+            if (!ssaRegsMapped.get(ssaCenterReg)) {
+                continue;
+            }
+
+            int rangeStart = mapper.oldToNew(ssaCenterReg) + rangeStartOffset;
+
+            if (rangeStart < 0 || spansParamRange(rangeStart, rangeLength)) {
+                continue;
+            }
+
+            BitSet curMovesRequired = new BitSet(szSources);
+
+            int fitWidth
+                    = fitPlanForRange(rangeStart, insn, categoriesForIndex,
+                    curMovesRequired);
+
+            if (fitWidth < 0) {
+                continue;
+            }
+
+            int score = fitWidth - curMovesRequired.cardinality();
+
+            if (score > maxScore) {
+                maxScore = score;
+                resultRangeStart = rangeStart;
+                resultMovesRequired = curMovesRequired;
+            }
+
+            if (fitWidth == rangeLength) {
+                // We can't do any better than this, so stop here
+                break;
+            }
+        }
+
+        /*
+         * If we were unable to find a plan for a fit centered around
+         * an already-mapped source, just try to find a range of
+         * registers we can move the range into.
+         */
+
+        if (resultRangeStart == -1) {
+            resultMovesRequired = new BitSet(szSources);
+
+            resultRangeStart = findAnyFittingRange(insn, rangeLength,
+                    categoriesForIndex, resultMovesRequired);
+        }
+
+        /*
+         * 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)));
+        }
+
+        return resultRangeStart;
+    }
+
+    /**
+     * Finds an unreserved range that will fit the sources of the
+     * specified instruction. Does not bother trying to center the range
+     * around an already-mapped source register;
+     *
+     * @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
+     */
+    private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength,
+            int[] categoriesForIndex, BitSet outMovesRequired) {
+        int rangeStart = paramRangeEnd;
+        while (true) {
+            rangeStart = findNextUnreservedRopReg(rangeStart, rangeLength);
+            int fitWidth
+                    = fitPlanForRange(rangeStart, insn,
+                    categoriesForIndex, outMovesRequired);
+
+            if (fitWidth >= 0) {
+                break;
+            }
+            rangeStart++;
+            outMovesRequired.clear();
+        }
+        return rangeStart;
+    }
+
+    /**
+     * Attempts to build a plan for fitting a range of sources into rop
+     * registers.
+     *
+     * @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
+     * @return the width of the fit that that does not involve added moves or
+     * {@code -1} if "no fit possible"
+     */
+    private int fitPlanForRange(int ropReg, NormalSsaInsn insn,
+            int[] categoriesForIndex, BitSet outMovesRequired) {
+        RegisterSpecList sources = insn.getSources();
+        int szSources = sources.size();
+        int fitWidth = 0;
+        IntSet liveOut = insn.getBlock().getLiveOutRegs();
+        RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut);
+
+        // An SSA reg may only be mapped into a range once.
+        BitSet seen = new BitSet(ssaMeth.getRegCount());
+
+        for (int i = 0; i < szSources ; i++) {
+            RegisterSpec ssaSpec = sources.get(i);
+            int ssaReg = ssaSpec.getReg();
+            int category = categoriesForIndex[i];
+
+            if (i != 0) {
+                ropReg += categoriesForIndex[i-1];
+            }
+
+            if (ssaRegsMapped.get(ssaReg)
+                    && mapper.oldToNew(ssaReg) == ropReg) {
+                // This is a register that is already mapped appropriately.
+                fitWidth += category;
+            } else if (rangeContainsReserved(ropReg, category)) {
+                fitWidth = -1;
+                break;
+            } else if (!ssaRegsMapped.get(ssaReg)
+                    && canMapReg(ssaSpec, ropReg)
+                    && !seen.get(ssaReg)) {
+                // This is a register that can be mapped appropriately.
+                fitWidth += category;
+            } else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category)
+                    && !mapper.areAnyPinned(sources, ropReg, category)) {
+                /*
+                 * 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)
+                 */
+
+                outMovesRequired.set(i);
+            } else {
+                fitWidth = -1;
+                break;
+            }
+
+            seen.set(ssaReg);
+        }
+        return fitWidth;
+    }
+
+    /**
+     * Converts a bit set of SSA registers into a RegisterSpecList containing
+     * the definition specs of all the registers.
+     *
+     * @param ssaSet {@code non-null;} set of SSA registers
+     * @return list of RegisterSpecs as noted above
+     */
+    RegisterSpecList ssaSetToSpecs(IntSet ssaSet) {
+        RegisterSpecList result = new RegisterSpecList(ssaSet.elements());
+
+        IntIterator iter = ssaSet.iterator();
+
+        int i = 0;
+        while (iter.hasNext()) {
+            result.set(i++, getDefinitionSpecForSsaReg(iter.next()));
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets a local item associated with an ssa register, if one exists.
+     *
+     * @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()) {
+                if (spec.getReg() == ssaReg) {
+                    return entry.getKey();
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Attempts to map the sources and result of a phi to a common register.
+     * Will try existing mappings first, from most to least common. If none
+     * of the registers have mappings yet, a new mapping is created.
+     */
+    private void processPhiInsn(PhiInsn insn) {
+        RegisterSpec result = insn.getResult();
+        int resultReg = result.getReg();
+        int category = result.getCategory();
+
+        RegisterSpecList sources = insn.getSources();
+        int sourcesSize = sources.size();
+
+        // List of phi sources / result that need mapping
+        ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>();
+
+        // Track how many times a particular mapping is found
+        Multiset mapSet = new Multiset(sourcesSize + 1);
+
+        /*
+         * If the result of the phi has an existing mapping, get it.
+         * Otherwise, add it to the list of regs that need mapping.
+         */
+        if (ssaRegsMapped.get(resultReg)) {
+            mapSet.add(mapper.oldToNew(resultReg));
+        } else {
+            ssaRegs.add(result);
+        }
+
+        for (int i = 0; i < sourcesSize; i++) {
+            RegisterSpec source = sources.get(i);
+            SsaInsn def = ssaMeth.getDefinitionForRegister(source.getReg());
+            RegisterSpec sourceDef = def.getResult();
+            int sourceReg = sourceDef.getReg();
+
+            /*
+             * If a source of the phi has an existing mapping, get it.
+             * Otherwise, add it to the list of regs that need mapping.
+             */
+            if (ssaRegsMapped.get(sourceReg)) {
+                mapSet.add(mapper.oldToNew(sourceReg));
+            } else {
+                ssaRegs.add(sourceDef);
+            }
+        }
+
+        // Try all existing mappings, with the most common ones first
+        for (int i = 0; i < mapSet.getSize(); i++) {
+            int maxReg = mapSet.getAndRemoveHighestCount();
+            tryMapRegs(ssaRegs, maxReg, category, false);
+        }
+
+        // Map any remaining unmapped regs with whatever fits
+        int mapReg = findNextUnreservedRopReg(paramRangeEnd, category);
+        while (!tryMapRegs(ssaRegs, mapReg, category, false)) {
+            mapReg = findNextUnreservedRopReg(mapReg + 1, category);
+        }
+    }
+
+    // A set that tracks how often elements are added to it.
+    private static class Multiset {
+        private final int[] reg;
+        private final int[] count;
+        private int size;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param maxSize the maximum distinct elements the set may have
+         */
+        public Multiset(int maxSize) {
+            reg = new int[maxSize];
+            count = new int[maxSize];
+            size = 0;
+        }
+
+        /**
+         * Adds an element to the set.
+         *
+         * @param element element to add
+         */
+        public void add(int element) {
+            for (int i = 0; i < size; i++) {
+                if (reg[i] == element) {
+                    count[i]++;
+                    return;
+                }
+            }
+
+            reg[size] = element;
+            count[size] = 1;
+            size++;
+        }
+
+        /**
+         * Searches the set for the element that has been added the most.
+         * In the case of a tie, the element that was added first is returned.
+         * Then, it clears the count on that element. The size of the set
+         * remains unchanged.
+         *
+         * @return element with the highest count
+         */
+        public int getAndRemoveHighestCount() {
+            int maxIndex = -1;
+            int maxReg = -1;
+            int maxCount = 0;
+
+            for (int i = 0; i < size; i++) {
+                if (maxCount < count[i]) {
+                    maxIndex = i;
+                    maxReg = reg[i];
+                    maxCount = count[i];
+                }
+            }
+
+            count[maxIndex] = 0;
+            return maxReg;
+        }
+
+        /**
+         * Gets the number of distinct elements in the set.
+         *
+         * @return size of the set
+         */
+        public int getSize() {
+            return size;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
new file mode 100644
index 0000000..515b04f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.CstInsn;
+import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.InsnList;
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.SwitchInsn;
+import com.android.dx.util.IntList;
+
+import java.util.BitSet;
+
+/**
+ * Searches for basic blocks that all have the same successor and insns
+ * but different predecessors. These blocks are then combined into a single
+ * block and the now-unused blocks are deleted. These identical blocks
+ * frequently are created when catch blocks are edge-split.
+ */
+public class IdenticalBlockCombiner {
+    private final RopMethod ropMethod;
+    private final BasicBlockList blocks;
+    private final BasicBlockList newBlocks;
+
+    /**
+     * Constructs instance. Call {@code process()} to run.
+     *
+     * @param rm {@code non-null;} instance to process
+     */
+    public IdenticalBlockCombiner(RopMethod rm) {
+        ropMethod = rm;
+        blocks = ropMethod.getBlocks();
+        newBlocks = blocks.getMutableCopy();
+    }
+
+    /**
+     * 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 {@code non-null;} new method that has been processed
+     */
+    public RopMethod process() {
+        int szBlocks = blocks.size();
+        // indexed by label
+        BitSet toDelete = new BitSet(blocks.getMaxLabel());
+
+        // For each non-deleted block...
+        for (int bindex = 0; bindex < szBlocks; bindex++) {
+            BasicBlock b = blocks.get(bindex);
+
+            if (toDelete.get(b.getLabel())) {
+                // doomed block
+                continue;
+            }
+
+            IntList preds = ropMethod.labelToPredecessors(b.getLabel());
+
+            // ...look at all of it's predecessors that have only one succ...
+            int szPreds = preds.size();
+            for (int i = 0; i < szPreds; i++) {
+                int iLabel = preds.get(i);
+
+                BasicBlock iBlock = blocks.labelToBlock(iLabel);
+
+                if (toDelete.get(iLabel)
+                        || iBlock.getSuccessors().size() > 1
+                        || iBlock.getFirstInsn().getOpcode().getOpcode() ==
+                            RegOps.MOVE_RESULT) {
+                    continue;
+                }
+
+                IntList toCombine = new IntList();
+
+                // ...and see if they can be combined with any other preds...
+                for (int j = i + 1; j < szPreds; j++) {
+                    int jLabel = preds.get(j);
+                    BasicBlock jBlock = blocks.labelToBlock(jLabel);
+
+                    if (jBlock.getSuccessors().size() == 1
+                            && compareInsns(iBlock, jBlock)) {
+
+                        toCombine.add(jLabel);
+                        toDelete.set(jLabel);
+                    }
+                }
+
+                combineBlocks(iLabel, toCombine);
+            }
+        }
+
+        for (int i = szBlocks - 1; i >= 0; i--) {
+            if (toDelete.get(newBlocks.get(i).getLabel())) {
+                newBlocks.set(i, null);
+            }
+        }
+
+        newBlocks.shrinkToFit();
+        newBlocks.setImmutable();
+
+        return new RopMethod(newBlocks, ropMethod.getFirstLabel());
+    }
+
+    /**
+     * 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());
+    }
+
+    /**
+     * Combines blocks proven identical into one alpha block, re-writing
+     * all of the successor links that point to the beta blocks to point
+     * to the alpha block instead.
+     *
+     * @param alphaLabel block that will replace all the beta block
+     * @param betaLabels label list of blocks to combine
+     */
+    private void combineBlocks(int alphaLabel, IntList betaLabels) {
+        int szBetas = betaLabels.size();
+
+        for (int i = 0; i < szBetas; i++) {
+            int betaLabel = betaLabels.get(i);
+            BasicBlock bb = blocks.labelToBlock(betaLabel);
+            IntList preds = ropMethod.labelToPredecessors(bb.getLabel());
+            int szPreds = preds.size();
+
+            for (int j = 0; j < szPreds; j++) {
+                BasicBlock predBlock = newBlocks.labelToBlock(preds.get(j));
+                replaceSucc(predBlock, betaLabel, alphaLabel);
+            }
+        }
+    }
+
+    /**
+     * Replaces one of a block's successors with a different label. Constructs
+     * 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;
+        }
+
+        newSuccessors.setImmutable();
+
+        BasicBlock newBB = new BasicBlock(block.getLabel(),
+                block.getInsns(), newSuccessors, newPrimarySuccessor);
+
+        newBlocks.set(newBlocks.indexOfLabel(block.getLabel()), newBB);
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/back/InterferenceGraph.java b/dx/src/com/android/dx/ssa/back/InterferenceGraph.java
new file mode 100644
index 0000000..e6cde62
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/InterferenceGraph.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.ssa.SsaBasicBlock;
+import com.android.dx.ssa.SsaInsn;
+import com.android.dx.ssa.PhiInsn;
+import com.android.dx.ssa.SetFactory;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.util.IntSet;
+import com.android.dx.util.BitIntSet;
+import com.android.dx.util.ListIntSet;
+
+import java.util.BitSet;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * A register interference graph
+ */
+public class InterferenceGraph {
+    /**
+     * {@code non-null;} interference graph, indexed by register in
+     * both dimensions
+     */
+    private final ArrayList<IntSet> interference;
+
+    /**
+     * Creates a new graph.
+     *
+     * @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);
+
+        for (int i = 0; i < countRegs; i++) {
+            interference.add(SetFactory.makeInterferenceSet(countRegs));
+        }
+    }
+
+    /**
+     * Adds a register pair to the interference/liveness graph. Parameter
+     * order is insignificant.
+     *
+     * @param regV one register index
+     * @param regW another register index
+     */
+    public void add(int regV, int regW) {
+        ensureCapacity(Math.max(regV, regW) + 1);
+
+        interference.get(regV).add(regW);
+        interference.get(regW).add(regV);
+    }
+
+    /**
+     * Dumps interference graph to stdout for debugging.
+     */
+    public void dumpToStdout() {
+        int oldRegCount = interference.size();
+
+        for (int i = 0; i < oldRegCount; i++) {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append("Reg " + i + ":" + interference.get(i).toString());
+
+            System.out.println(sb.toString());
+        }
+    }
+
+    /**
+     * Merges the interference set for a register into a given bit set
+     *
+     * @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()) {
+            set.merge(interference.get(reg));
+        }
+    }
+
+    /**
+     * Ensures that the interference graph is appropriately sized.
+     *
+     * @param size requested minumum size
+     */
+    private void ensureCapacity(int size) {
+        int countRegs = interference.size();
+
+        interference.ensureCapacity(size);
+
+        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
new file mode 100644
index 0000000..a293e6f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.ssa.SsaBasicBlock;
+import com.android.dx.ssa.SsaInsn;
+import com.android.dx.ssa.PhiInsn;
+import com.android.dx.rop.code.RegisterSpec;
+
+import java.util.BitSet;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * From Appel "Modern Compiler Implementation in Java" algorithm 19.17
+ * Calculate the live ranges for register {@code reg}.<p>
+ *
+ * v = regV <p>
+ * s = insn <p>
+ * M = visitedBlocks <p>
+ */
+public class LivenessAnalyzer {
+    /**
+     * {@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;
+
+    /**
+     * {@code non-null;} set of blocks remaing to visit as "live out as block"
+     */
+    private final BitSet liveOutBlocks;
+
+    /**
+     * {@code >=0;} SSA register currently being analyzed.
+     * "v" in the original Appel algorithm.
+     */
+    private final int regV;
+
+    /** method to process */
+    private final SsaMethod ssaMeth;
+
+    /** interference graph being updated */
+    private final InterferenceGraph interference;
+
+    /** block "n" in Appel 19.17 */
+    private SsaBasicBlock blockN;
+
+    /** index of statement {@code s} in {@code blockN} */
+    private int statementIndex;
+
+    /** the next function to call */
+    private NextFunction nextFunction;
+
+    /** 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} instances and
+     * returning an interference graph.
+     *
+     * @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++) {
+            new LivenessAnalyzer(ssaMeth, i, interference).run();
+        }
+
+        coInterferePhis(ssaMeth, interference);
+
+        return interference;
+    }
+
+    /**
+     * Makes liveness analyzer instance for specific register.
+     *
+     * @param ssaMeth {@code non-null;} method to process
+     * @param reg register whose liveness to analyze
+     * @param interference {@code non-null;} indexed by SSA reg in
+     * both dimensions; graph to update
+     *
+     */
+    private LivenessAnalyzer(SsaMethod ssaMeth, int reg,
+            InterferenceGraph interference) {
+        int blocksSz = ssaMeth.getBlocks().size();
+
+        this.ssaMeth = ssaMeth;
+        this.regV = reg;
+        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.
+     */
+    private void handleTailRecursion() {
+        while (nextFunction != NextFunction.DONE) {
+            switch (nextFunction) {
+                case LIVE_IN_AT_STATEMENT:
+                    nextFunction = NextFunction.DONE;
+                    liveInAtStatement();
+                    break;
+
+                case LIVE_OUT_AT_STATEMENT:
+                    nextFunction = NextFunction.DONE;
+                    liveOutAtStatement();
+                    break;
+
+                case LIVE_OUT_AT_BLOCK:
+                    nextFunction = NextFunction.DONE;
+                    liveOutAtBlock();
+                    break;
+
+                default:
+            }
+        }
+    }
+
+    /**
+     * From Appel algorithm 19.17.
+     */
+    public void run() {
+        List<SsaInsn> useList = ssaMeth.getUseListForRegister(regV);
+
+        for (SsaInsn insn : useList) {
+            nextFunction = NextFunction.DONE;
+
+            if (insn instanceof PhiInsn) {
+                // If s is a phi-function with V as it's ith argument.
+                PhiInsn phi = (PhiInsn) insn;
+
+                for (SsaBasicBlock pred :
+                         phi.predBlocksForReg(regV, ssaMeth)) {
+                    blockN = pred;
+
+                    nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
+                    handleTailRecursion();
+                }
+            } else {
+                blockN = insn.getBlock();
+                statementIndex = blockN.getInsns().indexOf(insn);
+
+                if (statementIndex < 0) {
+                    throw new RuntimeException(
+                            "insn not found in it's own block");
+                }
+
+                nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
+                handleTailRecursion();
+            }
+        }
+
+        int nextLiveOutBlock;
+        while ((nextLiveOutBlock = liveOutBlocks.nextSetBit(0)) >= 0) {
+            blockN = ssaMeth.getBlocks().get(nextLiveOutBlock);
+            liveOutBlocks.clear(nextLiveOutBlock);
+            nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
+            handleTailRecursion();
+        }
+    }
+
+    /**
+     * "v is live-out at n."
+     */
+    private void liveOutAtBlock() {
+        if (! visitedBlocks.get(blockN.getIndex())) {
+            visitedBlocks.set(blockN.getIndex());
+
+            blockN.addLiveOut(regV);
+
+            ArrayList<SsaInsn> insns;
+
+            insns = blockN.getInsns();
+
+            // Live out at last statement in blockN
+            statementIndex = insns.size() - 1;
+            nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
+        }
+    }
+
+    /**
+     * "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
+            blockN.addLiveIn(regV);
+
+            BitSet preds = blockN.getPredecessors();
+
+            liveOutBlocks.or(preds);
+        } else {
+            // Let s' be the statement preceeding s
+            statementIndex -= 1;
+            nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
+        }
+    }
+
+    /**
+     * "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) {
+                interference.add(regV, rs.getReg());
+            }
+            nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
+        }
+    }
+
+    /**
+     * Ensures that all the phi result registers for all the phis in the
+     * same basic block interfere with each other. This is needed since
+     * the dead code remover has allowed through "dead-end phis" whose
+     * results are not used except as local assignments. Without this step,
+     * a the result of a dead-end phi might be assigned the same register
+     * as the result of another phi, and the phi removal move scheduler may
+     * generate moves that over-write the live result.
+     *
+     * @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()) {
+            List<SsaInsn> phis = b.getPhiInsns();
+
+            int szPhis = phis.size();
+
+            for (int i = 0; i < szPhis; i++) {
+                for (int j = 0; j < szPhis; j++) {
+                    if (i == j) {
+                        continue;
+                    }
+
+                    interference.add(phis.get(i).getResult().getReg(),
+                        phis.get(j).getResult().getReg());
+                }
+            }
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
new file mode 100644
index 0000000..0205c11
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.ssa.BasicRegisterMapper;
+import com.android.dx.ssa.RegisterMapper;
+import com.android.dx.ssa.SsaMethod;
+
+import java.util.BitSet;
+import java.util.ArrayList;
+
+/**
+ * A register allocator that maps SSA register n to Rop register 2*n,
+ * essentially preserving the original mapping and remaining agnostic
+ * about normal or wide categories. Used for debugging.
+ */
+public class NullRegisterAllocator extends RegisterAllocator {
+    /** {@inheritDoc} */
+    public NullRegisterAllocator(SsaMethod ssaMeth,
+            InterferenceGraph interference) {
+        super(ssaMeth, interference);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean wantsParamsMovedHigh() {
+        // We're not smart enough for this.
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public RegisterMapper allocateRegisters() {
+        int oldRegCount = ssaMeth.getRegCount();
+
+        BasicRegisterMapper mapper = new BasicRegisterMapper(oldRegCount);
+
+        for (int i = 0; i < oldRegCount; i++) {
+            mapper.addMapping(i, i*2, 2);
+        }
+
+        return mapper;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
new file mode 100644
index 0000000..1f9f70f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.PlainInsn;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.rop.code.SourcePosition;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.ssa.NormalSsaInsn;
+import com.android.dx.ssa.RegisterMapper;
+import com.android.dx.ssa.SsaInsn;
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.ssa.SsaBasicBlock;
+import com.android.dx.util.IntSet;
+import com.android.dx.util.IntIterator;
+
+import java.util.BitSet;
+import java.util.ArrayList;
+
+/**
+ * Base class of all register allocators.
+ */
+public abstract class RegisterAllocator {
+    /** method being processed */
+    protected final SsaMethod ssaMeth;
+
+    /** interference graph, indexed by register in both dimensions */
+    protected final InterferenceGraph interference;
+
+    /**
+     * 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(SsaMethod ssaMeth,
+            InterferenceGraph interference) {
+        this.ssaMeth = ssaMeth;
+        this.interference = interference;
+    }
+
+    /**
+     * Indicates whether the method params were allocated at the bottom
+     * of the namespace, and thus should be moved up to the top of the
+     * namespace after phi removal.
+     *
+     * @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}
+     */
+    public abstract RegisterMapper allocateRegisters();
+
+    /**
+     * Returns the category (width) of the definition site of the register.
+     * Returns {@code 1} for undefined registers.
+     *
+     * @param reg register
+     * @return {@code 1..2}
+     */
+    protected final int getCategoryForSsaReg(int reg) {
+        SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
+
+        if (definition == null) {
+            // an undefined reg
+            return 1;
+        } else {
+            return definition.getResult().getCategory();
+        }
+    }
+
+    /**
+     * Returns the RegisterSpec of the definition of the 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)
+     */
+    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).
+     *
+     * @param reg register in question
+     * @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;
+
+            return ndefInsn.getOpcode().getOpcode() == RegOps.MOVE_PARAM;
+        }
+
+        return false;
+    }
+
+    /**
+     * Inserts a move instruction for a specified SSA register before a
+     * specified instruction, creating a new SSA register and adjusting the
+     * interference graph in the process. The insn currently must be the
+     * last insn in a block.
+     *
+     * @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) {
+            throw new IllegalArgumentException (
+                    "specified insn is not in this block");
+        }
+
+        if (insnIndex != insns.size() - 1) {
+            /*
+             * Presently, the interference updater only works when
+             * adding before the last insn, and the last insn must have no
+             * result
+             */
+            throw new IllegalArgumentException(
+                    "Adding move here not supported:" + insn.toHuman());
+        }
+
+        /*
+         * Get new register and make new move instruction.
+         */
+
+        // The new result must not have an associated local variable.
+        RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(),
+                reg.getTypeBearer());
+
+        SsaInsn toAdd = SsaInsn.makeFromRop(
+                new PlainInsn(Rops.opMove(newRegSpec.getType()),
+                        SourcePosition.NO_INFO, newRegSpec,
+                        RegisterSpecList.make(reg)), block);
+
+        insns.add(insnIndex, toAdd);
+
+        int newReg = newRegSpec.getReg();
+
+        /*
+         * Adjust interference graph based on what's live out of the current
+         * block and what's used by the final instruction.
+         */
+
+        IntSet liveOut = block.getLiveOutRegs();
+        IntIterator liveOutIter = liveOut.iterator();
+
+        while (liveOutIter.hasNext()) {
+            interference.add(newReg, liveOutIter.next());
+        }
+
+        // Everything that's a source in the last insn interferes.
+        RegisterSpecList sources = insn.getSources();
+        int szSources = sources.size();
+
+        for (int i = 0; i < szSources; i++) {
+            interference.add(newReg, sources.get(i).getReg());
+        }
+
+        ssaMeth.onInsnsChanged();
+
+        return newRegSpec;
+    }
+}
diff --git a/dx/src/com/android/dx/ssa/back/SsaToRop.java b/dx/src/com/android/dx/ssa/back/SsaToRop.java
new file mode 100644
index 0000000..0e30250
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/back/SsaToRop.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa.back;
+
+import com.android.dx.rop.code.BasicBlock;
+import com.android.dx.rop.code.BasicBlockList;
+import com.android.dx.rop.code.InsnList;
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RegisterSpecList;
+import com.android.dx.rop.code.Rop;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.rop.code.Rops;
+import com.android.dx.ssa.BasicRegisterMapper;
+import com.android.dx.ssa.PhiInsn;
+import com.android.dx.ssa.RegisterMapper;
+import com.android.dx.ssa.SsaBasicBlock;
+import com.android.dx.ssa.SsaInsn;
+import com.android.dx.ssa.SsaMethod;
+import com.android.dx.util.Hex;
+import com.android.dx.util.IntList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Comparator;
+
+/**
+ * Converts a method in SSA form to ROP form.
+ */
+public class SsaToRop {
+    /** local debug flag */
+    private static final boolean DEBUG = false;
+
+    /** {@code non-null;} method to process */
+    private final SsaMethod ssaMeth;
+
+    /**
+     * {@code true} if the converter should attempt to minimize
+     * the rop-form register count
+     */
+    private final boolean minimizeRegisters;
+
+    /** {@code non-null;} interference graph */
+    private final InterferenceGraph interference;
+
+    /**
+     * Converts a method in SSA form to ROP form.
+     *
+     * @param ssaMeth {@code non-null;} method to process
+     * @param minimizeRegisters {@code true} if the converter should
+     * attempt to minimize the rop-form register count
+     * @return {@code non-null;} rop-form output
+     */
+    public static RopMethod convertToRopMethod(SsaMethod ssaMeth,
+            boolean minimizeRegisters) {
+        return new SsaToRop(ssaMeth, minimizeRegisters).convert();
+    }
+
+    /**
+     * 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() {
+        if (DEBUG) {
+            interference.dumpToStdout();
+        }
+
+        // These are other allocators for debugging or historical comparison:
+        // allocator = new NullRegisterAllocator(ssaMeth, interference);
+        // allocator = new FirstFitAllocator(ssaMeth, interference);
+
+        RegisterAllocator allocator =
+            new FirstFitLocalCombiningAllocator(ssaMeth, interference,
+                    minimizeRegisters);
+
+        RegisterMapper mapper = allocator.allocateRegisters();
+
+        if (DEBUG) {
+            System.out.println("Printing reg map");
+            System.out.println(((BasicRegisterMapper)mapper).toHuman());
+        }
+
+        ssaMeth.setBackMode();
+
+        ssaMeth.mapRegisters(mapper);
+
+        removePhiFunctions();
+
+        if (allocator.wantsParamsMovedHigh()) {
+            moveParametersToHighRegisters();
+        }
+
+        removeEmptyGotos();
+
+        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.
+     */
+    private void removeEmptyGotos() {
+        final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+
+        ssaMeth.forEachBlockDepthFirst(false, new SsaBasicBlock.Visitor() {
+            public void visitBlock(SsaBasicBlock b, SsaBasicBlock parent) {
+                ArrayList<SsaInsn> insns = b.getInsns();
+
+                if ((insns.size() == 1)
+                        && (insns.get(0).getOpcode() == Rops.GOTO)) {
+                    BitSet preds = (BitSet) b.getPredecessors().clone();
+
+                    for (int i = preds.nextSetBit(0); i >= 0;
+                            i = preds.nextSetBit(i + 1)) {
+                        SsaBasicBlock pb = blocks.get(i);
+                        pb.replaceSuccessor(b.getIndex(),
+                                b.getPrimarySuccessorIndex());
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * 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() {
+        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.
+         */
+        for (SsaBasicBlock block : blocks) {
+            block.scheduleMovesFromPhis();
+        }
+    }
+
+    /**
+     * Helper for {@link #removePhiFunctions}: PhiSuccessorUpdater for
+     * adding move instructions to predecessors based on phi insns.
+     */
+    private static class PhiVisitor implements PhiInsn.Visitor {
+        private final ArrayList<SsaBasicBlock> blocks;
+
+        public PhiVisitor(ArrayList<SsaBasicBlock> blocks) {
+            this.blocks = blocks;
+        }
+
+        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 = sources.get(i);
+                SsaBasicBlock predBlock = blocks.get(
+                        insn.predBlockIndexForSourcesIndex(i));
+
+                predBlock.addMoveToEnd(result, source);
+            }
+        }
+    }
+
+    /**
+     * Moves the parameter registers, which allocateRegisters() places
+     * at the bottom of the frame, up to the top of the frame to match
+     * Dalvik calling convention.
+     */
+    private void moveParametersToHighRegisters() {
+        int paramWidth = ssaMeth.getParamWidth();
+        BasicRegisterMapper mapper
+                = new BasicRegisterMapper(ssaMeth.getRegCount());
+        int regCount = ssaMeth.getRegCount();
+
+        for (int i = 0; i < regCount; i++) {
+            if (i < paramWidth) {
+                mapper.addMapping(i, regCount - paramWidth + i, 1);
+            } else {
+                mapper.addMapping(i, i - paramWidth, 1);
+            }
+        }
+
+        if (DEBUG) {
+            System.out.printf("Moving %d registers from 0 to %d\n",
+                    paramWidth, regCount - paramWidth);
+        }
+
+        ssaMeth.mapRegisters(mapper);
+    }
+
+    /**
+     * @return rop-form basic block list
+     */
+    private BasicBlockList convertBasicBlocks() {
+        ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+
+        // Exit block may be null.
+        SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
+
+        ssaMeth.computeReachability();
+        int ropBlockCount = ssaMeth.getCountReachableBlocks();
+
+        // Don't count the exit block, if it exists and is reachable.
+        ropBlockCount -= (exitBlock != null && exitBlock.isReachable()) ? 1 : 0;
+
+        BasicBlockList result = new BasicBlockList(ropBlockCount);
+
+        // Convert all the reachable blocks except the exit block.
+        int ropBlockIndex = 0;
+        for (SsaBasicBlock b : blocks) {
+            if (b.isReachable() && b != exitBlock) {
+                result.set(ropBlockIndex++, convertBasicBlock(b));
+            }
+        }
+
+        // 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");
+        }
+
+        return result;
+    }
+
+    /**
+     * 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 {@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();
+
+        if (opcode.getBranchingness() != Rop.BRANCH_RETURN
+                && opcode != Rops.THROW) {
+            throw new RuntimeException("Exit predecessor must end"
+                    + " in valid exit statement.");
+        }
+    }
+
+    /**
+     * Converts a single basic block to rop form.
+     *
+     * @param block SSA block to process
+     * @return {@code non-null;} ROP block
+     */
+    private BasicBlock convertBasicBlock(SsaBasicBlock block) {
+        IntList successorList = block.getRopLabelSuccessorList();
+        int primarySuccessorLabel = block.getPrimarySuccessorRopLabel();
+
+        // 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(
+                        "Exit predecessor must have no other successors"
+                                + Hex.u2(block.getRopLabel()));
+            } else {
+                successorList = IntList.EMPTY;
+                primarySuccessorLabel = -1;
+
+                verifyValidExitPredecessor(block);
+            }
+        }
+
+        successorList.setImmutable();
+
+        BasicBlock result = new BasicBlock(
+                block.getRopLabel(), convertInsns(block.getInsns()),
+                successorList,
+                primarySuccessorLabel);
+
+        return result;
+    }
+
+    /**
+     * 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) {
+        int insnCount = ssaInsns.size();
+        InsnList result = new InsnList(insnCount);
+
+        for (int i = 0; i < insnCount; i++) {
+            result.set(i, ssaInsns.get(i).toRopInsn());
+        }
+
+        result.setImmutable();
+
+        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
new file mode 100644
index 0000000..582a327
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/package-info.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+/**
+ * <h1>An introduction to SSA Form</h1>
+ *
+ * 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
+ * implement basic optimization steps and register allocation so that a
+ * reasonably efficient register machine representation can be produced from a
+ * stack machine source bytecode.<p>
+ *
+ * <h2>Key Classes</h2>
+ *
+ * <h3>Classes related to conversion and lifetime</h3>
+ * <ul>
+ * <li> {@link Optimizer} is a singleton class containing methods for
+ * converting, optimizing, and then back-converting Rop-form methods. It's the
+ * typical gateway into the rest of the package.
+ * <li> {@link SsaConverter} converts a Rop-form method to SSA form.
+ * <li> {@link SsaToRop} converts an SSA-form method back to Rop form.
+ * </ul>
+ *
+ * <h3>Classes related to method representation</h3>
+ * <ul>
+ * <li> A {@link SsaMethod} instance represents a method.
+ * <li> A {@link SsaBasicBlock} instance represents a basic block, whose
+ * semantics are quite similar to basic blocks in
+ * {@link com.android.dx.rop Rop form}.
+ * <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} form.
+ * </ul>
+ *
+ * <h3>Classes related to optimization steps</h3>
+ * <ul>
+ * <li> {@link MoveParamCombiner} is a simple step that ensures each method
+ * parameter is represented by at most one SSA register.
+ * <li> {@link SCCP} is a (partially implemented) sparse-conditional
+ * constant propogator.
+ * <li> {@link LiteralOpUpgrader} is a step that attempts to use constant
+ * information to convert math and comparison instructions into
+ * constant-bearing "literal ops" in cases where they can be represented in the
+ * output form (see {@link TranslationAdvice#hasConstantOperation}).
+ * <li> {@link ConstCollector} is a step that attempts to trade (modest)
+ * increased register space for decreased instruction count in cases where
+ * the same constant value is used repeatedly in a single method.
+ * <li> {@link DeadCodeRemover} is a dead code remover. This phase must
+ * always be run to remove unused phi instructions.
+ * </ul>
+ *
+ * <h2>SSA Lifetime</h2>
+ * The representation of a method in SSA form obeys slightly different
+ * constraints depending upon whether it is in the process of being converted
+ * into or out of SSA form.
+ *
+ * <h3>Conversion into SSA Form</h3>
+ *
+ * {@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 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.
+ * <li> A {@link LocalVariableExtractor} is run to produce a table of
+ * 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} 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}.
+ * <li> Finally, source and result registers for all instructions are {@link
+ * SsaRenamer renamed} such that each assignment is given a unique register
+ * number (register categories or widths, significant in Rop form, do not
+ * exist in SSA). Move instructions are eliminated except where necessary
+ * to preserve local variable assignments.
+ * </ol>
+ *
+ */
diff --git a/dx/src/com/android/dx/util/AnnotatedOutput.java b/dx/src/com/android/dx/util/AnnotatedOutput.java
new file mode 100644
index 0000000..7a9ea29
--- /dev/null
+++ b/dx/src/com/android/dx/util/AnnotatedOutput.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Interface for a binary output destination that may be augmented
+ * with textual annotations.
+ */
+public interface AnnotatedOutput
+        extends Output {
+    /**
+     * Get whether this instance will actually keep annotations.
+     *
+     * @return {@code true} iff annotations are being kept
+     */
+    public boolean annotates();
+
+    /**
+     * Get whether this instance is intended to keep verbose annotations.
+     * Annotators may use the result of calling this method to inform their
+     * annotation activity.
+     *
+     * @return {@code true} iff annotations are to be verbose
+     */
+    public boolean isVerbose();
+
+    /**
+     * Add an annotation for the subsequent output. Any previously
+     * open annotation will be closed by this call, and the new
+     * annotation marks all subsequent output until another annotation
+     * call.
+     *
+     * @param msg {@code non-null;} the annotation message
+     */
+    public void annotate(String msg);
+
+    /**
+     * Add an annotation for a specified amount of subsequent
+     * output. Any previously open annotation will be closed by this
+     * call. If there is already pending annotation from one or more
+     * previous calls to this method, the new call "consumes" output
+     * after all the output covered by the previous calls.
+     *
+     * @param amt {@code >= 0;} the amount of output for this annotation to
+     * cover
+     * @param msg {@code non-null;} the annotation message
+     */
+    public void annotate(int amt, String msg);
+
+    /**
+     * End the most recent annotation. Subsequent output will be unannotated,
+     * until the next call to {@link #annotate}.
+     */
+    public void endAnnotation();
+
+    /**
+     * Get the maximum width of the annotated output. This is advisory:
+     * Implementations of this interface are encouraged to deal with too-wide
+     * output, but annotaters are encouraged to attempt to avoid exceeding
+     * the indicated width.
+     *
+     * @return {@code >= 1;} the maximum width
+     */
+    public int getAnnotationWidth();
+}
diff --git a/dx/src/com/android/dx/util/BitIntSet.java b/dx/src/com/android/dx/util/BitIntSet.java
new file mode 100644
index 0000000..b364f0c
--- /dev/null
+++ b/dx/src/com/android/dx/util/BitIntSet.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.util.NoSuchElementException;
+
+/**
+ * A set of integers, represented by a bit set
+ */
+public class BitIntSet implements IntSet {
+
+    /** also accessed in ListIntSet */
+    int[] bits;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param max the maximum value of ints in this set.
+     */
+    public BitIntSet(int max) {
+        bits = Bits.makeBitSet(max);
+    }
+
+    /** @inheritDoc */
+    public void add(int value) {
+        ensureCapacity(value);
+        Bits.set(bits, value, true);
+    }
+
+    /**
+     * Ensures that the bit set has the capacity to represent the given value.
+     *
+     * @param value {@code >= 0;} value to represent
+     */
+    private void ensureCapacity(int value) {
+        if (value >= Bits.getMax(bits)) {
+            int[] newBits = Bits.makeBitSet(
+                    Math.max(value + 1, 2 * Bits.getMax(bits)));
+            System.arraycopy(bits, 0, newBits, 0, bits.length);
+            bits = newBits;
+        }
+    }
+
+    /** @inheritDoc */
+    public void remove(int value) {
+        if (value < Bits.getMax(bits)) {
+            Bits.set(bits, value, false);
+        }
+    }
+
+    /** @inheritDoc */
+    public boolean has(int value) {
+        return (value < Bits.getMax(bits)) && Bits.get(bits, value);
+    }
+
+    /** @inheritDoc */
+    public void merge(IntSet other) {
+        if (other instanceof BitIntSet) {
+            BitIntSet o = (BitIntSet) other;
+            ensureCapacity(Bits.getMax(o.bits) + 1);
+            Bits.or(bits, o.bits);
+        } else if (other instanceof ListIntSet) {
+            ListIntSet o = (ListIntSet) other;
+            int sz = o.ints.size();
+
+            if (sz > 0) {
+                ensureCapacity(o.ints.get(sz - 1));
+            }
+            for (int i = 0; i < o.ints.size(); i++) {
+                Bits.set(bits, o.ints.get(i), true);
+            }
+        } else {
+            IntIterator iter = other.iterator();
+            while (iter.hasNext()) {
+                add(iter.next());
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    public int elements() {
+        return Bits.bitCount(bits);
+    }
+
+    /** @inheritDoc */
+    public IntIterator iterator() {
+        return new IntIterator() {
+            private int idx = Bits.findFirst(bits, 0);
+
+            /** @inheritDoc */
+            public boolean hasNext() {
+                return idx >= 0;
+            }
+
+            /** @inheritDoc */
+            public int next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                int ret = idx;
+
+                idx = Bits.findFirst(bits, idx+1);
+
+                return ret;
+            }
+        };
+    }
+
+    /** @inheritDoc */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append('{');
+
+        boolean first = true;
+        for (int i = Bits.findFirst(bits, 0)
+                ; i >= 0
+                ; i = Bits.findFirst(bits, i + 1)) {
+            if (!first) {
+                sb.append(", ");
+            }
+            first = false;
+            sb.append(i);
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/util/Bits.java b/dx/src/com/android/dx/util/Bits.java
new file mode 100644
index 0000000..cbc0a5b
--- /dev/null
+++ b/dx/src/com/android/dx/util/Bits.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Utilities for treating {@code int[]}s as bit sets.
+ */
+public final class Bits {
+    /**
+     * This class is uninstantiable.
+     */
+    private Bits() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Constructs a bit set to contain bits up to the given index (exclusive).
+     *
+     * @param max {@code >= 0;} the maximum bit index (exclusive)
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static int[] makeBitSet(int max) {
+        int size = (max + 0x1f) >> 5;
+        return new int[size];
+    }
+
+    /**
+     * Gets the maximum index (exclusive) for the given bit set.
+     *
+     * @param bits {@code non-null;} bit set in question
+     * @return {@code >= 0;} the maximum index (exclusive) that may be set
+     */
+    public static int getMax(int[] bits) {
+        return bits.length * 0x20;
+    }
+
+    /**
+     * Gets the value of the bit at the given index.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     * @return the value of the indicated bit
+     */
+    public static boolean get(int[] bits, int idx) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+        return (bits[arrayIdx] & bit) != 0;
+    }
+
+    /**
+     * Sets the given bit to the given value.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     * @param value the new value for the bit
+     */
+    public static void set(int[] bits, int idx, boolean value) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+
+        if (value) {
+            bits[arrayIdx] |= bit;
+        } else {
+            bits[arrayIdx] &= ~bit;
+        }
+    }
+
+    /**
+     * Sets the given bit to {@code true}.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     */
+    public static void set(int[] bits, int idx) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+        bits[arrayIdx] |= bit;
+    }
+
+    /**
+     * Sets the given bit to {@code false}.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0, < getMax(set);} which bit
+     */
+    public static void clear(int[] bits, int idx) {
+        int arrayIdx = idx >> 5;
+        int bit = 1 << (idx & 0x1f);
+        bits[arrayIdx] &= ~bit;
+    }
+
+    /**
+     * Returns whether or not the given bit set is empty, that is, whether
+     * no bit is set to {@code true}.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @return {@code true} iff all bits are {@code false}
+     */
+    public static boolean isEmpty(int[] bits) {
+        int len = bits.length;
+
+        for (int i = 0; i < len; i++) {
+            if (bits[i] != 0) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Gets the number of bits set to {@code true} in the given bit set.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @return {@code >= 0;} the bit count (aka population count) of the set
+     */
+    public static int bitCount(int[] bits) {
+        int len = bits.length;
+        int count = 0;
+
+        for (int i = 0; i < len; i++) {
+            count += Integer.bitCount(bits[i]);
+        }
+
+        return count;
+    }
+
+    /**
+     * Returns whether any bits are set to {@code true} in the
+     * specified range.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param start {@code >= 0;} index of the first bit in the range (inclusive)
+     * @param end {@code >= 0;} index of the last bit in the range (exclusive)
+     * @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) {
+        int idx = findFirst(bits, start);
+        return (idx >= 0) && (idx < end);
+    }
+
+    /**
+     * Finds the lowest-order bit set at or after the given index in the
+     * given bit set.
+     *
+     * @param bits {@code non-null;} bit set to operate on
+     * @param idx {@code >= 0;} minimum index to return
+     * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+     * or {@code -1} if there is no appropriate bit index to return
+     */
+    public static int findFirst(int[] bits, int idx) {
+        int len = bits.length;
+        int minBit = idx & 0x1f;
+
+        for (int arrayIdx = idx >> 5; arrayIdx < len; arrayIdx++) {
+            int word = bits[arrayIdx];
+            if (word != 0) {
+                int bitIdx = findFirst(word, minBit);
+                if (bitIdx >= 0) {
+                    return (arrayIdx << 5) + bitIdx;
+                }
+            }
+            minBit = 0;
+        }
+
+        return -1;
+    }
+
+    /**
+     * Finds the lowest-order bit set at or after the given index in the
+     * given {@code int}.
+     *
+     * @param value the value in question
+     * @param idx 0..31 the minimum bit index to return
+     * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+     * 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.
+        int result = Integer.numberOfTrailingZeros(value);
+        return (result == 32) ? -1 : result;
+    }
+
+    /**
+     * 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 {@code non-null;} int array to be ored with other argument. This
+     * argument is modified.
+     * @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) {
+        for (int i = 0; i < b.length; i++) {
+            a[i] |= b[i];
+        }
+    }
+
+    public static String toHuman(int[] bits) {
+        StringBuilder sb = new StringBuilder();
+
+        boolean needsComma = false;
+
+        sb.append('{');
+
+        int bitsLength = 32 * bits.length;
+        for (int i = 0; i < bitsLength; i++) {
+            if (Bits.get(bits, i)) {
+                if (needsComma) {
+                    sb.append(',');
+                }
+                needsComma = true;
+                sb.append(i);
+            }
+        }
+        sb.append('}');
+
+        return sb.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/util/ByteArray.java b/dx/src/com/android/dx/util/ByteArray.java
new file mode 100644
index 0000000..21d0457
--- /dev/null
+++ b/dx/src/com/android/dx/util/ByteArray.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 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 {
+    /** {@code non-null;} underlying array */
+    private final byte[] bytes;
+
+    /** {@code >= 0}; start index of the slice (inclusive) */
+    private final int start;
+
+    /** {@code >= 0, <= bytes.length}; size computed as
+     * {@code end - start} (in the constructor) */
+    private final int size;
+
+    /**
+     * Constructs an instance.
+     *
+     * @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) {
+        if (bytes == null) {
+            throw new NullPointerException("bytes == null");
+        }
+
+        if (start < 0) {
+            throw new IllegalArgumentException("start < 0");
+        }
+
+        if (end < start) {
+            throw new IllegalArgumentException("end < start");
+        }
+
+        if (end > bytes.length) {
+            throw new IllegalArgumentException("end > bytes.length");
+        }
+
+        this.bytes = bytes;
+        this.start = start;
+        this.size = end - start;
+    }
+
+    /**
+     * Constructs an instance from an entire {@code byte[]}.
+     *
+     * @param bytes {@code non-null;} the underlying array
+     */
+    public ByteArray(byte[] bytes) {
+        this(bytes, 0, bytes.length);
+    }
+
+    /**
+     * Gets the size of the array, in bytes.
+     *
+     * @return {@code >= 0;} the size
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns a slice (that is, a sub-array) of this instance.
+     *
+     * @param start {@code >= 0;} start index of the slice (inclusive)
+     * @param end {@code >= start, <= size();} end index of
+     * the slice (exclusive)
+     * @return {@code non-null;} the slice
+     */
+    public ByteArray slice(int start, int end) {
+        checkOffsets(start, end);
+        return new ByteArray(bytes, start + this.start, end + this.start);
+    }
+
+    /**
+     * Returns the offset into the given array represented by the given
+     * offset into this instance.
+     *
+     * @param offset offset into this instance
+     * @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) {
+        if (bytes != this.bytes) {
+            throw new IllegalArgumentException("wrong bytes");
+        }
+
+        return start + offset;
+    }
+
+    /**
+     * Gets the {@code signed byte} value at a particular 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);
+        return getByte0(off);
+    }
+
+    /**
+     * Gets the {@code signed short} value at a particular 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);
+        return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
+    }
+
+    /**
+     * Gets the {@code signed int} value at a particular 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);
+        return (getByte0(off) << 24) |
+            (getUnsignedByte0(off + 1) << 16) |
+            (getUnsignedByte0(off + 2) << 8) |
+            getUnsignedByte0(off + 3);
+    }
+
+    /**
+     * Gets the {@code signed long} value at a particular 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);
+        int part1 = (getByte0(off) << 24) |
+            (getUnsignedByte0(off + 1) << 16) |
+            (getUnsignedByte0(off + 2) << 8) |
+            getUnsignedByte0(off + 3);
+        int part2 = (getByte0(off + 4) << 24) |
+            (getUnsignedByte0(off + 5) << 16) |
+            (getUnsignedByte0(off + 6) << 8) |
+            getUnsignedByte0(off + 7);
+
+        return (part2 & 0xffffffffL) | ((long) part1) << 32;
+    }
+
+    /**
+     * Gets the {@code unsigned byte} value at a particular 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);
+        return getUnsignedByte0(off);
+    }
+
+    /**
+     * Gets the {@code unsigned short} value at a particular 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);
+        return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
+    }
+
+    /**
+     * Copies the contents of this instance into the given raw
+     * {@code byte[]} at the given offset. The given array must be
+     * large enough.
+     *
+     * @param out {@code non-null;} array to hold the output
+     * @param offset {@code non-null;} index into {@code out} for the first
+     * byte of output
+     */
+    public void getBytes(byte[] out, int offset) {
+        if ((out.length - offset) < size) {
+            throw new IndexOutOfBoundsException("(out.length - offset) < " +
+                                                "size()");
+        }
+
+        System.arraycopy(bytes, start, out, offset, size);
+    }
+
+    /**
+     * Checks a range of offsets for validity, throwing if invalid.
+     *
+     * @param s start offset (inclusive)
+     * @param e end offset (exclusive)
+     */
+    private void checkOffsets(int s, int e) {
+        if ((s < 0) || (e < s) || (e > size)) {
+            throw new IllegalArgumentException("bad range: " + s + ".." + e +
+                                               "; actual size " + size);
+        }
+    }
+
+    /**
+     * Gets the {@code signed byte} value at the given offset,
+     * without doing any argument checking.
+     *
+     * @param off offset to fetch
+     * @return byte at that offset
+     */
+    private int getByte0(int off) {
+        return bytes[start + off];
+    }
+
+    /**
+     * Gets the {@code unsigned byte} value at the given offset,
+     * without doing any argument checking.
+     *
+     * @param off offset to fetch
+     * @return byte at that offset
+     */
+    private int getUnsignedByte0(int off) {
+        return bytes[start + off] & 0xff;
+    }
+
+    /**
+     * 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 {@code non-null;} an appropriately-constructed
+     * {@code DataInputStream} instance
+     */
+    public MyDataInputStream makeDataInputStream() {
+        return new MyDataInputStream(makeInputStream());
+    }
+
+    /**
+     * 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 {@code non-null;} an appropriately-constructed
+     * {@code InputStream} instancex
+     */
+    public MyInputStream makeInputStream() {
+        return new MyInputStream();
+    }
+
+    /**
+     * Helper interface that allows one to get the cursor (of a stream).
+     */
+    public interface GetCursor {
+        /**
+         * Gets the current cursor.
+         *
+         * @return {@code 0..size();} the cursor
+         */
+        public int getCursor();
+    }
+
+    /**
+     * Helper class for {@link #makeInputStream}, which implements the
+     * stream functionality.
+     */
+    public class MyInputStream extends InputStream {
+        /** 0..size; the cursor */
+        private int cursor;
+
+        /** 0..size; the mark */
+        private int mark;
+
+        public MyInputStream() {
+            cursor = 0;
+            mark = 0;
+        }
+
+        public int read() throws IOException {
+            if (cursor >= size) {
+                return -1;
+            }
+
+            int result = getUnsignedByte0(cursor);
+            cursor++;
+            return result;
+        }
+
+        public int read(byte[] arr, int offset, int length) {
+            if ((offset + length) > arr.length) {
+                length = arr.length - offset;
+            }
+
+            int maxLength = size - cursor;
+            if (length > maxLength) {
+                length = maxLength;
+            }
+
+            System.arraycopy(bytes, cursor + start, arr, offset, length);
+            cursor += length;
+            return length;
+        }
+
+        public int available() {
+            return size - cursor;
+        }
+
+        public void mark(int reserve) {
+            mark = cursor;
+        }
+
+        public void reset() {
+            cursor = mark;
+        }
+
+        public boolean markSupported() {
+            return true;
+        }
+    }
+
+    /**
+     * Helper class for {@link #makeDataInputStream}. This is used
+     * simply so that the cursor of a wrapped {@link #MyInputStream}
+     * instance may be easily determined.
+     */
+    public static class MyDataInputStream extends DataInputStream {
+        /** {@code non-null;} the underlying {@link #MyInputStream} */
+        private final MyInputStream wrapped;
+
+        public MyDataInputStream(MyInputStream wrapped) {
+            super(wrapped);
+
+            this.wrapped = wrapped;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
new file mode 100644
index 0000000..05ec733
--- /dev/null
+++ b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+
+/**
+ * Implementation of {@link AnnotatedOutput} which stores the written data
+ * into a {@code byte[]}.
+ *
+ * <p><b>Note:</b> As per the {@link Output} interface, multi-byte
+ * writes all use little-endian order.</p>
+ */
+public final class ByteArrayAnnotatedOutput
+        implements AnnotatedOutput, ByteOutput {
+    /** default size for stretchy instances */
+    private static final int DEFAULT_SIZE = 1000;
+
+    /**
+     * whether the instance is stretchy, that is, whether its array
+     * may be resized to increase capacity
+     */
+    private final boolean stretchy;
+
+    /** {@code non-null;} the data itself */
+    private byte[] data;
+
+    /** {@code >= 0;} current output cursor */
+    private int cursor;
+
+    /** whether annotations are to be verbose */
+    private boolean verbose;
+
+    /**
+     * {@code null-ok;} list of annotations, or {@code null} if this instance
+     * isn't keeping them
+     */
+    private ArrayList<Annotation> annotations;
+
+    /** {@code >= 40 (if used);} the desired maximum annotation width */
+    private int annotationWidth;
+
+    /**
+     * {@code >= 8 (if used);} the number of bytes of hex output to use
+     * in annotations
+     */
+    private int hexCols;
+
+    /**
+     * Constructs an instance with a fixed maximum size. Note that the
+     * given array is the only one that will be used to store data. In
+     * particular, no reallocation will occur in order to expand the
+     * capacity of the resulting instance. Also, the constructed
+     * instance does not keep annotations by default.
+     *
+     * @param data {@code non-null;} data array to use for output
+     */
+    public ByteArrayAnnotatedOutput(byte[] data) {
+        this(data, false);
+    }
+
+    /**
+     * Constructs a "stretchy" instance. The underlying array may be
+     * reallocated. The constructed instance does not keep annotations
+     * by default.
+     */
+    public ByteArrayAnnotatedOutput() {
+        this(DEFAULT_SIZE);
+    }
+
+    /**
+     * Constructs a "stretchy" instance with initial size {@code size}. The
+     * underlying array may be reallocated. The constructed instance does not
+     * keep annotations by default.
+     */
+    public ByteArrayAnnotatedOutput(int size) {
+        this(new byte[size], true);
+    }
+
+    /**
+     * Internal constructor.
+     *
+     * @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) {
+        if (data == null) {
+            throw new NullPointerException("data == null");
+        }
+
+        this.stretchy = stretchy;
+        this.data = data;
+        this.cursor = 0;
+        this.verbose = false;
+        this.annotations = null;
+        this.annotationWidth = 0;
+        this.hexCols = 0;
+    }
+
+    /**
+     * Gets the underlying {@code byte[]} of this instance, which
+     * may be larger than the number of bytes written
+     *
+     * @see #toByteArray
+     *
+     * @return {@code non-null;} the {@code byte[]}
+     */
+    public byte[] getArray() {
+        return data;
+    }
+
+    /**
+     * Constructs and returns a new {@code byte[]} that contains
+     * the written contents exactly (that is, with no extra unwritten
+     * bytes at the end).
+     *
+     * @see #getArray
+     *
+     * @return {@code non-null;} an appropriately-constructed array
+     */
+    public byte[] toByteArray() {
+        byte[] result = new byte[cursor];
+        System.arraycopy(data, 0, result, 0, cursor);
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public int getCursor() {
+        return cursor;
+    }
+
+    /** {@inheritDoc} */
+    public void assertCursor(int expectedCursor) {
+        if (cursor != expectedCursor) {
+            throw new ExceptionWithContext("expected cursor " +
+                    expectedCursor + "; actual value: " + cursor);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void writeByte(int value) {
+        int writeAt = cursor;
+        int end = writeAt + 1;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        data[writeAt] = (byte) value;
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void writeShort(int value) {
+        int writeAt = cursor;
+        int end = writeAt + 2;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        data[writeAt] = (byte) value;
+        data[writeAt + 1] = (byte) (value >> 8);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void writeInt(int value) {
+        int writeAt = cursor;
+        int end = writeAt + 4;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        data[writeAt] = (byte) value;
+        data[writeAt + 1] = (byte) (value >> 8);
+        data[writeAt + 2] = (byte) (value >> 16);
+        data[writeAt + 3] = (byte) (value >> 24);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void writeLong(long value) {
+        int writeAt = cursor;
+        int end = writeAt + 8;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        int half = (int) value;
+        data[writeAt] = (byte) half;
+        data[writeAt + 1] = (byte) (half >> 8);
+        data[writeAt + 2] = (byte) (half >> 16);
+        data[writeAt + 3] = (byte) (half >> 24);
+
+        half = (int) (value >> 32);
+        data[writeAt + 4] = (byte) half;
+        data[writeAt + 5] = (byte) (half >> 8);
+        data[writeAt + 6] = (byte) (half >> 16);
+        data[writeAt + 7] = (byte) (half >> 24);
+
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public int writeUleb128(int value) {
+        if (stretchy) {
+            ensureCapacity(cursor + 5); // pessimistic
+        }
+        int cursorBefore = cursor;
+        Leb128Utils.writeUnsignedLeb128(this, value);
+        return (cursor - cursorBefore);
+    }
+
+    /** {@inheritDoc} */
+    public int writeSleb128(int value) {
+        if (stretchy) {
+            ensureCapacity(cursor + 5); // pessimistic
+        }
+        int cursorBefore = cursor;
+        Leb128Utils.writeSignedLeb128(this, value);
+        return (cursor - cursorBefore);
+    }
+
+    /** {@inheritDoc} */
+    public void write(ByteArray bytes) {
+        int blen = bytes.size();
+        int writeAt = cursor;
+        int end = writeAt + blen;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        bytes.getBytes(data, writeAt);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void write(byte[] bytes, int offset, int length) {
+        int writeAt = cursor;
+        int end = writeAt + length;
+        int bytesEnd = offset + length;
+
+        // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+        if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
+            throw new IndexOutOfBoundsException("bytes.length " +
+                                                bytes.length + "; " +
+                                                offset + "..!" + end);
+        }
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        System.arraycopy(bytes, offset, data, writeAt, length);
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void write(byte[] bytes) {
+        write(bytes, 0, bytes.length);
+    }
+
+    /** {@inheritDoc} */
+    public void writeZeroes(int count) {
+        if (count < 0) {
+            throw new IllegalArgumentException("count < 0");
+        }
+
+        int end = cursor + count;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        /*
+         * There is no need to actually write zeroes, since the array is
+         * already preinitialized with zeroes.
+         */
+
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public void alignTo(int alignment) {
+        int mask = alignment - 1;
+
+        if ((alignment < 0) || ((mask & alignment) != 0)) {
+            throw new IllegalArgumentException("bogus alignment");
+        }
+
+        int end = (cursor + mask) & ~mask;
+
+        if (stretchy) {
+            ensureCapacity(end);
+        } else if (end > data.length) {
+            throwBounds();
+            return;
+        }
+
+        /*
+         * There is no need to actually write zeroes, since the array is
+         * already preinitialized with zeroes.
+         */
+
+        cursor = end;
+    }
+
+    /** {@inheritDoc} */
+    public boolean annotates() {
+        return (annotations != null);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isVerbose() {
+        return verbose;
+    }
+
+    /** {@inheritDoc} */
+    public void annotate(String msg) {
+        if (annotations == null) {
+            return;
+        }
+
+        endAnnotation();
+        annotations.add(new Annotation(cursor, msg));
+    }
+
+    /** {@inheritDoc} */
+    public void annotate(int amt, String msg) {
+        if (annotations == null) {
+            return;
+        }
+
+        endAnnotation();
+
+        int asz = annotations.size();
+        int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
+        int startAt;
+
+        if (lastEnd <= cursor) {
+            startAt = cursor;
+        } else {
+            startAt = lastEnd;
+        }
+
+        annotations.add(new Annotation(startAt, startAt + amt, msg));
+    }
+
+    /** {@inheritDoc} */
+    public void endAnnotation() {
+        if (annotations == null) {
+            return;
+        }
+
+        int sz = annotations.size();
+
+        if (sz != 0) {
+            annotations.get(sz - 1).setEndIfUnset(cursor);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public int getAnnotationWidth() {
+        int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
+
+        return annotationWidth - leftWidth;
+    }
+
+    /**
+     * Indicates that this instance should keep annotations. This method may
+     * be called only once per instance, and only before any data has been
+     * written to the it.
+     *
+     * @param annotationWidth {@code >= 40;} the desired maximum annotation width
+     * @param verbose whether or not to indicate verbose annotations
+     */
+    public void enableAnnotations(int annotationWidth, boolean verbose) {
+        if ((annotations != null) || (cursor != 0)) {
+            throw new RuntimeException("cannot enable annotations");
+        }
+
+        if (annotationWidth < 40) {
+            throw new IllegalArgumentException("annotationWidth < 40");
+        }
+
+        int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
+        if (hexCols < 6) {
+            hexCols = 6;
+        } else if (hexCols > 10) {
+            hexCols = 10;
+        }
+
+        this.annotations = new ArrayList<Annotation>(1000);
+        this.annotationWidth = annotationWidth;
+        this.hexCols = hexCols;
+        this.verbose = verbose;
+    }
+
+    /**
+     * Finishes up annotation processing. This closes off any open
+     * annotations and removes annotations that don't refer to written
+     * data.
+     */
+    public void finishAnnotating() {
+        // Close off the final annotation, if any.
+        endAnnotation();
+
+        // Remove annotations that refer to unwritten data.
+        if (annotations != null) {
+            int asz = annotations.size();
+            while (asz > 0) {
+                Annotation last = annotations.get(asz - 1);
+                if (last.getStart() > cursor) {
+                    annotations.remove(asz - 1);
+                    asz--;
+                } else if (last.getEnd() > cursor) {
+                    last.setEnd(cursor);
+                    break;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Writes the annotated content of this instance to the given writer.
+     *
+     * @param out {@code non-null;} where to write to
+     */
+    public void writeAnnotationsTo(Writer out) throws IOException {
+        int width2 = getAnnotationWidth();
+        int width1 = annotationWidth - width2 - 1;
+
+        TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
+        Writer left = twoc.getLeft();
+        Writer right = twoc.getRight();
+        int leftAt = 0; // left-hand byte output cursor
+        int rightAt = 0; // right-hand annotation index
+        int rightSz = annotations.size();
+
+        while ((leftAt < cursor) && (rightAt < rightSz)) {
+            Annotation a = annotations.get(rightAt);
+            int start = a.getStart();
+            int end;
+            String text;
+
+            if (leftAt < start) {
+                // This is an area with no annotation.
+                end = start;
+                start = leftAt;
+                text = "";
+            } else {
+                // This is an area with an annotation.
+                end = a.getEnd();
+                text = a.getText();
+                rightAt++;
+            }
+
+            left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
+            right.write(text);
+            twoc.flush();
+            leftAt = end;
+        }
+
+        if (leftAt < cursor) {
+            // There is unannotated output at the end.
+            left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt,
+                                hexCols, 6));
+        }
+
+        while (rightAt < rightSz) {
+            // There are zero-byte annotations at the end.
+            right.write(annotations.get(rightAt).getText());
+            rightAt++;
+        }
+
+        twoc.flush();
+    }
+
+    /**
+     * Throws the excpetion for when an attempt is made to write past the
+     * end of the instance.
+     */
+    private static void throwBounds() {
+        throw new IndexOutOfBoundsException("attempt to write past the end");
+    }
+
+    /**
+     * Reallocates the underlying array if necessary. Calls to this method
+     * should be guarded by a test of {@link #stretchy}.
+     *
+     * @param desiredSize {@code >= 0;} the desired minimum total size of the array
+     */
+    private void ensureCapacity(int desiredSize) {
+        if (data.length < desiredSize) {
+            byte[] newData = new byte[desiredSize * 2 + 1000];
+            System.arraycopy(data, 0, newData, 0, cursor);
+            data = newData;
+        }
+    }
+
+    /**
+     * Annotation on output.
+     */
+    private static class Annotation {
+        /** {@code >= 0;} start of annotated range (inclusive) */
+        private final int start;
+
+        /**
+         * {@code >= 0;} end of annotated range (exclusive);
+         * {@code Integer.MAX_VALUE} if unclosed
+         */
+        private int end;
+
+        /** {@code non-null;} annotation text */
+        private final String text;
+
+        /**
+         * Constructs an instance.
+         *
+         * @param start {@code >= 0;} start of annotated range
+         * @param end {@code >= start;} end of annotated range (exclusive) or
+         * {@code Integer.MAX_VALUE} if unclosed
+         * @param text {@code non-null;} annotation text
+         */
+        public Annotation(int start, int end, String text) {
+            this.start = start;
+            this.end = end;
+            this.text = text;
+        }
+
+        /**
+         * Constructs an instance. It is initally unclosed.
+         *
+         * @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);
+        }
+
+        /**
+         * Sets the end as given, but only if the instance is unclosed;
+         * otherwise, do nothing.
+         *
+         * @param end {@code >= start;} the end
+         */
+        public void setEndIfUnset(int end) {
+            if (this.end == Integer.MAX_VALUE) {
+                this.end = end;
+            }
+        }
+
+        /**
+         * Sets the end as given.
+         *
+         * @param end {@code >= start;} the end
+         */
+        public void setEnd(int end) {
+            this.end = end;
+        }
+
+        /**
+         * Gets the start.
+         *
+         * @return the start
+         */
+        public int getStart() {
+            return start;
+        }
+
+        /**
+         * Gets the end.
+         *
+         * @return the end
+         */
+        public int getEnd() {
+            return end;
+        }
+
+        /**
+         * Gets the text.
+         *
+         * @return {@code non-null;} the text
+         */
+        public String getText() {
+            return text;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/util/ByteArrayByteInput.java b/dx/src/com/android/dx/util/ByteArrayByteInput.java
new file mode 100644
index 0000000..07c543f
--- /dev/null
+++ b/dx/src/com/android/dx/util/ByteArrayByteInput.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+public final class ByteArrayByteInput implements ByteInput {
+
+    private final byte[] bytes;
+    private int position;
+
+    public ByteArrayByteInput(byte... bytes) {
+        this.bytes = bytes;
+    }
+
+    @Override public byte readByte() {
+        return bytes[position++];
+    }
+}
diff --git a/dx/src/com/android/dx/util/ByteInput.java b/dx/src/com/android/dx/util/ByteInput.java
new file mode 100644
index 0000000..8181e3e
--- /dev/null
+++ b/dx/src/com/android/dx/util/ByteInput.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * A byte source.
+ */
+public interface ByteInput {
+
+    /**
+     * Returns a byte.
+     *
+     * @throws IndexOutOfBoundsException if all bytes have been read.
+     */
+    byte readByte();
+}
diff --git a/dx/src/com/android/dx/util/ByteOutput.java b/dx/src/com/android/dx/util/ByteOutput.java
new file mode 100644
index 0000000..512dcf8
--- /dev/null
+++ b/dx/src/com/android/dx/util/ByteOutput.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * A byte sink.
+ */
+public interface ByteOutput {
+
+    /**
+     * Writes a byte.
+     *
+     * @throws IndexOutOfBoundsException if all bytes have been written.
+     */
+    void writeByte(int i);
+}
diff --git a/dx/src/com/android/dx/util/DexException.java b/dx/src/com/android/dx/util/DexException.java
new file mode 100644
index 0000000..527b0b9
--- /dev/null
+++ b/dx/src/com/android/dx/util/DexException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Thrown when there's a format problem reading, writing, or generally
+ * processing a dex file.
+ */
+public final class DexException extends ExceptionWithContext {
+    public DexException(String message) {
+        super(message);
+    }
+
+    public DexException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/dx/src/com/android/dx/util/ExceptionWithContext.java b/dx/src/com/android/dx/util/ExceptionWithContext.java
new file mode 100644
index 0000000..7f8523c
--- /dev/null
+++ b/dx/src/com/android/dx/util/ExceptionWithContext.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * Exception which carries around structured context.
+ */
+public class ExceptionWithContext
+        extends RuntimeException {
+    /** {@code non-null;} human-oriented context of the exception */
+    private StringBuffer context;
+
+    /**
+     * Augments the given exception with the given context, and return the
+     * result. The result is either the given exception if it was an
+     * {@link ExceptionWithContext}, or a newly-constructed exception if it
+     * was not.
+     *
+     * @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;
+
+        if (ex instanceof ExceptionWithContext) {
+            ewc = (ExceptionWithContext) ex;
+        } else {
+            ewc = new ExceptionWithContext(ex);
+        }
+
+        ewc.addContext(str);
+        return ewc;
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param message human-oriented message
+     */
+    public ExceptionWithContext(String message) {
+        this(message, null);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param cause {@code null-ok;} exception that caused this one
+     */
+    public ExceptionWithContext(Throwable cause) {
+        this(null, cause);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param message human-oriented message
+     * @param cause {@code null-ok;} exception that caused this one
+     */
+    public ExceptionWithContext(String message, Throwable cause) {
+        super((message != null) ? message :
+              (cause != null) ? cause.getMessage() : null,
+              cause);
+
+        if (cause instanceof ExceptionWithContext) {
+            String ctx = ((ExceptionWithContext) cause).context.toString();
+            context = new StringBuffer(ctx.length() + 200);
+            context.append(ctx);
+        } else {
+            context = new StringBuffer(200);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void printStackTrace(PrintStream out) {
+        super.printStackTrace(out);
+        out.println(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void printStackTrace(PrintWriter out) {
+        super.printStackTrace(out);
+        out.println(context);
+    }
+
+    /**
+     * Adds a line of context to this instance.
+     *
+     * @param str {@code non-null;} new context
+     */
+    public void addContext(String str) {
+        if (str == null) {
+            throw new NullPointerException("str == null");
+        }
+
+        context.append(str);
+        if (!str.endsWith("\n")) {
+            context.append('\n');
+        }
+    }
+
+    /**
+     * Gets the context.
+     *
+     * @return {@code non-null;} the context
+     */
+    public String getContext() {
+        return context.toString();
+    }
+
+    /**
+     * Prints the message and context.
+     *
+     * @param out {@code non-null;} where to print to
+     */
+    public void printContext(PrintStream out) {
+        out.println(getMessage());
+        out.print(context);
+    }
+
+    /**
+     * Prints the message and context.
+     *
+     * @param out {@code non-null;} where to print to
+     */
+    public void printContext(PrintWriter out) {
+        out.println(getMessage());
+        out.print(context);
+    }
+}
diff --git a/dx/src/com/android/dx/util/FileUtils.java b/dx/src/com/android/dx/util/FileUtils.java
new file mode 100644
index 0000000..bcf6729
--- /dev/null
+++ b/dx/src/com/android/dx/util/FileUtils.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * File I/O utilities.
+ */
+public final class FileUtils {
+    /**
+     * This class is uninstantiable.
+     */
+    private FileUtils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Reads the named file, translating {@link IOException} to a
+     * {@link RuntimeException} of some sort.
+     *
+     * @param fileName {@code non-null;} name of the file to read
+     * @return {@code non-null;} contents of the file
+     */
+    public static byte[] readFile(String fileName) {
+        File file = new File(fileName);
+        return readFile(file);
+    }
+
+    /**
+     * Reads the given file, translating {@link IOException} to a
+     * {@link RuntimeException} of some sort.
+     *
+     * @param file {@code non-null;} the file to read
+     * @return {@code non-null;} contents of the file
+     */
+    public static byte[] readFile(File file) {
+        if (!file.exists()) {
+            throw new RuntimeException(file + ": file not found");
+        }
+
+        if (!file.isFile()) {
+            throw new RuntimeException(file + ": not a file");
+        }
+
+        if (!file.canRead()) {
+            throw new RuntimeException(file + ": file not readable");
+        }
+
+        long longLength = file.length();
+        int length = (int) longLength;
+        if (length != longLength) {
+            throw new RuntimeException(file + ": file too long");
+        }
+
+        byte[] result = new byte[length];
+
+        try {
+            FileInputStream in = new FileInputStream(file);
+            int at = 0;
+            while (length > 0) {
+                int amt = in.read(result, at, length);
+                if (amt == -1) {
+                    throw new RuntimeException(file + ": unexpected EOF");
+                }
+                at += amt;
+                length -= amt;
+            }
+            in.close();
+        } catch (IOException ex) {
+            throw new RuntimeException(file + ": trouble reading", ex);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if {@code fileName} names a .zip, .jar, or .apk.
+     */
+    public static boolean hasArchiveSuffix(String fileName) {
+        return fileName.endsWith(".zip")
+                || fileName.endsWith(".jar")
+                || fileName.endsWith(".apk");
+    }
+}
diff --git a/dx/src/com/android/dx/util/FixedSizeList.java b/dx/src/com/android/dx/util/FixedSizeList.java
new file mode 100644
index 0000000..fb3af04
--- /dev/null
+++ b/dx/src/com/android/dx/util/FixedSizeList.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.util.Arrays;
+
+/**
+ * Simple (mostly) fixed-size list of objects, which may be made immutable.
+ */
+public class FixedSizeList
+        extends MutabilityControl implements ToHuman {
+    /** {@code non-null;} array of elements */
+    private Object[] arr;
+
+    /**
+     * Constructs an instance. All indices initially contain {@code null}.
+     *
+     * @param size the size of the list
+     */
+    public FixedSizeList(int size) {
+        super(size != 0);
+
+        try {
+            arr = new Object[size];
+        } catch (NegativeArraySizeException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("size < 0");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            // Easy out.
+            return true;
+        }
+
+        if ((other == null) || (getClass() != other.getClass())) {
+            // Another easy out.
+            return false;
+        }
+
+        FixedSizeList list = (FixedSizeList) other;
+        return Arrays.equals(arr, list.arr);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(arr);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        String name = getClass().getName();
+
+        return toString0(name.substring(name.lastIndexOf('.') + 1) + '{',
+                         ", ",
+                         "}",
+                         false);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This method will only work if every element of the list
+     * implements {@link ToHuman}.
+     */
+    public String toHuman() {
+        String name = getClass().getName();
+
+        return toString0(name.substring(name.lastIndexOf('.') + 1) + '{',
+                         ", ",
+                         "}",
+                         true);
+    }
+
+    /**
+     * Gets a customized string form for this instance.
+     *
+     * @param prefix {@code null-ok;} prefix for the start of the result
+     * @param separator {@code null-ok;} separator to insert between each item
+     * @param suffix {@code null-ok;} suffix for the end of the result
+     * @return {@code non-null;} the custom string
+     */
+    public String toString(String prefix, String separator, String suffix) {
+        return toString0(prefix, separator, suffix, false);
+    }
+
+    /**
+     * Gets a customized human string for this instance. This method will
+     * only work if every element of the list implements {@link
+     * ToHuman}.
+     *
+     * @param prefix {@code null-ok;} prefix for the start of the result
+     * @param separator {@code null-ok;} separator to insert between each item
+     * @param suffix {@code null-ok;} suffix for the end of the result
+     * @return {@code non-null;} the custom string
+     */
+    public String toHuman(String prefix, String separator, String suffix) {
+        return toString0(prefix, separator, suffix, true);
+    }
+
+    /**
+     * Gets the number of elements in this list.
+     */
+    public final int size() {
+        return arr.length;
+    }
+
+    /**
+     * Shrinks this instance to fit, by removing any unset
+     * ({@code null}) elements, leaving the remaining elements in
+     * their original order.
+     */
+    public void shrinkToFit() {
+        int sz = arr.length;
+        int newSz = 0;
+
+        for (int i = 0; i < sz; i++) {
+            if (arr[i] != null) {
+                newSz++;
+            }
+        }
+
+        if (sz == newSz) {
+            return;
+        }
+
+        throwIfImmutable();
+
+        Object[] newa = new Object[newSz];
+        int at = 0;
+
+        for (int i = 0; i < sz; i++) {
+            Object one = arr[i];
+            if (one != null) {
+                newa[at] = one;
+                at++;
+            }
+        }
+
+        arr = newa;
+        if (newSz == 0) {
+            setImmutable();
+        }
+    }
+
+    /**
+     * 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}. This method is
+     * protected so that subclasses may offer a safe type-checked
+     * public interface to their clients.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return {@code non-null;} the indicated element
+     */
+    protected final Object get0(int n) {
+        try {
+            Object result = arr[n];
+
+            if (result == null) {
+                throw new NullPointerException("unset: " + n);
+            }
+
+            return result;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            return throwIndex(n);
+        }
+    }
+
+    /**
+     * 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 {@code >= 0, < size();} which element
+     * @return {@code null-ok;} the indicated element
+     */
+    protected final Object getOrNull0(int n) {
+        return arr[n];
+    }
+
+    /**
+     * Sets the element at the given index, but without doing any type
+     * checks on the element. This method is protected so that
+     * subclasses may offer a safe type-checked public interface to
+     * their clients.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param obj {@code null-ok;} the value to store
+     */
+    protected final void set0(int n, Object obj) {
+        throwIfImmutable();
+
+        try {
+            arr[n] = obj;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            throwIndex(n);
+        }
+    }
+
+    /**
+     * Throws the appropriate exception for the given index value.
+     *
+     * @param n the index value
+     * @return never
+     * @throws IndexOutOfBoundsException always thrown
+     */
+    private Object throwIndex(int n) {
+        if (n < 0) {
+            throw new IndexOutOfBoundsException("n < 0");
+        }
+
+        throw new IndexOutOfBoundsException("n >= size()");
+    }
+
+    /**
+     * Helper for {@link #toString} and {@link #toHuman}, which both of
+     * those call to pretty much do everything.
+     *
+     * @param prefix {@code null-ok;} prefix for the start of the result
+     * @param separator {@code null-ok;} separator to insert between each item
+     * @param suffix {@code null-ok;} suffix for the end of the result
+     * @param human whether the output is to be human
+     * @return {@code non-null;} the custom string
+     */
+    private String toString0(String prefix, String separator, String suffix,
+                             boolean human) {
+        int len = arr.length;
+        StringBuffer sb = new StringBuffer(len * 10 + 10);
+
+        if (prefix != null) {
+            sb.append(prefix);
+        }
+
+        for (int i = 0; i < len; i++) {
+            if ((i != 0) && (separator != null)) {
+                sb.append(separator);
+            }
+
+            if (human) {
+                sb.append(((ToHuman) arr[i]).toHuman());
+            } else {
+                sb.append(arr[i]);
+            }
+        }
+
+        if (suffix != null) {
+            sb.append(suffix);
+        }
+
+        return sb.toString();
+    }
+
+}
diff --git a/dx/src/com/android/dx/util/Hex.java b/dx/src/com/android/dx/util/Hex.java
new file mode 100644
index 0000000..e95669c
--- /dev/null
+++ b/dx/src/com/android/dx/util/Hex.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Utilities for formatting numbers as hexadecimal.
+ */
+public final class Hex {
+    /**
+     * This class is uninstantiable.
+     */
+    private Hex() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Formats a {@code long} as an 8-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u8(long v) {
+        char[] result = new char[16];
+        for (int i = 0; i < 16; i++) {
+            result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 4-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u4(int v) {
+        char[] result = new char[8];
+        for (int i = 0; i < 8; i++) {
+            result[7 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 3-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u3(int v) {
+        char[] result = new char[6];
+        for (int i = 0; i < 6; i++) {
+            result[5 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 2-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u2(int v) {
+        char[] result = new char[4];
+        for (int i = 0; i < 4; i++) {
+            result[3 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as either a 2-byte unsigned hex value
+     * (if the value is small enough) or a 4-byte unsigned hex value (if
+     * not).
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u2or4(int v) {
+        if (v == (char) v) {
+            return u2(v);
+        } else {
+            return u4(v);
+        }
+    }
+
+    /**
+     * Formats an {@code int} as a 1-byte unsigned hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String u1(int v) {
+        char[] result = new char[2];
+        for (int i = 0; i < 2; i++) {
+            result[1 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 4-bit unsigned hex nibble.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String uNibble(int v) {
+        char[] result = new char[1];
+
+        result[0] = Character.forDigit(v & 0x0f, 16);
+        return new String(result);
+    }
+
+    /**
+     * Formats a {@code long} as an 8-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s8(long v) {
+        char[] result = new char[17];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 16; i++) {
+            result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 4-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s4(int v) {
+        char[] result = new char[9];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 8; i++) {
+            result[8 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 2-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s2(int v) {
+        char[] result = new char[5];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 4; i++) {
+            result[4 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(result);
+    }
+
+    /**
+     * Formats an {@code int} as a 1-byte signed hex value.
+     *
+     * @param v value to format
+     * @return {@code non-null;} formatted form
+     */
+    public static String s1(int v) {
+        char[] result = new char[3];
+
+        if (v < 0) {
+            result[0] = '-';
+            v = -v;
+        } else {
+            result[0] = '+';
+        }
+
+        for (int i = 0; i < 2; i++) {
+            result[2 - i] = Character.forDigit(v & 0x0f, 16);
+            v >>= 4;
+        }
+
+        return new String(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 ""}).
+     *
+     * @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 {@code non-null;} a string of the dump
+     */
+    public static String dump(byte[] arr, int offset, int length,
+                              int outOffset, int bpl, int addressLength) {
+        int end = offset + length;
+
+        // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+        if (((offset | length | end) < 0) || (end > arr.length)) {
+            throw new IndexOutOfBoundsException("arr.length " +
+                                                arr.length + "; " +
+                                                offset + "..!" + end);
+        }
+
+        if (outOffset < 0) {
+            throw new IllegalArgumentException("outOffset < 0");
+        }
+
+        if (length == 0) {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer(length * 4 + 6);
+        boolean bol = true;
+        int col = 0;
+
+        while (length > 0) {
+            if (col == 0) {
+                String astr;
+                switch (addressLength) {
+                    case 2:  astr = Hex.u1(outOffset); break;
+                    case 4:  astr = Hex.u2(outOffset); break;
+                    case 6:  astr = Hex.u3(outOffset); break;
+                    default: astr = Hex.u4(outOffset); break;
+                }
+                sb.append(astr);
+                sb.append(": ");
+            } else if ((col & 1) == 0) {
+                sb.append(' ');
+            }
+            sb.append(Hex.u1(arr[offset]));
+            outOffset++;
+            offset++;
+            col++;
+            if (col == bpl) {
+                sb.append('\n');
+                col = 0;
+            }
+            length--;
+        }
+
+        if (col != 0) {
+            sb.append('\n');
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/util/HexParser.java b/dx/src/com/android/dx/util/HexParser.java
new file mode 100644
index 0000000..1b34345
--- /dev/null
+++ b/dx/src/com/android/dx/util/HexParser.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Utilities for parsing hexadecimal text.
+ */
+public final class HexParser {
+    /**
+     * This class is uninstantiable.
+     */
+    private HexParser() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * 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
+     * hex digits freely interspersed with whitespace. If a pound sign
+     * is encountered, it and the rest of the line are ignored as a
+     * comment. If a double quote is encountered, then the ASCII value
+     * of the subsequent characters is used, until the next double
+     * quote. Quoted strings may not span multiple lines.
+     *
+     * @param src {@code non-null;} the source string
+     * @return {@code non-null;} the parsed form
+     */
+    public static byte[] parse(String src) {
+        int len = src.length();
+        byte[] result = new byte[len / 2];
+        int at = 0;
+        int outAt = 0;
+
+        while (at < len) {
+            int nlAt = src.indexOf('\n', at);
+            if (nlAt < 0) {
+                nlAt = len;
+            }
+            int poundAt = src.indexOf('#', at);
+
+            String line;
+            if ((poundAt >= 0) && (poundAt < nlAt)) {
+                line = src.substring(at, poundAt);
+            } else {
+                line = src.substring(at, nlAt);
+            }
+            at = nlAt + 1;
+
+            int colonAt = line.indexOf(':');
+
+            atCheck:
+            if (colonAt != -1) {
+                int quoteAt = line.indexOf('\"');
+                if ((quoteAt != -1) && (quoteAt < colonAt)) {
+                    break atCheck;
+                }
+
+                String atStr = line.substring(0, colonAt).trim();
+                line = line.substring(colonAt + 1);
+                int alleged = Integer.parseInt(atStr, 16);
+                if (alleged != outAt) {
+                    throw new RuntimeException("bogus offset marker: " +
+                                               atStr);
+                }
+            }
+
+            int lineLen = line.length();
+            int value = -1;
+            boolean quoteMode = false;
+
+            for (int i = 0; i < lineLen; i++) {
+                char c = line.charAt(i);
+
+                if (quoteMode) {
+                    if (c == '\"') {
+                        quoteMode = false;
+                    } else {
+                        result[outAt] = (byte) c;
+                        outAt++;
+                    }
+                    continue;
+                }
+
+                if (c <= ' ') {
+                    continue;
+                }
+                if (c == '\"') {
+                    if (value != -1) {
+                        throw new RuntimeException("spare digit around " +
+                                                   "offset " + Hex.u4(outAt));
+                    }
+                    quoteMode = true;
+                    continue;
+                }
+
+                int digVal = Character.digit(c, 16);
+                if (digVal == -1) {
+                    throw new RuntimeException("bogus digit character: \"" +
+                                               c + "\"");
+                }
+                if (value == -1) {
+                    value = digVal;
+                } else {
+                    result[outAt] = (byte) ((value << 4) | digVal);
+                    outAt++;
+                    value = -1;
+                }
+            }
+
+            if (value != -1) {
+                throw new RuntimeException("spare digit around offset " +
+                                           Hex.u4(outAt));
+            }
+
+            if (quoteMode) {
+                throw new RuntimeException("unterminated quote around " +
+                                           "offset " + Hex.u4(outAt));
+            }
+        }
+
+        if (outAt < result.length) {
+            byte[] newr = new byte[outAt];
+            System.arraycopy(result, 0, newr, 0, outAt);
+            result = newr;
+        }
+
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/util/IndentingWriter.java b/dx/src/com/android/dx/util/IndentingWriter.java
new file mode 100644
index 0000000..3424e37
--- /dev/null
+++ b/dx/src/com/android/dx/util/IndentingWriter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Writer that wraps another writer and passes width-limited and
+ * optionally-prefixed output to its subordinate. When lines are
+ * wrapped they are automatically indented based on the start of the
+ * line.
+ */
+public final class IndentingWriter extends FilterWriter {
+    /** {@code null-ok;} optional prefix for every line */
+    private final String prefix;
+
+    /** {@code > 0;} the maximum output width */
+    private final int width;
+
+    /** {@code > 0;} the maximum indent */
+    private final int maxIndent;
+
+    /** {@code >= 0;} current output column (zero-based) */
+    private int column;
+
+    /** whether indent spaces are currently being collected */
+    private boolean collectingIndent;
+
+    /** {@code >= 0;} current indent amount */
+    private int indent;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param out {@code non-null;} writer to send final output to
+     * @param width {@code >= 0;} the maximum output width (not including
+     * {@code prefix}), or {@code 0} for no maximum
+     * @param prefix {@code non-null;} the prefix for each line
+     */
+    public IndentingWriter(Writer out, int width, String prefix) {
+        super(out);
+
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        }
+
+        if (width < 0) {
+            throw new IllegalArgumentException("width < 0");
+        }
+
+        if (prefix == null) {
+            throw new NullPointerException("prefix == null");
+        }
+
+        this.width = (width != 0) ? width : Integer.MAX_VALUE;
+        this.maxIndent = width >> 1;
+        this.prefix = (prefix.length() == 0) ? null : prefix;
+
+        bol();
+    }
+
+    /**
+     * Constructs a no-prefix instance.
+     *
+     * @param out {@code non-null;} writer to send final output to
+     * @param width {@code >= 0;} the maximum output width (not including
+     * {@code prefix}), or {@code 0} for no maximum
+     */
+    public IndentingWriter(Writer out, int width) {
+        this(out, width, "");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(int c) throws IOException {
+        synchronized (lock) {
+            if (collectingIndent) {
+                if (c == ' ') {
+                    indent++;
+                    if (indent >= maxIndent) {
+                        indent = maxIndent;
+                        collectingIndent = false;
+                    }
+                } else {
+                    collectingIndent = false;
+                }
+            }
+
+            if ((column == width) && (c != '\n')) {
+                out.write('\n');
+                column = 0;
+                /*
+                 * Note: No else, so this should fall through to the next
+                 * if statement.
+                 */
+            }
+
+            if (column == 0) {
+                if (prefix != null) {
+                    out.write(prefix);
+                }
+
+                if (!collectingIndent) {
+                    for (int i = 0; i < indent; i++) {
+                        out.write(' ');
+                    }
+                    column = indent;
+                }
+            }
+
+            out.write(c);
+
+            if (c == '\n') {
+                bol();
+            } else {
+                column++;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        synchronized (lock) {
+            while (len > 0) {
+                write(cbuf[off]);
+                off++;
+                len--;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void write(String str, int off, int len) throws IOException {
+        synchronized (lock) {
+            while (len > 0) {
+                write(str.charAt(off));
+                off++;
+                len--;
+            }
+        }
+    }
+
+    /**
+     * Indicates that output is at the beginning of a line.
+     */
+    private void bol() {
+        column = 0;
+        collectingIndent = (maxIndent != 0);
+        indent = 0;
+    }
+}
diff --git a/dx/src/com/android/dx/util/IntIterator.java b/dx/src/com/android/dx/util/IntIterator.java
new file mode 100644
index 0000000..4caa439
--- /dev/null
+++ b/dx/src/com/android/dx/util/IntIterator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * An iterator for a list of ints.
+ */
+public interface IntIterator {
+
+    /**
+     * Checks to see if the iterator has a next value.
+     *
+     * @return true if next() will succeed
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next value in the iterator.
+     *
+     * @return next value
+     * @throws java.util.NoSuchElementException if no next element exists
+     */
+    int next();
+}
diff --git a/dx/src/com/android/dx/util/IntList.java b/dx/src/com/android/dx/util/IntList.java
new file mode 100644
index 0000000..be400aa
--- /dev/null
+++ b/dx/src/com/android/dx/util/IntList.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.util.Arrays;
+
+/**
+ * Simple list of {@code int}s.
+ */
+public final class IntList extends MutabilityControl {
+    /** {@code non-null;} immutable, no-element instance */
+    public static final IntList EMPTY = new IntList(0);
+
+    /** {@code non-null;} array of elements */
+    private int[] values;
+
+    /** {@code >= 0;} current size of the list */
+    private int size;
+
+    /** whether the values are currently sorted */
+    private boolean sorted;
+
+    static {
+        EMPTY.setImmutable();
+    }
+
+    /**
+     * Constructs a new immutable instance with the given element.
+     *
+     * @param value the sole value in the list
+     */
+    public static IntList makeImmutable(int value) {
+        IntList result = new IntList(1);
+
+        result.add(value);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs a new immutable instance with the given elements.
+     *
+     * @param value0 the first value in the list
+     * @param value1 the second value in the list
+     */
+    public static IntList makeImmutable(int value0, int value1) {
+        IntList result = new IntList(2);
+
+        result.add(value0);
+        result.add(value1);
+        result.setImmutable();
+
+        return result;
+    }
+
+    /**
+     * Constructs an empty instance with a default initial capacity.
+     */
+    public IntList() {
+        this(4);
+    }
+
+    /**
+     * Constructs an empty instance.
+     *
+     * @param initialCapacity {@code >= 0;} initial capacity of the list
+     */
+    public IntList(int initialCapacity) {
+        super(true);
+
+        try {
+            values = new int[initialCapacity];
+        } catch (NegativeArraySizeException ex) {
+            // Translate the exception.
+            throw new IllegalArgumentException("size < 0");
+        }
+
+        size = 0;
+        sorted = true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        int result = 0;
+
+        for (int i = 0; i < size; i++) {
+            result = (result * 31) + values[i];
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+
+        if (! (other instanceof IntList)) {
+            return false;
+        }
+
+        IntList otherList = (IntList) other;
+
+        if (sorted != otherList.sorted) {
+            return false;
+        }
+
+        if (size != otherList.size) {
+            return false;
+        }
+
+        for (int i = 0; i < size; i++) {
+            if (values[i] != otherList.values[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(size * 5 + 10);
+
+        sb.append('{');
+
+        for (int i = 0; i < size; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append(values[i]);
+        }
+
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    /**
+     * Gets the number of elements in this list.
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Gets the indicated value.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @return the indicated element's value
+     */
+    public int get(int n) {
+        if (n >= size) {
+            throw new IndexOutOfBoundsException("n >= size()");
+        }
+
+        try {
+            return values[n];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate exception.
+            throw new IndexOutOfBoundsException("n < 0");
+        }
+    }
+
+    /**
+     * Sets the value at the given index.
+     *
+     * @param n {@code >= 0, < size();} which element
+     * @param value value to store
+     */
+    public void set(int n, int value) {
+        throwIfImmutable();
+
+        if (n >= size) {
+            throw new IndexOutOfBoundsException("n >= size()");
+        }
+
+        try {
+            values[n] = value;
+            sorted = false;
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // Translate the exception.
+            if (n < 0) {
+                throw new IllegalArgumentException("n < 0");
+            }
+        }
+    }
+
+    /**
+     * Adds an element to the end of the list. This will increase the
+     * list's capacity if necessary.
+     *
+     * @param value the value to add
+     */
+    public void add(int value) {
+        throwIfImmutable();
+
+        growIfNeeded();
+
+        values[size++] = value;
+
+        if (sorted && (size > 1)) {
+            sorted = (value >= values[size - 2]);
+        }
+    }
+
+    /**
+     * Inserts element into specified index, moving elements at and above
+     * that index up one. May not be used to insert at an index beyond the
+     * current size (that is, insertion as a last element is legal but
+     * no further).
+     *
+     * @param n {@code >= 0, <=size();} index of where to insert
+     * @param value value to insert
+     */
+    public void insert(int n, int value) {
+        if (n > size) {
+            throw new IndexOutOfBoundsException("n > size()");
+        }
+
+        growIfNeeded();
+
+        System.arraycopy (values, n, values, n+1, size - n);
+        values[n] = value;
+        size++;
+
+        sorted = sorted
+                && (n == 0 || value > values[n-1])
+                && (n == (size - 1) || value < values[n+1]);
+    }
+
+    /**
+     * Removes an element at a given index, shifting elements at greater
+     * indicies down one.
+     *
+     * @param n  {@code >=0, < size();} index of element to remove
+     */
+    public void removeIndex(int n) {
+        if (n >= size) {
+            throw new IndexOutOfBoundsException("n >= size()");
+        }
+
+        System.arraycopy (values, n + 1, values, n, size - n - 1);
+        size--;
+
+        // sort status is unchanged
+    }
+
+    /**
+     * Increases size of array if needed
+     */
+    private void growIfNeeded() {
+        if (size == values.length) {
+            // Resize.
+            int[] newv = new int[size * 3 / 2 + 10];
+            System.arraycopy(values, 0, newv, 0, size);
+            values = newv;
+        }
+    }
+
+    /**
+     * Returns the last element in the array without modifying the array
+     *
+     * @return last value in the array
+     * @throws IndexOutOfBoundsException if stack is empty
+     */
+    public int top() {
+        return get(size - 1);
+    }
+
+    /**
+     * Pops an element off the end of the list and decreasing the size by one.
+     *
+     * @return value from what was the last element
+     * @throws IndexOutOfBoundsException if stack is empty
+     */
+    public int pop() {
+        throwIfImmutable();
+
+        int result;
+
+        result = get(size-1);
+        size--;
+
+        return result;
+    }
+
+    /**
+     * Pops N elements off the end of the list and decreasing the size by N.
+     *
+     * @param n {@code >= 0;} number of elements to remove from end
+     * @throws IndexOutOfBoundsException if stack is smaller than N
+     */
+    public void pop(int n) {
+        throwIfImmutable();
+
+        size -= n;
+    }
+
+    /**
+     * Shrinks the size of the list.
+     *
+     * @param newSize {@code >= 0;} the new size
+     */
+    public void shrink(int newSize) {
+        if (newSize < 0) {
+            throw new IllegalArgumentException("newSize < 0");
+        }
+
+        if (newSize > size) {
+            throw new IllegalArgumentException("newSize > size");
+        }
+
+        throwIfImmutable();
+
+        size = newSize;
+    }
+
+    /**
+     * Makes and returns a mutable copy of the list.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public IntList mutableCopy() {
+        int sz = size;
+        IntList result = new IntList(sz);
+
+        for (int i = 0; i < sz; i++) {
+            result.add(values[i]);
+        }
+
+        return result;
+    }
+
+    /**
+     * Sorts the elements in the list in-place.
+     */
+    public void sort() {
+        throwIfImmutable();
+
+        if (!sorted) {
+            Arrays.sort(values, 0, size);
+            sorted = true;
+        }
+    }
+
+    /**
+     * Returns the index of the given value, or -1 if the value does not
+     * appear in the list.  This will do a binary search if the list is
+     * sorted or a linear search if not.
+     *
+     * @param value value to find
+     * @return index of value or -1
+     */
+    public int indexOf(int value) {
+        int ret = binarysearch(value);
+
+        return ret >= 0 ? ret : -1;
+
+    }
+
+    /**
+     * Performs a binary search on a sorted list, returning the index of
+     * the given value if it is present or
+     * {@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()} if the element is not found.
+     *
+     * @param value value to find
+     * @return index of value or {@code (-(insertion point) - 1)} if the
+     * value is not present
+     */
+    public int binarysearch(int value) {
+        int sz = size;
+
+        if (!sorted) {
+            // Linear search.
+            for (int i = 0; i < sz; i++) {
+                if (values[i] == value) {
+                    return i;
+                }
+            }
+
+            return -sz;
+        }
+
+        /*
+         * Binary search. This variant does only one value comparison
+         * per iteration but does one more iteration on average than
+         * the variant that includes a value equality check per
+         * iteration.
+         */
+
+        int min = -1;
+        int max = sz;
+
+        while (max > (min + 1)) {
+            /*
+             * The guessIdx calculation is equivalent to ((min + max)
+             * / 2) but won't go wonky when min and max are close to
+             * Integer.MAX_VALUE.
+             */
+            int guessIdx = min + ((max - min) >> 1);
+            int guess = values[guessIdx];
+
+            if (value <= guess) {
+                max = guessIdx;
+            } else {
+                min = guessIdx;
+            }
+        }
+
+        if ((max != sz)) {
+            return (value == values[max]) ? max : (-max - 1);
+        } else {
+            return -sz - 1;
+        }
+    }
+
+
+    /**
+     * Returns whether or not the given value appears in the list.
+     * This will do a binary search if the list is sorted or a linear
+     * search if not.
+     *
+     * @see #sort
+     *
+     * @param value value to look for
+     * @return whether the list contains the given value
+     */
+    public boolean contains(int value) {
+        return indexOf(value) >= 0;
+    }
+}
diff --git a/dx/src/com/android/dx/util/IntSet.java b/dx/src/com/android/dx/util/IntSet.java
new file mode 100644
index 0000000..33b6bdd
--- /dev/null
+++ b/dx/src/com/android/dx/util/IntSet.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * A set of integers
+ */
+public interface IntSet {
+
+    /**
+     * Adds an int to a set
+     *
+     * @param value int to add
+     */
+    void add(int value);
+
+    /**
+     * Removes an int from a set.
+     *
+     * @param value int to remove
+     */
+    void remove(int value);
+
+    /**
+     * Checks to see if a value is in the set
+     *
+     * @param value int to check
+     * @return true if in set
+     */
+    boolean has(int value);
+
+    /**
+     * Merges {@code other} into this set, so this set becomes the
+     * union of the two.
+     *
+     * @param other {@code non-null;} other set to merge with.
+     */
+    void merge(IntSet other);
+
+    /**
+     * Returns the count of unique elements in this set.
+     *
+     * @return {@code > = 0;} count of unique elements
+     */
+    int elements();
+
+    /**
+     * Iterates the set
+     *
+     * @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
new file mode 100644
index 0000000..b4856cf
--- /dev/null
+++ b/dx/src/com/android/dx/util/LabeledItem.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * An item that has an integer label.
+ */
+public interface LabeledItem {
+
+    /*
+     * Gets the label of this block.
+     *
+     * @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
new file mode 100644
index 0000000..963b5aa
--- /dev/null
+++ b/dx/src/com/android/dx/util/LabeledList.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.util.Arrays;
+
+/**
+ * A list of labeled items, allowing easy lookup by label.
+ */
+public class LabeledList extends FixedSizeList {
+    /**
+     * Sparse array indexed by label to FixedSizeList index;
+     * {@code -1} for an invalid label.
+     */
+    private final IntList labelToIndex;
+
+    /** @inheritDoc */
+    public LabeledList(int size) {
+        super(size);
+
+        labelToIndex = new IntList(size);
+    }
+
+    /**
+     * Constructs a new instance that is a copy of the old instance.
+     *
+     * @param old instance to copy
+     */
+    public LabeledList(LabeledList old) {
+        super(old.size());
+        labelToIndex = old.labelToIndex.mutableCopy();
+
+        int sz = old.size();
+
+        for (int i = 0; i < sz; i++) {
+            Object one = old.get0(i);
+            if (one != null) {
+                set0(i, one);
+            }
+        }
+    }
+
+    /**
+     * Gets the maximum label (exclusive) of any block added to this instance.
+     *
+     * @return {@code >= 0;} the maximum label
+     */
+    public final int getMaxLabel() {
+        int sz = labelToIndex.size();
+
+        // Gobble any deleted labels that may be at the end.
+        int i;
+        for (i = sz - 1; (i >= 0) && (labelToIndex.get(i) < 0); i--)
+            /*empty*/ ;
+
+        int newSize = i + 1;
+
+        labelToIndex.shrink(newSize);
+
+        return newSize;
+    }
+
+    /**
+     * Removes a label from the label-to-index mapping.
+     *
+     * @param oldLabel label to remove
+     */
+    private void removeLabel(int oldLabel) {
+        labelToIndex.set(oldLabel, -1);
+    }
+
+    /**
+     * Adds a label and index to the label-to-index mapping.
+     *
+     * @param label new label
+     * @param index index of block.
+     */
+    private void addLabelIndex(int label, int index) {
+        int origSz = labelToIndex.size();
+
+        for (int i = 0; i <= (label - origSz); i++) {
+            labelToIndex.add(-1);
+        }
+
+        labelToIndex.set(label, index);
+    }
+
+    /**
+     * Gets the index of the first item in the list with the given
+     * label, if any.
+     *
+     * @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 final int indexOfLabel(int label) {
+        if (label >= labelToIndex.size()) {
+            return -1;
+        } else {
+            return labelToIndex.get(label);
+        }
+    }
+
+    /**
+     * Gets an array containing all of the labels used in this instance,
+     * in order. The returned array is freshly-allocated and so may be
+     * modified safely by the caller without impacting this instance.
+     *
+     * @return {@code non-null;} ordered array of labels
+     * @throws NullPointerException thrown if there are any {@code null}
+     * items in this instance
+     */
+    public final int[] getLabelsInOrder() {
+        int sz = size();
+        int[] result = new int[sz];
+
+        for (int i = 0; i < sz; i++) {
+            LabeledItem li = (LabeledItem) get0(i);
+            if (li == null) {
+                throw new NullPointerException("null at index " + i);
+            }
+            result[i] = li.getLabel();
+        }
+
+        Arrays.sort(result);
+        return result;
+    }
+
+    /** @inheritDoc */
+    @Override
+    public void shrinkToFit() {
+        super.shrinkToFit();
+
+        rebuildLabelToIndex();
+    }
+
+    /**
+     * Rebuilds the label-to-index mapping after a {@code shrinkToFit()}.
+     * Note: This assumes that the labels that are in the list are the
+     * same, although the indicies may have changed.
+     */
+    private void rebuildLabelToIndex() {
+        int szItems = size();
+
+        for (int i = 0; i < szItems; i++) {
+            LabeledItem li = (LabeledItem) get0(i);
+
+            if (li != null) {
+                labelToIndex.set(li.getLabel(), i);
+            }
+        }
+    }
+
+    /**
+     * Sets the element at the given index.
+     *
+     * @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);
+
+        set0(n, item);
+
+        if (old != null) {
+            removeLabel(old.getLabel());
+        }
+
+        if (item != null) {
+            addLabelIndex(item.getLabel(), n);
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/util/Leb128Utils.java b/dx/src/com/android/dx/util/Leb128Utils.java
new file mode 100644
index 0000000..1037463
--- /dev/null
+++ b/dx/src/com/android/dx/util/Leb128Utils.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Reads and writes DWARFv3 LEB 128 signed and unsigned integers. See DWARF v3
+ * section 7.6.
+ */
+public final class Leb128Utils {
+    /**
+     * This class is uninstantiable.
+     */
+    private Leb128Utils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Gets the number of bytes in the unsigned LEB128 encoding of the
+     * given value.
+     *
+     * @param value the value in question
+     * @return its write size, in bytes
+     */
+    public static int unsignedLeb128Size(int value) {
+        // TODO: This could be much cleverer.
+
+        int remaining = value >> 7;
+        int count = 0;
+
+        while (remaining != 0) {
+            remaining >>= 7;
+            count++;
+        }
+
+        return count + 1;
+    }
+
+    /**
+     * Gets the number of bytes in the signed LEB128 encoding of the
+     * given value.
+     *
+     * @param value the value in question
+     * @return its write size, in bytes
+     */
+    public static int signedLeb128Size(int value) {
+        // TODO: This could be much cleverer.
+
+        int remaining = value >> 7;
+        int count = 0;
+        boolean hasMore = true;
+        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
+
+        while (hasMore) {
+            hasMore = (remaining != end)
+                || ((remaining & 1) != ((value >> 6) & 1));
+
+            value = remaining;
+            remaining >>= 7;
+            count++;
+        }
+
+        return count;
+    }
+
+    /**
+     * Reads an signed integer from {@code in}.
+     */
+    public static int readSignedLeb128(ByteInput in) {
+        int result = 0;
+        int cur;
+        int count = 0;
+        int signBits = -1;
+
+        do {
+            cur = in.readByte() & 0xff;
+            result |= (cur & 0x7f) << (count * 7);
+            signBits <<= 7;
+            count++;
+        } while (((cur & 0x80) == 0x80) && count < 5);
+
+        if ((cur & 0x80) == 0x80) {
+            throw new DexException("invalid LEB128 sequence");
+        }
+
+        // Sign extend if appropriate
+        if (((signBits >> 1) & result) != 0 ) {
+            result |= signBits;
+        }
+
+        return result;
+    }
+
+    /**
+     * Reads an unsigned integer from {@code in}.
+     */
+    public static int readUnsignedLeb128(ByteInput in) {
+        int result = 0;
+        int cur;
+        int count = 0;
+
+        do {
+            cur = in.readByte() & 0xff;
+            result |= (cur & 0x7f) << (count * 7);
+            count++;
+        } while (((cur & 0x80) == 0x80) && count < 5);
+
+        if ((cur & 0x80) == 0x80) {
+            throw new DexException("invalid LEB128 sequence");
+        }
+
+        return result;
+    }
+
+    /**
+     * Writes {@code value} as an unsigned integer to {@code out}, starting at
+     * {@code offset}. Returns the number of bytes written.
+     */
+    public static void writeUnsignedLeb128(ByteOutput out, int value) {
+        int remaining = value >>> 7;
+
+        while (remaining != 0) {
+            out.writeByte((byte) ((value & 0x7f) | 0x80));
+            value = remaining;
+            remaining >>>= 7;
+        }
+
+        out.writeByte((byte) (value & 0x7f));
+    }
+
+    /**
+     * Writes {@code value} as a signed integer to {@code out}, starting at
+     * {@code offset}. Returns the number of bytes written.
+     */
+    public static void writeSignedLeb128(ByteOutput out, int value) {
+        int remaining = value >> 7;
+        boolean hasMore = true;
+        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
+
+        while (hasMore) {
+            hasMore = (remaining != end)
+                    || ((remaining & 1) != ((value >> 6) & 1));
+
+            out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0)));
+            value = remaining;
+            remaining >>= 7;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/util/ListIntSet.java b/dx/src/com/android/dx/util/ListIntSet.java
new file mode 100644
index 0000000..2b4fc21
--- /dev/null
+++ b/dx/src/com/android/dx/util/ListIntSet.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.util.NoSuchElementException;
+
+/**
+ * A set of integers, represented by a list
+ */
+public class ListIntSet implements IntSet {
+
+    /** also accessed in BitIntSet */
+    final IntList ints;
+
+    /**
+     * Constructs an instance
+     */
+    public ListIntSet() {
+        ints = new IntList();
+        ints.sort();
+    }
+
+    /** @inheritDoc */
+    public void add(int value) {
+        int index = ints.binarysearch(value);
+
+        if (index < 0) {
+            ints.insert(-(index + 1), value);
+        }
+    }
+
+    /** @inheritDoc */
+    public void remove(int value) {
+        int index = ints.indexOf(value);
+
+        if (index >= 0) {
+            ints.removeIndex(index);
+        }
+    }
+
+    /** @inheritDoc */
+    public boolean has(int value) {
+        return ints.indexOf(value) >= 0;
+    }
+
+    /** @inheritDoc */
+    public void merge(IntSet other) {
+        if (other instanceof ListIntSet) {
+            ListIntSet o = (ListIntSet) other;
+            int szThis = ints.size();
+            int szOther = o.ints.size();
+
+            int i = 0;
+            int j = 0;
+
+            while (j < szOther && i < szThis) {
+                while (j < szOther && o.ints.get(j) < ints.get(i)) {
+                    add(o.ints.get(j++));
+                }
+                if (j == szOther) {
+                    break;
+                }
+                while (i < szThis && o.ints.get(j) >= ints.get(i)) {
+                    i++;
+                }
+            }
+
+            while (j < szOther) {
+                add(o.ints.get(j++));
+            }
+
+            ints.sort();
+        } else if (other instanceof BitIntSet) {
+            BitIntSet o = (BitIntSet) other;
+
+            for (int i = 0; i >= 0; i = Bits.findFirst(o.bits, i + 1)) {
+                ints.add(i);
+            }
+            ints.sort();
+        } else {
+            IntIterator iter = other.iterator();
+            while (iter.hasNext()) {
+                add(iter.next());
+            }
+        }
+    }
+
+    /** @inheritDoc */
+    public int elements() {
+        return ints.size();
+    }
+
+    /** @inheritDoc */
+    public IntIterator iterator() {
+        return new IntIterator() {
+            private int idx = 0;
+
+            /** @inheritDoc */
+            public boolean hasNext() {
+                return idx < ints.size();
+            }
+
+            /** @inheritDoc */
+            public int next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                return ints.get(idx++);
+            }
+        };
+    }
+
+    /** @inheritDoc */
+    public String toString() {
+        return ints.toString();
+    }
+}
diff --git a/dx/src/com/android/dx/util/MutabilityControl.java b/dx/src/com/android/dx/util/MutabilityControl.java
new file mode 100644
index 0000000..14e0f2e
--- /dev/null
+++ b/dx/src/com/android/dx/util/MutabilityControl.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Very simple base class that implements a flag to control the mutability
+ * of instances. This class just provides the flag and a utility to check
+ * and throw the right exception, but it is up to subclasses to place calls
+ * to the checker in all the right places.
+ */
+public class MutabilityControl {
+    /** whether this instance is mutable */
+    private boolean mutable;
+
+    /**
+     * Constructs an instance. It is initially mutable.
+     */
+    public MutabilityControl() {
+        mutable = true;
+    }
+
+    /**
+     * Constructs an instance, explicitly indicating the mutability.
+     *
+     * @param mutable {@code true} iff this instance is mutable
+     */
+    public MutabilityControl(boolean mutable) {
+        this.mutable = mutable;
+    }
+
+    /**
+     * Makes this instance immutable.
+     */
+    public void setImmutable() {
+        mutable = false;
+    }
+
+    /**
+     * Checks to see whether or not this instance is immutable. This is the
+     * same as calling {@code !isMutable()}.
+     *
+     * @return {@code true} iff this instance is immutable
+     */
+    public final boolean isImmutable() {
+        return !mutable;
+    }
+
+    /**
+     * Checks to see whether or not this instance is mutable.
+     *
+     * @return {@code true} iff this instance is mutable
+     */
+    public final boolean isMutable() {
+        return mutable;
+    }
+
+    /**
+     * Throws {@link MutabilityException} if this instance is
+     * immutable.
+     */
+    public final void throwIfImmutable() {
+        if (!mutable) {
+            throw new MutabilityException("immutable instance");
+        }
+    }
+
+    /**
+     * Throws {@link MutabilityException} if this instance is mutable.
+     */
+    public final void throwIfMutable() {
+        if (mutable) {
+            throw new MutabilityException("mutable instance");
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/util/MutabilityException.java b/dx/src/com/android/dx/util/MutabilityException.java
new file mode 100644
index 0000000..bd21651
--- /dev/null
+++ b/dx/src/com/android/dx/util/MutabilityException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Exception due to a mutability problem.
+ */
+public class MutabilityException
+        extends ExceptionWithContext {
+    public MutabilityException(String message) {
+        super(message);
+    }
+
+    public MutabilityException(Throwable cause) {
+        super(cause);
+    }
+
+    public MutabilityException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/dx/src/com/android/dx/util/Mutf8.java b/dx/src/com/android/dx/util/Mutf8.java
new file mode 100644
index 0000000..fe55724
--- /dev/null
+++ b/dx/src/com/android/dx/util/Mutf8.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.UTFDataFormatException;
+
+/**
+ * Modified UTF-8 as described in the dex file format spec.
+ *
+ * <p>Derived from libcore's MUTF-8 encoder at java.nio.charset.ModifiedUtf8.
+ */
+public final class Mutf8 {
+    private Mutf8() {}
+
+    /**
+     * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is
+     * encountered. Returns a new string containing the decoded characters.
+     */
+    public static String decode(ByteInput in, char[] out) throws UTFDataFormatException {
+        int s = 0;
+        while (true) {
+            char a = (char) (in.readByte() & 0xff);
+            if (a == 0) {
+                return new String(out, 0, s);
+            }
+            out[s] = a;
+            if (a < '\u0080') {
+                s++;
+            } else if ((a & 0xe0) == 0xc0) {
+                int b = in.readByte() & 0xff;
+                if ((b & 0xC0) != 0x80) {
+                    throw new UTFDataFormatException("bad second byte");
+                }
+                out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
+            } else if ((a & 0xf0) == 0xe0) {
+                int b = in.readByte() & 0xff;
+                int c = in.readByte() & 0xff;
+                if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
+                    throw new UTFDataFormatException("bad second or third byte");
+                }
+                out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
+            } else {
+                throw new UTFDataFormatException("bad byte");
+            }
+        }
+    }
+
+    /**
+     * Returns the number of bytes the modified UTF8 representation of 's' would take.
+     */
+    private static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
+        long result = 0;
+        final int length = s.length();
+        for (int i = 0; i < length; ++i) {
+            char ch = s.charAt(i);
+            if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
+                ++result;
+            } else if (ch <= 2047) {
+                result += 2;
+            } else {
+                result += 3;
+            }
+            if (shortLength && result > 65535) {
+                throw new UTFDataFormatException("String more than 65535 UTF bytes long");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Encodes the modified UTF-8 bytes corresponding to {@code s} into  {@code
+     * dst}, starting at {@code offset}.
+     */
+    public static void encode(byte[] dst, int offset, String s) {
+        final int length = s.length();
+        for (int i = 0; i < length; i++) {
+            char ch = s.charAt(i);
+            if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
+                dst[offset++] = (byte) ch;
+            } else if (ch <= 2047) {
+                dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6)));
+                dst[offset++] = (byte) (0x80 | (0x3f & ch));
+            } else {
+                dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12)));
+                dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6)));
+                dst[offset++] = (byte) (0x80 | (0x3f & ch));
+            }
+        }
+    }
+
+    /**
+     * Returns an array containing the <i>modified UTF-8</i> form of {@code s}.
+     */
+    public static byte[] encode(String s) throws UTFDataFormatException {
+        int utfCount = (int) countBytes(s, true);
+        byte[] result = new byte[utfCount];
+        encode(result, 0, s);
+        return result;
+    }
+}
diff --git a/dx/src/com/android/dx/util/Output.java b/dx/src/com/android/dx/util/Output.java
new file mode 100644
index 0000000..e5956a2
--- /dev/null
+++ b/dx/src/com/android/dx/util/Output.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Interface for a sink for binary output. This is similar to
+ * {@code java.util.DataOutput}, but no {@code IOExceptions}
+ * are declared, and multibyte output is defined to be little-endian.
+ */
+public interface Output extends ByteOutput {
+    /**
+     * Gets the current cursor position. This is the same as the number of
+     * bytes written to this instance.
+     *
+     * @return {@code >= 0;} the cursor position
+     */
+    public int getCursor();
+
+    /**
+     * Asserts that the cursor is the given value.
+     *
+     * @param expectedCursor the expected cursor value
+     * @throws RuntimeException thrown if {@code getCursor() !=
+     * expectedCursor}
+     */
+    public void assertCursor(int expectedCursor);
+
+    /**
+     * Writes a {@code byte} to this instance.
+     *
+     * @param value the value to write; all but the low 8 bits are ignored
+     */
+    public void writeByte(int value);
+
+    /**
+     * Writes a {@code short} to this instance.
+     *
+     * @param value the value to write; all but the low 16 bits are ignored
+     */
+    public void writeShort(int value);
+
+    /**
+     * Writes an {@code int} to this instance.
+     *
+     * @param value the value to write
+     */
+    public void writeInt(int value);
+
+    /**
+     * Writes a {@code long} to this instance.
+     *
+     * @param value the value to write
+     */
+    public void writeLong(long value);
+
+    /**
+     * Writes a DWARFv3-style unsigned LEB128 integer. For details,
+     * see the "Dalvik Executable Format" document or DWARF v3 section
+     * 7.6.
+     *
+     * @param value value to write, treated as an unsigned value
+     * @return {@code 1..5;} the number of bytes actually written
+     */
+    public int writeUleb128(int value);
+
+    /**
+     * Writes a DWARFv3-style unsigned LEB128 integer. For details,
+     * see the "Dalvik Executable Format" document or DWARF v3 section
+     * 7.6.
+     *
+     * @param value value to write
+     * @return {@code 1..5;} the number of bytes actually written
+     */
+    public int writeSleb128(int value);
+
+    /**
+     * Writes a {@link ByteArray} to this instance.
+     *
+     * @param bytes {@code non-null;} the array to write
+     */
+    public void write(ByteArray bytes);
+
+    /**
+     * Writes a portion of a {@code byte[]} to this instance.
+     *
+     * @param bytes {@code non-null;} the array to write
+     * @param offset {@code >= 0;} offset into {@code bytes} for the first
+     * byte to write
+     * @param length {@code >= 0;} number of bytes to write
+     */
+    public void write(byte[] bytes, int offset, int length);
+
+    /**
+     * Writes a {@code byte[]} to this instance. This is just
+     * a convenient shorthand for {@code write(bytes, 0, bytes.length)}.
+     *
+     * @param bytes {@code non-null;} the array to write
+     */
+    public void write(byte[] bytes);
+
+    /**
+     * Writes the given number of {@code 0} bytes.
+     *
+     * @param count {@code >= 0;} the number of zeroes to write
+     */
+    public void writeZeroes(int count);
+
+    /**
+     * Adds extra bytes if necessary (with value {@code 0}) to
+     * force alignment of the output cursor as given.
+     *
+     * @param alignment {@code > 0;} the alignment; must be a power of two
+     */
+    public void alignTo(int alignment);
+}
diff --git a/dx/src/com/android/dx/util/ToHuman.java b/dx/src/com/android/dx/util/ToHuman.java
new file mode 100644
index 0000000..b3a31a5
--- /dev/null
+++ b/dx/src/com/android/dx/util/ToHuman.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Simple interface for objects that can return a "human" (as opposed to
+ * a complete but often hard to read) string form.
+ */
+public interface ToHuman {
+    /**
+     * Return the "human" string form of this instance.  This is
+     * generally less "debuggy" than {@code toString()}.
+     *
+     * @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
new file mode 100644
index 0000000..ed2ab9f
--- /dev/null
+++ b/dx/src/com/android/dx/util/TwoColumnOutput.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+
+/**
+ * Class that takes a combined output destination and provides two
+ * output writers, one of which ends up writing to the left column and
+ * one which goes on the right.
+ */
+public final class TwoColumnOutput {
+    /** {@code non-null;} underlying writer for final output */
+    private final Writer out;
+
+    /** {@code > 0;} the left column width */
+    private final int leftWidth;
+
+    /** {@code non-null;} pending left column output */
+    private final StringBuffer leftBuf;
+
+    /** {@code non-null;} pending right column output */
+    private final StringBuffer rightBuf;
+
+    /** {@code non-null;} left column writer */
+    private final IndentingWriter leftColumn;
+
+    /** {@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 {@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) {
+        int len1 = s1.length();
+        int len2 = s2.length();
+
+        StringWriter sw = new StringWriter((len1 + len2) * 3);
+        TwoColumnOutput twoOut =
+            new TwoColumnOutput(sw, width1, width2, spacer);
+
+        try {
+            twoOut.getLeft().write(s1);
+            twoOut.getRight().write(s2);
+        } catch (IOException ex) {
+            throw new RuntimeException("shouldn't happen", ex);
+        }
+
+        twoOut.flush();
+        return sw.toString();
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param out {@code non-null;} writer to send final output to
+     * @param leftWidth {@code > 0;} width of the left column, in characters
+     * @param rightWidth {@code > 0;} width of the right column, in characters
+     * @param spacer {@code non-null;} spacer string to sit between the two columns
+     */
+    public TwoColumnOutput(Writer out, int leftWidth, int rightWidth,
+                           String spacer) {
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        }
+
+        if (leftWidth < 1) {
+            throw new IllegalArgumentException("leftWidth < 1");
+        }
+
+        if (rightWidth < 1) {
+            throw new IllegalArgumentException("rightWidth < 1");
+        }
+
+        if (spacer == null) {
+            throw new NullPointerException("spacer == null");
+        }
+
+        StringWriter leftWriter = new StringWriter(1000);
+        StringWriter rightWriter = new StringWriter(1000);
+
+        this.out = out;
+        this.leftWidth = leftWidth;
+        this.leftBuf = leftWriter.getBuffer();
+        this.rightBuf = rightWriter.getBuffer();
+        this.leftColumn = new IndentingWriter(leftWriter, leftWidth);
+        this.rightColumn =
+            new IndentingWriter(rightWriter, rightWidth, spacer);
+    }
+
+    /**
+     * Constructs an instance.
+     *
+     * @param out {@code non-null;} stream to send final output to
+     * @param leftWidth {@code >= 1;} width of the left column, in characters
+     * @param rightWidth {@code >= 1;} width of the right column, in characters
+     * @param spacer {@code non-null;} spacer string to sit between the two columns
+     */
+    public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth,
+                           String spacer) {
+        this(new OutputStreamWriter(out), leftWidth, rightWidth, spacer);
+    }
+
+    /**
+     * Gets the writer to use to write to the left column.
+     *
+     * @return {@code non-null;} the left column writer
+     */
+    public Writer getLeft() {
+        return leftColumn;
+    }
+
+    /**
+     * Gets the writer to use to write to the right column.
+     *
+     * @return {@code non-null;} the right column writer
+     */
+    public Writer getRight() {
+        return rightColumn;
+    }
+
+    /**
+     * Flushes the output. If there are more lines of pending output in one
+     * column, then the other column will get filled with blank lines.
+     */
+    public void flush() {
+        try {
+            appendNewlineIfNecessary(leftBuf, leftColumn);
+            appendNewlineIfNecessary(rightBuf, rightColumn);
+            outputFullLines();
+            flushLeft();
+            flushRight();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Outputs to the final destination as many full line pairs as
+     * there are in the pending output, removing those lines from
+     * their respective buffers. This method terminates when at
+     * least one of the two column buffers is empty.
+     */
+    private void outputFullLines() throws IOException {
+        for (;;) {
+            int leftLen = leftBuf.indexOf("\n");
+            if (leftLen < 0) {
+                return;
+            }
+
+            int rightLen = rightBuf.indexOf("\n");
+            if (rightLen < 0) {
+                return;
+            }
+
+            if (leftLen != 0) {
+                out.write(leftBuf.substring(0, leftLen));
+            }
+
+            if (rightLen != 0) {
+                writeSpaces(out, leftWidth - leftLen);
+                out.write(rightBuf.substring(0, rightLen));
+            }
+
+            out.write('\n');
+
+            leftBuf.delete(0, leftLen + 1);
+            rightBuf.delete(0, rightLen + 1);
+        }
+    }
+
+    /**
+     * Flushes the left column buffer, printing it and clearing the buffer.
+     * If the buffer is already empty, this does nothing.
+     */
+    private void flushLeft() throws IOException {
+        appendNewlineIfNecessary(leftBuf, leftColumn);
+
+        while (leftBuf.length() != 0) {
+            rightColumn.write('\n');
+            outputFullLines();
+        }
+    }
+
+    /**
+     * Flushes the right column buffer, printing it and clearing the buffer.
+     * If the buffer is already empty, this does nothing.
+     */
+    private void flushRight() throws IOException {
+        appendNewlineIfNecessary(rightBuf, rightColumn);
+
+        while (rightBuf.length() != 0) {
+            leftColumn.write('\n');
+            outputFullLines();
+        }
+    }
+
+    /**
+     * Appends a newline to the given buffer via the given writer, but
+     * only if it isn't empty and doesn't already end with one.
+     *
+     * @param buf {@code non-null;} the buffer in question
+     * @param out {@code non-null;} the writer to use
+     */
+    private static void appendNewlineIfNecessary(StringBuffer buf,
+                                                 Writer out)
+            throws IOException {
+        int len = buf.length();
+
+        if ((len != 0) && (buf.charAt(len - 1) != '\n')) {
+            out.write('\n');
+        }
+    }
+
+    /**
+     * Writes the given number of spaces to the given writer.
+     *
+     * @param out {@code non-null;} where to write
+     * @param amt {@code >= 0;} the number of spaces to write
+     */
+    private static void writeSpaces(Writer out, int amt) throws IOException {
+        while (amt > 0) {
+            out.write(' ');
+            amt--;
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/util/Uint.java b/dx/src/com/android/dx/util/Uint.java
new file mode 100644
index 0000000..039756a
--- /dev/null
+++ b/dx/src/com/android/dx/util/Uint.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * An unsigned integer.
+ */
+public final class Uint implements Comparable<Uint> {
+    public final int intValue;
+
+    public Uint(int value) {
+        this.intValue = value;
+    }
+
+    public int compareTo(Uint uint) {
+        return Unsigned.compare(intValue, uint.intValue);
+    }
+}
diff --git a/dx/src/com/android/dx/util/Unsigned.java b/dx/src/com/android/dx/util/Unsigned.java
new file mode 100644
index 0000000..f15bd86
--- /dev/null
+++ b/dx/src/com/android/dx/util/Unsigned.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Unsigned arithmetic over Java's signed types.
+ */
+public final class Unsigned {
+    private Unsigned() {}
+
+    public static int compare(short ushortA, short ushortB) {
+        if (ushortA == ushortB) {
+            return 0;
+        }
+        int a = ushortA & 0xFFFF;
+        int b = ushortB & 0xFFFF;
+        return a < b ? -1 : 1;
+    }
+
+    public static int compare(int uintA, int uintB) {
+        if (uintA == uintB) {
+            return 0;
+        }
+        long a = uintA & 0xFFFFFFFFL;
+        long b = uintB & 0xFFFFFFFFL;
+        return a < b ? -1 : 1;
+    }
+}
diff --git a/dx/src/com/android/dx/util/Warning.java b/dx/src/com/android/dx/util/Warning.java
new file mode 100644
index 0000000..3c23c7c
--- /dev/null
+++ b/dx/src/com/android/dx/util/Warning.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+/**
+ * Exception which is meant to indicate a non-fatal warning.
+ */
+public class Warning extends RuntimeException {
+    /**
+     * Constructs an instance.
+     *
+     * @param message human-oriented message
+     */
+    public Warning(String message) {
+        super(message);
+    }
+}
diff --git a/dx/src/com/android/dx/util/Writers.java b/dx/src/com/android/dx/util/Writers.java
new file mode 100644
index 0000000..eba845c
--- /dev/null
+++ b/dx/src/com/android/dx/util/Writers.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Utilities for dealing with {@code Writer}s.
+ */
+public final class Writers {
+    /**
+     * This class is uninstantiable.
+     */
+    private Writers() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Makes a {@code PrintWriter} for the given {@code Writer},
+     * returning the given writer if it already happens to be the right
+     * class.
+     *
+     * @param writer {@code non-null;} writer to (possibly) wrap
+     * @return {@code non-null;} an appropriate instance
+     */
+    public static PrintWriter printWriterFor(Writer writer) {
+        if (writer instanceof PrintWriter) {
+            return (PrintWriter) writer;
+        }
+
+        return new PrintWriter(writer);
+    }
+}
diff --git a/dx/src/com/android/dx/util/_tests/_BitIntSet.java b/dx/src/com/android/dx/util/_tests/_BitIntSet.java
new file mode 100644
index 0000000..e26d7a4
--- /dev/null
+++ b/dx/src/com/android/dx/util/_tests/_BitIntSet.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util._tests;
+
+import com.android.dx.util.BitIntSet;
+import com.android.dx.util.IntIterator;
+import com.android.dx.util.ListIntSet;
+
+import junit.framework.TestCase;
+
+import java.util.NoSuchElementException;
+
+public class _BitIntSet extends TestCase {
+    public void test_basic() {
+        BitIntSet set = new BitIntSet(32);
+
+        assertEquals(0, set.elements());
+
+        set.add(0);
+        set.add(1);
+        set.add(31);
+
+        assertTrue(set.has(0));
+        assertTrue(set.has(1));
+        assertTrue(set.has(31));
+
+        assertEquals(3, set.elements());
+
+        assertFalse(set.has(2));
+        assertFalse(set.has(7));
+        assertFalse(set.has(30));
+    }
+
+    public void test_iterator() {
+        BitIntSet set = new BitIntSet(32);
+
+        set.add(0);
+        set.add(0);
+        set.add(1);
+        set.add(1);
+        set.add(31);
+        set.add(31);
+
+        IntIterator iter = set.iterator();
+
+        assertTrue(iter.hasNext());
+        assertEquals(iter.next(), 0);
+        assertTrue(iter.hasNext());
+        assertEquals(iter.next(), 1);
+        assertTrue(iter.hasNext());
+        assertEquals(iter.next(), 31);
+
+        assertFalse(iter.hasNext());
+
+        try {
+            iter.next();
+            fail();
+        } catch (NoSuchElementException ex) {
+            // exception excepted
+        }
+    }
+
+    public void test_remove() {
+        BitIntSet set = new BitIntSet(32);
+
+        set.add(0);
+        set.add(1);
+        set.add(31);
+
+        assertTrue(set.has(0));
+        assertTrue(set.has(1));
+        assertTrue(set.has(31));
+
+        assertFalse(set.has(2));
+        assertFalse(set.has(7));
+        assertFalse(set.has(30));
+
+        set.remove(0);
+
+        assertFalse(set.has(0));
+
+        assertTrue(set.has(1));
+        assertTrue(set.has(31));
+    }
+
+    /**
+     * Tests the auto-expansion of the set
+     */
+    public void test_expand() {
+        BitIntSet set = new BitIntSet(32);
+        int[] values = {0, 1, 31, 32, 128};
+
+        for (int i = 0; i < values.length; i++) {
+            set.add(values[i]);
+        }
+
+        IntIterator iter = set.iterator();
+
+        for (int i = 0; i < values.length; i++) {
+            assertTrue(iter.hasNext());
+            assertEquals(values[i], iter.next());
+        }
+        assertFalse(iter.hasNext());
+    }
+
+    public void test_merge() {
+        BitIntSet setA = new BitIntSet(32);
+        int[] valuesA = {0, 1, 31};
+
+        for (int i = 0; i < valuesA.length; i++) {
+            setA.add(valuesA[i]);
+        }
+
+        BitIntSet setB = new BitIntSet(32);
+        int[] valuesB = {0, 5, 6, 8, 31};
+
+        for (int i = 0; i < valuesB.length; i++) {
+            setB.add(valuesB[i]);
+        }
+
+        setA.merge(setB);
+
+        for (int i = 0; i < valuesA.length; i++) {
+            assertTrue(setA.has(valuesA[i]));
+        }
+
+        for (int i = 0; i < valuesB.length; i++) {
+            assertTrue(setA.has(valuesB[i]));
+        }
+    }
+
+    public void test_mergeWithListIntSet() {
+        BitIntSet setA = new BitIntSet(32);
+        int[] valuesA = {0, 1, 31};
+
+        for (int i = 0; i < valuesA.length; i++) {
+            setA.add(valuesA[i]);
+        }
+
+        ListIntSet setB = new ListIntSet();
+        int[] valuesB = {0, 5, 6, 8, 31};
+
+        for (int i = 0; i < valuesB.length; i++) {
+            setB.add(valuesB[i]);
+        }
+
+        setA.merge(setB);
+
+        for (int i = 0; i < valuesA.length; i++) {
+            assertTrue(setA.has(valuesA[i]));
+        }
+
+        for (int i = 0; i < valuesB.length; i++) {
+            assertTrue(setA.has(valuesB[i]));
+        }
+    }
+
+    public void test_mergeAndExpand() {
+        BitIntSet setA = new BitIntSet(32);
+        int[] valuesA = {0, 1, 31};
+
+        for (int i = 0; i < valuesA.length; i++) {
+            setA.add(valuesA[i]);
+        }
+
+        BitIntSet setB = new BitIntSet(32);
+        int[] valuesB = {0, 5, 6, 32, 127};
+
+        for (int i = 0; i < valuesB.length; i++) {
+            setB.add(valuesB[i]);
+        }
+
+        setA.merge(setB);
+
+        for (int i = 0; i < valuesA.length; i++) {
+            assertTrue(setA.has(valuesA[i]));
+        }
+
+        for (int i = 0; i < valuesB.length; i++) {
+            assertTrue(setA.has(valuesB[i]));
+        }
+    }
+
+    public void test_toString() {
+        BitIntSet set = new BitIntSet(32);
+
+        assertEquals(set.toString(), "{}");
+
+        set.add(1);
+
+        assertEquals(set.toString(), "{1}");
+
+        set.add(2);
+
+        assertEquals(set.toString(), "{1, 2}");
+    }
+}
diff --git a/dx/src/com/android/dx/util/_tests/_Bits.java b/dx/src/com/android/dx/util/_tests/_Bits.java
new file mode 100644
index 0000000..a95fc14
--- /dev/null
+++ b/dx/src/com/android/dx/util/_tests/_Bits.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util._tests;
+
+import com.android.dx.util.Bits;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the class {@code com.android.dx.util.Bits}.
+ */
+public class _Bits
+        extends TestCase {
+    public void test_makeBitSet() {
+        assertEquals(label(0), 0, Bits.makeBitSet(0).length);
+
+        for (int i = 1; i <= 32; i++) {
+            assertEquals(label(i), 1, Bits.makeBitSet(i).length);
+        }
+
+        for (int i = 33; i <= 64; i++) {
+            assertEquals(label(i), 2, Bits.makeBitSet(i).length);
+        }
+
+        for (int i = 65; i < 4000; i += 101) {
+            int expect = i >> 5;
+            if ((expect * 32) < i) {
+                expect++;
+            }
+            assertEquals(label(i), expect, Bits.makeBitSet(i).length);
+        }
+    }
+
+    public void test_getMax() {
+        for (int i = 0; i < 4000; i += 59) {
+            int expect = i >> 5;
+            if ((expect * 32) < i) {
+                expect++;
+            }
+            assertEquals(label(i), expect * 32,
+                         Bits.getMax(new int[expect]));
+        }
+    }
+
+    public void test1_get() {
+        int[] bits = Bits.makeBitSet(100);
+
+        for (int i = 0; i < 100; i++) {
+            assertFalse(label(i), Bits.get(bits, i));
+        }
+    }
+
+    public void test2_get() {
+        int[] bits = Bits.makeBitSet(100);
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = -1;
+        }
+
+        for (int i = 0; i < 100; i++) {
+            assertTrue(label(i), Bits.get(bits, i));
+        }
+    }
+
+    public void test3_get() {
+        int[] bits = Bits.makeBitSet(100);
+
+        for (int i = 0; i < 100; i++) {
+            Bits.set(bits, i, (i % 5) == 0);
+        }
+
+        for (int i = 0; i < 100; i++) {
+            boolean expect = (i % 5) == 0;
+            assertTrue(label(i), Bits.get(bits, i) == expect);
+        }
+    }
+
+    public void test1_set1() {
+        int[] bits = Bits.makeBitSet(50);
+        bits[1] = -1;
+
+        Bits.set(bits, 0, true);
+        Bits.set(bits, 3, true);
+        Bits.set(bits, 6, true);
+        Bits.set(bits, 3, false);
+        Bits.set(bits, 35, false);
+        Bits.set(bits, 38, false);
+        Bits.set(bits, 42, false);
+        Bits.set(bits, 38, true);
+
+        assertEquals(label(1), 0x41, bits[0]);
+        assertEquals(label(2), 0xfffffbf7, bits[1]);
+    }
+
+    public void test2_set1() {
+        int[] bits = Bits.makeBitSet(100);
+
+        for (int i = 0; i < 100; i++) {
+            if ((i % 3) == 0) {
+                Bits.set(bits, i, true);
+            }
+        }
+
+        for (int i = 0; i < 100; i++) {
+            if ((i % 5) == 0) {
+                Bits.set(bits, i, false);
+            }
+        }
+
+        for (int i = 0; i < 100; i++) {
+            if ((i % 7) == 0) {
+                Bits.set(bits, i, true);
+            }
+        }
+
+        for (int i = 0; i < 100; i++) {
+            boolean expect = ((i % 7) == 0) ||
+                (((i % 3) == 0) && ((i % 5) != 0));
+            assertTrue(label(i), Bits.get(bits, i) == expect);
+        }
+    }
+
+    public void test_set2() {
+        int[] bits = Bits.makeBitSet(100);
+
+        for (int i = 0; i < 100; i++) {
+            if ((i % 11) == 0) {
+                Bits.set(bits, i);
+            }
+        }
+
+        for (int i = 0; i < 100; i++) {
+            boolean expect = (i % 11) == 0;
+            assertTrue(label(i), Bits.get(bits, i) == expect);
+        }
+    }
+
+    public void test_clear() {
+        int[] bits = Bits.makeBitSet(100);
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = -1;
+        }
+
+        for (int i = 0; i < 100; i++) {
+            if ((i % 5) == 0) {
+                Bits.clear(bits, i);
+            }
+        }
+
+        for (int i = 0; i < 100; i++) {
+            boolean expect = (i % 5) != 0;
+            assertTrue(label(i), Bits.get(bits, i) == expect);
+        }
+    }
+
+    public void test1_isEmpty() {
+        for (int i = 0; i < 10; i++) {
+            assertTrue(label(i), Bits.isEmpty(new int[i]));
+        }
+    }
+
+    public void test2_isEmpty() {
+        for (int i = 1; i < 1000; i += 11) {
+            int[] bits = Bits.makeBitSet(i);
+            for (int j = i % 11; j >= 0; j--) {
+                int x = i - 1 - (j * 13);
+                if (x >= 0) {
+                    Bits.set(bits, x);
+                }
+            }
+            assertFalse(label(i), Bits.isEmpty(bits));
+        }
+    }
+
+    public void test1_bitCount() {
+        for (int i = 0; i < 10; i++) {
+            assertEquals(label(i), 0, Bits.bitCount(new int[i]));
+        }
+    }
+
+    public void test2_bitCount() {
+        for (int i = 1; i < 1000; i += 13) {
+            int[] bits = Bits.makeBitSet(i);
+            int count = 0;
+            for (int j = 0; j < i; j += 20) {
+                Bits.set(bits, j);
+                count++;
+            }
+            for (int j = 7; j < i; j += 11) {
+                if (!Bits.get(bits, j)) {
+                    Bits.set(bits, j);
+                    count++;
+                }
+            }
+            for (int j = 3; j < i; j += 17) {
+                if (!Bits.get(bits, j)) {
+                    Bits.set(bits, j);
+                    count++;
+                }
+            }
+            assertEquals(label(i), count, Bits.bitCount(bits));
+        }
+    }
+
+    public void test1_anyInRange() {
+        int[] bits = new int[100];
+
+        for (int i = 0; i < 100; i += 11) {
+            assertFalse(label(i), Bits.anyInRange(bits, 0, i));
+        }
+    }
+
+    public void test2_anyInRange() {
+        int[] bits = new int[100];
+
+        for (int i = 0; i < 100; i += 11) {
+            assertFalse(label(i), Bits.anyInRange(bits, i, 100));
+        }
+    }
+
+    public void test3_anyInRange() {
+        int[] bits = new int[100];
+
+        for (int i = 0; i < 50; i += 7) {
+            assertFalse(label(i), Bits.anyInRange(bits, i, 100 - i));
+        }
+    }
+
+    public void test4_anyInRange() {
+        int[] bits = new int[100];
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = -1;
+        }
+
+        for (int i = 1; i < 100; i += 11) {
+            assertTrue(label(i), Bits.anyInRange(bits, 0, i));
+        }
+    }
+
+    public void test5_anyInRange() {
+        int[] bits = new int[100];
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = -1;
+        }
+
+        for (int i = 1; i < 100; i += 11) {
+            assertTrue(label(i), Bits.anyInRange(bits, i, 100));
+        }
+    }
+
+    public void test6_anyInRange() {
+        int[] bits = new int[100];
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = -1;
+        }
+
+        for (int i = 0; i < 50; i += 7) {
+            assertTrue(label(i), Bits.anyInRange(bits, i, 100 - i));
+        }
+    }
+
+    public void test1_findFirst1() {
+        int[] bits = new int[100];
+
+        for (int i = 0; i < 100; i++) {
+            assertEquals(label(i), -1, Bits.findFirst(bits, i));
+        }
+    }
+
+    public void test2_findFirst1() {
+        int[] bits = new int[100];
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = -1;
+        }
+
+        for (int i = 0; i < 100; i++) {
+            assertEquals(label(i), i, Bits.findFirst(bits, i));
+        }
+    }
+
+    public void test3_findFirst1() {
+        int[] bits = new int[100];
+
+        for (int i = 25; i < 80; i++) {
+            for (int j = 0; j < bits.length; j++) {
+                bits[j] = 0;
+            }
+
+            Bits.set(bits, i - 5);
+            Bits.set(bits, i + 5);
+            Bits.set(bits, i + 10);
+            Bits.set(bits, i + 20);
+            assertEquals(label(i), i + 5, Bits.findFirst(bits, i));
+        }
+    }
+
+    public void test1_findFirst2() {
+        for (int i = 0; i < 32; i++) {
+            assertEquals(label(i), -1, Bits.findFirst(0, i));
+        }
+    }
+
+    public void test2_findFirst2() {
+        for (int i = 0; i < 32; i++) {
+            assertEquals(label(i), i, Bits.findFirst(-1, i));
+        }
+    }
+
+    public void test3_findFirst2() {
+        for (int i = 0; i < 32; i++) {
+            assertEquals(label(i), -1, Bits.findFirst((1 << i) >>> 1, i));
+        }
+    }
+
+    public void test4_findFirst2() {
+        for (int i = 0; i < 32; i++) {
+            assertEquals(label(i), i, Bits.findFirst(1 << i, i));
+        }
+    }
+
+    public void test5_findFirst2() {
+        for (int i = 0; i < 31; i++) {
+            assertEquals(label(i), i + 1, Bits.findFirst(1 << (i + 1), i));
+        }
+    }
+
+    public void test6_findFirst2() {
+        for (int i = 0; i < 32; i++) {
+            int value = (1 << i);
+            value |= (value >>> 1);
+            assertEquals(label(i), i, Bits.findFirst(value, i));
+        }
+    }
+
+    private static String label(int n) {
+        return "(" + n + ")";
+    }
+}
diff --git a/dx/src/com/android/dx/util/_tests/_IntList.java b/dx/src/com/android/dx/util/_tests/_IntList.java
new file mode 100644
index 0000000..dadbd54
--- /dev/null
+++ b/dx/src/com/android/dx/util/_tests/_IntList.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util._tests;
+
+import com.android.dx.util.IntList;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the class {@code com.android.dx.util.IntList}.
+ */
+public class _IntList
+    extends TestCase {
+    // TODO: Add tests for the rest of the methods.
+
+    public void test_contains() {
+        for (int sz = 0; sz < 100; sz++) {
+            IntList list = new IntList(sz);
+            for (int i = 0; i < sz; i++) {
+                list.add(i * 2);
+            }
+            for (int i = (sz * 2) - 1; i >= 0; i--) {
+                boolean contains = list.contains(i);
+                if ((i & 1) == 0) {
+                    assertTrue(label(sz, i), contains);
+                } else {
+                    assertFalse(label(sz, i), contains);
+                }
+            }
+            assertFalse(label(sz, -1), list.contains(-1));
+            assertFalse(label(sz, sz * 2), list.contains(sz * 2));
+        }
+    }
+
+    public void test_addSorted() {
+        IntList list = new IntList(2);
+
+        list.add(9);
+        list.add(12);
+
+        assertTrue(list.contains(9));
+        assertTrue(list.contains(12));
+    }
+
+    public void test_addUnsorted() {
+        IntList list = new IntList(2);
+
+        list.add(12);
+        list.add(9);
+
+        assertTrue(list.contains(12));
+        assertTrue(list.contains(9));
+    }
+
+    private static String label(int n, int m) {
+        return "(" + n + "/" + m + ")";
+    }
+}
diff --git a/dx/src/com/android/dx/util/_tests/_ListIntSet.java b/dx/src/com/android/dx/util/_tests/_ListIntSet.java
new file mode 100644
index 0000000..ccd5991
--- /dev/null
+++ b/dx/src/com/android/dx/util/_tests/_ListIntSet.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util._tests;
+
+import com.android.dx.util.BitIntSet;
+import com.android.dx.util.ListIntSet;
+import com.android.dx.util.IntIterator;
+
+import junit.framework.TestCase;
+
+import java.util.NoSuchElementException;
+
+public class _ListIntSet extends TestCase {
+    public void test_basic() {
+        ListIntSet set = new ListIntSet();
+
+        assertEquals(0, set.elements());
+
+        set.add(31);
+        set.add(0);
+        set.add(1);
+
+        assertTrue(set.has(0));
+        assertTrue(set.has(1));
+        assertTrue(set.has(31));
+
+        assertEquals(3, set.elements());
+
+        assertFalse(set.has(2));
+        assertFalse(set.has(7));
+        assertFalse(set.has(30));
+    }
+
+    public void test_iterator() {
+        ListIntSet set = new ListIntSet();
+
+        set.add(0);
+        set.add(0);
+        set.add(1);
+        set.add(1);
+        set.add(31);
+        set.add(31);
+
+        IntIterator iter = set.iterator();
+
+        assertTrue(iter.hasNext());
+        assertEquals(iter.next(), 0);
+        assertTrue(iter.hasNext());
+        assertEquals(iter.next(), 1);
+        assertTrue(iter.hasNext());
+        assertEquals(iter.next(), 31);
+
+        assertFalse(iter.hasNext());
+
+        try {
+            iter.next();
+            fail();
+        } catch (NoSuchElementException ex) {
+            // exception excepted
+        }
+    }
+
+    public void test_empty() {
+        ListIntSet set = new ListIntSet();
+
+        IntIterator iter = set.iterator();
+
+        assertFalse(iter.hasNext());
+    }
+
+    public void test_remove() {
+        ListIntSet set = new ListIntSet();
+
+        set.add(0);
+        set.add(1);
+        set.add(31);
+
+        assertTrue(set.has(0));
+        assertTrue(set.has(1));
+        assertTrue(set.has(31));
+
+        assertFalse(set.has(2));
+        assertFalse(set.has(7));
+        assertFalse(set.has(30));
+
+        set.remove(0);
+
+        assertFalse(set.has(0));
+
+        assertTrue(set.has(1));
+        assertTrue(set.has(31));
+    }
+
+    public void test_mergeA() {
+        ListIntSet setA = new ListIntSet();
+        int[] valuesA = {0, 1, 31};
+
+        for (int i = 0; i < valuesA.length; i++) {
+            setA.add(valuesA[i]);
+        }
+
+        ListIntSet setB = new ListIntSet();
+        int[] valuesB = {0, 5, 6, 32, 127, 128};
+
+        for (int i = 0; i < valuesB.length; i++) {
+            setB.add(valuesB[i]);
+        }
+
+        setA.merge(setB);
+
+        for (int i = 0; i < valuesA.length; i++) {
+            assertTrue(setA.has(valuesA[i]));
+        }
+
+        for (int i = 0; i < valuesB.length; i++) {
+            assertTrue(setA.has(valuesB[i]));
+        }
+
+    }
+
+    public void test_mergeB() {
+        ListIntSet setA = new ListIntSet();
+        int[] valuesA = {0, 1, 31, 129, 130};
+
+        for (int i = 0; i < valuesA.length; i++) {
+            setA.add(valuesA[i]);
+        }
+
+        ListIntSet setB = new ListIntSet();
+        int[] valuesB = {0, 5, 6, 32, 127,128};
+
+        for (int i = 0; i < valuesB.length; i++) {
+            setB.add(valuesB[i]);
+        }
+
+        setA.merge(setB);
+
+        for (int i = 0; i < valuesA.length; i++) {
+            assertTrue(setA.has(valuesA[i]));
+        }
+
+        for (int i = 0; i < valuesB.length; i++) {
+            assertTrue(setA.has(valuesB[i]));
+        }
+
+    }
+
+    public void test_mergeWithBitIntSet() {
+        ListIntSet setA = new ListIntSet();
+        int[] valuesA = {0, 1, 31, 129, 130};
+
+        for (int i = 0; i < valuesA.length; i++) {
+            setA.add(valuesA[i]);
+        }
+
+        BitIntSet setB = new BitIntSet(129);
+        int[] valuesB = {0, 5, 6, 32, 127,128};
+
+        for (int i = 0; i < valuesB.length; i++) {
+            setB.add(valuesB[i]);
+        }
+
+        setA.merge(setB);
+
+        for (int i = 0; i < valuesA.length; i++) {
+            assertTrue(setA.has(valuesA[i]));
+        }
+
+        for (int i = 0; i < valuesB.length; i++) {
+            assertTrue(setA.has(valuesB[i]));
+        }
+
+    }
+
+    public void test_toString() {
+        ListIntSet set = new ListIntSet();
+
+        assertEquals(set.toString(), "{}");
+
+        set.add(1);
+
+        assertEquals(set.toString(), "{1}");
+
+        set.add(2);
+
+        assertEquals(set.toString(), "{1, 2}");
+    }
+
+}
diff --git a/dx/src/com/android/dx/util/package.html b/dx/src/com/android/dx/util/package.html
new file mode 100644
index 0000000..8e81e94
--- /dev/null
+++ b/dx/src/com/android/dx/util/package.html
@@ -0,0 +1,3 @@
+<body>
+<p>Utility classes for class file access/manipulation.</p>
+</body>
diff --git a/dx/src/junit/extensions/ActiveTestSuite.java b/dx/src/junit/extensions/ActiveTestSuite.java
new file mode 100644
index 0000000..1a3f163
--- /dev/null
+++ b/dx/src/junit/extensions/ActiveTestSuite.java
@@ -0,0 +1,64 @@
+package junit.extensions;
+
+import junit.framework.*;
+
+/**
+ * A TestSuite for active Tests. It runs each
+ * test in a separate thread and waits until all
+ * threads have terminated.
+ * -- Aarhus Radisson Scandinavian Center 11th floor
+ */ 
+public class ActiveTestSuite extends TestSuite {
+	private volatile int fActiveTestDeathCount;
+
+	public ActiveTestSuite() {
+	}
+		
+	public ActiveTestSuite(Class theClass) {
+		super(theClass);
+	}
+	
+	public ActiveTestSuite(String name) {
+		super (name);
+	}
+	
+	public ActiveTestSuite(Class theClass, String name) {
+		super(theClass, name);
+	}
+	
+	public void run(TestResult result) {
+		fActiveTestDeathCount= 0;
+		super.run(result);
+		waitUntilFinished();
+	}
+	
+	public void runTest(final Test test, final TestResult result) {
+		Thread t= new Thread() {
+			public void run() {
+				try {
+					// inlined due to limitation in VA/Java 
+					//ActiveTestSuite.super.runTest(test, result);
+					test.run(result);
+				} finally {
+					ActiveTestSuite.this.runFinished(test);
+				}
+			}
+		};
+		t.start();
+	}
+
+	synchronized void waitUntilFinished() {
+		while (fActiveTestDeathCount < testCount()) {
+			try {
+				wait();
+			} catch (InterruptedException e) {
+				return; // ignore
+			}
+		}
+	}
+	
+	synchronized public void runFinished(Test test) {
+		fActiveTestDeathCount++;
+		notifyAll();
+	}
+}
diff --git a/dx/src/junit/extensions/ExceptionTestCase.java b/dx/src/junit/extensions/ExceptionTestCase.java
new file mode 100644
index 0000000..fae5746
--- /dev/null
+++ b/dx/src/junit/extensions/ExceptionTestCase.java
@@ -0,0 +1,46 @@
+package junit.extensions;
+
+import junit.framework.*;
+
+/**
+ * A TestCase that expects an Exception of class fExpected to be thrown.
+ * The other way to check that an expected exception is thrown is:
+ * <pre>
+ * try {
+ *   shouldThrow();
+ * }
+ * catch (SpecialException e) {
+ *   return;
+ * }
+ * fail("Expected SpecialException");
+ * </pre>
+ *
+ * To use ExceptionTestCase, create a TestCase like:
+ * <pre>
+ * new ExceptionTestCase("testShouldThrow", SpecialException.class);
+ * </pre>
+ */
+public class ExceptionTestCase extends TestCase {
+	Class<?> fExpected;
+
+	public ExceptionTestCase(String name, Class exception) {
+		super(name);
+		fExpected= exception;
+	}
+	/**
+	 * Execute the test method expecting that an Exception of
+	 * class fExpected or one of its subclasses will be thrown
+	 */
+	protected void runTest() throws Throwable {
+		try {
+			super.runTest();
+		}
+		catch (Exception e) {
+			if (fExpected.isAssignableFrom(e.getClass()))
+				return;
+			else
+				throw e;
+		}
+		fail("Expected exception " + fExpected);
+	}
+}
diff --git a/dx/src/junit/extensions/RepeatedTest.java b/dx/src/junit/extensions/RepeatedTest.java
new file mode 100644
index 0000000..ebce775
--- /dev/null
+++ b/dx/src/junit/extensions/RepeatedTest.java
@@ -0,0 +1,31 @@
+package junit.extensions;
+
+import junit.framework.*;
+
+/**
+ * A Decorator that runs a test repeatedly.
+ *
+ */
+public class RepeatedTest extends  TestDecorator {
+	private int fTimesRepeat;
+
+	public RepeatedTest(Test test, int repeat) {
+		super(test);
+		if (repeat < 0)
+			throw new IllegalArgumentException("Repetition count must be > 0");
+		fTimesRepeat= repeat;
+	}
+	public int countTestCases() {
+		return super.countTestCases()*fTimesRepeat;
+	}
+	public void run(TestResult result) {
+		for (int i= 0; i < fTimesRepeat; i++) {
+			if (result.shouldStop())
+				break;
+			super.run(result);
+		}
+	}
+	public String toString() {
+		return super.toString()+"(repeated)";
+	}
+}
diff --git a/dx/src/junit/extensions/TestDecorator.java b/dx/src/junit/extensions/TestDecorator.java
new file mode 100644
index 0000000..a8e9e7d
--- /dev/null
+++ b/dx/src/junit/extensions/TestDecorator.java
@@ -0,0 +1,38 @@
+package junit.extensions;
+
+import junit.framework.*;
+
+/**
+ * A Decorator for Tests. Use TestDecorator as the base class
+ * for defining new test decorators. Test decorator subclasses
+ * can be introduced to add behaviour before or after a test
+ * is run.
+ *
+ */
+public class TestDecorator extends Assert implements Test {
+	protected Test fTest;
+
+	public TestDecorator(Test test) {
+		fTest= test;
+	}
+	/**
+	 * The basic run behaviour.
+	 */
+	public void basicRun(TestResult result) {
+		fTest.run(result);
+	}
+	public int countTestCases() {
+		return fTest.countTestCases();
+	}
+	public void run(TestResult result) {
+		basicRun(result);
+	}
+
+	public String toString() {
+		return fTest.toString();
+	}
+
+	public Test getTest() {
+		return fTest;
+	}
+}
diff --git a/dx/src/junit/extensions/TestSetup.java b/dx/src/junit/extensions/TestSetup.java
new file mode 100644
index 0000000..f1c25fa
--- /dev/null
+++ b/dx/src/junit/extensions/TestSetup.java
@@ -0,0 +1,37 @@
+package junit.extensions;
+
+import junit.framework.*;
+
+/**
+ * A Decorator to set up and tear down additional fixture state.
+ * Subclass TestSetup and insert it into your tests when you want
+ * to set up additional state once before the tests are run.
+ */
+public class TestSetup extends TestDecorator {
+
+	public TestSetup(Test test) {
+		super(test);
+	}
+	public void run(final TestResult result) {
+		Protectable p= new Protectable() {
+			public void protect() throws Exception {
+				setUp();
+				basicRun(result);
+				tearDown();
+			}
+		};
+		result.runProtected(this, p);
+	}
+	/**
+	 * Sets up the fixture. Override to set up additional fixture
+	 * state.
+	 */
+	protected void setUp() throws Exception {
+	}
+	/**
+	 * Tears down the fixture. Override to tear down the additional
+	 * fixture state.
+	 */
+	protected void tearDown() throws Exception {
+	}
+}
diff --git a/dx/src/junit/framework/Assert.java b/dx/src/junit/framework/Assert.java
new file mode 100644
index 0000000..eb5d960
--- /dev/null
+++ b/dx/src/junit/framework/Assert.java
@@ -0,0 +1,291 @@
+package junit.framework;
+
+/**
+ * A set of assert methods.  Messages are only displayed when an assert fails.
+ */
+
+public class Assert {
+	/**
+	 * Protect constructor since it is a static only class
+	 */
+	protected Assert() {
+	}
+
+	/**
+	 * Asserts that a condition is true. If it isn't it throws
+	 * an AssertionFailedError with the given message.
+	 */
+	static public void assertTrue(String message, boolean condition) {
+		if (!condition)
+			fail(message);
+	}
+	/**
+	 * Asserts that a condition is true. If it isn't it throws
+	 * an AssertionFailedError.
+	 */
+	static public void assertTrue(boolean condition) {
+		assertTrue(null, condition);
+	}
+	/**
+	 * Asserts that a condition is false. If it isn't it throws
+	 * an AssertionFailedError with the given message.
+	 */
+	static public void assertFalse(String message, boolean condition) {
+		assertTrue(message, !condition);
+	}
+	/**
+	 * Asserts that a condition is false. If it isn't it throws
+	 * an AssertionFailedError.
+	 */
+	static public void assertFalse(boolean condition) {
+		assertFalse(null, condition);
+	}
+	/**
+	 * Fails a test with the given message.
+	 */
+	static public void fail(String message) {
+		throw new AssertionFailedError(message);
+	}
+	/**
+	 * Fails a test with no message.
+	 */
+	static public void fail() {
+		fail(null);
+	}
+	/**
+	 * Asserts that two objects are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, Object expected, Object actual) {
+		if (expected == null && actual == null)
+			return;
+		if (expected != null && expected.equals(actual))
+			return;
+		failNotEquals(message, expected, actual);
+	}
+	/**
+	 * Asserts that two objects are equal. If they are not
+	 * an AssertionFailedError is thrown.
+	 */
+	static public void assertEquals(Object expected, Object actual) {
+	    assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two Strings are equal. 
+	 */
+	static public void assertEquals(String message, String expected, String actual) {
+		if (expected == null && actual == null)
+			return;
+		if (expected != null && expected.equals(actual))
+			return;
+		throw new ComparisonFailure(message, expected, actual);
+	}
+	/**
+	 * Asserts that two Strings are equal. 
+	 */
+	static public void assertEquals(String expected, String actual) {
+	    assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two doubles are equal concerning a delta.  If they are not
+	 * an AssertionFailedError is thrown with the given message.  If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(String message, double expected, double actual, double delta) {
+		// handle infinity specially since subtracting to infinite values gives NaN and the
+		// the following test fails
+		if (Double.isInfinite(expected)) {
+			if (!(expected == actual))
+				failNotEquals(message, new Double(expected), new Double(actual));
+		} else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false
+			failNotEquals(message, new Double(expected), new Double(actual));
+	}
+	/**
+	 * Asserts that two doubles are equal concerning a delta. If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(double expected, double actual, double delta) {
+	    assertEquals(null, expected, actual, delta);
+	}
+	/**
+	 * Asserts that two floats are equal concerning a delta. If they are not
+	 * an AssertionFailedError is thrown with the given message.  If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(String message, float expected, float actual, float delta) {
+ 		// handle infinity specially since subtracting to infinite values gives NaN and the
+		// the following test fails
+		if (Float.isInfinite(expected)) {
+			if (!(expected == actual))
+				failNotEquals(message, new Float(expected), new Float(actual));
+		} else if (!(Math.abs(expected-actual) <= delta))
+      		failNotEquals(message, new Float(expected), new Float(actual));
+	}
+	/**
+	 * Asserts that two floats are equal concerning a delta. If the expected
+	 * value is infinity then the delta value is ignored.
+	 */
+	static public void assertEquals(float expected, float actual, float delta) {
+		assertEquals(null, expected, actual, delta);
+	}
+	/**
+	 * Asserts that two longs are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, long expected, long actual) {
+	    assertEquals(message, new Long(expected), new Long(actual));
+	}
+	/**
+	 * Asserts that two longs are equal.
+	 */
+	static public void assertEquals(long expected, long actual) {
+	    assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two booleans are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, boolean expected, boolean actual) {
+    		assertEquals(message, new Boolean(expected), new Boolean(actual));
+  	}
+	/**
+	 * Asserts that two booleans are equal.
+ 	 */
+	static public void assertEquals(boolean expected, boolean actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two bytes are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+  	static public void assertEquals(String message, byte expected, byte actual) {
+		assertEquals(message, new Byte(expected), new Byte(actual));
+	}
+	/**
+   	 * Asserts that two bytes are equal.
+	 */
+	static public void assertEquals(byte expected, byte actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two chars are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+  	static public void assertEquals(String message, char expected, char actual) {
+    		assertEquals(message, new Character(expected), new Character(actual));
+  	}
+	/**
+	 * Asserts that two chars are equal.
+	 */
+  	static public void assertEquals(char expected, char actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two shorts are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertEquals(String message, short expected, short actual) {
+    		assertEquals(message, new Short(expected), new Short(actual));
+	}
+  	/**
+	 * Asserts that two shorts are equal.
+	 */
+	static public void assertEquals(short expected, short actual) {
+		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that two ints are equal. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+  	static public void assertEquals(String message, int expected, int actual) {
+		assertEquals(message, new Integer(expected), new Integer(actual));
+  	}
+  	/**
+   	 * Asserts that two ints are equal.
+	 */
+  	static public void assertEquals(int expected, int actual) {
+  		assertEquals(null, expected, actual);
+	}
+	/**
+	 * Asserts that an object isn't null.
+	 */
+	static public void assertNotNull(Object object) {
+		assertNotNull(null, object);
+	}
+	/**
+	 * Asserts that an object isn't null. If it is
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertNotNull(String message, Object object) {
+		assertTrue(message, object != null);
+	}
+	/**
+	 * Asserts that an object is null.
+	 */
+	static public void assertNull(Object object) {
+		assertNull(null, object);
+	}
+	/**
+	 * Asserts that an object is null.  If it is not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertNull(String message, Object object) {
+		assertTrue(message, object == null);
+	}
+	/**
+	 * Asserts that two objects refer to the same object. If they are not
+	 * an AssertionFailedError is thrown with the given message.
+	 */
+	static public void assertSame(String message, Object expected, Object actual) {
+		if (expected == actual)
+			return;
+		failNotSame(message, expected, actual);
+	}
+	/**
+	 * Asserts that two objects refer to the same object. If they are not
+	 * the same an AssertionFailedError is thrown.
+	 */
+	static public void assertSame(Object expected, Object actual) {
+	    assertSame(null, expected, actual);
+	}
+ 	/**
+ 	 * Asserts that two objects refer to the same object. If they are not
+ 	 * an AssertionFailedError is thrown with the given message.
+ 	 */
+	static public void assertNotSame(String message, Object expected, Object actual) {
+		if (expected == actual)
+			failSame(message);
+	}
+	/**
+	 * Asserts that two objects refer to the same object. If they are not
+	 * the same an AssertionFailedError is thrown.
+	 */
+	static public void assertNotSame(Object expected, Object actual) {
+		assertNotSame(null, expected, actual);
+	}
+
+	static private void failSame(String message) {
+		String formatted= "";
+ 		if (message != null)
+ 			formatted= message+" ";
+ 		fail(formatted+"expected not same");
+	}
+
+	static private void failNotSame(String message, Object expected, Object actual) {
+		String formatted= "";
+		if (message != null)
+			formatted= message+" ";
+		fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
+	}
+
+	static private void failNotEquals(String message, Object expected, Object actual) {
+		fail(format(message, expected, actual));
+	}
+
+	static String format(String message, Object expected, Object actual) {
+		String formatted= "";
+		if (message != null)
+			formatted= message+" ";
+		return formatted+"expected:<"+expected+"> but was:<"+actual+">";
+	}
+}
diff --git a/dx/src/junit/framework/AssertionFailedError.java b/dx/src/junit/framework/AssertionFailedError.java
new file mode 100644
index 0000000..9aee001
--- /dev/null
+++ b/dx/src/junit/framework/AssertionFailedError.java
@@ -0,0 +1,13 @@
+package junit.framework;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends Error {
+
+	public AssertionFailedError () {
+	}
+	public AssertionFailedError (String message) {
+		super (message);
+	}
+}
diff --git a/dx/src/junit/framework/ComparisonFailure.java b/dx/src/junit/framework/ComparisonFailure.java
new file mode 100644
index 0000000..1bfe591
--- /dev/null
+++ b/dx/src/junit/framework/ComparisonFailure.java
@@ -0,0 +1,68 @@
+package junit.framework;
+
+/**
+ * Thrown when an assert equals for Strings failed.
+ * 
+ * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
+ */
+public class ComparisonFailure extends AssertionFailedError {
+	private String fExpected;
+	private String fActual;
+
+	/**
+	 * Constructs a comparison failure.
+	 * @param message the identifying message or null
+	 * @param expected the expected string value
+	 * @param actual the actual string value
+	 */
+	public ComparisonFailure (String message, String expected, String actual) {
+		super (message);
+		fExpected= expected;
+		fActual= actual;
+	}
+	
+	/**
+	 * Returns "..." in place of common prefix and "..." in
+	 * place of common suffix between expected and actual.
+	 * 
+	 * @see java.lang.Throwable#getMessage()
+	 */
+	public String getMessage() {
+		if (fExpected == null || fActual == null)
+			return Assert.format(super.getMessage(), fExpected, fActual);
+			
+		int end= Math.min(fExpected.length(), fActual.length());
+		
+		int i= 0;
+		for(; i < end; i++) {
+			if (fExpected.charAt(i) != fActual.charAt(i))
+				break;
+		}
+		int j= fExpected.length()-1;
+		int k= fActual.length()-1;
+		for (; k >= i && j >= i; k--,j--) {
+			if (fExpected.charAt(j) != fActual.charAt(k))
+				break;
+		}
+		String actual, expected;
+		
+		// equal strings
+		if (j < i && k < i) {
+			expected= fExpected;
+			actual= fActual;
+		} else {
+			expected= fExpected.substring(i, j+1);
+			actual= fActual.substring(i, k+1);
+			if (i <= end && i > 0) {
+				expected= "..."+expected;
+				actual= "..."+actual;
+			}
+			
+			if (j < fExpected.length()-1)
+				expected= expected+"...";
+			if (k < fActual.length()-1)
+				actual= actual+"...";
+		}	
+		return Assert.format(super.getMessage(), expected, actual);
+	}
+}
diff --git a/dx/src/junit/framework/Protectable.java b/dx/src/junit/framework/Protectable.java
new file mode 100644
index 0000000..8243555
--- /dev/null
+++ b/dx/src/junit/framework/Protectable.java
@@ -0,0 +1,14 @@
+package junit.framework;
+
+/**
+ * A <em>Protectable</em> can be run and can throw a Throwable.
+ *
+ * @see TestResult
+ */
+public interface Protectable {
+
+	/**
+	 * Run the the following method protected.
+	 */
+	public abstract void protect() throws Throwable;
+}
diff --git a/dx/src/junit/framework/Test.java b/dx/src/junit/framework/Test.java
new file mode 100644
index 0000000..1c6d57b
--- /dev/null
+++ b/dx/src/junit/framework/Test.java
@@ -0,0 +1,17 @@
+package junit.framework;
+
+/**
+ * A <em>Test</em> can be run and collect its results.
+ *
+ * @see TestResult
+ */
+public interface Test {
+	/**
+	 * Counts the number of test cases that will be run by this test.
+	 */
+	public abstract int countTestCases();
+	/**
+	 * Runs a test and collects its result in a TestResult instance.
+	 */
+	public abstract void run(TestResult result);
+}
diff --git a/dx/src/junit/framework/TestCase.java b/dx/src/junit/framework/TestCase.java
new file mode 100644
index 0000000..8988c45
--- /dev/null
+++ b/dx/src/junit/framework/TestCase.java
@@ -0,0 +1,197 @@
+package junit.framework;
+
+import java.lang.reflect.*;
+
+/**
+ * A test case defines the fixture to run multiple tests. To define a test case<br>
+ * 1) implement a subclass of TestCase<br>
+ * 2) define instance variables that store the state of the fixture<br>
+ * 3) initialize the fixture state by overriding <code>setUp</code><br>
+ * 4) clean-up after a test by overriding <code>tearDown</code>.<br>
+ * Each test runs in its own fixture so there
+ * can be no side effects among test runs.
+ * Here is an example:
+ * <pre>
+ * public class MathTest extends TestCase {
+ *     protected double fValue1;
+ *     protected double fValue2;
+ *
+ *    protected void setUp() {
+ *         fValue1= 2.0;
+ *         fValue2= 3.0;
+ *     }
+ * }
+ * </pre>
+ *
+ * For each test implement a method which interacts
+ * with the fixture. Verify the expected results with assertions specified
+ * by calling <code>assertTrue</code> with a boolean.
+ * <pre>
+ *    public void testAdd() {
+ *        double result= fValue1 + fValue2;
+ *        assertTrue(result == 5.0);
+ *    }
+ * </pre>
+ * Once the methods are defined you can run them. The framework supports
+ * both a static type safe and more dynamic way to run a test.
+ * In the static way you override the runTest method and define the method to
+ * be invoked. A convenient way to do so is with an anonymous inner class.
+ * <pre>
+ * TestCase test= new MathTest("add") {
+ *        public void runTest() {
+ *            testAdd();
+ *        }
+ * };
+ * test.run();
+ * </pre>
+ * The dynamic way uses reflection to implement <code>runTest</code>. It dynamically finds
+ * and invokes a method.
+ * In this case the name of the test case has to correspond to the test method
+ * to be run.
+ * <pre>
+ * TestCase= new MathTest("testAdd");
+ * test.run();
+ * </pre>
+ * The tests to be run can be collected into a TestSuite. JUnit provides
+ * different <i>test runners</i> which can run a test suite and collect the results.
+ * A test runner either expects a static method <code>suite</code> as the entry
+ * point to get a test to run or it will extract the suite automatically.
+ * <pre>
+ * public static Test suite() {
+ *      suite.addTest(new MathTest("testAdd"));
+ *      suite.addTest(new MathTest("testDivideByZero"));
+ *      return suite;
+ *  }
+ * </pre>
+ * @see TestResult
+ * @see TestSuite
+ */
+
+public abstract class TestCase extends Assert implements Test {
+	/**
+	 * the name of the test case
+	 */
+	private String fName;
+
+	/**
+	 * No-arg constructor to enable serialization. This method
+	 * is not intended to be used by mere mortals without calling setName().
+	 */
+	public TestCase() {
+		fName= null;
+	}
+	/**
+	 * Constructs a test case with the given name.
+	 */
+	public TestCase(String name) {
+		fName= name;
+	}
+	/**
+	 * Counts the number of test cases executed by run(TestResult result).
+	 */
+	public int countTestCases() {
+		return 1;
+	}
+	/**
+	 * Creates a default TestResult object
+	 *
+	 * @see TestResult
+	 */
+	protected TestResult createResult() {
+	    return new TestResult();
+	}
+	/**
+	 * A convenience method to run this test, collecting the results with a
+	 * default TestResult object.
+	 *
+	 * @see TestResult
+	 */
+	public TestResult run() {
+		TestResult result= createResult();
+		run(result);
+		return result;
+	}
+	/**
+	 * Runs the test case and collects the results in TestResult.
+	 */
+	public void run(TestResult result) {
+		result.run(this);
+	}
+	/**
+	 * Runs the bare test sequence.
+	 * @exception Throwable if any exception is thrown
+	 */
+	public void runBare() throws Throwable {
+		setUp();
+		try {
+			runTest();
+		}
+		finally {
+			tearDown();
+		}
+	}
+	/**
+	 * Override to run the test and assert its state.
+	 * @exception Throwable if any exception is thrown
+	 */
+	protected void runTest() throws Throwable {
+		assertNotNull(fName);
+		Method runMethod= null;
+		try {
+			// use getMethod to get all public inherited
+			// methods. getDeclaredMethods returns all
+			// methods of this class but excludes the
+			// inherited ones.
+			runMethod= getClass().getMethod(fName, (Class[]) null);
+		} catch (NoSuchMethodException e) {
+			fail("Method \""+fName+"\" not found");
+		}
+		if (!Modifier.isPublic(runMethod.getModifiers())) {
+			fail("Method \""+fName+"\" should be public");
+		}
+
+		try {
+			runMethod.invoke(this, (Object[]) new Class[0]);
+		}
+		catch (InvocationTargetException e) {
+			e.fillInStackTrace();
+			throw e.getTargetException();
+		}
+		catch (IllegalAccessException e) {
+			e.fillInStackTrace();
+			throw e;
+		}
+	}
+	/**
+	 * Sets up the fixture, for example, open a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected void setUp() throws Exception {
+	}
+	/**
+	 * Tears down the fixture, for example, close a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected void tearDown() throws Exception {
+	}
+	/**
+	 * Returns a string representation of the test case
+	 */
+	public String toString() {
+	    return getName() + "(" + getClass().getName() + ")";
+	}
+	/**
+	 * Gets the name of a TestCase
+	 * @return returns a String
+	 */
+	public String getName() {
+		return fName;
+	}
+	/**
+	 * Sets the name of a TestCase
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		fName= name;
+	}
+}
diff --git a/dx/src/junit/framework/TestFailure.java b/dx/src/junit/framework/TestFailure.java
new file mode 100644
index 0000000..664747d
--- /dev/null
+++ b/dx/src/junit/framework/TestFailure.java
@@ -0,0 +1,57 @@
+package junit.framework;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+/**
+ * A <code>TestFailure</code> collects a failed test together with
+ * the caught exception.
+ * @see TestResult
+ */
+public class TestFailure extends Object {
+	protected Test fFailedTest;
+	protected Throwable fThrownException;
+	
+
+	/**
+	 * Constructs a TestFailure with the given test and exception.
+	 */
+	public TestFailure(Test failedTest, Throwable thrownException) {
+		fFailedTest= failedTest;
+		fThrownException= thrownException;
+	}
+	/**
+	 * Gets the failed test.
+	 */
+	public Test failedTest() {
+	    return fFailedTest;
+	}
+	/**
+	 * Gets the thrown exception.
+	 */
+	public Throwable thrownException() {
+	    return fThrownException;
+	}
+	/**
+	 * Returns a short description of the failure.
+	 */
+	public String toString() {
+	    StringBuffer buffer= new StringBuffer();
+	    buffer.append(fFailedTest+": "+fThrownException.getMessage());
+	    return buffer.toString();
+	}
+	public String trace() {
+		StringWriter stringWriter= new StringWriter();
+		PrintWriter writer= new PrintWriter(stringWriter);
+		thrownException().printStackTrace(writer);
+		StringBuffer buffer= stringWriter.getBuffer();
+		return buffer.toString();
+	}
+	public String exceptionMessage() {
+		return thrownException().getMessage();
+	}
+	public boolean isFailure() {
+		return thrownException() instanceof AssertionFailedError;
+	}
+}
diff --git a/dx/src/junit/framework/TestListener.java b/dx/src/junit/framework/TestListener.java
new file mode 100644
index 0000000..7558187
--- /dev/null
+++ b/dx/src/junit/framework/TestListener.java
@@ -0,0 +1,23 @@
+package junit.framework;
+
+/**
+ * A Listener for test progress
+ */
+public interface TestListener {
+	/**
+ 	 * An error occurred.
+ 	 */
+	public void addError(Test test, Throwable t);
+	/**
+ 	 * A failure occurred.
+ 	 */
+ 	public void addFailure(Test test, AssertionFailedError t);  
+	/**
+	 * A test ended.
+	 */
+ 	public void endTest(Test test); 
+	/**
+	 * A test started.
+	 */
+	public void startTest(Test test);
+}
diff --git a/dx/src/junit/framework/TestResult.java b/dx/src/junit/framework/TestResult.java
new file mode 100644
index 0000000..4b1a7e2
--- /dev/null
+++ b/dx/src/junit/framework/TestResult.java
@@ -0,0 +1,166 @@
+package junit.framework;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * A <code>TestResult</code> collects the results of executing
+ * a test case. It is an instance of the Collecting Parameter pattern.
+ * The test framework distinguishes between <i>failures</i> and <i>errors</i>.
+ * A failure is anticipated and checked for with assertions. Errors are
+ * unanticipated problems like an <code>ArrayIndexOutOfBoundsException</code>.
+ *
+ * @see Test
+ */
+public class TestResult extends Object {
+	protected Vector<TestFailure> fFailures;
+	protected Vector<TestFailure> fErrors;
+	protected Vector<TestListener> fListeners;
+	protected int fRunTests;
+	private boolean fStop;
+	
+	public TestResult() {
+		fFailures= new Vector<TestFailure>();
+		fErrors= new Vector<TestFailure>();
+		fListeners= new Vector<TestListener>();
+		fRunTests= 0;
+		fStop= false;
+	}
+	/**
+	 * Adds an error to the list of errors. The passed in exception
+	 * caused the error.
+	 */
+	public synchronized void addError(Test test, Throwable t) {
+		fErrors.addElement(new TestFailure(test, t));
+		for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
+			((TestListener)e.nextElement()).addError(test, t);
+		}
+	}
+	/**
+	 * Adds a failure to the list of failures. The passed in exception
+	 * caused the failure.
+	 */
+	public synchronized void addFailure(Test test, AssertionFailedError t) {
+		fFailures.addElement(new TestFailure(test, t));
+		for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
+			((TestListener)e.nextElement()).addFailure(test, t);
+		}
+	}
+	/**
+	 * Registers a TestListener
+	 */
+	public synchronized void addListener(TestListener listener) {
+		fListeners.addElement(listener);
+	}
+	/**
+	 * Unregisters a TestListener
+	 */
+	public synchronized void removeListener(TestListener listener) {
+		fListeners.removeElement(listener);
+	}
+	/**
+	 * Returns a copy of the listeners.
+	 */
+	private synchronized Vector cloneListeners() {
+		return (Vector)fListeners.clone();
+	}
+	/**
+	 * Informs the result that a test was completed.
+	 */
+	public void endTest(Test test) {
+		for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
+			((TestListener)e.nextElement()).endTest(test);
+		}
+	}
+	/**
+	 * Gets the number of detected errors.
+	 */
+	public synchronized int errorCount() {
+		return fErrors.size();
+	}
+	/**
+	 * Returns an Enumeration for the errors
+	 */
+	public synchronized Enumeration errors() {
+		return fErrors.elements();
+	}
+	/**
+	 * Gets the number of detected failures.
+	 */
+	public synchronized int failureCount() {
+		return fFailures.size();
+	}
+	/**
+	 * Returns an Enumeration for the failures
+	 */
+	public synchronized Enumeration failures() {
+		return fFailures.elements();
+	}
+	/**
+	 * Runs a TestCase.
+	 */
+	protected void run(final TestCase test) {
+		startTest(test);
+		Protectable p= new Protectable() {
+			public void protect() throws Throwable {
+				test.runBare();
+			}
+		};
+		runProtected(test, p);
+
+		endTest(test);
+	}
+	/**
+	 * Gets the number of run tests.
+	 */
+	public synchronized int runCount() {
+		return fRunTests;
+	}
+	/**
+	 * Runs a TestCase.
+	 */
+	public void runProtected(final Test test, Protectable p) {
+		try {
+			p.protect();
+		} 
+		catch (AssertionFailedError e) {
+			addFailure(test, e);
+		}
+		catch (ThreadDeath e) { // don't catch ThreadDeath by accident
+			throw e;
+		}
+		catch (Throwable e) {
+			addError(test, e);
+		}
+	}
+	/**
+	 * Checks whether the test run should stop
+	 */
+	public synchronized boolean shouldStop() {
+		return fStop;
+	}
+	/**
+	 * Informs the result that a test will be started.
+	 */
+	public void startTest(Test test) {
+		final int count= test.countTestCases();
+		synchronized(this) {
+			fRunTests+= count;
+		}
+		for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
+			((TestListener)e.nextElement()).startTest(test);
+		}
+	}
+	/**
+	 * Marks that the test run should stop.
+	 */
+	public synchronized void stop() {
+		fStop= true;
+	}
+	/**
+	 * Returns whether the entire test was successful or not.
+	 */
+	public synchronized boolean wasSuccessful() {
+		return failureCount() == 0 && errorCount() == 0;
+	}
+}
diff --git a/dx/src/junit/framework/TestSuite.java b/dx/src/junit/framework/TestSuite.java
new file mode 100644
index 0000000..2987ad1
--- /dev/null
+++ b/dx/src/junit/framework/TestSuite.java
@@ -0,0 +1,265 @@
+package junit.framework;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.PrintWriter;import java.io.StringWriter;import java.lang.reflect.*;
+import java.lang.reflect.Constructor;
+
+/**
+ * A <code>TestSuite</code> is a <code>Composite</code> of Tests.
+ * It runs a collection of test cases. Here is an example using
+ * the dynamic test definition.
+ * <pre>
+ * TestSuite suite= new TestSuite();
+ * suite.addTest(new MathTest("testAdd"));
+ * suite.addTest(new MathTest("testDivideByZero"));
+ * </pre>
+ * Alternatively, a TestSuite can extract the tests to be run automatically.
+ * To do so you pass the class of your TestCase class to the
+ * TestSuite constructor.
+ * <pre>
+ * TestSuite suite= new TestSuite(MathTest.class);
+ * </pre>
+ * This constructor creates a suite with all the methods
+ * starting with "test" that take no arguments.
+ *
+ * @see Test
+ */
+public class TestSuite implements Test {
+
+	private Vector<Test> fTests= new Vector<Test>(10);
+	private String fName;
+
+    /**
+	 * Constructs an empty TestSuite.
+	 */
+	public TestSuite() {
+	}
+	
+	/**
+	 * Constructs a TestSuite from the given class with the given name.
+	 * @see TestSuite#TestSuite(Class)
+	 */
+	public TestSuite(Class theClass, String name) {
+		this(theClass);
+		setName(name);
+	}
+	
+	/**
+	 * Constructs a TestSuite from the given class. Adds all the methods
+	 * starting with "test" as test cases to the suite.
+	 * Parts of this method was written at 2337 meters in the Huffihutte,
+	 * Kanton Uri
+	 */
+	 public TestSuite(final Class theClass) {
+		fName= theClass.getName();
+		try {
+			getTestConstructor(theClass); // Avoid generating multiple error messages
+		} catch (NoSuchMethodException e) {
+			addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"));
+			return;
+		}
+
+		if (!Modifier.isPublic(theClass.getModifiers())) {
+			addTest(warning("Class "+theClass.getName()+" is not public"));
+			return;
+		}
+
+		Class superClass= theClass;
+		Vector<String> names= new Vector<String>();
+		while (Test.class.isAssignableFrom(superClass)) {
+			Method[] methods= superClass.getDeclaredMethods();
+			for (int i= 0; i < methods.length; i++) {
+				addTestMethod(methods[i], names, theClass);
+			}
+			superClass= superClass.getSuperclass();
+		}
+		if (fTests.size() == 0)
+			addTest(warning("No tests found in "+theClass.getName()));
+	}
+	
+   	/**
+	 * Constructs an empty TestSuite.
+	 */
+	public TestSuite(String name) {
+		setName(name);
+	}
+	
+	/**
+	 * Adds a test to the suite.
+	 */
+	public void addTest(Test test) {
+		fTests.addElement(test);
+	}
+
+	/**
+	 * Adds the tests from the given class to the suite
+	 */
+	public void addTestSuite(Class testClass) {
+		addTest(new TestSuite(testClass));
+	}
+
+	private void addTestMethod(Method m, Vector<String> names, Class theClass) {
+		String name= m.getName();
+		if (names.contains(name))
+			return;
+		if (! isPublicTestMethod(m)) {
+			if (isTestMethod(m))
+				addTest(warning("Test method isn't public: "+m.getName()));
+			return;
+		}
+		names.addElement(name);
+		addTest(createTest(theClass, name));
+	}
+
+	/**
+	 * ...as the moon sets over the early morning Merlin, Oregon
+	 * mountains, our intrepid adventurers type...
+	 */
+	static public Test createTest(Class theClass, String name) {
+		Constructor constructor;
+		try {
+			constructor= getTestConstructor(theClass);
+		} catch (NoSuchMethodException e) {
+			return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()");
+		}
+		Object test;
+		try {
+			if (constructor.getParameterTypes().length == 0) {
+				test= constructor.newInstance(new Object[0]);
+				if (test instanceof TestCase)
+					((TestCase) test).setName(name);
+			} else {
+				test= constructor.newInstance(new Object[]{name});
+			}
+		} catch (InstantiationException e) {
+			return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
+		} catch (InvocationTargetException e) {
+			return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
+		} catch (IllegalAccessException e) {
+			return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
+		}
+		return (Test) test;
+	}
+
+	/**
+	 * Converts the stack trace into a string
+	 */
+	private static String exceptionToString(Throwable t) {
+		StringWriter stringWriter= new StringWriter();
+		PrintWriter writer= new PrintWriter(stringWriter);
+		t.printStackTrace(writer);
+		return stringWriter.toString();
+
+	}
+	
+	/**
+	 * Counts the number of test cases that will be run by this test.
+	 */
+	public int countTestCases() {
+		int count= 0;
+		for (Enumeration e= tests(); e.hasMoreElements(); ) {
+			Test test= (Test)e.nextElement();
+			count= count + test.countTestCases();
+		}
+		return count;
+	}
+	
+	/**
+	 * Gets a constructor which takes a single String as
+	 * its argument or a no arg constructor.
+	 */
+	public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException {
+		Class[] args= { String.class };
+		try {
+			return theClass.getConstructor(args);	
+		} catch (NoSuchMethodException e) {
+			// fall through
+		}
+		return theClass.getConstructor(new Class[0]);
+	}
+
+	private boolean isPublicTestMethod(Method m) {
+		return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
+	 }
+	 
+	private boolean isTestMethod(Method m) {
+		String name= m.getName();
+		Class[] parameters= m.getParameterTypes();
+		Class returnType= m.getReturnType();
+		return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
+	 }
+	 
+	/**
+	 * Runs the tests and collects their result in a TestResult.
+	 */
+	public void run(TestResult result) {
+		for (Enumeration e= tests(); e.hasMoreElements(); ) {
+	  		if (result.shouldStop() )
+	  			break;
+			Test test= (Test)e.nextElement();
+			runTest(test, result);
+		}
+	}
+
+	public void runTest(Test test, TestResult result) {
+		test.run(result);
+	}
+
+	/**
+	 * Returns the test at the given index
+	 */
+	public Test testAt(int index) {
+		return (Test)fTests.elementAt(index);
+	}
+	
+	/**
+	 * Returns the number of tests in this suite
+	 */
+	public int testCount() {
+		return fTests.size();
+	}
+	
+	/**
+	 * Returns the tests as an enumeration
+	 */
+	public Enumeration tests() {
+		return fTests.elements();
+	}
+	
+	/**
+	 */
+	public String toString() {
+		if (getName() != null)
+			return getName();
+		return super.toString();
+	 }
+	 
+	/**
+	 * Sets the name of the suite.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		fName= name;
+	}
+
+	/**
+	 * Returns the name of the suite. Not all
+	 * test suites have a name and this method
+	 * can return null.
+	 */
+	public String getName() {
+		return fName;
+	}
+
+	/**
+	 * Returns a test which will fail and log a warning message.
+	 */
+	private static Test warning(final String message) {
+		return new TestCase("warning") {
+			protected void runTest() {
+				fail(message);
+			}
+		};
+	}
+}
diff --git a/dx/src/junit/runner/BaseTestRunner.java b/dx/src/junit/runner/BaseTestRunner.java
new file mode 100644
index 0000000..39c8c2f
--- /dev/null
+++ b/dx/src/junit/runner/BaseTestRunner.java
@@ -0,0 +1,323 @@
+package junit.runner;
+
+import junit.framework.*;
+import java.lang.reflect.*;
+import java.text.NumberFormat;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Base class for all test runners.
+ * This class was born live on stage in Sardinia during XP2000.
+ */
+public abstract class BaseTestRunner implements TestListener {
+	public static final String SUITE_METHODNAME= "suite";
+
+	private static Properties fPreferences;
+	static int fgMaxMessageLength= 500;
+	static boolean fgFilterStack= true;
+	boolean fLoading= true;
+
+    /*
+    * Implementation of TestListener
+    */
+	public synchronized void startTest(Test test) {
+		testStarted(test.toString());
+	}
+
+	protected static void setPreferences(Properties preferences) {
+		fPreferences= preferences;
+	}
+
+	protected static Properties getPreferences() {
+		if (fPreferences == null) {
+			fPreferences= new Properties();
+	 		fPreferences.put("loading", "true");
+ 			fPreferences.put("filterstack", "true");
+  			readPreferences();
+		}
+		return fPreferences;
+	}
+
+	public static void savePreferences() throws IOException {
+		FileOutputStream fos= new FileOutputStream(getPreferencesFile());
+		try {
+			getPreferences().store(fos, "");
+		} finally {
+			fos.close();
+		}
+	}
+
+	public void setPreference(String key, String value) {
+		getPreferences().setProperty(key, value);
+	}
+
+	public synchronized void endTest(Test test) {
+		testEnded(test.toString());
+	}
+
+	public synchronized void addError(final Test test, final Throwable t) {
+		testFailed(TestRunListener.STATUS_ERROR, test, t);
+	}
+
+	public synchronized void addFailure(final Test test, final AssertionFailedError t) {
+		testFailed(TestRunListener.STATUS_FAILURE, test, t);
+	}
+
+	// TestRunListener implementation
+
+	public abstract void testStarted(String testName);
+
+	public abstract void testEnded(String testName);
+
+	public abstract void testFailed(int status, Test test, Throwable t);
+
+	/**
+	 * Returns the Test corresponding to the given suite. This is
+	 * a template method, subclasses override runFailed(), clearStatus().
+	 */
+	public Test getTest(String suiteClassName) {
+		if (suiteClassName.length() <= 0) {
+			clearStatus();
+			return null;
+		}
+		Class testClass= null;
+		try {
+			testClass= loadSuiteClass(suiteClassName);
+		} catch (ClassNotFoundException e) {
+			String clazz= e.getMessage();
+			if (clazz == null)
+				clazz= suiteClassName;
+			runFailed("Class not found \""+clazz+"\"");
+			return null;
+		} catch(Exception e) {
+			runFailed("Error: "+e.toString());
+			return null;
+		}
+		Method suiteMethod= null;
+		try {
+			suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
+	 	} catch(Exception e) {
+	 		// try to extract a test suite automatically
+			clearStatus();
+			return new TestSuite(testClass);
+		}
+		if (! Modifier.isStatic(suiteMethod.getModifiers())) {
+			runFailed("Suite() method must be static");
+			return null;
+		}
+		Test test= null;
+		try {
+			test= (Test)suiteMethod.invoke(null, (Object[]) new Class[0]); // static method
+			if (test == null)
+				return test;
+		}
+		catch (InvocationTargetException e) {
+			runFailed("Failed to invoke suite():" + e.getTargetException().toString());
+			return null;
+		}
+		catch (IllegalAccessException e) {
+			runFailed("Failed to invoke suite():" + e.toString());
+			return null;
+		}
+
+		clearStatus();
+		return test;
+	}
+
+	/**
+	 * Returns the formatted string of the elapsed time.
+	 */
+	public String elapsedTimeAsString(long runTime) {
+		return NumberFormat.getInstance().format((double)runTime/1000);
+	}
+
+	/**
+	 * Processes the command line arguments and
+	 * returns the name of the suite class to run or null
+	 */
+	protected String processArguments(String[] args) {
+		String suiteName= null;
+		for (int i= 0; i < args.length; i++) {
+			if (args[i].equals("-noloading")) {
+				setLoading(false);
+			} else if (args[i].equals("-nofilterstack")) {
+				fgFilterStack= false;
+			} else if (args[i].equals("-c")) {
+				if (args.length > i+1)
+					suiteName= extractClassName(args[i+1]);
+				else
+					System.out.println("Missing Test class name");
+				i++;
+			} else {
+				suiteName= args[i];
+			}
+		}
+		return suiteName;
+	}
+
+	/**
+	 * Sets the loading behaviour of the test runner
+	 */
+	public void setLoading(boolean enable) {
+		fLoading= enable;
+	}
+	/**
+	 * Extract the class name from a String in VA/Java style
+	 */
+	public String extractClassName(String className) {
+		if(className.startsWith("Default package for"))
+			return className.substring(className.lastIndexOf(".")+1);
+		return className;
+	}
+
+	/**
+	 * Truncates a String to the maximum length.
+	 */
+	public static String truncate(String s) {
+		if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength)
+			s= s.substring(0, fgMaxMessageLength)+"...";
+		return s;
+	}
+
+	/**
+	 * Override to define how to handle a failed loading of
+	 * a test suite.
+	 */
+	protected abstract void runFailed(String message);
+
+	/**
+	 * Returns the loaded Class for a suite name.
+	 */
+	protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+		return getLoader().load(suiteClassName);
+	}
+
+	/**
+	 * Clears the status message.
+	 */
+	protected void clearStatus() { // Belongs in the GUI TestRunner class
+	}
+
+	/**
+	 * Returns the loader to be used.
+	 */
+	public TestSuiteLoader getLoader() {
+		if (useReloadingTestSuiteLoader())
+			return new ReloadingTestSuiteLoader();
+		return new StandardTestSuiteLoader();
+	}
+
+	protected boolean useReloadingTestSuiteLoader() {
+		return getPreference("loading").equals("true") && !inVAJava() && fLoading;
+	}
+
+	private static File getPreferencesFile() {
+	 	String home= System.getProperty("user.home");
+ 		return new File(home, "junit.properties");
+ 	}
+
+ 	private static void readPreferences() {
+ 		InputStream is= null;
+ 		try {
+ 			is= new FileInputStream(getPreferencesFile());
+ 			setPreferences(new Properties(getPreferences()));
+			getPreferences().load(is);
+		} catch (IOException e) {
+			try {
+				if (is != null)
+					is.close();
+			} catch (IOException e1) {
+			}
+		}
+ 	}
+
+ 	public static String getPreference(String key) {
+ 		return getPreferences().getProperty(key);
+ 	}
+
+ 	public static int getPreference(String key, int dflt) {
+ 		String value= getPreference(key);
+ 		int intValue= dflt;
+ 		if (value == null)
+ 			return intValue;
+ 		try {
+ 			intValue= Integer.parseInt(value);
+ 	 	} catch (NumberFormatException ne) {
+ 		}
+ 		return intValue;
+ 	}
+
+ 	public static boolean inVAJava() {
+		try {
+			Class.forName("com.ibm.uvm.tools.DebugSupport");
+		}
+		catch (Exception e) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Returns a filtered stack trace
+	 */
+	public static String getFilteredTrace(Throwable t) {
+		StringWriter stringWriter= new StringWriter();
+		PrintWriter writer= new PrintWriter(stringWriter);
+		t.printStackTrace(writer);
+		StringBuffer buffer= stringWriter.getBuffer();
+		String trace= buffer.toString();
+		return BaseTestRunner.getFilteredTrace(trace);
+	}
+
+	/**
+	 * Filters stack frames from internal JUnit classes
+	 */
+	public static String getFilteredTrace(String stack) {
+		if (showStackRaw())
+			return stack;
+
+		StringWriter sw= new StringWriter();
+		PrintWriter pw= new PrintWriter(sw);
+		StringReader sr= new StringReader(stack);
+		BufferedReader br= new BufferedReader(sr);
+
+		String line;
+		try {
+			while ((line= br.readLine()) != null) {
+				if (!filterLine(line))
+					pw.println(line);
+			}
+		} catch (Exception IOException) {
+			return stack; // return the stack unfiltered
+		}
+		return sw.toString();
+	}
+
+	protected static boolean showStackRaw() {
+		return !getPreference("filterstack").equals("true") || fgFilterStack == false;
+	}
+
+	static boolean filterLine(String line) {
+		String[] patterns= new String[] {
+			"junit.framework.TestCase",
+			"junit.framework.TestResult",
+			"junit.framework.TestSuite",
+			"junit.framework.Assert.", // don't filter AssertionFailure
+			"junit.swingui.TestRunner",
+			"junit.awtui.TestRunner",
+			"junit.textui.TestRunner",
+			"java.lang.reflect.Method.invoke("
+		};
+		for (int i= 0; i < patterns.length; i++) {
+			if (line.indexOf(patterns[i]) > 0)
+				return true;
+		}
+		return false;
+	}
+
+ 	static {
+ 		fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
+ 	}
+
+}
diff --git a/dx/src/junit/runner/ClassPathTestCollector.java b/dx/src/junit/runner/ClassPathTestCollector.java
new file mode 100644
index 0000000..24bf1e9
--- /dev/null
+++ b/dx/src/junit/runner/ClassPathTestCollector.java
@@ -0,0 +1,80 @@
+package junit.runner;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * An implementation of a TestCollector that consults the
+ * class path. It considers all classes on the class path
+ * excluding classes in JARs. It leaves it up to subclasses
+ * to decide whether a class is a runnable Test.
+ *
+ * @see TestCollector
+ */
+public abstract class ClassPathTestCollector implements TestCollector {
+	
+	static final int SUFFIX_LENGTH= ".class".length();
+	
+	public ClassPathTestCollector() {
+	}
+	
+	public Enumeration collectTests() {
+		String classPath= System.getProperty("java.class.path");
+		Hashtable result = collectFilesInPath(classPath);
+		return result.elements();
+	}
+
+	public Hashtable collectFilesInPath(String classPath) {
+		Hashtable result= collectFilesInRoots(splitClassPath(classPath));
+		return result;
+	}
+	
+	Hashtable collectFilesInRoots(Vector roots) {
+                Hashtable<String,String> result= new Hashtable<String,String>(100);
+		Enumeration e= roots.elements();
+		while (e.hasMoreElements()) 
+			gatherFiles(new File((String)e.nextElement()), "", result);
+		return result;
+	}
+
+    void gatherFiles(File classRoot, String classFileName, Hashtable<String,String> result) {
+		File thisRoot= new File(classRoot, classFileName);
+		if (thisRoot.isFile()) {
+			if (isTestClass(classFileName)) {
+				String className= classNameFromFile(classFileName);
+				result.put(className, className);
+			}
+			return;
+		}		
+		String[] contents= thisRoot.list();
+		if (contents != null) { 
+			for (int i= 0; i < contents.length; i++) 
+				gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result);		
+		}
+	}
+	
+	Vector splitClassPath(String classPath) {
+		Vector<String> result= new Vector<String>();
+		String separator= System.getProperty("path.separator");
+		StringTokenizer tokenizer= new StringTokenizer(classPath, separator);
+		while (tokenizer.hasMoreTokens()) 
+			result.addElement(tokenizer.nextToken());
+		return result;
+	}
+	
+	protected boolean isTestClass(String classFileName) {
+		return 
+			classFileName.endsWith(".class") && 
+			classFileName.indexOf('$') < 0 &&
+			classFileName.indexOf("Test") > 0;
+	}
+	
+	protected String classNameFromFile(String classFileName) {
+		// convert /a/b.class to a.b
+		String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH);
+		String s2= s.replace(File.separatorChar, '.');
+		if (s2.startsWith("."))
+			return s2.substring(1);
+		return s2;
+	}	
+}
diff --git a/dx/src/junit/runner/FailureDetailView.java b/dx/src/junit/runner/FailureDetailView.java
new file mode 100644
index 0000000..762326b
--- /dev/null
+++ b/dx/src/junit/runner/FailureDetailView.java
@@ -0,0 +1,23 @@
+package junit.runner;
+
+import java.awt.Component; 
+
+import junit.framework.*;
+
+/**
+ * A view to show a details about a failure
+ */
+public interface FailureDetailView {
+	/**
+	 * Returns the component used to present the TraceView
+	 */
+	public Component getComponent();
+	/**
+	 * Shows details of a TestFailure
+	 */
+	public void showFailure(TestFailure failure);
+	/**
+	 * Clears the view
+	 */
+	public void clear();
+}
diff --git a/dx/src/junit/runner/LoadingTestCollector.java b/dx/src/junit/runner/LoadingTestCollector.java
new file mode 100644
index 0000000..b138359
--- /dev/null
+++ b/dx/src/junit/runner/LoadingTestCollector.java
@@ -0,0 +1,69 @@
+package junit.runner;
+
+import java.lang.reflect.*;
+import junit.runner.*;
+import junit.framework.*;
+
+/**
+ * An implementation of a TestCollector that loads
+ * all classes on the class path and tests whether
+ * it is assignable from Test or provides a static suite method.
+ * @see TestCollector
+ */
+public class LoadingTestCollector extends ClassPathTestCollector {
+	
+	TestCaseClassLoader fLoader;
+	
+	public LoadingTestCollector() {
+		fLoader= new TestCaseClassLoader();
+	}
+	
+	protected boolean isTestClass(String classFileName) {	
+		try {
+			if (classFileName.endsWith(".class")) {
+				Class testClass= classFromFile(classFileName);
+				return (testClass != null) && isTestClass(testClass);
+			}
+		} 
+		catch (ClassNotFoundException expected) {
+		}
+		catch (NoClassDefFoundError notFatal) {
+		} 
+		return false;
+	}
+	
+	Class classFromFile(String classFileName) throws ClassNotFoundException {
+		String className= classNameFromFile(classFileName);
+		if (!fLoader.isExcluded(className))
+			return fLoader.loadClass(className, false);
+		return null;
+	}
+	
+	boolean isTestClass(Class testClass) {
+		if (hasSuiteMethod(testClass))
+			return true;
+		if (Test.class.isAssignableFrom(testClass) &&
+			Modifier.isPublic(testClass.getModifiers()) &&
+			hasPublicConstructor(testClass)) 
+			return true;
+		return false;
+	}
+	
+	boolean hasSuiteMethod(Class testClass) {
+		try {
+			testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]);
+	 	} catch(Exception e) {
+	 		return false;
+		}
+		return true;
+	}
+	
+	boolean hasPublicConstructor(Class testClass) {
+		try {
+			TestSuite.getTestConstructor(testClass);
+		} catch(NoSuchMethodException e) {
+			return false;
+		}
+		return true;
+	}
+}
diff --git a/dx/src/junit/runner/ReloadingTestSuiteLoader.java b/dx/src/junit/runner/ReloadingTestSuiteLoader.java
new file mode 100644
index 0000000..f7ef919
--- /dev/null
+++ b/dx/src/junit/runner/ReloadingTestSuiteLoader.java
@@ -0,0 +1,19 @@
+package junit.runner;
+
+/**
+ * A TestSuite loader that can reload classes.
+ */
+public class ReloadingTestSuiteLoader implements TestSuiteLoader {
+	
+	public Class load(String suiteClassName) throws ClassNotFoundException {
+		return createLoader().loadClass(suiteClassName, true);
+	}
+	
+	public Class reload(Class aClass) throws ClassNotFoundException {
+		return createLoader().loadClass(aClass.getName(), true);
+	}
+	
+	protected TestCaseClassLoader createLoader() {
+		return new TestCaseClassLoader();
+	}
+}
diff --git a/dx/src/junit/runner/SimpleTestCollector.java b/dx/src/junit/runner/SimpleTestCollector.java
new file mode 100644
index 0000000..9d1956a
--- /dev/null
+++ b/dx/src/junit/runner/SimpleTestCollector.java
@@ -0,0 +1,20 @@
+package junit.runner;
+
+/**
+ * An implementation of a TestCollector that considers
+ * a class to be a test class when it contains the
+ * pattern "Test" in its name
+ * @see TestCollector
+ */
+public class SimpleTestCollector extends ClassPathTestCollector {
+	
+	public SimpleTestCollector() {
+	}
+	
+	protected boolean isTestClass(String classFileName) {
+		return 
+			classFileName.endsWith(".class") && 
+			classFileName.indexOf('$') < 0 &&
+			classFileName.indexOf("Test") > 0;
+	}
+}
diff --git a/dx/src/junit/runner/Sorter.java b/dx/src/junit/runner/Sorter.java
new file mode 100644
index 0000000..e614ab4
--- /dev/null
+++ b/dx/src/junit/runner/Sorter.java
@@ -0,0 +1,38 @@
+package junit.runner;
+
+import java.util.*;
+
+import junit.runner.*;
+
+/**
+ * A custom quick sort with support to customize the swap behaviour.
+ * NOTICE: We can't use the the sorting support from the JDK 1.2 collection
+ * classes because of the JDK 1.1.7 compatibility.
+ */
+public class Sorter {
+	public static interface Swapper {
+		public void swap(Vector values, int left, int right);
+	}
+		
+	public static void sortStrings(Vector values , int left, int right, Swapper swapper) { 
+		int oleft= left;
+		int oright= right;
+		String mid= (String)values.elementAt((left + right) / 2); 
+		do { 
+			while (((String)(values.elementAt(left))).compareTo(mid) < 0)  
+				left++; 
+			while (mid.compareTo((String)(values.elementAt(right))) < 0)  
+				right--; 
+			if (left <= right) {
+				swapper.swap(values, left, right); 
+				left++; 
+				right--; 
+			} 
+		} while (left <= right);
+		
+		if (oleft < right) 
+			sortStrings(values, oleft, right, swapper); 
+		if (left < oright) 
+			 sortStrings(values, left, oright, swapper); 
+	}
+}
diff --git a/dx/src/junit/runner/StandardTestSuiteLoader.java b/dx/src/junit/runner/StandardTestSuiteLoader.java
new file mode 100644
index 0000000..e2bd765
--- /dev/null
+++ b/dx/src/junit/runner/StandardTestSuiteLoader.java
@@ -0,0 +1,19 @@
+package junit.runner;
+
+/**
+ * The standard test suite loader. It can only load the same class once.
+ */
+public class StandardTestSuiteLoader implements TestSuiteLoader {
+	/**
+	 * Uses the system class loader to load the test class
+	 */
+	public Class load(String suiteClassName) throws ClassNotFoundException {
+		return Class.forName(suiteClassName);
+	}
+	/**
+	 * Uses the system class loader to load the test class
+	 */
+	public Class reload(Class aClass) throws ClassNotFoundException {
+		return aClass;
+	}
+}
diff --git a/dx/src/junit/runner/TestCaseClassLoader.java b/dx/src/junit/runner/TestCaseClassLoader.java
new file mode 100644
index 0000000..543641a
--- /dev/null
+++ b/dx/src/junit/runner/TestCaseClassLoader.java
@@ -0,0 +1,226 @@
+package junit.runner;
+
+import java.util.*;
+import java.io.*;
+import java.net.URL;
+import java.util.zip.*;
+
+/**
+ * A custom class loader which enables the reloading
+ * of classes for each test run. The class loader
+ * can be configured with a list of package paths that
+ * should be excluded from loading. The loading
+ * of these packages is delegated to the system class
+ * loader. They will be shared across test runs.
+ * <p>
+ * The list of excluded package paths is specified in
+ * a properties file "excluded.properties" that is located in 
+ * the same place as the TestCaseClassLoader class.
+ * <p>
+ * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes
+ * from jar files.
+ */
+
+
+public class TestCaseClassLoader extends ClassLoader {
+	/** scanned class path */
+	private Vector<String> fPathItems;
+	/** default excluded paths */
+	private String[] defaultExclusions= {
+		"junit.framework.", 
+		"junit.extensions.", 
+		"junit.runner."
+	};
+	/** name of excluded properties file */
+	static final String EXCLUDED_FILE= "excluded.properties";
+	/** excluded paths */
+	private Vector<String> fExcluded;
+	 
+	/**
+	 * Constructs a TestCaseLoader. It scans the class path
+	 * and the excluded package paths
+	 */
+	public TestCaseClassLoader() {
+		this(System.getProperty("java.class.path"));
+	}
+	
+	/**
+	 * Constructs a TestCaseLoader. It scans the class path
+	 * and the excluded package paths
+	 */
+	public TestCaseClassLoader(String classPath) {
+		scanPath(classPath);
+		readExcludedPackages();
+	}
+
+	private void scanPath(String classPath) {
+		String separator= System.getProperty("path.separator");
+		fPathItems= new Vector<String>(10);
+		StringTokenizer st= new StringTokenizer(classPath, separator);
+		while (st.hasMoreTokens()) {
+			fPathItems.addElement(st.nextToken());
+		}
+	}
+	
+	public URL getResource(String name) {
+		return ClassLoader.getSystemResource(name);
+	}
+	
+	public InputStream getResourceAsStream(String name) {
+		return ClassLoader.getSystemResourceAsStream(name);
+	} 
+	
+	public boolean isExcluded(String name) {
+		for (int i= 0; i < fExcluded.size(); i++) {
+			if (name.startsWith((String) fExcluded.elementAt(i))) {
+				return true;
+			}
+		}
+		return false;	
+	}
+	
+	public synchronized Class loadClass(String name, boolean resolve)
+		throws ClassNotFoundException {
+			
+		Class c= findLoadedClass(name);
+		if (c != null)
+			return c;
+		//
+		// Delegate the loading of excluded classes to the
+		// standard class loader.
+		//
+		if (isExcluded(name)) {
+			try {
+				c= findSystemClass(name);
+				return c;
+			} catch (ClassNotFoundException e) {
+				// keep searching
+			}
+		}
+		if (c == null) {
+			byte[] data= lookupClassData(name);
+			if (data == null)
+				throw new ClassNotFoundException();
+			c= defineClass(name, data, 0, data.length);
+		}
+		if (resolve) 
+			resolveClass(c);
+		return c;
+	}
+	
+	private byte[] lookupClassData(String className) throws ClassNotFoundException {
+		byte[] data= null;
+		for (int i= 0; i < fPathItems.size(); i++) {
+			String path= (String) fPathItems.elementAt(i);
+			String fileName= className.replace('.', '/')+".class";
+			if (isJar(path)) {
+				data= loadJarData(path, fileName);
+			} else {
+				data= loadFileData(path, fileName);
+			}
+			if (data != null)
+				return data;
+		}
+		throw new ClassNotFoundException(className);
+	}
+		
+	boolean isJar(String pathEntry) {
+		return pathEntry.endsWith(".jar") ||
+                       pathEntry.endsWith(".zip") ||
+                       pathEntry.endsWith(".apk");
+	}
+
+	private byte[] loadFileData(String path, String fileName) {
+		File file= new File(path, fileName);
+		if (file.exists()) { 
+			return getClassData(file);
+		}
+		return null;
+	}
+	
+	private byte[] getClassData(File f) {
+		try {
+			FileInputStream stream= new FileInputStream(f);
+			ByteArrayOutputStream out= new ByteArrayOutputStream(1000);
+			byte[] b= new byte[1000];
+			int n;
+			while ((n= stream.read(b)) != -1) 
+				out.write(b, 0, n);
+			stream.close();
+			out.close();
+			return out.toByteArray();
+
+		} catch (IOException e) {
+		}
+		return null;
+	}
+
+	private byte[] loadJarData(String path, String fileName) {
+		ZipFile zipFile= null;
+		InputStream stream= null;
+		File archive= new File(path);
+		if (!archive.exists())
+			return null;
+		try {
+			zipFile= new ZipFile(archive);
+		} catch(IOException io) {
+			return null;
+		}
+		ZipEntry entry= zipFile.getEntry(fileName);
+		if (entry == null)
+			return null;
+		int size= (int) entry.getSize();
+		try {
+			stream= zipFile.getInputStream(entry);
+			byte[] data= new byte[size];
+			int pos= 0;
+			while (pos < size) {
+				int n= stream.read(data, pos, data.length - pos);
+				pos += n;
+			}
+			zipFile.close();
+			return data;
+		} catch (IOException e) {
+		} finally {
+			try {
+				if (stream != null)
+					stream.close();
+			} catch (IOException e) {
+			}
+		}
+		return null;
+	}
+	
+	private void readExcludedPackages() {		
+		fExcluded= new Vector<String>(10);
+		for (int i= 0; i < defaultExclusions.length; i++)
+			fExcluded.addElement(defaultExclusions[i]);
+			
+		InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE);
+		if (is == null) 
+			return;
+		Properties p= new Properties();
+		try {
+			p.load(is);
+		}
+		catch (IOException e) {
+			return;
+		} finally {
+			try {
+				is.close();
+			} catch (IOException e) {
+			}
+		}
+		for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) {
+			String key= (String)e.nextElement();
+			if (key.startsWith("excluded.")) {
+				String path= p.getProperty(key);
+				path= path.trim();
+				if (path.endsWith("*"))
+					path= path.substring(0, path.length()-1);
+				if (path.length() > 0) 
+					fExcluded.addElement(path);				
+			}
+		}
+	}
+}
diff --git a/dx/src/junit/runner/TestCollector.java b/dx/src/junit/runner/TestCollector.java
new file mode 100644
index 0000000..73efb4e
--- /dev/null
+++ b/dx/src/junit/runner/TestCollector.java
@@ -0,0 +1,16 @@
+package junit.runner;
+
+import java.util.*;
+
+
+/**
+ * Collects Test class names to be presented
+ * by the TestSelector. 
+ * @see TestSelector
+ */
+public interface TestCollector {
+	/**
+	 * Returns an enumeration of Strings with qualified class names
+	 */
+	public Enumeration collectTests();
+}
diff --git a/dx/src/junit/runner/TestRunListener.java b/dx/src/junit/runner/TestRunListener.java
new file mode 100644
index 0000000..b11ef07
--- /dev/null
+++ b/dx/src/junit/runner/TestRunListener.java
@@ -0,0 +1,19 @@
+package junit.runner;
+/**
+ * A listener interface for observing the
+ * execution of a test run. Unlike TestListener,
+ * this interface using only primitive objects,
+ * making it suitable for remote test execution.
+ */
+ public interface TestRunListener {
+     /* test status constants*/
+     public static final int STATUS_ERROR= 1;
+     public static final int STATUS_FAILURE= 2;
+
+     public void testRunStarted(String testSuiteName, int testCount);
+     public void testRunEnded(long elapsedTime);
+     public void testRunStopped(long elapsedTime);
+     public void testStarted(String testName);
+     public void testEnded(String testName);
+     public void testFailed(int status, String testName, String trace);
+}
diff --git a/dx/src/junit/runner/TestSuiteLoader.java b/dx/src/junit/runner/TestSuiteLoader.java
new file mode 100644
index 0000000..39a4cf7
--- /dev/null
+++ b/dx/src/junit/runner/TestSuiteLoader.java
@@ -0,0 +1,9 @@
+package junit.runner;
+
+/**
+ * An interface to define how a test suite should be loaded.
+ */
+public interface TestSuiteLoader {
+	abstract public Class load(String suiteClassName) throws ClassNotFoundException;
+	abstract public Class reload(Class aClass) throws ClassNotFoundException;
+}
diff --git a/dx/src/junit/runner/Version.java b/dx/src/junit/runner/Version.java
new file mode 100644
index 0000000..b4541ab
--- /dev/null
+++ b/dx/src/junit/runner/Version.java
@@ -0,0 +1,14 @@
+package junit.runner;
+
+/**
+ * This class defines the current version of JUnit
+ */
+public class Version {
+	private Version() {
+		// don't instantiate
+	}
+
+	public static String id() {
+		return "3.8.1";
+	}
+}
diff --git a/dx/src/junit/runner/excluded.properties b/dx/src/junit/runner/excluded.properties
new file mode 100644
index 0000000..3284628
--- /dev/null
+++ b/dx/src/junit/runner/excluded.properties
@@ -0,0 +1,12 @@
+#
+# The list of excluded package paths for the TestCaseClassLoader
+#
+excluded.0=sun.*
+excluded.1=com.sun.*
+excluded.2=org.omg.*
+excluded.3=javax.*
+excluded.4=sunw.*
+excluded.5=java.*
+excluded.6=org.w3c.dom.*
+excluded.7=org.xml.sax.*
+excluded.8=net.jini.*
diff --git a/dx/src/junit/runner/logo.gif b/dx/src/junit/runner/logo.gif
new file mode 100644
index 0000000..d0e1547
--- /dev/null
+++ b/dx/src/junit/runner/logo.gif
Binary files differ
diff --git a/dx/src/junit/runner/smalllogo.gif b/dx/src/junit/runner/smalllogo.gif
new file mode 100644
index 0000000..7b25eaf
--- /dev/null
+++ b/dx/src/junit/runner/smalllogo.gif
Binary files differ
diff --git a/dx/src/junit/textui/ResultPrinter.java b/dx/src/junit/textui/ResultPrinter.java
new file mode 100644
index 0000000..1ebb7a1
--- /dev/null
+++ b/dx/src/junit/textui/ResultPrinter.java
@@ -0,0 +1,139 @@
+
+package junit.textui;
+
+import java.io.PrintStream;
+import java.text.NumberFormat;
+import java.util.Enumeration;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.runner.BaseTestRunner;
+
+public class ResultPrinter implements TestListener {
+	PrintStream fWriter;
+	int fColumn= 0;
+	
+	public ResultPrinter(PrintStream writer) {
+		fWriter= writer;
+	}
+	
+	/* API for use by textui.TestRunner
+	 */
+
+	synchronized void print(TestResult result, long runTime) {
+		printHeader(runTime);
+	    printErrors(result);
+	    printFailures(result);
+	    printFooter(result);
+	}
+
+	void printWaitPrompt() {
+		getWriter().println();
+		getWriter().println("<RETURN> to continue");
+	}
+	
+	/* Internal methods 
+	 */
+
+	protected void printHeader(long runTime) {
+		getWriter().println();
+		getWriter().println("Time: "+elapsedTimeAsString(runTime));
+	}
+	
+	protected void printErrors(TestResult result) {
+		printDefects(result.errors(), result.errorCount(), "error");
+	}
+	
+	protected void printFailures(TestResult result) {
+		printDefects(result.failures(), result.failureCount(), "failure");
+	}
+	
+	protected void printDefects(Enumeration booBoos, int count, String type) {
+		if (count == 0) return;
+		if (count == 1)
+			getWriter().println("There was " + count + " " + type + ":");
+		else
+			getWriter().println("There were " + count + " " + type + "s:");
+		for (int i= 1; booBoos.hasMoreElements(); i++) {
+			printDefect((TestFailure) booBoos.nextElement(), i);
+		}
+	}
+	
+	public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
+		printDefectHeader(booBoo, count);
+		printDefectTrace(booBoo);
+	}
+
+	protected void printDefectHeader(TestFailure booBoo, int count) {
+		// I feel like making this a println, then adding a line giving the throwable a chance to print something
+		// before we get to the stack trace.
+		getWriter().print(count + ") " + booBoo.failedTest());
+	}
+
+	protected void printDefectTrace(TestFailure booBoo) {
+		getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
+	}
+
+	protected void printFooter(TestResult result) {
+		if (result.wasSuccessful()) {
+			getWriter().println();
+			getWriter().print("OK");
+			getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")");
+
+		} else {
+			getWriter().println();
+			getWriter().println("FAILURES!!!");
+			getWriter().println("Tests run: "+result.runCount()+ 
+				         ",  Failures: "+result.failureCount()+
+				         ",  Errors: "+result.errorCount());
+		}
+	    getWriter().println();
+	}
+
+
+	/**
+	 * Returns the formatted string of the elapsed time.
+	 * Duplicated from BaseTestRunner. Fix it.
+	 */
+	protected String elapsedTimeAsString(long runTime) {
+		return NumberFormat.getInstance().format((double)runTime/1000);
+	}
+
+	public PrintStream getWriter() {
+		return fWriter;
+	}
+	/**
+	 * @see junit.framework.TestListener#addError(Test, Throwable)
+	 */
+	public void addError(Test test, Throwable t) {
+		getWriter().print("E");
+	}
+
+	/**
+	 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+	 */
+	public void addFailure(Test test, AssertionFailedError t) {
+		getWriter().print("F");
+	}
+
+	/**
+	 * @see junit.framework.TestListener#endTest(Test)
+	 */
+	public void endTest(Test test) {
+	}
+
+	/**
+	 * @see junit.framework.TestListener#startTest(Test)
+	 */
+	public void startTest(Test test) {
+		getWriter().print(".");
+		if (fColumn++ >= 40) {
+			getWriter().println();
+			fColumn= 0;
+		}
+	}
+
+}
diff --git a/dx/src/junit/textui/TestRunner.java b/dx/src/junit/textui/TestRunner.java
new file mode 100644
index 0000000..8bdc325
--- /dev/null
+++ b/dx/src/junit/textui/TestRunner.java
@@ -0,0 +1,189 @@
+package junit.textui;
+
+
+import java.io.PrintStream;
+
+import junit.framework.*;
+import junit.runner.*;
+
+/**
+ * A command line based tool to run tests.
+ * <pre>
+ * java junit.textui.TestRunner [-wait] TestCaseClass
+ * </pre>
+ * TestRunner expects the name of a TestCase class as argument.
+ * If this class defines a static <code>suite</code> method it 
+ * will be invoked and the returned test is run. Otherwise all 
+ * the methods starting with "test" having no arguments are run.
+ * <p>
+ * When the wait command line argument is given TestRunner
+ * waits until the users types RETURN.
+ * <p>
+ * TestRunner prints a trace as the tests are executed followed by a
+ * summary at the end. 
+ */
+public class TestRunner extends BaseTestRunner {
+	private ResultPrinter fPrinter;
+	
+	public static final int SUCCESS_EXIT= 0;
+	public static final int FAILURE_EXIT= 1;
+	public static final int EXCEPTION_EXIT= 2;
+
+	/**
+	 * Constructs a TestRunner.
+	 */
+	public TestRunner() {
+		this(System.out);
+	}
+
+	/**
+	 * Constructs a TestRunner using the given stream for all the output
+	 */
+	public TestRunner(PrintStream writer) {
+		this(new ResultPrinter(writer));
+	}
+	
+	/**
+	 * Constructs a TestRunner using the given ResultPrinter all the output
+	 */
+	public TestRunner(ResultPrinter printer) {
+		fPrinter= printer;
+	}
+	
+	/**
+	 * Runs a suite extracted from a TestCase subclass.
+	 */
+	static public void run(Class testClass) {
+		run(new TestSuite(testClass));
+	}
+
+	/**
+	 * Runs a single test and collects its results.
+	 * This method can be used to start a test run
+	 * from your program.
+	 * <pre>
+	 * public static void main (String[] args) {
+	 *     test.textui.TestRunner.run(suite());
+	 * }
+	 * </pre>
+	 */
+	static public TestResult run(Test test) {
+		TestRunner runner= new TestRunner();
+		return runner.doRun(test);
+	}
+
+	/**
+	 * Runs a single test and waits until the user
+	 * types RETURN.
+	 */
+	static public void runAndWait(Test suite) {
+		TestRunner aTestRunner= new TestRunner();
+		aTestRunner.doRun(suite, true);
+	}
+
+	/**
+	 * Always use the StandardTestSuiteLoader. Overridden from
+	 * BaseTestRunner.
+	 */
+	public TestSuiteLoader getLoader() {
+		return new StandardTestSuiteLoader();
+	}
+
+	public void testFailed(int status, Test test, Throwable t) {
+	}
+	
+	public void testStarted(String testName) {
+	}
+	
+	public void testEnded(String testName) {
+	}
+
+	/**
+	 * Creates the TestResult to be used for the test run.
+	 */
+	protected TestResult createTestResult() {
+		return new TestResult();
+	}
+	
+	public TestResult doRun(Test test) {
+		return doRun(test, false);
+	}
+	
+	public TestResult doRun(Test suite, boolean wait) {
+		TestResult result= createTestResult();
+		result.addListener(fPrinter);
+		long startTime= System.currentTimeMillis();
+		suite.run(result);
+		long endTime= System.currentTimeMillis();
+		long runTime= endTime-startTime;
+		fPrinter.print(result, runTime);
+
+		pause(wait);
+		return result;
+	}
+
+	protected void pause(boolean wait) {
+		if (!wait) return;
+		fPrinter.printWaitPrompt();
+		try {
+			System.in.read();
+		}
+		catch(Exception e) {
+		}
+	}
+	
+	public static void main(String args[]) {
+		TestRunner aTestRunner= new TestRunner();
+		try {
+			TestResult r= aTestRunner.start(args);
+			if (!r.wasSuccessful()) 
+				System.exit(FAILURE_EXIT);
+			System.exit(SUCCESS_EXIT);
+		} catch(Exception e) {
+			System.err.println(e.getMessage());
+			System.exit(EXCEPTION_EXIT);
+		}
+	}
+
+	/**
+	 * Starts a test run. Analyzes the command line arguments
+	 * and runs the given test suite.
+	 */
+	protected TestResult start(String args[]) throws Exception {
+		String testCase= "";
+		boolean wait= false;
+		
+		for (int i= 0; i < args.length; i++) {
+			if (args[i].equals("-wait"))
+				wait= true;
+			else if (args[i].equals("-c")) 
+				testCase= extractClassName(args[++i]);
+			else if (args[i].equals("-v"))
+				System.err.println("JUnit "+Version.id()+" by Kent Beck and Erich Gamma");
+			else
+				testCase= args[i];
+		}
+		
+		if (testCase.equals("")) 
+			throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
+
+		try {
+			Test suite= getTest(testCase);
+			return doRun(suite, wait);
+		}
+		catch(Exception e) {
+			throw new Exception("Could not create and run test suite: "+e);
+		}
+	}
+		
+	protected void runFailed(String message) {
+		System.err.println(message);
+		System.exit(FAILURE_EXIT);
+	}
+	
+	public void setPrinter(ResultPrinter printer) {
+		fPrinter= printer;
+	}
+		
+	
+}
diff --git a/dx/tests/001-nop/expected.txt b/dx/tests/001-nop/expected.txt
new file mode 100644
index 0000000..d4a85ce
--- /dev/null
+++ b/dx/tests/001-nop/expected.txt
@@ -0,0 +1 @@
+I am a jelly donut.
diff --git a/dx/tests/001-nop/info.txt b/dx/tests/001-nop/info.txt
new file mode 100644
index 0000000..9942f10
--- /dev/null
+++ b/dx/tests/001-nop/info.txt
@@ -0,0 +1,2 @@
+This is a sample no-op test, which does at least serve to verify that the
+test harness is working.
diff --git a/dx/tests/001-nop/run b/dx/tests/001-nop/run
new file mode 100644
index 0000000..51637c1
--- /dev/null
+++ b/dx/tests/001-nop/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+echo 'I am a jelly donut.'
diff --git a/dx/tests/002-minimal-valid/expected.txt b/dx/tests/002-minimal-valid/expected.txt
new file mode 100644
index 0000000..3877fb5
--- /dev/null
+++ b/dx/tests/002-minimal-valid/expected.txt
@@ -0,0 +1,46 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 000a
+
+constant_pool:
+  0001: method{java.lang.Object.<init>:()V}
+  0002: type{Small}
+  0003: type{java.lang.Object}
+  0004: utf8{"<init>"}
+  0005: utf8{"()V"}
+  0006: utf8{"Code"}
+  0007: nat{<init>:()V}
+  0008: utf8{"Small"}
+  0009: utf8{"java/lang/Object"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public
+  name: <init>
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Code
+    length: 00000011
+    max_stack: 0001
+    max_locals: 0001
+    code_length: 00000005
+    0000: aload_0 // 00
+    0001: invokespecial method{java.lang.Object.<init>:()V}
+    0004: return
+    exception_table_length: 0000
+    attributes_count: 0000
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/002-minimal-valid/info.txt b/dx/tests/002-minimal-valid/info.txt
new file mode 100644
index 0000000..f296af8
--- /dev/null
+++ b/dx/tests/002-minimal-valid/info.txt
@@ -0,0 +1 @@
+This is just a dump of a simple but valid class.
diff --git a/dx/tests/002-minimal-valid/run b/dx/tests/002-minimal-valid/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/002-minimal-valid/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/002-minimal-valid/small-class.txt b/dx/tests/002-minimal-valid/small-class.txt
new file mode 100644
index 0000000..25a323f
--- /dev/null
+++ b/dx/tests/002-minimal-valid/small-class.txt
@@ -0,0 +1,49 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+000a       # constant_pool_count
+
+#
+# constant_pool
+#
+0a 0003 0007               # 0001: method[0003, 0007]
+07 0008                    # 0002: class[0008]
+07 0009                    # 0003: class[0009]
+01 0006 "<init>"           # 0004: utf8["<init>"]
+01 0003 "()V"              # 0005: utf8["()V"]
+01 0004 "Code"             # 0006: utf8["Code"]
+0c 0004 0005               # 0007: nat[0004, 0005]
+01 0005 "Small"            # 0008: utf8["Small"]
+01 0010 "java/lang/Object" # 0009: utf8["java/lang/Object"]
+
+0021  # access_flags
+0002  # this_class
+0003  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+#
+# methods[0]
+#
+0001  # access_flags
+0004  # name
+0005  # descriptor
+0001  # attributes_count
+# attributes[0]
+0006       # name
+0000 0011  # length
+0001       # max_stack
+0001       # max_locals
+0000 0005  # code_length
+2a         # 0000: aload_0
+b7 0001    # 0001: invokespecial method[java/lang/Object.<init>:()V]
+b1         # 0004: return
+0000       # exception_table_length
+0000       # attributes_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-bad-magic.txt b/dx/tests/003-magic-version-access/class-bad-magic.txt
new file mode 100644
index 0000000..f3c64bd
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-bad-magic.txt
@@ -0,0 +1,25 @@
+#
+# classfile with a bad magic value
+#
+
+dead babe  # magic
+0000       # minor_version
+0031       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-44.0.txt b/dx/tests/003-magic-version-access/class-version-44.0.txt
new file mode 100644
index 0000000..2d9055c
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-44.0.txt
@@ -0,0 +1,25 @@
+#
+# classfile with an out-of-range version.
+#
+
+cafe babe  # magic
+0000       # minor_version
+002c       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-44.65535.txt b/dx/tests/003-magic-version-access/class-version-44.65535.txt
new file mode 100644
index 0000000..0f2b582
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-44.65535.txt
@@ -0,0 +1,25 @@
+#
+# classfile with an out-of-range version.
+#
+
+cafe babe  # magic
+ffff       # minor_version
+002c       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-45.0.txt b/dx/tests/003-magic-version-access/class-version-45.0.txt
new file mode 100644
index 0000000..335079d
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-45.0.txt
@@ -0,0 +1,25 @@
+#
+# classfile with the lowest valid version, 45.0 (0x2d.0x00)
+#
+
+cafe babe  # magic
+0000       # minor_version
+002d       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-45.65535.txt b/dx/tests/003-magic-version-access/class-version-45.65535.txt
new file mode 100644
index 0000000..2b31404
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-45.65535.txt
@@ -0,0 +1,25 @@
+#
+# classfile with the valid version 45.65535 (0x2d.0xffff)
+#
+
+cafe babe  # magic
+ffff       # minor_version
+002d       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-48.0.txt b/dx/tests/003-magic-version-access/class-version-48.0.txt
new file mode 100644
index 0000000..551b221
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-48.0.txt
@@ -0,0 +1,25 @@
+#
+# classfile with the valid version 48.0 (0x30.0x00)
+#
+
+cafe babe  # magic
+0000       # minor_version
+0030       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-48.65535.txt b/dx/tests/003-magic-version-access/class-version-48.65535.txt
new file mode 100644
index 0000000..ac95b52
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-48.65535.txt
@@ -0,0 +1,25 @@
+#
+# classfile with the valid version 48.65535 (0x30.0xffff)
+#
+
+cafe babe  # magic
+ffff       # minor_version
+0030       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-49.0.txt b/dx/tests/003-magic-version-access/class-version-49.0.txt
new file mode 100644
index 0000000..0b30fcd
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-49.0.txt
@@ -0,0 +1,25 @@
+#
+# classfile with the highest valid version, 49.0 (0x31.0x00)
+#
+
+cafe babe  # magic
+0000       # minor_version
+0031       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-49.1.txt b/dx/tests/003-magic-version-access/class-version-49.1.txt
new file mode 100644
index 0000000..9eb477c
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-49.1.txt
@@ -0,0 +1,26 @@
+#
+# classfile with a minor version 1 higher than the highest valid
+# version.  49.1 (0x31.0x01)
+#
+
+cafe babe  # magic
+0001       # minor_version
+0031       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-49.65535.txt b/dx/tests/003-magic-version-access/class-version-49.65535.txt
new file mode 100644
index 0000000..668631b
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-49.65535.txt
@@ -0,0 +1,26 @@
+#
+# classfile with an invalid version, with the same major version
+# as the highest valid version.  49.65535 (0x31.0xffff)
+#
+
+cafe babe  # magic
+ffff       # minor_version
+0031       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-50.0.txt b/dx/tests/003-magic-version-access/class-version-50.0.txt
new file mode 100644
index 0000000..fa67077
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-50.0.txt
@@ -0,0 +1,26 @@
+#
+# classfile with an invalid version, with a higher major version
+# than the highest valid version.  50.0 (0x32.0x00)
+#
+
+cafe babe  # magic
+0000       # minor_version
+0032       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-50.1.txt b/dx/tests/003-magic-version-access/class-version-50.1.txt
new file mode 100644
index 0000000..9543be1
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-50.1.txt
@@ -0,0 +1,26 @@
+#
+# classfile with an invalid version, with a higher major version
+# than the highest valid version.  50.0 (0x32.0x00)
+#
+
+cafe babe  # magic
+0001       # minor_version
+0032       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-50.65535.txt b/dx/tests/003-magic-version-access/class-version-50.65535.txt
new file mode 100644
index 0000000..9db1958
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-50.65535.txt
@@ -0,0 +1,26 @@
+#
+# classfile with an invalid version, with a higher major version
+# than the highest valid version.  50.0 (0x32.0x00)
+#
+
+cafe babe  # magic
+ffff       # minor_version
+0032       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/class-version-51.0.txt b/dx/tests/003-magic-version-access/class-version-51.0.txt
new file mode 100644
index 0000000..2ffb4cd
--- /dev/null
+++ b/dx/tests/003-magic-version-access/class-version-51.0.txt
@@ -0,0 +1,26 @@
+#
+# classfile with an invalid version, with a higher major version
+# than the highest valid version.  50.0 (0x32.0x00)
+#
+
+cafe babe  # magic
+0000       # minor_version
+0033       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/003-magic-version-access/expected.txt b/dx/tests/003-magic-version-access/expected.txt
new file mode 100644
index 0000000..a632922
--- /dev/null
+++ b/dx/tests/003-magic-version-access/expected.txt
@@ -0,0 +1,243 @@
+reading class-bad-magic.txt...
+begin classfile
+magic: deadbabe
+minor_version: 0000
+major_version: 0031
+
+trouble parsing:
+bad class file magic (deadbabe) or version (0031.0000)
+...while parsing class-bad-magic.txt
+reading class-version-44.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002c
+
+trouble parsing:
+bad class file magic (cafebabe) or version (002c.0000)
+...while parsing class-version-44.0.txt
+reading class-version-44.65535.txt...
+begin classfile
+magic: cafebabe
+minor_version: ffff
+major_version: 002c
+
+trouble parsing:
+bad class file magic (cafebabe) or version (002c.ffff)
+...while parsing class-version-44.65535.txt
+reading class-version-45.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002d
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-45.65535.txt...
+begin classfile
+magic: cafebabe
+minor_version: ffff
+major_version: 002d
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-48.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 0030
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-48.65535.txt...
+begin classfile
+magic: cafebabe
+minor_version: ffff
+major_version: 0030
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-49.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 0031
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-49.1.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0001
+major_version: 0031
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-49.65535.txt...
+begin classfile
+magic: cafebabe
+minor_version: ffff
+major_version: 0031
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-50.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 0032
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
+reading class-version-50.1.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0001
+major_version: 0032
+
+trouble parsing:
+bad class file magic (cafebabe) or version (0032.0001)
+...while parsing class-version-50.1.txt
+reading class-version-50.65535.txt...
+begin classfile
+magic: cafebabe
+minor_version: ffff
+major_version: 0032
+
+trouble parsing:
+bad class file magic (cafebabe) or version (0032.ffff)
+...while parsing class-version-50.65535.txt
+reading class-version-51.0.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 0033
+
+trouble parsing:
+bad class file magic (cafebabe) or version (0033.0000)
+...while parsing class-version-51.0.txt
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 0031
+constant_pool_count: 0005
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+end constant_pool
+access_flags: public|final|super|interface|abstract|synthetic|annotation|enum|89ce
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/003-magic-version-access/info.txt b/dx/tests/003-magic-version-access/info.txt
new file mode 100644
index 0000000..4d6a697
--- /dev/null
+++ b/dx/tests/003-magic-version-access/info.txt
@@ -0,0 +1,9 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bits of parsing tested here are:
+
+* magic number
+* major / minor version numbers
+* class access_flags
diff --git a/dx/tests/003-magic-version-access/run b/dx/tests/003-magic-version-access/run
new file mode 100644
index 0000000..24de48e
--- /dev/null
+++ b/dx/tests/003-magic-version-access/run
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# 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.
+
+# The tests that don't specify "--debug" are expected to
+# throw exceptions.  If --debug is on we'll get a stack
+# trace, which is unpredictable and doesn't work well with
+# expected.txt vs. out.txt comparisons.
+
+# Bad magic (throws an expection)
+dx         --dump --strict class-bad-magic.txt
+
+# Too small (throws an exception)
+dx         --dump --strict class-version-44.0.txt
+dx         --dump --strict class-version-44.65535.txt
+
+# Just right
+dx --debug --dump --width=100 class-version-45.0.txt
+dx --debug --dump --width=100 class-version-45.65535.txt
+dx --debug --dump --width=100 class-version-48.0.txt
+dx --debug --dump --width=100 class-version-48.65535.txt
+dx --debug --dump --width=100 class-version-49.0.txt
+dx --debug --dump --width=100 class-version-49.1.txt
+dx --debug --dump --width=100 class-version-49.65535.txt
+dx --debug --dump --width=100 class-version-50.0.txt
+
+# Too big (throws an exception)
+dx         --dump --strict class-version-50.1.txt
+dx         --dump --strict class-version-50.65535.txt
+dx         --dump --strict class-version-51.0.txt
+
+# Show that we can dump the access flags even when they
+# don't make any sense.
+dx --debug --dump --width=100 small-class.txt
diff --git a/dx/tests/003-magic-version-access/small-class.txt b/dx/tests/003-magic-version-access/small-class.txt
new file mode 100644
index 0000000..3eb7402
--- /dev/null
+++ b/dx/tests/003-magic-version-access/small-class.txt
@@ -0,0 +1,25 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+0031       # major_version
+0005       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+
+ffff  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/004-cp-bottom-up/expected.txt b/dx/tests/004-cp-bottom-up/expected.txt
new file mode 100644
index 0000000..4edbed5
--- /dev/null
+++ b/dx/tests/004-cp-bottom-up/expected.txt
@@ -0,0 +1,34 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0014
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"blort"}
+  0006: utf8{"x/y/Zzz"}
+  0007: utf8{"()V"}
+  0008: nat{blort:x/y/Zzz}
+  0009: nat{blort:()V}
+  000a: field{Small.blort:x/y/Zzz}
+  000b: method{Small.blort:()V}
+  000c: ifaceMethod{Small.blort:()V}
+  000d: string{"Small"}
+  000e: int{0x12345678 / 305419896}
+  000f: float{0x42f6e666 / 123.45}
+  0010: long{0x123456789abcdef0 / 1311768467463790320}
+  0012: double{0x411958955f8a0903 / 415269.3433}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/004-cp-bottom-up/info.txt b/dx/tests/004-cp-bottom-up/info.txt
new file mode 100644
index 0000000..f78a626
--- /dev/null
+++ b/dx/tests/004-cp-bottom-up/info.txt
@@ -0,0 +1,8 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the constant pool contains
+at least one valid entry of each possible constant pool type, and that
+entries that are referred to by other entries always occur before the
+referring entries.
diff --git a/dx/tests/004-cp-bottom-up/run b/dx/tests/004-cp-bottom-up/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/004-cp-bottom-up/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/004-cp-bottom-up/small-class.txt b/dx/tests/004-cp-bottom-up/small-class.txt
new file mode 100644
index 0000000..8a68cbf
--- /dev/null
+++ b/dx/tests/004-cp-bottom-up/small-class.txt
@@ -0,0 +1,38 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0014       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0007 "x/y/Zzz"          # 0006: utf8["x/y/Zzz"]
+01 0003 "()V"              # 0007: utf8["()V"]
+0c 0005 0006               # 0008: nat[blort:x/y/Zzz]
+0c 0005 0007               # 0009: nat[blort:()V]
+09 0003 0008               # 000a: field[Small.blort:x/y/Zzz]
+0a 0003 0009               # 000b: method[Small.blort:()V]
+0b 0003 0009               # 000c: ifaceMethod[Small.blort:()V]
+08 0001                    # 000d: string["Small"]
+03 12345678                # 000e: integer[0x12345678]
+04 42f6e666                # 000f: float[123.45]
+05 12345678 9abcdef0       # 0010: long[0x1234567890abcdef0]
+06 41195895 5f8a0903       # 0012: double[415269.3433]
+
+0001  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/005-cp-top-down/expected.txt b/dx/tests/005-cp-top-down/expected.txt
new file mode 100644
index 0000000..791b9da
--- /dev/null
+++ b/dx/tests/005-cp-top-down/expected.txt
@@ -0,0 +1,34 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0014
+
+constant_pool:
+  0001: double{0x411958955f8a0903 / 415269.3433}
+  0003: long{0x123456789abcdef0 / 1311768467463790320}
+  0005: float{0x42f6e666 / 123.45}
+  0006: int{0x12345678 / 305419896}
+  0007: string{"Small"}
+  0008: ifaceMethod{Small.blort:()V}
+  0009: method{Small.blort:()V}
+  000a: field{Small.blort:x/y/Zzz}
+  000b: nat{blort:()V}
+  000c: nat{blort:x/y/Zzz}
+  000d: utf8{"()V"}
+  000e: utf8{"x/y/Zzz"}
+  000f: utf8{"blort"}
+  0010: type{java.lang.Object}
+  0011: type{Small}
+  0012: utf8{"java/lang/Object"}
+  0013: utf8{"Small"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/005-cp-top-down/info.txt b/dx/tests/005-cp-top-down/info.txt
new file mode 100644
index 0000000..5842fb3
--- /dev/null
+++ b/dx/tests/005-cp-top-down/info.txt
@@ -0,0 +1,8 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the constant pool contains
+at least one valid entry of each possible constant pool type, and that
+entries that are referred to by other entries always occur after the
+referring entries.
diff --git a/dx/tests/005-cp-top-down/run b/dx/tests/005-cp-top-down/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/005-cp-top-down/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/005-cp-top-down/small-class.txt b/dx/tests/005-cp-top-down/small-class.txt
new file mode 100644
index 0000000..a681f65
--- /dev/null
+++ b/dx/tests/005-cp-top-down/small-class.txt
@@ -0,0 +1,38 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0014       # constant_pool_count
+
+#
+# constant_pool
+#
+06 41195895 5f8a0903       # 0001: double[415269.3433]
+05 12345678 9abcdef0       # 0003: long[0x1234567890abcdef0]
+04 42f6e666                # 0005: float[123.45]
+03 12345678                # 0006: integer[0x12345678]
+08 0013                    # 0007: string["Small"]
+0b 0011 000b               # 0008: ifaceMethod[Small.blort:()V]
+0a 0011 000b               # 0009: method[Small.blort:()V]
+09 0011 000c               # 000a: field[Small.blort:x/y/Zzz]
+0c 000f 000d               # 000b: nat[blort:()V]
+0c 000f 000e               # 000c: nat[blort:x/y/Zzz]
+01 0003 "()V"              # 000d: utf8["()V"]
+01 0007 "x/y/Zzz"          # 000e: utf8["x/y/Zzz"]
+01 0005 "blort"            # 000f: utf8["blort"]
+07 0012                    # 0010: class[java/lang/Object]
+07 0013                    # 0011: class[Small]
+01 0010 "java/lang/Object" # 0012: utf8["java/lang/Object"]
+01 0005 "Small"            # 0013: utf8["Small"]
+
+0001  # access_flags
+0011  # this_class
+0010  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/006-interfaces/expected.txt b/dx/tests/006-interfaces/expected.txt
new file mode 100644
index 0000000..09e066b
--- /dev/null
+++ b/dx/tests/006-interfaces/expected.txt
@@ -0,0 +1,31 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 000b
+
+constant_pool:
+  0001: utf8{"java/lang/Object"}
+  0002: utf8{"Small"}
+  0003: utf8{"Foo"}
+  0004: utf8{"Bar"}
+  0005: utf8{"Baz"}
+  0006: type{java.lang.Object}
+  0007: type{Small}
+  0008: type{Foo}
+  0009: type{Bar}
+  000a: type{Baz}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0003
+interfaces:
+  type{Foo}
+  type{Bar}
+  type{Baz}
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/006-interfaces/info.txt b/dx/tests/006-interfaces/info.txt
new file mode 100644
index 0000000..0959482
--- /dev/null
+++ b/dx/tests/006-interfaces/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a non-empty
+interfaces list.
diff --git a/dx/tests/006-interfaces/run b/dx/tests/006-interfaces/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/006-interfaces/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/006-interfaces/small-class.txt b/dx/tests/006-interfaces/small-class.txt
new file mode 100644
index 0000000..ea24923
--- /dev/null
+++ b/dx/tests/006-interfaces/small-class.txt
@@ -0,0 +1,33 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+000b       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0010 "java/lang/Object" # 0001: utf8["java/lang/Object"]
+01 0005 "Small"            # 0002: utf8["Small"]
+01 0003 "Foo"              # 0003: utf8["Foo"]
+01 0003 "Bar"              # 0004: utf8["Bar"]
+01 0003 "Baz"              # 0005: utf8["Baz"]
+07 0001                    # 0006: class[java/lang/Object]
+07 0002                    # 0007: class[Small]
+07 0003                    # 0008: class[Foo]
+07 0004                    # 0009: class[Bar]
+07 0005                    # 000a: class[Baz]
+
+0001  # access_flags
+0007  # this_class
+0006  # super_class
+0003  # interfaces_count
+0008 0009 000a  # interfaces
+
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/007-no-superclass/expected.txt b/dx/tests/007-no-superclass/expected.txt
new file mode 100644
index 0000000..d635c9a
--- /dev/null
+++ b/dx/tests/007-no-superclass/expected.txt
@@ -0,0 +1,19 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0003
+
+constant_pool:
+  0001: utf8{"java/lang/Object"}
+  0002: type{java.lang.Object}
+end constant_pool
+access_flags: public
+this_class: type{java.lang.Object}
+super_class: (none)
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/007-no-superclass/info.txt b/dx/tests/007-no-superclass/info.txt
new file mode 100644
index 0000000..5f941d0
--- /dev/null
+++ b/dx/tests/007-no-superclass/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class is Object-like and
+has no superclass.
diff --git a/dx/tests/007-no-superclass/run b/dx/tests/007-no-superclass/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/007-no-superclass/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/007-no-superclass/small-class.txt b/dx/tests/007-no-superclass/small-class.txt
new file mode 100644
index 0000000..6fd4408
--- /dev/null
+++ b/dx/tests/007-no-superclass/small-class.txt
@@ -0,0 +1,24 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0003       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0010 "java/lang/Object" # 0001: utf8["java/lang/Object"]
+07 0001                    # 0002: class[java/lang/Object]
+
+0001  # access_flags
+0002  # this_class
+0000  # super_class
+0000  # interfaces_count
+
+0000  # fields_count
+0000  # methods_count
+
+0000  # attributes_count
diff --git a/dx/tests/008-field/expected.txt b/dx/tests/008-field/expected.txt
new file mode 100644
index 0000000..9e3bcaf
--- /dev/null
+++ b/dx/tests/008-field/expected.txt
@@ -0,0 +1,30 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0007
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"foo"}
+  0006: utf8{"I"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0001
+
+fields[0]:
+  access_flags: public|private|protected|static|final|volatile|transient|synthetic|enum|af20
+  name: foo
+  descriptor: I
+  attributes_count: 0000
+end fields[0]
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/008-field/info.txt b/dx/tests/008-field/info.txt
new file mode 100644
index 0000000..0b8e92f
--- /dev/null
+++ b/dx/tests/008-field/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+simple field with no attributes and with every access flag turned on
+(so that the names can be verified in debugging output).
diff --git a/dx/tests/008-field/run b/dx/tests/008-field/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/008-field/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/008-field/small-class.txt b/dx/tests/008-field/small-class.txt
new file mode 100644
index 0000000..81eb164
--- /dev/null
+++ b/dx/tests/008-field/small-class.txt
@@ -0,0 +1,34 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0007       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0003 "foo"              # 0005: utf8["foo"]
+01 0001 "I"                # 0006: utf8["I"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+
+0001  # fields_count
+
+# fields[0]
+ffff  # access_flags
+0005  # name
+0006  # descriptor
+0000  # attributes_count
+
+0000  # methods_count
+0000  # attributes_count
diff --git a/dx/tests/009-method/expected.txt b/dx/tests/009-method/expected.txt
new file mode 100644
index 0000000..3c0d6ad
--- /dev/null
+++ b/dx/tests/009-method/expected.txt
@@ -0,0 +1,30 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0007
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"foo"}
+  0006: utf8{"()V"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public|private|protected|static|final|synchronized|bridge|varargs|native|abstract|strictfp|synthetic|e200
+  name: foo
+  descriptor: ()V
+  attributes_count: 0000
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/009-method/info.txt b/dx/tests/009-method/info.txt
new file mode 100644
index 0000000..3df2f09
--- /dev/null
+++ b/dx/tests/009-method/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+simple method with no attributes and with every access flag turned on
+(so that the names can be verified in debugging output).
diff --git a/dx/tests/009-method/run b/dx/tests/009-method/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/009-method/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/009-method/small-class.txt b/dx/tests/009-method/small-class.txt
new file mode 100644
index 0000000..54fbc5f
--- /dev/null
+++ b/dx/tests/009-method/small-class.txt
@@ -0,0 +1,34 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0007       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0003 "foo"              # 0005: utf8["foo"]
+01 0003 "()V"              # 0006: utf8["()V"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+
+0001  # methods_count
+
+# methods[0]
+ffff  # access_flags
+0005  # name
+0006  # descriptor
+0000  # attributes_count
+
+0000  # attributes_count
diff --git a/dx/tests/010-class-attrib-InnerClasses/expected.txt b/dx/tests/010-class-attrib-InnerClasses/expected.txt
new file mode 100644
index 0000000..f588190
--- /dev/null
+++ b/dx/tests/010-class-attrib-InnerClasses/expected.txt
@@ -0,0 +1,46 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0008
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"InnerClasses"}
+  0006: utf8{"Zorch"}
+  0007: type{Zorch}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: InnerClasses
+  length: 00000022
+  number_of_classes: 0004
+  inner_class: type{Small}
+    outer_class: (none)
+    name: (none)
+    access_flags: public
+  inner_class: type{Small}
+    outer_class: (none)
+    name: string{"Small"}
+    access_flags: private
+  inner_class: type{Small}
+    outer_class: type{Zorch}
+    name: (none)
+    access_flags: protected
+  inner_class: type{Zorch}
+    outer_class: type{Small}
+    name: string{"Zorch"}
+    access_flags: public|private|protected|static|final|interface|abstract|synthetic|annotation|enum|89e0
+end attributes[0]
+end classfile
diff --git a/dx/tests/010-class-attrib-InnerClasses/info.txt b/dx/tests/010-class-attrib-InnerClasses/info.txt
new file mode 100644
index 0000000..305b035
--- /dev/null
+++ b/dx/tests/010-class-attrib-InnerClasses/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+class-level InnerClasses attribute, which is syntactically valid and contains
+one entry for each of the possible combinations of null-vs-valid cpe.
diff --git a/dx/tests/010-class-attrib-InnerClasses/run b/dx/tests/010-class-attrib-InnerClasses/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/010-class-attrib-InnerClasses/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/010-class-attrib-InnerClasses/small-class.txt b/dx/tests/010-class-attrib-InnerClasses/small-class.txt
new file mode 100644
index 0000000..54fd19d
--- /dev/null
+++ b/dx/tests/010-class-attrib-InnerClasses/small-class.txt
@@ -0,0 +1,37 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0008       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 000c "InnerClasses"     # 0005: utf8["InnerClasses"]
+01 0005 "Zorch"            # 0006: utf8["Zorch"]
+07 0006                    # 0007: class[Zorch]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000022  # length
+0004      # number_of_classes
+0003 0000 0000 0001  # Small / null / null / public
+0003 0000 0001 0002  # Small / null / "Small" / private
+0003 0007 0000 0004  # Small / Zorch / null / protected
+0007 0003 0006 ffff  # Zorch / Small / "Zorch" / all-bits
diff --git a/dx/tests/011-class-attrib-Synthetic/expected.txt b/dx/tests/011-class-attrib-Synthetic/expected.txt
new file mode 100644
index 0000000..85e2bff
--- /dev/null
+++ b/dx/tests/011-class-attrib-Synthetic/expected.txt
@@ -0,0 +1,27 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0006
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"Synthetic"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: Synthetic
+  length: 00000000
+end attributes[0]
+end classfile
diff --git a/dx/tests/011-class-attrib-Synthetic/info.txt b/dx/tests/011-class-attrib-Synthetic/info.txt
new file mode 100644
index 0000000..bfd443e
--- /dev/null
+++ b/dx/tests/011-class-attrib-Synthetic/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+class-level Synthetic attribute, which is syntactically valid.
diff --git a/dx/tests/011-class-attrib-Synthetic/run b/dx/tests/011-class-attrib-Synthetic/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/011-class-attrib-Synthetic/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/011-class-attrib-Synthetic/small-class.txt b/dx/tests/011-class-attrib-Synthetic/small-class.txt
new file mode 100644
index 0000000..bc3281b
--- /dev/null
+++ b/dx/tests/011-class-attrib-Synthetic/small-class.txt
@@ -0,0 +1,30 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0006       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0009 "Synthetic"        # 0005: utf8["Synthetic"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000000  # length
diff --git a/dx/tests/012-class-attrib-SourceFile/expected.txt b/dx/tests/012-class-attrib-SourceFile/expected.txt
new file mode 100644
index 0000000..e607900
--- /dev/null
+++ b/dx/tests/012-class-attrib-SourceFile/expected.txt
@@ -0,0 +1,29 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0007
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"SourceFile"}
+  0006: utf8{"Blort.java"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: SourceFile
+  length: 00000002
+  source: string{"Blort.java"}
+end attributes[0]
+end classfile
diff --git a/dx/tests/012-class-attrib-SourceFile/info.txt b/dx/tests/012-class-attrib-SourceFile/info.txt
new file mode 100644
index 0000000..f1d8985
--- /dev/null
+++ b/dx/tests/012-class-attrib-SourceFile/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+class-level SourceFile attribute, which is syntactically valid.
diff --git a/dx/tests/012-class-attrib-SourceFile/run b/dx/tests/012-class-attrib-SourceFile/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/012-class-attrib-SourceFile/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/012-class-attrib-SourceFile/small-class.txt b/dx/tests/012-class-attrib-SourceFile/small-class.txt
new file mode 100644
index 0000000..3c514be
--- /dev/null
+++ b/dx/tests/012-class-attrib-SourceFile/small-class.txt
@@ -0,0 +1,32 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0007       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 000a "SourceFile"       # 0005: utf8["SourceFile"]
+01 000a "Blort.java"       # 0006: utf8["Blort.java"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000002  # length
+0006      # "Blort.java"
diff --git a/dx/tests/013-class-attrib-Deprecated/expected.txt b/dx/tests/013-class-attrib-Deprecated/expected.txt
new file mode 100644
index 0000000..4476c89
--- /dev/null
+++ b/dx/tests/013-class-attrib-Deprecated/expected.txt
@@ -0,0 +1,27 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0006
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"Deprecated"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: Deprecated
+  length: 00000000
+end attributes[0]
+end classfile
diff --git a/dx/tests/013-class-attrib-Deprecated/info.txt b/dx/tests/013-class-attrib-Deprecated/info.txt
new file mode 100644
index 0000000..8164fe1
--- /dev/null
+++ b/dx/tests/013-class-attrib-Deprecated/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+class-level Deprecated attribute, which is syntactically valid.
diff --git a/dx/tests/013-class-attrib-Deprecated/run b/dx/tests/013-class-attrib-Deprecated/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/013-class-attrib-Deprecated/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/013-class-attrib-Deprecated/small-class.txt b/dx/tests/013-class-attrib-Deprecated/small-class.txt
new file mode 100644
index 0000000..03d7e24
--- /dev/null
+++ b/dx/tests/013-class-attrib-Deprecated/small-class.txt
@@ -0,0 +1,30 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0006       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 000a "Deprecated"       # 0005: utf8["Deprecated"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000000  # length
diff --git a/dx/tests/014-field-attrib-ConstantValue/expected.txt b/dx/tests/014-field-attrib-ConstantValue/expected.txt
new file mode 100644
index 0000000..b3d91a5
--- /dev/null
+++ b/dx/tests/014-field-attrib-ConstantValue/expected.txt
@@ -0,0 +1,162 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 001f
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"ConstantValue"}
+  0006: utf8{"a"}
+  0007: utf8{"b"}
+  0008: utf8{"c"}
+  0009: utf8{"d"}
+  000a: utf8{"e"}
+  000b: utf8{"f"}
+  000c: utf8{"g"}
+  000d: utf8{"h"}
+  000e: utf8{"i"}
+  000f: string{"Small"}
+  0010: int{0x8191a1b1 / -2121162319}
+  0011: float{0xbffeb852 / -1.99}
+  0012: long{0x80818283f0f1f2f3 / -9186918261664386317}
+  0014: double{0xbfffd70a3d70a3d7 / -1.99}
+  0016: utf8{"B"}
+  0017: utf8{"C"}
+  0018: utf8{"D"}
+  0019: utf8{"F"}
+  001a: utf8{"I"}
+  001b: utf8{"J"}
+  001c: utf8{"S"}
+  001d: utf8{"Z"}
+  001e: utf8{"Ljava/lang/String;"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0009
+
+fields[0]:
+  access_flags: public
+  name: a
+  descriptor: B
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: int{0x8191a1b1 / -2121162319}
+  end attributes[0]
+end fields[0]
+
+fields[1]:
+  access_flags: private
+  name: b
+  descriptor: C
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: int{0x8191a1b1 / -2121162319}
+  end attributes[0]
+end fields[1]
+
+fields[2]:
+  access_flags: protected
+  name: c
+  descriptor: D
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: double{0xbfffd70a3d70a3d7 / -1.99}
+  end attributes[0]
+end fields[2]
+
+fields[3]:
+  access_flags: static
+  name: d
+  descriptor: F
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: float{0xbffeb852 / -1.99}
+  end attributes[0]
+end fields[3]
+
+fields[4]:
+  access_flags: final
+  name: e
+  descriptor: I
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: int{0x8191a1b1 / -2121162319}
+  end attributes[0]
+end fields[4]
+
+fields[5]:
+  access_flags: volatile
+  name: f
+  descriptor: J
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: long{0x80818283f0f1f2f3 / -9186918261664386317}
+  end attributes[0]
+end fields[5]
+
+fields[6]:
+  access_flags: transient
+  name: g
+  descriptor: S
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: int{0x8191a1b1 / -2121162319}
+  end attributes[0]
+end fields[6]
+
+fields[7]:
+  access_flags: public|static|final
+  name: h
+  descriptor: Z
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: int{0x8191a1b1 / -2121162319}
+  end attributes[0]
+end fields[7]
+
+fields[8]:
+  access_flags: public|static|final
+  name: i
+  descriptor: Ljava/lang/String;
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: ConstantValue
+    length: 00000002
+    value: string{"Small"}
+  end attributes[0]
+end fields[8]
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/014-field-attrib-ConstantValue/info.txt b/dx/tests/014-field-attrib-ConstantValue/info.txt
new file mode 100644
index 0000000..313159c
--- /dev/null
+++ b/dx/tests/014-field-attrib-ConstantValue/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a series of
+fields, each with a single ConstantValue attribute, which points at one
+of the appropriate sorts of cpes.
diff --git a/dx/tests/014-field-attrib-ConstantValue/run b/dx/tests/014-field-attrib-ConstantValue/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/014-field-attrib-ConstantValue/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/014-field-attrib-ConstantValue/small-class.txt b/dx/tests/014-field-attrib-ConstantValue/small-class.txt
new file mode 100644
index 0000000..8d869de
--- /dev/null
+++ b/dx/tests/014-field-attrib-ConstantValue/small-class.txt
@@ -0,0 +1,140 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+001f       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"              # 0001: utf8["Small"]
+01 0010 "java/lang/Object"   # 0002: utf8["java/lang/Object"]
+07 0001                      # 0003: class[Small]
+07 0002                      # 0004: class[java/lang/Object]
+01 000d "ConstantValue"      # 0005: utf8["ConstantValue"]
+01 0001 "a"                  # 0006: utf8["a"]
+01 0001 "b"                  # 0007: utf8["b"]
+01 0001 "c"                  # 0008: utf8["c"]
+01 0001 "d"                  # 0009: utf8["d"]
+01 0001 "e"                  # 000a: utf8["e"]
+01 0001 "f"                  # 000b: utf8["f"]
+01 0001 "g"                  # 000c: utf8["g"]
+01 0001 "h"                  # 000d: utf8["h"]
+01 0001 "i"                  # 000e: utf8["i"]
+08 0001                      # 000f: string["Small"]
+03 8191a1b1                  # 0010: integer[0x8191a1b1]
+04 bffeb852                  # 0011: float[-1.99]
+05 80818283 f0f1f2f3         # 0012: long[0x80818283f0f1f2f3]
+06 bfffd70a 3d70a3d7         # 0014: double[-1.99]
+01 0001 "B"                  # 0016: utf8["B"]
+01 0001 "C"                  # 0017: utf8["C"]
+01 0001 "D"                  # 0018: utf8["D"]
+01 0001 "F"                  # 0019: utf8["F"]
+01 0001 "I"                  # 001a: utf8["I"]
+01 0001 "J"                  # 001b: utf8["J"]
+01 0001 "S"                  # 001c: utf8["S"]
+01 0001 "Z"                  # 001d: utf8["Z"]
+01 0012 "Ljava/lang/String;" # 001e: utf8["Ljava/lang/String;"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+
+0009  # fields_count
+
+# fields[0]
+0001  # access_flags
+0006  # "a"
+0016  # "B"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0010      # value
+
+# fields[1]
+0002  # access_flags
+0007  # "b"
+0017  # "C"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0010      # value
+
+# fields[2]
+0004  # access_flags
+0008  # "c"
+0018  # "D"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0014      # value
+
+# fields[3]
+0008  # access_flags
+0009  # "d"
+0019  # "F"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0011      # value
+
+# fields[4]
+0010  # access_flags
+000a  # "e"
+001a  # "I"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0010      # value
+
+# fields[5]
+0040  # access_flags
+000b  # "f"
+001b  # "J"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0012      # value
+
+# fields[6]
+0080  # access_flags
+000c  # "g"
+001c  # "Z"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0010      # value
+
+# fields[7]
+0019  # access_flags
+000d  # "h"
+001d  # "S"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0010      # value
+
+# fields[8]
+0019  # access_flags
+000e  # "i"
+001e  # "Ljava/lang/String;"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+000f      # value
+
+0000  # methods_count
+0000  # attributes_count
diff --git a/dx/tests/015-field-attrib-Synthetic/expected.txt b/dx/tests/015-field-attrib-Synthetic/expected.txt
new file mode 100644
index 0000000..bdb4519
--- /dev/null
+++ b/dx/tests/015-field-attrib-Synthetic/expected.txt
@@ -0,0 +1,36 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0008
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"Synthetic"}
+  0006: utf8{"a"}
+  0007: utf8{"I"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0001
+
+fields[0]:
+  access_flags: public
+  name: a
+  descriptor: I
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Synthetic
+    length: 00000000
+  end attributes[0]
+end fields[0]
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/015-field-attrib-Synthetic/info.txt b/dx/tests/015-field-attrib-Synthetic/info.txt
new file mode 100644
index 0000000..6037cfa
--- /dev/null
+++ b/dx/tests/015-field-attrib-Synthetic/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+field with a valid Synthetic attribute.
diff --git a/dx/tests/015-field-attrib-Synthetic/run b/dx/tests/015-field-attrib-Synthetic/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/015-field-attrib-Synthetic/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/015-field-attrib-Synthetic/small-class.txt b/dx/tests/015-field-attrib-Synthetic/small-class.txt
new file mode 100644
index 0000000..e5f429e
--- /dev/null
+++ b/dx/tests/015-field-attrib-Synthetic/small-class.txt
@@ -0,0 +1,38 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0008       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0009 "Synthetic"        # 0005: utf8["Synthetic"]
+01 0001 "a"                # 0006: utf8["a"]
+01 0001 "I"                # 0007: utf8["I"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+
+0001  # fields_count
+
+# fields[0]
+0001  # access_flags
+0006  # "a"
+0007  # "I"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000000  # length
+
+0000  # methods_count
+0000  # attributes_count
diff --git a/dx/tests/016-field-attrib-Deprecated/expected.txt b/dx/tests/016-field-attrib-Deprecated/expected.txt
new file mode 100644
index 0000000..1b5547f
--- /dev/null
+++ b/dx/tests/016-field-attrib-Deprecated/expected.txt
@@ -0,0 +1,36 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0008
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"Deprecated"}
+  0006: utf8{"a"}
+  0007: utf8{"I"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0001
+
+fields[0]:
+  access_flags: public
+  name: a
+  descriptor: I
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Deprecated
+    length: 00000000
+  end attributes[0]
+end fields[0]
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/016-field-attrib-Deprecated/info.txt b/dx/tests/016-field-attrib-Deprecated/info.txt
new file mode 100644
index 0000000..1185981
--- /dev/null
+++ b/dx/tests/016-field-attrib-Deprecated/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+field with a valid Deprecated attribute.
diff --git a/dx/tests/016-field-attrib-Deprecated/run b/dx/tests/016-field-attrib-Deprecated/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/016-field-attrib-Deprecated/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/016-field-attrib-Deprecated/small-class.txt b/dx/tests/016-field-attrib-Deprecated/small-class.txt
new file mode 100644
index 0000000..2448ce4
--- /dev/null
+++ b/dx/tests/016-field-attrib-Deprecated/small-class.txt
@@ -0,0 +1,38 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0008       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 000a "Deprecated"       # 0005: utf8["Deprecated"]
+01 0001 "a"                # 0006: utf8["a"]
+01 0001 "I"                # 0007: utf8["I"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+
+0001  # fields_count
+
+# fields[0]
+0001  # access_flags
+0006  # "a"
+0007  # "I"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000000  # length
+
+0000  # methods_count
+0000  # attributes_count
diff --git a/dx/tests/017-method-attrib-Code/expected.txt b/dx/tests/017-method-attrib-Code/expected.txt
new file mode 100644
index 0000000..c43730c
--- /dev/null
+++ b/dx/tests/017-method-attrib-Code/expected.txt
@@ -0,0 +1,42 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0008
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Code"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Code
+    length: 0000000d
+    max_stack: 0001
+    max_locals: 0001
+    code_length: 00000001
+    0000: return
+    exception_table_length: 0000
+    attributes_count: 0000
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/017-method-attrib-Code/info.txt b/dx/tests/017-method-attrib-Code/info.txt
new file mode 100644
index 0000000..a3ed24c
--- /dev/null
+++ b/dx/tests/017-method-attrib-Code/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a minimal but syntactically valid Code attribute.
diff --git a/dx/tests/017-method-attrib-Code/run b/dx/tests/017-method-attrib-Code/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/017-method-attrib-Code/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/017-method-attrib-Code/small-class.txt b/dx/tests/017-method-attrib-Code/small-class.txt
new file mode 100644
index 0000000..699005b
--- /dev/null
+++ b/dx/tests/017-method-attrib-Code/small-class.txt
@@ -0,0 +1,43 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0008       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 0004 "Code"             # 0007: utf8["Code"]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0001  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+0000000d  # length
+0001      # max_stack
+0001      # max_locals
+00000001  # code_length
+b1        # 0000: return
+0000      # exception_table_length
+0000      # attributes_count
+
+0000  # attributes_count
diff --git a/dx/tests/018-method-attrib-Exceptions/expected.txt b/dx/tests/018-method-attrib-Exceptions/expected.txt
new file mode 100644
index 0000000..15f923f
--- /dev/null
+++ b/dx/tests/018-method-attrib-Exceptions/expected.txt
@@ -0,0 +1,40 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 000a
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Exceptions"}
+  0008: utf8{"java/lang/Error"}
+  0009: type{java.lang.Error}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public|abstract
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Exceptions
+    length: 00000004
+    number_of_exceptions: 0001
+      type{java.lang.Error}
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/018-method-attrib-Exceptions/info.txt b/dx/tests/018-method-attrib-Exceptions/info.txt
new file mode 100644
index 0000000..4a3738d
--- /dev/null
+++ b/dx/tests/018-method-attrib-Exceptions/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a syntactically valid Exceptions attribute.
diff --git a/dx/tests/018-method-attrib-Exceptions/run b/dx/tests/018-method-attrib-Exceptions/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/018-method-attrib-Exceptions/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/018-method-attrib-Exceptions/small-class.txt b/dx/tests/018-method-attrib-Exceptions/small-class.txt
new file mode 100644
index 0000000..5d05b43
--- /dev/null
+++ b/dx/tests/018-method-attrib-Exceptions/small-class.txt
@@ -0,0 +1,41 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+000a       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 000a "Exceptions"       # 0007: utf8["Exceptions"]
+01 000f "java/lang/Error"  # 0008: utf8["java/lang/Error"]
+07 0008                    # 0009: class[java/lang/Error]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0401  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+00000004  # length
+0001      # number_of_exceptions
+0009      # class[java/lang/Error]
+
+0000  # attributes_count
diff --git a/dx/tests/019-method-attrib-Synthetic/expected.txt b/dx/tests/019-method-attrib-Synthetic/expected.txt
new file mode 100644
index 0000000..5d1d9cb
--- /dev/null
+++ b/dx/tests/019-method-attrib-Synthetic/expected.txt
@@ -0,0 +1,36 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0008
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Synthetic"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public|abstract
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Synthetic
+    length: 00000000
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/019-method-attrib-Synthetic/info.txt b/dx/tests/019-method-attrib-Synthetic/info.txt
new file mode 100644
index 0000000..eddf4fb
--- /dev/null
+++ b/dx/tests/019-method-attrib-Synthetic/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a syntactically valid Synthetic attribute.
diff --git a/dx/tests/019-method-attrib-Synthetic/run b/dx/tests/019-method-attrib-Synthetic/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/019-method-attrib-Synthetic/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/019-method-attrib-Synthetic/small-class.txt b/dx/tests/019-method-attrib-Synthetic/small-class.txt
new file mode 100644
index 0000000..458dae8
--- /dev/null
+++ b/dx/tests/019-method-attrib-Synthetic/small-class.txt
@@ -0,0 +1,37 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0008       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 0009 "Synthetic"        # 0007: utf8["Synthetic"]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0401  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+00000000  # length
+
+0000  # attributes_count
diff --git a/dx/tests/020-method-attrib-Deprecated/expected.txt b/dx/tests/020-method-attrib-Deprecated/expected.txt
new file mode 100644
index 0000000..8da8aa8
--- /dev/null
+++ b/dx/tests/020-method-attrib-Deprecated/expected.txt
@@ -0,0 +1,36 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0008
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Deprecated"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public|abstract
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Deprecated
+    length: 00000000
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/020-method-attrib-Deprecated/info.txt b/dx/tests/020-method-attrib-Deprecated/info.txt
new file mode 100644
index 0000000..b7c6266
--- /dev/null
+++ b/dx/tests/020-method-attrib-Deprecated/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a syntactically valid Deprecated attribute.
diff --git a/dx/tests/020-method-attrib-Deprecated/run b/dx/tests/020-method-attrib-Deprecated/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/020-method-attrib-Deprecated/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/020-method-attrib-Deprecated/small-class.txt b/dx/tests/020-method-attrib-Deprecated/small-class.txt
new file mode 100644
index 0000000..f906733
--- /dev/null
+++ b/dx/tests/020-method-attrib-Deprecated/small-class.txt
@@ -0,0 +1,37 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0008       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 000a "Deprecated"       # 0007: utf8["Deprecated"]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0401  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+00000000  # length
+
+0000  # attributes_count
diff --git a/dx/tests/021-code-attrib-LineNumberTable/expected.txt b/dx/tests/021-code-attrib-LineNumberTable/expected.txt
new file mode 100644
index 0000000..3f29310
--- /dev/null
+++ b/dx/tests/021-code-attrib-LineNumberTable/expected.txt
@@ -0,0 +1,52 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0009
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Code"}
+  0008: utf8{"LineNumberTable"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Code
+    length: 0000001e
+    max_stack: 0001
+    max_locals: 0001
+    code_length: 00000002
+    0000: return
+    0001: return
+    exception_table_length: 0000
+    attributes_count: 0001
+    
+    attributes[0]:
+      name: LineNumberTable
+      length: 0000000a
+      line_number_table_length: 0002
+      0000 17
+      0001 34
+    end attributes[0]
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/021-code-attrib-LineNumberTable/info.txt b/dx/tests/021-code-attrib-LineNumberTable/info.txt
new file mode 100644
index 0000000..2ffc798
--- /dev/null
+++ b/dx/tests/021-code-attrib-LineNumberTable/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a simple Code attribute, which itself has a syntactically
+valid LineNumberTable attribute.
diff --git a/dx/tests/021-code-attrib-LineNumberTable/run b/dx/tests/021-code-attrib-LineNumberTable/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/021-code-attrib-LineNumberTable/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/021-code-attrib-LineNumberTable/small-class.txt b/dx/tests/021-code-attrib-LineNumberTable/small-class.txt
new file mode 100644
index 0000000..c28c39a
--- /dev/null
+++ b/dx/tests/021-code-attrib-LineNumberTable/small-class.txt
@@ -0,0 +1,51 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0009       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 0004 "Code"             # 0007: utf8["Code"]
+01 000f "LineNumberTable"  # 0008: utf8["LineNumberTable"]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0001  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+0000001e  # length
+0001      # max_stack
+0001      # max_locals
+00000002  # code_length
+b1        # 0000: return
+b1        # 0001: return
+0000      # exception_table_length
+0001      # attributes_count
+# attributes[0]
+0008      # name
+0000000a  # length
+0002      # line_number_table_length
+0000 0011 # offset 0000, line #17
+0001 0022 # offset 0001, line #34
+
+0000  # attributes_count
diff --git a/dx/tests/022-code-attrib-LocalVariableTable/expected.txt b/dx/tests/022-code-attrib-LocalVariableTable/expected.txt
new file mode 100644
index 0000000..80091ed
--- /dev/null
+++ b/dx/tests/022-code-attrib-LocalVariableTable/expected.txt
@@ -0,0 +1,57 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 000d
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Code"}
+  0008: utf8{"LocalVariableTable"}
+  0009: utf8{"foo"}
+  000a: utf8{"bar"}
+  000b: utf8{"baz"}
+  000c: utf8{"[I"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Code
+    length: 00000034
+    max_stack: 0001
+    max_locals: 0002
+    code_length: 00000002
+    0000: return
+    0001: return
+    exception_table_length: 0000
+    attributes_count: 0001
+    
+    attributes[0]:
+      name: LocalVariableTable
+      length: 00000020
+      local_variable_table_length: 0003
+      0000..0002 0000 foo [I
+      0000..0001 0001 bar [I
+      0001..0002 0001 baz [I
+    end attributes[0]
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/022-code-attrib-LocalVariableTable/info.txt b/dx/tests/022-code-attrib-LocalVariableTable/info.txt
new file mode 100644
index 0000000..5b44286
--- /dev/null
+++ b/dx/tests/022-code-attrib-LocalVariableTable/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a simple Code attribute, which itself has a syntactically
+valid LocalVariableTable attribute.
diff --git a/dx/tests/022-code-attrib-LocalVariableTable/run b/dx/tests/022-code-attrib-LocalVariableTable/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/022-code-attrib-LocalVariableTable/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/022-code-attrib-LocalVariableTable/small-class.txt b/dx/tests/022-code-attrib-LocalVariableTable/small-class.txt
new file mode 100644
index 0000000..abbf8ea
--- /dev/null
+++ b/dx/tests/022-code-attrib-LocalVariableTable/small-class.txt
@@ -0,0 +1,56 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+000d       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                      # 0001: class[Small]
+07 0004                      # 0002: class[java/lang/Object]
+01 0005 "Small"              # 0003: utf8["Small"]
+01 0010 "java/lang/Object"   # 0004: utf8["java/lang/Object"]
+01 0005 "blort"              # 0005: utf8["blort"]
+01 0003 "()V"                # 0006: utf8["()V"]
+01 0004 "Code"               # 0007: utf8["Code"]
+01 0012 "LocalVariableTable" # 0008: utf8["LocalVariableTable"]
+01 0003 "foo"                # 0009: utf8["foo"]
+01 0003 "bar"                # 000a: utf8["bar"]
+01 0003 "baz"                # 000b: utf8["baz"]
+01 0002 "[I"                 # 000c: utf8["[I"]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0001  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+00000034  # length
+0001      # max_stack
+0002      # max_locals
+00000002  # code_length
+b1        # 0000: return
+b1        # 0001: return
+0000      # exception_table_length
+0001      # attributes_count
+# attributes[0]
+0008      # name
+00000020  # length
+0003      # local_variable_table_length
+0000 0002 0009 000c 0000  # 0000..0002 foo:[I #0000
+0000 0001 000a 000c 0001  # 0000..0001 bar:[I #0001
+0001 0001 000b 000c 0001  # 0001..0002 baz:[I #0001
+
+0000  # attributes_count
diff --git a/dx/tests/023-code-exception-table/expected.txt b/dx/tests/023-code-exception-table/expected.txt
new file mode 100644
index 0000000..552e5d3
--- /dev/null
+++ b/dx/tests/023-code-exception-table/expected.txt
@@ -0,0 +1,51 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 000c
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Code"}
+  0008: utf8{"java/lang/Error"}
+  0009: utf8{"java/lang/Exception"}
+  000a: type{java.lang.Error}
+  000b: type{java.lang.Exception}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Code
+    length: 00000027
+    max_stack: 0001
+    max_locals: 0001
+    code_length: 00000003
+    0000: return
+    0001: return
+    0002: return
+    exception_table_length: 0003
+      0000..0002 -> 0002 java.lang.Error
+      0000..0001 -> 0001 java.lang.Exception
+      0001..0002 -> 0002 <any>
+    attributes_count: 0000
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/023-code-exception-table/info.txt b/dx/tests/023-code-exception-table/info.txt
new file mode 100644
index 0000000..2dbb5da
--- /dev/null
+++ b/dx/tests/023-code-exception-table/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a minimal but syntactically valid Code attribute, which
+sports a non-empty syntactically valid exception table.
diff --git a/dx/tests/023-code-exception-table/run b/dx/tests/023-code-exception-table/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/023-code-exception-table/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/023-code-exception-table/small-class.txt b/dx/tests/023-code-exception-table/small-class.txt
new file mode 100644
index 0000000..f8ff1f3
--- /dev/null
+++ b/dx/tests/023-code-exception-table/small-class.txt
@@ -0,0 +1,52 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+000c       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                       # 0001: class[Small]
+07 0004                       # 0002: class[java/lang/Object]
+01 0005 "Small"               # 0003: utf8["Small"]
+01 0010 "java/lang/Object"    # 0004: utf8["java/lang/Object"]
+01 0005 "blort"               # 0005: utf8["blort"]
+01 0003 "()V"                 # 0006: utf8["()V"]
+01 0004 "Code"                # 0007: utf8["Code"]
+01 000f "java/lang/Error"     # 0008: utf8["java/lang/Error"]
+01 0013 "java/lang/Exception" # 0009: utf8["java/lang/Exception"]
+07 0008                       # 000a: class[java/lang/Error]
+07 0009                       # 000b: class[java/lang/Exception]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0001  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+00000027  # length
+0001      # max_stack
+0001      # max_locals
+00000003  # code_length
+b1        # 0000: return
+b1        # 0001: return
+b1        # 0002: return
+0003      # exception_table_length
+0000 0002 0002 000a  # 0000..0002 -> 0002 java/lang/Error
+0000 0001 0001 000b  # 0000..0001 -> 0001 java/lang/Exception
+0001 0002 0002 0000  # 0001..0002 -> 0002 <any>
+0000      # attributes_count
+
+0000  # attributes_count
diff --git a/dx/tests/024-code-bytecode/expected.txt b/dx/tests/024-code-bytecode/expected.txt
new file mode 100644
index 0000000..4637474
--- /dev/null
+++ b/dx/tests/024-code-bytecode/expected.txt
@@ -0,0 +1,294 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0017
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Code"}
+  0008: string{"Small"}
+  0009: int{0x12345678 / 305419896}
+  000a: float{0x42f6e666 / 123.45}
+  000b: long{0x123456789abcdef0 / 1311768467463790320}
+  000d: double{0x411958955f8a0903 / 415269.3433}
+  000f: utf8{"blort"}
+  0010: utf8{"x/y/Zzz"}
+  0011: utf8{"()V"}
+  0012: nat{blort:x/y/Zzz}
+  0013: nat{blort:()V}
+  0014: field{Small.blort:x/y/Zzz}
+  0015: method{Small.blort:()V}
+  0016: ifaceMethod{Small.blort:()V}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Code
+    length: 000001dc
+    max_stack: 0001
+    max_locals: 0001
+    code_length: 000001d0
+    0000: nop
+    0001: aconst_null
+    0002: iconst_m1 // #-01
+    0003: iconst_0 // #+00
+    0004: iconst_1 // #+01
+    0005: iconst_2 // #+02
+    0006: iconst_3 // #+03
+    0007: iconst_4 // #+04
+    0008: iconst_5 // #+05
+    0009: lconst_0 // +00
+    000a: lconst_1 // +01
+    000b: fconst_0 // 0.0
+    000c: fconst_1 // 1.0
+    000d: fconst_2 // 2.0
+    000e: dconst_0 // 0.0
+    000f: dconst_1 // 1.0
+    0010: bipush #+45
+    0012: sipush #+5432
+    0015: ldc string{"Small"}
+    0017: ldc #+12345678
+    0019: ldc #42f6e666 // 123.45
+    001b: ldc_w string{"Small"}
+    001e: ldc_w #+12345678
+    0021: ldc_w #42f6e666 // 123.45
+    0024: ldc2_w #+123456789abcdef0
+    0027: ldc2_w #411958955f8a0903 // 415269.3433
+    002a: iload 01
+    002c: lload 02 // category-2
+    002e: fload 03
+    0030: dload 04 // category-2
+    0032: aload 05
+    0034: iload_0 // 00
+    0035: iload_1 // 01
+    0036: iload_2 // 02
+    0037: iload_3 // 03
+    0038: lload_0 // 00, category-2
+    0039: lload_1 // 01, category-2
+    003a: lload_2 // 02, category-2
+    003b: lload_3 // 03, category-2
+    003c: fload_0 // 00
+    003d: fload_1 // 01
+    003e: fload_2 // 02
+    003f: fload_3 // 03
+    0040: dload_0 // 00, category-2
+    0041: dload_1 // 01, category-2
+    0042: dload_2 // 02, category-2
+    0043: dload_3 // 03, category-2
+    0044: aload_0 // 00
+    0045: aload_1 // 01
+    0046: aload_2 // 02
+    0047: aload_3 // 03
+    0048: iaload
+    0049: laload
+    004a: faload
+    004b: daload
+    004c: aaload
+    004d: baload
+    004e: caload
+    004f: saload
+    0050: istore 41
+    0052: lstore 42 // category-2
+    0054: fstore 43
+    0056: dstore 44 // category-2
+    0058: astore 45
+    005a: istore_0 // 00
+    005b: istore_1 // 01
+    005c: istore_2 // 02
+    005d: istore_3 // 03
+    005e: lstore_0 // 00, category-2
+    005f: lstore_1 // 01, category-2
+    0060: lstore_2 // 02, category-2
+    0061: lstore_3 // 03, category-2
+    0062: fstore_0 // 00
+    0063: fstore_1 // 01
+    0064: fstore_2 // 02
+    0065: fstore_3 // 03
+    0066: dstore_0 // 00, category-2
+    0067: dstore_1 // 01, category-2
+    0068: dstore_2 // 02, category-2
+    0069: dstore_3 // 03, category-2
+    006a: astore_0 // 00
+    006b: astore_1 // 01
+    006c: astore_2 // 02
+    006d: astore_3 // 03
+    006e: iastore
+    006f: lastore
+    0070: fastore
+    0071: dastore
+    0072: aastore
+    0073: bastore
+    0074: castore
+    0075: sastore
+    0076: pop
+    0077: pop2
+    0078: dup
+    0079: dup_x1
+    007a: dup_x2
+    007b: dup2
+    007c: dup2_x1
+    007d: dup2_x2
+    007e: swap
+    007f: iadd
+    0080: ladd
+    0081: fadd
+    0082: dadd
+    0083: isub
+    0084: lsub
+    0085: fsub
+    0086: dsub
+    0087: imul
+    0088: lmul
+    0089: fmul
+    008a: dmul
+    008b: idiv
+    008c: ldiv
+    008d: fdiv
+    008e: ddiv
+    008f: irem
+    0090: lrem
+    0091: frem
+    0092: drem
+    0093: ineg
+    0094: lneg
+    0095: fneg
+    0096: dneg
+    0097: ishl
+    0098: lshl
+    0099: ishr
+    009a: lshr
+    009b: iushr
+    009c: lushr
+    009d: iand
+    009e: land
+    009f: ior
+    00a0: lor
+    00a1: ixor
+    00a2: lxor
+    00a3: iinc 05, #-01
+    00a6: i2l
+    00a7: i2f
+    00a8: i2d
+    00a9: l2i
+    00aa: l2f
+    00ab: l2d
+    00ac: f2i
+    00ad: f2l
+    00ae: f2d
+    00af: d2i
+    00b0: d2l
+    00b1: d2f
+    00b2: i2b
+    00b3: i2c
+    00b4: i2s
+    00b5: lcmp
+    00b6: fcmpl
+    00b7: fcmpg
+    00b8: dcmpl
+    00b9: dcmpg
+    00ba: ifeq 00ba
+    00bd: ifne 00ba
+    00c0: iflt 00ba
+    00c3: ifge 00ba
+    00c6: ifgt 00ba
+    00c9: ifle 00ba
+    00cc: if_icmpeq 00db
+    00cf: if_icmpne 00db
+    00d2: if_icmplt 00db
+    00d5: if_icmpge 00db
+    00d8: if_icmpgt 00db
+    00db: if_icmple 00db
+    00de: if_acmpeq 00de
+    00e1: if_acmpne 00e1
+    00e4: goto 0000
+    00e7: jsr 00e7
+    00ea: ret 2f
+    00ec: tableswitch
+      +12340000: 0000
+      +12340001: 0001
+      +12340002: 0002
+      +12340003: 0003
+      +12340004: 0004
+      +12340005: 0005
+      +12340006: 0007
+      +12340007: 0009
+      default: 00ea
+    011c: lookupswitch
+      -7689edcc: 0148
+      +00001000: 0149
+      +03333333: 0149
+      +79787776: 014b
+      default: 00ec
+    0148: ireturn
+    0149: lreturn
+    014a: freturn
+    014b: dreturn
+    014c: areturn
+    014d: return
+    014e: getstatic field{Small.blort:x/y/Zzz}
+    0151: putstatic field{Small.blort:x/y/Zzz}
+    0154: getfield field{Small.blort:x/y/Zzz}
+    0157: putfield field{Small.blort:x/y/Zzz}
+    015a: invokevirtual method{Small.blort:()V}
+    015d: invokespecial method{Small.blort:()V}
+    0160: invokestatic method{Small.blort:()V}
+    0163: invokeinterface ifaceMethod{Small.blort:()V}, 0001
+    0168: unused_ba
+    0169: new type{Small}
+    016c: newarray boolean
+    016e: newarray char
+    0170: newarray float
+    0172: newarray double
+    0174: newarray byte
+    0176: newarray short
+    0178: newarray int
+    017a: newarray long
+    017c: anewarray type{Small}
+    017f: arraylength
+    0180: athrow
+    0181: checkcast type{java.lang.Object}
+    0184: instanceof type{java.lang.Object}
+    0187: monitorenter
+    0188: monitorexit
+    0189: wide iload 0123
+    018d: wide lload 0124 // category-2
+    0191: wide fload 0125
+    0195: wide dload 0126 // category-2
+    0199: wide aload 0127
+    019d: wide istore 20f0
+    01a1: wide lstore 20f1 // category-2
+    01a5: wide fstore 20f2
+    01a9: wide dstore 20f3 // category-2
+    01ad: wide astore 20f4
+    01b1: wide ret ffff
+    01b5: wide iinc 0002, #+1000
+    01bb: multianewarray type{java.lang.Object}, 04
+    01bf: ifnull 0000
+    01c2: ifnonnull 01c2
+    01c5: goto_w 700001c5
+    01ca: jsr_w 000001c5
+    01cf: unused_ca
+    exception_table_length: 0000
+    attributes_count: 0000
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/024-code-bytecode/info.txt b/dx/tests/024-code-bytecode/info.txt
new file mode 100644
index 0000000..d1264a8
--- /dev/null
+++ b/dx/tests/024-code-bytecode/info.txt
@@ -0,0 +1,7 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a Code attribute, and the code[] array of the attribute has
+one instance of each interesting variant of each possible bytecode.
diff --git a/dx/tests/024-code-bytecode/run b/dx/tests/024-code-bytecode/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/024-code-bytecode/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/024-code-bytecode/small-class.txt b/dx/tests/024-code-bytecode/small-class.txt
new file mode 100644
index 0000000..2526cf2
--- /dev/null
+++ b/dx/tests/024-code-bytecode/small-class.txt
@@ -0,0 +1,304 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0017       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 0004 "Code"             # 0007: utf8["Code"]
+08 0003                    # 0008: string["Small"]
+03 12345678                # 0009: integer[0x12345678]
+04 42f6e666                # 000a: float[123.45]
+05 12345678 9abcdef0       # 000b: long[0x1234567890abcdef0]
+06 41195895 5f8a0903       # 000d: double[415269.3433]
+01 0005 "blort"            # 000f: utf8["blort"]
+01 0007 "x/y/Zzz"          # 0010: utf8["x/y/Zzz"]
+01 0003 "()V"              # 0011: utf8["()V"]
+0c 000f 0010               # 0012: nat[blort:x/y/Zzz]
+0c 000f 0011               # 0013: nat[blort:()V]
+09 0001 0012               # 0014: field[Small.blort:x/y/Zzz]
+0a 0001 0013               # 0015: method[Small.blort:()V]
+0b 0001 0013               # 0016: ifaceMethod[Small.blort:()V]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0001  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+000001dc  # length (note: == code_length + 0x0c)
+0001      # max_stack
+0001      # max_locals
+000001d0  # code_length
+
+00        # 0000: nop
+01        # 0001: aconst_null
+02        # 0002: aconst_m1
+03        # 0003: iconst_0
+04        # 0004: iconst_1
+05        # 0005: iconst_2
+06        # 0006: iconst_3
+07        # 0007: iconst_4
+08        # 0008: iconst_5
+09        # 0009: lconst_0
+0a        # 000a: lconst_1
+0b        # 000b: fconst_0
+0c        # 000c: fconst_1
+0d        # 000d: fconst_2
+0e        # 000e: dconst_0
+0f        # 000f: dconst_1
+10 45     # 0010: bipush #+45
+11 5432   # 0012: sipush #+5432
+12 08     # 0015: ldc <string>
+12 09     # 0017: ldc <integer>
+12 0a     # 0019: ldc <float>
+13 0008   # 001b: ldc_w <string>
+13 0009   # 001e: ldc_w <integer>
+13 000a   # 0021: ldc_w <float>
+14 000b   # 0024: ldc2_w <long>
+14 000d   # 0027: ldc2_w <double>
+15 01     # 002a: iload 01
+16 02     # 002c: lload 02
+17 03     # 002e: fload 03
+18 04     # 0030: dload 04
+19 05     # 0032: aload 05
+1a        # 0034: iload_0
+1b        # 0035: iload_1
+1c        # 0036: iload_2
+1d        # 0037: iload_3
+1e        # 0038: lload_0
+1f        # 0039: lload_1
+20        # 003a: lload_2
+21        # 003b: lload_3
+22        # 003c: fload_0
+23        # 003d: fload_1
+24        # 003e: fload_2
+25        # 003f: fload_3
+26        # 0040: dload_0
+27        # 0041: dload_1
+28        # 0042: dload_2
+29        # 0043: dload_3
+2a        # 0044: aload_0
+2b        # 0045: aload_1
+2c        # 0046: aload_2
+2d        # 0047: aload_3
+2e        # 0048: iaload
+2f        # 0049: laload
+30        # 004a: faload
+31        # 004b: daload
+32        # 004c: aaload
+33        # 004d: baload
+34        # 004e: caload
+35        # 004f: saload
+36 41     # 0050: istore 41
+37 42     # 0052: lstore 42
+38 43     # 0054: fstore 43
+39 44     # 0056: dstore 44
+3a 45     # 0058: astore 45
+3b        # 005a: istore_0
+3c        # 005b: istore_1
+3d        # 005c: istore_2
+3e        # 005d: istore_3
+3f        # 005e: lstore_0
+40        # 005f: lstore_1
+41        # 0060: lstore_2
+42        # 0061: lstore_3
+43        # 0062: fstore_0
+44        # 0063: fstore_1
+45        # 0064: fstore_2
+46        # 0065: fstore_3
+47        # 0066: dstore_0
+48        # 0067: dstore_1
+49        # 0068: dstore_2
+4a        # 0069: dstore_3
+4b        # 006a: astore_0
+4c        # 006b: astore_1
+4d        # 006c: astore_2
+4e        # 006d: astore_3
+4f        # 006e: iastore
+50        # 006f: lastore
+51        # 0070: fastore
+52        # 0071: dastore
+53        # 0072: aastore
+54        # 0073: bastore
+55        # 0074: castore
+56        # 0075: sastore
+57        # 0076: pop
+58        # 0077: pop2
+59        # 0078: dup
+5a        # 0079: dup_x1
+5b        # 007a: dup_x2
+5c        # 007b: dup2
+5d        # 007c: dup2_x1
+5e        # 007d: dup2_x2
+5f        # 007e: swap
+60        # 007f: iadd
+61        # 0080: ladd
+62        # 0081: fadd
+63        # 0082: dadd
+64        # 0083: isub
+65        # 0084: lsub
+66        # 0085: fsub
+67        # 0086: dsub
+68        # 0087: imul
+69        # 0088: lmul
+6a        # 0089: fmul
+6b        # 008a: dmul
+6c        # 008b: idiv
+6d        # 008c: ldiv
+6e        # 008d: fdiv
+6f        # 008e: ddiv
+70        # 008f: irem
+71        # 0090: lrem
+72        # 0091: frem
+73        # 0092: drem
+74        # 0093: ineg
+75        # 0094: lneg
+76        # 0095: fneg
+77        # 0096: dneg
+78        # 0097: ishl
+79        # 0098: lshl
+7a        # 0099: ishr
+7b        # 009a: lshr
+7c        # 009b: iushr
+7d        # 009c: lushr
+7e        # 009d: iand
+7f        # 009e: land
+80        # 009f: ior
+81        # 00a0: lor
+82        # 00a1: ixor
+83        # 00a2: lxor
+84 05 ff  # 00a3: iinc 05, #-1
+85        # 00a6: i2l
+86        # 00a7: i2f
+87        # 00a8: i2d
+88        # 00a9: l2i
+89        # 00aa: l2f
+8a        # 00ab: l2d
+8b        # 00ac: f2i
+8c        # 00ad: f2l
+8d        # 00ae: f2d
+8e        # 00af: d2i
+8f        # 00b0: d2l
+90        # 00b1: d2f
+91        # 00b2: i2b
+92        # 00b3: i2c
+93        # 00b4: i2s
+94        # 00b5: lcmp
+95        # 00b6: fcmpl
+96        # 00b7: fcmpg
+97        # 00b8: dcmpl
+98        # 00b9: dcmpg
+99 0000   # 00ba: ifeq 00ba
+9a fffd   # 00bd: ifne 00ba
+9b fffa   # 00c0: iflt 00ba
+9c fff7   # 00c3: ifge 00ba
+9d fff4   # 00c6: ifgt 00ba
+9e fff1   # 00c9: ifle 00ba
+9f 000f   # 00cc: if_icmpeq 00db
+a0 000c   # 00cf: if_icmpne 00db
+a1 0009   # 00d2: if_icmplt 00db
+a2 0006   # 00d5: if_icmpge 00db
+a3 0003   # 00d8: if_icmpgt 00db
+a4 0000   # 00db: if_icmple 00db
+a5 0000   # 00de: if_acmpeq 00de
+a6 0000   # 00e1: if_acmpne 00e1
+a7 ff1c   # 00e4: goto 0000
+a8 0000   # 00e7: jsr 00e7
+a9 2f     # 00ea: ret 2f
+aa 000000 # 00ec: tableswitch + padding
+ fffffffe #   default: 000000ea
+ 12340000 #   low: 12340000
+ 12340007 #   high: 12340007
+ ffffff14 #   [0]: 00000000
+ ffffff15 #   [1]: 00000001
+ ffffff16 #   [2]: 00000002
+ ffffff17 #   [3]: 00000003
+ ffffff18 #   [4]: 00000004
+ ffffff19 #   [5]: 00000005
+ ffffff1b #   [6]: 00000007
+ ffffff1d #   [7]: 00000009
+ab 000000 # 011c: lookupswitch + padding
+ ffffffd0 #   default: 000000ec
+ 00000004 #   npairs: 4
+ 89761234 #   match[0]: 89761234
+ 0000002c #   offset[0]: 0148
+ 00001000 #   match[1]: 00001000
+ 0000002d #   offset[1]: 0149
+ 03333333 #   match[2]: 03333333
+ 0000002d #   offset[2]: 0149
+ 79787776 #   match[3]: 79787776
+ 0000002f #   offset[3]: 014b
+ac        # 0148: ireturn
+ad        # 0149: lreturn
+ae        # 014a: freturn
+af        # 014b: dreturn
+b0        # 014c: areturn
+b1        # 014d: return
+b2 0014   # 014e: getstatic 0014
+b3 0014   # 0151: putstatic 0014
+b4 0014   # 0154: getfield 0014
+b5 0014   # 0157: putfield 0014
+b6 0015   # 015a: invokevirtual 0015
+b7 0015   # 015d: invokespecial 0015
+b8 0015   # 0160: invokestatic 0015
+b9 0016 01 00  # 0163: invokeinterface 0016
+ba        # 0168: <unused>
+bb 0001   # 0169: new 0001
+bc 04     # 016c: newarray boolean
+bc 05     # 016e: newarray char
+bc 06     # 0170: newarray float
+bc 07     # 0172: newarray double
+bc 08     # 0174: newarray byte
+bc 09     # 0176: newarray short
+bc 0a     # 0178: newarray int
+bc 0b     # 017a: newarray long
+bd 0001   # 017c: anewarray 0001
+be        # 017f: arraylength
+bf        # 0180: athrow
+c0 0002   # 0181: checkcast 0002
+c1 0002   # 0184: instanceof 0002
+c2        # 0187: monitorenter
+c3        # 0188: monitorexit
+c415 0123 # 0189: wide iload 0123
+c416 0124 # 018d: wide lload 0124
+c417 0125 # 0191: wide fload 0125
+c418 0126 # 0195: wide dload 0126
+c419 0127 # 0199: wide aload 0127
+c436 20f0 # 019d: wide istore 20f0
+c437 20f1 # 01a1: wide lstore 20f1
+c438 20f2 # 01a5: wide fstore 20f2
+c439 20f3 # 01a9: wide dstore 20f3
+c43a 20f4 # 01ad: wide astore 20f4
+c4a9 ffff # 01b1: wide ret ffff
+c484 0002 1000 # 01b5: wide iinc 0002, 1000
+c5 0002 04 # 01bb: multianewarray 0002, #04
+c6 fe41   # 01bf: ifnull 0000
+c7 0000   # 01c2: ifnonnull 01c2
+c8 70000000 # 01c5: goto_w 700001c5
+c9 fffffffb # 01ca: jsr_w 000001c5
+ca        # 01cf: <unused>
+
+0000      # exception_table_length
+0000      # attributes_count
+
+0000  # attributes_count
diff --git a/dx/tests/025-class-attrib-Signature/expected.txt b/dx/tests/025-class-attrib-Signature/expected.txt
new file mode 100644
index 0000000..e3f7233
--- /dev/null
+++ b/dx/tests/025-class-attrib-Signature/expected.txt
@@ -0,0 +1,29 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0007
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"Signature"}
+  0006: utf8{"LYo;"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: Signature
+  length: 00000002
+  signature: string{"LYo;"}
+end attributes[0]
+end classfile
diff --git a/dx/tests/025-class-attrib-Signature/info.txt b/dx/tests/025-class-attrib-Signature/info.txt
new file mode 100644
index 0000000..3d0ce51
--- /dev/null
+++ b/dx/tests/025-class-attrib-Signature/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+class-level Signature attribute, which is syntactically valid.
diff --git a/dx/tests/025-class-attrib-Signature/run b/dx/tests/025-class-attrib-Signature/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/025-class-attrib-Signature/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/025-class-attrib-Signature/small-class.txt b/dx/tests/025-class-attrib-Signature/small-class.txt
new file mode 100644
index 0000000..d332e3a
--- /dev/null
+++ b/dx/tests/025-class-attrib-Signature/small-class.txt
@@ -0,0 +1,32 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0007       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0009 "Signature"        # 0005: utf8["Signature"]
+01 0004 "LYo;"             # 0006: utf8["Yo"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000002  # length
+0006      # signature
\ No newline at end of file
diff --git a/dx/tests/026-field-attrib-Signature/expected.txt b/dx/tests/026-field-attrib-Signature/expected.txt
new file mode 100644
index 0000000..228989a
--- /dev/null
+++ b/dx/tests/026-field-attrib-Signature/expected.txt
@@ -0,0 +1,38 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0009
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"Signature"}
+  0006: utf8{"a"}
+  0007: utf8{"I"}
+  0008: utf8{"LYo;"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0001
+
+fields[0]:
+  access_flags: public
+  name: a
+  descriptor: I
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Signature
+    length: 00000002
+    signature: string{"LYo;"}
+  end attributes[0]
+end fields[0]
+methods_count: 0000
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/026-field-attrib-Signature/info.txt b/dx/tests/026-field-attrib-Signature/info.txt
new file mode 100644
index 0000000..5b21ccb
--- /dev/null
+++ b/dx/tests/026-field-attrib-Signature/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+field with a syntactically valid Signature attribute.
diff --git a/dx/tests/026-field-attrib-Signature/run b/dx/tests/026-field-attrib-Signature/run
new file mode 100644
index 0000000..1c759d6
--- /dev/null
+++ b/dx/tests/026-field-attrib-Signature/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class.txt
diff --git a/dx/tests/026-field-attrib-Signature/small-class.txt b/dx/tests/026-field-attrib-Signature/small-class.txt
new file mode 100644
index 0000000..07d56a0
--- /dev/null
+++ b/dx/tests/026-field-attrib-Signature/small-class.txt
@@ -0,0 +1,40 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0009       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 0009 "Signature"        # 0005: utf8["Signature"]
+01 0001 "a"                # 0006: utf8["a"]
+01 0001 "I"                # 0007: utf8["I"]
+01 0004 "LYo;"             # 0008: utf8["Yo"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+
+0001  # fields_count
+
+# fields[0]
+0001  # access_flags
+0006  # "a"
+0007  # "I"
+0001  # attributes_count
+# attributes[0]
+0005      # name
+00000002  # length
+0008      # signature
+
+0000  # methods_count
+0000  # attributes_count
diff --git a/dx/tests/027-method-attrib-Signature/expected.txt b/dx/tests/027-method-attrib-Signature/expected.txt
new file mode 100644
index 0000000..c3610e9
--- /dev/null
+++ b/dx/tests/027-method-attrib-Signature/expected.txt
@@ -0,0 +1,38 @@
+reading small-class.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0009
+
+constant_pool:
+  0001: type{Small}
+  0002: type{java.lang.Object}
+  0003: utf8{"Small"}
+  0004: utf8{"java/lang/Object"}
+  0005: utf8{"blort"}
+  0006: utf8{"()V"}
+  0007: utf8{"Signature"}
+  0008: utf8{"LYo;"}
+end constant_pool
+access_flags: public
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0001
+
+methods[0]:
+  access_flags: public|abstract
+  name: blort
+  descriptor: ()V
+  attributes_count: 0001
+  
+  attributes[0]:
+    name: Signature
+    length: 00000002
+    signature: string{"LYo;"}
+  end attributes[0]
+end methods[0]
+attributes_count: 0000
+end classfile
diff --git a/dx/tests/027-method-attrib-Signature/info.txt b/dx/tests/027-method-attrib-Signature/info.txt
new file mode 100644
index 0000000..ea18c03
--- /dev/null
+++ b/dx/tests/027-method-attrib-Signature/info.txt
@@ -0,0 +1,6 @@
+This is a dump of a simple class which is valid in structure but is overall
+invalid. That being said, the system should still have no trouble parsing and
+dumping it.
+
+The salient bit of parsing tested here is that the class has a single
+method with a syntactically valid Signature attribute.
diff --git a/dx/tests/027-method-attrib-Signature/run b/dx/tests/027-method-attrib-Signature/run
new file mode 100644
index 0000000..16b7755
--- /dev/null
+++ b/dx/tests/027-method-attrib-Signature/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump small-class.txt
diff --git a/dx/tests/027-method-attrib-Signature/small-class.txt b/dx/tests/027-method-attrib-Signature/small-class.txt
new file mode 100644
index 0000000..c1cd6e3
--- /dev/null
+++ b/dx/tests/027-method-attrib-Signature/small-class.txt
@@ -0,0 +1,39 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0009       # constant_pool_count
+
+#
+# constant_pool
+#
+07 0003                    # 0001: class[Small]
+07 0004                    # 0002: class[java/lang/Object]
+01 0005 "Small"            # 0003: utf8["Small"]
+01 0010 "java/lang/Object" # 0004: utf8["java/lang/Object"]
+01 0005 "blort"            # 0005: utf8["blort"]
+01 0003 "()V"              # 0006: utf8["()V"]
+01 0009 "Signature"        # 0007: utf8["Signature"]
+01 0004 "LYo;"             # 0008: utf8["Yo"]
+
+0001  # access_flags
+0001  # this_class
+0002  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0001  # methods_count
+
+# methods[0]
+0401  # access_flags
+0005  # name
+0006  # descriptor
+0001  # attributes_count
+# attributes[0]
+0007      # name
+00000002  # length
+0008      # signature
+
+0000  # attributes_count
diff --git a/dx/tests/028-class-attrib-EnclosingMethod/expected.txt b/dx/tests/028-class-attrib-EnclosingMethod/expected.txt
new file mode 100644
index 0000000..15e9524
--- /dev/null
+++ b/dx/tests/028-class-attrib-EnclosingMethod/expected.txt
@@ -0,0 +1,61 @@
+reading small-class-1.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0006
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"EnclosingMethod"}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: EnclosingMethod
+  length: 00000004
+  class: type{Small}
+  method: (none)
+end attributes[0]
+end classfile
+reading small-class-2.txt...
+begin classfile
+magic: cafebabe
+minor_version: 0000
+major_version: 002e
+constant_pool_count: 0009
+
+constant_pool:
+  0001: utf8{"Small"}
+  0002: utf8{"java/lang/Object"}
+  0003: type{Small}
+  0004: type{java.lang.Object}
+  0005: utf8{"EnclosingMethod"}
+  0006: utf8{"zorp"}
+  0007: utf8{"()V"}
+  0008: nat{zorp:()V}
+end constant_pool
+access_flags: public|super
+this_class: type{Small}
+super_class: type{java.lang.Object}
+interfaces_count: 0000
+fields_count: 0000
+methods_count: 0000
+attributes_count: 0001
+
+attributes[0]:
+  name: EnclosingMethod
+  length: 00000004
+  class: type{Small}
+  method: nat{zorp:()V}
+end attributes[0]
+end classfile
diff --git a/dx/tests/028-class-attrib-EnclosingMethod/info.txt b/dx/tests/028-class-attrib-EnclosingMethod/info.txt
new file mode 100644
index 0000000..9600803
--- /dev/null
+++ b/dx/tests/028-class-attrib-EnclosingMethod/info.txt
@@ -0,0 +1,8 @@
+This is a dump of two simple classes which are valid in structure but
+are overall invalid. That being said, the system should still have no
+trouble parsing and dumping them.
+
+The salient bit of parsing tested here is that each class has a single
+class-level EnclosingMethod attribute, which is syntactically valid. There
+are two possible variants (method may be null), and this test contains one
+of each.
diff --git a/dx/tests/028-class-attrib-EnclosingMethod/run b/dx/tests/028-class-attrib-EnclosingMethod/run
new file mode 100644
index 0000000..f33a338
--- /dev/null
+++ b/dx/tests/028-class-attrib-EnclosingMethod/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --width=200 small-class-1.txt small-class-2.txt
diff --git a/dx/tests/028-class-attrib-EnclosingMethod/small-class-1.txt b/dx/tests/028-class-attrib-EnclosingMethod/small-class-1.txt
new file mode 100644
index 0000000..aeaf2a3
--- /dev/null
+++ b/dx/tests/028-class-attrib-EnclosingMethod/small-class-1.txt
@@ -0,0 +1,32 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0006       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 000f "EnclosingMethod"  # 0005: utf8["EnclosingMethod"]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000004  # length
+0003      # class
+0000      # method
diff --git a/dx/tests/028-class-attrib-EnclosingMethod/small-class-2.txt b/dx/tests/028-class-attrib-EnclosingMethod/small-class-2.txt
new file mode 100644
index 0000000..8e6148e
--- /dev/null
+++ b/dx/tests/028-class-attrib-EnclosingMethod/small-class-2.txt
@@ -0,0 +1,35 @@
+#
+# sample small-but-valid classfile
+#
+
+cafe babe  # magic
+0000       # minor_version
+002e       # major_version
+0009       # constant_pool_count
+
+#
+# constant_pool
+#
+01 0005 "Small"            # 0001: utf8["Small"]
+01 0010 "java/lang/Object" # 0002: utf8["java/lang/Object"]
+07 0001                    # 0003: class[Small]
+07 0002                    # 0004: class[java/lang/Object]
+01 000f "EnclosingMethod"  # 0005: utf8["EnclosingMethod"]
+01 0004 "zorp"             # 0006: utf8["zorp"]
+01 0003 "()V"              # 0007: utf8["()V"]
+0c 0006 0007               # 0008: nat[zorp:()V]
+
+0021  # access_flags
+0003  # this_class
+0004  # super_class
+0000  # interfaces_count
+0000  # fields_count
+0000  # methods_count
+
+0001  # attributes_count
+
+# attribute[0]
+0005      # name
+00000004  # length
+0003      # class
+0008      # method
diff --git a/dx/tests/029-unit-Bits/expected.txt b/dx/tests/029-unit-Bits/expected.txt
new file mode 100644
index 0000000..5418338
--- /dev/null
+++ b/dx/tests/029-unit-Bits/expected.txt
@@ -0,0 +1 @@
+Yay!
diff --git a/dx/tests/029-unit-Bits/info.txt b/dx/tests/029-unit-Bits/info.txt
new file mode 100644
index 0000000..fa56715
--- /dev/null
+++ b/dx/tests/029-unit-Bits/info.txt
@@ -0,0 +1 @@
+Unit test for com.android.dx.util.Bits.
diff --git a/dx/tests/029-unit-Bits/run b/dx/tests/029-unit-Bits/run
new file mode 100644
index 0000000..9937ce5
--- /dev/null
+++ b/dx/tests/029-unit-Bits/run
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# 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.
+
+dx --junit com.android.dx.util._tests._Bits > unit-out.txt
+
+if [ "$?" = "0" ]; then
+    echo "Yay!"
+else
+    cat unit-out.txt
+fi
diff --git a/dx/tests/030-minimal-jasmin/blort.j b/dx/tests/030-minimal-jasmin/blort.j
new file mode 100644
index 0000000..45722bc
--- /dev/null
+++ b/dx/tests/030-minimal-jasmin/blort.j
@@ -0,0 +1,28 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public <init>()V
+    .limit locals 2
+    .limit stack 3
+
+    aload_0
+    dup
+    dup
+    astore_1
+    pop2
+    return
+.end method
diff --git a/dx/tests/030-minimal-jasmin/expected.txt b/dx/tests/030-minimal-jasmin/expected.txt
new file mode 100644
index 0000000..de52b4d
--- /dev/null
+++ b/dx/tests/030-minimal-jasmin/expected.txt
@@ -0,0 +1,7 @@
+Generated: ./blort.class
+    0000: aload_0 // 00
+    0001: dup
+    0002: dup
+    0003: astore_1 // 01
+    0004: pop2
+    0005: return
diff --git a/dx/tests/030-minimal-jasmin/info.txt b/dx/tests/030-minimal-jasmin/info.txt
new file mode 100644
index 0000000..816c244
--- /dev/null
+++ b/dx/tests/030-minimal-jasmin/info.txt
@@ -0,0 +1,2 @@
+This test is just a minimal test involving assembling a jasmin source
+file and then dumping it. It doesn't test any features in particular.
diff --git a/dx/tests/030-minimal-jasmin/run b/dx/tests/030-minimal-jasmin/run
new file mode 100644
index 0000000..6a50596
--- /dev/null
+++ b/dx/tests/030-minimal-jasmin/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j
+dx --debug --dump --width=200 blort.class | grep '    000.:'
diff --git a/dx/tests/031-bb-dead-code/blort.j b/dx/tests/031-bb-dead-code/blort.j
new file mode 100644
index 0000000..b6854f2
--- /dev/null
+++ b/dx/tests/031-bb-dead-code/blort.j
@@ -0,0 +1,182 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public <init>()V
+    .limit locals 1
+
+    aload_0
+    invokespecial java/lang/Object/<init>()V
+    return
+.end method
+
+; dead code after the last reachable instruction in a method
+.method public test_deadend1()V
+    return
+    aload_0
+.end method
+
+; dead code after the last reachable instruction in a method
+.method public test_deadend2()V
+    ireturn
+    aload_0
+    aload_0
+.end method
+
+; dead code after the last reachable instruction in a method
+.method public test_deadend3()V
+    aconst_null
+    athrow
+    sipush 0x1234
+.end method
+
+; make sure an exception handler for a dead range doesn't get enlivened
+.method public test_dead_exception_handler()V
+    return
+    nop
+blort:
+    nop
+    nop
+    return
+handler:
+    nop
+    return
+    .catch all from blort to handler using handler
+.end method
+
+; dead code after goto instruction
+.method public test_dead_goto()V
+    goto blort
+    nop
+blort:
+    return
+.end method
+
+; dead code after ret instruction
+.method public test_dead_ret()V
+    ifeq blort
+    ret 0
+    iconst_m1
+blort:
+    return
+.end method
+
+; dead code after tableswitch instruction
+.method public test_dead_tableswitch()V
+    tableswitch 0x10
+        blort
+        default: blort
+    nop
+    nop
+    nop
+    aload_0
+    aload_1
+    aload_2
+    aload_3
+blort:
+    return
+.end method
+
+; dead code after lookupswitch instruction
+.method public test_dead_lookupswitch()V
+    lookupswitch
+        0x10: blort
+        0x20: blort
+        default: blort
+    ldc "WHYA REYO UREA DING THIS ?"
+blort:
+    return
+.end method
+
+; dead code after ireturn instruction
+.method public test_dead_ireturn()V
+    ifeq blort
+    ireturn
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after lreturn instruction
+.method public test_dead_lreturn()V
+    ifeq blort
+    lreturn
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after freturn instruction
+.method public test_dead_freturn()V
+    ifeq blort
+    freturn
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after dreturn instruction
+.method public test_dead_dreturn()V
+    ifeq blort
+    dreturn
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after areturn instruction
+.method public test_dead_areturn()V
+    ifeq blort
+    areturn
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after return instruction
+.method public test_dead_return()V
+    ifeq blort
+    return
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after athrow instruction
+.method public test_dead_athrow()V
+    ifeq blort
+    athrow
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after wide ret instruction
+.method public test_dead_wideret()V
+    ifeq blort
+    ret 0x0100
+    iconst_1
+blort:
+    return
+.end method
+
+; dead code after goto_w instruction
+.method public test_dead_goto_w()V
+    goto_w blort
+    iconst_1
+blort:
+    return
+.end method
diff --git a/dx/tests/031-bb-dead-code/expected.txt b/dx/tests/031-bb-dead-code/expected.txt
new file mode 100644
index 0000000..1cd4959
--- /dev/null
+++ b/dx/tests/031-bb-dead-code/expected.txt
@@ -0,0 +1,190 @@
+Generated: ./blort.class
+reading blort.class...
+method <init> ()V
+block 0000: 0000..0004
+  0000: aload_0 // 00
+  0001: invokespecial method{java.lang.Object.<init>:()V}
+  next 0004
+block 0004: 0004..0005
+  0004: return
+  returns
+
+method test_deadend1 ()V
+block 0000: 0000..0001
+  0000: return
+  returns
+dead code 0001..0002
+
+method test_deadend2 ()V
+block 0000: 0000..0001
+  0000: ireturn
+  returns
+dead code 0001..0003
+
+method test_deadend3 ()V
+block 0000: 0000..0002
+  0000: aconst_null
+  0001: athrow
+  returns
+dead code 0002..0005
+
+method test_dead_exception_handler ()V
+block 0000: 0000..0001
+  0000: return
+  returns
+dead code 0001..0007
+
+method test_dead_goto ()V
+block 0000: 0000..0003
+  0000: goto 0004
+  next 0004
+dead code 0003..0004
+block 0004: 0004..0005
+  0004: return
+  returns
+
+method test_dead_ret ()V
+block 0000: 0000..0003
+  0000: ifeq 0006
+  next 0003
+  next 0006
+block 0003: 0003..0005
+  0003: ret 00
+  returns
+dead code 0005..0006
+block 0006: 0006..0007
+  0006: return
+  returns
+
+method test_dead_tableswitch ()V
+block 0000: 0000..0014
+  0000: tableswitch
+    default: 001b
+  next 001b
+dead code 0014..001b
+block 001b: 001b..001c
+  001b: return
+  returns
+
+method test_dead_lookupswitch ()V
+block 0000: 0000..001c
+  0000: lookupswitch
+    default: 001e
+  next 001e
+dead code 001c..001e
+block 001e: 001e..001f
+  001e: return
+  returns
+
+method test_dead_ireturn ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: ireturn
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_lreturn ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: lreturn
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_freturn ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: freturn
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_dreturn ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: dreturn
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_areturn ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: areturn
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_return ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: return
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_athrow ()V
+block 0000: 0000..0003
+  0000: ifeq 0005
+  next 0003
+  next 0005
+block 0003: 0003..0004
+  0003: athrow
+  returns
+dead code 0004..0005
+block 0005: 0005..0006
+  0005: return
+  returns
+
+method test_dead_wideret ()V
+block 0000: 0000..0003
+  0000: ifeq 0008
+  next 0003
+  next 0008
+block 0003: 0003..0007
+  0003: wide ret 0100
+  returns
+dead code 0007..0008
+block 0008: 0008..0009
+  0008: return
+  returns
+
+method test_dead_goto_w ()V
+block 0000: 0000..0005
+  0000: goto_w 00000006
+  next 0006
+dead code 0005..0006
+block 0006: 0006..0007
+  0006: return
+  returns
diff --git a/dx/tests/031-bb-dead-code/info.txt b/dx/tests/031-bb-dead-code/info.txt
new file mode 100644
index 0000000..d5aa398
--- /dev/null
+++ b/dx/tests/031-bb-dead-code/info.txt
@@ -0,0 +1,3 @@
+This test checks to see that the basic block recognizer properly omits
+dead code. There is at least one example of dead code after each instruction 
+that *doesn't* flow to the next instruction.
diff --git a/dx/tests/031-bb-dead-code/run b/dx/tests/031-bb-dead-code/run
new file mode 100644
index 0000000..4f82e15
--- /dev/null
+++ b/dx/tests/031-bb-dead-code/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j
+dx --debug --dump --basic-blocks --width=200 blort.class
diff --git a/dx/tests/032-bb-live-code/blort.j b/dx/tests/032-bb-live-code/blort.j
new file mode 100644
index 0000000..05790bb
--- /dev/null
+++ b/dx/tests/032-bb-live-code/blort.j
@@ -0,0 +1,342 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public <init>()V
+    .limit locals 1
+
+    aload_0
+    invokespecial java/lang/Object/<init>()V
+    return
+.end method
+
+; Test that an exception handler for a live range is enlivened.
+.method public test_live_exception([I)V
+    nop
+    nop
+start:
+    aload_0
+    arraylength
+end1:
+    nop
+end2:
+    return
+handler1:
+    return
+handler2:
+    return
+    .catch java/lang/RuntimeException from start to end2 using handler2
+    .catch all from start to end1 using handler1
+.end method
+
+; Test that an exception handler for a live range is dead as long as
+; the covered code can't possibly throw.
+.method public test_dead_exception()V
+    nop
+    nop
+start:
+    nop
+end1:
+    nop
+end2:
+    return
+handler1:
+    return
+handler2:
+    return
+    .catch java/lang/RuntimeException from start to end2 using handler2
+    .catch all from start to end1 using handler1
+.end method
+
+; Test all the if* variants.
+.method public test_ifs()V
+    ifeq x0
+    ifne x1
+    iflt x2
+    ifge x3
+    ifgt x4
+    ifle x5
+    if_icmpeq x6
+    if_icmpne x7
+    if_icmplt x8
+    if_icmpge x9
+    if_icmpgt x10
+    if_icmple x11
+    if_acmpeq x12
+    if_acmpne x13
+    ifnull x14
+    ifnonnull x15
+    return
+x0:
+    return
+x1:
+    return
+x2:
+    return
+x3:
+    return
+x4:
+    return
+x5:
+    return
+x6:
+    return
+x7:
+    return
+x8:
+    return
+x9:
+    return
+x10:
+    return
+x11:
+    return
+x12:
+    return
+x13:
+    return
+x14:
+    return
+x15:
+    return
+.end method
+
+; Test jsr and jsr_w.
+.method public test_jsr()V
+    jsr j1
+    jsr_w j2
+    return
+j1:
+    astore_0
+    ret 0
+j2:
+    astore_0
+    ret_w 0
+.end method
+
+; Test tableswitch.
+.method public test_tableswitch()V
+    tableswitch 0x10
+        t1
+        t2
+        default: t3
+t1:
+    return
+t2:
+    return
+t3:
+    return
+.end method
+
+; Test lookupswitch.
+.method public test_lookupswitch()V
+    lookupswitch
+        0x05: s1
+        0x10: s2
+        default: s3
+s1:
+    return
+s2:
+    return
+s3:
+    return
+.end method
+
+; Test every non-branching op.
+.method public test_nonbranch()V
+    nop
+    aconst_null
+    iconst_m1
+    iconst_0
+    iconst_1
+    iconst_2
+    iconst_3
+    iconst_4
+    iconst_5
+    lconst_0
+    lconst_1
+    fconst_0
+    fconst_1
+    fconst_2
+    dconst_0
+    dconst_1
+    bipush 0x10
+    sipush 0x1000
+    ldc "x"
+    ldc_w "y"
+    ldc2_w 3.0
+    iload 5
+    lload 5
+    fload 5
+    dload 5
+    aload 5
+    iload_0
+    iload_1
+    iload_2
+    iload_3
+    lload_0
+    lload_1
+    lload_2
+    lload_3
+    fload_0
+    fload_1
+    fload_2
+    fload_3
+    dload_0
+    dload_1
+    dload_2
+    dload_3
+    aload_0
+    aload_1
+    aload_2
+    aload_3
+    iaload
+    laload
+    faload
+    daload
+    aaload
+    baload
+    caload
+    saload
+    istore 5
+    lstore 5
+    fstore 5
+    dstore 5
+    astore 5
+    istore_0
+    istore_1
+    istore_2
+    istore_3
+    lstore_0
+    lstore_1
+    lstore_2
+    lstore_3
+    fstore_0
+    fstore_1
+    fstore_2
+    fstore_3
+    dstore_0
+    dstore_1
+    dstore_2
+    dstore_3
+    astore_0
+    astore_1
+    astore_2
+    astore_3
+    iastore
+    lastore
+    fastore
+    dastore
+    aastore
+    bastore
+    castore
+    sastore
+    pop
+    pop2
+    dup
+    dup_x1
+    dup_x2
+    dup2
+    dup2_x1
+    dup2_x2
+    swap
+    iadd
+    ladd
+    fadd
+    dadd
+    isub
+    lsub
+    fsub
+    dsub
+    imul
+    lmul
+    fmul
+    dmul
+    idiv
+    ldiv
+    fdiv
+    ddiv
+    irem
+    lrem
+    frem
+    drem
+    ineg
+    lneg
+    fneg
+    dneg
+    ishl
+    lshl
+    ishr
+    lshr
+    iushr
+    lushr
+    iand
+    land
+    ior
+    lor
+    ixor
+    lxor
+    iinc 5 0x10
+    i2l
+    i2f
+    i2d
+    l2i
+    l2f
+    l2d
+    f2i
+    f2l
+    f2d
+    d2i
+    d2l
+    d2f
+    i2b
+    i2c
+    i2s
+    lcmp
+    fcmpl
+    fcmpg
+    dcmpl
+    dcmpg
+    getstatic blort/x I
+    putstatic blort/x I
+    getfield blort/x I
+    putfield blort/x I
+    invokevirtual blort/x()V
+    invokespecial blort/x()V
+    invokestatic blort/x()V
+    invokeinterface blort/x()V 1
+    new blort
+    newarray int
+    anewarray blort
+    arraylength
+    checkcast blort
+    instanceof blort
+    monitorenter
+    monitorexit
+    iload 0x100
+    lload 0x100
+    fload 0x100
+    dload 0x100
+    aload 0x100
+    istore 0x100
+    lstore 0x100
+    fstore 0x100
+    dstore 0x100
+    astore 0x100
+    iinc 0x123 0x321
+    multianewarray [[[I 2
+    return
+.end method
diff --git a/dx/tests/032-bb-live-code/expected.txt b/dx/tests/032-bb-live-code/expected.txt
new file mode 100644
index 0000000..26444af
--- /dev/null
+++ b/dx/tests/032-bb-live-code/expected.txt
@@ -0,0 +1,497 @@
+Generated: ./blort.class
+reading blort.class...
+method <init> ()V
+block 0000: 0000..0004
+  0000: aload_0 // 00
+  0001: invokespecial method{java.lang.Object.<init>:()V}
+  next 0004
+block 0004: 0004..0005
+  0004: return
+  returns
+
+method test_live_exception ([I)V
+block 0000: 0000..0002
+  0000: nop
+  0001: nop
+  next 0002
+block 0002: 0002..0004
+  0002: aload_0 // 00
+  0003: arraylength
+  next 0007
+  next 0006
+  next 0004
+  catch java.lang.RuntimeException -> 0007
+  catch <any> -> 0006
+block 0004: 0004..0005
+  0004: nop
+  next 0005
+block 0005: 0005..0006
+  0005: return
+  returns
+block 0006: 0006..0007
+  0006: return
+  returns
+block 0007: 0007..0008
+  0007: return
+  returns
+
+method test_dead_exception ()V
+block 0000: 0000..0002
+  0000: nop
+  0001: nop
+  next 0002
+block 0002: 0002..0003
+  0002: nop
+  next 0003
+block 0003: 0003..0004
+  0003: nop
+  next 0004
+block 0004: 0004..0005
+  0004: return
+  returns
+block 0005: 0005..0006
+  0005: return
+  returns
+block 0006: 0006..0007
+  0006: return
+  returns
+
+method test_ifs ()V
+block 0000: 0000..0003
+  0000: ifeq 0031
+  next 0003
+  next 0031
+block 0003: 0003..0006
+  0003: ifne 0032
+  next 0006
+  next 0032
+block 0006: 0006..0009
+  0006: iflt 0033
+  next 0009
+  next 0033
+block 0009: 0009..000c
+  0009: ifge 0034
+  next 000c
+  next 0034
+block 000c: 000c..000f
+  000c: ifgt 0035
+  next 000f
+  next 0035
+block 000f: 000f..0012
+  000f: ifle 0036
+  next 0012
+  next 0036
+block 0012: 0012..0015
+  0012: if_icmpeq 0037
+  next 0015
+  next 0037
+block 0015: 0015..0018
+  0015: if_icmpne 0038
+  next 0018
+  next 0038
+block 0018: 0018..001b
+  0018: if_icmplt 0039
+  next 001b
+  next 0039
+block 001b: 001b..001e
+  001b: if_icmpge 003a
+  next 001e
+  next 003a
+block 001e: 001e..0021
+  001e: if_icmpgt 003b
+  next 0021
+  next 003b
+block 0021: 0021..0024
+  0021: if_icmple 003c
+  next 0024
+  next 003c
+block 0024: 0024..0027
+  0024: if_acmpeq 003d
+  next 0027
+  next 003d
+block 0027: 0027..002a
+  0027: if_acmpne 003e
+  next 002a
+  next 003e
+block 002a: 002a..002d
+  002a: ifnull 003f
+  next 002d
+  next 003f
+block 002d: 002d..0030
+  002d: ifnonnull 0040
+  next 0030
+  next 0040
+block 0030: 0030..0031
+  0030: return
+  returns
+block 0031: 0031..0032
+  0031: return
+  returns
+block 0032: 0032..0033
+  0032: return
+  returns
+block 0033: 0033..0034
+  0033: return
+  returns
+block 0034: 0034..0035
+  0034: return
+  returns
+block 0035: 0035..0036
+  0035: return
+  returns
+block 0036: 0036..0037
+  0036: return
+  returns
+block 0037: 0037..0038
+  0037: return
+  returns
+block 0038: 0038..0039
+  0038: return
+  returns
+block 0039: 0039..003a
+  0039: return
+  returns
+block 003a: 003a..003b
+  003a: return
+  returns
+block 003b: 003b..003c
+  003b: return
+  returns
+block 003c: 003c..003d
+  003c: return
+  returns
+block 003d: 003d..003e
+  003d: return
+  returns
+block 003e: 003e..003f
+  003e: return
+  returns
+block 003f: 003f..0040
+  003f: return
+  returns
+block 0040: 0040..0041
+  0040: return
+  returns
+
+method test_jsr ()V
+block 0000: 0000..0003
+  0000: jsr 0009
+  next 0003
+  next 0009
+block 0003: 0003..0008
+  0003: jsr_w 0000000c
+  next 0008
+  next 000c
+block 0008: 0008..0009
+  0008: return
+  returns
+block 0009: 0009..000c
+  0009: astore_0 // 00
+  000a: ret 00
+  returns
+block 000c: 000c..0011
+  000c: astore_0 // 00
+  000d: wide ret 0000
+  returns
+
+method test_tableswitch ()V
+block 0000: 0000..0018
+  0000: tableswitch
+    +00000010: 0018
+    +00000011: 0019
+    default: 001a
+  next 0018
+  next 0019
+  next 001a
+block 0018: 0018..0019
+  0018: return
+  returns
+block 0019: 0019..001a
+  0019: return
+  returns
+block 001a: 001a..001b
+  001a: return
+  returns
+
+method test_lookupswitch ()V
+block 0000: 0000..001c
+  0000: lookupswitch
+    +00000005: 001c
+    +00000010: 001d
+    default: 001e
+  next 001c
+  next 001d
+  next 001e
+block 001c: 001c..001d
+  001c: return
+  returns
+block 001d: 001d..001e
+  001d: return
+  returns
+block 001e: 001e..001f
+  001e: return
+  returns
+
+method test_nonbranch ()V
+block 0000: 0000..0017
+  0000: nop
+  0001: aconst_null
+  0002: iconst_m1 // #-01
+  0003: iconst_0 // #+00
+  0004: iconst_1 // #+01
+  0005: iconst_2 // #+02
+  0006: iconst_3 // #+03
+  0007: iconst_4 // #+04
+  0008: iconst_5 // #+05
+  0009: lconst_0 // +00
+  000a: lconst_1 // +01
+  000b: fconst_0 // 0.0
+  000c: fconst_1 // 1.0
+  000d: fconst_2 // 2.0
+  000e: dconst_0 // 0.0
+  000f: dconst_1 // 1.0
+  0010: bipush #+10
+  0012: sipush #+1000
+  0015: ldc string{"x"}
+  next 0017
+block 0017: 0017..001a
+  0017: ldc_w string{"y"}
+  next 001a
+block 001a: 001a..003c
+  001a: ldc2_w #4008000000000000 // 3.0
+  001d: iload 05
+  001f: lload 05 // category-2
+  0021: fload 05
+  0023: dload 05 // category-2
+  0025: aload 05
+  0027: iload_0 // 00
+  0028: iload_1 // 01
+  0029: iload_2 // 02
+  002a: iload_3 // 03
+  002b: lload_0 // 00, category-2
+  002c: lload_1 // 01, category-2
+  002d: lload_2 // 02, category-2
+  002e: lload_3 // 03, category-2
+  002f: fload_0 // 00
+  0030: fload_1 // 01
+  0031: fload_2 // 02
+  0032: fload_3 // 03
+  0033: dload_0 // 00, category-2
+  0034: dload_1 // 01, category-2
+  0035: dload_2 // 02, category-2
+  0036: dload_3 // 03, category-2
+  0037: aload_0 // 00
+  0038: aload_1 // 01
+  0039: aload_2 // 02
+  003a: aload_3 // 03
+  003b: iaload
+  next 003c
+block 003c: 003c..003d
+  003c: laload
+  next 003d
+block 003d: 003d..003e
+  003d: faload
+  next 003e
+block 003e: 003e..003f
+  003e: daload
+  next 003f
+block 003f: 003f..0040
+  003f: aaload
+  next 0040
+block 0040: 0040..0041
+  0040: baload
+  next 0041
+block 0041: 0041..0042
+  0041: caload
+  next 0042
+block 0042: 0042..0043
+  0042: saload
+  next 0043
+block 0043: 0043..0062
+  0043: istore 05
+  0045: lstore 05 // category-2
+  0047: fstore 05
+  0049: dstore 05 // category-2
+  004b: astore 05
+  004d: istore_0 // 00
+  004e: istore_1 // 01
+  004f: istore_2 // 02
+  0050: istore_3 // 03
+  0051: lstore_0 // 00, category-2
+  0052: lstore_1 // 01, category-2
+  0053: lstore_2 // 02, category-2
+  0054: lstore_3 // 03, category-2
+  0055: fstore_0 // 00
+  0056: fstore_1 // 01
+  0057: fstore_2 // 02
+  0058: fstore_3 // 03
+  0059: dstore_0 // 00, category-2
+  005a: dstore_1 // 01, category-2
+  005b: dstore_2 // 02, category-2
+  005c: dstore_3 // 03, category-2
+  005d: astore_0 // 00
+  005e: astore_1 // 01
+  005f: astore_2 // 02
+  0060: astore_3 // 03
+  0061: iastore
+  next 0062
+block 0062: 0062..0063
+  0062: lastore
+  next 0063
+block 0063: 0063..0064
+  0063: fastore
+  next 0064
+block 0064: 0064..0065
+  0064: dastore
+  next 0065
+block 0065: 0065..0066
+  0065: aastore
+  next 0066
+block 0066: 0066..0067
+  0066: bastore
+  next 0067
+block 0067: 0067..0068
+  0067: castore
+  next 0068
+block 0068: 0068..0069
+  0068: sastore
+  next 0069
+block 0069: 0069..007f
+  0069: pop
+  006a: pop2
+  006b: dup
+  006c: dup_x1
+  006d: dup_x2
+  006e: dup2
+  006f: dup2_x1
+  0070: dup2_x2
+  0071: swap
+  0072: iadd
+  0073: ladd
+  0074: fadd
+  0075: dadd
+  0076: isub
+  0077: lsub
+  0078: fsub
+  0079: dsub
+  007a: imul
+  007b: lmul
+  007c: fmul
+  007d: dmul
+  007e: idiv
+  next 007f
+block 007f: 007f..0080
+  007f: ldiv
+  next 0080
+block 0080: 0080..0083
+  0080: fdiv
+  0081: ddiv
+  0082: irem
+  next 0083
+block 0083: 0083..0084
+  0083: lrem
+  next 0084
+block 0084: 0084..00b0
+  0084: frem
+  0085: drem
+  0086: ineg
+  0087: lneg
+  0088: fneg
+  0089: dneg
+  008a: ishl
+  008b: lshl
+  008c: ishr
+  008d: lshr
+  008e: iushr
+  008f: lushr
+  0090: iand
+  0091: land
+  0092: ior
+  0093: lor
+  0094: ixor
+  0095: lxor
+  0096: iinc 05, #+10
+  0099: i2l
+  009a: i2f
+  009b: i2d
+  009c: l2i
+  009d: l2f
+  009e: l2d
+  009f: f2i
+  00a0: f2l
+  00a1: f2d
+  00a2: d2i
+  00a3: d2l
+  00a4: d2f
+  00a5: i2b
+  00a6: i2c
+  00a7: i2s
+  00a8: lcmp
+  00a9: fcmpl
+  00aa: fcmpg
+  00ab: dcmpl
+  00ac: dcmpg
+  00ad: getstatic field{blort.x:I}
+  next 00b0
+block 00b0: 00b0..00b3
+  00b0: putstatic field{blort.x:I}
+  next 00b3
+block 00b3: 00b3..00b6
+  00b3: getfield field{blort.x:I}
+  next 00b6
+block 00b6: 00b6..00b9
+  00b6: putfield field{blort.x:I}
+  next 00b9
+block 00b9: 00b9..00bc
+  00b9: invokevirtual method{blort.x:()V}
+  next 00bc
+block 00bc: 00bc..00bf
+  00bc: invokespecial method{blort.x:()V}
+  next 00bf
+block 00bf: 00bf..00c2
+  00bf: invokestatic method{blort.x:()V}
+  next 00c2
+block 00c2: 00c2..00c7
+  00c2: invokeinterface ifaceMethod{blort.x:()V}, 0001
+  next 00c7
+block 00c7: 00c7..00ca
+  00c7: new type{blort}
+  next 00ca
+block 00ca: 00ca..00cc
+  00ca: newarray int
+  next 00cc
+block 00cc: 00cc..00cf
+  00cc: anewarray type{blort}
+  next 00cf
+block 00cf: 00cf..00d0
+  00cf: arraylength
+  next 00d0
+block 00d0: 00d0..00d3
+  00d0: checkcast type{blort}
+  next 00d3
+block 00d3: 00d3..00d6
+  00d3: instanceof type{blort}
+  next 00d6
+block 00d6: 00d6..00d7
+  00d6: monitorenter
+  next 00d7
+block 00d7: 00d7..00d8
+  00d7: monitorexit
+  next 00d8
+block 00d8: 00d8..010a
+  00d8: wide iload 0100
+  00dc: wide lload 0100 // category-2
+  00e0: wide fload 0100
+  00e4: wide dload 0100 // category-2
+  00e8: wide aload 0100
+  00ec: wide istore 0100
+  00f0: wide lstore 0100 // category-2
+  00f4: wide fstore 0100
+  00f8: wide dstore 0100 // category-2
+  00fc: wide astore 0100
+  0100: wide iinc 0123, #+0321
+  0106: multianewarray type{int[][][]}, 02
+  next 010a
+block 010a: 010a..010b
+  010a: return
+  returns
diff --git a/dx/tests/032-bb-live-code/info.txt b/dx/tests/032-bb-live-code/info.txt
new file mode 100644
index 0000000..f94b435
--- /dev/null
+++ b/dx/tests/032-bb-live-code/info.txt
@@ -0,0 +1,5 @@
+This test checks to see that the basic block recognizer properly
+includes as live code all code which could possibly be flowed
+to. There is at least one example of each instruction which allows
+flow to the subsequent instruction, and all forks of each conditional
+branch are checked for liveness as well.
diff --git a/dx/tests/032-bb-live-code/run b/dx/tests/032-bb-live-code/run
new file mode 100644
index 0000000..4f82e15
--- /dev/null
+++ b/dx/tests/032-bb-live-code/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j
+dx --debug --dump --basic-blocks --width=200 blort.class
diff --git a/dx/tests/033-unit-IntList/expected.txt b/dx/tests/033-unit-IntList/expected.txt
new file mode 100644
index 0000000..5418338
--- /dev/null
+++ b/dx/tests/033-unit-IntList/expected.txt
@@ -0,0 +1 @@
+Yay!
diff --git a/dx/tests/033-unit-IntList/info.txt b/dx/tests/033-unit-IntList/info.txt
new file mode 100644
index 0000000..7d7e8aa
--- /dev/null
+++ b/dx/tests/033-unit-IntList/info.txt
@@ -0,0 +1 @@
+Unit test for com.android.dx.util.IntList.
diff --git a/dx/tests/033-unit-IntList/run b/dx/tests/033-unit-IntList/run
new file mode 100644
index 0000000..16ca6fb
--- /dev/null
+++ b/dx/tests/033-unit-IntList/run
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# 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.
+
+dx --junit com.android.dx.util._tests._IntList > unit-out.txt
+
+if [ "$?" = "0" ]; then
+    echo "Yay!"
+else
+    cat unit-out.txt
+fi
diff --git a/dx/tests/034-dex-minimal/blort.j b/dx/tests/034-dex-minimal/blort.j
new file mode 100644
index 0000000..b4715b2
--- /dev/null
+++ b/dx/tests/034-dex-minimal/blort.j
@@ -0,0 +1,16 @@
+; 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.
+
+.class blort
+.super java/lang/Object
diff --git a/dx/tests/034-dex-minimal/expected.txt b/dx/tests/034-dex-minimal/expected.txt
new file mode 100644
index 0000000..a8f81c8
--- /dev/null
+++ b/dx/tests/034-dex-minimal/expected.txt
@@ -0,0 +1,70 @@
+000000: 6465 780a 3033|magic: "dex\n035\0"
+000006: 3500          |
+000008: be0b 70d9     |checksum
+00000c: 1d9c 3f88 730d|signature
+000012: 0ed6 caa3 77d4|
+000018: 5204 65e7 322d|
+00001e: 365a          |
+000020: 8c00 0000     |file_size:       0000008c
+000024: 7000 0000     |header_size:     00000070
+000028: 7856 3412     |endian_tag:      12345678
+00002c: 0000 0000     |link_size:       0
+000030: 0000 0000     |link_off:        0
+000034: 7000 0000     |map_off:         00000070
+000038: 0000 0000     |string_ids_size: 00000000
+00003c: 0000 0000     |string_ids_off:  00000000
+000040: 0000 0000     |type_ids_size:   00000000
+000044: 0000 0000     |type_ids_off:    00000000
+000048: 0000 0000     |proto_ids_size:  00000000
+00004c: 0000 0000     |proto_ids_off:   00000000
+000050: 0000 0000     |field_ids_size:  00000000
+000054: 0000 0000     |field_ids_off:   00000000
+000058: 0000 0000     |method_ids_size: 00000000
+00005c: 0000 0000     |method_ids_off:  00000000
+000060: 0000 0000     |class_defs_size: 00000000
+000064: 0000 0000     |class_defs_off:  00000000
+000068: 1c00 0000     |data_size:       0000001c
+00006c: 7000 0000     |data_off:        00000070
+                      |
+                      |string_ids:
+                      |
+                      |type_ids:
+                      |
+                      |proto_ids:
+                      |
+                      |field_ids:
+                      |
+                      |method_ids:
+                      |
+                      |class_defs:
+                      |
+                      |word_data:
+                      |
+                      |
+                      |string_data:
+                      |
+                      |byte_data:
+                      |
+                      |
+                      |map:
+                      |[70] map list
+000070: 0200 0000     |  size: 00000002
+                      |[74] header_item map
+000074: 0000          |  type:   0000 // TYPE_HEADER_ITEM
+000076: 0000          |  unused: 0
+000078: 0100 0000     |  size:   00000001
+00007c: 0000 0000     |  offset: 00000000
+                      |[80] map_list map
+000080: 0010          |  type:   1000 // TYPE_MAP_LIST
+000082: 0000          |  unused: 0
+000084: 0100 0000     |  size:   00000001
+000088: 7000 0000     |  offset: 00000070
+                      |
+                      |statistics:
+                      |  header: 1 item; 112 bytes total
+                      |    112 bytes/item
+                      |  map list: 1 item; 28 bytes total
+                      |    28 bytes/item
+
+processing blort.class...
+Good!
diff --git a/dx/tests/034-dex-minimal/info.txt b/dx/tests/034-dex-minimal/info.txt
new file mode 100644
index 0000000..13bb9ab
--- /dev/null
+++ b/dx/tests/034-dex-minimal/info.txt
@@ -0,0 +1,9 @@
+This is a smoke test of a couple cases of minimal dex creation:
+
+The first test tries to create the truly minimal dex file by using the
+--no-files option. The output dump of this is checked to make sure it
+is exactly correct. (There is arguably only one "right" answer.)
+
+The second test tries to convert a minimal classfile and ensures that
+the conversion runs without failure, though the contents of the
+converted file are not checked for correctness.
diff --git a/dx/tests/034-dex-minimal/run b/dx/tests/034-dex-minimal/run
new file mode 100644
index 0000000..bf90624
--- /dev/null
+++ b/dx/tests/034-dex-minimal/run
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dex --dump-to=- --no-files
+echo ""
+
+jasmin -d . blort.j >/dev/null
+dx --verbose --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/035-dex-instance-var/blort.j b/dx/tests/035-dex-instance-var/blort.j
new file mode 100644
index 0000000..1bcdf8e
--- /dev/null
+++ b/dx/tests/035-dex-instance-var/blort.j
@@ -0,0 +1,18 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.field public x I
diff --git a/dx/tests/035-dex-instance-var/expected.txt b/dx/tests/035-dex-instance-var/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/035-dex-instance-var/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/035-dex-instance-var/info.txt b/dx/tests/035-dex-instance-var/info.txt
new file mode 100644
index 0000000..294c9eb
--- /dev/null
+++ b/dx/tests/035-dex-instance-var/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just an instance variable.
diff --git a/dx/tests/035-dex-instance-var/run b/dx/tests/035-dex-instance-var/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/035-dex-instance-var/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/036-dex-static-var/blort.j b/dx/tests/036-dex-static-var/blort.j
new file mode 100644
index 0000000..260f446
--- /dev/null
+++ b/dx/tests/036-dex-static-var/blort.j
@@ -0,0 +1,18 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.field public static x I
diff --git a/dx/tests/036-dex-static-var/expected.txt b/dx/tests/036-dex-static-var/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/036-dex-static-var/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/036-dex-static-var/info.txt b/dx/tests/036-dex-static-var/info.txt
new file mode 100644
index 0000000..5c562eb
--- /dev/null
+++ b/dx/tests/036-dex-static-var/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just a static variable.
diff --git a/dx/tests/036-dex-static-var/run b/dx/tests/036-dex-static-var/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/036-dex-static-var/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/037-dex-static-final-var/blort.j b/dx/tests/037-dex-static-final-var/blort.j
new file mode 100644
index 0000000..ac0332e
--- /dev/null
+++ b/dx/tests/037-dex-static-final-var/blort.j
@@ -0,0 +1,18 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.field public static final x I = 10
diff --git a/dx/tests/037-dex-static-final-var/expected.txt b/dx/tests/037-dex-static-final-var/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/037-dex-static-final-var/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/037-dex-static-final-var/info.txt b/dx/tests/037-dex-static-final-var/info.txt
new file mode 100644
index 0000000..03d798f
--- /dev/null
+++ b/dx/tests/037-dex-static-final-var/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just a final static variable.
diff --git a/dx/tests/037-dex-static-final-var/run b/dx/tests/037-dex-static-final-var/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/037-dex-static-final-var/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/038-dex-instance-method/blort.j b/dx/tests/038-dex-instance-method/blort.j
new file mode 100644
index 0000000..7ddd7b5
--- /dev/null
+++ b/dx/tests/038-dex-instance-method/blort.j
@@ -0,0 +1,21 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public blort()V
+    nop
+    return
+.end method
diff --git a/dx/tests/038-dex-instance-method/expected.txt b/dx/tests/038-dex-instance-method/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/038-dex-instance-method/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/038-dex-instance-method/info.txt b/dx/tests/038-dex-instance-method/info.txt
new file mode 100644
index 0000000..6aa93c3
--- /dev/null
+++ b/dx/tests/038-dex-instance-method/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just an instance method.
diff --git a/dx/tests/038-dex-instance-method/run b/dx/tests/038-dex-instance-method/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/038-dex-instance-method/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/039-dex-static-method/blort.j b/dx/tests/039-dex-static-method/blort.j
new file mode 100644
index 0000000..5b74c57
--- /dev/null
+++ b/dx/tests/039-dex-static-method/blort.j
@@ -0,0 +1,21 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public static blort()V
+    nop
+    return
+.end method
diff --git a/dx/tests/039-dex-static-method/expected.txt b/dx/tests/039-dex-static-method/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/039-dex-static-method/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/039-dex-static-method/info.txt b/dx/tests/039-dex-static-method/info.txt
new file mode 100644
index 0000000..59c8d6e
--- /dev/null
+++ b/dx/tests/039-dex-static-method/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just a static method.
diff --git a/dx/tests/039-dex-static-method/run b/dx/tests/039-dex-static-method/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/039-dex-static-method/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/040-dex-constructor/blort.j b/dx/tests/040-dex-constructor/blort.j
new file mode 100644
index 0000000..e0ae441
--- /dev/null
+++ b/dx/tests/040-dex-constructor/blort.j
@@ -0,0 +1,21 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public <init>()V
+    nop
+    return
+.end method
diff --git a/dx/tests/040-dex-constructor/expected.txt b/dx/tests/040-dex-constructor/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/040-dex-constructor/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/040-dex-constructor/info.txt b/dx/tests/040-dex-constructor/info.txt
new file mode 100644
index 0000000..65eef93
--- /dev/null
+++ b/dx/tests/040-dex-constructor/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just a constructor.
diff --git a/dx/tests/040-dex-constructor/run b/dx/tests/040-dex-constructor/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/040-dex-constructor/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/041-dex-abstract-method/blort.j b/dx/tests/041-dex-abstract-method/blort.j
new file mode 100644
index 0000000..8074fae
--- /dev/null
+++ b/dx/tests/041-dex-abstract-method/blort.j
@@ -0,0 +1,19 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public abstract blort()V
+.end method
diff --git a/dx/tests/041-dex-abstract-method/expected.txt b/dx/tests/041-dex-abstract-method/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/041-dex-abstract-method/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/041-dex-abstract-method/info.txt b/dx/tests/041-dex-abstract-method/info.txt
new file mode 100644
index 0000000..e004388
--- /dev/null
+++ b/dx/tests/041-dex-abstract-method/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of a classfile with
+just an abstract instance method.
diff --git a/dx/tests/041-dex-abstract-method/run b/dx/tests/041-dex-abstract-method/run
new file mode 100644
index 0000000..d7aa973
--- /dev/null
+++ b/dx/tests/041-dex-abstract-method/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --output=blort.dex blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/042-dex-ignore-result/Blort.java b/dx/tests/042-dex-ignore-result/Blort.java
new file mode 100644
index 0000000..2df4e66
--- /dev/null
+++ b/dx/tests/042-dex-ignore-result/Blort.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    static public int hello() {
+        return 10;
+    }
+
+    static public void ouch() {
+        hello();
+        hello();
+    }
+}
diff --git a/dx/tests/042-dex-ignore-result/expected.txt b/dx/tests/042-dex-ignore-result/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/042-dex-ignore-result/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/042-dex-ignore-result/info.txt b/dx/tests/042-dex-ignore-result/info.txt
new file mode 100644
index 0000000..6289664
--- /dev/null
+++ b/dx/tests/042-dex-ignore-result/info.txt
@@ -0,0 +1,5 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test is of the case of a
+method call to a method which returns a value, where that value is
+ignored.
diff --git a/dx/tests/042-dex-ignore-result/run b/dx/tests/042-dex-ignore-result/run
new file mode 100644
index 0000000..d035d09
--- /dev/null
+++ b/dx/tests/042-dex-ignore-result/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --output=blort.dex Blort.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/043-dex-two-classes/Blort.java b/dx/tests/043-dex-two-classes/Blort.java
new file mode 100644
index 0000000..235907d
--- /dev/null
+++ b/dx/tests/043-dex-two-classes/Blort.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/043-dex-two-classes/Zorch.java b/dx/tests/043-dex-two-classes/Zorch.java
new file mode 100644
index 0000000..c9dc4eb
--- /dev/null
+++ b/dx/tests/043-dex-two-classes/Zorch.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+public class Zorch
+{
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/043-dex-two-classes/expected.txt b/dx/tests/043-dex-two-classes/expected.txt
new file mode 100644
index 0000000..e88eb13
--- /dev/null
+++ b/dx/tests/043-dex-two-classes/expected.txt
@@ -0,0 +1,3 @@
+processing Blort.class...
+processing Zorch.class...
+Good!
diff --git a/dx/tests/043-dex-two-classes/info.txt b/dx/tests/043-dex-two-classes/info.txt
new file mode 100644
index 0000000..785fb9b
--- /dev/null
+++ b/dx/tests/043-dex-two-classes/info.txt
@@ -0,0 +1,4 @@
+This is a smoke test of dex conversion, which ensures that the
+conversion runs without failure, though the contents of the converted
+file are not checked for correctness. This test just makes sure that
+an attempt to combine two classes into a .dex file succeeds.
diff --git a/dx/tests/043-dex-two-classes/run b/dx/tests/043-dex-two-classes/run
new file mode 100644
index 0000000..41d3a0b
--- /dev/null
+++ b/dx/tests/043-dex-two-classes/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java Zorch.java
+dx --debug --verbose --dex --output=blort.dex *.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/044-dex-math-ops/Blort.java b/dx/tests/044-dex-math-ops/Blort.java
new file mode 100644
index 0000000..75095b5
--- /dev/null
+++ b/dx/tests/044-dex-math-ops/Blort.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    private volatile int i;
+    private volatile long l;
+    private volatile float f;
+    private volatile double d;
+
+    public void blort(int i1, int i2) {
+        i = -i1;
+        i = ~i1;
+        i = i1 + i2;
+        i = i1 - i2;
+        i = i1 * i2;
+        i = i1 / i2;
+        i = i1 % i2;
+        i = i1 & i2;
+        i = i1 | i2;
+        i = i1 ^ i2;
+        i = i1 << i2;
+        i = i1 >> i2;
+        i = i1 >>> i2;
+    }
+
+    public void blort(long l1, long l2) {
+        l = -l1;
+        l = ~l1;
+        l = l1 + l2;
+        l = l1 - l2;
+        l = l1 * l2;
+        l = l1 / l2;
+        l = l1 % l2;
+        l = l1 & l2;
+        l = l1 | l2;
+        l = l1 ^ l2;
+        l = l1 << l2;
+        l = l1 >> l2;
+        l = l1 >>> l2;
+    }
+
+    public void blort(float f1, float f2) {
+        f = -f1;
+        f = f1 + f2;
+        f = f1 - f2;
+        f = f1 * f2;
+        f = f1 / f2;
+        f = f1 % f2;
+    }
+
+    public void blort(double d1, double d2) {
+        d = -d1;
+        d = d1 + d2;
+        d = d1 - d2;
+        d = d1 * d2;
+        d = d1 / d2;
+        d = d1 % d2;
+    }
+}
diff --git a/dx/tests/044-dex-math-ops/expected.txt b/dx/tests/044-dex-math-ops/expected.txt
new file mode 100644
index 0000000..f6f8b79
--- /dev/null
+++ b/dx/tests/044-dex-math-ops/expected.txt
@@ -0,0 +1,213 @@
+Blort.blort:(DD)V:
+regs: 000f; ins: 0005; outs: 0000
+  0000: move-object v0, v10
+  0001: move-wide v1, v11
+  0002: move-wide v3, v13
+  0003: move-object v5, v0
+  0004: move-wide v6, v1
+  0005: neg-double v6, v6
+  0006: iput-wide v6, v5, Blort.d:D
+  0008: move-object v5, v0
+  0009: move-wide v6, v1
+  000a: move-wide v8, v3
+  000b: add-double/2addr v6, v8
+  000c: iput-wide v6, v5, Blort.d:D
+  000e: move-object v5, v0
+  000f: move-wide v6, v1
+  0010: move-wide v8, v3
+  0011: sub-double/2addr v6, v8
+  0012: iput-wide v6, v5, Blort.d:D
+  0014: move-object v5, v0
+  0015: move-wide v6, v1
+  0016: move-wide v8, v3
+  0017: mul-double/2addr v6, v8
+  0018: iput-wide v6, v5, Blort.d:D
+  001a: move-object v5, v0
+  001b: move-wide v6, v1
+  001c: move-wide v8, v3
+  001d: div-double/2addr v6, v8
+  001e: iput-wide v6, v5, Blort.d:D
+  0020: move-object v5, v0
+  0021: move-wide v6, v1
+  0022: move-wide v8, v3
+  0023: rem-double/2addr v6, v8
+  0024: iput-wide v6, v5, Blort.d:D
+  0026: return-void
+Blort.blort:(FF)V:
+regs: 0009; ins: 0003; outs: 0000
+  0000: move-object v0, v6
+  0001: move v1, v7
+  0002: move v2, v8
+  0003: move-object v3, v0
+  0004: move v4, v1
+  0005: neg-float v4, v4
+  0006: iput v4, v3, Blort.f:F
+  0008: move-object v3, v0
+  0009: move v4, v1
+  000a: move v5, v2
+  000b: add-float/2addr v4, v5
+  000c: iput v4, v3, Blort.f:F
+  000e: move-object v3, v0
+  000f: move v4, v1
+  0010: move v5, v2
+  0011: sub-float/2addr v4, v5
+  0012: iput v4, v3, Blort.f:F
+  0014: move-object v3, v0
+  0015: move v4, v1
+  0016: move v5, v2
+  0017: mul-float/2addr v4, v5
+  0018: iput v4, v3, Blort.f:F
+  001a: move-object v3, v0
+  001b: move v4, v1
+  001c: move v5, v2
+  001d: div-float/2addr v4, v5
+  001e: iput v4, v3, Blort.f:F
+  0020: move-object v3, v0
+  0021: move v4, v1
+  0022: move v5, v2
+  0023: rem-float/2addr v4, v5
+  0024: iput v4, v3, Blort.f:F
+  0026: return-void
+Blort.blort:(II)V:
+regs: 0009; ins: 0003; outs: 0000
+  0000: move-object v0, v6
+  0001: move v1, v7
+  0002: move v2, v8
+  0003: move-object v3, v0
+  0004: move v4, v1
+  0005: neg-int v4, v4
+  0006: iput v4, v3, Blort.i:I
+  0008: move-object v3, v0
+  0009: move v4, v1
+  000a: const/4 v5, #int -1 // #f
+  000b: xor-int/lit8 v4, v4, #int -1 // #ff
+  000d: iput v4, v3, Blort.i:I
+  000f: move-object v3, v0
+  0010: move v4, v1
+  0011: move v5, v2
+  0012: add-int/2addr v4, v5
+  0013: iput v4, v3, Blort.i:I
+  0015: move-object v3, v0
+  0016: move v4, v1
+  0017: move v5, v2
+  0018: sub-int/2addr v4, v5
+  0019: iput v4, v3, Blort.i:I
+  001b: move-object v3, v0
+  001c: move v4, v1
+  001d: move v5, v2
+  001e: mul-int/2addr v4, v5
+  001f: iput v4, v3, Blort.i:I
+  0021: move-object v3, v0
+  0022: move v4, v1
+  0023: move v5, v2
+  0024: div-int/2addr v4, v5
+  0025: iput v4, v3, Blort.i:I
+  0027: move-object v3, v0
+  0028: move v4, v1
+  0029: move v5, v2
+  002a: rem-int/2addr v4, v5
+  002b: iput v4, v3, Blort.i:I
+  002d: move-object v3, v0
+  002e: move v4, v1
+  002f: move v5, v2
+  0030: and-int/2addr v4, v5
+  0031: iput v4, v3, Blort.i:I
+  0033: move-object v3, v0
+  0034: move v4, v1
+  0035: move v5, v2
+  0036: or-int/2addr v4, v5
+  0037: iput v4, v3, Blort.i:I
+  0039: move-object v3, v0
+  003a: move v4, v1
+  003b: move v5, v2
+  003c: xor-int/2addr v4, v5
+  003d: iput v4, v3, Blort.i:I
+  003f: move-object v3, v0
+  0040: move v4, v1
+  0041: move v5, v2
+  0042: shl-int/2addr v4, v5
+  0043: iput v4, v3, Blort.i:I
+  0045: move-object v3, v0
+  0046: move v4, v1
+  0047: move v5, v2
+  0048: shr-int/2addr v4, v5
+  0049: iput v4, v3, Blort.i:I
+  004b: move-object v3, v0
+  004c: move v4, v1
+  004d: move v5, v2
+  004e: ushr-int/2addr v4, v5
+  004f: iput v4, v3, Blort.i:I
+  0051: return-void
+Blort.blort:(JJ)V:
+regs: 000f; ins: 0005; outs: 0000
+  0000: move-object v0, v10
+  0001: move-wide v1, v11
+  0002: move-wide v3, v13
+  0003: move-object v5, v0
+  0004: move-wide v6, v1
+  0005: neg-long v6, v6
+  0006: iput-wide v6, v5, Blort.l:J
+  0008: move-object v5, v0
+  0009: move-wide v6, v1
+  000a: const-wide/16 v8, #long -1 // #ffff
+  000c: xor-long/2addr v6, v8
+  000d: iput-wide v6, v5, Blort.l:J
+  000f: move-object v5, v0
+  0010: move-wide v6, v1
+  0011: move-wide v8, v3
+  0012: add-long/2addr v6, v8
+  0013: iput-wide v6, v5, Blort.l:J
+  0015: move-object v5, v0
+  0016: move-wide v6, v1
+  0017: move-wide v8, v3
+  0018: sub-long/2addr v6, v8
+  0019: iput-wide v6, v5, Blort.l:J
+  001b: move-object v5, v0
+  001c: move-wide v6, v1
+  001d: move-wide v8, v3
+  001e: mul-long/2addr v6, v8
+  001f: iput-wide v6, v5, Blort.l:J
+  0021: move-object v5, v0
+  0022: move-wide v6, v1
+  0023: move-wide v8, v3
+  0024: div-long/2addr v6, v8
+  0025: iput-wide v6, v5, Blort.l:J
+  0027: move-object v5, v0
+  0028: move-wide v6, v1
+  0029: move-wide v8, v3
+  002a: rem-long/2addr v6, v8
+  002b: iput-wide v6, v5, Blort.l:J
+  002d: move-object v5, v0
+  002e: move-wide v6, v1
+  002f: move-wide v8, v3
+  0030: and-long/2addr v6, v8
+  0031: iput-wide v6, v5, Blort.l:J
+  0033: move-object v5, v0
+  0034: move-wide v6, v1
+  0035: move-wide v8, v3
+  0036: or-long/2addr v6, v8
+  0037: iput-wide v6, v5, Blort.l:J
+  0039: move-object v5, v0
+  003a: move-wide v6, v1
+  003b: move-wide v8, v3
+  003c: xor-long/2addr v6, v8
+  003d: iput-wide v6, v5, Blort.l:J
+  003f: move-object v5, v0
+  0040: move-wide v6, v1
+  0041: move-wide v8, v3
+  0042: long-to-int v8, v8
+  0043: shl-long/2addr v6, v8
+  0044: iput-wide v6, v5, Blort.l:J
+  0046: move-object v5, v0
+  0047: move-wide v6, v1
+  0048: move-wide v8, v3
+  0049: long-to-int v8, v8
+  004a: shr-long/2addr v6, v8
+  004b: iput-wide v6, v5, Blort.l:J
+  004d: move-object v5, v0
+  004e: move-wide v6, v1
+  004f: move-wide v8, v3
+  0050: long-to-int v8, v8
+  0051: ushr-long/2addr v6, v8
+  0052: iput-wide v6, v5, Blort.l:J
+  0054: return-void
diff --git a/dx/tests/044-dex-math-ops/info.txt b/dx/tests/044-dex-math-ops/info.txt
new file mode 100644
index 0000000..733dcb6
--- /dev/null
+++ b/dx/tests/044-dex-math-ops/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+simple uses of all the math ops end up getting converted reasonably.
+
+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/044-dex-math-ops/run b/dx/tests/044-dex-math-ops/run
new file mode 100644
index 0000000..d8d4273
--- /dev/null
+++ b/dx/tests/044-dex-math-ops/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.blort *.class
diff --git a/dx/tests/045-dex-switch-ops/Blort.java b/dx/tests/045-dex-switch-ops/Blort.java
new file mode 100644
index 0000000..598bd69
--- /dev/null
+++ b/dx/tests/045-dex-switch-ops/Blort.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public int switchTest1(int x) {
+        switch (x) {
+            case 1: {
+                return 2;
+            }
+            case 2: {
+                return 3;
+            }
+            case 3: {
+                return 4;
+            }
+            case 4: {
+                return 5;
+            }
+        }
+
+        return 6;
+    }
+
+    public int switchTest2(int x) {
+        switch (x) {
+            case 1: {
+                return 2;
+            }
+            case 10: {
+                return 3;
+            }
+            case 100: {
+                return 4;
+            }
+            case 1000: {
+                return 50;
+            }
+        }
+
+        return 6;
+    }
+}
diff --git a/dx/tests/045-dex-switch-ops/expected.txt b/dx/tests/045-dex-switch-ops/expected.txt
new file mode 100644
index 0000000..80bc808
--- /dev/null
+++ b/dx/tests/045-dex-switch-ops/expected.txt
@@ -0,0 +1,53 @@
+Blort.switchTest1:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: packed-switch v2, 0016 // +0013
+  0006: const/4 v2, #int 6 // #6
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 2 // #2
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: const/4 v2, #int 3 // #3
+  000d: move v0, v2
+  000e: goto 0008 // -0006
+  000f: const/4 v2, #int 4 // #4
+  0010: move v0, v2
+  0011: goto 0008 // -0009
+  0012: const/4 v2, #int 5 // #5
+  0013: move v0, v2
+  0014: goto 0008 // -000c
+  0015: nop // spacer
+  0016: packed-switch-payload // for switch @ 0003
+          1: 00000009 // +00000006
+          2: 0000000c // +00000009
+          3: 0000000f // +0000000c
+          4: 00000012 // +0000000f
+Blort.switchTest2:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: sparse-switch v2, 0016 // +0013
+  0006: const/4 v2, #int 6 // #6
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 2 // #2
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: const/4 v2, #int 3 // #3
+  000d: move v0, v2
+  000e: goto 0008 // -0006
+  000f: const/4 v2, #int 4 // #4
+  0010: move v0, v2
+  0011: goto 0008 // -0009
+  0012: const/16 v2, #int 50 // #0032
+  0014: move v0, v2
+  0015: goto 0008 // -000d
+  0016: sparse-switch-payload // for switch @ 0003
+          1: 00000009 // +00000006
+          10: 0000000c // +00000009
+          100: 0000000f // +0000000c
+          1000: 00000012 // +0000000f
diff --git a/dx/tests/045-dex-switch-ops/info.txt b/dx/tests/045-dex-switch-ops/info.txt
new file mode 100644
index 0000000..492dc0b
--- /dev/null
+++ b/dx/tests/045-dex-switch-ops/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+both kinds of switch op get converted reasonably.
+
+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/045-dex-switch-ops/run b/dx/tests/045-dex-switch-ops/run
new file mode 100644
index 0000000..8d1b65e
--- /dev/null
+++ b/dx/tests/045-dex-switch-ops/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.switchTest'*' *.class
diff --git a/dx/tests/046-dex-exceptions/Blort.java b/dx/tests/046-dex-exceptions/Blort.java
new file mode 100644
index 0000000..a0b6c0b
--- /dev/null
+++ b/dx/tests/046-dex-exceptions/Blort.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int maybeThrow(int x) {
+        if (x < 10) {
+            throw new RuntimeException();
+        }
+
+        return x;
+    }
+
+    public static int exTest1(int x) {
+        try {
+            maybeThrow(x);
+            return 1;
+        } catch (RuntimeException ex) {
+            return 2;
+        }
+    }
+
+    public static int exTest2(int x) {
+        try {
+            x++;
+            x = maybeThrow(x);
+        } catch (RuntimeException ex) {
+            return 1;
+        }
+
+        // Since the code in the try block can't possibly throw, there
+        // should not be a catch in the final result.
+        try {
+            x++;
+        } catch (RuntimeException ex) {
+            return 2;
+        }
+
+        try {
+            return maybeThrow(x);
+        } catch (RuntimeException ex) {
+            return 3;
+        }
+    }
+}
diff --git a/dx/tests/046-dex-exceptions/expected.txt b/dx/tests/046-dex-exceptions/expected.txt
new file mode 100644
index 0000000..933a547
--- /dev/null
+++ b/dx/tests/046-dex-exceptions/expected.txt
@@ -0,0 +1,48 @@
+Blort.exTest1:(I)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: invoke-static {v2}, Blort.maybeThrow:(I)I
+  0005: move-result v2
+  0006: const/4 v2, #int 1 // #1
+  0007: move v0, v2
+  0008: return v0
+  0009: move-exception v2
+  000a: move-object v1, v2
+  000b: const/4 v2, #int 2 // #2
+  000c: move v0, v2
+  000d: goto 0008 // -0005
+  catches
+    tries:
+      try 0002..0005
+      catch java.lang.RuntimeException -> 0009
+Blort.exTest2:(I)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: add-int/lit8 v0, v0, #int 1 // #01
+  0003: move v2, v0
+  0004: invoke-static {v2}, Blort.maybeThrow:(I)I
+  0007: move-result v2
+  0008: move v0, v2
+  0009: add-int/lit8 v0, v0, #int 1 // #01
+  000b: move v2, v0
+  000c: invoke-static {v2}, Blort.maybeThrow:(I)I
+  000f: move-result v2
+  0010: move v0, v2
+  0011: return v0
+  0012: move-exception v2
+  0013: move-object v1, v2
+  0014: const/4 v2, #int 1 // #1
+  0015: move v0, v2
+  0016: goto 0011 // -0005
+  0017: move-exception v2
+  0018: move-object v1, v2
+  0019: const/4 v2, #int 3 // #3
+  001a: move v0, v2
+  001b: goto 0011 // -000a
+  catches
+    tries:
+      try 0004..0007
+      catch java.lang.RuntimeException -> 0012
+      try 000c..000f
+      catch java.lang.RuntimeException -> 0017
diff --git a/dx/tests/046-dex-exceptions/info.txt b/dx/tests/046-dex-exceptions/info.txt
new file mode 100644
index 0000000..a4bc065
--- /dev/null
+++ b/dx/tests/046-dex-exceptions/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple simple cases of exception handling get converted reasonably.
+
+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/046-dex-exceptions/run b/dx/tests/046-dex-exceptions/run
new file mode 100644
index 0000000..8c821b6
--- /dev/null
+++ b/dx/tests/046-dex-exceptions/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals --dump-method=Blort.exTest'*' *.class
diff --git a/dx/tests/047-dex-wide-args/Blort.java b/dx/tests/047-dex-wide-args/Blort.java
new file mode 100644
index 0000000..fa0f1d8
--- /dev/null
+++ b/dx/tests/047-dex-wide-args/Blort.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static long test1(int w, long x, int y, long z) {
+        return w + x + y + z;
+    }
+
+    public static long test2(long w, int x, long y, int z) {
+        return w + x + y + z;
+    }
+}
diff --git a/dx/tests/047-dex-wide-args/expected.txt b/dx/tests/047-dex-wide-args/expected.txt
new file mode 100644
index 0000000..cc353fc
--- /dev/null
+++ b/dx/tests/047-dex-wide-args/expected.txt
@@ -0,0 +1,34 @@
+Blort.test1:(IJIJ)J:
+regs: 0010; ins: 0006; outs: 0000
+  0000: move v0, v10
+  0001: move-wide v1, v11
+  0002: move v3, v13
+  0003: move-wide v4, v14
+  0004: move v6, v0
+  0005: int-to-long v6, v6
+  0006: move-wide v8, v1
+  0007: add-long/2addr v6, v8
+  0008: move v8, v3
+  0009: int-to-long v8, v8
+  000a: add-long/2addr v6, v8
+  000b: move-wide v8, v4
+  000c: add-long/2addr v6, v8
+  000d: move-wide v0, v6
+  000e: return-wide v0
+Blort.test2:(JIJI)J:
+regs: 0010; ins: 0006; outs: 0000
+  0000: move-wide v0, v10
+  0001: move v2, v12
+  0002: move-wide v3, v13
+  0003: move v5, v15
+  0004: move-wide v6, v0
+  0005: move v8, v2
+  0006: int-to-long v8, v8
+  0007: add-long/2addr v6, v8
+  0008: move-wide v8, v3
+  0009: add-long/2addr v6, v8
+  000a: move v8, v5
+  000b: int-to-long v8, v8
+  000c: add-long/2addr v6, v8
+  000d: move-wide v0, v6
+  000e: return-wide v0
diff --git a/dx/tests/047-dex-wide-args/info.txt b/dx/tests/047-dex-wide-args/info.txt
new file mode 100644
index 0000000..357204d
--- /dev/null
+++ b/dx/tests/047-dex-wide-args/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+wide (category-2) arguments get treated reasonably.
+
+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/047-dex-wide-args/run b/dx/tests/047-dex-wide-args/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/047-dex-wide-args/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/048-dex-new-array/Blort.java b/dx/tests/048-dex-new-array/Blort.java
new file mode 100644
index 0000000..1af0cde
--- /dev/null
+++ b/dx/tests/048-dex-new-array/Blort.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void sink(Object x) {
+        // Do nothing.
+    }
+
+    public static void test() {
+        sink(new boolean[0]);
+        sink(new byte[1]);
+        sink(new char[2]);
+        sink(new short[3]);
+        sink(new int[4]);
+        sink(new long[5]);
+        sink(new float[6]);
+        sink(new double[7]);
+        sink(new Object[0]);
+    }
+}
diff --git a/dx/tests/048-dex-new-array/expected.txt b/dx/tests/048-dex-new-array/expected.txt
new file mode 100644
index 0000000..15332ca
--- /dev/null
+++ b/dx/tests/048-dex-new-array/expected.txt
@@ -0,0 +1,29 @@
+Blort.test:()V:
+regs: 0002; ins: 0000; outs: 0001
+  0000: const/4 v1, #int 0 // #0
+  0001: new-array v0, v1, boolean[]
+  0003: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  0006: const/4 v0, #int 1 // #1
+  0007: new-array v0, v0, byte[]
+  0009: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  000c: const/4 v0, #int 2 // #2
+  000d: new-array v0, v0, char[]
+  000f: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  0012: const/4 v0, #int 3 // #3
+  0013: new-array v0, v0, short[]
+  0015: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  0018: const/4 v0, #int 4 // #4
+  0019: new-array v0, v0, int[]
+  001b: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  001e: const/4 v0, #int 5 // #5
+  001f: new-array v0, v0, long[]
+  0021: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  0024: const/4 v0, #int 6 // #6
+  0025: new-array v0, v0, float[]
+  0027: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  002a: const/4 v0, #int 7 // #7
+  002b: new-array v0, v0, double[]
+  002d: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  0030: new-array v0, v1, java.lang.Object[]
+  0032: invoke-static {v0}, Blort.sink:(Ljava/lang/Object;)V
+  0035: return-void
diff --git a/dx/tests/048-dex-new-array/info.txt b/dx/tests/048-dex-new-array/info.txt
new file mode 100644
index 0000000..a2ff173
--- /dev/null
+++ b/dx/tests/048-dex-new-array/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+simple array construction expressions get converted reasonably.
+
+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/048-dex-new-array/run b/dx/tests/048-dex-new-array/run
new file mode 100644
index 0000000..9927f1a
--- /dev/null
+++ b/dx/tests/048-dex-new-array/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --positions=none --no-locals --dump-method=Blort.test *.class
diff --git a/dx/tests/049-dex-instanceof/Blort.java b/dx/tests/049-dex-instanceof/Blort.java
new file mode 100644
index 0000000..ad41f30
--- /dev/null
+++ b/dx/tests/049-dex-instanceof/Blort.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static boolean test(Object x) {
+        return x instanceof Blort;
+    }
+}
diff --git a/dx/tests/049-dex-instanceof/expected.txt b/dx/tests/049-dex-instanceof/expected.txt
new file mode 100644
index 0000000..77f903c
--- /dev/null
+++ b/dx/tests/049-dex-instanceof/expected.txt
@@ -0,0 +1,7 @@
+Blort.test:(Ljava/lang/Object;)Z:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: move-object v1, v0
+  0002: instance-of v1, v1, Blort
+  0004: move v0, v1
+  0005: return v0
diff --git a/dx/tests/049-dex-instanceof/info.txt b/dx/tests/049-dex-instanceof/info.txt
new file mode 100644
index 0000000..a6c82b2
--- /dev/null
+++ b/dx/tests/049-dex-instanceof/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+instanceof expressions get converted reasonably.
+
+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/049-dex-instanceof/run b/dx/tests/049-dex-instanceof/run
new file mode 100644
index 0000000..7578321
--- /dev/null
+++ b/dx/tests/049-dex-instanceof/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test *.class
diff --git a/dx/tests/050-dex-checkcast/Blort.java b/dx/tests/050-dex-checkcast/Blort.java
new file mode 100644
index 0000000..5441eec
--- /dev/null
+++ b/dx/tests/050-dex-checkcast/Blort.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static Blort test(Object x) {
+        return (Blort) x;
+    }
+}
diff --git a/dx/tests/050-dex-checkcast/expected.txt b/dx/tests/050-dex-checkcast/expected.txt
new file mode 100644
index 0000000..96f7f20
--- /dev/null
+++ b/dx/tests/050-dex-checkcast/expected.txt
@@ -0,0 +1,7 @@
+Blort.test:(Ljava/lang/Object;)LBlort;:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: move-object v1, v0
+  0002: check-cast v1, Blort
+  0004: move-object v0, v1
+  0005: return-object v0
diff --git a/dx/tests/050-dex-checkcast/info.txt b/dx/tests/050-dex-checkcast/info.txt
new file mode 100644
index 0000000..b23daa4
--- /dev/null
+++ b/dx/tests/050-dex-checkcast/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+checked cast expressions get converted reasonably.
+
+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/050-dex-checkcast/run b/dx/tests/050-dex-checkcast/run
new file mode 100644
index 0000000..7578321
--- /dev/null
+++ b/dx/tests/050-dex-checkcast/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test *.class
diff --git a/dx/tests/051-dex-explicit-null/Blort.java b/dx/tests/051-dex-explicit-null/Blort.java
new file mode 100644
index 0000000..9045c50
--- /dev/null
+++ b/dx/tests/051-dex-explicit-null/Blort.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static Object test1() {
+        return null;
+    }
+
+    public static void test2(Object x) {
+        x = null;
+    }
+}
diff --git a/dx/tests/051-dex-explicit-null/expected.txt b/dx/tests/051-dex-explicit-null/expected.txt
new file mode 100644
index 0000000..18ce092
--- /dev/null
+++ b/dx/tests/051-dex-explicit-null/expected.txt
@@ -0,0 +1,10 @@
+Blort.test1:()Ljava/lang/Object;:
+regs: 0001; ins: 0000; outs: 0000
+  0000: const/4 v0, #null // #0
+  0001: return-object v0
+Blort.test2:(Ljava/lang/Object;)V:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #null // #0
+  0002: move-object v0, v1
+  0003: return-void
diff --git a/dx/tests/051-dex-explicit-null/info.txt b/dx/tests/051-dex-explicit-null/info.txt
new file mode 100644
index 0000000..8a03dc3
--- /dev/null
+++ b/dx/tests/051-dex-explicit-null/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to see that
+assigning a reference variable to null works, as well as explicitly
+returning a null.
+
+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/051-dex-explicit-null/run b/dx/tests/051-dex-explicit-null/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/051-dex-explicit-null/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/052-dex-static-var-access/Blort.java b/dx/tests/052-dex-static-var-access/Blort.java
new file mode 100644
index 0000000..3dd0e78
--- /dev/null
+++ b/dx/tests/052-dex-static-var-access/Blort.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static boolean staticBoolean;
+    public static byte staticByte;
+    public static char staticChar;
+    public static short staticShort;
+    public static int staticInt;
+    public static long staticLong;
+    public static float staticFloat;
+    public static double staticDouble;
+    public static Object staticObject;
+
+    public static Object test1() {
+        int x = staticByte + staticChar + staticShort + staticInt +
+            (int) staticLong + (int) staticFloat + (int) staticDouble;
+
+        if (staticBoolean && (x > 0)) {;
+            return staticObject;
+        } else {
+            return null;
+        }
+    }
+
+    public static void test2(boolean b, int i, Object o) {
+        staticBoolean = b;
+        staticByte = (byte) i;
+        staticChar = (char) i;
+        staticShort = (short) i;
+        staticInt = i;
+        staticLong = i;
+        staticFloat = i;
+        staticDouble = i;
+        staticObject = o;
+    }
+}
diff --git a/dx/tests/052-dex-static-var-access/expected.txt b/dx/tests/052-dex-static-var-access/expected.txt
new file mode 100644
index 0000000..239f984
--- /dev/null
+++ b/dx/tests/052-dex-static-var-access/expected.txt
@@ -0,0 +1,59 @@
+Blort.test1:()Ljava/lang/Object;:
+regs: 0004; ins: 0000; outs: 0000
+  0000: sget-byte v1, Blort.staticByte:B
+  0002: sget-char v2, Blort.staticChar:C
+  0004: add-int/2addr v1, v2
+  0005: sget-short v2, Blort.staticShort:S
+  0007: add-int/2addr v1, v2
+  0008: sget v2, Blort.staticInt:I
+  000a: add-int/2addr v1, v2
+  000b: sget-wide v2, Blort.staticLong:J
+  000d: long-to-int v2, v2
+  000e: add-int/2addr v1, v2
+  000f: sget v2, Blort.staticFloat:F
+  0011: float-to-int v2, v2
+  0012: add-int/2addr v1, v2
+  0013: sget-wide v2, Blort.staticDouble:D
+  0015: double-to-int v2, v2
+  0016: add-int/2addr v1, v2
+  0017: move v0, v1
+  0018: sget-boolean v1, Blort.staticBoolean:Z
+  001a: if-eqz v1, 0023 // +0009
+  001c: move v1, v0
+  001d: if-lez v1, 0023 // +0006
+  001f: sget-object v1, Blort.staticObject:Ljava/lang/Object;
+  0021: move-object v0, v1
+  0022: return-object v0
+  0023: const/4 v1, #null // #0
+  0024: move-object v0, v1
+  0025: goto 0022 // -0003
+Blort.test2:(ZILjava/lang/Object;)V:
+regs: 0008; ins: 0003; outs: 0000
+  0000: move v0, v5
+  0001: move v1, v6
+  0002: move-object v2, v7
+  0003: move v3, v0
+  0004: sput-boolean v3, Blort.staticBoolean:Z
+  0006: move v3, v1
+  0007: int-to-byte v3, v3
+  0008: sput-byte v3, Blort.staticByte:B
+  000a: move v3, v1
+  000b: int-to-char v3, v3
+  000c: sput-char v3, Blort.staticChar:C
+  000e: move v3, v1
+  000f: int-to-short v3, v3
+  0010: sput-short v3, Blort.staticShort:S
+  0012: move v3, v1
+  0013: sput v3, Blort.staticInt:I
+  0015: move v3, v1
+  0016: int-to-long v3, v3
+  0017: sput-wide v3, Blort.staticLong:J
+  0019: move v3, v1
+  001a: int-to-float v3, v3
+  001b: sput v3, Blort.staticFloat:F
+  001d: move v3, v1
+  001e: int-to-double v3, v3
+  001f: sput-wide v3, Blort.staticDouble:D
+  0021: move-object v3, v2
+  0022: sput-object v3, Blort.staticObject:Ljava/lang/Object;
+  0024: return-void
diff --git a/dx/tests/052-dex-static-var-access/info.txt b/dx/tests/052-dex-static-var-access/info.txt
new file mode 100644
index 0000000..c3c3b0b
--- /dev/null
+++ b/dx/tests/052-dex-static-var-access/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+static variable access works.
+
+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/052-dex-static-var-access/run b/dx/tests/052-dex-static-var-access/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/052-dex-static-var-access/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/053-dex-instance-var-access/Blort.java b/dx/tests/053-dex-instance-var-access/Blort.java
new file mode 100644
index 0000000..eb62d62
--- /dev/null
+++ b/dx/tests/053-dex-instance-var-access/Blort.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public boolean insBoolean;
+    public byte insByte;
+    public char insChar;
+    public short insShort;
+    public int insInt;
+    public long insLong;
+    public float insFloat;
+    public double insDouble;
+    public Object insObject;
+
+    public Object test1() {
+        int x = insByte + insChar + insShort + insInt +
+            (int) insLong + (int) insFloat + (int) insDouble;
+
+        if (insBoolean && (x > 0)) {;
+            return insObject;
+        } else {
+            return null;
+        }
+    }
+
+    public void test2(boolean b, int i, Object o) {
+        insBoolean = b;
+        insByte = (byte) i;
+        insChar = (char) i;
+        insShort = (short) i;
+        insInt = i;
+        insLong = i;
+        insFloat = i;
+        insDouble = i;
+        insObject = o;
+    }
+}
diff --git a/dx/tests/053-dex-instance-var-access/expected.txt b/dx/tests/053-dex-instance-var-access/expected.txt
new file mode 100644
index 0000000..b73f617
--- /dev/null
+++ b/dx/tests/053-dex-instance-var-access/expected.txt
@@ -0,0 +1,79 @@
+Blort.test1:()Ljava/lang/Object;:
+regs: 0006; ins: 0001; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v2, v0
+  0002: iget-byte v2, v2, Blort.insByte:B
+  0004: move-object v3, v0
+  0005: iget-char v3, v3, Blort.insChar:C
+  0007: add-int/2addr v2, v3
+  0008: move-object v3, v0
+  0009: iget-short v3, v3, Blort.insShort:S
+  000b: add-int/2addr v2, v3
+  000c: move-object v3, v0
+  000d: iget v3, v3, Blort.insInt:I
+  000f: add-int/2addr v2, v3
+  0010: move-object v3, v0
+  0011: iget-wide v3, v3, Blort.insLong:J
+  0013: long-to-int v3, v3
+  0014: add-int/2addr v2, v3
+  0015: move-object v3, v0
+  0016: iget v3, v3, Blort.insFloat:F
+  0018: float-to-int v3, v3
+  0019: add-int/2addr v2, v3
+  001a: move-object v3, v0
+  001b: iget-wide v3, v3, Blort.insDouble:D
+  001d: double-to-int v3, v3
+  001e: add-int/2addr v2, v3
+  001f: move v1, v2
+  0020: move-object v2, v0
+  0021: iget-boolean v2, v2, Blort.insBoolean:Z
+  0023: if-eqz v2, 002d // +000a
+  0025: move v2, v1
+  0026: if-lez v2, 002d // +0007
+  0028: move-object v2, v0
+  0029: iget-object v2, v2, Blort.insObject:Ljava/lang/Object;
+  002b: move-object v0, v2
+  002c: return-object v0
+  002d: const/4 v2, #null // #0
+  002e: move-object v0, v2
+  002f: goto 002c // -0003
+Blort.test2:(ZILjava/lang/Object;)V:
+regs: 000b; ins: 0004; outs: 0000
+  0000: move-object v0, v7
+  0001: move v1, v8
+  0002: move v2, v9
+  0003: move-object v3, v10
+  0004: move-object v4, v0
+  0005: move v5, v1
+  0006: iput-boolean v5, v4, Blort.insBoolean:Z
+  0008: move-object v4, v0
+  0009: move v5, v2
+  000a: int-to-byte v5, v5
+  000b: iput-byte v5, v4, Blort.insByte:B
+  000d: move-object v4, v0
+  000e: move v5, v2
+  000f: int-to-char v5, v5
+  0010: iput-char v5, v4, Blort.insChar:C
+  0012: move-object v4, v0
+  0013: move v5, v2
+  0014: int-to-short v5, v5
+  0015: iput-short v5, v4, Blort.insShort:S
+  0017: move-object v4, v0
+  0018: move v5, v2
+  0019: iput v5, v4, Blort.insInt:I
+  001b: move-object v4, v0
+  001c: move v5, v2
+  001d: int-to-long v5, v5
+  001e: iput-wide v5, v4, Blort.insLong:J
+  0020: move-object v4, v0
+  0021: move v5, v2
+  0022: int-to-float v5, v5
+  0023: iput v5, v4, Blort.insFloat:F
+  0025: move-object v4, v0
+  0026: move v5, v2
+  0027: int-to-double v5, v5
+  0028: iput-wide v5, v4, Blort.insDouble:D
+  002a: move-object v4, v0
+  002b: move-object v5, v3
+  002c: iput-object v5, v4, Blort.insObject:Ljava/lang/Object;
+  002e: return-void
diff --git a/dx/tests/053-dex-instance-var-access/info.txt b/dx/tests/053-dex-instance-var-access/info.txt
new file mode 100644
index 0000000..4f95797
--- /dev/null
+++ b/dx/tests/053-dex-instance-var-access/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+instance variable access works.
+
+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/053-dex-instance-var-access/run b/dx/tests/053-dex-instance-var-access/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/053-dex-instance-var-access/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/054-dex-high16/Blort.java b/dx/tests/054-dex-high16/Blort.java
new file mode 100644
index 0000000..9fba972
--- /dev/null
+++ b/dx/tests/054-dex-high16/Blort.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void sink(int i) {
+        // Do nothing.
+    }
+
+    public static void sink(long l) {
+        // Do nothing.
+    }
+
+    public static void sink(float f) {
+        // Do nothing.
+    }
+
+    public static void sink(double d) {
+        // Do nothing.
+    }
+
+    public static void testInt() {
+        sink(Integer.MIN_VALUE);
+        sink(0x40000000);
+        sink(0x20000000);
+        sink(0x10000000);
+        sink(0x00080000);
+        sink(0x00040000);
+        sink(0x00020000);
+        sink(0x00010000);
+        sink(0x56780000);
+    }
+
+    public static void testLong() {
+        sink(Long.MIN_VALUE);
+        sink(0x4000000000000000L);
+        sink(0x2000000000000000L);
+        sink(0x1000000000000000L);
+        sink(0x0008000000000000L);
+        sink(0x0004000000000000L);
+        sink(0x0002000000000000L);
+        sink(0x0001000000000000L);
+        sink(0x5678000000000000L);
+    }
+
+    public static void testFloat() {
+        sink(Float.NEGATIVE_INFINITY);
+        sink(-0.0f);
+        sink(1.0f);
+        sink(Float.POSITIVE_INFINITY);
+        sink(Float.NaN);
+    }
+
+    public static void testDouble() {
+        sink(Double.NEGATIVE_INFINITY);
+        sink(-0.0);
+        sink(1.0);
+        sink(Double.POSITIVE_INFINITY);
+        sink(Double.NaN);
+    }
+}
diff --git a/dx/tests/054-dex-high16/expected.txt b/dx/tests/054-dex-high16/expected.txt
new file mode 100644
index 0000000..b9d6cf3
--- /dev/null
+++ b/dx/tests/054-dex-high16/expected.txt
@@ -0,0 +1,68 @@
+Blort.testDouble:()V:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const-wide/high16 v0, #double -Infinity // #fff0000000000000
+  0002: invoke-static {v0, v1}, Blort.sink:(D)V
+  0005: const-wide/high16 v0, #double -0.0 // #8000000000000000
+  0007: invoke-static {v0, v1}, Blort.sink:(D)V
+  000a: const-wide/high16 v0, #double 1.0 // #3ff0000000000000
+  000c: invoke-static {v0, v1}, Blort.sink:(D)V
+  000f: const-wide/high16 v0, #double Infinity // #7ff0000000000000
+  0011: invoke-static {v0, v1}, Blort.sink:(D)V
+  0014: const-wide/high16 v0, #double NaN // #7ff8000000000000
+  0016: invoke-static {v0, v1}, Blort.sink:(D)V
+  0019: return-void
+Blort.testFloat:()V:
+regs: 0001; ins: 0000; outs: 0001
+  0000: const/high16 v0, #float -Infinity // #ff800000
+  0002: invoke-static {v0}, Blort.sink:(F)V
+  0005: const/high16 v0, #float -0.0 // #80000000
+  0007: invoke-static {v0}, Blort.sink:(F)V
+  000a: const/high16 v0, #float 1.0 // #3f800000
+  000c: invoke-static {v0}, Blort.sink:(F)V
+  000f: const/high16 v0, #float Infinity // #7f800000
+  0011: invoke-static {v0}, Blort.sink:(F)V
+  0014: const/high16 v0, #float NaN // #7fc00000
+  0016: invoke-static {v0}, Blort.sink:(F)V
+  0019: return-void
+Blort.testInt:()V:
+regs: 0001; ins: 0000; outs: 0001
+  0000: const/high16 v0, #int -2147483648 // #80000000
+  0002: invoke-static {v0}, Blort.sink:(I)V
+  0005: const/high16 v0, #int 1073741824 // #40000000
+  0007: invoke-static {v0}, Blort.sink:(I)V
+  000a: const/high16 v0, #int 536870912 // #20000000
+  000c: invoke-static {v0}, Blort.sink:(I)V
+  000f: const/high16 v0, #int 268435456 // #10000000
+  0011: invoke-static {v0}, Blort.sink:(I)V
+  0014: const/high16 v0, #int 524288 // #00080000
+  0016: invoke-static {v0}, Blort.sink:(I)V
+  0019: const/high16 v0, #int 262144 // #00040000
+  001b: invoke-static {v0}, Blort.sink:(I)V
+  001e: const/high16 v0, #int 131072 // #00020000
+  0020: invoke-static {v0}, Blort.sink:(I)V
+  0023: const/high16 v0, #int 65536 // #00010000
+  0025: invoke-static {v0}, Blort.sink:(I)V
+  0028: const/high16 v0, #int 1450704896 // #56780000
+  002a: invoke-static {v0}, Blort.sink:(I)V
+  002d: return-void
+Blort.testLong:()V:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const-wide/high16 v0, #long -9223372036854775808 // #8000000000000000
+  0002: invoke-static {v0, v1}, Blort.sink:(J)V
+  0005: const-wide/high16 v0, #long 4611686018427387904 // #4000000000000000
+  0007: invoke-static {v0, v1}, Blort.sink:(J)V
+  000a: const-wide/high16 v0, #long 2305843009213693952 // #2000000000000000
+  000c: invoke-static {v0, v1}, Blort.sink:(J)V
+  000f: const-wide/high16 v0, #long 1152921504606846976 // #1000000000000000
+  0011: invoke-static {v0, v1}, Blort.sink:(J)V
+  0014: const-wide/high16 v0, #long 2251799813685248 // #0008000000000000
+  0016: invoke-static {v0, v1}, Blort.sink:(J)V
+  0019: const-wide/high16 v0, #long 1125899906842624 // #0004000000000000
+  001b: invoke-static {v0, v1}, Blort.sink:(J)V
+  001e: const-wide/high16 v0, #long 562949953421312 // #0002000000000000
+  0020: invoke-static {v0, v1}, Blort.sink:(J)V
+  0023: const-wide/high16 v0, #long 281474976710656 // #0001000000000000
+  0025: invoke-static {v0, v1}, Blort.sink:(J)V
+  0028: const-wide/high16 v0, #long 6230730084467081216 // #5678000000000000
+  002a: invoke-static {v0, v1}, Blort.sink:(J)V
+  002d: return-void
diff --git a/dx/tests/054-dex-high16/info.txt b/dx/tests/054-dex-high16/info.txt
new file mode 100644
index 0000000..ef1fac4
--- /dev/null
+++ b/dx/tests/054-dex-high16/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+"high16" constants get converted properly.
+
+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/054-dex-high16/run b/dx/tests/054-dex-high16/run
new file mode 100644
index 0000000..a2c7458
--- /dev/null
+++ b/dx/tests/054-dex-high16/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/055-dex-explicit-throw/Blort.java b/dx/tests/055-dex-explicit-throw/Blort.java
new file mode 100644
index 0000000..e6720d9
--- /dev/null
+++ b/dx/tests/055-dex-explicit-throw/Blort.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    private static RuntimeException theException = new RuntimeException();
+
+    public static void test1() {
+        throw theException;
+    }
+
+    public static int test2() {
+        try {
+            throw theException;
+        } catch (RuntimeException ex) {
+            return 1;
+        }
+    }
+}
diff --git a/dx/tests/055-dex-explicit-throw/expected.txt b/dx/tests/055-dex-explicit-throw/expected.txt
new file mode 100644
index 0000000..b7e4c33
--- /dev/null
+++ b/dx/tests/055-dex-explicit-throw/expected.txt
@@ -0,0 +1,17 @@
+Blort.test1:()V:
+regs: 0001; ins: 0000; outs: 0000
+  0000: sget-object v0, Blort.theException:Ljava/lang/RuntimeException;
+  0002: throw v0
+Blort.test2:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: sget-object v1, Blort.theException:Ljava/lang/RuntimeException;
+  0002: throw v1
+  0003: move-exception v1
+  0004: move-object v0, v1
+  0005: const/4 v1, #int 1 // #1
+  0006: move v0, v1
+  0007: return v0
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 0003
diff --git a/dx/tests/055-dex-explicit-throw/info.txt b/dx/tests/055-dex-explicit-throw/info.txt
new file mode 100644
index 0000000..b3b7808
--- /dev/null
+++ b/dx/tests/055-dex-explicit-throw/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+explicit use of "throw" gets converted reasonably.
+
+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/055-dex-explicit-throw/run b/dx/tests/055-dex-explicit-throw/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/055-dex-explicit-throw/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/056-dex-call-interface/Blort.java b/dx/tests/056-dex-call-interface/Blort.java
new file mode 100644
index 0000000..4175f05
--- /dev/null
+++ b/dx/tests/056-dex-call-interface/Blort.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int test(Zorch z, double d) {
+        z.zorch1();
+        z.zorch2(d);
+        int x = z.zorch3(z);
+        int y = (int) z.zorch4();
+        return x + y;
+    }
+}
diff --git a/dx/tests/056-dex-call-interface/Zorch.java b/dx/tests/056-dex-call-interface/Zorch.java
new file mode 100644
index 0000000..03e3762
--- /dev/null
+++ b/dx/tests/056-dex-call-interface/Zorch.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+public interface Zorch
+{
+    public void zorch1();
+    public void zorch2(double d);
+    public int zorch3(Object o);
+    public long zorch4();
+}
diff --git a/dx/tests/056-dex-call-interface/expected.txt b/dx/tests/056-dex-call-interface/expected.txt
new file mode 100644
index 0000000..faf18c4
--- /dev/null
+++ b/dx/tests/056-dex-call-interface/expected.txt
@@ -0,0 +1,24 @@
+Blort.test:(LZorch;D)I:
+regs: 000b; ins: 0003; outs: 0003
+  0000: move-object v0, v8
+  0001: move-wide v1, v9
+  0002: move-object v5, v0
+  0003: invoke-interface {v5}, Zorch.zorch1:()V
+  0006: move-object v5, v0
+  0007: move-wide v6, v1
+  0008: invoke-interface {v5, v6, v7}, Zorch.zorch2:(D)V
+  000b: move-object v5, v0
+  000c: move-object v6, v0
+  000d: invoke-interface {v5, v6}, Zorch.zorch3:(Ljava/lang/Object;)I
+  0010: move-result v5
+  0011: move v3, v5
+  0012: move-object v5, v0
+  0013: invoke-interface {v5}, Zorch.zorch4:()J
+  0016: move-result-wide v5
+  0017: long-to-int v5, v5
+  0018: move v4, v5
+  0019: move v5, v3
+  001a: move v6, v4
+  001b: add-int/2addr v5, v6
+  001c: move v0, v5
+  001d: return v0
diff --git a/dx/tests/056-dex-call-interface/info.txt b/dx/tests/056-dex-call-interface/info.txt
new file mode 100644
index 0000000..2f964a2
--- /dev/null
+++ b/dx/tests/056-dex-call-interface/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of interface method invocation work properly.
+
+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/056-dex-call-interface/run b/dx/tests/056-dex-call-interface/run
new file mode 100644
index 0000000..1076ae1
--- /dev/null
+++ b/dx/tests/056-dex-call-interface/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test Blort.class
diff --git a/dx/tests/057-dex-call-virtual/Blort.java b/dx/tests/057-dex-call-virtual/Blort.java
new file mode 100644
index 0000000..75ee7d8
--- /dev/null
+++ b/dx/tests/057-dex-call-virtual/Blort.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int test(Zorch z) {
+        z.zorch1();
+        return z.zorch2(5);
+    }
+}
diff --git a/dx/tests/057-dex-call-virtual/Zorch.java b/dx/tests/057-dex-call-virtual/Zorch.java
new file mode 100644
index 0000000..867eaed
--- /dev/null
+++ b/dx/tests/057-dex-call-virtual/Zorch.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class Zorch
+{
+    public void zorch1() {
+        // This space intentionally left blank.
+    }
+
+    public int zorch2(int x) {
+        return 0;
+    }
+}
diff --git a/dx/tests/057-dex-call-virtual/expected.txt b/dx/tests/057-dex-call-virtual/expected.txt
new file mode 100644
index 0000000..ea50d35
--- /dev/null
+++ b/dx/tests/057-dex-call-virtual/expected.txt
@@ -0,0 +1,11 @@
+Blort.test:(LZorch;)I:
+regs: 0004; ins: 0001; outs: 0002
+  0000: move-object v0, v3
+  0001: move-object v1, v0
+  0002: invoke-virtual {v1}, Zorch.zorch1:()V
+  0005: move-object v1, v0
+  0006: const/4 v2, #int 5 // #5
+  0007: invoke-virtual {v1, v2}, Zorch.zorch2:(I)I
+  000a: move-result v1
+  000b: move v0, v1
+  000c: return v0
diff --git a/dx/tests/057-dex-call-virtual/info.txt b/dx/tests/057-dex-call-virtual/info.txt
new file mode 100644
index 0000000..452c9cb
--- /dev/null
+++ b/dx/tests/057-dex-call-virtual/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of regular virtual method invocation work properly.
+
+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/057-dex-call-virtual/run b/dx/tests/057-dex-call-virtual/run
new file mode 100644
index 0000000..1076ae1
--- /dev/null
+++ b/dx/tests/057-dex-call-virtual/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test Blort.class
diff --git a/dx/tests/058-dex-call-direct/Blort.java b/dx/tests/058-dex-call-direct/Blort.java
new file mode 100644
index 0000000..6d7fa7f
--- /dev/null
+++ b/dx/tests/058-dex-call-direct/Blort.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int test(Blort b) {
+        b.zorch1();
+        return b.zorch2(5);
+    }
+
+    private void zorch1() {
+        // This space intentionally left blank.
+    }
+
+    private int zorch2(int x) {
+        return 1;
+    }
+}
diff --git a/dx/tests/058-dex-call-direct/expected.txt b/dx/tests/058-dex-call-direct/expected.txt
new file mode 100644
index 0000000..11820a3
--- /dev/null
+++ b/dx/tests/058-dex-call-direct/expected.txt
@@ -0,0 +1,11 @@
+Blort.test:(LBlort;)I:
+regs: 0004; ins: 0001; outs: 0002
+  0000: move-object v0, v3
+  0001: move-object v1, v0
+  0002: invoke-direct {v1}, Blort.zorch1:()V
+  0005: move-object v1, v0
+  0006: const/4 v2, #int 5 // #5
+  0007: invoke-direct {v1, v2}, Blort.zorch2:(I)I
+  000a: move-result v1
+  000b: move v0, v1
+  000c: return v0
diff --git a/dx/tests/058-dex-call-direct/info.txt b/dx/tests/058-dex-call-direct/info.txt
new file mode 100644
index 0000000..a22c479
--- /dev/null
+++ b/dx/tests/058-dex-call-direct/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of direct instance method invocation work properly.
+
+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/058-dex-call-direct/run b/dx/tests/058-dex-call-direct/run
new file mode 100644
index 0000000..1076ae1
--- /dev/null
+++ b/dx/tests/058-dex-call-direct/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test Blort.class
diff --git a/dx/tests/059-dex-call-super/Blort.java b/dx/tests/059-dex-call-super/Blort.java
new file mode 100644
index 0000000..efb451e
--- /dev/null
+++ b/dx/tests/059-dex-call-super/Blort.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+public class Blort
+    extends Zorch
+{
+    public int test1() {
+        super.zorch1();
+        return super.zorch2(5);
+    }
+
+    public void test2() {
+        super.test2();
+    }
+}
diff --git a/dx/tests/059-dex-call-super/Zorch.java b/dx/tests/059-dex-call-super/Zorch.java
new file mode 100644
index 0000000..aa668ab
--- /dev/null
+++ b/dx/tests/059-dex-call-super/Zorch.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+public class Zorch
+{
+    public void zorch1() {
+        // This space intentionally left blank.
+    }
+
+    public int zorch2(int x) {
+        return 0;
+    }
+
+    public void test2() {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dx/tests/059-dex-call-super/expected.txt b/dx/tests/059-dex-call-super/expected.txt
new file mode 100644
index 0000000..8bb3bde
--- /dev/null
+++ b/dx/tests/059-dex-call-super/expected.txt
@@ -0,0 +1,17 @@
+Blort.test1:()I:
+regs: 0004; ins: 0001; outs: 0002
+  0000: move-object v0, v3
+  0001: move-object v1, v0
+  0002: invoke-super {v1}, Zorch.zorch1:()V
+  0005: move-object v1, v0
+  0006: const/4 v2, #int 5 // #5
+  0007: invoke-super {v1, v2}, Zorch.zorch2:(I)I
+  000a: move-result v1
+  000b: move v0, v1
+  000c: return v0
+Blort.test2:()V:
+regs: 0003; ins: 0001; outs: 0001
+  0000: move-object v0, v2
+  0001: move-object v1, v0
+  0002: invoke-super {v1}, Zorch.test2:()V
+  0005: return-void
diff --git a/dx/tests/059-dex-call-super/info.txt b/dx/tests/059-dex-call-super/info.txt
new file mode 100644
index 0000000..ff88814
--- /dev/null
+++ b/dx/tests/059-dex-call-super/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of superclass virtual method invocation work properly.
+
+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/059-dex-call-super/run b/dx/tests/059-dex-call-super/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/059-dex-call-super/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/060-dex-call-static/Blort.java b/dx/tests/060-dex-call-static/Blort.java
new file mode 100644
index 0000000..8ad2e27
--- /dev/null
+++ b/dx/tests/060-dex-call-static/Blort.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int test() {
+        Zorch.zorch1();
+        return Zorch.zorch2(5);
+    }
+}
diff --git a/dx/tests/060-dex-call-static/Zorch.java b/dx/tests/060-dex-call-static/Zorch.java
new file mode 100644
index 0000000..8ccc448
--- /dev/null
+++ b/dx/tests/060-dex-call-static/Zorch.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class Zorch
+{
+    public static void zorch1() {
+        // This space intentionally left blank.
+    }
+
+    public static int zorch2(int x) {
+        return 1;
+    }
+}
diff --git a/dx/tests/060-dex-call-static/expected.txt b/dx/tests/060-dex-call-static/expected.txt
new file mode 100644
index 0000000..9432989
--- /dev/null
+++ b/dx/tests/060-dex-call-static/expected.txt
@@ -0,0 +1,7 @@
+Blort.test:()I:
+regs: 0001; ins: 0000; outs: 0001
+  0000: invoke-static {}, Zorch.zorch1:()V
+  0003: const/4 v0, #int 5 // #5
+  0004: invoke-static {v0}, Zorch.zorch2:(I)I
+  0007: move-result v0
+  0008: return v0
diff --git a/dx/tests/060-dex-call-static/info.txt b/dx/tests/060-dex-call-static/info.txt
new file mode 100644
index 0000000..1253355
--- /dev/null
+++ b/dx/tests/060-dex-call-static/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of static method invocation work properly.
+
+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/060-dex-call-static/run b/dx/tests/060-dex-call-static/run
new file mode 100644
index 0000000..346856c
--- /dev/null
+++ b/dx/tests/060-dex-call-static/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --positions=none --no-locals \
+    --dump-method=Blort.test Blort.class
diff --git a/dx/tests/061-dex-try-catch/Blort.java b/dx/tests/061-dex-try-catch/Blort.java
new file mode 100644
index 0000000..903f40e
--- /dev/null
+++ b/dx/tests/061-dex-try-catch/Blort.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void caught() {
+        // This space intentionally left blank.
+    }
+
+    public static void zorch(int x) {
+        // This space intentionally left blank.
+    }
+
+    public static void test1(int x) {
+        // In this test, the code being try-caught can't possibly throw.
+        try {
+            x = 0;
+        } catch (RuntimeException ex) {
+            caught();
+        }
+    }
+
+    public static void test2(String[] sa) {
+        // In this test, the code being try-caught doesn't contain any
+        // constant pool references.
+        try {
+            int x = sa.length;
+        } catch (RuntimeException ex) {
+            caught();
+        }
+    }
+
+    public static void test3() {
+        // In this test, the code being try-caught contains a constant
+        // pool reference.
+        try {
+            zorch(1);
+        } catch (RuntimeException ex) {
+            caught();
+        }
+    }
+
+    public static void test4(String[] sa) {
+        // In this test, the code being try-caught contains one
+        // throwing instruction that has a constant pool reference and
+        // one that doesn't.
+        try {
+            zorch(sa.length);
+        } catch (RuntimeException ex) {
+            caught();
+        }
+    }
+}
diff --git a/dx/tests/061-dex-try-catch/expected.txt b/dx/tests/061-dex-try-catch/expected.txt
new file mode 100644
index 0000000..d66f404
--- /dev/null
+++ b/dx/tests/061-dex-try-catch/expected.txt
@@ -0,0 +1,49 @@
+Blort.test1:(I)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: const/4 v2, #int 0 // #0
+  0002: move v0, v2
+  0003: return-void
+Blort.test2:([Ljava/lang/String;)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move-object v0, v3
+  0001: move-object v2, v0
+  0002: array-length v2, v2
+  0003: move v1, v2
+  0004: return-void
+  0005: move-exception v2
+  0006: move-object v1, v2
+  0007: invoke-static {}, Blort.caught:()V
+  000a: goto 0004 // -0006
+  catches
+    tries:
+      try 0002..0003
+      catch java.lang.RuntimeException -> 0005
+Blort.test3:()V:
+regs: 0002; ins: 0000; outs: 0001
+  0000: const/4 v1, #int 1 // #1
+  0001: invoke-static {v1}, Blort.zorch:(I)V
+  0004: return-void
+  0005: move-exception v1
+  0006: move-object v0, v1
+  0007: invoke-static {}, Blort.caught:()V
+  000a: goto 0004 // -0006
+  catches
+    tries:
+      try 0001..0004
+      catch java.lang.RuntimeException -> 0005
+Blort.test4:([Ljava/lang/String;)V:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move-object v0, v3
+  0001: move-object v2, v0
+  0002: array-length v2, v2
+  0003: invoke-static {v2}, Blort.zorch:(I)V
+  0006: return-void
+  0007: move-exception v2
+  0008: move-object v1, v2
+  0009: invoke-static {}, Blort.caught:()V
+  000c: goto 0006 // -0006
+  catches
+    tries:
+      try 0002..0006
+      catch java.lang.RuntimeException -> 0007
diff --git a/dx/tests/061-dex-try-catch/info.txt b/dx/tests/061-dex-try-catch/info.txt
new file mode 100644
index 0000000..409b251
--- /dev/null
+++ b/dx/tests/061-dex-try-catch/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of try-catch work properly.
+
+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/061-dex-try-catch/run b/dx/tests/061-dex-try-catch/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/061-dex-try-catch/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/062-dex-synch-method/Blort.java b/dx/tests/062-dex-synch-method/Blort.java
new file mode 100644
index 0000000..4aca417
--- /dev/null
+++ b/dx/tests/062-dex-synch-method/Blort.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public synchronized void testInstance1() {
+        // This space intentionally left blank.
+    }
+
+    public synchronized void testInstance2(Object x) {
+        x.hashCode();
+    }
+
+    public synchronized int testInstance3(int x, int y, int z) {
+        if (x == 1) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public synchronized long testInstance4(long x) {
+        if (x == 1) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public synchronized void testInstance5() {
+        testInstance5();
+    }
+
+    public static synchronized void testStatic1() {
+        // This space intentionally left blank.
+    }
+
+    public static synchronized void testStatic2(Object x) {
+        x.hashCode();
+    }
+
+    public static synchronized int testStatic3(int x, int y, int z) {
+        if (x == 1) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static synchronized long testStatic4(long x) {
+        if (x == 1) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static synchronized void testStatic5() {
+        testStatic5();
+    }
+}
diff --git a/dx/tests/062-dex-synch-method/expected.txt b/dx/tests/062-dex-synch-method/expected.txt
new file mode 100644
index 0000000..5585038
--- /dev/null
+++ b/dx/tests/062-dex-synch-method/expected.txt
@@ -0,0 +1,146 @@
+Blort.testInstance1:()V:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: move-object v1, v2
+  0002: monitor-enter v1
+  0003: monitor-exit v1
+  0004: return-void
+Blort.testInstance2:(Ljava/lang/Object;)V:
+regs: 0006; ins: 0002; outs: 0001
+  0000: move-object v0, v4
+  0001: move-object v1, v5
+  0002: move-object v3, v4
+  0003: monitor-enter v3
+  0004: move-object v2, v1
+  0005: invoke-virtual {v2}, java.lang.Object.hashCode:()I
+  0008: move-result v2
+  0009: monitor-exit v3
+  000a: return-void
+  000b: move-exception v0
+  000c: monitor-exit v3
+  000d: throw v0
+  catches
+    tries:
+      try 0005..0008
+      catch <any> -> 000b
+Blort.testInstance3:(III)I:
+regs: 000b; ins: 0004; outs: 0000
+  0000: move-object v0, v7
+  0001: move v1, v8
+  0002: move v2, v9
+  0003: move v3, v10
+  0004: move-object v6, v7
+  0005: monitor-enter v6
+  0006: move v4, v1
+  0007: const/4 v5, #int 1 // #1
+  0008: if-ne v4, v5, 000e // +0006
+  000a: const/4 v4, #int 1 // #1
+  000b: move v0, v4
+  000c: monitor-exit v6
+  000d: return v0
+  000e: const/4 v4, #int 2 // #2
+  000f: move v0, v4
+  0010: goto 000c // -0004
+Blort.testInstance4:(J)J:
+regs: 000b; ins: 0003; outs: 0000
+  0000: move-object v0, v8
+  0001: move-wide v1, v9
+  0002: move-object v7, v8
+  0003: monitor-enter v7
+  0004: move-wide v3, v1
+  0005: const-wide/16 v5, #long 1 // #0001
+  0007: cmp-long v3, v3, v5
+  0009: if-nez v3, 0010 // +0007
+  000b: const-wide/16 v3, #long 1 // #0001
+  000d: move-wide v0, v3
+  000e: monitor-exit v7
+  000f: return-wide v0
+  0010: const-wide/16 v3, #long 2 // #0002
+  0012: move-wide v0, v3
+  0013: goto 000e // -0005
+Blort.testInstance5:()V:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move-object v0, v3
+  0001: move-object v2, v3
+  0002: monitor-enter v2
+  0003: move-object v1, v0
+  0004: invoke-virtual {v1}, Blort.testInstance5:()V
+  0007: monitor-exit v2
+  0008: return-void
+  0009: move-exception v0
+  000a: monitor-exit v2
+  000b: throw v0
+  catches
+    tries:
+      try 0004..0007
+      catch <any> -> 0009
+Blort.testStatic1:()V:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const-class v1, Blort
+  0002: monitor-enter v1
+  0003: monitor-exit v1
+  0004: return-void
+Blort.testStatic2:(Ljava/lang/Object;)V:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move-object v0, v3
+  0001: const-class v2, Blort
+  0003: monitor-enter v2
+  0004: move-object v1, v0
+  0005: invoke-virtual {v1}, java.lang.Object.hashCode:()I
+  0008: move-result v1
+  0009: monitor-exit v2
+  000a: return-void
+  000b: move-exception v0
+  000c: monitor-exit v2
+  000d: throw v0
+  catches
+    tries:
+      try 0005..0008
+      catch <any> -> 000b
+Blort.testStatic3:(III)I:
+regs: 0009; ins: 0003; outs: 0000
+  0000: move v0, v6
+  0001: move v1, v7
+  0002: move v2, v8
+  0003: const-class v5, Blort
+  0005: monitor-enter v5
+  0006: move v3, v0
+  0007: const/4 v4, #int 1 // #1
+  0008: if-ne v3, v4, 000e // +0006
+  000a: const/4 v3, #int 1 // #1
+  000b: move v0, v3
+  000c: monitor-exit v5
+  000d: return v0
+  000e: const/4 v3, #int 2 // #2
+  000f: move v0, v3
+  0010: goto 000c // -0004
+Blort.testStatic4:(J)J:
+regs: 0009; ins: 0002; outs: 0000
+  0000: move-wide v0, v7
+  0001: const-class v6, Blort
+  0003: monitor-enter v6
+  0004: move-wide v2, v0
+  0005: const-wide/16 v4, #long 1 // #0001
+  0007: cmp-long v2, v2, v4
+  0009: if-nez v2, 0010 // +0007
+  000b: const-wide/16 v2, #long 1 // #0001
+  000d: move-wide v0, v2
+  000e: monitor-exit v6
+  000f: return-wide v0
+  0010: const-wide/16 v2, #long 2 // #0002
+  0012: move-wide v0, v2
+  0013: goto 000e // -0005
+Blort.testStatic5:()V:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const-class v1, Blort
+  0002: monitor-enter v1
+  0003: invoke-static {}, Blort.testStatic5:()V
+  0006: monitor-exit v1
+  0007: return-void
+  0008: move-exception v0
+  0009: monitor-exit v1
+  000a: throw v0
+  catches
+    tries:
+      try 0003..0006
+      catch <any> -> 0008
diff --git a/dx/tests/062-dex-synch-method/info.txt b/dx/tests/062-dex-synch-method/info.txt
new file mode 100644
index 0000000..0e82727
--- /dev/null
+++ b/dx/tests/062-dex-synch-method/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of synchronized methods get converted reasonably.
+
+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/062-dex-synch-method/run b/dx/tests/062-dex-synch-method/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/062-dex-synch-method/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/063-dex-empty-switch/Blort.java b/dx/tests/063-dex-empty-switch/Blort.java
new file mode 100644
index 0000000..f538995
--- /dev/null
+++ b/dx/tests/063-dex-empty-switch/Blort.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public int test1(int x) {
+        switch (x) {
+            default: return 1;
+        }
+    }
+
+    public int test2(int x) {
+        switch (x) {
+            default: x = 1;
+        }
+
+        return x;
+    }
+}
diff --git a/dx/tests/063-dex-empty-switch/expected.txt b/dx/tests/063-dex-empty-switch/expected.txt
new file mode 100644
index 0000000..e4d1a46
--- /dev/null
+++ b/dx/tests/063-dex-empty-switch/expected.txt
@@ -0,0 +1,18 @@
+Blort.test1:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: const/4 v2, #int 1 // #1
+  0004: move v0, v2
+  0005: return v0
+Blort.test2:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: const/4 v2, #int 1 // #1
+  0004: move v1, v2
+  0005: move v2, v1
+  0006: move v0, v2
+  0007: return v0
diff --git a/dx/tests/063-dex-empty-switch/info.txt b/dx/tests/063-dex-empty-switch/info.txt
new file mode 100644
index 0000000..38f212b
--- /dev/null
+++ b/dx/tests/063-dex-empty-switch/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to see that
+a couple cases of empty (that is, default-only) switch statements
+get converted reasonably.
+
+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/063-dex-empty-switch/run b/dx/tests/063-dex-empty-switch/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/063-dex-empty-switch/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/064-dex-array-access/Blort.java b/dx/tests/064-dex-array-access/Blort.java
new file mode 100644
index 0000000..fa03ec0
--- /dev/null
+++ b/dx/tests/064-dex-array-access/Blort.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public boolean test01(boolean[] x) {
+        x[0] = true;
+        return x[1];
+    }
+
+    public byte test02(byte[] x) {
+        x[0] = 5;
+        return x[1];
+    }
+
+    public short test03(short[] x) {
+        x[0] = 5;
+        return x[1];
+    }
+
+    public char test04(char[] x) {
+        x[0] = 5;
+        return x[1];
+    }
+
+    public int test05(int[] x) {
+        x[0] = 5;
+        return x[1];
+    }
+
+    public long test06(long[] x) {
+        x[0] = 5;
+        return x[1];
+    }
+
+    public float test07(float[] x) {
+        x[0] = 2.0f;
+        return x[1];
+    }
+
+    public double test08(double[] x) {
+        x[0] = 2.0;
+        return x[1];
+    }
+
+    public Object test09(Object[] x) {
+        x[0] = null;
+        return x[1];
+    }
+
+    public static Object test10(Object[][] x) {
+        x[0][0] = null;
+        return x[1][2];
+    }
+
+    public static int test11(Object x) {
+        int[][][] arr = (int[][][]) x;
+        arr[0][0][0] = 123;
+        return arr[1][2][3];
+    }
+}
diff --git a/dx/tests/064-dex-array-access/expected.txt b/dx/tests/064-dex-array-access/expected.txt
new file mode 100644
index 0000000..ae251e7
--- /dev/null
+++ b/dx/tests/064-dex-array-access/expected.txt
@@ -0,0 +1,157 @@
+Blort.test01:([Z)Z:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/4 v4, #int 1 // #1
+  0005: aput-boolean v4, v2, v3
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 1 // #1
+  0009: aget-boolean v2, v2, v3
+  000b: move v0, v2
+  000c: return v0
+Blort.test02:([B)B:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/4 v4, #int 5 // #5
+  0005: aput-byte v4, v2, v3
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 1 // #1
+  0009: aget-byte v2, v2, v3
+  000b: move v0, v2
+  000c: return v0
+Blort.test03:([S)S:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/4 v4, #int 5 // #5
+  0005: aput-short v4, v2, v3
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 1 // #1
+  0009: aget-short v2, v2, v3
+  000b: move v0, v2
+  000c: return v0
+Blort.test04:([C)C:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/4 v4, #int 5 // #5
+  0005: aput-char v4, v2, v3
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 1 // #1
+  0009: aget-char v2, v2, v3
+  000b: move v0, v2
+  000c: return v0
+Blort.test05:([I)I:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/4 v4, #int 5 // #5
+  0005: aput v4, v2, v3
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 1 // #1
+  0009: aget v2, v2, v3
+  000b: move v0, v2
+  000c: return v0
+Blort.test06:([J)J:
+regs: 0008; ins: 0002; outs: 0000
+  0000: move-object v0, v6
+  0001: move-object v1, v7
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const-wide/16 v4, #long 5 // #0005
+  0006: aput-wide v4, v2, v3
+  0008: move-object v2, v1
+  0009: const/4 v3, #int 1 // #1
+  000a: aget-wide v2, v2, v3
+  000c: move-wide v0, v2
+  000d: return-wide v0
+Blort.test07:([F)F:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/high16 v4, #float 2.0 // #40000000
+  0006: aput v4, v2, v3
+  0008: move-object v2, v1
+  0009: const/4 v3, #int 1 // #1
+  000a: aget v2, v2, v3
+  000c: move v0, v2
+  000d: return v0
+Blort.test08:([D)D:
+regs: 0008; ins: 0002; outs: 0000
+  0000: move-object v0, v6
+  0001: move-object v1, v7
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const-wide/high16 v4, #double 2.0 // #4000000000000000
+  0006: aput-wide v4, v2, v3
+  0008: move-object v2, v1
+  0009: const/4 v3, #int 1 // #1
+  000a: aget-wide v2, v2, v3
+  000c: move-wide v0, v2
+  000d: return-wide v0
+Blort.test09:([Ljava/lang/Object;)Ljava/lang/Object;:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v1, v6
+  0002: move-object v2, v1
+  0003: const/4 v3, #int 0 // #0
+  0004: const/4 v4, #null // #0
+  0005: aput-object v4, v2, v3
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 1 // #1
+  0009: aget-object v2, v2, v3
+  000b: move-object v0, v2
+  000c: return-object v0
+Blort.test10:([[Ljava/lang/Object;)Ljava/lang/Object;:
+regs: 0005; ins: 0001; outs: 0000
+  0000: move-object v0, v4
+  0001: move-object v1, v0
+  0002: const/4 v2, #int 0 // #0
+  0003: aget-object v1, v1, v2
+  0005: const/4 v2, #int 0 // #0
+  0006: const/4 v3, #null // #0
+  0007: aput-object v3, v1, v2
+  0009: move-object v1, v0
+  000a: const/4 v2, #int 1 // #1
+  000b: aget-object v1, v1, v2
+  000d: const/4 v2, #int 2 // #2
+  000e: aget-object v1, v1, v2
+  0010: move-object v0, v1
+  0011: return-object v0
+Blort.test11:(Ljava/lang/Object;)I:
+regs: 0006; ins: 0001; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v2, v0
+  0002: check-cast v2, int[][][]
+  0004: check-cast v2, int[][][]
+  0006: move-object v1, v2
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 0 // #0
+  0009: aget-object v2, v2, v3
+  000b: const/4 v3, #int 0 // #0
+  000c: aget-object v2, v2, v3
+  000e: const/4 v3, #int 0 // #0
+  000f: const/16 v4, #int 123 // #007b
+  0011: aput v4, v2, v3
+  0013: move-object v2, v1
+  0014: const/4 v3, #int 1 // #1
+  0015: aget-object v2, v2, v3
+  0017: const/4 v3, #int 2 // #2
+  0018: aget-object v2, v2, v3
+  001a: const/4 v3, #int 3 // #3
+  001b: aget v2, v2, v3
+  001d: move v0, v2
+  001e: return v0
diff --git a/dx/tests/064-dex-array-access/info.txt b/dx/tests/064-dex-array-access/info.txt
new file mode 100644
index 0000000..8f81663
--- /dev/null
+++ b/dx/tests/064-dex-array-access/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a few cases of array access get converted reasonably.
+
+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/064-dex-array-access/run b/dx/tests/064-dex-array-access/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/064-dex-array-access/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/065-dex-new-array/Blort.java b/dx/tests/065-dex-new-array/Blort.java
new file mode 100644
index 0000000..7a7eaa4
--- /dev/null
+++ b/dx/tests/065-dex-new-array/Blort.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public boolean[] test1() {
+        return new boolean[1];
+    }
+
+    public byte[] test2() {
+        return new byte[1];
+    }
+
+    public short[] test3() {
+        return new short[1];
+    }
+
+    public char[] test4() {
+        return new char[1];
+    }
+
+    public int[] test5() {
+        return new int[1];
+    }
+
+    public long[] test6() {
+        return new long[1];
+    }
+
+    public float[] test7() {
+        return new float[1];
+    }
+
+    public double[] test8() {
+        return new double[1];
+    }
+
+    public Object[] test9() {
+        return new Object[1];
+    }
+}
diff --git a/dx/tests/065-dex-new-array/expected.txt b/dx/tests/065-dex-new-array/expected.txt
new file mode 100644
index 0000000..0b26182
--- /dev/null
+++ b/dx/tests/065-dex-new-array/expected.txt
@@ -0,0 +1,63 @@
+Blort.test1:()[Z:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, boolean[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test2:()[B:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, byte[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test3:()[S:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, short[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test4:()[C:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, char[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test5:()[I:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, int[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test6:()[J:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, long[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test7:()[F:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, float[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test8:()[D:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, double[]
+  0004: move-object v0, v1
+  0005: return-object v0
+Blort.test9:()[Ljava/lang/Object;:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: const/4 v1, #int 1 // #1
+  0002: new-array v1, v1, java.lang.Object[]
+  0004: move-object v0, v1
+  0005: return-object v0
diff --git a/dx/tests/065-dex-new-array/info.txt b/dx/tests/065-dex-new-array/info.txt
new file mode 100644
index 0000000..f4d2cc5
--- /dev/null
+++ b/dx/tests/065-dex-new-array/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a few cases of array construction get converted reasonably.
+
+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/065-dex-new-array/run b/dx/tests/065-dex-new-array/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/065-dex-new-array/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/066-dex-try-catch-rethrow/Blort.java b/dx/tests/066-dex-try-catch-rethrow/Blort.java
new file mode 100644
index 0000000..cdb00ea
--- /dev/null
+++ b/dx/tests/066-dex-try-catch-rethrow/Blort.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static Object zorch1(String s) {
+        return null;
+    }
+
+    public static void test1() {
+        try {
+            zorch1("x");
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static void zorch2(String s) {
+        // This space intentionally left blank.
+    }
+
+    public static void test2() {
+        try {
+            zorch2("x");
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static int zorch3(String s) {
+        return 0;
+    }
+
+    public static void test3() {
+        try {
+            zorch3("x");
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static Object zorch4(int x) {
+        return null;
+    }
+
+    public static void test4() {
+        try {
+            zorch4(1);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static Object zorch5(int x) {
+        return null;
+    }
+
+    public static Object test5() {
+        try {
+            return zorch5(1);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/dx/tests/066-dex-try-catch-rethrow/expected.txt b/dx/tests/066-dex-try-catch-rethrow/expected.txt
new file mode 100644
index 0000000..13af56c
--- /dev/null
+++ b/dx/tests/066-dex-try-catch-rethrow/expected.txt
@@ -0,0 +1,95 @@
+Blort.test1:()V:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const-string v1, "x"
+  0002: invoke-static {v1}, Blort.zorch1:(Ljava/lang/String;)Ljava/lang/Object;
+  0005: move-result-object v1
+  0006: return-void
+  0007: move-exception v1
+  0008: move-object v0, v1
+  0009: new-instance v1, java.lang.RuntimeException
+  000b: move-object v4, v1
+  000c: move-object v1, v4
+  000d: move-object v2, v4
+  000e: move-object v3, v0
+  000f: invoke-direct {v2, v3}, java.lang.RuntimeException.<init>:(Ljava/lang/Throwable;)V
+  0012: throw v1
+  catches
+    tries:
+      try 0000..0005
+      catch java.lang.Exception -> 0007
+Blort.test2:()V:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const-string v1, "x"
+  0002: invoke-static {v1}, Blort.zorch2:(Ljava/lang/String;)V
+  0005: return-void
+  0006: move-exception v1
+  0007: move-object v0, v1
+  0008: new-instance v1, java.lang.RuntimeException
+  000a: move-object v4, v1
+  000b: move-object v1, v4
+  000c: move-object v2, v4
+  000d: move-object v3, v0
+  000e: invoke-direct {v2, v3}, java.lang.RuntimeException.<init>:(Ljava/lang/Throwable;)V
+  0011: throw v1
+  catches
+    tries:
+      try 0000..0005
+      catch java.lang.Exception -> 0006
+Blort.test3:()V:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const-string v1, "x"
+  0002: invoke-static {v1}, Blort.zorch3:(Ljava/lang/String;)I
+  0005: move-result v1
+  0006: return-void
+  0007: move-exception v1
+  0008: move-object v0, v1
+  0009: new-instance v1, java.lang.RuntimeException
+  000b: move-object v4, v1
+  000c: move-object v1, v4
+  000d: move-object v2, v4
+  000e: move-object v3, v0
+  000f: invoke-direct {v2, v3}, java.lang.RuntimeException.<init>:(Ljava/lang/Throwable;)V
+  0012: throw v1
+  catches
+    tries:
+      try 0000..0005
+      catch java.lang.Exception -> 0007
+Blort.test4:()V:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 1 // #1
+  0001: invoke-static {v1}, Blort.zorch4:(I)Ljava/lang/Object;
+  0004: move-result-object v1
+  0005: return-void
+  0006: move-exception v1
+  0007: move-object v0, v1
+  0008: new-instance v1, java.lang.RuntimeException
+  000a: move-object v4, v1
+  000b: move-object v1, v4
+  000c: move-object v2, v4
+  000d: move-object v3, v0
+  000e: invoke-direct {v2, v3}, java.lang.RuntimeException.<init>:(Ljava/lang/Throwable;)V
+  0011: throw v1
+  catches
+    tries:
+      try 0001..0004
+      catch java.lang.Exception -> 0006
+Blort.test5:()Ljava/lang/Object;:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 1 // #1
+  0001: invoke-static {v1}, Blort.zorch5:(I)Ljava/lang/Object;
+  0004: move-result-object v1
+  0005: move-object v0, v1
+  0006: return-object v0
+  0007: move-exception v1
+  0008: move-object v0, v1
+  0009: new-instance v1, java.lang.RuntimeException
+  000b: move-object v4, v1
+  000c: move-object v1, v4
+  000d: move-object v2, v4
+  000e: move-object v3, v0
+  000f: invoke-direct {v2, v3}, java.lang.RuntimeException.<init>:(Ljava/lang/Throwable;)V
+  0012: throw v1
+  catches
+    tries:
+      try 0001..0004
+      catch java.lang.Exception -> 0007
diff --git a/dx/tests/066-dex-try-catch-rethrow/info.txt b/dx/tests/066-dex-try-catch-rethrow/info.txt
new file mode 100644
index 0000000..b2696b8
--- /dev/null
+++ b/dx/tests/066-dex-try-catch-rethrow/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which looks at a few cases of
+a try-catch where the exception handler rethrows.
+
+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/066-dex-try-catch-rethrow/run b/dx/tests/066-dex-try-catch-rethrow/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/066-dex-try-catch-rethrow/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/067-dex-switch-and-try/Blort.java b/dx/tests/067-dex-switch-and-try/Blort.java
new file mode 100644
index 0000000..e6435e1
--- /dev/null
+++ b/dx/tests/067-dex-switch-and-try/Blort.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    static public void blort() {
+        // This space intentionally left blank.
+    }
+
+    // This test has a try-catch but the try code can't possibly throw.
+    public int test1(int x) {
+        try {
+            switch (x) {
+                case 1: {
+                    x = 10;
+                    break;
+                }
+                case 2: {
+                    x = 20;
+                    break;
+                }
+            }
+        } catch (RuntimeException ex) {
+            // Ignore it.
+        }
+
+        return x;
+    }
+
+    // This test has a try-catch where the try code can theoretically throw.
+    public int test2(int x) {
+        try {
+            switch (x) {
+                case 1: {
+                    x = 10;
+                    blort();
+                    break;
+                }
+                case 2: {
+                    x = 20;
+                    break;
+                }
+            }
+        } catch (RuntimeException ex) {
+            // Ignore it.
+        }
+
+        return x;
+    }
+
+    // This test has a switch with a case that has a try-catch where
+    // the try code can theoretically throw, but it would be caught
+    // inside the case itself.
+    public int test3(int x) {
+        switch (x) {
+            case 1: {
+                try {
+                    x = 10;
+                    blort();
+                } catch (RuntimeException ex) {
+                    // Ignore it.
+                }
+                break;
+            }
+            case 2: {
+                x = 20;
+                break;
+            }
+        }
+
+        return x;
+    }
+
+    // This test has a try-catch that has a switch with a case that
+    // has a try-catch where the try code can theoretically throw, but
+    // it would be caught inside the case itself, so the outer
+    // exception handler should be considered dead.
+    public int test4(int x) {
+        try {
+            switch (x) {
+                case 1: {
+                    try {
+                        x = 10;
+                        blort();
+                    } catch (RuntimeException ex) {
+                        // Ignore it.
+                    }
+                    break;
+                }
+                case 2: {
+                    x = 20;
+                    break;
+                }
+            }
+        } catch (RuntimeException ex) {
+            return 4;
+        }
+
+        return x;
+    }
+}
diff --git a/dx/tests/067-dex-switch-and-try/expected.txt b/dx/tests/067-dex-switch-and-try/expected.txt
new file mode 100644
index 0000000..0a101d5
--- /dev/null
+++ b/dx/tests/067-dex-switch-and-try/expected.txt
@@ -0,0 +1,100 @@
+Blort.test1:(I)I:
+regs: 0006; ins: 0002; outs: 0000
+  0000: move-object v0, v4
+  0001: move v1, v5
+  0002: move v3, v1
+  0003: packed-switch v3, 0012 // +000f
+  0006: move v3, v1
+  0007: move v0, v3
+  0008: return v0
+  0009: const/16 v3, #int 10 // #000a
+  000b: move v1, v3
+  000c: goto 0006 // -0006
+  000d: const/16 v3, #int 20 // #0014
+  000f: move v1, v3
+  0010: goto 0006 // -000a
+  0011: nop // spacer
+  0012: packed-switch-payload // for switch @ 0003
+          1: 00000009 // +00000006
+          2: 0000000d // +0000000a
+Blort.test2:(I)I:
+regs: 0006; ins: 0002; outs: 0000
+  0000: move-object v0, v4
+  0001: move v1, v5
+  0002: move v3, v1
+  0003: packed-switch v3, 0018 // +0015
+  0006: move v3, v1
+  0007: move v0, v3
+  0008: return v0
+  0009: const/16 v3, #int 10 // #000a
+  000b: move v1, v3
+  000c: invoke-static {}, Blort.blort:()V
+  000f: goto 0006 // -0009
+  0010: const/16 v3, #int 20 // #0014
+  0012: move v1, v3
+  0013: goto 0006 // -000d
+  0014: move-exception v3
+  0015: move-object v2, v3
+  0016: goto 0006 // -0010
+  0017: nop // spacer
+  0018: packed-switch-payload // for switch @ 0003
+          1: 00000009 // +00000006
+          2: 00000010 // +0000000d
+  catches
+    tries:
+      try 000c..000f
+      catch java.lang.RuntimeException -> 0014
+Blort.test3:(I)I:
+regs: 0006; ins: 0002; outs: 0000
+  0000: move-object v0, v4
+  0001: move v1, v5
+  0002: move v3, v1
+  0003: packed-switch v3, 0018 // +0015
+  0006: move v3, v1
+  0007: move v0, v3
+  0008: return v0
+  0009: const/16 v3, #int 10 // #000a
+  000b: move v1, v3
+  000c: invoke-static {}, Blort.blort:()V
+  000f: goto 0006 // -0009
+  0010: move-exception v3
+  0011: move-object v2, v3
+  0012: goto 0006 // -000c
+  0013: const/16 v3, #int 20 // #0014
+  0015: move v1, v3
+  0016: goto 0006 // -0010
+  0017: nop // spacer
+  0018: packed-switch-payload // for switch @ 0003
+          1: 00000009 // +00000006
+          2: 00000013 // +00000010
+  catches
+    tries:
+      try 000c..000f
+      catch java.lang.RuntimeException -> 0010
+Blort.test4:(I)I:
+regs: 0006; ins: 0002; outs: 0000
+  0000: move-object v0, v4
+  0001: move v1, v5
+  0002: move v3, v1
+  0003: packed-switch v3, 0018 // +0015
+  0006: move v3, v1
+  0007: move v0, v3
+  0008: return v0
+  0009: const/16 v3, #int 10 // #000a
+  000b: move v1, v3
+  000c: invoke-static {}, Blort.blort:()V
+  000f: goto 0006 // -0009
+  0010: move-exception v3
+  0011: move-object v2, v3
+  0012: goto 0006 // -000c
+  0013: const/16 v3, #int 20 // #0014
+  0015: move v1, v3
+  0016: goto 0006 // -0010
+  0017: nop // spacer
+  0018: packed-switch-payload // for switch @ 0003
+          1: 00000009 // +00000006
+          2: 00000013 // +00000010
+  catches
+    tries:
+      try 000c..000f
+      catch java.lang.RuntimeException -> 0010
diff --git a/dx/tests/067-dex-switch-and-try/info.txt b/dx/tests/067-dex-switch-and-try/info.txt
new file mode 100644
index 0000000..68e8117
--- /dev/null
+++ b/dx/tests/067-dex-switch-and-try/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which looks at a couple cases of
+embedding a switch statement in a try-catch and vice versa. This test
+was created specifically because of a bug with exactly this situation.
+
+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/067-dex-switch-and-try/run b/dx/tests/067-dex-switch-and-try/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/067-dex-switch-and-try/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/068-dex-infinite-loop/Blort.java b/dx/tests/068-dex-infinite-loop/Blort.java
new file mode 100644
index 0000000..f026407
--- /dev/null
+++ b/dx/tests/068-dex-infinite-loop/Blort.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static boolean zorch() {
+        return true;
+    }
+
+    public static void test1() {
+        for (;;) {
+            // This space intentionally left blank.
+        }
+    }
+
+    public static void test2() {
+        while (zorch()) {
+            // This space intentionally left blank.
+        }
+    }
+
+    public static void test3() {
+        while (zorch()) {
+            zorch();
+        }
+    }
+
+    public static void test4() {
+        for (;;) {
+            if (zorch()) {
+                break;
+            }
+
+            while (zorch()) {
+                zorch();
+            }
+        }
+    }
+}
diff --git a/dx/tests/068-dex-infinite-loop/expected.txt b/dx/tests/068-dex-infinite-loop/expected.txt
new file mode 100644
index 0000000..1a84bd9
--- /dev/null
+++ b/dx/tests/068-dex-infinite-loop/expected.txt
@@ -0,0 +1,28 @@
+Blort.test1:()V:
+regs: 0000; ins: 0000; outs: 0000
+  0000: goto/32 0000 // +0000
+Blort.test2:()V:
+regs: 0001; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.zorch:()Z
+  0003: move-result v0
+  0004: if-nez v0, 0000 // -0004
+  0006: return-void
+Blort.test3:()V:
+regs: 0001; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.zorch:()Z
+  0003: move-result v0
+  0004: if-eqz v0, 000a // +0006
+  0006: invoke-static {}, Blort.zorch:()Z
+  0009: goto 0000 // -0009
+  000a: return-void
+Blort.test4:()V:
+regs: 0001; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.zorch:()Z
+  0003: move-result v0
+  0004: if-eqz v0, 0007 // +0003
+  0006: return-void
+  0007: invoke-static {}, Blort.zorch:()Z
+  000a: move-result v0
+  000b: if-eqz v0, 0000 // -000b
+  000d: invoke-static {}, Blort.zorch:()Z
+  0010: goto 0007 // -0009
diff --git a/dx/tests/068-dex-infinite-loop/info.txt b/dx/tests/068-dex-infinite-loop/info.txt
new file mode 100644
index 0000000..358f0a8
--- /dev/null
+++ b/dx/tests/068-dex-infinite-loop/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which makes sure that a couple
+cases of (potentially) infinite loops translate reasonably.
+
+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/068-dex-infinite-loop/run b/dx/tests/068-dex-infinite-loop/run
new file mode 100644
index 0000000..3fe95cc
--- /dev/null
+++ b/dx/tests/068-dex-infinite-loop/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/069-dex-source-position/Blort.java b/dx/tests/069-dex-source-position/Blort.java
new file mode 100644
index 0000000..8c0c5c0
--- /dev/null
+++ b/dx/tests/069-dex-source-position/Blort.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int test(int x) {
+        if (x == 0) { // line 6
+            return 1; // line 7
+        } else {
+            try {
+                x = test(x - 1); // line 10
+            } catch (RuntimeException ex) { // line 11
+                return 2; // line 12
+            }
+            x += test(x - 2); // line 14
+            return x; // line 15
+        }
+    }
+}
diff --git a/dx/tests/069-dex-source-position/expected.txt b/dx/tests/069-dex-source-position/expected.txt
new file mode 100644
index 0000000..cd45497
--- /dev/null
+++ b/dx/tests/069-dex-source-position/expected.txt
@@ -0,0 +1,134 @@
+Blort.test:(I)I:
+regs: 0006; ins: 0001; outs: 0001
+  0000: move v0, v5
+  0001: move v2, v0
+  0002: if-nez v2, 0007 // +0005
+  0004: const/4 v2, #int 1 // #1
+  0005: move v0, v2
+  0006: return v0
+  0007: move v2, v0
+  0008: const/4 v3, #int 1 // #1
+  0009: add-int/lit8 v2, v2, #int -1 // #ff
+  000b: invoke-static {v2}, Blort.test:(I)I
+  000e: move-result v2
+  000f: move v0, v2
+  0010: move v2, v0
+  0011: move v3, v0
+  0012: const/4 v4, #int 2 // #2
+  0013: add-int/lit8 v3, v3, #int -2 // #fe
+  0015: invoke-static {v3}, Blort.test:(I)I
+  0018: move-result v3
+  0019: add-int/2addr v2, v3
+  001a: move v0, v2
+  001b: move v2, v0
+  001c: move v0, v2
+  001d: goto 0006 // -0017
+  001e: move-exception v2
+  001f: move-object v1, v2
+  0020: const/4 v2, #int 2 // #2
+  0021: move v0, v2
+  0022: goto 0006 // -001c
+  catches
+    tries:
+      try 000b..000e
+      catch java.lang.RuntimeException -> 001e
+Blort.test:(I)I:
+regs: 0006; ins: 0001; outs: 0001
+  0000: move v0, v5
+  0001: move v2, v0
+  0002: if-nez v2, 0007 // +0005
+  0004: const/4 v2, #int 1 // #1
+  0005: move v0, v2
+  0006: return v0
+  0007: move v2, v0
+  0008: const/4 v3, #int 1 // #1
+  0009: add-int/lit8 v2, v2, #int -1 // #ff
+  000b: invoke-static {v2}, Blort.test:(I)I
+  000e: move-result v2
+  000f: move v0, v2
+  0010: move v2, v0
+  0011: move v3, v0
+  0012: const/4 v4, #int 2 // #2
+  0013: add-int/lit8 v3, v3, #int -2 // #fe
+  0015: invoke-static {v3}, Blort.test:(I)I
+  0018: move-result v3
+  0019: add-int/2addr v2, v3
+  001a: move v0, v2
+  001b: move v2, v0
+  001c: move v0, v2
+  001d: goto 0006 // -0017
+  001e: move-exception v2
+  001f: move-object v1, v2
+  0020: const/4 v2, #int 2 // #2
+  0021: move v0, v2
+  0022: goto 0006 // -001c
+  catches
+    tries:
+      try 000b..000e
+      catch java.lang.RuntimeException -> 001e
+  debug info
+    line_start: 20
+    parameters_size: 0001
+    parameter <unnamed> v5
+    0000: prologue end
+    0000: line 20
+    0004: line 21
+    0006: line 29
+    line = 24
+    0007: line 24
+    0010: line 28
+    001b: line 29
+    001e: line 25
+    0020: line 26
+    end sequence
+  source file: "Blort.java"
+Blort.test:(I)I:
+regs: 0006; ins: 0001; outs: 0001
+  0000: move v0, v5
+  0001: move v2, v0
+  0002: if-nez v2, 0007 // +0005
+  0004: const/4 v2, #int 1 // #1
+  0005: move v0, v2
+  0006: return v0
+  0007: move v2, v0
+  0008: const/4 v3, #int 1 // #1
+  0009: add-int/lit8 v2, v2, #int -1 // #ff
+  000b: invoke-static {v2}, Blort.test:(I)I
+  000e: move-result v2
+  000f: move v0, v2
+  0010: move v2, v0
+  0011: move v3, v0
+  0012: const/4 v4, #int 2 // #2
+  0013: add-int/lit8 v3, v3, #int -2 // #fe
+  0015: invoke-static {v3}, Blort.test:(I)I
+  0018: move-result v3
+  0019: add-int/2addr v2, v3
+  001a: move v0, v2
+  001b: move v2, v0
+  001c: move v0, v2
+  001d: goto 0006 // -0017
+  001e: move-exception v2
+  001f: move-object v1, v2
+  0020: const/4 v2, #int 2 // #2
+  0021: move v0, v2
+  0022: goto 0006 // -001c
+  catches
+    tries:
+      try 000b..000e
+      catch java.lang.RuntimeException -> 001e
+  debug info
+    line_start: 20
+    parameters_size: 0001
+    parameter <unnamed> v5
+    0000: prologue end
+    0000: line 20
+    0004: line 21
+    0006: line 29
+    line = 24
+    0007: line 24
+    0010: line 28
+    001b: line 29
+    001e: line 25
+    0020: line 26
+    end sequence
+  source file: "Blort.java"
diff --git a/dx/tests/069-dex-source-position/info.txt b/dx/tests/069-dex-source-position/info.txt
new file mode 100644
index 0000000..28c8b51
--- /dev/null
+++ b/dx/tests/069-dex-source-position/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which makes sure that source
+position information is faithfully reproduced (or not, as directed).
+
+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/069-dex-source-position/run b/dx/tests/069-dex-source-position/run
new file mode 100644
index 0000000..98c2630
--- /dev/null
+++ b/dx/tests/069-dex-source-position/run
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
+dx --debug --dex --no-optimize --positions=important --no-locals \
+    --dump-method=Blort.test'*' Blort.class
+dx --debug --dex --no-optimize --positions=lines --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/070-dex-multianewarray/Blort.java b/dx/tests/070-dex-multianewarray/Blort.java
new file mode 100644
index 0000000..ef812cf
--- /dev/null
+++ b/dx/tests/070-dex-multianewarray/Blort.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static Object test01() {
+        Object[][] x = new Object[2][5];
+        return x;
+    }
+
+    public static Object test02() {
+        Object[][][] x = new Object[4][1][];
+        return x;
+    }
+
+    public static Object test03() {
+        Object[][][] x = new Object[7][2][4];
+        return x;
+    }
+
+    public static Object test04() {
+        Object[][][] x = new Object[3][0][0];
+        return x;
+    }
+
+    public static Object test05() {
+        Object[][][][] x = new Object[1][3][5][7];
+        return x;
+    }
+
+    public static Object test06() {
+        Object[][][][][] x = new Object[8][7][2][3][4];
+        return x;
+    }
+
+    public static Object test07() {
+        Object[][][][][][] x = new Object[8][7][2][3][4][];
+        return x;
+    }
+
+    public static Object test08() {
+        Object[][][][][][][] x = new Object[8][7][2][3][4][][];
+        return x;
+    }
+
+    public static boolean[][] test09() {
+        return new boolean[1][2];
+    }
+
+    public static byte[][] test10() {
+        return new byte[3][4];
+    }
+
+    public static char[][] test11() {
+        return new char[5][6];
+    }
+
+    public static double[][] test12() {
+        return new double[7][8];
+    }
+
+    public static float[][] test13() {
+        return new float[9][1];
+    }
+
+    public static int[][][] test14() {
+        return new int[5][3][2];
+    }
+
+    public static long[][][] test15() {
+        return new long[3][4][7];
+    }
+
+    public static short[][][][] test16() {
+        return new short[5][4][3][2];
+    }
+
+    public static String[][][][][] test17() {
+        return new String[5][4][3][2][1];
+    }
+
+    public static Runnable[][][][][][] test18() {
+        return new Runnable[5][4][3][2][1][8];
+    }
+}
diff --git a/dx/tests/070-dex-multianewarray/expected.txt b/dx/tests/070-dex-multianewarray/expected.txt
new file mode 100644
index 0000000..9ddbabe
--- /dev/null
+++ b/dx/tests/070-dex-multianewarray/expected.txt
@@ -0,0 +1,246 @@
+Blort.test01:()Ljava/lang/Object;:
+regs: 0003; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 2 // #2
+  0001: const/4 v2, #int 5 // #5
+  0002: filled-new-array {v1, v2}, int[]
+  0005: move-result-object v2
+  0006: const-class v1, java.lang.Object
+  0008: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000b: move-result-object v1
+  000c: check-cast v1, java.lang.Object[][]
+  000e: move-object v0, v1
+  000f: move-object v1, v0
+  0010: move-object v0, v1
+  0011: return-object v0
+Blort.test02:()Ljava/lang/Object;:
+regs: 0003; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 4 // #4
+  0001: const/4 v2, #int 1 // #1
+  0002: filled-new-array {v1, v2}, int[]
+  0005: move-result-object v2
+  0006: const-class v1, java.lang.Object[]
+  0008: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000b: move-result-object v1
+  000c: check-cast v1, java.lang.Object[][][]
+  000e: move-object v0, v1
+  000f: move-object v1, v0
+  0010: move-object v0, v1
+  0011: return-object v0
+Blort.test03:()Ljava/lang/Object;:
+regs: 0004; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 7 // #7
+  0001: const/4 v2, #int 2 // #2
+  0002: const/4 v3, #int 4 // #4
+  0003: filled-new-array {v1, v2, v3}, int[]
+  0006: move-result-object v2
+  0007: const-class v1, java.lang.Object
+  0009: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000c: move-result-object v1
+  000d: check-cast v1, java.lang.Object[][][]
+  000f: move-object v0, v1
+  0010: move-object v1, v0
+  0011: move-object v0, v1
+  0012: return-object v0
+Blort.test04:()Ljava/lang/Object;:
+regs: 0004; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 3 // #3
+  0001: const/4 v2, #int 0 // #0
+  0002: const/4 v3, #int 0 // #0
+  0003: filled-new-array {v1, v2, v3}, int[]
+  0006: move-result-object v2
+  0007: const-class v1, java.lang.Object
+  0009: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000c: move-result-object v1
+  000d: check-cast v1, java.lang.Object[][][]
+  000f: move-object v0, v1
+  0010: move-object v1, v0
+  0011: move-object v0, v1
+  0012: return-object v0
+Blort.test05:()Ljava/lang/Object;:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const/4 v1, #int 1 // #1
+  0001: const/4 v2, #int 3 // #3
+  0002: const/4 v3, #int 5 // #5
+  0003: const/4 v4, #int 7 // #7
+  0004: filled-new-array {v1, v2, v3, v4}, int[]
+  0007: move-result-object v2
+  0008: const-class v1, java.lang.Object
+  000a: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000d: move-result-object v1
+  000e: check-cast v1, java.lang.Object[][][][]
+  0010: move-object v0, v1
+  0011: move-object v1, v0
+  0012: move-object v0, v1
+  0013: return-object v0
+Blort.test06:()Ljava/lang/Object;:
+regs: 0006; ins: 0000; outs: 0002
+  0000: const/16 v1, #int 8 // #0008
+  0002: const/4 v2, #int 7 // #7
+  0003: const/4 v3, #int 2 // #2
+  0004: const/4 v4, #int 3 // #3
+  0005: const/4 v5, #int 4 // #4
+  0006: filled-new-array {v1, v2, v3, v4, v5}, int[]
+  0009: move-result-object v2
+  000a: const-class v1, java.lang.Object
+  000c: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000f: move-result-object v1
+  0010: check-cast v1, java.lang.Object[][][][][]
+  0012: move-object v0, v1
+  0013: move-object v1, v0
+  0014: move-object v0, v1
+  0015: return-object v0
+Blort.test07:()Ljava/lang/Object;:
+regs: 0006; ins: 0000; outs: 0002
+  0000: const/16 v1, #int 8 // #0008
+  0002: const/4 v2, #int 7 // #7
+  0003: const/4 v3, #int 2 // #2
+  0004: const/4 v4, #int 3 // #3
+  0005: const/4 v5, #int 4 // #4
+  0006: filled-new-array {v1, v2, v3, v4, v5}, int[]
+  0009: move-result-object v2
+  000a: const-class v1, java.lang.Object[]
+  000c: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000f: move-result-object v1
+  0010: check-cast v1, java.lang.Object[][][][][][]
+  0012: move-object v0, v1
+  0013: move-object v1, v0
+  0014: move-object v0, v1
+  0015: return-object v0
+Blort.test08:()Ljava/lang/Object;:
+regs: 0006; ins: 0000; outs: 0002
+  0000: const/16 v1, #int 8 // #0008
+  0002: const/4 v2, #int 7 // #7
+  0003: const/4 v3, #int 2 // #2
+  0004: const/4 v4, #int 3 // #3
+  0005: const/4 v5, #int 4 // #4
+  0006: filled-new-array {v1, v2, v3, v4, v5}, int[]
+  0009: move-result-object v2
+  000a: const-class v1, java.lang.Object[][]
+  000c: invoke-static {v1, v2}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000f: move-result-object v1
+  0010: check-cast v1, java.lang.Object[][][][][][][]
+  0012: move-object v0, v1
+  0013: move-object v1, v0
+  0014: move-object v0, v1
+  0015: return-object v0
+Blort.test09:()[[Z:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 1 // #1
+  0001: const/4 v1, #int 2 // #2
+  0002: filled-new-array {v0, v1}, int[]
+  0005: move-result-object v1
+  0006: sget-object v0, java.lang.Boolean.TYPE:Ljava/lang/Class;
+  0008: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000b: move-result-object v0
+  000c: check-cast v0, boolean[][]
+  000e: return-object v0
+Blort.test10:()[[B:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 3 // #3
+  0001: const/4 v1, #int 4 // #4
+  0002: filled-new-array {v0, v1}, int[]
+  0005: move-result-object v1
+  0006: sget-object v0, java.lang.Byte.TYPE:Ljava/lang/Class;
+  0008: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000b: move-result-object v0
+  000c: check-cast v0, byte[][]
+  000e: return-object v0
+Blort.test11:()[[C:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 5 // #5
+  0001: const/4 v1, #int 6 // #6
+  0002: filled-new-array {v0, v1}, int[]
+  0005: move-result-object v1
+  0006: sget-object v0, java.lang.Character.TYPE:Ljava/lang/Class;
+  0008: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000b: move-result-object v0
+  000c: check-cast v0, char[][]
+  000e: return-object v0
+Blort.test12:()[[D:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 7 // #7
+  0001: const/16 v1, #int 8 // #0008
+  0003: filled-new-array {v0, v1}, int[]
+  0006: move-result-object v1
+  0007: sget-object v0, java.lang.Double.TYPE:Ljava/lang/Class;
+  0009: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000c: move-result-object v0
+  000d: check-cast v0, double[][]
+  000f: return-object v0
+Blort.test13:()[[F:
+regs: 0002; ins: 0000; outs: 0002
+  0000: const/16 v0, #int 9 // #0009
+  0002: const/4 v1, #int 1 // #1
+  0003: filled-new-array {v0, v1}, int[]
+  0006: move-result-object v1
+  0007: sget-object v0, java.lang.Float.TYPE:Ljava/lang/Class;
+  0009: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000c: move-result-object v0
+  000d: check-cast v0, float[][]
+  000f: return-object v0
+Blort.test14:()[[[I:
+regs: 0003; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 5 // #5
+  0001: const/4 v1, #int 3 // #3
+  0002: const/4 v2, #int 2 // #2
+  0003: filled-new-array {v0, v1, v2}, int[]
+  0006: move-result-object v1
+  0007: sget-object v0, java.lang.Integer.TYPE:Ljava/lang/Class;
+  0009: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000c: move-result-object v0
+  000d: check-cast v0, int[][][]
+  000f: return-object v0
+Blort.test15:()[[[J:
+regs: 0003; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 3 // #3
+  0001: const/4 v1, #int 4 // #4
+  0002: const/4 v2, #int 7 // #7
+  0003: filled-new-array {v0, v1, v2}, int[]
+  0006: move-result-object v1
+  0007: sget-object v0, java.lang.Long.TYPE:Ljava/lang/Class;
+  0009: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000c: move-result-object v0
+  000d: check-cast v0, long[][][]
+  000f: return-object v0
+Blort.test16:()[[[[S:
+regs: 0004; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 5 // #5
+  0001: const/4 v1, #int 4 // #4
+  0002: const/4 v2, #int 3 // #3
+  0003: const/4 v3, #int 2 // #2
+  0004: filled-new-array {v0, v1, v2, v3}, int[]
+  0007: move-result-object v1
+  0008: sget-object v0, java.lang.Short.TYPE:Ljava/lang/Class;
+  000a: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000d: move-result-object v0
+  000e: check-cast v0, short[][][][]
+  0010: return-object v0
+Blort.test17:()[[[[[Ljava/lang/String;:
+regs: 0005; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 5 // #5
+  0001: const/4 v1, #int 4 // #4
+  0002: const/4 v2, #int 3 // #3
+  0003: const/4 v3, #int 2 // #2
+  0004: const/4 v4, #int 1 // #1
+  0005: filled-new-array {v0, v1, v2, v3, v4}, int[]
+  0008: move-result-object v1
+  0009: const-class v0, java.lang.String
+  000b: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  000e: move-result-object v0
+  000f: check-cast v0, java.lang.String[][][][][]
+  0011: return-object v0
+Blort.test18:()[[[[[[Ljava/lang/Runnable;:
+regs: 0006; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 5 // #5
+  0001: const/4 v1, #int 4 // #4
+  0002: const/4 v2, #int 3 // #3
+  0003: const/4 v3, #int 2 // #2
+  0004: const/4 v4, #int 1 // #1
+  0005: const/16 v5, #int 8 // #0008
+  0007: filled-new-array/range {v0..v5}, int[]
+  000a: move-result-object v1
+  000b: const-class v0, java.lang.Runnable
+  000d: invoke-static {v0, v1}, java.lang.reflect.Array.newInstance:(Ljava/lang/Class;[I)Ljava/lang/Object;
+  0010: move-result-object v0
+  0011: check-cast v0, java.lang.Runnable[][][][][][]
+  0013: return-object v0
diff --git a/dx/tests/070-dex-multianewarray/info.txt b/dx/tests/070-dex-multianewarray/info.txt
new file mode 100644
index 0000000..1251f0c
--- /dev/null
+++ b/dx/tests/070-dex-multianewarray/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that a few
+cases of multidimensional array construction get converted reasonably.
+
+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/070-dex-multianewarray/run b/dx/tests/070-dex-multianewarray/run
new file mode 100644
index 0000000..e5eb509
--- /dev/null
+++ b/dx/tests/070-dex-multianewarray/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/071-dex-java-stack-ops/blort.j b/dx/tests/071-dex-java-stack-ops/blort.j
new file mode 100644
index 0000000..848a84e
--- /dev/null
+++ b/dx/tests/071-dex-java-stack-ops/blort.j
@@ -0,0 +1,319 @@
+; 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.
+
+.class Blort
+.super java/lang/Object
+
+; Methods to "consume" an int.
+.method public static consume1(I)V
+.limit stack 0
+.limit locals 1
+    nop
+    return
+.end method
+
+.method public static consume2(I)V
+.limit stack 0
+.limit locals 1
+    nop
+    return
+.end method
+
+.method public static consume3(I)V
+.limit stack 0
+.limit locals 1
+    nop
+    return
+.end method
+
+.method public static consume4(I)V
+.limit stack 0
+.limit locals 1
+    nop
+    return
+.end method
+
+.method public static consume5(I)V
+.limit stack 0
+.limit locals 1
+    nop
+    return
+.end method
+
+.method public static consume6(I)V
+.limit stack 0
+.limit locals 1
+    nop
+    return
+.end method
+
+; Methods to "consume" a long.
+.method public static consume1(J)V
+.limit stack 0
+.limit locals 2
+    nop
+    return
+.end method
+
+.method public static consume2(J)V
+.limit stack 0
+.limit locals 2
+    nop
+    return
+.end method
+
+.method public static consume3(J)V
+.limit stack 0
+.limit locals 2
+    nop
+    return
+.end method
+
+.method public static consume4(J)V
+.limit stack 0
+.limit locals 2
+    nop
+    return
+.end method
+
+; Test of "pop" opcode. This should end up causing a call to consume1(0).
+.method public static test_pop()V
+.limit stack 2
+.limit locals 0
+    iconst_0
+    iconst_1
+    pop          ; A1 -> (empty)
+    invokestatic Blort/consume1(I)V
+    return
+.end method
+
+; Test of "pop2" opcode, form 1. This should end up causing a call
+; to consume1(0).
+.method public static test_pop2_form1()V
+.limit stack 3
+.limit locals 0
+    iconst_0
+    iconst_1
+    iconst_2
+    pop2         ; A1 B1 -> (empty)
+    invokestatic Blort/consume1(I)V
+    return
+.end method
+
+; Test of "pop2" opcode, form 2. This should end up causing a call
+; to consume1(0).
+.method public static test_pop2_form2()V
+.limit stack 3
+.limit locals 0
+    iconst_0
+    lconst_0
+    pop2         ; A2 -> (empty)
+    invokestatic Blort/consume1(I)V
+    return
+.end method
+
+; Test of "dup" opcode. This should end up causing these calls in order:
+; consume1(0), consume2(0).
+.method public static test_dup()V
+.limit stack 2
+.limit locals 0
+    iconst_0
+    dup          ; A1 -> A1 A1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    return
+.end method
+
+; Test of "dup_x1" opcode. This should end up causing these calls in order:
+; consume1(1), consume2(0), consume3(1).
+.method public static test_dup_x1()V
+.limit stack 3
+.limit locals 0
+    iconst_0
+    iconst_1
+    dup_x1       ; A1 B1 -> B1 A1 B1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(I)V
+    return
+.end method
+
+; Test of "dup_x2" opcode, form 1. This should end up causing these calls
+; in order: consume1(2), consume2(1), consume3(0), consume4(2).
+.method public static test_dup_x2_form1()V
+.limit stack 4
+.limit locals 0
+    iconst_0
+    iconst_1
+    iconst_2
+    dup_x2       ; A1 B1 C1 -> C1 A1 B1 C1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(I)V
+    invokestatic Blort/consume4(I)V
+    return
+.end method
+
+; Test of "dup_x2" opcode, form 2. This should end up causing these calls
+; in order: consume1(1), consume2(0L), consume3(1).
+.method public static test_dup_x2_form2()V
+.limit stack 4
+.limit locals 0
+    lconst_0
+    iconst_1
+    dup_x2       ; A2 B1 -> B1 A2 B1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(J)V
+    invokestatic Blort/consume3(I)V
+    return
+.end method
+
+; Test of "dup2" opcode, form 1. This should end up causing these calls
+; in order: consume1(1), consume2(0), consume3(1), consume4(0).
+.method public static test_dup2_form1()V
+.limit stack 4
+.limit locals 0
+    iconst_0
+    iconst_1
+    dup2         ; A1 B1 -> A1 B1 A1 B1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(I)V
+    invokestatic Blort/consume4(I)V
+    return
+.end method
+
+; Test of "dup2" opcode, form 2. This should end up causing these calls
+; in order: consume1(0L), consume2(0L).
+.method public static test_dup2_form2()V
+.limit stack 4
+.limit locals 0
+    lconst_0
+    dup2         ; A2 -> A2 A2
+    invokestatic Blort/consume1(J)V
+    invokestatic Blort/consume2(J)V
+    return
+.end method
+
+; Test of "dup2_x1" opcode, form 1. This should end up causing these calls
+; in order: consume1(1), consume2(2), consume3(0), consume4(1), consume5(2).
+.method public static test_dup2_x1_form1()V
+.limit stack 5
+.limit locals 0
+    iconst_0
+    iconst_1
+    iconst_2
+    dup2_x1      ; A1 B1 C1 -> B1 C1 A1 B1 C1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(I)V
+    invokestatic Blort/consume4(I)V
+    invokestatic Blort/consume5(I)V
+    return
+.end method
+
+
+; Test of "dup2_x1" opcode, form 2. This should end up causing these calls
+; in order: consume1(1L), consume2(2), consume3(1L).
+.method public static test_dup2_x1_form2()V
+.limit stack 5
+.limit locals 0
+    iconst_0
+    lconst_1
+    dup2_x1      ; A1 B2 -> B2 A1 B2
+    invokestatic Blort/consume1(J)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(J)V
+    return
+.end method
+
+; Test of "dup2_x2" opcode, form 1. This should end up causing these calls
+; in order: consume1(3), consume2(2), consume3(1), consume4(0), consume5(3),
+; consume6(2).
+.method public static test_dup2_x2_form1()V
+.limit stack 6
+.limit locals 0
+    iconst_0
+    iconst_1
+    iconst_2
+    iconst_3
+    dup2_x2      ; A1 B1 C1 D1 -> C1 D1 A1 B1 C1 D1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(I)V
+    invokestatic Blort/consume4(I)V
+    invokestatic Blort/consume5(I)V
+    invokestatic Blort/consume6(I)V
+    return
+.end method
+
+; Test of "dup2_x2" opcode, form 2. This should end up causing these calls
+; in order: consume1(2L), consume2(1), consume3(0), consume4(2L).
+.method public static test_dup2_x2_form2()V
+.limit stack 6
+.limit locals 0
+    iconst_0
+    iconst_1
+    ldc2_w 2
+    dup2_x2      ; A1 B1 C2 -> C2 A1 B1 C2
+    invokestatic Blort/consume1(J)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(I)V
+    invokestatic Blort/consume4(J)V
+    return
+.end method
+
+; Test of "dup2_x2" opcode, form 3. This should end up causing these calls
+; in order: consume1(2), consume2(1), consume3(0L), consume4(2), consume5(1).
+.method public static test_dup2_x2_form3()V
+.limit stack 6
+.limit locals 0
+    lconst_0
+    iconst_1
+    iconst_2
+    dup2_x2      ; A2 B1 C1 -> B1 C1 A2 B1 C1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    invokestatic Blort/consume3(J)V
+    invokestatic Blort/consume4(I)V
+    invokestatic Blort/consume5(I)V
+    return
+.end method
+
+; Test of "dup2_x2" opcode, form 4. This should end up causing these calls
+; in order: consume1(1L), consume2(0L), consume3(1L).
+.method public static test_dup2_x2_form4()V
+.limit stack 6
+.limit locals 0
+    lconst_0
+    lconst_1
+    dup2_x2      ; A2 B2 -> B2 A2 B2
+    invokestatic Blort/consume1(J)V
+    invokestatic Blort/consume2(J)V
+    invokestatic Blort/consume3(J)V
+    return
+.end method
+
+; Test of "swap" opcode. This should end up causing these calls
+; in order: consume1(0), consume2(1).
+.method public static test_swap()V
+.limit stack 2
+.limit locals 0
+    iconst_0
+    iconst_1
+    swap         ; A1 B1 -> B1 A1
+    invokestatic Blort/consume1(I)V
+    invokestatic Blort/consume2(I)V
+    return
+.end method
diff --git a/dx/tests/071-dex-java-stack-ops/expected.txt b/dx/tests/071-dex-java-stack-ops/expected.txt
new file mode 100644
index 0000000..3ba8ef3
--- /dev/null
+++ b/dx/tests/071-dex-java-stack-ops/expected.txt
@@ -0,0 +1,210 @@
+Blort.test_dup:()V:
+regs: 0003; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: move v2, v0
+  0002: move v0, v2
+  0003: move v1, v2
+  0004: invoke-static {v1}, Blort.consume1:(I)V
+  0007: invoke-static {v0}, Blort.consume2:(I)V
+  000a: return-void
+Blort.test_dup2_form1:()V:
+regs: 0006; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: move v4, v0
+  0003: move v5, v1
+  0004: move v0, v4
+  0005: move v1, v5
+  0006: move v2, v4
+  0007: move v3, v5
+  0008: invoke-static {v3}, Blort.consume1:(I)V
+  000b: invoke-static {v2}, Blort.consume2:(I)V
+  000e: invoke-static {v1}, Blort.consume3:(I)V
+  0011: invoke-static {v0}, Blort.consume4:(I)V
+  0014: return-void
+Blort.test_dup2_form2:()V:
+regs: 0006; ins: 0000; outs: 0002
+  0000: const-wide/16 v0, #long 0 // #0000
+  0002: move-wide v4, v0
+  0003: move-wide v0, v4
+  0004: move-wide v2, v4
+  0005: invoke-static {v2, v3}, Blort.consume1:(J)V
+  0008: invoke-static {v0, v1}, Blort.consume2:(J)V
+  000b: return-void
+Blort.test_dup2_x1_form1:()V:
+regs: 0008; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: const/4 v2, #int 2 // #2
+  0003: move v5, v0
+  0004: move v6, v1
+  0005: move v7, v2
+  0006: move v0, v6
+  0007: move v1, v7
+  0008: move v2, v5
+  0009: move v3, v6
+  000a: move v4, v7
+  000b: invoke-static {v4}, Blort.consume1:(I)V
+  000e: invoke-static {v3}, Blort.consume2:(I)V
+  0011: invoke-static {v2}, Blort.consume3:(I)V
+  0014: invoke-static {v1}, Blort.consume4:(I)V
+  0017: invoke-static {v0}, Blort.consume5:(I)V
+  001a: return-void
+Blort.test_dup2_x1_form2:()V:
+regs: 0008; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 0 // #0
+  0001: const-wide/16 v1, #long 1 // #0001
+  0003: move v5, v0
+  0004: move-wide v6, v1
+  0005: move-wide v0, v6
+  0006: move v2, v5
+  0007: move-wide v3, v6
+  0008: invoke-static {v3, v4}, Blort.consume1:(J)V
+  000b: invoke-static {v2}, Blort.consume2:(I)V
+  000e: invoke-static {v0, v1}, Blort.consume3:(J)V
+  0011: return-void
+Blort.test_dup2_x2_form1:()V:
+regs: 000a; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: const/4 v2, #int 2 // #2
+  0003: const/4 v3, #int 3 // #3
+  0004: move v6, v0
+  0005: move v7, v1
+  0006: move v8, v2
+  0007: move v9, v3
+  0008: move v0, v8
+  0009: move v1, v9
+  000a: move v2, v6
+  000b: move v3, v7
+  000c: move v4, v8
+  000d: move v5, v9
+  000e: invoke-static {v5}, Blort.consume1:(I)V
+  0011: invoke-static {v4}, Blort.consume2:(I)V
+  0014: invoke-static {v3}, Blort.consume3:(I)V
+  0017: invoke-static {v2}, Blort.consume4:(I)V
+  001a: invoke-static {v1}, Blort.consume5:(I)V
+  001d: invoke-static {v0}, Blort.consume6:(I)V
+  0020: return-void
+Blort.test_dup2_x2_form2:()V:
+regs: 000a; ins: 0000; outs: 0002
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: const-wide/16 v2, #long 2 // #0002
+  0004: move v6, v0
+  0005: move v7, v1
+  0006: move-wide v8, v2
+  0007: move-wide v0, v8
+  0008: move v2, v6
+  0009: move v3, v7
+  000a: move-wide v4, v8
+  000b: invoke-static {v4, v5}, Blort.consume1:(J)V
+  000e: invoke-static {v3}, Blort.consume2:(I)V
+  0011: invoke-static {v2}, Blort.consume3:(I)V
+  0014: invoke-static {v0, v1}, Blort.consume4:(J)V
+  0017: return-void
+Blort.test_dup2_x2_form3:()V:
+regs: 000a; ins: 0000; outs: 0002
+  0000: const-wide/16 v0, #long 0 // #0000
+  0002: const/4 v2, #int 1 // #1
+  0003: const/4 v3, #int 2 // #2
+  0004: move-wide v6, v0
+  0005: move v8, v2
+  0006: move v9, v3
+  0007: move v0, v8
+  0008: move v1, v9
+  0009: move-wide v2, v6
+  000a: move v4, v8
+  000b: move v5, v9
+  000c: invoke-static {v5}, Blort.consume1:(I)V
+  000f: invoke-static {v4}, Blort.consume2:(I)V
+  0012: invoke-static {v2, v3}, Blort.consume3:(J)V
+  0015: invoke-static {v1}, Blort.consume4:(I)V
+  0018: invoke-static {v0}, Blort.consume5:(I)V
+  001b: return-void
+Blort.test_dup2_x2_form4:()V:
+regs: 000a; ins: 0000; outs: 0002
+  0000: const-wide/16 v0, #long 0 // #0000
+  0002: const-wide/16 v2, #long 1 // #0001
+  0004: move-wide v6, v0
+  0005: move-wide v8, v2
+  0006: move-wide v0, v8
+  0007: move-wide v2, v6
+  0008: move-wide v4, v8
+  0009: invoke-static {v4, v5}, Blort.consume1:(J)V
+  000c: invoke-static {v2, v3}, Blort.consume2:(J)V
+  000f: invoke-static {v0, v1}, Blort.consume3:(J)V
+  0012: return-void
+Blort.test_dup_x1:()V:
+regs: 0005; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: move v3, v0
+  0003: move v4, v1
+  0004: move v0, v4
+  0005: move v1, v3
+  0006: move v2, v4
+  0007: invoke-static {v2}, Blort.consume1:(I)V
+  000a: invoke-static {v1}, Blort.consume2:(I)V
+  000d: invoke-static {v0}, Blort.consume3:(I)V
+  0010: return-void
+Blort.test_dup_x2_form1:()V:
+regs: 0007; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: const/4 v2, #int 2 // #2
+  0003: move v4, v0
+  0004: move v5, v1
+  0005: move v6, v2
+  0006: move v0, v6
+  0007: move v1, v4
+  0008: move v2, v5
+  0009: move v3, v6
+  000a: invoke-static {v3}, Blort.consume1:(I)V
+  000d: invoke-static {v2}, Blort.consume2:(I)V
+  0010: invoke-static {v1}, Blort.consume3:(I)V
+  0013: invoke-static {v0}, Blort.consume4:(I)V
+  0016: return-void
+Blort.test_dup_x2_form2:()V:
+regs: 0007; ins: 0000; outs: 0002
+  0000: const-wide/16 v0, #long 0 // #0000
+  0002: const/4 v2, #int 1 // #1
+  0003: move-wide v4, v0
+  0004: move v6, v2
+  0005: move v0, v6
+  0006: move-wide v1, v4
+  0007: move v3, v6
+  0008: invoke-static {v3}, Blort.consume1:(I)V
+  000b: invoke-static {v1, v2}, Blort.consume2:(J)V
+  000e: invoke-static {v0}, Blort.consume3:(I)V
+  0011: return-void
+Blort.test_pop:()V:
+regs: 0002; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: invoke-static {v0}, Blort.consume1:(I)V
+  0005: return-void
+Blort.test_pop2_form1:()V:
+regs: 0003; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: const/4 v2, #int 2 // #2
+  0003: invoke-static {v0}, Blort.consume1:(I)V
+  0006: return-void
+Blort.test_pop2_form2:()V:
+regs: 0003; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const-wide/16 v1, #long 0 // #0000
+  0003: invoke-static {v0}, Blort.consume1:(I)V
+  0006: return-void
+Blort.test_swap:()V:
+regs: 0004; ins: 0000; outs: 0001
+  0000: const/4 v0, #int 0 // #0
+  0001: const/4 v1, #int 1 // #1
+  0002: move v2, v0
+  0003: move v3, v1
+  0004: move v0, v3
+  0005: move v1, v2
+  0006: invoke-static {v1}, Blort.consume1:(I)V
+  0009: invoke-static {v0}, Blort.consume2:(I)V
+  000c: return-void
diff --git a/dx/tests/071-dex-java-stack-ops/info.txt b/dx/tests/071-dex-java-stack-ops/info.txt
new file mode 100644
index 0000000..6c5383a
--- /dev/null
+++ b/dx/tests/071-dex-java-stack-ops/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to see that at
+least one case of each of the possible forms of Java stack
+manipulation op translate reasonably.
+
+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/071-dex-java-stack-ops/run b/dx/tests/071-dex-java-stack-ops/run
new file mode 100644
index 0000000..52d8a77
--- /dev/null
+++ b/dx/tests/071-dex-java-stack-ops/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/072-dex-switch-edge-cases/Blort.java b/dx/tests/072-dex-switch-edge-cases/Blort.java
new file mode 100644
index 0000000..2d4d107
--- /dev/null
+++ b/dx/tests/072-dex-switch-edge-cases/Blort.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    // Empty switch statement. (Note: This is the same as a default-only
+    // switch statement, since under the covers every switch statement
+    // has a default of some sort.)
+    public int test1(int x) {
+        switch (x) {
+            // This space intentionally left blank.
+        }
+
+        return 0;
+    }
+
+    // Single element.
+    public int test2(int x) {
+        switch (x) {
+            case 0: return 0;
+        }
+
+        return 1;
+    }
+
+    // Single element: Integer.MIN_VALUE.
+    public int test3(int x) {
+        switch (x) {
+            case Integer.MIN_VALUE: return 0;
+        }
+
+        return 1;
+    }
+
+    // Single element: Integer.MAX_VALUE.
+    public int test4(int x) {
+        switch (x) {
+            case Integer.MAX_VALUE: return 0;
+        }
+
+        return 1;
+    }
+
+    // Two elements: 0 and Integer.MIN_VALUE.
+    public int test5(int x) {
+        switch (x) {
+            case 0: return 0;
+            case Integer.MIN_VALUE: return 1;
+        }
+
+        return 2;
+    }
+
+    // Two elements: 0 and Integer.MAX_VALUE.
+    public int test6(int x) {
+        switch (x) {
+            case 0: return 0;
+            case Integer.MAX_VALUE: return 1;
+        }
+
+        return 2;
+    }
+
+    // Two elements: Integer.MIN_VALUE and Integer.MAX_VALUE.
+    public int test7(int x) {
+        switch (x) {
+            case Integer.MIN_VALUE: return 0;
+            case Integer.MAX_VALUE: return 1;
+        }
+
+        return 2;
+    }
+
+    // Two elements: Large enough to be packed but such that 32 bit
+    // threshold calculations could overflow.
+    public int test8(int x) {
+        switch (x) {
+            case 0: return 0;
+            case 0x4cccccc8: return 1;
+        }
+
+        return 2;
+    }
+}
diff --git a/dx/tests/072-dex-switch-edge-cases/expected.txt b/dx/tests/072-dex-switch-edge-cases/expected.txt
new file mode 100644
index 0000000..38a467a
--- /dev/null
+++ b/dx/tests/072-dex-switch-edge-cases/expected.txt
@@ -0,0 +1,126 @@
+Blort.test1:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: const/4 v2, #int 0 // #0
+  0004: move v0, v2
+  0005: return v0
+Blort.test2:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: packed-switch v2, 000c // +0009
+  0006: const/4 v2, #int 1 // #1
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: packed-switch-payload // for switch @ 0003
+          0: 00000009 // +00000006
+Blort.test3:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: packed-switch v2, 000c // +0009
+  0006: const/4 v2, #int 1 // #1
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: packed-switch-payload // for switch @ 0003
+          -2147483648: 00000009 // +00000006
+Blort.test4:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: packed-switch v2, 000c // +0009
+  0006: const/4 v2, #int 1 // #1
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: packed-switch-payload // for switch @ 0003
+          2147483647: 00000009 // +00000006
+Blort.test5:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: sparse-switch v2, 0010 // +000d
+  0006: const/4 v2, #int 2 // #2
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: const/4 v2, #int 1 // #1
+  000d: move v0, v2
+  000e: goto 0008 // -0006
+  000f: nop // spacer
+  0010: sparse-switch-payload // for switch @ 0003
+          -2147483648: 0000000c // +00000009
+          0: 00000009 // +00000006
+Blort.test6:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: sparse-switch v2, 0010 // +000d
+  0006: const/4 v2, #int 2 // #2
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: const/4 v2, #int 1 // #1
+  000d: move v0, v2
+  000e: goto 0008 // -0006
+  000f: nop // spacer
+  0010: sparse-switch-payload // for switch @ 0003
+          0: 00000009 // +00000006
+          2147483647: 0000000c // +00000009
+Blort.test7:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: sparse-switch v2, 0010 // +000d
+  0006: const/4 v2, #int 2 // #2
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: const/4 v2, #int 1 // #1
+  000d: move v0, v2
+  000e: goto 0008 // -0006
+  000f: nop // spacer
+  0010: sparse-switch-payload // for switch @ 0003
+          -2147483648: 00000009 // +00000006
+          2147483647: 0000000c // +00000009
+Blort.test8:(I)I:
+regs: 0005; ins: 0002; outs: 0000
+  0000: move-object v0, v3
+  0001: move v1, v4
+  0002: move v2, v1
+  0003: sparse-switch v2, 0010 // +000d
+  0006: const/4 v2, #int 2 // #2
+  0007: move v0, v2
+  0008: return v0
+  0009: const/4 v2, #int 0 // #0
+  000a: move v0, v2
+  000b: goto 0008 // -0003
+  000c: const/4 v2, #int 1 // #1
+  000d: move v0, v2
+  000e: goto 0008 // -0006
+  000f: nop // spacer
+  0010: sparse-switch-payload // for switch @ 0003
+          0: 00000009 // +00000006
+          1288490184: 0000000c // +00000009
diff --git a/dx/tests/072-dex-switch-edge-cases/info.txt b/dx/tests/072-dex-switch-edge-cases/info.txt
new file mode 100644
index 0000000..4c7b42c
--- /dev/null
+++ b/dx/tests/072-dex-switch-edge-cases/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+a bunch of switch op edge cases get converted reasonably.
+
+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/072-dex-switch-edge-cases/run b/dx/tests/072-dex-switch-edge-cases/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/072-dex-switch-edge-cases/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/073-dex-null-array-refs/Blort.java b/dx/tests/073-dex-null-array-refs/Blort.java
new file mode 100644
index 0000000..e16e0f4
--- /dev/null
+++ b/dx/tests/073-dex-null-array-refs/Blort.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static Object test1() {
+        return ((Object[]) null)[0];
+    }
+
+    public static void test2() {
+        ((Object[]) null)[0] = null;
+    }
+
+    public static int test3() {
+        return ((Object[]) null).length;
+    }
+
+    public static Object test4() {
+        Object[] arr = null;
+        return arr[0];
+    }
+
+    public static void test5() {
+        Object[] arr = null;
+        arr[0] = null;
+    }
+
+    public static int test6() {
+        Object[] arr = null;
+        return arr.length;
+    }
+
+    public static Object test7(Object[] arr) {
+        if (check()) {
+            arr = null;
+        }
+
+        return arr[0];
+    }
+
+    public static void test8(Object[] arr) {
+        if (check()) {
+            arr = null;
+        }
+
+        arr[0] = null;
+    }
+
+    public static int test9(Object[] arr) {
+        if (check()) {
+            arr = null;
+        }
+
+        return arr.length;
+    }
+
+    public static boolean check() {
+        return true;
+    }
+}
diff --git a/dx/tests/073-dex-null-array-refs/expected.txt b/dx/tests/073-dex-null-array-refs/expected.txt
new file mode 100644
index 0000000..7f3ee21
--- /dev/null
+++ b/dx/tests/073-dex-null-array-refs/expected.txt
@@ -0,0 +1,85 @@
+Blort.test1:()Ljava/lang/Object;:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v0, #null // #0
+  0001: check-cast v0, java.lang.Object[]
+  0003: const/4 v1, #int 0 // #0
+  0004: aget-object v0, v0, v1
+  0006: return-object v0
+Blort.test2:()V:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v0, #null // #0
+  0001: check-cast v0, java.lang.Object[]
+  0003: const/4 v1, #int 0 // #0
+  0004: const/4 v2, #null // #0
+  0005: aput-object v2, v0, v1
+  0007: return-void
+Blort.test3:()I:
+regs: 0001; ins: 0000; outs: 0000
+  0000: const/4 v0, #null // #0
+  0001: check-cast v0, java.lang.Object[]
+  0003: array-length v0, v0
+  0004: return v0
+Blort.test4:()Ljava/lang/Object;:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v1, #null // #0
+  0001: move-object v0, v1
+  0002: move-object v1, v0
+  0003: const/4 v2, #int 0 // #0
+  0004: aget-object v1, v1, v2
+  0006: move-object v0, v1
+  0007: return-object v0
+Blort.test5:()V:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v1, #null // #0
+  0001: move-object v0, v1
+  0002: move-object v1, v0
+  0003: const/4 v2, #int 0 // #0
+  0004: const/4 v3, #null // #0
+  0005: aput-object v3, v1, v2
+  0007: return-void
+Blort.test6:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: const/4 v1, #null // #0
+  0001: move-object v0, v1
+  0002: move-object v1, v0
+  0003: array-length v1, v1
+  0004: move v0, v1
+  0005: return v0
+Blort.test7:([Ljava/lang/Object;)Ljava/lang/Object;:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move-object v0, v3
+  0001: invoke-static {}, Blort.check:()Z
+  0004: move-result v1
+  0005: if-eqz v1, 0009 // +0004
+  0007: const/4 v1, #null // #0
+  0008: move-object v0, v1
+  0009: move-object v1, v0
+  000a: const/4 v2, #int 0 // #0
+  000b: aget-object v1, v1, v2
+  000d: move-object v0, v1
+  000e: return-object v0
+Blort.test8:([Ljava/lang/Object;)V:
+regs: 0005; ins: 0001; outs: 0000
+  0000: move-object v0, v4
+  0001: invoke-static {}, Blort.check:()Z
+  0004: move-result v1
+  0005: if-eqz v1, 0009 // +0004
+  0007: const/4 v1, #null // #0
+  0008: move-object v0, v1
+  0009: move-object v1, v0
+  000a: const/4 v2, #int 0 // #0
+  000b: const/4 v3, #null // #0
+  000c: aput-object v3, v1, v2
+  000e: return-void
+Blort.test9:([Ljava/lang/Object;)I:
+regs: 0003; ins: 0001; outs: 0000
+  0000: move-object v0, v2
+  0001: invoke-static {}, Blort.check:()Z
+  0004: move-result v1
+  0005: if-eqz v1, 0009 // +0004
+  0007: const/4 v1, #null // #0
+  0008: move-object v0, v1
+  0009: move-object v1, v0
+  000a: array-length v1, v1
+  000b: move v0, v1
+  000c: return v0
diff --git a/dx/tests/073-dex-null-array-refs/info.txt b/dx/tests/073-dex-null-array-refs/info.txt
new file mode 100644
index 0000000..ca3b161
--- /dev/null
+++ b/dx/tests/073-dex-null-array-refs/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to see that
+a bunch of cases convert reasonably, where necessarily or possibly
+null array references are used.
+
+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/073-dex-null-array-refs/run b/dx/tests/073-dex-null-array-refs/run
new file mode 100644
index 0000000..52f1131
--- /dev/null
+++ b/dx/tests/073-dex-null-array-refs/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/074-dex-form35c-edge-case/Blort.java b/dx/tests/074-dex-form35c-edge-case/Blort.java
new file mode 100644
index 0000000..979263f
--- /dev/null
+++ b/dx/tests/074-dex-form35c-edge-case/Blort.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public void test()
+    {
+        int i1 = 0;
+        int i2 = 0;
+        int i3 = 0;
+        int i4 = 0;
+        int i5 = 0;
+        int i6 = 0;
+        int i7 = 0;
+        int i8 = 0;
+        int i9 = 0;
+        int i10 = 0;
+        int i11 = 0;
+        int i12 = 0;
+        int i13 = 0;
+
+        blort(0);
+    }
+
+    public void blort(long x) {
+        // blank
+    }
+}
diff --git a/dx/tests/074-dex-form35c-edge-case/expected.txt b/dx/tests/074-dex-form35c-edge-case/expected.txt
new file mode 100644
index 0000000..6afdcd7
--- /dev/null
+++ b/dx/tests/074-dex-form35c-edge-case/expected.txt
@@ -0,0 +1,33 @@
+Blort.test:()V:
+regs: 0012; ins: 0001; outs: 0003
+  0000: move-object/from16 v0, v17
+  0002: const/4 v14, #int 0 // #0
+  0003: move v1, v14
+  0004: const/4 v14, #int 0 // #0
+  0005: move v2, v14
+  0006: const/4 v14, #int 0 // #0
+  0007: move v3, v14
+  0008: const/4 v14, #int 0 // #0
+  0009: move v4, v14
+  000a: const/4 v14, #int 0 // #0
+  000b: move v5, v14
+  000c: const/4 v14, #int 0 // #0
+  000d: move v6, v14
+  000e: const/4 v14, #int 0 // #0
+  000f: move v7, v14
+  0010: const/4 v14, #int 0 // #0
+  0011: move v8, v14
+  0012: const/4 v14, #int 0 // #0
+  0013: move v9, v14
+  0014: const/4 v14, #int 0 // #0
+  0015: move v10, v14
+  0016: const/4 v14, #int 0 // #0
+  0017: move v11, v14
+  0018: const/4 v14, #int 0 // #0
+  0019: move v12, v14
+  001a: const/4 v14, #int 0 // #0
+  001b: move v13, v14
+  001c: move-object v14, v0
+  001d: const-wide/16 v15, #long 0 // #0000
+  001f: invoke-virtual/range {v14..v16}, Blort.blort:(J)V
+  0022: return-void
diff --git a/dx/tests/074-dex-form35c-edge-case/info.txt b/dx/tests/074-dex-form35c-edge-case/info.txt
new file mode 100644
index 0000000..51d83bd
--- /dev/null
+++ b/dx/tests/074-dex-form35c-edge-case/info.txt
@@ -0,0 +1,8 @@
+This is a smoke test of dex conversion, which checks to see that
+an edge case of instruction format 35c works, where a reference
+is made to register 15 as a category-2 value, meaning that
+the instruction has to be rewritten to use a different format.
+
+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/074-dex-form35c-edge-case/run b/dx/tests/074-dex-form35c-edge-case/run
new file mode 100644
index 0000000..7578321
--- /dev/null
+++ b/dx/tests/074-dex-form35c-edge-case/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test *.class
diff --git a/dx/tests/075-dex-cat2-value-merge/Blort.java b/dx/tests/075-dex-cat2-value-merge/Blort.java
new file mode 100644
index 0000000..0aa4c5a
--- /dev/null
+++ b/dx/tests/075-dex-cat2-value-merge/Blort.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void test(long[] arr)
+    {
+        long x = 0;
+
+        for (;;) {
+            x += arr[0];
+        }
+    }
+}
diff --git a/dx/tests/075-dex-cat2-value-merge/expected.txt b/dx/tests/075-dex-cat2-value-merge/expected.txt
new file mode 100644
index 0000000..e1b9b1b
--- /dev/null
+++ b/dx/tests/075-dex-cat2-value-merge/expected.txt
@@ -0,0 +1,12 @@
+Blort.test:([J)V:
+regs: 0008; ins: 0001; outs: 0000
+  0000: move-object v0, v7
+  0001: const-wide/16 v3, #long 0 // #0000
+  0003: move-wide v1, v3
+  0004: move-wide v3, v1
+  0005: move-object v5, v0
+  0006: const/4 v6, #int 0 // #0
+  0007: aget-wide v5, v5, v6
+  0009: add-long/2addr v3, v5
+  000a: move-wide v1, v3
+  000b: goto 0004 // -0007
diff --git a/dx/tests/075-dex-cat2-value-merge/info.txt b/dx/tests/075-dex-cat2-value-merge/info.txt
new file mode 100644
index 0000000..de411b8
--- /dev/null
+++ b/dx/tests/075-dex-cat2-value-merge/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to see that
+when a known value of category-2 gets merged during control
+flow analysis, things don't break.
+
+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/075-dex-cat2-value-merge/run b/dx/tests/075-dex-cat2-value-merge/run
new file mode 100644
index 0000000..7578321
--- /dev/null
+++ b/dx/tests/075-dex-cat2-value-merge/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test *.class
diff --git a/dx/tests/076-dex-synch-and-stack/Blort.java b/dx/tests/076-dex-synch-and-stack/Blort.java
new file mode 100644
index 0000000..8a83492
--- /dev/null
+++ b/dx/tests/076-dex-synch-and-stack/Blort.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public synchronized void test() {
+        new Object();
+    }
+}
diff --git a/dx/tests/076-dex-synch-and-stack/expected.txt b/dx/tests/076-dex-synch-and-stack/expected.txt
new file mode 100644
index 0000000..eba839e
--- /dev/null
+++ b/dx/tests/076-dex-synch-and-stack/expected.txt
@@ -0,0 +1,19 @@
+Blort.test:()V:
+regs: 0006; ins: 0001; outs: 0001
+  0000: move-object v0, v5
+  0001: move-object v3, v5
+  0002: monitor-enter v3
+  0003: new-instance v1, java.lang.Object
+  0005: move-object v4, v1
+  0006: move-object v1, v4
+  0007: move-object v2, v4
+  0008: invoke-direct {v2}, java.lang.Object.<init>:()V
+  000b: monitor-exit v3
+  000c: return-void
+  000d: move-exception v0
+  000e: monitor-exit v3
+  000f: throw v0
+  catches
+    tries:
+      try 0003..000b
+      catch <any> -> 000d
diff --git a/dx/tests/076-dex-synch-and-stack/info.txt b/dx/tests/076-dex-synch-and-stack/info.txt
new file mode 100644
index 0000000..ab5206f
--- /dev/null
+++ b/dx/tests/076-dex-synch-and-stack/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to make sure that
+the synchronized method conversion doesn't interact poorly with stack
+operation unwinding.
+
+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/076-dex-synch-and-stack/run b/dx/tests/076-dex-synch-and-stack/run
new file mode 100644
index 0000000..7578321
--- /dev/null
+++ b/dx/tests/076-dex-synch-and-stack/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test *.class
diff --git a/dx/tests/077-dex-code-alignment/Blort.java b/dx/tests/077-dex-code-alignment/Blort.java
new file mode 100644
index 0000000..3ec041a
--- /dev/null
+++ b/dx/tests/077-dex-code-alignment/Blort.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void justReturn1() {
+        // This space intentionally left blank.
+    }
+
+    public static void justReturn2() {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dx/tests/077-dex-code-alignment/expected.txt b/dx/tests/077-dex-code-alignment/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dx/tests/077-dex-code-alignment/expected.txt
diff --git a/dx/tests/077-dex-code-alignment/info.txt b/dx/tests/077-dex-code-alignment/info.txt
new file mode 100644
index 0000000..0dd662b
--- /dev/null
+++ b/dx/tests/077-dex-code-alignment/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to make sure that
+code arrays are 4-byte aligned within a dex file.
+
+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/077-dex-code-alignment/run b/dx/tests/077-dex-code-alignment/run
new file mode 100644
index 0000000..f311dbf
--- /dev/null
+++ b/dx/tests/077-dex-code-alignment/run
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+
+# The awk script below attempts to filter out everything but the
+# essentials: That methods justReturn1() and justReturn2() contain
+# a single "return-void" code unit, and that there is an empty (0x0000)
+# code unit between the two of them.
+
+dx --debug --dex --positions=none --no-locals --dump-to=- *.class | awk '
+BEGIN { codes = 0; dump = 0; }
+/codes:/ { codes = 1; }
+codes && /justReturn/ { dump = 1; print "method start"; }
+/string_data:/ { codes = 0; dump = 0; }
+dump && /^......: ....     / { print $2; }
+'
diff --git a/dx/tests/078-dex-local-variable-table/Blort.java b/dx/tests/078-dex-local-variable-table/Blort.java
new file mode 100644
index 0000000..7291445
--- /dev/null
+++ b/dx/tests/078-dex-local-variable-table/Blort.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void test01(Object x) {
+        x.hashCode();
+    }
+
+    public static Object test02() {
+        Object[] arr = null;
+        return arr[0];
+    }
+
+    public static String test03(int x) {
+        String foo = null;
+        return foo;
+    }
+
+    public static String test04(int x) {
+        String foo = null;
+        if (x < 0) {
+            foo = "bar";
+        }
+        return foo;
+    }
+
+    public static int test05(Object x) {
+        int[] arr = (int[]) x;
+        arr[0] = 123;
+        return arr[0];
+    }
+
+    public static int test06(int x) {
+        if (x < 10) {
+            int y = 1;
+            return y;
+        } else {
+            int y = 2;
+            return y;
+        }
+    }
+
+    // Test for representation of boolean.
+    public static void test07(boolean x) {
+        boolean y = x;
+    }
+
+    // Test for representation of byte.
+    public static void test08(byte x) {
+        byte y = x;
+    }
+
+    // Test for representation of char.
+    public static void test09(char x) {
+        char y = x;
+    }
+
+    // Test for representation of double.
+    public static void test10(double x) {
+        double y = x;
+    }
+
+    // Test for representation of float.
+    public static void test11(float x) {
+        float y = x;
+    }
+
+    // Test for representation of int.
+    public static void test12(int x) {
+        int y = x;
+    }
+
+    // Test for representation of long.
+    public static void test13(long x) {
+        long y = x;
+    }
+
+    // Test for representation of short.
+    public static void test14(short x) {
+        short y = x;
+    }
+
+    // Test for representation of Object.
+    public static void test15(Object x) {
+        Object y = x;
+    }
+
+    // Test for representation of String (as a token example of a non-Object
+    // reference type).
+    public static void test16(String x) {
+        String y = x;
+    }
+
+    // Test for representation of int[] (as a token example of an array class).
+    public static void test17(int[] x) {
+        int[] y = x;
+    }
+}
diff --git a/dx/tests/078-dex-local-variable-table/expected.txt b/dx/tests/078-dex-local-variable-table/expected.txt
new file mode 100644
index 0000000..3e5cd69
--- /dev/null
+++ b/dx/tests/078-dex-local-variable-table/expected.txt
@@ -0,0 +1,314 @@
+Blort.test01:(Ljava/lang/Object;)V:
+regs: 0003; ins: 0001; outs: 0001
+  0000: move-object v0, v2
+  0001: move-object v1, v0
+  0002: invoke-virtual {v1}, java.lang.Object.hashCode:()I
+  0005: move-result v1
+  0006: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v2
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x java.lang.Object
+    end sequence
+Blort.test02:()Ljava/lang/Object;:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/4 v1, #null // #0
+  0001: move-object v0, v1
+  0002: move-object v1, v0
+  0003: const/4 v2, #int 0 // #0
+  0004: aget-object v1, v1, v2
+  0006: move-object v0, v1
+  0007: return-object v0
+  debug info
+    line_start: 1
+    parameters_size: 0000
+    0000: prologue end
+    0002: advance pc
+    0002: +local v0 arr java.lang.Object[]
+    0007: advance pc
+    0007: -local v0 arr java.lang.Object[]
+    end sequence
+Blort.test03:(I)Ljava/lang/String;:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: const/4 v2, #null // #0
+  0002: move-object v1, v2
+  0003: move-object v2, v1
+  0004: move-object v0, v2
+  0005: return-object v0
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x int
+    0003: advance pc
+    0003: +local v1 foo java.lang.String
+    0005: advance pc
+    0005: -local v0 x int
+    end sequence
+Blort.test04:(I)Ljava/lang/String;:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: const/4 v2, #null // #0
+  0002: move-object v1, v2
+  0003: move v2, v0
+  0004: if-gez v2, 0009 // +0005
+  0006: const-string v2, "bar"
+  0008: move-object v1, v2
+  0009: move-object v2, v1
+  000a: move-object v0, v2
+  000b: return-object v0
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x int
+    0003: advance pc
+    0003: +local v1 foo java.lang.String
+    000b: advance pc
+    000b: -local v0 x int
+    end sequence
+Blort.test05:(Ljava/lang/Object;)I:
+regs: 0006; ins: 0001; outs: 0000
+  0000: move-object v0, v5
+  0001: move-object v2, v0
+  0002: check-cast v2, int[]
+  0004: check-cast v2, int[]
+  0006: move-object v1, v2
+  0007: move-object v2, v1
+  0008: const/4 v3, #int 0 // #0
+  0009: const/16 v4, #int 123 // #007b
+  000b: aput v4, v2, v3
+  000d: move-object v2, v1
+  000e: const/4 v3, #int 0 // #0
+  000f: aget v2, v2, v3
+  0011: move v0, v2
+  0012: return v0
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v5
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x java.lang.Object
+    0007: advance pc
+    0007: +local v1 arr int[]
+    0012: advance pc
+    0012: -local v0 x java.lang.Object
+    end sequence
+Blort.test06:(I)I:
+regs: 0005; ins: 0001; outs: 0000
+  0000: move v0, v4
+  0001: move v2, v0
+  0002: const/16 v3, #int 10 // #000a
+  0004: if-ge v2, v3, 000b // +0007
+  0006: const/4 v2, #int 1 // #1
+  0007: move v1, v2
+  0008: move v2, v1
+  0009: move v0, v2
+  000a: return v0
+  000b: const/4 v2, #int 2 // #2
+  000c: move v1, v2
+  000d: move v2, v1
+  000e: move v0, v2
+  000f: goto 000a // -0005
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v4
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x int
+    0008: advance pc
+    0008: +local v1 y int
+    000a: advance pc
+    000a: -local v0 x int
+    000b: advance pc
+    000b: -local v1 y int
+    000b: +local restart v0 x int
+    000d: advance pc
+    000d: +local restart v1 y int
+    end sequence
+Blort.test07:(Z)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: move v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x boolean
+    0003: advance pc
+    0003: +local v1 y boolean
+    end sequence
+Blort.test08:(B)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: move v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x byte
+    0003: advance pc
+    0003: +local v1 y byte
+    end sequence
+Blort.test09:(C)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: move v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x char
+    0003: advance pc
+    0003: +local v1 y char
+    end sequence
+Blort.test10:(D)V:
+regs: 0008; ins: 0002; outs: 0000
+  0000: move-wide v0, v6
+  0001: move-wide v4, v0
+  0002: move-wide v2, v4
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v6
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x double
+    0003: advance pc
+    0003: +local v2 y double
+    end sequence
+Blort.test11:(F)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: move v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x float
+    0003: advance pc
+    0003: +local v1 y float
+    end sequence
+Blort.test12:(I)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: move v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x int
+    0003: advance pc
+    0003: +local v1 y int
+    end sequence
+Blort.test13:(J)V:
+regs: 0008; ins: 0002; outs: 0000
+  0000: move-wide v0, v6
+  0001: move-wide v4, v0
+  0002: move-wide v2, v4
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v6
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x long
+    0003: advance pc
+    0003: +local v2 y long
+    end sequence
+Blort.test14:(S)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: move v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x short
+    0003: advance pc
+    0003: +local v1 y short
+    end sequence
+Blort.test15:(Ljava/lang/Object;)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move-object v0, v3
+  0001: move-object v2, v0
+  0002: move-object v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x java.lang.Object
+    0003: advance pc
+    0003: +local v1 y java.lang.Object
+    end sequence
+Blort.test16:(Ljava/lang/String;)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move-object v0, v3
+  0001: move-object v2, v0
+  0002: move-object v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x java.lang.String
+    0003: advance pc
+    0003: +local v1 y java.lang.String
+    end sequence
+Blort.test17:([I)V:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move-object v0, v3
+  0001: move-object v2, v0
+  0002: move-object v1, v2
+  0003: return-void
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v3
+    0000: prologue end
+    0001: advance pc
+    0001: +local v0 x int[]
+    0003: advance pc
+    0003: +local v1 y int[]
+    end sequence
diff --git a/dx/tests/078-dex-local-variable-table/info.txt b/dx/tests/078-dex-local-variable-table/info.txt
new file mode 100644
index 0000000..7834271
--- /dev/null
+++ b/dx/tests/078-dex-local-variable-table/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to make sure that
+local variable tables get emitted properly.
+
+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/078-dex-local-variable-table/run b/dx/tests/078-dex-local-variable-table/run
new file mode 100644
index 0000000..426f1e6
--- /dev/null
+++ b/dx/tests/078-dex-local-variable-table/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --dump-method=Blort.test'*' \
+    *.class
diff --git a/dx/tests/079-dex-local-variable-renumbering/Blort.java b/dx/tests/079-dex-local-variable-renumbering/Blort.java
new file mode 100644
index 0000000..c8453a2
--- /dev/null
+++ b/dx/tests/079-dex-local-variable-renumbering/Blort.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static int test1(int x) {
+        float f0 = 0.0f;
+        float f1 = 0.0f;
+        float f2 = 0.0f;
+        float f3 = 0.0f;
+        float f4 = 0.0f;
+        float f5 = 0.0f;
+        float f6 = 0.0f;
+        float f7 = 0.0f;
+        float f8 = 0.0f;
+        float f9 = 0.0f;
+        float f10 = 0.0f;
+        float f11 = 0.0f;
+        float f12 = 0.0f;
+        float f13 = 0.0f;
+        float f14 = 0.0f;
+        float f15 = 0.0f;
+        int x16 = x;
+        return -x16;
+    }
+}
diff --git a/dx/tests/079-dex-local-variable-renumbering/expected.txt b/dx/tests/079-dex-local-variable-renumbering/expected.txt
new file mode 100644
index 0000000..94ba113
--- /dev/null
+++ b/dx/tests/079-dex-local-variable-renumbering/expected.txt
@@ -0,0 +1,87 @@
+Blort.test1:(I)I:
+regs: 0015; ins: 0001; outs: 0000
+  0000: move/from16 v1, v20
+  0002: const/16 v19, #float 0.0 // #0000
+  0004: move/from16 v2, v19
+  0006: const/16 v19, #float 0.0 // #0000
+  0008: move/from16 v3, v19
+  000a: const/16 v19, #float 0.0 // #0000
+  000c: move/from16 v4, v19
+  000e: const/16 v19, #float 0.0 // #0000
+  0010: move/from16 v5, v19
+  0012: const/16 v19, #float 0.0 // #0000
+  0014: move/from16 v6, v19
+  0016: const/16 v19, #float 0.0 // #0000
+  0018: move/from16 v7, v19
+  001a: const/16 v19, #float 0.0 // #0000
+  001c: move/from16 v8, v19
+  001e: const/16 v19, #float 0.0 // #0000
+  0020: move/from16 v9, v19
+  0022: const/16 v19, #float 0.0 // #0000
+  0024: move/from16 v10, v19
+  0026: const/16 v19, #float 0.0 // #0000
+  0028: move/from16 v11, v19
+  002a: const/16 v19, #float 0.0 // #0000
+  002c: move/from16 v12, v19
+  002e: const/16 v19, #float 0.0 // #0000
+  0030: move/from16 v13, v19
+  0032: const/16 v19, #float 0.0 // #0000
+  0034: move/from16 v14, v19
+  0036: const/16 v19, #float 0.0 // #0000
+  0038: move/from16 v15, v19
+  003a: const/16 v19, #float 0.0 // #0000
+  003c: move/from16 v16, v19
+  003e: const/16 v19, #float 0.0 // #0000
+  0040: move/from16 v17, v19
+  0042: move/from16 v19, v1
+  0044: move/from16 v18, v19
+  0046: move/from16 v19, v18
+  0048: move/from16 v0, v19
+  004a: neg-int v0, v0
+  004b: move/from16 v19, v0
+  004d: move/from16 v1, v19
+  004f: return v1
+  debug info
+    line_start: 1
+    parameters_size: 0001
+    parameter <unnamed> v20
+    0000: prologue end
+    0002: advance pc
+    0002: +local v1 x int
+    0006: advance pc
+    0006: +local v2 f0 float
+    000a: advance pc
+    000a: +local v3 f1 float
+    000e: advance pc
+    000e: +local v4 f2 float
+    0012: advance pc
+    0012: +local v5 f3 float
+    0016: advance pc
+    0016: +local v6 f4 float
+    001a: advance pc
+    001a: +local v7 f5 float
+    001e: advance pc
+    001e: +local v8 f6 float
+    0022: advance pc
+    0022: +local v9 f7 float
+    0026: advance pc
+    0026: +local v10 f8 float
+    002a: advance pc
+    002a: +local v11 f9 float
+    002e: advance pc
+    002e: +local v12 f10 float
+    0032: advance pc
+    0032: +local v13 f11 float
+    0036: advance pc
+    0036: +local v14 f12 float
+    003a: advance pc
+    003a: +local v15 f13 float
+    003e: advance pc
+    003e: +local v16 f14 float
+    0042: advance pc
+    0042: +local v17 f15 float
+    0046: advance pc
+    0046: +local v18 x16 int
+    004f: advance pc
+    004f: -local v1 x int
+    end sequence
diff --git a/dx/tests/079-dex-local-variable-renumbering/info.txt b/dx/tests/079-dex-local-variable-renumbering/info.txt
new file mode 100644
index 0000000..249b23f
--- /dev/null
+++ b/dx/tests/079-dex-local-variable-renumbering/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to make sure that
+local variable tables stay in sync when the register set gets renumbered
+to make room for low scratch registers.
+
+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/079-dex-local-variable-renumbering/run b/dx/tests/079-dex-local-variable-renumbering/run
new file mode 100644
index 0000000..426f1e6
--- /dev/null
+++ b/dx/tests/079-dex-local-variable-renumbering/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --dump-method=Blort.test'*' \
+    *.class
diff --git a/dx/tests/080-dex-exception-tables/Blort.java b/dx/tests/080-dex-exception-tables/Blort.java
new file mode 100644
index 0000000..2143f7f
--- /dev/null
+++ b/dx/tests/080-dex-exception-tables/Blort.java
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public static void call1() { }
+    public static void call2() { }
+    public static void call3() { }
+    public static void call4() { }
+    public static void call5() { }
+
+    public static int test1() {
+        try {
+            call1();
+            call2();
+        } catch (IndexOutOfBoundsException ex) {
+            return 10;
+        } catch (RuntimeException ex) {
+            return 11;
+        }
+
+        call3();
+        return 12;
+    }
+
+    public static int test2() {
+        try {
+            call1();
+            try {
+                call2();
+            } catch (IndexOutOfBoundsException ex) {
+                return 10;
+            }
+            call3();
+        } catch (RuntimeException ex) {
+            return 11;
+        }
+
+        return 12;
+    }
+
+    public static int test3() {
+        try {
+            call1();
+            try {
+                call2();
+                try {
+                    call3();
+                } catch (NullPointerException ex) {
+                    return 10;
+                }
+                call4();
+            } catch (IndexOutOfBoundsException ex) {
+                return 11;
+            }
+            call5();
+        } catch (RuntimeException ex) {
+            return 12;
+        }
+
+        return 13;
+    }
+
+    public static int test4() {
+        try {
+            call1();
+            try {
+                call2();
+                try {
+                    call3();
+                } catch (NullPointerException ex) {
+                    return 10;
+                }
+            } catch (IndexOutOfBoundsException ex) {
+                return 11;
+            }
+            call5();
+        } catch (RuntimeException ex) {
+            return 12;
+        }
+
+        return 13;
+    }
+
+    public static int test5() {
+        try {
+            call1();
+            try {
+                call2();
+                try {
+                    call3();
+                } catch (NullPointerException ex) {
+                    return 10;
+                }
+            } catch (IndexOutOfBoundsException ex) {
+                return 11;
+            }
+        } catch (RuntimeException ex) {
+            return 12;
+        }
+
+        return 13;
+    }
+
+    public static int test6() {
+        try {
+            try {
+                try {
+                    call1();
+                } catch (NullPointerException ex) {
+                    return 10;
+                }
+                call2();
+            } catch (IndexOutOfBoundsException ex) {
+                return 11;
+            }
+            call3();
+        } catch (RuntimeException ex) {
+            return 12;
+        }
+
+        call4();
+        return 13;
+    }
+
+    public static int test7() {
+        try {
+            call1();
+        } catch (RuntimeException ex) {
+            return 10;
+        }
+
+        try {
+            call2();
+        } catch (RuntimeException ex) {
+            return 11;
+        }
+
+        return 12;
+    }
+
+    public static int test8() {
+        try {
+            call1();
+            call2();
+        } catch (RuntimeException ex) {
+            return 10;
+        }
+
+        try {
+            call3();
+            call4();
+        } catch (RuntimeException ex) {
+            return 11;
+        }
+
+        return 12;
+    }
+
+    public static int test9() {
+        try {
+            call1();
+            try {
+                call2();
+            } catch (IllegalArgumentException ex) {
+                return 10;
+            }
+        } catch (RuntimeException ex) {
+            return 11;
+        }
+
+        try {
+            call3();
+            try {
+                call4();
+            } catch (IllegalArgumentException ex) {
+                return 12;
+            }
+        } catch (RuntimeException ex) {
+            return 13;
+        }
+
+        return 14;
+    }
+
+}
diff --git a/dx/tests/080-dex-exception-tables/expected.txt b/dx/tests/080-dex-exception-tables/expected.txt
new file mode 100644
index 0000000..4cf43f1
--- /dev/null
+++ b/dx/tests/080-dex-exception-tables/expected.txt
@@ -0,0 +1,286 @@
+Blort.test1:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: const/16 v1, #int 12 // #000c
+  000b: move v0, v1
+  000c: return v0
+  000d: move-exception v1
+  000e: move-object v0, v1
+  000f: const/16 v1, #int 10 // #000a
+  0011: move v0, v1
+  0012: goto 000c // -0006
+  0013: move-exception v1
+  0014: move-object v0, v1
+  0015: const/16 v1, #int 11 // #000b
+  0017: move v0, v1
+  0018: goto 000c // -000c
+  catches
+    tries:
+      try 0000..0006
+      catch java.lang.IndexOutOfBoundsException -> 000d,
+        java.lang.RuntimeException -> 0013
+Blort.test2:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: const/16 v1, #int 12 // #000c
+  000b: move v0, v1
+  000c: return v0
+  000d: move-exception v1
+  000e: move-object v0, v1
+  000f: const/16 v1, #int 10 // #000a
+  0011: move v0, v1
+  0012: goto 000c // -0006
+  0013: move-exception v1
+  0014: move-object v0, v1
+  0015: const/16 v1, #int 11 // #000b
+  0017: move v0, v1
+  0018: goto 000c // -000c
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 0013
+      try 0003..0006
+      catch java.lang.IndexOutOfBoundsException -> 000d,
+        java.lang.RuntimeException -> 0013
+      try 0006..0009
+      catch java.lang.RuntimeException -> 0013
+Blort.test3:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: invoke-static {}, Blort.call4:()V
+  000c: invoke-static {}, Blort.call5:()V
+  000f: const/16 v1, #int 13 // #000d
+  0011: move v0, v1
+  0012: return v0
+  0013: move-exception v1
+  0014: move-object v0, v1
+  0015: const/16 v1, #int 10 // #000a
+  0017: move v0, v1
+  0018: goto 0012 // -0006
+  0019: move-exception v1
+  001a: move-object v0, v1
+  001b: const/16 v1, #int 11 // #000b
+  001d: move v0, v1
+  001e: goto 0012 // -000c
+  001f: move-exception v1
+  0020: move-object v0, v1
+  0021: const/16 v1, #int 12 // #000c
+  0023: move v0, v1
+  0024: goto 0012 // -0012
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 001f
+      try 0003..0006
+      catch java.lang.IndexOutOfBoundsException -> 0019,
+        java.lang.RuntimeException -> 001f
+      try 0006..0009
+      catch java.lang.NullPointerException -> 0013,
+        java.lang.IndexOutOfBoundsException -> 0019,
+        java.lang.RuntimeException -> 001f
+      try 0009..000c
+      catch java.lang.IndexOutOfBoundsException -> 0019,
+        java.lang.RuntimeException -> 001f
+      try 000c..000f
+      catch java.lang.RuntimeException -> 001f
+Blort.test4:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: invoke-static {}, Blort.call5:()V
+  000c: const/16 v1, #int 13 // #000d
+  000e: move v0, v1
+  000f: return v0
+  0010: move-exception v1
+  0011: move-object v0, v1
+  0012: const/16 v1, #int 10 // #000a
+  0014: move v0, v1
+  0015: goto 000f // -0006
+  0016: move-exception v1
+  0017: move-object v0, v1
+  0018: const/16 v1, #int 11 // #000b
+  001a: move v0, v1
+  001b: goto 000f // -000c
+  001c: move-exception v1
+  001d: move-object v0, v1
+  001e: const/16 v1, #int 12 // #000c
+  0020: move v0, v1
+  0021: goto 000f // -0012
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 001c
+      try 0003..0006
+      catch java.lang.IndexOutOfBoundsException -> 0016,
+        java.lang.RuntimeException -> 001c
+      try 0006..0009
+      catch java.lang.NullPointerException -> 0010,
+        java.lang.IndexOutOfBoundsException -> 0016,
+        java.lang.RuntimeException -> 001c
+      try 0009..000c
+      catch java.lang.RuntimeException -> 001c
+Blort.test5:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: const/16 v1, #int 13 // #000d
+  000b: move v0, v1
+  000c: return v0
+  000d: move-exception v1
+  000e: move-object v0, v1
+  000f: const/16 v1, #int 10 // #000a
+  0011: move v0, v1
+  0012: goto 000c // -0006
+  0013: move-exception v1
+  0014: move-object v0, v1
+  0015: const/16 v1, #int 11 // #000b
+  0017: move v0, v1
+  0018: goto 000c // -000c
+  0019: move-exception v1
+  001a: move-object v0, v1
+  001b: const/16 v1, #int 12 // #000c
+  001d: move v0, v1
+  001e: goto 000c // -0012
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 0019
+      try 0003..0006
+      catch java.lang.IndexOutOfBoundsException -> 0013,
+        java.lang.RuntimeException -> 0019
+      try 0006..0009
+      catch java.lang.NullPointerException -> 000d,
+        java.lang.IndexOutOfBoundsException -> 0013,
+        java.lang.RuntimeException -> 0019
+Blort.test6:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: invoke-static {}, Blort.call4:()V
+  000c: const/16 v1, #int 13 // #000d
+  000e: move v0, v1
+  000f: return v0
+  0010: move-exception v1
+  0011: move-object v0, v1
+  0012: const/16 v1, #int 10 // #000a
+  0014: move v0, v1
+  0015: goto 000f // -0006
+  0016: move-exception v1
+  0017: move-object v0, v1
+  0018: const/16 v1, #int 11 // #000b
+  001a: move v0, v1
+  001b: goto 000f // -000c
+  001c: move-exception v1
+  001d: move-object v0, v1
+  001e: const/16 v1, #int 12 // #000c
+  0020: move v0, v1
+  0021: goto 000f // -0012
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.NullPointerException -> 0010,
+        java.lang.IndexOutOfBoundsException -> 0016,
+        java.lang.RuntimeException -> 001c
+      try 0003..0006
+      catch java.lang.IndexOutOfBoundsException -> 0016,
+        java.lang.RuntimeException -> 001c
+      try 0006..0009
+      catch java.lang.RuntimeException -> 001c
+Blort.test7:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: const/16 v1, #int 12 // #000c
+  0008: move v0, v1
+  0009: return v0
+  000a: move-exception v1
+  000b: move-object v0, v1
+  000c: const/16 v1, #int 10 // #000a
+  000e: move v0, v1
+  000f: goto 0009 // -0006
+  0010: move-exception v1
+  0011: move-object v0, v1
+  0012: const/16 v1, #int 11 // #000b
+  0014: move v0, v1
+  0015: goto 0009 // -000c
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 000a
+      try 0003..0006
+      catch java.lang.RuntimeException -> 0010
+Blort.test8:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: invoke-static {}, Blort.call4:()V
+  000c: const/16 v1, #int 12 // #000c
+  000e: move v0, v1
+  000f: return v0
+  0010: move-exception v1
+  0011: move-object v0, v1
+  0012: const/16 v1, #int 10 // #000a
+  0014: move v0, v1
+  0015: goto 000f // -0006
+  0016: move-exception v1
+  0017: move-object v0, v1
+  0018: const/16 v1, #int 11 // #000b
+  001a: move v0, v1
+  001b: goto 000f // -000c
+  catches
+    tries:
+      try 0000..0006
+      catch java.lang.RuntimeException -> 0010
+      try 0006..000c
+      catch java.lang.RuntimeException -> 0016
+Blort.test9:()I:
+regs: 0002; ins: 0000; outs: 0000
+  0000: invoke-static {}, Blort.call1:()V
+  0003: invoke-static {}, Blort.call2:()V
+  0006: invoke-static {}, Blort.call3:()V
+  0009: invoke-static {}, Blort.call4:()V
+  000c: const/16 v1, #int 14 // #000e
+  000e: move v0, v1
+  000f: return v0
+  0010: move-exception v1
+  0011: move-object v0, v1
+  0012: const/16 v1, #int 10 // #000a
+  0014: move v0, v1
+  0015: goto 000f // -0006
+  0016: move-exception v1
+  0017: move-object v0, v1
+  0018: const/16 v1, #int 11 // #000b
+  001a: move v0, v1
+  001b: goto 000f // -000c
+  001c: move-exception v1
+  001d: move-object v0, v1
+  001e: const/16 v1, #int 12 // #000c
+  0020: move v0, v1
+  0021: goto 000f // -0012
+  0022: move-exception v1
+  0023: move-object v0, v1
+  0024: const/16 v1, #int 13 // #000d
+  0026: move v0, v1
+  0027: goto 000f // -0018
+  catches
+    tries:
+      try 0000..0003
+      catch java.lang.RuntimeException -> 0016
+      try 0003..0006
+      catch java.lang.IllegalArgumentException -> 0010,
+        java.lang.RuntimeException -> 0016
+      try 0006..0009
+      catch java.lang.RuntimeException -> 0022
+      try 0009..000c
+      catch java.lang.IllegalArgumentException -> 001c,
+        java.lang.RuntimeException -> 0022
diff --git a/dx/tests/080-dex-exception-tables/info.txt b/dx/tests/080-dex-exception-tables/info.txt
new file mode 100644
index 0000000..99f2cbc
--- /dev/null
+++ b/dx/tests/080-dex-exception-tables/info.txt
@@ -0,0 +1,8 @@
+This is a smoke test of dex conversion, which checks to make sure that
+exception handler tables get built reasonably (combining entries that
+ought to be combined, listing entries in a correct and sensible order,
+etc.).
+
+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/080-dex-exception-tables/run b/dx/tests/080-dex-exception-tables/run
new file mode 100644
index 0000000..3acfcfd
--- /dev/null
+++ b/dx/tests/080-dex-exception-tables/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/081-dex-throws-list/Blort.java b/dx/tests/081-dex-throws-list/Blort.java
new file mode 100644
index 0000000..6011c9c
--- /dev/null
+++ b/dx/tests/081-dex-throws-list/Blort.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public int test1()
+            throws RuntimeException {
+        throw new RuntimeException();
+    }
+
+    public int test2()
+            throws Throwable, IllegalArgumentException {
+        throw new IllegalArgumentException();
+    }
+}
diff --git a/dx/tests/081-dex-throws-list/expected.txt b/dx/tests/081-dex-throws-list/expected.txt
new file mode 100644
index 0000000..1350edf
--- /dev/null
+++ b/dx/tests/081-dex-throws-list/expected.txt
@@ -0,0 +1,4 @@
+Blort.test1:()I:
+    system-annotation dalvik.annotation.Throws {value: {java.lang.RuntimeException}}
+Blort.test2:()I:
+    system-annotation dalvik.annotation.Throws {value: {java.lang.Throwable, java.lang.IllegalArgumentException}}
diff --git a/dx/tests/081-dex-throws-list/info.txt b/dx/tests/081-dex-throws-list/info.txt
new file mode 100644
index 0000000..eb4bdd7
--- /dev/null
+++ b/dx/tests/081-dex-throws-list/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to make sure that
+throws lists (that is, list of declared exceptions on methods) get
+represented reasonably.
+
+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/081-dex-throws-list/run b/dx/tests/081-dex-throws-list/run
new file mode 100644
index 0000000..2236cf2
--- /dev/null
+++ b/dx/tests/081-dex-throws-list/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --positions=none --no-locals --dump-method=Blort.test'*' \
+    *.class | grep 'Blort\|Throws'
diff --git a/dx/tests/082-dex-throws-list-sharing/Blort.java b/dx/tests/082-dex-throws-list-sharing/Blort.java
new file mode 100644
index 0000000..31591d0
--- /dev/null
+++ b/dx/tests/082-dex-throws-list-sharing/Blort.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public int test1()
+            throws RuntimeException {
+        throw new RuntimeException();
+    }
+
+    public int test2()
+            throws RuntimeException {
+        throw new RuntimeException();
+    }
+
+    public int test3()
+            throws Error, UnsupportedOperationException {
+        throw new RuntimeException();
+    }
+
+    public int test4()
+            throws Error, UnsupportedOperationException {
+        throw new RuntimeException();
+    }
+}
diff --git a/dx/tests/082-dex-throws-list-sharing/expected.txt b/dx/tests/082-dex-throws-list-sharing/expected.txt
new file mode 100644
index 0000000..0f33924
--- /dev/null
+++ b/dx/tests/082-dex-throws-list-sharing/expected.txt
@@ -0,0 +1,2 @@
+java.lang.RuntimeException
+java.lang.Error, java.lang.UnsupportedOperationException
diff --git a/dx/tests/082-dex-throws-list-sharing/info.txt b/dx/tests/082-dex-throws-list-sharing/info.txt
new file mode 100644
index 0000000..3b7dca1
--- /dev/null
+++ b/dx/tests/082-dex-throws-list-sharing/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to make sure that
+identical throws lists in different methods get collapsed into a single
+dex file structure.
+
+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/082-dex-throws-list-sharing/run b/dx/tests/082-dex-throws-list-sharing/run
new file mode 100644
index 0000000..6eed9bd
--- /dev/null
+++ b/dx/tests/082-dex-throws-list-sharing/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --positions=none --no-locals --dump-to=- --dump-width=200 \
+    *.class | grep '^[0-9a-f].*value.*Exception' \
+    | sed -e 's/^[^{]*{//g' -e 's/}//g'
diff --git a/dx/tests/083-ssa-phi-placement/Blort.java b/dx/tests/083-ssa-phi-placement/Blort.java
new file mode 100644
index 0000000..ed3264d
--- /dev/null
+++ b/dx/tests/083-ssa-phi-placement/Blort.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+
+    public int phiTest() {
+        int i = 1;
+        int j = 1;
+        int k = 0;
+
+        while (k < 100) {
+            if (j < 20) {
+                j = i;
+                k++;
+            } else {
+                j = k;
+                k += 2;
+            }
+        }
+
+        return j;
+    }
+
+    /**
+     * This method uses no registers.
+     */
+    public static void noVars() {
+    }
+
+    /**
+     * This method requires an ordered successor list with
+     * multiple identically-valued entries.
+     */
+    Object fd;
+    public Object getOption(int optID) throws RuntimeException
+    {
+        if (fd == null) {
+            throw new RuntimeException("socket not created");
+        }
+
+        int value = 0;
+        switch (optID)
+        {
+            case 1:
+            case 2:
+                return new Integer(value);
+            case 3:
+            default:
+                return Boolean.valueOf(value != 0);
+        }
+    }
+}
diff --git a/dx/tests/083-ssa-phi-placement/expected.txt b/dx/tests/083-ssa-phi-placement/expected.txt
new file mode 100644
index 0000000..dda99cd
--- /dev/null
+++ b/dx/tests/083-ssa-phi-placement/expected.txt
@@ -0,0 +1,345 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  live in:{}
+  Blort.java:17@0000: move-object v1:NffffLBlort; <- v0:NffffLBlort;
+  Blort.java:17@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <an
+  y>}(java.lang.Object.<init>:()V catch) . <- v1:NffffLBlort;
+  next 0004
+  live out:{}
+block 0004
+  pred 0000
+  live in:{}
+  Blort.java:17@0004: goto . <- .
+  next 000b
+  live out:{}
+block 000a
+  pred 000c
+  live in:{}
+  Blort.java:17@0000: move-param-object(0) v0:NffffLBlort; <- .
+  Blort.java:17@0000: goto . <- .
+  next 0000
+  live out:{}
+block 000b
+  pred 0004
+  live in:{}
+  Blort.java:17@0004: return-void . <- .
+  returns
+  live out:{}
+block 000c
+  live in:{}
+  @????: goto . <- .
+  next 000a
+  live out:{}
+
+method phiTest ()I
+first 0048
+block 0000
+  pred 0046
+  live in:{}
+  Blort.java:21@0000: const-int(1) v4:I=1 <- .
+  Blort.java:21@0001: move-int v1:I=1 <- v4:I=1
+  Blort.java:22@0002: const-int(1) v4:I=1 <- .
+  Blort.java:22@0003: move-int v2:I=1 <- v4:I=1
+  Blort.java:23@0004: const-int(0) v4:I=0 <- .
+  Blort.java:23@0005: move-int v3:I=0 <- v4:I=0
+  Blort.java:23@0005: goto . <- .
+  next 0049
+  live out:{}
+block 0006
+  pred 0049
+  live in:{}
+  Blort.java:25@0006: move-int v4:I <- v3:I
+  Blort.java:25@0007: const-int(100) v5:I=100 <- .
+  Blort.java:25@0009: if-ge-int . <- v4:I v5:I=100
+  next 000c *
+  next 0022
+  live out:{}
+block 000c
+  pred 0006
+  live in:{}
+  Blort.java:26@000c: move-int v4:I <- v2:I
+  Blort.java:26@000d: const-int(20) v5:I=20 <- .
+  Blort.java:26@000f: if-ge-int . <- v4:I v5:I=20
+  next 0012 *
+  next 001a
+  live out:{}
+block 0012
+  pred 000c
+  live in:{}
+  Blort.java:27@0012: move-int v4:I <- v1:I
+  Blort.java:27@0013: move-int v2:I <- v4:I
+  Blort.java:28@0014: add-const-int(1) v3:I <- v3:I
+  Blort.java:28@0017: goto . <- .
+  next 0049
+  live out:{}
+block 001a
+  pred 000c
+  live in:{}
+  Blort.java:30@001a: move-int v4:I <- v3:I
+  Blort.java:30@001b: move-int v2:I <- v4:I
+  Blort.java:31@001c: add-const-int(2) v3:I <- v3:I
+  Blort.java:31@001f: goto . <- .
+  next 0049
+  live out:{}
+block 0022
+  pred 0006
+  live in:{}
+  Blort.java:35@0022: move-int v4:I <- v2:I
+  Blort.java:35@0023: move-int v0:I <- v4:I
+  Blort.java:35@0023: goto . <- .
+  next 0047
+  live out:{}
+block 0046
+  pred 0048
+  live in:{}
+  Blort.java:21@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:21@0000: goto . <- .
+  next 0000
+  live out:{}
+block 0047
+  pred 0022
+  live in:{}
+  Blort.java:35@0023: return-int . <- v0:I
+  returns
+  live out:{}
+block 0048
+  live in:{}
+  @????: goto . <- .
+  next 0046
+  live out:{}
+block 0049
+  pred 0000
+  pred 0012
+  pred 001a
+  live in:{}
+  @????: phi v5:V <- .
+  @????: phi v4:V <- .
+  @????: phi v3:V <- .
+  @????: phi v2:V <- .
+  @????: goto . <- .
+  next 0006
+  live out:{}
+
+method noVars ()V
+first 0004
+block 0000
+  pred 0002
+  live in:{}
+  Blort.java:42@0000: goto . <- .
+  next 0003
+  live out:{}
+block 0002
+  pred 0004
+  live in:{}
+  Blort.java:42@0000: goto . <- .
+  next 0000
+  live out:{}
+block 0003
+  pred 0000
+  live in:{}
+  Blort.java:42@0000: return-void . <- .
+  returns
+  live out:{}
+block 0004
+  live in:{}
+  @????: goto . <- .
+  next 0002
+  live out:{}
+
+method getOption (I)Ljava/lang/Object;
+first 0098
+block 0000
+  pred 008c
+  live in:{}
+  Blort.java:51@0000: move-object v3:LBlort; <- v0:LBlort;
+  Blort.java:51@0001: get-field-object(Blort.fd:Ljava/lang/Object; catch) . <- 
+  v3:LBlort;
+  next 0093
+  live out:{}
+block 0004
+  pred 0093
+  live in:{}
+  Blort.java:51@0004: if-nez-object . <- v3:Ljava/lang/Object;
+  next 0007 *
+  next 0011
+  live out:{}
+block 0007
+  pred 0004
+  live in:{}
+  Blort.java:52@0007: new-instance(java.lang.RuntimeException catch) . <- .
+  next 0094
+  live out:{}
+block 000a
+  pred 0094
+  live in:{}
+  Blort.java:52@000a: move-object v6:N0007Ljava/lang/RuntimeException; <- v3:N0
+  007Ljava/lang/RuntimeException;
+  Blort.java:52@000a: move-object v3:N0007Ljava/lang/RuntimeException; <- v6:N0
+  007Ljava/lang/RuntimeException;
+  Blort.java:52@000a: move-object v4:N0007Ljava/lang/RuntimeException; <- v6:N0
+  007Ljava/lang/RuntimeException;
+  Blort.java:52@000b: const-object("socket not created" catch) . <- .
+  next 0095
+  live out:{}
+block 000d
+  pred 0095
+  live in:{}
+  Blort.java:52@000d: Rop{invoke-direct . <- Ljava/lang/RuntimeException; Ljava
+  /lang/String; call throws <any>}(java.lang.RuntimeException.<init>:(Ljava/lan
+  g/String;)V catch) . <- v4:N0007Ljava/lang/RuntimeException; v5:Ljava/lang/St
+  ring;="socket not created"
+  next 0010
+  live out:{}
+block 0010
+  pred 000d
+  live in:{}
+  Blort.java:52@0010: throw(catch) . <- v3:Ljava/lang/RuntimeException;
+  returns
+  live out:{}
+block 0011
+  pred 0004
+  live in:{}
+  Blort.java:55@0011: const-int(0) v3:I=0 <- .
+  Blort.java:55@0012: move-int v2:I=0 <- v3:I=0
+  Blort.java:56@0013: move-int v3:I <- v1:I
+  Blort.java:56@0014: switch({1, 2}) . <- v3:I
+  next 0030
+  next 0030
+  next 0039 *
+  live out:{}
+block 0030
+  pred 0011
+  live in:{}
+  Blort.java:60@0030: new-instance(java.lang.Integer catch) . <- .
+  next 0096
+  live out:{}
+block 0033
+  pred 0096
+  live in:{}
+  Blort.java:60@0033: move-object v6:N0030Ljava/lang/Integer; <- v3:N0030Ljava/
+  lang/Integer;
+  Blort.java:60@0033: move-object v3:N0030Ljava/lang/Integer; <- v6:N0030Ljava/
+  lang/Integer;
+  Blort.java:60@0033: move-object v4:N0030Ljava/lang/Integer; <- v6:N0030Ljava/
+  lang/Integer;
+  Blort.java:60@0034: move-int v5:I <- v2:I
+  Blort.java:60@0035: Rop{invoke-direct . <- Ljava/lang/Integer; I call throws 
+  <any>}(java.lang.Integer.<init>:(I)V catch) . <- v4:N0030Ljava/lang/Integer; 
+  v5:I
+  next 0038
+  live out:{}
+block 0038
+  pred 0033
+  live in:{}
+  Blort.java:60@0038: move-object v0:Ljava/lang/Integer; <- v3:Ljava/lang/Integ
+  er;
+  Blort.java:60@0038: goto . <- .
+  next 008d
+  live out:{}
+block 0039
+  pred 0011
+  live in:{}
+  Blort.java:63@0039: move-int v3:I <- v2:I
+  Blort.java:63@003a: if-eqz-int . <- v3:I
+  next 003d *
+  next 0041
+  live out:{}
+block 003d
+  pred 0039
+  live in:{}
+  Blort.java:63@003d: const-int(1) v3:I=1 <- .
+  Blort.java:63@003e: goto . <- .
+  next 0042
+  live out:{}
+block 0041
+  pred 0039
+  live in:{}
+  Blort.java:63@0041: const-int(0) v3:I=0 <- .
+  Blort.java:63@0041: goto . <- .
+  next 0042
+  live out:{}
+block 0042
+  pred 003d
+  pred 0041
+  live in:{}
+  @????: phi v3:V <- .
+  Blort.java:63@0042: Rop{invoke-static . <- I call throws <any>}(java.lang.Boo
+  lean.valueOf:(Z)Ljava/lang/Boolean; catch) . <- v3:I
+  next 0097
+  live out:{}
+block 0045
+  pred 0097
+  live in:{}
+  Blort.java:63@0045: move-object v0:Ljava/lang/Boolean; <- v3:Ljava/lang/Boole
+  an;
+  Blort.java:63@0045: goto . <- .
+  next 008d
+  live out:{}
+block 008c
+  pred 0098
+  live in:{}
+  Blort.java:51@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:51@0000: move-param-int(1) v1:I <- .
+  Blort.java:51@0000: goto . <- .
+  next 0000
+  live out:{}
+block 008d
+  pred 0038
+  pred 0045
+  live in:{}
+  @????: phi v6:V <- .
+  @????: phi v5:V <- .
+  @????: phi v4:V <- .
+  @????: phi v3:V <- .
+  @????: phi v0:V <- .
+  Blort.java:63@0045: return-object . <- v0:Ljava/lang/Object;
+  returns
+  live out:{}
+block 0093
+  pred 0000
+  live in:{}
+  Blort.java:51@0001: Rop{move-result-pseudo Ljava/lang/Object; <- . flows} v3:
+  Ljava/lang/Object; <- .
+  Blort.java:51@0001: goto . <- .
+  next 0004
+  live out:{}
+block 0094
+  pred 0007
+  live in:{}
+  Blort.java:52@0007: Rop{move-result-pseudo N0007Ljava/lang/RuntimeException; 
+  <- . flows} v3:N0007Ljava/lang/RuntimeException; <- .
+  Blort.java:52@0007: goto . <- .
+  next 000a
+  live out:{}
+block 0095
+  pred 000a
+  live in:{}
+  Blort.java:52@000b: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v5:
+  Ljava/lang/String;="socket not created" <- .
+  Blort.java:52@000b: goto . <- .
+  next 000d
+  live out:{}
+block 0096
+  pred 0030
+  live in:{}
+  Blort.java:60@0030: Rop{move-result-pseudo N0030Ljava/lang/Integer; <- . flow
+  s} v3:N0030Ljava/lang/Integer; <- .
+  Blort.java:60@0030: goto . <- .
+  next 0033
+  live out:{}
+block 0097
+  pred 0042
+  live in:{}
+  Blort.java:63@0042: Rop{move-result Ljava/lang/Boolean; <- . flows} v3:Ljava/
+  lang/Boolean; <- .
+  Blort.java:63@0042: goto . <- .
+  next 0045
+  live out:{}
+block 0098
+  live in:{}
+  @????: goto . <- .
+  next 008c
+  live out:{}
diff --git a/dx/tests/083-ssa-phi-placement/info.txt b/dx/tests/083-ssa-phi-placement/info.txt
new file mode 100644
index 0000000..8d4eebf
--- /dev/null
+++ b/dx/tests/083-ssa-phi-placement/info.txt
@@ -0,0 +1,5 @@
+This is a test case for the phi placement algorthim used in the conversion to SSA form.
+
+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/083-ssa-phi-placement/run b/dx/tests/083-ssa-phi-placement/run
new file mode 100644
index 0000000..ddcb597
--- /dev/null
+++ b/dx/tests/083-ssa-phi-placement/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --dump --ssa-blocks --ssa-step=phi-placement Blort.class
diff --git a/dx/tests/084-dex-high-register-moves/Blort.java b/dx/tests/084-dex-high-register-moves/Blort.java
new file mode 100644
index 0000000..e68ebd8
--- /dev/null
+++ b/dx/tests/084-dex-high-register-moves/Blort.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    private static int i;
+    private static long l;
+    private static Object o;
+
+    public static void test() {
+        int i0 = 0;
+        int i1 = 0;
+        int i2 = 0;
+        int i3 = 0;
+        int i4 = 0;
+        int i5 = 0;
+        int i6 = 0;
+        int i7 = 0;
+        int i8 = 0;
+        int i9 = 0;
+        int i10 = 0;
+        int i11 = 0;
+        int i12 = 0;
+        int i13 = 0;
+        int i14 = 0;
+        int i15 = 0;
+
+        int ix = i;
+        long lx = l;
+        Object ox = o;
+
+        i = -ix;
+        l = -lx;
+        i = (ox instanceof String) ? 0 : 1;
+    }
+}
diff --git a/dx/tests/084-dex-high-register-moves/expected.txt b/dx/tests/084-dex-high-register-moves/expected.txt
new file mode 100644
index 0000000..061e7d3
--- /dev/null
+++ b/dx/tests/084-dex-high-register-moves/expected.txt
@@ -0,0 +1,58 @@
+Blort.test:()V:
+regs: 0018; ins: 0000; outs: 0000
+  0000: const/16 v22, #int 0 // #0000
+  0002: move/from16 v2, v22
+  0004: const/16 v22, #int 0 // #0000
+  0006: move/from16 v3, v22
+  0008: const/16 v22, #int 0 // #0000
+  000a: move/from16 v4, v22
+  000c: const/16 v22, #int 0 // #0000
+  000e: move/from16 v5, v22
+  0010: const/16 v22, #int 0 // #0000
+  0012: move/from16 v6, v22
+  0014: const/16 v22, #int 0 // #0000
+  0016: move/from16 v7, v22
+  0018: const/16 v22, #int 0 // #0000
+  001a: move/from16 v8, v22
+  001c: const/16 v22, #int 0 // #0000
+  001e: move/from16 v9, v22
+  0020: const/16 v22, #int 0 // #0000
+  0022: move/from16 v10, v22
+  0024: const/16 v22, #int 0 // #0000
+  0026: move/from16 v11, v22
+  0028: const/16 v22, #int 0 // #0000
+  002a: move/from16 v12, v22
+  002c: const/16 v22, #int 0 // #0000
+  002e: move/from16 v13, v22
+  0030: const/16 v22, #int 0 // #0000
+  0032: move/from16 v14, v22
+  0034: const/16 v22, #int 0 // #0000
+  0036: move/from16 v15, v22
+  0038: const/16 v22, #int 0 // #0000
+  003a: move/from16 v16, v22
+  003c: const/16 v22, #int 0 // #0000
+  003e: move/from16 v17, v22
+  0040: sget v22, Blort.i:I
+  0042: move/from16 v18, v22
+  0044: sget-wide v22, Blort.l:J
+  0046: move-wide/from16 v19, v22
+  0048: sget-object v22, Blort.o:Ljava/lang/Object;
+  004a: move-object/from16 v21, v22
+  004c: move/from16 v22, v18
+  004e: move/from16 v0, v22
+  0050: neg-int v0, v0
+  0051: move/from16 v22, v0
+  0053: sput v22, Blort.i:I
+  0055: move-wide/from16 v22, v19
+  0057: move-wide/from16 v0, v22
+  0059: neg-long v0, v0
+  005a: move-wide/from16 v22, v0
+  005c: sput-wide v22, Blort.l:J
+  005e: move-object/from16 v22, v21
+  0060: instance-of/jumbo v22, v22, java.lang.String
+  0065: if-eqz v22, 006c // +0007
+  0067: const/16 v22, #int 0 // #0000
+  0069: sput v22, Blort.i:I
+  006b: return-void
+  006c: const/16 v22, #int 1 // #0001
+  006e: goto 0069 // -0005
diff --git a/dx/tests/084-dex-high-register-moves/info.txt b/dx/tests/084-dex-high-register-moves/info.txt
new file mode 100644
index 0000000..77f0945
--- /dev/null
+++ b/dx/tests/084-dex-high-register-moves/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to make sure that
+high registers are moved to and from low registers with
+type-appropriate instructions.
+
+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/084-dex-high-register-moves/run b/dx/tests/084-dex-high-register-moves/run
new file mode 100644
index 0000000..3acfcfd
--- /dev/null
+++ b/dx/tests/084-dex-high-register-moves/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' *.class
diff --git a/dx/tests/085-dex-jsr-ret/blort.j b/dx/tests/085-dex-jsr-ret/blort.j
new file mode 100644
index 0000000..e6a901c
--- /dev/null
+++ b/dx/tests/085-dex-jsr-ret/blort.j
@@ -0,0 +1,57 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+; Test jsr and jsr_w.
+.method public test_jsr()Ljava/lang/Object;
+    .limit locals 3
+    .limit stack 4
+    aload_0
+    jsr j1
+    aload_0
+    pop
+    ; Call j1 with different locals
+    ldc 10
+    istore_0
+    jsr j1
+    iload_0
+    pop
+    jsr j3
+    areturn
+j1:
+    astore_2
+    jsr_w j2
+    ret 2
+j2:
+    ; a subroutine with two returns and a catch block
+    astore_1
+    dup
+    dup
+    ; Just something that could throw an exception...
+    invokevirtual blort.test_jsr()V
+    ifnonnull j2a
+    ret_w 1
+j2a:
+    ret_w 1
+j3:
+    ; a subroutine that does not return
+    pop
+    areturn
+catchBlock:
+    areturn
+
+.catch java/lang/Throwable from j2 to j2a using catchBlock
+.end method
diff --git a/dx/tests/085-dex-jsr-ret/expected.txt b/dx/tests/085-dex-jsr-ret/expected.txt
new file mode 100644
index 0000000..6bba047
--- /dev/null
+++ b/dx/tests/085-dex-jsr-ret/expected.txt
@@ -0,0 +1,148 @@
+Generated: ./blort.class
+reading blort.class...
+method test_jsr ()Ljava/lang/Object;
+first 005c
+block 0000
+  pred 005c
+  blort.j:@0000: move-object v3:Lblort; <- v0:Lblort;
+  blort.j:@0000: goto . <- .
+  next 0001
+block 0001
+  pred 0000
+  @????: goto . <- .
+  next 0063
+block 0004
+  pred 0065
+  blort.j:@0004: move-object v4:Lblort; <- v0:Lblort;
+  blort.j:@0006: const-int(10) v4:I=10 <- .
+  blort.j:@0008: move-int v0:I=10 <- v4:I=10
+  blort.j:@0008: goto . <- .
+  next 0009
+block 0009
+  pred 0004
+  @????: goto . <- .
+  next 006c
+block 000c
+  pred 006e
+  blort.j:@000c: move-int v4:I <- v0:I
+  blort.j:@000c: goto . <- .
+  next 000e
+block 000e
+  pred 000c
+  @????: goto . <- .
+  next 0075
+block 005c
+  blort.j:@0000: move-param-object(0) v0:Lblort; <- .
+  blort.j:@0000: goto . <- .
+  next 0000
+block 005d
+  pred 006b
+  pred 0074
+  pred 0075
+  blort.j:@002c: return-object . <- v0:Ljava/lang/Object;
+  returns
+block 0063
+  pred 0001
+  blort.j:@0012: goto . <- .
+  next 0064
+block 0064
+  pred 0063
+  @????: goto . <- .
+  next 0066
+block 0065
+  pred 0069
+  pred 006a
+  @????: goto . <- .
+  next 0004
+block 0066
+  pred 0064
+  blort.j:@001b: move-object v7:Lblort; <- v3:Lblort;
+  blort.j:@001b: move-object v3:Lblort; <- v7:Lblort;
+  blort.j:@001b: move-object v4:Lblort; <- v7:Lblort;
+  blort.j:@001c: move-object v7:Lblort; <- v4:Lblort;
+  blort.j:@001c: move-object v4:Lblort; <- v7:Lblort;
+  blort.j:@001c: move-object v5:Lblort; <- v7:Lblort;
+  blort.j:@001d: Rop{invoke-virtual . <- Lblort; call throws <any>}(blort.test_
+  jsr:()V catch java.lang.Throwable) . <- v5:Lblort;
+  next 0067
+  next 0068 *
+block 0067
+  pred 0066
+  blort.j:@002d: Rop{move-exception Ljava/lang/Throwable; <- . flows} v3:Ljava/
+  lang/Throwable; <- .
+  blort.j:@002d: goto . <- .
+  next 006b
+block 0068
+  pred 0066
+  blort.j:@0020: if-nez-object . <- v4:Lblort;
+  next 0069 *
+  next 006a
+block 0069
+  pred 0068
+  @????: goto . <- .
+  next 0065
+block 006a
+  pred 0068
+  @????: goto . <- .
+  next 0065
+block 006b
+  pred 0067
+  blort.j:@002d: move-object v0:Ljava/lang/Class;=java.lang.Throwable <- v3:Lja
+  va/lang/Class;=java.lang.Throwable
+  blort.j:@002d: goto . <- .
+  next 005d
+block 006c
+  pred 0009
+  blort.j:@0012: goto . <- .
+  next 006d
+block 006d
+  pred 006c
+  @????: goto . <- .
+  next 006f
+block 006e
+  pred 0072
+  pred 0073
+  @????: goto . <- .
+  next 000c
+block 006f
+  pred 006d
+  blort.j:@001b: move-object v7:Lblort; <- v3:Lblort;
+  blort.j:@001b: move-object v3:Lblort; <- v7:Lblort;
+  blort.j:@001b: move-object v4:Lblort; <- v7:Lblort;
+  blort.j:@001c: move-object v7:Lblort; <- v4:Lblort;
+  blort.j:@001c: move-object v4:Lblort; <- v7:Lblort;
+  blort.j:@001c: move-object v5:Lblort; <- v7:Lblort;
+  blort.j:@001d: Rop{invoke-virtual . <- Lblort; call throws <any>}(blort.test_
+  jsr:()V catch java.lang.Throwable) . <- v5:Lblort;
+  next 0070
+  next 0071 *
+block 0070
+  pred 006f
+  blort.j:@002d: Rop{move-exception Ljava/lang/Throwable; <- . flows} v3:Ljava/
+  lang/Throwable; <- .
+  blort.j:@002d: goto . <- .
+  next 0074
+block 0071
+  pred 006f
+  blort.j:@0020: if-nez-object . <- v4:Lblort;
+  next 0072 *
+  next 0073
+block 0072
+  pred 0071
+  @????: goto . <- .
+  next 006e
+block 0073
+  pred 0071
+  @????: goto . <- .
+  next 006e
+block 0074
+  pred 0070
+  blort.j:@002d: move-object v0:Ljava/lang/Class;=java.lang.Throwable <- v3:Lja
+  va/lang/Class;=java.lang.Throwable
+  blort.j:@002d: goto . <- .
+  next 005d
+block 0075
+  pred 000e
+  blort.j:@002c: move-object v0:Lblort; <- v3:Lblort;
+  blort.j:@002c: goto . <- .
+  next 005d
diff --git a/dx/tests/085-dex-jsr-ret/info.txt b/dx/tests/085-dex-jsr-ret/info.txt
new file mode 100644
index 0000000..8e164d6
--- /dev/null
+++ b/dx/tests/085-dex-jsr-ret/info.txt
@@ -0,0 +1 @@
+Tests handling of the Java jsr/jsr_w/ret bytecodes.
diff --git a/dx/tests/085-dex-jsr-ret/run b/dx/tests/085-dex-jsr-ret/run
new file mode 100644
index 0000000..00a7404
--- /dev/null
+++ b/dx/tests/085-dex-jsr-ret/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j
+dx --dump --rop-blocks blort.class
diff --git a/dx/tests/086-ssa-edge-split/Blort.java b/dx/tests/086-ssa-edge-split/Blort.java
new file mode 100644
index 0000000..d12b3f9
--- /dev/null
+++ b/dx/tests/086-ssa-edge-split/Blort.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    /**
+     * This method requires the edge-splitter to add a node
+     * to get to the finally block, since there are
+     * two exception sources.
+     *
+     */
+    public int edgeSplitPredTest(int x) {
+        int y = 1;
+
+        try {
+            Integer.toString(x);
+            Integer.toString(x);
+            y++;
+        } finally {
+            return y;
+        }
+    }
+
+    /**
+     * just because this should do nothing
+     */
+    void voidFunction() {
+    }
+
+    /**
+     * Current SSA form requires each move-exception block to have
+     * a unique predecessor
+     */
+    void edgeSplitMoveException() {
+        try {
+            hashCode();
+            hashCode();
+        } catch (Throwable tr) {
+        }
+    }
+
+    /**
+     * Presently, any basic block ending in an instruction with
+     * a result needs to have a unique successor. This appies
+     * only to the block between the switch instruction and the return
+     * in this case.
+     */
+    int edgeSplitSuccessor(int x) {
+        int y = 0;
+
+        switch(x) {
+            case 1: y++;
+            break;
+            case 2: y++;
+            break;
+            case 3: y++;
+            break;
+        }
+        return y;
+    }
+}
diff --git a/dx/tests/086-ssa-edge-split/expected.txt b/dx/tests/086-ssa-edge-split/expected.txt
new file mode 100644
index 0000000..0a09fb1
--- /dev/null
+++ b/dx/tests/086-ssa-edge-split/expected.txt
@@ -0,0 +1,343 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  live in:{}
+  Blort.java:17@0000: move-object v1:NffffLBlort; <- v0:NffffLBlort;
+  Blort.java:17@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <any>}(java.lang.Object.<init>:()V catch) . <- v1:NffffLBlort;
+  next 0004
+  live out:{}
+block 0004
+  pred 0000
+  live in:{}
+  Blort.java:17@0004: goto . <- .
+  next 000b
+  live out:{}
+block 000a
+  pred 000c
+  live in:{}
+  Blort.java:17@0000: move-param-object(0) v0:NffffLBlort; <- .
+  Blort.java:17@0000: goto . <- .
+  next 0000
+  live out:{}
+block 000b
+  pred 0004
+  live in:{}
+  Blort.java:17@0004: return-void . <- .
+  returns
+  live out:{}
+block 000c
+  live in:{}
+  @????: goto . <- .
+  next 000a
+  live out:{}
+
+method edgeSplitPredTest (I)I
+first 002f
+block 0000
+  pred 0026
+  live in:{}
+  Blort.java:26@0000: const-int(1) v4:I=1 <- .
+  Blort.java:26@0001: move-int v2:I=1 <- v4:I=1
+  Blort.java:26@0001: goto . <- .
+  next 0002
+  live out:{}
+block 0002
+  pred 0000
+  live in:{}
+  Blort.java:29@0002: move-int v4:I <- v1:I
+  Blort.java:29@0003: Rop{invoke-static . <- I call throws <any>}(java.lang.Integer.toString:(I)Ljava/lang/String; catch java.lang.Object) . <- v4:I
+  next 0030
+  next 002d *
+  live out:{}
+block 0006
+  pred 002d
+  live in:{}
+  Blort.java:30@0007: move-int v4:I <- v1:I
+  Blort.java:30@0008: Rop{invoke-static . <- I call throws <any>}(java.lang.Integer.toString:(I)Ljava/lang/String; catch java.lang.Object) . <- v4:I
+  next 0031
+  next 002e *
+  live out:{}
+block 000b
+  pred 002e
+  live in:{}
+  Blort.java:31@000c: add-const-int(1) v2:I <- v2:I
+  Blort.java:31@000c: goto . <- .
+  next 000f
+  live out:{}
+block 000f
+  pred 000b
+  live in:{}
+  Blort.java:33@000f: move-int v4:I <- v2:I
+  Blort.java:33@0010: move-int v0:I <- v4:I
+  Blort.java:33@0010: goto . <- .
+  next 0027
+  live out:{}
+block 0011
+  pred 0024
+  live in:{}
+  Blort.java:33@0011: move-object v3:Ljava/lang/Class;=java.lang.Object <- v4:Ljava/lang/Class;=java.lang.Object
+  Blort.java:33@0011: goto . <- .
+  next 0012
+  live out:{}
+block 0012
+  pred 0011
+  live in:{}
+  Blort.java:33@0012: move-int v4:I <- v2:I
+  Blort.java:33@0013: move-int v0:I <- v4:I
+  Blort.java:33@0013: goto . <- .
+  next 0027
+  live out:{}
+block 0024
+  pred 0030
+  pred 0031
+  live in:{}
+  Blort.java:33@0011: goto . <- .
+  next 0011
+  live out:{}
+block 0026
+  pred 002f
+  live in:{}
+  Blort.java:26@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:26@0000: move-param-int(1) v1:I <- .
+  Blort.java:26@0000: goto . <- .
+  next 0000
+  live out:{}
+block 0027
+  pred 000f
+  pred 0012
+  live in:{}
+  Blort.java:33@0010: return-int . <- v0:I
+  returns
+  live out:{}
+block 002d
+  pred 0002
+  live in:{}
+  Blort.java:29@0003: Rop{move-result Ljava/lang/String; <- . flows} v4:Ljava/lang/String; <- .
+  Blort.java:29@0003: goto . <- .
+  next 0006
+  live out:{}
+block 002e
+  pred 0006
+  live in:{}
+  Blort.java:30@0008: Rop{move-result Ljava/lang/String; <- . flows} v4:Ljava/lang/String; <- .
+  Blort.java:30@0008: goto . <- .
+  next 000b
+  live out:{}
+block 002f
+  live in:{}
+  @????: goto . <- .
+  next 0026
+  live out:{}
+block 0030
+  pred 0002
+  live in:{}
+  Blort.java:33@0011: Rop{move-exception Ljava/lang/Object; <- . flows} v4:Ljava/lang/Object; <- .
+  @????: goto . <- .
+  next 0024
+  live out:{}
+block 0031
+  pred 0006
+  live in:{}
+  Blort.java:33@0011: Rop{move-exception Ljava/lang/Object; <- . flows} v4:Ljava/lang/Object; <- .
+  @????: goto . <- .
+  next 0024
+  live out:{}
+
+method voidFunction ()V
+first 0004
+block 0000
+  pred 0002
+  live in:{}
+  Blort.java:41@0000: goto . <- .
+  next 0003
+  live out:{}
+block 0002
+  pred 0004
+  live in:{}
+  Blort.java:41@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:41@0000: goto . <- .
+  next 0000
+  live out:{}
+block 0003
+  pred 0000
+  live in:{}
+  Blort.java:41@0000: return-void . <- .
+  returns
+  live out:{}
+block 0004
+  live in:{}
+  @????: goto . <- .
+  next 0002
+  live out:{}
+
+method edgeSplitMoveException ()V
+first 0027
+block 0000
+  pred 001e
+  live in:{}
+  Blort.java:49@0000: move-object v2:LBlort; <- v0:LBlort;
+  Blort.java:49@0001: Rop{invoke-virtual . <- Ljava/lang/Object; call throws <any>}(java.lang.Object.hashCode:()I catch java.lang.Throwable) . <- v2:LBlort;
+  next 0028
+  next 0025 *
+  live out:{}
+block 0004
+  pred 0025
+  live in:{}
+  Blort.java:50@0005: move-object v2:LBlort; <- v0:LBlort;
+  Blort.java:50@0006: Rop{invoke-virtual . <- Ljava/lang/Object; call throws <any>}(java.lang.Object.hashCode:()I catch java.lang.Throwable) . <- v2:LBlort;
+  next 0029
+  next 0026 *
+  live out:{}
+block 0009
+  pred 0026
+  live in:{}
+  @????: goto . <- .
+  next 000a
+  live out:{}
+block 000a
+  pred 0009
+  live in:{}
+  Blort.java:52@000a: goto . <- .
+  next 000e
+  live out:{}
+block 000d
+  pred 001c
+  live in:{}
+  Blort.java:51@000d: move-object v1:Ljava/lang/Class;=java.lang.Throwable <- v2:Ljava/lang/Class;=java.lang.Throwable
+  Blort.java:51@000d: goto . <- .
+  next 000e
+  live out:{}
+block 000e
+  pred 000a
+  pred 000d
+  live in:{}
+  Blort.java:53@000e: goto . <- .
+  next 001f
+  live out:{}
+block 001c
+  pred 0028
+  pred 0029
+  live in:{}
+  Blort.java:51@000d: goto . <- .
+  next 000d
+  live out:{}
+block 001e
+  pred 0027
+  live in:{}
+  Blort.java:49@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:49@0000: goto . <- .
+  next 0000
+  live out:{}
+block 001f
+  pred 000e
+  live in:{}
+  Blort.java:53@000e: return-void . <- .
+  returns
+  live out:{}
+block 0025
+  pred 0000
+  live in:{}
+  Blort.java:49@0001: Rop{move-result I <- . flows} v2:I <- .
+  Blort.java:49@0001: goto . <- .
+  next 0004
+  live out:{}
+block 0026
+  pred 0004
+  live in:{}
+  Blort.java:50@0006: Rop{move-result I <- . flows} v2:I <- .
+  Blort.java:50@0006: goto . <- .
+  next 0009
+  live out:{}
+block 0027
+  live in:{}
+  @????: goto . <- .
+  next 001e
+  live out:{}
+block 0028
+  pred 0000
+  live in:{}
+  Blort.java:51@000d: Rop{move-exception Ljava/lang/Throwable; <- . flows} v2:Ljava/lang/Throwable; <- .
+  @????: goto . <- .
+  next 001c
+  live out:{}
+block 0029
+  pred 0004
+  live in:{}
+  Blort.java:51@000d: Rop{move-exception Ljava/lang/Throwable; <- . flows} v2:Ljava/lang/Throwable; <- .
+  @????: goto . <- .
+  next 001c
+  live out:{}
+
+method edgeSplitSuccessor (I)I
+first 005a
+block 0000
+  pred 0058
+  live in:{}
+  Blort.java:62@0000: const-int(0) v3:I=0 <- .
+  Blort.java:62@0001: move-int v2:I=0 <- v3:I=0
+  Blort.java:64@0002: move-int v3:I <- v1:I
+  Blort.java:64@0003: switch({1, 2, 3}) . <- v3:I
+  next 001c
+  next 0022
+  next 0028
+  next 005b *
+  live out:{}
+block 001c
+  pred 0000
+  live in:{}
+  Blort.java:65@001c: add-const-int(1) v2:I <- v2:I
+  Blort.java:66@001f: goto . <- .
+  next 002b
+  live out:{}
+block 0022
+  pred 0000
+  live in:{}
+  Blort.java:67@0022: add-const-int(1) v2:I <- v2:I
+  Blort.java:68@0025: goto . <- .
+  next 002b
+  live out:{}
+block 0028
+  pred 0000
+  live in:{}
+  Blort.java:69@0028: add-const-int(1) v2:I <- v2:I
+  Blort.java:69@0028: goto . <- .
+  next 002b
+  live out:{}
+block 002b
+  pred 001c
+  pred 0022
+  pred 0028
+  pred 005b
+  live in:{}
+  Blort.java:72@002b: move-int v3:I <- v2:I
+  Blort.java:72@002c: move-int v0:I <- v3:I
+  Blort.java:72@002c: goto . <- .
+  next 0059
+  live out:{}
+block 0058
+  pred 005a
+  live in:{}
+  Blort.java:62@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:62@0000: move-param-int(1) v1:I <- .
+  Blort.java:62@0000: goto . <- .
+  next 0000
+  live out:{}
+block 0059
+  pred 002b
+  live in:{}
+  Blort.java:72@002c: return-int . <- v0:I
+  returns
+  live out:{}
+block 005a
+  live in:{}
+  @????: goto . <- .
+  next 0058
+  live out:{}
+block 005b
+  pred 0000
+  live in:{}
+  @????: goto . <- .
+  next 002b
+  live out:{}
diff --git a/dx/tests/086-ssa-edge-split/info.txt b/dx/tests/086-ssa-edge-split/info.txt
new file mode 100644
index 0000000..ff873e8
--- /dev/null
+++ b/dx/tests/086-ssa-edge-split/info.txt
@@ -0,0 +1,5 @@
+This is a test case for the edge-splitting algorthim used in the conversion to SSA form.
+
+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/086-ssa-edge-split/run b/dx/tests/086-ssa-edge-split/run
new file mode 100644
index 0000000..914deb1
--- /dev/null
+++ b/dx/tests/086-ssa-edge-split/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --dump --width=1000 --ssa-blocks --ssa-step=edge-split Blort.class
diff --git a/dx/tests/087-ssa-local-vars/Blort.java b/dx/tests/087-ssa-local-vars/Blort.java
new file mode 100644
index 0000000..7ce8a91
--- /dev/null
+++ b/dx/tests/087-ssa-local-vars/Blort.java
@@ -0,0 +1,94 @@
+import java.io.IOException;
+class Blort {
+    private static void arrayCopyTest(int k) {
+        // A local variable assigned from an argument
+        int j = k;
+        // These two locals are defined once and used multiple times
+        String[] stringArray = new String[8];
+        Object[] objectArray = new Object[8];
+        // Should cause another move to be inserted
+        Object anotherOne = objectArray;
+
+        if (anotherOne != null) {
+            System.out.println("foo");
+        }
+
+        // "i" is used in a loop
+        for (int i = 0; i < stringArray.length; i++)
+            stringArray[i] = new String(Integer.toString(i));
+
+        System.out.println("string -> object");
+        System.arraycopy(stringArray, 0, objectArray, 0, stringArray.length);
+        System.out.println("object -> string");
+        System.arraycopy(objectArray, 0, stringArray, 0, stringArray.length);
+        System.out.println("object -> string (modified)");
+        objectArray[4] = new Object();
+        try {
+            System.arraycopy(objectArray, 0, stringArray, 0,stringArray.length);
+        } catch (ArrayStoreException ase) {
+            // "ase" is an unused local which still must be preserved
+            System.out.println("caught ArrayStoreException (expected)");
+        }
+    }
+
+    private void testConstructor() {
+        Blort foo = null;
+        try {
+            foo = new Blort();
+        } catch (Exception ex) {
+        }
+        System.err.println(foo);
+    }
+    /**
+     * Stolen from
+     * java/android/org/apache/http/impl/io/AbstractMessageParser.java
+     * Simplified.
+     *
+     * Checks to see that local variable assignment is preserved through
+     * phi's. The key component here is the assignment of previous = current.
+     */
+    public static void parseHeaderGroup(
+            final Object headGroup,
+            final Object inbuffer,
+            int maxHeaderCount,
+            int maxLineLen)
+        throws  IOException {
+
+        StringBuilder current = null;
+        StringBuilder previous = null;
+        for (;;) {
+            if (current == null) {
+                current = new StringBuilder(64);
+            } else {
+                current.length();
+            }
+            int l = inbuffer.hashCode();
+            if (l == -1 || current.length() < 1) {
+                break;
+            }
+
+            if ((current.charAt(0) == ' ' || current.charAt(0) == '\t') && previous != null) {
+                int i = 0;
+                while (i < current.length()) {
+                    char ch = current.charAt(i);
+                    if (ch != ' ' && ch != '\t') {
+                        break;
+                    }
+                    i++;
+                }
+                if (maxLineLen > 0
+                        && previous.length() + 1 + current.length() - i > maxLineLen) {
+                    throw new IOException("Maximum line length limit exceeded");
+                }
+                previous.append(' ');
+                previous.append(current, i, current.length() - i);
+            } else {
+                previous = current;
+                current = null;
+            }
+            if (maxHeaderCount > 0) {
+                throw new IOException("Maximum header count exceeded");
+            }
+        }
+    }
+}
diff --git a/dx/tests/087-ssa-local-vars/expected.txt b/dx/tests/087-ssa-local-vars/expected.txt
new file mode 100644
index 0000000..1c875b9
--- /dev/null
+++ b/dx/tests/087-ssa-local-vars/expected.txt
@@ -0,0 +1,1266 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  live in:{2}
+  Blort.java:2@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <any
+  >}(java.lang.Object.<init>:()V catch) . <- v2:NffffLBlort;
+  next 0004
+  live out:{}
+block 0004
+  pred 0000
+  live in:{}
+  Blort.java:2@0004: goto . <- .
+  next 000b
+  live out:{}
+block 000a
+  pred 000c
+  live in:{}
+  Blort.java:2@0000: move-param-object(0) v2:"this"NffffLBlort; <- .
+  Blort.java:2@0000: goto . <- .
+  next 0000
+  live out:{2}
+block 000b
+  pred 0004
+  live in:{}
+  Blort.java:2@0004: return-void . <- .
+  next 000d
+  live out:{}
+block 000c
+  live in:{}
+  @????: goto . <- .
+  next 000a
+  live out:{}
+block 000d
+  pred 000b
+  live in:{}
+  returns
+  live out:{}
+
+method arrayCopyTest (I)V
+first 012c
+block 0000
+  pred 0112
+  live in:{12, 62, 63}
+  Blort.java:5@0001: move-int v13:"j"I <- v12:I
+  Blort.java:7@0004: new-array-object(java.lang.String[] catch) . <- v63:I=8
+  next 0119
+  live out:{62, 63}
+block 0007
+  pred 0119
+  live in:{15, 62, 63}
+  @????: mark-local-object . <- v15:"stringArray"[Ljava/lang/String;
+  Blort.java:8@000a: new-array-object(java.lang.Object[] catch) . <- v63:I=8
+  next 011a
+  live out:{15, 62}
+block 000d
+  pred 011a
+  live in:{15, 17, 62}
+  @????: mark-local-object . <- v17:"objectArray"[Ljava/lang/Object;
+  Blort.java:10@000f: move-object v18:"anotherOne"[Ljava/lang/Object; <- v17:[L
+  java/lang/Object;
+  Blort.java:12@0013: if-eqz-object . <- v18:[Ljava/lang/Object;
+  next 0016 *
+  next 0131
+  live out:{15, 17, 62}
+block 0016
+  pred 000d
+  live in:{15, 17, 62}
+  Blort.java:13@0016: get-static-object(java.lang.System.out:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 011b
+  live out:{15, 17, 62}
+block 0019
+  pred 011b
+  live in:{15, 17, 19, 62}
+  Blort.java:13@0019: const-object("foo" catch) . <- .
+  next 011c
+  live out:{15, 17, 19, 62}
+block 001b
+  pred 011c
+  live in:{15, 17, 19, 20, 62}
+  Blort.java:13@001b: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  String; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V 
+  catch) . <- v19:Ljava/io/PrintStream; v20:Ljava/lang/String;="foo"
+  next 0130
+  live out:{15, 17, 62}
+block 001e
+  pred 0130
+  pred 0131
+  live in:{15, 17, 62}
+  Blort.java:17@001e: const-int(0) v23:I=0 <- .
+  @????: mark-local-int . <- v23:"i"I
+  Blort.java:17@001f: goto . <- .
+  next 0021
+  live out:{15, 17, 23, 62}
+block 0021
+  pred 001e
+  pred 0038
+  live in:{15, 17, 62}
+  @????: phi v30:"i"I <- v23:"i"I[b=001e] v34:"i"I[b=0038]
+  Blort.java:17@0024: array-length(catch) . <- v15:[Ljava/lang/String;
+  next 011d
+  live out:{15, 17, 30, 62}
+block 0025
+  pred 011d
+  live in:{15, 17, 30, 31, 62}
+  Blort.java:17@0025: if-ge-int . <- v30:I v31:I
+  next 0028 *
+  next 003e
+  live out:{15, 17, 30, 62}
+block 0028
+  pred 0025
+  live in:{15, 17, 30, 62}
+  Blort.java:18@002b: new-instance(java.lang.String catch) . <- .
+  next 011e
+  live out:{15, 17, 30, 62}
+block 002e
+  pred 011e
+  live in:{15, 17, 30, 32, 62}
+  Blort.java:18@0031: Rop{invoke-static . <- I call throws <any>}(java.lang.Int
+  eger.toString:(I)Ljava/lang/String; catch) . <- v30:I
+  next 011f
+  live out:{15, 17, 30, 32, 62}
+block 0034
+  pred 011f
+  live in:{15, 17, 30, 32, 33, 62}
+  Blort.java:18@0034: Rop{invoke-direct . <- Ljava/lang/String; Ljava/lang/Stri
+  ng; call throws <any>}(java.lang.String.<init>:(Ljava/lang/String;)V catch) .
+   <- v32:N002bLjava/lang/String; v33:Ljava/lang/String;
+  next 0037
+  live out:{15, 17, 30, 32, 62}
+block 0037
+  pred 0034
+  live in:{15, 17, 30, 32, 62}
+  Blort.java:18@0037: aput-object(catch) . <- v32:Ljava/lang/String; v15:[Ljava
+  /lang/String; v30:I
+  next 0038
+  live out:{15, 17, 30, 62}
+block 0038
+  pred 0037
+  live in:{15, 17, 30, 62}
+  Blort.java:17@0038: add-const-int(1) v34:"i"I <- v30:I
+  Blort.java:17@003b: goto . <- .
+  next 0021
+  live out:{15, 17, 34, 62}
+block 003e
+  pred 0025
+  live in:{15, 17, 62}
+  Blort.java:20@003e: get-static-object(java.lang.System.out:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 0120
+  live out:{15, 17, 62}
+block 0041
+  pred 0120
+  live in:{15, 17, 35, 62}
+  Blort.java:20@0041: const-object("string -> object" catch) . <- .
+  next 0121
+  live out:{15, 17, 35, 62}
+block 0043
+  pred 0121
+  live in:{15, 17, 35, 36, 62}
+  Blort.java:20@0043: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  String; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V 
+  catch) . <- v35:Ljava/io/PrintStream; v36:Ljava/lang/String;="string -> objec
+  t"
+  next 0046
+  live out:{15, 17, 62}
+block 0046
+  pred 0043
+  live in:{15, 17, 62}
+  Blort.java:21@004b: array-length(catch) . <- v15:[Ljava/lang/String;
+  next 0122
+  live out:{15, 17, 62}
+block 004c
+  pred 0122
+  live in:{15, 17, 39, 62}
+  Blort.java:21@004c: Rop{invoke-static . <- Ljava/lang/Object; I Ljava/lang/Ob
+  ject; I I call throws <any>}(java.lang.System.arraycopy:(Ljava/lang/Object;IL
+  java/lang/Object;II)V catch) . <- v15:[Ljava/lang/String; v62:I=0 v17:[Ljava/
+  lang/Object; v62:I=0 v39:I
+  next 004f
+  live out:{15, 17, 62}
+block 004f
+  pred 004c
+  live in:{15, 17, 62}
+  Blort.java:22@004f: get-static-object(java.lang.System.out:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 0123
+  live out:{15, 17, 62}
+block 0052
+  pred 0123
+  live in:{15, 17, 40, 62}
+  Blort.java:22@0052: const-object("object -> string" catch) . <- .
+  next 0124
+  live out:{15, 17, 40, 62}
+block 0054
+  pred 0124
+  live in:{15, 17, 40, 41, 62}
+  Blort.java:22@0054: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  String; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V 
+  catch) . <- v40:Ljava/io/PrintStream; v41:Ljava/lang/String;="object -> strin
+  g"
+  next 0057
+  live out:{15, 17, 62}
+block 0057
+  pred 0054
+  live in:{15, 17, 62}
+  Blort.java:23@005c: array-length(catch) . <- v15:[Ljava/lang/String;
+  next 0125
+  live out:{15, 17, 62}
+block 005d
+  pred 0125
+  live in:{15, 17, 44, 62}
+  Blort.java:23@005d: Rop{invoke-static . <- Ljava/lang/Object; I Ljava/lang/Ob
+  ject; I I call throws <any>}(java.lang.System.arraycopy:(Ljava/lang/Object;IL
+  java/lang/Object;II)V catch) . <- v17:[Ljava/lang/Object; v62:I=0 v15:[Ljava/
+  lang/String; v62:I=0 v44:I
+  next 0060
+  live out:{15, 17}
+block 0060
+  pred 005d
+  live in:{15, 17}
+  Blort.java:24@0060: get-static-object(java.lang.System.out:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 0126
+  live out:{15, 17}
+block 0063
+  pred 0126
+  live in:{15, 17, 45}
+  Blort.java:24@0063: const-object("object -> string (modified)" catch) . <- .
+  next 0127
+  live out:{15, 17, 45}
+block 0065
+  pred 0127
+  live in:{15, 17, 45, 46}
+  Blort.java:24@0065: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  String; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V 
+  catch) . <- v45:Ljava/io/PrintStream; v46:Ljava/lang/String;="object -> strin
+  g (modified)"
+  next 0068
+  live out:{15, 17}
+block 0068
+  pred 0065
+  live in:{15, 17}
+  Blort.java:25@0069: const-int(4) v47:I=4 <- .
+  Blort.java:25@006a: new-instance(java.lang.Object catch) . <- .
+  next 0128
+  live out:{15, 17, 47}
+block 006d
+  pred 0128
+  live in:{15, 17, 47, 48}
+  Blort.java:25@006e: Rop{invoke-direct . <- Ljava/lang/Object; call throws <an
+  y>}(java.lang.Object.<init>:()V catch) . <- v48:N006aLjava/lang/Object;
+  next 0071
+  live out:{15, 17, 47, 48}
+block 0071
+  pred 006d
+  live in:{15, 17, 47, 48}
+  Blort.java:25@0071: aput-object(catch) . <- v48:Ljava/lang/Object; v17:[Ljava
+  /lang/Object; v47:I=4
+  next 0072
+  live out:{15, 17}
+block 0072
+  pred 0071
+  live in:{15, 17}
+  Blort.java:27@0073: const-int(0) v49:I=0 <- .
+  Blort.java:27@0075: const-int(0) v50:I=0 <- .
+  Blort.java:27@0077: array-length(catch java.lang.ArrayStoreException) . <- v1
+  5:[Ljava/lang/String;
+  next 012d
+  next 0129 *
+  live out:{15, 17, 49, 50}
+block 0078
+  pred 0129
+  live in:{15, 17, 49, 50, 51}
+  Blort.java:27@0078: Rop{invoke-static . <- Ljava/lang/Object; I Ljava/lang/Ob
+  ject; I I call throws <any>}(java.lang.System.arraycopy:(Ljava/lang/Object;IL
+  java/lang/Object;II)V catch java.lang.ArrayStoreException) . <- v17:[Ljava/la
+  ng/Object; v49:I=0 v15:[Ljava/lang/String; v50:I=0 v51:I
+  next 012e
+  next 007b *
+  live out:{}
+block 007b
+  pred 0078
+  live in:{}
+  Blort.java:31@007b: goto . <- .
+  next 0088
+  live out:{}
+block 007e
+  pred 0107
+  live in:{58}
+  @????: mark-local-object . <- v58:"ase"Ljava/lang/ArrayStoreException;
+  Blort.java:30@0080: get-static-object(java.lang.System.out:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 012a
+  live out:{}
+block 0083
+  pred 012a
+  live in:{59}
+  Blort.java:30@0083: const-object("caught ArrayStoreException (expected)" catc
+  h) . <- .
+  next 012b
+  live out:{59}
+block 0085
+  pred 012b
+  live in:{59, 60}
+  Blort.java:30@0085: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  String; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V 
+  catch) . <- v59:Ljava/io/PrintStream; v60:Ljava/lang/String;="caught ArraySto
+  reException (expected)"
+  next 012f
+  live out:{}
+block 0088
+  pred 007b
+  pred 012f
+  live in:{}
+  Blort.java:32@0088: goto . <- .
+  next 0113
+  live out:{}
+block 0107
+  pred 012d
+  pred 012e
+  live in:{}
+  @????: phi v58:Ljava/lang/ArrayStoreException; <- v52:Ljava/lang/ArrayStoreEx
+  ception;[b=012e] v61:Ljava/lang/ArrayStoreException;[b=012d]
+  Blort.java:28@007e: goto . <- .
+  next 007e
+  live out:{58}
+block 0112
+  pred 012c
+  live in:{62, 63}
+  Blort.java:5@0000: move-param-int(0) v12:"k"I <- .
+  Blort.java:5@0000: goto . <- .
+  next 0000
+  live out:{12, 62, 63}
+block 0113
+  pred 0088
+  live in:{}
+  Blort.java:32@0088: return-void . <- .
+  next 0132
+  live out:{}
+block 0119
+  pred 0000
+  live in:{62, 63}
+  Blort.java:7@0004: Rop{move-result-pseudo [Ljava/lang/String; <- . flows} v15
+  :[Ljava/lang/String; <- .
+  Blort.java:7@0004: goto . <- .
+  next 0007
+  live out:{15, 62, 63}
+block 011a
+  pred 0007
+  live in:{15, 62}
+  Blort.java:8@000a: Rop{move-result-pseudo [Ljava/lang/Object; <- . flows} v17
+  :[Ljava/lang/Object; <- .
+  Blort.java:8@000a: goto . <- .
+  next 000d
+  live out:{15, 17, 62}
+block 011b
+  pred 0016
+  live in:{15, 17, 62}
+  Blort.java:13@0016: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v19:Ljava/io/PrintStream; <- .
+  Blort.java:13@0016: goto . <- .
+  next 0019
+  live out:{15, 17, 19, 62}
+block 011c
+  pred 0019
+  live in:{15, 17, 19, 62}
+  Blort.java:13@0019: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v20
+  :Ljava/lang/String;="foo" <- .
+  Blort.java:13@0019: goto . <- .
+  next 001b
+  live out:{15, 17, 19, 20, 62}
+block 011d
+  pred 0021
+  live in:{15, 17, 30, 62}
+  Blort.java:17@0024: Rop{move-result-pseudo I <- . flows} v31:I <- .
+  Blort.java:17@0024: goto . <- .
+  next 0025
+  live out:{15, 17, 30, 31, 62}
+block 011e
+  pred 0028
+  live in:{15, 17, 30, 62}
+  Blort.java:18@002b: Rop{move-result-pseudo N002bLjava/lang/String; <- . flows
+  } v32:N002bLjava/lang/String; <- .
+  Blort.java:18@002b: goto . <- .
+  next 002e
+  live out:{15, 17, 30, 32, 62}
+block 011f
+  pred 002e
+  live in:{15, 17, 30, 32, 62}
+  Blort.java:18@0031: Rop{move-result Ljava/lang/String; <- . flows} v33:Ljava/
+  lang/String; <- .
+  Blort.java:18@0031: goto . <- .
+  next 0034
+  live out:{15, 17, 30, 32, 33, 62}
+block 0120
+  pred 003e
+  live in:{15, 17, 62}
+  Blort.java:20@003e: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v35:Ljava/io/PrintStream; <- .
+  Blort.java:20@003e: goto . <- .
+  next 0041
+  live out:{15, 17, 35, 62}
+block 0121
+  pred 0041
+  live in:{15, 17, 35, 62}
+  Blort.java:20@0041: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v36
+  :Ljava/lang/String;="string -> object" <- .
+  Blort.java:20@0041: goto . <- .
+  next 0043
+  live out:{15, 17, 35, 36, 62}
+block 0122
+  pred 0046
+  live in:{15, 17, 62}
+  Blort.java:21@004b: Rop{move-result-pseudo I <- . flows} v39:I <- .
+  Blort.java:21@004b: goto . <- .
+  next 004c
+  live out:{15, 17, 39, 62}
+block 0123
+  pred 004f
+  live in:{15, 17, 62}
+  Blort.java:22@004f: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v40:Ljava/io/PrintStream; <- .
+  Blort.java:22@004f: goto . <- .
+  next 0052
+  live out:{15, 17, 40, 62}
+block 0124
+  pred 0052
+  live in:{15, 17, 40, 62}
+  Blort.java:22@0052: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v41
+  :Ljava/lang/String;="object -> string" <- .
+  Blort.java:22@0052: goto . <- .
+  next 0054
+  live out:{15, 17, 40, 41, 62}
+block 0125
+  pred 0057
+  live in:{15, 17, 62}
+  Blort.java:23@005c: Rop{move-result-pseudo I <- . flows} v44:I <- .
+  Blort.java:23@005c: goto . <- .
+  next 005d
+  live out:{15, 17, 44, 62}
+block 0126
+  pred 0060
+  live in:{15, 17}
+  Blort.java:24@0060: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v45:Ljava/io/PrintStream; <- .
+  Blort.java:24@0060: goto . <- .
+  next 0063
+  live out:{15, 17, 45}
+block 0127
+  pred 0063
+  live in:{15, 17, 45}
+  Blort.java:24@0063: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v46
+  :Ljava/lang/String;="object -> string (modified)" <- .
+  Blort.java:24@0063: goto . <- .
+  next 0065
+  live out:{15, 17, 45, 46}
+block 0128
+  pred 0068
+  live in:{15, 17, 47}
+  Blort.java:25@006a: Rop{move-result-pseudo N006aLjava/lang/Object; <- . flows
+  } v48:N006aLjava/lang/Object; <- .
+  Blort.java:25@006a: goto . <- .
+  next 006d
+  live out:{15, 17, 47, 48}
+block 0129
+  pred 0072
+  live in:{15, 17, 49, 50}
+  Blort.java:27@0077: Rop{move-result-pseudo I <- . flows} v51:I <- .
+  Blort.java:27@0077: goto . <- .
+  next 0078
+  live out:{15, 17, 49, 50, 51}
+block 012a
+  pred 007e
+  live in:{}
+  Blort.java:30@0080: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v59:Ljava/io/PrintStream; <- .
+  Blort.java:30@0080: goto . <- .
+  next 0083
+  live out:{59}
+block 012b
+  pred 0083
+  live in:{59}
+  Blort.java:30@0083: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v60
+  :Ljava/lang/String;="caught ArrayStoreException (expected)" <- .
+  Blort.java:30@0083: goto . <- .
+  next 0085
+  live out:{59, 60}
+block 012c
+  live in:{}
+  @????: const-int(8) v63:I=8 <- .
+  @????: const-int(0) v62:I=0 <- .
+  @????: goto . <- .
+  next 0112
+  live out:{62, 63}
+block 012d
+  pred 0072
+  live in:{}
+  Blort.java:28@007e: Rop{move-exception Ljava/lang/ArrayStoreException; <- . f
+  lows} v61:Ljava/lang/ArrayStoreException; <- .
+  @????: goto . <- .
+  next 0107
+  live out:{61}
+block 012e
+  pred 0078
+  live in:{}
+  Blort.java:28@007e: Rop{move-exception Ljava/lang/ArrayStoreException; <- . f
+  lows} v52:Ljava/lang/ArrayStoreException; <- .
+  @????: goto . <- .
+  next 0107
+  live out:{52}
+block 012f
+  pred 0085
+  live in:{}
+  @????: goto . <- .
+  next 0088
+  live out:{}
+block 0130
+  pred 001b
+  live in:{15, 17, 62}
+  @????: goto . <- .
+  next 001e
+  live out:{15, 17, 62}
+block 0131
+  pred 000d
+  live in:{15, 17, 62}
+  @????: goto . <- .
+  next 001e
+  live out:{15, 17, 62}
+block 0132
+  pred 0113
+  live in:{}
+  returns
+  live out:{}
+
+method testConstructor ()V
+first 0035
+block 0000
+  pred 002c
+  live in:{}
+  Blort.java:35@0000: const-object-nothrow(null) v7:<null>=null <- .
+  @????: mark-local-object . <- v7:"foo"LBlort;
+  Blort.java:35@0001: goto . <- .
+  next 0002
+  live out:{7}
+block 0002
+  pred 0000
+  live in:{7}
+  Blort.java:37@0002: new-instance(Blort catch java.lang.Exception) . <- .
+  next 0036
+  next 0033 *
+  live out:{7}
+block 0005
+  pred 0033
+  live in:{7, 8}
+  Blort.java:37@0006: Rop{invoke-direct . <- LBlort; call throws <any>}(Blort.<
+  init>:()V catch java.lang.Exception) . <- v8:N0002LBlort;
+  next 0037
+  next 0009 *
+  live out:{7, 8}
+block 0009
+  pred 0005
+  live in:{8}
+  @????: mark-local-object . <- v8:"foo"LBlort;
+  Blort.java:37@0009: goto . <- .
+  next 000a
+  live out:{8}
+block 000a
+  pred 0009
+  live in:{8}
+  Blort.java:39@000a: goto . <- .
+  next 000e
+  live out:{8}
+block 000d
+  pred 0023
+  live in:{7}
+  Blort.java:38@000d: goto . <- .
+  next 000e
+  live out:{7}
+block 000e
+  pred 000a
+  pred 000d
+  live in:{}
+  @????: phi v14:"foo"LBlort; <- v8:"foo"LBlort;[b=000a] v7:"foo"LBlort;[b=000d
+  ]
+  Blort.java:40@000e: get-static-object(java.lang.System.err:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 0034
+  live out:{14}
+block 0011
+  pred 0034
+  live in:{14, 15}
+  Blort.java:40@0012: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  Object; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/Object;)V 
+  catch) . <- v15:Ljava/io/PrintStream; v14:LBlort;
+  next 0015
+  live out:{}
+block 0015
+  pred 0011
+  live in:{}
+  Blort.java:41@0015: goto . <- .
+  next 002d
+  live out:{}
+block 0023
+  pred 0036
+  pred 0037
+  live in:{7}
+  Blort.java:38@000d: goto . <- .
+  next 000d
+  live out:{7}
+block 002c
+  pred 0035
+  live in:{}
+  Blort.java:35@0000: move-param-object(0) v6:"this"LBlort; <- .
+  Blort.java:35@0000: goto . <- .
+  next 0000
+  live out:{}
+block 002d
+  pred 0015
+  live in:{}
+  Blort.java:41@0015: return-void . <- .
+  next 0038
+  live out:{}
+block 0033
+  pred 0002
+  live in:{7}
+  Blort.java:37@0002: Rop{move-result-pseudo N0002LBlort; <- . flows} v8:N0002L
+  Blort; <- .
+  Blort.java:37@0002: goto . <- .
+  next 0005
+  live out:{7, 8}
+block 0034
+  pred 000e
+  live in:{14}
+  Blort.java:40@000e: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v15:Ljava/io/PrintStream; <- .
+  Blort.java:40@000e: goto . <- .
+  next 0011
+  live out:{14, 15}
+block 0035
+  live in:{}
+  @????: goto . <- .
+  next 002c
+  live out:{}
+block 0036
+  pred 0002
+  live in:{7}
+  Blort.java:38@000d: Rop{move-exception Ljava/lang/Exception; <- . flows} v19:
+  Ljava/lang/Exception; <- .
+  @????: goto . <- .
+  next 0023
+  live out:{7}
+block 0037
+  pred 0005
+  live in:{7}
+  Blort.java:38@000d: Rop{move-exception Ljava/lang/Exception; <- . flows} v9:L
+  java/lang/Exception; <- .
+  @????: goto . <- .
+  next 0023
+  live out:{7}
+block 0038
+  pred 002d
+  live in:{}
+  returns
+  live out:{}
+
+method parseHeaderGroup (Ljava/lang/Object;Ljava/lang/Object;II)V
+first 01c6
+block 0000
+  pred 01ae
+  live in:{16, 17, 18, 99, 100, 101}
+  Blort.java:57@0000: const-object-nothrow(null) v19:<null>=null <- .
+  @????: mark-local-object . <- v19:"current"Ljava/lang/StringBuilder;
+  Blort.java:58@0003: const-object-nothrow(null) v20:<null>=null <- .
+  @????: mark-local-object . <- v20:"previous"Ljava/lang/StringBuilder;
+  Blort.java:58@0004: goto . <- .
+  next 01ca
+  live out:{16, 17, 18, 19, 20, 99, 100, 101}
+block 0006
+  pred 01ca
+  live in:{16, 17, 18, 30, 31, 99, 100, 101}
+  Blort.java:60@0008: if-nez-object . <- v31:Ljava/lang/StringBuilder;
+  next 000b *
+  next 0019
+  live out:{16, 17, 18, 30, 31, 99, 100, 101}
+block 000b
+  pred 0006
+  live in:{16, 17, 18, 30, 99, 100, 101}
+  Blort.java:61@000b: new-instance(java.lang.StringBuilder catch) . <- .
+  next 01b5
+  live out:{16, 17, 18, 30, 99, 100, 101}
+block 000e
+  pred 01b5
+  live in:{16, 17, 18, 30, 32, 99, 100, 101}
+  Blort.java:61@000f: const-int(64) v33:I=64 <- .
+  Blort.java:61@0011: Rop{invoke-direct . <- Ljava/lang/StringBuilder; I call t
+  hrows <any>}(java.lang.StringBuilder.<init>:(I)V catch) . <- v32:N000bLjava/l
+  ang/StringBuilder; v33:I=64
+  next 0014
+  live out:{16, 17, 18, 30, 32, 99, 100, 101}
+block 0014
+  pred 000e
+  live in:{16, 17, 18, 30, 32, 99, 100, 101}
+  @????: mark-local-object . <- v32:"current"Ljava/lang/StringBuilder;
+  Blort.java:61@0016: goto . <- .
+  next 001f
+  live out:{16, 17, 18, 30, 32, 99, 100, 101}
+block 0019
+  pred 0006
+  live in:{16, 17, 18, 30, 31, 99, 100, 101}
+  Blort.java:63@001b: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; call th
+  rows <any>}(java.lang.StringBuilder.length:()I catch) . <- v31:Ljava/lang/Str
+  ingBuilder;
+  next 01b6
+  live out:{16, 17, 18, 30, 31, 99, 100, 101}
+block 001e
+  pred 01b6
+  live in:{16, 17, 18, 30, 31, 99, 100, 101}
+  @????: goto . <- .
+  next 001f
+  live out:{16, 17, 18, 30, 31, 99, 100, 101}
+block 001f
+  pred 0014
+  pred 001e
+  live in:{16, 17, 18, 30, 99, 100, 101}
+  @????: phi v39:"current"Ljava/lang/StringBuilder; <- v32:"current"Ljava/lang/
+  StringBuilder;[b=0014] v31:"current"Ljava/lang/StringBuilder;[b=001e]
+  Blort.java:65@0020: Rop{invoke-virtual . <- Ljava/lang/Object; call throws <a
+  ny>}(java.lang.Object.hashCode:()I catch) . <- v16:Ljava/lang/Object;
+  next 01b7
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 0023
+  pred 01b7
+  live in:{16, 17, 18, 30, 39, 40, 99, 100, 101}
+  @????: mark-local-int . <- v40:"l"I
+  Blort.java:66@0027: const-int(-1) v41:I=-1 <- .
+  Blort.java:66@0028: if-eq-int . <- v40:I v41:I=-1
+  next 002b *
+  next 01d4
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 002b
+  pred 0023
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:66@002d: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; call th
+  rows <any>}(java.lang.StringBuilder.length:()I catch) . <- v39:Ljava/lang/Str
+  ingBuilder;
+  next 01b8
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 0030
+  pred 01b8
+  live in:{16, 17, 18, 30, 39, 42, 99, 100, 101}
+  Blort.java:66@0030: const-int(1) v43:I=1 <- .
+  Blort.java:66@0031: if-ge-int . <- v42:I v43:I=1
+  next 0034 *
+  next 0037
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 0034
+  pred 0030
+  live in:{}
+  Blort.java:67@0034: goto . <- .
+  next 00d6
+  live out:{}
+block 0037
+  pred 0030
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:70@003a: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; I call 
+  throws <any>}(java.lang.StringBuilder.charAt:(I)C catch) . <- v39:Ljava/lang/
+  StringBuilder; v100:I=0
+  next 01b9
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 003d
+  pred 01b9
+  live in:{16, 17, 18, 30, 39, 45, 99, 100, 101}
+  Blort.java:70@003f: if-eq-int . <- v45:I v99:I=32
+  next 0042 *
+  next 01d3
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 0042
+  pred 003d
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:70@0045: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; I call 
+  throws <any>}(java.lang.StringBuilder.charAt:(I)C catch) . <- v39:Ljava/lang/
+  StringBuilder; v100:I=0
+  next 01ba
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 0048
+  pred 01ba
+  live in:{16, 17, 18, 30, 39, 48, 99, 100, 101}
+  Blort.java:70@004a: if-ne-int . <- v48:I v101:I=9
+  next 01d2 *
+  next 01d1
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 004d
+  pred 01c9
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:70@004f: if-eqz-object . <- v30:Ljava/lang/StringBuilder;
+  next 0052 *
+  next 01d0
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 0052
+  pred 004d
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:71@0052: const-int(0) v67:I=0 <- .
+  @????: mark-local-int . <- v67:"i"I
+  Blort.java:71@0053: goto . <- .
+  next 0055
+  live out:{16, 17, 18, 30, 39, 67, 99, 100, 101}
+block 0055
+  pred 0052
+  pred 0079
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  @????: phi v71:"i"I <- v67:"i"I[b=0052] v78:"i"I[b=0079]
+  Blort.java:72@0059: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; call th
+  rows <any>}(java.lang.StringBuilder.length:()I catch) . <- v39:Ljava/lang/Str
+  ingBuilder;
+  next 01bb
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 005c
+  pred 01bb
+  live in:{16, 17, 18, 30, 39, 71, 72, 99, 100, 101}
+  Blort.java:72@005c: if-ge-int . <- v71:I v72:I
+  next 005f *
+  next 01cf
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 005f
+  pred 005c
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:73@0063: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; I call 
+  throws <any>}(java.lang.StringBuilder.charAt:(I)C catch) . <- v39:Ljava/lang/
+  StringBuilder; v71:I
+  next 01bc
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 0066
+  pred 01bc
+  live in:{16, 17, 18, 30, 39, 71, 73, 99, 100, 101}
+  @????: mark-local-int . <- v73:"ch"C
+  Blort.java:74@006c: if-eq-int . <- v73:I v99:I=32
+  next 006f *
+  next 01ce
+  live out:{16, 17, 18, 30, 39, 71, 73, 99, 100, 101}
+block 006f
+  pred 0066
+  live in:{16, 17, 18, 30, 39, 71, 73, 99, 100, 101}
+  Blort.java:74@0073: if-eq-int . <- v73:I v101:I=9
+  next 0076 *
+  next 01cd
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 0076
+  pred 006f
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:75@0076: goto . <- .
+  next 01c8
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 0079
+  pred 01cd
+  pred 01ce
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:77@0079: add-const-int(1) v78:"i"I <- v71:I
+  Blort.java:78@007c: goto . <- .
+  next 0055
+  live out:{16, 17, 18, 30, 39, 78, 99, 100, 101}
+block 007f
+  pred 01c8
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:79@0080: if-lez-int . <- v18:I
+  next 0083 *
+  next 01cc
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 0083
+  pred 007f
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:79@0085: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; call th
+  rows <any>}(java.lang.StringBuilder.length:()I catch) . <- v30:Ljava/lang/Str
+  ingBuilder;
+  next 01bd
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 0088
+  pred 01bd
+  live in:{16, 17, 18, 30, 39, 71, 82, 99, 100, 101}
+  Blort.java:79@0089: add-const-int(1) v84:I <- v82:I
+  Blort.java:79@008c: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; call th
+  rows <any>}(java.lang.StringBuilder.length:()I catch) . <- v39:Ljava/lang/Str
+  ingBuilder;
+  next 01be
+  live out:{16, 17, 18, 30, 39, 71, 84, 99, 100, 101}
+block 008f
+  pred 01be
+  live in:{16, 17, 18, 30, 39, 71, 84, 85, 99, 100, 101}
+  Blort.java:79@008f: add-int v86:I <- v84:I v85:I
+  Blort.java:79@0092: sub-int v87:I <- v86:I v71:I
+  Blort.java:79@0094: if-le-int . <- v87:I v18:I
+  next 0097 *
+  next 01cb
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 0097
+  pred 008f
+  live in:{}
+  Blort.java:81@0097: new-instance(java.io.IOException catch) . <- .
+  next 01bf
+  live out:{}
+block 009a
+  pred 01bf
+  live in:{88}
+  Blort.java:81@009b: const-object("Maximum line length limit exceeded" catch) 
+  . <- .
+  next 01c0
+  live out:{88}
+block 009d
+  pred 01c0
+  live in:{88, 89}
+  Blort.java:81@009d: Rop{invoke-direct . <- Ljava/io/IOException; Ljava/lang/S
+  tring; call throws <any>}(java.io.IOException.<init>:(Ljava/lang/String;)V ca
+  tch) . <- v88:N0097Ljava/io/IOException; v89:Ljava/lang/String;="Maximum line
+   length limit exceeded"
+  next 00a0
+  live out:{88}
+block 00a0
+  pred 009d
+  live in:{88}
+  Blort.java:81@00a0: throw(catch) . <- v88:Ljava/io/IOException;
+  next 01d5
+  live out:{}
+block 00a1
+  pred 01cb
+  pred 01cc
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:83@00a5: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; I call 
+  throws <any>}(java.lang.StringBuilder.append:(C)Ljava/lang/StringBuilder; cat
+  ch) . <- v30:Ljava/lang/StringBuilder; v99:I=32
+  next 01c1
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 00a8
+  pred 01c1
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:84@00b1: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; call th
+  rows <any>}(java.lang.StringBuilder.length:()I catch) . <- v39:Ljava/lang/Str
+  ingBuilder;
+  next 01c2
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 00b4
+  pred 01c2
+  live in:{16, 17, 18, 30, 39, 71, 94, 99, 100, 101}
+  Blort.java:84@00b6: sub-int v95:I <- v94:I v71:I
+  Blort.java:84@00b7: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/CharSequence; I I call throws <any>}(java.lang.StringBuilder.append:(Ljav
+  a/lang/CharSequence;II)Ljava/lang/StringBuilder; catch) . <- v30:Ljava/lang/S
+  tringBuilder; v39:Ljava/lang/StringBuilder; v71:I v95:I
+  next 01c3
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 00ba
+  pred 01c3
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:85@00bb: goto . <- .
+  next 01c7
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 00be
+  pred 01d0
+  pred 01d1
+  live in:{16, 17, 18, 39, 99, 100, 101}
+  Blort.java:86@00c0: move-object v52:"previous"Ljava/lang/StringBuilder; <- v3
+  9:Ljava/lang/StringBuilder;
+  Blort.java:87@00c2: const-object-nothrow(null) v53:<null>=null <- .
+  @????: mark-local-object . <- v53:"current"Ljava/lang/StringBuilder;
+  Blort.java:87@00c3: goto . <- .
+  next 01c7
+  live out:{16, 17, 18, 52, 53, 99, 100, 101}
+block 00c5
+  pred 01c7
+  live in:{16, 17, 18, 61, 62, 99, 100, 101}
+  Blort.java:89@00c6: if-lez-int . <- v17:I
+  next 00c9 *
+  next 00d3
+  live out:{16, 17, 18, 61, 62, 99, 100, 101}
+block 00c9
+  pred 00c5
+  live in:{}
+  Blort.java:90@00c9: new-instance(java.io.IOException catch) . <- .
+  next 01c4
+  live out:{}
+block 00cc
+  pred 01c4
+  live in:{63}
+  Blort.java:90@00cd: const-object("Maximum header count exceeded" catch) . <- 
+  .
+  next 01c5
+  live out:{63}
+block 00cf
+  pred 01c5
+  live in:{63, 64}
+  Blort.java:90@00cf: Rop{invoke-direct . <- Ljava/io/IOException; Ljava/lang/S
+  tring; call throws <any>}(java.io.IOException.<init>:(Ljava/lang/String;)V ca
+  tch) . <- v63:N00c9Ljava/io/IOException; v64:Ljava/lang/String;="Maximum head
+  er count exceeded"
+  next 00d2
+  live out:{63}
+block 00d2
+  pred 00cf
+  live in:{63}
+  Blort.java:90@00d2: throw(catch) . <- v63:Ljava/io/IOException;
+  next 01d5
+  live out:{}
+block 00d3
+  pred 00c5
+  live in:{16, 17, 18, 61, 62, 99, 100, 101}
+  Blort.java:92@00d3: goto . <- .
+  next 01ca
+  live out:{16, 17, 18, 61, 62, 99, 100, 101}
+block 00d6
+  pred 0034
+  pred 01d4
+  live in:{}
+  Blort.java:93@00d6: goto . <- .
+  next 01af
+  live out:{}
+block 01ae
+  pred 01c6
+  live in:{99, 100, 101}
+  Blort.java:57@0000: move-param-object(0) v15:"headGroup"Ljava/lang/Object; <-
+   .
+  Blort.java:57@0000: move-param-object(1) v16:"inbuffer"Ljava/lang/Object; <- 
+  .
+  Blort.java:57@0000: move-param-int(2) v17:"maxHeaderCount"I <- .
+  Blort.java:57@0000: move-param-int(3) v18:"maxLineLen"I <- .
+  Blort.java:57@0000: goto . <- .
+  next 0000
+  live out:{16, 17, 18, 99, 100, 101}
+block 01af
+  pred 00d6
+  live in:{}
+  Blort.java:93@00d6: return-void . <- .
+  next 01d5
+  live out:{}
+block 01b5
+  pred 000b
+  live in:{16, 17, 18, 30, 99, 100, 101}
+  Blort.java:61@000b: Rop{move-result-pseudo N000bLjava/lang/StringBuilder; <- 
+  . flows} v32:N000bLjava/lang/StringBuilder; <- .
+  Blort.java:61@000b: goto . <- .
+  next 000e
+  live out:{16, 17, 18, 30, 32, 99, 100, 101}
+block 01b6
+  pred 0019
+  live in:{16, 17, 18, 30, 31, 99, 100, 101}
+  Blort.java:63@001b: goto . <- .
+  next 001e
+  live out:{16, 17, 18, 30, 31, 99, 100, 101}
+block 01b7
+  pred 001f
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:65@0020: Rop{move-result I <- . flows} v40:I <- .
+  Blort.java:65@0020: goto . <- .
+  next 0023
+  live out:{16, 17, 18, 30, 39, 40, 99, 100, 101}
+block 01b8
+  pred 002b
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:66@002d: Rop{move-result I <- . flows} v42:I <- .
+  Blort.java:66@002d: goto . <- .
+  next 0030
+  live out:{16, 17, 18, 30, 39, 42, 99, 100, 101}
+block 01b9
+  pred 0037
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:70@003a: Rop{move-result C <- . flows} v45:C <- .
+  Blort.java:70@003a: goto . <- .
+  next 003d
+  live out:{16, 17, 18, 30, 39, 45, 99, 100, 101}
+block 01ba
+  pred 0042
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:70@0045: Rop{move-result C <- . flows} v48:C <- .
+  Blort.java:70@0045: goto . <- .
+  next 0048
+  live out:{16, 17, 18, 30, 39, 48, 99, 100, 101}
+block 01bb
+  pred 0055
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:72@0059: Rop{move-result I <- . flows} v72:I <- .
+  Blort.java:72@0059: goto . <- .
+  next 005c
+  live out:{16, 17, 18, 30, 39, 71, 72, 99, 100, 101}
+block 01bc
+  pred 005f
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:73@0063: Rop{move-result C <- . flows} v73:C <- .
+  Blort.java:73@0063: goto . <- .
+  next 0066
+  live out:{16, 17, 18, 30, 39, 71, 73, 99, 100, 101}
+block 01bd
+  pred 0083
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:79@0085: Rop{move-result I <- . flows} v82:I <- .
+  Blort.java:79@0085: goto . <- .
+  next 0088
+  live out:{16, 17, 18, 30, 39, 71, 82, 99, 100, 101}
+block 01be
+  pred 0088
+  live in:{16, 17, 18, 30, 39, 71, 84, 99, 100, 101}
+  Blort.java:79@008c: Rop{move-result I <- . flows} v85:I <- .
+  Blort.java:79@008c: goto . <- .
+  next 008f
+  live out:{16, 17, 18, 30, 39, 71, 84, 85, 99, 100, 101}
+block 01bf
+  pred 0097
+  live in:{}
+  Blort.java:81@0097: Rop{move-result-pseudo N0097Ljava/io/IOException; <- . fl
+  ows} v88:N0097Ljava/io/IOException; <- .
+  Blort.java:81@0097: goto . <- .
+  next 009a
+  live out:{88}
+block 01c0
+  pred 009a
+  live in:{88}
+  Blort.java:81@009b: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v89
+  :Ljava/lang/String;="Maximum line length limit exceeded" <- .
+  Blort.java:81@009b: goto . <- .
+  next 009d
+  live out:{88, 89}
+block 01c1
+  pred 00a1
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:83@00a5: goto . <- .
+  next 00a8
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01c2
+  pred 00a8
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  Blort.java:84@00b1: Rop{move-result I <- . flows} v94:I <- .
+  Blort.java:84@00b1: goto . <- .
+  next 00b4
+  live out:{16, 17, 18, 30, 39, 71, 94, 99, 100, 101}
+block 01c3
+  pred 00b4
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  Blort.java:84@00b7: goto . <- .
+  next 00ba
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 01c4
+  pred 00c9
+  live in:{}
+  Blort.java:90@00c9: Rop{move-result-pseudo N00c9Ljava/io/IOException; <- . fl
+  ows} v63:N00c9Ljava/io/IOException; <- .
+  Blort.java:90@00c9: goto . <- .
+  next 00cc
+  live out:{63}
+block 01c5
+  pred 00cc
+  live in:{63}
+  Blort.java:90@00cd: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v64
+  :Ljava/lang/String;="Maximum header count exceeded" <- .
+  Blort.java:90@00cd: goto . <- .
+  next 00cf
+  live out:{63, 64}
+block 01c6
+  live in:{}
+  @????: const-int(9) v101:I=9 <- .
+  @????: const-int(0) v100:I=0 <- .
+  @????: const-int(32) v99:I=32 <- .
+  @????: goto . <- .
+  next 01ae
+  live out:{99, 100, 101}
+block 01c7
+  pred 00ba
+  pred 00be
+  live in:{16, 17, 18, 99, 100, 101}
+  @????: phi v61:"previous"Ljava/lang/StringBuilder; <- v52:"previous"Ljava/lan
+  g/StringBuilder;[b=00be] v30:"previous"Ljava/lang/StringBuilder;[b=00ba]
+  @????: phi v62:"current"Ljava/lang/StringBuilder; <- v53:"current"Ljava/lang/
+  StringBuilder;[b=00be] v39:"current"Ljava/lang/StringBuilder;[b=00ba]
+  @????: goto . <- .
+  next 00c5
+  live out:{16, 17, 18, 61, 62, 99, 100, 101}
+block 01c8
+  pred 0076
+  pred 01cf
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  @????: goto . <- .
+  next 007f
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01c9
+  pred 01d2
+  pred 01d3
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  @????: goto . <- .
+  next 004d
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 01ca
+  pred 0000
+  pred 00d3
+  live in:{16, 17, 18, 99, 100, 101}
+  @????: phi v30:"previous"Ljava/lang/StringBuilder; <- v20:"previous"Ljava/lan
+  g/StringBuilder;[b=0000] v61:"previous"Ljava/lang/StringBuilder;[b=00d3]
+  @????: phi v31:"current"Ljava/lang/StringBuilder; <- v19:"current"Ljava/lang/
+  StringBuilder;[b=0000] v62:"current"Ljava/lang/StringBuilder;[b=00d3]
+  @????: goto . <- .
+  next 0006
+  live out:{16, 17, 18, 30, 31, 99, 100, 101}
+block 01cb
+  pred 008f
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  @????: goto . <- .
+  next 00a1
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01cc
+  pred 007f
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  @????: goto . <- .
+  next 00a1
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01cd
+  pred 006f
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  @????: goto . <- .
+  next 0079
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01ce
+  pred 0066
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  @????: goto . <- .
+  next 0079
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01cf
+  pred 005c
+  live in:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+  @????: goto . <- .
+  next 01c8
+  live out:{16, 17, 18, 30, 39, 71, 99, 100, 101}
+block 01d0
+  pred 004d
+  live in:{16, 17, 18, 39, 99, 100, 101}
+  @????: goto . <- .
+  next 00be
+  live out:{16, 17, 18, 39, 99, 100, 101}
+block 01d1
+  pred 0048
+  live in:{16, 17, 18, 39, 99, 100, 101}
+  @????: goto . <- .
+  next 00be
+  live out:{16, 17, 18, 39, 99, 100, 101}
+block 01d2
+  pred 0048
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  @????: goto . <- .
+  next 01c9
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 01d3
+  pred 003d
+  live in:{16, 17, 18, 30, 39, 99, 100, 101}
+  @????: goto . <- .
+  next 01c9
+  live out:{16, 17, 18, 30, 39, 99, 100, 101}
+block 01d4
+  pred 0023
+  live in:{}
+  @????: goto . <- .
+  next 00d6
+  live out:{}
+block 01d5
+  pred 00a0
+  pred 00d2
+  pred 01af
+  live in:{}
+  returns
+  live out:{}
diff --git a/dx/tests/087-ssa-local-vars/info.txt b/dx/tests/087-ssa-local-vars/info.txt
new file mode 100644
index 0000000..6e9d675
--- /dev/null
+++ b/dx/tests/087-ssa-local-vars/info.txt
@@ -0,0 +1,5 @@
+This is a test case to ensure proper preservation of local variable information through the register renamer and dead code remover at the beginning of the SSA conversion.
+
+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/087-ssa-local-vars/run b/dx/tests/087-ssa-local-vars/run
new file mode 100644
index 0000000..ae97c15
--- /dev/null
+++ b/dx/tests/087-ssa-local-vars/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --dump --ssa-blocks Blort.class
diff --git a/dx/tests/088-ssa-combine-blocks/Blort.java b/dx/tests/088-ssa-combine-blocks/Blort.java
new file mode 100644
index 0000000..bf49dbe
--- /dev/null
+++ b/dx/tests/088-ssa-combine-blocks/Blort.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    /**
+     * just because this should do nothing
+     */
+    void voidFunction() {
+    }
+
+    /**
+     * Current SSA form requires each move-exception block to have
+     * a unique predecessor
+     */
+    void edgeSplitMoveException() {
+        try {
+            hashCode();
+            hashCode();
+        } catch (Throwable tr) {
+        }
+    }
+
+    /**
+     * An empty infinite loop for the empty goto optimizer
+     */
+    void infiniteLoop() {
+        while (true) {
+        }
+    }
+}
diff --git a/dx/tests/088-ssa-combine-blocks/expected.txt b/dx/tests/088-ssa-combine-blocks/expected.txt
new file mode 100644
index 0000000..e00f774
--- /dev/null
+++ b/dx/tests/088-ssa-combine-blocks/expected.txt
@@ -0,0 +1,82 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  Blort.java:17@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <any>}(java.lang.Object.<init>:()V catch) . <- v0:NffffLBlort;
+  next 000b
+block 000a
+  pred 000c
+  Blort.java:17@0000: move-param-object(0) v0:NffffLBlort; <- .
+  Blort.java:17@0000: goto . <- .
+  next 0000
+block 000b
+  pred 0000
+  Blort.java:17@0004: return-void . <- .
+  returns
+block 000c
+  @????: goto . <- .
+  next 000a
+
+method voidFunction ()V
+first 0004
+block 0002
+  pred 0004
+  Blort.java:23@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:23@0000: goto . <- .
+  next 0003
+block 0003
+  pred 0002
+  Blort.java:23@0000: return-void . <- .
+  returns
+block 0004
+  @????: goto . <- .
+  next 0002
+
+method edgeSplitMoveException ()V
+first 0027
+block 0000
+  pred 001e
+  Blort.java:31@0001: Rop{invoke-virtual . <- Ljava/lang/Object; call throws <any>}(java.lang.Object.hashCode:()I catch java.lang.Throwable) . <- v1:LBlort;
+  next 0028
+  next 0004 *
+block 0004
+  pred 0000
+  Blort.java:32@0006: Rop{invoke-virtual . <- Ljava/lang/Object; call throws <any>}(java.lang.Object.hashCode:()I catch java.lang.Throwable) . <- v1:LBlort;
+  next 0028
+  next 001f *
+block 001e
+  pred 0027
+  Blort.java:31@0000: move-param-object(0) v1:LBlort; <- .
+  Blort.java:31@0000: goto . <- .
+  next 0000
+block 001f
+  pred 0004
+  pred 0028
+  Blort.java:35@000e: return-void . <- .
+  returns
+block 0027
+  @????: goto . <- .
+  next 001e
+block 0028
+  pred 0000
+  pred 0004
+  Blort.java:33@000d: Rop{move-exception Ljava/lang/Throwable; <- . flows} v0:Ljava/lang/Throwable; <- .
+  @????: goto . <- .
+  next 001f
+
+method infiniteLoop ()V
+first 0003
+block 0000
+  pred 0000
+  pred 0002
+  Blort.java:41@0000: goto . <- .
+  next 0000
+block 0002
+  pred 0003
+  Blort.java:41@0000: move-param-object(0) v0:LBlort; <- .
+  Blort.java:41@0000: goto . <- .
+  next 0000
+block 0003
+  @????: goto . <- .
+  next 0002
diff --git a/dx/tests/088-ssa-combine-blocks/info.txt b/dx/tests/088-ssa-combine-blocks/info.txt
new file mode 100644
index 0000000..603c1c0
--- /dev/null
+++ b/dx/tests/088-ssa-combine-blocks/info.txt
@@ -0,0 +1,5 @@
+This is a test case for the identical-block combining algorithm, which runs after the SSA optimizer to recombine identical blocks (usually exception handlers) created during edge-splitting.
+
+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/088-ssa-combine-blocks/run b/dx/tests/088-ssa-combine-blocks/run
new file mode 100644
index 0000000..29fe559
--- /dev/null
+++ b/dx/tests/088-ssa-combine-blocks/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java
+dx --dump --width=1000 --optimize --rop-blocks Blort.class
diff --git a/dx/tests/089-dex-define-object/Class.java b/dx/tests/089-dex-define-object/Class.java
new file mode 100644
index 0000000..4de5e70
--- /dev/null
+++ b/dx/tests/089-dex-define-object/Class.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang;
+
+public class Class<T> {
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/089-dex-define-object/Object.java b/dx/tests/089-dex-define-object/Object.java
new file mode 100644
index 0000000..575c736
--- /dev/null
+++ b/dx/tests/089-dex-define-object/Object.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang;
+
+public class Object {
+    public Object() {
+        // This space intentionally left blank.
+    }
+
+    public boolean equals(Object o) {
+        return true;
+    }
+
+    protected void finalize() {
+        // This space intentionally left blank.
+    }
+
+    public final native Class<? extends Object> getClass();
+    public native int hashCode();
+    public final native void notify();
+    public final native void notifyAll();
+
+    public String toString() {
+        return "blort";
+    }
+
+    public final void wait() {
+        wait(0, 0);
+    }
+
+    public final void wait(long time) {
+        wait(time, 0);
+    }
+
+    public final native void wait(long time, int frac);
+}
diff --git a/dx/tests/089-dex-define-object/String.java b/dx/tests/089-dex-define-object/String.java
new file mode 100644
index 0000000..26e7370
--- /dev/null
+++ b/dx/tests/089-dex-define-object/String.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.lang;
+
+public final class String {
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/089-dex-define-object/expected.txt b/dx/tests/089-dex-define-object/expected.txt
new file mode 100644
index 0000000..a1db6a4
--- /dev/null
+++ b/dx/tests/089-dex-define-object/expected.txt
@@ -0,0 +1 @@
+Good!
diff --git a/dx/tests/089-dex-define-object/info.txt b/dx/tests/089-dex-define-object/info.txt
new file mode 100644
index 0000000..e035834
--- /dev/null
+++ b/dx/tests/089-dex-define-object/info.txt
@@ -0,0 +1,4 @@
+This tests that a stripped down definition of the class Object can in
+fact be converted to a dex file. This test ensures that the conversion
+runs without failure, though the contents of the converted file are
+not checked for correctness.
diff --git a/dx/tests/089-dex-define-object/run b/dx/tests/089-dex-define-object/run
new file mode 100644
index 0000000..e53e147
--- /dev/null
+++ b/dx/tests/089-dex-define-object/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --core-library --output=blort.dex */*/*.class
+if [ -r blort.dex ]; then
+    echo Good!
+fi
diff --git a/dx/tests/090-dex-unify-arrays/Blort.java b/dx/tests/090-dex-unify-arrays/Blort.java
new file mode 100644
index 0000000..507153e
--- /dev/null
+++ b/dx/tests/090-dex-unify-arrays/Blort.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    /*
+     * Note: The use of the casts after the "?" in the following are
+     * to avoid a bug in some (source code level) compilers.
+     */
+
+    static public Object test1(boolean b) {
+        return (b ? new String[1] : new Integer[1])[0];
+    }
+
+    static public int test2(boolean b) {
+        Object o = b ? (Object) new int[1] : new float[1];
+        return o.hashCode();
+    }
+
+    static public int test3(boolean b) {
+        Object o = b ? (Object) new char[1] : new double[1];
+        return o.hashCode();
+    }
+
+    static public int test4(boolean b) {
+        Object o = b ? (Object) new long[1] : new boolean[1];
+        return o.hashCode();
+    }
+
+    static public int test5(boolean b) {
+        Object o = b ? (Object) new short[1] : new Object[1];
+        return o.hashCode();
+    }
+
+    static public int test6(boolean b) {
+        Object o = b ? (Object) new byte[1] : new boolean[1];
+        return o.hashCode();
+    }
+
+    static public Object test7(boolean b) {
+        return (b ? new String[1] : new int[1][])[0];
+    }
+
+    static public Object[] test8(boolean b) {
+        return (b ? new String[1][] : new int[1][][])[0];
+    }
+}
diff --git a/dx/tests/090-dex-unify-arrays/expected.txt b/dx/tests/090-dex-unify-arrays/expected.txt
new file mode 100644
index 0000000..7a4125f
--- /dev/null
+++ b/dx/tests/090-dex-unify-arrays/expected.txt
@@ -0,0 +1,122 @@
+Blort.test1:(Z)Ljava/lang/Object;:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v1, v0
+  0002: if-eqz v1, 000c // +000a
+  0004: const/4 v1, #int 1 // #1
+  0005: new-array v1, v1, java.lang.String[]
+  0007: const/4 v2, #int 0 // #0
+  0008: aget-object v1, v1, v2
+  000a: move-object v0, v1
+  000b: return-object v0
+  000c: const/4 v1, #int 1 // #1
+  000d: new-array v1, v1, java.lang.Integer[]
+  000f: goto 0007 // -0008
+Blort.test2:(Z)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: if-eqz v2, 000f // +000d
+  0004: const/4 v2, #int 1 // #1
+  0005: new-array v2, v2, int[]
+  0007: move-object v1, v2
+  0008: move-object v2, v1
+  0009: invoke-virtual {v2}, java.lang.Object.hashCode:()I
+  000c: move-result v2
+  000d: move v0, v2
+  000e: return v0
+  000f: const/4 v2, #int 1 // #1
+  0010: new-array v2, v2, float[]
+  0012: goto 0007 // -000b
+Blort.test3:(Z)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: if-eqz v2, 000f // +000d
+  0004: const/4 v2, #int 1 // #1
+  0005: new-array v2, v2, char[]
+  0007: move-object v1, v2
+  0008: move-object v2, v1
+  0009: invoke-virtual {v2}, java.lang.Object.hashCode:()I
+  000c: move-result v2
+  000d: move v0, v2
+  000e: return v0
+  000f: const/4 v2, #int 1 // #1
+  0010: new-array v2, v2, double[]
+  0012: goto 0007 // -000b
+Blort.test4:(Z)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: if-eqz v2, 000f // +000d
+  0004: const/4 v2, #int 1 // #1
+  0005: new-array v2, v2, long[]
+  0007: move-object v1, v2
+  0008: move-object v2, v1
+  0009: invoke-virtual {v2}, java.lang.Object.hashCode:()I
+  000c: move-result v2
+  000d: move v0, v2
+  000e: return v0
+  000f: const/4 v2, #int 1 // #1
+  0010: new-array v2, v2, boolean[]
+  0012: goto 0007 // -000b
+Blort.test5:(Z)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: if-eqz v2, 000f // +000d
+  0004: const/4 v2, #int 1 // #1
+  0005: new-array v2, v2, short[]
+  0007: move-object v1, v2
+  0008: move-object v2, v1
+  0009: invoke-virtual {v2}, java.lang.Object.hashCode:()I
+  000c: move-result v2
+  000d: move v0, v2
+  000e: return v0
+  000f: const/4 v2, #int 1 // #1
+  0010: new-array v2, v2, java.lang.Object[]
+  0012: goto 0007 // -000b
+Blort.test6:(Z)I:
+regs: 0004; ins: 0001; outs: 0001
+  0000: move v0, v3
+  0001: move v2, v0
+  0002: if-eqz v2, 000f // +000d
+  0004: const/4 v2, #int 1 // #1
+  0005: new-array v2, v2, byte[]
+  0007: move-object v1, v2
+  0008: move-object v2, v1
+  0009: invoke-virtual {v2}, java.lang.Object.hashCode:()I
+  000c: move-result v2
+  000d: move v0, v2
+  000e: return v0
+  000f: const/4 v2, #int 1 // #1
+  0010: new-array v2, v2, boolean[]
+  0012: goto 0007 // -000b
+Blort.test7:(Z)Ljava/lang/Object;:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v1, v0
+  0002: if-eqz v1, 000c // +000a
+  0004: const/4 v1, #int 1 // #1
+  0005: new-array v1, v1, java.lang.String[]
+  0007: const/4 v2, #int 0 // #0
+  0008: aget-object v1, v1, v2
+  000a: move-object v0, v1
+  000b: return-object v0
+  000c: const/4 v1, #int 1 // #1
+  000d: new-array v1, v1, int[][]
+  000f: goto 0007 // -0008
+Blort.test8:(Z)[Ljava/lang/Object;:
+regs: 0004; ins: 0001; outs: 0000
+  0000: move v0, v3
+  0001: move v1, v0
+  0002: if-eqz v1, 000c // +000a
+  0004: const/4 v1, #int 1 // #1
+  0005: new-array v1, v1, java.lang.String[][]
+  0007: const/4 v2, #int 0 // #0
+  0008: aget-object v1, v1, v2
+  000a: move-object v0, v1
+  000b: return-object v0
+  000c: const/4 v1, #int 1 // #1
+  000d: new-array v1, v1, int[][][]
+  000f: goto 0007 // -0008
diff --git a/dx/tests/090-dex-unify-arrays/info.txt b/dx/tests/090-dex-unify-arrays/info.txt
new file mode 100644
index 0000000..018fd25
--- /dev/null
+++ b/dx/tests/090-dex-unify-arrays/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+array type unification works properly.
+
+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/090-dex-unify-arrays/run b/dx/tests/090-dex-unify-arrays/run
new file mode 100644
index 0000000..47b709c
--- /dev/null
+++ b/dx/tests/090-dex-unify-arrays/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/091-ssa-const-collector/Blort.java b/dx/tests/091-ssa-const-collector/Blort.java
new file mode 100644
index 0000000..ea99a0d
--- /dev/null
+++ b/dx/tests/091-ssa-const-collector/Blort.java
@@ -0,0 +1,64 @@
+
+class Blort {
+    /** Class constructors for enums use a lot of const's */
+    enum Foo {
+        ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT
+    }
+
+    /** all uses of 10 should be combined except the local assignment */
+    void testNumeric() {
+        int foo = 10;
+
+        for (int i = 0; i < 10; i++){
+            foo += i * 10;
+        }
+
+        for (int i = 0; i < 10; i++){
+            foo += i + 10;
+        }
+    }
+
+    void testStrings() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("foo");
+        sb.append("foo");
+        sb.append("foo");
+        sb.append("foo");
+        sb.append("foo");
+        sb.append("foo");
+    }
+
+    void testCaughtStrings() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("foo");
+        sb.append("foo");
+        sb.append("foo");
+        try {
+            sb.append("foo");
+            sb.append("foo");
+            sb.append("foo");
+        } catch (Throwable tr) {
+            System.out.println("foo");
+        }
+    }
+
+    /** local variables cannot be intermingled */
+    void testLocalVars() {
+        int i = 10;
+        int j = 10;
+        int k = 10;
+        int a = 10;
+        int b = 10;
+        int c = 10;
+
+        i *= 10;
+    }
+
+    void testNull(Object a) {
+        a.equals(null);
+        a.equals(null);
+
+    }
+}
diff --git a/dx/tests/091-ssa-const-collector/expected.txt b/dx/tests/091-ssa-const-collector/expected.txt
new file mode 100644
index 0000000..764c7ee
--- /dev/null
+++ b/dx/tests/091-ssa-const-collector/expected.txt
@@ -0,0 +1,454 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  Blort.java:2@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <any
+  >}(java.lang.Object.<init>:()V catch) . <- v0:NffffLBlort;
+  next 000b
+block 000a
+  pred 000c
+  Blort.java:2@0000: move-param-object(0) v0:"this"NffffLBlort; <- .
+  Blort.java:2@0000: goto . <- .
+  next 0000
+block 000b
+  pred 0000
+  Blort.java:4@0004: return-void . <- .
+  returns
+block 000c
+  @????: goto . <- .
+  next 000a
+
+method testNumeric ()V
+first 005e
+block 0000
+  pred 005c
+  Blort.java:10@0000: const-int(10) v0:I=10 <- .
+  @????: mark-local-int . <- v0:"foo"I
+  Blort.java:12@0003: const-int(0) v1:I=0 <- .
+  @????: mark-local-int . <- v1:"i"I
+  Blort.java:12@0004: goto . <- .
+  next 0005
+block 0005
+  pred 0000
+  pred 000b
+  Blort.java:12@0008: if-ge-int . <- v1:I v3:I=10
+  next 000b *
+  next 0018
+block 000b
+  pred 0005
+  Blort.java:13@000f: mul-const-int(10) v2:I <- v1:I
+  Blort.java:13@0010: add-int v0:I <- v0:I v2:I
+  @????: mark-local-int . <- v0:"foo"I
+  Blort.java:12@0012: add-const-int(1) v1:"i"I <- v1:I
+  Blort.java:12@0015: goto . <- .
+  next 0005
+block 0018
+  pred 0005
+  Blort.java:16@0018: const-int(0) v1:I=0 <- .
+  @????: mark-local-int . <- v1:"i"I
+  Blort.java:16@0019: goto . <- .
+  next 001a
+block 001a
+  pred 0018
+  pred 0020
+  Blort.java:16@001d: if-ge-int . <- v1:I v3:I=10
+  next 0020 *
+  next 005d
+block 0020
+  pred 001a
+  Blort.java:17@0024: add-const-int(10) v2:I <- v1:I
+  Blort.java:17@0025: add-int v0:I <- v0:I v2:I
+  @????: mark-local-int . <- v0:"foo"I
+  Blort.java:16@0027: add-const-int(1) v1:"i"I <- v1:I
+  Blort.java:16@002a: goto . <- .
+  next 001a
+block 005c
+  pred 005e
+  Blort.java:10@0000: move-param-object(0) v4:"this"LBlort; <- .
+  Blort.java:10@0000: goto . <- .
+  next 0000
+block 005d
+  pred 001a
+  Blort.java:19@002d: return-void . <- .
+  returns
+block 005e
+  @????: const-int(10) v3:I=10 <- .
+  @????: goto . <- .
+  next 005c
+
+method testStrings ()V
+first 0078
+block 0000
+  pred 0064
+  Blort.java:22@0000: new-instance(java.lang.StringBuilder catch) . <- .
+  next 006b
+block 0003
+  pred 006b
+  Blort.java:22@0004: Rop{invoke-direct . <- Ljava/lang/StringBuilder; call thr
+  ows <any>}(java.lang.StringBuilder.<init>:()V catch) . <- v0:N0000Ljava/lang/
+  StringBuilder;
+  next 0007
+block 0007
+  pred 0003
+  @????: mark-local-object . <- v0:"sb"Ljava/lang/StringBuilder;
+  Blort.java:24@0009: const-object("foo" catch) . <- .
+  next 006c
+block 000b
+  pred 006c
+  Blort.java:24@000b: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v1:Lj
+  ava/lang/String;="foo"
+  next 000e
+block 000e
+  pred 000b
+  Blort.java:25@0010: const-object("foo" catch) . <- .
+  next 006e
+block 0012
+  pred 006e
+  Blort.java:25@0012: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v1:Lj
+  ava/lang/String;="foo"
+  next 0015
+block 0015
+  pred 0012
+  Blort.java:26@0017: const-object("foo" catch) . <- .
+  next 0070
+block 0019
+  pred 0070
+  Blort.java:26@0019: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v1:Lj
+  ava/lang/String;="foo"
+  next 001c
+block 001c
+  pred 0019
+  Blort.java:27@001e: const-object("foo" catch) . <- .
+  next 0072
+block 0020
+  pred 0072
+  Blort.java:27@0020: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v1:Lj
+  ava/lang/String;="foo"
+  next 0023
+block 0023
+  pred 0020
+  Blort.java:28@0025: const-object("foo" catch) . <- .
+  next 0074
+block 0027
+  pred 0074
+  Blort.java:28@0027: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v1:Lj
+  ava/lang/String;="foo"
+  next 002a
+block 002a
+  pred 0027
+  Blort.java:29@002c: const-object("foo" catch) . <- .
+  next 0076
+block 002e
+  pred 0076
+  Blort.java:29@002e: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v1:Lj
+  ava/lang/String;="foo"
+  next 0065
+block 0064
+  pred 0078
+  Blort.java:22@0000: move-param-object(0) v2:"this"LBlort; <- .
+  Blort.java:22@0000: goto . <- .
+  next 0000
+block 0065
+  pred 002e
+  Blort.java:30@0032: return-void . <- .
+  returns
+block 006b
+  pred 0000
+  Blort.java:22@0000: Rop{move-result-pseudo N0000Ljava/lang/StringBuilder; <- 
+  . flows} v0:N0000Ljava/lang/StringBuilder; <- .
+  Blort.java:22@0000: goto . <- .
+  next 0003
+block 006c
+  pred 0007
+  Blort.java:24@0009: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:24@0009: goto . <- .
+  next 000b
+block 006e
+  pred 000e
+  Blort.java:25@0010: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:25@0010: goto . <- .
+  next 0012
+block 0070
+  pred 0015
+  Blort.java:26@0017: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:26@0017: goto . <- .
+  next 0019
+block 0072
+  pred 001c
+  Blort.java:27@001e: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:27@001e: goto . <- .
+  next 0020
+block 0074
+  pred 0023
+  Blort.java:28@0025: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:28@0025: goto . <- .
+  next 0027
+block 0076
+  pred 002a
+  Blort.java:29@002c: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:29@002c: goto . <- .
+  next 002e
+block 0078
+  @????: goto . <- .
+  next 0064
+
+method testCaughtStrings ()V
+first 0094
+block 0000
+  pred 007e
+  Blort.java:33@0000: new-instance(java.lang.StringBuilder catch) . <- .
+  next 0085
+block 0003
+  pred 0085
+  Blort.java:33@0004: Rop{invoke-direct . <- Ljava/lang/StringBuilder; call thr
+  ows <any>}(java.lang.StringBuilder.<init>:()V catch) . <- v0:N0000Ljava/lang/
+  StringBuilder;
+  next 0007
+block 0007
+  pred 0003
+  @????: mark-local-object . <- v0:"sb"Ljava/lang/StringBuilder;
+  Blort.java:35@0009: const-object("foo" catch) . <- .
+  next 0086
+block 000b
+  pred 0086
+  Blort.java:35@000b: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v2:Lj
+  ava/lang/String;="foo"
+  next 000e
+block 000e
+  pred 000b
+  Blort.java:36@0010: const-object("foo" catch) . <- .
+  next 0088
+block 0012
+  pred 0088
+  Blort.java:36@0012: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v2:Lj
+  ava/lang/String;="foo"
+  next 0015
+block 0015
+  pred 0012
+  Blort.java:37@0017: const-object("foo" catch) . <- .
+  next 008a
+block 0019
+  pred 008a
+  Blort.java:37@0019: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch) . <- v0:Ljava/lang/StringBuilder; v2:Lj
+  ava/lang/String;="foo"
+  next 001d
+block 001d
+  pred 0019
+  Blort.java:39@001e: const-object("foo" catch java.lang.Throwable) . <- .
+  next 0095
+  next 008c *
+block 0020
+  pred 008c
+  Blort.java:39@0020: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch java.lang.Throwable) . <- v0:Ljava/lang/
+  StringBuilder; v2:Ljava/lang/String;="foo"
+  next 0095
+  next 0023 *
+block 0023
+  pred 0020
+  Blort.java:40@0025: const-object("foo" catch java.lang.Throwable) . <- .
+  next 0095
+  next 008e *
+block 0027
+  pred 008e
+  Blort.java:40@0027: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch java.lang.Throwable) . <- v0:Ljava/lang/
+  StringBuilder; v2:Ljava/lang/String;="foo"
+  next 0095
+  next 002a *
+block 002a
+  pred 0027
+  Blort.java:41@002c: const-object("foo" catch java.lang.Throwable) . <- .
+  next 0095
+  next 0090 *
+block 002e
+  pred 0090
+  Blort.java:41@002e: Rop{invoke-virtual . <- Ljava/lang/StringBuilder; Ljava/l
+  ang/String; call throws <any>}(java.lang.StringBuilder.append:(Ljava/lang/Str
+  ing;)Ljava/lang/StringBuilder; catch java.lang.Throwable) . <- v0:Ljava/lang/
+  StringBuilder; v2:Ljava/lang/String;="foo"
+  next 0095
+  next 007f *
+block 0035
+  pred 0095
+  @????: mark-local-object . <- v1:"tr"Ljava/lang/Throwable;
+  Blort.java:43@0036: get-static-object(java.lang.System.out:Ljava/io/PrintStre
+  am; catch) . <- .
+  next 0092
+block 0039
+  pred 0092
+  Blort.java:43@0039: const-object("foo" catch) . <- .
+  next 0093
+block 003b
+  pred 0093
+  Blort.java:43@003b: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/
+  String; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V 
+  catch) . <- v2:Ljava/io/PrintStream; v3:Ljava/lang/String;="foo"
+  next 007f
+block 007e
+  pred 0094
+  Blort.java:33@0000: move-param-object(0) v4:"this"LBlort; <- .
+  Blort.java:33@0000: goto . <- .
+  next 0000
+block 007f
+  pred 002e
+  pred 003b
+  Blort.java:45@003e: return-void . <- .
+  returns
+block 0085
+  pred 0000
+  Blort.java:33@0000: Rop{move-result-pseudo N0000Ljava/lang/StringBuilder; <- 
+  . flows} v0:N0000Ljava/lang/StringBuilder; <- .
+  Blort.java:33@0000: goto . <- .
+  next 0003
+block 0086
+  pred 0007
+  Blort.java:35@0009: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v2:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:35@0009: goto . <- .
+  next 000b
+block 0088
+  pred 000e
+  Blort.java:36@0010: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v2:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:36@0010: goto . <- .
+  next 0012
+block 008a
+  pred 0015
+  Blort.java:37@0017: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v2:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:37@0017: goto . <- .
+  next 0019
+block 008c
+  pred 001d
+  Blort.java:39@001e: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v2:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:39@001e: goto . <- .
+  next 0020
+block 008e
+  pred 0023
+  Blort.java:40@0025: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v2:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:40@0025: goto . <- .
+  next 0027
+block 0090
+  pred 002a
+  Blort.java:41@002c: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v2:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:41@002c: goto . <- .
+  next 002e
+block 0092
+  pred 0035
+  Blort.java:43@0036: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} 
+  v2:Ljava/io/PrintStream; <- .
+  Blort.java:43@0036: goto . <- .
+  next 0039
+block 0093
+  pred 0039
+  Blort.java:43@0039: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v3:
+  Ljava/lang/String;="foo" <- .
+  Blort.java:43@0039: goto . <- .
+  next 003b
+block 0094
+  @????: goto . <- .
+  next 007e
+block 0095
+  pred 001d
+  pred 0020
+  pred 0023
+  pred 0027
+  pred 002a
+  pred 002e
+  Blort.java:42@0035: Rop{move-exception Ljava/lang/Throwable; <- . flows} v1:L
+  java/lang/Throwable; <- .
+  @????: goto . <- .
+  next 0035
+
+method testLocalVars ()V
+first 0004
+block 0000
+  pred 0002
+  Blort.java:49@0000: const-int(10) v3:I=10 <- .
+  @????: mark-local-int . <- v3:"i"I
+  Blort.java:50@0003: const-int(10) v4:I=10 <- .
+  @????: mark-local-int . <- v4:"j"I
+  Blort.java:51@0006: const-int(10) v5:I=10 <- .
+  @????: mark-local-int . <- v5:"k"I
+  Blort.java:52@0009: const-int(10) v0:I=10 <- .
+  @????: mark-local-int . <- v0:"a"I
+  Blort.java:53@000d: const-int(10) v1:I=10 <- .
+  @????: mark-local-int . <- v1:"b"I
+  Blort.java:54@0011: const-int(10) v2:I=10 <- .
+  @????: mark-local-int . <- v2:"c"I
+  Blort.java:56@0018: mul-const-int(10) v3:I=100 <- v3:I
+  @????: mark-local-int . <- v3:"i"I=100
+  Blort.java:57@001a: goto . <- .
+  next 0003
+block 0002
+  pred 0004
+  Blort.java:49@0000: move-param-object(0) v6:"this"LBlort; <- .
+  Blort.java:49@0000: goto . <- .
+  next 0000
+block 0003
+  pred 0000
+  Blort.java:57@001a: return-void . <- .
+  returns
+block 0004
+  @????: goto . <- .
+  next 0002
+
+method testNull (Ljava/lang/Object;)V
+first 0021
+block 0000
+  pred 0018
+  Blort.java:60@0002: Rop{invoke-virtual . <- Ljava/lang/Object; Ljava/lang/Obj
+  ect; call throws <any>}(java.lang.Object.equals:(Ljava/lang/Object;)Z catch) 
+  . <- v2:Ljava/lang/Object; v0:<null>=null
+  next 0005
+block 0005
+  pred 0000
+  Blort.java:61@0008: Rop{invoke-virtual . <- Ljava/lang/Object; Ljava/lang/Obj
+  ect; call throws <any>}(java.lang.Object.equals:(Ljava/lang/Object;)Z catch) 
+  . <- v2:Ljava/lang/Object; v0:<null>=null
+  next 0019
+block 0018
+  pred 0021
+  Blort.java:60@0000: move-param-object(0) v1:"this"LBlort; <- .
+  Blort.java:60@0000: move-param-object(1) v2:"a"Ljava/lang/Object; <- .
+  Blort.java:60@0000: goto . <- .
+  next 0000
+block 0019
+  pred 0005
+  Blort.java:63@000c: return-void . <- .
+  returns
+block 0021
+  @????: const-object-nothrow(null) v0:<null>=null <- .
+  @????: goto . <- .
+  next 0018
diff --git a/dx/tests/091-ssa-const-collector/info.txt b/dx/tests/091-ssa-const-collector/info.txt
new file mode 100644
index 0000000..020d3b3
--- /dev/null
+++ b/dx/tests/091-ssa-const-collector/info.txt
@@ -0,0 +1,5 @@
+This test case tests the "const collector" optimization step.
+
+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/091-ssa-const-collector/run b/dx/tests/091-ssa-const-collector/run
new file mode 100644
index 0000000..aa37784
--- /dev/null
+++ b/dx/tests/091-ssa-const-collector/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --dump --optimize --rop-blocks Blort.class
diff --git a/dx/tests/092-ssa-cfg-edge-cases/Blort.java b/dx/tests/092-ssa-cfg-edge-cases/Blort.java
new file mode 100644
index 0000000..8b3602f
--- /dev/null
+++ b/dx/tests/092-ssa-cfg-edge-cases/Blort.java
@@ -0,0 +1,20 @@
+
+class Blort {
+
+    void testMultipleIdenticalSuccessors(int foo) {
+        switch(foo) {
+            case 1:
+            case 2:
+            case 3:
+                System.out.println("foo");
+            break;
+        }
+    }
+
+    void testNoPrimarySuccessor() {
+        try {
+            throw new RuntimeException();
+        } catch (RuntimeException ex){
+        }
+    }
+}
diff --git a/dx/tests/092-ssa-cfg-edge-cases/expected.txt b/dx/tests/092-ssa-cfg-edge-cases/expected.txt
new file mode 100644
index 0000000..e3d660a
--- /dev/null
+++ b/dx/tests/092-ssa-cfg-edge-cases/expected.txt
@@ -0,0 +1,120 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  Blort.java:2@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <any
+  >}(java.lang.Object.<init>:()V catch) . <- v0:NffffLBlort;
+  next 000b
+block 000a
+  pred 000c
+  Blort.java:2@0000: move-param-object(0) v0:"this"NffffLBlort; <- .
+  Blort.java:2@0000: goto . <- .
+  next 0000
+block 000b
+  pred 0000
+  Blort.java:2@0004: return-void . <- .
+  returns
+block 000c
+  @????: goto . <- .
+  next 000a
+
+method testMultipleIdenticalSuccessors (I)V
+first 0053
+block 0000
+  pred 004a
+  Blort.java:5@0001: switch({1, 2, 3}) . <- v3:I
+  next 001c
+  next 001c
+  next 001c
+  next 004b *
+block 001c
+  pred 0000
+  pred 0000
+  pred 0000
+  Blort.java:9@001c: get-static-object(java.lang.System.out:Ljava/io/PrintStrea
+  m; catch) . <- .
+  next 0051
+block 001f
+  pred 0051
+  Blort.java:9@001f: const-object("foo" catch) . <- .
+  next 0052
+block 0021
+  pred 0052
+  Blort.java:9@0021: Rop{invoke-virtual . <- Ljava/io/PrintStream; Ljava/lang/S
+  tring; call throws <any>}(java.io.PrintStream.println:(Ljava/lang/String;)V c
+  atch) . <- v0:Ljava/io/PrintStream; v1:Ljava/lang/String;="foo"
+  next 004b
+block 004a
+  pred 0053
+  Blort.java:5@0000: move-param-object(0) v2:"this"LBlort; <- .
+  Blort.java:5@0000: move-param-int(1) v3:"foo"I <- .
+  Blort.java:5@0000: goto . <- .
+  next 0000
+block 004b
+  pred 0000
+  pred 0021
+  Blort.java:12@0024: return-void . <- .
+  returns
+block 0051
+  pred 001c
+  Blort.java:9@001c: Rop{move-result-pseudo Ljava/io/PrintStream; <- . flows} v
+  0:Ljava/io/PrintStream; <- .
+  Blort.java:9@001c: goto . <- .
+  next 001f
+block 0052
+  pred 001f
+  Blort.java:9@001f: Rop{move-result-pseudo Ljava/lang/String; <- . flows} v1:L
+  java/lang/String;="foo" <- .
+  Blort.java:9@001f: goto . <- .
+  next 0021
+block 0053
+  @????: goto . <- .
+  next 004a
+
+method testNoPrimarySuccessor ()V
+first 001a
+block 0000
+  pred 0012
+  Blort.java:16@0000: new-instance(java.lang.RuntimeException catch java.lang.R
+  untimeException) . <- .
+  next 001b
+  next 0019 *
+block 0003
+  pred 0019
+  Blort.java:16@0004: Rop{invoke-direct . <- Ljava/lang/RuntimeException; call 
+  throws <any>}(java.lang.RuntimeException.<init>:()V catch java.lang.RuntimeEx
+  ception) . <- v0:N0000Ljava/lang/RuntimeException;
+  next 001b
+  next 0007 *
+block 0007
+  pred 0003
+  Blort.java:16@0007: throw(catch java.lang.RuntimeException) . <- v0:Ljava/lan
+  g/RuntimeException;
+  next 001b
+block 0012
+  pred 001a
+  Blort.java:16@0000: move-param-object(0) v1:"this"LBlort; <- .
+  Blort.java:16@0000: goto . <- .
+  next 0000
+block 0013
+  pred 001b
+  Blort.java:19@0009: return-void . <- .
+  returns
+block 0019
+  pred 0000
+  Blort.java:16@0000: Rop{move-result-pseudo N0000Ljava/lang/RuntimeException; 
+  <- . flows} v0:N0000Ljava/lang/RuntimeException; <- .
+  Blort.java:16@0000: goto . <- .
+  next 0003
+block 001a
+  @????: goto . <- .
+  next 0012
+block 001b
+  pred 0000
+  pred 0003
+  pred 0007
+  Blort.java:17@0008: Rop{move-exception Ljava/lang/RuntimeException; <- . flow
+  s} v0:Ljava/lang/RuntimeException; <- .
+  @????: goto . <- .
+  next 0013
diff --git a/dx/tests/092-ssa-cfg-edge-cases/info.txt b/dx/tests/092-ssa-cfg-edge-cases/info.txt
new file mode 100644
index 0000000..7c56302
--- /dev/null
+++ b/dx/tests/092-ssa-cfg-edge-cases/info.txt
@@ -0,0 +1,5 @@
+This test case runs a few odd control flow graphs through the optimizer.
+
+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/092-ssa-cfg-edge-cases/run b/dx/tests/092-ssa-cfg-edge-cases/run
new file mode 100644
index 0000000..090a4d7
--- /dev/null
+++ b/dx/tests/092-ssa-cfg-edge-cases/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --dump --optimize --rop-blocks Blort.class
diff --git a/dx/tests/093-ssa-invoke-range/Blort.java b/dx/tests/093-ssa-invoke-range/Blort.java
new file mode 100644
index 0000000..f2bb66c
--- /dev/null
+++ b/dx/tests/093-ssa-invoke-range/Blort.java
@@ -0,0 +1,69 @@
+
+class Blort {
+
+    static void methodThatNeedsInvokeRange
+        (int a, int b, int c, int d, int e, int f) {
+    }
+
+    void testNoLocals() {
+        methodThatNeedsInvokeRange(5, 0, 5, 0, 5, 0);
+    }
+
+    void testMixedLocals() {
+        int src = 6;
+        int dest = 7;
+
+        methodThatNeedsInvokeRange(src, 0, dest, 1, 5, 0);
+        methodThatNeedsInvokeRange(src, 0, dest, 1, 5, 0);
+    }
+
+    // here the current algorithm partial-overlapping will stumble a bit
+    // The register containing "zero" will be marked as "reserved for locals"
+    // Then the subsequent arraycopy will need a whole new set of 5 registers
+    void testMixedWorseCase() {
+        int src = 6;
+        int dest = 7;
+        int zero = 0;
+
+        methodThatNeedsInvokeRange(src, zero, dest, 1, 5, 0);
+        methodThatNeedsInvokeRange(src, 0, dest, 1, 5, 0);
+    }
+
+    void testAllParams(int a, int b, int c, int d, int e, int f) {
+        methodThatNeedsInvokeRange(a, b, c, d, e, f);
+    }
+
+    // this could try to make use of param positions, but doesn't
+    static void testTailParams(int destPos, int length) {
+        int src = 6;
+        int dest = 7;
+
+        methodThatNeedsInvokeRange(src, 0, dest, 0, destPos, length);
+    }
+
+
+    // This presently requires a whole N new registers
+    void testFlip() {
+        int src = 6;
+        int dest = 7;
+
+        methodThatNeedsInvokeRange(src, 0, dest, 1, 5, 0);
+        methodThatNeedsInvokeRange(dest, 0, src, 1, 5, 0);
+    }
+
+    // ensure that an attempt to combine registers for a local
+    // with a differing category doesn't mess us up.
+    long testMixedCategory(boolean foo) {
+        if (foo) {
+            int offset = 1;
+            int src = 6;
+            int dest = 7;
+
+            methodThatNeedsInvokeRange(src, 0, dest, offset, 5, 0);
+            return offset;
+        } else {
+            long offset = System.currentTimeMillis();;
+            return offset;
+        }
+    }
+}
diff --git a/dx/tests/093-ssa-invoke-range/expected.txt b/dx/tests/093-ssa-invoke-range/expected.txt
new file mode 100644
index 0000000..0506c4d
--- /dev/null
+++ b/dx/tests/093-ssa-invoke-range/expected.txt
@@ -0,0 +1,300 @@
+reading Blort.class...
+method <init> ()V
+first 000c
+block 0000
+  pred 000a
+  Blort.java:2@0001: Rop{invoke-direct . <- Ljava/lang/Object; call throws <any
+  >}(java.lang.Object.<init>:()V catch) . <- v0:NffffLBlort;
+  next 000b
+block 000a
+  pred 000c
+  Blort.java:2@0000: move-param-object(0) v0:"this"NffffLBlort; <- .
+  Blort.java:2@0000: goto . <- .
+  next 0000
+block 000b
+  pred 0000
+  Blort.java:2@0004: return-void . <- .
+  returns
+block 000c
+  @????: goto . <- .
+  next 000a
+
+method methodThatNeedsInvokeRange (IIIIII)V
+first 0004
+block 0002
+  pred 0004
+  Blort.java:6@0000: move-param-int(0) v0:"a"I <- .
+  Blort.java:6@0000: move-param-int(1) v1:"b"I <- .
+  Blort.java:6@0000: move-param-int(2) v2:"c"I <- .
+  Blort.java:6@0000: move-param-int(3) v3:"d"I <- .
+  Blort.java:6@0000: move-param-int(4) v4:"e"I <- .
+  Blort.java:6@0000: move-param-int(5) v5:"f"I <- .
+  Blort.java:6@0000: goto . <- .
+  next 0003
+block 0003
+  pred 0002
+  Blort.java:6@0000: return-void . <- .
+  returns
+block 0004
+  @????: goto . <- .
+  next 0002
+
+method testNoLocals ()V
+first 0016
+block 0000
+  pred 0014
+  @????: move-int v2:I=5 <- v0:I=5
+  @????: move-int v3:I=0 <- v1:I=0
+  @????: move-int v4:I=5 <- v0:I=5
+  @????: move-int v5:I=0 <- v1:I=0
+  Blort.java:9@0006: Rop{invoke-static . <- I I I I I I call throws <any>}(Blor
+  t.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I=5 v1:I=0 v2:I=5 v3:I=
+  0 v4:I=5 v5:I=0
+  next 0015
+block 0014
+  pred 0016
+  Blort.java:9@0000: move-param-object(0) v6:"this"LBlort; <- .
+  Blort.java:9@0000: goto . <- .
+  next 0000
+block 0015
+  pred 0000
+  Blort.java:10@0009: return-void . <- .
+  returns
+block 0016
+  @????: const-int(5) v0:I=5 <- .
+  @????: const-int(0) v1:I=0 <- .
+  @????: goto . <- .
+  next 0014
+
+method testMixedLocals ()V
+first 0034
+block 0000
+  pred 0032
+  Blort.java:13@0000: const-int(6) v0:I=6 <- .
+  @????: mark-local-int . <- v0:"src"I
+  Blort.java:14@0003: const-int(7) v2:I=7 <- .
+  @????: mark-local-int . <- v2:"dest"I
+  @????: move-int v5:I=0 <- v1:I=0
+  Blort.java:16@000c: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I v1:I=0 v2:I v3:I=1 v
+  4:I=5 v5:I=0
+  next 000f
+block 000f
+  pred 0000
+  @????: move-int v5:I=0 <- v1:I=0
+  Blort.java:17@0015: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I v1:I=0 v2:I v3:I=1 v
+  4:I=5 v5:I=0
+  next 0033
+block 0032
+  pred 0034
+  Blort.java:13@0000: move-param-object(0) v6:"this"LBlort; <- .
+  Blort.java:13@0000: goto . <- .
+  next 0000
+block 0033
+  pred 000f
+  Blort.java:18@0018: return-void . <- .
+  returns
+block 0034
+  @????: const-int(5) v4:I=5 <- .
+  @????: const-int(1) v3:I=1 <- .
+  @????: const-int(0) v1:I=0 <- .
+  @????: goto . <- .
+  next 0032
+
+method testMixedWorseCase ()V
+first 0038
+block 0000
+  pred 0036
+  Blort.java:24@0000: const-int(6) v0:I=6 <- .
+  @????: mark-local-int . <- v0:"src"I
+  Blort.java:25@0003: const-int(7) v2:I=7 <- .
+  @????: mark-local-int . <- v2:"dest"I
+  Blort.java:26@0006: const-int(0) v1:I=0 <- .
+  @????: mark-local-int . <- v1:"zero"I
+  Blort.java:28@000e: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I v1:I v2:I v3:I=1 v4:
+  I=5 v5:I=0
+  next 0011
+block 0011
+  pred 0000
+  @????: move-int v6:I <- v0:I
+  @????: move-int v7:I=0 <- v5:I=0
+  @????: move-int v8:I <- v2:I
+  @????: move-int v9:I=1 <- v3:I=1
+  @????: move-int v10:I=5 <- v4:I=5
+  @????: move-int v11:I=0 <- v5:I=0
+  Blort.java:29@0017: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v6:I v7:I=0 v8:I v9:I=1 v
+  10:I=5 v11:I=0
+  next 0037
+block 0036
+  pred 0038
+  Blort.java:24@0000: move-param-object(0) v12:"this"LBlort; <- .
+  Blort.java:24@0000: goto . <- .
+  next 0000
+block 0037
+  pred 0011
+  Blort.java:30@001a: return-void . <- .
+  returns
+block 0038
+  @????: const-int(5) v4:I=5 <- .
+  @????: const-int(1) v3:I=1 <- .
+  @????: const-int(0) v5:I=0 <- .
+  @????: goto . <- .
+  next 0036
+
+method testAllParams (IIIIII)V
+first 001c
+block 0000
+  pred 001a
+  Blort.java:33@0009: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v1:I v2:I v3:I v4:I v5:I 
+  v6:I
+  next 001b
+block 001a
+  pred 001c
+  Blort.java:33@0000: move-param-object(0) v0:"this"LBlort; <- .
+  Blort.java:33@0000: move-param-int(1) v1:"a"I <- .
+  Blort.java:33@0000: move-param-int(2) v2:"b"I <- .
+  Blort.java:33@0000: move-param-int(3) v3:"c"I <- .
+  Blort.java:33@0000: move-param-int(4) v4:"d"I <- .
+  Blort.java:33@0000: move-param-int(5) v5:"e"I <- .
+  Blort.java:33@0000: move-param-int(6) v6:"f"I <- .
+  Blort.java:33@0000: goto . <- .
+  next 0000
+block 001b
+  pred 0000
+  Blort.java:34@000c: return-void . <- .
+  returns
+block 001c
+  @????: goto . <- .
+  next 001a
+
+method testTailParams (II)V
+first 0022
+block 0000
+  pred 0020
+  Blort.java:38@0000: const-int(6) v0:I=6 <- .
+  @????: mark-local-int . <- v0:"src"I
+  Blort.java:39@0003: const-int(7) v2:I=7 <- .
+  @????: mark-local-int . <- v2:"dest"I
+  @????: move-int v3:I=0 <- v1:I=0
+  @????: move-int v4:I <- v6:I
+  @????: move-int v5:I <- v7:I
+  Blort.java:41@000c: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I v1:I=0 v2:I v3:I=0 v
+  4:I v5:I
+  next 0021
+block 0020
+  pred 0022
+  Blort.java:38@0000: move-param-int(0) v6:"destPos"I <- .
+  Blort.java:38@0000: move-param-int(1) v7:"length"I <- .
+  Blort.java:38@0000: goto . <- .
+  next 0000
+block 0021
+  pred 0000
+  Blort.java:42@000f: return-void . <- .
+  returns
+block 0022
+  @????: const-int(0) v1:I=0 <- .
+  @????: goto . <- .
+  next 0020
+
+method testFlip ()V
+first 0034
+block 0000
+  pred 0032
+  Blort.java:47@0000: const-int(6) v0:I=6 <- .
+  @????: mark-local-int . <- v0:"src"I
+  Blort.java:48@0003: const-int(7) v2:I=7 <- .
+  @????: mark-local-int . <- v2:"dest"I
+  @????: move-int v5:I=0 <- v1:I=0
+  Blort.java:50@000c: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I v1:I=0 v2:I v3:I=1 v
+  4:I=5 v5:I=0
+  next 000f
+block 000f
+  pred 0000
+  @????: move-int v5:I <- v2:I
+  @????: move-int v6:I=0 <- v1:I=0
+  @????: move-int v7:I <- v0:I
+  @????: move-int v8:I=1 <- v3:I=1
+  @????: move-int v9:I=5 <- v4:I=5
+  @????: move-int v10:I=0 <- v1:I=0
+  Blort.java:51@0015: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v5:I v6:I=0 v7:I v8:I=1 v
+  9:I=5 v10:I=0
+  next 0033
+block 0032
+  pred 0034
+  Blort.java:47@0000: move-param-object(0) v11:"this"LBlort; <- .
+  Blort.java:47@0000: goto . <- .
+  next 0000
+block 0033
+  pred 000f
+  Blort.java:52@0018: return-void . <- .
+  returns
+block 0034
+  @????: const-int(5) v4:I=5 <- .
+  @????: const-int(1) v3:I=1 <- .
+  @????: const-int(0) v1:I=0 <- .
+  @????: goto . <- .
+  next 0032
+
+method testMixedCategory (Z)J
+first 0044
+block 0000
+  pred 003c
+  Blort.java:57@0001: if-eqz-int . <- v9:I
+  next 0004 *
+  next 001a
+block 0004
+  pred 0000
+  Blort.java:58@0004: const-int(1) v3:I=1 <- .
+  @????: mark-local-int . <- v3:"offset"I
+  Blort.java:59@0006: const-int(6) v0:I=6 <- .
+  @????: mark-local-int . <- v0:"src"I
+  Blort.java:60@0009: const-int(7) v2:I=7 <- .
+  @????: mark-local-int . <- v2:"dest"I
+  Blort.java:62@0012: const-int(5) v4:I=5 <- .
+  @????: move-int v5:I=0 <- v1:I=0
+  Blort.java:62@0014: Rop{invoke-static . <- I I I I I I call throws <any>}(Blo
+  rt.methodThatNeedsInvokeRange:(IIIIII)V catch) . <- v0:I v1:I=0 v2:I v3:I v4:
+  I=5 v5:I=0
+  next 0017
+block 0017
+  pred 0004
+  Blort.java:63@0018: conv-i2l v6:J <- v3:I
+  Blort.java:63@0019: goto . <- .
+  next 003d
+block 001a
+  pred 0000
+  Blort.java:65@001a: Rop{invoke-static . <- . call throws <any>}(java.lang.Sys
+  tem.currentTimeMillis:()J catch) . <- .
+  next 0043
+block 001d
+  pred 0043
+  @????: mark-local-long . <- v6:"offset"J
+  Blort.java:66@001f: goto . <- .
+  next 003d
+block 003c
+  pred 0044
+  Blort.java:57@0000: move-param-object(0) v8:"this"LBlort; <- .
+  Blort.java:57@0000: move-param-int(1) v9:"foo"Z <- .
+  Blort.java:57@0000: goto . <- .
+  next 0000
+block 003d
+  pred 0017
+  pred 001d
+  Blort.java:66@001f: return-long . <- v6:J
+  returns
+block 0043
+  pred 001a
+  Blort.java:65@001a: Rop{move-result J <- . flows} v6:J <- .
+  Blort.java:65@001a: goto . <- .
+  next 001d
+block 0044
+  @????: const-int(0) v1:I=0 <- .
+  @????: goto . <- .
+  next 003c
diff --git a/dx/tests/093-ssa-invoke-range/info.txt b/dx/tests/093-ssa-invoke-range/info.txt
new file mode 100644
index 0000000..372bed7
--- /dev/null
+++ b/dx/tests/093-ssa-invoke-range/info.txt
@@ -0,0 +1,6 @@
+This test case checks the ability of the register allocator to plan
+for dex's invoke-range instruction.
+
+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/093-ssa-invoke-range/run b/dx/tests/093-ssa-invoke-range/run
new file mode 100644
index 0000000..aa37784
--- /dev/null
+++ b/dx/tests/093-ssa-invoke-range/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --dump --optimize --rop-blocks Blort.class
diff --git a/dx/tests/094-scala-locals/blort.j b/dx/tests/094-scala-locals/blort.j
new file mode 100644
index 0000000..7c711ef
--- /dev/null
+++ b/dx/tests/094-scala-locals/blort.j
@@ -0,0 +1,44 @@
+; 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.
+
+.class Blort
+.super java/lang/Object
+
+.method public static returnint()I
+    .limit stack 1
+    ldc 10
+    ireturn
+.end method
+
+.method public static scalalocals()V
+    .limit locals 5
+    .limit stack 5
+    .var 4 is x I from start to end
+start:
+    invokestatic blort/returnint()I
+    invokestatic blort/returnint()I
+    invokestatic blort/returnint()I
+    invokestatic blort/returnint()I
+    dup
+    istore 4
+    istore 2
+    istore 3
+    istore 1
+    istore 0
+    iload_2
+    istore 4
+    iload_3
+end:
+    return
+.end method
diff --git a/dx/tests/094-scala-locals/expected.txt b/dx/tests/094-scala-locals/expected.txt
new file mode 100644
index 0000000..c3187f8
--- /dev/null
+++ b/dx/tests/094-scala-locals/expected.txt
@@ -0,0 +1,85 @@
+reading Blort.class...
+method scalalocals ()V
+first 0025
+block 0000
+  pred 001a
+  live in:{}
+  blort.j:@0000: Rop{invoke-static . <- . call throws <any>}(blort.returnint:()
+  I catch) . <- .
+  next 0021
+  live out:{}
+block 0003
+  pred 0021
+  live in:{}
+  blort.j:@0003: Rop{invoke-static . <- . call throws <any>}(blort.returnint:()
+  I catch) . <- .
+  next 0022
+  live out:{}
+block 0006
+  pred 0022
+  live in:{}
+  blort.j:@0006: Rop{invoke-static . <- . call throws <any>}(blort.returnint:()
+  I catch) . <- .
+  next 0023
+  live out:{}
+block 0009
+  pred 0023
+  live in:{}
+  blort.j:@0009: Rop{invoke-static . <- . call throws <any>}(blort.returnint:()
+  I catch) . <- .
+  next 0024
+  live out:{}
+block 000c
+  pred 0024
+  live in:{14}
+  @????: mark-local-int . <- v14:"x"I
+  blort.j:@001b: goto . <- .
+  next 001b
+  live out:{}
+block 001a
+  pred 0025
+  live in:{}
+  blort.j:@0000: goto . <- .
+  next 0000
+  live out:{}
+block 001b
+  pred 000c
+  live in:{}
+  blort.j:@001b: return-void . <- .
+  next 0026
+  live out:{}
+block 0021
+  pred 0000
+  live in:{}
+  blort.j:@0000: goto . <- .
+  next 0003
+  live out:{}
+block 0022
+  pred 0003
+  live in:{}
+  blort.j:@0003: goto . <- .
+  next 0006
+  live out:{}
+block 0023
+  pred 0006
+  live in:{}
+  blort.j:@0006: goto . <- .
+  next 0009
+  live out:{}
+block 0024
+  pred 0009
+  live in:{}
+  blort.j:@0009: Rop{move-result I <- . flows} v14:I <- .
+  blort.j:@0009: goto . <- .
+  next 000c
+  live out:{14}
+block 0025
+  live in:{}
+  @????: goto . <- .
+  next 001a
+  live out:{}
+block 0026
+  pred 001b
+  live in:{}
+  returns
+  live out:{}
diff --git a/dx/tests/094-scala-locals/info.txt b/dx/tests/094-scala-locals/info.txt
new file mode 100644
index 0000000..cb1a42e
--- /dev/null
+++ b/dx/tests/094-scala-locals/info.txt
@@ -0,0 +1,8 @@
+This is a smoke test of the SSA renamer's local variable preserver.
+It tests a case observed from Scala, wherein a local variable is assigned
+an identical value twice. The correct result should be only a single
+mark-local, with the second assignment eaten by copy-propogation.
+
+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/094-scala-locals/run b/dx/tests/094-scala-locals/run
new file mode 100644
index 0000000..4bbfa79
--- /dev/null
+++ b/dx/tests/094-scala-locals/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j >/dev/null
+dx --debug --dump --ssa-blocks  --method=scalalocals Blort.class
diff --git a/dx/tests/095-dex-const-string-jumbo/Blort.java b/dx/tests/095-dex-const-string-jumbo/Blort.java
new file mode 100644
index 0000000..a0271b5
--- /dev/null
+++ b/dx/tests/095-dex-const-string-jumbo/Blort.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+public class Blort {
+    static public void consume(String s) {
+        // This space intentionally left blank.
+    }
+
+    public void test() {
+        consume("zorch");
+    }
+}
diff --git a/dx/tests/095-dex-const-string-jumbo/expected.txt b/dx/tests/095-dex-const-string-jumbo/expected.txt
new file mode 100644
index 0000000..a4014d9
--- /dev/null
+++ b/dx/tests/095-dex-const-string-jumbo/expected.txt
@@ -0,0 +1,6 @@
+Blort.test:()V:
+regs: 0003; ins: 0001; outs: 0001
+  0000: move-object v0, v2
+  0001: const-string/jumbo v1, "zorch"
+  0004: invoke-static {v1}, Blort.consume:(Ljava/lang/String;)V
+  0007: return-void
diff --git a/dx/tests/095-dex-const-string-jumbo/info.txt b/dx/tests/095-dex-const-string-jumbo/info.txt
new file mode 100644
index 0000000..c14fd8e
--- /dev/null
+++ b/dx/tests/095-dex-const-string-jumbo/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+const-string/jumbo gets emitted appropriately.
+
+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/095-dex-const-string-jumbo/run b/dx/tests/095-dex-const-string-jumbo/run
new file mode 100644
index 0000000..a1c7365
--- /dev/null
+++ b/dx/tests/095-dex-const-string-jumbo/run
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# 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.
+
+# Write out files with 32768 total static string declarations, so that
+# the reference to "zorch" in the real test file will be guaranteed to
+# need a jumbo string reference (it sorts last after all the others).
+# Note: Each string reference is stored in a separate static variable,
+# and that variable's name is also represented in the strings, which
+# is why we can just have 32768 and not 65536 declarations.
+
+awk '
+BEGIN {
+    writeFile("Zorch1", 0, 16383);
+    writeFile("Zorch2", 16384, 32767);
+}
+function writeFile(name, start, end) {
+    fileName = name ".java";
+    printf("public class %s {\n", name) > fileName;
+    for (i = start; i <= end; i++) {
+        printf("    static public final String s%d = \"%d\";\n",
+            i, i) > fileName;
+    }
+    printf("}\n") > fileName;
+}'
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test *.class
diff --git a/dx/tests/096-dex-giant-catch/Blort.java b/dx/tests/096-dex-giant-catch/Blort.java
new file mode 100644
index 0000000..f5f6e8d
--- /dev/null
+++ b/dx/tests/096-dex-giant-catch/Blort.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+public class Blort {
+    static public void blort(long v1, long v2, long v3, long v4,
+            long v5, long v6, long v7, long v8) {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dx/tests/096-dex-giant-catch/expected.txt b/dx/tests/096-dex-giant-catch/expected.txt
new file mode 100644
index 0000000..e71992e
--- /dev/null
+++ b/dx/tests/096-dex-giant-catch/expected.txt
@@ -0,0 +1,5 @@
+  catches
+      try 0024..00010017
+      catch java.lang.RuntimeException -> 00011260
+      try 0001003b..0001125f
+      catch java.lang.RuntimeException -> 00011260
diff --git a/dx/tests/096-dex-giant-catch/info.txt b/dx/tests/096-dex-giant-catch/info.txt
new file mode 100644
index 0000000..b81ce94
--- /dev/null
+++ b/dx/tests/096-dex-giant-catch/info.txt
@@ -0,0 +1,7 @@
+This is a smoke test of dex conversion, which checks to see that
+very long catch ranges (that cover >= 65536 code units) get emitted
+appropriately.
+
+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/096-dex-giant-catch/run b/dx/tests/096-dex-giant-catch/run
new file mode 100644
index 0000000..c81d04c
--- /dev/null
+++ b/dx/tests/096-dex-giant-catch/run
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# 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.
+
+# Write out a file with a really huge catch range.
+
+awk '
+BEGIN {
+    fileName = "Zorch.java";
+    printf("public class Zorch {\n") > fileName;
+    printf("    static public void test() {\n") > fileName;
+    printf("        try {\n") > fileName;
+    for (i = 0; i <= 1800; i++) {
+        d = i + 1000000;
+        printf("    Blort.blort(100%dL, 200%dL, 300%dL, 400%dL, 500%dL, " \
+            "600%dL, 700%dL, 800%dL);\n",
+            d, d + 1, d + 2, d + 3, d + 4, d + 5, d + 6, d + 7) > fileName;
+    }
+    printf("        } catch (RuntimeException ex) {\n") > fileName;
+    printf("            throw ex;\n") > fileName;
+    printf("        }\n") > fileName;
+    printf("    }\n") > fileName;
+    printf("}\n") > fileName;
+}'
+
+$JAVAC -d . *.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Zorch.test Zorch.class | grep 'try\|catch'
diff --git a/dx/tests/097-dex-branch-offset-zero/Blort.java b/dx/tests/097-dex-branch-offset-zero/Blort.java
new file mode 100644
index 0000000..5033c8f
--- /dev/null
+++ b/dx/tests/097-dex-branch-offset-zero/Blort.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+public class Blort
+{
+    public void test1() {
+        for (;;) /*empty*/ ;
+    }
+
+    public void test2(int x) {
+        while (x > 0) /*empty*/ ;
+    }
+
+    public void test3(int x, int y) {
+        while (x < y) /*empty*/ ;
+    }
+}
diff --git a/dx/tests/097-dex-branch-offset-zero/expected.txt b/dx/tests/097-dex-branch-offset-zero/expected.txt
new file mode 100644
index 0000000..2b021a5
--- /dev/null
+++ b/dx/tests/097-dex-branch-offset-zero/expected.txt
@@ -0,0 +1 @@
+No bad branches found.
diff --git a/dx/tests/097-dex-branch-offset-zero/info.txt b/dx/tests/097-dex-branch-offset-zero/info.txt
new file mode 100644
index 0000000..4bf9502
--- /dev/null
+++ b/dx/tests/097-dex-branch-offset-zero/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to make sure that
+the only non-switch branches to offset 0 happen using the goto/32 opcode.
+
+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/097-dex-branch-offset-zero/run b/dx/tests/097-dex-branch-offset-zero/run
new file mode 100644
index 0000000..34539eb
--- /dev/null
+++ b/dx/tests/097-dex-branch-offset-zero/run
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --positions=none --no-locals --dump-method=Blort.test'*' \
+    *.class | grep '[-+][0-9]' | grep -v 'goto/32.*+00*$' | grep '// +00*$'
+
+if [ "$?" = "1" ]; then
+    echo "No bad branches found."
+else
+    # Redo the dx command without filters, to aid with debugging.
+    dx --debug --dex --positions=none --no-locals --dump-method=Blort.test'*' \
+    *.class
+fi
diff --git a/dx/tests/098-dex-jsr-ret-throw/ViewDebug$ViewServer.class b/dx/tests/098-dex-jsr-ret-throw/ViewDebug$ViewServer.class
new file mode 100644
index 0000000..ff992ca
--- /dev/null
+++ b/dx/tests/098-dex-jsr-ret-throw/ViewDebug$ViewServer.class
Binary files differ
diff --git a/dx/tests/098-dex-jsr-ret-throw/expected.txt b/dx/tests/098-dex-jsr-ret-throw/expected.txt
new file mode 100644
index 0000000..28552c6
--- /dev/null
+++ b/dx/tests/098-dex-jsr-ret-throw/expected.txt
@@ -0,0 +1,652 @@
+reading ViewDebug$ViewServer.class...
+method run ()V
+first 0162
+block 0000
+  pred 0162
+  ViewDebug.java:564@0000: move-object v11:Landroid/view/ViewDebug$ViewServer; 
+  <- v0:Landroid/view/ViewDebug$ViewServer;
+  ViewDebug.java:564@0001: get-field-object(android.view.ViewDebug$ViewServer.m
+  ViewServerSocket:Ljava/net/ServerSocket; catch) . <- v11:Landroid/view/ViewDe
+  bug$ViewServer;
+  next 0169
+block 0004
+  pred 0169
+  ViewDebug.java:564@0004: move-object v1:"server"Ljava/net/ServerSocket; <- v1
+  1:Ljava/net/ServerSocket;
+  ViewDebug.java:564@0004: goto . <- .
+  next 0005
+block 0005
+  pred 0004
+  pred 00ad
+  ViewDebug.java:566@0005: Rop{invoke-static . <- . call throws <any>}(java.lan
+  g.Thread.currentThread:()Ljava/lang/Thread; catch) . <- .
+  next 016a
+block 0008
+  pred 016a
+  ViewDebug.java:566@0008: move-object v12:Landroid/view/ViewDebug$ViewServer; 
+  <- v0:Landroid/view/ViewDebug$ViewServer;
+  ViewDebug.java:566@0009: get-field-object(android.view.ViewDebug$ViewServer.m
+  Thread:Ljava/lang/Thread; catch) . <- v12:Landroid/view/ViewDebug$ViewServer;
+  next 016b
+block 000c
+  pred 016b
+  ViewDebug.java:566@000c: if-ne-object . <- v11:Ljava/lang/Thread; v12:Ljava/l
+  ang/Thread;
+  next 000f *
+  next 00b0
+block 000f
+  pred 000c
+  ViewDebug.java:567@000f: const-object-nothrow(null) v11:<null>=null <- .
+  ViewDebug.java:567@0010: move-object v2:"client"Ljava/net/Socket; <- v11:<nul
+  l>=null
+  ViewDebug.java:567@0010: goto . <- .
+  next 0011
+block 0011
+  pred 000f
+  ViewDebug.java:569@0011: move-object v11:Ljava/net/ServerSocket; <- v1:Ljava/
+  net/ServerSocket;
+  ViewDebug.java:569@0012: Rop{invoke-virtual . <- Ljava/net/ServerSocket; call
+   throws <any>}(java.net.ServerSocket.accept:()Ljava/net/Socket; catch java.io
+  .IOException java.lang.Object) . <- v11:Ljava/net/ServerSocket;
+  next 0130
+  next 0140
+  next 016c *
+block 0015
+  pred 016c
+  ViewDebug.java:569@0015: move-object v2:"client"Ljava/net/Socket; <- v11:Ljav
+  a/net/Socket;
+  ViewDebug.java:571@0016: const-object-nothrow(null) v11:<null>=null <- .
+  ViewDebug.java:571@0017: move-object v3:"in"Ljava/io/BufferedReader; <- v11:<
+  null>=null
+  ViewDebug.java:571@0017: goto . <- .
+  next 0018
+block 0018
+  pred 0015
+  ViewDebug.java:573@0018: new-instance(java.io.BufferedReader catch java.lang.
+  Object) . <- .
+  next 0116
+  next 016d *
+block 001b
+  pred 016d
+  ViewDebug.java:573@001b: move-object v16:N0018Ljava/io/BufferedReader; <- v11
+  :N0018Ljava/io/BufferedReader;
+  ViewDebug.java:573@001b: move-object v11:N0018Ljava/io/BufferedReader; <- v16
+  :N0018Ljava/io/BufferedReader;
+  ViewDebug.java:573@001b: move-object v12:N0018Ljava/io/BufferedReader; <- v16
+  :N0018Ljava/io/BufferedReader;
+  ViewDebug.java:573@001c: new-instance(java.io.InputStreamReader catch java.la
+  ng.Object) . <- .
+  next 0116
+  next 016e *
+block 001f
+  pred 016e
+  ViewDebug.java:573@001f: move-object v16:N001cLjava/io/InputStreamReader; <- 
+  v13:N001cLjava/io/InputStreamReader;
+  ViewDebug.java:573@001f: move-object v13:N001cLjava/io/InputStreamReader; <- 
+  v16:N001cLjava/io/InputStreamReader;
+  ViewDebug.java:573@001f: move-object v14:N001cLjava/io/InputStreamReader; <- 
+  v16:N001cLjava/io/InputStreamReader;
+  ViewDebug.java:573@0020: move-object v15:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:573@0021: Rop{invoke-virtual . <- Ljava/net/Socket; call throw
+  s <any>}(java.net.Socket.getInputStream:()Ljava/io/InputStream; catch java.la
+  ng.Object) . <- v15:Ljava/net/Socket;
+  next 0116
+  next 016f *
+block 0024
+  pred 016f
+  ViewDebug.java:573@0024: Rop{invoke-direct . <- Ljava/io/InputStreamReader; L
+  java/io/InputStream; call throws <any>}(java.io.InputStreamReader.<init>:(Lja
+  va/io/InputStream;)V catch java.lang.Object) . <- v14:N001cLjava/io/InputStre
+  amReader; v15:Ljava/io/InputStream;
+  next 0116
+  next 0027 *
+block 0027
+  pred 0024
+  ViewDebug.java:573@0027: Rop{invoke-direct . <- Ljava/io/BufferedReader; Ljav
+  a/io/Reader; call throws <any>}(java.io.BufferedReader.<init>:(Ljava/io/Reade
+  r;)V catch java.lang.Object) . <- v12:N0018Ljava/io/BufferedReader; v13:Ljava
+  /io/InputStreamReader;
+  next 0116
+  next 002a *
+block 002a
+  pred 0027
+  ViewDebug.java:573@002a: move-object v3:"in"Ljava/io/BufferedReader; <- v11:L
+  java/io/BufferedReader;
+  ViewDebug.java:574@002b: move-object v11:Ljava/io/BufferedReader; <- v3:Ljava
+  /io/BufferedReader;
+  ViewDebug.java:574@002c: Rop{invoke-virtual . <- Ljava/io/BufferedReader; cal
+  l throws <any>}(java.io.BufferedReader.readLine:()Ljava/lang/String; catch ja
+  va.lang.Object) . <- v11:Ljava/io/BufferedReader;
+  next 0116
+  next 0170 *
+block 002f
+  pred 0170
+  ViewDebug.java:574@002f: move-object v4:"command"Ljava/lang/String; <- v11:Lj
+  ava/lang/String;
+  ViewDebug.java:576@0031: const-object("DUMP" catch java.lang.Object) . <- .
+  next 0116
+  next 0171 *
+block 0033
+  pred 0171
+  ViewDebug.java:576@0033: move-object v12:Ljava/lang/String; <- v4:Ljava/lang/
+  String;
+  ViewDebug.java:576@0035: Rop{invoke-virtual . <- Ljava/lang/String; Ljava/lan
+  g/String; call throws <any>}(java.lang.String.equalsIgnoreCase:(Ljava/lang/St
+  ring;)Z catch java.lang.Object) . <- v11:Ljava/lang/String;="DUMP" v12:Ljava/
+  lang/String;
+  next 0116
+  next 0172 *
+block 0038
+  pred 0172
+  ViewDebug.java:576@0038: if-eqz-int . <- v11:I
+  next 003b *
+  next 0042
+block 003b
+  pred 0038
+  ViewDebug.java:577@003b: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:577@003c: Rop{invoke-static . <- Ljava/net/Socket; call throws
+   <any>}(android.view.ViewDebug$ViewServer.dump:(Ljava/net/Socket;)V catch jav
+  a.lang.Object) . <- v11:Ljava/net/Socket;
+  next 0116
+  next 003f *
+block 003f
+  pred 003b
+  ViewDebug.java:577@003f: goto . <- .
+  next 005f
+block 0042
+  pred 0038
+  ViewDebug.java:579@0042: move-object v11:Ljava/lang/String; <- v4:Ljava/lang/
+  String;
+  ViewDebug.java:579@0044: const-object(" " catch java.lang.Object) . <- .
+  next 0116
+  next 0173 *
+block 0046
+  pred 0173
+  ViewDebug.java:579@0046: Rop{invoke-virtual . <- Ljava/lang/String; Ljava/lan
+  g/String; call throws <any>}(java.lang.String.split:(Ljava/lang/String;)[Ljav
+  a/lang/String; catch java.lang.Object) . <- v11:Ljava/lang/String; v12:Ljava/
+  lang/String;=" "
+  next 0116
+  next 0174 *
+block 0049
+  pred 0174
+  ViewDebug.java:579@0049: move-object v5:"params"[Ljava/lang/String; <- v11:[L
+  java/lang/String;
+  ViewDebug.java:580@004b: const-object("CAPTURE" catch java.lang.Object) . <- 
+  .
+  next 0116
+  next 0175 *
+block 004d
+  pred 0175
+  ViewDebug.java:580@004d: move-object v12:[Ljava/lang/String; <- v5:[Ljava/lan
+  g/String;
+  ViewDebug.java:580@004f: const-int(0) v13:I=0 <- .
+  ViewDebug.java:580@0050: aget-object(catch java.lang.Object) . <- v12:[Ljava/
+  lang/String; v13:I=0
+  next 0116
+  next 0176 *
+block 0051
+  pred 0176
+  ViewDebug.java:580@0051: Rop{invoke-virtual . <- Ljava/lang/String; Ljava/lan
+  g/String; call throws <any>}(java.lang.String.equalsIgnoreCase:(Ljava/lang/St
+  ring;)Z catch java.lang.Object) . <- v11:Ljava/lang/String;="CAPTURE" v12:Lja
+  va/lang/String;
+  next 0116
+  next 0177 *
+block 0054
+  pred 0177
+  ViewDebug.java:580@0054: if-eqz-int . <- v11:I
+  next 0057 *
+  next 005f
+block 0057
+  pred 0054
+  ViewDebug.java:581@0057: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:581@0058: move-object v12:[Ljava/lang/String; <- v5:[Ljava/lan
+  g/String;
+  ViewDebug.java:581@005a: const-int(1) v13:I=1 <- .
+  ViewDebug.java:581@005b: aget-object(catch java.lang.Object) . <- v12:[Ljava/
+  lang/String; v13:I=1
+  next 0116
+  next 0178 *
+block 005c
+  pred 0178
+  ViewDebug.java:581@005c: Rop{invoke-static . <- Ljava/net/Socket; Ljava/lang/
+  String; call throws <any>}(android.view.ViewDebug$ViewServer.capture:(Ljava/n
+  et/Socket;Ljava/lang/String;)V catch java.lang.Object) . <- v11:Ljava/net/Soc
+  ket; v12:Ljava/lang/String;
+  next 0116
+  next 005f *
+block 005f
+  pred 003f
+  pred 0054
+  pred 005c
+  @????: goto . <- .
+  next 018b
+block 0062
+  pred 018d
+  ViewDebug.java:589@0062: goto . <- .
+  next 0079
+block 0065
+  pred 0116
+  ViewDebug.java:586@0065: move-object v6:Ljava/lang/Class;=java.lang.Object <-
+   v11:Ljava/lang/Class;=java.lang.Object
+  ViewDebug.java:586@0065: goto . <- .
+  next 0067
+block 0067
+  pred 0065
+  @????: goto . <- .
+  next 0188
+block 006a
+  pred 018a
+  ViewDebug.java:586@006a: move-object v11:Ljava/lang/Class;=java.lang.Object <
+  - v6:Ljava/lang/Class;=java.lang.Object
+  ViewDebug.java:586@006c: throw(catch java.io.IOException java.lang.Object) . 
+  <- v11:Ljava/lang/Class;=java.lang.Object
+  next 0130
+  next 0140
+block 0079
+  pred 0062
+  @????: goto . <- .
+  next 018e
+block 007c
+  pred 0190
+  ViewDebug.java:600@007c: goto . <- .
+  next 00ad
+block 007f
+  pred 0130
+  ViewDebug.java:590@007f: move-object v3:"e"Ljava/io/IOException; <- v11:Ljava
+  /lang/Class;=java.io.IOException
+  ViewDebug.java:591@0080: const-object("ViewServer" catch java.lang.Object) . 
+  <- .
+  next 0140
+  next 0179 *
+block 0082
+  pred 0179
+  ViewDebug.java:591@0082: const-object("Connection error: " catch java.lang.Ob
+  ject) . <- .
+  next 0140
+  next 017a *
+block 0084
+  pred 017a
+  ViewDebug.java:591@0084: move-object v13:Ljava/io/IOException; <- v3:Ljava/io
+  /IOException;
+  ViewDebug.java:591@0085: Rop{invoke-static . <- Ljava/lang/String; Ljava/lang
+  /String; Ljava/lang/Throwable; call throws <any>}(android.util.Log.w:(Ljava/l
+  ang/String;Ljava/lang/String;Ljava/lang/Throwable;)I catch java.lang.Object) 
+  . <- v11:Ljava/lang/String;="ViewServer" v12:Ljava/lang/String;="Connection e
+  rror: " v13:Ljava/io/IOException;
+  next 0140
+  next 017b *
+block 0088
+  pred 017b
+  @????: goto . <- .
+  next 0089
+block 0089
+  pred 0088
+  @????: goto . <- .
+  next 0182
+block 008c
+  pred 0184
+  ViewDebug.java:600@008c: goto . <- .
+  next 00ad
+block 008f
+  pred 0140
+  ViewDebug.java:593@008f: move-object v8:Ljava/lang/Class;=java.lang.Object <-
+   v11:Ljava/lang/Class;=java.lang.Object
+  ViewDebug.java:593@008f: goto . <- .
+  next 0091
+block 0091
+  pred 008f
+  @????: goto . <- .
+  next 017c
+block 0094
+  pred 017e
+  ViewDebug.java:593@0094: move-object v11:Ljava/lang/Class;=java.lang.Object <
+  - v8:Ljava/lang/Class;=java.lang.Object
+  ViewDebug.java:593@0096: throw(catch) . <- v11:Ljava/lang/Class;=java.lang.Ob
+  ject
+  returns
+block 00ad
+  pred 007c
+  pred 008c
+  ViewDebug.java:601@00ad: goto . <- .
+  next 0005
+block 00b0
+  pred 000c
+  ViewDebug.java:602@00b0: goto . <- .
+  next 0163
+block 0116
+  pred 0018
+  pred 001b
+  pred 001f
+  pred 0024
+  pred 0027
+  pred 002a
+  pred 002f
+  pred 0033
+  pred 003b
+  pred 0042
+  pred 0046
+  pred 0049
+  pred 004d
+  pred 0051
+  pred 0057
+  pred 005c
+  ViewDebug.java:586@0065: Rop{move-exception Ljava/lang/Object; <- . flows} v1
+  1:Ljava/lang/Object; <- .
+  ViewDebug.java:586@0065: goto . <- .
+  next 0065
+block 0130
+  pred 0011
+  pred 006a
+  pred 0189
+  pred 018c
+  ViewDebug.java:590@007f: Rop{move-exception Ljava/io/IOException; <- . flows}
+   v11:Ljava/io/IOException; <- .
+  ViewDebug.java:590@007f: goto . <- .
+  next 007f
+block 0140
+  pred 0011
+  pred 006a
+  pred 007f
+  pred 0082
+  pred 0084
+  pred 0189
+  pred 018c
+  ViewDebug.java:593@008f: Rop{move-exception Ljava/lang/Object; <- . flows} v1
+  1:Ljava/lang/Object; <- .
+  ViewDebug.java:593@008f: goto . <- .
+  next 008f
+block 0162
+  ViewDebug.java:564@0000: move-param-object(0) v0:"this"Landroid/view/ViewDebu
+  g$ViewServer; <- .
+  ViewDebug.java:564@0000: goto . <- .
+  next 0000
+block 0163
+  pred 00b0
+  ViewDebug.java:602@00b0: return-void . <- .
+  returns
+block 0169
+  pred 0000
+  ViewDebug.java:564@0001: Rop{move-result-pseudo Ljava/net/ServerSocket; <- . 
+  flows} v11:Ljava/net/ServerSocket; <- .
+  ViewDebug.java:564@0001: goto . <- .
+  next 0004
+block 016a
+  pred 0005
+  ViewDebug.java:566@0005: Rop{move-result Ljava/lang/Thread; <- . flows} v11:L
+  java/lang/Thread; <- .
+  ViewDebug.java:566@0005: goto . <- .
+  next 0008
+block 016b
+  pred 0008
+  ViewDebug.java:566@0009: Rop{move-result-pseudo Ljava/lang/Thread; <- . flows
+  } v12:Ljava/lang/Thread; <- .
+  ViewDebug.java:566@0009: goto . <- .
+  next 000c
+block 016c
+  pred 0011
+  ViewDebug.java:569@0012: Rop{move-result Ljava/net/Socket; <- . flows} v11:Lj
+  ava/net/Socket; <- .
+  ViewDebug.java:569@0012: goto . <- .
+  next 0015
+block 016d
+  pred 0018
+  ViewDebug.java:573@0018: Rop{move-result-pseudo N0018Ljava/io/BufferedReader;
+   <- . flows} v11:N0018Ljava/io/BufferedReader; <- .
+  ViewDebug.java:573@0018: goto . <- .
+  next 001b
+block 016e
+  pred 001b
+  ViewDebug.java:573@001c: Rop{move-result-pseudo N001cLjava/io/InputStreamRead
+  er; <- . flows} v13:N001cLjava/io/InputStreamReader; <- .
+  ViewDebug.java:573@001c: goto . <- .
+  next 001f
+block 016f
+  pred 001f
+  ViewDebug.java:573@0021: Rop{move-result Ljava/io/InputStream; <- . flows} v1
+  5:Ljava/io/InputStream; <- .
+  ViewDebug.java:573@0021: goto . <- .
+  next 0024
+block 0170
+  pred 002a
+  ViewDebug.java:574@002c: Rop{move-result Ljava/lang/String; <- . flows} v11:L
+  java/lang/String; <- .
+  ViewDebug.java:574@002c: goto . <- .
+  next 002f
+block 0171
+  pred 002f
+  ViewDebug.java:576@0031: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v11:Ljava/lang/String;="DUMP" <- .
+  ViewDebug.java:576@0031: goto . <- .
+  next 0033
+block 0172
+  pred 0033
+  ViewDebug.java:576@0035: Rop{move-result Z <- . flows} v11:Z <- .
+  ViewDebug.java:576@0035: goto . <- .
+  next 0038
+block 0173
+  pred 0042
+  ViewDebug.java:579@0044: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v12:Ljava/lang/String;=" " <- .
+  ViewDebug.java:579@0044: goto . <- .
+  next 0046
+block 0174
+  pred 0046
+  ViewDebug.java:579@0046: Rop{move-result [Ljava/lang/String; <- . flows} v11:
+  [Ljava/lang/String; <- .
+  ViewDebug.java:579@0046: goto . <- .
+  next 0049
+block 0175
+  pred 0049
+  ViewDebug.java:580@004b: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v11:Ljava/lang/String;="CAPTURE" <- .
+  ViewDebug.java:580@004b: goto . <- .
+  next 004d
+block 0176
+  pred 004d
+  ViewDebug.java:580@0050: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v12:Ljava/lang/String; <- .
+  ViewDebug.java:580@0050: goto . <- .
+  next 0051
+block 0177
+  pred 0051
+  ViewDebug.java:580@0051: Rop{move-result Z <- . flows} v11:Z <- .
+  ViewDebug.java:580@0051: goto . <- .
+  next 0054
+block 0178
+  pred 0057
+  ViewDebug.java:581@005b: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v12:Ljava/lang/String; <- .
+  ViewDebug.java:581@005b: goto . <- .
+  next 005c
+block 0179
+  pred 007f
+  ViewDebug.java:591@0080: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v11:Ljava/lang/String;="ViewServer" <- .
+  ViewDebug.java:591@0080: goto . <- .
+  next 0082
+block 017a
+  pred 0082
+  ViewDebug.java:591@0082: Rop{move-result-pseudo Ljava/lang/String; <- . flows
+  } v12:Ljava/lang/String;="Connection error: " <- .
+  ViewDebug.java:591@0082: goto . <- .
+  next 0084
+block 017b
+  pred 0084
+  ViewDebug.java:591@0085: Rop{move-result I <- . flows} v11:I <- .
+  ViewDebug.java:591@0085: goto . <- .
+  next 0088
+block 017c
+  pred 0091
+  ViewDebug.java:593@0099: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:593@009a: if-eqz-object . <- v11:Ljava/net/Socket;
+  next 017d *
+  next 017e
+block 017d
+  pred 017c
+  ViewDebug.java:595@009d: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:595@009e: Rop{invoke-virtual . <- Ljava/net/Socket; call throw
+  s <any>}(java.net.Socket.close:()V catch java.io.IOException) . <- v11:Ljava/
+  net/Socket;
+  next 017f
+  next 0180 *
+block 017e
+  pred 017c
+  pred 0180
+  pred 0181
+  @????: goto . <- .
+  next 0094
+block 017f
+  pred 017d
+  ViewDebug.java:596@00a4: Rop{move-exception Ljava/io/IOException; <- . flows}
+   v11:Ljava/io/IOException; <- .
+  ViewDebug.java:596@00a4: goto . <- .
+  next 0181
+block 0180
+  pred 017d
+  ViewDebug.java:598@00a1: goto . <- .
+  next 017e
+block 0181
+  pred 017f
+  ViewDebug.java:596@00a4: move-object v10:"e"Ljava/io/IOException; <- v11:Ljav
+  a/lang/Class;=java.io.IOException
+  ViewDebug.java:597@00a6: move-object v11:Ljava/io/IOException; <- v10:Ljava/i
+  o/IOException;
+  ViewDebug.java:597@00a8: Rop{invoke-virtual . <- Ljava/io/IOException; call t
+  hrows <any>}(java.io.IOException.printStackTrace:()V catch) . <- v11:Ljava/io
+  /IOException;
+  next 017e
+block 0182
+  pred 0089
+  ViewDebug.java:593@0099: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:593@009a: if-eqz-object . <- v11:Ljava/net/Socket;
+  next 0183 *
+  next 0184
+block 0183
+  pred 0182
+  ViewDebug.java:595@009d: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:595@009e: Rop{invoke-virtual . <- Ljava/net/Socket; call throw
+  s <any>}(java.net.Socket.close:()V catch java.io.IOException) . <- v11:Ljava/
+  net/Socket;
+  next 0185
+  next 0186 *
+block 0184
+  pred 0182
+  pred 0186
+  pred 0187
+  @????: goto . <- .
+  next 008c
+block 0185
+  pred 0183
+  ViewDebug.java:596@00a4: Rop{move-exception Ljava/io/IOException; <- . flows}
+   v11:Ljava/io/IOException; <- .
+  ViewDebug.java:596@00a4: goto . <- .
+  next 0187
+block 0186
+  pred 0183
+  ViewDebug.java:598@00a1: goto . <- .
+  next 0184
+block 0187
+  pred 0185
+  ViewDebug.java:596@00a4: move-object v10:"e"Ljava/io/IOException; <- v11:Ljav
+  a/lang/Class;=java.io.IOException
+  ViewDebug.java:597@00a6: move-object v11:Ljava/io/IOException; <- v10:Ljava/i
+  o/IOException;
+  ViewDebug.java:597@00a8: Rop{invoke-virtual . <- Ljava/io/IOException; call t
+  hrows <any>}(java.io.IOException.printStackTrace:()V catch) . <- v11:Ljava/io
+  /IOException;
+  next 0184
+block 0188
+  pred 0067
+  ViewDebug.java:586@006f: move-object v11:Ljava/io/BufferedReader; <- v3:Ljava
+  /io/BufferedReader;
+  ViewDebug.java:586@0070: if-eqz-object . <- v11:Ljava/io/BufferedReader;
+  next 0189 *
+  next 018a
+block 0189
+  pred 0188
+  ViewDebug.java:587@0073: move-object v11:Ljava/io/BufferedReader; <- v3:Ljava
+  /io/BufferedReader;
+  ViewDebug.java:587@0074: Rop{invoke-virtual . <- Ljava/io/BufferedReader; cal
+  l throws <any>}(java.io.BufferedReader.close:()V catch java.io.IOException ja
+  va.lang.Object) . <- v11:Ljava/io/BufferedReader;
+  next 0130
+  next 0140
+  next 018a *
+block 018a
+  pred 0188
+  pred 0189
+  @????: goto . <- .
+  next 006a
+block 018b
+  pred 005f
+  ViewDebug.java:586@006f: move-object v11:Ljava/io/BufferedReader; <- v3:Ljava
+  /io/BufferedReader;
+  ViewDebug.java:586@0070: if-eqz-object . <- v11:Ljava/io/BufferedReader;
+  next 018c *
+  next 018d
+block 018c
+  pred 018b
+  ViewDebug.java:587@0073: move-object v11:Ljava/io/BufferedReader; <- v3:Ljava
+  /io/BufferedReader;
+  ViewDebug.java:587@0074: Rop{invoke-virtual . <- Ljava/io/BufferedReader; cal
+  l throws <any>}(java.io.BufferedReader.close:()V catch java.io.IOException ja
+  va.lang.Object) . <- v11:Ljava/io/BufferedReader;
+  next 0130
+  next 0140
+  next 018d *
+block 018d
+  pred 018b
+  pred 018c
+  @????: goto . <- .
+  next 0062
+block 018e
+  pred 0079
+  ViewDebug.java:593@0099: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:593@009a: if-eqz-object . <- v11:Ljava/net/Socket;
+  next 018f *
+  next 0190
+block 018f
+  pred 018e
+  ViewDebug.java:595@009d: move-object v11:Ljava/net/Socket; <- v2:Ljava/net/So
+  cket;
+  ViewDebug.java:595@009e: Rop{invoke-virtual . <- Ljava/net/Socket; call throw
+  s <any>}(java.net.Socket.close:()V catch java.io.IOException) . <- v11:Ljava/
+  net/Socket;
+  next 0191
+  next 0192 *
+block 0190
+  pred 018e
+  pred 0192
+  pred 0193
+  @????: goto . <- .
+  next 007c
+block 0191
+  pred 018f
+  ViewDebug.java:596@00a4: Rop{move-exception Ljava/io/IOException; <- . flows}
+   v11:Ljava/io/IOException; <- .
+  ViewDebug.java:596@00a4: goto . <- .
+  next 0193
+block 0192
+  pred 018f
+  ViewDebug.java:598@00a1: goto . <- .
+  next 0190
+block 0193
+  pred 0191
+  ViewDebug.java:596@00a4: move-object v10:"e"Ljava/io/IOException; <- v11:Ljav
+  a/lang/Class;=java.io.IOException
+  ViewDebug.java:597@00a6: move-object v11:Ljava/io/IOException; <- v10:Ljava/i
+  o/IOException;
+  ViewDebug.java:597@00a8: Rop{invoke-virtual . <- Ljava/io/IOException; call t
+  hrows <any>}(java.io.IOException.printStackTrace:()V catch) . <- v11:Ljava/io
+  /IOException;
+  next 0190
diff --git a/dx/tests/098-dex-jsr-ret-throw/info.txt b/dx/tests/098-dex-jsr-ret-throw/info.txt
new file mode 100644
index 0000000..9dcd39d
--- /dev/null
+++ b/dx/tests/098-dex-jsr-ret-throw/info.txt
@@ -0,0 +1,4 @@
+The enclosed class file was generated with javac version 1.5.0_13-b05. 
+It contains an example of a subroutine being exited by a "throw" instruction in 
+such a way that it caused the frame merge and subroutine inliner
+algorithms to not converge. This was bug #1137450.
diff --git a/dx/tests/098-dex-jsr-ret-throw/run b/dx/tests/098-dex-jsr-ret-throw/run
new file mode 100755
index 0000000..dfc7b89
--- /dev/null
+++ b/dx/tests/098-dex-jsr-ret-throw/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+dx --debug --dump --method=run --rop-blocks 'ViewDebug$ViewServer.class'
diff --git a/dx/tests/099-dex-core-library-error/Blort.java b/dx/tests/099-dex-core-library-error/Blort.java
new file mode 100644
index 0000000..6f619d7
--- /dev/null
+++ b/dx/tests/099-dex-core-library-error/Blort.java
@@ -0,0 +1,5 @@
+package java.blort;
+
+public class Blort {
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/099-dex-core-library-error/Muffins.java b/dx/tests/099-dex-core-library-error/Muffins.java
new file mode 100644
index 0000000..7ee4c4c
--- /dev/null
+++ b/dx/tests/099-dex-core-library-error/Muffins.java
@@ -0,0 +1,5 @@
+package javax.net;
+
+public class Muffins {
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/099-dex-core-library-error/Zorch.java b/dx/tests/099-dex-core-library-error/Zorch.java
new file mode 100644
index 0000000..57c311f
--- /dev/null
+++ b/dx/tests/099-dex-core-library-error/Zorch.java
@@ -0,0 +1,5 @@
+package javax.zorch;
+
+public class Zorch {
+    // This space intentionally left blank.
+}
diff --git a/dx/tests/099-dex-core-library-error/expected.txt b/dx/tests/099-dex-core-library-error/expected.txt
new file mode 100644
index 0000000..d9c405b
--- /dev/null
+++ b/dx/tests/099-dex-core-library-error/expected.txt
@@ -0,0 +1,5 @@
+exit code: 1
+exit code: 1
+exit code: 0
+Found zorch.dex
+Done
diff --git a/dx/tests/099-dex-core-library-error/info.txt b/dx/tests/099-dex-core-library-error/info.txt
new file mode 100644
index 0000000..3a62267
--- /dev/null
+++ b/dx/tests/099-dex-core-library-error/info.txt
@@ -0,0 +1,3 @@
+This tests that attempts to define core classes fail and that
+an attempt to define a legal javax.* class succeeds. (Only *some*
+javax packages are considered to be off-limits.)
diff --git a/dx/tests/099-dex-core-library-error/run b/dx/tests/099-dex-core-library-error/run
new file mode 100644
index 0000000..f063266
--- /dev/null
+++ b/dx/tests/099-dex-core-library-error/run
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+
+dx --debug --dex --output=blort.dex java/blort/Blort.class >/dev/null 2>&1
+echo "exit code: $?"
+if [ -r blort.dex ]; then
+    echo Found blort.dex
+fi
+
+dx --debug --dex --output=muffins.dex javax/net/Muffins.class >/dev/null 2>&1
+echo "exit code: $?"
+if [ -r muffins.dex ]; then
+    echo Found muffins.dex
+fi
+
+dx --debug --dex --output=zorch.dex javax/zorch/Zorch.class >/dev/null 2>&1
+echo "exit code: $?"
+if [ -r zorch.dex ]; then
+    echo Found zorch.dex
+fi
+
+echo Done
diff --git a/dx/tests/100-local-mismatch/blort1.j b/dx/tests/100-local-mismatch/blort1.j
new file mode 100644
index 0000000..327557e
--- /dev/null
+++ b/dx/tests/100-local-mismatch/blort1.j
@@ -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.
+
+.class Blort1
+.super java/lang/Object
+
+.method public static basicTypeMismatch1()V
+    .limit locals 1
+    .limit stack 1
+    .var 0 is x Ljava/lang/Object; from start to end
+    bipush 1
+    istore_0
+start:
+    nop
+end:
+    return
+.end method
diff --git a/dx/tests/100-local-mismatch/blort2.j b/dx/tests/100-local-mismatch/blort2.j
new file mode 100644
index 0000000..6fc79cc
--- /dev/null
+++ b/dx/tests/100-local-mismatch/blort2.j
@@ -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.
+
+.class Blort2
+.super java/lang/Object
+
+.method public static basicTypeMismatch2()V
+    .limit locals 1
+    .limit stack 1
+    .var 0 is x I from start to end
+    aconst_null
+    astore_0
+start:
+    nop
+end:
+    return
+.end method
diff --git a/dx/tests/100-local-mismatch/blort3.j b/dx/tests/100-local-mismatch/blort3.j
new file mode 100644
index 0000000..0fdcb89
--- /dev/null
+++ b/dx/tests/100-local-mismatch/blort3.j
@@ -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.
+
+.class Blort3
+.super java/lang/Object
+
+.method public static arrayMismatch1()V
+    .limit locals 1
+    .limit stack 1
+    .var 0 is x [B from start to end
+    bipush 1
+    istore_0
+start:
+    nop
+end:
+    return
+.end method
diff --git a/dx/tests/100-local-mismatch/blort4.j b/dx/tests/100-local-mismatch/blort4.j
new file mode 100644
index 0000000..1ef207d
--- /dev/null
+++ b/dx/tests/100-local-mismatch/blort4.j
@@ -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.
+
+.class Blort4
+.super java/lang/Object
+
+.method public static arrayMismatch2()V
+    .limit locals 1
+    .limit stack 1
+    .var 0 is x [Ljava/lang/Object; from start to end
+    ldc "hello"
+    astore_0
+start:
+    nop
+end:
+    return
+.end method
diff --git a/dx/tests/100-local-mismatch/expected.txt b/dx/tests/100-local-mismatch/expected.txt
new file mode 100644
index 0000000..0f77225
--- /dev/null
+++ b/dx/tests/100-local-mismatch/expected.txt
@@ -0,0 +1,9 @@
+TEST 1
+local variable type mismatch: attempt to set or access a value of type int using a local variable of type java.lang.Object. This is symptomatic of .class transformation tools that ignore local variable information.
+TEST 2
+local variable type mismatch: attempt to set or access a value of type java.lang.Object using a local variable of type int. This is symptomatic of .class transformation tools that ignore local variable information.
+TEST 3
+local variable type mismatch: attempt to set or access a value of type int using a local variable of type byte[]. This is symptomatic of .class transformation tools that ignore local variable information.
+TEST 4
+local variable type mismatch: attempt to set or access a value of type java.lang.String using a local variable of type java.lang.Object[]. This is symptomatic of .class transformation tools that ignore local variable information.
+DONE
diff --git a/dx/tests/100-local-mismatch/info.txt b/dx/tests/100-local-mismatch/info.txt
new file mode 100644
index 0000000..89b6e10
--- /dev/null
+++ b/dx/tests/100-local-mismatch/info.txt
@@ -0,0 +1,3 @@
+This is a smoke test that makes sure that dx complains when a local
+variable table entry fundamentally disagrees with an instruction that
+accesses that local.
diff --git a/dx/tests/100-local-mismatch/run b/dx/tests/100-local-mismatch/run
new file mode 100644
index 0000000..fbcf1ed
--- /dev/null
+++ b/dx/tests/100-local-mismatch/run
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort1.j >/dev/null
+jasmin -d . blort2.j >/dev/null
+jasmin -d . blort3.j >/dev/null
+jasmin -d . blort4.j >/dev/null
+
+echo "TEST 1"
+dx --dex Blort1.class 2>&1 | grep mismatch
+
+echo "TEST 2"
+dx --dex Blort2.class 2>&1 | grep mismatch
+
+echo "TEST 3"
+dx --dex Blort3.class 2>&1 | grep mismatch
+
+echo "TEST 4"
+dx --dex Blort4.class 2>&1 | grep mismatch
+
+echo "DONE"
diff --git a/dx/tests/101-verify-wide-math/expected.txt b/dx/tests/101-verify-wide-math/expected.txt
new file mode 100644
index 0000000..4bd352d
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/expected.txt
@@ -0,0 +1,54 @@
+Generated: ./op_d2f.class
+d2f: expected failure occurred
+Generated: ./op_d2i.class
+d2i: expected failure occurred
+Generated: ./op_d2l.class
+d2l: expected failure occurred
+Generated: ./op_dadd.class
+dadd: expected failure occurred
+Generated: ./op_dcmpg.class
+dcmpg: expected failure occurred
+Generated: ./op_dcmpl.class
+dcmpl: expected failure occurred
+Generated: ./op_ddiv.class
+ddiv: expected failure occurred
+Generated: ./op_dmul.class
+dmul: expected failure occurred
+Generated: ./op_dneg.class
+dneg: expected failure occurred
+Generated: ./op_drem.class
+drem: expected failure occurred
+Generated: ./op_dsub.class
+dsub: expected failure occurred
+Generated: ./op_l2d.class
+l2d: expected failure occurred
+Generated: ./op_l2f.class
+l2f: expected failure occurred
+Generated: ./op_l2i.class
+l2i: expected failure occurred
+Generated: ./op_ladd.class
+ladd: expected failure occurred
+Generated: ./op_land.class
+land: expected failure occurred
+Generated: ./op_lcmp.class
+lcmp: expected failure occurred
+Generated: ./op_ldiv.class
+ldiv: expected failure occurred
+Generated: ./op_lmul.class
+lmul: expected failure occurred
+Generated: ./op_lneg.class
+lneg: expected failure occurred
+Generated: ./op_lor.class
+lor: expected failure occurred
+Generated: ./op_lrem.class
+lrem: expected failure occurred
+Generated: ./op_lshl.class
+lshl: expected failure occurred
+Generated: ./op_lshr.class
+lshr: expected failure occurred
+Generated: ./op_lsub.class
+lsub: expected failure occurred
+Generated: ./op_lushr.class
+lushr: expected failure occurred
+Generated: ./op_lxor.class
+lxor: expected failure occurred
diff --git a/dx/tests/101-verify-wide-math/info.txt b/dx/tests/101-verify-wide-math/info.txt
new file mode 100644
index 0000000..6ec551d
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/info.txt
@@ -0,0 +1,3 @@
+This tests that wide-taking (category-2) "calculation" opcodes (math
+ops, comparisons, etc.) verify that their arguments are actually of
+the appropriate types.
diff --git a/dx/tests/101-verify-wide-math/op_d2f.j b/dx/tests/101-verify-wide-math/op_d2f.j
new file mode 100644
index 0000000..65a3c9d
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_d2f.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_d2f
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    d2f
+    freturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_d2i.j b/dx/tests/101-verify-wide-math/op_d2i.j
new file mode 100644
index 0000000..6e8976c
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_d2i.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_d2i
+.super java/lang/Object
+
+.method public static test(II)I
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    d2i
+    ireturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_d2l.j b/dx/tests/101-verify-wide-math/op_d2l.j
new file mode 100644
index 0000000..f8e24c9
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_d2l.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_d2l
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    d2l
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_dadd.j b/dx/tests/101-verify-wide-math/op_dadd.j
new file mode 100644
index 0000000..232c541
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_dadd.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dadd
+.super java/lang/Object
+
+.method public static test(II)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    dadd
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_dcmpg.j b/dx/tests/101-verify-wide-math/op_dcmpg.j
new file mode 100644
index 0000000..cd1b151
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_dcmpg.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dcmpg
+.super java/lang/Object
+
+.method public static test(II)I
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    dcmpg
+    ireturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_dcmpl.j b/dx/tests/101-verify-wide-math/op_dcmpl.j
new file mode 100644
index 0000000..dd54c52
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_dcmpl.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dcmpl
+.super java/lang/Object
+
+.method public static test(II)I
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    dcmpl
+    ireturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_ddiv.j b/dx/tests/101-verify-wide-math/op_ddiv.j
new file mode 100644
index 0000000..b9ee329
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_ddiv.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ddiv
+.super java/lang/Object
+
+.method public static test(II)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    ddiv
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_dmul.j b/dx/tests/101-verify-wide-math/op_dmul.j
new file mode 100644
index 0000000..f915e79
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_dmul.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dmul
+.super java/lang/Object
+
+.method public static test(II)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    dmul
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_dneg.j b/dx/tests/101-verify-wide-math/op_dneg.j
new file mode 100644
index 0000000..98fd9df
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_dneg.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dneg
+.super java/lang/Object
+
+.method public static test(II)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    dneg
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_drem.j b/dx/tests/101-verify-wide-math/op_drem.j
new file mode 100644
index 0000000..c0fca65
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_drem.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_drem
+.super java/lang/Object
+
+.method public static test(II)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    drem
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_dsub.j b/dx/tests/101-verify-wide-math/op_dsub.j
new file mode 100644
index 0000000..e04f505
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_dsub.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dsub
+.super java/lang/Object
+
+.method public static test(II)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    dsub
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_l2d.j b/dx/tests/101-verify-wide-math/op_l2d.j
new file mode 100644
index 0000000..d4ac0a8
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_l2d.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_l2d
+.super java/lang/Object
+
+.method public static test(I)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    l2d
+    dreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_l2f.j b/dx/tests/101-verify-wide-math/op_l2f.j
new file mode 100644
index 0000000..2dbe9d2
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_l2f.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_l2f
+.super java/lang/Object
+
+.method public static test(I)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    l2f
+    freturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_l2i.j b/dx/tests/101-verify-wide-math/op_l2i.j
new file mode 100644
index 0000000..1b4e68a
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_l2i.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_l2i
+.super java/lang/Object
+
+.method public static test(I)I
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    l2i
+    ireturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_ladd.j b/dx/tests/101-verify-wide-math/op_ladd.j
new file mode 100644
index 0000000..1dbb6f8
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_ladd.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ladd
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    ladd
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_land.j b/dx/tests/101-verify-wide-math/op_land.j
new file mode 100644
index 0000000..e8a55bb
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_land.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_land
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    land
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lcmp.j b/dx/tests/101-verify-wide-math/op_lcmp.j
new file mode 100644
index 0000000..b651c9c
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lcmp.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lcmp
+.super java/lang/Object
+
+.method public static test(II)I
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lcmp
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_ldiv.j b/dx/tests/101-verify-wide-math/op_ldiv.j
new file mode 100644
index 0000000..677daa2
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_ldiv.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ldiv
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    ldiv
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lmul.j b/dx/tests/101-verify-wide-math/op_lmul.j
new file mode 100644
index 0000000..074d67c
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lmul.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lmul
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lmul
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lneg.j b/dx/tests/101-verify-wide-math/op_lneg.j
new file mode 100644
index 0000000..18d5780
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lneg.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_lneg
+.super java/lang/Object
+
+.method public static test(I)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    lneg
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lor.j b/dx/tests/101-verify-wide-math/op_lor.j
new file mode 100644
index 0000000..267ff1f
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lor.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lor
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lor
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lrem.j b/dx/tests/101-verify-wide-math/op_lrem.j
new file mode 100644
index 0000000..5e0df6e
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lrem.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lrem
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lrem
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lshl.j b/dx/tests/101-verify-wide-math/op_lshl.j
new file mode 100644
index 0000000..bc16ea5
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lshl.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lshl
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lshl
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lshr.j b/dx/tests/101-verify-wide-math/op_lshr.j
new file mode 100644
index 0000000..b93fb2f
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lshr.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lshr
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lshr
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lsub.j b/dx/tests/101-verify-wide-math/op_lsub.j
new file mode 100644
index 0000000..823d899
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lsub.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lsub
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lsub
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lushr.j b/dx/tests/101-verify-wide-math/op_lushr.j
new file mode 100644
index 0000000..aa9feb2
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lushr.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lushr
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lushr
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/op_lxor.j b/dx/tests/101-verify-wide-math/op_lxor.j
new file mode 100644
index 0000000..3897c96
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/op_lxor.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_lxor
+.super java/lang/Object
+
+.method public static test(II)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    lxor
+    lreturn
+.end method
diff --git a/dx/tests/101-verify-wide-math/run b/dx/tests/101-verify-wide-math/run
new file mode 100644
index 0000000..a5ecd58
--- /dev/null
+++ b/dx/tests/101-verify-wide-math/run
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop d2f
+oneop d2i
+oneop d2l
+oneop dadd
+oneop dcmpg
+oneop dcmpl
+oneop ddiv
+oneop dmul
+oneop dneg
+oneop drem
+oneop dsub
+oneop l2d
+oneop l2f
+oneop l2i
+oneop ladd
+oneop land
+oneop lcmp
+oneop ldiv
+oneop lmul
+oneop lneg
+oneop lor
+oneop lrem
+oneop lshl
+oneop lshr
+oneop lsub
+oneop lushr
+oneop lxor
diff --git a/dx/tests/102-verify-nonwide-math/expected.txt b/dx/tests/102-verify-nonwide-math/expected.txt
new file mode 100644
index 0000000..3f857b1
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/expected.txt
@@ -0,0 +1,48 @@
+Generated: ./op_f2d.class
+f2d: expected failure occurred
+Generated: ./op_f2i.class
+f2i: expected failure occurred
+Generated: ./op_f2l.class
+f2l: expected failure occurred
+Generated: ./op_fadd.class
+fadd: expected failure occurred
+Generated: ./op_fdiv.class
+fdiv: expected failure occurred
+Generated: ./op_fmul.class
+fmul: expected failure occurred
+Generated: ./op_fneg.class
+fneg: expected failure occurred
+Generated: ./op_frem.class
+frem: expected failure occurred
+Generated: ./op_fsub.class
+fsub: expected failure occurred
+Generated: ./op_i2d.class
+i2d: expected failure occurred
+Generated: ./op_i2f.class
+i2f: expected failure occurred
+Generated: ./op_i2l.class
+i2l: expected failure occurred
+Generated: ./op_iadd.class
+iadd: expected failure occurred
+Generated: ./op_iand.class
+iand: expected failure occurred
+Generated: ./op_idiv.class
+idiv: expected failure occurred
+Generated: ./op_imul.class
+imul: expected failure occurred
+Generated: ./op_ineg.class
+ineg: expected failure occurred
+Generated: ./op_ior.class
+ior: expected failure occurred
+Generated: ./op_irem.class
+irem: expected failure occurred
+Generated: ./op_ishl.class
+ishl: expected failure occurred
+Generated: ./op_ishr.class
+ishr: expected failure occurred
+Generated: ./op_isub.class
+isub: expected failure occurred
+Generated: ./op_iushr.class
+iushr: expected failure occurred
+Generated: ./op_ixor.class
+ixor: expected failure occurred
diff --git a/dx/tests/102-verify-nonwide-math/info.txt b/dx/tests/102-verify-nonwide-math/info.txt
new file mode 100644
index 0000000..10e52ba
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/info.txt
@@ -0,0 +1,3 @@
+This tests that non-wide-taking (category-1) "calculation" opcodes (math
+ops, comparisons, etc.) to verify that their arguments are actually of
+the appropriate types.
diff --git a/dx/tests/102-verify-nonwide-math/op_f2d.j b/dx/tests/102-verify-nonwide-math/op_f2d.j
new file mode 100644
index 0000000..75e8917
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_f2d.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_f2d
+.super java/lang/Object
+
+.method public static test(I)D
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    f2d
+    dreturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_f2i.j b/dx/tests/102-verify-nonwide-math/op_f2i.j
new file mode 100644
index 0000000..2d36af7
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_f2i.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_f2i
+.super java/lang/Object
+
+.method public static test(I)I
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    f2i
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_f2l.j b/dx/tests/102-verify-nonwide-math/op_f2l.j
new file mode 100644
index 0000000..fae9e21
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_f2l.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_f2l
+.super java/lang/Object
+
+.method public static test(I)J
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    f2l
+    lreturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_fadd.j b/dx/tests/102-verify-nonwide-math/op_fadd.j
new file mode 100644
index 0000000..dc3743f
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_fadd.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_fadd
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    fadd
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_fdiv.j b/dx/tests/102-verify-nonwide-math/op_fdiv.j
new file mode 100644
index 0000000..8609be2
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_fdiv.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_fdiv
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    fdiv
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_fmul.j b/dx/tests/102-verify-nonwide-math/op_fmul.j
new file mode 100644
index 0000000..fe4661c
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_fmul.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_fmul
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    fmul
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_fneg.j b/dx/tests/102-verify-nonwide-math/op_fneg.j
new file mode 100644
index 0000000..34898bd
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_fneg.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_fneg
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    fneg
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_frem.j b/dx/tests/102-verify-nonwide-math/op_frem.j
new file mode 100644
index 0000000..17f4602
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_frem.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_frem
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    frem
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_fsub.j b/dx/tests/102-verify-nonwide-math/op_fsub.j
new file mode 100644
index 0000000..692f4f8
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_fsub.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_fsub
+.super java/lang/Object
+
+.method public static test(II)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    iload_1
+    fsub
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_i2d.j b/dx/tests/102-verify-nonwide-math/op_i2d.j
new file mode 100644
index 0000000..6c73dbe
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_i2d.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_i2d
+.super java/lang/Object
+
+.method public static test(FF)D
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    i2d
+    dreturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_i2f.j b/dx/tests/102-verify-nonwide-math/op_i2f.j
new file mode 100644
index 0000000..cee0b84
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_i2f.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_i2f
+.super java/lang/Object
+
+.method public static test(FF)F
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    i2f
+    freturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_i2l.j b/dx/tests/102-verify-nonwide-math/op_i2l.j
new file mode 100644
index 0000000..d6f2daa
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_i2l.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_i2l
+.super java/lang/Object
+
+.method public static test(FF)J
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    i2l
+    lreturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_iadd.j b/dx/tests/102-verify-nonwide-math/op_iadd.j
new file mode 100644
index 0000000..e3d92e3
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_iadd.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_iadd
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    iadd
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_iand.j b/dx/tests/102-verify-nonwide-math/op_iand.j
new file mode 100644
index 0000000..063738c
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_iand.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_iand
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    iand
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_idiv.j b/dx/tests/102-verify-nonwide-math/op_idiv.j
new file mode 100644
index 0000000..2e3e3a3
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_idiv.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_idiv
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    idiv
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_imul.j b/dx/tests/102-verify-nonwide-math/op_imul.j
new file mode 100644
index 0000000..7f4f612
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_imul.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_imul
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    imul
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_ineg.j b/dx/tests/102-verify-nonwide-math/op_ineg.j
new file mode 100644
index 0000000..68fcb8c
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_ineg.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_ineg
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ineg
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_ior.j b/dx/tests/102-verify-nonwide-math/op_ior.j
new file mode 100644
index 0000000..c8c3a4b
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_ior.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ior
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    ior
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_irem.j b/dx/tests/102-verify-nonwide-math/op_irem.j
new file mode 100644
index 0000000..b22f1fd
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_irem.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_irem
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    irem
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_ishl.j b/dx/tests/102-verify-nonwide-math/op_ishl.j
new file mode 100644
index 0000000..e617182
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_ishl.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ishl
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    ishl
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_ishr.j b/dx/tests/102-verify-nonwide-math/op_ishr.j
new file mode 100644
index 0000000..64eba11
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_ishr.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ishr
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    ishr
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_isub.j b/dx/tests/102-verify-nonwide-math/op_isub.j
new file mode 100644
index 0000000..ee789b0
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_isub.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_isub
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    isub
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_iushr.j b/dx/tests/102-verify-nonwide-math/op_iushr.j
new file mode 100644
index 0000000..73c34f1
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_iushr.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_iushr
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    iushr
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/op_ixor.j b/dx/tests/102-verify-nonwide-math/op_ixor.j
new file mode 100644
index 0000000..68f095b
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/op_ixor.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_ixor
+.super java/lang/Object
+
+.method public static test(FF)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    ixor
+    ireturn
+.end method
diff --git a/dx/tests/102-verify-nonwide-math/run b/dx/tests/102-verify-nonwide-math/run
new file mode 100644
index 0000000..eb4a294
--- /dev/null
+++ b/dx/tests/102-verify-nonwide-math/run
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop f2d
+oneop f2i
+oneop f2l
+oneop fadd
+oneop fdiv
+oneop fmul
+oneop fneg
+oneop frem
+oneop fsub
+oneop i2d
+oneop i2f
+oneop i2l
+oneop iadd
+oneop iand
+oneop idiv
+oneop imul
+oneop ineg
+oneop ior
+oneop irem
+oneop ishl
+oneop ishr
+oneop isub
+oneop iushr
+oneop ixor
diff --git a/dx/tests/103-verify-branch-ops/expected.txt b/dx/tests/103-verify-branch-ops/expected.txt
new file mode 100644
index 0000000..2c96704
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/expected.txt
@@ -0,0 +1,36 @@
+Generated: ./op_if_acmpeq.class
+if_acmpeq: expected failure occurred
+Generated: ./op_if_acmpne.class
+if_acmpne: expected failure occurred
+Generated: ./op_if_icmpeq.class
+if_icmpeq: expected failure occurred
+Generated: ./op_if_icmpge.class
+if_icmpge: expected failure occurred
+Generated: ./op_if_icmpgt.class
+if_icmpgt: expected failure occurred
+Generated: ./op_if_icmple.class
+if_icmple: expected failure occurred
+Generated: ./op_if_icmplt.class
+if_icmplt: expected failure occurred
+Generated: ./op_if_icmpne.class
+if_icmpne: expected failure occurred
+Generated: ./op_ifeq.class
+ifeq: expected failure occurred
+Generated: ./op_ifge.class
+ifge: expected failure occurred
+Generated: ./op_ifgt.class
+ifgt: expected failure occurred
+Generated: ./op_ifle.class
+ifle: expected failure occurred
+Generated: ./op_iflt.class
+iflt: expected failure occurred
+Generated: ./op_ifne.class
+ifne: expected failure occurred
+Generated: ./op_ifnonnull.class
+ifnonnull: expected failure occurred
+Generated: ./op_ifnull.class
+ifnull: expected failure occurred
+Generated: ./op_lookupswitch.class
+lookupswitch: expected failure occurred
+Generated: ./op_tableswitch.class
+tableswitch: expected failure occurred
diff --git a/dx/tests/103-verify-branch-ops/info.txt b/dx/tests/103-verify-branch-ops/info.txt
new file mode 100644
index 0000000..8705e83
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/info.txt
@@ -0,0 +1,2 @@
+This tests branch opcodes to verify that their arguments are actually of
+the appropriate types.
diff --git a/dx/tests/103-verify-branch-ops/op_if_acmpeq.j b/dx/tests/103-verify-branch-ops/op_if_acmpeq.j
new file mode 100644
index 0000000..4339200
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_acmpeq.j
@@ -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.
+
+.class op_if_acmpeq
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_acmpeq blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_acmpne.j b/dx/tests/103-verify-branch-ops/op_if_acmpne.j
new file mode 100644
index 0000000..57a317b
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_acmpne.j
@@ -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.
+
+.class op_if_acmpne
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_acmpne blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_icmpeq.j b/dx/tests/103-verify-branch-ops/op_if_icmpeq.j
new file mode 100644
index 0000000..1f141bc
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_icmpeq.j
@@ -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.
+
+.class op_if_icmpeq
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_icmpeq blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_icmpge.j b/dx/tests/103-verify-branch-ops/op_if_icmpge.j
new file mode 100644
index 0000000..6ae2e3f
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_icmpge.j
@@ -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.
+
+.class op_if_icmpge
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_icmpge blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_icmpgt.j b/dx/tests/103-verify-branch-ops/op_if_icmpgt.j
new file mode 100644
index 0000000..4e67282
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_icmpgt.j
@@ -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.
+
+.class op_if_icmpgt
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_icmpgt blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_icmple.j b/dx/tests/103-verify-branch-ops/op_if_icmple.j
new file mode 100644
index 0000000..3511800
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_icmple.j
@@ -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.
+
+.class op_if_icmple
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_icmple blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_icmplt.j b/dx/tests/103-verify-branch-ops/op_if_icmplt.j
new file mode 100644
index 0000000..89527f5
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_icmplt.j
@@ -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.
+
+.class op_if_icmplt
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_icmplt blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_if_icmpne.j b/dx/tests/103-verify-branch-ops/op_if_icmpne.j
new file mode 100644
index 0000000..a94faee
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_if_icmpne.j
@@ -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.
+
+.class op_if_icmpne
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    fload_1
+    if_icmpne blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifeq.j b/dx/tests/103-verify-branch-ops/op_ifeq.j
new file mode 100644
index 0000000..620e1c9
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifeq.j
@@ -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.
+
+.class op_ifeq
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ifeq blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifge.j b/dx/tests/103-verify-branch-ops/op_ifge.j
new file mode 100644
index 0000000..c46b176
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifge.j
@@ -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.
+
+.class op_ifge
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ifge blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifgt.j b/dx/tests/103-verify-branch-ops/op_ifgt.j
new file mode 100644
index 0000000..8165038
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifgt.j
@@ -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.
+
+.class op_ifgt
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ifgt blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifle.j b/dx/tests/103-verify-branch-ops/op_ifle.j
new file mode 100644
index 0000000..758943f
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifle.j
@@ -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.
+
+.class op_ifle
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ifle blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_iflt.j b/dx/tests/103-verify-branch-ops/op_iflt.j
new file mode 100644
index 0000000..5091355
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_iflt.j
@@ -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.
+
+.class op_iflt
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iflt blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifne.j b/dx/tests/103-verify-branch-ops/op_ifne.j
new file mode 100644
index 0000000..bb2dadc
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifne.j
@@ -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.
+
+.class op_ifne
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ifne blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifnonnull.j b/dx/tests/103-verify-branch-ops/op_ifnonnull.j
new file mode 100644
index 0000000..f2422f0
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifnonnull.j
@@ -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.
+
+.class op_ifnonnull
+.super java/lang/Object
+
+.method public static test(IF)V
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    ifnonnull blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_ifnull.j b/dx/tests/103-verify-branch-ops/op_ifnull.j
new file mode 100644
index 0000000..c253b09
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_ifnull.j
@@ -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.
+
+.class op_ifnull
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ifnull blort
+    nop
+blort:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_lookupswitch.j b/dx/tests/103-verify-branch-ops/op_lookupswitch.j
new file mode 100644
index 0000000..21fe8f7
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_lookupswitch.j
@@ -0,0 +1,33 @@
+; 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.
+
+.class op_lookupswitch
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    lookupswitch
+        0x05: t1
+        0x10: t2
+        default: t3
+t1:
+    nop
+t2:
+    nop
+t3:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/op_tableswitch.j b/dx/tests/103-verify-branch-ops/op_tableswitch.j
new file mode 100644
index 0000000..657feff
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/op_tableswitch.j
@@ -0,0 +1,33 @@
+; 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.
+
+.class op_tableswitch
+.super java/lang/Object
+
+.method public static test(FF)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    tableswitch 0x10
+        t1
+        t2
+        default: t3
+t1:
+    nop
+t2:
+    nop
+t3:
+    return
+.end method
diff --git a/dx/tests/103-verify-branch-ops/run b/dx/tests/103-verify-branch-ops/run
new file mode 100644
index 0000000..c9ca89f
--- /dev/null
+++ b/dx/tests/103-verify-branch-ops/run
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop if_acmpeq
+oneop if_acmpne
+oneop if_icmpeq
+oneop if_icmpge
+oneop if_icmpgt
+oneop if_icmple
+oneop if_icmplt
+oneop if_icmpne
+oneop ifeq
+oneop ifge
+oneop ifgt
+oneop ifle
+oneop iflt
+oneop ifne
+oneop ifnonnull
+oneop ifnull
+oneop lookupswitch
+oneop tableswitch
diff --git a/dx/tests/104-verify-return-ops/expected.txt b/dx/tests/104-verify-return-ops/expected.txt
new file mode 100644
index 0000000..5bd9dfd
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/expected.txt
@@ -0,0 +1,22 @@
+Generated: ./op_areturn.class
+areturn: expected failure occurred
+Generated: ./op_dreturn.class
+dreturn: expected failure occurred
+Generated: ./op_freturn.class
+freturn: expected failure occurred
+Generated: ./op_ireturn.class
+ireturn: expected failure occurred
+Generated: ./op_lreturn.class
+lreturn: expected failure occurred
+Generated: ./op_sig_areturn.class
+sig_areturn: expected failure occurred
+Generated: ./op_sig_dreturn.class
+sig_dreturn: expected failure occurred
+Generated: ./op_sig_freturn.class
+sig_freturn: expected failure occurred
+Generated: ./op_sig_ireturn.class
+sig_ireturn: expected failure occurred
+Generated: ./op_sig_lreturn.class
+sig_lreturn: expected failure occurred
+Generated: ./op_sig_return.class
+sig_return: expected failure occurred
diff --git a/dx/tests/104-verify-return-ops/info.txt b/dx/tests/104-verify-return-ops/info.txt
new file mode 100644
index 0000000..1f5e634
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/info.txt
@@ -0,0 +1,2 @@
+This tests that return opcodes verify that their arguments are actually of
+the appropriate types and that the opcode matches the method signature.
diff --git a/dx/tests/104-verify-return-ops/op_areturn.j b/dx/tests/104-verify-return-ops/op_areturn.j
new file mode 100644
index 0000000..0b25088
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_areturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_areturn
+.super java/lang/Object
+
+.method public static test(F)Ljava/lang/Object;
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    areturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_dreturn.j b/dx/tests/104-verify-return-ops/op_dreturn.j
new file mode 100644
index 0000000..1075fe1
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_dreturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_dreturn
+.super java/lang/Object
+
+.method public static test(F)D
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    dreturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_freturn.j b/dx/tests/104-verify-return-ops/op_freturn.j
new file mode 100644
index 0000000..6586ce6
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_freturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_freturn
+.super java/lang/Object
+
+.method public static test(I)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    freturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_ireturn.j b/dx/tests/104-verify-return-ops/op_ireturn.j
new file mode 100644
index 0000000..e93dda8
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_ireturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_ireturn
+.super java/lang/Object
+
+.method public static test(F)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    ireturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_lreturn.j b/dx/tests/104-verify-return-ops/op_lreturn.j
new file mode 100644
index 0000000..349f353
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_lreturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_lreturn
+.super java/lang/Object
+
+.method public static test(F)J
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    lreturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_sig_areturn.j b/dx/tests/104-verify-return-ops/op_sig_areturn.j
new file mode 100644
index 0000000..f1ea1b4
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_sig_areturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_sig_areturn
+.super java/lang/Object
+
+.method public static test(I)F
+    .limit locals 2
+    .limit stack 3
+
+    aconst_null
+    areturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_sig_dreturn.j b/dx/tests/104-verify-return-ops/op_sig_dreturn.j
new file mode 100644
index 0000000..fa6fcd2
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_sig_dreturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_sig_dreturn
+.super java/lang/Object
+
+.method public static test(D)F
+    .limit locals 2
+    .limit stack 3
+
+    dload_0
+    dreturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_sig_freturn.j b/dx/tests/104-verify-return-ops/op_sig_freturn.j
new file mode 100644
index 0000000..be5dea8
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_sig_freturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_sig_freturn
+.super java/lang/Object
+
+.method public static test(F)I
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    freturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_sig_ireturn.j b/dx/tests/104-verify-return-ops/op_sig_ireturn.j
new file mode 100644
index 0000000..ab3aa40
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_sig_ireturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_sig_ireturn
+.super java/lang/Object
+
+.method public static test(I)F
+    .limit locals 2
+    .limit stack 3
+
+    iload_0
+    ireturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_sig_lreturn.j b/dx/tests/104-verify-return-ops/op_sig_lreturn.j
new file mode 100644
index 0000000..e5a121d
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_sig_lreturn.j
@@ -0,0 +1,24 @@
+; 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.
+
+.class op_sig_lreturn
+.super java/lang/Object
+
+.method public static test(J)F
+    .limit locals 2
+    .limit stack 3
+
+    lload_0
+    lreturn
+.end method
diff --git a/dx/tests/104-verify-return-ops/op_sig_return.j b/dx/tests/104-verify-return-ops/op_sig_return.j
new file mode 100644
index 0000000..26c0678
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/op_sig_return.j
@@ -0,0 +1,23 @@
+; 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.
+
+.class op_sig_return
+.super java/lang/Object
+
+.method public static test(I)F
+    .limit locals 2
+    .limit stack 3
+
+    return
+.end method
diff --git a/dx/tests/104-verify-return-ops/run b/dx/tests/104-verify-return-ops/run
new file mode 100644
index 0000000..fbce332
--- /dev/null
+++ b/dx/tests/104-verify-return-ops/run
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop areturn
+oneop dreturn
+oneop freturn
+oneop ireturn
+oneop lreturn
+oneop sig_areturn
+oneop sig_dreturn
+oneop sig_freturn
+oneop sig_ireturn
+oneop sig_lreturn
+oneop sig_return
diff --git a/dx/tests/105-verify-load-store-ops/expected.txt b/dx/tests/105-verify-load-store-ops/expected.txt
new file mode 100644
index 0000000..b5db406
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/expected.txt
@@ -0,0 +1,84 @@
+Generated: ./op_aaload.class
+aaload: expected failure occurred
+Generated: ./op_aastore.class
+aastore: expected failure occurred
+Generated: ./op_aastore2.class
+aastore2: expected failure occurred
+Generated: ./op_astore.class
+astore: expected failure occurred
+Generated: ./op_astore_0.class
+astore_0: expected failure occurred
+Generated: ./op_astore_1.class
+astore_1: expected failure occurred
+Generated: ./op_astore_2.class
+astore_2: expected failure occurred
+Generated: ./op_astore_3.class
+astore_3: expected failure occurred
+Generated: ./op_baload.class
+baload: expected failure occurred
+Generated: ./op_bastore.class
+bastore: expected failure occurred
+Generated: ./op_caload.class
+caload: expected failure occurred
+Generated: ./op_castore.class
+castore: expected failure occurred
+Generated: ./op_daload.class
+daload: expected failure occurred
+Generated: ./op_dastore.class
+dastore: expected failure occurred
+Generated: ./op_dstore.class
+dstore: expected failure occurred
+Generated: ./op_dstore_0.class
+dstore_0: expected failure occurred
+Generated: ./op_dstore_1.class
+dstore_1: expected failure occurred
+Generated: ./op_dstore_2.class
+dstore_2: expected failure occurred
+Generated: ./op_dstore_3.class
+dstore_3: expected failure occurred
+Generated: ./op_faload.class
+faload: expected failure occurred
+Generated: ./op_fastore.class
+fastore: expected failure occurred
+Generated: ./op_fstore.class
+fstore: expected failure occurred
+Generated: ./op_fstore_0.class
+fstore_0: expected failure occurred
+Generated: ./op_fstore_1.class
+fstore_1: expected failure occurred
+Generated: ./op_fstore_2.class
+fstore_2: expected failure occurred
+Generated: ./op_fstore_3.class
+fstore_3: expected failure occurred
+Generated: ./op_iaload.class
+iaload: expected failure occurred
+Generated: ./op_iastore.class
+iastore: expected failure occurred
+Generated: ./op_istore.class
+istore: expected failure occurred
+Generated: ./op_istore_0.class
+istore_0: expected failure occurred
+Generated: ./op_istore_1.class
+istore_1: expected failure occurred
+Generated: ./op_istore_2.class
+istore_2: expected failure occurred
+Generated: ./op_istore_3.class
+istore_3: expected failure occurred
+Generated: ./op_laload.class
+laload: expected failure occurred
+Generated: ./op_lastore.class
+lastore: expected failure occurred
+Generated: ./op_lstore.class
+lstore: expected failure occurred
+Generated: ./op_lstore_0.class
+lstore_0: expected failure occurred
+Generated: ./op_lstore_1.class
+lstore_1: expected failure occurred
+Generated: ./op_lstore_2.class
+lstore_2: expected failure occurred
+Generated: ./op_lstore_3.class
+lstore_3: expected failure occurred
+Generated: ./op_saload.class
+saload: expected failure occurred
+Generated: ./op_sastore.class
+sastore: expected failure occurred
diff --git a/dx/tests/105-verify-load-store-ops/info.txt b/dx/tests/105-verify-load-store-ops/info.txt
new file mode 100644
index 0000000..a3a41d6
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/info.txt
@@ -0,0 +1,2 @@
+This tests that load and store opcodes verify that their arguments are
+actually of the appropriate types.
diff --git a/dx/tests/105-verify-load-store-ops/op_aaload.j b/dx/tests/105-verify-load-store-ops/op_aaload.j
new file mode 100644
index 0000000..f77827e
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_aaload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_aaload
+.super java/lang/Object
+
+.method public static test([F)V
+    .limit locals 2
+    .limit stack 3
+
+    aload_0
+    iconst_0
+    aaload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_aastore.j b/dx/tests/105-verify-load-store-ops/op_aastore.j
new file mode 100644
index 0000000..58e1576
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_aastore.j
@@ -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.
+
+.class op_aastore
+.super java/lang/Object
+
+.method public static test([I)V
+    .limit locals 2
+    .limit stack 4
+
+    aload_0
+    iconst_0
+    aconst_null
+    aastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_aastore2.j b/dx/tests/105-verify-load-store-ops/op_aastore2.j
new file mode 100644
index 0000000..0083800
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_aastore2.j
@@ -0,0 +1,27 @@
+; Copyright (C) 2010 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.class op_aastore2
+.super java/lang/Object
+
+.method public static test([I)V
+    .limit locals 2
+    .limit stack 4
+
+    aload_0
+    iconst_0
+    iconst_0
+    aastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_astore.j b/dx/tests/105-verify-load-store-ops/op_astore.j
new file mode 100644
index 0000000..25131bf
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_astore.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_astore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    astore 5
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_astore_0.j b/dx/tests/105-verify-load-store-ops/op_astore_0.j
new file mode 100644
index 0000000..b509c12
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_astore_0.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_astore_0
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    astore_0
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_astore_1.j b/dx/tests/105-verify-load-store-ops/op_astore_1.j
new file mode 100644
index 0000000..a6c1043
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_astore_1.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_astore_1
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    astore_1
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_astore_2.j b/dx/tests/105-verify-load-store-ops/op_astore_2.j
new file mode 100644
index 0000000..cb84ee8
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_astore_2.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_astore_2
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    astore_2
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_astore_3.j b/dx/tests/105-verify-load-store-ops/op_astore_3.j
new file mode 100644
index 0000000..c716ba2
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_astore_3.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_astore_3
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    astore_3
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_baload.j b/dx/tests/105-verify-load-store-ops/op_baload.j
new file mode 100644
index 0000000..cfcaf74
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_baload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_baload
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iconst_0
+    baload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_bastore.j b/dx/tests/105-verify-load-store-ops/op_bastore.j
new file mode 100644
index 0000000..587fcd3
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_bastore.j
@@ -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.
+
+.class op_bastore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    iconst_0
+    bastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_caload.j b/dx/tests/105-verify-load-store-ops/op_caload.j
new file mode 100644
index 0000000..ceaf09f
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_caload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_caload
+.super java/lang/Object
+
+.method public static test(D)V
+    .limit locals 2
+    .limit stack 3
+
+    dload_0
+    iconst_0
+    caload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_castore.j b/dx/tests/105-verify-load-store-ops/op_castore.j
new file mode 100644
index 0000000..5bd493e
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_castore.j
@@ -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.
+
+.class op_castore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    iconst_0
+    castore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_daload.j b/dx/tests/105-verify-load-store-ops/op_daload.j
new file mode 100644
index 0000000..895d6be
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_daload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_daload
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iconst_0
+    daload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_dastore.j b/dx/tests/105-verify-load-store-ops/op_dastore.j
new file mode 100644
index 0000000..b102f79
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_dastore.j
@@ -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.
+
+.class op_dastore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    dconst_0
+    dastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_dstore.j b/dx/tests/105-verify-load-store-ops/op_dstore.j
new file mode 100644
index 0000000..d656a84
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_dstore.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dstore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    dstore 5
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_dstore_0.j b/dx/tests/105-verify-load-store-ops/op_dstore_0.j
new file mode 100644
index 0000000..cb3da3a
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_dstore_0.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dstore_0
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    dstore_0
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_dstore_1.j b/dx/tests/105-verify-load-store-ops/op_dstore_1.j
new file mode 100644
index 0000000..45fcf9b
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_dstore_1.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dstore_1
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    dstore_1
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_dstore_2.j b/dx/tests/105-verify-load-store-ops/op_dstore_2.j
new file mode 100644
index 0000000..7c167d4
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_dstore_2.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dstore_2
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    dstore_2
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_dstore_3.j b/dx/tests/105-verify-load-store-ops/op_dstore_3.j
new file mode 100644
index 0000000..17222e0
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_dstore_3.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dstore_3
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    dstore_3
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_faload.j b/dx/tests/105-verify-load-store-ops/op_faload.j
new file mode 100644
index 0000000..1c17a8e
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_faload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_faload
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iconst_0
+    faload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_fastore.j b/dx/tests/105-verify-load-store-ops/op_fastore.j
new file mode 100644
index 0000000..799555e
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_fastore.j
@@ -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.
+
+.class op_fastore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    fconst_0
+    fastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_fstore.j b/dx/tests/105-verify-load-store-ops/op_fstore.j
new file mode 100644
index 0000000..5c61ebe
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_fstore.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_fstore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    iconst_0
+    fstore 5
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_fstore_0.j b/dx/tests/105-verify-load-store-ops/op_fstore_0.j
new file mode 100644
index 0000000..d3033e9
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_fstore_0.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_fstore_0
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    iconst_0
+    fstore_0
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_fstore_1.j b/dx/tests/105-verify-load-store-ops/op_fstore_1.j
new file mode 100644
index 0000000..0abca8f
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_fstore_1.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_fstore_1
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    iconst_0
+    fstore_1
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_fstore_2.j b/dx/tests/105-verify-load-store-ops/op_fstore_2.j
new file mode 100644
index 0000000..5cd1ebc
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_fstore_2.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_fstore_2
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    iconst_0
+    fstore_2
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_fstore_3.j b/dx/tests/105-verify-load-store-ops/op_fstore_3.j
new file mode 100644
index 0000000..a232307
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_fstore_3.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_fstore_3
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    iconst_0
+    fstore_3
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_iaload.j b/dx/tests/105-verify-load-store-ops/op_iaload.j
new file mode 100644
index 0000000..3face08
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_iaload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_iaload
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iconst_0
+    iaload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_iastore.j b/dx/tests/105-verify-load-store-ops/op_iastore.j
new file mode 100644
index 0000000..d090e37
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_iastore.j
@@ -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.
+
+.class op_iastore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    iconst_0
+    iastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_istore.j b/dx/tests/105-verify-load-store-ops/op_istore.j
new file mode 100644
index 0000000..138d709
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_istore.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_istore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    istore 5
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_istore_0.j b/dx/tests/105-verify-load-store-ops/op_istore_0.j
new file mode 100644
index 0000000..2644c3d
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_istore_0.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_istore_0
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    istore_0
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_istore_1.j b/dx/tests/105-verify-load-store-ops/op_istore_1.j
new file mode 100644
index 0000000..03534ee
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_istore_1.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_istore_1
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    istore_1
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_istore_2.j b/dx/tests/105-verify-load-store-ops/op_istore_2.j
new file mode 100644
index 0000000..e1a80b3
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_istore_2.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_istore_2
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    istore_2
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_istore_3.j b/dx/tests/105-verify-load-store-ops/op_istore_3.j
new file mode 100644
index 0000000..43c226f
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_istore_3.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_istore_3
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    istore_3
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_laload.j b/dx/tests/105-verify-load-store-ops/op_laload.j
new file mode 100644
index 0000000..3143604
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_laload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_laload
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iconst_0
+    laload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_lastore.j b/dx/tests/105-verify-load-store-ops/op_lastore.j
new file mode 100644
index 0000000..b7ea069
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_lastore.j
@@ -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.
+
+.class op_lastore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    lconst_0
+    lastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_lstore.j b/dx/tests/105-verify-load-store-ops/op_lstore.j
new file mode 100644
index 0000000..fde6974
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_lstore.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_lstore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    lstore 5
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_lstore_0.j b/dx/tests/105-verify-load-store-ops/op_lstore_0.j
new file mode 100644
index 0000000..e98eab4
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_lstore_0.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_lstore_0
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    lstore_0
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_lstore_1.j b/dx/tests/105-verify-load-store-ops/op_lstore_1.j
new file mode 100644
index 0000000..0e2291a
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_lstore_1.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_lstore_1
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    lstore_1
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_lstore_2.j b/dx/tests/105-verify-load-store-ops/op_lstore_2.j
new file mode 100644
index 0000000..a84702d
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_lstore_2.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_lstore_2
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    dconst_0
+    lstore_2
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_lstore_3.j b/dx/tests/105-verify-load-store-ops/op_lstore_3.j
new file mode 100644
index 0000000..c35ace8
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_lstore_3.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_lstore_3
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 6
+    .limit stack 4
+
+    fconst_0
+    lstore_3
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_saload.j b/dx/tests/105-verify-load-store-ops/op_saload.j
new file mode 100644
index 0000000..4a80939
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_saload.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_saload
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 3
+
+    fload_0
+    iconst_0
+    saload
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/op_sastore.j b/dx/tests/105-verify-load-store-ops/op_sastore.j
new file mode 100644
index 0000000..c97dd66
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/op_sastore.j
@@ -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.
+
+.class op_sastore
+.super java/lang/Object
+
+.method public static test(F)V
+    .limit locals 2
+    .limit stack 4
+
+    fload_0
+    iconst_0
+    iconst_0
+    sastore
+    return
+.end method
diff --git a/dx/tests/105-verify-load-store-ops/run b/dx/tests/105-verify-load-store-ops/run
new file mode 100644
index 0000000..a6c5acc
--- /dev/null
+++ b/dx/tests/105-verify-load-store-ops/run
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop aaload
+oneop aastore
+oneop aastore2 # second aastore test
+oneop astore
+oneop astore_0
+oneop astore_1
+oneop astore_2
+oneop astore_3
+oneop baload
+oneop bastore
+oneop caload
+oneop castore
+oneop daload
+oneop dastore
+oneop dstore
+oneop dstore_0
+oneop dstore_1
+oneop dstore_2
+oneop dstore_3
+oneop faload
+oneop fastore
+oneop fstore
+oneop fstore_0
+oneop fstore_1
+oneop fstore_2
+oneop fstore_3
+oneop iaload
+oneop iastore
+oneop istore
+oneop istore_0
+oneop istore_1
+oneop istore_2
+oneop istore_3
+oneop laload
+oneop lastore
+oneop lstore
+oneop lstore_0
+oneop lstore_1
+oneop lstore_2
+oneop lstore_3
+oneop saload
+oneop sastore
diff --git a/dx/tests/106-verify-object-ops/expected.txt b/dx/tests/106-verify-object-ops/expected.txt
new file mode 100644
index 0000000..ce36b7e
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/expected.txt
@@ -0,0 +1,32 @@
+Generated: ./op_anewarray.class
+anewarray: expected failure occurred
+Generated: ./op_arraylength.class
+arraylength: expected failure occurred
+Generated: ./op_athrow.class
+athrow: expected failure occurred
+Generated: ./op_checkcast.class
+checkcast: expected failure occurred
+Generated: ./op_getfield.class
+getfield: expected failure occurred
+Generated: ./op_instanceof.class
+instanceof: expected failure occurred
+Generated: ./op_invokeinterface.class
+invokeinterface: expected failure occurred
+Generated: ./op_invokespecial.class
+invokespecial: expected failure occurred
+Generated: ./op_invokestatic.class
+invokestatic: expected failure occurred
+Generated: ./op_invokevirtual.class
+invokevirtual: expected failure occurred
+Generated: ./op_monitorenter.class
+monitorenter: expected failure occurred
+Generated: ./op_monitorexit.class
+monitorexit: expected failure occurred
+Generated: ./op_multianewarray.class
+multianewarray: expected failure occurred
+Generated: ./op_newarray.class
+newarray: expected failure occurred
+Generated: ./op_putfield.class
+putfield: expected failure occurred
+Generated: ./op_putstatic.class
+putstatic: expected failure occurred
diff --git a/dx/tests/106-verify-object-ops/info.txt b/dx/tests/106-verify-object-ops/info.txt
new file mode 100644
index 0000000..85295d7
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/info.txt
@@ -0,0 +1,2 @@
+This tests that the various "objecty" opcodes verify that their
+arguments are actually of the appropriate types.
diff --git a/dx/tests/106-verify-object-ops/op_anewarray.j b/dx/tests/106-verify-object-ops/op_anewarray.j
new file mode 100644
index 0000000..348acbd
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_anewarray.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_anewarray
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    anewarray java/lang/Object
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_arraylength.j b/dx/tests/106-verify-object-ops/op_arraylength.j
new file mode 100644
index 0000000..df5af82
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_arraylength.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_arraylength
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    arraylength
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_athrow.j b/dx/tests/106-verify-object-ops/op_athrow.j
new file mode 100644
index 0000000..a5a5be3
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_athrow.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_athrow
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    athrow
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_checkcast.j b/dx/tests/106-verify-object-ops/op_checkcast.j
new file mode 100644
index 0000000..d921ec4
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_checkcast.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_checkcast
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    checkcast java/lang/Object
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_getfield.j b/dx/tests/106-verify-object-ops/op_getfield.j
new file mode 100644
index 0000000..4d5f782
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_getfield.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_getfield
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    getfield blort/x I
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_instanceof.j b/dx/tests/106-verify-object-ops/op_instanceof.j
new file mode 100644
index 0000000..8a938f5
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_instanceof.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_instanceof
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    instanceof java/lang/Object
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_invokeinterface.j b/dx/tests/106-verify-object-ops/op_invokeinterface.j
new file mode 100644
index 0000000..2f1528f
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_invokeinterface.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_invokeinterface
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    invokeinterface blort/x()V 1
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_invokespecial.j b/dx/tests/106-verify-object-ops/op_invokespecial.j
new file mode 100644
index 0000000..87baffc
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_invokespecial.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_invokespecial
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    invokespecial blort/x()V
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_invokestatic.j b/dx/tests/106-verify-object-ops/op_invokestatic.j
new file mode 100644
index 0000000..80247bd
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_invokestatic.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_invokestatic
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    invokestatic blort/x(I)V
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_invokevirtual.j b/dx/tests/106-verify-object-ops/op_invokevirtual.j
new file mode 100644
index 0000000..d7ba9b5
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_invokevirtual.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_invokevirtual
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    invokevirtual blort/x()V
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_monitorenter.j b/dx/tests/106-verify-object-ops/op_monitorenter.j
new file mode 100644
index 0000000..95e23d8
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_monitorenter.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_monitorenter
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    monitorenter
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_monitorexit.j b/dx/tests/106-verify-object-ops/op_monitorexit.j
new file mode 100644
index 0000000..50e5fe2
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_monitorexit.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_monitorexit
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    monitorexit
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_multianewarray.j b/dx/tests/106-verify-object-ops/op_multianewarray.j
new file mode 100644
index 0000000..d02f474
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_multianewarray.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_multianewarray
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    iconst_0
+    multianewarray [[[I 2
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_newarray.j b/dx/tests/106-verify-object-ops/op_newarray.j
new file mode 100644
index 0000000..16ab256
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_newarray.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_newarray
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    newarray short
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_putfield.j b/dx/tests/106-verify-object-ops/op_putfield.j
new file mode 100644
index 0000000..eb33fc9
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_putfield.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_putfield
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    iconst_0
+    putfield blort/x I
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/op_putstatic.j b/dx/tests/106-verify-object-ops/op_putstatic.j
new file mode 100644
index 0000000..221f08b
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/op_putstatic.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_putstatic
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 3
+
+    fconst_0
+    putstatic blort/x I
+    return
+.end method
diff --git a/dx/tests/106-verify-object-ops/run b/dx/tests/106-verify-object-ops/run
new file mode 100644
index 0000000..f512210
--- /dev/null
+++ b/dx/tests/106-verify-object-ops/run
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop anewarray
+oneop arraylength
+oneop athrow
+oneop checkcast
+oneop getfield
+oneop instanceof
+oneop invokeinterface
+oneop invokespecial
+oneop invokestatic
+oneop invokevirtual
+oneop monitorenter
+oneop monitorexit
+oneop multianewarray
+oneop newarray
+oneop putfield
+oneop putstatic
diff --git a/dx/tests/107-verify-stack-ops/expected.txt b/dx/tests/107-verify-stack-ops/expected.txt
new file mode 100644
index 0000000..812025d
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/expected.txt
@@ -0,0 +1,34 @@
+Generated: ./op_dup.class
+dup: expected failure occurred
+Generated: ./op_dup_x1_case1.class
+dup_x1_case1: expected failure occurred
+Generated: ./op_dup_x1_case2.class
+dup_x1_case2: expected failure occurred
+Generated: ./op_dup_x2_case1.class
+dup_x2_case1: expected failure occurred
+Generated: ./op_dup_x2_case2.class
+dup_x2_case2: expected failure occurred
+Generated: ./op_dup_x2_case3.class
+dup_x2_case3: expected failure occurred
+Generated: ./op_dup2.class
+dup2: expected failure occurred
+Generated: ./op_dup2_x1_case1.class
+dup2_x1_case1: expected failure occurred
+Generated: ./op_dup2_x1_case2.class
+dup2_x1_case2: expected failure occurred
+Generated: ./op_dup2_x1_case3.class
+dup2_x1_case3: expected failure occurred
+Generated: ./op_dup2_x2_case1.class
+dup2_x2_case1: expected failure occurred
+Generated: ./op_dup2_x2_case2.class
+dup2_x2_case2: expected failure occurred
+Generated: ./op_dup2_x2_case3.class
+dup2_x2_case3: expected failure occurred
+Generated: ./op_pop.class
+pop: expected failure occurred
+Generated: ./op_pop2.class
+pop2: expected failure occurred
+Generated: ./op_swap_case1.class
+swap_case1: expected failure occurred
+Generated: ./op_swap_case2.class
+swap_case2: expected failure occurred
diff --git a/dx/tests/107-verify-stack-ops/info.txt b/dx/tests/107-verify-stack-ops/info.txt
new file mode 100644
index 0000000..c489ace
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/info.txt
@@ -0,0 +1,2 @@
+This tests that the various stack manipulation opcodes verify that their
+arguments are actually of the appropriate categories.
diff --git a/dx/tests/107-verify-stack-ops/op_dup.j b/dx/tests/107-verify-stack-ops/op_dup.j
new file mode 100644
index 0000000..6c9ebc2
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_dup
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    dup
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2.j b/dx/tests/107-verify-stack-ops/op_dup2.j
new file mode 100644
index 0000000..d17ce20
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dup2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    dup2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_case1.j b/dx/tests/107-verify-stack-ops/op_dup2_case1.j
new file mode 100644
index 0000000..7b014f7
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_case1.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dup2_case1
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    dup2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_x1_case1.j b/dx/tests/107-verify-stack-ops/op_dup2_x1_case1.j
new file mode 100644
index 0000000..26667f0
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_x1_case1.j
@@ -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.
+
+.class op_dup2_x1_case1
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 8
+
+    dconst_0
+    iconst_0
+    iconst_0
+    dup2_x1
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_x1_case2.j b/dx/tests/107-verify-stack-ops/op_dup2_x1_case2.j
new file mode 100644
index 0000000..35e97c4
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_x1_case2.j
@@ -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.
+
+.class op_dup2_x1_case2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 8
+
+    iconst_0
+    dconst_0
+    iconst_0
+    dup2_x1
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_x1_case3.j b/dx/tests/107-verify-stack-ops/op_dup2_x1_case3.j
new file mode 100644
index 0000000..d15ccc3
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_x1_case3.j
@@ -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.
+
+.class op_dup2_x1_case3
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 8
+
+    iconst_0
+    dconst_0
+    dconst_0
+    dup2_x1
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_x2_case1.j b/dx/tests/107-verify-stack-ops/op_dup2_x2_case1.j
new file mode 100644
index 0000000..e2538a0
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_x2_case1.j
@@ -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.
+
+.class op_dup2_x2_case1
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 8
+
+    dconst_0
+    iconst_0
+    iconst_0
+    iconst_0
+    dup2_x2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_x2_case2.j b/dx/tests/107-verify-stack-ops/op_dup2_x2_case2.j
new file mode 100644
index 0000000..1e2645c
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_x2_case2.j
@@ -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.
+
+.class op_dup2_x2_case2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 8
+
+    iconst_0
+    iconst_0
+    dconst_0
+    iconst_0
+    dup2_x2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup2_x2_case3.j b/dx/tests/107-verify-stack-ops/op_dup2_x2_case3.j
new file mode 100644
index 0000000..dad31e5
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup2_x2_case3.j
@@ -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.
+
+.class op_dup2_x2_case3
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 8
+
+    dconst_0
+    iconst_0
+    dconst_0
+    dup2_x2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup_x1_case1.j b/dx/tests/107-verify-stack-ops/op_dup_x1_case1.j
new file mode 100644
index 0000000..037b0f8
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup_x1_case1.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dup_x1_case1
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    iconst_0
+    dconst_0
+    dup_x1
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup_x1_case2.j b/dx/tests/107-verify-stack-ops/op_dup_x1_case2.j
new file mode 100644
index 0000000..fa52b16
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup_x1_case2.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_dup_x1_case2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    dup_x1
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup_x2_case1.j b/dx/tests/107-verify-stack-ops/op_dup_x2_case1.j
new file mode 100644
index 0000000..7c4e89c
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup_x2_case1.j
@@ -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.
+
+.class op_dup_x2_case1
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    iconst_0
+    dup_x2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup_x2_case2.j b/dx/tests/107-verify-stack-ops/op_dup_x2_case2.j
new file mode 100644
index 0000000..c4aa545
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup_x2_case2.j
@@ -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.
+
+.class op_dup_x2_case2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    iconst_0
+    iconst_0
+    dconst_0
+    dup_x2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_dup_x2_case3.j b/dx/tests/107-verify-stack-ops/op_dup_x2_case3.j
new file mode 100644
index 0000000..f920d8c
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_dup_x2_case3.j
@@ -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.
+
+.class op_dup_x2_case3
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    iconst_0
+    dconst_0
+    dconst_0
+    dup_x2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_pop.j b/dx/tests/107-verify-stack-ops/op_pop.j
new file mode 100644
index 0000000..1b74e2c
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_pop.j
@@ -0,0 +1,25 @@
+; 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.
+
+.class op_pop
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    pop
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_pop2.j b/dx/tests/107-verify-stack-ops/op_pop2.j
new file mode 100644
index 0000000..ef2d122
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_pop2.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_pop2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    pop2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_pop2_case2.j b/dx/tests/107-verify-stack-ops/op_pop2_case2.j
new file mode 100644
index 0000000..f9d6ea3
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_pop2_case2.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_pop2_case2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    pop2
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_swap_case1.j b/dx/tests/107-verify-stack-ops/op_swap_case1.j
new file mode 100644
index 0000000..f6b4ab7
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_swap_case1.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_swap_case1
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    dconst_0
+    iconst_0
+    swap
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/op_swap_case2.j b/dx/tests/107-verify-stack-ops/op_swap_case2.j
new file mode 100644
index 0000000..6e0fcba
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/op_swap_case2.j
@@ -0,0 +1,26 @@
+; 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.
+
+.class op_swap_case2
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 2
+    .limit stack 6
+
+    iconst_0
+    dconst_0
+    swap
+    return
+.end method
diff --git a/dx/tests/107-verify-stack-ops/run b/dx/tests/107-verify-stack-ops/run
new file mode 100644
index 0000000..a55c639
--- /dev/null
+++ b/dx/tests/107-verify-stack-ops/run
@@ -0,0 +1,44 @@
+#!/bin/bash
+#
+# 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.
+
+function oneop()
+{
+    jasmin -d . op_"$1".j
+    dx --debug --dex op_"$1".class >/dev/null 2>&1
+    if [ "$?" = "0" ]; then
+        dx --debug --dex --dump-method="op_$1.test*" op_"$1".class
+    else
+        echo "$1: expected failure occurred"
+    fi
+}
+
+oneop dup
+oneop dup_x1_case1
+oneop dup_x1_case2
+oneop dup_x2_case1
+oneop dup_x2_case2
+oneop dup_x2_case3
+oneop dup2
+oneop dup2_x1_case1
+oneop dup2_x1_case2
+oneop dup2_x1_case3
+oneop dup2_x2_case1
+oneop dup2_x2_case2
+oneop dup2_x2_case3
+oneop pop
+oneop pop2
+oneop swap_case1
+oneop swap_case2
diff --git a/dx/tests/108-string-annotation/Blort.java b/dx/tests/108-string-annotation/Blort.java
new file mode 100644
index 0000000..9bb52e4
--- /dev/null
+++ b/dx/tests/108-string-annotation/Blort.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+public class Blort {
+    @Frotz(name = "grue")
+    public static void testSingle() {
+        // This space intentionally left blank.
+    }
+
+    @Fizmo(names = "gruesome")
+    public static void testArray1() {
+        // This space intentionally left blank.
+    }
+
+    @Fizmo(names = {"awful", "awesome"})
+    public static void testArray2() {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dx/tests/108-string-annotation/Fizmo.java b/dx/tests/108-string-annotation/Fizmo.java
new file mode 100644
index 0000000..a20bba0
--- /dev/null
+++ b/dx/tests/108-string-annotation/Fizmo.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+public @interface Fizmo {
+    String[] names();
+}
diff --git a/dx/tests/108-string-annotation/Frotz.java b/dx/tests/108-string-annotation/Frotz.java
new file mode 100644
index 0000000..3ad5426
--- /dev/null
+++ b/dx/tests/108-string-annotation/Frotz.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+public @interface Frotz {
+    String name();
+}
diff --git a/dx/tests/108-string-annotation/expected.txt b/dx/tests/108-string-annotation/expected.txt
new file mode 100644
index 0000000..a4c4af4
--- /dev/null
+++ b/dx/tests/108-string-annotation/expected.txt
@@ -0,0 +1,12 @@
+
+  elements[0]:
+    name
+    value: utf8 grue
+
+  elements[0]:
+    names
+    value: array {gruesome}
+
+  elements[0]:
+    names
+    value: array {awful, awesome}
diff --git a/dx/tests/108-string-annotation/info.txt b/dx/tests/108-string-annotation/info.txt
new file mode 100644
index 0000000..6c85834
--- /dev/null
+++ b/dx/tests/108-string-annotation/info.txt
@@ -0,0 +1,6 @@
+This is a smoke test of dex conversion, which checks to see that
+string annotations get represented reasonably.
+
+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/108-string-annotation/run b/dx/tests/108-string-annotation/run
new file mode 100644
index 0000000..d89053f
--- /dev/null
+++ b/dx/tests/108-string-annotation/run
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . Blort.java Fizmo.java Frotz.java
+dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-to=- *.class | cut -f 2 -d '|' | awk '
+
+BEGIN {
+    dumping = 0;
+}
+
+/annotation$/ {
+    dumping = 1;
+    printf("\n");
+    next;
+}
+
+/^[ ]*$/ {
+    dumping = 0;
+    next;
+}
+
+dumping && /^  elements/ {
+    print;
+}
+
+dumping && /^    name_idx/ {
+    printf("    %s\n", $4);
+}
+
+dumping && /^    value/ {
+    print;
+}
+'
diff --git a/dx/tests/109-int-branch/blort.j b/dx/tests/109-int-branch/blort.j
new file mode 100644
index 0000000..8517177
--- /dev/null
+++ b/dx/tests/109-int-branch/blort.j
@@ -0,0 +1,99 @@
+; 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.
+
+.class blort
+.super java/lang/Object
+
+.method public static test1(ZBCSI[I)V
+    .limit locals 6
+    .limit stack 3
+
+    iload_0
+    iload_1
+    if_icmpeq zorch
+
+    iload_2
+    iload_3
+    if_icmpne zorch
+
+    iload 4
+    aload 5
+    iconst_0
+    iaload
+    if_icmplt zorch
+
+    aload 5
+    iconst_0
+    iaload
+    iload_0
+    if_icmpgt zorch
+
+    iload 4
+    iload_1
+    if_icmpge zorch
+
+    nop
+
+zorch:
+    return
+.end method
+
+.method public static test2(I)Ljava/lang/Object;
+    .limit locals 2
+    .limit stack 3
+
+    aconst_null
+    astore 1
+
+    aload_1
+    iconst_0
+    iaload
+    iload_0
+    if_icmpge zorch
+
+    nop
+
+zorch:
+    aconst_null
+    areturn
+.end method
+
+.method public static test3(I[I)Ljava/lang/Object;
+    .limit locals 3
+    .limit stack 3
+
+    aconst_null
+    astore 2
+
+frotz:
+    aload_2
+    ifnonnull fizmo
+
+    aload_1
+    astore_2
+    goto frotz
+
+fizmo:
+    aload_2
+    iconst_0
+    iaload
+    iload_0
+    if_icmpge zorch
+
+    nop
+
+zorch:
+    aconst_null
+    areturn
+.end method
diff --git a/dx/tests/109-int-branch/expected.txt b/dx/tests/109-int-branch/expected.txt
new file mode 100644
index 0000000..223a459
--- /dev/null
+++ b/dx/tests/109-int-branch/expected.txt
@@ -0,0 +1,67 @@
+Generated: ./blort.class
+blort.test1:(ZBCSI[I)V:
+regs: 000f; ins: 0006; outs: 0000
+  0000: move v0, v9
+  0001: move v1, v10
+  0002: move v2, v11
+  0003: move v3, v12
+  0004: move v4, v13
+  0005: move-object v5, v14
+  0006: move v6, v0
+  0007: move v7, v1
+  0008: if-eq v6, v7, 0021 // +0019
+  000a: move v6, v2
+  000b: move v7, v3
+  000c: if-ne v6, v7, 0021 // +0015
+  000e: move v6, v4
+  000f: move-object v7, v5
+  0010: const/4 v8, #int 0 // #0
+  0011: aget v7, v7, v8
+  0013: if-lt v6, v7, 0021 // +000e
+  0015: move-object v6, v5
+  0016: const/4 v7, #int 0 // #0
+  0017: aget v6, v6, v7
+  0019: move v7, v0
+  001a: if-gt v6, v7, 0021 // +0007
+  001c: move v6, v4
+  001d: move v7, v1
+  001e: if-ge v6, v7, 0021 // +0003
+  0020: nop
+  0021: return-void
+  source file: "blort.j"
+blort.test2:(I)Ljava/lang/Object;:
+regs: 0005; ins: 0001; outs: 0000
+  0000: move v0, v4
+  0001: const/4 v2, #null // #0
+  0002: move-object v1, v2
+  0003: move-object v2, v1
+  0004: const/4 v3, #int 0 // #0
+  0005: aget v2, v2, v3
+  0007: move v3, v0
+  0008: if-ge v2, v3, 000b // +0003
+  000a: nop
+  000b: const/4 v2, #null // #0
+  000c: move-object v0, v2
+  000d: return-object v0
+  source file: "blort.j"
+blort.test3:(I[I)Ljava/lang/Object;:
+regs: 0007; ins: 0002; outs: 0000
+  0000: move v0, v5
+  0001: move-object v1, v6
+  0002: const/4 v3, #null // #0
+  0003: move-object v2, v3
+  0004: move-object v3, v2
+  0005: if-nez v3, 000a // +0005
+  0007: move-object v3, v1
+  0008: move-object v2, v3
+  0009: goto 0004 // -0005
+  000a: move-object v3, v2
+  000b: const/4 v4, #int 0 // #0
+  000c: aget v3, v3, v4
+  000e: move v4, v0
+  000f: if-ge v3, v4, 0012 // +0003
+  0011: nop
+  0012: const/4 v3, #null // #0
+  0013: move-object v0, v3
+  0014: return-object v0
+  source file: "blort.j"
diff --git a/dx/tests/109-int-branch/info.txt b/dx/tests/109-int-branch/info.txt
new file mode 100644
index 0000000..e650a12
--- /dev/null
+++ b/dx/tests/109-int-branch/info.txt
@@ -0,0 +1,6 @@
+This tests that an int branch with valid arguments is properly translated.
+(Regression test.)
+
+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/109-int-branch/run b/dx/tests/109-int-branch/run
new file mode 100644
index 0000000..68b17ea
--- /dev/null
+++ b/dx/tests/109-int-branch/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+jasmin -d . blort.j
+dx --debug --dex --no-optimize --dump-method="blort.test*" blort.class
diff --git a/dx/tests/110-dex-preserve-this/Blort.java b/dx/tests/110-dex-preserve-this/Blort.java
new file mode 100644
index 0000000..e2965b3
--- /dev/null
+++ b/dx/tests/110-dex-preserve-this/Blort.java
@@ -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.
+ */
+
+public class Blort {
+    public int test() {
+        Object z = "";
+        Number t = new Integer(3);
+        if (z instanceof Integer) {
+            return 3;
+        }
+        return ((Integer) t);
+    }
+}
diff --git a/dx/tests/110-dex-preserve-this/expected.txt b/dx/tests/110-dex-preserve-this/expected.txt
new file mode 100644
index 0000000..e91d4bf
--- /dev/null
+++ b/dx/tests/110-dex-preserve-this/expected.txt
@@ -0,0 +1 @@
+this: v4
diff --git a/dx/tests/110-dex-preserve-this/info.txt b/dx/tests/110-dex-preserve-this/info.txt
new file mode 100644
index 0000000..913c196
--- /dev/null
+++ b/dx/tests/110-dex-preserve-this/info.txt
@@ -0,0 +1,10 @@
+This is a smoke test of dex conversion, which checks to see that a
+"this" argument is never reused for a temporary. (Background: Popular
+debuggers will get confused if "this" is reused, and it arguably
+should be the case that the target object of an instance method being
+executed ought never be gc'ed anyway, and overwriting "this" could in
+fact cause that to happen.)
+
+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/110-dex-preserve-this/run b/dx/tests/110-dex-preserve-this/run
new file mode 100644
index 0000000..9770237
--- /dev/null
+++ b/dx/tests/110-dex-preserve-this/run
@@ -0,0 +1,41 @@
+#!/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 \
+    --dump-to=dump.txt --dump-method="Blort.test" *.class
+
+cat dump.txt | awk '
+BEGIN {
+    thisReg = "BOGUS";
+}
+# Find the number of registers; in this case the last register is "this".
+/^regs:/ {
+    regs = substr($2, 4, 1);
+    thisReg = "v" (regs - 1);
+    printf("this: %s\n", thisReg);
+}
+# Output any lines that mention the "this" register.
+{
+    count = split($0, words, /,? */);
+    for (i = 1; i <= count; i++) {
+        if (words[i] == thisReg) {
+            printf("%s\n", $0);
+            break;
+        }
+    }
+}
+'
\ No newline at end of file
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..79d2b4f
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/Blort.java
@@ -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.
+ */
+
+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/dx/tests/112-dex-return-jsr-result/blort.j b/dx/tests/112-dex-return-jsr-result/blort.j
new file mode 100644
index 0000000..6f6cddb
--- /dev/null
+++ b/dx/tests/112-dex-return-jsr-result/blort.j
@@ -0,0 +1,41 @@
+; Copyright (C) 2010 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.class blort
+.super java/lang/Object
+
+.method public static zorch(ZLjava/lang/Object;)Ljava/lang/Object;
+    .limit locals 3
+    .limit stack 1
+
+    iload_0
+    ifeq thenBlock
+    jsr subroutine
+    goto endBlock
+
+thenBlock:
+    jsr subroutine
+    goto endBlock
+
+subroutine:
+    astore_2
+    aload_1
+    invokestatic java/lang/String/valueOf(Ljava/lang/Object;)Ljava/lang/String;
+    astore_1
+    ret 2
+
+endBlock:
+    aload_1
+    areturn
+.end method
diff --git a/dx/tests/112-dex-return-jsr-result/expected.txt b/dx/tests/112-dex-return-jsr-result/expected.txt
new file mode 100644
index 0000000..0e32069
--- /dev/null
+++ b/dx/tests/112-dex-return-jsr-result/expected.txt
@@ -0,0 +1,2 @@
+Generated: ./blort.class
+total invokes: 2
diff --git a/dx/tests/112-dex-return-jsr-result/info.txt b/dx/tests/112-dex-return-jsr-result/info.txt
new file mode 100644
index 0000000..289ebb2
--- /dev/null
+++ b/dx/tests/112-dex-return-jsr-result/info.txt
@@ -0,0 +1,6 @@
+This test checks to make sure a result returned more-or-less directly
+from a jsr subroutine ends up being represented appropriately.
+
+In particular, this is a regression test for a bug which caused a
+goto instruction to be interposed between an invoke instruction and
+its associated move-result.
diff --git a/dx/tests/112-dex-return-jsr-result/run b/dx/tests/112-dex-return-jsr-result/run
new file mode 100644
index 0000000..4075d16
--- /dev/null
+++ b/dx/tests/112-dex-return-jsr-result/run
@@ -0,0 +1,63 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The awk fun here tries to cull out all but the salient bits. The aim
+# is to check to see that there are two invoke-static instructions, each
+# followed directly by a move-result-object.
+
+jasmin -d . blort.j
+dx --debug --dex --dump-to=- --dump-method=blort.zorch --dump-width=200 \
+    blort.class | awk '
+
+BEGIN {
+    invokeAt = -1;
+    moveAt = -1;
+    invokeCount = 0;
+    failed = 0;
+}
+
+# Note: This has to be done before the test clause below.
+/move-result-object/ {
+    moveAt = NR;
+}
+
+(invokeAt > 0) {
+    if (moveAt != (invokeAt + 1)) {
+        failed = 1;
+    }
+    invokeAt = -1;
+    moveAt = -1;
+}
+
+# Note: This has to be done after the test clause above.
+/invoke-static/ {
+    invokeAt = NR;
+    invokeCount++;
+}
+
+END {
+    printf("total invokes: %d\n", invokeCount);
+    if (failed) {
+        exit 1;
+    }
+}
+'
+
+if [ "$?" = "1" ]; then
+    # The test failed. Be helpful and print the entire method body.
+    dx --debug --dex --dump-to=- --dump-method=blort.zorch --dump-width=200 \
+        blort.class
+fi
diff --git a/dx/tests/113-old-style-inner-class/Blort.java b/dx/tests/113-old-style-inner-class/Blort.java
new file mode 100644
index 0000000..89b1ba0
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/Blort.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Blort {
+    public static Runnable theRunnable = new Runnable() {
+            public void run() { }
+        };
+
+    public Runnable create() {
+        return new Runnable() {
+                public void run() { }
+            };
+    }
+}
diff --git a/dx/tests/113-old-style-inner-class/expected.txt b/dx/tests/113-old-style-inner-class/expected.txt
new file mode 100644
index 0000000..d58d6db
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/expected.txt
@@ -0,0 +1,2 @@
+warning:
+warning:
diff --git a/dx/tests/113-old-style-inner-class/info.txt b/dx/tests/113-old-style-inner-class/info.txt
new file mode 100644
index 0000000..91b3aad
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/info.txt
@@ -0,0 +1,3 @@
+This is a smoke test of dex conversion, which makes sure that
+converstion of old-style anonymous inner classes (whose representation
+is information-lossy) causes a warning to be issued.
diff --git a/dx/tests/113-old-style-inner-class/run b/dx/tests/113-old-style-inner-class/run
new file mode 100644
index 0000000..c93661f
--- /dev/null
+++ b/dx/tests/113-old-style-inner-class/run
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# We compile for a 1.4 target to suppress the use of EnclosingMethod
+# attributes.
+${JAVAC} -source 1.4 -target 1.4 -d . Blort.java
+
+# We expect there to be two warning lines, one for each of the inner classes.
+dx --debug --dex *.class 2>&1 | awk '/^warning:/ { print $1 }'
diff --git a/dx/tests/114-value-propagation/blort.j b/dx/tests/114-value-propagation/blort.j
new file mode 100644
index 0000000..2cc8f5b
--- /dev/null
+++ b/dx/tests/114-value-propagation/blort.j
@@ -0,0 +1,24 @@
+; Copyright (C) 2010 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.class blort
+.super java/lang/Object
+
+.method public static test()V
+    .limit locals 1
+    .limit stack 1
+    ldc 99
+    istore_0
+    return
+.end method
diff --git a/dx/tests/114-value-propagation/expected.txt b/dx/tests/114-value-propagation/expected.txt
new file mode 100644
index 0000000..cbd17de
--- /dev/null
+++ b/dx/tests/114-value-propagation/expected.txt
@@ -0,0 +1,3 @@
+Generated: ./blort.class
+  blort.j:@0000: const-int(99) v1:I=99 <- .
+  blort.j:@0002: move-int v0:I=99 <- v1:I=99
diff --git a/dx/tests/114-value-propagation/info.txt b/dx/tests/114-value-propagation/info.txt
new file mode 100644
index 0000000..2ff498d
--- /dev/null
+++ b/dx/tests/114-value-propagation/info.txt
@@ -0,0 +1,2 @@
+Tests propagation of constant values, specifically when going from a
+stack location to a local variable. (regression test)
diff --git a/dx/tests/114-value-propagation/run b/dx/tests/114-value-propagation/run
new file mode 100644
index 0000000..7dde4d7
--- /dev/null
+++ b/dx/tests/114-value-propagation/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jasmin -d . blort.j
+dx --dump --rop-blocks blort.class | grep 'const\|move'
diff --git a/dx/tests/115-merge/com/android/dx/merge/DexMergeTest.java b/dx/tests/115-merge/com/android/dx/merge/DexMergeTest.java
new file mode 100644
index 0000000..c6ffbdc
--- /dev/null
+++ b/dx/tests/115-merge/com/android/dx/merge/DexMergeTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.io.DexBuffer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import junit.framework.TestCase;
+
+/**
+ * Test that DexMerge works by merging dex files, and then loading them into
+ * the current VM.
+ */
+public final class DexMergeTest extends TestCase {
+
+    public void testFillArrayData() throws Exception {
+        ClassLoader loader = mergeAndLoad(
+                "/testdata/Basic.dex",
+                "/testdata/FillArrayData.dex");
+
+        Class<?> basic = loader.loadClass("testdata.Basic");
+        assertEquals(1, basic.getDeclaredMethods().length);
+
+        Class<?> fillArrayData = loader.loadClass("testdata.FillArrayData");
+        assertTrue(Arrays.equals(
+                new byte[] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, -112, -23, 121 },
+                (byte[]) fillArrayData.getMethod("newByteArray").invoke(null)));
+        assertTrue(Arrays.equals(
+                new char[] { 0xFFFF, 0x4321, 0xABCD, 0, 'a', 'b', 'c' },
+                (char[]) fillArrayData.getMethod("newCharArray").invoke(null)));
+        assertTrue(Arrays.equals(
+                new long[] { 4660046610375530309L, 7540113804746346429L, -6246583658587674878L },
+                (long[]) fillArrayData.getMethod("newLongArray").invoke(null)));
+    }
+
+    public void testTryCatchFinally() throws Exception {
+        ClassLoader loader = mergeAndLoad(
+                "/testdata/Basic.dex",
+                "/testdata/TryCatchFinally.dex");
+
+        Class<?> basic = loader.loadClass("testdata.Basic");
+        assertEquals(1, basic.getDeclaredMethods().length);
+
+        Class<?> tryCatchFinally = loader.loadClass("testdata.TryCatchFinally");
+        tryCatchFinally.getDeclaredMethod("method").invoke(null);
+    }
+
+    public void testStaticValues() throws Exception {
+        ClassLoader loader = mergeAndLoad(
+                "/testdata/Basic.dex",
+                "/testdata/StaticValues.dex");
+
+        Class<?> basic = loader.loadClass("testdata.Basic");
+        assertEquals(1, basic.getDeclaredMethods().length);
+
+        Class<?> staticValues = loader.loadClass("testdata.StaticValues");
+        assertEquals((byte) 1, staticValues.getField("a").get(null));
+        assertEquals((short) 2, staticValues.getField("b").get(null));
+        assertEquals('C', staticValues.getField("c").get(null));
+        assertEquals(0xabcd1234, staticValues.getField("d").get(null));
+        assertEquals(4660046610375530309L,staticValues.getField("e").get(null));
+        assertEquals(0.5f, staticValues.getField("f").get(null));
+        assertEquals(-0.25, staticValues.getField("g").get(null));
+        assertEquals("this is a String", staticValues.getField("h").get(null));
+        assertEquals(String.class, staticValues.getField("i").get(null));
+        assertEquals("[0, 1]", Arrays.toString((int[]) staticValues.getField("j").get(null)));
+        assertEquals(null, staticValues.getField("k").get(null));
+        assertEquals(true, staticValues.getField("l").get(null));
+        assertEquals(false, staticValues.getField("m").get(null));
+    }
+
+    public void testAnnotations() throws Exception {
+        ClassLoader loader = mergeAndLoad(
+                "/testdata/Basic.dex",
+                "/testdata/Annotated.dex");
+
+        Class<?> basic = loader.loadClass("testdata.Basic");
+        assertEquals(1, basic.getDeclaredMethods().length);
+
+        Class<?> annotated = loader.loadClass("testdata.Annotated");
+        Method method = annotated.getMethod("method", String.class, String.class);
+        Field field = annotated.getField("field");
+
+        @SuppressWarnings("unchecked")
+        Class<? extends Annotation> marker
+                = (Class<? extends Annotation>) loader.loadClass("testdata.Annotated$Marker");
+
+        assertEquals("@testdata.Annotated$Marker(a=on class, b=[A, B, C], "
+                + "c=@testdata.Annotated$Nested(e=E1, f=1695938256, g=7264081114510713000), "
+                + "d=[@testdata.Annotated$Nested(e=E2, f=1695938256, g=7264081114510713000)])",
+                annotated.getAnnotation(marker).toString());
+        assertEquals("@testdata.Annotated$Marker(a=on method, b=[], "
+                + "c=@testdata.Annotated$Nested(e=, f=0, g=0), d=[])",
+                method.getAnnotation(marker).toString());
+        assertEquals("@testdata.Annotated$Marker(a=on field, b=[], "
+                + "c=@testdata.Annotated$Nested(e=, f=0, g=0), d=[])",
+                field.getAnnotation(marker).toString());
+        assertEquals("@testdata.Annotated$Marker(a=on parameter, b=[], "
+                + "c=@testdata.Annotated$Nested(e=, f=0, g=0), d=[])",
+                method.getParameterAnnotations()[1][0].toString());
+    }
+
+    /**
+     * Merging dex files uses pessimistic sizes that naturally leave gaps in the
+     * output files. If those gaps grow too large, the merger is supposed to
+     * compact the result. This exercises that by repeatedly merging a dex with
+     * itself.
+     */
+    public void testMergedOutputSizeIsBounded() throws Exception {
+        /*
+         * At the time this test was written, the output would grow ~25% with
+         * each merge. Setting a low 1KiB ceiling on the maximum size caused
+         * the file to be compacted every four merges.
+         */
+        int steps = 100;
+        int compactWasteThreshold = 1024;
+
+        DexBuffer dexA = resourceToDexBuffer("/testdata/Basic.dex");
+        DexBuffer dexB = resourceToDexBuffer("/testdata/TryCatchFinally.dex");
+        DexBuffer merged = new DexMerger(dexA, dexB, CollisionPolicy.KEEP_FIRST).merge();
+
+        int maxLength = 0;
+        for (int i = 0; i < steps; i++) {
+            DexMerger dexMerger = new DexMerger(dexA, merged, CollisionPolicy.KEEP_FIRST);
+            dexMerger.setCompactWasteThreshold(compactWasteThreshold);
+            merged = dexMerger.merge();
+            maxLength = Math.max(maxLength, merged.getLength());
+        }
+
+        int maxExpectedLength = dexA.getLength() + dexB.getLength() + compactWasteThreshold;
+        assertTrue(maxLength + " < " + maxExpectedLength, maxLength < maxExpectedLength);
+    }
+
+    public ClassLoader mergeAndLoad(String dexAResource, String dexBResource) throws Exception {
+        DexBuffer dexA = resourceToDexBuffer(dexAResource);
+        DexBuffer dexB = resourceToDexBuffer(dexBResource);
+        DexBuffer merged = new DexMerger(dexA, dexB, CollisionPolicy.KEEP_FIRST).merge();
+        File mergedDex = File.createTempFile("DexMergeTest", ".classes.dex");
+        merged.writeTo(mergedDex);
+        File mergedJar = dexToJar(mergedDex);
+        // simplify the javac classpath by not depending directly on 'dalvik.system' classes
+        return (ClassLoader) Class.forName("dalvik.system.PathClassLoader")
+                .getConstructor(String.class, ClassLoader.class)
+                .newInstance(mergedJar.getPath(), getClass().getClassLoader());
+    }
+
+    private DexBuffer resourceToDexBuffer(String resource) throws IOException {
+        return new DexBuffer(getClass().getResourceAsStream(resource));
+    }
+
+    private File dexToJar(File dex) throws IOException {
+        File result = File.createTempFile("DexMergeTest", ".jar");
+        result.deleteOnExit();
+        JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
+        jarOut.putNextEntry(new JarEntry("classes.dex"));
+        copy(new FileInputStream(dex), jarOut);
+        jarOut.closeEntry();
+        jarOut.close();
+        return result;
+    }
+
+    private void copy(InputStream in, OutputStream out) throws IOException {
+        byte[] buffer = new byte[1024];
+        int count;
+        while ((count = in.read(buffer)) != -1) {
+            out.write(buffer, 0, count);
+        }
+        in.close();
+    }
+}
diff --git a/dx/tests/115-merge/expected.txt b/dx/tests/115-merge/expected.txt
new file mode 100644
index 0000000..5418338
--- /dev/null
+++ b/dx/tests/115-merge/expected.txt
@@ -0,0 +1 @@
+Yay!
diff --git a/dx/tests/115-merge/info.txt b/dx/tests/115-merge/info.txt
new file mode 100644
index 0000000..c1fa2e4
--- /dev/null
+++ b/dx/tests/115-merge/info.txt
@@ -0,0 +1,6 @@
+Merges two dex files into one and then loads the result.
+
+Because it loads the merged dex files, this JUnit test only works on a dalvikvm.
+The run script requires vogar, so you must have vogar on your $PATH to run this
+test. You'll also need a device or host VM for vogar to attach to.
+
diff --git a/dx/tests/115-merge/run b/dx/tests/115-merge/run
new file mode 100644
index 0000000..83e5b3d
--- /dev/null
+++ b/dx/tests/115-merge/run
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# 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.
+
+# Find dx.jar from dx in the android dev tree
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+
+javac -cp $dxjar `find . -name "*.java"`
+dx --dex --output=test.jar com/android/dx/merge/* $dxjar
+
+# Build a resource .jar containing the .dex files to merge
+dx --dex --output=testdata/Annotated.dex testdata/Annotated*
+dx --dex --output=testdata/Basic.dex testdata/Basic*
+dx --dex --output=testdata/FillArrayData.dex testdata/FillArrayData*
+dx --dex --output=testdata/StaticValues.dex testdata/StaticValues*
+dx --dex --output=testdata/TryCatchFinally.dex testdata/TryCatchFinally*
+jar cfM resources.jar testdata/*.dex
+
+dalvik -classpath test.jar:resources.jar \
+  junit.textui.TestRunner com.android.dx.merge.DexMergeTest > unit-out.txt
+
+if [ "$?" = "0" ]; then
+    echo "Yay!"
+else
+    cat unit-out.txt
+fi
diff --git a/dx/tests/115-merge/testdata/Annotated.java b/dx/tests/115-merge/testdata/Annotated.java
new file mode 100644
index 0000000..2e893f2
--- /dev/null
+++ b/dx/tests/115-merge/testdata/Annotated.java
@@ -0,0 +1,31 @@
+package testdata;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Annotated.Marker(a = "on class", b = {"A", "B", "C" },
+        c = @Annotated.Nested(e="E1", f=1695938256, g=7264081114510713000L),
+        d = { @Annotated.Nested(e="E2", f=1695938256, g=7264081114510713000L) })
+public class Annotated {
+
+    @Annotated.Marker(a="on field")
+    public String field;
+
+    @Annotated.Marker(a="on method")
+    public void method(String a, @Annotated.Marker(a="on parameter") String b) {}
+
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface Marker {
+        String a() default "";
+        String[] b() default {};
+        Nested c() default @Nested;
+        Nested[] d() default {};
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface Nested {
+        String e() default "";
+        int f() default 0;
+        long g() default 0L;
+    }
+}
diff --git a/dx/tests/115-merge/testdata/Basic.java b/dx/tests/115-merge/testdata/Basic.java
new file mode 100644
index 0000000..01a1635
--- /dev/null
+++ b/dx/tests/115-merge/testdata/Basic.java
@@ -0,0 +1,10 @@
+package testdata;
+
+public class Basic {
+
+    String field = "this is a field";
+
+    String method() {
+        return "this is a method result";
+    }
+}
diff --git a/dx/tests/115-merge/testdata/FillArrayData.java b/dx/tests/115-merge/testdata/FillArrayData.java
new file mode 100644
index 0000000..0ece934
--- /dev/null
+++ b/dx/tests/115-merge/testdata/FillArrayData.java
@@ -0,0 +1,16 @@
+package testdata;
+
+public class FillArrayData {
+
+    public static byte[] newByteArray() {
+        return new byte[] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, -112, -23, 121 };
+    }
+
+    public static char[] newCharArray() {
+        return new char[] { 0xFFFF, 0x4321, 0xABCD, 0, 'a', 'b', 'c' };
+    }
+
+    public static long[] newLongArray() {
+        return new long[] { 4660046610375530309L, 7540113804746346429L, -6246583658587674878L };
+    }
+}
diff --git a/dx/tests/115-merge/testdata/StaticValues.java b/dx/tests/115-merge/testdata/StaticValues.java
new file mode 100644
index 0000000..1a8648f
--- /dev/null
+++ b/dx/tests/115-merge/testdata/StaticValues.java
@@ -0,0 +1,17 @@
+package testdata;
+
+public class StaticValues {
+    public static final byte a = 1;
+    public static final short b = 2;
+    public static final char c = 'C';
+    public static final int d = 0xabcd1234;
+    public static final long e = 4660046610375530309L;
+    public static final float f = 0.5f;
+    public static final double g = -0.25;
+    public static final String h = "this is a String";
+    public static final Class<?> i = String.class;
+    public static final int[] j = { 0, 1 };
+    public static final String k = null;
+    public static final boolean l = true;
+    public static final boolean m = false;
+}
diff --git a/dx/tests/115-merge/testdata/TryCatchFinally.java b/dx/tests/115-merge/testdata/TryCatchFinally.java
new file mode 100644
index 0000000..4f3769e
--- /dev/null
+++ b/dx/tests/115-merge/testdata/TryCatchFinally.java
@@ -0,0 +1,26 @@
+package testdata;
+
+public class TryCatchFinally {
+
+    public static void method() {
+        int count = 0;
+        try {
+            if (true) {
+                throw new NullPointerException();
+            }
+            throw new AssertionError();
+        } catch (IllegalStateException e) {
+            throw new AssertionError();
+        } catch (NullPointerException expected) {
+            count++;
+        } catch (RuntimeException e) {
+            throw new AssertionError();
+        } finally {
+            count++;
+        }
+
+        if (count != 2) {
+            throw new AssertionError();
+        }
+    }
+}
diff --git a/dx/tests/116-leb128/com/android/dx/util/Leb128UtilsTest.java b/dx/tests/116-leb128/com/android/dx/util/Leb128UtilsTest.java
new file mode 100644
index 0000000..dbc0ea3
--- /dev/null
+++ b/dx/tests/116-leb128/com/android/dx/util/Leb128UtilsTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.IOException;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+public final class Leb128UtilsTest extends TestCase {
+
+    public void testDecodeUnsignedLeb() throws IOException {
+        assertEquals(0, Leb128Utils.readUnsignedLeb128(new ByteArrayByteInput((byte) 0)));
+        assertEquals(1, Leb128Utils.readUnsignedLeb128(new ByteArrayByteInput((byte) 1)));
+        assertEquals(127, Leb128Utils.readUnsignedLeb128(new ByteArrayByteInput((byte) 0x7f)));
+        assertEquals(16256, Leb128Utils.readUnsignedLeb128(
+                new ByteArrayByteInput((byte) 0x80, (byte) 0x7f)));
+    }
+
+    public void testEncodeUnsignedLeb() throws IOException {
+        assertEquals(new byte[] { 0 }, encodeUnsignedLeb(0));
+        assertEquals(new byte[] { 1 }, encodeUnsignedLeb(1));
+        assertEquals(new byte[] { 0x7f }, encodeUnsignedLeb(127));
+        assertEquals(new byte[] { (byte) 0x80, 0x7f }, encodeUnsignedLeb(16256));
+        assertEquals(new byte[] { (byte) 0xb4, 0x07 }, encodeUnsignedLeb(0x3b4));
+        assertEquals(new byte[] { (byte) 0x8c, 0x08 }, encodeUnsignedLeb(0x40c));
+        assertEquals(new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0xf },
+                encodeUnsignedLeb(0xffffffff));
+    }
+
+    public void testDecodeSignedLeb() throws IOException {
+        assertEquals(0, Leb128Utils.readSignedLeb128(new ByteArrayByteInput((byte) 0)));
+        assertEquals(1, Leb128Utils.readSignedLeb128(new ByteArrayByteInput((byte) 1)));
+        assertEquals(-1, Leb128Utils.readSignedLeb128(new ByteArrayByteInput((byte) 0x7f)));
+        assertEquals(0x3c, Leb128Utils.readSignedLeb128(new ByteArrayByteInput((byte) 0x3c)));
+        assertEquals(-128, Leb128Utils.readSignedLeb128(
+                new ByteArrayByteInput((byte) 0x80, (byte) 0x7f)));
+    }
+
+    public void testEncodeSignedLeb() throws IOException {
+        assertEquals(new byte[] { 0 }, encodeSignedLeb(0));
+        assertEquals(new byte[] { 1 }, encodeSignedLeb(1));
+        assertEquals(new byte[] { 0x7f }, encodeSignedLeb(-1));
+        assertEquals(new byte[] { (byte) 0x80, 0x7f }, encodeSignedLeb(-128));
+    }
+
+    private byte[] encodeSignedLeb(int value) {
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(5);
+        Leb128Utils.writeSignedLeb128(out, value);
+        return out.toByteArray();
+    }
+
+    private byte[] encodeUnsignedLeb(int value) {
+        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(5);
+        Leb128Utils.writeUnsignedLeb128(out, value);
+        return out.toByteArray();
+    }
+
+    private void assertEquals(byte[] expected, byte[] actual) {
+        assertTrue(Arrays.toString(actual), Arrays.equals(expected, actual));
+    }
+}
diff --git a/dx/tests/116-leb128/expected.txt b/dx/tests/116-leb128/expected.txt
new file mode 100644
index 0000000..5418338
--- /dev/null
+++ b/dx/tests/116-leb128/expected.txt
@@ -0,0 +1 @@
+Yay!
diff --git a/dx/tests/116-leb128/info.txt b/dx/tests/116-leb128/info.txt
new file mode 100644
index 0000000..1603ec3
--- /dev/null
+++ b/dx/tests/116-leb128/info.txt
@@ -0,0 +1,5 @@
+Performs little endian operations.
+
+The run script requires vogar, so you must have vogar on your $PATH to run this
+test. You'll also need a device or host VM for vogar to attach to.
+
diff --git a/dx/tests/116-leb128/run b/dx/tests/116-leb128/run
new file mode 100644
index 0000000..5f36cd9
--- /dev/null
+++ b/dx/tests/116-leb128/run
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+# 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.
+
+# Find dx.jar from dx in the android dev tree
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+
+javac -cp $dxjar `find . -name "*.java"`
+java -classpath $dxjar:. junit.textui.TestRunner com.android.dx.util.Leb128UtilsTest > unit-out.txt
+
+if [ "$?" = "0" ]; then
+    echo "Yay!"
+else
+    cat unit-out.txt
+fi
diff --git a/dx/tests/117-modified-utf8/com/android/dx/util/Mutf8Test.java b/dx/tests/117-modified-utf8/com/android/dx/util/Mutf8Test.java
new file mode 100644
index 0000000..8e6188d
--- /dev/null
+++ b/dx/tests/117-modified-utf8/com/android/dx/util/Mutf8Test.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.util;
+
+import java.io.IOException;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+public final class Mutf8Test extends TestCase {
+
+    public void testDecode() throws IOException {
+        ByteInput in = new ByteArrayByteInput(
+                new byte[] { 'A', 'B', 'C', (byte) 0xc0, (byte) 0x80, 0, 'E' });
+        assertEquals('A', in.readByte());
+        assertEquals("BC\u0000", Mutf8.decode(in, new char[3]));
+        assertEquals('E', in.readByte());
+    }
+
+    public void testEncode() throws IOException {
+        assertEquals(Arrays.toString(new byte[] { 'B', 'C', (byte) 0xc0, (byte) 0x80 }),
+                Arrays.toString(Mutf8.encode("BC\u0000")));
+    }
+}
diff --git a/dx/tests/117-modified-utf8/expected.txt b/dx/tests/117-modified-utf8/expected.txt
new file mode 100644
index 0000000..5418338
--- /dev/null
+++ b/dx/tests/117-modified-utf8/expected.txt
@@ -0,0 +1 @@
+Yay!
diff --git a/dx/tests/117-modified-utf8/info.txt b/dx/tests/117-modified-utf8/info.txt
new file mode 100644
index 0000000..df11d98
--- /dev/null
+++ b/dx/tests/117-modified-utf8/info.txt
@@ -0,0 +1,5 @@
+Performs modified UTF-8 operations.
+
+The run script requires vogar, so you must have vogar on your $PATH to run this
+test. You'll also need a device or host VM for vogar to attach to.
+
diff --git a/dx/tests/117-modified-utf8/run b/dx/tests/117-modified-utf8/run
new file mode 100644
index 0000000..a4c202e
--- /dev/null
+++ b/dx/tests/117-modified-utf8/run
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+# 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.
+
+# Find dx.jar from dx in the android dev tree
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+
+javac -cp $dxjar `find . -name "*.java"`
+java -classpath $dxjar:. junit.textui.TestRunner com.android.dx.util.Mutf8Test > unit-out.txt
+
+if [ "$?" = "0" ]; then
+    echo "Yay!"
+else
+    cat unit-out.txt
+fi
diff --git a/dx/tests/118-find-usages/Foo.java b/dx/tests/118-find-usages/Foo.java
new file mode 100644
index 0000000..d5dc0bd
--- /dev/null
+++ b/dx/tests/118-find-usages/Foo.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 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.Reader;
+import java.io.StreamTokenizer;
+import java.util.AbstractList;
+import java.util.ArrayList;
+
+public final class Foo {
+
+    public void writeStreamTokenizerNval() {
+        new StreamTokenizer((Reader) null).nval = 5;
+    }
+
+    public double readStreamTokenizerNval() {
+        return new StreamTokenizer((Reader) null).nval;
+    }
+
+    public void callStringValueOf() {
+        String.valueOf(5);
+    }
+
+    public void callIntegerValueOf() {
+        Integer.valueOf("5");
+    }
+
+    public void callArrayListRemoveIndex() {
+        new ArrayList<String>().remove(5);
+    }
+
+    public void callArrayListRemoveValue() {
+        new ArrayList<String>().remove("5");
+    }
+
+    static class MyList<T> extends AbstractList<T> {
+        @Override public T get(int index) {
+            return null;
+        }
+        @Override public int size() {
+            return 0;
+        }
+        @Override public boolean remove(Object o) {
+            return false;
+        }
+    }
+}
diff --git a/dx/tests/118-find-usages/expected.txt b/dx/tests/118-find-usages/expected.txt
new file mode 100644
index 0000000..aca2bf1
--- /dev/null
+++ b/dx/tests/118-find-usages/expected.txt
@@ -0,0 +1,9 @@
+StreamTokenizer.nval
+LFoo;.readStreamTokenizerNval: field reference (iget-wide)
+LFoo;.writeStreamTokenizerNval: field reference (iput-wide)
+ArrayList.remove()
+LFoo;.callArrayListRemoveIndex: method reference (invoke-virtual)
+LFoo;.callArrayListRemoveValue: method reference (invoke-virtual)
+Collection.remove()
+String.valueOf()
+LFoo;.callStringValueOf: method reference (invoke-static)
diff --git a/dx/tests/118-find-usages/info.txt b/dx/tests/118-find-usages/info.txt
new file mode 100644
index 0000000..2a4e8a6
--- /dev/null
+++ b/dx/tests/118-find-usages/info.txt
@@ -0,0 +1,3 @@
+Creates a .dex file and runs find usages on it to find references and declarations.
+
+The expected output assumes this bug has not yet been fixed: http://b/3366285
\ No newline at end of file
diff --git a/dx/tests/118-find-usages/run b/dx/tests/118-find-usages/run
new file mode 100644
index 0000000..22f38cc
--- /dev/null
+++ b/dx/tests/118-find-usages/run
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright (C) 2011 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 -d . *.java
+dx --output=foo.dex --dex *.class
+
+echo "StreamTokenizer.nval"
+dx --find-usages foo.dex "Ljava/io/StreamTokenizer;" nval
+
+echo "ArrayList.remove()"
+dx --find-usages foo.dex "Ljava/util/ArrayList;" remove
+
+echo "Collection.remove()"
+dx --find-usages foo.dex "Ljava/util/Collection;" remove
+
+echo "String.valueOf()"
+dx --find-usages foo.dex "Ljava/lang/String;" valueOf
diff --git a/dx/tests/119-merge-conflict/com/android/dx/merge/MergeConflictTest.java b/dx/tests/119-merge-conflict/com/android/dx/merge/MergeConflictTest.java
new file mode 100644
index 0000000..421d332
--- /dev/null
+++ b/dx/tests/119-merge-conflict/com/android/dx/merge/MergeConflictTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.merge;
+
+import com.android.dx.io.DexBuffer;
+import com.android.dx.util.DexException;
+import java.io.IOException;
+import junit.framework.TestCase;
+
+public final class MergeConflictTest extends TestCase {
+
+    public void testMergeConflict() throws IOException {
+        DexBuffer a = resourceToDexBuffer("/testdata/A.dex");
+        DexBuffer b = resourceToDexBuffer("/testdata/B.dex");
+
+        // a and b don't overlap; this should succeed
+        DexBuffer ab = new DexMerger(a, b, CollisionPolicy.FAIL).merge();
+
+        // a and ab overlap; this should fail
+        DexMerger dexMerger = new DexMerger(a, ab, CollisionPolicy.FAIL);
+        try {
+            dexMerger.merge();
+            fail();
+        } catch (DexException expected) {
+            assertEquals("Multiple dex files define Ltestdata/A;", expected.getMessage());
+        }
+    }
+
+    private DexBuffer resourceToDexBuffer(String resource) throws IOException {
+        return new DexBuffer(getClass().getResourceAsStream(resource));
+    }
+}
diff --git a/dx/tests/119-merge-conflict/expected.txt b/dx/tests/119-merge-conflict/expected.txt
new file mode 100644
index 0000000..5418338
--- /dev/null
+++ b/dx/tests/119-merge-conflict/expected.txt
@@ -0,0 +1 @@
+Yay!
diff --git a/dx/tests/119-merge-conflict/info.txt b/dx/tests/119-merge-conflict/info.txt
new file mode 100644
index 0000000..012187a
--- /dev/null
+++ b/dx/tests/119-merge-conflict/info.txt
@@ -0,0 +1,5 @@
+Merges dex files with and without conflicts.
+
+The run script requires vogar, so you must have vogar on your $PATH to run this
+test. You'll also need a device or host VM for vogar to attach to.
+
diff --git a/dx/tests/119-merge-conflict/run b/dx/tests/119-merge-conflict/run
new file mode 100644
index 0000000..28c152d
--- /dev/null
+++ b/dx/tests/119-merge-conflict/run
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Copyright (C) 2011 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.
+
+# Find dx.jar from dx in the android dev tree
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+
+javac -cp $dxjar `find . -name "*.java"`
+dx --dex --output=test.jar com/android/dx/merge/* $dxjar
+
+# Build a resource .jar containing the .dex files to merge
+dx --dex --output=testdata/A.dex testdata/A.class
+dx --dex --output=testdata/B.dex testdata/B.class
+jar cfM resources.jar testdata/*.dex
+
+dalvik -classpath test.jar:resources.jar \
+  junit.textui.TestRunner com.android.dx.merge.MergeConflictTest > unit-out.txt
+
+if [ "$?" = "0" ]; then
+    echo "Yay!"
+else
+    cat unit-out.txt
+fi
+
+
diff --git a/dx/tests/119-merge-conflict/testdata/A.java b/dx/tests/119-merge-conflict/testdata/A.java
new file mode 100644
index 0000000..8ff8341
--- /dev/null
+++ b/dx/tests/119-merge-conflict/testdata/A.java
@@ -0,0 +1,7 @@
+package testdata;
+
+public class A {
+    String hello() {
+        return "hello from A";
+    }
+}
diff --git a/dx/tests/119-merge-conflict/testdata/B.java b/dx/tests/119-merge-conflict/testdata/B.java
new file mode 100644
index 0000000..cadd96f
--- /dev/null
+++ b/dx/tests/119-merge-conflict/testdata/B.java
@@ -0,0 +1,7 @@
+package testdata;
+
+public class B {
+    public static void main(String[] args) {
+        System.out.println(new A().hello());
+    }
+}
diff --git a/dx/tests/120-disable-extended-ops/Blort.java b/dx/tests/120-disable-extended-ops/Blort.java
new file mode 100644
index 0000000..a1cfa36
--- /dev/null
+++ b/dx/tests/120-disable-extended-ops/Blort.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 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
+{
+    private int field0 = 0;
+    private int field1 = 1;
+    private int field2 = 2;
+    private int field3 = 3;
+    private int field4 = 4;
+    private int field5 = 5;
+    private int field6 = 6;
+    private int field7 = 7;
+    private int field8 = 8;
+    private int field9 = 9;
+
+    public void test() {
+        int v0 = field0;
+        int v1 = field1;
+        int v2 = field2;
+        int v3 = field3;
+        int v4 = field4;
+        int v5 = field5;
+        int v6 = field6;
+        int v7 = field7;
+        int v8 = field8;
+        int v9 = field9;
+        int v10 = field0;
+        int v11 = field1;
+        int v12 = field2;
+        int v13 = field3;
+        int v14 = field4;
+        int v15 = field5;
+        int v16 = field6;
+        int v17 = field7;
+        int v18 = field8;
+        int v19 = field9;
+
+        sink(v0);
+        sink(v1);
+        sink(v2);
+        sink(v3);
+        sink(v4);
+        sink(v5);
+        sink(v6);
+        sink(v7);
+        sink(v8);
+        sink(v9);
+        sink(v10);
+        sink(v11);
+        sink(v12);
+        sink(v13);
+        sink(v14);
+        sink(v15);
+        sink(v16);
+        sink(v17);
+        sink(v18);
+        sink(v19);
+    }
+
+    private static void sink(int arg) {
+        // This space intentionally left blank.
+    }
+}
diff --git a/dx/tests/120-disable-extended-ops/expected.txt b/dx/tests/120-disable-extended-ops/expected.txt
new file mode 100644
index 0000000..a965a70
--- /dev/null
+++ b/dx/tests/120-disable-extended-ops/expected.txt
@@ -0,0 +1 @@
+Done
diff --git a/dx/tests/120-disable-extended-ops/info.txt b/dx/tests/120-disable-extended-ops/info.txt
new file mode 100644
index 0000000..213c29c
--- /dev/null
+++ b/dx/tests/120-disable-extended-ops/info.txt
@@ -0,0 +1,3 @@
+This is a test of the dx option --target-api, which is supposed to
+disable the emission of extended-opcode instructions when the target
+API is for Honeycomb or earlier.
diff --git a/dx/tests/120-disable-extended-ops/run b/dx/tests/120-disable-extended-ops/run
new file mode 100644
index 0000000..c0116c8
--- /dev/null
+++ b/dx/tests/120-disable-extended-ops/run
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This test checks to see that without --target-api=11, the result of
+# dx contains at least one "iget/jumbo" opcode (one example of an
+# extended opcode); and that with that option no such opcode is
+# produced.
+
+$JAVAC -d . *.java
+
+count=`dx --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-method=Blort.test Blort.class | grep "iget/jumbo" | wc -l`
+if [ "$count" = "0" ]; then
+    echo "No iget/jumbo emitted without --target-api"
+fi
+
+count=`dx --debug --dex --no-optimize --positions=none --no-locals \
+    --target-api=11 \
+    --dump-method=Blort.test Blort.class | grep "iget/jumbo" | wc -l`
+if [ "$count" != "0" ]; then
+    echo "Found $count iget/jumbo emitted with --target-api=11"
+fi
+
+echo "Done"
diff --git a/dx/tests/121-sccp/Blort.java b/dx/tests/121-sccp/Blort.java
new file mode 100644
index 0000000..31e7d8e
--- /dev/null
+++ b/dx/tests/121-sccp/Blort.java
@@ -0,0 +1,164 @@
+class Blort {
+
+    // Test integers
+    public static int testIntAddSub() {
+        int a, b, c, d;
+        a = 3;
+        b = 5 - a;
+        while (true) {
+            c = a + b;
+            d = 5;
+            a = d - b;
+            if (c <= d) {
+                c = d + 1;
+            } else {
+                return c;
+            }
+            b = 2;
+        }
+    }
+
+    public static int testIntMult() {
+        int a = 6;
+        int b = 9 - a;
+        int c = b * 4;
+
+        if (c > 10) {
+            c = c - 10;
+        }
+        return c * 2;
+    }
+
+    public static int testIntDiv() {
+        int a = 30;
+        int b = 9 - a / 5;
+        int c = b * 4;
+
+        if (c > 10) {
+            c = c - 10;
+        }
+        return c * (60 / a);
+    }
+
+    public static int testIntMod() {
+        int a = 5;
+        int b = a % 3;
+        int c = a % 0;
+        return b + c;
+    }
+
+    public static int testIntPhi() {
+        int a = 37;
+        int b = 3;
+        int c = (b == 0) ? 0 : (a / b);
+        return c;
+    }
+
+    // Test floats
+    public static float testFloatAddSub() {
+        float a, b, c, d;
+        a = 3;
+        b = 5 - a;
+        while (true) {
+            c = a + b;
+            d = 5;
+            a = d - b;
+            if (c <= d) {
+                c = d + 1;
+            } else {
+                return c;
+            }
+            b = 2;
+        }
+    }
+
+    public static float testFloatMult() {
+        float a = 6;
+        float b = 9 - a;
+        float c = b * 4;
+
+        if (c > 10) {
+            c = c - 10;
+        }
+        return c * 2;
+    }
+
+    public static float testFloatDiv() {
+        float a = 30;
+        float b = 9 - a / 5;
+        float c = b * 4;
+
+        if (c > 10) {
+            c = c - 10;
+        }
+        return c * (60 / a);
+    }
+
+    public static float testFloatMod() {
+        float a = 5;
+        float b = a % 3;
+        float c = a % 0;
+        return b + c;
+    }
+
+    public static float testFloatPhi() {
+        float a = 37;
+        float b = 3;
+        float c = (b == 0) ? 0 : (a / b);
+        return c;
+    }
+
+    // Test doubles
+    public static double testDoubleAddSub() {
+        double a, b, c, d;
+        a = 3;
+        b = 5 - a;
+        while (true) {
+            c = a + b;
+            d = 5;
+            a = d - b;
+            if (c <= d) {
+                c = d + 1;
+            } else {
+                return c;
+            }
+            b = 2;
+        }
+    }
+
+    public static double testDoubleMult() {
+        double a = 6;
+        double b = 9 - a;
+        double c = b * 4;
+
+        if (c > 10) {
+            c = c - 10;
+        }
+        return c * 2;
+    }
+
+    public static double testDoubleDiv() {
+        double a = 30;
+        double b = 9 - a / 5;
+        double c = b * 4;
+
+        if (c > 10) {
+            c = c - 10;
+        }
+        return c * (60 / a);
+    }
+
+    public static double testDoubleMod() {
+        double a = 5;
+        double b = a % 3;
+        double c = a % 0;
+        return b + c;
+    }
+
+    public static double testDoublePhi() {
+        double a = 37;
+        double b = 3;
+        double c = (b == 0) ? 0 : (a / b);
+        return c;
+    }
+}
diff --git a/dx/tests/121-sccp/expected.txt b/dx/tests/121-sccp/expected.txt
new file mode 100644
index 0000000..afc02c7
--- /dev/null
+++ b/dx/tests/121-sccp/expected.txt
@@ -0,0 +1,715 @@
+Blort.testDoubleAddSub:()D:
+regs: 0008; ins: 0000; outs: 0000
+  0000: const-wide/high16 v6, #double 5.0 // #4014000000000000
+  0002: const-wide/high16 v2, #double 3.0 // #4008000000000000
+  0004: sub-double v0, v6, v2
+  0006: add-double v4, v2, v0
+  0008: sub-double v2, v6, v0
+  000a: cmpg-double v0, v4, v6
+  000c: if-gtz v0, 0014 // +0008
+  000e: const-wide/high16 v0, #double 1.0 // #3ff0000000000000
+  0010: add-double/2addr v0, v6
+  0011: const-wide/high16 v0, #double 2.0 // #4000000000000000
+  0013: goto 0006 // -000d
+  0014: return-wide v4
+  debug info
+    line_start: 114
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 114
+    0004: line 115
+    0006: line 117
+    0008: line 119
+    000a: line 120
+    000e: line 121
+    0011: line 125
+    0014: line 123
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleDiv:()D:
+regs: 0008; ins: 0000; outs: 0000
+  0000: const-wide/high16 v6, #double 10.0 // #4024000000000000
+  0002: const-wide/high16 v2, #double 30.0 // #403e000000000000
+  0004: const-wide/high16 v0, #double 9.0 // #4022000000000000
+  0006: const-wide/high16 v4, #double 5.0 // #4014000000000000
+  0008: div-double v4, v2, v4
+  000a: sub-double/2addr v0, v4
+  000b: const-wide/high16 v4, #double 4.0 // #4010000000000000
+  000d: mul-double/2addr v0, v4
+  000e: cmpl-double v4, v0, v6
+  0010: if-lez v4, 0013 // +0003
+  0012: sub-double/2addr v0, v6
+  0013: const-wide/high16 v4, #double 60.0 // #404e000000000000
+  0015: div-double v2, v4, v2
+  0017: mul-double/2addr v0, v2
+  0018: return-wide v0
+  debug info
+    line_start: 141
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 141
+    0004: line 142
+    000b: line 143
+    000e: line 145
+    0012: line 146
+    0013: line 148
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleMod:()D:
+regs: 0006; ins: 0000; outs: 0000
+  0000: const-wide/high16 v0, #double 5.0 // #4014000000000000
+  0002: const-wide/high16 v2, #double 3.0 // #4008000000000000
+  0004: rem-double v2, v0, v2
+  0006: const-wide/16 v4, #double 0.0 // #0000
+  0008: rem-double/2addr v0, v4
+  0009: add-double/2addr v0, v2
+  000a: return-wide v0
+  debug info
+    line_start: 152
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 152
+    0002: line 153
+    0006: line 154
+    0009: line 155
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleMult:()D:
+regs: 0006; ins: 0000; outs: 0000
+  0000: const-wide/high16 v4, #double 10.0 // #4024000000000000
+  0002: const-wide/high16 v0, #double 6.0 // #4018000000000000
+  0004: const-wide/high16 v2, #double 9.0 // #4022000000000000
+  0006: sub-double v0, v2, v0
+  0008: const-wide/high16 v2, #double 4.0 // #4010000000000000
+  000a: mul-double/2addr v0, v2
+  000b: cmpl-double v2, v0, v4
+  000d: if-lez v2, 0010 // +0003
+  000f: sub-double/2addr v0, v4
+  0010: const-wide/high16 v2, #double 2.0 // #4000000000000000
+  0012: mul-double/2addr v0, v2
+  0013: return-wide v0
+  debug info
+    line_start: 130
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 130
+    0004: line 131
+    0008: line 132
+    000b: line 134
+    000f: line 135
+    0010: line 137
+    end sequence
+  source file: "Blort.java"
+Blort.testDoublePhi:()D:
+regs: 0007; ins: 0000; outs: 0000
+  0000: const-wide/16 v0, #double 0.0 // #0000
+  0002: const-wide v2, #double 37.0 // #4042800000000000
+  0007: const-wide/high16 v4, #double 3.0 // #4008000000000000
+  0009: cmpl-double v6, v4, v0
+  000b: if-nez v6, 000e // +0003
+  000d: return-wide v0
+  000e: div-double v0, v2, v4
+  0010: goto 000d // -0003
+  debug info
+    line_start: 159
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 159
+    0007: line 160
+    0009: line 161
+    000d: line 162
+    000e: line 161
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatAddSub:()F:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/high16 v3, #float 5.0 // #40a00000
+  0002: const/high16 v1, #float 3.0 // #40400000
+  0004: sub-float v0, v3, v1
+  0006: add-float v2, v1, v0
+  0008: sub-float v1, v3, v0
+  000a: cmpg-float v0, v2, v3
+  000c: if-gtz v0, 0014 // +0008
+  000e: const/high16 v0, #float 1.0 // #3f800000
+  0010: add-float/2addr v0, v3
+  0011: const/high16 v0, #float 2.0 // #40000000
+  0013: goto 0006 // -000d
+  0014: return v2
+  debug info
+    line_start: 60
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 60
+    0004: line 61
+    0006: line 63
+    0008: line 65
+    000a: line 66
+    000e: line 67
+    0011: line 71
+    0014: line 69
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatDiv:()F:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/high16 v3, #float 10.0 // #41200000
+  0002: const/high16 v1, #float 30.0 // #41f00000
+  0004: const/high16 v0, #float 9.0 // #41100000
+  0006: const/high16 v2, #float 5.0 // #40a00000
+  0008: div-float v2, v1, v2
+  000a: sub-float/2addr v0, v2
+  000b: const/high16 v2, #float 4.0 // #40800000
+  000d: mul-float/2addr v0, v2
+  000e: cmpl-float v2, v0, v3
+  0010: if-lez v2, 0013 // +0003
+  0012: sub-float/2addr v0, v3
+  0013: const/high16 v2, #float 60.0 // #42700000
+  0015: div-float v1, v2, v1
+  0017: mul-float/2addr v0, v1
+  0018: return v0
+  debug info
+    line_start: 87
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 87
+    0004: line 88
+    000b: line 89
+    000e: line 91
+    0012: line 92
+    0013: line 94
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatMod:()F:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/high16 v0, #float 5.0 // #40a00000
+  0002: const/high16 v1, #float 3.0 // #40400000
+  0004: rem-float v1, v0, v1
+  0006: const/4 v2, #float 0.0 // #0
+  0007: rem-float/2addr v0, v2
+  0008: add-float/2addr v0, v1
+  0009: return v0
+  debug info
+    line_start: 98
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 98
+    0002: line 99
+    0006: line 100
+    0008: line 101
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatMult:()F:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/high16 v2, #float 10.0 // #41200000
+  0002: const/high16 v0, #float 6.0 // #40c00000
+  0004: const/high16 v1, #float 9.0 // #41100000
+  0006: sub-float v0, v1, v0
+  0008: const/high16 v1, #float 4.0 // #40800000
+  000a: mul-float/2addr v0, v1
+  000b: cmpl-float v1, v0, v2
+  000d: if-lez v1, 0010 // +0003
+  000f: sub-float/2addr v0, v2
+  0010: const/high16 v1, #float 2.0 // #40000000
+  0012: mul-float/2addr v0, v1
+  0013: return v0
+  debug info
+    line_start: 76
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 76
+    0004: line 77
+    0008: line 78
+    000b: line 80
+    000f: line 81
+    0010: line 83
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatPhi:()F:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v0, #float 0.0 // #0
+  0001: const/high16 v1, #float 37.0 // #42140000
+  0003: const/high16 v2, #float 3.0 // #40400000
+  0005: cmpl-float v3, v2, v0
+  0007: if-nez v3, 000a // +0003
+  0009: return v0
+  000a: div-float v0, v1, v2
+  000c: goto 0009 // -0003
+  debug info
+    line_start: 105
+    parameters_size: 0000
+    0000: prologue end
+    0001: line 105
+    0003: line 106
+    0005: line 107
+    0009: line 108
+    000a: line 107
+    end sequence
+  source file: "Blort.java"
+Blort.testIntAddSub:()I:
+regs: 0000; ins: 0000; outs: 0000
+  0000: goto/32 0000 // +0000
+  debug info
+    line_start: 17
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 17
+    end sequence
+  source file: "Blort.java"
+Blort.testIntDiv:()I:
+regs: 0001; ins: 0000; outs: 0000
+  0000: const/4 v0, #int 4 // #4
+  0001: return v0
+  debug info
+    line_start: 40
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 40
+    end sequence
+  source file: "Blort.java"
+Blort.testIntMod:()I:
+regs: 0001; ins: 0000; outs: 0000
+  0000: const/4 v0, #int 5 // #5
+  0001: rem-int/lit8 v0, v0, #int 0 // #00
+  0003: add-int/lit8 v0, v0, #int 2 // #02
+  0005: return v0
+  debug info
+    line_start: 44
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 44
+    0001: line 46
+    0003: line 47
+    end sequence
+  source file: "Blort.java"
+Blort.testIntMult:()I:
+regs: 0001; ins: 0000; outs: 0000
+  0000: const/4 v0, #int 4 // #4
+  0001: return v0
+  debug info
+    line_start: 29
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 29
+    end sequence
+  source file: "Blort.java"
+Blort.testIntPhi:()I:
+regs: 0001; ins: 0000; outs: 0000
+  0000: const/16 v0, #int 12 // #000c
+  0002: return v0
+  debug info
+    line_start: 53
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 53
+    0002: line 54
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleAddSub:()D:
+regs: 000a; ins: 0000; outs: 0000
+  0000: const-wide/high16 v0, #double 3.0 // #4008000000000000
+  0002: const-wide/high16 v8, #double 5.0 // #4014000000000000
+  0004: sub-double v2, v8, v0
+  0006: add-double v4, v0, v2
+  0008: const-wide/high16 v6, #double 5.0 // #4014000000000000
+  000a: sub-double v0, v6, v2
+  000c: cmpg-double v8, v4, v6
+  000e: if-gtz v8, 0017 // +0009
+  0010: const-wide/high16 v8, #double 1.0 // #3ff0000000000000
+  0012: add-double v4, v6, v8
+  0014: const-wide/high16 v2, #double 2.0 // #4000000000000000
+  0016: goto 0006 // -0010
+  0017: return-wide v4
+  debug info
+    line_start: 114
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 114
+    0002: line 115
+    0002: +local v0 a double
+    0006: line 117
+    0006: +local v2 b double
+    0008: line 118
+    0008: +local v4 c double
+    000a: line 119
+    000a: +local v6 d double
+    000c: line 120
+    0010: line 121
+    0014: line 125
+    0017: line 123
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleDiv:()D:
+regs: 000c; ins: 0000; outs: 0000
+  0000: const-wide/high16 v10, #double 10.0 // #4024000000000000
+  0002: const-wide/high16 v0, #double 30.0 // #403e000000000000
+  0004: const-wide/high16 v6, #double 9.0 // #4022000000000000
+  0006: const-wide/high16 v8, #double 5.0 // #4014000000000000
+  0008: div-double v8, v0, v8
+  000a: sub-double v2, v6, v8
+  000c: const-wide/high16 v6, #double 4.0 // #4010000000000000
+  000e: mul-double v4, v2, v6
+  0010: cmpl-double v6, v4, v10
+  0012: if-lez v6, 0015 // +0003
+  0014: sub-double/2addr v4, v10
+  0015: const-wide/high16 v6, #double 60.0 // #404e000000000000
+  0017: div-double/2addr v6, v0
+  0018: mul-double/2addr v6, v4
+  0019: return-wide v6
+  debug info
+    line_start: 141
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 141
+    0004: line 142
+    0004: +local v0 a double
+    000c: line 143
+    000c: +local v2 b double
+    0010: line 145
+    0010: +local v4 c double
+    0014: line 146
+    0015: line 148
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleMod:()D:
+regs: 0008; ins: 0000; outs: 0000
+  0000: const-wide/high16 v0, #double 5.0 // #4014000000000000
+  0002: const-wide/high16 v6, #double 3.0 // #4008000000000000
+  0004: rem-double v2, v0, v6
+  0006: const-wide/16 v6, #double 0.0 // #0000
+  0008: rem-double v4, v0, v6
+  000a: add-double v6, v2, v4
+  000c: return-wide v6
+  debug info
+    line_start: 152
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 152
+    0002: line 153
+    0002: +local v0 a double
+    0006: line 154
+    0006: +local v2 b double
+    000a: line 155
+    000a: +local v4 c double
+    end sequence
+  source file: "Blort.java"
+Blort.testDoubleMult:()D:
+regs: 000a; ins: 0000; outs: 0000
+  0000: const-wide/high16 v8, #double 10.0 // #4024000000000000
+  0002: const-wide/high16 v0, #double 6.0 // #4018000000000000
+  0004: const-wide/high16 v6, #double 9.0 // #4022000000000000
+  0006: sub-double v2, v6, v0
+  0008: const-wide/high16 v6, #double 4.0 // #4010000000000000
+  000a: mul-double v4, v2, v6
+  000c: cmpl-double v6, v4, v8
+  000e: if-lez v6, 0011 // +0003
+  0010: sub-double/2addr v4, v8
+  0011: const-wide/high16 v6, #double 2.0 // #4000000000000000
+  0013: mul-double/2addr v6, v4
+  0014: return-wide v6
+  debug info
+    line_start: 130
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 130
+    0004: line 131
+    0004: +local v0 a double
+    0008: line 132
+    0008: +local v2 b double
+    000c: line 134
+    000c: +local v4 c double
+    0010: line 135
+    0011: line 137
+    end sequence
+  source file: "Blort.java"
+Blort.testDoublePhi:()D:
+regs: 0007; ins: 0000; outs: 0000
+  0000: const-wide/16 v4, #double 0.0 // #0000
+  0002: const-wide v0, #double 37.0 // #4042800000000000
+  0007: const-wide/high16 v2, #double 3.0 // #4008000000000000
+  0009: cmpl-double v6, v2, v4
+  000b: if-nez v6, 000e // +0003
+  000d: return-wide v4
+  000e: div-double v4, v0, v2
+  0010: goto 000d // -0003
+  debug info
+    line_start: 159
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 159
+    0007: line 160
+    0007: +local v0 a double
+    0009: line 161
+    0009: +local v2 b double
+    000d: line 162
+    000d: +local v4 c double
+    000e: line 161
+    000e: -local v4 c double
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatAddSub:()F:
+regs: 0005; ins: 0000; outs: 0000
+  0000: const/high16 v0, #float 3.0 // #40400000
+  0002: const/high16 v4, #float 5.0 // #40a00000
+  0004: sub-float v1, v4, v0
+  0006: add-float v2, v0, v1
+  0008: const/high16 v3, #float 5.0 // #40a00000
+  000a: sub-float v0, v3, v1
+  000c: cmpg-float v4, v2, v3
+  000e: if-gtz v4, 0017 // +0009
+  0010: const/high16 v4, #float 1.0 // #3f800000
+  0012: add-float v2, v3, v4
+  0014: const/high16 v1, #float 2.0 // #40000000
+  0016: goto 0006 // -0010
+  0017: return v2
+  debug info
+    line_start: 60
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 60
+    0002: line 61
+    0002: +local v0 a float
+    0006: line 63
+    0006: +local v1 b float
+    0008: line 64
+    0008: +local v2 c float
+    000a: line 65
+    000a: +local v3 d float
+    000c: line 66
+    0010: line 67
+    0014: line 71
+    0017: line 69
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatDiv:()F:
+regs: 0006; ins: 0000; outs: 0000
+  0000: const/high16 v5, #float 10.0 // #41200000
+  0002: const/high16 v0, #float 30.0 // #41f00000
+  0004: const/high16 v3, #float 9.0 // #41100000
+  0006: const/high16 v4, #float 5.0 // #40a00000
+  0008: div-float v4, v0, v4
+  000a: sub-float v1, v3, v4
+  000c: const/high16 v3, #float 4.0 // #40800000
+  000e: mul-float v2, v1, v3
+  0010: cmpl-float v3, v2, v5
+  0012: if-lez v3, 0015 // +0003
+  0014: sub-float/2addr v2, v5
+  0015: const/high16 v3, #float 60.0 // #42700000
+  0017: div-float/2addr v3, v0
+  0018: mul-float/2addr v3, v2
+  0019: return v3
+  debug info
+    line_start: 87
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 87
+    0004: line 88
+    0004: +local v0 a float
+    000c: line 89
+    000c: +local v1 b float
+    0010: line 91
+    0010: +local v2 c float
+    0014: line 92
+    0015: line 94
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatMod:()F:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/high16 v0, #float 5.0 // #40a00000
+  0002: const/high16 v3, #float 3.0 // #40400000
+  0004: rem-float v1, v0, v3
+  0006: const/4 v3, #float 0.0 // #0
+  0007: rem-float v2, v0, v3
+  0009: add-float v3, v1, v2
+  000b: return v3
+  debug info
+    line_start: 98
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 98
+    0002: line 99
+    0002: +local v0 a float
+    0006: line 100
+    0006: +local v1 b float
+    0009: line 101
+    0009: +local v2 c float
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatMult:()F:
+regs: 0005; ins: 0000; outs: 0000
+  0000: const/high16 v4, #float 10.0 // #41200000
+  0002: const/high16 v0, #float 6.0 // #40c00000
+  0004: const/high16 v3, #float 9.0 // #41100000
+  0006: sub-float v1, v3, v0
+  0008: const/high16 v3, #float 4.0 // #40800000
+  000a: mul-float v2, v1, v3
+  000c: cmpl-float v3, v2, v4
+  000e: if-lez v3, 0011 // +0003
+  0010: sub-float/2addr v2, v4
+  0011: const/high16 v3, #float 2.0 // #40000000
+  0013: mul-float/2addr v3, v2
+  0014: return v3
+  debug info
+    line_start: 76
+    parameters_size: 0000
+    0000: prologue end
+    0002: line 76
+    0004: line 77
+    0004: +local v0 a float
+    0008: line 78
+    0008: +local v1 b float
+    000c: line 80
+    000c: +local v2 c float
+    0010: line 81
+    0011: line 83
+    end sequence
+  source file: "Blort.java"
+Blort.testFloatPhi:()F:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v2, #float 0.0 // #0
+  0001: const/high16 v0, #float 37.0 // #42140000
+  0003: const/high16 v1, #float 3.0 // #40400000
+  0005: cmpl-float v3, v1, v2
+  0007: if-nez v3, 000a // +0003
+  0009: return v2
+  000a: div-float v2, v0, v1
+  000c: goto 0009 // -0003
+  debug info
+    line_start: 105
+    parameters_size: 0000
+    0000: prologue end
+    0001: line 105
+    0003: line 106
+    0003: +local v0 a float
+    0005: line 107
+    0005: +local v1 b float
+    0009: line 108
+    0009: +local v2 c float
+    000a: line 107
+    000a: -local v2 c float
+    end sequence
+  source file: "Blort.java"
+Blort.testIntAddSub:()I:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v0, #int 3 // #3
+  0001: rsub-int/lit8 v1, v0, #int 5 // #05
+  0003: add-int/lit8 v2, v0, #int 2 // #02
+  0005: const/4 v3, #int 5 // #5
+  0006: add-int/lit8 v0, v3, #int -2 // #fe
+  0008: if-gt v2, v3, 000e // +0006
+  000a: add-int/lit8 v2, v3, #int 1 // #01
+  000c: const/4 v1, #int 2 // #2
+  000d: goto 0003 // -000a
+  000e: return v2
+  debug info
+    line_start: 6
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 6
+    0001: line 7
+    0001: +local v0 a int
+    0003: line 9
+    0003: +local v1 b int
+    0005: line 10
+    0005: +local v2 c int
+    0006: line 11
+    0006: +local v3 d int
+    0008: line 12
+    000a: line 13
+    000c: line 17
+    000e: line 15
+    end sequence
+  source file: "Blort.java"
+Blort.testIntDiv:()I:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/16 v0, #int 30 // #001e
+  0002: const/4 v3, #int 6 // #6
+  0003: rsub-int/lit8 v1, v3, #int 9 // #09
+  0005: mul-int/lit8 v2, v1, #int 4 // #04
+  0007: const/16 v3, #int 10 // #000a
+  0009: if-le v2, v3, 000d // +0004
+  000b: add-int/lit8 v2, v2, #int -10 // #f6
+  000d: mul-int/lit8 v3, v2, #int 2 // #02
+  000f: return v3
+  debug info
+    line_start: 33
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 33
+    0002: line 34
+    0002: +local v0 a int
+    0005: line 35
+    0005: +local v1 b int
+    0007: line 37
+    0007: +local v2 c int
+    000b: line 38
+    000d: line 40
+    end sequence
+  source file: "Blort.java"
+Blort.testIntMod:()I:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v0, #int 5 // #5
+  0001: rem-int/lit8 v1, v0, #int 3 // #03
+  0003: rem-int/lit8 v2, v0, #int 0 // #00
+  0005: add-int/lit8 v3, v2, #int 2 // #02
+  0007: return v3
+  debug info
+    line_start: 44
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 44
+    0001: line 45
+    0001: +local v0 a int
+    0003: line 46
+    0003: +local v1 b int
+    0005: line 47
+    0005: +local v2 c int
+    end sequence
+  source file: "Blort.java"
+Blort.testIntMult:()I:
+regs: 0004; ins: 0000; outs: 0000
+  0000: const/4 v0, #int 6 // #6
+  0001: rsub-int/lit8 v1, v0, #int 9 // #09
+  0003: mul-int/lit8 v2, v1, #int 4 // #04
+  0005: const/16 v3, #int 10 // #000a
+  0007: if-le v2, v3, 000b // +0004
+  0009: add-int/lit8 v2, v2, #int -10 // #f6
+  000b: mul-int/lit8 v3, v2, #int 2 // #02
+  000d: return v3
+  debug info
+    line_start: 22
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 22
+    0001: line 23
+    0001: +local v0 a int
+    0003: line 24
+    0003: +local v1 b int
+    0005: line 26
+    0005: +local v2 c int
+    0009: line 27
+    000b: line 29
+    end sequence
+  source file: "Blort.java"
+Blort.testIntPhi:()I:
+regs: 0003; ins: 0000; outs: 0000
+  0000: const/16 v0, #int 37 // #0025
+  0002: const/4 v1, #int 3 // #3
+  0003: if-nez v1, 0007 // +0004
+  0005: const/4 v2, #int 0 // #0
+  0006: return v2
+  0007: const/16 v2, #int 12 // #000c
+  0009: goto 0006 // -0003
+  debug info
+    line_start: 51
+    parameters_size: 0000
+    0000: prologue end
+    0000: line 51
+    0002: line 52
+    0002: +local v0 a int
+    0003: line 53
+    0003: +local v1 b int
+    0006: line 54
+    0006: +local v2 c int
+    0007: line 53
+    0007: -local v2 c int
+    end sequence
+  source file: "Blort.java"
diff --git a/dx/tests/121-sccp/info.txt b/dx/tests/121-sccp/info.txt
new file mode 100644
index 0000000..76e6bcd
--- /dev/null
+++ b/dx/tests/121-sccp/info.txt
@@ -0,0 +1,6 @@
+This tests various aspects of the SCCP pass for correctness, and to
+ensure there aren't any regressions.
+
+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/121-sccp/run b/dx/tests/121-sccp/run
new file mode 100644
index 0000000..4f65461
--- /dev/null
+++ b/dx/tests/121-sccp/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -d . *.java
+dx --debug --dex --dump-method=Blort.test'*' Blort.class
+$JAVAC -g -d . *.java
+dx --debug --dex --dump-method=Blort.test'*' Blort.class
diff --git a/dx/tests/run-all-tests b/dx/tests/run-all-tests
new file mode 100755
index 0000000..68062c2
--- /dev/null
+++ b/dx/tests/run-all-tests
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# 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.
+
+# 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}"`
+
+passed=0
+failed=0
+failNames=""
+
+for i in *; do
+    if [ -d "$i" -a -r "$i" ]; then
+        ./run-test "$i"
+        if [ "$?" = "0" ]; then
+            ((passed += 1))
+        else
+            ((failed += 1))
+            failNames="$failNames $i"
+        fi
+    fi
+done
+
+echo "passed: $passed test(s)"
+echo "failed: $failed test(s)"
+
+for i in $failNames; do
+    echo "failed: $i"
+done
diff --git a/dx/tests/run-test b/dx/tests/run-test
new file mode 100755
index 0000000..a9221de
--- /dev/null
+++ b/dx/tests/run-test
@@ -0,0 +1,149 @@
+#!/bin/bash
+#
+# 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.
+
+# 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}"`
+
+export JAVAC="${progdir}/../../../prebuilt/common/openjdk/bin/javac"
+if [ "!" -e "$JAVAC" ]; then
+    JAVAC="javac"
+fi
+
+info="info.txt"
+run="run"
+expected="expected.txt"
+output="out.txt"
+
+dev_mode="no"
+if [ "x$1" = "x--dev" ]; then
+    dev_mode="yes"
+    shift
+fi
+
+update_mode="no"
+if [ "x$1" = "x--update" ]; then
+    update_mode="yes"
+    shift
+fi
+
+usage="no"
+if [ "x$1" = "x--help" ]; then
+    usage="yes"
+else
+    if [ "x$1" = "x" ]; then
+        testdir=`basename "$oldwd"`
+    else
+        testdir="$1"
+    fi
+
+    if [ '!' -d "$testdir" ]; then
+        td2=`echo ${testdir}-*`
+        if [ '!' -d "$td2" ]; then
+            echo "${testdir}: no such test directory" 1>&2
+            usage="yes"
+        fi
+        testdir="$td2"
+    fi
+fi
+
+if [ "$usage" = "yes" ]; then
+    prog=`basename $prog`
+    (
+        echo "usage:"
+        echo "  $prog --help             Print this message."
+        echo "  $prog testname           Run test normally."
+        echo "  $prog --dev testname     Development mode (dump to stdout)."
+        echo "  $prog --update testname  Update mode (replace expected.txt)."
+        echo "  Omitting the test name uses the current directory as the test."
+    ) 1>&2
+    exit 1
+fi
+
+td_info="$testdir"/"$info"
+td_run="$testdir"/"$run"
+td_expected="$testdir"/"$expected"
+
+tmpdir=/tmp/test-$$
+
+if [ '!' '(' -r "$td_info" -a -r "$td_run" -a -r "$td_expected" ')' ]; then
+    echo "${testdir}: missing files" 1>&2
+    exit 1
+fi
+
+# copy the test to a temp dir and run it
+
+echo "${testdir}: running..." 1>&2
+
+rm -rf "$tmpdir"
+cp -Rp "$testdir" "$tmpdir"
+cd "$tmpdir"
+chmod 755 "$run"
+
+#PATH="${progdir}/../build/bin:${PATH}"
+
+good="no"
+if [ "$dev_mode" = "yes" ]; then
+    "./$run" 2>&1
+    echo "exit status: $?" 1>&2
+    good="yes"
+elif [ "$update_mode" = "yes" ]; then
+    "./$run" >"${progdir}/$td_expected" 2>&1
+    good="yes"
+else
+    "./$run" >"$output" 2>&1
+    cmp -s "$expected" "$output"
+    if [ "$?" = "0" ]; then
+        # output == expected
+        good="yes"
+        echo "$testdir"': succeeded!' 1>&2
+    fi
+fi
+
+if [ "$good" = "yes" ]; then
+    cd "$oldwd"
+    rm -rf "$tmpdir"
+    exit 0
+fi
+
+(
+    echo "${testdir}: FAILED!"
+    echo ' '
+    echo '#################### info'
+    cat "$info" | sed 's/^/# /g'
+    echo '#################### diffs'
+    diff -u "$expected" "$output"
+    echo '####################'
+    echo ' '
+    echo "files left in $tmpdir"
+) 1>&2
+
+exit 1
diff --git a/hit/samples/android.hprof b/hit/samples/android.hprof
new file mode 100644
index 0000000..bb8d2e0
--- /dev/null
+++ b/hit/samples/android.hprof
Binary files differ
diff --git a/hit/src/com/android/hit/ArrayInstance.java b/hit/src/com/android/hit/ArrayInstance.java
new file mode 100644
index 0000000..42e8803
--- /dev/null
+++ b/hit/src/com/android/hit/ArrayInstance.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.util.Set;
+
+public class ArrayInstance extends Instance {
+    private int mType;
+    private int mNumEntries;
+    private byte[] mData;
+
+    public ArrayInstance(long id, StackTrace stack, int type, int numEntries,
+            byte[] data) {
+        mId = id;
+        mStack = stack;
+        mType = type;
+        mNumEntries = numEntries;
+        mData = data;
+    }
+
+    public final void resolveReferences(State state) {
+        if (mType != Types.OBJECT) {
+            return;
+        }
+
+        /*
+         * mData holds a stream of object instance ids
+         * Spin through them all and list ourselves as a reference holder.
+         */
+        int idSize = Types.getTypeSize(mType);
+        final int N = mNumEntries;
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(mData);
+        DataInputStream dis = new DataInputStream(bais);
+
+        for (int i = 0; i < N; i++) {
+            long id;
+
+            try {
+                if (idSize == 4) {
+                    id = dis.readInt();
+                } else {
+                    id = dis.readLong();
+                }
+
+                Instance instance = state.findReference(id);
+
+                if (instance != null) {
+                    instance.addParent(this);
+                }
+            } catch (java.io.IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public final int getSize() {
+        return mData.length;
+    }
+
+    @Override
+    public final void visit(Set<Instance> resultSet, Filter filter) {
+        //  If we're in the set then we and our children have been visited
+        if (resultSet.contains(this)) {
+            return;
+        }
+
+        if (null != filter) {
+            if (filter.accept(this)) {
+                resultSet.add(this);
+            }
+        } else {
+            resultSet.add(this);
+        }
+
+        if (mType != Types.OBJECT) {
+            return;
+        }
+
+        /*
+         * mData holds a stream of object instance ids
+         * Spin through them all and visit them
+         */
+        int idSize = Types.getTypeSize(mType);
+        final int N = mNumEntries;
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(mData);
+        DataInputStream dis = new DataInputStream(bais);
+        State state = mHeap.mState;
+
+        for (int i = 0; i < N; i++) {
+            long id;
+
+            try {
+                if (idSize == 4) {
+                    id = dis.readInt();
+                } else {
+                    id = dis.readLong();
+                }
+
+                Instance instance = state.findReference(id);
+
+                if (instance != null) {
+                    instance.visit(resultSet, filter);
+                }
+            } catch (java.io.IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public final String getTypeName() {
+        return Types.getTypeName(mType) + "[" + mNumEntries + "]";
+    }
+
+    public final String toString() {
+        return String.format("%s@0x08x", getTypeName(), mId);
+    }
+
+    @Override
+    public String describeReferenceTo(long referent) {
+        //  If this isn't an object array then we can't refer to an object
+        if (mType != Types.OBJECT) {
+            return super.describeReferenceTo(referent);
+        }
+
+        int idSize = Types.getTypeSize(mType);
+        final int N = mNumEntries;
+        int numRefs = 0;
+        StringBuilder result = new StringBuilder("Elements [");
+        ByteArrayInputStream bais = new ByteArrayInputStream(mData);
+        DataInputStream dis = new DataInputStream(bais);
+
+        /*
+         * Spin through all the objects and build up a string describing
+         * all of the array elements that refer to the target object.
+         */
+        for (int i = 0; i < N; i++) {
+            long id;
+
+            try {
+                if (idSize == 4) {
+                    id = dis.readInt();
+                } else {
+                    id = dis.readLong();
+                }
+
+                if (id == referent) {
+                    numRefs++;
+
+                    if (numRefs > 1) {
+                        result.append(", ");
+                    }
+
+                    result.append(i);
+                }
+            } catch (java.io.IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (numRefs == 0) {
+            return super.describeReferenceTo(referent);
+        }
+
+        result.append("]");
+
+        return result.toString();
+    }
+}
diff --git a/hit/src/com/android/hit/ClassInstance.java b/hit/src/com/android/hit/ClassInstance.java
new file mode 100644
index 0000000..0869769
--- /dev/null
+++ b/hit/src/com/android/hit/ClassInstance.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Set;
+
+public class ClassInstance extends Instance {
+    private byte[] mFieldValues;
+
+    public ClassInstance(long id, StackTrace stack, long classId) {
+        mId = id;
+        mStack = stack;
+        mClassId = classId;
+    }
+
+    public final void loadFieldData(DataInputStream in, int numBytes)
+            throws IOException {
+        mFieldValues = new byte[numBytes];
+        in.readFully(mFieldValues);
+    }
+
+    @Override
+    public void resolveReferences(State state) {
+        ClassObj isa = mHeap.mState.findClass(mClassId);
+
+        resolve(state, isa, isa.mStaticFieldTypes, isa.mStaticFieldValues);
+        resolve(state, isa, isa.mFieldTypes, mFieldValues);
+    }
+
+    private void resolve(State state, ClassObj isa, int[] types,
+            byte[] values) {
+        ByteArrayInputStream bais = new ByteArrayInputStream(values);
+        DataInputStream dis = new DataInputStream(bais);
+        final int N = types.length;
+
+        /*
+         * Spin through the list of fields, find all object references,
+         * and list ourselves as a reference holder.
+         */
+        try {
+            for (int i = 0; i < N; i++) {
+                int type = types[i];
+                int size = Types.getTypeSize(type);
+
+                    if (type == Types.OBJECT) {
+                        long id;
+
+                        if (size == 4) {
+                            id = dis.readInt();
+                        } else {
+                            id = dis.readLong();
+                        }
+
+                        Instance instance = state.findReference(id);
+
+                        if (instance != null) {
+                            instance.addParent(this);
+                        }
+                    } else {
+                        dis.skipBytes(size);
+                    }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public final int getSize() {
+        ClassObj isa = mHeap.mState.findClass(mClassId);
+
+        return isa.getSize();
+    }
+
+    @Override
+    public final void visit(Set<Instance> resultSet, Filter filter) {
+        if (resultSet.contains(this)) {
+            return;
+        }
+
+        if (filter != null) {
+            if (filter.accept(this)) {
+                resultSet.add(this);
+            }
+        } else {
+            resultSet.add(this);
+        }
+
+        State state = mHeap.mState;
+        ClassObj isa = state.findClass(mClassId);
+        int[] types = isa.mFieldTypes;
+        ByteArrayInputStream bais = new ByteArrayInputStream(mFieldValues);
+        DataInputStream dis = new DataInputStream(bais);
+        final int N = types.length;
+
+        /*
+         * Spin through the list of fields, find all object references,
+         * and list ourselves as a reference holder.
+         */
+        try {
+            for (int i = 0; i < N; i++) {
+                int type = types[i];
+                int size = Types.getTypeSize(type);
+
+                if (type == Types.OBJECT) {
+                    long id;
+
+                    if (size == 4) {
+                        id = dis.readInt();
+                    } else {
+                        id = dis.readLong();
+                    }
+
+                    Instance instance = state.findReference(id);
+
+                    if (instance != null) {
+                        instance.visit(resultSet, filter);
+                    }
+                } else {
+                    dis.skipBytes(size);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public final String getTypeName() {
+        ClassObj theClass = mHeap.mState.findClass(mClassId);
+
+        return theClass.mClassName;
+    }
+
+    public final String toString() {
+        return String.format("%s@0x%08x", getTypeName(), mId);
+    }
+
+    @Override
+    public String describeReferenceTo(long referent) {
+        ClassObj isa = mHeap.mState.findClass(mClassId);
+        int[] types = isa.mFieldTypes;
+        String[] fieldNames = isa.mFieldNames;
+        ByteArrayInputStream bais = new ByteArrayInputStream(mFieldValues);
+        DataInputStream dis = new DataInputStream(bais);
+        final int N = types.length;
+        StringBuilder result = new StringBuilder("Referenced in field(s):");
+        int numReferences = 0;
+
+        /*
+         * Spin through the list of fields, add info about the field
+         * references to the output text.
+         */
+        try {
+            for (int i = 0; i < N; i++) {
+                int type = types[i];
+                int size = Types.getTypeSize(type);
+
+                if (type == Types.OBJECT) {
+                    long id;
+
+                    if (size == 4) {
+                        id = dis.readInt();
+                    } else {
+                        id = dis.readLong();
+                    }
+
+                    if (id == referent) {
+                        numReferences++;
+                        result.append("\n    ");
+                        result.append(fieldNames[i]);
+                    }
+                } else {
+                    dis.skipBytes(size);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        /*
+         *  TODO:  perform a similar loop over the static fields of isa
+         */
+
+        if (numReferences == 0) {
+            return super.describeReferenceTo(referent);
+        }
+
+        return result.toString();
+    }
+}
diff --git a/hit/src/com/android/hit/ClassObj.java b/hit/src/com/android/hit/ClassObj.java
new file mode 100644
index 0000000..1e3ac28
--- /dev/null
+++ b/hit/src/com/android/hit/ClassObj.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ClassObj extends Instance implements Comparable<ClassObj> {
+    String mClassName;
+    long mSuperclassId;
+
+    String[] mFieldNames;
+    int[] mFieldTypes;
+
+    String[] mStaticFieldNames;
+    int[] mStaticFieldTypes;
+    byte[] mStaticFieldValues;
+
+    ArrayList<Instance> mInstances = new ArrayList<Instance>();
+    Set<ClassObj> mSubclasses = new HashSet<ClassObj>();
+
+    int mSize;
+
+    public ClassObj(long id, StackTrace stack, String className) {
+        mId = id;
+        mStack = stack;
+        mClassName = className;
+    }
+
+    @Override
+    public final void resolveReferences(State state) {
+        ByteArrayInputStream bais =
+            new ByteArrayInputStream(mStaticFieldValues);
+        DataInputStream dis = new DataInputStream(bais);
+        int[] types = mStaticFieldTypes;
+        final int N = types.length;
+
+        /*
+         * Spin through the list of static fields, find all object references,
+         * and list ourselves as a reference holder.  Also add them to
+         * the list of root objects.
+         */
+        try {
+            for (int i = 0; i < N; i++) {
+                int type = types[i];
+                int size = Types.getTypeSize(type);
+
+                if (type == Types.OBJECT) {
+                    long id;
+
+                    if (size == 4) {
+                        id = dis.readInt();
+                    } else {
+                        id = dis.readLong();
+                    }
+
+                    RootObj root = new RootObj(RootType.JAVA_STATIC, id);
+
+                    if (id == 0) {
+                        root.mComment = String.format(
+                            "Static field %s:%s null",
+                                mClassName,
+                                mStaticFieldNames[i]);
+                    } else {
+                        Instance instance = state.findReference(id);
+
+                        instance.addParent(this);
+
+                        root.mComment = String.format(
+                            "Static field %s:%s %s [%s] 0x%08x",
+                                mClassName,
+                                mStaticFieldNames[i],
+                                instance.getTypeName(),
+                                instance.mHeap.mName,
+                                id);
+                    }
+
+                    mHeap.addRoot(root);
+                } else {
+                    dis.skipBytes(size);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+
+        //  Lastly, add ourself as a subclass of our superclass
+        if (mSuperclassId != 0) {
+            ClassObj superclass = state.findClass(mSuperclassId);
+
+            superclass.addSubclass(this);
+        }
+    }
+
+    public final void addSubclass(ClassObj subclass) {
+        mSubclasses.add(subclass);
+    }
+
+    public final void dumpSubclasses() {
+        for (ClassObj subclass: mSubclasses) {
+            System.out.println("     " + subclass.mClassName);
+        }
+    }
+
+    public final String toString() {
+        return mClassName.replace('/', '.');
+    }
+
+    public final void addInstance(Instance instance) {
+        mInstances.add(instance);
+    }
+
+    public final void setSuperclassId(long id) {
+        mSuperclassId = id;
+    }
+
+    public final void setFieldNames(String[] names) {
+        mFieldNames = names;
+    }
+
+    public final void setFieldTypes(int[] types) {
+        mFieldTypes = types;
+    }
+
+    public final void setStaticFieldNames(String[] names) {
+        mStaticFieldNames = names;
+    }
+
+    public final void setStaticFieldTypes(int[] types) {
+        mStaticFieldTypes = types;
+    }
+
+    public final void setStaticFieldValues(byte[] values) {
+        mStaticFieldValues = values;
+    }
+
+    public final void dump() {
+        System.out.println("+----------  ClassObj dump for: " + mClassName);
+
+        System.out.println("+-----  Static fields");
+
+        for (int i = 0; i < mStaticFieldNames.length; i++) {
+            System.out.println(mStaticFieldNames[i] + ": "
+                + mStaticFieldTypes[i]);
+        }
+
+        System.out.println("+-----  Instance fields");
+
+        for (int i = 0; i < mFieldNames.length; i++) {
+            System.out.println(mFieldNames[i] + ": " + mFieldTypes[i]);
+        }
+    }
+
+    @Override
+    public final String getTypeName() {
+        return "class " + mClassName;
+    }
+
+    @Override
+    public final void visit(Set<Instance> resultSet, Filter filter) {
+        if (resultSet.contains(this)) {
+            return;
+        }
+
+        if (filter != null) {
+            if (filter.accept(this)) {
+                resultSet.add(this);
+            }
+        } else {
+            resultSet.add(this);
+        }
+
+        ByteArrayInputStream bais =
+            new ByteArrayInputStream(mStaticFieldValues);
+        DataInputStream dis = new DataInputStream(bais);
+        int[] types = mStaticFieldTypes;
+        final int N = types.length;
+        State state = mHeap.mState;
+
+        /*
+         * Spin through the list of static fields, find all object references,
+         * and visit them.
+         */
+        try {
+            for (int i = 0; i < N; i++) {
+                int type = types[i];
+                int size = Types.getTypeSize(type);
+
+                if (type == Types.OBJECT) {
+                    long id;
+
+                    if (size == 4) {
+                        id = dis.readInt();
+                    } else {
+                        id = dis.readLong();
+                    }
+
+                    Instance instance = state.findReference(id);
+
+                    if (instance != null) {
+                        instance.visit(resultSet, filter);
+                    }
+                } else {
+                    dis.skipBytes(size);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public final int compareTo(ClassObj o) {
+        return mClassName.compareTo(o.mClassName);
+    }
+
+    public final boolean equals(Object o) {
+        if (! (o instanceof ClassObj)) {
+            return false;
+        }
+
+        return 0 == compareTo((ClassObj) o);
+    }
+}
diff --git a/hit/src/com/android/hit/Heap.java b/hit/src/com/android/hit/Heap.java
new file mode 100644
index 0000000..37b15dd
--- /dev/null
+++ b/hit/src/com/android/hit/Heap.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class Heap {
+    String mName;
+
+    //  List of individual stack frames
+    HashMap<Long, StackFrame> mFrames = new HashMap<Long, StackFrame>();
+
+    //  List stack traces, which are lists of stack frames
+    HashMap<Integer, StackTrace> mTraces = new HashMap<Integer, StackTrace>();
+
+    //  Root objects such as interned strings, jni locals, etc
+    ArrayList<RootObj> mRoots = new ArrayList<RootObj>();
+
+    //  List of threads
+    HashMap<Integer, ThreadObj> mThreads = new HashMap<Integer, ThreadObj>();
+
+    //  Class definitions
+    HashMap<Long, ClassObj> mClassesById = new HashMap<Long, ClassObj>();
+    HashMap<String, ClassObj> mClassesByName = new HashMap<String, ClassObj>();
+
+    //  List of instances of above class definitions
+    HashMap<Long, Instance> mInstances = new HashMap<Long, Instance>();
+
+    //  The super-state that this heap is part of
+    State mState;
+
+    public Heap(String name) {
+        mName = name;
+    }
+
+    public final void addStackFrame(StackFrame theFrame) {
+        mFrames.put(theFrame.mId, theFrame);
+    }
+
+    public final StackFrame getStackFrame(long id) {
+        return mFrames.get(id);
+    }
+
+    public final void addStackTrace(StackTrace theTrace) {
+        mTraces.put(theTrace.mSerialNumber, theTrace);
+    }
+
+    public final StackTrace getStackTrace(int traceSerialNumber) {
+        return mTraces.get(traceSerialNumber);
+    }
+
+    public final StackTrace getStackTraceAtDepth(int traceSerialNumber,
+            int depth) {
+        StackTrace trace = mTraces.get(traceSerialNumber);
+
+        if (trace != null) {
+            trace = trace.fromDepth(depth);
+        }
+
+        return trace;
+    }
+
+    public final void addRoot(RootObj root) {
+        root.mIndex = mRoots.size();
+        mRoots.add(root);
+    }
+
+    public final void addThread(ThreadObj thread, int serialNumber) {
+        mThreads.put(serialNumber, thread);
+    }
+
+    public final ThreadObj getThread(int serialNumber) {
+        return mThreads.get(serialNumber);
+    }
+
+    public final void addInstance(long id, Instance instance) {
+        mInstances.put(id, instance);
+    }
+
+    public final Instance getInstance(long id) {
+        return mInstances.get(id);
+    }
+
+    public final void addClass(long id, ClassObj theClass) {
+        mClassesById.put(id, theClass);
+        mClassesByName.put(theClass.mClassName, theClass);
+    }
+
+    public final ClassObj getClass(long id) {
+        return mClassesById.get(id);
+    }
+
+    public final ClassObj getClass(String name) {
+        return mClassesByName.get(name);
+    }
+
+    public final void dumpInstanceCounts() {
+        for (ClassObj theClass: mClassesById.values()) {
+            int count = theClass.mInstances.size();
+
+            if (count > 0) {
+                System.out.println(theClass + ": " + count);
+            }
+        }
+    }
+
+    public final void dumpSubclasses() {
+        for (ClassObj theClass: mClassesById.values()) {
+            int count = theClass.mSubclasses.size();
+
+            if (count > 0) {
+                System.out.println(theClass);
+                theClass.dumpSubclasses();
+            }
+        }
+    }
+
+    public final void dumpSizes() {
+        for (ClassObj theClass: mClassesById.values()) {
+            int size = 0;
+
+            for (Instance instance: theClass.mInstances) {
+                size += instance.getCompositeSize();
+            }
+
+            if (size > 0) {
+                System.out.println(theClass + ": base " + theClass.getSize()
+                    + ", composite " + size);
+            }
+        }
+    }
+
+    /*
+     * Spin through all of the class instances and link them to their
+     * parent class definition objects.  Then have each instance resolve
+     * its own internal object references.
+     */
+    public final void resolveInstanceRefs(State state) {
+        for (Instance instance : mInstances.values()) {
+            ClassObj theClass = mClassesById.get(instance.mClassId);
+
+            if (theClass == null) {
+                continue;
+            }
+
+            String name = theClass.mClassName;
+            String superclassName = "none";
+            ClassObj superClass = mClassesById.get(theClass.mSuperclassId);
+
+            if (superClass != null) {
+                superclassName = superClass.mClassName;
+            }
+
+            theClass.addInstance(instance);
+            instance.resolveReferences(state);
+        }
+    }
+
+    public final void resolveClassStatics(State state) {
+        for (ClassObj theClass: mClassesById.values()) {
+            theClass.resolveReferences(state);
+        }
+    }
+
+    public final void resolveRoots(State state) {
+        for (RootObj root: mRoots) {
+            root.resolveReferences(state);
+        }
+    }
+}
diff --git a/hit/src/com/android/hit/HprofParser.java b/hit/src/com/android/hit/HprofParser.java
new file mode 100644
index 0000000..98fef1e
--- /dev/null
+++ b/hit/src/com/android/hit/HprofParser.java
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.HashMap;
+
+public class HprofParser
+{
+    private static final int STRING_IN_UTF8             =   0x01;
+    private static final int LOAD_CLASS                 =   0x02;
+    private static final int UNLOAD_CLASS               =   0x03;   //  unused
+    private static final int STACK_FRAME                =   0x04;
+    private static final int STACK_TRACE                =   0x05;
+    private static final int ALLOC_SITES                =   0x06;   //  unused
+    private static final int HEAP_SUMMARY               =   0x07;
+    private static final int START_THREAD               =   0x0a;   //  unused
+    private static final int END_THREAD                 =   0x0b;   //  unused
+    private static final int HEAP_DUMP                  =   0x0c;
+    private static final int HEAP_DUMP_SEGMENT          =   0x1c;
+    private static final int HEAP_DUMP_END              =   0x2c;
+    private static final int CPU_SAMPLES                =   0x0d;   //  unused
+    private static final int CONTROL_SETTINGS           =   0x0e;   //  unused
+
+    private static final int ROOT_UNKNOWN               =   0xff;
+    private static final int ROOT_JNI_GLOBAL            =   0x01;
+    private static final int ROOT_JNI_LOCAL             =   0x02;
+    private static final int ROOT_JAVA_FRAME            =   0x03;
+    private static final int ROOT_NATIVE_STACK          =   0x04;
+    private static final int ROOT_STICKY_CLASS          =   0x05;
+    private static final int ROOT_THREAD_BLOCK          =   0x06;
+    private static final int ROOT_MONITOR_USED          =   0x07;
+    private static final int ROOT_THREAD_OBJECT         =   0x08;
+    private static final int ROOT_CLASS_DUMP            =   0x20;
+    private static final int ROOT_INSTANCE_DUMP         =   0x21;
+    private static final int ROOT_OBJECT_ARRAY_DUMP     =   0x22;
+    private static final int ROOT_PRIMITIVE_ARRAY_DUMP  =   0x23;
+
+    /**
+     * Android format addition
+     *
+     * Specifies information about which heap certain objects came from.
+     * When a sub-tag of this type appears in a HPROF_HEAP_DUMP or
+     * HPROF_HEAP_DUMP_SEGMENT record, entries that follow it will be
+     * associated with the specified heap.  The HEAP_DUMP_INFO data is reset
+     * at the end of the HEAP_DUMP[_SEGMENT].  Multiple HEAP_DUMP_INFO entries
+     * may appear in a single HEAP_DUMP[_SEGMENT].
+     *
+     * Format:
+     *     u1: Tag value (0xFE)
+     *     u4: heap ID
+     *     ID: heap name string ID
+     */
+    private static final int ROOT_HEAP_DUMP_INFO        =   0xfe;
+    private static final int ROOT_INTERNED_STRING       =   0x89;
+    private static final int ROOT_FINALIZING            =   0x8a;
+    private static final int ROOT_DEBUGGER              =   0x8b;
+    private static final int ROOT_REFERENCE_CLEANUP     =   0x8c;
+    private static final int ROOT_VM_INTERNAL           =   0x8d;
+    private static final int ROOT_JNI_MONITOR           =   0x8e;
+    private static final int ROOT_UNREACHABLE           =   0x90;
+    private static final int ROOT_PRIMITIVE_ARRAY_NODATA=   0xc3;
+
+    DataInputStream mInput;
+    int mIdSize;
+    State mState;
+
+    byte[] mFieldBuffer = new byte[8];
+
+    /*
+     * These are only needed while parsing so are not kept as part of the
+     * heap data.
+     */
+    HashMap<Long, String> mStrings = new HashMap<Long, String>();
+    HashMap<Long, String> mClassNames = new HashMap<Long, String>();
+
+    public HprofParser(DataInputStream in) {
+        mInput = in;
+    }
+
+    public final State parse() {
+        State state = new State();
+        mState = state;
+
+        try {
+            String  s = readNullTerminatedString();
+            DataInputStream in = mInput;
+
+            mIdSize = in.readInt();
+            Types.setIdSize(mIdSize);
+
+            in.readLong();  //  Timestamp, ignored for now
+
+            while (true) {
+                int tag = in.readUnsignedByte();
+                int timestamp = in.readInt();
+                int length = in.readInt();
+
+                switch (tag) {
+                    case STRING_IN_UTF8:
+                        loadString(length - 4);
+                        break;
+
+                    case LOAD_CLASS:
+                        loadClass();
+                        break;
+
+                    case STACK_FRAME:
+                        loadStackFrame();
+                        break;
+
+                    case STACK_TRACE:
+                        loadStackTrace();
+                        break;
+
+                    case HEAP_DUMP:
+                        loadHeapDump(length);
+                        mState.setToDefaultHeap();
+                        break;
+
+                    case HEAP_DUMP_SEGMENT:
+                        loadHeapDump(length);
+                        mState.setToDefaultHeap();
+                        break;
+
+                    default:
+                        skipFully(length);
+                }
+
+            }
+        } catch (EOFException eof) {
+            //  this is fine
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        mState.resolveReferences();
+
+        return state;
+    }
+
+    private String readNullTerminatedString() throws IOException {
+        StringBuilder s = new StringBuilder();
+        DataInputStream in = mInput;
+
+        for (int c = in.read(); c != 0; c = in.read()) {
+            s.append((char) c);
+        }
+
+        return s.toString();
+    }
+
+    private long readId() throws IOException {
+        switch (mIdSize) {
+            case 1: return mInput.readUnsignedByte();
+            case 2: return mInput.readUnsignedShort();
+            case 4: return ((long) mInput.readInt()) & 0x00000000ffffffffL;
+            case 8: return mInput.readLong();
+        }
+
+        throw new IllegalArgumentException("ID Length must be 1, 2, 4, or 8");
+    }
+
+    private String readUTF8(int length) throws IOException {
+        byte[] b = new byte[length];
+
+        mInput.read(b);
+
+        return new String(b, "utf-8");
+    }
+
+    private void loadString(int length) throws IOException {
+        long id = readId();
+        String string = readUTF8(length);
+
+        mStrings.put(id, string);
+    }
+
+    private void loadClass() throws IOException {
+        DataInputStream in = mInput;
+        int serial = in.readInt();
+        long id = readId();
+        int stackTrace = in.readInt();              //  unused
+        String name = mStrings.get(readId());
+
+        mClassNames.put(id, name);
+    }
+
+    private void loadStackFrame() throws IOException {
+        long id = readId();
+        String methodName = mStrings.get(readId());
+        String methodSignature = mStrings.get(readId());
+        String sourceFile = mStrings.get(readId());
+        int serial = mInput.readInt();
+        int lineNumber = mInput.readInt();
+
+        StackFrame frame = new StackFrame(id, methodName, methodSignature,
+            sourceFile, serial, lineNumber);
+
+        mState.addStackFrame(frame);
+    }
+
+    private void loadStackTrace() throws IOException {
+        int serialNumber = mInput.readInt();
+        int threadSerialNumber = mInput.readInt();
+        final int numFrames = mInput.readInt();
+        StackFrame[] frames = new StackFrame[numFrames];
+
+        for (int i = 0; i < numFrames; i++) {
+            frames[i] = mState.getStackFrame(readId());
+        }
+
+        StackTrace trace = new StackTrace(serialNumber, threadSerialNumber,
+            frames);
+
+        mState.addStackTrace(trace);
+    }
+
+    private void loadHeapDump(int length) throws IOException {
+        DataInputStream in = mInput;
+
+        while (length > 0) {
+            int tag = in.readUnsignedByte();
+            length--;
+
+            switch (tag) {
+                case ROOT_UNKNOWN:
+                    length -= loadBasicObj(RootType.UNKNOWN);
+                    break;
+
+                case ROOT_JNI_GLOBAL:
+                    length -= loadBasicObj(RootType.NATIVE_STATIC);
+                    readId();   //  ignored
+                    length -= mIdSize;
+                    break;
+
+                case ROOT_JNI_LOCAL:
+                    length -= loadJniLocal();
+                    break;
+
+                case ROOT_JAVA_FRAME:
+                    length -= loadJavaFrame();
+                    break;
+
+                case ROOT_NATIVE_STACK:
+                    length -= loadNativeStack();
+                    break;
+
+                case ROOT_STICKY_CLASS:
+                    length -= loadBasicObj(RootType.SYSTEM_CLASS);
+                    break;
+
+                case ROOT_THREAD_BLOCK:
+                    length -= loadThreadBlock();
+                    break;
+
+                case ROOT_MONITOR_USED:
+                    length -= loadBasicObj(RootType.BUSY_MONITOR);
+                    break;
+
+                case ROOT_THREAD_OBJECT:
+                    length -= loadThreadObject();
+                    break;
+
+                case ROOT_CLASS_DUMP:
+                    length -= loadClassDump();
+                    break;
+
+                case ROOT_INSTANCE_DUMP:
+                    length -= loadInstanceDump();
+                    break;
+
+                case ROOT_OBJECT_ARRAY_DUMP:
+                    length -= loadObjectArrayDump();
+                    break;
+
+                case ROOT_PRIMITIVE_ARRAY_DUMP:
+                    length -= loadPrimitiveArrayDump();
+                    break;
+
+                case ROOT_PRIMITIVE_ARRAY_NODATA:
+                    System.err.println("+--- PRIMITIVE ARRAY NODATA DUMP");
+                    length -= loadPrimitiveArrayDump();
+
+                    throw new IllegalArgumentException(
+                        "Don't know how to load a nodata array");
+
+                case ROOT_HEAP_DUMP_INFO:
+                    int heapId = mInput.readInt();
+                    long heapNameId = readId();
+                    String heapName = mStrings.get(heapNameId);
+
+                    mState.setHeapTo(heapId, heapName);
+                    length -= 4 + mIdSize;
+                    break;
+
+                case ROOT_INTERNED_STRING:
+                    length -= loadBasicObj(RootType.INTERNED_STRING);
+                    break;
+
+                case ROOT_FINALIZING:
+                    length -= loadBasicObj(RootType.FINALIZING);
+                    break;
+
+                case ROOT_DEBUGGER:
+                    length -= loadBasicObj(RootType.DEBUGGER);
+                    break;
+
+                case ROOT_REFERENCE_CLEANUP:
+                    length -= loadBasicObj(RootType.REFERENCE_CLEANUP);
+                    break;
+
+                case ROOT_VM_INTERNAL:
+                    length -= loadBasicObj(RootType.VM_INTERNAL);
+                    break;
+
+                case ROOT_JNI_MONITOR:
+                    length -= loadJniMonitor();
+                    break;
+
+                case ROOT_UNREACHABLE:
+                    length -= loadBasicObj(RootType.UNREACHABLE);
+                    break;
+
+                default:
+                    throw new IllegalArgumentException(
+                        "loadHeapDump loop with unknown tag " + tag
+                        + " with " + mInput.available()
+                        + " bytes possibly remaining");
+            }
+        }
+    }
+
+    private int loadJniLocal() throws IOException {
+        long id = readId();
+        int threadSerialNumber = mInput.readInt();
+        int stackFrameNumber = mInput.readInt();
+        ThreadObj thread = mState.getThread(threadSerialNumber);
+        StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
+            stackFrameNumber);
+        RootObj root = new RootObj(RootType.NATIVE_LOCAL, id,
+            threadSerialNumber, trace);
+
+        root.setHeap(mState.mCurrentHeap);
+        mState.addRoot(root);
+
+        return mIdSize + 4 + 4;
+    }
+
+    private int loadJavaFrame() throws IOException {
+        long id = readId();
+        int threadSerialNumber = mInput.readInt();
+        int stackFrameNumber = mInput.readInt();
+        ThreadObj thread = mState.getThread(threadSerialNumber);
+        StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
+            stackFrameNumber);
+        RootObj root = new RootObj(RootType.JAVA_LOCAL, id, threadSerialNumber,
+            trace);
+
+        root.setHeap(mState.mCurrentHeap);
+        mState.addRoot(root);
+
+        return mIdSize + 4 + 4;
+    }
+
+    private int loadNativeStack() throws IOException {
+        long id = readId();
+        int threadSerialNumber = mInput.readInt();
+        ThreadObj thread = mState.getThread(threadSerialNumber);
+        StackTrace trace = mState.getStackTrace(thread.mStackTrace);
+        RootObj root = new RootObj(RootType.NATIVE_STACK, id,
+            threadSerialNumber, trace);
+
+        root.setHeap(mState.mCurrentHeap);
+        mState.addRoot(root);
+
+        return mIdSize + 4;
+    }
+
+    private int loadBasicObj(RootType type) throws IOException {
+        long id = readId();
+        RootObj root = new RootObj(type, id);
+
+        root.setHeap(mState.mCurrentHeap);
+        mState.addRoot(root);
+
+        return mIdSize;
+    }
+
+    private int loadThreadBlock() throws IOException {
+        long id = readId();
+        int threadSerialNumber = mInput.readInt();
+        ThreadObj thread = mState.getThread(threadSerialNumber);
+        StackTrace stack = mState.getStackTrace(thread.mStackTrace);
+        RootObj root = new RootObj(RootType.THREAD_BLOCK, id,
+            threadSerialNumber, stack);
+
+        root.setHeap(mState.mCurrentHeap);
+        mState.addRoot(root);
+
+        return mIdSize + 4;
+    }
+
+    private int loadThreadObject() throws IOException {
+        long id = readId();
+        int threadSerialNumber = mInput.readInt();
+        int stackSerialNumber = mInput.readInt();
+        ThreadObj thread = new ThreadObj(id, stackSerialNumber);
+
+        mState.addThread(thread, threadSerialNumber);
+
+        return mIdSize + 4 + 4;
+    }
+
+    private int loadClassDump() throws IOException {
+        int bytesRead = 0;
+        DataInputStream in = mInput;
+        long id = readId();
+        int stackSerialNumber = in.readInt();
+        StackTrace stack = mState.getStackTrace(stackSerialNumber);
+        long superClassId = readId();
+        long classLoaderId = readId();
+        long signersId = readId();
+        long protectionDomainId = readId();
+        long reserved1 = readId();
+        long reserved2 = readId();
+        int instanceSize = in.readInt();
+
+        bytesRead = (7 * mIdSize) + 4 + 4;
+
+        //  Skip over the constant pool
+        int numEntries = in.readUnsignedShort();
+        bytesRead += 2;
+
+        for (int i = 0; i < numEntries; i++) {
+            in.readUnsignedShort();
+            bytesRead += 2 + skipValue();
+        }
+
+        //  Static fields
+        numEntries = in.readUnsignedShort();
+        bytesRead += 2;
+
+        String[] staticFieldNames = new String[numEntries];
+        int[] staticFieldTypes = new int[numEntries];
+        ByteArrayOutputStream staticFieldValues = new ByteArrayOutputStream();
+        byte[] buffer = mFieldBuffer;
+
+        for (int i = 0; i < numEntries; i++) {
+            staticFieldNames[i] = mStrings.get(readId());
+
+            int fieldType = in.readByte();
+            int fieldSize = Types.getTypeSize(fieldType);
+            staticFieldTypes[i] = fieldType;
+
+            in.readFully(buffer, 0, fieldSize);
+            staticFieldValues.write(buffer, 0, fieldSize);
+
+            bytesRead += mIdSize + 1 + fieldSize;
+        }
+
+        //  Instance fields
+        numEntries = in.readUnsignedShort();
+        bytesRead += 2;
+
+        String[] names = new String[numEntries];
+        int[] types = new int[numEntries];
+
+        for (int i = 0; i < numEntries; i++) {
+            long fieldName = readId();
+            int type = in.readUnsignedByte();
+
+            names[i] = mStrings.get(fieldName);
+            types[i] = type;
+
+            bytesRead += mIdSize + 1;
+        }
+
+        ClassObj theClass = new ClassObj(id, stack, mClassNames.get(id));
+
+        theClass.setStaticFieldNames(staticFieldNames);
+        theClass.setStaticFieldTypes(staticFieldTypes);
+        theClass.setStaticFieldValues(staticFieldValues.toByteArray());
+
+        theClass.setSuperclassId(superClassId);
+        theClass.setFieldNames(names);
+        theClass.setFieldTypes(types);
+        theClass.setSize(instanceSize);
+
+        theClass.setHeap(mState.mCurrentHeap);
+
+        mState.addClass(id, theClass);
+
+        return bytesRead;
+    }
+
+    private int loadInstanceDump() throws IOException {
+        long id = readId();
+        int stackId = mInput.readInt();
+        StackTrace stack = mState.getStackTrace(stackId);
+        long classId = readId();
+        int remaining = mInput.readInt();
+        ClassInstance instance = new ClassInstance(id, stack, classId);
+
+        instance.loadFieldData(mInput, remaining);
+        instance.setHeap(mState.mCurrentHeap);
+        mState.addInstance(id, instance);
+
+        return mIdSize + 4 + mIdSize + 4 + remaining;
+    }
+
+    private int loadObjectArrayDump() throws IOException {
+        long id = readId();
+        int stackId = mInput.readInt();
+        StackTrace stack = mState.getStackTrace(stackId);
+        int numElements = mInput.readInt();
+        long classId = readId();
+        int totalBytes = numElements * mIdSize;
+        byte[] data = new byte[totalBytes];
+        String className = mClassNames.get(classId);
+
+        mInput.readFully(data);
+
+        ArrayInstance array = new ArrayInstance(id, stack, Types.OBJECT,
+            numElements, data);
+
+        array.mClassId = classId;
+        array.setHeap(mState.mCurrentHeap);
+        mState.addInstance(id, array);
+
+        return mIdSize + 4 + 4 + mIdSize + totalBytes;
+    }
+
+    private int loadPrimitiveArrayDump() throws IOException {
+        long id = readId();
+        int stackId = mInput.readInt();
+        StackTrace stack = mState.getStackTrace(stackId);
+        int numElements = mInput.readInt();
+        int type = mInput.readUnsignedByte();
+        int size = Types.getTypeSize(type);
+        int totalBytes = numElements * size;
+        byte[] data = new byte[totalBytes];
+
+        mInput.readFully(data);
+
+        ArrayInstance array = new ArrayInstance(id, stack, type, numElements,
+            data);
+
+        array.setHeap(mState.mCurrentHeap);
+        mState.addInstance(id, array);
+
+        return mIdSize + 4 + 4 + 1 + totalBytes;
+    }
+
+    private int loadJniMonitor() throws IOException {
+        long id = readId();
+        int threadSerialNumber = mInput.readInt();
+        int stackDepth = mInput.readInt();
+        ThreadObj thread = mState.getThread(threadSerialNumber);
+        StackTrace trace = mState.getStackTraceAtDepth(thread.mStackTrace,
+            stackDepth);
+        RootObj root = new RootObj(RootType.NATIVE_MONITOR, id,
+            threadSerialNumber, trace);
+
+        root.setHeap(mState.mCurrentHeap);
+        mState.addRoot(root);
+
+        return mIdSize + 4 + 4;
+    }
+
+    private int skipValue() throws IOException {
+        int type = mInput.readUnsignedByte();
+        int size = Types.getTypeSize(type);
+
+        skipFully(size);
+
+        return size + 1;
+    }
+
+    /*
+     * BufferedInputStream will not skip(int) the entire requested number
+     * of bytes if it extends past the current buffer boundary.  So, this
+     * routine is needed to actually skip over the requested number of bytes
+     * using as many iterations as needed.
+     */
+    private void skipFully(long numBytes) throws IOException {
+        while (numBytes > 0) {
+            long skipped = mInput.skip(numBytes);
+
+            numBytes -= skipped;
+        }
+    }
+}
diff --git a/hit/src/com/android/hit/Instance.java b/hit/src/com/android/hit/Instance.java
new file mode 100644
index 0000000..6afa2b2
--- /dev/null
+++ b/hit/src/com/android/hit/Instance.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class Instance {
+    long mId;
+
+    //  Id of the ClassObj of which this object is an instance
+    long mClassId;
+
+    //  The stack in which this object was allocated
+    StackTrace mStack;
+
+    //  The heap in which this object was allocated (app, zygote, etc)
+    Heap mHeap;
+
+    //  The size of this object
+    int mSize;
+
+    public interface Filter {
+        public boolean accept(Instance instance);
+    }
+
+    //  List of all objects that hold a live reference to this object
+    private ArrayList<Instance> mParents;
+
+    /*
+     * After the whole HPROF file is read and parsed this method will be
+     * called on all heap objects so that they can resolve their internal
+     * object references.
+     *
+     * The super-State is passed in because some object references (such
+     * as interned Strings and static class fields) may need to be searched
+     * for in a heap other than the one this Instance is in.
+     */
+    public abstract void resolveReferences(State state);
+
+    /*
+     * Some operations require gathering all the objects in a given section
+     * of the object graph.  If non-null, the filter is applied to each
+     * node in the graph to determine if it should be added to the result
+     * set.
+     */
+    public abstract void visit(Set<Instance> resultSet, Filter filter);
+
+    public void setSize(int size) {
+        mSize = size;
+    }
+
+    public final int getCompositeSize() {
+        HashSet<Instance> set = new HashSet<Instance>();
+
+        visit(set, null);
+
+        int size = 0;
+
+        for (Instance instance: set) {
+            size += instance.getSize();
+        }
+
+        return size;
+    }
+
+    //  Returns the instrinsic size of a given object
+    public int getSize() {
+        return mSize;
+    }
+
+    public abstract String getTypeName();
+
+    public void setHeap(Heap heap) {
+        mHeap = heap;
+    }
+
+    //  Add to the list of objects that have a hard reference to this Instance
+    public void addParent(Instance parent) {
+        if (mParents == null) {
+            mParents = new ArrayList<Instance>();
+        }
+
+        mParents.add(parent);
+    }
+
+    public ArrayList<Instance> getParents() {
+        if (mParents == null) {
+            mParents = new ArrayList<Instance>();
+        }
+
+        return mParents;
+    }
+
+    /*
+     * If this object has a reference to the object identified by id, return
+     * a String describing the reference in detail.
+     */
+    public String describeReferenceTo(long id) {
+        return "No reference to 0x" + Long.toHexString(id);
+    }
+}
diff --git a/hit/src/com/android/hit/Main.java b/hit/src/com/android/hit/Main.java
new file mode 100644
index 0000000..4ed5c11
--- /dev/null
+++ b/hit/src/com/android/hit/Main.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.util.Map;
+import java.util.Set;
+
+public class Main
+{
+    public static void main(String argv[]) {
+        FileInputStream fis;
+        BufferedInputStream bis;
+        DataInputStream dis;
+
+        try {
+            fis = new FileInputStream(argv[0]);
+            bis = new BufferedInputStream(fis);
+            dis = new DataInputStream(bis);
+
+            State state = (new HprofParser(dis)).parse();
+
+            dis.close();
+
+            testClassesQuery(state);
+            testAllClassesQuery(state);
+            testFindInstancesOf(state);
+            testFindAllInstancesOf(state);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static void testClassesQuery(State state) {
+        String[] x = new String[] {
+            "char[",
+            "javax.",
+            "org.xml.sax"
+        };
+
+        Map<String, Set<ClassObj>> someClasses = Queries.classes(state, x);
+
+        for (String thePackage: someClasses.keySet()) {
+            System.out.println("------------------- " + thePackage);
+
+            Set<ClassObj> classes = someClasses.get(thePackage);
+
+            for (ClassObj theClass: classes) {
+                System.out.println("     " + theClass.mClassName);
+            }
+        }
+    }
+
+    private static void testAllClassesQuery(State state) {
+        Map<String, Set<ClassObj>> allClasses = Queries.allClasses(state);
+
+        for (String thePackage: allClasses.keySet()) {
+            System.out.println("------------------- " + thePackage);
+
+            Set<ClassObj> classes = allClasses.get(thePackage);
+
+            for (ClassObj theClass: classes) {
+                System.out.println("     " + theClass.mClassName);
+            }
+        }
+    }
+
+    private static void testFindInstancesOf(State state) {
+        Instance[] instances = Queries.instancesOf(state, "java.lang.String");
+
+        System.out.println("There are " + instances.length + " Strings.");
+    }
+
+    private static void testFindAllInstancesOf(State state) {
+        Instance[] instances = Queries.allInstancesOf(state,
+            "android.graphics.drawable.Drawable");
+
+        System.out.println("There are " + instances.length
+            + " instances of Drawables and its subclasses.");
+    }
+}
diff --git a/hit/src/com/android/hit/Queries.java b/hit/src/com/android/hit/Queries.java
new file mode 100644
index 0000000..0dac796
--- /dev/null
+++ b/hit/src/com/android/hit/Queries.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+public class Queries {
+    /*
+     * NOTES:  Here's a list of the queries that can be done in hat and
+     * how you'd perform a similar query here in hit:
+     *
+     * hat                      hit
+     * ------------------------------------------------------------------------
+     * allClasses               classes
+     * allClassesWithPlatform   allClasses
+     * class                    findClass
+     * instances                instancesOf
+     * allInstances             allInstancesOf
+     * object                   findObject
+     * showRoots                getRoots
+     * newInstances             newInstances
+     *
+     * reachableFrom            make a call to findObject to get the target
+     *                          parent object, this will give you an Instance.
+     *                          Then call visit(Set, Filter) on that to have
+     *                          it build the set of objects in its subgraph.
+     *
+     * rootsTo                  make a call to findObject on the leaf node
+     *                          in question, this will give you an Instance.
+     *                          Instances have an ArrayList of all of the
+     *                          parent objects that refer to it.  You can
+     *                          follow those parent links until you hit an
+     *                          object whose parent is null or a ThreadObj.
+     *                          You've not successfully traced the paths to
+     *                          the roots.
+     */
+
+    private static final String DEFAULT_PACKAGE = "<default>";
+
+    /*
+     * Produce a collection of all classes, broken down by package.
+     * The keys of the resultant map iterate in sorted package order.
+     * The values of the map are the classes defined in each package.
+     */
+    public static Map<String, Set<ClassObj>> allClasses(State state) {
+        return classes(state, null);
+    }
+
+    public static Map<String, Set<ClassObj>> classes(State state,
+            String[] excludedPrefixes) {
+        TreeMap<String, Set<ClassObj>> result =
+        new TreeMap<String, Set<ClassObj>>();
+
+        Set<ClassObj> classes = new TreeSet<ClassObj>();
+
+        //  Build a set of all classes across all heaps
+        for (Heap heap: state.mHeaps.values()) {
+            classes.addAll(heap.mClassesById.values());
+        }
+
+        //  Filter it if needed
+        if (excludedPrefixes != null) {
+            final int N = excludedPrefixes.length;
+            Iterator<ClassObj> iter = classes.iterator();
+
+            while (iter.hasNext()) {
+                ClassObj theClass = iter.next();
+                String classPath = theClass.toString();
+
+                for (int i = 0; i < N; i++) {
+                    if (classPath.startsWith(excludedPrefixes[i])) {
+                        iter.remove();
+                        break;
+                    }
+                }
+            }
+        }
+
+        //  Now that we have a final list of classes, group them by package
+        for (ClassObj theClass: classes) {
+            String packageName = DEFAULT_PACKAGE;
+            int lastDot = theClass.mClassName.lastIndexOf('.');
+
+            if (lastDot != -1) {
+                packageName = theClass.mClassName.substring(0, lastDot);
+            }
+
+            Set<ClassObj> classSet = result.get(packageName);
+
+            if (classSet == null) {
+                classSet = new TreeSet<ClassObj>();
+                result.put(packageName, classSet);
+            }
+
+            classSet.add(theClass);
+        }
+
+        return result;
+    }
+
+    /*
+     * It's sorta sad that this is a pass-through call, but it seems like
+     * having all of the hat-like query methods in one place is a good thing
+     * even if there is duplication of effort.
+     */
+    public static ClassObj findClass(State state, String name) {
+        return state.findClass(name);
+    }
+
+    /*
+     * Return an array of instances of the given class.  This does not include
+     * instances of subclasses.
+     */
+     public static Instance[] instancesOf(State state, String baseClassName) {
+         ClassObj theClass = state.findClass(baseClassName);
+
+         if (theClass == null) {
+             throw new IllegalArgumentException("Class not found: "
+                + baseClassName);
+         }
+
+         Instance[] instances = new Instance[theClass.mInstances.size()];
+
+         return theClass.mInstances.toArray(instances);
+     }
+
+    /*
+     * Return an array of instances of the given class.  This includes
+     * instances of subclasses.
+     */
+    public static Instance[] allInstancesOf(State state, String baseClassName) {
+        ClassObj theClass = state.findClass(baseClassName);
+
+        if (theClass == null) {
+            throw new IllegalArgumentException("Class not found: "
+                + baseClassName);
+        }
+
+        ArrayList<ClassObj> classList = new ArrayList<ClassObj>();
+
+        classList.add(theClass);
+        classList.addAll(traverseSubclasses(theClass));
+
+        ArrayList<Instance> instanceList = new ArrayList<Instance>();
+
+        for (ClassObj someClass: classList) {
+            instanceList.addAll(someClass.mInstances);
+        }
+
+        Instance[] result = new Instance[instanceList.size()];
+
+        instanceList.toArray(result);
+
+        return result;
+    }
+
+    private static ArrayList<ClassObj> traverseSubclasses(ClassObj base) {
+        ArrayList<ClassObj> result = new ArrayList<ClassObj>();
+
+        for (ClassObj subclass: base.mSubclasses) {
+            result.add(subclass);
+            result.addAll(traverseSubclasses(subclass));
+        }
+
+        return result;
+    }
+
+    /*
+     * Find a reference to an object based on its id.  The id should be
+     * in hexadecimal.
+     */
+    public static Instance findObject(State state, String id) {
+        long id2 = Long.parseLong(id, 16);
+
+        return state.findReference(id2);
+    }
+
+    public static Collection<RootObj> getRoots(State state) {
+        HashSet<RootObj> result = new HashSet<RootObj>();
+
+        for (Heap heap: state.mHeaps.values()) {
+            result.addAll(heap.mRoots);
+        }
+
+        return result;
+    }
+
+    public static final Instance[] newInstances(State older, State newer) {
+        ArrayList<Instance> resultList = new ArrayList<Instance>();
+
+        for (Heap newHeap: newer.mHeaps.values()) {
+            Heap oldHeap = older.getHeap(newHeap.mName);
+
+            if (oldHeap == null) {
+                continue;
+            }
+
+            for (Instance instance: newHeap.mInstances.values()) {
+                Instance oldInstance = oldHeap.getInstance(instance.mId);
+
+                /*
+                 * If this instance wasn't in the old heap, or was there,
+                 * but that ID was for an obj of a different type, then we have
+                 * a newly allocated object and we should report it in the
+                 * results.
+                 */
+                if ((oldInstance == null)
+                        || (instance.mClassId != oldInstance.mClassId)) {
+                    resultList.add(instance);
+                }
+            }
+        }
+
+        Instance[] resultArray = new Instance[resultList.size()];
+
+        return resultList.toArray(resultArray);
+    }
+}
diff --git a/hit/src/com/android/hit/RootObj.java b/hit/src/com/android/hit/RootObj.java
new file mode 100644
index 0000000..a9acd35
--- /dev/null
+++ b/hit/src/com/android/hit/RootObj.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.util.Set;
+
+public class RootObj extends Instance {
+    RootType mType = RootType.UNKNOWN;
+    int mIndex;
+    int mThread;
+
+    /*
+     * These two fields are only used by roots that are static
+     * fields of class objects
+     */
+    long mParent;
+    String mComment;
+
+    public RootObj(RootType type) {
+        this(type, 0, 0, null);
+    }
+
+    public RootObj(RootType type, long id) {
+        this(type, id, 0, null);
+    }
+
+    public RootObj(RootType type, long id, int thread, StackTrace stack) {
+        mType = type;
+        mId = id;
+        mThread = thread;
+        mStack = stack;
+    }
+
+    public final String getClassName(State state) {
+        ClassObj theClass;
+
+        if (mType == RootType.SYSTEM_CLASS) {
+            theClass = state.findClass(mId);
+        } else {
+            Instance instance = state.findReference(mId);
+
+            theClass = state.findClass(instance.mClassId);
+        }
+
+        if (theClass == null) {
+            return "no class defined!!";
+        }
+
+        return theClass.mClassName;
+    }
+
+    @Override
+    public final int getSize() {
+        Instance instance = null;
+
+        if (mType == RootType.SYSTEM_CLASS) {
+            instance = mHeap.mState.findClass(mId);
+        } else {
+            instance = mHeap.mState.findReference(mId);
+        }
+
+        if (instance == null) {
+            return 0;
+        }
+
+        return instance.getSize();
+    }
+
+    @Override
+    public final void visit(Set<Instance> resultSet, Filter filter) {
+        if (resultSet.contains(this)) {
+            return;
+        }
+
+        if (filter != null) {
+            if (filter.accept(this)) {
+                resultSet.add(this);
+            }
+        } else {
+            resultSet.add(this);
+        }
+    }
+
+    @Override
+    public final void resolveReferences(State state) {
+        //  Nothing to do here
+    }
+
+    @Override
+    public final String getTypeName() {
+        return "root " + mType.getName();
+    }
+
+    public final String toString() {
+        return String.format("%s@0x08x", mType.getName(), mId);
+    }
+}
diff --git a/hit/src/com/android/hit/RootType.java b/hit/src/com/android/hit/RootType.java
new file mode 100644
index 0000000..209ed1b
--- /dev/null
+++ b/hit/src/com/android/hit/RootType.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+public enum RootType {
+    UNREACHABLE         (0, "unreachable object"),
+    INVALID_TYPE        (1, "invalid type"),
+    INTERNED_STRING     (2, "interned string"),
+    UNKNOWN             (3, "unknown"),
+    SYSTEM_CLASS        (4, "system class"),
+    VM_INTERNAL         (5, "vm internal"),
+    DEBUGGER            (6, "debugger"),
+    NATIVE_LOCAL        (7, "native local"),
+    NATIVE_STATIC       (8, "native static"),
+    THREAD_BLOCK        (9, "thread block"),
+    BUSY_MONITOR        (10, "busy monitor"),
+    NATIVE_MONITOR      (11, "native monitor"),
+    REFERENCE_CLEANUP   (12, "reference cleanup"),
+    FINALIZING          (13, "finalizing"),
+    JAVA_LOCAL          (14, "java local"),
+    NATIVE_STACK        (15, "native stack"),
+    JAVA_STATIC         (16, "java static");
+
+    private final int mType;
+    private final String mName;
+
+    RootType(int type, String name) {
+        mType = type;
+        mName = name;
+    }
+
+    public final int getType() {
+        return mType;
+    }
+
+    public final String getName() {
+        return mName;
+    }
+}
diff --git a/hit/src/com/android/hit/StackFrame.java b/hit/src/com/android/hit/StackFrame.java
new file mode 100644
index 0000000..2ae7f32
--- /dev/null
+++ b/hit/src/com/android/hit/StackFrame.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+public class StackFrame {
+    public static final int NO_LINE_NUMBER          =   0;
+    public static final int UNKNOWN_LOCATION        =   -1;
+    public static final int COMPILED_METHOD         =   -2;
+    public static final int NATIVE_METHOD           =   -3;
+
+    long mId;
+    String mMethodName;
+    String mSignature;
+    String mFilename;
+    int mSerialNumber;
+    int mLineNumber;
+
+    public StackFrame(long id, String method, String sig, String file,
+            int serial, int line) {
+        mId = id;
+        mMethodName = method;
+        mSignature = sig;
+        mFilename = file;
+        mSerialNumber = serial;
+        mLineNumber = line;
+    }
+
+    private final String lineNumberString() {
+        switch (mLineNumber) {
+            case NO_LINE_NUMBER:    return "No line number";
+            case UNKNOWN_LOCATION:  return "Unknown line number";
+            case COMPILED_METHOD:   return "Compiled method";
+            case NATIVE_METHOD:     return "Native method";
+
+            default:                return String.valueOf(mLineNumber);
+        }
+    }
+
+    public final String toString() {
+        return mMethodName
+            + mSignature.replace('/', '.')
+            + " - "
+            + mFilename + ":"
+            + lineNumberString();
+    }
+}
diff --git a/hit/src/com/android/hit/StackTrace.java b/hit/src/com/android/hit/StackTrace.java
new file mode 100644
index 0000000..53cb86d
--- /dev/null
+++ b/hit/src/com/android/hit/StackTrace.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+public class StackTrace {
+    int mSerialNumber;
+    int mThreadSerialNumber;
+    StackFrame[] mFrames;
+
+    /*
+     * For subsets of the stack frame we'll reference the parent list of frames
+     * but keep track of its offset into the parent's list of stack frame ids.
+     * This alleviates the need to constantly be duplicating subsections of the
+     * list of stack frame ids.
+     */
+    StackTrace mParent = null;
+    int mOffset = 0;
+
+    private StackTrace() {
+
+    }
+
+    public StackTrace(int serial, int thread, StackFrame[] frames) {
+        mSerialNumber = serial;
+        mThreadSerialNumber = thread;
+        mFrames = frames;
+    }
+
+    public final StackTrace fromDepth(int startingDepth) {
+        StackTrace result = new StackTrace();
+
+        if (mParent != null) {
+            result.mParent = mParent;
+        } else {
+            result.mParent = this;
+        }
+
+        result.mOffset = startingDepth + mOffset;
+
+        return result;
+    }
+
+    public final void dump() {
+        final int N = mFrames.length;
+
+        for (int i = 0; i < N; i++) {
+            System.out.println(mFrames[i].toString());
+        }
+    }
+}
diff --git a/hit/src/com/android/hit/State.java b/hit/src/com/android/hit/State.java
new file mode 100644
index 0000000..96c944d
--- /dev/null
+++ b/hit/src/com/android/hit/State.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/*
+ * State is a snapshot of all of the heaps, and related meta-data, for
+ * the runtime at a given instant.
+ *
+ * During parsing of the HPROF file HEAP_DUMP_INFO chunks change which heap
+ * is being referenced.
+ */
+public class State {
+    HashMap<Integer, Heap> mHeaps;
+    Heap mCurrentHeap;
+
+    public State() {
+        mHeaps = new HashMap<Integer, Heap>();
+        setToDefaultHeap();
+    }
+
+    public Heap setToDefaultHeap() {
+        return setHeapTo(0, "default");
+    }
+
+    public Heap setHeapTo(int id, String name) {
+        Heap heap = mHeaps.get(id);
+
+        if (heap == null) {
+            heap = new Heap(name);
+            heap.mState = this;
+            mHeaps.put(id, heap);
+        }
+
+        mCurrentHeap = heap;
+
+        return mCurrentHeap;
+    }
+
+    public Heap getHeap(int id) {
+        return mHeaps.get(id);
+    }
+
+    public Heap getHeap(String name) {
+        for (Heap heap: mHeaps.values()) {
+            if (heap.mName.equals(name)) {
+                return heap;
+            }
+        }
+
+        return null;
+    }
+
+    public final void addStackFrame(StackFrame theFrame) {
+        mCurrentHeap.addStackFrame(theFrame);
+    }
+
+    public final StackFrame getStackFrame(long id) {
+        return mCurrentHeap.getStackFrame(id);
+    }
+
+    public final void addStackTrace(StackTrace theTrace) {
+        mCurrentHeap.addStackTrace(theTrace);
+    }
+
+    public final StackTrace getStackTrace(int traceSerialNumber) {
+        return mCurrentHeap.getStackTrace(traceSerialNumber);
+    }
+
+    public final StackTrace getStackTraceAtDepth(int traceSerialNumber,
+            int depth) {
+        return mCurrentHeap.getStackTraceAtDepth(traceSerialNumber, depth);
+    }
+
+    public final void addRoot(RootObj root) {
+        mCurrentHeap.addRoot(root);
+    }
+
+    public final void addThread(ThreadObj thread, int serialNumber) {
+        mCurrentHeap.addThread(thread, serialNumber);
+    }
+
+    public final ThreadObj getThread(int serialNumber) {
+        return mCurrentHeap.getThread(serialNumber);
+    }
+
+    public final void addInstance(long id, Instance instance) {
+        mCurrentHeap.addInstance(id, instance);
+    }
+
+    public final void addClass(long id, ClassObj theClass) {
+        mCurrentHeap.addClass(id, theClass);
+    }
+
+    public final Instance findReference(long id) {
+        for (Heap heap: mHeaps.values()) {
+            Instance instance = heap.getInstance(id);
+
+            if (instance != null) {
+                return instance;
+            }
+        }
+
+        //  Couldn't find an instance of a class, look for a class object
+        return findClass(id);
+    }
+
+    public final ClassObj findClass(long id) {
+        for (Heap heap: mHeaps.values()) {
+            ClassObj theClass = heap.getClass(id);
+
+            if (theClass != null) {
+                return theClass;
+            }
+        }
+
+        return null;
+    }
+
+    public final ClassObj findClass(String name) {
+        for (Heap heap: mHeaps.values()) {
+            ClassObj theClass = heap.getClass(name);
+
+            if (theClass != null) {
+                return theClass;
+            }
+        }
+
+        return null;
+    }
+
+    public final void dumpInstanceCounts() {
+        for (Heap heap: mHeaps.values()) {
+            System.out.println(
+                "+------------------ instance counts for heap: " + heap.mName);
+            heap.dumpInstanceCounts();
+        }
+    }
+
+    public final void dumpSizes() {
+        for (Heap heap: mHeaps.values()) {
+            System.out.println(
+                "+------------------ sizes for heap: " + heap.mName);
+            heap.dumpSizes();
+        }
+    }
+
+    public final void dumpSubclasses() {
+        for (Heap heap: mHeaps.values()) {
+            System.out.println(
+                "+------------------ subclasses for heap: " + heap.mName);
+            heap.dumpSubclasses();
+        }
+    }
+
+    public final void resolveReferences() {
+        for (Heap heap: mHeaps.values()) {
+            heap.resolveInstanceRefs(this);
+            heap.resolveClassStatics(this);
+            heap.resolveRoots(this);
+        }
+    }
+}
diff --git a/hit/src/com/android/hit/ThreadObj.java b/hit/src/com/android/hit/ThreadObj.java
new file mode 100644
index 0000000..32a73f0
--- /dev/null
+++ b/hit/src/com/android/hit/ThreadObj.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+public class ThreadObj {
+    long mId;
+    int mStackTrace;
+
+    public ThreadObj(long id, int stackTrace) {
+        mId = id;
+        mStackTrace = stackTrace;
+    }
+}
diff --git a/hit/src/com/android/hit/Types.java b/hit/src/com/android/hit/Types.java
new file mode 100644
index 0000000..62228ce
--- /dev/null
+++ b/hit/src/com/android/hit/Types.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.hit;
+
+public class Types {
+    private static int mIdSize = 4;
+
+    public static final int OBJECT     =   2;
+    public static final int BOOLEAN    =   4;
+    public static final int CHAR       =   5;
+    public static final int FLOAT      =   6;
+    public static final int DOUBLE     =   7;
+    public static final int BYTE       =   8;
+    public static final int SHORT      =   9;
+    public static final int INT        =   10;
+    public static final int LONG       =   11;
+
+    public static final void setIdSize(int size) {
+        mIdSize = size;
+    }
+
+    public static final int getTypeSize(int type) {
+        switch (type) {
+            case '[':      return mIdSize; //  array object
+            case 'L':      return mIdSize; //  object
+            case 'Z':      return 1;       //  boolean
+            case 'C':      return 2;       //  char
+            case 'F':      return 4;       //  float
+            case 'D':      return 8;       //  double
+            case 'B':      return 1;       //  byte
+            case 'S':      return 2;       //  short
+            case 'I':      return 4;       //  int
+            case 'J':      return 8;       //  long
+
+            case OBJECT:   return mIdSize;
+            case BOOLEAN:  return 1;
+            case CHAR:     return 2;
+            case FLOAT:    return 4;
+            case DOUBLE:   return 8;
+            case BYTE:     return 1;
+            case SHORT:    return 2;
+            case INT:      return 4;
+            case LONG:     return 8;
+        }
+
+        throw new IllegalArgumentException("Illegal type signature: " + type);
+    }
+
+    public static final String getTypeName(int type) {
+        switch (type) {
+            case '[':      return "array";
+            case 'L':      return "object";
+            case 'Z':      return "boolean";
+            case 'C':      return "char";
+            case 'F':      return "float";
+            case 'D':      return "double";
+            case 'B':      return "byte";
+            case 'S':      return "short";
+            case 'I':      return "int";
+            case 'J':      return "long";
+
+            case OBJECT:   return "object";
+            case BOOLEAN:  return "boolean";
+            case CHAR:     return "char";
+            case FLOAT:    return "float";
+            case DOUBLE:   return "double";
+            case BYTE:     return "byte";
+            case SHORT:    return "short";
+            case INT:      return "int";
+            case LONG:     return "long";
+        }
+
+        throw new IllegalArgumentException("Illegal type signature: " + type);
+    }
+}
diff --git a/hit/test/testparser b/hit/test/testparser
new file mode 100755
index 0000000..a3a722e
--- /dev/null
+++ b/hit/test/testparser
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+find ../src -name \*java | xargs javac -d build -Xlint:unchecked
+
+# debug launch line tha turns off the jit and runs a debug server
+#java -Djava.compiler=NONE -Xdebug -Xrunjdwp:transport=dt_socket,address=53635,server=y,suspend=y -cp build com.android.hit.Main ../samples/android.hprof
+
+java -cp build com.android.hit.Main ../samples/android.hprof
diff --git a/libdex/Android.mk b/libdex/Android.mk
new file mode 100644
index 0000000..bb8d03b
--- /dev/null
+++ b/libdex/Android.mk
@@ -0,0 +1,71 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+dex_src_files := \
+	CmdUtils.cpp \
+	DexCatch.cpp \
+	DexClass.cpp \
+	DexDataMap.cpp \
+	DexDebugInfo.cpp \
+	DexFile.cpp \
+	DexInlines.cpp \
+	DexOptData.cpp \
+	DexOpcodes.cpp \
+	DexProto.cpp \
+	DexSwapVerify.cpp \
+	DexUtf.cpp \
+	InstrUtils.cpp \
+	Leb128.cpp \
+	OptInvocation.cpp \
+	sha1.cpp \
+	SysUtil.cpp \
+	ZipArchive.cpp
+
+dex_include_files := \
+	dalvik \
+	$(JNI_H_INCLUDE) \
+	external/zlib \
+	external/safe-iop/include
+
+##
+##
+## Build the device version of libdex
+##
+##
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+
+include $(CLEAR_VARS)
+#LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1
+LOCAL_SRC_FILES := $(dex_src_files)
+LOCAL_C_INCLUDES += $(dex_include_files)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libdex
+include $(BUILD_STATIC_LIBRARY)
+
+endif # !SDK_ONLY
+
+
+##
+##
+## Build the host version of libdex
+##
+##
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(dex_src_files)
+LOCAL_C_INCLUDES += $(dex_include_files)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libdex
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libdex/CmdUtils.cpp b/libdex/CmdUtils.cpp
new file mode 100644
index 0000000..ff737a3
--- /dev/null
+++ b/libdex/CmdUtils.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+/*
+ * Some utility functions for use with command-line utilities.
+ */
+#include "DexFile.h"
+#include "ZipArchive.h"
+#include "CmdUtils.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/*
+ * Extract "classes.dex" from archive file.
+ *
+ * If "quiet" is set, don't report common errors.
+ */
+UnzipToFileResult dexUnzipToFile(const char* zipFileName,
+    const char* outFileName, bool quiet)
+{
+    UnzipToFileResult result = kUTFRSuccess;
+    static const char* kFileToExtract = "classes.dex";
+    ZipArchive archive;
+    ZipEntry entry;
+    bool unlinkOnFailure = false;
+    int fd = -1;
+
+    if (dexZipOpenArchive(zipFileName, &archive) != 0) {
+        if (!quiet) {
+            fprintf(stderr, "Unable to open '%s' as zip archive\n",
+                zipFileName);
+        }
+        result = kUTFRNotZip;
+        goto bail;
+    }
+
+    fd = open(outFileName, O_WRONLY | O_CREAT | O_EXCL, 0600);
+    if (fd < 0) {
+        fprintf(stderr, "Unable to create output file '%s': %s\n",
+            outFileName, strerror(errno));
+        result = kUTFROutputFileProblem;
+        goto bail;
+    }
+
+    unlinkOnFailure = true;
+
+    entry = dexZipFindEntry(&archive, kFileToExtract);
+    if (entry == NULL) {
+        if (!quiet) {
+            fprintf(stderr, "Unable to find '%s' in '%s'\n",
+                kFileToExtract, zipFileName);
+        }
+        result = kUTFRNoClassesDex;
+        goto bail;
+    }
+
+    if (dexZipExtractEntryToFile(&archive, entry, fd) != 0) {
+        fprintf(stderr, "Extract of '%s' from '%s' failed\n",
+            kFileToExtract, zipFileName);
+        result = kUTFRBadZip;
+        goto bail;
+    }
+
+bail:
+    if (fd >= 0)
+        close(fd);
+    if (unlinkOnFailure && result != kUTFRSuccess)
+        unlink(outFileName);
+    dexZipCloseArchive(&archive);
+    return result;
+}
+
+/*
+ * Map the specified DEX file read-only (possibly after expanding it into a
+ * temp file from a Jar).  Pass in a MemMapping struct to hold the info.
+ * If the file is an unoptimized DEX file, then byte-swapping and structural
+ * verification are performed on it before the memory is made read-only.
+ *
+ * The temp file is deleted after the map succeeds.
+ *
+ * This is intended for use by tools (e.g. dexdump) that need to get a
+ * read-only copy of a DEX file that could be in a number of different states.
+ *
+ * If "tempFileName" is NULL, a default value is used.  The temp file is
+ * deleted after the map succeeds.
+ *
+ * If "quiet" is set, don't report common errors.
+ *
+ * Returns 0 (kUTFRSuccess) on success.
+ */
+UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName,
+    MemMapping* pMap, bool quiet)
+{
+    UnzipToFileResult result = kUTFRGenericFailure;
+    int len = strlen(fileName);
+    char tempNameBuf[32];
+    bool removeTemp = false;
+    int fd = -1;
+
+    if (len < 5) {
+        if (!quiet) {
+            fprintf(stderr,
+                "ERROR: filename must end in .dex, .zip, .jar, or .apk\n");
+        }
+        result = kUTFRBadArgs;
+        goto bail;
+    }
+
+    if (strcasecmp(fileName + len -3, "dex") != 0) {
+        if (tempFileName == NULL) {
+            /*
+             * Try .zip/.jar/.apk, all of which are Zip archives with
+             * "classes.dex" inside.  We need to extract the compressed
+             * data to a temp file, the location of which varies.
+             *
+             * On the device we must use /sdcard because most other
+             * directories aren't writable (either because of permissions
+             * or because the volume is mounted read-only).  On desktop
+             * it's nice to use the designated temp directory.
+             */
+            if (access("/tmp", W_OK) == 0) {
+                sprintf(tempNameBuf, "/tmp/dex-temp-%d", getpid());
+            } else if (access("/sdcard", W_OK) == 0) {
+                sprintf(tempNameBuf, "/sdcard/dex-temp-%d", getpid());
+            } else {
+                fprintf(stderr,
+                    "NOTE: /tmp and /sdcard unavailable for temp files\n");
+                sprintf(tempNameBuf, "dex-temp-%d", getpid());
+            }
+
+            tempFileName = tempNameBuf;
+        }
+
+        result = dexUnzipToFile(fileName, tempFileName, quiet);
+
+        if (result == kUTFRSuccess) {
+            //printf("+++ Good unzip to '%s'\n", tempFileName);
+            fileName = tempFileName;
+            removeTemp = true;
+        } else if (result == kUTFRNotZip) {
+            if (!quiet) {
+                fprintf(stderr, "Not Zip, retrying as DEX\n");
+            }
+        } else {
+            if (!quiet && result == kUTFRNoClassesDex) {
+                fprintf(stderr, "Zip has no classes.dex\n");
+            }
+            goto bail;
+        }
+    }
+
+    result = kUTFRGenericFailure;
+
+    /*
+     * Pop open the (presumed) DEX file.
+     */
+    fd = open(fileName, O_RDONLY | O_BINARY);
+    if (fd < 0) {
+        if (!quiet) {
+            fprintf(stderr, "ERROR: unable to open '%s': %s\n",
+                fileName, strerror(errno));
+        }
+        goto bail;
+    }
+
+    if (sysMapFileInShmemWritableReadOnly(fd, pMap) != 0) {
+        fprintf(stderr, "ERROR: Unable to map '%s'\n", fileName);
+        goto bail;
+    }
+
+    /*
+     * This call will fail if the file exists on a filesystem that
+     * doesn't support mprotect(). If that's the case, then the file
+     * will have already been mapped private-writable by the previous
+     * call, so we don't need to do anything special if this call
+     * returns non-zero.
+     */
+    sysChangeMapAccess(pMap->addr, pMap->length, true, pMap);
+
+    if (dexSwapAndVerifyIfNecessary((u1*) pMap->addr, pMap->length)) {
+        fprintf(stderr, "ERROR: Failed structural verification of '%s'\n",
+            fileName);
+        goto bail;
+    }
+
+    /*
+     * Similar to above, this call will fail if the file wasn't ever
+     * read-only to begin with. This is innocuous, though it is
+     * undesirable from a memory hygiene perspective.
+     */
+    sysChangeMapAccess(pMap->addr, pMap->length, false, pMap);
+
+    /*
+     * Success!  Close the file and return with the start/length in pMap.
+     */
+    result = kUTFRSuccess;
+
+bail:
+    if (fd >= 0)
+        close(fd);
+    if (removeTemp) {
+        /* this will fail if the OS doesn't allow removal of a mapped file */
+        if (unlink(tempFileName) != 0) {
+            fprintf(stderr, "WARNING: unable to remove temp '%s'\n",
+                tempFileName);
+        }
+    }
+    return result;
+}
diff --git a/libdex/CmdUtils.h b/libdex/CmdUtils.h
new file mode 100644
index 0000000..887eed9
--- /dev/null
+++ b/libdex/CmdUtils.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+/*
+ * Access .dex (Dalvik Executable Format) files.  The code here assumes that
+ * the DEX file has been rewritten (byte-swapped, word-aligned) and that
+ * the contents can be directly accessed as a collection of C arrays.  Please
+ * see docs/dalvik/dex-format.html for a detailed description.
+ *
+ * The structure and field names were chosen to match those in the DEX spec.
+ *
+ * It's generally assumed that the DEX file will be stored in shared memory,
+ * obviating the need to copy code and constant pool entries into newly
+ * allocated storage.  Maintaining local pointers to items in the shared area
+ * is valid and encouraged.
+ *
+ * All memory-mapped structures are 32-bit aligned unless otherwise noted.
+ */
+#ifndef LIBDEX_CMDUTILS_H_
+#define LIBDEX_CMDUTILS_H_
+
+/* encode the result of unzipping to a file */
+enum UnzipToFileResult {
+    kUTFRSuccess = 0,
+    kUTFRGenericFailure,
+    kUTFRBadArgs,
+    kUTFRNotZip,
+    kUTFRNoClassesDex,
+    kUTFROutputFileProblem,
+    kUTFRBadZip,
+};
+
+/*
+ * Map the specified DEX file read-only (possibly after expanding it into a
+ * temp file from a Jar).  Pass in a MemMapping struct to hold the info.
+ * If the file is an unoptimized DEX file, then byte-swapping and structural
+ * verification are performed on it before the memory is made read-only.
+ *
+ * The temp file is deleted after the map succeeds.
+ *
+ * This is intended for use by tools (e.g. dexdump) that need to get a
+ * read-only copy of a DEX file that could be in a number of different states.
+ *
+ * If "tempFileName" is NULL, a default value is used.  The temp file is
+ * deleted after the map succeeds.
+ *
+ * If "quiet" is set, don't report common errors.
+ *
+ * Returns 0 (kUTFRSuccess) on success.
+ */
+UnzipToFileResult dexOpenAndMap(const char* fileName, const char* tempFileName,
+    MemMapping* pMap, bool quiet);
+
+/*
+ * Utility function to open a Zip archive, find "classes.dex", and extract
+ * it to a file.
+ */
+UnzipToFileResult dexUnzipToFile(const char* zipFileName,
+    const char* outFileName, bool quiet);
+
+#endif  // LIBDEX_CMDUTILS_H_
diff --git a/libdex/DexCatch.cpp b/libdex/DexCatch.cpp
new file mode 100644
index 0000000..ed97e87
--- /dev/null
+++ b/libdex/DexCatch.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions for dealing with try-catch info.
+ */
+
+#include "DexCatch.h"
+
+/* Get the first handler offset for the given DexCode.
+ * It's not 0 because the handlers list is prefixed with its size
+ * (in entries) as a uleb128. */
+u4 dexGetFirstHandlerOffset(const DexCode* pCode) {
+    if (pCode->triesSize == 0) {
+        return 0;
+    }
+
+    const u1* baseData = dexGetCatchHandlerData(pCode);
+    const u1* data = baseData;
+
+    readUnsignedLeb128(&data);
+
+    return data - baseData;
+}
+
+/* Get count of handler lists for the given DexCode. */
+u4 dexGetHandlersSize(const DexCode* pCode) {
+    if (pCode->triesSize == 0) {
+        return 0;
+    }
+
+    const u1* data = dexGetCatchHandlerData(pCode);
+
+    return readUnsignedLeb128(&data);
+}
+
+/* Helper for dexFindCatchHandlerOffset(), which does an actual search
+ * in the tries table. Returns -1 if there is no applicable handler. */
+int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries,
+        u4 address) {
+    // Note: Signed type is important for max and min.
+    int min = 0;
+    int max = triesSize - 1;
+
+    while (max >= min) {
+        int guess = (min + max) >> 1;
+        const DexTry* pTry = &pTries[guess];
+        u4 start = pTry->startAddr;
+
+        if (address < start) {
+            max = guess - 1;
+            continue;
+        }
+
+        u4 end = start + pTry->insnCount;
+
+        if (address >= end) {
+            min = guess + 1;
+            continue;
+        }
+
+        // We have a winner!
+        return (int) pTry->handlerOff;
+    }
+
+    // No match.
+    return -1;
+}
+
+/* Get the handler offset just past the end of the one just iterated over.
+ * This ends the iteration if it wasn't already. */
+u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator,
+        const DexCode* pCode) {
+    while (dexCatchIteratorNext(pIterator) != NULL) /* empty */ ;
+
+    return (u4) (pIterator->pEncodedData - dexGetCatchHandlerData(pCode));
+}
diff --git a/libdex/DexCatch.h b/libdex/DexCatch.h
new file mode 100644
index 0000000..cfea2d9
--- /dev/null
+++ b/libdex/DexCatch.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions for dealing with try-catch info.
+ */
+
+#ifndef LIBDEX_DEXCATCH_H_
+#define LIBDEX_DEXCATCH_H_
+
+#include "DexFile.h"
+#include "Leb128.h"
+
+/*
+ * Catch handler entry, used while iterating over catch_handler_items.
+ */
+struct DexCatchHandler {
+    u4          typeIdx;    /* type index of the caught exception type */
+    u4          address;    /* handler address */
+};
+
+/* Get the first handler offset for the given DexCode.
+ * It's not 0 because the handlers list is prefixed with its size
+ * (in entries) as a uleb128. */
+u4 dexGetFirstHandlerOffset(const DexCode* pCode);
+
+/* Get count of handler lists for the given DexCode. */
+u4 dexGetHandlersSize(const DexCode* pCode);
+
+/*
+ * Iterator over catch handler data. This structure should be treated as
+ * opaque.
+ */
+struct DexCatchIterator {
+    const u1* pEncodedData;
+    bool catchesAll;
+    u4 countRemaining;
+    DexCatchHandler handler;
+};
+
+/* Initialize a DexCatchIterator to emptiness. This mostly exists to
+ * squelch innocuous warnings. */
+DEX_INLINE void dexCatchIteratorClear(DexCatchIterator* pIterator) {
+    pIterator->pEncodedData = NULL;
+    pIterator->catchesAll = false;
+    pIterator->countRemaining = 0;
+    pIterator->handler.typeIdx = 0;
+    pIterator->handler.address = 0;
+}
+
+/* Initialize a DexCatchIterator with a direct pointer to encoded handlers. */
+DEX_INLINE void dexCatchIteratorInitToPointer(DexCatchIterator* pIterator,
+    const u1* pEncodedData)
+{
+    s4 count = readSignedLeb128(&pEncodedData);
+
+    if (count <= 0) {
+        pIterator->catchesAll = true;
+        count = -count;
+    } else {
+        pIterator->catchesAll = false;
+    }
+
+    pIterator->pEncodedData = pEncodedData;
+    pIterator->countRemaining = count;
+}
+
+/* Initialize a DexCatchIterator to a particular handler offset. */
+DEX_INLINE void dexCatchIteratorInit(DexCatchIterator* pIterator,
+    const DexCode* pCode, u4 offset)
+{
+    dexCatchIteratorInitToPointer(pIterator,
+            dexGetCatchHandlerData(pCode) + offset);
+}
+
+/* Get the next item from a DexCatchIterator. Returns NULL if at end. */
+DEX_INLINE DexCatchHandler* dexCatchIteratorNext(DexCatchIterator* pIterator) {
+    if (pIterator->countRemaining == 0) {
+        if (! pIterator->catchesAll) {
+            return NULL;
+        }
+
+        pIterator->catchesAll = false;
+        pIterator->handler.typeIdx = kDexNoIndex;
+    } else {
+        u4 typeIdx = readUnsignedLeb128(&pIterator->pEncodedData);
+        pIterator->handler.typeIdx = typeIdx;
+        pIterator->countRemaining--;
+    }
+
+    pIterator->handler.address = readUnsignedLeb128(&pIterator->pEncodedData);
+    return &pIterator->handler;
+}
+
+/* Get the handler offset just past the end of the one just iterated over.
+ * This ends the iteration if it wasn't already. */
+u4 dexCatchIteratorGetEndOffset(DexCatchIterator* pIterator,
+    const DexCode* pCode);
+
+/* Helper for dexFindCatchHandler(). Do not call directly. */
+int dexFindCatchHandlerOffset0(u2 triesSize, const DexTry* pTries,
+        u4 address);
+
+/* Find the handler associated with a given address, if any.
+ * Initializes the given iterator and returns true if a match is
+ * found. Returns false if there is no applicable handler. */
+DEX_INLINE bool dexFindCatchHandler(DexCatchIterator *pIterator,
+        const DexCode* pCode, u4 address) {
+    u2 triesSize = pCode->triesSize;
+    int offset = -1;
+
+    // Short-circuit the overwhelmingly common cases.
+    switch (triesSize) {
+        case 0: {
+            break;
+        }
+        case 1: {
+            const DexTry* tries = dexGetTries(pCode);
+            u4 start = tries[0].startAddr;
+
+            if (address < start) {
+                break;
+            }
+
+            u4 end = start + tries[0].insnCount;
+
+            if (address >= end) {
+                break;
+            }
+
+            offset = tries[0].handlerOff;
+            break;
+        }
+        default: {
+            offset = dexFindCatchHandlerOffset0(triesSize, dexGetTries(pCode),
+                    address);
+        }
+    }
+
+    if (offset < 0) {
+        dexCatchIteratorClear(pIterator); // This squelches warnings.
+        return false;
+    } else {
+        dexCatchIteratorInit(pIterator, pCode, offset);
+        return true;
+    }
+}
+
+#endif  // LIBDEX_DEXCATCH_H_
diff --git a/libdex/DexClass.cpp b/libdex/DexClass.cpp
new file mode 100644
index 0000000..552229c
--- /dev/null
+++ b/libdex/DexClass.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions to deal with class definition structures in DEX files
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "DexClass.h"
+#include "Leb128.h"
+
+/* Helper for verification which reads and verifies a given number
+ * of uleb128 values. */
+static bool verifyUlebs(const u1* pData, const u1* pLimit, u4 count) {
+    bool okay = true;
+    u4 i;
+
+    while (okay && (count-- != 0)) {
+        readAndVerifyUnsignedLeb128(&pData, pLimit, &okay);
+    }
+
+    return okay;
+}
+
+/* Read and verify the header of a class_data_item. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure). */
+bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit,
+        DexClassDataHeader *pHeader) {
+    if (! verifyUlebs(*pData, pLimit, 4)) {
+        return false;
+    }
+
+    dexReadClassDataHeader(pData, pHeader);
+    return true;
+}
+
+/* Read and verify an encoded_field. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first field in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags or indices
+ * are valid. */
+bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit,
+        DexField* pField, u4* lastIndex) {
+    if (! verifyUlebs(*pData, pLimit, 2)) {
+        return false;
+    }
+
+    dexReadClassDataField(pData, pField, lastIndex);
+    return true;
+}
+
+/* Read and verify an encoded_method. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first method in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit,
+        DexMethod* pMethod, u4* lastIndex) {
+    if (! verifyUlebs(*pData, pLimit, 3)) {
+        return false;
+    }
+
+    dexReadClassDataMethod(pData, pMethod, lastIndex);
+    return true;
+}
+
+/* Read, verify, and return an entire class_data_item. This updates
+ * the given data pointer to point past the end of the read data. This
+ * function allocates a single chunk of memory for the result, which
+ * must subsequently be free()d. This function returns NULL if there
+ * was trouble parsing the data. If this function is passed NULL, it
+ * returns an initialized empty DexClassData structure.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit) {
+    DexClassDataHeader header;
+    u4 lastIndex;
+
+    if (*pData == NULL) {
+        DexClassData* result = (DexClassData*) malloc(sizeof(DexClassData));
+        memset(result, 0, sizeof(*result));
+        return result;
+    }
+
+    if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) {
+        return NULL;
+    }
+
+    size_t resultSize = sizeof(DexClassData) +
+        (header.staticFieldsSize * sizeof(DexField)) +
+        (header.instanceFieldsSize * sizeof(DexField)) +
+        (header.directMethodsSize * sizeof(DexMethod)) +
+        (header.virtualMethodsSize * sizeof(DexMethod));
+
+    DexClassData* result = (DexClassData*) malloc(resultSize);
+    u1* ptr = ((u1*) result) + sizeof(DexClassData);
+    bool okay = true;
+    u4 i;
+
+    if (result == NULL) {
+        return NULL;
+    }
+
+    result->header = header;
+
+    if (header.staticFieldsSize != 0) {
+        result->staticFields = (DexField*) ptr;
+        ptr += header.staticFieldsSize * sizeof(DexField);
+    } else {
+        result->staticFields = NULL;
+    }
+
+    if (header.instanceFieldsSize != 0) {
+        result->instanceFields = (DexField*) ptr;
+        ptr += header.instanceFieldsSize * sizeof(DexField);
+    } else {
+        result->instanceFields = NULL;
+    }
+
+    if (header.directMethodsSize != 0) {
+        result->directMethods = (DexMethod*) ptr;
+        ptr += header.directMethodsSize * sizeof(DexMethod);
+    } else {
+        result->directMethods = NULL;
+    }
+
+    if (header.virtualMethodsSize != 0) {
+        result->virtualMethods = (DexMethod*) ptr;
+    } else {
+        result->virtualMethods = NULL;
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.staticFieldsSize); i++) {
+        okay = dexReadAndVerifyClassDataField(pData, pLimit,
+                &result->staticFields[i], &lastIndex);
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.instanceFieldsSize); i++) {
+        okay = dexReadAndVerifyClassDataField(pData, pLimit,
+                &result->instanceFields[i], &lastIndex);
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.directMethodsSize); i++) {
+        okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
+                &result->directMethods[i], &lastIndex);
+    }
+
+    lastIndex = 0;
+    for (i = 0; okay && (i < header.virtualMethodsSize); i++) {
+        okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
+                &result->virtualMethods[i], &lastIndex);
+    }
+
+    if (! okay) {
+        free(result);
+        return NULL;
+    }
+
+    return result;
+}
diff --git a/libdex/DexClass.h b/libdex/DexClass.h
new file mode 100644
index 0000000..11b3b0e
--- /dev/null
+++ b/libdex/DexClass.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions to deal with class definition structures in DEX files
+ */
+
+#ifndef LIBDEX_DEXCLASS_H_
+#define LIBDEX_DEXCLASS_H_
+
+#include "DexFile.h"
+#include "Leb128.h"
+
+/* expanded form of a class_data_item header */
+struct DexClassDataHeader {
+    u4 staticFieldsSize;
+    u4 instanceFieldsSize;
+    u4 directMethodsSize;
+    u4 virtualMethodsSize;
+};
+
+/* expanded form of encoded_field */
+struct DexField {
+    u4 fieldIdx;    /* index to a field_id_item */
+    u4 accessFlags;
+};
+
+/* expanded form of encoded_method */
+struct DexMethod {
+    u4 methodIdx;    /* index to a method_id_item */
+    u4 accessFlags;
+    u4 codeOff;      /* file offset to a code_item */
+};
+
+/* expanded form of class_data_item. Note: If a particular item is
+ * absent (e.g., no static fields), then the corresponding pointer
+ * is set to NULL. */
+struct DexClassData {
+    DexClassDataHeader header;
+    DexField*          staticFields;
+    DexField*          instanceFields;
+    DexMethod*         directMethods;
+    DexMethod*         virtualMethods;
+};
+
+/* Read and verify the header of a class_data_item. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure). */
+bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit,
+        DexClassDataHeader *pHeader);
+
+/* Read and verify an encoded_field. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first field in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags or indices
+ * are valid. */
+bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit,
+        DexField* pField, u4* lastIndex);
+
+/* Read and verify an encoded_method. This updates the
+ * given data pointer to point past the end of the read data and
+ * returns an "okay" flag (that is, false == failure).
+ *
+ * The lastIndex value should be set to 0 before the first method in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit,
+        DexMethod* pMethod, u4* lastIndex);
+
+/* Read, verify, and return an entire class_data_item. This updates
+ * the given data pointer to point past the end of the read data. This
+ * function allocates a single chunk of memory for the result, which
+ * must subsequently be free()d. This function returns NULL if there
+ * was trouble parsing the data. If this function is passed NULL, it
+ * returns an initialized empty DexClassData structure.
+ *
+ * The verification done by this function is of the raw data format
+ * only; it does not verify that access flags, indices, or offsets
+ * are valid. */
+DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit);
+
+/*
+ * Get the DexCode for a DexMethod.  Returns NULL if the class is native
+ * or abstract.
+ */
+DEX_INLINE const DexCode* dexGetCode(const DexFile* pDexFile,
+    const DexMethod* pDexMethod)
+{
+    if (pDexMethod->codeOff == 0)
+        return NULL;
+    return (const DexCode*) (pDexFile->baseAddr + pDexMethod->codeOff);
+}
+
+
+/* Read the header of a class_data_item without verification. This
+ * updates the given data pointer to point past the end of the read
+ * data. */
+DEX_INLINE void dexReadClassDataHeader(const u1** pData,
+        DexClassDataHeader *pHeader) {
+    pHeader->staticFieldsSize = readUnsignedLeb128(pData);
+    pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
+    pHeader->directMethodsSize = readUnsignedLeb128(pData);
+    pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
+}
+
+/* Read an encoded_field without verification. This updates the
+ * given data pointer to point past the end of the read data.
+ *
+ * The lastIndex value should be set to 0 before the first field in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ */
+DEX_INLINE void dexReadClassDataField(const u1** pData, DexField* pField,
+        u4* lastIndex) {
+    u4 index = *lastIndex + readUnsignedLeb128(pData);
+
+    pField->accessFlags = readUnsignedLeb128(pData);
+    pField->fieldIdx = index;
+    *lastIndex = index;
+}
+
+/* Read an encoded_method without verification. This updates the
+ * given data pointer to point past the end of the read data.
+ *
+ * The lastIndex value should be set to 0 before the first method in
+ * a list is read. It is updated as fields are read and used in the
+ * decode process.
+ */
+DEX_INLINE void dexReadClassDataMethod(const u1** pData, DexMethod* pMethod,
+        u4* lastIndex) {
+    u4 index = *lastIndex + readUnsignedLeb128(pData);
+
+    pMethod->accessFlags = readUnsignedLeb128(pData);
+    pMethod->codeOff = readUnsignedLeb128(pData);
+    pMethod->methodIdx = index;
+    *lastIndex = index;
+}
+
+#endif  // LIBDEX_DEXCLASS_H_
diff --git a/libdex/DexDataMap.cpp b/libdex/DexDataMap.cpp
new file mode 100644
index 0000000..3553c36
--- /dev/null
+++ b/libdex/DexDataMap.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/*
+ * Verification-time map of data section items
+ */
+
+#include "DexDataMap.h"
+#include <safe_iop.h>
+#include <stdlib.h>
+
+/*
+ * Allocate and initialize a DexDataMap. Returns NULL on failure.
+ */
+DexDataMap* dexDataMapAlloc(u4 maxCount) {
+    /*
+     * Allocate a single chunk for the DexDataMap per se as well as the
+     * two arrays.
+     */
+    size_t size = 0;
+    DexDataMap* map = NULL;
+
+    /*
+     * Avoiding pulling in safe_iop for safe_iopf.
+     */
+    if (!safe_mul(&size, maxCount, sizeof(u4) + sizeof(u2)) ||
+        !safe_add(&size, size, sizeof(DexDataMap))) {
+      return NULL;
+    }
+
+    map = (DexDataMap*) malloc(size);
+
+    if (map == NULL) {
+        return NULL;
+    }
+
+    map->count = 0;
+    map->max = maxCount;
+    map->offsets = (u4*) (map + 1);
+    map->types = (u2*) (map->offsets + maxCount);
+
+    return map;
+}
+
+/*
+ * Free a DexDataMap.
+ */
+void dexDataMapFree(DexDataMap* map) {
+    /*
+     * Since everything got allocated together, everything can be freed
+     * in one fell swoop. Also, free(NULL) is a nop (per spec), so we
+     * don't have to worry about an explicit test for that.
+     */
+    free(map);
+}
+
+/*
+ * Add a new element to the map. The offset must be greater than the
+ * all previously added offsets.
+ */
+void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type) {
+    assert(map != NULL);
+    assert(map->count < map->max);
+
+    if ((map->count != 0) &&
+            (map->offsets[map->count - 1] >= offset)) {
+        LOGE("Out-of-order data map offset: %#x then %#x",
+                map->offsets[map->count - 1], offset);
+        return;
+    }
+
+    map->offsets[map->count] = offset;
+    map->types[map->count] = type;
+    map->count++;
+}
+
+/*
+ * Get the type associated with the given offset. This returns -1 if
+ * there is no entry for the given offset.
+ */
+int dexDataMapGet(DexDataMap* map, u4 offset) {
+    assert(map != NULL);
+
+    // Note: Signed type is important for max and min.
+    int min = 0;
+    int max = map->count - 1;
+    u4* offsets = map->offsets;
+
+    while (max >= min) {
+        int guessIdx = (min + max) >> 1;
+        u4 guess = offsets[guessIdx];
+
+        if (offset < guess) {
+            max = guessIdx - 1;
+        } else if (offset > guess) {
+            min = guessIdx + 1;
+        } else {
+            // We have a winner!
+            return map->types[guessIdx];
+        }
+    }
+
+    // No match.
+    return -1;
+}
+
+/*
+ * Verify that there is an entry in the map, mapping the given offset to
+ * the given type. This will return true if such an entry exists and
+ * return false as well as log an error if not.
+ */
+bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type) {
+    int found = dexDataMapGet(map, offset);
+
+    if (found == type) {
+        return true;
+    }
+
+    if (found < 0) {
+        LOGE("No data map entry found @ %#x; expected %x",
+                offset, type);
+    } else {
+        LOGE("Unexpected data map entry @ %#x: expected %x, found %x",
+                offset, type, found);
+    }
+
+    return false;
+}
diff --git a/libdex/DexDataMap.h b/libdex/DexDataMap.h
new file mode 100644
index 0000000..7e43dc9
--- /dev/null
+++ b/libdex/DexDataMap.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+/*
+ * Verification-time map of data section items
+ */
+
+#ifndef LIBDEX_DEXDATAMAP_H_
+#define LIBDEX_DEXDATAMAP_H_
+
+#include "DexFile.h"
+
+struct DexDataMap {
+    u4 count;    /* number of items currently in the map */
+    u4 max;      /* maximum number of items that may be held */
+    u4* offsets; /* array of item offsets */
+    u2* types;   /* corresponding array of item types */
+};
+
+/*
+ * Allocate and initialize a DexDataMap. Returns NULL on failure.
+ */
+DexDataMap* dexDataMapAlloc(u4 maxCount);
+
+/*
+ * Free a DexDataMap.
+ */
+void dexDataMapFree(DexDataMap* map);
+
+/*
+ * Add a new element to the map. The offset must be greater than the
+ * all previously added offsets.
+ */
+void dexDataMapAdd(DexDataMap* map, u4 offset, u2 type);
+
+/*
+ * Get the type associated with the given offset. This returns -1 if
+ * there is no entry for the given offset.
+ */
+int dexDataMapGet(DexDataMap* map, u4 offset);
+
+/*
+ * Verify that there is an entry in the map, mapping the given offset to
+ * the given type. This will return true if such an entry exists and
+ * return false as well as log an error if not.
+ */
+bool dexDataMapVerify(DexDataMap* map, u4 offset, u2 type);
+
+/*
+ * Like dexDataMapVerify(), but also accept a 0 offset as valid.
+ */
+DEX_INLINE bool dexDataMapVerify0Ok(DexDataMap* map, u4 offset, u2 type) {
+    if (offset == 0) {
+        return true;
+    }
+
+    return dexDataMapVerify(map, offset, type);
+}
+
+#endif  // LIBDEX_DEXDATAMAP_H_
diff --git a/libdex/DexDebugInfo.cpp b/libdex/DexDebugInfo.cpp
new file mode 100644
index 0000000..cbb58d4
--- /dev/null
+++ b/libdex/DexDebugInfo.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*
+ * Handling of method debug info in a .dex file.
+ */
+
+#include "DexDebugInfo.h"
+#include "DexProto.h"
+#include "Leb128.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Decode the arguments in a method signature, which looks something
+ * like "(ID[Ljava/lang/String;)V".
+ *
+ * Returns the type signature letter for the next argument, or ')' if
+ * there are no more args.  Advances "pSig" to point to the character
+ * after the one returned.
+ */
+static char decodeSignature(const char** pSig)
+{
+    const char* sig = *pSig;
+
+    if (*sig == '(')
+        sig++;
+
+    if (*sig == 'L') {
+        /* object ref */
+        while (*++sig != ';')
+            ;
+        *pSig = sig+1;
+        return 'L';
+    }
+    if (*sig == '[') {
+        /* array; advance past array type */
+        while (*++sig == '[')
+            ;
+        if (*sig == 'L') {
+            while (*++sig != ';')
+                ;
+        }
+        *pSig = sig+1;
+        return '[';
+    }
+    if (*sig == '\0')
+        return *sig;        /* don't advance further */
+
+    *pSig = sig+1;
+    return *sig;
+}
+
+/*
+ * returns the length of a type string, given the start of the
+ * type string. Used for the case where the debug info format
+ * references types that are inside a method type signature.
+ */
+static int typeLength(const char *type) {
+    // Assumes any leading '(' has already been gobbled
+    const char *end = type;
+    decodeSignature(&end);
+    return end - type;
+}
+
+/*
+ * Reads a string index as encoded for the debug info format,
+ * returning a string pointer or NULL as appropriate.
+ */
+static const char* readStringIdx(const DexFile* pDexFile,
+        const u1** pStream) {
+    u4 stringIdx = readUnsignedLeb128(pStream);
+
+    // Remember, encoded string indicies have 1 added to them.
+    if (stringIdx == 0) {
+        return NULL;
+    } else {
+        return dexStringById(pDexFile, stringIdx - 1);
+    }
+}
+
+/*
+ * Reads a type index as encoded for the debug info format, returning
+ * a string pointer for its descriptor or NULL as appropriate.
+ */
+static const char* readTypeIdx(const DexFile* pDexFile,
+        const u1** pStream) {
+    u4 typeIdx = readUnsignedLeb128(pStream);
+
+    // Remember, encoded type indicies have 1 added to them.
+    if (typeIdx == 0) {
+        return NULL;
+    } else {
+        return dexStringByTypeIdx(pDexFile, typeIdx - 1);
+    }
+}
+
+struct LocalInfo {
+    const char *name;
+    const char *descriptor;
+    const char *signature;
+    u2 startAddress;
+    bool live;
+};
+
+static void emitLocalCbIfLive(void *cnxt, int reg, u4 endAddress,
+        LocalInfo *localInReg, DexDebugNewLocalCb localCb)
+{
+    if (localCb != NULL && localInReg[reg].live) {
+        localCb(cnxt, reg, localInReg[reg].startAddress, endAddress,
+                localInReg[reg].name,
+                localInReg[reg].descriptor,
+                localInReg[reg].signature == NULL
+                ? "" : localInReg[reg].signature );
+    }
+}
+
+static void invalidStream(const char* classDescriptor, const DexProto* proto) {
+    IF_LOGE() {
+        char* methodDescriptor = dexProtoCopyMethodDescriptor(proto);
+        LOGE("Invalid debug info stream. class %s; proto %s",
+                classDescriptor, methodDescriptor);
+        free(methodDescriptor);
+    }
+}
+
+static void dexDecodeDebugInfo0(
+            const DexFile* pDexFile,
+            const DexCode* pCode,
+            const char* classDescriptor,
+            u4 protoIdx,
+            u4 accessFlags,
+            DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
+            void* cnxt,
+            const u1* stream,
+            LocalInfo* localInReg)
+{
+    DexProto proto = { pDexFile, protoIdx };
+    u4 insnsSize = pCode->insnsSize;
+    u4 line = readUnsignedLeb128(&stream);
+    u4 parametersSize = readUnsignedLeb128(&stream);
+    u2 argReg = pCode->registersSize - pCode->insSize;
+    u4 address = 0;
+
+    if ((accessFlags & ACC_STATIC) == 0) {
+        /*
+         * The code is an instance method, which means that there is
+         * an initial this parameter. Also, the proto list should
+         * contain exactly one fewer argument word than the insSize
+         * indicates.
+         */
+        assert(pCode->insSize == (dexProtoComputeArgsSize(&proto) + 1));
+        localInReg[argReg].name = "this";
+        localInReg[argReg].descriptor = classDescriptor;
+        localInReg[argReg].startAddress = 0;
+        localInReg[argReg].live = true;
+        argReg++;
+    } else {
+        assert(pCode->insSize == dexProtoComputeArgsSize(&proto));
+    }
+
+    DexParameterIterator iterator;
+    dexParameterIteratorInit(&iterator, &proto);
+
+    while (parametersSize-- != 0) {
+        const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
+        const char *name;
+        int reg;
+
+        if ((argReg >= pCode->registersSize) || (descriptor == NULL)) {
+            invalidStream(classDescriptor, &proto);
+            return;
+        }
+
+        name = readStringIdx(pDexFile, &stream);
+        reg = argReg;
+
+        switch (descriptor[0]) {
+            case 'D':
+            case 'J':
+                argReg += 2;
+                break;
+            default:
+                argReg += 1;
+                break;
+        }
+
+        if (name != NULL) {
+            localInReg[reg].name = name;
+            localInReg[reg].descriptor = descriptor;
+            localInReg[reg].signature = NULL;
+            localInReg[reg].startAddress = address;
+            localInReg[reg].live = true;
+        }
+    }
+
+    for (;;)  {
+        u1 opcode = *stream++;
+        u2 reg;
+
+        switch (opcode) {
+            case DBG_END_SEQUENCE:
+                return;
+
+            case DBG_ADVANCE_PC:
+                address += readUnsignedLeb128(&stream);
+                break;
+
+            case DBG_ADVANCE_LINE:
+                line += readSignedLeb128(&stream);
+                break;
+
+            case DBG_START_LOCAL:
+            case DBG_START_LOCAL_EXTENDED:
+                reg = readUnsignedLeb128(&stream);
+                if (reg > pCode->registersSize) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                // Emit what was previously there, if anything
+                emitLocalCbIfLive(cnxt, reg, address,
+                    localInReg, localCb);
+
+                localInReg[reg].name = readStringIdx(pDexFile, &stream);
+                localInReg[reg].descriptor = readTypeIdx(pDexFile, &stream);
+                if (opcode == DBG_START_LOCAL_EXTENDED) {
+                    localInReg[reg].signature
+                        = readStringIdx(pDexFile, &stream);
+                } else {
+                    localInReg[reg].signature = NULL;
+                }
+                localInReg[reg].startAddress = address;
+                localInReg[reg].live = true;
+                break;
+
+            case DBG_END_LOCAL:
+                reg = readUnsignedLeb128(&stream);
+                if (reg > pCode->registersSize) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                emitLocalCbIfLive (cnxt, reg, address, localInReg, localCb);
+                localInReg[reg].live = false;
+                break;
+
+            case DBG_RESTART_LOCAL:
+                reg = readUnsignedLeb128(&stream);
+                if (reg > pCode->registersSize) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                if (localInReg[reg].name == NULL
+                        || localInReg[reg].descriptor == NULL) {
+                    invalidStream(classDescriptor, &proto);
+                    return;
+                }
+
+                /*
+                 * If the register is live, the "restart" is superfluous,
+                 * and we don't want to mess with the existing start address.
+                 */
+                if (!localInReg[reg].live) {
+                    localInReg[reg].startAddress = address;
+                    localInReg[reg].live = true;
+                }
+                break;
+
+            case DBG_SET_PROLOGUE_END:
+            case DBG_SET_EPILOGUE_BEGIN:
+            case DBG_SET_FILE:
+                break;
+
+            default: {
+                int adjopcode = opcode - DBG_FIRST_SPECIAL;
+
+                address += adjopcode / DBG_LINE_RANGE;
+                line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
+
+                if (posCb != NULL) {
+                    int done;
+                    done = posCb(cnxt, address, line);
+
+                    if (done) {
+                        // early exit
+                        return;
+                    }
+                }
+                break;
+            }
+        }
+    }
+}
+
+// TODO optimize localCb == NULL case
+void dexDecodeDebugInfo(
+            const DexFile* pDexFile,
+            const DexCode* pCode,
+            const char* classDescriptor,
+            u4 protoIdx,
+            u4 accessFlags,
+            DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
+            void* cnxt)
+{
+    const u1* stream = dexGetDebugInfoStream(pDexFile, pCode);
+    LocalInfo localInReg[pCode->registersSize];
+
+    memset(localInReg, 0, sizeof(LocalInfo) * pCode->registersSize);
+
+    if (stream != NULL) {
+        dexDecodeDebugInfo0(pDexFile, pCode, classDescriptor, protoIdx, accessFlags,
+            posCb, localCb, cnxt, stream, localInReg);
+    }
+
+    for (int reg = 0; reg < pCode->registersSize; reg++) {
+        emitLocalCbIfLive(cnxt, reg, pCode->insnsSize, localInReg, localCb);
+    }
+}
diff --git a/libdex/DexDebugInfo.h b/libdex/DexDebugInfo.h
new file mode 100644
index 0000000..bd0954c
--- /dev/null
+++ b/libdex/DexDebugInfo.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*
+ * Handling of method debug info in a .dex file.
+ */
+
+#ifndef LIBDEX_DEXDEBUGINFO_H_
+#define LIBDEX_DEXDEBUGINFO_H_
+
+#include "DexFile.h"
+
+/*
+ * Callback for "new position table entry".
+ * Returning non-0 causes the decoder to stop early.
+ */
+typedef int (*DexDebugNewPositionCb)(void *cnxt, u4 address, u4 lineNum);
+
+/*
+ * Callback for "new locals table entry". "signature" is an empty string
+ * if no signature is available for an entry.
+ */
+typedef void (*DexDebugNewLocalCb)(void *cnxt, u2 reg, u4 startAddress,
+        u4 endAddress, const char *name, const char *descriptor,
+        const char *signature);
+
+/*
+ * Decode debug info for method.
+ *
+ * posCb is called in ascending address order.
+ * localCb is called in order of ascending end address.
+ */
+void dexDecodeDebugInfo(
+            const DexFile* pDexFile,
+            const DexCode* pDexCode,
+            const char* classDescriptor,
+            u4 protoIdx,
+            u4 accessFlags,
+            DexDebugNewPositionCb posCb, DexDebugNewLocalCb localCb,
+            void* cnxt);
+
+#endif  // LIBDEX_DEXDEBUGINFO_H_
diff --git a/libdex/DexFile.cpp b/libdex/DexFile.cpp
new file mode 100644
index 0000000..4dcc097
--- /dev/null
+++ b/libdex/DexFile.cpp
@@ -0,0 +1,542 @@
+/*
+ * 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.
+ */
+
+/*
+ * Access the contents of a .dex file.
+ */
+
+#include "DexFile.h"
+#include "DexOptData.h"
+#include "DexProto.h"
+#include "DexCatch.h"
+#include "Leb128.h"
+#include "sha1.h"
+#include "ZipArchive.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+/*
+ * Verifying checksums is good, but it slows things down and causes us to
+ * touch every page.  In the "optimized" world, it doesn't work at all,
+ * because we rewrite the contents.
+ */
+static const bool kVerifyChecksum = false;
+static const bool kVerifySignature = false;
+
+/* (documented in header) */
+char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) {
+    const char* string = dexGetPrimitiveTypeDescriptor(type);
+
+    return (string == NULL) ? '\0' : string[0];
+}
+
+/* (documented in header) */
+const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) {
+    switch (type) {
+        case PRIM_VOID:    return "V";
+        case PRIM_BOOLEAN: return "Z";
+        case PRIM_BYTE:    return "B";
+        case PRIM_SHORT:   return "S";
+        case PRIM_CHAR:    return "C";
+        case PRIM_INT:     return "I";
+        case PRIM_LONG:    return "J";
+        case PRIM_FLOAT:   return "F";
+        case PRIM_DOUBLE:  return "D";
+        default:           return NULL;
+    }
+
+    return NULL;
+}
+
+/* (documented in header) */
+const char* dexGetBoxedTypeDescriptor(PrimitiveType type) {
+    switch (type) {
+        case PRIM_VOID:    return NULL;
+        case PRIM_BOOLEAN: return "Ljava/lang/Boolean;";
+        case PRIM_BYTE:    return "Ljava/lang/Byte;";
+        case PRIM_SHORT:   return "Ljava/lang/Short;";
+        case PRIM_CHAR:    return "Ljava/lang/Character;";
+        case PRIM_INT:     return "Ljava/lang/Integer;";
+        case PRIM_LONG:    return "Ljava/lang/Long;";
+        case PRIM_FLOAT:   return "Ljava/lang/Float;";
+        case PRIM_DOUBLE:  return "Ljava/lang/Double;";
+        default:           return NULL;
+    }
+}
+
+/* (documented in header) */
+PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) {
+    switch (descriptorChar) {
+        case 'V': return PRIM_VOID;
+        case 'Z': return PRIM_BOOLEAN;
+        case 'B': return PRIM_BYTE;
+        case 'S': return PRIM_SHORT;
+        case 'C': return PRIM_CHAR;
+        case 'I': return PRIM_INT;
+        case 'J': return PRIM_LONG;
+        case 'F': return PRIM_FLOAT;
+        case 'D': return PRIM_DOUBLE;
+        default:  return PRIM_NOT;
+    }
+}
+
+/* Return the UTF-8 encoded string with the specified string_id index,
+ * also filling in the UTF-16 size (number of 16-bit code points).*/
+const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
+        u4* utf16Size) {
+    const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
+    const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
+
+    *utf16Size = readUnsignedLeb128(&ptr);
+    return (const char*) ptr;
+}
+
+/*
+ * Format an SHA-1 digest for printing.  tmpBuf must be able to hold at
+ * least kSHA1DigestOutputLen bytes.
+ */
+const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf);
+
+/*
+ * Compute a SHA-1 digest on a range of bytes.
+ */
+static void dexComputeSHA1Digest(const unsigned char* data, size_t length,
+    unsigned char digest[])
+{
+    SHA1_CTX context;
+    SHA1Init(&context);
+    SHA1Update(&context, data, length);
+    SHA1Final(digest, &context);
+}
+
+/*
+ * Format the SHA-1 digest into the buffer, which must be able to hold at
+ * least kSHA1DigestOutputLen bytes.  Returns a pointer to the buffer,
+ */
+static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf)
+{
+    static const char hexDigit[] = "0123456789abcdef";
+    char* cp;
+    int i;
+
+    cp = tmpBuf;
+    for (i = 0; i < kSHA1DigestLen; i++) {
+        *cp++ = hexDigit[digest[i] >> 4];
+        *cp++ = hexDigit[digest[i] & 0x0f];
+    }
+    *cp++ = '\0';
+
+    assert(cp == tmpBuf + kSHA1DigestOutputLen);
+
+    return tmpBuf;
+}
+
+/*
+ * Compute a hash code on a UTF-8 string, for use with internal hash tables.
+ *
+ * This may or may not be compatible with UTF-8 hash functions used inside
+ * the Dalvik VM.
+ *
+ * The basic "multiply by 31 and add" approach does better on class names
+ * than most other things tried (e.g. adler32).
+ */
+static u4 classDescriptorHash(const char* str)
+{
+    u4 hash = 1;
+
+    while (*str != '\0')
+        hash = hash * 31 + *str++;
+
+    return hash;
+}
+
+/*
+ * Add an entry to the class lookup table.  We hash the string and probe
+ * until we find an open slot.
+ */
+static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup,
+    int stringOff, int classDefOff, int* pNumProbes)
+{
+    const char* classDescriptor =
+        (const char*) (pDexFile->baseAddr + stringOff);
+    const DexClassDef* pClassDef =
+        (const DexClassDef*) (pDexFile->baseAddr + classDefOff);
+    u4 hash = classDescriptorHash(classDescriptor);
+    int mask = pLookup->numEntries-1;
+    int idx = hash & mask;
+
+    /*
+     * Find the first empty slot.  We oversized the table, so this is
+     * guaranteed to finish.
+     */
+    int probes = 0;
+    while (pLookup->table[idx].classDescriptorOffset != 0) {
+        idx = (idx + 1) & mask;
+        probes++;
+    }
+    //if (probes > 1)
+    //    LOGW("classLookupAdd: probes=%d", probes);
+
+    pLookup->table[idx].classDescriptorHash = hash;
+    pLookup->table[idx].classDescriptorOffset = stringOff;
+    pLookup->table[idx].classDefOffset = classDefOff;
+    *pNumProbes = probes;
+}
+
+/*
+ * Create the class lookup hash table.
+ *
+ * Returns newly-allocated storage.
+ */
+DexClassLookup* dexCreateClassLookup(DexFile* pDexFile)
+{
+    DexClassLookup* pLookup;
+    int allocSize;
+    int i, numEntries;
+    int numProbes, totalProbes, maxProbes;
+
+    numProbes = totalProbes = maxProbes = 0;
+
+    assert(pDexFile != NULL);
+
+    /*
+     * Using a factor of 3 results in far less probing than a factor of 2,
+     * but almost doubles the flash storage requirements for the bootstrap
+     * DEX files.  The overall impact on class loading performance seems
+     * to be minor.  We could probably get some performance improvement by
+     * using a secondary hash.
+     */
+    numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2);
+    allocSize = offsetof(DexClassLookup, table)
+                    + numEntries * sizeof(pLookup->table[0]);
+
+    pLookup = (DexClassLookup*) calloc(1, allocSize);
+    if (pLookup == NULL)
+        return NULL;
+    pLookup->size = allocSize;
+    pLookup->numEntries = numEntries;
+
+    for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) {
+        const DexClassDef* pClassDef;
+        const char* pString;
+
+        pClassDef = dexGetClassDef(pDexFile, i);
+        pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+        classLookupAdd(pDexFile, pLookup,
+            (u1*)pString - pDexFile->baseAddr,
+            (u1*)pClassDef - pDexFile->baseAddr, &numProbes);
+
+        if (numProbes > maxProbes)
+            maxProbes = numProbes;
+        totalProbes += numProbes;
+    }
+
+    LOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d"
+         " total=%d max=%d",
+        pDexFile->pHeader->classDefsSize, numEntries,
+        (100 * pDexFile->pHeader->classDefsSize) / numEntries,
+        allocSize, totalProbes, maxProbes);
+
+    return pLookup;
+}
+
+
+/*
+ * Set up the basic raw data pointers of a DexFile. This function isn't
+ * meant for general use.
+ */
+void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) {
+    DexHeader *pHeader = (DexHeader*) data;
+
+    pDexFile->baseAddr = data;
+    pDexFile->pHeader = pHeader;
+    pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
+    pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
+    pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
+    pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
+    pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
+    pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
+    pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
+}
+
+/*
+ * Parse an optimized or unoptimized .dex file sitting in memory.  This is
+ * called after the byte-ordering and structure alignment has been fixed up.
+ *
+ * On success, return a newly-allocated DexFile.
+ */
+DexFile* dexFileParse(const u1* data, size_t length, int flags)
+{
+    DexFile* pDexFile = NULL;
+    const DexHeader* pHeader;
+    const u1* magic;
+    int result = -1;
+
+    if (length < sizeof(DexHeader)) {
+        LOGE("too short to be a valid .dex");
+        goto bail;      /* bad file format */
+    }
+
+    pDexFile = (DexFile*) malloc(sizeof(DexFile));
+    if (pDexFile == NULL)
+        goto bail;      /* alloc failure */
+    memset(pDexFile, 0, sizeof(DexFile));
+
+    /*
+     * Peel off the optimized header.
+     */
+    if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) {
+        magic = data;
+        if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
+            LOGE("bad opt version (0x%02x %02x %02x %02x)",
+                 magic[4], magic[5], magic[6], magic[7]);
+            goto bail;
+        }
+
+        pDexFile->pOptHeader = (const DexOptHeader*) data;
+        LOGV("Good opt header, DEX offset is %d, flags=0x%02x",
+            pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags);
+
+        /* parse the optimized dex file tables */
+        if (!dexParseOptData(data, length, pDexFile))
+            goto bail;
+
+        /* ignore the opt header and appended data from here on out */
+        data += pDexFile->pOptHeader->dexOffset;
+        length -= pDexFile->pOptHeader->dexOffset;
+        if (pDexFile->pOptHeader->dexLength > length) {
+            LOGE("File truncated? stored len=%d, rem len=%d",
+                pDexFile->pOptHeader->dexLength, (int) length);
+            goto bail;
+        }
+        length = pDexFile->pOptHeader->dexLength;
+    }
+
+    dexFileSetupBasicPointers(pDexFile, data);
+    pHeader = pDexFile->pHeader;
+
+    if (!dexHasValidMagic(pHeader)) {
+        goto bail;
+    }
+
+    /*
+     * Verify the checksum(s).  This is reasonably quick, but does require
+     * touching every byte in the DEX file.  The base checksum changes after
+     * byte-swapping and DEX optimization.
+     */
+    if (flags & kDexParseVerifyChecksum) {
+        u4 adler = dexComputeChecksum(pHeader);
+        if (adler != pHeader->checksum) {
+            LOGE("ERROR: bad checksum (%08x vs %08x)",
+                adler, pHeader->checksum);
+            if (!(flags & kDexParseContinueOnError))
+                goto bail;
+        } else {
+            LOGV("+++ adler32 checksum (%08x) verified", adler);
+        }
+
+        const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
+        if (pOptHeader != NULL) {
+            adler = dexComputeOptChecksum(pOptHeader);
+            if (adler != pOptHeader->checksum) {
+                LOGE("ERROR: bad opt checksum (%08x vs %08x)",
+                    adler, pOptHeader->checksum);
+                if (!(flags & kDexParseContinueOnError))
+                    goto bail;
+            } else {
+                LOGV("+++ adler32 opt checksum (%08x) verified", adler);
+            }
+        }
+    }
+
+    /*
+     * Verify the SHA-1 digest.  (Normally we don't want to do this --
+     * the digest is used to uniquely identify the original DEX file, and
+     * can't be computed for verification after the DEX is byte-swapped
+     * and optimized.)
+     */
+    if (kVerifySignature) {
+        unsigned char sha1Digest[kSHA1DigestLen];
+        const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) +
+                            kSHA1DigestLen;
+
+        dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest);
+        if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) {
+            char tmpBuf1[kSHA1DigestOutputLen];
+            char tmpBuf2[kSHA1DigestOutputLen];
+            LOGE("ERROR: bad SHA1 digest (%s vs %s)",
+                dexSHA1DigestToStr(sha1Digest, tmpBuf1),
+                dexSHA1DigestToStr(pHeader->signature, tmpBuf2));
+            if (!(flags & kDexParseContinueOnError))
+                goto bail;
+        } else {
+            LOGV("+++ sha1 digest verified");
+        }
+    }
+
+    if (pHeader->fileSize != length) {
+        LOGE("ERROR: stored file size (%d) != expected (%d)",
+            (int) pHeader->fileSize, (int) length);
+        if (!(flags & kDexParseContinueOnError))
+            goto bail;
+    }
+
+    if (pHeader->classDefsSize == 0) {
+        LOGE("ERROR: DEX file has no classes in it, failing");
+        goto bail;
+    }
+
+    /*
+     * Success!
+     */
+    result = 0;
+
+bail:
+    if (result != 0 && pDexFile != NULL) {
+        dexFileFree(pDexFile);
+        pDexFile = NULL;
+    }
+    return pDexFile;
+}
+
+/*
+ * Free up the DexFile and any associated data structures.
+ *
+ * Note we may be called with a partially-initialized DexFile.
+ */
+void dexFileFree(DexFile* pDexFile)
+{
+    if (pDexFile == NULL)
+        return;
+
+    free(pDexFile);
+}
+
+/*
+ * Look up a class definition entry by descriptor.
+ *
+ * "descriptor" should look like "Landroid/debug/Stuff;".
+ */
+const DexClassDef* dexFindClass(const DexFile* pDexFile,
+    const char* descriptor)
+{
+    const DexClassLookup* pLookup = pDexFile->pClassLookup;
+    u4 hash;
+    int idx, mask;
+
+    hash = classDescriptorHash(descriptor);
+    mask = pLookup->numEntries - 1;
+    idx = hash & mask;
+
+    /*
+     * Search until we find a matching entry or an empty slot.
+     */
+    while (true) {
+        int offset;
+
+        offset = pLookup->table[idx].classDescriptorOffset;
+        if (offset == 0)
+            return NULL;
+
+        if (pLookup->table[idx].classDescriptorHash == hash) {
+            const char* str;
+
+            str = (const char*) (pDexFile->baseAddr + offset);
+            if (strcmp(str, descriptor) == 0) {
+                return (const DexClassDef*)
+                    (pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
+            }
+        }
+
+        idx = (idx + 1) & mask;
+    }
+}
+
+
+/*
+ * Compute the DEX file checksum for a memory-mapped DEX file.
+ */
+u4 dexComputeChecksum(const DexHeader* pHeader)
+{
+    const u1* start = (const u1*) pHeader;
+
+    uLong adler = adler32(0L, Z_NULL, 0);
+    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
+
+    return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum);
+}
+
+/*
+ * 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",
+    //    pCode, handlerData, offset);
+
+    /* return the size of the catch handler + everything before it */
+    return (handlerData - (u1*) pCode) + offset;
+}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+u4 dexRoundUpPower2(u4 val)
+{
+    val--;
+    val |= val >> 1;
+    val |= val >> 2;
+    val |= val >> 4;
+    val |= val >> 8;
+    val |= val >> 16;
+    val++;
+
+    return val;
+}
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
new file mode 100644
index 0000000..38e6eca
--- /dev/null
+++ b/libdex/DexFile.h
@@ -0,0 +1,977 @@
+/*
+ * 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.
+ */
+
+/*
+ * Access .dex (Dalvik Executable Format) files.  The code here assumes that
+ * the DEX file has been rewritten (byte-swapped, word-aligned) and that
+ * the contents can be directly accessed as a collection of C arrays.  Please
+ * see docs/dalvik/dex-format.html for a detailed description.
+ *
+ * The structure and field names were chosen to match those in the DEX spec.
+ *
+ * It's generally assumed that the DEX file will be stored in shared memory,
+ * obviating the need to copy code and constant pool entries into newly
+ * allocated storage.  Maintaining local pointers to items in the shared area
+ * is valid and encouraged.
+ *
+ * All memory-mapped structures are 32-bit aligned unless otherwise noted.
+ */
+
+#ifndef LIBDEX_DEXFILE_H_
+#define LIBDEX_DEXFILE_H_
+
+#include "vm/Common.h"      // basic type defs, e.g. u1/u2/u4/u8, and LOG
+#include "libdex/SysUtil.h"
+
+/*
+ * gcc-style inline management -- ensures we have a copy of all functions
+ * in the library, so code that links against us will work whether or not
+ * it was built with optimizations enabled.
+ */
+#ifndef _DEX_GEN_INLINES             /* only defined by DexInlines.c */
+# define DEX_INLINE extern __inline__
+#else
+# define DEX_INLINE
+#endif
+
+/* DEX file magic number */
+#define DEX_MAGIC       "dex\n"
+
+/* current version, encoded in 4 bytes of ASCII */
+#define DEX_MAGIC_VERS  "036\0"
+
+/*
+ * older but still-recognized version (corresponding to Android API
+ * levels 13 and earlier
+ */
+#define DEX_MAGIC_VERS_API_13  "035\0"
+
+/* same, but for optimized DEX header */
+#define DEX_OPT_MAGIC   "dey\n"
+#define DEX_OPT_MAGIC_VERS  "036\0"
+
+#define DEX_DEP_MAGIC   "deps"
+
+/*
+ * 160-bit SHA-1 digest.
+ */
+enum { kSHA1DigestLen = 20,
+       kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };
+
+/* general constants */
+enum {
+    kDexEndianConstant = 0x12345678,    /* the endianness indicator */
+    kDexNoIndex = 0xffffffff,           /* not a valid index value */
+};
+
+/*
+ * Enumeration of all the primitive types.
+ */
+enum PrimitiveType {
+    PRIM_NOT        = 0,       /* value is a reference type, not a primitive type */
+    PRIM_VOID       = 1,
+    PRIM_BOOLEAN    = 2,
+    PRIM_BYTE       = 3,
+    PRIM_SHORT      = 4,
+    PRIM_CHAR       = 5,
+    PRIM_INT        = 6,
+    PRIM_LONG       = 7,
+    PRIM_FLOAT      = 8,
+    PRIM_DOUBLE     = 9,
+};
+
+/*
+ * access flags and masks; the "standard" ones are all <= 0x4000
+ *
+ * Note: There are related declarations in vm/oo/Object.h in the ClassFlags
+ * enum.
+ */
+enum {
+    ACC_PUBLIC       = 0x00000001,       // class, field, method, ic
+    ACC_PRIVATE      = 0x00000002,       // field, method, ic
+    ACC_PROTECTED    = 0x00000004,       // field, method, ic
+    ACC_STATIC       = 0x00000008,       // field, method, ic
+    ACC_FINAL        = 0x00000010,       // class, field, method, ic
+    ACC_SYNCHRONIZED = 0x00000020,       // method (only allowed on natives)
+    ACC_SUPER        = 0x00000020,       // class (not used in Dalvik)
+    ACC_VOLATILE     = 0x00000040,       // field
+    ACC_BRIDGE       = 0x00000040,       // method (1.5)
+    ACC_TRANSIENT    = 0x00000080,       // field
+    ACC_VARARGS      = 0x00000080,       // method (1.5)
+    ACC_NATIVE       = 0x00000100,       // method
+    ACC_INTERFACE    = 0x00000200,       // class, ic
+    ACC_ABSTRACT     = 0x00000400,       // class, method, ic
+    ACC_STRICT       = 0x00000800,       // method
+    ACC_SYNTHETIC    = 0x00001000,       // field, method, ic
+    ACC_ANNOTATION   = 0x00002000,       // class, ic (1.5)
+    ACC_ENUM         = 0x00004000,       // class, field, ic (1.5)
+    ACC_CONSTRUCTOR  = 0x00010000,       // method (Dalvik only)
+    ACC_DECLARED_SYNCHRONIZED =
+                       0x00020000,       // method (Dalvik only)
+    ACC_CLASS_MASK =
+        (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
+                | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
+    ACC_INNER_CLASS_MASK =
+        (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
+    ACC_FIELD_MASK =
+        (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
+                | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
+    ACC_METHOD_MASK =
+        (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
+                | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
+                | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
+                | ACC_DECLARED_SYNCHRONIZED),
+};
+
+/* annotation constants */
+enum {
+    kDexVisibilityBuild         = 0x00,     /* annotation visibility */
+    kDexVisibilityRuntime       = 0x01,
+    kDexVisibilitySystem        = 0x02,
+
+    kDexAnnotationByte          = 0x00,
+    kDexAnnotationShort         = 0x02,
+    kDexAnnotationChar          = 0x03,
+    kDexAnnotationInt           = 0x04,
+    kDexAnnotationLong          = 0x06,
+    kDexAnnotationFloat         = 0x10,
+    kDexAnnotationDouble        = 0x11,
+    kDexAnnotationString        = 0x17,
+    kDexAnnotationType          = 0x18,
+    kDexAnnotationField         = 0x19,
+    kDexAnnotationMethod        = 0x1a,
+    kDexAnnotationEnum          = 0x1b,
+    kDexAnnotationArray         = 0x1c,
+    kDexAnnotationAnnotation    = 0x1d,
+    kDexAnnotationNull          = 0x1e,
+    kDexAnnotationBoolean       = 0x1f,
+
+    kDexAnnotationValueTypeMask = 0x1f,     /* low 5 bits */
+    kDexAnnotationValueArgShift = 5,
+};
+
+/* map item type codes */
+enum {
+    kDexTypeHeaderItem               = 0x0000,
+    kDexTypeStringIdItem             = 0x0001,
+    kDexTypeTypeIdItem               = 0x0002,
+    kDexTypeProtoIdItem              = 0x0003,
+    kDexTypeFieldIdItem              = 0x0004,
+    kDexTypeMethodIdItem             = 0x0005,
+    kDexTypeClassDefItem             = 0x0006,
+    kDexTypeMapList                  = 0x1000,
+    kDexTypeTypeList                 = 0x1001,
+    kDexTypeAnnotationSetRefList     = 0x1002,
+    kDexTypeAnnotationSetItem        = 0x1003,
+    kDexTypeClassDataItem            = 0x2000,
+    kDexTypeCodeItem                 = 0x2001,
+    kDexTypeStringDataItem           = 0x2002,
+    kDexTypeDebugInfoItem            = 0x2003,
+    kDexTypeAnnotationItem           = 0x2004,
+    kDexTypeEncodedArrayItem         = 0x2005,
+    kDexTypeAnnotationsDirectoryItem = 0x2006,
+};
+
+/* auxillary data section chunk codes */
+enum {
+    kDexChunkClassLookup            = 0x434c4b50,   /* CLKP */
+    kDexChunkRegisterMaps           = 0x524d4150,   /* RMAP */
+
+    kDexChunkEnd                    = 0x41454e44,   /* AEND */
+};
+
+/* debug info opcodes and constants */
+enum {
+    DBG_END_SEQUENCE         = 0x00,
+    DBG_ADVANCE_PC           = 0x01,
+    DBG_ADVANCE_LINE         = 0x02,
+    DBG_START_LOCAL          = 0x03,
+    DBG_START_LOCAL_EXTENDED = 0x04,
+    DBG_END_LOCAL            = 0x05,
+    DBG_RESTART_LOCAL        = 0x06,
+    DBG_SET_PROLOGUE_END     = 0x07,
+    DBG_SET_EPILOGUE_BEGIN   = 0x08,
+    DBG_SET_FILE             = 0x09,
+    DBG_FIRST_SPECIAL        = 0x0a,
+    DBG_LINE_BASE            = -4,
+    DBG_LINE_RANGE           = 15,
+};
+
+/*
+ * Direct-mapped "header_item" struct.
+ */
+struct DexHeader {
+    u1  magic[8];           /* includes version number */
+    u4  checksum;           /* adler32 checksum */
+    u1  signature[kSHA1DigestLen]; /* SHA-1 hash */
+    u4  fileSize;           /* length of entire file */
+    u4  headerSize;         /* offset to start of next section */
+    u4  endianTag;
+    u4  linkSize;
+    u4  linkOff;
+    u4  mapOff;
+    u4  stringIdsSize;
+    u4  stringIdsOff;
+    u4  typeIdsSize;
+    u4  typeIdsOff;
+    u4  protoIdsSize;
+    u4  protoIdsOff;
+    u4  fieldIdsSize;
+    u4  fieldIdsOff;
+    u4  methodIdsSize;
+    u4  methodIdsOff;
+    u4  classDefsSize;
+    u4  classDefsOff;
+    u4  dataSize;
+    u4  dataOff;
+};
+
+/*
+ * Direct-mapped "map_item".
+ */
+struct DexMapItem {
+    u2 type;              /* type code (see kDexType* above) */
+    u2 unused;
+    u4 size;              /* count of items of the indicated type */
+    u4 offset;            /* file offset to the start of data */
+};
+
+/*
+ * Direct-mapped "map_list".
+ */
+struct DexMapList {
+    u4  size;               /* #of entries in list */
+    DexMapItem list[1];     /* entries */
+};
+
+/*
+ * Direct-mapped "string_id_item".
+ */
+struct DexStringId {
+    u4 stringDataOff;      /* file offset to string_data_item */
+};
+
+/*
+ * Direct-mapped "type_id_item".
+ */
+struct DexTypeId {
+    u4  descriptorIdx;      /* index into stringIds list for type descriptor */
+};
+
+/*
+ * Direct-mapped "field_id_item".
+ */
+struct DexFieldId {
+    u2  classIdx;           /* index into typeIds list for defining class */
+    u2  typeIdx;            /* index into typeIds for field type */
+    u4  nameIdx;            /* index into stringIds for field name */
+};
+
+/*
+ * Direct-mapped "method_id_item".
+ */
+struct DexMethodId {
+    u2  classIdx;           /* index into typeIds list for defining class */
+    u2  protoIdx;           /* index into protoIds for method prototype */
+    u4  nameIdx;            /* index into stringIds for method name */
+};
+
+/*
+ * Direct-mapped "proto_id_item".
+ */
+struct DexProtoId {
+    u4  shortyIdx;          /* index into stringIds for shorty descriptor */
+    u4  returnTypeIdx;      /* index into typeIds list for return type */
+    u4  parametersOff;      /* file offset to type_list for parameter types */
+};
+
+/*
+ * Direct-mapped "class_def_item".
+ */
+struct DexClassDef {
+    u4  classIdx;           /* index into typeIds for this class */
+    u4  accessFlags;
+    u4  superclassIdx;      /* index into typeIds for superclass */
+    u4  interfacesOff;      /* file offset to DexTypeList */
+    u4  sourceFileIdx;      /* index into stringIds for source file name */
+    u4  annotationsOff;     /* file offset to annotations_directory_item */
+    u4  classDataOff;       /* file offset to class_data_item */
+    u4  staticValuesOff;    /* file offset to DexEncodedArray */
+};
+
+/*
+ * Direct-mapped "type_item".
+ */
+struct DexTypeItem {
+    u2  typeIdx;            /* index into typeIds */
+};
+
+/*
+ * Direct-mapped "type_list".
+ */
+struct DexTypeList {
+    u4  size;               /* #of entries in list */
+    DexTypeItem list[1];    /* entries */
+};
+
+/*
+ * Direct-mapped "code_item".
+ *
+ * The "catches" table is used when throwing an exception,
+ * "debugInfo" is used when displaying an exception stack trace or
+ * debugging. An offset of zero indicates that there are no entries.
+ */
+struct DexCode {
+    u2  registersSize;
+    u2  insSize;
+    u2  outsSize;
+    u2  triesSize;
+    u4  debugInfoOff;       /* file offset to debug info stream */
+    u4  insnsSize;          /* size of the insns array, in u2 units */
+    u2  insns[1];
+    /* followed by optional u2 padding */
+    /* followed by try_item[triesSize] */
+    /* followed by uleb128 handlersSize */
+    /* followed by catch_handler_item[handlersSize] */
+};
+
+/*
+ * Direct-mapped "try_item".
+ */
+struct DexTry {
+    u4  startAddr;          /* start address, in 16-bit code units */
+    u2  insnCount;          /* instruction count, in 16-bit code units */
+    u2  handlerOff;         /* offset in encoded handler data to handlers */
+};
+
+/*
+ * Link table.  Currently undefined.
+ */
+struct DexLink {
+    u1  bleargh;
+};
+
+
+/*
+ * Direct-mapped "annotations_directory_item".
+ */
+struct DexAnnotationsDirectoryItem {
+    u4  classAnnotationsOff;  /* offset to DexAnnotationSetItem */
+    u4  fieldsSize;           /* count of DexFieldAnnotationsItem */
+    u4  methodsSize;          /* count of DexMethodAnnotationsItem */
+    u4  parametersSize;       /* count of DexParameterAnnotationsItem */
+    /* followed by DexFieldAnnotationsItem[fieldsSize] */
+    /* followed by DexMethodAnnotationsItem[methodsSize] */
+    /* followed by DexParameterAnnotationsItem[parametersSize] */
+};
+
+/*
+ * Direct-mapped "field_annotations_item".
+ */
+struct DexFieldAnnotationsItem {
+    u4  fieldIdx;
+    u4  annotationsOff;             /* offset to DexAnnotationSetItem */
+};
+
+/*
+ * Direct-mapped "method_annotations_item".
+ */
+struct DexMethodAnnotationsItem {
+    u4  methodIdx;
+    u4  annotationsOff;             /* offset to DexAnnotationSetItem */
+};
+
+/*
+ * Direct-mapped "parameter_annotations_item".
+ */
+struct DexParameterAnnotationsItem {
+    u4  methodIdx;
+    u4  annotationsOff;             /* offset to DexAnotationSetRefList */
+};
+
+/*
+ * Direct-mapped "annotation_set_ref_item".
+ */
+struct DexAnnotationSetRefItem {
+    u4  annotationsOff;             /* offset to DexAnnotationSetItem */
+};
+
+/*
+ * Direct-mapped "annotation_set_ref_list".
+ */
+struct DexAnnotationSetRefList {
+    u4  size;
+    DexAnnotationSetRefItem list[1];
+};
+
+/*
+ * Direct-mapped "annotation_set_item".
+ */
+struct DexAnnotationSetItem {
+    u4  size;
+    u4  entries[1];                 /* offset to DexAnnotationItem */
+};
+
+/*
+ * Direct-mapped "annotation_item".
+ *
+ * NOTE: this structure is byte-aligned.
+ */
+struct DexAnnotationItem {
+    u1  visibility;
+    u1  annotation[1];              /* data in encoded_annotation format */
+};
+
+/*
+ * Direct-mapped "encoded_array".
+ *
+ * NOTE: this structure is byte-aligned.
+ */
+struct DexEncodedArray {
+    u1  array[1];                   /* data in encoded_array format */
+};
+
+/*
+ * Lookup table for classes.  It provides a mapping from class name to
+ * class definition.  Used by dexFindClass().
+ *
+ * We calculate this at DEX optimization time and embed it in the file so we
+ * don't need the same hash table in every VM.  This is slightly slower than
+ * a hash table with direct pointers to the items, but because it's shared
+ * there's less of a penalty for using a fairly sparse table.
+ */
+struct DexClassLookup {
+    int     size;                       // total size, including "size"
+    int     numEntries;                 // size of table[]; always power of 2
+    struct {
+        u4      classDescriptorHash;    // class descriptor hash code
+        int     classDescriptorOffset;  // in bytes, from start of DEX
+        int     classDefOffset;         // in bytes, from start of DEX
+    } table[1];
+};
+
+/*
+ * Header added by DEX optimization pass.  Values are always written in
+ * local byte and structure padding.  The first field (magic + version)
+ * is guaranteed to be present and directly readable for all expected
+ * compiler configurations; the rest is version-dependent.
+ *
+ * Try to keep this simple and fixed-size.
+ */
+struct DexOptHeader {
+    u1  magic[8];           /* includes version number */
+
+    u4  dexOffset;          /* file offset of DEX header */
+    u4  dexLength;
+    u4  depsOffset;         /* offset of optimized DEX dependency table */
+    u4  depsLength;
+    u4  optOffset;          /* file offset of optimized data tables */
+    u4  optLength;
+
+    u4  flags;              /* some info flags */
+    u4  checksum;           /* adler32 checksum covering deps/opt */
+
+    /* pad for 64-bit alignment if necessary */
+};
+
+#define DEX_OPT_FLAG_BIG            (1<<1)  /* swapped to big-endian */
+
+#define DEX_INTERFACE_CACHE_SIZE    128     /* must be power of 2 */
+
+/*
+ * Structure representing a DEX file.
+ *
+ * Code should regard DexFile as opaque, using the API calls provided here
+ * to access specific structures.
+ */
+struct DexFile {
+    /* directly-mapped "opt" header */
+    const DexOptHeader* pOptHeader;
+
+    /* pointers to directly-mapped structs and arrays in base DEX */
+    const DexHeader*    pHeader;
+    const DexStringId*  pStringIds;
+    const DexTypeId*    pTypeIds;
+    const DexFieldId*   pFieldIds;
+    const DexMethodId*  pMethodIds;
+    const DexProtoId*   pProtoIds;
+    const DexClassDef*  pClassDefs;
+    const DexLink*      pLinkData;
+
+    /*
+     * These are mapped out of the "auxillary" section, and may not be
+     * included in the file.
+     */
+    const DexClassLookup* pClassLookup;
+    const void*         pRegisterMapPool;       // RegisterMapClassPool
+
+    /* points to start of DEX file data */
+    const u1*           baseAddr;
+
+    /* track memory overhead for auxillary structures */
+    int                 overhead;
+
+    /* additional app-specific data structures associated with the DEX */
+    //void*               auxData;
+};
+
+/*
+ * Utility function -- rounds up to the nearest power of 2.
+ */
+u4 dexRoundUpPower2(u4 val);
+
+/*
+ * Parse an optimized or unoptimized .dex file sitting in memory.
+ *
+ * On success, return a newly-allocated DexFile.
+ */
+DexFile* dexFileParse(const u1* data, size_t length, int flags);
+
+/* bit values for "flags" argument to dexFileParse */
+enum {
+    kDexParseDefault            = 0,
+    kDexParseVerifyChecksum     = 1,
+    kDexParseContinueOnError    = (1 << 1),
+};
+
+/*
+ * Fix the byte ordering of all fields in the DEX file, and do
+ * structural verification. This is only required for code that opens
+ * "raw" DEX files, such as the DEX optimizer.
+ *
+ * Return 0 on success.
+ */
+int dexSwapAndVerify(u1* addr, int len);
+
+/*
+ * Detect the file type of the given memory buffer via magic number.
+ * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
+ * but return successfully on an optimized DEX file, and report an
+ * error for all other cases.
+ *
+ * Return 0 on success.
+ */
+int dexSwapAndVerifyIfNecessary(u1* addr, int len);
+
+/*
+ * Check to see if the file magic and format version in the given
+ * header are recognized as valid. Returns true if they are
+ * acceptable.
+ */
+bool dexHasValidMagic(const DexHeader* pHeader);
+
+/*
+ * Compute DEX checksum.
+ */
+u4 dexComputeChecksum(const DexHeader* pHeader);
+
+/*
+ * Free a DexFile structure, along with any associated structures.
+ */
+void dexFileFree(DexFile* pDexFile);
+
+/*
+ * Create class lookup table.
+ */
+DexClassLookup* dexCreateClassLookup(DexFile* pDexFile);
+
+/*
+ * Find a class definition by descriptor.
+ */
+const DexClassDef* dexFindClass(const DexFile* pFile, const char* descriptor);
+
+/*
+ * Set up the basic raw data pointers of a DexFile. This function isn't
+ * meant for general use.
+ */
+void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data);
+
+/* return the DexMapList of the file, if any */
+DEX_INLINE const DexMapList* dexGetMap(const DexFile* pDexFile) {
+    u4 mapOff = pDexFile->pHeader->mapOff;
+
+    if (mapOff == 0) {
+        return NULL;
+    } else {
+        return (const DexMapList*) (pDexFile->baseAddr + mapOff);
+    }
+}
+
+/* return the const char* string data referred to by the given string_id */
+DEX_INLINE const char* dexGetStringData(const DexFile* pDexFile,
+        const DexStringId* pStringId) {
+    const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
+
+    // Skip the uleb128 length.
+    while (*(ptr++) > 0x7f) /* empty */ ;
+
+    return (const char*) ptr;
+}
+/* return the StringId with the specified index */
+DEX_INLINE const DexStringId* dexGetStringId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->stringIdsSize);
+    return &pDexFile->pStringIds[idx];
+}
+/* return the UTF-8 encoded string with the specified string_id index */
+DEX_INLINE const char* dexStringById(const DexFile* pDexFile, u4 idx) {
+    const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
+    return dexGetStringData(pDexFile, pStringId);
+}
+
+/* Return the UTF-8 encoded string with the specified string_id index,
+ * also filling in the UTF-16 size (number of 16-bit code points).*/
+const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
+        u4* utf16Size);
+
+/* return the TypeId with the specified index */
+DEX_INLINE const DexTypeId* dexGetTypeId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->typeIdsSize);
+    return &pDexFile->pTypeIds[idx];
+}
+
+/*
+ * Get the descriptor string associated with a given type index.
+ * The caller should not free() the returned string.
+ */
+DEX_INLINE const char* dexStringByTypeIdx(const DexFile* pDexFile, u4 idx) {
+    const DexTypeId* typeId = dexGetTypeId(pDexFile, idx);
+    return dexStringById(pDexFile, typeId->descriptorIdx);
+}
+
+/* return the MethodId with the specified index */
+DEX_INLINE const DexMethodId* dexGetMethodId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->methodIdsSize);
+    return &pDexFile->pMethodIds[idx];
+}
+
+/* return the FieldId with the specified index */
+DEX_INLINE const DexFieldId* dexGetFieldId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->fieldIdsSize);
+    return &pDexFile->pFieldIds[idx];
+}
+
+/* return the ProtoId with the specified index */
+DEX_INLINE const DexProtoId* dexGetProtoId(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->protoIdsSize);
+    return &pDexFile->pProtoIds[idx];
+}
+
+/*
+ * Get the parameter list from a ProtoId. The returns NULL if the ProtoId
+ * does not have a parameter list.
+ */
+DEX_INLINE const DexTypeList* dexGetProtoParameters(
+    const DexFile *pDexFile, const DexProtoId* pProtoId) {
+    if (pProtoId->parametersOff == 0) {
+        return NULL;
+    }
+    return (const DexTypeList*)
+        (pDexFile->baseAddr + pProtoId->parametersOff);
+}
+
+/* return the ClassDef with the specified index */
+DEX_INLINE const DexClassDef* dexGetClassDef(const DexFile* pDexFile, u4 idx) {
+    assert(idx < pDexFile->pHeader->classDefsSize);
+    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)
+{
+    if (pClassDef->interfacesOff == 0)
+        return NULL;
+    return (const DexTypeList*)
+        (pDexFile->baseAddr + pClassDef->interfacesOff);
+}
+/* return the Nth entry in a DexTypeList. */
+DEX_INLINE const DexTypeItem* dexGetTypeItem(const DexTypeList* pList,
+    u4 idx)
+{
+    assert(idx < pList->size);
+    return &pList->list[idx];
+}
+/* return the type_idx for the Nth entry in a TypeList */
+DEX_INLINE u4 dexTypeListGetIdx(const DexTypeList* pList, u4 idx) {
+    const DexTypeItem* pItem = dexGetTypeItem(pList, idx);
+    return pItem->typeIdx;
+}
+
+/* get the static values list for a DexClass */
+DEX_INLINE const DexEncodedArray* dexGetStaticValuesList(
+    const DexFile* pDexFile, const DexClassDef* pClassDef)
+{
+    if (pClassDef->staticValuesOff == 0)
+        return NULL;
+    return (const DexEncodedArray*)
+        (pDexFile->baseAddr + pClassDef->staticValuesOff);
+}
+
+/* get the annotations directory item for a DexClass */
+DEX_INLINE const DexAnnotationsDirectoryItem* dexGetAnnotationsDirectoryItem(
+    const DexFile* pDexFile, const DexClassDef* pClassDef)
+{
+    if (pClassDef->annotationsOff == 0)
+        return NULL;
+    return (const DexAnnotationsDirectoryItem*)
+        (pDexFile->baseAddr + pClassDef->annotationsOff);
+}
+
+/* get the source file string */
+DEX_INLINE const char* dexGetSourceFile(
+    const DexFile* pDexFile, const DexClassDef* pClassDef)
+{
+    if (pClassDef->sourceFileIdx == 0xffffffff)
+        return NULL;
+    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];
+
+    // Round to four bytes.
+    if ((((u4) insnsEnd) & 3) != 0) {
+        insnsEnd++;
+    }
+
+    return (const DexTry*) insnsEnd;
+}
+
+/* Get the base of the encoded data for the given DexCode. */
+DEX_INLINE const u1* dexGetCatchHandlerData(const DexCode* pCode) {
+    const DexTry* pTries = dexGetTries(pCode);
+    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)
+{
+    if (pCode->debugInfoOff == 0) {
+        return NULL;
+    } else {
+        return pDexFile->baseAddr + pCode->debugInfoOff;
+    }
+}
+
+/* DexClassDef convenience - get class descriptor */
+DEX_INLINE const char* dexGetClassDescriptor(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    return dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+}
+
+/* DexClassDef convenience - get superclass descriptor */
+DEX_INLINE const char* dexGetSuperClassDescriptor(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    if (pClassDef->superclassIdx == 0)
+        return NULL;
+    return dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+}
+
+/* DexClassDef convenience - get class_data_item pointer */
+DEX_INLINE const u1* dexGetClassData(const DexFile* pDexFile,
+    const DexClassDef* pClassDef)
+{
+    if (pClassDef->classDataOff == 0)
+        return NULL;
+    return (const u1*) (pDexFile->baseAddr + pClassDef->classDataOff);
+}
+
+/* Get an annotation set at a particular offset. */
+DEX_INLINE const DexAnnotationSetItem* dexGetAnnotationSetItem(
+    const DexFile* pDexFile, u4 offset)
+{
+    return (const DexAnnotationSetItem*) (pDexFile->baseAddr + offset);
+}
+/* get the class' annotation set */
+DEX_INLINE const DexAnnotationSetItem* dexGetClassAnnotationSet(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    if (pAnnoDir->classAnnotationsOff == 0)
+        return NULL;
+    return dexGetAnnotationSetItem(pDexFile, pAnnoDir->classAnnotationsOff);
+}
+
+/* get the class' field annotation list */
+DEX_INLINE const DexFieldAnnotationsItem* dexGetFieldAnnotations(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    if (pAnnoDir->fieldsSize == 0)
+        return NULL;
+
+    // Skip past the header to the start of the field annotations.
+    return (const DexFieldAnnotationsItem*) &pAnnoDir[1];
+}
+
+/* get field annotation list size */
+DEX_INLINE int dexGetFieldAnnotationsSize(const DexFile* pDexFile,
+    const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    return pAnnoDir->fieldsSize;
+}
+
+/* return a pointer to the field's annotation set */
+DEX_INLINE const DexAnnotationSetItem* dexGetFieldAnnotationSetItem(
+    const DexFile* pDexFile, const DexFieldAnnotationsItem* pItem)
+{
+    return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff);
+}
+
+/* get the class' method annotation list */
+DEX_INLINE const DexMethodAnnotationsItem* dexGetMethodAnnotations(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    if (pAnnoDir->methodsSize == 0)
+        return NULL;
+
+    /*
+     * Skip past the header and field annotations to the start of the
+     * method annotations.
+     */
+    const u1* addr = (const u1*) &pAnnoDir[1];
+    addr += pAnnoDir->fieldsSize * sizeof (DexFieldAnnotationsItem);
+    return (const DexMethodAnnotationsItem*) addr;
+}
+
+/* get method annotation list size */
+DEX_INLINE int dexGetMethodAnnotationsSize(const DexFile* pDexFile,
+    const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    return pAnnoDir->methodsSize;
+}
+
+/* return a pointer to the method's annotation set */
+DEX_INLINE const DexAnnotationSetItem* dexGetMethodAnnotationSetItem(
+    const DexFile* pDexFile, const DexMethodAnnotationsItem* pItem)
+{
+    return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff);
+}
+
+/* get the class' parameter annotation list */
+DEX_INLINE const DexParameterAnnotationsItem* dexGetParameterAnnotations(
+    const DexFile* pDexFile, const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    if (pAnnoDir->parametersSize == 0)
+        return NULL;
+
+    /*
+     * Skip past the header, field annotations, and method annotations
+     * to the start of the parameter annotations.
+     */
+    const u1* addr = (const u1*) &pAnnoDir[1];
+    addr += pAnnoDir->fieldsSize * sizeof (DexFieldAnnotationsItem);
+    addr += pAnnoDir->methodsSize * sizeof (DexMethodAnnotationsItem);
+    return (const DexParameterAnnotationsItem*) addr;
+}
+
+/* get method annotation list size */
+DEX_INLINE int dexGetParameterAnnotationsSize(const DexFile* pDexFile,
+    const DexAnnotationsDirectoryItem* pAnnoDir)
+{
+    return pAnnoDir->parametersSize;
+}
+
+/* return the parameter annotation ref list */
+DEX_INLINE const DexAnnotationSetRefList* dexGetParameterAnnotationSetRefList(
+    const DexFile* pDexFile, const DexParameterAnnotationsItem* pItem)
+{
+    return (const DexAnnotationSetRefList*)
+        (pDexFile->baseAddr + pItem->annotationsOff);
+}
+
+/* get method annotation list size */
+DEX_INLINE int dexGetParameterAnnotationSetRefSize(const DexFile* pDexFile,
+    const DexParameterAnnotationsItem* pItem)
+{
+    if (pItem->annotationsOff == 0)
+        return 0;
+    return dexGetParameterAnnotationSetRefList(pDexFile, pItem)->size;
+}
+
+/* return the Nth entry from an annotation set ref list */
+DEX_INLINE const DexAnnotationSetRefItem* dexGetParameterAnnotationSetRef(
+    const DexAnnotationSetRefList* pList, u4 idx)
+{
+    assert(idx < pList->size);
+    return &pList->list[idx];
+}
+
+/* given a DexAnnotationSetRefItem, return the DexAnnotationSetItem */
+DEX_INLINE const DexAnnotationSetItem* dexGetSetRefItemItem(
+    const DexFile* pDexFile, const DexAnnotationSetRefItem* pItem)
+{
+    return dexGetAnnotationSetItem(pDexFile, pItem->annotationsOff);
+}
+
+/* return the Nth annotation offset from a DexAnnotationSetItem */
+DEX_INLINE u4 dexGetAnnotationOff(
+    const DexAnnotationSetItem* pAnnoSet, u4 idx)
+{
+    assert(idx < pAnnoSet->size);
+    return pAnnoSet->entries[idx];
+}
+
+/* return the Nth annotation item from a DexAnnotationSetItem */
+DEX_INLINE const DexAnnotationItem* dexGetAnnotationItem(
+    const DexFile* pDexFile, const DexAnnotationSetItem* pAnnoSet, u4 idx)
+{
+    return (const DexAnnotationItem*)
+        (pDexFile->baseAddr + dexGetAnnotationOff(pAnnoSet, idx));
+}
+
+/*
+ * Get the type descriptor character associated with a given primitive
+ * type. This returns '\0' if the type is invalid.
+ */
+char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type);
+
+/*
+ * Get the type descriptor string associated with a given primitive
+ * type.
+ */
+const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type);
+
+/*
+ * Get the boxed type descriptor string associated with a given
+ * primitive type. This returns NULL for an invalid type, including
+ * particularly for type "void". In the latter case, even though there
+ * is a class Void, there's no such thing as a boxed instance of it.
+ */
+const char* dexGetBoxedTypeDescriptor(PrimitiveType type);
+
+/*
+ * Get the primitive type constant from the given descriptor character.
+ * This returns PRIM_NOT (note: this is a 0) if the character is invalid
+ * as a primitive type descriptor.
+ */
+PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar);
+
+#endif  // LIBDEX_DEXFILE_H_
diff --git a/libdex/DexInlines.cpp b/libdex/DexInlines.cpp
new file mode 100644
index 0000000..cbedb62
--- /dev/null
+++ b/libdex/DexInlines.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/*
+ * Generate non-inline copies of inline functions in header files.
+ */
+
+#define _DEX_GEN_INLINES
+
+#include "DexFile.h"
+
+#include "DexCatch.h"
+#include "DexClass.h"
+#include "DexDataMap.h"
+#include "DexUtf.h"
+#include "DexOpcodes.h"
+#include "DexProto.h"
+#include "InstrUtils.h"
+#include "Leb128.h"
+#include "ZipArchive.h"
diff --git a/libdex/DexOpcodes.cpp b/libdex/DexOpcodes.cpp
new file mode 100644
index 0000000..50254a7
--- /dev/null
+++ b/libdex/DexOpcodes.cpp
@@ -0,0 +1,555 @@
+/*
+ * 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.
+ */
+
+/*
+ * Table of Dalvik opcode names.
+ *
+ * IMPORTANT NOTE: The contents of this file are mostly generated
+ * automatically by the opcode-gen tool. Any edits to the generated
+ * sections will get wiped out the next time the tool is run.
+ */
+
+#include "DexOpcodes.h"
+#include <assert.h>
+
+/*
+ * Dalvik opcode names.
+ */
+static const char* gOpNames[kNumPackedOpcodes] = {
+    // BEGIN(libdex-opcode-names); GENERATED AUTOMATICALLY BY opcode-gen
+    "nop",
+    "move",
+    "move/from16",
+    "move/16",
+    "move-wide",
+    "move-wide/from16",
+    "move-wide/16",
+    "move-object",
+    "move-object/from16",
+    "move-object/16",
+    "move-result",
+    "move-result-wide",
+    "move-result-object",
+    "move-exception",
+    "return-void",
+    "return",
+    "return-wide",
+    "return-object",
+    "const/4",
+    "const/16",
+    "const",
+    "const/high16",
+    "const-wide/16",
+    "const-wide/32",
+    "const-wide",
+    "const-wide/high16",
+    "const-string",
+    "const-string/jumbo",
+    "const-class",
+    "monitor-enter",
+    "monitor-exit",
+    "check-cast",
+    "instance-of",
+    "array-length",
+    "new-instance",
+    "new-array",
+    "filled-new-array",
+    "filled-new-array/range",
+    "fill-array-data",
+    "throw",
+    "goto",
+    "goto/16",
+    "goto/32",
+    "packed-switch",
+    "sparse-switch",
+    "cmpl-float",
+    "cmpg-float",
+    "cmpl-double",
+    "cmpg-double",
+    "cmp-long",
+    "if-eq",
+    "if-ne",
+    "if-lt",
+    "if-ge",
+    "if-gt",
+    "if-le",
+    "if-eqz",
+    "if-nez",
+    "if-ltz",
+    "if-gez",
+    "if-gtz",
+    "if-lez",
+    "unused-3e",
+    "unused-3f",
+    "unused-40",
+    "unused-41",
+    "unused-42",
+    "unused-43",
+    "aget",
+    "aget-wide",
+    "aget-object",
+    "aget-boolean",
+    "aget-byte",
+    "aget-char",
+    "aget-short",
+    "aput",
+    "aput-wide",
+    "aput-object",
+    "aput-boolean",
+    "aput-byte",
+    "aput-char",
+    "aput-short",
+    "iget",
+    "iget-wide",
+    "iget-object",
+    "iget-boolean",
+    "iget-byte",
+    "iget-char",
+    "iget-short",
+    "iput",
+    "iput-wide",
+    "iput-object",
+    "iput-boolean",
+    "iput-byte",
+    "iput-char",
+    "iput-short",
+    "sget",
+    "sget-wide",
+    "sget-object",
+    "sget-boolean",
+    "sget-byte",
+    "sget-char",
+    "sget-short",
+    "sput",
+    "sput-wide",
+    "sput-object",
+    "sput-boolean",
+    "sput-byte",
+    "sput-char",
+    "sput-short",
+    "invoke-virtual",
+    "invoke-super",
+    "invoke-direct",
+    "invoke-static",
+    "invoke-interface",
+    "unused-73",
+    "invoke-virtual/range",
+    "invoke-super/range",
+    "invoke-direct/range",
+    "invoke-static/range",
+    "invoke-interface/range",
+    "unused-79",
+    "unused-7a",
+    "neg-int",
+    "not-int",
+    "neg-long",
+    "not-long",
+    "neg-float",
+    "neg-double",
+    "int-to-long",
+    "int-to-float",
+    "int-to-double",
+    "long-to-int",
+    "long-to-float",
+    "long-to-double",
+    "float-to-int",
+    "float-to-long",
+    "float-to-double",
+    "double-to-int",
+    "double-to-long",
+    "double-to-float",
+    "int-to-byte",
+    "int-to-char",
+    "int-to-short",
+    "add-int",
+    "sub-int",
+    "mul-int",
+    "div-int",
+    "rem-int",
+    "and-int",
+    "or-int",
+    "xor-int",
+    "shl-int",
+    "shr-int",
+    "ushr-int",
+    "add-long",
+    "sub-long",
+    "mul-long",
+    "div-long",
+    "rem-long",
+    "and-long",
+    "or-long",
+    "xor-long",
+    "shl-long",
+    "shr-long",
+    "ushr-long",
+    "add-float",
+    "sub-float",
+    "mul-float",
+    "div-float",
+    "rem-float",
+    "add-double",
+    "sub-double",
+    "mul-double",
+    "div-double",
+    "rem-double",
+    "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-long/2addr",
+    "sub-long/2addr",
+    "mul-long/2addr",
+    "div-long/2addr",
+    "rem-long/2addr",
+    "and-long/2addr",
+    "or-long/2addr",
+    "xor-long/2addr",
+    "shl-long/2addr",
+    "shr-long/2addr",
+    "ushr-long/2addr",
+    "add-float/2addr",
+    "sub-float/2addr",
+    "mul-float/2addr",
+    "div-float/2addr",
+    "rem-float/2addr",
+    "add-double/2addr",
+    "sub-double/2addr",
+    "mul-double/2addr",
+    "div-double/2addr",
+    "rem-double/2addr",
+    "add-int/lit16",
+    "rsub-int",
+    "mul-int/lit16",
+    "div-int/lit16",
+    "rem-int/lit16",
+    "and-int/lit16",
+    "or-int/lit16",
+    "xor-int/lit16",
+    "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",
+    "+iget-volatile",
+    "+iput-volatile",
+    "+sget-volatile",
+    "+sput-volatile",
+    "+iget-object-volatile",
+    "+iget-wide-volatile",
+    "+iput-wide-volatile",
+    "+sget-wide-volatile",
+    "+sput-wide-volatile",
+    "^breakpoint",
+    "^throw-verification-error",
+    "+execute-inline",
+    "+execute-inline/range",
+    "+invoke-object-init/range",
+    "+return-void-barrier",
+    "+iget-quick",
+    "+iget-wide-quick",
+    "+iget-object-quick",
+    "+iput-quick",
+    "+iput-wide-quick",
+    "+iput-object-quick",
+    "+invoke-virtual-quick",
+    "+invoke-virtual-quick/range",
+    "+invoke-super-quick",
+    "+invoke-super-quick/range",
+    "+iput-object-volatile",
+    "+sget-object-volatile",
+    "+sput-object-volatile",
+    "dispatch-ff",
+    "const-class/jumbo",
+    "check-cast/jumbo",
+    "instance-of/jumbo",
+    "new-instance/jumbo",
+    "new-array/jumbo",
+    "filled-new-array/jumbo",
+    "iget/jumbo",
+    "iget-wide/jumbo",
+    "iget-object/jumbo",
+    "iget-boolean/jumbo",
+    "iget-byte/jumbo",
+    "iget-char/jumbo",
+    "iget-short/jumbo",
+    "iput/jumbo",
+    "iput-wide/jumbo",
+    "iput-object/jumbo",
+    "iput-boolean/jumbo",
+    "iput-byte/jumbo",
+    "iput-char/jumbo",
+    "iput-short/jumbo",
+    "sget/jumbo",
+    "sget-wide/jumbo",
+    "sget-object/jumbo",
+    "sget-boolean/jumbo",
+    "sget-byte/jumbo",
+    "sget-char/jumbo",
+    "sget-short/jumbo",
+    "sput/jumbo",
+    "sput-wide/jumbo",
+    "sput-object/jumbo",
+    "sput-boolean/jumbo",
+    "sput-byte/jumbo",
+    "sput-char/jumbo",
+    "sput-short/jumbo",
+    "invoke-virtual/jumbo",
+    "invoke-super/jumbo",
+    "invoke-direct/jumbo",
+    "invoke-static/jumbo",
+    "invoke-interface/jumbo",
+    "unused-27ff",
+    "unused-28ff",
+    "unused-29ff",
+    "unused-2aff",
+    "unused-2bff",
+    "unused-2cff",
+    "unused-2dff",
+    "unused-2eff",
+    "unused-2fff",
+    "unused-30ff",
+    "unused-31ff",
+    "unused-32ff",
+    "unused-33ff",
+    "unused-34ff",
+    "unused-35ff",
+    "unused-36ff",
+    "unused-37ff",
+    "unused-38ff",
+    "unused-39ff",
+    "unused-3aff",
+    "unused-3bff",
+    "unused-3cff",
+    "unused-3dff",
+    "unused-3eff",
+    "unused-3fff",
+    "unused-40ff",
+    "unused-41ff",
+    "unused-42ff",
+    "unused-43ff",
+    "unused-44ff",
+    "unused-45ff",
+    "unused-46ff",
+    "unused-47ff",
+    "unused-48ff",
+    "unused-49ff",
+    "unused-4aff",
+    "unused-4bff",
+    "unused-4cff",
+    "unused-4dff",
+    "unused-4eff",
+    "unused-4fff",
+    "unused-50ff",
+    "unused-51ff",
+    "unused-52ff",
+    "unused-53ff",
+    "unused-54ff",
+    "unused-55ff",
+    "unused-56ff",
+    "unused-57ff",
+    "unused-58ff",
+    "unused-59ff",
+    "unused-5aff",
+    "unused-5bff",
+    "unused-5cff",
+    "unused-5dff",
+    "unused-5eff",
+    "unused-5fff",
+    "unused-60ff",
+    "unused-61ff",
+    "unused-62ff",
+    "unused-63ff",
+    "unused-64ff",
+    "unused-65ff",
+    "unused-66ff",
+    "unused-67ff",
+    "unused-68ff",
+    "unused-69ff",
+    "unused-6aff",
+    "unused-6bff",
+    "unused-6cff",
+    "unused-6dff",
+    "unused-6eff",
+    "unused-6fff",
+    "unused-70ff",
+    "unused-71ff",
+    "unused-72ff",
+    "unused-73ff",
+    "unused-74ff",
+    "unused-75ff",
+    "unused-76ff",
+    "unused-77ff",
+    "unused-78ff",
+    "unused-79ff",
+    "unused-7aff",
+    "unused-7bff",
+    "unused-7cff",
+    "unused-7dff",
+    "unused-7eff",
+    "unused-7fff",
+    "unused-80ff",
+    "unused-81ff",
+    "unused-82ff",
+    "unused-83ff",
+    "unused-84ff",
+    "unused-85ff",
+    "unused-86ff",
+    "unused-87ff",
+    "unused-88ff",
+    "unused-89ff",
+    "unused-8aff",
+    "unused-8bff",
+    "unused-8cff",
+    "unused-8dff",
+    "unused-8eff",
+    "unused-8fff",
+    "unused-90ff",
+    "unused-91ff",
+    "unused-92ff",
+    "unused-93ff",
+    "unused-94ff",
+    "unused-95ff",
+    "unused-96ff",
+    "unused-97ff",
+    "unused-98ff",
+    "unused-99ff",
+    "unused-9aff",
+    "unused-9bff",
+    "unused-9cff",
+    "unused-9dff",
+    "unused-9eff",
+    "unused-9fff",
+    "unused-a0ff",
+    "unused-a1ff",
+    "unused-a2ff",
+    "unused-a3ff",
+    "unused-a4ff",
+    "unused-a5ff",
+    "unused-a6ff",
+    "unused-a7ff",
+    "unused-a8ff",
+    "unused-a9ff",
+    "unused-aaff",
+    "unused-abff",
+    "unused-acff",
+    "unused-adff",
+    "unused-aeff",
+    "unused-afff",
+    "unused-b0ff",
+    "unused-b1ff",
+    "unused-b2ff",
+    "unused-b3ff",
+    "unused-b4ff",
+    "unused-b5ff",
+    "unused-b6ff",
+    "unused-b7ff",
+    "unused-b8ff",
+    "unused-b9ff",
+    "unused-baff",
+    "unused-bbff",
+    "unused-bcff",
+    "unused-bdff",
+    "unused-beff",
+    "unused-bfff",
+    "unused-c0ff",
+    "unused-c1ff",
+    "unused-c2ff",
+    "unused-c3ff",
+    "unused-c4ff",
+    "unused-c5ff",
+    "unused-c6ff",
+    "unused-c7ff",
+    "unused-c8ff",
+    "unused-c9ff",
+    "unused-caff",
+    "unused-cbff",
+    "unused-ccff",
+    "unused-cdff",
+    "unused-ceff",
+    "unused-cfff",
+    "unused-d0ff",
+    "unused-d1ff",
+    "unused-d2ff",
+    "unused-d3ff",
+    "unused-d4ff",
+    "unused-d5ff",
+    "unused-d6ff",
+    "unused-d7ff",
+    "unused-d8ff",
+    "unused-d9ff",
+    "unused-daff",
+    "unused-dbff",
+    "unused-dcff",
+    "unused-ddff",
+    "unused-deff",
+    "unused-dfff",
+    "unused-e0ff",
+    "unused-e1ff",
+    "unused-e2ff",
+    "unused-e3ff",
+    "unused-e4ff",
+    "unused-e5ff",
+    "unused-e6ff",
+    "unused-e7ff",
+    "unused-e8ff",
+    "unused-e9ff",
+    "unused-eaff",
+    "unused-ebff",
+    "unused-ecff",
+    "unused-edff",
+    "unused-eeff",
+    "unused-efff",
+    "unused-f0ff",
+    "unused-f1ff",
+    "+invoke-object-init/jumbo",
+    "+iget-volatile/jumbo",
+    "+iget-wide-volatile/jumbo",
+    "+iget-object-volatile/jumbo",
+    "+iput-volatile/jumbo",
+    "+iput-wide-volatile/jumbo",
+    "+iput-object-volatile/jumbo",
+    "+sget-volatile/jumbo",
+    "+sget-wide-volatile/jumbo",
+    "+sget-object-volatile/jumbo",
+    "+sput-volatile/jumbo",
+    "+sput-wide-volatile/jumbo",
+    "+sput-object-volatile/jumbo",
+    "^throw-verification-error/jumbo",
+    // END(libdex-opcode-names)
+};
+
+/*
+ * Return the name of an opcode.
+ */
+const char* dexGetOpcodeName(Opcode op)
+{
+    assert(op >= 0 && op < kNumPackedOpcodes);
+    return gOpNames[op];
+}
diff --git a/libdex/DexOpcodes.h b/libdex/DexOpcodes.h
new file mode 100644
index 0000000..472fe36
--- /dev/null
+++ b/libdex/DexOpcodes.h
@@ -0,0 +1,1136 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik opcode information.
+ *
+ * IMPORTANT NOTE: The contents of this file are mostly generated
+ * automatically by the opcode-gen tool. Any edits to the generated
+ * sections will get wiped out the next time the tool is run.
+ *
+ * See the file opcode-gen/README.txt for information about updating
+ * opcodes and instruction formats.
+ */
+
+#ifndef LIBDEX_DEXOPCODES_H_
+#define LIBDEX_DEXOPCODES_H_
+
+#include "DexFile.h"
+
+/*
+ * kMaxOpcodeValue: the highest possible raw (unpacked) opcode value
+ *
+ * kNumPackedOpcodes: the highest possible packed opcode value of a
+ * valid Dalvik opcode, plus one
+ *
+ * TODO: Change this once the rest of the code is prepared to deal with
+ * extended opcodes.
+ */
+// BEGIN(libdex-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen
+#define kMaxOpcodeValue 0xffff
+#define kNumPackedOpcodes 0x200
+// END(libdex-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen
+
+/*
+ * Switch table and array data signatures are a code unit consisting
+ * of "NOP" (0x00) in the low-order byte and a non-zero identifying
+ * code in the high-order byte. (A true NOP is 0x0000.)
+ */
+#define kPackedSwitchSignature  0x0100
+#define kSparseSwitchSignature  0x0200
+#define kArrayDataSignature     0x0300
+
+/*
+ * Enumeration of all Dalvik opcodes, where the enumeration value
+ * associated with each is the corresponding packed opcode number.
+ * This is different than the opcode value from the Dalvik bytecode
+ * spec for opcode values >= 0xff; see dexOpcodeFromCodeUnit() below.
+ *
+ * A note about the "breakpoint" opcode. This instruction is special,
+ * in that it should never be seen by anything but the debug
+ * interpreter. During debugging it takes the place of an arbitrary
+ * opcode, which means operations like "tell me the opcode width so I
+ * can find the next instruction" aren't possible. (This is
+ * correctable, but probably not useful.)
+ */
+enum Opcode {
+    // BEGIN(libdex-opcode-enum); GENERATED AUTOMATICALLY BY opcode-gen
+    OP_NOP                          = 0x00,
+    OP_MOVE                         = 0x01,
+    OP_MOVE_FROM16                  = 0x02,
+    OP_MOVE_16                      = 0x03,
+    OP_MOVE_WIDE                    = 0x04,
+    OP_MOVE_WIDE_FROM16             = 0x05,
+    OP_MOVE_WIDE_16                 = 0x06,
+    OP_MOVE_OBJECT                  = 0x07,
+    OP_MOVE_OBJECT_FROM16           = 0x08,
+    OP_MOVE_OBJECT_16               = 0x09,
+    OP_MOVE_RESULT                  = 0x0a,
+    OP_MOVE_RESULT_WIDE             = 0x0b,
+    OP_MOVE_RESULT_OBJECT           = 0x0c,
+    OP_MOVE_EXCEPTION               = 0x0d,
+    OP_RETURN_VOID                  = 0x0e,
+    OP_RETURN                       = 0x0f,
+    OP_RETURN_WIDE                  = 0x10,
+    OP_RETURN_OBJECT                = 0x11,
+    OP_CONST_4                      = 0x12,
+    OP_CONST_16                     = 0x13,
+    OP_CONST                        = 0x14,
+    OP_CONST_HIGH16                 = 0x15,
+    OP_CONST_WIDE_16                = 0x16,
+    OP_CONST_WIDE_32                = 0x17,
+    OP_CONST_WIDE                   = 0x18,
+    OP_CONST_WIDE_HIGH16            = 0x19,
+    OP_CONST_STRING                 = 0x1a,
+    OP_CONST_STRING_JUMBO           = 0x1b,
+    OP_CONST_CLASS                  = 0x1c,
+    OP_MONITOR_ENTER                = 0x1d,
+    OP_MONITOR_EXIT                 = 0x1e,
+    OP_CHECK_CAST                   = 0x1f,
+    OP_INSTANCE_OF                  = 0x20,
+    OP_ARRAY_LENGTH                 = 0x21,
+    OP_NEW_INSTANCE                 = 0x22,
+    OP_NEW_ARRAY                    = 0x23,
+    OP_FILLED_NEW_ARRAY             = 0x24,
+    OP_FILLED_NEW_ARRAY_RANGE       = 0x25,
+    OP_FILL_ARRAY_DATA              = 0x26,
+    OP_THROW                        = 0x27,
+    OP_GOTO                         = 0x28,
+    OP_GOTO_16                      = 0x29,
+    OP_GOTO_32                      = 0x2a,
+    OP_PACKED_SWITCH                = 0x2b,
+    OP_SPARSE_SWITCH                = 0x2c,
+    OP_CMPL_FLOAT                   = 0x2d,
+    OP_CMPG_FLOAT                   = 0x2e,
+    OP_CMPL_DOUBLE                  = 0x2f,
+    OP_CMPG_DOUBLE                  = 0x30,
+    OP_CMP_LONG                     = 0x31,
+    OP_IF_EQ                        = 0x32,
+    OP_IF_NE                        = 0x33,
+    OP_IF_LT                        = 0x34,
+    OP_IF_GE                        = 0x35,
+    OP_IF_GT                        = 0x36,
+    OP_IF_LE                        = 0x37,
+    OP_IF_EQZ                       = 0x38,
+    OP_IF_NEZ                       = 0x39,
+    OP_IF_LTZ                       = 0x3a,
+    OP_IF_GEZ                       = 0x3b,
+    OP_IF_GTZ                       = 0x3c,
+    OP_IF_LEZ                       = 0x3d,
+    OP_UNUSED_3E                    = 0x3e,
+    OP_UNUSED_3F                    = 0x3f,
+    OP_UNUSED_40                    = 0x40,
+    OP_UNUSED_41                    = 0x41,
+    OP_UNUSED_42                    = 0x42,
+    OP_UNUSED_43                    = 0x43,
+    OP_AGET                         = 0x44,
+    OP_AGET_WIDE                    = 0x45,
+    OP_AGET_OBJECT                  = 0x46,
+    OP_AGET_BOOLEAN                 = 0x47,
+    OP_AGET_BYTE                    = 0x48,
+    OP_AGET_CHAR                    = 0x49,
+    OP_AGET_SHORT                   = 0x4a,
+    OP_APUT                         = 0x4b,
+    OP_APUT_WIDE                    = 0x4c,
+    OP_APUT_OBJECT                  = 0x4d,
+    OP_APUT_BOOLEAN                 = 0x4e,
+    OP_APUT_BYTE                    = 0x4f,
+    OP_APUT_CHAR                    = 0x50,
+    OP_APUT_SHORT                   = 0x51,
+    OP_IGET                         = 0x52,
+    OP_IGET_WIDE                    = 0x53,
+    OP_IGET_OBJECT                  = 0x54,
+    OP_IGET_BOOLEAN                 = 0x55,
+    OP_IGET_BYTE                    = 0x56,
+    OP_IGET_CHAR                    = 0x57,
+    OP_IGET_SHORT                   = 0x58,
+    OP_IPUT                         = 0x59,
+    OP_IPUT_WIDE                    = 0x5a,
+    OP_IPUT_OBJECT                  = 0x5b,
+    OP_IPUT_BOOLEAN                 = 0x5c,
+    OP_IPUT_BYTE                    = 0x5d,
+    OP_IPUT_CHAR                    = 0x5e,
+    OP_IPUT_SHORT                   = 0x5f,
+    OP_SGET                         = 0x60,
+    OP_SGET_WIDE                    = 0x61,
+    OP_SGET_OBJECT                  = 0x62,
+    OP_SGET_BOOLEAN                 = 0x63,
+    OP_SGET_BYTE                    = 0x64,
+    OP_SGET_CHAR                    = 0x65,
+    OP_SGET_SHORT                   = 0x66,
+    OP_SPUT                         = 0x67,
+    OP_SPUT_WIDE                    = 0x68,
+    OP_SPUT_OBJECT                  = 0x69,
+    OP_SPUT_BOOLEAN                 = 0x6a,
+    OP_SPUT_BYTE                    = 0x6b,
+    OP_SPUT_CHAR                    = 0x6c,
+    OP_SPUT_SHORT                   = 0x6d,
+    OP_INVOKE_VIRTUAL               = 0x6e,
+    OP_INVOKE_SUPER                 = 0x6f,
+    OP_INVOKE_DIRECT                = 0x70,
+    OP_INVOKE_STATIC                = 0x71,
+    OP_INVOKE_INTERFACE             = 0x72,
+    OP_UNUSED_73                    = 0x73,
+    OP_INVOKE_VIRTUAL_RANGE         = 0x74,
+    OP_INVOKE_SUPER_RANGE           = 0x75,
+    OP_INVOKE_DIRECT_RANGE          = 0x76,
+    OP_INVOKE_STATIC_RANGE          = 0x77,
+    OP_INVOKE_INTERFACE_RANGE       = 0x78,
+    OP_UNUSED_79                    = 0x79,
+    OP_UNUSED_7A                    = 0x7a,
+    OP_NEG_INT                      = 0x7b,
+    OP_NOT_INT                      = 0x7c,
+    OP_NEG_LONG                     = 0x7d,
+    OP_NOT_LONG                     = 0x7e,
+    OP_NEG_FLOAT                    = 0x7f,
+    OP_NEG_DOUBLE                   = 0x80,
+    OP_INT_TO_LONG                  = 0x81,
+    OP_INT_TO_FLOAT                 = 0x82,
+    OP_INT_TO_DOUBLE                = 0x83,
+    OP_LONG_TO_INT                  = 0x84,
+    OP_LONG_TO_FLOAT                = 0x85,
+    OP_LONG_TO_DOUBLE               = 0x86,
+    OP_FLOAT_TO_INT                 = 0x87,
+    OP_FLOAT_TO_LONG                = 0x88,
+    OP_FLOAT_TO_DOUBLE              = 0x89,
+    OP_DOUBLE_TO_INT                = 0x8a,
+    OP_DOUBLE_TO_LONG               = 0x8b,
+    OP_DOUBLE_TO_FLOAT              = 0x8c,
+    OP_INT_TO_BYTE                  = 0x8d,
+    OP_INT_TO_CHAR                  = 0x8e,
+    OP_INT_TO_SHORT                 = 0x8f,
+    OP_ADD_INT                      = 0x90,
+    OP_SUB_INT                      = 0x91,
+    OP_MUL_INT                      = 0x92,
+    OP_DIV_INT                      = 0x93,
+    OP_REM_INT                      = 0x94,
+    OP_AND_INT                      = 0x95,
+    OP_OR_INT                       = 0x96,
+    OP_XOR_INT                      = 0x97,
+    OP_SHL_INT                      = 0x98,
+    OP_SHR_INT                      = 0x99,
+    OP_USHR_INT                     = 0x9a,
+    OP_ADD_LONG                     = 0x9b,
+    OP_SUB_LONG                     = 0x9c,
+    OP_MUL_LONG                     = 0x9d,
+    OP_DIV_LONG                     = 0x9e,
+    OP_REM_LONG                     = 0x9f,
+    OP_AND_LONG                     = 0xa0,
+    OP_OR_LONG                      = 0xa1,
+    OP_XOR_LONG                     = 0xa2,
+    OP_SHL_LONG                     = 0xa3,
+    OP_SHR_LONG                     = 0xa4,
+    OP_USHR_LONG                    = 0xa5,
+    OP_ADD_FLOAT                    = 0xa6,
+    OP_SUB_FLOAT                    = 0xa7,
+    OP_MUL_FLOAT                    = 0xa8,
+    OP_DIV_FLOAT                    = 0xa9,
+    OP_REM_FLOAT                    = 0xaa,
+    OP_ADD_DOUBLE                   = 0xab,
+    OP_SUB_DOUBLE                   = 0xac,
+    OP_MUL_DOUBLE                   = 0xad,
+    OP_DIV_DOUBLE                   = 0xae,
+    OP_REM_DOUBLE                   = 0xaf,
+    OP_ADD_INT_2ADDR                = 0xb0,
+    OP_SUB_INT_2ADDR                = 0xb1,
+    OP_MUL_INT_2ADDR                = 0xb2,
+    OP_DIV_INT_2ADDR                = 0xb3,
+    OP_REM_INT_2ADDR                = 0xb4,
+    OP_AND_INT_2ADDR                = 0xb5,
+    OP_OR_INT_2ADDR                 = 0xb6,
+    OP_XOR_INT_2ADDR                = 0xb7,
+    OP_SHL_INT_2ADDR                = 0xb8,
+    OP_SHR_INT_2ADDR                = 0xb9,
+    OP_USHR_INT_2ADDR               = 0xba,
+    OP_ADD_LONG_2ADDR               = 0xbb,
+    OP_SUB_LONG_2ADDR               = 0xbc,
+    OP_MUL_LONG_2ADDR               = 0xbd,
+    OP_DIV_LONG_2ADDR               = 0xbe,
+    OP_REM_LONG_2ADDR               = 0xbf,
+    OP_AND_LONG_2ADDR               = 0xc0,
+    OP_OR_LONG_2ADDR                = 0xc1,
+    OP_XOR_LONG_2ADDR               = 0xc2,
+    OP_SHL_LONG_2ADDR               = 0xc3,
+    OP_SHR_LONG_2ADDR               = 0xc4,
+    OP_USHR_LONG_2ADDR              = 0xc5,
+    OP_ADD_FLOAT_2ADDR              = 0xc6,
+    OP_SUB_FLOAT_2ADDR              = 0xc7,
+    OP_MUL_FLOAT_2ADDR              = 0xc8,
+    OP_DIV_FLOAT_2ADDR              = 0xc9,
+    OP_REM_FLOAT_2ADDR              = 0xca,
+    OP_ADD_DOUBLE_2ADDR             = 0xcb,
+    OP_SUB_DOUBLE_2ADDR             = 0xcc,
+    OP_MUL_DOUBLE_2ADDR             = 0xcd,
+    OP_DIV_DOUBLE_2ADDR             = 0xce,
+    OP_REM_DOUBLE_2ADDR             = 0xcf,
+    OP_ADD_INT_LIT16                = 0xd0,
+    OP_RSUB_INT                     = 0xd1,
+    OP_MUL_INT_LIT16                = 0xd2,
+    OP_DIV_INT_LIT16                = 0xd3,
+    OP_REM_INT_LIT16                = 0xd4,
+    OP_AND_INT_LIT16                = 0xd5,
+    OP_OR_INT_LIT16                 = 0xd6,
+    OP_XOR_INT_LIT16                = 0xd7,
+    OP_ADD_INT_LIT8                 = 0xd8,
+    OP_RSUB_INT_LIT8                = 0xd9,
+    OP_MUL_INT_LIT8                 = 0xda,
+    OP_DIV_INT_LIT8                 = 0xdb,
+    OP_REM_INT_LIT8                 = 0xdc,
+    OP_AND_INT_LIT8                 = 0xdd,
+    OP_OR_INT_LIT8                  = 0xde,
+    OP_XOR_INT_LIT8                 = 0xdf,
+    OP_SHL_INT_LIT8                 = 0xe0,
+    OP_SHR_INT_LIT8                 = 0xe1,
+    OP_USHR_INT_LIT8                = 0xe2,
+    OP_IGET_VOLATILE                = 0xe3,
+    OP_IPUT_VOLATILE                = 0xe4,
+    OP_SGET_VOLATILE                = 0xe5,
+    OP_SPUT_VOLATILE                = 0xe6,
+    OP_IGET_OBJECT_VOLATILE         = 0xe7,
+    OP_IGET_WIDE_VOLATILE           = 0xe8,
+    OP_IPUT_WIDE_VOLATILE           = 0xe9,
+    OP_SGET_WIDE_VOLATILE           = 0xea,
+    OP_SPUT_WIDE_VOLATILE           = 0xeb,
+    OP_BREAKPOINT                   = 0xec,
+    OP_THROW_VERIFICATION_ERROR     = 0xed,
+    OP_EXECUTE_INLINE               = 0xee,
+    OP_EXECUTE_INLINE_RANGE         = 0xef,
+    OP_INVOKE_OBJECT_INIT_RANGE     = 0xf0,
+    OP_RETURN_VOID_BARRIER          = 0xf1,
+    OP_IGET_QUICK                   = 0xf2,
+    OP_IGET_WIDE_QUICK              = 0xf3,
+    OP_IGET_OBJECT_QUICK            = 0xf4,
+    OP_IPUT_QUICK                   = 0xf5,
+    OP_IPUT_WIDE_QUICK              = 0xf6,
+    OP_IPUT_OBJECT_QUICK            = 0xf7,
+    OP_INVOKE_VIRTUAL_QUICK         = 0xf8,
+    OP_INVOKE_VIRTUAL_QUICK_RANGE   = 0xf9,
+    OP_INVOKE_SUPER_QUICK           = 0xfa,
+    OP_INVOKE_SUPER_QUICK_RANGE     = 0xfb,
+    OP_IPUT_OBJECT_VOLATILE         = 0xfc,
+    OP_SGET_OBJECT_VOLATILE         = 0xfd,
+    OP_SPUT_OBJECT_VOLATILE         = 0xfe,
+    OP_DISPATCH_FF                  = 0xff,
+    OP_CONST_CLASS_JUMBO            = 0x100,
+    OP_CHECK_CAST_JUMBO             = 0x101,
+    OP_INSTANCE_OF_JUMBO            = 0x102,
+    OP_NEW_INSTANCE_JUMBO           = 0x103,
+    OP_NEW_ARRAY_JUMBO              = 0x104,
+    OP_FILLED_NEW_ARRAY_JUMBO       = 0x105,
+    OP_IGET_JUMBO                   = 0x106,
+    OP_IGET_WIDE_JUMBO              = 0x107,
+    OP_IGET_OBJECT_JUMBO            = 0x108,
+    OP_IGET_BOOLEAN_JUMBO           = 0x109,
+    OP_IGET_BYTE_JUMBO              = 0x10a,
+    OP_IGET_CHAR_JUMBO              = 0x10b,
+    OP_IGET_SHORT_JUMBO             = 0x10c,
+    OP_IPUT_JUMBO                   = 0x10d,
+    OP_IPUT_WIDE_JUMBO              = 0x10e,
+    OP_IPUT_OBJECT_JUMBO            = 0x10f,
+    OP_IPUT_BOOLEAN_JUMBO           = 0x110,
+    OP_IPUT_BYTE_JUMBO              = 0x111,
+    OP_IPUT_CHAR_JUMBO              = 0x112,
+    OP_IPUT_SHORT_JUMBO             = 0x113,
+    OP_SGET_JUMBO                   = 0x114,
+    OP_SGET_WIDE_JUMBO              = 0x115,
+    OP_SGET_OBJECT_JUMBO            = 0x116,
+    OP_SGET_BOOLEAN_JUMBO           = 0x117,
+    OP_SGET_BYTE_JUMBO              = 0x118,
+    OP_SGET_CHAR_JUMBO              = 0x119,
+    OP_SGET_SHORT_JUMBO             = 0x11a,
+    OP_SPUT_JUMBO                   = 0x11b,
+    OP_SPUT_WIDE_JUMBO              = 0x11c,
+    OP_SPUT_OBJECT_JUMBO            = 0x11d,
+    OP_SPUT_BOOLEAN_JUMBO           = 0x11e,
+    OP_SPUT_BYTE_JUMBO              = 0x11f,
+    OP_SPUT_CHAR_JUMBO              = 0x120,
+    OP_SPUT_SHORT_JUMBO             = 0x121,
+    OP_INVOKE_VIRTUAL_JUMBO         = 0x122,
+    OP_INVOKE_SUPER_JUMBO           = 0x123,
+    OP_INVOKE_DIRECT_JUMBO          = 0x124,
+    OP_INVOKE_STATIC_JUMBO          = 0x125,
+    OP_INVOKE_INTERFACE_JUMBO       = 0x126,
+    OP_UNUSED_27FF                  = 0x127,
+    OP_UNUSED_28FF                  = 0x128,
+    OP_UNUSED_29FF                  = 0x129,
+    OP_UNUSED_2AFF                  = 0x12a,
+    OP_UNUSED_2BFF                  = 0x12b,
+    OP_UNUSED_2CFF                  = 0x12c,
+    OP_UNUSED_2DFF                  = 0x12d,
+    OP_UNUSED_2EFF                  = 0x12e,
+    OP_UNUSED_2FFF                  = 0x12f,
+    OP_UNUSED_30FF                  = 0x130,
+    OP_UNUSED_31FF                  = 0x131,
+    OP_UNUSED_32FF                  = 0x132,
+    OP_UNUSED_33FF                  = 0x133,
+    OP_UNUSED_34FF                  = 0x134,
+    OP_UNUSED_35FF                  = 0x135,
+    OP_UNUSED_36FF                  = 0x136,
+    OP_UNUSED_37FF                  = 0x137,
+    OP_UNUSED_38FF                  = 0x138,
+    OP_UNUSED_39FF                  = 0x139,
+    OP_UNUSED_3AFF                  = 0x13a,
+    OP_UNUSED_3BFF                  = 0x13b,
+    OP_UNUSED_3CFF                  = 0x13c,
+    OP_UNUSED_3DFF                  = 0x13d,
+    OP_UNUSED_3EFF                  = 0x13e,
+    OP_UNUSED_3FFF                  = 0x13f,
+    OP_UNUSED_40FF                  = 0x140,
+    OP_UNUSED_41FF                  = 0x141,
+    OP_UNUSED_42FF                  = 0x142,
+    OP_UNUSED_43FF                  = 0x143,
+    OP_UNUSED_44FF                  = 0x144,
+    OP_UNUSED_45FF                  = 0x145,
+    OP_UNUSED_46FF                  = 0x146,
+    OP_UNUSED_47FF                  = 0x147,
+    OP_UNUSED_48FF                  = 0x148,
+    OP_UNUSED_49FF                  = 0x149,
+    OP_UNUSED_4AFF                  = 0x14a,
+    OP_UNUSED_4BFF                  = 0x14b,
+    OP_UNUSED_4CFF                  = 0x14c,
+    OP_UNUSED_4DFF                  = 0x14d,
+    OP_UNUSED_4EFF                  = 0x14e,
+    OP_UNUSED_4FFF                  = 0x14f,
+    OP_UNUSED_50FF                  = 0x150,
+    OP_UNUSED_51FF                  = 0x151,
+    OP_UNUSED_52FF                  = 0x152,
+    OP_UNUSED_53FF                  = 0x153,
+    OP_UNUSED_54FF                  = 0x154,
+    OP_UNUSED_55FF                  = 0x155,
+    OP_UNUSED_56FF                  = 0x156,
+    OP_UNUSED_57FF                  = 0x157,
+    OP_UNUSED_58FF                  = 0x158,
+    OP_UNUSED_59FF                  = 0x159,
+    OP_UNUSED_5AFF                  = 0x15a,
+    OP_UNUSED_5BFF                  = 0x15b,
+    OP_UNUSED_5CFF                  = 0x15c,
+    OP_UNUSED_5DFF                  = 0x15d,
+    OP_UNUSED_5EFF                  = 0x15e,
+    OP_UNUSED_5FFF                  = 0x15f,
+    OP_UNUSED_60FF                  = 0x160,
+    OP_UNUSED_61FF                  = 0x161,
+    OP_UNUSED_62FF                  = 0x162,
+    OP_UNUSED_63FF                  = 0x163,
+    OP_UNUSED_64FF                  = 0x164,
+    OP_UNUSED_65FF                  = 0x165,
+    OP_UNUSED_66FF                  = 0x166,
+    OP_UNUSED_67FF                  = 0x167,
+    OP_UNUSED_68FF                  = 0x168,
+    OP_UNUSED_69FF                  = 0x169,
+    OP_UNUSED_6AFF                  = 0x16a,
+    OP_UNUSED_6BFF                  = 0x16b,
+    OP_UNUSED_6CFF                  = 0x16c,
+    OP_UNUSED_6DFF                  = 0x16d,
+    OP_UNUSED_6EFF                  = 0x16e,
+    OP_UNUSED_6FFF                  = 0x16f,
+    OP_UNUSED_70FF                  = 0x170,
+    OP_UNUSED_71FF                  = 0x171,
+    OP_UNUSED_72FF                  = 0x172,
+    OP_UNUSED_73FF                  = 0x173,
+    OP_UNUSED_74FF                  = 0x174,
+    OP_UNUSED_75FF                  = 0x175,
+    OP_UNUSED_76FF                  = 0x176,
+    OP_UNUSED_77FF                  = 0x177,
+    OP_UNUSED_78FF                  = 0x178,
+    OP_UNUSED_79FF                  = 0x179,
+    OP_UNUSED_7AFF                  = 0x17a,
+    OP_UNUSED_7BFF                  = 0x17b,
+    OP_UNUSED_7CFF                  = 0x17c,
+    OP_UNUSED_7DFF                  = 0x17d,
+    OP_UNUSED_7EFF                  = 0x17e,
+    OP_UNUSED_7FFF                  = 0x17f,
+    OP_UNUSED_80FF                  = 0x180,
+    OP_UNUSED_81FF                  = 0x181,
+    OP_UNUSED_82FF                  = 0x182,
+    OP_UNUSED_83FF                  = 0x183,
+    OP_UNUSED_84FF                  = 0x184,
+    OP_UNUSED_85FF                  = 0x185,
+    OP_UNUSED_86FF                  = 0x186,
+    OP_UNUSED_87FF                  = 0x187,
+    OP_UNUSED_88FF                  = 0x188,
+    OP_UNUSED_89FF                  = 0x189,
+    OP_UNUSED_8AFF                  = 0x18a,
+    OP_UNUSED_8BFF                  = 0x18b,
+    OP_UNUSED_8CFF                  = 0x18c,
+    OP_UNUSED_8DFF                  = 0x18d,
+    OP_UNUSED_8EFF                  = 0x18e,
+    OP_UNUSED_8FFF                  = 0x18f,
+    OP_UNUSED_90FF                  = 0x190,
+    OP_UNUSED_91FF                  = 0x191,
+    OP_UNUSED_92FF                  = 0x192,
+    OP_UNUSED_93FF                  = 0x193,
+    OP_UNUSED_94FF                  = 0x194,
+    OP_UNUSED_95FF                  = 0x195,
+    OP_UNUSED_96FF                  = 0x196,
+    OP_UNUSED_97FF                  = 0x197,
+    OP_UNUSED_98FF                  = 0x198,
+    OP_UNUSED_99FF                  = 0x199,
+    OP_UNUSED_9AFF                  = 0x19a,
+    OP_UNUSED_9BFF                  = 0x19b,
+    OP_UNUSED_9CFF                  = 0x19c,
+    OP_UNUSED_9DFF                  = 0x19d,
+    OP_UNUSED_9EFF                  = 0x19e,
+    OP_UNUSED_9FFF                  = 0x19f,
+    OP_UNUSED_A0FF                  = 0x1a0,
+    OP_UNUSED_A1FF                  = 0x1a1,
+    OP_UNUSED_A2FF                  = 0x1a2,
+    OP_UNUSED_A3FF                  = 0x1a3,
+    OP_UNUSED_A4FF                  = 0x1a4,
+    OP_UNUSED_A5FF                  = 0x1a5,
+    OP_UNUSED_A6FF                  = 0x1a6,
+    OP_UNUSED_A7FF                  = 0x1a7,
+    OP_UNUSED_A8FF                  = 0x1a8,
+    OP_UNUSED_A9FF                  = 0x1a9,
+    OP_UNUSED_AAFF                  = 0x1aa,
+    OP_UNUSED_ABFF                  = 0x1ab,
+    OP_UNUSED_ACFF                  = 0x1ac,
+    OP_UNUSED_ADFF                  = 0x1ad,
+    OP_UNUSED_AEFF                  = 0x1ae,
+    OP_UNUSED_AFFF                  = 0x1af,
+    OP_UNUSED_B0FF                  = 0x1b0,
+    OP_UNUSED_B1FF                  = 0x1b1,
+    OP_UNUSED_B2FF                  = 0x1b2,
+    OP_UNUSED_B3FF                  = 0x1b3,
+    OP_UNUSED_B4FF                  = 0x1b4,
+    OP_UNUSED_B5FF                  = 0x1b5,
+    OP_UNUSED_B6FF                  = 0x1b6,
+    OP_UNUSED_B7FF                  = 0x1b7,
+    OP_UNUSED_B8FF                  = 0x1b8,
+    OP_UNUSED_B9FF                  = 0x1b9,
+    OP_UNUSED_BAFF                  = 0x1ba,
+    OP_UNUSED_BBFF                  = 0x1bb,
+    OP_UNUSED_BCFF                  = 0x1bc,
+    OP_UNUSED_BDFF                  = 0x1bd,
+    OP_UNUSED_BEFF                  = 0x1be,
+    OP_UNUSED_BFFF                  = 0x1bf,
+    OP_UNUSED_C0FF                  = 0x1c0,
+    OP_UNUSED_C1FF                  = 0x1c1,
+    OP_UNUSED_C2FF                  = 0x1c2,
+    OP_UNUSED_C3FF                  = 0x1c3,
+    OP_UNUSED_C4FF                  = 0x1c4,
+    OP_UNUSED_C5FF                  = 0x1c5,
+    OP_UNUSED_C6FF                  = 0x1c6,
+    OP_UNUSED_C7FF                  = 0x1c7,
+    OP_UNUSED_C8FF                  = 0x1c8,
+    OP_UNUSED_C9FF                  = 0x1c9,
+    OP_UNUSED_CAFF                  = 0x1ca,
+    OP_UNUSED_CBFF                  = 0x1cb,
+    OP_UNUSED_CCFF                  = 0x1cc,
+    OP_UNUSED_CDFF                  = 0x1cd,
+    OP_UNUSED_CEFF                  = 0x1ce,
+    OP_UNUSED_CFFF                  = 0x1cf,
+    OP_UNUSED_D0FF                  = 0x1d0,
+    OP_UNUSED_D1FF                  = 0x1d1,
+    OP_UNUSED_D2FF                  = 0x1d2,
+    OP_UNUSED_D3FF                  = 0x1d3,
+    OP_UNUSED_D4FF                  = 0x1d4,
+    OP_UNUSED_D5FF                  = 0x1d5,
+    OP_UNUSED_D6FF                  = 0x1d6,
+    OP_UNUSED_D7FF                  = 0x1d7,
+    OP_UNUSED_D8FF                  = 0x1d8,
+    OP_UNUSED_D9FF                  = 0x1d9,
+    OP_UNUSED_DAFF                  = 0x1da,
+    OP_UNUSED_DBFF                  = 0x1db,
+    OP_UNUSED_DCFF                  = 0x1dc,
+    OP_UNUSED_DDFF                  = 0x1dd,
+    OP_UNUSED_DEFF                  = 0x1de,
+    OP_UNUSED_DFFF                  = 0x1df,
+    OP_UNUSED_E0FF                  = 0x1e0,
+    OP_UNUSED_E1FF                  = 0x1e1,
+    OP_UNUSED_E2FF                  = 0x1e2,
+    OP_UNUSED_E3FF                  = 0x1e3,
+    OP_UNUSED_E4FF                  = 0x1e4,
+    OP_UNUSED_E5FF                  = 0x1e5,
+    OP_UNUSED_E6FF                  = 0x1e6,
+    OP_UNUSED_E7FF                  = 0x1e7,
+    OP_UNUSED_E8FF                  = 0x1e8,
+    OP_UNUSED_E9FF                  = 0x1e9,
+    OP_UNUSED_EAFF                  = 0x1ea,
+    OP_UNUSED_EBFF                  = 0x1eb,
+    OP_UNUSED_ECFF                  = 0x1ec,
+    OP_UNUSED_EDFF                  = 0x1ed,
+    OP_UNUSED_EEFF                  = 0x1ee,
+    OP_UNUSED_EFFF                  = 0x1ef,
+    OP_UNUSED_F0FF                  = 0x1f0,
+    OP_UNUSED_F1FF                  = 0x1f1,
+    OP_INVOKE_OBJECT_INIT_JUMBO     = 0x1f2,
+    OP_IGET_VOLATILE_JUMBO          = 0x1f3,
+    OP_IGET_WIDE_VOLATILE_JUMBO     = 0x1f4,
+    OP_IGET_OBJECT_VOLATILE_JUMBO   = 0x1f5,
+    OP_IPUT_VOLATILE_JUMBO          = 0x1f6,
+    OP_IPUT_WIDE_VOLATILE_JUMBO     = 0x1f7,
+    OP_IPUT_OBJECT_VOLATILE_JUMBO   = 0x1f8,
+    OP_SGET_VOLATILE_JUMBO          = 0x1f9,
+    OP_SGET_WIDE_VOLATILE_JUMBO     = 0x1fa,
+    OP_SGET_OBJECT_VOLATILE_JUMBO   = 0x1fb,
+    OP_SPUT_VOLATILE_JUMBO          = 0x1fc,
+    OP_SPUT_WIDE_VOLATILE_JUMBO     = 0x1fd,
+    OP_SPUT_OBJECT_VOLATILE_JUMBO   = 0x1fe,
+    OP_THROW_VERIFICATION_ERROR_JUMBO = 0x1ff,
+    // END(libdex-opcode-enum)
+};
+
+/*
+ * Macro used to generate a computed goto table for use in implementing
+ * an interpreter in C.
+ */
+#define DEFINE_GOTO_TABLE(_name) \
+    static const void* _name[kNumPackedOpcodes] = {                      \
+        /* BEGIN(libdex-goto-table); GENERATED AUTOMATICALLY BY opcode-gen */ \
+        H(OP_NOP),                                                            \
+        H(OP_MOVE),                                                           \
+        H(OP_MOVE_FROM16),                                                    \
+        H(OP_MOVE_16),                                                        \
+        H(OP_MOVE_WIDE),                                                      \
+        H(OP_MOVE_WIDE_FROM16),                                               \
+        H(OP_MOVE_WIDE_16),                                                   \
+        H(OP_MOVE_OBJECT),                                                    \
+        H(OP_MOVE_OBJECT_FROM16),                                             \
+        H(OP_MOVE_OBJECT_16),                                                 \
+        H(OP_MOVE_RESULT),                                                    \
+        H(OP_MOVE_RESULT_WIDE),                                               \
+        H(OP_MOVE_RESULT_OBJECT),                                             \
+        H(OP_MOVE_EXCEPTION),                                                 \
+        H(OP_RETURN_VOID),                                                    \
+        H(OP_RETURN),                                                         \
+        H(OP_RETURN_WIDE),                                                    \
+        H(OP_RETURN_OBJECT),                                                  \
+        H(OP_CONST_4),                                                        \
+        H(OP_CONST_16),                                                       \
+        H(OP_CONST),                                                          \
+        H(OP_CONST_HIGH16),                                                   \
+        H(OP_CONST_WIDE_16),                                                  \
+        H(OP_CONST_WIDE_32),                                                  \
+        H(OP_CONST_WIDE),                                                     \
+        H(OP_CONST_WIDE_HIGH16),                                              \
+        H(OP_CONST_STRING),                                                   \
+        H(OP_CONST_STRING_JUMBO),                                             \
+        H(OP_CONST_CLASS),                                                    \
+        H(OP_MONITOR_ENTER),                                                  \
+        H(OP_MONITOR_EXIT),                                                   \
+        H(OP_CHECK_CAST),                                                     \
+        H(OP_INSTANCE_OF),                                                    \
+        H(OP_ARRAY_LENGTH),                                                   \
+        H(OP_NEW_INSTANCE),                                                   \
+        H(OP_NEW_ARRAY),                                                      \
+        H(OP_FILLED_NEW_ARRAY),                                               \
+        H(OP_FILLED_NEW_ARRAY_RANGE),                                         \
+        H(OP_FILL_ARRAY_DATA),                                                \
+        H(OP_THROW),                                                          \
+        H(OP_GOTO),                                                           \
+        H(OP_GOTO_16),                                                        \
+        H(OP_GOTO_32),                                                        \
+        H(OP_PACKED_SWITCH),                                                  \
+        H(OP_SPARSE_SWITCH),                                                  \
+        H(OP_CMPL_FLOAT),                                                     \
+        H(OP_CMPG_FLOAT),                                                     \
+        H(OP_CMPL_DOUBLE),                                                    \
+        H(OP_CMPG_DOUBLE),                                                    \
+        H(OP_CMP_LONG),                                                       \
+        H(OP_IF_EQ),                                                          \
+        H(OP_IF_NE),                                                          \
+        H(OP_IF_LT),                                                          \
+        H(OP_IF_GE),                                                          \
+        H(OP_IF_GT),                                                          \
+        H(OP_IF_LE),                                                          \
+        H(OP_IF_EQZ),                                                         \
+        H(OP_IF_NEZ),                                                         \
+        H(OP_IF_LTZ),                                                         \
+        H(OP_IF_GEZ),                                                         \
+        H(OP_IF_GTZ),                                                         \
+        H(OP_IF_LEZ),                                                         \
+        H(OP_UNUSED_3E),                                                      \
+        H(OP_UNUSED_3F),                                                      \
+        H(OP_UNUSED_40),                                                      \
+        H(OP_UNUSED_41),                                                      \
+        H(OP_UNUSED_42),                                                      \
+        H(OP_UNUSED_43),                                                      \
+        H(OP_AGET),                                                           \
+        H(OP_AGET_WIDE),                                                      \
+        H(OP_AGET_OBJECT),                                                    \
+        H(OP_AGET_BOOLEAN),                                                   \
+        H(OP_AGET_BYTE),                                                      \
+        H(OP_AGET_CHAR),                                                      \
+        H(OP_AGET_SHORT),                                                     \
+        H(OP_APUT),                                                           \
+        H(OP_APUT_WIDE),                                                      \
+        H(OP_APUT_OBJECT),                                                    \
+        H(OP_APUT_BOOLEAN),                                                   \
+        H(OP_APUT_BYTE),                                                      \
+        H(OP_APUT_CHAR),                                                      \
+        H(OP_APUT_SHORT),                                                     \
+        H(OP_IGET),                                                           \
+        H(OP_IGET_WIDE),                                                      \
+        H(OP_IGET_OBJECT),                                                    \
+        H(OP_IGET_BOOLEAN),                                                   \
+        H(OP_IGET_BYTE),                                                      \
+        H(OP_IGET_CHAR),                                                      \
+        H(OP_IGET_SHORT),                                                     \
+        H(OP_IPUT),                                                           \
+        H(OP_IPUT_WIDE),                                                      \
+        H(OP_IPUT_OBJECT),                                                    \
+        H(OP_IPUT_BOOLEAN),                                                   \
+        H(OP_IPUT_BYTE),                                                      \
+        H(OP_IPUT_CHAR),                                                      \
+        H(OP_IPUT_SHORT),                                                     \
+        H(OP_SGET),                                                           \
+        H(OP_SGET_WIDE),                                                      \
+        H(OP_SGET_OBJECT),                                                    \
+        H(OP_SGET_BOOLEAN),                                                   \
+        H(OP_SGET_BYTE),                                                      \
+        H(OP_SGET_CHAR),                                                      \
+        H(OP_SGET_SHORT),                                                     \
+        H(OP_SPUT),                                                           \
+        H(OP_SPUT_WIDE),                                                      \
+        H(OP_SPUT_OBJECT),                                                    \
+        H(OP_SPUT_BOOLEAN),                                                   \
+        H(OP_SPUT_BYTE),                                                      \
+        H(OP_SPUT_CHAR),                                                      \
+        H(OP_SPUT_SHORT),                                                     \
+        H(OP_INVOKE_VIRTUAL),                                                 \
+        H(OP_INVOKE_SUPER),                                                   \
+        H(OP_INVOKE_DIRECT),                                                  \
+        H(OP_INVOKE_STATIC),                                                  \
+        H(OP_INVOKE_INTERFACE),                                               \
+        H(OP_UNUSED_73),                                                      \
+        H(OP_INVOKE_VIRTUAL_RANGE),                                           \
+        H(OP_INVOKE_SUPER_RANGE),                                             \
+        H(OP_INVOKE_DIRECT_RANGE),                                            \
+        H(OP_INVOKE_STATIC_RANGE),                                            \
+        H(OP_INVOKE_INTERFACE_RANGE),                                         \
+        H(OP_UNUSED_79),                                                      \
+        H(OP_UNUSED_7A),                                                      \
+        H(OP_NEG_INT),                                                        \
+        H(OP_NOT_INT),                                                        \
+        H(OP_NEG_LONG),                                                       \
+        H(OP_NOT_LONG),                                                       \
+        H(OP_NEG_FLOAT),                                                      \
+        H(OP_NEG_DOUBLE),                                                     \
+        H(OP_INT_TO_LONG),                                                    \
+        H(OP_INT_TO_FLOAT),                                                   \
+        H(OP_INT_TO_DOUBLE),                                                  \
+        H(OP_LONG_TO_INT),                                                    \
+        H(OP_LONG_TO_FLOAT),                                                  \
+        H(OP_LONG_TO_DOUBLE),                                                 \
+        H(OP_FLOAT_TO_INT),                                                   \
+        H(OP_FLOAT_TO_LONG),                                                  \
+        H(OP_FLOAT_TO_DOUBLE),                                                \
+        H(OP_DOUBLE_TO_INT),                                                  \
+        H(OP_DOUBLE_TO_LONG),                                                 \
+        H(OP_DOUBLE_TO_FLOAT),                                                \
+        H(OP_INT_TO_BYTE),                                                    \
+        H(OP_INT_TO_CHAR),                                                    \
+        H(OP_INT_TO_SHORT),                                                   \
+        H(OP_ADD_INT),                                                        \
+        H(OP_SUB_INT),                                                        \
+        H(OP_MUL_INT),                                                        \
+        H(OP_DIV_INT),                                                        \
+        H(OP_REM_INT),                                                        \
+        H(OP_AND_INT),                                                        \
+        H(OP_OR_INT),                                                         \
+        H(OP_XOR_INT),                                                        \
+        H(OP_SHL_INT),                                                        \
+        H(OP_SHR_INT),                                                        \
+        H(OP_USHR_INT),                                                       \
+        H(OP_ADD_LONG),                                                       \
+        H(OP_SUB_LONG),                                                       \
+        H(OP_MUL_LONG),                                                       \
+        H(OP_DIV_LONG),                                                       \
+        H(OP_REM_LONG),                                                       \
+        H(OP_AND_LONG),                                                       \
+        H(OP_OR_LONG),                                                        \
+        H(OP_XOR_LONG),                                                       \
+        H(OP_SHL_LONG),                                                       \
+        H(OP_SHR_LONG),                                                       \
+        H(OP_USHR_LONG),                                                      \
+        H(OP_ADD_FLOAT),                                                      \
+        H(OP_SUB_FLOAT),                                                      \
+        H(OP_MUL_FLOAT),                                                      \
+        H(OP_DIV_FLOAT),                                                      \
+        H(OP_REM_FLOAT),                                                      \
+        H(OP_ADD_DOUBLE),                                                     \
+        H(OP_SUB_DOUBLE),                                                     \
+        H(OP_MUL_DOUBLE),                                                     \
+        H(OP_DIV_DOUBLE),                                                     \
+        H(OP_REM_DOUBLE),                                                     \
+        H(OP_ADD_INT_2ADDR),                                                  \
+        H(OP_SUB_INT_2ADDR),                                                  \
+        H(OP_MUL_INT_2ADDR),                                                  \
+        H(OP_DIV_INT_2ADDR),                                                  \
+        H(OP_REM_INT_2ADDR),                                                  \
+        H(OP_AND_INT_2ADDR),                                                  \
+        H(OP_OR_INT_2ADDR),                                                   \
+        H(OP_XOR_INT_2ADDR),                                                  \
+        H(OP_SHL_INT_2ADDR),                                                  \
+        H(OP_SHR_INT_2ADDR),                                                  \
+        H(OP_USHR_INT_2ADDR),                                                 \
+        H(OP_ADD_LONG_2ADDR),                                                 \
+        H(OP_SUB_LONG_2ADDR),                                                 \
+        H(OP_MUL_LONG_2ADDR),                                                 \
+        H(OP_DIV_LONG_2ADDR),                                                 \
+        H(OP_REM_LONG_2ADDR),                                                 \
+        H(OP_AND_LONG_2ADDR),                                                 \
+        H(OP_OR_LONG_2ADDR),                                                  \
+        H(OP_XOR_LONG_2ADDR),                                                 \
+        H(OP_SHL_LONG_2ADDR),                                                 \
+        H(OP_SHR_LONG_2ADDR),                                                 \
+        H(OP_USHR_LONG_2ADDR),                                                \
+        H(OP_ADD_FLOAT_2ADDR),                                                \
+        H(OP_SUB_FLOAT_2ADDR),                                                \
+        H(OP_MUL_FLOAT_2ADDR),                                                \
+        H(OP_DIV_FLOAT_2ADDR),                                                \
+        H(OP_REM_FLOAT_2ADDR),                                                \
+        H(OP_ADD_DOUBLE_2ADDR),                                               \
+        H(OP_SUB_DOUBLE_2ADDR),                                               \
+        H(OP_MUL_DOUBLE_2ADDR),                                               \
+        H(OP_DIV_DOUBLE_2ADDR),                                               \
+        H(OP_REM_DOUBLE_2ADDR),                                               \
+        H(OP_ADD_INT_LIT16),                                                  \
+        H(OP_RSUB_INT),                                                       \
+        H(OP_MUL_INT_LIT16),                                                  \
+        H(OP_DIV_INT_LIT16),                                                  \
+        H(OP_REM_INT_LIT16),                                                  \
+        H(OP_AND_INT_LIT16),                                                  \
+        H(OP_OR_INT_LIT16),                                                   \
+        H(OP_XOR_INT_LIT16),                                                  \
+        H(OP_ADD_INT_LIT8),                                                   \
+        H(OP_RSUB_INT_LIT8),                                                  \
+        H(OP_MUL_INT_LIT8),                                                   \
+        H(OP_DIV_INT_LIT8),                                                   \
+        H(OP_REM_INT_LIT8),                                                   \
+        H(OP_AND_INT_LIT8),                                                   \
+        H(OP_OR_INT_LIT8),                                                    \
+        H(OP_XOR_INT_LIT8),                                                   \
+        H(OP_SHL_INT_LIT8),                                                   \
+        H(OP_SHR_INT_LIT8),                                                   \
+        H(OP_USHR_INT_LIT8),                                                  \
+        H(OP_IGET_VOLATILE),                                                  \
+        H(OP_IPUT_VOLATILE),                                                  \
+        H(OP_SGET_VOLATILE),                                                  \
+        H(OP_SPUT_VOLATILE),                                                  \
+        H(OP_IGET_OBJECT_VOLATILE),                                           \
+        H(OP_IGET_WIDE_VOLATILE),                                             \
+        H(OP_IPUT_WIDE_VOLATILE),                                             \
+        H(OP_SGET_WIDE_VOLATILE),                                             \
+        H(OP_SPUT_WIDE_VOLATILE),                                             \
+        H(OP_BREAKPOINT),                                                     \
+        H(OP_THROW_VERIFICATION_ERROR),                                       \
+        H(OP_EXECUTE_INLINE),                                                 \
+        H(OP_EXECUTE_INLINE_RANGE),                                           \
+        H(OP_INVOKE_OBJECT_INIT_RANGE),                                       \
+        H(OP_RETURN_VOID_BARRIER),                                            \
+        H(OP_IGET_QUICK),                                                     \
+        H(OP_IGET_WIDE_QUICK),                                                \
+        H(OP_IGET_OBJECT_QUICK),                                              \
+        H(OP_IPUT_QUICK),                                                     \
+        H(OP_IPUT_WIDE_QUICK),                                                \
+        H(OP_IPUT_OBJECT_QUICK),                                              \
+        H(OP_INVOKE_VIRTUAL_QUICK),                                           \
+        H(OP_INVOKE_VIRTUAL_QUICK_RANGE),                                     \
+        H(OP_INVOKE_SUPER_QUICK),                                             \
+        H(OP_INVOKE_SUPER_QUICK_RANGE),                                       \
+        H(OP_IPUT_OBJECT_VOLATILE),                                           \
+        H(OP_SGET_OBJECT_VOLATILE),                                           \
+        H(OP_SPUT_OBJECT_VOLATILE),                                           \
+        H(OP_DISPATCH_FF),                                                    \
+        H(OP_CONST_CLASS_JUMBO),                                              \
+        H(OP_CHECK_CAST_JUMBO),                                               \
+        H(OP_INSTANCE_OF_JUMBO),                                              \
+        H(OP_NEW_INSTANCE_JUMBO),                                             \
+        H(OP_NEW_ARRAY_JUMBO),                                                \
+        H(OP_FILLED_NEW_ARRAY_JUMBO),                                         \
+        H(OP_IGET_JUMBO),                                                     \
+        H(OP_IGET_WIDE_JUMBO),                                                \
+        H(OP_IGET_OBJECT_JUMBO),                                              \
+        H(OP_IGET_BOOLEAN_JUMBO),                                             \
+        H(OP_IGET_BYTE_JUMBO),                                                \
+        H(OP_IGET_CHAR_JUMBO),                                                \
+        H(OP_IGET_SHORT_JUMBO),                                               \
+        H(OP_IPUT_JUMBO),                                                     \
+        H(OP_IPUT_WIDE_JUMBO),                                                \
+        H(OP_IPUT_OBJECT_JUMBO),                                              \
+        H(OP_IPUT_BOOLEAN_JUMBO),                                             \
+        H(OP_IPUT_BYTE_JUMBO),                                                \
+        H(OP_IPUT_CHAR_JUMBO),                                                \
+        H(OP_IPUT_SHORT_JUMBO),                                               \
+        H(OP_SGET_JUMBO),                                                     \
+        H(OP_SGET_WIDE_JUMBO),                                                \
+        H(OP_SGET_OBJECT_JUMBO),                                              \
+        H(OP_SGET_BOOLEAN_JUMBO),                                             \
+        H(OP_SGET_BYTE_JUMBO),                                                \
+        H(OP_SGET_CHAR_JUMBO),                                                \
+        H(OP_SGET_SHORT_JUMBO),                                               \
+        H(OP_SPUT_JUMBO),                                                     \
+        H(OP_SPUT_WIDE_JUMBO),                                                \
+        H(OP_SPUT_OBJECT_JUMBO),                                              \
+        H(OP_SPUT_BOOLEAN_JUMBO),                                             \
+        H(OP_SPUT_BYTE_JUMBO),                                                \
+        H(OP_SPUT_CHAR_JUMBO),                                                \
+        H(OP_SPUT_SHORT_JUMBO),                                               \
+        H(OP_INVOKE_VIRTUAL_JUMBO),                                           \
+        H(OP_INVOKE_SUPER_JUMBO),                                             \
+        H(OP_INVOKE_DIRECT_JUMBO),                                            \
+        H(OP_INVOKE_STATIC_JUMBO),                                            \
+        H(OP_INVOKE_INTERFACE_JUMBO),                                         \
+        H(OP_UNUSED_27FF),                                                    \
+        H(OP_UNUSED_28FF),                                                    \
+        H(OP_UNUSED_29FF),                                                    \
+        H(OP_UNUSED_2AFF),                                                    \
+        H(OP_UNUSED_2BFF),                                                    \
+        H(OP_UNUSED_2CFF),                                                    \
+        H(OP_UNUSED_2DFF),                                                    \
+        H(OP_UNUSED_2EFF),                                                    \
+        H(OP_UNUSED_2FFF),                                                    \
+        H(OP_UNUSED_30FF),                                                    \
+        H(OP_UNUSED_31FF),                                                    \
+        H(OP_UNUSED_32FF),                                                    \
+        H(OP_UNUSED_33FF),                                                    \
+        H(OP_UNUSED_34FF),                                                    \
+        H(OP_UNUSED_35FF),                                                    \
+        H(OP_UNUSED_36FF),                                                    \
+        H(OP_UNUSED_37FF),                                                    \
+        H(OP_UNUSED_38FF),                                                    \
+        H(OP_UNUSED_39FF),                                                    \
+        H(OP_UNUSED_3AFF),                                                    \
+        H(OP_UNUSED_3BFF),                                                    \
+        H(OP_UNUSED_3CFF),                                                    \
+        H(OP_UNUSED_3DFF),                                                    \
+        H(OP_UNUSED_3EFF),                                                    \
+        H(OP_UNUSED_3FFF),                                                    \
+        H(OP_UNUSED_40FF),                                                    \
+        H(OP_UNUSED_41FF),                                                    \
+        H(OP_UNUSED_42FF),                                                    \
+        H(OP_UNUSED_43FF),                                                    \
+        H(OP_UNUSED_44FF),                                                    \
+        H(OP_UNUSED_45FF),                                                    \
+        H(OP_UNUSED_46FF),                                                    \
+        H(OP_UNUSED_47FF),                                                    \
+        H(OP_UNUSED_48FF),                                                    \
+        H(OP_UNUSED_49FF),                                                    \
+        H(OP_UNUSED_4AFF),                                                    \
+        H(OP_UNUSED_4BFF),                                                    \
+        H(OP_UNUSED_4CFF),                                                    \
+        H(OP_UNUSED_4DFF),                                                    \
+        H(OP_UNUSED_4EFF),                                                    \
+        H(OP_UNUSED_4FFF),                                                    \
+        H(OP_UNUSED_50FF),                                                    \
+        H(OP_UNUSED_51FF),                                                    \
+        H(OP_UNUSED_52FF),                                                    \
+        H(OP_UNUSED_53FF),                                                    \
+        H(OP_UNUSED_54FF),                                                    \
+        H(OP_UNUSED_55FF),                                                    \
+        H(OP_UNUSED_56FF),                                                    \
+        H(OP_UNUSED_57FF),                                                    \
+        H(OP_UNUSED_58FF),                                                    \
+        H(OP_UNUSED_59FF),                                                    \
+        H(OP_UNUSED_5AFF),                                                    \
+        H(OP_UNUSED_5BFF),                                                    \
+        H(OP_UNUSED_5CFF),                                                    \
+        H(OP_UNUSED_5DFF),                                                    \
+        H(OP_UNUSED_5EFF),                                                    \
+        H(OP_UNUSED_5FFF),                                                    \
+        H(OP_UNUSED_60FF),                                                    \
+        H(OP_UNUSED_61FF),                                                    \
+        H(OP_UNUSED_62FF),                                                    \
+        H(OP_UNUSED_63FF),                                                    \
+        H(OP_UNUSED_64FF),                                                    \
+        H(OP_UNUSED_65FF),                                                    \
+        H(OP_UNUSED_66FF),                                                    \
+        H(OP_UNUSED_67FF),                                                    \
+        H(OP_UNUSED_68FF),                                                    \
+        H(OP_UNUSED_69FF),                                                    \
+        H(OP_UNUSED_6AFF),                                                    \
+        H(OP_UNUSED_6BFF),                                                    \
+        H(OP_UNUSED_6CFF),                                                    \
+        H(OP_UNUSED_6DFF),                                                    \
+        H(OP_UNUSED_6EFF),                                                    \
+        H(OP_UNUSED_6FFF),                                                    \
+        H(OP_UNUSED_70FF),                                                    \
+        H(OP_UNUSED_71FF),                                                    \
+        H(OP_UNUSED_72FF),                                                    \
+        H(OP_UNUSED_73FF),                                                    \
+        H(OP_UNUSED_74FF),                                                    \
+        H(OP_UNUSED_75FF),                                                    \
+        H(OP_UNUSED_76FF),                                                    \
+        H(OP_UNUSED_77FF),                                                    \
+        H(OP_UNUSED_78FF),                                                    \
+        H(OP_UNUSED_79FF),                                                    \
+        H(OP_UNUSED_7AFF),                                                    \
+        H(OP_UNUSED_7BFF),                                                    \
+        H(OP_UNUSED_7CFF),                                                    \
+        H(OP_UNUSED_7DFF),                                                    \
+        H(OP_UNUSED_7EFF),                                                    \
+        H(OP_UNUSED_7FFF),                                                    \
+        H(OP_UNUSED_80FF),                                                    \
+        H(OP_UNUSED_81FF),                                                    \
+        H(OP_UNUSED_82FF),                                                    \
+        H(OP_UNUSED_83FF),                                                    \
+        H(OP_UNUSED_84FF),                                                    \
+        H(OP_UNUSED_85FF),                                                    \
+        H(OP_UNUSED_86FF),                                                    \
+        H(OP_UNUSED_87FF),                                                    \
+        H(OP_UNUSED_88FF),                                                    \
+        H(OP_UNUSED_89FF),                                                    \
+        H(OP_UNUSED_8AFF),                                                    \
+        H(OP_UNUSED_8BFF),                                                    \
+        H(OP_UNUSED_8CFF),                                                    \
+        H(OP_UNUSED_8DFF),                                                    \
+        H(OP_UNUSED_8EFF),                                                    \
+        H(OP_UNUSED_8FFF),                                                    \
+        H(OP_UNUSED_90FF),                                                    \
+        H(OP_UNUSED_91FF),                                                    \
+        H(OP_UNUSED_92FF),                                                    \
+        H(OP_UNUSED_93FF),                                                    \
+        H(OP_UNUSED_94FF),                                                    \
+        H(OP_UNUSED_95FF),                                                    \
+        H(OP_UNUSED_96FF),                                                    \
+        H(OP_UNUSED_97FF),                                                    \
+        H(OP_UNUSED_98FF),                                                    \
+        H(OP_UNUSED_99FF),                                                    \
+        H(OP_UNUSED_9AFF),                                                    \
+        H(OP_UNUSED_9BFF),                                                    \
+        H(OP_UNUSED_9CFF),                                                    \
+        H(OP_UNUSED_9DFF),                                                    \
+        H(OP_UNUSED_9EFF),                                                    \
+        H(OP_UNUSED_9FFF),                                                    \
+        H(OP_UNUSED_A0FF),                                                    \
+        H(OP_UNUSED_A1FF),                                                    \
+        H(OP_UNUSED_A2FF),                                                    \
+        H(OP_UNUSED_A3FF),                                                    \
+        H(OP_UNUSED_A4FF),                                                    \
+        H(OP_UNUSED_A5FF),                                                    \
+        H(OP_UNUSED_A6FF),                                                    \
+        H(OP_UNUSED_A7FF),                                                    \
+        H(OP_UNUSED_A8FF),                                                    \
+        H(OP_UNUSED_A9FF),                                                    \
+        H(OP_UNUSED_AAFF),                                                    \
+        H(OP_UNUSED_ABFF),                                                    \
+        H(OP_UNUSED_ACFF),                                                    \
+        H(OP_UNUSED_ADFF),                                                    \
+        H(OP_UNUSED_AEFF),                                                    \
+        H(OP_UNUSED_AFFF),                                                    \
+        H(OP_UNUSED_B0FF),                                                    \
+        H(OP_UNUSED_B1FF),                                                    \
+        H(OP_UNUSED_B2FF),                                                    \
+        H(OP_UNUSED_B3FF),                                                    \
+        H(OP_UNUSED_B4FF),                                                    \
+        H(OP_UNUSED_B5FF),                                                    \
+        H(OP_UNUSED_B6FF),                                                    \
+        H(OP_UNUSED_B7FF),                                                    \
+        H(OP_UNUSED_B8FF),                                                    \
+        H(OP_UNUSED_B9FF),                                                    \
+        H(OP_UNUSED_BAFF),                                                    \
+        H(OP_UNUSED_BBFF),                                                    \
+        H(OP_UNUSED_BCFF),                                                    \
+        H(OP_UNUSED_BDFF),                                                    \
+        H(OP_UNUSED_BEFF),                                                    \
+        H(OP_UNUSED_BFFF),                                                    \
+        H(OP_UNUSED_C0FF),                                                    \
+        H(OP_UNUSED_C1FF),                                                    \
+        H(OP_UNUSED_C2FF),                                                    \
+        H(OP_UNUSED_C3FF),                                                    \
+        H(OP_UNUSED_C4FF),                                                    \
+        H(OP_UNUSED_C5FF),                                                    \
+        H(OP_UNUSED_C6FF),                                                    \
+        H(OP_UNUSED_C7FF),                                                    \
+        H(OP_UNUSED_C8FF),                                                    \
+        H(OP_UNUSED_C9FF),                                                    \
+        H(OP_UNUSED_CAFF),                                                    \
+        H(OP_UNUSED_CBFF),                                                    \
+        H(OP_UNUSED_CCFF),                                                    \
+        H(OP_UNUSED_CDFF),                                                    \
+        H(OP_UNUSED_CEFF),                                                    \
+        H(OP_UNUSED_CFFF),                                                    \
+        H(OP_UNUSED_D0FF),                                                    \
+        H(OP_UNUSED_D1FF),                                                    \
+        H(OP_UNUSED_D2FF),                                                    \
+        H(OP_UNUSED_D3FF),                                                    \
+        H(OP_UNUSED_D4FF),                                                    \
+        H(OP_UNUSED_D5FF),                                                    \
+        H(OP_UNUSED_D6FF),                                                    \
+        H(OP_UNUSED_D7FF),                                                    \
+        H(OP_UNUSED_D8FF),                                                    \
+        H(OP_UNUSED_D9FF),                                                    \
+        H(OP_UNUSED_DAFF),                                                    \
+        H(OP_UNUSED_DBFF),                                                    \
+        H(OP_UNUSED_DCFF),                                                    \
+        H(OP_UNUSED_DDFF),                                                    \
+        H(OP_UNUSED_DEFF),                                                    \
+        H(OP_UNUSED_DFFF),                                                    \
+        H(OP_UNUSED_E0FF),                                                    \
+        H(OP_UNUSED_E1FF),                                                    \
+        H(OP_UNUSED_E2FF),                                                    \
+        H(OP_UNUSED_E3FF),                                                    \
+        H(OP_UNUSED_E4FF),                                                    \
+        H(OP_UNUSED_E5FF),                                                    \
+        H(OP_UNUSED_E6FF),                                                    \
+        H(OP_UNUSED_E7FF),                                                    \
+        H(OP_UNUSED_E8FF),                                                    \
+        H(OP_UNUSED_E9FF),                                                    \
+        H(OP_UNUSED_EAFF),                                                    \
+        H(OP_UNUSED_EBFF),                                                    \
+        H(OP_UNUSED_ECFF),                                                    \
+        H(OP_UNUSED_EDFF),                                                    \
+        H(OP_UNUSED_EEFF),                                                    \
+        H(OP_UNUSED_EFFF),                                                    \
+        H(OP_UNUSED_F0FF),                                                    \
+        H(OP_UNUSED_F1FF),                                                    \
+        H(OP_INVOKE_OBJECT_INIT_JUMBO),                                       \
+        H(OP_IGET_VOLATILE_JUMBO),                                            \
+        H(OP_IGET_WIDE_VOLATILE_JUMBO),                                       \
+        H(OP_IGET_OBJECT_VOLATILE_JUMBO),                                     \
+        H(OP_IPUT_VOLATILE_JUMBO),                                            \
+        H(OP_IPUT_WIDE_VOLATILE_JUMBO),                                       \
+        H(OP_IPUT_OBJECT_VOLATILE_JUMBO),                                     \
+        H(OP_SGET_VOLATILE_JUMBO),                                            \
+        H(OP_SGET_WIDE_VOLATILE_JUMBO),                                       \
+        H(OP_SGET_OBJECT_VOLATILE_JUMBO),                                     \
+        H(OP_SPUT_VOLATILE_JUMBO),                                            \
+        H(OP_SPUT_WIDE_VOLATILE_JUMBO),                                       \
+        H(OP_SPUT_OBJECT_VOLATILE_JUMBO),                                     \
+        H(OP_THROW_VERIFICATION_ERROR_JUMBO),                                 \
+        /* END(libdex-goto-table) */                                          \
+    };
+
+/*
+ * Return the Opcode for a given raw opcode code unit (which may
+ * include data payload). The packed index is a zero-based index which
+ * can be used to point into various opcode-related tables. The Dalvik
+ * opcode space is inherently sparse, in that the opcode unit is 16
+ * bits wide, but for most opcodes, eight of those bits are for data.
+ */
+DEX_INLINE Opcode dexOpcodeFromCodeUnit(u2 codeUnit) {
+    /*
+     * This will want to become table-driven should the opcode layout
+     * get more complicated.
+     *
+     * Note: This has to match the corresponding code in opcode-gen, so
+     * that data tables get generated in a consistent way.
+     */
+    int lowByte = codeUnit & 0xff;
+    if (lowByte != 0xff) {
+        return (Opcode) lowByte;
+    } else {
+        return (Opcode) ((codeUnit >> 8) | 0x100);
+    }
+}
+
+/*
+ * Return the name of an opcode.
+ */
+const char* dexGetOpcodeName(Opcode op);
+
+#endif  // LIBDEX_DEXOPCODES_H_
diff --git a/libdex/DexOptData.cpp b/libdex/DexOptData.cpp
new file mode 100644
index 0000000..b224d6d
--- /dev/null
+++ b/libdex/DexOptData.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions to parse and manipulate the additional data tables added
+ * to optimized .dex files.
+ */
+
+#include <zlib.h>
+
+#include "DexOptData.h"
+
+/*
+ * Check to see if a given data pointer is a valid double-word-aligned
+ * pointer into the given memory range (from start inclusive to end
+ * exclusive). Returns true if valid.
+ */
+static bool isValidPointer(const void* ptr, const void* start, const void* end)
+{
+    return (ptr >= start) && (ptr < end) && (((u4) ptr & 7) == 0);
+}
+
+/* (documented in header file) */
+u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader)
+{
+    const u1* start = (const u1*) pOptHeader + pOptHeader->depsOffset;
+    const u1* end = (const u1*) pOptHeader +
+        pOptHeader->optOffset + pOptHeader->optLength;
+
+    uLong adler = adler32(0L, Z_NULL, 0);
+
+    return (u4) adler32(adler, start, end - start);
+}
+
+/* (documented in header file) */
+bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile)
+{
+    const void* pOptStart = data + pDexFile->pOptHeader->optOffset;
+    const void* pOptEnd = data + length;
+    const u4* pOpt = (const u4*) pOptStart;
+    u4 optLength = (const u1*) pOptEnd - (const u1*) pOptStart;
+
+    /*
+     * Make sure the opt data start is in range and aligned. This may
+     * seem like a superfluous check, but (a) if the file got
+     * truncated, it might turn out that pOpt >= pOptEnd; and (b)
+     * if the opt data header got corrupted, pOpt might not be
+     * properly aligned. This test will catch both of these cases.
+     */
+    if (!isValidPointer(pOpt, pOptStart, pOptEnd)) {
+        LOGE("Bogus opt data start pointer");
+        return false;
+    }
+
+    /* Make sure that the opt data length is a whole number of words. */
+    if ((optLength & 3) != 0) {
+        LOGE("Unaligned opt data area end");
+        return false;
+    }
+
+    /*
+     * Make sure that the opt data area is large enough to have at least
+     * one chunk header.
+     */
+    if (optLength < 8) {
+        LOGE("Undersized opt data area (%u)", optLength);
+        return false;
+    }
+
+    /* Process chunks until we see the end marker. */
+    while (*pOpt != kDexChunkEnd) {
+        if (!isValidPointer(pOpt + 2, pOptStart, pOptEnd)) {
+            LOGE("Bogus opt data content pointer at offset %u",
+                    ((const u1*) pOpt) - data);
+            return false;
+        }
+
+        u4 size = *(pOpt + 1);
+        const u1* pOptData = (const u1*) (pOpt + 2);
+
+        /*
+         * The rounded size is 64-bit aligned and includes +8 for the
+         * type/size header (which was extracted immediately above).
+         */
+        u4 roundedSize = (size + 8 + 7) & ~7;
+        const u4* pNextOpt = pOpt + (roundedSize / sizeof(u4));
+
+        if (!isValidPointer(pNextOpt, pOptStart, pOptEnd)) {
+            LOGE("Opt data area problem for chunk of size %u at offset %u",
+                    size, ((const u1*) pOpt) - data);
+            return false;
+        }
+
+        switch (*pOpt) {
+        case kDexChunkClassLookup:
+            pDexFile->pClassLookup = (const DexClassLookup*) pOptData;
+            break;
+        case kDexChunkRegisterMaps:
+            LOGV("+++ found register maps, size=%u", size);
+            pDexFile->pRegisterMapPool = pOptData;
+            break;
+        default:
+            LOGI("Unknown chunk 0x%08x (%c%c%c%c), size=%d in opt data area",
+                *pOpt,
+                (char) ((*pOpt) >> 24), (char) ((*pOpt) >> 16),
+                (char) ((*pOpt) >> 8),  (char)  (*pOpt),
+                size);
+            break;
+        }
+
+        pOpt = pNextOpt;
+    }
+
+    return true;
+}
diff --git a/libdex/DexOptData.h b/libdex/DexOptData.h
new file mode 100644
index 0000000..69eda01
--- /dev/null
+++ b/libdex/DexOptData.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Functions to parse and manipulate the additional data tables added
+ * to optimized .dex files.
+ */
+
+#ifndef _LIBDEX_DEXOPTDATA
+#define _LIBDEX_DEXOPTDATA
+
+#include "libdex/DexFile.h"
+
+/*
+ * Parse the optimized data tables in the given dex file.
+ *
+ * @param data pointer to the start of the entire dex file
+ * @param length length of the entire dex file, in bytes
+ * @param pDexFile pointer to the associated dex file structure
+ */
+bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile);
+
+/*
+ * Compute the checksum of the optimized data tables pointed at by the given
+ * header.
+ */
+u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader);
+
+#endif /* def _LIBDEX_DEXOPTDATA */
diff --git a/libdex/DexProto.cpp b/libdex/DexProto.cpp
new file mode 100644
index 0000000..06c59b3
--- /dev/null
+++ b/libdex/DexProto.cpp
@@ -0,0 +1,523 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions for dealing with method prototypes
+ */
+
+#include "DexProto.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ===========================================================================
+ *      String Cache
+ * ===========================================================================
+ */
+
+/*
+ * Make sure that the given cache can hold a string of the given length,
+ * including the final '\0' byte.
+ */
+void dexStringCacheAlloc(DexStringCache* pCache, size_t length) {
+    if (pCache->allocatedSize != 0) {
+        if (pCache->allocatedSize >= length) {
+            return;
+        }
+        free((void*) pCache->value);
+    }
+
+    if (length <= sizeof(pCache->buffer)) {
+        pCache->value = pCache->buffer;
+        pCache->allocatedSize = 0;
+    } else {
+        pCache->value = (char*) malloc(length);
+        pCache->allocatedSize = length;
+    }
+}
+
+/*
+ * Initialize the given DexStringCache. Use this function before passing
+ * one into any other function.
+ */
+void dexStringCacheInit(DexStringCache* pCache) {
+    pCache->value = pCache->buffer;
+    pCache->allocatedSize = 0;
+    pCache->buffer[0] = '\0';
+}
+
+/*
+ * Release the allocated contents of the given DexStringCache, if any.
+ * Use this function after your last use of a DexStringCache.
+ */
+void dexStringCacheRelease(DexStringCache* pCache) {
+    if (pCache->allocatedSize != 0) {
+        free((void*) pCache->value);
+        pCache->value = pCache->buffer;
+        pCache->allocatedSize = 0;
+    }
+}
+
+/*
+ * If the given DexStringCache doesn't already point at the given value,
+ * make a copy of it into the cache. This always returns a writable
+ * pointer to the contents (whether or not a copy had to be made). This
+ * function is intended to be used after making a call that at least
+ * sometimes doesn't populate a DexStringCache.
+ */
+char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value) {
+    if (value != pCache->value) {
+        size_t length = strlen(value) + 1;
+        dexStringCacheAlloc(pCache, length);
+        memcpy(pCache->value, value, length);
+    }
+
+    return pCache->value;
+}
+
+/*
+ * Abandon the given DexStringCache, and return a writable copy of the
+ * given value (reusing the string cache's allocation if possible).
+ * The return value must be free()d by the caller. Use this instead of
+ * dexStringCacheRelease() if you want the buffer to survive past the
+ * scope of the DexStringCache.
+ */
+char* dexStringCacheAbandon(DexStringCache* pCache, const char* value) {
+    if ((value == pCache->value) && (pCache->allocatedSize != 0)) {
+        char* result = pCache->value;
+        pCache->allocatedSize = 0;
+        pCache->value = pCache->buffer;
+        return result;
+    } else {
+        return strdup(value);
+    }
+}
+
+
+/*
+ * ===========================================================================
+ *      Method Prototypes
+ * ===========================================================================
+ */
+
+/*
+ * Return the DexProtoId from the given DexProto. The DexProto must
+ * actually refer to a DexProtoId.
+ */
+static inline const DexProtoId* getProtoId(const DexProto* pProto) {
+    return dexGetProtoId(pProto->dexFile, pProto->protoIdx);
+}
+
+/* (documented in header file) */
+const char* dexProtoGetShorty(const DexProto* pProto) {
+    const DexProtoId* protoId = getProtoId(pProto);
+
+    return dexStringById(pProto->dexFile, protoId->shortyIdx);
+}
+
+/* (documented in header file) */
+const char* dexProtoGetMethodDescriptor(const DexProto* pProto,
+        DexStringCache* pCache) {
+    const DexFile* dexFile = pProto->dexFile;
+    const DexProtoId* protoId = getProtoId(pProto);
+    const DexTypeList* typeList = dexGetProtoParameters(dexFile, protoId);
+    size_t length = 3; // parens and terminating '\0'
+    u4 paramCount = (typeList == NULL) ? 0 : typeList->size;
+    u4 i;
+
+    for (i = 0; i < paramCount; i++) {
+        u4 idx = dexTypeListGetIdx(typeList, i);
+        length += strlen(dexStringByTypeIdx(dexFile, idx));
+    }
+
+    length += strlen(dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
+
+    dexStringCacheAlloc(pCache, length);
+
+    char *at = (char*) pCache->value;
+    *(at++) = '(';
+
+    for (i = 0; i < paramCount; i++) {
+        u4 idx = dexTypeListGetIdx(typeList, i);
+        const char* desc = dexStringByTypeIdx(dexFile, idx);
+        strcpy(at, desc);
+        at += strlen(desc);
+    }
+
+    *(at++) = ')';
+
+    strcpy(at, dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
+    return pCache->value;
+}
+
+/* (documented in header file) */
+char* dexProtoCopyMethodDescriptor(const DexProto* pProto) {
+    DexStringCache cache;
+
+    dexStringCacheInit(&cache);
+    return dexStringCacheAbandon(&cache,
+            dexProtoGetMethodDescriptor(pProto, &cache));
+}
+
+/* (documented in header file) */
+const char* dexProtoGetParameterDescriptors(const DexProto* pProto,
+        DexStringCache* pCache) {
+    DexParameterIterator iterator;
+    size_t length = 1; /* +1 for the terminating '\0' */
+
+    dexParameterIteratorInit(&iterator, pProto);
+
+    for (;;) {
+        const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
+        if (descriptor == NULL) {
+            break;
+        }
+
+        length += strlen(descriptor);
+    }
+
+    dexParameterIteratorInit(&iterator, pProto);
+
+    dexStringCacheAlloc(pCache, length);
+    char *at = (char*) pCache->value;
+
+    for (;;) {
+        const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
+        if (descriptor == NULL) {
+            break;
+        }
+
+        strcpy(at, descriptor);
+        at += strlen(descriptor);
+    }
+
+    return pCache->value;
+}
+
+/* (documented in header file) */
+const char* dexProtoGetReturnType(const DexProto* pProto) {
+    const DexProtoId* protoId = getProtoId(pProto);
+    return dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx);
+}
+
+/* (documented in header file) */
+size_t dexProtoGetParameterCount(const DexProto* pProto) {
+    const DexProtoId* protoId = getProtoId(pProto);
+    const DexTypeList* typeList =
+        dexGetProtoParameters(pProto->dexFile, protoId);
+    return (typeList == NULL) ? 0 : typeList->size;
+}
+
+/* (documented in header file) */
+int dexProtoComputeArgsSize(const DexProto* pProto) {
+    const char* shorty = dexProtoGetShorty(pProto);
+    int count = 0;
+
+    /* Skip the return type. */
+    shorty++;
+
+    for (;;) {
+        switch (*(shorty++)) {
+            case '\0': {
+                return count;
+            }
+            case 'D':
+            case 'J': {
+                count += 2;
+                break;
+            }
+            default: {
+                count++;
+                break;
+            }
+        }
+    }
+}
+
+/*
+ * Common implementation for dexProtoCompare() and dexProtoCompareParameters().
+ */
+static int protoCompare(const DexProto* pProto1, const DexProto* pProto2,
+        bool compareReturnType) {
+
+    if (pProto1 == pProto2) {
+        // Easy out.
+        return 0;
+    } else {
+        const DexFile* dexFile1 = pProto1->dexFile;
+        const DexProtoId* protoId1 = getProtoId(pProto1);
+        const DexTypeList* typeList1 =
+            dexGetProtoParameters(dexFile1, protoId1);
+        int paramCount1 = (typeList1 == NULL) ? 0 : typeList1->size;
+
+        const DexFile* dexFile2 = pProto2->dexFile;
+        const DexProtoId* protoId2 = getProtoId(pProto2);
+        const DexTypeList* typeList2 =
+            dexGetProtoParameters(dexFile2, protoId2);
+        int paramCount2 = (typeList2 == NULL) ? 0 : typeList2->size;
+
+        if (protoId1 == protoId2) {
+            // Another easy out.
+            return 0;
+        }
+
+        // Compare return types.
+
+        if (compareReturnType) {
+            int result =
+                strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx),
+                        dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx));
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        // Compare parameters.
+
+        int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1;
+        int i;
+
+        for (i = 0; i < minParam; i++) {
+            u4 idx1 = dexTypeListGetIdx(typeList1, i);
+            u4 idx2 = dexTypeListGetIdx(typeList2, i);
+            int result =
+                strcmp(dexStringByTypeIdx(dexFile1, idx1),
+                        dexStringByTypeIdx(dexFile2, idx2));
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        if (paramCount1 < paramCount2) {
+            return -1;
+        } else if (paramCount1 > paramCount2) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+}
+
+/* (documented in header file) */
+int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2) {
+    return protoCompare(pProto1, pProto2, true);
+}
+
+/* (documented in header file) */
+int dexProtoCompareParameters(const DexProto* pProto1, const DexProto* pProto2){
+    return protoCompare(pProto1, pProto2, false);
+}
+
+
+/*
+ * Helper for dexProtoCompareToDescriptor(), which gets the return type
+ * descriptor from a method descriptor string.
+ */
+static const char* methodDescriptorReturnType(const char* descriptor) {
+    const char* result = strchr(descriptor, ')');
+
+    if (result == NULL) {
+        return NULL;
+    }
+
+    // The return type is the character just past the ')'.
+    return result + 1;
+}
+
+/*
+ * Helper for dexProtoCompareToDescriptor(), which indicates the end
+ * of an embedded argument type descriptor, which is also the
+ * beginning of the next argument type descriptor. Since this is for
+ * argument types, it doesn't accept 'V' as a valid type descriptor.
+ */
+static const char* methodDescriptorNextType(const char* descriptor) {
+    // Skip any array references.
+
+    while (*descriptor == '[') {
+        descriptor++;
+    }
+
+    switch (*descriptor) {
+        case 'B': case 'C': case 'D': case 'F':
+        case 'I': case 'J': case 'S': case 'Z': {
+            return descriptor + 1;
+        }
+        case 'L': {
+            const char* result = strchr(descriptor + 1, ';');
+            if (result != NULL) {
+                // The type ends just past the ';'.
+                return result + 1;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Common implementation for dexProtoCompareToDescriptor() and
+ * dexProtoCompareToParameterDescriptors(). The descriptor argument
+ * can be either a full method descriptor (with parens and a return
+ * type) or an unadorned concatenation of types (e.g. a list of
+ * argument types).
+ */
+static int protoCompareToParameterDescriptors(const DexProto* proto,
+        const char* descriptor, bool expectParens) {
+    char expectedEndChar = expectParens ? ')' : '\0';
+    DexParameterIterator iterator;
+    dexParameterIteratorInit(&iterator, proto);
+
+    if (expectParens) {
+        // Skip the '('.
+        assert (*descriptor == '(');
+        descriptor++;
+    }
+
+    for (;;) {
+        const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (*descriptor == expectedEndChar) {
+            // It's the end of the descriptor string.
+            if (protoDesc == NULL) {
+                // It's also the end of the prototype's arguments.
+                return 0;
+            } else {
+                // The prototype still has more arguments.
+                return 1;
+            }
+        }
+
+        if (protoDesc == NULL) {
+            /*
+             * The prototype doesn't have arguments left, but the
+             * descriptor string does.
+             */
+            return -1;
+        }
+
+        // Both prototype and descriptor have arguments. Compare them.
+
+        const char* nextDesc = methodDescriptorNextType(descriptor);
+        assert(nextDesc != NULL);
+
+        for (;;) {
+            char c1 = *(protoDesc++);
+            char c2 = (descriptor < nextDesc) ? *(descriptor++) : '\0';
+
+            if (c1 < c2) {
+                // This includes the case where the proto is shorter.
+                return -1;
+            } else if (c1 > c2) {
+                // This includes the case where the desc is shorter.
+                return 1;
+            } else if (c1 == '\0') {
+                // The two types are equal in length. (c2 necessarily == '\0'.)
+                break;
+            }
+        }
+
+        /*
+         * If we made it here, the two arguments matched, and
+         * descriptor == nextDesc.
+         */
+    }
+}
+
+/* (documented in header file) */
+int dexProtoCompareToDescriptor(const DexProto* proto,
+        const char* descriptor) {
+    // First compare the return types.
+
+    const char *returnType = methodDescriptorReturnType(descriptor);
+    assert(returnType != NULL);
+
+    int result = strcmp(dexProtoGetReturnType(proto), returnType);
+
+    if (result != 0) {
+        return result;
+    }
+
+    // The return types match, so we have to check arguments.
+    return protoCompareToParameterDescriptors(proto, descriptor, true);
+}
+
+/* (documented in header file) */
+int dexProtoCompareToParameterDescriptors(const DexProto* proto,
+        const char* descriptors) {
+    return protoCompareToParameterDescriptors(proto, descriptors, false);
+}
+
+
+
+
+
+
+/*
+ * ===========================================================================
+ *      Parameter Iterators
+ * ===========================================================================
+ */
+
+/*
+ * Initialize the given DexParameterIterator to be at the start of the
+ * parameters of the given prototype.
+ */
+void dexParameterIteratorInit(DexParameterIterator* pIterator,
+        const DexProto* pProto) {
+    pIterator->proto = pProto;
+    pIterator->cursor = 0;
+
+    pIterator->parameters =
+        dexGetProtoParameters(pProto->dexFile, getProtoId(pProto));
+    pIterator->parameterCount = (pIterator->parameters == NULL) ? 0
+        : pIterator->parameters->size;
+}
+
+/*
+ * Get the type_id index for the next parameter, if any. This returns
+ * kDexNoIndex if the last parameter has already been consumed.
+ */
+u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator) {
+    int cursor = pIterator->cursor;
+    int parameterCount = pIterator->parameterCount;
+
+    if (cursor >= parameterCount) {
+        // The iteration is complete.
+        return kDexNoIndex;
+    } else {
+        u4 idx = dexTypeListGetIdx(pIterator->parameters, cursor);
+        pIterator->cursor++;
+        return idx;
+    }
+}
+
+/*
+ * Get the type descriptor for the next parameter, if any. This returns
+ * NULL if the last parameter has already been consumed.
+ */
+const char* dexParameterIteratorNextDescriptor(
+        DexParameterIterator* pIterator) {
+    u4 idx = dexParameterIteratorNextIndex(pIterator);
+
+    if (idx == kDexNoIndex) {
+        return NULL;
+    }
+
+    return dexStringByTypeIdx(pIterator->proto->dexFile, idx);
+}
diff --git a/libdex/DexProto.h b/libdex/DexProto.h
new file mode 100644
index 0000000..dccae6c
--- /dev/null
+++ b/libdex/DexProto.h
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions for dealing with method prototypes
+ */
+
+#ifndef LIBDEX_DEXPROTO_H_
+#define LIBDEX_DEXPROTO_H_
+
+#include "DexFile.h"
+
+/*
+ * Single-thread single-string cache. This structure holds a pointer to
+ * a string which is semi-automatically manipulated by some of the
+ * method prototype functions. Functions which use in this struct
+ * generally return a string that is valid until the next
+ * time the same DexStringCache is used.
+ */
+struct DexStringCache {
+    char* value;          /* the latest value */
+    size_t allocatedSize; /* size of the allocated buffer, if allocated */
+    char buffer[120];     /* buffer used to hold small-enough results */
+};
+
+/*
+ * Make sure that the given cache can hold a string of the given length,
+ * including the final '\0' byte.
+ */
+void dexStringCacheAlloc(DexStringCache* pCache, size_t length);
+
+/*
+ * Initialize the given DexStringCache. Use this function before passing
+ * one into any other function.
+ */
+void dexStringCacheInit(DexStringCache* pCache);
+
+/*
+ * Release the allocated contents of the given DexStringCache, if any.
+ * Use this function after your last use of a DexStringCache.
+ */
+void dexStringCacheRelease(DexStringCache* pCache);
+
+/*
+ * If the given DexStringCache doesn't already point at the given value,
+ * make a copy of it into the cache. This always returns a writable
+ * pointer to the contents (whether or not a copy had to be made). This
+ * function is intended to be used after making a call that at least
+ * sometimes doesn't populate a DexStringCache.
+ */
+char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value);
+
+/*
+ * Abandon the given DexStringCache, and return a writable copy of the
+ * given value (reusing the string cache's allocation if possible).
+ * The return value must be free()d by the caller. Use this instead of
+ * dexStringCacheRelease() if you want the buffer to survive past the
+ * scope of the DexStringCache.
+ */
+char* dexStringCacheAbandon(DexStringCache* pCache, const char* value);
+
+/*
+ * Method prototype structure, which refers to a protoIdx in a
+ * particular DexFile.
+ */
+struct DexProto {
+    const DexFile* dexFile;     /* file the idx refers to */
+    u4 protoIdx;                /* index into proto_ids table of dexFile */
+};
+
+/*
+ * Set the given DexProto to refer to the prototype of the given MethodId.
+ */
+DEX_INLINE void dexProtoSetFromMethodId(DexProto* pProto,
+    const DexFile* pDexFile, const DexMethodId* pMethodId)
+{
+    pProto->dexFile = pDexFile;
+    pProto->protoIdx = pMethodId->protoIdx;
+}
+
+/*
+ * Get the short-form method descriptor for the given prototype. The
+ * prototype must be protoIdx-based.
+ */
+const char* dexProtoGetShorty(const DexProto* pProto);
+
+/*
+ * Get the full method descriptor for the given prototype.
+ */
+const char* dexProtoGetMethodDescriptor(const DexProto* pProto,
+    DexStringCache* pCache);
+
+/*
+ * Get a copy of the descriptor string associated with the given prototype.
+ * The returned pointer must be free()ed by the caller.
+ */
+char* dexProtoCopyMethodDescriptor(const DexProto* pProto);
+
+/*
+ * Get the parameter descriptors for the given prototype. This is the
+ * concatenation of all the descriptors for all the parameters, in
+ * order, with no other adornment.
+ */
+const char* dexProtoGetParameterDescriptors(const DexProto* pProto,
+    DexStringCache* pCache);
+
+/*
+ * Return the utf-8 encoded descriptor string from the proto of a MethodId.
+ */
+DEX_INLINE const char* dexGetDescriptorFromMethodId(const DexFile* pDexFile,
+        const DexMethodId* pMethodId, DexStringCache* pCache)
+{
+    DexProto proto;
+
+    dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
+    return dexProtoGetMethodDescriptor(&proto, pCache);
+}
+
+/*
+ * Get a copy of the utf-8 encoded method descriptor string from the
+ * proto of a MethodId. The returned pointer must be free()ed by the
+ * caller.
+ */
+DEX_INLINE char* dexCopyDescriptorFromMethodId(const DexFile* pDexFile,
+    const DexMethodId* pMethodId)
+{
+    DexProto proto;
+
+    dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
+    return dexProtoCopyMethodDescriptor(&proto);
+}
+
+/*
+ * Get the type descriptor for the return type of the given prototype.
+ */
+const char* dexProtoGetReturnType(const DexProto* pProto);
+
+/*
+ * Get the parameter count of the given prototype.
+ */
+size_t dexProtoGetParameterCount(const DexProto* pProto);
+
+/*
+ * Compute the number of parameter words (u4 units) required by the
+ * given prototype. For example, if the method takes (int, long) and
+ * returns double, this would return 3 (one for the int, two for the
+ * long, and the return type isn't relevant).
+ */
+int dexProtoComputeArgsSize(const DexProto* pProto);
+
+/*
+ * Compare the two prototypes. The two prototypes are compared
+ * with the return type as the major order, then the first arguments,
+ * then second, etc. If two prototypes are identical except that one
+ * has extra arguments, then the shorter argument is considered the
+ * earlier one in sort order (similar to strcmp()).
+ */
+int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2);
+
+/*
+ * Compare the two prototypes, ignoring return type. The two
+ * prototypes are compared with the first argument as the major order,
+ * then second, etc. If two prototypes are identical except that one
+ * has extra arguments, then the shorter argument is considered the
+ * earlier one in sort order (similar to strcmp()).
+ */
+int dexProtoCompareParameters(const DexProto* pProto1,
+        const DexProto* pProto2);
+
+/*
+ * Compare a prototype and a string method descriptor. The comparison
+ * is done as if the descriptor were converted to a prototype and compared
+ * with dexProtoCompare().
+ */
+int dexProtoCompareToDescriptor(const DexProto* proto, const char* descriptor);
+
+/*
+ * Compare a prototype and a concatenation of type descriptors. The
+ * comparison is done as if the descriptors were converted to a
+ * prototype and compared with dexProtoCompareParameters().
+ */
+int dexProtoCompareToParameterDescriptors(const DexProto* proto,
+        const char* descriptors);
+
+/*
+ * Single-thread prototype parameter iterator. This structure holds a
+ * pointer to a prototype and its parts, along with a cursor.
+ */
+struct DexParameterIterator {
+    const DexProto* proto;
+    const DexTypeList* parameters;
+    int parameterCount;
+    int cursor;
+};
+
+/*
+ * Initialize the given DexParameterIterator to be at the start of the
+ * parameters of the given prototype.
+ */
+void dexParameterIteratorInit(DexParameterIterator* pIterator,
+        const DexProto* pProto);
+
+/*
+ * Get the type_id index for the next parameter, if any. This returns
+ * kDexNoIndex if the last parameter has already been consumed.
+ */
+u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator);
+
+/*
+ * Get the type descriptor for the next parameter, if any. This returns
+ * NULL if the last parameter has already been consumed.
+ */
+const char* dexParameterIteratorNextDescriptor(
+        DexParameterIterator* pIterator);
+
+#endif  // LIBDEX_DEXPROTO_H_
diff --git a/libdex/DexSwapVerify.cpp b/libdex/DexSwapVerify.cpp
new file mode 100644
index 0000000..0d028da
--- /dev/null
+++ b/libdex/DexSwapVerify.cpp
@@ -0,0 +1,2959 @@
+/*
+ * 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.
+ */
+
+/*
+ * Byte-swapping and verification of dex files.
+ */
+
+#include "DexFile.h"
+#include "DexClass.h"
+#include "DexDataMap.h"
+#include "DexProto.h"
+#include "DexUtf.h"
+#include "Leb128.h"
+
+#include <safe_iop.h>
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __BYTE_ORDER
+# error "byte ordering not defined"
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define SWAP2(_value)      (_value)
+# define SWAP4(_value)      (_value)
+# define SWAP8(_value)      (_value)
+#else
+# define SWAP2(_value)      endianSwapU2((_value))
+# define SWAP4(_value)      endianSwapU4((_value))
+# define SWAP8(_value)      endianSwapU8((_value))
+static u2 endianSwapU2(u2 value) {
+    return (value >> 8) | (value << 8);
+}
+static u4 endianSwapU4(u4 value) {
+    /* ABCD --> CDAB --> DCBA */
+    value = (value >> 16) | (value << 16);
+    return ((value & 0xff00ff00) >> 8) | ((value << 8) & 0xff00ff00);
+}
+static u8 endianSwapU8(u8 value) {
+    /* ABCDEFGH --> EFGHABCD --> GHEFCDAB --> HGFEDCBA */
+    value = (value >> 32) | (value << 32);
+    value = ((value & 0xffff0000ffff0000ULL) >> 16) |
+            ((value << 16) & 0xffff0000ffff0000ULL);
+    return ((value & 0xff00ff00ff00ff00ULL) >> 8) |
+           ((value << 8) & 0xff00ff00ff00ff00ULL);
+}
+#endif
+
+#define SWAP_FIELD2(_field) (_field) = SWAP2(_field)
+#define SWAP_FIELD4(_field) (_field) = SWAP4(_field)
+#define SWAP_FIELD8(_field) (_field) = SWAP8(_field)
+
+/*
+ * Some information we pass around to help verify values.
+ */
+struct CheckState {
+    const DexHeader*  pHeader;
+    const u1*         fileStart;
+    const u1*         fileEnd;      // points to fileStart + fileLen
+    u4                fileLen;
+    DexDataMap*       pDataMap;     // set after map verification
+    const DexFile*    pDexFile;     // set after intraitem verification
+
+    /*
+     * bitmap of type_id indices that have been used to define classes;
+     * initialized immediately before class_def cross-verification, and
+     * freed immediately after it
+     */
+    u4*               pDefinedClassBits;
+
+    const void*       previousItem; // set during section iteration
+};
+
+/*
+ * Return the file offset of the given pointer.
+ */
+static inline u4 fileOffset(const CheckState* state, const void* ptr) {
+    return ((const u1*) ptr) - state->fileStart;
+}
+
+/*
+ * Return a pointer for the given file offset.
+ */
+static inline void* filePointer(const CheckState* state, u4 offset) {
+    return (void*) (state->fileStart + offset);
+}
+
+/*
+ * Verify that a pointer range, start inclusive to end exclusive, only
+ * covers bytes in the file and doesn't point beyond the end of the
+ * file. That is, the start must indicate a valid byte or may point at
+ * the byte just past the end of the file (but no further), and the
+ * end must be no less than the start and must also not point beyond
+ * the byte just past the end of the file.
+ */
+static inline bool checkPtrRange(const CheckState* state,
+        const void* start, const void* end, const char* label) {
+    const void* fileStart = state->fileStart;
+    const void* fileEnd = state->fileEnd;
+    if ((start < fileStart) || (start > fileEnd)
+            || (end < start) || (end > fileEnd)) {
+        LOGW("Bad offset range for %s: %#x..%#x", label,
+                fileOffset(state, start), fileOffset(state, end));
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Verify that a range of offsets, start inclusive to end exclusive,
+ * are all valid. That is, the start must indicate a valid byte or may
+ * point at the byte just past the end of the file (but no further),
+ * and the end must be no less than the start and must also not point
+ * beyond the byte just past the end of the file.
+ *
+ * Assumes "const CheckState* state".
+ */
+#define CHECK_OFFSET_RANGE(_start, _end) {                                  \
+        const u1* _startPtr = (const u1*) filePointer(state, (_start));     \
+        const u1* _endPtr = (const u1*) filePointer(state, (_end));         \
+        if (!checkPtrRange(state, _startPtr, _endPtr,                       \
+                        #_start ".." #_end)) {                              \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Verify that a pointer range, start inclusive to end exclusive, only
+ * covers bytes in the file and doesn't point beyond the end of the
+ * file. That is, the start must indicate a valid byte or may point at
+ * the byte just past the end of the file (but no further), and the
+ * end must be no less than the start and must also not point beyond
+ * the byte just past the end of the file.
+ *
+ * Assumes "const CheckState* state".
+ */
+#define CHECK_PTR_RANGE(_start, _end) {                                     \
+        if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) {  \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Make sure a list of items fits entirely within the file.
+ *
+ * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)"
+ * If the type sizes or signs are mismatched, this will return 0.
+ */
+#define CHECK_LIST_SIZE(_ptr, _count, _elemSize) {                          \
+        const u1* _start = (const u1*) (_ptr);                              \
+        const u1* _end = _start + ((_count) * (_elemSize));                 \
+        if (!safe_mul(NULL, (_count), (_elemSize)) ||                       \
+            !checkPtrRange(state, _start, _end, #_ptr)) {                   \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Swap a field that is known to hold an absolute DEX file offset. Note:
+ * This does not check to see that the swapped offset points within the
+ * mapped file, since that should be handled (with even more rigor) by
+ * the cross-verification phase.
+ *
+ * Assumes "const CheckState* state".
+ */
+#define SWAP_OFFSET4(_field) {                                              \
+        SWAP_FIELD4((_field));                                              \
+    }
+
+/*
+ * Verify that an index falls in a valid range.
+ */
+#define CHECK_INDEX(_field, _limit) {                                       \
+        if ((_field) >= (_limit)) {                                         \
+            LOGW("Bad index: %s(%u) > %s(%u)",                              \
+                #_field, (u4)(_field), #_limit, (u4)(_limit));              \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Swap an index, and verify that it falls in a valid range.
+ */
+#define SWAP_INDEX2(_field, _limit) {                                       \
+        SWAP_FIELD2((_field));                                              \
+        CHECK_INDEX((_field), (_limit));                                    \
+    }
+
+/*
+ * Verify that an index falls in a valid range or is kDexNoIndex.
+ */
+#define CHECK_INDEX_OR_NOINDEX(_field, _limit) {                            \
+        if ((_field) != kDexNoIndex && (_field) >= (_limit)) {              \
+            LOGW("Bad index: %s(%u) > %s(%u)",                              \
+                #_field, (u4)(_field), #_limit, (u4)(_limit));              \
+            return 0;                                                       \
+        }                                                                   \
+    }
+
+/*
+ * Swap an index, and verify that it falls in a valid range.
+ */
+#define SWAP_INDEX4(_field, _limit) {                                       \
+        SWAP_FIELD4((_field));                                              \
+        CHECK_INDEX((_field), (_limit));                                    \
+    }
+
+/*
+ * Swap an index, and verify that it falls in a valid range or is
+ * kDexNoIndex.
+ */
+#define SWAP_INDEX4_OR_NOINDEX(_field, _limit) {                            \
+        SWAP_FIELD4((_field));                                              \
+        CHECK_INDEX_OR_NOINDEX((_field), (_limit));                         \
+    }
+
+/* Verify the definer of a given field_idx. */
+static bool verifyFieldDefiner(const CheckState* state, u4 definingClass,
+        u4 fieldIdx) {
+    const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
+    return field->classIdx == definingClass;
+}
+
+/* Verify the definer of a given method_idx. */
+static bool verifyMethodDefiner(const CheckState* state, u4 definingClass,
+        u4 methodIdx) {
+    const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
+    return meth->classIdx == definingClass;
+}
+
+/*
+ * Calculate the required size (in elements) of the array pointed at by
+ * pDefinedClassBits.
+ */
+static size_t calcDefinedClassBitsSize(const CheckState* state)
+{
+    // Divide typeIdsSize by 32 (0x20), rounding up.
+    return (state->pHeader->typeIdsSize + 0x1f) >> 5;
+}
+
+/*
+ * Set the given bit in pDefinedClassBits, returning its former value.
+ */
+static bool setDefinedClassBit(const CheckState* state, u4 typeIdx) {
+    u4 arrayIdx = typeIdx >> 5;
+    u4 bit = 1 << (typeIdx & 0x1f);
+    u4* element = &state->pDefinedClassBits[arrayIdx];
+    bool result = (*element & bit) != 0;
+
+    *element |= bit;
+
+    return result;
+}
+
+/*
+ * Swap the header_item.
+ */
+static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
+{
+    CHECK_PTR_RANGE(pHeader, pHeader + 1);
+
+    // magic is ok
+    SWAP_FIELD4(pHeader->checksum);
+    // signature is ok
+    SWAP_FIELD4(pHeader->fileSize);
+    SWAP_FIELD4(pHeader->headerSize);
+    SWAP_FIELD4(pHeader->endianTag);
+    SWAP_FIELD4(pHeader->linkSize);
+    SWAP_OFFSET4(pHeader->linkOff);
+    SWAP_OFFSET4(pHeader->mapOff);
+    SWAP_FIELD4(pHeader->stringIdsSize);
+    SWAP_OFFSET4(pHeader->stringIdsOff);
+    SWAP_FIELD4(pHeader->typeIdsSize);
+    SWAP_OFFSET4(pHeader->typeIdsOff);
+    SWAP_FIELD4(pHeader->fieldIdsSize);
+    SWAP_OFFSET4(pHeader->fieldIdsOff);
+    SWAP_FIELD4(pHeader->methodIdsSize);
+    SWAP_OFFSET4(pHeader->methodIdsOff);
+    SWAP_FIELD4(pHeader->protoIdsSize);
+    SWAP_OFFSET4(pHeader->protoIdsOff);
+    SWAP_FIELD4(pHeader->classDefsSize);
+    SWAP_OFFSET4(pHeader->classDefsOff);
+    SWAP_FIELD4(pHeader->dataSize);
+    SWAP_OFFSET4(pHeader->dataOff);
+
+    if (pHeader->endianTag != kDexEndianConstant) {
+        LOGE("Unexpected endian_tag: %#x", pHeader->endianTag);
+        return false;
+    }
+
+    // Assign variables so the diagnostic is prettier. (Hooray for macros.)
+    u4 linkOff = pHeader->linkOff;
+    u4 linkEnd = linkOff + pHeader->linkSize;
+    u4 dataOff = pHeader->dataOff;
+    u4 dataEnd = dataOff + pHeader->dataSize;
+    CHECK_OFFSET_RANGE(linkOff, linkEnd);
+    CHECK_OFFSET_RANGE(dataOff, dataEnd);
+
+    /*
+     * Note: The offsets and ranges of the other header items end up getting
+     * checked during the first iteration over the map.
+     */
+
+    return true;
+}
+
+/* Check the header section for sanity. */
+static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
+        u4 sectionCount, u4* endOffset) {
+    if (sectionCount != 1) {
+        LOGE("Multiple header items");
+        return false;
+    }
+
+    if (sectionOffset != 0) {
+        LOGE("Header at %#x; not at start of file", sectionOffset);
+        return false;
+    }
+
+    const DexHeader* pHeader = (const DexHeader*) filePointer(state, 0);
+    *endOffset = pHeader->headerSize;
+    return true;
+}
+
+/*
+ * Helper for swapMap(), which turns a map type constant into a small
+ * one-bit-on integer, suitable for use in an int-sized bit set.
+ */
+static u4 mapTypeToBitMask(int mapType) {
+    switch (mapType) {
+        case kDexTypeHeaderItem:               return 1 << 0;
+        case kDexTypeStringIdItem:             return 1 << 1;
+        case kDexTypeTypeIdItem:               return 1 << 2;
+        case kDexTypeProtoIdItem:              return 1 << 3;
+        case kDexTypeFieldIdItem:              return 1 << 4;
+        case kDexTypeMethodIdItem:             return 1 << 5;
+        case kDexTypeClassDefItem:             return 1 << 6;
+        case kDexTypeMapList:                  return 1 << 7;
+        case kDexTypeTypeList:                 return 1 << 8;
+        case kDexTypeAnnotationSetRefList:     return 1 << 9;
+        case kDexTypeAnnotationSetItem:        return 1 << 10;
+        case kDexTypeClassDataItem:            return 1 << 11;
+        case kDexTypeCodeItem:                 return 1 << 12;
+        case kDexTypeStringDataItem:           return 1 << 13;
+        case kDexTypeDebugInfoItem:            return 1 << 14;
+        case kDexTypeAnnotationItem:           return 1 << 15;
+        case kDexTypeEncodedArrayItem:         return 1 << 16;
+        case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
+        default: {
+            LOGE("Unknown map item type %04x", mapType);
+            return 0;
+        }
+    }
+}
+
+/*
+ * Helper for swapMap(), which indicates if an item type should appear
+ * in the data section.
+ */
+static bool isDataSectionType(int mapType) {
+    switch (mapType) {
+        case kDexTypeHeaderItem:
+        case kDexTypeStringIdItem:
+        case kDexTypeTypeIdItem:
+        case kDexTypeProtoIdItem:
+        case kDexTypeFieldIdItem:
+        case kDexTypeMethodIdItem:
+        case kDexTypeClassDefItem: {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Swap the map_list and verify what we can about it. Also, if verification
+ * passes, allocate the state's DexDataMap.
+ */
+static bool swapMap(CheckState* state, DexMapList* pMap)
+{
+    DexMapItem* item = pMap->list;
+    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));
+
+    while (count--) {
+        SWAP_FIELD2(item->type);
+        SWAP_FIELD2(item->unused);
+        SWAP_FIELD4(item->size);
+        SWAP_OFFSET4(item->offset);
+
+        if (first) {
+            first = false;
+        } else if (lastOffset >= item->offset) {
+            LOGE("Out-of-order map item: %#x then %#x",
+                    lastOffset, item->offset);
+            return false;
+        }
+
+        if (item->offset >= state->pHeader->fileSize) {
+            LOGE("Map item after end of file: %x, size %#x",
+                    item->offset, state->pHeader->fileSize);
+            return false;
+        }
+
+        if (isDataSectionType(item->type)) {
+            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 (icount > dataItemsLeft) {
+                LOGE("Unrealistically many items in the data section: "
+                        "at least %d", dataItemCount + icount);
+                return false;
+            }
+
+            dataItemsLeft -= icount;
+            dataItemCount += icount;
+        }
+
+        u4 bit = mapTypeToBitMask(item->type);
+
+        if (bit == 0) {
+            return false;
+        }
+
+        if ((usedBits & bit) != 0) {
+            LOGE("Duplicate map section of type %#x", item->type);
+            return false;
+        }
+
+        usedBits |= bit;
+        lastOffset = item->offset;
+        item++;
+    }
+
+    if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
+        LOGE("Map is missing header entry");
+        return false;
+    }
+
+    if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
+        LOGE("Map is missing map_list entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
+            && ((state->pHeader->stringIdsOff != 0)
+                    || (state->pHeader->stringIdsSize != 0))) {
+        LOGE("Map is missing string_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
+            && ((state->pHeader->typeIdsOff != 0)
+                    || (state->pHeader->typeIdsSize != 0))) {
+        LOGE("Map is missing type_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
+            && ((state->pHeader->protoIdsOff != 0)
+                    || (state->pHeader->protoIdsSize != 0))) {
+        LOGE("Map is missing proto_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
+            && ((state->pHeader->fieldIdsOff != 0)
+                    || (state->pHeader->fieldIdsSize != 0))) {
+        LOGE("Map is missing field_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
+            && ((state->pHeader->methodIdsOff != 0)
+                    || (state->pHeader->methodIdsSize != 0))) {
+        LOGE("Map is missing method_ids entry");
+        return false;
+    }
+
+    if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
+            && ((state->pHeader->classDefsOff != 0)
+                    || (state->pHeader->classDefsSize != 0))) {
+        LOGE("Map is missing class_defs entry");
+        return false;
+    }
+
+    state->pDataMap = dexDataMapAlloc(dataItemCount);
+    if (state->pDataMap == NULL) {
+        LOGE("Unable to allocate data map (size %#x)", dataItemCount);
+        return false;
+    }
+
+    return true;
+}
+
+/* Check the map section for sanity. */
+static bool checkMapSection(const CheckState* state, u4 sectionOffset,
+        u4 sectionCount, u4* endOffset) {
+    if (sectionCount != 1) {
+        LOGE("Multiple map list items");
+        return false;
+    }
+
+    if (sectionOffset != state->pHeader->mapOff) {
+        LOGE("Map not at header-defined offset: %#x, expected %#x",
+                sectionOffset, state->pHeader->mapOff);
+        return false;
+    }
+
+    const DexMapList* pMap = (const DexMapList*) filePointer(state, sectionOffset);
+
+    *endOffset =
+        sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem));
+    return true;
+}
+
+/* Perform byte-swapping and intra-item verification on string_id_item. */
+static void* swapStringIdItem(const CheckState* state, void* ptr) {
+    DexStringId* item = (DexStringId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_OFFSET4(item->stringDataOff);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of string_id_item. */
+static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
+    const DexStringId* item = (const DexStringId*) ptr;
+
+    if (!dexDataMapVerify(state->pDataMap,
+                    item->stringDataOff, kDexTypeStringDataItem)) {
+        return NULL;
+    }
+
+    const DexStringId* item0 = (const DexStringId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering.
+        const char* s0 = dexGetStringData(state->pDexFile, item0);
+        const char* s1 = dexGetStringData(state->pDexFile, item);
+        if (dexUtf8Cmp(s0, s1) >= 0) {
+            LOGE("Out-of-order string_ids: '%s' then '%s'", s0, s1);
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on type_id_item. */
+static void* swapTypeIdItem(const CheckState* state, void* ptr) {
+    DexTypeId* item = (DexTypeId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of type_id_item. */
+static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
+    const DexTypeId* item = (const DexTypeId*) ptr;
+    const char* descriptor =
+        dexStringById(state->pDexFile, item->descriptorIdx);
+
+    if (!dexIsValidTypeDescriptor(descriptor)) {
+        LOGE("Invalid type descriptor: '%s'", descriptor);
+        return NULL;
+    }
+
+    const DexTypeId* item0 = (const DexTypeId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on string_ids being in order.
+        if (item0->descriptorIdx >= item->descriptorIdx) {
+            LOGE("Out-of-order type_ids: %#x then %#x",
+                    item0->descriptorIdx, item->descriptorIdx);
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on proto_id_item. */
+static void* swapProtoIdItem(const CheckState* state, void* ptr) {
+    DexProtoId* item = (DexProtoId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize);
+    SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize);
+    SWAP_OFFSET4(item->parametersOff);
+
+    return item + 1;
+}
+
+/* Helper for crossVerifyProtoIdItem(), which checks a shorty character
+ * to see if it is compatible with a type descriptor. Returns true if
+ * so, false if not. */
+static bool shortyDescMatch(char shorty, const char* descriptor, bool
+        isReturnType) {
+    switch (shorty) {
+        case 'V': {
+            if (!isReturnType) {
+                LOGE("Invalid use of void");
+                return false;
+            }
+            // Fall through.
+        }
+        case 'B':
+        case 'C':
+        case 'D':
+        case 'F':
+        case 'I':
+        case 'J':
+        case 'S':
+        case 'Z': {
+            if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) {
+                LOGE("Shorty vs. primitive type mismatch: '%c', '%s'",
+                        shorty, descriptor);
+                return false;
+            }
+            break;
+        }
+        case 'L': {
+            if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
+                LOGE("Shorty vs. type mismatch: '%c', '%s'",
+                        shorty, descriptor);
+                return false;
+            }
+            break;
+        }
+        default: {
+            LOGE("Bogus shorty: '%c'", shorty);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/* Perform cross-item verification of proto_id_item. */
+static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
+    const DexProtoId* item = (const DexProtoId*) ptr;
+    const char* shorty =
+        dexStringById(state->pDexFile, item->shortyIdx);
+
+    if (!dexDataMapVerify0Ok(state->pDataMap,
+                    item->parametersOff, kDexTypeTypeList)) {
+        return NULL;
+    }
+
+    if (!shortyDescMatch(*shorty,
+                    dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx),
+                    true)) {
+        return NULL;
+    }
+
+    u4 protoIdx = item - state->pDexFile->pProtoIds;
+    DexProto proto = { state->pDexFile, protoIdx };
+    DexParameterIterator iterator;
+
+    dexParameterIteratorInit(&iterator, &proto);
+    shorty++; // Skip the return type.
+
+    for (;;) {
+        const char *desc = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (desc == NULL) {
+            break;
+        }
+
+        if (*shorty == '\0') {
+            LOGE("Shorty is too short");
+            return NULL;
+        }
+
+        if (!shortyDescMatch(*shorty, desc, false)) {
+            return NULL;
+        }
+
+        shorty++;
+    }
+
+    if (*shorty != '\0') {
+        LOGE("Shorty is too long");
+        return NULL;
+    }
+
+    const DexProtoId* item0 = (const DexProtoId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on type_ids being in order.
+        if (item0->returnTypeIdx > item->returnTypeIdx) {
+            LOGE("Out-of-order proto_id return types");
+            return NULL;
+        } else if (item0->returnTypeIdx == item->returnTypeIdx) {
+            bool badOrder = false;
+            DexProto proto0 = { state->pDexFile, protoIdx - 1 };
+            DexParameterIterator iterator0;
+
+            dexParameterIteratorInit(&iterator, &proto);
+            dexParameterIteratorInit(&iterator0, &proto0);
+
+            for (;;) {
+                u4 idx0 = dexParameterIteratorNextIndex(&iterator0);
+                u4 idx1 = dexParameterIteratorNextIndex(&iterator);
+
+                if (idx1 == kDexNoIndex) {
+                    badOrder = true;
+                    break;
+                }
+
+                if (idx0 == kDexNoIndex) {
+                    break;
+                }
+
+                if (idx0 < idx1) {
+                    break;
+                } else if (idx0 > idx1) {
+                    badOrder = true;
+                    break;
+                }
+            }
+
+            if (badOrder) {
+                LOGE("Out-of-order proto_id arguments");
+                return NULL;
+            }
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on field_id_item. */
+static void* swapFieldIdItem(const CheckState* state, void* ptr) {
+    DexFieldId* item = (DexFieldId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
+    SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize);
+    SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of field_id_item. */
+static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
+    const DexFieldId* item = (const DexFieldId*) ptr;
+    const char* s;
+
+    s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
+    if (!dexIsClassDescriptor(s)) {
+        LOGE("Invalid descriptor for class_idx: '%s'", s);
+        return NULL;
+    }
+
+    s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
+    if (!dexIsFieldDescriptor(s)) {
+        LOGE("Invalid descriptor for type_idx: '%s'", s);
+        return NULL;
+    }
+
+    s = dexStringById(state->pDexFile, item->nameIdx);
+    if (!dexIsValidMemberName(s)) {
+        LOGE("Invalid name: '%s'", s);
+        return NULL;
+    }
+
+    const DexFieldId* item0 = (const DexFieldId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on the other sections being in order.
+        bool done = false;
+        bool bogus = false;
+
+        if (item0->classIdx > item->classIdx) {
+            bogus = true;
+            done = true;
+        } else if (item0->classIdx < item->classIdx) {
+            done = true;
+        }
+
+        if (!done) {
+            if (item0->nameIdx > item->nameIdx) {
+                bogus = true;
+                done = true;
+            } else if (item0->nameIdx < item->nameIdx) {
+                done = true;
+            }
+        }
+
+        if (!done) {
+            if (item0->typeIdx >= item->typeIdx) {
+                bogus = true;
+            }
+        }
+
+        if (bogus) {
+            LOGE("Out-of-order field_ids");
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on method_id_item. */
+static void* swapMethodIdItem(const CheckState* state, void* ptr) {
+    DexMethodId* item = (DexMethodId*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
+    SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize);
+    SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
+
+    return item + 1;
+}
+
+/* Perform cross-item verification of method_id_item. */
+static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
+    const DexMethodId* item = (const DexMethodId*) ptr;
+    const char* s;
+
+    s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
+    if (!dexIsReferenceDescriptor(s)) {
+        LOGE("Invalid descriptor for class_idx: '%s'", s);
+        return NULL;
+    }
+
+    s = dexStringById(state->pDexFile, item->nameIdx);
+    if (!dexIsValidMemberName(s)) {
+        LOGE("Invalid name: '%s'", s);
+        return NULL;
+    }
+
+    const DexMethodId* item0 = (const DexMethodId*) state->previousItem;
+    if (item0 != NULL) {
+        // Check ordering. This relies on the other sections being in order.
+        bool done = false;
+        bool bogus = false;
+
+        if (item0->classIdx > item->classIdx) {
+            bogus = true;
+            done = true;
+        } else if (item0->classIdx < item->classIdx) {
+            done = true;
+        }
+
+        if (!done) {
+            if (item0->nameIdx > item->nameIdx) {
+                bogus = true;
+                done = true;
+            } else if (item0->nameIdx < item->nameIdx) {
+                done = true;
+            }
+        }
+
+        if (!done) {
+            if (item0->protoIdx >= item->protoIdx) {
+                bogus = true;
+            }
+        }
+
+        if (bogus) {
+            LOGE("Out-of-order method_ids");
+            return NULL;
+        }
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Perform byte-swapping and intra-item verification on class_def_item. */
+static void* swapClassDefItem(const CheckState* state, void* ptr) {
+    DexClassDef* item = (DexClassDef*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize);
+    SWAP_FIELD4(item->accessFlags);
+    SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize);
+    SWAP_OFFSET4(item->interfacesOff);
+    SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize);
+    SWAP_OFFSET4(item->annotationsOff);
+    SWAP_OFFSET4(item->classDataOff);
+
+    return item + 1;
+}
+
+/* defined below */
+static u4 findFirstClassDataDefiner(const CheckState* state,
+        DexClassData* classData);
+static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
+        const DexAnnotationsDirectoryItem* dir);
+
+/* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
+ * make sure all its references are to a given class. */
+static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
+        u4 definerIdx) {
+    if (offset == 0) {
+        return true;
+    }
+
+    const u1* data = (const u1*) filePointer(state, offset);
+    DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
+
+    if (classData == NULL) {
+        // Shouldn't happen, but bail here just in case.
+        return false;
+    }
+
+    /*
+     * The class_data_item verification ensures that
+     * it consistently refers to the same definer, so all we need to
+     * do is check the first one.
+     */
+    u4 dataDefiner = findFirstClassDataDefiner(state, classData);
+    bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
+
+    free(classData);
+    return result;
+}
+
+/* Helper for crossVerifyClassDefItem(), which checks an
+ * annotations_directory_item to make sure all its references are to a
+ * given class. */
+static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
+        u4 offset, u4 definerIdx) {
+    if (offset == 0) {
+        return true;
+    }
+
+    const DexAnnotationsDirectoryItem* dir =
+        (const DexAnnotationsDirectoryItem*) filePointer(state, offset);
+    u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
+
+    return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
+}
+
+/* Perform cross-item verification of class_def_item. */
+static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
+    const DexClassDef* item = (const DexClassDef*) ptr;
+    u4 classIdx = item->classIdx;
+    const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx);
+
+    if (!dexIsClassDescriptor(descriptor)) {
+        LOGE("Invalid class: '%s'", descriptor);
+        return NULL;
+    }
+
+    if (setDefinedClassBit(state, classIdx)) {
+        LOGE("Duplicate class definition: '%s'", descriptor);
+        return NULL;
+    }
+
+    bool okay =
+        dexDataMapVerify0Ok(state->pDataMap,
+                item->interfacesOff, kDexTypeTypeList)
+        && dexDataMapVerify0Ok(state->pDataMap,
+                item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
+        && dexDataMapVerify0Ok(state->pDataMap,
+                item->classDataOff, kDexTypeClassDataItem)
+        && dexDataMapVerify0Ok(state->pDataMap,
+                item->staticValuesOff, kDexTypeEncodedArrayItem);
+
+    if (!okay) {
+        return NULL;
+    }
+
+    if (item->superclassIdx != kDexNoIndex) {
+        descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
+        if (!dexIsClassDescriptor(descriptor)) {
+            LOGE("Invalid superclass: '%s'", descriptor);
+            return NULL;
+        }
+    }
+
+    const DexTypeList* interfaces =
+        dexGetInterfacesList(state->pDexFile, item);
+    if (interfaces != NULL) {
+        u4 size = interfaces->size;
+        u4 i;
+
+        /*
+         * Ensure that all interfaces refer to classes (not arrays or
+         * primitives).
+         */
+        for (i = 0; i < size; i++) {
+            descriptor = dexStringByTypeIdx(state->pDexFile,
+                    dexTypeListGetIdx(interfaces, i));
+            if (!dexIsClassDescriptor(descriptor)) {
+                LOGE("Invalid interface: '%s'", descriptor);
+                return NULL;
+            }
+        }
+
+        /*
+         * Ensure that there are no duplicates. This is an O(N^2) test,
+         * but in practice the number of interfaces implemented by any
+         * given class is low. I will buy a milkshake for the
+         * first person to show me a realistic case for which this test
+         * would be unacceptably slow.
+         */
+        for (i = 1; i < size; i++) {
+            u4 idx1 = dexTypeListGetIdx(interfaces, i);
+            u4 j;
+            for (j = 0; j < i; j++) {
+                u4 idx2 = dexTypeListGetIdx(interfaces, j);
+                if (idx1 == idx2) {
+                    LOGE("Duplicate interface: '%s'",
+                            dexStringByTypeIdx(state->pDexFile, idx1));
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
+        LOGE("Invalid class_data_item");
+        return NULL;
+    }
+
+    if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
+                    item->classIdx)) {
+        LOGE("Invalid annotations_directory_item");
+        return NULL;
+    }
+
+    return (void*) (item + 1);
+}
+
+/* Helper for swapAnnotationsDirectoryItem(), which performs
+ * byte-swapping and intra-item verification on an
+ * annotation_directory_item's field elements. */
+static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
+    DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
+    bool first = true;
+    u4 lastIdx = 0;
+
+    CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
+
+    while (count--) {
+        SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
+        SWAP_OFFSET4(item->annotationsOff);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= item->fieldIdx) {
+            LOGE("Out-of-order field_idx: %#x then %#x", lastIdx,
+                 item->fieldIdx);
+            return NULL;
+        }
+
+        lastIdx = item->fieldIdx;
+        item++;
+    }
+
+    return (u1*) item;
+}
+
+/* Helper for swapAnnotationsDirectoryItem(), which performs
+ * byte-swapping and intra-item verification on an
+ * annotation_directory_item's method elements. */
+static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
+    DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
+    bool first = true;
+    u4 lastIdx = 0;
+
+    CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
+
+    while (count--) {
+        SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
+        SWAP_OFFSET4(item->annotationsOff);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= item->methodIdx) {
+            LOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
+                 item->methodIdx);
+            return NULL;
+        }
+
+        lastIdx = item->methodIdx;
+        item++;
+    }
+
+    return (u1*) item;
+}
+
+/* Helper for swapAnnotationsDirectoryItem(), which performs
+ * byte-swapping and intra-item verification on an
+ * annotation_directory_item's parameter elements. */
+static u1* swapParameterAnnotations(const CheckState* state, u4 count,
+        u1* addr) {
+    DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
+    bool first = true;
+    u4 lastIdx = 0;
+
+    CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
+
+    while (count--) {
+        SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
+        SWAP_OFFSET4(item->annotationsOff);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= item->methodIdx) {
+            LOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
+                 item->methodIdx);
+            return NULL;
+        }
+
+        lastIdx = item->methodIdx;
+        item++;
+    }
+
+    return (u1*) item;
+}
+
+/* Perform byte-swapping and intra-item verification on
+ * annotations_directory_item. */
+static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
+    DexAnnotationsDirectoryItem* item = (DexAnnotationsDirectoryItem*) ptr;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_OFFSET4(item->classAnnotationsOff);
+    SWAP_FIELD4(item->fieldsSize);
+    SWAP_FIELD4(item->methodsSize);
+    SWAP_FIELD4(item->parametersSize);
+
+    u1* addr = (u1*) (item + 1);
+
+    if (item->fieldsSize != 0) {
+        addr = swapFieldAnnotations(state, item->fieldsSize, addr);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->methodsSize != 0) {
+        addr = swapMethodAnnotations(state, item->methodsSize, addr);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->parametersSize != 0) {
+        addr = swapParameterAnnotations(state, item->parametersSize, addr);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    return addr;
+}
+
+/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
+ * field elements. */
+static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
+        const u1* addr, u4 definingClass) {
+    const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
+
+    while (count--) {
+        if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
+            return NULL;
+        }
+        if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
+                        kDexTypeAnnotationSetItem)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (const u1*) item;
+}
+
+/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
+ * method elements. */
+static const u1* crossVerifyMethodAnnotations(const CheckState* state,
+        u4 count, const u1* addr, u4 definingClass) {
+    const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
+
+    while (count--) {
+        if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
+            return NULL;
+        }
+        if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
+                        kDexTypeAnnotationSetItem)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (const u1*) item;
+}
+
+/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
+ * parameter elements. */
+static const u1* crossVerifyParameterAnnotations(const CheckState* state,
+        u4 count, const u1* addr, u4 definingClass) {
+    const DexParameterAnnotationsItem* item =
+        (DexParameterAnnotationsItem*) addr;
+
+    while (count--) {
+        if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
+            return NULL;
+        }
+        if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
+                        kDexTypeAnnotationSetRefList)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (const u1*) item;
+}
+
+/* Helper for crossVerifyClassDefItem() and
+ * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
+ * the definer of the first item in the data. */
+static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
+        const DexAnnotationsDirectoryItem* dir) {
+    if (dir->fieldsSize != 0) {
+        const DexFieldAnnotationsItem* fields =
+            dexGetFieldAnnotations(state->pDexFile, dir);
+        const DexFieldId* field =
+            dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
+        return field->classIdx;
+    }
+
+    if (dir->methodsSize != 0) {
+        const DexMethodAnnotationsItem* methods =
+            dexGetMethodAnnotations(state->pDexFile, dir);
+        const DexMethodId* method =
+            dexGetMethodId(state->pDexFile, methods[0].methodIdx);
+        return method->classIdx;
+    }
+
+    if (dir->parametersSize != 0) {
+        const DexParameterAnnotationsItem* parameters =
+            dexGetParameterAnnotations(state->pDexFile, dir);
+        const DexMethodId* method =
+            dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
+        return method->classIdx;
+    }
+
+    return kDexNoIndex;
+}
+
+/* Perform cross-item verification of annotations_directory_item. */
+static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
+        void* ptr) {
+    const DexAnnotationsDirectoryItem* item = (const DexAnnotationsDirectoryItem*) ptr;
+    u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
+
+    if (!dexDataMapVerify0Ok(state->pDataMap,
+                    item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
+        return NULL;
+    }
+
+    const u1* addr = (const u1*) (item + 1);
+
+    if (item->fieldsSize != 0) {
+        addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
+                definingClass);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->methodsSize != 0) {
+        addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
+                definingClass);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    if (item->parametersSize != 0) {
+        addr = crossVerifyParameterAnnotations(state, item->parametersSize,
+                addr, definingClass);
+        if (addr == NULL) {
+            return NULL;
+        }
+    }
+
+    return (void*) addr;
+}
+
+/* Perform byte-swapping and intra-item verification on type_list. */
+static void* swapTypeList(const CheckState* state, void* ptr)
+{
+    DexTypeList* pTypeList = (DexTypeList*) ptr;
+    DexTypeItem* pType;
+    u4 count;
+
+    CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
+    SWAP_FIELD4(pTypeList->size);
+    count = pTypeList->size;
+    pType = pTypeList->list;
+    CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
+
+    while (count--) {
+        SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
+        pType++;
+    }
+
+    return pType;
+}
+
+/* Perform byte-swapping and intra-item verification on
+ * annotation_set_ref_list. */
+static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
+    DexAnnotationSetRefList* list = (DexAnnotationSetRefList*) ptr;
+    DexAnnotationSetRefItem* item;
+    u4 count;
+
+    CHECK_PTR_RANGE(list, list + 1);
+    SWAP_FIELD4(list->size);
+    count = list->size;
+    item = list->list;
+    CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
+
+    while (count--) {
+        SWAP_OFFSET4(item->annotationsOff);
+        item++;
+    }
+
+    return item;
+}
+
+/* Perform cross-item verification of annotation_set_ref_list. */
+static void* crossVerifyAnnotationSetRefList(const CheckState* state,
+        void* ptr) {
+    const DexAnnotationSetRefList* list = (const DexAnnotationSetRefList*) ptr;
+    const DexAnnotationSetRefItem* item = list->list;
+    int count = list->size;
+
+    while (count--) {
+        if (!dexDataMapVerify0Ok(state->pDataMap,
+                        item->annotationsOff, kDexTypeAnnotationSetItem)) {
+            return NULL;
+        }
+        item++;
+    }
+
+    return (void*) item;
+}
+
+/* Perform byte-swapping and intra-item verification on
+ * annotation_set_item. */
+static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
+    DexAnnotationSetItem* set = (DexAnnotationSetItem*) ptr;
+    u4* item;
+    u4 count;
+
+    CHECK_PTR_RANGE(set, set + 1);
+    SWAP_FIELD4(set->size);
+    count = set->size;
+    item = set->entries;
+    CHECK_LIST_SIZE(item, count, sizeof(u4));
+
+    while (count--) {
+        SWAP_OFFSET4(*item);
+        item++;
+    }
+
+    return item;
+}
+
+/* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
+ * out of an annotation_item. */
+static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
+    const u1* data = item->annotation;
+    return readUnsignedLeb128(&data);
+}
+
+/* Perform cross-item verification of annotation_set_item. */
+static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
+    const DexAnnotationSetItem* set = (const DexAnnotationSetItem*) ptr;
+    int count = set->size;
+    u4 lastIdx = 0;
+    bool first = true;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (!dexDataMapVerify0Ok(state->pDataMap,
+                        dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
+            return NULL;
+        }
+
+        const DexAnnotationItem* annotation =
+            dexGetAnnotationItem(state->pDexFile, set, i);
+        u4 idx = annotationItemTypeIdx(annotation);
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= idx) {
+            LOGE("Out-of-order entry types: %#x then %#x",
+                    lastIdx, idx);
+            return NULL;
+        }
+
+        lastIdx = idx;
+    }
+
+    return (void*) (set->entries + count);
+}
+
+/* Helper for verifyClassDataItem(), which checks a list of fields. */
+static bool verifyFields(const CheckState* state, u4 size,
+        DexField* fields, bool expectStatic) {
+    u4 i;
+
+    for (i = 0; i < size; i++) {
+        DexField* field = &fields[i];
+        u4 accessFlags = field->accessFlags;
+        bool isStatic = (accessFlags & ACC_STATIC) != 0;
+
+        CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
+
+        if (isStatic != expectStatic) {
+            LOGE("Field in wrong list @ %d", i);
+            return false;
+        }
+
+        if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
+            LOGE("Bogus field access flags %x @ %d", accessFlags, i);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/* Helper for verifyClassDataItem(), which checks a list of methods. */
+static bool verifyMethods(const CheckState* state, u4 size,
+        DexMethod* methods, bool expectDirect) {
+    u4 i;
+
+    for (i = 0; i < size; i++) {
+        DexMethod* method = &methods[i];
+
+        CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
+
+        u4 accessFlags = method->accessFlags;
+        bool isDirect =
+            (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
+        bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
+        bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
+        bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
+
+        if (isDirect != expectDirect) {
+            LOGE("Method in wrong list @ %d", i);
+            return false;
+        }
+
+        if (((accessFlags & ~ACC_METHOD_MASK) != 0)
+                || (isSynchronized && !allowSynchronized)) {
+            LOGE("Bogus method access flags %x @ %d", accessFlags, i);
+            return false;
+        }
+
+        if (expectCode) {
+            if (method->codeOff == 0) {
+                LOGE("Unexpected zero code_off for access_flags %x",
+                        accessFlags);
+                return false;
+            }
+        } else if (method->codeOff != 0) {
+            LOGE("Unexpected non-zero code_off %#x for access_flags %x",
+                    method->codeOff, accessFlags);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/* Helper for verifyClassDataItem(), which does most of the work. */
+static bool verifyClassDataItem0(const CheckState* state,
+        DexClassData* classData) {
+    bool okay;
+
+    okay = verifyFields(state, classData->header.staticFieldsSize,
+            classData->staticFields, true);
+
+    if (!okay) {
+        LOGE("Trouble with static fields");
+        return false;
+    }
+
+    verifyFields(state, classData->header.instanceFieldsSize,
+            classData->instanceFields, false);
+
+    if (!okay) {
+        LOGE("Trouble with instance fields");
+        return false;
+    }
+
+    okay = verifyMethods(state, classData->header.directMethodsSize,
+            classData->directMethods, true);
+
+    if (!okay) {
+        LOGE("Trouble with direct methods");
+        return false;
+    }
+
+    okay = verifyMethods(state, classData->header.virtualMethodsSize,
+            classData->virtualMethods, false);
+
+    if (!okay) {
+        LOGE("Trouble with virtual methods");
+        return false;
+    }
+
+    return true;
+}
+
+/* Perform intra-item verification on class_data_item. */
+static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+    DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
+
+    if (classData == NULL) {
+        LOGE("Unable to parse class_data_item");
+        return NULL;
+    }
+
+    bool okay = verifyClassDataItem0(state, classData);
+
+    free(classData);
+
+    if (!okay) {
+        return NULL;
+    }
+
+    return (void*) data;
+}
+
+/* Helper for crossVerifyClassDefItem() and
+ * crossVerifyClassDataItem(), which finds the type_idx of the definer
+ * of the first item in the data. */
+static u4 findFirstClassDataDefiner(const CheckState* state,
+        DexClassData* classData) {
+    if (classData->header.staticFieldsSize != 0) {
+        u4 fieldIdx = classData->staticFields[0].fieldIdx;
+        const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
+        return field->classIdx;
+    }
+
+    if (classData->header.instanceFieldsSize != 0) {
+        u4 fieldIdx = classData->instanceFields[0].fieldIdx;
+        const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
+        return field->classIdx;
+    }
+
+    if (classData->header.directMethodsSize != 0) {
+        u4 methodIdx = classData->directMethods[0].methodIdx;
+        const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
+        return meth->classIdx;
+    }
+
+    if (classData->header.virtualMethodsSize != 0) {
+        u4 methodIdx = classData->virtualMethods[0].methodIdx;
+        const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
+        return meth->classIdx;
+    }
+
+    return kDexNoIndex;
+}
+
+/* Perform cross-item verification of class_data_item. */
+static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+    DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
+    u4 definingClass = findFirstClassDataDefiner(state, classData);
+    bool okay = true;
+    u4 i;
+
+    for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexField* field = &classData->staticFields[i];
+        okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
+    }
+
+    for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexField* field = &classData->instanceFields[i];
+        okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
+    }
+
+    for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexMethod* meth = &classData->directMethods[i];
+        okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
+                kDexTypeCodeItem)
+            && verifyMethodDefiner(state, definingClass, meth->methodIdx);
+    }
+
+    for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
+        i--;
+        const DexMethod* meth = &classData->virtualMethods[i];
+        okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
+                kDexTypeCodeItem)
+            && verifyMethodDefiner(state, definingClass, meth->methodIdx);
+    }
+
+    free(classData);
+
+    if (!okay) {
+        return NULL;
+    }
+
+    return (void*) data;
+}
+
+/* Helper for swapCodeItem(), which fills an array with all the valid
+ * handlerOff values for catch handlers and also verifies the handler
+ * contents. */
+static u4 setHandlerOffsAndVerify(const CheckState* state,
+        DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
+    const u1* fileEnd = state->fileEnd;
+    const u1* handlersBase = dexGetCatchHandlerData(code);
+    u4 offset = firstOffset;
+    bool okay = true;
+    u4 i;
+
+    for (i = 0; i < handlersSize; i++) {
+        const u1* ptr = handlersBase + offset;
+        int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
+        bool catchAll;
+
+        if (!okay) {
+            LOGE("Bogus size");
+            return 0;
+        }
+
+        if ((size < -65536) || (size > 65536)) {
+            LOGE("Invalid size: %d", size);
+            return 0;
+        }
+
+        if (size <= 0) {
+            catchAll = true;
+            size = -size;
+        } else {
+            catchAll = false;
+        }
+
+        handlerOffs[i] = offset;
+
+        while (size-- > 0) {
+            u4 typeIdx =
+                readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
+
+            if (!okay) {
+                LOGE("Bogus type_idx");
+                return 0;
+            }
+
+            CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
+
+            u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
+
+            if (!okay) {
+                LOGE("Bogus addr");
+                return 0;
+            }
+
+            if (addr >= code->insnsSize) {
+                LOGE("Invalid addr: %#x", addr);
+                return 0;
+            }
+        }
+
+        if (catchAll) {
+            u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
+
+            if (!okay) {
+                LOGE("Bogus catch_all_addr");
+                return 0;
+            }
+
+            if (addr >= code->insnsSize) {
+                LOGE("Invalid catch_all_addr: %#x", addr);
+                return 0;
+            }
+        }
+
+        offset = ptr - handlersBase;
+    }
+
+    return offset;
+}
+
+/* Helper for swapCodeItem(), which does all the try-catch related
+ * swapping and verification. */
+static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
+    const u1* encodedHandlers = dexGetCatchHandlerData(code);
+    const u1* encodedPtr = encodedHandlers;
+    bool okay = true;
+    u4 handlersSize =
+        readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
+
+    if (!okay) {
+        LOGE("Bogus handlers_size");
+        return NULL;
+    }
+
+    if ((handlersSize == 0) || (handlersSize >= 65536)) {
+        LOGE("Invalid handlers_size: %d", handlersSize);
+        return NULL;
+    }
+
+    u4 handlerOffs[handlersSize]; // list of valid handlerOff values
+    u4 endOffset = setHandlerOffsAndVerify(state, code,
+            encodedPtr - encodedHandlers,
+            handlersSize, handlerOffs);
+
+    if (endOffset == 0) {
+        return NULL;
+    }
+
+    DexTry* tries = (DexTry*) dexGetTries(code);
+    u4 count = code->triesSize;
+    u4 lastEnd = 0;
+
+    CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
+
+    while (count--) {
+        u4 i;
+
+        SWAP_FIELD4(tries->startAddr);
+        SWAP_FIELD2(tries->insnCount);
+        SWAP_FIELD2(tries->handlerOff);
+
+        if (tries->startAddr < lastEnd) {
+            LOGE("Out-of-order try");
+            return NULL;
+        }
+
+        if (tries->startAddr >= code->insnsSize) {
+            LOGE("Invalid start_addr: %#x", tries->startAddr);
+            return NULL;
+        }
+
+        for (i = 0; i < handlersSize; i++) {
+            if (tries->handlerOff == handlerOffs[i]) {
+                break;
+            }
+        }
+
+        if (i == handlersSize) {
+            LOGE("Bogus handler offset: %#x", tries->handlerOff);
+            return NULL;
+        }
+
+        lastEnd = tries->startAddr + tries->insnCount;
+
+        if (lastEnd > code->insnsSize) {
+            LOGE("Invalid insn_count: %#x (end addr %#x)",
+                    tries->insnCount, lastEnd);
+            return NULL;
+        }
+
+        tries++;
+    }
+
+    return (u1*) encodedHandlers + endOffset;
+}
+
+/* Perform byte-swapping and intra-item verification on code_item. */
+static void* swapCodeItem(const CheckState* state, void* ptr) {
+    DexCode* item = (DexCode*) ptr;
+    u2* insns;
+    u4 count;
+
+    CHECK_PTR_RANGE(item, item + 1);
+    SWAP_FIELD2(item->registersSize);
+    SWAP_FIELD2(item->insSize);
+    SWAP_FIELD2(item->outsSize);
+    SWAP_FIELD2(item->triesSize);
+    SWAP_OFFSET4(item->debugInfoOff);
+    SWAP_FIELD4(item->insnsSize);
+
+    if (item->insSize > item->registersSize) {
+        LOGE("insSize (%u) > registersSize (%u)", item->insSize,
+                item->registersSize);
+        return NULL;
+    }
+
+    if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
+        /*
+         * It's okay for outsSize to be up to five, even if registersSize
+         * is smaller, since the short forms of method invocation allow
+         * repetition of a register multiple times within a single parameter
+         * list. Longer parameter lists, though, need to be represented
+         * in-order in the register file.
+         */
+        LOGE("outsSize (%u) > registersSize (%u)", item->outsSize,
+                item->registersSize);
+        return NULL;
+    }
+
+    count = item->insnsSize;
+    insns = item->insns;
+    CHECK_LIST_SIZE(insns, count, sizeof(u2));
+
+    while (count--) {
+        *insns = SWAP2(*insns);
+        insns++;
+    }
+
+    if (item->triesSize == 0) {
+        ptr = insns;
+    } else {
+        if ((((u4) insns) & 3) != 0) {
+            // Four-byte alignment for the tries. Verify the spacer is a 0.
+            if (*insns != 0) {
+                LOGE("Non-zero padding: %#x", (u4) *insns);
+                return NULL;
+            }
+        }
+
+        ptr = swapTriesAndCatches(state, item);
+    }
+
+    return ptr;
+}
+
+/* Perform intra-item verification on string_data_item. */
+static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
+    const u1* fileEnd = state->fileEnd;
+    const u1* data = (const u1*) ptr;
+    bool okay = true;
+    u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+    u4 i;
+
+    if (!okay) {
+        LOGE("Bogus utf16_size");
+        return NULL;
+    }
+
+    for (i = 0; i < utf16Size; i++) {
+        if (data >= fileEnd) {
+            LOGE("String data would go beyond end-of-file");
+            return NULL;
+        }
+
+        u1 byte1 = *(data++);
+
+        // Switch on the high four bits.
+        switch (byte1 >> 4) {
+            case 0x00: {
+                // Special case of bit pattern 0xxx.
+                if (byte1 == 0) {
+                    LOGE("String shorter than indicated utf16_size %#x",
+                            utf16Size);
+                    return NULL;
+                }
+                break;
+            }
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07: {
+                // Bit pattern 0xxx. No need for any extra bytes or checks.
+                break;
+            }
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0f: {
+                /*
+                 * Bit pattern 10xx or 1111, which are illegal start bytes.
+                 * Note: 1111 is valid for normal UTF-8, but not the
+                 * modified UTF-8 used here.
+                 */
+                LOGE("Illegal start byte %#x", byte1);
+                return NULL;
+            }
+            case 0x0e: {
+                // Bit pattern 1110, so there are two additional bytes.
+                u1 byte2 = *(data++);
+                if ((byte2 & 0xc0) != 0x80) {
+                    LOGE("Illegal continuation byte %#x", byte2);
+                    return NULL;
+                }
+                u1 byte3 = *(data++);
+                if ((byte3 & 0xc0) != 0x80) {
+                    LOGE("Illegal continuation byte %#x", byte3);
+                    return NULL;
+                }
+                u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
+                    | (byte3 & 0x3f);
+                if (value < 0x800) {
+                    LOGE("Illegal representation for value %x", value);
+                    return NULL;
+                }
+                break;
+            }
+            case 0x0c:
+            case 0x0d: {
+                // Bit pattern 110x, so there is one additional byte.
+                u1 byte2 = *(data++);
+                if ((byte2 & 0xc0) != 0x80) {
+                    LOGE("Illegal continuation byte %#x", byte2);
+                    return NULL;
+                }
+                u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
+                if ((value != 0) && (value < 0x80)) {
+                    LOGE("Illegal representation for value %x", value);
+                    return NULL;
+                }
+                break;
+            }
+        }
+    }
+
+    if (*(data++) != '\0') {
+        LOGE("String longer than indicated utf16_size %#x", utf16Size);
+        return NULL;
+    }
+
+    return (void*) data;
+}
+
+/* Perform intra-item verification on debug_info_item. */
+static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
+    const u1* fileEnd = state->fileEnd;
+    const u1* data = (const u1*) ptr;
+    bool okay = true;
+    u4 i;
+
+    readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+    if (!okay) {
+        LOGE("Bogus line_start");
+        return NULL;
+    }
+
+    u4 parametersSize =
+        readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+    if (!okay) {
+        LOGE("Bogus parameters_size");
+        return NULL;
+    }
+
+    if (parametersSize > 65536) {
+        LOGE("Invalid parameters_size: %#x", parametersSize);
+        return NULL;
+    }
+
+    for (i = 0; i < parametersSize; i++) {
+        u4 parameterName =
+            readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+        if (!okay) {
+            LOGE("Bogus parameter_name");
+            return NULL;
+        }
+
+        if (parameterName != 0) {
+            parameterName--;
+            CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
+        }
+    }
+
+    bool done = false;
+    while (!done) {
+        u1 opcode = *(data++);
+
+        switch (opcode) {
+            case DBG_END_SEQUENCE: {
+                done = true;
+                break;
+            }
+            case DBG_ADVANCE_PC: {
+                readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                break;
+            }
+            case DBG_ADVANCE_LINE: {
+                readAndVerifySignedLeb128(&data, fileEnd, &okay);
+                break;
+            }
+            case DBG_START_LOCAL: {
+                u4 idx;
+                u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (regNum >= 65536) {
+                    okay = false;
+                    break;
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                break;
+            }
+            case DBG_END_LOCAL:
+            case DBG_RESTART_LOCAL: {
+                u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (regNum >= 65536) {
+                    okay = false;
+                    break;
+                }
+                break;
+            }
+            case DBG_START_LOCAL_EXTENDED: {
+                u4 idx;
+                u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (regNum >= 65536) {
+                    okay = false;
+                    break;
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                break;
+            }
+            case DBG_SET_FILE: {
+                u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+                if (!okay) break;
+                if (idx != 0) {
+                    idx--;
+                    CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+                }
+                break;
+            }
+            default: {
+                // No arguments to parse for anything else.
+            }
+        }
+
+        if (!okay) {
+            LOGE("Bogus syntax for opcode %02x", opcode);
+            return NULL;
+        }
+    }
+
+    return (void*) data;
+}
+
+/* defined below */
+static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
+        bool crossVerify);
+static const u1* verifyEncodedAnnotation(const CheckState* state,
+        const u1* data, bool crossVerify);
+
+/* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
+ * little endian value. */
+static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
+        u4 size) {
+    const u1* data = *pData;
+    u4 result = 0;
+    u4 i;
+
+    CHECK_PTR_RANGE(data, data + size);
+
+    for (i = 0; i < size; i++) {
+        result |= ((u4) *(data++)) << (i * 8);
+    }
+
+    *pData = data;
+    return result;
+}
+
+/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
+ * verifies an encoded_array. */
+static const u1* verifyEncodedArray(const CheckState* state,
+        const u1* data, bool crossVerify) {
+    bool okay = true;
+    u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
+
+    if (!okay) {
+        LOGE("Bogus encoded_array size");
+        return NULL;
+    }
+
+    while (size--) {
+        data = verifyEncodedValue(state, data, crossVerify);
+        if (data == NULL) {
+            LOGE("Bogus encoded_array value");
+            return NULL;
+        }
+    }
+
+    return data;
+}
+
+/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
+ * verifies an encoded_value. */
+static const u1* verifyEncodedValue(const CheckState* state,
+        const u1* data, bool crossVerify) {
+    CHECK_PTR_RANGE(data, data + 1);
+
+    u1 headerByte = *(data++);
+    u4 valueType = headerByte & kDexAnnotationValueTypeMask;
+    u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
+
+    switch (valueType) {
+        case kDexAnnotationByte: {
+            if (valueArg != 0) {
+                LOGE("Bogus byte size %#x", valueArg);
+                return NULL;
+            }
+            data++;
+            break;
+        }
+        case kDexAnnotationShort:
+        case kDexAnnotationChar: {
+            if (valueArg > 1) {
+                LOGE("Bogus char/short size %#x", valueArg);
+                return NULL;
+            }
+            data += valueArg + 1;
+            break;
+        }
+        case kDexAnnotationInt:
+        case kDexAnnotationFloat: {
+            if (valueArg > 3) {
+                LOGE("Bogus int/float size %#x", valueArg);
+                return NULL;
+            }
+            data += valueArg + 1;
+            break;
+        }
+        case kDexAnnotationLong:
+        case kDexAnnotationDouble: {
+            data += valueArg + 1;
+            break;
+        }
+        case kDexAnnotationString: {
+            if (valueArg > 3) {
+                LOGE("Bogus string size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+            break;
+        }
+        case kDexAnnotationType: {
+            if (valueArg > 3) {
+                LOGE("Bogus type size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->typeIdsSize);
+            break;
+        }
+        case kDexAnnotationField:
+        case kDexAnnotationEnum: {
+            if (valueArg > 3) {
+                LOGE("Bogus field/enum size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
+            break;
+        }
+        case kDexAnnotationMethod: {
+            if (valueArg > 3) {
+                LOGE("Bogus method size %#x", valueArg);
+                return NULL;
+            }
+            u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
+            CHECK_INDEX(idx, state->pHeader->methodIdsSize);
+            break;
+        }
+        case kDexAnnotationArray: {
+            if (valueArg != 0) {
+                LOGE("Bogus array value_arg %#x", valueArg);
+                return NULL;
+            }
+            data = verifyEncodedArray(state, data, crossVerify);
+            break;
+        }
+        case kDexAnnotationAnnotation: {
+            if (valueArg != 0) {
+                LOGE("Bogus annotation value_arg %#x", valueArg);
+                return NULL;
+            }
+            data = verifyEncodedAnnotation(state, data, crossVerify);
+            break;
+        }
+        case kDexAnnotationNull: {
+            if (valueArg != 0) {
+                LOGE("Bogus null value_arg %#x", valueArg);
+                return NULL;
+            }
+            // Nothing else to do for this type.
+            break;
+        }
+        case kDexAnnotationBoolean: {
+            if (valueArg > 1) {
+                LOGE("Bogus boolean value_arg %#x", valueArg);
+                return NULL;
+            }
+            // Nothing else to do for this type.
+            break;
+        }
+        default: {
+            LOGE("Bogus value_type %#x", valueType);
+            return NULL;
+        }
+    }
+
+    return data;
+}
+
+/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
+ * verifies an encoded_annotation. */
+static const u1* verifyEncodedAnnotation(const CheckState* state,
+        const u1* data, bool crossVerify) {
+    const u1* fileEnd = state->fileEnd;
+    bool okay = true;
+    u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+    if (!okay) {
+        LOGE("Bogus encoded_annotation type_idx");
+        return NULL;
+    }
+
+    CHECK_INDEX(idx, state->pHeader->typeIdsSize);
+
+    if (crossVerify) {
+        const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
+        if (!dexIsClassDescriptor(descriptor)) {
+            LOGE("Bogus annotation type: '%s'", descriptor);
+            return NULL;
+        }
+    }
+
+    u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+    u4 lastIdx = 0;
+    bool first = true;
+
+    if (!okay) {
+        LOGE("Bogus encoded_annotation size");
+        return NULL;
+    }
+
+    while (size--) {
+        idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
+
+        if (!okay) {
+            LOGE("Bogus encoded_annotation name_idx");
+            return NULL;
+        }
+
+        CHECK_INDEX(idx, state->pHeader->stringIdsSize);
+
+        if (crossVerify) {
+            const char* name = dexStringById(state->pDexFile, idx);
+            if (!dexIsValidMemberName(name)) {
+                LOGE("Bogus annotation member name: '%s'", name);
+                return NULL;
+            }
+        }
+
+        if (first) {
+            first = false;
+        } else if (lastIdx >= idx) {
+            LOGE("Out-of-order encoded_annotation name_idx: %#x then %#x",
+                    lastIdx, idx);
+            return NULL;
+        }
+
+        data = verifyEncodedValue(state, data, crossVerify);
+        lastIdx = idx;
+
+        if (data == NULL) {
+            return NULL;
+        }
+    }
+
+    return data;
+}
+
+/* Perform intra-item verification on encoded_array_item. */
+static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
+    return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
+}
+
+/* Perform intra-item verification on annotation_item. */
+static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+
+    CHECK_PTR_RANGE(data, data + 1);
+
+    switch (*(data++)) {
+        case kDexVisibilityBuild:
+        case kDexVisibilityRuntime:
+        case kDexVisibilitySystem: {
+            break;
+        }
+        default: {
+            LOGE("Bogus annotation visibility: %#x", *data);
+            return NULL;
+        }
+    }
+
+    return (void*) verifyEncodedAnnotation(state, data, false);
+}
+
+/* Perform cross-item verification on annotation_item. */
+static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
+    const u1* data = (const u1*) ptr;
+
+    // Skip the visibility byte.
+    data++;
+
+    return (void*) verifyEncodedAnnotation(state, data, true);
+}
+
+
+
+
+/*
+ * Function to visit an individual top-level item type.
+ */
+typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
+
+/*
+ * Iterate over all the items in a section, optionally updating the
+ * data map (done if mapType is passed as non-negative). The section
+ * must consist of concatenated items of the same type.
+ */
+static bool iterateSectionWithOptionalUpdate(CheckState* state,
+        u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
+        u4* nextOffset, int mapType) {
+    u4 alignmentMask = alignment - 1;
+    u4 i;
+
+    state->previousItem = NULL;
+
+    for (i = 0; i < count; i++) {
+        u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
+        u1* ptr = (u1*) filePointer(state, newOffset);
+
+        if (offset < newOffset) {
+            ptr = (u1*) filePointer(state, offset);
+            if (offset < newOffset) {
+                CHECK_OFFSET_RANGE(offset, newOffset);
+                while (offset < newOffset) {
+                    if (*ptr != '\0') {
+                        LOGE("Non-zero padding 0x%02x @ %x", *ptr, offset);
+                        return false;
+                    }
+                    ptr++;
+                    offset++;
+                }
+            }
+        }
+
+        u1* newPtr = (u1*) func(state, ptr);
+        newOffset = fileOffset(state, newPtr);
+
+        if (newPtr == NULL) {
+            LOGE("Trouble with item %d @ offset %#x", i, offset);
+            return false;
+        }
+
+        if (newOffset > state->fileLen) {
+            LOGE("Item %d @ offset %#x ends out of bounds", i, offset);
+            return false;
+        }
+
+        if (mapType >= 0) {
+            dexDataMapAdd(state->pDataMap, offset, mapType);
+        }
+
+        state->previousItem = ptr;
+        offset = newOffset;
+    }
+
+    if (nextOffset != NULL) {
+        *nextOffset = offset;
+    }
+
+    return true;
+}
+
+/*
+ * Iterate over all the items in a section. The section must consist of
+ * concatenated items of the same type. This variant will not update the data
+ * map.
+ */
+static bool iterateSection(CheckState* state, u4 offset, u4 count,
+        ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
+    return iterateSectionWithOptionalUpdate(state, offset, count, func,
+            alignment, nextOffset, -1);
+}
+
+/*
+ * Like iterateSection(), but also check that the offset and count match
+ * a given pair of expected values.
+ */
+static bool checkBoundsAndIterateSection(CheckState* state,
+        u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
+        ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
+    if (offset != expectedOffset) {
+        LOGE("Bogus offset for section: got %#x; expected %#x",
+                offset, expectedOffset);
+        return false;
+    }
+
+    if (count != expectedCount) {
+        LOGE("Bogus size for section: got %#x; expected %#x",
+                count, expectedCount);
+        return false;
+    }
+
+    return iterateSection(state, offset, count, func, alignment, nextOffset);
+}
+
+/*
+ * Like iterateSection(), but also update the data section map and
+ * check that all the items fall within the data section.
+ */
+static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
+        ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
+    u4 dataStart = state->pHeader->dataOff;
+    u4 dataEnd = dataStart + state->pHeader->dataSize;
+
+    assert(nextOffset != NULL);
+
+    if ((offset < dataStart) || (offset >= dataEnd)) {
+        LOGE("Bogus offset for data subsection: %#x", offset);
+        return false;
+    }
+
+    if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
+                    alignment, nextOffset, mapType)) {
+        return false;
+    }
+
+    if (*nextOffset > dataEnd) {
+        LOGE("Out-of-bounds end of data subsection: %#x", *nextOffset);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Byte-swap all items in the given map except the header and the map
+ * itself, both of which should have already gotten swapped. This also
+ * does all possible intra-item verification, that is, verification
+ * that doesn't need to assume the sanctity of the contents of *other*
+ * items. The intra-item limitation is because at the time an item is
+ * asked to verify itself, it can't assume that the items it refers to
+ * have been byte-swapped and verified.
+ */
+static bool swapEverythingButHeaderAndMap(CheckState* state,
+        DexMapList* pMap) {
+    const DexMapItem* item = pMap->list;
+    u4 lastOffset = 0;
+    u4 count = pMap->size;
+    bool okay = true;
+
+    while (okay && count--) {
+        u4 sectionOffset = item->offset;
+        u4 sectionCount = item->size;
+        u2 type = item->type;
+
+        if (lastOffset < sectionOffset) {
+            CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
+            const u1* ptr = (const u1*) filePointer(state, lastOffset);
+            while (lastOffset < sectionOffset) {
+                if (*ptr != '\0') {
+                    LOGE("Non-zero padding 0x%02x before section start @ %x",
+                            *ptr, lastOffset);
+                    okay = false;
+                    break;
+                }
+                ptr++;
+                lastOffset++;
+            }
+        } else if (lastOffset > sectionOffset) {
+            LOGE("Section overlap or out-of-order map: %x, %x",
+                    lastOffset, sectionOffset);
+            okay = false;
+        }
+
+        if (!okay) {
+            break;
+        }
+
+        switch (type) {
+            case kDexTypeHeaderItem: {
+                /*
+                 * The header got swapped very early on, but do some
+                 * additional sanity checking here.
+                 */
+                okay = checkHeaderSection(state, sectionOffset, sectionCount,
+                        &lastOffset);
+                break;
+            }
+            case kDexTypeStringIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->stringIdsOff,
+                        state->pHeader->stringIdsSize, swapStringIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeTypeIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->typeIdsOff,
+                        state->pHeader->typeIdsSize, swapTypeIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeProtoIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->protoIdsOff,
+                        state->pHeader->protoIdsSize, swapProtoIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeFieldIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->fieldIdsOff,
+                        state->pHeader->fieldIdsSize, swapFieldIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeMethodIdItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->methodIdsOff,
+                        state->pHeader->methodIdsSize, swapMethodIdItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeClassDefItem: {
+                okay = checkBoundsAndIterateSection(state, sectionOffset,
+                        sectionCount, state->pHeader->classDefsOff,
+                        state->pHeader->classDefsSize, swapClassDefItem,
+                        sizeof(u4), &lastOffset);
+                break;
+            }
+            case kDexTypeMapList: {
+                /*
+                 * The map section was swapped early on, but do some
+                 * additional sanity checking here.
+                 */
+                okay = checkMapSection(state, sectionOffset, sectionCount,
+                        &lastOffset);
+                break;
+            }
+            case kDexTypeTypeList: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapTypeList, sizeof(u4), &lastOffset, type);
+                break;
+            }
+            case kDexTypeAnnotationSetRefList: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapAnnotationSetRefList, sizeof(u4), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeAnnotationSetItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
+                break;
+            }
+            case kDexTypeClassDataItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyClassDataItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeCodeItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapCodeItem, sizeof(u4), &lastOffset, type);
+                break;
+            }
+            case kDexTypeStringDataItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyStringDataItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeDebugInfoItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeAnnotationItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeEncodedArrayItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
+                        type);
+                break;
+            }
+            case kDexTypeAnnotationsDirectoryItem: {
+                okay = iterateDataSection(state, sectionOffset, sectionCount,
+                        swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
+                        type);
+                break;
+            }
+            default: {
+                LOGE("Unknown map item type %04x", type);
+                return false;
+            }
+        }
+
+        if (!okay) {
+            LOGE("Swap of section type %04x failed", type);
+        }
+
+        item++;
+    }
+
+    return okay;
+}
+
+/*
+ * Perform cross-item verification on everything that needs it. This
+ * pass is only called after all items are byte-swapped and
+ * intra-verified (checked for internal consistency).
+ */
+static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
+{
+    const DexMapItem* item = pMap->list;
+    u4 count = pMap->size;
+    bool okay = true;
+
+    while (okay && count--) {
+        u4 sectionOffset = item->offset;
+        u4 sectionCount = item->size;
+
+        switch (item->type) {
+            case kDexTypeHeaderItem:
+            case kDexTypeMapList:
+            case kDexTypeTypeList:
+            case kDexTypeCodeItem:
+            case kDexTypeStringDataItem:
+            case kDexTypeDebugInfoItem:
+            case kDexTypeAnnotationItem:
+            case kDexTypeEncodedArrayItem: {
+                // There is no need for cross-item verification for these.
+                break;
+            }
+            case kDexTypeStringIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyStringIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeTypeIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyTypeIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeProtoIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyProtoIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeFieldIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyFieldIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeMethodIdItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyMethodIdItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeClassDefItem: {
+                // Allocate (on the stack) the "observed class_def" bits.
+                size_t arraySize = calcDefinedClassBitsSize(state);
+                u4 definedClassBits[arraySize];
+                memset(definedClassBits, 0, arraySize * sizeof(u4));
+                state->pDefinedClassBits = definedClassBits;
+
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyClassDefItem, sizeof(u4), NULL);
+
+                state->pDefinedClassBits = NULL;
+                break;
+            }
+            case kDexTypeAnnotationSetRefList: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeAnnotationSetItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyAnnotationSetItem, sizeof(u4), NULL);
+                break;
+            }
+            case kDexTypeClassDataItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyClassDataItem, sizeof(u1), NULL);
+                break;
+            }
+            case kDexTypeAnnotationsDirectoryItem: {
+                okay = iterateSection(state, sectionOffset, sectionCount,
+                        crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
+                break;
+            }
+            default: {
+                LOGE("Unknown map item type %04x", item->type);
+                return false;
+            }
+        }
+
+        if (!okay) {
+            LOGE("Cross-item verify of section type %04x failed",
+                    item->type);
+        }
+
+        item++;
+    }
+
+    return okay;
+}
+
+/* (documented in header file) */
+bool dexHasValidMagic(const DexHeader* pHeader)
+{
+    const u1* magic = pHeader->magic;
+    const u1* version = &magic[4];
+
+    if (memcmp(magic, DEX_MAGIC, 4) != 0) {
+        LOGE("ERROR: unrecognized magic number (%02x %02x %02x %02x)",
+            magic[0], magic[1], magic[2], magic[3]);
+        return false;
+    }
+
+    if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
+            (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0)) {
+        /*
+         * Magic was correct, but this is an unsupported older or
+         * newer format variant.
+         */
+        LOGE("ERROR: unsupported dex version (%02x %02x %02x %02x)",
+            version[0], version[1], version[2], version[3]);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Fix the byte ordering of all fields in the DEX file, and do
+ * structural verification. This is only required for code that opens
+ * "raw" DEX files, such as the DEX optimizer.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+int dexSwapAndVerify(u1* addr, int len)
+{
+    DexHeader* pHeader;
+    CheckState state;
+    bool okay = true;
+
+    memset(&state, 0, sizeof(state));
+    LOGV("+++ swapping and verifying");
+
+    /*
+     * Note: The caller must have verified that "len" is at least as
+     * large as a dex file header.
+     */
+    pHeader = (DexHeader*) addr;
+
+    if (!dexHasValidMagic(pHeader)) {
+        okay = false;
+    }
+
+    if (okay) {
+        int expectedLen = (int) SWAP4(pHeader->fileSize);
+        if (len < expectedLen) {
+            LOGE("ERROR: Bad length: expected %d, got %d", expectedLen, len);
+            okay = false;
+        } else if (len != expectedLen) {
+            LOGW("WARNING: Odd length: expected %d, got %d", expectedLen,
+                    len);
+            // keep going
+        }
+    }
+
+    if (okay) {
+        /*
+         * Compute the adler32 checksum and compare it to what's stored in
+         * the file.  This isn't free, but chances are good that we just
+         * unpacked this from a jar file and have all of the pages sitting
+         * in memory, so it's pretty quick.
+         *
+         * This might be a big-endian system, so we need to do this before
+         * we byte-swap the header.
+         */
+        uLong adler = adler32(0L, Z_NULL, 0);
+        const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
+        u4 storedFileSize = SWAP4(pHeader->fileSize);
+        u4 expectedChecksum = SWAP4(pHeader->checksum);
+
+        adler = adler32(adler, ((const u1*) pHeader) + nonSum,
+                    storedFileSize - nonSum);
+
+        if (adler != expectedChecksum) {
+            LOGE("ERROR: bad checksum (%08lx, expected %08x)",
+                adler, expectedChecksum);
+            okay = false;
+        }
+    }
+
+    if (okay) {
+        state.fileStart = addr;
+        state.fileEnd = addr + len;
+        state.fileLen = len;
+        state.pDexFile = NULL;
+        state.pDataMap = NULL;
+        state.pDefinedClassBits = NULL;
+        state.previousItem = NULL;
+
+        /*
+         * Swap the header and check the contents.
+         */
+        okay = swapDexHeader(&state, pHeader);
+    }
+
+    if (okay) {
+        state.pHeader = pHeader;
+
+        if (pHeader->headerSize < sizeof(DexHeader)) {
+            LOGE("ERROR: Small header size %d, struct %d",
+                    pHeader->headerSize, (int) sizeof(DexHeader));
+            okay = false;
+        } else if (pHeader->headerSize > sizeof(DexHeader)) {
+            LOGW("WARNING: Large header size %d, struct %d",
+                    pHeader->headerSize, (int) sizeof(DexHeader));
+            // keep going?
+        }
+    }
+
+    if (okay) {
+        /*
+         * Look for the map. Swap it and then use it to find and swap
+         * everything else.
+         */
+        if (pHeader->mapOff != 0) {
+            DexFile dexFile;
+            DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
+
+            okay = okay && swapMap(&state, pDexMap);
+            okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
+
+            dexFileSetupBasicPointers(&dexFile, addr);
+            state.pDexFile = &dexFile;
+
+            okay = okay && crossVerifyEverything(&state, pDexMap);
+        } else {
+            LOGE("ERROR: No map found; impossible to byte-swap and verify");
+            okay = false;
+        }
+    }
+
+    if (!okay) {
+        LOGE("ERROR: Byte swap + verify failed");
+    }
+
+    if (state.pDataMap != NULL) {
+        dexDataMapFree(state.pDataMap);
+    }
+
+    return !okay;       // 0 == success
+}
+
+/*
+ * Detect the file type of the given memory buffer via magic number.
+ * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
+ * but return successfully on an optimized DEX file, and report an
+ * error for all other cases.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+int dexSwapAndVerifyIfNecessary(u1* addr, int len)
+{
+    if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
+        // It is an optimized dex file.
+        return 0;
+    }
+
+    if (memcmp(addr, DEX_MAGIC, 4) == 0) {
+        // It is an unoptimized dex file.
+        return dexSwapAndVerify(addr, len);
+    }
+
+    LOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)",
+             addr[0], addr[1], addr[2], addr[3]);
+
+    return 1;
+}
diff --git a/libdex/DexUtf.cpp b/libdex/DexUtf.cpp
new file mode 100644
index 0000000..df49d18
--- /dev/null
+++ b/libdex/DexUtf.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*
+ * Validate and manipulate MUTF-8 encoded string data.
+ */
+
+#include "DexUtf.h"
+
+/* Compare two '\0'-terminated modified UTF-8 strings, using Unicode
+ * code point values for comparison. This treats different encodings
+ * for the same code point as equivalent, except that only a real '\0'
+ * byte is considered the string terminator. The return value is as
+ * for strcmp(). */
+int dexUtf8Cmp(const char* s1, const char* s2) {
+    for (;;) {
+        if (*s1 == '\0') {
+            if (*s2 == '\0') {
+                return 0;
+            }
+            return -1;
+        } else if (*s2 == '\0') {
+            return 1;
+        }
+
+        int utf1 = dexGetUtf16FromUtf8(&s1);
+        int utf2 = dexGetUtf16FromUtf8(&s2);
+        int diff = utf1 - utf2;
+
+        if (diff != 0) {
+            return diff;
+        }
+    }
+}
+
+/* for dexIsValidMemberNameUtf8(), a bit vector indicating valid low ascii */
+u4 DEX_MEMBER_VALID_LOW_ASCII[4] = {
+    0x00000000, // 00..1f low control characters; nothing valid
+    0x03ff2010, // 20..3f digits and symbols; valid: '0'..'9', '$', '-'
+    0x87fffffe, // 40..5f uppercase etc.; valid: 'A'..'Z', '_'
+    0x07fffffe  // 60..7f lowercase etc.; valid: 'a'..'z'
+};
+
+/* Helper for dexIsValidMemberNameUtf8(); do not call directly. */
+bool dexIsValidMemberNameUtf8_0(const char** pUtf8Ptr) {
+    /*
+     * It's a multibyte encoded character. Decode it and analyze. We
+     * accept anything that isn't (a) an improperly encoded low value,
+     * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high
+     * control character, or (e) a high space, layout, or special
+     * character (U+00a0, U+2000..U+200f, U+2028..U+202f,
+     * U+fff0..U+ffff). This is all specified in the dex format
+     * document.
+     */
+
+    u2 utf16 = dexGetUtf16FromUtf8(pUtf8Ptr);
+
+    // Perform follow-up tests based on the high 8 bits.
+    switch (utf16 >> 8) {
+        case 0x00: {
+            // It's only valid if it's above the ISO-8859-1 high space (0xa0).
+            return (utf16 > 0x00a0);
+        }
+        case 0xd8:
+        case 0xd9:
+        case 0xda:
+        case 0xdb: {
+            /*
+             * It's a leading surrogate. Check to see that a trailing
+             * surrogate follows.
+             */
+            utf16 = dexGetUtf16FromUtf8(pUtf8Ptr);
+            return (utf16 >= 0xdc00) && (utf16 <= 0xdfff);
+        }
+        case 0xdc:
+        case 0xdd:
+        case 0xde:
+        case 0xdf: {
+            // It's a trailing surrogate, which is not valid at this point.
+            return false;
+        }
+        case 0x20:
+        case 0xff: {
+            // It's in the range that has spaces, controls, and specials.
+            switch (utf16 & 0xfff8) {
+                case 0x2000:
+                case 0x2008:
+                case 0x2028:
+                case 0xfff0:
+                case 0xfff8: {
+                    return false;
+                }
+            }
+            break;
+        }
+    }
+
+    return true;
+}
+
+/* Return whether the given string is a valid field or method name. */
+bool dexIsValidMemberName(const char* s) {
+    bool angleName = false;
+
+    switch (*s) {
+        case '\0': {
+            // The empty string is not a valid name.
+            return false;
+        }
+        case '<': {
+            /*
+             * '<' is allowed only at the start of a name, and if present,
+             * means that the name must end with '>'.
+             */
+            angleName = true;
+            s++;
+            break;
+        }
+    }
+
+    for (;;) {
+        switch (*s) {
+            case '\0': {
+                return !angleName;
+            }
+            case '>': {
+                return angleName && s[1] == '\0';
+            }
+        }
+        if (!dexIsValidMemberNameUtf8(&s)) {
+            return false;
+        }
+    }
+}
+
+/* Helper for validating type descriptors and class names, which is parametric
+ * with respect to type vs. class and dot vs. slash. */
+static bool isValidTypeDescriptorOrClassName(const char* s, bool isClassName,
+        bool dotSeparator) {
+    int arrayCount = 0;
+
+    while (*s == '[') {
+        arrayCount++;
+        s++;
+    }
+
+    if (arrayCount > 255) {
+        // Arrays may have no more than 255 dimensions.
+        return false;
+    }
+
+    if (arrayCount != 0) {
+        /*
+         * If we're looking at an array of some sort, then it doesn't
+         * matter if what is being asked for is a class name; the
+         * format looks the same as a type descriptor in that case, so
+         * treat it as such.
+         */
+        isClassName = false;
+    }
+
+    if (!isClassName) {
+        /*
+         * We are looking for a descriptor. Either validate it as a
+         * single-character primitive type, or continue on to check the
+         * embedded class name (bracketed by "L" and ";").
+         */
+        switch (*(s++)) {
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'F':
+            case 'I':
+            case 'J':
+            case 'S':
+            case 'Z': {
+                // These are all single-character descriptors for primitive types.
+                return (*s == '\0');
+            }
+            case 'V': {
+                // Non-array void is valid, but you can't have an array of void.
+                return (arrayCount == 0) && (*s == '\0');
+            }
+            case 'L': {
+                // Class name: Break out and continue below.
+                break;
+            }
+            default: {
+                // Oddball descriptor character.
+                return false;
+            }
+        }
+    }
+
+    /*
+     * We just consumed the 'L' that introduces a class name as part
+     * of a type descriptor, or we are looking for an unadorned class
+     * name.
+     */
+
+    bool sepOrFirst = true; // first character or just encountered a separator.
+    for (;;) {
+        u1 c = (u1) *s;
+        switch (c) {
+            case '\0': {
+                /*
+                 * Premature end for a type descriptor, but valid for
+                 * a class name as long as we haven't encountered an
+                 * empty component (including the degenerate case of
+                 * the empty string "").
+                 */
+                return isClassName && !sepOrFirst;
+            }
+            case ';': {
+                /*
+                 * Invalid character for a class name, but the
+                 * legitimate end of a type descriptor. In the latter
+                 * case, make sure that this is the end of the string
+                 * and that it doesn't end with an empty component
+                 * (including the degenerate case of "L;").
+                 */
+                return !isClassName && !sepOrFirst && (s[1] == '\0');
+            }
+            case '/':
+            case '.': {
+                if (dotSeparator != (c == '.')) {
+                    // The wrong separator character.
+                    return false;
+                }
+                if (sepOrFirst) {
+                    // Separator at start or two separators in a row.
+                    return false;
+                }
+                sepOrFirst = true;
+                s++;
+                break;
+            }
+            default: {
+                if (!dexIsValidMemberNameUtf8(&s)) {
+                    return false;
+                }
+                sepOrFirst = false;
+                break;
+            }
+        }
+    }
+}
+
+/* Return whether the given string is a valid type descriptor. */
+bool dexIsValidTypeDescriptor(const char* s) {
+    return isValidTypeDescriptorOrClassName(s, false, false);
+}
+
+/* (documented in header) */
+bool dexIsValidClassName(const char* s, bool dotSeparator) {
+    return isValidTypeDescriptorOrClassName(s, true, dotSeparator);
+}
+
+/* Return whether the given string is a valid reference descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class or array and not a primitive type. */
+bool dexIsReferenceDescriptor(const char* s) {
+    if (!dexIsValidTypeDescriptor(s)) {
+        return false;
+    }
+
+    return (s[0] == 'L') || (s[0] == '[');
+}
+
+/* Return whether the given string is a valid class descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class and not an array or primitive type. */
+bool dexIsClassDescriptor(const char* s) {
+    if (!dexIsValidTypeDescriptor(s)) {
+        return false;
+    }
+
+    return s[0] == 'L';
+}
+
+/* Return whether the given string is a valid field type descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for anything but "void". */
+bool dexIsFieldDescriptor(const char* s) {
+    if (!dexIsValidTypeDescriptor(s)) {
+        return false;
+    }
+
+    return s[0] != 'V';
+}
+
diff --git a/libdex/DexUtf.h b/libdex/DexUtf.h
new file mode 100644
index 0000000..cb3d919
--- /dev/null
+++ b/libdex/DexUtf.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*
+ * Validate and manipulate MUTF-8 (modified UTF-8) encoded string data.
+ */
+
+#ifndef LIBDEX_DEXUTF_H_
+#define LIBDEX_DEXUTF_H_
+
+#include "DexFile.h"
+
+/*
+ * Retrieve the next UTF-16 character from a UTF-8 string.
+ *
+ * Advances "*pUtf8Ptr" to the start of the next character.
+ *
+ * WARNING: If a string is corrupted by dropping a '\0' in the middle
+ * of a 3-byte sequence, you can end up overrunning the buffer with
+ * reads (and possibly with the writes if the length was computed and
+ * cached before the damage). For performance reasons, this function
+ * assumes that the string being parsed is known to be valid (e.g., by
+ * already being verified). Most strings we process here are coming
+ * out of dex files or other internal translations, so the only real
+ * risk comes from the JNI NewStringUTF call.
+ */
+DEX_INLINE u2 dexGetUtf16FromUtf8(const char** pUtf8Ptr)
+{
+    unsigned int one, two, three;
+
+    one = *(*pUtf8Ptr)++;
+    if ((one & 0x80) != 0) {
+        /* two- or three-byte encoding */
+        two = *(*pUtf8Ptr)++;
+        if ((one & 0x20) != 0) {
+            /* three-byte encoding */
+            three = *(*pUtf8Ptr)++;
+            return ((one & 0x0f) << 12) |
+                   ((two & 0x3f) << 6) |
+                   (three & 0x3f);
+        } else {
+            /* two-byte encoding */
+            return ((one & 0x1f) << 6) |
+                   (two & 0x3f);
+        }
+    } else {
+        /* one-byte encoding */
+        return one;
+    }
+}
+
+/* Compare two '\0'-terminated modified UTF-8 strings, using Unicode
+ * code point values for comparison. This treats different encodings
+ * for the same code point as equivalent, except that only a real '\0'
+ * byte is considered the string terminator. The return value is as
+ * for strcmp(). */
+int dexUtf8Cmp(const char* s1, const char* s2);
+
+/* for dexIsValidMemberNameUtf8(), a bit vector indicating valid low ascii */
+extern u4 DEX_MEMBER_VALID_LOW_ASCII[4];
+
+/* Helper for dexIsValidMemberUtf8(); do not call directly. */
+bool dexIsValidMemberNameUtf8_0(const char** pUtf8Ptr);
+
+/* Return whether the pointed-at modified-UTF-8 encoded character is
+ * valid as part of a member name, updating the pointer to point past
+ * the consumed character. This will consume two encoded UTF-16 code
+ * points if the character is encoded as a surrogate pair. Also, if
+ * this function returns false, then the given pointer may only have
+ * been partially advanced. */
+DEX_INLINE bool dexIsValidMemberNameUtf8(const char** pUtf8Ptr) {
+    u1 c = (u1) **pUtf8Ptr;
+    if (c <= 0x7f) {
+        // It's low-ascii, so check the table.
+        u4 wordIdx = c >> 5;
+        u4 bitIdx = c & 0x1f;
+        (*pUtf8Ptr)++;
+        return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
+    }
+
+    /*
+     * It's a multibyte encoded character. Call a non-inline function
+     * for the heavy lifting.
+     */
+    return dexIsValidMemberNameUtf8_0(pUtf8Ptr);
+}
+
+/* Return whether the given string is a valid field or method name. */
+bool dexIsValidMemberName(const char* s);
+
+/* Return whether the given string is a valid type descriptor. */
+bool dexIsValidTypeDescriptor(const char* s);
+
+/* Return whether the given string is a valid internal-form class
+ * name, with components separated either by dots or slashes as
+ * specified. A class name is like a type descriptor, except that it
+ * can't name a primitive type (including void). In terms of syntax,
+ * the form is either (a) the name of the class without adornment
+ * (that is, not bracketed by "L" and ";"); or (b) identical to the
+ * type descriptor syntax for array types. */
+bool dexIsValidClassName(const char* s, bool dotSeparator);
+
+/* Return whether the given string is a valid reference descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class or array and not a primitive type. */
+bool dexIsReferenceDescriptor(const char* s);
+
+/* Return whether the given string is a valid class descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for a class and not an array or primitive type. */
+bool dexIsClassDescriptor(const char* s);
+
+/* Return whether the given string is a valid field type descriptor. This
+ * is true if dexIsValidTypeDescriptor() returns true and the descriptor
+ * is for anything but "void". */
+bool dexIsFieldDescriptor(const char* s);
+
+#endif  // LIBDEX_DEXUTF_H_
diff --git a/libdex/InstrUtils.cpp b/libdex/InstrUtils.cpp
new file mode 100644
index 0000000..59c22c7
--- /dev/null
+++ b/libdex/InstrUtils.cpp
@@ -0,0 +1,1109 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik instruction utility functions.
+ *
+ * IMPORTANT NOTE: Much of the contents of this file are generated
+ * automatically by the opcode-gen tool. Any edits to the generated
+ * sections will get wiped out the next time the tool is run.
+ */
+
+#include "InstrUtils.h"
+#include <stdlib.h>
+
+/*
+ * Table that maps each opcode to the full width of instructions that
+ * use that opcode, in (16-bit) code units. Unimplemented opcodes as
+ * well as the "breakpoint" opcode have a width of zero.
+ */
+static InstructionWidth gInstructionWidthTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-widths); GENERATED AUTOMATICALLY BY opcode-gen
+    1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 2, 3, 2, 2, 3, 5, 2, 2, 3, 2, 1, 1, 2,
+    2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+    0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
+    3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 3,
+    3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0,
+    4, 4, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4,
+    // END(libdex-widths)
+};
+
+/*
+ * Table that maps each opcode to the flags associated with that
+ * opcode.
+ */
+static u1 gOpcodeFlagsTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-flags); GENERATED AUTOMATICALLY BY opcode-gen
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanReturn,
+    kInstrCanReturn,
+    kInstrCanReturn,
+    kInstrCanReturn,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanThrow,
+    kInstrCanBranch,
+    kInstrCanBranch,
+    kInstrCanBranch,
+    kInstrCanContinue|kInstrCanSwitch,
+    kInstrCanContinue|kInstrCanSwitch,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    kInstrCanContinue|kInstrCanBranch,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    0,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    0,
+    0,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    0,
+    kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanReturn,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    0,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    kInstrCanContinue|kInstrCanThrow|kInstrInvoke,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanContinue|kInstrCanThrow,
+    kInstrCanThrow,
+    // END(libdex-flags)
+};
+
+/*
+ * Table that maps each opcode to the instruction format associated
+ * that opcode.
+ */
+static u1 gInstructionFormatTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-formats); GENERATED AUTOMATICALLY BY opcode-gen
+    kFmt10x,  kFmt12x,  kFmt22x,  kFmt32x,  kFmt12x,  kFmt22x,  kFmt32x,
+    kFmt12x,  kFmt22x,  kFmt32x,  kFmt11x,  kFmt11x,  kFmt11x,  kFmt11x,
+    kFmt10x,  kFmt11x,  kFmt11x,  kFmt11x,  kFmt11n,  kFmt21s,  kFmt31i,
+    kFmt21h,  kFmt21s,  kFmt31i,  kFmt51l,  kFmt21h,  kFmt21c,  kFmt31c,
+    kFmt21c,  kFmt11x,  kFmt11x,  kFmt21c,  kFmt22c,  kFmt12x,  kFmt21c,
+    kFmt22c,  kFmt35c,  kFmt3rc,  kFmt31t,  kFmt11x,  kFmt10t,  kFmt20t,
+    kFmt30t,  kFmt31t,  kFmt31t,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt22t,  kFmt22t,  kFmt22t,  kFmt22t,  kFmt22t,  kFmt22t,
+    kFmt21t,  kFmt21t,  kFmt21t,  kFmt21t,  kFmt21t,  kFmt21t,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt22c,  kFmt22c,
+    kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,
+    kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,
+    kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,
+    kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt21c,  kFmt35c,  kFmt35c,
+    kFmt35c,  kFmt35c,  kFmt35c,  kFmt00x,  kFmt3rc,  kFmt3rc,  kFmt3rc,
+    kFmt3rc,  kFmt3rc,  kFmt00x,  kFmt00x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,  kFmt23x,
+    kFmt23x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,
+    kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt12x,  kFmt22s,  kFmt22s,
+    kFmt22s,  kFmt22s,  kFmt22s,  kFmt22s,  kFmt22s,  kFmt22s,  kFmt22b,
+    kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,  kFmt22b,
+    kFmt22b,  kFmt22b,  kFmt22b,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,
+    kFmt22c,  kFmt22c,  kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,  kFmt20bc,
+    kFmt35mi, kFmt3rmi, kFmt35c,  kFmt10x,  kFmt22cs, kFmt22cs, kFmt22cs,
+    kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt35ms, kFmt3rms,
+    kFmt22c,  kFmt21c,  kFmt21c,  kFmt00x,  kFmt41c,  kFmt41c,  kFmt52c,
+    kFmt41c,  kFmt52c,  kFmt5rc,  kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,
+    kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,
+    kFmt52c,  kFmt52c,  kFmt52c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,
+    kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,
+    kFmt41c,  kFmt41c,  kFmt41c,  kFmt5rc,  kFmt5rc,  kFmt5rc,  kFmt5rc,
+    kFmt5rc,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,  kFmt00x,
+    kFmt00x,  kFmt5rc,  kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,  kFmt52c,
+    kFmt52c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,  kFmt41c,
+    kFmt40sc,
+    // END(libdex-formats)
+};
+
+/*
+ * Table that maps each opcode to the index type implied by that
+ * opcode.
+ */
+static u1 gInstructionIndexTypeTable[kNumPackedOpcodes] = {
+    // BEGIN(libdex-index-types); GENERATED AUTOMATICALLY BY opcode-gen
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexStringRef,
+    kIndexStringRef,    kIndexTypeRef,      kIndexNone,
+    kIndexNone,         kIndexTypeRef,      kIndexTypeRef,
+    kIndexNone,         kIndexTypeRef,      kIndexTypeRef,
+    kIndexTypeRef,      kIndexTypeRef,      kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexMethodRef,
+    kIndexMethodRef,    kIndexMethodRef,    kIndexMethodRef,
+    kIndexMethodRef,    kIndexUnknown,      kIndexMethodRef,
+    kIndexMethodRef,    kIndexMethodRef,    kIndexMethodRef,
+    kIndexMethodRef,    kIndexUnknown,      kIndexUnknown,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexNone,
+    kIndexNone,         kIndexNone,         kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexUnknown,
+    kIndexVaries,       kIndexInlineMethod, kIndexInlineMethod,
+    kIndexMethodRef,    kIndexNone,         kIndexFieldOffset,
+    kIndexFieldOffset,  kIndexFieldOffset,  kIndexFieldOffset,
+    kIndexFieldOffset,  kIndexFieldOffset,  kIndexVtableOffset,
+    kIndexVtableOffset, kIndexVtableOffset, kIndexVtableOffset,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexUnknown,      kIndexTypeRef,      kIndexTypeRef,
+    kIndexTypeRef,      kIndexTypeRef,      kIndexTypeRef,
+    kIndexTypeRef,      kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexMethodRef,
+    kIndexMethodRef,    kIndexMethodRef,    kIndexMethodRef,
+    kIndexMethodRef,    kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexUnknown,      kIndexUnknown,      kIndexUnknown,
+    kIndexMethodRef,    kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexFieldRef,     kIndexFieldRef,
+    kIndexFieldRef,     kIndexVaries,
+    // END(libdex-index-types)
+};
+
+/*
+ * Global InstructionInfoTables struct.
+ */
+InstructionInfoTables gDexOpcodeInfo = {
+    gInstructionFormatTable,
+    gInstructionIndexTypeTable,
+    gOpcodeFlagsTable,
+    gInstructionWidthTable
+};
+
+/*
+ * Handy macros for helping decode instructions.
+ */
+#define FETCH(_offset)      (insns[(_offset)])
+#define FETCH_u4(_offset)   (fetch_u4_impl((_offset), insns))
+#define INST_A(_inst)       (((u2)(_inst) >> 8) & 0x0f)
+#define INST_B(_inst)       ((u2)(_inst) >> 12)
+#define INST_AA(_inst)      ((_inst) >> 8)
+
+/* Helper for FETCH_u4, above. */
+static inline u4 fetch_u4_impl(u4 offset, const u2* insns) {
+    return insns[offset] | ((u4) insns[offset+1] << 16);
+}
+
+/*
+ * Decode the instruction pointed to by "insns".
+ *
+ * Fills out the pieces of "pDec" that are affected by the current
+ * instruction.  Does not touch anything else.
+ */
+void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec)
+{
+    u2 inst = *insns;
+    Opcode opcode = dexOpcodeFromCodeUnit(inst);
+    InstructionFormat format = dexGetFormatFromOpcode(opcode);
+
+    pDec->opcode = opcode;
+    pDec->indexType = dexGetIndexTypeFromOpcode(opcode);
+
+    switch (format) {
+    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
+        pDec->vA = INST_A(inst);
+        pDec->vB = INST_B(inst);
+        break;
+    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
+        pDec->vA = INST_AA(inst);
+        break;
+    case kFmt10t:       // op +AA
+        pDec->vA = (s1) INST_AA(inst);              // sign-extend 8-bit value
+        break;
+    case kFmt20t:       // op +AAAA
+        pDec->vA = (s2) FETCH(1);                   // sign-extend 16-bit value
+        break;
+    case kFmt20bc:      // [opt] 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
+        pDec->vA = INST_AA(inst);
+        pDec->vB = (s2) FETCH(1);                   // sign-extend 16-bit value
+        break;
+    case kFmt21h:       // op vAA, #+BBBB0000[00000000]
+        pDec->vA = INST_AA(inst);
+        /*
+         * The value should be treated as right-zero-extended, but we don't
+         * actually do that here. Among other things, we don't know if it's
+         * the top bits of a 32- or 64-bit value.
+         */
+        pDec->vB = FETCH(1);
+        break;
+    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
+        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
+        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
+        pDec->vA = INST_A(inst);
+        pDec->vB = INST_B(inst);
+        pDec->vC = FETCH(1);
+        break;
+    case kFmt30t:       // op +AAAAAAAA
+        pDec->vA = FETCH_u4(1);                     // signed 32-bit value
+        break;
+    case kFmt31t:       // op vAA, +BBBBBBBB
+    case kFmt31c:       // op vAA, string@BBBBBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH_u4(1);                     // 32-bit value
+        break;
+    case kFmt32x:       // op vAAAA, vBBBB
+        pDec->vA = FETCH(1);
+        pDec->vB = FETCH(2);
+        break;
+    case kFmt31i:       // op vAA, #+BBBBBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH_u4(1);                     // signed 32-bit value
+        break;
+    case kFmt35c:       // op {vC, vD, vE, vF, vG}, thing@BBBB
+    case kFmt35ms:      // [opt] invoke-virtual+super
+    case kFmt35mi:      // [opt] inline invoke
+        {
+            /*
+             * Note that the fields mentioned in the spec don't appear in
+             * their "usual" positions here compared to most formats. This
+             * was done so that the field names for the argument count and
+             * reference index match between this format and the corresponding
+             * range formats (3rc and friends).
+             *
+             * Bottom line: The argument count is always in vA, and the
+             * method constant (or equivalent) is always in vB.
+             */
+            u2 regList;
+            int i, count;
+
+            pDec->vA = INST_B(inst); // This is labeled A in the spec.
+            pDec->vB = FETCH(1);
+            regList = FETCH(2);
+
+            count = pDec->vA;
+
+            /*
+             * Copy the argument registers into the arg[] array, and
+             * also copy the first argument (if any) into vC. (The
+             * DecodedInstruction structure doesn't have separate
+             * fields for {vD, vE, vF, vG}, so there's no need to make
+             * copies of those.) Note that cases 5..2 fall through.
+             */
+            switch (count) {
+            case 5: {
+                if (format == kFmt35mi) {
+                    /* A fifth arg is verboten for inline invokes. */
+                    LOGW("Invalid arg count in 35mi (5)");
+                    goto bail;
+                }
+                /*
+                 * Per note at the top of this format decoder, the
+                 * fifth argument comes from the A field in the
+                 * instruction, but it's labeled G in the spec.
+                 */
+                pDec->arg[4] = INST_A(inst);
+            }
+            case 4: pDec->arg[3] = (regList >> 12) & 0x0f;
+            case 3: pDec->arg[2] = (regList >> 8) & 0x0f;
+            case 2: pDec->arg[1] = (regList >> 4) & 0x0f;
+            case 1: pDec->vC = pDec->arg[0] = regList & 0x0f; break;
+            case 0: break; // Valid, but no need to do anything.
+            default:
+                LOGW("Invalid arg count in 35c/35ms/35mi (%d)", count);
+                goto bail;
+            }
+        }
+        break;
+    case kFmt3rc:       // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
+    case kFmt3rms:      // [opt] invoke-virtual+super/range
+    case kFmt3rmi:      // [opt] execute-inline/range
+        pDec->vA = INST_AA(inst);
+        pDec->vB = FETCH(1);
+        pDec->vC = FETCH(2);
+        break;
+    case kFmt51l:       // op vAA, #+BBBBBBBBBBBBBBBB
+        pDec->vA = INST_AA(inst);
+        pDec->vB_wide = FETCH_u4(1) | ((u8) FETCH_u4(3) << 32);
+        break;
+    case kFmt33x:       // exop vAA, vBB, vCCCC
+        pDec->vA = FETCH(1) & 0xff;
+        pDec->vB = FETCH(1) >> 8;
+        pDec->vC = FETCH(2);
+        break;
+    case kFmt32s:       // exop vAA, vBB, #+CCCC
+        pDec->vA = FETCH(1) & 0xff;
+        pDec->vB = FETCH(1) >> 8;
+        pDec->vC = (s2) FETCH(2);                   // sign-extend 16-bit value
+        break;
+    case kFmt40sc:      // [opt] exop AAAA, thing@BBBBBBBB
+    case kFmt41c:       // exop vAAAA, thing@BBBBBBBB
+        /*
+         * The order of fields for this format in the spec is {B, A},
+         * to match formats 21c and 31c.
+         */
+        pDec->vB = FETCH_u4(1);                     // 32-bit value
+        pDec->vA = FETCH(3);
+        break;
+    case kFmt52c:       // exop vAAAA, vBBBB, thing@CCCCCCCC
+        /*
+         * The order of fields for this format in the spec is {C, A, B},
+         * to match formats 22c and 22cs.
+         */
+        pDec->vC = FETCH_u4(1);                     // 32-bit value
+        pDec->vA = FETCH(3);
+        pDec->vB = FETCH(4);
+        break;
+    case kFmt5rc:       // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
+        /*
+         * The order of fields for this format in the spec is {B, A, C},
+         * to match formats 3rc and friends.
+         */
+        pDec->vB = FETCH_u4(1);                     // 32-bit value
+        pDec->vA = FETCH(3);
+        pDec->vC = FETCH(4);
+        break;
+    default:
+        LOGW("Can't decode unexpected format %d (op=%d)", format, opcode);
+        assert(false);
+        break;
+    }
+
+bail:
+    ;
+}
+
+/*
+ * Return the width of the specified instruction, or 0 if not defined.  Also
+ * works for special OP_NOP entries, including switch statement data tables
+ * and array data.
+ */
+size_t dexGetWidthFromInstruction(const u2* insns)
+{
+    size_t width;
+
+    if (*insns == kPackedSwitchSignature) {
+        width = 4 + insns[1] * 2;
+    } else if (*insns == kSparseSwitchSignature) {
+        width = 2 + insns[1] * 4;
+    } else if (*insns == kArrayDataSignature) {
+        u2 elemWidth = insns[1];
+        u4 len = insns[2] | (((u4)insns[3]) << 16);
+        // The plus 1 is to round up for odd size and width.
+        width = 4 + (elemWidth * len + 1) / 2;
+    } else {
+        width = dexGetWidthFromOpcode(dexOpcodeFromCodeUnit(insns[0]));
+    }
+
+    return width;
+}
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
new file mode 100644
index 0000000..708a479
--- /dev/null
+++ b/libdex/InstrUtils.h
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik instruction utility functions.
+ */
+#ifndef LIBDEX_INSTRUTILS_H_
+#define LIBDEX_INSTRUTILS_H_
+
+#include "DexFile.h"
+#include "DexOpcodes.h"
+
+/*
+ * Possible instruction formats associated with Dalvik opcodes.
+ *
+ * See the file opcode-gen/README.txt for information about updating
+ * opcodes and instruction formats.
+ */
+enum InstructionFormat {
+    kFmt00x = 0,    // unknown format (also used for "breakpoint" opcode)
+    kFmt10x,        // op
+    kFmt12x,        // op vA, vB
+    kFmt11n,        // op vA, #+B
+    kFmt11x,        // op vAA
+    kFmt10t,        // op +AA
+    kFmt20bc,       // [opt] op AA, thing@BBBB
+    kFmt20t,        // op +AAAA
+    kFmt22x,        // op vAA, vBBBB
+    kFmt21t,        // op vAA, +BBBB
+    kFmt21s,        // op vAA, #+BBBB
+    kFmt21h,        // op vAA, #+BBBB00000[00000000]
+    kFmt21c,        // op vAA, thing@BBBB
+    kFmt23x,        // op vAA, vBB, vCC
+    kFmt22b,        // op vAA, vBB, #+CC
+    kFmt22t,        // op vA, vB, +CCCC
+    kFmt22s,        // op vA, vB, #+CCCC
+    kFmt22c,        // op vA, vB, thing@CCCC
+    kFmt22cs,       // [opt] op vA, vB, field offset CCCC
+    kFmt30t,        // op +AAAAAAAA
+    kFmt32x,        // op vAAAA, vBBBB
+    kFmt31i,        // op vAA, #+BBBBBBBB
+    kFmt31t,        // op vAA, +BBBBBBBB
+    kFmt31c,        // op vAA, string@BBBBBBBB
+    kFmt35c,        // op {vC,vD,vE,vF,vG}, thing@BBBB
+    kFmt35ms,       // [opt] invoke-virtual+super
+    kFmt3rc,        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    kFmt3rms,       // [opt] invoke-virtual+super/range
+    kFmt51l,        // op vAA, #+BBBBBBBBBBBBBBBB
+    kFmt35mi,       // [opt] inline invoke
+    kFmt3rmi,       // [opt] inline invoke/range
+    kFmt33x,        // exop vAA, vBB, vCCCC
+    kFmt32s,        // exop vAA, vBB, #+CCCC
+    kFmt40sc,       // [opt] exop AAAA, thing@BBBBBBBB
+    kFmt41c,        // exop vAAAA, thing@BBBBBBBB
+    kFmt52c,        // exop vAAAA, vBBBB, thing@CCCCCCCC
+    kFmt5rc,        // exop {vCCCC .. v(CCCC+AAAA-1)}, thing@BBBBBBBB
+};
+
+/*
+ * Types of indexed reference that are associated with opcodes whose
+ * formats include such an indexed reference (e.g., 21c and 35c).
+ */
+enum InstructionIndexType {
+    kIndexUnknown = 0,
+    kIndexNone,         // has no index
+    kIndexVaries,       // "It depends." Used for throw-verification-error
+    kIndexTypeRef,      // type reference index
+    kIndexStringRef,    // string reference index
+    kIndexMethodRef,    // method reference index
+    kIndexFieldRef,     // field reference index
+    kIndexInlineMethod, // inline method index (for inline linked methods)
+    kIndexVtableOffset, // vtable offset (for static linked methods)
+    kIndexFieldOffset   // field offset (for static linked fields)
+};
+
+/*
+ * Instruction width implied by an opcode's format; a value in the
+ * range 0 to 5. Note that there are special "pseudo-instructions"
+ * which are used to encode switch and data tables, and these don't
+ * have a fixed width. See dexGetWidthFromInstruction(), below.
+ */
+typedef u1 InstructionWidth;
+
+/*
+ * Opcode control flow flags, used by the verifier and JIT.
+ */
+typedef u1 OpcodeFlags;
+enum OpcodeFlagsBits {
+    kInstrCanBranch     = 1,        // conditional or unconditional branch
+    kInstrCanContinue   = 1 << 1,   // flow can continue to next statement
+    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
+};
+
+/*
+ * Struct that includes a pointer to each of the opcode information
+ * tables.
+ *
+ * Note: We use "u1*" here instead of the names of the enumerated
+ * types to guarantee that elements don't use much space. We hold out
+ * hope for a standard way to indicate the size of an enumerated type
+ * that works for both C and C++, but in the mean time, this will
+ * suffice.
+ */
+struct InstructionInfoTables {
+    u1*                formats;    /* InstructionFormat elements */
+    u1*                indexTypes; /* InstructionIndexType elements */
+    OpcodeFlags*       flags;
+    InstructionWidth*  widths;
+};
+
+/*
+ * Global InstructionInfoTables struct.
+ */
+extern InstructionInfoTables gDexOpcodeInfo;
+
+/*
+ * Holds the contents of a decoded instruction.
+ */
+struct DecodedInstruction {
+    u4      vA;
+    u4      vB;
+    u8      vB_wide;        /* for kFmt51l */
+    u4      vC;
+    u4      arg[5];         /* vC/D/E/F/G in invoke or filled-new-array */
+    Opcode  opcode;
+    InstructionIndexType indexType;
+};
+
+/*
+ * Return the instruction width of the specified opcode, or 0 if not defined.
+ */
+DEX_INLINE size_t dexGetWidthFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return gDexOpcodeInfo.widths[opcode];
+}
+
+/*
+ * Return the width of the specified instruction, or 0 if not defined.  Also
+ * works for special OP_NOP entries, including switch statement data tables
+ * and array data.
+ */
+size_t dexGetWidthFromInstruction(const u2* insns);
+
+/*
+ * Returns the flags for the specified opcode.
+ */
+DEX_INLINE OpcodeFlags dexGetFlagsFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return gDexOpcodeInfo.flags[opcode];
+}
+
+/*
+ * Returns true if the given flags represent a goto (unconditional branch).
+ */
+DEX_INLINE bool dexIsGoto(OpcodeFlags flags)
+{
+    return (flags & (kInstrCanBranch | kInstrCanContinue)) == kInstrCanBranch;
+}
+
+/*
+ * Return the instruction format for the specified opcode.
+ */
+DEX_INLINE InstructionFormat dexGetFormatFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return (InstructionFormat) gDexOpcodeInfo.formats[opcode];
+}
+
+/*
+ * Return the instruction index type for the specified opcode.
+ */
+DEX_INLINE InstructionIndexType dexGetIndexTypeFromOpcode(Opcode opcode)
+{
+    assert((u4) opcode < kNumPackedOpcodes);
+    return (InstructionIndexType) gDexOpcodeInfo.indexTypes[opcode];
+}
+
+/*
+ * Decode the instruction pointed to by "insns".
+ */
+void dexDecodeInstruction(const u2* insns, DecodedInstruction* pDec);
+
+#endif  // LIBDEX_INSTRUTILS_H_
diff --git a/libdex/Leb128.cpp b/libdex/Leb128.cpp
new file mode 100644
index 0000000..ed09e19
--- /dev/null
+++ b/libdex/Leb128.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions for interpreting LEB128 (little endian base 128) values
+ */
+
+#include "Leb128.h"
+
+/*
+ * Reads an unsigned LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit,
+        bool* okay) {
+    const u1* ptr = *pStream;
+    int result = readUnsignedLeb128(pStream);
+
+    if (((limit != NULL) && (*pStream > limit))
+            || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) {
+        *okay = false;
+    }
+
+    return result;
+}
+
+/*
+ * Reads a signed LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifySignedLeb128(const u1** pStream, const u1* limit,
+        bool* okay) {
+    const u1* ptr = *pStream;
+    int result = readSignedLeb128(pStream);
+
+    if (((limit != NULL) && (*pStream > limit))
+            || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) {
+        *okay = false;
+    }
+
+    return result;
+}
diff --git a/libdex/Leb128.h b/libdex/Leb128.h
new file mode 100644
index 0000000..21f4eda
--- /dev/null
+++ b/libdex/Leb128.h
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions for interpreting LEB128 (little endian base 128) values
+ */
+
+#ifndef LIBDEX_LEB128_H_
+#define LIBDEX_LEB128_H_
+
+#include "DexFile.h"
+
+/*
+ * Reads an unsigned LEB128 value, updating the given pointer to point
+ * just past the end of the read value. This function tolerates
+ * non-zero high-order bits in the fifth encoded byte.
+ */
+DEX_INLINE int readUnsignedLeb128(const u1** pStream) {
+    const u1* ptr = *pStream;
+    int result = *(ptr++);
+
+    if (result > 0x7f) {
+        int cur = *(ptr++);
+        result = (result & 0x7f) | ((cur & 0x7f) << 7);
+        if (cur > 0x7f) {
+            cur = *(ptr++);
+            result |= (cur & 0x7f) << 14;
+            if (cur > 0x7f) {
+                cur = *(ptr++);
+                result |= (cur & 0x7f) << 21;
+                if (cur > 0x7f) {
+                    /*
+                     * Note: We don't check to see if cur is out of
+                     * range here, meaning we tolerate garbage in the
+                     * high four-order bits.
+                     */
+                    cur = *(ptr++);
+                    result |= cur << 28;
+                }
+            }
+        }
+    }
+
+    *pStream = ptr;
+    return result;
+}
+
+/*
+ * Reads a signed LEB128 value, updating the given pointer to point
+ * just past the end of the read value. This function tolerates
+ * non-zero high-order bits in the fifth encoded byte.
+ */
+DEX_INLINE int readSignedLeb128(const u1** pStream) {
+    const u1* ptr = *pStream;
+    int result = *(ptr++);
+
+    if (result <= 0x7f) {
+        result = (result << 25) >> 25;
+    } else {
+        int cur = *(ptr++);
+        result = (result & 0x7f) | ((cur & 0x7f) << 7);
+        if (cur <= 0x7f) {
+            result = (result << 18) >> 18;
+        } else {
+            cur = *(ptr++);
+            result |= (cur & 0x7f) << 14;
+            if (cur <= 0x7f) {
+                result = (result << 11) >> 11;
+            } else {
+                cur = *(ptr++);
+                result |= (cur & 0x7f) << 21;
+                if (cur <= 0x7f) {
+                    result = (result << 4) >> 4;
+                } else {
+                    /*
+                     * Note: We don't check to see if cur is out of
+                     * range here, meaning we tolerate garbage in the
+                     * high four-order bits.
+                     */
+                    cur = *(ptr++);
+                    result |= cur << 28;
+                }
+            }
+        }
+    }
+
+    *pStream = ptr;
+    return result;
+}
+
+/*
+ * Reads an unsigned LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit,
+        bool* okay);
+
+/*
+ * Reads a signed LEB128 value, updating the given pointer to point
+ * just past the end of the read value and also indicating whether the
+ * value was syntactically valid. The only syntactically *invalid*
+ * values are ones that are five bytes long where the final byte has
+ * any but the low-order four bits set. Additionally, if the limit is
+ * passed as non-NULL and bytes would need to be read past the limit,
+ * then the read is considered invalid.
+ */
+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/OptInvocation.cpp b/libdex/OptInvocation.cpp
new file mode 100644
index 0000000..4e88c24
--- /dev/null
+++ b/libdex/OptInvocation.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+/*
+ * Utility functions for dealing with optimized dex files.
+ */
+
+#include "vm/DalvikVersion.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <errno.h>
+
+#include "OptInvocation.h"
+#include "DexFile.h"
+
+static const char* kCacheDirectoryName = "dalvik-cache";
+static const char* kClassesDex = "classes.dex";
+
+/*
+ * Given the filename of a .jar or .dex file, construct the DEX file cache
+ * name.
+ *
+ * For a Jar, "subFileName" is the name of the entry (usually "classes.dex").
+ * For a DEX, it may be NULL.
+ *
+ * Returns a newly-allocated string, or NULL on failure.
+ */
+char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName)
+{
+    char nameBuf[512];
+    char absoluteFile[sizeof(nameBuf)];
+    const size_t kBufLen = sizeof(nameBuf) - 1;
+    const char* dataRoot;
+    char* cp;
+
+    /*
+     * Get the absolute path of the Jar or DEX file.
+     */
+    absoluteFile[0] = '\0';
+    if (fileName[0] != '/') {
+        /*
+         * Generate the absolute path.  This doesn't do everything it
+         * should, e.g. if filename is "./out/whatever" it doesn't crunch
+         * the leading "./" out, but it'll do.
+         */
+        if (getcwd(absoluteFile, kBufLen) == NULL) {
+            LOGE("Can't get CWD while opening jar file");
+            return NULL;
+        }
+        strncat(absoluteFile, "/", kBufLen);
+    }
+    strncat(absoluteFile, fileName, kBufLen);
+
+    /*
+     * Append the name of the Jar file entry, if any.  This is not currently
+     * required, but will be if we start putting more than one DEX file
+     * in a Jar.
+     */
+    if (subFileName != NULL) {
+        strncat(absoluteFile, "/", kBufLen);
+        strncat(absoluteFile, subFileName, kBufLen);
+    }
+
+    /* Turn the path into a flat filename by replacing
+     * any slashes after the first one with '@' characters.
+     */
+    cp = absoluteFile + 1;
+    while (*cp != '\0') {
+        if (*cp == '/') {
+            *cp = '@';
+        }
+        cp++;
+    }
+
+    /* Build the name of the cache directory.
+     */
+    dataRoot = getenv("ANDROID_DATA");
+    if (dataRoot == NULL)
+        dataRoot = "/data";
+    snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName);
+
+    /* Tack on the file name for the actual cache file path.
+     */
+    strncat(nameBuf, absoluteFile, kBufLen);
+
+    LOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf);
+    return strdup(nameBuf);
+}
+
+/*
+ * Create a skeletal "opt" header in a new file.  Most of the fields are
+ * initialized to garbage, but we fill in "dexOffset" so others can
+ * see how large the header is.
+ *
+ * "fd" must be positioned at the start of the file.  On return, it will
+ * be positioned just past the header, and the place where the DEX data
+ * should go.
+ *
+ * Returns 0 on success, errno on failure.
+ */
+int dexOptCreateEmptyHeader(int fd)
+{
+    DexOptHeader optHdr;
+    ssize_t actual;
+
+    assert(lseek(fd, 0, SEEK_CUR) == 0);
+
+    /*
+     * The data is only expected to be readable on the current system, so
+     * we just write the structure.  We do need the file offset to be 64-bit
+     * aligned to fulfill a DEX requirement.
+     */
+    assert((sizeof(optHdr) & 0x07) == 0);
+    memset(&optHdr, 0xff, sizeof(optHdr));
+    optHdr.dexOffset = sizeof(optHdr);
+    actual = write(fd, &optHdr, sizeof(optHdr));
+    if (actual != sizeof(optHdr)) {
+        int err = errno ? errno : -1;
+        LOGE("opt header write failed: %s", strerror(errno));
+        return errno;
+    }
+
+    return 0;
+}
diff --git a/libdex/OptInvocation.h b/libdex/OptInvocation.h
new file mode 100644
index 0000000..3f32b94
--- /dev/null
+++ b/libdex/OptInvocation.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/*
+ * Utility functions related to "dexopt".
+ */
+#ifndef LIBDEX_OPTINVOCATION_H_
+#define LIBDEX_OPTINVOCATION_H_
+
+/*
+ * Utility routines, used by the VM.
+ */
+char* dexOptGenerateCacheFileName(const char* fileName,
+    const char* subFileName);
+int dexOptCreateEmptyHeader(int fd);
+
+#endif  // LIBDEX_OPTINVOCATION_H_
diff --git a/libdex/SysUtil.cpp b/libdex/SysUtil.cpp
new file mode 100644
index 0000000..da5eb97
--- /dev/null
+++ b/libdex/SysUtil.cpp
@@ -0,0 +1,433 @@
+/*
+ * 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.
+ */
+
+/*
+ * System utilities.
+ */
+#include "DexFile.h"
+#include "SysUtil.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_POSIX_FILEMAP
+# include <sys/mman.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+
+#include <JNIHelp.h>        // TEMP_FAILURE_RETRY may or may not be in unistd
+
+
+/*
+ * Create an anonymous shared memory segment large enough to hold "length"
+ * bytes.  The actual segment may be larger because mmap() operates on
+ * page boundaries (usually 4K).
+ */
+static void* sysCreateAnonShmem(size_t length)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    void* ptr;
+
+    ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
+            MAP_SHARED | MAP_ANON, -1, 0);
+    if (ptr == MAP_FAILED) {
+        LOGW("mmap(%d, RW, SHARED|ANON) failed: %s", (int) length,
+            strerror(errno));
+        return NULL;
+    }
+
+    return ptr;
+#else
+    LOGE("sysCreateAnonShmem not implemented.");
+    return NULL;
+#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;
+    size_t length;
+
+    assert(start_ != NULL);
+    assert(length_ != NULL);
+
+    start = lseek(fd, 0L, SEEK_CUR);
+    end = lseek(fd, 0L, SEEK_END);
+    (void) lseek(fd, start, SEEK_SET);
+
+    if (start == (off_t) -1 || end == (off_t) -1) {
+        LOGE("could not determine length of file");
+        return -1;
+    }
+
+    length = end - start;
+    if (length == 0) {
+        LOGE("file is empty");
+        return -1;
+    }
+
+    *start_ = start;
+    *length_ = length;
+
+    return 0;
+}
+
+/*
+ * Pull the contents of a file into an new shared memory segment.  We grab
+ * everything from fd's current offset on.
+ *
+ * We need to know the length ahead of time so we can allocate a segment
+ * of sufficient size.
+ */
+int sysLoadFileInShmem(int fd, MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    off_t start;
+    size_t length, actual;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = sysCreateAnonShmem(length);
+    if (memPtr == NULL)
+        return -1;
+
+    actual = read(fd, memPtr, length);
+    if (actual != length) {
+        LOGE("only read %d of %d bytes", (int) actual, (int) length);
+        sysReleaseShmem(pMap);
+        return -1;
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+#else
+    LOGE("sysLoadFileInShmem not implemented.");
+    return -1;
+#endif
+}
+
+#ifndef HAVE_POSIX_FILEMAP
+int sysFakeMapFile(int fd, MemMapping* pMap)
+{
+    /* No MMAP, just fake it by copying the bits.
+       For Win32 we could use MapViewOfFile if really necessary
+       (see libs/utils/FileMap.cpp).
+    */
+    off_t start;
+    size_t length;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = malloc(length);
+    if (read(fd, memPtr, length) < 0) {
+        LOGW("read(fd=%d, start=%d, length=%d) failed: %s", (int) length,
+            fd, (int) start, strerror(errno));
+        return -1;
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+}
+#endif
+
+/*
+ * Map a file (from fd's current offset) into a shared, read-only memory
+ * segment.  The file offset must be a multiple of the system page size.
+ *
+ * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
+ * value and does not disturb "pMap".
+ */
+int sysMapFileInShmemReadOnly(int fd, MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    off_t start;
+    size_t length;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
+    if (memPtr == MAP_FAILED) {
+        LOGW("mmap(%d, RO, FILE|SHARED, %d, %d) failed: %s", (int) length,
+            fd, (int) start, strerror(errno));
+        return -1;
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+#else
+    return sysFakeMapFile(fd, pMap);
+#endif
+}
+
+/*
+ * Map a file (from fd's current offset) into a private, read-write memory
+ * segment that will be marked read-only (a/k/a "writable read-only").  The
+ * file offset must be a multiple of the system page size.
+ *
+ * In some cases the mapping will be fully writable (e.g. for files on
+ * FAT filesystems).
+ *
+ * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
+ * value and does not disturb "pMap".
+ */
+int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    off_t start;
+    size_t length;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
+            fd, start);
+    if (memPtr == MAP_FAILED) {
+        LOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s", (int) length,
+            fd, (int) start, strerror(errno));
+        return -1;
+    }
+    if (mprotect(memPtr, length, PROT_READ) < 0) {
+        /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */
+        int err = errno;
+        LOGV("mprotect(%p, %d, PROT_READ) failed: %s",
+            memPtr, length, strerror(err));
+        LOGD("mprotect(RO) failed (%d), file will remain read-write", err);
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+#else
+    return sysFakeMapFile(fd, pMap);
+#endif
+}
+
+/*
+ * Map part of a file into a shared, read-only memory segment.  The "start"
+ * offset is absolute, not relative.
+ *
+ * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
+ * value and does not disturb "pMap".
+ */
+int sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
+    MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    size_t actualLength;
+    off_t actualStart;
+    int adjust;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    /* adjust to be page-aligned */
+    adjust = start % SYSTEM_PAGE_SIZE;
+    actualStart = start - adjust;
+    actualLength = length + adjust;
+
+    memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
+                fd, actualStart);
+    if (memPtr == MAP_FAILED) {
+        LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s",
+            (int) actualLength, fd, (int) actualStart, strerror(errno));
+        return -1;
+    }
+
+    pMap->baseAddr = memPtr;
+    pMap->baseLength = actualLength;
+    pMap->addr = (char*)memPtr + adjust;
+    pMap->length = length;
+
+    LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d",
+        (int) start, (int) length,
+        pMap->baseAddr, (int) pMap->baseLength,
+        pMap->addr, (int) pMap->length);
+
+    return 0;
+#else
+    LOGE("sysMapFileSegmentInShmem not implemented.");
+    return -1;
+#endif
+}
+
+/*
+ * Change the access rights on one or more pages to read-only or read-write.
+ *
+ * Returns 0 on success.
+ */
+int sysChangeMapAccess(void* addr, size_t length, int wantReadWrite,
+    MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    /*
+     * Verify that "addr" is part of this mapping file.
+     */
+    if (addr < pMap->baseAddr ||
+        (u1*)addr >= (u1*)pMap->baseAddr + pMap->baseLength)
+    {
+        LOGE("Attempted to change %p; map is %p - %p",
+            addr, pMap->baseAddr, (u1*)pMap->baseAddr + pMap->baseLength);
+        return -1;
+    }
+
+    /*
+     * Align "addr" to a page boundary and adjust "length" appropriately.
+     * (The address must be page-aligned, the length doesn't need to be,
+     * but we do need to ensure we cover the same range.)
+     */
+    u1* alignAddr = (u1*) ((int) addr & ~(SYSTEM_PAGE_SIZE-1));
+    size_t alignLength = length + ((u1*) addr - alignAddr);
+
+    //LOGI("%p/%zd --> %p/%zd", addr, length, alignAddr, alignLength);
+    int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ);
+    if (mprotect(alignAddr, alignLength, prot) != 0) {
+        int err = errno;
+        LOGV("mprotect (%p,%zd,%d) failed: %s",
+            alignAddr, alignLength, prot, strerror(errno));
+        return (errno != 0) ? errno : -1;
+    }
+#endif
+
+    /* for "fake" mapping, no need to do anything */
+    return 0;
+}
+
+/*
+ * Release a memory mapping.
+ */
+void sysReleaseShmem(MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    if (pMap->baseAddr == NULL && pMap->baseLength == 0)
+        return;
+
+    if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
+        LOGW("munmap(%p, %d) failed: %s",
+            pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
+    } else {
+        LOGV("munmap(%p, %d) succeeded", pMap->baseAddr, pMap->baseLength);
+        pMap->baseAddr = NULL;
+        pMap->baseLength = 0;
+    }
+#else
+    /* Free the bits allocated by sysMapFileInShmem. */
+    if (pMap->baseAddr != NULL) {
+      free(pMap->baseAddr);
+      pMap->baseAddr = NULL;
+    }
+    pMap->baseLength = 0;
+#endif
+}
+
+/*
+ * Make a copy of a MemMapping.
+ */
+void sysCopyMap(MemMapping* dst, const MemMapping* src)
+{
+    memcpy(dst, src, sizeof(MemMapping));
+}
+
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg)
+{
+    while (count != 0) {
+        ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count));
+        if (actual < 0) {
+            int err = errno;
+            LOGE("%s: write failed: %s", logMsg, strerror(err));
+            return err;
+        } else if (actual != (ssize_t) count) {
+            LOGD("%s: partial write (will retry): (%d of %zd)",
+                logMsg, (int) actual, count);
+            buf = (const void*) (((const u1*) buf) + actual);
+        }
+        count -= actual;
+    }
+
+    return 0;
+}
+
+/* See documentation comment in header file. */
+int sysCopyFileToFile(int outFd, int inFd, size_t count)
+{
+    const size_t kBufSize = 32768;
+    unsigned char buf[kBufSize];
+
+    while (count != 0) {
+        size_t getSize = (count > kBufSize) ? kBufSize : count;
+
+        ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, buf, getSize));
+        if (actual != (ssize_t) getSize) {
+            LOGW("sysCopyFileToFile: copy read failed (%d vs %zd)",
+                (int) actual, getSize);
+            return -1;
+        }
+
+        if (sysWriteFully(outFd, buf, getSize, "sysCopyFileToFile") != 0)
+            return -1;
+
+        count -= getSize;
+    }
+
+    return 0;
+}
diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h
new file mode 100644
index 0000000..100c312
--- /dev/null
+++ b/libdex/SysUtil.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+/*
+ * System utilities.
+ */
+#ifndef LIBDEX_SYSUTIL_H_
+#define LIBDEX_SYSUTIL_H_
+
+#include <sys/types.h>
+
+/*
+ * System page size.  Normally you're expected to get this from
+ * sysconf(_SC_PAGESIZE) or some system-specific define (usually PAGESIZE
+ * or PAGE_SIZE).  If we use a simple #define the compiler can generate
+ * appropriate masks directly, so we define it here and verify it as the
+ * VM is starting up.
+ *
+ * Must be a power of 2.
+ */
+#define SYSTEM_PAGE_SIZE        4096
+
+/*
+ * Use this to keep track of mapped segments.
+ */
+struct MemMapping {
+    void*   addr;           /* start of data */
+    size_t  length;         /* length of data */
+
+    void*   baseAddr;       /* page-aligned base address */
+    size_t  baseLength;     /* length of mapping */
+};
+
+/*
+ * Copy a map.
+ */
+void sysCopyMap(MemMapping* dst, const MemMapping* src);
+
+/*
+ * Load a file into a new shared memory segment.  All data from the current
+ * offset to the end of the file is pulled in.
+ *
+ * The segment is read-write, allowing VM fixups.  (It should be modified
+ * to support .gz/.zip compressed data.)
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysLoadFileInShmem(int fd, MemMapping* pMap);
+
+/*
+ * Map a file (from fd's current offset) into a shared,
+ * read-only memory segment.
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysMapFileInShmemReadOnly(int fd, MemMapping* pMap);
+
+/*
+ * Map a file (from fd's current offset) into a shared, read-only memory
+ * segment that can be made writable.  (In some cases, such as when
+ * mapping a file on a FAT filesystem, the result may be fully writable.)
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap);
+
+/*
+ * Like sysMapFileInShmemReadOnly, but on only part of a file.
+ */
+int sysMapFileSegmentInShmem(int fd, off_t start, size_t length,
+    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);
+
+/*
+ * Change the access rights on one or more pages.  If "wantReadWrite" is
+ * zero, the pages will be made read-only; otherwise they will be read-write.
+ *
+ * Returns 0 on success.
+ */
+int sysChangeMapAccess(void* addr, size_t length, int wantReadWrite,
+    MemMapping* pmap);
+
+/*
+ * Release the pages associated with a shared memory segment.
+ *
+ * This does not free "pMap"; it just releases the memory.
+ */
+void sysReleaseShmem(MemMapping* pMap);
+
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg);
+
+/*
+ * Copy the given number of bytes from one fd to another. Returns
+ * 0 on success, -1 on failure.
+ */
+int sysCopyFileToFile(int outFd, int inFd, size_t count);
+
+#endif  // LIBDEX_SYSUTIL_H_
diff --git a/libdex/ZipArchive.cpp b/libdex/ZipArchive.cpp
new file mode 100644
index 0000000..59d28d9
--- /dev/null
+++ b/libdex/ZipArchive.cpp
@@ -0,0 +1,732 @@
+/*
+ * 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.
+ */
+
+/*
+ * Read-only access to Zip archives, with minimal heap allocation.
+ */
+#include "ZipArchive.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <JNIHelp.h>        // TEMP_FAILURE_RETRY may or may not be in unistd
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/*
+ * Zip file constants.
+ */
+#define kEOCDSignature      0x06054b50
+#define kEOCDLen            22
+#define kEOCDNumEntries     8               // offset to #of entries in file
+#define kEOCDSize           12              // size of the central directory
+#define kEOCDFileOffset     16              // offset to central directory
+
+#define kMaxCommentLen      65535           // longest possible in ushort
+#define kMaxEOCDSearch      (kMaxCommentLen + kEOCDLen)
+
+#define kLFHSignature       0x04034b50
+#define kLFHLen             30              // excluding variable-len fields
+#define kLFHNameLen         26              // offset to filename length
+#define kLFHExtraLen        28              // offset to extra length
+
+#define kCDESignature       0x02014b50
+#define kCDELen             46              // excluding variable-len fields
+#define kCDEMethod          10              // offset to compression method
+#define kCDEModWhen         12              // offset to modification timestamp
+#define kCDECRC             16              // offset to entry CRC
+#define kCDECompLen         20              // offset to compressed length
+#define kCDEUncompLen       24              // offset to uncompressed length
+#define kCDENameLen         28              // offset to filename length
+#define kCDEExtraLen        30              // offset to extra length
+#define kCDECommentLen      32              // offset to comment length
+#define kCDELocalOffset     42              // offset to local hdr
+
+/*
+ * The values we return for ZipEntry use 0 as an invalid value, so we
+ * want to adjust the hash table index by a fixed amount.  Using a large
+ * value helps insure that people don't mix & match arguments, e.g. with
+ * entry indices.
+ */
+#define kZipEntryAdj        10000
+
+/*
+ * Convert a ZipEntry to a hash table index, verifying that it's in a
+ * valid range.
+ */
+static int entryToIndex(const ZipArchive* pArchive, const ZipEntry entry)
+{
+    long ent = ((long) entry) - kZipEntryAdj;
+    if (ent < 0 || ent >= pArchive->mHashTableSize ||
+        pArchive->mHashTable[ent].name == NULL)
+    {
+        LOGW("Zip: invalid ZipEntry %p (%ld)", entry, ent);
+        return -1;
+    }
+    return ent;
+}
+
+/*
+ * Simple string hash function for non-null-terminated strings.
+ */
+static unsigned int computeHash(const char* str, int len)
+{
+    unsigned int hash = 0;
+
+    while (len--)
+        hash = hash * 31 + *str++;
+
+    return hash;
+}
+
+/*
+ * Add a new entry to the hash table.
+ */
+static void addToHash(ZipArchive* pArchive, const char* str, int strLen,
+    unsigned int hash)
+{
+    const int hashTableSize = pArchive->mHashTableSize;
+    int ent = hash & (hashTableSize - 1);
+
+    /*
+     * We over-allocated the table, so we're guaranteed to find an empty slot.
+     */
+    while (pArchive->mHashTable[ent].name != NULL)
+        ent = (ent + 1) & (hashTableSize-1);
+
+    pArchive->mHashTable[ent].name = str;
+    pArchive->mHashTable[ent].nameLen = strLen;
+}
+
+/*
+ * Get 2 little-endian bytes.
+ */
+static u2 get2LE(unsigned char const* pSrc)
+{
+    return pSrc[0] | (pSrc[1] << 8);
+}
+
+/*
+ * Get 4 little-endian bytes.
+ */
+static u4 get4LE(unsigned char const* pSrc)
+{
+    u4 result;
+
+    result = pSrc[0];
+    result |= pSrc[1] << 8;
+    result |= pSrc[2] << 16;
+    result |= pSrc[3] << 24;
+
+    return result;
+}
+
+static int mapCentralDirectory0(int fd, const char* debugFileName,
+        ZipArchive* pArchive, off_t fileLength, size_t readAmount, u1* scanBuf)
+{
+    off_t searchStart = fileLength - readAmount;
+
+    if (lseek(fd, searchStart, SEEK_SET) != searchStart) {
+        LOGW("Zip: seek %ld failed: %s", (long) searchStart, strerror(errno));
+        return -1;
+    }
+    ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, readAmount));
+    if (actual != (ssize_t) readAmount) {
+        LOGW("Zip: read %zd failed: %s", readAmount, strerror(errno));
+        return -1;
+    }
+
+    /*
+     * Scan backward for the EOCD magic.  In an archive without a trailing
+     * comment, we'll find it on the first try.  (We may want to consider
+     * doing an initial minimal read; if we don't find it, retry with a
+     * second read as above.)
+     */
+    int i;
+    for (i = readAmount - kEOCDLen; i >= 0; i--) {
+        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
+            LOGV("+++ Found EOCD at buf+%d", i);
+            break;
+        }
+    }
+    if (i < 0) {
+        LOGD("Zip: EOCD not found, %s is not zip", debugFileName);
+        return -1;
+    }
+
+    off_t eocdOffset = searchStart + i;
+    const u1* eocdPtr = scanBuf + i;
+
+    assert(eocdOffset < fileLength);
+
+    /*
+     * Grab the CD offset and size, and the number of entries in the
+     * archive.  Verify that they look reasonable.
+     */
+    u4 numEntries = get2LE(eocdPtr + kEOCDNumEntries);
+    u4 dirSize = get4LE(eocdPtr + kEOCDSize);
+    u4 dirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+
+    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
+        LOGW("Zip: bad offsets (dir %ld, size %u, eocd %ld)",
+            (long) dirOffset, dirSize, (long) eocdOffset);
+        return -1;
+    }
+    if (numEntries == 0) {
+        LOGW("Zip: empty archive?");
+        return -1;
+    }
+
+    LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d",
+        numEntries, dirSize, dirOffset);
+
+    /*
+     * It all looks good.  Create a mapping for the CD, and set the fields
+     * in pArchive.
+     */
+    if (sysMapFileSegmentInShmem(fd, dirOffset, dirSize,
+            &pArchive->mDirectoryMap) != 0)
+    {
+        LOGW("Zip: cd map failed");
+        return -1;
+    }
+
+    pArchive->mNumEntries = numEntries;
+    pArchive->mDirectoryOffset = dirOffset;
+
+    return 0;
+}
+
+/*
+ * Find the zip Central Directory and memory-map it.
+ *
+ * On success, returns 0 after populating fields from the EOCD area:
+ *   mDirectoryOffset
+ *   mDirectoryMap
+ *   mNumEntries
+ */
+static int mapCentralDirectory(int fd, const char* debugFileName,
+    ZipArchive* pArchive)
+{
+    /*
+     * Get and test file length.
+     */
+    off_t fileLength = lseek(fd, 0, SEEK_END);
+    if (fileLength < kEOCDLen) {
+        LOGV("Zip: length %ld is too small to be zip", (long) fileLength);
+        return -1;
+    }
+
+    /*
+     * Perform the traditional EOCD snipe hunt.
+     *
+     * We're searching for the End of Central Directory magic number,
+     * which appears at the start of the EOCD block.  It's followed by
+     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
+     * need to read the last part of the file into a buffer, dig through
+     * it to find the magic number, parse some values out, and use those
+     * to determine the extent of the CD.
+     *
+     * We start by pulling in the last part of the file.
+     */
+    size_t readAmount = kMaxEOCDSearch;
+    if (fileLength < off_t(readAmount))
+        readAmount = fileLength;
+
+    u1* scanBuf = (u1*) malloc(readAmount);
+    if (scanBuf == NULL) {
+        return -1;
+    }
+
+    int result = mapCentralDirectory0(fd, debugFileName, pArchive,
+            fileLength, readAmount, scanBuf);
+
+    free(scanBuf);
+    return result;
+}
+
+/*
+ * Parses the Zip archive's Central Directory.  Allocates and populates the
+ * hash table.
+ *
+ * Returns 0 on success.
+ */
+static int parseZipArchive(ZipArchive* pArchive)
+{
+    int result = -1;
+    const u1* cdPtr = (const u1*)pArchive->mDirectoryMap.addr;
+    size_t cdLength = pArchive->mDirectoryMap.length;
+    int numEntries = pArchive->mNumEntries;
+
+    /*
+     * Create hash table.  We have a minimum 75% load factor, possibly as
+     * low as 50% after we round off to a power of 2.  There must be at
+     * least one unused entry to avoid an infinite loop during creation.
+     */
+    pArchive->mHashTableSize = dexRoundUpPower2(1 + (numEntries * 4) / 3);
+    pArchive->mHashTable = (ZipHashEntry*)
+            calloc(pArchive->mHashTableSize, sizeof(ZipHashEntry));
+
+    /*
+     * Walk through the central directory, adding entries to the hash
+     * table and verifying values.
+     */
+    const u1* ptr = cdPtr;
+    int i;
+    for (i = 0; i < numEntries; i++) {
+        if (get4LE(ptr) != kCDESignature) {
+            LOGW("Zip: missed a central dir sig (at %d)", i);
+            goto bail;
+        }
+        if (ptr + kCDELen > cdPtr + cdLength) {
+            LOGW("Zip: ran off the end (at %d)", i);
+            goto bail;
+        }
+
+        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset >= pArchive->mDirectoryOffset) {
+            LOGW("Zip: bad LFH offset %ld at entry %d", localHdrOffset, i);
+            goto bail;
+        }
+
+        unsigned int fileNameLen, extraLen, commentLen, hash;
+        fileNameLen = get2LE(ptr + kCDENameLen);
+        extraLen = get2LE(ptr + kCDEExtraLen);
+        commentLen = get2LE(ptr + kCDECommentLen);
+
+        /* add the CDE filename to the hash table */
+        hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
+        addToHash(pArchive, (const char*)ptr + kCDELen, fileNameLen, hash);
+
+        ptr += kCDELen + fileNameLen + extraLen + commentLen;
+        if ((size_t)(ptr - cdPtr) > cdLength) {
+            LOGW("Zip: bad CD advance (%d vs %zd) at entry %d",
+                (int) (ptr - cdPtr), cdLength, i);
+            goto bail;
+        }
+    }
+    LOGV("+++ zip good scan %d entries", numEntries);
+
+    result = 0;
+
+bail:
+    return result;
+}
+
+/*
+ * Open the specified file read-only.  We examine the contents and verify
+ * that it appears to be a valid zip file.
+ *
+ * This will be called on non-Zip files, especially during VM startup, so
+ * we don't want to be too noisy about certain types of failure.  (Do
+ * we want a "quiet" flag?)
+ *
+ * On success, we fill out the contents of "pArchive" and return 0.  On
+ * failure we return the errno value.
+ */
+int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive)
+{
+    int fd, err;
+
+    LOGV("Opening as zip '%s' %p", fileName, pArchive);
+
+    memset(pArchive, 0, sizeof(ZipArchive));
+
+    fd = open(fileName, O_RDONLY | O_BINARY, 0);
+    if (fd < 0) {
+        err = errno ? errno : -1;
+        LOGV("Unable to open '%s': %s", fileName, strerror(err));
+        return err;
+    }
+
+    return dexZipPrepArchive(fd, fileName, pArchive);
+}
+
+/*
+ * Prepare to access a ZipArchive through an open file descriptor.
+ *
+ * On success, we fill out the contents of "pArchive" and return 0.
+ */
+int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive)
+{
+    int result = -1;
+
+    memset(pArchive, 0, sizeof(*pArchive));
+    pArchive->mFd = fd;
+
+    if (mapCentralDirectory(fd, debugFileName, pArchive) != 0)
+        goto bail;
+
+    if (parseZipArchive(pArchive) != 0) {
+        LOGV("Zip: parsing '%s' failed", debugFileName);
+        goto bail;
+    }
+
+    /* success */
+    result = 0;
+
+bail:
+    if (result != 0)
+        dexZipCloseArchive(pArchive);
+    return result;
+}
+
+
+/*
+ * Close a ZipArchive, closing the file and freeing the contents.
+ *
+ * NOTE: the ZipArchive may not have been fully created.
+ */
+void dexZipCloseArchive(ZipArchive* pArchive)
+{
+    LOGV("Closing archive %p", pArchive);
+
+    if (pArchive->mFd >= 0)
+        close(pArchive->mFd);
+
+    sysReleaseShmem(&pArchive->mDirectoryMap);
+
+    free(pArchive->mHashTable);
+
+    /* ensure nobody tries to use the ZipArchive after it's closed */
+    pArchive->mDirectoryOffset = -1;
+    pArchive->mFd = -1;
+    pArchive->mNumEntries = -1;
+    pArchive->mHashTableSize = -1;
+    pArchive->mHashTable = NULL;
+}
+
+
+/*
+ * Find a matching entry.
+ *
+ * Returns 0 if not found.
+ */
+ZipEntry dexZipFindEntry(const ZipArchive* pArchive, const char* entryName)
+{
+    int nameLen = strlen(entryName);
+    unsigned int hash = computeHash(entryName, nameLen);
+    const int hashTableSize = pArchive->mHashTableSize;
+    int ent = hash & (hashTableSize-1);
+
+    while (pArchive->mHashTable[ent].name != NULL) {
+        if (pArchive->mHashTable[ent].nameLen == nameLen &&
+            memcmp(pArchive->mHashTable[ent].name, entryName, nameLen) == 0)
+        {
+            /* match */
+            return (ZipEntry)(long)(ent + kZipEntryAdj);
+        }
+
+        ent = (ent + 1) & (hashTableSize-1);
+    }
+
+    return NULL;
+}
+
+#if 0
+/*
+ * Find the Nth entry.
+ *
+ * This currently involves walking through the sparse hash table, counting
+ * non-empty entries.  If we need to speed this up we can either allocate
+ * a parallel lookup table or (perhaps better) provide an iterator interface.
+ */
+ZipEntry findEntryByIndex(ZipArchive* pArchive, int idx)
+{
+    if (idx < 0 || idx >= pArchive->mNumEntries) {
+        LOGW("Invalid index %d", idx);
+        return NULL;
+    }
+
+    int ent;
+    for (ent = 0; ent < pArchive->mHashTableSize; ent++) {
+        if (pArchive->mHashTable[ent].name != NULL) {
+            if (idx-- == 0)
+                return (ZipEntry) (ent + kZipEntryAdj);
+        }
+    }
+
+    return NULL;
+}
+#endif
+
+/*
+ * Get the useful fields from the zip entry.
+ *
+ * Returns non-zero if the contents of the fields (particularly the data
+ * offset) appear to be bogus.
+ */
+int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
+    int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
+    long* pModWhen, long* pCrc32)
+{
+    int ent = entryToIndex(pArchive, entry);
+    if (ent < 0)
+        return -1;
+
+    /*
+     * Recover the start of the central directory entry from the filename
+     * pointer.  The filename is the first entry past the fixed-size data,
+     * so we can just subtract back from that.
+     */
+    const unsigned char* basePtr = (const unsigned char*)
+        pArchive->mDirectoryMap.addr;
+    const unsigned char* ptr = (const unsigned char*)
+        pArchive->mHashTable[ent].name;
+    off_t cdOffset = pArchive->mDirectoryOffset;
+
+    ptr -= kCDELen;
+
+    int method = get2LE(ptr + kCDEMethod);
+    if (pMethod != NULL)
+        *pMethod = method;
+
+    if (pModWhen != NULL)
+        *pModWhen = get4LE(ptr + kCDEModWhen);
+    if (pCrc32 != NULL)
+        *pCrc32 = get4LE(ptr + kCDECRC);
+
+    size_t compLen = get4LE(ptr + kCDECompLen);
+    if (pCompLen != NULL)
+        *pCompLen = compLen;
+    size_t uncompLen = get4LE(ptr + kCDEUncompLen);
+    if (pUncompLen != NULL)
+        *pUncompLen = uncompLen;
+
+    /*
+     * If requested, determine the offset of the start of the data.  All we
+     * have is the offset to the Local File Header, which is variable size,
+     * so we have to read the contents of the struct to figure out where
+     * the actual data starts.
+     *
+     * We also need to make sure that the lengths are not so large that
+     * somebody trying to map the compressed or uncompressed data runs
+     * off the end of the mapped region.
+     *
+     * Note we don't verify compLen/uncompLen if they don't request the
+     * dataOffset, because dataOffset is expensive to determine.  However,
+     * if they don't have the file offset, they're not likely to be doing
+     * anything with the contents.
+     */
+    if (pOffset != NULL) {
+        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset + kLFHLen >= cdOffset) {
+            LOGW("Zip: bad local hdr offset in zip");
+            return -1;
+        }
+
+        u1 lfhBuf[kLFHLen];
+        if (lseek(pArchive->mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
+            LOGW("Zip: failed seeking to lfh at offset %ld", localHdrOffset);
+            return -1;
+        }
+        ssize_t actual =
+            TEMP_FAILURE_RETRY(read(pArchive->mFd, lfhBuf, sizeof(lfhBuf)));
+        if (actual != sizeof(lfhBuf)) {
+            LOGW("Zip: failed reading lfh from offset %ld", localHdrOffset);
+            return -1;
+        }
+
+        if (get4LE(lfhBuf) != kLFHSignature) {
+            LOGW("Zip: didn't find signature at start of lfh, offset=%ld",
+                localHdrOffset);
+            return -1;
+        }
+
+        off_t dataOffset = localHdrOffset + kLFHLen
+            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
+        if (dataOffset >= cdOffset) {
+            LOGW("Zip: bad data offset %ld in zip", (long) dataOffset);
+            return -1;
+        }
+
+        /* check lengths */
+        if ((off_t)(dataOffset + compLen) > cdOffset) {
+            LOGW("Zip: bad compressed length in zip (%ld + %zd > %ld)",
+                (long) dataOffset, compLen, (long) cdOffset);
+            return -1;
+        }
+
+        if (method == kCompressStored &&
+            (off_t)(dataOffset + uncompLen) > cdOffset)
+        {
+            LOGW("Zip: bad uncompressed length in zip (%ld + %zd > %ld)",
+                (long) dataOffset, uncompLen, (long) cdOffset);
+            return -1;
+        }
+
+        *pOffset = dataOffset;
+    }
+    return 0;
+}
+
+/*
+ * Uncompress "deflate" data from the archive's file to an open file
+ * descriptor.
+ */
+static int inflateToFile(int outFd, int inFd, size_t uncompLen, size_t compLen)
+{
+    int result = -1;
+    const size_t kBufSize = 32768;
+    unsigned char* readBuf = (unsigned char*) malloc(kBufSize);
+    unsigned char* writeBuf = (unsigned char*) malloc(kBufSize);
+    z_stream zstream;
+    int zerr;
+
+    if (readBuf == NULL || writeBuf == NULL)
+        goto bail;
+
+    /*
+     * Initialize the zlib stream struct.
+     */
+    memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = (Bytef*) writeBuf;
+    zstream.avail_out = kBufSize;
+    zstream.data_type = Z_UNKNOWN;
+
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
+    zerr = inflateInit2(&zstream, -MAX_WBITS);
+    if (zerr != Z_OK) {
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)",
+                ZLIB_VERSION);
+        } else {
+            LOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
+        }
+        goto bail;
+    }
+
+    /*
+     * Loop while we have more to do.
+     */
+    do {
+        /* read as much as we can */
+        if (zstream.avail_in == 0) {
+            size_t getSize = (compLen > kBufSize) ? kBufSize : compLen;
+
+            ssize_t actual = TEMP_FAILURE_RETRY(read(inFd, readBuf, getSize));
+            if (actual != (ssize_t) getSize) {
+                LOGW("Zip: inflate read failed (%d vs %zd)",
+                    (int)actual, getSize);
+                goto z_bail;
+            }
+
+            compLen -= getSize;
+
+            zstream.next_in = readBuf;
+            zstream.avail_in = getSize;
+        }
+
+        /* uncompress the data */
+        zerr = inflate(&zstream, Z_NO_FLUSH);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            LOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
+                zerr, zstream.next_in, zstream.avail_in,
+                zstream.next_out, zstream.avail_out);
+            goto z_bail;
+        }
+
+        /* write when we're full or when we're done */
+        if (zstream.avail_out == 0 ||
+            (zerr == Z_STREAM_END && zstream.avail_out != kBufSize))
+        {
+            size_t writeSize = zstream.next_out - writeBuf;
+            if (sysWriteFully(outFd, writeBuf, writeSize, "Zip inflate") != 0)
+                goto z_bail;
+
+            zstream.next_out = writeBuf;
+            zstream.avail_out = kBufSize;
+        }
+    } while (zerr == Z_OK);
+
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+
+    /* paranoia */
+    if (zstream.total_out != uncompLen) {
+        LOGW("Zip: size mismatch on inflated file (%ld vs %zd)",
+            zstream.total_out, uncompLen);
+        goto z_bail;
+    }
+
+    result = 0;
+
+z_bail:
+    inflateEnd(&zstream);        /* free up any allocated structures */
+
+bail:
+    free(readBuf);
+    free(writeBuf);
+    return result;
+}
+
+/*
+ * Uncompress an entry, in its entirety, to an open file descriptor.
+ *
+ * TODO: this doesn't verify the data's CRC, but probably should (especially
+ * for uncompressed data).
+ */
+int dexZipExtractEntryToFile(const ZipArchive* pArchive,
+    const ZipEntry entry, int fd)
+{
+    int result = -1;
+    int ent = entryToIndex(pArchive, entry);
+    if (ent < 0) {
+        LOGW("Zip: extract can't find entry %p", entry);
+        goto bail;
+    }
+
+    int method;
+    size_t uncompLen, compLen;
+    off_t dataOffset;
+
+    if (dexZipGetEntryInfo(pArchive, entry, &method, &uncompLen, &compLen,
+            &dataOffset, NULL, NULL) != 0)
+    {
+        goto bail;
+    }
+    if (lseek(pArchive->mFd, dataOffset, SEEK_SET) != dataOffset) {
+        LOGW("Zip: lseek to data at %ld failed", (long) dataOffset);
+        goto bail;
+    }
+
+    if (method == kCompressStored) {
+        if (sysCopyFileToFile(fd, pArchive->mFd, uncompLen) != 0)
+            goto bail;
+    } else {
+        if (inflateToFile(fd, pArchive->mFd, uncompLen, compLen) != 0)
+            goto bail;
+    }
+
+    result = 0;
+
+bail:
+    return result;
+}
diff --git a/libdex/ZipArchive.h b/libdex/ZipArchive.h
new file mode 100644
index 0000000..df5c49a
--- /dev/null
+++ b/libdex/ZipArchive.h
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/*
+ * Read-only access to Zip archives, with minimal heap allocation.
+ */
+#ifndef LIBDEX_ZIPARCHIVE_H_
+#define LIBDEX_ZIPARCHIVE_H_
+
+#include "SysUtil.h"
+#include "DexFile.h"            // need DEX_INLINE
+
+/*
+ * Trivial typedef to ensure that ZipEntry is not treated as a simple
+ * integer.  We use NULL to indicate an invalid value.
+ */
+typedef void* ZipEntry;
+
+/*
+ * One entry in the hash table.
+ */
+struct ZipHashEntry {
+    const char*     name;
+    unsigned short  nameLen;
+};
+
+/*
+ * Read-only Zip archive.
+ *
+ * We want "open" and "find entry by name" to be fast operations, and
+ * we want to use as little memory as possible.  We memory-map the zip
+ * central directory, and load a hash table with pointers to the filenames
+ * (which aren't null-terminated).  The other fields are at a fixed offset
+ * from the filename, so we don't need to extract those (but we do need
+ * to byte-read and endian-swap them every time we want them).
+ *
+ * It's possible that somebody has handed us a massive (~1GB) zip archive,
+ * so we can't expect to mmap the entire file.
+ *
+ * To speed comparisons when doing a lookup by name, we could make the mapping
+ * "private" (copy-on-write) and null-terminate the filenames after verifying
+ * the record structure.  However, this requires a private mapping of
+ * every page that the Central Directory touches.  Easier to tuck a copy
+ * of the string length into the hash table entry.
+ */
+struct ZipArchive {
+    /* open Zip archive */
+    int         mFd;
+
+    /* mapped central directory area */
+    off_t       mDirectoryOffset;
+    MemMapping  mDirectoryMap;
+
+    /* number of entries in the Zip archive */
+    int         mNumEntries;
+
+    /*
+     * We know how many entries are in the Zip archive, so we can have a
+     * fixed-size hash table.  We probe on collisions.
+     */
+    int         mHashTableSize;
+    ZipHashEntry* mHashTable;
+};
+
+/* Zip compression methods we support */
+enum {
+    kCompressStored     = 0,        // no compression
+    kCompressDeflated   = 8,        // standard deflate
+};
+
+
+/*
+ * Open a Zip archive.
+ *
+ * On success, returns 0 and populates "pArchive".  Returns nonzero errno
+ * value on failure.
+ */
+int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive);
+
+/*
+ * Like dexZipOpenArchive, but takes a file descriptor open for reading
+ * at the start of the file.  The descriptor must be mappable (this does
+ * not allow access to a stream).
+ *
+ * "debugFileName" will appear in error messages, but is not otherwise used.
+ */
+int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive);
+
+/*
+ * Close archive, releasing resources associated with it.
+ *
+ * Depending on the implementation this could unmap pages used by classes
+ * stored in a Jar.  This should only be done after unloading classes.
+ */
+void dexZipCloseArchive(ZipArchive* pArchive);
+
+/*
+ * Return the archive's file descriptor.
+ */
+DEX_INLINE int dexZipGetArchiveFd(const ZipArchive* pArchive) {
+    return pArchive->mFd;
+}
+
+/*
+ * Find an entry in the Zip archive, by name.  Returns NULL if the entry
+ * was not found.
+ */
+ZipEntry dexZipFindEntry(const ZipArchive* pArchive,
+    const char* entryName);
+
+/*
+ * Retrieve one or more of the "interesting" fields.  Non-NULL pointers
+ * are filled in.
+ *
+ * Returns 0 on success.
+ */
+int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
+    int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
+    long* pModWhen, long* pCrc32);
+
+/*
+ * Simple accessors.
+ */
+DEX_INLINE long dexGetZipEntryOffset(const ZipArchive* pArchive,
+    const ZipEntry entry)
+{
+    off_t val = 0;
+    dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, &val, NULL, NULL);
+    return (long) val;
+}
+DEX_INLINE size_t dexGetZipEntryUncompLen(const ZipArchive* pArchive,
+    const ZipEntry entry)
+{
+    size_t val = 0;
+    dexZipGetEntryInfo(pArchive, entry, NULL, &val, NULL, NULL, NULL, NULL);
+    return val;
+}
+DEX_INLINE long dexGetZipEntryModTime(const ZipArchive* pArchive,
+    const ZipEntry entry)
+{
+    long val = 0;
+    dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, &val, NULL);
+    return val;
+}
+DEX_INLINE long dexGetZipEntryCrc32(const ZipArchive* pArchive,
+    const ZipEntry entry)
+{
+    long val = 0;
+    dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, NULL, &val);
+    return val;
+}
+
+/*
+ * Uncompress and write an entry to a file descriptor.
+ *
+ * Returns 0 on success.
+ */
+int dexZipExtractEntryToFile(const ZipArchive* pArchive,
+    const ZipEntry entry, int fd);
+
+/*
+ * Utility function to compute a CRC-32.
+ */
+u4 dexInitCrc32(void);
+u4 dexComputeCrc32(u4 crc, const void* buf, size_t len);
+
+#endif  // LIBDEX_ZIPARCHIVE_H_
diff --git a/libdex/sha1.cpp b/libdex/sha1.cpp
new file mode 100644
index 0000000..15a81cc
--- /dev/null
+++ b/libdex/sha1.cpp
@@ -0,0 +1,514 @@
+/*
+ * Tweaked in various ways for Google/Android:
+ *  - Changed from .cpp to .c.
+ *  - Made argument to SHA1Update a const pointer, and enabled
+ *    SHA1HANDSOFF.  This incurs a speed penalty but prevents us from
+ *    trashing the input.
+ *  - Include <endian.h> to get endian info.
+ *  - Split a small piece into a header file.
+ */
+
+/*
+sha1sum: inspired by md5sum.
+
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+bit machines
+Routine SHA1Update changed from
+    void SHA1Update(SHA1_CTX* context, unsigned char* data,
+      unsigned int len)
+to
+    void SHA1Update(SHA1_CTX* context, unsigned char* data,
+      unsigned long len)
+
+The 'len' parameter was declared an int which works fine on 32
+bit machines. However, on 16 bit machines an int is too small
+for the shifts being done against it.  This caused the hash
+function to generate incorrect values if len was greater than
+8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or
+larger would be guaranteed to generate the wrong hash (e.g.
+Test Vector #3, a million "a"s).
+
+I also changed the declaration of variables i & j in SHA1Update
+to unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit
+implementations since an int and a long are the same size in
+those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland
+C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments
+containing 'JHB'
+
+-----------------
+Modified 13 August 2000
+By Michael Paul Johnson <mpj@cryptography.org>
+Still 100% Public Domain
+
+Changed command line syntax, added feature to automatically
+check files against their previous SHA-1 check values, kind of
+like md5sum does. Added functions hexval, verifyfile,
+and sha1file. Rewrote main().
+-----------------
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#define SHA1HANDSOFF    /*Copies data before messing with it.*/
+
+/*#define CMDLINE        * include main() and file processing */
+
+#include "sha1.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef __BORLANDC__
+#include <dir.h>
+#include <dos.h>
+#include <process.h>   /*  prototype for exit() - JHB
+               needed for Win32, but chokes Linux - MPJ */
+#define X_LITTLE_ENDIAN /* This should be #define'd if true.*/
+#else
+# include <unistd.h>
+# include <stdlib.h>
+//# include <endian.h>
+
+#include "DexFile.h"    // want common byte ordering def
+
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define X_LITTLE_ENDIAN
+# endif
+#endif
+#include <ctype.h>
+
+#define LINESIZE 2048
+
+static void SHA1Transform(unsigned long state[5],
+    const unsigned char buffer[64]);
+
+#define rol(value,bits) \
+ (((value)<<(bits))|((value)>>(32-(bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from
+   SSLeay */
+#ifdef X_LITTLE_ENDIAN
+#define blk0(i) (block->l[i]=(rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void SHA1Transform(unsigned long state[5],
+    const unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+union CHAR64LONG16 {
+    unsigned char c[64];
+    unsigned long l[16];
+};
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+    block = (CHAR64LONG16*)workspace;
+    memcpy(block, buffer, 64);
+#else
+    block = (CHAR64LONG16*)buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2);
+    R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5);
+    R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8);
+    R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14);
+    R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17);
+    R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20);
+    R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26);
+    R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29);
+    R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32);
+    R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38);
+    R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41);
+    R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44);
+    R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50);
+    R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53);
+    R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56);
+    R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62);
+    R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65);
+    R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68);
+    R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74);
+    R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77);
+    R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+/*    a = b = c = d = e = 0; Nice try, but the compiler
+optimizes this out, anyway, and it produces an annoying
+warning. */
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data,
+    unsigned long len)  /* JHB */
+{
+    unsigned long i, j; /* JHB */
+
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3))
+        context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63)
+    {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else
+        i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX*
+context)
+{
+unsigned long i;    /* JHB */
+unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++)
+    {
+        finalcount[i] = (unsigned char)((context->count[(i>=4?
+            0:1)]>>((3-(i&3))*8))&255);
+        /* Endian independent */
+    }
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    SHA1Update(context, finalcount, 8);
+    /* Should cause a SHA1Transform() */
+    for (i = 0; i < HASHSIZE; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, HASHSIZE);
+    memset(context->count, 0, 8);
+    memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF
+    /* make SHA1Transform overwrite it's own static vars */
+    SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+
+#ifdef CMDLINE
+
+/* sha1file computes the SHA-1 hash of the named file and puts
+   it in the 20-byte array digest. If fname is NULL, stdin is
+   assumed.
+*/
+void sha1file(char *fname, unsigned char* digest)
+{
+    int bytesread;
+    SHA1_CTX context;
+    unsigned char buffer[16384];
+    FILE* f;
+
+    if (fname)
+    {
+        f = fopen(fname, "rb");
+        if (!f)
+        {
+            fprintf(stderr, "Can't open %s\n", fname);
+            memset(digest, 0, HASHSIZE);
+            return;
+        }
+    }
+    else
+    {
+        f = stdin;
+    }
+    SHA1Init(&context);
+    while (!feof(f))
+    {
+        bytesread = fread(buffer, 1, 16384, f);
+        SHA1Update(&context, buffer, bytesread);
+    }
+    SHA1Final(digest, &context);
+    if (fname)
+        fclose(f);
+}
+
+/* Convert ASCII hexidecimal digit to 4-bit value. */
+unsigned char hexval(char c)
+{
+    unsigned char h;
+
+    c = toupper(c);
+    if (c >= 'A')
+        h = c - 'A' + 10;
+    else
+        h = c - '0';
+    return h;
+}
+
+/* Verify a file created with sha1sum by redirecting output
+   to a file. */
+int verifyfile(char *fname)
+{
+    int j, k;
+    int found = 0;
+    unsigned char digest[HASHSIZE];
+    unsigned char expected_digest[HASHSIZE];
+    FILE *checkfile;
+    char checkline[LINESIZE];
+    char *s;
+    unsigned char err;
+
+    checkfile = fopen(fname, "rt");
+    if (!checkfile)
+    {
+        fprintf(stderr, "Can't open %s\n", fname);
+        return(0);
+    }
+    do
+    {
+        s = fgets(checkline, LINESIZE, checkfile);
+        if (s)
+        {
+            if ((strlen(checkline)>26)&&
+                1 /*(!strncmp(checkline,"SHA1=", 5))*/)
+            {
+                /* Overwrite newline. */
+                checkline[strlen(checkline)-1]=0;
+                found = 1;
+
+                /* Read expected check value. */
+                for (k=0, j=5; k < HASHSIZE; k++)
+                {
+                    expected_digest[k]=hexval(checkline[j++]);
+                    expected_digest[k]=(expected_digest[k]<<4)
+                        +hexval(checkline[j++]);
+                }
+
+                /* Compute fingerprints */
+                s = checkline+46;
+                sha1file(s, digest);
+
+                /* Compare fingerprints */
+                err = 0;
+                for (k=0; k<HASHSIZE; k++)
+                    err |= digest[k]-
+                        expected_digest[k];
+                if (err)
+                {
+                    fprintf(stderr, "FAILED: %s\n"
+                        " EXPECTED: ", s);
+                    for (k=0; k<HASHSIZE; k++)
+                        fprintf(stderr, "%02X",
+                            expected_digest[k]);
+                    fprintf(stderr,"\n    FOUND: ");
+                    for (k=0; k<HASHSIZE; k++)
+                        fprintf(stderr, "%02X", digest[k]);
+                    fprintf(stderr, "\n");
+                }
+                else
+                {
+                    printf("OK: %s\n", s);
+                }
+            }
+        }
+    } while (s);
+    return found;
+}
+
+
+
+void syntax(char *progname)
+{
+    printf("\nsyntax:\n"
+     "%s [-c|-h][-q] file name[s]\n"
+     "    -c = check files against previous check values\n"
+     "    -g = generate SHA-1 check values (default action)\n"
+     "    -h = display this help\n"
+     "For example,\n"
+     "sha1sum test.txt > check.txt\n"
+     "generates check value for test.txt in check.txt, and\n"
+     "sha1sum -c check.txt\n"
+     "checks test.txt against the check value in check.txt\n",
+     progname);
+    exit(1);
+}
+
+
+/**********************************************************/
+
+int main(int argc, char** argv)
+{
+    int i, j, k;
+    int check = 0;
+    int found = 0;
+    unsigned char digest[HASHSIZE];
+    unsigned char expected_digest[HASHSIZE];
+    FILE *checkfile;
+    char checkline[LINESIZE];
+    char *s;
+#ifdef __BORLANDC__
+    struct ffblk f;
+    int done;
+    char path[MAXPATH];
+    char drive[MAXDRIVE];
+    char dir[MAXDIR];
+    char name[MAXFILE];
+    char ext[MAXEXT];
+#endif
+    unsigned char err;
+
+    for (i = 1; i < argc; i++)
+    {
+        if (argv[i][0] == '-')
+        {
+            switch (argv[i][1])
+            {
+                case 'c':
+                case 'C':
+                    check = 1;
+                    break;
+                case 'g':
+                case 'G':
+                    check = 0;
+                    break;
+                default:
+                    syntax(argv[0]);
+            }
+        }
+    }
+
+    for (i=1; i<argc; i++)
+    {
+        if (argv[i][0] != '-')
+        {
+#ifdef __BORLANDC__
+            fnsplit(argv[i], drive, dir, name, ext);
+            done = findfirst(argv[i], &f, FA_RDONLY |
+                FA_HIDDEN|FA_SYSTEM|FA_ARCH);
+             while (!done)
+            {
+                sprintf(path, "%s%s%s", drive, dir, f.ff_name);
+                s = path;
+#else
+                s = argv[i];
+#endif
+
+                if (check)
+                {   /* Check fingerprint file. */
+                    found |= verifyfile(s);
+                }
+                else
+                {   /* Generate fingerprints & write to
+                       stdout. */
+                    sha1file(s, digest);
+                    //printf("SHA1=");
+                    for (j=0; j<HASHSIZE; j++)
+                        printf("%02x", digest[j]);
+                    printf("  %s\n", s);
+                    found = 1;
+                }
+
+#ifdef __BORLANDC__
+                done = findnext(&f);
+            }
+#endif
+
+        }
+    }
+    if (!found)
+    {
+        if (check)
+        {
+            fprintf(stderr,
+                "No SHA1 lines found in %s\n",
+                argv[i]);
+        }
+        else
+        {
+            fprintf(stderr, "No files checked.\n");
+            syntax(argv[0]);
+        }
+    }
+    return(0);  /* JHB */
+}
+
+#endif  /*CMDLINE*/
diff --git a/libdex/sha1.h b/libdex/sha1.h
new file mode 100644
index 0000000..28907de
--- /dev/null
+++ b/libdex/sha1.h
@@ -0,0 +1,20 @@
+/*
+ * See "sha1.cpp" for author info.
+ */
+#ifndef LIBDEX_SHA1_H_
+#define LIBDEX_SHA1_H_
+
+struct SHA1_CTX {
+    unsigned long state[5];
+    unsigned long count[2];
+    unsigned char buffer[64];
+};
+
+#define HASHSIZE 20
+
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data,
+    unsigned long len);
+void SHA1Final(unsigned char digest[HASHSIZE], SHA1_CTX* context);
+
+#endif  // LIBDEX_SHA1_H_
diff --git a/libnativehelper/Android.mk b/libnativehelper/Android.mk
new file mode 100644
index 0000000..dea0907
--- /dev/null
+++ b/libnativehelper/Android.mk
@@ -0,0 +1,86 @@
+# 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)
+
+#
+# Common definitions for host and device.
+#
+
+src_files := \
+    JNIHelp.cpp \
+    Register.cpp
+
+c_includes := \
+    $(JNI_H_INCLUDE)
+
+# Any shared/static libs required by libcore
+# need to be mentioned here as well.
+# TODO: fix this requirement
+
+shared_libraries := \
+    libcrypto  \
+    libicui18n \
+    libicuuc   \
+    libssl
+
+static_libraries := \
+    libjavacore \
+    libfdlibm
+
+
+
+#
+# Build for the target (device).
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(src_files)
+LOCAL_C_INCLUDES := $(c_includes)
+LOCAL_STATIC_LIBRARIES := $(static_libraries)
+LOCAL_SHARED_LIBRARIES := $(shared_libraries) libcutils libexpat liblog libstlport libz
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libnativehelper
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+#
+# Build for the host.
+#
+
+ifeq ($(WITH_HOST_DALVIK),true)
+
+    include $(CLEAR_VARS)
+
+    LOCAL_SRC_FILES := $(src_files)
+    LOCAL_C_INCLUDES := $(c_includes)
+    LOCAL_WHOLE_STATIC_LIBRARIES := $(static_libraries:%=%-host)
+
+    ifeq ($(HOST_OS)-$(HOST_ARCH),darwin-x86)
+        # OSX has a lot of libraries built in, which we don't have to
+        # bother building; just include them on the ld line.
+        LOCAL_LDLIBS := -lexpat -lssl -lz -lcrypto -licucore
+    else
+        LOCAL_SHARED_LIBRARIES := $(shared_libraries)
+        LOCAL_STATIC_LIBRARIES := libcutils libexpat liblog libz
+    endif
+
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_MODULE := libnativehelper
+    include $(BUILD_HOST_STATIC_LIBRARY)
+
+endif
diff --git a/libnativehelper/JNIHelp.cpp b/libnativehelper/JNIHelp.cpp
new file mode 100644
index 0000000..e1ad6fc
--- /dev/null
+++ b/libnativehelper/JNIHelp.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "JNIHelp"
+
+#include "JNIHelp.h"
+#include "cutils/log.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/**
+ * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
+ */
+template<typename T>
+class scoped_local_ref {
+public:
+    scoped_local_ref(C_JNIEnv* env, T localRef = NULL)
+    : mEnv(env), mLocalRef(localRef)
+    {
+    }
+
+    ~scoped_local_ref() {
+        reset();
+    }
+
+    void reset(T localRef = NULL) {
+        if (mLocalRef != NULL) {
+            (*mEnv)->DeleteLocalRef(reinterpret_cast<JNIEnv*>(mEnv), mLocalRef);
+            mLocalRef = localRef;
+        }
+    }
+
+    T get() const {
+        return mLocalRef;
+    }
+
+private:
+    C_JNIEnv* mEnv;
+    T mLocalRef;
+
+    // Disallow copy and assignment.
+    scoped_local_ref(const scoped_local_ref&);
+    void operator=(const scoped_local_ref&);
+};
+
+static jclass findClass(C_JNIEnv* env, const char* className) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+    return (*env)->FindClass(e, className);
+}
+
+extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
+    const JNINativeMethod* gMethods, int numMethods)
+{
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+
+    LOGV("Registering %s natives", className);
+
+    scoped_local_ref<jclass> c(env, findClass(env, className));
+    if (c.get() == NULL) {
+        LOGE("Native registration unable to find class '%s', aborting", className);
+        abort();
+    }
+
+    if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
+        LOGE("RegisterNatives failed for '%s', aborting", className);
+        abort();
+    }
+
+    return 0;
+}
+
+/*
+ * Returns a human-readable summary of an exception object.  The buffer will
+ * be populated with the "binary" class name and, if present, the
+ * exception message.
+ */
+static char* getExceptionSummary0(C_JNIEnv* env, jthrowable exception) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+
+    /* get the name of the exception's class */
+    scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
+    scoped_local_ref<jclass> classClass(env,
+            (*env)->GetObjectClass(e, exceptionClass.get())); // java.lang.Class, can't fail
+    jmethodID classGetNameMethod =
+            (*env)->GetMethodID(e, classClass.get(), "getName", "()Ljava/lang/String;");
+    scoped_local_ref<jstring> classNameStr(env,
+            (jstring) (*env)->CallObjectMethod(e, exceptionClass.get(), classGetNameMethod));
+    if (classNameStr.get() == NULL) {
+        return NULL;
+    }
+
+    /* get printable string */
+    const char* classNameChars = (*env)->GetStringUTFChars(e, classNameStr.get(), NULL);
+    if (classNameChars == NULL) {
+        return NULL;
+    }
+
+    /* if the exception has a detail message, get that */
+    jmethodID getMessage =
+            (*env)->GetMethodID(e, exceptionClass.get(), "getMessage", "()Ljava/lang/String;");
+    scoped_local_ref<jstring> messageStr(env,
+            (jstring) (*env)->CallObjectMethod(e, exception, getMessage));
+    if (messageStr.get() == NULL) {
+        return strdup(classNameChars);
+    }
+
+    char* result = NULL;
+    const char* messageChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
+    if (messageChars != NULL) {
+        asprintf(&result, "%s: %s", classNameChars, messageChars);
+        (*env)->ReleaseStringUTFChars(e, messageStr.get(), messageChars);
+    } else {
+        (*env)->ExceptionClear(e); // clear OOM
+        asprintf(&result, "%s: <error getting message>", classNameChars);
+    }
+
+    (*env)->ReleaseStringUTFChars(e, classNameStr.get(), classNameChars);
+    return result;
+}
+
+static char* getExceptionSummary(C_JNIEnv* env, jthrowable exception) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+    char* result = getExceptionSummary0(env, exception);
+    if (result == NULL) {
+        (*env)->ExceptionClear(e);
+        result = strdup("<error getting class name>");
+    }
+    return result;
+}
+
+/*
+ * Returns an exception (with stack trace) as a string.
+ */
+static char* getStackTrace(C_JNIEnv* env, jthrowable exception) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+
+    scoped_local_ref<jclass> stringWriterClass(env, findClass(env, "java/io/StringWriter"));
+    if (stringWriterClass.get() == NULL) {
+        return NULL;
+    }
+
+    jmethodID stringWriterCtor = (*env)->GetMethodID(e, stringWriterClass.get(), "<init>", "()V");
+    jmethodID stringWriterToStringMethod =
+            (*env)->GetMethodID(e, stringWriterClass.get(), "toString", "()Ljava/lang/String;");
+
+    scoped_local_ref<jclass> printWriterClass(env, findClass(env, "java/io/PrintWriter"));
+    if (printWriterClass.get() == NULL) {
+        return NULL;
+    }
+
+    jmethodID printWriterCtor =
+            (*env)->GetMethodID(e, printWriterClass.get(), "<init>", "(Ljava/io/Writer;)V");
+
+    scoped_local_ref<jobject> stringWriter(env,
+            (*env)->NewObject(e, stringWriterClass.get(), stringWriterCtor));
+    if (stringWriter.get() == NULL) {
+        return NULL;
+    }
+
+    jobject printWriter =
+            (*env)->NewObject(e, printWriterClass.get(), printWriterCtor, stringWriter.get());
+    if (printWriter == NULL) {
+        return NULL;
+    }
+
+    scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
+    jmethodID printStackTraceMethod =
+            (*env)->GetMethodID(e, exceptionClass.get(), "printStackTrace", "(Ljava/io/PrintWriter;)V");
+    (*env)->CallVoidMethod(e, exception, printStackTraceMethod, printWriter);
+
+    if ((*env)->ExceptionCheck(e)) {
+        return NULL;
+    }
+
+    scoped_local_ref<jstring> messageStr(env,
+            (jstring) (*env)->CallObjectMethod(e, stringWriter.get(), stringWriterToStringMethod));
+    if (messageStr.get() == NULL) {
+        return NULL;
+    }
+
+    const char* utfChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
+    if (utfChars == NULL) {
+        return NULL;
+    }
+
+    char* result = strdup(utfChars);
+    (*env)->ReleaseStringUTFChars(e, messageStr.get(), utfChars);
+    return result;
+}
+
+extern "C" int jniThrowException(C_JNIEnv* env, const char* className, const char* msg) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+
+    if ((*env)->ExceptionCheck(e)) {
+        /* TODO: consider creating the new exception with this as "cause" */
+        scoped_local_ref<jthrowable> exception(env, (*env)->ExceptionOccurred(e));
+        (*env)->ExceptionClear(e);
+
+        if (exception.get() != NULL) {
+            char* text = getExceptionSummary(env, exception.get());
+            LOGW("Discarding pending exception (%s) to throw %s", text, className);
+            free(text);
+        }
+    }
+
+    scoped_local_ref<jclass> exceptionClass(env, findClass(env, className));
+    if (exceptionClass.get() == NULL) {
+        LOGE("Unable to find exception class %s", className);
+        /* ClassNotFoundException now pending */
+        return -1;
+    }
+
+    if ((*env)->ThrowNew(e, exceptionClass.get(), msg) != JNI_OK) {
+        LOGE("Failed throwing '%s' '%s'", className, msg);
+        /* an exception, most likely OOM, will now be pending */
+        return -1;
+    }
+
+    return 0;
+}
+
+int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args) {
+    char msgBuf[512];
+    vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
+    return jniThrowException(env, className, msgBuf);
+}
+
+int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) {
+    return jniThrowException(env, "java/lang/NullPointerException", msg);
+}
+
+int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) {
+    return jniThrowException(env, "java/lang/RuntimeException", msg);
+}
+
+int jniThrowIOException(C_JNIEnv* env, int errnum) {
+    char buffer[80];
+    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
+    return jniThrowException(env, "java/io/IOException", message);
+}
+
+void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+
+    scoped_local_ref<jthrowable> currentException(env);
+    if (exception == NULL) {
+        exception = (*env)->ExceptionOccurred(e);
+        if (exception == NULL) {
+            return;
+        }
+
+        (*env)->ExceptionClear(e);
+        currentException.reset(exception);
+    }
+
+    char* buffer = getStackTrace(env, exception);
+    if (buffer == NULL) {
+        (*env)->ExceptionClear(e);
+        buffer = getExceptionSummary(env, exception);
+    }
+
+    __android_log_write(priority, tag, buffer);
+    free(buffer);
+
+    if (currentException.get() != NULL) {
+        (*env)->Throw(e, exception); // rethrow
+    }
+}
+
+const char* jniStrError(int errnum, char* buf, size_t buflen) {
+    // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
+    // char *strerror_r(int errnum, char *buf, size_t n);
+    char* ret = (char*) strerror_r(errnum, buf, buflen);
+    if (((int)ret) == 0) {
+        // POSIX strerror_r, success
+        return buf;
+    } else if (((int)ret) == -1) {
+        // POSIX strerror_r, failure
+        // (Strictly, POSIX only guarantees a value other than 0. The safest
+        // way to implement this function is to use C++ and overload on the
+        // type of strerror_r to accurately distinguish GNU from POSIX. But
+        // realistic implementations will always return -1.)
+        snprintf(buf, buflen, "errno %d", errnum);
+        return buf;
+    } else {
+        // glibc strerror_r returning a string
+        return ret;
+    }
+}
+
+static struct CachedFields {
+    jclass fileDescriptorClass;
+    jmethodID fileDescriptorCtor;
+    jfieldID descriptorField;
+} gCachedFields;
+
+int registerJniHelp(JNIEnv* env) {
+    gCachedFields.fileDescriptorClass =
+            reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass("java/io/FileDescriptor")));
+    if (gCachedFields.fileDescriptorClass == NULL) {
+        return -1;
+    }
+
+    gCachedFields.fileDescriptorCtor =
+            env->GetMethodID(gCachedFields.fileDescriptorClass, "<init>", "()V");
+    if (gCachedFields.fileDescriptorCtor == NULL) {
+        return -1;
+    }
+
+    gCachedFields.descriptorField =
+            env->GetFieldID(gCachedFields.fileDescriptorClass, "descriptor", "I");
+    if (gCachedFields.descriptorField == NULL) {
+        return -1;
+    }
+
+    return 0;
+}
+
+jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+    jobject fileDescriptor = (*env)->NewObject(e,
+            gCachedFields.fileDescriptorClass, gCachedFields.fileDescriptorCtor);
+    jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
+    return fileDescriptor;
+}
+
+int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+    return (*env)->GetIntField(e, fileDescriptor, gCachedFields.descriptorField);
+}
+
+void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+    (*env)->SetIntField(e, fileDescriptor, gCachedFields.descriptorField, value);
+}
+
+/*
+ * DO NOT USE THIS FUNCTION
+ *
+ * Get a pointer to the elements of a non-movable array.
+ *
+ * The semantics are similar to GetDirectBufferAddress.  Specifically, the VM
+ * guarantees that the array will not move, and the caller must ensure that
+ * it does not continue to use the pointer after the object is collected.
+ *
+ * We currently use an illegal sequence that trips up CheckJNI when
+ * the "forcecopy" mode is enabled.  We pass in a magic value to work
+ * around the problem.
+ *
+ * Returns NULL if the array is movable.
+ */
+#define kNoCopyMagic 0xd5aab57f     /* also in CheckJni.c */
+extern "C" jbyte* jniGetNonMovableArrayElements(C_JNIEnv* env, jarray arrayObj) {
+    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
+
+    jbyteArray byteArray = reinterpret_cast<jbyteArray>(arrayObj);
+
+    /*
+     * Normally the "isCopy" parameter is for a return value only, so the
+     * non-CheckJNI VM will ignore whatever we pass in.
+     */
+    uint32_t noCopy = kNoCopyMagic;
+    jbyte* result = (*env)->GetByteArrayElements(e, byteArray, reinterpret_cast<jboolean*>(&noCopy));
+
+    /*
+     * The non-CheckJNI implementation only cares about the array object,
+     * so we can replace the element pointer with the magic value.
+     */
+    (*env)->ReleaseByteArrayElements(e, byteArray, reinterpret_cast<jbyte*>(kNoCopyMagic), 0);
+    return result;
+}
diff --git a/libnativehelper/MODULE_LICENSE_APACHE2 b/libnativehelper/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libnativehelper/MODULE_LICENSE_APACHE2
diff --git a/libnativehelper/NOTICE b/libnativehelper/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libnativehelper/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libnativehelper/README b/libnativehelper/README
new file mode 100644
index 0000000..5a5f5d4
--- /dev/null
+++ b/libnativehelper/README
@@ -0,0 +1,11 @@
+Support functions for Android's class libraries
+
+
+These are VM-agnostic native functions that implement methods for system
+class libraries.  All code here:
+
+ - MUST not be associated with an android.* class (that code lives in
+   frameworks/base/).
+ - SHOULD be written in C rather than C++ where possible.
+
+Some helper functions are defined in include/nativehelper/JNIHelp.h.
diff --git a/libnativehelper/Register.cpp b/libnativehelper/Register.cpp
new file mode 100644
index 0000000..b6b1b1f
--- /dev/null
+++ b/libnativehelper/Register.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+extern int registerCoreLibrariesJni(JNIEnv* env);
+extern int registerJniHelp(JNIEnv* env);
+
+/*
+ * Register all methods for system classes.
+ */
+int jniRegisterSystemMethods(JNIEnv* env) {
+    // JniHelp depends on core library classes such as java.io.FileDescriptor.
+    return registerCoreLibrariesJni(env) != -1 && registerJniHelp(env) != -1;
+}
diff --git a/libnativehelper/include/nativehelper/JNIHelp.h b/libnativehelper/include/nativehelper/JNIHelp.h
new file mode 100644
index 0000000..aa98c2c
--- /dev/null
+++ b/libnativehelper/include/nativehelper/JNIHelp.h
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+/*
+ * JNI helper functions.
+ *
+ * This file may be included by C or C++ code, which is trouble because jni.h
+ * uses different typedefs for JNIEnv in each language.
+ */
+#ifndef NATIVEHELPER_JNIHELP_H_
+#define NATIVEHELPER_JNIHELP_H_
+
+#include "jni.h"
+#include "cutils/log.h"
+#include <unistd.h>
+
+#ifndef NELEM
+# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Register one or more native methods with a particular class.
+ * "className" looks like "java/lang/String".
+ */
+int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods);
+
+/*
+ * 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").
+ *
+ * If an exception is currently pending, we log a warning message and
+ * clear it.
+ *
+ * Returns 0 on success, nonzero if something failed (e.g. the exception
+ * class couldn't be found, so *an* exception will still be pending).
+ *
+ * Currently aborts the VM if it can't throw the exception.
+ */
+int jniThrowException(C_JNIEnv* env, const char* className, const char* msg);
+
+/*
+ * Throw a java.lang.NullPointerException, with an optional message.
+ */
+int jniThrowNullPointerException(C_JNIEnv* env, const char* msg);
+
+/*
+ * Throw a java.lang.RuntimeException, with an optional message.
+ */
+int jniThrowRuntimeException(C_JNIEnv* env, const char* msg);
+
+/*
+ * Throw a java.io.IOException, generating the message from errno.
+ */
+int jniThrowIOException(C_JNIEnv* env, int errnum);
+
+/*
+ * Return a pointer to a locale-dependent error string explaining errno
+ * value 'errnum'. The returned pointer may or may not be equal to 'buf'.
+ * This function is thread-safe (unlike strerror) and portable (unlike
+ * strerror_r).
+ */
+const char* jniStrError(int errnum, char* buf, size_t buflen);
+
+/*
+ * Returns a new java.io.FileDescriptor for the given int fd.
+ */
+jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd);
+
+/*
+ * Returns the int fd from a java.io.FileDescriptor.
+ */
+int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor);
+
+/*
+ * Sets the int fd in a java.io.FileDescriptor.
+ */
+void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value);
+
+/*
+ * Log a message and an exception.
+ * If exception is NULL, logs the current exception in the JNI environment.
+ */
+void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * For C++ code, we provide inlines that map to the C functions.  g++ always
+ * inlines these, even on non-optimized builds.
+ */
+#if defined(__cplusplus)
+inline int jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) {
+    return jniRegisterNativeMethods(&env->functions, className, gMethods, numMethods);
+}
+
+inline int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
+    return jniThrowException(&env->functions, className, msg);
+}
+
+extern "C" int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args);
+
+/*
+ * Equivalent to jniThrowException but with a printf-like format string and
+ * variable-length argument list. This is only available in C++.
+ */
+inline int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    return jniThrowExceptionFmt(&env->functions, className, fmt, args);
+    va_end(args);
+}
+
+inline int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
+    return jniThrowNullPointerException(&env->functions, msg);
+}
+
+inline int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
+    return jniThrowRuntimeException(&env->functions, msg);
+}
+
+inline int jniThrowIOException(JNIEnv* env, int errnum) {
+    return jniThrowIOException(&env->functions, errnum);
+}
+
+inline jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
+    return jniCreateFileDescriptor(&env->functions, fd);
+}
+
+inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
+    return jniGetFDFromFileDescriptor(&env->functions, fileDescriptor);
+}
+
+inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
+    jniSetFileDescriptorOfFD(&env->functions, fileDescriptor, value);
+}
+
+inline void jniLogException(JNIEnv* env, int priority, const char* tag, jthrowable exception = NULL) {
+    jniLogException(&env->functions, priority, tag, exception);
+}
+#endif
+
+/* Logging macros.
+ *
+ * Logs an exception.  If the exception is omitted or NULL, logs the current exception
+ * from the JNI environment, if any.
+ */
+#define LOG_EX(env, priority, tag, ...) \
+    IF_LOG(priority, tag) jniLogException(env, ANDROID_##priority, tag, ##__VA_ARGS__)
+#define LOGV_EX(env, ...) LOG_EX(env, LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define LOGD_EX(env, ...) LOG_EX(env, LOG_DEBUG, LOG_TAG, ##__VA_ARGS__)
+#define LOGI_EX(env, ...) LOG_EX(env, LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define LOGW_EX(env, ...) LOG_EX(env, LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define LOGE_EX(env, ...) LOG_EX(env, LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+#endif  /* NATIVEHELPER_JNIHELP_H_ */
diff --git a/libnativehelper/include/nativehelper/jni.h b/libnativehelper/include/nativehelper/jni.h
new file mode 100644
index 0000000..e4d74cf
--- /dev/null
+++ b/libnativehelper/include/nativehelper/jni.h
@@ -0,0 +1,1154 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * JNI specification, as defined by Sun:
+ * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html
+ *
+ * Everything here is expected to be VM-neutral.
+ */
+
+#ifndef JNI_H_
+#define JNI_H_
+
+#include <stdarg.h>
+
+/*
+ * Primitive types that match up with Java equivalents.
+ */
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>      /* C99 */
+typedef uint8_t         jboolean;       /* unsigned 8 bits */
+typedef int8_t          jbyte;          /* signed 8 bits */
+typedef uint16_t        jchar;          /* unsigned 16 bits */
+typedef int16_t         jshort;         /* signed 16 bits */
+typedef int32_t         jint;           /* signed 32 bits */
+typedef int64_t         jlong;          /* signed 64 bits */
+typedef float           jfloat;         /* 32-bit IEEE 754 */
+typedef double          jdouble;        /* 64-bit IEEE 754 */
+#else
+typedef unsigned char   jboolean;       /* unsigned 8 bits */
+typedef signed char     jbyte;          /* signed 8 bits */
+typedef unsigned short  jchar;          /* unsigned 16 bits */
+typedef short           jshort;         /* signed 16 bits */
+typedef int             jint;           /* signed 32 bits */
+typedef long long       jlong;          /* signed 64 bits */
+typedef float           jfloat;         /* 32-bit IEEE 754 */
+typedef double          jdouble;        /* 64-bit IEEE 754 */
+#endif
+
+/* "cardinal indices and sizes" */
+typedef jint            jsize;
+
+#ifdef __cplusplus
+/*
+ * Reference types, in C++
+ */
+class _jobject {};
+class _jclass : public _jobject {};
+class _jstring : public _jobject {};
+class _jarray : public _jobject {};
+class _jobjectArray : public _jarray {};
+class _jbooleanArray : public _jarray {};
+class _jbyteArray : public _jarray {};
+class _jcharArray : public _jarray {};
+class _jshortArray : public _jarray {};
+class _jintArray : public _jarray {};
+class _jlongArray : public _jarray {};
+class _jfloatArray : public _jarray {};
+class _jdoubleArray : public _jarray {};
+class _jthrowable : public _jobject {};
+
+typedef _jobject*       jobject;
+typedef _jclass*        jclass;
+typedef _jstring*       jstring;
+typedef _jarray*        jarray;
+typedef _jobjectArray*  jobjectArray;
+typedef _jbooleanArray* jbooleanArray;
+typedef _jbyteArray*    jbyteArray;
+typedef _jcharArray*    jcharArray;
+typedef _jshortArray*   jshortArray;
+typedef _jintArray*     jintArray;
+typedef _jlongArray*    jlongArray;
+typedef _jfloatArray*   jfloatArray;
+typedef _jdoubleArray*  jdoubleArray;
+typedef _jthrowable*    jthrowable;
+typedef _jobject*       jweak;
+
+
+#else /* not __cplusplus */
+
+/*
+ * Reference types, in C.
+ */
+typedef void*           jobject;
+typedef jobject         jclass;
+typedef jobject         jstring;
+typedef jobject         jarray;
+typedef jarray          jobjectArray;
+typedef jarray          jbooleanArray;
+typedef jarray          jbyteArray;
+typedef jarray          jcharArray;
+typedef jarray          jshortArray;
+typedef jarray          jintArray;
+typedef jarray          jlongArray;
+typedef jarray          jfloatArray;
+typedef jarray          jdoubleArray;
+typedef jobject         jthrowable;
+typedef jobject         jweak;
+
+#endif /* not __cplusplus */
+
+struct _jfieldID;                       /* opaque structure */
+typedef struct _jfieldID* jfieldID;     /* field IDs */
+
+struct _jmethodID;                      /* opaque structure */
+typedef struct _jmethodID* jmethodID;   /* method IDs */
+
+struct JNIInvokeInterface;
+
+typedef union jvalue {
+    jboolean    z;
+    jbyte       b;
+    jchar       c;
+    jshort      s;
+    jint        i;
+    jlong       j;
+    jfloat      f;
+    jdouble     d;
+    jobject     l;
+} jvalue;
+
+typedef enum jobjectRefType {
+    JNIInvalidRefType = 0,
+    JNILocalRefType = 1,
+    JNIGlobalRefType = 2,
+    JNIWeakGlobalRefType = 3
+} jobjectRefType;
+
+typedef struct {
+    const char* name;
+    const char* signature;
+    void*       fnPtr;
+} JNINativeMethod;
+
+struct _JNIEnv;
+struct _JavaVM;
+typedef const struct JNINativeInterface* C_JNIEnv;
+
+#if defined(__cplusplus)
+typedef _JNIEnv JNIEnv;
+typedef _JavaVM JavaVM;
+#else
+typedef const struct JNINativeInterface* JNIEnv;
+typedef const struct JNIInvokeInterface* JavaVM;
+#endif
+
+/*
+ * Table of interface function pointers.
+ */
+struct JNINativeInterface {
+    void*       reserved0;
+    void*       reserved1;
+    void*       reserved2;
+    void*       reserved3;
+
+    jint        (*GetVersion)(JNIEnv *);
+
+    jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
+                        jsize);
+    jclass      (*FindClass)(JNIEnv*, const char*);
+
+    jmethodID   (*FromReflectedMethod)(JNIEnv*, jobject);
+    jfieldID    (*FromReflectedField)(JNIEnv*, jobject);
+    /* spec doesn't show jboolean parameter */
+    jobject     (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);
+
+    jclass      (*GetSuperclass)(JNIEnv*, jclass);
+    jboolean    (*IsAssignableFrom)(JNIEnv*, jclass, jclass);
+
+    /* spec doesn't show jboolean parameter */
+    jobject     (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);
+
+    jint        (*Throw)(JNIEnv*, jthrowable);
+    jint        (*ThrowNew)(JNIEnv *, jclass, const char *);
+    jthrowable  (*ExceptionOccurred)(JNIEnv*);
+    void        (*ExceptionDescribe)(JNIEnv*);
+    void        (*ExceptionClear)(JNIEnv*);
+    void        (*FatalError)(JNIEnv*, const char*);
+
+    jint        (*PushLocalFrame)(JNIEnv*, jint);
+    jobject     (*PopLocalFrame)(JNIEnv*, jobject);
+
+    jobject     (*NewGlobalRef)(JNIEnv*, jobject);
+    void        (*DeleteGlobalRef)(JNIEnv*, jobject);
+    void        (*DeleteLocalRef)(JNIEnv*, jobject);
+    jboolean    (*IsSameObject)(JNIEnv*, jobject, jobject);
+
+    jobject     (*NewLocalRef)(JNIEnv*, jobject);
+    jint        (*EnsureLocalCapacity)(JNIEnv*, jint);
+
+    jobject     (*AllocObject)(JNIEnv*, jclass);
+    jobject     (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
+    jobject     (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);
+    jobject     (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*);
+
+    jclass      (*GetObjectClass)(JNIEnv*, jobject);
+    jboolean    (*IsInstanceOf)(JNIEnv*, jobject, jclass);
+    jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
+
+    jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jobject     (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jobject     (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jboolean    (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jboolean    (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jboolean    (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jbyte       (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jbyte       (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jbyte       (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jchar       (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jchar       (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jchar       (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jshort      (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jshort      (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jshort      (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jint        (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jint        (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jlong       (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jlong       (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jlong       (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jfloat      (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jfloat      (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jfloat      (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    jdouble     (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);
+    jdouble     (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    jdouble     (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
+    void        (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
+    void        (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
+
+    jobject     (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jobject     (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jobject     (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jboolean    (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jboolean    (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass,
+                         jmethodID, va_list);
+    jboolean    (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass,
+                         jmethodID, jvalue*);
+    jbyte       (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jbyte       (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jbyte       (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jchar       (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jchar       (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jchar       (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jshort      (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jshort      (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jshort      (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jint        (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jint        (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jint        (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jlong       (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jlong       (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jlong       (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jfloat      (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jfloat      (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jfloat      (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    jdouble     (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    jdouble     (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    jdouble     (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+    void        (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass,
+                        jmethodID, ...);
+    void        (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass,
+                        jmethodID, va_list);
+    void        (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass,
+                        jmethodID, jvalue*);
+
+    jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
+
+    jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
+    jboolean    (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
+    jbyte       (*GetByteField)(JNIEnv*, jobject, jfieldID);
+    jchar       (*GetCharField)(JNIEnv*, jobject, jfieldID);
+    jshort      (*GetShortField)(JNIEnv*, jobject, jfieldID);
+    jint        (*GetIntField)(JNIEnv*, jobject, jfieldID);
+    jlong       (*GetLongField)(JNIEnv*, jobject, jfieldID);
+    jfloat      (*GetFloatField)(JNIEnv*, jobject, jfieldID);
+    jdouble     (*GetDoubleField)(JNIEnv*, jobject, jfieldID);
+
+    void        (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
+    void        (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
+    void        (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
+    void        (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
+    void        (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
+    void        (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
+    void        (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
+    void        (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);
+    void        (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);
+
+    jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
+
+    jobject     (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jobject     (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jobject     (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jboolean    (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jboolean    (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID,
+                        va_list);
+    jboolean    (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID,
+                        jvalue*);
+    jbyte       (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jbyte       (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jbyte       (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jchar       (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jchar       (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jchar       (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jshort      (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jshort      (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jshort      (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jint        (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jint        (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jint        (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jlong       (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jlong       (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jlong       (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jfloat      (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jfloat      (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jfloat      (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    jdouble     (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...);
+    jdouble     (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    jdouble     (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+    void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
+    void        (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);
+    void        (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
+
+    jfieldID    (*GetStaticFieldID)(JNIEnv*, jclass, const char*,
+                        const char*);
+
+    jobject     (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);
+    jboolean    (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);
+    jbyte       (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);
+    jchar       (*GetStaticCharField)(JNIEnv*, jclass, jfieldID);
+    jshort      (*GetStaticShortField)(JNIEnv*, jclass, jfieldID);
+    jint        (*GetStaticIntField)(JNIEnv*, jclass, jfieldID);
+    jlong       (*GetStaticLongField)(JNIEnv*, jclass, jfieldID);
+    jfloat      (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID);
+    jdouble     (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID);
+
+    void        (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);
+    void        (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);
+    void        (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);
+    void        (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar);
+    void        (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort);
+    void        (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint);
+    void        (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong);
+    void        (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat);
+    void        (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble);
+
+    jstring     (*NewString)(JNIEnv*, const jchar*, jsize);
+    jsize       (*GetStringLength)(JNIEnv*, jstring);
+    const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);
+    void        (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);
+    jstring     (*NewStringUTF)(JNIEnv*, const char*);
+    jsize       (*GetStringUTFLength)(JNIEnv*, jstring);
+    /* JNI spec says this returns const jbyte*, but that's inconsistent */
+    const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);
+    void        (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);
+    jsize       (*GetArrayLength)(JNIEnv*, jarray);
+    jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);
+    jobject     (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);
+    void        (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);
+
+    jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);
+    jbyteArray    (*NewByteArray)(JNIEnv*, jsize);
+    jcharArray    (*NewCharArray)(JNIEnv*, jsize);
+    jshortArray   (*NewShortArray)(JNIEnv*, jsize);
+    jintArray     (*NewIntArray)(JNIEnv*, jsize);
+    jlongArray    (*NewLongArray)(JNIEnv*, jsize);
+    jfloatArray   (*NewFloatArray)(JNIEnv*, jsize);
+    jdoubleArray  (*NewDoubleArray)(JNIEnv*, jsize);
+
+    jboolean*   (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);
+    jbyte*      (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);
+    jchar*      (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);
+    jshort*     (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);
+    jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
+    jlong*      (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);
+    jfloat*     (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);
+    jdouble*    (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);
+
+    void        (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,
+                        jboolean*, jint);
+    void        (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray,
+                        jbyte*, jint);
+    void        (*ReleaseCharArrayElements)(JNIEnv*, jcharArray,
+                        jchar*, jint);
+    void        (*ReleaseShortArrayElements)(JNIEnv*, jshortArray,
+                        jshort*, jint);
+    void        (*ReleaseIntArrayElements)(JNIEnv*, jintArray,
+                        jint*, jint);
+    void        (*ReleaseLongArrayElements)(JNIEnv*, jlongArray,
+                        jlong*, jint);
+    void        (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray,
+                        jfloat*, jint);
+    void        (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,
+                        jdouble*, jint);
+
+    void        (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray,
+                        jsize, jsize, jboolean*);
+    void        (*GetByteArrayRegion)(JNIEnv*, jbyteArray,
+                        jsize, jsize, jbyte*);
+    void        (*GetCharArrayRegion)(JNIEnv*, jcharArray,
+                        jsize, jsize, jchar*);
+    void        (*GetShortArrayRegion)(JNIEnv*, jshortArray,
+                        jsize, jsize, jshort*);
+    void        (*GetIntArrayRegion)(JNIEnv*, jintArray,
+                        jsize, jsize, jint*);
+    void        (*GetLongArrayRegion)(JNIEnv*, jlongArray,
+                        jsize, jsize, jlong*);
+    void        (*GetFloatArrayRegion)(JNIEnv*, jfloatArray,
+                        jsize, jsize, jfloat*);
+    void        (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray,
+                        jsize, jsize, jdouble*);
+
+    /* spec shows these without const; some jni.h do, some don't */
+    void        (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray,
+                        jsize, jsize, const jboolean*);
+    void        (*SetByteArrayRegion)(JNIEnv*, jbyteArray,
+                        jsize, jsize, const jbyte*);
+    void        (*SetCharArrayRegion)(JNIEnv*, jcharArray,
+                        jsize, jsize, const jchar*);
+    void        (*SetShortArrayRegion)(JNIEnv*, jshortArray,
+                        jsize, jsize, const jshort*);
+    void        (*SetIntArrayRegion)(JNIEnv*, jintArray,
+                        jsize, jsize, const jint*);
+    void        (*SetLongArrayRegion)(JNIEnv*, jlongArray,
+                        jsize, jsize, const jlong*);
+    void        (*SetFloatArrayRegion)(JNIEnv*, jfloatArray,
+                        jsize, jsize, const jfloat*);
+    void        (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray,
+                        jsize, jsize, const jdouble*);
+
+    jint        (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,
+                        jint);
+    jint        (*UnregisterNatives)(JNIEnv*, jclass);
+    jint        (*MonitorEnter)(JNIEnv*, jobject);
+    jint        (*MonitorExit)(JNIEnv*, jobject);
+    jint        (*GetJavaVM)(JNIEnv*, JavaVM**);
+
+    void        (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*);
+    void        (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*);
+
+    void*       (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*);
+    void        (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint);
+
+    const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*);
+    void        (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*);
+
+    jweak       (*NewWeakGlobalRef)(JNIEnv*, jobject);
+    void        (*DeleteWeakGlobalRef)(JNIEnv*, jweak);
+
+    jboolean    (*ExceptionCheck)(JNIEnv*);
+
+    jobject     (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);
+    void*       (*GetDirectBufferAddress)(JNIEnv*, jobject);
+    jlong       (*GetDirectBufferCapacity)(JNIEnv*, jobject);
+
+    /* added in JNI 1.6 */
+    jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);
+};
+
+/*
+ * C++ object wrapper.
+ *
+ * This is usually overlaid on a C struct whose first element is a
+ * JNINativeInterface*.  We rely somewhat on compiler behavior.
+ */
+struct _JNIEnv {
+    /* do not rename this; it does not seem to be entirely opaque */
+    const struct JNINativeInterface* functions;
+
+#if defined(__cplusplus)
+
+    jint GetVersion()
+    { return functions->GetVersion(this); }
+
+    jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
+        jsize bufLen)
+    { return functions->DefineClass(this, name, loader, buf, bufLen); }
+
+    jclass FindClass(const char* name)
+    { return functions->FindClass(this, name); }
+
+    jmethodID FromReflectedMethod(jobject method)
+    { return functions->FromReflectedMethod(this, method); }
+
+    jfieldID FromReflectedField(jobject field)
+    { return functions->FromReflectedField(this, field); }
+
+    jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic)
+    { return functions->ToReflectedMethod(this, cls, methodID, isStatic); }
+
+    jclass GetSuperclass(jclass clazz)
+    { return functions->GetSuperclass(this, clazz); }
+
+    jboolean IsAssignableFrom(jclass clazz1, jclass clazz2)
+    { return functions->IsAssignableFrom(this, clazz1, clazz2); }
+
+    jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic)
+    { return functions->ToReflectedField(this, cls, fieldID, isStatic); }
+
+    jint Throw(jthrowable obj)
+    { return functions->Throw(this, obj); }
+
+    jint ThrowNew(jclass clazz, const char* message)
+    { return functions->ThrowNew(this, clazz, message); }
+
+    jthrowable ExceptionOccurred()
+    { return functions->ExceptionOccurred(this); }
+
+    void ExceptionDescribe()
+    { functions->ExceptionDescribe(this); }
+
+    void ExceptionClear()
+    { functions->ExceptionClear(this); }
+
+    void FatalError(const char* msg)
+    { functions->FatalError(this, msg); }
+
+    jint PushLocalFrame(jint capacity)
+    { return functions->PushLocalFrame(this, capacity); }
+
+    jobject PopLocalFrame(jobject result)
+    { return functions->PopLocalFrame(this, result); }
+
+    jobject NewGlobalRef(jobject obj)
+    { return functions->NewGlobalRef(this, obj); }
+
+    void DeleteGlobalRef(jobject globalRef)
+    { functions->DeleteGlobalRef(this, globalRef); }
+
+    void DeleteLocalRef(jobject localRef)
+    { functions->DeleteLocalRef(this, localRef); }
+
+    jboolean IsSameObject(jobject ref1, jobject ref2)
+    { return functions->IsSameObject(this, ref1, ref2); }
+
+    jobject NewLocalRef(jobject ref)
+    { return functions->NewLocalRef(this, ref); }
+
+    jint EnsureLocalCapacity(jint capacity)
+    { return functions->EnsureLocalCapacity(this, capacity); }
+
+    jobject AllocObject(jclass clazz)
+    { return functions->AllocObject(this, clazz); }
+
+    jobject NewObject(jclass clazz, jmethodID methodID, ...)
+    {
+        va_list args;
+        va_start(args, methodID);
+        jobject result = functions->NewObjectV(this, clazz, methodID, args);
+        va_end(args);
+        return result;
+    }
+
+    jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args)
+    { return functions->NewObjectV(this, clazz, methodID, args); }
+
+    jobject NewObjectA(jclass clazz, jmethodID methodID, jvalue* args)
+    { return functions->NewObjectA(this, clazz, methodID, args); }
+
+    jclass GetObjectClass(jobject obj)
+    { return functions->GetObjectClass(this, obj); }
+
+    jboolean IsInstanceOf(jobject obj, jclass clazz)
+    { return functions->IsInstanceOf(this, obj, clazz); }
+
+    jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
+    { return functions->GetMethodID(this, clazz, name, sig); }
+
+#define CALL_TYPE_METHOD(_jtype, _jname)                                    \
+    _jtype Call##_jname##Method(jobject obj, jmethodID methodID, ...)       \
+    {                                                                       \
+        _jtype result;                                                      \
+        va_list args;                                                       \
+        va_start(args, methodID);                                           \
+        result = functions->Call##_jname##MethodV(this, obj, methodID,      \
+                    args);                                                  \
+        va_end(args);                                                       \
+        return result;                                                      \
+    }
+#define CALL_TYPE_METHODV(_jtype, _jname)                                   \
+    _jtype Call##_jname##MethodV(jobject obj, jmethodID methodID,           \
+        va_list args)                                                       \
+    { return functions->Call##_jname##MethodV(this, obj, methodID, args); }
+#define CALL_TYPE_METHODA(_jtype, _jname)                                   \
+    _jtype Call##_jname##MethodA(jobject obj, jmethodID methodID,           \
+        jvalue* args)                                                       \
+    { return functions->Call##_jname##MethodA(this, obj, methodID, args); }
+
+#define CALL_TYPE(_jtype, _jname)                                           \
+    CALL_TYPE_METHOD(_jtype, _jname)                                        \
+    CALL_TYPE_METHODV(_jtype, _jname)                                       \
+    CALL_TYPE_METHODA(_jtype, _jname)
+
+    CALL_TYPE(jobject, Object)
+    CALL_TYPE(jboolean, Boolean)
+    CALL_TYPE(jbyte, Byte)
+    CALL_TYPE(jchar, Char)
+    CALL_TYPE(jshort, Short)
+    CALL_TYPE(jint, Int)
+    CALL_TYPE(jlong, Long)
+    CALL_TYPE(jfloat, Float)
+    CALL_TYPE(jdouble, Double)
+
+    void CallVoidMethod(jobject obj, jmethodID methodID, ...)
+    {
+        va_list args;
+        va_start(args, methodID);
+        functions->CallVoidMethodV(this, obj, methodID, args);
+        va_end(args);
+    }
+    void CallVoidMethodV(jobject obj, jmethodID methodID, va_list args)
+    { functions->CallVoidMethodV(this, obj, methodID, args); }
+    void CallVoidMethodA(jobject obj, jmethodID methodID, jvalue* args)
+    { functions->CallVoidMethodA(this, obj, methodID, args); }
+
+#define CALL_NONVIRT_TYPE_METHOD(_jtype, _jname)                            \
+    _jtype CallNonvirtual##_jname##Method(jobject obj, jclass clazz,        \
+        jmethodID methodID, ...)                                            \
+    {                                                                       \
+        _jtype result;                                                      \
+        va_list args;                                                       \
+        va_start(args, methodID);                                           \
+        result = functions->CallNonvirtual##_jname##MethodV(this, obj,      \
+                    clazz, methodID, args);                                 \
+        va_end(args);                                                       \
+        return result;                                                      \
+    }
+#define CALL_NONVIRT_TYPE_METHODV(_jtype, _jname)                           \
+    _jtype CallNonvirtual##_jname##MethodV(jobject obj, jclass clazz,       \
+        jmethodID methodID, va_list args)                                   \
+    { return functions->CallNonvirtual##_jname##MethodV(this, obj, clazz,   \
+        methodID, args); }
+#define CALL_NONVIRT_TYPE_METHODA(_jtype, _jname)                           \
+    _jtype CallNonvirtual##_jname##MethodA(jobject obj, jclass clazz,       \
+        jmethodID methodID, jvalue* args)                                   \
+    { return functions->CallNonvirtual##_jname##MethodA(this, obj, clazz,   \
+        methodID, args); }
+
+#define CALL_NONVIRT_TYPE(_jtype, _jname)                                   \
+    CALL_NONVIRT_TYPE_METHOD(_jtype, _jname)                                \
+    CALL_NONVIRT_TYPE_METHODV(_jtype, _jname)                               \
+    CALL_NONVIRT_TYPE_METHODA(_jtype, _jname)
+
+    CALL_NONVIRT_TYPE(jobject, Object)
+    CALL_NONVIRT_TYPE(jboolean, Boolean)
+    CALL_NONVIRT_TYPE(jbyte, Byte)
+    CALL_NONVIRT_TYPE(jchar, Char)
+    CALL_NONVIRT_TYPE(jshort, Short)
+    CALL_NONVIRT_TYPE(jint, Int)
+    CALL_NONVIRT_TYPE(jlong, Long)
+    CALL_NONVIRT_TYPE(jfloat, Float)
+    CALL_NONVIRT_TYPE(jdouble, Double)
+
+    void CallNonvirtualVoidMethod(jobject obj, jclass clazz,
+        jmethodID methodID, ...)
+    {
+        va_list args;
+        va_start(args, methodID);
+        functions->CallNonvirtualVoidMethodV(this, obj, clazz, methodID, args);
+        va_end(args);
+    }
+    void CallNonvirtualVoidMethodV(jobject obj, jclass clazz,
+        jmethodID methodID, va_list args)
+    { functions->CallNonvirtualVoidMethodV(this, obj, clazz, methodID, args); }
+    void CallNonvirtualVoidMethodA(jobject obj, jclass clazz,
+        jmethodID methodID, jvalue* args)
+    { functions->CallNonvirtualVoidMethodA(this, obj, clazz, methodID, args); }
+
+    jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
+    { return functions->GetFieldID(this, clazz, name, sig); }
+
+    jobject GetObjectField(jobject obj, jfieldID fieldID)
+    { return functions->GetObjectField(this, obj, fieldID); }
+    jboolean GetBooleanField(jobject obj, jfieldID fieldID)
+    { return functions->GetBooleanField(this, obj, fieldID); }
+    jbyte GetByteField(jobject obj, jfieldID fieldID)
+    { return functions->GetByteField(this, obj, fieldID); }
+    jchar GetCharField(jobject obj, jfieldID fieldID)
+    { return functions->GetCharField(this, obj, fieldID); }
+    jshort GetShortField(jobject obj, jfieldID fieldID)
+    { return functions->GetShortField(this, obj, fieldID); }
+    jint GetIntField(jobject obj, jfieldID fieldID)
+    { return functions->GetIntField(this, obj, fieldID); }
+    jlong GetLongField(jobject obj, jfieldID fieldID)
+    { return functions->GetLongField(this, obj, fieldID); }
+    jfloat GetFloatField(jobject obj, jfieldID fieldID)
+    { return functions->GetFloatField(this, obj, fieldID); }
+    jdouble GetDoubleField(jobject obj, jfieldID fieldID)
+    { return functions->GetDoubleField(this, obj, fieldID); }
+
+    void SetObjectField(jobject obj, jfieldID fieldID, jobject value)
+    { functions->SetObjectField(this, obj, fieldID, value); }
+    void SetBooleanField(jobject obj, jfieldID fieldID, jboolean value)
+    { functions->SetBooleanField(this, obj, fieldID, value); }
+    void SetByteField(jobject obj, jfieldID fieldID, jbyte value)
+    { functions->SetByteField(this, obj, fieldID, value); }
+    void SetCharField(jobject obj, jfieldID fieldID, jchar value)
+    { functions->SetCharField(this, obj, fieldID, value); }
+    void SetShortField(jobject obj, jfieldID fieldID, jshort value)
+    { functions->SetShortField(this, obj, fieldID, value); }
+    void SetIntField(jobject obj, jfieldID fieldID, jint value)
+    { functions->SetIntField(this, obj, fieldID, value); }
+    void SetLongField(jobject obj, jfieldID fieldID, jlong value)
+    { functions->SetLongField(this, obj, fieldID, value); }
+    void SetFloatField(jobject obj, jfieldID fieldID, jfloat value)
+    { functions->SetFloatField(this, obj, fieldID, value); }
+    void SetDoubleField(jobject obj, jfieldID fieldID, jdouble value)
+    { functions->SetDoubleField(this, obj, fieldID, value); }
+
+    jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)
+    { return functions->GetStaticMethodID(this, clazz, name, sig); }
+
+#define CALL_STATIC_TYPE_METHOD(_jtype, _jname)                             \
+    _jtype CallStatic##_jname##Method(jclass clazz, jmethodID methodID,     \
+        ...)                                                                \
+    {                                                                       \
+        _jtype result;                                                      \
+        va_list args;                                                       \
+        va_start(args, methodID);                                           \
+        result = functions->CallStatic##_jname##MethodV(this, clazz,        \
+                    methodID, args);                                        \
+        va_end(args);                                                       \
+        return result;                                                      \
+    }
+#define CALL_STATIC_TYPE_METHODV(_jtype, _jname)                            \
+    _jtype CallStatic##_jname##MethodV(jclass clazz, jmethodID methodID,    \
+        va_list args)                                                       \
+    { return functions->CallStatic##_jname##MethodV(this, clazz, methodID,  \
+        args); }
+#define CALL_STATIC_TYPE_METHODA(_jtype, _jname)                            \
+    _jtype CallStatic##_jname##MethodA(jclass clazz, jmethodID methodID,    \
+        jvalue* args)                                                       \
+    { return functions->CallStatic##_jname##MethodA(this, clazz, methodID,  \
+        args); }
+
+#define CALL_STATIC_TYPE(_jtype, _jname)                                    \
+    CALL_STATIC_TYPE_METHOD(_jtype, _jname)                                 \
+    CALL_STATIC_TYPE_METHODV(_jtype, _jname)                                \
+    CALL_STATIC_TYPE_METHODA(_jtype, _jname)
+
+    CALL_STATIC_TYPE(jobject, Object)
+    CALL_STATIC_TYPE(jboolean, Boolean)
+    CALL_STATIC_TYPE(jbyte, Byte)
+    CALL_STATIC_TYPE(jchar, Char)
+    CALL_STATIC_TYPE(jshort, Short)
+    CALL_STATIC_TYPE(jint, Int)
+    CALL_STATIC_TYPE(jlong, Long)
+    CALL_STATIC_TYPE(jfloat, Float)
+    CALL_STATIC_TYPE(jdouble, Double)
+
+    void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
+    {
+        va_list args;
+        va_start(args, methodID);
+        functions->CallStaticVoidMethodV(this, clazz, methodID, args);
+        va_end(args);
+    }
+    void CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args)
+    { functions->CallStaticVoidMethodV(this, clazz, methodID, args); }
+    void CallStaticVoidMethodA(jclass clazz, jmethodID methodID, jvalue* args)
+    { functions->CallStaticVoidMethodA(this, clazz, methodID, args); }
+
+    jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig)
+    { return functions->GetStaticFieldID(this, clazz, name, sig); }
+
+    jobject GetStaticObjectField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticObjectField(this, clazz, fieldID); }
+    jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticBooleanField(this, clazz, fieldID); }
+    jbyte GetStaticByteField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticByteField(this, clazz, fieldID); }
+    jchar GetStaticCharField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticCharField(this, clazz, fieldID); }
+    jshort GetStaticShortField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticShortField(this, clazz, fieldID); }
+    jint GetStaticIntField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticIntField(this, clazz, fieldID); }
+    jlong GetStaticLongField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticLongField(this, clazz, fieldID); }
+    jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticFloatField(this, clazz, fieldID); }
+    jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID)
+    { return functions->GetStaticDoubleField(this, clazz, fieldID); }
+
+    void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value)
+    { functions->SetStaticObjectField(this, clazz, fieldID, value); }
+    void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value)
+    { functions->SetStaticBooleanField(this, clazz, fieldID, value); }
+    void SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value)
+    { functions->SetStaticByteField(this, clazz, fieldID, value); }
+    void SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value)
+    { functions->SetStaticCharField(this, clazz, fieldID, value); }
+    void SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value)
+    { functions->SetStaticShortField(this, clazz, fieldID, value); }
+    void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value)
+    { functions->SetStaticIntField(this, clazz, fieldID, value); }
+    void SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value)
+    { functions->SetStaticLongField(this, clazz, fieldID, value); }
+    void SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value)
+    { functions->SetStaticFloatField(this, clazz, fieldID, value); }
+    void SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value)
+    { functions->SetStaticDoubleField(this, clazz, fieldID, value); }
+
+    jstring NewString(const jchar* unicodeChars, jsize len)
+    { return functions->NewString(this, unicodeChars, len); }
+
+    jsize GetStringLength(jstring string)
+    { return functions->GetStringLength(this, string); }
+
+    const jchar* GetStringChars(jstring string, jboolean* isCopy)
+    { return functions->GetStringChars(this, string, isCopy); }
+
+    void ReleaseStringChars(jstring string, const jchar* chars)
+    { functions->ReleaseStringChars(this, string, chars); }
+
+    jstring NewStringUTF(const char* bytes)
+    { return functions->NewStringUTF(this, bytes); }
+
+    jsize GetStringUTFLength(jstring string)
+    { return functions->GetStringUTFLength(this, string); }
+
+    const char* GetStringUTFChars(jstring string, jboolean* isCopy)
+    { return functions->GetStringUTFChars(this, string, isCopy); }
+
+    void ReleaseStringUTFChars(jstring string, const char* utf)
+    { functions->ReleaseStringUTFChars(this, string, utf); }
+
+    jsize GetArrayLength(jarray array)
+    { return functions->GetArrayLength(this, array); }
+
+    jobjectArray NewObjectArray(jsize length, jclass elementClass,
+        jobject initialElement)
+    { return functions->NewObjectArray(this, length, elementClass,
+        initialElement); }
+
+    jobject GetObjectArrayElement(jobjectArray array, jsize index)
+    { return functions->GetObjectArrayElement(this, array, index); }
+
+    void SetObjectArrayElement(jobjectArray array, jsize index, jobject value)
+    { functions->SetObjectArrayElement(this, array, index, value); }
+
+    jbooleanArray NewBooleanArray(jsize length)
+    { return functions->NewBooleanArray(this, length); }
+    jbyteArray NewByteArray(jsize length)
+    { return functions->NewByteArray(this, length); }
+    jcharArray NewCharArray(jsize length)
+    { return functions->NewCharArray(this, length); }
+    jshortArray NewShortArray(jsize length)
+    { return functions->NewShortArray(this, length); }
+    jintArray NewIntArray(jsize length)
+    { return functions->NewIntArray(this, length); }
+    jlongArray NewLongArray(jsize length)
+    { return functions->NewLongArray(this, length); }
+    jfloatArray NewFloatArray(jsize length)
+    { return functions->NewFloatArray(this, length); }
+    jdoubleArray NewDoubleArray(jsize length)
+    { return functions->NewDoubleArray(this, length); }
+
+    jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy)
+    { return functions->GetBooleanArrayElements(this, array, isCopy); }
+    jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy)
+    { return functions->GetByteArrayElements(this, array, isCopy); }
+    jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy)
+    { return functions->GetCharArrayElements(this, array, isCopy); }
+    jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy)
+    { return functions->GetShortArrayElements(this, array, isCopy); }
+    jint* GetIntArrayElements(jintArray array, jboolean* isCopy)
+    { return functions->GetIntArrayElements(this, array, isCopy); }
+    jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy)
+    { return functions->GetLongArrayElements(this, array, isCopy); }
+    jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy)
+    { return functions->GetFloatArrayElements(this, array, isCopy); }
+    jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy)
+    { return functions->GetDoubleArrayElements(this, array, isCopy); }
+
+    void ReleaseBooleanArrayElements(jbooleanArray array, jboolean* elems,
+        jint mode)
+    { functions->ReleaseBooleanArrayElements(this, array, elems, mode); }
+    void ReleaseByteArrayElements(jbyteArray array, jbyte* elems,
+        jint mode)
+    { functions->ReleaseByteArrayElements(this, array, elems, mode); }
+    void ReleaseCharArrayElements(jcharArray array, jchar* elems,
+        jint mode)
+    { functions->ReleaseCharArrayElements(this, array, elems, mode); }
+    void ReleaseShortArrayElements(jshortArray array, jshort* elems,
+        jint mode)
+    { functions->ReleaseShortArrayElements(this, array, elems, mode); }
+    void ReleaseIntArrayElements(jintArray array, jint* elems,
+        jint mode)
+    { functions->ReleaseIntArrayElements(this, array, elems, mode); }
+    void ReleaseLongArrayElements(jlongArray array, jlong* elems,
+        jint mode)
+    { functions->ReleaseLongArrayElements(this, array, elems, mode); }
+    void ReleaseFloatArrayElements(jfloatArray array, jfloat* elems,
+        jint mode)
+    { functions->ReleaseFloatArrayElements(this, array, elems, mode); }
+    void ReleaseDoubleArrayElements(jdoubleArray array, jdouble* elems,
+        jint mode)
+    { functions->ReleaseDoubleArrayElements(this, array, elems, mode); }
+
+    void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,
+        jboolean* buf)
+    { functions->GetBooleanArrayRegion(this, array, start, len, buf); }
+    void GetByteArrayRegion(jbyteArray array, jsize start, jsize len,
+        jbyte* buf)
+    { functions->GetByteArrayRegion(this, array, start, len, buf); }
+    void GetCharArrayRegion(jcharArray array, jsize start, jsize len,
+        jchar* buf)
+    { functions->GetCharArrayRegion(this, array, start, len, buf); }
+    void GetShortArrayRegion(jshortArray array, jsize start, jsize len,
+        jshort* buf)
+    { functions->GetShortArrayRegion(this, array, start, len, buf); }
+    void GetIntArrayRegion(jintArray array, jsize start, jsize len,
+        jint* buf)
+    { functions->GetIntArrayRegion(this, array, start, len, buf); }
+    void GetLongArrayRegion(jlongArray array, jsize start, jsize len,
+        jlong* buf)
+    { functions->GetLongArrayRegion(this, array, start, len, buf); }
+    void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len,
+        jfloat* buf)
+    { functions->GetFloatArrayRegion(this, array, start, len, buf); }
+    void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
+        jdouble* buf)
+    { functions->GetDoubleArrayRegion(this, array, start, len, buf); }
+
+    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,
+        const jboolean* buf)
+    { functions->SetBooleanArrayRegion(this, array, start, len, buf); }
+    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,
+        const jbyte* buf)
+    { functions->SetByteArrayRegion(this, array, start, len, buf); }
+    void SetCharArrayRegion(jcharArray array, jsize start, jsize len,
+        const jchar* buf)
+    { functions->SetCharArrayRegion(this, array, start, len, buf); }
+    void SetShortArrayRegion(jshortArray array, jsize start, jsize len,
+        const jshort* buf)
+    { functions->SetShortArrayRegion(this, array, start, len, buf); }
+    void SetIntArrayRegion(jintArray array, jsize start, jsize len,
+        const jint* buf)
+    { functions->SetIntArrayRegion(this, array, start, len, buf); }
+    void SetLongArrayRegion(jlongArray array, jsize start, jsize len,
+        const jlong* buf)
+    { functions->SetLongArrayRegion(this, array, start, len, buf); }
+    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,
+        const jfloat* buf)
+    { functions->SetFloatArrayRegion(this, array, start, len, buf); }
+    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
+        const jdouble* buf)
+    { functions->SetDoubleArrayRegion(this, array, start, len, buf); }
+
+    jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
+        jint nMethods)
+    { return functions->RegisterNatives(this, clazz, methods, nMethods); }
+
+    jint UnregisterNatives(jclass clazz)
+    { return functions->UnregisterNatives(this, clazz); }
+
+    jint MonitorEnter(jobject obj)
+    { return functions->MonitorEnter(this, obj); }
+
+    jint MonitorExit(jobject obj)
+    { return functions->MonitorExit(this, obj); }
+
+    jint GetJavaVM(JavaVM** vm)
+    { return functions->GetJavaVM(this, vm); }
+
+    void GetStringRegion(jstring str, jsize start, jsize len, jchar* buf)
+    { functions->GetStringRegion(this, str, start, len, buf); }
+
+    void GetStringUTFRegion(jstring str, jsize start, jsize len, char* buf)
+    { return functions->GetStringUTFRegion(this, str, start, len, buf); }
+
+    void* GetPrimitiveArrayCritical(jarray array, jboolean* isCopy)
+    { return functions->GetPrimitiveArrayCritical(this, array, isCopy); }
+
+    void ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode)
+    { functions->ReleasePrimitiveArrayCritical(this, array, carray, mode); }
+
+    const jchar* GetStringCritical(jstring string, jboolean* isCopy)
+    { return functions->GetStringCritical(this, string, isCopy); }
+
+    void ReleaseStringCritical(jstring string, const jchar* carray)
+    { functions->ReleaseStringCritical(this, string, carray); }
+
+    jweak NewWeakGlobalRef(jobject obj)
+    { return functions->NewWeakGlobalRef(this, obj); }
+
+    void DeleteWeakGlobalRef(jweak obj)
+    { functions->DeleteWeakGlobalRef(this, obj); }
+
+    jboolean ExceptionCheck()
+    { return functions->ExceptionCheck(this); }
+
+    jobject NewDirectByteBuffer(void* address, jlong capacity)
+    { return functions->NewDirectByteBuffer(this, address, capacity); }
+
+    void* GetDirectBufferAddress(jobject buf)
+    { return functions->GetDirectBufferAddress(this, buf); }
+
+    jlong GetDirectBufferCapacity(jobject buf)
+    { return functions->GetDirectBufferCapacity(this, buf); }
+
+    /* added in JNI 1.6 */
+    jobjectRefType GetObjectRefType(jobject obj)
+    { return functions->GetObjectRefType(this, obj); }
+#endif /*__cplusplus*/
+};
+
+
+/*
+ * JNI invocation interface.
+ */
+struct JNIInvokeInterface {
+    void*       reserved0;
+    void*       reserved1;
+    void*       reserved2;
+
+    jint        (*DestroyJavaVM)(JavaVM*);
+    jint        (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);
+    jint        (*DetachCurrentThread)(JavaVM*);
+    jint        (*GetEnv)(JavaVM*, void**, jint);
+    jint        (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
+};
+
+/*
+ * C++ version.
+ */
+struct _JavaVM {
+    const struct JNIInvokeInterface* functions;
+
+#if defined(__cplusplus)
+    jint DestroyJavaVM()
+    { return functions->DestroyJavaVM(this); }
+    jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
+    { return functions->AttachCurrentThread(this, p_env, thr_args); }
+    jint DetachCurrentThread()
+    { return functions->DetachCurrentThread(this); }
+    jint GetEnv(void** env, jint version)
+    { return functions->GetEnv(this, env, version); }
+    jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
+    { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
+#endif /*__cplusplus*/
+};
+
+struct JavaVMAttachArgs {
+    jint        version;    /* must be >= JNI_VERSION_1_2 */
+    const char* name;       /* NULL or name of thread as modified UTF-8 str */
+    jobject     group;      /* global ref of a ThreadGroup object, or NULL */
+};
+typedef struct JavaVMAttachArgs JavaVMAttachArgs;
+
+/*
+ * JNI 1.2+ initialization.  (As of 1.6, the pre-1.2 structures are no
+ * longer supported.)
+ */
+typedef struct JavaVMOption {
+    const char* optionString;
+    void*       extraInfo;
+} JavaVMOption;
+
+typedef struct JavaVMInitArgs {
+    jint        version;    /* use JNI_VERSION_1_2 or later */
+
+    jint        nOptions;
+    JavaVMOption* options;
+    jboolean    ignoreUnrecognized;
+} JavaVMInitArgs;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * VM initialization functions.
+ *
+ * Note these are the only symbols exported for JNI by the VM.
+ */
+jint JNI_GetDefaultJavaVMInitArgs(void*);
+jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
+jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
+
+#define JNIIMPORT
+#define JNIEXPORT  __attribute__ ((visibility ("default")))
+#define JNICALL
+
+/*
+ * Prototypes for functions exported by loadable shared libs.  These are
+ * called by JNI, not provided by JNI.
+ */
+JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
+JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Manifest constants.
+ */
+#define JNI_FALSE   0
+#define JNI_TRUE    1
+
+#define JNI_VERSION_1_1 0x00010001
+#define JNI_VERSION_1_2 0x00010002
+#define JNI_VERSION_1_4 0x00010004
+#define JNI_VERSION_1_6 0x00010006
+
+#define JNI_OK          (0)         /* no error */
+#define JNI_ERR         (-1)        /* generic error */
+#define JNI_EDETACHED   (-2)        /* thread detached from the VM */
+#define JNI_EVERSION    (-3)        /* JNI version error */
+
+#define JNI_COMMIT      1           /* copy content, do not free buffer */
+#define JNI_ABORT       2           /* free buffer w/o copying back */
+
+#endif  /* JNI_H_ */
diff --git a/opcode-gen/README.txt b/opcode-gen/README.txt
new file mode 100644
index 0000000..a210842
--- /dev/null
+++ b/opcode-gen/README.txt
@@ -0,0 +1,74 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---------------------------------------------------------------------
+Notes on updating the sets of defined opcodes and instruction formats
+---------------------------------------------------------------------
+
+##########
+
+If you want to add, delete, or change opcodes:
+
+* Update the file bytecode.txt, in this directory.
+
+* Run the regen-all script, in this directory. This will regenerate a
+  number of tables, definitions, and declarations in the code, in
+  dalvik/dx, dalvik/libdex, and libcore/dalvik.
+
+* Implement/update the opcode in C in vm/mterp/c/...
+  * Verify new code by running with "dalvik.vm.execution-mode = int:portable"
+    or "-Xint:portable".
+
+* Implement/update the instruction in assembly in vm/mterp/{arm*,x86*}/...
+  * Verify by enabling the assembly (e.g. ARM) handler for that instruction
+    in mterp/config-* and running "int:fast" as above.
+
+* Implement/update the instruction in
+  vm/compiler/codegen/{arm,x86}/CodegenDriver.c.
+
+* Rebuild the interpreter code. See the notes in vm/mterp/ReadMe.txt for
+  details.
+
+* Look in the directory vm/analysis at the files CodeVerify.c,
+  DexVerify.c, and Optimize.c. You may need to update them to account
+  for your changes.
+  * If you change anything here, be sure to try running the system with
+    the verifier enabled (which is in fact the default).
+
+##########
+
+If you want to add, delete, or change instruction formats:
+
+This is a more manual affair than changing opcodes.
+
+* Update the file bytecode.txt, and run regen-all, as per above.
+
+* Update the instruction format list in libdex/InstrUtils.h.
+
+* Update dexDecodeInstruction() in libdex/InstrUtils.c.
+
+* Update dumpInstruction() and its helper code in dexdump/DexDump.c.
+
+* Update the switch inside dvmCompilerMIR2LIR() in
+  vm/compiler/codegen/{arm,x86}/CodegenDriver.c. (There may be other
+  architectures to deal with too.)
+
+##########
+
+Testing your work:
+
+The Dalvik VM tests (in the vm/tests directory) provide a convenient
+way to test most of the above without doing any rebuilds. In
+particular, test 003-omnibus-opcodes will exercise most of the
+opcodes.
diff --git a/opcode-gen/bytecode.txt b/opcode-gen/bytecode.txt
new file mode 100644
index 0000000..89b8c83
--- /dev/null
+++ b/opcode-gen/bytecode.txt
@@ -0,0 +1,410 @@
+# 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.
+
+#
+# Bytecode definition file
+#
+
+# One line per instruction format family. Each line consists of a
+# series of instruction formats that all take (potentially) compatible
+# arguments. The order is the preferred order (most to least
+# preferable) of formats, when more than one opcode could be used for
+# a given instruction's arguments.
+#
+# Note: The family that starts with 12x has a mix of both two- and
+# three- register formats. This is because some of the two-register
+# opcodes effectively take three, with a destination and two sources
+# where the destination and one of the sources have to be the same.
+
+# Regular formats
+format 10t 20t 30t
+format 10x
+format 11n 21s 21h 31i 51l
+format 11x
+format 12x 22x 23x 32x 33x  # See note, above.
+format 21c 31c 41c
+format 21t 31t
+format 22b 22s 32s
+format 22c 52c
+format 22t
+format 35c 3rc 5rc
+
+# Optimized formats
+format 00x 
+format 20bc
+format 22cs
+format 35mi
+format 35ms
+format 3rmi
+format 3rms
+format 40sc
+
+# One line per opcode. Columns are:
+#   hex for opcode
+#   opcode name
+#   format
+#   has result register; one of:
+#     y
+#     n
+#   index type; one of:
+#     unknown -- used for undefined opcodes and breakpoint
+#     none
+#     varies
+#     type-ref
+#     string-ref
+#     method-ref
+#     field-ref
+#     inline-method
+#     vtable-offset
+#     field-offset
+#   flags; pipe-combined combo of one or more of:
+#     optimized     -- optimized; not to be included in unoptimized dex files
+#     branch        -- might branch to an address
+#     continue      -- might continue to the next address in sequence
+#     switch        -- is a switch
+#     throw         -- might throw an exception
+#     return        -- is a return from method
+#     invoke        -- is a method invoke; this is only used for true
+#                      method invokes and notably *not* vm-implemented
+#                      execute-inline nor the nop-equivalent
+#                      invoke-direct-empty
+
+#
+# Regular opcodes (with a couple holes)
+#
+
+op   00 nop                         10x  n none          continue
+op   01 move                        12x  y none          continue
+op   02 move/from16                 22x  y none          continue
+op   03 move/16                     32x  y none          continue
+op   04 move-wide                   12x  y none          continue
+op   05 move-wide/from16            22x  y none          continue
+op   06 move-wide/16                32x  y none          continue
+op   07 move-object                 12x  y none          continue
+op   08 move-object/from16          22x  y none          continue
+op   09 move-object/16              32x  y none          continue
+op   0a move-result                 11x  y none          continue
+op   0b move-result-wide            11x  y none          continue
+op   0c move-result-object          11x  y none          continue
+op   0d move-exception              11x  y none          continue
+op   0e return-void                 10x  n none          return
+op   0f return                      11x  n none          return
+op   10 return-wide                 11x  n none          return
+op   11 return-object               11x  n none          return
+op   12 const/4                     11n  y none          continue
+op   13 const/16                    21s  y none          continue
+op   14 const                       31i  y none          continue
+op   15 const/high16                21h  y none          continue
+op   16 const-wide/16               21s  y none          continue
+op   17 const-wide/32               31i  y none          continue
+op   18 const-wide                  51l  y none          continue
+op   19 const-wide/high16           21h  y none          continue
+op   1a const-string                21c  y string-ref    continue|throw
+op   1b const-string/jumbo          31c  y string-ref    continue|throw
+op   1c const-class                 21c  y type-ref      continue|throw
+op   1d monitor-enter               11x  n none          continue|throw
+op   1e monitor-exit                11x  n none          continue|throw
+op   1f check-cast                  21c  y type-ref      continue|throw
+op   20 instance-of                 22c  y type-ref      continue|throw
+op   21 array-length                12x  y none          continue|throw
+op   22 new-instance                21c  y type-ref      continue|throw
+op   23 new-array                   22c  y type-ref      continue|throw
+op   24 filled-new-array            35c  n type-ref      continue|throw
+op   25 filled-new-array/range      3rc  n type-ref      continue|throw
+op   26 fill-array-data             31t  n none          continue
+op   27 throw                       11x  n none          throw
+op   28 goto                        10t  n none          branch
+op   29 goto/16                     20t  n none          branch
+op   2a goto/32                     30t  n none          branch
+op   2b packed-switch               31t  n none          continue|switch
+op   2c sparse-switch               31t  n none          continue|switch
+op   2d cmpl-float                  23x  y none          continue
+op   2e cmpg-float                  23x  y none          continue
+op   2f cmpl-double                 23x  y none          continue
+op   30 cmpg-double                 23x  y none          continue
+op   31 cmp-long                    23x  y none          continue
+op   32 if-eq                       22t  n none          continue|branch
+op   33 if-ne                       22t  n none          continue|branch
+op   34 if-lt                       22t  n none          continue|branch
+op   35 if-ge                       22t  n none          continue|branch
+op   36 if-gt                       22t  n none          continue|branch
+op   37 if-le                       22t  n none          continue|branch
+op   38 if-eqz                      21t  n none          continue|branch
+op   39 if-nez                      21t  n none          continue|branch
+op   3a if-ltz                      21t  n none          continue|branch
+op   3b if-gez                      21t  n none          continue|branch
+op   3c if-gtz                      21t  n none          continue|branch
+op   3d if-lez                      21t  n none          continue|branch
+# unused: op 3e..43
+op   44 aget                        23x  y none          continue|throw
+op   45 aget-wide                   23x  y none          continue|throw
+op   46 aget-object                 23x  y none          continue|throw
+op   47 aget-boolean                23x  y none          continue|throw
+op   48 aget-byte                   23x  y none          continue|throw
+op   49 aget-char                   23x  y none          continue|throw
+op   4a aget-short                  23x  y none          continue|throw
+op   4b aput                        23x  n none          continue|throw
+op   4c aput-wide                   23x  n none          continue|throw
+op   4d aput-object                 23x  n none          continue|throw
+op   4e aput-boolean                23x  n none          continue|throw
+op   4f aput-byte                   23x  n none          continue|throw
+op   50 aput-char                   23x  n none          continue|throw
+op   51 aput-short                  23x  n none          continue|throw
+op   52 iget                        22c  y field-ref     continue|throw
+op   53 iget-wide                   22c  y field-ref     continue|throw
+op   54 iget-object                 22c  y field-ref     continue|throw
+op   55 iget-boolean                22c  y field-ref     continue|throw
+op   56 iget-byte                   22c  y field-ref     continue|throw
+op   57 iget-char                   22c  y field-ref     continue|throw
+op   58 iget-short                  22c  y field-ref     continue|throw
+op   59 iput                        22c  n field-ref     continue|throw
+op   5a iput-wide                   22c  n field-ref     continue|throw
+op   5b iput-object                 22c  n field-ref     continue|throw
+op   5c iput-boolean                22c  n field-ref     continue|throw
+op   5d iput-byte                   22c  n field-ref     continue|throw
+op   5e iput-char                   22c  n field-ref     continue|throw
+op   5f iput-short                  22c  n field-ref     continue|throw
+op   60 sget                        21c  y field-ref     continue|throw
+op   61 sget-wide                   21c  y field-ref     continue|throw
+op   62 sget-object                 21c  y field-ref     continue|throw
+op   63 sget-boolean                21c  y field-ref     continue|throw
+op   64 sget-byte                   21c  y field-ref     continue|throw
+op   65 sget-char                   21c  y field-ref     continue|throw
+op   66 sget-short                  21c  y field-ref     continue|throw
+op   67 sput                        21c  n field-ref     continue|throw
+op   68 sput-wide                   21c  n field-ref     continue|throw
+op   69 sput-object                 21c  n field-ref     continue|throw
+op   6a sput-boolean                21c  n field-ref     continue|throw
+op   6b sput-byte                   21c  n field-ref     continue|throw
+op   6c sput-char                   21c  n field-ref     continue|throw
+op   6d sput-short                  21c  n field-ref     continue|throw
+op   6e invoke-virtual              35c  n method-ref    continue|throw|invoke
+op   6f invoke-super                35c  n method-ref    continue|throw|invoke
+op   70 invoke-direct               35c  n method-ref    continue|throw|invoke
+op   71 invoke-static               35c  n method-ref    continue|throw|invoke
+op   72 invoke-interface            35c  n method-ref    continue|throw|invoke
+# unused: op 73
+op   74 invoke-virtual/range        3rc  n method-ref    continue|throw|invoke
+op   75 invoke-super/range          3rc  n method-ref    continue|throw|invoke
+op   76 invoke-direct/range         3rc  n method-ref    continue|throw|invoke
+op   77 invoke-static/range         3rc  n method-ref    continue|throw|invoke
+op   78 invoke-interface/range      3rc  n method-ref    continue|throw|invoke
+# unused: op 79..7a
+op   7b neg-int                     12x  y none          continue
+op   7c not-int                     12x  y none          continue
+op   7d neg-long                    12x  y none          continue
+op   7e not-long                    12x  y none          continue
+op   7f neg-float                   12x  y none          continue
+op   80 neg-double                  12x  y none          continue
+op   81 int-to-long                 12x  y none          continue
+op   82 int-to-float                12x  y none          continue
+op   83 int-to-double               12x  y none          continue
+op   84 long-to-int                 12x  y none          continue
+op   85 long-to-float               12x  y none          continue
+op   86 long-to-double              12x  y none          continue
+op   87 float-to-int                12x  y none          continue
+op   88 float-to-long               12x  y none          continue
+op   89 float-to-double             12x  y none          continue
+op   8a double-to-int               12x  y none          continue
+op   8b double-to-long              12x  y none          continue
+op   8c double-to-float             12x  y none          continue
+op   8d int-to-byte                 12x  y none          continue
+op   8e int-to-char                 12x  y none          continue
+op   8f int-to-short                12x  y none          continue
+op   90 add-int                     23x  y none          continue
+op   91 sub-int                     23x  y none          continue
+op   92 mul-int                     23x  y none          continue
+op   93 div-int                     23x  y none          continue|throw
+op   94 rem-int                     23x  y none          continue|throw
+op   95 and-int                     23x  y none          continue
+op   96 or-int                      23x  y none          continue
+op   97 xor-int                     23x  y none          continue
+op   98 shl-int                     23x  y none          continue
+op   99 shr-int                     23x  y none          continue
+op   9a ushr-int                    23x  y none          continue
+op   9b add-long                    23x  y none          continue
+op   9c sub-long                    23x  y none          continue
+op   9d mul-long                    23x  y none          continue
+op   9e div-long                    23x  y none          continue|throw
+op   9f rem-long                    23x  y none          continue|throw
+op   a0 and-long                    23x  y none          continue
+op   a1 or-long                     23x  y none          continue
+op   a2 xor-long                    23x  y none          continue
+op   a3 shl-long                    23x  y none          continue
+op   a4 shr-long                    23x  y none          continue
+op   a5 ushr-long                   23x  y none          continue
+op   a6 add-float                   23x  y none          continue
+op   a7 sub-float                   23x  y none          continue
+op   a8 mul-float                   23x  y none          continue
+op   a9 div-float                   23x  y none          continue
+op   aa rem-float                   23x  y none          continue
+op   ab add-double                  23x  y none          continue
+op   ac sub-double                  23x  y none          continue
+op   ad mul-double                  23x  y none          continue
+op   ae div-double                  23x  y none          continue
+op   af rem-double                  23x  y none          continue
+op   b0 add-int/2addr               12x  y none          continue
+op   b1 sub-int/2addr               12x  y none          continue
+op   b2 mul-int/2addr               12x  y none          continue
+op   b3 div-int/2addr               12x  y none          continue|throw
+op   b4 rem-int/2addr               12x  y none          continue|throw
+op   b5 and-int/2addr               12x  y none          continue
+op   b6 or-int/2addr                12x  y none          continue
+op   b7 xor-int/2addr               12x  y none          continue
+op   b8 shl-int/2addr               12x  y none          continue
+op   b9 shr-int/2addr               12x  y none          continue
+op   ba ushr-int/2addr              12x  y none          continue
+op   bb add-long/2addr              12x  y none          continue
+op   bc sub-long/2addr              12x  y none          continue
+op   bd mul-long/2addr              12x  y none          continue
+op   be div-long/2addr              12x  y none          continue|throw
+op   bf rem-long/2addr              12x  y none          continue|throw
+op   c0 and-long/2addr              12x  y none          continue
+op   c1 or-long/2addr               12x  y none          continue
+op   c2 xor-long/2addr              12x  y none          continue
+op   c3 shl-long/2addr              12x  y none          continue
+op   c4 shr-long/2addr              12x  y none          continue
+op   c5 ushr-long/2addr             12x  y none          continue
+op   c6 add-float/2addr             12x  y none          continue
+op   c7 sub-float/2addr             12x  y none          continue
+op   c8 mul-float/2addr             12x  y none          continue
+op   c9 div-float/2addr             12x  y none          continue
+op   ca rem-float/2addr             12x  y none          continue
+op   cb add-double/2addr            12x  y none          continue
+op   cc sub-double/2addr            12x  y none          continue
+op   cd mul-double/2addr            12x  y none          continue
+op   ce div-double/2addr            12x  y none          continue
+op   cf rem-double/2addr            12x  y none          continue
+op   d0 add-int/lit16               22s  y none          continue
+op   d1 rsub-int                    22s  y none          continue
+op   d2 mul-int/lit16               22s  y none          continue
+op   d3 div-int/lit16               22s  y none          continue|throw
+op   d4 rem-int/lit16               22s  y none          continue|throw
+op   d5 and-int/lit16               22s  y none          continue
+op   d6 or-int/lit16                22s  y none          continue
+op   d7 xor-int/lit16               22s  y none          continue
+op   d8 add-int/lit8                22b  y none          continue
+op   d9 rsub-int/lit8               22b  y none          continue
+op   da mul-int/lit8                22b  y none          continue
+op   db div-int/lit8                22b  y none          continue|throw
+op   dc rem-int/lit8                22b  y none          continue|throw
+op   dd and-int/lit8                22b  y none          continue
+op   de or-int/lit8                 22b  y none          continue
+op   df xor-int/lit8                22b  y none          continue
+op   e0 shl-int/lit8                22b  y none          continue
+op   e1 shr-int/lit8                22b  y none          continue
+op   e2 ushr-int/lit8               22b  y none          continue
+
+#
+# Optimized opcodes (not valid in an unoptimized dex file)
+#
+
+op   e3 +iget-volatile              22c  y field-ref     optimized|continue|throw
+op   e4 +iput-volatile              22c  n field-ref     optimized|continue|throw
+op   e5 +sget-volatile              21c  y field-ref     optimized|continue|throw
+op   e6 +sput-volatile              21c  n field-ref     optimized|continue|throw
+op   e7 +iget-object-volatile       22c  y field-ref     optimized|continue|throw
+op   e8 +iget-wide-volatile         22c  y field-ref     optimized|continue|throw
+op   e9 +iput-wide-volatile         22c  n field-ref     optimized|continue|throw
+op   ea +sget-wide-volatile         21c  y field-ref     optimized|continue|throw
+op   eb +sput-wide-volatile         21c  n field-ref     optimized|continue|throw
+
+# Technically "breakpoint" isn't really an optimized opcode, but it
+# fits the label in terms of not being valid in regular dex files.
+op   ec ^breakpoint                 00x  n unknown       optimized
+
+op   ed ^throw-verification-error   20bc n varies        optimized|throw
+op   ee +execute-inline             35mi n inline-method optimized|continue|throw
+op   ef +execute-inline/range       3rmi n inline-method optimized|continue|throw
+
+op   f0 +invoke-object-init/range   35c  n method-ref    optimized|continue|throw|invoke
+op   f1 +return-void-barrier        10x  n none          optimized|return
+op   f2 +iget-quick                 22cs y field-offset  optimized|continue|throw
+op   f3 +iget-wide-quick            22cs y field-offset  optimized|continue|throw
+op   f4 +iget-object-quick          22cs y field-offset  optimized|continue|throw
+op   f5 +iput-quick                 22cs n field-offset  optimized|continue|throw
+op   f6 +iput-wide-quick            22cs n field-offset  optimized|continue|throw
+op   f7 +iput-object-quick          22cs n field-offset  optimized|continue|throw
+op   f8 +invoke-virtual-quick       35ms n vtable-offset optimized|continue|throw|invoke
+op   f9 +invoke-virtual-quick/range 3rms n vtable-offset optimized|continue|throw|invoke
+op   fa +invoke-super-quick         35ms n vtable-offset optimized|continue|throw|invoke
+op   fb +invoke-super-quick/range   3rms n vtable-offset optimized|continue|throw|invoke
+op   fc +iput-object-volatile       22c  n field-ref     optimized|continue|throw
+op   fd +sget-object-volatile       21c  y field-ref     optimized|continue|throw
+op   fe +sput-object-volatile       21c  n field-ref     optimized|continue|throw
+
+#
+# Extended-width opcodes
+#
+
+op 00ff const-class/jumbo           41c  y type-ref      continue|throw
+op 01ff check-cast/jumbo            41c  n type-ref      continue|throw
+op 02ff instance-of/jumbo           52c  y type-ref      continue|throw
+op 03ff new-instance/jumbo          41c  y type-ref      continue|throw
+op 04ff new-array/jumbo             52c  y type-ref      continue|throw
+op 05ff filled-new-array/jumbo      5rc  n type-ref      continue|throw
+op 06ff iget/jumbo                  52c  y field-ref     continue|throw
+op 07ff iget-wide/jumbo             52c  y field-ref     continue|throw
+op 08ff iget-object/jumbo           52c  y field-ref     continue|throw
+op 09ff iget-boolean/jumbo          52c  y field-ref     continue|throw
+op 0aff iget-byte/jumbo             52c  y field-ref     continue|throw
+op 0bff iget-char/jumbo             52c  y field-ref     continue|throw
+op 0cff iget-short/jumbo            52c  y field-ref     continue|throw
+op 0dff iput/jumbo                  52c  n field-ref     continue|throw
+op 0eff iput-wide/jumbo             52c  n field-ref     continue|throw
+op 0fff iput-object/jumbo           52c  n field-ref     continue|throw
+op 10ff iput-boolean/jumbo          52c  n field-ref     continue|throw
+op 11ff iput-byte/jumbo             52c  n field-ref     continue|throw
+op 12ff iput-char/jumbo             52c  n field-ref     continue|throw
+op 13ff iput-short/jumbo            52c  n field-ref     continue|throw
+op 14ff sget/jumbo                  41c  y field-ref     continue|throw
+op 15ff sget-wide/jumbo             41c  y field-ref     continue|throw
+op 16ff sget-object/jumbo           41c  y field-ref     continue|throw
+op 17ff sget-boolean/jumbo          41c  y field-ref     continue|throw
+op 18ff sget-byte/jumbo             41c  y field-ref     continue|throw
+op 19ff sget-char/jumbo             41c  y field-ref     continue|throw
+op 1aff sget-short/jumbo            41c  y field-ref     continue|throw
+op 1bff sput/jumbo                  41c  n field-ref     continue|throw
+op 1cff sput-wide/jumbo             41c  n field-ref     continue|throw
+op 1dff sput-object/jumbo           41c  n field-ref     continue|throw
+op 1eff sput-boolean/jumbo          41c  n field-ref     continue|throw
+op 1fff sput-byte/jumbo             41c  n field-ref     continue|throw
+op 20ff sput-char/jumbo             41c  n field-ref     continue|throw
+op 21ff sput-short/jumbo            41c  n field-ref     continue|throw
+op 22ff invoke-virtual/jumbo        5rc  n method-ref    continue|throw|invoke
+op 23ff invoke-super/jumbo          5rc  n method-ref    continue|throw|invoke
+op 24ff invoke-direct/jumbo         5rc  n method-ref    continue|throw|invoke
+op 25ff invoke-static/jumbo         5rc  n method-ref    continue|throw|invoke
+op 26ff invoke-interface/jumbo      5rc  n method-ref    continue|throw|invoke
+
+# unused: op 27ff..f1ff
+
+#
+# Optimized opcodes (not valid in an unoptimized dex file)
+#
+
+op f2ff +invoke-object-init/jumbo   5rc  n method-ref    optimized|continue|throw|invoke
+op f3ff +iget-volatile/jumbo        52c  y field-ref     optimized|continue|throw
+op f4ff +iget-wide-volatile/jumbo   52c  y field-ref     optimized|continue|throw
+op f5ff +iget-object-volatile/jumbo 52c  y field-ref     optimized|continue|throw
+op f6ff +iput-volatile/jumbo        52c  n field-ref     optimized|continue|throw
+op f7ff +iput-wide-volatile/jumbo   52c  n field-ref     optimized|continue|throw
+op f8ff +iput-object-volatile/jumbo 52c  n field-ref     optimized|continue|throw
+op f9ff +sget-volatile/jumbo        41c  y field-ref     optimized|continue|throw
+op faff +sget-wide-volatile/jumbo   41c  y field-ref     optimized|continue|throw
+op fbff +sget-object-volatile/jumbo 41c  y field-ref     optimized|continue|throw
+op fcff +sput-volatile/jumbo        41c  n field-ref     optimized|continue|throw
+op fdff +sput-wide-volatile/jumbo   41c  n field-ref     optimized|continue|throw
+op feff +sput-object-volatile/jumbo 41c  n field-ref     optimized|continue|throw
+op ffff ^throw-verification-error/jumbo 40sc n varies    optimized|throw
diff --git a/opcode-gen/opcode-gen b/opcode-gen/opcode-gen
new file mode 100755
index 0000000..b8e4397
--- /dev/null
+++ b/opcode-gen/opcode-gen
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# 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.
+
+# opcode-gen <file>
+#
+# This script uses the file bytecodes.txt (in this directory) to
+# generate code inside the given <file>, based on the directives found
+# in that file. Refer to those files to understand what's being
+# generated. (Look for comments that say "BEGIN(name)" where "name" is
+# one of the "emission" directives defined in opcode-gen.awk in this
+# directory.)
+
+file="$1"
+tmpfile="/tmp/$$.txt"
+
+echo "processing `basename $1`" 1>&2
+
+if [ "x$1" = "x" ]; then
+    echo "must specify a file" 1>&2
+    exit 1
+fi
+
+# 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}"
+
+bytecodeFile="$progdir/bytecode.txt"
+
+awk -v "bytecodeFile=$bytecodeFile" -f "$progdir/opcode-gen.awk" \
+    "$file" > "$tmpfile"
+
+if [ "$?" = "0" ]; then
+    cp "$tmpfile" "$file"
+    rm "$tmpfile"
+else
+    echo "error running awk" 1>&2
+    exit 1
+fi
diff --git a/opcode-gen/opcode-gen.awk b/opcode-gen/opcode-gen.awk
new file mode 100644
index 0000000..0e0ff6c
--- /dev/null
+++ b/opcode-gen/opcode-gen.awk
@@ -0,0 +1,546 @@
+# 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.
+
+#
+# Awk helper script for opcode-gen.
+#
+
+#
+# Initialization.
+#
+
+BEGIN {
+    MAX_OPCODE = 65535;
+    MAX_PACKED_OPCODE = 511;
+    initIndexTypes();
+    initFlags();
+    if (readBytecodes()) exit 1;
+    deriveOpcodeChains();
+    createPackedTables();
+    consumeUntil = "";
+    emission = "";
+}
+
+#
+# General control (must appear above directive handlers).
+#
+
+# Clear out the preexisting output within a directive section.
+consumeUntil != "" {
+    if (index($0, consumeUntil) != 0) {
+        consumeUntil = "";
+        print;
+    }
+
+    next;
+}
+
+# Detect directives.
+/BEGIN\([a-z-]*\)/ {
+    i = match($0, /BEGIN\([a-z-]*\)/);
+    emission = substr($0, i + 6, RLENGTH - 7);
+    consumeUntil = "END(" emission ")";
+    emissionHandled = 0;
+}
+
+# Most lines just get copied from the source as-is, including the start
+# comment for directives.
+{
+    print;
+}
+
+#
+# Handlers for all of the directives.
+#
+
+emission == "opcodes" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i) || isOptimized(i)) continue;
+        printf("    public static final int %s = 0x%s;\n",
+               constName[i], hex[i]);
+    }
+}
+
+emission == "first-opcodes" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i) || isOptimized(i)) continue;
+        if (isFirst[i] == "true") {
+            printf("    //     Opcodes.%s\n", constName[i]);
+        }
+    }
+}
+
+emission == "dops" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i) || isOptimized(i)) continue;
+
+        nextOp = nextOpcode[i];
+        nextOp = (nextOp == -1) ? "NO_NEXT" : constName[nextOp];
+
+        printf("    public static final Dop %s =\n" \
+               "        new Dop(Opcodes.%s, Opcodes.%s,\n" \
+               "            Opcodes.%s, Form%s.THE_ONE, %s);\n\n",
+               constName[i], constName[i], family[i], nextOp, format[i],
+               hasResult[i]);
+    }
+}
+
+emission == "opcode-info-defs" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i) || isOptimized(i)) continue;
+
+        itype = toupper(indexType[i]);
+        gsub(/-/, "_", itype);
+
+        printf("    public static final Info %s =\n" \
+               "        new Info(Opcodes.%s, \"%s\",\n" \
+               "            InstructionCodec.FORMAT_%s, IndexType.%s);\n\n", \
+               constName[i], constName[i], name[i], toupper(format[i]), itype);
+    }
+}
+
+emission == "dops-init" || emission == "opcode-info-init" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i) || isOptimized(i)) continue;
+        printf("        set(%s);\n", constName[i]);
+    }
+}
+
+emission == "libcore-opcodes" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i) || isOptimized(i)) continue;
+        printf("    int OP_%-28s = 0x%04x;\n", constName[i], i);
+    }
+}
+
+emission == "libcore-maximum-values" {
+    emissionHandled = 1;
+
+    printf("        MAXIMUM_VALUE = %d;\n", MAX_OPCODE);
+    printf("        MAXIMUM_PACKED_VALUE = %d;\n", MAX_PACKED_OPCODE);
+}
+
+emission == "libdex-maximum-values" {
+    emissionHandled = 1;
+
+    printf("#define kMaxOpcodeValue 0x%x\n", MAX_OPCODE);
+    printf("#define kNumPackedOpcodes 0x%x\n", MAX_PACKED_OPCODE + 1);
+}
+
+emission == "libdex-opcode-enum" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        printf("    OP_%-28s = 0x%02x,\n", packedConstName[i], i);
+    }
+}
+
+emission == "libdex-goto-table" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        content = sprintf("        H(OP_%s),", packedConstName[i]);
+        printf("%-78s\\\n", content);
+    }
+}
+
+emission == "libdex-opcode-names" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        printf("    \"%s\",\n", packedName[i]);
+    }
+}
+
+emission == "libdex-widths" {
+    emissionHandled = 1;
+
+    col = 1;
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = sprintf("%d,", packedWidth[i]);
+        col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 16, 2, "    ");
+    }
+}
+
+emission == "libdex-flags" {
+    emissionHandled = 1;
+
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = flagsToC(packedFlags[i]);
+        printf("    %s,\n", value);
+    }
+}
+
+emission == "libdex-formats" {
+    emissionHandled = 1;
+
+    col = 1;
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = sprintf("kFmt%s,", packedFormat[i]);
+        col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 7, 9, "    ");
+    }
+}
+
+emission == "libdex-index-types" {
+    emissionHandled = 1;
+
+    col = 1;
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        value = sprintf("%s,", indexTypeValues[packedIndexType[i]]);
+        col = colPrint(value, (i == MAX_PACKED_OPCODE), col, 3, 19, "    ");
+    }
+}
+
+# Handle the end of directive processing (must appear after the directive
+# clauses).
+emission != "" {
+    if (!emissionHandled) {
+        printf("WARNING: unknown tag \"%s\"\n", emission) >"/dev/stderr";
+        consumeUntil = "";
+    }
+
+    emission = "";
+}
+
+#
+# Helper functions.
+#
+
+# Helper to print out an element in a multi-column fashion. It returns
+# the (one-based) column number that the next element will be printed
+# in.
+function colPrint(value, isLast, col, numCols, colWidth, linePrefix) {
+    isLast = (isLast || (col == numCols));
+    printf("%s%-*s%s",
+        (col == 1) ? linePrefix : " ",
+        isLast ? 1 : colWidth, value,
+        isLast ? "\n" : "");
+
+    return (col % numCols) + 1;
+}
+
+# Read the bytecode description file.
+function readBytecodes(i, parts, line, cmd, status, count) {
+    # locals: parts, line, cmd, status, count
+    for (;;) {
+        # Read a line.
+        status = getline line <bytecodeFile;
+        if (status == 0) break;
+        if (status < 0) {
+            print "trouble reading bytecode file";
+            exit 1;
+        }
+
+        # Clean up the line and extract the command.
+        gsub(/  */, " ", line);
+        sub(/ *#.*$/, "", line);
+        sub(/ $/, "", line);
+        sub(/^ /, "", line);
+        count = split(line, parts);
+        if (count == 0) continue; # Blank or comment line.
+        cmd = parts[1];
+        sub(/^[a-z][a-z]* */, "", line); # Remove the command from line.
+
+        if (cmd == "op") {
+            status = defineOpcode(line);
+        } else if (cmd == "format") {
+            status = defineFormat(line);
+        } else {
+            status = -1;
+        }
+
+        if (status != 0) {
+            printf("syntax error on line: %s\n", line) >"/dev/stderr";
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+# Define an opcode.
+function defineOpcode(line, count, parts, idx) {
+    # locals: count, parts, idx
+    count = split(line, parts);
+    if (count != 6)  return -1;
+    idx = parseHex(parts[1]);
+    if (idx < 0) return -1;
+
+    # Extract directly specified values from the line.
+    hex[idx] = parts[1];
+    name[idx] = parts[2];
+    format[idx] = parts[3];
+    hasResult[idx] = (parts[4] == "n") ? "false" : "true";
+    indexType[idx] = parts[5];
+    flags[idx] = parts[6];
+
+    # Calculate derived values.
+
+    constName[idx] = toupper(name[idx]);
+    gsub("[/-]", "_", constName[idx]);   # Dash and slash become underscore.
+    gsub("[+^]", "", constName[idx]);    # Plus and caret are removed.
+    split(name[idx], parts, "/");
+
+    family[idx] = toupper(parts[1]);
+    gsub("-", "_", family[idx]);         # Dash becomes underscore.
+    gsub("[+^]", "", family[idx]);       # Plus and caret are removed.
+
+    split(format[idx], parts, "");       # Width is the first format char.
+    width[idx] = parts[1];
+
+    # This association is used when computing "next" opcodes.
+    familyFormat[family[idx],format[idx]] = idx;
+
+    # Verify values.
+
+    if (nextFormat[format[idx]] == "") {
+        printf("unknown format: %s\n", format[idx]) >"/dev/stderr";
+        return 1;
+    }
+
+    if (indexTypeValues[indexType[idx]] == "") {
+        printf("unknown index type: %s\n", indexType[idx]) >"/dev/stderr";
+        return 1;
+    }
+
+    if (flagsToC(flags[idx]) == "") {
+        printf("bogus flags: %s\n", flags[idx]) >"/dev/stderr";
+        return 1;
+    }
+
+    return 0;
+}
+
+# Define a format family.
+function defineFormat(line, count, parts, i) {
+    # locals: count, parts, i
+    count = split(line, parts);
+    if (count < 1)  return -1;
+    formats[parts[1]] = line;
+
+    parts[count + 1] = "none";
+    for (i = 1; i <= count; i++) {
+        nextFormat[parts[i]] = parts[i + 1];
+    }
+
+    return 0;
+}
+
+# Produce the nextOpcode and isFirst arrays. The former indicates, for
+# each opcode, which one should be tried next when doing instruction
+# fitting. The latter indicates which opcodes are at the head of an
+# instruction fitting chain.
+function deriveOpcodeChains(i, op) {
+    # locals: i, op
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i)) continue;
+        isFirst[i] = "true";
+    }
+
+    for (i = 0; i <= MAX_OPCODE; i++) {
+        if (isUnused(i)) continue;
+        op = findNextOpcode(i);
+        nextOpcode[i] = op;
+        if (op != -1) {
+            isFirst[op] = "false";
+        }
+    }
+}
+
+# Given an opcode by index, find the next opcode in the same family
+# (that is, with the same base name) to try when matching instructions
+# to opcodes. This simply walks the nextFormat chain looking for a
+# match. This returns the index of the matching opcode or -1 if there
+# is none.
+function findNextOpcode(idx, fam, fmt, result) {
+    # locals: fam, fmt, result
+    fam = family[idx];
+    fmt = format[idx];
+
+    # Not every opcode has a version with every possible format, so
+    # we have to iterate down the chain until we find one or run out of
+    # formats to try.
+    for (fmt = nextFormat[format[idx]]; fmt != "none"; fmt = nextFormat[fmt]) {
+        result = familyFormat[fam,fmt];
+        if (result != "") {
+            return result;
+        }
+    }
+
+    return -1;
+}
+
+# Construct the tables of info indexed by packed opcode. The packed opcode
+# values are in the range 0-0x1ff, whereas the unpacked opcodes sparsely
+# span the range 0-0xffff.
+function createPackedTables(i, op) {
+    # locals: i, op
+    for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
+        op = unpackOpcode(i);
+        if (i == 255) {
+            # Special case: This is the low-opcode slot for a would-be
+            # extended opcode dispatch implementation.
+            packedName[i]      = "dispatch-ff";
+            packedConstName[i] = "DISPATCH_FF";
+            packedFormat[i]    = "00x";
+            packedFlags[i]     = 0;
+            packedWidth[i]     = 0;
+            packedIndexType[i] = "unknown";
+        } else if (isUnused(op)) {
+            packedName[i]      = unusedName(op);
+            packedConstName[i] = unusedConstName(op);
+            packedFormat[i]    = "00x";
+            packedFlags[i]     = 0;
+            packedWidth[i]     = 0;
+            packedIndexType[i] = "unknown";
+        } else {
+            packedName[i]      = name[op];
+            packedConstName[i] = constName[op];
+            packedFormat[i]    = format[op];
+            packedFlags[i]     = flags[op];
+            packedWidth[i]     = width[op];
+            packedIndexType[i] = indexType[op];
+        }
+    }
+}
+
+# Given a packed opcode, returns the raw (unpacked) opcode value.
+function unpackOpcode(idx) {
+    # Note: This must be the inverse of the corresponding code in
+    # libdex/DexOpcodes.h.
+    if (idx <= 255) {
+        return idx;
+    } else {
+        idx -= 256;
+        return (idx * 256) + 255;
+    }
+}
+
+# Returns the "unused" name of the given opcode (by index).
+# That is, this is the human-oriented name to use for an opcode
+# definition in cases
+# where the opcode isn't used.
+function unusedName(idx) {
+    if (idx <= 255) {
+         return sprintf("unused-%02x", idx);
+    } else {
+         return sprintf("unused-%04x", idx);
+    }
+}
+
+# Returns the "unused" constant name of the given opcode (by index).
+# That is, this is the name to use for a constant definition in cases
+# where the opcode isn't used.
+function unusedConstName(idx) {
+    if (idx <= 255) {
+         return toupper(sprintf("UNUSED_%02x", idx));
+    } else {
+         return toupper(sprintf("UNUSED_%04x", idx));
+    }
+}
+
+# Convert a hex value to an int.
+function parseHex(hex, result, chars, count, c, i) {
+    # locals: result, chars, count, c, i
+    hex = tolower(hex);
+    count = split(hex, chars, "");
+    result = 0;
+    for (i = 1; i <= count; i++) {
+        c = index("0123456789abcdef", chars[i]);
+        if (c == 0) {
+            printf("bogus hex value: %s\n", hex) >"/dev/stderr";
+            return -1;
+        }
+        result = (result * 16) + c - 1;
+    }
+    return result;
+}
+
+# Initialize the indexTypes data.
+function initIndexTypes() {
+    indexTypeValues["unknown"]       = "kIndexUnknown";
+    indexTypeValues["none"]          = "kIndexNone";
+    indexTypeValues["varies"]        = "kIndexVaries";
+    indexTypeValues["type-ref"]      = "kIndexTypeRef";
+    indexTypeValues["string-ref"]    = "kIndexStringRef";
+    indexTypeValues["method-ref"]    = "kIndexMethodRef";
+    indexTypeValues["field-ref"]     = "kIndexFieldRef";
+    indexTypeValues["inline-method"] = "kIndexInlineMethod";
+    indexTypeValues["vtable-offset"] = "kIndexVtableOffset";
+    indexTypeValues["field-offset"]  = "kIndexFieldOffset";
+}
+
+# Initialize the flags data.
+function initFlags() {
+    flagValues["branch"]        = "kInstrCanBranch";
+    flagValues["continue"]      = "kInstrCanContinue";
+    flagValues["switch"]        = "kInstrCanSwitch";
+    flagValues["throw"]         = "kInstrCanThrow";
+    flagValues["return"]        = "kInstrCanReturn";
+    flagValues["invoke"]        = "kInstrInvoke";
+    flagValues["optimized"]     = "0"; # Not represented in C output
+    flagValues["0"]             = "0";
+}
+
+# Translate the given flags into the equivalent C expression. Returns
+# "" on error.
+function flagsToC(f, parts, result, i) {
+    # locals: parts, result, i
+    count = split(f, parts, /\|/); # Split input at pipe characters.
+    result = "0";
+
+    for (i = 1; i <= count; i++) {
+        f = flagValues[parts[i]];
+        if (f == "") {
+            printf("bogus flag: %s\n", f) >"/dev/stderr";
+            return ""; # Bogus flag name.
+        } else if (f == "0") {
+            # Nothing to append for this case.
+        } else if (result == "0") {
+            result = f;
+        } else {
+            result = result "|" f;
+        }
+    }
+
+    return result;
+}
+
+# Returns true if the given opcode (by index) is an "optimized" opcode.
+function isOptimized(idx, parts, f) {
+    # locals: parts, f
+    split(flags[idx], parts, /\|/); # Split flags[idx] at pipes.
+    for (f in parts) {
+        if (parts[f] == "optimized") return 1;
+    }
+    return 0;
+}
+
+# Returns true if there is no definition for the given opcode (by index).
+function isUnused(idx) {
+    return (name[idx] == "");
+}
diff --git a/opcode-gen/regen-all b/opcode-gen/regen-all
new file mode 100755
index 0000000..161cda9
--- /dev/null
+++ b/opcode-gen/regen-all
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# 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.
+
+# 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
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+
+# Be in the parent of the progdir when running the rest of the script.
+cd ".."
+
+${progdir}/opcode-gen dx/src/com/android/dx/dex/code/Dops.java
+${progdir}/opcode-gen dx/src/com/android/dx/dex/code/RopToDop.java
+${progdir}/opcode-gen dx/src/com/android/dx/io/OpcodeInfo.java
+${progdir}/opcode-gen dx/src/com/android/dx/io/Opcodes.java
+${progdir}/opcode-gen libdex/DexOpcodes.cpp
+${progdir}/opcode-gen libdex/DexOpcodes.h
+${progdir}/opcode-gen libdex/InstrUtils.cpp
+
+# It's a minor shame that these files live in a different top-level project.
+# So it goes.
+${progdir}/opcode-gen \
+    ../libcore/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
+${progdir}/opcode-gen \
+    ../libcore/dalvik/src/main/java/dalvik/bytecode/Opcodes.java
diff --git a/tests/001-nop/build b/tests/001-nop/build
new file mode 100644
index 0000000..5233a2d
--- /dev/null
+++ b/tests/001-nop/build
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+# Nothing to do here.
diff --git a/tests/001-nop/expected.txt b/tests/001-nop/expected.txt
new file mode 100644
index 0000000..80a233e
--- /dev/null
+++ b/tests/001-nop/expected.txt
@@ -0,0 +1 @@
+Blort.
diff --git a/tests/001-nop/info.txt b/tests/001-nop/info.txt
new file mode 100644
index 0000000..9942f10
--- /dev/null
+++ b/tests/001-nop/info.txt
@@ -0,0 +1,2 @@
+This is a sample no-op test, which does at least serve to verify that the
+test harness is working.
diff --git a/tests/001-nop/run b/tests/001-nop/run
new file mode 100644
index 0000000..210296b
--- /dev/null
+++ b/tests/001-nop/run
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "Blort."
diff --git a/tests/002-sleep/expected.txt b/tests/002-sleep/expected.txt
new file mode 100644
index 0000000..f994ce5
--- /dev/null
+++ b/tests/002-sleep/expected.txt
@@ -0,0 +1,2 @@
+Sleeping 1000 msec...
+Done sleeping
diff --git a/tests/002-sleep/info.txt b/tests/002-sleep/info.txt
new file mode 100644
index 0000000..9a0afe9
--- /dev/null
+++ b/tests/002-sleep/info.txt
@@ -0,0 +1,3 @@
+Test that Thread.sleep() operates reasonably. This test is actually
+mostly meant as an easy thing to modify in order to test other things
+in an ad-hoc way.
diff --git a/tests/002-sleep/src/Main.java b/tests/002-sleep/src/Main.java
new file mode 100644
index 0000000..c1a2d83
--- /dev/null
+++ b/tests/002-sleep/src/Main.java
@@ -0,0 +1,22 @@
+public class Main {
+    static public void main(String[] args) throws Exception {
+        int millis = 1000;
+
+        if (args.length != 0) {
+            millis = Integer.parseInt(args[0]);
+        }
+
+        System.out.println("Sleeping " + millis + " msec...");
+
+        long start = System.currentTimeMillis();
+        Thread.sleep(millis);
+        long elapsed = System.currentTimeMillis() - start;
+        long offBy = Math.abs(elapsed - millis);
+
+        System.out.println("Done sleeping");
+
+        if (offBy > 250) {
+            System.out.println("Actually slept about " + elapsed + " msec...");
+        }
+    }
+}
diff --git a/tests/003-omnibus-opcodes/build b/tests/003-omnibus-opcodes/build
new file mode 100644
index 0000000..9eb5ed3
--- /dev/null
+++ b/tests/003-omnibus-opcodes/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# 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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/UnresClass.class
+${JAVAC} -d classes `find src2 -name '*.java'`
+
+dx -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+zip test.jar classes.dex
diff --git a/tests/003-omnibus-opcodes/expected.txt b/tests/003-omnibus-opcodes/expected.txt
new file mode 100644
index 0000000..4895dc3
--- /dev/null
+++ b/tests/003-omnibus-opcodes/expected.txt
@@ -0,0 +1,74 @@
+(assertions are enabled)
+InstField assign...
+InstField check...
+InstField.nullCheck
+StaticField assign...
+StaticField check...
+IntMath.shiftTest1
+IntMath.shiftTest2
+IntMath.unsignedShiftTest
+IntMath.convTest
+IntMath.charSubTest
+IntMath.intOperTest
+IntMath.intOperCheck
+IntMath.longOperTest
+IntMath.longOperCheck
+IntMath.lit16Test
+IntMath.lit8Test
+IntMath.intShiftTest
+IntMath.intShiftCheck
+IntMath.longShiftTest
+IntMath.longShiftCheck
+IntMath.truncateTest
+IntMath.divideByZero
+IntMath.bigDivideOverflow
+IntMath.checkConsts
+IntMath.jlmTests
+FloatMath.convTest
+FloatMath.floatOperTest
+FloatMath.doubleOperTest
+FloatMath.checkConvI
+FloatMath.checkConvL
+FloatMath.checkConvF
+ 0: -2.0054409E9
+ 1: -8.613303E18
+ 2: -3.1415927
+-2.0054409E9, -8.6133031E18, -3.1415927
+FloatMath.checkConvD
+ 0: -2.005440939E9
+ 1: -8.613303245920329E18
+ 2: 123.45600128173828
+-2.005440939E9, -8.6133032459203287E18, 123.4560012817382
+FloatMath.checkConsts
+FloatMath.jlmTests
+IntMath.testIntCompare
+IntMath.testLongCompare
+IntMath.testFloatCompare
+IntMath.testDoubleCompare
+Monitor.run
+Switch.testSwitch
+Array check...
+Array.checkRange32
+Array.checkRange64
+Array.checkNegAlloc
+Classes.checkCast
+Classes.arrayInstance
+Goto.smallGoto
+Goto.smallGoto
+Goto.mediumGoto
+Goto.mediumGoto
+Goto.bigGoto
+Goto.bigGoto
+  MethodCallBase ctor
+  MethodCall ctor
+MethodCalls.manyArgs
+Throw.one
+Throw.twoA
+Throw.twoN
+Throw.rethrow
+UnresTest1...
+UnresTest1...
+UnresTest2...
+UnresTest2 done
+InternedString.run
+Done!
diff --git a/tests/003-omnibus-opcodes/info.txt b/tests/003-omnibus-opcodes/info.txt
new file mode 100644
index 0000000..6c0fbda
--- /dev/null
+++ b/tests/003-omnibus-opcodes/info.txt
@@ -0,0 +1 @@
+This is a smoke test of many Dalvik opcodes.
diff --git a/tests/003-omnibus-opcodes/src/Array.java b/tests/003-omnibus-opcodes/src/Array.java
new file mode 100644
index 0000000..f385dd8
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Array.java
@@ -0,0 +1,224 @@
+// Copyright 2008 The Android Open Source Project
+
+
+/**
+ * Exercise arrays.
+ */
+public class Array {
+
+    /*
+     * Verify array contents.
+     */
+    static void checkBytes(byte[] bytes) {
+        assert(bytes[0] == 0);
+        assert(bytes[1] == -1);
+        assert(bytes[2] == -2);
+        assert(bytes[3] == -3);
+        assert(bytes[4] == -4);
+    }
+    static void checkShorts(short[] shorts) {
+        assert(shorts[0] == 20);
+        assert(shorts[1] == 10);
+        assert(shorts[2] == 0);
+        assert(shorts[3] == -10);
+        assert(shorts[4] == -20);
+    }
+    static void checkChars(char[] chars) {
+        assert(chars[0] == 40000);
+        assert(chars[1] == 40001);
+        assert(chars[2] == 40002);
+        assert(chars[3] == 40003);
+        assert(chars[4] == 40004);
+    }
+    static void checkInts(int[] ints) {
+        assert(ints[0] == 70000);
+        assert(ints[1] == 70001);
+        assert(ints[2] == 70002);
+        assert(ints[3] == 70003);
+        assert(ints[4] == 70004);
+    }
+    static void checkBooleans(boolean[] booleans) {
+        assert(booleans[0]);
+        assert(booleans[1]);
+        assert(!booleans[2]);
+        assert(booleans[3]);
+        assert(!booleans[4]);
+    }
+    static void checkFloats(float[] floats) {
+        assert(floats[0] == -1.5);
+        assert(floats[1] == -0.5);
+        assert(floats[2] == 0.0);
+        assert(floats[3] == 0.5);
+        assert(floats[4] == 1.5);
+    }
+    static void checkLongs(long[] longs) {
+        assert(longs[0] == 0x1122334455667788L);
+        assert(longs[1] == 0x8877665544332211L);
+        assert(longs[2] == 0L);
+        assert(longs[3] == 1L);
+        assert(longs[4] == -1L);
+    }
+    static void checkStrings(String[] strings) {
+        assert(strings[0].equals("zero"));
+        assert(strings[1].equals("one"));
+        assert(strings[2].equals("two"));
+        assert(strings[3].equals("three"));
+        assert(strings[4].equals("four"));
+    }
+
+    /*
+     * Try bad range values, 32 bit get/put.
+     */
+    static void checkRange32(int[] ints, int[] empty, int negVal1, int negVal2){
+        System.out.println("Array.checkRange32");
+        int i = 0;
+
+        assert(ints.length == 5);
+
+        try {
+            i = ints[5];            // exact bound
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            ints[5] = i;            // exact bound
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            i = ints[6];            // one past
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            i = ints[negVal1];      // -1
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            ints[negVal1] = i;      // -1
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            i = ints[negVal2];      // min int
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+
+
+        try {
+            i = empty[1];
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+    }
+
+    /*
+     * Try bad range values, 64 bit get/put.
+     */
+    static void checkRange64(long[] longs, int negVal1, int negVal2) {
+        System.out.println("Array.checkRange64");
+        long l = 0L;
+
+        assert(longs.length == 5);
+
+        try {
+            l = longs[5];            // exact bound
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            longs[5] = l;            // exact bound
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            l = longs[6];            // one past
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            l = longs[negVal1];      // -1
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            longs[negVal1] = l;      // -1
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+        try {
+            l = longs[negVal2];      // min int
+            assert(false);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            // good
+        }
+    }
+
+    /*
+     * Test negative allocations of object and primitive arrays.
+     */
+    static void checkNegAlloc(int count) {
+        System.out.println("Array.checkNegAlloc");
+        String[] strings;
+        int[] ints;
+
+        try {
+            ints = new int[count];
+            assert(false);
+        } catch (NegativeArraySizeException nase) {
+            // good
+        }
+
+        try {
+            strings = new String[count];
+            assert(false);
+        } catch (NegativeArraySizeException nase) {
+            // good
+        }
+    }
+
+    public static void run() {
+        System.out.println("Array check...");
+
+        byte[] xBytes = new byte[] { 0, -1, -2, -3, -4 };
+        short[] xShorts = new short[] { 20, 10, 0, -10, -20 };
+        char[] xChars = new char[] { 40000, 40001, 40002, 40003, 40004 };
+        int[] xInts = new int[] { 70000, 70001, 70002, 70003, 70004 };
+        boolean[] xBooleans = new boolean[] { true, true, false, true, false };
+        float[] xFloats = new float[] { -1.5f, -0.5f, 0.0f, 0.5f, 1.5f };
+        long[] xLongs = new long[] {
+            0x1122334455667788L, 0x8877665544332211L, 0L, 1L, -1l };
+        String[] xStrings = new String[] {
+            "zero", "one", "two", "three", "four" };
+
+        int[] xEmpty = new int[0];
+
+        checkBytes(xBytes);
+        checkShorts(xShorts);
+        checkChars(xChars);
+        checkInts(xInts);
+        checkBooleans(xBooleans);
+        checkFloats(xFloats);
+        checkLongs(xLongs);
+        checkStrings(xStrings);
+
+        checkRange32(xInts, xEmpty, -1, (int) 0x80000000);
+        checkRange64(xLongs, -1, (int) 0x80000000);
+
+        checkNegAlloc(-1);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Classes.java b/tests/003-omnibus-opcodes/src/Classes.java
new file mode 100644
index 0000000..c89ff3e
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Classes.java
@@ -0,0 +1,219 @@
+// Copyright 2008 The Android Open Source Project
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * Exercise some class-related instructions.
+ */
+public class Classes {
+    int mSome;
+
+    public void subFunc(boolean wantSub) {
+        assert(!wantSub);
+    }
+
+    void checkCast(Object thisRef, Object moreRef, Object nullRef) {
+        System.out.println("Classes.checkCast");
+
+        Classes classes;
+        MoreClasses more;
+
+        classes = (Classes) thisRef;
+        assert(thisRef instanceof Classes);
+        classes = (Classes) moreRef;
+        assert(moreRef instanceof Classes);
+
+        more = (MoreClasses) moreRef;
+        assert(moreRef instanceof MoreClasses);
+        assert(!(thisRef instanceof MoreClasses));
+
+        try {
+            more = (MoreClasses) thisRef;
+            assert(false);
+        } catch (ClassCastException cce) {
+            //System.out.println("  class cast msg: " + cce.getMessage());
+            //Dalvik throws terser message than Hotspot VM
+            assert(cce.getMessage().regionMatches(false, 0, "Classes", 0, 7));
+        }
+        assert(!(thisRef instanceof MoreClasses));
+
+        /* hopefully these classes cause a resolve */
+        try {
+            java.math.RoundingMode mode = (java.math.RoundingMode) thisRef;
+            assert(false);
+        } catch (ClassCastException cce) {
+            //System.out.println("  class cast msg: " + cce.getMessage());
+            //Dalvik throws terser message than Hotspot VM
+            assert(cce.getMessage().regionMatches(false, 0, "Classes", 0, 7));
+        }
+        assert(!(thisRef instanceof java.math.BigDecimal));
+
+        /* try some stuff with a null reference */
+        classes = (Classes) nullRef;
+        classes = (MoreClasses) nullRef;
+        more = (MoreClasses) nullRef;
+        assert(!(nullRef instanceof Classes));
+
+    }
+
+
+    static void xTests(Object x) {
+        assert(  x instanceof Classes);
+        assert(!(x instanceof MoreClasses));
+    }
+    static void yTests(Object y) {
+        assert(  y instanceof Classes);
+        assert(  y instanceof MoreClasses);
+    }
+    static void xarTests(Object xar) {
+        assert(  xar instanceof Object);
+        assert(!(xar instanceof Classes));
+        assert(  xar instanceof Classes[]);
+        assert(!(xar instanceof MoreClasses[]));
+        assert(  xar instanceof Object[]);
+        assert(!(xar instanceof Object[][]));
+    }
+    static void yarTests(Object yar) {
+        assert(  yar instanceof Classes[]);
+        assert(  yar instanceof MoreClasses[]);
+    }
+    static void xarararTests(Object xararar) {
+        assert(  xararar instanceof Object);
+        assert(  xararar instanceof Object[]);
+        assert(!(xararar instanceof Classes));
+        assert(!(xararar instanceof Classes[]));
+        assert(!(xararar instanceof Classes[][]));
+        assert(  xararar instanceof Classes[][][]);
+        assert(!(xararar instanceof MoreClasses[][][]));
+        assert(  xararar instanceof Object[][][]);
+        assert(  xararar instanceof Serializable);
+        assert(  xararar instanceof Serializable[]);
+        assert(  xararar instanceof Serializable[][]);
+        assert(!(xararar instanceof Serializable[][][]));
+    }
+    static void yarararTests(Object yararar) {
+        assert(  yararar instanceof Classes[][][]);
+        assert(  yararar instanceof MoreClasses[][][]);
+    }
+    static void iarTests(Object iar) {
+        assert(  iar instanceof Object);
+        assert(!(iar instanceof Object[]));
+    }
+    static void iararTests(Object iarar) {
+        assert(  iarar instanceof Object);
+        assert(  iarar instanceof Object[]);
+        assert(!(iarar instanceof Object[][]));
+    }
+
+    /*
+     * Exercise filled-new-array and test instanceof on arrays.
+     *
+     * We call out instead of using "instanceof" directly to avoid
+     * compiler optimizations.
+     */
+    static void arrayInstance() {
+        System.out.println("Classes.arrayInstance");
+
+        Classes x = new Classes();
+        Classes[] xar = new Classes[1];
+        Classes[][] xarar = new Classes[1][1];
+        Classes[][][] xararar = new Classes[1][2][3];
+        MoreClasses y = new MoreClasses();
+        MoreClasses[] yar = new MoreClasses[3];
+        MoreClasses[][] yarar = new MoreClasses[2][3];
+        MoreClasses[][][] yararar = new MoreClasses[1][2][3];
+        int[] iar = new int[1];
+        int[][] iarar = new int[1][1];
+        Object test;
+
+        xTests(x);
+        yTests(y);
+        xarTests(xar);
+        yarTests(yar);
+        xarararTests(xararar);
+        yarararTests(yararar);
+        iarTests(iar);
+        iararTests(iarar);
+
+        yararar[0] = yarar;
+        yararar[0][0] = yar;
+        yararar[0][1] = yar;
+        yararar[0][0][0] = y;
+        yararar[0][0][1] = y;
+        yararar[0][0][2] = y;
+        yararar[0][1][0] = y;
+        yararar[0][1][1] = y;
+        yararar[0][1][2] = y;
+
+        String strForm;
+
+        String[][][][] multi1 = new String[2][3][2][1];
+        multi1[0] = new String[2][3][2];
+        multi1[0][1] = new String[3][2];
+        multi1[0][1][2] = new String[2];
+        multi1[0][1][2][1] = "HELLO-1";
+        strForm = Arrays.deepToString(multi1);
+
+        String[][][][][] multi2 = new String[5][2][3][2][1];
+        multi2[0] = new String[5][2][3][2];
+        multi2[0][1] = new String[5][2][3];
+        multi2[0][1][2] = new String[5][2];
+        multi2[0][1][2][1] = new String[5];
+        multi2[0][1][2][1][4] = "HELLO-2";
+        strForm = Arrays.deepToString(multi2);
+
+
+        String[][][][][][] multi3 = new String[2][5][2][3][2][1];
+        multi3[0] = new String[2][][][][];
+        multi3[0][1] = new String[3][][][];
+        multi3[0][1][2] = new String[2][][];
+        multi3[0][1][2][1] = new String[5][];
+        multi3[0][1][2][1][4] = new String[2];
+        multi3[0][1][2][1][4][1] = "HELLO-3";
+        strForm = Arrays.deepToString(multi3);
+
+        // build up pieces
+        String[][][][][][] multi4 = new String[1][][][][][];
+        multi4[0] = new String[2][][][][];
+        multi4[0][1] = new String[3][][][];
+        multi4[0][1][2] = new String[2][][];
+        multi4[0][1][2][1] = new String[5][];
+        multi4[0][1][2][1][4] = new String[2];
+        multi4[0][1][2][1][4][1] = "HELLO-4";
+        strForm = Arrays.deepToString(multi4);
+
+        /* this is expected to fail; 1073921584 * 4 overflows 32 bits */
+        try {
+            String[][][][][] multiX = new String[5][2][3][2][1073921584];
+            assert(false);
+        } catch (Error e) {
+            //System.out.println("  Got expected failure: " + e);
+        }
+
+    }
+
+    public static void run() {
+        Classes classes = new Classes();
+        MoreClasses more = new MoreClasses();
+        classes.checkCast(classes, more, null);
+
+        more.subFunc(true);
+        more.superFunc(false);
+        arrayInstance();
+    }
+}
+
+class MoreClasses extends Classes {
+    int mMore;
+
+    public MoreClasses() {}
+
+    public void subFunc(boolean wantSub) {
+        assert(wantSub);
+    }
+
+    public void superFunc(boolean wantSub) {
+        super.subFunc(wantSub);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Compare.java b/tests/003-omnibus-opcodes/src/Compare.java
new file mode 100644
index 0000000..43a708a
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Compare.java
@@ -0,0 +1,171 @@
+// Copyright 2008 The Android Open Source Project
+
+
+
+/**
+ * Test comparison operators.
+ */
+public class Compare {
+
+    /*
+     * Test the integer comparisons in various ways.
+     */
+    static void testIntCompare(int minus, int plus, int plus2, int zero) {
+        System.out.println("IntMath.testIntCompare");
+
+        if (minus > plus)
+            assert(false);
+        if (minus >= plus)
+            assert(false);
+        if (plus < minus)
+            assert(false);
+        if (plus <= minus)
+            assert(false);
+        if (plus == minus)
+            assert(false);
+        if (plus != plus2)
+            assert(false);
+
+        /* try a branch-taken */
+        if (plus != minus) {
+            assert(true);
+        } else {
+            assert(false);
+        }
+
+        if (minus > 0)
+            assert(false);
+        if (minus >= 0)
+            assert(false);
+        if (plus < 0)
+            assert(false);
+        if (plus <= 0)
+            assert(false);
+        if (plus == 0)
+            assert(false);
+        if (zero != 0)
+            assert(false);
+
+        if (zero == 0) {
+            assert(true);
+        } else {
+            assert(false);
+        }
+    }
+
+    /*
+     * Test cmp-long.
+     *
+     * minus=-5, alsoMinus=0xFFFFFFFF00000009, plus=4, alsoPlus=8
+     */
+    static void testLongCompare(long minus, long alsoMinus, long plus,
+        long alsoPlus) {
+
+        System.out.println("IntMath.testLongCompare");
+        if (minus > plus)
+            assert(false);
+        if (plus < minus)
+            assert(false);
+        if (plus == minus)
+            assert(false);
+
+        if (plus >= plus+1)
+            assert(false);
+        if (minus >= minus+1)
+            assert(false);
+
+        /* try a branch-taken */
+        if (plus != minus) {
+            assert(true);
+        } else {
+            assert(false);
+        }
+
+        /* compare when high words are equal but low words differ */
+        if (plus > alsoPlus)
+            assert(false);
+        if (alsoPlus < plus)
+            assert(false);
+        if (alsoPlus == plus)
+            assert(false);
+
+        /* high words are equal, low words have apparently different signs */
+        if (minus < alsoMinus)      // bug!
+            assert(false);
+        if (alsoMinus > minus)
+            assert(false);
+        if (alsoMinus == minus)
+            assert(false);
+    }
+
+    /*
+     * Test cmpl-float and cmpg-float.
+     */
+    static void testFloatCompare(float minus, float plus, float plus2,
+        float nan) {
+
+        System.out.println("IntMath.testFloatCompare");
+        if (minus > plus)
+            assert(false);
+        if (plus < minus)
+            assert(false);
+        if (plus == minus)
+            assert(false);
+        if (plus != plus2)
+            assert(false);
+
+        if (plus <= nan)
+            assert(false);
+        if (plus >= nan)
+            assert(false);
+        if (minus <= nan)
+            assert(false);
+        if (minus >= nan)
+            assert(false);
+        if (nan >= plus)
+            assert(false);
+        if (nan <= plus)
+            assert(false);
+
+        if (nan == nan)
+            assert(false);
+    }
+
+    static void testDoubleCompare(double minus, double plus, double plus2,
+        double nan) {
+
+        System.out.println("IntMath.testDoubleCompare");
+        if (minus > plus)
+            assert(false);
+        if (plus < minus)
+            assert(false);
+        if (plus == minus)
+            assert(false);
+        if (plus != plus2)
+            assert(false);
+
+        if (plus <= nan)
+            assert(false);
+        if (plus >= nan)
+            assert(false);
+        if (minus <= nan)
+            assert(false);
+        if (minus >= nan)
+            assert(false);
+        if (nan >= plus)
+            assert(false);
+        if (nan <= plus)
+            assert(false);
+
+        if (nan == nan)
+            assert(false);
+    }
+
+    public static void run() {
+        testIntCompare(-5, 4, 4, 0);
+        testLongCompare(-5L, -4294967287L, 4L, 8L);
+
+        testFloatCompare(-5.0f, 4.0f, 4.0f, (1.0f/0.0f) / (1.0f/0.0f));
+        testDoubleCompare(-5.0, 4.0, 4.0, (1.0/0.0) / (1.0/0.0));
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/FloatMath.java b/tests/003-omnibus-opcodes/src/FloatMath.java
new file mode 100644
index 0000000..3c49402
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/FloatMath.java
@@ -0,0 +1,337 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Test arithmetic operations.
+ */
+public class FloatMath {
+
+    static void convTest() {
+        System.out.println("FloatMath.convTest");
+
+        float f;
+        double d;
+        int i;
+        long l;
+
+        /* float --> int */
+        f = 1234.5678f;
+        i = (int) f;
+        assert(i == 1234);
+
+        f = -1234.5678f;
+        i = (int) f;
+        assert(i == -1234);
+
+        /* float --> long */
+        f = 1238.5678f;
+        l = (long) f;
+        assert(l == 1238);
+
+        f = -1238.5678f;
+        l = (long) f;
+        assert(l == -1238);
+
+        /* float --> double */
+        f = 1238.5678f;
+        d = (double) f;
+        assert(d > 1238.567 && d < 1238.568);
+
+        /* double --> int */
+        d = 1234.5678;
+        i = (int) d;
+        assert(i == 1234);
+
+        d = -1234.5678;
+        i = (int) d;
+        assert(i == -1234);
+
+        /* double --> long */
+        d = 5678956789.0123;
+        l = (long) d;
+        assert(l == 5678956789L);
+
+        d = -5678956789.0123;
+        l = (long) d;
+        assert(l == -5678956789L);
+
+        /* double --> float */
+        d = 1238.5678;
+        f = (float) d;
+        assert(f > 1238.567 && f < 1238.568);
+
+        /* int --> long */
+        i = 7654;
+        l = (long) i;
+        assert(l == 7654L);
+
+        i = -7654;
+        l = (long) i;
+        assert(l == -7654L);
+
+        /* int --> float */
+        i = 1234;
+        f = (float) i;
+        assert(f > 1233.9f && f < 1234.1f);
+
+        i = -1234;
+        f = (float) i;
+        assert(f < -1233.9f && f > -1234.1f);
+
+        /* int --> double */
+        i = 1238;
+        d = (double) i;
+        assert(d > 1237.9f && d < 1238.1f);
+
+        i = -1238;
+        d = (double) i;
+        assert(d < -1237.9f && d > -1238.1f);
+
+        /* long --> int (with truncation) */
+        l = 5678956789L;
+        i = (int) l;
+        assert(i == 1383989493);
+
+        l = -5678956789L;
+        i = (int) l;
+        assert(i == -1383989493);
+
+        /* long --> float */
+        l = 5678956789L;
+        f = (float) l;
+        assert(f > 5.6789564E9 && f < 5.6789566E9);
+
+        l = -5678956789L;
+        f = (float) l;
+        assert(f < -5.6789564E9 && f > -5.6789566E9);
+
+        /* long --> double */
+        l = 6678956789L;
+        d = (double) l;
+        assert(d > 6.6789567E9 && d < 6.6789568E9);
+
+        l = -6678956789L;
+        d = (double) l;
+        assert(d < -6.6789567E9 && d > -6.6789568E9);
+    }
+
+    /*
+     * We pass in the arguments and return the results so the compiler
+     * doesn't do the math for us.
+     */
+    static float[] floatOperTest(float x, float y) {
+        System.out.println("FloatMath.floatOperTest");
+
+        float[] results = new float[9];
+
+        /* this seems to generate "op-float" instructions */
+        results[0] = x + y;
+        results[1] = x - y;
+        results[2] = x * y;
+        results[3] = x / y;
+        results[4] = x % -y;
+
+        /* this seems to generate "op-float/2addr" instructions */
+        results[8] = x + (((((x + y) - y) * y) / y) % y);
+
+        return results;
+    }
+    static void floatOperCheck(float[] results) {
+        assert(results[0] > 69996.99f && results[0] < 69997.01f);
+        assert(results[1] > 70002.99f && results[1] < 70003.01f);
+        assert(results[2] > -210000.01f && results[2] < -209999.99f);
+        assert(results[3] > -23333.34f && results[3] < -23333.32f);
+        assert(results[4] > 0.999f && results[4] < 1.001f);
+        assert(results[8] > 70000.99f && results[8] < 70001.01f);
+    }
+
+    /*
+     * We pass in the arguments and return the results so the compiler
+     * doesn't do the math for us.
+     */
+    static double[] doubleOperTest(double x, double y) {
+        System.out.println("FloatMath.doubleOperTest");
+
+        double[] results = new double[9];
+
+        /* this seems to generate "op-double" instructions */
+        results[0] = x + y;
+        results[1] = x - y;
+        results[2] = x * y;
+        results[3] = x / y;
+        results[4] = x % -y;
+
+        /* this seems to generate "op-double/2addr" instructions */
+        results[8] = x + (((((x + y) - y) * y) / y) % y);
+
+        return results;
+    }
+    static void doubleOperCheck(double[] results) {
+        assert(results[0] > 69996.99 && results[0] < 69997.01);
+        assert(results[1] > 70002.99 && results[1] < 70003.01);
+        assert(results[2] > -210000.01 && results[2] < -209999.99);
+        assert(results[3] > -23333.34 && results[3] < -23333.32);
+        assert(results[4] > 0.999 && results[4] < 1.001);
+        assert(results[8] > 70000.99 && results[8] < 70001.01);
+    }
+
+    /*
+     * Try to cause some unary operations.
+     */
+    static float unopTest(float f) {
+        f = -f;
+        return f;
+    }
+
+    static int[] convI(long l, float f, double d, float zero) {
+        int[] results = new int[6];
+        results[0] = (int) l;
+        results[1] = (int) f;
+        results[2] = (int) d;
+        results[3] = (int) (1.0f / zero);       // +inf
+        results[4] = (int) (-1.0f / zero);      // -inf
+        results[5] = (int) ((1.0f / zero) / (1.0f / zero)); // NaN
+        return results;
+    }
+    static void checkConvI(int[] results) {
+        System.out.println("FloatMath.checkConvI");
+        assert(results[0] == 0x44332211);
+        assert(results[1] == 123);
+        assert(results[2] == -3);
+        assert(results[3] == 0x7fffffff);
+        assert(results[4] == 0x80000000);
+        assert(results[5] == 0);
+    }
+
+    static long[] convL(int i, float f, double d, double zero) {
+        long[] results = new long[6];
+        results[0] = (long) i;
+        results[1] = (long) f;
+        results[2] = (long) d;
+        results[3] = (long) (1.0 / zero);       // +inf
+        results[4] = (long) (-1.0 / zero);      // -inf
+        results[5] = (long) ((1.0 / zero) / (1.0 / zero));  // NaN
+        return results;
+    }
+    static void checkConvL(long[] results) {
+        System.out.println("FloatMath.checkConvL");
+        assert(results[0] == 0xFFFFFFFF88776655L);
+        assert(results[1] == 123);
+        assert(results[2] == -3);
+        assert(results[3] == 0x7fffffffffffffffL);
+        assert(results[4] == 0x8000000000000000L);
+        assert(results[5] == 0);
+    }
+
+    static float[] convF(int i, long l, double d) {
+        float[] results = new float[3];
+        results[0] = (float) i;
+        results[1] = (float) l;
+        results[2] = (float) d;
+        return results;
+    }
+    static void checkConvF(float[] results) {
+        System.out.println("FloatMath.checkConvF");
+        // TODO: assert values
+        for (int i = 0; i < results.length; i++)
+            System.out.println(" " + i + ": " + results[i]);
+        System.out.println("-2.0054409E9, -8.6133031E18, -3.1415927");
+    }
+
+    static double[] convD(int i, long l, float f) {
+        double[] results = new double[3];
+        results[0] = (double) i;
+        results[1] = (double) l;
+        results[2] = (double) f;
+        return results;
+    }
+    static void checkConvD(double[] results) {
+        System.out.println("FloatMath.checkConvD");
+        // TODO: assert values
+        for (int i = 0; i < results.length; i++)
+            System.out.println(" " + i + ": " + results[i]);
+        System.out.println("-2.005440939E9, -8.6133032459203287E18, 123.4560012817382");
+    }
+
+    static void checkConsts() {
+        System.out.println("FloatMath.checkConsts");
+
+        float f = 10.0f;        // const/special
+        assert(f > 9.9 && f < 10.1);
+
+        double d = 10.0;        // const-wide/special
+        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();
+
+        float[] floatResults;
+        double[] doubleResults;
+        int[] intResults;
+        long[] longResults;
+
+        floatResults = floatOperTest(70000.0f, -3.0f);
+        floatOperCheck(floatResults);
+        doubleResults = doubleOperTest(70000.0, -3.0);
+        doubleOperCheck(doubleResults);
+
+        intResults = convI(0x8877665544332211L, 123.456f, -3.1415926535, 0.0f);
+        checkConvI(intResults);
+        longResults = convL(0x88776655, 123.456f, -3.1415926535, 0.0);
+        checkConvL(longResults);
+        floatResults = convF(0x88776655, 0x8877665544332211L, -3.1415926535);
+        checkConvF(floatResults);
+        doubleResults = convD(0x88776655, 0x8877665544332211L, 123.456f);
+        checkConvD(doubleResults);
+
+        unopTest(123.456f);
+
+        checkConsts();
+
+        jlmTests(3.14159f, 123456.78987654321);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Goto.java b/tests/003-omnibus-opcodes/src/Goto.java
new file mode 100644
index 0000000..d56ceae
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Goto.java
@@ -0,0 +1,2408 @@
+/*
+ * 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.
+ */
+
+/**
+ * Try to cause some gotos.
+ */
+class Goto {
+    static int filler(int i) {
+        return i+1;
+    }
+
+    static int smallGoto(boolean which) {
+        System.out.println("Goto.smallGoto");
+
+        int i = 0;
+
+        if (which) {
+            i += filler(i);
+        } else {
+            i -= filler(i);
+        }
+
+        return i;
+    }
+
+    static int mediumGoto(boolean which) {
+        System.out.println("Goto.mediumGoto");
+
+        int i = 0;
+
+        if (which) {
+            i += filler(i);
+        } else {
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+        }
+
+        return i;
+    }
+
+    static int bigGoto(boolean which) {
+        System.out.println("Goto.bigGoto");
+
+        int i = 0;
+
+        if (which) {
+            i += filler(i);
+        } else {
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+            i -= filler(i);  i -= filler(i);  i -= filler(i);  i -= filler(i);
+        }
+
+        return i;
+    }
+
+    public static void run() {
+        smallGoto(false);
+        smallGoto(true);
+        mediumGoto(false);
+        mediumGoto(true);
+        bigGoto(false);
+        bigGoto(true);
+    }
+};
diff --git a/tests/003-omnibus-opcodes/src/InstField.java b/tests/003-omnibus-opcodes/src/InstField.java
new file mode 100644
index 0000000..80b95ab
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/InstField.java
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+public class InstField {
+    public boolean mBoolean1, mBoolean2;
+    public byte mByte1, mByte2;
+    public char mChar1, mChar2;
+    public short mShort1, mShort2;
+    public int mInt1, mInt2;
+    public float mFloat1, mFloat2;
+    public long mLong1, mLong2;
+    public double mDouble1, mDouble2;
+    public volatile long mVolatileLong1, mVolatileLong2;
+
+    public void run() {
+        assignFields();
+        checkFields();
+        InstField.nullCheck(null);
+    }
+
+    /*
+     * Check access to instance fields through a null pointer.
+     */
+    static public void nullCheck(InstField nully) {
+        System.out.println("InstField.nullCheck");
+        try {
+            int x = nully.mInt1;
+            assert(false);
+        } catch (NullPointerException npe) {
+            // good
+        }
+        try {
+            long l = nully.mLong1;
+            assert(false);
+        } catch (NullPointerException npe) {
+            // good
+        }
+        try {
+            nully.mInt1 = 5;
+            assert(false);
+        } catch (NullPointerException npe) {
+            // good
+        }
+        try {
+            nully.mLong1 = 17L;
+            assert(false);
+        } catch (NullPointerException npe) {
+            // good
+        }
+    }
+
+    public void assignFields() {
+        System.out.println("InstField assign...");
+        mBoolean1 = true;
+        mBoolean2 = false;
+        mByte1 = 127;
+        mByte2 = -128;
+        mChar1 = 32767;
+        mChar2 = 65535;
+        mShort1 = 32767;
+        mShort2 = -32768;
+        mInt1 = 65537;
+        mInt2 = -65537;
+        mFloat1 = 3.1415f;
+        mFloat2 = -1.0f / 0.0f;                // -inf
+        mLong1 = 1234605616436508552L;     // 0x1122334455667788
+        mLong2 = -1234605616436508552L;
+        mDouble1 = 3.1415926535;
+        mDouble2 = 1.0 / 0.0;               // +inf
+        mVolatileLong1 = mLong1 - 1;
+        mVolatileLong2 = mLong2 + 1;
+    }
+
+    public void checkFields() {
+        System.out.println("InstField check...");
+        assert(mBoolean1);
+        assert(!mBoolean2);
+        assert(mByte1 == 127);
+        assert(mByte2 == -128);
+        assert(mChar1 == 32767);
+        assert(mChar2 == 65535);
+        assert(mShort1 == 32767);
+        assert(mShort2 == -32768);
+        assert(mInt1 == 65537);
+        assert(mInt2 == -65537);
+        assert(mFloat1 > 3.141f && mFloat1 < 3.142f);
+        assert(mFloat2 < mFloat1);
+        assert(mLong1 == 1234605616436508552L);
+        assert(mLong2 == -1234605616436508552L);
+        assert(mDouble1 > 3.141592653 && mDouble1 < 3.141592654);
+        assert(mDouble2 > mDouble1);
+        assert(mVolatileLong1 == 1234605616436508551L);
+        assert(mVolatileLong2 == -1234605616436508551L);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/IntMath.java b/tests/003-omnibus-opcodes/src/IntMath.java
new file mode 100644
index 0000000..89194de
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/IntMath.java
@@ -0,0 +1,492 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Test arithmetic operations.
+ */
+public class IntMath {
+
+    static void shiftTest1() {
+        System.out.println("IntMath.shiftTest1");
+
+        final int[] mBytes = {
+            0x11, 0x22, 0x33, 0x44, 0x88, 0x99, 0xaa, 0xbb
+        };
+        long l;
+        int i1, i2;
+
+        i1 = mBytes[0] | mBytes[1] << 8 | mBytes[2] << 16 | mBytes[3] << 24;
+        i2 = mBytes[4] | mBytes[5] << 8 | mBytes[6] << 16 | mBytes[7] << 24;
+        l = i1 | ((long)i2 << 32);
+
+        assert(i1 == 0x44332211);
+        assert(i2 == 0xbbaa9988);
+        assert(l == 0xbbaa998844332211L);
+
+        l = (long)mBytes[0]
+            | (long)mBytes[1] << 8
+            | (long)mBytes[2] << 16
+            | (long)mBytes[3] << 24
+            | (long)mBytes[4] << 32
+            | (long)mBytes[5] << 40
+            | (long)mBytes[6] << 48
+            | (long)mBytes[7] << 56;
+
+        assert(l == 0xbbaa998844332211L);
+    }
+
+    static void shiftTest2() {
+        System.out.println("IntMath.shiftTest2");
+
+        long    a = 0x11;
+        long    b = 0x22;
+        long    c = 0x33;
+        long    d = 0x44;
+        long    e = 0x55;
+        long    f = 0x66;
+        long    g = 0x77;
+        long    h = 0x88;
+
+        long    result = ((a << 56) | (b << 48) | (c << 40) | (d << 32) |
+                         (e << 24) | (f << 16) | (g <<  8) | h);
+
+        assert(result == 0x1122334455667788L);
+    }
+
+    static void unsignedShiftTest() {
+        System.out.println("IntMath.unsignedShiftTest");
+
+        byte b = -4;
+        short s = -4;
+        char c = 0xfffc;
+        int i = -4;
+
+        b >>>= 4;
+        s >>>= 4;
+        c >>>= 4;
+        i >>>= 4;
+
+        assert((int) b == -1);
+        assert((int) s == -1);
+        assert((int) c == 0x0fff);
+        assert(i == 268435455);
+    }
+
+    static void convTest() {
+        System.out.println("IntMath.convTest");
+
+        float f;
+        double d;
+        int i;
+        long l;
+
+        /* int --> long */
+        i = 7654;
+        l = (long) i;
+        assert(l == 7654L);
+
+        i = -7654;
+        l = (long) i;
+        assert(l == -7654L);
+
+        /* long --> int (with truncation) */
+        l = 5678956789L;
+        i = (int) l;
+        assert(i == 1383989493);
+
+        l = -5678956789L;
+        i = (int) l;
+        assert(i == -1383989493);
+    }
+
+    static void charSubTest() {
+        System.out.println("IntMath.charSubTest");
+
+        char char1 = 0x00e9;
+        char char2 = 0xffff;
+        int i;
+
+        /* chars are unsigned-expanded to ints before subtraction */
+        i = char1 - char2;
+        assert(i == 0xffff00ea);
+    }
+
+    /*
+     * We pass in the arguments and return the results so the compiler
+     * doesn't do the math for us.  (x=70000, y=-3)
+     */
+    static int[] intOperTest(int x, int y) {
+        System.out.println("IntMath.intOperTest");
+
+        int[] results = new int[10];
+
+        /* this seems to generate "op-int" instructions */
+        results[0] = x + y;
+        results[1] = x - y;
+        results[2] = x * y;
+        results[3] = x * x;
+        results[4] = x / y;
+        results[5] = x % -y;
+        results[6] = x & y;
+        results[7] = x | y;
+        results[8] = x ^ y;
+
+        /* this seems to generate "op-int/2addr" instructions */
+        results[9] = x + ((((((((x + y) - y) * y) / y) % y) & y) | y) ^ y);
+
+        return results;
+    }
+    static void intOperCheck(int[] results) {
+        System.out.println("IntMath.intOperCheck");
+
+        /* check this edge case while we're here (div-int/2addr) */
+        int minInt = -2147483648;
+        int negOne = -results[5];
+        int plusOne = 1;
+        int result = (((minInt + plusOne) - plusOne) / negOne) / negOne;
+        assert(result == minInt);
+
+        assert(results[0] == 69997);
+        assert(results[1] == 70003);
+        assert(results[2] == -210000);
+        assert(results[3] == 605032704);    // overflow / truncate
+        assert(results[4] == -23333);
+        assert(results[5] == 1);
+        assert(results[6] == 70000);
+        assert(results[7] == -3);
+        assert(results[8] == -70003);
+        assert(results[9] == 70000);
+    }
+
+    /*
+     * More operations, this time with 16-bit constants.  (x=77777)
+     */
+    static int[] lit16Test(int x) {
+        System.out.println("IntMath.lit16Test");
+
+        int[] results = new int[8];
+
+        /* try to generate op-int/lit16" instructions */
+        results[0] = x + 1000;
+        results[1] = 1000 - x;
+        results[2] = x * 1000;
+        results[3] = x / 1000;
+        results[4] = x % 1000;
+        results[5] = x & 1000;
+        results[6] = x | -1000;
+        results[7] = x ^ -1000;
+        return results;
+    }
+    static void lit16Check(int[] results) {
+        assert(results[0] == 78777);
+        assert(results[1] == -76777);
+        assert(results[2] == 77777000);
+        assert(results[3] == 77);
+        assert(results[4] == 777);
+        assert(results[5] == 960);
+        assert(results[6] == -39);
+        assert(results[7] == -76855);
+    }
+
+    /*
+     * More operations, this time with 8-bit constants.  (x=-55555)
+     */
+    static int[] lit8Test(int x) {
+        System.out.println("IntMath.lit8Test");
+
+        int[] results = new int[8];
+
+        /* try to generate op-int/lit8" instructions */
+        results[0] = x + 10;
+        results[1] = 10 - x;
+        results[2] = x * 10;
+        results[3] = x / 10;
+        results[4] = x % 10;
+        results[5] = x & 10;
+        results[6] = x | -10;
+        results[7] = x ^ -10;
+        return results;
+    }
+    static void lit8Check(int[] results) {
+        //for (int i = 0; i < results.length; i++)
+        //    System.out.println(" " + i + ": " + results[i]);
+
+        /* check this edge case while we're here (div-int/lit8) */
+        int minInt = -2147483648;
+        int result = minInt / -1;
+        assert(result == minInt);
+
+        assert(results[0] == -55545);
+        assert(results[1] == 55565);
+        assert(results[2] == -555550);
+        assert(results[3] == -5555);
+        assert(results[4] == -5);
+        assert(results[5] == 8);
+        assert(results[6] == -1);
+        assert(results[7] == 55563);
+    }
+
+
+    /*
+     * Shift some data.  (value=0xff00aa01, dist=8)
+     */
+    static int[] intShiftTest(int value, int dist) {
+        System.out.println("IntMath.intShiftTest");
+
+        int results[] = new int[4];
+
+        results[0] = value << dist;
+        results[1] = value >> dist;
+        results[2] = value >>> dist;
+
+        results[3] = (((value << dist) >> dist) >>> dist) << dist;
+        return results;
+    }
+    static void intShiftCheck(int[] results) {
+        System.out.println("IntMath.intShiftCheck");
+
+        assert(results[0] == 0x00aa0100);
+        assert(results[1] == 0xffff00aa);
+        assert(results[2] == 0x00ff00aa);
+        assert(results[3] == 0xaa00);
+    }
+
+    /*
+     * We pass in the arguments and return the results so the compiler
+     * doesn't do the math for us.  (x=70000000000, y=-3)
+     */
+    static long[] longOperTest(long x, long y) {
+        System.out.println("IntMath.longOperTest");
+
+        long[] results = new long[10];
+
+        /* this seems to generate "op-long" instructions */
+        results[0] = x + y;
+        results[1] = x - y;
+        results[2] = x * y;
+        results[3] = x * x;
+        results[4] = x / y;
+        results[5] = x % -y;
+        results[6] = x & y;
+        results[7] = x | y;
+        results[8] = x ^ y;
+
+        /* this seems to generate "op-long/2addr" instructions */
+        results[9] = x + ((((((((x + y) - y) * y) / y) % y) & y) | y) ^ y);
+
+        return results;
+    }
+    static void longOperCheck(long[] results) {
+        System.out.println("IntMath.longOperCheck");
+
+        /* check this edge case while we're here (div-long/2addr) */
+        long minLong = -9223372036854775808L;
+        long negOne = -results[5];
+        long plusOne = 1;
+        long result = (((minLong + plusOne) - plusOne) / negOne) / negOne;
+        assert(result == minLong);
+
+        assert(results[0] == 69999999997L);
+        assert(results[1] == 70000000003L);
+        assert(results[2] == -210000000000L);
+        assert(results[3] == -6833923606740729856L);    // overflow
+        assert(results[4] == -23333333333L);
+        assert(results[5] == 1);
+        assert(results[6] == 70000000000L);
+        assert(results[7] == -3);
+        assert(results[8] == -70000000003L);
+        assert(results[9] == 70000000000L);
+
+        assert(results.length == 10);
+    }
+
+    /*
+     * Shift some data.  (value=0xd5aa96deff00aa01, dist=8)
+     */
+    static long[] longShiftTest(long value, int dist) {
+        System.out.println("IntMath.longShiftTest");
+
+        long results[] = new long[4];
+
+        results[0] = value << dist;
+        results[1] = value >> dist;
+        results[2] = value >>> dist;
+
+        results[3] = (((value << dist) >> dist) >>> dist) << dist;
+        return results;
+    }
+    static long longShiftCheck(long[] results) {
+        System.out.println("IntMath.longShiftCheck");
+
+        assert(results[0] == 0x96deff00aa010000L);
+        assert(results[1] == 0xffffd5aa96deff00L);
+        assert(results[2] == 0x0000d5aa96deff00L);
+        assert(results[3] == 0xffff96deff000000L);
+
+        assert(results.length == 4);
+
+        return results[0];      // test return-long
+    }
+
+
+    /*
+     * Try to cause some unary operations.
+     */
+    static int unopTest(int x) {
+        x = -x;
+        x ^= 0xffffffff;
+        return x;
+    }
+    static void unopCheck(int result) {
+        assert(result == 37);
+    }
+
+    static class Shorty {
+        public short mShort;
+        public char mChar;
+        public byte mByte;
+    };
+
+    /*
+     * Truncate an int.
+     */
+    static Shorty truncateTest(int x) {
+        System.out.println("IntMath.truncateTest");
+        Shorty shorts = new Shorty();
+
+        shorts.mShort = (short) x;
+        shorts.mChar = (char) x;
+        shorts.mByte = (byte) x;
+        return shorts;
+    }
+    static void truncateCheck(Shorty shorts) {
+        assert(shorts.mShort == -5597);     // 0xea23
+        assert(shorts.mChar == 59939);      // 0xea23
+        assert(shorts.mByte == 35);         // 0x23
+    }
+
+    /*
+     * Verify that we get a divide-by-zero exception.
+     */
+    static void divideByZero(int z) {
+        System.out.println("IntMath.divideByZero");
+
+        try {
+            int x = 100 / z;
+            assert(false);
+        } catch (ArithmeticException ae) {
+        }
+
+        try {
+            int x = 100 % z;
+            assert(false);
+        } catch (ArithmeticException ae) {
+        }
+
+        try {
+            long x = 100L / z;
+            assert(false);
+        } catch (ArithmeticException ae) {
+        }
+
+        try {
+            long x = 100L % z;
+            assert(false);
+        } catch (ArithmeticException ae) {
+        }
+    }
+
+    /*
+     * Check an edge condition: dividing the most-negative integer by -1
+     * returns the most-negative integer, and doesn't cause an exception.
+     *
+     * Pass in -1, -1L.
+     */
+    static void bigDivideOverflow(int idiv, long ldiv) {
+        System.out.println("IntMath.bigDivideOverflow");
+        int mostNegInt = (int) 0x80000000;
+        long mostNegLong = (long) 0x8000000000000000L;
+
+        int intDivResult = mostNegInt / idiv;
+        int intModResult = mostNegInt % idiv;
+        long longDivResult = mostNegLong / ldiv;
+        long longModResult = mostNegLong % ldiv;
+
+        assert(intDivResult == mostNegInt);
+        assert(intModResult == 0);
+        assert(longDivResult == mostNegLong);
+        assert(longModResult == 0);
+    }
+
+    /*
+     * Check "const" instructions.  We use negative values to ensure that
+     * sign-extension is happening.
+     */
+    static void checkConsts(byte small, short medium, int large, long huge) {
+        System.out.println("IntMath.checkConsts");
+
+        assert(small == 1);                     // const/4
+        assert(medium == -256);                 // const/16
+        assert(medium == -256L);                // const-wide/16
+        assert(large == -88888);                // const
+        assert(large == -88888L);               // const-wide/32
+        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();
+        unsignedShiftTest();
+        convTest();
+        charSubTest();
+
+        int[] intResults;
+        long[] longResults;
+
+        intResults = intOperTest(70000, -3);
+        intOperCheck(intResults);
+        longResults = longOperTest(70000000000L, -3L);
+        longOperCheck(longResults);
+
+        intResults = lit16Test(77777);
+        lit16Check(intResults);
+        intResults = lit8Test(-55555);
+        lit8Check(intResults);
+
+        intResults = intShiftTest(0xff00aa01, 8);
+        intShiftCheck(intResults);
+        longResults = longShiftTest(0xd5aa96deff00aa01L, 16);
+        long longRet = longShiftCheck(longResults);
+        assert(longRet == 0x96deff00aa010000L);
+
+        Shorty shorts = truncateTest(-16717277);    // 0xff00ea23
+        truncateCheck(shorts);
+
+        divideByZero(0);
+        bigDivideOverflow(-1, -1L);
+
+        checkConsts((byte) 1, (short) -256, -88888, 0x9922334455667788L);
+
+        unopCheck(unopTest(38));
+
+        jlmTests(12345, 0x1122334455667788L);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/InternedString.java b/tests/003-omnibus-opcodes/src/InternedString.java
new file mode 100644
index 0000000..4baab0c
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/InternedString.java
@@ -0,0 +1,56 @@
+/*
+ * 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.lang.ref.*;
+
+public class InternedString {
+    public static final String CONST = "Class InternedString";
+
+    public static void run() {
+        System.out.println("InternedString.run");
+        testImmortalInternedString();
+        testDeadInternedString();
+    }
+
+    private static void testDeadInternedString() {
+        String s = "blah";
+        s = s + s;
+        WeakReference strRef = new WeakReference<String>(s.intern());
+        // Kill s, otherwise the string object is still accessible from root set
+        s = CONST;
+        System.gc();
+        // "blahblah" should disappear from the intern list
+        assert(strRef.get() == null);
+    }
+
+    private static void testImmortalInternedString() {
+        WeakReference strRef = new WeakReference<String>(CONST.intern());
+        System.gc();
+        // Class constant string should be entered to the interned table when
+        // loaded
+        assert(CONST == CONST.intern());
+        // and it should survive the gc
+        assert(strRef.get() != null);
+
+        String s = CONST;
+        // "Class InternedString" should remain on the intern list
+        strRef = new WeakReference<String>(s.intern());
+        // Kill s, otherwise the string object is still accessible from root set
+        s = "";
+        System.gc();
+        assert(strRef.get() == CONST);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Main.java b/tests/003-omnibus-opcodes/src/Main.java
new file mode 100644
index 0000000..fb39d76
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Main.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/**
+ * Dalvik instruction exerciser.
+ */
+public class Main {
+    /*
+     * Start up.
+     */
+    public static void main(String[] args) {
+        boolean assertEnabled = false;
+        assert assertEnabled = true;
+        if (!assertEnabled) {
+            System.out.println("FAIL: assert doesn't work (specify '-ea')\n");
+            throw new RuntimeException();
+        } else {
+            System.out.println("(assertions are enabled)");
+        }
+
+        Main main = new Main();
+        main.run();
+
+        /* run through the heap to see if we trashed something */
+        System.gc();
+
+        System.out.println("Done!");
+    }
+
+    public void run() {
+        InstField instField = new InstField();
+        instField.run();
+
+        StaticField.run();
+
+        IntMath.run();
+        FloatMath.run();
+        Compare.run();
+
+        Monitor.run();
+        Switch.run();
+        Array.run();
+        Classes.run();
+        Goto.run();
+        MethodCall.run();
+        Throw.run();
+
+        try {
+            UnresTest1.run();
+        } catch (VerifyError ve) {
+            System.out.println("Caught: " + ve);
+        }
+        try {
+            UnresTest1.run();
+        } catch (VerifyError ve) {
+            System.out.println("Caught (retry): " + ve);
+        }
+
+        try {
+            UnresTest2.run();
+        } catch (VerifyError ve) {
+            System.out.println("Caught: " + ve);
+        } catch (NoClassDefFoundError ncdfe) {
+            /* UnresClass can cause desktop Java to freak out */
+            System.out.println("NOTE: UnresTest2 not available");
+        }
+        InternedString.run();
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/MethodCall.java b/tests/003-omnibus-opcodes/src/MethodCall.java
new file mode 100644
index 0000000..f89194b
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/MethodCall.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/**
+ * Try different kinds of method calls.
+ */
+public class MethodCall extends MethodCallBase {
+    MethodCall() {
+        super();
+        System.out.println("  MethodCall ctor");
+    }
+
+    /* overridden method */
+    int tryThing() {
+        int val = super.tryThing();
+        assert(val == 7);
+        return val;
+    }
+
+    /* do-nothing private instance method */
+    private void directly() {}
+
+    /*
+     * Function with many arguments.
+     */
+    static void manyArgs(int a0, long a1, int a2, long a3, int a4, long a5,
+        int a6, int a7, double a8, float a9, double a10, short a11, int a12,
+        char a13, int a14, int a15, byte a16, boolean a17, int a18, int a19,
+        long a20, long a21, int a22, int a23, int a24, int a25, int a26,
+        String[][] a27, String[] a28, String a29)
+    {
+        System.out.println("MethodCalls.manyArgs");
+        assert(a0 == 0);
+        assert(a9 > 8.99 && a9 < 9.01);
+        assert(a16 == -16);
+        assert(a25 == 25);
+        assert(a29.equals("twenty nine"));
+    }
+
+    public static void run() {
+        MethodCall inst = new MethodCall();
+
+        MethodCallBase base = inst;
+        base.tryThing();
+        inst.tryThing();
+
+        inst = null;
+        try {
+            inst.directly();
+            assert(false);
+        } catch (NullPointerException npe) {
+            // good
+        }
+
+        manyArgs(0, 1L, 2, 3L, 4, 5L, 6, 7, 8.0, 9.0f, 10.0, (short)11, 12,
+            (char)13, 14, 15, (byte)-16, true, 18, 19, 20L, 21L, 22, 23, 24,
+            25, 26, null, null, "twenty nine");
+    }
+}
+
+class MethodCallBase {
+    MethodCallBase() {
+        System.out.println("  MethodCallBase ctor");
+    }
+
+    int tryThing() {
+        return 7;
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Monitor.java b/tests/003-omnibus-opcodes/src/Monitor.java
new file mode 100644
index 0000000..66d7c65
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Monitor.java
@@ -0,0 +1,44 @@
+// Copyright 2008 The Android Open Source Project
+
+
+
+/**
+ * Exercise monitors.
+ */
+public class Monitor {
+    public static int mVal = 0;
+
+    public synchronized void subTest() {
+        Object obj = new Object();
+        synchronized (obj) {
+            mVal++;
+            obj = null;     // does NOT cause a failure on exit
+            assert(obj == null);
+        }
+    }
+
+
+    public static void run() {
+        System.out.println("Monitor.run");
+
+        Object obj = null;
+
+        try {
+            synchronized (obj) {
+                mVal++;
+            }
+            assert(false);
+        } catch (NullPointerException npe) {
+            /* expected */
+        }
+
+        obj = new Object();
+        synchronized (obj) {
+            mVal++;
+        }
+
+        new Monitor().subTest();
+
+        assert(mVal == 2);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/StaticField.java b/tests/003-omnibus-opcodes/src/StaticField.java
new file mode 100644
index 0000000..7ccdd7e
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/StaticField.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+public class StaticField {
+    public static boolean mBoolean1, mBoolean2;
+    public static byte mByte1, mByte2;
+    public static char mChar1, mChar2;
+    public static short mShort1, mShort2;
+    public static int mInt1, mInt2;
+    public static float mFloat1, mFloat2;
+    public static long mLong1, mLong2;
+    public static double mDouble1, mDouble2;
+    public static volatile long mVolatileLong1, mVolatileLong2;
+
+    public static void run() {
+        assignFields();
+        checkFields();
+    }
+
+    public static void assignFields() {
+        System.out.println("StaticField assign...");
+        mBoolean1 = true;
+        mBoolean2 = false;
+        mByte1 = 127;
+        mByte2 = -128;
+        mChar1 = 32767;
+        mChar2 = 65535;
+        mShort1 = 32767;
+        mShort2 = -32768;
+        mInt1 = 65537;
+        mInt2 = -65537;
+        mFloat1 = 3.1415f;
+        mFloat2 = -1.0f / 0.0f;                // -inf
+        mLong1 = 1234605616436508552L;     // 0x1122334455667788
+        mLong2 = -1234605616436508552L;
+        mDouble1 = 3.1415926535;
+        mDouble2 = 1.0 / 0.0;               // +inf
+        mVolatileLong1 = mLong1 - 1;
+        mVolatileLong2 = mLong2 + 1;
+    }
+
+    public static void checkFields() {
+        System.out.println("StaticField check...");
+        assert(mBoolean1);
+        assert(!mBoolean2);
+        assert(mByte1 == 127);
+        assert(mByte2 == -128);
+        assert(mChar1 == 32767);
+        assert(mChar2 == 65535);
+        assert(mShort1 == 32767);
+        assert(mShort2 == -32768);
+        assert(mInt1 == 65537);
+        assert(mInt2 == -65537);
+        assert(mFloat1 > 3.141f && mFloat2 < 3.142f);
+        assert(mFloat2 < mFloat1);
+        assert(mLong1 == 1234605616436508552L);
+        assert(mLong2 == -1234605616436508552L);
+        assert(mDouble1 > 3.141592653 && mDouble1 < 3.141592654);
+        assert(mDouble2 > mDouble1);
+        assert(mVolatileLong1 == 1234605616436508551L);
+        assert(mVolatileLong2 == -1234605616436508551L);
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Switch.java b/tests/003-omnibus-opcodes/src/Switch.java
new file mode 100644
index 0000000..67c82b0
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Switch.java
@@ -0,0 +1,62 @@
+public class Switch {
+    /**
+     * Test switch() blocks
+     */
+    private static void testSwitch() {
+        System.out.println("Switch.testSwitch");
+
+        int a = 1;
+
+        switch (a) {
+            case -1: assert(false); break;
+            case 0: assert(false); break;
+            case 1: /*correct*/ break;
+            case 2: assert(false); break;
+            case 3: assert(false); break;
+            case 4: assert(false); break;
+            default: assert(false); break;
+        }
+        switch (a) {
+            case 3: assert(false); break;
+            case 4: assert(false); break;
+            default: /*correct*/ break;
+        }
+
+        a = 0x12345678;
+
+        switch (a) {
+            case 0x12345678: /*correct*/ break;
+            case 0x12345679: assert(false); break;
+            default: assert(false); break;
+        }
+        switch (a) {
+            case 57: assert(false); break;
+            case -6: assert(false); break;
+            case 0x12345678: /*correct*/ break;
+            case 22: assert(false); break;
+            case 3: assert(false); break;
+            default: assert(false); break;
+        }
+        switch (a) {
+            case -6: assert(false); break;
+            case 3: assert(false); break;
+            default: /*correct*/ break;
+        }
+
+        a = -5;
+        switch (a) {
+            case 12: assert(false); break;
+            case -5: /*correct*/ break;
+            case 0: assert(false); break;
+            default: assert(false); break;
+        }
+
+        switch (a) {
+            default: /*correct*/ break;
+        }
+    }
+
+    public static void run() {
+        testSwitch();
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/Throw.java b/tests/003-omnibus-opcodes/src/Throw.java
new file mode 100644
index 0000000..91ee6dd
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/Throw.java
@@ -0,0 +1,124 @@
+/*
+ * 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 exception throwing.
+ */
+public class Throw {
+    public void throwNullPointerException() {
+        throw new NullPointerException("npe!");
+    }
+
+    public void throwArithmeticException() {
+        throw new ArithmeticException();
+    }
+
+    public void one() {
+        System.out.println("Throw.one");
+        try {
+            throwNullPointerException();
+            assert(false);
+        } catch (Exception ex) {
+            // good
+            return;
+        }
+
+        assert(false);
+    }
+
+    public void twoA() {
+        System.out.println("Throw.twoA");
+        boolean gotN = false;
+        boolean gotA = false;
+        boolean gotWeird = false;
+
+        try {
+            try {
+                throwArithmeticException();
+                gotWeird = true;
+            } catch (ArithmeticException ae) {
+                gotA = true;
+            }
+        } catch (NullPointerException npe) {
+            gotN = true;
+        }
+
+        assert(gotA);
+        assert(!gotN);
+        assert(!gotWeird);
+    }
+
+    public void twoN() {
+        System.out.println("Throw.twoN");
+        boolean gotN = false;
+        boolean gotA = false;
+        boolean gotWeird = false;
+
+        try {
+            try {
+                throwNullPointerException();
+                gotWeird = true;
+            } catch (ArithmeticException ae) {
+                gotA = true;
+            }
+        } catch (NullPointerException npe) {
+            gotN = true;
+        }
+
+        assert(!gotA);
+        assert(gotN);
+        assert(!gotWeird);
+    }
+
+    public void rethrow() {
+        System.out.println("Throw.rethrow");
+        boolean caught = false;
+        boolean lly = false;
+        boolean second = false;
+
+        try {
+            try {
+                throwNullPointerException();
+                assert(false);
+            } catch (Exception ex) {
+                if (ex instanceof ArithmeticException) {
+                    assert(false);
+                }
+                if (ex instanceof NullPointerException) {
+                    caught = true;
+                    throw (NullPointerException) ex;
+                }
+            } finally {
+                lly = true;
+            }
+        } catch (Exception ex) {
+            second = true;
+        }
+
+        assert(caught);
+        assert(lly);
+        assert(second);
+    }
+
+    public static void run() {
+        Throw th = new Throw();
+
+        th.one();
+        th.twoA();
+        th.twoN();
+        th.rethrow();
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/UnresClass.java b/tests/003-omnibus-opcodes/src/UnresClass.java
new file mode 100644
index 0000000..52b3d4f
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/UnresClass.java
@@ -0,0 +1,9 @@
+/*
+ * Unresolved class.
+ *
+ * "happy" version.
+ */
+
+public class UnresClass {
+    int foo;
+}
diff --git a/tests/003-omnibus-opcodes/src/UnresStuff.java b/tests/003-omnibus-opcodes/src/UnresStuff.java
new file mode 100644
index 0000000..1d2a556
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/UnresStuff.java
@@ -0,0 +1,22 @@
+/*
+ * Unresolved classes / fields / methods in a resolved class.
+ *
+ * "happy" version.
+ */
+
+public class UnresStuff {
+    public int instField;
+
+    public static int staticField;
+
+    public double wideInstField;
+    public static double wideStaticField;
+
+    public void virtualMethod() {
+        System.out.println("unres!");
+    }
+
+    public static void staticMethod() {
+        System.out.println("unres!");
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/UnresTest1.java b/tests/003-omnibus-opcodes/src/UnresTest1.java
new file mode 100644
index 0000000..5a80a7a
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/UnresTest1.java
@@ -0,0 +1,80 @@
+/*
+ * Test failure to resolve class members.
+ */
+class UnresTest1 {
+    public static void run() {
+        System.out.println("UnresTest1...");
+
+        UnresStuff stuff = new UnresStuff();
+        try {
+            int x = stuff.instField;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+        try {       // hit the same one a second time
+            int x = stuff.instField;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+        try {
+            stuff.instField = 5;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+
+        try {
+            double d = stuff.wideInstField;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+        try {
+            stuff.wideInstField = 0.0;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+
+        try {
+            int y = UnresStuff.staticField;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+        try {
+            UnresStuff.staticField = 17;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+
+        try {
+            double d = UnresStuff.wideStaticField;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+        try {
+            UnresStuff.wideStaticField = 1.0;
+            assert(false);
+        } catch (NoSuchFieldError nsfe) {
+            // good
+        }
+
+        try {
+            stuff.virtualMethod();
+            assert(false);
+        } catch (NoSuchMethodError nsfe) {
+            // good
+        }
+        try {
+            UnresStuff.staticMethod();
+            assert(false);
+        } catch (NoSuchMethodError nsfe) {
+            // good
+        }
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src/UnresTest2.java b/tests/003-omnibus-opcodes/src/UnresTest2.java
new file mode 100644
index 0000000..768be8f
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src/UnresTest2.java
@@ -0,0 +1,49 @@
+/*
+ * Test failure to resolve classes.
+ */
+class UnresTest2 {
+    /*
+     * Try check-cast and instance-of.
+     */
+    static boolean checkCasts(Object obj) {
+        boolean foo = false;
+
+        try {
+            UnresClass un = (UnresClass) obj;
+            assert(false);
+        } catch (NoClassDefFoundError ncdfe) {
+            // good
+        }
+        try {
+            foo = obj instanceof UnresClass;
+            assert(false);
+        } catch (NoClassDefFoundError ncdfe) {
+            // good
+        }
+
+        return foo;
+    }
+
+    public static void run() {
+        System.out.println("UnresTest2...");
+        UnresClass un;
+        UnresStuff stuff = new UnresStuff();
+
+        try {
+            un = new UnresClass();
+            assert(false);
+        } catch (NoClassDefFoundError ncdfe) {
+            // good
+        }
+
+        try {
+            UnresClass[] uar = new UnresClass[3];
+            assert(false);
+        } catch (NoClassDefFoundError ncdfe) {
+            // good
+        }
+
+        checkCasts(stuff);
+        System.out.println("UnresTest2 done");
+    }
+}
diff --git a/tests/003-omnibus-opcodes/src2/UnresStuff.java b/tests/003-omnibus-opcodes/src2/UnresStuff.java
new file mode 100644
index 0000000..56f43af
--- /dev/null
+++ b/tests/003-omnibus-opcodes/src2/UnresStuff.java
@@ -0,0 +1,9 @@
+/*
+ * Unresolved classes / fields / methods in a resolved class.
+ *
+ * "happy" version.
+ */
+
+public class UnresStuff {
+    public int x;
+}
diff --git a/tests/004-annotations/expected.txt b/tests/004-annotations/expected.txt
new file mode 100644
index 0000000..8f19c4c
--- /dev/null
+++ b/tests/004-annotations/expected.txt
@@ -0,0 +1,96 @@
+TestAnnotations...
+java.lang.String android.test.anno.TestAnnotations.thing1: @android.test.anno.AnnoArrayField(bb=[], cc=[a, b], dd=[0.987654321], ff=[3.1415927], ii=[], jj=[], ss=[], str=[], zz=[])
+java.lang.String android.test.anno.TestAnnotations.thing2: @android.test.anno.AnnoArrayField(bb=[-1, 0, 1], cc=[Q], dd=[0.3, 0.6, 0.9], ff=[1.1, 1.2, 1.3], ii=[1, 2, 3, 4], jj=[-5, 0, 5], ss=[12, 13, 14, 15, 16, 17], str=[hickory, dickory, dock], zz=[true, false, true])
+mapping is class [Landroid.test.anno.IntToString;
+  0='@android.test.anno.IntToString(from=0, to=NORMAL_FOCUS)'
+  1='@android.test.anno.IntToString(from=2, to=WEAK_FOCUS)'
+present(getFocusType, ExportedProperty): true
+present(getFocusType, AnnoSimpleType): false
+
+AnnoSimpleField true, SimplyNoted false
+annotations on TYPE class android.test.anno.SimplyNoted(2):
+  @android.test.anno.AnnoSimpleType()
+    interface android.test.anno.AnnoSimpleType
+  @android.test.anno.AnnoSimpleType2()
+    interface android.test.anno.AnnoSimpleType2
+
+  annotations on CTOR android.test.anno.SimplyNoted():
+    @android.test.anno.AnnoSimpleConstructor()
+      interface android.test.anno.AnnoSimpleConstructor
+    constructor parameter annotations:
+  annotations on CTOR android.test.anno.SimplyNoted(int):
+    @android.test.anno.AnnoSimpleConstructor()
+      interface android.test.anno.AnnoSimpleConstructor
+    constructor parameter annotations:
+      @android.test.anno.AnnoSimpleParameter()
+        interface android.test.anno.AnnoSimpleParameter
+  annotations on METH public int android.test.anno.SimplyNoted.foo():
+    @android.test.anno.AnnoSimpleMethod()
+      interface android.test.anno.AnnoSimpleMethod
+    method parameter annotations:
+  annotations on FIELD public static int android.test.anno.SimplyNoted.mOneFoo:
+    @android.test.anno.AnnoSimpleField()
+      interface android.test.anno.AnnoSimpleField
+  annotations on FIELD public int android.test.anno.SimplyNoted.mFoo:
+    @android.test.anno.AnnoSimpleField()
+      interface android.test.anno.AnnoSimpleField
+
+annotations on TYPE interface android.test.anno.INoted(1):
+  @android.test.anno.AnnoSimpleType2()
+    interface android.test.anno.AnnoSimpleType2
+
+  annotations on METH public abstract int android.test.anno.INoted.bar():
+    @android.test.anno.AnnoSimpleMethod()
+      interface android.test.anno.AnnoSimpleMethod
+    method parameter annotations:
+
+annotations on TYPE class android.test.anno.SubNoted(3):
+  @android.test.anno.AnnoFancyType(name=unknown, num=5)
+    interface android.test.anno.AnnoFancyType
+  @android.test.anno.AnnoSimpleType()
+    interface android.test.anno.AnnoSimpleType
+  @android.test.anno.AnnoSimpleType2()
+    interface android.test.anno.AnnoSimpleType2
+
+  annotations on CTOR public android.test.anno.SubNoted():
+    constructor parameter annotations:
+  annotations on METH public int android.test.anno.SubNoted.bar():
+    method parameter annotations:
+  annotations on FIELD int android.test.anno.SubNoted.mBar:
+
+annotations on TYPE class android.test.anno.FullyNoted(1):
+  @android.test.anno.AnnoFancyType(name=full, num=5)
+    interface android.test.anno.AnnoFancyType
+
+  annotations on CTOR android.test.anno.FullyNoted(int):
+    @android.test.anno.AnnoFancyConstructor(numArgs=1)
+      interface android.test.anno.AnnoFancyConstructor
+    constructor parameter annotations:
+      @android.test.anno.AnnoFancyParameter(factor=0.5)
+        interface android.test.anno.AnnoFancyParameter
+  annotations on METH public int android.test.anno.FullyNoted.bar(int,long) throws java.io.IOException,java.io.EOFException:
+    @android.test.anno.AnnoFancyMethod(biteMe=false, callMe=true, enumerated=FOO, someClass=class android.test.anno.SomeClass)
+      interface android.test.anno.AnnoFancyMethod
+    method parameter annotations:
+      @android.test.anno.AnnoSimpleParameter()
+        interface android.test.anno.AnnoSimpleParameter
+      @android.test.anno.AnnoFancyParameter(factor=3.7879912899761)
+        interface android.test.anno.AnnoFancyParameter
+  annotations on METH public int android.test.anno.FullyNoted.bar1(int,long) throws java.io.IOException:
+    @android.test.anno.AnnoFancyMethod(biteMe=true, callMe=false, enumerated=BAR, someClass=class android.test.anno.SomeClass)
+      interface android.test.anno.AnnoFancyMethod
+    method parameter annotations:
+      @android.test.anno.AnnoSimpleParameter()
+        interface android.test.anno.AnnoSimpleParameter
+      @android.test.anno.AnnoFancyParameter(factor=3.7879912899761)
+        interface android.test.anno.AnnoFancyParameter
+  annotations on METH public int android.test.anno.FullyNoted.notAnnotated():
+    method parameter annotations:
+  annotations on FIELD int android.test.anno.FullyNoted.mBar:
+    @android.test.anno.AnnoFancyField(nombre=fubar)
+      interface android.test.anno.AnnoFancyField
+    aff: @android.test.anno.AnnoFancyField(nombre=fubar) / class $Proxy13
+    --> nombre is 'fubar'
+
+SimplyNoted.get(AnnoSimpleType) = @android.test.anno.AnnoSimpleType()
+SubNoted.get(AnnoSimpleType) = @android.test.anno.AnnoSimpleType()
diff --git a/tests/004-annotations/info.txt b/tests/004-annotations/info.txt
new file mode 100644
index 0000000..c8c9280
--- /dev/null
+++ b/tests/004-annotations/info.txt
@@ -0,0 +1 @@
+Test a bunch of uses of annotations.
diff --git a/tests/004-annotations/src/Main.java b/tests/004-annotations/src/Main.java
new file mode 100644
index 0000000..e44722f
--- /dev/null
+++ b/tests/004-annotations/src/Main.java
@@ -0,0 +1,7 @@
+import android.test.anno.TestAnnotations;
+
+public class Main {
+    static public void main(String[] args) {
+        TestAnnotations.main(args);
+    }
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoArrayField.java b/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
new file mode 100644
index 0000000..681045c
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoArrayField.java
@@ -0,0 +1,19 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Documented
+@Inherited
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnoArrayField {
+    boolean[] zz() default {};
+    byte[] bb() default {};
+    char[] cc() default {'a', 'b'};
+    short[] ss() default {};
+    int[] ii() default {};
+    float[] ff() default {3.141592654f};
+    long[] jj() default {};
+    double[] dd() default {0.987654321};
+    String[] str() default {};
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java b/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java
new file mode 100644
index 0000000..19dadec
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyConstructor.java
@@ -0,0 +1,10 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.CONSTRUCTOR)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoFancyConstructor {
+    public int numArgs() default 0;
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyField.java b/tests/004-annotations/src/android/test/anno/AnnoFancyField.java
new file mode 100644
index 0000000..855ba56
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyField.java
@@ -0,0 +1,12 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited      // should have no effect
+@Documented
+
+public @interface AnnoFancyField {
+    public String nombre() default "no se";
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java b/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java
new file mode 100644
index 0000000..3088866
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyMethod.java
@@ -0,0 +1,14 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoFancyMethod {
+    enum AnnoFancyMethodEnum { FOO, BAR };
+    boolean callMe() default false;
+    boolean biteMe();
+    AnnoFancyMethodEnum enumerated() default AnnoFancyMethodEnum.FOO;
+    Class someClass() default SomeClass.class;
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java b/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java
new file mode 100644
index 0000000..bc2ba7c
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyParameter.java
@@ -0,0 +1,10 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoFancyParameter {
+    double factor();
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoFancyType.java b/tests/004-annotations/src/android/test/anno/AnnoFancyType.java
new file mode 100644
index 0000000..745f838
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoFancyType.java
@@ -0,0 +1,11 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoFancyType {
+    public int num();
+    public String name() default "unknown";
+}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java
new file mode 100644
index 0000000..d66b9ae
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.CONSTRUCTOR)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoSimpleConstructor {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java
new file mode 100644
index 0000000..04193d2
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleField.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoSimpleField {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
new file mode 100644
index 0000000..a839fa2
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.LOCAL_VARIABLE)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoSimpleLocalVariable {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java
new file mode 100644
index 0000000..fcd9c0f
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleMethod.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoSimpleMethod {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java b/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java
new file mode 100644
index 0000000..4aadfe7
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimplePackage.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.PACKAGE)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoSimplePackage {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java
new file mode 100644
index 0000000..6e26ca3
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleParameter.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface AnnoSimpleParameter {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java
new file mode 100644
index 0000000..3bba3db
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleType.java
@@ -0,0 +1,9 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface AnnoSimpleType {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java
new file mode 100644
index 0000000..f74b291
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleType2.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface AnnoSimpleType2 {}
diff --git a/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java b/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
new file mode 100644
index 0000000..541d82e
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+
+public @interface AnnoSimpleTypeInvis {}
diff --git a/tests/004-annotations/src/android/test/anno/ExportedProperty.java b/tests/004-annotations/src/android/test/anno/ExportedProperty.java
new file mode 100644
index 0000000..810d28f
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/ExportedProperty.java
@@ -0,0 +1,12 @@
+/* part of test for array problem */
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target({ ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface ExportedProperty {
+    boolean resolveId() default false;
+    IntToString[] mapping() default { @IntToString(from = -1, to = "-1") };
+}
diff --git a/tests/004-annotations/src/android/test/anno/FullyNoted.java b/tests/004-annotations/src/android/test/anno/FullyNoted.java
new file mode 100644
index 0000000..76a7b04
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/FullyNoted.java
@@ -0,0 +1,39 @@
+
+package android.test.anno;
+
+import java.io.IOException;
+import java.io.EOFException;
+
+@AnnoFancyType(num=5, name="full")
+public class FullyNoted {
+    @AnnoFancyField(nombre="fubar")
+    int mBar;
+
+    @AnnoFancyConstructor(numArgs=1)
+    FullyNoted(@AnnoFancyParameter(factor=0.5) int bar)
+    {
+        mBar = bar;
+    }
+
+    @AnnoFancyMethod(callMe=true, biteMe=false)
+    public int bar(
+        @AnnoSimpleParameter int one,
+        @AnnoFancyParameter(factor=3.7879912899761) long two)
+        throws IOException, EOFException {
+
+        return 0;
+    }
+
+    @AnnoFancyMethod(biteMe=true, enumerated=AnnoFancyMethod.AnnoFancyMethodEnum.BAR)
+    public int bar1(
+        @AnnoSimpleParameter int one,
+        @AnnoFancyParameter(factor=3.7879912899761) long two)
+        throws IOException {
+
+        return 0;
+    }
+
+    public int notAnnotated() {
+        return 0;
+    }
+}
diff --git a/tests/004-annotations/src/android/test/anno/INoted.java b/tests/004-annotations/src/android/test/anno/INoted.java
new file mode 100644
index 0000000..b2cd007
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/INoted.java
@@ -0,0 +1,7 @@
+package android.test.anno;
+
+@AnnoSimpleType2
+public interface INoted {
+    @AnnoSimpleMethod
+    public int bar();
+}
diff --git a/tests/004-annotations/src/android/test/anno/IntToString.java b/tests/004-annotations/src/android/test/anno/IntToString.java
new file mode 100644
index 0000000..e84fcfa
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/IntToString.java
@@ -0,0 +1,12 @@
+/* part of test for array problem */
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+
+public @interface IntToString {
+    int from();
+    String to();
+}
diff --git a/tests/004-annotations/src/android/test/anno/SimplyNoted.java b/tests/004-annotations/src/android/test/anno/SimplyNoted.java
new file mode 100644
index 0000000..95a3d24
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/SimplyNoted.java
@@ -0,0 +1,30 @@
+package android.test.anno;
+
+@AnnoSimpleType
+@AnnoSimpleType2
+@AnnoSimpleTypeInvis
+public class SimplyNoted {
+    @AnnoSimpleField
+    public int mFoo;
+
+    @AnnoSimpleField
+    public static int mOneFoo;
+
+    @AnnoSimpleConstructor
+    SimplyNoted() {
+        mFoo = 0;
+    }
+
+    @AnnoSimpleConstructor
+    SimplyNoted(@AnnoSimpleParameter int xyzzy) {
+        mFoo = xyzzy;
+    }
+
+    @AnnoSimpleMethod
+    public int foo() {
+        @AnnoSimpleLocalVariable
+        int bar = 5;
+
+        return bar;
+    }
+}
diff --git a/tests/004-annotations/src/android/test/anno/SomeClass.java b/tests/004-annotations/src/android/test/anno/SomeClass.java
new file mode 100644
index 0000000..c21d68d
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/SomeClass.java
@@ -0,0 +1,4 @@
+package android.test.anno;
+
+public class SomeClass {
+}
diff --git a/tests/004-annotations/src/android/test/anno/SubNoted.java b/tests/004-annotations/src/android/test/anno/SubNoted.java
new file mode 100644
index 0000000..2530346
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/SubNoted.java
@@ -0,0 +1,12 @@
+package android.test.anno;
+
+@AnnoFancyType(num=5)       // first occurrence of AnnoFancyType
+                            // we inherit @AnnoSimpleType
+@AnnoSimpleType2            // AnnoSimpleType2 here *and* inherited from parent
+public class SubNoted extends SimplyNoted implements INoted {
+    int mBar;
+
+    public int bar() {
+        return 0;
+    }
+}
diff --git a/tests/004-annotations/src/android/test/anno/TestAnnotations.java b/tests/004-annotations/src/android/test/anno/TestAnnotations.java
new file mode 100644
index 0000000..4ad32d5
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/TestAnnotations.java
@@ -0,0 +1,177 @@
+package android.test.anno;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.TreeMap;
+
+public class TestAnnotations {
+    /**
+     * Print the annotations in sorted order, so as to avoid
+     * any (legitimate) non-determinism with regard to the iteration order.
+     */
+    static private void printAnnotationArray(String prefix, Annotation[] arr) {
+        TreeMap<String, Annotation> sorted =
+            new TreeMap<String, Annotation>();
+
+        for (Annotation a : arr) {
+            sorted.put(a.annotationType().getName(), a);
+        }
+
+        for (Annotation a : sorted.values()) {
+            System.out.println(prefix + "  " + a);
+            System.out.println(prefix + "    " + a.annotationType());
+        }
+    }
+
+    static void printAnnotations(Class clazz) {
+        Annotation[] annos;
+        Annotation[][] parAnnos;
+
+        annos = clazz.getAnnotations();
+        System.out.println("annotations on TYPE " + clazz +
+            "(" + annos.length + "):");
+        printAnnotationArray("", annos);
+        System.out.println();
+
+        for (Constructor c: clazz.getDeclaredConstructors()) {
+            annos = c.getDeclaredAnnotations();
+            System.out.println("  annotations on CTOR " + c + ":");
+            printAnnotationArray("  ", annos);
+
+            System.out.println("    constructor parameter annotations:");
+            for (Annotation[] pannos: c.getParameterAnnotations()) {
+                printAnnotationArray("    ", pannos);
+            }
+        }
+
+        for (Method m: clazz.getDeclaredMethods()) {
+            annos = m.getDeclaredAnnotations();
+            System.out.println("  annotations on METH " + m + ":");
+            printAnnotationArray("  ", annos);
+
+            System.out.println("    method parameter annotations:");
+            for (Annotation[] pannos: m.getParameterAnnotations()) {
+                printAnnotationArray("    ", pannos);
+            }
+        }
+
+        for (Field f: clazz.getDeclaredFields()) {
+            annos = f.getDeclaredAnnotations();
+            System.out.println("  annotations on FIELD " + f + ":");
+            printAnnotationArray("  ", annos);
+
+            AnnoFancyField aff;
+            aff = (AnnoFancyField) f.getAnnotation(AnnoFancyField.class);
+            if (aff != null) {
+                System.out.println("    aff: " + aff + " / " + aff.getClass());
+                System.out.println("    --> nombre is '" + aff.nombre() + "'");
+            }
+        }
+        System.out.println();
+    }
+
+
+    @ExportedProperty(mapping = {
+        @IntToString(from = 0, to = "NORMAL_FOCUS"),
+        @IntToString(from = 2, to = "WEAK_FOCUS")
+    })
+    public int getFocusType() {
+        return 2;
+    }
+
+
+    @AnnoArrayField
+    String thing1;
+
+    @AnnoArrayField(
+            zz = {true,false,true},
+            bb = {-1,0,1},
+            cc = {'Q'},
+            ss = {12,13,14,15,16,17},
+            ii = {1,2,3,4},
+            ff = {1.1f,1.2f,1.3f},
+            jj = {-5,0,5},
+            dd = {0.3,0.6,0.9},
+            str = {"hickory","dickory","dock"}
+            )
+    String thing2;
+
+    public static void testArrays() {
+        TestAnnotations ta = new TestAnnotations();
+        Field field;
+        Annotation[] annotations;
+
+        try {
+            field = TestAnnotations.class.getDeclaredField("thing1");
+            annotations = field.getAnnotations();
+            System.out.println(field + ": " + annotations[0].toString());
+
+            field = TestAnnotations.class.getDeclaredField("thing2");
+            annotations = field.getAnnotations();
+            System.out.println(field + ": " + annotations[0].toString());
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        }
+    }
+
+    public static void testArrayProblem() {
+        Method meth;
+        ExportedProperty property;
+        final IntToString[] mapping;
+
+        try {
+            meth = TestAnnotations.class.getMethod("getFocusType",
+                    (Class[])null);
+        } catch (NoSuchMethodException nsme) {
+            throw new RuntimeException(nsme);
+        }
+        property = meth.getAnnotation(ExportedProperty.class);
+        mapping = property.mapping();
+
+        System.out.println("mapping is " + mapping.getClass() +
+            "\n  0='" + mapping[0] + "'\n  1='" + mapping[1] + "'");
+
+        /* while we're here, check isAnnotationPresent on Method */
+        System.out.println("present(getFocusType, ExportedProperty): " +
+            meth.isAnnotationPresent(ExportedProperty.class));
+        System.out.println("present(getFocusType, AnnoSimpleType): " +
+            meth.isAnnotationPresent(AnnoSimpleType.class));
+
+        System.out.println("");
+    }
+
+
+
+    public static void main(String[] args) {
+        System.out.println("TestAnnotations...");
+
+        testArrays();
+        testArrayProblem();
+        //System.exit(0);
+
+        System.out.println(
+            "AnnoSimpleField " + AnnoSimpleField.class.isAnnotation() +
+            ", SimplyNoted " + SimplyNoted.class.isAnnotation());
+
+        Class clazz;
+        clazz = SimplyNoted.class;
+        printAnnotations(clazz);
+        clazz = INoted.class;
+        printAnnotations(clazz);
+        clazz = SubNoted.class;
+        printAnnotations(clazz);
+        clazz = FullyNoted.class;
+        printAnnotations(clazz);
+
+        Annotation anno;
+
+        // this is expected to be non-null
+        anno = SimplyNoted.class.getAnnotation(AnnoSimpleType.class);
+        System.out.println("SimplyNoted.get(AnnoSimpleType) = " + anno);
+        // this is non-null if the @Inherited tag is present
+        anno = SubNoted.class.getAnnotation(AnnoSimpleType.class);
+        System.out.println("SubNoted.get(AnnoSimpleType) = " + anno);
+    }
+}
diff --git a/tests/004-annotations/src/android/test/anno/package-info.java b/tests/004-annotations/src/android/test/anno/package-info.java
new file mode 100644
index 0000000..74b11f9
--- /dev/null
+++ b/tests/004-annotations/src/android/test/anno/package-info.java
@@ -0,0 +1,2 @@
+@AnnoSimplePackage
+package android.test.anno;
diff --git a/tests/005-args/expected.txt b/tests/005-args/expected.txt
new file mode 100644
index 0000000..094fbbb
--- /dev/null
+++ b/tests/005-args/expected.txt
@@ -0,0 +1,5 @@
+VALUES: 1122334455667788 9887766554433221 1122334455667788
+VALUES: 1234605616436508552 -7455860480511102431 1234605616436508552
+1234605616436508552
+j = 1234605616436508552
+a=123 c=q d=3.343434 j=1234605616436508552 f=0.12345
diff --git a/tests/005-args/info.txt b/tests/005-args/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/005-args/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/005-args/src/ArgsTest.java b/tests/005-args/src/ArgsTest.java
new file mode 100644
index 0000000..2b874cd
--- /dev/null
+++ b/tests/005-args/src/ArgsTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+class ArgsTest{
+    public ArgsTest() {
+
+    }
+
+    private long mLongArray[] = new long[] {
+        0x1122334455667788L, 0x9887766554433221L };
+
+    /**
+     *
+     * @param a
+     * @param c
+     * @param d
+     * @param j
+     * @param f
+     */
+    void argTest(int a, char c, double d, long j, float f) {
+        System.out.println("VALUES: " + Long.toHexString(mLongArray[0]) + " "
+            + Long.toHexString(mLongArray[1]) + " " + Long.toHexString(j));
+        System.out.println("VALUES: " + mLongArray[0] + " "
+            + mLongArray[1] + " " + j);
+
+        System.out.println(j);
+        System.out.println("j = " + j);
+        System.out.println("a=" + a + " c=" + c + " d=" + d
+            + " j=" + j + " f=" + f);
+    }
+}
diff --git a/tests/005-args/src/Main.java b/tests/005-args/src/Main.java
new file mode 100644
index 0000000..1240ec5
--- /dev/null
+++ b/tests/005-args/src/Main.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test passing arguments of various sizes
+ */
+public class Main {
+    public static void main (String args[]) {
+        new ArgsTest()
+                .argTest(123, 'q', 3.343434, 0x1122334455667788L, 0.12345f);
+    }
+}
diff --git a/tests/006-count10/expected.txt b/tests/006-count10/expected.txt
new file mode 100644
index 0000000..8b1acc1
--- /dev/null
+++ b/tests/006-count10/expected.txt
@@ -0,0 +1,10 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
diff --git a/tests/006-count10/info.txt b/tests/006-count10/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/006-count10/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/006-count10/src/Main.java b/tests/006-count10/src/Main.java
new file mode 100644
index 0000000..650d053
--- /dev/null
+++ b/tests/006-count10/src/Main.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Simple loop-and-print
+ */
+public class Main {
+    public static void main(String args[]) {
+        for (int i = 0; i < 10; i++) {
+            System.out.println(i);
+        }
+    }
+}
diff --git a/tests/007-exceptions/expected.txt b/tests/007-exceptions/expected.txt
new file mode 100644
index 0000000..2a31636
--- /dev/null
+++ b/tests/007-exceptions/expected.txt
@@ -0,0 +1,9 @@
+Got an NPE: second throw
+java.lang.NullPointerException: second throw
+	at Main.catchAndRethrow(Main.java:36)
+	at Main.main(Main.java:23)
+	at dalvik.system.NativeStart.main(Native Method)
+Caused by: java.lang.NullPointerException: first throw
+	at Main.throwNullPointerException(Main.java:43)
+	at Main.catchAndRethrow(Main.java:33)
+	... 2 more
diff --git a/tests/007-exceptions/info.txt b/tests/007-exceptions/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/007-exceptions/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/007-exceptions/src/Main.java b/tests/007-exceptions/src/Main.java
new file mode 100644
index 0000000..c7da215
--- /dev/null
+++ b/tests/007-exceptions/src/Main.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/**
+ * Exceptions across method calls
+ */
+public class Main {
+    public static void main (String args[]) {
+        try {
+            catchAndRethrow();
+        } catch (NullPointerException npe) {
+            System.out.print("Got an NPE: ");
+            System.out.println(npe.getMessage());
+            npe.printStackTrace();
+        }
+    }
+
+    private static void catchAndRethrow() {
+        try {
+            throwNullPointerException();
+        } catch (NullPointerException npe) {
+            NullPointerException npe2;
+            npe2 = new NullPointerException("second throw");
+            npe2.initCause(npe);
+            throw npe2;
+        }
+    }
+
+    private static void throwNullPointerException() {
+        throw new NullPointerException("first throw");
+    }
+}
diff --git a/tests/008-instanceof/expected.txt b/tests/008-instanceof/expected.txt
new file mode 100644
index 0000000..77fd0cb
--- /dev/null
+++ b/tests/008-instanceof/expected.txt
@@ -0,0 +1,6 @@
+iface1.mFloaty = 5.0 wahoo
+aa.mFloaty = 5.0 wahoo
+bb.mWhoami = ImplB!
+aaOkay (false) = false
+bbOkay (true) = true
+Caught a ClassCastException (expected)
diff --git a/tests/008-instanceof/info.txt b/tests/008-instanceof/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/008-instanceof/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/008-instanceof/src/Iface1.java b/tests/008-instanceof/src/Iface1.java
new file mode 100644
index 0000000..ba17d45
--- /dev/null
+++ b/tests/008-instanceof/src/Iface1.java
@@ -0,0 +1,13 @@
+// Copyright 2005 The Android Open Source Project
+
+/**
+ * Test stuff.
+ */
+public interface Iface1 {
+
+    public int iFunc1(int ii);
+
+    public float mFloaty = 5.0f;
+
+    public String mWahoo = new String("wahoo");
+}
diff --git a/tests/008-instanceof/src/Iface2.java b/tests/008-instanceof/src/Iface2.java
new file mode 100644
index 0000000..83fe650
--- /dev/null
+++ b/tests/008-instanceof/src/Iface2.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2 {
+
+    public int iFunc2(int ii);
+}
diff --git a/tests/008-instanceof/src/Iface2Sub1.java b/tests/008-instanceof/src/Iface2Sub1.java
new file mode 100644
index 0000000..db3e905
--- /dev/null
+++ b/tests/008-instanceof/src/Iface2Sub1.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2Sub1 extends Iface2, Cloneable {
+
+    //public int iFunc2(int ii);
+}
diff --git a/tests/008-instanceof/src/ImplA.java b/tests/008-instanceof/src/ImplA.java
new file mode 100644
index 0000000..9007001
--- /dev/null
+++ b/tests/008-instanceof/src/ImplA.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplA implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+1;
+    }
+    public int iFunc2(int ii) {
+        return ii+2;
+    }
+}
diff --git a/tests/008-instanceof/src/ImplB.java b/tests/008-instanceof/src/ImplB.java
new file mode 100644
index 0000000..619fa00
--- /dev/null
+++ b/tests/008-instanceof/src/ImplB.java
@@ -0,0 +1,16 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplB implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+10;
+    }
+    public int iFunc2(int ii) {
+        return ii+20;
+    }
+
+    public static String mWhoami = new String("ImplB!");
+}
diff --git a/tests/008-instanceof/src/ImplBSub.java b/tests/008-instanceof/src/ImplBSub.java
new file mode 100644
index 0000000..f3a7714
--- /dev/null
+++ b/tests/008-instanceof/src/ImplBSub.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Interface test.
+ */
+public class ImplBSub extends ImplB implements /*Iface2,*/ Iface2Sub1 {
+
+    public int iFunc1(int ii) {
+        return ii+100;
+    }
+    public int iFunc2(int ii) {
+        return ii+200;
+    }
+}
diff --git a/tests/008-instanceof/src/Main.java b/tests/008-instanceof/src/Main.java
new file mode 100644
index 0000000..77f3f51
--- /dev/null
+++ b/tests/008-instanceof/src/Main.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test instanceof
+ */
+public class Main {
+    public static void main(String args[]) {
+        Iface1 face1;
+        ImplA aa = new ImplA();
+        ImplBSub bb = new ImplBSub();
+        boolean aaOkay, bbOkay;
+
+        face1 = aa;
+        face1 = bb;
+
+        System.out.println("iface1.mFloaty = " + face1.mFloaty + " " + face1.mWahoo);
+        System.out.println("aa.mFloaty = " + aa.mFloaty + " " + aa.mWahoo);
+        System.out.println("bb.mWhoami = " + bb.mWhoami);
+
+        aaOkay = face1 instanceof ImplA;
+        System.out.print("aaOkay (false) = ");
+        System.out.println(aaOkay);
+        bbOkay = face1 instanceof ImplB;
+        System.out.print("bbOkay (true) = ");
+        System.out.println(bbOkay);
+
+        bb = (ImplBSub) face1;
+        try {
+            aa = (ImplA) face1;
+        }
+        catch (ClassCastException cce) {
+            System.out.println("Caught a ClassCastException (expected)");
+        }
+    }
+}
diff --git a/tests/009-instanceof2/expected.txt b/tests/009-instanceof2/expected.txt
new file mode 100644
index 0000000..74ad202
--- /dev/null
+++ b/tests/009-instanceof2/expected.txt
@@ -0,0 +1,5 @@
+instanceof Serializable = true
+instanceof Cloneable = true
+instanceof Runnable = false
+aaOkay (false) = false
+bbOkay (true) = true
diff --git a/tests/009-instanceof2/info.txt b/tests/009-instanceof2/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/009-instanceof2/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/009-instanceof2/src/Iface1.java b/tests/009-instanceof2/src/Iface1.java
new file mode 100644
index 0000000..ba17d45
--- /dev/null
+++ b/tests/009-instanceof2/src/Iface1.java
@@ -0,0 +1,13 @@
+// Copyright 2005 The Android Open Source Project
+
+/**
+ * Test stuff.
+ */
+public interface Iface1 {
+
+    public int iFunc1(int ii);
+
+    public float mFloaty = 5.0f;
+
+    public String mWahoo = new String("wahoo");
+}
diff --git a/tests/009-instanceof2/src/Iface2.java b/tests/009-instanceof2/src/Iface2.java
new file mode 100644
index 0000000..83fe650
--- /dev/null
+++ b/tests/009-instanceof2/src/Iface2.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2 {
+
+    public int iFunc2(int ii);
+}
diff --git a/tests/009-instanceof2/src/Iface2Sub1.java b/tests/009-instanceof2/src/Iface2Sub1.java
new file mode 100644
index 0000000..db3e905
--- /dev/null
+++ b/tests/009-instanceof2/src/Iface2Sub1.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2Sub1 extends Iface2, Cloneable {
+
+    //public int iFunc2(int ii);
+}
diff --git a/tests/009-instanceof2/src/ImplA.java b/tests/009-instanceof2/src/ImplA.java
new file mode 100644
index 0000000..9007001
--- /dev/null
+++ b/tests/009-instanceof2/src/ImplA.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplA implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+1;
+    }
+    public int iFunc2(int ii) {
+        return ii+2;
+    }
+}
diff --git a/tests/009-instanceof2/src/ImplB.java b/tests/009-instanceof2/src/ImplB.java
new file mode 100644
index 0000000..619fa00
--- /dev/null
+++ b/tests/009-instanceof2/src/ImplB.java
@@ -0,0 +1,16 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplB implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+10;
+    }
+    public int iFunc2(int ii) {
+        return ii+20;
+    }
+
+    public static String mWhoami = new String("ImplB!");
+}
diff --git a/tests/009-instanceof2/src/ImplBSub.java b/tests/009-instanceof2/src/ImplBSub.java
new file mode 100644
index 0000000..f3a7714
--- /dev/null
+++ b/tests/009-instanceof2/src/ImplBSub.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Interface test.
+ */
+public class ImplBSub extends ImplB implements /*Iface2,*/ Iface2Sub1 {
+
+    public int iFunc1(int ii) {
+        return ii+100;
+    }
+    public int iFunc2(int ii) {
+        return ii+200;
+    }
+}
diff --git a/tests/009-instanceof2/src/Main.java b/tests/009-instanceof2/src/Main.java
new file mode 100644
index 0000000..15a1e50
--- /dev/null
+++ b/tests/009-instanceof2/src/Main.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/**
+ * more instanceof cases
+ */
+public class Main {
+    public static void main(String args[]) {
+        Iface1[] faceArray;
+        ImplA[] aaArray = new ImplA[5];
+        ImplBSub[] bbArray = new ImplBSub[5];
+        boolean aaOkay, bbOkay;
+
+        faceArray = aaArray;
+        faceArray = bbArray;
+
+        System.out.print("instanceof Serializable = ");
+        System.out.println((Object)aaArray instanceof java.io.Serializable);
+        System.out.print("instanceof Cloneable = ");
+        System.out.println((Object)aaArray instanceof java.lang.Cloneable);
+        System.out.print("instanceof Runnable = ");
+        System.out.println((Object)aaArray instanceof java.lang.Runnable);
+
+        aaOkay = faceArray instanceof ImplA[];
+        System.out.print("aaOkay (false) = ");
+        System.out.println(aaOkay);
+        bbOkay = faceArray instanceof ImplB[];
+        System.out.print("bbOkay (true) = ");
+        System.out.println(bbOkay);
+    }
+}
diff --git a/tests/010-instance/expected.txt b/tests/010-instance/expected.txt
new file mode 100644
index 0000000..219dd06
--- /dev/null
+++ b/tests/010-instance/expected.txt
@@ -0,0 +1,30 @@
+instance begin
+x instanceof X (true): true
+x instanceof Y (false): false
+y instanceof X (true): true
+y instanceof Y (true): true
+xar instanceof Object (true): true
+xar instanceof X (false): false
+xar instanceof X[] (true): true
+xar instanceof Y[] (false): false
+xar instanceof Object[] (true): true
+xar instanceof X[][] (false): false
+yar instanceof X[] (true): true
+xararar instanceof Object (true): true
+xararar instanceof Object[] (true): true
+xararar instanceof X (false): false
+xararar instanceof X[] (false): false
+xararar instanceof X[][] (false): false
+xararar instanceof X[][][] (true): true
+xararar instanceof Object[][][] (true): true
+xararar instanceof Serializable (true): true
+xararar instanceof Serializable[] (true): true
+xararar instanceof Serializable[][] (true): true
+xararar instanceof Serializable[][][] (false): false
+yararar instanceof X[][][] (true): true
+iar instanceof Object (true): true
+iar instanceof Object[] (false): false
+iarar instanceof Object (true): true
+iarar instanceof Object[] (true): true
+iarar instanceof Object[][] (false): false
+instanceof end
diff --git a/tests/010-instance/info.txt b/tests/010-instance/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/010-instance/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/010-instance/src/InstanceTest.java b/tests/010-instance/src/InstanceTest.java
new file mode 100644
index 0000000..78384ff
--- /dev/null
+++ b/tests/010-instance/src/InstanceTest.java
@@ -0,0 +1,93 @@
+// Copyright 2006 The Android Open Source Project
+
+import java.io.Serializable;
+
+/**
+ * Test some instanceof stuff.
+ */
+public class InstanceTest {
+    public static void main(String[] args) {
+        System.out.println("instance begin");
+
+        X x = new X();
+        X[] xar = new X[1];
+        X[][] xarar = new X[1][1];
+        X[][][] xararar = new X[1][1][1];
+        Y y = new Y();
+        Y[] yar = new Y[1];
+        Y[][] yarar = new Y[1][1];
+        Y[][][] yararar = new Y[1][1][1];
+        int[] iar = new int[1];
+        int[][] iarar = new int[1][1];
+        Object test;
+
+        test = x;
+        System.out.println("x instanceof X (true): " + (test instanceof X));
+        System.out.println("x instanceof Y (false): " + (test instanceof Y));
+        test = y;
+        System.out.println("y instanceof X (true): " + (test instanceof X));
+        System.out.println("y instanceof Y (true): " + (test instanceof Y));
+
+        test = xar;
+        System.out.println("xar instanceof Object (true): "
+            + (test instanceof Object));
+        System.out.println("xar instanceof X (false): "
+            + (test instanceof X));
+        System.out.println("xar instanceof X[] (true): "
+            + (test instanceof X[]));
+        System.out.println("xar instanceof Y[] (false): "
+            + (test instanceof Y[]));
+        System.out.println("xar instanceof Object[] (true): "
+            + (test instanceof Object[]));
+        System.out.println("xar instanceof X[][] (false): "
+            + (test instanceof X[][]));
+        test = yar;
+        System.out.println("yar instanceof X[] (true): "
+            + (test instanceof X[]));
+
+        test = xararar;
+        System.out.println("xararar instanceof Object (true): "
+            + (test instanceof Object));
+        System.out.println("xararar instanceof Object[] (true): "
+            + (test instanceof Object[]));
+        System.out.println("xararar instanceof X (false): "
+            + (test instanceof X));
+        System.out.println("xararar instanceof X[] (false): "
+            + (test instanceof X[]));
+        System.out.println("xararar instanceof X[][] (false): "
+            + (test instanceof X[][]));
+        System.out.println("xararar instanceof X[][][] (true): "
+            + (test instanceof X[][][]));
+        System.out.println("xararar instanceof Object[][][] (true): "
+            + (test instanceof Object[][][]));
+
+        System.out.println("xararar instanceof Serializable (true): "
+            + (test instanceof Serializable));
+        System.out.println("xararar instanceof Serializable[] (true): "
+            + (test instanceof Serializable[]));
+        System.out.println("xararar instanceof Serializable[][] (true): "
+            + (test instanceof Serializable[][]));
+        System.out.println("xararar instanceof Serializable[][][] (false): "
+            + (test instanceof Serializable[][][]));
+
+        test = yararar;
+        System.out.println("yararar instanceof X[][][] (true): "
+            + (test instanceof X[][][]));
+
+        test = iar;
+        System.out.println("iar instanceof Object (true): "
+            + (test instanceof Object));
+        System.out.println("iar instanceof Object[] (false): "
+            + (test instanceof Object[]));
+
+        test = iarar;
+        System.out.println("iarar instanceof Object (true): "
+            + (test instanceof Object));
+        System.out.println("iarar instanceof Object[] (true): "
+            + (test instanceof Object[]));
+        System.out.println("iarar instanceof Object[][] (false): "
+            + (test instanceof Object[][]));
+
+        System.out.println("instanceof end");
+    }
+}
diff --git a/tests/010-instance/src/Main.java b/tests/010-instance/src/Main.java
new file mode 100644
index 0000000..ab0ab5e
--- /dev/null
+++ b/tests/010-instance/src/Main.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * even more instanceof cases
+ */
+public class Main {
+    public static void main(String args[]) {
+        InstanceTest.main(null);
+    }
+}
diff --git a/tests/010-instance/src/X.java b/tests/010-instance/src/X.java
new file mode 100644
index 0000000..d664d48
--- /dev/null
+++ b/tests/010-instance/src/X.java
@@ -0,0 +1,8 @@
+class X {
+    public X() {
+    }
+
+    int foo() {
+        return 0;
+    }
+}
diff --git a/tests/010-instance/src/Y.java b/tests/010-instance/src/Y.java
new file mode 100644
index 0000000..2b2c371
--- /dev/null
+++ b/tests/010-instance/src/Y.java
@@ -0,0 +1,8 @@
+class Y extends X {
+    public Y() {
+    }
+
+    int bar() {
+        return 1;
+    }
+}
diff --git a/tests/011-array-copy/expected.txt b/tests/011-array-copy/expected.txt
new file mode 100644
index 0000000..724786e
--- /dev/null
+++ b/tests/011-array-copy/expected.txt
@@ -0,0 +1,15 @@
+string -> object
+object -> string
+object -> string (modified)
+caught ArrayStoreException (expected)
+copy: 0,0,0: [0, 1, 2, 3, 4, 5, 6, 7]
+copy: 0,0,8: [0, 1, 2, 3, 4, 5, 6, 7]
+copy: 0,2,4: [0, 1, 0, 1, 2, 3, 6, 7]
+copy: 2,0,4: [2, 3, 4, 5, 4, 5, 6, 7]
+copy: 1,3,4: [0, 1, 2, 1, 2, 3, 4, 7]
+copy: 3,1,4: [0, 3, 4, 5, 6, 5, 6, 7]
+copy: 3,1,5: [0, 3, 4, 5, 6, 7, 6, 7]
+copy: 1,3,5: [0, 1, 2, 1, 2, 3, 4, 5]
+copy: 0,3,5: [0, 1, 2, 0, 1, 2, 3, 4]
+copy: 3,0,5: [3, 4, 5, 6, 7, 5, 6, 7]
+copy: 0,5,1: [0, 1, 2, 3, 4, 0, 6, 7]
diff --git a/tests/011-array-copy/info.txt b/tests/011-array-copy/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/011-array-copy/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/011-array-copy/src/Iface1.java b/tests/011-array-copy/src/Iface1.java
new file mode 100644
index 0000000..ba17d45
--- /dev/null
+++ b/tests/011-array-copy/src/Iface1.java
@@ -0,0 +1,13 @@
+// Copyright 2005 The Android Open Source Project
+
+/**
+ * Test stuff.
+ */
+public interface Iface1 {
+
+    public int iFunc1(int ii);
+
+    public float mFloaty = 5.0f;
+
+    public String mWahoo = new String("wahoo");
+}
diff --git a/tests/011-array-copy/src/Iface2.java b/tests/011-array-copy/src/Iface2.java
new file mode 100644
index 0000000..83fe650
--- /dev/null
+++ b/tests/011-array-copy/src/Iface2.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2 {
+
+    public int iFunc2(int ii);
+}
diff --git a/tests/011-array-copy/src/ImplA.java b/tests/011-array-copy/src/ImplA.java
new file mode 100644
index 0000000..9007001
--- /dev/null
+++ b/tests/011-array-copy/src/ImplA.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplA implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+1;
+    }
+    public int iFunc2(int ii) {
+        return ii+2;
+    }
+}
diff --git a/tests/011-array-copy/src/Main.java b/tests/011-array-copy/src/Main.java
new file mode 100644
index 0000000..505d8b0
--- /dev/null
+++ b/tests/011-array-copy/src/Main.java
@@ -0,0 +1,146 @@
+/*
+ * 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.util.Arrays;
+
+/**
+ * System.arraycopy cases
+ */
+public class Main {
+    public static void main(String args[]) {
+        testObjectCopy();
+        testOverlappingMoves();
+    }
+
+    public static void testObjectCopy() {
+        String[] stringArray = new String[8];
+        Object[] objectArray = new Object[8];
+
+        for (int i = 0; i < stringArray.length; i++)
+            stringArray[i] = new String(Integer.toString(i));
+
+        System.out.println("string -> object");
+        System.arraycopy(stringArray, 0, objectArray, 0, stringArray.length);
+        System.out.println("object -> string");
+        System.arraycopy(objectArray, 0, stringArray, 0, stringArray.length);
+        System.out.println("object -> string (modified)");
+        objectArray[4] = new ImplA();
+        try {
+            System.arraycopy(objectArray, 0, stringArray, 0,stringArray.length);
+        }
+        catch (ArrayStoreException ase) {
+            System.out.println("caught ArrayStoreException (expected)");
+        }
+    }
+
+    static final int ARRAY_SIZE = 8;
+
+    static void initByteArray(byte[] array) {
+        for (int i = 0; i < ARRAY_SIZE; i++) {
+            array[i] = (byte) i;
+        }
+    }
+    static void initShortArray(short[] array) {
+        for (int i = 0; i < ARRAY_SIZE; i++) {
+            array[i] = (short) i;
+        }
+    }
+    static void initIntArray(int[] array) {
+        for (int i = 0; i < ARRAY_SIZE; i++) {
+            array[i] = (int) i;
+        }
+    }
+    static void initLongArray(long[] array) {
+        for (int i = 0; i < ARRAY_SIZE; i++) {
+            array[i] = (long) i;
+        }
+    }
+
+    /*
+     * Perform an array copy operation on primitive arrays with different
+     * element widths.
+     */
+    static void makeCopies(int srcPos, int dstPos, int length) {
+        byte[] byteArray = new byte[ARRAY_SIZE];
+        short[] shortArray = new short[ARRAY_SIZE];
+        int[] intArray = new int[ARRAY_SIZE];
+        long[] longArray = new long[ARRAY_SIZE];
+
+        initByteArray(byteArray);
+        initShortArray(shortArray);
+        initIntArray(intArray);
+        initLongArray(longArray);
+
+        System.arraycopy(byteArray, srcPos, byteArray, dstPos, length);
+        System.arraycopy(shortArray, srcPos, shortArray, dstPos, length);
+        System.arraycopy(intArray, srcPos, intArray, dstPos, length);
+        System.arraycopy(longArray, srcPos, longArray, dstPos, length);
+
+        for (int i = 0; i < ARRAY_SIZE; i++) {
+            if (intArray[i] != byteArray[i]) {
+                System.out.println("mismatch int vs byte at " + i + " : " +
+                    Arrays.toString(byteArray));
+                break;
+            } else if (intArray[i] != shortArray[i]) {
+                System.out.println("mismatch int vs short at " + i + " : " +
+                    Arrays.toString(shortArray));
+                break;
+            } else if (intArray[i] != longArray[i]) {
+                System.out.println("mismatch int vs long at " + i + " : " +
+                    Arrays.toString(longArray));
+                break;
+            }
+        }
+
+        System.out.println("copy: " + srcPos + "," + dstPos + "," + length +
+            ": " + Arrays.toString(intArray));
+    }
+
+    public static void testOverlappingMoves() {
+        /* do nothing */
+        makeCopies(0, 0, 0);
+
+        /* do more nothing */
+        makeCopies(0, 0, ARRAY_SIZE);
+
+        /* copy forward, even alignment */
+        makeCopies(0, 2, 4);
+
+        /* copy backward, even alignment */
+        makeCopies(2, 0, 4);
+
+        /* copy forward, odd alignment */
+        makeCopies(1, 3, 4);
+
+        /* copy backward, odd alignment */
+        makeCopies(3, 1, 4);
+
+        /* copy backward, odd length */
+        makeCopies(3, 1, 5);
+
+        /* copy forward, odd length */
+        makeCopies(1, 3, 5);
+
+        /* copy forward, mixed alignment */
+        makeCopies(0, 3, 5);
+
+        /* copy backward, mixed alignment */
+        makeCopies(3, 0, 5);
+
+        /* copy forward, mixed alignment, trivial length */
+        makeCopies(0, 5, 1);
+    }
+}
diff --git a/tests/012-math/expected.txt b/tests/012-math/expected.txt
new file mode 100644
index 0000000..af9708e
--- /dev/null
+++ b/tests/012-math/expected.txt
@@ -0,0 +1,32 @@
+res:10
+res:-4
+res:2
+res:-2
+res:21
+res:0
+res:3
+res:4
+res:384
+res:0
+res:0
+a:10
+a:3
+a:2
+a:-3
+a:-21
+a:-3
+a:-3
+a:-6
+a:-768
+a:-6
+a:33554431
+fres:10.0
+fres:-4.0
+fres:21.0
+fres:0.42857142857142855
+fres:3.0
+f:10.0
+f:3.0
+f:21.0
+f:3.0
+f:3.0
diff --git a/tests/012-math/info.txt b/tests/012-math/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/012-math/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/012-math/src/Main.java b/tests/012-math/src/Main.java
new file mode 100644
index 0000000..87ea40b
--- /dev/null
+++ b/tests/012-math/src/Main.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/**
+ * test simple math opers
+ */
+public class Main {
+    public static void main(String args[]) {
+        int pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
+        int pad8, pad9, pad10, pad11, pad12, pad13, pad14, pad15;
+        int a, b, res;
+        //long a, b, res;
+
+        a = 3;
+        b = 7;
+
+        res = a + b;
+        System.out.println("res:" +res);
+        res = a - b;
+        System.out.println("res:" +res);
+        res = 5 - a;
+        System.out.println("res:" +res);
+        res = a - 5;
+        System.out.println("res:" +res);
+        res = a * b;
+        System.out.println("res:" +res);
+        res = a / b;
+        System.out.println("res:" +res);
+        res = a % b;
+        System.out.println("res:" +res);
+        res = a ^ b;
+        System.out.println("res:" +res);
+        res = a << b;
+        System.out.println("res:" +res);
+        res = a >> b;
+        System.out.println("res:" +res);
+        res = a >>> b;
+        System.out.println("res:" +res);
+
+        a += b;
+        System.out.println("a:" +a);
+        a -= b;
+        System.out.println("a:" +a);
+        a = 5 - a;
+        System.out.println("a:" +a);
+        a -= 5;
+        System.out.println("a:" +a);
+        a *= b;
+        System.out.println("a:" +a);
+        a /= b;
+        System.out.println("a:" +a);
+        a %= b;
+        System.out.println("a:" +a);
+        a ^= b;
+        System.out.println("a:" +a);
+        a <<= b;
+        System.out.println("a:" +a);
+        a >>= b;
+        System.out.println("a:" +a);
+        a >>>= b;
+        System.out.println("a:" +a);
+
+        double f, g, fres;
+
+        f = 3.0f;
+        g = 7.0f;
+
+        fres = f + g;
+        System.out.println("fres:" +fres);
+        fres = f - g;
+        System.out.println("fres:" +fres);
+        fres = f * g;
+        System.out.println("fres:" +fres);
+        fres = f / g;
+        System.out.println("fres:" +fres);
+        fres = f % g;
+        System.out.println("fres:" +fres);
+        f += g;
+        System.out.println("f:" +f);
+        f -= g;
+        System.out.println("f:" +f);
+        f *= g;
+        System.out.println("f:" +f);
+        f /= g;
+        System.out.println("f:" +f);
+        f %= g;
+        System.out.println("f:" +f);
+    }
+}
diff --git a/tests/013-math2/expected.txt b/tests/013-math2/expected.txt
new file mode 100644
index 0000000..d36c468
--- /dev/null
+++ b/tests/013-math2/expected.txt
@@ -0,0 +1 @@
+a:32003
diff --git a/tests/013-math2/info.txt b/tests/013-math2/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/013-math2/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/013-math2/src/Main.java b/tests/013-math2/src/Main.java
new file mode 100644
index 0000000..819571d
--- /dev/null
+++ b/tests/013-math2/src/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * test add by a 16-bit constant
+ */
+public class Main {
+    public static void main(String args[]) {
+        int a, b, res;
+
+        a = 3;
+        b = 7;
+
+        // a 16-bit constant
+        a += 32000;
+        System.out.println("a:" +a);
+    }
+}
diff --git a/tests/014-math3/expected.txt b/tests/014-math3/expected.txt
new file mode 100644
index 0000000..bda3dc7
--- /dev/null
+++ b/tests/014-math3/expected.txt
@@ -0,0 +1 @@
+testMath3 success
diff --git a/tests/014-math3/info.txt b/tests/014-math3/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/014-math3/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/014-math3/src/Main.java b/tests/014-math3/src/Main.java
new file mode 100644
index 0000000..f55b17a
--- /dev/null
+++ b/tests/014-math3/src/Main.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test math exceptions
+ */
+public class Main {
+    public static void main(String args[]) {
+        int expectedThrows = 2;
+        int i;
+        long j;
+        float f = 0.0f;
+        double d = 0.0;
+
+        try { i = 10 / 0; }
+        catch (ArithmeticException ae) {
+            expectedThrows--;
+        }
+
+        try { j = 10L / 0L; }
+        catch (ArithmeticException ae) {
+            expectedThrows--;
+        }
+
+        /*
+         * Floating point divide by zero doesn't throw an exception -- the
+         * result is just NaN.
+         */
+        try { f = 10.0f / f; }
+        catch (ArithmeticException ae) {
+            expectedThrows--;
+        }
+
+        try { d = 10.0 / d; }
+        catch (ArithmeticException ae) {
+            expectedThrows--;
+        }
+
+        if (expectedThrows != 0)
+            System.out.println("HEY: expected throws is " + expectedThrows);
+        else
+            System.out.println("testMath3 success");
+    }
+}
diff --git a/tests/015-switch/expected.txt b/tests/015-switch/expected.txt
new file mode 100644
index 0000000..ca3b518
--- /dev/null
+++ b/tests/015-switch/expected.txt
@@ -0,0 +1,10 @@
+CORRECT (one)
+CORRECT (not found)
+CORRECT (large)
+CORRECT (large2)
+CORRECT (large3)
+CORRECT (not found)
+CORRECT (not found)
+CORRECT (default only)
+CORRECT big sparse / first
+CORRECT big sparse / last
diff --git a/tests/015-switch/info.txt b/tests/015-switch/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/015-switch/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/015-switch/src/Main.java b/tests/015-switch/src/Main.java
new file mode 100644
index 0000000..7198e2b
--- /dev/null
+++ b/tests/015-switch/src/Main.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test switch() blocks
+ */
+public class Main {
+    public static void main(String args[]) {
+        int a = 1;
+
+        switch (a) {
+            case -1: System.out.print("neg one\n"); break;
+            case 0: System.out.print("zero\n"); break;
+            case 1: System.out.print("CORRECT (one)\n"); break;
+            case 2: System.out.print("two\n"); break;
+            case 3: System.out.print("three\n"); break;
+            case 4: System.out.print("four\n"); break;
+            default: System.out.print("???\n"); break;
+        }
+        switch (a) {
+            case 3: System.out.print("three\n"); break;
+            case 4: System.out.print("four\n"); break;
+            default: System.out.print("CORRECT (not found)\n"); break;
+        }
+
+        a = 0x12345678;
+
+        switch (a) {
+            case 0x12345678: System.out.print("CORRECT (large)\n"); break;
+            case 0x12345679: System.out.print("large+1\n"); break;
+            default: System.out.print("nuts\n"); break;
+        }
+        switch (a) {
+            case 0x12345678: System.out.print("CORRECT (large2)\n"); break;
+            case 0x12345700: System.out.print("large+many\n"); break;
+            default: System.out.print("nuts\n"); break;
+        }
+        switch (a) {
+            case 57: System.out.print("fifty-seven!\n"); break;
+            case -6: System.out.print("neg six!\n"); break;
+            case 0x12345678: System.out.print("CORRECT (large3)\n"); break;
+            case 22: System.out.print("twenty-two!\n"); break;
+            case 3: System.out.print("three!\n"); break;
+            default: System.out.print("huh?\n"); break;
+        }
+        switch (a) {
+            case -6: System.out.print("neg six!\n"); break;
+            case 3: System.out.print("three!\n"); break;
+            default: System.out.print("CORRECT (not found)\n"); break;
+        }
+
+        a = -5;
+        switch (a) {
+            case 12: System.out.print("twelve\n"); break;
+            case -5: System.out.print("CORRECT (not found)\n"); break;
+            case 0: System.out.print("zero\n"); break;
+            default: System.out.print("wah?\n"); break;
+        }
+
+        switch (a) {
+            default: System.out.print("CORRECT (default only)\n"); break;
+        }
+
+        a = -10;
+        switch (a) {
+            case -10: System.out.print("CORRECT big sparse / first\n"); break;
+            case -5: System.out.print("neg five\n"); break;
+            case 0: System.out.print("zero\n"); break;
+            case 5: System.out.print("five\n"); break;
+            case 10: System.out.print("ten\n"); break;
+            case 15: System.out.print("fifteen\n"); break;
+            case 20: System.out.print("twenty\n"); break;
+            case 50: System.out.print("fifty\n"); break;
+            case 100: System.out.print("hundred\n"); break;
+            default: System.out.print("blah!\n"); break;
+        }
+
+        a = 100;
+        switch (a) {
+            case -10: System.out.print("neg ten\n"); break;
+            case -5: System.out.print("neg five\n"); break;
+            case 0: System.out.print("zero\n"); break;
+            case 5: System.out.print("five\n"); break;
+            case 10: System.out.print("ten\n"); break;
+            case 15: System.out.print("fifteen\n"); break;
+            case 20: System.out.print("twenty\n"); break;
+            case 50: System.out.print("fifty\n"); break;
+            case 100: System.out.print("CORRECT big sparse / last\n"); break;
+            default: System.out.print("blah!\n"); break;
+        }
+    }
+}
diff --git a/tests/016-intern/expected.txt b/tests/016-intern/expected.txt
new file mode 100644
index 0000000..7d91963
--- /dev/null
+++ b/tests/016-intern/expected.txt
@@ -0,0 +1 @@
+good! foobar
diff --git a/tests/016-intern/info.txt b/tests/016-intern/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/016-intern/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/016-intern/src/Main.java b/tests/016-intern/src/Main.java
new file mode 100644
index 0000000..4306863
--- /dev/null
+++ b/tests/016-intern/src/Main.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/**
+ * Interned strings
+ */
+public class Main {
+    public static void main(String args[]) {
+        String a, b;
+        String foo = "foo";
+        String bar = "bar";
+
+        a = foo.concat(bar).intern();
+        b = foo.concat(bar).intern();
+        if (a == b && foo != bar) {
+            System.out.println("good! " + a);
+        } else {
+            System.out.println("bad!");
+        }
+    }
+}
diff --git a/tests/017-float/expected.txt b/tests/017-float/expected.txt
new file mode 100644
index 0000000..2062f9e
--- /dev/null
+++ b/tests/017-float/expected.txt
@@ -0,0 +1,3 @@
+base values: d=3.1415926535 f=3.1415927
+base values: d=3.1415926535 f=3.1415927
+base values: f=3.1415927 d=3.1415926535
diff --git a/tests/017-float/info.txt b/tests/017-float/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/017-float/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/017-float/src/Main.java b/tests/017-float/src/Main.java
new file mode 100644
index 0000000..a5dbe1e
--- /dev/null
+++ b/tests/017-float/src/Main.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * I dont know what this test does.
+ */
+public class Main {
+    public static void main(String args[]) {
+        float f = 3.1415926535f;
+        double d = 3.1415926535;
+        //float fd = (float) d;
+        //Float off = new Float(f);
+        //Float ofd = new Float(d);
+        System.out.println("base values: d=" + d + " f=" + f);
+        System.out.println("base values: d=" + d + " f=" + f);
+        System.out.println("base values: f=" + f + " d=" + d);
+        //System.out.println("object values: off="
+        //    + off.floatValue() + " ofd=" + ofd.floatValue());
+    }
+}
diff --git a/tests/018-stack-overflow/expected.txt b/tests/018-stack-overflow/expected.txt
new file mode 100644
index 0000000..7797816
--- /dev/null
+++ b/tests/018-stack-overflow/expected.txt
@@ -0,0 +1,2 @@
+caught SOE
+SOE test done
diff --git a/tests/018-stack-overflow/info.txt b/tests/018-stack-overflow/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/018-stack-overflow/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/018-stack-overflow/src/Main.java b/tests/018-stack-overflow/src/Main.java
new file mode 100644
index 0000000..f79c269
--- /dev/null
+++ b/tests/018-stack-overflow/src/Main.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/**
+ * generate a stack overflow condition and catch it
+ */
+public class Main {
+    public static void main(String args[]) {
+        try {
+            stackOverflowTestSub(0.0, 0.0, 0.0);
+        }
+        catch (StackOverflowError soe) {
+            System.out.println("caught SOE");
+        }
+        System.out.println("SOE test done");
+    }
+
+    private static void stackOverflowTestSub(double pad1, double pad2,
+            double pad3) {
+        stackOverflowTestSub(pad1, pad2, pad3);
+    }
+}
diff --git a/tests/019-wrong-array-type/expected.txt b/tests/019-wrong-array-type/expected.txt
new file mode 100644
index 0000000..c0ed716
--- /dev/null
+++ b/tests/019-wrong-array-type/expected.txt
@@ -0,0 +1 @@
+Got correct array store exception
diff --git a/tests/019-wrong-array-type/info.txt b/tests/019-wrong-array-type/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/019-wrong-array-type/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/019-wrong-array-type/src/Main.java b/tests/019-wrong-array-type/src/Main.java
new file mode 100644
index 0000000..c424ae9
--- /dev/null
+++ b/tests/019-wrong-array-type/src/Main.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * Stuff the wrong type object into an array.
+ */
+public class Main {
+    public static void main(String args[]) {
+        String[] strArray = new String[1];
+
+        Object[] objArray = strArray;
+
+        try {
+            objArray[0] = new Integer(1);
+            System.out.println("Array store succeeded?!");
+        } catch (ArrayStoreException ase) {
+            System.out.println("Got correct array store exception");
+        }
+    }
+}
diff --git a/tests/020-string/expected.txt b/tests/020-string/expected.txt
new file mode 100644
index 0000000..081fea3
--- /dev/null
+++ b/tests/020-string/expected.txt
@@ -0,0 +1,7 @@
+testStr is 'This is a very nice string'
+This is a very nice string
+Compare result is 32
+Compare unicode: -65302
+Got expected exception
+subStr is 'uick brown fox jumps over the lazy '
+Indexes are: 0:-1:0:43:33:-1:18:13:13:-1:18:18:-1:13:-1:-1:-1
diff --git a/tests/020-string/info.txt b/tests/020-string/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/020-string/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/020-string/src/Main.java b/tests/020-string/src/Main.java
new file mode 100644
index 0000000..bb8ce1f
--- /dev/null
+++ b/tests/020-string/src/Main.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+/**
+ * Simple string test.
+ */
+public class Main {
+    public static void main(String args[]) {
+        basicTest();
+        indexTest();
+    }
+
+    public static void basicTest() {
+        String baseStr = "*** This is a very nice string!!!";
+        String testStr;
+        int i;
+
+        testStr = baseStr.substring(4, baseStr.length() - 3);
+        System.out.println("testStr is '" + testStr + "'");
+
+        /* sloppy for loop */
+        for (i = 0; i < testStr.length(); i++)
+            System.out.print(testStr.charAt(i));
+        System.out.print("\n");
+
+        String testStr2 = "This is a very nice strinG";
+        if (testStr.length() != testStr2.length())
+            System.out.println("WARNING: stringTest length mismatch");
+
+        System.out.println("Compare result is " + testStr.compareTo(testStr2));
+
+        // expected: -65302
+        String s1 = "\u0c6d\u0cb6\u0d00\u0000\u0080\u0080\u0080\u0000\u0002\u0002\u0002\u0000\u00e9\u00e9\u00e9";
+        String s2 = "\u0c6d\u0cb6\u0d00\u0000\u0080\u0080\u0080\u0000\u0002\u0002\u0002\u0000\uffff\uffff\uffff\u00e9\u00e9\u00e9";
+        System.out.println("Compare unicode: " + s1.compareTo(s2));
+
+        try {
+            testStr.charAt(500);
+            System.out.println("GLITCH: expected exception");
+        } catch (StringIndexOutOfBoundsException sioobe) {
+            System.out.println("Got expected exception");
+        }
+    }
+
+    public static void indexTest() {
+        String baseStr = "The quick brown fox jumps over the lazy dog!";
+        String subStr;
+
+        subStr = baseStr.substring(5, baseStr.length() - 4);
+        System.out.println("subStr is '" + subStr + "'");
+
+        System.out.println("Indexes are: " +
+            baseStr.indexOf('T') + ":" +
+            subStr.indexOf('T') + ":" +
+            subStr.indexOf('u') + ":" +
+            baseStr.indexOf('!') + ":" +
+            subStr.indexOf('y') + ":" +
+            subStr.indexOf('d') + ":" +
+            baseStr.indexOf('x') + ":" +
+            subStr.indexOf('x', 0) + ":" +
+            subStr.indexOf('x', -1) + ":" +
+            subStr.indexOf('x', 200) + ":" +
+            baseStr.indexOf('x', 17) + ":" +
+            baseStr.indexOf('x', 18) + ":" +
+            baseStr.indexOf('x', 19) + ":" +
+            subStr.indexOf('x', 13) + ":" +
+            subStr.indexOf('x', 14) + ":" +
+            subStr.indexOf('&') + ":" +
+            baseStr.indexOf(0x12341234));
+    }
+}
diff --git a/tests/021-string2/expected.txt b/tests/021-string2/expected.txt
new file mode 100644
index 0000000..bd7f049
--- /dev/null
+++ b/tests/021-string2/expected.txt
@@ -0,0 +1 @@
+Got expected npe
diff --git a/tests/021-string2/info.txt b/tests/021-string2/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/021-string2/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/021-string2/src/Main.java b/tests/021-string2/src/Main.java
new file mode 100644
index 0000000..87e4baf
--- /dev/null
+++ b/tests/021-string2/src/Main.java
@@ -0,0 +1,83 @@
+/*
+ * 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 junit.framework.Assert;
+
+/**
+ * more string tests
+ */
+public class Main {
+    public static void main(String args[]) {
+        String test = "0123456789";
+        String test1 = new String("0123456789");    // different object
+        String test2 = new String("0123456780");    // different value
+        String offset = new String("xxx0123456789yyy");
+        String sub = offset.substring(3, 13);
+        Object blah = new Object();
+
+        Assert.assertTrue(test.equals(test));
+        Assert.assertTrue(test.equals(test1));
+        Assert.assertFalse(test.equals(test2));
+
+        Assert.assertEquals(test.compareTo(test1), 0);
+        Assert.assertTrue(test1.compareTo(test2) > 0);
+        Assert.assertTrue(test2.compareTo(test1) < 0);
+
+        /* compare string with a nonzero offset, in left/right side */
+        Assert.assertEquals(test.compareTo(sub), 0);
+        Assert.assertEquals(sub.compareTo(test), 0);
+        Assert.assertTrue(test.equals(sub));
+        Assert.assertTrue(sub.equals(test));
+        /* same base, one is a substring */
+        Assert.assertFalse(offset.equals(sub));
+        Assert.assertFalse(sub.equals(offset));
+        /* wrong class */
+        Assert.assertFalse(test.equals(blah));
+
+        /* null ptr - throw */
+        try {
+            test.compareTo(null);
+            Assert.fail("didn't get expected npe");
+        } catch (NullPointerException npe) {
+            System.out.println("Got expected npe");
+        }
+        /* null ptr - ok */
+        Assert.assertFalse(test.equals(null));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("123456789"));
+        Assert.assertFalse(test.equals(test1));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("23456789"));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("3456789"));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("456789"));
+
+        test = test.substring(3,5);
+        Assert.assertTrue(test.equals("78"));
+
+        test = "this/is/a/path";
+        String[] strings = test.split("/");
+        Assert.assertEquals(4, strings.length);
+
+        Assert.assertEquals("this is a path", test.replaceAll("/", " "));
+        Assert.assertEquals("this is a path", test.replace("/", " "));
+    }
+}
diff --git a/tests/021-string2/src/junit/framework/Assert.java b/tests/021-string2/src/junit/framework/Assert.java
new file mode 100644
index 0000000..364e646
--- /dev/null
+++ b/tests/021-string2/src/junit/framework/Assert.java
@@ -0,0 +1,291 @@
+package junit.framework;
+
+/**
+ * A set of assert methods.  Messages are only displayed when an assert fails.
+ */
+
+public class Assert {
+    /**
+     * Protect constructor since it is a static only class
+     */
+    protected Assert() {
+    }
+
+    /**
+     * Asserts that a condition is true. If it isn't it throws
+     * an AssertionFailedError with the given message.
+     */
+    static public void assertTrue(String message, boolean condition) {
+        if (!condition)
+            fail(message);
+    }
+    /**
+     * Asserts that a condition is true. If it isn't it throws
+     * an AssertionFailedError.
+     */
+    static public void assertTrue(boolean condition) {
+        assertTrue(null, condition);
+    }
+    /**
+     * Asserts that a condition is false. If it isn't it throws
+     * an AssertionFailedError with the given message.
+     */
+    static public void assertFalse(String message, boolean condition) {
+        assertTrue(message, !condition);
+    }
+    /**
+     * Asserts that a condition is false. If it isn't it throws
+     * an AssertionFailedError.
+     */
+    static public void assertFalse(boolean condition) {
+        assertFalse(null, condition);
+    }
+    /**
+     * Fails a test with the given message.
+     */
+    static public void fail(String message) {
+        throw new AssertionFailedError(message);
+    }
+    /**
+     * Fails a test with no message.
+     */
+    static public void fail() {
+        fail(null);
+    }
+    /**
+     * Asserts that two objects are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, Object expected, Object actual) {
+        if (expected == null && actual == null)
+            return;
+        if (expected != null && expected.equals(actual))
+            return;
+        failNotEquals(message, expected, actual);
+    }
+    /**
+     * Asserts that two objects are equal. If they are not
+     * an AssertionFailedError is thrown.
+     */
+    static public void assertEquals(Object expected, Object actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two Strings are equal.
+     */
+    static public void assertEquals(String message, String expected, String actual) {
+        if (expected == null && actual == null)
+            return;
+        if (expected != null && expected.equals(actual))
+            return;
+        throw new ComparisonFailure(message, expected, actual);
+    }
+    /**
+     * Asserts that two Strings are equal.
+     */
+    static public void assertEquals(String expected, String actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two doubles are equal concerning a delta.  If they are not
+     * an AssertionFailedError is thrown with the given message.  If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(String message, double expected, double actual, double delta) {
+        // handle infinity specially since subtracting to infinite values gives NaN and the
+        // the following test fails
+        if (Double.isInfinite(expected)) {
+            if (!(expected == actual))
+                failNotEquals(message, new Double(expected), new Double(actual));
+        } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false
+            failNotEquals(message, new Double(expected), new Double(actual));
+    }
+    /**
+     * Asserts that two doubles are equal concerning a delta. If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(double expected, double actual, double delta) {
+        assertEquals(null, expected, actual, delta);
+    }
+    /**
+     * Asserts that two floats are equal concerning a delta. If they are not
+     * an AssertionFailedError is thrown with the given message.  If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(String message, float expected, float actual, float delta) {
+         // handle infinity specially since subtracting to infinite values gives NaN and the
+        // the following test fails
+        if (Float.isInfinite(expected)) {
+            if (!(expected == actual))
+                failNotEquals(message, new Float(expected), new Float(actual));
+        } else if (!(Math.abs(expected-actual) <= delta))
+              failNotEquals(message, new Float(expected), new Float(actual));
+    }
+    /**
+     * Asserts that two floats are equal concerning a delta. If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(float expected, float actual, float delta) {
+        assertEquals(null, expected, actual, delta);
+    }
+    /**
+     * Asserts that two longs are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, long expected, long actual) {
+        assertEquals(message, new Long(expected), new Long(actual));
+    }
+    /**
+     * Asserts that two longs are equal.
+     */
+    static public void assertEquals(long expected, long actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two booleans are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, boolean expected, boolean actual) {
+            assertEquals(message, new Boolean(expected), new Boolean(actual));
+      }
+    /**
+     * Asserts that two booleans are equal.
+      */
+    static public void assertEquals(boolean expected, boolean actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two bytes are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+      static public void assertEquals(String message, byte expected, byte actual) {
+        assertEquals(message, new Byte(expected), new Byte(actual));
+    }
+    /**
+        * Asserts that two bytes are equal.
+     */
+    static public void assertEquals(byte expected, byte actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two chars are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+      static public void assertEquals(String message, char expected, char actual) {
+            assertEquals(message, new Character(expected), new Character(actual));
+      }
+    /**
+     * Asserts that two chars are equal.
+     */
+      static public void assertEquals(char expected, char actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two shorts are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, short expected, short actual) {
+            assertEquals(message, new Short(expected), new Short(actual));
+    }
+      /**
+     * Asserts that two shorts are equal.
+     */
+    static public void assertEquals(short expected, short actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two ints are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+      static public void assertEquals(String message, int expected, int actual) {
+        assertEquals(message, new Integer(expected), new Integer(actual));
+      }
+      /**
+        * Asserts that two ints are equal.
+     */
+      static public void assertEquals(int expected, int actual) {
+          assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that an object isn't null.
+     */
+    static public void assertNotNull(Object object) {
+        assertNotNull(null, object);
+    }
+    /**
+     * Asserts that an object isn't null. If it is
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertNotNull(String message, Object object) {
+        assertTrue(message, object != null);
+    }
+    /**
+     * Asserts that an object is null.
+     */
+    static public void assertNull(Object object) {
+        assertNull(null, object);
+    }
+    /**
+     * Asserts that an object is null.  If it is not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertNull(String message, Object object) {
+        assertTrue(message, object == null);
+    }
+    /**
+     * Asserts that two objects refer to the same object. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertSame(String message, Object expected, Object actual) {
+        if (expected == actual)
+            return;
+        failNotSame(message, expected, actual);
+    }
+    /**
+     * Asserts that two objects refer to the same object. If they are not
+     * the same an AssertionFailedError is thrown.
+     */
+    static public void assertSame(Object expected, Object actual) {
+        assertSame(null, expected, actual);
+    }
+     /**
+      * Asserts that two objects refer to the same object. If they are not
+      * an AssertionFailedError is thrown with the given message.
+      */
+    static public void assertNotSame(String message, Object expected, Object actual) {
+        if (expected == actual)
+            failSame(message);
+    }
+    /**
+     * Asserts that two objects refer to the same object. If they are not
+     * the same an AssertionFailedError is thrown.
+     */
+    static public void assertNotSame(Object expected, Object actual) {
+        assertNotSame(null, expected, actual);
+    }
+
+    static private void failSame(String message) {
+        String formatted= "";
+         if (message != null)
+             formatted= message+" ";
+         fail(formatted+"expected not same");
+    }
+
+    static private void failNotSame(String message, Object expected, Object actual) {
+        String formatted= "";
+        if (message != null)
+            formatted= message+" ";
+        fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
+    }
+
+    static private void failNotEquals(String message, Object expected, Object actual) {
+        fail(format(message, expected, actual));
+    }
+
+    static String format(String message, Object expected, Object actual) {
+        String formatted= "";
+        if (message != null)
+            formatted= message+" ";
+        return formatted+"expected:<"+expected+"> but was:<"+actual+">";
+    }
+}
diff --git a/tests/021-string2/src/junit/framework/AssertionFailedError.java b/tests/021-string2/src/junit/framework/AssertionFailedError.java
new file mode 100644
index 0000000..e9cb3a3
--- /dev/null
+++ b/tests/021-string2/src/junit/framework/AssertionFailedError.java
@@ -0,0 +1,13 @@
+package junit.framework;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends Error {
+
+    public AssertionFailedError () {
+    }
+    public AssertionFailedError (String message) {
+        super (message);
+    }
+}
diff --git a/tests/021-string2/src/junit/framework/ComparisonFailure.java b/tests/021-string2/src/junit/framework/ComparisonFailure.java
new file mode 100644
index 0000000..0cb2cee
--- /dev/null
+++ b/tests/021-string2/src/junit/framework/ComparisonFailure.java
@@ -0,0 +1,68 @@
+package junit.framework;
+
+/**
+ * Thrown when an assert equals for Strings failed.
+ *
+ * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
+ */
+public class ComparisonFailure extends AssertionFailedError {
+    private String fExpected;
+    private String fActual;
+
+    /**
+     * Constructs a comparison failure.
+     * @param message the identifying message or null
+     * @param expected the expected string value
+     * @param actual the actual string value
+     */
+    public ComparisonFailure (String message, String expected, String actual) {
+        super (message);
+        fExpected= expected;
+        fActual= actual;
+    }
+
+    /**
+     * Returns "..." in place of common prefix and "..." in
+     * place of common suffix between expected and actual.
+     *
+     * @see java.lang.Throwable#getMessage()
+     */
+    public String getMessage() {
+        if (fExpected == null || fActual == null)
+            return Assert.format(super.getMessage(), fExpected, fActual);
+
+        int end= Math.min(fExpected.length(), fActual.length());
+
+        int i= 0;
+        for(; i < end; i++) {
+            if (fExpected.charAt(i) != fActual.charAt(i))
+                break;
+        }
+        int j= fExpected.length()-1;
+        int k= fActual.length()-1;
+        for (; k >= i && j >= i; k--,j--) {
+            if (fExpected.charAt(j) != fActual.charAt(k))
+                break;
+        }
+        String actual, expected;
+
+        // equal strings
+        if (j < i && k < i) {
+            expected= fExpected;
+            actual= fActual;
+        } else {
+            expected= fExpected.substring(i, j+1);
+            actual= fActual.substring(i, k+1);
+            if (i <= end && i > 0) {
+                expected= "..."+expected;
+                actual= "..."+actual;
+            }
+
+            if (j < fExpected.length()-1)
+                expected= expected+"...";
+            if (k < fActual.length()-1)
+                actual= actual+"...";
+        }
+        return Assert.format(super.getMessage(), expected, actual);
+    }
+}
diff --git a/tests/022-interface/expected.txt b/tests/022-interface/expected.txt
new file mode 100644
index 0000000..1212663
--- /dev/null
+++ b/tests/022-interface/expected.txt
@@ -0,0 +1,2 @@
+ImplBSub intf: 205
+ImplA: 7
diff --git a/tests/022-interface/info.txt b/tests/022-interface/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/022-interface/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/022-interface/src/Iface1.java b/tests/022-interface/src/Iface1.java
new file mode 100644
index 0000000..ba17d45
--- /dev/null
+++ b/tests/022-interface/src/Iface1.java
@@ -0,0 +1,13 @@
+// Copyright 2005 The Android Open Source Project
+
+/**
+ * Test stuff.
+ */
+public interface Iface1 {
+
+    public int iFunc1(int ii);
+
+    public float mFloaty = 5.0f;
+
+    public String mWahoo = new String("wahoo");
+}
diff --git a/tests/022-interface/src/Iface2.java b/tests/022-interface/src/Iface2.java
new file mode 100644
index 0000000..83fe650
--- /dev/null
+++ b/tests/022-interface/src/Iface2.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2 {
+
+    public int iFunc2(int ii);
+}
diff --git a/tests/022-interface/src/Iface2Sub1.java b/tests/022-interface/src/Iface2Sub1.java
new file mode 100644
index 0000000..db3e905
--- /dev/null
+++ b/tests/022-interface/src/Iface2Sub1.java
@@ -0,0 +1,9 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Another interface.
+ */
+public interface Iface2Sub1 extends Iface2, Cloneable {
+
+    //public int iFunc2(int ii);
+}
diff --git a/tests/022-interface/src/ImplA.java b/tests/022-interface/src/ImplA.java
new file mode 100644
index 0000000..9007001
--- /dev/null
+++ b/tests/022-interface/src/ImplA.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplA implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+1;
+    }
+    public int iFunc2(int ii) {
+        return ii+2;
+    }
+}
diff --git a/tests/022-interface/src/ImplB.java b/tests/022-interface/src/ImplB.java
new file mode 100644
index 0000000..619fa00
--- /dev/null
+++ b/tests/022-interface/src/ImplB.java
@@ -0,0 +1,16 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Blah.
+ */
+public class ImplB implements Iface1, Iface2 {
+
+    public int iFunc1(int ii) {
+        return ii+10;
+    }
+    public int iFunc2(int ii) {
+        return ii+20;
+    }
+
+    public static String mWhoami = new String("ImplB!");
+}
diff --git a/tests/022-interface/src/ImplBSub.java b/tests/022-interface/src/ImplBSub.java
new file mode 100644
index 0000000..f3a7714
--- /dev/null
+++ b/tests/022-interface/src/ImplBSub.java
@@ -0,0 +1,14 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Interface test.
+ */
+public class ImplBSub extends ImplB implements /*Iface2,*/ Iface2Sub1 {
+
+    public int iFunc1(int ii) {
+        return ii+100;
+    }
+    public int iFunc2(int ii) {
+        return ii+200;
+    }
+}
diff --git a/tests/022-interface/src/Main.java b/tests/022-interface/src/Main.java
new file mode 100644
index 0000000..9151e89
--- /dev/null
+++ b/tests/022-interface/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/**
+ * test calling through an interface
+ */
+public class Main {
+    public static void main(String args[]) {
+        int result = 0;
+        Iface2Sub1 faceObj;
+        ImplA faceObj2;
+
+        faceObj = new ImplBSub();
+
+        result = faceObj.iFunc2(5);
+        System.out.print("ImplBSub intf: ");
+        System.out.println(result);
+
+        faceObj2 = new ImplA();
+        result = faceObj2.iFunc2(5);
+        System.out.print("ImplA: ");
+        System.out.println(result);
+    }
+}
diff --git a/tests/023-many-interfaces/build b/tests/023-many-interfaces/build
new file mode 100644
index 0000000..fc81d62
--- /dev/null
+++ b/tests/023-many-interfaces/build
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# 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.
+
+# Stop if something fails.
+set -e
+
+# Write out a bunch of interface source files.
+gcc -o iface-gen iface-gen.c
+./iface-gen
+
+mkdir classes
+${JAVAC} -d classes src/*.java
+
+dx --debug --dex --dump-to=classes.lst --output=classes.dex classes
+zip test.jar classes.dex
diff --git a/tests/023-many-interfaces/expected.txt b/tests/023-many-interfaces/expected.txt
new file mode 100644
index 0000000..c6a0c61
--- /dev/null
+++ b/tests/023-many-interfaces/expected.txt
@@ -0,0 +1,9 @@
+testIface001: done
+testIface049: done
+testIface099: done
+testVirt001: done
+testVirt049: done
+testVirt099: done
+testInst001: done
+testInst049: done
+testInst099: done
diff --git a/tests/023-many-interfaces/iface-gen.c b/tests/023-many-interfaces/iface-gen.c
new file mode 100644
index 0000000..1e3284a
--- /dev/null
+++ b/tests/023-many-interfaces/iface-gen.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Generate a big pile of interface classes.
+ */
+#include <stdio.h>
+
+/*
+ * Create N interface files.
+ */
+static int createFiles(int count)
+{
+    FILE* fp;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        char nameBuf[32];
+
+        sprintf(nameBuf, "src/Interface%03d.java", i);
+        fp = fopen(nameBuf, "w");
+        if (fp == NULL) {
+            fprintf(stderr, "ERROR: unable to open %s\n", nameBuf);
+            return -1;
+        }
+
+        fprintf(fp, "interface Interface%03d {\n", i);
+        if ((i & 0x01) != 0)
+            fprintf(fp, "    int func%03d();\n", i);
+        fprintf(fp, "}\n");
+        fclose(fp);
+    }
+
+    fp = fopen("func-decl", "w");
+    fprintf(fp, "    implements\n");
+    for (i = 0; i < count; i++) {
+        fprintf(fp, "        Interface%03d%s\n", i, (i == count-1) ? "" : ",");
+    }
+    fprintf(fp, "\n");
+    for (i = 1; i < count; i += 2) {
+        fprintf(fp, "    public int func%03d() { return %d; }\n", i, i);
+    }
+    fclose(fp);
+
+    return 0;
+}
+
+int main()
+{
+    int result;
+
+    result = createFiles(100);
+
+    return (result != 0);
+}
diff --git a/tests/023-many-interfaces/info.txt b/tests/023-many-interfaces/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/023-many-interfaces/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/023-many-interfaces/src/Main.java b/tests/023-many-interfaces/src/Main.java
new file mode 100644
index 0000000..666a41c
--- /dev/null
+++ b/tests/023-many-interfaces/src/Main.java
@@ -0,0 +1,6 @@
+public class Main {
+    static public void main(String[] args) throws Exception {
+        boolean timing = (args.length >= 1) && args[0].equals("--timing");
+        ManyInterfaces.run(timing);
+    }
+}
diff --git a/tests/023-many-interfaces/src/ManyInterfaces.java b/tests/023-many-interfaces/src/ManyInterfaces.java
new file mode 100644
index 0000000..375938a
--- /dev/null
+++ b/tests/023-many-interfaces/src/ManyInterfaces.java
@@ -0,0 +1,413 @@
+// Copyright 2007 The Android Open Source Project
+
+/*
+Initial:
+test001: 2039901us  (4079ns per call)
+test049: 3346619us  (6693ns per call)
+test099: 4687402us  (9374ns per call)
+testInst001: 1327216us  (2654ns per use)
+testInst049: 1326995us  (2653ns per use)
+testInst099: 1327735us  (2655ns per use)
+
+After refactoring cache code: 2871ns per use
+After re-refactoring cache code: 2797ns per use
+
+After de-inlining invoke-interface:
+test001: 2164873us  (4329ns per call)
+test049: 3303884us  (6607ns per call)
+test099: 4656718us  (9313ns per call)
+testInst001: 1401731us  (2803ns per use)
+testInst049: 1401120us  (2802ns per use)
+testInst099: 1401298us  (2802ns per use)
+
+After adding caching for invoke-interface:
+testIface001: 1909330us  (3818ns per call)
+testIface049: 1905204us  (3810ns per call)
+testIface099: 1899012us  (3798ns per call)
+testVirt001: 1825001us  (3650ns per call)
+testVirt049: 1826161us  (3652ns per call)
+testVirt099: 1823915us  (3647ns per call)
+testInst001: 1393963us  (2787ns per use)
+testInst049: 1393163us  (2786ns per use)
+testInst099: 1390496us  (2780ns per use)
+
+After repeating each operation 16 times inside the inner loop:
+testIface001: 1429472us  (2726ns per call)      * 2382ns
+testIface049: 1427847us  (2723ns per call)      * 2396ns
+testIface099: 1423707us  (2715ns per call)      * 2387ns
+testVirt001: 1277790us  (2437ns per call)       * 2118ns
+testVirt049: 1280276us  (2441ns per call)       * 2119ns
+testVirt099: 1272640us  (2427ns per call)       * 2118ns
+testInst001: 844694us  (1611ns per use)         * 1396ns
+testInst049: 845619us  (1612ns per use)         * 1395ns
+testInst099: 845526us  (1612ns per use)         * 1394ns
+('*' is with dx optimizations enabled)
+*/
+
+/**
+ * Semi-generated class with many interfaces.
+ */
+public class ManyInterfaces
+    implements
+        Interface000,
+        Interface001,
+        Interface002,
+        Interface003,
+        Interface004,
+        Interface005,
+        Interface006,
+        Interface007,
+        Interface008,
+        Interface009,
+        Interface010,
+        Interface011,
+        Interface012,
+        Interface013,
+        Interface014,
+        Interface015,
+        Interface016,
+        Interface017,
+        Interface018,
+        Interface019,
+        Interface020,
+        Interface021,
+        Interface022,
+        Interface023,
+        Interface024,
+        Interface025,
+        Interface026,
+        Interface027,
+        Interface028,
+        Interface029,
+        Interface030,
+        Interface031,
+        Interface032,
+        Interface033,
+        Interface034,
+        Interface035,
+        Interface036,
+        Interface037,
+        Interface038,
+        Interface039,
+        Interface040,
+        Interface041,
+        Interface042,
+        Interface043,
+        Interface044,
+        Interface045,
+        Interface046,
+        Interface047,
+        Interface048,
+        Interface049,
+        Interface050,
+        Interface051,
+        Interface052,
+        Interface053,
+        Interface054,
+        Interface055,
+        Interface056,
+        Interface057,
+        Interface058,
+        Interface059,
+        Interface060,
+        Interface061,
+        Interface062,
+        Interface063,
+        Interface064,
+        Interface065,
+        Interface066,
+        Interface067,
+        Interface068,
+        Interface069,
+        Interface070,
+        Interface071,
+        Interface072,
+        Interface073,
+        Interface074,
+        Interface075,
+        Interface076,
+        Interface077,
+        Interface078,
+        Interface079,
+        Interface080,
+        Interface081,
+        Interface082,
+        Interface083,
+        Interface084,
+        Interface085,
+        Interface086,
+        Interface087,
+        Interface088,
+        Interface089,
+        Interface090,
+        Interface091,
+        Interface092,
+        Interface093,
+        Interface094,
+        Interface095,
+        Interface096,
+        Interface097,
+        Interface098,
+        Interface099
+{
+    /** whether to report timing information */
+    private static boolean timing = false;
+
+    /**
+     * Report on a section.
+     */
+    private static void report(String label, long start, long end, int iter,
+            int rept) {
+        if (timing) {
+            System.out.println(label + ": " + (end - start) / 1000 + "us"
+                    + "  (" + (end - start) / (iter*rept) + "ns per call)");
+        } else {
+            System.out.println(label + ": done");
+        }
+    }
+
+    /**
+     * Run tests.
+     *
+     * @param timing whether to print out timing info
+     */
+    public static void run(boolean timing) {
+        ManyInterfaces.timing = timing;
+        ManyInterfaces obj = new ManyInterfaces();
+        Interface001 one;
+        Interface049 forty;
+        Interface099 ninety;
+        long start, end;
+        int iter = 32768;
+        int rept = 16;
+        int i;
+
+        /*
+         * Clear the heap.  The various classes involved should already
+         * be loaded and ready as a result of instantiating ManyInterfaces.
+         */
+        System.gc();
+
+        start = System.nanoTime();
+        testIface001(obj, iter);
+        end = System.nanoTime();
+        report("testIface001", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testIface049(obj, iter);
+        end = System.nanoTime();
+        report("testIface049", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testIface099(obj, iter);
+        end = System.nanoTime();
+        report("testIface099", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testVirt001(obj, iter);
+        end = System.nanoTime();
+        report("testVirt001", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testVirt049(obj, iter);
+        end = System.nanoTime();
+        report("testVirt049", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testVirt099(obj, iter);
+        end = System.nanoTime();
+        report("testVirt099", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testInstance001(obj, iter);
+        end = System.nanoTime();
+        report("testInst001", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testInstance049(obj, iter);
+        end = System.nanoTime();
+        report("testInst049", start, end, iter, rept);
+
+        start = System.nanoTime();
+        testInstance099(obj, iter);
+        end = System.nanoTime();
+        report("testInst099", start, end, iter, rept);
+    }
+
+    public int func001() { return 1; }
+    public int func003() { return 3; }
+    public int func005() { return 5; }
+    public int func007() { return 7; }
+    public int func009() { return 9; }
+    public int func011() { return 11; }
+    public int func013() { return 13; }
+    public int func015() { return 15; }
+    public int func017() { return 17; }
+    public int func019() { return 19; }
+    public int func021() { return 21; }
+    public int func023() { return 23; }
+    public int func025() { return 25; }
+    public int func027() { return 27; }
+    public int func029() { return 29; }
+    public int func031() { return 31; }
+    public int func033() { return 33; }
+    public int func035() { return 35; }
+    public int func037() { return 37; }
+    public int func039() { return 39; }
+    public int func041() { return 41; }
+    public int func043() { return 43; }
+    public int func045() { return 45; }
+    public int func047() { return 47; }
+    public int func049() { return 49; }
+    public int func051() { return 51; }
+    public int func053() { return 53; }
+    public int func055() { return 55; }
+    public int func057() { return 57; }
+    public int func059() { return 59; }
+    public int func061() { return 61; }
+    public int func063() { return 63; }
+    public int func065() { return 65; }
+    public int func067() { return 67; }
+    public int func069() { return 69; }
+    public int func071() { return 71; }
+    public int func073() { return 73; }
+    public int func075() { return 75; }
+    public int func077() { return 77; }
+    public int func079() { return 79; }
+    public int func081() { return 81; }
+    public int func083() { return 83; }
+    public int func085() { return 85; }
+    public int func087() { return 87; }
+    public int func089() { return 89; }
+    public int func091() { return 91; }
+    public int func093() { return 93; }
+    public int func095() { return 95; }
+    public int func097() { return 97; }
+    public int func099() { return 99; }
+
+    static void testIface001(Interface001 iface, int count) {
+        while (count-- != 0) {
+            iface.func001(); iface.func001(); iface.func001(); iface.func001();
+            iface.func001(); iface.func001(); iface.func001(); iface.func001();
+            iface.func001(); iface.func001(); iface.func001(); iface.func001();
+            iface.func001(); iface.func001(); iface.func001(); iface.func001();
+        }
+    }
+
+    static void testIface049(Interface049 iface, int count) {
+        while (count-- != 0) {
+            iface.func049(); iface.func049(); iface.func049(); iface.func049();
+            iface.func049(); iface.func049(); iface.func049(); iface.func049();
+            iface.func049(); iface.func049(); iface.func049(); iface.func049();
+            iface.func049(); iface.func049(); iface.func049(); iface.func049();
+        }
+    }
+
+    static void testIface099(Interface099 iface, int count) {
+        while (count-- != 0) {
+            iface.func099(); iface.func099(); iface.func099(); iface.func099();
+            iface.func099(); iface.func099(); iface.func099(); iface.func099();
+            iface.func099(); iface.func099(); iface.func099(); iface.func099();
+            iface.func099(); iface.func099(); iface.func099(); iface.func099();
+        }
+    }
+
+    static void testVirt001(ManyInterfaces obj, int count) {
+        while (count-- != 0) {
+            obj.func001(); obj.func001(); obj.func001(); obj.func001();
+            obj.func001(); obj.func001(); obj.func001(); obj.func001();
+            obj.func001(); obj.func001(); obj.func001(); obj.func001();
+            obj.func001(); obj.func001(); obj.func001(); obj.func001();
+        }
+    }
+
+    static void testVirt049(ManyInterfaces obj, int count) {
+        while (count-- != 0) {
+            obj.func049(); obj.func049(); obj.func049(); obj.func049();
+            obj.func049(); obj.func049(); obj.func049(); obj.func049();
+            obj.func049(); obj.func049(); obj.func049(); obj.func049();
+            obj.func049(); obj.func049(); obj.func049(); obj.func049();
+        }
+    }
+
+    static void testVirt099(ManyInterfaces obj, int count) {
+        while (count-- != 0) {
+            obj.func099(); obj.func099(); obj.func099(); obj.func099();
+            obj.func099(); obj.func099(); obj.func099(); obj.func099();
+            obj.func099(); obj.func099(); obj.func099(); obj.func099();
+            obj.func099(); obj.func099(); obj.func099(); obj.func099();
+        }
+    }
+
+    static void testInstance001(Object obj, int count) {
+        if (!(obj instanceof Interface001))
+            System.err.println("BAD");
+        while (count-- != 0) {
+            boolean is;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+            is = obj instanceof Interface001;
+        }
+    }
+
+    static void testInstance049(Object obj, int count) {
+        if (!(obj instanceof Interface049))
+            System.err.println("BAD");
+        while (count-- != 0) {
+            boolean is;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+            is = obj instanceof Interface049;
+        }
+    }
+
+    static void testInstance099(Object obj, int count) {
+        if (!(obj instanceof Interface099))
+            System.err.println("BAD");
+        while (count-- != 0) {
+            boolean is;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+            is = obj instanceof Interface099;
+        }
+    }
+}
diff --git a/tests/024-illegal-access/expected.txt b/tests/024-illegal-access/expected.txt
new file mode 100644
index 0000000..5f951f4
--- /dev/null
+++ b/tests/024-illegal-access/expected.txt
@@ -0,0 +1,2 @@
+Got expected failure 1
+Got expected failure 2
diff --git a/tests/024-illegal-access/info.txt b/tests/024-illegal-access/info.txt
new file mode 100644
index 0000000..16a284d
--- /dev/null
+++ b/tests/024-illegal-access/info.txt
@@ -0,0 +1,3 @@
+Test that an attempt to access a private field results in a verification
+error.  Also try to access a non-public class in a different package with
+"instanceof".
diff --git a/tests/024-illegal-access/src/CheckInstanceof.java b/tests/024-illegal-access/src/CheckInstanceof.java
new file mode 100644
index 0000000..de48cd2
--- /dev/null
+++ b/tests/024-illegal-access/src/CheckInstanceof.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/**
+ * Make sure we're performing access checks on classes used in "instanceof".
+ */
+public class CheckInstanceof {
+    public static void main(Object obj) {
+        if (obj instanceof otherpkg.Package)
+            System.out.println("yes!");
+        else
+            System.out.println("no!");
+    }
+}
diff --git a/tests/024-illegal-access/src/Main.java b/tests/024-illegal-access/src/Main.java
new file mode 100644
index 0000000..bde73e9
--- /dev/null
+++ b/tests/024-illegal-access/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * 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 {
+    static public void main(String[] args) {
+        try {
+            PublicAccess.main();
+            System.err.println("ERROR: call 1 not expected to succeed");
+        } catch (VerifyError ve) {
+            // dalvik
+            System.out.println("Got expected failure 1");
+        } catch (IllegalAccessError iae) {
+            // reference
+            System.out.println("Got expected failure 1");
+        }
+
+        try {
+            CheckInstanceof.main(new Object());
+            System.err.println("ERROR: call 2 not expected to succeed");
+        } catch (VerifyError ve) {
+            // dalvik
+            System.out.println("Got expected failure 2");
+        } catch (IllegalAccessError iae) {
+            // reference
+            System.out.println("Got expected failure 2");
+        }
+    }
+}
diff --git a/tests/024-illegal-access/src/PublicAccess.java b/tests/024-illegal-access/src/PublicAccess.java
new file mode 100644
index 0000000..fdc0e9e
--- /dev/null
+++ b/tests/024-illegal-access/src/PublicAccess.java
@@ -0,0 +1,11 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Some stuff for access checks.
+ */
+public class PublicAccess {
+    public static void main() {
+        String shouldFail = SemiPrivate.mPrivvy;
+        System.out.println("Got " + shouldFail);
+    }
+}
diff --git a/tests/024-illegal-access/src/SemiPrivate.java b/tests/024-illegal-access/src/SemiPrivate.java
new file mode 100644
index 0000000..17b2ac0
--- /dev/null
+++ b/tests/024-illegal-access/src/SemiPrivate.java
@@ -0,0 +1,8 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Version with package scope access.
+ */
+public class SemiPrivate {
+    /* not private */ static String mPrivvy = "stuff";
+}
diff --git a/tests/024-illegal-access/src/otherpkg/Package.java b/tests/024-illegal-access/src/otherpkg/Package.java
new file mode 100644
index 0000000..bc295b5
--- /dev/null
+++ b/tests/024-illegal-access/src/otherpkg/Package.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package otherpkg;
+
+/*
+ * Package-scope class (public here).
+ */
+public class Package {
+}
diff --git a/tests/024-illegal-access/src2/SemiPrivate.java b/tests/024-illegal-access/src2/SemiPrivate.java
new file mode 100644
index 0000000..cf6f8e6
--- /dev/null
+++ b/tests/024-illegal-access/src2/SemiPrivate.java
@@ -0,0 +1,8 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Version with private access.
+ */
+public class SemiPrivate {
+    private static String mPrivvy = "stuff";
+}
diff --git a/tests/024-illegal-access/src2/otherpkg/Package.java b/tests/024-illegal-access/src2/otherpkg/Package.java
new file mode 100644
index 0000000..54d8341
--- /dev/null
+++ b/tests/024-illegal-access/src2/otherpkg/Package.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package otherpkg;
+
+/*
+ * Package-scope class.
+ */
+class Package {
+}
diff --git a/tests/025-access-controller/expected.txt b/tests/025-access-controller/expected.txt
new file mode 100644
index 0000000..75cfc99
--- /dev/null
+++ b/tests/025-access-controller/expected.txt
@@ -0,0 +1 @@
+AccessControllerTest: got 39
diff --git a/tests/025-access-controller/info.txt b/tests/025-access-controller/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/025-access-controller/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/025-access-controller/src/Main.java b/tests/025-access-controller/src/Main.java
new file mode 100644
index 0000000..84dc057
--- /dev/null
+++ b/tests/025-access-controller/src/Main.java
@@ -0,0 +1,14 @@
+// Copyright 2007 The Android Open Source Project
+
+import java.security.AccessController;
+
+/**
+ * Test java.security.AccessController.
+ */
+public class Main {
+    public static void main(String[] args) {
+        Privvy priv = new Privvy(38);
+        Integer result = AccessController.doPrivileged(priv);
+        System.out.println("AccessControllerTest: got " + result);
+    }
+}
diff --git a/tests/025-access-controller/src/Privvy.java b/tests/025-access-controller/src/Privvy.java
new file mode 100644
index 0000000..07a0678
--- /dev/null
+++ b/tests/025-access-controller/src/Privvy.java
@@ -0,0 +1,18 @@
+// Copyright 2007 The Android Open Source Project
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+
+class Privvy implements PrivilegedAction<Integer> {
+
+    private Integer mValue;
+
+    public Privvy(int val) {
+        mValue = new Integer(val + 1);
+    }
+
+    public Integer run() {
+        return mValue;
+    }
+}
diff --git a/tests/026-access/expected.txt b/tests/026-access/expected.txt
new file mode 100644
index 0000000..dabfb37
--- /dev/null
+++ b/tests/026-access/expected.txt
@@ -0,0 +1,2 @@
+access test
+Blort.
diff --git a/tests/026-access/info.txt b/tests/026-access/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/026-access/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/026-access/src/Main.java b/tests/026-access/src/Main.java
new file mode 100644
index 0000000..9628259
--- /dev/null
+++ b/tests/026-access/src/Main.java
@@ -0,0 +1,12 @@
+// Copyright 2006 The Android Open Source Project
+
+import otherpackage.PublicAccess;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("access test");
+
+        PublicAccess pa = new PublicAccess();
+        pa.main();
+    }
+}
diff --git a/tests/026-access/src/otherpackage/PublicAccess.java b/tests/026-access/src/otherpackage/PublicAccess.java
new file mode 100644
index 0000000..996fa76
--- /dev/null
+++ b/tests/026-access/src/otherpackage/PublicAccess.java
@@ -0,0 +1,7 @@
+package otherpackage;
+
+public class PublicAccess {
+    static public void main() {
+        System.out.println("Blort.");
+    }
+}
diff --git a/tests/027-arithmetic/expected.txt b/tests/027-arithmetic/expected.txt
new file mode 100644
index 0000000..2dadf10
--- /dev/null
+++ b/tests/027-arithmetic/expected.txt
@@ -0,0 +1,18 @@
+f=1234.5677 --> i=1234
+f=-1234.5677 --> i=-1234
+d=1234.5678 --> i=1234
+d=-1234.5678 --> i=-1234
+d=5.6789567890123E9 --> l=5678956789
+d=-5.6789567890123E9 --> l=-5678956789
+i=7654 --> l=7654
+i=-7654 --> l=-7654
+l=5678956789 --> i=1383989493
+l=-5678956789 --> i=-1383989493
+i=1234 --> f=1234.0
+i=-1234 --> f=-1234.0
+values are 44332211 and bbaa9988
+First l is bbaa998844332211
+Second l is bbaa998844332211
+shiftTest2 l is 1122334455667788
+b=-1, s=-1, c=4095, i=268435455
+b=0xffffffff, s=0xffffffff, c=0xfff, i=0xfffffff
diff --git a/tests/027-arithmetic/info.txt b/tests/027-arithmetic/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/027-arithmetic/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/027-arithmetic/src/Main.java b/tests/027-arithmetic/src/Main.java
new file mode 100644
index 0000000..4d0f74e
--- /dev/null
+++ b/tests/027-arithmetic/src/Main.java
@@ -0,0 +1,141 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Test arithmetic operations.
+ */
+public class Main {
+
+    static void shiftTest1()
+    {
+        final int[] mBytes = {
+            0x11, 0x22, 0x33, 0x44, 0x88, 0x99, 0xaa, 0xbb
+        };
+        long l;
+        int i1, i2;
+
+        i1 = mBytes[0] | mBytes[1] << 8 | mBytes[2] << 16 | mBytes[3] << 24;
+        i2 = mBytes[4] | mBytes[5] << 8 | mBytes[6] << 16 | mBytes[7] << 24;
+        l = i1 | ((long)i2 << 32);
+
+	System.out.println("values are " + Integer.toHexString(i1)
+	    + " and " + Integer.toHexString(i2));
+
+        System.out.println("First l is " + Long.toHexString(l));
+
+        l = (long)mBytes[0]
+            | (long)mBytes[1] << 8
+            | (long)mBytes[2] << 16
+            | (long)mBytes[3] << 24
+            | (long)mBytes[4] << 32
+            | (long)mBytes[5] << 40
+            | (long)mBytes[6] << 48
+            | (long)mBytes[7] << 56;
+
+        System.out.println("Second l is " + Long.toHexString(l));
+    }
+
+    static void shiftTest2()
+    {
+        long    a = 0x11;
+        long    b = 0x22;
+        long    c = 0x33;
+        long    d = 0x44;
+        long    e = 0x55;
+        long    f = 0x66;
+        long    g = 0x77;
+        long    h = 0x88;
+
+        long    result = ((a << 56) | (b << 48) | (c << 40) | (d << 32) |
+                         (e << 24) | (f << 16) | (g << 8) | h);
+
+        System.out.println("shiftTest2 l is " + Long.toHexString(result));
+    }
+
+    static void convTest()
+    {
+        float f;
+        double d;
+        int i;
+        long l;
+
+        /* float --> int */
+        f = 1234.5678f;
+        i = (int) f;
+        System.out.println("f=" + f + " --> i=" + i);
+
+        f = -1234.5678f;
+        i = (int) f;
+        System.out.println("f=" + f + " --> i=" + i);
+
+        /* double --> int */
+        d = 1234.5678;
+        i = (int) d;
+        System.out.println("d=" + d + " --> i=" + i);
+
+        d = -1234.5678;
+        i = (int) d;
+        System.out.println("d=" + d + " --> i=" + i);
+
+        /* double --> long */
+        d = 5678956789.0123;
+        l = (long) d;
+        System.out.println("d=" + d + " --> l=" + l);
+
+        d = -5678956789.0123;
+        l = (long) d;
+        System.out.println("d=" + d + " --> l=" + l);
+
+        /* int --> long */
+        i = 7654;
+        l = (long) i;
+        System.out.println("i=" + i + " --> l=" + l);
+
+        i = -7654;
+        l = (long) i;
+        System.out.println("i=" + i + " --> l=" + l);
+
+        /* long --> int (with truncation) */
+        l = 5678956789L;
+        i = (int) l;
+        System.out.println("l=" + l + " --> i=" + i);
+
+        l = -5678956789L;
+        i = (int) l;
+        System.out.println("l=" + l + " --> i=" + i);
+
+        /* int --> float */
+        i = 1234;
+        f = (float) i;
+        System.out.println("i=" + i + " --> f=" + f);
+
+        i = -1234;
+        f = (float) i;
+        System.out.println("i=" + i + " --> f=" + f);
+    }
+
+    static void unsignedShiftTest()
+    {
+        byte b = -4;
+        short s = -4;
+        char c = 0xfffc;
+        int i = -4;
+
+        b >>>= 4;
+        s >>>= 4;
+        c >>>= 4;
+        i >>>= 4;
+
+        System.out.println("b=" + b + ", s=" + s + ", c=" + (int)c + ", i=" +i);
+        System.out.println("b=0x" + Integer.toHexString((int)b)
+            + ", s=0x" + Integer.toHexString((int)s)
+            + ", c=0x" + Integer.toHexString((int)c)
+            + ", i=0x" + Integer.toHexString(i));
+    }
+
+    public static void main(String[] args) {
+        convTest();
+        shiftTest1();
+        shiftTest2();
+        unsignedShiftTest();
+    }
+}
diff --git a/tests/028-array-write/expected.txt b/tests/028-array-write/expected.txt
new file mode 100644
index 0000000..85986b5
--- /dev/null
+++ b/tests/028-array-write/expected.txt
@@ -0,0 +1,3 @@
+Running writeTest...
+Running copyTest...
+Done!
diff --git a/tests/028-array-write/info.txt b/tests/028-array-write/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/028-array-write/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/028-array-write/src/Main.java b/tests/028-array-write/src/Main.java
new file mode 100644
index 0000000..6f36f84
--- /dev/null
+++ b/tests/028-array-write/src/Main.java
@@ -0,0 +1,68 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Array write speed test.
+ */
+public class Main {
+    /** whether to report times */
+    static boolean timing = false;
+
+    static final int STORAGE_SIZE = 128*1024;
+    static int[] mStorage = new int[STORAGE_SIZE];
+
+    static public void report(long start, long end) {
+        if (! timing) {
+            return;
+        }
+
+        System.out.println("Finished in " + ((end - start) / 1000000.0)
+            + " msec");
+    }
+
+    static void writeArray(int val) {
+        for (int i = STORAGE_SIZE-1; i >= 0; i--)
+            mStorage[i] = val;
+    }
+
+    static void writeTest() {
+        long start, end;
+
+        writeArray(0);  // touch all the memory
+
+        System.out.println("Running writeTest...");
+        start = System.nanoTime();
+        for (int i = 1; i < 20; i++)
+            writeArray(i);
+        end = System.nanoTime();
+
+        report(start, end);
+    }
+
+    static void copyTest() {
+        long start, end;
+
+        // touch once
+        System.arraycopy(mStorage, 0, mStorage,
+            STORAGE_SIZE/2, STORAGE_SIZE/2);
+
+        System.out.println("Running copyTest...");
+        start = System.nanoTime();
+        for (int i = 1; i < 35; i++) {
+            System.arraycopy(mStorage, 0, mStorage,
+                STORAGE_SIZE/2, STORAGE_SIZE/2);
+        }
+        end = System.nanoTime();
+
+        report(start, end);
+    }
+
+    public static void main(String[] args) {
+        if ((args.length >= 1) && args[0].equals("--timing")) {
+            timing = true;
+        }
+
+        writeTest();
+        copyTest();
+        System.out.println("Done!");
+    }
+}
diff --git a/tests/029-assert/expected.txt b/tests/029-assert/expected.txt
new file mode 100644
index 0000000..bf0efec
--- /dev/null
+++ b/tests/029-assert/expected.txt
@@ -0,0 +1 @@
+caught expected assert exception
diff --git a/tests/029-assert/info.txt b/tests/029-assert/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/029-assert/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/029-assert/src/Main.java b/tests/029-assert/src/Main.java
new file mode 100644
index 0000000..1e5cc7c
--- /dev/null
+++ b/tests/029-assert/src/Main.java
@@ -0,0 +1,16 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Test Java language asserts.
+ */
+public class Main {
+    public static void main(String[] args) {
+        assert true;
+        try {
+            assert false;
+            System.out.println("GLITCH: didn't assert (is '-ea' set?)");
+        } catch (AssertionError ae) {
+            System.out.println("caught expected assert exception");
+        }
+    }
+}
diff --git a/tests/030-bad-finalizer/expected.txt b/tests/030-bad-finalizer/expected.txt
new file mode 100644
index 0000000..88b1896
--- /dev/null
+++ b/tests/030-bad-finalizer/expected.txt
@@ -0,0 +1,7 @@
+Constructed object.
+Nulled. Requestion gc.
+Finalizer started and spinning...
+Finalizer done spinning.
+Finalizer sleeping forever now.
+Requesting another GC.
+Requesting another GC.
diff --git a/tests/030-bad-finalizer/info.txt b/tests/030-bad-finalizer/info.txt
new file mode 100644
index 0000000..26f4993
--- /dev/null
+++ b/tests/030-bad-finalizer/info.txt
@@ -0,0 +1,15 @@
+The finalizer for this class never finishes.  Dalvik is expected to detect
+this situation and abort the VM (so you will likely see a stacktrace like
+the following in the log output).
+
+java.util.concurrent.TimeoutException
+	at java.lang.VMThread.sleep(Native Method)
+	at java.lang.Thread.sleep(Thread.java:1031)
+	at java.lang.Thread.sleep(Thread.java:1013)
+	at BadFinalizer.snooze(BadFinalizer.java:9)
+	at BadFinalizer.finalize(BadFinalizer.java:29)
+	at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:182)
+	at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:168)
+	at java.lang.Thread.run(Thread.java:856)
+Calling exit(2)
+
diff --git a/tests/030-bad-finalizer/src/BadFinalizer.java b/tests/030-bad-finalizer/src/BadFinalizer.java
new file mode 100644
index 0000000..3ff422b
--- /dev/null
+++ b/tests/030-bad-finalizer/src/BadFinalizer.java
@@ -0,0 +1,32 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Class with a bad finalizer.
+ */
+public class BadFinalizer {
+    public static void snooze(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException ie) {
+            System.out.println("Snooze: " + ie.getMessage());
+        }
+    }
+
+    protected void finalize() {
+        System.out.println("Finalizer started and spinning...");
+        int j = 0;
+
+        /* spin for a bit */
+        long start, end;
+        start = System.nanoTime();
+        for (int i = 0; i < 1000000; i++)
+            j++;
+        end = System.nanoTime();
+        System.out.println("Finalizer done spinning.");
+
+        System.out.println("Finalizer sleeping forever now.");
+        while (true) {
+            snooze(10000);
+        }
+    }
+}
diff --git a/tests/030-bad-finalizer/src/Main.java b/tests/030-bad-finalizer/src/Main.java
new file mode 100644
index 0000000..c063476
--- /dev/null
+++ b/tests/030-bad-finalizer/src/Main.java
@@ -0,0 +1,25 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Test a class with a bad finalizer.
+ */
+public class Main {
+    public static void main(String[] args) {
+        BadFinalizer bf = new BadFinalizer();
+
+        System.out.println("Constructed object.");
+        bf = null;
+
+        System.out.println("Nulled. Requestion gc.");
+        System.gc();
+
+        for (int i = 0; i < 8; i++) {
+            BadFinalizer.snooze(5000);
+            System.out.println("Requesting another GC.");
+            System.gc();
+        }
+
+        System.out.println("Done waiting.");
+        System.exit(0);
+    }
+}
diff --git a/tests/031-class-attributes/expected.txt b/tests/031-class-attributes/expected.txt
new file mode 100644
index 0000000..47eaeee
--- /dev/null
+++ b/tests/031-class-attributes/expected.txt
@@ -0,0 +1,164 @@
+***** class ClassAttrs:
+  name: ClassAttrs
+  canonical: ClassAttrs
+  simple: ClassAttrs
+  genericSignature: null
+  super: class java.lang.Object
+  declaring: null
+  enclosing: null
+  enclosingCon: null
+  enclosingMeth: null
+  modifiers: 1
+  package: null
+  declaredClasses: [2] class ClassAttrs$PublicMemberClass, class ClassAttrs$MemberClass
+  member classes: [1] class ClassAttrs$PublicMemberClass
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: false
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+***** class OtherClass:
+  name: OtherClass
+  canonical: OtherClass
+  simple: OtherClass
+  genericSignature: null
+  super: class java.lang.Object
+  declaring: null
+  enclosing: null
+  enclosingCon: null
+  enclosingMeth: null
+  modifiers: 0
+  package: null
+  declaredClasses: [0]
+  member classes: [0]
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: false
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+***** class otherpackage.OtherPackageClass:
+  name: otherpackage.OtherPackageClass
+  canonical: otherpackage.OtherPackageClass
+  simple: OtherPackageClass
+  genericSignature: null
+  super: class java.lang.Object
+  declaring: null
+  enclosing: null
+  enclosingCon: null
+  enclosingMeth: null
+  modifiers: 1
+  package: package otherpackage
+  declaredClasses: [0]
+  member classes: [0]
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: false
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+***** class ClassAttrs$1InnerNamed:
+  name: ClassAttrs$1InnerNamed
+  canonical: null
+  simple: InnerNamed
+  genericSignature: null
+  super: class java.lang.Object
+  declaring: null
+  enclosing: class ClassAttrs
+  enclosingCon: null
+  enclosingMeth: public static void ClassAttrs.main()
+  modifiers: 0
+  package: null
+  declaredClasses: [0]
+  member classes: [0]
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: true
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+***** class ClassAttrs$1ConsInnerNamed:
+  name: ClassAttrs$1ConsInnerNamed
+  canonical: null
+  simple: ConsInnerNamed
+  genericSignature: null
+  super: class java.lang.Object
+  declaring: null
+  enclosing: class ClassAttrs
+  enclosingCon: ClassAttrs()
+  enclosingMeth: null
+  modifiers: 0
+  package: null
+  declaredClasses: [0]
+  member classes: [0]
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: true
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+***** class ClassAttrs$1:
+  name: ClassAttrs$1
+  canonical: null
+  simple: 
+  genericSignature: null
+  super: class OtherClass
+  declaring: null
+  enclosing: class ClassAttrs
+  enclosingCon: null
+  enclosingMeth: public static void ClassAttrs.main()
+  modifiers: 8
+  package: null
+  declaredClasses: [0]
+  member classes: [0]
+  isAnnotation: false
+  isAnonymous: true
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: false
+  isMemberClass: false
+  isPrimitive: false
+  isSynthetic: false
+***** class ClassAttrs$MemberClass:
+  name: ClassAttrs$MemberClass
+  canonical: ClassAttrs.MemberClass
+  simple: MemberClass
+  genericSignature: <XYZ:Ljava/lang/Object;>Ljava/lang/Object;
+  super: class java.lang.Object
+  declaring: class ClassAttrs
+  enclosing: class ClassAttrs
+  enclosingCon: null
+  enclosingMeth: null
+  modifiers: 8
+  package: null
+  declaredClasses: [0]
+  member classes: [0]
+  isAnnotation: false
+  isAnonymous: false
+  isArray: false
+  isEnum: false
+  isInterface: false
+  isLocalClass: false
+  isMemberClass: true
+  isPrimitive: false
+  isSynthetic: false
+constructor signature: (LClassAttrs$MemberClass<TXYZ;>;)V
+method signature: ()Ljava/lang/Class<TXYZ;>;
+field signature: LClassAttrs$MemberClass<TXYZ;>;
diff --git a/tests/031-class-attributes/info.txt b/tests/031-class-attributes/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/031-class-attributes/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/031-class-attributes/src/ClassAttrs.java b/tests/031-class-attributes/src/ClassAttrs.java
new file mode 100644
index 0000000..c1407bd
--- /dev/null
+++ b/tests/031-class-attributes/src/ClassAttrs.java
@@ -0,0 +1,201 @@
+import otherpackage.OtherPackageClass;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+public class ClassAttrs {
+    ClassAttrs() {
+        /* local, not anonymous, not member */
+        class ConsInnerNamed {
+            public void showMe() {
+                printClassAttrs(this.getClass());
+            }
+        }
+
+        ConsInnerNamed cinner = new ConsInnerNamed();
+        cinner.showMe();
+    }
+
+    public static void main() {
+        printClassAttrs(ClassAttrs.class);
+        printClassAttrs(OtherClass.class);
+        printClassAttrs(OtherPackageClass.class);
+
+        /* local, not anonymous, not member */
+        class InnerNamed {
+            public void showMe() {
+                printClassAttrs(this.getClass());
+            }
+        }
+        InnerNamed inner = new InnerNamed();
+        inner.showMe();
+
+        ClassAttrs attrs = new ClassAttrs();
+
+        /* anonymous, not local, not member */
+        printClassAttrs((new OtherClass() { int i = 5; }).getClass());
+
+        /* member, not anonymous, not local */
+        printClassAttrs(MemberClass.class);
+
+        try {
+            Constructor cons;
+            cons = MemberClass.class.getConstructor(
+                    new Class[] { MemberClass.class });
+            System.out.println("constructor signature: "
+                    + getSignatureAttribute(cons));
+
+            Method meth;
+            meth = MemberClass.class.getMethod("foo", (Class[]) null);
+            System.out.println("method signature: "
+                    + getSignatureAttribute(meth));
+
+            Field field;
+            field = MemberClass.class.getField("mWha");
+            System.out.println("field signature: "
+                    + getSignatureAttribute(field));
+        } catch (NoSuchMethodException nsme) {
+            System.err.println("FAILED: " + nsme);
+        } catch (NoSuchFieldException nsfe) {
+            System.err.println("FAILED: " + nsfe);
+        } catch (RuntimeException re) {
+            System.err.println("FAILED: " + re);
+            re.printStackTrace();
+        }
+    }
+
+    /* to call the (out-of-scope) <code>getSignatureAttribute</code> methods */
+    public static String getSignatureAttribute(Object obj) {
+        Method method;
+        try {
+            if (obj instanceof AccessibleObject) {
+                method = AccessibleObject.class.getDeclaredMethod(
+                        "getSignatureAttribute");
+            } else {
+                // Should be a Class.
+                method = Class.class.getDeclaredMethod(
+                        "getSignatureAttribute");
+            }
+            method.setAccessible(true);
+        } catch (NoSuchMethodException ex) {
+            System.err.println("getSignatureAttribute() not defined.");
+            ex.printStackTrace();
+            return "<unknown>";
+        }
+
+        try {
+            return (String) method.invoke(obj);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(ex);
+        } catch (InvocationTargetException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /* for reflection testing */
+    static class MemberClass<XYZ> {
+        public MemberClass<XYZ> mWha;
+
+        public MemberClass(MemberClass<XYZ> memb) {
+            mWha = memb;
+        }
+
+        public Class<XYZ> foo() throws NoSuchMethodException {
+            return null;
+        }
+    }
+
+    /* for reflection testing (getClasses vs getDeclaredClasses) */
+    static public class PublicMemberClass {
+        float mBlah;
+    }
+
+    /*
+     * Dump a variety of class attributes.
+     */
+    public static void printClassAttrs(Class clazz) {
+        final boolean WORKING = false;
+        Class clazz2;
+
+        System.out.println("***** " + clazz + ":");
+
+        System.out.println("  name: "
+            + clazz.getName());
+        System.out.println("  canonical: "
+            + clazz.getCanonicalName());
+        System.out.println("  simple: "
+            + clazz.getSimpleName());
+        System.out.println("  genericSignature: "
+            + getSignatureAttribute(clazz));
+
+        System.out.println("  super: "
+            + clazz.getSuperclass());
+        if (WORKING) System.out.println("  genericSuperclass: "
+            + clazz.getGenericSuperclass());
+        System.out.println("  declaring: "
+            + clazz.getDeclaringClass());
+        System.out.println("  enclosing: "
+            + clazz.getEnclosingClass());
+        System.out.println("  enclosingCon: "
+            + clazz.getEnclosingConstructor());
+        System.out.println("  enclosingMeth: "
+            + clazz.getEnclosingMethod());
+        System.out.println("  modifiers: "
+            + clazz.getModifiers());
+        System.out.println("  package: "
+            + clazz.getPackage());
+
+        System.out.println("  declaredClasses: "
+            + stringifyTypeArray(clazz.getDeclaredClasses()));
+        System.out.println("  member classes: "
+            + stringifyTypeArray(clazz.getClasses()));
+
+        System.out.println("  isAnnotation: "
+            + clazz.isAnnotation());
+        System.out.println("  isAnonymous: "
+            + clazz.isAnonymousClass());
+        System.out.println("  isArray: "
+            + clazz.isArray());
+        System.out.println("  isEnum: "
+            + clazz.isEnum());
+        System.out.println("  isInterface: "
+            + clazz.isInterface());
+        System.out.println("  isLocalClass: "
+            + clazz.isLocalClass());
+        System.out.println("  isMemberClass: "
+            + clazz.isMemberClass());
+        System.out.println("  isPrimitive: "
+            + clazz.isPrimitive());
+        System.out.println("  isSynthetic: "
+            + clazz.isSynthetic());
+
+        if (WORKING) System.out.println("  genericInterfaces: "
+            + stringifyTypeArray(clazz.getGenericInterfaces()));
+    }
+
+    /*
+     * Convert an array of Type into a string.  Start with an array count.
+     */
+    private static String stringifyTypeArray(Type[] types) {
+        StringBuilder stb = new StringBuilder();
+        boolean first = true;
+
+        stb.append("[" + types.length + "]");
+
+        for (Type t: types) {
+            if (first) {
+                stb.append(" ");
+                first = false;
+            } else {
+                stb.append(", ");
+            }
+            stb.append(t.toString());
+        }
+
+        return stb.toString();
+    }
+}
diff --git a/tests/031-class-attributes/src/Main.java b/tests/031-class-attributes/src/Main.java
new file mode 100644
index 0000000..bc6b749
--- /dev/null
+++ b/tests/031-class-attributes/src/Main.java
@@ -0,0 +1,5 @@
+public class Main {
+    public static void main(String[] args) {
+        ClassAttrs.main();
+    }
+}
diff --git a/tests/031-class-attributes/src/OtherClass.java b/tests/031-class-attributes/src/OtherClass.java
new file mode 100644
index 0000000..0b4526e
--- /dev/null
+++ b/tests/031-class-attributes/src/OtherClass.java
@@ -0,0 +1,2 @@
+class OtherClass {
+}
diff --git a/tests/031-class-attributes/src/otherpackage/OtherPackageClass.java b/tests/031-class-attributes/src/otherpackage/OtherPackageClass.java
new file mode 100644
index 0000000..9652b77
--- /dev/null
+++ b/tests/031-class-attributes/src/otherpackage/OtherPackageClass.java
@@ -0,0 +1,4 @@
+package otherpackage;
+
+public class OtherPackageClass {
+}
diff --git a/tests/032-concrete-sub/expected.txt b/tests/032-concrete-sub/expected.txt
new file mode 100644
index 0000000..56f25bb
--- /dev/null
+++ b/tests/032-concrete-sub/expected.txt
@@ -0,0 +1,6 @@
+calling abs.doStuff()
+In AbstractBase.doStuff (src2)
+Got expected exception from abs.doStuff().
+class modifiers=1025
+meth modifiers=1025
+Got expected failure
diff --git a/tests/032-concrete-sub/info.txt b/tests/032-concrete-sub/info.txt
new file mode 100644
index 0000000..1956994
--- /dev/null
+++ b/tests/032-concrete-sub/info.txt
@@ -0,0 +1,3 @@
+This tests some facets of abstract method handling, notably situations
+where a concrete class and its abstract superclass were compiled with
+different notions about which methods are abstract.
diff --git a/tests/032-concrete-sub/src/AbstractBase.java b/tests/032-concrete-sub/src/AbstractBase.java
new file mode 100644
index 0000000..6281189
--- /dev/null
+++ b/tests/032-concrete-sub/src/AbstractBase.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Abstract base class.
+ */
+public abstract class AbstractBase {
+    public void doStuff() {
+        System.out.println("In AbstractBase.doStuff");
+    }
+
+    public void abstractOrNot() {}
+}
diff --git a/tests/032-concrete-sub/src/ConcreteSub.java b/tests/032-concrete-sub/src/ConcreteSub.java
new file mode 100644
index 0000000..083f25d
--- /dev/null
+++ b/tests/032-concrete-sub/src/ConcreteSub.java
@@ -0,0 +1,53 @@
+/*
+ * 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.Method;
+
+/**
+ * Test insertion of an abstract method in a superclass.
+ */
+public class ConcreteSub extends AbstractBase {
+    private static void callBase(AbstractBase abs) {
+        System.out.println("calling abs.doStuff()");
+        abs.doStuff();
+    }
+
+    public static void main() {
+        ConcreteSub sub = new ConcreteSub();
+
+        try {
+            callBase(sub);
+        } catch (AbstractMethodError ame) {
+            System.out.println("Got expected exception from abs.doStuff().");
+        }
+
+        /*
+         * Check reflection stuff.
+         */
+        Class absClass = AbstractBase.class;
+        Method meth;
+
+        System.out.println("class modifiers=" + absClass.getModifiers());
+
+        try {
+            meth = absClass.getMethod("redefineMe", (Class[]) null);
+        } catch (NoSuchMethodException nsme) {
+            nsme.printStackTrace();
+            return;
+        }
+        System.out.println("meth modifiers=" + meth.getModifiers());
+    }
+}
diff --git a/tests/032-concrete-sub/src/ConcreteSub2.java b/tests/032-concrete-sub/src/ConcreteSub2.java
new file mode 100644
index 0000000..0a9e67e
--- /dev/null
+++ b/tests/032-concrete-sub/src/ConcreteSub2.java
@@ -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.
+ */
+
+/**
+ * Test conversion of a concrete method to an abstract method.  This class
+ * will fail verification because there is no implementation of the
+ * abstractOrNot() method.
+ */
+public class ConcreteSub2 extends AbstractBase {
+    public void doStuff() {
+        abstractOrNot();
+    }
+}
diff --git a/tests/032-concrete-sub/src/Main.java b/tests/032-concrete-sub/src/Main.java
new file mode 100644
index 0000000..4a5193d
--- /dev/null
+++ b/tests/032-concrete-sub/src/Main.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test insertion of an abstract method in a superclass.
+ */
+public class Main {
+    public static void main(String[] args) {
+        ConcreteSub.main();
+
+        try {
+            // Dalvik verifier stops here (VerifyError)
+            ConcreteSub2 blah = new ConcreteSub2();
+            // other VMs fail here (AbstractMethodError)
+            blah.doStuff();
+            System.err.println("Succeeded unexpectedly");
+        } catch (VerifyError ve) {
+            System.out.println("Got expected failure");
+        } catch (AbstractMethodError ame) {
+            System.out.println("Got expected failure");
+        }
+    }
+}
diff --git a/tests/032-concrete-sub/src2/AbstractBase.java b/tests/032-concrete-sub/src2/AbstractBase.java
new file mode 100644
index 0000000..534f738
--- /dev/null
+++ b/tests/032-concrete-sub/src2/AbstractBase.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Abstract base class.
+ */
+public abstract class AbstractBase {
+    public void doStuff() {
+        System.out.println("In AbstractBase.doStuff (src2)");
+        redefineMe();
+    }
+
+    public abstract void redefineMe();
+
+    public abstract void abstractOrNot();
+}
diff --git a/tests/033-class-init-deadlock/expected.txt b/tests/033-class-init-deadlock/expected.txt
new file mode 100644
index 0000000..387a426
--- /dev/null
+++ b/tests/033-class-init-deadlock/expected.txt
@@ -0,0 +1,7 @@
+Deadlock test starting.
+A initializing...
+B initializing...
+Deadlock test interupting threads.
+Deadlock test main thread bailing.
+A initialized: false
+B initialized: false
diff --git a/tests/033-class-init-deadlock/info.txt b/tests/033-class-init-deadlock/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/033-class-init-deadlock/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/033-class-init-deadlock/src/Main.java b/tests/033-class-init-deadlock/src/Main.java
new file mode 100644
index 0000000..27c4922
--- /dev/null
+++ b/tests/033-class-init-deadlock/src/Main.java
@@ -0,0 +1,51 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * This causes most VMs to lock up.
+ *
+ * Interrupting threads in class initialization should NOT work.
+ */
+public class Main {
+    public static boolean aInitialized = false;
+    public static boolean bInitialized = false;
+
+    static public void main(String[] args) {
+        Thread thread1, thread2;
+
+        System.out.println("Deadlock test starting.");
+        thread1 = new Thread() { public void run() { new A(); } };
+        thread2 = new Thread() { public void run() { new B(); } };
+        thread1.start();
+        thread2.start();
+
+        try { Thread.sleep(6000); } catch (InterruptedException ie) { }
+
+        System.out.println("Deadlock test interupting threads.");
+        thread1.interrupt();
+        thread2.interrupt();
+        System.out.println("Deadlock test main thread bailing.");
+        System.out.println("A initialized: " + aInitialized);
+        System.out.println("B initialized: " + bInitialized);
+        System.exit(0);
+    }
+}
+
+class A {
+    static {
+        System.out.println("A initializing...");
+        try { Thread.sleep(3000); } catch (InterruptedException ie) { }
+        new B();
+        System.out.println("A initialized");
+        Main.aInitialized = true;
+    }
+}
+
+class B {
+    static {
+        System.out.println("B initializing...");
+        try { Thread.sleep(3000); } catch (InterruptedException ie) { }
+        new A();
+        System.out.println("B initialized");
+        Main.bInitialized = true;
+    }
+}
diff --git a/tests/034-call-null/expected.txt b/tests/034-call-null/expected.txt
new file mode 100644
index 0000000..5ffbe05
--- /dev/null
+++ b/tests/034-call-null/expected.txt
@@ -0,0 +1,3 @@
+java.lang.NullPointerException
+	at Main.main(Main.java:12)
+	at dalvik.system.NativeStart.main(Native Method)
diff --git a/tests/034-call-null/info.txt b/tests/034-call-null/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/034-call-null/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/034-call-null/src/Main.java b/tests/034-call-null/src/Main.java
new file mode 100644
index 0000000..a0a129e
--- /dev/null
+++ b/tests/034-call-null/src/Main.java
@@ -0,0 +1,14 @@
+// Copyright 2008 The Android Open Source Project
+
+public class Main {
+    int mFoo = 27;
+
+    private void doStuff() {
+        System.out.println("mFoo is " + mFoo);
+    }
+
+    public static void main(String[] args) {
+        Main instance = null;
+        instance.doStuff();
+    }
+}
diff --git a/tests/035-enum/expected.txt b/tests/035-enum/expected.txt
new file mode 100644
index 0000000..50f2791
--- /dev/null
+++ b/tests/035-enum/expected.txt
@@ -0,0 +1,3 @@
+found field CRAWLING
+  synthetic? false
+  enum? true
diff --git a/tests/035-enum/info.txt b/tests/035-enum/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/035-enum/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/035-enum/src/Main.java b/tests/035-enum/src/Main.java
new file mode 100644
index 0000000..09fcc98
--- /dev/null
+++ b/tests/035-enum/src/Main.java
@@ -0,0 +1,23 @@
+// Copyright 2008 The Android Open Source Project
+
+import java.lang.reflect.Field;
+
+/**
+ * Try some stuff with enumerations.
+ */
+public class Main {
+    public enum Shubbery { GROUND, CRAWLING, HANGING }
+
+    public static void main(String[] args) {
+        Field field;
+        try {
+            field = Shubbery.class.getDeclaredField("CRAWLING");
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        }
+
+        System.out.println("found field " + field.getName());
+        System.out.println("  synthetic? " + field.isSynthetic());
+        System.out.println("  enum? " + field.isEnumConstant());
+    }
+}
diff --git a/tests/036-finalizer/expected.txt b/tests/036-finalizer/expected.txt
new file mode 100644
index 0000000..f9b29b0
--- /dev/null
+++ b/tests/036-finalizer/expected.txt
@@ -0,0 +1,14 @@
+wimp: wahoo
+gc
+finalizer executed: wahoo
+wimp: null
+finalize
+wimp: null
+sleep
+reborn: wahoo
+wimp: null
+reset reborn
+gc + finalize
+sleep
+reborn: nothing
+wimp: null
diff --git a/tests/036-finalizer/info.txt b/tests/036-finalizer/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/036-finalizer/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/036-finalizer/src/FinalizerTest.java b/tests/036-finalizer/src/FinalizerTest.java
new file mode 100644
index 0000000..420ec34
--- /dev/null
+++ b/tests/036-finalizer/src/FinalizerTest.java
@@ -0,0 +1,23 @@
+// Copyright 2008 The Android Open Source Project
+
+import java.lang.ref.WeakReference;
+
+public class FinalizerTest {
+    public static FinalizerTest mNothing = new FinalizerTest("nothing");
+    public static FinalizerTest mReborn = mNothing;
+
+    public String mMsg = "default";
+
+    public FinalizerTest(String msg) {
+        mMsg = msg;
+    }
+
+    public String toString() {
+        return mMsg;
+    }
+
+    protected void finalize() {
+        System.out.println("finalizer executed: " + mMsg);
+        mReborn = this;
+    }
+}
diff --git a/tests/036-finalizer/src/Main.java b/tests/036-finalizer/src/Main.java
new file mode 100644
index 0000000..c29cc11
--- /dev/null
+++ b/tests/036-finalizer/src/Main.java
@@ -0,0 +1,107 @@
+// Copyright 2008 The Android Open Source Project
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Some finalizer tests.
+ *
+ * This only works if System.runFinalization() causes finalizers to run
+ * immediately or very soon.
+ */
+public class Main {
+    private static void snooze(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException ie) {
+            System.out.println("Snooze: " + ie.getMessage());
+        }
+    }
+
+    public static WeakReference makeRef() {
+        /*
+         * Make ft in another thread, so there is no danger of
+         * a conservative reference leaking onto the main thread's
+         * stack.
+         */
+
+        final WeakReference[] wimp = new WeakReference[1];
+        Thread t = new Thread() {
+                public void run() {
+                    FinalizerTest ft = new FinalizerTest("wahoo");
+                    wimp[0] = new WeakReference(ft);
+                    ft = null;
+                }
+            };
+
+        t.start();
+
+        try {
+            t.join();
+        } catch (InterruptedException ie) {
+            throw new RuntimeException(ie);
+        }
+
+        return wimp[0];
+    }
+
+    public static String wimpString(final WeakReference wimp) {
+        /*
+         * Do the work in another thread, so there is no danger of a
+         * conservative reference to ft leaking onto the main thread's
+         * stack.
+         */
+
+        final String[] s = new String[1];
+        Thread t = new Thread() {
+                public void run() {
+                    Object ref = wimp.get();
+                    if (ref != null) {
+                        s[0] = ref.toString();
+                    }
+                }
+            };
+
+        t.start();
+
+        try {
+            t.join();
+        } catch (InterruptedException ie) {
+            throw new RuntimeException(ie);
+        }
+
+        return s[0];
+    }
+
+    public static void main(String[] args) {
+        WeakReference wimp = makeRef();
+
+        System.out.println("wimp: " + wimpString(wimp));
+
+        /* this will try to collect and finalize ft */
+        System.out.println("gc");
+        System.gc();
+
+        System.out.println("wimp: " + wimpString(wimp));
+        System.out.println("finalize");
+        System.runFinalization();
+        System.out.println("wimp: " + wimpString(wimp));
+
+        System.out.println("sleep");
+        snooze(1000);
+
+        System.out.println("reborn: " + FinalizerTest.mReborn);
+        System.out.println("wimp: " + wimpString(wimp));
+        System.out.println("reset reborn");
+        System.gc();
+        FinalizerTest.mReborn = FinalizerTest.mNothing;
+        System.out.println("gc + finalize");
+        System.gc();
+        System.runFinalization();
+
+        System.out.println("sleep");
+        snooze(1000);
+
+        System.out.println("reborn: " + FinalizerTest.mReborn);
+        System.out.println("wimp: " + wimpString(wimp));
+    }
+}
diff --git a/tests/037-inherit/expected.txt b/tests/037-inherit/expected.txt
new file mode 100644
index 0000000..1fb9912
--- /dev/null
+++ b/tests/037-inherit/expected.txt
@@ -0,0 +1,3 @@
+magic is 64.0
+ 0: 64.0
+ 1: 64.0
diff --git a/tests/037-inherit/info.txt b/tests/037-inherit/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/037-inherit/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/037-inherit/src/Main.java b/tests/037-inherit/src/Main.java
new file mode 100644
index 0000000..55b782e
--- /dev/null
+++ b/tests/037-inherit/src/Main.java
@@ -0,0 +1,37 @@
+public class Main {
+    static void arrayCluster(IMagic[] magicArray) {
+        int i;
+
+        for (i = 0; i < magicArray.length; i++)
+            System.out.println(" " + i + ": " + magicArray[i].getSomeData());
+    }
+
+    public static void main(String args[]) {
+        MagicClass magic = new MagicClass();
+
+        System.out.print("magic is ");
+        System.out.println(magic.getSomeData());
+
+        MagicClass magicArray[] = new MagicClass[2];
+        magicArray[0] = new MagicClass();
+        magicArray[1] = new MagicClass();
+        arrayCluster(magicArray);
+    }
+}
+
+class IntSource {
+    public int getMagicInt() { return 64; }
+}
+
+interface IMagic {
+    public double getSomeData();
+
+    IntSource mIntSource = new IntSource();
+    public int MAGIC_INT = mIntSource.getMagicInt();
+}
+
+class MagicClass implements IMagic {
+    public double getSomeData() {
+        return this.MAGIC_INT;
+    }
+}
diff --git a/tests/038-inner-null/expected.txt b/tests/038-inner-null/expected.txt
new file mode 100644
index 0000000..0be8ffd
--- /dev/null
+++ b/tests/038-inner-null/expected.txt
@@ -0,0 +1,5 @@
+new Special()
+java.lang.NullPointerException
+	at Main$Special.callInner(Main.java:17)
+	at Main.main(Main.java:6)
+	at dalvik.system.NativeStart.main(Native Method)
diff --git a/tests/038-inner-null/info.txt b/tests/038-inner-null/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/038-inner-null/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/038-inner-null/src/Main.java b/tests/038-inner-null/src/Main.java
new file mode 100644
index 0000000..acc8764
--- /dev/null
+++ b/tests/038-inner-null/src/Main.java
@@ -0,0 +1,27 @@
+// Copyright 2008 The Android Open Source Project
+
+public class Main {
+    public static void main(String[] args) {
+        Special special = new Special();
+        special.callInner();
+    }
+
+    public static class Special {
+        Blort mBlort = null;
+
+        Special() {
+            System.out.println("new Special()");
+        }
+
+        public void callInner() {
+            mBlort.repaint();
+        }
+    }
+
+    private class Blort {
+        public void repaint() {
+            System.out.println("shouldn't see this");
+        }
+    }
+
+}
diff --git a/tests/039-join-main/expected.txt b/tests/039-join-main/expected.txt
new file mode 100644
index 0000000..37e6d77
--- /dev/null
+++ b/tests/039-join-main/expected.txt
@@ -0,0 +1,5 @@
+Starting thread 'Joiner'
+@ JoinMainSub running
+JoinMain starter returning
+@ JoinMainSub successfully joined main
+@ JoinMainSub bailing
diff --git a/tests/039-join-main/info.txt b/tests/039-join-main/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/039-join-main/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/039-join-main/src/Main.java b/tests/039-join-main/src/Main.java
new file mode 100644
index 0000000..0644f1c
--- /dev/null
+++ b/tests/039-join-main/src/Main.java
@@ -0,0 +1,41 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Make sure that a sub-thread can join the main thread.
+ */
+public class Main {
+    public static void main(String[] args) {
+        Thread t;
+
+        t = new Thread(new JoinMainSub(Thread.currentThread()), "Joiner");
+        System.out.print("Starting thread '" + t.getName() + "'\n");
+        t.start();
+
+        try { Thread.sleep(1000); }
+        catch (InterruptedException ie) {}
+
+        System.out.print("JoinMain starter returning\n");
+    }
+}
+
+class JoinMainSub implements Runnable {
+    private Thread mJoinMe;
+
+    public JoinMainSub(Thread joinMe) {
+        mJoinMe = joinMe;
+    }
+
+    public void run() {
+        System.out.print("@ JoinMainSub running\n");
+
+        try {
+            mJoinMe.join();
+            System.out.print("@ JoinMainSub successfully joined main\n");
+        } catch (InterruptedException ie) {
+            System.out.print("@ JoinMainSub interrupted!\n");
+        }
+        finally {
+            System.out.print("@ JoinMainSub bailing\n");
+        }
+    }
+}
diff --git a/tests/040-miranda/expected.txt b/tests/040-miranda/expected.txt
new file mode 100644
index 0000000..e22bbd9
--- /dev/null
+++ b/tests/040-miranda/expected.txt
@@ -0,0 +1,12 @@
+MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+MirandaAbstract / MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+MirandaAbstract / MirandaClass2:
+  inInterface:  true
+  inInterface2: 28
+  inAbstract:   true
diff --git a/tests/040-miranda/info.txt b/tests/040-miranda/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/040-miranda/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/040-miranda/src/Main.java b/tests/040-miranda/src/Main.java
new file mode 100644
index 0000000..558806a
--- /dev/null
+++ b/tests/040-miranda/src/Main.java
@@ -0,0 +1,27 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Miranda testing.
+ */
+public class Main {
+    public static void main(String[] args) {
+        MirandaClass mir = new MirandaClass();
+        System.out.println("MirandaClass:");
+        System.out.println("  inInterface:  " + mir.inInterface());
+        System.out.println("  inInterface2: " + mir.inInterface2());
+        System.out.println("  inAbstract:   " + mir.inAbstract());
+
+        /* try again through abstract class; results should be identical */
+        MirandaAbstract mira = mir;
+        System.out.println("MirandaAbstract / MirandaClass:");
+        System.out.println("  inInterface:  " + mira.inInterface());
+        System.out.println("  inInterface2: " + mira.inInterface2());
+        System.out.println("  inAbstract:   " + mira.inAbstract());
+
+        MirandaAbstract mira2 = new MirandaClass2();
+        System.out.println("MirandaAbstract / MirandaClass2:");
+        System.out.println("  inInterface:  " + mira2.inInterface());
+        System.out.println("  inInterface2: " + mira2.inInterface2());
+        System.out.println("  inAbstract:   " + mira2.inAbstract());
+    }
+}
diff --git a/tests/040-miranda/src/MirandaAbstract.java b/tests/040-miranda/src/MirandaAbstract.java
new file mode 100644
index 0000000..b603ce6
--- /dev/null
+++ b/tests/040-miranda/src/MirandaAbstract.java
@@ -0,0 +1,16 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Miranda testing.
+ */
+public abstract class MirandaAbstract implements MirandaInterface, MirandaInterface2
+{
+    protected MirandaAbstract() { }
+
+    //public abstract boolean inInterface();
+    //public abstract int inInterface2();
+
+    public boolean inAbstract() {
+        return true;
+    }
+}
diff --git a/tests/040-miranda/src/MirandaClass.java b/tests/040-miranda/src/MirandaClass.java
new file mode 100644
index 0000000..3bf6704
--- /dev/null
+++ b/tests/040-miranda/src/MirandaClass.java
@@ -0,0 +1,24 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Miranda testing.
+ */
+public class MirandaClass extends MirandaAbstract {
+
+    public MirandaClass() {}
+
+    public boolean inInterface() {
+        //System.out.println("    MirandaClass inInterface");
+        return true;
+    }
+
+    public int inInterface2() {
+        //System.out.println("    MirandaClass inInterface2");
+        return 27;
+    }
+
+    public boolean inAbstract() {
+        //System.out.println("    MirandaClass inAbstract");
+        return false;
+    }
+}
diff --git a/tests/040-miranda/src/MirandaClass2.java b/tests/040-miranda/src/MirandaClass2.java
new file mode 100644
index 0000000..e9bdf2b
--- /dev/null
+++ b/tests/040-miranda/src/MirandaClass2.java
@@ -0,0 +1,9 @@
+class MirandaClass2 extends MirandaAbstract {
+    public boolean inInterface() {
+        return true;
+    }
+
+    public int inInterface2() {
+        return 28;
+    }
+}
diff --git a/tests/040-miranda/src/MirandaInterface.java b/tests/040-miranda/src/MirandaInterface.java
new file mode 100644
index 0000000..2c0a59a
--- /dev/null
+++ b/tests/040-miranda/src/MirandaInterface.java
@@ -0,0 +1,10 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Miranda testing.
+ */
+public interface MirandaInterface {
+
+    public boolean inInterface();
+
+}
diff --git a/tests/040-miranda/src/MirandaInterface2.java b/tests/040-miranda/src/MirandaInterface2.java
new file mode 100644
index 0000000..83b6af8
--- /dev/null
+++ b/tests/040-miranda/src/MirandaInterface2.java
@@ -0,0 +1,12 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Miranda testing.
+ */
+public interface MirandaInterface2 {
+
+    public boolean inInterface();
+
+    public int inInterface2();
+
+}
diff --git a/tests/041-narrowing/expected.txt b/tests/041-narrowing/expected.txt
new file mode 100644
index 0000000..93b8590
--- /dev/null
+++ b/tests/041-narrowing/expected.txt
@@ -0,0 +1,38 @@
+
+Double.POSITIVE_INFINITY = 7ff0000000000000
+Double.NEGATIVE_INFINITY = fff0000000000000
+Float.POSITIVE_INFINITY  = 7ff0000000000000
+Float.NEGATIVE_INFINITY  = fff0000000000000
+Double.NaN               = 7ff8000000000000
+Float.NaN                = 7ff8000000000000
+
+(byte) Double.NaN  =               00 expected:               00
+(short) Double.NaN =             0000 expected:             0000
+(int) Double.NaN   =         00000000 expected:         00000000
+(long) Double.NaN  = 0000000000000000 expected: 0000000000000000
+
+(byte) Float.NaN  =               00 expected:               00
+(short) Float.NaN =             0000 expected:             0000
+(int) Float.NaN   =         00000000 expected:         00000000
+(long) Float.NaN  = 0000000000000000 expected: 0000000000000000
+
+(byte) Double.POSITIVE_INFINITY  =               ff expected:               ff
+(short) Double.POSITIVE_INFINITY =             ffff expected:             ffff
+(int) Double.POSITIVE_INFINITY   =         7fffffff expected:         7fffffff
+(long) Double.POSITIVE_INFINITY  = 7fffffffffffffff expected: 7fffffffffffffff
+
+(byte) Double.NEGATIVE_INFINITY  =               00 expected:               00
+(short) Double.NEGATIVE_INFINITY =             0000 expected:             0000
+(int) Double.NEGATIVE_INFINITY   =         80000000 expected:         80000000
+(long) Double.NEGATIVE_INFINITY  = 8000000000000000 expected: 8000000000000000
+
+(byte) Float.POSITIVE_INFINITY   =               ff expected:               ff
+(short) Float.POSITIVE_INFINITY  =             ffff expected:             ffff
+(int) Float.POSITIVE_INFINITY    =         7fffffff expected:         7fffffff
+(long) Float.POSITIVE_INFINITY   = 7fffffffffffffff expected: 7fffffffffffffff
+
+(byte) Float.NEGATIVE_INFINITY   =               00 expected:               00
+(short) Float.NEGATIVE_INFINITY  =             0000 expected:             0000
+(int) Float.NEGATIVE_INFINITY    =         80000000 expected:         80000000
+(long) Float.NEGATIVE_INFINITY   = 8000000000000000 expected: 8000000000000000
+
diff --git a/tests/041-narrowing/info.txt b/tests/041-narrowing/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/041-narrowing/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/041-narrowing/src/Main.java b/tests/041-narrowing/src/Main.java
new file mode 100644
index 0000000..eb9d64a
--- /dev/null
+++ b/tests/041-narrowing/src/Main.java
@@ -0,0 +1,99 @@
+public class Main {
+    public static void main(String[] args) {
+        test_printNarrowing();
+    }
+
+    public static void test_printNarrowing() {
+
+        System.out.println();
+        System.out.println("Double.POSITIVE_INFINITY = "
+                + Long.toHexString(Double.doubleToRawLongBits(Double.POSITIVE_INFINITY)));
+        System.out.println("Double.NEGATIVE_INFINITY = "
+                + Long.toHexString(Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY)));
+        System.out.println("Float.POSITIVE_INFINITY  = "
+                + Long.toHexString(Double.doubleToRawLongBits(Float.POSITIVE_INFINITY)));
+        System.out.println("Float.NEGATIVE_INFINITY  = "
+                + Long.toHexString(Double.doubleToRawLongBits(Float.NEGATIVE_INFINITY)));
+        System.out.println("Double.NaN               = "
+                + Long.toHexString(Double.doubleToRawLongBits(Double.NaN)));
+        System.out.println("Float.NaN                = "
+                + Long.toHexString(Double.doubleToRawLongBits(Float.NaN)));
+        double dbl2 = Double.NaN;
+        System.out.println();
+        System.out.println("(byte) Double.NaN  =               "
+                + (Long.toHexString((byte)dbl2).equals("0") ? "00" : Long.toHexString((byte)dbl2)
+                        .substring(6)) + " expected:               00");
+        System.out.println("(short) Double.NaN =             "
+                + (Integer.toHexString((short)dbl2).equals("0") ? "0000" : Integer.toHexString(
+                        (short)dbl2).substring(4)) + " expected:             0000");
+        System.out.println("(int) Double.NaN   =         "
+                + (Integer.toHexString((int)dbl2).equals("0") ? "00000000" : Integer
+                        .toHexString((int)dbl2)) + " expected:         00000000");
+        System.out.println("(long) Double.NaN  = "
+                + (Long.toHexString((long)dbl2).equals("0") ? "0000000000000000" : Long
+                        .toHexString((long)dbl2)) + " expected: 0000000000000000");
+        float fl2 = Float.NaN;
+        System.out.println();
+        System.out.println("(byte) Float.NaN  =               "
+                + (Long.toHexString((byte)fl2).equals("0") ? "00" : Long.toHexString((byte)fl2)
+                        .substring(6)) + " expected:               00");
+        System.out.println("(short) Float.NaN =             "
+                + (Integer.toHexString((short)fl2).equals("0") ? "0000" : Integer.toHexString(
+                        (short)fl2).substring(4)) + " expected:             0000");
+        System.out.println("(int) Float.NaN   =         "
+                + (Integer.toHexString((int)fl2).equals("0") ? "00000000" : Integer
+                        .toHexString((int)fl2)) + " expected:         00000000");
+        System.out.println("(long) Float.NaN  = "
+                + (Long.toHexString((long)fl2).equals("0") ? "0000000000000000" : Long
+                        .toHexString((long)fl2)) + " expected: 0000000000000000");
+        double dbl3 = Double.POSITIVE_INFINITY;
+        System.out.println();
+        System.out.println("(byte) Double.POSITIVE_INFINITY  =               "
+                + (Integer.toHexString((byte)dbl3).equals("0") ? "00" : Integer.toHexString(
+                        (byte)dbl3).substring(6)) + " expected:               ff");
+        System.out.println("(short) Double.POSITIVE_INFINITY =             "
+                + (Integer.toHexString((short)dbl3).equals("0") ? "0000" : Integer.toHexString(
+                        (short)dbl3).substring(4)) + " expected:             ffff");
+        System.out.println("(int) Double.POSITIVE_INFINITY   =         "
+                + Integer.toHexString((int)dbl3) + " expected:         7fffffff");
+        System.out.println("(long) Double.POSITIVE_INFINITY  = " + Long.toHexString((long)dbl3)
+                + " expected: 7fffffffffffffff");
+        double dbl4 = Double.NEGATIVE_INFINITY;
+        System.out.println();
+        System.out.println("(byte) Double.NEGATIVE_INFINITY  = "
+                + (Long.toHexString((byte)dbl4).equals("0") ? "              00" : Long
+                        .toHexString((byte)dbl4)) + " expected:               00");
+        System.out.println("(short) Double.NEGATIVE_INFINITY = "
+                + (Integer.toHexString((short)dbl4).equals("0") ? "            0000" : Long
+                        .toHexString((short)dbl4)) + " expected:             0000");
+        System.out.println("(int) Double.NEGATIVE_INFINITY   =         "
+                + Integer.toHexString((int)dbl4) + " expected:         80000000");
+        System.out.println("(long) Double.NEGATIVE_INFINITY  = " + Long.toHexString((long)dbl4)
+                + " expected: 8000000000000000");
+        float fl3 = Float.POSITIVE_INFINITY;
+        System.out.println();
+        System.out.println("(byte) Float.POSITIVE_INFINITY   =               "
+                + (Integer.toHexString((byte)fl3).equals("0") ? "00" : Integer.toHexString(
+                        (byte)fl3).substring(6)) + " expected:               ff");
+        System.out.println("(short) Float.POSITIVE_INFINITY  =             "
+                + (Integer.toHexString((short)fl3).equals("0") ? "0000" : Integer.toHexString(
+                        (short)fl3).substring(4)) + " expected:             ffff");
+        System.out.println("(int) Float.POSITIVE_INFINITY    =         "
+                + Integer.toHexString((int)fl3) + " expected:         7fffffff");
+        System.out.println("(long) Float.POSITIVE_INFINITY   = " + Long.toHexString((long)fl3)
+                + " expected: 7fffffffffffffff");
+        float fl4 = Float.NEGATIVE_INFINITY;
+        System.out.println();
+        System.out.println("(byte) Float.NEGATIVE_INFINITY   = "
+                + (Long.toHexString((byte)fl4).equals("0") ? "              00" : Long
+                        .toHexString((byte)fl4)) + " expected:               00");
+        System.out.println("(short) Float.NEGATIVE_INFINITY  = "
+                + (Integer.toHexString((short)fl4).equals("0") ? "            0000" : Long
+                        .toHexString((short)fl4)) + " expected:             0000");
+        System.out.println("(int) Float.NEGATIVE_INFINITY    =         "
+                + Integer.toHexString((int)fl4) + " expected:         80000000");
+        System.out.println("(long) Float.NEGATIVE_INFINITY   = " + Long.toHexString((long)fl4)
+                + " expected: 8000000000000000");
+        System.out.println();
+    }
+}
diff --git a/tests/042-new-instance/expected.txt b/tests/042-new-instance/expected.txt
new file mode 100644
index 0000000..53447db
--- /dev/null
+++ b/tests/042-new-instance/expected.txt
@@ -0,0 +1,8 @@
+LocalClass succeeded
+Got expected PackageAccess complaint
+LocalClass3 succeeded
+Got expected InstantationError
+Cons LocalClass failed as expected
+Cons LocalClass2 succeeded
+Cons got expected PackageAccess complaint
+Cons got expected InstantationException
diff --git a/tests/042-new-instance/info.txt b/tests/042-new-instance/info.txt
new file mode 100644
index 0000000..49c9e02
--- /dev/null
+++ b/tests/042-new-instance/info.txt
@@ -0,0 +1,2 @@
+Test various permutations of Class.newInstance and Constructor.newInstance,
+looking for correct handling of access rights and abstract classes.
diff --git a/tests/042-new-instance/src/Main.java b/tests/042-new-instance/src/Main.java
new file mode 100644
index 0000000..8faef13
--- /dev/null
+++ b/tests/042-new-instance/src/Main.java
@@ -0,0 +1,156 @@
+/*
+ * 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;
+
+/**
+ * Test instance creation.
+ */
+public class Main {
+    public static void main(String[] args) {
+        testClassNewInstance();
+        testConstructorNewInstance();
+    }
+
+    /**
+     * Tests Class.newInstance().
+     */
+    static void testClassNewInstance() {
+        // should succeed
+        try {
+            Class c = Class.forName("LocalClass");
+            Object obj = c.newInstance();
+            System.out.println("LocalClass succeeded");
+        } catch (Exception ex) {
+            System.err.println("LocalClass failed");
+            ex.printStackTrace();
+        }
+
+        // should fail
+        try {
+            Class c = Class.forName("otherpackage.PackageAccess");
+            Object obj = c.newInstance();
+            System.err.println("ERROR: PackageAccess succeeded unexpectedly");
+        } catch (IllegalAccessException iae) {
+            System.out.println("Got expected PackageAccess complaint");
+        } catch (Exception ex) {
+            System.err.println("Got unexpected PackageAccess failure");
+            ex.printStackTrace();
+        }
+
+        LocalClass3.main();
+
+        try {
+            MaybeAbstract ma = new MaybeAbstract();
+            System.err.println("ERROR: MaybeAbstract succeeded unexpectedly");
+        } catch (InstantiationError ie) {
+            System.out.println("Got expected InstantationError");
+        } catch (Exception ex) {
+            System.err.println("Got unexpected MaybeAbstract failure");
+        }
+    }
+
+    /**
+     * Tests Constructor.newInstance().
+     */
+    static void testConstructorNewInstance() {
+        // should fail -- getConstructor only returns public constructors
+        try {
+            Class c = Class.forName("LocalClass");
+            Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+            System.err.println("Cons LocalClass succeeded unexpectedly");
+        } catch (NoSuchMethodException nsme) {
+            System.out.println("Cons LocalClass failed as expected");
+        } catch (Exception ex) {
+            System.err.println("Cons LocalClass failed strangely");
+            ex.printStackTrace();
+        }
+
+        // should succeed
+        try {
+            Class c = Class.forName("LocalClass2");
+            Constructor cons = c.getConstructor((Class[]) null);
+            Object obj = cons.newInstance();
+            System.out.println("Cons LocalClass2 succeeded");
+        } catch (Exception ex) {
+            System.err.println("Cons LocalClass2 failed");
+            ex.printStackTrace();
+        }
+
+        // should fail
+        try {
+            Class c = Class.forName("otherpackage.PackageAccess");
+            Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+            System.err.println("ERROR: Cons PackageAccess succeeded unexpectedly");
+        } catch (NoSuchMethodException nsme) {
+            System.out.println("Cons got expected PackageAccess complaint");
+        } catch (Exception ex) {
+            System.err.println("Cons got unexpected PackageAccess failure");
+            ex.printStackTrace();
+        }
+
+        // should fail
+        try {
+            Class c = Class.forName("MaybeAbstract");
+            Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+            Object obj = cons.newInstance();
+            System.err.println("ERROR: Cons MaybeAbstract succeeded unexpectedly");
+        } catch (InstantiationException ie) {
+            // note InstantiationException vs. InstantiationError
+            System.out.println("Cons got expected InstantationException");
+        } catch (Exception ex) {
+            System.err.println("Cons got unexpected MaybeAbstract failure");
+            ex.printStackTrace();
+        }
+    }
+}
+
+class LocalClass {
+    // this class has a default constructor with package visibility
+}
+
+class LocalClass2 {
+    public LocalClass2() {}
+}
+
+
+class LocalClass3 {
+    public static void main() {
+        try {
+            CC.newInstance();
+            System.out.println("LocalClass3 succeeded");
+        } catch (Exception ex) {
+            System.err.println("Got unexpected LocalClass3 failure");
+            ex.printStackTrace();
+        }
+    }
+
+    static class CC {
+        private CC() {}
+
+        static Object newInstance() {
+            try {
+                Class c = CC.class;
+                return c.newInstance();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                return null;
+            }
+        }
+    }
+}
diff --git a/tests/042-new-instance/src/MaybeAbstract.java b/tests/042-new-instance/src/MaybeAbstract.java
new file mode 100644
index 0000000..6d3b05b
--- /dev/null
+++ b/tests/042-new-instance/src/MaybeAbstract.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 /*abstract*/ class MaybeAbstract {
+    public MaybeAbstract() {}
+    int foo() { return 0; }
+}
diff --git a/tests/042-new-instance/src/otherpackage/PackageAccess.java b/tests/042-new-instance/src/otherpackage/PackageAccess.java
new file mode 100644
index 0000000..0749d67
--- /dev/null
+++ b/tests/042-new-instance/src/otherpackage/PackageAccess.java
@@ -0,0 +1,6 @@
+package otherpackage;
+
+class PackageAccess {
+    /*package*/ PackageAccess() {
+    }
+}
diff --git a/tests/042-new-instance/src2/MaybeAbstract.java b/tests/042-new-instance/src2/MaybeAbstract.java
new file mode 100644
index 0000000..8b70a07
--- /dev/null
+++ b/tests/042-new-instance/src2/MaybeAbstract.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 abstract class MaybeAbstract {
+    public MaybeAbstract() {}
+    int foo() { return 0; }
+}
diff --git a/tests/043-privates/expected.txt b/tests/043-privates/expected.txt
new file mode 100644
index 0000000..2779ec7
--- /dev/null
+++ b/tests/043-privates/expected.txt
@@ -0,0 +1,6 @@
+PrivatePackage --> PrivatePackage!
+PrivatePackage --> PrivatePackage!
+PrivatePackage --> PrivatePackage!
+PrivatePackageSub --> PrivatePackageSub!
+PrivatePackage --> PrivatePackage!
+PrivatePackage --> PrivatePackage!
diff --git a/tests/043-privates/info.txt b/tests/043-privates/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/043-privates/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/043-privates/src/Main.java b/tests/043-privates/src/Main.java
new file mode 100644
index 0000000..73b4d79
--- /dev/null
+++ b/tests/043-privates/src/Main.java
@@ -0,0 +1,45 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Make sure private methods don't inherit.
+ */
+public class Main {
+    public static void main(String args[]) {
+        PrivatePackage inst1 = new PrivatePackage();
+        PrivatePackage inst2 = new PrivatePackageSub();
+        PrivatePackageSub inst3 = new PrivatePackageSub();
+
+        System.out.println("PrivatePackage --> " + inst1.getStr());
+        System.out.println("PrivatePackage --> " + inst2.getStr());
+        System.out.println("PrivatePackage --> " + inst3.getStr());
+        System.out.println("PrivatePackageSub --> " + inst3.getStrSub());
+
+        inst1.stretchTest();
+    }
+}
+
+class PrivatePackage {
+    public String getStr() {
+        return privGetStr();
+    }
+
+    private String privGetStr() {
+        return "PrivatePackage!";
+    }
+
+    public void stretchTest() {
+        PrivatePackage inst = new PrivatePackageSub();
+        System.out.println("PrivatePackage --> " + inst.getStr());
+        System.out.println("PrivatePackage --> " + inst.privGetStr());
+    }
+}
+
+class PrivatePackageSub extends PrivatePackage {
+    public String getStrSub() {
+        return privGetStr();
+    }
+
+    private String privGetStr() {
+        return "PrivatePackageSub!";
+    }
+}
diff --git a/tests/044-proxy/expected.txt b/tests/044-proxy/expected.txt
new file mode 100644
index 0000000..4be26cf
--- /dev/null
+++ b/tests/044-proxy/expected.txt
@@ -0,0 +1,80 @@
+Invoke public abstract void Shapes.circle(int)
+ 0: 3
+--- circle 3
+Success: method circle res=null
+Invoke public abstract int Quads.rectangle(int,int)
+ 0: 10
+ 1: 20
+--- rectangle 10,20
+Success: method rectangle res=4
+Invoke public abstract java.lang.String Shapes.blob()
+ (no args)
+--- blob
+Success: method blob res=mix
+Invoke public abstract int Quads.rectangle(int,int)
+ 0: 15
+ 1: 25
+--- rectangle 15,25
+Success: method rectangle res=4
+Invoke public abstract int Quads.trapezoid(int,double,int)
+ 0: 6
+ 1: 81.18
+ 2: 4
+--- trap 6,4,81.18
+Success: method trapezoid res=8
+Invoke public abstract int Colors.red(float)
+ 0: 1.0
+--- red 1.0
+Success: method red res=0
+Invoke public abstract double Colors.blue(int)
+ 0: 777
+--- blue 777
+Success: method blue res=2.54
+Invoke public abstract int Colors.mauve(java.lang.String)
+ 0: sorry
+--- mauve sorry
+Success: method mauve res=3
+Invoke public abstract java.lang.String Shapes.blob()
+ (no args)
+--- blob
+Success: method blob res=mix
+Invoke public abstract void Shapes.upChuck()
+ (no args)
+Got expected ioobe
+Invoke public abstract void Shapes.upCheck() throws java.lang.InterruptedException
+ (no args)
+Got expected ie
+
+Proxy methods: [public native boolean $Proxy0.equals(java.lang.Object), public native int $Proxy0.hashCode(), public native java.lang.String $Proxy0.toString(), public native int $Proxy0.rectangle(int,int), public native int $Proxy0.square(int,int), public native int $Proxy0.trapezoid(int,double,int), public native java.lang.String $Proxy0.blob(), public native void $Proxy0.circle(int), public native void $Proxy0.upCheck(), public native void $Proxy0.upChuck(), public native double $Proxy0.blue(int), public native R0aa $Proxy0.checkMe(), public native int $Proxy0.green(double), public native int $Proxy0.mauve(java.lang.String), public native int $Proxy0.red(float)]
+Decl annos: []
+Param annos (1) : [[]]
+Proxy fields: [private static java.lang.Throwable[][] $Proxy0.throws]
+Dupe threw expected exception
+Clash threw expected exception
+Clash2 threw expected exception
+Clash3 threw expected exception
+Clash4 threw expected exception
+Invoke public abstract void InterfaceW1.throwFunky()
+ (no args)
+Got expected UTE
+Invoke public abstract void InterfaceW1.throwFunky2() throws BaseException,java.lang.NoSuchMethodException,java.io.IOException
+ (no args)
+Got expected IOE
+Invoke public abstract void InterfaceW1.throwFunky2() throws BaseException,java.lang.NoSuchMethodException,java.io.IOException
+ (no args)
+Got expected IOE
+Invoke public abstract void InterfaceW1.throwException() throws BaseException
+ (no args)
+Got expected UTE
+Invoke public abstract void InterfaceW1.throwBase() throws BaseException
+ (no args)
+Got expected UTE
+Invoke public abstract void InterfaceW1.throwSub() throws BaseException
+ (no args)
+Got expected exception
+Invoke public abstract void InterfaceW1.throwSubSub() throws BaseException
+ (no args)
+Got expected exception
+Invoke public abstract void InterfaceW1.bothThrowBase() throws BaseException,SubException,SubSubException
+ (no args)
+Got expected exception
diff --git a/tests/044-proxy/info.txt b/tests/044-proxy/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/044-proxy/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/044-proxy/src/BasicTest.java b/tests/044-proxy/src/BasicTest.java
new file mode 100644
index 0000000..2a453c4
--- /dev/null
+++ b/tests/044-proxy/src/BasicTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+
+/**
+ * Do some basic tests.
+ */
+public class BasicTest {
+
+    public static void main(String[] args) {
+        Mix proxyMe = new Mix();
+        Object proxy = createProxy(proxyMe);
+
+        if (!Proxy.isProxyClass(proxy.getClass()))
+            System.err.println("not a proxy class?");
+        if (Proxy.getInvocationHandler(proxy) == null)
+            System.err.println("ERROR: Proxy.getInvocationHandler is null");
+
+        /* take it for a spin; verifies instanceof constraint */
+        Shapes shapes = (Shapes) proxy;
+        shapes.circle(3);
+        shapes.rectangle(10, 20);
+        shapes.blob();
+        Quads quads = (Quads) proxy;
+        quads.rectangle(15, 25);
+        quads.trapezoid(6, 81.18, 4);
+        Colors colors = (Colors) proxy;
+        colors.red(1.0f);
+        colors.blue(777);
+        colors.mauve("sorry");
+        colors.blob();
+
+        try {
+            shapes.upChuck();
+            System.out.println("Didn't get expected exception");
+        } catch (IndexOutOfBoundsException ioobe) {
+            System.out.println("Got expected ioobe");
+        }
+        try {
+            shapes.upCheck();
+            System.out.println("Didn't get expected exception");
+        } catch (InterruptedException ie) {
+            System.out.println("Got expected ie");
+        }
+
+        /*
+         * Exercise annotations on Proxy classes.  This is mostly to ensure
+         * that annotation calls work correctly on generated classes.
+         */
+        System.out.println("");
+        Method[] methods = proxy.getClass().getDeclaredMethods();
+        System.out.println("Proxy methods: " + Arrays.deepToString(methods));
+        Method meth = methods[methods.length -1];
+        System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations()));
+        Annotation[][] paramAnnos = meth.getParameterAnnotations();
+        System.out.println("Param annos (" + paramAnnos.length + ") : "
+            + Arrays.deepToString(paramAnnos));
+        Field[] fields = proxy.getClass().getDeclaredFields();
+        System.out.println("Proxy fields: " + Arrays.deepToString(fields));
+    }
+
+    static Object createProxy(Object proxyMe) {
+        /* declare an object that will handle the method calls */
+        InvocationHandler handler = new MyInvocationHandler(proxyMe);
+
+        /* create the proxy class */
+        Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
+                            new Class[] { Quads.class, Colors.class });
+
+        /* create a proxy object, passing the handler object in */
+        Object proxy = null;
+        try {
+            Constructor<Class> cons;
+            cons = proxyClass.getConstructor(
+                            new Class[] { InvocationHandler.class });
+            //System.out.println("Constructor is " + cons);
+            proxy = cons.newInstance(new Object[] { handler });
+        } catch (NoSuchMethodException nsme) {
+            System.err.println("failed: " + nsme);
+        } catch (InstantiationException ie) {
+            System.err.println("failed: " + ie);
+        } catch (IllegalAccessException ie) {
+            System.err.println("failed: " + ie);
+        } catch (InvocationTargetException ite) {
+            System.err.println("failed: " + ite);
+        }
+
+        return proxy;
+    }
+}
+
+/*
+ * Some interfaces.
+ */
+interface Shapes {
+    public void circle(int r);
+    public int rectangle(int x, int y);
+
+    public String blob();
+
+    public R0base checkMe();
+    public void upChuck();
+    public void upCheck() throws InterruptedException;
+}
+
+interface Quads extends Shapes {
+    public int rectangle(int x, int y);
+    public int square(int x, int y);
+    public int trapezoid(int x, double off, int y);
+
+    public R0a checkMe();
+}
+
+/*
+ * More interfaces.
+ */
+interface Colors {
+    public int red(float howRed);
+    public int green(double howGreen);
+    public double blue(int howBlue);
+    public int mauve(String apology);
+
+    public String blob();
+
+    public R0aa checkMe();
+}
+
+/*
+ * Some return types.
+ */
+class R0base { int mBlah;  }
+class R0a extends R0base { int mBlah_a;  }
+class R0aa extends R0a { int mBlah_aa;  }
+
+
+/*
+ * A class that implements them all.
+ */
+class Mix implements Quads, Colors {
+    public void circle(int r) {
+        System.out.println("--- circle " + r);
+    }
+    public int rectangle(int x, int y) {
+        System.out.println("--- rectangle " + x + "," + y);
+        return 4;
+    }
+    public int square(int x, int y) {
+        System.out.println("--- square " + x + "," + y);
+        return 4;
+    }
+    public int trapezoid(int x, double off, int y) {
+        System.out.println("--- trap " + x + "," + y + "," + off);
+        return 8;
+    }
+    public String blob() {
+        System.out.println("--- blob");
+        return "mix";
+    }
+
+    public int red(float howRed) {
+        System.out.println("--- red " + howRed);
+        return 0;
+    }
+    public int green(double howGreen) {
+        System.out.println("--- green " + howGreen);
+        return 1;
+    }
+    public double blue(int howBlue) {
+        System.out.println("--- blue " + howBlue);
+        return 2.54;
+    }
+    public int mauve(String apology) {
+        System.out.println("--- mauve " + apology);
+        return 3;
+    }
+
+    public R0aa checkMe() {
+        return null;
+    }
+    public void upChuck() {
+        throw new IndexOutOfBoundsException("upchuck");
+    }
+    public void upCheck() throws InterruptedException {
+        throw new InterruptedException("upcheck");
+    }
+}
+
+/*
+ * Invocation handler, defining the implementation of the proxy functions.
+ */
+class MyInvocationHandler implements InvocationHandler {
+    Object mObj;
+
+    public MyInvocationHandler(Object obj) {
+        mObj = obj;
+    }
+
+    /*
+     * This is called when anything gets invoked in the proxy object.
+     */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+
+        Object result = null;
+
+        // Trap Object calls.  This is important here to avoid a recursive
+        // invocation of toString() in the print statements below.
+        if (method.getDeclaringClass() == java.lang.Object.class) {
+            //System.out.println("!!! object " + method.getName());
+            if (method.getName().equals("toString"))
+                return super.toString();
+            else if (method.getName().equals("hashCode"))
+                return Integer.valueOf(super.hashCode());
+            else if (method.getName().equals("equals"))
+                return Boolean.valueOf(super.equals(args[0]));
+            else
+                throw new RuntimeException("huh?");
+        }
+
+        System.out.println("Invoke " + method);
+        if (args == null || args.length == 0) {
+            System.out.println(" (no args)");
+        } else {
+            for (int i = 0; i < args.length; i++)
+                System.out.println(" " + i + ": " + args[i]);
+        }
+
+        try {
+            if (true)
+                result = method.invoke(mObj, args);
+            else
+                result = -1;
+            System.out.println("Success: method " + method.getName()
+                + " res=" + result);
+        } catch (InvocationTargetException ite) {
+            throw ite.getTargetException();
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+        return result;
+    }
+}
diff --git a/tests/044-proxy/src/Clash.java b/tests/044-proxy/src/Clash.java
new file mode 100644
index 0000000..adeffdc
--- /dev/null
+++ b/tests/044-proxy/src/Clash.java
@@ -0,0 +1,70 @@
+/*
+ * 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/*
+ * Try to instantiate a proxy class with interfaces that have conflicting
+ * duplicate methods (primitive vs. object).
+ */
+public class Clash {
+    public static void main(String[] args) {
+        InvocationHandler handler = new ClashInvocationHandler();
+
+        /* try passing in the same interface twice */
+        try {
+            Proxy.newProxyInstance(Clash.class.getClassLoader(),
+                new Class[] { Interface1A.class, Interface1A.class },
+                handler);
+            System.err.println("Dupe did not throw expected exception");
+        } catch (IllegalArgumentException iae) {
+            System.out.println("Dupe threw expected exception");
+        }
+
+        try {
+            Proxy.newProxyInstance(Clash.class.getClassLoader(),
+                new Class[] { Interface1A.class, Interface1B.class },
+                handler);
+            System.err.println("Clash did not throw expected exception");
+        } catch (IllegalArgumentException iae) {
+            System.out.println("Clash threw expected exception");
+        }
+    }
+}
+
+interface Interface1A {
+    public int thisIsOkay();
+
+    public float thisIsTrouble();
+}
+
+interface Interface1B {
+    public int thisIsOkay();
+
+    public Object thisIsTrouble();
+}
+
+class ClashInvocationHandler implements InvocationHandler {
+    /* don't really need to do anything -- should never get this far */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+
+        return null;
+    }
+}
diff --git a/tests/044-proxy/src/Clash2.java b/tests/044-proxy/src/Clash2.java
new file mode 100644
index 0000000..2a384f4
--- /dev/null
+++ b/tests/044-proxy/src/Clash2.java
@@ -0,0 +1,60 @@
+/*
+ * 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/*
+ * Try to instantiate a proxy class with interfaces that have conflicting
+ * duplicate methods (primitive types).
+ */
+public class Clash2 {
+    public static void main(String[] args) {
+        InvocationHandler handler = new Clash2InvocationHandler();
+
+        try {
+            Proxy.newProxyInstance(Clash.class.getClassLoader(),
+                new Class[] { Interface2A.class, Interface2B.class },
+                handler);
+            System.err.println("Clash2 did not throw expected exception");
+        } catch (IllegalArgumentException iae) {
+            System.out.println("Clash2 threw expected exception");
+        }
+    }
+}
+
+interface Interface2A {
+    public int thisIsOkay();
+
+    public int thisIsTrouble();
+}
+
+interface Interface2B {
+    public int thisIsOkay();
+
+    public short thisIsTrouble();
+}
+
+class Clash2InvocationHandler implements InvocationHandler {
+    /* don't really need to do anything -- should never get this far */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+
+        return null;
+    }
+}
diff --git a/tests/044-proxy/src/Clash3.java b/tests/044-proxy/src/Clash3.java
new file mode 100644
index 0000000..6d6f2f2
--- /dev/null
+++ b/tests/044-proxy/src/Clash3.java
@@ -0,0 +1,75 @@
+/*
+ * 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/*
+ * Try to instantiate a proxy class with interfaces that have conflicting
+ * duplicate methods (type tree with interface).
+ */
+public class Clash3 {
+    public static void main(String[] args) {
+        InvocationHandler handler = new Clash3InvocationHandler();
+
+        try {
+            Proxy.newProxyInstance(Clash.class.getClassLoader(),
+                new Class[] {
+                    Interface3a.class,
+                    Interface3base.class,
+                    Interface3aa.class,
+                    Interface3b.class },
+                handler);
+            System.err.println("Clash3 did not throw expected exception");
+        } catch (IllegalArgumentException iae) {
+            System.out.println("Clash3 threw expected exception");
+        }
+    }
+}
+
+class R3base implements I3 { int mBlah; public void x() {} }
+class R3a extends R3base { int mBlah_a;  }
+class R3aa extends R3a { int mBlah_aa;  }
+class R3b implements I3 { int mBlah_b; public void x() {} }
+
+interface I3 {
+    void x();
+}
+
+interface Interface3base {
+    public R3base thisIsTrouble();
+}
+
+interface Interface3a {
+    public R3a thisIsTrouble();
+}
+interface Interface3aa {
+    public R3aa thisIsTrouble();
+}
+interface Interface3b {
+    public R3b thisIsTrouble();
+}
+
+class Clash3InvocationHandler implements InvocationHandler {
+    /* don't really need to do anything -- should never get this far */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+
+        return null;
+    }
+}
diff --git a/tests/044-proxy/src/Clash4.java b/tests/044-proxy/src/Clash4.java
new file mode 100644
index 0000000..1bfb37f
--- /dev/null
+++ b/tests/044-proxy/src/Clash4.java
@@ -0,0 +1,77 @@
+/*
+ * 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/*
+ * Try to instantiate a proxy class with interfaces that have conflicting
+ * duplicate methods (tree of types).
+ */
+public class Clash4 {
+    public static void main(String[] args) {
+        InvocationHandler handler = new Clash4InvocationHandler();
+
+        try {
+            Proxy.newProxyInstance(Clash.class.getClassLoader(),
+                new Class[] {
+                    Interface4a.class,
+                    Interface4aa.class,
+                    Interface4base.class,
+                    Interface4b.class,
+                    Interface4bb.class },
+                handler);
+            System.err.println("Clash4 did not throw expected exception");
+        } catch (IllegalArgumentException iae) {
+            System.out.println("Clash4 threw expected exception");
+            //System.out.println(iae);
+        }
+    }
+}
+
+class R4base { int mBlah;  }
+class R4a extends R4base { int mBlah_a;  }
+class R4aa extends R4a { int mBlah_aa;  }
+class R4b extends R4base { int mBlah_b;  }
+class R4bb extends R4b { int mBlah_bb;  }
+
+interface Interface4base {
+    public R4base thisIsTrouble();
+}
+
+interface Interface4a {
+    public R4a thisIsTrouble();
+}
+interface Interface4aa {
+    public R4aa thisIsTrouble();
+}
+interface Interface4b {
+    public R4b thisIsTrouble();
+}
+interface Interface4bb {
+    public R4bb thisIsTrouble();
+}
+
+class Clash4InvocationHandler implements InvocationHandler {
+    /* don't really need to do anything -- should never get this far */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+
+        return null;
+    }
+}
diff --git a/tests/044-proxy/src/Main.java b/tests/044-proxy/src/Main.java
new file mode 100644
index 0000000..01926af
--- /dev/null
+++ b/tests/044-proxy/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * 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 java.lang.reflect.Proxy
+ */
+public class Main {
+    public static void main(String[] args) {
+        BasicTest.main(null);
+        Clash.main(null);
+        Clash2.main(null);
+        Clash3.main(null);
+        Clash4.main(null);
+        WrappedThrow.main(null);
+    }
+}
diff --git a/tests/044-proxy/src/WrappedThrow.java b/tests/044-proxy/src/WrappedThrow.java
new file mode 100644
index 0000000..27ae84e
--- /dev/null
+++ b/tests/044-proxy/src/WrappedThrow.java
@@ -0,0 +1,244 @@
+/*
+ * 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.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.UndeclaredThrowableException;
+
+/*
+ * Create a Proxy class that blah.
+ */
+public class WrappedThrow {
+    public static void main(String[] args) {
+        WTMix mix = new WTMix();
+        InvocationHandler handler = new WTInvocationHandler(mix);
+        Object proxy;
+
+        try {
+            proxy = Proxy.newProxyInstance(WrappedThrow.class.getClassLoader(),
+                new Class[] { InterfaceW1.class, InterfaceW2.class },
+                handler);
+        } catch (IllegalArgumentException iae) {
+            System.out.println("WT init failed");
+            return;
+        }
+
+        InterfaceW1 if1 = (InterfaceW1) proxy;
+        InterfaceW2 if2 = (InterfaceW2) proxy;
+        try {
+            if1.throwFunky();
+            System.err.println("No exception thrown");
+        } catch (UndeclaredThrowableException ute) {
+            System.out.println("Got expected UTE");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        try {
+            if1.throwFunky2();
+            System.err.println("No exception thrown");
+        } catch (IOException ioe) {
+            System.out.println("Got expected IOE");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        try {
+            if2.throwFunky2();
+            System.err.println("No exception thrown");
+        } catch (IOException ioe) {
+            System.out.println("Got expected IOE");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        /*
+         * Throw exceptions, walking down the hierarchy.
+         */
+        try {
+            if1.throwException();
+            System.err.println("No exception thrown");
+        } catch (UndeclaredThrowableException ute) {
+            System.out.println("Got expected UTE");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        try {
+            if1.throwBase();
+            System.err.println("No exception thrown");
+        } catch (UndeclaredThrowableException ute) {
+            System.out.println("Got expected UTE");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        try {
+            if2.throwSub();
+            System.err.println("No exception thrown");
+        } catch (SubException se) {
+            System.out.println("Got expected exception");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        try {
+            if2.throwSubSub();
+            System.err.println("No exception thrown");
+        } catch (SubException se) {
+            System.out.println("Got expected exception");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+
+        /*
+         * Make sure that, if the class explicitly allows the base
+         * class of an exception, that we still allow it.
+         */
+        try {
+            if1.bothThrowBase();
+            System.err.println("No exception thrown");
+        } catch (BaseException se) {
+            System.out.println("Got expected exception");
+        } catch (Throwable t) {
+            System.err.println("Got unexpected exception: " + t);
+        }
+    }
+}
+
+class BaseException extends Exception {}
+class SubException extends BaseException {}
+class SubSubException extends SubException {}
+
+interface InterfaceW1 {
+    public void throwFunky();
+
+    public void throwFunky2() throws BaseException,
+           NoSuchMethodException, IOException;
+
+    public void throwException() throws BaseException;
+    public void throwBase() throws BaseException;
+    public void throwSub() throws BaseException;
+    public void throwSubSub() throws BaseException;
+
+    public void bothThrowBase() throws BaseException, SubException, SubSubException;
+}
+
+interface InterfaceW2 {
+    public void throwFunky2() throws InterruptedException,
+           NoSuchMethodException, IOException;
+
+    public void throwException() throws SubException;
+    public void throwBase() throws SubException;
+    public void throwSub() throws SubException;
+    public void throwSubSub() throws SubException;
+
+    public void bothThrowBase() throws SubException, BaseException, SubSubException;
+}
+
+/**
+ * Implement all of the proxied interfaces.
+ */
+class WTMix implements InterfaceW1, InterfaceW2 {
+    public int dastardlyDeed() throws SubException {
+        System.out.println("Throwing SubException");
+        throw new SubException();
+    }
+
+    /* these don't actually get called; they just cause exceptions */
+    public void throwFunky() {}
+    public void throwFunky2() {}
+    public void throwException() throws SubException {}
+    public void throwBase() throws SubException {}
+    public void throwSub() throws SubException {}
+    public void throwSubSub() throws SubException {}
+
+    public void bothThrowBase() throws BaseException, SubException {}
+}
+
+/**
+ * Invocation handler for our proxy class.
+ */
+class WTInvocationHandler implements InvocationHandler {
+    private Object mObj;
+
+    public WTInvocationHandler(Object obj) {
+        mObj = obj;
+    }
+
+    /*
+     * This is called when anything gets invoked in the proxy object.
+     */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+
+        Object result = null;
+
+        // Trap Object calls.  This is important here to avoid a recursive
+        // invocation of toString() in the print statements below.
+        if (method.getDeclaringClass() == java.lang.Object.class) {
+            //System.out.println("!!! object " + method.getName());
+            if (method.getName().equals("toString"))
+                return super.toString();
+            else if (method.getName().equals("hashCode"))
+                return Integer.valueOf(super.hashCode());
+            else if (method.getName().equals("equals"))
+                return Boolean.valueOf(super.equals(args[0]));
+            else
+                throw new RuntimeException("huh?");
+        }
+
+        System.out.println("Invoke " + method);
+        if (args == null || args.length == 0) {
+            System.out.println(" (no args)");
+        } else {
+            for (int i = 0; i < args.length; i++)
+                System.out.println(" " + i + ": " + args[i]);
+        }
+
+        try {
+            if (method.getName().equals("throwFunky"))
+                throw new InterruptedException("fake");
+            if (method.getName().equals("throwFunky2"))
+                throw new IOException("fake2");
+            if (method.getName().equals("throwException"))
+                throw new Exception();
+            if (method.getName().equals("throwBase"))
+                throw new BaseException();
+            if (method.getName().equals("throwSub"))
+                throw new SubException();
+            if (method.getName().equals("throwSubSub"))
+                throw new SubSubException();
+            if (method.getName().equals("bothThrowBase"))
+                throw new BaseException();
+
+            if (true)
+                result = method.invoke(mObj, args);
+            else
+                result = -1;
+            System.out.println("Success: method " + method.getName()
+                + " res=" + result);
+        } catch (InvocationTargetException ite) {
+            throw ite.getTargetException();
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+        return result;
+    }
+}
diff --git a/tests/045-reflect-array/expected.txt b/tests/045-reflect-array/expected.txt
new file mode 100644
index 0000000..5c609b5
--- /dev/null
+++ b/tests/045-reflect-array/expected.txt
@@ -0,0 +1,6 @@
+ReflectArrayTest.testSingleInt passed
+ReflectArrayTest.testSingle passed
+ReflectArrayTest.testMultiInt passed
+zero one two ++
+ReflectArrayTest.testMulti passed
+ReflectArrayTest passed
diff --git a/tests/045-reflect-array/info.txt b/tests/045-reflect-array/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/045-reflect-array/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/045-reflect-array/src/Main.java b/tests/045-reflect-array/src/Main.java
new file mode 100644
index 0000000..c70e291
--- /dev/null
+++ b/tests/045-reflect-array/src/Main.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ */
+
+import java.lang.reflect.Array;
+
+/**
+ * Test java.lang.reflect.Array.
+ */
+public class Main {
+    public static void main(String[] args) {
+        testSingleInt();
+        testSingle();
+        testMultiInt();
+        testMulti();
+
+        System.out.println("ReflectArrayTest passed");
+    }
+
+    static void testSingleInt() {
+        Object intArray;
+
+        intArray = Array.newInstance(Integer.TYPE, 2);
+
+        int[] array = (int[]) intArray;
+        array[0] = 5;
+        Array.setInt(intArray, 1, 6);
+
+        if (Array.getInt(intArray, 0) != 5)
+            throw new RuntimeException();
+        if (array[1] != 6)
+            throw new RuntimeException();
+        try {
+            array[2] = 27;
+            throw new RuntimeException("store should have failed");
+        }
+        catch (ArrayIndexOutOfBoundsException abe) {
+        }
+        if (array.length != Array.getLength(intArray) ||
+            array.length != 2)
+        {
+            throw new RuntimeException("bad len");
+        }
+
+        int[][] wrongArray;
+        try {
+            wrongArray = (int[][]) intArray;
+            throw new RuntimeException("cast should have failed");
+        }
+        catch (ClassCastException cce) {
+        }
+
+        intArray = Array.newInstance(Integer.TYPE, 0);
+        if (Array.getLength(intArray) != 0)
+            throw new RuntimeException();
+        System.out.println("ReflectArrayTest.testSingleInt passed");
+    }
+
+    static void testSingle() {
+        Object strArray;
+
+        strArray = Array.newInstance(String.class, 2);
+
+        String[] array = (String[]) strArray;
+        array[0] = "entry zero";
+        Array.set(strArray, 1, "entry one");
+
+        //System.out.println("array: " + array);
+
+        if (!"entry zero".equals(Array.get(strArray, 0)))
+            throw new RuntimeException();
+        if (!"entry one".equals(array[1]))
+            throw new RuntimeException();
+
+        if (array.length != Array.getLength(strArray) ||
+            array.length != 2)
+        {
+            throw new RuntimeException("bad len");
+        }
+        System.out.println("ReflectArrayTest.testSingle passed");
+    }
+
+    static void testMultiInt() {
+        Object intIntIntArray;
+        int[] dimensions = { 3, 2, 1 };
+
+        intIntIntArray = Array.newInstance(Integer.TYPE, dimensions);
+        int[][][] array3 = (int[][][]) intIntIntArray;
+
+        array3[0][0][0] = 123;      // trouble
+        array3[2][1][0] = 456;
+
+        try {
+            array3[2][1][1] = 768;
+            throw new RuntimeException("store should have failed");
+        }
+        catch (ArrayIndexOutOfBoundsException abe) {
+        }
+        System.out.println("ReflectArrayTest.testMultiInt passed");
+    }
+
+    static void testMulti() {
+        Object strStrStrArray;
+        int[] dimensions = { 1, 2, 3 };
+
+        strStrStrArray = Array.newInstance(String.class, dimensions);
+        String[][][] array3 = (String[][][]) strStrStrArray;
+
+        array3[0][0][0] = "zero zero zero";
+        array3[0][1][2] = "zero one two";
+
+        try {
+            array3[1][0][0] = "bad store";
+            throw new RuntimeException("store should have failed");
+        }
+        catch (ArrayIndexOutOfBoundsException abe) {
+        }
+
+        try {
+            String[][] array2 = (String[][]) strStrStrArray;
+            throw new RuntimeException("expecting bad cast");
+        }
+        catch (ClassCastException cce) {
+        }
+
+        String[] strar = new String[4];
+        strar[2] = "zero one two ++";
+        array3[0][1] = strar;
+        System.out.println(array3[0][1][2]);
+        //System.out.println("array3: " + array3);
+
+
+        int[] dimensions2 = { 1, 2 };
+        strStrStrArray = Array.newInstance(String[].class, dimensions2);
+        array3 = (String[][][]) strStrStrArray;
+
+        array3[0][1] = new String[3];
+        array3[0][1][2] = "zero one two";
+        try {
+            array3[1][0][0] = "bad store";
+            throw new RuntimeException("store should have failed");
+        }
+        catch (ArrayIndexOutOfBoundsException abe) {
+        }
+        System.out.println("ReflectArrayTest.testMulti passed");
+    }
+}
diff --git a/tests/046-reflect/expected.txt b/tests/046-reflect/expected.txt
new file mode 100644
index 0000000..55b0eca
--- /dev/null
+++ b/tests/046-reflect/expected.txt
@@ -0,0 +1,97 @@
+Method name is myMethod
+ Declaring class is Target
+ Arg 0: int
+ Exc 0: java.lang.NullPointerException
+ Exc 1: java.io.IOException
+ Return type is int
+ Access flags are 0x1
+Method name is myMethod
+ Declaring class is SuperTarget
+ Arg 0: float
+ Return type is int
+ Access flags are 0x1
+Method name is myNoargMethod
+ Declaring class is Target
+ Return type is void
+ Access flags are 0x9
+Method name is myMethod
+ Declaring class is Target
+ Arg 0: [Ljava.lang.String;
+ Arg 1: float
+ Arg 2: char
+ Return type is int
+ Access flags are 0x1
+SuperTarget constructor ()V
+Target constructor ()V
+Before, float is 3.1415925
+myMethod: hi there 3.1415925 Q !
+Result of invoke: 7
+Calling no-arg void-return method
+myNoargMethod ()V
+throwingMethod
+Invoke got expected exception:
+java.lang.reflect.InvocationTargetException
+java.lang.NullPointerException: gratuitous throw!
+
+Field name is string1
+ Declaring class is Target
+ Field type is java.lang.String
+ Access flags are 0x1
+  string1 value is 'hey'
+  ::: hey:yo:there
+  string1 value is now 'a new string'
+  ::: a new string:yo:there
+  got expected illegal obj store exc
+  got the other expected access exc
+  got expected arg exc
+pubLong initial value is 1122334455667788
+pubLong new value is 9988776655443322
+Field name is superInt
+ Declaring class is SuperTarget
+ Field type is int
+ Access flags are 0x1
+  superInt value is 1010101
+  superInt boxed is 1010101
+  superInt value is now 20202
+  superInt value (from short) is now 30303
+  superInt value is now 40404
+  got expected long->int failure
+  got expected long->int failure
+  got expected string->int failure
+  got expected int->short failure
+Field name is superClassInt
+ Declaring class is SuperTarget
+ Field type is int
+ Access flags are 0x9
+  superClassInt value is 1010102
+Field name is staticDouble
+ Declaring class is Target
+ Field type is double
+ Access flags are 0x9
+  staticDoubleVal value is 3.3
+  got expected double->long failure
+as expected: aPrivateInt not found
+Field name is constantString
+ Declaring class is Target
+ Field type is java.lang.String
+ Access flags are 0x19
+  Constant test value is a constant string
+Field name is cantTouchThis
+ Declaring class is Target
+ Field type is int
+ Access flags are 0x11
+  cantTouchThis is 77
+  got expected set-final failure
+  cantTouchThis is now 77
+  cantTouchThis is now 88
+cons modifiers=1
+SuperTarget constructor ()V
+Target constructor (IF)V : ii=7 ff=3.3333
+myMethod (I)I
+ arg=17 anInt=7
+ReflectTest done!
+checkType invoking null
+checkType got expected exception
+got methods
+NoisyInitUser is initializing
+NoisyInit is initializing
diff --git a/tests/046-reflect/info.txt b/tests/046-reflect/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/046-reflect/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/046-reflect/src/Main.java b/tests/046-reflect/src/Main.java
new file mode 100644
index 0000000..e604979
--- /dev/null
+++ b/tests/046-reflect/src/Main.java
@@ -0,0 +1,441 @@
+// Copyright 2006 The Android Open Source Project
+
+import java.lang.reflect.*;
+import java.io.IOException;
+import java.util.Collections;
+
+/**
+ * Reflection test.
+ */
+public class Main {
+    void printMethodInfo(Method meth) {
+        Class[] params, exceptions;
+        int i;
+
+        System.out.println("Method name is " + meth.getName());
+        System.out.println(" Declaring class is "
+            + meth.getDeclaringClass().getName());
+        params = meth.getParameterTypes();
+        for (i = 0; i < params.length; i++)
+            System.out.println(" Arg " + i + ": " + params[i].getName());
+        exceptions = meth.getExceptionTypes();
+        for (i = 0; i < exceptions.length; i++)
+            System.out.println(" Exc " + i + ": " + exceptions[i].getName());
+        System.out.println(" Return type is " + meth.getReturnType().getName());
+        System.out.println(" Access flags are 0x"
+            + Integer.toHexString(meth.getModifiers()));
+        //System.out.println(" GenericStr is " + meth.toGenericString());
+    }
+
+    void printFieldInfo(Field field) {
+        System.out.println("Field name is " + field.getName());
+        System.out.println(" Declaring class is "
+            + field.getDeclaringClass().getName());
+        System.out.println(" Field type is " + field.getType().getName());
+        System.out.println(" Access flags are 0x"
+            + Integer.toHexString(field.getModifiers()));
+    }
+
+    private void showStrings(Target instance)
+        throws NoSuchFieldException, IllegalAccessException {
+
+        Class target = Target.class;
+        String one, two, three, four;
+        Field field = null;
+
+        field = target.getField("string1");
+        one = (String) field.get(instance);
+
+        field = target.getField("string2");
+        two = (String) field.get(instance);
+
+        field = target.getField("string3");
+        three = (String) field.get(instance);
+
+        System.out.println("  ::: " + one + ":" + two + ":" + three);
+    }
+
+    public void run() {
+        Class target = Target.class;
+        Method meth = null;
+        Field field = null;
+        boolean excep;
+
+        try {
+            meth = target.getMethod("myMethod", new Class[] { int.class });
+
+            if (meth.getDeclaringClass() != target)
+                throw new RuntimeException();
+            printMethodInfo(meth);
+
+            meth = target.getMethod("myMethod", new Class[] { float.class });
+            printMethodInfo(meth);
+
+            meth = target.getMethod("myNoargMethod", (Class[]) null);
+            printMethodInfo(meth);
+
+            meth = target.getMethod("myMethod",
+                new Class[] { String[].class, float.class, char.class });
+            printMethodInfo(meth);
+
+            Target instance = new Target();
+            Object[] argList = new Object[] {
+                new String[] { "hi there" },
+                new Float(3.1415926f),
+                new Character('Q')
+            };
+            System.out.println("Before, float is "
+                + ((Float)argList[1]).floatValue());
+
+            Integer boxval;
+            boxval = (Integer) meth.invoke(instance, argList);
+            System.out.println("Result of invoke: " + boxval.intValue());
+
+            System.out.println("Calling no-arg void-return method");
+            meth = target.getMethod("myNoargMethod", (Class[]) null);
+            meth.invoke(instance, (Object[]) null);
+
+            /* try invoking a method that throws an exception */
+            meth = target.getMethod("throwingMethod", (Class[]) null);
+            try {
+                meth.invoke(instance, (Object[]) null);
+                System.out.println("GLITCH: didn't throw");
+            } catch (InvocationTargetException ite) {
+                System.out.println("Invoke got expected exception:");
+                System.out.println(ite.getClass().getName());
+                System.out.println(ite.getCause());
+            }
+            catch (Exception ex) {
+                System.out.println("GLITCH: invoke got wrong exception:");
+                ex.printStackTrace();
+            }
+            System.out.println("");
+
+
+            field = target.getField("string1");
+            if (field.getDeclaringClass() != target)
+                throw new RuntimeException();
+            printFieldInfo(field);
+            String strVal = (String) field.get(instance);
+            System.out.println("  string1 value is '" + strVal + "'");
+
+            showStrings(instance);
+
+            field.set(instance, new String("a new string"));
+            strVal = (String) field.get(instance);
+            System.out.println("  string1 value is now '" + strVal + "'");
+
+            showStrings(instance);
+
+            try {
+                field.set(instance, new Object());
+                System.out.println("WARNING: able to store Object into String");
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected illegal obj store exc");
+            }
+
+
+            try {
+                String four;
+                field = target.getField("string4");
+                four = (String) field.get(instance);
+                System.out.println("WARNING: able to access string4: "
+                    + four);
+            }
+            catch (IllegalAccessException iae) {
+                System.out.println("  got expected access exc");
+            }
+            catch (NoSuchFieldException nsfe) {
+                System.out.println("  got the other expected access exc");
+            }
+            try {
+                String three;
+                field = target.getField("string3");
+                three = (String) field.get(this);
+                System.out.println("WARNING: able to get string3 in wrong obj: "
+                    + three);
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected arg exc");
+            }
+
+            /*
+             * Try setting a field to null.
+             */
+            String four;
+            field = target.getDeclaredField("string3");
+            field.set(instance, null);
+
+            /*
+             * Do some stuff with long.
+             */
+            long longVal;
+            field = target.getField("pubLong");
+            longVal = field.getLong(instance);
+            System.out.println("pubLong initial value is " +
+                Long.toHexString(longVal));
+            field.setLong(instance, 0x9988776655443322L);
+            longVal = field.getLong(instance);
+            System.out.println("pubLong new value is " +
+                Long.toHexString(longVal));
+
+
+            field = target.getField("superInt");
+            if (field.getDeclaringClass() == target)
+                throw new RuntimeException();
+            printFieldInfo(field);
+            int intVal = field.getInt(instance);
+            System.out.println("  superInt value is " + intVal);
+            Integer boxedIntVal = (Integer) field.get(instance);
+            System.out.println("  superInt boxed is " + boxedIntVal);
+
+            field.set(instance, new Integer(20202));
+            intVal = field.getInt(instance);
+            System.out.println("  superInt value is now " + intVal);
+            field.setShort(instance, (short)30303);
+            intVal = field.getInt(instance);
+            System.out.println("  superInt value (from short) is now " +intVal);
+            field.setInt(instance, 40404);
+            intVal = field.getInt(instance);
+            System.out.println("  superInt value is now " + intVal);
+            try {
+                field.set(instance, new Long(123));
+                System.out.println("FAIL: expected exception not thrown");
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected long->int failure");
+            }
+            try {
+                field.setLong(instance, 123);
+                System.out.println("FAIL: expected exception not thrown");
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected long->int failure");
+            }
+            try {
+                field.set(instance, new String("abc"));
+                System.out.println("FAIL: expected exception not thrown");
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected string->int failure");
+            }
+
+            try {
+                field.getShort(instance);
+                System.out.println("FAIL: expected exception not thrown");
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected int->short failure");
+            }
+
+            field = target.getField("superClassInt");
+            printFieldInfo(field);
+            int superClassIntVal = field.getInt(instance);
+            System.out.println("  superClassInt value is " + superClassIntVal);
+
+            field = target.getField("staticDouble");
+            printFieldInfo(field);
+            double staticDoubleVal = field.getDouble(null);
+            System.out.println("  staticDoubleVal value is " + staticDoubleVal);
+
+            try {
+                field.getLong(instance);
+                System.out.println("FAIL: expected exception not thrown");
+            }
+            catch (IllegalArgumentException iae) {
+                System.out.println("  got expected double->long failure");
+            }
+
+            excep = false;
+            try {
+                field = target.getField("aPrivateInt");
+                printFieldInfo(field);
+            }
+            catch (NoSuchFieldException nsfe) {
+                System.out.println("as expected: aPrivateInt not found");
+                excep = true;
+            }
+            if (!excep)
+                System.out.println("BUG: got aPrivateInt");
+
+
+            field = target.getField("constantString");
+            printFieldInfo(field);
+            String val = (String) field.get(instance);
+            System.out.println("  Constant test value is " + val);
+
+
+            field = target.getField("cantTouchThis");
+            printFieldInfo(field);
+            intVal = field.getInt(instance);
+            System.out.println("  cantTouchThis is " + intVal);
+            try {
+                field.setInt(instance, 99);
+                System.out.println("ERROR: set-final succeeded");
+            } catch (IllegalAccessException iae) {
+                System.out.println("  got expected set-final failure");
+            }
+            intVal = field.getInt(instance);
+            System.out.println("  cantTouchThis is now " + intVal);
+
+            field.setAccessible(true);
+            field.setInt(instance, 87);     // exercise int version
+            field.set(instance, 88);        // exercise Object version
+            intVal = field.getInt(instance);
+            System.out.println("  cantTouchThis is now " + intVal);
+
+            Constructor<Target> cons;
+            Target targ;
+            Object[] args;
+
+            cons = target.getConstructor(new Class[] { int.class,float.class });
+            args = new Object[] { new Integer(7), new Float(3.3333) };
+            System.out.println("cons modifiers=" + cons.getModifiers());
+            targ = cons.newInstance(args);
+            targ.myMethod(17);
+
+        }
+        catch (Exception ex) {
+            System.out.println("----- unexpected exception -----");
+            ex.printStackTrace();
+        }
+
+        System.out.println("ReflectTest done!");
+    }
+
+    public static void checkType() {
+        Method m;
+
+        try {
+            m = Collections.class.getDeclaredMethod("checkType",
+                            Object.class, Class.class);
+        } catch (NoSuchMethodException nsme) {
+            nsme.printStackTrace();
+            return;
+        }
+
+        m.setAccessible(true);
+        try {
+            m.invoke(null, new Object(), Object.class);
+        } catch (IllegalAccessException iae) {
+            iae.printStackTrace();
+            return;
+        } catch (InvocationTargetException ite) {
+            ite.printStackTrace();
+            return;
+        }
+
+        try {
+            System.out.println("checkType invoking null");
+            m.invoke(null, new Object(), int.class);
+            System.out.println("ERROR: should throw InvocationTargetException");
+        } catch (InvocationTargetException ite) {
+            System.out.println("checkType got expected exception");
+        } catch (IllegalAccessException iae) {
+            iae.printStackTrace();
+            return;
+        }
+    }
+
+    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();
+    }
+}
+
+
+class SuperTarget {
+    public SuperTarget() {
+        System.out.println("SuperTarget constructor ()V");
+        superInt = 1010101;
+        superClassInt = 1010102;
+    }
+
+    public int myMethod(float floatArg) {
+        System.out.println("myMethod (F)I " + floatArg);
+        return 6;
+    }
+
+    public int superInt;
+    public static int superClassInt;
+}
+
+class Target extends SuperTarget {
+    public Target() {
+        System.out.println("Target constructor ()V");
+    }
+
+    public Target(int ii, float ff) {
+        System.out.println("Target constructor (IF)V : ii="
+            + ii + " ff=" + ff);
+        anInt = ii;
+    }
+
+    public int myMethod(int intarg) throws NullPointerException, IOException {
+        System.out.println("myMethod (I)I");
+        System.out.println(" arg=" + intarg + " anInt=" + anInt);
+        return 5;
+    }
+
+    public int myMethod(String[] strarg, float f, char c) {
+        System.out.println("myMethod: " + strarg[0] + " " + f + " " + c + " !");
+        return 7;
+    }
+
+    public static void myNoargMethod() {
+        System.out.println("myNoargMethod ()V");
+    }
+
+    public void throwingMethod() {
+        System.out.println("throwingMethod");
+        throw new NullPointerException("gratuitous throw!");
+    }
+
+    public void misc() {
+        System.out.println("misc");
+    }
+
+    public int anInt;
+    public String string1 = "hey";
+    public String string2 = "yo";
+    public String string3 = "there";
+    private String string4 = "naughty";
+    public static final String constantString = "a constant string";
+    private int aPrivateInt;
+
+    public final int cantTouchThis = 77;
+
+    public long pubLong = 0x1122334455667788L;
+
+    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/047-returns/expected.txt b/tests/047-returns/expected.txt
new file mode 100644
index 0000000..160f69c
--- /dev/null
+++ b/tests/047-returns/expected.txt
@@ -0,0 +1,10 @@
+pick 1
+one running
+one
+1
+pick 2
+two running
+two
+2
+pick 3
+three running
diff --git a/tests/047-returns/info.txt b/tests/047-returns/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/047-returns/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/047-returns/src/Main.java b/tests/047-returns/src/Main.java
new file mode 100644
index 0000000..d53c4a7
--- /dev/null
+++ b/tests/047-returns/src/Main.java
@@ -0,0 +1,65 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Return stuff.
+ */
+public class Main {
+    public static void main(String[] args) {
+
+        System.out.println("pick 1");
+        pickOne(1).run();
+        System.out.println(((CommonInterface)pickOne(1)).doStuff());
+
+        System.out.println("pick 2");
+        pickOne(2).run();
+        System.out.println(((CommonInterface)pickOne(2)).doStuff());
+
+        System.out.println("pick 3");
+        pickOne(3).run();
+    }
+
+    public static Runnable pickOne(int which) {
+        Runnable runme;
+
+        if (which == 1)
+            runme = new ClassOne();
+        else if (which == 2)
+            runme = new ClassTwo();
+        else if (which == 3)
+            runme = new ClassThree();
+        else
+            runme = null;
+
+        return runme;
+    }
+}
+
+class ClassOne implements CommonInterface, Runnable {
+    public void run() {
+        System.out.println("one running");
+    }
+    public int doStuff() {
+        System.out.println("one");
+        return 1;
+    }
+}
+
+class ClassTwo implements CommonInterface, Runnable {
+    public void run() {
+        System.out.println("two running");
+    }
+    public int doStuff() {
+        System.out.println("two");
+        return 2;
+    }
+}
+
+class ClassThree implements Runnable {
+    public void run() {
+        System.out.println("three running");
+    }
+}
+
+interface CommonInterface {
+    int doStuff();
+}
diff --git a/tests/048-server-socket/expected.txt b/tests/048-server-socket/expected.txt
new file mode 100644
index 0000000..23c3e84
--- /dev/null
+++ b/tests/048-server-socket/expected.txt
@@ -0,0 +1,4 @@
+opened!
+closed!
+reopened!
+done
diff --git a/tests/048-server-socket/info.txt b/tests/048-server-socket/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/048-server-socket/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/048-server-socket/src/Main.java b/tests/048-server-socket/src/Main.java
new file mode 100644
index 0000000..55dbf9a
--- /dev/null
+++ b/tests/048-server-socket/src/Main.java
@@ -0,0 +1,52 @@
+// Copyright 2007 The Android Open Source Project
+
+import java.net.ServerSocket;
+import java.io.IOException;
+
+
+/**
+ * Quick server socket test.
+ */
+public class Main {
+    private static void snooze(int sec) {
+        try {
+            Thread.sleep(sec * 1000);
+        } catch (InterruptedException ie) {
+            ie.printStackTrace();
+        }
+    }
+
+    public static void main(String[] args) {
+        ServerSocket socket;
+
+        try {
+            socket = new ServerSocket(7890);
+        } catch (IOException ioe) {
+            System.out.println("couldn't open socket " + ioe.getMessage());
+            return;
+        }
+
+        System.out.println("opened!");
+        snooze(1);
+
+        try {
+            socket.close();
+        } catch (IOException ioe) {
+            System.out.println("couldn't close socket " + ioe.getMessage());
+            return;
+        }
+
+        System.out.println("closed!");
+        snooze(1);
+
+        try {
+            socket = new ServerSocket(7890);
+        } catch (IOException ioe) {
+            System.out.println("couldn't reopen socket " + ioe.getMessage());
+            return;
+        }
+
+        System.out.println("reopened!");
+        System.out.println("done");
+    }
+}
diff --git a/tests/049-show-object/expected.txt b/tests/049-show-object/expected.txt
new file mode 100644
index 0000000..4613c39
--- /dev/null
+++ b/tests/049-show-object/expected.txt
@@ -0,0 +1,11 @@
+d is 3.1415
+class: class [Ljava.lang.Object;
+0: null
+1: null
+2: null
+3: null
+4: null
+class: class [Ljava.lang.String;
+0: hey
+1: you
+2: there
diff --git a/tests/049-show-object/info.txt b/tests/049-show-object/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/049-show-object/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/049-show-object/src/Main.java b/tests/049-show-object/src/Main.java
new file mode 100644
index 0000000..d31eeda
--- /dev/null
+++ b/tests/049-show-object/src/Main.java
@@ -0,0 +1,34 @@
+// Copyright 2008 The Android Open Source Project
+
+/*
+ * Some basic operations for testing the debugger.
+ */
+public class Main {
+    long mLong = 0x1122334455667788L;
+
+    public Main() {
+        double d = 3.1415;
+        System.out.println("d is " + d);
+    }
+
+    public static void showObject(Object[] foo) {
+        int xyz = 27;
+        System.out.println("class: " + foo.getClass());
+
+        for (int i = 0; i < foo.length; i++) {
+            System.out.println(i + ": "  + foo[i]);
+        }
+    }
+
+    public static void main(String[] args) {
+        int x = 5;
+        Main testObj = new Main();
+
+        Object[] array = new Object[5];
+        showObject(array);
+
+        String[] niftyStrings = new String[] { "hey", "you", "there" };
+        array = niftyStrings;
+        showObject(array);
+    }
+}
diff --git a/tests/050-sync-test/expected.txt b/tests/050-sync-test/expected.txt
new file mode 100644
index 0000000..c2a7031
--- /dev/null
+++ b/tests/050-sync-test/expected.txt
@@ -0,0 +1,34 @@
+Sleep Test
+GOING
+GONE
+
+Count Test
+going: 1
+going: 1
+going: 1
+going: 1
+going: 1
+going: 1
+going: 1
+going: 1
+going: 1
+going: 1
+Final result: 10
+going: 2
+going: 2
+going: 2
+going: 2
+going: 2
+going: 2
+going: 2
+going: 2
+going: 2
+going: 2
+Final result: 20
+main: all done
+
+Interrupt Test
+SleepyThread.run starting
+SleepyThread.run starting
+interrupting other (isAlive=true)
+thread#0 interrupted, flag=false
diff --git a/tests/050-sync-test/info.txt b/tests/050-sync-test/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/050-sync-test/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/050-sync-test/src/Main.java b/tests/050-sync-test/src/Main.java
new file mode 100644
index 0000000..c2ea192
--- /dev/null
+++ b/tests/050-sync-test/src/Main.java
@@ -0,0 +1,179 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Test synchronization primitives.
+ *
+ * TODO: this should be re-written to be a little more rigorous and/or
+ * useful.  Also, the ThreadDeathHandler stuff should be exposed or
+ * split out.
+ */
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Sleep Test");
+        sleepTest();
+
+        System.out.println("\nCount Test");
+        countTest();
+
+        System.out.println("\nInterrupt Test");
+        interruptTest();
+    }
+
+    static void sleepTest() {
+        System.out.println("GOING");
+        try {
+            Thread.sleep(1000);
+        }
+        catch (InterruptedException ie) {
+            System.out.println("INTERRUPT!");
+            ie.printStackTrace();
+        }
+        System.out.println("GONE");
+    }
+
+    static void countTest() {
+        CpuThread one, two;
+
+        one = new CpuThread(1);
+        two = new CpuThread(2);
+
+        one.start();
+        two.start();
+
+        try {
+            Thread.sleep(100);
+        }
+        catch (InterruptedException ie) {
+            System.out.println("INTERRUPT!");
+            ie.printStackTrace();
+        }
+
+        //System.out.println("main: off and running");
+
+        try {
+            one.join();
+            two.join();
+        }
+        catch (InterruptedException ie) {
+            System.out.println("INTERRUPT!");
+            ie.printStackTrace();
+        }
+        System.out.println("main: all done");
+    }
+
+    static void interruptTest() {
+        SleepyThread sleepy, pesky;
+
+        sleepy = new SleepyThread(null);
+        pesky = new SleepyThread(sleepy);
+
+        sleepy.setPriority(4);
+        sleepy.start();
+        pesky.start();
+        pesky.setPriority(3);
+    }
+}
+
+class CpuThread extends Thread {
+    static Object mSyncable = new Object();
+    static int mCount = 0;
+    int mNumber;
+
+    CpuThread(int num) {
+        super("CpuThread " + num);
+        mNumber = num;
+    }
+
+    public void run() {
+        //System.out.print("thread running -- ");
+        //System.out.println(Thread.currentThread().getName());
+
+        for (int i = 0; i < 10; i++) {
+            output(mNumber);
+        }
+
+        System.out.print("Final result: ");
+        System.out.println(mCount);
+    }
+
+    void output(int num) {
+        /*
+         * Delete the next line; last "final result" should != 20.
+         */
+        synchronized (mSyncable)
+        {
+            int i, count;
+
+            count = mCount;
+
+            System.out.print("going: ");
+            System.out.println(num);
+
+            /* burn CPU; adjust end value so we exceed scheduler quantum */
+            for (int j = 0; j < 5000; j++)
+                ;
+
+            count++;
+            mCount = count;
+        }
+    }
+}
+
+class SleepyThread extends Thread {
+    private SleepyThread mOther;
+    private Integer[] mWaitOnMe;      // any type of object will do
+
+    private static int count = 0;
+
+    SleepyThread(SleepyThread other) {
+        mOther = other;
+        mWaitOnMe = new Integer[] { 1, 2 };
+
+        setName("thread#" + count);
+        count++;
+    }
+
+    public void run() {
+        System.out.println("SleepyThread.run starting");
+
+        if (false) {
+            ThreadDeathHandler threadHandler =
+                new ThreadDeathHandler("SYNC THREAD");
+            Thread.currentThread().setUncaughtExceptionHandler(threadHandler);
+            throw new NullPointerException("die");
+        }
+
+        if (mOther == null) {
+            boolean intr = false;
+
+            try {
+                synchronized (mWaitOnMe) {
+                    mWaitOnMe.wait(9000);
+                }
+            }
+            catch (InterruptedException ie) {
+                // Expecting this; interrupted should be false.
+                System.out.println(Thread.currentThread().getName() +
+                        " interrupted, flag=" + Thread.interrupted());
+                intr = true;
+            }
+            catch (Exception ex) {
+                ex.printStackTrace();
+            }
+
+            if (!intr)
+                System.out.println("NOT INTERRUPTED");
+        } else {
+            try {
+                Thread.sleep(2000);
+            }
+            catch (InterruptedException ie) {
+                System.out.println("PESKY INTERRUPTED?");
+            }
+
+            System.out.println("interrupting other (isAlive="
+                + mOther.isAlive() + ")");
+            mOther.interrupt();
+        }
+    }
+}
diff --git a/tests/050-sync-test/src/ThreadDeathHandler.java b/tests/050-sync-test/src/ThreadDeathHandler.java
new file mode 100644
index 0000000..5ea61a5
--- /dev/null
+++ b/tests/050-sync-test/src/ThreadDeathHandler.java
@@ -0,0 +1,19 @@
+// Copyright 2007 The Android Open Source Project
+
+import java.lang.Thread.UncaughtExceptionHandler;
+
+/**
+ * Report death-by-uncaught-exception.
+ */
+public class ThreadDeathHandler implements Thread.UncaughtExceptionHandler {
+    private String mMyMessage;
+
+    public ThreadDeathHandler(String msg) {
+        mMyMessage = msg;
+    }
+
+    public void uncaughtException(Thread t, Throwable e) {
+        System.err.println("Uncaught exception " + mMyMessage + "!");
+        e.printStackTrace();
+    }
+}
diff --git a/tests/051-thread/expected.txt b/tests/051-thread/expected.txt
new file mode 100644
index 0000000..fbe32f6
--- /dev/null
+++ b/tests/051-thread/expected.txt
@@ -0,0 +1,518 @@
+running 0
+running 1
+running 2
+running 3
+running 4
+running 5
+running 6
+running 7
+running 8
+running 9
+running 10
+running 11
+running 12
+running 13
+running 14
+running 15
+running 16
+running 17
+running 18
+running 19
+running 20
+running 21
+running 22
+running 23
+running 24
+running 25
+running 26
+running 27
+running 28
+running 29
+running 30
+running 31
+running 32
+running 33
+running 34
+running 35
+running 36
+running 37
+running 38
+running 39
+running 40
+running 41
+running 42
+running 43
+running 44
+running 45
+running 46
+running 47
+running 48
+running 49
+running 50
+running 51
+running 52
+running 53
+running 54
+running 55
+running 56
+running 57
+running 58
+running 59
+running 60
+running 61
+running 62
+running 63
+running 64
+running 65
+running 66
+running 67
+running 68
+running 69
+running 70
+running 71
+running 72
+running 73
+running 74
+running 75
+running 76
+running 77
+running 78
+running 79
+running 80
+running 81
+running 82
+running 83
+running 84
+running 85
+running 86
+running 87
+running 88
+running 89
+running 90
+running 91
+running 92
+running 93
+running 94
+running 95
+running 96
+running 97
+running 98
+running 99
+running 100
+running 101
+running 102
+running 103
+running 104
+running 105
+running 106
+running 107
+running 108
+running 109
+running 110
+running 111
+running 112
+running 113
+running 114
+running 115
+running 116
+running 117
+running 118
+running 119
+running 120
+running 121
+running 122
+running 123
+running 124
+running 125
+running 126
+running 127
+running 128
+running 129
+running 130
+running 131
+running 132
+running 133
+running 134
+running 135
+running 136
+running 137
+running 138
+running 139
+running 140
+running 141
+running 142
+running 143
+running 144
+running 145
+running 146
+running 147
+running 148
+running 149
+running 150
+running 151
+running 152
+running 153
+running 154
+running 155
+running 156
+running 157
+running 158
+running 159
+running 160
+running 161
+running 162
+running 163
+running 164
+running 165
+running 166
+running 167
+running 168
+running 169
+running 170
+running 171
+running 172
+running 173
+running 174
+running 175
+running 176
+running 177
+running 178
+running 179
+running 180
+running 181
+running 182
+running 183
+running 184
+running 185
+running 186
+running 187
+running 188
+running 189
+running 190
+running 191
+running 192
+running 193
+running 194
+running 195
+running 196
+running 197
+running 198
+running 199
+running 200
+running 201
+running 202
+running 203
+running 204
+running 205
+running 206
+running 207
+running 208
+running 209
+running 210
+running 211
+running 212
+running 213
+running 214
+running 215
+running 216
+running 217
+running 218
+running 219
+running 220
+running 221
+running 222
+running 223
+running 224
+running 225
+running 226
+running 227
+running 228
+running 229
+running 230
+running 231
+running 232
+running 233
+running 234
+running 235
+running 236
+running 237
+running 238
+running 239
+running 240
+running 241
+running 242
+running 243
+running 244
+running 245
+running 246
+running 247
+running 248
+running 249
+running 250
+running 251
+running 252
+running 253
+running 254
+running 255
+running 256
+running 257
+running 258
+running 259
+running 260
+running 261
+running 262
+running 263
+running 264
+running 265
+running 266
+running 267
+running 268
+running 269
+running 270
+running 271
+running 272
+running 273
+running 274
+running 275
+running 276
+running 277
+running 278
+running 279
+running 280
+running 281
+running 282
+running 283
+running 284
+running 285
+running 286
+running 287
+running 288
+running 289
+running 290
+running 291
+running 292
+running 293
+running 294
+running 295
+running 296
+running 297
+running 298
+running 299
+running 300
+running 301
+running 302
+running 303
+running 304
+running 305
+running 306
+running 307
+running 308
+running 309
+running 310
+running 311
+running 312
+running 313
+running 314
+running 315
+running 316
+running 317
+running 318
+running 319
+running 320
+running 321
+running 322
+running 323
+running 324
+running 325
+running 326
+running 327
+running 328
+running 329
+running 330
+running 331
+running 332
+running 333
+running 334
+running 335
+running 336
+running 337
+running 338
+running 339
+running 340
+running 341
+running 342
+running 343
+running 344
+running 345
+running 346
+running 347
+running 348
+running 349
+running 350
+running 351
+running 352
+running 353
+running 354
+running 355
+running 356
+running 357
+running 358
+running 359
+running 360
+running 361
+running 362
+running 363
+running 364
+running 365
+running 366
+running 367
+running 368
+running 369
+running 370
+running 371
+running 372
+running 373
+running 374
+running 375
+running 376
+running 377
+running 378
+running 379
+running 380
+running 381
+running 382
+running 383
+running 384
+running 385
+running 386
+running 387
+running 388
+running 389
+running 390
+running 391
+running 392
+running 393
+running 394
+running 395
+running 396
+running 397
+running 398
+running 399
+running 400
+running 401
+running 402
+running 403
+running 404
+running 405
+running 406
+running 407
+running 408
+running 409
+running 410
+running 411
+running 412
+running 413
+running 414
+running 415
+running 416
+running 417
+running 418
+running 419
+running 420
+running 421
+running 422
+running 423
+running 424
+running 425
+running 426
+running 427
+running 428
+running 429
+running 430
+running 431
+running 432
+running 433
+running 434
+running 435
+running 436
+running 437
+running 438
+running 439
+running 440
+running 441
+running 442
+running 443
+running 444
+running 445
+running 446
+running 447
+running 448
+running 449
+running 450
+running 451
+running 452
+running 453
+running 454
+running 455
+running 456
+running 457
+running 458
+running 459
+running 460
+running 461
+running 462
+running 463
+running 464
+running 465
+running 466
+running 467
+running 468
+running 469
+running 470
+running 471
+running 472
+running 473
+running 474
+running 475
+running 476
+running 477
+running 478
+running 479
+running 480
+running 481
+running 482
+running 483
+running 484
+running 485
+running 486
+running 487
+running 488
+running 489
+running 490
+running 491
+running 492
+running 493
+running 494
+running 495
+running 496
+running 497
+running 498
+running 499
+running 500
+running 501
+running 502
+running 503
+running 504
+running 505
+running 506
+running 507
+running 508
+running 509
+running 510
+running 511
+Starting thread 'Thready'
+@ Thread running
+@ Got expected setDaemon exception
+@ Thread bailing
+Thread starter returning
+thread test done
diff --git a/tests/051-thread/info.txt b/tests/051-thread/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/051-thread/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/051-thread/src/Main.java b/tests/051-thread/src/Main.java
new file mode 100644
index 0000000..9acc89e
--- /dev/null
+++ b/tests/051-thread/src/Main.java
@@ -0,0 +1,73 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Test some basic thread stuff.
+ */
+public class Main {
+    public static void main(String[] args) {
+        for (int i = 0; i < 512; i++) {
+            MyThread myThread = new MyThread();
+            myThread.start();
+            try {
+                Thread.sleep(1);
+            } catch (InterruptedException ie) {
+                ie.printStackTrace();
+            }
+        }
+
+        go();
+        System.out.println("thread test done");
+    }
+
+    public static void go() {
+        Thread t = new Thread(null, new ThreadTestSub(), "Thready", 7168);
+
+        t.setDaemon(false);
+
+        System.out.print("Starting thread '" + t.getName() + "'\n");
+        t.start();
+
+        try {
+            t.join();
+        } catch (InterruptedException ex) {
+            ex.printStackTrace();
+        }
+
+        System.out.print("Thread starter returning\n");
+    }
+
+    /*
+     * Simple thread capacity test.
+     */
+    static class MyThread extends Thread {
+        private static int mCount = 0;
+        public void run() {
+            System.out.println("running " + (mCount++));
+        }
+    }
+}
+
+class ThreadTestSub implements Runnable {
+    public void run() {
+        System.out.print("@ Thread running\n");
+
+        try {
+            Thread.currentThread().setDaemon(true);
+            System.out.print("@ FAILED: setDaemon() succeeded\n");
+        } catch (IllegalThreadStateException itse) {
+            System.out.print("@ Got expected setDaemon exception\n");
+        }
+
+        //if (true)
+        //    throw new NullPointerException();
+        try {
+            Thread.sleep(2000);
+        }
+        catch (InterruptedException ie) {
+            System.out.print("@ Interrupted!\n");
+        }
+        finally {
+            System.out.print("@ Thread bailing\n");
+        }
+    }
+}
diff --git a/tests/052-verifier-fun/expected.txt b/tests/052-verifier-fun/expected.txt
new file mode 100644
index 0000000..5662675
--- /dev/null
+++ b/tests/052-verifier-fun/expected.txt
@@ -0,0 +1,2 @@
+BlahOne
+Zorch.
diff --git a/tests/052-verifier-fun/info.txt b/tests/052-verifier-fun/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/052-verifier-fun/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/052-verifier-fun/src/Blah.java b/tests/052-verifier-fun/src/Blah.java
new file mode 100644
index 0000000..edd6c9d
--- /dev/null
+++ b/tests/052-verifier-fun/src/Blah.java
@@ -0,0 +1,4 @@
+public abstract class Blah {
+    public void unrelatedStuff() {
+    }
+}
diff --git a/tests/052-verifier-fun/src/BlahFeature.java b/tests/052-verifier-fun/src/BlahFeature.java
new file mode 100644
index 0000000..ea0e18a
--- /dev/null
+++ b/tests/052-verifier-fun/src/BlahFeature.java
@@ -0,0 +1,3 @@
+public interface BlahFeature {
+    public void doStuff();
+}
diff --git a/tests/052-verifier-fun/src/BlahOne.java b/tests/052-verifier-fun/src/BlahOne.java
new file mode 100644
index 0000000..ed423cd
--- /dev/null
+++ b/tests/052-verifier-fun/src/BlahOne.java
@@ -0,0 +1,5 @@
+public class BlahOne extends Blah implements BlahFeature {
+    public void doStuff() {
+        System.out.println("BlahOne");
+    }
+}
diff --git a/tests/052-verifier-fun/src/BlahTwo.java b/tests/052-verifier-fun/src/BlahTwo.java
new file mode 100644
index 0000000..cff3670
--- /dev/null
+++ b/tests/052-verifier-fun/src/BlahTwo.java
@@ -0,0 +1,5 @@
+public class BlahTwo extends Blah implements BlahFeature {
+    public void doStuff() {
+        System.out.println("BlahTwo");
+    }
+}
diff --git a/tests/052-verifier-fun/src/Main.java b/tests/052-verifier-fun/src/Main.java
new file mode 100644
index 0000000..ca960cf
--- /dev/null
+++ b/tests/052-verifier-fun/src/Main.java
@@ -0,0 +1,109 @@
+// Copyright 2007 The Android Open Source Project
+
+import java.lang.reflect.Type;
+
+/**
+ * Throw a few things at the verifier, all of which are expected to pass.
+ */
+public class Main {
+    static public void main(String[] args) {
+        tryBlah(1);
+
+        System.out.println("Zorch.");
+    }
+
+    /*
+     * Make sure the verifier is handling type merge of arrays of
+     * references correctly.
+     */
+    static Object[] arrayCheck1(int wanted) {
+        String[] arrayOne;
+        Integer[] arrayTwo;
+
+        arrayOne = new String[1];
+        arrayTwo = new Integer[1];
+
+        switch (wanted) {
+            case 0:     return arrayOne;
+            case 1:     return arrayTwo;
+            default:    return null;
+        }
+    }
+
+    static Object arrayCheck1b(int wanted) {
+        String[] arrayOne;
+        Integer[] arrayTwo;
+        int[] arrayThree;
+
+        arrayOne = new String[1];
+        arrayTwo = new Integer[1];
+        arrayThree = new int[1];
+
+        switch (wanted) {
+            case 0:     return arrayOne;
+            case 1:     return arrayTwo;
+            case 2:     return arrayThree;
+            default:    return null;
+        }
+    }
+
+    static Object[] arrayCheck2(int wanted) {
+        String[][] arrayOne;
+        String[][] arrayTwo;
+        Integer[][] arrayThree;
+
+        arrayOne = new String[1][];
+        arrayTwo = new String[1][];
+        arrayThree = new Integer[1][];
+
+        switch (wanted) {
+            case 0:     return arrayOne;
+            case 1:     return arrayTwo;
+            case 2:     return arrayThree;
+            default:    return null;
+        }
+    }
+
+    static Object[] arrayCheck3(int wanted) {
+        String[][] arrayTwo;
+        String[][][][] arrayFour;
+
+        arrayTwo = new String[1][];
+        arrayFour = new String[1][][][];
+
+        switch (wanted) {
+            case 0:     return arrayTwo;
+            case 1:     return arrayFour;
+            default:    return null;
+        }
+    }
+
+    /*
+     * Check return type merge.
+     */
+    private Type[] typeTest() {
+        if(this == null) {
+            return (Class<?>[])null;
+        }
+        return (Type[])null;
+    }
+
+
+    /*
+     * Exercise the blahs.
+     */
+    static void tryBlah(int num) {
+        BlahFeature feature = null;     // interface ref
+
+        switch (num) {
+            case 1:
+                feature = new BlahOne();
+                break;
+            default:
+                feature = new BlahTwo();
+                break;
+        }
+
+        feature.doStuff();
+    }
+}
diff --git a/tests/053-wait-some/expected.txt b/tests/053-wait-some/expected.txt
new file mode 100644
index 0000000..182892c
--- /dev/null
+++ b/tests/053-wait-some/expected.txt
@@ -0,0 +1,7 @@
+Caught expected exception on neg arg
+Waiting for 200ms...
+Waiting for 500ms...
+Waiting for 1000ms...
+Waiting for 2000ms...
+Waiting for 3500ms...
+Waiting for 8000ms...
diff --git a/tests/053-wait-some/info.txt b/tests/053-wait-some/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/053-wait-some/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/053-wait-some/src/Main.java b/tests/053-wait-some/src/Main.java
new file mode 100644
index 0000000..51e6c52
--- /dev/null
+++ b/tests/053-wait-some/src/Main.java
@@ -0,0 +1,71 @@
+// Copyright 2007 The Android Open Source Project
+
+/**
+ * Exercise Object.wait(), comparing results against wall clock time.
+ */
+public class Main {
+    /* delays, in milliseconds */
+    private final static long[] DELAYS = {
+        200, 500, 1000, 2000, 3500, 8000
+    };
+
+    public static void main(String[] args) {
+        boolean timing = (args.length >= 1) && args[0].equals("--timing");
+        doit(timing);
+    }
+
+    public static void doit(boolean timing) {
+        Object sleepy = new Object();
+        long start, end;
+
+        synchronized (sleepy) {
+            try {
+                sleepy.wait(-500);
+                System.out.println("HEY: didn't throw on negative arg");
+            } catch (IllegalArgumentException iae) {
+                System.out.println("Caught expected exception on neg arg");
+            } catch (InterruptedException ie) {
+                ie.printStackTrace();
+            }
+
+            for(long delay : DELAYS) {
+                System.out.println("Waiting for " + delay + "ms...");
+
+                start = System.currentTimeMillis();
+                try {
+                    sleepy.wait(delay);
+                } catch (InterruptedException ie) {
+                    ie.printStackTrace();
+                }
+                end = System.currentTimeMillis();
+
+                long elapsed = end - start;
+                boolean showTime = timing;
+
+                if (! timing) {
+                    long epsilon = delay / 10;
+                    if (epsilon > 50) {
+                        epsilon = 50;
+                    }
+
+                    long min = delay - epsilon;
+                    long max = delay + epsilon;
+
+                    if (elapsed < min) {
+                        System.out.println("  Elapsed time was too short");
+                        showTime = true;
+                    } else if (elapsed > max) {
+                        System.out.println("  Elapsed time was too long: "
+                            + "elapsed=" + elapsed + " max=" + max);
+                        showTime = true;
+                    }
+                }
+
+                if (showTime) {
+                    System.out.println("  Wall clock elapsed "
+                            + elapsed + "ms");
+                }
+            }
+        }
+    }
+}
diff --git a/tests/054-uncaught/expected.txt b/tests/054-uncaught/expected.txt
new file mode 100644
index 0000000..e7473be
--- /dev/null
+++ b/tests/054-uncaught/expected.txt
@@ -0,0 +1,21 @@
+Test 1
+Uncaught exception DEFAULT!
+java.lang.NullPointerException: Hi diddly-ho, neighborino.
+	at Main.catchTheUncaught(Main.java:49)
+	at Main$Helper.run(Main.java:60)
+Test 2
+Uncaught exception THREAD!
+java.lang.NullPointerException: Hi diddly-ho, neighborino.
+	at Main.catchTheUncaught(Main.java:49)
+	at Main$Helper.run(Main.java:60)
+Test 3
+Uncaught exception THREAD!
+java.lang.NullPointerException: Hi diddly-ho, neighborino.
+	at Main.catchTheUncaught(Main.java:49)
+	at Main$Helper.run(Main.java:60)
+Test 1
+Uncaught exception DEFAULT!
+java.lang.NullPointerException: Hi diddly-ho, neighborino.
+	at Main.catchTheUncaught(Main.java:49)
+	at Main.main(Main.java:12)
+	at dalvik.system.NativeStart.main(Native Method)
diff --git a/tests/054-uncaught/info.txt b/tests/054-uncaught/info.txt
new file mode 100644
index 0000000..08127da
--- /dev/null
+++ b/tests/054-uncaught/info.txt
@@ -0,0 +1,6 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+TODO: Real description goes here.
diff --git a/tests/054-uncaught/src/Main.java b/tests/054-uncaught/src/Main.java
new file mode 100644
index 0000000..4ee6b05
--- /dev/null
+++ b/tests/054-uncaught/src/Main.java
@@ -0,0 +1,63 @@
+// Copyright 2006 The Android Open Source Project
+
+/**
+ * Test the uncaught exception handler.
+ */
+public class Main {
+    public static void main(String[] args) {
+        testThread(1);
+        testThread(2);
+        testThread(3);
+
+        catchTheUncaught(1);
+    }
+
+    private static void testThread(int which) {
+        Thread t = new Helper(which);
+        t.start();
+
+        try {
+            t.join();
+        } catch (InterruptedException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    static void catchTheUncaught(int which) {
+        ThreadDeathHandler defHandler = new ThreadDeathHandler("DEFAULT");
+        ThreadDeathHandler threadHandler = new ThreadDeathHandler("THREAD");
+
+        System.out.println("Test " + which);
+        switch (which) {
+            case 1: {
+                Thread.setDefaultUncaughtExceptionHandler(defHandler);
+                break;
+            }
+            case 2: {
+                Thread.currentThread().setUncaughtExceptionHandler(
+                        threadHandler);
+                break;
+            }
+            case 3: {
+                Thread.setDefaultUncaughtExceptionHandler(defHandler);
+                Thread.currentThread().setUncaughtExceptionHandler(
+                        threadHandler);
+                break;
+            }
+        }
+
+        throw new NullPointerException("Hi diddly-ho, neighborino.");
+    }
+
+    private static class Helper extends Thread {
+        private int which;
+
+        public Helper(int which) {
+            this.which = which;
+        }
+
+        public void run() {
+            catchTheUncaught(which);
+        }
+    }
+}
diff --git a/tests/054-uncaught/src/ThreadDeathHandler.java b/tests/054-uncaught/src/ThreadDeathHandler.java
new file mode 100644
index 0000000..5ea61a5
--- /dev/null
+++ b/tests/054-uncaught/src/ThreadDeathHandler.java
@@ -0,0 +1,19 @@
+// Copyright 2007 The Android Open Source Project
+
+import java.lang.Thread.UncaughtExceptionHandler;
+
+/**
+ * Report death-by-uncaught-exception.
+ */
+public class ThreadDeathHandler implements Thread.UncaughtExceptionHandler {
+    private String mMyMessage;
+
+    public ThreadDeathHandler(String msg) {
+        mMyMessage = msg;
+    }
+
+    public void uncaughtException(Thread t, Throwable e) {
+        System.err.println("Uncaught exception " + mMyMessage + "!");
+        e.printStackTrace();
+    }
+}
diff --git a/tests/055-enum-performance/expected.txt b/tests/055-enum-performance/expected.txt
new file mode 100644
index 0000000..ceb6bc4
--- /dev/null
+++ b/tests/055-enum-performance/expected.txt
@@ -0,0 +1,12 @@
+FOUR
+ONE
+FOURTEEN
+NINE
+FIVE
+TWELVE
+SamePackagePublicEnum
+basis: performed 10000 iterations
+test1: performed 10000 iterations
+test2: performed 10000 iterations
+test3: performed 10000 iterations
+Timing is acceptable.
diff --git a/tests/055-enum-performance/info.txt b/tests/055-enum-performance/info.txt
new file mode 100644
index 0000000..2ea1b9d
--- /dev/null
+++ b/tests/055-enum-performance/info.txt
@@ -0,0 +1,2 @@
+This is a performance test of Enum.valueOf(). To see the numbers, invoke
+this test with the "--timing" option.
diff --git a/tests/055-enum-performance/src/Main.java b/tests/055-enum-performance/src/Main.java
new file mode 100644
index 0000000..43f45f1
--- /dev/null
+++ b/tests/055-enum-performance/src/Main.java
@@ -0,0 +1,195 @@
+import otherpackage.OtherPackagePublicEnum;
+
+public class Main {
+    /** used by {@link #basisCall} */
+    static private int basisTestValue = 12;
+
+    static public void main(String[] args) throws Exception {
+        boolean timing = (args.length >= 1) && args[0].equals("--timing");
+        run(timing);
+    }
+
+    static public void run(boolean timing) {
+        preTest();
+
+        long time0 = System.nanoTime();
+        int count1 = test1(500);
+        long time1 = System.nanoTime();
+        int count2 = test2(500);
+        long time2 = System.nanoTime();
+        int count3 = test3(500);
+        long time3 = System.nanoTime();
+        int count4 = basis(500);
+        long time4 = System.nanoTime();
+
+        System.out.println("basis: performed " + count4 + " iterations");
+        System.out.println("test1: performed " + count1 + " iterations");
+        System.out.println("test2: performed " + count2 + " iterations");
+        System.out.println("test3: performed " + count3 + " iterations");
+
+        double msec1 = (time1 - time0) / (double) count1 / 1000000;
+        double msec2 = (time2 - time1) / (double) count2 / 1000000;
+        double msec3 = (time3 - time2) / (double) count3 / 1000000;
+        double basisMsec = (time4 - time3) / (double) count4 / 1000000;
+
+        double avg = (msec1 + msec2 + msec3) / 3;
+        if (avg < (basisMsec * 10)) {
+            System.out.println("Timing is acceptable.");
+        } else {
+            System.out.println("Iterations are taking too long!");
+            timing = true;
+        }
+
+        if (timing) {
+            System.out.printf("basis time: %.3g msec\n", basisMsec);
+            System.out.printf("test1: %.3g msec per iteration\n", msec1);
+            System.out.printf("test2: %.3g msec per iteration\n", msec2);
+            System.out.printf("test3: %.3g msec per iteration\n", msec3);
+        }
+
+    }
+
+    static public void preTest() {
+        /*
+         * This is meant to ensure that the basic enum functionality
+         * really is working.
+         */
+
+        Class<SamePackagePublicEnum> c = SamePackagePublicEnum.class;
+
+        System.out.println(Enum.valueOf(c, "FOUR"));
+        System.out.println(Enum.valueOf(c, "ONE"));
+        System.out.println(Enum.valueOf(c, "FOURTEEN"));
+        System.out.println(Enum.valueOf(c, "NINE"));
+        System.out.println(Enum.valueOf(c, "FIVE"));
+        System.out.println(Enum.valueOf(c, "TWELVE"));
+
+        System.out.println(Enum.valueOf(c, "ZERO").getClass().getName());
+    }
+
+    static final String[] BASIS_COMPARE_ARRAY = {
+        "ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT",
+        "NINE", "TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", "FIFTEEN",
+        "SIXTEEN", "SEVENTEEN", "EIGHTEEN", "NINETEEN"
+    };
+
+    static public int basis(int iters) {
+        for (int i = iters; i > 0; i--) {
+            basisValueOf("ZERO");
+            basisValueOf("ONE");
+            basisValueOf("TWO");
+            basisValueOf("THREE");
+            basisValueOf("FOUR");
+            basisValueOf("FIVE");
+            basisValueOf("SIX");
+            basisValueOf("SEVEN");
+            basisValueOf("EIGHT");
+            basisValueOf("NINE");
+            basisValueOf("TEN");
+            basisValueOf("ELEVEN");
+            basisValueOf("TWELVE");
+            basisValueOf("THIRTEEN");
+            basisValueOf("FOURTEEN");
+            basisValueOf("FIFTEEN");
+            basisValueOf("SIXTEEN");
+            basisValueOf("SEVENTEEN");
+            basisValueOf("EIGHTEEN");
+            basisValueOf("NINETEEN");
+        }
+
+        return iters * 20;
+    }
+
+    static String basisValueOf(String key) {
+        for (String s : BASIS_COMPARE_ARRAY) {
+            if (s.equals(key)) {
+                return s;
+            }
+        }
+        throw new IllegalArgumentException();
+    }
+
+    static public int test1(int iters) {
+        Class<SamePackagePublicEnum> c = SamePackagePublicEnum.class;
+        for (int i = iters; i > 0; i--) {
+            Enum.valueOf(c, "ZERO");
+            Enum.valueOf(c, "ONE");
+            Enum.valueOf(c, "TWO");
+            Enum.valueOf(c, "THREE");
+            Enum.valueOf(c, "FOUR");
+            Enum.valueOf(c, "FIVE");
+            Enum.valueOf(c, "SIX");
+            Enum.valueOf(c, "SEVEN");
+            Enum.valueOf(c, "EIGHT");
+            Enum.valueOf(c, "NINE");
+            Enum.valueOf(c, "TEN");
+            Enum.valueOf(c, "ELEVEN");
+            Enum.valueOf(c, "TWELVE");
+            Enum.valueOf(c, "THIRTEEN");
+            Enum.valueOf(c, "FOURTEEN");
+            Enum.valueOf(c, "FIFTEEN");
+            Enum.valueOf(c, "SIXTEEN");
+            Enum.valueOf(c, "SEVENTEEN");
+            Enum.valueOf(c, "EIGHTEEN");
+            Enum.valueOf(c, "NINETEEN");
+        }
+
+        return iters * 20;
+    }
+
+    static public int test2(int iters) {
+        Class<SamePackagePrivateEnum> c = SamePackagePrivateEnum.class;
+        for (int i = iters; i > 0; i--) {
+            Enum.valueOf(c, "ZERO");
+            Enum.valueOf(c, "ONE");
+            Enum.valueOf(c, "TWO");
+            Enum.valueOf(c, "THREE");
+            Enum.valueOf(c, "FOUR");
+            Enum.valueOf(c, "FIVE");
+            Enum.valueOf(c, "SIX");
+            Enum.valueOf(c, "SEVEN");
+            Enum.valueOf(c, "EIGHT");
+            Enum.valueOf(c, "NINE");
+            Enum.valueOf(c, "TEN");
+            Enum.valueOf(c, "ELEVEN");
+            Enum.valueOf(c, "TWELVE");
+            Enum.valueOf(c, "THIRTEEN");
+            Enum.valueOf(c, "FOURTEEN");
+            Enum.valueOf(c, "FIFTEEN");
+            Enum.valueOf(c, "SIXTEEN");
+            Enum.valueOf(c, "SEVENTEEN");
+            Enum.valueOf(c, "EIGHTEEN");
+            Enum.valueOf(c, "NINETEEN");
+        }
+
+        return iters * 20;
+    }
+
+    static public int test3(int iters) {
+        Class<OtherPackagePublicEnum> c = OtherPackagePublicEnum.class;
+        for (int i = iters; i > 0; i--) {
+            Enum.valueOf(c, "ZERO");
+            Enum.valueOf(c, "ONE");
+            Enum.valueOf(c, "TWO");
+            Enum.valueOf(c, "THREE");
+            Enum.valueOf(c, "FOUR");
+            Enum.valueOf(c, "FIVE");
+            Enum.valueOf(c, "SIX");
+            Enum.valueOf(c, "SEVEN");
+            Enum.valueOf(c, "EIGHT");
+            Enum.valueOf(c, "NINE");
+            Enum.valueOf(c, "TEN");
+            Enum.valueOf(c, "ELEVEN");
+            Enum.valueOf(c, "TWELVE");
+            Enum.valueOf(c, "THIRTEEN");
+            Enum.valueOf(c, "FOURTEEN");
+            Enum.valueOf(c, "FIFTEEN");
+            Enum.valueOf(c, "SIXTEEN");
+            Enum.valueOf(c, "SEVENTEEN");
+            Enum.valueOf(c, "EIGHTEEN");
+            Enum.valueOf(c, "NINETEEN");
+        }
+
+        return iters * 20;
+    }
+}
diff --git a/tests/055-enum-performance/src/SamePackagePrivateEnum.java b/tests/055-enum-performance/src/SamePackagePrivateEnum.java
new file mode 100644
index 0000000..b6759f6
--- /dev/null
+++ b/tests/055-enum-performance/src/SamePackagePrivateEnum.java
@@ -0,0 +1,5 @@
+/*package*/ enum SamePackagePrivateEnum {
+    ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
+        TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN, SIXTEEN,
+        SEVENTEEN, EIGHTEEN, NINETEEN;
+}
diff --git a/tests/055-enum-performance/src/SamePackagePublicEnum.java b/tests/055-enum-performance/src/SamePackagePublicEnum.java
new file mode 100644
index 0000000..3a1c230
--- /dev/null
+++ b/tests/055-enum-performance/src/SamePackagePublicEnum.java
@@ -0,0 +1,5 @@
+public enum SamePackagePublicEnum {
+    ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
+        TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN, SIXTEEN,
+        SEVENTEEN, EIGHTEEN, NINETEEN;
+}
diff --git a/tests/055-enum-performance/src/otherpackage/OtherPackagePublicEnum.java b/tests/055-enum-performance/src/otherpackage/OtherPackagePublicEnum.java
new file mode 100644
index 0000000..4ef4d78
--- /dev/null
+++ b/tests/055-enum-performance/src/otherpackage/OtherPackagePublicEnum.java
@@ -0,0 +1,7 @@
+package otherpackage;
+
+public enum OtherPackagePublicEnum {
+    ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
+        TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN, SIXTEEN,
+        SEVENTEEN, EIGHTEEN, NINETEEN;
+}
diff --git a/tests/056-const-string-jumbo/build b/tests/056-const-string-jumbo/build
new file mode 100644
index 0000000..c5e35db
--- /dev/null
+++ b/tests/056-const-string-jumbo/build
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# 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.
+
+# Stop if something fails.
+set -e
+
+# Write out files with 32768 total static string declarations, so that
+# the reference to "zorch" in the real test file will be guaranteed to
+# need a jumbo string reference (it sorts last after all the others).
+# Note: Each string reference is stored in a separate static variable,
+# and that variable's name is also represented in the strings, which
+# is why we can just have 32768 and not 65536 declarations.
+
+awk '
+BEGIN {
+    writeFile("Zorch1", 0, 16383);
+    writeFile("Zorch2", 16384, 32767);
+}
+function writeFile(name, start, end) {
+    fileName = "src/" name ".java";
+    printf("public class %s {\n", name) > fileName;
+    for (i = start; i <= end; i++) {
+        printf("    static public final String s%d = \"%d\";\n",
+            i, i) > fileName;
+    }
+    printf("}\n") > fileName;
+}'
+
+mkdir classes
+${JAVAC} -d classes src/*.java
+
+dx -JXmx500m --debug --dex --no-optimize --positions=none --no-locals \
+    --dump-to=classes.lst --output=classes.dex classes
+zip test.jar classes.dex
diff --git a/tests/056-const-string-jumbo/expected.txt b/tests/056-const-string-jumbo/expected.txt
new file mode 100644
index 0000000..bebbf9e
--- /dev/null
+++ b/tests/056-const-string-jumbo/expected.txt
@@ -0,0 +1 @@
+zorch
diff --git a/tests/056-const-string-jumbo/info.txt b/tests/056-const-string-jumbo/info.txt
new file mode 100644
index 0000000..c4ba856
--- /dev/null
+++ b/tests/056-const-string-jumbo/info.txt
@@ -0,0 +1 @@
+Test that the opcode const-string/jumbo works.
diff --git a/tests/056-const-string-jumbo/src/Main.java b/tests/056-const-string-jumbo/src/Main.java
new file mode 100644
index 0000000..68d6e53
--- /dev/null
+++ b/tests/056-const-string-jumbo/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public class Main {
+    static public void main(String[] args) {
+        System.out.println("zorch");
+    }
+}
diff --git a/tests/058-enum-order/expected.txt b/tests/058-enum-order/expected.txt
new file mode 100644
index 0000000..b812404
--- /dev/null
+++ b/tests/058-enum-order/expected.txt
@@ -0,0 +1,5 @@
+0: CORN
+1: BLUEBERRY
+2: CRANBERRY
+3: BRAN
+4: BLACKBERRY
diff --git a/tests/058-enum-order/info.txt b/tests/058-enum-order/info.txt
new file mode 100644
index 0000000..b9809fd
--- /dev/null
+++ b/tests/058-enum-order/info.txt
@@ -0,0 +1 @@
+Test that the ordering of enums is as expected.
diff --git a/tests/058-enum-order/src/Main.java b/tests/058-enum-order/src/Main.java
new file mode 100644
index 0000000..2cd6052
--- /dev/null
+++ b/tests/058-enum-order/src/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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 enum ordering.
+ */
+public class Main {
+    public static enum Muffin {
+        CORN, BLUEBERRY, CRANBERRY, BRAN, BLACKBERRY;
+    }
+
+    public static void main(String args[]) {
+        Muffin[] array = Muffin.class.getEnumConstants();
+        for (Muffin m : array) {
+            System.out.println(m.ordinal() + ": " + m);
+        }
+    }
+}
diff --git a/tests/059-finalizer-throw/expected.txt b/tests/059-finalizer-throw/expected.txt
new file mode 100644
index 0000000..cbc9ece
--- /dev/null
+++ b/tests/059-finalizer-throw/expected.txt
@@ -0,0 +1,2 @@
+In finalizer
+done
diff --git a/tests/059-finalizer-throw/info.txt b/tests/059-finalizer-throw/info.txt
new file mode 100644
index 0000000..6261372
--- /dev/null
+++ b/tests/059-finalizer-throw/info.txt
@@ -0,0 +1 @@
+Verify that exceptions thrown from finalizers are ignored.
diff --git a/tests/059-finalizer-throw/src/Main.java b/tests/059-finalizer-throw/src/Main.java
new file mode 100644
index 0000000..42260e4
--- /dev/null
+++ b/tests/059-finalizer-throw/src/Main.java
@@ -0,0 +1,56 @@
+// Copyright 2008 The Android Open Source Project
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/*
+ * Throw an exception from a finalizer and make sure it's harmless.  Under
+ * Dalvik this may also generate a warning in the log file.
+ */
+public class Main {
+    static Object waiter = new Object();
+    static volatile boolean didFinal = false;
+
+    static void createAndForget() {
+        Main main = new Main();
+    }
+
+    public static void main(String[] args) {
+        createAndForget();
+
+        System.gc();
+        System.runFinalization();
+
+        new Timer(true).schedule(new TimerTask() {
+                public void run() {
+                    System.out.println("Timed out, exiting");
+                    System.exit(1);
+                }
+            }, 30000);
+
+        while (!didFinal) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException ie) {
+                System.err.println(ie);
+            }
+        }
+
+        /* give it a chance to cause mayhem */
+        try {
+            Thread.sleep(750);
+        } catch (InterruptedException ie) {
+            System.err.println(ie);
+        }
+
+        System.out.println("done");
+    }
+
+    protected void finalize() throws Throwable {
+        System.out.println("In finalizer");
+
+        didFinal = true;
+
+        throw new InterruptedException("whee");
+    }
+}
diff --git a/tests/061-out-of-memory/expected.txt b/tests/061-out-of-memory/expected.txt
new file mode 100644
index 0000000..ca87629
--- /dev/null
+++ b/tests/061-out-of-memory/expected.txt
@@ -0,0 +1,7 @@
+tests beginning
+Got expected huge-array OOM
+testOomeLarge beginning
+testOomeLarge succeeded
+testOomeSmall beginning
+testOomeSmall succeeded
+tests succeeded
diff --git a/tests/061-out-of-memory/info.txt b/tests/061-out-of-memory/info.txt
new file mode 100644
index 0000000..523f3a2
--- /dev/null
+++ b/tests/061-out-of-memory/info.txt
@@ -0,0 +1 @@
+Tests the various ways that an OutOfMemoryError can be constructed and thrown.
diff --git a/tests/061-out-of-memory/src/Main.java b/tests/061-out-of-memory/src/Main.java
new file mode 100644
index 0000000..b5999b3
--- /dev/null
+++ b/tests/061-out-of-memory/src/Main.java
@@ -0,0 +1,117 @@
+/*
+ * 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.util.Arrays;
+import java.util.LinkedList;
+
+/**
+ * Exercise the construction and throwing of OutOfMemoryError.
+ */
+public class Main {
+    public static void main(String args[]) {
+        System.out.println("tests beginning");
+        testHugeArray();
+        testOomeLarge();
+        testOomeSmall();
+        System.out.println("tests succeeded");
+    }
+
+    private static void testHugeArray() {
+        try {
+            final int COUNT = 32768*32768 + 4;
+            int[] tooBig = new int[COUNT];
+
+            Arrays.fill(tooBig, 0xdd);
+        } catch (OutOfMemoryError oom) {
+            System.out.println("Got expected huge-array OOM");
+        }
+    }
+
+    private static void testOomeLarge() {
+        System.out.println("testOomeLarge beginning");
+
+        /* Just shy of the typical max heap size so that it will actually
+         * try to allocate it instead of short-circuiting.
+         *
+         * TODO: stop assuming the VM defaults to 16MB max
+         */
+        final int SIXTEEN_MB = (16 * 1024 * 1024 - 32);
+
+        Boolean sawEx = false;
+        byte a[];
+
+        try {
+            a = new byte[SIXTEEN_MB];
+        } catch (OutOfMemoryError oom) {
+            //Log.i(TAG, "HeapTest/OomeLarge caught " + oom);
+            sawEx = true;
+        }
+
+        if (!sawEx) {
+            throw new RuntimeException("Test failed: " +
+                    "OutOfMemoryError not thrown");
+        }
+
+        System.out.println("testOomeLarge succeeded");
+    }
+
+    /* Do this in another method so that the GC has a chance of freeing the
+     * list afterwards.  Even if we null out list when we're done, the conservative
+     * GC may see a stale pointer to it in a register.
+     *
+     * TODO: stop assuming the VM defaults to 16MB max
+     */
+    private static boolean testOomeSmallInternal() {
+        final int SIXTEEN_MB = (16 * 1024 * 1024);
+        final int LINK_SIZE = 6 * 4; // estimated size of a LinkedList's node
+
+        LinkedList<Object> list = new LinkedList<Object>();
+
+        /* Allocate progressively smaller objects to fill up the entire heap.
+         */
+        int objSize = 1 * 1024 * 1024;
+        while (objSize >= LINK_SIZE) {
+            boolean sawEx = false;
+            try {
+                for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
+                    list.add((Object)new byte[objSize]);
+                }
+            } catch (OutOfMemoryError oom) {
+                sawEx = true;
+            }
+
+            if (!sawEx) {
+                return false;
+            }
+
+            objSize = (objSize * 4) / 5;
+        }
+
+        return true;
+    }
+
+    private static void testOomeSmall() {
+        System.out.println("testOomeSmall beginning");
+        if (!testOomeSmallInternal()) {
+            /* Can't reliably throw this from inside the internal function, because
+             * we may not be able to allocate the RuntimeException.
+             */
+            throw new RuntimeException("Test failed: " +
+                    "OutOfMemoryError not thrown while filling heap");
+        }
+        System.out.println("testOomeSmall succeeded");
+    }
+}
diff --git a/tests/062-character-encodings/expected.txt b/tests/062-character-encodings/expected.txt
new file mode 100644
index 0000000..b395a2a
--- /dev/null
+++ b/tests/062-character-encodings/expected.txt
@@ -0,0 +1 @@
+Missing: []
diff --git a/tests/062-character-encodings/info.txt b/tests/062-character-encodings/info.txt
new file mode 100644
index 0000000..bdf60bf
--- /dev/null
+++ b/tests/062-character-encodings/info.txt
@@ -0,0 +1 @@
+Test that the list of character encodings is what we expect.
diff --git a/tests/062-character-encodings/src/Main.java b/tests/062-character-encodings/src/Main.java
new file mode 100644
index 0000000..6e9f0cd
--- /dev/null
+++ b/tests/062-character-encodings/src/Main.java
@@ -0,0 +1,25 @@
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.Set;
+
+public class Main {
+    static public void main(String[] args) throws Exception {
+        // These charsets must be provided; anything else is optional.
+        List<String> standardCharsets = Arrays.asList("US-ASCII", "ISO-8859-1",
+                "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16");
+
+        SortedMap<String, Charset> all = Charset.availableCharsets();
+        Set<String> needed = new HashSet<String>(standardCharsets);
+        for (Map.Entry<String, Charset> e : all.entrySet()) {
+            String canonicalName = e.getKey();
+            needed.remove(canonicalName);
+        }
+        System.out.println("Missing: " + needed);
+    }
+}
diff --git a/tests/063-process-manager/expected.txt b/tests/063-process-manager/expected.txt
new file mode 100644
index 0000000..8360239
--- /dev/null
+++ b/tests/063-process-manager/expected.txt
@@ -0,0 +1,15 @@
+process manager: nonexistent
+
+spawning child #1
+spawning child
+process manager: RUNNABLE
+child died
+process manager: WAITING
+
+spawning child #2
+spawning child
+process manager: RUNNABLE
+child died
+process manager: WAITING
+
+done!
diff --git a/tests/063-process-manager/info.txt b/tests/063-process-manager/info.txt
new file mode 100644
index 0000000..e5907c4
--- /dev/null
+++ b/tests/063-process-manager/info.txt
@@ -0,0 +1,2 @@
+Test that spawning a child process and then reaping it (a) works and (b)
+doesn't cause the system to busy-wait.
diff --git a/tests/063-process-manager/src/Main.java b/tests/063-process-manager/src/Main.java
new file mode 100644
index 0000000..c94b8ad
--- /dev/null
+++ b/tests/063-process-manager/src/Main.java
@@ -0,0 +1,43 @@
+import java.util.Map;
+
+public class Main {
+    static public void main(String[] args) throws Exception {
+        checkManager();
+        for (int i = 1; i <= 2; i++) {
+            System.out.println("\nspawning child #" + i);
+            child();
+            Thread.sleep(2000);
+            checkManager();
+        }
+        System.out.println("\ndone!");
+    }
+
+    static private void child() throws Exception {
+        System.out.println("spawning child");
+        ProcessBuilder pb = new ProcessBuilder("/system/bin/sleep", "5");
+        Process proc = pb.start();
+        Thread.sleep(1000);
+        checkManager();
+        proc.waitFor();
+        System.out.println("child died");
+    }
+
+    static private void checkManager() {
+        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+        boolean found = false;
+
+        for (Map.Entry<Thread, StackTraceElement[]> entry :
+                 traces.entrySet()) {
+            Thread t = entry.getKey();
+            String name = t.getName();
+            if (name.equals("java.lang.ProcessManager")) {
+                System.out.println("process manager: " + t.getState());
+                found = true;
+            }
+        }
+
+        if (! found) {
+            System.out.println("process manager: nonexistent");
+        }
+    }
+}
diff --git a/tests/064-field-access/expected.txt b/tests/064-field-access/expected.txt
new file mode 100644
index 0000000..0af56ba
--- /dev/null
+++ b/tests/064-field-access/expected.txt
@@ -0,0 +1,2 @@
+good
+Got expected failure
diff --git a/tests/064-field-access/info.txt b/tests/064-field-access/info.txt
new file mode 100644
index 0000000..442baf2
--- /dev/null
+++ b/tests/064-field-access/info.txt
@@ -0,0 +1,10 @@
+The documentation lists exceptional conditions and the exceptions that
+should be thrown, but doesn't say which exception previals when two or
+more exceptional conditions exist at the same time.  For example,
+attempting to set a protected field from an unrelated class causes an
+IllegalAccessException, while passing in a data type that doesn't match
+the field causes an IllegalArgumentException.  If code does both at the
+same time, we can only throw one or the other.
+
+This exercises the various failure modes to ensure that behavior is
+equivalent, and not merely spec-compliant.
diff --git a/tests/064-field-access/src/GetNonexistent.java b/tests/064-field-access/src/GetNonexistent.java
new file mode 100644
index 0000000..faad686
--- /dev/null
+++ b/tests/064-field-access/src/GetNonexistent.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 class GetNonexistent {
+    public static void main(String[] args) {
+        Object obj = Holder.mObject;
+    }
+}
diff --git a/tests/064-field-access/src/Holder.java b/tests/064-field-access/src/Holder.java
new file mode 100644
index 0000000..5e34024
--- /dev/null
+++ b/tests/064-field-access/src/Holder.java
@@ -0,0 +1,19 @@
+/*
+ * 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 Holder {
+    public static Object mObject = new Object();
+}
diff --git a/tests/064-field-access/src/Main.java b/tests/064-field-access/src/Main.java
new file mode 100644
index 0000000..c068d23
--- /dev/null
+++ b/tests/064-field-access/src/Main.java
@@ -0,0 +1,345 @@
+/*
+ * 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 other.OtherPackage;
+
+import java.lang.reflect.Field;
+
+/*
+ * Test field access through reflection.
+ */
+public class Main {
+    public static void main(String[] args) {
+        SubOther.main(null);
+
+        try {
+            GetNonexistent.main(null);
+            System.err.println("Not expected to succeed");
+        } catch (VerifyError fe) {
+            // dalvik
+            System.out.println("Got expected failure");
+        } catch (NoSuchFieldError nsfe) {
+            // reference
+            System.out.println("Got expected failure");
+        }
+    }
+
+    /*
+     * Get the field specified by "field" from "obj".
+     *
+     * "type" determines which "get" call is made, e.g. 'B' turns into
+     * field.getByte().
+     *
+     * The "expectedException" must match the class of the exception thrown,
+     * or be null if no exception was expected.
+     *
+     * On success, the boxed value retrieved is returned.
+     */
+    public Object getValue(Field field, Object obj, char type,
+            Class expectedException) {
+
+        Object result = null;
+        try {
+            switch (type) {
+            case 'Z':
+                result = new Boolean(field.getBoolean(obj));
+                break;
+            case 'B':
+                result = new Byte(field.getByte(obj));
+                break;
+            case 'S':
+                result = new Short(field.getShort(obj));
+                break;
+            case 'C':
+                result = new Character(field.getChar(obj));
+                break;
+            case 'I':
+                result = new Integer(field.getInt(obj));
+                break;
+            case 'J':
+                result = new Long(field.getLong(obj));
+                break;
+            case 'F':
+                result = new Float(field.getFloat(obj));
+                break;
+            case 'D':
+                result = new Double(field.getDouble(obj));
+                break;
+            case 'L':
+                result = field.get(obj);
+                break;
+            default:
+                throw new RuntimeException("bad type '" + type + "'");
+            }
+
+            /* success; expected? */
+            if (expectedException != null) {
+                Throwable th = new Throwable();
+                System.err.println("ERROR: call succeeded, was expecting "
+                    + expectedException);
+                th.printStackTrace();
+            }
+        } catch (Exception ex) {
+            if (expectedException == null) {
+                System.err.println("ERROR: call failed unexpectedly: "
+                    + ex.getClass());
+                ex.printStackTrace();
+            } else {
+                if (!expectedException.equals(ex.getClass())) {
+                    System.err.println("ERROR: incorrect exception: wanted "
+                        + expectedException.getName() + ", got "
+                        + ex.getClass());
+                    ex.printStackTrace();
+                }
+            }
+        }
+
+        return result;
+    }
+}
+
+/*
+ * Local class with some fields.
+ */
+class SamePackage {
+    public byte pubByteField;
+
+    protected byte protByteField;
+    protected Object protObjectField;
+
+    private float privFloatField;
+}
+
+/*
+ * This is a sub-class of OtherPackage, which should be allowed to access
+ * the various protected fields.
+ */
+class SubOther extends OtherPackage {
+
+    protected long protLongField = 0x1122334455667788L;
+
+    /*
+     * Perform the various tests.
+     *
+     * localInst.getValue() is performed using an instance of Main as the
+     * source of the reflection call.  otherInst.getValue() uses a subclass
+     * of OtherPackage as the source.
+     */
+    public static void main(String[] args) {
+        SubOther subOther = new SubOther();
+        subOther.doTests();
+    }
+
+    public void doTests() {
+        Class localClass = SamePackage.class;
+        Class otherClass = OtherPackage.class;
+        Field localPubByteField, localProtByteField, localProtObjectField,
+              localPrivFloatField;
+        Field otherPubCharField, otherProtShortField, otherProtObjectField,
+              otherPkgDoubleField;
+        Field subProtLongField;
+        Main localInst = new Main();
+        SamePackage samePkgInst = new SamePackage();
+        OtherPackage otherPkgInst = new OtherPackage();
+        Object plainObj = new Object();
+
+        /*
+         * Locate the various fields.
+         */
+        try {
+            localPubByteField = localClass.getDeclaredField("pubByteField");
+            localProtByteField = localClass.getDeclaredField("protByteField");
+            localProtObjectField = localClass.getDeclaredField("protObjectField");
+            localPrivFloatField = localClass.getDeclaredField("privFloatField");
+
+            otherPubCharField = otherClass.getDeclaredField("pubCharField");
+            otherProtShortField = otherClass.getDeclaredField("protShortField");
+            otherProtObjectField = otherClass.getDeclaredField("protObjectField");
+            otherPkgDoubleField = otherClass.getDeclaredField("pkgDoubleField");
+
+            subProtLongField = getClass().getDeclaredField("protLongField");
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        }
+
+        /*
+         * Get a public field from a class in the same package.
+         */
+        localInst.getValue(localPubByteField, samePkgInst, 'B', null);
+
+        /*
+         * Get a protected field from a class in the same package.
+         */
+        this.getValue(localProtByteField, samePkgInst, 'B', null);
+
+        /*
+         * Get a private field from a class in the same package.
+         */
+        this.getValue(localPrivFloatField, samePkgInst, 'F',
+            IllegalAccessException.class);
+
+        /*
+         * Get a protected field from otherInst's superclass.
+         *
+         * We can get at "this.protShortField" but not
+         * "otherPkgInst.protShortField" because we can only access
+         * protected fields in instances of our class -- being a subclass
+         * of OtherPackage does not allow us to modify protected fields in
+         * all other subclasses of OtherPackage.
+         */
+        this.getValue(otherProtShortField, this, 'S',
+            null);
+        this.getValue(otherProtShortField, otherPkgInst, 'S',
+            IllegalAccessException.class);
+        this.getValue(otherPkgDoubleField, otherPkgInst, 'D',
+            IllegalAccessException.class);
+
+        /*
+         * Null object.  Different exceptions based on which package
+         * we would be trying to access and whether or not our object
+         * has the correct type.
+         */
+        localInst.getValue(localPubByteField, null, 'B',
+            NullPointerException.class);
+
+        this.getValue(subProtLongField, null, 'J',
+            NullPointerException.class);
+
+        this.getValue(localPrivFloatField, null, 'F',
+            IllegalAccessException.class);
+
+        localInst.getValue(otherProtShortField, null, 'S',
+            IllegalAccessException.class);
+        this.getValue(otherProtShortField, null, 'S',
+            IllegalAccessException.class);
+        this.getValue(otherPkgDoubleField, null, 'D',
+            IllegalAccessException.class);
+
+        localInst.getValue(otherProtShortField, null, 'Z',
+            IllegalAccessException.class);
+        /* -- Dalvik VM currently throws NPE
+        this.getValue(subProtLongField, null, 'Z',
+            IllegalArgumentException.class);
+        */
+
+        /*
+         * Valid object, wrong field type.
+         */
+        this.getValue(subProtLongField, this, 'J',
+            null);
+        this.getValue(localProtByteField, samePkgInst, 'Z',
+            IllegalArgumentException.class);
+        this.getValue(subProtLongField, this, 'Z',
+            IllegalArgumentException.class);
+        this.getValue(localPrivFloatField, this, 'Z',
+            IllegalAccessException.class);
+        this.getValue(localPrivFloatField, this, 'Z',
+            IllegalAccessException.class);
+        localInst.getValue(otherProtShortField, otherPkgInst, 'Z',
+            IllegalAccessException.class);
+        this.getValue(otherProtShortField, otherPkgInst, 'Z',
+            IllegalAccessException.class);
+
+        /*
+         * Wrong object.
+         */
+        this.getValue(subProtLongField, plainObj, 'J',
+            IllegalArgumentException.class);
+
+        /* wrong object + private field */
+        this.getValue(localPrivFloatField, plainObj, 'F',
+            IllegalAccessException.class);
+
+        /* wrong object + wrong field type */
+        this.getValue(subProtLongField, plainObj, 'Z',
+            IllegalArgumentException.class);
+
+        /* wrong object + invalid access */
+        localInst.getValue(otherProtShortField, plainObj, 'S',
+            IllegalAccessException.class);
+        this.getValue(otherProtShortField, plainObj, 'S',
+            IllegalAccessException.class);
+
+        System.out.println("good");
+    }
+
+    /*
+     * [this is a clone of Main.getValue() -- the class issuing the
+     * reflection call is significant]
+     */
+    public Object getValue(Field field, Object obj, char type,
+            Class expectedException) {
+
+        Object result = null;
+        try {
+            switch (type) {
+            case 'Z':
+                result = new Boolean(field.getBoolean(obj));
+                break;
+            case 'B':
+                result = new Byte(field.getByte(obj));
+                break;
+            case 'S':
+                result = new Short(field.getShort(obj));
+                break;
+            case 'C':
+                result = new Character(field.getChar(obj));
+                break;
+            case 'I':
+                result = new Integer(field.getInt(obj));
+                break;
+            case 'J':
+                result = new Long(field.getLong(obj));
+                break;
+            case 'F':
+                result = new Float(field.getFloat(obj));
+                break;
+            case 'D':
+                result = new Double(field.getDouble(obj));
+                break;
+            case 'L':
+                result = field.get(obj);
+                break;
+            default:
+                throw new RuntimeException("bad type '" + type + "'");
+            }
+
+            /* success; expected? */
+            if (expectedException != null) {
+                Throwable th = new Throwable();
+                System.err.println("ERROR: call succeeded, was expecting "
+                    + expectedException);
+                th.printStackTrace();
+            }
+        } catch (Exception ex) {
+            if (expectedException == null) {
+                System.err.println("ERROR: call failed unexpectedly: "
+                    + ex.getClass());
+                ex.printStackTrace();
+            } else {
+                if (!expectedException.equals(ex.getClass())) {
+                    System.err.println("ERROR: incorrect exception: wanted "
+                        + expectedException.getName() + ", got "
+                        + ex.getClass());
+                    ex.printStackTrace();
+                }
+            }
+        }
+
+        return result;
+    }
+
+}
diff --git a/tests/064-field-access/src/other/OtherPackage.java b/tests/064-field-access/src/other/OtherPackage.java
new file mode 100644
index 0000000..a595db5
--- /dev/null
+++ b/tests/064-field-access/src/other/OtherPackage.java
@@ -0,0 +1,15 @@
+// Copyright 2008 The Android Open Source Project
+
+package other;
+
+/*
+ * Declare a few fields to reflect upon.
+ */
+public class OtherPackage {
+    public char pubCharField = 0x8765;
+
+    protected short protShortField = 0x1234;
+    protected Object protObjectField = "blah";
+
+    double pkgDoubleField = 3.141592654;
+}
diff --git a/tests/064-field-access/src2/Holder.java b/tests/064-field-access/src2/Holder.java
new file mode 100644
index 0000000..28224d7
--- /dev/null
+++ b/tests/064-field-access/src2/Holder.java
@@ -0,0 +1,19 @@
+/*
+ * 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 Holder {
+    //public static Object mObject = new Object();
+}
diff --git a/tests/065-mismatched-implements/expected.txt b/tests/065-mismatched-implements/expected.txt
new file mode 100644
index 0000000..09c0596
--- /dev/null
+++ b/tests/065-mismatched-implements/expected.txt
@@ -0,0 +1 @@
+Got expected ICCE
diff --git a/tests/065-mismatched-implements/info.txt b/tests/065-mismatched-implements/info.txt
new file mode 100644
index 0000000..74c3ff3
--- /dev/null
+++ b/tests/065-mismatched-implements/info.txt
@@ -0,0 +1,2 @@
+This tests what happens when class A implements interface B, but somebody
+turns B into an abstract class without rebuilding A.
diff --git a/tests/065-mismatched-implements/src/Base.java b/tests/065-mismatched-implements/src/Base.java
new file mode 100644
index 0000000..8623ad7
--- /dev/null
+++ b/tests/065-mismatched-implements/src/Base.java
@@ -0,0 +1,7 @@
+// Copyright 2008 The Android Open Source Project
+
+public class Base implements Defs {
+    public void func() {
+        System.out.println("whee");
+    }
+};
diff --git a/tests/065-mismatched-implements/src/Defs.java b/tests/065-mismatched-implements/src/Defs.java
new file mode 100644
index 0000000..bab92d8
--- /dev/null
+++ b/tests/065-mismatched-implements/src/Defs.java
@@ -0,0 +1,7 @@
+// Copyright 2008 The Android Open Source Project
+
+public interface Defs {
+    public void func();
+
+    // func2 not defined
+}
diff --git a/tests/065-mismatched-implements/src/Indirect.java b/tests/065-mismatched-implements/src/Indirect.java
new file mode 100644
index 0000000..023e409
--- /dev/null
+++ b/tests/065-mismatched-implements/src/Indirect.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.
+ */
+
+/**
+ * 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
new file mode 100644
index 0000000..5975b99
--- /dev/null
+++ b/tests/065-mismatched-implements/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * 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) {
+        try {
+            Indirect.main();
+            System.err.println("Succeeded unexpectedly");
+        } catch (IncompatibleClassChangeError icce) {
+            System.out.println("Got expected ICCE");
+        }
+    }
+}
diff --git a/tests/065-mismatched-implements/src2/Defs.java b/tests/065-mismatched-implements/src2/Defs.java
new file mode 100644
index 0000000..e7eb8a1
--- /dev/null
+++ b/tests/065-mismatched-implements/src2/Defs.java
@@ -0,0 +1,11 @@
+// Copyright 2008 The Android Open Source Project
+
+public abstract class Defs {
+    public void func() {
+        System.out.println("yo");
+    }
+
+    public void func2() {
+        System.out.println("yo yo");
+    }
+}
diff --git a/tests/066-mismatched-super/expected.txt b/tests/066-mismatched-super/expected.txt
new file mode 100644
index 0000000..09c0596
--- /dev/null
+++ b/tests/066-mismatched-super/expected.txt
@@ -0,0 +1 @@
+Got expected ICCE
diff --git a/tests/066-mismatched-super/info.txt b/tests/066-mismatched-super/info.txt
new file mode 100644
index 0000000..7865ffc
--- /dev/null
+++ b/tests/066-mismatched-super/info.txt
@@ -0,0 +1,2 @@
+This tests what happens when class A extends abstract class B, but somebody
+turns B into an interface without rebuilding A.
diff --git a/tests/066-mismatched-super/src/Base.java b/tests/066-mismatched-super/src/Base.java
new file mode 100644
index 0000000..6180c8b
--- /dev/null
+++ b/tests/066-mismatched-super/src/Base.java
@@ -0,0 +1,5 @@
+// Copyright 2008 The Android Open Source Project
+
+public class Base extends Defs {
+    // no need to implement func(), provided by abstract class
+};
diff --git a/tests/066-mismatched-super/src/Defs.java b/tests/066-mismatched-super/src/Defs.java
new file mode 100644
index 0000000..e7eb8a1
--- /dev/null
+++ b/tests/066-mismatched-super/src/Defs.java
@@ -0,0 +1,11 @@
+// Copyright 2008 The Android Open Source Project
+
+public abstract class Defs {
+    public void func() {
+        System.out.println("yo");
+    }
+
+    public void func2() {
+        System.out.println("yo yo");
+    }
+}
diff --git a/tests/066-mismatched-super/src/Indirect.java b/tests/066-mismatched-super/src/Indirect.java
new file mode 100644
index 0000000..023e409
--- /dev/null
+++ b/tests/066-mismatched-super/src/Indirect.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.
+ */
+
+/**
+ * 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
new file mode 100644
index 0000000..5975b99
--- /dev/null
+++ b/tests/066-mismatched-super/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * 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) {
+        try {
+            Indirect.main();
+            System.err.println("Succeeded unexpectedly");
+        } catch (IncompatibleClassChangeError icce) {
+            System.out.println("Got expected ICCE");
+        }
+    }
+}
diff --git a/tests/066-mismatched-super/src2/Defs.java b/tests/066-mismatched-super/src2/Defs.java
new file mode 100644
index 0000000..bab92d8
--- /dev/null
+++ b/tests/066-mismatched-super/src2/Defs.java
@@ -0,0 +1,7 @@
+// Copyright 2008 The Android Open Source Project
+
+public interface Defs {
+    public void func();
+
+    // func2 not defined
+}
diff --git a/tests/067-preemptive-unpark/expected.txt b/tests/067-preemptive-unpark/expected.txt
new file mode 100644
index 0000000..12bfee0
--- /dev/null
+++ b/tests/067-preemptive-unpark/expected.txt
@@ -0,0 +1,5 @@
+Test starting
+GC'ing
+Asking thread to park
+park() returned quickly
+Test succeeded!
diff --git a/tests/067-preemptive-unpark/info.txt b/tests/067-preemptive-unpark/info.txt
new file mode 100644
index 0000000..0bc0c61
--- /dev/null
+++ b/tests/067-preemptive-unpark/info.txt
@@ -0,0 +1 @@
+Test that Unsafe.unpark() operates as expected, in particular across a gc.
diff --git a/tests/067-preemptive-unpark/src/Main.java b/tests/067-preemptive-unpark/src/Main.java
new file mode 100644
index 0000000..a16219e
--- /dev/null
+++ b/tests/067-preemptive-unpark/src/Main.java
@@ -0,0 +1,107 @@
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class Main {
+    private static Unsafe UNSAFE;
+
+    public static void main(String[] args) throws Exception {
+        setUp();
+
+        ParkTester test = new ParkTester();
+
+        System.out.println("Test starting");
+
+        test.start();
+        UNSAFE.unpark(test);
+        clearStack(10);
+
+        System.out.println("GC'ing");
+        System.gc();
+        System.gc();
+
+        System.out.println("Asking thread to park");
+        test.parkNow = true;
+
+        try {
+            Thread.sleep(1500);
+        } catch (InterruptedException ex) {
+            // Ignore it.
+        }
+
+        if (test.success) {
+            System.out.println("Test succeeded!");
+        } else {
+            System.out.println("Test failed.");
+        }
+    }
+
+    /**
+     * Set up {@link #UNSAFE}.
+     */
+    public static void setUp() {
+        /*
+         * Subvert the access check to get the unique Unsafe instance.
+         * We can do this because there's no security manager
+         * installed when running the test.
+         */
+        try {
+            Field field = Unsafe.class.getDeclaredField("THE_ONE");
+            field.setAccessible(true);
+
+            UNSAFE = (Unsafe) field.get(null);
+        } catch (NoSuchFieldException ex) {
+            throw new RuntimeException(ex);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * Scribbles on the stack to help ensure we don't have a fake
+     * pointer that would keep would-be garbage alive.
+     */
+    private static void clearStack(int depth) {
+        int a = 0;
+        int b = 0;
+        int c = 0;
+        int d = 0;
+        int e = 0;
+        int f = 0;
+        int g = 0;
+        int h = 0;
+        int i = 0;
+        int j = 0;
+
+        if (depth > 0) {
+            clearStack(depth - 1);
+        }
+    }
+
+    private static class ParkTester extends Thread {
+        public volatile boolean parkNow = false;
+        public volatile boolean success = false;
+
+        public void run() {
+            while (!parkNow) {
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException ex) {
+                    // Ignore it.
+                }
+            }
+
+            long start = System.currentTimeMillis();
+            UNSAFE.park(false, 500 * 1000000); // 500 msec
+            long elapsed = System.currentTimeMillis() - start;
+
+            if (elapsed > 200) {
+                System.out.println("park()ed for " + elapsed + " msec");
+                success = false;
+            } else {
+                System.out.println("park() returned quickly");
+                success = true;
+            }
+        }
+    }
+}
diff --git a/tests/068-classloader/expected.txt b/tests/068-classloader/expected.txt
new file mode 100644
index 0000000..bf131ee
--- /dev/null
+++ b/tests/068-classloader/expected.txt
@@ -0,0 +1,13 @@
+base: class DoubledImplement
+base2: class DoubledImplement2
+Got expected access exception #1
+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)
+Got LinkageError on IDI (early)
diff --git a/tests/068-classloader/info.txt b/tests/068-classloader/info.txt
new file mode 100644
index 0000000..421e52a
--- /dev/null
+++ b/tests/068-classloader/info.txt
@@ -0,0 +1,8 @@
+Class loaders allow code to "redefine" a given class, e.g. it's possible to
+have multiple classes called "com.android.Blah" loaded simultaneously.  The
+classes are distinct and must be treated as such.  This test exercises
+some situations in which a VM that only checks the UTF-8 signatures could
+mix things up.
+
+This also tests a couple of situations in which an IllegalAccessException
+is expected.
diff --git a/tests/068-classloader/src-ex/AbstractGet.java b/tests/068-classloader/src-ex/AbstractGet.java
new file mode 100644
index 0000000..db13b32
--- /dev/null
+++ b/tests/068-classloader/src-ex/AbstractGet.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.
+ */
+
+/**
+ * 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/DoubledExtend.java b/tests/068-classloader/src-ex/DoubledExtend.java
new file mode 100644
index 0000000..6ad2708
--- /dev/null
+++ b/tests/068-classloader/src-ex/DoubledExtend.java
@@ -0,0 +1,20 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Doubled sub-class, form #2.
+ */
+public class DoubledExtend extends Base {
+    public DoubledExtend() {
+        //System.out.println("Ctor: doubled extend, type 2");
+    }
+
+    @Override
+    public DoubledExtend getExtended() {
+        //System.out.println("getExtended 2");
+        return new DoubledExtend();
+    }
+
+    public String getStr() {
+        return "DoubledExtend 2";
+    }
+}
diff --git a/tests/068-classloader/src-ex/DoubledExtendOkay.java b/tests/068-classloader/src-ex/DoubledExtendOkay.java
new file mode 100644
index 0000000..9674875
--- /dev/null
+++ b/tests/068-classloader/src-ex/DoubledExtendOkay.java
@@ -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.
+ */
+
+/**
+ * "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/DoubledImplement.java b/tests/068-classloader/src-ex/DoubledImplement.java
new file mode 100644
index 0000000..5c44fc3
--- /dev/null
+++ b/tests/068-classloader/src-ex/DoubledImplement.java
@@ -0,0 +1,18 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Doubled sub-class, form #2.
+ */
+public class DoubledImplement implements ICommon {
+    public DoubledImplement() {
+        System.out.println("Ctor: doubled implement, type 2");
+    }
+
+    public DoubledImplement getDoubledInstance() {
+        return new DoubledImplement();
+    }
+
+    public void two() {
+        System.out.println("DoubledImplement two");
+    }
+}
diff --git a/tests/068-classloader/src-ex/DoubledImplement2.java b/tests/068-classloader/src-ex/DoubledImplement2.java
new file mode 100644
index 0000000..24ecb65
--- /dev/null
+++ b/tests/068-classloader/src-ex/DoubledImplement2.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/**
+ * Another doubled sub-class, form #2.
+ */
+public class DoubledImplement2 implements ICommon2 {
+    public DoubledImplement2() {
+        System.out.println("Ctor: doubled implement, type 2");
+    }
+
+    public DoubledImplement2 getDoubledInstance2() {
+        return new DoubledImplement2();
+    }
+
+    public void two() {
+        System.out.println("DoubledImplement2 two");
+    }
+}
diff --git a/tests/068-classloader/src-ex/GetDoubled.java b/tests/068-classloader/src-ex/GetDoubled.java
new file mode 100644
index 0000000..28ada1e
--- /dev/null
+++ b/tests/068-classloader/src-ex/GetDoubled.java
@@ -0,0 +1,26 @@
+/*
+ * 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-ex/IfaceImpl.java b/tests/068-classloader/src-ex/IfaceImpl.java
new file mode 100644
index 0000000..7e9c27d
--- /dev/null
+++ b/tests/068-classloader/src-ex/IfaceImpl.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public class IfaceImpl implements IfaceSub {
+    public DoubledImplement2 getDoubledInstance2() {
+        return new DoubledImplement2();
+    }
+}
diff --git a/tests/068-classloader/src-ex/IfaceSub.java b/tests/068-classloader/src-ex/IfaceSub.java
new file mode 100644
index 0000000..7e512e7
--- /dev/null
+++ b/tests/068-classloader/src-ex/IfaceSub.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+public interface IfaceSub extends IfaceSuper {
+    public DoubledImplement2 getDoubledInstance2();
+}
diff --git a/tests/068-classloader/src-ex/Inaccessible1.java b/tests/068-classloader/src-ex/Inaccessible1.java
new file mode 100644
index 0000000..415a8a1
--- /dev/null
+++ b/tests/068-classloader/src-ex/Inaccessible1.java
@@ -0,0 +1,11 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Non-public class, inaccessible from Main.  Note the constructor is
+ * public.
+ */
+class Inaccessible1 extends SimpleBase {
+    public Inaccessible1() {
+        System.out.println("--- inaccessible1");
+    }
+}
diff --git a/tests/068-classloader/src-ex/Inaccessible2.java b/tests/068-classloader/src-ex/Inaccessible2.java
new file mode 100644
index 0000000..dc20c21
--- /dev/null
+++ b/tests/068-classloader/src-ex/Inaccessible2.java
@@ -0,0 +1,10 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Public class that can't access its base.
+ */
+public class Inaccessible2 extends InaccessibleBase {
+    public Inaccessible2() {
+        System.out.println("--- inaccessible2");
+    }
+}
diff --git a/tests/068-classloader/src-ex/Inaccessible3.java b/tests/068-classloader/src-ex/Inaccessible3.java
new file mode 100644
index 0000000..771d0f7
--- /dev/null
+++ b/tests/068-classloader/src-ex/Inaccessible3.java
@@ -0,0 +1,10 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Public class that can't access its interface.
+ */
+public class Inaccessible3 implements InaccessibleInterface {
+    public Inaccessible3() {
+        System.out.println("--- inaccessible3");
+    }
+}
diff --git a/tests/068-classloader/src/Base.java b/tests/068-classloader/src/Base.java
new file mode 100644
index 0000000..b297a8a
--- /dev/null
+++ b/tests/068-classloader/src/Base.java
@@ -0,0 +1,16 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Common base class.
+ */
+public class Base {
+    public Base() {}
+
+    public DoubledExtend getExtended() {
+        return new DoubledExtend();
+    }
+
+    public static String doStuff(DoubledExtend dt) {
+        return dt.getStr();
+    }
+}
diff --git a/tests/068-classloader/src/BaseOkay.java b/tests/068-classloader/src/BaseOkay.java
new file mode 100644
index 0000000..48b7796
--- /dev/null
+++ b/tests/068-classloader/src/BaseOkay.java
@@ -0,0 +1,38 @@
+/*
+ * 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/DoubledExtend.java b/tests/068-classloader/src/DoubledExtend.java
new file mode 100644
index 0000000..5f8ebc2
--- /dev/null
+++ b/tests/068-classloader/src/DoubledExtend.java
@@ -0,0 +1,20 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Doubled sub-class, form #1.
+ */
+public class DoubledExtend extends Base {
+    public DoubledExtend() {
+        //System.out.println("Ctor: doubled extend, type 1");
+    }
+
+    @Override
+    public DoubledExtend getExtended() {
+        System.out.println("getExtended 1");
+        return new DoubledExtend();
+    }
+
+    public String getStr() {
+        return "DoubledExtend 1";
+    }
+}
diff --git a/tests/068-classloader/src/DoubledExtendOkay.java b/tests/068-classloader/src/DoubledExtendOkay.java
new file mode 100644
index 0000000..e226e5f
--- /dev/null
+++ b/tests/068-classloader/src/DoubledExtendOkay.java
@@ -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.
+ */
+
+/**
+ * "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/DoubledImplement.java b/tests/068-classloader/src/DoubledImplement.java
new file mode 100644
index 0000000..64ec5e2
--- /dev/null
+++ b/tests/068-classloader/src/DoubledImplement.java
@@ -0,0 +1,18 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Doubled sub-class, form #1.
+ */
+class DoubledImplement implements ICommon {
+    public DoubledImplement() {
+        System.out.println("Ctor: doubled implement, type 1");
+    }
+
+    public DoubledImplement getDoubledInstance() {
+        return new DoubledImplement();
+    }
+
+    public void one() {
+        System.out.println("DoubledImplement one");
+    }
+}
diff --git a/tests/068-classloader/src/DoubledImplement2.java b/tests/068-classloader/src/DoubledImplement2.java
new file mode 100644
index 0000000..12c036c
--- /dev/null
+++ b/tests/068-classloader/src/DoubledImplement2.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/**
+ * Another doubled sub-class, form #1.
+ */
+public class DoubledImplement2 implements ICommon2 {
+    public DoubledImplement2() {
+        System.out.println("Ctor: doubled implement, type 1");
+    }
+
+    public DoubledImplement2 getDoubledInstance2() {
+        return new DoubledImplement2();
+    }
+
+    public void one() {
+        System.out.println("DoubledImplement2 one");
+    }
+}
diff --git a/tests/068-classloader/src/FancyLoader.java b/tests/068-classloader/src/FancyLoader.java
new file mode 100644
index 0000000..173b08f
--- /dev/null
+++ b/tests/068-classloader/src/FancyLoader.java
@@ -0,0 +1,228 @@
+/*
+ * 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;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * A class loader with atypical behavior: we try to load a private
+ * class implementation before asking the system or boot loader.  This
+ * is used to create multiple classes with identical names in a single VM.
+ *
+ * If DexFile is available, we use that; if not, we assume we're not in
+ * Dalvik and instantiate the class with defineClass().
+ *
+ * The location of the DEX files and class data is dependent upon the
+ * test framework.
+ */
+public class FancyLoader extends ClassLoader {
+    /* this is where the "alternate" .class files live */
+    static final String CLASS_PATH = "classes-ex/";
+
+    /* this is the "alternate" DEX/Jar file */
+    static final String DEX_FILE = "test-ex.jar";
+
+    /* 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.
+     */
+    public FancyLoader(ClassLoader parent) {
+        super(parent);
+
+        try {
+            mDexClass = parent.loadClass("dalvik/system/DexFile");
+        } catch (ClassNotFoundException cnfe) {
+            // ignore -- not running Dalvik
+        }
+    }
+
+    /**
+     * Finds the class with the specified binary name.
+     *
+     * We search for a file in CLASS_PATH or pull an entry from DEX_FILE.
+     * If we don't find a match, we throw an exception.
+     */
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (mDexClass != null) {
+            return findClassDalvik(name);
+        } else {
+            return findClassNonDalvik(name);
+        }
+    }
+
+    /**
+     * Finds the class with the specified binary name, from a DEX file.
+     */
+    private Class<?> findClassDalvik(String name)
+        throws ClassNotFoundException {
+
+        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);
+                }
+
+                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);
+                }
+            }
+        }
+
+        /*
+         * Call DexFile.loadClass(String, ClassLoader).
+         */
+        Method meth;
+
+        try {
+            meth = mDexClass.getMethod("loadClass",
+                    new Class[] { String.class, ClassLoader.class });
+        } catch (NoSuchMethodException nsme) {
+            throw new ClassNotFoundException("getMethod failed", nsme);
+        }
+
+        try {
+            meth.invoke(mDexFile, name, this);
+        } catch (IllegalAccessException iae) {
+            throw new ClassNotFoundException("loadClass failed", iae);
+        } catch (InvocationTargetException ite) {
+            throw new ClassNotFoundException("loadClass failed",
+                ite.getCause());
+        }
+
+        return null;
+    }
+
+    /**
+     * Finds the class with the specified binary name, from .class files.
+     */
+    private Class<?> findClassNonDalvik(String name)
+        throws ClassNotFoundException {
+
+        String pathName = CLASS_PATH + name + ".class";
+        //System.out.println("--- Fancy: looking for " + pathName);
+
+        File path = new File(pathName);
+        RandomAccessFile raf;
+
+        try {
+            raf = new RandomAccessFile(path, "r");
+        } catch (FileNotFoundException fnfe) {
+            throw new ClassNotFoundException("Not found: " + pathName);
+        }
+
+        /* read the entire file in */
+        byte[] fileData;
+        try {
+            fileData = new byte[(int) raf.length()];
+            raf.readFully(fileData);
+        } catch (IOException ioe) {
+            throw new ClassNotFoundException("Read error: " + pathName);
+        } finally {
+            try {
+                raf.close();
+            } catch (IOException ioe) {
+                // drop
+            }
+        }
+
+        /* create the class */
+        //System.out.println("--- Fancy: defining " + name);
+        try {
+            return defineClass(name, fileData, 0, fileData.length);
+        } catch (Throwable th) {
+            throw new ClassNotFoundException("defineClass failed", th);
+        }
+    }
+
+    /**
+     * Load a class.
+     *
+     * Normally a class loader wouldn't override this, but we want our
+     * version of the class to take precedence over an already-loaded
+     * version.
+     *
+     * We still want the system classes (e.g. java.lang.Object) from the
+     * bootstrap class loader.
+     */
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        Class res;
+
+        /*
+         * 1. Invoke findLoadedClass(String) to check if the class has
+         * already been loaded.
+         *
+         * This doesn't change.
+         */
+        res = findLoadedClass(name);
+        if (res != null) {
+            System.out.println("FancyLoader.loadClass: "
+                + name + " already loaded");
+            if (resolve)
+                resolveClass(res);
+            return res;
+        }
+
+        /*
+         * 3. Invoke the findClass(String) method to find the class.
+         */
+        try {
+            res = findClass(name);
+            if (resolve)
+                resolveClass(res);
+        }
+        catch (ClassNotFoundException e) {
+            // we couldn't find it, so eat the exception and keep going
+        }
+
+        /*
+         * 2. Invoke the loadClass method on the parent class loader.  If
+         * the parent loader is null the class loader built-in to the
+         * virtual machine is used, instead.
+         *
+         * (Since we're not in java.lang, we can't actually invoke the
+         * parent's loadClass() method, but we passed our parent to the
+         * super-class which can take care of it for us.)
+         */
+        res = super.loadClass(name, resolve);   // returns class or throws
+        return res;
+    }
+}
diff --git a/tests/068-classloader/src/ICommon.java b/tests/068-classloader/src/ICommon.java
new file mode 100644
index 0000000..35a98cc
--- /dev/null
+++ b/tests/068-classloader/src/ICommon.java
@@ -0,0 +1,8 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Common interface.
+ */
+public interface ICommon {
+    public DoubledImplement getDoubledInstance();
+}
diff --git a/tests/068-classloader/src/ICommon2.java b/tests/068-classloader/src/ICommon2.java
new file mode 100644
index 0000000..6d81afc
--- /dev/null
+++ b/tests/068-classloader/src/ICommon2.java
@@ -0,0 +1,22 @@
+/*
+ * 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 interface.
+ */
+public interface ICommon2 {
+    public DoubledImplement2 getDoubledInstance2();
+}
diff --git a/tests/068-classloader/src/IGetDoubled.java b/tests/068-classloader/src/IGetDoubled.java
new file mode 100644
index 0000000..08cd1ce
--- /dev/null
+++ b/tests/068-classloader/src/IGetDoubled.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.
+ */
+
+/**
+ * Interface, loaded from one loader, used from another.
+ */
+public interface IGetDoubled {
+    public DoubledExtendOkay getDoubled();
+}
diff --git a/tests/068-classloader/src/IfaceSuper.java b/tests/068-classloader/src/IfaceSuper.java
new file mode 100644
index 0000000..36d278c
--- /dev/null
+++ b/tests/068-classloader/src/IfaceSuper.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+public interface IfaceSuper {
+    public DoubledImplement2 getDoubledInstance2();
+}
diff --git a/tests/068-classloader/src/InaccessibleBase.java b/tests/068-classloader/src/InaccessibleBase.java
new file mode 100644
index 0000000..83af665
--- /dev/null
+++ b/tests/068-classloader/src/InaccessibleBase.java
@@ -0,0 +1,7 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Non-public base class, inaccessible from alternate class loader.
+ */
+class InaccessibleBase {
+}
diff --git a/tests/068-classloader/src/InaccessibleInterface.java b/tests/068-classloader/src/InaccessibleInterface.java
new file mode 100644
index 0000000..7f52b80
--- /dev/null
+++ b/tests/068-classloader/src/InaccessibleInterface.java
@@ -0,0 +1,7 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Non-public interface class, inaccessible from alternate class loader.
+ */
+interface InaccessibleInterface {
+}
diff --git a/tests/068-classloader/src/Main.java b/tests/068-classloader/src/Main.java
new file mode 100644
index 0000000..1bc7b04
--- /dev/null
+++ b/tests/068-classloader/src/Main.java
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+/**
+ * Class loader test.
+ */
+public class Main {
+    /**
+     * Main entry point.
+     */
+    public static void main(String[] args) {
+        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
+         * change the point where a LinkageException is thrown in
+         * testImplement().  When this is present the "reference
+         * implementation" throws an exception from Class.newInstance(),
+         * when it's absent the exception is deferred until the first time
+         * we call a method that isn't actually implemented.
+         *
+         * This isn't the class that fails -- it's a class with the same
+         * name in the "fancy" class loader --  but the VM thinks it has a
+         * reference to one of these; presumably the difference is that
+         * without this the VM finds itself holding a reference to an
+         * instance of an uninitialized class.
+         */
+        System.out.println("base: " + DoubledImplement.class);
+        System.out.println("base2: " + DoubledImplement2.class);
+
+        /*
+         * Run tests.
+         */
+        testAccess1(loader);
+        testAccess2(loader);
+        testAccess3(loader);
+
+        testExtend(loader);
+        testExtendOkay(loader);
+        testInterface(loader);
+        testAbstract(loader);
+        testImplement(loader);
+        testIfaceImplement(loader);
+    }
+
+    /**
+     * See if we can load a class that isn't public to us.  We should be
+     * able to load it but not instantiate it.
+     */
+    static void testAccess1(ClassLoader loader) {
+        Class altClass;
+
+        try {
+            altClass = loader.loadClass("Inaccessible1");
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println("loadClass failed");
+            cnfe.printStackTrace();
+            return;
+        }
+
+        /* instantiate */
+        Object obj;
+        try {
+            obj = altClass.newInstance();
+            System.err.println("ERROR: Inaccessible1 was accessible");
+        } catch (InstantiationException ie) {
+            System.err.println("newInstance failed: " + ie);
+            return;
+        } catch (IllegalAccessException iae) {
+            System.out.println("Got expected access exception #1");
+            //System.out.println("+++ " + iae);
+            return;
+        }
+    }
+
+    /**
+     * See if we can load a class whose base class is not accessible to it
+     * (though the base *is* accessible to us).
+     */
+    static void testAccess2(ClassLoader loader) {
+        Class altClass;
+
+        try {
+            altClass = loader.loadClass("Inaccessible2");
+            System.err.println("ERROR: Inaccessible2 was accessible");
+        } catch (ClassNotFoundException cnfe) {
+            Throwable cause = cnfe.getCause();
+            if (cause instanceof IllegalAccessError) {
+                System.out.println("Got expected CNFE/IAE #2");
+            } else {
+                System.err.println("Got unexpected CNFE/IAE #2");
+                cnfe.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * See if we can load a class with an inaccessible interface.
+     */
+    static void testAccess3(ClassLoader loader) {
+        Class altClass;
+
+        try {
+            altClass = loader.loadClass("Inaccessible3");
+            System.err.println("ERROR: Inaccessible3 was accessible");
+        } catch (ClassNotFoundException cnfe) {
+            Throwable cause = cnfe.getCause();
+            if (cause instanceof IllegalAccessError) {
+                System.out.println("Got expected CNFE/IAE #3");
+            } else {
+                System.err.println("Got unexpected CNFE/IAE #3");
+                cnfe.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Test a doubled class that extends the base class.
+     */
+    static void testExtend(ClassLoader loader) {
+        Class doubledExtendClass;
+        Object obj;
+
+        /* get the "alternate" version of DoubledExtend */
+        try {
+            doubledExtendClass = loader.loadClass("DoubledExtend");
+            //System.out.println("+++ DoubledExtend is " + doubledExtendClass
+            //    + " in " + doubledExtendClass.getClassLoader());
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println("loadClass failed: " + cnfe);
+            return;
+        }
+
+        /* instantiate */
+        try {
+            obj = doubledExtendClass.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 expected LinkageError on DE");
+            return;
+        }
+
+        /* use the base class reference to get a CL-specific instance */
+        Base baseRef = (Base) obj;
+        DoubledExtend de = baseRef.getExtended();
+
+        /* try to call through it */
+        try {
+            String result;
+
+            result = Base.doStuff(de);
+            System.err.println("ERROR: did not get LinkageError on DE");
+            System.err.println("(result=" + result + ")");
+        } catch (LinkageError le) {
+            System.out.println("Got expected LinkageError on DE");
+            return;
+        }
+    }
+
+    /**
+     * 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) {
+        Class doubledImplementClass;
+        Object obj;
+
+        useImplement(new DoubledImplement(), true);
+
+        /* get the "alternate" version of DoubledImplement */
+        try {
+            doubledImplementClass = loader.loadClass("DoubledImplement");
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println("loadClass failed: " + cnfe);
+            return;
+        }
+
+        /* instantiate */
+        try {
+            obj = doubledImplementClass.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 DI (early)");
+            return;
+        }
+
+        /* if we lived this long, try to do something with it */
+        ICommon icommon = (ICommon) obj;
+        useImplement(icommon.getDoubledInstance(), false);
+    }
+
+    /**
+     * Do something with a DoubledImplement instance.
+     */
+    static void useImplement(DoubledImplement di, boolean isOne) {
+        //System.out.println("useObject: " + di.toString() + " -- "
+        //    + di.getClass().getClassLoader());
+        try {
+            di.one();
+            if (!isOne) {
+                System.err.println("ERROR: did not get LinkageError on DI");
+            }
+        } catch (LinkageError le) {
+            if (!isOne) {
+                System.out.println("Got LinkageError on DI (late)");
+            } else {
+                throw le;
+            }
+        }
+    }
+
+
+    /**
+     * Test a class that implements an interface with a super-interface
+     * that refers to a doubled class.
+     */
+    static void testIfaceImplement(ClassLoader loader) {
+        Class ifaceImplClass;
+        Object obj;
+
+        /*
+         * Create an instance of IfaceImpl.  We also pull in
+         * DoubledImplement2 from the other class loader; without this
+         * we don't fail in some implementations.
+         */
+        try {
+            ifaceImplClass = loader.loadClass("IfaceImpl");
+            ifaceImplClass = loader.loadClass("DoubledImplement2");
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println("loadClass failed: " + cnfe);
+            return;
+        }
+
+        /* instantiate */
+        try {
+            obj = ifaceImplClass.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 IDI (early)");
+            //System.out.println(le);
+            return;
+        }
+
+        /*
+         * Without the pre-load of FancyLoader->DoubledImplement2, some
+         * implementations will happily execute through this part.  "obj"
+         * comes from FancyLoader, but the di2 returned from ifaceSuper
+         * comes from the application class loader.
+         */
+        IfaceSuper ifaceSuper = (IfaceSuper) obj;
+        DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2();
+        di2.one();
+    }
+}
diff --git a/tests/068-classloader/src/SimpleBase.java b/tests/068-classloader/src/SimpleBase.java
new file mode 100644
index 0000000..fd56db9
--- /dev/null
+++ b/tests/068-classloader/src/SimpleBase.java
@@ -0,0 +1,8 @@
+// Copyright 2008 The Android Open Source Project
+
+/**
+ * Simple, public base class.
+ */
+public class SimpleBase {
+    public SimpleBase() {}
+}
diff --git a/tests/068-classloader/src/Useless.java b/tests/068-classloader/src/Useless.java
new file mode 100644
index 0000000..f51d9a8
--- /dev/null
+++ b/tests/068-classloader/src/Useless.java
@@ -0,0 +1,4 @@
+
+public class Useless implements ICommon {
+    public DoubledImplement getDoubledInstance() { return null; }
+}
diff --git a/tests/069-field-type/expected.txt b/tests/069-field-type/expected.txt
new file mode 100644
index 0000000..8828178
--- /dev/null
+++ b/tests/069-field-type/expected.txt
@@ -0,0 +1,4 @@
+Assignment was allowed
+Got expected IncompatibleClassChangeError
+In compareTo
+Done
diff --git a/tests/069-field-type/info.txt b/tests/069-field-type/info.txt
new file mode 100644
index 0000000..6e3a22f
--- /dev/null
+++ b/tests/069-field-type/info.txt
@@ -0,0 +1,4 @@
+This tests to see if the VM allows you to store a reference to an
+inappropriate object type in an instance field.  By compiling two
+versions of the field-holder class we can bypass the compiler's type
+safety.
diff --git a/tests/069-field-type/src/Blah.java b/tests/069-field-type/src/Blah.java
new file mode 100644
index 0000000..fd98336
--- /dev/null
+++ b/tests/069-field-type/src/Blah.java
@@ -0,0 +1,9 @@
+
+/**
+ * Trivial class; must implement an interesting interface.
+ */
+public class Blah implements Runnable {
+    public void run() {
+        System.out.println("run");
+    }
+}
diff --git a/tests/069-field-type/src/Holder.java b/tests/069-field-type/src/Holder.java
new file mode 100644
index 0000000..e3c9f89
--- /dev/null
+++ b/tests/069-field-type/src/Holder.java
@@ -0,0 +1,7 @@
+
+/**
+ * Simple class with one field.
+ */
+public class Holder {
+    public Runnable mValue;
+}
diff --git a/tests/069-field-type/src/Main.java b/tests/069-field-type/src/Main.java
new file mode 100644
index 0000000..f9885e6
--- /dev/null
+++ b/tests/069-field-type/src/Main.java
@@ -0,0 +1,34 @@
+
+/**
+ * Create some objects and store them into an instance field.
+ */
+public class Main {
+    /**
+     * Entry point.
+     */
+    public static void main(String[] args) {
+        Holder holder = new Holder();
+
+        Blah blah = new Blah();
+
+        /* strictly speaking, this should fail */
+        holder.mValue = blah;
+
+        System.out.println("Assignment was allowed");
+
+        /* try to use the reference; should fail */
+        try {
+            holder.mValue.run();
+            System.err.println("ERROR: did not get expected ICCE");
+        } catch (IncompatibleClassChangeError icce) {
+            System.out.println("Got expected IncompatibleClassChangeError");
+        }
+
+        /* for fun, verify that it's the "alternate" type */
+        //Comparable cmpx = holder.mValue;      /* compiler rejects */
+        Comparable cmp = (Comparable) holder.mValue;
+        cmp.compareTo(cmp);
+
+        System.out.println("Done");
+    }
+}
diff --git a/tests/069-field-type/src2/Blah.java b/tests/069-field-type/src2/Blah.java
new file mode 100644
index 0000000..1bffff6
--- /dev/null
+++ b/tests/069-field-type/src2/Blah.java
@@ -0,0 +1,10 @@
+
+/**
+ * Trivial class; must implement an interesting interface.
+ */
+public class Blah implements Comparable {
+    public int compareTo(Object another) {
+        System.out.println("In compareTo");
+        return 0;
+    }
+}
diff --git a/tests/070-nio-buffer/expected.txt b/tests/070-nio-buffer/expected.txt
new file mode 100644
index 0000000..e271001
--- /dev/null
+++ b/tests/070-nio-buffer/expected.txt
@@ -0,0 +1,3 @@
+Got expected buffer overflow exception
+Got expected out-of-bounds exception
+Got expected buffer overflow exception
diff --git a/tests/070-nio-buffer/info.txt b/tests/070-nio-buffer/info.txt
new file mode 100644
index 0000000..761714e
--- /dev/null
+++ b/tests/070-nio-buffer/info.txt
@@ -0,0 +1 @@
+Exercise NIO buffers (e.g. java.nio.ByteBuffer).
diff --git a/tests/070-nio-buffer/src/Main.java b/tests/070-nio-buffer/src/Main.java
new file mode 100644
index 0000000..bfcab3a
--- /dev/null
+++ b/tests/070-nio-buffer/src/Main.java
@@ -0,0 +1,97 @@
+/*
+ * 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.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+public class Main {
+    public static void main(String[] args) {
+         intFloatTest();
+         basicShortTest();
+    }
+
+    /*
+     * Create a buffer and fiddle with it.
+     */
+    public static void basicShortTest() {
+        ByteBuffer directBuf = ByteBuffer.allocateDirect(64);
+        //ByteBuffer directBuf = ByteBuffer.allocateDirect(65);
+
+        ShortBuffer shortBuf = directBuf.asShortBuffer();
+
+        short[] myShorts = {
+            1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
+            1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015,
+            1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
+            1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031
+        };
+
+        shortBuf.position(0);
+        shortBuf.put(myShorts, 0, 32);      // should work
+        shortBuf.position(0);
+        shortBuf.put(myShorts, 16, 16);     // should work
+        shortBuf.put(myShorts, 16, 16);     // advance to end
+
+        try {
+            shortBuf.put(myShorts, 0, 1);     // should fail
+            System.err.println("ERROR: out-of-bounds put succeeded\n");
+        } catch (BufferOverflowException boe) {
+            System.out.println("Got expected buffer overflow exception");
+        }
+
+        try {
+            shortBuf.position(0);
+            shortBuf.put(myShorts, 0, 33);     // should fail
+            System.err.println("ERROR: out-of-bounds put succeeded\n");
+        } catch (IndexOutOfBoundsException ioobe) {
+            System.out.println("Got expected out-of-bounds exception");
+        }
+
+        try {
+            shortBuf.position(16);
+            shortBuf.put(myShorts, 0, 17);     // should fail
+            System.err.println("ERROR: out-of-bounds put succeeded\n");
+        } catch (BufferOverflowException boe) {
+            System.out.println("Got expected buffer overflow exception");
+        }
+    }
+
+    /*
+     * Try this with either floats or ints; ints fail with
+     * BufferOverflowException, floats work.
+     *
+     * From http://code.google.com/p/android/issues/detail?id=1585 .
+     */
+    public static void intFloatTest() {
+        ByteBuffer direct = ByteBuffer.allocateDirect(100);
+        direct.order(ByteOrder.nativeOrder());
+        IntBuffer int1 = direct.asIntBuffer();
+        int data[] = new int[25];
+        //FloatBuffer int1 = direct.asFloatBuffer();
+        //float data[] = new float[25];
+        int1.clear ();
+        int1.put (data);
+        int1.position (0);
+
+        int1.clear ();
+        int1.put (data);
+        int1.position (0);
+    }
+}
diff --git a/tests/071-dexfile/expected.txt b/tests/071-dexfile/expected.txt
new file mode 100644
index 0000000..b7af75e
--- /dev/null
+++ b/tests/071-dexfile/expected.txt
@@ -0,0 +1,3 @@
+Constructing another
+Got expected ULE
+done
diff --git a/tests/071-dexfile/info.txt b/tests/071-dexfile/info.txt
new file mode 100644
index 0000000..54d9ed0
--- /dev/null
+++ b/tests/071-dexfile/info.txt
@@ -0,0 +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-ex/Another.java b/tests/071-dexfile/src-ex/Another.java
new file mode 100644
index 0000000..c978c59
--- /dev/null
+++ b/tests/071-dexfile/src-ex/Another.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.
+ */
+
+public class Another {
+    public Another() {
+        System.out.println("Constructing another");
+
+        /* not expected to work; just exercises the call */
+        try {
+            System.loadLibrary("nonexistent");
+        } catch (UnsatisfiedLinkError ule) {
+            System.out.println("Got expected ULE");
+        }
+    }
+}
diff --git a/tests/071-dexfile/src/Main.java b/tests/071-dexfile/src/Main.java
new file mode 100644
index 0000000..d71aec0
--- /dev/null
+++ b/tests/071-dexfile/src/Main.java
@@ -0,0 +1,145 @@
+/*
+ * 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.IOException;
+import java.lang.reflect.Constructor;
+
+/**
+ * DexFile tests (Dalvik-specific).
+ */
+public class Main {
+    private static final String CLASS_PATH = "test-ex.jar";
+    private static final String ODEX_DIR = "/sdcard";
+    //private static final String ODEX_DIR = ".";
+    private static final String ODEX_ALT = "/tmp";
+    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.
+     */
+    private static void testDexClassLoader() {
+        ClassLoader dexClassLoader = getDexClassLoader();
+
+        Class anotherClass;
+        try {
+            anotherClass = dexClassLoader.loadClass("Another");
+        } catch (ClassNotFoundException cnfe) {
+            throw new RuntimeException("Another?");
+        }
+
+        Object another;
+        try {
+            another = anotherClass.newInstance();
+        } catch (IllegalAccessException ie) {
+            throw new RuntimeException("new another", ie);
+        } catch (InstantiationException ie) {
+            throw new RuntimeException("new another", ie);
+        }
+
+        // not expected to work; just exercises the call
+        dexClassLoader.getResource("nonexistent");
+    }
+
+    /*
+     * Create an instance of DexClassLoader.  The test harness doesn't
+     * have visibility into dalvik.system.*, so we do this through
+     * reflection.
+     */
+    private static ClassLoader getDexClassLoader() {
+        String odexDir;
+
+        /*
+        String androidData = System.getenv("ANDROID_DATA");
+        if (androidData == null)
+            androidData = "";
+        odexDir = androidData + "/" + ODEX_DIR;
+        */
+
+        File test = new File(ODEX_DIR);
+        if (test.isDirectory())
+            odexDir = ODEX_DIR;
+        else
+            odexDir = ODEX_ALT;
+        //System.out.println("Output dir is " + odexDir);
+
+        ClassLoader myLoader = Main.class.getClassLoader();
+        Class dclClass;
+        try {
+            dclClass = myLoader.loadClass("dalvik.system.DexClassLoader");
+        } catch (ClassNotFoundException cnfe) {
+            throw new RuntimeException("dalvik.system.DexClassLoader not found");
+        }
+
+        Constructor ctor;
+        try {
+            ctor = dclClass.getConstructor(String.class, String.class,
+                String.class, ClassLoader.class);
+        } catch (NoSuchMethodException nsme) {
+            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);
+        } catch (Exception ex) {
+            throw new RuntimeException("DCL newInstance", ex);
+        }
+
+        return (ClassLoader) dclObj;
+    }
+}
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..e049221
--- /dev/null
+++ b/tests/072-precise-gc/src/Main.java
@@ -0,0 +1,113 @@
+/*
+ * 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..3ad5ecb
--- /dev/null
+++ b/tests/073-mismatched-field/src/IMain.java
@@ -0,0 +1,19 @@
+/*
+ * 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..70709c0
--- /dev/null
+++ b/tests/073-mismatched-field/src/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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..48a9bab
--- /dev/null
+++ b/tests/073-mismatched-field/src/SuperMain.java
@@ -0,0 +1,19 @@
+/*
+ * 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..136f2a1
--- /dev/null
+++ b/tests/073-mismatched-field/src2/IMain.java
@@ -0,0 +1,19 @@
+/*
+ * 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..ded1582
--- /dev/null
+++ b/tests/074-gc-thrash/info.txt
@@ -0,0 +1 @@
+This thrashes the memory allocator and garbage collector for a brief period.
diff --git a/tests/074-gc-thrash/src/Main.java b/tests/074-gc-thrash/src/Main.java
new file mode 100644
index 0000000..f85aa4b
--- /dev/null
+++ b/tests/074-gc-thrash/src/Main.java
@@ -0,0 +1,337 @@
+/*
+ * 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..6e4f584
--- /dev/null
+++ b/tests/075-verification-error/expected.txt
@@ -0,0 +1,12 @@
+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 (field-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..51d648c
--- /dev/null
+++ b/tests/075-verification-error/src/Main.java
@@ -0,0 +1,148 @@
+/*
+ * 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 meth-class access succeeded\n");
+        } catch (IllegalAccessError iae) {
+            System.out.println("Got expected IllegalAccessError (meth-class)");
+            if (VERBOSE) System.out.println("--- " + iae);
+        }
+
+        try {
+            /* accessible static field in an inaccessible class */
+            int blah = InaccessibleClass.blah;
+            System.err.println("ERROR: bad field-class access succeeded\n");
+        } catch (IllegalAccessError iae) {
+            System.out.println("Got expected IllegalAccessError (field-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..6d3b05b
--- /dev/null
+++ b/tests/075-verification-error/src/MaybeAbstract.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 /*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..b9bdfc4
--- /dev/null
+++ b/tests/075-verification-error/src/other/InaccessibleClass.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.
+ */
+
+package other;
+
+public class InaccessibleClass {
+    public static void test() {}
+
+    public static int blah = 5;
+}
diff --git a/tests/075-verification-error/src/other/InaccessibleMethod.java b/tests/075-verification-error/src/other/InaccessibleMethod.java
new file mode 100644
index 0000000..0460373
--- /dev/null
+++ b/tests/075-verification-error/src/other/InaccessibleMethod.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.
+ */
+
+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..ec4754b
--- /dev/null
+++ b/tests/075-verification-error/src/other/Mutant.java
@@ -0,0 +1,43 @@
+/*
+ * 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..8b70a07
--- /dev/null
+++ b/tests/075-verification-error/src2/MaybeAbstract.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 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..812fac9
--- /dev/null
+++ b/tests/075-verification-error/src2/other/InaccessibleClass.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.
+ */
+
+package other;
+
+/*package*/ class InaccessibleClass {
+    public static void test() {}
+
+    public static int blah = 5;
+}
diff --git a/tests/075-verification-error/src2/other/InaccessibleMethod.java b/tests/075-verification-error/src2/other/InaccessibleMethod.java
new file mode 100644
index 0000000..9fb844e
--- /dev/null
+++ b/tests/075-verification-error/src2/other/InaccessibleMethod.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.
+ */
+
+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..67cd36d
--- /dev/null
+++ b/tests/075-verification-error/src2/other/Mutant.java
@@ -0,0 +1,43 @@
+/*
+ * 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..befe2e2
--- /dev/null
+++ b/tests/077-method-override/src/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 */
+    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..7dc43d0
--- /dev/null
+++ b/tests/077-method-override/src/Derived.java
@@ -0,0 +1,59 @@
+/*
+ * 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..2d10ee0
--- /dev/null
+++ b/tests/077-method-override/src/Main.java
@@ -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.
+ */
+
+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..ab2a28b
--- /dev/null
+++ b/tests/077-method-override/src2/Base.java
@@ -0,0 +1,82 @@
+/*
+ * 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/078-polymorphic-virtual/expected.txt b/tests/078-polymorphic-virtual/expected.txt
new file mode 100644
index 0000000..0d29728
--- /dev/null
+++ b/tests/078-polymorphic-virtual/expected.txt
@@ -0,0 +1,3 @@
+10000000
+20000000
+30000000
diff --git a/tests/078-polymorphic-virtual/info.txt b/tests/078-polymorphic-virtual/info.txt
new file mode 100644
index 0000000..7c8a561
--- /dev/null
+++ b/tests/078-polymorphic-virtual/info.txt
@@ -0,0 +1,2 @@
+Stress test predicted chaining for overloaded virtual callsite with 3 resolved
+calless invoked 10,000,000 times each in three threads.
diff --git a/tests/078-polymorphic-virtual/src/Base.java b/tests/078-polymorphic-virtual/src/Base.java
new file mode 100644
index 0000000..ec3aadd
--- /dev/null
+++ b/tests/078-polymorphic-virtual/src/Base.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 Base extends Thread {
+    int value;
+
+    public void run() {
+        for (int i = 0; i < 10000000; i++) {
+            incrimentValue();
+        }
+    }
+
+    public void incrimentValue() {
+    }
+
+    public int getValue() {
+        return value;
+    }
+}
diff --git a/tests/078-polymorphic-virtual/src/Derived1.java b/tests/078-polymorphic-virtual/src/Derived1.java
new file mode 100644
index 0000000..57bd3b0
--- /dev/null
+++ b/tests/078-polymorphic-virtual/src/Derived1.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 class Derived1 extends Base {
+    public void incrimentValue() {
+        value += 1;
+    }
+}
diff --git a/tests/078-polymorphic-virtual/src/Derived2.java b/tests/078-polymorphic-virtual/src/Derived2.java
new file mode 100644
index 0000000..1d7de57
--- /dev/null
+++ b/tests/078-polymorphic-virtual/src/Derived2.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 class Derived2 extends Base {
+    public void incrimentValue() {
+        value += 2;
+    }
+}
diff --git a/tests/078-polymorphic-virtual/src/Derived3.java b/tests/078-polymorphic-virtual/src/Derived3.java
new file mode 100644
index 0000000..c2594d2
--- /dev/null
+++ b/tests/078-polymorphic-virtual/src/Derived3.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 class Derived3 extends Base {
+    public void incrimentValue() {
+        value += 3;
+    }
+}
diff --git a/tests/078-polymorphic-virtual/src/Main.java b/tests/078-polymorphic-virtual/src/Main.java
new file mode 100644
index 0000000..0514e53
--- /dev/null
+++ b/tests/078-polymorphic-virtual/src/Main.java
@@ -0,0 +1,40 @@
+/*
+ * 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[]) {
+        Derived1 derived1 = new Derived1();
+        Derived2 derived2 = new Derived2();
+        Derived3 derived3 = new Derived3();
+
+        derived1.start();
+        derived2.start();
+        derived3.start();
+
+        try {
+            derived1.join();
+            derived2.join();
+            derived3.join();
+        } catch (Exception e) {
+            System.out.println(e);
+            return;
+        }
+
+        System.out.println(derived1.getValue());
+        System.out.println(derived2.getValue());
+        System.out.println(derived3.getValue());
+    }
+}
diff --git a/tests/079-phantom/expected.txt b/tests/079-phantom/expected.txt
new file mode 100644
index 0000000..a932b77
--- /dev/null
+++ b/tests/079-phantom/expected.txt
@@ -0,0 +1,14 @@
+start
+Created Bitmap one: 10x10 (100)
+Created Bitmap two: 20x20 (101)
+Created Bitmap three/four: 20x20 (101)
+Drawing Bitmap two: 20x20 (101)
+nulling 1
+freeNativeStorage: 100
+nulling 2
+nulling 3
+nulling 4
+freeNativeStorage: 101
+intr
+Bitmap has shut down
+done
diff --git a/tests/079-phantom/info.txt b/tests/079-phantom/info.txt
new file mode 100644
index 0000000..d974e2c
--- /dev/null
+++ b/tests/079-phantom/info.txt
@@ -0,0 +1 @@
+Exercise phantom references.
diff --git a/tests/079-phantom/src/Bitmap.java b/tests/079-phantom/src/Bitmap.java
new file mode 100644
index 0000000..9d03cbd
--- /dev/null
+++ b/tests/079-phantom/src/Bitmap.java
@@ -0,0 +1,152 @@
+/*
+ * 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.ReferenceQueue;
+import java.lang.ref.PhantomReference;
+import java.util.ArrayList;
+
+public class Bitmap {
+    String mName;           /* for debugging */
+    int mWidth, mHeight;
+    Bitmap.NativeWrapper mNativeWrapper;
+
+    private static int sSerial = 100;
+    private static ArrayList sPhantomList = new ArrayList<PhantomWrapper>();
+    private static ReferenceQueue<PhantomWrapper> sPhantomQueue =
+            new ReferenceQueue<PhantomWrapper>();
+    private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue);
+    static {
+        sWatcher.start();
+    };
+
+    Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData) {
+        mName = name;
+        mWidth = width;
+        mHeight = height;
+        mNativeWrapper = nativeData;
+
+        System.out.println("Created " + this);
+    }
+
+    public String toString() {
+        return "Bitmap " + mName + ": " + mWidth + "x" + mHeight + " (" +
+                mNativeWrapper.mNativeData + ")";
+    }
+
+    public void drawAt(int x, int y) {
+        System.out.println("Drawing " + this);
+    }
+
+    public static void shutDown() {
+        sWatcher.shutDown();
+        try {
+            sWatcher.join();
+        } catch (InterruptedException ie) {
+            System.out.println("join intr");
+        }
+        System.out.println("Bitmap has shut down");
+    }
+
+    /*
+     * Pretend we're allocating native storage.  Just returns a unique
+     * serial number.
+     */
+    static Bitmap.NativeWrapper allocNativeStorage(int width, int height) {
+        int nativeData;
+
+        synchronized (Bitmap.class) {
+            nativeData = sSerial++;
+        }
+
+        Bitmap.NativeWrapper wrapper = new Bitmap.NativeWrapper(nativeData);
+        PhantomWrapper phan = new PhantomWrapper(wrapper, sPhantomQueue,
+                nativeData);
+        sPhantomList.add(phan);
+        return wrapper;
+    }
+
+    static void freeNativeStorage(int nativeDataPtr) {
+        System.out.println("freeNativeStorage: " + nativeDataPtr);
+    }
+
+    /*
+     * Wraps a native data pointer in an object.  When this object is no
+     * longer referenced, we free the native data.
+     */
+    static class NativeWrapper {
+        public NativeWrapper(int nativeDataPtr) {
+            mNativeData = nativeDataPtr;
+        }
+        public int mNativeData;
+
+        /*
+        @Override
+        protected void finalize() throws Throwable {
+            System.out.println("finalized " + mNativeData);
+        }
+        */
+    }
+}
+
+/*
+ * Keep an eye on the native data.
+ *
+ * We keep a copy of the native data pointer value, and set the wrapper
+ * as our referent.  We need the copy because you can't get the referred-to
+ * object back out of a PhantomReference.
+ */
+class PhantomWrapper extends PhantomReference {
+    PhantomWrapper(Bitmap.NativeWrapper wrapper,
+        ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr)
+    {
+        super(wrapper, queue);
+        mNativeData = nativeDataPtr;
+    }
+
+    public int mNativeData;
+}
+
+/*
+ * Thread that watches for un-referenced bitmap data.
+ */
+class BitmapWatcher extends Thread {
+    ReferenceQueue<PhantomWrapper> mQueue;
+    volatile boolean mQuit = false;
+
+    BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) {
+        mQueue = queue;
+        setName("Bitmap Watcher");
+    }
+
+    public void run() {
+        while (!mQuit) {
+            try {
+                PhantomWrapper ref = (PhantomWrapper) mQueue.remove();
+                //System.out.println("dequeued ref " + ref.mNativeData +
+                //    " - " + ref);
+                Bitmap.freeNativeStorage(ref.mNativeData);
+                //ref.clear();
+            } catch (InterruptedException ie) {
+                System.out.println("intr");
+            }
+        }
+    }
+
+    public void shutDown() {
+        mQuit = true;
+        interrupt();
+    }
+}
diff --git a/tests/079-phantom/src/Main.java b/tests/079-phantom/src/Main.java
new file mode 100644
index 0000000..9c459c9
--- /dev/null
+++ b/tests/079-phantom/src/Main.java
@@ -0,0 +1,85 @@
+/*
+ * 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 {
+    Bitmap mBitmap1, mBitmap2, mBitmap3, mBitmap4;
+
+    public static void sleep(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException ie) {
+            System.err.println("sleep interrupted");
+        }
+    }
+
+    public static void main(String args[]) {
+        System.out.println("start");
+
+        Main main = new Main();
+        main.run();
+
+        sleep(1000);
+        System.out.println("done");
+    }
+
+    public void run() {
+        createBitmaps();
+
+        System.gc();
+        sleep(250);
+
+        mBitmap2.drawAt(0, 0);
+
+        System.out.println("nulling 1");
+        mBitmap1 = null;
+        System.gc();
+        sleep(500);
+
+        System.out.println("nulling 2");
+        mBitmap2 = null;
+        System.gc();
+        sleep(500);
+
+        System.out.println("nulling 3");
+        mBitmap3 = null;
+        System.gc();
+        sleep(500);
+
+        System.out.println("nulling 4");
+        mBitmap4 = null;
+        System.gc();
+        sleep(500);
+
+        Bitmap.shutDown();
+    }
+
+    /*
+     * Create bitmaps.
+     *
+     * bitmap1 is 10x10 and unique
+     * bitmap2 and bitmap3 are 20x20 and share the same storage.
+     * bitmap4 is just another reference to bitmap3
+     *
+     * When we return there should be no local refs lurking on the stack.
+     */
+    public void createBitmaps() {
+        Bitmap.NativeWrapper dataA = Bitmap.allocNativeStorage(10, 10);
+        Bitmap.NativeWrapper dataB = Bitmap.allocNativeStorage(20, 20);
+        mBitmap1 = new Bitmap("one", 10, 10, dataA);
+        mBitmap2 = new Bitmap("two", 20, 20, dataB);
+        mBitmap3 = mBitmap4 = new Bitmap("three/four", 20, 20, dataB);
+    }
+}
diff --git a/tests/080-oom-throw/expected.txt b/tests/080-oom-throw/expected.txt
new file mode 100644
index 0000000..811f68c
--- /dev/null
+++ b/tests/080-oom-throw/expected.txt
@@ -0,0 +1,2 @@
+Array allocation failed
+Instance allocation failed
diff --git a/tests/080-oom-throw/info.txt b/tests/080-oom-throw/info.txt
new file mode 100644
index 0000000..e8ae6f6
--- /dev/null
+++ b/tests/080-oom-throw/info.txt
@@ -0,0 +1,3 @@
+Inject memory allocation failures for NEW_ARRAY and NEW_INSTANCE and make sure
+the JIT'ed code handles OOM exception correctly since it cannot fall back to
+the interpreter and re-execute the bytecode.
diff --git a/tests/080-oom-throw/src/Main.java b/tests/080-oom-throw/src/Main.java
new file mode 100644
index 0000000..3d75f3d
--- /dev/null
+++ b/tests/080-oom-throw/src/Main.java
@@ -0,0 +1,79 @@
+/*
+ * 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 {
+    static class ArrayMemEater {
+        static int blowup(char[][] holder, int size) {
+            int i = 0;
+            try {
+                for ( ; i < size; i++)
+                    holder[i] = new char[128];
+            } catch (OutOfMemoryError oome) {
+                return i;
+            }
+
+            return size;
+        }
+
+        static void confuseCompilerOptimization(char[][] holder) {
+        }
+    }
+
+    static class InstanceMemEater {
+        InstanceMemEater next;
+        double d1, d2, d3, d4, d5, d6, d7, d8;
+
+        static InstanceMemEater blowup() {
+            InstanceMemEater memEater;
+            try {
+                memEater = new InstanceMemEater();
+            } catch (OutOfMemoryError e) {
+                memEater = null;
+            }
+            return memEater;
+        }
+
+        static void confuseCompilerOptimization(InstanceMemEater memEater) {
+        }
+    }
+
+    static void triggerArrayOOM() {
+        int size = 1 * 1024 * 1024;
+        char[][] holder = new char[size][];
+
+        int count = ArrayMemEater.blowup(holder, size);
+        ArrayMemEater.confuseCompilerOptimization(holder);
+        if (count < size) {
+            System.out.println("Array allocation failed");
+        }
+    }
+
+    static void triggerInstanceOOM() {
+        InstanceMemEater memEater = InstanceMemEater.blowup();
+        InstanceMemEater lastMemEater = memEater;
+        do {
+            lastMemEater.next = InstanceMemEater.blowup();
+            lastMemEater = lastMemEater.next;
+        } while (lastMemEater != null);
+        memEater.confuseCompilerOptimization(memEater);
+        System.out.println("Instance allocation failed");
+    }
+
+    public static void main(String[] args) {
+        triggerArrayOOM();
+        triggerInstanceOOM();
+    }
+}
diff --git a/tests/081-hot-exceptions/expected.txt b/tests/081-hot-exceptions/expected.txt
new file mode 100644
index 0000000..2432ff4
--- /dev/null
+++ b/tests/081-hot-exceptions/expected.txt
@@ -0,0 +1,2 @@
+sum = 0
+exception = 1024
diff --git a/tests/081-hot-exceptions/info.txt b/tests/081-hot-exceptions/info.txt
new file mode 100644
index 0000000..cc514f3
--- /dev/null
+++ b/tests/081-hot-exceptions/info.txt
@@ -0,0 +1,3 @@
+Make a hot exception-throwing path to stress test how the trace builder handles
+exceptions encountered during trace selection. The existence of exceptions will
+cause a control flow change to deviate from the current method.
diff --git a/tests/081-hot-exceptions/src/Main.java b/tests/081-hot-exceptions/src/Main.java
new file mode 100644
index 0000000..90e7af2
--- /dev/null
+++ b/tests/081-hot-exceptions/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * 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 {
+    static class ArrayObj {
+        int[] array;
+
+        int getArrayElement(int i) throws NullPointerException {
+            return array[i];
+        }
+    }
+
+    public static void main(String[] args) {
+        ArrayObj arrayObj2 = new ArrayObj();
+        int sum = 0;
+        int exception = 0;
+
+        for (int i = 0; i < 1024; i++) {
+            try {
+                // A hot method invocation that always encounters exceptions
+                sum += arrayObj2.getArrayElement(i);
+            } catch (NullPointerException npe) {
+                exception++;
+            }
+        }
+        System.out.println("sum = " + sum);
+        System.out.println("exception = " + exception);
+    }
+}
diff --git a/tests/082-inline-execute/expected.txt b/tests/082-inline-execute/expected.txt
new file mode 100644
index 0000000..5059fe8
--- /dev/null
+++ b/tests/082-inline-execute/expected.txt
@@ -0,0 +1,8 @@
+Length of  : 0
+Length of x : 1
+Length of 01234567890123456789012345678901234567890123456789012345678901234567890123456789 : 80
+Now is the time[0] = "N"
+Now is the time[1] = "o"
+Now is the time[10] = " "
+Now is the time[last] = "e"
+Num throws 2000
diff --git a/tests/082-inline-execute/info.txt b/tests/082-inline-execute/info.txt
new file mode 100644
index 0000000..ddc31fe
--- /dev/null
+++ b/tests/082-inline-execute/info.txt
@@ -0,0 +1,8 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+This test covers the string inline-execute tests, and it done in a
+looping manner to ensure that the tests are translated when a Jit is
+active.
diff --git a/tests/082-inline-execute/src/Main.java b/tests/082-inline-execute/src/Main.java
new file mode 100644
index 0000000..b512091
--- /dev/null
+++ b/tests/082-inline-execute/src/Main.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test for Jit's handling of string inline-execute.  Should be tested
+ * twice - once using self-cosimulation (if available) and once without.
+ * The non-self-cosimulation test ensures that the answer computed the first
+ * time through (via the interpreter) is the same after looping enough
+ * to trigger translation.
+ */
+
+import junit.framework.Assert;
+
+public class Main {
+    public static void main(String args[]) {
+        int i;
+        stringLengthTest();
+        stringCharAtTest();
+        stringIndexOfTest();
+        for (i = 0; i < 1000; i++)
+            stringCompareToTest();
+    }
+
+    public static void stringLengthTest() {
+        String str0 = "";
+        String str1 = "x";
+        String str80 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789";
+        int len0 = str0.length();
+        int len1 = str1.length();
+        int len80 = str80.length();
+        int i;
+
+        System.out.println("Length of " + str0 + " : " + len0);
+        System.out.println("Length of " + str1 + " : " + len1);
+        System.out.println("Length of " + str80 + " : " + len80);
+
+        for (i = 0; i < 1000; i++) {
+            assert(str0.length() == len0);
+            assert(str1.length() == len1);
+            assert(str80.length() == len80);
+        }
+    }
+
+    public static void stringCharAtTest() {
+        String testStr = "Now is the time";
+        int under = -1;
+        int over = testStr.length();
+        int numThrown = 0;
+        int numNotThrown = 0;
+        int at0 = testStr.charAt(0);
+        int at1 = testStr.charAt(1);
+        int at10 = testStr.charAt(10);
+        int atLast = testStr.charAt(testStr.length()-1);
+        int i;
+
+        System.out.println(testStr + "[0] = \"" + (char)at0 + "\"");
+        System.out.println(testStr + "[1] = \"" + (char)at1 + "\"");
+        System.out.println(testStr + "[10] = \"" + (char)at10 + "\"");
+        System.out.println(testStr + "[last] = \"" + (char)atLast + "\"");
+
+        for (i = 0; i < 1000; i++) {
+            assert(at0 == testStr.charAt(0));
+            assert(at1 == testStr.charAt(1));
+            assert(at10 == testStr.charAt(10));
+            assert(atLast == testStr.charAt(testStr.length()-1));
+        }
+
+        for (i = 0; i < 1000; i++) {
+            try {
+                testStr.charAt(under);
+                numNotThrown++;
+            } catch (StringIndexOutOfBoundsException sioobe) {
+                numThrown++;
+            }
+            try {
+                testStr.charAt(over);
+                numNotThrown++;
+            } catch (StringIndexOutOfBoundsException sioobe) {
+                numThrown++;
+            }
+        }
+        assert(numNotThrown == 0);
+        System.out.println("Num throws " + numThrown);
+    }
+
+
+    public static void stringIndexOfTest() {
+        String str0 = "";
+        String str3 = "abc";
+        String str10 = "abcdefghij";
+        String str40 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabc";
+        int i;
+
+        for (i = 0; i < 1000; i++) {
+            assert(str0.indexOf('a') == -1);
+            assert(str3.indexOf('a') == 0);
+            assert(str3.indexOf('b') == 1);
+            assert(str3.indexOf('c') == 2);
+            assert(str10.indexOf('j') == 9);
+            assert(str40.indexOf('a') == 0);
+            assert(str40.indexOf('b') == 38);
+            assert(str40.indexOf('c') == 39);
+            assert(str0.indexOf('a',20) == -1);
+            assert(str0.indexOf('a',0) == -1);
+            assert(str0.indexOf('a',-1) == -1);
+            assert(str3.indexOf('a',0) == 0);
+            assert(str3.indexOf('a',1) == -1);
+            assert(str3.indexOf('a',1234) == -1);
+            assert(str3.indexOf('b',0) == 1);
+            assert(str3.indexOf('b',1) == 1);
+            assert(str3.indexOf('c',2) == 2);
+            assert(str10.indexOf('j',5) == 9);
+            assert(str10.indexOf('j',9) == 9);
+            assert(str40.indexOf('a',10) == 10);
+            assert(str40.indexOf('b',40) == -1);
+        }
+
+    }
+
+    public static void stringCompareToTest() {
+        String test = "0123456789";
+        String test1 = new String("0123456789");    // different object
+        String test2 = new String("0123456780");    // different value
+        String offset = new String("xxx0123456789yyy");
+        String sub = offset.substring(3, 13);
+        String str32 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+        String str33 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy";
+        String lc = "abcdefg";
+        String uc = "ABCDEFG";
+        Object blah = new Object();
+
+        for (int i = 0; i < 100; i++) {
+            String y = lc.toUpperCase();
+            Assert.assertTrue(y.equals(uc));
+        }
+
+        Assert.assertEquals(str32.compareTo(str33), -1);
+        Assert.assertEquals(str33.compareTo(str32), 1);
+
+        Assert.assertTrue(test.equals(test));
+        Assert.assertTrue(test.equals(test1));
+        Assert.assertFalse(test.equals(test2));
+
+        Assert.assertEquals(test.compareTo(test1), 0);
+        Assert.assertTrue(test1.compareTo(test2) > 0);
+        Assert.assertTrue(test2.compareTo(test1) < 0);
+
+        /* compare string with a nonzero offset, in left/right side */
+        Assert.assertEquals(test.compareTo(sub), 0);
+        Assert.assertEquals(sub.compareTo(test), 0);
+        Assert.assertTrue(test.equals(sub));
+        Assert.assertTrue(sub.equals(test));
+        /* same base, one is a substring */
+        Assert.assertFalse(offset.equals(sub));
+        Assert.assertFalse(sub.equals(offset));
+        /* wrong class */
+        Assert.assertFalse(test.equals(blah));
+
+        /* null ptr - throw */
+        try {
+            test.compareTo(null);
+            Assert.fail("didn't get expected npe");
+        } catch (NullPointerException npe) {
+        }
+        /* null ptr - ok */
+        Assert.assertFalse(test.equals(null));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("123456789"));
+        Assert.assertFalse(test.equals(test1));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("23456789"));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("3456789"));
+
+        test = test.substring(1);
+        Assert.assertTrue(test.equals("456789"));
+
+        test = test.substring(3,5);
+        Assert.assertTrue(test.equals("78"));
+
+        test = "this/is/a/path";
+        String[] strings = test.split("/");
+        Assert.assertEquals(4, strings.length);
+
+        Assert.assertEquals("this is a path", test.replaceAll("/", " "));
+        Assert.assertEquals("this is a path", test.replace("/", " "));
+    }
+
+}
diff --git a/tests/082-inline-execute/src/junit/framework/Assert.java b/tests/082-inline-execute/src/junit/framework/Assert.java
new file mode 100644
index 0000000..364e646
--- /dev/null
+++ b/tests/082-inline-execute/src/junit/framework/Assert.java
@@ -0,0 +1,291 @@
+package junit.framework;
+
+/**
+ * A set of assert methods.  Messages are only displayed when an assert fails.
+ */
+
+public class Assert {
+    /**
+     * Protect constructor since it is a static only class
+     */
+    protected Assert() {
+    }
+
+    /**
+     * Asserts that a condition is true. If it isn't it throws
+     * an AssertionFailedError with the given message.
+     */
+    static public void assertTrue(String message, boolean condition) {
+        if (!condition)
+            fail(message);
+    }
+    /**
+     * Asserts that a condition is true. If it isn't it throws
+     * an AssertionFailedError.
+     */
+    static public void assertTrue(boolean condition) {
+        assertTrue(null, condition);
+    }
+    /**
+     * Asserts that a condition is false. If it isn't it throws
+     * an AssertionFailedError with the given message.
+     */
+    static public void assertFalse(String message, boolean condition) {
+        assertTrue(message, !condition);
+    }
+    /**
+     * Asserts that a condition is false. If it isn't it throws
+     * an AssertionFailedError.
+     */
+    static public void assertFalse(boolean condition) {
+        assertFalse(null, condition);
+    }
+    /**
+     * Fails a test with the given message.
+     */
+    static public void fail(String message) {
+        throw new AssertionFailedError(message);
+    }
+    /**
+     * Fails a test with no message.
+     */
+    static public void fail() {
+        fail(null);
+    }
+    /**
+     * Asserts that two objects are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, Object expected, Object actual) {
+        if (expected == null && actual == null)
+            return;
+        if (expected != null && expected.equals(actual))
+            return;
+        failNotEquals(message, expected, actual);
+    }
+    /**
+     * Asserts that two objects are equal. If they are not
+     * an AssertionFailedError is thrown.
+     */
+    static public void assertEquals(Object expected, Object actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two Strings are equal.
+     */
+    static public void assertEquals(String message, String expected, String actual) {
+        if (expected == null && actual == null)
+            return;
+        if (expected != null && expected.equals(actual))
+            return;
+        throw new ComparisonFailure(message, expected, actual);
+    }
+    /**
+     * Asserts that two Strings are equal.
+     */
+    static public void assertEquals(String expected, String actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two doubles are equal concerning a delta.  If they are not
+     * an AssertionFailedError is thrown with the given message.  If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(String message, double expected, double actual, double delta) {
+        // handle infinity specially since subtracting to infinite values gives NaN and the
+        // the following test fails
+        if (Double.isInfinite(expected)) {
+            if (!(expected == actual))
+                failNotEquals(message, new Double(expected), new Double(actual));
+        } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false
+            failNotEquals(message, new Double(expected), new Double(actual));
+    }
+    /**
+     * Asserts that two doubles are equal concerning a delta. If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(double expected, double actual, double delta) {
+        assertEquals(null, expected, actual, delta);
+    }
+    /**
+     * Asserts that two floats are equal concerning a delta. If they are not
+     * an AssertionFailedError is thrown with the given message.  If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(String message, float expected, float actual, float delta) {
+         // handle infinity specially since subtracting to infinite values gives NaN and the
+        // the following test fails
+        if (Float.isInfinite(expected)) {
+            if (!(expected == actual))
+                failNotEquals(message, new Float(expected), new Float(actual));
+        } else if (!(Math.abs(expected-actual) <= delta))
+              failNotEquals(message, new Float(expected), new Float(actual));
+    }
+    /**
+     * Asserts that two floats are equal concerning a delta. If the expected
+     * value is infinity then the delta value is ignored.
+     */
+    static public void assertEquals(float expected, float actual, float delta) {
+        assertEquals(null, expected, actual, delta);
+    }
+    /**
+     * Asserts that two longs are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, long expected, long actual) {
+        assertEquals(message, new Long(expected), new Long(actual));
+    }
+    /**
+     * Asserts that two longs are equal.
+     */
+    static public void assertEquals(long expected, long actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two booleans are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, boolean expected, boolean actual) {
+            assertEquals(message, new Boolean(expected), new Boolean(actual));
+      }
+    /**
+     * Asserts that two booleans are equal.
+      */
+    static public void assertEquals(boolean expected, boolean actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two bytes are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+      static public void assertEquals(String message, byte expected, byte actual) {
+        assertEquals(message, new Byte(expected), new Byte(actual));
+    }
+    /**
+        * Asserts that two bytes are equal.
+     */
+    static public void assertEquals(byte expected, byte actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two chars are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+      static public void assertEquals(String message, char expected, char actual) {
+            assertEquals(message, new Character(expected), new Character(actual));
+      }
+    /**
+     * Asserts that two chars are equal.
+     */
+      static public void assertEquals(char expected, char actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two shorts are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertEquals(String message, short expected, short actual) {
+            assertEquals(message, new Short(expected), new Short(actual));
+    }
+      /**
+     * Asserts that two shorts are equal.
+     */
+    static public void assertEquals(short expected, short actual) {
+        assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that two ints are equal. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+      static public void assertEquals(String message, int expected, int actual) {
+        assertEquals(message, new Integer(expected), new Integer(actual));
+      }
+      /**
+        * Asserts that two ints are equal.
+     */
+      static public void assertEquals(int expected, int actual) {
+          assertEquals(null, expected, actual);
+    }
+    /**
+     * Asserts that an object isn't null.
+     */
+    static public void assertNotNull(Object object) {
+        assertNotNull(null, object);
+    }
+    /**
+     * Asserts that an object isn't null. If it is
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertNotNull(String message, Object object) {
+        assertTrue(message, object != null);
+    }
+    /**
+     * Asserts that an object is null.
+     */
+    static public void assertNull(Object object) {
+        assertNull(null, object);
+    }
+    /**
+     * Asserts that an object is null.  If it is not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertNull(String message, Object object) {
+        assertTrue(message, object == null);
+    }
+    /**
+     * Asserts that two objects refer to the same object. If they are not
+     * an AssertionFailedError is thrown with the given message.
+     */
+    static public void assertSame(String message, Object expected, Object actual) {
+        if (expected == actual)
+            return;
+        failNotSame(message, expected, actual);
+    }
+    /**
+     * Asserts that two objects refer to the same object. If they are not
+     * the same an AssertionFailedError is thrown.
+     */
+    static public void assertSame(Object expected, Object actual) {
+        assertSame(null, expected, actual);
+    }
+     /**
+      * Asserts that two objects refer to the same object. If they are not
+      * an AssertionFailedError is thrown with the given message.
+      */
+    static public void assertNotSame(String message, Object expected, Object actual) {
+        if (expected == actual)
+            failSame(message);
+    }
+    /**
+     * Asserts that two objects refer to the same object. If they are not
+     * the same an AssertionFailedError is thrown.
+     */
+    static public void assertNotSame(Object expected, Object actual) {
+        assertNotSame(null, expected, actual);
+    }
+
+    static private void failSame(String message) {
+        String formatted= "";
+         if (message != null)
+             formatted= message+" ";
+         fail(formatted+"expected not same");
+    }
+
+    static private void failNotSame(String message, Object expected, Object actual) {
+        String formatted= "";
+        if (message != null)
+            formatted= message+" ";
+        fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
+    }
+
+    static private void failNotEquals(String message, Object expected, Object actual) {
+        fail(format(message, expected, actual));
+    }
+
+    static String format(String message, Object expected, Object actual) {
+        String formatted= "";
+        if (message != null)
+            formatted= message+" ";
+        return formatted+"expected:<"+expected+"> but was:<"+actual+">";
+    }
+}
diff --git a/tests/082-inline-execute/src/junit/framework/AssertionFailedError.java b/tests/082-inline-execute/src/junit/framework/AssertionFailedError.java
new file mode 100644
index 0000000..e9cb3a3
--- /dev/null
+++ b/tests/082-inline-execute/src/junit/framework/AssertionFailedError.java
@@ -0,0 +1,13 @@
+package junit.framework;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends Error {
+
+    public AssertionFailedError () {
+    }
+    public AssertionFailedError (String message) {
+        super (message);
+    }
+}
diff --git a/tests/082-inline-execute/src/junit/framework/ComparisonFailure.java b/tests/082-inline-execute/src/junit/framework/ComparisonFailure.java
new file mode 100644
index 0000000..0cb2cee
--- /dev/null
+++ b/tests/082-inline-execute/src/junit/framework/ComparisonFailure.java
@@ -0,0 +1,68 @@
+package junit.framework;
+
+/**
+ * Thrown when an assert equals for Strings failed.
+ *
+ * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
+ */
+public class ComparisonFailure extends AssertionFailedError {
+    private String fExpected;
+    private String fActual;
+
+    /**
+     * Constructs a comparison failure.
+     * @param message the identifying message or null
+     * @param expected the expected string value
+     * @param actual the actual string value
+     */
+    public ComparisonFailure (String message, String expected, String actual) {
+        super (message);
+        fExpected= expected;
+        fActual= actual;
+    }
+
+    /**
+     * Returns "..." in place of common prefix and "..." in
+     * place of common suffix between expected and actual.
+     *
+     * @see java.lang.Throwable#getMessage()
+     */
+    public String getMessage() {
+        if (fExpected == null || fActual == null)
+            return Assert.format(super.getMessage(), fExpected, fActual);
+
+        int end= Math.min(fExpected.length(), fActual.length());
+
+        int i= 0;
+        for(; i < end; i++) {
+            if (fExpected.charAt(i) != fActual.charAt(i))
+                break;
+        }
+        int j= fExpected.length()-1;
+        int k= fActual.length()-1;
+        for (; k >= i && j >= i; k--,j--) {
+            if (fExpected.charAt(j) != fActual.charAt(k))
+                break;
+        }
+        String actual, expected;
+
+        // equal strings
+        if (j < i && k < i) {
+            expected= fExpected;
+            actual= fActual;
+        } else {
+            expected= fExpected.substring(i, j+1);
+            actual= fActual.substring(i, k+1);
+            if (i <= end && i > 0) {
+                expected= "..."+expected;
+                actual= "..."+actual;
+            }
+
+            if (j < fExpected.length()-1)
+                expected= expected+"...";
+            if (k < fActual.length()-1)
+                actual= actual+"...";
+        }
+        return Assert.format(super.getMessage(), expected, actual);
+    }
+}
diff --git a/tests/083-jit-regressions/expected.txt b/tests/083-jit-regressions/expected.txt
new file mode 100644
index 0000000..4b9ad5b
--- /dev/null
+++ b/tests/083-jit-regressions/expected.txt
@@ -0,0 +1,4 @@
+b2296099 passes
+b2302318 passes
+b2487514 passes
+b5884080 passes
diff --git a/tests/083-jit-regressions/info.txt b/tests/083-jit-regressions/info.txt
new file mode 100644
index 0000000..00c24ee
--- /dev/null
+++ b/tests/083-jit-regressions/info.txt
@@ -0,0 +1,11 @@
+This is a miscellaneous test that was imported into the new-at-the-time
+runtime test framework. The test is intended to exercise basic features,
+and as such cannot be build on top of junit, since failure of such basic
+features might disrupt junit.
+
+This test covers JIT regressions
+
+2296099 JIT shift bug
+2302318 Crash during spin-on-suspend testing
+2487514 Missed exception in PriorityBlockingQueueTest.testToArray1_BadArg
+5884080 ICS JIT regression in nested loop formation
diff --git a/tests/083-jit-regressions/src/Main.java b/tests/083-jit-regressions/src/Main.java
new file mode 100644
index 0000000..3b596db
--- /dev/null
+++ b/tests/083-jit-regressions/src/Main.java
@@ -0,0 +1,143 @@
+/*
+ * 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.util.concurrent.*;
+
+/**
+ * Test for Jit regressions.
+ */
+public class Main {
+    public static void main(String args[]) throws Exception {
+        b2296099Test();
+        b2302318Test();
+        b2487514Test();
+        b5884080Test();
+    }
+
+    static void b2296099Test() throws Exception {
+       int x = -1190771042;
+       int dist = 360530809;
+       int xl = -1190771042;
+       int distl = 360530809;
+
+       for (int i = 0; i < 100000; i++) {
+           int b = rotateLeft(x, dist);
+           if (b != 1030884493)
+               throw new RuntimeException("Unexpected value: " + b
+                       + " after " + i + " iterations");
+       }
+       for (int i = 0; i < 100000; i++) {
+           long bl = rotateLeft(xl, distl);
+           if (bl != 1030884493)
+               throw new RuntimeException("Unexpected value: " + bl
+                       + " after " + i + " iterations");
+       }
+       System.out.println("b2296099 passes");
+   }
+
+    static int rotateLeft(int i, int distance) {
+        return ((i << distance) | (i >>> (-distance)));
+    }
+
+    static void b2302318Test() {
+        System.gc();
+
+        SpinThread slow = new SpinThread(Thread.MIN_PRIORITY);
+        SpinThread fast1 = new SpinThread(Thread.NORM_PRIORITY);
+        SpinThread fast2 = new SpinThread(Thread.MAX_PRIORITY);
+
+        slow.setDaemon(true);
+        fast1.setDaemon(true);
+        fast2.setDaemon(true);
+
+        fast2.start();
+        slow.start();
+        fast1.start();
+        try {
+            Thread.sleep(3000);
+        } catch (InterruptedException ie) {/*ignore */}
+        System.gc();
+
+        System.out.println("b2302318 passes");
+    }
+
+    static void b2487514Test() {
+        PriorityBlockingQueue q = new PriorityBlockingQueue(10);
+        int catchCount = 0;
+
+        q.offer(new Integer(0));
+        /*
+         * Warm up the code cache to have toArray() compiled. The key here is
+         * to pass a compatible type so that there are no exceptions when
+         * executing the method body (ie the APUT_OBJECT bytecode).
+         */
+        for (int i = 0; i < 1000; i++) {
+            Integer[] ints = (Integer[]) q.toArray(new Integer[5]);
+        }
+
+        /* Now pass an incompatible type which is guaranteed to throw */
+        for (int i = 0; i < 1000; i++) {
+            try {
+                Object[] obj = q.toArray(new String[5]);
+            }
+            catch (ArrayStoreException  success) {
+                catchCount++;
+            }
+        }
+
+        if (catchCount == 1000) {
+            System.out.println("b2487514 passes");
+        }
+        else {
+            System.out.println("b2487514 fails: catchCount is " + catchCount +
+                               " (expecting 1000)");
+        }
+    }
+
+    static void b5884080Test() {
+        int vA = 1;
+
+        int l = 0;
+        do
+        {
+            int k = 0;
+            do
+                vA += 1;
+            while(++k < 100);
+        } while(++l < 1000);
+        if (vA == 100001) {
+            System.out.println("b5884080 passes");
+        }
+        else {
+            System.out.println("b5884080 fails: vA is " + vA +
+                               " (expecting 100001)");
+        }
+    }
+}
+
+class SpinThread extends Thread {
+    int mPriority;
+
+    SpinThread(int prio) {
+        super("Spin prio=" + prio);
+        mPriority = prio;
+    }
+
+    public void run() {
+        setPriority(mPriority);
+        while (true) {}
+    }
+}
diff --git a/tests/084-class-init/expected.txt b/tests/084-class-init/expected.txt
new file mode 100644
index 0000000..6e74fbb
--- /dev/null
+++ b/tests/084-class-init/expected.txt
@@ -0,0 +1,8 @@
+Got expected EIIE for FIELD0
+Got expected NCDFE for FIELD0
+Got expected NCDFE for FIELD1
+SlowInit static block pre-sleep
+SlowInit static block post-sleep
+MethodThread message
+Fields (child thread): 111222333444
+Fields (main thread): 111222333444
diff --git a/tests/084-class-init/info.txt b/tests/084-class-init/info.txt
new file mode 100644
index 0000000..00fa31b
--- /dev/null
+++ b/tests/084-class-init/info.txt
@@ -0,0 +1 @@
+Test class initialization edge cases and race conditions.
diff --git a/tests/084-class-init/src/IntHolder.java b/tests/084-class-init/src/IntHolder.java
new file mode 100644
index 0000000..4012d6e
--- /dev/null
+++ b/tests/084-class-init/src/IntHolder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Holds an int.
+ */
+public class IntHolder {
+    private int mValue = 0;
+
+    /**
+     * Constructs an IntHolder with the specified value.  Throws an
+     * exception if the initial value is less than zero.
+     */
+    public IntHolder(int initialVal) {
+        if (initialVal < 0)
+            throw new RuntimeException("negative number");
+
+        mValue = initialVal;
+    }
+
+    public int getValue() {
+        return mValue;
+    }
+    public void setValue(int val) {
+        mValue = val;
+    }
+}
diff --git a/tests/084-class-init/src/Main.java b/tests/084-class-init/src/Main.java
new file mode 100644
index 0000000..f777113
--- /dev/null
+++ b/tests/084-class-init/src/Main.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+    public static void main(String[] args) {
+        checkExceptions();
+        checkTiming();
+    }
+
+    public static void sleep(int msec) {
+        try {
+            Thread.sleep(msec);
+        } catch (InterruptedException ie) {
+            System.err.println("sleep interrupted");
+        }
+    }
+
+    static void checkExceptions() {
+        try {
+            System.out.println(PartialInit.FIELD0);
+            System.err.println("Construction of PartialInit succeeded unexpectedly");
+        } catch (ExceptionInInitializerError eiie) {
+            System.out.println("Got expected EIIE for FIELD0");
+        }
+
+        try {
+            System.out.println(PartialInit.FIELD0);
+            System.err.println("Load of FIELD0 succeeded unexpectedly");
+        } catch (NoClassDefFoundError ncdfe) {
+            System.out.println("Got expected NCDFE for FIELD0");
+        }
+        try {
+            System.out.println(PartialInit.FIELD1);
+            System.err.println("Load of FIELD1 succeeded unexpectedly");
+        } catch (NoClassDefFoundError ncdfe) {
+            System.out.println("Got expected NCDFE for FIELD1");
+        }
+    }
+
+    static void checkTiming() {
+        FieldThread fieldThread = new FieldThread();
+        MethodThread methodThread = new MethodThread();
+
+        fieldThread.start();
+        methodThread.start();
+
+        /* start class init */
+        IntHolder zero = SlowInit.FIELD0;
+
+        /* wait for children to complete */
+        try {
+            fieldThread.join();
+            methodThread.join();
+        } catch (InterruptedException ie) {
+            System.err.println(ie);
+        }
+
+        /* print all values */
+        System.out.println("Fields (main thread): " +
+            SlowInit.FIELD0.getValue() + SlowInit.FIELD1.getValue() +
+            SlowInit.FIELD2.getValue() + SlowInit.FIELD3.getValue());
+    }
+
+    static class FieldThread extends Thread {
+        public void run() {
+            /* allow class init to start */
+            Main.sleep(200);
+
+            /* collect fields; should delay until class init completes */
+            int field0, field1, field2, field3;
+            field0 = SlowInit.FIELD0.getValue();
+            field1 = SlowInit.FIELD1.getValue();
+            field2 = SlowInit.FIELD2.getValue();
+            field3 = SlowInit.FIELD3.getValue();
+
+            /* let MethodThread print first */
+            Main.sleep(400);
+            System.out.println("Fields (child thread): " +
+                field0 + field1 + field2 + field3);
+        }
+    }
+
+    static class MethodThread extends Thread {
+        public void run() {
+            /* allow class init to start */
+            Main.sleep(200);
+
+            /* use a method that shouldn't be accessible yet */
+            SlowInit.printMsg("MethodThread message");
+        }
+    }
+}
diff --git a/tests/084-class-init/src/PartialInit.java b/tests/084-class-init/src/PartialInit.java
new file mode 100644
index 0000000..d4c71ff
--- /dev/null
+++ b/tests/084-class-init/src/PartialInit.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Partially-initialized class.
+ */
+public class PartialInit {
+    public static final IntHolder FIELD0 = new IntHolder(1);    // succeeds
+    public static final IntHolder FIELD1 = new IntHolder(-2);   // throws
+}
diff --git a/tests/084-class-init/src/SlowInit.java b/tests/084-class-init/src/SlowInit.java
new file mode 100644
index 0000000..8ac72be
--- /dev/null
+++ b/tests/084-class-init/src/SlowInit.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Class that initializes with a pause.
+ */
+public class SlowInit {
+
+    public static final IntHolder FIELD0 = new IntHolder(0);
+    public static final IntHolder FIELD1 = new IntHolder(0);
+    public static final IntHolder FIELD2 = new IntHolder(0);
+    public static final IntHolder FIELD3 = new IntHolder(0);
+
+    public static void printMsg(String msg) {
+        System.out.println(msg);
+    }
+
+    static {
+        FIELD0.setValue(111);
+        FIELD1.setValue(222);
+        printMsg("SlowInit static block pre-sleep");
+        Main.sleep(600);
+        printMsg("SlowInit static block post-sleep");
+        FIELD2.setValue(333);
+        FIELD3.setValue(444);
+    };
+}
diff --git a/tests/085-old-style-inner-class/build b/tests/085-old-style-inner-class/build
new file mode 100644
index 0000000..dc6f3bb
--- /dev/null
+++ b/tests/085-old-style-inner-class/build
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# We compile for a 1.4 target to suppress the use of EnclosingMethod
+# attributes.
+mkdir classes
+${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
+
+# Suppress stderr to keep the inner class warnings out of the expected output.
+dx --debug --dex --dump-to=classes.lst --output=classes.dex \
+    --dump-width=1000 classes 2>/dev/null
+
+zip test.jar classes.dex
diff --git a/tests/085-old-style-inner-class/expected.txt b/tests/085-old-style-inner-class/expected.txt
new file mode 100644
index 0000000..63a0076
--- /dev/null
+++ b/tests/085-old-style-inner-class/expected.txt
@@ -0,0 +1,8 @@
+Class: Main$1
+  getDeclaringClass(): (null)
+  getEnclosingClass(): (null)
+  getEnclosingMethod(): (null)
+Class: Main$2
+  getDeclaringClass(): (null)
+  getEnclosingClass(): (null)
+  getEnclosingMethod(): (null)
diff --git a/tests/085-old-style-inner-class/info.txt b/tests/085-old-style-inner-class/info.txt
new file mode 100644
index 0000000..9e5c4f9
--- /dev/null
+++ b/tests/085-old-style-inner-class/info.txt
@@ -0,0 +1,2 @@
+Test that the conversion of an old-style (pre-1.5) inner class results
+in a loss of inner class reflection information.
diff --git a/tests/085-old-style-inner-class/src/Main.java b/tests/085-old-style-inner-class/src/Main.java
new file mode 100644
index 0000000..c9a5b72
--- /dev/null
+++ b/tests/085-old-style-inner-class/src/Main.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+/**
+ * Test reflection on old-style inner classes.
+ */
+public class Main {
+    private static Runnable theRunnable = new Runnable() {
+            public void run() { }
+        };
+
+    private static Runnable create() {
+        return new Runnable() {
+                public void run() { }
+            };
+    }
+
+    private static String nameOf(Class clazz) {
+        return (clazz == null) ? "(null)" : clazz.getName();
+    }
+
+    private static String nameOf(Method meth) {
+        return (meth == null) ? "(null)" : meth.toString();
+    }
+
+    private static void infoFor(Class clazz) {
+        System.out.println("Class: " + nameOf(clazz) + "\n" +
+                "  getDeclaringClass(): " +
+                nameOf(clazz.getDeclaringClass()) + "\n" +
+                "  getEnclosingClass(): " +
+                nameOf(clazz.getEnclosingClass()) + "\n" +
+                "  getEnclosingMethod(): " +
+                nameOf(clazz.getEnclosingMethod()));
+    }
+
+    public static void main(String args[]) {
+        infoFor(theRunnable.getClass());
+        infoFor(create().getClass());
+    }
+}
diff --git a/tests/086-null-super/expected.txt b/tests/086-null-super/expected.txt
new file mode 100644
index 0000000..20c6796
--- /dev/null
+++ b/tests/086-null-super/expected.txt
@@ -0,0 +1 @@
+Got expected ITE/NPE
diff --git a/tests/086-null-super/info.txt b/tests/086-null-super/info.txt
new file mode 100644
index 0000000..f983bd0
--- /dev/null
+++ b/tests/086-null-super/info.txt
@@ -0,0 +1,7 @@
+ClassLoader.loadClass() is expected to throw an exception, usually
+ClassNotFound, if it can't find the given Class, and not return null.
+
+This is a regression test for a defect in Dalvik, which was assuming
+that if there was no exception, the value returned would be non-null.
+
+This test is not expected to work for the reference implementation.
diff --git a/tests/086-null-super/src/Main.java b/tests/086-null-super/src/Main.java
new file mode 100644
index 0000000..6decb20
--- /dev/null
+++ b/tests/086-null-super/src/Main.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Class loader test.
+ */
+public class Main {
+    /**
+     * Thrown when an unexpected Exception is caught internally.
+     */
+    static class TestFailed extends Exception {
+        public TestFailed(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    /**
+     * A class loader which loads classes from the dex file
+     * "test.jar". However, it will return null when asked to load the
+     * class InaccessibleSuper.
+     *
+     * When testing code calls BrokenDexLoader's findBrokenClass(),
+     * a BrokenDexLoader will be the defining loader for the class
+     * Inaccessible.  The VM will call the defining loader for
+     * "InaccessibleSuper", which will return null, which the VM
+     * should be able to deal with gracefully.
+     *
+     * Note that this depends heavily on the Dalvik test harness.
+     */
+    static class BrokenDexLoader extends ClassLoader {
+
+        /** We return null when asked to load InaccessibleSuper. */
+        private static class InaccessibleSuper {}
+        private static class Inaccessible extends InaccessibleSuper {}
+
+        private static final String SUPERCLASS_NAME =
+                "Main$BrokenDexLoader$InaccessibleSuper";
+        private static final String CLASS_NAME =
+                "Main$BrokenDexLoader$Inaccessible";
+
+        private static final String DEX_FILE = "test.jar";
+
+        public BrokenDexLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        /**
+         * Finds the class with the specified binary name, from DEX_FILE.
+         *
+         * If we don't find a match, we throw an exception.
+         */
+        private Class<?> findDexClass(String name)
+                throws TestFailed, InvocationTargetException
+        {
+
+            try {
+                /*
+                 * Find the DexFile class, and construct a DexFile object
+                 * through reflection, then call loadCLass on it.
+                 */
+                Class mDexClass = ClassLoader.getSystemClassLoader().
+                        loadClass("dalvik/system/DexFile");
+                Constructor ctor = mDexClass.
+                        getConstructor(new Class[] {String.class});
+                Object mDexFile = ctor.newInstance(DEX_FILE);
+                Method meth = mDexClass.
+                        getMethod("loadClass",
+                            new Class[] { String.class, ClassLoader.class });
+                /*
+                 * Invoking loadClass on CLASS_NAME is expected to
+                 * throw an InvocationTargetException. Anything else
+                 * is an error we can't recover from.
+                 */
+                meth.invoke(mDexFile, name, this);
+            } catch (NoSuchMethodException nsme) {
+                throw new TestFailed(nsme);
+            } catch (InstantiationException ie) {
+                throw new TestFailed(ie);
+            } catch (IllegalAccessException iae) {
+                throw new TestFailed(iae);
+            } catch (ClassNotFoundException cnfe) {
+                throw new TestFailed(cnfe);
+            }
+
+            return null;
+        }
+
+        /**
+         * Load a class.
+         *
+         * Return null if the class's name is SUPERCLASS_NAME;
+         * otherwise invoke the super's loadClass method.
+         */
+        public Class<?> loadClass(String name, boolean resolve)
+                throws ClassNotFoundException
+        {
+            if (SUPERCLASS_NAME.equals(name)) {
+                return null;
+            }
+
+            return super.loadClass(name, resolve);
+        }
+
+        /**
+         * Attempt to find the class with the superclass we refuse to
+         * load.  This is expected to throw an
+         * InvocationTargetException, with a NullPointerException as
+         * its cause.
+         */
+        public void findBrokenClass()
+                throws TestFailed, InvocationTargetException
+        {
+            findDexClass(CLASS_NAME);
+        }
+    }
+
+    /**
+     * Main entry point.
+     */
+    public static void main(String[] args)
+            throws TestFailed, ClassNotFoundException {
+        /*
+         * Run test.
+         */
+        testFailLoadAndGc();
+    }
+
+    /**
+     * See if we can GC after a failed load.
+     */
+    static void testFailLoadAndGc() throws TestFailed {
+        try {
+            BrokenDexLoader loader;
+
+            loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
+            loader.findBrokenClass();
+            System.err.println("ERROR: Inaccessible was accessible");
+        } catch (InvocationTargetException ite) {
+            Throwable cause = ite.getCause();
+            if (cause instanceof NullPointerException) {
+                System.err.println("Got expected ITE/NPE");
+            } else {
+                System.err.println("Got unexpected ITE");
+                ite.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/tests/087-gc-after-link/expected.txt b/tests/087-gc-after-link/expected.txt
new file mode 100644
index 0000000..3b2d33a
--- /dev/null
+++ b/tests/087-gc-after-link/expected.txt
@@ -0,0 +1,2 @@
+Got expected ITE/NPE
+GC complete.
diff --git a/tests/087-gc-after-link/info.txt b/tests/087-gc-after-link/info.txt
new file mode 100644
index 0000000..9483838
--- /dev/null
+++ b/tests/087-gc-after-link/info.txt
@@ -0,0 +1,8 @@
+This test causes a linkage error, which calls dvmFreeClassInnards on
+the unlinked Class.
+
+This is a regression test for a defect in Dalvik, which was assuming
+that dvmFreeClassInnards could be called twice on the same class.
+
+This test is a modified version of test 086.
+This test is not expected to work for the reference implementation.
diff --git a/tests/087-gc-after-link/src/Main.java b/tests/087-gc-after-link/src/Main.java
new file mode 100644
index 0000000..dc68f9f
--- /dev/null
+++ b/tests/087-gc-after-link/src/Main.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Class loader test.
+ */
+public class Main {
+    /**
+     * Thrown when an unexpected Exception is caught internally.
+     */
+    static class TestFailed extends Exception {
+        public TestFailed(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    /**
+     * A class loader which loads classes from the dex file
+     * "test.jar". However, it will return null when asked to load the
+     * class InaccessibleSuper.
+     *
+     * When testing code calls BrokenDexLoader's findBrokenClass(),
+     * a BrokenDexLoader will be the defining loader for the class
+     * Inaccessible.  The VM will call the defining loader for
+     * "InaccessibleSuper", which will return null, which the VM
+     * should be able to deal with gracefully.
+     *
+     * Note that this depends heavily on the Dalvik test harness.
+     */
+    static class BrokenDexLoader extends ClassLoader {
+
+        /** We return null when asked to load InaccessibleSuper. */
+        private static class InaccessibleSuper {}
+        private static class Inaccessible extends InaccessibleSuper {}
+
+        private static final String SUPERCLASS_NAME =
+                "Main$BrokenDexLoader$InaccessibleSuper";
+        private static final String CLASS_NAME =
+                "Main$BrokenDexLoader$Inaccessible";
+
+        private static final String DEX_FILE = "test.jar";
+
+        public BrokenDexLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        /**
+         * Finds the class with the specified binary name, from DEX_FILE.
+         *
+         * If we don't find a match, we throw an exception.
+         */
+        private Class<?> findDexClass(String name)
+                throws TestFailed, InvocationTargetException
+        {
+            Object dexFile = null;
+            Class dexClass = null;
+
+            try {
+                try {
+                    /*
+                     * Find the DexFile class, and construct a DexFile object
+                     * through reflection, then call loadClass on it.
+                     */
+                    dexClass = ClassLoader.getSystemClassLoader().
+                            loadClass("dalvik/system/DexFile");
+                    Constructor ctor = dexClass.
+                            getConstructor(new Class[] {String.class});
+                    dexFile = ctor.newInstance(DEX_FILE);
+                    Method meth = dexClass.getMethod("loadClass",
+                            new Class[] { String.class, ClassLoader.class });
+                    /*
+                     * Invoking loadClass on CLASS_NAME is expected to
+                     * throw an InvocationTargetException. Anything else
+                     * is an error we can't recover from.
+                     */
+                    meth.invoke(dexFile, name, this);
+                } finally {
+                    if (dexFile != null) {
+                        /* close the DexFile to make CloseGuard happy */
+                        Method meth = dexClass.getMethod("close", (Class[]) null);
+                        meth.invoke(dexFile);
+                    }
+                }
+            } catch (NoSuchMethodException nsme) {
+                throw new TestFailed(nsme);
+            } catch (InstantiationException ie) {
+                throw new TestFailed(ie);
+            } catch (IllegalAccessException iae) {
+                throw new TestFailed(iae);
+            } catch (ClassNotFoundException cnfe) {
+                throw new TestFailed(cnfe);
+            }
+
+            return null;
+        }
+
+        /**
+         * Load a class.
+         *
+         * Return null if the class's name is SUPERCLASS_NAME;
+         * otherwise invoke the super's loadClass method.
+         */
+        public Class<?> loadClass(String name, boolean resolve)
+                throws ClassNotFoundException
+        {
+            if (SUPERCLASS_NAME.equals(name)) {
+                return null;
+            }
+
+            return super.loadClass(name, resolve);
+        }
+
+        /**
+         * Attempt to find the class with the superclass we refuse to
+         * load.  This is expected to throw an
+         * InvocationTargetException, with a NullPointerException as
+         * its cause.
+         */
+        public void findBrokenClass()
+                throws TestFailed, InvocationTargetException
+        {
+            findDexClass(CLASS_NAME);
+        }
+    }
+
+    /**
+     * Main entry point.
+     */
+    public static void main(String[] args)
+            throws TestFailed, ClassNotFoundException {
+        /*
+         * Run test.
+         */
+        testFailLoadAndGc();
+    }
+
+    /**
+     * See if we can GC after a failed load.
+     */
+    static void testFailLoadAndGc() throws TestFailed {
+        try {
+            BrokenDexLoader loader;
+
+            loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
+            loader.findBrokenClass();
+            System.err.println("ERROR: Inaccessible was accessible");
+        } catch (InvocationTargetException ite) {
+            Throwable cause = ite.getCause();
+            if (cause instanceof NullPointerException) {
+                System.err.println("Got expected ITE/NPE");
+            } else {
+                System.err.println("Got unexpected ITE");
+                ite.printStackTrace();
+            }
+        }
+        System.gc();
+        System.out.println("GC complete.");
+    }
+}
diff --git a/tests/088-monitor-verification/expected.txt b/tests/088-monitor-verification/expected.txt
new file mode 100644
index 0000000..07f5b0b
--- /dev/null
+++ b/tests/088-monitor-verification/expected.txt
@@ -0,0 +1,7 @@
+recursiveSync ok
+nestedMayThrow ok
+constantLock ok
+excessiveNesting ok
+notNested ok
+twoPath ok
+triplet ok
diff --git a/tests/088-monitor-verification/info.txt b/tests/088-monitor-verification/info.txt
new file mode 100644
index 0000000..c00cb1c
--- /dev/null
+++ b/tests/088-monitor-verification/info.txt
@@ -0,0 +1,2 @@
+Try different arrangements of "synchronized" to exercise the structured
+lock checks in the bytecode verifier.
diff --git a/tests/088-monitor-verification/src/Main.java b/tests/088-monitor-verification/src/Main.java
new file mode 100644
index 0000000..aa90b92
--- /dev/null
+++ b/tests/088-monitor-verification/src/Main.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * Entry point and tests that are expected to succeed.
+ */
+public class Main {
+    /**
+     * Drives tests.
+     */
+    public static void main(String[] args) {
+        Main m = new Main();
+
+        m.recursiveSync(0);
+
+        m.nestedMayThrow(false);
+        try {
+            m.nestedMayThrow(true);
+            System.err.println("nestedThrow(true) did not throw");
+        } catch (MyException me) {}
+        System.out.println("nestedMayThrow ok");
+
+        m.constantLock();
+        System.out.println("constantLock ok");
+
+        m.notExcessiveNesting();
+        if (false) {    // TODO: remove when verification is turned on
+        try {
+            TooDeep.excessiveNesting();
+            System.err.println("excessiveNesting did not throw");
+        } catch (VerifyError ve) {}
+        }
+        System.out.println("excessiveNesting ok");
+
+        m.notNested();
+        System.out.println("notNested ok");
+
+        Object obj1 = new Object();
+        Object obj2 = new Object();
+
+        m.twoPath(obj1, obj2, 0);
+        System.out.println("twoPath ok");
+
+        m.triplet(obj1, obj2, 0);
+        System.out.println("triplet ok");
+    }
+
+    /**
+     * Recursive synchronized method.
+     */
+    synchronized void recursiveSync(int iter) {
+        if (iter < 40) {
+            recursiveSync(iter+1);
+        } else {
+            System.out.println("recursiveSync ok");
+        }
+    }
+
+    /**
+     * Tests simple nesting, with and without a throw.
+     */
+    void nestedMayThrow(boolean doThrow) {
+        synchronized (this) {
+            synchronized (Main.class) {
+                synchronized (new Object()) {
+                    synchronized(Class.class) {
+                        if (doThrow) {
+                            throw new MyException();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Exercises bug 3215458.
+     */
+    void constantLock() {
+        Class thing = Thread.class;
+        synchronized (Thread.class) {}
+    }
+
+    /**
+     * Confirms that we can have 32 nested monitors on one method.
+     */
+    void notExcessiveNesting() {
+        synchronized (this) {   // 1
+        synchronized (this) {   // 2
+        synchronized (this) {   // 3
+        synchronized (this) {   // 4
+        synchronized (this) {   // 5
+        synchronized (this) {   // 6
+        synchronized (this) {   // 7
+        synchronized (this) {   // 8
+        synchronized (this) {   // 9
+        synchronized (this) {   // 10
+        synchronized (this) {   // 11
+        synchronized (this) {   // 12
+        synchronized (this) {   // 13
+        synchronized (this) {   // 14
+        synchronized (this) {   // 15
+        synchronized (this) {   // 16
+        synchronized (this) {   // 17
+        synchronized (this) {   // 18
+        synchronized (this) {   // 19
+        synchronized (this) {   // 20
+        synchronized (this) {   // 21
+        synchronized (this) {   // 22
+        synchronized (this) {   // 23
+        synchronized (this) {   // 24
+        synchronized (this) {   // 25
+        synchronized (this) {   // 26
+        synchronized (this) {   // 27
+        synchronized (this) {   // 28
+        synchronized (this) {   // 29
+        synchronized (this) {   // 30
+        synchronized (this) {   // 31
+        synchronized (this) {   // 32
+        }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+    }
+
+    /**
+     * Confirms that we can have more than 32 non-nested monitors in one
+     * method.
+     */
+    void notNested() {
+        synchronized (this) {}  // 1
+        synchronized (this) {}  // 2
+        synchronized (this) {}  // 3
+        synchronized (this) {}  // 4
+        synchronized (this) {}  // 5
+        synchronized (this) {}  // 6
+        synchronized (this) {}  // 7
+        synchronized (this) {}  // 8
+        synchronized (this) {}  // 9
+        synchronized (this) {}  // 10
+        synchronized (this) {}  // 11
+        synchronized (this) {}  // 12
+        synchronized (this) {}  // 13
+        synchronized (this) {}  // 14
+        synchronized (this) {}  // 15
+        synchronized (this) {}  // 16
+        synchronized (this) {}  // 17
+        synchronized (this) {}  // 18
+        synchronized (this) {}  // 19
+        synchronized (this) {}  // 20
+        synchronized (this) {}  // 21
+        synchronized (this) {}  // 22
+        synchronized (this) {}  // 23
+        synchronized (this) {}  // 24
+        synchronized (this) {}  // 25
+        synchronized (this) {}  // 26
+        synchronized (this) {}  // 27
+        synchronized (this) {}  // 28
+        synchronized (this) {}  // 29
+        synchronized (this) {}  // 30
+        synchronized (this) {}  // 31
+        synchronized (this) {}  // 32
+        synchronized (this) {}  // 33
+        synchronized (this) {}  // 34
+    }
+
+    /* does nothing but ensure that the compiler doesn't discard an object */
+    private void doNothing(Object obj) {}
+
+    /**
+     * Conditionally uses one of the synchronized objects.
+     */
+    public void twoPath(Object obj1, Object obj2, int x) {
+        Object localObj;
+
+        synchronized (obj1) {
+            synchronized(obj2) {
+                if (x == 0) {
+                    localObj = obj2;
+                } else {
+                    localObj = obj1;
+                }
+            }
+        }
+
+        doNothing(localObj);
+    }
+
+    /**
+     * Lock the monitor two or three times, and make use of the locked or
+     * unlocked object.
+     */
+    public void triplet(Object obj1, Object obj2, int x) {
+        Object localObj;
+
+        synchronized (obj1) {
+            synchronized(obj1) {
+                if (x == 0) {
+                    synchronized(obj1) {
+                        localObj = obj2;
+                    }
+                } else {
+                    localObj = obj1;
+                }
+            }
+        }
+
+        doNothing(localObj);
+    }
+}
diff --git a/tests/088-monitor-verification/src/MyException.java b/tests/088-monitor-verification/src/MyException.java
new file mode 100644
index 0000000..cf65d6d
--- /dev/null
+++ b/tests/088-monitor-verification/src/MyException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class MyException extends RuntimeException {
+    public MyException() {
+        super();
+    }
+    public MyException(String msg) {
+        super(msg);
+    }
+}
diff --git a/tests/088-monitor-verification/src/TooDeep.java b/tests/088-monitor-verification/src/TooDeep.java
new file mode 100644
index 0000000..76192e5
--- /dev/null
+++ b/tests/088-monitor-verification/src/TooDeep.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * The class has a method with too many levels of nested "synchronized"
+ * blocks.  The verifier will reject it.
+ *
+ * (It would be perfectly okay if the verifier *didn't* reject this.
+ * The goal here is just to exercise the failure path.  It also serves
+ * as a check to see if the monitor checks are enabled.)
+ */
+public class TooDeep {
+
+    public static void excessiveNesting() {
+        synchronized (TooDeep.class) {   // 1
+        synchronized (TooDeep.class) {   // 2
+        synchronized (TooDeep.class) {   // 3
+        synchronized (TooDeep.class) {   // 4
+        synchronized (TooDeep.class) {   // 5
+        synchronized (TooDeep.class) {   // 6
+        synchronized (TooDeep.class) {   // 7
+        synchronized (TooDeep.class) {   // 8
+        synchronized (TooDeep.class) {   // 9
+        synchronized (TooDeep.class) {   // 10
+        synchronized (TooDeep.class) {   // 11
+        synchronized (TooDeep.class) {   // 12
+        synchronized (TooDeep.class) {   // 13
+        synchronized (TooDeep.class) {   // 14
+        synchronized (TooDeep.class) {   // 15
+        synchronized (TooDeep.class) {   // 16
+        synchronized (TooDeep.class) {   // 17
+        synchronized (TooDeep.class) {   // 18
+        synchronized (TooDeep.class) {   // 19
+        synchronized (TooDeep.class) {   // 20
+        synchronized (TooDeep.class) {   // 21
+        synchronized (TooDeep.class) {   // 22
+        synchronized (TooDeep.class) {   // 23
+        synchronized (TooDeep.class) {   // 24
+        synchronized (TooDeep.class) {   // 25
+        synchronized (TooDeep.class) {   // 26
+        synchronized (TooDeep.class) {   // 27
+        synchronized (TooDeep.class) {   // 28
+        synchronized (TooDeep.class) {   // 29
+        synchronized (TooDeep.class) {   // 30
+        synchronized (TooDeep.class) {   // 31
+        synchronized (TooDeep.class) {   // 32
+        synchronized (TooDeep.class) {   // 33
+        }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+    }
+}
diff --git a/tests/089-jumbo-opcodes/build b/tests/089-jumbo-opcodes/build
new file mode 100644
index 0000000..dcbb559
--- /dev/null
+++ b/tests/089-jumbo-opcodes/build
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# 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.
+
+# Stop if something fails.
+set -e
+
+# Write out files with 65500 total static fields, instance fields, and methods,
+# so that references to the Jumbo fields in Main will be guaranteed to be jumbo
+# instructions.
+
+awk '
+BEGIN {
+    writeFileField("FillerStatic", "static public int staticInt");
+    writeFileField("FillerField", "public int fieldInt");
+    writeFileMethod("FillerMethod");
+}
+function writeFileField(name, type) {
+    fileName = "src/" name ".java";
+    printf("public class %s {\n", name) > fileName;
+    for (i = 1; i <= 65500; i++) {
+        printf("    %s%d;\n", type, i) > fileName;
+    }
+    printf("}\n") > fileName;
+}
+function writeFileMethod(name) {
+    fileName = "src/" name ".java";
+    printf("public class %s {\n", name) > fileName;
+    for (i = 1; i <= 65500; i++) {
+      printf("    public void meth%d() { }\n", i) > fileName;
+    }
+    printf("}\n") > fileName;
+}'
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${JAVAC} -d classes `find src2 -name '*.java'`
+
+dx -JXmx1024m --debug --dex --no-optimize \
+    --dump-to=classes.lst --output=classes.dex classes
+zip test.jar classes.dex
diff --git a/tests/089-jumbo-opcodes/expected.txt b/tests/089-jumbo-opcodes/expected.txt
new file mode 100644
index 0000000..253547c
--- /dev/null
+++ b/tests/089-jumbo-opcodes/expected.txt
@@ -0,0 +1,10 @@
+Invoked virtual
+Invoked super
+Invoked direct
+Invoked static
+Invoked interface
+Got expected InstantationError
+Got expected NoSuchFieldError
+Got expected NoSuchFieldError
+Got expected NoSuchMethodError
+Got expected NoSuchMethodError
diff --git a/tests/089-jumbo-opcodes/info.txt b/tests/089-jumbo-opcodes/info.txt
new file mode 100644
index 0000000..56f9624
--- /dev/null
+++ b/tests/089-jumbo-opcodes/info.txt
@@ -0,0 +1,4 @@
+Test basic functionality of jumbo opcodes. Note that check-cast/jumbo and
+filled-new-array/jumbo can't be generated by dx currently (because dx can't
+support more than 65536 classes yet, and it always uses low registers for the
+result of these instructions).
diff --git a/tests/089-jumbo-opcodes/src/Main.java b/tests/089-jumbo-opcodes/src/Main.java
new file mode 100644
index 0000000..95f5a16
--- /dev/null
+++ b/tests/089-jumbo-opcodes/src/Main.java
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import other.Mutant;
+
+/*
+ * Entry point and tests that are expected to succeed.
+ */
+public class Main {
+
+    /**
+     * Drives tests.
+     */
+    public static void main(String[] args) {
+
+        // Test static put/get
+        testStaticInt();
+        testStaticVolatileInt();
+        testStaticWide();
+        testStaticVolatileWide();
+        testStaticObject();
+        testStaticVolatileObject();
+        testStaticBoolean();
+        testStaticByte();
+        testStaticChar();
+        testStaticShort();
+
+        // Test field put/get
+        JumboField fieldTest = new JumboField();
+        testFieldInt(fieldTest);
+        testFieldVolatileInt(fieldTest);
+        testFieldWide(fieldTest);
+        testFieldVolatileWide(fieldTest);
+        testFieldObject(fieldTest);
+        testFieldVolatileObject(fieldTest);
+        testFieldBoolean(fieldTest);
+        testFieldByte(fieldTest);
+        testFieldChar(fieldTest);
+        testFieldShort(fieldTest);
+
+        // Test method invokes
+        JumboMethod methodTest = new JumboMethod();
+        methodTest.testMethods();
+
+        // Test remaining jumbo instructions
+        // const-class/jumbo, check-cast/jumbo, instance-of/jumbo,
+        // new-instance/jumbo, new-array/jumbo, filled-new-array/jumbo
+        // throw-verification-error/jumbo
+        JumboRegister registerTest = new JumboRegister();
+        registerTest.testRegisters();
+    }
+
+    // Test sput/jumbo & sget/jumbo
+    public static void testStaticInt() {
+        int putInt = 0x12345678;
+        JumboStatic.testInt = putInt;
+        int getInt = JumboStatic.testInt;
+        if (putInt != getInt) {
+            System.out.println("Static put int: " + putInt +
+                " does not match static get int: " + getInt);
+        }
+    }
+
+    // Test sput-wide/jumbo & sget-wide/jumbo
+    public static void testStaticWide() {
+        long putWide = 0xfedcba9876543210l;
+        JumboStatic.testWide = putWide;
+        long getWide = JumboStatic.testWide;
+        if (putWide != getWide) {
+            System.out.println("Static put wide: " + putWide +
+                " does not match static get wide: " + getWide);
+        }
+    }
+
+    // Test sput-object/jumbo & sget-object/jumbo
+    public static void testStaticObject() {
+        Object putObject = new Object();
+        JumboStatic.testObject = putObject;
+        Object getObject = JumboStatic.testObject;
+        if (putObject != getObject) {
+            System.out.println("Static put object: " + putObject +
+                " does not match static get object: " + getObject);
+        }
+    }
+
+    // Test sput-volatile/jumbo & sget-volatile/jumbo
+    public static void testStaticVolatileInt() {
+        int putInt = 0x12345678;
+        JumboStatic.testVolatileInt = putInt;
+        int getInt = JumboStatic.testVolatileInt;
+        if (putInt != getInt) {
+            System.out.println("Static put int: " + putInt +
+                " does not match static get int: " + getInt);
+        }
+    }
+
+    // Test sput-wide-volatile/jumbo & sget-wide-volatile/jumbo
+    public static void testStaticVolatileWide() {
+        long putWide = 0xfedcba9876543210l;
+        JumboStatic.testVolatileWide = putWide;
+        long getWide = JumboStatic.testVolatileWide;
+        if (putWide != getWide) {
+            System.out.println("Static put wide: " + putWide +
+                " does not match static get wide: " + getWide);
+        }
+    }
+
+    // Test sput-object-volatile/jumbo & sget-object-volatile/jumbo
+    public static void testStaticVolatileObject() {
+        Object putObject = new Object();
+        JumboStatic.testVolatileObject = putObject;
+        Object getObject = JumboStatic.testVolatileObject;
+        if (putObject != getObject) {
+            System.out.println("Static put object: " + putObject +
+                " does not match static get object: " + getObject);
+        }
+    }
+
+    // Test sput-boolean/jumbo & sget-boolean/jumbo
+    public static void testStaticBoolean() {
+        boolean putBoolean = true;
+        JumboStatic.testBoolean = putBoolean;
+        boolean getBoolean = JumboStatic.testBoolean;
+        if (putBoolean != getBoolean) {
+            System.out.println("Static put boolean: " + putBoolean +
+                " does not match static get boolean: " + getBoolean);
+        }
+    }
+
+    // Test sput-byte/jumbo & sget-byte/jumbo
+    public static void testStaticByte() {
+        byte putByte = 0x6D;
+        JumboStatic.testByte = putByte;
+        byte getByte = JumboStatic.testByte;
+        if (putByte != getByte) {
+            System.out.println("Static put byte: " + putByte +
+                " does not match static get byte: " + getByte);
+        }
+    }
+
+    // Test sput-char/jumbo & sget-char/jumbo
+    public static void testStaticChar() {
+        char putChar = 0xE5;
+        JumboStatic.testChar = putChar;
+        char getChar = JumboStatic.testChar;
+        if (putChar != getChar) {
+            System.out.println("Static put char: " + putChar +
+                " does not match static get char: " + getChar);
+        }
+    }
+
+    // Test sput-short/jumbo & sget-short/jumbo
+    public static void testStaticShort() {
+        short putShort = 0x7A3B;
+        JumboStatic.testShort = putShort;
+        short getShort = JumboStatic.testShort;
+        if (putShort != getShort) {
+            System.out.println("Static put short: " + putShort +
+                " does not match static get short: " + getShort);
+        }
+    }
+
+    // Test iput/jumbo & iget/jumbo
+    public static void testFieldInt(JumboField fieldTest) {
+        int putInt = 0x12345678;
+        fieldTest.testInt = putInt;
+        int getInt = fieldTest.testInt;
+        if (putInt != getInt) {
+            System.out.println("Field put int: " + putInt +
+                " does not match field get int: " + getInt);
+        }
+    }
+
+    // Test iput-wide/jumbo & iget-wide/jumbo
+    public static void testFieldWide(JumboField fieldTest) {
+        long putWide = 0xfedcba9876543210l;
+        fieldTest.testWide = putWide;
+        long getWide = fieldTest.testWide;
+        if (putWide != getWide) {
+            System.out.println("Field put wide: " + putWide +
+                " does not match field get wide: " + getWide);
+        }
+    }
+
+    // Test iput-object/jumbo & iget-object/jumbo
+    public static void testFieldObject(JumboField fieldTest) {
+        Object putObject = new Object();
+        fieldTest.testObject = putObject;
+        Object getObject = fieldTest.testObject;
+        if (putObject != getObject) {
+            System.out.println("Field put object: " + putObject +
+                " does not match field get object: " + getObject);
+        }
+    }
+
+    // Test iput-volatile/jumbo & iget-volatile/jumbo
+    public static void testFieldVolatileInt(JumboField fieldTest) {
+        int putInt = 0x12345678;
+        fieldTest.testVolatileInt = putInt;
+        int getInt = fieldTest.testVolatileInt;
+        if (putInt != getInt) {
+            System.out.println("Field put int: " + putInt +
+                " does not match field get int: " + getInt);
+        }
+    }
+
+    // Test iput-wide-volatile/jumbo & iget-wide-volatile/jumbo
+    public static void testFieldVolatileWide(JumboField fieldTest) {
+        long putWide = 0xfedcba9876543210l;
+        fieldTest.testVolatileWide = putWide;
+        long getWide = fieldTest.testVolatileWide;
+        if (putWide != getWide) {
+            System.out.println("Field put wide: " + putWide +
+                " does not match field get wide: " + getWide);
+        }
+    }
+
+    // Test iput-object-volatile/jumbo & iget-object-volatile/jumbo
+    public static void testFieldVolatileObject(JumboField fieldTest) {
+        Object putObject = new Object();
+        fieldTest.testVolatileObject = putObject;
+        Object getObject = fieldTest.testVolatileObject;
+        if (putObject != getObject) {
+            System.out.println("Field put object: " + putObject +
+                " does not match field get object: " + getObject);
+        }
+    }
+
+    // Test iput-boolean/jumbo & iget-boolean/jumbo
+    public static void testFieldBoolean(JumboField fieldTest) {
+        boolean putBoolean = true;
+        fieldTest.testBoolean = putBoolean;
+        boolean getBoolean = fieldTest.testBoolean;
+        if (putBoolean != getBoolean) {
+            System.out.println("Field put boolean: " + putBoolean +
+                " does not match field get boolean: " + getBoolean);
+        }
+    }
+
+    // Test iput-byte/jumbo & iget-byte/jumbo
+    public static void testFieldByte(JumboField fieldTest) {
+        byte putByte = 0x6D;
+        fieldTest.testByte = putByte;
+        byte getByte = fieldTest.testByte;
+        if (putByte != getByte) {
+            System.out.println("Field put byte: " + putByte +
+                " does not match field get byte: " + getByte);
+        }
+    }
+
+    // Test iput-char/jumbo & iget-char/jumbo
+    public static void testFieldChar(JumboField fieldTest) {
+        char putChar = 0xE5;
+        fieldTest.testChar = putChar;
+        char getChar = fieldTest.testChar;
+        if (putChar != getChar) {
+            System.out.println("Field put char: " + putChar +
+                " does not match field get char: " + getChar);
+        }
+    }
+
+    // Test iput-short/jumbo & iget-short/jumbo
+    public static void testFieldShort(JumboField fieldTest) {
+        short putShort = 0x7A3B;
+        fieldTest.testShort = putShort;
+        short getShort = fieldTest.testShort;
+        if (putShort != getShort) {
+            System.out.println("Field put short: " + putShort +
+                " does not match field get short: " + getShort);
+        }
+    }
+}
+
+class JumboStatic {
+    static int staticInt1;
+    static int staticInt2;
+    static int staticInt3;
+    static int staticInt4;
+    static int staticInt5;
+    static int staticInt6;
+    static int staticInt7;
+    static int staticInt8;
+    static int staticInt9;
+    static int staticInt10;
+    static int staticInt11;
+    static int staticInt12;
+    static int staticInt13;
+    static int staticInt14;
+    static int staticInt15;
+    static int staticInt16;
+    static int staticInt17;
+    static int staticInt18;
+    static int staticInt19;
+    static int staticInt20;
+    static int staticInt21;
+    static int staticInt22;
+    static int staticInt23;
+    static int staticInt24;
+    static int staticInt25;
+    static int staticInt26;
+    static int staticInt27;
+    static int staticInt28;
+    static int staticInt29;
+    static int staticInt30;
+    static int staticInt31;
+    static int staticInt32;
+    static int staticInt33;
+    static int staticInt34;
+    static int staticInt35;
+    static int staticInt36;
+    static int staticInt37;
+    static int staticInt38;
+    static int staticInt39;
+    static int staticInt40;
+    static int staticInt41;
+    static int staticInt42;
+    static int staticInt43;
+    static int staticInt44;
+    static int staticInt45;
+    static int staticInt46;
+    static int staticInt47;
+    static int staticInt48;
+    static int staticInt49;
+    static int staticInt50;
+
+    static int     testInt;
+    static long    testWide;
+    static Object  testObject;
+    static boolean testBoolean;
+    static byte    testByte;
+    static char    testChar;
+    static short   testShort;
+    static volatile int     testVolatileInt;
+    static volatile long    testVolatileWide;
+    static volatile Object  testVolatileObject;
+}
+
+class JumboField {
+    int fieldInt1;
+    int fieldInt2;
+    int fieldInt3;
+    int fieldInt4;
+    int fieldInt5;
+    int fieldInt6;
+    int fieldInt7;
+    int fieldInt8;
+    int fieldInt9;
+    int fieldInt10;
+    int fieldInt11;
+    int fieldInt12;
+    int fieldInt13;
+    int fieldInt14;
+    int fieldInt15;
+    int fieldInt16;
+    int fieldInt17;
+    int fieldInt18;
+    int fieldInt19;
+    int fieldInt20;
+    int fieldInt21;
+    int fieldInt22;
+    int fieldInt23;
+    int fieldInt24;
+    int fieldInt25;
+    int fieldInt26;
+    int fieldInt27;
+    int fieldInt28;
+    int fieldInt29;
+    int fieldInt30;
+    int fieldInt31;
+    int fieldInt32;
+    int fieldInt33;
+    int fieldInt34;
+    int fieldInt35;
+    int fieldInt36;
+    int fieldInt37;
+    int fieldInt38;
+    int fieldInt39;
+    int fieldInt40;
+    int fieldInt41;
+    int fieldInt42;
+    int fieldInt43;
+    int fieldInt44;
+    int fieldInt45;
+    int fieldInt46;
+    int fieldInt47;
+    int fieldInt48;
+    int fieldInt49;
+    int fieldInt50;
+
+    int     testInt;
+    long    testWide;
+    Object  testObject;
+    boolean testBoolean;
+    byte    testByte;
+    char    testChar;
+    short   testShort;
+    volatile int     testVolatileInt;
+    volatile long    testVolatileWide;
+    volatile Object  testVolatileObject;
+}
+
+class JumboMethodSuper {
+    void testSuper() {
+        System.out.println("Invoked super");
+    }
+}
+
+interface JumboMethodInterface {
+    void testInterface();
+}
+
+class JumboMethod extends JumboMethodSuper implements JumboMethodInterface {
+    void meth1() { }
+    void meth2() { }
+    void meth3() { }
+    void meth4() { }
+    void meth5() { }
+    void meth6() { }
+    void meth7() { }
+    void meth8() { }
+    void meth9() { }
+    void meth10() { }
+    void meth11() { }
+    void meth12() { }
+    void meth13() { }
+    void meth14() { }
+    void meth15() { }
+    void meth16() { }
+    void meth17() { }
+    void meth18() { }
+    void meth19() { }
+    void meth20() { }
+    void meth21() { }
+    void meth22() { }
+    void meth23() { }
+    void meth24() { }
+    void meth25() { }
+    void meth26() { }
+    void meth27() { }
+    void meth28() { }
+    void meth29() { }
+    void meth30() { }
+    void meth31() { }
+    void meth32() { }
+    void meth33() { }
+    void meth34() { }
+    void meth35() { }
+    void meth36() { }
+    void meth37() { }
+    void meth38() { }
+    void meth39() { }
+    void meth40() { }
+    void meth41() { }
+    void meth42() { }
+    void meth43() { }
+    void meth44() { }
+    void meth45() { }
+    void meth46() { }
+    void meth47() { }
+    void meth48() { }
+    void meth49() { }
+    void meth50() { }
+
+    void testMethods() {
+        testVirtual();
+        super.testSuper();
+        testDirect();
+        testStatic();
+        ((JumboMethodInterface) this).testInterface();
+    }
+
+    void testVirtual() {
+        System.out.println("Invoked virtual");
+    }
+
+    void testSuper() {
+        System.out.println("Invoked base");
+    }
+
+    private void testDirect() {
+        System.out.println("Invoked direct");
+    }
+
+    static void testStatic() {
+        System.out.println("Invoked static");
+    }
+
+    public void testInterface() {
+        System.out.println("Invoked interface");
+    }
+}
+
+class JumboRegister {
+    void testRegisters() {
+        // Create a bunch of registers
+        Class c1 = Thread.class;
+        Class c2 = Thread.class;
+        Class c3 = Thread.class;
+        Class c4 = Thread.class;
+        Class c5 = Thread.class;
+        Class c6 = Thread.class;
+        Class c7 = Thread.class;
+        Class c8 = Thread.class;
+        Class c9 = Thread.class;
+        Class c10 = Thread.class;
+        Class c11 = Thread.class;
+        Class c12 = Thread.class;
+        Class c13 = Thread.class;
+        Class c14 = Thread.class;
+        Class c15 = Thread.class;
+        Class c16 = Thread.class;
+        Class c17 = Thread.class;
+        Class c18 = Thread.class;
+        Class c19 = Thread.class;
+        Class c20 = Thread.class;
+        Class c21 = Thread.class;
+        Class c22 = Thread.class;
+        Class c23 = Thread.class;
+        Class c24 = Thread.class;
+        Class c25 = Thread.class;
+        Class c26 = Thread.class;
+        Class c27 = Thread.class;
+        Class c28 = Thread.class;
+        Class c29 = Thread.class;
+        Class c30 = Thread.class;
+        Class c31 = Thread.class;
+        Class c32 = Thread.class;
+        Class c33 = Thread.class;
+        Class c34 = Thread.class;
+        Class c35 = Thread.class;
+        Class c36 = Thread.class;
+        Class c37 = Thread.class;
+        Class c38 = Thread.class;
+        Class c39 = Thread.class;
+        Class c40 = Thread.class;
+        Class c41 = Thread.class;
+        Class c42 = Thread.class;
+        Class c43 = Thread.class;
+        Class c44 = Thread.class;
+        Class c45 = Thread.class;
+        Class c46 = Thread.class;
+        Class c47 = Thread.class;
+        Class c48 = Thread.class;
+        Class c49 = Thread.class;
+        Class c50 = Thread.class;
+        Class c51 = Thread.class;
+        Class c52 = Thread.class;
+        Class c53 = Thread.class;
+        Class c54 = Thread.class;
+        Class c55 = Thread.class;
+        Class c56 = Thread.class;
+        Class c57 = Thread.class;
+        Class c58 = Thread.class;
+        Class c59 = Thread.class;
+        Class c60 = Thread.class;
+        Class c61 = Thread.class;
+        Class c62 = Thread.class;
+        Class c63 = Thread.class;
+        Class c64 = Thread.class;
+        Class c65 = Thread.class;
+        Class c66 = Thread.class;
+        Class c67 = Thread.class;
+        Class c68 = Thread.class;
+        Class c69 = Thread.class;
+        Class c70 = Thread.class;
+        Class c71 = Thread.class;
+        Class c72 = Thread.class;
+        Class c73 = Thread.class;
+        Class c74 = Thread.class;
+        Class c75 = Thread.class;
+        Class c76 = Thread.class;
+        Class c77 = Thread.class;
+        Class c78 = Thread.class;
+        Class c79 = Thread.class;
+        Class c80 = Thread.class;
+        Class c81 = Thread.class;
+        Class c82 = Thread.class;
+        Class c83 = Thread.class;
+        Class c84 = Thread.class;
+        Class c85 = Thread.class;
+        Class c86 = Thread.class;
+        Class c87 = Thread.class;
+        Class c88 = Thread.class;
+        Class c89 = Thread.class;
+        Class c90 = Thread.class;
+        Class c91 = Thread.class;
+        Class c92 = Thread.class;
+        Class c93 = Thread.class;
+        Class c94 = Thread.class;
+        Class c95 = Thread.class;
+        Class c96 = Thread.class;
+        Class c97 = Thread.class;
+        Class c98 = Thread.class;
+        Class c99 = Thread.class;
+        Class c100 = Thread.class;
+        Class c101 = Thread.class;
+        Class c102 = Thread.class;
+        Class c103 = Thread.class;
+        Class c104 = Thread.class;
+        Class c105 = Thread.class;
+        Class c106 = Thread.class;
+        Class c107 = Thread.class;
+        Class c108 = Thread.class;
+        Class c109 = Thread.class;
+        Class c110 = Thread.class;
+        Class c111 = Thread.class;
+        Class c112 = Thread.class;
+        Class c113 = Thread.class;
+        Class c114 = Thread.class;
+        Class c115 = Thread.class;
+        Class c116 = Thread.class;
+        Class c117 = Thread.class;
+        Class c118 = Thread.class;
+        Class c119 = Thread.class;
+        Class c120 = Thread.class;
+        Class c121 = Thread.class;
+        Class c122 = Thread.class;
+        Class c123 = Thread.class;
+        Class c124 = Thread.class;
+        Class c125 = Thread.class;
+        Class c126 = Thread.class;
+        Class c127 = Thread.class;
+        Class c128 = Thread.class;
+        Class c129 = Thread.class;
+        Class c130 = Thread.class;
+        Class c131 = Thread.class;
+        Class c132 = Thread.class;
+        Class c133 = Thread.class;
+        Class c134 = Thread.class;
+        Class c135 = Thread.class;
+        Class c136 = Thread.class;
+        Class c137 = Thread.class;
+        Class c138 = Thread.class;
+        Class c139 = Thread.class;
+        Class c140 = Thread.class;
+        Class c141 = Thread.class;
+        Class c142 = Thread.class;
+        Class c143 = Thread.class;
+        Class c144 = Thread.class;
+        Class c145 = Thread.class;
+        Class c146 = Thread.class;
+        Class c147 = Thread.class;
+        Class c148 = Thread.class;
+        Class c149 = Thread.class;
+        Class c150 = Thread.class;
+        Class c151 = Thread.class;
+        Class c152 = Thread.class;
+        Class c153 = Thread.class;
+        Class c154 = Thread.class;
+        Class c155 = Thread.class;
+        Class c156 = Thread.class;
+        Class c157 = Thread.class;
+        Class c158 = Thread.class;
+        Class c159 = Thread.class;
+        Class c160 = Thread.class;
+        Class c161 = Thread.class;
+        Class c162 = Thread.class;
+        Class c163 = Thread.class;
+        Class c164 = Thread.class;
+        Class c165 = Thread.class;
+        Class c166 = Thread.class;
+        Class c167 = Thread.class;
+        Class c168 = Thread.class;
+        Class c169 = Thread.class;
+        Class c170 = Thread.class;
+        Class c171 = Thread.class;
+        Class c172 = Thread.class;
+        Class c173 = Thread.class;
+        Class c174 = Thread.class;
+        Class c175 = Thread.class;
+        Class c176 = Thread.class;
+        Class c177 = Thread.class;
+        Class c178 = Thread.class;
+        Class c179 = Thread.class;
+        Class c180 = Thread.class;
+        Class c181 = Thread.class;
+        Class c182 = Thread.class;
+        Class c183 = Thread.class;
+        Class c184 = Thread.class;
+        Class c185 = Thread.class;
+        Class c186 = Thread.class;
+        Class c187 = Thread.class;
+        Class c188 = Thread.class;
+        Class c189 = Thread.class;
+        Class c190 = Thread.class;
+        Class c191 = Thread.class;
+        Class c192 = Thread.class;
+        Class c193 = Thread.class;
+        Class c194 = Thread.class;
+        Class c195 = Thread.class;
+        Class c196 = Thread.class;
+        Class c197 = Thread.class;
+        Class c198 = Thread.class;
+        Class c199 = Thread.class;
+        Class c200 = Thread.class;
+        Class c201 = Thread.class;
+        Class c202 = Thread.class;
+        Class c203 = Thread.class;
+        Class c204 = Thread.class;
+        Class c205 = Thread.class;
+        Class c206 = Thread.class;
+        Class c207 = Thread.class;
+        Class c208 = Thread.class;
+        Class c209 = Thread.class;
+        Class c210 = Thread.class;
+        Class c211 = Thread.class;
+        Class c212 = Thread.class;
+        Class c213 = Thread.class;
+        Class c214 = Thread.class;
+        Class c215 = Thread.class;
+        Class c216 = Thread.class;
+        Class c217 = Thread.class;
+        Class c218 = Thread.class;
+        Class c219 = Thread.class;
+        Class c220 = Thread.class;
+        Class c221 = Thread.class;
+        Class c222 = Thread.class;
+        Class c223 = Thread.class;
+        Class c224 = Thread.class;
+        Class c225 = Thread.class;
+        Class c226 = Thread.class;
+        Class c227 = Thread.class;
+        Class c228 = Thread.class;
+        Class c229 = Thread.class;
+        Class c230 = Thread.class;
+        Class c231 = Thread.class;
+        Class c232 = Thread.class;
+        Class c233 = Thread.class;
+        Class c234 = Thread.class;
+        Class c235 = Thread.class;
+        Class c236 = Thread.class;
+        Class c237 = Thread.class;
+        Class c238 = Thread.class;
+        Class c239 = Thread.class;
+        Class c240 = Thread.class;
+        Class c241 = Thread.class;
+        Class c242 = Thread.class;
+        Class c243 = Thread.class;
+        Class c244 = Thread.class;
+        Class c245 = Thread.class;
+        Class c246 = Thread.class;
+        Class c247 = Thread.class;
+        Class c248 = Thread.class;
+        Class c249 = Thread.class;
+        Class c250 = Thread.class;
+        Class c251 = Thread.class;
+        Class c252 = Thread.class;
+        Class c253 = Thread.class;
+        Class c254 = Thread.class;
+        Class c255 = Thread.class;
+
+        // Test const-class/jumbo
+        Class c256 = Thread.class;
+
+        // Test check-cast/jumbo
+
+        // Test instance-of/jumbo
+        boolean b1 = c1 instanceof Object;
+        if (!b1) System.out.println("instance-of/jumbo returned wrong result");
+
+        // Test new-instance/jumbo
+        Object o1 = new Object();
+
+        // Test new-array/jumbo
+        int[] a1 = new int[10];
+        a1[0] = 1;
+        a1[1] = 2;
+        a1[2] = 3;
+        a1[3] = 4;
+        a1[4] = 5;
+        a1[5] = 6;
+        a1[6] = 7;
+        a1[7] = 8;
+        a1[8] = 9;
+        a1[9] = 10;
+
+        // Test filled-new-array/jumbo
+
+        // Test throw-verification-error/jumbo
+        try {
+            MaybeAbstract ma = new MaybeAbstract();
+            System.err.println("ERROR: MaybeAbstract succeeded unexpectedly");
+        } catch (InstantiationError ie) {
+            System.out.println("Got expected InstantationError");
+        } catch (Exception ex) {
+            System.err.println("Got unexpected MaybeAbstract failure");
+        }
+        testMissingStuff();
+
+        // Do something with those registers to force other ops to be jumbo
+        useRegs(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10);
+        useRegs(c11, c12, c13, c14, c15, c16, c17, c18, c19, c20);
+        useRegs(c21, c22, c23, c24, c25, c26, c27, c28, c29, c30);
+        useRegs(c31, c32, c33, c34, c35, c36, c37, c38, c39, c40);
+        useRegs(c41, c42, c43, c44, c45, c46, c47, c48, c49, c50);
+        useRegs(c51, c52, c53, c54, c55, c56, c57, c58, c59, c60);
+        useRegs(c61, c62, c63, c64, c65, c66, c67, c68, c69, c70);
+        useRegs(c71, c72, c73, c74, c75, c76, c77, c78, c79, c80);
+        useRegs(c81, c82, c83, c84, c85, c86, c87, c88, c89, c90);
+        useRegs(c91, c92, c93, c94, c95, c96, c97, c98, c99, c100);
+        useRegs(c101, c102, c103, c104, c105, c106, c107, c108, c109, c110);
+        useRegs(c111, c112, c113, c114, c115, c116, c117, c118, c119, c120);
+        useRegs(c121, c122, c123, c124, c125, c126, c127, c128, c129, c130);
+        useRegs(c131, c132, c133, c134, c135, c136, c137, c138, c139, c140);
+        useRegs(c141, c142, c143, c144, c145, c146, c147, c148, c149, c150);
+        useRegs(c151, c152, c153, c154, c155, c156, c157, c158, c159, c160);
+        useRegs(c161, c162, c163, c164, c165, c166, c167, c168, c169, c170);
+        useRegs(c171, c172, c173, c174, c175, c176, c177, c178, c179, c180);
+        useRegs(c181, c182, c183, c184, c185, c186, c187, c188, c189, c190);
+        useRegs(c191, c192, c193, c194, c195, c196, c197, c198, c199, c200);
+        useRegs(c201, c202, c203, c204, c205, c206, c207, c208, c209, c210);
+        useRegs(c211, c212, c213, c214, c215, c216, c217, c218, c219, c220);
+        useRegs(c221, c222, c223, c224, c225, c226, c227, c228, c229, c230);
+        useRegs(c231, c232, c233, c234, c235, c236, c237, c238, c239, c240);
+        useRegs(c241, c242, c243, c244, c245, c246, c247, c248, c249, c250);
+        useRegs(c251, c252, c253, c254, c255, c256, c256, c256, c256, c256);
+
+        useRegs(b1);
+        useRegs(o1);
+        useRegs(a1);
+    }
+
+    // Trigger more jumbo verification errors
+    static void testMissingStuff() {
+        Mutant mutant = new Mutant();
+
+        try {
+            int x = mutant.disappearingField;
+        } catch (NoSuchFieldError nsfe) {
+            System.out.println("Got expected NoSuchFieldError");
+        }
+
+        try {
+            int y = Mutant.disappearingStaticField;
+        } catch (NoSuchFieldError nsfe) {
+            System.out.println("Got expected NoSuchFieldError");
+        }
+
+        try {
+            mutant.disappearingMethod();
+        } catch (NoSuchMethodError nsme) {
+            System.out.println("Got expected NoSuchMethodError");
+        }
+
+        try {
+            Mutant.disappearingStaticMethod();
+        } catch (NoSuchMethodError nsme) {
+            System.out.println("Got expected NoSuchMethodError");
+        }
+    }
+
+    void useRegs(Object o1, Object o2, Object o3, Object o4, Object o5,
+        Object o6, Object o7, Object o8, Object o9, Object o10) {
+    }
+
+    void useRegs(Object o1) { }
+    void useRegs(boolean b1) { }
+}
diff --git a/tests/089-jumbo-opcodes/src/MaybeAbstract.java b/tests/089-jumbo-opcodes/src/MaybeAbstract.java
new file mode 100644
index 0000000..6d3b05b
--- /dev/null
+++ b/tests/089-jumbo-opcodes/src/MaybeAbstract.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 /*abstract*/ class MaybeAbstract {
+    public MaybeAbstract() {}
+    int foo() { return 0; }
+}
diff --git a/tests/089-jumbo-opcodes/src/other/Mutant.java b/tests/089-jumbo-opcodes/src/other/Mutant.java
new file mode 100644
index 0000000..ec4754b
--- /dev/null
+++ b/tests/089-jumbo-opcodes/src/other/Mutant.java
@@ -0,0 +1,43 @@
+/*
+ * 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/089-jumbo-opcodes/src2/MaybeAbstract.java b/tests/089-jumbo-opcodes/src2/MaybeAbstract.java
new file mode 100644
index 0000000..8b70a07
--- /dev/null
+++ b/tests/089-jumbo-opcodes/src2/MaybeAbstract.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 abstract class MaybeAbstract {
+    public MaybeAbstract() {}
+    int foo() { return 0; }
+}
diff --git a/tests/089-jumbo-opcodes/src2/other/Mutant.java b/tests/089-jumbo-opcodes/src2/other/Mutant.java
new file mode 100644
index 0000000..67cd36d
--- /dev/null
+++ b/tests/089-jumbo-opcodes/src2/other/Mutant.java
@@ -0,0 +1,43 @@
+/*
+ * 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/090-loop-formation/expected.txt b/tests/090-loop-formation/expected.txt
new file mode 100644
index 0000000..b7e0bb3
--- /dev/null
+++ b/tests/090-loop-formation/expected.txt
@@ -0,0 +1,5 @@
+counter1 is 0
+counter2 is 32767
+counter3 is 32767
+counter4 is 0
+counter5 is 65534
diff --git a/tests/090-loop-formation/info.txt b/tests/090-loop-formation/info.txt
new file mode 100644
index 0000000..98d1d4b
--- /dev/null
+++ b/tests/090-loop-formation/info.txt
@@ -0,0 +1,3 @@
+Test loop formation heuristics and code generation. Basically the problem to
+catch here is to make sure that some never-exercised code blocks are included
+in the loop region, and the JIT compiler won't choke on unresolved fields.
diff --git a/tests/090-loop-formation/src/Main.java b/tests/090-loop-formation/src/Main.java
new file mode 100644
index 0000000..7c16667
--- /dev/null
+++ b/tests/090-loop-formation/src/Main.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Create two versions of loops where the unresolved field is on either the
+ * taken or the non-taken path to make sure that the loop detection code bails
+ * on unresolved fields.
+ */
+public class Main {
+    static int counter1;
+    static int counter2;
+    static int counter3;
+    static int counter4;
+    static int counter5;
+
+    public static void main(String[] args) {
+        /* counter1 is not resolved */
+        for (int i = 0; i < 32767; i++) {
+            if (i < 0) {
+                counter1++;
+            } else {
+                counter2++;
+            }
+            counter5++;
+        }
+
+        /* counter4 is not resolved */
+        for (int i = 0; i < 32767; i++) {
+            if (i >= 0) {
+                counter3++;
+            } else {
+                counter4++;
+            }
+            counter5++;
+        }
+
+        System.out.println("counter1 is " + counter1);
+        System.out.println("counter2 is " + counter2);
+        System.out.println("counter3 is " + counter3);
+        System.out.println("counter4 is " + counter4);
+        System.out.println("counter5 is " + counter5);
+    }
+}
diff --git a/tests/README.txt b/tests/README.txt
new file mode 100644
index 0000000..eb1ce36
--- /dev/null
+++ b/tests/README.txt
@@ -0,0 +1,13 @@
+VM test harness.
+
+Use "./run-all-tests" to run all tests, or "./run-test <number>" to run a
+single test.  Run "./run-test" with no arguments to see command flags;
+in particular, the tests can be run on the desktop, on a USB-attached
+device, or using the desktop "reference implementation".
+
+
+For most tests, the sources are in the "src" subdirectory.  Sources found
+in the "src2" directory are compiled separately but to the same output
+directory; this can be used to exercise "API mismatch" situations by
+replacing class files created in the first pass.  The "src-ex" directory
+is built separately, and is intended for exercising class loaders.
diff --git a/tests/etc/default-build b/tests/etc/default-build
new file mode 100755
index 0000000..b8df442
--- /dev/null
+++ b/tests/etc/default-build
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# 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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+
+if [ -r src2 ]; then
+    ${JAVAC} -d classes `find src2 -name '*.java'`
+fi
+
+dx -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+    --dump-width=1000 classes
+zip test.jar classes.dex
+
+if [ -r src-ex ]; then
+    mkdir classes-ex
+    ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
+    dx -JXmx256m --debug --dex --dump-to=classes-ex.lst \
+        --output=classes-ex.dex --dump-width=1000 classes-ex
+
+    # quick shuffle so that the stored name is "classes.dex"
+    mv classes.dex classes-1.dex
+    mv classes-ex.dex classes.dex
+    zip test-ex.jar classes.dex
+    mv classes.dex classes-ex.dex
+    mv classes-1.dex classes.dex
+fi
diff --git a/tests/etc/default-run b/tests/etc/default-run
new file mode 100755
index 0000000..ecbbbc7
--- /dev/null
+++ b/tests/etc/default-run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+exec ${RUN} "$@"
diff --git a/tests/etc/host-run-test-jar b/tests/etc/host-run-test-jar
new file mode 100755
index 0000000..d3c0fd5
--- /dev/null
+++ b/tests/etc/host-run-test-jar
@@ -0,0 +1,159 @@
+#!/bin/sh
+#
+# Run the code in test.jar using the host-mode virtual machine. The jar should
+# contain a top-level class named Main to run.
+#
+# Options:
+#   --quiet       -- don't chatter
+#   --fast        -- use the fast interpreter (the default)
+#   --jit         -- use the jit
+#   --portable    -- use the portable interpreter
+#   --debug       -- wait for debugger to attach
+#   --valgrind    -- use valgrind
+#   --no-verify   -- turn off verification (on by default)
+#   --no-optimize -- turn off optimization (on by default)
+
+msg() {
+    if [ "$QUIET" = "n" ]; then
+        echo "$@"
+    fi
+}
+
+INTERP=""
+DEBUG="n"
+GDB="n"
+VERIFY="y"
+OPTIMIZE="y"
+VALGRIND="n"
+DEV_MODE="n"
+QUIET="n"
+PRECISE="y"
+
+while true; do
+    if [ "x$1" = "x--quiet" ]; then
+        QUIET="y"
+        shift
+    elif [ "x$1" = "x--jit" ]; then
+        INTERP="jit"
+        msg "Using jit"
+        shift
+    elif [ "x$1" = "x--fast" ]; then
+        INTERP="fast"
+        msg "Using fast interpreter"
+        shift
+    elif [ "x$1" = "x--portable" ]; then
+        INTERP="portable"
+        msg "Using portable interpreter"
+        shift
+    elif [ "x$1" = "x--debug" ]; then
+        DEBUG="y"
+        shift
+    elif [ "x$1" = "x--gdb" ]; then
+        GDB="y"
+        shift
+    elif [ "x$1" = "x--valgrind" ]; then
+        VALGRIND="y"
+        shift
+    elif [ "x$1" = "x--dev" ]; then
+        DEV_MODE="y"
+        shift
+    elif [ "x$1" = "x--no-verify" ]; then
+        VERIFY="n"
+        shift
+    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
+    elif expr "x$1" : "x--" >/dev/null 2>&1; then
+        echo "unknown option: $1" 1>&2
+        exit 1
+    else
+        break
+    fi
+done
+
+if [ "x$INTERP" = "x" ]; then
+    INTERP="fast"
+    msg "Using fast interpreter by default"
+fi
+
+if [ "$OPTIMIZE" = "y" ]; then
+    if [ "$VERIFY" = "y" ]; then
+        DEX_OPTIMIZE="-Xdexopt:verified"
+    else
+        DEX_OPTIMIZE="-Xdexopt:all"
+    fi
+    msg "Performing optimizations"
+else
+    DEX_OPTIMIZE="-Xdexopt:none"
+    msg "Skipping optimizations"
+fi
+
+if [ "$VERIFY" = "y" ]; then
+    DEX_VERIFY=""
+    msg "Performing verification"
+else
+    DEX_VERIFY="-Xverify:none"
+    msg "Skipping verification"
+fi
+
+if [ "$VALGRIND" = "y" ]; then
+    msg "Running with valgrind"
+    valgrind_cmd="valgrind"
+    #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 "------------------------------"
+
+HOSTBASE="${ANDROID_BUILD_TOP}/out/host"
+BASE="$OUT" # from build environment
+DATA_DIR=/tmp
+DEBUG_OPTS="-Xcheck:jni -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
+
+if [ ! -d $DATA_DIR/dalvik-cache ]; then
+    mkdir -p $DATA_DIR/dalvik-cache
+    [[ $? -ne 0 ]] && exit
+fi
+
+export ANDROID_PRINTF_LOG=brief
+if [ "$DEV_MODE" = "y" ]; then
+    export ANDROID_LOG_TAGS='*:d'
+else
+    export ANDROID_LOG_TAGS='*:s'
+fi
+export ANDROID_DATA="$DATA_DIR"
+export ANDROID_ROOT="${HOSTBASE}/linux-x86"
+export LD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
+export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
+
+exe="${ANDROID_ROOT}/bin/dalvikvm"
+framework="${BASE}/system/framework"
+bpath="${framework}/core.jar:${framework}/ext.jar:${framework}/framework.jar"
+
+if [ "$DEBUG" = "y" ]; then
+    PORT=8000
+    msg "Waiting for debugger to connect on localhost:$PORT"
+    DEX_DEBUG="-agentlib:jdwp=transport=dt_socket,addres=$PORT,server=y,suspend=y"
+fi
+
+if [ "$GDB" = "y" ]; then
+    gdb=gdb
+    gdbargs="--args $exe"
+fi
+
+$valgrind_cmd $gdb $exe $gdbargs "-Xbootclasspath:${bpath}" \
+    $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
new file mode 100755
index 0000000..e2fde42
--- /dev/null
+++ b/tests/etc/push-and-run-test-jar
@@ -0,0 +1,135 @@
+#!/bin/sh
+#
+# Run the code in test.jar on the device. The jar should contain a top-level
+# class named Main to run.
+#
+# Options:
+#   --quiet       -- don't chatter
+#   --fast        -- use the fast interpreter (the default)
+#   --jit         -- use the jit
+#   --portable    -- use the portable interpreter
+#   --debug       -- wait for debugger to attach
+#   --zygote      -- use the zygote (if so, all other options are ignored)
+#   --dev         -- development mode (print the vm invocation cmdline)
+#   --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
+        echo "$@"
+    fi
+}
+
+INTERP=""
+DEBUG="n"
+VERIFY="y"
+OPTIMIZE="y"
+ZYGOTE="n"
+QUIET="n"
+PRECISE="y"
+DEV_MODE="n"
+
+while true; do
+    if [ "x$1" = "x--quiet" ]; then
+        QUIET="y"
+        shift
+    elif [ "x$1" = "x--fast" ]; then
+        INTERP="fast"
+        msg "Using fast interpreter"
+        shift
+    elif [ "x$1" = "x--jit" ]; then
+        INTERP="jit"
+        msg "Using jit"
+        shift
+    elif [ "x$1" = "x--portable" ]; then
+        INTERP="portable"
+        msg "Using portable interpreter"
+        shift
+    elif [ "x$1" = "x--debug" ]; then
+        DEBUG="y"
+        shift
+    elif [ "x$1" = "x--zygote" ]; then
+        ZYGOTE="y"
+        msg "Spawning from zygote"
+        shift
+    elif [ "x$1" = "x--dev" ]; then
+        DEV_MODE="y"
+        shift
+    elif [ "x$1" = "x--no-verify" ]; then
+        VERIFY="n"
+        shift
+    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
+    elif expr "x$1" : "x--" >/dev/null 2>&1; then
+        echo "unknown option: $1" 1>&2
+        exit 1
+    else
+        break
+    fi
+done
+
+if [ "$ZYGOTE" = "n" ]; then
+    if [ "x$INTERP" = "x" ]; then
+        INTERP="fast"
+        msg "Using fast interpreter by default"
+    fi
+
+    if [ "$OPTIMIZE" = "y" ]; then
+        if [ "$VERIFY" = "y" ]; then
+            DEX_OPTIMIZE="-Xdexopt:verified"
+        else
+            DEX_OPTIMIZE="-Xdexopt:all"
+        fi
+        msg "Performing optimizations"
+    else
+        DEX_OPTIMIZE="-Xdexopt:none"
+        msg "Skipping optimizations"
+    fi
+
+    if [ "$VERIFY" = "y" ]; then
+        DEX_VERIFY=""
+        msg "Performing verification"
+    else
+        DEX_VERIFY="-Xverify:none"
+        msg "Skipping verification"
+    fi
+fi
+
+msg "------------------------------"
+
+if [ "$QUIET" = "n" ]; then
+    adb push test.jar /data
+    adb push test-ex.jar /data
+else
+    adb push test.jar /data >/dev/null 2>&1
+    adb push test-ex.jar /data >/dev/null 2>&1
+fi
+
+if [ "$DEBUG" = "y" ]; then
+    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
+    cmdline="cd /data; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
+        $GC_OPTS -cp test.jar -Xint:${INTERP} -ea Main"
+    if [ "$DEV_MODE" = "y" ]; then
+        echo $cmdline "$@"
+    fi
+    adb shell $cmdline "$@"
+fi
diff --git a/tests/etc/reference-run-test-classes b/tests/etc/reference-run-test-classes
new file mode 100755
index 0000000..94c8050
--- /dev/null
+++ b/tests/etc/reference-run-test-classes
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Run the code in a classes directory on a host-local reference virtual
+# machine. The jar should contain a top-level class named Main to run.
+#
+# Options:
+#   --quiet       -- don't chatter
+#   --debug       -- wait for debugger to attach
+#   --no-verify   -- turn off verification (on by default)
+#   --dev         -- development mode
+
+msg() {
+    if [ "$QUIET" = "n" ]; then
+        echo "$@"
+    fi
+}
+
+DEBUG="n"
+QUIET="n"
+VERIFY="y"
+
+while true; do
+    if [ "x$1" = "x--quiet" ]; then
+        QUIET="y"
+        shift
+    elif [ "x$1" = "x--debug" ]; then
+        DEBUG="y"
+        shift
+    elif [ "x$1" = "x--no-verify" ]; then
+        VERIFY="n"
+        shift
+    elif [ "x$1" = "x--dev" ]; then
+        # not used; ignore
+        shift
+    elif [ "x$1" = "x--" ]; then
+        shift
+        break
+    elif expr "x$1" : "x--" >/dev/null 2>&1; then
+        echo "unknown option: $1" 1>&2
+        exit 1
+    else
+        break
+    fi
+done
+
+if [ "$VERIFY" = "y" ]; then
+    VERIFY_ARG="-Xverify:all"
+    msg "Performing verification"
+else
+    VERIFY_ARG="-Xverify:none"
+    msg "Skipping verification"
+fi
+
+if [ "$DEBUG" = "y" ]; then
+    PORT=8000
+    msg "Waiting for debugger to connect on localhost:$PORT"
+    DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
+fi
+
+${JAVA} ${DEBUG_OPTS} -ea ${VERIFY_ARG} -classpath classes Main "$@"
diff --git a/tests/run-all-tests b/tests/run-all-tests
new file mode 100755
index 0000000..f66cd76
--- /dev/null
+++ b/tests/run-all-tests
@@ -0,0 +1,124 @@
+#!/bin/bash
+#
+# 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.
+
+# 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}"`
+
+run_args=""
+usage="no"
+
+while true; do
+    if [ "x$1" = "x--host" ]; then
+        run_args="${run_args} --host"
+        shift
+    elif [ "x$1" = "x--reference" ]; then
+        run_args="${run_args} --reference"
+        shift
+    elif [ "x$1" = "x--jit" ]; then
+        run_args="${run_args} --jit"
+        shift
+    elif [ "x$1" = "x--fast" ]; then
+        run_args="${run_args} --fast"
+        shift
+    elif [ "x$1" = "x--portable" ]; then
+        run_args="${run_args} --portable"
+        shift
+    elif [ "x$1" = "x--debug" ]; then
+        run_args="${run_args} --debug"
+        shift
+    elif [ "x$1" = "x--zygote" ]; then
+        run_args="${run_args} --zygote"
+        shift
+    elif [ "x$1" = "x--no-verify" ]; then
+        run_args="${run_args} --no-verify"
+        shift
+    elif [ "x$1" = "x--no-optimize" ]; then
+        run_args="${run_args} --no-optimize"
+        shift
+    elif [ "x$1" = "x--valgrind" ]; then
+        run_args="${run_args} --valgrind"
+        shift
+    elif [ "x$1" = "x--dev" ]; then
+        run_args="${run_args} --dev"
+        shift
+    elif [ "x$1" = "x--update" ]; then
+        run_args="${run_args} --update"
+        shift
+    elif [ "x$1" = "x--help" ]; then
+        usage="yes"
+        shift
+    elif expr "x$1" : "x--" >/dev/null 2>&1; then
+        echo "unknown option: $1" 1>&2
+        usage="yes"
+        break
+    else
+        break
+    fi
+done
+
+if [ "$usage" = "yes" ]; then
+    prog=`basename $prog`
+    (
+        echo "usage:"
+        echo "  $prog --help     Print this message."
+        echo "  $prog [options]  Run all tests with the given options."
+        echo "  Options are all passed to run-test; refer to that for " \
+             "further documentation:"
+        echo "    --debug --dev --fast --host --no-optimize --no-verify" \
+             "--portable"
+        echo "    --reference --update --valgrind --zygote"
+    ) 1>&2
+    exit 1
+fi
+
+passed=0
+failed=0
+failNames=""
+
+for i in *; do
+    if [ -d "$i" -a -r "$i" -a -r "${i}/info.txt" ]; then
+        ./run-test ${run_args} "$i"
+        if [ "$?" = "0" ]; then
+            ((passed += 1))
+        else
+            ((failed += 1))
+            failNames="$failNames $i"
+        fi
+    fi
+done
+
+echo "passed: $passed test(s)"
+echo "failed: $failed test(s)"
+
+for i in $failNames; do
+    echo "failed: $i"
+done
diff --git a/tests/run-test b/tests/run-test
new file mode 100755
index 0000000..fb758d7
--- /dev/null
+++ b/tests/run-test
@@ -0,0 +1,254 @@
+#!/bin/bash
+#
+# 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.
+
+# 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}"`
+
+export JAVA="java"
+export JAVAC="javac -target 1.5"
+export RUN="${progdir}/etc/push-and-run-test-jar"
+
+info="info.txt"
+build="build"
+run="run"
+expected="expected.txt"
+output="output.txt"
+build_output="build-output.txt"
+run_args="--quiet"
+
+dev_mode="no"
+update_mode="no"
+debug_mode="no"
+usage="no"
+
+while true; do
+    if [ "x$1" = "x--host" ]; then
+        RUN="${progdir}/etc/host-run-test-jar"
+        shift
+    elif [ "x$1" = "x--reference" ]; then
+        RUN="${progdir}/etc/reference-run-test-classes"
+        shift
+    elif [ "x$1" = "x--jit" ]; then
+        run_args="${run_args} --jit"
+        shift
+    elif [ "x$1" = "x--fast" ]; then
+        run_args="${run_args} --fast"
+        shift
+    elif [ "x$1" = "x--portable" ]; then
+        run_args="${run_args} --portable"
+        shift
+    elif [ "x$1" = "x--debug" ]; then
+        run_args="${run_args} --debug"
+        shift
+    elif [ "x$1" = "x--gdb" ]; then
+        run_args="${run_args} --gdb"
+        dev_mode="yes"
+        shift
+    elif [ "x$1" = "x--zygote" ]; then
+        run_args="${run_args} --zygote"
+        shift
+    elif [ "x$1" = "x--no-verify" ]; then
+        run_args="${run_args} --no-verify"
+        shift
+    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
+    elif [ "x$1" = "x--dev" ]; then
+        run_args="${run_args} --dev"
+        dev_mode="yes"
+        shift
+    elif [ "x$1" = "x--update" ]; then
+        update_mode="yes"
+        shift
+    elif [ "x$1" = "x--help" ]; then
+        usage="yes"
+        shift
+    elif expr "x$1" : "x--" >/dev/null 2>&1; then
+        echo "unknown option: $1" 1>&2
+        usage="yes"
+        break
+    else
+        break
+    fi
+done
+
+if [ "$dev_mode" = "yes" -a "$update_mode" = "yes" ]; then
+    echo "--dev and --update are mutually exclusive" 1>&2
+    usage="yes"
+fi
+
+if [ "$usage" = "no" ]; then
+    if [ "x$1" = "x" -o "x$1" = "x-" ]; then
+        test_dir=`basename "$oldwd"`
+    else
+        test_dir="$1"
+    fi
+
+    if [ '!' -d "$test_dir" ]; then
+        td2=`echo ${test_dir}-*`
+        if [ '!' -d "$td2" ]; then
+            echo "${test_dir}: no such test directory" 1>&2
+            usage="yes"
+        fi
+        test_dir="$td2"
+    fi
+
+    # Shift to get rid of the test name argument. The rest of the arguments
+    # will get passed to the test run.
+    shift
+fi
+
+if [ "$usage" = "yes" ]; then
+    prog=`basename $prog`
+    (
+        echo "usage:"
+        echo "  $prog --help                          Print this message."
+        echo "  $prog [options] [test-name]           Run test normally."
+        echo "  $prog --dev [options] [test-name]     Development mode" \
+             "(dumps to stdout)."
+        echo "  $prog --update [options] [test-name]  Update mode" \
+             "(replaces expected.txt)."
+        echo '  Omitting the test name or specifying "-" will use the' \
+             "current directory."
+        echo "  Runtime Options:"
+        echo "    --fast         Use the fast interpreter (the default)."
+        echo "    --jit          Use the jit."
+        echo "    --portable     Use the portable interpreter."
+        echo "    --debug        Wait for a debugger to attach."
+        #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."
+        echo "    --host         Use the host-mode virtual machine."
+        echo "    --valgrind     Use valgrind when running locally."
+        echo "    --reference    Use a host-local reference virtual machine."
+    ) 1>&2
+    exit 1
+fi
+
+cd "$test_dir"
+test_dir=`pwd`
+
+td_info="${test_dir}/${info}"
+td_expected="${test_dir}/${expected}"
+
+tmp_dir="/tmp/test-$$"
+
+if [ '!' '(' -r "$td_info" -a -r "$td_expected" ')' ]; then
+    echo "${test_dir}: missing files" 1>&2
+    exit 1
+fi
+
+# copy the test to a temp dir and run it
+
+echo "${test_dir}: running..." 1>&2
+
+rm -rf "$tmp_dir"
+cp -Rp "$test_dir" "$tmp_dir"
+cd "$tmp_dir"
+
+if [ '!' -r "$build" ]; then
+    cp "${progdir}/etc/default-build" build
+fi
+
+if [ '!' -r "$run" ]; then
+    cp "${progdir}/etc/default-run" run
+fi
+
+chmod 755 "$build"
+chmod 755 "$run"
+
+good="no"
+if [ "$dev_mode" = "yes" ]; then
+    "./${build}" 2>&1
+    echo "build exit status: $?" 1>&2
+    "./${run}" $run_args "$@" 2>&1
+    echo "run exit status: $?" 1>&2
+    good="yes"
+elif [ "$update_mode" = "yes" ]; then
+    "./${build}" >"$build_output" 2>&1
+    build_exit="$?"
+    if [ "$build_exit" = '0' ]; then
+        "./${run}" $run_args "$@" >"$output" 2>&1
+        sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}"
+        good="yes"
+    else
+        cat "$build_output" 1>&2
+        echo "build exit status: $build_exit" 1>&2
+    fi
+else
+    "./${build}" >"$build_output" 2>&1
+    build_exit="$?"
+    if [ "$build_exit" = '0' ]; then
+        "./${run}" $run_args "$@" >"$output" 2>&1
+    else
+        cp "$build_output" "$output"
+        echo "build exit status: $build_exit" >>"$output"
+    fi
+    diff --strip-trailing-cr -q "$expected" "$output" >/dev/null
+    if [ "$?" = "0" ]; then
+        # output == expected
+        good="yes"
+        echo "${test_dir}: succeeded!" 1>&2
+    fi
+fi
+
+if [ "$good" = "yes" ]; then
+    cd "$oldwd"
+    rm -rf "$tmp_dir"
+    exit 0
+fi
+
+(
+    if [ "$update_mode" '!=' "yes" ]; then
+        echo "${test_dir}: FAILED!"
+        echo ' '
+        echo '#################### info'
+        cat "${td_info}" | sed 's/^/# /g'
+        echo '#################### diffs'
+        diff --strip-trailing-cr -u "$expected" "$output"
+        echo '####################'
+        echo ' '
+    fi
+    echo "files left in ${tmp_dir}"
+) 1>&2
+
+exit 1
diff --git a/tools/Android.mk b/tools/Android.mk
new file mode 100644
index 0000000..6571161
--- /dev/null
+++ b/tools/Android.mk
@@ -0,0 +1 @@
+include $(all-subdir-makefiles)
diff --git a/tools/deadcode.py b/tools/deadcode.py
new file mode 100755
index 0000000..2ef8c70
--- /dev/null
+++ b/tools/deadcode.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+
+import os
+import re
+import sys
+
+def SplitSections(buffer):
+    """Spin through the input buffer looking for section header lines.
+    When found, the name of the section is extracted.  The entire contents
+    of that section is added to a result hashmap with the section name
+    as the key"""
+
+    # Match lines like
+    #              |section_name:
+    # capturing section_name
+    headerPattern = re.compile(r'^\s+\|([a-z _]+)\:$', re.MULTILINE)
+
+    sections = {}
+    start = 0
+    anchor = -1
+    sectionName = ''
+
+    while True:
+        # Look for a section header
+        result = headerPattern.search(buffer, start)
+
+        # If there are no more, add a section from the last header to EOF
+        if result is None:
+            if anchor is not -1:
+                sections[sectionName] = buffer[anchor]
+            return sections
+
+        # Add the lines from the last header, to this one to the sections
+        # map indexed by the section name
+        if anchor is not -1:
+            sections[sectionName] = buffer[anchor:result.start()]
+
+        sectionName = result.group(1)
+        start = result.end()
+        anchor = start
+
+    return sections
+
+def FindMethods(section):
+    """Spin through the 'method code index' section and extract all
+    method signatures.  When found, they are added to a result list."""
+
+    # Match lines like:
+    #             |[abcd] com/example/app/Class.method:(args)return
+    # capturing the method signature
+    methodPattern = re.compile(r'^\s+\|\[\w{4}\] (.*)$', re.MULTILINE)
+
+    start = 0
+    methods = []
+
+    while True:
+        # Look for a method name
+        result = methodPattern.search(section, start)
+
+        if result is None:
+            return methods
+
+        # Add the captured signature to the method list
+        methods.append(result.group(1))
+        start = result.end()
+
+def CallsMethod(codes, method):
+    """Spin through all the input method signatures.  For each one, return
+    whether or not there is method invokation line in the codes section that
+    lists the method as the target."""
+
+    start = 0
+
+    while True:
+        # Find the next reference to the method signature
+        match = codes.find(method, start)
+
+        if match is -1:
+            break;
+
+        # Find the beginning of the line the method reference is on
+        startOfLine = codes.rfind("\n", 0, match) + 1
+
+        # If the word 'invoke' comes between the beginning of the line
+        # and the method reference, then it is a call to that method rather
+        # than the beginning of the code section for that method.
+        if codes.find("invoke", startOfLine, match) is not -1:
+            return True
+
+        start = match + len(method)
+
+    return False
+
+
+
+def main():
+    if len(sys.argv) is not 2 or not sys.argv[1].endswith(".jar"):
+        print "Usage:", sys.argv[0], "<filename.jar>"
+        sys.exit()
+
+    command = 'dx --dex --dump-width=1000 --dump-to=-"" "%s"' % sys.argv[1]
+
+    pipe = os.popen(command)
+
+    # Read the whole dump file into memory
+    data = pipe.read()
+    sections = SplitSections(data)
+
+    pipe.close()
+    del(data)
+
+    methods = FindMethods(sections['method code index'])
+    codes = sections['codes']
+    del(sections)
+
+    print "Dead Methods:"
+    count = 0
+
+    for method in methods:
+        if not CallsMethod(codes, method):
+            print "\t", method
+            count += 1
+
+    if count is 0:
+        print "\tNone"
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/dex-preopt b/tools/dex-preopt
new file mode 100755
index 0000000..a9b75a4
--- /dev/null
+++ b/tools/dex-preopt
@@ -0,0 +1,320 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Usage: dex-preopt [options] path/to/input.jar path/to/output.odex
+#
+# This tool runs a host build of dalvikvm in order to preoptimize dex
+# files that will be run on a device.
+#
+# The input may be any sort of jar file (including .apk files), as long
+# as it contains a classes.dex file. Note that optimized versions of
+# bootstrap classes must be created before this can be run on other files;
+# use the "--bootstrap" option to do this.
+#
+# The "output.odex" file must not already exist.
+#
+# This is expected to be running in a user build environment, where
+# "dexopt" is available on the host.
+#
+# Options:
+#   --build-dir=path/to/out -- Specify where the base of the build tree is.
+#     This is typically a directory named "out". If not specified, it is
+#     assumed to be the current directory. The specified input and output
+#     paths are taken to be relative to this directory.
+#   --dexopt=path/to/dexopt -- Specify the path to the dexopt executable.
+#     If unspecified, there must be a unique subdirectory of the build-dir
+#     that looks like host/ARCH/bin which must contain dexopt.
+#   --product-dir=path/to/product -- Specify the path, relative to the build
+#     directory, where the product tree to be used is. This directory should
+#     contain the boot classpath jar files. If not specified, then there
+#     must be a unique directory in the build named "target/product/NAME",
+#     and this is the directory that will be used.
+#   --boot-dir=path/to/bootclasspath -- Specify the path, relative to the
+#     product directory, of the directory where the boot classpath files
+#     reside. If not specified, this defaults to "system/framework"
+#   --boot-jars=list:of:jar:base:names -- Specify the list of base names
+#     of bootstrap classpath elements, colon-separated. Order is significant
+#     and must match the BOOTCLASSPATH that is eventually specified at
+#     runtime on the device. This defaults to "core". However, this really
+#     needs to match the target product's BOOTCLASSPATH, which, as of this
+#     writing, doesn't have a super-strict way of being defined within the
+#     build. You can find variations of it in different init.rc files under
+#     system/core/rootdir or under product-specific directories.
+#   --bootstrap -- Process the bootstrap classes. If this is specified,
+#     then, instead of processing a specified input file, no other arguments
+#     are taken, and what is processed is the entirety of the boot jar
+#     list, in order.
+#   --verify={none,remote,all} -- Specify what level of verification to
+#     do. Defaults to "all".
+#   --optimize={none,verified,all} -- Specify which classes to optimize.
+#     Defaults to "verified".
+#   --no-register-maps -- Indicate that the output should not contain
+#     register maps. By default, register maps are created and included.
+#   --uniprocessor -- Indicate that the output should target a uniprocessor.
+#     By default, optimizations will be made that specifically target
+#     SMP processors (which will merely be superfluous on uniprocessors).
+#
+
+# Defaults.
+dexopt=''
+buildDir='.'
+productDir=''
+bootDir='system/framework'
+bootstrap='no'
+doVerify='all'
+doOptimize='verified'
+doRegisterMaps='yes'
+doUniprocessor='no'
+bootJars='core'
+
+optimizeFlags='' # built up from the more human-friendly options
+bogus='no' # indicates if there was an error during processing arguments
+
+# Iterate over the arguments looking for options.
+while true; do
+    origOption="$1"
+
+    if [ "x${origOption}" = "x--" ]; then
+        # A raw "--" signals the end of option processing.
+        shift
+        break
+    fi
+
+    # Parse the option into components.
+    optionBeforeValue=`expr -- "${origOption}" : '--\([^=]*\)='`
+
+    if [ "$?" = '0' ]; then
+        # Option has the form "--option=value".
+        option="${optionBeforeValue}"
+        value=`expr -- "${origOption}" : '--[^=]*=\(.*\)'`
+        hasValue='yes'
+    else
+        option=`expr -- "${origOption}" : '--\(.*\)'`
+        if [ "$?" = '1' ]; then
+            # Not an option.
+            break
+        fi
+        # Option has the form "--option".
+        value=""
+        hasValue='no'
+    fi
+    shift
+
+    # Interpret the option
+    if [ "${option}" = 'build-dir' -a "${hasValue}" = 'yes' ]; then
+        buildDir="${value}"
+    elif [ "${option}" = 'dexopt' -a "${hasValue}" = 'yes' ]; then
+        dexopt="${value}"
+    elif [ "${option}" = 'boot-dir' -a "${hasValue}" = 'yes' ]; then
+        bootDir="${value}"
+    elif [ "${option}" = 'product-dir' -a "${hasValue}" = 'yes' ]; then
+        productDir="${value}"
+    elif [ "${option}" = 'boot-jars' -a "${hasValue}" = 'yes' ]; then
+        bootJars="${value}"
+    elif [ "${option}" = 'bootstrap' -a "${hasValue}" = 'no' ]; then
+        bootstrap='yes'
+    elif [ "${option}" = 'verify' -a "${hasValue}" = 'yes' ]; then
+        doVerify="${value}"
+    elif [ "${option}" = 'optimize' -a "${hasValue}" = 'yes' ]; then
+        doOptimize="${value}"
+    elif [ "${option}" = 'no-register-maps' -a "${hasValue}" = 'no' ]; then
+        doRegisterMaps='no'
+    elif [ "${option}" = 'uniprocessor' -a "${hasValue}" = 'no' ]; then
+        doUniprocessor='yes'
+    else
+        echo "unknown option: ${origOption}" 1>&2
+        bogus='yes'
+    fi
+done
+
+# Check and set up the input and output files. In the case of bootstrap
+# processing, verify that no files are specified.
+inputFile=$1
+outputFile=$2
+if [ "${bootstrap}" = 'yes' ]; then
+    if [ "$#" != '0' ]; then
+        echo "unexpected arguments in --bootstrap mode" 1>&2
+        bogus=yes
+    fi
+elif [ "$#" != '2' ]; then
+    echo "must specify input and output files (and no more arguments)" 1>&2
+    bogus=yes
+fi
+
+# Sanity-check the specified build directory.
+if [ "x${buildDir}" = 'x' ]; then
+    echo "must specify build directory" 1>&2
+    bogus=yes
+elif [ ! '(' -d "${buildDir}" -a -w "${buildDir}" ')' ]; then
+    echo "build-dir is not a writable directory: ${buildDir}" 1>&2
+    bogus=yes
+fi
+
+# Sanity-check the specified boot classpath directory.
+if [ "x${bootDir}" = 'x' ]; then
+    echo "must specify boot classpath directory" 1>&2
+    bogus=yes
+fi
+
+# Sanity-check the specified boot jar list.
+if [ "x${bootJars}" = 'x' ]; then
+    echo "must specify non-empty boot-jars list" 1>&2
+    bogus=yes
+fi
+
+# Sanity-check and expand the verify option.
+if [ "x${doVerify}" = 'xnone' ]; then
+    optimizeFlags="${optimizeFlags},v=n"
+elif [ "x${doVerify}" = 'xremote' ]; then
+    optimizeFlags="${optimizeFlags},v=r"
+elif [ "x${doVerify}" = 'xall' ]; then
+    optimizeFlags="${optimizeFlags},v=a"
+else
+    echo "bad value for --verify: ${doVerify}" 1>&2
+    bogus=yes
+fi
+
+# Sanity-check and expand the optimize option.
+if [ "x${doOptimize}" = 'xnone' ]; then
+    optimizeFlags="${optimizeFlags},o=n"
+elif [ "x${doOptimize}" = 'xverified' ]; then
+    optimizeFlags="${optimizeFlags},o=v"
+elif [ "x${doOptimize}" = 'xall' ]; then
+    optimizeFlags="${optimizeFlags},o=a"
+else
+    echo "bad value for --optimize: ${doOptimize}" 1>&2
+    bogus=yes
+fi
+
+# Expand the register maps selection, if necessary.
+if [ "${doRegisterMaps}" = 'yes' ]; then
+    optimizeFlags="${optimizeFlags},m=y"
+fi
+
+# Expand the uniprocessor directive, if necessary.
+if [ "${doUniprocessor}" = 'yes' ]; then
+    optimizeFlags="${optimizeFlags},u=y"
+else
+    optimizeFlags="${optimizeFlags},u=n"
+fi
+
+# Kill off the spare comma in optimizeFlags.
+optimizeFlags=`echo ${optimizeFlags} | sed 's/^,//'`
+
+# Error out if there was trouble.
+if [ "${bogus}" = 'yes' ]; then
+    # There was an error during option processing.
+    echo "usage: $0" 1>&2
+    echo '  [--build-dir=path/to/out] [--dexopt=path/to/dexopt]' 1>&2
+    echo '  [--product-dir=path/to/product] [--boot-dir=name]' 1>&2
+    echo '  [--boot-jars=list:of:names] [--bootstrap]' 1>&2
+    echo '  [--verify=type] [--optimize=type] [--no-register-maps]' 1>&2
+    echo '  [--uniprocessor] path/to/input.jar path/to/output.odex' 1>&2
+    exit 1
+fi
+
+# Cd to the build directory, un-symlinkifying it for clarity.
+cd "${buildDir}"
+cd "`/bin/pwd`"
+
+# If needed, find the default product directory.
+if [ "x${productDir}" = 'x' ]; then
+    productDir="`ls target/product`"
+    if [ "$?" != '0' ]; then
+        echo "can't find product directory" 1>&2
+        exit 1
+    elif [ `expr -- "${productDir}" : ".* "` != '0' ]; then
+        echo "ambiguous product directory" 1>&2
+        exit 1
+    fi
+    productDir="target/product/${productDir}"
+fi
+
+# Verify the product directory.
+if [ ! '(' -d "${productDir}" -a -w "${productDir}" ')' ]; then
+    echo "product-dir is not a writable directory: ${productDir}" 1>&2
+    exit 1
+fi
+
+# Expand and verify the boot classpath directory. We add "/./" here to
+# separate the build system part of the path from the target system
+# suffix part of the path. The dexopt executable (deep inside the vm
+# really) uses this to know how to generate the names of the
+# dependencies (since we don't want the device files to contain bits
+# of pathname from the host build system).
+productBootDir="${productDir}/./${bootDir}"
+if [ ! '(' -d "${productBootDir}" -a -w "${productBootDir}" ')' ]; then
+    echo "boot-dir is not a writable directory: ${productBootDir}" 1>&2
+    exit 1
+fi
+
+# Find the dexopt binary if necesasry, and verify it.
+if [ "x${dexopt}" = 'x' ]; then
+    dexopt="`ls host/*/bin/dexopt`"
+    if [ "$?" != '0' ]; then
+        echo "can't find dexopt binary" 1>&2
+        exit 1
+    elif [ `expr -- "${dexopt}" : ".* "` != '0' ]; then
+        echo "ambiguous host directory" 1>&2
+        exit 1
+    fi
+fi
+if [ ! -x "${dexopt}" ]; then
+    echo "dexopt binary is not executable: ${dexopt}" 1>&2
+    exit 1
+fi
+
+# Expand the bootJars into paths that are relative from the build
+# directory, maintaining the colon separators.
+BOOTCLASSPATH=`echo ":${bootJars}" | \
+    sed "s!:\([^:]*\)!:${productBootDir}/\1.jar!g" | \
+    sed 's/^://'`
+export BOOTCLASSPATH
+
+if [ "${bootstrap}" = 'yes' ]; then
+    # Split the boot classpath into separate elements and iterate over them,
+    # processing each, in order.
+    elements=`echo "${BOOTCLASSPATH}" | sed 's/:/ /g'`
+
+    for inputFile in $elements; do
+        echo "Processing ${inputFile}" 1>&2
+        outputFile="`dirname ${inputFile}`/`basename ${inputFile} .jar`.odex"
+        "${dexopt}" --preopt "${inputFile}" "${outputFile}" "${optimizeFlags}"
+        status="$?"
+        if [ "${status}" != '0' ]; then
+            exit "${status}"
+        fi
+    done
+else
+    echo "Processing ${inputFile}" 1>&2
+
+    bootJarFile=`expr -- "${inputFile}" : "${productDir}/${bootDir}/\(.*\)"`
+    if [ "x${bootJarFile}" != 'x' ]; then
+        # The input file is in the boot classpath directory, so it needs
+        # to have "/./" inserted into it (see longer description above).
+        inputFile="${productBootDir}/${bootJarFile}"
+    fi
+
+    "${dexopt}" --preopt "${inputFile}" "${outputFile}" "${optimizeFlags}"
+
+    status="$?"
+    if [ "${status}" != '0' ]; then
+        exit "${status}"
+    fi
+fi
+
+echo "Done!" 1>&2
diff --git a/tools/dexcheck b/tools/dexcheck
new file mode 100755
index 0000000..2ec8b29
--- /dev/null
+++ b/tools/dexcheck
@@ -0,0 +1,67 @@
+#!/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.
+
+#
+# This tool checks the integrity of the optimized dex files on a single
+# Android device connected to your computer.
+#
+# Brief HOW-TO:
+#
+# 1. Disconnect all but one device from USB.
+# 2. Set up a standard shell environment (envsetup.sh, lunch, etc.).
+# 3. Run "adb root" if necessary to ensure read permission on
+#    /data/dalvik-cache. If in doubt, run the command. Power users may
+#    also use "su" followed by "chmod 777 /data/dalvik-cache".
+# 4. Run this script, e.g. from the build root, "dalvik/tools/dexcheck".
+#
+# If all of the dex files are okay, you will just see a series of
+# lines written to your shell window naming each of the files. If
+# there is a problem, though, you will see something like this:
+#
+#     system@app@Maps.apk@classes.dex
+#     Failure in system@app@Maps.apk@classes.dex: ERROR: DEX parse failed
+#
+# When this happens, the log ("adb logcat") will generally have at
+# least a little more information about the dex level of the problem.
+# However, any error at all usually indicates some form of lower level
+# filesystem or filesystem cache corruption.
+#
+
+# Get the list of files.  Use "sed" to drop the trailing carriage return.
+files=`adb shell "cd /data/dalvik-cache; echo *" | sed -e s/.$//`
+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
+# flag was not available in 1.6 and earlier.
+#
+# 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..e1b7e73
--- /dev/null
+++ b/tools/dexdeps/Android.mk
@@ -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.
+
+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_TAGS := optional
+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..22380ce
--- /dev/null
+++ b/tools/dexdeps/README.txt
@@ -0,0 +1,32 @@
+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[]").
+
+  --just-classes
+
+    Indicates that output should only include a list of classes, as
+    opposed to also listing fields and methods.
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..8e4abaf
--- /dev/null
+++ b/tools/dexdeps/src/Android.mk
@@ -0,0 +1,31 @@
+# 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_TAGS := optional
+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/ClassRef.java b/tools/dexdeps/src/com/android/dexdeps/ClassRef.java
new file mode 100644
index 0000000..7f6edc9
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/ClassRef.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexdeps;
+
+import java.util.ArrayList;
+
+public class ClassRef {
+    private String mClassName;
+    private ArrayList<FieldRef> mFieldRefs;
+    private ArrayList<MethodRef> mMethodRefs;
+
+    /**
+     * Initializes a new class reference.
+     */
+    public ClassRef(String className) {
+        mClassName = className;
+        mFieldRefs = new ArrayList<FieldRef>();
+        mMethodRefs = new ArrayList<MethodRef>();
+    }
+
+    /**
+     * Adds the field to the field list.
+     */
+    public void addField(FieldRef fref) {
+        mFieldRefs.add(fref);
+    }
+
+    /**
+     * Returns the field list as an array.
+     */
+    public FieldRef[] getFieldArray() {
+        return mFieldRefs.toArray(new FieldRef[mFieldRefs.size()]);
+    }
+
+    /**
+     * Adds the method to the method list.
+     */
+    public void addMethod(MethodRef mref) {
+        mMethodRefs.add(mref);
+    }
+
+    /**
+     * Returns the method list as an array.
+     */
+    public MethodRef[] getMethodArray() {
+        return mMethodRefs.toArray(new MethodRef[mMethodRefs.size()]);
+    }
+
+    /**
+     * Gets the class name.
+     */
+    public String getName() {
+        return mClassName;
+    }
+}
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..89dff18
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/DexData.java
@@ -0,0 +1,602 @@
+/*
+ * 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();
+    }
+
+    /**
+     * Verifies the given magic number.
+     */
+    private static boolean verifyMagic(byte[] magic) {
+        return Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC) ||
+            Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC_API_13);
+    }
+
+    /**
+     * 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 (!verifyMagic(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 class references that don't
+     * correspond to classes in the DEX file.  Each class reference has
+     * a list of the referenced fields and methods associated with
+     * that class.
+     */
+    public ClassRef[] getExternalReferences() {
+        // create a sparse array of ClassRef that parallels mTypeIds
+        ClassRef[] sparseRefs = new ClassRef[mTypeIds.length];
+
+        // create entries for all externally-referenced classes
+        int count = 0;
+        for (int i = 0; i < mTypeIds.length; i++) {
+            if (!mTypeIds[i].internal) {
+                sparseRefs[i] =
+                    new ClassRef(mStrings[mTypeIds[i].descriptorIdx]);
+                count++;
+            }
+        }
+
+        // add fields and methods to the appropriate class entry
+        addExternalFieldReferences(sparseRefs);
+        addExternalMethodReferences(sparseRefs);
+
+        // crunch out the sparseness
+        ClassRef[] classRefs = new ClassRef[count];
+        int idx = 0;
+        for (int i = 0; i < mTypeIds.length; i++) {
+            if (sparseRefs[i] != null)
+                classRefs[idx++] = sparseRefs[i];
+        }
+
+        assert idx == count;
+
+        return classRefs;
+    }
+
+    /**
+     * Runs through the list of field references, inserting external
+     * references into the appropriate ClassRef.
+     */
+    private void addExternalFieldReferences(ClassRef[] sparseRefs) {
+        for (int i = 0; i < mFieldIds.length; i++) {
+            if (!mTypeIds[mFieldIds[i].classIdx].internal) {
+                FieldIdItem fieldId = mFieldIds[i];
+                FieldRef newFieldRef = new FieldRef(
+                        classNameFromTypeIndex(fieldId.classIdx),
+                        classNameFromTypeIndex(fieldId.typeIdx),
+                        mStrings[fieldId.nameIdx]);
+                sparseRefs[mFieldIds[i].classIdx].addField(newFieldRef);
+            }
+        }
+    }
+
+    /**
+     * Runs through the list of method references, inserting external
+     * references into the appropriate ClassRef.
+     */
+    private void addExternalMethodReferences(ClassRef[] sparseRefs) {
+        for (int i = 0; i < mMethodIds.length; i++) {
+            if (!mTypeIds[mMethodIds[i].classIdx].internal) {
+                MethodIdItem methodId = mMethodIds[i];
+                MethodRef newMethodRef = new MethodRef(
+                        classNameFromTypeIndex(methodId.classIdx),
+                        argArrayFromProtoIndex(methodId.protoIdx),
+                        returnTypeFromProtoIndex(methodId.protoIdx),
+                        mStrings[methodId.nameIdx]);
+                sparseRefs[mMethodIds[i].classIdx].addMethod(newMethodRef);
+            }
+        }
+    }
+
+
+    /*
+     * =======================================================================
+     *      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, 0x36, 0x00 };
+        public static final byte[] DEX_FILE_MAGIC_API_13 = {
+            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..873db94
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/DexDataException.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.
+ */
+
+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..93e87cb
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/FieldRef.java
@@ -0,0 +1,51 @@
+/*
+ * 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..410694a
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/Main.java
@@ -0,0 +1,231 @@
+/*
+ * 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[] mInputFileNames;
+    private String mOutputFormat = "xml";
+
+    /**
+     * whether to only emit info about classes used; when {@code false},
+     * info about fields and methods is also emitted
+     */
+    private boolean mJustClasses = false;
+
+    /**
+     * 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);
+            boolean first = true;
+
+            for (String fileName : mInputFileNames) {
+                RandomAccessFile raf = openInputFile(fileName);
+                DexData dexData = new DexData(raf);
+                dexData.load();
+
+                if (first) {
+                    first = false;
+                    Output.generateFirstHeader(fileName, mOutputFormat);
+                } else {
+                    Output.generateHeader(fileName, mOutputFormat);
+                }
+
+                Output.generate(dexData, mOutputFormat, mJustClasses);
+                Output.generateFooter(mOutputFormat);
+                raf.close();
+            }
+        } 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 an 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.
+     *
+     * @param fileName the name of the file to open
+     */
+    RandomAccessFile openInputFile(String fileName) throws IOException {
+        RandomAccessFile raf;
+
+        raf = openInputFileAsZip(fileName);
+        if (raf == null) {
+            File inputFile = new File(fileName);
+            raf = new RandomAccessFile(inputFile, "r");
+        }
+
+        return raf;
+    }
+
+    /**
+     * Tries to open an input file as a Zip archive (jar/apk) with a
+     * "classes.dex" inside.
+     *
+     * @param fileName the name of the file to open
+     * @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(String fileName) throws IOException {
+        ZipFile zipFile;
+
+        /*
+         * Try it as a zip file.
+         */
+        try {
+            zipFile = new ZipFile(fileName);
+        } catch (FileNotFoundException fnfe) {
+            /* not found, no point in retrying as non-zip */
+            System.err.println("Unable to open '" + fileName + "': " +
+                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 '" + fileName + "'");
+            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 if (arg.equals("--just-classes")) {
+                mJustClasses = true;
+            } else {
+                System.err.println("Unknown option '" + arg + "'");
+                throw new UsageException();
+            }
+        }
+
+        // We expect at least one more argument (file name).
+        int fileCount = args.length - idx;
+        if (fileCount == 0) {
+            throw new UsageException();
+        }
+
+        mInputFileNames = new String[fileCount];
+        System.arraycopy(args, idx, mInputFileNames, 0, fileCount);
+    }
+
+    /**
+     * Prints command-line usage info.
+     */
+    void usage() {
+        System.err.print(
+                "DEX dependency scanner v1.2\n" +
+                "Copyright (C) 2009 The Android Open Source Project\n\n" +
+                "Usage: dexdeps [options] <file.{dex,apk,jar}> ...\n" +
+                "Options:\n" +
+                "  --format={xml,brief}\n" +
+                "  --just-classes\n");
+    }
+}
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..67dce62
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/MethodRef.java
@@ -0,0 +1,87 @@
+/*
+ * 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..dbe3bc2
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/Output.java
@@ -0,0 +1,346 @@
+/*
+ * 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.PrintStream;
+
+/**
+ * Generate fancy output.
+ */
+public class Output {
+    private static final String IN0 = "";
+    private static final String IN1 = "  ";
+    private static final String IN2 = "    ";
+    private static final String IN3 = "      ";
+    private static final String IN4 = "        ";
+
+    private static final PrintStream out = System.out;
+
+    private static void generateHeader0(String fileName, String format) {
+        if (format.equals("brief")) {
+            if (fileName != null) {
+                out.println("File: " + fileName);
+            }
+        } else if (format.equals("xml")) {
+            if (fileName != null) {
+                out.println(IN0 + "<external file=\"" + fileName + "\">");
+            } else {
+                out.println(IN0 + "<external>");
+            }
+        } else {
+            /* should've been trapped in arg handler */
+            throw new RuntimeException("unknown output format");
+        }
+    }
+
+    public static void generateFirstHeader(String fileName, String format) {
+        generateHeader0(fileName, format);
+    }
+
+    public static void generateHeader(String fileName, String format) {
+        out.println();
+        generateHeader0(fileName, format);
+    }
+
+    public static void generateFooter(String format) {
+        if (format.equals("brief")) {
+            // Nothing to do.
+        } else if (format.equals("xml")) {
+            out.println("</external>");
+        } else {
+            /* should've been trapped in arg handler */
+            throw new RuntimeException("unknown output format");
+        }
+    }
+
+    public static void generate(DexData dexData, String format,
+            boolean justClasses) {
+        if (format.equals("brief")) {
+            printBrief(dexData, justClasses);
+        } else if (format.equals("xml")) {
+            printXml(dexData, justClasses);
+        } 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, boolean justClasses) {
+        ClassRef[] externClassRefs = dexData.getExternalReferences();
+
+        printClassRefs(externClassRefs, justClasses);
+
+        if (!justClasses) {
+            printFieldRefs(externClassRefs);
+            printMethodRefs(externClassRefs);
+        }
+    }
+
+    /**
+     * Prints the list of classes in a simple human-readable format.
+     */
+    static void printClassRefs(ClassRef[] classes, boolean justClasses) {
+        if (!justClasses) {
+            out.println("Classes:");
+        }
+
+        for (int i = 0; i < classes.length; i++) {
+            ClassRef ref = classes[i];
+
+            out.println(descriptorToDot(ref.getName()));
+        }
+    }
+
+    /**
+     * Prints the list of fields in a simple human-readable format.
+     */
+    static void printFieldRefs(ClassRef[] classes) {
+        out.println("\nFields:");
+        for (int i = 0; i < classes.length; i++) {
+            FieldRef[] fields = classes[i].getFieldArray();
+
+            for (int j = 0; j < fields.length; j++) {
+                FieldRef ref = fields[j];
+
+                out.println(descriptorToDot(ref.getDeclClassName()) +
+                    "." + ref.getName() + " : " + ref.getTypeName());
+            }
+        }
+    }
+
+    /**
+     * Prints the list of methods in a simple human-readable format.
+     */
+    static void printMethodRefs(ClassRef[] classes) {
+        out.println("\nMethods:");
+        for (int i = 0; i < classes.length; i++) {
+            MethodRef[] methods = classes[i].getMethodArray();
+
+            for (int j = 0; j < methods.length; j++) {
+                MethodRef ref = methods[j];
+
+                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, boolean justClasses) {
+        ClassRef[] externClassRefs = dexData.getExternalReferences();
+
+        /*
+         * Iterate through externClassRefs.  For each class, dump all of
+         * the matching fields and methods.
+         */
+        String prevPackage = null;
+        for (int i = 0; i < externClassRefs.length; i++) {
+            ClassRef cref = externClassRefs[i];
+            String declClassName = cref.getName();
+            String className = classNameOnly(declClassName);
+            String packageName = packageNameOnly(declClassName);
+
+            /*
+             * If we're in a different package, emit the appropriate tags.
+             */
+            if (!packageName.equals(prevPackage)) {
+                if (prevPackage != null) {
+                    out.println(IN1 + "</package>");
+                }
+
+                out.println(IN1 +
+                    "<package name=\"" + packageName + "\">");
+
+                prevPackage = packageName;
+            }
+
+            out.println(IN2 + "<class name=\"" + className + "\">");
+            if (!justClasses) {
+                printXmlFields(cref);
+                printXmlMethods(cref);
+            }
+            out.println(IN2 + "</class>");
+        }
+
+        if (prevPackage != null)
+            out.println(IN1 + "</package>");
+    }
+
+    /**
+     * Prints the externally-visible fields in XML format.
+     */
+    private static void printXmlFields(ClassRef cref) {
+        FieldRef[] fields = cref.getFieldArray();
+        for (int i = 0; i < fields.length; i++) {
+            FieldRef fref = fields[i];
+
+            out.println(IN3 + "<field name=\"" + fref.getName() +
+                "\" type=\"" + descriptorToDot(fref.getTypeName()) + "\"/>");
+        }
+    }
+
+    /**
+     * Prints the externally-visible methods in XML format.
+     */
+    private static void printXmlMethods(ClassRef cref) {
+        MethodRef[] methods = cref.getMethodArray();
+        for (int i = 0; i < methods.length; i++) {
+            MethodRef mref = methods[i];
+            String declClassName = mref.getDeclClassName();
+            boolean constructor;
+
+            constructor = mref.getName().equals("<init>");
+            if (constructor) {
+                // use class name instead of method name
+                out.println(IN3 + "<constructor name=\"" +
+                    classNameOnly(declClassName) + "\">");
+            } else {
+                out.println(IN3 + "<method name=\"" + mref.getName() +
+                    "\" return=\"" + descriptorToDot(mref.getReturnTypeName()) +
+                    "\">");
+            }
+            String[] args = mref.getArgumentTypeNames();
+            for (int j = 0; j < args.length; j++) {
+                out.println(IN4 + "<parameter type=\"" +
+                    descriptorToDot(args[j]) + "\"/>");
+            }
+            if (constructor) {
+                out.println(IN3 + "</constructor>");
+            } else {
+                out.println(IN3 + "</method>");
+            }
+        }
+    }
+
+
+    /*
+     * =======================================================================
+     *      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..e695fc7
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/UsageException.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.
+ */
+
+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/dmtracedump/Android.mk b/tools/dmtracedump/Android.mk
new file mode 100644
index 0000000..5d3146e
--- /dev/null
+++ b/tools/dmtracedump/Android.mk
@@ -0,0 +1,24 @@
+#
+# Copyright 2006 The Android Open Source Project
+#
+# Java method trace dump tool
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := TraceDump.c
+LOCAL_CFLAGS += -O0 -g
+LOCAL_C_INCLUDES += dalvik/vm
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := dmtracedump
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := CreateTestTrace.c
+LOCAL_CFLAGS += -O0 -g
+LOCAL_C_INCLUDES += dalvik/vm
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := create_test_dmtrace
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/dmtracedump/CreateTestTrace.c b/tools/dmtracedump/CreateTestTrace.c
new file mode 100644
index 0000000..a4ae02e
--- /dev/null
+++ b/tools/dmtracedump/CreateTestTrace.c
@@ -0,0 +1,493 @@
+/* //device/tools/dmtracedump/CreateTrace.c
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+/*
+ * Create a test file in the format required by dmtrace.
+ */
+#define NOT_VM
+#include "Profile.h"        // from VM header
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <ctype.h>
+
+/*
+ * Values from the header of the data file.
+ */
+typedef struct DataHeader {
+    unsigned int magic;
+    short version;
+    short offsetToData;
+    long long startWhen;
+} DataHeader;
+
+#define VERSION 2
+int versionNumber = VERSION;
+int verbose = 0;
+
+DataHeader header = { 0x574f4c53, VERSION, sizeof(DataHeader), 0LL };
+
+char *versionHeader = "*version\n";
+char *clockDef = "clock=thread-cpu\n";
+
+char *keyThreads =
+"*threads\n"
+"1      main\n"
+"2      foo\n"
+"3      bar\n"
+"4      blah\n";
+
+char *keyEnd = "*end\n";
+
+typedef struct dataRecord {
+    unsigned int        time;
+    int                 threadId;
+    unsigned int        action;         /* 0=entry, 1=exit, 2=exception exit */
+    char                *fullName;
+    char                *className;
+    char                *methodName;
+    char                *signature;
+    unsigned int        methodId;
+} dataRecord;
+
+dataRecord *records;
+
+#define BUF_SIZE 1024
+char buf[BUF_SIZE];
+
+typedef struct stack {
+    dataRecord  **frames;
+    int         indentLevel;
+} stack;
+
+/* Mac OS doesn't have strndup(), so implement it here.
+ */
+char *strndup(const char *src, size_t len)
+{
+    char *dest = (char *) malloc(len + 1);
+    strncpy(dest, src, len);
+    dest[len] = 0;
+    return dest;
+}
+
+/*
+ * Parse the input file.  It looks something like this:
+ * # This is a comment line
+ * 4  1 A
+ * 6  1  B
+ * 8  1  B
+ * 10 1 A
+ *
+ * where the first column is the time, the second column is the thread id,
+ * and the third column is the method (actually just the class name).  The
+ * number of spaces between the 2nd and 3rd columns is the indentation and
+ * determines the call stack.  Each called method must be indented by one
+ * more space.  In the example above, A is called at time 4, A calls B at
+ * time 6, B returns at time 8, and A returns at time 10.  Thread 1 is the
+ * only thread that is running.
+ *
+ * An alternative file format leaves out the first two columns:
+ * A
+ *  B
+ *  B
+ * A
+ *
+ * In this file format, the thread id is always 1, and the time starts at
+ * 2 and increments by 2 for each line.
+ */
+void parseInputFile(const char *inputFileName)
+{
+    unsigned int time = 0, threadId;
+    int len;
+    int linenum = 0;
+    int nextRecord = 0;
+    int indentLevel = 0;
+    stack *callStack;
+
+    FILE *inputFp = fopen(inputFileName, "r");
+    if (inputFp == NULL) {
+        perror(inputFileName);
+        exit(1);
+    }
+
+    /* Count the number of lines in the buffer */
+    int numRecords = 0;
+    int maxThreadId = 1;
+    int maxFrames = 0;
+    char *indentEnd;
+    while (fgets(buf, BUF_SIZE, inputFp)) {
+        char *cp = buf;
+        if (*cp == '#')
+            continue;
+        numRecords += 1;
+        if (isdigit(*cp)) {
+            int time = strtoul(cp, &cp, 0);
+            while (isspace(*cp))
+                cp += 1;
+            int threadId = strtoul(cp, &cp, 0);
+            if (maxThreadId < threadId)
+                maxThreadId = threadId;
+        }
+        indentEnd = cp;
+        while (isspace(*indentEnd))
+            indentEnd += 1;
+        if (indentEnd - cp + 1 > maxFrames)
+            maxFrames = indentEnd - cp + 1;
+    }
+    int numThreads = maxThreadId + 1;
+
+    /* Add space for a sentinel record at the end */
+    numRecords += 1;
+    records = (dataRecord *) malloc(sizeof(dataRecord) * numRecords);
+    callStack = (stack *) malloc(sizeof(stack) * numThreads);
+    int ii;
+    for (ii = 0; ii < numThreads; ++ii) {
+        callStack[ii].frames = NULL;
+        callStack[ii].indentLevel = 0;
+    }
+
+    rewind(inputFp);
+    while (fgets(buf, BUF_SIZE, inputFp)) {
+        int indent;
+        int action;
+        char *save_cp;
+
+        linenum += 1;
+        char *cp = buf;
+
+        /* Skip lines that start with '#' */
+        if (*cp == '#')
+            continue;
+
+        /* Get time and thread id */
+        if (!isdigit(*cp)) {
+            /* If the line does not begin with a digit, then fill in
+             * default values for the time and threadId.
+             */
+            time += 2;
+            threadId = 1;
+        } else {
+            time = strtoul(cp, &cp, 0);
+            while (isspace(*cp))
+                cp += 1;
+            threadId = strtoul(cp, &cp, 0);
+            cp += 1;
+        }
+
+        // Allocate space for the thread stack, if necessary
+        if (callStack[threadId].frames == NULL) {
+            dataRecord **stk;
+            stk = (dataRecord **) malloc(sizeof(dataRecord *) * maxFrames);
+            callStack[threadId].frames = stk;
+        }
+        indentLevel = callStack[threadId].indentLevel;
+
+        save_cp = cp;
+        while (isspace(*cp)) {
+            cp += 1;
+        }
+        indent = cp - save_cp + 1;
+        records[nextRecord].time = time;
+        records[nextRecord].threadId = threadId;
+
+        save_cp = cp;
+        while (*cp != '\n')
+            cp += 1;
+
+        /* Remove trailing spaces */
+        cp -= 1;
+        while (isspace(*cp))
+            cp -= 1;
+        cp += 1;
+        len = cp - save_cp;
+        records[nextRecord].fullName = strndup(save_cp, len);
+
+        /* Parse the name to support "class.method signature" */
+        records[nextRecord].className = NULL;
+        records[nextRecord].methodName = NULL;
+        records[nextRecord].signature = NULL;
+        cp = strchr(save_cp, '.');
+        if (cp) {
+            len = cp - save_cp;
+            if (len > 0)
+                records[nextRecord].className = strndup(save_cp, len);
+            save_cp = cp + 1;
+            cp = strchr(save_cp, ' ');
+            if (cp == NULL)
+                cp = strchr(save_cp, '\n');
+            if (cp && cp > save_cp) {
+                len = cp - save_cp;
+                records[nextRecord].methodName = strndup(save_cp, len);
+                save_cp = cp + 1;
+                cp = strchr(save_cp, ' ');
+                if (cp == NULL)
+                    cp = strchr(save_cp, '\n');
+                if (cp && cp > save_cp) {
+                    len = cp - save_cp;
+                    records[nextRecord].signature = strndup(save_cp, len);
+                }
+            }
+        }
+
+        if (verbose) {
+            printf("Indent: %d; IndentLevel: %d; Line: %s", indent, indentLevel, buf);
+        }
+
+        action = 0;
+        if (indent == indentLevel + 1) { // Entering a method
+            if (verbose)
+                printf("  Entering %s\n", records[nextRecord].fullName);
+            callStack[threadId].frames[indentLevel] = &records[nextRecord];
+        } else if (indent == indentLevel) { // Exiting a method
+            // Exiting method must be currently on top of stack (unless stack is empty)
+            if (callStack[threadId].frames[indentLevel - 1] == NULL) {
+                if (verbose)
+                    printf("  Exiting %s (past bottom of stack)\n", records[nextRecord].fullName);
+                callStack[threadId].frames[indentLevel - 1] = &records[nextRecord];
+                action = 1;
+            } else {
+                if (indentLevel < 1) {
+                    fprintf(stderr, "Error: line %d: %s", linenum, buf);
+                    fprintf(stderr, "  expected positive (>0) indentation, found %d\n",
+                            indent);
+                    exit(1);
+                }
+                char *name = callStack[threadId].frames[indentLevel - 1]->fullName;
+                if (strcmp(name, records[nextRecord].fullName) == 0) {
+                    if (verbose)
+                        printf("  Exiting %s\n", name);
+                    action = 1;
+                } else { // exiting method doesn't match stack's top method
+                    fprintf(stderr, "Error: line %d: %s", linenum, buf);
+                    fprintf(stderr, "  expected exit from %s\n",
+                            callStack[threadId].frames[indentLevel - 1]->fullName);
+                    exit(1);
+                }
+            }
+        } else {
+            if (nextRecord != 0) {
+                fprintf(stderr, "Error: line %d: %s", linenum, buf);
+                fprintf(stderr, "  expected indentation %d [+1], found %d\n",
+                        indentLevel, indent);
+                exit(1);
+            }
+
+            if (verbose) {
+                printf("  Nonzero indent at first record\n");
+                printf("  Entering %s\n", records[nextRecord].fullName);
+            }
+
+            // This is the first line of data, so we allow a larger
+            // initial indent.  This allows us to test popping off more
+            // frames than we entered.
+            indentLevel = indent - 1;
+            callStack[threadId].frames[indentLevel] = &records[nextRecord];
+        }
+
+        if (action == 0)
+            indentLevel += 1;
+        else
+            indentLevel -= 1;
+        records[nextRecord].action = action;
+        callStack[threadId].indentLevel = indentLevel;
+
+        nextRecord += 1;
+    }
+
+    /* Mark the last record with a sentinel */
+    memset(&records[nextRecord], 0, sizeof(dataRecord));
+}
+
+
+/*
+ * Write values to the binary data file.
+ */
+void write2LE(FILE* fp, unsigned short val)
+{
+    putc(val & 0xff, fp);
+    putc(val >> 8, fp);
+}
+
+void write4LE(FILE* fp, unsigned int val)
+{
+    putc(val & 0xff, fp);
+    putc((val >> 8) & 0xff, fp);
+    putc((val >> 16) & 0xff, fp);
+    putc((val >> 24) & 0xff, fp);
+}
+
+void write8LE(FILE* fp, unsigned long long val)
+{
+    putc(val & 0xff, fp);
+    putc((val >> 8) & 0xff, fp);
+    putc((val >> 16) & 0xff, fp);
+    putc((val >> 24) & 0xff, fp);
+    putc((val >> 32) & 0xff, fp);
+    putc((val >> 40) & 0xff, fp);
+    putc((val >> 48) & 0xff, fp);
+    putc((val >> 56) & 0xff, fp);
+}
+
+void writeDataRecord(FILE *dataFp, int threadId, unsigned int methodVal,
+                   unsigned int elapsedTime)
+{
+    if (versionNumber == 1)
+        putc(threadId, dataFp);
+    else
+        write2LE(dataFp, threadId);
+    write4LE(dataFp, methodVal);
+    write4LE(dataFp, elapsedTime);
+}
+
+void writeDataHeader(FILE *dataFp)
+{
+    struct timeval tv;
+    struct timezone tz;
+
+    gettimeofday(&tv, &tz);
+    unsigned long long startTime = tv.tv_sec;
+    startTime = (startTime << 32) | tv.tv_usec;
+    header.version = versionNumber;
+    write4LE(dataFp, header.magic);
+    write2LE(dataFp, header.version);
+    write2LE(dataFp, header.offsetToData);
+    write8LE(dataFp, startTime);
+}
+
+void writeKeyMethods(FILE *keyFp)
+{
+    dataRecord *pRecord, *pNext;
+    char *methodStr = "*methods\n";
+    fwrite(methodStr, strlen(methodStr), 1, keyFp);
+
+    /* Assign method ids in multiples of 4 */
+    unsigned int methodId = 0;
+    for (pRecord = records; pRecord->fullName; ++pRecord) {
+        if (pRecord->methodId)
+            continue;
+        unsigned int id = ++methodId << 2;
+        pRecord->methodId = id;
+
+        /* Assign this id to all the other records that have the
+         * same name.
+         */
+        for (pNext = pRecord + 1; pNext->fullName; ++pNext) {
+            if (pNext->methodId)
+                continue;
+            if (strcmp(pRecord->fullName, pNext->fullName) == 0)
+                pNext->methodId = id;
+        }
+        if (pRecord->className == NULL || pRecord->methodName == NULL) {
+            fprintf(keyFp, "%#x        %s      m       ()\n",
+                    pRecord->methodId, pRecord->fullName);
+        } else if (pRecord->signature == NULL) {
+            fprintf(keyFp, "%#x        %s      %s      ()\n",
+                    pRecord->methodId, pRecord->className,
+                    pRecord->methodName);
+        } else {
+            fprintf(keyFp, "%#x        %s      %s      %s\n",
+                    pRecord->methodId, pRecord->className,
+                    pRecord->methodName, pRecord->signature);
+        }
+    }
+}
+
+void writeKeys(FILE *keyFp)
+{
+    fprintf(keyFp, "%s%d\n%s", versionHeader, versionNumber, clockDef);
+    fwrite(keyThreads, strlen(keyThreads), 1, keyFp);
+    writeKeyMethods(keyFp);
+    fwrite(keyEnd, strlen(keyEnd), 1, keyFp);
+}
+
+void writeDataRecords(FILE *dataFp)
+{
+    dataRecord *pRecord;
+
+    for (pRecord = records; pRecord->fullName; ++pRecord) {
+        unsigned int val = METHOD_COMBINE(pRecord->methodId, pRecord->action);
+        writeDataRecord(dataFp, pRecord->threadId, val, pRecord->time);
+    }
+}
+
+void writeTrace(const char* traceFileName)
+{
+    FILE *fp = fopen(traceFileName, "w");
+    if (fp == NULL) {
+        perror(traceFileName);
+        exit(1);
+    }
+    writeKeys(fp);
+    writeDataHeader(fp);
+    writeDataRecords(fp);
+    fclose(fp);
+}
+
+int parseOptions(int argc, char **argv)
+{
+    int err = 0;
+    while (1) {
+        int opt = getopt(argc, argv, "v:d");
+        if (opt == -1)
+            break;
+        switch (opt) {
+            case 'v':
+                versionNumber = strtoul(optarg, NULL, 0);
+                if (versionNumber != 1 && versionNumber != 2) {
+                    fprintf(stderr, "Error: version number (%d) must be 1 or 2\n",
+                            versionNumber);
+                    err = 1;
+                }
+                break;
+            case 'd':
+                verbose = 1;
+                break;
+            default:
+                err = 1;
+                break;
+        }
+    }
+    return err;
+}
+
+int main(int argc, char** argv)
+{
+    char *inputFile;
+    char *traceFileName = NULL;
+    int len;
+
+    if (parseOptions(argc, argv) || argc - optind != 2) {
+        fprintf(stderr, "Usage: %s [-v version] [-d] input_file trace_prefix\n",
+                argv[0]);
+        exit(1);
+    }
+
+    inputFile = argv[optind++];
+    parseInputFile(inputFile);
+    traceFileName = argv[optind++];
+
+    writeTrace(traceFileName);
+
+    return 0;
+}
diff --git a/tools/dmtracedump/TraceDump.c b/tools/dmtracedump/TraceDump.c
new file mode 100644
index 0000000..976fe5f
--- /dev/null
+++ b/tools/dmtracedump/TraceDump.c
@@ -0,0 +1,2906 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Process dmtrace output.
+ *
+ * This is the wrong way to go about it -- C is a clumsy language for
+ * shuffling data around.  It'll do for a first pass.
+ */
+#define NOT_VM
+#include "Profile.h"        // from VM header
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+
+/* Version number in the key file.
+ * Version 1 uses one byte for the thread id.
+ * Version 2 uses two bytes for the thread ids.
+ * Version 3 encodes the record size and adds an optional extra timestamp field.
+ */
+int versionNumber;
+
+/* arbitrarily limit indentation */
+#define MAX_STACK_DEPTH 10000
+
+/* thread list in key file is not reliable, so just max out */
+#define MAX_THREADS     32768
+
+/* Size of temporary buffers for escaping html strings */
+#define HTML_BUFSIZE 10240
+
+char *htmlHeader =
+"<html>\n<head>\n<script type=\"text/javascript\" src=\"%ssortable.js\"></script>\n"
+"<script langugage=\"javascript\">\n"
+"function toggle(item) {\n"
+"    obj=document.getElementById(item);\n"
+"    visible=(obj.style.display!=\"none\" && obj.style.display!=\"\");\n"
+"    key=document.getElementById(\"x\" + item);\n"
+"    if (visible) {\n"
+"        obj.style.display=\"none\";\n"
+"        key.innerHTML=\"+\";\n"
+"    } else {\n"
+"        obj.style.display=\"block\";\n"
+"        key.innerHTML=\"-\";\n"
+"    }\n"
+"}\n"
+"function onMouseOver(obj) {\n"
+"    obj.style.background=\"lightblue\";\n"
+"}\n"
+"function onMouseOut(obj) {\n"
+"    obj.style.background=\"white\";\n"
+"}\n"
+"</script>\n"
+"<style type=\"text/css\">\n"
+"div { font-family: courier; font-size: 13 }\n"
+"div.parent { margin-left: 15; display: none }\n"
+"div.leaf { margin-left: 10 }\n"
+"div.header { margin-left: 10 }\n"
+"div.link { margin-left: 10; cursor: move }\n"
+"span.parent { padding-right: 10; }\n"
+"span.leaf { padding-right: 10; }\n"
+"a img { border: 0;}\n"
+"table.sortable th { border-width: 0px 1px 1px 1px; background-color: #ccc;}\n"
+"a { text-decoration: none; }\n"
+"a:hover { text-decoration: underline; }\n"
+"table.sortable th, table.sortable td { text-align: left;}"
+"table.sortable tr.odd td { background-color: #ddd; }\n"
+"table.sortable tr.even td { background-color: #fff; }\n"
+"</style>\n"
+"</head><body>\n\n";
+
+char *htmlFooter = "\n</body>\n</html>\n";
+char *profileSeparator =
+    "======================================================================";
+
+const char* tableHeader =
+    "<table class='sortable' id='%s'><tr>\n"
+    "<th>Method</th>\n"
+    "<th>Run 1 (us)</th>\n"
+    "<th>Run 2 (us)</th>\n"
+    "<th>Diff (us)</th>\n"
+    "<th>Diff (%%)</th>\n"
+    "<th>1: # calls</th>\n"
+    "<th>2: # calls</th>\n"
+    "</tr>\n";
+
+const char* tableHeaderMissing =
+    "<table class='sortable' id='%s'>\n"
+    "<th>Method</th>\n"
+    "<th>Exclusive</th>\n"
+    "<th>Inclusive</th>\n"
+    "<th># calls</th>\n";
+
+#define GRAPH_LABEL_VISITED 0x0001
+#define GRAPH_NODE_VISITED  0x0002
+
+/*
+ * Values from the header of the data file.
+ */
+typedef struct DataHeader {
+    unsigned int magic;
+    short version;
+    short offsetToData;
+    long long startWhen;
+    short recordSize;
+} DataHeader;
+
+/*
+ * Entry from the thread list.
+ */
+typedef struct ThreadEntry {
+    int         threadId;
+    const char* threadName;
+} ThreadEntry;
+
+struct MethodEntry;
+typedef struct TimedMethod {
+    struct TimedMethod *next;
+    uint64_t elapsedInclusive;
+    int numCalls;
+    struct MethodEntry *method;
+} TimedMethod;
+
+typedef struct ClassEntry {
+    const char *className;
+    uint64_t elapsedExclusive;
+    int numMethods;
+    struct MethodEntry **methods;       /* list of methods in this class */
+    int numCalls[2];                    /* 0=normal, 1=recursive */
+} ClassEntry;
+
+typedef struct UniqueMethodEntry {
+    uint64_t elapsedExclusive;
+    int numMethods;
+    struct MethodEntry **methods;       /* list of methods with same name */
+    int numCalls[2];                    /* 0=normal, 1=recursive */
+} UniqueMethodEntry;
+
+/*
+ * Entry from the method list.
+ */
+typedef struct MethodEntry {
+    unsigned int methodId;
+    const char* className;
+    const char* methodName;
+    const char* signature;
+    const char* fileName;
+    int lineNum;
+    uint64_t elapsedExclusive;
+    uint64_t elapsedInclusive;
+    uint64_t topExclusive;              /* non-recursive exclusive time */
+    uint64_t recursiveInclusive;
+    struct TimedMethod *parents[2];     /* 0=normal, 1=recursive */
+    struct TimedMethod *children[2];    /* 0=normal, 1=recursive */
+    int numCalls[2];                    /* 0=normal, 1=recursive */
+    int index;                  /* used after sorting to number methods */
+    int recursiveEntries;       /* number of entries on the stack */
+    int graphState;             /* used when graphing to see if this method has been visited before */
+} MethodEntry;
+
+/*
+ * The parsed contents of the key file.
+ */
+typedef struct DataKeys {
+    char*        fileData;      /* contents of the entire file */
+    long         fileLen;
+    int          numThreads;
+    ThreadEntry* threads;
+    int          numMethods;
+    MethodEntry* methods;       /* 2 extra methods: "toplevel" and "unknown" */
+} DataKeys;
+
+#define TOPLEVEL_INDEX 0
+#define UNKNOWN_INDEX 1
+
+typedef struct StackEntry {
+    MethodEntry *method;
+    uint64_t    entryTime;
+} StackEntry;
+
+typedef struct CallStack {
+    int         top;
+    StackEntry  calls[MAX_STACK_DEPTH];
+    uint64_t    lastEventTime;
+    uint64_t    threadStartTime;
+} CallStack;
+
+typedef struct DiffEntry {
+    MethodEntry* method1;
+    MethodEntry* method2;
+    int64_t differenceExclusive;
+    int64_t differenceInclusive;
+    double differenceExclusivePercentage;
+    double differenceInclusivePercentage;
+} DiffEntry;
+
+// Global options
+typedef struct Options {
+    const char* traceFileName;
+    const char* diffFileName;
+    const char* graphFileName;
+    int keepDotFile;
+    int dump;
+    int outputHtml;
+    const char* sortableUrl;
+    int threshold;
+} Options;
+
+typedef struct TraceData {
+    int numClasses;
+    ClassEntry *classes;
+    CallStack *stacks[MAX_THREADS];
+    int depth[MAX_THREADS];
+    int numUniqueMethods;
+    UniqueMethodEntry *uniqueMethods;
+} TraceData;
+
+static Options gOptions;
+
+/* Escapes characters in the source string that are html special entities.
+ * The escaped string is written to "dest" which must be large enough to
+ * hold the result.  A pointer to "dest" is returned.  The characters and
+ * their corresponding escape sequences are:
+ *  '<'  &lt;
+ *  '>'  &gt;
+ *  '&'  &amp;
+ */
+char *htmlEscape(const char *src, char *dest, int len)
+{
+    char *destStart = dest;
+
+    if (src == NULL)
+        return NULL;
+
+    int nbytes = 0;
+    while (*src) {
+        if (*src == '<') {
+            nbytes += 4;
+            if (nbytes >= len)
+                break;
+            *dest++ = '&';
+            *dest++ = 'l';
+            *dest++ = 't';
+            *dest++ = ';';
+        } else if (*src == '>') {
+            nbytes += 4;
+            if (nbytes >= len)
+                break;
+            *dest++ = '&';
+            *dest++ = 'g';
+            *dest++ = 't';
+            *dest++ = ';';
+        } else if (*src == '&') {
+            nbytes += 5;
+            if (nbytes >= len)
+                break;
+            *dest++ = '&';
+            *dest++ = 'a';
+            *dest++ = 'm';
+            *dest++ = 'p';
+            *dest++ = ';';
+        } else {
+            nbytes += 1;
+            if (nbytes >= len)
+                break;
+            *dest++ = *src;
+        }
+        src += 1;
+    }
+    if (nbytes >= len) {
+        fprintf(stderr, "htmlEscape(): buffer overflow\n");
+        exit(1);
+    }
+    *dest = 0;
+
+    return destStart;
+}
+
+/* Initializes a MethodEntry
+ */
+void initMethodEntry(MethodEntry *method, unsigned int methodId,
+                     const char *className, const char *methodName,
+                     const char *signature, const char* fileName,
+                     const char* lineNumStr)
+{
+    method->methodId = methodId;
+    method->className = className;
+    method->methodName = methodName;
+    method->signature = signature;
+    method->fileName = fileName;
+    method->lineNum = (lineNumStr != NULL) ? atoi(lineNumStr) : -1;
+    method->elapsedExclusive = 0;
+    method->elapsedInclusive = 0;
+    method->topExclusive = 0;
+    method->recursiveInclusive = 0;
+    method->parents[0] = NULL;
+    method->parents[1] = NULL;
+    method->children[0] = NULL;
+    method->children[1] = NULL;
+    method->numCalls[0] = 0;
+    method->numCalls[1] = 0;
+    method->index = 0;
+    method->recursiveEntries = 0;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * methods into decreasing order of exclusive elapsed time.
+ */
+int compareElapsedExclusive(const void *a, const void *b) {
+    uint64_t elapsed1, elapsed2;
+    int result;
+
+    const MethodEntry *methodA = *(const MethodEntry**)a;
+    const MethodEntry *methodB = *(const MethodEntry**)b;
+    elapsed1 = methodA->elapsedExclusive;
+    elapsed2 = methodB->elapsedExclusive;
+    if (elapsed1 < elapsed2)
+        return 1;
+    if (elapsed1 > elapsed2)
+        return -1;
+
+    /* If the elapsed times of two methods are equal, then sort them
+     * into alphabetical order.
+     */
+    result = strcmp(methodA->className, methodB->className);
+    if (result == 0) {
+        if (methodA->methodName == NULL || methodB->methodName == NULL) {
+            unsigned int idA = methodA->methodId;
+            unsigned int idB = methodB->methodId;
+            if (idA < idB)
+                return -1;
+            if (idA > idB)
+                return 1;
+            return 0;
+        }
+        result = strcmp(methodA->methodName, methodB->methodName);
+        if (result == 0)
+            result = strcmp(methodA->signature, methodB->signature);
+    }
+    return result;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * methods into decreasing order of inclusive elapsed time.
+ */
+int compareElapsedInclusive(const void *a, const void *b) {
+    const MethodEntry *methodA, *methodB;
+    uint64_t elapsed1, elapsed2;
+    int result;
+
+    methodA = *(MethodEntry const **)a;
+    methodB = *(MethodEntry const **)b;
+    elapsed1 = methodA->elapsedInclusive;
+    elapsed2 = methodB->elapsedInclusive;
+    if (elapsed1 < elapsed2)
+        return 1;
+    if (elapsed1 > elapsed2)
+        return -1;
+
+    /* If the elapsed times of two methods are equal, then sort them
+     * into alphabetical order.
+     */
+    result = strcmp(methodA->className, methodB->className);
+    if (result == 0) {
+        if (methodA->methodName == NULL || methodB->methodName == NULL) {
+            unsigned int idA = methodA->methodId;
+            unsigned int idB = methodB->methodId;
+            if (idA < idB)
+                return -1;
+            if (idA > idB)
+                return 1;
+            return 0;
+        }
+        result = strcmp(methodA->methodName, methodB->methodName);
+        if (result == 0)
+            result = strcmp(methodA->signature, methodB->signature);
+    }
+    return result;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * TimedMethods into decreasing order of inclusive elapsed time.
+ */
+int compareTimedMethod(const void *a, const void *b) {
+    const TimedMethod *timedA, *timedB;
+    uint64_t elapsed1, elapsed2;
+    int result;
+
+    timedA = (TimedMethod const *)a;
+    timedB = (TimedMethod const *)b;
+    elapsed1 = timedA->elapsedInclusive;
+    elapsed2 = timedB->elapsedInclusive;
+    if (elapsed1 < elapsed2)
+        return 1;
+    if (elapsed1 > elapsed2)
+        return -1;
+
+    /* If the elapsed times of two methods are equal, then sort them
+     * into alphabetical order.
+     */
+    MethodEntry *methodA = timedA->method;
+    MethodEntry *methodB = timedB->method;
+    result = strcmp(methodA->className, methodB->className);
+    if (result == 0) {
+        if (methodA->methodName == NULL || methodB->methodName == NULL) {
+            unsigned int idA = methodA->methodId;
+            unsigned int idB = methodB->methodId;
+            if (idA < idB)
+                return -1;
+            if (idA > idB)
+                return 1;
+            return 0;
+        }
+        result = strcmp(methodA->methodName, methodB->methodName);
+        if (result == 0)
+            result = strcmp(methodA->signature, methodB->signature);
+    }
+    return result;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * MethodEntry pointers into alphabetical order of class names.
+ */
+int compareClassNames(const void *a, const void *b) {
+    int result;
+
+    const MethodEntry *methodA = *(const MethodEntry**)a;
+    const MethodEntry *methodB = *(const MethodEntry**)b;
+    result = strcmp(methodA->className, methodB->className);
+    if (result == 0) {
+        unsigned int idA = methodA->methodId;
+        unsigned int idB = methodB->methodId;
+        if (idA < idB)
+            return -1;
+        if (idA > idB)
+            return 1;
+        return 0;
+    }
+    return result;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * classes into decreasing order of exclusive elapsed time.
+ */
+int compareClassExclusive(const void *a, const void *b) {
+    uint64_t elapsed1, elapsed2;
+    int result;
+
+    const ClassEntry *classA = *(const ClassEntry**)a;
+    const ClassEntry *classB = *(const ClassEntry**)b;
+    elapsed1 = classA->elapsedExclusive;
+    elapsed2 = classB->elapsedExclusive;
+    if (elapsed1 < elapsed2)
+        return 1;
+    if (elapsed1 > elapsed2)
+        return -1;
+
+    /* If the elapsed times of two classs are equal, then sort them
+     * into alphabetical order.
+     */
+    result = strcmp(classA->className, classB->className);
+    if (result == 0) {
+        /* Break ties with the first method id.  This is probably not
+         * needed.
+         */
+        unsigned int idA = classA->methods[0]->methodId;
+        unsigned int idB = classB->methods[0]->methodId;
+        if (idA < idB)
+            return -1;
+        if (idA > idB)
+            return 1;
+        return 0;
+    }
+    return result;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * MethodEntry pointers into alphabetical order by method name,
+ * then by class name.
+ */
+int compareMethodNames(const void *a, const void *b) {
+    int result;
+
+    const MethodEntry *methodA = *(const MethodEntry**)a;
+    const MethodEntry *methodB = *(const MethodEntry**)b;
+    if (methodA->methodName == NULL || methodB->methodName == NULL) {
+        return compareClassNames(a, b);
+    }
+    result = strcmp(methodA->methodName, methodB->methodName);
+    if (result == 0) {
+        result = strcmp(methodA->className, methodB->className);
+        if (result == 0) {
+            unsigned int idA = methodA->methodId;
+            unsigned int idB = methodB->methodId;
+            if (idA < idB)
+                return -1;
+            if (idA > idB)
+                return 1;
+            return 0;
+        }
+    }
+    return result;
+}
+
+/*
+ * This comparison function is called from qsort() to sort
+ * unique methods into decreasing order of exclusive elapsed time.
+ */
+int compareUniqueExclusive(const void *a, const void *b) {
+    uint64_t elapsed1, elapsed2;
+    int result;
+
+    const UniqueMethodEntry *uniqueA = *(const UniqueMethodEntry**)a;
+    const UniqueMethodEntry *uniqueB = *(const UniqueMethodEntry**)b;
+    elapsed1 = uniqueA->elapsedExclusive;
+    elapsed2 = uniqueB->elapsedExclusive;
+    if (elapsed1 < elapsed2)
+        return 1;
+    if (elapsed1 > elapsed2)
+        return -1;
+
+    /* If the elapsed times of two methods are equal, then sort them
+     * into alphabetical order.
+     */
+    result = strcmp(uniqueA->methods[0]->className,
+                    uniqueB->methods[0]->className);
+    if (result == 0) {
+        unsigned int idA = uniqueA->methods[0]->methodId;
+        unsigned int idB = uniqueB->methods[0]->methodId;
+        if (idA < idB)
+            return -1;
+        if (idA > idB)
+            return 1;
+        return 0;
+    }
+    return result;
+}
+
+/*
+ * Free a DataKeys struct.
+ */
+void freeDataKeys(DataKeys* pKeys)
+{
+    if (pKeys == NULL)
+        return;
+
+    free(pKeys->fileData);
+    free(pKeys->threads);
+    free(pKeys->methods);
+    free(pKeys);
+}
+
+/*
+ * Find the offset to the next occurrence of the specified character.
+ *
+ * "data" should point somewhere within the current line.  "len" is the
+ * number of bytes left in the buffer.
+ *
+ * Returns -1 if we hit the end of the buffer.
+ */
+int findNextChar(const char* data, int len, char lookFor)
+{
+    const char* start = data;
+
+    while (len > 0) {
+        if (*data == lookFor)
+            return data - start;
+
+        data++;
+        len--;
+    }
+
+    return -1;
+}
+
+/*
+ * Count the number of lines until the next token.
+ *
+ * Returns -1 if none found before EOF.
+ */
+int countLinesToToken(const char* data, int len)
+{
+    int count = 0;
+    int next;
+
+    while (*data != TOKEN_CHAR) {
+        next = findNextChar(data, len, '\n');
+        if (next < 0)
+            return -1;
+        count++;
+        data += next+1;
+        len -= next+1;
+    }
+
+    return count;
+}
+
+/*
+ * Make sure we're at the start of the right section.
+ *
+ * Returns the length of the token line, or -1 if something is wrong.
+ */
+int checkToken(const char* data, int len, const char* cmpStr)
+{
+    int cmpLen = strlen(cmpStr);
+    int next;
+
+    if (*data != TOKEN_CHAR) {
+        fprintf(stderr,
+            "ERROR: not at start of %s (found '%.10s')\n", cmpStr, data);
+        return -1;
+    }
+
+    next = findNextChar(data, len, '\n');
+    if (next < cmpLen+1)
+        return -1;
+
+    if (strncmp(data+1, cmpStr, cmpLen) != 0) {
+        fprintf(stderr, "ERROR: '%s' not found (got '%.7s')\n", cmpStr, data+1);
+        return -1;
+    }
+
+    return next+1;
+}
+
+/*
+ * Parse the "*version" section.
+ */
+long parseVersion(DataKeys* pKeys, long offset, int verbose)
+{
+    char* data;
+    char* dataEnd;
+    int i, count, next;
+
+    if (offset < 0)
+        return -1;
+
+    data = pKeys->fileData + offset;
+    dataEnd = pKeys->fileData + pKeys->fileLen;
+    next = checkToken(data, dataEnd - data, "version");
+    if (next <= 0)
+        return -1;
+
+    data += next;
+
+    /*
+     * Count the number of items in the "version" section.
+     */
+    count = countLinesToToken(data, dataEnd - data);
+    if (count <= 0) {
+        fprintf(stderr,
+            "ERROR: failed while reading version (found %d)\n", count);
+        return -1;
+    }
+
+    /* find the end of the line */
+    next = findNextChar(data, dataEnd - data, '\n');
+    if (next < 0)
+        return -1;
+
+    data[next] = '\0';
+    versionNumber = strtoul(data, NULL, 0);
+    if (verbose)
+        printf("VERSION: %d\n", versionNumber);
+
+    data += next+1;
+
+    /* skip over the rest of the stuff, which is "name=value" lines */
+    for (i = 1; i < count; i++) {
+        next = findNextChar(data, dataEnd - data, '\n');
+        if (next < 0)
+            return -1;
+        //data[next] = '\0';
+        //printf("IGNORING: '%s'\n", data);
+        data += next+1;
+    }
+
+    return data - pKeys->fileData;
+}
+
+/*
+ * Parse the "*threads" section.
+ */
+long parseThreads(DataKeys* pKeys, long offset)
+{
+    char* data;
+    char* dataEnd;
+    int i, next, tab, count;
+
+    if (offset < 0)
+        return -1;
+
+    data = pKeys->fileData + offset;
+    dataEnd = pKeys->fileData + pKeys->fileLen;
+    next = checkToken(data, dataEnd - data, "threads");
+
+    data += next;
+
+    /*
+     * Count the number of thread entries (one per line).
+     */
+    count = countLinesToToken(data, dataEnd - data);
+    if (count <= 0) {
+        fprintf(stderr,
+            "ERROR: failed while reading threads (found %d)\n", count);
+        return -1;
+    }
+
+    //printf("+++ found %d threads\n", count);
+    pKeys->threads = (ThreadEntry*) malloc(sizeof(ThreadEntry) * count);
+    if (pKeys->threads == NULL)
+        return -1;
+
+    /*
+     * Extract all entries.
+     */
+    for (i = 0; i < count; i++) {
+        next = findNextChar(data, dataEnd - data, '\n');
+        assert(next > 0);
+        data[next] = '\0';
+
+        tab = findNextChar(data, next, '\t');
+        data[tab] = '\0';
+
+        pKeys->threads[i].threadId = atoi(data);
+        pKeys->threads[i].threadName = data + tab +1;
+
+        data += next+1;
+    }
+
+    pKeys->numThreads = count;
+    return data - pKeys->fileData;
+}
+
+/*
+ * Parse the "*methods" section.
+ */
+long parseMethods(DataKeys* pKeys, long offset)
+{
+    char* data;
+    char* dataEnd;
+    int i, next, count;
+
+    if (offset < 0)
+        return -1;
+
+    data = pKeys->fileData + offset;
+    dataEnd = pKeys->fileData + pKeys->fileLen;
+    next = checkToken(data, dataEnd - data, "methods");
+    if (next < 0)
+        return -1;
+
+    data += next;
+
+    /*
+     * Count the number of method entries (one per line).
+     */
+    count = countLinesToToken(data, dataEnd - data);
+    if (count <= 0) {
+        fprintf(stderr,
+            "ERROR: failed while reading methods (found %d)\n", count);
+        return -1;
+    }
+
+    /* Reserve an extra method at location 0 for the "toplevel" method,
+     * and another extra method for all other "unknown" methods.
+     */
+    count += 2;
+    pKeys->methods = (MethodEntry*) malloc(sizeof(MethodEntry) * count);
+    if (pKeys->methods == NULL)
+        return -1;
+    initMethodEntry(&pKeys->methods[TOPLEVEL_INDEX], 0, "(toplevel)",
+        NULL, NULL, NULL, NULL);
+    initMethodEntry(&pKeys->methods[UNKNOWN_INDEX], 0, "(unknown)",
+        NULL, NULL, NULL, NULL);
+
+    /*
+     * Extract all entries, starting with index 2.
+     */
+    for (i = UNKNOWN_INDEX + 1; i < count; i++) {
+        int tab1, tab2, tab3, tab4, tab5;
+        unsigned int id;
+        char* endptr;
+
+        next = findNextChar(data, dataEnd - data, '\n');
+        assert(next > 0);
+        data[next] = '\0';
+
+        tab1 = findNextChar(data, next, '\t');
+        tab2 = findNextChar(data+(tab1+1), next-(tab1+1), '\t');
+        tab3 = findNextChar(data+(tab1+tab2+2), next-(tab1+tab2+2), '\t');
+        tab4 = findNextChar(data+(tab1+tab2+tab3+3),
+                            next-(tab1+tab2+tab3+3), '\t');
+        tab5 = findNextChar(data+(tab1+tab2+tab3+tab4+4),
+                            next-(tab1+tab2+tab3+tab4+4), '\t');
+        if (tab1 < 0) {
+            fprintf(stderr, "ERROR: missing field on method line: '%s'\n",
+                    data);
+            return -1;
+        }
+        assert(data[tab1] == '\t');
+        data[tab1] = '\0';
+
+        id = strtoul(data, &endptr, 0);
+        if (*endptr != '\0') {
+            fprintf(stderr, "ERROR: bad method ID '%s'\n", data);
+            return -1;
+        }
+
+        // Allow files that specify just a function name, instead of requiring
+        // "class \t method \t signature"
+        if (tab2 > 0 && tab3 > 0) {
+            tab2 += tab1+1;
+            tab3 += tab2+1;
+            assert(data[tab2] == '\t');
+            assert(data[tab3] == '\t');
+            data[tab2] = data[tab3] = '\0';
+
+            // This is starting to get awkward.  Allow filename and line #.
+            if (tab4 > 0 && tab5 > 0) {
+                tab4 += tab3+1;
+                tab5 += tab4+1;
+
+                assert(data[tab4] == '\t');
+                assert(data[tab5] == '\t');
+                data[tab4] = data[tab5] = '\0';
+
+                initMethodEntry(&pKeys->methods[i], id, data + tab1 +1,
+                        data + tab2 +1, data + tab3 +1, data + tab4 +1,
+                        data + tab5 +1);
+            } else {
+                initMethodEntry(&pKeys->methods[i], id, data + tab1 +1,
+                        data + tab2 +1, data + tab3 +1, NULL, NULL);
+            }
+        } else {
+            initMethodEntry(&pKeys->methods[i], id, data + tab1 +1,
+                NULL, NULL, NULL, NULL);
+        }
+
+        data += next+1;
+    }
+
+    pKeys->numMethods = count;
+    return data - pKeys->fileData;
+}
+
+/*
+ * Parse the "*end" section.
+ */
+long parseEnd(DataKeys* pKeys, long offset)
+{
+    char* data;
+    char* dataEnd;
+    int next;
+
+    if (offset < 0)
+        return -1;
+
+    data = pKeys->fileData + offset;
+    dataEnd = pKeys->fileData + pKeys->fileLen;
+    next = checkToken(data, dataEnd - data, "end");
+    if (next < 0)
+        return -1;
+
+    data += next;
+
+    return data - pKeys->fileData;
+}
+
+/*
+ * Sort the thread list entries.
+ */
+static int compareThreads(const void* thread1, const void* thread2)
+{
+    return ((const ThreadEntry*) thread1)->threadId -
+            ((const ThreadEntry*) thread2)->threadId;
+}
+
+void sortThreadList(DataKeys* pKeys)
+{
+    qsort(pKeys->threads, pKeys->numThreads, sizeof(pKeys->threads[0]),
+        compareThreads);
+}
+
+/*
+ * Sort the method list entries.
+ */
+static int compareMethods(const void* meth1, const void* meth2)
+{
+    unsigned int id1, id2;
+
+    id1 = ((const MethodEntry*) meth1)->methodId;
+    id2 = ((const MethodEntry*) meth2)->methodId;
+    if (id1 < id2)
+        return -1;
+    if (id1 > id2)
+        return 1;
+    return 0;
+}
+
+void sortMethodList(DataKeys* pKeys)
+{
+    qsort(pKeys->methods, pKeys->numMethods, sizeof(MethodEntry),
+        compareMethods);
+}
+
+/*
+ * Parse the key section, and return a copy of the parsed contents.
+ */
+DataKeys* parseKeys(FILE *fp, int verbose)
+{
+    DataKeys* pKeys = NULL;
+    long offset;
+    int i;
+
+    pKeys = (DataKeys*) calloc(1, sizeof(DataKeys));
+    if (pKeys == NULL)
+        goto fail;
+
+    /*
+     * We load the entire file into memory.  We do this, rather than memory-
+     * mapping it, because we want to change some whitespace to NULs.
+     */
+    if (fseek(fp, 0L, SEEK_END) != 0) {
+        perror("fseek");
+        goto fail;
+    }
+    pKeys->fileLen = ftell(fp);
+    if (pKeys->fileLen == 0) {
+        fprintf(stderr, "Key file is empty.\n");
+        goto fail;
+    }
+    rewind(fp);
+
+    pKeys->fileData = (char*) malloc(pKeys->fileLen);
+    if (pKeys->fileData == NULL) {
+        fprintf(stderr, "ERROR: unable to alloc %ld bytes\n", pKeys->fileLen);
+        goto fail;
+    }
+
+    if (fread(pKeys->fileData, 1, pKeys->fileLen, fp) != (size_t) pKeys->fileLen)
+    {
+        fprintf(stderr, "ERROR: unable to read %ld bytes from trace file\n",
+            pKeys->fileLen);
+        goto fail;
+    }
+
+    offset = 0;
+
+    offset = parseVersion(pKeys, offset, verbose);
+    offset = parseThreads(pKeys, offset);
+    offset = parseMethods(pKeys, offset);
+    offset = parseEnd(pKeys, offset);
+    if (offset < 0)
+        goto fail;
+
+    /* Reduce our allocation now that we know where the end of the key section is. */
+    pKeys->fileData = (char *)realloc(pKeys->fileData, offset);
+    pKeys->fileLen = offset;
+    /* Leave fp pointing to the beginning of the data section. */
+    fseek(fp, offset, SEEK_SET);
+
+    sortThreadList(pKeys);
+    sortMethodList(pKeys);
+
+    /*
+     * Dump list of threads.
+     */
+    if (verbose) {
+        printf("Threads (%d):\n", pKeys->numThreads);
+        for (i = 0; i < pKeys->numThreads; i++) {
+            printf("%2d %s\n",
+                   pKeys->threads[i].threadId, pKeys->threads[i].threadName);
+        }
+    }
+
+#if 0
+    /*
+     * Dump list of methods.
+     */
+    if (verbose) {
+        printf("Methods (%d):\n", pKeys->numMethods);
+        for (i = 0; i < pKeys->numMethods; i++) {
+            printf("0x%08x %s : %s : %s\n",
+                   pKeys->methods[i].methodId, pKeys->methods[i].className,
+                   pKeys->methods[i].methodName, pKeys->methods[i].signature);
+        }
+    }
+#endif
+
+    return pKeys;
+
+fail:
+    freeDataKeys(pKeys);
+    return NULL;
+}
+
+
+/*
+ * Read values from the binary data file.
+ */
+
+/* Make the return value "unsigned int" instead of "unsigned short" so that
+ * we can detect EOF.
+ */
+unsigned int read2LE(FILE* fp)
+{
+    unsigned int val;
+
+    val = getc(fp);
+    val |= getc(fp) << 8;
+    return val;
+}
+unsigned int read4LE(FILE* fp)
+{
+    unsigned int val;
+
+    val = getc(fp);
+    val |= getc(fp) << 8;
+    val |= getc(fp) << 16;
+    val |= getc(fp) << 24;
+    return val;
+}
+unsigned long long read8LE(FILE* fp)
+{
+    unsigned long long val;
+
+    val = getc(fp);
+    val |= (unsigned long long) getc(fp) << 8;
+    val |= (unsigned long long) getc(fp) << 16;
+    val |= (unsigned long long) getc(fp) << 24;
+    val |= (unsigned long long) getc(fp) << 32;
+    val |= (unsigned long long) getc(fp) << 40;
+    val |= (unsigned long long) getc(fp) << 48;
+    val |= (unsigned long long) getc(fp) << 56;
+    return val;
+}
+
+/*
+ * Parse the header of the data section.
+ *
+ * Returns with the file positioned at the start of the record data.
+ */
+int parseDataHeader(FILE *fp, DataHeader* pHeader)
+{
+    int bytesToRead;
+
+    pHeader->magic = read4LE(fp);
+    pHeader->version = read2LE(fp);
+    pHeader->offsetToData = read2LE(fp);
+    pHeader->startWhen = read8LE(fp);
+    bytesToRead = pHeader->offsetToData - 16;
+    if (pHeader->version == 1) {
+        pHeader->recordSize = 9;
+    } else if (pHeader->version == 2) {
+        pHeader->recordSize = 10;
+    } else if (pHeader->version == 3) {
+        pHeader->recordSize = read2LE(fp);
+        bytesToRead -= 2;
+    } else {
+        fprintf(stderr, "Unsupported trace file version: %d\n", pHeader->version);
+        return -1;
+    }
+
+    if (fseek(fp, bytesToRead, SEEK_CUR) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Look up a method by it's method ID.
+ *
+ * Returns NULL if no matching method was found.
+ */
+MethodEntry* lookupMethod(DataKeys* pKeys, unsigned int methodId)
+{
+    int hi, lo, mid;
+    unsigned int id;
+
+    lo = 0;
+    hi = pKeys->numMethods - 1;
+
+    while (hi >= lo) {
+        mid = (hi + lo) / 2;
+
+        id = pKeys->methods[mid].methodId;
+        if (id == methodId)           /* match */
+            return &pKeys->methods[mid];
+        else if (id < methodId)       /* too low */
+            lo = mid + 1;
+        else                          /* too high */
+            hi = mid - 1;
+    }
+
+    return NULL;
+}
+
+/*
+ * Reads the next data record, and assigns the data values to threadId,
+ * methodVal and elapsedTime.  On end-of-file, the threadId, methodVal,
+ * and elapsedTime are unchanged.  Returns 1 on end-of-file, otherwise
+ * returns 0.
+ */
+int readDataRecord(FILE *dataFp, DataHeader* dataHeader,
+        int *threadId, unsigned int *methodVal, uint64_t *elapsedTime)
+{
+    int id;
+    int bytesToRead;
+
+    bytesToRead = dataHeader->recordSize;
+    if (dataHeader->version == 1) {
+        id = getc(dataFp);
+        bytesToRead -= 1;
+    } else {
+        id = read2LE(dataFp);
+        bytesToRead -= 2;
+    }
+    if (id == EOF)
+        return 1;
+    *threadId = id;
+
+    *methodVal = read4LE(dataFp);
+    *elapsedTime = read4LE(dataFp);
+    bytesToRead -= 8;
+
+    while (bytesToRead-- > 0) {
+        getc(dataFp);
+    }
+
+    if (feof(dataFp)) {
+        fprintf(stderr, "WARNING: hit EOF mid-record\n");
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * Read the key file and use it to produce formatted output from the
+ * data file.
+ */
+void dumpTrace()
+{
+    static const char* actionStr[] = { "ent", "xit", "unr", "???" };
+    MethodEntry bogusMethod = { 0, "???", "???", "???", "???", -1, 0, 0, 0, 0,
+                                {NULL, NULL}, {NULL, NULL}, {0, 0}, 0, 0, -1 };
+    char bogusBuf[80];
+    char spaces[MAX_STACK_DEPTH+1];
+    FILE* dataFp = NULL;
+    DataHeader dataHeader;
+    DataKeys* pKeys = NULL;
+    int i;
+    TraceData traceData;
+
+    //printf("Dumping '%s' '%s'\n", dataFileName, keyFileName);
+
+    memset(spaces, '.', MAX_STACK_DEPTH);
+    spaces[MAX_STACK_DEPTH] = '\0';
+
+    for (i = 0; i < MAX_THREADS; i++)
+        traceData.depth[i] = 2;       // adjust for return from start function
+
+    dataFp = fopen(gOptions.traceFileName, "r");
+    if (dataFp == NULL)
+        goto bail;
+
+    if ((pKeys = parseKeys(dataFp, 1)) == NULL)
+        goto bail;
+
+    if (parseDataHeader(dataFp, &dataHeader) < 0)
+        goto bail;
+
+    printf("Trace (threadID action usecs class.method signature):\n");
+
+    while (1) {
+        MethodEntry* method;
+        int threadId;
+        unsigned int methodVal;
+        uint64_t elapsedTime;
+        int action, printDepth;
+        unsigned int methodId, lastEnter = 0;
+        int mismatch = 0;
+        char depthNote;
+
+        /*
+         * Extract values from file.
+         */
+        if (readDataRecord(dataFp, &dataHeader, &threadId, &methodVal, &elapsedTime))
+            break;
+
+        action = METHOD_ACTION(methodVal);
+        methodId = METHOD_ID(methodVal);
+
+        /*
+         * Generate a line of output.
+         */
+        if (action == METHOD_TRACE_ENTER) {
+            traceData.depth[threadId]++;
+            lastEnter = methodId;
+        } else {
+            /* quick test for mismatched adjacent enter/exit */
+            if (lastEnter != 0 && lastEnter != methodId)
+                mismatch = 1;
+        }
+
+        printDepth = traceData.depth[threadId];
+        depthNote = ' ';
+        if (printDepth < 0) {
+            printDepth = 0;
+            depthNote = '-';
+        } else if (printDepth > MAX_STACK_DEPTH) {
+            printDepth = MAX_STACK_DEPTH;
+            depthNote = '+';
+        }
+
+        method = lookupMethod(pKeys, methodId);
+        if (method == NULL) {
+            method = &bogusMethod;
+            sprintf(bogusBuf, "methodId: %#x", methodId);
+            method->signature = bogusBuf;
+        }
+
+	if (method->methodName) {
+	    printf("%2d %s%c %8lld%c%s%s.%s %s\n", threadId,
+		   actionStr[action], mismatch ? '!' : ' ',
+		   elapsedTime, depthNote,
+		   spaces + (MAX_STACK_DEPTH - printDepth),
+		   method->className, method->methodName, method->signature);
+	} else {
+	    printf("%2d %s%c %8lld%c%s%s\n", threadId,
+		   actionStr[action], mismatch ? '!' : ' ',
+		   elapsedTime, depthNote,
+		   spaces + (MAX_STACK_DEPTH - printDepth),
+		   method->className);
+	}
+
+        if (action != METHOD_TRACE_ENTER) {
+            traceData.depth[threadId]--;  /* METHOD_TRACE_EXIT or METHOD_TRACE_UNROLL */
+            lastEnter = 0;
+        }
+
+        mismatch = 0;
+    }
+
+bail:
+    if (dataFp != NULL)
+        fclose(dataFp);
+    if (pKeys != NULL)
+        freeDataKeys(pKeys);
+}
+
+/* This routine adds the given time to the parent and child methods.
+ * This is called when the child routine exits, after the child has
+ * been popped from the stack.  The elapsedTime parameter is the
+ * duration of the child routine, including time spent in called routines.
+ */
+void addInclusiveTime(MethodEntry *parent, MethodEntry *child,
+                      uint64_t elapsedTime)
+{
+    TimedMethod *pTimed;
+
+#if 0
+    bool verbose = false;
+    if (strcmp(child->className, debugClassName) == 0)
+        verbose = true;
+#endif
+
+    int childIsRecursive = (child->recursiveEntries > 0);
+    int parentIsRecursive = (parent->recursiveEntries > 1);
+
+    if (child->recursiveEntries == 0) {
+        child->elapsedInclusive += elapsedTime;
+    } else if (child->recursiveEntries == 1) {
+        child->recursiveInclusive += elapsedTime;
+    }
+    child->numCalls[childIsRecursive] += 1;
+
+#if 0
+    if (verbose) {
+        fprintf(stderr,
+                "%s %d elapsedTime: %lld eI: %lld, rI: %lld\n",
+                child->className, child->recursiveEntries,
+                elapsedTime, child->elapsedInclusive,
+                child->recursiveInclusive);
+    }
+#endif
+
+    /* Find the child method in the parent */
+    TimedMethod *children = parent->children[parentIsRecursive];
+    for (pTimed = children; pTimed; pTimed = pTimed->next) {
+        if (pTimed->method == child) {
+            pTimed->elapsedInclusive += elapsedTime;
+            pTimed->numCalls += 1;
+            break;
+        }
+    }
+    if (pTimed == NULL) {
+        /* Allocate a new TimedMethod */
+        pTimed = (TimedMethod *) malloc(sizeof(TimedMethod));
+        pTimed->elapsedInclusive = elapsedTime;
+        pTimed->numCalls = 1;
+        pTimed->method = child;
+
+        /* Add it to the front of the list */
+        pTimed->next = children;
+        parent->children[parentIsRecursive] = pTimed;
+    }
+
+    /* Find the parent method in the child */
+    TimedMethod *parents = child->parents[childIsRecursive];
+    for (pTimed = parents; pTimed; pTimed = pTimed->next) {
+        if (pTimed->method == parent) {
+            pTimed->elapsedInclusive += elapsedTime;
+            pTimed->numCalls += 1;
+            break;
+        }
+    }
+    if (pTimed == NULL) {
+        /* Allocate a new TimedMethod */
+        pTimed = (TimedMethod *) malloc(sizeof(TimedMethod));
+        pTimed->elapsedInclusive = elapsedTime;
+        pTimed->numCalls = 1;
+        pTimed->method = parent;
+
+        /* Add it to the front of the list */
+        pTimed->next = parents;
+        child->parents[childIsRecursive] = pTimed;
+    }
+
+#if 0
+    if (verbose) {
+        fprintf(stderr,
+                "  %s %d eI: %lld\n",
+                parent->className, parent->recursiveEntries,
+                pTimed->elapsedInclusive);
+    }
+#endif
+}
+
+/* Sorts a linked list and returns a newly allocated array containing
+ * the sorted entries.
+ */
+TimedMethod *sortTimedMethodList(TimedMethod *list, int *num)
+{
+    int ii;
+    TimedMethod *pTimed, *sorted;
+
+    /* Count the elements */
+    int num_entries = 0;
+    for (pTimed = list; pTimed; pTimed = pTimed->next)
+        num_entries += 1;
+    *num = num_entries;
+    if (num_entries == 0)
+        return NULL;
+
+    /* Copy all the list elements to a new array and sort them */
+    sorted = (TimedMethod *) malloc(sizeof(TimedMethod) * num_entries);
+    for (ii = 0, pTimed = list; pTimed; pTimed = pTimed->next, ++ii)
+        memcpy(&sorted[ii], pTimed, sizeof(TimedMethod));
+    qsort(sorted, num_entries, sizeof(TimedMethod), compareTimedMethod);
+
+    /* Fix up the "next" pointers so that they work. */
+    for (ii = 0; ii < num_entries - 1; ++ii)
+        sorted[ii].next = &sorted[ii + 1];
+    sorted[num_entries - 1].next = NULL;
+
+    return sorted;
+}
+
+/* Define flag values for printInclusiveMethod() */
+static const int kIsRecursive = 1;
+
+/* This prints the inclusive stats for all the parents or children of a
+ * method, depending on the list that is passed in.
+ */
+void printInclusiveMethod(MethodEntry *method, TimedMethod *list, int numCalls,
+                          int flags)
+{
+    int num;
+    TimedMethod *pTimed;
+    char buf[80];
+    char *anchor_close;
+    char *spaces = "      ";    /* 6 spaces */
+    int num_spaces = strlen(spaces);
+    char *space_ptr = &spaces[num_spaces];
+    char *className, *methodName, *signature;
+    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
+    char signatureBuf[HTML_BUFSIZE];
+
+    anchor_close = "";
+    if (gOptions.outputHtml)
+        anchor_close = "</a>";
+
+    TimedMethod *sorted = sortTimedMethodList(list,  &num);
+    double methodTotal = method->elapsedInclusive;
+    for (pTimed = sorted; pTimed; pTimed = pTimed->next) {
+        MethodEntry *relative = pTimed->method;
+        className = (char*)(relative->className);
+        methodName = (char*)(relative->methodName);
+        signature = (char*)(relative->signature);
+        double per = 100.0 * pTimed->elapsedInclusive / methodTotal;
+        sprintf(buf, "[%d]", relative->index);
+        if (gOptions.outputHtml) {
+            int len = strlen(buf);
+            if (len > num_spaces)
+                len = num_spaces;
+            sprintf(buf, "<a href=\"#m%d\">[%d]",
+                    relative->index, relative->index);
+            space_ptr = &spaces[len];
+            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
+            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
+            signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
+        }
+        int nCalls = numCalls;
+        if (nCalls == 0)
+            nCalls = relative->numCalls[0] + relative->numCalls[1];
+        if (relative->methodName) {
+            if (flags & kIsRecursive) {
+                // Don't display percentages for recursive functions
+                printf("%6s %5s   %6s %s%6s%s %6d/%-6d %9llu %s.%s %s\n",
+                       "", "", "",
+                       space_ptr, buf, anchor_close,
+                       pTimed->numCalls, nCalls,
+                       pTimed->elapsedInclusive,
+                       className, methodName, signature);
+            } else {
+                printf("%6s %5s   %5.1f%% %s%6s%s %6d/%-6d %9llu %s.%s %s\n",
+                       "", "", per,
+                       space_ptr, buf, anchor_close,
+                       pTimed->numCalls, nCalls,
+                       pTimed->elapsedInclusive,
+                       className, methodName, signature);
+            }
+        } else {
+            if (flags & kIsRecursive) {
+                // Don't display percentages for recursive functions
+                printf("%6s %5s   %6s %s%6s%s %6d/%-6d %9llu %s\n",
+                       "", "", "",
+                       space_ptr, buf, anchor_close,
+                       pTimed->numCalls, nCalls,
+                       pTimed->elapsedInclusive,
+                       className);
+            } else {
+                printf("%6s %5s   %5.1f%% %s%6s%s %6d/%-6d %9llu %s\n",
+                       "", "", per,
+                       space_ptr, buf, anchor_close,
+                       pTimed->numCalls, nCalls,
+                       pTimed->elapsedInclusive,
+                       className);
+            }
+        }
+    }
+}
+
+void countRecursiveEntries(CallStack *pStack, int top, MethodEntry *method)
+{
+    int ii;
+
+    method->recursiveEntries = 0;
+    for (ii = 0; ii < top; ++ii) {
+        if (pStack->calls[ii].method == method)
+            method->recursiveEntries += 1;
+    }
+}
+
+void stackDump(CallStack *pStack, int top)
+{
+    int ii;
+
+    for (ii = 0; ii < top; ++ii) {
+        MethodEntry *method = pStack->calls[ii].method;
+        uint64_t entryTime = pStack->calls[ii].entryTime;
+        if (method->methodName) {
+            fprintf(stderr, "  %2d: %8llu %s.%s %s\n", ii, entryTime,
+                   method->className, method->methodName, method->signature);
+        } else {
+            fprintf(stderr, "  %2d: %8llu %s\n", ii, entryTime, method->className);
+        }
+    }
+}
+
+void outputTableOfContents()
+{
+    printf("<a name=\"contents\"></a>\n");
+    printf("<h2>Table of Contents</h2>\n");
+    printf("<ul>\n");
+    printf("  <li><a href=\"#exclusive\">Exclusive profile</a></li>\n");
+    printf("  <li><a href=\"#inclusive\">Inclusive profile</a></li>\n");
+    printf("  <li><a href=\"#class\">Class/method profile</a></li>\n");
+    printf("  <li><a href=\"#method\">Method/class profile</a></li>\n");
+    printf("</ul>\n\n");
+}
+
+void outputNavigationBar()
+{
+    printf("<a href=\"#contents\">[Top]</a>\n");
+    printf("<a href=\"#exclusive\">[Exclusive]</a>\n");
+    printf("<a href=\"#inclusive\">[Inclusive]</a>\n");
+    printf("<a href=\"#class\">[Class]</a>\n");
+    printf("<a href=\"#method\">[Method]</a>\n");
+    printf("<br><br>\n");
+}
+
+void printExclusiveProfile(MethodEntry **pMethods, int numMethods,
+                           uint64_t sumThreadTime)
+{
+    int ii;
+    MethodEntry* method;
+    double total, sum, per, sum_per;
+    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
+    char signatureBuf[HTML_BUFSIZE];
+    char anchor_buf[80];
+    char *anchor_close = "";
+
+    total = sumThreadTime;
+    anchor_buf[0] = 0;
+    if (gOptions.outputHtml) {
+        anchor_close = "</a>";
+        printf("<a name=\"exclusive\"></a>\n");
+        printf("<hr>\n");
+        outputNavigationBar();
+    } else {
+        printf("\n%s\n", profileSeparator);
+    }
+
+    /* First, sort the methods into decreasing order of inclusive
+     * elapsed time so that we can assign the method indices.
+     */
+    qsort(pMethods, numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
+
+    for (ii = 0; ii < numMethods; ++ii)
+        pMethods[ii]->index = ii;
+
+    /* Sort the methods into decreasing order of exclusive elapsed time.
+     */
+    qsort(pMethods, numMethods, sizeof(MethodEntry*),
+          compareElapsedExclusive);
+
+    printf("Total cycles: %llu\n\n", sumThreadTime);
+    if (gOptions.outputHtml) {
+        printf("<br><br>\n");
+    }
+    printf("Exclusive elapsed times for each method, not including time spent in\n");
+    printf("children, sorted by exclusive time.\n\n");
+    if (gOptions.outputHtml) {
+        printf("<br><br>\n<pre>\n");
+    }
+
+    printf("    Usecs  self %%  sum %%  Method\n");
+    sum = 0;
+
+    for (ii = 0; ii < numMethods; ++ii) {
+        char *className, *methodName, *signature;
+
+        method = pMethods[ii];
+        /* Don't show methods with zero cycles */
+        if (method->elapsedExclusive == 0)
+            break;
+        className = (char*)(method->className);
+        methodName = (char*)(method->methodName);
+        signature = (char*)(method->signature);
+        sum += method->elapsedExclusive;
+        per = 100.0 * method->elapsedExclusive / total;
+        sum_per = 100.0 * sum / total;
+        if (gOptions.outputHtml) {
+            sprintf(anchor_buf, "<a href=\"#m%d\">", method->index);
+            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
+            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
+            signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
+        }
+        if (method->methodName) {
+            printf("%9llu  %6.2f %6.2f  %s[%d]%s %s.%s %s\n",
+                   method->elapsedExclusive, per, sum_per,
+                   anchor_buf, method->index, anchor_close,
+                   className, methodName, signature);
+        } else {
+            printf("%9llu  %6.2f %6.2f  %s[%d]%s %s\n",
+                   method->elapsedExclusive, per, sum_per,
+                   anchor_buf, method->index, anchor_close,
+                   className);
+        }
+    }
+    if (gOptions.outputHtml) {
+        printf("</pre>\n");
+    }
+}
+
+/* check to make sure that the child method meets the threshold of the parent */
+int checkThreshold(MethodEntry* parent, MethodEntry* child)
+{
+    double parentTime = parent->elapsedInclusive;
+    double childTime = child->elapsedInclusive;
+    int64_t percentage = (childTime / parentTime) * 100.0;
+    return (percentage < gOptions.threshold) ? 0 : 1;
+}
+
+void createLabels(FILE* file, MethodEntry* method)
+{
+    fprintf(file, "node%d[label = \"[%d] %s.%s (%llu, %llu, %d)\"]\n",
+             method->index, method->index, method->className, method->methodName,
+             method->elapsedInclusive / 1000,
+             method->elapsedExclusive / 1000,
+             method->numCalls[0]);
+
+    method->graphState = GRAPH_LABEL_VISITED;
+
+    TimedMethod* child;
+    for (child = method->children[0] ; child ; child = child->next) {
+        MethodEntry* childMethod = child->method;
+
+        if ((childMethod->graphState & GRAPH_LABEL_VISITED) == 0 && checkThreshold(method, childMethod)) {
+            createLabels(file, child->method);
+        }
+    }
+}
+
+void createLinks(FILE* file, MethodEntry* method)
+{
+    method->graphState |= GRAPH_NODE_VISITED;
+
+    TimedMethod* child;
+    for (child = method->children[0] ; child ; child = child->next) {
+        MethodEntry* childMethod = child->method;
+        if (checkThreshold(method, child->method)) {
+            fprintf(file, "node%d -> node%d\n", method->index, child->method->index);
+            // only visit children that haven't been visited before
+            if ((childMethod->graphState & GRAPH_NODE_VISITED) == 0) {
+                createLinks(file, child->method);
+            }
+        }
+    }
+}
+
+void createInclusiveProfileGraphNew(DataKeys* dataKeys)
+{
+    // create a temporary file in /tmp
+    char path[FILENAME_MAX];
+    if (gOptions.keepDotFile) {
+        snprintf(path, FILENAME_MAX, "%s.dot", gOptions.graphFileName);
+    } else {
+        snprintf(path, FILENAME_MAX, "/tmp/dot-%d-%d.dot", (int)time(NULL), rand());
+    }
+
+    FILE* file = fopen(path, "w+");
+
+    fprintf(file, "digraph g {\nnode [shape = record,height=.1];\n");
+
+    createLabels(file, dataKeys->methods);
+    createLinks(file, dataKeys->methods);
+
+    fprintf(file, "}");
+    fclose(file);
+
+    // now that we have the dot file generate the image
+    char command[1024];
+    snprintf(command, 1024, "dot -Tpng -o '%s' '%s'", gOptions.graphFileName, path);
+
+    system(command);
+
+    if (! gOptions.keepDotFile) {
+        remove(path);
+    }
+}
+
+void printInclusiveProfile(MethodEntry **pMethods, int numMethods,
+                           uint64_t sumThreadTime)
+{
+    int ii;
+    MethodEntry* method;
+    double total, sum, per, sum_per;
+    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
+    char signatureBuf[HTML_BUFSIZE];
+    char anchor_buf[80];
+    char *anchor_close = "";
+
+    total = sumThreadTime;
+    anchor_buf[0] = 0;
+    if (gOptions.outputHtml) {
+        anchor_close = "</a>";
+        printf("<a name=\"inclusive\"></a>\n");
+        printf("<hr>\n");
+        outputNavigationBar();
+    } else {
+        printf("\n%s\n", profileSeparator);
+    }
+
+    /* Sort the methods into decreasing order of inclusive elapsed time. */
+    qsort(pMethods, numMethods, sizeof(MethodEntry*),
+          compareElapsedInclusive);
+
+    printf("\nInclusive elapsed times for each method and its parents and children,\n");
+    printf("sorted by inclusive time.\n\n");
+
+    if (gOptions.outputHtml) {
+        printf("<br><br>\n<pre>\n");
+    }
+
+    printf("index  %%/total %%/self  index     calls         usecs name\n");
+    for (ii = 0; ii < numMethods; ++ii) {
+        int num;
+        TimedMethod *pTimed;
+        double excl_per;
+        char buf[40];
+        char *className, *methodName, *signature;
+
+        method = pMethods[ii];
+        /* Don't show methods with zero cycles */
+        if (method->elapsedInclusive == 0)
+            break;
+
+        className = (char*)(method->className);
+        methodName = (char*)(method->methodName);
+        signature = (char*)(method->signature);
+
+        if (gOptions.outputHtml) {
+            printf("<a name=\"m%d\"></a>", method->index);
+            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
+            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
+            signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
+        }
+        printf("----------------------------------------------------\n");
+
+        /* Sort and print the parents */
+        int numCalls = method->numCalls[0] + method->numCalls[1];
+        printInclusiveMethod(method, method->parents[0], numCalls, 0);
+        if (method->parents[1]) {
+            printf("               +++++++++++++++++++++++++\n");
+            printInclusiveMethod(method, method->parents[1], numCalls,
+                                 kIsRecursive);
+        }
+
+        per = 100.0 * method->elapsedInclusive / total;
+        sprintf(buf, "[%d]", ii);
+        if (method->methodName) {
+            printf("%-6s %5.1f%%   %5s %6s %6d+%-6d %9llu %s.%s %s\n",
+                   buf,
+                   per, "", "", method->numCalls[0], method->numCalls[1],
+                   method->elapsedInclusive,
+                   className, methodName, signature);
+        } else {
+            printf("%-6s %5.1f%%   %5s %6s %6d+%-6d %9llu %s\n",
+                   buf,
+                   per, "", "", method->numCalls[0], method->numCalls[1],
+                   method->elapsedInclusive,
+                   className);
+        }
+        excl_per = 100.0 * method->topExclusive / method->elapsedInclusive;
+        printf("%6s %5s   %5.1f%% %6s %6s %6s %9llu\n",
+               "", "", excl_per, "excl", "", "", method->topExclusive);
+
+        /* Sort and print the children */
+        printInclusiveMethod(method, method->children[0], 0, 0);
+        if (method->children[1]) {
+            printf("               +++++++++++++++++++++++++\n");
+            printInclusiveMethod(method, method->children[1], 0,
+                                 kIsRecursive);
+        }
+    }
+    if (gOptions.outputHtml) {
+        printf("</pre>\n");
+    }
+}
+
+void createClassList(TraceData* traceData, MethodEntry **pMethods, int numMethods)
+{
+    int ii;
+
+    /* Sort the methods into alphabetical order to find the unique class
+     * names.
+     */
+    qsort(pMethods, numMethods, sizeof(MethodEntry*), compareClassNames);
+
+    /* Count the number of unique class names. */
+    const char *currentClassName = "";
+    const char *firstClassName = NULL;
+    traceData->numClasses = 0;
+    for (ii = 0; ii < numMethods; ++ii) {
+        if (pMethods[ii]->methodName == NULL) {
+            continue;
+        }
+        if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
+            // Remember the first one
+            if (firstClassName == NULL) {
+                firstClassName = pMethods[ii]->className;
+            }
+            traceData->numClasses += 1;
+            currentClassName = pMethods[ii]->className;
+        }
+    }
+
+    if (traceData->numClasses == 0) {
+        traceData->classes = NULL;
+        return;
+    }
+
+    /* Allocate space for all of the unique class names */
+    traceData->classes = (ClassEntry *) malloc(sizeof(ClassEntry) * traceData->numClasses);
+
+    /* Initialize the classes array */
+    memset(traceData->classes, 0, sizeof(ClassEntry) * traceData->numClasses);
+    ClassEntry *pClass = traceData->classes;
+    pClass->className = currentClassName = firstClassName;
+    int prevNumMethods = 0;
+    for (ii = 0; ii < numMethods; ++ii) {
+        if (pMethods[ii]->methodName == NULL) {
+            continue;
+        }
+        if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
+            pClass->numMethods = prevNumMethods;
+            (++pClass)->className = currentClassName = pMethods[ii]->className;
+            prevNumMethods = 0;
+        }
+        prevNumMethods += 1;
+    }
+    pClass->numMethods = prevNumMethods;
+
+    /* Create the array of MethodEntry pointers for each class */
+    pClass = NULL;
+    currentClassName = "";
+    int nextMethod = 0;
+    for (ii = 0; ii < numMethods; ++ii) {
+        if (pMethods[ii]->methodName == NULL) {
+            continue;
+        }
+        if (strcmp(pMethods[ii]->className, currentClassName) != 0) {
+            currentClassName = pMethods[ii]->className;
+            if (pClass == NULL)
+                pClass = traceData->classes;
+            else
+                pClass++;
+            /* Allocate space for the methods array */
+            int nbytes = sizeof(MethodEntry*) * pClass->numMethods;
+            pClass->methods = (MethodEntry**) malloc(nbytes);
+            nextMethod = 0;
+        }
+        pClass->methods[nextMethod++] = pMethods[ii];
+    }
+}
+
+/* Prints a number of html non-breaking spaces according so that the length
+ * of the string "buf" is at least "width" characters wide.  If width is
+ * negative, then trailing spaces are added instead of leading spaces.
+ */
+void printHtmlField(char *buf, int width)
+{
+    int ii;
+
+    int leadingSpaces = 1;
+    if (width < 0) {
+        width = -width;
+        leadingSpaces = 0;
+    }
+    int len = strlen(buf);
+    int numSpaces = width - len;
+    if (numSpaces <= 0) {
+        printf("%s", buf);
+        return;
+    }
+    if (leadingSpaces == 0)
+        printf("%s", buf);
+    for (ii = 0; ii < numSpaces; ++ii)
+        printf("&nbsp;");
+    if (leadingSpaces == 1)
+        printf("%s", buf);
+}
+
+void printClassProfiles(TraceData* traceData, uint64_t sumThreadTime)
+{
+    int ii, jj;
+    MethodEntry* method;
+    double total, sum, per, sum_per;
+    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
+    char signatureBuf[HTML_BUFSIZE];
+
+    total = sumThreadTime;
+    if (gOptions.outputHtml) {
+        printf("<a name=\"class\"></a>\n");
+        printf("<hr>\n");
+        outputNavigationBar();
+    } else {
+        printf("\n%s\n", profileSeparator);
+    }
+
+    if (traceData->numClasses == 0) {
+        printf("\nNo classes.\n");
+        if (gOptions.outputHtml) {
+            printf("<br><br>\n");
+        }
+        return;
+    }
+
+    printf("\nExclusive elapsed time for each class, summed over all the methods\n");
+    printf("in the class.\n\n");
+    if (gOptions.outputHtml) {
+        printf("<br><br>\n");
+    }
+
+    /* For each class, sum the exclusive times in all of the methods
+     * in that class.  Also sum the number of method calls.  Also
+     * sort the methods so the most expensive appear at the top.
+     */
+    ClassEntry *pClass = traceData->classes;
+    for (ii = 0; ii < traceData->numClasses; ++ii, ++pClass) {
+        //printf("%s %d methods\n", pClass->className, pClass->numMethods);
+        int numMethods = pClass->numMethods;
+        for (jj = 0; jj < numMethods; ++jj) {
+            method = pClass->methods[jj];
+            pClass->elapsedExclusive += method->elapsedExclusive;
+            pClass->numCalls[0] += method->numCalls[0];
+            pClass->numCalls[1] += method->numCalls[1];
+        }
+
+        /* Sort the methods into decreasing order of exclusive time */
+        qsort(pClass->methods, numMethods, sizeof(MethodEntry*),
+              compareElapsedExclusive);
+    }
+
+    /* Allocate an array of pointers to the classes for more efficient
+     * sorting.
+     */
+    ClassEntry **pClasses;
+    pClasses = (ClassEntry**) malloc(sizeof(ClassEntry*) * traceData->numClasses);
+    for (ii = 0; ii < traceData->numClasses; ++ii)
+        pClasses[ii] = &traceData->classes[ii];
+
+    /* Sort the classes into decreasing order of exclusive time */
+    qsort(pClasses, traceData->numClasses, sizeof(ClassEntry*), compareClassExclusive);
+
+    if (gOptions.outputHtml) {
+        printf("<div class=\"header\"><span class=\"parent\">&nbsp;</span>&nbsp;&nbsp;&nbsp;");
+        printf("Cycles %%/total Cumul.%% &nbsp;Calls+Recur&nbsp; Class</div>\n");
+    } else {
+        printf("   Cycles %%/total Cumul.%%  Calls+Recur  Class\n");
+    }
+
+    sum = 0;
+    for (ii = 0; ii < traceData->numClasses; ++ii) {
+        char *className, *methodName, *signature;
+
+        /* Skip classes with zero cycles */
+        pClass = pClasses[ii];
+        if (pClass->elapsedExclusive == 0)
+            break;
+
+        per = 100.0 * pClass->elapsedExclusive / total;
+        sum += pClass->elapsedExclusive;
+        sum_per = 100.0 * sum / total;
+        className = (char*)(pClass->className);
+        if (gOptions.outputHtml) {
+            char buf[80];
+
+            className = htmlEscape(className, classBuf, HTML_BUFSIZE);
+            printf("<div class=\"link\" onClick=\"javascript:toggle('d%d')\" onMouseOver=\"javascript:onMouseOver(this)\" onMouseOut=\"javascript:onMouseOut(this)\"><span class=\"parent\" id=\"xd%d\">+</span>", ii, ii);
+            sprintf(buf, "%llu", pClass->elapsedExclusive);
+            printHtmlField(buf, 9);
+            printf(" ");
+            sprintf(buf, "%.1f", per);
+            printHtmlField(buf, 7);
+            printf(" ");
+            sprintf(buf, "%.1f", sum_per);
+            printHtmlField(buf, 7);
+            printf(" ");
+            sprintf(buf, "%d", pClass->numCalls[0]);
+            printHtmlField(buf, 6);
+            printf("+");
+            sprintf(buf, "%d", pClass->numCalls[1]);
+            printHtmlField(buf, -6);
+            printf(" ");
+            printf("%s", className);
+            printf("</div>\n");
+            printf("<div class=\"parent\" id=\"d%d\">\n", ii);
+        } else {
+            printf("---------------------------------------------\n");
+            printf("%9llu %7.1f %7.1f %6d+%-6d %s\n",
+                   pClass->elapsedExclusive, per, sum_per,
+                   pClass->numCalls[0], pClass->numCalls[1],
+                   className);
+        }
+
+        int numMethods = pClass->numMethods;
+        double classExclusive = pClass->elapsedExclusive;
+        double sumMethods = 0;
+        for (jj = 0; jj < numMethods; ++jj) {
+            method = pClass->methods[jj];
+            methodName = (char*)(method->methodName);
+            signature = (char*)(method->signature);
+            per = 100.0 * method->elapsedExclusive / classExclusive;
+            sumMethods += method->elapsedExclusive;
+            sum_per = 100.0 * sumMethods / classExclusive;
+            if (gOptions.outputHtml) {
+                char buf[80];
+
+                methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
+                signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
+                printf("<div class=\"leaf\"><span class=\"leaf\">&nbsp;</span>");
+                sprintf(buf, "%llu", method->elapsedExclusive);
+                printHtmlField(buf, 9);
+                printf("&nbsp;");
+                sprintf(buf, "%llu", method->elapsedInclusive);
+                printHtmlField(buf, 9);
+                printf("&nbsp;");
+                sprintf(buf, "%.1f", per);
+                printHtmlField(buf, 7);
+                printf("&nbsp;");
+                sprintf(buf, "%.1f", sum_per);
+                printHtmlField(buf, 7);
+                printf("&nbsp;");
+                sprintf(buf, "%d", method->numCalls[0]);
+                printHtmlField(buf, 6);
+                printf("+");
+                sprintf(buf, "%d", method->numCalls[1]);
+                printHtmlField(buf, -6);
+                printf("&nbsp;");
+                printf("<a href=\"#m%d\">[%d]</a>&nbsp;%s&nbsp;%s",
+                       method->index, method->index, methodName, signature);
+                printf("</div>\n");
+            } else {
+                printf("%9llu %9llu %7.1f %7.1f %6d+%-6d [%d] %s %s\n",
+                       method->elapsedExclusive,
+                       method->elapsedInclusive,
+                       per, sum_per,
+                       method->numCalls[0], method->numCalls[1],
+                       method->index, methodName, signature);
+            }
+        }
+        if (gOptions.outputHtml) {
+            printf("</div>\n");
+        }
+    }
+}
+
+void createUniqueMethodList(TraceData* traceData, MethodEntry **pMethods, int numMethods)
+{
+    int ii;
+
+    /* Sort the methods into alphabetical order of method names
+     * to find the unique method names.
+     */
+    qsort(pMethods, numMethods, sizeof(MethodEntry*), compareMethodNames);
+
+    /* Count the number of unique method names, ignoring class and
+     * signature.
+     */
+    const char *currentMethodName = "";
+    traceData->numUniqueMethods = 0;
+    for (ii = 0; ii < numMethods; ++ii) {
+        if (pMethods[ii]->methodName == NULL)
+            continue;
+        if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
+            traceData->numUniqueMethods += 1;
+            currentMethodName = pMethods[ii]->methodName;
+        }
+    }
+    if (traceData->numUniqueMethods == 0)
+        return;
+
+    /* Allocate space for pointers to all of the unique methods */
+    int nbytes = sizeof(UniqueMethodEntry) * traceData->numUniqueMethods;
+    traceData->uniqueMethods = (UniqueMethodEntry *) malloc(nbytes);
+
+    /* Initialize the uniqueMethods array */
+    memset(traceData->uniqueMethods, 0, nbytes);
+    UniqueMethodEntry *pUnique = traceData->uniqueMethods;
+    currentMethodName = NULL;
+    int prevNumMethods = 0;
+    for (ii = 0; ii < numMethods; ++ii) {
+        if (pMethods[ii]->methodName == NULL)
+            continue;
+        if (currentMethodName == NULL)
+            currentMethodName = pMethods[ii]->methodName;
+        if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
+            currentMethodName = pMethods[ii]->methodName;
+            pUnique->numMethods = prevNumMethods;
+            pUnique++;
+            prevNumMethods = 0;
+        }
+        prevNumMethods += 1;
+    }
+    pUnique->numMethods = prevNumMethods;
+
+    /* Create the array of MethodEntry pointers for each unique method */
+    pUnique = NULL;
+    currentMethodName = "";
+    int nextMethod = 0;
+    for (ii = 0; ii < numMethods; ++ii) {
+        if (pMethods[ii]->methodName == NULL)
+            continue;
+        if (strcmp(pMethods[ii]->methodName, currentMethodName) != 0) {
+            currentMethodName = pMethods[ii]->methodName;
+            if (pUnique == NULL)
+                pUnique = traceData->uniqueMethods;
+            else
+                pUnique++;
+            /* Allocate space for the methods array */
+            int nbytes = sizeof(MethodEntry*) * pUnique->numMethods;
+            pUnique->methods = (MethodEntry**) malloc(nbytes);
+            nextMethod = 0;
+        }
+        pUnique->methods[nextMethod++] = pMethods[ii];
+    }
+}
+
+void printMethodProfiles(TraceData* traceData, uint64_t sumThreadTime)
+{
+    int ii, jj;
+    MethodEntry* method;
+    double total, sum, per, sum_per;
+    char classBuf[HTML_BUFSIZE], methodBuf[HTML_BUFSIZE];
+    char signatureBuf[HTML_BUFSIZE];
+
+    if (traceData->numUniqueMethods == 0)
+        return;
+
+    total = sumThreadTime;
+    if (gOptions.outputHtml) {
+        printf("<a name=\"method\"></a>\n");
+        printf("<hr>\n");
+        outputNavigationBar();
+    } else {
+        printf("\n%s\n", profileSeparator);
+    }
+
+    printf("\nExclusive elapsed time for each method, summed over all the classes\n");
+    printf("that contain a method with the same name.\n\n");
+    if (gOptions.outputHtml) {
+        printf("<br><br>\n");
+    }
+
+    /* For each unique method, sum the exclusive times in all of the methods
+     * with the same name.  Also sum the number of method calls.  Also
+     * sort the methods so the most expensive appear at the top.
+     */
+    UniqueMethodEntry *pUnique = traceData->uniqueMethods;
+    for (ii = 0; ii < traceData->numUniqueMethods; ++ii, ++pUnique) {
+        int numMethods = pUnique->numMethods;
+        for (jj = 0; jj < numMethods; ++jj) {
+            method = pUnique->methods[jj];
+            pUnique->elapsedExclusive += method->elapsedExclusive;
+            pUnique->numCalls[0] += method->numCalls[0];
+            pUnique->numCalls[1] += method->numCalls[1];
+        }
+
+        /* Sort the methods into decreasing order of exclusive time */
+        qsort(pUnique->methods, numMethods, sizeof(MethodEntry*),
+              compareElapsedExclusive);
+    }
+
+    /* Allocate an array of pointers to the methods for more efficient
+     * sorting.
+     */
+    UniqueMethodEntry **pUniqueMethods;
+    int nbytes = sizeof(UniqueMethodEntry*) * traceData->numUniqueMethods;
+    pUniqueMethods = (UniqueMethodEntry**) malloc(nbytes);
+    for (ii = 0; ii < traceData->numUniqueMethods; ++ii)
+        pUniqueMethods[ii] = &traceData->uniqueMethods[ii];
+
+    /* Sort the methods into decreasing order of exclusive time */
+    qsort(pUniqueMethods, traceData->numUniqueMethods, sizeof(UniqueMethodEntry*),
+          compareUniqueExclusive);
+
+    if (gOptions.outputHtml) {
+        printf("<div class=\"header\"><span class=\"parent\">&nbsp;</span>&nbsp;&nbsp;&nbsp;");
+        printf("Cycles %%/total Cumul.%% &nbsp;Calls+Recur&nbsp; Method</div>\n");
+    } else {
+        printf("   Cycles %%/total Cumul.%%  Calls+Recur  Method\n");
+    }
+
+    sum = 0;
+    for (ii = 0; ii < traceData->numUniqueMethods; ++ii) {
+        char *className, *methodName, *signature;
+
+        /* Skip methods with zero cycles */
+        pUnique = pUniqueMethods[ii];
+        if (pUnique->elapsedExclusive == 0)
+            break;
+
+        per = 100.0 * pUnique->elapsedExclusive / total;
+        sum += pUnique->elapsedExclusive;
+        sum_per = 100.0 * sum / total;
+        methodName = (char*)(pUnique->methods[0]->methodName);
+        if (gOptions.outputHtml) {
+            char buf[80];
+
+            methodName = htmlEscape(methodName, methodBuf, HTML_BUFSIZE);
+            printf("<div class=\"link\" onClick=\"javascript:toggle('e%d')\" onMouseOver=\"javascript:onMouseOver(this)\" onMouseOut=\"javascript:onMouseOut(this)\"><span class=\"parent\" id=\"xe%d\">+</span>", ii, ii);
+            sprintf(buf, "%llu", pUnique->elapsedExclusive);
+            printHtmlField(buf, 9);
+            printf(" ");
+            sprintf(buf, "%.1f", per);
+            printHtmlField(buf, 7);
+            printf(" ");
+            sprintf(buf, "%.1f", sum_per);
+            printHtmlField(buf, 7);
+            printf(" ");
+            sprintf(buf, "%d", pUnique->numCalls[0]);
+            printHtmlField(buf, 6);
+            printf("+");
+            sprintf(buf, "%d", pUnique->numCalls[1]);
+            printHtmlField(buf, -6);
+            printf(" ");
+            printf("%s", methodName);
+            printf("</div>\n");
+            printf("<div class=\"parent\" id=\"e%d\">\n", ii);
+        } else {
+            printf("---------------------------------------------\n");
+            printf("%9llu %7.1f %7.1f %6d+%-6d %s\n",
+                   pUnique->elapsedExclusive, per, sum_per,
+                   pUnique->numCalls[0], pUnique->numCalls[1],
+                   methodName);
+        }
+        int numMethods = pUnique->numMethods;
+        double methodExclusive = pUnique->elapsedExclusive;
+        double sumMethods = 0;
+        for (jj = 0; jj < numMethods; ++jj) {
+            method = pUnique->methods[jj];
+            className = (char*)(method->className);
+            signature = (char*)(method->signature);
+            per = 100.0 * method->elapsedExclusive / methodExclusive;
+            sumMethods += method->elapsedExclusive;
+            sum_per = 100.0 * sumMethods / methodExclusive;
+            if (gOptions.outputHtml) {
+                char buf[80];
+
+                className = htmlEscape(className, classBuf, HTML_BUFSIZE);
+                signature = htmlEscape(signature, signatureBuf, HTML_BUFSIZE);
+                printf("<div class=\"leaf\"><span class=\"leaf\">&nbsp;</span>");
+                sprintf(buf, "%llu", method->elapsedExclusive);
+                printHtmlField(buf, 9);
+                printf("&nbsp;");
+                sprintf(buf, "%llu", method->elapsedInclusive);
+                printHtmlField(buf, 9);
+                printf("&nbsp;");
+                sprintf(buf, "%.1f", per);
+                printHtmlField(buf, 7);
+                printf("&nbsp;");
+                sprintf(buf, "%.1f", sum_per);
+                printHtmlField(buf, 7);
+                printf("&nbsp;");
+                sprintf(buf, "%d", method->numCalls[0]);
+                printHtmlField(buf, 6);
+                printf("+");
+                sprintf(buf, "%d", method->numCalls[1]);
+                printHtmlField(buf, -6);
+                printf("&nbsp;");
+                printf("<a href=\"#m%d\">[%d]</a>&nbsp;%s.%s&nbsp;%s",
+                       method->index, method->index,
+                       className, methodName, signature);
+                printf("</div>\n");
+            } else {
+                printf("%9llu %9llu %7.1f %7.1f %6d+%-6d [%d] %s.%s %s\n",
+                       method->elapsedExclusive,
+                       method->elapsedInclusive,
+                       per, sum_per,
+                       method->numCalls[0], method->numCalls[1],
+                       method->index, className, methodName, signature);
+            }
+        }
+        if (gOptions.outputHtml) {
+            printf("</div>\n");
+        }
+    }
+}
+
+/*
+ * Read the key and data files and return the MethodEntries for those files
+ */
+DataKeys* parseDataKeys(TraceData* traceData, const char* traceFileName, uint64_t* threadTime)
+{
+    DataKeys* dataKeys = NULL;
+    MethodEntry **pMethods = NULL;
+    MethodEntry* method;
+    FILE* dataFp = NULL;
+    DataHeader dataHeader;
+    int ii;
+    uint64_t currentTime;
+    MethodEntry* caller;
+
+    dataFp = fopen(traceFileName, "r");
+    if (dataFp == NULL)
+        goto bail;
+
+    if ((dataKeys = parseKeys(dataFp, 0)) == NULL)
+        goto bail;
+
+    if (parseDataHeader(dataFp, &dataHeader) < 0)
+        goto bail;
+
+#if 0
+    FILE *dumpStream = fopen("debug", "w");
+#endif
+    while (1) {
+        int threadId;
+        unsigned int methodVal;
+        int action;
+        unsigned int methodId;
+        CallStack *pStack;
+        /*
+         * Extract values from file.
+         */
+        if (readDataRecord(dataFp, &dataHeader, &threadId, &methodVal, &currentTime))
+            break;
+
+        action = METHOD_ACTION(methodVal);
+        methodId = METHOD_ID(methodVal);
+
+        /* Get the call stack for this thread */
+        pStack = traceData->stacks[threadId];
+
+        /* If there is no call stack yet for this thread, then allocate one */
+        if (pStack == NULL) {
+            pStack = malloc(sizeof(CallStack));
+            pStack->top = 0;
+            pStack->lastEventTime = currentTime;
+            pStack->threadStartTime = currentTime;
+            traceData->stacks[threadId] = pStack;
+        }
+
+        /* Lookup the current method */
+        method = lookupMethod(dataKeys, methodId);
+        if (method == NULL)
+            method = &dataKeys->methods[UNKNOWN_INDEX];
+
+#if 0
+        if (method->methodName) {
+            fprintf(dumpStream, "%2d %-8llu %d %8llu r %d c %d %s.%s %s\n",
+                    threadId, currentTime, action, pStack->threadStartTime,
+                    method->recursiveEntries,
+                    pStack->top, method->className, method->methodName,
+                    method->signature);
+        } else {
+            fprintf(dumpStream, "%2d %-8llu %d %8llu r %d c %d %s\n",
+                    threadId, currentTime, action, pStack->threadStartTime,
+                    method->recursiveEntries,
+                    pStack->top, method->className);
+        }
+#endif
+
+        if (action == METHOD_TRACE_ENTER) {
+            /* This is a method entry */
+            if (pStack->top >= MAX_STACK_DEPTH) {
+                fprintf(stderr, "Stack overflow (exceeded %d frames)\n",
+                        MAX_STACK_DEPTH);
+                exit(1);
+            }
+
+            /* Get the caller method */
+            if (pStack->top >= 1)
+                caller = pStack->calls[pStack->top - 1].method;
+            else
+                caller = &dataKeys->methods[TOPLEVEL_INDEX];
+            countRecursiveEntries(pStack, pStack->top, caller);
+            caller->elapsedExclusive += currentTime - pStack->lastEventTime;
+#if 0
+            if (caller->elapsedExclusive > 10000000)
+                fprintf(dumpStream, "%llu current %llu last %llu diff %llu\n",
+                        caller->elapsedExclusive, currentTime,
+                        pStack->lastEventTime,
+                        currentTime - pStack->lastEventTime);
+#endif
+            if (caller->recursiveEntries <= 1) {
+                caller->topExclusive += currentTime - pStack->lastEventTime;
+            }
+
+            /* Push the method on the stack for this thread */
+            pStack->calls[pStack->top].method = method;
+            pStack->calls[pStack->top++].entryTime = currentTime;
+        } else {
+            /* This is a method exit */
+            uint64_t entryTime = 0;
+
+            /* Pop the method off the stack for this thread */
+            if (pStack->top > 0) {
+                pStack->top -= 1;
+                entryTime = pStack->calls[pStack->top].entryTime;
+                if (method != pStack->calls[pStack->top].method) {
+                    if (method->methodName) {
+                        fprintf(stderr,
+                            "Exit from method %s.%s %s does not match stack:\n",
+                            method->className, method->methodName,
+                            method->signature);
+                    } else {
+                        fprintf(stderr,
+                            "Exit from method %s does not match stack:\n",
+                            method->className);
+                    }
+                    stackDump(pStack, pStack->top + 1);
+                    exit(1);
+                }
+            }
+
+            /* Get the caller method */
+            if (pStack->top >= 1)
+                caller = pStack->calls[pStack->top - 1].method;
+            else
+                caller = &dataKeys->methods[TOPLEVEL_INDEX];
+            countRecursiveEntries(pStack, pStack->top, caller);
+            countRecursiveEntries(pStack, pStack->top, method);
+            uint64_t elapsed = currentTime - entryTime;
+            addInclusiveTime(caller, method, elapsed);
+            method->elapsedExclusive += currentTime - pStack->lastEventTime;
+            if (method->recursiveEntries == 0) {
+                method->topExclusive += currentTime - pStack->lastEventTime;
+            }
+        }
+        /* Remember the time of the last entry or exit event */
+        pStack->lastEventTime = currentTime;
+    }
+
+    /* If we have calls on the stack when the trace ends, then clean
+     * up the stack and add time to the callers by pretending that we
+     * are exiting from their methods now.
+     */
+    CallStack *pStack;
+    int threadId;
+    uint64_t sumThreadTime = 0;
+    for (threadId = 0; threadId < MAX_THREADS; ++threadId) {
+        pStack = traceData->stacks[threadId];
+
+        /* If this thread never existed, then continue with next thread */
+        if (pStack == NULL)
+            continue;
+
+        /* Also, add up the time taken by all of the threads */
+        sumThreadTime += pStack->lastEventTime - pStack->threadStartTime;
+
+        for (ii = 0; ii < pStack->top; ++ii) {
+            if (ii == 0)
+                caller = &dataKeys->methods[TOPLEVEL_INDEX];
+            else
+                caller = pStack->calls[ii - 1].method;
+            method = pStack->calls[ii].method;
+            countRecursiveEntries(pStack, ii, caller);
+            countRecursiveEntries(pStack, ii, method);
+
+            uint64_t entryTime = pStack->calls[ii].entryTime;
+            uint64_t elapsed = pStack->lastEventTime - entryTime;
+            addInclusiveTime(caller, method, elapsed);
+        }
+    }
+    caller = &dataKeys->methods[TOPLEVEL_INDEX];
+    caller->elapsedInclusive = sumThreadTime;
+
+#if 0
+    fclose(dumpStream);
+#endif
+
+    if (threadTime != NULL) {
+        *threadTime = sumThreadTime;
+    }
+
+bail:
+    if (dataFp != NULL)
+        fclose(dataFp);
+
+    return dataKeys;
+}
+
+MethodEntry** parseMethodEntries(DataKeys* dataKeys)
+{
+    int ii;
+    /* Create a new array of pointers to the methods and sort the pointers
+     * instead of the actual MethodEntry structs.  We need to do this
+     * because there are other lists that contain pointers to the
+     * MethodEntry structs.
+     */
+    MethodEntry** pMethods = (MethodEntry**) malloc(sizeof(MethodEntry*) * dataKeys->numMethods);
+    for (ii = 0; ii < dataKeys->numMethods; ++ii) {
+        MethodEntry* entry = &dataKeys->methods[ii];
+        pMethods[ii] = entry;
+    }
+
+    return pMethods;
+}
+
+/*
+ * Produce a function profile from the following methods
+ */
+void profileTrace(TraceData* traceData, MethodEntry **pMethods, int numMethods, uint64_t sumThreadTime)
+{
+    /* Print the html header, if necessary */
+    if (gOptions.outputHtml) {
+        printf(htmlHeader, gOptions.sortableUrl);
+        outputTableOfContents();
+    }
+
+    printExclusiveProfile(pMethods, numMethods, sumThreadTime);
+    printInclusiveProfile(pMethods, numMethods, sumThreadTime);
+
+    createClassList(traceData, pMethods, numMethods);
+    printClassProfiles(traceData, sumThreadTime);
+
+    createUniqueMethodList(traceData, pMethods, numMethods);
+    printMethodProfiles(traceData, sumThreadTime);
+
+    if (gOptions.outputHtml) {
+        printf("%s", htmlFooter);
+    }
+}
+
+int compareMethodNamesForDiff(const void *a, const void *b)
+{
+    int result;
+
+    const MethodEntry *methodA = *(const MethodEntry**)a;
+    const MethodEntry *methodB = *(const MethodEntry**)b;
+    if (methodA->methodName == NULL || methodB->methodName == NULL) {
+        return compareClassNames(a, b);
+    }
+    result = strcmp(methodA->methodName, methodB->methodName);
+    if (result == 0) {
+        result = strcmp(methodA->signature, methodB->signature);
+        if (result == 0) {
+           return strcmp(methodA->className, methodB->className);
+        }
+    }
+    return result;
+}
+
+int findMatch(MethodEntry** methods, int size, MethodEntry* matchThis)
+{
+    int i;
+
+    for (i = 0 ; i < size ; i++) {
+        MethodEntry* method = methods[i];
+
+        if (method != NULL && !compareMethodNamesForDiff(&method, &matchThis)) {
+//            printf("%s.%s == %s.%s<br>\n", matchThis->className, matchThis->methodName,
+  //              method->className, method->methodName);
+
+            return i;
+/*            if (!compareMethodNames(&method, &matchThis)) {
+                return i;
+            }
+*/        }
+    }
+
+    return -1;
+}
+
+int compareDiffEntriesExculsive(const void *a, const void *b)
+{
+    int result;
+
+    const DiffEntry* entryA = (const DiffEntry*)a;
+    const DiffEntry* entryB = (const DiffEntry*)b;
+
+    if (entryA->differenceExclusive < entryB->differenceExclusive) {
+        return 1;
+    } else if (entryA->differenceExclusive > entryB->differenceExclusive) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int compareDiffEntriesInculsive(const void *a, const void *b)
+{
+    int result;
+
+    const DiffEntry* entryA = (const DiffEntry*)a;
+    const DiffEntry* entryB = (const DiffEntry*)b;
+
+    if (entryA->differenceInclusive < entryB->differenceInclusive) {
+        return 1;
+    } else if (entryA->differenceInclusive > entryB->differenceInclusive) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void printMissingMethod(MethodEntry* method)
+{
+    char classBuf[HTML_BUFSIZE];
+    char methodBuf[HTML_BUFSIZE];
+    char* className;
+    char* methodName;
+
+    className = htmlEscape(method->className, classBuf, HTML_BUFSIZE);
+    methodName = htmlEscape(method->methodName, methodBuf, HTML_BUFSIZE);
+
+    if (gOptions.outputHtml) printf("<tr><td>\n");
+
+    printf("%s.%s ", className, methodName);
+    if (gOptions.outputHtml) printf("</td><td>");
+
+    printf("%lld ", method->elapsedExclusive);
+    if (gOptions.outputHtml) printf("</td><td>");
+
+    printf("%lld ", method->elapsedInclusive);
+    if (gOptions.outputHtml) printf("</td><td>");
+
+    printf("%d\n", method->numCalls[0]);
+    if (gOptions.outputHtml) printf("</td><td>\n");
+}
+
+
+void createDiff(DataKeys* d1, uint64_t sum1, DataKeys* d2, uint64_t sum2)
+{
+    MethodEntry** methods1 = parseMethodEntries(d1);
+    MethodEntry** methods2 = parseMethodEntries(d2);
+
+    // sort and assign the indicies
+    int i;
+    qsort(methods1, d1->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
+    for (i = 0; i < d1->numMethods; ++i) {
+        methods1[i]->index = i;
+    }
+
+    qsort(methods2, d2->numMethods, sizeof(MethodEntry*), compareElapsedInclusive);
+    for (i = 0; i < d2->numMethods; ++i) {
+        methods2[i]->index = i;
+    }
+
+    int max = (d1->numMethods < d2->numMethods) ? d2->numMethods : d1->numMethods;
+    max++;
+    DiffEntry* diffs = (DiffEntry*)malloc(max * sizeof(DiffEntry));
+    memset(diffs, 0, max * sizeof(DiffEntry));
+    DiffEntry* ptr = diffs;
+
+//    printf("<br>d1->numMethods: %d d1->numMethods: %d<br>\n", d1->numMethods, d2->numMethods);
+
+    int matches = 0;
+
+    for (i = 0 ; i < d1->numMethods ; i++) {
+        int match = findMatch(methods2, d2->numMethods, methods1[i]);
+        if (match >= 0) {
+            ptr->method1 = methods1[i];
+            ptr->method2 = methods2[match];
+
+            uint64_t e1 = ptr->method1->elapsedExclusive;
+            uint64_t e2 = ptr->method2->elapsedExclusive;
+            if (e1 > 0) {
+                ptr->differenceExclusive = e2 - e1;
+                ptr->differenceExclusivePercentage = ((double)e2 / (double)e1) * 100.0;
+            }
+
+            uint64_t i1 = ptr->method1->elapsedInclusive;
+            uint64_t i2 = ptr->method2->elapsedInclusive;
+            if (i1 > 0) {
+                ptr->differenceInclusive = i2 - i1;
+                ptr->differenceInclusivePercentage = ((double)i2 / (double)i1) * 100.0;
+            }
+
+            // clear these out so we don't find them again and we know which ones
+            // we have left over
+            methods1[i] = NULL;
+            methods2[match] = NULL;
+            ptr++;
+
+            matches++;
+        }
+    }
+    ptr->method1 = NULL;
+    ptr->method2 = NULL;
+
+    qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesExculsive);
+    ptr = diffs;
+
+    if (gOptions.outputHtml) {
+        printf(htmlHeader, gOptions.sortableUrl);
+        printf("<h3>Table of Contents</h3>\n");
+        printf("<ul>\n");
+        printf("<li><a href='#exclusive'>Exclusive</a>\n");
+        printf("<li><a href='#inclusive'>Inclusive</a>\n");
+        printf("</ul>\n");
+        printf("Run 1: %s<br>\n", gOptions.diffFileName);
+        printf("Run 2: %s<br>\n", gOptions.traceFileName);
+        printf("<a name=\"exclusive\"></a><h3 id=\"exclusive\">Exclusive</h3>\n");
+        printf(tableHeader, "exclusive_table");
+    }
+
+    char classBuf[HTML_BUFSIZE];
+    char methodBuf[HTML_BUFSIZE];
+    char* className;
+    char* methodName;
+
+    while (ptr->method1 != NULL && ptr->method2 != NULL) {
+        if (gOptions.outputHtml) printf("<tr><td>\n");
+
+        className = htmlEscape(ptr->method1->className, classBuf, HTML_BUFSIZE);
+        methodName = htmlEscape(ptr->method1->methodName, methodBuf, HTML_BUFSIZE);
+
+        printf("%s.%s ", className, methodName);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%lld ", ptr->method1->elapsedExclusive);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%llu ", ptr->method2->elapsedExclusive);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%lld ", ptr->differenceExclusive);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%.2f\n", ptr->differenceExclusivePercentage);
+        if (gOptions.outputHtml) printf("</td><td>\n");
+
+        printf("%d\n", ptr->method1->numCalls[0]);
+        if (gOptions.outputHtml) printf("</td><td>\n");
+
+        printf("%d\n", ptr->method2->numCalls[0]);
+        if (gOptions.outputHtml) printf("</td></tr>\n");
+
+        ptr++;
+    }
+
+    if (gOptions.outputHtml) printf("</table>\n");
+
+    if (gOptions.outputHtml) {
+        printf(htmlHeader, gOptions.sortableUrl);
+        printf("Run 1: %s<br>\n", gOptions.diffFileName);
+        printf("Run 2: %s<br>\n", gOptions.traceFileName);
+        printf("<a name=\"inclusive\"></a><h3 id=\"inculisve\">Inclusive</h3>\n");
+        printf(tableHeader, "inclusive_table");
+    }
+
+    qsort(diffs, matches, sizeof(DiffEntry), compareDiffEntriesInculsive);
+    ptr = diffs;
+
+    while (ptr->method1 != NULL && ptr->method2 != NULL) {
+        if (gOptions.outputHtml) printf("<tr><td>\n");
+
+        className = htmlEscape(ptr->method1->className, classBuf, HTML_BUFSIZE);
+        methodName = htmlEscape(ptr->method1->methodName, methodBuf, HTML_BUFSIZE);
+
+        printf("%s.%s ", className, methodName);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%lld ", ptr->method1->elapsedInclusive);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%llu ", ptr->method2->elapsedInclusive);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%lld ", ptr->differenceInclusive);
+        if (gOptions.outputHtml) printf("</td><td>");
+
+        printf("%.2f\n", ptr->differenceInclusivePercentage);
+        if (gOptions.outputHtml) printf("</td><td>\n");
+
+        printf("%d\n", ptr->method1->numCalls[0]);
+        if (gOptions.outputHtml) printf("</td><td>\n");
+
+        printf("%d\n", ptr->method2->numCalls[0]);
+        if (gOptions.outputHtml) printf("</td></tr>\n");
+
+        ptr++;
+    }
+
+    if (gOptions.outputHtml) {
+        printf("</table>\n");
+        printf("<h3>Run 1 methods not found in Run 2</h3>");
+        printf(tableHeaderMissing, "?");
+    }
+
+    for (i = 0; i < d1->numMethods; ++i) {
+        if (methods1[i] != NULL) {
+           printMissingMethod(methods1[i]);
+        }
+    }
+
+    if (gOptions.outputHtml) {
+        printf("</table>\n");
+        printf("<h3>Run 2 methods not found in Run 1</h3>");
+        printf(tableHeaderMissing, "?");
+    }
+
+    for (i = 0; i < d2->numMethods; ++i) {
+        if (methods2[i] != NULL) {
+            printMissingMethod(methods2[i]);
+        }
+    }
+
+    if (gOptions.outputHtml) printf("</body></html\n");
+}
+
+int usage(const char *program)
+{
+    fprintf(stderr, "Copyright (C) 2006 The Android Open Source Project\n\n");
+    fprintf(stderr, "usage: %s [-ho] [-s sortable] [-d trace-file-name] [-g outfile] trace-file-name\n", program);
+    fprintf(stderr, "  -d trace-file-name  - Diff with this trace\n");
+    fprintf(stderr, "  -g outfile          - Write graph to 'outfile'\n");
+    fprintf(stderr, "  -k                  - When writing a graph, keep the intermediate DOT file\n");
+    fprintf(stderr, "  -h                  - Turn on HTML output\n");
+    fprintf(stderr, "  -o                  - Dump the dmtrace file instead of profiling\n");
+    fprintf(stderr, "  -s                  - URL base to where the sortable javascript file\n");
+    fprintf(stderr, "  -t threshold        - Threshold percentage for including nodes in the graph\n");
+    return 2;
+}
+
+// Returns true if there was an error
+int parseOptions(int argc, char **argv)
+{
+    while (1) {
+        int opt = getopt(argc, argv, "d:hg:kos:t:");
+        if (opt == -1)
+            break;
+        switch (opt) {
+            case 'd':
+                gOptions.diffFileName = optarg;
+                break;
+            case 'g':
+                gOptions.graphFileName = optarg;
+                break;
+            case 'k':
+                gOptions.keepDotFile = 1;
+                break;
+            case 'h':
+                gOptions.outputHtml = 1;
+                break;
+            case 'o':
+                gOptions.dump = 1;
+                break;
+            case 's':
+                gOptions.sortableUrl = optarg;
+                break;
+            case 't':
+                gOptions.threshold = atoi(optarg);
+                break;
+            default:
+                return 1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * Parse args.
+ */
+int main(int argc, char** argv)
+{
+    gOptions.threshold = -1;
+
+    // Parse the options
+    if (parseOptions(argc, argv) || argc - optind != 1)
+        return usage(argv[0]);
+
+    gOptions.traceFileName = argv[optind];
+
+    if (gOptions.threshold < 0 || 100 <= gOptions.threshold) {
+        gOptions.threshold = 20;
+    }
+
+    if (gOptions.dump) {
+        dumpTrace();
+        return 0;
+    }
+
+    uint64_t sumThreadTime = 0;
+
+    TraceData data1;
+    DataKeys* dataKeys = parseDataKeys(&data1, gOptions.traceFileName,
+                                       &sumThreadTime);
+    if (dataKeys == NULL) {
+        fprintf(stderr, "Cannot read trace.\n");
+        exit(1);
+    }
+
+    if (gOptions.diffFileName != NULL) {
+        uint64_t sum2;
+        TraceData data2;
+        DataKeys* d2 = parseDataKeys(&data2, gOptions.diffFileName, &sum2);
+
+        createDiff(d2, sum2, dataKeys, sumThreadTime);
+
+        freeDataKeys(d2);
+    } else {
+        MethodEntry** methods = parseMethodEntries(dataKeys);
+        profileTrace(&data1, methods, dataKeys->numMethods, sumThreadTime);
+        if (gOptions.graphFileName != NULL) {
+            createInclusiveProfileGraphNew(dataKeys);
+        }
+        free(methods);
+    }
+
+    freeDataKeys(dataKeys);
+
+    return 0;
+}
diff --git a/tools/dmtracedump/dmtracedump.pl b/tools/dmtracedump/dmtracedump.pl
new file mode 100755
index 0000000..6e487c6
--- /dev/null
+++ b/tools/dmtracedump/dmtracedump.pl
@@ -0,0 +1,18 @@
+#!/usr/bin/perl
+
+opendir(DIR, ".") || die "can't opendir $some_dir: $!";
+@traces = grep { /.*\.dmtrace\.data/ } readdir(DIR);
+
+foreach (@traces)
+{
+    $input = $_;
+    $input =~ s/\.data$//;
+
+    $output = "$input.html";
+
+    print("dmtracedump -h -p $input > $output\n");
+    system("dmtracedump -h -p '$input' > '$output'");
+
+}
+
+closedir DIR;
diff --git a/tools/dmtracedump/dumpdir.sh b/tools/dmtracedump/dumpdir.sh
new file mode 100644
index 0000000..81992a2
--- /dev/null
+++ b/tools/dmtracedump/dumpdir.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+FILES=`ls $1/*.data | sed "s/^\\(.*\\).data$/\\1/"`
+
+mkdir -p $2
+
+for F in $FILES
+do
+    G=$2/`echo $F | sed "s/.*\\///g"`.html
+    dmtracedump -h -p $F > $G
+done
diff --git a/tools/gdbjithelper/Android.mk b/tools/gdbjithelper/Android.mk
new file mode 100644
index 0000000..087bc8f
--- /dev/null
+++ b/tools/gdbjithelper/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := gdbjithelper.c
+LOCAL_CFLAGS += -O0 -g
+LOCAL_MODULE := gdbjithelper
+LOCAL_MODULE_TAGS := eng
+include $(BUILD_EXECUTABLE)
diff --git a/tools/gdbjithelper/README.txt b/tools/gdbjithelper/README.txt
new file mode 100644
index 0000000..aab1a00
--- /dev/null
+++ b/tools/gdbjithelper/README.txt
@@ -0,0 +1,65 @@
+Step 1
+
+If you see a native crash in the bugreport and the PC/LR are pointing to the
+code cache address range*, copy them into codePC and codeLR in gdbjithelper.c,
+respectively.
+
+*Caveats: debuggerd doesn't know the range of code cache. So apply this tool if
+the crashing address is not contained by any shared library.
+
+       #00  pc 463ba204
+       #01  lr 463ba1c9  <unknown>
+
+code around pc:
+463ba1e4 4300e119 4284aa7a f927f7b7 40112268
+463ba1f4 419da7f8 00002000 01000100 00080000
+463ba204 4191debc 01010000 4284aa74 68b00054
+463ba214 045cf205 cc016468 0718f2a5 d0102800
+463ba224 4c13c701 a20aa108 efb0f775 e008e010
+
+code around lr:
+463ba1a8 42e19e58 f2050050 cc01045c 0718f2a5
+463ba1b8 d00f2800 4c13c701 a20aa108 efe4f775
+463ba1c8 e007e010 29006bf8 6e77dc01 a10347b8
+463ba1d8 ef60f775 6db1480b 1c2d4788 4300e119
+463ba1e8 4284aa7a f927f7b7 40112268 419da7f8
+
+
+Step 2
+
+Push $OUT/EXECUTABLES/gdbjithelper_intermediates/LINKED/gdbjithelper to
+/system/bin on the device or emulator
+
+
+Step 3
+
+Debug the executable as usual:
+
+adb forward tcp:5039 tcp:5039
+adb shell gdbserver :5039 /system/bin/gdbjithelper &
+arm-eabi-gdb $OUT/symbols/system/bin/gdbjithelper
+(gdb) tar r :5039
+Remote debugging using :5039
+Remote debugging from host 127.0.0.1
+gdb: Unable to get location for thread creation breakpoint: requested event is not supported
+__dl__start () at bionic/linker/arch/arm/begin.S:35
+35      mov r0, sp
+gdb: Unable to get location for thread creation breakpoint: requested event is not supported
+Current language:  auto; currently asm
+(gdb) c
+Continuing.
+[New Thread 596]
+codePC[0]: 0x4300e119
+codePC[1]: 0x4284aa7a
+         :
+
+
+Step 4
+
+Hit ctrl-C
+
+Issue the following command to see code around PC
+x /20i (char *) &codePC+1
+
+Issue the following command to see code around LR
+x /20i (char *) &codeLR+1
diff --git a/tools/gdbjithelper/gdbjithelper.c b/tools/gdbjithelper/gdbjithelper.c
new file mode 100644
index 0000000..817d5a4
--- /dev/null
+++ b/tools/gdbjithelper/gdbjithelper.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+
+/* Currently debuggerd dumps 20 words each around PC and LR */
+#define NUM_DUMPED_WORDS 20
+
+volatile int done;
+
+/*
+ * See README.txt for detailed steps.
+ *
+ * If you see a native crash in the bugreport and the PC/LR are
+ * pointing to the code cache address range, copy them into the following
+ * arrays.
+ *
+ *        #00  pc 463ba204
+ *        #01  lr 463ba1c9  <unknown>
+ *
+ * code around pc:
+ * 463ba1e4 4300e119 4284aa7a f927f7b7 40112268
+ * 463ba1f4 419da7f8 00002000 01000100 00080000
+ * 463ba204 4191debc 01010000 4284aa74 68b00054
+ * 463ba214 045cf205 cc016468 0718f2a5 d0102800
+ * 463ba224 4c13c701 a20aa108 efb0f775 e008e010
+ *
+ * code around lr:
+ * 463ba1a8 42e19e58 f2050050 cc01045c 0718f2a5
+ * 463ba1b8 d00f2800 4c13c701 a20aa108 efe4f775
+ * 463ba1c8 e007e010 29006bf8 6e77dc01 a10347b8
+ * 463ba1d8 ef60f775 6db1480b 1c2d4788 4300e119
+ * 463ba1e8 4284aa7a f927f7b7 40112268 419da7f8
+ *
+ */
+
+int codePC[] = {
+    // Sample content
+    0x4300e119, 0x4284aa7a, 0xf927f7b7, 0x40112268,
+    0x419da7f8, 0x00002000, 0x01000100, 0x00080000,
+    0x4191debc, 0x01010000, 0x4284aa74, 0x68b00054,
+    0x045cf205, 0xcc016468, 0x0718f2a5, 0xd0102800,
+    0x4c13c701, 0xa20aa108, 0xefb0f775, 0xe008e010,
+};
+
+int codeLR[] = {
+    // Sample content
+    0x42e19e58, 0xf2050050, 0xcc01045c, 0x0718f2a5,
+    0xd00f2800, 0x4c13c701, 0xa20aa108, 0xefe4f775,
+    0xe007e010, 0x29006bf8, 0x6e77dc01, 0xa10347b8,
+    0xef60f775, 0x6db1480b, 0x1c2d4788, 0x4300e119,
+    0x4284aa7a, 0xf927f7b7, 0x40112268, 0x419da7f8,
+};
+
+/* For example: 463ba1e4 & 0xfff */
+#define START_PC_PAGE_OFFSET 0x1e4
+
+/* For example: 463ba1a8 & 0xfff */
+#define START_LR_PAGE_OFFSET 0x1a8
+
+/* Each points to a two-page buffer */
+char *codePCCache, *codeLRCache;
+
+void dumpCode(int *pc, int *lr)
+{
+    unsigned int i;
+
+    for (i = 0; i < NUM_DUMPED_WORDS; i++) {
+        printf("%p codePC[%d]: %#010x\n", pc + i, i, pc[i]);
+    }
+
+    for (i = 0; i < NUM_DUMPED_WORDS; i++) {
+        printf("%p codeLR[%d]: %#010x\n", lr + i, i, lr[i]);
+    }
+}
+
+int main()
+{
+    codePCCache = memalign(4096, 8192);
+    codeLRCache = memalign(4096, 8192);
+
+    memcpy(codePCCache + START_PC_PAGE_OFFSET, codePC, 4 * NUM_DUMPED_WORDS);
+    memcpy(codeLRCache + START_LR_PAGE_OFFSET, codeLR, 4 * NUM_DUMPED_WORDS);
+
+    dumpCode((int *) (codePCCache + START_PC_PAGE_OFFSET),
+             (int *) (codeLRCache + START_LR_PAGE_OFFSET));
+
+    while (!done) {
+        sleep(1000);
+    }
+    return 0;
+}
diff --git a/tools/get-hprof b/tools/get-hprof
new file mode 100755
index 0000000..d56d7ad
--- /dev/null
+++ b/tools/get-hprof
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# 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.
+
+# Grab an hprof file using adb. If an argument is specified, grab
+# the so-named file. If no argument is specified, grab the last such file
+# as found by using "ls".
+
+FILE_BASE="$1"
+if [ "x$FILE_BASE" = "x" ]; then
+    # Note: substr() is to get rid of the final carriage return.
+    FILE_BASE=`adb shell ls -l '/data/misc/heap-dump*.hprof' | tail -1 | \
+	awk '{ printf("%s", substr($7, 1, length($7) - 1)); }'`
+    if [ "x$FILE_BASE" = "x" ]; then
+        echo "No file base defined."
+        exit 1
+    fi
+fi
+
+FILE_BASE=/data/misc/${FILE_BASE}
+OUT_FILE=heap-dump.hprof
+
+adb pull "$FILE_BASE" "$OUT_FILE"
+if [ $? -ne 0 ]; then
+    echo "Failed pulling $FILE_BASE."
+    exit 1
+fi
+echo "hat $OUT_FILE"
+exit 0
diff --git a/tools/hprof-conv/Android.mk b/tools/hprof-conv/Android.mk
new file mode 100644
index 0000000..dad399e
--- /dev/null
+++ b/tools/hprof-conv/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := HprofConv.c
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := hprof-conv
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/hprof-conv/HprofConv.c b/tools/hprof-conv/HprofConv.c
new file mode 100644
index 0000000..02cb7f4
--- /dev/null
+++ b/tools/hprof-conv/HprofConv.c
@@ -0,0 +1,718 @@
+/*
+ * 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.
+ */
+
+/*
+ * Strip Android-specific records out of hprof data, back-converting from
+ * 1.0.3 to 1.0.2.  This removes some useful information, but allows
+ * Android hprof data to be handled by widely-available tools (like "jhat").
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+
+//#define VERBOSE_DEBUG
+#ifdef VERBOSE_DEBUG
+# define DBUG(...) fprintf(stderr, __VA_ARGS__)
+#else
+# define DBUG(...)
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE (!FALSE)
+#endif
+
+typedef enum HprofBasicType {
+    HPROF_BASIC_OBJECT = 2,
+    HPROF_BASIC_BOOLEAN = 4,
+    HPROF_BASIC_CHAR = 5,
+    HPROF_BASIC_FLOAT = 6,
+    HPROF_BASIC_DOUBLE = 7,
+    HPROF_BASIC_BYTE = 8,
+    HPROF_BASIC_SHORT = 9,
+    HPROF_BASIC_INT = 10,
+    HPROF_BASIC_LONG = 11,
+} HprofBasicType;
+
+typedef enum HprofTag {
+    /* tags we must handle specially */
+    HPROF_TAG_HEAP_DUMP                 = 0x0c,
+    HPROF_TAG_HEAP_DUMP_SEGMENT         = 0x1c,
+} HprofTag;
+
+typedef enum HprofHeapTag {
+    /* 1.0.2 tags */
+    HPROF_ROOT_UNKNOWN                  = 0xff,
+    HPROF_ROOT_JNI_GLOBAL               = 0x01,
+    HPROF_ROOT_JNI_LOCAL                = 0x02,
+    HPROF_ROOT_JAVA_FRAME               = 0x03,
+    HPROF_ROOT_NATIVE_STACK             = 0x04,
+    HPROF_ROOT_STICKY_CLASS             = 0x05,
+    HPROF_ROOT_THREAD_BLOCK             = 0x06,
+    HPROF_ROOT_MONITOR_USED             = 0x07,
+    HPROF_ROOT_THREAD_OBJECT            = 0x08,
+    HPROF_CLASS_DUMP                    = 0x20,
+    HPROF_INSTANCE_DUMP                 = 0x21,
+    HPROF_OBJECT_ARRAY_DUMP             = 0x22,
+    HPROF_PRIMITIVE_ARRAY_DUMP          = 0x23,
+
+    /* Android 1.0.3 tags */
+    HPROF_HEAP_DUMP_INFO                = 0xfe,
+    HPROF_ROOT_INTERNED_STRING          = 0x89,
+    HPROF_ROOT_FINALIZING               = 0x8a,
+    HPROF_ROOT_DEBUGGER                 = 0x8b,
+    HPROF_ROOT_REFERENCE_CLEANUP        = 0x8c,
+    HPROF_ROOT_VM_INTERNAL              = 0x8d,
+    HPROF_ROOT_JNI_MONITOR              = 0x8e,
+    HPROF_UNREACHABLE                   = 0x90,  /* deprecated */
+    HPROF_PRIMITIVE_ARRAY_NODATA_DUMP   = 0xc3,
+} HprofHeapTag;
+
+#define kIdentSize  4
+#define kRecHdrLen  9
+
+
+/*
+ * ===========================================================================
+ *      Expanding buffer
+ * ===========================================================================
+ */
+
+/* simple struct */
+typedef struct {
+    unsigned char* storage;
+    size_t curLen;
+    size_t maxLen;
+} ExpandBuf;
+
+/*
+ * Create an ExpandBuf.
+ */
+static ExpandBuf* ebAlloc(void)
+{
+    static const int kInitialSize = 64;
+
+    ExpandBuf* newBuf = (ExpandBuf*) malloc(sizeof(ExpandBuf));
+    if (newBuf == NULL)
+        return NULL;
+    newBuf->storage = (unsigned char*) malloc(kInitialSize);
+    newBuf->curLen = 0;
+    newBuf->maxLen = kInitialSize;
+
+    return newBuf;
+}
+
+/*
+ * Release the storage associated with an ExpandBuf.
+ */
+static void ebFree(ExpandBuf* pBuf)
+{
+    if (pBuf != NULL) {
+        free(pBuf->storage);
+        free(pBuf);
+    }
+}
+
+/*
+ * Return a pointer to the data buffer.
+ *
+ * The pointer may change as data is added to the buffer, so this value
+ * should not be cached.
+ */
+static inline unsigned char* ebGetBuffer(ExpandBuf* pBuf)
+{
+    return pBuf->storage;
+}
+
+/*
+ * Get the amount of data currently in the buffer.
+ */
+static inline size_t ebGetLength(ExpandBuf* pBuf)
+{
+    return pBuf->curLen;
+}
+
+/*
+ * Empty the buffer.
+ */
+static void ebClear(ExpandBuf* pBuf)
+{
+    pBuf->curLen = 0;
+}
+
+/*
+ * Ensure that the buffer can hold at least "size" additional bytes.
+ */
+static int ebEnsureCapacity(ExpandBuf* pBuf, int size)
+{
+    assert(size > 0);
+
+    if (pBuf->curLen + size > pBuf->maxLen) {
+        int newSize = pBuf->curLen + size + 128;    /* oversize slightly */
+        unsigned char* newStorage = realloc(pBuf->storage, newSize);
+        if (newStorage == NULL) {
+            fprintf(stderr, "ERROR: realloc failed on size=%d\n", newSize);
+            return -1;
+        }
+
+        pBuf->storage = newStorage;
+        pBuf->maxLen = newSize;
+    }
+
+    assert(pBuf->curLen + size <= pBuf->maxLen);
+    return 0;
+}
+
+/*
+ * Add data to the buffer after ensuring it can hold it.
+ */
+static int ebAddData(ExpandBuf* pBuf, const void* data, size_t count)
+{
+    ebEnsureCapacity(pBuf, count);
+    memcpy(pBuf->storage + pBuf->curLen, data, count);
+    pBuf->curLen += count;
+    return 0;
+}
+
+/*
+ * Read a NULL-terminated string from the input.
+ */
+static int ebReadString(ExpandBuf* pBuf, FILE* in)
+{
+    int ic;
+
+    do {
+        ebEnsureCapacity(pBuf, 1);
+
+        ic = getc(in);
+        if (feof(in) || ferror(in)) {
+            fprintf(stderr, "ERROR: failed reading input\n");
+            return -1;
+        }
+
+        pBuf->storage[pBuf->curLen++] = (unsigned char) ic;
+    } while (ic != 0);
+
+    return 0;
+}
+
+/*
+ * Read some data, adding it to the expanding buffer.
+ *
+ * This will ensure that the buffer has enough space to hold the new data
+ * (plus the previous contents).
+ */
+static int ebReadData(ExpandBuf* pBuf, FILE* in, size_t count, int eofExpected)
+{
+    size_t actual;
+
+    assert(count > 0);
+
+    ebEnsureCapacity(pBuf, count);
+    actual = fread(pBuf->storage + pBuf->curLen, 1, count, in);
+    if (actual != count) {
+        if (eofExpected && feof(in) && !ferror(in)) {
+            /* return without reporting an error */
+        } else {
+            fprintf(stderr, "ERROR: read %d of %d bytes\n", actual, count);
+            return -1;
+        }
+    }
+
+    pBuf->curLen += count;
+    assert(pBuf->curLen <= pBuf->maxLen);
+
+    return 0;
+}
+
+/*
+ * Write the data from the buffer.  Resets the data count to zero.
+ */
+static int ebWriteData(ExpandBuf* pBuf, FILE* out)
+{
+    size_t actual;
+
+    assert(pBuf->curLen > 0);
+    assert(pBuf->curLen <= pBuf->maxLen);
+
+    actual = fwrite(pBuf->storage, 1, pBuf->curLen, out);
+    if (actual != pBuf->curLen) {
+        fprintf(stderr, "ERROR: write %d of %d bytes\n", actual, pBuf->curLen);
+        return -1;
+    }
+
+    pBuf->curLen = 0;
+
+    return 0;
+}
+
+
+/*
+ * ===========================================================================
+ *      Hprof stuff
+ * ===========================================================================
+ */
+
+/*
+ * Get a 2-byte value, in big-endian order, from memory.
+ */
+static uint16_t get2BE(const unsigned char* buf)
+{
+    uint16_t val;
+
+    val = (buf[0] << 8) | buf[1];
+    return val;
+}
+
+/*
+ * Get a 4-byte value, in big-endian order, from memory.
+ */
+static uint32_t get4BE(const unsigned char* buf)
+{
+    uint32_t val;
+
+    val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+    return val;
+}
+
+/*
+ * Set a 4-byte value, in big-endian order.
+ */
+static void set4BE(unsigned char* buf, uint32_t val)
+{
+    buf[0] = val >> 24;
+    buf[1] = val >> 16;
+    buf[2] = val >> 8;
+    buf[3] = val;
+}
+
+/*
+ * Get the size, in bytes, of one of the "basic types".
+ */
+static int computeBasicLen(HprofBasicType basicType)
+{
+    static const int sizes[] = { -1, -1, 4, -1, 1, 2, 4, 8, 1, 2, 4, 8  };
+    static const size_t maxSize = sizeof(sizes) / sizeof(sizes[0]);
+
+    assert(basicType >= 0);
+    if (basicType >= maxSize)
+        return -1;
+    return sizes[basicType];
+}
+
+/*
+ * Compute the length of a HPROF_CLASS_DUMP block.
+ */
+static int computeClassDumpLen(const unsigned char* origBuf, int len)
+{
+    const unsigned char* buf = origBuf;
+    int blockLen = 0;
+    int i, count;
+
+    blockLen += kIdentSize * 7 + 8;
+    buf += blockLen;
+    len -= blockLen;
+
+    if (len < 0)
+        return -1;
+
+    count = get2BE(buf);
+    buf += 2;
+    len -= 2;
+    DBUG("CDL: 1st count is %d\n", count);
+    for (i = 0; i < count; i++) {
+        HprofBasicType basicType;
+        int basicLen;
+
+        basicType = buf[2];
+        basicLen = computeBasicLen(basicType);
+        if (basicLen < 0) {
+            DBUG("ERROR: invalid basicType %d\n", basicType);
+            return -1;
+        }
+
+        buf += 2 + 1 + basicLen;
+        len -= 2 + 1 + basicLen;
+        if (len < 0)
+            return -1;
+    }
+
+    count = get2BE(buf);
+    buf += 2;
+    len -= 2;
+    DBUG("CDL: 2nd count is %d\n", count);
+    for (i = 0; i < count; i++) {
+        HprofBasicType basicType;
+        int basicLen;
+
+        basicType = buf[kIdentSize];
+        basicLen = computeBasicLen(basicType);
+        if (basicLen < 0) {
+            fprintf(stderr, "ERROR: invalid basicType %d\n", basicType);
+            return -1;
+        }
+
+        buf += kIdentSize + 1 + basicLen;
+        len -= kIdentSize + 1 + basicLen;
+        if (len < 0)
+            return -1;
+    }
+
+    count = get2BE(buf);
+    buf += 2;
+    len -= 2;
+    DBUG("CDL: 3rd count is %d\n", count);
+    for (i = 0; i < count; i++) {
+        buf += kIdentSize + 1;
+        len -= kIdentSize + 1;
+        if (len < 0)
+            return -1;
+    }
+
+    DBUG("Total class dump len: %d\n", buf - origBuf);
+    return buf - origBuf;
+}
+
+/*
+ * Compute the length of a HPROF_INSTANCE_DUMP block.
+ */
+static int computeInstanceDumpLen(const unsigned char* origBuf, int len)
+{
+    int extraCount = get4BE(origBuf + kIdentSize * 2 + 4);
+    return kIdentSize * 2 + 8 + extraCount;
+}
+
+/*
+ * Compute the length of a HPROF_OBJECT_ARRAY_DUMP block.
+ */
+static int computeObjectArrayDumpLen(const unsigned char* origBuf, int len)
+{
+    int arrayCount = get4BE(origBuf + kIdentSize + 4);
+    return kIdentSize * 2 + 8 + arrayCount * kIdentSize;
+}
+
+/*
+ * Compute the length of a HPROF_PRIMITIVE_ARRAY_DUMP block.
+ */
+static int computePrimitiveArrayDumpLen(const unsigned char* origBuf, int len)
+{
+    int arrayCount = get4BE(origBuf + kIdentSize + 4);
+    HprofBasicType basicType = origBuf[kIdentSize + 8];
+    int basicLen = computeBasicLen(basicType);
+
+    return kIdentSize + 9 + arrayCount * basicLen;
+}
+
+/*
+ * Crunch through a heap dump record, writing the original or converted
+ * data to "out".
+ */
+static int processHeapDump(ExpandBuf* pBuf, FILE* out)
+{
+    ExpandBuf* pOutBuf = ebAlloc();
+    unsigned char* origBuf = ebGetBuffer(pBuf);
+    unsigned char* buf = origBuf;
+    int len = ebGetLength(pBuf);
+    int result = -1;
+
+    pBuf = NULL;        /* we just use the raw pointer from here forward */
+
+    /* copy the original header to the output buffer */
+    if (ebAddData(pOutBuf, buf, kRecHdrLen) != 0)
+        goto bail;
+
+    buf += kRecHdrLen;      /* skip past record header */
+    len -= kRecHdrLen;
+
+    while (len > 0) {
+        unsigned char subType = buf[0];
+        int justCopy = TRUE;
+        int subLen;
+
+        DBUG("--- 0x%02x  ", subType);
+        switch (subType) {
+        /* 1.0.2 types */
+        case HPROF_ROOT_UNKNOWN:
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_JNI_GLOBAL:
+            subLen = kIdentSize * 2;
+            break;
+        case HPROF_ROOT_JNI_LOCAL:
+            subLen = kIdentSize + 8;
+            break;
+        case HPROF_ROOT_JAVA_FRAME:
+            subLen = kIdentSize + 8;
+            break;
+        case HPROF_ROOT_NATIVE_STACK:
+            subLen = kIdentSize + 4;
+            break;
+        case HPROF_ROOT_STICKY_CLASS:
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_THREAD_BLOCK:
+            subLen = kIdentSize + 4;
+            break;
+        case HPROF_ROOT_MONITOR_USED:
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_THREAD_OBJECT:
+            subLen = kIdentSize + 8;
+            break;
+        case HPROF_CLASS_DUMP:
+            subLen = computeClassDumpLen(buf+1, len-1);
+            break;
+        case HPROF_INSTANCE_DUMP:
+            subLen = computeInstanceDumpLen(buf+1, len-1);
+            break;
+        case HPROF_OBJECT_ARRAY_DUMP:
+            subLen = computeObjectArrayDumpLen(buf+1, len-1);
+            break;
+        case HPROF_PRIMITIVE_ARRAY_DUMP:
+            subLen = computePrimitiveArrayDumpLen(buf+1, len-1);
+            break;
+
+        /* these were added for Android in 1.0.3 */
+        case HPROF_HEAP_DUMP_INFO:
+            justCopy = FALSE;
+            subLen = kIdentSize + 4;
+            // no 1.0.2 equivalent for this
+            break;
+        case HPROF_ROOT_INTERNED_STRING:
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_FINALIZING:
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_DEBUGGER:
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_REFERENCE_CLEANUP:
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_VM_INTERNAL:
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            subLen = kIdentSize;
+            break;
+        case HPROF_ROOT_JNI_MONITOR:
+            /* keep the ident, drop the next 8 bytes */
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            justCopy = FALSE;
+            ebAddData(pOutBuf, buf, 1 + kIdentSize);
+            subLen = kIdentSize + 8;
+            break;
+        case HPROF_UNREACHABLE:
+            buf[0] = HPROF_ROOT_UNKNOWN;
+            subLen = kIdentSize;
+            break;
+        case HPROF_PRIMITIVE_ARRAY_NODATA_DUMP:
+            buf[0] = HPROF_PRIMITIVE_ARRAY_DUMP;
+            buf[5] = buf[6] = buf[7] = buf[8] = 0;  /* set array len to 0 */
+            subLen = kIdentSize + 9;
+            break;
+
+        /* shouldn't get here */
+        default:
+            fprintf(stderr, "ERROR: unexpected subtype 0x%02x at offset %d\n",
+                subType, buf - origBuf);
+            goto bail;
+        }
+
+        if (justCopy) {
+            /* copy source data */
+            DBUG("(%d)\n", 1 + subLen);
+            ebAddData(pOutBuf, buf, 1 + subLen);
+        } else {
+            /* other data has been written, or the sub-record omitted */
+            DBUG("(adv %d)\n", 1 + subLen);
+        }
+
+        /* advance to next entry */
+        buf += 1 + subLen;
+        len -= 1 + subLen;
+    }
+
+    /*
+     * Update the record length.
+     */
+    set4BE(ebGetBuffer(pOutBuf) + 5, ebGetLength(pOutBuf) - kRecHdrLen);
+
+    if (ebWriteData(pOutBuf, out) != 0)
+        goto bail;
+
+    result = 0;
+
+bail:
+    ebFree(pOutBuf);
+    return result;
+}
+
+/*
+ * Filter an hprof data file.
+ */
+static int filterData(FILE* in, FILE* out)
+{
+    ExpandBuf* pBuf;
+    int result = -1;
+
+    pBuf = ebAlloc();
+    if (pBuf == NULL)
+        goto bail;
+
+    /*
+     * Start with the header.
+     */
+    if (ebReadString(pBuf, in) != 0)
+        goto bail;
+
+    if (strcmp((const char*)ebGetBuffer(pBuf), "JAVA PROFILE 1.0.3") != 0) {
+        fprintf(stderr, "ERROR: expecting 1.0.3\n");
+        goto bail;
+    }
+
+    /* downgrade to 1.0.2 */
+    (ebGetBuffer(pBuf))[17] = '2';
+    if (ebWriteData(pBuf, out) != 0)
+        goto bail;
+
+    /*
+     * Copy:
+     * (4b) identifier size, always 4
+     * (8b) file creation date
+     */
+    if (ebReadData(pBuf, in, 12, FALSE) != 0)
+        goto bail;
+    if (ebWriteData(pBuf, out) != 0)
+        goto bail;
+
+    /*
+     * Read records until we hit EOF.  Each record begins with:
+     * (1b) type
+     * (4b) timestamp
+     * (4b) length of data that follows
+     */
+    while (1) {
+        assert(ebGetLength(pBuf) == 0);
+
+        /* read type char */
+        if (ebReadData(pBuf, in, 1, TRUE) != 0)
+            goto bail;
+        if (feof(in))
+            break;
+
+        /* read the rest of the header */
+        if (ebReadData(pBuf, in, kRecHdrLen-1, FALSE) != 0)
+            goto bail;
+
+        unsigned char* buf = ebGetBuffer(pBuf);
+        unsigned char type;
+        unsigned int timestamp, length;
+
+        type = buf[0];
+        timestamp = get4BE(buf + 1);
+        length = get4BE(buf + 5);
+        buf = NULL;     /* ptr invalid after next read op */
+
+        /* read the record data */
+        if (length != 0) {
+            if (ebReadData(pBuf, in, length, FALSE) != 0)
+                goto bail;
+        }
+
+        if (type == HPROF_TAG_HEAP_DUMP ||
+            type == HPROF_TAG_HEAP_DUMP_SEGMENT)
+        {
+            DBUG("Processing heap dump 0x%02x (%d bytes)\n",
+                type, length);
+            if (processHeapDump(pBuf, out) != 0)
+                goto bail;
+            ebClear(pBuf);
+        } else {
+            /* keep */
+            DBUG("Keeping 0x%02x (%d bytes)\n", type, length);
+            if (ebWriteData(pBuf, out) != 0)
+                goto bail;
+        }
+    }
+
+    result = 0;
+
+bail:
+    ebFree(pBuf);
+    return result;
+}
+
+/*
+ * Get args.
+ */
+int main(int argc, char** argv)
+{
+    FILE* in = stdin;
+    FILE* out = stdout;
+    int cc;
+
+    if (argc != 3) {
+        fprintf(stderr, "Usage: hprof-conf infile outfile\n\n");
+        fprintf(stderr,
+            "Specify '-' for either or both to use stdin/stdout.\n\n");
+
+        fprintf(stderr,
+            "Copyright (C) 2009 The Android Open Source Project\n\n"
+            "This software is built from source code licensed under the "
+            "Apache License,\n"
+            "Version 2.0 (the \"License\"). You may obtain a copy of the "
+            "License at\n\n"
+            "     http://www.apache.org/licenses/LICENSE-2.0\n\n"
+            "See the associated NOTICE file for this software for further "
+            "details.\n");
+
+        return 2;
+    }
+
+    if (strcmp(argv[1], "-") != 0) {
+        in = fopen(argv[1], "rb");
+        if (in == NULL) {
+            fprintf(stderr, "ERROR: failed to open input '%s': %s\n",
+                argv[1], strerror(errno));
+            return 1;
+        }
+    }
+    if (strcmp(argv[2], "-") != 0) {
+        out = fopen(argv[2], "wb");
+        if (out == NULL) {
+            fprintf(stderr, "ERROR: failed to open output '%s': %s\n",
+                argv[2], strerror(errno));
+            if (in != stdin)
+                fclose(in);
+            return 1;
+        }
+    }
+
+    cc = filterData(in, out);
+
+    if (in != stdin)
+        fclose(in);
+    if (out != stdout)
+        fclose(out);
+    return (cc != 0);
+}
diff --git a/unit-tests/Android.mk b/unit-tests/Android.mk
new file mode 100644
index 0000000..62b666a
--- /dev/null
+++ b/unit-tests/Android.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# Copyright The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+test_module = dalvik-vm-unit-tests
+test_tags = eng tests
+
+test_src_files = \
+    dvmHumanReadableDescriptor_test.cpp \
+    
+test_c_includes = \
+    dalvik \
+    dalvik/vm \
+
+# Build for the device. Run with:
+#   adb shell /data/nativetest/dalvik-vm-unit-tests/dalvik-vm-unit-tests
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_SMP=1
+LOCAL_C_INCLUDES += $(test_c_includes)
+LOCAL_MODULE := $(test_module)
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES += libcutils libdvm
+include $(BUILD_NATIVE_TEST)
+
+# Build for the host.
+# TODO: BUILD_HOST_NATIVE_TEST doesn't work yet; STL-related compile-time and
+# run-time failures, presumably astl/stlport/genuine host STL confusion.
+#include $(CLEAR_VARS)
+#LOCAL_C_INCLUDES += $(test_c_includes)
+#LOCAL_MODULE := $(test_module)
+#LOCAL_MODULE_TAGS := $(test_tags)
+#LOCAL_SRC_FILES := $(test_src_files)
+#LOCAL_SHARED_LIBRARIES += libdvm libcrypto libssl libicuuc libicui18n
+#LOCAL_WHOLE_STATIC_LIBRARIES += libcutils liblog libdvm
+#include $(BUILD_HOST_NATIVE_TEST)
diff --git a/unit-tests/dvmHumanReadableDescriptor_test.cpp b/unit-tests/dvmHumanReadableDescriptor_test.cpp
new file mode 100644
index 0000000..89ca85c
--- /dev/null
+++ b/unit-tests/dvmHumanReadableDescriptor_test.cpp
@@ -0,0 +1,43 @@
+#include <gtest/gtest.h>
+
+#include "Dalvik.h"
+
+TEST(dvmHumanReadableDescriptor, ArrayReferences) {
+  ASSERT_EQ("java.lang.Class[]", dvmHumanReadableDescriptor("[Ljava/lang/Class;"));
+  ASSERT_EQ("java.lang.Class[][]", dvmHumanReadableDescriptor("[[Ljava/lang/Class;"));
+}
+
+TEST(dvmHumanReadableDescriptor, ScalarReferences) {
+  ASSERT_EQ("java.lang.String", dvmHumanReadableDescriptor("Ljava.lang.String;"));
+  ASSERT_EQ("java.lang.String", dvmHumanReadableDescriptor("Ljava/lang/String;"));
+}
+
+TEST(dvmHumanReadableDescriptor, PrimitiveArrays) {
+  ASSERT_EQ("boolean[]", dvmHumanReadableDescriptor("[Z"));
+  ASSERT_EQ("boolean[][]", dvmHumanReadableDescriptor("[[Z"));
+  ASSERT_EQ("byte[]", dvmHumanReadableDescriptor("[B"));
+  ASSERT_EQ("byte[][]", dvmHumanReadableDescriptor("[[B"));
+  ASSERT_EQ("char[]", dvmHumanReadableDescriptor("[C"));
+  ASSERT_EQ("char[][]", dvmHumanReadableDescriptor("[[C"));
+  ASSERT_EQ("double[]", dvmHumanReadableDescriptor("[D"));
+  ASSERT_EQ("double[][]", dvmHumanReadableDescriptor("[[D"));
+  ASSERT_EQ("float[]", dvmHumanReadableDescriptor("[F"));
+  ASSERT_EQ("float[][]", dvmHumanReadableDescriptor("[[F"));
+  ASSERT_EQ("int[]", dvmHumanReadableDescriptor("[I"));
+  ASSERT_EQ("int[][]", dvmHumanReadableDescriptor("[[I"));
+  ASSERT_EQ("long[]", dvmHumanReadableDescriptor("[J"));
+  ASSERT_EQ("long[][]", dvmHumanReadableDescriptor("[[J"));
+  ASSERT_EQ("short[]", dvmHumanReadableDescriptor("[S"));
+  ASSERT_EQ("short[][]", dvmHumanReadableDescriptor("[[S"));
+}
+
+TEST(dvmHumanReadableDescriptor, PrimitiveScalars) {
+  ASSERT_EQ("boolean", dvmHumanReadableDescriptor("Z"));
+  ASSERT_EQ("byte", dvmHumanReadableDescriptor("B"));
+  ASSERT_EQ("char", dvmHumanReadableDescriptor("C"));
+  ASSERT_EQ("double", dvmHumanReadableDescriptor("D"));
+  ASSERT_EQ("float", dvmHumanReadableDescriptor("F"));
+  ASSERT_EQ("int", dvmHumanReadableDescriptor("I"));
+  ASSERT_EQ("long", dvmHumanReadableDescriptor("J"));
+  ASSERT_EQ("short", dvmHumanReadableDescriptor("S"));
+}
diff --git a/vm/AllocTracker.cpp b/vm/AllocTracker.cpp
new file mode 100644
index 0000000..a9c7644
--- /dev/null
+++ b/vm/AllocTracker.cpp
@@ -0,0 +1,654 @@
+/*
+ * 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.
+ */
+
+/*
+ * Allocation tracking and reporting.  We maintain a circular buffer with
+ * the most recent allocations.  The data can be viewed through DDMS.
+ *
+ * There are two basic approaches: manage the buffer with atomic updates
+ * and do a system-wide suspend when DDMS requests it, or protect all
+ * accesses with a mutex.  The former is potentially more efficient, but
+ * the latter is much simpler and more reliable.
+ *
+ * Ideally we'd just use the object heap allocation mutex to guard this
+ * structure, but at the point we grab that (under dvmMalloc()) we're just
+ * allocating a collection of bytes and no longer have the class reference.
+ * Because this is an optional feature it's best to leave the existing
+ * code undisturbed and just use an additional lock.
+ *
+ * We don't currently track allocations of class objects.  We could, but
+ * with the possible exception of Proxy objects they're not that interesting.
+ *
+ * TODO: if we add support for class unloading, we need to add the class
+ * references here to the root set (or just disable class unloading while
+ * this is active).
+ *
+ * TODO: consider making the parameters configurable, so DDMS can decide
+ * how many allocations it wants to see and what the stack depth should be.
+ * Changing the window size is easy, changing the max stack depth is harder
+ * because we go from an array of fixed-size structs to variable-sized data.
+ */
+#include "Dalvik.h"
+
+#define kMaxAllocRecordStackDepth   16      /* max 255 */
+#define kNumAllocRecords            512     /* MUST be power of 2 */
+
+/*
+ * Record the details of an allocation.
+ */
+struct AllocRecord {
+    ClassObject*    clazz;      /* class allocated in this block */
+    u4              size;       /* total size requested */
+    u2              threadId;   /* simple thread ID; could be recycled */
+
+    /* stack trace elements; unused entries have method==NULL */
+    struct {
+        const Method* method;   /* which method we're executing in */
+        int         pc;         /* current execution offset, in 16-bit units */
+    } stackElem[kMaxAllocRecordStackDepth];
+
+    /*
+     * This was going to be either wall-clock time in seconds or monotonic
+     * time in milliseconds since the VM started, to give a rough sense for
+     * how long ago an allocation happened.  This adds a system call per
+     * allocation, which is too much overhead.
+     */
+    //u4      timestamp;
+};
+
+/*
+ * Initialize a few things.  This gets called early, so keep activity to
+ * a minimum.
+ */
+bool dvmAllocTrackerStartup()
+{
+    /* prep locks */
+    dvmInitMutex(&gDvm.allocTrackerLock);
+
+    /* initialized when enabled by DDMS */
+    assert(gDvm.allocRecords == NULL);
+
+    return true;
+}
+
+/*
+ * Release anything we're holding on to.
+ */
+void dvmAllocTrackerShutdown()
+{
+    free(gDvm.allocRecords);
+    dvmDestroyMutex(&gDvm.allocTrackerLock);
+}
+
+
+/*
+ * ===========================================================================
+ *      Collection
+ * ===========================================================================
+ */
+
+/*
+ * Enable allocation tracking.  Does nothing if tracking is already enabled.
+ *
+ * Returns "true" on success.
+ */
+bool dvmEnableAllocTracker()
+{
+    bool result = true;
+    dvmLockMutex(&gDvm.allocTrackerLock);
+
+    if (gDvm.allocRecords == NULL) {
+        LOGI("Enabling alloc tracker (%d entries, %d frames --> %d bytes)",
+            kNumAllocRecords, kMaxAllocRecordStackDepth,
+            sizeof(AllocRecord) * kNumAllocRecords);
+        gDvm.allocRecordHead = gDvm.allocRecordCount = 0;
+        gDvm.allocRecords =
+            (AllocRecord*) malloc(sizeof(AllocRecord) * kNumAllocRecords);
+
+        if (gDvm.allocRecords == NULL)
+            result = false;
+    }
+
+    dvmUnlockMutex(&gDvm.allocTrackerLock);
+    return result;
+}
+
+/*
+ * Disable allocation tracking.  Does nothing if tracking is not enabled.
+ */
+void dvmDisableAllocTracker()
+{
+    dvmLockMutex(&gDvm.allocTrackerLock);
+
+    if (gDvm.allocRecords != NULL) {
+        free(gDvm.allocRecords);
+        gDvm.allocRecords = NULL;
+    }
+
+    dvmUnlockMutex(&gDvm.allocTrackerLock);
+}
+
+/*
+ * Get the last few stack frames.
+ */
+static void getStackFrames(Thread* self, AllocRecord* pRec)
+{
+    int stackDepth = 0;
+    void* fp;
+
+    fp = self->interpSave.curFrame;
+
+    while ((fp != NULL) && (stackDepth < kMaxAllocRecordStackDepth)) {
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+        const Method* method = saveArea->method;
+
+        if (!dvmIsBreakFrame((u4*) fp)) {
+            pRec->stackElem[stackDepth].method = method;
+            if (dvmIsNativeMethod(method)) {
+                pRec->stackElem[stackDepth].pc = 0;
+            } else {
+                assert(saveArea->xtra.currentPc >= method->insns &&
+                        saveArea->xtra.currentPc <
+                        method->insns + dvmGetMethodInsnsSize(method));
+                pRec->stackElem[stackDepth].pc =
+                    (int) (saveArea->xtra.currentPc - method->insns);
+            }
+            stackDepth++;
+        }
+
+        assert(fp != saveArea->prevFrame);
+        fp = saveArea->prevFrame;
+    }
+
+    /* clear out the rest (normally there won't be any) */
+    while (stackDepth < kMaxAllocRecordStackDepth) {
+        pRec->stackElem[stackDepth].method = NULL;
+        pRec->stackElem[stackDepth].pc = 0;
+        stackDepth++;
+    }
+}
+
+/*
+ * Add a new allocation to the set.
+ */
+void dvmDoTrackAllocation(ClassObject* clazz, size_t size)
+{
+    Thread* self = dvmThreadSelf();
+    if (self == NULL) {
+        LOGW("alloc tracker: no thread");
+        return;
+    }
+
+    dvmLockMutex(&gDvm.allocTrackerLock);
+    if (gDvm.allocRecords == NULL) {
+        dvmUnlockMutex(&gDvm.allocTrackerLock);
+        return;
+    }
+
+    /* advance and clip */
+    if (++gDvm.allocRecordHead == kNumAllocRecords)
+        gDvm.allocRecordHead = 0;
+
+    AllocRecord* pRec = &gDvm.allocRecords[gDvm.allocRecordHead];
+
+    pRec->clazz = clazz;
+    pRec->size = size;
+    pRec->threadId = self->threadId;
+    getStackFrames(self, pRec);
+
+    if (gDvm.allocRecordCount < kNumAllocRecords)
+        gDvm.allocRecordCount++;
+
+    dvmUnlockMutex(&gDvm.allocTrackerLock);
+}
+
+
+/*
+ * ===========================================================================
+ *      Reporting
+ * ===========================================================================
+ */
+
+/*
+The data we send to DDMS contains everything we have recorded.
+
+Message header (all values big-endian):
+  (1b) message header len (to allow future expansion); includes itself
+  (1b) entry header len
+  (1b) stack frame len
+  (2b) number of entries
+  (4b) offset to string table from start of message
+  (2b) number of class name strings
+  (2b) number of method name strings
+  (2b) number of source file name strings
+  For each entry:
+    (4b) total allocation size
+    (2b) threadId
+    (2b) allocated object's class name index
+    (1b) stack depth
+    For each stack frame:
+      (2b) method's class name
+      (2b) method name
+      (2b) method source file
+      (2b) line number, clipped to 32767; -2 if native; -1 if no source
+  (xb) class name strings
+  (xb) method name strings
+  (xb) source file strings
+
+  As with other DDM traffic, strings are sent as a 4-byte length
+  followed by UTF-16 data.
+
+We send up 16-bit unsigned indexes into string tables.  In theory there
+can be (kMaxAllocRecordStackDepth * kNumAllocRecords) unique strings in
+each table, but in practice there should be far fewer.
+
+The chief reason for using a string table here is to keep the size of
+the DDMS message to a minimum.  This is partly to make the protocol
+efficient, but also because we have to form the whole thing up all at
+once in a memory buffer.
+
+We use separate string tables for class names, method names, and source
+files to keep the indexes small.  There will generally be no overlap
+between the contents of these tables.
+*/
+const int kMessageHeaderLen = 15;
+const int kEntryHeaderLen = 9;
+const int kStackFrameLen = 8;
+
+/*
+ * Return the index of the head element.
+ *
+ * We point at the most-recently-written record, so if allocRecordCount is 1
+ * we want to use the current element.  Take "head+1" and subtract count
+ * from it.
+ *
+ * We need to handle underflow in our circular buffer, so we add
+ * kNumAllocRecords and then mask it back down.
+ */
+inline static int headIndex()
+{
+    return (gDvm.allocRecordHead+1 + kNumAllocRecords - gDvm.allocRecordCount)
+        & (kNumAllocRecords-1);
+}
+
+/*
+ * Dump the contents of a PointerSet full of character pointers.
+ */
+static void dumpStringTable(PointerSet* strings)
+{
+    int count = dvmPointerSetGetCount(strings);
+    int i;
+
+    for (i = 0; i < count; i++)
+        printf("  %s\n", (const char*) dvmPointerSetGetEntry(strings, i));
+}
+
+/*
+ * Get the method's source file.  If we don't know it, return "" instead
+ * of a NULL pointer.
+ */
+static const char* getMethodSourceFile(const Method* method)
+{
+    const char* fileName = dvmGetMethodSourceFile(method);
+    if (fileName == NULL)
+        fileName = "";
+    return fileName;
+}
+
+/*
+ * Generate string tables.
+ *
+ * Our source material is UTF-8 string constants from DEX files.  If we
+ * want to be thorough we can generate a hash value for each string and
+ * use the VM hash table implementation, or we can do a quick & dirty job
+ * by just maintaining a list of unique pointers.  If the same string
+ * constant appears in multiple DEX files we'll end up with duplicates,
+ * but in practice this shouldn't matter (and if it does, we can uniq-sort
+ * the result in a second pass).
+ */
+static bool populateStringTables(PointerSet* classNames,
+    PointerSet* methodNames, PointerSet* fileNames)
+{
+    int count = gDvm.allocRecordCount;
+    int idx = headIndex();
+    int classCount, methodCount, fileCount;         /* debug stats */
+
+    classCount = methodCount = fileCount = 0;
+
+    while (count--) {
+        AllocRecord* pRec = &gDvm.allocRecords[idx];
+
+        dvmPointerSetAddEntry(classNames, pRec->clazz->descriptor);
+        classCount++;
+
+        int i;
+        for (i = 0; i < kMaxAllocRecordStackDepth; i++) {
+            if (pRec->stackElem[i].method == NULL)
+                break;
+
+            const Method* method = pRec->stackElem[i].method;
+            dvmPointerSetAddEntry(classNames, method->clazz->descriptor);
+            classCount++;
+            dvmPointerSetAddEntry(methodNames, method->name);
+            methodCount++;
+            dvmPointerSetAddEntry(fileNames, getMethodSourceFile(method));
+            fileCount++;
+        }
+
+        idx = (idx + 1) & (kNumAllocRecords-1);
+    }
+
+    LOGI("class %d/%d, method %d/%d, file %d/%d",
+        dvmPointerSetGetCount(classNames), classCount,
+        dvmPointerSetGetCount(methodNames), methodCount,
+        dvmPointerSetGetCount(fileNames), fileCount);
+
+    return true;
+}
+
+/*
+ * Generate the base info (i.e. everything but the string tables).
+ *
+ * This should be called twice.  On the first call, "ptr" is NULL and
+ * "baseLen" is zero.  The return value is used to allocate a buffer.
+ * On the second call, "ptr" points to a data buffer, and "baseLen"
+ * holds the value from the result of the first call.
+ *
+ * The size of the output data is returned.
+ */
+static size_t generateBaseOutput(u1* ptr, size_t baseLen,
+    const PointerSet* classNames, const PointerSet* methodNames,
+    const PointerSet* fileNames)
+{
+    u1* origPtr = ptr;
+    int count = gDvm.allocRecordCount;
+    int idx = headIndex();
+
+    if (origPtr != NULL) {
+        set1(&ptr[0], kMessageHeaderLen);
+        set1(&ptr[1], kEntryHeaderLen);
+        set1(&ptr[2], kStackFrameLen);
+        set2BE(&ptr[3], count);
+        set4BE(&ptr[5], baseLen);
+        set2BE(&ptr[9], dvmPointerSetGetCount(classNames));
+        set2BE(&ptr[11], dvmPointerSetGetCount(methodNames));
+        set2BE(&ptr[13], dvmPointerSetGetCount(fileNames));
+    }
+    ptr += kMessageHeaderLen;
+
+    while (count--) {
+        AllocRecord* pRec = &gDvm.allocRecords[idx];
+
+        /* compute depth */
+        int  depth;
+        for (depth = 0; depth < kMaxAllocRecordStackDepth; depth++) {
+            if (pRec->stackElem[depth].method == NULL)
+                break;
+        }
+
+        /* output header */
+        if (origPtr != NULL) {
+            set4BE(&ptr[0], pRec->size);
+            set2BE(&ptr[4], pRec->threadId);
+            set2BE(&ptr[6],
+                dvmPointerSetFind(classNames, pRec->clazz->descriptor));
+            set1(&ptr[8], depth);
+        }
+        ptr += kEntryHeaderLen;
+
+        /* convert stack frames */
+        int i;
+        for (i = 0; i < depth; i++) {
+            if (origPtr != NULL) {
+                const Method* method = pRec->stackElem[i].method;
+                int lineNum;
+
+                lineNum = dvmLineNumFromPC(method, pRec->stackElem[i].pc);
+                if (lineNum > 32767)
+                    lineNum = 32767;
+
+                set2BE(&ptr[0], dvmPointerSetFind(classNames,
+                        method->clazz->descriptor));
+                set2BE(&ptr[2], dvmPointerSetFind(methodNames,
+                        method->name));
+                set2BE(&ptr[4], dvmPointerSetFind(fileNames,
+                        getMethodSourceFile(method)));
+                set2BE(&ptr[6], (u2)lineNum);
+            }
+            ptr += kStackFrameLen;
+        }
+
+        idx = (idx + 1) & (kNumAllocRecords-1);
+    }
+
+    return ptr - origPtr;
+}
+
+/*
+ * Compute the size required to store a string table.  Includes the length
+ * word and conversion to UTF-16.
+ */
+static size_t computeStringTableSize(PointerSet* strings)
+{
+    int count = dvmPointerSetGetCount(strings);
+    size_t size = 0;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        const char* str = (const char*) dvmPointerSetGetEntry(strings, i);
+
+        size += 4 + dvmUtf8Len(str) * 2;
+    }
+
+    return size;
+}
+
+/*
+ * Convert a UTF-8 string to UTF-16.  We also need to byte-swap the values
+ * to big-endian, and we can't assume even alignment on the target.
+ *
+ * Returns the string's length, in characters.
+ */
+static int convertUtf8ToUtf16BEUA(u1* utf16Str, const char* utf8Str)
+{
+    u1* origUtf16Str = utf16Str;
+
+    while (*utf8Str != '\0') {
+        u2 utf16 = dexGetUtf16FromUtf8(&utf8Str);       /* advances utf8Str */
+        set2BE(utf16Str, utf16);
+        utf16Str += 2;
+    }
+
+    return (utf16Str - origUtf16Str) / 2;
+}
+
+/*
+ * Output a string table serially.
+ */
+static size_t outputStringTable(PointerSet* strings, u1* ptr)
+{
+    int count = dvmPointerSetGetCount(strings);
+    u1* origPtr = ptr;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        const char* str = (const char*) dvmPointerSetGetEntry(strings, i);
+        int charLen;
+
+        /* copy UTF-8 string to big-endian unaligned UTF-16 */
+        charLen = convertUtf8ToUtf16BEUA(&ptr[4], str);
+        set4BE(&ptr[0], charLen);
+
+        ptr += 4 + charLen * 2;
+    }
+
+    return ptr - origPtr;
+}
+
+/*
+ * Generate a DDM packet with all of the tracked allocation data.
+ *
+ * On success, returns "true" with "*pData" and "*pDataLen" set.
+ */
+bool dvmGenerateTrackedAllocationReport(u1** pData, size_t* pDataLen)
+{
+    bool result = false;
+    u1* buffer = NULL;
+
+    dvmLockMutex(&gDvm.allocTrackerLock);
+
+    /*
+     * Part 1: generate string tables.
+     */
+    PointerSet* classNames = NULL;
+    PointerSet* methodNames = NULL;
+    PointerSet* fileNames = NULL;
+
+    /*
+     * Allocate storage.  Usually there's 60-120 of each thing (sampled
+     * when max=512), but it varies widely and isn't closely bound to
+     * the number of allocations we've captured.  The sets expand quickly
+     * if needed.
+     */
+    classNames = dvmPointerSetAlloc(128);
+    methodNames = dvmPointerSetAlloc(128);
+    fileNames = dvmPointerSetAlloc(128);
+    if (classNames == NULL || methodNames == NULL || fileNames == NULL) {
+        LOGE("Failed allocating pointer sets");
+        goto bail;
+    }
+
+    if (!populateStringTables(classNames, methodNames, fileNames))
+        goto bail;
+
+    if (false) {
+        printf("Classes:\n");
+        dumpStringTable(classNames);
+        printf("Methods:\n");
+        dumpStringTable(methodNames);
+        printf("Files:\n");
+        dumpStringTable(fileNames);
+    }
+
+    /*
+     * Part 2: compute the size of the output.
+     *
+     * (Could also just write to an expanding buffer.)
+     */
+    size_t baseSize, totalSize;
+    baseSize = generateBaseOutput(NULL, 0, classNames, methodNames, fileNames);
+    assert(baseSize > 0);
+    totalSize = baseSize;
+    totalSize += computeStringTableSize(classNames);
+    totalSize += computeStringTableSize(methodNames);
+    totalSize += computeStringTableSize(fileNames);
+    LOGI("Generated AT, size is %zd/%zd", baseSize, totalSize);
+
+    /*
+     * Part 3: allocate a buffer and generate the output.
+     */
+    u1* strPtr;
+
+    buffer = (u1*) malloc(totalSize);
+    strPtr = buffer + baseSize;
+    generateBaseOutput(buffer, baseSize, classNames, methodNames, fileNames);
+    strPtr += outputStringTable(classNames, strPtr);
+    strPtr += outputStringTable(methodNames, strPtr);
+    strPtr += outputStringTable(fileNames, strPtr);
+    if (strPtr - buffer != (int)totalSize) {
+        LOGE("size mismatch (%d vs %zd)", strPtr - buffer, totalSize);
+        dvmAbort();
+    }
+    //dvmPrintHexDump(buffer, totalSize);
+
+    *pData = buffer;
+    *pDataLen = totalSize;
+    buffer = NULL;          // don't free -- caller will own
+    result = true;
+
+bail:
+    dvmPointerSetFree(classNames);
+    dvmPointerSetFree(methodNames);
+    dvmPointerSetFree(fileNames);
+    free(buffer);
+    dvmUnlockMutex(&gDvm.allocTrackerLock);
+    //dvmDumpTrackedAllocations(false);
+    return result;
+}
+
+/*
+ * Dump the tracked allocations to the log file.
+ *
+ * If "enable" is set, we try to enable the feature if it's not already
+ * active.
+ */
+void dvmDumpTrackedAllocations(bool enable)
+{
+    if (enable)
+        dvmEnableAllocTracker();
+
+    dvmLockMutex(&gDvm.allocTrackerLock);
+    if (gDvm.allocRecords == NULL) {
+        dvmUnlockMutex(&gDvm.allocTrackerLock);
+        return;
+    }
+
+    /*
+     * "idx" is the head of the list.  We want to start at the end of the
+     * list and move forward to the tail.
+     */
+    int idx = headIndex();
+    int count = gDvm.allocRecordCount;
+
+    LOGI("Tracked allocations, (head=%d count=%d)",
+        gDvm.allocRecordHead, count);
+    while (count--) {
+        AllocRecord* pRec = &gDvm.allocRecords[idx];
+        LOGI(" T=%-2d %6d %s",
+            pRec->threadId, pRec->size, pRec->clazz->descriptor);
+
+        if (true) {
+            for (int i = 0; i < kMaxAllocRecordStackDepth; i++) {
+                if (pRec->stackElem[i].method == NULL)
+                    break;
+
+                const Method* method = pRec->stackElem[i].method;
+                if (dvmIsNativeMethod(method)) {
+                    LOGI("    %s.%s (Native)",
+                        method->clazz->descriptor, method->name);
+                } else {
+                    LOGI("    %s.%s +%d",
+                        method->clazz->descriptor, method->name,
+                        pRec->stackElem[i].pc);
+                }
+            }
+        }
+
+        /* pause periodically to help logcat catch up */
+        if ((count % 5) == 0)
+            usleep(40000);
+
+        idx = (idx + 1) & (kNumAllocRecords-1);
+    }
+
+    dvmUnlockMutex(&gDvm.allocTrackerLock);
+    if (false) {
+        u1* data;
+        size_t dataLen;
+        if (dvmGenerateTrackedAllocationReport(&data, &dataLen))
+            free(data);
+    }
+}
diff --git a/vm/AllocTracker.h b/vm/AllocTracker.h
new file mode 100644
index 0000000..dede397
--- /dev/null
+++ b/vm/AllocTracker.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+/*
+ * Allocation tracking and reporting.
+ */
+#ifndef DALVIK_ALLOCTRACKER_H_
+#define DALVIK_ALLOCTRACKER_H_
+
+/* initialization */
+bool dvmAllocTrackerStartup(void);
+void dvmAllocTrackerShutdown(void);
+
+struct AllocRecord;
+
+/*
+ * Enable allocation tracking.  Does nothing if tracking is already enabled.
+ */
+bool dvmEnableAllocTracker(void);
+
+/*
+ * Disable allocation tracking.  Does nothing if tracking is not enabled.
+ */
+void dvmDisableAllocTracker(void);
+
+/*
+ * If allocation tracking is enabled, add a new entry to the set.
+ */
+#define dvmTrackAllocation(_clazz, _size)                                   \
+    {                                                                       \
+        if (gDvm.allocRecords != NULL)                                      \
+            dvmDoTrackAllocation(_clazz, _size);                            \
+    }
+void dvmDoTrackAllocation(ClassObject* clazz, size_t size);
+
+/*
+ * Generate a DDM packet with all of the tracked allocation data.
+ *
+ * On success, returns "true" with "*pData" and "*pDataLen" set.  "*pData"
+ * refers to newly-allocated storage that must be freed by the caller.
+ */
+bool dvmGenerateTrackedAllocationReport(u1** pData, size_t* pDataLen);
+
+/*
+ * Dump the tracked allocations to the log file.  If "enable" is set, this
+ * will enable tracking if it's not already on.
+ */
+void dvmDumpTrackedAllocations(bool enable);
+
+#endif  // DALVIK_ALLOCTRACKER_H_
diff --git a/vm/Android.mk b/vm/Android.mk
new file mode 100644
index 0000000..17b5a04
--- /dev/null
+++ b/vm/Android.mk
@@ -0,0 +1,144 @@
+# 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.
+
+#
+# Android.mk for Dalvik VM.
+#
+# This makefile builds both for host and target, and so the very large
+# swath of common definitions are factored out into a separate file to
+# minimize duplication.
+#
+# If you enable or disable optional features here (or in Dvm.mk),
+# rebuild the VM with:
+#
+#  make clean-libdvm clean-libdvm_assert clean-libdvm_sv clean-libdvm_interp
+#  make -j4 libdvm
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build for the target (device).
+#
+
+ifeq ($(TARGET_CPU_SMP),true)
+    target_smp_flag := -DANDROID_SMP=1
+else
+    target_smp_flag := -DANDROID_SMP=0
+endif
+host_smp_flag := -DANDROID_SMP=1
+
+# Build the installed version (libdvm.so) first
+include $(LOCAL_PATH)/ReconfigureDvm.mk
+
+# Overwrite default settings
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libdvm
+LOCAL_CFLAGS += $(target_smp_flag)
+include $(BUILD_SHARED_LIBRARY)
+
+# If WITH_JIT is configured, build multiple versions of libdvm.so to facilitate
+# correctness/performance bugs triage
+ifeq ($(WITH_JIT),true)
+
+    # Derivation #1
+    # Enable assert and JIT tuning
+    include $(LOCAL_PATH)/ReconfigureDvm.mk
+
+    # Enable assertions and JIT-tuning
+    LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \
+                    -DWITH_JIT_TUNING $(target_smp_flag)
+    LOCAL_MODULE := libdvm_assert
+    include $(BUILD_SHARED_LIBRARY)
+
+    # Derivation #2
+    # Enable assert and self-verification
+    include $(LOCAL_PATH)/ReconfigureDvm.mk
+
+    # Enable assertions and JIT self-verification
+    LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT \
+                    -DWITH_SELF_VERIFICATION $(target_smp_flag)
+    LOCAL_MODULE := libdvm_sv
+    include $(BUILD_SHARED_LIBRARY)
+
+    # Derivation #3
+    # Compile out the JIT
+    WITH_JIT := false
+    include $(LOCAL_PATH)/ReconfigureDvm.mk
+
+    LOCAL_CFLAGS += $(target_smp_flag)
+    LOCAL_MODULE := libdvm_interp
+    include $(BUILD_SHARED_LIBRARY)
+
+endif
+
+#
+# Build for the host.
+#
+
+ifeq ($(WITH_HOST_DALVIK),true)
+
+    include $(CLEAR_VARS)
+
+    # Variables used in the included Dvm.mk.
+    dvm_os := $(HOST_OS)
+    dvm_arch := $(HOST_ARCH)
+    # Note: HOST_ARCH_VARIANT isn't defined.
+    dvm_arch_variant := $(HOST_ARCH)
+
+    WITH_JIT := false
+    include $(LOCAL_PATH)/Dvm.mk
+
+    LOCAL_SHARED_LIBRARIES += libcrypto libssl libicuuc libicui18n
+
+    LOCAL_LDLIBS := -lpthread -ldl
+    ifeq ($(HOST_OS),linux)
+      # need this for clock_gettime() in profiling
+      LOCAL_LDLIBS += -lrt
+    endif
+
+    # Build as a WHOLE static library so dependencies are available at link
+    # time. When building this target as a regular static library, certain
+    # dependencies like expat are not found by the linker.
+    LOCAL_WHOLE_STATIC_LIBRARIES += libexpat libcutils libdex liblog libnativehelper libz
+
+    # The libffi from the source tree should never be used by host builds.
+    # The recommendation is that host builds should always either
+    # have sufficient custom code so that libffi isn't needed at all,
+    # or they should use the platform's provided libffi. So, if the common
+    # build rules decided to include it, axe it back out here.
+    ifneq (,$(findstring libffi,$(LOCAL_SHARED_LIBRARIES)))
+        LOCAL_SHARED_LIBRARIES := \
+            $(patsubst libffi, ,$(LOCAL_SHARED_LIBRARIES))
+    endif
+
+    LOCAL_CFLAGS += $(host_smp_flag)
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_MODULE := libdvm
+
+    include $(BUILD_HOST_SHARED_LIBRARY)
+
+    # Copy the dalvik shell script to the host's bin directory
+    include $(CLEAR_VARS)
+    LOCAL_IS_HOST_MODULE := true
+    LOCAL_MODULE_TAGS := optional
+    LOCAL_MODULE_CLASS := EXECUTABLES
+    LOCAL_MODULE := dalvik
+    include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/dalvik | $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+endif
diff --git a/vm/Atomic.cpp b/vm/Atomic.cpp
new file mode 100644
index 0000000..98ff7d0
--- /dev/null
+++ b/vm/Atomic.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+
+#include <cutils/atomic.h>
+
+/*
+ * Quasi-atomic 64-bit operations, for platforms that lack the real thing.
+ *
+ * TODO: unify ARMv6/x86/sh implementations using the to-be-written
+ * spin lock implementation.  We don't want to rely on mutex innards,
+ * and it would be great if all platforms were running the same code.
+ */
+
+#if defined(HAVE_MACOSX_IPC)
+
+#include <libkern/OSAtomic.h>
+
+#if defined(__ppc__)        \
+    || defined(__PPC__)     \
+    || defined(__powerpc__) \
+    || defined(__powerpc)   \
+    || defined(__POWERPC__) \
+    || defined(_M_PPC)      \
+    || defined(__PPC)
+#define NEED_QUASIATOMICS 1
+#else
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+    volatile int64_t* addr)
+{
+    return OSAtomicCompareAndSwap64Barrier(oldvalue, newvalue,
+            (int64_t*)addr) == 0;
+}
+
+
+static inline int64_t dvmQuasiAtomicSwap64Body(int64_t value,
+                                               volatile int64_t* addr)
+{
+    int64_t oldValue;
+    do {
+        oldValue = *addr;
+    } while (dvmQuasiAtomicCas64(oldValue, value, addr));
+    return oldValue;
+}
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+    return dvmQuasiAtomicSwap64Body(value, addr);
+}
+
+int64_t dvmQuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr)
+{
+    int64_t oldValue;
+    ANDROID_MEMBAR_STORE();
+    oldValue = dvmQuasiAtomicSwap64Body(value, addr);
+    /* TUNING: barriers can be avoided on some architectures */
+    ANDROID_MEMBAR_FULL();
+    return oldValue;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+    return OSAtomicAdd64Barrier(0, addr);
+}
+#endif
+
+#elif defined(__i386__) || defined(__x86_64__)
+#define NEED_QUASIATOMICS 1
+
+#elif __arm__
+#include <machine/cpu-features.h>
+
+#ifdef __ARM_HAVE_LDREXD
+static inline int64_t dvmQuasiAtomicSwap64Body(int64_t newvalue,
+                                               volatile int64_t* addr)
+{
+    int64_t prev;
+    int status;
+    do {
+        __asm__ __volatile__ ("@ dvmQuasiAtomicSwap64\n"
+            "ldrexd     %0, %H0, [%3]\n"
+            "strexd     %1, %4, %H4, [%3]"
+            : "=&r" (prev), "=&r" (status), "+m"(*addr)
+            : "r" (addr), "r" (newvalue)
+            : "cc");
+    } while (__builtin_expect(status != 0, 0));
+    return prev;
+}
+
+int64_t dvmQuasiAtomicSwap64(int64_t newvalue, volatile int64_t* addr)
+{
+    return dvmQuasiAtomicSwap64Body(newvalue, addr);
+}
+
+int64_t dvmQuasiAtomicSwap64Sync(int64_t newvalue, volatile int64_t* addr)
+{
+    int64_t prev;
+    ANDROID_MEMBAR_STORE();
+    prev = dvmQuasiAtomicSwap64Body(newvalue, addr);
+    ANDROID_MEMBAR_FULL();
+    return prev;
+}
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+    volatile int64_t* addr)
+{
+    int64_t prev;
+    int status;
+    do {
+        __asm__ __volatile__ ("@ dvmQuasiAtomicCas64\n"
+            "ldrexd     %0, %H0, [%3]\n"
+            "mov        %1, #0\n"
+            "teq        %0, %4\n"
+            "teqeq      %H0, %H4\n"
+            "strexdeq   %1, %5, %H5, [%3]"
+            : "=&r" (prev), "=&r" (status), "+m"(*addr)
+            : "r" (addr), "Ir" (oldvalue), "r" (newvalue)
+            : "cc");
+    } while (__builtin_expect(status != 0, 0));
+    return prev != oldvalue;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+    int64_t value;
+    __asm__ __volatile__ ("@ dvmQuasiAtomicRead64\n"
+        "ldrexd     %0, %H0, [%1]"
+        : "=&r" (value)
+        : "r" (addr));
+    return value;
+}
+
+#else
+
+// on the device, we implement the 64-bit atomic operations through
+// mutex locking. normally, this is bad because we must initialize
+// a pthread_mutex_t before being able to use it, and this means
+// having to do an initialization check on each function call, and
+// that's where really ugly things begin...
+//
+// BUT, as a special twist, we take advantage of the fact that in our
+// pthread library, a mutex is simply a volatile word whose value is always
+// initialized to 0. In other words, simply declaring a static mutex
+// object initializes it !
+//
+// another twist is that we use a small array of mutexes to dispatch
+// the contention locks from different memory addresses
+//
+
+#include <pthread.h>
+
+#define  SWAP_LOCK_COUNT  32U
+static pthread_mutex_t  _swap_locks[SWAP_LOCK_COUNT];
+
+#define  SWAP_LOCK(addr)   \
+   &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
+
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+    int64_t oldValue;
+    pthread_mutex_t*  lock = SWAP_LOCK(addr);
+
+    pthread_mutex_lock(lock);
+
+    oldValue = *addr;
+    *addr    = value;
+
+    pthread_mutex_unlock(lock);
+    return oldValue;
+}
+
+/* Same as dvmQuasiAtomicSwap64 - mutex handles barrier */
+int64_t dvmQuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr)
+{
+    return dvmQuasiAtomicSwap64(value, addr);
+}
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+    volatile int64_t* addr)
+{
+    int result;
+    pthread_mutex_t*  lock = SWAP_LOCK(addr);
+
+    pthread_mutex_lock(lock);
+
+    if (*addr == oldvalue) {
+        *addr  = newvalue;
+        result = 0;
+    } else {
+        result = 1;
+    }
+    pthread_mutex_unlock(lock);
+    return result;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+    int64_t result;
+    pthread_mutex_t*  lock = SWAP_LOCK(addr);
+
+    pthread_mutex_lock(lock);
+    result = *addr;
+    pthread_mutex_unlock(lock);
+    return result;
+}
+
+#endif /*__ARM_HAVE_LDREXD*/
+
+/*****************************************************************************/
+#elif __sh__
+#define NEED_QUASIATOMICS 1
+
+#else
+#error "Unsupported atomic operations for this platform"
+#endif
+
+
+#if NEED_QUASIATOMICS
+
+/* Note that a spinlock is *not* a good idea in general
+ * since they can introduce subtle issues. For example,
+ * a real-time thread trying to acquire a spinlock already
+ * acquired by another thread will never yeld, making the
+ * CPU loop endlessly!
+ *
+ * However, this code is only used on the Linux simulator
+ * so it's probably ok for us.
+ *
+ * The alternative is to use a pthread mutex, but
+ * these must be initialized before being used, and
+ * then you have the problem of lazily initializing
+ * a mutex without any other synchronization primitive.
+ *
+ * TODO: these currently use sched_yield(), which is not guaranteed to
+ * do anything at all.  We need to use dvmIterativeSleep or a wait /
+ * notify mechanism if the initial attempt fails.
+ */
+
+/* global spinlock for all 64-bit quasiatomic operations */
+static int32_t quasiatomic_spinlock = 0;
+
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+    volatile int64_t* addr)
+{
+    int result;
+
+    while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
+#ifdef HAVE_WIN32_THREADS
+        Sleep(0);
+#else
+        sched_yield();
+#endif
+    }
+
+    if (*addr == oldvalue) {
+        *addr = newvalue;
+        result = 0;
+    } else {
+        result = 1;
+    }
+
+    android_atomic_release_store(0, &quasiatomic_spinlock);
+
+    return result;
+}
+
+int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr)
+{
+    int64_t result;
+
+    while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
+#ifdef HAVE_WIN32_THREADS
+        Sleep(0);
+#else
+        sched_yield();
+#endif
+    }
+
+    result = *addr;
+    android_atomic_release_store(0, &quasiatomic_spinlock);
+
+    return result;
+}
+
+int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr)
+{
+    int64_t result;
+
+    while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
+#ifdef HAVE_WIN32_THREADS
+        Sleep(0);
+#else
+        sched_yield();
+#endif
+    }
+
+    result = *addr;
+    *addr = value;
+    android_atomic_release_store(0, &quasiatomic_spinlock);
+
+    return result;
+}
+
+/* Same as dvmQuasiAtomicSwap64 - syscall handles barrier */
+int64_t dvmQuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr)
+{
+    return dvmQuasiAtomicSwap64(value, addr);
+}
+
+#endif /*NEED_QUASIATOMICS*/
diff --git a/vm/Atomic.h b/vm/Atomic.h
new file mode 100644
index 0000000..6f7100b
--- /dev/null
+++ b/vm/Atomic.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+/*
+ * Atomic operations
+ */
+#ifndef DALVIK_ATOMIC_H_
+#define DALVIK_ATOMIC_H_
+
+#include <cutils/atomic.h>          /* use common Android atomic ops */
+#include <cutils/atomic-inline.h>   /* and some uncommon ones */
+
+/*
+ * NOTE: Two "quasiatomic" operations on the exact same memory address
+ * are guaranteed to operate atomically with respect to each other,
+ * but no guarantees are made about quasiatomic operations mixed with
+ * non-quasiatomic operations on the same address, nor about
+ * quasiatomic operations that are performed on partially-overlapping
+ * memory.
+ *
+ * Only the "Sync" versions of these provide a memory barrier.
+ */
+
+/*
+ * Swap the 64-bit value at "addr" with "value".  Returns the previous
+ * value.
+ */
+extern "C" int64_t dvmQuasiAtomicSwap64(int64_t value, volatile int64_t* addr);
+
+/*
+ * Swap the 64-bit value at "addr" with "value".  Returns the previous
+ * value.  Provides memory barriers.
+ */
+extern "C" int64_t dvmQuasiAtomicSwap64Sync(int64_t value,
+                                            volatile int64_t* addr);
+
+/*
+ * Read the 64-bit value at "addr".
+ */
+extern "C" int64_t dvmQuasiAtomicRead64(volatile const int64_t* addr);
+
+/*
+ * If the value at "addr" is equal to "oldvalue", replace it with "newvalue"
+ * and return 0.  Otherwise, don't swap, and return nonzero.
+ */
+int dvmQuasiAtomicCas64(int64_t oldvalue, int64_t newvalue,
+        volatile int64_t* addr);
+
+#endif  // DALVIK_ATOMIC_H_
diff --git a/vm/AtomicCache.cpp b/vm/AtomicCache.cpp
new file mode 100644
index 0000000..28fcbfe
--- /dev/null
+++ b/vm/AtomicCache.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/*
+ * Mutex-free cache.  Each entry has two 32-bit keys, one 32-bit value,
+ * and a 32-bit version.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+/*
+ * I think modern C mandates that the results of a boolean expression are
+ * 0 or 1.  If not, or we suddenly turn into C++ and bool != int, use this.
+ */
+#define BOOL_TO_INT(x)  (x)
+//#define BOOL_TO_INT(x)  ((x) ? 1 : 0)
+
+#define CPU_CACHE_WIDTH         32
+#define CPU_CACHE_WIDTH_1       (CPU_CACHE_WIDTH-1)
+
+#define ATOMIC_LOCK_FLAG        (1 << 31)
+
+/*
+ * Allocate cache.
+ */
+AtomicCache* dvmAllocAtomicCache(int numEntries)
+{
+    AtomicCache* newCache;
+
+    newCache = (AtomicCache*) calloc(1, sizeof(AtomicCache));
+    if (newCache == NULL)
+        return NULL;
+
+    newCache->numEntries = numEntries;
+
+    newCache->entryAlloc = calloc(1,
+        sizeof(AtomicCacheEntry) * numEntries + CPU_CACHE_WIDTH);
+    if (newCache->entryAlloc == NULL)
+        return NULL;
+
+    /*
+     * Adjust storage to align on a 32-byte boundary.  Each entry is 16 bytes
+     * wide.  This ensures that each cache entry sits on a single CPU cache
+     * line.
+     */
+    assert(sizeof(AtomicCacheEntry) == 16);
+    newCache->entries = (AtomicCacheEntry*)
+        (((int) newCache->entryAlloc + CPU_CACHE_WIDTH_1) & ~CPU_CACHE_WIDTH_1);
+
+    return newCache;
+}
+
+/*
+ * Free cache.
+ */
+void dvmFreeAtomicCache(AtomicCache* cache)
+{
+    if (cache != NULL) {
+        free(cache->entryAlloc);
+        free(cache);
+    }
+}
+
+
+/*
+ * Update a cache entry.
+ *
+ * In the event of a collision with another thread, the update may be skipped.
+ *
+ * We only need "pCache" for stats.
+ */
+void dvmUpdateAtomicCache(u4 key1, u4 key2, u4 value, AtomicCacheEntry* pEntry,
+    u4 firstVersion
+#if CALC_CACHE_STATS > 0
+    , AtomicCache* pCache
+#endif
+    )
+{
+    /*
+     * The fields don't match, so we want to update them.  There is a risk
+     * that another thread is also trying to update them, so we grab an
+     * ownership flag to lock out other threads.
+     *
+     * If the lock flag was already set in "firstVersion", somebody else
+     * was in mid-update, and we don't want to continue here.  (This means
+     * that using "firstVersion" as the "before" argument to the CAS would
+     * succeed when it shouldn't and vice-versa -- we could also just pass
+     * in (firstVersion & ~ATOMIC_LOCK_FLAG) as the first argument.)
+     *
+     * NOTE: we don't deal with the situation where we overflow the version
+     * counter and trample the ATOMIC_LOCK_FLAG (at 2^31).  Probably not
+     * a real concern.
+     */
+    if ((firstVersion & ATOMIC_LOCK_FLAG) != 0 ||
+        android_atomic_release_cas(
+                firstVersion, firstVersion | ATOMIC_LOCK_FLAG,
+                (volatile s4*) &pEntry->version) != 0)
+    {
+        /*
+         * We couldn't get the write lock.  Return without updating the table.
+         */
+#if CALC_CACHE_STATS > 0
+        pCache->fail++;
+#endif
+        return;
+    }
+
+    /* must be even-valued on entry */
+    assert((firstVersion & 0x01) == 0);
+
+#if CALC_CACHE_STATS > 0
+    /* for stats, assume a key value of zero indicates an empty entry */
+    if (pEntry->key1 == 0)
+        pCache->fills++;
+    else
+        pCache->misses++;
+#endif
+
+    /*
+     * We have the write lock, but somebody could be reading this entry
+     * while we work.  We use memory barriers to ensure that the state
+     * is always consistent when the version number is even.
+     */
+    u4 newVersion = (firstVersion | ATOMIC_LOCK_FLAG) + 1;
+    assert((newVersion & 0x01) == 1);
+
+    pEntry->version = newVersion;
+
+    android_atomic_release_store(key1, (int32_t*) &pEntry->key1);
+    pEntry->key2 = key2;
+    pEntry->value = value;
+
+    newVersion++;
+    android_atomic_release_store(newVersion, (int32_t*) &pEntry->version);
+
+    /*
+     * Clear the lock flag.  Nobody else should have been able to modify
+     * pEntry->version, so if this fails the world is broken.
+     */
+    assert(newVersion == ((firstVersion + 2) | ATOMIC_LOCK_FLAG));
+    if (android_atomic_release_cas(
+            newVersion, newVersion & ~ATOMIC_LOCK_FLAG,
+            (volatile s4*) &pEntry->version) != 0)
+    {
+        //LOGE("unable to reset the instanceof cache ownership");
+        dvmAbort();
+    }
+}
+
+
+/*
+ * Dump the "instanceof" cache stats.
+ */
+void dvmDumpAtomicCacheStats(const AtomicCache* pCache)
+{
+    if (pCache == NULL)
+        return;
+    dvmFprintf(stdout,
+        "Cache stats: trv=%d fai=%d hit=%d mis=%d fil=%d %d%% (size=%d)\n",
+        pCache->trivial, pCache->fail, pCache->hits,
+        pCache->misses, pCache->fills,
+        (pCache->hits == 0) ? 0 :
+            pCache->hits * 100 /
+                (pCache->fail + pCache->hits + pCache->misses + pCache->fills),
+        pCache->numEntries);
+}
diff --git a/vm/AtomicCache.h b/vm/AtomicCache.h
new file mode 100644
index 0000000..00a0900
--- /dev/null
+++ b/vm/AtomicCache.h
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+/*
+ * Mutex-free cache for key1+key2=value.
+ */
+#ifndef DALVIK_ATOMICCACHE_H_
+#define DALVIK_ATOMICCACHE_H_
+
+/*
+ * If set to "1", gather some stats on our caching success rate.
+ */
+#define CALC_CACHE_STATS 0
+
+
+/*
+ * One entry in the cache.  We store two keys (e.g. the classes that are
+ * arguments to "instanceof") and one result (e.g. a boolean value).
+ *
+ * Must be exactly 16 bytes.
+ */
+struct AtomicCacheEntry {
+    u4          key1;
+    u4          key2;
+    u4          value;
+    volatile u4 version;    /* version and lock flag */
+};
+
+/*
+ * One cache.
+ *
+ * Thought: we might be able to save a few cycles by storing the cache
+ * struct and "entries" separately, avoiding an indirection.  (We already
+ * handle "numEntries" separately in ATOMIC_CACHE_LOOKUP.)
+ */
+struct AtomicCache {
+    AtomicCacheEntry*   entries;        /* array of entries */
+    int         numEntries;             /* #of entries, must be power of 2 */
+
+    void*       entryAlloc;             /* memory allocated for entries */
+
+    /* cache stats; note we don't guarantee atomic increments for these */
+    int         trivial;                /* cache access not required */
+    int         fail;                   /* contention failure */
+    int         hits;                   /* found entry in cache */
+    int         misses;                 /* entry was for other keys */
+    int         fills;                  /* entry was empty */
+};
+
+/*
+ * Do a cache lookup.  We need to be able to read and write entries
+ * atomically.  There are a couple of ways to do this:
+ *  (1) Have a global lock.  A mutex is too heavy, so instead we would use
+ *      an atomic flag.  If the flag is set, we could sit and spin,
+ *      but if we're a high-priority thread that may cause a lockup.
+ *      Better to just ignore the cache and do the full computation.
+ *  (2) Have a "version" that gets incremented atomically when a write
+ *      begins and again when it completes.  Compare the version before
+ *      and after doing reads.  So long as we have memory barriers in the
+ *      right place the compiler and CPU will do the right thing, allowing
+ *      us to skip atomic ops in the common read case.  The table updates
+ *      are expensive, requiring two writes with barriers.  We also need
+ *      some sort of lock to ensure that nobody else tries to start an
+ *      update while we're in the middle of one.
+ *
+ * We expect a 95+% hit rate for the things we use this for, so #2 is
+ * much better than #1.
+ *
+ * _cache is an AtomicCache*
+ * _cacheSize is _cache->cacheSize (can save a cycle avoiding the lookup)
+ * _key1, _key2 are the keys
+ *
+ * Define a function ATOMIC_CACHE_CALC that returns a 32-bit value.  This
+ * will be invoked when we need to compute the value.
+ *
+ * Returns the value.
+ */
+#if CALC_CACHE_STATS > 0
+# define CACHE_XARG(_value) ,_value
+#else
+# define CACHE_XARG(_value)
+#endif
+#define ATOMIC_CACHE_LOOKUP(_cache, _cacheSize, _key1, _key2) ({            \
+    AtomicCacheEntry* pEntry;                                               \
+    int hash;                                                               \
+    u4 firstVersion, secondVersion;                                         \
+    u4 value;                                                               \
+                                                                            \
+    /* simple hash function */                                              \
+    hash = (((u4)(_key1) >> 2) ^ (u4)(_key2)) & ((_cacheSize)-1);           \
+    pEntry = (_cache)->entries + hash;                                      \
+                                                                            \
+    firstVersion = android_atomic_acquire_load((int32_t*)&pEntry->version); \
+                                                                            \
+    if (pEntry->key1 == (u4)(_key1) && pEntry->key2 == (u4)(_key2)) {       \
+        /*                                                                  \
+         * The fields match.  Get the value, then read the version a        \
+         * second time to verify that we didn't catch a partial update.     \
+         * We're also hosed if "firstVersion" was odd, indicating that      \
+         * an update was in progress before we got here (unlikely).         \
+         */                                                                 \
+        value = android_atomic_acquire_load((int32_t*) &pEntry->value);     \
+        secondVersion = pEntry->version;                                    \
+                                                                            \
+        if ((firstVersion & 0x01) != 0 || firstVersion != secondVersion) {  \
+            /*                                                              \
+             * We clashed with another thread.  Instead of sitting and      \
+             * spinning, which might not complete if we're a high priority  \
+             * thread, just do the regular computation.                     \
+             */                                                             \
+            if (CALC_CACHE_STATS)                                           \
+                (_cache)->fail++;                                           \
+            value = (u4) ATOMIC_CACHE_CALC;                                 \
+        } else {                                                            \
+            /* all good */                                                  \
+            if (CALC_CACHE_STATS)                                           \
+                (_cache)->hits++;                                           \
+        }                                                                   \
+    } else {                                                                \
+        /*                                                                  \
+         * Compute the result and update the cache.  We really want this    \
+         * to happen in a different method -- it makes the ARM frame        \
+         * setup for this method simpler, which gives us a ~10% speed       \
+         * boost.                                                           \
+         */                                                                 \
+        value = (u4) ATOMIC_CACHE_CALC;                                     \
+        dvmUpdateAtomicCache((u4) (_key1), (u4) (_key2), value, pEntry,     \
+                    firstVersion CACHE_XARG(_cache) );                      \
+    }                                                                       \
+    value;                                                                  \
+})
+
+/*
+ * Allocate a cache.
+ */
+AtomicCache* dvmAllocAtomicCache(int numEntries);
+
+/*
+ * Free a cache.
+ */
+void dvmFreeAtomicCache(AtomicCache* cache);
+
+/*
+ * Update a cache entry.
+ *
+ * Making the last argument optional, instead of merely unused, saves us
+ * a few percent in the ATOMIC_CACHE_LOOKUP time.
+ */
+void dvmUpdateAtomicCache(u4 key1, u4 key2, u4 value, AtomicCacheEntry* pEntry,
+    u4 firstVersion
+#if CALC_CACHE_STATS > 0
+    , AtomicCache* pCache
+#endif
+    );
+
+/*
+ * Debugging.
+ */
+void dvmDumpAtomicCacheStats(const AtomicCache* pCache);
+
+#endif  // DALVIK_ATOMICCACHE_H_
diff --git a/vm/BitVector.cpp b/vm/BitVector.cpp
new file mode 100644
index 0000000..0ef6f60
--- /dev/null
+++ b/vm/BitVector.cpp
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+
+/*
+ * Implementation of an expandable bit vector.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <strings.h>
+
+#define kBitVectorGrowth    4   /* increase by 4 u4s when limit hit */
+
+
+/*
+ * Allocate a bit vector with enough space to hold at least the specified
+ * number of bits.
+ */
+BitVector* dvmAllocBitVector(unsigned int startBits, bool expandable)
+{
+    BitVector* bv;
+    unsigned int count;
+
+    assert(sizeof(bv->storage[0]) == 4);        /* assuming 32-bit units */
+
+    bv = (BitVector*) malloc(sizeof(BitVector));
+
+    count = (startBits + 31) >> 5;
+
+    bv->storageSize = count;
+    bv->expandable = expandable;
+    bv->storage = (u4*) malloc(count * sizeof(u4));
+    memset(bv->storage, 0x00, count * sizeof(u4));
+    return bv;
+}
+
+/*
+ * Free a BitVector.
+ */
+void dvmFreeBitVector(BitVector* pBits)
+{
+    if (pBits == NULL)
+        return;
+
+    free(pBits->storage);
+    free(pBits);
+}
+
+/*
+ * "Allocate" the first-available bit in the bitmap.
+ *
+ * This is not synchronized.  The caller is expected to hold some sort of
+ * lock that prevents multiple threads from executing simultaneously in
+ * dvmAllocBit/dvmFreeBit.
+ */
+int dvmAllocBit(BitVector* pBits)
+{
+    unsigned int word, bit;
+
+retry:
+    for (word = 0; word < pBits->storageSize; word++) {
+        if (pBits->storage[word] != 0xffffffff) {
+            /*
+             * There are unallocated bits in this word.  Return the first.
+             */
+            bit = ffs(~(pBits->storage[word])) -1;
+            assert(bit < 32);
+            pBits->storage[word] |= 1 << bit;
+            return (word << 5) | bit;
+        }
+    }
+
+    /*
+     * Ran out of space, allocate more if we're allowed to.
+     */
+    if (!pBits->expandable)
+        return -1;
+
+    pBits->storage = (u4*)realloc(pBits->storage,
+                    (pBits->storageSize + kBitVectorGrowth) * sizeof(u4));
+    memset(&pBits->storage[pBits->storageSize], 0x00,
+        kBitVectorGrowth * sizeof(u4));
+    pBits->storageSize += kBitVectorGrowth;
+    goto retry;
+}
+
+/*
+ * Mark the specified bit as "set".
+ */
+void dvmSetBit(BitVector* pBits, unsigned int num)
+{
+    if (num >= pBits->storageSize * sizeof(u4) * 8) {
+        if (!pBits->expandable) {
+            LOGE("Attempt to set bit outside valid range (%d, limit is %d)",
+                num, pBits->storageSize * sizeof(u4) * 8);
+            dvmAbort();
+        }
+
+        /* Round up to word boundaries for "num+1" bits */
+        unsigned int newSize = (num + 1 + 31) >> 5;
+        assert(newSize > pBits->storageSize);
+        pBits->storage = (u4*)realloc(pBits->storage, newSize * sizeof(u4));
+        if (pBits->storage == NULL) {
+            LOGE("BitVector expansion to %d failed", newSize * sizeof(u4));
+            dvmAbort();
+        }
+        memset(&pBits->storage[pBits->storageSize], 0x00,
+            (newSize - pBits->storageSize) * sizeof(u4));
+        pBits->storageSize = newSize;
+    }
+
+    pBits->storage[num >> 5] |= 1 << (num & 0x1f);
+}
+
+/*
+ * Mark the specified bit as "clear".
+ */
+void dvmClearBit(BitVector* pBits, unsigned int num)
+{
+    assert(num < pBits->storageSize * sizeof(u4) * 8);
+
+    pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
+}
+
+/*
+ * Mark all bits bit as "clear".
+ */
+void dvmClearAllBits(BitVector* pBits)
+{
+    unsigned int count = pBits->storageSize;
+    memset(pBits->storage, 0, count * sizeof(u4));
+}
+
+/*
+ * Mark specified number of bits as "set". Cannot set all bits like ClearAll
+ * since there might be unused bits - setting those to one will confuse the
+ * iterator.
+ */
+void dvmSetInitialBits(BitVector* pBits, unsigned int numBits)
+{
+    unsigned int idx;
+    assert(((numBits + 31) >> 5) <= pBits->storageSize);
+    for (idx = 0; idx < (numBits >> 5); idx++) {
+        pBits->storage[idx] = -1;
+    }
+    unsigned int remNumBits = numBits & 0x1f;
+    if (remNumBits) {
+        pBits->storage[idx] = (1 << remNumBits) - 1;
+    }
+}
+
+/*
+ * Determine whether or not the specified bit is set.
+ */
+bool dvmIsBitSet(const BitVector* pBits, unsigned int num)
+{
+    assert(num < pBits->storageSize * sizeof(u4) * 8);
+
+    unsigned int val = pBits->storage[num >> 5] & (1 << (num & 0x1f));
+    return (val != 0);
+}
+
+/*
+ * Count the number of bits that are set.
+ */
+int dvmCountSetBits(const BitVector* pBits)
+{
+    unsigned int word;
+    unsigned int count = 0;
+
+    for (word = 0; word < pBits->storageSize; word++) {
+        u4 val = pBits->storage[word];
+
+        if (val != 0) {
+            if (val == 0xffffffff) {
+                count += 32;
+            } else {
+                /* count the number of '1' bits */
+                while (val != 0) {
+                    val &= val - 1;
+                    count++;
+                }
+            }
+        }
+    }
+
+    return count;
+}
+
+/*
+ * If the vector sizes don't match, log an error and abort.
+ */
+static void checkSizes(const BitVector* bv1, const BitVector* bv2)
+{
+    if (bv1->storageSize != bv2->storageSize) {
+        LOGE("Mismatched vector sizes (%d, %d)",
+            bv1->storageSize, bv2->storageSize);
+        dvmAbort();
+    }
+}
+
+/*
+ * Copy a whole vector to the other. Only do that when the both vectors have
+ * the same size.
+ */
+void dvmCopyBitVector(BitVector *dest, const BitVector *src)
+{
+    /* if dest is expandable and < src, we could expand dest to match */
+    checkSizes(dest, src);
+
+    memcpy(dest->storage, src->storage, sizeof(u4) * dest->storageSize);
+}
+
+/*
+ * Intersect two bit vectors and store the result to the dest vector.
+ */
+bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1,
+                            const BitVector *src2)
+{
+    if (dest->storageSize != src1->storageSize ||
+        dest->storageSize != src2->storageSize ||
+        dest->expandable != src1->expandable ||
+        dest->expandable != src2->expandable)
+        return false;
+
+    unsigned int idx;
+    for (idx = 0; idx < dest->storageSize; idx++) {
+        dest->storage[idx] = src1->storage[idx] & src2->storage[idx];
+    }
+    return true;
+}
+
+/*
+ * Unify two bit vectors and store the result to the dest vector.
+ */
+bool dvmUnifyBitVectors(BitVector *dest, const BitVector *src1,
+                        const BitVector *src2)
+{
+    if (dest->storageSize != src1->storageSize ||
+        dest->storageSize != src2->storageSize ||
+        dest->expandable != src1->expandable ||
+        dest->expandable != src2->expandable)
+        return false;
+
+    unsigned int idx;
+    for (idx = 0; idx < dest->storageSize; idx++) {
+        dest->storage[idx] = src1->storage[idx] | src2->storage[idx];
+    }
+    return true;
+}
+
+/*
+ * Compare two bit vectors and return true if difference is seen.
+ */
+bool dvmCompareBitVectors(const BitVector *src1, const BitVector *src2)
+{
+    if (src1->storageSize != src2->storageSize ||
+        src1->expandable != src2->expandable)
+        return true;
+
+    unsigned int idx;
+    for (idx = 0; idx < src1->storageSize; idx++) {
+        if (src1->storage[idx] != src2->storage[idx]) return true;
+    }
+    return false;
+}
+
+/* Initialize the iterator structure */
+void dvmBitVectorIteratorInit(BitVector* pBits, BitVectorIterator* iterator)
+{
+    iterator->pBits = pBits;
+    iterator->bitSize = pBits->storageSize * sizeof(u4) * 8;
+    iterator->idx = 0;
+}
+
+/* Return the next position set to 1. -1 means end-of-element reached */
+int dvmBitVectorIteratorNext(BitVectorIterator* iterator)
+{
+    const BitVector* pBits = iterator->pBits;
+    u4 bitIndex = iterator->idx;
+
+    assert(iterator->bitSize == pBits->storageSize * sizeof(u4) * 8);
+    if (bitIndex >= iterator->bitSize) return -1;
+
+    for (; bitIndex < iterator->bitSize; bitIndex++) {
+        unsigned int wordIndex = bitIndex >> 5;
+        unsigned int mask = 1 << (bitIndex & 0x1f);
+        if (pBits->storage[wordIndex] & mask) {
+            iterator->idx = bitIndex+1;
+            return bitIndex;
+        }
+    }
+    /* No more set bits */
+    return -1;
+}
+
+
+/*
+ * Merge the contents of "src" into "dst", checking to see if this causes
+ * any changes to occur.  This is a logical OR.
+ *
+ * Returns "true" if the contents of the destination vector were modified.
+ */
+bool dvmCheckMergeBitVectors(BitVector* dst, const BitVector* src)
+{
+    bool changed = false;
+
+    checkSizes(dst, src);
+
+    unsigned int idx;
+    for (idx = 0; idx < dst->storageSize; idx++) {
+        u4 merged = src->storage[idx] | dst->storage[idx];
+        if (dst->storage[idx] != merged) {
+            dst->storage[idx] = merged;
+            changed = true;
+        }
+    }
+
+    return changed;
+}
diff --git a/vm/BitVector.h b/vm/BitVector.h
new file mode 100644
index 0000000..2ac0ddf
--- /dev/null
+++ b/vm/BitVector.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/*
+ * Miscellaneous utility functions.
+ */
+#ifndef DALVIK_BITVECTOR_H_
+#define DALVIK_BITVECTOR_H_
+
+/*
+ * Expanding bitmap, used for tracking resources.  Bits are numbered starting
+ * from zero.
+ *
+ * All operations on a BitVector are unsynchronized.
+ */
+struct BitVector {
+    bool    expandable;     /* expand bitmap if we run out? */
+    u4      storageSize;    /* current size, in 32-bit words */
+    u4*     storage;
+};
+
+/* Handy iterator to walk through the bit positions set to 1 */
+struct BitVectorIterator {
+    BitVector *pBits;
+    u4 idx;
+    u4 bitSize;
+};
+
+/* allocate a bit vector with enough space to hold "startBits" bits */
+BitVector* dvmAllocBitVector(unsigned int startBits, bool expandable);
+void dvmFreeBitVector(BitVector* pBits);
+
+/*
+ * dvmAllocBit always allocates the first possible bit.  If we run out of
+ * space in the bitmap, and it's not marked expandable, dvmAllocBit
+ * returns -1.
+ *
+ * dvmSetBit sets the specified bit, expanding the vector if necessary
+ * (and possible).  Attempting to set a bit past the limit of a non-expandable
+ * bit vector will cause a fatal error.
+ *
+ * dvmSetInitialBits sets all bits in [0..numBits-1]. Won't expand the vector.
+ *
+ * dvmIsBitSet returns "true" if the bit is set.
+ */
+int dvmAllocBit(BitVector* pBits);
+void dvmSetBit(BitVector* pBits, unsigned int num);
+void dvmClearBit(BitVector* pBits, unsigned int num);
+void dvmClearAllBits(BitVector* pBits);
+void dvmSetInitialBits(BitVector* pBits, unsigned int numBits);
+bool dvmIsBitSet(const BitVector* pBits, unsigned int num);
+
+/* count the number of bits that have been set */
+int dvmCountSetBits(const BitVector* pBits);
+
+/* copy one vector to another of equal size */
+void dvmCopyBitVector(BitVector *dest, const BitVector *src);
+
+/*
+ * Intersect two bit vectors and store the result to the dest vector.
+ */
+bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1,
+                            const BitVector *src2);
+
+/*
+ * Unify two bit vectors and store the result to the dest vector.
+ */
+bool dvmUnifyBitVectors(BitVector *dest, const BitVector *src1,
+                        const BitVector *src2);
+
+/*
+ * Merge the contents of "src" into "dst", checking to see if this causes
+ * any changes to occur.
+ *
+ * Returns "true" if the contents of the destination vector were modified.
+ */
+bool dvmCheckMergeBitVectors(BitVector* dst, const BitVector* src);
+
+/*
+ * Compare two bit vectors and return true if difference is seen.
+ */
+bool dvmCompareBitVectors(const BitVector *src1, const BitVector *src2);
+
+/* Initialize the iterator structure */
+void dvmBitVectorIteratorInit(BitVector* pBits, BitVectorIterator* iterator);
+
+/* Return the next position set to 1. -1 means end-of-vector reached */
+int dvmBitVectorIteratorNext(BitVectorIterator* iterator);
+
+#endif  // DALVIK_BITVECTOR_H_
diff --git a/vm/Bits.h b/vm/Bits.h
new file mode 100644
index 0000000..04d4fd1
--- /dev/null
+++ b/vm/Bits.h
@@ -0,0 +1,358 @@
+/*
+ * 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.
+ */
+/*
+ * Some handy functions for manipulating bits and bytes.
+ *
+ * These get inlined, so prefer small size over maximum speed.
+ */
+#ifndef DALVIK_BITS_H_
+#define DALVIK_BITS_H_
+
+#include "Common.h"
+#include "Inlines.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Get 1 byte.  (Included to make the code more legible.)
+ */
+INLINE u1 get1(unsigned const char* pSrc)
+{
+    return *pSrc;
+}
+
+/*
+ * Get 2 big-endian bytes.
+ */
+INLINE u2 get2BE(unsigned char const* pSrc)
+{
+    return (pSrc[0] << 8) | pSrc[1];
+}
+
+/*
+ * Get 4 big-endian bytes.
+ */
+INLINE u4 get4BE(unsigned char const* pSrc)
+{
+    return (pSrc[0] << 24) | (pSrc[1] << 16) | (pSrc[2] << 8) | pSrc[3];
+}
+
+/*
+ * Get 8 big-endian bytes.
+ */
+INLINE u8 get8BE(unsigned char const* pSrc)
+{
+    u4 low, high;
+
+    high = pSrc[0];
+    high = (high << 8) | pSrc[1];
+    high = (high << 8) | pSrc[2];
+    high = (high << 8) | pSrc[3];
+    low = pSrc[4];
+    low = (low << 8) | pSrc[5];
+    low = (low << 8) | pSrc[6];
+    low = (low << 8) | pSrc[7];
+
+    return ((u8) high << 32) | (u8) low;
+}
+
+/*
+ * Get 2 little-endian bytes.
+ */
+INLINE u2 get2LE(unsigned char const* pSrc)
+{
+    return pSrc[0] | (pSrc[1] << 8);
+}
+
+/*
+ * Get 4 little-endian bytes.
+ */
+INLINE u4 get4LE(unsigned char const* pSrc)
+{
+    u4 result;
+
+    result = pSrc[0];
+    result |= pSrc[1] << 8;
+    result |= pSrc[2] << 16;
+    result |= pSrc[3] << 24;
+
+    return result;
+}
+
+/*
+ * Get 8 little-endian bytes.
+ */
+INLINE u8 get8LE(unsigned char const* pSrc)
+{
+    u4 low, high;
+
+    low = pSrc[0];
+    low |= pSrc[1] << 8;
+    low |= pSrc[2] << 16;
+    low |= pSrc[3] << 24;
+    high = pSrc[4];
+    high |= pSrc[5] << 8;
+    high |= pSrc[6] << 16;
+    high |= pSrc[7] << 24;
+    return ((u8) high << 32) | (u8) low;
+}
+
+/*
+ * Grab 1 byte and advance the data pointer.
+ */
+INLINE u1 read1(unsigned const char** ppSrc)
+{
+    return *(*ppSrc)++;
+}
+
+/*
+ * Grab 2 big-endian bytes and advance the data pointer.
+ */
+INLINE u2 read2BE(unsigned char const** ppSrc)
+{
+    const unsigned char* pSrc = *ppSrc;
+
+    *ppSrc = pSrc + 2;
+    return pSrc[0] << 8 | pSrc[1];
+}
+
+/*
+ * Grab 4 big-endian bytes and advance the data pointer.
+ */
+INLINE u4 read4BE(unsigned char const** ppSrc)
+{
+    const unsigned char* pSrc = *ppSrc;
+    u4 result;
+
+    result = pSrc[0] << 24;
+    result |= pSrc[1] << 16;
+    result |= pSrc[2] << 8;
+    result |= pSrc[3];
+
+    *ppSrc = pSrc + 4;
+    return result;
+}
+
+/*
+ * Get 8 big-endian bytes and advance the data pointer.
+ */
+INLINE u8 read8BE(unsigned char const** ppSrc)
+{
+    const unsigned char* pSrc = *ppSrc;
+    u4 low, high;
+
+    high = pSrc[0];
+    high = (high << 8) | pSrc[1];
+    high = (high << 8) | pSrc[2];
+    high = (high << 8) | pSrc[3];
+    low = pSrc[4];
+    low = (low << 8) | pSrc[5];
+    low = (low << 8) | pSrc[6];
+    low = (low << 8) | pSrc[7];
+
+    *ppSrc = pSrc + 8;
+    return ((u8) high << 32) | (u8) low;
+}
+
+/*
+ * Grab 2 little-endian bytes and advance the data pointer.
+ */
+INLINE u2 read2LE(unsigned char const** ppSrc)
+{
+    const unsigned char* pSrc = *ppSrc;
+    *ppSrc = pSrc + 2;
+    return pSrc[0] | pSrc[1] << 8;
+}
+
+/*
+ * Grab 4 little-endian bytes and advance the data pointer.
+ */
+INLINE u4 read4LE(unsigned char const** ppSrc)
+{
+    const unsigned char* pSrc = *ppSrc;
+    u4 result;
+
+    result = pSrc[0];
+    result |= pSrc[1] << 8;
+    result |= pSrc[2] << 16;
+    result |= pSrc[3] << 24;
+
+    *ppSrc = pSrc + 4;
+    return result;
+}
+
+/*
+ * Get 8 little-endian bytes and advance the data pointer.
+ */
+INLINE u8 read8LE(unsigned char const** ppSrc)
+{
+    const unsigned char* pSrc = *ppSrc;
+    u4 low, high;
+
+    low = pSrc[0];
+    low |= pSrc[1] << 8;
+    low |= pSrc[2] << 16;
+    low |= pSrc[3] << 24;
+    high = pSrc[4];
+    high |= pSrc[5] << 8;
+    high |= pSrc[6] << 16;
+    high |= pSrc[7] << 24;
+
+    *ppSrc = pSrc + 8;
+    return ((u8) high << 32) | (u8) low;
+}
+
+/*
+ * Skip over a UTF-8 string (preceded by a 4-byte length).
+ */
+INLINE void skipUtf8String(unsigned char const** ppSrc)
+{
+    u4 length = read4BE(ppSrc);
+
+    (*ppSrc) += length;
+}
+
+/*
+ * Read a UTF-8 string into a fixed-size buffer, and null-terminate it.
+ *
+ * Returns the length of the original string.
+ */
+INLINE int readUtf8String(unsigned char const** ppSrc, char* buf, size_t bufLen)
+{
+    u4 length = read4BE(ppSrc);
+    size_t copyLen = (length < bufLen) ? length : bufLen-1;
+
+    memcpy(buf, *ppSrc, copyLen);
+    buf[copyLen] = '\0';
+
+    (*ppSrc) += length;
+    return length;
+}
+
+/*
+ * Read a UTF-8 string into newly-allocated storage, and null-terminate it.
+ *
+ * Returns the string and its length.  (The latter is probably unnecessary
+ * for the way we're using UTF8.)
+ */
+INLINE char* readNewUtf8String(unsigned char const** ppSrc, size_t* pLength)
+{
+    u4 length = read4BE(ppSrc);
+    char* buf;
+
+    buf = (char*) malloc(length+1);
+
+    memcpy(buf, *ppSrc, length);
+    buf[length] = '\0';
+
+    (*ppSrc) += length;
+
+    *pLength = length;
+    return buf;
+}
+
+
+/*
+ * Set 1 byte.  (Included to make code more consistent/legible.)
+ */
+INLINE void set1(u1* buf, u1 val)
+{
+    *buf = (u1)(val);
+}
+
+/*
+ * Set 2 big-endian bytes.
+ */
+INLINE void set2BE(u1* buf, u2 val)
+{
+    *buf++ = (u1)(val >> 8);
+    *buf = (u1)(val);
+}
+
+/*
+ * Set 4 big-endian bytes.
+ */
+INLINE void set4BE(u1* buf, u4 val)
+{
+    *buf++ = (u1)(val >> 24);
+    *buf++ = (u1)(val >> 16);
+    *buf++ = (u1)(val >> 8);
+    *buf = (u1)(val);
+}
+
+/*
+ * Set 8 big-endian bytes.
+ */
+INLINE void set8BE(u1* buf, u8 val)
+{
+    *buf++ = (u1)(val >> 56);
+    *buf++ = (u1)(val >> 48);
+    *buf++ = (u1)(val >> 40);
+    *buf++ = (u1)(val >> 32);
+    *buf++ = (u1)(val >> 24);
+    *buf++ = (u1)(val >> 16);
+    *buf++ = (u1)(val >> 8);
+    *buf = (u1)(val);
+}
+
+/*
+ * Set 2 little-endian bytes.
+ */
+INLINE void set2LE(u1* buf, u2 val)
+{
+    *buf++ = (u1)(val);
+    *buf = (u1)(val >> 8);
+}
+
+/*
+ * Set 4 little-endian bytes.
+ */
+INLINE void set4LE(u1* buf, u4 val)
+{
+    *buf++ = (u1)(val);
+    *buf++ = (u1)(val >> 8);
+    *buf++ = (u1)(val >> 16);
+    *buf = (u1)(val >> 24);
+}
+
+/*
+ * Set 8 little-endian bytes.
+ */
+INLINE void set8LE(u1* buf, u8 val)
+{
+    *buf++ = (u1)(val);
+    *buf++ = (u1)(val >> 8);
+    *buf++ = (u1)(val >> 16);
+    *buf++ = (u1)(val >> 24);
+    *buf++ = (u1)(val >> 32);
+    *buf++ = (u1)(val >> 40);
+    *buf++ = (u1)(val >> 48);
+    *buf = (u1)(val >> 56);
+}
+
+/*
+ * Stuff a UTF-8 string into the buffer.
+ */
+INLINE void setUtf8String(u1* buf, const u1* str)
+{
+    u4 strLen = strlen((const char*)str);
+
+    set4BE(buf, strLen);
+    memcpy(buf + sizeof(u4), str, strLen);
+}
+
+#endif  // DALVIK_BITS_H_
diff --git a/vm/CheckJni.cpp b/vm/CheckJni.cpp
new file mode 100644
index 0000000..021ae42
--- /dev/null
+++ b/vm/CheckJni.cpp
@@ -0,0 +1,2357 @@
+/*
+ * 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.
+ */
+
+/*
+ * Support for -Xcheck:jni (the "careful" version of the JNI interfaces).
+ *
+ * We want to verify types, make sure class and field IDs are valid, and
+ * ensure that JNI's semantic expectations are being met.  JNI seems to
+ * be relatively lax when it comes to requirements for permission checks,
+ * e.g. access to private methods is generally allowed from anywhere.
+ */
+
+#include "Dalvik.h"
+#include "JniInternal.h"
+
+#include <sys/mman.h>
+#include <zlib.h>
+
+/*
+ * Abort if we are configured to bail out on JNI warnings.
+ */
+static void abortMaybe() {
+    if (!gDvmJni.warnOnly) {
+        dvmDumpThread(dvmThreadSelf(), false);
+        dvmAbort();
+    }
+}
+
+/*
+ * ===========================================================================
+ *      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.
+ *
+ * At this point, pResult->l has already been converted to an object pointer.
+ */
+static void checkCallResultCommon(const u4* args, const JValue* pResult,
+        const Method* method, Thread* self)
+{
+    assert(pResult->l != NULL);
+    const Object* resultObj = (const Object*) pResult->l;
+
+    if (resultObj == kInvalidIndirectRefObject) {
+        LOGW("JNI WARNING: invalid reference returned from native code");
+        const Method* method = dvmGetCurrentJNIMethod();
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGW("             in %s.%s:%s", method->clazz->descriptor, method->name, desc);
+        free(desc);
+        abortMaybe();
+        return;
+    }
+
+    ClassObject* objClazz = resultObj->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)",
+            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).  However, the current class loader may
+         * not be listed as an initiating loader, so we can't just look for
+         * it in the loaded-classes list.
+         */
+        ClassObject* declClazz = dvmFindClassNoInit(declType, method->clazz->classLoader);
+        if (declClazz == NULL) {
+            LOGW("JNI WARNING: method declared to return '%s' returned '%s'",
+                declType, objType);
+            LOGW("             failed in %s.%s ('%s' not found)",
+                method->clazz->descriptor, method->name, declType);
+            abortMaybe();
+            return;
+        }
+        if (!dvmInstanceof(objClazz, declClazz)) {
+            LOGW("JNI WARNING: method declared to return '%s' returned '%s'",
+                declType, objType);
+            LOGW("             failed in %s.%s",
+                method->clazz->descriptor, method->name);
+            abortMaybe();
+            return;
+        } else {
+            LOGV("Check %s.%s: %s io %s (SLOW-OK)",
+                method->clazz->descriptor, method->name, objType, declType);
+        }
+    }
+}
+
+/*
+ * Determine if we need to check the return type coming out of the call.
+ *
+ * (We don't simply do this at the top of checkCallResultCommon() because
+ * this is on the critical path for native method calls.)
+ */
+static inline bool callNeedsCheck(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    return (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL);
+}
+
+/*
+ * Check a call into native code.
+ */
+void dvmCheckCallJNIMethod(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    dvmCallJNIMethod(args, pResult, method, self);
+    if (callNeedsCheck(args, pResult, method, self)) {
+        checkCallResultCommon(args, pResult, method, self);
+    }
+}
+
+/*
+ * ===========================================================================
+ *      JNI function helpers
+ * ===========================================================================
+ */
+
+static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
+    return ((JNIEnvExt*) env)->baseFuncTable;
+}
+
+static inline const JNIInvokeInterface* baseVm(JavaVM* vm) {
+    return ((JavaVMExt*) vm)->baseFuncTable;
+}
+
+class ScopedCheckJniThreadState {
+public:
+    explicit ScopedCheckJniThreadState(JNIEnv* env) {
+        dvmChangeStatus(NULL, THREAD_RUNNING);
+    }
+
+    ~ScopedCheckJniThreadState() {
+        dvmChangeStatus(NULL, THREAD_NATIVE);
+    }
+
+private:
+    // Disallow copy and assignment.
+    ScopedCheckJniThreadState(const ScopedCheckJniThreadState&);
+    void operator=(const ScopedCheckJniThreadState&);
+};
+
+/*
+ * Flags passed into ScopedCheck.
+ */
+#define kFlag_Default       0x0000
+
+#define kFlag_CritBad       0x0000      /* calling while in critical is bad */
+#define kFlag_CritOkay      0x0001      /* ...okay */
+#define kFlag_CritGet       0x0002      /* this is a critical "get" */
+#define kFlag_CritRelease   0x0003      /* this is a critical "release" */
+#define kFlag_CritMask      0x0003      /* bit mask to get "crit" value */
+
+#define kFlag_ExcepBad      0x0000      /* raised exceptions are bad */
+#define kFlag_ExcepOkay     0x0004      /* ...okay */
+
+#define kFlag_Release       0x0010      /* are we in a non-critical release function? */
+#define kFlag_NullableUtf   0x0020      /* are our UTF parameters nullable? */
+
+#define kFlag_Invocation    0x8000      /* Part of the invocation interface (JavaVM*) */
+
+static const char* indirectRefKindName(IndirectRef iref)
+{
+    return indirectRefKindToString(indirectRefKind(iref));
+}
+
+class ScopedCheck {
+public:
+    // For JNIEnv* functions.
+    explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
+        init(env, flags, functionName, true);
+        checkThread(flags);
+    }
+
+    // For JavaVM* functions.
+    explicit ScopedCheck(bool hasMethod, const char* functionName) {
+        init(NULL, kFlag_Invocation, functionName, hasMethod);
+    }
+
+    /*
+     * In some circumstances the VM will screen class names, but it doesn't
+     * for class lookup.  When things get bounced through a class loader, they
+     * can actually get normalized a couple of times; as a result, passing in
+     * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
+     * work in some circumstances.
+     *
+     * This is incorrect and could cause strange behavior or compatibility
+     * problems, so we want to screen that out here.
+     *
+     * We expect "fully-qualified" class names, like "java/lang/Thread" or
+     * "[Ljava/lang/Object;".
+     */
+    void checkClassName(const char* className) {
+        if (!dexIsValidClassName(className, false)) {
+            LOGW("JNI WARNING: illegal class name '%s' (%s)", className, mFunctionName);
+            LOGW("             (should be formed like 'dalvik/system/DexFile')");
+            LOGW("             or '[Ldalvik/system/DexFile;' or '[[B')");
+            abortMaybe();
+        }
+    }
+
+    void checkFieldTypeForGet(jfieldID fid, const char* expectedSignature, bool isStatic) {
+        if (fid == NULL) {
+            LOGW("JNI WARNING: null jfieldID");
+            showLocation();
+            abortMaybe();
+        }
+
+        bool printWarn = false;
+        Field* field = (Field*) fid;
+        const char* actualSignature = field->signature;
+        if (*expectedSignature == 'L') {
+            // 'actualSignature' has the exact type.
+            // We just know we're expecting some kind of reference.
+            if (*actualSignature != 'L' && *actualSignature != '[') {
+                printWarn = true;
+            }
+        } else if (*actualSignature != *expectedSignature) {
+            printWarn = true;
+        }
+
+        if (!printWarn && isStatic && !dvmIsStaticField(field)) {
+            if (isStatic) {
+                LOGW("JNI WARNING: accessing non-static field %s as static", field->name);
+            } else {
+                LOGW("JNI WARNING: accessing static field %s as non-static", field->name);
+            }
+            printWarn = true;
+        }
+
+        if (printWarn) {
+            LOGW("JNI WARNING: %s for field '%s' of expected type %s, got %s",
+                    mFunctionName, field->name, expectedSignature, actualSignature);
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that the field is of the appropriate type.  If the field has an
+     * object type, "jobj" is the object we're trying to assign into it.
+     *
+     * Works for both static and instance fields.
+     */
+    void checkFieldTypeForSet(jobject jobj, jfieldID fieldID, PrimitiveType prim, bool isStatic) {
+        if (fieldID == NULL) {
+            LOGW("JNI WARNING: null jfieldID");
+            showLocation();
+            abortMaybe();
+        }
+
+        bool printWarn = false;
+        Field* field = (Field*) fieldID;
+        if ((field->signature[0] == 'L' || field->signature[0] == '[') && jobj != NULL) {
+            ScopedCheckJniThreadState ts(mEnv);
+            Object* obj = dvmDecodeIndirectRef(self(), jobj);
+            /*
+             * If jobj is a weak global ref whose referent has been cleared,
+             * obj will be NULL.  Otherwise, obj should always be non-NULL
+             * and valid.
+             */
+            if (obj != NULL && !dvmIsHeapAddress(obj)) {
+                LOGW("JNI WARNING: field operation on invalid %s reference (%p)",
+                        indirectRefKindName(jobj), jobj);
+                printWarn = true;
+            } else {
+                ClassObject* fieldClass = dvmFindLoadedClass(field->signature);
+                ClassObject* objClass = obj->clazz;
+
+                assert(fieldClass != NULL);
+                assert(objClass != NULL);
+
+                if (!dvmInstanceof(objClass, fieldClass)) {
+                    LOGW("JNI WARNING: set field '%s' expected type %s, got %s",
+                            field->name, field->signature, objClass->descriptor);
+                    printWarn = true;
+                }
+            }
+        } else if (dexGetPrimitiveTypeFromDescriptorChar(field->signature[0]) != prim) {
+            LOGW("JNI WARNING: %s for field '%s' expected type %s, got %s",
+                    mFunctionName, field->name, field->signature, primitiveTypeToName(prim));
+            printWarn = true;
+        } else if (isStatic && !dvmIsStaticField(field)) {
+            if (isStatic) {
+                LOGW("JNI WARNING: accessing non-static field %s as static", field->name);
+            } else {
+                LOGW("JNI WARNING: accessing static field %s as non-static", field->name);
+            }
+            printWarn = true;
+        }
+
+        if (printWarn) {
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that this instance field ID is valid for this object.
+     *
+     * Assumes "jobj" has already been validated.
+     */
+    void checkInstanceFieldID(jobject jobj, jfieldID fieldID) {
+        ScopedCheckJniThreadState ts(mEnv);
+
+        Object* obj = dvmDecodeIndirectRef(self(), jobj);
+        if (!dvmIsHeapAddress(obj)) {
+            LOGW("JNI ERROR: field operation on invalid reference (%p)", jobj);
+            dvmAbort();
+        }
+
+        /*
+         * Check this class and all of its superclasses for a matching field.
+         * Don't need to scan interfaces.
+         */
+        ClassObject* clazz = obj->clazz;
+        while (clazz != NULL) {
+            if ((InstField*) fieldID >= clazz->ifields &&
+                    (InstField*) fieldID < clazz->ifields + clazz->ifieldCount) {
+                return;
+            }
+
+            clazz = clazz->super;
+        }
+
+        LOGW("JNI WARNING: instance fieldID %p not valid for class %s",
+                fieldID, obj->clazz->descriptor);
+        showLocation();
+        abortMaybe();
+    }
+
+    /*
+     * Verify that the pointer value is non-NULL.
+     */
+    void checkNonNull(const void* ptr) {
+        if (ptr == NULL) {
+            LOGW("JNI WARNING: invalid null pointer (%s)", mFunctionName);
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that the method's return type matches the type of call.
+     * 'expectedType' will be "L" for all objects, including arrays.
+     */
+    void checkSig(jmethodID methodID, const char* expectedType, bool isStatic) {
+        const Method* method = (const Method*) methodID;
+        bool printWarn = false;
+
+        if (*expectedType != method->shorty[0]) {
+            LOGW("JNI WARNING: expected return type '%s'", expectedType);
+            printWarn = true;
+        } else if (isStatic && !dvmIsStaticMethod(method)) {
+            if (isStatic) {
+                LOGW("JNI WARNING: calling non-static method with static call");
+            } else {
+                LOGW("JNI WARNING: calling static method with non-static call");
+            }
+            printWarn = true;
+        }
+
+        if (printWarn) {
+            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+            LOGW("             calling %s.%s %s", method->clazz->descriptor, method->name, desc);
+            free(desc);
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that this static field ID is valid for this class.
+     *
+     * Assumes "jclazz" has already been validated.
+     */
+    void checkStaticFieldID(jclass jclazz, jfieldID fieldID) {
+        ScopedCheckJniThreadState ts(mEnv);
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(self(), jclazz);
+        StaticField* base = &clazz->sfields[0];
+        int fieldCount = clazz->sfieldCount;
+        if ((StaticField*) fieldID < base || (StaticField*) fieldID >= base + fieldCount) {
+            LOGW("JNI WARNING: static fieldID %p not valid for class %s",
+                    fieldID, clazz->descriptor);
+            LOGW("             base=%p count=%d", base, fieldCount);
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that "methodID" is appropriate for "clazz".
+     *
+     * A mismatch isn't dangerous, because the jmethodID defines the class.  In
+     * fact, jclazz is unused in the implementation.  It's best if we don't
+     * allow bad code in the system though.
+     *
+     * Instances of "jclazz" must be instances of the method's declaring class.
+     */
+    void checkStaticMethod(jclass jclazz, jmethodID methodID) {
+        ScopedCheckJniThreadState ts(mEnv);
+
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(self(), jclazz);
+        const Method* method = (const Method*) methodID;
+
+        if (!dvmInstanceof(clazz, method->clazz)) {
+            LOGW("JNI WARNING: can't call static %s.%s on class %s",
+                    method->clazz->descriptor, method->name, clazz->descriptor);
+            showLocation();
+            // no abort?
+        }
+    }
+
+    /*
+     * Verify that "methodID" is appropriate for "jobj".
+     *
+     * Make sure the object is an instance of the method's declaring class.
+     * (Note the methodID might point to a declaration in an interface; this
+     * will be handled automatically by the instanceof check.)
+     */
+    void checkVirtualMethod(jobject jobj, jmethodID methodID) {
+        ScopedCheckJniThreadState ts(mEnv);
+
+        Object* obj = dvmDecodeIndirectRef(self(), jobj);
+        const Method* method = (const Method*) methodID;
+
+        if (!dvmInstanceof(obj->clazz, method->clazz)) {
+            LOGW("JNI WARNING: can't call %s.%s on instance of %s",
+                    method->clazz->descriptor, method->name, obj->clazz->descriptor);
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /**
+     * The format string is a sequence of the following characters,
+     * and must be followed by arguments of the corresponding types
+     * in the same order.
+     *
+     * Java primitive types:
+     * B - jbyte
+     * C - jchar
+     * D - jdouble
+     * F - jfloat
+     * I - jint
+     * J - jlong
+     * S - jshort
+     * Z - jboolean (shown as true and false)
+     * V - void
+     *
+     * Java reference types:
+     * L - jobject
+     * a - jarray
+     * c - jclass
+     * s - jstring
+     *
+     * JNI types:
+     * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
+     * f - jfieldID
+     * m - jmethodID
+     * p - void*
+     * r - jint (for release mode arguments)
+     * u - const char* (modified UTF-8)
+     * z - jsize (for lengths; use i if negative values are okay)
+     * v - JavaVM*
+     * E - JNIEnv*
+     * . - no argument; just print "..." (used for varargs JNI calls)
+     *
+     * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
+     */
+    void check(bool entry, const char* fmt0, ...) {
+        va_list ap;
+
+        bool shouldTrace = false;
+        const Method* method = NULL;
+        if ((gDvm.jniTrace || gDvmJni.logThirdPartyJni) && mHasMethod) {
+            // We need to guard some of the invocation interface's calls: a bad caller might
+            // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
+            if ((mFlags & kFlag_Invocation) == 0 || dvmThreadSelf() != NULL) {
+                method = dvmGetCurrentJNIMethod();
+            }
+        }
+        if (method != NULL) {
+            // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
+            // when a native method that matches the Xjnitrace argument calls a JNI function
+            // such as NewByteArray.
+            if (gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace) != NULL) {
+                shouldTrace = true;
+            }
+            // If -Xjniopts:logThirdPartyJni is on, we want to log any JNI function calls
+            // made by a third-party native method.
+            if (gDvmJni.logThirdPartyJni) {
+                shouldTrace |= method->shouldTrace;
+            }
+        }
+
+        if (shouldTrace) {
+            va_start(ap, fmt0);
+            std::string msg;
+            for (const char* fmt = fmt0; *fmt;) {
+                char ch = *fmt++;
+                if (ch == 'B') { // jbyte
+                    jbyte b = va_arg(ap, int);
+                    if (b >= 0 && b < 10) {
+                        StringAppendF(&msg, "%d", b);
+                    } else {
+                        StringAppendF(&msg, "%#x (%d)", b, b);
+                    }
+                } else if (ch == 'C') { // jchar
+                    jchar c = va_arg(ap, int);
+                    if (c < 0x7f && c >= ' ') {
+                        StringAppendF(&msg, "U+%x ('%c')", c, c);
+                    } else {
+                        StringAppendF(&msg, "U+%x", c);
+                    }
+                } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
+                    StringAppendF(&msg, "%g", va_arg(ap, double));
+                } else if (ch == 'I' || ch == 'S') { // jint, jshort
+                    StringAppendF(&msg, "%d", va_arg(ap, int));
+                } else if (ch == 'J') { // jlong
+                    StringAppendF(&msg, "%lld", va_arg(ap, jlong));
+                } else if (ch == 'Z') { // jboolean
+                    StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
+                } else if (ch == 'V') { // void
+                    msg += "void";
+                } else if (ch == 'v') { // JavaVM*
+                    JavaVM* vm = va_arg(ap, JavaVM*);
+                    StringAppendF(&msg, "(JavaVM*)%p", vm);
+                } else if (ch == 'E') { // JNIEnv*
+                    JNIEnv* env = va_arg(ap, JNIEnv*);
+                    StringAppendF(&msg, "(JNIEnv*)%p", env);
+                } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
+                    // For logging purposes, these are identical.
+                    jobject o = va_arg(ap, jobject);
+                    if (o == NULL) {
+                        msg += "NULL";
+                    } else {
+                        StringAppendF(&msg, "%p", o);
+                    }
+                } else if (ch == 'b') { // jboolean (JNI-style)
+                    jboolean b = va_arg(ap, int);
+                    msg += (b ? "JNI_TRUE" : "JNI_FALSE");
+                } else if (ch == 'c') { // jclass
+                    jclass jc = va_arg(ap, jclass);
+                    Object* c = dvmDecodeIndirectRef(self(), jc);
+                    if (c == NULL) {
+                        msg += "NULL";
+                    } else if (c == kInvalidIndirectRefObject || !dvmIsHeapAddress(c)) {
+                        StringAppendF(&msg, "%p(INVALID)", jc);
+                    } else {
+                        std::string className(dvmHumanReadableType(c));
+                        StringAppendF(&msg, "%s", className.c_str());
+                        if (!entry) {
+                            StringAppendF(&msg, " (%p)", jc);
+                        }
+                    }
+                } else if (ch == 'f') { // jfieldID
+                    jfieldID fid = va_arg(ap, jfieldID);
+                    std::string name(dvmHumanReadableField((Field*) fid));
+                    StringAppendF(&msg, "%s", name.c_str());
+                    if (!entry) {
+                        StringAppendF(&msg, " (%p)", fid);
+                    }
+                } else if (ch == 'z') { // non-negative jsize
+                    // You might expect jsize to be size_t, but it's not; it's the same as jint.
+                    // We only treat this specially so we can do the non-negative check.
+                    // TODO: maybe this wasn't worth it?
+                    jint i = va_arg(ap, jint);
+                    StringAppendF(&msg, "%d", i);
+                } else if (ch == 'm') { // jmethodID
+                    jmethodID mid = va_arg(ap, jmethodID);
+                    std::string name(dvmHumanReadableMethod((Method*) mid, true));
+                    StringAppendF(&msg, "%s", name.c_str());
+                    if (!entry) {
+                        StringAppendF(&msg, " (%p)", mid);
+                    }
+                } else if (ch == 'p') { // void* ("pointer")
+                    void* p = va_arg(ap, void*);
+                    if (p == NULL) {
+                        msg += "NULL";
+                    } else {
+                        StringAppendF(&msg, "(void*) %p", p);
+                    }
+                } else if (ch == 'r') { // jint (release mode)
+                    jint releaseMode = va_arg(ap, jint);
+                    if (releaseMode == 0) {
+                        msg += "0";
+                    } else if (releaseMode == JNI_ABORT) {
+                        msg += "JNI_ABORT";
+                    } else if (releaseMode == JNI_COMMIT) {
+                        msg += "JNI_COMMIT";
+                    } else {
+                        StringAppendF(&msg, "invalid release mode %d", releaseMode);
+                    }
+                } else if (ch == 'u') { // const char* (modified UTF-8)
+                    const char* utf = va_arg(ap, const char*);
+                    if (utf == NULL) {
+                        msg += "NULL";
+                    } else {
+                        StringAppendF(&msg, "\"%s\"", utf);
+                    }
+                } else if (ch == '.') {
+                    msg += "...";
+                } else {
+                    LOGE("unknown trace format specifier %c", ch);
+                    dvmAbort();
+                }
+                if (*fmt) {
+                    StringAppendF(&msg, ", ");
+                }
+            }
+            va_end(ap);
+
+            if (entry) {
+                if (mHasMethod) {
+                    std::string methodName(dvmHumanReadableMethod(method, false));
+                    LOGI("JNI: %s -> %s(%s)", methodName.c_str(), mFunctionName, msg.c_str());
+                    mIndent = methodName.size() + 1;
+                } else {
+                    LOGI("JNI: -> %s(%s)", mFunctionName, msg.c_str());
+                    mIndent = 0;
+                }
+            } else {
+                LOGI("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str());
+            }
+        }
+
+        // We always do the thorough checks on entry, and never on exit...
+        if (entry) {
+            va_start(ap, fmt0);
+            for (const char* fmt = fmt0; *fmt; ++fmt) {
+                char ch = *fmt;
+                if (ch == 'a') {
+                    checkArray(va_arg(ap, jarray));
+                } else if (ch == 'c') {
+                    checkClass(va_arg(ap, jclass));
+                } else if (ch == 'L') {
+                    checkObject(va_arg(ap, jobject));
+                } else if (ch == 'r') {
+                    checkReleaseMode(va_arg(ap, jint));
+                } else if (ch == 's') {
+                    checkString(va_arg(ap, jstring));
+                } else if (ch == 'u') {
+                    if ((mFlags & kFlag_Release) != 0) {
+                        checkNonNull(va_arg(ap, const char*));
+                    } else {
+                        bool nullable = ((mFlags & kFlag_NullableUtf) != 0);
+                        checkUtfString(va_arg(ap, const char*), nullable);
+                    }
+                } else if (ch == 'z') {
+                    checkLengthPositive(va_arg(ap, jsize));
+                } else if (strchr("BCISZbfmpEv", ch) != NULL) {
+                    va_arg(ap, int); // Skip this argument.
+                } else if (ch == 'D' || ch == 'F') {
+                    va_arg(ap, double); // Skip this argument.
+                } else if (ch == 'J') {
+                    va_arg(ap, long); // Skip this argument.
+                } else if (ch == '.') {
+                } else {
+                    LOGE("unknown check format specifier %c", ch);
+                    dvmAbort();
+                }
+            }
+            va_end(ap);
+        }
+    }
+
+    // Only safe after checkThread returns.
+    Thread* self() {
+        return ((JNIEnvExt*) mEnv)->self;
+    }
+
+private:
+    JNIEnv* mEnv;
+    const char* mFunctionName;
+    int mFlags;
+    bool mHasMethod;
+    size_t mIndent;
+
+    void init(JNIEnv* env, int flags, const char* functionName, bool hasMethod) {
+        mEnv = env;
+        mFlags = flags;
+
+        // Use +6 to drop the leading "Check_"...
+        mFunctionName = functionName + 6;
+
+        // Set "hasMethod" to true if we have a valid thread with a method pointer.
+        // We won't have one before attaching a thread, after detaching a thread, or
+        // after destroying the VM.
+        mHasMethod = hasMethod;
+    }
+
+    /*
+     * Verify that "array" is non-NULL and points to an Array object.
+     *
+     * Since we're dealing with objects, switch to "running" mode.
+     */
+    void checkArray(jarray jarr) {
+        if (jarr == NULL) {
+            LOGW("JNI WARNING: received null array");
+            showLocation();
+            abortMaybe();
+            return;
+        }
+
+        ScopedCheckJniThreadState ts(mEnv);
+        bool printWarn = false;
+
+        Object* obj = dvmDecodeIndirectRef(self(), jarr);
+        if (!dvmIsHeapAddress(obj)) {
+            LOGW("JNI WARNING: jarray is an invalid %s reference (%p)",
+            indirectRefKindName(jarr), jarr);
+            printWarn = true;
+        } else if (obj->clazz->descriptor[0] != '[') {
+            LOGW("JNI WARNING: jarray arg has wrong type (expected array, got %s)",
+            obj->clazz->descriptor);
+            printWarn = true;
+        }
+
+        if (printWarn) {
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    void checkClass(jclass c) {
+        checkInstance(c, gDvm.classJavaLangClass, "jclass");
+    }
+
+    void checkLengthPositive(jsize length) {
+        if (length < 0) {
+            LOGW("JNI WARNING: negative jsize (%s)", mFunctionName);
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that "jobj" is a valid object, and that it's an object that JNI
+     * is allowed to know about.  We allow NULL references.
+     *
+     * Switches to "running" mode before performing checks.
+     */
+    void checkObject(jobject jobj) {
+        if (jobj == NULL) {
+            return;
+        }
+
+        ScopedCheckJniThreadState ts(mEnv);
+
+        bool printWarn = false;
+        if (dvmGetJNIRefType(self(), jobj) == JNIInvalidRefType) {
+            LOGW("JNI WARNING: %p is not a valid JNI reference", jobj);
+            printWarn = true;
+        } else {
+            Object* obj = dvmDecodeIndirectRef(self(), jobj);
+            if (obj == kInvalidIndirectRefObject) {
+                LOGW("JNI WARNING: native code passing in invalid reference %p", jobj);
+                printWarn = true;
+            } else if (obj != NULL && !dvmIsHeapAddress(obj)) {
+                // TODO: when we remove workAroundAppJniBugs, this should be impossible.
+                LOGW("JNI WARNING: native code passing in reference to invalid object %p %p",
+                        jobj, obj);
+                printWarn = true;
+            }
+        }
+
+        if (printWarn) {
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that the "mode" argument passed to a primitive array Release
+     * function is one of the valid values.
+     */
+    void checkReleaseMode(jint mode) {
+        if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
+            LOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName);
+            abortMaybe();
+        }
+    }
+
+    void checkString(jstring s) {
+        checkInstance(s, gDvm.classJavaLangString, "jstring");
+    }
+
+    void checkThread(int flags) {
+        // Get the *correct* JNIEnv by going through our TLS pointer.
+        JNIEnvExt* threadEnv = dvmGetJNIEnvForThread();
+
+        /*
+         * Verify that the current thread is (a) attached and (b) associated with
+         * this particular instance of JNIEnv.
+         */
+        bool printWarn = false;
+        if (threadEnv == NULL) {
+            LOGE("JNI ERROR: non-VM thread making JNI calls");
+            // don't set printWarn -- it'll try to call showLocation()
+            dvmAbort();
+        } else if ((JNIEnvExt*) mEnv != threadEnv) {
+            if (dvmThreadSelf()->threadId != threadEnv->envThreadId) {
+                LOGE("JNI: threadEnv != thread->env?");
+                dvmAbort();
+            }
+
+            LOGW("JNI WARNING: threadid=%d using env from threadid=%d",
+                    threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId);
+            printWarn = true;
+
+            // If we're keeping broken code limping along, we need to suppress the abort...
+            if (gDvmJni.workAroundAppJniBugs) {
+                printWarn = false;
+            }
+
+            /* this is a bad idea -- need to throw as we exit, or abort func */
+            //dvmThrowRuntimeException("invalid use of JNI env ptr");
+        } else if (((JNIEnvExt*) mEnv)->self != dvmThreadSelf()) {
+            /* correct JNIEnv*; make sure the "self" pointer is correct */
+            LOGE("JNI ERROR: env->self != thread-self (%p vs. %p)",
+                    ((JNIEnvExt*) mEnv)->self, dvmThreadSelf());
+            dvmAbort();
+        }
+
+        /*
+         * Verify that, if this thread previously made a critical "get" call, we
+         * do the corresponding "release" call before we try anything else.
+         */
+        switch (flags & kFlag_CritMask) {
+        case kFlag_CritOkay:    // okay to call this method
+            break;
+        case kFlag_CritBad:     // not okay to call
+            if (threadEnv->critical) {
+                LOGW("JNI WARNING: threadid=%d using JNI after critical get",
+                        threadEnv->envThreadId);
+                printWarn = true;
+            }
+            break;
+        case kFlag_CritGet:     // this is a "get" call
+            /* don't check here; we allow nested gets */
+            threadEnv->critical++;
+            break;
+        case kFlag_CritRelease: // this is a "release" call
+            threadEnv->critical--;
+            if (threadEnv->critical < 0) {
+                LOGW("JNI WARNING: threadid=%d called too many crit releases",
+                        threadEnv->envThreadId);
+                printWarn = true;
+            }
+            break;
+        default:
+            assert(false);
+        }
+
+        /*
+         * Verify that, if an exception has been raised, the native code doesn't
+         * make any JNI calls other than the Exception* methods.
+         */
+        bool printException = false;
+        if ((flags & kFlag_ExcepOkay) == 0 && dvmCheckException(dvmThreadSelf())) {
+            LOGW("JNI WARNING: JNI method called with exception pending");
+            printWarn = true;
+            printException = true;
+        }
+
+        if (printWarn) {
+            showLocation();
+        }
+        if (printException) {
+            LOGW("Pending exception is:");
+            dvmLogExceptionStackTrace();
+        }
+        if (printWarn) {
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that "bytes" points to valid "modified UTF-8" data.
+     */
+    void checkUtfString(const char* bytes, bool nullable) {
+        if (bytes == NULL) {
+            if (!nullable) {
+                LOGW("JNI WARNING: non-nullable const char* was NULL");
+                showLocation();
+                abortMaybe();
+            }
+            return;
+        }
+
+        const char* errorKind = NULL;
+        u1 utf8 = checkUtfBytes(bytes, &errorKind);
+        if (errorKind != NULL) {
+            LOGW("JNI WARNING: input is not valid Modified UTF-8: illegal %s byte %#x", errorKind, utf8);
+            LOGW("             string: '%s'", bytes);
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    /*
+     * Verify that "jobj" is a valid non-NULL object reference, and points to
+     * an instance of expectedClass.
+     *
+     * Because we're looking at an object on the GC heap, we have to switch
+     * to "running" mode before doing the checks.
+     */
+    void checkInstance(jobject jobj, ClassObject* expectedClass, const char* argName) {
+        if (jobj == NULL) {
+            LOGW("JNI WARNING: received null %s", argName);
+            showLocation();
+            abortMaybe();
+            return;
+        }
+
+        ScopedCheckJniThreadState ts(mEnv);
+        bool printWarn = false;
+
+        Object* obj = dvmDecodeIndirectRef(self(), jobj);
+        if (!dvmIsHeapAddress(obj)) {
+            LOGW("JNI WARNING: %s is an invalid %s reference (%p)",
+                    argName, indirectRefKindName(jobj), jobj);
+            printWarn = true;
+        } else if (obj->clazz != expectedClass) {
+            LOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s)",
+                    argName, expectedClass->descriptor, obj->clazz->descriptor);
+            printWarn = true;
+        }
+
+        if (printWarn) {
+            showLocation();
+            abortMaybe();
+        }
+    }
+
+    static u1 checkUtfBytes(const char* bytes, const char** errorKind) {
+        while (*bytes != '\0') {
+            u1 utf8 = *(bytes++);
+            // Switch on the high four bits.
+            switch (utf8 >> 4) {
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+                // Bit pattern 0xxx. No need for any extra bytes.
+                break;
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0f:
+                /*
+                 * Bit pattern 10xx or 1111, which are illegal start bytes.
+                 * Note: 1111 is valid for normal UTF-8, but not the
+                 * modified UTF-8 used here.
+                 */
+                *errorKind = "start";
+                return utf8;
+            case 0x0e:
+                // Bit pattern 1110, so there are two additional bytes.
+                utf8 = *(bytes++);
+                if ((utf8 & 0xc0) != 0x80) {
+                    *errorKind = "continuation";
+                    return utf8;
+                }
+                // Fall through to take care of the final byte.
+            case 0x0c:
+            case 0x0d:
+                // Bit pattern 110x, so there is one additional byte.
+                utf8 = *(bytes++);
+                if ((utf8 & 0xc0) != 0x80) {
+                    *errorKind = "continuation";
+                    return utf8;
+                }
+                break;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Returns a human-readable name for the given primitive type.
+     */
+    static const char* primitiveTypeToName(PrimitiveType primType) {
+        switch (primType) {
+        case PRIM_VOID:    return "void";
+        case PRIM_BOOLEAN: return "boolean";
+        case PRIM_BYTE:    return "byte";
+        case PRIM_SHORT:   return "short";
+        case PRIM_CHAR:    return "char";
+        case PRIM_INT:     return "int";
+        case PRIM_LONG:    return "long";
+        case PRIM_FLOAT:   return "float";
+        case PRIM_DOUBLE:  return "double";
+        case PRIM_NOT:     return "Object/array";
+        default:           return "???";
+        }
+    }
+
+    void showLocation() {
+        const Method* method = dvmGetCurrentJNIMethod();
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGW("             in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName);
+        free(desc);
+    }
+
+    // Disallow copy and assignment.
+    ScopedCheck(const ScopedCheck&);
+    void operator=(const ScopedCheck&);
+};
+
+/*
+ * ===========================================================================
+ *      Guarded arrays
+ * ===========================================================================
+ */
+
+#define kGuardLen       512         /* must be multiple of 2 */
+#define kGuardPattern   0xd5e3      /* uncommon values; d5e3d5e3 invalid addr */
+#define kGuardMagic     0xffd5aa96
+
+/* this gets tucked in at the start of the buffer; struct size must be even */
+struct GuardedCopy {
+    u4          magic;
+    uLong       adler;
+    size_t      originalLen;
+    const void* originalPtr;
+
+    /* find the GuardedCopy given the pointer into the "live" data */
+    static inline const GuardedCopy* fromData(const void* dataBuf) {
+        return reinterpret_cast<const GuardedCopy*>(actualBuffer(dataBuf));
+    }
+
+    /*
+     * Create an over-sized buffer to hold the contents of "buf".  Copy it in,
+     * filling in the area around it with guard data.
+     *
+     * We use a 16-bit pattern to make a rogue memset less likely to elude us.
+     */
+    static void* create(const void* buf, size_t len, bool modOkay) {
+        size_t newLen = actualLength(len);
+        u1* newBuf = debugAlloc(newLen);
+
+        /* fill it in with a pattern */
+        u2* pat = (u2*) newBuf;
+        for (size_t i = 0; i < newLen / 2; i++) {
+            *pat++ = kGuardPattern;
+        }
+
+        /* copy the data in; note "len" could be zero */
+        memcpy(newBuf + kGuardLen / 2, buf, len);
+
+        /* if modification is not expected, grab a checksum */
+        uLong adler = 0;
+        if (!modOkay) {
+            adler = adler32(0L, Z_NULL, 0);
+            adler = adler32(adler, (const Bytef*)buf, len);
+            *(uLong*)newBuf = adler;
+        }
+
+        GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
+        pExtra->magic = kGuardMagic;
+        pExtra->adler = adler;
+        pExtra->originalPtr = buf;
+        pExtra->originalLen = len;
+
+        return newBuf + kGuardLen / 2;
+    }
+
+    /*
+     * Free up the guard buffer, scrub it, and return the original pointer.
+     */
+    static void* destroy(void* dataBuf) {
+        const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf);
+        void* originalPtr = (void*) pExtra->originalPtr;
+        size_t len = pExtra->originalLen;
+        debugFree(dataBuf, len);
+        return originalPtr;
+    }
+
+    /*
+     * Verify the guard area and, if "modOkay" is false, that the data itself
+     * has not been altered.
+     *
+     * The caller has already checked that "dataBuf" is non-NULL.
+     */
+    static bool check(const void* dataBuf, bool modOkay) {
+        static const u4 kMagicCmp = kGuardMagic;
+        const u1* fullBuf = actualBuffer(dataBuf);
+        const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf);
+
+        /*
+         * Before we do anything with "pExtra", check the magic number.  We
+         * do the check with memcmp rather than "==" in case the pointer is
+         * unaligned.  If it points to completely bogus memory we're going
+         * to crash, but there's no easy way around that.
+         */
+        if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
+            u1 buf[4];
+            memcpy(buf, &pExtra->magic, 4);
+            LOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
+                    buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
+            return false;
+        }
+
+        size_t len = pExtra->originalLen;
+
+        /* check bottom half of guard; skip over optional checksum storage */
+        const u2* pat = (u2*) fullBuf;
+        for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
+            if (pat[i] != kGuardPattern) {
+                LOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2);
+                return false;
+            }
+        }
+
+        int offset = kGuardLen / 2 + len;
+        if (offset & 0x01) {
+            /* odd byte; expected value depends on endian-ness of host */
+            const u2 patSample = kGuardPattern;
+            if (fullBuf[offset] != ((const u1*) &patSample)[1]) {
+                LOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x",
+                        fullBuf, offset, fullBuf[offset], ((const u1*) &patSample)[1]);
+                return false;
+            }
+            offset++;
+        }
+
+        /* check top half of guard */
+        pat = (u2*) (fullBuf + offset);
+        for (size_t i = 0; i < kGuardLen / 4; i++) {
+            if (pat[i] != kGuardPattern) {
+                LOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2);
+                return false;
+            }
+        }
+
+        /*
+         * If modification is not expected, verify checksum.  Strictly speaking
+         * this is wrong: if we told the client that we made a copy, there's no
+         * reason they can't alter the buffer.
+         */
+        if (!modOkay) {
+            uLong adler = adler32(0L, Z_NULL, 0);
+            adler = adler32(adler, (const Bytef*)dataBuf, len);
+            if (pExtra->adler != adler) {
+                LOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p",
+                        pExtra->adler, adler, dataBuf);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+private:
+    static u1* debugAlloc(size_t len) {
+        void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+        if (result == MAP_FAILED) {
+            LOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno));
+            dvmAbort();
+        }
+        return reinterpret_cast<u1*>(result);
+    }
+
+    static void debugFree(void* dataBuf, size_t len) {
+        u1* fullBuf = actualBuffer(dataBuf);
+        size_t totalByteCount = actualLength(len);
+        // TODO: we could mprotect instead, and keep the allocation around for a while.
+        // This would be even more expensive, but it might catch more errors.
+        // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
+        //     LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
+        // }
+        if (munmap(fullBuf, totalByteCount) != 0) {
+            LOGW("munmap failed: %s", strerror(errno));
+            dvmAbort();
+        }
+    }
+
+    static const u1* actualBuffer(const void* dataBuf) {
+        return reinterpret_cast<const u1*>(dataBuf) - kGuardLen / 2;
+    }
+
+    static u1* actualBuffer(void* dataBuf) {
+        return reinterpret_cast<u1*>(dataBuf) - kGuardLen / 2;
+    }
+
+    // Underlying length of a user allocation of 'length' bytes.
+    static size_t actualLength(size_t length) {
+        return (length + kGuardLen + 1) & ~0x01;
+    }
+};
+
+/*
+ * Return the width, in bytes, of a primitive type.
+ */
+static int dvmPrimitiveTypeWidth(PrimitiveType primType) {
+    switch (primType) {
+        case PRIM_BOOLEAN: return 1;
+        case PRIM_BYTE:    return 1;
+        case PRIM_SHORT:   return 2;
+        case PRIM_CHAR:    return 2;
+        case PRIM_INT:     return 4;
+        case PRIM_LONG:    return 8;
+        case PRIM_FLOAT:   return 4;
+        case PRIM_DOUBLE:  return 8;
+        case PRIM_VOID:
+        default: {
+            assert(false);
+            return -1;
+        }
+    }
+}
+
+/*
+ * Create a guarded copy of a primitive array.  Modifications to the copied
+ * data are allowed.  Returns a pointer to the copied data.
+ */
+static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCopy) {
+    ScopedCheckJniThreadState ts(env);
+
+    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr);
+    PrimitiveType primType = arrObj->clazz->elementClass->primitiveType;
+    int len = arrObj->length * dvmPrimitiveTypeWidth(primType);
+    void* result = GuardedCopy::create(arrObj->contents, len, true);
+    if (isCopy != NULL) {
+        *isCopy = JNI_TRUE;
+    }
+    return result;
+}
+
+/*
+ * Perform the array "release" operation, which may or may not copy data
+ * back into the VM, and may or may not release the underlying storage.
+ */
+static void* releaseGuardedPACopy(JNIEnv* env, jarray jarr, void* dataBuf, int mode) {
+    ScopedCheckJniThreadState ts(env);
+    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr);
+
+    if (!GuardedCopy::check(dataBuf, true)) {
+        LOGE("JNI: failed guarded copy check in releaseGuardedPACopy");
+        abortMaybe();
+        return NULL;
+    }
+
+    if (mode != JNI_ABORT) {
+        size_t len = GuardedCopy::fromData(dataBuf)->originalLen;
+        memcpy(arrObj->contents, dataBuf, len);
+    }
+
+    u1* result = NULL;
+    if (mode != JNI_COMMIT) {
+        result = (u1*) GuardedCopy::destroy(dataBuf);
+    } else {
+        result = (u1*) (void*) GuardedCopy::fromData(dataBuf)->originalPtr;
+    }
+
+    /* pointer is to the array contents; back up to the array object */
+    result -= OFFSETOF_MEMBER(ArrayObject, contents);
+    return result;
+}
+
+
+/*
+ * ===========================================================================
+ *      JNI functions
+ * ===========================================================================
+ */
+
+#define CHECK_JNI_ENTRY(flags, types, args...) \
+    ScopedCheck sc(env, flags, __FUNCTION__); \
+    sc.check(true, types, ##args)
+
+#define CHECK_JNI_EXIT(type, exp) ({ \
+    typeof (exp) _rc = (exp); \
+    sc.check(false, type, _rc); \
+    _rc; })
+#define CHECK_JNI_EXIT_VOID() \
+    sc.check(false, "V")
+
+static jint Check_GetVersion(JNIEnv* env) {
+    CHECK_JNI_ENTRY(kFlag_Default, "E", env);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
+}
+
+static jclass Check_DefineClass(JNIEnv* env, const char* name, jobject loader,
+    const jbyte* buf, jsize bufLen)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
+    sc.checkClassName(name);
+    return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
+}
+
+static jclass Check_FindClass(JNIEnv* env, const char* name) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
+    sc.checkClassName(name);
+    return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
+}
+
+static jclass Check_GetSuperclass(JNIEnv* env, jclass clazz) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
+    return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
+}
+
+static jboolean Check_IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
+    return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
+}
+
+static jmethodID Check_FromReflectedMethod(JNIEnv* env, jobject method) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
+    // TODO: check that 'field' is a java.lang.reflect.Method.
+    return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
+}
+
+static jfieldID Check_FromReflectedField(JNIEnv* env, jobject field) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
+    // TODO: check that 'field' is a java.lang.reflect.Field.
+    return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
+}
+
+static jobject Check_ToReflectedMethod(JNIEnv* env, jclass cls,
+        jmethodID methodID, jboolean isStatic)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, methodID, isStatic);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, methodID, isStatic));
+}
+
+static jobject Check_ToReflectedField(JNIEnv* env, jclass cls,
+        jfieldID fieldID, jboolean isStatic)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fieldID, isStatic);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fieldID, isStatic));
+}
+
+static jint Check_Throw(JNIEnv* env, jthrowable obj) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
+    // TODO: check that 'obj' is a java.lang.Throwable.
+    return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
+}
+
+static jint Check_ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
+    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
+}
+
+static jthrowable Check_ExceptionOccurred(JNIEnv* env) {
+    CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
+}
+
+static void Check_ExceptionDescribe(JNIEnv* env) {
+    CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
+    baseEnv(env)->ExceptionDescribe(env);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static void Check_ExceptionClear(JNIEnv* env) {
+    CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
+    baseEnv(env)->ExceptionClear(env);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static void Check_FatalError(JNIEnv* env, const char* msg) {
+    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
+    baseEnv(env)->FatalError(env, msg);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static jint Check_PushLocalFrame(JNIEnv* env, jint capacity) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
+}
+
+static jobject Check_PopLocalFrame(JNIEnv* env, jobject res) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
+}
+
+static jobject Check_NewGlobalRef(JNIEnv* env, jobject obj) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
+}
+
+static void Check_DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
+    if (globalRef != NULL && dvmGetJNIRefType(sc.self(), globalRef) != JNIGlobalRefType) {
+        LOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)",
+             globalRef, dvmGetJNIRefType(sc.self(), globalRef));
+        abortMaybe();
+    } else {
+        baseEnv(env)->DeleteGlobalRef(env, globalRef);
+        CHECK_JNI_EXIT_VOID();
+    }
+}
+
+static jobject Check_NewLocalRef(JNIEnv* env, jobject ref) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
+}
+
+static void Check_DeleteLocalRef(JNIEnv* env, jobject localRef) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
+    if (localRef != NULL && dvmGetJNIRefType(sc.self(), localRef) != JNILocalRefType) {
+        LOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)",
+             localRef, dvmGetJNIRefType(sc.self(), localRef));
+        abortMaybe();
+    } else {
+        baseEnv(env)->DeleteLocalRef(env, localRef);
+        CHECK_JNI_EXIT_VOID();
+    }
+}
+
+static jint Check_EnsureLocalCapacity(JNIEnv *env, jint capacity) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
+}
+
+static jboolean Check_IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
+    CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
+    return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
+}
+
+static jobject Check_AllocObject(JNIEnv* env, jclass clazz) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
+}
+
+static jobject Check_NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID);
+    va_list args;
+    va_start(args, methodID);
+    jobject result = baseEnv(env)->NewObjectV(env, clazz, methodID, args);
+    va_end(args);
+    return CHECK_JNI_EXIT("L", result);
+}
+
+static jobject Check_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, methodID, args));
+}
+
+static jobject Check_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue* args) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, methodID, args));
+}
+
+static jclass Check_GetObjectClass(JNIEnv* env, jobject obj) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
+    return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
+}
+
+static jboolean Check_IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
+    CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
+    return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
+}
+
+static jmethodID Check_GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
+    return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
+}
+
+static jfieldID Check_GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
+    return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
+}
+
+static jmethodID Check_GetStaticMethodID(JNIEnv* env, jclass clazz,
+        const char* name, const char* sig)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
+    return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
+}
+
+static jfieldID Check_GetStaticFieldID(JNIEnv* env, jclass clazz,
+        const char* name, const char* sig)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
+    return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
+}
+
+#define FIELD_ACCESSORS(_ctype, _jname, _ftype, _type) \
+    static _ctype Check_GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fieldID); \
+        sc.checkStaticFieldID(clazz, fieldID); \
+        sc.checkFieldTypeForGet(fieldID, _type, true); \
+        return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fieldID)); \
+    } \
+    static _ctype Check_Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fieldID); \
+        sc.checkInstanceFieldID(obj, fieldID); \
+        sc.checkFieldTypeForGet(fieldID, _type, false); \
+        return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fieldID)); \
+    } \
+    static void Check_SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID, _ctype value) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fieldID, value); \
+        sc.checkStaticFieldID(clazz, fieldID); \
+        /* "value" arg only used when type == ref */ \
+        sc.checkFieldTypeForSet((jobject)(u4)value, fieldID, _ftype, true); \
+        baseEnv(env)->SetStatic##_jname##Field(env, clazz, fieldID, value); \
+        CHECK_JNI_EXIT_VOID(); \
+    } \
+    static void Check_Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID, _ctype value) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fieldID, value); \
+        sc.checkInstanceFieldID(obj, fieldID); \
+        /* "value" arg only used when type == ref */ \
+        sc.checkFieldTypeForSet((jobject)(u4) value, fieldID, _ftype, false); \
+        baseEnv(env)->Set##_jname##Field(env, obj, fieldID, value); \
+        CHECK_JNI_EXIT_VOID(); \
+    }
+
+FIELD_ACCESSORS(jobject, Object, PRIM_NOT, "L");
+FIELD_ACCESSORS(jboolean, Boolean, PRIM_BOOLEAN, "Z");
+FIELD_ACCESSORS(jbyte, Byte, PRIM_BYTE, "B");
+FIELD_ACCESSORS(jchar, Char, PRIM_CHAR, "C");
+FIELD_ACCESSORS(jshort, Short, PRIM_SHORT, "S");
+FIELD_ACCESSORS(jint, Int, PRIM_INT, "I");
+FIELD_ACCESSORS(jlong, Long, PRIM_LONG, "J");
+FIELD_ACCESSORS(jfloat, Float, PRIM_FLOAT, "F");
+FIELD_ACCESSORS(jdouble, Double, PRIM_DOUBLE, "D");
+
+#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
+    /* Virtual... */ \
+    static _ctype Check_Call##_jname##Method(JNIEnv* env, jobject obj, \
+        jmethodID methodID, ...) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, false); \
+        sc.checkVirtualMethod(obj, methodID); \
+        _retdecl; \
+        va_list args; \
+        va_start(args, methodID); \
+        _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \
+        va_end(args); \
+        _retok; \
+    } \
+    static _ctype Check_Call##_jname##MethodV(JNIEnv* env, jobject obj, \
+        jmethodID methodID, va_list args) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, false); \
+        sc.checkVirtualMethod(obj, methodID); \
+        _retdecl; \
+        _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \
+        _retok; \
+    } \
+    static _ctype Check_Call##_jname##MethodA(JNIEnv* env, jobject obj, \
+        jmethodID methodID, jvalue* args) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, false); \
+        sc.checkVirtualMethod(obj, methodID); \
+        _retdecl; \
+        _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, methodID, args); \
+        _retok; \
+    } \
+    /* Non-virtual... */ \
+    static _ctype Check_CallNonvirtual##_jname##Method(JNIEnv* env, \
+        jobject obj, jclass clazz, jmethodID methodID, ...) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, false); \
+        sc.checkVirtualMethod(obj, methodID); \
+        _retdecl; \
+        va_list args; \
+        va_start(args, methodID); \
+        _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \
+        va_end(args); \
+        _retok; \
+    } \
+    static _ctype Check_CallNonvirtual##_jname##MethodV(JNIEnv* env, \
+        jobject obj, jclass clazz, jmethodID methodID, va_list args) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, false); \
+        sc.checkVirtualMethod(obj, methodID); \
+        _retdecl; \
+        _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \
+        _retok; \
+    } \
+    static _ctype Check_CallNonvirtual##_jname##MethodA(JNIEnv* env, \
+        jobject obj, jclass clazz, jmethodID methodID, jvalue* args) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, false); \
+        sc.checkVirtualMethod(obj, methodID); \
+        _retdecl; \
+        _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, methodID, args); \
+        _retok; \
+    } \
+    /* Static... */ \
+    static _ctype Check_CallStatic##_jname##Method(JNIEnv* env, \
+        jclass clazz, jmethodID methodID, ...) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, true); \
+        sc.checkStaticMethod(clazz, methodID); \
+        _retdecl; \
+        va_list args; \
+        va_start(args, methodID); \
+        _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \
+        va_end(args); \
+        _retok; \
+    } \
+    static _ctype Check_CallStatic##_jname##MethodV(JNIEnv* env, \
+        jclass clazz, jmethodID methodID, va_list args) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, true); \
+        sc.checkStaticMethod(clazz, methodID); \
+        _retdecl; \
+        _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \
+        _retok; \
+    } \
+    static _ctype Check_CallStatic##_jname##MethodA(JNIEnv* env, \
+        jclass clazz, jmethodID methodID, jvalue* args) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \
+        sc.checkSig(methodID, _retsig, true); \
+        sc.checkStaticMethod(clazz, methodID); \
+        _retdecl; \
+        _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, methodID, args); \
+        _retok; \
+    }
+
+#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
+#define VOID_RETURN CHECK_JNI_EXIT_VOID()
+
+CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L");
+CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z");
+CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B");
+CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C");
+CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S");
+CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I");
+CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J");
+CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F");
+CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D");
+CALL(void, Void, , , VOID_RETURN, "V");
+
+static jstring Check_NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
+    return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
+}
+
+static jsize Check_GetStringLength(JNIEnv* env, jstring string) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
+}
+
+static const jchar* Check_GetStringChars(JNIEnv* env, jstring string, jboolean* isCopy) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
+    const jchar* result = baseEnv(env)->GetStringChars(env, string, isCopy);
+    if (gDvmJni.forceCopy && result != NULL) {
+        ScopedCheckJniThreadState ts(env);
+        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string);
+        int byteCount = strObj->length() * 2;
+        result = (const jchar*) GuardedCopy::create(result, byteCount, false);
+        if (isCopy != NULL) {
+            *isCopy = JNI_TRUE;
+        }
+    }
+    return CHECK_JNI_EXIT("p", result);
+}
+
+static void Check_ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
+    sc.checkNonNull(chars);
+    if (gDvmJni.forceCopy) {
+        if (!GuardedCopy::check(chars, false)) {
+            LOGE("JNI: failed guarded copy check in ReleaseStringChars");
+            abortMaybe();
+            return;
+        }
+        chars = (const jchar*) GuardedCopy::destroy((jchar*)chars);
+    }
+    baseEnv(env)->ReleaseStringChars(env, string, chars);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static jstring Check_NewStringUTF(JNIEnv* env, const char* bytes) {
+    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
+    return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
+}
+
+static jsize Check_GetStringUTFLength(JNIEnv* env, jstring string) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
+}
+
+static const char* Check_GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
+    const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
+    if (gDvmJni.forceCopy && result != NULL) {
+        result = (const char*) GuardedCopy::create(result, strlen(result) + 1, false);
+        if (isCopy != NULL) {
+            *isCopy = JNI_TRUE;
+        }
+    }
+    return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
+}
+
+static void Check_ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
+    CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
+    if (gDvmJni.forceCopy) {
+        if (!GuardedCopy::check(utf, false)) {
+            LOGE("JNI: failed guarded copy check in ReleaseStringUTFChars");
+            abortMaybe();
+            return;
+        }
+        utf = (const char*) GuardedCopy::destroy((char*)utf);
+    }
+    baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static jsize Check_GetArrayLength(JNIEnv* env, jarray array) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
+}
+
+static jobjectArray Check_NewObjectArray(JNIEnv* env, jsize length,
+        jclass elementClass, jobject initialElement)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
+    return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
+}
+
+static jobject Check_GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
+}
+
+static void Check_SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
+    baseEnv(env)->SetObjectArrayElement(env, array, index, value);
+    CHECK_JNI_EXIT_VOID();
+}
+
+#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
+    static _artype Check_New##_jname##Array(JNIEnv* env, jsize length) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
+        return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
+    }
+NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
+NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
+NEW_PRIMITIVE_ARRAY(jcharArray, Char);
+NEW_PRIMITIVE_ARRAY(jshortArray, Short);
+NEW_PRIMITIVE_ARRAY(jintArray, Int);
+NEW_PRIMITIVE_ARRAY(jlongArray, Long);
+NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
+NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
+
+
+/*
+ * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
+ * The code deliberately uses an invalid sequence of operations, so we
+ * need to pass it through unmodified.  Review that code before making
+ * any changes here.
+ */
+#define kNoCopyMagic    0xd5aab57f
+
+#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
+    static _ctype* Check_Get##_jname##ArrayElements(JNIEnv* env, \
+        _ctype##Array array, jboolean* isCopy) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
+        u4 noCopy = 0; \
+        if (gDvmJni.forceCopy && isCopy != NULL) { \
+            /* capture this before the base call tramples on it */ \
+            noCopy = *(u4*) isCopy; \
+        } \
+        _ctype* result = baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy); \
+        if (gDvmJni.forceCopy && result != NULL) { \
+            if (noCopy == kNoCopyMagic) { \
+                LOGV("FC: not copying %p %x", array, noCopy); \
+            } else { \
+                result = (_ctype*) createGuardedPACopy(env, array, isCopy); \
+            } \
+        } \
+        return CHECK_JNI_EXIT("p", result); \
+    }
+
+#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
+    static void Check_Release##_jname##ArrayElements(JNIEnv* env, \
+        _ctype##Array array, _ctype* elems, jint mode) \
+    { \
+        CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
+        sc.checkNonNull(elems); \
+        if (gDvmJni.forceCopy) { \
+            if ((uintptr_t)elems == kNoCopyMagic) { \
+                LOGV("FC: not freeing %p", array); \
+                elems = NULL;   /* base JNI call doesn't currently need */ \
+            } else { \
+                elems = (_ctype*) releaseGuardedPACopy(env, array, elems, mode); \
+            } \
+        } \
+        baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
+        CHECK_JNI_EXIT_VOID(); \
+    }
+
+#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
+    static void Check_Get##_jname##ArrayRegion(JNIEnv* env, \
+            _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
+        baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
+        CHECK_JNI_EXIT_VOID(); \
+    }
+
+#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
+    static void Check_Set##_jname##ArrayRegion(JNIEnv* env, \
+            _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
+        CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
+        baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
+        CHECK_JNI_EXIT_VOID(); \
+    }
+
+#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
+    GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
+    RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
+    GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
+    SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
+
+/* TODO: verify primitive array type matches call type */
+PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
+PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
+PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
+PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
+PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
+PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
+PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
+PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
+
+static jint Check_RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods,
+        jint nMethods)
+{
+    CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
+}
+
+static jint Check_UnregisterNatives(JNIEnv* env, jclass clazz) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
+}
+
+static jint Check_MonitorEnter(JNIEnv* env, jobject obj) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
+}
+
+static jint Check_MonitorExit(JNIEnv* env, jobject obj) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
+}
+
+static jint Check_GetJavaVM(JNIEnv *env, JavaVM **vm) {
+    CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
+    return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
+}
+
+static void Check_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
+    baseEnv(env)->GetStringRegion(env, str, start, len, buf);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static void Check_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
+    baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static void* Check_GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
+    CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
+    void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
+    if (gDvmJni.forceCopy && result != NULL) {
+        result = createGuardedPACopy(env, array, isCopy);
+    }
+    return CHECK_JNI_EXIT("p", result);
+}
+
+static void Check_ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode)
+{
+    CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
+    sc.checkNonNull(carray);
+    if (gDvmJni.forceCopy) {
+        carray = releaseGuardedPACopy(env, array, carray, mode);
+    }
+    baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string, jboolean* isCopy) {
+    CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, string, isCopy);
+    const jchar* result = baseEnv(env)->GetStringCritical(env, string, isCopy);
+    if (gDvmJni.forceCopy && result != NULL) {
+        ScopedCheckJniThreadState ts(env);
+        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string);
+        int byteCount = strObj->length() * 2;
+        result = (const jchar*) GuardedCopy::create(result, byteCount, false);
+        if (isCopy != NULL) {
+            *isCopy = JNI_TRUE;
+        }
+    }
+    return CHECK_JNI_EXIT("p", result);
+}
+
+static void Check_ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
+    CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
+    sc.checkNonNull(carray);
+    if (gDvmJni.forceCopy) {
+        if (!GuardedCopy::check(carray, false)) {
+            LOGE("JNI: failed guarded copy check in ReleaseStringCritical");
+            abortMaybe();
+            return;
+        }
+        carray = (const jchar*) GuardedCopy::destroy((jchar*)carray);
+    }
+    baseEnv(env)->ReleaseStringCritical(env, string, carray);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static jweak Check_NewWeakGlobalRef(JNIEnv* env, jobject obj) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
+    return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
+}
+
+static void Check_DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
+    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
+    baseEnv(env)->DeleteWeakGlobalRef(env, obj);
+    CHECK_JNI_EXIT_VOID();
+}
+
+static jboolean Check_ExceptionCheck(JNIEnv* env) {
+    CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
+    return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
+}
+
+static jobjectRefType Check_GetObjectRefType(JNIEnv* env, jobject obj) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
+    // TODO: proper decoding of jobjectRefType!
+    return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
+}
+
+static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
+    if (address == NULL || capacity < 0) {
+        LOGW("JNI WARNING: invalid values for address (%p) or capacity (%ld)",
+            address, (long) capacity);
+        abortMaybe();
+        return NULL;
+    }
+    return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
+}
+
+static void* Check_GetDirectBufferAddress(JNIEnv* env, jobject buf) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
+    // TODO: check that 'buf' is a java.nio.Buffer.
+    return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
+}
+
+static jlong Check_GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
+    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
+    // TODO: check that 'buf' is a java.nio.Buffer.
+    return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
+}
+
+
+/*
+ * ===========================================================================
+ *      JNI invocation functions
+ * ===========================================================================
+ */
+
+static jint Check_DestroyJavaVM(JavaVM* vm) {
+    ScopedCheck sc(false, __FUNCTION__);
+    sc.check(true, "v", vm);
+    return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm));
+}
+
+static jint Check_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
+    ScopedCheck sc(false, __FUNCTION__);
+    sc.check(true, "vpp", vm, p_env, thr_args);
+    return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
+}
+
+static jint Check_AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
+    ScopedCheck sc(false, __FUNCTION__);
+    sc.check(true, "vpp", vm, p_env, thr_args);
+    return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
+}
+
+static jint Check_DetachCurrentThread(JavaVM* vm) {
+    ScopedCheck sc(true, __FUNCTION__);
+    sc.check(true, "v", vm);
+    return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm));
+}
+
+static jint Check_GetEnv(JavaVM* vm, void** env, jint version) {
+    ScopedCheck sc(true, __FUNCTION__);
+    sc.check(true, "v", vm);
+    return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version));
+}
+
+
+/*
+ * ===========================================================================
+ *      Function tables
+ * ===========================================================================
+ */
+
+static const struct JNINativeInterface gCheckNativeInterface = {
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+
+    Check_GetVersion,
+
+    Check_DefineClass,
+    Check_FindClass,
+
+    Check_FromReflectedMethod,
+    Check_FromReflectedField,
+    Check_ToReflectedMethod,
+
+    Check_GetSuperclass,
+    Check_IsAssignableFrom,
+
+    Check_ToReflectedField,
+
+    Check_Throw,
+    Check_ThrowNew,
+    Check_ExceptionOccurred,
+    Check_ExceptionDescribe,
+    Check_ExceptionClear,
+    Check_FatalError,
+
+    Check_PushLocalFrame,
+    Check_PopLocalFrame,
+
+    Check_NewGlobalRef,
+    Check_DeleteGlobalRef,
+    Check_DeleteLocalRef,
+    Check_IsSameObject,
+    Check_NewLocalRef,
+    Check_EnsureLocalCapacity,
+
+    Check_AllocObject,
+    Check_NewObject,
+    Check_NewObjectV,
+    Check_NewObjectA,
+
+    Check_GetObjectClass,
+    Check_IsInstanceOf,
+
+    Check_GetMethodID,
+
+    Check_CallObjectMethod,
+    Check_CallObjectMethodV,
+    Check_CallObjectMethodA,
+    Check_CallBooleanMethod,
+    Check_CallBooleanMethodV,
+    Check_CallBooleanMethodA,
+    Check_CallByteMethod,
+    Check_CallByteMethodV,
+    Check_CallByteMethodA,
+    Check_CallCharMethod,
+    Check_CallCharMethodV,
+    Check_CallCharMethodA,
+    Check_CallShortMethod,
+    Check_CallShortMethodV,
+    Check_CallShortMethodA,
+    Check_CallIntMethod,
+    Check_CallIntMethodV,
+    Check_CallIntMethodA,
+    Check_CallLongMethod,
+    Check_CallLongMethodV,
+    Check_CallLongMethodA,
+    Check_CallFloatMethod,
+    Check_CallFloatMethodV,
+    Check_CallFloatMethodA,
+    Check_CallDoubleMethod,
+    Check_CallDoubleMethodV,
+    Check_CallDoubleMethodA,
+    Check_CallVoidMethod,
+    Check_CallVoidMethodV,
+    Check_CallVoidMethodA,
+
+    Check_CallNonvirtualObjectMethod,
+    Check_CallNonvirtualObjectMethodV,
+    Check_CallNonvirtualObjectMethodA,
+    Check_CallNonvirtualBooleanMethod,
+    Check_CallNonvirtualBooleanMethodV,
+    Check_CallNonvirtualBooleanMethodA,
+    Check_CallNonvirtualByteMethod,
+    Check_CallNonvirtualByteMethodV,
+    Check_CallNonvirtualByteMethodA,
+    Check_CallNonvirtualCharMethod,
+    Check_CallNonvirtualCharMethodV,
+    Check_CallNonvirtualCharMethodA,
+    Check_CallNonvirtualShortMethod,
+    Check_CallNonvirtualShortMethodV,
+    Check_CallNonvirtualShortMethodA,
+    Check_CallNonvirtualIntMethod,
+    Check_CallNonvirtualIntMethodV,
+    Check_CallNonvirtualIntMethodA,
+    Check_CallNonvirtualLongMethod,
+    Check_CallNonvirtualLongMethodV,
+    Check_CallNonvirtualLongMethodA,
+    Check_CallNonvirtualFloatMethod,
+    Check_CallNonvirtualFloatMethodV,
+    Check_CallNonvirtualFloatMethodA,
+    Check_CallNonvirtualDoubleMethod,
+    Check_CallNonvirtualDoubleMethodV,
+    Check_CallNonvirtualDoubleMethodA,
+    Check_CallNonvirtualVoidMethod,
+    Check_CallNonvirtualVoidMethodV,
+    Check_CallNonvirtualVoidMethodA,
+
+    Check_GetFieldID,
+
+    Check_GetObjectField,
+    Check_GetBooleanField,
+    Check_GetByteField,
+    Check_GetCharField,
+    Check_GetShortField,
+    Check_GetIntField,
+    Check_GetLongField,
+    Check_GetFloatField,
+    Check_GetDoubleField,
+    Check_SetObjectField,
+    Check_SetBooleanField,
+    Check_SetByteField,
+    Check_SetCharField,
+    Check_SetShortField,
+    Check_SetIntField,
+    Check_SetLongField,
+    Check_SetFloatField,
+    Check_SetDoubleField,
+
+    Check_GetStaticMethodID,
+
+    Check_CallStaticObjectMethod,
+    Check_CallStaticObjectMethodV,
+    Check_CallStaticObjectMethodA,
+    Check_CallStaticBooleanMethod,
+    Check_CallStaticBooleanMethodV,
+    Check_CallStaticBooleanMethodA,
+    Check_CallStaticByteMethod,
+    Check_CallStaticByteMethodV,
+    Check_CallStaticByteMethodA,
+    Check_CallStaticCharMethod,
+    Check_CallStaticCharMethodV,
+    Check_CallStaticCharMethodA,
+    Check_CallStaticShortMethod,
+    Check_CallStaticShortMethodV,
+    Check_CallStaticShortMethodA,
+    Check_CallStaticIntMethod,
+    Check_CallStaticIntMethodV,
+    Check_CallStaticIntMethodA,
+    Check_CallStaticLongMethod,
+    Check_CallStaticLongMethodV,
+    Check_CallStaticLongMethodA,
+    Check_CallStaticFloatMethod,
+    Check_CallStaticFloatMethodV,
+    Check_CallStaticFloatMethodA,
+    Check_CallStaticDoubleMethod,
+    Check_CallStaticDoubleMethodV,
+    Check_CallStaticDoubleMethodA,
+    Check_CallStaticVoidMethod,
+    Check_CallStaticVoidMethodV,
+    Check_CallStaticVoidMethodA,
+
+    Check_GetStaticFieldID,
+
+    Check_GetStaticObjectField,
+    Check_GetStaticBooleanField,
+    Check_GetStaticByteField,
+    Check_GetStaticCharField,
+    Check_GetStaticShortField,
+    Check_GetStaticIntField,
+    Check_GetStaticLongField,
+    Check_GetStaticFloatField,
+    Check_GetStaticDoubleField,
+
+    Check_SetStaticObjectField,
+    Check_SetStaticBooleanField,
+    Check_SetStaticByteField,
+    Check_SetStaticCharField,
+    Check_SetStaticShortField,
+    Check_SetStaticIntField,
+    Check_SetStaticLongField,
+    Check_SetStaticFloatField,
+    Check_SetStaticDoubleField,
+
+    Check_NewString,
+
+    Check_GetStringLength,
+    Check_GetStringChars,
+    Check_ReleaseStringChars,
+
+    Check_NewStringUTF,
+    Check_GetStringUTFLength,
+    Check_GetStringUTFChars,
+    Check_ReleaseStringUTFChars,
+
+    Check_GetArrayLength,
+    Check_NewObjectArray,
+    Check_GetObjectArrayElement,
+    Check_SetObjectArrayElement,
+
+    Check_NewBooleanArray,
+    Check_NewByteArray,
+    Check_NewCharArray,
+    Check_NewShortArray,
+    Check_NewIntArray,
+    Check_NewLongArray,
+    Check_NewFloatArray,
+    Check_NewDoubleArray,
+
+    Check_GetBooleanArrayElements,
+    Check_GetByteArrayElements,
+    Check_GetCharArrayElements,
+    Check_GetShortArrayElements,
+    Check_GetIntArrayElements,
+    Check_GetLongArrayElements,
+    Check_GetFloatArrayElements,
+    Check_GetDoubleArrayElements,
+
+    Check_ReleaseBooleanArrayElements,
+    Check_ReleaseByteArrayElements,
+    Check_ReleaseCharArrayElements,
+    Check_ReleaseShortArrayElements,
+    Check_ReleaseIntArrayElements,
+    Check_ReleaseLongArrayElements,
+    Check_ReleaseFloatArrayElements,
+    Check_ReleaseDoubleArrayElements,
+
+    Check_GetBooleanArrayRegion,
+    Check_GetByteArrayRegion,
+    Check_GetCharArrayRegion,
+    Check_GetShortArrayRegion,
+    Check_GetIntArrayRegion,
+    Check_GetLongArrayRegion,
+    Check_GetFloatArrayRegion,
+    Check_GetDoubleArrayRegion,
+    Check_SetBooleanArrayRegion,
+    Check_SetByteArrayRegion,
+    Check_SetCharArrayRegion,
+    Check_SetShortArrayRegion,
+    Check_SetIntArrayRegion,
+    Check_SetLongArrayRegion,
+    Check_SetFloatArrayRegion,
+    Check_SetDoubleArrayRegion,
+
+    Check_RegisterNatives,
+    Check_UnregisterNatives,
+
+    Check_MonitorEnter,
+    Check_MonitorExit,
+
+    Check_GetJavaVM,
+
+    Check_GetStringRegion,
+    Check_GetStringUTFRegion,
+
+    Check_GetPrimitiveArrayCritical,
+    Check_ReleasePrimitiveArrayCritical,
+
+    Check_GetStringCritical,
+    Check_ReleaseStringCritical,
+
+    Check_NewWeakGlobalRef,
+    Check_DeleteWeakGlobalRef,
+
+    Check_ExceptionCheck,
+
+    Check_NewDirectByteBuffer,
+    Check_GetDirectBufferAddress,
+    Check_GetDirectBufferCapacity,
+
+    Check_GetObjectRefType
+};
+
+static const struct JNIInvokeInterface gCheckInvokeInterface = {
+    NULL,
+    NULL,
+    NULL,
+
+    Check_DestroyJavaVM,
+    Check_AttachCurrentThread,
+    Check_DetachCurrentThread,
+
+    Check_GetEnv,
+
+    Check_AttachCurrentThreadAsDaemon,
+};
+
+/*
+ * Replace the normal table with the checked table.
+ */
+void dvmUseCheckedJniEnv(JNIEnvExt* pEnv) {
+    assert(pEnv->funcTable != &gCheckNativeInterface);
+    pEnv->baseFuncTable = pEnv->funcTable;
+    pEnv->funcTable = &gCheckNativeInterface;
+}
+
+/*
+ * Replace the normal table with the checked table.
+ */
+void dvmUseCheckedJniVm(JavaVMExt* pVm) {
+    assert(pVm->funcTable != &gCheckInvokeInterface);
+    pVm->baseFuncTable = pVm->funcTable;
+    pVm->funcTable = &gCheckInvokeInterface;
+}
diff --git a/vm/Common.h b/vm/Common.h
new file mode 100644
index 0000000..43c7500
--- /dev/null
+++ b/vm/Common.h
@@ -0,0 +1,123 @@
+/*
+ * 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 defines for all Dalvik code.
+ */
+#ifndef DALVIK_COMMON_H_
+#define DALVIK_COMMON_H_
+
+#ifndef LOG_TAG
+# define LOG_TAG "dalvikvm"
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include "cutils/log.h"
+
+#if defined(HAVE_ENDIAN_H)
+# include <endian.h>
+#else /*not HAVE_ENDIAN_H*/
+# define __BIG_ENDIAN 4321
+# define __LITTLE_ENDIAN 1234
+# if defined(HAVE_LITTLE_ENDIAN)
+#  define __BYTE_ORDER __LITTLE_ENDIAN
+# else
+#  define __BYTE_ORDER __BIG_ENDIAN
+# endif
+#endif /*not HAVE_ENDIAN_H*/
+
+#if !defined(NDEBUG) && defined(WITH_DALVIK_ASSERT)
+# undef assert
+# define assert(x) \
+    ((x) ? ((void)0) : (LOGE("ASSERT FAILED (%s:%d): %s", \
+        __FILE__, __LINE__, #x), *(int*)39=39, (void)0) )
+#endif
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+#define LIKELY(exp) (__builtin_expect((exp) != 0, true))
+#define UNLIKELY(exp) (__builtin_expect((exp) != 0, false))
+
+#define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
+#define ALIGN_DOWN(x, n) ((size_t)(x) & -(n))
+#define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
+#define ALIGN_DOWN_TO_PAGE_SIZE(p) ALIGN_DOWN(p, SYSTEM_PAGE_SIZE)
+
+#define CLZ(x) __builtin_clz(x)
+
+/*
+ * If "very verbose" logging is enabled, make it equivalent to LOGV.
+ * Otherwise, make it disappear.
+ *
+ * Define this above the #include "Dalvik.h" to enable for only a
+ * single file.
+ */
+/* #define VERY_VERBOSE_LOG */
+#if defined(VERY_VERBOSE_LOG)
+# define LOGVV      LOGV
+# define IF_LOGVV() IF_LOGV()
+#else
+# define LOGVV(...) ((void)0)
+# define IF_LOGVV() if (false)
+#endif
+
+
+/*
+ * These match the definitions in the VM specification.
+ */
+typedef uint8_t             u1;
+typedef uint16_t            u2;
+typedef uint32_t            u4;
+typedef uint64_t            u8;
+typedef int8_t              s1;
+typedef int16_t             s2;
+typedef int32_t             s4;
+typedef int64_t             s8;
+
+/*
+ * Storage for primitive types and object references.
+ *
+ * Some parts of the code (notably object field access) assume that values
+ * are "left aligned", i.e. given "JValue jv", "jv.i" and "*((s4*)&jv)"
+ * yield the same result.  This seems to be guaranteed by gcc on big- and
+ * little-endian systems.
+ */
+struct Object;
+
+union JValue {
+    u1      z;
+    s1      b;
+    u2      c;
+    s2      s;
+    s4      i;
+    s8      j;
+    float   f;
+    double  d;
+    Object* l;
+};
+
+#define OFFSETOF_MEMBER(t, f)         \
+  (reinterpret_cast<char*>(           \
+     &reinterpret_cast<t*>(16)->f) -  \
+   reinterpret_cast<char*>(16))
+
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+#endif  // DALVIK_COMMON_H_
diff --git a/vm/Dalvik.h b/vm/Dalvik.h
new file mode 100644
index 0000000..eecbf8d
--- /dev/null
+++ b/vm/Dalvik.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+/*
+ * All-inclusive internal header file.  Include this to get everything useful.
+ */
+#ifndef DALVIK_DALVIK_H_
+#define DALVIK_DALVIK_H_
+
+#include "Common.h"
+#include "Inlines.h"
+#include "Misc.h"
+#include "Bits.h"
+#include "BitVector.h"
+#include "libdex/SysUtil.h"
+#include "libdex/DexDebugInfo.h"
+#include "libdex/DexFile.h"
+#include "libdex/DexProto.h"
+#include "libdex/DexUtf.h"
+#include "libdex/ZipArchive.h"
+#include "DvmDex.h"
+#include "RawDexFile.h"
+#include "Sync.h"
+#include "oo/Object.h"
+#include "Native.h"
+#include "native/InternalNative.h"
+
+#include "DalvikVersion.h"
+#include "Debugger.h"
+#include "Profile.h"
+#include "UtfString.h"
+#include "Intern.h"
+#include "ReferenceTable.h"
+#include "IndirectRefTable.h"
+#include "AtomicCache.h"
+#include "Thread.h"
+#include "Ddm.h"
+#include "Hash.h"
+#include "interp/Stack.h"
+#include "oo/Class.h"
+#include "oo/Resolve.h"
+#include "oo/Array.h"
+#include "Exception.h"
+#include "alloc/Alloc.h"
+#include "alloc/CardTable.h"
+#include "alloc/HeapDebug.h"
+#include "alloc/WriteBarrier.h"
+#include "oo/AccessCheck.h"
+#include "JarFile.h"
+#include "jdwp/Jdwp.h"
+#include "SignalCatcher.h"
+#include "StdioConverter.h"
+#include "JniInternal.h"
+#include "LinearAlloc.h"
+#include "analysis/DexVerify.h"
+#include "analysis/DexPrepare.h"
+#include "analysis/RegisterMap.h"
+#include "Init.h"
+#include "libdex/DexOpcodes.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"
+#include "Atomic.h"
+#include "interp/Interp.h"
+#include "InlineNative.h"
+#include "oo/ObjectInlines.h"
+
+#endif  // DALVIK_DALVIK_H_
diff --git a/vm/DalvikVersion.h b/vm/DalvikVersion.h
new file mode 100644
index 0000000..e71c839
--- /dev/null
+++ b/vm/DalvikVersion.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik VM version info.
+ */
+#ifndef DALVIK_VERSION_H_
+#define DALVIK_VERSION_H_
+
+/*
+ * The version we show to tourists.
+ */
+#define DALVIK_MAJOR_VERSION    1
+#define DALVIK_MINOR_VERSION    6
+#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         27
+
+#endif  // DALVIK_VERSION_H_
diff --git a/vm/Ddm.cpp b/vm/Ddm.cpp
new file mode 100644
index 0000000..e370204
--- /dev/null
+++ b/vm/Ddm.cpp
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+/*
+ * Handle Dalvik Debug Monitor requests and events.
+ *
+ * Remember that all DDM traffic is big-endian since it travels over the
+ * JDWP connection.
+ */
+#include "Dalvik.h"
+
+#include <fcntl.h>
+#include <errno.h>
+
+/*
+ * "buf" contains a full JDWP packet, possibly with multiple chunks.  We
+ * need to process each, accumulate the replies, and ship the whole thing
+ * back.
+ *
+ * Returns "true" if we have a reply.  The reply buffer is newly allocated,
+ * and includes the chunk type/length, followed by the data.
+ *
+ * TODO: we currently assume that the request and reply include a single
+ * chunk.  If this becomes inconvenient we will need to adapt.
+ */
+bool dvmDdmHandlePacket(const u1* buf, int dataLen, u1** pReplyBuf,
+    int* pReplyLen)
+{
+    Thread* self = dvmThreadSelf();
+    const int kChunkHdrLen = 8;
+    ArrayObject* dataArray = NULL;
+    Object* chunk = NULL;
+    bool result = false;
+
+    assert(dataLen >= 0);
+
+    if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyDalvikDdmcChunk)) {
+        if (!dvmInitClass(gDvm.classOrgApacheHarmonyDalvikDdmcChunk)) {
+            dvmLogExceptionStackTrace();
+            dvmClearException(self);
+            goto bail;
+        }
+    }
+
+    /*
+     * The chunk handlers are written in the Java programming language, so
+     * we need to convert the buffer to a byte array.
+     */
+    dataArray = dvmAllocPrimitiveArray('B', dataLen, ALLOC_DEFAULT);
+    if (dataArray == NULL) {
+        LOGW("array alloc failed (%d)", dataLen);
+        dvmClearException(self);
+        goto bail;
+    }
+    memcpy(dataArray->contents, buf, dataLen);
+
+    /*
+     * Run through and find all chunks.  [Currently just find the first.]
+     */
+    unsigned int offset, length, type;
+    type = get4BE((u1*)dataArray->contents + 0);
+    length = get4BE((u1*)dataArray->contents + 4);
+    offset = kChunkHdrLen;
+    if (offset+length > (unsigned int) dataLen) {
+        LOGW("WARNING: bad chunk found (len=%u pktLen=%d)", length, dataLen);
+        goto bail;
+    }
+
+    /*
+     * Call the handler.
+     */
+    JValue callRes;
+    dvmCallMethod(self, gDvm.methDalvikDdmcServer_dispatch, NULL, &callRes,
+        type, dataArray, offset, length);
+    if (dvmCheckException(self)) {
+        LOGI("Exception thrown by dispatcher for 0x%08x", type);
+        dvmLogExceptionStackTrace();
+        dvmClearException(self);
+        goto bail;
+    }
+
+    ArrayObject* replyData;
+    chunk = (Object*) callRes.l;
+    if (chunk == NULL)
+        goto bail;
+
+    /* not strictly necessary -- we don't alloc from managed heap here */
+    dvmAddTrackedAlloc(chunk, self);
+
+    /*
+     * Pull the pieces out of the chunk.  We copy the results into a
+     * newly-allocated buffer that the caller can free.  We don't want to
+     * continue using the Chunk object because nothing has a reference to it.
+     *
+     * We could avoid this by returning type/data/offset/length and having
+     * the caller be aware of the object lifetime issues, but that
+     * integrates the JDWP code more tightly into the VM, and doesn't work
+     * if we have responses for multiple chunks.
+     *
+     * So we're pretty much stuck with copying data around multiple times.
+     */
+    type = dvmGetFieldInt(chunk, gDvm.offDalvikDdmcChunk_type);
+    replyData =
+        (ArrayObject*) dvmGetFieldObject(chunk, gDvm.offDalvikDdmcChunk_data);
+    offset = dvmGetFieldInt(chunk, gDvm.offDalvikDdmcChunk_offset);
+    length = dvmGetFieldInt(chunk, gDvm.offDalvikDdmcChunk_length);
+
+    LOGV("DDM reply: type=0x%08x data=%p offset=%d length=%d",
+        type, replyData, offset, length);
+
+    if (length == 0 || replyData == NULL)
+        goto bail;
+    if (offset + length > replyData->length) {
+        LOGW("WARNING: chunk off=%d len=%d exceeds reply array len %d",
+            offset, length, replyData->length);
+        goto bail;
+    }
+
+    u1* reply;
+    reply = (u1*) malloc(length + kChunkHdrLen);
+    if (reply == NULL) {
+        LOGW("malloc %d failed", length+kChunkHdrLen);
+        goto bail;
+    }
+    set4BE(reply + 0, type);
+    set4BE(reply + 4, length);
+    memcpy(reply+kChunkHdrLen, (const u1*)replyData->contents + offset, length);
+
+    *pReplyBuf = reply;
+    *pReplyLen = length + kChunkHdrLen;
+    result = true;
+
+    LOGV("dvmHandleDdm returning type=%.4s buf=%p len=%d",
+        (char*) reply, reply, length);
+
+bail:
+    dvmReleaseTrackedAlloc((Object*) dataArray, self);
+    dvmReleaseTrackedAlloc(chunk, self);
+    return result;
+}
+
+/* defined in org.apache.harmony.dalvik.ddmc.DdmServer */
+#define CONNECTED       1
+#define DISCONNECTED    2
+
+/*
+ * Broadcast an event to all handlers.
+ */
+static void broadcast(int event)
+{
+    Thread* self = dvmThreadSelf();
+
+    if (self->status != THREAD_RUNNING) {
+        LOGE("ERROR: DDM broadcast with thread status=%d", self->status);
+        /* try anyway? */
+    }
+
+    if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyDalvikDdmcDdmServer)) {
+        if (!dvmInitClass(gDvm.classOrgApacheHarmonyDalvikDdmcDdmServer)) {
+            dvmLogExceptionStackTrace();
+            dvmClearException(self);
+            return;
+        }
+    }
+
+    JValue unused;
+    dvmCallMethod(self, gDvm.methDalvikDdmcServer_broadcast, NULL, &unused,
+        event);
+    if (dvmCheckException(self)) {
+        LOGI("Exception thrown by broadcast(%d)", event);
+        dvmLogExceptionStackTrace();
+        dvmClearException(self);
+        return;
+    }
+}
+
+/*
+ * First DDM packet has arrived over JDWP.  Notify the press.
+ *
+ * We can do some initialization here too.
+ */
+void dvmDdmConnected()
+{
+    // TODO: any init
+
+    LOGV("Broadcasting DDM connect");
+    broadcast(CONNECTED);
+}
+
+/*
+ * JDWP connection has dropped.
+ *
+ * Do some cleanup.
+ */
+void dvmDdmDisconnected()
+{
+    LOGV("Broadcasting DDM disconnect");
+    broadcast(DISCONNECTED);
+
+    gDvm.ddmThreadNotification = false;
+}
+
+
+/*
+ * Turn thread notification on or off.
+ */
+void dvmDdmSetThreadNotification(bool enable)
+{
+    /*
+     * We lock the thread list to avoid sending duplicate events or missing
+     * a thread change.  We should be okay holding this lock while sending
+     * the messages out.  (We have to hold it while accessing a live thread.)
+     */
+    dvmLockThreadList(NULL);
+    gDvm.ddmThreadNotification = enable;
+
+    if (enable) {
+        Thread* thread;
+        for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+            //LOGW("notify %d", thread->threadId);
+            dvmDdmSendThreadNotification(thread, true);
+        }
+    }
+
+    dvmUnlockThreadList();
+}
+
+/*
+ * Send a notification when a thread starts or stops.
+ *
+ * Because we broadcast the full set of threads when the notifications are
+ * first enabled, it's possible for "thread" to be actively executing.
+ */
+void dvmDdmSendThreadNotification(Thread* thread, bool started)
+{
+    if (!gDvm.ddmThreadNotification) {
+        return;
+    }
+
+    StringObject* nameObj = NULL;
+    Object* threadObj = thread->threadObj;
+
+    if (threadObj != NULL) {
+        nameObj = (StringObject*)
+            dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_name);
+    }
+
+    int type, len;
+    u1 buf[256];
+
+    if (started) {
+        const u2* chars;
+        u2* outChars;
+        size_t stringLen;
+
+        type = CHUNK_TYPE("THCR");
+
+        if (nameObj != NULL) {
+            stringLen = nameObj->length();
+            chars = nameObj->chars();
+        } else {
+            stringLen = 0;
+            chars = NULL;
+        }
+
+        /* leave room for the two integer fields */
+        if (stringLen > (sizeof(buf) - sizeof(u4)*2) / 2) {
+            stringLen = (sizeof(buf) - sizeof(u4)*2) / 2;
+        }
+        len = stringLen*2 + sizeof(u4)*2;
+
+        set4BE(&buf[0x00], thread->threadId);
+        set4BE(&buf[0x04], stringLen);
+
+        /* copy the UTF-16 string, transforming to big-endian */
+        outChars = (u2*)(void*)&buf[0x08];
+        while (stringLen--) {
+            set2BE((u1*) (outChars++), *chars++);
+        }
+    } else {
+        type = CHUNK_TYPE("THDE");
+
+        len = 4;
+
+        set4BE(&buf[0x00], thread->threadId);
+    }
+
+    dvmDbgDdmSendChunk(type, len, buf);
+}
+
+/*
+ * Send a notification when a thread's name changes.
+ */
+void dvmDdmSendThreadNameChange(int threadId, StringObject* newName)
+{
+    if (!gDvm.ddmThreadNotification) {
+        return;
+    }
+
+    size_t stringLen = newName->length();
+    const u2* chars = newName->chars();
+
+    /*
+     * Output format:
+     *  (4b) thread ID
+     *  (4b) stringLen
+     *  (xb) string chars
+     */
+    int bufLen = 4 + 4 + (stringLen * 2);
+    u1 buf[bufLen];
+
+    set4BE(&buf[0x00], threadId);
+    set4BE(&buf[0x04], stringLen);
+    u2* outChars = (u2*)(void*)&buf[0x08];
+    while (stringLen--) {
+        set2BE((u1*) (outChars++), *chars++);
+    }
+
+    dvmDbgDdmSendChunk(CHUNK_TYPE("THNM"), bufLen, buf);
+}
+
+/*
+ * Generate the contents of a THST chunk.  The data encompasses all known
+ * threads.
+ *
+ * Response has:
+ *  (1b) header len
+ *  (1b) bytes per entry
+ *  (2b) thread count
+ * Then, for each thread:
+ *  (4b) threadId
+ *  (1b) thread status
+ *  (4b) tid
+ *  (4b) utime
+ *  (4b) stime
+ *  (1b) is daemon?
+ *
+ * The length fields exist in anticipation of adding additional fields
+ * without wanting to break ddms or bump the full protocol version.  I don't
+ * think it warrants full versioning.  They might be extraneous and could
+ * be removed from a future version.
+ *
+ * Returns a new byte[] with the data inside, or NULL on failure.  The
+ * caller must call dvmReleaseTrackedAlloc() on the array.
+ */
+ArrayObject* dvmDdmGenerateThreadStats()
+{
+    const int kHeaderLen = 4;
+    const int kBytesPerEntry = 18;
+
+    dvmLockThreadList(NULL);
+
+    Thread* thread;
+    int threadCount = 0;
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next)
+        threadCount++;
+
+    /*
+     * Create a temporary buffer.  We can't perform heap allocation with
+     * the thread list lock held (could cause a GC).  The output is small
+     * enough to sit on the stack.
+     */
+    int bufLen = kHeaderLen + threadCount * kBytesPerEntry;
+    u1 tmpBuf[bufLen];
+    u1* buf = tmpBuf;
+
+    set1(buf+0, kHeaderLen);
+    set1(buf+1, kBytesPerEntry);
+    set2BE(buf+2, (u2) threadCount);
+    buf += kHeaderLen;
+
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        bool isDaemon = false;
+
+        ProcStatData procStatData;
+        if (!dvmGetThreadStats(&procStatData, thread->systemTid)) {
+            /* failed; show zero */
+            memset(&procStatData, 0, sizeof(procStatData));
+        }
+
+        Object* threadObj = thread->threadObj;
+        if (threadObj != NULL) {
+            isDaemon = dvmGetFieldBoolean(threadObj,
+                            gDvm.offJavaLangThread_daemon);
+        }
+
+        set4BE(buf+0, thread->threadId);
+        set1(buf+4, thread->status);
+        set4BE(buf+5, thread->systemTid);
+        set4BE(buf+9, procStatData.utime);
+        set4BE(buf+13, procStatData.stime);
+        set1(buf+17, isDaemon);
+
+        buf += kBytesPerEntry;
+    }
+    dvmUnlockThreadList();
+
+
+    /*
+     * Create a byte array to hold the data.
+     */
+    ArrayObject* arrayObj = dvmAllocPrimitiveArray('B', bufLen, ALLOC_DEFAULT);
+    if (arrayObj != NULL)
+        memcpy(arrayObj->contents, tmpBuf, bufLen);
+    return arrayObj;
+}
+
+
+/*
+ * Find the specified thread and return its stack trace as an array of
+ * StackTraceElement objects.
+ */
+ArrayObject* dvmDdmGetStackTraceById(u4 threadId)
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+    int* traceBuf;
+
+    dvmLockThreadList(self);
+
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread->threadId == threadId)
+            break;
+    }
+    if (thread == NULL) {
+        LOGI("dvmDdmGetStackTraceById: threadid=%d not found", threadId);
+        dvmUnlockThreadList();
+        return NULL;
+    }
+
+    /*
+     * Suspend the thread, pull out the stack trace, then resume the thread
+     * and release the thread list lock.  If we're being asked to examine
+     * our own stack trace, skip the suspend/resume.
+     */
+    size_t stackDepth;
+    if (thread != self)
+        dvmSuspendThread(thread);
+    traceBuf = dvmFillInStackTraceRaw(thread, &stackDepth);
+    if (thread != self)
+        dvmResumeThread(thread);
+    dvmUnlockThreadList();
+
+    /*
+     * Convert the raw buffer into an array of StackTraceElement.
+     */
+    ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth);
+    free(traceBuf);
+    return trace;
+}
+
+/*
+ * Gather up the allocation data and copy it into a byte[].
+ *
+ * Returns NULL on failure with an exception raised.
+ */
+ArrayObject* dvmDdmGetRecentAllocations()
+{
+    u1* data;
+    size_t len;
+
+    if (!dvmGenerateTrackedAllocationReport(&data, &len)) {
+        /* assume OOM */
+        dvmThrowOutOfMemoryError("recent alloc native");
+        return NULL;
+    }
+
+    ArrayObject* arrayObj = dvmAllocPrimitiveArray('B', len, ALLOC_DEFAULT);
+    if (arrayObj != NULL)
+        memcpy(arrayObj->contents, data, len);
+    return arrayObj;
+}
diff --git a/vm/Ddm.h b/vm/Ddm.h
new file mode 100644
index 0000000..f8c22ee
--- /dev/null
+++ b/vm/Ddm.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+/*
+ * Dalvik Debug Monitor
+ */
+#ifndef DALVIK_DDM_H_
+#define DALVIK_DDM_H_
+
+/*
+ * Handle a packet full of DDM goodness.
+ *
+ * Returns "true" if we have anything to say in return; in which case,
+ * "*pReplyBuf" and "*pReplyLen" will also be set.
+ */
+bool dvmDdmHandlePacket(const u1* buf, int dataLen, u1** pReplyBuf,
+    int* pReplyLen);
+
+/*
+ * Deal with the DDM server connecting and disconnecting.
+ */
+void dvmDdmConnected(void);
+void dvmDdmDisconnected(void);
+
+/*
+ * Turn thread notification on or off.
+ */
+void dvmDdmSetThreadNotification(bool enable);
+
+/*
+ * If thread start/stop notification is enabled, call this when threads
+ * are created or die.
+ */
+void dvmDdmSendThreadNotification(Thread* thread, bool started);
+
+/*
+ * If thread start/stop notification is enabled, call this when the
+ * thread name changes.
+ */
+void dvmDdmSendThreadNameChange(int threadId, StringObject* newName);
+
+/*
+ * Generate a byte[] full of thread stats for a THST packet.
+ */
+ArrayObject* dvmDdmGenerateThreadStats(void);
+
+/*
+ * Let the heap know that the HPIF when value has changed.
+ *
+ * @return true iff the when value is supported by the VM.
+ */
+bool dvmDdmHandleHpifChunk(int when);
+
+/*
+ * Let the heap know that the HPSG or NHSG what/when values have changed.
+ *
+ * @param native false for an HPSG chunk, true for an NHSG chunk
+ *
+ * @return true iff the what/when values are supported by the VM.
+ */
+bool dvmDdmHandleHpsgNhsgChunk(int when, int what, bool native);
+
+/*
+ * Get an array of StackTraceElement objects for the specified thread.
+ */
+ArrayObject* dvmDdmGetStackTraceById(u4 threadId);
+
+/*
+ * Gather up recent allocation data and return it in a byte[].
+ *
+ * Returns NULL on failure with an exception raised.
+ */
+ArrayObject* dvmDdmGetRecentAllocations(void);
+
+#endif  // DALVIK_DDM_H_
diff --git a/vm/Debugger.cpp b/vm/Debugger.cpp
new file mode 100644
index 0000000..5a4e0e5
--- /dev/null
+++ b/vm/Debugger.cpp
@@ -0,0 +1,2972 @@
+/*
+ * 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.
+ */
+
+/*
+ * Link between JDWP and the VM.  The code here only runs as a result of
+ * requests from the debugger, so speed is not essential.  Maintaining
+ * isolation of the JDWP code should make it easier to maintain and reuse.
+ *
+ * Collecting all debugger-related pieces here will also allow us to #ifdef
+ * the JDWP code out of release builds.
+ */
+#include "Dalvik.h"
+
+/*
+Notes on garbage collection and object registration
+
+JDWP does not allow the debugger to assume that objects passed to it
+will not be garbage collected.  It specifies explicit commands (e.g.
+ObjectReference.DisableCollection) to allow the debugger to manage
+object lifetime.  It does, however, require that the VM not re-use an
+object ID unless an explicit "dispose" call has been made, and if the
+VM asks for a now-collected object we must return INVALID_OBJECT.
+
+JDWP also requires that, while the VM is suspended, no garbage collection
+occur.  The JDWP docs suggest that this is obvious, because no threads
+can be running.  Unfortunately it's not entirely clear how to deal
+with situations where the debugger itself allocates strings or executes
+code as part of displaying variables.  The easiest way to enforce this,
+short of disabling GC whenever the debugger is connected, is to ensure
+that the debugger thread can't cause a GC: it has to expand the heap or
+fail to allocate.  (Might want to make that "is debugger thread AND all
+other threads are suspended" to avoid unnecessary heap expansion by a
+poorly-timed JDWP request.)
+
+We use an "object registry" so that we can separate our internal
+representation from what we show the debugger.  This allows us to
+return a registry table index instead of a pointer or handle.
+
+There are various approaches we can take to achieve correct behavior:
+
+(1) Disable garbage collection entirely while the debugger is attached.
+This is very easy, but doesn't allow extended debugging sessions on
+small devices.
+
+(2) Keep a list of all object references requested by or sent to the
+debugger, and include the list in the GC root set.  This ensures that
+objects the debugger might care about don't go away.  This is straightforward,
+but it can cause us to hold on to large objects and prevent finalizers from
+being executed.
+
+(3) Keep a list of what amount to weak object references.  This way we
+don't interfere with the GC, and can support JDWP requests like
+"ObjectReference.IsCollected".
+
+The current implementation is #2.  The set should be reasonably small and
+performance isn't critical, so a simple expanding array can be used.
+
+
+Notes on threads:
+
+The VM has a Thread struct associated with every active thread.  The
+ThreadId we pass to the debugger is the ObjectId for the java/lang/Thread
+object, so to retrieve the VM's Thread struct we have to scan through the
+list looking for a match.
+
+When a thread goes away, we lock the list and free the struct.  To
+avoid having the thread list updated or Thread structs freed out from
+under us, we want to acquire and hold the thread list lock while we're
+performing operations on Threads.  Exceptions to this rule are noted in
+a couple of places.
+
+We can speed this up a bit by adding a Thread struct pointer to the
+java/lang/Thread object, and ensuring that both are discarded at the
+same time.
+*/
+
+#define THREAD_GROUP_ALL ((ObjectId) 0x12345)   // magic, internal-only value
+
+#define kSlot0Sub   1000    // Eclipse workaround
+
+/*
+ * System init.  We don't allocate the registry until first use.
+ * Make sure we do this before initializing JDWP.
+ */
+bool dvmDebuggerStartup()
+{
+    if (!dvmBreakpointStartup())
+        return false;
+
+    gDvm.dbgRegistry = dvmHashTableCreate(1000, NULL);
+    return (gDvm.dbgRegistry != NULL);
+}
+
+/*
+ * Free registry storage.
+ */
+void dvmDebuggerShutdown()
+{
+    dvmHashTableFree(gDvm.dbgRegistry);
+    gDvm.dbgRegistry = NULL;
+    dvmBreakpointShutdown();
+}
+
+
+/*
+ * Pass these through to the VM functions.  Allows extended checking
+ * (e.g. "errorcheck" mutexes).  If nothing else we can assert() success.
+ */
+void dvmDbgInitMutex(pthread_mutex_t* pMutex)
+{
+    dvmInitMutex(pMutex);
+}
+void dvmDbgLockMutex(pthread_mutex_t* pMutex)
+{
+    dvmLockMutex(pMutex);
+}
+void dvmDbgUnlockMutex(pthread_mutex_t* pMutex)
+{
+    dvmUnlockMutex(pMutex);
+}
+void dvmDbgInitCond(pthread_cond_t* pCond)
+{
+    pthread_cond_init(pCond, NULL);
+}
+void dvmDbgCondWait(pthread_cond_t* pCond, pthread_mutex_t* pMutex)
+{
+    int cc __attribute__ ((__unused__)) = pthread_cond_wait(pCond, pMutex);
+    assert(cc == 0);
+}
+void dvmDbgCondSignal(pthread_cond_t* pCond)
+{
+    int cc __attribute__ ((__unused__)) = pthread_cond_signal(pCond);
+    assert(cc == 0);
+}
+void dvmDbgCondBroadcast(pthread_cond_t* pCond)
+{
+    int cc __attribute__ ((__unused__)) = pthread_cond_broadcast(pCond);
+    assert(cc == 0);
+}
+
+
+/* keep track of type, in case we need to distinguish them someday */
+enum RegistryType {
+    kObjectId = 0xc1, kRefTypeId
+};
+
+/*
+ * Hash function for object IDs.  Since objects are at least 8 bytes, and
+ * could someday be allocated on 16-byte boundaries, we don't want to use
+ * the low 4 bits in our hash.
+ */
+static inline u4 registryHash(u4 val)
+{
+    return val >> 4;
+}
+
+/*
+ * (This is a dvmHashTableLookup() callback.)
+ */
+static int registryCompare(const void* obj1, const void* obj2)
+{
+    return (int) obj1 - (int) obj2;
+}
+
+
+/*
+ * Determine if an id is already in the list.
+ *
+ * If the list doesn't yet exist, this creates it.
+ *
+ * Lock the registry before calling here.
+ */
+#ifndef NDEBUG
+static bool lookupId(ObjectId id)
+{
+    void* found;
+
+    found = dvmHashTableLookup(gDvm.dbgRegistry, registryHash((u4) id),
+                (void*)(u4) id, registryCompare, false);
+    if (found == NULL)
+        return false;
+    assert(found == (void*)(u4) id);
+    return true;
+}
+#endif
+
+/*
+ * Register an object, if it hasn't already been.
+ *
+ * This is used for both ObjectId and RefTypeId.  In theory we don't have
+ * to register RefTypeIds unless we're worried about classes unloading.
+ *
+ * Null references must be represented as zero, or the debugger will get
+ * very confused.
+ */
+static ObjectId registerObject(const Object* obj, RegistryType type, bool reg)
+{
+    ObjectId id;
+
+    if (obj == NULL)
+        return 0;
+
+    assert((u4) obj != 0xcccccccc);
+    assert((u4) obj > 0x100);
+
+    id = (ObjectId)(u4)obj | ((u8) type) << 32;
+    if (!reg)
+        return id;
+
+    dvmHashTableLock(gDvm.dbgRegistry);
+    if (!gDvm.debuggerConnected) {
+        /* debugger has detached while we were doing stuff? */
+        LOGI("ignoring registerObject request in thread=%d",
+            dvmThreadSelf()->threadId);
+        //dvmAbort();
+        goto bail;
+    }
+
+    dvmHashTableLookup(gDvm.dbgRegistry, registryHash((u4) id),
+                (void*)(u4) id, registryCompare, true);
+
+bail:
+    dvmHashTableUnlock(gDvm.dbgRegistry);
+    return id;
+}
+
+/*
+ * Verify that an object has been registered.  If it hasn't, the debugger
+ * is asking for something we didn't send it, which means something
+ * somewhere is broken.
+ *
+ * If speed is an issue we can encode the registry index in the high
+ * four bytes.  We could also just hard-wire this to "true".
+ *
+ * Note this actually takes both ObjectId and RefTypeId.
+ */
+#ifndef NDEBUG
+static bool objectIsRegistered(ObjectId id, RegistryType type)
+{
+    UNUSED_PARAMETER(type);
+
+    if (id == 0)        // null reference?
+        return true;
+
+    dvmHashTableLock(gDvm.dbgRegistry);
+    bool result = lookupId(id);
+    dvmHashTableUnlock(gDvm.dbgRegistry);
+    return result;
+}
+#endif
+
+/*
+ * Convert to/from a RefTypeId.
+ *
+ * These are rarely NULL, but can be (e.g. java/lang/Object's superclass).
+ */
+static RefTypeId classObjectToRefTypeId(ClassObject* clazz)
+{
+    return (RefTypeId) registerObject((Object*) clazz, kRefTypeId, true);
+}
+#if 0
+static RefTypeId classObjectToRefTypeIdNoReg(ClassObject* clazz)
+{
+    return (RefTypeId) registerObject((Object*) clazz, kRefTypeId, false);
+}
+#endif
+static ClassObject* refTypeIdToClassObject(RefTypeId id)
+{
+    assert(objectIsRegistered(id, kRefTypeId) || !gDvm.debuggerConnected);
+    return (ClassObject*)(u4) id;
+}
+
+/*
+ * Convert to/from an ObjectId.
+ */
+static ObjectId objectToObjectId(const Object* obj)
+{
+    return registerObject(obj, kObjectId, true);
+}
+static ObjectId objectToObjectIdNoReg(const Object* obj)
+{
+    return registerObject(obj, kObjectId, false);
+}
+static Object* objectIdToObject(ObjectId id)
+{
+    assert(objectIsRegistered(id, kObjectId) || !gDvm.debuggerConnected);
+    return (Object*)(u4) id;
+}
+
+/*
+ * Register an object ID that might not have been registered previously.
+ *
+ * Normally this wouldn't happen -- the conversion to an ObjectId would
+ * have added the object to the registry -- but in some cases (e.g.
+ * throwing exceptions) we really want to do the registration late.
+ */
+void dvmDbgRegisterObjectId(ObjectId id)
+{
+    Object* obj = (Object*)(u4) id;
+    LOGV("+++ registering %p (%s)", obj, obj->clazz->descriptor);
+    registerObject(obj, kObjectId, true);
+}
+
+/*
+ * Convert to/from a MethodId.
+ *
+ * These IDs are only guaranteed unique within a class, so they could be
+ * an enumeration index.  For now we just use the Method*.
+ */
+static MethodId methodToMethodId(const Method* meth)
+{
+    return (MethodId)(u4) meth;
+}
+static Method* methodIdToMethod(RefTypeId refTypeId, MethodId id)
+{
+    // TODO? verify "id" is actually a method in "refTypeId"
+    return (Method*)(u4) id;
+}
+
+/*
+ * Convert to/from a FieldId.
+ *
+ * These IDs are only guaranteed unique within a class, so they could be
+ * an enumeration index.  For now we just use the Field*.
+ */
+static FieldId fieldToFieldId(const Field* field)
+{
+    return (FieldId)(u4) field;
+}
+static Field* fieldIdToField(RefTypeId refTypeId, FieldId id)
+{
+    // TODO? verify "id" is actually a field in "refTypeId"
+    return (Field*)(u4) id;
+}
+
+/*
+ * Convert to/from a FrameId.
+ *
+ * We just return a pointer to the stack frame.
+ */
+static FrameId frameToFrameId(const void* frame)
+{
+    return (FrameId)(u4) frame;
+}
+static u4* frameIdToFrame(FrameId id)
+{
+    return (u4*)(u4) id;
+}
+
+
+/*
+ * Get the invocation request state.
+ */
+DebugInvokeReq* dvmDbgGetInvokeReq()
+{
+    return &dvmThreadSelf()->invokeReq;
+}
+
+/*
+ * Enable the object registry, but don't enable debugging features yet.
+ *
+ * Only called from the JDWP handler thread.
+ */
+void dvmDbgConnected()
+{
+    assert(!gDvm.debuggerConnected);
+
+    LOGV("JDWP has attached");
+    assert(dvmHashTableNumEntries(gDvm.dbgRegistry) == 0);
+    gDvm.debuggerConnected = true;
+}
+
+/*
+ * Enable all debugging features, including scans for breakpoints.
+ *
+ * This is a no-op if we're already active.
+ *
+ * Only called from the JDWP handler thread.
+ */
+void dvmDbgActive()
+{
+    if (gDvm.debuggerActive)
+        return;
+
+    LOGI("Debugger is active");
+    dvmInitBreakpoints();
+    gDvm.debuggerActive = true;
+    dvmEnableAllSubMode(kSubModeDebuggerActive);
+#if defined(WITH_JIT)
+    dvmCompilerUpdateGlobalState();
+#endif
+}
+
+/*
+ * Disable debugging features.
+ *
+ * Set "debuggerConnected" to false, which disables use of the object
+ * registry.
+ *
+ * Only called from the JDWP handler thread.
+ */
+void dvmDbgDisconnected()
+{
+    assert(gDvm.debuggerConnected);
+
+    gDvm.debuggerActive = false;
+    dvmDisableAllSubMode(kSubModeDebuggerActive);
+#if defined(WITH_JIT)
+    dvmCompilerUpdateGlobalState();
+#endif
+
+    dvmHashTableLock(gDvm.dbgRegistry);
+    gDvm.debuggerConnected = false;
+
+    LOGD("Debugger has detached; object registry had %d entries",
+        dvmHashTableNumEntries(gDvm.dbgRegistry));
+    //int i;
+    //for (i = 0; i < gDvm.dbgRegistryNext; i++)
+    //    LOGVV("%4d: 0x%llx", i, gDvm.dbgRegistryTable[i]);
+
+    dvmHashTableClear(gDvm.dbgRegistry);
+    dvmHashTableUnlock(gDvm.dbgRegistry);
+}
+
+/*
+ * Returns "true" if a debugger is connected.
+ *
+ * Does not return "true" if it's just a DDM server.
+ */
+bool dvmDbgIsDebuggerConnected()
+{
+    return gDvm.debuggerActive;
+}
+
+/*
+ * Get time since last debugger activity.  Used when figuring out if the
+ * debugger has finished configuring us.
+ */
+s8 dvmDbgLastDebuggerActivity()
+{
+    return dvmJdwpLastDebuggerActivity(gDvm.jdwpState);
+}
+
+/*
+ * JDWP thread is running, don't allow GC.
+ */
+int dvmDbgThreadRunning()
+{
+    ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_RUNNING);
+    return static_cast<int>(oldStatus);
+}
+
+/*
+ * JDWP thread is idle, allow GC.
+ */
+int dvmDbgThreadWaiting()
+{
+    ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
+    return static_cast<int>(oldStatus);
+}
+
+/*
+ * Restore state returned by Running/Waiting calls.
+ */
+int dvmDbgThreadContinuing(int status)
+{
+    ThreadStatus newStatus = static_cast<ThreadStatus>(status);
+    ThreadStatus oldStatus = dvmChangeStatus(NULL, newStatus);
+    return static_cast<int>(oldStatus);
+}
+
+/*
+ * The debugger wants us to exit.
+ */
+void dvmDbgExit(int status)
+{
+    // TODO? invoke System.exit() to perform exit processing; ends up
+    // in System.exitInternal(), which can call JNI exit hook
+    LOGI("GC lifetime allocation: %d bytes", gDvm.allocProf.allocCount);
+    if (CALC_CACHE_STATS) {
+        dvmDumpAtomicCacheStats(gDvm.instanceofCache);
+        dvmDumpBootClassPath();
+    }
+    exit(status);
+}
+
+
+/*
+ * ===========================================================================
+ *      Class, Object, Array
+ * ===========================================================================
+ */
+
+/*
+ * Get the class's type descriptor from a reference type ID.
+ */
+const char* dvmDbgGetClassDescriptor(RefTypeId id)
+{
+    ClassObject* clazz;
+
+    clazz = refTypeIdToClassObject(id);
+    return clazz->descriptor;
+}
+
+/*
+ * Convert a RefTypeId to an ObjectId.
+ */
+ObjectId dvmDbgGetClassObject(RefTypeId id)
+{
+    ClassObject* clazz = refTypeIdToClassObject(id);
+    return objectToObjectId((Object*) clazz);
+}
+
+/*
+ * Return the superclass of a class (will be NULL for java/lang/Object).
+ */
+RefTypeId dvmDbgGetSuperclass(RefTypeId id)
+{
+    ClassObject* clazz = refTypeIdToClassObject(id);
+    return classObjectToRefTypeId(clazz->super);
+}
+
+/*
+ * Return a class's defining class loader.
+ */
+RefTypeId dvmDbgGetClassLoader(RefTypeId id)
+{
+    ClassObject* clazz = refTypeIdToClassObject(id);
+    return objectToObjectId(clazz->classLoader);
+}
+
+/*
+ * Return a class's access flags.
+ */
+u4 dvmDbgGetAccessFlags(RefTypeId id)
+{
+    ClassObject* clazz = refTypeIdToClassObject(id);
+    return clazz->accessFlags & JAVA_FLAGS_MASK;
+}
+
+/*
+ * Is this class an interface?
+ */
+bool dvmDbgIsInterface(RefTypeId id)
+{
+    ClassObject* clazz = refTypeIdToClassObject(id);
+    return dvmIsInterfaceClass(clazz);
+}
+
+/*
+ * dvmHashForeach callback
+ */
+static int copyRefType(void* vclazz, void* varg)
+{
+    RefTypeId** pRefType = (RefTypeId**)varg;
+    **pRefType = classObjectToRefTypeId((ClassObject*) vclazz);
+    (*pRefType)++;
+    return 0;
+}
+
+/*
+ * Get the complete list of reference classes (i.e. all classes except
+ * the primitive types).
+ *
+ * Returns a newly-allocated buffer full of RefTypeId values.
+ */
+void dvmDbgGetClassList(u4* pNumClasses, RefTypeId** pClassRefBuf)
+{
+    RefTypeId* pRefType;
+
+    dvmHashTableLock(gDvm.loadedClasses);
+    *pNumClasses = dvmHashTableNumEntries(gDvm.loadedClasses);
+    pRefType = *pClassRefBuf =
+        (RefTypeId*)malloc(sizeof(RefTypeId) * *pNumClasses);
+
+    if (dvmHashForeach(gDvm.loadedClasses, copyRefType, &pRefType) != 0) {
+        LOGW("Warning: problem getting class list");
+        /* not really expecting this to happen */
+    } else {
+        assert(pRefType - *pClassRefBuf == (int) *pNumClasses);
+    }
+
+    dvmHashTableUnlock(gDvm.loadedClasses);
+}
+
+/*
+ * Get the list of reference classes "visible" to the specified class
+ * loader.  A class is visible to a class loader if the ClassLoader object
+ * is the defining loader or is listed as an initiating loader.
+ *
+ * Returns a newly-allocated buffer full of RefTypeId values.
+ */
+void dvmDbgGetVisibleClassList(ObjectId classLoaderId, u4* pNumClasses,
+    RefTypeId** pClassRefBuf)
+{
+    Object* classLoader;
+    int numClasses = 0, maxClasses;
+
+    classLoader = objectIdToObject(classLoaderId);
+    // I don't think classLoader can be NULL, but the spec doesn't say
+
+    LOGVV("GetVisibleList: comparing to %p", classLoader);
+
+    dvmHashTableLock(gDvm.loadedClasses);
+
+    /* over-allocate the return buffer */
+    maxClasses = dvmHashTableNumEntries(gDvm.loadedClasses);
+    *pClassRefBuf = (RefTypeId*)malloc(sizeof(RefTypeId) * maxClasses);
+
+    /*
+     * Run through the list, looking for matches.
+     */
+    HashIter iter;
+    for (dvmHashIterBegin(gDvm.loadedClasses, &iter); !dvmHashIterDone(&iter);
+        dvmHashIterNext(&iter))
+    {
+        ClassObject* clazz = (ClassObject*) dvmHashIterData(&iter);
+
+        if (clazz->classLoader == classLoader ||
+            dvmLoaderInInitiatingList(clazz, classLoader))
+        {
+            LOGVV("  match '%s'", clazz->descriptor);
+            (*pClassRefBuf)[numClasses++] = classObjectToRefTypeId(clazz);
+        }
+    }
+    *pNumClasses = numClasses;
+
+    dvmHashTableUnlock(gDvm.loadedClasses);
+}
+
+/*
+ * Get the "JNI signature" for a class, e.g. "Ljava/lang/String;".
+ *
+ * Our class descriptors are in the correct format, so we just return that.
+ */
+static const char* jniSignature(ClassObject* clazz)
+{
+    return clazz->descriptor;
+}
+
+/*
+ * Get information about a class.
+ *
+ * If "pSignature" is not NULL, *pSignature gets the "JNI signature" of
+ * the class.
+ */
+void dvmDbgGetClassInfo(RefTypeId classId, u1* pTypeTag, u4* pStatus,
+    const char** pSignature)
+{
+    ClassObject* clazz = refTypeIdToClassObject(classId);
+
+    if (clazz->descriptor[0] == '[') {
+        /* generated array class */
+        *pStatus = CS_VERIFIED | CS_PREPARED;
+        *pTypeTag = TT_ARRAY;
+    } else {
+        if (clazz->status == CLASS_ERROR)
+            *pStatus = CS_ERROR;
+        else
+            *pStatus = CS_VERIFIED | CS_PREPARED | CS_INITIALIZED;
+        if (dvmIsInterfaceClass(clazz))
+            *pTypeTag = TT_INTERFACE;
+        else
+            *pTypeTag = TT_CLASS;
+    }
+    if (pSignature != NULL)
+        *pSignature = jniSignature(clazz);
+}
+
+/*
+ * Search the list of loaded classes for a match.
+ */
+bool dvmDbgFindLoadedClassBySignature(const char* classDescriptor,
+        RefTypeId* pRefTypeId)
+{
+    ClassObject* clazz;
+
+    clazz = dvmFindLoadedClass(classDescriptor);
+    if (clazz != NULL) {
+        *pRefTypeId = classObjectToRefTypeId(clazz);
+        return true;
+    } else
+        return false;
+}
+
+
+/*
+ * Get an object's class and "type tag".
+ */
+void dvmDbgGetObjectType(ObjectId objectId, u1* pRefTypeTag,
+    RefTypeId* pRefTypeId)
+{
+    Object* obj = objectIdToObject(objectId);
+
+    if (dvmIsArrayClass(obj->clazz))
+        *pRefTypeTag = TT_ARRAY;
+    else if (dvmIsInterfaceClass(obj->clazz))
+        *pRefTypeTag = TT_INTERFACE;
+    else
+        *pRefTypeTag = TT_CLASS;
+    *pRefTypeId = classObjectToRefTypeId(obj->clazz);
+}
+
+/*
+ * Get a class object's "type tag".
+ */
+u1 dvmDbgGetClassObjectType(RefTypeId refTypeId)
+{
+    ClassObject* clazz = refTypeIdToClassObject(refTypeId);
+
+    if (dvmIsArrayClass(clazz))
+        return TT_ARRAY;
+    else if (dvmIsInterfaceClass(clazz))
+        return TT_INTERFACE;
+    else
+        return TT_CLASS;
+}
+
+/*
+ * Get a class' signature.
+ */
+const char* dvmDbgGetSignature(RefTypeId refTypeId)
+{
+    ClassObject* clazz;
+
+    clazz = refTypeIdToClassObject(refTypeId);
+    assert(clazz != NULL);
+
+    return jniSignature(clazz);
+}
+
+/*
+ * Get class' source file.
+ *
+ * Returns a newly-allocated string.
+ */
+const char* dvmDbgGetSourceFile(RefTypeId refTypeId)
+{
+    ClassObject* clazz;
+
+    clazz = refTypeIdToClassObject(refTypeId);
+    assert(clazz != NULL);
+
+    return clazz->sourceFile;
+}
+
+/*
+ * Get an object's type name.  (For log message display only.)
+ */
+const char* dvmDbgGetObjectTypeName(ObjectId objectId)
+{
+    if (objectId == 0)
+        return "(null)";
+
+    Object* obj = objectIdToObject(objectId);
+    return jniSignature(obj->clazz);
+}
+
+/*
+ * Determine whether or not a tag represents a primitive type.
+ */
+static bool isTagPrimitive(u1 tag)
+{
+    switch (tag) {
+    case JT_BYTE:
+    case JT_CHAR:
+    case JT_FLOAT:
+    case JT_DOUBLE:
+    case JT_INT:
+    case JT_LONG:
+    case JT_SHORT:
+    case JT_VOID:
+    case JT_BOOLEAN:
+        return true;
+    case JT_ARRAY:
+    case JT_OBJECT:
+    case JT_STRING:
+    case JT_CLASS_OBJECT:
+    case JT_THREAD:
+    case JT_THREAD_GROUP:
+    case JT_CLASS_LOADER:
+        return false;
+    default:
+        LOGE("ERROR: unhandled tag '%c'", tag);
+        assert(false);
+        return false;
+    }
+}
+
+/*
+ * Determine the best tag type given an object's class.
+ */
+static u1 tagFromClass(ClassObject* clazz)
+{
+    if (dvmIsArrayClass(clazz))
+        return JT_ARRAY;
+
+    if (clazz == gDvm.classJavaLangString) {
+        return JT_STRING;
+    } else if (dvmIsTheClassClass(clazz)) {
+        return JT_CLASS_OBJECT;
+    } else if (dvmInstanceof(clazz, gDvm.classJavaLangThread)) {
+        return JT_THREAD;
+    } else if (dvmInstanceof(clazz, gDvm.classJavaLangThreadGroup)) {
+        return JT_THREAD_GROUP;
+    } else if (dvmInstanceof(clazz, gDvm.classJavaLangClassLoader)) {
+        return JT_CLASS_LOADER;
+    } else {
+        return JT_OBJECT;
+    }
+}
+
+/*
+ * Return a basic tag value based solely on a type descriptor.
+ *
+ * The ASCII value maps directly to the JDWP tag constants, so we don't
+ * need to do much here.  This does not return the fancier tags like
+ * JT_THREAD.
+ */
+static u1 basicTagFromDescriptor(const char* descriptor)
+{
+    return descriptor[0];
+}
+
+/*
+ * Objects declared to hold Object might actually hold a more specific
+ * type.  The debugger may take a special interest in these (e.g. it
+ * wants to display the contents of Strings), so we want to return an
+ * appropriate tag.
+ *
+ * Null objects are tagged JT_OBJECT.
+ */
+static u1 tagFromObject(const Object* obj)
+{
+    if (obj == NULL)
+        return JT_OBJECT;
+    return tagFromClass(obj->clazz);
+}
+
+/*
+ * Determine the tag for an object.
+ *
+ * "objectId" may be 0 (i.e. NULL reference).
+ */
+u1 dvmDbgGetObjectTag(ObjectId objectId)
+{
+    return tagFromObject(objectIdToObject(objectId));
+}
+
+/*
+ * Get the widths of the specified JDWP.Tag value.
+ */
+int dvmDbgGetTagWidth(int tag)
+{
+    switch (tag) {
+    case JT_VOID:
+        return 0;
+    case JT_BYTE:
+    case JT_BOOLEAN:
+        return 1;
+    case JT_CHAR:
+    case JT_SHORT:
+        return 2;
+    case JT_FLOAT:
+    case JT_INT:
+        return 4;
+    case JT_ARRAY:
+    case JT_OBJECT:
+    case JT_STRING:
+    case JT_THREAD:
+    case JT_THREAD_GROUP:
+    case JT_CLASS_LOADER:
+    case JT_CLASS_OBJECT:
+        return sizeof(ObjectId);
+    case JT_DOUBLE:
+    case JT_LONG:
+        return 8;
+    default:
+        LOGE("ERROR: unhandled tag '%c'", tag);
+        assert(false);
+        return -1;
+    }
+}
+
+
+/*
+ * Return the length of the specified array.
+ */
+int dvmDbgGetArrayLength(ObjectId arrayId)
+{
+    ArrayObject* arrayObj = (ArrayObject*) objectIdToObject(arrayId);
+    assert(dvmIsArray(arrayObj));
+    return arrayObj->length;
+}
+
+/*
+ * Return a tag indicating the general type of elements in the array.
+ */
+u1 dvmDbgGetArrayElementTag(ObjectId arrayId)
+{
+    ArrayObject* arrayObj = (ArrayObject*) objectIdToObject(arrayId);
+
+    ClassObject* arrayClass = arrayObj->clazz;
+    u1 tag = basicTagFromDescriptor(arrayClass->descriptor + 1);
+    if (!isTagPrimitive(tag)) {
+        /* try to refine it */
+        tag = tagFromClass(arrayClass->elementClass);
+    }
+
+    return tag;
+}
+
+/*
+ * Copy a series of values with the specified width, changing the byte
+ * ordering to big-endian.
+ */
+static void copyValuesToBE(u1* out, const u1* in, int count, int width)
+{
+    int i;
+
+    switch (width) {
+    case 1:
+        memcpy(out, in, count);
+        break;
+    case 2:
+        for (i = 0; i < count; i++)
+            *(((u2*) out)+i) = get2BE(in + i*2);
+        break;
+    case 4:
+        for (i = 0; i < count; i++)
+            *(((u4*) out)+i) = get4BE(in + i*4);
+        break;
+    case 8:
+        for (i = 0; i < count; i++)
+            *(((u8*) out)+i) = get8BE(in + i*8);
+        break;
+    default:
+        assert(false);
+    }
+}
+
+/*
+ * Copy a series of values with the specified width, changing the
+ * byte order from big-endian.
+ */
+static void copyValuesFromBE(u1* out, const u1* in, int count, int width)
+{
+    int i;
+
+    switch (width) {
+    case 1:
+        memcpy(out, in, count);
+        break;
+    case 2:
+        for (i = 0; i < count; i++)
+            set2BE(out + i*2, *((u2*)in + i));
+        break;
+    case 4:
+        for (i = 0; i < count; i++)
+            set4BE(out + i*4, *((u4*)in + i));
+        break;
+    case 8:
+        for (i = 0; i < count; i++)
+            set8BE(out + i*8, *((u8*)in + i));
+        break;
+    default:
+        assert(false);
+    }
+}
+
+/*
+ * Output a piece of an array to the reply buffer.
+ *
+ * Returns "false" if something looks fishy.
+ */
+bool dvmDbgOutputArray(ObjectId arrayId, int firstIndex, int count,
+    ExpandBuf* pReply)
+{
+    ArrayObject* arrayObj = (ArrayObject*) objectIdToObject(arrayId);
+    const u1* data = (const u1*)arrayObj->contents;
+    u1 tag;
+
+    assert(dvmIsArray(arrayObj));
+
+    if (firstIndex + count > (int)arrayObj->length) {
+        LOGW("Request for index=%d + count=%d excceds length=%d",
+            firstIndex, count, arrayObj->length);
+        return false;
+    }
+
+    tag = basicTagFromDescriptor(arrayObj->clazz->descriptor + 1);
+
+    if (isTagPrimitive(tag)) {
+        int width = dvmDbgGetTagWidth(tag);
+        u1* outBuf;
+
+        outBuf = expandBufAddSpace(pReply, count * width);
+
+        copyValuesToBE(outBuf, data + firstIndex*width, count, width);
+    } else {
+        Object** pObjects;
+        int i;
+
+        pObjects = (Object**) data;
+        pObjects += firstIndex;
+
+        LOGV("    --> copying %d object IDs", count);
+        //assert(tag == JT_OBJECT);     // could be object or "refined" type
+
+        for (i = 0; i < count; i++, pObjects++) {
+            u1 thisTag;
+            if (*pObjects != NULL)
+                thisTag = tagFromObject(*pObjects);
+            else
+                thisTag = tag;
+            expandBufAdd1(pReply, thisTag);
+            expandBufAddObjectId(pReply, objectToObjectId(*pObjects));
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Set a range of elements in an array from the data in "buf".
+ */
+bool dvmDbgSetArrayElements(ObjectId arrayId, int firstIndex, int count,
+    const u1* buf)
+{
+    ArrayObject* arrayObj = (ArrayObject*) objectIdToObject(arrayId);
+    u1* data = (u1*)arrayObj->contents;
+    u1 tag;
+
+    assert(dvmIsArray(arrayObj));
+
+    if (firstIndex + count > (int)arrayObj->length) {
+        LOGW("Attempt to set index=%d + count=%d excceds length=%d",
+            firstIndex, count, arrayObj->length);
+        return false;
+    }
+
+    tag = basicTagFromDescriptor(arrayObj->clazz->descriptor + 1);
+
+    if (isTagPrimitive(tag)) {
+        int width = dvmDbgGetTagWidth(tag);
+
+        LOGV("    --> setting %d '%c' width=%d", count, tag, width);
+
+        copyValuesFromBE(data + firstIndex*width, buf, count, width);
+    } else {
+        Object** pObjects;
+        int i;
+
+        pObjects = (Object**) data;
+        pObjects += firstIndex;
+
+        LOGV("    --> setting %d objects", count);
+
+        /* should do array type check here */
+        for (i = 0; i < count; i++) {
+            ObjectId id = dvmReadObjectId(&buf);
+            *pObjects++ = objectIdToObject(id);
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Create a new string.
+ *
+ * The only place the reference will be held in the VM is in our registry.
+ */
+ObjectId dvmDbgCreateString(const char* str)
+{
+    StringObject* strObj;
+
+    strObj = dvmCreateStringFromCstr(str);
+    dvmReleaseTrackedAlloc((Object*) strObj, NULL);
+    return objectToObjectId((Object*) strObj);
+}
+
+/*
+ * Allocate a new object of the specified type.
+ *
+ * Add it to the registry to prevent it from being GCed.
+ */
+ObjectId dvmDbgCreateObject(RefTypeId classId)
+{
+    ClassObject* clazz = refTypeIdToClassObject(classId);
+    Object* newObj = dvmAllocObject(clazz, ALLOC_DEFAULT);
+    dvmReleaseTrackedAlloc(newObj, NULL);
+    return objectToObjectId(newObj);
+}
+
+/*
+ * Allocate a new array object of the specified type and length.  The
+ * type is the array type, not the element type.
+ *
+ * Add it to the registry to prevent it from being GCed.
+ */
+ObjectId dvmDbgCreateArrayObject(RefTypeId arrayTypeId, u4 length)
+{
+    ClassObject* clazz = refTypeIdToClassObject(arrayTypeId);
+    Object* newObj = (Object*) dvmAllocArrayByClass(clazz, length, ALLOC_DEFAULT);
+    dvmReleaseTrackedAlloc(newObj, NULL);
+    return objectToObjectId(newObj);
+}
+
+/*
+ * Determine if "instClassId" is an instance of "classId".
+ */
+bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId)
+{
+    ClassObject* instClazz = refTypeIdToClassObject(instClassId);
+    ClassObject* clazz = refTypeIdToClassObject(classId);
+
+    return dvmInstanceof(instClazz, clazz);
+}
+
+
+/*
+ * ===========================================================================
+ *      Method and Field
+ * ===========================================================================
+ */
+
+/*
+ * Get the method name from a MethodId.
+ */
+const char* dvmDbgGetMethodName(RefTypeId refTypeId, MethodId id)
+{
+    Method* meth;
+
+    meth = methodIdToMethod(refTypeId, id);
+    return meth->name;
+}
+
+/*
+ * Augment the access flags for synthetic methods and fields by setting
+ * the (as described by the spec) "0xf0000000 bit".  Also, strip out any
+ * flags not specified by the Java programming language.
+ */
+static u4 augmentedAccessFlags(u4 accessFlags)
+{
+    accessFlags &= JAVA_FLAGS_MASK;
+
+    if ((accessFlags & ACC_SYNTHETIC) != 0) {
+        return accessFlags | 0xf0000000;
+    } else {
+        return accessFlags;
+    }
+}
+
+/*
+ * For ReferenceType.Fields and ReferenceType.FieldsWithGeneric:
+ * output all fields declared by the class.  Inherited fields are
+ * not included.
+ */
+void dvmDbgOutputAllFields(RefTypeId refTypeId, bool withGeneric,
+    ExpandBuf* pReply)
+{
+    ClassObject* clazz = refTypeIdToClassObject(refTypeId);
+    assert(clazz != NULL);
+
+    u4 declared = clazz->sfieldCount + clazz->ifieldCount;
+    expandBufAdd4BE(pReply, declared);
+
+    for (int i = 0; i < clazz->sfieldCount; i++) {
+        Field* field = &clazz->sfields[i];
+        expandBufAddFieldId(pReply, fieldToFieldId(field));
+        expandBufAddUtf8String(pReply, (const u1*) field->name);
+        expandBufAddUtf8String(pReply, (const u1*) field->signature);
+        if (withGeneric) {
+            static const u1 genericSignature[1] = "";
+            expandBufAddUtf8String(pReply, genericSignature);
+        }
+        expandBufAdd4BE(pReply, augmentedAccessFlags(field->accessFlags));
+    }
+    for (int i = 0; i < clazz->ifieldCount; i++) {
+        Field* field = &clazz->ifields[i];
+        expandBufAddFieldId(pReply, fieldToFieldId(field));
+        expandBufAddUtf8String(pReply, (const u1*) field->name);
+        expandBufAddUtf8String(pReply, (const u1*) field->signature);
+        if (withGeneric) {
+            static const u1 genericSignature[1] = "";
+            expandBufAddUtf8String(pReply, genericSignature);
+        }
+        expandBufAdd4BE(pReply, augmentedAccessFlags(field->accessFlags));
+    }
+}
+
+/*
+ * For ReferenceType.Methods and ReferenceType.MethodsWithGeneric:
+ * output all methods declared by the class.  Inherited methods are
+ * not included.
+ */
+void dvmDbgOutputAllMethods(RefTypeId refTypeId, bool withGeneric,
+    ExpandBuf* pReply)
+{
+    DexStringCache stringCache;
+    static const u1 genericSignature[1] = "";
+    ClassObject* clazz;
+    Method* meth;
+    u4 declared;
+    int i;
+
+    dexStringCacheInit(&stringCache);
+
+    clazz = refTypeIdToClassObject(refTypeId);
+    assert(clazz != NULL);
+
+    declared = clazz->directMethodCount + clazz->virtualMethodCount;
+    expandBufAdd4BE(pReply, declared);
+
+    for (i = 0; i < clazz->directMethodCount; i++) {
+        meth = &clazz->directMethods[i];
+
+        expandBufAddMethodId(pReply, methodToMethodId(meth));
+        expandBufAddUtf8String(pReply, (const u1*) meth->name);
+
+        expandBufAddUtf8String(pReply,
+            (const u1*) dexProtoGetMethodDescriptor(&meth->prototype,
+                    &stringCache));
+
+        if (withGeneric)
+            expandBufAddUtf8String(pReply, genericSignature);
+        expandBufAdd4BE(pReply, augmentedAccessFlags(meth->accessFlags));
+    }
+    for (i = 0; i < clazz->virtualMethodCount; i++) {
+        meth = &clazz->virtualMethods[i];
+
+        expandBufAddMethodId(pReply, methodToMethodId(meth));
+        expandBufAddUtf8String(pReply, (const u1*) meth->name);
+
+        expandBufAddUtf8String(pReply,
+            (const u1*) dexProtoGetMethodDescriptor(&meth->prototype,
+                    &stringCache));
+
+        if (withGeneric)
+            expandBufAddUtf8String(pReply, genericSignature);
+        expandBufAdd4BE(pReply, augmentedAccessFlags(meth->accessFlags));
+    }
+
+    dexStringCacheRelease(&stringCache);
+}
+
+/*
+ * Output all interfaces directly implemented by the class.
+ */
+void dvmDbgOutputAllInterfaces(RefTypeId refTypeId, ExpandBuf* pReply)
+{
+    ClassObject* clazz;
+    int i, start, count;
+
+    clazz = refTypeIdToClassObject(refTypeId);
+    assert(clazz != NULL);
+
+    if (clazz->super == NULL)
+        start = 0;
+    else
+        start = clazz->super->iftableCount;
+
+    count = clazz->iftableCount - start;
+    expandBufAdd4BE(pReply, count);
+    for (i = start; i < clazz->iftableCount; i++) {
+        ClassObject* iface = clazz->iftable[i].clazz;
+        expandBufAddRefTypeId(pReply, classObjectToRefTypeId(iface));
+    }
+}
+
+struct DebugCallbackContext {
+    int numItems;
+    ExpandBuf* pReply;
+    // used by locals table
+    bool withGeneric;
+};
+
+static int lineTablePositionsCb(void *cnxt, u4 address, u4 lineNum)
+{
+    DebugCallbackContext *pContext = (DebugCallbackContext *)cnxt;
+
+    expandBufAdd8BE(pContext->pReply, address);
+    expandBufAdd4BE(pContext->pReply, lineNum);
+    pContext->numItems++;
+
+    return 0;
+}
+
+/*
+ * For Method.LineTable: output the line table.
+ *
+ * Note we operate in Dalvik's 16-bit units rather than bytes.
+ */
+void dvmDbgOutputLineTable(RefTypeId refTypeId, MethodId methodId,
+    ExpandBuf* pReply)
+{
+    Method* method;
+    u8 start, end;
+    DebugCallbackContext context;
+
+    memset (&context, 0, sizeof(DebugCallbackContext));
+
+    method = methodIdToMethod(refTypeId, methodId);
+    if (dvmIsNativeMethod(method)) {
+        start = (u8) -1;
+        end = (u8) -1;
+    } else {
+        start = 0;
+        end = dvmGetMethodInsnsSize(method);
+    }
+
+    expandBufAdd8BE(pReply, start);
+    expandBufAdd8BE(pReply, end);
+
+    // Add numLines later
+    size_t numLinesOffset = expandBufGetLength(pReply);
+    expandBufAdd4BE(pReply, 0);
+
+    context.pReply = pReply;
+
+    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
+        dvmGetMethodCode(method),
+        method->clazz->descriptor,
+        method->prototype.protoIdx,
+        method->accessFlags,
+        lineTablePositionsCb, NULL, &context);
+
+    set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
+}
+
+/*
+ * Eclipse appears to expect that the "this" reference is in slot zero.
+ * If it's not, the "variables" display will show two copies of "this",
+ * possibly because it gets "this" from SF.ThisObject and then displays
+ * all locals with nonzero slot numbers.
+ *
+ * So, we remap the item in slot 0 to 1000, and remap "this" to zero.  On
+ * SF.GetValues / SF.SetValues we map them back.
+ */
+static int tweakSlot(int slot, const char* name)
+{
+    int newSlot = slot;
+
+    if (strcmp(name, "this") == 0)      // only remap "this" ptr
+        newSlot = 0;
+    else if (slot == 0)                 // always remap slot 0
+        newSlot = kSlot0Sub;
+
+    LOGV("untweak: %d to %d", slot, newSlot);
+    return newSlot;
+}
+
+/*
+ * Reverse Eclipse hack.
+ */
+static int untweakSlot(int slot, const void* framePtr)
+{
+    int newSlot = slot;
+
+    if (slot == kSlot0Sub) {
+        newSlot = 0;
+    } else if (slot == 0) {
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
+        const Method* method = saveArea->method;
+        newSlot = method->registersSize - method->insSize;
+    }
+
+    LOGV("untweak: %d to %d", slot, newSlot);
+    return newSlot;
+}
+
+static void variableTableCb (void *cnxt, u2 reg, u4 startAddress,
+        u4 endAddress, const char *name, const char *descriptor,
+        const char *signature)
+{
+    DebugCallbackContext *pContext = (DebugCallbackContext *)cnxt;
+
+    reg = (u2) tweakSlot(reg, name);
+
+    LOGV("    %2d: %d(%d) '%s' '%s' slot=%d",
+        pContext->numItems, startAddress, endAddress - startAddress,
+        name, descriptor, reg);
+
+    expandBufAdd8BE(pContext->pReply, startAddress);
+    expandBufAddUtf8String(pContext->pReply, (const u1*)name);
+    expandBufAddUtf8String(pContext->pReply, (const u1*)descriptor);
+    if (pContext->withGeneric) {
+        expandBufAddUtf8String(pContext->pReply, (const u1*) signature);
+    }
+    expandBufAdd4BE(pContext->pReply, endAddress - startAddress);
+    expandBufAdd4BE(pContext->pReply, reg);
+
+    pContext->numItems++;
+}
+
+/*
+ * For Method.VariableTable[WithGeneric]: output information about local
+ * variables for the specified method.
+ */
+void dvmDbgOutputVariableTable(RefTypeId refTypeId, MethodId methodId,
+    bool withGeneric, ExpandBuf* pReply)
+{
+    Method* method;
+    DebugCallbackContext context;
+
+    memset (&context, 0, sizeof(DebugCallbackContext));
+
+    method = methodIdToMethod(refTypeId, methodId);
+
+    expandBufAdd4BE(pReply, method->insSize);
+
+    // Add numLocals later
+    size_t numLocalsOffset = expandBufGetLength(pReply);
+    expandBufAdd4BE(pReply, 0);
+
+    context.pReply = pReply;
+    context.withGeneric = withGeneric;
+    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
+        dvmGetMethodCode(method),
+        method->clazz->descriptor,
+        method->prototype.protoIdx,
+        method->accessFlags,
+        NULL, variableTableCb, &context);
+
+    set4BE(expandBufGetBuffer(pReply) + numLocalsOffset, context.numItems);
+}
+
+/*
+ * Get the basic tag for an instance field.
+ */
+u1 dvmDbgGetFieldBasicTag(ObjectId objId, FieldId fieldId)
+{
+    Object* obj = objectIdToObject(objId);
+    RefTypeId classId = classObjectToRefTypeId(obj->clazz);
+    const Field* field = fieldIdToField(classId, fieldId);
+    return basicTagFromDescriptor(field->signature);
+}
+
+/*
+ * Get the basic tag for a static field.
+ */
+u1 dvmDbgGetStaticFieldBasicTag(RefTypeId refTypeId, FieldId fieldId)
+{
+    const Field* field = fieldIdToField(refTypeId, fieldId);
+    return basicTagFromDescriptor(field->signature);
+}
+
+
+/*
+ * Copy the value of a static field into the output buffer, preceded
+ * by an appropriate tag.  The tag is based on the value held by the
+ * field, not the field's type.
+ */
+void dvmDbgGetFieldValue(ObjectId objectId, FieldId fieldId, ExpandBuf* pReply)
+{
+    Object* obj = objectIdToObject(objectId);
+    RefTypeId classId = classObjectToRefTypeId(obj->clazz);
+    InstField* ifield = (InstField*) fieldIdToField(classId, fieldId);
+    u1 tag = basicTagFromDescriptor(ifield->signature);
+
+    if (tag == JT_ARRAY || tag == JT_OBJECT) {
+        Object* objVal = dvmGetFieldObject(obj, ifield->byteOffset);
+        tag = tagFromObject(objVal);
+        expandBufAdd1(pReply, tag);
+        expandBufAddObjectId(pReply, objectToObjectId(objVal));
+        LOGV("    --> ifieldId %x --> tag '%c' %p", fieldId, tag, objVal);
+    } else {
+        LOGV("    --> ifieldId %x --> tag '%c'", fieldId, tag);
+        expandBufAdd1(pReply, tag);
+
+        switch (tag) {
+        case JT_BOOLEAN:
+            expandBufAdd1(pReply, dvmGetFieldBoolean(obj, ifield->byteOffset));
+            break;
+        case JT_BYTE:
+            expandBufAdd1(pReply, dvmGetFieldByte(obj, ifield->byteOffset));
+            break;
+        case JT_SHORT:
+            expandBufAdd2BE(pReply, dvmGetFieldShort(obj, ifield->byteOffset));
+            break;
+        case JT_CHAR:
+            expandBufAdd2BE(pReply, dvmGetFieldChar(obj, ifield->byteOffset));
+            break;
+        case JT_INT:
+        case JT_FLOAT:
+            expandBufAdd4BE(pReply, dvmGetFieldInt(obj, ifield->byteOffset));
+            break;
+        case JT_LONG:
+        case JT_DOUBLE:
+            expandBufAdd8BE(pReply, dvmGetFieldLong(obj, ifield->byteOffset));
+            break;
+        default:
+            LOGE("ERROR: unhandled field type '%s'", ifield->signature);
+            assert(false);
+            break;
+        }
+    }
+}
+
+/*
+ * Set the value of the specified field.
+ */
+void dvmDbgSetFieldValue(ObjectId objectId, FieldId fieldId, u8 value,
+    int width)
+{
+    Object* obj = objectIdToObject(objectId);
+    RefTypeId classId = classObjectToRefTypeId(obj->clazz);
+    InstField* field = (InstField*) fieldIdToField(classId, fieldId);
+
+    switch (field->signature[0]) {
+    case JT_BOOLEAN:
+        assert(width == 1);
+        dvmSetFieldBoolean(obj, field->byteOffset, value != 0);
+        break;
+    case JT_BYTE:
+        assert(width == 1);
+        dvmSetFieldInt(obj, field->byteOffset, value);
+        break;
+    case JT_SHORT:
+    case JT_CHAR:
+        assert(width == 2);
+        dvmSetFieldInt(obj, field->byteOffset, value);
+        break;
+    case JT_INT:
+    case JT_FLOAT:
+        assert(width == 4);
+        dvmSetFieldInt(obj, field->byteOffset, value);
+        break;
+    case JT_ARRAY:
+    case JT_OBJECT:
+        assert(width == sizeof(ObjectId));
+        dvmSetFieldObject(obj, field->byteOffset, objectIdToObject(value));
+        break;
+    case JT_DOUBLE:
+    case JT_LONG:
+        assert(width == 8);
+        dvmSetFieldLong(obj, field->byteOffset, value);
+        break;
+    default:
+        LOGE("ERROR: unhandled class type '%s'", field->signature);
+        assert(false);
+        break;
+    }
+}
+
+/*
+ * Copy the value of a static field into the output buffer, preceded
+ * by an appropriate tag.  The tag is based on the value held by the
+ * field, not the field's type.
+ */
+void dvmDbgGetStaticFieldValue(RefTypeId refTypeId, FieldId fieldId,
+    ExpandBuf* pReply)
+{
+    StaticField* sfield = (StaticField*) fieldIdToField(refTypeId, fieldId);
+    u1 tag = basicTagFromDescriptor(sfield->signature);
+
+    if (tag == JT_ARRAY || tag == JT_OBJECT) {
+        Object* objVal = dvmGetStaticFieldObject(sfield);
+        tag = tagFromObject(objVal);
+        expandBufAdd1(pReply, tag);
+        expandBufAddObjectId(pReply, objectToObjectId(objVal));
+        LOGV("    --> sfieldId %x --> tag '%c' %p", fieldId, tag, objVal);
+    } else {
+        JValue value;
+
+        LOGV("    --> sfieldId %x --> tag '%c'", fieldId, tag);
+        expandBufAdd1(pReply, tag);
+
+        switch (tag) {
+        case JT_BOOLEAN:
+            expandBufAdd1(pReply, dvmGetStaticFieldBoolean(sfield));
+            break;
+        case JT_BYTE:
+            expandBufAdd1(pReply, dvmGetStaticFieldByte(sfield));
+            break;
+        case JT_SHORT:
+            expandBufAdd2BE(pReply, dvmGetStaticFieldShort(sfield));
+            break;
+        case JT_CHAR:
+            expandBufAdd2BE(pReply, dvmGetStaticFieldChar(sfield));
+            break;
+        case JT_INT:
+            expandBufAdd4BE(pReply, dvmGetStaticFieldInt(sfield));
+            break;
+        case JT_FLOAT:
+            value.f = dvmGetStaticFieldFloat(sfield);
+            expandBufAdd4BE(pReply, value.i);
+            break;
+        case JT_LONG:
+            expandBufAdd8BE(pReply, dvmGetStaticFieldLong(sfield));
+            break;
+        case JT_DOUBLE:
+            value.d = dvmGetStaticFieldDouble(sfield);
+            expandBufAdd8BE(pReply, value.j);
+            break;
+        default:
+            LOGE("ERROR: unhandled field type '%s'", sfield->signature);
+            assert(false);
+            break;
+        }
+    }
+}
+
+/*
+ * Set the value of a static field.
+ */
+void dvmDbgSetStaticFieldValue(RefTypeId refTypeId, FieldId fieldId,
+    u8 rawValue, int width)
+{
+    StaticField* sfield = (StaticField*) fieldIdToField(refTypeId, fieldId);
+    Object* objVal;
+    JValue value;
+
+    value.j = rawValue;
+
+    switch (sfield->signature[0]) {
+    case JT_BOOLEAN:
+        assert(width == 1);
+        dvmSetStaticFieldBoolean(sfield, value.z);
+        break;
+    case JT_BYTE:
+        assert(width == 1);
+        dvmSetStaticFieldByte(sfield, value.b);
+        break;
+    case JT_SHORT:
+        assert(width == 2);
+        dvmSetStaticFieldShort(sfield, value.s);
+        break;
+    case JT_CHAR:
+        assert(width == 2);
+        dvmSetStaticFieldChar(sfield, value.c);
+        break;
+    case JT_INT:
+        assert(width == 4);
+        dvmSetStaticFieldInt(sfield, value.i);
+        break;
+    case JT_FLOAT:
+        assert(width == 4);
+        dvmSetStaticFieldFloat(sfield, value.f);
+        break;
+    case JT_ARRAY:
+    case JT_OBJECT:
+        assert(width == sizeof(ObjectId));
+        objVal = objectIdToObject(rawValue);
+        dvmSetStaticFieldObject(sfield, objVal);
+        break;
+    case JT_LONG:
+        assert(width == 8);
+        dvmSetStaticFieldLong(sfield, value.j);
+        break;
+    case JT_DOUBLE:
+        assert(width == 8);
+        dvmSetStaticFieldDouble(sfield, value.d);
+        break;
+    default:
+        LOGE("ERROR: unhandled class type '%s'", sfield->signature);
+        assert(false);
+        break;
+    }
+}
+
+/*
+ * Convert a string object to a UTF-8 string.
+ *
+ * Returns a newly-allocated string.
+ */
+char* dvmDbgStringToUtf8(ObjectId strId)
+{
+    StringObject* strObj = (StringObject*) objectIdToObject(strId);
+
+    return dvmCreateCstrFromString(strObj);
+}
+
+
+/*
+ * ===========================================================================
+ *      Thread and ThreadGroup
+ * ===========================================================================
+ */
+
+/*
+ * Convert a thread object to a Thread ptr.
+ *
+ * This currently requires running through the list of threads and finding
+ * a match.
+ *
+ * IMPORTANT: grab gDvm.threadListLock before calling here.
+ */
+static Thread* threadObjToThread(Object* threadObj)
+{
+    Thread* thread;
+
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread->threadObj == threadObj)
+            break;
+    }
+
+    return thread;
+}
+
+/*
+ * Get the status and suspend state of a thread.
+ */
+bool dvmDbgGetThreadStatus(ObjectId threadId, u4* pThreadStatus,
+    u4* pSuspendStatus)
+{
+    Object* threadObj;
+    Thread* thread;
+    bool result = false;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    /* lock the thread list, so the thread doesn't vanish while we work */
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL)
+        goto bail;
+
+    switch (thread->status) {
+    case THREAD_ZOMBIE:         *pThreadStatus = TS_ZOMBIE;     break;
+    case THREAD_RUNNING:        *pThreadStatus = TS_RUNNING;    break;
+    case THREAD_TIMED_WAIT:     *pThreadStatus = TS_SLEEPING;   break;
+    case THREAD_MONITOR:        *pThreadStatus = TS_MONITOR;    break;
+    case THREAD_WAIT:           *pThreadStatus = TS_WAIT;       break;
+    case THREAD_INITIALIZING:   *pThreadStatus = TS_ZOMBIE;     break;
+    case THREAD_STARTING:       *pThreadStatus = TS_ZOMBIE;     break;
+    case THREAD_NATIVE:         *pThreadStatus = TS_RUNNING;    break;
+    case THREAD_VMWAIT:         *pThreadStatus = TS_WAIT;       break;
+    case THREAD_SUSPENDED:      *pThreadStatus = TS_RUNNING;    break;
+    default:
+        assert(false);
+        *pThreadStatus = THREAD_ZOMBIE;
+        break;
+    }
+
+    if (dvmIsSuspended(thread))
+        *pSuspendStatus = SUSPEND_STATUS_SUSPENDED;
+    else
+        *pSuspendStatus = 0;
+
+    result = true;
+
+bail:
+    dvmUnlockThreadList();
+    return result;
+}
+
+/*
+ * Get the thread's suspend count.
+ */
+u4 dvmDbgGetThreadSuspendCount(ObjectId threadId)
+{
+    Object* threadObj;
+    Thread* thread;
+    u4 result = 0;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    /* lock the thread list, so the thread doesn't vanish while we work */
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL)
+        goto bail;
+
+    result = thread->suspendCount;
+
+bail:
+    dvmUnlockThreadList();
+    return result;
+}
+
+/*
+ * Determine whether or not a thread exists in the VM's thread list.
+ *
+ * Returns "true" if the thread exists.
+ */
+bool dvmDbgThreadExists(ObjectId threadId)
+{
+    Object* threadObj;
+    Thread* thread;
+    bool result;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    /* lock the thread list, so the thread doesn't vanish while we work */
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL)
+        result = false;
+    else
+        result = true;
+
+    dvmUnlockThreadList();
+    return result;
+}
+
+/*
+ * Determine whether or not a thread is suspended.
+ *
+ * Returns "false" if the thread is running or doesn't exist.
+ */
+bool dvmDbgIsSuspended(ObjectId threadId)
+{
+    Object* threadObj;
+    Thread* thread;
+    bool result = false;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    /* lock the thread list, so the thread doesn't vanish while we work */
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL)
+        goto bail;
+
+    result = dvmIsSuspended(thread);
+
+bail:
+    dvmUnlockThreadList();
+    return result;
+}
+
+/*
+ * Return the ObjectId for the "system" thread group.
+ */
+ObjectId dvmDbgGetSystemThreadGroupId()
+{
+    Object* groupObj = dvmGetSystemThreadGroup();
+    return objectToObjectId(groupObj);
+}
+
+/*
+ * Return the ObjectId for the "main" thread group.
+ */
+ObjectId dvmDbgGetMainThreadGroupId()
+{
+    Object* groupObj = dvmGetMainThreadGroup();
+    return objectToObjectId(groupObj);
+}
+
+/*
+ * Get the name of a thread.
+ *
+ * Returns a newly-allocated string.
+ */
+char* dvmDbgGetThreadName(ObjectId threadId)
+{
+    Object* threadObj;
+    StringObject* nameStr;
+    char* str;
+    char* result;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    nameStr = (StringObject*) dvmGetFieldObject(threadObj,
+                                                gDvm.offJavaLangThread_name);
+    str = dvmCreateCstrFromString(nameStr);
+    result = (char*) malloc(strlen(str) + 20);
+
+    /* lock the thread list, so the thread doesn't vanish while we work */
+    dvmLockThreadList(NULL);
+    Thread* thread = threadObjToThread(threadObj);
+    if (thread != NULL)
+        sprintf(result, "<%d> %s", thread->threadId, str);
+    else
+        sprintf(result, "%s", str);
+    dvmUnlockThreadList();
+
+    free(str);
+    return result;
+}
+
+/*
+ * Get a thread's group.
+ */
+ObjectId dvmDbgGetThreadGroup(ObjectId threadId)
+{
+    Object* threadObj;
+    Object* group;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    group = dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_group);
+    return objectToObjectId(group);
+}
+
+
+/*
+ * Get the name of a thread group.
+ *
+ * Returns a newly-allocated string.
+ */
+char* dvmDbgGetThreadGroupName(ObjectId threadGroupId)
+{
+    Object* threadGroup;
+    StringObject* nameStr;
+
+    threadGroup = objectIdToObject(threadGroupId);
+    assert(threadGroup != NULL);
+
+    nameStr = (StringObject*)
+        dvmGetFieldObject(threadGroup, gDvm.offJavaLangThreadGroup_name);
+    return dvmCreateCstrFromString(nameStr);
+}
+
+/*
+ * Get the parent of a thread group.
+ *
+ * Returns a newly-allocated string.
+ */
+ObjectId dvmDbgGetThreadGroupParent(ObjectId threadGroupId)
+{
+    Object* threadGroup;
+    Object* parent;
+
+    threadGroup = objectIdToObject(threadGroupId);
+    assert(threadGroup != NULL);
+
+    parent = dvmGetFieldObject(threadGroup, gDvm.offJavaLangThreadGroup_parent);
+    return objectToObjectId(parent);
+}
+
+/*
+ * Get the list of threads in the thread group.
+ *
+ * We do this by running through the full list of threads and returning
+ * the ones that have the ThreadGroup object as their owner.
+ *
+ * If threadGroupId is set to "kAllThreads", we ignore the group field and
+ * return all threads.
+ *
+ * The caller must free "*ppThreadIds".
+ */
+void dvmDbgGetThreadGroupThreads(ObjectId threadGroupId,
+    ObjectId** ppThreadIds, u4* pThreadCount)
+{
+    Object* targetThreadGroup = NULL;
+    Thread* thread;
+    int count;
+
+    if (threadGroupId != THREAD_GROUP_ALL) {
+        targetThreadGroup = objectIdToObject(threadGroupId);
+        assert(targetThreadGroup != NULL);
+    }
+
+    dvmLockThreadList(NULL);
+
+    thread = gDvm.threadList;
+    count = 0;
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        Object* group;
+
+        /* Skip over the JDWP support thread.  Some debuggers
+         * get bent out of shape when they can't suspend and
+         * query all threads, so it's easier if we just don't
+         * tell them about us.
+         */
+        if (thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState))
+            continue;
+
+        /* This thread is currently being created, and isn't ready
+         * to be seen by the debugger yet.
+         */
+        if (thread->threadObj == NULL)
+            continue;
+
+        group = dvmGetFieldObject(thread->threadObj,
+                    gDvm.offJavaLangThread_group);
+        if (threadGroupId == THREAD_GROUP_ALL || group == targetThreadGroup)
+            count++;
+    }
+
+    *pThreadCount = count;
+
+    if (count == 0) {
+        *ppThreadIds = NULL;
+    } else {
+        ObjectId* ptr;
+        ptr = *ppThreadIds = (ObjectId*) malloc(sizeof(ObjectId) * count);
+
+        for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+            Object* group;
+
+            /* Skip over the JDWP support thread.  Some debuggers
+             * get bent out of shape when they can't suspend and
+             * query all threads, so it's easier if we just don't
+             * tell them about us.
+             */
+            if (thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState))
+                continue;
+
+            /* This thread is currently being created, and isn't ready
+             * to be seen by the debugger yet.
+             */
+            if (thread->threadObj == NULL)
+                continue;
+
+            group = dvmGetFieldObject(thread->threadObj,
+                        gDvm.offJavaLangThread_group);
+            if (threadGroupId == THREAD_GROUP_ALL || group == targetThreadGroup)
+            {
+                *ptr++ = objectToObjectId(thread->threadObj);
+                count--;
+            }
+        }
+
+        assert(count == 0);
+    }
+
+    dvmUnlockThreadList();
+}
+
+/*
+ * Get all threads.
+ *
+ * The caller must free "*ppThreadIds".
+ */
+void dvmDbgGetAllThreads(ObjectId** ppThreadIds, u4* pThreadCount)
+{
+    dvmDbgGetThreadGroupThreads(THREAD_GROUP_ALL, ppThreadIds, pThreadCount);
+}
+
+
+/*
+ * Count up the #of frames on the thread's stack.
+ *
+ * Returns -1 on failure.
+ */
+int dvmDbgGetThreadFrameCount(ObjectId threadId)
+{
+    Object* threadObj;
+    Thread* thread;
+    int count = -1;
+
+    threadObj = objectIdToObject(threadId);
+
+    dvmLockThreadList(NULL);
+    thread = threadObjToThread(threadObj);
+    if (thread != NULL) {
+        count = dvmComputeExactFrameDepth(thread->interpSave.curFrame);
+    }
+    dvmUnlockThreadList();
+
+    return count;
+}
+
+/*
+ * Get info for frame N from the specified thread's stack.
+ */
+bool dvmDbgGetThreadFrame(ObjectId threadId, int num, FrameId* pFrameId,
+    JdwpLocation* pLoc)
+{
+    Object* threadObj;
+    Thread* thread;
+    void* framePtr;
+    int count;
+
+    threadObj = objectIdToObject(threadId);
+
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL)
+        goto bail;
+
+    framePtr = thread->interpSave.curFrame;
+    count = 0;
+    while (framePtr != NULL) {
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
+        const Method* method = saveArea->method;
+
+        if (!dvmIsBreakFrame((u4*)framePtr)) {
+            if (count == num) {
+                *pFrameId = frameToFrameId(framePtr);
+                if (dvmIsInterfaceClass(method->clazz))
+                    pLoc->typeTag = TT_INTERFACE;
+                else
+                    pLoc->typeTag = TT_CLASS;
+                pLoc->classId = classObjectToRefTypeId(method->clazz);
+                pLoc->methodId = methodToMethodId(method);
+                if (dvmIsNativeMethod(method))
+                    pLoc->idx = (u8)-1;
+                else
+                    pLoc->idx = saveArea->xtra.currentPc - method->insns;
+                dvmUnlockThreadList();
+                return true;
+            }
+
+            count++;
+        }
+
+        framePtr = saveArea->prevFrame;
+    }
+
+bail:
+    dvmUnlockThreadList();
+    return false;
+}
+
+/*
+ * Get the ThreadId for the current thread.
+ */
+ObjectId dvmDbgGetThreadSelfId()
+{
+    Thread* self = dvmThreadSelf();
+    return objectToObjectId(self->threadObj);
+}
+
+/*
+ * Suspend the VM.
+ */
+void dvmDbgSuspendVM(bool isEvent)
+{
+    dvmSuspendAllThreads(isEvent ? SUSPEND_FOR_DEBUG_EVENT : SUSPEND_FOR_DEBUG);
+}
+
+/*
+ * Resume the VM.
+ */
+void dvmDbgResumeVM()
+{
+    dvmResumeAllThreads(SUSPEND_FOR_DEBUG);
+}
+
+/*
+ * Suspend one thread (not ourselves).
+ */
+void dvmDbgSuspendThread(ObjectId threadId)
+{
+    Object* threadObj = objectIdToObject(threadId);
+    Thread* thread;
+
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL) {
+        /* can happen if our ThreadDeath notify crosses in the mail */
+        LOGW("WARNING: threadid=%llx obj=%p no match", threadId, threadObj);
+    } else {
+        dvmSuspendThread(thread);
+    }
+
+    dvmUnlockThreadList();
+}
+
+/*
+ * Resume one thread (not ourselves).
+ */
+void dvmDbgResumeThread(ObjectId threadId)
+{
+    Object* threadObj = objectIdToObject(threadId);
+    Thread* thread;
+
+    dvmLockThreadList(NULL);
+
+    thread = threadObjToThread(threadObj);
+    if (thread == NULL) {
+        LOGW("WARNING: threadid=%llx obj=%p no match", threadId, threadObj);
+    } else {
+        dvmResumeThread(thread);
+    }
+
+    dvmUnlockThreadList();
+}
+
+/*
+ * Suspend ourselves after sending an event to the debugger.
+ */
+void dvmDbgSuspendSelf()
+{
+    dvmSuspendSelf(true);
+}
+
+/*
+ * Get the "this" object for the specified frame.
+ */
+static Object* getThisObject(const u4* framePtr)
+{
+    const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
+    const Method* method = saveArea->method;
+    int argOffset = method->registersSize - method->insSize;
+    Object* thisObj;
+
+    if (method == NULL) {
+        /* this is a "break" frame? */
+        assert(false);
+        return NULL;
+    }
+
+    LOGVV("  Pulling this object for frame at %p", framePtr);
+    LOGVV("    Method='%s' native=%d static=%d this=%p",
+        method->name, dvmIsNativeMethod(method),
+        dvmIsStaticMethod(method), (Object*) framePtr[argOffset]);
+
+    /*
+     * No "this" pointer for statics.  No args on the interp stack for
+     * native methods invoked directly from the VM.
+     */
+    if (dvmIsNativeMethod(method) || dvmIsStaticMethod(method))
+        thisObj = NULL;
+    else
+        thisObj = (Object*) framePtr[argOffset];
+
+    if (thisObj != NULL && !dvmIsHeapAddress(thisObj)) {
+        LOGW("Debugger: invalid 'this' pointer %p in %s.%s; returning NULL",
+            framePtr, method->clazz->descriptor, method->name);
+        thisObj = NULL;
+    }
+
+    return thisObj;
+}
+
+/*
+ * Return the "this" object for the specified frame.  The thread must be
+ * suspended.
+ */
+bool dvmDbgGetThisObject(ObjectId threadId, FrameId frameId, ObjectId* pThisId)
+{
+    const u4* framePtr = frameIdToFrame(frameId);
+    Object* thisObj;
+
+    UNUSED_PARAMETER(threadId);
+
+    thisObj = getThisObject(framePtr);
+
+    *pThisId = objectToObjectId(thisObj);
+    return true;
+}
+
+/*
+ * Copy the value of a method argument or local variable into the
+ * specified buffer.  The value will be preceeded with the tag.
+ *
+ * The debugger includes the tags in the request.  Object tags may
+ * be updated with a more refined type.
+ */
+void dvmDbgGetLocalValue(ObjectId threadId, FrameId frameId, int slot,
+    u1 tag, u1* buf, int expectedLen)
+{
+    const u4* framePtr = frameIdToFrame(frameId);
+    Object* objVal;
+    u4 intVal;
+    u8 longVal;
+
+    UNUSED_PARAMETER(threadId);
+
+    slot = untweakSlot(slot, framePtr);     // Eclipse workaround
+
+    switch (tag) {
+    case JT_BOOLEAN:
+        assert(expectedLen == 1);
+        intVal = framePtr[slot];
+        set1(buf+1, intVal != 0);
+        break;
+    case JT_BYTE:
+        assert(expectedLen == 1);
+        intVal = framePtr[slot];
+        set1(buf+1, intVal);
+        break;
+    case JT_SHORT:
+    case JT_CHAR:
+        assert(expectedLen == 2);
+        intVal = framePtr[slot];
+        set2BE(buf+1, intVal);
+        break;
+    case JT_INT:
+    case JT_FLOAT:
+        assert(expectedLen == 4);
+        intVal = framePtr[slot];
+        set4BE(buf+1, intVal);
+        break;
+    case JT_ARRAY:
+        assert(expectedLen == sizeof(ObjectId));
+        {
+            /* convert to "ObjectId" */
+            objVal = (Object*)framePtr[slot];
+            if (objVal != NULL && !dvmIsHeapAddress(objVal)) {
+                LOGW("JDWP: slot %d expected to hold array, %p invalid",
+                    slot, objVal);
+                dvmAbort();         // DEBUG: make it obvious
+                objVal = NULL;
+                tag = JT_OBJECT;    // JT_ARRAY not expected for NULL ref
+            }
+            dvmSetObjectId(buf+1, objectToObjectId(objVal));
+        }
+        break;
+    case JT_OBJECT:
+        assert(expectedLen == sizeof(ObjectId));
+        {
+            /* convert to "ObjectId" */
+            objVal = (Object*)framePtr[slot];
+
+            if (objVal != NULL && !dvmIsHeapAddress(objVal)) {
+                LOGW("JDWP: slot %d expected to hold object, %p invalid",
+                    slot, objVal);
+                dvmAbort();         // DEBUG: make it obvious
+                objVal = NULL;
+            }
+            tag = tagFromObject(objVal);
+            dvmSetObjectId(buf+1, objectToObjectId(objVal));
+        }
+        break;
+    case JT_DOUBLE:
+    case JT_LONG:
+        assert(expectedLen == 8);
+        memcpy(&longVal, &framePtr[slot], 8);
+        set8BE(buf+1, longVal);
+        break;
+    default:
+        LOGE("ERROR: unhandled tag '%c'", tag);
+        assert(false);
+        break;
+    }
+
+    /* prepend tag, which may have been updated */
+    set1(buf, tag);
+}
+
+/*
+ * Copy a new value into an argument or local variable.
+ */
+void dvmDbgSetLocalValue(ObjectId threadId, FrameId frameId, int slot, u1 tag,
+    u8 value, int width)
+{
+    u4* framePtr = frameIdToFrame(frameId);
+
+    UNUSED_PARAMETER(threadId);
+
+    slot = untweakSlot(slot, framePtr);     // Eclipse workaround
+
+    switch (tag) {
+    case JT_BOOLEAN:
+        assert(width == 1);
+        framePtr[slot] = (u4)value;
+        break;
+    case JT_BYTE:
+        assert(width == 1);
+        framePtr[slot] = (u4)value;
+        break;
+    case JT_SHORT:
+    case JT_CHAR:
+        assert(width == 2);
+        framePtr[slot] = (u4)value;
+        break;
+    case JT_INT:
+    case JT_FLOAT:
+        assert(width == 4);
+        framePtr[slot] = (u4)value;
+        break;
+    case JT_STRING:
+        /* The debugger calls VirtualMachine.CreateString to create a new
+         * string, then uses this to set the object reference, when you
+         * edit a String object */
+    case JT_ARRAY:
+    case JT_OBJECT:
+        assert(width == sizeof(ObjectId));
+        framePtr[slot] = (u4) objectIdToObject(value);
+        break;
+    case JT_DOUBLE:
+    case JT_LONG:
+        assert(width == 8);
+        memcpy(&framePtr[slot], &value, 8);
+        break;
+    case JT_VOID:
+    case JT_CLASS_OBJECT:
+    case JT_THREAD:
+    case JT_THREAD_GROUP:
+    case JT_CLASS_LOADER:
+        /* not expecting these from debugger; fall through to failure */
+    default:
+        LOGE("ERROR: unhandled tag '%c'", tag);
+        assert(false);
+        break;
+    }
+}
+
+
+/*
+ * ===========================================================================
+ *      Debugger notification
+ * ===========================================================================
+ */
+
+/*
+ * Tell JDWP that a breakpoint address has been reached.
+ *
+ * "pcOffset" will be -1 for native methods.
+ * "thisPtr" will be NULL for static methods.
+ */
+void dvmDbgPostLocationEvent(const Method* method, int pcOffset,
+    Object* thisPtr, int eventFlags)
+{
+    JdwpLocation loc;
+
+    if (dvmIsInterfaceClass(method->clazz))
+        loc.typeTag = TT_INTERFACE;
+    else
+        loc.typeTag = TT_CLASS;
+    loc.classId = classObjectToRefTypeId(method->clazz);
+    loc.methodId = methodToMethodId(method);
+    loc.idx = pcOffset;
+
+    /*
+     * Note we use "NoReg" so we don't keep track of references that are
+     * never actually sent to the debugger.  The "thisPtr" is only used to
+     * compare against registered events.
+     */
+
+    if (dvmJdwpPostLocationEvent(gDvm.jdwpState, &loc,
+            objectToObjectIdNoReg(thisPtr), eventFlags))
+    {
+        classObjectToRefTypeId(method->clazz);
+        objectToObjectId(thisPtr);
+    }
+}
+
+/*
+ * Tell JDWP that an exception has occurred.
+ */
+void dvmDbgPostException(void* throwFp, int throwRelPc, void* catchFp,
+    int catchRelPc, Object* exception)
+{
+    JdwpLocation throwLoc, catchLoc;
+    const Method* throwMeth;
+    const Method* catchMeth;
+
+    throwMeth = SAVEAREA_FROM_FP(throwFp)->method;
+    if (dvmIsInterfaceClass(throwMeth->clazz))
+        throwLoc.typeTag = TT_INTERFACE;
+    else
+        throwLoc.typeTag = TT_CLASS;
+    throwLoc.classId = classObjectToRefTypeId(throwMeth->clazz);
+    throwLoc.methodId = methodToMethodId(throwMeth);
+    throwLoc.idx = throwRelPc;
+
+    if (catchRelPc < 0) {
+        memset(&catchLoc, 0, sizeof(catchLoc));
+    } else {
+        catchMeth = SAVEAREA_FROM_FP(catchFp)->method;
+        if (dvmIsInterfaceClass(catchMeth->clazz))
+            catchLoc.typeTag = TT_INTERFACE;
+        else
+            catchLoc.typeTag = TT_CLASS;
+        catchLoc.classId = classObjectToRefTypeId(catchMeth->clazz);
+        catchLoc.methodId = methodToMethodId(catchMeth);
+        catchLoc.idx = catchRelPc;
+    }
+
+    /* need this for InstanceOnly filters */
+    Object* thisObj = getThisObject((u4*)throwFp);
+
+    /*
+     * Hand the event to the JDWP exception handler.  Note we're using the
+     * "NoReg" objectID on the exception, which is not strictly correct --
+     * the exception object WILL be passed up to the debugger if the
+     * debugger is interested in the event.  We do this because the current
+     * implementation of the debugger object registry never throws anything
+     * away, and some people were experiencing a fatal build up of exception
+     * objects when dealing with certain libraries.
+     */
+    dvmJdwpPostException(gDvm.jdwpState, &throwLoc,
+        objectToObjectIdNoReg(exception),
+        classObjectToRefTypeId(exception->clazz), &catchLoc,
+        objectToObjectId(thisObj));
+}
+
+/*
+ * Tell JDWP and/or DDMS that a thread has started.
+ */
+void dvmDbgPostThreadStart(Thread* thread)
+{
+    if (gDvm.debuggerActive) {
+        dvmJdwpPostThreadChange(gDvm.jdwpState,
+            objectToObjectId(thread->threadObj), true);
+    }
+    if (gDvm.ddmThreadNotification)
+        dvmDdmSendThreadNotification(thread, true);
+}
+
+/*
+ * Tell JDWP and/or DDMS that a thread has gone away.
+ */
+void dvmDbgPostThreadDeath(Thread* thread)
+{
+    if (gDvm.debuggerActive) {
+        dvmJdwpPostThreadChange(gDvm.jdwpState,
+            objectToObjectId(thread->threadObj), false);
+    }
+    if (gDvm.ddmThreadNotification)
+        dvmDdmSendThreadNotification(thread, false);
+}
+
+/*
+ * Tell JDWP that a new class has been prepared.
+ */
+void dvmDbgPostClassPrepare(ClassObject* clazz)
+{
+    const char* signature;
+    int tag;
+
+    if (dvmIsInterfaceClass(clazz))
+        tag = TT_INTERFACE;
+    else
+        tag = TT_CLASS;
+
+    // TODO - we currently always send both "verified" and "prepared" since
+    // debuggers seem to like that.  There might be some advantage to honesty,
+    // since the class may not yet be verified.
+    signature = jniSignature(clazz);
+    dvmJdwpPostClassPrepare(gDvm.jdwpState, tag, classObjectToRefTypeId(clazz),
+        signature, CS_VERIFIED | CS_PREPARED);
+}
+
+/*
+ * The JDWP event mechanism has registered an event with a LocationOnly
+ * mod.  Tell the interpreter to call us if we hit the specified
+ * address.
+ */
+bool dvmDbgWatchLocation(const JdwpLocation* pLoc)
+{
+    Method* method = methodIdToMethod(pLoc->classId, pLoc->methodId);
+    assert(!dvmIsNativeMethod(method));
+    dvmAddBreakAddr(method, pLoc->idx);
+    return true;        /* assume success */
+}
+
+/*
+ * An event with a LocationOnly mod has been removed.
+ */
+void dvmDbgUnwatchLocation(const JdwpLocation* pLoc)
+{
+    Method* method = methodIdToMethod(pLoc->classId, pLoc->methodId);
+    assert(!dvmIsNativeMethod(method));
+    dvmClearBreakAddr(method, pLoc->idx);
+}
+
+/*
+ * The JDWP event mechanism has registered a single-step event.  Tell
+ * the interpreter about it.
+ */
+bool dvmDbgConfigureStep(ObjectId threadId, JdwpStepSize size,
+    JdwpStepDepth depth)
+{
+    Object* threadObj;
+    Thread* thread;
+    bool result = false;
+
+    threadObj = objectIdToObject(threadId);
+    assert(threadObj != NULL);
+
+    /*
+     * Get a pointer to the Thread struct for this ID.  The pointer will
+     * be used strictly for comparisons against the current thread pointer
+     * after the setup is complete, so we can safely release the lock.
+     */
+    dvmLockThreadList(NULL);
+    thread = threadObjToThread(threadObj);
+
+    if (thread == NULL) {
+        LOGE("Thread for single-step not found");
+        goto bail;
+    }
+    if (!dvmIsSuspended(thread)) {
+        LOGE("Thread for single-step not suspended");
+        assert(!"non-susp step");      // I want to know if this can happen
+        goto bail;
+    }
+
+    assert(dvmIsSuspended(thread));
+    if (!dvmAddSingleStep(thread, size, depth))
+        goto bail;
+
+    result = true;
+
+bail:
+    dvmUnlockThreadList();
+    return result;
+}
+
+/*
+ * A single-step event has been removed.
+ */
+void dvmDbgUnconfigureStep(ObjectId threadId)
+{
+    UNUSED_PARAMETER(threadId);
+
+    /* right now it's global, so don't need to find Thread */
+    dvmClearSingleStep(NULL);
+}
+
+/*
+ * Invoke a method in a thread that has been stopped on a breakpoint or
+ * other debugger event.  (This function is called from the JDWP thread.)
+ *
+ * Note that access control is not enforced, per spec.
+ */
+JdwpError dvmDbgInvokeMethod(ObjectId threadId, ObjectId objectId,
+    RefTypeId classId, MethodId methodId, u4 numArgs, ObjectId* argArray,
+    u4 options, u1* pResultTag, u8* pResultValue, ObjectId* pExceptObj)
+{
+    Object* threadObj = objectIdToObject(threadId);
+
+    dvmLockThreadList(NULL);
+
+    Thread* targetThread = threadObjToThread(threadObj);
+    if (targetThread == NULL) {
+        dvmUnlockThreadList();
+        return ERR_INVALID_THREAD;       /* thread does not exist */
+    }
+    if (!targetThread->invokeReq.ready) {
+        dvmUnlockThreadList();
+        return ERR_INVALID_THREAD;       /* thread not stopped by event */
+    }
+
+    /*
+     * We currently have a bug where we don't successfully resume the
+     * target thread if the suspend count is too deep.  We're expected to
+     * require one "resume" for each "suspend", but when asked to execute
+     * a method we have to resume fully and then re-suspend it back to the
+     * same level.  (The easiest way to cause this is to type "suspend"
+     * multiple times in jdb.)
+     *
+     * It's unclear what this means when the event specifies "resume all"
+     * and some threads are suspended more deeply than others.  This is
+     * a rare problem, so for now we just prevent it from hanging forever
+     * by rejecting the method invocation request.  Without this, we will
+     * be stuck waiting on a suspended thread.
+     */
+    if (targetThread->suspendCount > 1) {
+        LOGW("threadid=%d: suspend count on threadid=%d is %d, too deep "
+             "for method exec",
+            dvmThreadSelf()->threadId, targetThread->threadId,
+            targetThread->suspendCount);
+        dvmUnlockThreadList();
+        return ERR_THREAD_SUSPENDED;     /* probably not expected here */
+    }
+
+    /*
+     * TODO: ought to screen the various IDs, and verify that the argument
+     * list is valid.
+     */
+
+    targetThread->invokeReq.obj = objectIdToObject(objectId);
+    targetThread->invokeReq.thread = threadObj;
+    targetThread->invokeReq.clazz = refTypeIdToClassObject(classId);
+    targetThread->invokeReq.method = methodIdToMethod(classId, methodId);
+    targetThread->invokeReq.numArgs = numArgs;
+    targetThread->invokeReq.argArray = argArray;
+    targetThread->invokeReq.options = options;
+    targetThread->invokeReq.invokeNeeded = true;
+
+    /*
+     * This is a bit risky -- if the thread goes away we're sitting high
+     * and dry -- but we must release this before the dvmResumeAllThreads
+     * call, and it's unwise to hold it during dvmWaitForSuspend.
+     */
+    dvmUnlockThreadList();
+
+    /*
+     * We change our (JDWP thread) status, which should be THREAD_RUNNING,
+     * so the VM can suspend for a GC if the invoke request causes us to
+     * run out of memory.  It's also a good idea to change it before locking
+     * the invokeReq mutex, although that should never be held for long.
+     */
+    Thread* self = dvmThreadSelf();
+    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+
+    LOGV("    Transferring control to event thread");
+    dvmLockMutex(&targetThread->invokeReq.lock);
+
+    if ((options & INVOKE_SINGLE_THREADED) == 0) {
+        LOGV("      Resuming all threads");
+        dvmResumeAllThreads(SUSPEND_FOR_DEBUG_EVENT);
+    } else {
+        LOGV("      Resuming event thread only");
+        dvmResumeThread(targetThread);
+    }
+
+    /*
+     * Wait for the request to finish executing.
+     */
+    while (targetThread->invokeReq.invokeNeeded) {
+        pthread_cond_wait(&targetThread->invokeReq.cv,
+                          &targetThread->invokeReq.lock);
+    }
+    dvmUnlockMutex(&targetThread->invokeReq.lock);
+    LOGV("    Control has returned from event thread");
+
+    /* wait for thread to re-suspend itself */
+    dvmWaitForSuspend(targetThread);
+
+    /*
+     * Done waiting, switch back to RUNNING.
+     */
+    dvmChangeStatus(self, oldStatus);
+
+    /*
+     * Suspend the threads.  We waited for the target thread to suspend
+     * itself, so all we need to do is suspend the others.
+     *
+     * The suspendAllThreads() call will double-suspend the event thread,
+     * so we want to resume the target thread once to keep the books straight.
+     */
+    if ((options & INVOKE_SINGLE_THREADED) == 0) {
+        LOGV("      Suspending all threads");
+        dvmSuspendAllThreads(SUSPEND_FOR_DEBUG_EVENT);
+        LOGV("      Resuming event thread to balance the count");
+        dvmResumeThread(targetThread);
+    }
+
+    /*
+     * Set up the result.
+     */
+    *pResultTag = targetThread->invokeReq.resultTag;
+    if (isTagPrimitive(targetThread->invokeReq.resultTag))
+        *pResultValue = targetThread->invokeReq.resultValue.j;
+    else {
+        Object* tmpObj = (Object*)targetThread->invokeReq.resultValue.l;
+        *pResultValue = objectToObjectId(tmpObj);
+    }
+    *pExceptObj = targetThread->invokeReq.exceptObj;
+    return targetThread->invokeReq.err;
+}
+
+/*
+ * Return a basic tag value for the return type.
+ */
+static u1 getReturnTypeBasicTag(const Method* method)
+{
+    const char* descriptor = dexProtoGetReturnType(&method->prototype);
+    return basicTagFromDescriptor(descriptor);
+}
+
+/*
+ * Execute the method described by "*pReq".
+ *
+ * We're currently in VMWAIT, because we're stopped on a breakpoint.  We
+ * want to switch to RUNNING while we execute.
+ */
+void dvmDbgExecuteMethod(DebugInvokeReq* pReq)
+{
+    Thread* self = dvmThreadSelf();
+    const Method* meth;
+    Object* oldExcept;
+    ThreadStatus oldStatus;
+
+    /*
+     * We can be called while an exception is pending in the VM.  We need
+     * to preserve that across the method invocation.
+     */
+    oldExcept = dvmGetException(self);
+    if (oldExcept != NULL) {
+        dvmAddTrackedAlloc(oldExcept, self);
+        dvmClearException(self);
+    }
+
+    oldStatus = dvmChangeStatus(self, THREAD_RUNNING);
+
+    /*
+     * Translate the method through the vtable, unless we're calling a
+     * direct method or the debugger wants to suppress it.
+     */
+    if ((pReq->options & INVOKE_NONVIRTUAL) != 0 || pReq->obj == NULL ||
+        dvmIsDirectMethod(pReq->method))
+    {
+        meth = pReq->method;
+    } else {
+        meth = dvmGetVirtualizedMethod(pReq->clazz, pReq->method);
+    }
+    assert(meth != NULL);
+
+    assert(sizeof(jvalue) == sizeof(u8));
+
+    IF_LOGV() {
+        char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+        LOGV("JDWP invoking method %p/%p %s.%s:%s",
+            pReq->method, meth, meth->clazz->descriptor, meth->name, desc);
+        free(desc);
+    }
+
+    dvmCallMethodA(self, meth, pReq->obj, false, &pReq->resultValue,
+        (jvalue*)pReq->argArray);
+    pReq->exceptObj = objectToObjectId(dvmGetException(self));
+    pReq->resultTag = getReturnTypeBasicTag(meth);
+    if (pReq->exceptObj != 0) {
+        Object* exc = dvmGetException(self);
+        LOGD("  JDWP invocation returning with exceptObj=%p (%s)",
+            exc, exc->clazz->descriptor);
+        //dvmLogExceptionStackTrace();
+        dvmClearException(self);
+        /*
+         * Nothing should try to use this, but it looks like something is.
+         * Make it null to be safe.
+         */
+        pReq->resultValue.j = 0; /*0xadadadad;*/
+    } else if (pReq->resultTag == JT_OBJECT) {
+        /* if no exception thrown, examine object result more closely */
+        u1 newTag = tagFromObject((Object*)pReq->resultValue.l);
+        if (newTag != pReq->resultTag) {
+            LOGVV("  JDWP promoted result from %d to %d",
+                pReq->resultTag, newTag);
+            pReq->resultTag = newTag;
+        }
+
+        /*
+         * Register the object.  We don't actually need an ObjectId yet,
+         * but we do need to be sure that the GC won't move or discard the
+         * object when we switch out of RUNNING.  The ObjectId conversion
+         * will add the object to the "do not touch" list.
+         *
+         * We can't use the "tracked allocation" mechanism here because
+         * the object is going to be handed off to a different thread.
+         */
+        objectToObjectId((Object*)pReq->resultValue.l);
+    }
+
+    if (oldExcept != NULL) {
+        dvmSetException(self, oldExcept);
+        dvmReleaseTrackedAlloc(oldExcept, self);
+    }
+    dvmChangeStatus(self, oldStatus);
+}
+
+// for dvmAddressSetForLine
+struct AddressSetContext {
+    bool lastAddressValid;
+    u4 lastAddress;
+    u4 lineNum;
+    AddressSet *pSet;
+};
+
+// for dvmAddressSetForLine
+static int addressSetCb (void *cnxt, u4 address, u4 lineNum)
+{
+    AddressSetContext *pContext = (AddressSetContext *)cnxt;
+
+    if (lineNum == pContext->lineNum) {
+        if (!pContext->lastAddressValid) {
+            // Everything from this address until the next line change is ours
+            pContext->lastAddress = address;
+            pContext->lastAddressValid = true;
+        }
+        // else, If we're already in a valid range for this lineNum,
+        // just keep going (shouldn't really happen)
+    } else if (pContext->lastAddressValid) { // and the line number is new
+        u4 i;
+        // Add everything from the last entry up until here to the set
+        for (i = pContext->lastAddress; i < address; i++) {
+            dvmAddressSetSet(pContext->pSet, i);
+        }
+
+        pContext->lastAddressValid = false;
+    }
+
+    // there may be multiple entries for a line
+    return 0;
+}
+/*
+ * Build up a set of bytecode addresses associated with a line number
+ */
+const AddressSet *dvmAddressSetForLine(const Method* method, int line)
+{
+    AddressSet *result;
+    const DexFile *pDexFile = method->clazz->pDvmDex->pDexFile;
+    u4 insnsSize = dvmGetMethodInsnsSize(method);
+    AddressSetContext context;
+
+    result = (AddressSet*)calloc(1, sizeof(AddressSet) + (insnsSize/8) + 1);
+    result->setSize = insnsSize;
+
+    memset(&context, 0, sizeof(context));
+    context.pSet = result;
+    context.lineNum = line;
+    context.lastAddressValid = false;
+
+    dexDecodeDebugInfo(pDexFile, dvmGetMethodCode(method),
+        method->clazz->descriptor,
+        method->prototype.protoIdx,
+        method->accessFlags,
+        addressSetCb, NULL, &context);
+
+    // If the line number was the last in the position table...
+    if (context.lastAddressValid) {
+        u4 i;
+        for (i = context.lastAddress; i < insnsSize; i++) {
+            dvmAddressSetSet(result, i);
+        }
+    }
+
+    return result;
+}
+
+
+/*
+ * ===========================================================================
+ *      Dalvik Debug Monitor support
+ * ===========================================================================
+ */
+
+/*
+ * We have received a DDM packet over JDWP.  Hand it off to the VM.
+ */
+bool dvmDbgDdmHandlePacket(const u1* buf, int dataLen, u1** pReplyBuf,
+    int* pReplyLen)
+{
+    return dvmDdmHandlePacket(buf, dataLen, pReplyBuf, pReplyLen);
+}
+
+/*
+ * First DDM packet has arrived over JDWP.  Notify the press.
+ */
+void dvmDbgDdmConnected()
+{
+    dvmDdmConnected();
+}
+
+/*
+ * JDWP connection has dropped.
+ */
+void dvmDbgDdmDisconnected()
+{
+    dvmDdmDisconnected();
+}
+
+/*
+ * Send up a JDWP event packet with a DDM chunk in it.
+ */
+void dvmDbgDdmSendChunk(int type, size_t len, const u1* buf)
+{
+    assert(buf != NULL);
+    struct iovec vec[1] = { {(void*)buf, len} };
+    dvmDbgDdmSendChunkV(type, vec, 1);
+}
+
+/*
+ * Send up a JDWP event packet with a DDM chunk in it.  The chunk is
+ * concatenated from multiple source buffers.
+ */
+void dvmDbgDdmSendChunkV(int type, const struct iovec* iov, int iovcnt)
+{
+    if (gDvm.jdwpState == NULL) {
+        LOGV("Debugger thread not active, ignoring DDM send (t=0x%08x)",
+            type);
+        return;
+    }
+
+    dvmJdwpDdmSendChunkV(gDvm.jdwpState, type, iov, iovcnt);
+}
diff --git a/vm/Debugger.h b/vm/Debugger.h
new file mode 100644
index 0000000..760463e
--- /dev/null
+++ b/vm/Debugger.h
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik-specific side of debugger support.  (The JDWP code is intended to
+ * be relatively generic.)
+ */
+#ifndef DALVIK_DEBUGGER_H_
+#define DALVIK_DEBUGGER_H_
+
+#include <pthread.h>
+#include "Common.h"
+#include "Misc.h"
+#include "jdwp/Jdwp.h"
+
+/* fwd decl */
+struct Object;
+struct ClassObject;
+struct Method;
+struct Thread;
+
+/*
+ * Used by StepControl to track a set of addresses associated with
+ * a single line.
+ */
+struct AddressSet {
+    u4 setSize;
+    u1 set[1];
+};
+
+INLINE void dvmAddressSetSet(AddressSet *pSet, u4 toSet)
+{
+    if (toSet < pSet->setSize) {
+        pSet->set[toSet/8] |= 1 << (toSet % 8);
+    }
+}
+
+INLINE bool dvmAddressSetGet(const AddressSet *pSet, u4 toGet)
+{
+    if (toGet < pSet->setSize) {
+        return (pSet->set[toGet/8] & (1 << (toGet % 8))) != 0;
+    } else {
+        return false;
+    }
+}
+
+/*
+ * Single-step management.
+ */
+struct StepControl {
+    /* request */
+    JdwpStepSize size;
+    JdwpStepDepth depth;
+    Thread* thread;         /* don't deref; for comparison only */
+
+    /* current state */
+    bool active;
+    const Method* method;
+    int line;           /* line #; could be -1 */
+    const AddressSet* pAddressSet;    /* if non-null, address set for line */
+    int frameDepth;
+};
+
+/*
+ * Invoke-during-breakpoint support.
+ */
+struct DebugInvokeReq {
+    /* boolean; only set when we're in the tail end of an event handler */
+    bool ready;
+
+    /* boolean; set if the JDWP thread wants this thread to do work */
+    bool invokeNeeded;
+
+    /* request */
+    Object* obj;        /* not used for ClassType.InvokeMethod */
+    Object* thread;
+    ClassObject* clazz;
+    Method* method;
+    u4 numArgs;
+    u8* argArray;   /* will be NULL if numArgs==0 */
+    u4 options;
+
+    /* result */
+    JdwpError err;
+    u1 resultTag;
+    JValue resultValue;
+    ObjectId exceptObj;
+
+    /* condition variable to wait on while the method executes */
+    pthread_mutex_t lock;
+    pthread_cond_t cv;
+};
+
+/* system init/shutdown */
+bool dvmDebuggerStartup(void);
+void dvmDebuggerShutdown(void);
+
+void dvmDbgInitMutex(pthread_mutex_t* pMutex);
+void dvmDbgLockMutex(pthread_mutex_t* pMutex);
+void dvmDbgUnlockMutex(pthread_mutex_t* pMutex);
+void dvmDbgInitCond(pthread_cond_t* pCond);
+void dvmDbgCondWait(pthread_cond_t* pCond, pthread_mutex_t* pMutex);
+void dvmDbgCondSignal(pthread_cond_t* pCond);
+void dvmDbgCondBroadcast(pthread_cond_t* pCond);
+
+/*
+ * Return the DebugInvokeReq for the current thread.
+ */
+DebugInvokeReq* dvmDbgGetInvokeReq(void);
+
+/*
+ * Enable/disable breakpoints and step modes.  Used to provide a heads-up
+ * when the debugger attaches.
+ */
+void dvmDbgConnected(void);
+void dvmDbgActive(void);
+void dvmDbgDisconnected(void);
+
+/*
+ * Returns "true" if a debugger is connected.  Returns "false" if it's
+ * just DDM.
+ */
+bool dvmDbgIsDebuggerConnected(void);
+
+/*
+ * Time, in milliseconds, since the last debugger activity.  Does not
+ * include DDMS activity.  Returns -1 if there has been no activity.
+ * Returns 0 if we're in the middle of handling a debugger request.
+ */
+s8 dvmDbgLastDebuggerActivity(void);
+
+/*
+ * Block/allow GC depending on what we're doing.  These return the old
+ * status, which can be fed to dvmDbgThreadGoing() to restore the previous
+ * mode.
+ */
+int dvmDbgThreadRunning(void);
+int dvmDbgThreadWaiting(void);
+int dvmDbgThreadContinuing(int status);
+
+/*
+ * The debugger wants the VM to exit.
+ */
+void dvmDbgExit(int status);
+
+/*
+ * Class, Object, Array
+ */
+const char* dvmDbgGetClassDescriptor(RefTypeId id);
+ObjectId dvmDbgGetClassObject(RefTypeId id);
+RefTypeId dvmDbgGetSuperclass(RefTypeId id);
+ObjectId dvmDbgGetClassLoader(RefTypeId id);
+u4 dvmDbgGetAccessFlags(RefTypeId id);
+bool dvmDbgIsInterface(RefTypeId id);
+void dvmDbgGetClassList(u4* pNumClasses, RefTypeId** pClassRefBuf);
+void dvmDbgGetVisibleClassList(ObjectId classLoaderId, u4* pNumClasses,
+        RefTypeId** pClassRefBuf);
+void dvmDbgGetClassInfo(RefTypeId classId, u1* pTypeTag, u4* pStatus,
+    const char** pSignature);
+bool dvmDbgFindLoadedClassBySignature(const char* classDescriptor,
+        RefTypeId* pRefTypeId);
+void dvmDbgGetObjectType(ObjectId objectId, u1* pRefTypeTag,
+    RefTypeId* pRefTypeId);
+u1 dvmDbgGetClassObjectType(RefTypeId refTypeId);
+const char* dvmDbgGetSignature(RefTypeId refTypeId);
+const char* dvmDbgGetSourceFile(RefTypeId refTypeId);
+const char* dvmDbgGetObjectTypeName(ObjectId objectId);
+u1 dvmDbgGetObjectTag(ObjectId objectId);
+int dvmDbgGetTagWidth(int tag);
+
+int dvmDbgGetArrayLength(ObjectId arrayId);
+u1 dvmDbgGetArrayElementTag(ObjectId arrayId);
+bool dvmDbgOutputArray(ObjectId arrayId, int firstIndex, int count,
+    ExpandBuf* pReply);
+bool dvmDbgSetArrayElements(ObjectId arrayId, int firstIndex, int count,
+    const u1* buf);
+
+ObjectId dvmDbgCreateString(const char* str);
+ObjectId dvmDbgCreateObject(RefTypeId classId);
+ObjectId dvmDbgCreateArrayObject(RefTypeId arrayTypeId, u4 length);
+
+bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId);
+
+/*
+ * Method and Field
+ */
+const char* dvmDbgGetMethodName(RefTypeId refTypeId, MethodId id);
+void dvmDbgOutputAllFields(RefTypeId refTypeId, bool withGeneric,
+    ExpandBuf* pReply);
+void dvmDbgOutputAllMethods(RefTypeId refTypeId, bool withGeneric,
+    ExpandBuf* pReply);
+void dvmDbgOutputAllInterfaces(RefTypeId refTypeId, ExpandBuf* pReply);
+void dvmDbgOutputLineTable(RefTypeId refTypeId, MethodId methodId,
+    ExpandBuf* pReply);
+void dvmDbgOutputVariableTable(RefTypeId refTypeId, MethodId id,
+    bool withGeneric, ExpandBuf* pReply);
+
+u1 dvmDbgGetFieldBasicTag(ObjectId objId, FieldId fieldId);
+u1 dvmDbgGetStaticFieldBasicTag(RefTypeId refTypeId, FieldId fieldId);
+void dvmDbgGetFieldValue(ObjectId objectId, FieldId fieldId, ExpandBuf* pReply);
+void dvmDbgSetFieldValue(ObjectId objectId, FieldId fieldId, u8 value,
+    int width);
+void dvmDbgGetStaticFieldValue(RefTypeId refTypeId, FieldId fieldId,
+    ExpandBuf* pReply);
+void dvmDbgSetStaticFieldValue(RefTypeId refTypeId, FieldId fieldId,
+    u8 rawValue, int width);
+
+char* dvmDbgStringToUtf8(ObjectId strId);
+
+/*
+ * Thread, ThreadGroup, Frame
+ */
+char* dvmDbgGetThreadName(ObjectId threadId);
+ObjectId dvmDbgGetThreadGroup(ObjectId threadId);
+char* dvmDbgGetThreadGroupName(ObjectId threadGroupId);
+ObjectId dvmDbgGetThreadGroupParent(ObjectId threadGroupId);
+ObjectId dvmDbgGetSystemThreadGroupId(void);
+ObjectId dvmDbgGetMainThreadGroupId(void);
+
+bool dvmDbgGetThreadStatus(ObjectId threadId, u4* threadStatus,
+    u4* suspendStatus);
+u4 dvmDbgGetThreadSuspendCount(ObjectId threadId);
+bool dvmDbgThreadExists(ObjectId threadId);
+bool dvmDbgIsSuspended(ObjectId threadId);
+//void dvmDbgWaitForSuspend(ObjectId threadId);
+void dvmDbgGetThreadGroupThreads(ObjectId threadGroupId,
+    ObjectId** ppThreadIds, u4* pThreadCount);
+void dvmDbgGetAllThreads(ObjectId** ppThreadIds, u4* pThreadCount);
+int dvmDbgGetThreadFrameCount(ObjectId threadId);
+bool dvmDbgGetThreadFrame(ObjectId threadId, int num, FrameId* pFrameId,
+    JdwpLocation* pLoc);
+
+ObjectId dvmDbgGetThreadSelfId(void);
+void dvmDbgSuspendVM(bool isEvent);
+void dvmDbgResumeVM(void);
+void dvmDbgSuspendThread(ObjectId threadId);
+void dvmDbgResumeThread(ObjectId threadId);
+void dvmDbgSuspendSelf(void);
+
+bool dvmDbgGetThisObject(ObjectId threadId, FrameId frameId, ObjectId* pThisId);
+void dvmDbgGetLocalValue(ObjectId threadId, FrameId frameId, int slot,
+    u1 tag, u1* buf, int expectedLen);
+void dvmDbgSetLocalValue(ObjectId threadId, FrameId frameId, int slot,
+    u1 tag, u8 value, int width);
+
+
+/*
+ * Debugger notification
+ */
+void dvmDbgPostLocationEvent(const Method* method, int pcOffset,
+    Object* thisPtr, int eventFlags);
+void dvmDbgPostException(void* throwFp, int throwRelPc, void* catchFp,
+    int catchRelPc, Object* exception);
+void dvmDbgPostThreadStart(Thread* thread);
+void dvmDbgPostThreadDeath(Thread* thread);
+void dvmDbgPostClassPrepare(ClassObject* clazz);
+
+/* for "eventFlags" */
+enum {
+    DBG_BREAKPOINT      = 0x01,
+    DBG_SINGLE_STEP     = 0x02,
+    DBG_METHOD_ENTRY    = 0x04,
+    DBG_METHOD_EXIT     = 0x08,
+};
+
+bool dvmDbgWatchLocation(const JdwpLocation* pLoc);
+void dvmDbgUnwatchLocation(const JdwpLocation* pLoc);
+bool dvmDbgConfigureStep(ObjectId threadId, JdwpStepSize size,
+    JdwpStepDepth depth);
+void dvmDbgUnconfigureStep(ObjectId threadId);
+
+JdwpError dvmDbgInvokeMethod(ObjectId threadId, ObjectId objectId,
+    RefTypeId classId, MethodId methodId, u4 numArgs, u8* argArray,
+    u4 options, u1* pResultTag, u8* pResultValue, ObjectId* pExceptObj);
+void dvmDbgExecuteMethod(DebugInvokeReq* pReq);
+
+/* Make an AddressSet for a line, for single stepping */
+const AddressSet *dvmAddressSetForLine(const Method* method, int line);
+
+/* perform "late registration" of an object ID */
+void dvmDbgRegisterObjectId(ObjectId id);
+
+/*
+ * DDM support.
+ */
+bool dvmDbgDdmHandlePacket(const u1* buf, int dataLen, u1** pReplyBuf,
+    int* pReplyLen);
+void dvmDbgDdmConnected(void);
+void dvmDbgDdmDisconnected(void);
+void dvmDbgDdmSendChunk(int type, size_t len, const u1* buf);
+void dvmDbgDdmSendChunkV(int type, const struct iovec* iov, int iovcnt);
+
+#define CHUNK_TYPE(_name) \
+    ((_name)[0] << 24 | (_name)[1] << 16 | (_name)[2] << 8 | (_name)[3])
+
+#endif  // DALVIK_DEBUGGER_H_
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
new file mode 100644
index 0000000..4aa054d
--- /dev/null
+++ b/vm/Dvm.mk
@@ -0,0 +1,310 @@
+# 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 definitions for host or target builds of libdvm.
+#
+# If you enable or disable optional features here, make sure you do
+# a "clean" build -- not everything depends on Dalvik.h.  (See Android.mk
+# for the exact command.)
+#
+
+
+#
+# Compiler defines.
+#
+LOCAL_CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2 -fno-align-jumps
+LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter
+LOCAL_CFLAGS += -DARCH_VARIANT=\"$(dvm_arch_variant)\"
+
+#
+# Optional features.  These may impact the size or performance of the VM.
+#
+
+# Make a debugging version when building the simulator (if not told
+# otherwise) and when explicitly asked.
+dvm_make_debug_vm := false
+ifneq ($(strip $(DEBUG_DALVIK_VM)),)
+  dvm_make_debug_vm := $(DEBUG_DALVIK_VM)
+endif
+
+ifeq ($(dvm_make_debug_vm),true)
+  #
+  # "Debug" profile:
+  # - debugger enabled
+  # - profiling enabled
+  # - tracked-reference verification enabled
+  # - allocation limits enabled
+  # - GDB helpers enabled
+  # - LOGV
+  # - assert()
+  #
+  LOCAL_CFLAGS += -DWITH_INSTR_CHECKS
+  LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION
+  LOCAL_CFLAGS += -DWITH_TRACKREF_CHECKS
+  LOCAL_CFLAGS += -DWITH_EXTRA_GC_CHECKS=1
+  #LOCAL_CFLAGS += -DCHECK_MUTEX
+  LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=3
+  # add some extra stuff to make it easier to examine with GDB
+  LOCAL_CFLAGS += -DEASY_GDB
+  # overall config may be for a "release" build, so reconfigure these
+  LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
+else  # !dvm_make_debug_vm
+  #
+  # "Performance" profile:
+  # - all development features disabled
+  # - compiler optimizations enabled (redundant for "release" builds)
+  # - (debugging and profiling still enabled)
+  #
+  #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 += -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
+endif  # !dvm_make_debug_vm
+
+# bug hunting: checksum and verify interpreted stack when making JNI calls
+#LOCAL_CFLAGS += -DWITH_JNI_STACK_CHECK
+
+LOCAL_SRC_FILES := \
+	AllocTracker.cpp \
+	Atomic.cpp.arm \
+	AtomicCache.cpp \
+	BitVector.cpp.arm \
+	CheckJni.cpp \
+	Ddm.cpp \
+	Debugger.cpp \
+	DvmDex.cpp \
+	Exception.cpp \
+	Hash.cpp \
+	IndirectRefTable.cpp.arm \
+	Init.cpp \
+	InitRefs.cpp \
+	InlineNative.cpp.arm \
+	Inlines.cpp \
+	Intern.cpp \
+	Jni.cpp \
+	JarFile.cpp \
+	LinearAlloc.cpp \
+	Misc.cpp \
+	Native.cpp \
+	PointerSet.cpp \
+	Profile.cpp \
+	RawDexFile.cpp \
+	ReferenceTable.cpp \
+	SignalCatcher.cpp \
+	StdioConverter.cpp \
+	Sync.cpp \
+	Thread.cpp \
+	UtfString.cpp \
+	alloc/Alloc.cpp \
+	alloc/CardTable.cpp \
+	alloc/HeapBitmap.cpp.arm \
+	alloc/HeapDebug.cpp \
+	alloc/Heap.cpp.arm \
+	alloc/DdmHeap.cpp \
+	alloc/Verify.cpp \
+	alloc/Visit.cpp \
+	analysis/CodeVerify.cpp \
+	analysis/DexPrepare.cpp \
+	analysis/DexVerify.cpp \
+	analysis/Liveness.cpp \
+	analysis/Optimize.cpp \
+	analysis/RegisterMap.cpp \
+	analysis/VerifySubs.cpp \
+	analysis/VfyBasicBlock.cpp \
+	hprof/Hprof.cpp \
+	hprof/HprofClass.cpp \
+	hprof/HprofHeap.cpp \
+	hprof/HprofOutput.cpp \
+	hprof/HprofString.cpp \
+	interp/Interp.cpp.arm \
+	interp/Stack.cpp \
+	jdwp/ExpandBuf.cpp \
+	jdwp/JdwpAdb.cpp \
+	jdwp/JdwpConstants.cpp \
+	jdwp/JdwpEvent.cpp \
+	jdwp/JdwpHandler.cpp \
+	jdwp/JdwpMain.cpp \
+	jdwp/JdwpSocket.cpp \
+	mterp/Mterp.cpp.arm \
+	mterp/out/InterpC-portable.cpp.arm \
+	native/InternalNative.cpp \
+	native/dalvik_bytecode_OpcodeInfo.cpp \
+	native/dalvik_system_DexFile.cpp \
+	native/dalvik_system_VMDebug.cpp \
+	native/dalvik_system_VMRuntime.cpp \
+	native/dalvik_system_VMStack.cpp \
+	native/dalvik_system_Zygote.cpp \
+	native/java_lang_Class.cpp \
+	native/java_lang_Double.cpp \
+	native/java_lang_Float.cpp \
+	native/java_lang_Math.cpp \
+	native/java_lang_Object.cpp \
+	native/java_lang_Runtime.cpp \
+	native/java_lang_String.cpp \
+	native/java_lang_System.cpp \
+	native/java_lang_Throwable.cpp \
+	native/java_lang_VMClassLoader.cpp \
+	native/java_lang_VMThread.cpp \
+	native/java_lang_reflect_AccessibleObject.cpp \
+	native/java_lang_reflect_Array.cpp \
+	native/java_lang_reflect_Constructor.cpp \
+	native/java_lang_reflect_Field.cpp \
+	native/java_lang_reflect_Method.cpp \
+	native/java_lang_reflect_Proxy.cpp \
+	native/java_util_concurrent_atomic_AtomicLong.cpp \
+	native/org_apache_harmony_dalvik_NativeTestTarget.cpp \
+	native/org_apache_harmony_dalvik_ddmc_DdmServer.cpp \
+	native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cpp \
+	native/sun_misc_Unsafe.cpp \
+	oo/AccessCheck.cpp \
+	oo/Array.cpp \
+	oo/Class.cpp \
+	oo/Object.cpp \
+	oo/Resolve.cpp \
+	oo/TypeCheck.cpp \
+	reflect/Annotation.cpp \
+	reflect/Proxy.cpp \
+	reflect/Reflect.cpp \
+	test/AtomicTest.cpp.arm \
+	test/TestHash.cpp \
+	test/TestIndirectRefTable.cpp
+
+# TODO: this is the wrong test, but what's the right one?
+ifeq ($(dvm_arch),arm)
+  LOCAL_SRC_FILES += os/android.cpp
+else
+  LOCAL_SRC_FILES += os/linux.cpp
+endif
+
+WITH_COPYING_GC := $(strip $(WITH_COPYING_GC))
+
+ifeq ($(WITH_COPYING_GC),true)
+  LOCAL_CFLAGS += -DWITH_COPYING_GC
+  LOCAL_SRC_FILES += \
+	alloc/Copying.cpp.arm
+else
+  LOCAL_SRC_FILES += \
+	alloc/HeapSource.cpp \
+	alloc/MarkSweep.cpp.arm
+endif
+
+WITH_JIT := $(strip $(WITH_JIT))
+
+ifeq ($(WITH_JIT),true)
+  LOCAL_CFLAGS += -DWITH_JIT
+  LOCAL_SRC_FILES += \
+	compiler/Compiler.cpp \
+	compiler/Frontend.cpp \
+	compiler/Utility.cpp \
+	compiler/InlineTransformation.cpp \
+	compiler/IntermediateRep.cpp \
+	compiler/Dataflow.cpp \
+	compiler/SSATransformation.cpp \
+	compiler/Loop.cpp \
+	compiler/Ralloc.cpp \
+	interp/Jit.cpp
+endif
+
+LOCAL_C_INCLUDES += \
+	$(JNI_H_INCLUDE) \
+	dalvik \
+	dalvik/vm \
+	external/zlib \
+	libcore/include \
+
+MTERP_ARCH_KNOWN := false
+
+ifeq ($(dvm_arch),arm)
+  #dvm_arch_variant := armv7-a
+  #LOCAL_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp
+  LOCAL_CFLAGS += -Werror
+  MTERP_ARCH_KNOWN := true
+  # Select architecture-specific sources (armv5te, armv7-a, etc.)
+  LOCAL_SRC_FILES += \
+		arch/arm/CallOldABI.S \
+		arch/arm/CallEABI.S \
+		arch/arm/HintsEABI.cpp \
+		mterp/out/InterpC-$(dvm_arch_variant).cpp.arm \
+		mterp/out/InterpAsm-$(dvm_arch_variant).S
+
+  ifeq ($(WITH_JIT),true)
+    LOCAL_SRC_FILES += \
+		compiler/codegen/RallocUtil.cpp \
+		compiler/codegen/arm/$(dvm_arch_variant)/Codegen.cpp \
+		compiler/codegen/arm/$(dvm_arch_variant)/CallingConvention.S \
+		compiler/codegen/arm/Assemble.cpp \
+		compiler/codegen/arm/ArchUtility.cpp \
+		compiler/codegen/arm/LocalOptimizations.cpp \
+		compiler/codegen/arm/GlobalOptimizations.cpp \
+		compiler/codegen/arm/ArmRallocUtil.cpp \
+		compiler/template/out/CompilerTemplateAsm-$(dvm_arch_variant).S
+  endif
+endif
+
+ifeq ($(dvm_arch),x86)
+  ifeq ($(dvm_os),linux)
+    MTERP_ARCH_KNOWN := true
+    LOCAL_CFLAGS += -DDVM_JMP_TABLE_MTERP=1
+    LOCAL_SRC_FILES += \
+		arch/$(dvm_arch_variant)/Call386ABI.S \
+		arch/$(dvm_arch_variant)/Hints386ABI.cpp \
+		mterp/out/InterpC-$(dvm_arch_variant).cpp \
+		mterp/out/InterpAsm-$(dvm_arch_variant).S
+    ifeq ($(WITH_JIT),true)
+      LOCAL_SRC_FILES += \
+		compiler/codegen/x86/Assemble.cpp \
+		compiler/codegen/x86/ArchUtility.cpp \
+		compiler/codegen/x86/ia32/Codegen.cpp \
+		compiler/codegen/x86/ia32/CallingConvention.S \
+		compiler/template/out/CompilerTemplateAsm-ia32.S
+    endif
+  endif
+endif
+
+ifeq ($(dvm_arch),sh)
+  MTERP_ARCH_KNOWN := true
+  LOCAL_SRC_FILES += \
+		arch/sh/CallSH4ABI.S \
+		arch/generic/Hints.cpp \
+		mterp/out/InterpC-allstubs.cpp \
+		mterp/out/InterpAsm-allstubs.S
+endif
+
+ifeq ($(MTERP_ARCH_KNOWN),false)
+  # unknown architecture, try to use FFI
+  LOCAL_C_INCLUDES += external/libffi/$(dvm_os)-$(dvm_arch)
+
+  ifeq ($(dvm_os)-$(dvm_arch),darwin-x86)
+      # OSX includes libffi, so just make the linker aware of it directly.
+      LOCAL_LDLIBS += -lffi
+  else
+      LOCAL_SHARED_LIBRARIES += libffi
+  endif
+
+  LOCAL_SRC_FILES += \
+		arch/generic/Call.cpp \
+		arch/generic/Hints.cpp \
+		mterp/out/InterpC-allstubs.cpp
+
+  # The following symbols are usually defined in the asm file, but
+  # since we don't have an asm file in this case, we instead just
+  # peg them at 0 here, and we add an #ifdef'able define for good
+  # measure, too.
+  LOCAL_CFLAGS += -DdvmAsmInstructionStart=0 -DdvmAsmInstructionEnd=0 \
+	-DdvmAsmSisterStart=0 -DdvmAsmSisterEnd=0 -DDVM_NO_ASM_INTERP=1
+endif
diff --git a/vm/DvmDex.cpp b/vm/DvmDex.cpp
new file mode 100644
index 0000000..aa78c7a
--- /dev/null
+++ b/vm/DvmDex.cpp
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+/*
+ * VM-specific state associated with a DEX file.
+ */
+#include "Dalvik.h"
+
+
+/*
+ * Create auxillary data structures.
+ *
+ * We need a 4-byte pointer for every reference to a class, method, field,
+ * or string constant.  Summed up over all loaded DEX files (including the
+ * whoppers in the boostrap class path), this adds up to be quite a bit
+ * of native memory.
+ *
+ * For more traditional VMs these values could be stuffed into the loaded
+ * class file constant pool area, but we don't have that luxury since our
+ * classes are memory-mapped read-only.
+ *
+ * The DEX optimizer will remove the need for some of these (e.g. we won't
+ * use the entry for virtual methods that are only called through
+ * invoke-virtual-quick), creating the possibility of some space reduction
+ * at dexopt time.
+ */
+static DvmDex* allocateAuxStructures(DexFile* pDexFile)
+{
+    DvmDex* pDvmDex;
+    const DexHeader* pHeader;
+    u4 stringCount, classCount, methodCount, fieldCount;
+
+    pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
+    if (pDvmDex == NULL)
+        return NULL;
+
+    pDvmDex->pDexFile = pDexFile;
+    pDvmDex->pHeader = pDexFile->pHeader;
+
+    pHeader = pDvmDex->pHeader;
+
+    stringCount = pHeader->stringIdsSize;
+    classCount = pHeader->typeIdsSize;
+    methodCount = pHeader->methodIdsSize;
+    fieldCount = pHeader->fieldIdsSize;
+
+    pDvmDex->pResStrings = (struct StringObject**)
+        calloc(stringCount, sizeof(struct StringObject*));
+
+    pDvmDex->pResClasses = (struct ClassObject**)
+        calloc(classCount, sizeof(struct ClassObject*));
+
+    pDvmDex->pResMethods = (struct Method**)
+        calloc(methodCount, sizeof(struct Method*));
+
+    pDvmDex->pResFields = (struct Field**)
+        calloc(fieldCount, sizeof(struct Field*));
+
+    LOGV("+++ DEX %p: allocateAux %d+%d+%d+%d * 4 = %d bytes",
+        pDvmDex, stringCount, classCount, methodCount, fieldCount,
+        (stringCount + classCount + methodCount + fieldCount) * 4);
+
+    pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
+
+    if (pDvmDex->pResStrings == NULL ||
+        pDvmDex->pResClasses == NULL ||
+        pDvmDex->pResMethods == NULL ||
+        pDvmDex->pResFields == NULL ||
+        pDvmDex->pInterfaceCache == NULL)
+    {
+        LOGE("Alloc failure in allocateAuxStructures");
+        free(pDvmDex->pResStrings);
+        free(pDvmDex->pResClasses);
+        free(pDvmDex->pResMethods);
+        free(pDvmDex->pResFields);
+        free(pDvmDex);
+        return NULL;
+    }
+
+    return pDvmDex;
+
+}
+
+/*
+ * Given an open optimized DEX file, map it into read-only shared memory and
+ * parse the contents.
+ *
+ * Returns nonzero on error.
+ */
+int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)
+{
+    DvmDex* pDvmDex;
+    DexFile* pDexFile;
+    MemMapping memMap;
+    int parseFlags = kDexParseDefault;
+    int result = -1;
+
+    if (gDvm.verifyDexChecksum)
+        parseFlags |= kDexParseVerifyChecksum;
+
+    if (lseek(fd, 0, SEEK_SET) < 0) {
+        LOGE("lseek rewind failed");
+        goto bail;
+    }
+
+    if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {
+        LOGE("Unable to map file");
+        goto bail;
+    }
+
+    pDexFile = dexFileParse((u1*)memMap.addr, memMap.length, parseFlags);
+    if (pDexFile == NULL) {
+        LOGE("DEX parse failed");
+        sysReleaseShmem(&memMap);
+        goto bail;
+    }
+
+    pDvmDex = allocateAuxStructures(pDexFile);
+    if (pDvmDex == NULL) {
+        dexFileFree(pDexFile);
+        sysReleaseShmem(&memMap);
+        goto bail;
+    }
+
+    /* tuck this into the DexFile so it gets released later */
+    sysCopyMap(&pDvmDex->memMap, &memMap);
+    pDvmDex->isMappedReadOnly = true;
+    *ppDvmDex = pDvmDex;
+    result = 0;
+
+bail:
+    return result;
+}
+
+/*
+ * Create a DexFile structure for a "partial" DEX.  This is one that is in
+ * the process of being optimized.  The optimization header isn't finished
+ * and we won't have any of the auxillary data tables, so we have to do
+ * the initialization slightly differently.
+ *
+ * Returns nonzero on error.
+ */
+int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
+{
+    DvmDex* pDvmDex;
+    DexFile* pDexFile;
+    int parseFlags = kDexParseDefault;
+    int result = -1;
+
+    /* -- file is incomplete, new checksum has not yet been calculated
+    if (gDvm.verifyDexChecksum)
+        parseFlags |= kDexParseVerifyChecksum;
+    */
+
+    pDexFile = dexFileParse((u1*)addr, len, parseFlags);
+    if (pDexFile == NULL) {
+        LOGE("DEX parse failed");
+        goto bail;
+    }
+    pDvmDex = allocateAuxStructures(pDexFile);
+    if (pDvmDex == NULL) {
+        dexFileFree(pDexFile);
+        goto bail;
+    }
+
+    pDvmDex->isMappedReadOnly = false;
+    *ppDvmDex = pDvmDex;
+    result = 0;
+
+bail:
+    return result;
+}
+
+/*
+ * Free up the DexFile and any associated data structures.
+ *
+ * Note we may be called with a partially-initialized DvmDex.
+ */
+void dvmDexFileFree(DvmDex* pDvmDex)
+{
+    if (pDvmDex == NULL)
+        return;
+
+    dexFileFree(pDvmDex->pDexFile);
+
+    LOGV("+++ DEX %p: freeing aux structs", pDvmDex);
+    free(pDvmDex->pResStrings);
+    free(pDvmDex->pResClasses);
+    free(pDvmDex->pResMethods);
+    free(pDvmDex->pResFields);
+    dvmFreeAtomicCache(pDvmDex->pInterfaceCache);
+
+    sysReleaseShmem(&pDvmDex->memMap);
+    free(pDvmDex);
+}
+
+
+/*
+ * Change the byte at the specified address to a new value.  If the location
+ * already has the new value, do nothing.
+ *
+ * This requires changing the access permissions to read-write, updating
+ * the value, and then resetting the permissions.
+ *
+ * We need to ensure mutual exclusion at a page granularity to avoid a race
+ * where one threads sets read-write, another thread sets read-only, and
+ * then the first thread does a write.  Since we don't do a lot of updates,
+ * and the window is small, we just use a lock across the entire DvmDex.
+ * We're only trying to make the page state change atomic; it's up to the
+ * caller to ensure that multiple threads aren't stomping on the same
+ * location (e.g. breakpoints and verifier/optimizer changes happening
+ * simultaneously).
+ *
+ * TODO: if we're back to the original state of the page, use
+ * madvise(MADV_DONTNEED) to release the private/dirty copy.
+ *
+ * Returns "true" on success.
+ */
+bool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal)
+{
+    if (*addr == newVal) {
+        LOGV("+++ byte at %p is already 0x%02x", addr, newVal);
+        return true;
+    }
+
+    /*
+     * We're not holding this for long, so we don't bother with switching
+     * to VMWAIT.
+     */
+    dvmLockMutex(&pDvmDex->modLock);
+
+    LOGV("+++ change byte at %p from 0x%02x to 0x%02x", addr, *addr, newVal);
+    if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RW) failed");
+        /* expected on files mounted from FAT; keep going (may crash) */
+    }
+
+    *addr = newVal;
+
+    if (sysChangeMapAccess(addr, 1, false, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RO) failed");
+        /* expected on files mounted from FAT; keep going */
+    }
+
+    dvmUnlockMutex(&pDvmDex->modLock);
+
+    return true;
+}
+
+/*
+ * Change the 2-byte value at the specified address to a new value.  If the
+ * location already has the new value, do nothing.
+ *
+ * Otherwise works like dvmDexChangeDex1.
+ */
+bool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal)
+{
+    if (*addr == newVal) {
+        LOGV("+++ value at %p is already 0x%04x", addr, newVal);
+        return true;
+    }
+
+    /*
+     * We're not holding this for long, so we don't bother with switching
+     * to VMWAIT.
+     */
+    dvmLockMutex(&pDvmDex->modLock);
+
+    LOGV("+++ change 2byte at %p from 0x%04x to 0x%04x", addr, *addr, newVal);
+    if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RW) failed");
+        /* expected on files mounted from FAT; keep going (may crash) */
+    }
+
+    *addr = newVal;
+
+    if (sysChangeMapAccess(addr, 2, false, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RO) failed");
+        /* expected on files mounted from FAT; keep going */
+    }
+
+    dvmUnlockMutex(&pDvmDex->modLock);
+
+    return true;
+}
diff --git a/vm/DvmDex.h b/vm/DvmDex.h
new file mode 100644
index 0000000..b3b5960
--- /dev/null
+++ b/vm/DvmDex.h
@@ -0,0 +1,161 @@
+/*
+ * 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 VM wraps some additional data structures around the DexFile.  These
+ * are defined here.
+ */
+#ifndef DALVIK_DVMDEX_H_
+#define DALVIK_DVMDEX_H_
+
+#include "libdex/DexFile.h"
+
+/* extern */
+struct ClassObject;
+struct HashTable;
+struct InstField;
+struct Method;
+struct StringObject;
+
+
+/*
+ * Some additional VM data structures that are associated with the DEX file.
+ */
+struct DvmDex {
+    /* pointer to the DexFile we're associated with */
+    DexFile*            pDexFile;
+
+    /* clone of pDexFile->pHeader (it's used frequently enough) */
+    const DexHeader*    pHeader;
+
+    /* interned strings; parallel to "stringIds" */
+    struct StringObject** pResStrings;
+
+    /* resolved classes; parallel to "typeIds" */
+    struct ClassObject** pResClasses;
+
+    /* resolved methods; parallel to "methodIds" */
+    struct Method**     pResMethods;
+
+    /* resolved instance fields; parallel to "fieldIds" */
+    /* (this holds both InstField and StaticField) */
+    struct Field**      pResFields;
+
+    /* interface method lookup cache */
+    struct AtomicCache* pInterfaceCache;
+
+    /* shared memory region with file contents */
+    bool                isMappedReadOnly;
+    MemMapping          memMap;
+
+    /* lock ensuring mutual exclusion during updates */
+    pthread_mutex_t     modLock;
+};
+
+
+/*
+ * Given a file descriptor for an open "optimized" DEX file, map it into
+ * memory and parse the contents.
+ *
+ * On success, returns 0 and sets "*ppDvmDex" to a newly-allocated DvmDex.
+ * On failure, returns a meaningful error code [currently just -1].
+ */
+int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex);
+
+/*
+ * Open a partial DEX file.  Only useful as part of the optimization process.
+ */
+int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex);
+
+/*
+ * Free a DvmDex structure, along with any associated structures.
+ */
+void dvmDexFileFree(DvmDex* pDvmDex);
+
+
+/*
+ * Change the 1- or 2-byte value at the specified address to a new value.  If
+ * the location already has the new value, do nothing.
+ *
+ * This does not make any synchronization guarantees.  The caller must
+ * ensure exclusivity vs. other callers.
+ *
+ * For the 2-byte call, the pointer should have 16-bit alignment.
+ *
+ * Returns "true" on success.
+ */
+bool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal);
+bool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal);
+
+
+/*
+ * Return the requested item if it has been resolved, or NULL if it hasn't.
+ */
+INLINE struct StringObject* dvmDexGetResolvedString(const DvmDex* pDvmDex,
+    u4 stringIdx)
+{
+    assert(stringIdx < pDvmDex->pHeader->stringIdsSize);
+    return pDvmDex->pResStrings[stringIdx];
+}
+INLINE struct ClassObject* dvmDexGetResolvedClass(const DvmDex* pDvmDex,
+    u4 classIdx)
+{
+    assert(classIdx < pDvmDex->pHeader->typeIdsSize);
+    return pDvmDex->pResClasses[classIdx];
+}
+INLINE struct Method* dvmDexGetResolvedMethod(const DvmDex* pDvmDex,
+    u4 methodIdx)
+{
+    assert(methodIdx < pDvmDex->pHeader->methodIdsSize);
+    return pDvmDex->pResMethods[methodIdx];
+}
+INLINE struct Field* dvmDexGetResolvedField(const DvmDex* pDvmDex,
+    u4 fieldIdx)
+{
+    assert(fieldIdx < pDvmDex->pHeader->fieldIdsSize);
+    return pDvmDex->pResFields[fieldIdx];
+}
+
+/*
+ * Update the resolved item table.  Resolution always produces the same
+ * result, so we're not worried about atomicity here.
+ */
+INLINE void dvmDexSetResolvedString(DvmDex* pDvmDex, u4 stringIdx,
+    struct StringObject* str)
+{
+    assert(stringIdx < pDvmDex->pHeader->stringIdsSize);
+    pDvmDex->pResStrings[stringIdx] = str;
+}
+INLINE void dvmDexSetResolvedClass(DvmDex* pDvmDex, u4 classIdx,
+    struct ClassObject* clazz)
+{
+    assert(classIdx < pDvmDex->pHeader->typeIdsSize);
+    pDvmDex->pResClasses[classIdx] = clazz;
+}
+INLINE void dvmDexSetResolvedMethod(DvmDex* pDvmDex, u4 methodIdx,
+    struct Method* method)
+{
+    assert(methodIdx < pDvmDex->pHeader->methodIdsSize);
+    pDvmDex->pResMethods[methodIdx] = method;
+}
+INLINE void dvmDexSetResolvedField(DvmDex* pDvmDex, u4 fieldIdx,
+    struct Field* field)
+{
+    assert(fieldIdx < pDvmDex->pHeader->fieldIdsSize);
+    pDvmDex->pResFields[fieldIdx] = field;
+}
+
+#endif  // DALVIK_DVMDEX_H_
diff --git a/vm/Exception.cpp b/vm/Exception.cpp
new file mode 100644
index 0000000..5af48ba
--- /dev/null
+++ b/vm/Exception.cpp
@@ -0,0 +1,1443 @@
+/*
+ * 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.
+ */
+/*
+ * Exception handling.
+ */
+#include "Dalvik.h"
+#include "libdex/DexCatch.h"
+
+#include <stdlib.h>
+
+/*
+Notes on Exception Handling
+
+We have one fairly sticky issue to deal with: creating the exception stack
+trace.  The trouble is that we need the current value of the program
+counter for the method now being executed, but that's only held in a local
+variable or hardware register in the main interpreter loop.
+
+The exception mechanism requires that the current stack trace be associated
+with a Throwable at the time the Throwable is constructed.  The construction
+may or may not be associated with a throw.  We have three situations to
+consider:
+
+ (1) A Throwable is created with a "new Throwable" statement in the
+     application code, for immediate or deferred use with a "throw" statement.
+ (2) The VM throws an exception from within the interpreter core, e.g.
+     after an integer divide-by-zero.
+ (3) The VM throws an exception from somewhere deeper down, e.g. while
+     trying to link a class.
+
+We need to have the current value for the PC, which means that for
+situation (3) the interpreter loop must copy it to an externally-accessible
+location before handling any opcode that could cause the VM to throw
+an exception.  We can't store it globally, because the various threads
+would trample each other.  We can't store it in the Thread structure,
+because it'll get overwritten as soon as the Throwable constructor starts
+executing.  It needs to go on the stack, but our stack frames hold the
+caller's *saved* PC, not the current PC.
+
+Situation #1 doesn't require special handling.  Situation #2 could be dealt
+with by passing the PC into the exception creation function.  The trick
+is to solve situation #3 in a way that adds minimal overhead to common
+operations.  Making it more costly to throw an exception is acceptable.
+
+There are a few ways to deal with this:
+
+ (a) Change "savedPc" to "currentPc" in the stack frame.  All of the
+     stack logic gets offset by one frame.  The current PC is written
+     to the current stack frame when necessary.
+ (b) Write the current PC into the current stack frame, but without
+     replacing "savedPc".  The JNI local refs pointer, which is only
+     used for native code, can be overloaded to save space.
+ (c) In dvmThrowException(), push an extra stack frame on, with the
+     current PC in it.  The current PC is written into the Thread struct
+     when necessary, and copied out when the VM throws.
+ (d) Before doing something that might throw an exception, push a
+     temporary frame on with the saved PC in it.
+
+Solution (a) is the simplest, but breaks Dalvik's goal of mingling native
+and interpreted stacks.
+
+Solution (b) retains the simplicity of (a) without rearranging the stack,
+but now in some cases we're storing the PC twice, which feels wrong.
+
+Solution (c) usually works, because we push the saved PC onto the stack
+before the Throwable construction can overwrite the copy in Thread.  One
+way solution (c) could break is:
+ - Interpreter saves the PC
+ - Execute some bytecode, which runs successfully (and alters the saved PC)
+ - Throw an exception before re-saving the PC (i.e in the same opcode)
+This is a risk for anything that could cause <clinit> to execute, e.g.
+executing a static method or accessing a static field.  Attemping to access
+a field that doesn't exist in a class that does exist might cause this.
+It may be possible to simply bracket the dvmCallMethod*() functions to
+save/restore it.
+
+Solution (d) incurs additional overhead, but may have other benefits (e.g.
+it's easy to find the stack frames that should be removed before storage
+in the Throwable).
+
+Current plan is option (b), because it's simple, fast, and doesn't change
+the way the stack works.
+*/
+
+/* fwd */
+static bool initException(Object* exception, const char* msg, Object* cause,
+    Thread* self);
+
+void dvmThrowExceptionFmtV(ClassObject* exceptionClass,
+    const char* fmt, va_list args)
+{
+    char msgBuf[512];
+
+    vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
+    dvmThrowChainedException(exceptionClass, msgBuf, NULL);
+}
+
+void dvmThrowChainedException(ClassObject* excepClass, const char* msg,
+    Object* cause)
+{
+    Thread* self = dvmThreadSelf();
+    Object* exception;
+
+    if (excepClass == NULL) {
+        /*
+         * The exception class was passed in as NULL. This might happen
+         * early on in VM initialization. There's nothing better to do
+         * than just log the message as an error and abort.
+         */
+        LOGE("Fatal error: %s", msg);
+        dvmAbort();
+    }
+
+    /* make sure the exception is initialized */
+    if (!dvmIsClassInitialized(excepClass) && !dvmInitClass(excepClass)) {
+        LOGE("ERROR: unable to initialize exception class '%s'",
+            excepClass->descriptor);
+        if (strcmp(excepClass->descriptor, "Ljava/lang/InternalError;") == 0)
+            dvmAbort();
+        dvmThrowChainedException(gDvm.exInternalError,
+            "failed to init original exception class", cause);
+        return;
+    }
+
+    exception = dvmAllocObject(excepClass, ALLOC_DEFAULT);
+    if (exception == NULL) {
+        /*
+         * We're in a lot of trouble.  We might be in the process of
+         * throwing an out-of-memory exception, in which case the
+         * pre-allocated object will have been thrown when our object alloc
+         * failed.  So long as there's an exception raised, return and
+         * allow the system to try to recover.  If not, something is broken
+         * and we need to bail out.
+         */
+        if (dvmCheckException(self))
+            goto bail;
+        LOGE("FATAL: unable to allocate exception '%s' '%s'",
+            excepClass->descriptor, msg != NULL ? msg : "(no msg)");
+        dvmAbort();
+    }
+
+    /*
+     * Init the exception.
+     */
+    if (gDvm.optimizing) {
+        /* need the exception object, but can't invoke interpreted code */
+        LOGV("Skipping init of exception %s '%s'",
+            excepClass->descriptor, msg);
+    } else {
+        assert(excepClass == exception->clazz);
+        if (!initException(exception, msg, cause, self)) {
+            /*
+             * Whoops.  If we can't initialize the exception, we can't use
+             * it.  If there's an exception already set, the constructor
+             * probably threw an OutOfMemoryError.
+             */
+            if (!dvmCheckException(self)) {
+                /*
+                 * We're required to throw something, so we just
+                 * throw the pre-constructed internal error.
+                 */
+                self->exception = gDvm.internalErrorObj;
+            }
+            goto bail;
+        }
+    }
+
+    self->exception = exception;
+
+bail:
+    dvmReleaseTrackedAlloc(exception, self);
+}
+
+void dvmThrowChainedExceptionWithClassMessage(
+    ClassObject* exceptionClass, const char* messageDescriptor,
+    Object* cause)
+{
+    char* message = dvmDescriptorToName(messageDescriptor);
+
+    dvmThrowChainedException(exceptionClass, message, cause);
+    free(message);
+}
+
+/*
+ * Find and return an exception constructor method that can take the
+ * indicated parameters, or return NULL if no such constructor exists.
+ */
+static Method* findExceptionInitMethod(ClassObject* excepClass,
+    bool hasMessage, bool hasCause)
+{
+    if (hasMessage) {
+        Method* result;
+
+        if (hasCause) {
+            result = dvmFindDirectMethodByDescriptor(
+                    excepClass, "<init>",
+                    "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+        } else {
+            result = dvmFindDirectMethodByDescriptor(
+                    excepClass, "<init>", "(Ljava/lang/String;)V");
+        }
+
+        if (result != NULL) {
+            return result;
+        }
+
+        if (hasCause) {
+            return dvmFindDirectMethodByDescriptor(
+                    excepClass, "<init>",
+                    "(Ljava/lang/Object;Ljava/lang/Throwable;)V");
+        } else {
+            return dvmFindDirectMethodByDescriptor(
+                    excepClass, "<init>", "(Ljava/lang/Object;)V");
+        }
+    } else if (hasCause) {
+        return dvmFindDirectMethodByDescriptor(
+                excepClass, "<init>", "(Ljava/lang/Throwable;)V");
+    } else {
+        return dvmFindDirectMethodByDescriptor(excepClass, "<init>", "()V");
+    }
+}
+
+/*
+ * Initialize an exception with an appropriate constructor.
+ *
+ * "exception" is the exception object to initialize.
+ * Either or both of "msg" and "cause" may be null.
+ * "self" is dvmThreadSelf(), passed in so we don't have to look it up again.
+ *
+ * If the process of initializing the exception causes another
+ * exception (e.g., OutOfMemoryError) to be thrown, return an error
+ * and leave self->exception intact.
+ */
+static bool initException(Object* exception, const char* msg, Object* cause,
+    Thread* self)
+{
+    enum {
+        kInitUnknown,
+        kInitNoarg,
+        kInitMsg,
+        kInitMsgThrow,
+        kInitThrow
+    } initKind = kInitUnknown;
+    Method* initMethod = NULL;
+    ClassObject* excepClass = exception->clazz;
+    StringObject* msgStr = NULL;
+    bool result = false;
+    bool needInitCause = false;
+
+    assert(self != NULL);
+    assert(self->exception == NULL);
+
+    /* if we have a message, create a String */
+    if (msg == NULL)
+        msgStr = NULL;
+    else {
+        msgStr = dvmCreateStringFromCstr(msg);
+        if (msgStr == NULL) {
+            LOGW("Could not allocate message string \"%s\" while "
+                    "throwing internal exception (%s)",
+                    msg, excepClass->descriptor);
+            goto bail;
+        }
+    }
+
+    if (cause != NULL) {
+        if (!dvmInstanceof(cause->clazz, gDvm.exThrowable)) {
+            LOGE("Tried to init exception with cause '%s'",
+                cause->clazz->descriptor);
+            dvmAbort();
+        }
+    }
+
+    /*
+     * The Throwable class has four public constructors:
+     *  (1) Throwable()
+     *  (2) Throwable(String message)
+     *  (3) Throwable(String message, Throwable cause)  (added in 1.4)
+     *  (4) Throwable(Throwable cause)                  (added in 1.4)
+     *
+     * The first two are part of the original design, and most exception
+     * classes should support them.  The third prototype was used by
+     * individual exceptions. e.g. ClassNotFoundException added it in 1.2.
+     * The general "cause" mechanism was added in 1.4.  Some classes,
+     * such as IllegalArgumentException, initially supported the first
+     * two, but added the second two in a later release.
+     *
+     * Exceptions may be picky about how their "cause" field is initialized.
+     * If you call ClassNotFoundException(String), it may choose to
+     * initialize its "cause" field to null.  Doing so prevents future
+     * calls to Throwable.initCause().
+     *
+     * So, if "cause" is not NULL, we need to look for a constructor that
+     * takes a throwable.  If we can't find one, we fall back on calling
+     * #1/#2 and making a separate call to initCause().  Passing a null ref
+     * for "message" into Throwable(String, Throwable) is allowed, but we
+     * prefer to use the Throwable-only version because it has different
+     * behavior.
+     *
+     * java.lang.TypeNotPresentException is a strange case -- it has #3 but
+     * not #2.  (Some might argue that the constructor is actually not #3,
+     * because it doesn't take the message string as an argument, but it
+     * has the same effect and we can work with it here.)
+     *
+     * java.lang.AssertionError is also a strange case -- it has a
+     * constructor that takes an Object, but not one that takes a String.
+     * There may be other cases like this, as well, so we generally look
+     * for an Object-taking constructor if we can't find one that takes
+     * a String.
+     */
+    if (cause == NULL) {
+        if (msgStr == NULL) {
+            initMethod = findExceptionInitMethod(excepClass, false, false);
+            initKind = kInitNoarg;
+        } else {
+            initMethod = findExceptionInitMethod(excepClass, true, false);
+            if (initMethod != NULL) {
+                initKind = kInitMsg;
+            } else {
+                /* no #2, try #3 */
+                initMethod = findExceptionInitMethod(excepClass, true, true);
+                if (initMethod != NULL) {
+                    initKind = kInitMsgThrow;
+                }
+            }
+        }
+    } else {
+        if (msgStr == NULL) {
+            initMethod = findExceptionInitMethod(excepClass, false, true);
+            if (initMethod != NULL) {
+                initKind = kInitThrow;
+            } else {
+                initMethod = findExceptionInitMethod(excepClass, false, false);
+                initKind = kInitNoarg;
+                needInitCause = true;
+            }
+        } else {
+            initMethod = findExceptionInitMethod(excepClass, true, true);
+            if (initMethod != NULL) {
+                initKind = kInitMsgThrow;
+            } else {
+                initMethod = findExceptionInitMethod(excepClass, true, false);
+                initKind = kInitMsg;
+                needInitCause = true;
+            }
+        }
+    }
+
+    if (initMethod == NULL) {
+        /*
+         * We can't find the desired constructor.  This can happen if a
+         * subclass of java/lang/Throwable doesn't define an expected
+         * constructor, e.g. it doesn't provide one that takes a string
+         * when a message has been provided.
+         */
+        LOGW("WARNING: exception class '%s' missing constructor "
+            "(msg='%s' kind=%d)",
+            excepClass->descriptor, msg, initKind);
+        assert(strcmp(excepClass->descriptor,
+                      "Ljava/lang/RuntimeException;") != 0);
+        dvmThrowChainedException(gDvm.exRuntimeException,
+            "re-throw on exception class missing constructor", NULL);
+        goto bail;
+    }
+
+    /*
+     * Call the constructor with the appropriate arguments.
+     */
+    JValue unused;
+    switch (initKind) {
+    case kInitNoarg:
+        LOGVV("+++ exc noarg (ic=%d)", needInitCause);
+        dvmCallMethod(self, initMethod, exception, &unused);
+        break;
+    case kInitMsg:
+        LOGVV("+++ exc msg (ic=%d)", needInitCause);
+        dvmCallMethod(self, initMethod, exception, &unused, msgStr);
+        break;
+    case kInitThrow:
+        LOGVV("+++ exc throw");
+        assert(!needInitCause);
+        dvmCallMethod(self, initMethod, exception, &unused, cause);
+        break;
+    case kInitMsgThrow:
+        LOGVV("+++ exc msg+throw");
+        assert(!needInitCause);
+        dvmCallMethod(self, initMethod, exception, &unused, msgStr, cause);
+        break;
+    default:
+        assert(false);
+        goto bail;
+    }
+
+    /*
+     * It's possible the constructor has thrown an exception.  If so, we
+     * return an error and let our caller deal with it.
+     */
+    if (self->exception != NULL) {
+        LOGW("Exception thrown (%s) while throwing internal exception (%s)",
+            self->exception->clazz->descriptor, exception->clazz->descriptor);
+        goto bail;
+    }
+
+    /*
+     * If this exception was caused by another exception, and we weren't
+     * able to find a cause-setting constructor, set the "cause" field
+     * with an explicit call.
+     */
+    if (needInitCause) {
+        Method* initCause;
+        initCause = dvmFindVirtualMethodHierByDescriptor(excepClass, "initCause",
+            "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+        if (initCause != NULL) {
+            dvmCallMethod(self, initCause, exception, &unused, cause);
+            if (self->exception != NULL) {
+                /* initCause() threw an exception; return an error and
+                 * let the caller deal with it.
+                 */
+                LOGW("Exception thrown (%s) during initCause() "
+                        "of internal exception (%s)",
+                        self->exception->clazz->descriptor,
+                        exception->clazz->descriptor);
+                goto bail;
+            }
+        } else {
+            LOGW("WARNING: couldn't find initCause in '%s'",
+                excepClass->descriptor);
+        }
+    }
+
+
+    result = true;
+
+bail:
+    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // NULL is ok
+    return result;
+}
+
+
+/*
+ * Clear the pending exception. This is used by the optimization and
+ * verification code, which mostly happens during runs of dexopt.
+ *
+ * This can also be called when the VM is in a "normal" state, e.g. when
+ * verifying classes that couldn't be verified at optimization time.
+ */
+void dvmClearOptException(Thread* self)
+{
+    self->exception = NULL;
+}
+
+/*
+ * Returns "true" if this is a "checked" exception, i.e. it's a subclass
+ * of Throwable (assumed) but not a subclass of RuntimeException or Error.
+ */
+bool dvmIsCheckedException(const Object* exception)
+{
+    if (dvmInstanceof(exception->clazz, gDvm.exError) ||
+        dvmInstanceof(exception->clazz, gDvm.exRuntimeException))
+    {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+/*
+ * Wrap the now-pending exception in a different exception.  This is useful
+ * for reflection stuff that wants to hand a checked exception back from a
+ * method that doesn't declare it.
+ *
+ * If something fails, an (unchecked) exception related to that failure
+ * will be pending instead.
+ */
+void dvmWrapException(const char* newExcepStr)
+{
+    Thread* self = dvmThreadSelf();
+    Object* origExcep;
+    ClassObject* iteClass;
+
+    origExcep = dvmGetException(self);
+    dvmAddTrackedAlloc(origExcep, self);    // don't let the GC free it
+
+    dvmClearException(self);                // clear before class lookup
+    iteClass = dvmFindSystemClass(newExcepStr);
+    if (iteClass != NULL) {
+        Object* iteExcep;
+        Method* initMethod;
+
+        iteExcep = dvmAllocObject(iteClass, ALLOC_DEFAULT);
+        if (iteExcep != NULL) {
+            initMethod = dvmFindDirectMethodByDescriptor(iteClass, "<init>",
+                            "(Ljava/lang/Throwable;)V");
+            if (initMethod != NULL) {
+                JValue unused;
+                dvmCallMethod(self, initMethod, iteExcep, &unused,
+                    origExcep);
+
+                /* if <init> succeeded, replace the old exception */
+                if (!dvmCheckException(self))
+                    dvmSetException(self, iteExcep);
+            }
+            dvmReleaseTrackedAlloc(iteExcep, NULL);
+
+            /* if initMethod doesn't exist, or failed... */
+            if (!dvmCheckException(self))
+                dvmSetException(self, origExcep);
+        } else {
+            /* leave OutOfMemoryError pending */
+        }
+    } else {
+        /* leave ClassNotFoundException pending */
+    }
+
+    assert(dvmCheckException(self));
+    dvmReleaseTrackedAlloc(origExcep, self);
+}
+
+/*
+ * 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.exThrowable)) {
+        LOGE("Tried to get cause from object of type '%s'",
+            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.
+ *
+ * For consistency we just invoke the Throwable printStackTrace method,
+ * which might be overridden in the exception object.
+ *
+ * Exceptions thrown during the course of printing the stack trace are
+ * ignored.
+ */
+void dvmPrintExceptionStackTrace()
+{
+    Thread* self = dvmThreadSelf();
+    Object* exception;
+    Method* printMethod;
+
+    exception = self->exception;
+    if (exception == NULL)
+        return;
+
+    dvmAddTrackedAlloc(exception, self);
+    self->exception = NULL;
+    printMethod = dvmFindVirtualMethodHierByDescriptor(exception->clazz,
+                    "printStackTrace", "()V");
+    if (printMethod != NULL) {
+        JValue unused;
+        dvmCallMethod(self, printMethod, exception, &unused);
+    } else {
+        LOGW("WARNING: could not find printStackTrace in %s",
+            exception->clazz->descriptor);
+    }
+
+    if (self->exception != NULL) {
+        LOGW("NOTE: exception thrown while printing stack trace: %s",
+            self->exception->clazz->descriptor);
+    }
+
+    self->exception = exception;
+    dvmReleaseTrackedAlloc(exception, self);
+}
+
+/*
+ * Search the method's list of exceptions for a match.
+ *
+ * Returns the offset of the catch block on success, or -1 on failure.
+ */
+static int findCatchInMethod(Thread* self, const Method* method, int relPc,
+    ClassObject* excepClass)
+{
+    /*
+     * Need to clear the exception before entry.  Otherwise, dvmResolveClass
+     * might think somebody threw an exception while it was loading a class.
+     */
+    assert(!dvmCheckException(self));
+    assert(!dvmIsNativeMethod(method));
+
+    LOGVV("findCatchInMethod %s.%s excep=%s depth=%d",
+        method->clazz->descriptor, method->name, excepClass->descriptor,
+        dvmComputeExactFrameDepth(self->interpSave.curFrame));
+
+    DvmDex* pDvmDex = method->clazz->pDvmDex;
+    const DexCode* pCode = dvmGetMethodCode(method);
+    DexCatchIterator iterator;
+
+    if (dexFindCatchHandler(&iterator, pCode, relPc)) {
+        for (;;) {
+            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+
+            if (handler == NULL) {
+                break;
+            }
+
+            if (handler->typeIdx == kDexNoIndex) {
+                /* catch-all */
+                LOGV("Match on catch-all block at 0x%02x in %s.%s for %s",
+                        relPc, method->clazz->descriptor,
+                        method->name, excepClass->descriptor);
+                return handler->address;
+            }
+
+            ClassObject* throwable =
+                dvmDexGetResolvedClass(pDvmDex, handler->typeIdx);
+            if (throwable == NULL) {
+                /*
+                 * TODO: this behaves badly if we run off the stack
+                 * while trying to throw an exception.  The problem is
+                 * that, if we're in a class loaded by a class loader,
+                 * the call to dvmResolveClass has to ask the class
+                 * loader for help resolving any previously-unresolved
+                 * classes.  If this particular class loader hasn't
+                 * resolved StackOverflowError, it will call into
+                 * interpreted code, and blow up.
+                 *
+                 * We currently replace the previous exception with
+                 * the StackOverflowError, which means they won't be
+                 * catching it *unless* they explicitly catch
+                 * StackOverflowError, in which case we'll be unable
+                 * to resolve the class referred to by the "catch"
+                 * block.
+                 *
+                 * We end up getting a huge pile of warnings if we do
+                 * a simple synthetic test, because this method gets
+                 * called on every stack frame up the tree, and it
+                 * fails every time.
+                 *
+                 * This eventually bails out, effectively becoming an
+                 * uncatchable exception, so other than the flurry of
+                 * warnings it's not really a problem.  Still, we could
+                 * probably handle this better.
+                 */
+                throwable = dvmResolveClass(method->clazz, handler->typeIdx,
+                    true);
+                if (throwable == NULL) {
+                    /*
+                     * We couldn't find the exception they wanted in
+                     * our class files (or, perhaps, the stack blew up
+                     * while we were querying a class loader). Cough
+                     * up a warning, then move on to the next entry.
+                     * Keep the exception status clear.
+                     */
+                    LOGW("Could not resolve class ref'ed in exception "
+                            "catch list (class index %d, exception %s)",
+                            handler->typeIdx,
+                            (self->exception != NULL) ?
+                            self->exception->clazz->descriptor : "(none)");
+                    dvmClearException(self);
+                    continue;
+                }
+            }
+
+            //LOGD("ADDR MATCH, check %s instanceof %s",
+            //    excepClass->descriptor, pEntry->excepClass->descriptor);
+
+            if (dvmInstanceof(excepClass, throwable)) {
+                LOGV("Match on catch block at 0x%02x in %s.%s for %s",
+                        relPc, method->clazz->descriptor,
+                        method->name, excepClass->descriptor);
+                return handler->address;
+            }
+        }
+    }
+
+    LOGV("No matching catch block at 0x%02x in %s for %s",
+        relPc, method->name, excepClass->descriptor);
+    return -1;
+}
+
+/*
+ * Find a matching "catch" block.  "pc" is the relative PC within the
+ * current method, indicating the offset from the start in 16-bit units.
+ *
+ * Returns the offset to the catch block, or -1 if we run up against a
+ * break frame without finding anything.
+ *
+ * The class resolution stuff we have to do while evaluating the "catch"
+ * blocks could cause an exception.  The caller should clear the exception
+ * before calling here and restore it after.
+ *
+ * Sets *newFrame to the frame pointer of the frame with the catch block.
+ * If "scanOnly" is false, self->interpSave.curFrame is also set to this value.
+ */
+int dvmFindCatchBlock(Thread* self, int relPc, Object* exception,
+    bool scanOnly, void** newFrame)
+{
+    u4* fp = self->interpSave.curFrame;
+    int catchAddr = -1;
+
+    assert(!dvmCheckException(self));
+
+    while (true) {
+        StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+        catchAddr = findCatchInMethod(self, saveArea->method, relPc,
+                        exception->clazz);
+        if (catchAddr >= 0)
+            break;
+
+        /*
+         * Normally we'd check for ACC_SYNCHRONIZED methods and unlock
+         * them as we unroll.  Dalvik uses what amount to generated
+         * "finally" blocks to take care of this for us.
+         */
+
+        /* output method profiling info */
+        if (!scanOnly) {
+            TRACE_METHOD_UNROLL(self, saveArea->method);
+        }
+
+        /*
+         * Move up one frame.  If the next thing up is a break frame,
+         * break out now so we're left unrolled to the last method frame.
+         * We need to point there so we can roll up the JNI local refs
+         * if this was a native method.
+         */
+        assert(saveArea->prevFrame != NULL);
+        if (dvmIsBreakFrame((u4*)saveArea->prevFrame)) {
+            if (!scanOnly)
+                break;      // bail with catchAddr == -1
+
+            /*
+             * We're scanning for the debugger.  It needs to know if this
+             * exception is going to be caught or not, and we need to figure
+             * out if it will be caught *ever* not just between the current
+             * position and the next break frame.  We can't tell what native
+             * code is going to do, so we assume it never catches exceptions.
+             *
+             * Start by finding an interpreted code frame.
+             */
+            fp = saveArea->prevFrame;           // this is the break frame
+            saveArea = SAVEAREA_FROM_FP(fp);
+            fp = saveArea->prevFrame;           // this may be a good one
+            while (fp != NULL) {
+                if (!dvmIsBreakFrame((u4*)fp)) {
+                    saveArea = SAVEAREA_FROM_FP(fp);
+                    if (!dvmIsNativeMethod(saveArea->method))
+                        break;
+                }
+
+                fp = SAVEAREA_FROM_FP(fp)->prevFrame;
+            }
+            if (fp == NULL)
+                break;      // bail with catchAddr == -1
+
+            /*
+             * Now fp points to the "good" frame.  When the interp code
+             * invoked the native code, it saved a copy of its current PC
+             * into xtra.currentPc.  Pull it out of there.
+             */
+            relPc =
+                saveArea->xtra.currentPc - SAVEAREA_FROM_FP(fp)->method->insns;
+        } else {
+            fp = saveArea->prevFrame;
+
+            /* savedPc in was-current frame goes with method in now-current */
+            relPc = saveArea->savedPc - SAVEAREA_FROM_FP(fp)->method->insns;
+        }
+    }
+
+    if (!scanOnly)
+        self->interpSave.curFrame = fp;
+
+    /*
+     * The class resolution in findCatchInMethod() could cause an exception.
+     * Clear it to be safe.
+     */
+    self->exception = NULL;
+
+    *newFrame = fp;
+    return catchAddr;
+}
+
+/*
+ * We have to carry the exception's stack trace around, but in many cases
+ * it will never be examined.  It makes sense to keep it in a compact,
+ * VM-specific object, rather than an array of Objects with strings.
+ *
+ * Pass in the thread whose stack we're interested in.  If "thread" is
+ * not self, the thread must be suspended.  This implies that the thread
+ * list lock is held, which means we can't allocate objects or we risk
+ * jamming the GC.  So, we allow this function to return different formats.
+ * (This shouldn't be called directly -- see the inline functions in the
+ * header file.)
+ *
+ * If "wantObject" is true, this returns a newly-allocated Object, which is
+ * presently an array of integers, but could become something else in the
+ * future.  If "wantObject" is false, return plain malloc data.
+ *
+ * NOTE: if we support class unloading, we will need to scan the class
+ * object references out of these arrays.
+ */
+void* dvmFillInStackTraceInternal(Thread* thread, bool wantObject, size_t* pCount)
+{
+    ArrayObject* stackData = NULL;
+    int* simpleData = NULL;
+    void* fp;
+    void* startFp;
+    size_t stackDepth;
+    int* intPtr;
+
+    if (pCount != NULL)
+        *pCount = 0;
+    fp = thread->interpSave.curFrame;
+
+    assert(thread == dvmThreadSelf() || dvmIsSuspended(thread));
+
+    /*
+     * We're looking at a stack frame for code running below a Throwable
+     * constructor.  We want to remove the Throwable methods and the
+     * superclass initializations so the user doesn't see them when they
+     * read the stack dump.
+     *
+     * TODO: this just scrapes off the top layers of Throwable.  Might not do
+     * the right thing if we create an exception object or cause a VM
+     * exception while in a Throwable method.
+     */
+    while (fp != NULL) {
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+        const Method* method = saveArea->method;
+
+        if (dvmIsBreakFrame((u4*)fp))
+            break;
+        if (!dvmInstanceof(method->clazz, gDvm.exThrowable))
+            break;
+        //LOGD("EXCEP: ignoring %s.%s",
+        //         method->clazz->descriptor, method->name);
+        fp = saveArea->prevFrame;
+    }
+    startFp = fp;
+
+    /*
+     * Compute the stack depth.
+     */
+    stackDepth = 0;
+    while (fp != NULL) {
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+
+        if (!dvmIsBreakFrame((u4*)fp))
+            stackDepth++;
+
+        assert(fp != saveArea->prevFrame);
+        fp = saveArea->prevFrame;
+    }
+    //LOGD("EXCEP: stack depth is %d", stackDepth);
+
+    if (!stackDepth)
+        goto bail;
+
+    /*
+     * We need to store a pointer to the Method and the program counter.
+     * We have 4-byte pointers, so we use '[I'.
+     */
+    if (wantObject) {
+        assert(sizeof(Method*) == 4);
+        stackData = dvmAllocPrimitiveArray('I', stackDepth*2, ALLOC_DEFAULT);
+        if (stackData == NULL) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            goto bail;
+        }
+        intPtr = (int*)(void*)stackData->contents;
+    } else {
+        /* array of ints; first entry is stack depth */
+        assert(sizeof(Method*) == sizeof(int));
+        simpleData = (int*) malloc(sizeof(int) * stackDepth*2);
+        if (simpleData == NULL)
+            goto bail;
+
+        assert(pCount != NULL);
+        intPtr = simpleData;
+    }
+    if (pCount != NULL)
+        *pCount = stackDepth;
+
+    fp = startFp;
+    while (fp != NULL) {
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+        const Method* method = saveArea->method;
+
+        if (!dvmIsBreakFrame((u4*)fp)) {
+            //LOGD("EXCEP keeping %s.%s", method->clazz->descriptor,
+            //         method->name);
+
+            *intPtr++ = (int) method;
+            if (dvmIsNativeMethod(method)) {
+                *intPtr++ = 0;      /* no saved PC for native methods */
+            } else {
+                assert(saveArea->xtra.currentPc >= method->insns &&
+                        saveArea->xtra.currentPc <
+                        method->insns + dvmGetMethodInsnsSize(method));
+                *intPtr++ = (int) (saveArea->xtra.currentPc - method->insns);
+            }
+
+            stackDepth--;       // for verification
+        }
+
+        assert(fp != saveArea->prevFrame);
+        fp = saveArea->prevFrame;
+    }
+    assert(stackDepth == 0);
+
+bail:
+    if (wantObject) {
+        dvmReleaseTrackedAlloc((Object*) stackData, dvmThreadSelf());
+        return stackData;
+    } else {
+        return simpleData;
+    }
+}
+
+
+/*
+ * Given an Object previously created by dvmFillInStackTrace(), use the
+ * contents of the saved stack trace to generate an array of
+ * java/lang/StackTraceElement objects.
+ *
+ * The returned array is not added to the "local refs" list.
+ */
+ArrayObject* dvmGetStackTrace(const Object* ostackData)
+{
+    const ArrayObject* stackData = (const ArrayObject*) ostackData;
+    size_t stackSize = stackData->length / 2;
+    const int* intVals = (const int*)(void*)stackData->contents;
+    return dvmGetStackTraceRaw(intVals, stackSize);
+}
+
+/*
+ * Generate an array of StackTraceElement objects from the raw integer
+ * data encoded by dvmFillInStackTrace().
+ *
+ * "intVals" points to the first {method,pc} pair.
+ *
+ * The returned array is not added to the "local refs" list.
+ */
+ArrayObject* dvmGetStackTraceRaw(const int* intVals, size_t stackDepth)
+{
+    /* allocate a StackTraceElement array */
+    ClassObject* klass = gDvm.classJavaLangStackTraceElementArray;
+    ArrayObject* array = dvmAllocArrayByClass(klass, stackDepth, ALLOC_DEFAULT);
+    if (array != NULL){
+      dvmFillStackTraceElements(intVals, stackDepth, array);
+      dvmReleaseTrackedAlloc((Object*) array, NULL);
+    }
+    return array;
+}
+
+/*
+ * Fills the StackTraceElement array elements from the raw integer
+ * data encoded by dvmFillInStackTrace().
+ *
+ * "intVals" points to the first {method,pc} pair.
+ */
+void dvmFillStackTraceElements(const int* intVals, size_t stackDepth, ArrayObject* steArray)
+{
+    unsigned int i;
+
+    /* init this if we haven't yet */
+    if (!dvmIsClassInitialized(gDvm.classJavaLangStackTraceElement))
+        dvmInitClass(gDvm.classJavaLangStackTraceElement);
+
+    /*
+     * Allocate and initialize a StackTraceElement for each stack frame.
+     * We use the standard constructor to configure the object.
+     */
+    for (i = 0; i < stackDepth; i++) {
+        Object* ste = dvmAllocObject(gDvm.classJavaLangStackTraceElement,ALLOC_DEFAULT);
+        if (ste == NULL) {
+            return;
+        }
+
+        Method* meth = (Method*) *intVals++;
+        int pc = *intVals++;
+
+        int lineNumber;
+        if (pc == -1)      // broken top frame?
+            lineNumber = 0;
+        else
+            lineNumber = dvmLineNumFromPC(meth, pc);
+
+        std::string dotName(dvmHumanReadableDescriptor(meth->clazz->descriptor));
+        StringObject* className = dvmCreateStringFromCstr(dotName);
+
+        StringObject* methodName = dvmCreateStringFromCstr(meth->name);
+
+        const char* sourceFile = dvmGetMethodSourceFile(meth);
+        StringObject* fileName = (sourceFile != NULL) ? dvmCreateStringFromCstr(sourceFile) : NULL;
+
+        /*
+         * Invoke:
+         *  public StackTraceElement(String declaringClass, String methodName,
+         *      String fileName, int lineNumber)
+         * (where lineNumber==-2 means "native")
+         */
+        JValue unused;
+        dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangStackTraceElement_init,
+            ste, &unused, className, methodName, fileName, lineNumber);
+
+        dvmReleaseTrackedAlloc(ste, NULL);
+        dvmReleaseTrackedAlloc((Object*) className, NULL);
+        dvmReleaseTrackedAlloc((Object*) methodName, NULL);
+        dvmReleaseTrackedAlloc((Object*) fileName, NULL);
+
+        if (dvmCheckException(dvmThreadSelf())) {
+            return;
+        }
+
+        dvmSetObjectArrayElement(steArray, i, ste);
+    }
+}
+
+/*
+ * Dump the contents of a raw stack trace to the log.
+ */
+void dvmLogRawStackTrace(const int* intVals, int stackDepth) {
+    /*
+     * Run through the array of stack frame data.
+     */
+    for (int i = 0; i < stackDepth; i++) {
+        Method* meth = (Method*) *intVals++;
+        int pc = *intVals++;
+
+        std::string dotName(dvmHumanReadableDescriptor(meth->clazz->descriptor));
+        if (dvmIsNativeMethod(meth)) {
+            LOGI("\tat %s.%s(Native Method)", dotName.c_str(), meth->name);
+        } else {
+            LOGI("\tat %s.%s(%s:%d)",
+                dotName.c_str(), meth->name, dvmGetMethodSourceFile(meth),
+                dvmLineNumFromPC(meth, pc));
+        }
+    }
+}
+
+/*
+ * Get the message string.  We'd like to just grab the field out of
+ * Throwable, but the getMessage() function can be overridden by the
+ * sub-class.
+ *
+ * Returns the message string object, or NULL if it wasn't set or
+ * we encountered a failure trying to retrieve it.  The string will
+ * be added to the tracked references table.
+ */
+static StringObject* getExceptionMessage(Object* exception)
+{
+    Thread* self = dvmThreadSelf();
+    Method* getMessageMethod;
+    StringObject* messageStr = NULL;
+    Object* pendingException;
+
+    /*
+     * If an exception is pending, clear it while we work and restore
+     * it when we're done.
+     */
+    pendingException = dvmGetException(self);
+    if (pendingException != NULL) {
+        dvmAddTrackedAlloc(pendingException, self);
+        dvmClearException(self);
+    }
+
+    getMessageMethod = dvmFindVirtualMethodHierByDescriptor(exception->clazz,
+            "getMessage", "()Ljava/lang/String;");
+    if (getMessageMethod != NULL) {
+        /* could be in NATIVE mode from CheckJNI, so switch state */
+        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_RUNNING);
+        JValue result;
+
+        dvmCallMethod(self, getMessageMethod, exception, &result);
+        messageStr = (StringObject*) result.l;
+        if (messageStr != NULL)
+            dvmAddTrackedAlloc((Object*) messageStr, self);
+
+        dvmChangeStatus(self, oldStatus);
+    } else {
+        LOGW("WARNING: could not find getMessage in %s",
+            exception->clazz->descriptor);
+    }
+
+    if (dvmGetException(self) != NULL) {
+        LOGW("NOTE: exception thrown while retrieving exception message: %s",
+            dvmGetException(self)->clazz->descriptor);
+        /* will be overwritten below */
+    }
+
+    dvmSetException(self, pendingException);
+    if (pendingException != NULL) {
+        dvmReleaseTrackedAlloc(pendingException, self);
+    }
+    return messageStr;
+}
+
+/*
+ * Print the direct stack trace of the given exception to the log.
+ */
+static void logStackTraceOf(Object* exception) {
+    std::string className(dvmHumanReadableDescriptor(exception->clazz->descriptor));
+    StringObject* messageStr = getExceptionMessage(exception);
+    if (messageStr != NULL) {
+        char* cp = dvmCreateCstrFromString(messageStr);
+        dvmReleaseTrackedAlloc((Object*) messageStr, dvmThreadSelf());
+        messageStr = NULL;
+
+        LOGI("%s: %s", className.c_str(), cp);
+        free(cp);
+    } else {
+        LOGI("%s:", className.c_str());
+    }
+
+    /*
+     * This relies on the stackState field, which contains the "raw"
+     * form of the stack.  The Throwable class may clear this field
+     * after it generates the "cooked" form, in which case we'll have
+     * nothing to show.
+     */
+    const ArrayObject* stackData = (const ArrayObject*) dvmGetFieldObject(exception,
+                    gDvm.offJavaLangThrowable_stackState);
+    if (stackData == NULL) {
+        LOGI("  (raw stack trace not found)");
+        return;
+    }
+
+    int stackSize = stackData->length / 2;
+    const int* intVals = (const int*)(void*)stackData->contents;
+
+    dvmLogRawStackTrace(intVals, stackSize);
+}
+
+/*
+ * Print the stack trace of the current thread's exception, as well as
+ * the stack traces of any chained exceptions, to the log. We extract
+ * the stored stack trace and process it internally instead of calling
+ * interpreted code.
+ */
+void dvmLogExceptionStackTrace()
+{
+    Object* exception = dvmThreadSelf()->exception;
+    Object* cause;
+
+    if (exception == NULL) {
+        LOGW("tried to log a null exception?");
+        return;
+    }
+
+    for (;;) {
+        logStackTraceOf(exception);
+        cause = dvmGetExceptionCause(exception);
+        if (cause == NULL) {
+            break;
+        }
+        LOGI("Caused by:");
+        exception = cause;
+    }
+}
+
+/*
+ * Helper for a few of the throw functions defined below. This throws
+ * the indicated exception, with a message based on a format in which
+ * "%s" is used exactly twice, first for a received class and second
+ * for the expected class.
+ */
+static void throwTypeError(ClassObject* exceptionClass, const char* fmt,
+    ClassObject* actual, ClassObject* desired)
+{
+    std::string actualClassName(dvmHumanReadableDescriptor(actual->descriptor));
+    std::string desiredClassName(dvmHumanReadableDescriptor(desired->descriptor));
+    dvmThrowExceptionFmt(exceptionClass, fmt, actualClassName.c_str(), desiredClassName.c_str());
+}
+
+void dvmThrowAbstractMethodError(const char* msg) {
+    dvmThrowException(gDvm.exAbstractMethodError, msg);
+}
+
+void dvmThrowArithmeticException(const char* msg) {
+    dvmThrowException(gDvm.exArithmeticException, msg);
+}
+
+void dvmThrowArrayIndexOutOfBoundsException(int length, int index)
+{
+    dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
+        "length=%d; index=%d", length, index);
+}
+
+void dvmThrowArrayStoreExceptionIncompatibleElement(ClassObject* objectType,
+        ClassObject* arrayType)
+{
+    throwTypeError(gDvm.exArrayStoreException,
+        "%s cannot be stored in an array of type %s",
+        objectType, arrayType);
+}
+
+void dvmThrowArrayStoreExceptionNotArray(ClassObject* actual, const char* label) {
+    std::string actualClassName(dvmHumanReadableDescriptor(actual->descriptor));
+    dvmThrowExceptionFmt(gDvm.exArrayStoreException, "%s of type %s is not an array",
+            label, actualClassName.c_str());
+}
+
+void dvmThrowArrayStoreExceptionIncompatibleArrays(ClassObject* source, ClassObject* destination)
+{
+    throwTypeError(gDvm.exArrayStoreException,
+        "%s and %s are incompatible array types",
+        source, destination);
+}
+
+void dvmThrowArrayStoreExceptionIncompatibleArrayElement(s4 index, ClassObject* objectType,
+        ClassObject* arrayType)
+{
+    std::string objectClassName(dvmHumanReadableDescriptor(objectType->descriptor));
+    std::string arrayClassName(dvmHumanReadableDescriptor(arrayType->descriptor));
+    dvmThrowExceptionFmt(gDvm.exArrayStoreException,
+            "source[%d] of type %s cannot be stored in destination array of type %s",
+            index, objectClassName.c_str(), arrayClassName.c_str());
+}
+
+void dvmThrowClassCastException(ClassObject* actual, ClassObject* desired)
+{
+    throwTypeError(gDvm.exClassCastException,
+        "%s cannot be cast to %s", actual, desired);
+}
+
+void dvmThrowClassCircularityError(const char* descriptor) {
+    dvmThrowExceptionWithClassMessage(gDvm.exClassCircularityError,
+            descriptor);
+}
+
+void dvmThrowClassFormatError(const char* msg) {
+    dvmThrowException(gDvm.exClassFormatError, msg);
+}
+
+void dvmThrowClassNotFoundException(const char* name) {
+    dvmThrowChainedClassNotFoundException(name, NULL);
+}
+
+void dvmThrowChainedClassNotFoundException(const char* name, Object* cause) {
+    /*
+     * Note: This exception is thrown in response to a request coming
+     * from client code for the name as given, so it is preferable to
+     * make the exception message be that string, per se, instead of
+     * trying to prettify it.
+     */
+    dvmThrowChainedException(gDvm.exClassNotFoundException, name, cause);
+}
+
+void dvmThrowExceptionInInitializerError()
+{
+    /*
+     * TODO: Do we want to wrap it if the original is an Error rather than
+     * an Exception?
+     *
+     * TODO: Should this just use dvmWrapException()?
+     */
+
+    if (gDvm.exExceptionInInitializerError == NULL) {
+        /*
+         * ExceptionInInitializerError isn't itself initialized. This
+         * can happen very early during VM startup if there is a
+         * problem with one of the corest-of-the-core classes, and it
+         * can possibly happen during a dexopt run. Rather than do
+         * anything fancier, we just abort here with a blatant
+         * message.
+         */
+        LOGE("Fatal error during early class initialization:");
+        dvmLogExceptionStackTrace();
+        dvmAbort();
+    }
+
+    Thread* self = dvmThreadSelf();
+    Object* exception = dvmGetException(self);
+
+    dvmAddTrackedAlloc(exception, self);
+    dvmClearException(self);
+
+    dvmThrowChainedException(gDvm.exExceptionInInitializerError,
+            NULL, exception);
+    dvmReleaseTrackedAlloc(exception, self);
+}
+
+void dvmThrowFileNotFoundException(const char* msg) {
+    dvmThrowException(gDvm.exFileNotFoundException, msg);
+}
+
+void dvmThrowIOException(const char* msg) {
+    dvmThrowException(gDvm.exIOException, msg);
+}
+
+void dvmThrowIllegalAccessException(const char* msg) {
+    dvmThrowException(gDvm.exIllegalAccessException, msg);
+}
+
+void dvmThrowIllegalAccessError(const char* msg) {
+    dvmThrowException(gDvm.exIllegalAccessError, msg);
+}
+
+void dvmThrowIllegalArgumentException(const char* msg) {
+    dvmThrowException(gDvm.exIllegalArgumentException, msg);
+}
+
+void dvmThrowIllegalMonitorStateException(const char* msg) {
+    dvmThrowException(gDvm.exIllegalMonitorStateException, msg);
+}
+
+void dvmThrowIllegalStateException(const char* msg) {
+    dvmThrowException(gDvm.exIllegalStateException, msg);
+}
+
+void dvmThrowIllegalThreadStateException(const char* msg) {
+    dvmThrowException(gDvm.exIllegalThreadStateException, msg);
+}
+
+void dvmThrowIncompatibleClassChangeError(const char* msg) {
+    dvmThrowException(gDvm.exIncompatibleClassChangeError, msg);
+}
+
+void dvmThrowIncompatibleClassChangeErrorWithClassMessage(
+        const char* descriptor)
+{
+    dvmThrowExceptionWithClassMessage(
+            gDvm.exIncompatibleClassChangeError, descriptor);
+}
+
+void dvmThrowInstantiationException(ClassObject* clazz, const char* extraDetail) {
+    std::string className(dvmHumanReadableDescriptor(clazz->descriptor));
+    dvmThrowExceptionFmt(gDvm.exInstantiationException,
+            "can't instantiate class %s%s%s", className.c_str(),
+            (extraDetail == NULL) ? "" : "; ",
+            (extraDetail == NULL) ? "" : extraDetail);
+}
+
+void dvmThrowInternalError(const char* msg) {
+    dvmThrowException(gDvm.exInternalError, msg);
+}
+
+void dvmThrowInterruptedException(const char* msg) {
+    dvmThrowException(gDvm.exInterruptedException, msg);
+}
+
+void dvmThrowLinkageError(const char* msg) {
+    dvmThrowException(gDvm.exLinkageError, msg);
+}
+
+void dvmThrowNegativeArraySizeException(s4 size) {
+    dvmThrowExceptionFmt(gDvm.exNegativeArraySizeException, "%d", size);
+}
+
+void dvmThrowNoClassDefFoundError(const char* descriptor) {
+    dvmThrowExceptionWithClassMessage(gDvm.exNoClassDefFoundError,
+            descriptor);
+}
+
+void dvmThrowChainedNoClassDefFoundError(const char* descriptor,
+        Object* cause) {
+    dvmThrowChainedExceptionWithClassMessage(
+            gDvm.exNoClassDefFoundError, descriptor, cause);
+}
+
+void dvmThrowNoSuchFieldError(const char* msg) {
+    dvmThrowException(gDvm.exNoSuchFieldError, msg);
+}
+
+void dvmThrowNoSuchFieldException(const char* msg) {
+    dvmThrowException(gDvm.exNoSuchFieldException, msg);
+}
+
+void dvmThrowNoSuchMethodError(const char* msg) {
+    dvmThrowException(gDvm.exNoSuchMethodError, msg);
+}
+
+void dvmThrowNullPointerException(const char* msg) {
+    dvmThrowException(gDvm.exNullPointerException, msg);
+}
+
+void dvmThrowOutOfMemoryError(const char* msg) {
+    dvmThrowException(gDvm.exOutOfMemoryError, msg);
+}
+
+void dvmThrowRuntimeException(const char* msg) {
+    dvmThrowException(gDvm.exRuntimeException, msg);
+}
+
+void dvmThrowStaleDexCacheError(const char* msg) {
+    dvmThrowException(gDvm.exStaleDexCacheError, msg);
+}
+
+void dvmThrowStringIndexOutOfBoundsExceptionWithIndex(jsize stringLength,
+        jsize requestIndex) {
+    dvmThrowExceptionFmt(gDvm.exStringIndexOutOfBoundsException,
+            "length=%d; index=%d", stringLength, requestIndex);
+}
+
+void dvmThrowStringIndexOutOfBoundsExceptionWithRegion(jsize stringLength,
+        jsize requestStart, jsize requestLength) {
+    dvmThrowExceptionFmt(gDvm.exStringIndexOutOfBoundsException,
+            "length=%d; regionStart=%d; regionLength=%d",
+            stringLength, requestStart, requestLength);
+}
+
+void dvmThrowTypeNotPresentException(const char* descriptor) {
+    dvmThrowExceptionWithClassMessage(gDvm.exTypeNotPresentException,
+            descriptor);
+}
+
+void dvmThrowUnsatisfiedLinkError(const char* msg) {
+    dvmThrowException(gDvm.exUnsatisfiedLinkError, msg);
+}
+
+void dvmThrowUnsupportedOperationException(const char* msg) {
+    dvmThrowException(gDvm.exUnsupportedOperationException, msg);
+}
+
+void dvmThrowVerifyError(const char* descriptor) {
+    dvmThrowExceptionWithClassMessage(gDvm.exVerifyError, descriptor);
+}
+
+void dvmThrowVirtualMachineError(const char* msg) {
+    dvmThrowException(gDvm.exVirtualMachineError, msg);
+}
diff --git a/vm/Exception.h b/vm/Exception.h
new file mode 100644
index 0000000..3b7bdd9
--- /dev/null
+++ b/vm/Exception.h
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+/*
+ * Exception handling.
+ */
+#ifndef DALVIK_EXCEPTION_H_
+#define DALVIK_EXCEPTION_H_
+
+/*
+ * Create a Throwable and throw an exception in the current thread (where
+ * "throwing" just means "set the thread's exception pointer").
+ *
+ * "msg" and/or "cause" may be NULL.
+ *
+ * If we have a bad exception hierarchy -- something in Throwable.<init>
+ * is missing -- then every attempt to throw an exception will result
+ * in another exception.  Exceptions are generally allowed to "chain"
+ * to other exceptions, so it's hard to auto-detect this problem.  It can
+ * only happen if the system classes are broken, so it's probably not
+ * worth spending cycles to detect it.
+ *
+ * We do have one case to worry about: if the classpath is completely
+ * wrong, we'll go into a death spin during startup because we can't find
+ * the initial class and then we can't find NoClassDefFoundError.  We have
+ * to handle this case.
+ */
+void dvmThrowChainedException(ClassObject* exceptionClass,
+    const char* msg, Object* cause);
+INLINE void dvmThrowException(ClassObject* exceptionClass,
+    const char* msg)
+{
+    dvmThrowChainedException(exceptionClass, msg, NULL);
+}
+
+/*
+ * Like dvmThrowException, but takes printf-style args for the message.
+ */
+void dvmThrowExceptionFmtV(ClassObject* exceptionClass,
+    const char* fmt, va_list args);
+void dvmThrowExceptionFmt(ClassObject* exceptionClass,
+    const char* fmt, ...)
+#if defined(__GNUC__)
+    __attribute__ ((format(printf, 2, 3)))
+#endif
+    ;
+INLINE void dvmThrowExceptionFmt(ClassObject* exceptionClass,
+    const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    dvmThrowExceptionFmtV(exceptionClass, fmt, args);
+    va_end(args);
+}
+
+/*
+ * Like dvmThrowChainedException, but take a class object
+ * instead of a name and turn the given message into the
+ * human-readable form for a descriptor.
+ */
+void dvmThrowChainedExceptionWithClassMessage(
+    ClassObject* exceptionClass, const char* messageDescriptor,
+    Object* cause);
+
+/*
+ * Like dvmThrowException, but take a class object instead of a name
+ * and turn the given message into the human-readable form for a descriptor.
+ */
+INLINE void dvmThrowExceptionWithClassMessage(
+    ClassObject* exceptionClass, const char* messageDescriptor)
+{
+    dvmThrowChainedExceptionWithClassMessage(exceptionClass,
+            messageDescriptor, NULL);
+}
+
+/*
+ * Return the exception being thrown in the current thread, or NULL if
+ * no exception is pending.
+ */
+INLINE Object* dvmGetException(Thread* self) {
+    return self->exception;
+}
+
+/*
+ * Set the exception being thrown in the current thread.
+ */
+INLINE void dvmSetException(Thread* self, Object* exception)
+{
+    assert(exception != NULL);
+    self->exception = exception;
+}
+
+/*
+ * Clear the pending exception.
+ *
+ * (We use this rather than "set(null)" because we may need to have special
+ * fixups here for StackOverflowError stuff.  Calling "clear" in the code
+ * makes it obvious.)
+ */
+INLINE void dvmClearException(Thread* self) {
+    self->exception = NULL;
+}
+
+/*
+ * Clear the pending exception.  Used by the optimization and verification
+ * code, which has to run with "initializing" set to avoid going into a
+ * death-spin if the "class not found" exception can't be found.
+ */
+void dvmClearOptException(Thread* self);
+
+/*
+ * Returns "true" if an exception is pending.  Use this if you have a
+ * "self" pointer.
+ */
+INLINE bool dvmCheckException(Thread* self) {
+    return (self->exception != NULL);
+}
+
+/*
+ * Returns "true" if this is a "checked" exception, i.e. it's a subclass
+ * of Throwable (assumed) but not a subclass of RuntimeException or Error.
+ */
+bool dvmIsCheckedException(const Object* exception);
+
+/*
+ * Wrap the now-pending exception in a different exception.
+ *
+ * If something fails, an (unchecked) exception related to that failure
+ * will be pending instead.
+ */
+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.
+ */
+void dvmPrintExceptionStackTrace(void);
+
+/*
+ * Print the exception stack trace to the log file.  The exception stack
+ * trace is computed within the VM.
+ */
+void dvmLogExceptionStackTrace(void);
+
+/*
+ * Search for a catch block that matches "exception".
+ *
+ * "*newFrame" gets a copy of the new frame pointer.
+ *
+ * If "doUnroll" is set, we unroll "thread"s stack as we go (and update
+ * self->interpSave.curFrame with the same value as in *newFrame).
+ *
+ * Returns the offset to the catch code on success, or -1 if we couldn't
+ * find a catcher.
+ */
+extern "C" int dvmFindCatchBlock(Thread* self, int relPc, Object* exception,
+    bool doUnroll, void** newFrame);
+
+/*
+ * Support for saving exception stack traces and converting them to
+ * usable form.  Use the "FillIn" function to generate a compact array
+ * that represents the stack frames, then "GetStackTrace" to convert it
+ * to an array of StackTraceElement objects.
+ *
+ * Don't call the "Internal" form of the function directly.
+ */
+void* dvmFillInStackTraceInternal(Thread* thread, bool wantObject, size_t* pCount);
+/* return an [I for use by interpreted code */
+INLINE Object* dvmFillInStackTrace(Thread* thread) {
+    return (Object*) dvmFillInStackTraceInternal(thread, true, NULL);
+}
+ArrayObject* dvmGetStackTrace(const Object* stackState);
+/* return an int* and array count; caller must free() the return value */
+INLINE int* dvmFillInStackTraceRaw(Thread* thread, size_t* pCount) {
+    return (int*) dvmFillInStackTraceInternal(thread, false, pCount);
+}
+ArrayObject* dvmGetStackTraceRaw(const int* intVals, size_t stackDepth);
+void dvmFillStackTraceElements(const int* intVals, size_t stackDepth, ArrayObject* steArray);
+
+/*
+ * Print a formatted version of a raw stack trace to the log file.
+ */
+void dvmLogRawStackTrace(const int* intVals, int stackDepth);
+
+/**
+ * Throw an AbstractMethodError in the current thread, with the given detail
+ * message.
+ */
+void dvmThrowAbstractMethodError(const char* msg);
+
+/**
+ * Throw an ArithmeticException in the current thread, with the given detail
+ * message.
+ */
+extern "C" void dvmThrowArithmeticException(const char* msg);
+
+/*
+ * Throw an ArrayIndexOutOfBoundsException in the current thread,
+ * using the given array length and index in the detail message.
+ */
+extern "C" void dvmThrowArrayIndexOutOfBoundsException(int length, int index);
+
+/*
+ * Throw an ArrayStoreException in the current thread, using the given classes'
+ * names in the detail message, indicating that an object of the given type
+ * can't be stored into an array of the given type.
+ */
+extern "C" void dvmThrowArrayStoreExceptionIncompatibleElement(ClassObject* objectType, ClassObject* arrayType);
+
+/*
+ * Throw an ArrayStoreException in the current thread, using the given
+ * class name and argument label in the detail message, indicating
+ * that it is not an array.
+ */
+void dvmThrowArrayStoreExceptionNotArray(ClassObject* actual, const char* label);
+
+/*
+ * Throw an ArrayStoreException in the current thread, using the given
+ * classes' names in the detail message, indicating that the arrays
+ * aren't compatible (for copying contents).
+ */
+void dvmThrowArrayStoreExceptionIncompatibleArrays(ClassObject* source, ClassObject* destination);
+
+/*
+ * Throw an ArrayStoreException in the current thread, using the given
+ * index and classes' names in the detail message, indicating that the
+ * object at the given index and of the given type cannot be stored
+ * into an array of the given type.
+ */
+void dvmThrowArrayStoreExceptionIncompatibleArrayElement(s4 index, ClassObject* objectType,
+        ClassObject* arrayType);
+
+/**
+ * Throw a ClassCastException in the current thread, using the given classes'
+ * names in the detail message.
+ */
+extern "C" void dvmThrowClassCastException(ClassObject* actual, ClassObject* desired);
+
+/**
+ * Throw a ClassCircularityError in the current thread, with the
+ * human-readable form of the given descriptor as the detail message.
+ */
+void dvmThrowClassCircularityError(const char* descriptor);
+
+/**
+ * Throw a ClassFormatError in the current thread, with the given
+ * detail message.
+ */
+void dvmThrowClassFormatError(const char* msg);
+
+/**
+ * Throw a ClassNotFoundException in the current thread, with the given
+ * class name as the detail message.
+ */
+void dvmThrowClassNotFoundException(const char* name);
+
+/**
+ * Throw a ClassNotFoundException in the current thread, with the given
+ * cause, and the given class name as the detail message.
+ */
+void dvmThrowChainedClassNotFoundException(const char* name, Object* cause);
+
+/*
+ * Throw the VM-spec-mandated error when an exception is thrown during
+ * class initialization. Unlike other helper functions, this automatically
+ * wraps the current thread's pending exception.
+ */
+void dvmThrowExceptionInInitializerError(void);
+
+/**
+ * Throw a FileNotFoundException in the current thread, with the given
+ * detail message.
+ */
+void dvmThrowFileNotFoundException(const char* msg);
+
+/**
+ * Throw an IOException in the current thread, with the given
+ * detail message.
+ */
+void dvmThrowIOException(const char* msg);
+
+/**
+ * Throw an IllegalAccessError in the current thread, with the
+ * given detail message.
+ */
+void dvmThrowIllegalAccessError(const char* msg);
+
+/**
+ * Throw an IllegalAccessException in the current thread, with the
+ * given detail message.
+ */
+void dvmThrowIllegalAccessException(const char* msg);
+
+/**
+ * Throw an IllegalArgumentException in the current thread, with the
+ * given detail message.
+ */
+void dvmThrowIllegalArgumentException(const char* msg);
+
+/**
+ * Throw an IllegalMonitorStateException in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowIllegalMonitorStateException(const char* msg);
+
+/**
+ * Throw an IllegalStateException in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowIllegalStateException(const char* msg);
+
+/**
+ * Throw an IllegalThreadStateException in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowIllegalThreadStateException(const char* msg);
+
+/**
+ * Throw an IncompatibleClassChangeError in the current thread,
+ * the given detail message.
+ */
+void dvmThrowIncompatibleClassChangeError(const char* msg);
+
+/**
+ * Throw an IncompatibleClassChangeError in the current thread, with the
+ * human-readable form of the given descriptor as the detail message.
+ */
+void dvmThrowIncompatibleClassChangeErrorWithClassMessage(
+        const char* descriptor);
+
+/**
+ * Throw an InstantiationException in the current thread, with
+ * the human-readable form of the given class as the detail message,
+ * with optional extra detail appended to the message.
+ */
+void dvmThrowInstantiationException(ClassObject* clazz,
+        const char* extraDetail);
+
+/**
+ * Throw an InternalError in the current thread, with the given
+ * detail message.
+ */
+extern "C" void dvmThrowInternalError(const char* msg);
+
+/**
+ * Throw an InterruptedException in the current thread, with the given
+ * detail message.
+ */
+void dvmThrowInterruptedException(const char* msg);
+
+/**
+ * Throw a LinkageError in the current thread, with the
+ * given detail message.
+ */
+void dvmThrowLinkageError(const char* msg);
+
+/**
+ * Throw a NegativeArraySizeException in the current thread, with the
+ * given number as the detail message.
+ */
+extern "C" void dvmThrowNegativeArraySizeException(s4 size);
+
+/**
+ * Throw a NoClassDefFoundError in the current thread, with the
+ * human-readable form of the given descriptor as the detail message.
+ */
+extern "C" void dvmThrowNoClassDefFoundError(const char* descriptor);
+
+/**
+ * Throw a NoClassDefFoundError in the current thread, with the given
+ * cause, and the human-readable form of the given descriptor as the
+ * detail message.
+ */
+void dvmThrowChainedNoClassDefFoundError(const char* descriptor,
+        Object* cause);
+
+/**
+ * Throw a NoSuchFieldError in the current thread, with the given
+ * detail message.
+ */
+extern "C" void dvmThrowNoSuchFieldError(const char* msg);
+
+/**
+ * Throw a NoSuchFieldException in the current thread, with the given
+ * detail message.
+ */
+void dvmThrowNoSuchFieldException(const char* msg);
+
+/**
+ * Throw a NoSuchMethodError in the current thread, with the given
+ * detail message.
+ */
+extern "C" void dvmThrowNoSuchMethodError(const char* msg);
+
+/**
+ * Throw a NullPointerException in the current thread, with the given
+ * detail message.
+ */
+extern "C" void dvmThrowNullPointerException(const char* msg);
+
+/**
+ * Throw an OutOfMemoryError in the current thread, with the given
+ * detail message.
+ */
+void dvmThrowOutOfMemoryError(const char* msg);
+
+/**
+ * Throw a RuntimeException in the current thread, with the given detail
+ * message.
+ */
+void dvmThrowRuntimeException(const char* msg);
+
+/**
+ * Throw a StaleDexCacheError in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowStaleDexCacheError(const char* msg);
+
+/**
+ * Throw a StringIndexOutOfBoundsException in the current thread, with
+ * a detail message specifying an actual length as well as a requested
+ * index.
+ */
+void dvmThrowStringIndexOutOfBoundsExceptionWithIndex(jsize stringLength,
+        jsize requestIndex);
+
+/**
+ * Throw a StringIndexOutOfBoundsException in the current thread, with
+ * a detail message specifying an actual length as well as a requested
+ * region.
+ */
+void dvmThrowStringIndexOutOfBoundsExceptionWithRegion(jsize stringLength,
+        jsize requestStart, jsize requestLength);
+
+/**
+ * Throw a TypeNotPresentException in the current thread, with the
+ * human-readable form of the given descriptor as the detail message.
+ */
+void dvmThrowTypeNotPresentException(const char* descriptor);
+
+/**
+ * Throw an UnsatisfiedLinkError in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowUnsatisfiedLinkError(const char* msg);
+
+/**
+ * Throw an UnsupportedOperationException in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowUnsupportedOperationException(const char* msg);
+
+/**
+ * Throw a VerifyError in the current thread, with the
+ * human-readable form of the given descriptor as the detail message.
+ */
+void dvmThrowVerifyError(const char* descriptor);
+
+/**
+ * Throw a VirtualMachineError in the current thread, with
+ * the given detail message.
+ */
+void dvmThrowVirtualMachineError(const char* msg);
+
+#endif  // DALVIK_EXCEPTION_H_
diff --git a/vm/Globals.h b/vm/Globals.h
new file mode 100644
index 0000000..3cc0b49
--- /dev/null
+++ b/vm/Globals.h
@@ -0,0 +1,984 @@
+/*
+ * 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.
+ */
+
+/*
+ * Variables with library scope.
+ *
+ * Prefer this over scattered static and global variables -- it's easier to
+ * view the state in a debugger, it makes clean shutdown simpler, we can
+ * trivially dump the state into a crash log, and it dodges most naming
+ * collisions that will arise when we are embedded in a larger program.
+ *
+ * If we want multiple VMs per process, this can get stuffed into TLS (or
+ * accessed through a Thread field).  May need to pass it around for some
+ * of the early initialization functions.
+ */
+#ifndef DALVIK_GLOBALS_H_
+#define DALVIK_GLOBALS_H_
+
+#include <string>
+#include <vector>
+
+#include <stdarg.h>
+#include <pthread.h>
+
+/* private structures */
+struct GcHeap;
+struct BreakpointSet;
+struct InlineSub;
+
+/*
+ * One of these for each -ea/-da/-esa/-dsa on the command line.
+ */
+struct AssertionControl {
+    char*   pkgOrClass;         /* package/class string, or NULL for esa/dsa */
+    int     pkgOrClassLen;      /* string length, for quick compare */
+    bool    enable;             /* enable or disable */
+    bool    isPackage;          /* string ended with "..."? */
+};
+
+/*
+ * Register map generation mode.  Only applicable when generateRegisterMaps
+ * is enabled.  (The "disabled" state is not folded into this because
+ * there are callers like dexopt that want to enable/disable without
+ * specifying the configuration details.)
+ *
+ * "TypePrecise" is slower and requires additional storage for the register
+ * maps, but allows type-precise GC.  "LivePrecise" is even slower and
+ * requires additional heap during processing, but allows live-precise GC.
+ */
+enum RegisterMapMode {
+    kRegisterMapModeUnknown = 0,
+    kRegisterMapModeTypePrecise,
+    kRegisterMapModeLivePrecise
+};
+
+/*
+ * Profiler clock source.
+ */
+enum ProfilerClockSource {
+    kProfilerClockSourceThreadCpu,
+    kProfilerClockSourceWall,
+    kProfilerClockSourceDual,
+};
+
+/*
+ * All fields are initialized to zero.
+ *
+ * Storage allocated here must be freed by a subsystem shutdown function.
+ */
+struct DvmGlobals {
+    /*
+     * Some options from the command line or environment.
+     */
+    char*       bootClassPathStr;
+    char*       classPathStr;
+
+    size_t      heapStartingSize;
+    size_t      heapMaximumSize;
+    size_t      heapGrowthLimit;
+    size_t      stackSize;
+
+    bool        verboseGc;
+    bool        verboseJni;
+    bool        verboseClass;
+    bool        verboseShutdown;
+
+    bool        jdwpAllowed;        // debugging allowed for this process?
+    bool        jdwpConfigured;     // has debugging info been provided?
+    JdwpTransportType jdwpTransport;
+    bool        jdwpServer;
+    char*       jdwpHost;
+    int         jdwpPort;
+    bool        jdwpSuspend;
+
+    ProfilerClockSource profilerClockSource;
+
+    /*
+     * Lock profiling threshold value in milliseconds.  Acquires that
+     * exceed threshold are logged.  Acquires within the threshold are
+     * logged with a probability of $\frac{time}{threshold}$ .  If the
+     * threshold is unset no additional logging occurs.
+     */
+    u4          lockProfThreshold;
+
+    int         (*vfprintfHook)(FILE*, const char*, va_list);
+    void        (*exitHook)(int);
+    void        (*abortHook)(void);
+    bool        (*isSensitiveThreadHook)(void);
+
+    int         jniGrefLimit;       // 0 means no limit
+    char*       jniTrace;
+    bool        reduceSignals;
+    bool        noQuitHandler;
+    bool        verifyDexChecksum;
+    char*       stackTraceFile;     // for SIGQUIT-inspired output
+
+    bool        logStdio;
+
+    DexOptimizerMode    dexOptMode;
+    DexClassVerifyMode  classVerifyMode;
+
+    bool        generateRegisterMaps;
+    RegisterMapMode     registerMapMode;
+
+    bool        monitorVerification;
+
+    bool        dexOptForSmp;
+
+    /*
+     * GC option flags.
+     */
+    bool        preciseGc;
+    bool        preVerify;
+    bool        postVerify;
+    bool        concurrentMarkSweep;
+    bool        verifyCardTable;
+    bool        disableExplicitGc;
+
+    int         assertionCtrlCount;
+    AssertionControl*   assertionCtrl;
+
+    ExecutionMode   executionMode;
+
+    /*
+     * VM init management.
+     */
+    bool        initializing;
+    bool        optimizing;
+
+    /*
+     * java.lang.System properties set from the command line with -D.
+     * This is effectively a set, where later entries override earlier
+     * ones.
+     */
+    std::vector<std::string>* properties;
+
+    /*
+     * Where the VM goes to find system classes.
+     */
+    ClassPathEntry* bootClassPath;
+    /* used by the DEX optimizer to load classes from an unfinished DEX */
+    DvmDex*     bootClassPathOptExtra;
+    bool        optimizingBootstrapClass;
+
+    /*
+     * Loaded classes, hashed by class name.  Each entry is a ClassObject*,
+     * allocated in GC space.
+     */
+    HashTable*  loadedClasses;
+
+    /*
+     * Value for the next class serial number to be assigned.  This is
+     * incremented as we load classes.  Failed loads and races may result
+     * in some numbers being skipped, and the serial number is not
+     * guaranteed to start at 1, so the current value should not be used
+     * as a count of loaded classes.
+     */
+    volatile int classSerialNumber;
+
+    /*
+     * Classes with a low classSerialNumber are probably in the zygote, and
+     * their InitiatingLoaderList is not used, to promote sharing. The list is
+     * kept here instead.
+     */
+    InitiatingLoaderList* initiatingLoaderList;
+
+    /*
+     * Interned strings.
+     */
+
+    /* A mutex that guards access to the interned string tables. */
+    pthread_mutex_t internLock;
+
+    /* Hash table of strings interned by the user. */
+    HashTable*  internedStrings;
+
+    /* Hash table of strings interned by the class loader. */
+    HashTable*  literalStrings;
+
+    /*
+     * Classes constructed directly by the vm.
+     */
+
+    /* the class Class */
+    ClassObject* classJavaLangClass;
+
+    /* synthetic classes representing primitive types */
+    ClassObject* typeVoid;
+    ClassObject* typeBoolean;
+    ClassObject* typeByte;
+    ClassObject* typeShort;
+    ClassObject* typeChar;
+    ClassObject* typeInt;
+    ClassObject* typeLong;
+    ClassObject* typeFloat;
+    ClassObject* typeDouble;
+
+    /* synthetic classes for arrays of primitives */
+    ClassObject* classArrayBoolean;
+    ClassObject* classArrayByte;
+    ClassObject* classArrayShort;
+    ClassObject* classArrayChar;
+    ClassObject* classArrayInt;
+    ClassObject* classArrayLong;
+    ClassObject* classArrayFloat;
+    ClassObject* classArrayDouble;
+
+    /*
+     * Quick lookups for popular classes used internally.
+     */
+    ClassObject* classJavaLangClassArray;
+    ClassObject* classJavaLangClassLoader;
+    ClassObject* classJavaLangObject;
+    ClassObject* classJavaLangObjectArray;
+    ClassObject* classJavaLangString;
+    ClassObject* classJavaLangThread;
+    ClassObject* classJavaLangVMThread;
+    ClassObject* classJavaLangThreadGroup;
+    ClassObject* classJavaLangStackTraceElement;
+    ClassObject* classJavaLangStackTraceElementArray;
+    ClassObject* classJavaLangAnnotationAnnotationArray;
+    ClassObject* classJavaLangAnnotationAnnotationArrayArray;
+    ClassObject* classJavaLangReflectAccessibleObject;
+    ClassObject* classJavaLangReflectConstructor;
+    ClassObject* classJavaLangReflectConstructorArray;
+    ClassObject* classJavaLangReflectField;
+    ClassObject* classJavaLangReflectFieldArray;
+    ClassObject* classJavaLangReflectMethod;
+    ClassObject* classJavaLangReflectMethodArray;
+    ClassObject* classJavaLangReflectProxy;
+    ClassObject* classJavaNioReadWriteDirectByteBuffer;
+    ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationFactory;
+    ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMember;
+    ClassObject* classOrgApacheHarmonyLangAnnotationAnnotationMemberArray;
+    ClassObject* classOrgApacheHarmonyDalvikDdmcChunk;
+    ClassObject* classOrgApacheHarmonyDalvikDdmcDdmServer;
+    ClassObject* classJavaLangRefFinalizerReference;
+
+    /*
+     * classes representing exception types. The names here don't include
+     * packages, just to keep the use sites a bit less verbose. All are
+     * in java.lang, except where noted.
+     */
+    ClassObject* exAbstractMethodError;
+    ClassObject* exArithmeticException;
+    ClassObject* exArrayIndexOutOfBoundsException;
+    ClassObject* exArrayStoreException;
+    ClassObject* exClassCastException;
+    ClassObject* exClassCircularityError;
+    ClassObject* exClassFormatError;
+    ClassObject* exClassNotFoundException;
+    ClassObject* exError;
+    ClassObject* exExceptionInInitializerError;
+    ClassObject* exFileNotFoundException; /* in java.io */
+    ClassObject* exIOException;           /* in java.io */
+    ClassObject* exIllegalAccessError;
+    ClassObject* exIllegalAccessException;
+    ClassObject* exIllegalArgumentException;
+    ClassObject* exIllegalMonitorStateException;
+    ClassObject* exIllegalStateException;
+    ClassObject* exIllegalThreadStateException;
+    ClassObject* exIncompatibleClassChangeError;
+    ClassObject* exInstantiationError;
+    ClassObject* exInstantiationException;
+    ClassObject* exInternalError;
+    ClassObject* exInterruptedException;
+    ClassObject* exLinkageError;
+    ClassObject* exNegativeArraySizeException;
+    ClassObject* exNoClassDefFoundError;
+    ClassObject* exNoSuchFieldError;
+    ClassObject* exNoSuchFieldException;
+    ClassObject* exNoSuchMethodError;
+    ClassObject* exNullPointerException;
+    ClassObject* exOutOfMemoryError;
+    ClassObject* exRuntimeException;
+    ClassObject* exStackOverflowError;
+    ClassObject* exStaleDexCacheError;    /* in dalvik.system */
+    ClassObject* exStringIndexOutOfBoundsException;
+    ClassObject* exThrowable;
+    ClassObject* exTypeNotPresentException;
+    ClassObject* exUnsatisfiedLinkError;
+    ClassObject* exUnsupportedOperationException;
+    ClassObject* exVerifyError;
+    ClassObject* exVirtualMachineError;
+
+    /* method offsets - Object */
+    int         voffJavaLangObject_equals;
+    int         voffJavaLangObject_hashCode;
+    int         voffJavaLangObject_toString;
+
+    /* field offsets - String */
+    int         offJavaLangString_value;
+    int         offJavaLangString_count;
+    int         offJavaLangString_offset;
+    int         offJavaLangString_hashCode;
+
+    /* field offsets - Thread */
+    int         offJavaLangThread_vmThread;
+    int         offJavaLangThread_group;
+    int         offJavaLangThread_daemon;
+    int         offJavaLangThread_name;
+    int         offJavaLangThread_priority;
+    int         offJavaLangThread_uncaughtHandler;
+    int         offJavaLangThread_contextClassLoader;
+
+    /* method offsets - Thread */
+    int         voffJavaLangThread_run;
+
+    /* field offsets - ThreadGroup */
+    int         offJavaLangThreadGroup_name;
+    int         offJavaLangThreadGroup_parent;
+
+    /* field offsets - VMThread */
+    int         offJavaLangVMThread_thread;
+    int         offJavaLangVMThread_vmData;
+
+    /* method offsets - ThreadGroup */
+    int         voffJavaLangThreadGroup_removeThread;
+
+    /* field offsets - Throwable */
+    int         offJavaLangThrowable_stackState;
+    int         offJavaLangThrowable_cause;
+
+    /* method offsets - ClassLoader */
+    int         voffJavaLangClassLoader_loadClass;
+
+    /* direct method pointers - ClassLoader */
+    Method*     methJavaLangClassLoader_getSystemClassLoader;
+
+    /* field offsets - java.lang.reflect.* */
+    int         offJavaLangReflectConstructor_slot;
+    int         offJavaLangReflectConstructor_declClass;
+    int         offJavaLangReflectField_slot;
+    int         offJavaLangReflectField_declClass;
+    int         offJavaLangReflectMethod_slot;
+    int         offJavaLangReflectMethod_declClass;
+
+    /* field offsets - java.lang.ref.Reference */
+    int         offJavaLangRefReference_referent;
+    int         offJavaLangRefReference_queue;
+    int         offJavaLangRefReference_queueNext;
+    int         offJavaLangRefReference_pendingNext;
+
+    /* field offsets - java.lang.ref.FinalizerReference */
+    int offJavaLangRefFinalizerReference_zombie;
+
+    /* method pointers - java.lang.ref.ReferenceQueue */
+    Method* methJavaLangRefReferenceQueueAdd;
+
+    /* method pointers - java.lang.ref.FinalizerReference */
+    Method* methJavaLangRefFinalizerReferenceAdd;
+
+    /* constructor method pointers; no vtable involved, so use Method* */
+    Method*     methJavaLangStackTraceElement_init;
+    Method*     methJavaLangReflectConstructor_init;
+    Method*     methJavaLangReflectField_init;
+    Method*     methJavaLangReflectMethod_init;
+    Method*     methOrgApacheHarmonyLangAnnotationAnnotationMember_init;
+
+    /* static method pointers - android.lang.annotation.* */
+    Method*
+        methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation;
+
+    /* direct method pointers - java.lang.reflect.Proxy */
+    Method*     methJavaLangReflectProxy_constructorPrototype;
+
+    /* field offsets - java.lang.reflect.Proxy */
+    int         offJavaLangReflectProxy_h;
+
+    /* field offsets - java.io.FileDescriptor */
+    int         offJavaIoFileDescriptor_descriptor;
+
+    /* direct method pointers - dalvik.system.NativeStart */
+    Method*     methDalvikSystemNativeStart_main;
+    Method*     methDalvikSystemNativeStart_run;
+
+    /* assorted direct buffer helpers */
+    Method*     methJavaNioReadWriteDirectByteBuffer_init;
+    int         offJavaNioBuffer_capacity;
+    int         offJavaNioBuffer_effectiveDirectAddress;
+
+    /* direct method pointers - org.apache.harmony.dalvik.ddmc.DdmServer */
+    Method*     methDalvikDdmcServer_dispatch;
+    Method*     methDalvikDdmcServer_broadcast;
+
+    /* field offsets - org.apache.harmony.dalvik.ddmc.Chunk */
+    int         offDalvikDdmcChunk_type;
+    int         offDalvikDdmcChunk_data;
+    int         offDalvikDdmcChunk_offset;
+    int         offDalvikDdmcChunk_length;
+
+    /*
+     * Thread list.  This always has at least one element in it (main),
+     * and main is always the first entry.
+     *
+     * The threadListLock is used for several things, including the thread
+     * start condition variable.  Generally speaking, you must hold the
+     * threadListLock when:
+     *  - adding/removing items from the list
+     *  - waiting on or signaling threadStartCond
+     *  - examining the Thread struct for another thread (this is to avoid
+     *    one thread freeing the Thread struct while another thread is
+     *    perusing it)
+     */
+    Thread*     threadList;
+    pthread_mutex_t threadListLock;
+
+    pthread_cond_t threadStartCond;
+
+    /*
+     * The thread code grabs this before suspending all threads.  There
+     * 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.
+     */
+    pthread_mutex_t _threadSuspendLock;
+
+    /*
+     * Guards Thread->suspendCount for all threads, and
+     * provides the lock for the condition variable that all suspended threads
+     * sleep on (threadSuspendCountCond).
+     *
+     * This has to be separate from threadListLock because of the way
+     * threads put themselves to sleep.
+     */
+    pthread_mutex_t threadSuspendCountLock;
+
+    /*
+     * Suspended threads sleep on this.  They should sleep on the condition
+     * variable until their "suspend count" is zero.
+     *
+     * Paired with "threadSuspendCountLock".
+     */
+    pthread_cond_t  threadSuspendCountCond;
+
+    /*
+     * Sum of all threads' suspendCount fields. Guarded by
+     * threadSuspendCountLock.
+     */
+    int  sumThreadSuspendCount;
+
+    /*
+     * MUTEX ORDERING: when locking multiple mutexes, always grab them in
+     * this order to avoid deadlock:
+     *
+     *  (1) _threadSuspendLock      (use lockThreadSuspend())
+     *  (2) threadListLock          (use dvmLockThreadList())
+     *  (3) threadSuspendCountLock  (use lockThreadSuspendCount())
+     */
+
+
+    /*
+     * Thread ID bitmap.  We want threads to have small integer IDs so
+     * we can use them in "thin locks".
+     */
+    BitVector*  threadIdMap;
+
+    /*
+     * Manage exit conditions.  The VM exits when all non-daemon threads
+     * have exited.  If the main thread returns early, we need to sleep
+     * on a condition variable.
+     */
+    int         nonDaemonThreadCount;   /* must hold threadListLock to access */
+    pthread_cond_t  vmExitCond;
+
+    /*
+     * The set of DEX files loaded by custom class loaders.
+     */
+    HashTable*  userDexFiles;
+
+    /*
+     * JNI global reference table.
+     */
+    IndirectRefTable jniGlobalRefTable;
+    IndirectRefTable jniWeakGlobalRefTable;
+    pthread_mutex_t jniGlobalRefLock;
+    pthread_mutex_t jniWeakGlobalRefLock;
+    int         jniGlobalRefHiMark;
+    int         jniGlobalRefLoMark;
+
+    /*
+     * JNI pinned object table (used for primitive arrays).
+     */
+    ReferenceTable  jniPinRefTable;
+    pthread_mutex_t jniPinRefLock;
+
+    /*
+     * Native shared library table.
+     */
+    HashTable*  nativeLibs;
+
+    /*
+     * GC heap lock.  Functions like gcMalloc() acquire this before making
+     * any changes to the heap.  It is held throughout garbage collection.
+     */
+    pthread_mutex_t gcHeapLock;
+
+    /*
+     * Condition variable to queue threads waiting to retry an
+     * allocation.  Signaled after a concurrent GC is completed.
+     */
+    pthread_cond_t gcHeapCond;
+
+    /* Opaque pointer representing the heap. */
+    GcHeap*     gcHeap;
+
+    /* The card table base, modified as needed for marking cards. */
+    u1*         biasedCardTableBase;
+
+    /*
+     * Pre-allocated throwables.
+     */
+    Object*     outOfMemoryObj;
+    Object*     internalErrorObj;
+    Object*     noClassDefFoundErrorObj;
+
+    /* Monitor list, so we can free them */
+    /*volatile*/ Monitor* monitorList;
+
+    /* Monitor for Thread.sleep() implementation */
+    Monitor*    threadSleepMon;
+
+    /* set when we create a second heap inside the zygote */
+    bool        newZygoteHeapAllocated;
+
+    /*
+     * TLS keys.
+     */
+    pthread_key_t pthreadKeySelf;       /* Thread*, for dvmThreadSelf */
+
+    /*
+     * Cache results of "A instanceof B".
+     */
+    AtomicCache* instanceofCache;
+
+    /* inline substitution table, used during optimization */
+    InlineSub*          inlineSubs;
+
+    /*
+     * Bootstrap class loader linear allocator.
+     */
+    LinearAllocHdr* pBootLoaderAlloc;
+
+    /*
+     * Compute some stats on loaded classes.
+     */
+    int         numLoadedClasses;
+    int         numDeclaredMethods;
+    int         numDeclaredInstFields;
+    int         numDeclaredStaticFields;
+
+    /* when using a native debugger, set this to suppress watchdog timers */
+    bool        nativeDebuggerActive;
+
+    /*
+     * JDWP debugger support.
+     *
+     * Note: Each thread will normally determine whether the debugger is active
+     * for it by referring to its subMode flags.  "debuggerActive" here should be
+     * seen as "debugger is making requests of 1 or more threads".
+     */
+    bool        debuggerConnected;      /* debugger or DDMS is connected */
+    bool        debuggerActive;         /* debugger is making requests */
+    JdwpState*  jdwpState;
+
+    /*
+     * Registry of objects known to the debugger.
+     */
+    HashTable*  dbgRegistry;
+
+    /*
+     * Debugger breakpoint table.
+     */
+    BreakpointSet*  breakpointSet;
+
+    /*
+     * Single-step control struct.  We currently only allow one thread to
+     * be single-stepping at a time, which is all that really makes sense,
+     * but it's possible we may need to expand this to be per-thread.
+     */
+    StepControl stepControl;
+
+    /*
+     * DDM features embedded in the VM.
+     */
+    bool        ddmThreadNotification;
+
+    /*
+     * Zygote (partially-started process) support
+     */
+    bool        zygote;
+
+    /*
+     * Used for tracking allocations that we report to DDMS.  When the feature
+     * is enabled (through a DDMS request) the "allocRecords" pointer becomes
+     * non-NULL.
+     */
+    pthread_mutex_t allocTrackerLock;
+    AllocRecord*    allocRecords;
+    int             allocRecordHead;        /* most-recently-added entry */
+    int             allocRecordCount;       /* #of valid entries */
+
+    /*
+     * When a profiler is enabled, this is incremented.  Distinct profilers
+     * include "dmtrace" method tracing, emulator method tracing, and
+     * possibly instruction counting.
+     *
+     * The purpose of this is to have a single value that shows whether any
+     * profiling is going on.  Individual thread will normally check their
+     * thread-private subMode flags to take any profiling action.
+     */
+    volatile int activeProfilers;
+
+    /*
+     * State for method-trace profiling.
+     */
+    MethodTraceState methodTrace;
+    Method*     methodTraceGcMethod;
+    Method*     methodTraceClassPrepMethod;
+
+    /*
+     * State for emulator tracing.
+     */
+    void*       emulatorTracePage;
+    int         emulatorTraceEnableCount;
+
+    /*
+     * Global state for memory allocation profiling.
+     */
+    AllocProfState allocProf;
+
+    /*
+     * Pointers to the original methods for things that have been inlined.
+     * This makes it easy for us to output method entry/exit records for
+     * the method calls we're not actually making.  (Used by method
+     * profiling.)
+     */
+    Method**    inlinedMethods;
+
+    /*
+     * Dalvik instruction counts (kNumPackedOpcodes entries).
+     */
+    int*        executedInstrCounts;
+    int         instructionCountEnableCount;
+
+    /*
+     * Signal catcher thread (for SIGQUIT).
+     */
+    pthread_t   signalCatcherHandle;
+    bool        haltSignalCatcher;
+
+    /*
+     * Stdout/stderr conversion thread.
+     */
+    bool            haltStdioConverter;
+    bool            stdioConverterReady;
+    pthread_t       stdioConverterHandle;
+    pthread_mutex_t stdioConverterLock;
+    pthread_cond_t  stdioConverterCond;
+    int             stdoutPipe[2];
+    int             stderrPipe[2];
+
+    /*
+     * pid of the system_server process. We track it so that when system server
+     * crashes the Zygote process will be killed and restarted.
+     */
+    pid_t systemServerPid;
+
+    int kernelGroupScheduling;
+
+//#define COUNT_PRECISE_METHODS
+#ifdef COUNT_PRECISE_METHODS
+    PointerSet* preciseMethods;
+#endif
+
+    /* some RegisterMap statistics, useful during development */
+    void*       registerMapStats;
+
+#ifdef VERIFIER_STATS
+    VerifierStats verifierStats;
+#endif
+
+    /* String pointed here will be deposited on the stack frame of dvmAbort */
+    const char *lastMessage;
+};
+
+extern struct DvmGlobals gDvm;
+
+#if defined(WITH_JIT)
+
+/* Trace profiling modes.  Ordering matters - off states before on states */
+enum TraceProfilingModes {
+    kTraceProfilingDisabled = 0,      // Not profiling
+    kTraceProfilingPeriodicOff = 1,   // Periodic profiling, off phase
+    kTraceProfilingContinuous = 2,    // Always profiling
+    kTraceProfilingPeriodicOn = 3     // Periodic profiling, on phase
+};
+
+/*
+ * Exiting the compiled code w/o chaining will incur overhead to look up the
+ * target in the code cache which is extra work only when JIT is enabled. So
+ * we want to monitor it closely to make sure we don't have performance bugs.
+ */
+enum NoChainExits {
+    kInlineCacheMiss = 0,
+    kCallsiteInterpreted,
+    kSwitchOverflow,
+    kHeavyweightMonitor,
+    kNoChainExitLast,
+};
+
+/*
+ * 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 compilation trigger threshold counters */
+    unsigned char *pProfTable;
+
+    /* Trace profiling counters */
+    struct JitTraceProfCounters *pJitTraceProfCounters;
+
+    /* Copy of pProfTable used for temporarily disabling the Jit */
+    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;
+
+    /* Bytes allocated for the code cache */
+    unsigned int codeCacheSize;
+
+    /* Trigger for trace selection */
+    unsigned short threshold;
+
+    /* JIT Compiler Control */
+    bool               haltCompilerThread;
+    bool               blockingMode;
+    bool               methodTraceSupport;
+    bool               genSuspendPoll;
+    Thread*            compilerThread;
+    pthread_t          compilerHandle;
+    pthread_mutex_t    compilerLock;
+    pthread_mutex_t    compilerICPatchLock;
+    pthread_cond_t     compilerQueueActivity;
+    pthread_cond_t     compilerQueueEmpty;
+    volatile int       compilerQueueLength;
+    int                compilerHighWater;
+    int                compilerWorkEnqueueIndex;
+    int                compilerWorkDequeueIndex;
+    int                compilerICPatchIndex;
+
+    /* JIT internal stats */
+    int                compilerMaxQueued;
+    int                translationChains;
+
+    /* Compiled code cache */
+    void* codeCache;
+
+    /*
+     * This is used to store the base address of an in-flight compilation whose
+     * class object pointers have been calculated to populate literal pool.
+     * Once the compiler thread has changed its status to VM_WAIT, we cannot
+     * guarantee whether GC has happened before the code address has been
+     * installed to the JIT table. Because of that, this field can only
+     * been cleared/overwritten by the compiler thread if it is in the
+     * THREAD_RUNNING state or in a safe point.
+     */
+    void *inflightBaseAddr;
+
+    /* Translation cache version (protected by compilerLock */
+    int cacheVersion;
+
+    /* 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;
+
+    /* Page size  - 1 */
+    unsigned int pageSizeMask;
+
+    /* Lock to change the protection type of the code cache */
+    pthread_mutex_t    codeCacheProtectionLock;
+
+    /* Number of times that the code cache has been reset */
+    int numCodeCacheReset;
+
+    /* Number of times that the code cache reset request has been delayed */
+    int numCodeCacheResetDelayed;
+
+    /* 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[(kNumPackedOpcodes+7)/8];
+
+    /* Disable JIT for selected methods */
+    HashTable *methodTable;
+
+    /* Flag to dump all compiled code */
+    bool printMe;
+
+    /* Per-process debug flag toggled when receiving a SIGUSR2 */
+    bool receivedSIGUSR2;
+
+    /* Trace profiling mode */
+    TraceProfilingModes profileMode;
+
+    /* Periodic trace profiling countdown timer */
+    int profileCountdown;
+
+    /* Vector to disable selected optimizations */
+    int disableOpt;
+
+    /* Table to track the overall and trace statistics of hot methods */
+    HashTable*  methodStatsTable;
+
+    /* Filter method compilation blacklist with call-graph information */
+    bool checkCallGraph;
+
+    /* New translation chain has been set up */
+    volatile bool hasNewChain;
+
+#if defined(WITH_SELF_VERIFICATION)
+    /* Spin when error is detected, volatile so GDB can reset it */
+    volatile bool selfVerificationSpin;
+#endif
+
+    /* Framework or stand-alone? */
+    bool runningInAndroidFramework;
+
+    /* Framework callback happened? */
+    bool alreadyEnabledViaFramework;
+
+    /* Framework requests to disable the JIT for good */
+    bool disableJit;
+
+#if defined(SIGNATURE_BREAKPOINT)
+    /* Signature breakpoint */
+    u4 signatureBreakpointSize;         // # of words
+    u4 *signatureBreakpoint;            // Signature content
+#endif
+
+#if defined(WITH_JIT_TUNING)
+    /* Performance tuning counters */
+    int                addrLookupsFound;
+    int                addrLookupsNotFound;
+    int                noChainExit[kNoChainExitLast];
+    int                normalExit;
+    int                puntExit;
+    int                invokeMonomorphic;
+    int                invokePolymorphic;
+    int                invokeNative;
+    int                invokeMonoGetterInlined;
+    int                invokeMonoSetterInlined;
+    int                invokePolyGetterInlined;
+    int                invokePolySetterInlined;
+    int                returnOp;
+    int                icPatchInit;
+    int                icPatchLockFree;
+    int                icPatchQueued;
+    int                icPatchRejected;
+    int                icPatchDropped;
+    int                codeCachePatches;
+    int                numCompilerThreadBlockGC;
+    u8                 jitTime;
+    u8                 compilerThreadBlockGCStart;
+    u8                 compilerThreadBlockGCTime;
+    u8                 maxCompilerThreadBlockGCTime;
+#endif
+
+    /* Place arrays at the end to ease the display in gdb sessions */
+
+    /* Work order queue for compilations */
+    CompilerWorkOrder compilerWorkQueue[COMPILER_WORK_QUEUE_SIZE];
+
+    /* Work order queue for predicted chain patching */
+    ICPatchWorkOrder compilerICPatchQueue[COMPILER_IC_PATCH_QUEUE_SIZE];
+};
+
+extern struct DvmJitGlobals gDvmJit;
+
+#if defined(WITH_JIT_TUNING)
+extern int gDvmICHitCount;
+#endif
+
+#endif
+
+struct DvmJniGlobals {
+    bool useCheckJni;
+    bool warnOnly;
+    bool forceCopy;
+
+    // Provide backwards compatibility for pre-ICS apps on ICS.
+    bool workAroundAppJniBugs;
+
+    // Debugging help for third-party developers. Similar to -Xjnitrace.
+    bool logThirdPartyJni;
+
+    // We only support a single JavaVM per process.
+    JavaVM*     jniVm;
+};
+
+extern struct DvmJniGlobals gDvmJni;
+
+#endif  // DALVIK_GLOBALS_H_
diff --git a/vm/Hash.cpp b/vm/Hash.cpp
new file mode 100644
index 0000000..39d9d86
--- /dev/null
+++ b/vm/Hash.cpp
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+/*
+ * Hash table.  The dominant calls are add and lookup, with removals
+ * happening very infrequently.  We use probing, and don't worry much
+ * about tombstone removal.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+/* table load factor, i.e. how full can it get before we resize */
+//#define LOAD_NUMER  3       // 75%
+//#define LOAD_DENOM  4
+#define LOAD_NUMER  5       // 62.5%
+#define LOAD_DENOM  8
+//#define LOAD_NUMER  1       // 50%
+//#define LOAD_DENOM  2
+
+/*
+ * Compute the capacity needed for a table to hold "size" elements.
+ */
+size_t dvmHashSize(size_t size) {
+    return (size * LOAD_DENOM) / LOAD_NUMER +1;
+}
+
+
+/*
+ * Create and initialize a hash table.
+ */
+HashTable* dvmHashTableCreate(size_t initialSize, HashFreeFunc freeFunc)
+{
+    HashTable* pHashTable;
+
+    assert(initialSize > 0);
+
+    pHashTable = (HashTable*) malloc(sizeof(*pHashTable));
+    if (pHashTable == NULL)
+        return NULL;
+
+    dvmInitMutex(&pHashTable->lock);
+
+    pHashTable->tableSize = dexRoundUpPower2(initialSize);
+    pHashTable->numEntries = pHashTable->numDeadEntries = 0;
+    pHashTable->freeFunc = freeFunc;
+    pHashTable->pEntries =
+        (HashEntry*) malloc(pHashTable->tableSize * sizeof(HashEntry));
+    if (pHashTable->pEntries == NULL) {
+        free(pHashTable);
+        return NULL;
+    }
+
+    memset(pHashTable->pEntries, 0, pHashTable->tableSize * sizeof(HashEntry));
+    return pHashTable;
+}
+
+/*
+ * Clear out all entries.
+ */
+void dvmHashTableClear(HashTable* pHashTable)
+{
+    HashEntry* pEnt;
+    int i;
+
+    pEnt = pHashTable->pEntries;
+    for (i = 0; i < pHashTable->tableSize; i++, pEnt++) {
+        if (pEnt->data == HASH_TOMBSTONE) {
+            // nuke entry
+            pEnt->data = NULL;
+        } else if (pEnt->data != NULL) {
+            // call free func then nuke entry
+            if (pHashTable->freeFunc != NULL)
+                (*pHashTable->freeFunc)(pEnt->data);
+            pEnt->data = NULL;
+        }
+    }
+
+    pHashTable->numEntries = 0;
+    pHashTable->numDeadEntries = 0;
+}
+
+/*
+ * Free the table.
+ */
+void dvmHashTableFree(HashTable* pHashTable)
+{
+    if (pHashTable == NULL)
+        return;
+    dvmHashTableClear(pHashTable);
+    free(pHashTable->pEntries);
+    free(pHashTable);
+}
+
+#ifndef NDEBUG
+/*
+ * Count up the number of tombstone entries in the hash table.
+ */
+static int countTombStones(HashTable* pHashTable)
+{
+    int i, count;
+
+    for (count = i = 0; i < pHashTable->tableSize; i++) {
+        if (pHashTable->pEntries[i].data == HASH_TOMBSTONE)
+            count++;
+    }
+    return count;
+}
+#endif
+
+/*
+ * Resize a hash table.  We do this when adding an entry increased the
+ * size of the table beyond its comfy limit.
+ *
+ * This essentially requires re-inserting all elements into the new storage.
+ *
+ * If multiple threads can access the hash table, the table's lock should
+ * have been grabbed before issuing the "lookup+add" call that led to the
+ * resize, so we don't have a synchronization problem here.
+ */
+static bool resizeHash(HashTable* pHashTable, int newSize)
+{
+    HashEntry* pNewEntries;
+    int i;
+
+    assert(countTombStones(pHashTable) == pHashTable->numDeadEntries);
+    //LOGI("before: dead=%d", pHashTable->numDeadEntries);
+
+    pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashEntry));
+    if (pNewEntries == NULL)
+        return false;
+
+    for (i = 0; i < pHashTable->tableSize; i++) {
+        void* data = pHashTable->pEntries[i].data;
+        if (data != NULL && data != HASH_TOMBSTONE) {
+            int hashValue = pHashTable->pEntries[i].hashValue;
+            int newIdx;
+
+            /* probe for new spot, wrapping around */
+            newIdx = hashValue & (newSize-1);
+            while (pNewEntries[newIdx].data != NULL)
+                newIdx = (newIdx + 1) & (newSize-1);
+
+            pNewEntries[newIdx].hashValue = hashValue;
+            pNewEntries[newIdx].data = data;
+        }
+    }
+
+    free(pHashTable->pEntries);
+    pHashTable->pEntries = pNewEntries;
+    pHashTable->tableSize = newSize;
+    pHashTable->numDeadEntries = 0;
+
+    assert(countTombStones(pHashTable) == 0);
+    return true;
+}
+
+/*
+ * Look up an entry.
+ *
+ * We probe on collisions, wrapping around the table.
+ */
+void* dvmHashTableLookup(HashTable* pHashTable, u4 itemHash, void* item,
+    HashCompareFunc cmpFunc, bool doAdd)
+{
+    HashEntry* pEntry;
+    HashEntry* pEnd;
+    void* result = NULL;
+
+    assert(pHashTable->tableSize > 0);
+    assert(item != HASH_TOMBSTONE);
+    assert(item != NULL);
+
+    /* jump to the first entry and probe for a match */
+    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
+    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
+    while (pEntry->data != NULL) {
+        if (pEntry->data != HASH_TOMBSTONE &&
+            pEntry->hashValue == itemHash &&
+            (*cmpFunc)(pEntry->data, item) == 0)
+        {
+            /* match */
+            //LOGD("+++ match on entry %d", pEntry - pHashTable->pEntries);
+            break;
+        }
+
+        pEntry++;
+        if (pEntry == pEnd) {     /* wrap around to start */
+            if (pHashTable->tableSize == 1)
+                break;      /* edge case - single-entry table */
+            pEntry = pHashTable->pEntries;
+        }
+
+        //LOGI("+++ look probing %d...", pEntry - pHashTable->pEntries);
+    }
+
+    if (pEntry->data == NULL) {
+        if (doAdd) {
+            pEntry->hashValue = itemHash;
+            pEntry->data = item;
+            pHashTable->numEntries++;
+
+            /*
+             * We've added an entry.  See if this brings us too close to full.
+             */
+            if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM
+                > pHashTable->tableSize * LOAD_NUMER)
+            {
+                if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) {
+                    /* don't really have a way to indicate failure */
+                    LOGE("Dalvik hash resize failure");
+                    dvmAbort();
+                }
+                /* note "pEntry" is now invalid */
+            } else {
+                //LOGW("okay %d/%d/%d",
+                //    pHashTable->numEntries, pHashTable->tableSize,
+                //    (pHashTable->tableSize * LOAD_NUMER) / LOAD_DENOM);
+            }
+
+            /* full table is bad -- search for nonexistent never halts */
+            assert(pHashTable->numEntries < pHashTable->tableSize);
+            result = item;
+        } else {
+            assert(result == NULL);
+        }
+    } else {
+        result = pEntry->data;
+    }
+
+    return result;
+}
+
+/*
+ * Remove an entry from the table.
+ *
+ * Does NOT invoke the "free" function on the item.
+ */
+bool dvmHashTableRemove(HashTable* pHashTable, u4 itemHash, void* item)
+{
+    HashEntry* pEntry;
+    HashEntry* pEnd;
+
+    assert(pHashTable->tableSize > 0);
+
+    /* jump to the first entry and probe for a match */
+    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
+    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
+    while (pEntry->data != NULL) {
+        if (pEntry->data == item) {
+            //LOGI("+++ stepping on entry %d", pEntry - pHashTable->pEntries);
+            pEntry->data = HASH_TOMBSTONE;
+            pHashTable->numEntries--;
+            pHashTable->numDeadEntries++;
+            return true;
+        }
+
+        pEntry++;
+        if (pEntry == pEnd) {     /* wrap around to start */
+            if (pHashTable->tableSize == 1)
+                break;      /* edge case - single-entry table */
+            pEntry = pHashTable->pEntries;
+        }
+
+        //LOGI("+++ del probing %d...", pEntry - pHashTable->pEntries);
+    }
+
+    return false;
+}
+
+/*
+ * Scan every entry in the hash table and evaluate it with the specified
+ * indirect function call. If the function returns 1, remove the entry from
+ * the table.
+ *
+ * Does NOT invoke the "free" function on the item.
+ *
+ * Returning values other than 0 or 1 will abort the routine.
+ */
+int dvmHashForeachRemove(HashTable* pHashTable, HashForeachRemoveFunc func)
+{
+    int i, val;
+
+    for (i = 0; i < pHashTable->tableSize; i++) {
+        HashEntry* pEnt = &pHashTable->pEntries[i];
+
+        if (pEnt->data != NULL && pEnt->data != HASH_TOMBSTONE) {
+            val = (*func)(pEnt->data);
+            if (val == 1) {
+                pEnt->data = HASH_TOMBSTONE;
+                pHashTable->numEntries--;
+                pHashTable->numDeadEntries++;
+            }
+            else if (val != 0) {
+                return val;
+            }
+        }
+    }
+    return 0;
+}
+
+
+/*
+ * Execute a function on every entry in the hash table.
+ *
+ * If "func" returns a nonzero value, terminate early and return the value.
+ */
+int dvmHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg)
+{
+    int i, val;
+
+    for (i = 0; i < pHashTable->tableSize; i++) {
+        HashEntry* pEnt = &pHashTable->pEntries[i];
+
+        if (pEnt->data != NULL && pEnt->data != HASH_TOMBSTONE) {
+            val = (*func)(pEnt->data, arg);
+            if (val != 0)
+                return val;
+        }
+    }
+
+    return 0;
+}
+
+
+/*
+ * Look up an entry, counting the number of times we have to probe.
+ *
+ * Returns -1 if the entry wasn't found.
+ */
+static int countProbes(HashTable* pHashTable, u4 itemHash, const void* item,
+    HashCompareFunc cmpFunc)
+{
+    HashEntry* pEntry;
+    HashEntry* pEnd;
+    int count = 0;
+
+    assert(pHashTable->tableSize > 0);
+    assert(item != HASH_TOMBSTONE);
+    assert(item != NULL);
+
+    /* jump to the first entry and probe for a match */
+    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
+    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
+    while (pEntry->data != NULL) {
+        if (pEntry->data != HASH_TOMBSTONE &&
+            pEntry->hashValue == itemHash &&
+            (*cmpFunc)(pEntry->data, item) == 0)
+        {
+            /* match */
+            break;
+        }
+
+        pEntry++;
+        if (pEntry == pEnd) {     /* wrap around to start */
+            if (pHashTable->tableSize == 1)
+                break;      /* edge case - single-entry table */
+            pEntry = pHashTable->pEntries;
+        }
+
+        count++;
+    }
+    if (pEntry->data == NULL)
+        return -1;
+
+    return count;
+}
+
+/*
+ * Evaluate the amount of probing required for the specified hash table.
+ *
+ * We do this by running through all entries in the hash table, computing
+ * the hash value and then doing a lookup.
+ *
+ * The caller should lock the table before calling here.
+ */
+void dvmHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
+    HashCompareFunc cmpFunc)
+{
+    int numEntries, minProbe, maxProbe, totalProbe;
+    HashIter iter;
+
+    numEntries = maxProbe = totalProbe = 0;
+    minProbe = 65536*32767;
+
+    for (dvmHashIterBegin(pHashTable, &iter); !dvmHashIterDone(&iter);
+        dvmHashIterNext(&iter))
+    {
+        const void* data = (const void*)dvmHashIterData(&iter);
+        int count;
+
+        count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
+
+        numEntries++;
+
+        if (count < minProbe)
+            minProbe = count;
+        if (count > maxProbe)
+            maxProbe = count;
+        totalProbe += count;
+    }
+
+    LOGI("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f",
+        minProbe, maxProbe, totalProbe, numEntries, pHashTable->tableSize,
+        (float) totalProbe / (float) numEntries);
+}
diff --git a/vm/Hash.h b/vm/Hash.h
new file mode 100644
index 0000000..38f710f
--- /dev/null
+++ b/vm/Hash.h
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+/*
+ * General purpose hash table, used for finding classes, methods, etc.
+ *
+ * When the number of elements reaches a certain percentage of the table's
+ * capacity, the table will be resized.
+ */
+#ifndef DALVIK_HASH_H_
+#define DALVIK_HASH_H_
+
+/* compute the hash of an item with a specific type */
+typedef u4 (*HashCompute)(const void* item);
+
+/*
+ * Compare a hash entry with a "loose" item after their hash values match.
+ * Returns { <0, 0, >0 } depending on ordering of items (same semantics
+ * as strcmp()).
+ */
+typedef int (*HashCompareFunc)(const void* tableItem, const void* looseItem);
+
+/*
+ * This function will be used to free entries in the table.  This can be
+ * NULL if no free is required, free(), or a custom function.
+ */
+typedef void (*HashFreeFunc)(void* ptr);
+
+/*
+ * Used by dvmHashForeach().
+ */
+typedef int (*HashForeachFunc)(void* data, void* arg);
+
+/*
+ * Used by dvmHashForeachRemove().
+ */
+typedef int (*HashForeachRemoveFunc)(void* data);
+
+/*
+ * One entry in the hash table.  "data" values are expected to be (or have
+ * the same characteristics as) valid pointers.  In particular, a NULL
+ * value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates
+ * a no-longer-used slot that must be stepped over during probing.
+ *
+ * Attempting to add a NULL or tombstone value is an error.
+ *
+ * When an entry is released, we will call (HashFreeFunc)(entry->data).
+ */
+struct HashEntry {
+    u4 hashValue;
+    void* data;
+};
+
+#define HASH_TOMBSTONE ((void*) 0xcbcacccd)     // invalid ptr value
+
+/*
+ * Expandable hash table.
+ *
+ * This structure should be considered opaque.
+ */
+struct HashTable {
+    int         tableSize;          /* must be power of 2 */
+    int         numEntries;         /* current #of "live" entries */
+    int         numDeadEntries;     /* current #of tombstone entries */
+    HashEntry*  pEntries;           /* array on heap */
+    HashFreeFunc freeFunc;
+    pthread_mutex_t lock;
+};
+
+/*
+ * Create and initialize a HashTable structure, using "initialSize" as
+ * a basis for the initial capacity of the table.  (The actual initial
+ * table size may be adjusted upward.)  If you know exactly how many
+ * elements the table will hold, pass the result from dvmHashSize() in.)
+ *
+ * Returns "false" if unable to allocate the table.
+ */
+HashTable* dvmHashTableCreate(size_t initialSize, HashFreeFunc freeFunc);
+
+/*
+ * Compute the capacity needed for a table to hold "size" elements.  Use
+ * this when you know ahead of time how many elements the table will hold.
+ * Pass this value into dvmHashTableCreate() to ensure that you can add
+ * all elements without needing to reallocate the table.
+ */
+size_t dvmHashSize(size_t size);
+
+/*
+ * Clear out a hash table, freeing the contents of any used entries.
+ */
+void dvmHashTableClear(HashTable* pHashTable);
+
+/*
+ * Free a hash table.  Performs a "clear" first.
+ */
+void dvmHashTableFree(HashTable* pHashTable);
+
+/*
+ * Exclusive access.  Important when adding items to a table, or when
+ * doing any operations on a table that could be added to by another thread.
+ */
+INLINE void dvmHashTableLock(HashTable* pHashTable) {
+    dvmLockMutex(&pHashTable->lock);
+}
+INLINE void dvmHashTableUnlock(HashTable* pHashTable) {
+    dvmUnlockMutex(&pHashTable->lock);
+}
+
+/*
+ * Get #of entries in hash table.
+ */
+INLINE int dvmHashTableNumEntries(HashTable* pHashTable) {
+    return pHashTable->numEntries;
+}
+
+/*
+ * Get total size of hash table (for memory usage calculations).
+ */
+INLINE int dvmHashTableMemUsage(HashTable* pHashTable) {
+    return sizeof(HashTable) + pHashTable->tableSize * sizeof(HashEntry);
+}
+
+/*
+ * Look up an entry in the table, possibly adding it if it's not there.
+ *
+ * If "item" is not found, and "doAdd" is false, NULL is returned.
+ * Otherwise, a pointer to the found or added item is returned.  (You can
+ * tell the difference by seeing if return value == item.)
+ *
+ * An "add" operation may cause the entire table to be reallocated.  Don't
+ * forget to lock the table before calling this.
+ */
+void* dvmHashTableLookup(HashTable* pHashTable, u4 itemHash, void* item,
+    HashCompareFunc cmpFunc, bool doAdd);
+
+/*
+ * Remove an item from the hash table, given its "data" pointer.  Does not
+ * invoke the "free" function; just detaches it from the table.
+ */
+bool dvmHashTableRemove(HashTable* pHashTable, u4 hash, void* item);
+
+/*
+ * Execute "func" on every entry in the hash table.
+ *
+ * If "func" returns a nonzero value, terminate early and return the value.
+ */
+int dvmHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg);
+
+/*
+ * Execute "func" on every entry in the hash table.
+ *
+ * If "func" returns 1 detach the entry from the hash table. Does not invoke
+ * the "free" function.
+ *
+ * Returning values other than 0 or 1 from "func" will abort the routine.
+ */
+int dvmHashForeachRemove(HashTable* pHashTable, HashForeachRemoveFunc func);
+
+/*
+ * An alternative to dvmHashForeach(), using an iterator.
+ *
+ * Use like this:
+ *   HashIter iter;
+ *   for (dvmHashIterBegin(hashTable, &iter); !dvmHashIterDone(&iter);
+ *       dvmHashIterNext(&iter))
+ *   {
+ *       MyData* data = (MyData*)dvmHashIterData(&iter);
+ *   }
+ */
+struct HashIter {
+    void*       data;
+    HashTable*  pHashTable;
+    int         idx;
+};
+INLINE void dvmHashIterNext(HashIter* pIter) {
+    int i = pIter->idx +1;
+    int lim = pIter->pHashTable->tableSize;
+    for ( ; i < lim; i++) {
+        void* data = pIter->pHashTable->pEntries[i].data;
+        if (data != NULL && data != HASH_TOMBSTONE)
+            break;
+    }
+    pIter->idx = i;
+}
+INLINE void dvmHashIterBegin(HashTable* pHashTable, HashIter* pIter) {
+    pIter->pHashTable = pHashTable;
+    pIter->idx = -1;
+    dvmHashIterNext(pIter);
+}
+INLINE bool dvmHashIterDone(HashIter* pIter) {
+    return (pIter->idx >= pIter->pHashTable->tableSize);
+}
+INLINE void* dvmHashIterData(HashIter* pIter) {
+    assert(pIter->idx >= 0 && pIter->idx < pIter->pHashTable->tableSize);
+    return pIter->pHashTable->pEntries[pIter->idx].data;
+}
+
+
+/*
+ * Evaluate hash table performance by examining the number of times we
+ * have to probe for an entry.
+ *
+ * The caller should lock the table beforehand.
+ */
+typedef u4 (*HashCalcFunc)(const void* item);
+void dvmHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
+    HashCompareFunc cmpFunc);
+
+#endif  // DALVIK_HASH_H_
diff --git a/vm/IndirectRefTable.cpp b/vm/IndirectRefTable.cpp
new file mode 100644
index 0000000..c38458d
--- /dev/null
+++ b/vm/IndirectRefTable.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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.
+ */
+
+/*
+ * Indirect reference table management.
+ */
+#include "Dalvik.h"
+
+static void abortMaybe() {
+    // If CheckJNI is on, it'll give a more detailed error before aborting.
+    // Otherwise, we want to abort rather than hand back a bad reference.
+    if (!gDvmJni.useCheckJni) {
+        dvmAbort();
+    }
+}
+
+bool IndirectRefTable::init(size_t initialCount,
+        size_t maxCount, IndirectRefKind desiredKind)
+{
+    assert(initialCount > 0);
+    assert(initialCount <= maxCount);
+    assert(desiredKind != kIndirectKindInvalid);
+
+    table_ = (IndirectRefSlot*) malloc(initialCount * sizeof(IndirectRefSlot));
+    if (table_ == NULL) {
+        return false;
+    }
+    memset(table_, 0xd1, initialCount * sizeof(IndirectRefSlot));
+
+    segmentState.all = IRT_FIRST_SEGMENT;
+    alloc_entries_ = initialCount;
+    max_entries_ = maxCount;
+    kind_ = desiredKind;
+
+    return true;
+}
+
+/*
+ * Clears out the contents of a IndirectRefTable, freeing allocated storage.
+ */
+void IndirectRefTable::destroy()
+{
+    free(table_);
+    table_ = NULL;
+    alloc_entries_ = max_entries_ = -1;
+}
+
+IndirectRef IndirectRefTable::add(u4 cookie, Object* obj)
+{
+    IRTSegmentState prevState;
+    prevState.all = cookie;
+    size_t topIndex = segmentState.parts.topIndex;
+
+    assert(obj != NULL);
+    assert(dvmIsHeapAddress(obj));
+    assert(table_ != NULL);
+    assert(alloc_entries_ <= max_entries_);
+    assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
+
+    /*
+     * We know there's enough room in the table.  Now we just need to find
+     * the right spot.  If there's a hole, find it and fill it; otherwise,
+     * add to the end of the list.
+     */
+    IndirectRef result;
+    IndirectRefSlot* slot;
+    int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles;
+    if (numHoles > 0) {
+        assert(topIndex > 1);
+        /* find the first hole; likely to be near the end of the list,
+         * we know the item at the topIndex is not a hole */
+        slot = &table_[topIndex - 1];
+        assert(slot->obj != NULL);
+        while ((--slot)->obj != NULL) {
+            assert(slot >= table_ + prevState.parts.topIndex);
+        }
+        segmentState.parts.numHoles--;
+    } else {
+        /* add to the end, grow if needed */
+        if (topIndex == alloc_entries_) {
+            /* reached end of allocated space; did we hit buffer max? */
+            if (topIndex == max_entries_) {
+                LOGE("JNI ERROR (app bug): %s reference table overflow (max=%d)",
+                        indirectRefKindToString(kind_), max_entries_);
+                return NULL;
+            }
+
+            size_t newSize = alloc_entries_ * 2;
+            if (newSize > max_entries_) {
+                newSize = max_entries_;
+            }
+            assert(newSize > alloc_entries_);
+
+            IndirectRefSlot* newTable =
+                    (IndirectRefSlot*) realloc(table_, newSize * sizeof(IndirectRefSlot));
+            if (table_ == NULL) {
+                LOGE("JNI ERROR (app bug): unable to expand %s reference table "
+                        "(from %d to %d, max=%d)",
+                        indirectRefKindToString(kind_),
+                        alloc_entries_, newSize, max_entries_);
+                return NULL;
+            }
+
+            memset(newTable + alloc_entries_, 0xd1,
+                   (newSize - alloc_entries_) * sizeof(IndirectRefSlot));
+
+            alloc_entries_ = newSize;
+            table_ = newTable;
+        }
+        slot = &table_[topIndex++];
+        segmentState.parts.topIndex = topIndex;
+    }
+
+    slot->obj = obj;
+    slot->serial = nextSerial(slot->serial);
+    result = toIndirectRef(slot - table_, slot->serial, kind_);
+
+    assert(result != NULL);
+    return result;
+}
+
+/*
+ * Get the referent of an indirect ref from the table.
+ *
+ * Returns kInvalidIndirectRefObject if iref is invalid.
+ */
+Object* IndirectRefTable::get(IndirectRef iref) const {
+    IndirectRefKind kind = indirectRefKind(iref);
+    if (kind != kind_) {
+        if (iref == NULL) {
+            LOGW("Attempt to look up NULL %s reference", indirectRefKindToString(kind_));
+            return kInvalidIndirectRefObject;
+        }
+        if (kind == kIndirectKindInvalid) {
+            LOGE("JNI ERROR (app bug): invalid %s reference %p",
+                    indirectRefKindToString(kind_), iref);
+            abortMaybe();
+            return kInvalidIndirectRefObject;
+        }
+        // References of the requested kind cannot appear within this table.
+        return kInvalidIndirectRefObject;
+    }
+
+    u4 topIndex = segmentState.parts.topIndex;
+    u4 index = extractIndex(iref);
+    if (index >= topIndex) {
+        /* bad -- stale reference? */
+        LOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)",
+                indirectRefKindToString(kind_), iref, index, topIndex);
+        abortMaybe();
+        return kInvalidIndirectRefObject;
+    }
+
+    Object* obj = table_[index].obj;
+    if (obj == NULL) {
+        LOGI("JNI ERROR (app bug): accessed deleted %s reference %p",
+                indirectRefKindToString(kind_), iref);
+        abortMaybe();
+        return kInvalidIndirectRefObject;
+    }
+
+    u4 serial = extractSerial(iref);
+    if (serial != table_[index].serial) {
+        LOGE("JNI ERROR (app bug): attempt to use stale %s reference %p",
+                indirectRefKindToString(kind_), iref);
+        abortMaybe();
+        return kInvalidIndirectRefObject;
+    }
+
+    return obj;
+}
+
+static int findObject(const Object* obj, int bottomIndex, int topIndex,
+        const IndirectRefSlot* table) {
+    for (int i = bottomIndex; i < topIndex; ++i) {
+        if (table[i].obj == obj) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+bool IndirectRefTable::contains(const Object* obj) const {
+    return findObject(obj, 0, segmentState.parts.topIndex, table_) >= 0;
+}
+
+/*
+ * Remove "obj" from "pRef".  We extract the table offset bits from "iref"
+ * and zap the corresponding entry, leaving a hole if it's not at the top.
+ *
+ * If the entry is not between the current top index and the bottom index
+ * specified by the cookie, we don't remove anything.  This is the behavior
+ * required by JNI's DeleteLocalRef function.
+ *
+ * Note this is NOT called when a local frame is popped.  This is only used
+ * for explicit single removals.
+ *
+ * Returns "false" if nothing was removed.
+ */
+bool IndirectRefTable::remove(u4 cookie, IndirectRef iref)
+{
+    IRTSegmentState prevState;
+    prevState.all = cookie;
+    u4 topIndex = segmentState.parts.topIndex;
+    u4 bottomIndex = prevState.parts.topIndex;
+
+    assert(table_ != NULL);
+    assert(alloc_entries_ <= max_entries_);
+    assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
+
+    IndirectRefKind kind = indirectRefKind(iref);
+    u4 index;
+    if (kind == kind_) {
+        index = extractIndex(iref);
+        if (index < bottomIndex) {
+            /* wrong segment */
+            LOGV("Attempt to remove index outside index area (%ud vs %ud-%ud)",
+                    index, bottomIndex, topIndex);
+            return false;
+        }
+        if (index >= topIndex) {
+            /* bad -- stale reference? */
+            LOGD("Attempt to remove invalid index %ud (bottom=%ud top=%ud)",
+                    index, bottomIndex, topIndex);
+            return false;
+        }
+        if (table_[index].obj == NULL) {
+            LOGD("Attempt to remove cleared %s reference %p",
+                    indirectRefKindToString(kind_), iref);
+            return false;
+        }
+        u4 serial = extractSerial(iref);
+        if (table_[index].serial != serial) {
+            LOGD("Attempt to remove stale %s reference %p",
+                    indirectRefKindToString(kind_), iref);
+            return false;
+        }
+    } else if (kind == kIndirectKindInvalid && gDvmJni.workAroundAppJniBugs) {
+        // reference looks like a pointer, scan the table to find the index
+        int i = findObject(reinterpret_cast<Object*>(iref), bottomIndex, topIndex, table_);
+        if (i < 0) {
+            LOGW("trying to work around app JNI bugs, but didn't find %p in table!", iref);
+            return false;
+        }
+        index = i;
+    } else {
+        // References of the requested kind cannot appear within this table.
+        return false;
+    }
+
+    if (index == topIndex - 1) {
+        // Top-most entry.  Scan up and consume holes.
+        int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles;
+        if (numHoles != 0) {
+            while (--topIndex > bottomIndex && numHoles != 0) {
+                LOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p",
+                    topIndex-1, cookie, table_[topIndex-1].obj);
+                if (table_[topIndex-1].obj != NULL) {
+                    break;
+                }
+                LOGV("+++ ate hole at %d", topIndex-1);
+                numHoles--;
+            }
+            segmentState.parts.numHoles = numHoles + prevState.parts.numHoles;
+            segmentState.parts.topIndex = topIndex;
+        } else {
+            segmentState.parts.topIndex = topIndex-1;
+            LOGV("+++ ate last entry %d", topIndex-1);
+        }
+    } else {
+        /*
+         * Not the top-most entry.  This creates a hole.  We NULL out the
+         * entry to prevent somebody from deleting it twice and screwing up
+         * the hole count.
+         */
+        table_[index].obj = NULL;
+        segmentState.parts.numHoles++;
+        LOGV("+++ left hole at %d, holes=%d", index, segmentState.parts.numHoles);
+    }
+
+    return true;
+}
+
+const char* indirectRefKindToString(IndirectRefKind kind)
+{
+    switch (kind) {
+    case kIndirectKindInvalid:      return "invalid";
+    case kIndirectKindLocal:        return "local";
+    case kIndirectKindGlobal:       return "global";
+    case kIndirectKindWeakGlobal:   return "weak global";
+    default:                        return "UNKNOWN";
+    }
+}
+
+void IndirectRefTable::dump(const char* descr) const
+{
+    size_t count = capacity();
+    Object** copy = new Object*[count];
+    for (size_t i = 0; i < count; i++) {
+        copy[i] = table_[i].obj;
+    }
+    dvmDumpReferenceTableContents(copy, count, descr);
+    delete[] copy;
+}
diff --git a/vm/IndirectRefTable.h b/vm/IndirectRefTable.h
new file mode 100644
index 0000000..9172ada
--- /dev/null
+++ b/vm/IndirectRefTable.h
@@ -0,0 +1,367 @@
+/*
+ * 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_INDIRECTREFTABLE_H_
+#define DALVIK_INDIRECTREFTABLE_H_
+
+/*
+ * Maintain a table of indirect references.  Used for local/global JNI
+ * references.
+ *
+ * The table contains object references that are part of the GC root set.
+ * When an object is added we return an IndirectRef that is not a valid
+ * pointer but can be used to find the original value in O(1) time.
+ * Conversions to and from indirect refs are performed on JNI method calls
+ * in and out of the VM, so they need to be very fast.
+ *
+ * To be efficient for JNI local variable storage, we need to provide
+ * operations that allow us to operate on segments of the table, where
+ * segments are pushed and popped as if on a stack.  For example, deletion
+ * of an entry should only succeed if it appears in the current segment,
+ * and we want to be able to strip off the current segment quickly when
+ * a method returns.  Additions to the table must be made in the current
+ * segment even if space is available in an earlier area.
+ *
+ * A new segment is created when we call into native code from interpreted
+ * code, or when we handle the JNI PushLocalFrame function.
+ *
+ * The GC must be able to scan the entire table quickly.
+ *
+ * In summary, these must be very fast:
+ *  - adding or removing a segment
+ *  - adding references to a new segment
+ *  - converting an indirect reference back to an Object
+ * These can be a little slower, but must still be pretty quick:
+ *  - adding references to a "mature" segment
+ *  - removing individual references
+ *  - scanning the entire table straight through
+ *
+ * If there's more than one segment, we don't guarantee that the table
+ * will fill completely before we fail due to lack of space.  We do ensure
+ * that the current segment will pack tightly, which should satisfy JNI
+ * requirements (e.g. EnsureLocalCapacity).
+ *
+ * To make everything fit nicely in 32-bit integers, the maximum size of
+ * the table is capped at 64K.
+ *
+ * None of the table functions are synchronized.
+ */
+
+/*
+ * Indirect reference definition.  This must be interchangeable with JNI's
+ * jobject, and it's convenient to let null be null, so we use void*.
+ *
+ * We need a 16-bit table index and a 2-bit reference type (global, local,
+ * weak global).  Real object pointers will have zeroes in the low 2 or 3
+ * bits (4- or 8-byte alignment), so it's useful to put the ref type
+ * in the low bits and reserve zero as an invalid value.
+ *
+ * The remaining 14 bits can be used to detect stale indirect references.
+ * For example, if objects don't move, we can use a hash of the original
+ * Object* to make sure the entry hasn't been re-used.  (If the Object*
+ * we find there doesn't match because of heap movement, we could do a
+ * secondary check on the preserved hash value; this implies that creating
+ * a global/local ref queries the hash value and forces it to be saved.)
+ *
+ * A more rigorous approach would be to put a serial number in the extra
+ * bits, and keep a copy of the serial number in a parallel table.  This is
+ * easier when objects can move, but requires 2x the memory and additional
+ * memory accesses on add/get.  It will catch additional problems, e.g.:
+ * create iref1 for obj, delete iref1, create iref2 for same obj, lookup
+ * iref1.  A pattern based on object bits will miss this.
+ *
+ * For now, we use a serial number.
+ */
+typedef void* IndirectRef;
+
+/* magic failure value; must not pass dvmIsHeapAddress() */
+#define kInvalidIndirectRefObject reinterpret_cast<Object*>(0xdead4321)
+
+#define kClearedJniWeakGlobal reinterpret_cast<Object*>(0xdead1234)
+
+/*
+ * Indirect reference kind, used as the two low bits of IndirectRef.
+ *
+ * For convenience these match up with enum jobjectRefType from jni.h.
+ */
+enum IndirectRefKind {
+    kIndirectKindInvalid    = 0,
+    kIndirectKindLocal      = 1,
+    kIndirectKindGlobal     = 2,
+    kIndirectKindWeakGlobal = 3
+};
+const char* indirectRefKindToString(IndirectRefKind kind);
+
+/*
+ * Determine what kind of indirect reference this is.
+ */
+INLINE IndirectRefKind indirectRefKind(IndirectRef iref)
+{
+    return (IndirectRefKind)((u4) iref & 0x03);
+}
+
+/*
+ * Information we store for each slot in the reference table.
+ */
+struct IndirectRefSlot {
+    Object* obj;        /* object pointer itself, NULL if the slot is unused */
+    u4      serial;     /* slot serial number */
+};
+
+/* use as initial value for "cookie", and when table has only one segment */
+#define IRT_FIRST_SEGMENT   0
+
+/*
+ * Table definition.
+ *
+ * For the global reference table, the expected common operations are
+ * adding a new entry and removing a recently-added entry (usually the
+ * most-recently-added entry).  For JNI local references, the common
+ * operations are adding a new entry and removing an entire table segment.
+ *
+ * If "alloc_entries_" is not equal to "max_entries_", the table may expand
+ * when entries are added, which means the memory may move.  If you want
+ * to keep pointers into "table" rather than offsets, you must use a
+ * fixed-size table.
+ *
+ * If we delete entries from the middle of the list, we will be left with
+ * "holes".  We track the number of holes so that, when adding new elements,
+ * we can quickly decide to do a trivial append or go slot-hunting.
+ *
+ * When the top-most entry is removed, any holes immediately below it are
+ * also removed.  Thus, deletion of an entry may reduce "topIndex" by more
+ * than one.
+ *
+ * To get the desired behavior for JNI locals, we need to know the bottom
+ * and top of the current "segment".  The top is managed internally, and
+ * the bottom is passed in as a function argument (the VM keeps it in a
+ * slot in the interpreted stack frame).  When we call a native method or
+ * push a local frame, the current top index gets pushed on, and serves
+ * as the new bottom.  When we pop a frame off, the value from the stack
+ * becomes the new top index, and the value stored in the previous frame
+ * becomes the new bottom.
+ *
+ * To avoid having to re-scan the table after a pop, we want to push the
+ * number of holes in the table onto the stack.  Because of our 64K-entry
+ * cap, we can combine the two into a single unsigned 32-bit value.
+ * Instead of a "bottom" argument we take a "cookie", which includes the
+ * bottom index and the count of holes below the bottom.
+ *
+ * We need to minimize method call/return overhead.  If we store the
+ * "cookie" externally, on the interpreted call stack, the VM can handle
+ * pushes and pops with a single 4-byte load and store.  (We could also
+ * store it internally in a public structure, but the local JNI refs are
+ * logically tied to interpreted stack frames anyway.)
+ *
+ * Common alternative implementation: make IndirectRef a pointer to the
+ * actual reference slot.  Instead of getting a table and doing a lookup,
+ * the lookup can be done instantly.  Operations like determining the
+ * type and deleting the reference are more expensive because the table
+ * must be hunted for (i.e. you have to do a pointer comparison to see
+ * which table it's in), you can't move the table when expanding it (so
+ * realloc() is out), and tricks like serial number checking to detect
+ * stale references aren't possible (though we may be able to get similar
+ * benefits with other approaches).
+ *
+ * TODO: consider a "lastDeleteIndex" for quick hole-filling when an
+ * add immediately follows a delete; must invalidate after segment pop
+ * (which could increase the cost/complexity of method call/return).
+ * Might be worth only using it for JNI globals.
+ *
+ * TODO: may want completely different add/remove algorithms for global
+ * and local refs to improve performance.  A large circular buffer might
+ * reduce the amortized cost of adding global references.
+ *
+ * TODO: if we can guarantee that the underlying storage doesn't move,
+ * e.g. by using oversized mmap regions to handle expanding tables, we may
+ * be able to avoid having to synchronize lookups.  Might make sense to
+ * add a "synchronized lookup" call that takes the mutex as an argument,
+ * and either locks or doesn't lock based on internal details.
+ */
+union IRTSegmentState {
+    u4          all;
+    struct {
+        u4      topIndex:16;            /* index of first unused entry */
+        u4      numHoles:16;            /* #of holes in entire table */
+    } parts;
+};
+
+class iref_iterator {
+public:
+    explicit iref_iterator(IndirectRefSlot* table, size_t i, size_t capacity) :
+            table_(table), i_(i), capacity_(capacity) {
+        skipNullsAndTombstones();
+    }
+
+    iref_iterator& operator++() {
+        ++i_;
+        skipNullsAndTombstones();
+        return *this;
+    }
+
+    Object** operator*() {
+        return &table_[i_].obj;
+    }
+
+    bool equals(const iref_iterator& rhs) const {
+        return (i_ == rhs.i_ && table_ == rhs.table_);
+    }
+
+private:
+    void skipNullsAndTombstones() {
+        // We skip NULLs and tombstones. Clients don't want to see implementation details.
+        while (i_ < capacity_ && (table_[i_].obj == NULL
+                || table_[i_].obj == kClearedJniWeakGlobal)) {
+            ++i_;
+        }
+    }
+
+    IndirectRefSlot* table_;
+    size_t i_;
+    size_t capacity_;
+};
+
+bool inline operator!=(const iref_iterator& lhs, const iref_iterator& rhs) {
+    return !lhs.equals(rhs);
+}
+
+struct IndirectRefTable {
+public:
+    typedef iref_iterator iterator;
+
+    /* semi-public - read/write by interpreter in native call handler */
+    IRTSegmentState segmentState;
+
+    /*
+     * private:
+     *
+     * TODO: we can't make these private as long as the interpreter
+     * uses offsetof, since private member data makes us non-POD.
+     */
+    /* bottom of the stack */
+    IndirectRefSlot* table_;
+    /* bit mask, ORed into all irefs */
+    IndirectRefKind kind_;
+    /* #of entries we have space for */
+    size_t          alloc_entries_;
+    /* max #of entries allowed */
+    size_t          max_entries_;
+
+    // TODO: want hole-filling stats (#of holes filled, total entries scanned)
+    //       for performance evaluation.
+
+    /*
+     * Add a new entry.  "obj" must be a valid non-NULL object reference
+     * (though it's okay if it's not fully-formed, e.g. the result from
+     * dvmMalloc doesn't have obj->clazz set).
+     *
+     * Returns NULL if the table is full (max entries reached, or alloc
+     * failed during expansion).
+     */
+    IndirectRef add(u4 cookie, Object* obj);
+
+    /*
+     * Given an IndirectRef in the table, return the Object it refers to.
+     *
+     * Returns kInvalidIndirectRefObject if iref is invalid.
+     */
+    Object* get(IndirectRef iref) const;
+
+    /*
+     * Returns true if the table contains a reference to this object.
+     */
+    bool contains(const Object* obj) const;
+
+    /*
+     * Remove an existing entry.
+     *
+     * If the entry is not between the current top index and the bottom index
+     * specified by the cookie, we don't remove anything.  This is the behavior
+     * required by JNI's DeleteLocalRef function.
+     *
+     * Returns "false" if nothing was removed.
+     */
+    bool remove(u4 cookie, IndirectRef iref);
+
+    /*
+     * Initialize an IndirectRefTable.
+     *
+     * If "initialCount" != "maxCount", the table will expand as required.
+     *
+     * "kind" should be Local or Global.  The Global table may also hold
+     * WeakGlobal refs.
+     *
+     * Returns "false" if table allocation fails.
+     */
+    bool init(size_t initialCount, size_t maxCount, IndirectRefKind kind);
+
+    /*
+     * Clear out the contents, freeing allocated storage.
+     *
+     * You must call dvmInitReferenceTable() before you can re-use this table.
+     *
+     * TODO: this should be a destructor.
+     */
+    void destroy();
+
+    /*
+     * Dump the contents of a reference table to the log file.
+     *
+     * The caller should lock any external sync before calling.
+     *
+     * TODO: we should name the table in a constructor and remove
+     * the argument here.
+     */
+    void dump(const char* descr) const;
+
+    /*
+     * Return the #of entries in the entire table.  This includes holes, and
+     * so may be larger than the actual number of "live" entries.
+     */
+    size_t capacity() const {
+        return segmentState.parts.topIndex;
+    }
+
+    iterator begin() {
+        return iterator(table_, 0, capacity());
+    }
+
+    iterator end() {
+        return iterator(table_, capacity(), capacity());
+    }
+
+private:
+    static inline u4 extractIndex(IndirectRef iref) {
+        u4 uref = (u4) iref;
+        return (uref >> 2) & 0xffff;
+    }
+
+    static inline u4 extractSerial(IndirectRef iref) {
+        u4 uref = (u4) iref;
+        return uref >> 20;
+    }
+
+    static inline u4 nextSerial(u4 serial) {
+        return (serial + 1) & 0xfff;
+    }
+
+    static inline IndirectRef toIndirectRef(u4 index, u4 serial, IndirectRefKind kind) {
+        assert(index < 65536);
+        return reinterpret_cast<IndirectRef>((serial << 20) | (index << 2) | kind);
+    }
+};
+
+#endif  // DALVIK_INDIRECTREFTABLE_H_
diff --git a/vm/Init.cpp b/vm/Init.cpp
new file mode 100644
index 0000000..36ac269
--- /dev/null
+++ b/vm/Init.cpp
@@ -0,0 +1,1859 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik initialization, shutdown, and command-line argument processing.
+ */
+#define __STDC_LIMIT_MACROS
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <limits.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "Dalvik.h"
+#include "test/Test.h"
+#include "mterp/Mterp.h"
+#include "Hash.h"
+
+#define kMinHeapStartSize   (1*1024*1024)
+#define kMinHeapSize        (2*1024*1024)
+#define kMaxHeapSize        (1*1024*1024*1024)
+
+/*
+ * Register VM-agnostic native methods for system classes.
+ */
+extern int jniRegisterSystemMethods(JNIEnv* env);
+
+/* fwd */
+static bool registerSystemNatives(JNIEnv* pEnv);
+static bool initJdwp();
+static bool initZygote();
+
+
+/* global state */
+struct DvmGlobals gDvm;
+struct DvmJniGlobals gDvmJni;
+
+/* JIT-specific global state */
+#if defined(WITH_JIT)
+struct DvmJitGlobals gDvmJit;
+
+#if defined(WITH_JIT_TUNING)
+/*
+ * Track the number of hits in the inline cache for predicted chaining.
+ * Use an ugly global variable here since it is accessed in assembly code.
+ */
+int gDvmICHitCount;
+#endif
+
+#endif
+
+/*
+ * Show usage.
+ *
+ * We follow the tradition of unhyphenated compound words.
+ */
+static void usage(const char* progName)
+{
+    dvmFprintf(stderr, "%s: [options] class [argument ...]\n", progName);
+    dvmFprintf(stderr, "%s: [options] -jar file.jar [argument ...]\n",progName);
+    dvmFprintf(stderr, "\n");
+    dvmFprintf(stderr, "The following standard options are recognized:\n");
+    dvmFprintf(stderr, "  -classpath classpath\n");
+    dvmFprintf(stderr, "  -Dproperty=value\n");
+    dvmFprintf(stderr, "  -verbose:tag  ('gc', 'jni', or 'class')\n");
+    dvmFprintf(stderr, "  -ea[:<package name>... |:<class name>]\n");
+    dvmFprintf(stderr, "  -da[:<package name>... |:<class name>]\n");
+    dvmFprintf(stderr, "   (-enableassertions, -disableassertions)\n");
+    dvmFprintf(stderr, "  -esa\n");
+    dvmFprintf(stderr, "  -dsa\n");
+    dvmFprintf(stderr,
+                "   (-enablesystemassertions, -disablesystemassertions)\n");
+    dvmFprintf(stderr, "  -showversion\n");
+    dvmFprintf(stderr, "  -help\n");
+    dvmFprintf(stderr, "\n");
+    dvmFprintf(stderr, "The following extended options are recognized:\n");
+    dvmFprintf(stderr, "  -Xrunjdwp:<options>\n");
+    dvmFprintf(stderr, "  -Xbootclasspath:bootclasspath\n");
+    dvmFprintf(stderr, "  -Xcheck:tag  (e.g. 'jni')\n");
+    dvmFprintf(stderr, "  -XmsN  (min heap, must be multiple of 1K, >= 1MB)\n");
+    dvmFprintf(stderr, "  -XmxN  (max heap, must be multiple of 1K, >= 2MB)\n");
+    dvmFprintf(stderr, "  -XssN  (stack size, >= %dKB, <= %dKB)\n",
+        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");
+    dvmFprintf(stderr, "  -Xdexopt:{none,verified,all,full}\n");
+    dvmFprintf(stderr, "  -Xnoquithandler\n");
+    dvmFprintf(stderr,
+                "  -Xjnigreflimit:N  (must be multiple of 100, >= 200)\n");
+    dvmFprintf(stderr, "  -Xjniopts:{warnonly,forcecopy}\n");
+    dvmFprintf(stderr, "  -Xjnitrace:substring (eg NativeClass or nativeMethod)\n");
+    dvmFprintf(stderr, "  -Xstacktracefile:<filename>\n");
+    dvmFprintf(stderr, "  -Xgc:[no]precise\n");
+    dvmFprintf(stderr, "  -Xgc:[no]preverify\n");
+    dvmFprintf(stderr, "  -Xgc:[no]postverify\n");
+    dvmFprintf(stderr, "  -Xgc:[no]concurrent\n");
+    dvmFprintf(stderr, "  -Xgc:[no]verifycardtable\n");
+    dvmFprintf(stderr, "  -XX:+DisableExplicitGC\n");
+    dvmFprintf(stderr, "  -X[no]genregmap\n");
+    dvmFprintf(stderr, "  -Xverifyopt:[no]checkmon\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, "  -Xjitthreshold:decimalvalue\n");
+    dvmFprintf(stderr, "  -Xjitblocking\n");
+    dvmFprintf(stderr, "  -Xjitmethod:signature[,signature]* "
+                       "(eg Ljava/lang/String\\;replace)\n");
+    dvmFprintf(stderr, "  -Xjitcheckcg\n");
+    dvmFprintf(stderr, "  -Xjitverbose\n");
+    dvmFprintf(stderr, "  -Xjitprofile\n");
+    dvmFprintf(stderr, "  -Xjitdisableopt\n");
+    dvmFprintf(stderr, "  -Xjitsuspendpoll\n");
+#endif
+    dvmFprintf(stderr, "\n");
+    dvmFprintf(stderr, "Configured with:"
+        " debugger"
+        " profiler"
+        " hprof"
+#ifdef WITH_TRACKREF_CHECKS
+        " trackref_checks"
+#endif
+#ifdef WITH_INSTR_CHECKS
+        " instr_checks"
+#endif
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+        " extra_object_validation"
+#endif
+#ifdef WITH_EXTRA_GC_CHECKS
+        " extra_gc_checks"
+#endif
+#if !defined(NDEBUG) && defined(WITH_DALVIK_ASSERT)
+        " dalvik_assert"
+#endif
+#ifdef WITH_JNI_STACK_CHECK
+        " jni_stack_check"
+#endif
+#ifdef EASY_GDB
+        " easy_gdb"
+#endif
+#ifdef CHECK_MUTEX
+        " check_mutex"
+#endif
+#if defined(WITH_JIT)
+        " jit(" ARCH_VARIANT ")"
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+        " self_verification"
+#endif
+#if ANDROID_SMP != 0
+        " smp"
+#endif
+    );
+#ifdef DVM_SHOW_EXCEPTION
+    dvmFprintf(stderr, " show_exception=%d", DVM_SHOW_EXCEPTION);
+#endif
+    dvmFprintf(stderr, "\n\n");
+}
+
+/*
+ * Show helpful information on JDWP options.
+ */
+static void showJdwpHelp()
+{
+    dvmFprintf(stderr,
+        "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n");
+    dvmFprintf(stderr,
+        "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
+}
+
+/*
+ * Show version and copyright info.
+ */
+static void showVersion()
+{
+    dvmFprintf(stdout, "DalvikVM version %d.%d.%d\n",
+        DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
+    dvmFprintf(stdout,
+        "Copyright (C) 2007 The Android Open Source Project\n\n"
+        "This software is built from source code licensed under the "
+        "Apache License,\n"
+        "Version 2.0 (the \"License\"). You may obtain a copy of the "
+        "License at\n\n"
+        "     http://www.apache.org/licenses/LICENSE-2.0\n\n"
+        "See the associated NOTICE file for this software for further "
+        "details.\n");
+}
+
+/*
+ * Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
+ * memory sizes.  [kK] indicates kilobytes, [mM] megabytes, and
+ * [gG] gigabytes.
+ *
+ * "s" should point just past the "-Xm?" part of the string.
+ * "min" specifies the lowest acceptable value described by "s".
+ * "div" specifies a divisor, e.g. 1024 if the value must be a multiple
+ * of 1024.
+ *
+ * The spec says the -Xmx and -Xms options must be multiples of 1024.  It
+ * doesn't say anything about -Xss.
+ *
+ * Returns 0 (a useless size) if "s" is malformed or specifies a low or
+ * non-evenly-divisible value.
+ */
+static size_t parseMemOption(const char *s, size_t div)
+{
+    /* strtoul accepts a leading [+-], which we don't want,
+     * so make sure our string starts with a decimal digit.
+     */
+    if (isdigit(*s)) {
+        const char *s2;
+        size_t val;
+
+        val = strtoul(s, (char **)&s2, 10);
+        if (s2 != s) {
+            /* s2 should be pointing just after the number.
+             * If this is the end of the string, the user
+             * has specified a number of bytes.  Otherwise,
+             * there should be exactly one more character
+             * that specifies a multiplier.
+             */
+            if (*s2 != '\0') {
+                char c;
+
+                /* The remainder of the string is either a single multiplier
+                 * character, or nothing to indicate that the value is in
+                 * bytes.
+                 */
+                c = *s2++;
+                if (*s2 == '\0') {
+                    size_t mul;
+
+                    if (c == '\0') {
+                        mul = 1;
+                    } else if (c == 'k' || c == 'K') {
+                        mul = 1024;
+                    } else if (c == 'm' || c == 'M') {
+                        mul = 1024 * 1024;
+                    } else if (c == 'g' || c == 'G') {
+                        mul = 1024 * 1024 * 1024;
+                    } else {
+                        /* Unknown multiplier character.
+                         */
+                        return 0;
+                    }
+
+                    if (val <= SIZE_MAX / mul) {
+                        val *= mul;
+                    } else {
+                        /* Clamp to a multiple of 1024.
+                         */
+                        val = SIZE_MAX & ~(1024-1);
+                    }
+                } else {
+                    /* There's more than one character after the
+                     * numeric part.
+                     */
+                    return 0;
+                }
+            }
+
+            /* The man page says that a -Xm value must be
+             * a multiple of 1024.
+             */
+            if (val % div == 0) {
+                return val;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Handle one of the JDWP name/value pairs.
+ *
+ * JDWP options are:
+ *  help: if specified, show help message and bail
+ *  transport: may be dt_socket or dt_shmem
+ *  address: for dt_socket, "host:port", or just "port" when listening
+ *  server: if "y", wait for debugger to attach; if "n", attach to debugger
+ *  timeout: how long to wait for debugger to connect / listen
+ *
+ * Useful with server=n (these aren't supported yet):
+ *  onthrow=<exception-name>: connect to debugger when exception thrown
+ *  onuncaught=y|n: connect to debugger when uncaught exception thrown
+ *  launch=<command-line>: launch the debugger itself
+ *
+ * The "transport" option is required, as is "address" if server=n.
+ */
+static bool handleJdwpOption(const char* name, const char* value)
+{
+    if (strcmp(name, "transport") == 0) {
+        if (strcmp(value, "dt_socket") == 0) {
+            gDvm.jdwpTransport = kJdwpTransportSocket;
+        } else if (strcmp(value, "dt_android_adb") == 0) {
+            gDvm.jdwpTransport = kJdwpTransportAndroidAdb;
+        } else {
+            LOGE("JDWP transport '%s' not supported", value);
+            return false;
+        }
+    } else if (strcmp(name, "server") == 0) {
+        if (*value == 'n')
+            gDvm.jdwpServer = false;
+        else if (*value == 'y')
+            gDvm.jdwpServer = true;
+        else {
+            LOGE("JDWP option 'server' must be 'y' or 'n'");
+            return false;
+        }
+    } else if (strcmp(name, "suspend") == 0) {
+        if (*value == 'n')
+            gDvm.jdwpSuspend = false;
+        else if (*value == 'y')
+            gDvm.jdwpSuspend = true;
+        else {
+            LOGE("JDWP option 'suspend' must be 'y' or 'n'");
+            return false;
+        }
+    } else if (strcmp(name, "address") == 0) {
+        /* this is either <port> or <host>:<port> */
+        const char* colon = strchr(value, ':');
+        char* end;
+        long port;
+
+        if (colon != NULL) {
+            free(gDvm.jdwpHost);
+            gDvm.jdwpHost = (char*) malloc(colon - value +1);
+            strncpy(gDvm.jdwpHost, value, colon - value +1);
+            gDvm.jdwpHost[colon-value] = '\0';
+            value = colon + 1;
+        }
+        if (*value == '\0') {
+            LOGE("JDWP address missing port");
+            return false;
+        }
+        port = strtol(value, &end, 10);
+        if (*end != '\0') {
+            LOGE("JDWP address has junk in port field '%s'", value);
+            return false;
+        }
+        gDvm.jdwpPort = port;
+    } else if (strcmp(name, "launch") == 0 ||
+               strcmp(name, "onthrow") == 0 ||
+               strcmp(name, "oncaught") == 0 ||
+               strcmp(name, "timeout") == 0)
+    {
+        /* valid but unsupported */
+        LOGI("Ignoring JDWP option '%s'='%s'", name, value);
+    } else {
+        LOGI("Ignoring unrecognized JDWP option '%s'='%s'", name, value);
+    }
+
+    return true;
+}
+
+/*
+ * Parse the latter half of a -Xrunjdwp/-agentlib:jdwp= string, e.g.:
+ * "transport=dt_socket,address=8000,server=y,suspend=n"
+ */
+static bool parseJdwpOptions(const char* str)
+{
+    char* mangle = strdup(str);
+    char* name = mangle;
+    bool result = false;
+
+    /*
+     * Process all of the name=value pairs.
+     */
+    while (true) {
+        char* value;
+        char* comma;
+
+        value = strchr(name, '=');
+        if (value == NULL) {
+            LOGE("JDWP opts: garbage at '%s'", name);
+            goto bail;
+        }
+
+        comma = strchr(name, ',');      // use name, not value, for safety
+        if (comma != NULL) {
+            if (comma < value) {
+                LOGE("JDWP opts: found comma before '=' in '%s'", mangle);
+                goto bail;
+            }
+            *comma = '\0';
+        }
+
+        *value++ = '\0';        // stomp the '='
+
+        if (!handleJdwpOption(name, value))
+            goto bail;
+
+        if (comma == NULL) {
+            /* out of options */
+            break;
+        }
+        name = comma+1;
+    }
+
+    /*
+     * Make sure the combination of arguments makes sense.
+     */
+    if (gDvm.jdwpTransport == kJdwpTransportUnknown) {
+        LOGE("JDWP opts: must specify transport");
+        goto bail;
+    }
+    if (!gDvm.jdwpServer && (gDvm.jdwpHost == NULL || gDvm.jdwpPort == 0)) {
+        LOGE("JDWP opts: when server=n, must specify host and port");
+        goto bail;
+    }
+    // transport mandatory
+    // outbound server address
+
+    gDvm.jdwpConfigured = true;
+    result = true;
+
+bail:
+    free(mangle);
+    return result;
+}
+
+/*
+ * Handle one of the four kinds of assertion arguments.
+ *
+ * "pkgOrClass" is the last part of an enable/disable line.  For a package
+ * the arg looks like "-ea:com.google.fubar...", for a class it looks
+ * like "-ea:com.google.fubar.Wahoo".  The string we get starts at the ':'.
+ *
+ * For system assertions (-esa/-dsa), "pkgOrClass" is NULL.
+ *
+ * Multiple instances of these arguments can be specified, e.g. you can
+ * enable assertions for a package and then disable them for one class in
+ * the package.
+ */
+static bool enableAssertions(const char* pkgOrClass, bool enable)
+{
+    AssertionControl* pCtrl = &gDvm.assertionCtrl[gDvm.assertionCtrlCount++];
+    pCtrl->enable = enable;
+
+    if (pkgOrClass == NULL) {
+        /* enable or disable for all system classes */
+        pCtrl->isPackage = false;
+        pCtrl->pkgOrClass = NULL;
+        pCtrl->pkgOrClassLen = 0;
+    } else {
+        if (*pkgOrClass == '\0') {
+            /* global enable/disable for all but system */
+            pCtrl->isPackage = false;
+            pCtrl->pkgOrClass = strdup("");
+            pCtrl->pkgOrClassLen = 0;
+        } else {
+            pCtrl->pkgOrClass = dvmDotToSlash(pkgOrClass+1);    // skip ':'
+            if (pCtrl->pkgOrClass == NULL) {
+                /* can happen if class name includes an illegal '/' */
+                LOGW("Unable to process assertion arg '%s'", pkgOrClass);
+                return false;
+            }
+
+            int len = strlen(pCtrl->pkgOrClass);
+            if (len >= 3 && strcmp(pCtrl->pkgOrClass + len-3, "///") == 0) {
+                /* mark as package, truncate two of the three slashes */
+                pCtrl->isPackage = true;
+                *(pCtrl->pkgOrClass + len-2) = '\0';
+                pCtrl->pkgOrClassLen = len - 2;
+            } else {
+                /* just a class */
+                pCtrl->isPackage = false;
+                pCtrl->pkgOrClassLen = len;
+            }
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Turn assertions on when requested to do so by the Zygote.
+ *
+ * This is a bit sketchy.  We can't (easily) go back and fiddle with all
+ * of the classes that have already been initialized, so this only
+ * affects classes that have yet to be loaded.  If some or all assertions
+ * have been enabled through some other means, we don't want to mess with
+ * it here, so we do nothing.  Finally, we assume that there's room in
+ * "assertionCtrl" to hold at least one entry; this is guaranteed by the
+ * allocator.
+ *
+ * This must only be called from the main thread during zygote init.
+ */
+void dvmLateEnableAssertions()
+{
+    if (gDvm.assertionCtrl == NULL) {
+        LOGD("Not late-enabling assertions: no assertionCtrl array");
+        return;
+    } else if (gDvm.assertionCtrlCount != 0) {
+        LOGD("Not late-enabling assertions: some asserts already configured");
+        return;
+    }
+    LOGD("Late-enabling assertions");
+
+    /* global enable for all but system */
+    AssertionControl* pCtrl = gDvm.assertionCtrl;
+    pCtrl->pkgOrClass = strdup("");
+    pCtrl->pkgOrClassLen = 0;
+    pCtrl->isPackage = false;
+    pCtrl->enable = true;
+    gDvm.assertionCtrlCount = 1;
+}
+
+
+/*
+ * Release memory associated with the AssertionCtrl array.
+ */
+static void freeAssertionCtrl()
+{
+    int i;
+
+    for (i = 0; i < gDvm.assertionCtrlCount; i++)
+        free(gDvm.assertionCtrl[i].pkgOrClass);
+    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 %= kNumPackedOpcodes;
+
+                if (*endPtr == '-') {
+                    endValue = strtol(endPtr+1, &endPtr, 16);
+                    endValue %= kNumPackedOpcodes;
+                } 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 < (kNumPackedOpcodes+7)/8; 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,
+ * argv[0] does not contain the name of the program.
+ *
+ * If "ignoreUnrecognized" is set, we ignore options starting with "-X" or "_"
+ * that we don't recognize.  Otherwise, we return with an error as soon as
+ * we see anything we can't identify.
+ *
+ * Returns 0 on success, -1 on failure, and 1 for the special case of
+ * "-version" where we want to stop without showing an error message.
+ */
+static int processOptions(int argc, const char* const argv[],
+    bool ignoreUnrecognized)
+{
+    int i;
+
+    LOGV("VM options (%d):", argc);
+    for (i = 0; i < argc; i++)
+        LOGV("  %d: '%s'", i, argv[i]);
+
+    /*
+     * Over-allocate AssertionControl array for convenience.  If allocated,
+     * the array must be able to hold at least one entry, so that the
+     * zygote-time activation can do its business.
+     */
+    assert(gDvm.assertionCtrl == NULL);
+    if (argc > 0) {
+        gDvm.assertionCtrl =
+            (AssertionControl*) malloc(sizeof(AssertionControl) * argc);
+        if (gDvm.assertionCtrl == NULL)
+            return -1;
+        assert(gDvm.assertionCtrlCount == 0);
+    }
+
+    for (i = 0; i < argc; i++) {
+        if (strcmp(argv[i], "-help") == 0) {
+            /* show usage and stop */
+            return -1;
+
+        } else if (strcmp(argv[i], "-version") == 0) {
+            /* show version and stop */
+            showVersion();
+            return 1;
+        } else if (strcmp(argv[i], "-showversion") == 0) {
+            /* show version and continue */
+            showVersion();
+
+        } else if (strcmp(argv[i], "-classpath") == 0 ||
+                   strcmp(argv[i], "-cp") == 0)
+        {
+            /* set classpath */
+            if (i == argc-1) {
+                dvmFprintf(stderr, "Missing classpath path list\n");
+                return -1;
+            }
+            free(gDvm.classPathStr); /* in case we have compiled-in default */
+            gDvm.classPathStr = strdup(argv[++i]);
+
+        } else if (strncmp(argv[i], "-Xbootclasspath:",
+                sizeof("-Xbootclasspath:")-1) == 0)
+        {
+            /* set bootclasspath */
+            const char* path = argv[i] + sizeof("-Xbootclasspath:")-1;
+
+            if (*path == '\0') {
+                dvmFprintf(stderr, "Missing bootclasspath path list\n");
+                return -1;
+            }
+            free(gDvm.bootClassPathStr);
+            gDvm.bootClassPathStr = strdup(path);
+
+        } else if (strncmp(argv[i], "-Xbootclasspath/a:",
+                sizeof("-Xbootclasspath/a:")-1) == 0) {
+            const char* appPath = argv[i] + sizeof("-Xbootclasspath/a:")-1;
+
+            if (*(appPath) == '\0') {
+                dvmFprintf(stderr, "Missing appending bootclasspath path list\n");
+                return -1;
+            }
+            char* allPath;
+
+            if (asprintf(&allPath, "%s:%s", gDvm.bootClassPathStr, appPath) < 0) {
+                dvmFprintf(stderr, "Can't append to bootclasspath path list\n");
+                return -1;
+            }
+            free(gDvm.bootClassPathStr);
+            gDvm.bootClassPathStr = allPath;
+
+        } else if (strncmp(argv[i], "-Xbootclasspath/p:",
+                sizeof("-Xbootclasspath/p:")-1) == 0) {
+            const char* prePath = argv[i] + sizeof("-Xbootclasspath/p:")-1;
+
+            if (*(prePath) == '\0') {
+                dvmFprintf(stderr, "Missing prepending bootclasspath path list\n");
+                return -1;
+            }
+            char* allPath;
+
+            if (asprintf(&allPath, "%s:%s", prePath, gDvm.bootClassPathStr) < 0) {
+                dvmFprintf(stderr, "Can't prepend to bootclasspath path list\n");
+                return -1;
+            }
+            free(gDvm.bootClassPathStr);
+            gDvm.bootClassPathStr = allPath;
+
+        } else if (strncmp(argv[i], "-D", 2) == 0) {
+            /* Properties are handled in managed code. We just check syntax. */
+            if (strchr(argv[i], '=') == NULL) {
+                dvmFprintf(stderr, "Bad system property setting: \"%s\"\n",
+                    argv[i]);
+                return -1;
+            }
+            gDvm.properties->push_back(argv[i] + 2);
+
+        } else if (strcmp(argv[i], "-jar") == 0) {
+            // TODO: handle this; name of jar should be in argv[i+1]
+            dvmFprintf(stderr, "-jar not yet handled\n");
+            assert(false);
+
+        } else if (strncmp(argv[i], "-Xms", 4) == 0) {
+            size_t val = parseMemOption(argv[i]+4, 1024);
+            if (val != 0) {
+                if (val >= kMinHeapStartSize && val <= kMaxHeapSize) {
+                    gDvm.heapStartingSize = val;
+                } else {
+                    dvmFprintf(stderr,
+                        "Invalid -Xms '%s', range is %dKB to %dKB\n",
+                        argv[i], kMinHeapStartSize/1024, kMaxHeapSize/1024);
+                    return -1;
+                }
+            } else {
+                dvmFprintf(stderr, "Invalid -Xms option '%s'\n", argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-Xmx", 4) == 0) {
+            size_t val = parseMemOption(argv[i]+4, 1024);
+            if (val != 0) {
+                if (val >= kMinHeapSize && val <= kMaxHeapSize) {
+                    gDvm.heapMaximumSize = val;
+                } else {
+                    dvmFprintf(stderr,
+                        "Invalid -Xmx '%s', range is %dKB to %dKB\n",
+                        argv[i], kMinHeapSize/1024, kMaxHeapSize/1024);
+                    return -1;
+                }
+            } else {
+                dvmFprintf(stderr, "Invalid -Xmx option '%s'\n", argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-XX:HeapGrowthLimit=", 20) == 0) {
+            size_t val = parseMemOption(argv[i] + 20, 1024);
+            if (val != 0) {
+                gDvm.heapGrowthLimit = val;
+            } else {
+                dvmFprintf(stderr, "Invalid -XX:HeapGrowthLimit option '%s'\n", argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-Xss", 4) == 0) {
+            size_t val = parseMemOption(argv[i]+4, 1);
+            if (val != 0) {
+                if (val >= kMinStackSize && val <= kMaxStackSize) {
+                    gDvm.stackSize = val;
+                } else {
+                    dvmFprintf(stderr, "Invalid -Xss '%s', range is %d to %d\n",
+                        argv[i], kMinStackSize, kMaxStackSize);
+                    return -1;
+                }
+            } else {
+                dvmFprintf(stderr, "Invalid -Xss option '%s'\n", argv[i]);
+                return -1;
+            }
+
+        } else if (strncmp(argv[i], "-XX:+DisableExplicitGC", 22) == 0) {
+            gDvm.disableExplicitGc = true;
+        } else if (strcmp(argv[i], "-verbose") == 0 ||
+            strcmp(argv[i], "-verbose:class") == 0)
+        {
+            // JNI spec says "-verbose:gc,class" is valid, but cmd line
+            // doesn't work that way; may want to support.
+            gDvm.verboseClass = true;
+        } else if (strcmp(argv[i], "-verbose:jni") == 0) {
+            gDvm.verboseJni = true;
+        } else if (strcmp(argv[i], "-verbose:gc") == 0) {
+            gDvm.verboseGc = true;
+        } else if (strcmp(argv[i], "-verbose:shutdown") == 0) {
+            gDvm.verboseShutdown = true;
+
+        } else if (strncmp(argv[i], "-enableassertions", 17) == 0) {
+            enableAssertions(argv[i] + 17, true);
+        } else if (strncmp(argv[i], "-ea", 3) == 0) {
+            enableAssertions(argv[i] + 3, true);
+        } else if (strncmp(argv[i], "-disableassertions", 18) == 0) {
+            enableAssertions(argv[i] + 18, false);
+        } else if (strncmp(argv[i], "-da", 3) == 0) {
+            enableAssertions(argv[i] + 3, false);
+        } else if (strcmp(argv[i], "-enablesystemassertions") == 0 ||
+                   strcmp(argv[i], "-esa") == 0)
+        {
+            enableAssertions(NULL, true);
+        } else if (strcmp(argv[i], "-disablesystemassertions") == 0 ||
+                   strcmp(argv[i], "-dsa") == 0)
+        {
+            enableAssertions(NULL, false);
+
+        } else if (strncmp(argv[i], "-Xcheck:jni", 11) == 0) {
+            /* nothing to do now -- was handled during JNI init */
+
+        } else if (strcmp(argv[i], "-Xdebug") == 0) {
+            /* accept but ignore */
+
+        } else if (strncmp(argv[i], "-Xrunjdwp:", 10) == 0 ||
+            strncmp(argv[i], "-agentlib:jdwp=", 15) == 0)
+        {
+            const char* tail;
+
+            if (argv[i][1] == 'X')
+                tail = argv[i] + 10;
+            else
+                tail = argv[i] + 15;
+
+            if (strncmp(tail, "help", 4) == 0 || !parseJdwpOptions(tail)) {
+                showJdwpHelp();
+                return 1;
+            }
+        } else if (strcmp(argv[i], "-Xrs") == 0) {
+            gDvm.reduceSignals = true;
+        } else if (strcmp(argv[i], "-Xnoquithandler") == 0) {
+            /* disables SIGQUIT handler thread while still blocking SIGQUIT */
+            /* (useful if we don't want thread but system still signals us) */
+            gDvm.noQuitHandler = true;
+        } else if (strcmp(argv[i], "-Xzygote") == 0) {
+            gDvm.zygote = true;
+#if defined(WITH_JIT)
+            gDvmJit.runningInAndroidFramework = true;
+#endif
+        } else if (strncmp(argv[i], "-Xdexopt:", 9) == 0) {
+            if (strcmp(argv[i] + 9, "none") == 0)
+                gDvm.dexOptMode = OPTIMIZE_MODE_NONE;
+            else if (strcmp(argv[i] + 9, "verified") == 0)
+                gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
+            else if (strcmp(argv[i] + 9, "all") == 0)
+                gDvm.dexOptMode = OPTIMIZE_MODE_ALL;
+            else if (strcmp(argv[i] + 9, "full") == 0)
+                gDvm.dexOptMode = OPTIMIZE_MODE_FULL;
+            else {
+                dvmFprintf(stderr, "Unrecognized dexopt option '%s'\n",argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-Xverify:", 9) == 0) {
+            if (strcmp(argv[i] + 9, "none") == 0)
+                gDvm.classVerifyMode = VERIFY_MODE_NONE;
+            else if (strcmp(argv[i] + 9, "remote") == 0)
+                gDvm.classVerifyMode = VERIFY_MODE_REMOTE;
+            else if (strcmp(argv[i] + 9, "all") == 0)
+                gDvm.classVerifyMode = VERIFY_MODE_ALL;
+            else {
+                dvmFprintf(stderr, "Unrecognized verify option '%s'\n",argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-Xjnigreflimit:", 15) == 0) {
+            int lim = atoi(argv[i] + 15);
+            if (lim < 200 || (lim % 100) != 0) {
+                dvmFprintf(stderr, "Bad value for -Xjnigreflimit: '%s'\n",
+                    argv[i]+15);
+                return -1;
+            }
+            gDvm.jniGrefLimit = lim;
+        } else if (strncmp(argv[i], "-Xjnitrace:", 11) == 0) {
+            gDvm.jniTrace = strdup(argv[i] + 11);
+        } else if (strcmp(argv[i], "-Xlog-stdio") == 0) {
+            gDvm.logStdio = true;
+
+        } else if (strncmp(argv[i], "-Xint", 5) == 0) {
+            if (argv[i][5] == ':') {
+                if (strcmp(argv[i] + 6, "portable") == 0)
+                    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]);
+                    /* keep going */
+                }
+            } else {
+                /* disable JIT if it was enabled by default */
+                gDvm.executionMode = kExecutionModeInterpFast;
+            }
+
+        } else if (strncmp(argv[i], "-Xlockprofthreshold:", 20) == 0) {
+            gDvm.lockProfThreshold = atoi(argv[i] + 20);
+
+#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], "-Xjitblocking", 13) == 0) {
+          gDvmJit.blockingMode = true;
+        } else if (strncmp(argv[i], "-Xjitthreshold:", 15) == 0) {
+          gDvmJit.threshold = atoi(argv[i] + 15);
+        } 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], "-Xjitcheckcg", 12) == 0) {
+          gDvmJit.checkCallGraph = true;
+          /* Need to enable blocking mode due to stack crawling */
+          gDvmJit.blockingMode = true;
+        } else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
+          gDvmJit.printMe = true;
+        } else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
+          gDvmJit.profileMode = kTraceProfilingContinuous;
+        } else if (strncmp(argv[i], "-Xjitdisableopt", 15) == 0) {
+          /* Disable selected optimizations */
+          if (argv[i][15] == ':') {
+              sscanf(argv[i] + 16, "%x", &gDvmJit.disableOpt);
+          /* Disable all optimizations */
+          } else {
+              gDvmJit.disableOpt = -1;
+          }
+        } else if (strncmp(argv[i], "-Xjitsuspendpoll", 16) == 0) {
+          gDvmJit.genSuspendPoll = true;
+#endif
+
+        } else if (strncmp(argv[i], "-Xstacktracefile:", 17) == 0) {
+            gDvm.stackTraceFile = strdup(argv[i]+17);
+
+        } else if (strcmp(argv[i], "-Xgenregmap") == 0) {
+            gDvm.generateRegisterMaps = true;
+        } else if (strcmp(argv[i], "-Xnogenregmap") == 0) {
+            gDvm.generateRegisterMaps = false;
+
+        } else if (strcmp(argv[i], "Xverifyopt:checkmon") == 0) {
+            gDvm.monitorVerification = true;
+        } else if (strcmp(argv[i], "Xverifyopt:nocheckmon") == 0) {
+            gDvm.monitorVerification = false;
+
+        } 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 if (strcmp(argv[i] + 5, "preverify") == 0)
+                gDvm.preVerify = true;
+            else if (strcmp(argv[i] + 5, "nopreverify") == 0)
+                gDvm.preVerify = false;
+            else if (strcmp(argv[i] + 5, "postverify") == 0)
+                gDvm.postVerify = true;
+            else if (strcmp(argv[i] + 5, "nopostverify") == 0)
+                gDvm.postVerify = false;
+            else if (strcmp(argv[i] + 5, "concurrent") == 0)
+                gDvm.concurrentMarkSweep = true;
+            else if (strcmp(argv[i] + 5, "noconcurrent") == 0)
+                gDvm.concurrentMarkSweep = false;
+            else if (strcmp(argv[i] + 5, "verifycardtable") == 0)
+                gDvm.verifyCardTable = true;
+            else if (strcmp(argv[i] + 5, "noverifycardtable") == 0)
+                gDvm.verifyCardTable = false;
+            else {
+                dvmFprintf(stderr, "Bad value for -Xgc");
+                return -1;
+            }
+            LOGV("Precise GC configured %s", gDvm.preciseGc ? "ON" : "OFF");
+
+        } else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
+            gDvm.verifyDexChecksum = true;
+
+        } else if (strcmp(argv[i], "-Xprofile:threadcpuclock") == 0) {
+            gDvm.profilerClockSource = kProfilerClockSourceThreadCpu;
+        } else if (strcmp(argv[i], "-Xprofile:wallclock") == 0) {
+            gDvm.profilerClockSource = kProfilerClockSourceWall;
+        } else if (strcmp(argv[i], "-Xprofile:dualclock") == 0) {
+            gDvm.profilerClockSource = kProfilerClockSourceDual;
+
+        } else {
+            if (!ignoreUnrecognized) {
+                dvmFprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Set defaults for fields altered or modified by arguments.
+ *
+ * Globals are initialized to 0 (a/k/a NULL or false).
+ */
+static void setCommandLineDefaults()
+{
+    const char* envStr = getenv("CLASSPATH");
+    if (envStr != NULL) {
+        gDvm.classPathStr = strdup(envStr);
+    } else {
+        gDvm.classPathStr = strdup(".");
+    }
+    envStr = getenv("BOOTCLASSPATH");
+    if (envStr != NULL) {
+        gDvm.bootClassPathStr = strdup(envStr);
+    } else {
+        gDvm.bootClassPathStr = strdup(".");
+    }
+
+    gDvm.properties = new std::vector<std::string>();
+
+    /* Defaults overridden by -Xms and -Xmx.
+     * TODO: base these on a system or application-specific default
+     */
+    gDvm.heapStartingSize = 2 * 1024 * 1024;  // Spec says 16MB; too big for us.
+    gDvm.heapMaximumSize = 16 * 1024 * 1024;  // Spec says 75% physical mem
+    gDvm.heapGrowthLimit = 0;  // 0 means no growth limit
+    gDvm.stackSize = kDefaultStackSize;
+
+    gDvm.concurrentMarkSweep = true;
+
+    /* gDvm.jdwpSuspend = true; */
+
+    /* allowed unless zygote config doesn't allow it */
+    gDvm.jdwpAllowed = true;
+
+    /* default verification and optimization modes */
+    gDvm.classVerifyMode = VERIFY_MODE_ALL;
+    gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
+    gDvm.monitorVerification = false;
+    gDvm.generateRegisterMaps = true;
+    gDvm.registerMapMode = kRegisterMapModeTypePrecise;
+
+    /*
+     * Default execution mode.
+     *
+     * This should probably interact with the mterp code somehow, e.g. if
+     * we know we're using the "desktop" build we should probably be
+     * using "portable" rather than "fast".
+     */
+#if defined(WITH_JIT)
+    gDvm.executionMode = kExecutionModeJit;
+#else
+    gDvm.executionMode = kExecutionModeInterpFast;
+#endif
+
+    /*
+     * SMP support is a compile-time define, but we may want to have
+     * dexopt target a differently-configured device.
+     */
+    gDvm.dexOptForSmp = (ANDROID_SMP != 0);
+
+    /*
+     * Default profiler configuration.
+     */
+    gDvm.profilerClockSource = kProfilerClockSourceDual;
+}
+
+
+/*
+ * Handle a SIGBUS, which frequently occurs because somebody replaced an
+ * optimized DEX file out from under us.
+ */
+static void busCatcher(int signum, siginfo_t* info, void* context)
+{
+    void* addr = info->si_addr;
+
+    LOGE("Caught a SIGBUS (%d), addr=%p", signum, addr);
+
+    /*
+     * If we return at this point the SIGBUS just keeps happening, so we
+     * remove the signal handler and allow it to kill us.  TODO: restore
+     * the original, which points to a debuggerd stub; if we don't then
+     * debuggerd won't be notified.
+     */
+    signal(SIGBUS, SIG_DFL);
+}
+
+/*
+ * Configure signals.  We need to block SIGQUIT so that the signal only
+ * reaches the dump-stack-trace thread.
+ *
+ * This can be disabled with the "-Xrs" flag.
+ */
+static void blockSignals()
+{
+    sigset_t mask;
+    int cc;
+
+    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);
+
+    if (false) {
+        /* TODO: save the old sigaction in a global */
+        struct sigaction sa;
+        memset(&sa, 0, sizeof(sa));
+        sa.sa_sigaction = busCatcher;
+        sa.sa_flags = SA_SIGINFO;
+        cc = sigaction(SIGBUS, &sa, NULL);
+        assert(cc == 0);
+    }
+}
+
+class ScopedShutdown {
+public:
+    ScopedShutdown() : armed_(true) {
+    }
+
+    ~ScopedShutdown() {
+        if (armed_) {
+            dvmShutdown();
+        }
+    }
+
+    void disarm() {
+        armed_ = false;
+    }
+
+private:
+    bool armed_;
+};
+
+/*
+ * VM initialization.  Pass in any options provided on the command line.
+ * Do not pass in the class name or the options for the class.
+ *
+ * Returns 0 on success.
+ */
+std::string dvmStartup(int argc, const char* const argv[],
+        bool ignoreUnrecognized, JNIEnv* pEnv)
+{
+    ScopedShutdown scopedShutdown;
+
+    assert(gDvm.initializing);
+
+    LOGV("VM init args (%d):", argc);
+    for (int i = 0; i < argc; i++) {
+        LOGV("  %d: '%s'", i, argv[i]);
+    }
+    setCommandLineDefaults();
+
+    /*
+     * Process the option flags (if any).
+     */
+    int cc = processOptions(argc, argv, ignoreUnrecognized);
+    if (cc != 0) {
+        if (cc < 0) {
+            dvmFprintf(stderr, "\n");
+            usage("dalvikvm");
+        }
+        return "syntax error";
+    }
+
+#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");
+        gDvm.executionMode = kExecutionModeInterpPortable;
+    }
+#endif
+
+    /* Configure group scheduling capabilities */
+    if (!access("/dev/cpuctl/tasks", F_OK)) {
+        LOGV("Using kernel group scheduling");
+        gDvm.kernelGroupScheduling = 1;
+    } else {
+        LOGV("Using kernel scheduler policies");
+    }
+
+    /* configure signal handling */
+    if (!gDvm.reduceSignals)
+        blockSignals();
+
+    /* verify system page size */
+    if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {
+        return StringPrintf("expected page size %d, got %d",
+                SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));
+    }
+
+    /* mterp setup */
+    LOGV("Using executionMode %d", gDvm.executionMode);
+    dvmCheckAsmConstants();
+
+    /*
+     * Initialize components.
+     */
+    if (!dvmAllocTrackerStartup()) {
+        return "dvmAllocTrackerStartup failed";
+    }
+    if (!dvmGcStartup()) {
+        return "dvmGcStartup failed";
+    }
+    if (!dvmThreadStartup()) {
+        return "dvmThreadStartup failed";
+    }
+    if (!dvmInlineNativeStartup()) {
+        return "dvmInlineNativeStartup";
+    }
+    if (!dvmRegisterMapStartup()) {
+        return "dvmRegisterMapStartup failed";
+    }
+    if (!dvmInstanceofStartup()) {
+        return "dvmInstanceofStartup failed";
+    }
+    if (!dvmClassStartup()) {
+        return "dvmClassStartup failed";
+    }
+
+    /*
+     * At this point, the system is guaranteed to be sufficiently
+     * initialized that we can look up classes and class members. This
+     * call populates the gDvm instance with all the class and member
+     * references that the VM wants to use directly.
+     */
+    if (!dvmFindRequiredClassesAndMembers()) {
+        return "dvmFindRequiredClassesAndMembers failed";
+    }
+
+    if (!dvmStringInternStartup()) {
+        return "dvmStringInternStartup failed";
+    }
+    if (!dvmNativeStartup()) {
+        return "dvmNativeStartup failed";
+    }
+    if (!dvmInternalNativeStartup()) {
+        return "dvmInternalNativeStartup failed";
+    }
+    if (!dvmJniStartup()) {
+        return "dvmJniStartup failed";
+    }
+    if (!dvmProfilingStartup()) {
+        return "dvmProfilingStartup failed";
+    }
+
+    /*
+     * Create a table of methods for which we will substitute an "inline"
+     * version for performance.
+     */
+    if (!dvmCreateInlineSubsTable()) {
+        return "dvmCreateInlineSubsTable failed";
+    }
+
+    /*
+     * Miscellaneous class library validation.
+     */
+    if (!dvmValidateBoxClasses()) {
+        return "dvmValidateBoxClasses failed";
+    }
+
+    /*
+     * Do the last bits of Thread struct initialization we need to allow
+     * JNI calls to work.
+     */
+    if (!dvmPrepMainForJni(pEnv)) {
+        return "dvmPrepMainForJni failed";
+    }
+
+    /*
+     * Explicitly initialize java.lang.Class.  This doesn't happen
+     * automatically because it's allocated specially (it's an instance
+     * of itself).  Must happen before registration of system natives,
+     * which make some calls that throw assertions if the classes they
+     * operate on aren't initialized.
+     */
+    if (!dvmInitClass(gDvm.classJavaLangClass)) {
+        return "couldn't initialized java.lang.Class";
+    }
+
+    /*
+     * Register the system native methods, which are registered through JNI.
+     */
+    if (!registerSystemNatives(pEnv)) {
+        return "couldn't register system natives";
+    }
+
+    /*
+     * Do some "late" initialization for the memory allocator.  This may
+     * allocate storage and initialize classes.
+     */
+    if (!dvmCreateStockExceptions()) {
+        return "dvmCreateStockExceptions failed";
+    }
+
+    /*
+     * At this point, the VM is in a pretty good state.  Finish prep on
+     * the main thread (specifically, create a java.lang.Thread object to go
+     * along with our Thread struct).  Note we will probably be executing
+     * some interpreted class initializer code in here.
+     */
+    if (!dvmPrepMainThread()) {
+        return "dvmPrepMainThread failed";
+    }
+
+    /*
+     * Make sure we haven't accumulated any tracked references.  The main
+     * thread should be starting with a clean slate.
+     */
+    if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0)
+    {
+        LOGW("Warning: tracked references remain post-initialization");
+        dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN");
+    }
+
+    /* general debugging setup */
+    if (!dvmDebuggerStartup()) {
+        return "dvmDebuggerStartup failed";
+    }
+
+    if (!dvmGcStartupClasses()) {
+        return "dvmGcStartupClasses failed";
+    }
+
+    /*
+     * Init for either zygote mode or non-zygote mode.  The key difference
+     * is that we don't start any additional threads in Zygote mode.
+     */
+    if (gDvm.zygote) {
+        if (!initZygote()) {
+            return "initZygote failed";
+        }
+    } else {
+        if (!dvmInitAfterZygote()) {
+            return "dvmInitAfterZygote failed";
+        }
+    }
+
+
+#ifndef NDEBUG
+    if (!dvmTestHash())
+        LOGE("dvmTestHash FAILED");
+    if (false /*noisy!*/ && !dvmTestIndirectRefTable())
+        LOGE("dvmTestIndirectRefTable FAILED");
+#endif
+
+    if (dvmCheckException(dvmThreadSelf())) {
+        dvmLogExceptionStackTrace();
+        return "Exception pending at end of VM initialization";
+    }
+
+    scopedShutdown.disarm();
+    return "";
+}
+
+/*
+ * Register java.* natives from our class libraries.  We need to do
+ * this after we're ready for JNI registration calls, but before we
+ * do any class initialization.
+ *
+ * If we get this wrong, we will blow up in the ThreadGroup class init if
+ * interpreted code makes any reference to System.  It will likely do this
+ * since it wants to do some java.io.File setup (e.g. for static in/out/err).
+ *
+ * We need to have gDvm.initializing raised here so that JNI FindClass
+ * won't try to use the system/application class loader.
+ */
+static bool registerSystemNatives(JNIEnv* pEnv)
+{
+    Thread* self;
+
+    /* main thread is always first in list */
+    self = gDvm.threadList;
+
+    /* must set this before allowing JNI-based method registration */
+    self->status = THREAD_NATIVE;
+
+    if (jniRegisterSystemMethods(pEnv) < 0) {
+        LOGE("jniRegisterSystemMethods failed");
+        return false;
+    }
+
+    /* back to run mode */
+    self->status = THREAD_RUNNING;
+
+    return true;
+}
+
+
+/*
+ * Do zygote-mode-only initialization.
+ */
+static bool initZygote()
+{
+    /* zygote goes into its own process group */
+    setpgid(0,0);
+
+    return true;
+}
+
+/*
+ * Do non-zygote-mode initialization.  This is done during VM init for
+ * standard startup, or after a "zygote fork" when creating a new process.
+ */
+bool dvmInitAfterZygote()
+{
+    u8 startHeap, startQuit, startJdwp;
+    u8 endHeap, endQuit, endJdwp;
+
+    startHeap = dvmGetRelativeTimeUsec();
+
+    /*
+     * Post-zygote heap initialization, including starting
+     * the HeapWorker thread.
+     */
+    if (!dvmGcStartupAfterZygote())
+        return false;
+
+    endHeap = dvmGetRelativeTimeUsec();
+    startQuit = dvmGetRelativeTimeUsec();
+
+    /* start signal catcher thread that dumps stacks on SIGQUIT */
+    if (!gDvm.reduceSignals && !gDvm.noQuitHandler) {
+        if (!dvmSignalCatcherStartup())
+            return false;
+    }
+
+    /* start stdout/stderr copier, if requested */
+    if (gDvm.logStdio) {
+        if (!dvmStdioConverterStartup())
+            return false;
+    }
+
+    endQuit = dvmGetRelativeTimeUsec();
+    startJdwp = dvmGetRelativeTimeUsec();
+
+    /*
+     * Start JDWP thread.  If the command-line debugger flags specified
+     * "suspend=y", this will pause the VM.  We probably want this to
+     * come last.
+     */
+    if (!initJdwp()) {
+        LOGD("JDWP init failed; continuing anyway");
+    }
+
+    endJdwp = dvmGetRelativeTimeUsec();
+
+    LOGV("thread-start heap=%d quit=%d jdwp=%d total=%d usec",
+        (int)(endHeap-startHeap), (int)(endQuit-startQuit),
+        (int)(endJdwp-startJdwp), (int)(endJdwp-startHeap));
+
+#ifdef WITH_JIT
+    if (gDvm.executionMode == kExecutionModeJit) {
+        if (!dvmCompilerStartup())
+            return false;
+    }
+#endif
+
+    return true;
+}
+
+/*
+ * Prepare for a connection to a JDWP-compliant debugger.
+ *
+ * Note this needs to happen fairly late in the startup process, because
+ * we need to have all of the java.* native methods registered (which in
+ * turn requires JNI to be fully prepped).
+ *
+ * There are several ways to initialize:
+ *   server=n
+ *     We immediately try to connect to host:port.  Bail on failure.  On
+ *     success, send VM_START (suspending the VM if "suspend=y").
+ *   server=y suspend=n
+ *     Passively listen for a debugger to connect.  Return immediately.
+ *   server=y suspend=y
+ *     Wait until debugger connects.  Send VM_START ASAP, suspending the
+ *     VM after the message is sent.
+ *
+ * This gets more complicated with a nonzero value for "timeout".
+ */
+static bool initJdwp()
+{
+    assert(!gDvm.zygote);
+
+    /*
+     * Init JDWP if the debugger is enabled.  This may connect out to a
+     * debugger, passively listen for a debugger, or block waiting for a
+     * debugger.
+     */
+    if (gDvm.jdwpAllowed && gDvm.jdwpConfigured) {
+        JdwpStartupParams params;
+
+        if (gDvm.jdwpHost != NULL) {
+            if (strlen(gDvm.jdwpHost) >= sizeof(params.host)-1) {
+                LOGE("ERROR: hostname too long: '%s'", gDvm.jdwpHost);
+                return false;
+            }
+            strcpy(params.host, gDvm.jdwpHost);
+        } else {
+            params.host[0] = '\0';
+        }
+        params.transport = gDvm.jdwpTransport;
+        params.server = gDvm.jdwpServer;
+        params.suspend = gDvm.jdwpSuspend;
+        params.port = gDvm.jdwpPort;
+
+        gDvm.jdwpState = dvmJdwpStartup(&params);
+        if (gDvm.jdwpState == NULL) {
+            LOGW("WARNING: debugger thread failed to initialize");
+            /* TODO: ignore? fail? need to mimic "expected" behavior */
+        }
+    }
+
+    /*
+     * If a debugger has already attached, send the "welcome" message.  This
+     * may cause us to suspend all threads.
+     */
+    if (dvmJdwpIsActive(gDvm.jdwpState)) {
+        //dvmChangeStatus(NULL, THREAD_RUNNING);
+        if (!dvmJdwpPostVMStart(gDvm.jdwpState, gDvm.jdwpSuspend)) {
+            LOGW("WARNING: failed to post 'start' message to debugger");
+            /* keep going */
+        }
+        //dvmChangeStatus(NULL, THREAD_NATIVE);
+    }
+
+    return true;
+}
+
+/*
+ * An alternative to JNI_CreateJavaVM/dvmStartup that does the first bit
+ * of initialization and then returns with "initializing" still set.  (Used
+ * by DexOpt command-line utility.)
+ *
+ * Attempting to use JNI or internal natives will fail.  It's best
+ * if no bytecode gets executed, which means no <clinit>, which means
+ * no exception-throwing.  (In practice we need to initialize Class and
+ * Object, and probably some exception classes.)
+ *
+ * Returns 0 on success.
+ */
+int dvmPrepForDexOpt(const char* bootClassPath, DexOptimizerMode dexOptMode,
+    DexClassVerifyMode verifyMode, int dexoptFlags)
+{
+    gDvm.initializing = true;
+    gDvm.optimizing = true;
+
+    /* configure signal handling */
+    blockSignals();
+
+    /* set some defaults */
+    setCommandLineDefaults();
+    free(gDvm.bootClassPathStr);
+    gDvm.bootClassPathStr = strdup(bootClassPath);
+
+    /* set opt/verify modes */
+    gDvm.dexOptMode = dexOptMode;
+    gDvm.classVerifyMode = verifyMode;
+    gDvm.generateRegisterMaps = (dexoptFlags & DEXOPT_GEN_REGISTER_MAPS) != 0;
+    if (dexoptFlags & DEXOPT_SMP) {
+        assert((dexoptFlags & DEXOPT_UNIPROCESSOR) == 0);
+        gDvm.dexOptForSmp = true;
+    } else if (dexoptFlags & DEXOPT_UNIPROCESSOR) {
+        gDvm.dexOptForSmp = false;
+    } else {
+        gDvm.dexOptForSmp = (ANDROID_SMP != 0);
+    }
+
+    /*
+     * Initialize the heap, some basic thread control mutexes, and
+     * get the bootclasspath prepped.
+     *
+     * We can't load any classes yet because we may not yet have a source
+     * for things like java.lang.Object and java.lang.Class.
+     */
+    if (!dvmGcStartup())
+        goto fail;
+    if (!dvmThreadStartup())
+        goto fail;
+    if (!dvmInlineNativeStartup())
+        goto fail;
+    if (!dvmRegisterMapStartup())
+        goto fail;
+    if (!dvmInstanceofStartup())
+        goto fail;
+    if (!dvmClassStartup())
+        goto fail;
+
+    /*
+     * We leave gDvm.initializing set to "true" so that, if we're not
+     * able to process the "core" classes, we don't go into a death-spin
+     * trying to throw a "class not found" exception.
+     */
+
+    return 0;
+
+fail:
+    dvmShutdown();
+    return 1;
+}
+
+
+/*
+ * All threads have stopped.  Finish the shutdown procedure.
+ *
+ * We can also be called if startup fails partway through, so be prepared
+ * to deal with partially initialized data.
+ *
+ * Free any storage allocated in gGlobals.
+ *
+ * We can't dlclose() shared libs we've loaded, because it's possible a
+ * thread not associated with the VM is running code in one.
+ *
+ * This is called from the JNI DestroyJavaVM function, which can be
+ * called from any thread.  (In practice, this will usually run in the
+ * same thread that started the VM, a/k/a the main thread, but we don't
+ * want to assume that.)
+ */
+void dvmShutdown()
+{
+    LOGV("VM shutting down");
+
+    if (CALC_CACHE_STATS)
+        dvmDumpAtomicCacheStats(gDvm.instanceofCache);
+
+    /*
+     * Stop our internal threads.
+     */
+    dvmGcThreadShutdown();
+
+    if (gDvm.jdwpState != NULL)
+        dvmJdwpShutdown(gDvm.jdwpState);
+    free(gDvm.jdwpHost);
+    gDvm.jdwpHost = NULL;
+    free(gDvm.jniTrace);
+    gDvm.jniTrace = NULL;
+    free(gDvm.stackTraceFile);
+    gDvm.stackTraceFile = NULL;
+
+    /* tell signal catcher to shut down if it was started */
+    dvmSignalCatcherShutdown();
+
+    /* shut down stdout/stderr conversion */
+    dvmStdioConverterShutdown();
+
+#ifdef WITH_JIT
+    if (gDvm.executionMode == kExecutionModeJit) {
+        /* shut down the compiler thread */
+        dvmCompilerShutdown();
+    }
+#endif
+
+    /*
+     * Kill any daemon threads that still exist.  Actively-running threads
+     * are likely to crash the process if they continue to execute while
+     * the VM shuts down.
+     */
+    dvmSlayDaemons();
+
+    if (gDvm.verboseShutdown)
+        LOGD("VM cleaning up");
+
+    dvmDebuggerShutdown();
+    dvmProfilingShutdown();
+    dvmJniShutdown();
+    dvmStringInternShutdown();
+    dvmThreadShutdown();
+    dvmClassShutdown();
+    dvmRegisterMapShutdown();
+    dvmInstanceofShutdown();
+    dvmInlineNativeShutdown();
+    dvmGcShutdown();
+    dvmAllocTrackerShutdown();
+
+    /* these must happen AFTER dvmClassShutdown has walked through class data */
+    dvmNativeShutdown();
+    dvmInternalNativeShutdown();
+
+    dvmFreeInlineSubsTable();
+
+    free(gDvm.bootClassPathStr);
+    free(gDvm.classPathStr);
+    delete gDvm.properties;
+
+    freeAssertionCtrl();
+
+    /*
+     * We want valgrind to report anything we forget to free as "definitely
+     * lost".  If there's a pointer in the global chunk, it would be reported
+     * as "still reachable".  Erasing the memory fixes this.
+     *
+     * This must be erased to zero if we want to restart the VM within this
+     * process.
+     */
+    memset(&gDvm, 0xcd, sizeof(gDvm));
+}
+
+
+/*
+ * fprintf() wrapper that calls through the JNI-specified vfprintf hook if
+ * one was specified.
+ */
+int dvmFprintf(FILE* fp, const char* format, ...)
+{
+    va_list args;
+    int result;
+
+    va_start(args, format);
+    if (gDvm.vfprintfHook != NULL)
+        result = (*gDvm.vfprintfHook)(fp, format, args);
+    else
+        result = vfprintf(fp, format, args);
+    va_end(args);
+
+    return result;
+}
+
+#ifdef __GLIBC__
+#include <execinfo.h>
+/*
+ * glibc-only stack dump function.  Requires link with "--export-dynamic".
+ *
+ * TODO: move this into libs/cutils and make it work for all platforms.
+ */
+void dvmPrintNativeBackTrace()
+{
+    size_t MAX_STACK_FRAMES = 64;
+    void* stackFrames[MAX_STACK_FRAMES];
+    size_t frameCount = backtrace(stackFrames, MAX_STACK_FRAMES);
+
+    /*
+     * TODO: in practice, we may find that we should use backtrace_symbols_fd
+     * to avoid allocation, rather than use our own custom formatting.
+     */
+    char** strings = backtrace_symbols(stackFrames, frameCount);
+    if (strings == NULL) {
+        LOGE("backtrace_symbols failed: %s", strerror(errno));
+        return;
+    }
+
+    size_t i;
+    for (i = 0; i < frameCount; ++i) {
+        LOGW("#%-2d %s", i, strings[i]);
+    }
+    free(strings);
+}
+#else
+void dvmPrintNativeBackTrace() {
+    /* Hopefully, you're on an Android device and debuggerd will do this. */
+}
+#endif
+
+/*
+ * Abort the VM.  We get here on fatal errors.  Try very hard not to use
+ * this; whenever possible, return an error to somebody responsible.
+ */
+void dvmAbort()
+{
+    /*
+     * Leave gDvm.lastMessage on the stack frame which can be decoded in the
+     * tombstone file. This is for situations where we only have tombstone files
+     * but no logs (ie b/5372634).
+     *
+     * For example, in the tombstone file you usually see this:
+     *
+     *   #00  pc 00050ef2  /system/lib/libdvm.so (dvmAbort)
+     *   #01  pc 00077670  /system/lib/libdvm.so (_Z15dvmClassStartupv)
+     *     :
+     *
+     * stack:
+     *     :
+     * #00 beed2658  00000000
+     *     beed265c  7379732f
+     *     beed2660  2f6d6574
+     *     beed2664  6d617266
+     *     beed2668  726f7765
+     *     beed266c  6f632f6b
+     *     beed2670  6a2e6572
+     *     beed2674  00007261
+     *     beed2678  00000000
+     *
+     * The ascii values between beed265c and beed2674 belongs to messageBuffer
+     * and it can be decoded as "/system/framework/core.jar".
+     */
+    const int messageLength = 512;
+    char messageBuffer[messageLength] = {0};
+    int result = 0;
+
+    snprintf(messageBuffer, messageLength, "%s", gDvm.lastMessage);
+
+    /* So that messageBuffer[] looks like useful stuff to the compiler */
+    for (int i = 0; i < messageLength && messageBuffer[i]; i++) {
+        result += messageBuffer[i];
+    }
+
+    LOGE("VM aborting");
+
+    fflush(NULL);       // flush all open file buffers
+
+    /* JNI-supplied abort hook gets right of first refusal */
+    if (gDvm.abortHook != NULL)
+        (*gDvm.abortHook)();
+
+    /*
+     * On the device, debuggerd will give us a stack trace.
+     * On the host, we have to help ourselves.
+     */
+    dvmPrintNativeBackTrace();
+
+    /*
+     * If we call abort(), all threads in the process receives a SIBABRT.
+     * debuggerd dumps the stack trace of the main thread, whether or not
+     * that was the thread that failed.
+     *
+     * By stuffing a value into a bogus address, we cause a segmentation
+     * fault in the current thread, and get a useful log from debuggerd.
+     * We can also trivially tell the difference between a VM crash and
+     * a deliberate abort by looking at the fault address.
+     */
+    *((char*)0xdeadd00d) = result;
+    abort();
+
+    /* notreached */
+}
diff --git a/vm/Init.h b/vm/Init.h
new file mode 100644
index 0000000..1b585fa
--- /dev/null
+++ b/vm/Init.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+/*
+ * VM initialization and shutdown.
+ */
+#ifndef DALVIK_INIT_H_
+#define DALVIK_INIT_H_
+
+/*
+ * Standard VM initialization, usually invoked through JNI.
+ */
+std::string dvmStartup(int argc, const char* const argv[],
+        bool ignoreUnrecognized, JNIEnv* pEnv);
+void dvmShutdown(void);
+bool dvmInitAfterZygote(void);
+
+/*
+ * Enable Java programming language assert statements after the Zygote fork.
+ */
+void dvmLateEnableAssertions(void);
+
+/*
+ * Partial VM initialization; only used as part of "dexopt", which may be
+ * asked to optimize a DEX file holding fundamental classes.
+ */
+int dvmPrepForDexOpt(const char* bootClassPath, DexOptimizerMode dexOptMode,
+    DexClassVerifyMode verifyMode, int dexoptFlags);
+
+/*
+ * Look up the set of classes and members used directly by the VM,
+ * storing references to them into the globals instance. See
+ * Globals.h. This function is exposed so that dex optimization may
+ * call it (while avoiding doing other unnecessary VM initialization).
+ *
+ * The function returns a success flag (true == success).
+ */
+bool dvmFindRequiredClassesAndMembers(void);
+
+/*
+ * Look up required members of the class Reference, and set the global
+ * reference to Reference itself too. This needs to be done separately
+ * from dvmFindRequiredClassesAndMembers(), during the course of
+ * linking the class Reference (which is done specially).
+ */
+bool dvmFindReferenceMembers(ClassObject* classReference);
+
+/*
+ * 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, ...)
+#if defined(__GNUC__)
+    __attribute__ ((format(printf, 2, 3)))
+#endif
+    ;
+
+#endif  // DALVIK_INIT_H_
diff --git a/vm/InitRefs.cpp b/vm/InitRefs.cpp
new file mode 100644
index 0000000..6fddf9a
--- /dev/null
+++ b/vm/InitRefs.cpp
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*
+ * Code to initialize references to classes and members for use by
+ * lower-level VM facilities
+ */
+
+#include "Dalvik.h"
+
+static bool initClassReference(ClassObject** pClass, const char* name) {
+    ClassObject* result;
+
+    assert(*pClass == NULL);
+
+    if (name[0] == '[') {
+        result = dvmFindArrayClass(name, NULL);
+    } else {
+        result = dvmFindSystemClassNoInit(name);
+    }
+
+    if (result == NULL) {
+        LOGE("Could not find essential class %s", name);
+        return false;
+    }
+
+    *pClass = result;
+    return true;
+}
+
+static bool initClassReferences() {
+    static struct { ClassObject** ref; const char* name; } classes[] = {
+        /*
+         * Note: The class Class gets special treatment during initial
+         * VM startup, so there is no need to list it here.
+         */
+
+        /* The corest of the core classes */
+        { &gDvm.classJavaLangObject, "Ljava/lang/Object;" },
+        { &gDvm.exThrowable,         "Ljava/lang/Throwable;" },
+
+        /* Slightly less core, but still down there, classes */
+        { &gDvm.classJavaLangClassArray,             "[Ljava/lang/Class;" },
+        { &gDvm.classJavaLangClassLoader,            "Ljava/lang/ClassLoader;" },
+        { &gDvm.classJavaLangObjectArray,            "[Ljava/lang/Object;"},
+        { &gDvm.classJavaLangStackTraceElement,      "Ljava/lang/StackTraceElement;" },
+        { &gDvm.classJavaLangStackTraceElementArray, "[Ljava/lang/StackTraceElement;" },
+        { &gDvm.classJavaLangString,                 "Ljava/lang/String;" },
+        { &gDvm.classJavaLangThread,                 "Ljava/lang/Thread;" },
+        { &gDvm.classJavaLangThreadGroup,            "Ljava/lang/ThreadGroup;" },
+        { &gDvm.classJavaLangVMThread,               "Ljava/lang/VMThread;" },
+
+        /* Arrays of primitive types */
+        { &gDvm.classArrayBoolean, "[Z" },
+        { &gDvm.classArrayByte,    "[B" },
+        { &gDvm.classArrayShort,   "[S" },
+        { &gDvm.classArrayChar,    "[C" },
+        { &gDvm.classArrayInt,     "[I" },
+        { &gDvm.classArrayLong,    "[J" },
+        { &gDvm.classArrayFloat,   "[F" },
+        { &gDvm.classArrayDouble,  "[D" },
+
+        /* Exception classes */
+        { &gDvm.exAbstractMethodError,             "Ljava/lang/AbstractMethodError;" },
+        { &gDvm.exArithmeticException,             "Ljava/lang/ArithmeticException;" },
+        { &gDvm.exArrayIndexOutOfBoundsException,  "Ljava/lang/ArrayIndexOutOfBoundsException;" },
+        { &gDvm.exArrayStoreException,             "Ljava/lang/ArrayStoreException;" },
+        { &gDvm.exClassCastException,              "Ljava/lang/ClassCastException;" },
+        { &gDvm.exClassCircularityError,           "Ljava/lang/ClassCircularityError;" },
+        { &gDvm.exClassNotFoundException,          "Ljava/lang/ClassNotFoundException;" },
+        { &gDvm.exClassFormatError,                "Ljava/lang/ClassFormatError;" },
+        { &gDvm.exError,                           "Ljava/lang/Error;" },
+        { &gDvm.exExceptionInInitializerError,     "Ljava/lang/ExceptionInInitializerError;" },
+        { &gDvm.exFileNotFoundException,           "Ljava/io/FileNotFoundException;" },
+        { &gDvm.exIOException,                     "Ljava/io/IOException;" },
+        { &gDvm.exIllegalAccessError,              "Ljava/lang/IllegalAccessError;" },
+        { &gDvm.exIllegalAccessException,          "Ljava/lang/IllegalAccessException;" },
+        { &gDvm.exIllegalArgumentException,        "Ljava/lang/IllegalArgumentException;" },
+        { &gDvm.exIllegalMonitorStateException,    "Ljava/lang/IllegalMonitorStateException;" },
+        { &gDvm.exIllegalStateException,           "Ljava/lang/IllegalStateException;" },
+        { &gDvm.exIllegalThreadStateException,     "Ljava/lang/IllegalThreadStateException;" },
+        { &gDvm.exIncompatibleClassChangeError,    "Ljava/lang/IncompatibleClassChangeError;" },
+        { &gDvm.exInstantiationError,              "Ljava/lang/InstantiationError;" },
+        { &gDvm.exInstantiationException,          "Ljava/lang/InstantiationException;" },
+        { &gDvm.exInternalError,                   "Ljava/lang/InternalError;" },
+        { &gDvm.exInterruptedException,            "Ljava/lang/InterruptedException;" },
+        { &gDvm.exLinkageError,                    "Ljava/lang/LinkageError;" },
+        { &gDvm.exNegativeArraySizeException,      "Ljava/lang/NegativeArraySizeException;" },
+        { &gDvm.exNoClassDefFoundError,            "Ljava/lang/NoClassDefFoundError;" },
+        { &gDvm.exNoSuchFieldError,                "Ljava/lang/NoSuchFieldError;" },
+        { &gDvm.exNoSuchFieldException,            "Ljava/lang/NoSuchFieldException;" },
+        { &gDvm.exNoSuchMethodError,               "Ljava/lang/NoSuchMethodError;" },
+        { &gDvm.exNullPointerException,            "Ljava/lang/NullPointerException;" },
+        { &gDvm.exOutOfMemoryError,                "Ljava/lang/OutOfMemoryError;" },
+        { &gDvm.exRuntimeException,                "Ljava/lang/RuntimeException;" },
+        { &gDvm.exStackOverflowError,              "Ljava/lang/StackOverflowError;" },
+        { &gDvm.exStaleDexCacheError,              "Ldalvik/system/StaleDexCacheError;" },
+        { &gDvm.exStringIndexOutOfBoundsException, "Ljava/lang/StringIndexOutOfBoundsException;" },
+        { &gDvm.exTypeNotPresentException,         "Ljava/lang/TypeNotPresentException;" },
+        { &gDvm.exUnsatisfiedLinkError,            "Ljava/lang/UnsatisfiedLinkError;" },
+        { &gDvm.exUnsupportedOperationException,   "Ljava/lang/UnsupportedOperationException;" },
+        { &gDvm.exVerifyError,                     "Ljava/lang/VerifyError;" },
+        { &gDvm.exVirtualMachineError,             "Ljava/lang/VirtualMachineError;" },
+
+        /* Other classes */
+        { &gDvm.classJavaLangAnnotationAnnotationArray, "[Ljava/lang/annotation/Annotation;" },
+        { &gDvm.classJavaLangAnnotationAnnotationArrayArray,
+          "[[Ljava/lang/annotation/Annotation;" },
+        { &gDvm.classJavaLangReflectAccessibleObject,   "Ljava/lang/reflect/AccessibleObject;" },
+        { &gDvm.classJavaLangReflectConstructor,        "Ljava/lang/reflect/Constructor;" },
+        { &gDvm.classJavaLangReflectConstructorArray,   "[Ljava/lang/reflect/Constructor;" },
+        { &gDvm.classJavaLangReflectField,              "Ljava/lang/reflect/Field;" },
+        { &gDvm.classJavaLangReflectFieldArray,         "[Ljava/lang/reflect/Field;" },
+        { &gDvm.classJavaLangReflectMethod,             "Ljava/lang/reflect/Method;" },
+        { &gDvm.classJavaLangReflectMethodArray,        "[Ljava/lang/reflect/Method;"},
+        { &gDvm.classJavaLangReflectProxy,              "Ljava/lang/reflect/Proxy;" },
+        { &gDvm.classJavaNioReadWriteDirectByteBuffer,  "Ljava/nio/ReadWriteDirectByteBuffer;" },
+        { &gDvm.classOrgApacheHarmonyDalvikDdmcChunk,
+          "Lorg/apache/harmony/dalvik/ddmc/Chunk;" },
+        { &gDvm.classOrgApacheHarmonyDalvikDdmcDdmServer,
+          "Lorg/apache/harmony/dalvik/ddmc/DdmServer;" },
+        { &gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory,
+          "Lorg/apache/harmony/lang/annotation/AnnotationFactory;" },
+        { &gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember,
+          "Lorg/apache/harmony/lang/annotation/AnnotationMember;" },
+        { &gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray,
+          "[Lorg/apache/harmony/lang/annotation/AnnotationMember;" },
+
+        { NULL, NULL }
+    };
+
+    int i;
+    for (i = 0; classes[i].ref != NULL; i++) {
+        if (!initClassReference(classes[i].ref, classes[i].name)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool initFieldOffset(ClassObject* clazz, int *pOffset,
+        const char* name, const char* type) {
+    int offset = dvmFindFieldOffset(clazz, name, type);
+    if (offset < 0) {
+        LOGE("Could not find essential field %s.%s of type %s", clazz->descriptor, name, type);
+        return false;
+    }
+
+    *pOffset = offset;
+    return true;
+}
+
+static bool initFieldOffsets() {
+    struct FieldInfo {
+        int* offset;
+        const char* name;
+        const char* type;
+    };
+
+    static struct FieldInfo infoDdmcChunk[] = {
+        { &gDvm.offDalvikDdmcChunk_type,   "type",   "I" },
+        { &gDvm.offDalvikDdmcChunk_data,   "data",   "[B" },
+        { &gDvm.offDalvikDdmcChunk_offset, "offset", "I" },
+        { &gDvm.offDalvikDdmcChunk_length, "length", "I" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoFileDescriptor[] = {
+        { &gDvm.offJavaIoFileDescriptor_descriptor, "descriptor", "I" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoString[] = {
+        { &gDvm.offJavaLangString_value,    "value",    "[C" },
+        { &gDvm.offJavaLangString_count,    "count",    "I" },
+        { &gDvm.offJavaLangString_offset,   "offset",   "I" },
+        { &gDvm.offJavaLangString_hashCode, "hashCode", "I" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoThread[] = {
+        { &gDvm.offJavaLangThread_vmThread,           "vmThread",           "Ljava/lang/VMThread;" },
+        { &gDvm.offJavaLangThread_group,              "group",              "Ljava/lang/ThreadGroup;" },
+        { &gDvm.offJavaLangThread_daemon,             "daemon",             "Z" },
+        { &gDvm.offJavaLangThread_name,               "name",               "Ljava/lang/String;" },
+        { &gDvm.offJavaLangThread_priority,           "priority",           "I" },
+        { &gDvm.offJavaLangThread_uncaughtHandler,    "uncaughtHandler",    "Ljava/lang/Thread$UncaughtExceptionHandler;" },
+        { &gDvm.offJavaLangThread_contextClassLoader, "contextClassLoader", "Ljava/lang/ClassLoader;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoThreadGroup[] = {
+        { &gDvm.offJavaLangThreadGroup_name,   "name",   "Ljava/lang/String;" },
+        { &gDvm.offJavaLangThreadGroup_parent, "parent", "Ljava/lang/ThreadGroup;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoThrowable[] = {
+        { &gDvm.offJavaLangThrowable_stackState, "stackState", "Ljava/lang/Object;" },
+        { &gDvm.offJavaLangThrowable_cause,      "cause",      "Ljava/lang/Throwable;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoVMThread[] = {
+        { &gDvm.offJavaLangVMThread_thread, "thread", "Ljava/lang/Thread;" },
+        { &gDvm.offJavaLangVMThread_vmData, "vmData", "I" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoFinalizerReference[] = {
+        { &gDvm.offJavaLangRefFinalizerReference_zombie, "zombie", "Ljava/lang/Object;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoConstructor[] = {
+        { &gDvm.offJavaLangReflectConstructor_slot,      "slot",           "I" },
+        { &gDvm.offJavaLangReflectConstructor_declClass, "declaringClass", "Ljava/lang/Class;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoField[] = {
+        { &gDvm.offJavaLangReflectField_slot,      "slot",           "I" },
+        { &gDvm.offJavaLangReflectField_declClass, "declaringClass", "Ljava/lang/Class;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoMethod[] = {
+        { &gDvm.offJavaLangReflectMethod_slot,      "slot",           "I" },
+        { &gDvm.offJavaLangReflectMethod_declClass, "declaringClass", "Ljava/lang/Class;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoProxy[] = {
+        { &gDvm.offJavaLangReflectProxy_h, "h", "Ljava/lang/reflect/InvocationHandler;" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct FieldInfo infoBuffer[] = {
+        { &gDvm.offJavaNioBuffer_capacity,               "capacity",               "I" },
+        { &gDvm.offJavaNioBuffer_effectiveDirectAddress, "effectiveDirectAddress", "I" },
+        { NULL, NULL, NULL }
+    };
+
+    static struct { const char* name; const struct FieldInfo* fields; } classes[] = {
+        { "Lorg/apache/harmony/dalvik/ddmc/Chunk;", infoDdmcChunk },
+        { "Ljava/io/FileDescriptor;",               infoFileDescriptor },
+        { "Ljava/lang/String;",                     infoString },
+        { "Ljava/lang/Thread;",                     infoThread },
+        { "Ljava/lang/ThreadGroup;",                infoThreadGroup },
+        { "Ljava/lang/Throwable;",                  infoThrowable },
+        { "Ljava/lang/VMThread;",                   infoVMThread },
+        { "Ljava/lang/ref/FinalizerReference;", infoFinalizerReference },
+        { "Ljava/lang/reflect/Constructor;",        infoConstructor },
+        { "Ljava/lang/reflect/Field;",              infoField },
+        { "Ljava/lang/reflect/Method;",             infoMethod },
+        { "Ljava/lang/reflect/Proxy;",              infoProxy },
+        { "Ljava/nio/Buffer;",                      infoBuffer },
+        { NULL, NULL }
+    };
+
+    int i;
+    for (i = 0; classes[i].name != NULL; i++) {
+        const char* className = classes[i].name;
+        ClassObject* clazz = dvmFindSystemClassNoInit(className);
+        const struct FieldInfo* fields = classes[i].fields;
+
+        if (clazz == NULL) {
+            LOGE("Could not find essential class %s for field lookup", className);
+            return false;
+        }
+
+        int j;
+        for (j = 0; fields[j].offset != NULL; j++) {
+            if (!initFieldOffset(clazz, fields[j].offset, fields[j].name, fields[j].type)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+static bool initDirectMethodReferenceByClass(Method** pMethod, ClassObject* clazz,
+        const char* name, const char* descriptor) {
+    Method* method = dvmFindDirectMethodByDescriptor(clazz, name, descriptor);
+
+    if (method == NULL) {
+        LOGE("Could not find essential direct method %s.%s with descriptor %s",
+                clazz->descriptor, name, descriptor);
+        return false;
+    }
+
+    *pMethod = method;
+    return true;
+}
+
+static bool initDirectMethodReference(Method** pMethod, const char* className,
+        const char* name, const char* descriptor) {
+    ClassObject* clazz = dvmFindSystemClassNoInit(className);
+
+    if (clazz == NULL) {
+        LOGE("Could not find essential class %s for direct method lookup", className);
+        return false;
+    }
+
+    return initDirectMethodReferenceByClass(pMethod, clazz, name, descriptor);
+}
+
+static bool initConstructorReferences() {
+    static struct { Method** method; const char* name; const char* descriptor; } constructors[] = {
+        { &gDvm.methJavaLangStackTraceElement_init, "Ljava/lang/StackTraceElement;",
+          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V" },
+        { &gDvm.methJavaLangReflectConstructor_init, "Ljava/lang/reflect/Constructor;",
+          "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;I)V" },
+        { &gDvm.methJavaLangReflectField_init, "Ljava/lang/reflect/Field;",
+          "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;I)V" },
+        { &gDvm.methJavaLangReflectMethod_init, "Ljava/lang/reflect/Method;",
+          "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;"
+          "Ljava/lang/String;I)V" },
+        { &gDvm.methJavaNioReadWriteDirectByteBuffer_init, "Ljava/nio/ReadWriteDirectByteBuffer;",
+          "(II)V" },
+        { &gDvm.methOrgApacheHarmonyLangAnnotationAnnotationMember_init,
+          "Lorg/apache/harmony/lang/annotation/AnnotationMember;",
+          "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/reflect/Method;)V" },
+        { NULL, NULL, NULL }
+    };
+
+    int i;
+    for (i = 0; constructors[i].method != NULL; i++) {
+        if (!initDirectMethodReference(constructors[i].method, constructors[i].name,
+                "<init>", constructors[i].descriptor)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool initDirectMethodReferences() {
+    static struct {
+        Method** method;
+        const char* className;
+        const char* name;
+        const char* descriptor;
+    } methods[] = {
+        { &gDvm.methJavaLangClassLoader_getSystemClassLoader, "Ljava/lang/ClassLoader;",
+          "getSystemClassLoader", "()Ljava/lang/ClassLoader;" },
+        { &gDvm.methJavaLangReflectProxy_constructorPrototype, "Ljava/lang/reflect/Proxy;",
+          "constructorPrototype", "(Ljava/lang/reflect/InvocationHandler;)V" },
+        { &gDvm.methodTraceGcMethod, "Ldalvik/system/VMDebug;", "startGC", "()V" },
+        { &gDvm.methodTraceClassPrepMethod, "Ldalvik/system/VMDebug;", "startClassPrep", "()V" },
+        { &gDvm.methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation,
+          "Lorg/apache/harmony/lang/annotation/AnnotationFactory;", "createAnnotation",
+          "(Ljava/lang/Class;[Lorg/apache/harmony/lang/annotation/AnnotationMember;)"
+          "Ljava/lang/annotation/Annotation;" },
+        { &gDvm.methDalvikSystemNativeStart_main, "Ldalvik/system/NativeStart;", "main", "([Ljava/lang/String;)V" },
+        { &gDvm.methDalvikSystemNativeStart_run, "Ldalvik/system/NativeStart;", "run", "()V" },
+        { &gDvm.methJavaLangRefFinalizerReferenceAdd,
+          "Ljava/lang/ref/FinalizerReference;", "add", "(Ljava/lang/Object;)V" },
+        { &gDvm.methDalvikDdmcServer_dispatch,
+          "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;" },
+        { &gDvm.methDalvikDdmcServer_broadcast,
+          "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", "broadcast", "(I)V" },
+        { &gDvm.methJavaLangRefReferenceQueueAdd,
+          "Ljava/lang/ref/ReferenceQueue;", "add", "(Ljava/lang/ref/Reference;)V" },
+        { NULL, NULL, NULL, NULL }
+    };
+
+    int i;
+    for (i = 0; methods[i].method != NULL; i++) {
+        if (!initDirectMethodReference(methods[i].method, methods[i].className,
+                methods[i].name, methods[i].descriptor)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool initVirtualMethodOffset(int* pOffset, const char* className,
+        const char* name, const char* descriptor) {
+    ClassObject* clazz = dvmFindSystemClassNoInit(className);
+
+    if (clazz == NULL) {
+        LOGE("Could not find essential class %s for virtual method lookup", className);
+        return false;
+    }
+
+    Method* method = dvmFindVirtualMethodByDescriptor(clazz, name, descriptor);
+
+    if (method == NULL) {
+        LOGE("Could not find essential virtual method %s.%s with descriptor %s",
+                clazz->descriptor, name, descriptor);
+        return false;
+    }
+
+    *pOffset = method->methodIndex;
+    return true;
+}
+
+static bool initVirtualMethodOffsets() {
+    static struct {
+        int* offset;
+        const char* className;
+        const char* name;
+        const char* descriptor;
+    } methods[] = {
+        { &gDvm.voffJavaLangClassLoader_loadClass, "Ljava/lang/ClassLoader;", "loadClass",
+          "(Ljava/lang/String;)Ljava/lang/Class;" },
+        { &gDvm.voffJavaLangObject_equals, "Ljava/lang/Object;", "equals",
+          "(Ljava/lang/Object;)Z" },
+        { &gDvm.voffJavaLangObject_hashCode, "Ljava/lang/Object;", "hashCode", "()I" },
+        { &gDvm.voffJavaLangObject_toString, "Ljava/lang/Object;", "toString",
+          "()Ljava/lang/String;" },
+        { &gDvm.voffJavaLangThread_run, "Ljava/lang/Thread;", "run", "()V" },
+        { &gDvm.voffJavaLangThreadGroup_removeThread, "Ljava/lang/ThreadGroup;",
+          "removeThread", "(Ljava/lang/Thread;)V" },
+        { NULL, NULL, NULL, NULL }
+    };
+
+    int i;
+    for (i = 0; methods[i].offset != NULL; i++) {
+        if (!initVirtualMethodOffset(methods[i].offset, methods[i].className,
+                methods[i].name, methods[i].descriptor)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool initFinalizerReference()
+{
+    gDvm.classJavaLangRefFinalizerReference =
+        dvmFindSystemClass("Ljava/lang/ref/FinalizerReference;");
+    return gDvm.classJavaLangRefFinalizerReference != NULL;
+}
+
+static bool verifyStringOffset(const char* name, int actual, int expected) {
+    if (actual != expected) {
+        LOGE("InitRefs: String.%s offset = %d; expected %d", name, actual, expected);
+        return false;
+    }
+
+    return true;
+}
+
+static bool verifyStringOffsets() {
+    /*
+     * Various parts of the system use predefined constants for the
+     * offsets to a few fields of the class String. This code verifies
+     * that the predefined offsets match what is actually defined by
+     * the class.
+     */
+
+    bool ok = true;
+    ok &= verifyStringOffset("value",    gDvm.offJavaLangString_value,  STRING_FIELDOFF_VALUE);
+    ok &= verifyStringOffset("count",    gDvm.offJavaLangString_count,  STRING_FIELDOFF_COUNT);
+    ok &= verifyStringOffset("offset",   gDvm.offJavaLangString_offset, STRING_FIELDOFF_OFFSET);
+    ok &= verifyStringOffset("hashCode", gDvm.offJavaLangString_hashCode,
+            STRING_FIELDOFF_HASHCODE);
+
+    return ok;
+}
+
+/* (documented in header) */
+bool dvmFindRequiredClassesAndMembers() {
+    /*
+     * Note: Under normal VM use, this is called by dvmStartup()
+     * in Init.c. For dex optimization, this is called as well, but in
+     * that case, the call is made from DexPrepare.c.
+     */
+
+    return initClassReferences()
+        && initFieldOffsets()
+        && initConstructorReferences()
+        && initDirectMethodReferences()
+        && initVirtualMethodOffsets()
+        && initFinalizerReference()
+        && verifyStringOffsets();
+}
+
+/* (documented in header) */
+bool dvmFindReferenceMembers(ClassObject* classReference) {
+    if (strcmp(classReference->descriptor, "Ljava/lang/ref/Reference;") != 0) {
+        LOGE("Attempt to set up the wrong class as Reference");
+        return false;
+    }
+    return initFieldOffset(classReference, &gDvm.offJavaLangRefReference_pendingNext,
+                "pendingNext", "Ljava/lang/ref/Reference;")
+        && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queue,
+                "queue", "Ljava/lang/ref/ReferenceQueue;")
+        && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_queueNext,
+                "queueNext", "Ljava/lang/ref/Reference;")
+        && initFieldOffset(classReference, &gDvm.offJavaLangRefReference_referent,
+                "referent", "Ljava/lang/Object;");
+}
diff --git a/vm/InlineNative.cpp b/vm/InlineNative.cpp
new file mode 100644
index 0000000..124031d
--- /dev/null
+++ b/vm/InlineNative.cpp
@@ -0,0 +1,923 @@
+/*
+ * 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.
+ */
+
+/*
+ * Inlined native functions.  These definitions replace interpreted or
+ * native implementations at runtime; "intrinsic" might be a better word.
+ */
+#include "Dalvik.h"
+
+#include <math.h>
+
+#ifdef HAVE__MEMCMP16
+/* hand-coded assembly implementation, available on some platforms */
+//#warning "trying memcmp16"
+//#define CHECK_MEMCMP16
+/* "count" is in 16-bit units */
+extern "C" u4 __memcmp16(const u2* s0, const u2* s1, size_t count);
+#endif
+
+/*
+ * Some notes on "inline" functions.
+ *
+ * These are NOT simply native implementations.  A full method definition
+ * must still be provided.  Depending on the flags passed into the VM
+ * at runtime, the original or inline version may be selected by the
+ * DEX optimizer.
+ *
+ * PLEASE DO NOT use this as the default location for native methods.
+ * The difference between this and an "internal native" static method
+ * call on a 200MHz ARM 9 is roughly 370ns vs. 700ns.  The code here
+ * "secretly replaces" the other method, so you can't avoid having two
+ * implementations.  Since the DEX optimizer mode can't be known ahead
+ * of time, both implementations must be correct and complete.
+ *
+ * The only stuff that really needs to be here are methods that
+ * are high-volume or must be low-overhead, e.g. certain String/Math
+ * methods and some java.util.concurrent.atomic operations.
+ *
+ * Normally, a class is loaded and initialized the first time a static
+ * method is invoked.  This property is NOT preserved here.  If you need
+ * to access a static field in a class, you must ensure initialization
+ * yourself (cheap/easy way is to check the resolved-methods table, and
+ * resolve the method if it hasn't been).
+ *
+ * DO NOT replace "synchronized" methods.  We do not support method
+ * synchronization here.
+ *
+ * DO NOT perform any allocations or do anything that could cause a
+ * garbage collection.  The method arguments are not visible to the GC
+ * and will not be pinned or updated when memory blocks move.  You are
+ * allowed to allocate and throw an exception so long as you only do so
+ * immediately before returning.
+ *
+ * Remember that these functions are executing while the thread is in
+ * the "RUNNING" state, not the "NATIVE" state.  If you perform a blocking
+ * operation you can stall the entire VM if the GC or debugger wants to
+ * suspend the thread.  Since these are arguably native implementations
+ * rather than VM internals, prefer NATIVE to VMWAIT if you want to change
+ * the thread state.
+ *
+ * Always write results to 32-bit or 64-bit fields in "pResult", e.g. do
+ * not write boolean results to pResult->z.  The interpreter expects
+ * 32 or 64 bits to be set.
+ *
+ * Inline op methods return "false" if an exception was thrown, "true" if
+ * everything went well.
+ *
+ * DO NOT provide implementations of methods that can be overridden by a
+ * subclass, as polymorphism does not work correctly.  For safety you should
+ * only provide inline functions for classes/methods declared "final".
+ *
+ * It's best to avoid inlining the overridden version of a method.  For
+ * example, String.hashCode() is inherited from Object.hashCode().  Code
+ * calling String.hashCode() through an Object reference will run the
+ * "slow" version, while calling it through a String reference gets
+ * the inlined version.  It's best to have just one version unless there
+ * are clear performance gains.
+ *
+ * Because the actual method is not called, debugger breakpoints on these
+ * methods will not happen.  (TODO: have the code here find the original
+ * method and call it when the debugger is active.)  Additional steps have
+ * been taken to allow method profiling to produce correct results.
+ */
+
+
+/*
+ * ===========================================================================
+ *      org.apache.harmony.dalvik.NativeTestTarget
+ * ===========================================================================
+ */
+
+/*
+ * public static void emptyInlineMethod
+ *
+ * This exists only for benchmarks.
+ */
+static bool org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod(
+    u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+{
+    // do nothing
+    return true;
+}
+
+
+/*
+ * ===========================================================================
+ *      java.lang.String
+ * ===========================================================================
+ */
+
+/*
+ * public char charAt(int index)
+ */
+bool javaLangString_charAt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    int count, offset;
+    ArrayObject* chars;
+
+    /* null reference check on "this" */
+    if ((Object*) arg0 == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+
+    //LOGI("String.charAt this=0x%08x index=%d", arg0, arg1);
+    count = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
+    if ((s4) arg1 < 0 || (s4) arg1 >= count) {
+        dvmThrowStringIndexOutOfBoundsExceptionWithIndex(count, arg1);
+        return false;
+    } else {
+        offset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
+        chars = (ArrayObject*)
+            dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
+
+        pResult->i = ((const u2*)(void*)chars->contents)[arg1 + offset];
+        return true;
+    }
+}
+
+#ifdef CHECK_MEMCMP16
+/*
+ * Utility function when we're evaluating alternative implementations.
+ */
+static void badMatch(StringObject* thisStrObj, StringObject* compStrObj,
+    int expectResult, int newResult, const char* compareType)
+{
+    ArrayObject* thisArray;
+    ArrayObject* compArray;
+    const char* thisStr;
+    const char* compStr;
+    int thisOffset, compOffset, thisCount, compCount;
+
+    thisCount =
+        dvmGetFieldInt((Object*) thisStrObj, STRING_FIELDOFF_COUNT);
+    compCount =
+        dvmGetFieldInt((Object*) compStrObj, STRING_FIELDOFF_COUNT);
+    thisOffset =
+        dvmGetFieldInt((Object*) thisStrObj, STRING_FIELDOFF_OFFSET);
+    compOffset =
+        dvmGetFieldInt((Object*) compStrObj, STRING_FIELDOFF_OFFSET);
+    thisArray = (ArrayObject*)
+        dvmGetFieldObject((Object*) thisStrObj, STRING_FIELDOFF_VALUE);
+    compArray = (ArrayObject*)
+        dvmGetFieldObject((Object*) compStrObj, STRING_FIELDOFF_VALUE);
+
+    thisStr = dvmCreateCstrFromString(thisStrObj);
+    compStr = dvmCreateCstrFromString(compStrObj);
+
+    LOGE("%s expected %d got %d", compareType, expectResult, newResult);
+    LOGE(" this (o=%d l=%d) '%s'", thisOffset, thisCount, thisStr);
+    LOGE(" comp (o=%d l=%d) '%s'", compOffset, compCount, compStr);
+    dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
+        ((const u2*) thisArray->contents) + thisOffset, thisCount*2,
+        kHexDumpLocal);
+    dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
+        ((const u2*) compArray->contents) + compOffset, compCount*2,
+        kHexDumpLocal);
+    dvmAbort();
+}
+#endif
+
+/*
+ * public int compareTo(String s)
+ */
+bool javaLangString_compareTo(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    /*
+     * Null reference check on "this".  Normally this is performed during
+     * the setup of the virtual method call.  We need to do it before
+     * anything else.  While we're at it, check out the other string,
+     * which must also be non-null.
+     */
+    if ((Object*) arg0 == NULL || (Object*) arg1 == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+
+    /* quick test for comparison with itself */
+    if (arg0 == arg1) {
+        pResult->i = 0;
+        return true;
+    }
+
+    /*
+     * This would be simpler and faster if we promoted StringObject to
+     * a full representation, lining up the C structure fields with the
+     * actual object fields.
+     */
+    int thisCount, thisOffset, compCount, compOffset;
+    ArrayObject* thisArray;
+    ArrayObject* compArray;
+    const u2* thisChars;
+    const u2* compChars;
+    int minCount, countDiff;
+
+    thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
+    compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
+    countDiff = thisCount - compCount;
+    minCount = (countDiff < 0) ? thisCount : compCount;
+    thisOffset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
+    compOffset = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_OFFSET);
+    thisArray = (ArrayObject*)
+        dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
+    compArray = (ArrayObject*)
+        dvmGetFieldObject((Object*) arg1, STRING_FIELDOFF_VALUE);
+    thisChars = ((const u2*)(void*)thisArray->contents) + thisOffset;
+    compChars = ((const u2*)(void*)compArray->contents) + compOffset;
+
+#ifdef HAVE__MEMCMP16
+    /*
+     * Use assembly version, which returns the difference between the
+     * characters.  The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
+     * because the interpreter converts the characters to 32-bit integers
+     * *without* sign extension before it subtracts them (which makes some
+     * sense since "char" is unsigned).  So what we get is the result of
+     * 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
+     */
+    int otherRes = __memcmp16(thisChars, compChars, minCount);
+# ifdef CHECK_MEMCMP16
+    int i;
+    for (i = 0; i < minCount; i++) {
+        if (thisChars[i] != compChars[i]) {
+            pResult->i = (s4) thisChars[i] - (s4) compChars[i];
+            if (pResult->i != otherRes) {
+                badMatch((StringObject*) arg0, (StringObject*) arg1,
+                    pResult->i, otherRes, "compareTo");
+            }
+            return true;
+        }
+    }
+# endif
+    if (otherRes != 0) {
+        pResult->i = otherRes;
+        return true;
+    }
+
+#else
+    /*
+     * Straightforward implementation, examining 16 bits at a time.  Compare
+     * the characters that overlap, and if they're all the same then return
+     * the difference in lengths.
+     */
+    int i;
+    for (i = 0; i < minCount; i++) {
+        if (thisChars[i] != compChars[i]) {
+            pResult->i = (s4) thisChars[i] - (s4) compChars[i];
+            return true;
+        }
+    }
+#endif
+
+    pResult->i = countDiff;
+    return true;
+}
+
+/*
+ * public boolean equals(Object anObject)
+ */
+bool javaLangString_equals(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    /*
+     * Null reference check on "this".
+     */
+    if ((Object*) arg0 == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+
+    /* quick test for comparison with itself */
+    if (arg0 == arg1) {
+        pResult->i = true;
+        return true;
+    }
+
+    /*
+     * See if the other object is also a String.
+     *
+     * str.equals(null) is expected to return false, presumably based on
+     * the results of the instanceof test.
+     */
+    if (arg1 == 0 || ((Object*) arg0)->clazz != ((Object*) arg1)->clazz) {
+        pResult->i = false;
+        return true;
+    }
+
+    /*
+     * This would be simpler and faster if we promoted StringObject to
+     * a full representation, lining up the C structure fields with the
+     * actual object fields.
+     */
+    int thisCount, thisOffset, compCount, compOffset;
+    ArrayObject* thisArray;
+    ArrayObject* compArray;
+    const u2* thisChars;
+    const u2* compChars;
+
+    /* quick length check */
+    thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
+    compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
+    if (thisCount != compCount) {
+        pResult->i = false;
+        return true;
+    }
+
+    /*
+     * You may, at this point, be tempted to pull out the hashCode fields
+     * and compare them.  If both fields have been initialized, and they
+     * are not equal, we can return false immediately.
+     *
+     * However, the hashCode field is often not set.  If it is set,
+     * there's an excellent chance that the String is being used as a key
+     * in a hashed data structure (e.g. HashMap).  That data structure has
+     * already made the comparison and determined that the hashes are equal,
+     * making a check here redundant.
+     *
+     * It's not clear that checking the hashes will be a win in "typical"
+     * use cases.  We err on the side of simplicity and ignore them.
+     */
+
+    thisOffset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
+    compOffset = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_OFFSET);
+    thisArray = (ArrayObject*)
+        dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
+    compArray = (ArrayObject*)
+        dvmGetFieldObject((Object*) arg1, STRING_FIELDOFF_VALUE);
+    thisChars = ((const u2*)(void*)thisArray->contents) + thisOffset;
+    compChars = ((const u2*)(void*)compArray->contents) + compOffset;
+
+#ifdef HAVE__MEMCMP16
+    pResult->i = (__memcmp16(thisChars, compChars, thisCount) == 0);
+# ifdef CHECK_MEMCMP16
+    int otherRes = (memcmp(thisChars, compChars, thisCount * 2) == 0);
+    if (pResult->i != otherRes) {
+        badMatch((StringObject*) arg0, (StringObject*) arg1,
+            otherRes, pResult->i, "equals-1");
+    }
+# endif
+#else
+    /*
+     * Straightforward implementation, examining 16 bits at a time.  The
+     * direction of the loop doesn't matter, and starting at the end may
+     * give us an advantage when comparing certain types of strings (e.g.
+     * class names).
+     *
+     * We want to go forward for benchmarks against __memcmp16 so we get a
+     * meaningful comparison when the strings don't match (could also test
+     * with palindromes).
+     */
+    int i;
+    //for (i = 0; i < thisCount; i++)
+    for (i = thisCount-1; i >= 0; --i)
+    {
+        if (thisChars[i] != compChars[i]) {
+            pResult->i = false;
+            return true;
+        }
+    }
+    pResult->i = true;
+#endif
+
+    return true;
+}
+
+/*
+ * public int length()
+ */
+bool javaLangString_length(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    //LOGI("String.length this=0x%08x pResult=%p", arg0, pResult);
+
+    /* null reference check on "this" */
+    if ((Object*) arg0 == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+
+    pResult->i = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
+    return true;
+}
+
+/*
+ * public boolean isEmpty()
+ */
+bool javaLangString_isEmpty(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    //LOGI("String.isEmpty this=0x%08x pResult=%p", arg0, pResult);
+
+    /* null reference check on "this" */
+    if ((Object*) arg0 == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+
+    pResult->i = (dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT) == 0);
+    return true;
+}
+
+/*
+ * Determine the index of the first character matching "ch".  The string
+ * to search is described by "chars", "offset", and "count".
+ *
+ * The character must be <= 0xffff. Supplementary characters are handled in
+ * Java.
+ *
+ * The "start" parameter must be clamped to [0..count].
+ *
+ * Returns -1 if no match is found.
+ */
+static inline int indexOfCommon(Object* strObj, int ch, int start)
+{
+    //if ((ch & 0xffff) != ch)        /* 32-bit code point */
+    //    return -1;
+
+    /* pull out the basic elements */
+    ArrayObject* charArray =
+        (ArrayObject*) dvmGetFieldObject(strObj, STRING_FIELDOFF_VALUE);
+    const u2* chars = (const u2*)(void*)charArray->contents;
+    int offset = dvmGetFieldInt(strObj, STRING_FIELDOFF_OFFSET);
+    int count = dvmGetFieldInt(strObj, STRING_FIELDOFF_COUNT);
+    //LOGI("String.indexOf(0x%08x, 0x%04x, %d) off=%d count=%d",
+    //    (u4) strObj, ch, start, offset, count);
+
+    /* factor out the offset */
+    chars += offset;
+
+    if (start < 0)
+        start = 0;
+
+#if 0
+    /* 16-bit loop, simple */
+    while (start < count) {
+        if (chars[start] == ch)
+            return start;
+        start++;
+    }
+#else
+    /* 16-bit loop, slightly better on ARM */
+    const u2* ptr = chars + start;
+    const u2* endPtr = chars + count;
+    while (ptr < endPtr) {
+        if (*ptr++ == ch)
+            return (ptr-1) - chars;
+    }
+#endif
+
+    return -1;
+}
+
+/*
+ * public int indexOf(int c, int start)
+ *
+ * Scan forward through the string for a matching character.
+ * The character must be <= 0xffff; this method does not handle supplementary
+ * characters.
+ */
+bool javaLangString_fastIndexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    /* null reference check on "this" */
+    if ((Object*) arg0 == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+
+    pResult->i = indexOfCommon((Object*) arg0, arg1, arg2);
+    return true;
+}
+
+
+/*
+ * ===========================================================================
+ *      java.lang.Math
+ * ===========================================================================
+ */
+
+union Convert32 {
+    u4 arg;
+    float ff;
+};
+
+union Convert64 {
+    u4 arg[2];
+    s8 ll;
+    double dd;
+};
+
+/*
+ * public static int abs(int)
+ */
+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)
+ */
+bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    Convert64 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)
+ */
+bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    Convert32 convert;
+    /* clear the sign bit; assumes a fairly common fp representation */
+    convert.arg = arg0 & 0x7fffffff;
+    pResult->f = convert.ff;
+    return true;
+}
+
+/*
+ * public static double abs(double)
+ */
+bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    /* clear the sign bit in the (endian-dependent) high word */
+    convert.ll &= 0x7fffffffffffffffULL;
+    pResult->d = convert.dd;
+    return true;
+}
+
+/*
+ * public static int min(int)
+ */
+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)
+ */
+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.
+ */
+bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    pResult->d = sqrt(convert.dd);
+    return true;
+}
+
+/*
+ * public static double cos(double)
+ */
+bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    pResult->d = cos(convert.dd);
+    return true;
+}
+
+/*
+ * public static double sin(double)
+ */
+bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    pResult->d = sin(convert.dd);
+    return true;
+}
+
+/*
+ * ===========================================================================
+ *      java.lang.Float
+ * ===========================================================================
+ */
+
+bool javaLangFloat_floatToIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+    JValue* pResult)
+{
+    Convert32 convert;
+    convert.arg = arg0;
+    pResult->i = isnanf(convert.ff) ? 0x7fc00000 : arg0;
+    return true;
+}
+
+bool javaLangFloat_floatToRawIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+    JValue* pResult)
+{
+    pResult->i = arg0;
+    return true;
+}
+
+bool javaLangFloat_intBitsToFloat(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+    JValue* pResult)
+{
+    Convert32 convert;
+    convert.arg = arg0;
+    pResult->f = convert.ff;
+    return true;
+}
+
+/*
+ * ===========================================================================
+ *      java.lang.Double
+ * ===========================================================================
+ */
+
+bool javaLangDouble_doubleToLongBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+    JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    pResult->j = isnan(convert.dd) ? 0x7ff8000000000000LL : convert.ll;
+    return true;
+}
+
+bool javaLangDouble_doubleToRawLongBits(u4 arg0, u4 arg1, u4 arg2,
+    u4 arg, JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    pResult->j = convert.ll;
+    return true;
+}
+
+bool javaLangDouble_longBitsToDouble(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+    JValue* pResult)
+{
+    Convert64 convert;
+    convert.arg[0] = arg0;
+    convert.arg[1] = arg1;
+    pResult->d = convert.dd;
+    return true;
+}
+
+/*
+ * ===========================================================================
+ *      Infrastructure
+ * ===========================================================================
+ */
+
+/*
+ * Table of methods.
+ *
+ * The DEX optimizer uses the class/method/signature string fields to decide
+ * which calls it can trample.  The interpreter just uses the function
+ * pointer field.
+ *
+ * IMPORTANT: you must update DALVIK_VM_BUILD in DalvikVersion.h if you make
+ * changes to this table.
+ *
+ * NOTE: If present, the JIT will also need to know about changes
+ * to this table.  Update the NativeInlineOps enum in InlineNative.h and
+ * the dispatch code in compiler/codegen/<target>/Codegen.c.
+ */
+const InlineOperation gDvmInlineOpsTable[] = {
+    { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
+        "Lorg/apache/harmony/dalvik/NativeTestTarget;",
+        "emptyInlineMethod", "()V" },
+
+    { javaLangString_charAt,
+        "Ljava/lang/String;", "charAt", "(I)C" },
+    { javaLangString_compareTo,
+        "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
+    { javaLangString_equals,
+        "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
+    { javaLangString_fastIndexOf_II,
+        "Ljava/lang/String;", "fastIndexOf", "(II)I" },
+    { javaLangString_isEmpty,
+        "Ljava/lang/String;", "isEmpty", "()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" },
+
+    { javaLangFloat_floatToIntBits,
+        "Ljava/lang/Float;", "floatToIntBits", "(F)I" },
+    { javaLangFloat_floatToRawIntBits,
+        "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" },
+    { javaLangFloat_intBitsToFloat,
+        "Ljava/lang/Float;", "intBitsToFloat", "(I)F" },
+
+    { javaLangDouble_doubleToLongBits,
+        "Ljava/lang/Double;", "doubleToLongBits", "(D)J" },
+    { javaLangDouble_doubleToRawLongBits,
+        "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" },
+    { javaLangDouble_longBitsToDouble,
+        "Ljava/lang/Double;", "longBitsToDouble", "(J)D" },
+};
+
+/*
+ * Allocate some tables.
+ */
+bool dvmInlineNativeStartup()
+{
+    gDvm.inlinedMethods =
+        (Method**) calloc(NELEM(gDvmInlineOpsTable), sizeof(Method*));
+    if (gDvm.inlinedMethods == NULL)
+        return false;
+
+    return true;
+}
+
+/*
+ * Free generated tables.
+ */
+void dvmInlineNativeShutdown()
+{
+    free(gDvm.inlinedMethods);
+}
+
+
+/*
+ * Get a pointer to the inlineops table.
+ */
+const InlineOperation* dvmGetInlineOpsTable()
+{
+    return gDvmInlineOpsTable;
+}
+
+/*
+ * Get the number of entries in the inlineops table.
+ */
+int dvmGetInlineOpsTableLength()
+{
+    return NELEM(gDvmInlineOpsTable);
+}
+
+Method* dvmFindInlinableMethod(const char* classDescriptor,
+    const char* methodName, const char* methodSignature)
+{
+    /*
+     * Find the class.
+     */
+    ClassObject* clazz = dvmFindClassNoInit(classDescriptor, NULL);
+    if (clazz == NULL) {
+        LOGE("dvmFindInlinableMethod: can't find class '%s'",
+            classDescriptor);
+        dvmClearException(dvmThreadSelf());
+        return NULL;
+    }
+
+    /*
+     * Method could be virtual or direct.  Try both.  Don't use
+     * the "hier" versions.
+     */
+    Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName,
+        methodSignature);
+    if (method == NULL) {
+        method = dvmFindVirtualMethodByDescriptor(clazz, methodName,
+            methodSignature);
+    }
+    if (method == NULL) {
+        LOGE("dvmFindInlinableMethod: can't find method %s.%s %s",
+            clazz->descriptor, methodName, methodSignature);
+        return NULL;
+    }
+
+    /*
+     * Check that the method is appropriate for inlining.
+     */
+    if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
+        LOGE("dvmFindInlinableMethod: can't inline non-final method %s.%s",
+            clazz->descriptor, method->name);
+        return NULL;
+    }
+    if (dvmIsSynchronizedMethod(method) ||
+            dvmIsDeclaredSynchronizedMethod(method)) {
+        LOGE("dvmFindInlinableMethod: can't inline synchronized method %s.%s",
+            clazz->descriptor, method->name);
+        return NULL;
+    }
+
+    return method;
+}
+
+/*
+ * Populate the methods table on first use.  It's possible the class
+ * hasn't been resolved yet, so we need to do the full "calling the
+ * method for the first time" routine.  (It's probably okay to skip
+ * the access checks.)
+ *
+ * Currently assuming that we're only inlining stuff loaded by the
+ * bootstrap class loader.  This is a safe assumption for many reasons.
+ */
+Method* dvmResolveInlineNative(int opIndex)
+{
+    assert(opIndex >= 0 && opIndex < NELEM(gDvmInlineOpsTable));
+    Method* method = gDvm.inlinedMethods[opIndex];
+    if (method != NULL) {
+        return method;
+    }
+
+    method = dvmFindInlinableMethod(
+        gDvmInlineOpsTable[opIndex].classDescriptor,
+        gDvmInlineOpsTable[opIndex].methodName,
+        gDvmInlineOpsTable[opIndex].methodSignature);
+
+    if (method == NULL) {
+        /* We already reported the error. */
+        return NULL;
+    }
+
+    gDvm.inlinedMethods[opIndex] = method;
+    IF_LOGV() {
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGV("Registered for profile: %s.%s %s",
+            method->clazz->descriptor, method->name, desc);
+        free(desc);
+    }
+
+    return method;
+}
+
+/*
+ * Make an inline call for the "debug" interpreter, used when the debugger
+ * or profiler is active.
+ */
+bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult, int opIndex)
+{
+    Method* method = dvmResolveInlineNative(opIndex);
+    if (method == NULL) {
+        return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
+            pResult);
+    }
+
+    Thread* self = dvmThreadSelf();
+    TRACE_METHOD_ENTER(self, method);
+    bool result = (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
+        pResult);
+    TRACE_METHOD_EXIT(self, method);
+    return result;
+}
diff --git a/vm/InlineNative.h b/vm/InlineNative.h
new file mode 100644
index 0000000..101ddd1
--- /dev/null
+++ b/vm/InlineNative.h
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+/*
+ * Inlined native functions.
+ */
+#ifndef DALVIK_INLINENATIVE_H_
+#define DALVIK_INLINENATIVE_H_
+
+/* startup/shutdown */
+bool dvmInlineNativeStartup(void);
+void dvmInlineNativeShutdown(void);
+
+Method* dvmFindInlinableMethod(const char* classDescriptor,
+    const char* methodName, const char* methodSignature);
+
+/*
+ * Basic 4-argument inline operation handler.
+ */
+typedef bool (*InlineOp4Func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult);
+
+/*
+ * Table of inline operations.
+ *
+ * Try to keep this at a power-of-two size, so we don't have to multiply.
+ *
+ * TODO: might be to our advantage to generate a compact jump table on
+ * the heap at runtime (or just declare two static tables, one with full
+ * info and one with just function pointers).  Especially useful if we decide
+ * to support other method call forms, e.g. /range.  We can also just
+ * generate assembly code that knows how many args it needs and has the
+ * target address embedded.
+ */
+struct InlineOperation {
+    InlineOp4Func   func;               /* MUST be first entry */
+    const char*     classDescriptor;
+    const char*     methodName;
+    const char*     methodSignature;
+};
+
+/*
+ * Must be kept in sync w/ gDvmInlineOpsTable in InlineNative.c
+ *
+ * You should also add a test to libcore's IntrinsicTest.
+ */
+enum NativeInlineOps {
+    INLINE_EMPTYINLINEMETHOD = 0,
+    INLINE_STRING_CHARAT = 1,
+    INLINE_STRING_COMPARETO = 2,
+    INLINE_STRING_EQUALS = 3,
+    INLINE_STRING_FASTINDEXOF_II = 4,
+    INLINE_STRING_IS_EMPTY = 5,
+    INLINE_STRING_LENGTH = 6,
+    INLINE_MATH_ABS_INT = 7,
+    INLINE_MATH_ABS_LONG = 8,
+    INLINE_MATH_ABS_FLOAT = 9,
+    INLINE_MATH_ABS_DOUBLE = 10,
+    INLINE_MATH_MIN_INT = 11,
+    INLINE_MATH_MAX_INT = 12,
+    INLINE_MATH_SQRT = 13,
+    INLINE_MATH_COS = 14,
+    INLINE_MATH_SIN = 15,
+    INLINE_FLOAT_TO_INT_BITS = 16,
+    INLINE_FLOAT_TO_RAW_INT_BITS = 17,
+    INLINE_INT_BITS_TO_FLOAT = 18,
+    INLINE_DOUBLE_TO_LONG_BITS = 19,
+    INLINE_DOUBLE_TO_RAW_LONG_BITS = 20,
+    INLINE_LONG_BITS_TO_DOUBLE = 21,
+};
+
+/*
+ * Get the inlineops table.
+ */
+const InlineOperation* dvmGetInlineOpsTable(void);
+int dvmGetInlineOpsTableLength(void);
+
+/*
+ * The table, exposed so we can access it with C inlines.  Prefer access
+ * through dvmGetInlineOpsTable().
+ */
+extern const InlineOperation gDvmInlineOpsTable[];
+
+/*
+ * Perform the operation specified by "opIndex".
+ *
+ * We want the arguments to appear in the first 4 registers so they can
+ * be passed straight through to the handler function.  Ideally on ARM
+ * they'll go into r0-r3 and stay there.
+ *
+ * Returns "true" if everything went normally, "false" if an exception
+ * was thrown.
+ */
+INLINE bool dvmPerformInlineOp4Std(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult, int opIndex)
+{
+    return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult);
+}
+
+/*
+ * Like the "std" version, but will emit profiling info.
+ */
+bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+    JValue* pResult, int opIndex);
+
+/*
+ * Return method & populate the table on first use.
+ */
+extern "C" Method* dvmResolveInlineNative(int opIndex);
+
+/*
+ * The actual inline native definitions.
+ */
+bool javaLangString_charAt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                           JValue* pResult);
+
+bool javaLangString_compareTo(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                              JValue* pResult);
+
+bool javaLangString_equals(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                           JValue* pResult);
+
+bool javaLangString_length(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                           JValue* pResult);
+
+bool javaLangString_isEmpty(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                            JValue* pResult);
+
+bool javaLangString_fastIndexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                                   JValue* pResult);
+
+bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                          JValue* pResult);
+
+bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                           JValue* pResult);
+
+bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                            JValue* pResult);
+
+bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                             JValue* pResult);
+
+bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                          JValue* pResult);
+
+bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                          JValue* pResult);
+
+bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                       JValue* pResult);
+
+bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                      JValue* pResult);
+
+bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+                      JValue* pResult);
+
+bool javaLangFloat_floatToIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+                                  JValue* pResult);
+
+bool javaLangFloat_floatToRawIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+                                     JValue* pResult);
+
+bool javaLangFloat_intBitsToFloat(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+                                  JValue* pResult);
+
+bool javaLangDouble_doubleToLongBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+                                     JValue* pResult);
+
+bool javaLangDouble_longBitsToDouble(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+                                     JValue* pResult);
+
+bool javaLangDouble_doubleToRawLongBits(u4 arg0, u4 arg1, u4 arg2,
+                                        u4 arg, JValue* pResult);
+
+bool javaLangDouble_longBitsToDouble(u4 arg0, u4 arg1, u4 arg2, u4 arg,
+                                     JValue* pResult);
+
+#endif  // DALVIK_INLINENATIVE_H_
diff --git a/vm/Inlines.cpp b/vm/Inlines.cpp
new file mode 100644
index 0000000..3ab7717
--- /dev/null
+++ b/vm/Inlines.cpp
@@ -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.
+ */
+
+/*
+ * Generate non-inline copies of inline functions declared in header files.
+ */
+
+#define _DALVIK_GEN_INLINES
+#include "Dalvik.h"
+#include "analysis/CodeVerify.h"
+#include "analysis/RegisterMap.h"
+#include "mterp/c/header.cpp"
+
+#undef LOG_TAG
+#include "jdwp/JdwpPriv.h"
diff --git a/vm/Inlines.h b/vm/Inlines.h
new file mode 100644
index 0000000..f1580e3
--- /dev/null
+++ b/vm/Inlines.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/*
+ * In gcc, "extern inline" ensures that the copy in the header is never
+ * turned into a separate function.  This prevents us from having multiple
+ * non-inline copies.  However, we still need to provide a non-inline
+ * version in the library for the benefit of applications that include our
+ * headers and are built with optimizations disabled.  Either that, or use
+ * the "always_inline" gcc attribute to ensure that the non-inline version
+ * is never needed.
+ *
+ * (Note C99 has different notions about what the keyword combos mean.)
+ */
+#ifndef _DALVIK_GEN_INLINES             /* only defined by Inlines.c */
+# define INLINE extern __inline__
+#else
+# define INLINE
+#endif
diff --git a/vm/Intern.cpp b/vm/Intern.cpp
new file mode 100644
index 0000000..7754bb3
--- /dev/null
+++ b/vm/Intern.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+/*
+ * String interning.
+ */
+#include "Dalvik.h"
+
+#include <stddef.h>
+
+/*
+ * Prep string interning.
+ */
+bool dvmStringInternStartup()
+{
+    dvmInitMutex(&gDvm.internLock);
+    gDvm.internedStrings = dvmHashTableCreate(256, NULL);
+    if (gDvm.internedStrings == NULL)
+        return false;
+    gDvm.literalStrings = dvmHashTableCreate(256, NULL);
+    if (gDvm.literalStrings == NULL)
+        return false;
+    return true;
+}
+
+/*
+ * Chuck the intern list.
+ *
+ * The contents of the list are StringObjects that live on the GC heap.
+ */
+void dvmStringInternShutdown()
+{
+    if (gDvm.internedStrings != NULL || gDvm.literalStrings != NULL) {
+        dvmDestroyMutex(&gDvm.internLock);
+    }
+    dvmHashTableFree(gDvm.internedStrings);
+    gDvm.internedStrings = NULL;
+    dvmHashTableFree(gDvm.literalStrings);
+    gDvm.literalStrings = NULL;
+}
+
+static StringObject* lookupString(HashTable* table, u4 key, StringObject* value)
+{
+    void* entry = dvmHashTableLookup(table, key, (void*)value,
+                                     dvmHashcmpStrings, false);
+    return (StringObject*)entry;
+}
+
+static StringObject* insertString(HashTable* table, u4 key, StringObject* value)
+{
+    if (dvmIsNonMovingObject(value) == false) {
+        value = (StringObject*)dvmCloneObject(value, ALLOC_NON_MOVING);
+    }
+    void* entry = dvmHashTableLookup(table, key, (void*)value,
+                                     dvmHashcmpStrings, true);
+    return (StringObject*)entry;
+}
+
+static StringObject* lookupInternedString(StringObject* strObj, bool isLiteral)
+{
+    StringObject* found;
+
+    assert(strObj != NULL);
+    u4 key = dvmComputeStringHash(strObj);
+    dvmLockMutex(&gDvm.internLock);
+    if (isLiteral) {
+        /*
+         * Check the literal table for a match.
+         */
+        StringObject* literal = lookupString(gDvm.literalStrings, key, strObj);
+        if (literal != NULL) {
+            /*
+             * A match was found in the literal table, the easy case.
+             */
+            found = literal;
+        } else {
+            /*
+             * There is no match in the literal table, check the
+             * interned string table.
+             */
+            StringObject* interned = lookupString(gDvm.internedStrings, key, strObj);
+            if (interned != NULL) {
+                /*
+                 * A match was found in the interned table.  Move the
+                 * matching string to the literal table.
+                 */
+                dvmHashTableRemove(gDvm.internedStrings, key, interned);
+                found = insertString(gDvm.literalStrings, key, interned);
+                assert(found == interned);
+            } else {
+                /*
+                 * No match in the literal table or the interned
+                 * table.  Insert into the literal table.
+                 */
+                found = insertString(gDvm.literalStrings, key, strObj);
+                assert(found == strObj);
+            }
+        }
+    } else {
+        /*
+         * Check the literal table for a match.
+         */
+        found = lookupString(gDvm.literalStrings, key, strObj);
+        if (found == NULL) {
+            /*
+             * No match was found in the literal table.  Insert into
+             * the intern table if it does not already exist.
+             */
+            found = insertString(gDvm.internedStrings, key, strObj);
+        }
+    }
+    assert(found != NULL);
+    dvmUnlockMutex(&gDvm.internLock);
+    return found;
+}
+
+/*
+ * Find an entry in the interned string table.
+ *
+ * If the string doesn't already exist, the StringObject is added to
+ * the table.  Otherwise, the existing entry is returned.
+ */
+StringObject* dvmLookupInternedString(StringObject* strObj)
+{
+    return lookupInternedString(strObj, false);
+}
+
+/*
+ * Same as dvmLookupInternedString(), but guarantees that the
+ * returned string is a literal.
+ */
+StringObject* dvmLookupImmortalInternedString(StringObject* strObj)
+{
+    return lookupInternedString(strObj, true);
+}
+
+/*
+ * Returns true if the object is a weak interned string.  Any string
+ * interned by the user is weak.
+ */
+bool dvmIsWeakInternedString(StringObject* strObj)
+{
+    assert(strObj != NULL);
+    if (gDvm.internedStrings == NULL) {
+        return false;
+    }
+    dvmLockMutex(&gDvm.internLock);
+    u4 key = dvmComputeStringHash(strObj);
+    StringObject* found = lookupString(gDvm.internedStrings, key, strObj);
+    dvmUnlockMutex(&gDvm.internLock);
+    return found == strObj;
+}
+
+/*
+ * Clear white references from the intern table.
+ */
+void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *))
+{
+    /* It's possible for a GC to happen before dvmStringInternStartup()
+     * is called.
+     */
+    if (gDvm.internedStrings != NULL) {
+        dvmLockMutex(&gDvm.internLock);
+        dvmHashForeachRemove(gDvm.internedStrings, isUnmarkedObject);
+        dvmUnlockMutex(&gDvm.internLock);
+    }
+}
diff --git a/vm/Intern.h b/vm/Intern.h
new file mode 100644
index 0000000..9944e5c
--- /dev/null
+++ b/vm/Intern.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+/*
+ * Interned strings.
+ */
+#ifndef DALVIK_INTERN_H_
+#define DALVIK_INTERN_H_
+
+bool dvmStringInternStartup(void);
+void dvmStringInternShutdown(void);
+StringObject* dvmLookupInternedString(StringObject* strObj);
+StringObject* dvmLookupImmortalInternedString(StringObject* strObj);
+bool dvmIsWeakInternedString(StringObject* strObj);
+void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *));
+
+#endif  // DALVIK_INTERN_H_
diff --git a/vm/JarFile.cpp b/vm/JarFile.cpp
new file mode 100644
index 0000000..0499e9b
--- /dev/null
+++ b/vm/JarFile.cpp
@@ -0,0 +1,378 @@
+/*
+ * 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.
+ */
+
+/*
+ * Access the contents of a Jar file.
+ *
+ * This isn't actually concerned with any of the Jar-like elements; it
+ * just wants a zip archive with "classes.dex" inside.  In Android the
+ * most common example is ".apk".
+ */
+
+#include "Dalvik.h"
+#include "libdex/OptInvocation.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static const char* kDexInJarName = "classes.dex";
+
+/*
+ * Attempt to open a file whose name is similar to <fileName>,
+ * but with the supplied suffix.  E.g.,
+ * openAlternateSuffix("Home.apk", "dex", O_RDONLY) will attempt
+ * to open "Home.dex".  If the open succeeds, a pointer to a
+ * malloc()ed copy of the opened file name will be put in <*pCachedName>.
+ *
+ * <flags> is passed directly to open(). O_CREAT is not supported.
+ */
+static int openAlternateSuffix(const char *fileName, const char *suffix,
+    int flags, char **pCachedName)
+{
+    char *buf, *c;
+    size_t fileNameLen = strlen(fileName);
+    size_t suffixLen = strlen(suffix);
+    size_t bufLen = fileNameLen + suffixLen + 1;
+    int fd = -1;
+
+    buf = (char*)malloc(bufLen);
+    if (buf == NULL) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    /* Copy the original filename into the buffer, find
+     * the last dot, and copy the suffix to just after it.
+     */
+    memcpy(buf, fileName, fileNameLen + 1);
+    c = strrchr(buf, '.');
+    if (c == NULL) {
+        errno = ENOENT;
+        goto bail;
+    }
+    memcpy(c + 1, suffix, suffixLen + 1);
+
+    fd = open(buf, flags);
+    if (fd >= 0) {
+        *pCachedName = buf;
+        return fd;
+    }
+    LOGV("Couldn't open %s: %s", buf, strerror(errno));
+bail:
+    free(buf);
+    return -1;
+}
+
+/*
+ * Checks the dependencies of the dex cache file corresponding
+ * to the jar file at the absolute path "fileName".
+ */
+DexCacheStatus dvmDexCacheStatus(const char *fileName)
+{
+    ZipArchive archive;
+    char* cachedName = NULL;
+    int fd;
+    DexCacheStatus result = DEX_CACHE_ERROR;
+    ZipEntry entry;
+
+    /* Always treat elements of the bootclasspath as up-to-date.
+     * The fact that interpreted code is running at all means that this
+     * should be true.
+     */
+    if (dvmClassPathContains(gDvm.bootClassPath, fileName)) {
+        return DEX_CACHE_OK;
+    }
+
+    //TODO: match dvmJarFileOpen()'s logic.  Not super-important
+    //      (the odex-first logic is only necessary for dexpreopt)
+    //      but it would be nice to be consistent.
+
+    /* Try to find the dex file inside of the archive.
+     */
+    if (dexZipOpenArchive(fileName, &archive) != 0) {
+        return DEX_CACHE_BAD_ARCHIVE;
+    }
+    entry = dexZipFindEntry(&archive, kDexInJarName);
+    if (entry != NULL) {
+        bool newFile = false;
+
+        /*
+         * See if there's an up-to-date copy of the optimized dex
+         * in the cache, but don't create one if there isn't.
+         */
+        LOGV("dvmDexCacheStatus: Checking cache for %s", fileName);
+        cachedName = dexOptGenerateCacheFileName(fileName, kDexInJarName);
+        if (cachedName == NULL)
+            return DEX_CACHE_BAD_ARCHIVE;
+
+        fd = dvmOpenCachedDexFile(fileName, cachedName,
+                dexGetZipEntryModTime(&archive, entry),
+                dexGetZipEntryCrc32(&archive, entry),
+                /*isBootstrap=*/false, &newFile, /*createIfMissing=*/false);
+        LOGV("dvmOpenCachedDexFile returned fd %d", fd);
+        if (fd < 0) {
+            result = DEX_CACHE_STALE;
+            goto bail;
+        }
+
+        /* dvmOpenCachedDexFile locks the file as a side-effect.
+         * Unlock and close it.
+         */
+        if (!dvmUnlockCachedDexFile(fd)) {
+            /* uh oh -- this process needs to exit or we'll wedge the system */
+            LOGE("Unable to unlock DEX file");
+            goto bail;
+        }
+
+        /* When createIfMissing is false, dvmOpenCachedDexFile() only
+         * returns a valid fd if the cache file is up-to-date.
+         */
+    } else {
+        /*
+         * There's no dex file in the jar file.  See if there's an
+         * optimized dex file living alongside the jar.
+         */
+        fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
+        if (fd < 0) {
+            LOGI("Zip is good, but no %s inside, and no .odex "
+                    "file in the same directory", kDexInJarName);
+            result = DEX_CACHE_BAD_ARCHIVE;
+            goto bail;
+        }
+
+        LOGV("Using alternate file (odex) for %s ...", fileName);
+        if (!dvmCheckOptHeaderAndDependencies(fd, false, 0, 0, true, true)) {
+            LOGE("%s odex has stale dependencies", fileName);
+            LOGE("odex source not available -- failing");
+            result = DEX_CACHE_STALE_ODEX;
+            goto bail;
+        } else {
+            LOGV("%s odex has good dependencies", fileName);
+        }
+    }
+    result = DEX_CACHE_OK;
+
+bail:
+    dexZipCloseArchive(&archive);
+    free(cachedName);
+    if (fd >= 0) {
+        close(fd);
+    }
+    return result;
+}
+
+/*
+ * Open a Jar file.  It's okay if it's just a Zip archive without all of
+ * the Jar trimmings, but we do insist on finding "classes.dex" inside
+ * or an appropriately-named ".odex" file alongside.
+ *
+ * If "isBootstrap" is not set, the optimizer/verifier regards this DEX as
+ * being part of a different class loader.
+ */
+int dvmJarFileOpen(const char* fileName, const char* odexOutputName,
+    JarFile** ppJarFile, bool isBootstrap)
+{
+    /*
+     * TODO: This function has been duplicated and modified to become
+     * dvmRawDexFileOpen() in RawDexFile.c. This should be refactored.
+     */
+
+    ZipArchive archive;
+    DvmDex* pDvmDex = NULL;
+    char* cachedName = NULL;
+    bool archiveOpen = false;
+    bool locked = false;
+    int fd = -1;
+    int result = -1;
+
+    /* Even if we're not going to look at the archive, we need to
+     * open it so we can stuff it into ppJarFile.
+     */
+    if (dexZipOpenArchive(fileName, &archive) != 0)
+        goto bail;
+    archiveOpen = true;
+
+    /* If we fork/exec into dexopt, don't let it inherit the archive's fd.
+     */
+    dvmSetCloseOnExec(dexZipGetArchiveFd(&archive));
+
+    /* First, look for a ".odex" alongside the jar file.  It will
+     * have the same name/path except for the extension.
+     */
+    fd = openAlternateSuffix(fileName, "odex", O_RDONLY, &cachedName);
+    if (fd >= 0) {
+        LOGV("Using alternate file (odex) for %s ...", fileName);
+        if (!dvmCheckOptHeaderAndDependencies(fd, false, 0, 0, true, true)) {
+            LOGE("%s odex has stale dependencies", fileName);
+            free(cachedName);
+            cachedName = NULL;
+            close(fd);
+            fd = -1;
+            goto tryArchive;
+        } else {
+            LOGV("%s odex has good dependencies", fileName);
+            //TODO: make sure that the .odex actually corresponds
+            //      to the classes.dex inside the archive (if present).
+            //      For typical use there will be no classes.dex.
+        }
+    } else {
+        ZipEntry entry;
+
+tryArchive:
+        /*
+         * Pre-created .odex absent or stale.  Look inside the jar for a
+         * "classes.dex".
+         */
+        entry = dexZipFindEntry(&archive, kDexInJarName);
+        if (entry != NULL) {
+            bool newFile = false;
+
+            /*
+             * We've found the one we want.  See if there's an up-to-date copy
+             * in the cache.
+             *
+             * On return, "fd" will be seeked just past the "opt" header.
+             *
+             * If a stale .odex file is present and classes.dex exists in
+             * the archive, this will *not* return an fd pointing to the
+             * .odex file; the fd will point into dalvik-cache like any
+             * other jar.
+             */
+            if (odexOutputName == NULL) {
+                cachedName = dexOptGenerateCacheFileName(fileName,
+                                kDexInJarName);
+                if (cachedName == NULL)
+                    goto bail;
+            } else {
+                cachedName = strdup(odexOutputName);
+            }
+            LOGV("dvmJarFileOpen: Checking cache for %s (%s)",
+                fileName, cachedName);
+            fd = dvmOpenCachedDexFile(fileName, cachedName,
+                    dexGetZipEntryModTime(&archive, entry),
+                    dexGetZipEntryCrc32(&archive, entry),
+                    isBootstrap, &newFile, /*createIfMissing=*/true);
+            if (fd < 0) {
+                LOGI("Unable to open or create cache for %s (%s)",
+                    fileName, cachedName);
+                goto bail;
+            }
+            locked = true;
+
+            /*
+             * If fd points to a new file (because there was no cached version,
+             * or the cached version was stale), generate the optimized DEX.
+             * The file descriptor returned is still locked, and is positioned
+             * just past the optimization header.
+             */
+            if (newFile) {
+                u8 startWhen, extractWhen, endWhen;
+                bool result;
+                off_t dexOffset;
+
+                dexOffset = lseek(fd, 0, SEEK_CUR);
+                result = (dexOffset > 0);
+
+                if (result) {
+                    startWhen = dvmGetRelativeTimeUsec();
+                    result = dexZipExtractEntryToFile(&archive, entry, fd) == 0;
+                    extractWhen = dvmGetRelativeTimeUsec();
+                }
+                if (result) {
+                    result = dvmOptimizeDexFile(fd, dexOffset,
+                                dexGetZipEntryUncompLen(&archive, entry),
+                                fileName,
+                                dexGetZipEntryModTime(&archive, entry),
+                                dexGetZipEntryCrc32(&archive, entry),
+                                isBootstrap);
+                }
+
+                if (!result) {
+                    LOGE("Unable to extract+optimize DEX from '%s'",
+                        fileName);
+                    goto bail;
+                }
+
+                endWhen = dvmGetRelativeTimeUsec();
+                LOGD("DEX prep '%s': unzip in %dms, rewrite %dms",
+                    fileName,
+                    (int) (extractWhen - startWhen) / 1000,
+                    (int) (endWhen - extractWhen) / 1000);
+            }
+        } else {
+            LOGI("Zip is good, but no %s inside, and no valid .odex "
+                    "file in the same directory", kDexInJarName);
+            goto bail;
+        }
+    }
+
+    /*
+     * Map the cached version.  This immediately rewinds the fd, so it
+     * doesn't have to be seeked anywhere in particular.
+     */
+    if (dvmDexFileOpenFromFd(fd, &pDvmDex) != 0) {
+        LOGI("Unable to map %s in %s", kDexInJarName, fileName);
+        goto bail;
+    }
+
+    if (locked) {
+        /* unlock the fd */
+        if (!dvmUnlockCachedDexFile(fd)) {
+            /* uh oh -- this process needs to exit or we'll wedge the system */
+            LOGE("Unable to unlock DEX file");
+            goto bail;
+        }
+        locked = false;
+    }
+
+    LOGV("Successfully opened '%s' in '%s'", kDexInJarName, fileName);
+
+    *ppJarFile = (JarFile*) calloc(1, sizeof(JarFile));
+    (*ppJarFile)->archive = archive;
+    (*ppJarFile)->cacheFileName = cachedName;
+    (*ppJarFile)->pDvmDex = pDvmDex;
+    cachedName = NULL;      // don't free it below
+    result = 0;
+
+bail:
+    /* clean up, closing the open file */
+    if (archiveOpen && result != 0)
+        dexZipCloseArchive(&archive);
+    free(cachedName);
+    if (fd >= 0) {
+        if (locked)
+            (void) dvmUnlockCachedDexFile(fd);
+        close(fd);
+    }
+    return result;
+}
+
+/*
+ * Close a Jar file and free the struct.
+ */
+void dvmJarFileFree(JarFile* pJarFile)
+{
+    if (pJarFile == NULL)
+        return;
+
+    dvmDexFileFree(pJarFile->pDvmDex);
+    dexZipCloseArchive(&pJarFile->archive);
+    free(pJarFile->cacheFileName);
+    free(pJarFile);
+}
diff --git a/vm/JarFile.h b/vm/JarFile.h
new file mode 100644
index 0000000..d8fd998
--- /dev/null
+++ b/vm/JarFile.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+/*
+ * Decode jar/apk/zip files.
+ */
+#ifndef DALVIK_JARFILE_H_
+#define DALVIK_JARFILE_H_
+
+/*
+ * This represents an open, scanned Jar file.  (It's actually for any Zip
+ * archive that happens to hold a Dex file.)
+ */
+struct JarFile {
+    ZipArchive  archive;
+    //MemMapping  map;
+    char*       cacheFileName;
+    DvmDex*     pDvmDex;
+};
+
+/*
+ * Open the Zip archive and get a list of the classfile entries.
+ *
+ * On success, returns 0 and sets "*ppJarFile" to a newly-allocated JarFile.
+ * On failure, returns a meaningful error code [currently just -1].
+ */
+int dvmJarFileOpen(const char* fileName, const char* odexOutputName,
+    JarFile** ppJarFile, bool isBootstrap);
+
+/*
+ * Free a JarFile structure, along with any associated structures.
+ */
+void dvmJarFileFree(JarFile* pJarFile);
+
+/* pry the DexFile out of a JarFile */
+INLINE DvmDex* dvmGetJarFileDex(JarFile* pJarFile) {
+    return pJarFile->pDvmDex;
+}
+
+/* get full path of optimized DEX file */
+INLINE const char* dvmGetJarFileCacheFileName(JarFile* pJarFile) {
+    return pJarFile->cacheFileName;
+}
+
+enum DexCacheStatus {
+    DEX_CACHE_ERROR = -2,
+    DEX_CACHE_BAD_ARCHIVE = -1,
+    DEX_CACHE_OK = 0,
+    DEX_CACHE_STALE,
+    DEX_CACHE_STALE_ODEX,
+};
+
+/*
+ * Checks the dependencies of the dex cache file corresponding
+ * to the jar file at the absolute path "fileName".
+ */
+DexCacheStatus dvmDexCacheStatus(const char *fileName);
+
+#endif  // DALVIK_JARFILE_H_
diff --git a/vm/Jni.cpp b/vm/Jni.cpp
new file mode 100644
index 0000000..fac6696
--- /dev/null
+++ b/vm/Jni.cpp
@@ -0,0 +1,3512 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik implementation of JNI interfaces.
+ */
+#include "Dalvik.h"
+#include "JniInternal.h"
+#include "ScopedPthreadMutexLock.h"
+#include "UniquePtr.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <limits.h>
+
+/*
+Native methods and interaction with the GC
+
+All JNI methods must start by changing their thread status to
+THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
+returning to native code.  The switch to "running" triggers a thread
+suspension check.
+
+With a rudimentary GC we should be able to skip the status change for
+simple functions, e.g.  IsSameObject, GetJavaVM, GetStringLength, maybe
+even access to fields with primitive types.  Our options are more limited
+with a compacting GC.
+
+For performance reasons we do as little error-checking as possible here.
+For example, we don't check to make sure the correct type of Object is
+passed in when setting a field, and we don't prevent you from storing
+new values in a "final" field.  Such things are best handled in the
+"check" version.  For actions that are common, dangerous, and must be
+checked at runtime, such as array bounds checks, we do the tests here.
+
+
+General notes on local/global reference tracking
+
+JNI provides explicit control over natively-held references that the GC
+needs to know about.  These can be local, in which case they're released
+when the native method returns into the VM, or global, which are held
+until explicitly released.  (There are also weak-global references,
+which have the lifespan and visibility of global references, but the
+object they refer to may be collected.)
+
+The references can be created with explicit JNI NewLocalRef / NewGlobalRef
+calls.  The former is very unusual, the latter is reasonably common
+(e.g. for caching references to class objects).
+
+Local references are most often created as a side-effect of JNI functions.
+For example, the AllocObject/NewObject functions must create local
+references to the objects returned, because nothing else in the GC root
+set has a reference to the new objects.
+
+The most common mode of operation is for a method to create zero or
+more local references and return.  Explicit "local delete" operations
+are expected to be exceedingly rare, except when walking through an
+object array, and the Push/PopLocalFrame calls are expected to be used
+infrequently.  For efficient operation, we want to add new local refs
+with a simple store/increment operation; to avoid infinite growth in
+pathological situations, we need to reclaim the space used by deleted
+entries.
+
+If we just want to maintain a list for the GC root set, we can use an
+expanding append-only array that compacts when objects are deleted.
+In typical situations, e.g. running through an array of objects, we will
+be deleting one of the most recently added entries, so we can minimize
+the number of elements moved (or avoid having to move any).
+
+If we want to conceal the pointer values from native code, which is
+necessary to allow the GC to move JNI-referenced objects around, then we
+have to use a more complicated indirection mechanism.
+
+The spec says, "Local references are only valid in the thread in which
+they are created.  The native code must not pass local references from
+one thread to another."
+
+
+Pinned objects
+
+For some large chunks of data, notably primitive arrays and String data,
+JNI allows the VM to choose whether it wants to pin the array object or
+make a copy.  We currently pin the memory for better execution performance.
+
+TODO: we're using simple root set references to pin primitive array data,
+because they have the property we need (i.e. the pointer we return is
+guaranteed valid until we explicitly release it).  However, if we have a
+compacting GC and don't want to pin all memory held by all global refs,
+we need to treat these differently.
+
+
+Global reference tracking
+
+There should be a small "active" set centered around the most-recently
+added items.
+
+Because it's global, access to it has to be synchronized.  Additions and
+removals require grabbing a mutex.  If the table serves as an indirection
+mechanism (i.e. it's not just a list for the benefit of the garbage
+collector), reference lookups may also require grabbing a mutex.
+
+The JNI spec does not define any sort of limit, so the list must be able
+to expand to a reasonable size.  It may be useful to log significant
+increases in usage to help identify resource leaks.
+
+
+Weak-global reference tracking
+
+[TBD]
+
+
+Local reference tracking
+
+Each Thread/JNIEnv points to an IndirectRefTable.
+
+We implement Push/PopLocalFrame with actual stack frames.  Before a JNI
+frame gets popped, we set "nextEntry" to the "top" pointer of the current
+frame, effectively releasing the references.
+
+The GC will scan all references in the table.
+
+*/
+
+#ifdef WITH_JNI_STACK_CHECK
+# define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
+# define CHECK_STACK_SUM(_self)     checkStackSum(_self);
+
+/*
+ * Compute a CRC on the entire interpreted stack.
+ *
+ * Would be nice to compute it on "self" as well, but there are parts of
+ * the Thread that can be altered by other threads (e.g. prev/next pointers).
+ */
+static void computeStackSum(Thread* self) {
+    const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    u4 crc = dvmInitCrc32();
+    self->stackCrc = 0;
+    crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
+    self->stackCrc = crc;
+}
+
+/*
+ * Compute a CRC on the entire interpreted stack, and compare it to what
+ * we previously computed.
+ *
+ * We can execute JNI directly from native code without calling in from
+ * interpreted code during VM initialization and immediately after JNI
+ * thread attachment.  Another opportunity exists during JNI_OnLoad.  Rather
+ * than catching these cases we just ignore them here, which is marginally
+ * less accurate but reduces the amount of code we have to touch with #ifdefs.
+ */
+static void checkStackSum(Thread* self) {
+    const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    u4 stackCrc = self->stackCrc;
+    self->stackCrc = 0;
+    u4 crc = dvmInitCrc32();
+    crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
+    if (crc != stackCrc) {
+        const Method* meth = dvmGetCurrentJNIMethod();
+        if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) {
+            LOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc);
+        } else if (strcmp(meth->name, "nativeLoad") == 0 &&
+                (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) {
+            LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
+        } else {
+            LOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
+            dvmAbort();
+        }
+    }
+    self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
+}
+
+#else
+# define COMPUTE_STACK_SUM(_self)   ((void)0)
+# define CHECK_STACK_SUM(_self)     ((void)0)
+#endif
+
+
+/*
+ * ===========================================================================
+ *      Utility functions
+ * ===========================================================================
+ */
+
+/*
+ * Entry/exit processing for all JNI calls.
+ *
+ * We skip the (curiously expensive) thread-local storage lookup on our Thread*.
+ * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized
+ * structures from more than one thread, and things are going to fail
+ * in bizarre ways.  This is only sensible if the native code has been
+ * fully exercised with CheckJNI enabled.
+ */
+class ScopedJniThreadState {
+public:
+    explicit ScopedJniThreadState(JNIEnv* env) {
+        mSelf = ((JNIEnvExt*) env)->self;
+
+        if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
+            // When emulating direct pointers with indirect references, it's critical
+            // that we use the correct per-thread indirect reference table.
+            Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : mSelf;
+            if (self != mSelf) {
+                LOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", mSelf, self);
+                mSelf = self;
+            }
+        }
+
+        CHECK_STACK_SUM(mSelf);
+        dvmChangeStatus(mSelf, THREAD_RUNNING);
+    }
+
+    ~ScopedJniThreadState() {
+        dvmChangeStatus(mSelf, THREAD_NATIVE);
+        COMPUTE_STACK_SUM(mSelf);
+    }
+
+    inline Thread* self() {
+        return mSelf;
+    }
+
+private:
+    Thread* mSelf;
+
+    // Disallow copy and assignment.
+    ScopedJniThreadState(const ScopedJniThreadState&);
+    void operator=(const ScopedJniThreadState&);
+};
+
+#define kGlobalRefsTableInitialSize 512
+#define kGlobalRefsTableMaxSize     51200       /* arbitrary, must be < 64K */
+#define kGrefWaterInterval          100
+#define kTrackGrefUsage             true
+
+#define kWeakGlobalRefsTableInitialSize 16
+
+#define kPinTableInitialSize        16
+#define kPinTableMaxSize            1024
+#define kPinComplainThreshold       10
+
+bool dvmJniStartup() {
+    if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
+                                 kGlobalRefsTableMaxSize,
+                                 kIndirectKindGlobal)) {
+        return false;
+    }
+    if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
+                                 kGlobalRefsTableMaxSize,
+                                 kIndirectKindWeakGlobal)) {
+        return false;
+    }
+
+    dvmInitMutex(&gDvm.jniGlobalRefLock);
+    dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
+    gDvm.jniGlobalRefLoMark = 0;
+    gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
+
+    if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
+        return false;
+    }
+
+    dvmInitMutex(&gDvm.jniPinRefLock);
+
+    return true;
+}
+
+void dvmJniShutdown() {
+    gDvm.jniGlobalRefTable.destroy();
+    gDvm.jniWeakGlobalRefTable.destroy();
+    dvmClearReferenceTable(&gDvm.jniPinRefTable);
+}
+
+/*
+ * Find the JNIEnv associated with the current thread.
+ *
+ * Currently stored in the Thread struct.  Could also just drop this into
+ * thread-local storage.
+ */
+JNIEnvExt* dvmGetJNIEnvForThread() {
+    Thread* self = dvmThreadSelf();
+    if (self == NULL) {
+        return NULL;
+    }
+    return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
+}
+
+/*
+ * Convert an indirect reference to an Object reference.  The indirect
+ * reference may be local, global, or weak-global.
+ *
+ * If "jobj" is NULL, or is a weak global reference whose reference has
+ * been cleared, this returns NULL.  If jobj is an invalid indirect
+ * reference, kInvalidIndirectRefObject is returned.
+ *
+ * Note "env" may be NULL when decoding global references.
+ */
+Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
+    if (jobj == NULL) {
+        return NULL;
+    }
+
+    switch (indirectRefKind(jobj)) {
+    case kIndirectKindLocal:
+        {
+            Object* result = self->jniLocalRefTable.get(jobj);
+            if (UNLIKELY(result == NULL)) {
+                LOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
+                dvmAbort();
+            }
+            return result;
+        }
+    case kIndirectKindGlobal:
+        {
+            // TODO: find a way to avoid the mutex activity here
+            IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
+            ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
+            Object* result = pRefTable->get(jobj);
+            if (UNLIKELY(result == NULL)) {
+                LOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
+                dvmAbort();
+            }
+            return result;
+        }
+    case kIndirectKindWeakGlobal:
+        {
+            // TODO: find a way to avoid the mutex activity here
+            IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
+            ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
+            Object* result = pRefTable->get(jobj);
+            if (result == kClearedJniWeakGlobal) {
+                result = NULL;
+            } else if (UNLIKELY(result == NULL)) {
+                LOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
+                dvmAbort();
+            }
+            return result;
+        }
+    case kIndirectKindInvalid:
+    default:
+        if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
+            // Assume an invalid local reference is actually a direct pointer.
+            return reinterpret_cast<Object*>(jobj);
+        }
+        LOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
+        dvmAbort();
+        return kInvalidIndirectRefObject;
+    }
+}
+
+static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
+    pRefTable->dump("JNI local");
+    LOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmAbort();     // spec says call FatalError; this is equivalent
+}
+
+/*
+ * Add a local reference for an object to the current stack frame.  When
+ * the native function returns, the reference will be discarded.
+ *
+ * We need to allow the same reference to be added multiple times.
+ *
+ * This will be called on otherwise unreferenced objects.  We cannot do
+ * GC allocations here, and it's best if we don't grab a mutex.
+ */
+static inline jobject addLocalReference(Thread* self, Object* obj) {
+    if (obj == NULL) {
+        return NULL;
+    }
+
+    IndirectRefTable* pRefTable = &self->jniLocalRefTable;
+    void* curFrame = self->interpSave.curFrame;
+    u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
+    jobject jobj = (jobject) pRefTable->add(cookie, obj);
+    if (UNLIKELY(jobj == NULL)) {
+        AddLocalReferenceFailure(pRefTable);
+    }
+    if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
+        // Hand out direct pointers to support broken old apps.
+        return reinterpret_cast<jobject>(obj);
+    }
+    return jobj;
+}
+
+/*
+ * Ensure that at least "capacity" references can be held in the local
+ * refs table of the current thread.
+ */
+static bool ensureLocalCapacity(Thread* self, int capacity) {
+    int numEntries = self->jniLocalRefTable.capacity();
+    // TODO: this isn't quite right, since "numEntries" includes holes
+    return ((kJniLocalRefMax - numEntries) >= capacity);
+}
+
+/*
+ * Explicitly delete a reference from the local list.
+ */
+static void deleteLocalReference(Thread* self, jobject jobj) {
+    if (jobj == NULL) {
+        return;
+    }
+
+    IndirectRefTable* pRefTable = &self->jniLocalRefTable;
+    void* curFrame = self->interpSave.curFrame;
+    u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
+    if (!pRefTable->remove(cookie, jobj)) {
+        /*
+         * Attempting to delete a local reference that is not in the
+         * topmost local reference frame is a no-op.  DeleteLocalRef returns
+         * void and doesn't throw any exceptions, but we should probably
+         * complain about it so the user will notice that things aren't
+         * going quite the way they expect.
+         */
+        LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
+    }
+}
+
+/*
+ * Add a global reference for an object.
+ *
+ * We may add the same object more than once.  Add/remove calls are paired,
+ * so it needs to appear on the list multiple times.
+ */
+static jobject addGlobalReference(Object* obj) {
+    if (obj == NULL) {
+        return NULL;
+    }
+
+    //LOGI("adding obj=%p", obj);
+    //dvmDumpThread(dvmThreadSelf(), false);
+
+    if (false && dvmIsClassObject((Object*)obj)) {
+        ClassObject* clazz = (ClassObject*) obj;
+        LOGI("-------");
+        LOGI("Adding global ref on class %s", clazz->descriptor);
+        dvmDumpThread(dvmThreadSelf(), false);
+    }
+    if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
+        StringObject* strObj = (StringObject*) obj;
+        char* str = dvmCreateCstrFromString(strObj);
+        if (strcmp(str, "sync-response") == 0) {
+            LOGI("-------");
+            LOGI("Adding global ref on string '%s'", str);
+            dvmDumpThread(dvmThreadSelf(), false);
+            //dvmAbort();
+        }
+        free(str);
+    }
+    if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
+        ArrayObject* arrayObj = (ArrayObject*) obj;
+        if (arrayObj->length == 8192 /*&&
+            dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
+        {
+            LOGI("Adding global ref on byte array %p (len=%d)",
+                arrayObj, arrayObj->length);
+            dvmDumpThread(dvmThreadSelf(), false);
+        }
+    }
+
+    ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
+
+    /*
+     * Throwing an exception on failure is problematic, because JNI code
+     * may not be expecting an exception, and things sort of cascade.  We
+     * want to have a hard limit to catch leaks during debugging, but this
+     * otherwise needs to expand until memory is consumed.  As a practical
+     * matter, if we have many thousands of global references, chances are
+     * we're either leaking global ref table entries or we're going to
+     * run out of space in the GC heap.
+     */
+    jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
+    if (jobj == NULL) {
+        gDvm.jniGlobalRefTable.dump("JNI global");
+        LOGE("Failed adding to JNI global ref table (%zd entries)",
+                gDvm.jniGlobalRefTable.capacity());
+        dvmAbort();
+    }
+
+    LOGVV("GREF add %p  (%s.%s)", obj,
+        dvmGetCurrentJNIMethod()->clazz->descriptor,
+        dvmGetCurrentJNIMethod()->name);
+
+    /* GREF usage tracking; should probably be disabled for production env */
+    if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
+        int count = gDvm.jniGlobalRefTable.capacity();
+        // TODO: adjust for "holes"
+        if (count > gDvm.jniGlobalRefHiMark) {
+            LOGD("GREF has increased to %d", count);
+            gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
+            gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
+
+            /* watch for "excessive" use; not generally appropriate */
+            if (count >= gDvm.jniGrefLimit) {
+                if (gDvmJni.warnOnly) {
+                    LOGW("Excessive JNI global references (%d)", count);
+                } else {
+                    gDvm.jniGlobalRefTable.dump("JNI global");
+                    LOGE("Excessive JNI global references (%d)", count);
+                    dvmAbort();
+                }
+            }
+        }
+    }
+    return jobj;
+}
+
+static jobject addWeakGlobalReference(Object* obj) {
+    if (obj == NULL) {
+        return NULL;
+    }
+
+    ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
+    IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
+    jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
+    if (jobj == NULL) {
+        gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
+        LOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
+        dvmAbort();
+    }
+    return jobj;
+}
+
+static void deleteWeakGlobalReference(jobject jobj) {
+    if (jobj == NULL) {
+        return;
+    }
+
+    ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
+    IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
+    if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
+        LOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
+    }
+}
+
+/*
+ * Remove a global reference.  In most cases it's the entry most recently
+ * added, which makes this pretty quick.
+ *
+ * Thought: if it's not the most recent entry, just null it out.  When we
+ * fill up, do a compaction pass before we expand the list.
+ */
+static void deleteGlobalReference(jobject jobj) {
+    if (jobj == NULL) {
+        return;
+    }
+
+    ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
+    if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
+        LOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
+        return;
+    }
+
+    if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
+        int count = gDvm.jniGlobalRefTable.capacity();
+        // TODO: not quite right, need to subtract holes
+        if (count < gDvm.jniGlobalRefLoMark) {
+            LOGD("GREF has decreased to %d", count);
+            gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
+            gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
+        }
+    }
+}
+
+/*
+ * Objects don't currently move, so we just need to create a reference
+ * that will ensure the array object isn't collected.
+ *
+ * We use a separate reference table, which is part of the GC root set.
+ */
+static void pinPrimitiveArray(ArrayObject* arrayObj) {
+    if (arrayObj == NULL) {
+        return;
+    }
+
+    ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
+
+    if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
+        dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
+        LOGE("Failed adding to JNI pinned array ref table (%d entries)",
+           (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
+        dvmDumpThread(dvmThreadSelf(), false);
+        dvmAbort();
+    }
+
+    /*
+     * If we're watching global ref usage, also keep an eye on these.
+     *
+     * The total number of pinned primitive arrays should be pretty small.
+     * A single array should not be pinned more than once or twice; any
+     * more than that is a strong indicator that a Release function is
+     * not being called.
+     */
+    if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
+        int count = 0;
+        Object** ppObj = gDvm.jniPinRefTable.table;
+        while (ppObj < gDvm.jniPinRefTable.nextEntry) {
+            if (*ppObj++ == (Object*) arrayObj)
+                count++;
+        }
+
+        if (count > kPinComplainThreshold) {
+            LOGW("JNI: pin count on array %p (%s) is now %d",
+                arrayObj, arrayObj->clazz->descriptor, count);
+            /* keep going */
+        }
+    }
+}
+
+/*
+ * Un-pin the array object.  If an object was pinned twice, it must be
+ * unpinned twice before it's free to move.
+ */
+static void unpinPrimitiveArray(ArrayObject* arrayObj) {
+    if (arrayObj == NULL) {
+        return;
+    }
+
+    ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
+    if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
+            gDvm.jniPinRefTable.table, (Object*) arrayObj))
+    {
+        LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
+            arrayObj, dvmIsHeapAddress((Object*) arrayObj));
+        return;
+    }
+}
+
+/*
+ * Dump the contents of the JNI reference tables to the log file.
+ *
+ * We only dump the local refs associated with the current thread.
+ */
+void dvmDumpJniReferenceTables() {
+    Thread* self = dvmThreadSelf();
+    self->jniLocalRefTable.dump("JNI local");
+    gDvm.jniGlobalRefTable.dump("JNI global");
+    dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
+}
+
+/*
+ * Verify that a reference passed in from native code is one that the
+ * code is allowed to have.
+ *
+ * It's okay for native code to pass us a reference that:
+ *  - was passed in as an argument when invoked by native code (and hence
+ *    is in the JNI local refs table)
+ *  - was returned to it from JNI (and is now in the local refs table)
+ *  - is present in the JNI global refs table
+ *
+ * Used by -Xcheck:jni and GetObjectRefType.
+ */
+jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj) {
+    /*
+     * IndirectRefKind is currently defined as an exact match of
+     * jobjectRefType, so this is easy.  We have to decode it to determine
+     * if it's a valid reference and not merely valid-looking.
+     */
+    assert(jobj != NULL);
+
+    Object* obj = dvmDecodeIndirectRef(self, jobj);
+    if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
+        // If we're handing out direct pointers, check whether 'jobj' is a direct reference
+        // to a local reference.
+        return self->jniLocalRefTable.contains(obj) ? JNILocalRefType : JNIInvalidRefType;
+    } else if (obj == kInvalidIndirectRefObject) {
+        return JNIInvalidRefType;
+    } else {
+        return (jobjectRefType) indirectRefKind(jobj);
+    }
+}
+
+static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
+    size_t i;
+    for (i = 0; i < methodCount; ++i) {
+        Method* method = &methods[i];
+        if (strcmp(name, method->name) == 0) {
+            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+            LOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
+            free(desc);
+        }
+    }
+}
+
+static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
+    LOGE("ERROR: couldn't find native method");
+    LOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
+    dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
+    dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
+}
+
+/*
+ * Register a method that uses JNI calling conventions.
+ */
+static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
+    const char* signature, void* fnPtr)
+{
+    if (fnPtr == NULL) {
+        return false;
+    }
+
+    // If a signature starts with a '!', we take that as a sign that the native code doesn't
+    // need the extra JNI arguments (the JNIEnv* and the jclass).
+    bool fastJni = false;
+    if (*signature == '!') {
+        fastJni = true;
+        ++signature;
+        LOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
+    }
+
+    Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
+    if (method == NULL) {
+        method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
+    }
+    if (method == NULL) {
+        dumpCandidateMethods(clazz, methodName, signature);
+        return false;
+    }
+
+    if (!dvmIsNativeMethod(method)) {
+        LOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
+        return false;
+    }
+
+    if (fastJni) {
+        // In this case, we have extra constraints to check...
+        if (dvmIsSynchronizedMethod(method)) {
+            // Synchronization is usually provided by the JNI bridge,
+            // but we won't have one.
+            LOGE("fast JNI method %s.%s:%s cannot be synchronized",
+                    clazz->descriptor, methodName, signature);
+            return false;
+        }
+        if (!dvmIsStaticMethod(method)) {
+            // There's no real reason for this constraint, but since we won't
+            // be supplying a JNIEnv* or a jobject 'this', you're effectively
+            // static anyway, so it seems clearer to say so.
+            LOGE("fast JNI method %s.%s:%s cannot be non-static",
+                    clazz->descriptor, methodName, signature);
+            return false;
+        }
+    }
+
+    if (method->nativeFunc != dvmResolveNativeMethod) {
+        /* this is allowed, but unusual */
+        LOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
+    }
+
+    method->fastJni = fastJni;
+    dvmUseJNIBridge(method, fnPtr);
+
+    LOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
+    return true;
+}
+
+static const char* builtInPrefixes[] = {
+    "Landroid/",
+    "Lcom/android/",
+    "Lcom/google/android/",
+    "Ldalvik/",
+    "Ljava/",
+    "Ljavax/",
+    "Llibcore/",
+    "Lorg/apache/harmony/",
+};
+
+static bool shouldTrace(Method* method) {
+    const char* className = method->clazz->descriptor;
+    // Return true if the -Xjnitrace setting implies we should trace 'method'.
+    if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
+        return true;
+    }
+    // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
+    // like part of Android.
+    if (gDvmJni.logThirdPartyJni) {
+        for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
+            if (strstr(className, builtInPrefixes[i]) == className) {
+                return false;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+/*
+ * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
+ * to point at the actual function.
+ */
+void dvmUseJNIBridge(Method* method, void* func) {
+    method->shouldTrace = shouldTrace(method);
+
+    // Does the method take any reference arguments?
+    method->noRef = true;
+    const char* cp = method->shorty;
+    while (*++cp != '\0') { // Pre-increment to skip return type.
+        if (*cp == 'L') {
+            method->noRef = false;
+            break;
+        }
+    }
+
+    DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
+    dvmSetNativeFunc(method, bridge, (const u2*) func);
+}
+
+// TODO: rewrite this to share code with CheckJNI's tracing...
+static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
+{
+    size_t len = strlen(buf);
+    if (len >= n - 32) { // 32 should be longer than anything we could append.
+        buf[len - 1] = '.';
+        buf[len - 2] = '.';
+        buf[len - 3] = '.';
+        return;
+    }
+    char* p = buf + len;
+    switch (type) {
+    case 'B':
+        if (value.b >= 0 && value.b < 10) {
+            sprintf(p, "%d", value.b);
+        } else {
+            sprintf(p, "%#x (%d)", value.b, value.b);
+        }
+        break;
+    case 'C':
+        if (value.c < 0x7f && value.c >= ' ') {
+            sprintf(p, "U+%x ('%c')", value.c, value.c);
+        } else {
+            sprintf(p, "U+%x", value.c);
+        }
+        break;
+    case 'D':
+        sprintf(p, "%g", value.d);
+        break;
+    case 'F':
+        sprintf(p, "%g", value.f);
+        break;
+    case 'I':
+        sprintf(p, "%d", value.i);
+        break;
+    case 'L':
+        sprintf(p, "%#x", value.i);
+        break;
+    case 'J':
+        sprintf(p, "%lld", value.j);
+        break;
+    case 'S':
+        sprintf(p, "%d", value.s);
+        break;
+    case 'V':
+        strcpy(p, "void");
+        break;
+    case 'Z':
+        strcpy(p, value.z ? "true" : "false");
+        break;
+    default:
+        sprintf(p, "unknown type '%c'", type);
+        break;
+    }
+
+    if (appendComma) {
+        strcat(p, ", ");
+    }
+}
+
+static void logNativeMethodEntry(const Method* method, const u4* args)
+{
+    char thisString[32] = { 0 };
+    const u4* sp = args;
+    if (!dvmIsStaticMethod(method)) {
+        sprintf(thisString, "this=0x%08x ", *sp++);
+    }
+
+    char argsString[128]= { 0 };
+    const char* desc = &method->shorty[1];
+    while (*desc != '\0') {
+        char argType = *desc++;
+        JValue value;
+        if (argType == 'D' || argType == 'J') {
+            value.j = dvmGetArgLong(sp, 0);
+            sp += 2;
+        } else {
+            value.i = *sp++;
+        }
+        appendValue(argType, value, argsString, sizeof(argsString),
+        *desc != '\0');
+    }
+
+    std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
+    char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
+    LOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
+    free(signature);
+}
+
+static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
+{
+    std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
+    char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
+    if (dvmCheckException(self)) {
+        Object* exception = dvmGetException(self);
+        std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
+        LOGI("<- %s %s%s threw %s", className.c_str(),
+                method->name, signature, exceptionClassName.c_str());
+    } else {
+        char returnValueString[128] = { 0 };
+        char returnType = method->shorty[0];
+        appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
+        LOGI("<- %s %s%s returned %s", className.c_str(),
+                method->name, signature, returnValueString);
+    }
+    free(signature);
+}
+
+/*
+ * Get the method currently being executed by examining the interp stack.
+ */
+const Method* dvmGetCurrentJNIMethod() {
+    assert(dvmThreadSelf() != NULL);
+
+    void* fp = dvmThreadSelf()->interpSave.curFrame;
+    const Method* meth = SAVEAREA_FROM_FP(fp)->method;
+
+    assert(meth != NULL);
+    assert(dvmIsNativeMethod(meth));
+    return meth;
+}
+
+/*
+ * Track a JNI MonitorEnter in the current thread.
+ *
+ * The goal is to be able to "implicitly" release all JNI-held monitors
+ * when the thread detaches.
+ *
+ * Monitors may be entered multiple times, so we add a new entry for each
+ * enter call.  It would be more efficient to keep a counter.  At present
+ * there's no real motivation to improve this however.
+ */
+static void trackMonitorEnter(Thread* self, Object* obj) {
+    static const int kInitialSize = 16;
+    ReferenceTable* refTable = &self->jniMonitorRefTable;
+
+    /* init table on first use */
+    if (refTable->table == NULL) {
+        assert(refTable->maxEntries == 0);
+
+        if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
+            LOGE("Unable to initialize monitor tracking table");
+            dvmAbort();
+        }
+    }
+
+    if (!dvmAddToReferenceTable(refTable, obj)) {
+        /* ran out of memory? could throw exception instead */
+        LOGE("Unable to add entry to monitor tracking table");
+        dvmAbort();
+    } else {
+        LOGVV("--- added monitor %p", obj);
+    }
+}
+
+/*
+ * Track a JNI MonitorExit in the current thread.
+ */
+static void trackMonitorExit(Thread* self, Object* obj) {
+    ReferenceTable* pRefTable = &self->jniMonitorRefTable;
+
+    if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
+        LOGE("JNI monitor %p not found in tracking list", obj);
+        /* keep going? */
+    } else {
+        LOGVV("--- removed monitor %p", obj);
+    }
+}
+
+/*
+ * Release all monitors held by the jniMonitorRefTable list.
+ */
+void dvmReleaseJniMonitors(Thread* self) {
+    ReferenceTable* pRefTable = &self->jniMonitorRefTable;
+    Object** top = pRefTable->table;
+
+    if (top == NULL) {
+        return;
+    }
+    Object** ptr = pRefTable->nextEntry;
+    while (--ptr >= top) {
+        if (!dvmUnlockObject(self, *ptr)) {
+            LOGW("Unable to unlock monitor %p at thread detach", *ptr);
+        } else {
+            LOGVV("--- detach-releasing monitor %p", *ptr);
+        }
+    }
+
+    /* zap it */
+    pRefTable->nextEntry = pRefTable->table;
+}
+
+/*
+ * Determine if the specified class can be instantiated from JNI.  This
+ * is used by AllocObject / NewObject, which are documented as throwing
+ * an exception for abstract and interface classes, and not accepting
+ * array classes.  We also want to reject attempts to create new Class
+ * objects, since only DefineClass should do that.
+ */
+static bool canAllocClass(ClassObject* clazz) {
+    if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
+        /* JNI spec defines what this throws */
+        dvmThrowInstantiationException(clazz, "abstract class or interface");
+        return false;
+    } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
+        /* spec says "must not" for arrays, ignores Class */
+        dvmThrowInstantiationException(clazz, "wrong JNI function");
+        return false;
+    }
+    return true;
+}
+
+
+/*
+ * ===========================================================================
+ *      JNI call bridge
+ * ===========================================================================
+ */
+
+/*
+ * The functions here form a bridge between interpreted code and JNI native
+ * functions.  The basic task is to convert an array of primitives and
+ * references into C-style function arguments.  This is architecture-specific
+ * and usually requires help from assembly code.
+ *
+ * The bridge takes four arguments: the array of parameters, a place to
+ * store the function result (if any), the method to call, and a pointer
+ * to the current thread.
+ *
+ * These functions aren't called directly from elsewhere in the VM.
+ * A pointer in the Method struct points to one of these, and when a native
+ * method is invoked the interpreter jumps to it.
+ *
+ * (The "internal native" methods are invoked the same way, but instead
+ * of calling through a bridge, the target method is called directly.)
+ *
+ * The "args" array should not be modified, but we do so anyway for
+ * performance reasons.  We know that it points to the "outs" area on
+ * the current method's interpreted stack.  This area is ignored by the
+ * precise GC, because there is no register map for a native method (for
+ * an interpreted method the args would be listed in the argument set).
+ * We know all of the values exist elsewhere on the interpreted stack,
+ * because the method call setup copies them right before making the call,
+ * so we don't have to worry about concealing stuff from the GC.
+ *
+ * If we don't want to modify "args", we either have to create a local
+ * copy and modify it before calling dvmPlatformInvoke, or we have to do
+ * the local reference replacement within dvmPlatformInvoke.  The latter
+ * has some performance advantages, though if we can inline the local
+ * reference adds we may win when there's a lot of reference args (unless
+ * we want to code up some local ref table manipulation in assembly.
+ */
+
+/*
+ * If necessary, convert the value in pResult from a local/global reference
+ * to an object pointer.
+ *
+ * If the returned reference is invalid, kInvalidIndirectRefObject will
+ * be returned in pResult.
+ */
+static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
+        pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
+    }
+}
+
+/*
+ * General form, handles all cases.
+ */
+void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
+    u4* modArgs = (u4*) args;
+    jclass staticMethodClass = NULL;
+
+    u4 accessFlags = method->accessFlags;
+    bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
+
+    //LOGI("JNI calling %p (%s.%s:%s):", method->insns,
+    //    method->clazz->descriptor, method->name, method->shorty);
+
+    /*
+     * Walk the argument list, creating local references for appropriate
+     * arguments.
+     */
+    int idx = 0;
+    Object* lockObj;
+    if ((accessFlags & ACC_STATIC) != 0) {
+        lockObj = (Object*) method->clazz;
+        /* add the class object we pass in */
+        staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
+    } else {
+        lockObj = (Object*) args[0];
+        /* add "this" */
+        modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
+    }
+
+    if (!method->noRef) {
+        const char* shorty = &method->shorty[1];        /* skip return type */
+        while (*shorty != '\0') {
+            switch (*shorty++) {
+            case 'L':
+                //LOGI("  local %d: 0x%08x", idx, modArgs[idx]);
+                if (modArgs[idx] != 0) {
+                    modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
+                }
+                break;
+            case 'D':
+            case 'J':
+                idx++;
+                break;
+            default:
+                /* Z B C S I -- do nothing */
+                break;
+            }
+            idx++;
+        }
+    }
+
+    if (UNLIKELY(method->shouldTrace)) {
+        logNativeMethodEntry(method, args);
+    }
+    if (UNLIKELY(isSynchronized)) {
+        dvmLockObject(self, lockObj);
+    }
+
+    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+
+    ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
+    assert(method->insns != NULL);
+
+    JNIEnv* env = self->jniEnv;
+    COMPUTE_STACK_SUM(self);
+    dvmPlatformInvoke(env,
+            (ClassObject*) staticMethodClass,
+            method->jniArgInfo, method->insSize, modArgs, method->shorty,
+            (void*) method->insns, pResult);
+    CHECK_STACK_SUM(self);
+
+    dvmChangeStatus(self, oldStatus);
+
+    convertReferenceResult(env, pResult, method, self);
+
+    if (UNLIKELY(isSynchronized)) {
+        dvmUnlockObject(self, lockObj);
+    }
+    if (UNLIKELY(method->shouldTrace)) {
+        logNativeMethodExit(method, self, *pResult);
+    }
+}
+
+/*
+ * ===========================================================================
+ *      JNI implementation
+ * ===========================================================================
+ */
+
+/*
+ * Return the version of the native method interface.
+ */
+static jint GetVersion(JNIEnv* env) {
+    /*
+     * There is absolutely no need to toggle the mode for correct behavior.
+     * However, it does provide native code with a simple "suspend self
+     * if necessary" call.
+     */
+    ScopedJniThreadState ts(env);
+    return JNI_VERSION_1_6;
+}
+
+/*
+ * Create a new class from a bag of bytes.
+ *
+ * This is not currently supported within Dalvik.
+ */
+static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
+    const jbyte* buf, jsize bufLen)
+{
+    UNUSED_PARAMETER(name);
+    UNUSED_PARAMETER(loader);
+    UNUSED_PARAMETER(buf);
+    UNUSED_PARAMETER(bufLen);
+
+    ScopedJniThreadState ts(env);
+    LOGW("JNI DefineClass is not supported");
+    return NULL;
+}
+
+/*
+ * Find a class by name.
+ *
+ * We have to use the "no init" version of FindClass here, because we might
+ * be getting the class prior to registering native methods that will be
+ * used in <clinit>.
+ *
+ * We need to get the class loader associated with the current native
+ * method.  If there is no native method, e.g. we're calling this from native
+ * code right after creating the VM, the spec says we need to use the class
+ * loader returned by "ClassLoader.getBaseClassLoader".  There is no such
+ * method, but it's likely they meant ClassLoader.getSystemClassLoader.
+ * We can't get that until after the VM has initialized though.
+ */
+static jclass FindClass(JNIEnv* env, const char* name) {
+    ScopedJniThreadState ts(env);
+
+    const Method* thisMethod = dvmGetCurrentJNIMethod();
+    assert(thisMethod != NULL);
+
+    Object* loader;
+    Object* trackedLoader = NULL;
+    if (ts.self()->classLoaderOverride != NULL) {
+        /* hack for JNI_OnLoad */
+        assert(strcmp(thisMethod->name, "nativeLoad") == 0);
+        loader = ts.self()->classLoaderOverride;
+    } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
+               thisMethod == gDvm.methDalvikSystemNativeStart_run) {
+        /* start point of invocation interface */
+        if (!gDvm.initializing) {
+            loader = trackedLoader = dvmGetSystemClassLoader();
+        } else {
+            loader = NULL;
+        }
+    } else {
+        loader = thisMethod->clazz->classLoader;
+    }
+
+    char* descriptor = dvmNameToDescriptor(name);
+    if (descriptor == NULL) {
+        return NULL;
+    }
+    ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
+    free(descriptor);
+
+    jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
+    dvmReleaseTrackedAlloc(trackedLoader, ts.self());
+    return jclazz;
+}
+
+/*
+ * Return the superclass of a class.
+ */
+static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
+}
+
+/*
+ * Determine whether an object of clazz1 can be safely cast to clazz2.
+ *
+ * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
+ */
+static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
+    ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
+    return dvmInstanceof(clazz1, clazz2);
+}
+
+/*
+ * Given a java.lang.reflect.Method or .Constructor, return a methodID.
+ */
+static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
+    ScopedJniThreadState ts(env);
+    Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
+    return (jmethodID) dvmGetMethodFromReflectObj(method);
+}
+
+/*
+ * Given a java.lang.reflect.Field, return a fieldID.
+ */
+static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
+    ScopedJniThreadState ts(env);
+    Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
+    return (jfieldID) dvmGetFieldFromReflectObj(field);
+}
+
+/*
+ * Convert a methodID to a java.lang.reflect.Method or .Constructor.
+ *
+ * (The "isStatic" field does not appear in the spec.)
+ *
+ * Throws OutOfMemory and returns NULL on failure.
+ */
+static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
+    Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
+    dvmReleaseTrackedAlloc(obj, NULL);
+    return addLocalReference(ts.self(), obj);
+}
+
+/*
+ * Convert a fieldID to a java.lang.reflect.Field.
+ *
+ * (The "isStatic" field does not appear in the spec.)
+ *
+ * Throws OutOfMemory and returns NULL on failure.
+ */
+static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
+    Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
+    dvmReleaseTrackedAlloc(obj, NULL);
+    return addLocalReference(ts.self(), obj);
+}
+
+/*
+ * Take this exception and throw it.
+ */
+static jint Throw(JNIEnv* env, jthrowable jobj) {
+    ScopedJniThreadState ts(env);
+    if (jobj != NULL) {
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+        dvmSetException(ts.self(), obj);
+        return JNI_OK;
+    }
+    return JNI_ERR;
+}
+
+/*
+ * Constructs an exception object from the specified class with the message
+ * specified by "message", and throws it.
+ */
+static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    dvmThrowException(clazz, message);
+    // TODO: should return failure if this didn't work (e.g. OOM)
+    return JNI_OK;
+}
+
+/*
+ * If an exception is being thrown, return the exception object.  Otherwise,
+ * return NULL.
+ *
+ * TODO: if there is no pending exception, we should be able to skip the
+ * enter/exit checks.  If we find one, we need to enter and then re-fetch
+ * the exception (in case it got moved by a compacting GC).
+ */
+static jthrowable ExceptionOccurred(JNIEnv* env) {
+    ScopedJniThreadState ts(env);
+    Object* exception = dvmGetException(ts.self());
+    jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
+    if (localException == NULL && exception != NULL) {
+        /*
+         * We were unable to add a new local reference, and threw a new
+         * exception.  We can't return "exception", because it's not a
+         * local reference.  So we have to return NULL, indicating that
+         * there was no exception, even though it's pretty much raining
+         * exceptions in here.
+         */
+        LOGW("JNI WARNING: addLocal/exception combo");
+    }
+    return localException;
+}
+
+/*
+ * Print an exception and stack trace to stderr.
+ */
+static void ExceptionDescribe(JNIEnv* env) {
+    ScopedJniThreadState ts(env);
+    Object* exception = dvmGetException(ts.self());
+    if (exception != NULL) {
+        dvmPrintExceptionStackTrace();
+    } else {
+        LOGI("Odd: ExceptionDescribe called, but no exception pending");
+    }
+}
+
+/*
+ * Clear the exception currently being thrown.
+ *
+ * TODO: we should be able to skip the enter/exit stuff.
+ */
+static void ExceptionClear(JNIEnv* env) {
+    ScopedJniThreadState ts(env);
+    dvmClearException(ts.self());
+}
+
+/*
+ * Kill the VM.  This function does not return.
+ */
+static void FatalError(JNIEnv* env, const char* msg) {
+    //dvmChangeStatus(NULL, THREAD_RUNNING);
+    LOGE("JNI posting fatal error: %s", msg);
+    dvmAbort();
+}
+
+/*
+ * Push a new JNI frame on the stack, with a new set of locals.
+ *
+ * The new frame must have the same method pointer.  (If for no other
+ * reason than FindClass needs it to get the appropriate class loader.)
+ */
+static jint PushLocalFrame(JNIEnv* env, jint capacity) {
+    ScopedJniThreadState ts(env);
+    if (!ensureLocalCapacity(ts.self(), capacity) ||
+            !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
+    {
+        /* yes, OutOfMemoryError, not StackOverflowError */
+        dvmClearException(ts.self());
+        dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
+        return JNI_ERR;
+    }
+    return JNI_OK;
+}
+
+/*
+ * Pop the local frame off.  If "jresult" is not null, add it as a
+ * local reference on the now-current frame.
+ */
+static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
+    ScopedJniThreadState ts(env);
+    Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
+    if (!dvmPopLocalFrame(ts.self())) {
+        LOGW("JNI WARNING: too many PopLocalFrame calls");
+        dvmClearException(ts.self());
+        dvmThrowRuntimeException("too many PopLocalFrame calls");
+    }
+    return addLocalReference(ts.self(), result);
+}
+
+/*
+ * Add a reference to the global list.
+ */
+static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    return addGlobalReference(obj);
+}
+
+/*
+ * Delete a reference from the global list.
+ */
+static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
+    ScopedJniThreadState ts(env);
+    deleteGlobalReference(jglobalRef);
+}
+
+
+/*
+ * Add a reference to the local list.
+ */
+static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    return addLocalReference(ts.self(), obj);
+}
+
+/*
+ * Delete a reference from the local list.
+ */
+static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
+    ScopedJniThreadState ts(env);
+    deleteLocalReference(ts.self(), jlocalRef);
+}
+
+/*
+ * Ensure that the local references table can hold at least this many
+ * references.
+ */
+static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
+    ScopedJniThreadState ts(env);
+    bool okay = ensureLocalCapacity(ts.self(), capacity);
+    if (!okay) {
+        dvmThrowOutOfMemoryError("can't ensure local reference capacity");
+    }
+    return okay ? 0 : -1;
+}
+
+
+/*
+ * Determine whether two Object references refer to the same underlying object.
+ */
+static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
+    ScopedJniThreadState ts(env);
+    Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
+    Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
+    return (obj1 == obj2);
+}
+
+/*
+ * Allocate a new object without invoking any constructors.
+ */
+static jobject AllocObject(JNIEnv* env, jclass jclazz) {
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    if (!canAllocClass(clazz) ||
+        (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
+    {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    return addLocalReference(ts.self(), newObj);
+}
+
+/*
+ * Allocate a new object and invoke the supplied constructor.
+ */
+static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+
+    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    jobject result = addLocalReference(ts.self(), newObj);
+    if (newObj != NULL) {
+        JValue unused;
+        va_list args;
+        va_start(args, methodID);
+        dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
+        va_end(args);
+    }
+    return result;
+}
+
+static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+
+    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    jobject result = addLocalReference(ts.self(), newObj);
+    if (newObj != NULL) {
+        JValue unused;
+        dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
+    }
+    return result;
+}
+
+static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
+    ScopedJniThreadState ts(env);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+
+    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    jobject result = addLocalReference(ts.self(), newObj);
+    if (newObj != NULL) {
+        JValue unused;
+        dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
+    }
+    return result;
+}
+
+/*
+ * Returns the class of an object.
+ *
+ * JNI spec says: obj must not be NULL.
+ */
+static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+
+    assert(jobj != NULL);
+
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
+}
+
+/*
+ * Determine whether "obj" is an instance of "clazz".
+ */
+static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
+    ScopedJniThreadState ts(env);
+
+    assert(jclazz != NULL);
+    if (jobj == NULL) {
+        return true;
+    }
+
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    return dvmInstanceof(obj->clazz, clazz);
+}
+
+/*
+ * Get a method ID for an instance method.
+ *
+ * While Dalvik bytecode has distinct instructions for virtual, super,
+ * static, direct, and interface method invocation, JNI only provides
+ * two functions for acquiring a method ID.  This call handles everything
+ * but static methods.
+ *
+ * JNI defines <init> as an instance method, but Dalvik considers it a
+ * "direct" method, so we have to special-case it here.
+ *
+ * Dalvik also puts all private methods into the "direct" list, so we
+ * really need to just search both lists.
+ */
+static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+        assert(dvmCheckException(ts.self()));
+    } else if (dvmIsInterfaceClass(clazz)) {
+        Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
+        if (meth == NULL) {
+            dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
+                "no method with name='%s' signature='%s' in interface %s",
+                name, sig, clazz->descriptor);
+        }
+        return (jmethodID) meth;
+    }
+    Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
+    if (meth == NULL) {
+        /* search private methods and constructors; non-hierarchical */
+        meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
+    }
+    if (meth != NULL && dvmIsStaticMethod(meth)) {
+        IF_LOGD() {
+            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+            LOGD("GetMethodID: not returning static method %s.%s %s",
+                    clazz->descriptor, meth->name, desc);
+            free(desc);
+        }
+        meth = NULL;
+    }
+    if (meth == NULL) {
+        dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
+                "no method with name='%s' signature='%s' in class %s",
+                name, sig, clazz->descriptor);
+    } else {
+        /*
+         * The method's class may not be the same as clazz, but if
+         * it isn't this must be a virtual method and the class must
+         * be a superclass (and, hence, already initialized).
+         */
+        assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
+    }
+    return (jmethodID) meth;
+}
+
+/*
+ * Get a field ID (instance fields).
+ */
+static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+
+    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
+    if (id == NULL) {
+        dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
+                "no field with name='%s' signature='%s' in class %s",
+                name, sig, clazz->descriptor);
+    }
+    return id;
+}
+
+/*
+ * Get the method ID for a static method in a class.
+ */
+static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
+
+    /* make sure it's static, not virtual+private */
+    if (meth != NULL && !dvmIsStaticMethod(meth)) {
+        IF_LOGD() {
+            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+            LOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
+                    clazz->descriptor, meth->name, desc);
+            free(desc);
+        }
+        meth = NULL;
+    }
+
+    jmethodID id = (jmethodID) meth;
+    if (id == NULL) {
+        dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
+                "no static method with name='%s' signature='%s' in class %s",
+                name, sig, clazz->descriptor);
+    }
+    return id;
+}
+
+/*
+ * Get a field ID (static fields).
+ */
+static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+
+    jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
+    if (id == NULL) {
+        dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
+                "no static field with name='%s' signature='%s' in class %s",
+                name, sig, clazz->descriptor);
+    }
+    return id;
+}
+
+/*
+ * Get a static field.
+ *
+ * If we get an object reference, add it to the local refs list.
+ */
+#define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
+    static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz,      \
+        jfieldID fieldID)                                                   \
+    {                                                                       \
+        UNUSED_PARAMETER(jclazz);                                           \
+        ScopedJniThreadState ts(env);                                       \
+        StaticField* sfield = (StaticField*) fieldID;                       \
+        _ctype value;                                                       \
+        if (dvmIsVolatileField(sfield)) {                                   \
+            if (_isref) {   /* only when _ctype==jobject */                 \
+                Object* obj = dvmGetStaticFieldObjectVolatile(sfield);      \
+                value = (_ctype)(u4)addLocalReference(ts.self(), obj);            \
+            } else {                                                        \
+                value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
+            }                                                               \
+        } else {                                                            \
+            if (_isref) {                                                   \
+                Object* obj = dvmGetStaticFieldObject(sfield);              \
+                value = (_ctype)(u4)addLocalReference(ts.self(), obj);            \
+            } else {                                                        \
+                value = (_ctype) dvmGetStaticField##_jname(sfield);         \
+            }                                                               \
+        }                                                                   \
+        return value;                                                       \
+    }
+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);
+
+/*
+ * Set a static field.
+ */
+#define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)              \
+    static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz,        \
+        jfieldID fieldID, _ctype value)                                     \
+    {                                                                       \
+        UNUSED_PARAMETER(jclazz);                                           \
+        ScopedJniThreadState ts(env);                                       \
+        StaticField* sfield = (StaticField*) fieldID;                       \
+        if (dvmIsVolatileField(sfield)) {                                   \
+            if (_isref) {   /* only when _ctype==jobject */                 \
+                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
+                dvmSetStaticFieldObjectVolatile(sfield, valObj);            \
+            } else {                                                        \
+                dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
+            }                                                               \
+        } else {                                                            \
+            if (_isref) {                                                   \
+                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
+                dvmSetStaticFieldObject(sfield, valObj);                    \
+            } else {                                                        \
+                dvmSetStaticField##_jname(sfield, (_ctype2)value);          \
+            }                                                               \
+        }                                                                   \
+    }
+SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
+SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
+SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
+SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
+SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
+SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
+SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
+SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
+SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
+
+/*
+ * Get an instance field.
+ *
+ * If we get an object reference, add it to the local refs list.
+ */
+#define GET_TYPE_FIELD(_ctype, _jname, _isref)                              \
+    static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj,             \
+        jfieldID fieldID)                                                   \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
+        InstField* field = (InstField*) fieldID;                            \
+        _ctype value;                                                       \
+        if (dvmIsVolatileField(field)) {                            \
+            if (_isref) {   /* only when _ctype==jobject */                 \
+                Object* valObj =                                            \
+                    dvmGetFieldObjectVolatile(obj, field->byteOffset);      \
+                value = (_ctype)(u4)addLocalReference(ts.self(), valObj);         \
+            } else {                                                        \
+                value = (_ctype)                                            \
+                    dvmGetField##_jname##Volatile(obj, field->byteOffset);  \
+            }                                                               \
+        } else {                                                            \
+            if (_isref) {                                                   \
+                Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
+                value = (_ctype)(u4)addLocalReference(ts.self(), valObj);         \
+            } else {                                                        \
+                value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
+            }                                                               \
+        }                                                                   \
+        return value;                                                       \
+    }
+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);
+
+/*
+ * Set an instance field.
+ */
+#define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)                     \
+    static void Set##_jname##Field(JNIEnv* env, jobject jobj,               \
+        jfieldID fieldID, _ctype value)                                     \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
+        InstField* field = (InstField*) fieldID;                            \
+        if (dvmIsVolatileField(field)) {                                    \
+            if (_isref) {   /* only when _ctype==jobject */                 \
+                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
+                dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj);  \
+            } else {                                                        \
+                dvmSetField##_jname##Volatile(obj,                          \
+                    field->byteOffset, (_ctype2)value);                     \
+            }                                                               \
+        } else {                                                            \
+            if (_isref) {                                                   \
+                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
+                dvmSetFieldObject(obj, field->byteOffset, valObj);          \
+            } else {                                                        \
+                dvmSetField##_jname(obj,                                    \
+                    field->byteOffset, (_ctype2)value);                     \
+            }                                                               \
+        }                                                                   \
+    }
+SET_TYPE_FIELD(jobject, Object*, Object, true);
+SET_TYPE_FIELD(jboolean, bool, Boolean, false);
+SET_TYPE_FIELD(jbyte, s1, Byte, false);
+SET_TYPE_FIELD(jchar, u2, Char, false);
+SET_TYPE_FIELD(jshort, s2, Short, false);
+SET_TYPE_FIELD(jint, s4, Int, false);
+SET_TYPE_FIELD(jlong, s8, Long, false);
+SET_TYPE_FIELD(jfloat, float, Float, false);
+SET_TYPE_FIELD(jdouble, double, Double, false);
+
+/*
+ * Make a virtual method call.
+ *
+ * Three versions (..., va_list, jvalue[]) for each return type.  If we're
+ * returning an Object, we have to add it to the local references table.
+ */
+#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref)              \
+    static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj,           \
+        jmethodID methodID, ...)                                            \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
+        const Method* meth;                                                 \
+        va_list args;                                                       \
+        JValue result;                                                      \
+        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
+        if (meth == NULL) {                                                 \
+            return _retfail;                                                \
+        }                                                                   \
+        va_start(args, methodID);                                           \
+        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
+        va_end(args);                                                       \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }                                                                       \
+    static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj,          \
+        jmethodID methodID, va_list args)                                   \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
+        const Method* meth;                                                 \
+        JValue result;                                                      \
+        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
+        if (meth == NULL) {                                                 \
+            return _retfail;                                                \
+        }                                                                   \
+        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }                                                                       \
+    static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj,          \
+        jmethodID methodID, jvalue* args)                                   \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
+        const Method* meth;                                                 \
+        JValue result;                                                      \
+        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
+        if (meth == NULL) {                                                 \
+            return _retfail;                                                \
+        }                                                                   \
+        dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }
+CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
+CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
+CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
+CALL_VIRTUAL(jchar, Char, 0, result.c, false);
+CALL_VIRTUAL(jshort, Short, 0, result.s, false);
+CALL_VIRTUAL(jint, Int, 0, result.i, false);
+CALL_VIRTUAL(jlong, Long, 0, result.j, false);
+CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
+CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
+CALL_VIRTUAL(void, Void, , , false);
+
+/*
+ * Make a "non-virtual" method call.  We're still calling a virtual method,
+ * but this time we're not doing an indirection through the object's vtable.
+ * The "clazz" parameter defines which implementation of a method we want.
+ *
+ * Three versions (..., va_list, jvalue[]) for each return type.
+ */
+#define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref)           \
+    static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
+        jclass jclazz, jmethodID methodID, ...)                             \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
+        const Method* meth;                                                 \
+        va_list args;                                                       \
+        JValue result;                                                      \
+        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
+        if (meth == NULL) {                                                 \
+            return _retfail;                                                \
+        }                                                                   \
+        va_start(args, methodID);                                           \
+        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        va_end(args);                                                       \
+        return _retok;                                                      \
+    }                                                                       \
+    static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
+        jclass jclazz, jmethodID methodID, va_list args)                    \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
+        const Method* meth;                                                 \
+        JValue result;                                                      \
+        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
+        if (meth == NULL) {                                                 \
+            return _retfail;                                                \
+        }                                                                   \
+        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }                                                                       \
+    static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
+        jclass jclazz, jmethodID methodID, jvalue* args)                    \
+    {                                                                       \
+        ScopedJniThreadState ts(env);                                       \
+        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
+        const Method* meth;                                                 \
+        JValue result;                                                      \
+        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
+        if (meth == NULL) {                                                 \
+            return _retfail;                                                \
+        }                                                                   \
+        dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }
+CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
+CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
+CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
+CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
+CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
+CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
+CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
+CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
+CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
+CALL_NONVIRTUAL(void, Void, , , false);
+
+
+/*
+ * Call a static method.
+ */
+#define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
+    static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
+        jmethodID methodID, ...)                                            \
+    {                                                                       \
+        UNUSED_PARAMETER(jclazz);                                           \
+        ScopedJniThreadState ts(env);                                       \
+        JValue result;                                                      \
+        va_list args;                                                       \
+        va_start(args, methodID);                                           \
+        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
+        va_end(args);                                                       \
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }                                                                       \
+    static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
+        jmethodID methodID, va_list args)                                   \
+    {                                                                       \
+        UNUSED_PARAMETER(jclazz);                                           \
+        ScopedJniThreadState ts(env);                                       \
+        JValue result;                                                      \
+        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }                                                                       \
+    static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
+        jmethodID methodID, jvalue* args)                                   \
+    {                                                                       \
+        UNUSED_PARAMETER(jclazz);                                           \
+        ScopedJniThreadState ts(env);                                       \
+        JValue result;                                                      \
+        dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
+        if (_isref && !dvmCheckException(ts.self()))                        \
+            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
+        return _retok;                                                      \
+    }
+CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
+CALL_STATIC(jboolean, Boolean, 0, result.z, false);
+CALL_STATIC(jbyte, Byte, 0, result.b, false);
+CALL_STATIC(jchar, Char, 0, result.c, false);
+CALL_STATIC(jshort, Short, 0, result.s, false);
+CALL_STATIC(jint, Int, 0, result.i, false);
+CALL_STATIC(jlong, Long, 0, result.j, false);
+CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
+CALL_STATIC(jdouble, Double, 0.0, result.d, false);
+CALL_STATIC(void, Void, , , false);
+
+/*
+ * Create a new String from Unicode data.
+ *
+ * If "len" is zero, we will return an empty string even if "unicodeChars"
+ * is NULL.  (The JNI spec is vague here.)
+ */
+static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
+    ScopedJniThreadState ts(env);
+    StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
+    if (jstr == NULL) {
+        return NULL;
+    }
+    dvmReleaseTrackedAlloc((Object*) jstr, NULL);
+    return (jstring) addLocalReference(ts.self(), (Object*) jstr);
+}
+
+/*
+ * Return the length of a String in Unicode character units.
+ */
+static jsize GetStringLength(JNIEnv* env, jstring jstr) {
+    ScopedJniThreadState ts(env);
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    return strObj->length();
+}
+
+
+/*
+ * Get a string's character data.
+ *
+ * The result is guaranteed to be valid until ReleaseStringChars is
+ * called, which means we have to pin it or return a copy.
+ */
+static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
+    ScopedJniThreadState ts(env);
+
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    ArrayObject* strChars = strObj->array();
+
+    pinPrimitiveArray(strChars);
+
+    const u2* data = strObj->chars();
+    if (isCopy != NULL) {
+        *isCopy = JNI_FALSE;
+    }
+    return (jchar*) data;
+}
+
+/*
+ * Release our grip on some characters from a string.
+ */
+static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
+    ScopedJniThreadState ts(env);
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    ArrayObject* strChars = strObj->array();
+    unpinPrimitiveArray(strChars);
+}
+
+/*
+ * Create a new java.lang.String object from chars in modified UTF-8 form.
+ *
+ * The spec doesn't say how to handle a NULL string.  Popular desktop VMs
+ * accept it and return a NULL pointer in response.
+ */
+static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
+    ScopedJniThreadState ts(env);
+    if (bytes == NULL) {
+        return NULL;
+    }
+    /* note newStr could come back NULL on OOM */
+    StringObject* newStr = dvmCreateStringFromCstr(bytes);
+    jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
+    dvmReleaseTrackedAlloc((Object*)newStr, NULL);
+    return result;
+}
+
+/*
+ * Return the length in bytes of the modified UTF-8 form of the string.
+ */
+static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
+    ScopedJniThreadState ts(env);
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    if (strObj == NULL) {
+        return 0; // Should we throw something or assert?
+    }
+    return strObj->utfLength();
+}
+
+/*
+ * Convert "string" to modified UTF-8 and return a pointer.  The returned
+ * value must be released with ReleaseStringUTFChars.
+ *
+ * According to the JNI reference, "Returns a pointer to a UTF-8 string,
+ * or NULL if the operation fails. Returns NULL if and only if an invocation
+ * of this function has thrown an exception."
+ *
+ * The behavior here currently follows that of other open-source VMs, which
+ * quietly return NULL if "string" is NULL.  We should consider throwing an
+ * NPE.  (The CheckJNI code blows up if you try to pass in a NULL string,
+ * which should catch this sort of thing during development.)  Certain other
+ * VMs will crash with a segmentation fault.
+ */
+static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
+    ScopedJniThreadState ts(env);
+    if (jstr == NULL) {
+        /* this shouldn't happen; throw NPE? */
+        return NULL;
+    }
+    if (isCopy != NULL) {
+        *isCopy = JNI_TRUE;
+    }
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    char* newStr = dvmCreateCstrFromString(strObj);
+    if (newStr == NULL) {
+        /* assume memory failure */
+        dvmThrowOutOfMemoryError("native heap string alloc failed");
+    }
+    return newStr;
+}
+
+/*
+ * Release a string created by GetStringUTFChars().
+ */
+static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
+    ScopedJniThreadState ts(env);
+    free((char*) utf);
+}
+
+/*
+ * Return the capacity of the array.
+ */
+static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
+    ScopedJniThreadState ts(env);
+    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
+    return arrObj->length;
+}
+
+/*
+ * Construct a new array that holds objects from class "elementClass".
+ */
+static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
+    jclass jelementClass, jobject jinitialElement)
+{
+    ScopedJniThreadState ts(env);
+
+    if (jelementClass == NULL) {
+        dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
+        return NULL;
+    }
+
+    ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
+    ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
+    ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
+    if (newObj == NULL) {
+        assert(dvmCheckException(ts.self()));
+        return NULL;
+    }
+    jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
+    dvmReleaseTrackedAlloc((Object*) newObj, NULL);
+
+    /*
+     * Initialize the array.
+     */
+    if (jinitialElement != NULL) {
+        Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
+        Object** arrayData = (Object**) (void*) newObj->contents;
+        for (jsize i = 0; i < length; ++i) {
+            arrayData[i] = initialElement;
+        }
+    }
+
+    return newArray;
+}
+
+static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
+    assert(arrayObj != NULL);
+    if (index < 0 || index >= (int) arrayObj->length) {
+        dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Get one element of an Object array.
+ *
+ * Add the object to the local references table in case the array goes away.
+ */
+static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
+    ScopedJniThreadState ts(env);
+
+    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
+    if (!checkArrayElementBounds(arrayObj, index)) {
+        return NULL;
+    }
+
+    Object* value = ((Object**) (void*) arrayObj->contents)[index];
+    return addLocalReference(ts.self(), value);
+}
+
+/*
+ * Set one element of an Object array.
+ */
+static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
+    ScopedJniThreadState ts(env);
+
+    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
+    if (!checkArrayElementBounds(arrayObj, index)) {
+        return;
+    }
+
+    //LOGV("JNI: set element %d in array %p to %p", index, array, value);
+
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    dvmSetObjectArrayElement(arrayObj, index, obj);
+}
+
+/*
+ * Create a new array of primitive elements.
+ */
+#define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
+    static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
+        ScopedJniThreadState ts(env); \
+        ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
+        if (arrayObj == NULL) { \
+            return NULL; \
+        } \
+        _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
+        dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
+        return result; \
+    }
+NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
+NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
+NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
+NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
+NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
+NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
+NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
+NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
+
+/*
+ * Get a pointer to a C array of primitive elements from an array object
+ * of the matching type.
+ *
+ * In a compacting GC, we either need to return a copy of the elements or
+ * "pin" the memory.  Otherwise we run the risk of native code using the
+ * buffer as the destination of e.g. a blocking read() call that wakes up
+ * during a GC.
+ */
+#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
+    static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
+        _ctype##Array jarr, jboolean* isCopy) \
+    { \
+        ScopedJniThreadState ts(env); \
+        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
+        pinPrimitiveArray(arrayObj); \
+        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
+        if (isCopy != NULL) { \
+            *isCopy = JNI_FALSE; \
+        } \
+        return data; \
+    }
+
+/*
+ * Release the storage locked down by the "get" function.
+ *
+ * The spec says, "'mode' has no effect if 'elems' is not a copy of the
+ * elements in 'array'."  They apparently did not anticipate the need to
+ * un-pin memory.
+ */
+#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
+    static void Release##_jname##ArrayElements(JNIEnv* env,                 \
+        _ctype##Array jarr, _ctype* elems, jint mode)                       \
+    {                                                                       \
+        UNUSED_PARAMETER(elems);                                            \
+        if (mode != JNI_COMMIT) {                                           \
+            ScopedJniThreadState ts(env);                                   \
+            ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
+            unpinPrimitiveArray(arrayObj);                                  \
+        }                                                                   \
+    }
+
+static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
+    jsize len, const char* arrayIdentifier)
+{
+    dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
+        "%s offset=%d length=%d %s.length=%d",
+        arrayObj->clazz->descriptor, start, len, arrayIdentifier,
+        arrayObj->length);
+}
+
+/*
+ * Copy a section of a primitive array to a buffer.
+ */
+#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
+    static void Get##_jname##ArrayRegion(JNIEnv* env, \
+        _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
+    { \
+        ScopedJniThreadState ts(env); \
+        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
+        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
+        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
+            throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
+        } else { \
+            memcpy(buf, data + start, len * sizeof(_ctype)); \
+        } \
+    }
+
+/*
+ * Copy a section of a primitive array from a buffer.
+ */
+#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
+    static void Set##_jname##ArrayRegion(JNIEnv* env, \
+        _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
+    { \
+        ScopedJniThreadState ts(env); \
+        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
+        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
+        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
+            throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
+        } else { \
+            memcpy(data + start, buf, len * sizeof(_ctype)); \
+        } \
+    }
+
+/*
+ * 4-in-1:
+ *  Get<Type>ArrayElements
+ *  Release<Type>ArrayElements
+ *  Get<Type>ArrayRegion
+ *  Set<Type>ArrayRegion
+ */
+#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
+    GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
+    RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
+    GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
+    SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
+
+PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
+PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
+PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
+PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
+PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
+PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
+PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
+PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
+
+/*
+ * Register one or more native functions in one class.
+ *
+ * This can be called multiple times on the same method, allowing the
+ * caller to redefine the method implementation at will.
+ */
+static jint RegisterNatives(JNIEnv* env, jclass jclazz,
+    const JNINativeMethod* methods, jint nMethods)
+{
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+
+    if (gDvm.verboseJni) {
+        LOGI("[Registering JNI native methods for class %s]",
+            clazz->descriptor);
+    }
+
+    for (int i = 0; i < nMethods; i++) {
+        if (!dvmRegisterJNIMethod(clazz, methods[i].name,
+                methods[i].signature, methods[i].fnPtr))
+        {
+            return JNI_ERR;
+        }
+    }
+    return JNI_OK;
+}
+
+/*
+ * Un-register all native methods associated with the class.
+ *
+ * The JNI docs refer to this as a way to reload/relink native libraries,
+ * and say it "should not be used in normal native code".  In particular,
+ * there is no need to do this during shutdown, and you do not need to do
+ * this before redefining a method implementation with RegisterNatives.
+ *
+ * It's chiefly useful for a native "plugin"-style library that wasn't
+ * loaded with System.loadLibrary() (since there's no way to unload those).
+ * For example, the library could upgrade itself by:
+ *
+ *  1. call UnregisterNatives to unbind the old methods
+ *  2. ensure that no code is still executing inside it (somehow)
+ *  3. dlclose() the library
+ *  4. dlopen() the new library
+ *  5. use RegisterNatives to bind the methods from the new library
+ *
+ * The above can work correctly without the UnregisterNatives call, but
+ * creates a window of opportunity in which somebody might try to call a
+ * method that is pointing at unmapped memory, crashing the VM.  In theory
+ * the same guards that prevent dlclose() from unmapping executing code could
+ * prevent that anyway, but with this we can be more thorough and also deal
+ * with methods that only exist in the old or new form of the library (maybe
+ * the lib wants to try the call and catch the UnsatisfiedLinkError).
+ */
+static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
+    ScopedJniThreadState ts(env);
+
+    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
+    if (gDvm.verboseJni) {
+        LOGI("[Unregistering JNI native methods for class %s]",
+            clazz->descriptor);
+    }
+    dvmUnregisterJNINativeMethods(clazz);
+    return JNI_OK;
+}
+
+/*
+ * Lock the monitor.
+ *
+ * We have to track all monitor enters and exits, so that we can undo any
+ * outstanding synchronization before the thread exits.
+ */
+static jint MonitorEnter(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    dvmLockObject(ts.self(), obj);
+    trackMonitorEnter(ts.self(), obj);
+    return JNI_OK;
+}
+
+/*
+ * Unlock the monitor.
+ *
+ * Throws an IllegalMonitorStateException if the current thread
+ * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
+ *
+ * According to the 1.6 spec, it's legal to call here with an exception
+ * pending.  If this fails, we'll stomp the original exception.
+ */
+static jint MonitorExit(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    bool success = dvmUnlockObject(ts.self(), obj);
+    if (success) {
+        trackMonitorExit(ts.self(), obj);
+    }
+    return success ? JNI_OK : JNI_ERR;
+}
+
+/*
+ * Return the JavaVM interface associated with the current thread.
+ */
+static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
+    ScopedJniThreadState ts(env);
+    *vm = gDvmJni.jniVm;
+    return (*vm == NULL) ? JNI_ERR : JNI_OK;
+}
+
+/*
+ * Copies "len" Unicode characters, from offset "start".
+ */
+static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
+    ScopedJniThreadState ts(env);
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    int strLen = strObj->length();
+    if (((start|len) < 0) || (start + len > strLen)) {
+        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
+        return;
+    }
+    memcpy(buf, strObj->chars() + start, len * sizeof(u2));
+}
+
+/*
+ * Translates "len" Unicode characters, from offset "start", into
+ * modified UTF-8 encoding.
+ */
+static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
+    ScopedJniThreadState ts(env);
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    int strLen = strObj->length();
+    if (((start|len) < 0) || (start + len > strLen)) {
+        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
+        return;
+    }
+    dvmGetStringUtfRegion(strObj, start, len, buf);
+}
+
+/*
+ * Get a raw pointer to array data.
+ *
+ * The caller is expected to call "release" before doing any JNI calls
+ * or blocking I/O operations.
+ *
+ * We need to pin the memory or block GC.
+ */
+static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
+    ScopedJniThreadState ts(env);
+    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
+    pinPrimitiveArray(arrayObj);
+    void* data = arrayObj->contents;
+    if (UNLIKELY(isCopy != NULL)) {
+        *isCopy = JNI_FALSE;
+    }
+    return data;
+}
+
+/*
+ * Release an array obtained with GetPrimitiveArrayCritical.
+ */
+static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
+    if (mode != JNI_COMMIT) {
+        ScopedJniThreadState ts(env);
+        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
+        unpinPrimitiveArray(arrayObj);
+    }
+}
+
+/*
+ * Like GetStringChars, but with restricted use.
+ */
+static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
+    ScopedJniThreadState ts(env);
+
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    ArrayObject* strChars = strObj->array();
+
+    pinPrimitiveArray(strChars);
+
+    const u2* data = strObj->chars();
+    if (isCopy != NULL) {
+        *isCopy = JNI_FALSE;
+    }
+    return (jchar*) data;
+}
+
+/*
+ * Like ReleaseStringChars, but with restricted use.
+ */
+static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
+    ScopedJniThreadState ts(env);
+    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
+    ArrayObject* strChars = strObj->array();
+    unpinPrimitiveArray(strChars);
+}
+
+/*
+ * Create a new weak global reference.
+ */
+static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+    Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
+    return (jweak) addWeakGlobalReference(obj);
+}
+
+/*
+ * Delete the specified weak global reference.
+ */
+static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
+    ScopedJniThreadState ts(env);
+    deleteWeakGlobalReference(wref);
+}
+
+/*
+ * Quick check for pending exceptions.
+ *
+ * TODO: we should be able to skip the enter/exit macros here.
+ */
+static jboolean ExceptionCheck(JNIEnv* env) {
+    ScopedJniThreadState ts(env);
+    return dvmCheckException(ts.self());
+}
+
+/*
+ * Returns the type of the object referred to by "obj".  It can be local,
+ * global, or weak global.
+ *
+ * In the current implementation, references can be global and local at
+ * the same time, so while the return value is accurate it may not tell
+ * the whole story.
+ */
+static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
+    ScopedJniThreadState ts(env);
+    return dvmGetJNIRefType(ts.self(), jobj);
+}
+
+/*
+ * Allocate and return a new java.nio.ByteBuffer for this block of memory.
+ *
+ * "address" may not be NULL, and "capacity" must be > 0.  (These are only
+ * verified when CheckJNI is enabled.)
+ */
+static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
+    ScopedJniThreadState ts(env);
+
+    /* create an instance of java.nio.ReadWriteDirectByteBuffer */
+    ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
+    if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
+        return NULL;
+    }
+    Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
+    if (newObj == NULL) {
+        return NULL;
+    }
+    /* call the constructor */
+    jobject result = addLocalReference(ts.self(), newObj);
+    JValue unused;
+    dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
+            newObj, &unused, (jint) address, (jint) capacity);
+    if (dvmGetException(ts.self()) != NULL) {
+        deleteLocalReference(ts.self(), result);
+        return NULL;
+    }
+    return result;
+}
+
+/*
+ * Get the starting address of the buffer for the specified java.nio.Buffer.
+ *
+ * If this is not a "direct" buffer, we return NULL.
+ */
+static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
+    ScopedJniThreadState ts(env);
+
+    // All Buffer objects have an effectiveDirectAddress field.
+    Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
+    return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
+}
+
+/*
+ * Get the capacity of the buffer for the specified java.nio.Buffer.
+ *
+ * Returns -1 if the object is not a direct buffer.  (We actually skip
+ * this check, since it's expensive to determine, and just return the
+ * capacity regardless.)
+ */
+static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
+    ScopedJniThreadState ts(env);
+
+    /*
+     * The capacity is always in the Buffer.capacity field.
+     *
+     * (The "check" version should verify that this is actually a Buffer,
+     * but we're not required to do so here.)
+     */
+    Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
+    return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
+}
+
+
+/*
+ * ===========================================================================
+ *      JNI invocation functions
+ * ===========================================================================
+ */
+
+/*
+ * Handle AttachCurrentThread{AsDaemon}.
+ *
+ * We need to make sure the VM is actually running.  For example, if we start
+ * up, issue an Attach, and the VM exits almost immediately, by the time the
+ * attaching happens the VM could already be shutting down.
+ *
+ * It's hard to avoid a race condition here because we don't want to hold
+ * a lock across the entire operation.  What we can do is temporarily
+ * increment the thread count to prevent a VM exit.
+ *
+ * This could potentially still have problems if a daemon thread calls here
+ * while the VM is shutting down.  dvmThreadSelf() will work, since it just
+ * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
+ * you shut down a VM while threads are still running inside it.
+ *
+ * Remember that some code may call this as a way to find the per-thread
+ * JNIEnv pointer.  Don't do excess work for that case.
+ */
+static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
+    JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
+
+    /*
+     * Return immediately if we're already one with the VM.
+     */
+    Thread* self = dvmThreadSelf();
+    if (self != NULL) {
+        *p_env = self->jniEnv;
+        return JNI_OK;
+    }
+
+    /*
+     * No threads allowed in zygote mode.
+     */
+    if (gDvm.zygote) {
+        return JNI_ERR;
+    }
+
+    /* increment the count to keep the VM from bailing while we run */
+    dvmLockThreadList(NULL);
+    if (gDvm.nonDaemonThreadCount == 0) {
+        // dead or dying
+        LOGV("Refusing to attach thread '%s' -- VM is shutting down",
+            (thr_args == NULL) ? "(unknown)" : args->name);
+        dvmUnlockThreadList();
+        return JNI_ERR;
+    }
+    gDvm.nonDaemonThreadCount++;
+    dvmUnlockThreadList();
+
+    /* tweak the JavaVMAttachArgs as needed */
+    JavaVMAttachArgs argsCopy;
+    if (args == NULL) {
+        /* allow the v1.1 calling convention */
+        argsCopy.version = JNI_VERSION_1_2;
+        argsCopy.name = NULL;
+        argsCopy.group = (jobject) dvmGetMainThreadGroup();
+    } else {
+        assert(args->version >= JNI_VERSION_1_2);
+
+        argsCopy.version = args->version;
+        argsCopy.name = args->name;
+        if (args->group != NULL) {
+            argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
+        } else {
+            argsCopy.group = (jobject) dvmGetMainThreadGroup();
+        }
+    }
+
+    bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
+
+    /* restore the count */
+    dvmLockThreadList(NULL);
+    gDvm.nonDaemonThreadCount--;
+    dvmUnlockThreadList();
+
+    /*
+     * Change the status to indicate that we're out in native code.  This
+     * call is not guarded with state-change macros, so we have to do it
+     * by hand.
+     */
+    if (result) {
+        self = dvmThreadSelf();
+        assert(self != NULL);
+        dvmChangeStatus(self, THREAD_NATIVE);
+        *p_env = self->jniEnv;
+        return JNI_OK;
+    } else {
+        return JNI_ERR;
+    }
+}
+
+/*
+ * Attach the current thread to the VM.  If the thread is already attached,
+ * this is a no-op.
+ */
+static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
+    return attachThread(vm, p_env, thr_args, false);
+}
+
+/*
+ * Like AttachCurrentThread, but set the "daemon" flag.
+ */
+static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
+{
+    return attachThread(vm, p_env, thr_args, true);
+}
+
+/*
+ * Dissociate the current thread from the VM.
+ */
+static jint DetachCurrentThread(JavaVM* vm) {
+    Thread* self = dvmThreadSelf();
+    if (self == NULL) {
+        /* not attached, can't do anything */
+        return JNI_ERR;
+    }
+
+    /* switch to "running" to check for suspension */
+    dvmChangeStatus(self, THREAD_RUNNING);
+
+    /* detach the thread */
+    dvmDetachCurrentThread();
+
+    /* (no need to change status back -- we have no status) */
+    return JNI_OK;
+}
+
+/*
+ * If current thread is attached to VM, return the associated JNIEnv.
+ * Otherwise, stuff NULL in and return JNI_EDETACHED.
+ *
+ * JVMTI overloads this by specifying a magic value for "version", so we
+ * do want to check that here.
+ */
+static jint GetEnv(JavaVM* vm, void** env, jint version) {
+    Thread* self = dvmThreadSelf();
+
+    if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
+        return JNI_EVERSION;
+    }
+
+    if (self == NULL) {
+        *env = NULL;
+    } else {
+        /* TODO: status change is probably unnecessary */
+        dvmChangeStatus(self, THREAD_RUNNING);
+        *env = (void*) dvmGetThreadJNIEnv(self);
+        dvmChangeStatus(self, THREAD_NATIVE);
+    }
+    return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
+}
+
+/*
+ * Destroy the VM.  This may be called from any thread.
+ *
+ * If the current thread is attached, wait until the current thread is
+ * the only non-daemon user-level thread.  If the current thread is not
+ * attached, we attach it and do the processing as usual.  (If the attach
+ * fails, it's probably because all the non-daemon threads have already
+ * exited and the VM doesn't want to let us back in.)
+ *
+ * TODO: we don't really deal with the situation where more than one thread
+ * has called here.  One thread wins, the other stays trapped waiting on
+ * the condition variable forever.  Not sure this situation is interesting
+ * in real life.
+ */
+static jint DestroyJavaVM(JavaVM* vm) {
+    JavaVMExt* ext = (JavaVMExt*) vm;
+    if (ext == NULL) {
+        return JNI_ERR;
+    }
+
+    if (gDvm.verboseShutdown) {
+        LOGD("DestroyJavaVM waiting for non-daemon threads to exit");
+    }
+
+    /*
+     * Sleep on a condition variable until it's okay to exit.
+     */
+    Thread* self = dvmThreadSelf();
+    if (self == NULL) {
+        JNIEnv* tmpEnv;
+        if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
+            LOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
+                gDvm.nonDaemonThreadCount);
+            goto shutdown;
+        } else {
+            LOGV("Attached to wait for shutdown in Destroy");
+        }
+    }
+    dvmChangeStatus(self, THREAD_VMWAIT);
+
+    dvmLockThreadList(self);
+    gDvm.nonDaemonThreadCount--;    // remove current thread from count
+
+    while (gDvm.nonDaemonThreadCount > 0) {
+        pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
+    }
+
+    dvmUnlockThreadList();
+    self = NULL;
+
+shutdown:
+    // TODO: call System.exit() to run any registered shutdown hooks
+    // (this may not return -- figure out how this should work)
+
+    if (gDvm.verboseShutdown) {
+        LOGD("DestroyJavaVM shutting VM down");
+    }
+    dvmShutdown();
+
+    // TODO - free resources associated with JNI-attached daemon threads
+    free(ext->envList);
+    free(ext);
+
+    return JNI_OK;
+}
+
+
+/*
+ * ===========================================================================
+ *      Function tables
+ * ===========================================================================
+ */
+
+static const struct JNINativeInterface gNativeInterface = {
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+
+    GetVersion,
+
+    DefineClass,
+    FindClass,
+
+    FromReflectedMethod,
+    FromReflectedField,
+    ToReflectedMethod,
+
+    GetSuperclass,
+    IsAssignableFrom,
+
+    ToReflectedField,
+
+    Throw,
+    ThrowNew,
+    ExceptionOccurred,
+    ExceptionDescribe,
+    ExceptionClear,
+    FatalError,
+
+    PushLocalFrame,
+    PopLocalFrame,
+
+    NewGlobalRef,
+    DeleteGlobalRef,
+    DeleteLocalRef,
+    IsSameObject,
+    NewLocalRef,
+    EnsureLocalCapacity,
+
+    AllocObject,
+    NewObject,
+    NewObjectV,
+    NewObjectA,
+
+    GetObjectClass,
+    IsInstanceOf,
+
+    GetMethodID,
+
+    CallObjectMethod,
+    CallObjectMethodV,
+    CallObjectMethodA,
+    CallBooleanMethod,
+    CallBooleanMethodV,
+    CallBooleanMethodA,
+    CallByteMethod,
+    CallByteMethodV,
+    CallByteMethodA,
+    CallCharMethod,
+    CallCharMethodV,
+    CallCharMethodA,
+    CallShortMethod,
+    CallShortMethodV,
+    CallShortMethodA,
+    CallIntMethod,
+    CallIntMethodV,
+    CallIntMethodA,
+    CallLongMethod,
+    CallLongMethodV,
+    CallLongMethodA,
+    CallFloatMethod,
+    CallFloatMethodV,
+    CallFloatMethodA,
+    CallDoubleMethod,
+    CallDoubleMethodV,
+    CallDoubleMethodA,
+    CallVoidMethod,
+    CallVoidMethodV,
+    CallVoidMethodA,
+
+    CallNonvirtualObjectMethod,
+    CallNonvirtualObjectMethodV,
+    CallNonvirtualObjectMethodA,
+    CallNonvirtualBooleanMethod,
+    CallNonvirtualBooleanMethodV,
+    CallNonvirtualBooleanMethodA,
+    CallNonvirtualByteMethod,
+    CallNonvirtualByteMethodV,
+    CallNonvirtualByteMethodA,
+    CallNonvirtualCharMethod,
+    CallNonvirtualCharMethodV,
+    CallNonvirtualCharMethodA,
+    CallNonvirtualShortMethod,
+    CallNonvirtualShortMethodV,
+    CallNonvirtualShortMethodA,
+    CallNonvirtualIntMethod,
+    CallNonvirtualIntMethodV,
+    CallNonvirtualIntMethodA,
+    CallNonvirtualLongMethod,
+    CallNonvirtualLongMethodV,
+    CallNonvirtualLongMethodA,
+    CallNonvirtualFloatMethod,
+    CallNonvirtualFloatMethodV,
+    CallNonvirtualFloatMethodA,
+    CallNonvirtualDoubleMethod,
+    CallNonvirtualDoubleMethodV,
+    CallNonvirtualDoubleMethodA,
+    CallNonvirtualVoidMethod,
+    CallNonvirtualVoidMethodV,
+    CallNonvirtualVoidMethodA,
+
+    GetFieldID,
+
+    GetObjectField,
+    GetBooleanField,
+    GetByteField,
+    GetCharField,
+    GetShortField,
+    GetIntField,
+    GetLongField,
+    GetFloatField,
+    GetDoubleField,
+    SetObjectField,
+    SetBooleanField,
+    SetByteField,
+    SetCharField,
+    SetShortField,
+    SetIntField,
+    SetLongField,
+    SetFloatField,
+    SetDoubleField,
+
+    GetStaticMethodID,
+
+    CallStaticObjectMethod,
+    CallStaticObjectMethodV,
+    CallStaticObjectMethodA,
+    CallStaticBooleanMethod,
+    CallStaticBooleanMethodV,
+    CallStaticBooleanMethodA,
+    CallStaticByteMethod,
+    CallStaticByteMethodV,
+    CallStaticByteMethodA,
+    CallStaticCharMethod,
+    CallStaticCharMethodV,
+    CallStaticCharMethodA,
+    CallStaticShortMethod,
+    CallStaticShortMethodV,
+    CallStaticShortMethodA,
+    CallStaticIntMethod,
+    CallStaticIntMethodV,
+    CallStaticIntMethodA,
+    CallStaticLongMethod,
+    CallStaticLongMethodV,
+    CallStaticLongMethodA,
+    CallStaticFloatMethod,
+    CallStaticFloatMethodV,
+    CallStaticFloatMethodA,
+    CallStaticDoubleMethod,
+    CallStaticDoubleMethodV,
+    CallStaticDoubleMethodA,
+    CallStaticVoidMethod,
+    CallStaticVoidMethodV,
+    CallStaticVoidMethodA,
+
+    GetStaticFieldID,
+
+    GetStaticObjectField,
+    GetStaticBooleanField,
+    GetStaticByteField,
+    GetStaticCharField,
+    GetStaticShortField,
+    GetStaticIntField,
+    GetStaticLongField,
+    GetStaticFloatField,
+    GetStaticDoubleField,
+
+    SetStaticObjectField,
+    SetStaticBooleanField,
+    SetStaticByteField,
+    SetStaticCharField,
+    SetStaticShortField,
+    SetStaticIntField,
+    SetStaticLongField,
+    SetStaticFloatField,
+    SetStaticDoubleField,
+
+    NewString,
+
+    GetStringLength,
+    GetStringChars,
+    ReleaseStringChars,
+
+    NewStringUTF,
+    GetStringUTFLength,
+    GetStringUTFChars,
+    ReleaseStringUTFChars,
+
+    GetArrayLength,
+    NewObjectArray,
+    GetObjectArrayElement,
+    SetObjectArrayElement,
+
+    NewBooleanArray,
+    NewByteArray,
+    NewCharArray,
+    NewShortArray,
+    NewIntArray,
+    NewLongArray,
+    NewFloatArray,
+    NewDoubleArray,
+
+    GetBooleanArrayElements,
+    GetByteArrayElements,
+    GetCharArrayElements,
+    GetShortArrayElements,
+    GetIntArrayElements,
+    GetLongArrayElements,
+    GetFloatArrayElements,
+    GetDoubleArrayElements,
+
+    ReleaseBooleanArrayElements,
+    ReleaseByteArrayElements,
+    ReleaseCharArrayElements,
+    ReleaseShortArrayElements,
+    ReleaseIntArrayElements,
+    ReleaseLongArrayElements,
+    ReleaseFloatArrayElements,
+    ReleaseDoubleArrayElements,
+
+    GetBooleanArrayRegion,
+    GetByteArrayRegion,
+    GetCharArrayRegion,
+    GetShortArrayRegion,
+    GetIntArrayRegion,
+    GetLongArrayRegion,
+    GetFloatArrayRegion,
+    GetDoubleArrayRegion,
+    SetBooleanArrayRegion,
+    SetByteArrayRegion,
+    SetCharArrayRegion,
+    SetShortArrayRegion,
+    SetIntArrayRegion,
+    SetLongArrayRegion,
+    SetFloatArrayRegion,
+    SetDoubleArrayRegion,
+
+    RegisterNatives,
+    UnregisterNatives,
+
+    MonitorEnter,
+    MonitorExit,
+
+    GetJavaVM,
+
+    GetStringRegion,
+    GetStringUTFRegion,
+
+    GetPrimitiveArrayCritical,
+    ReleasePrimitiveArrayCritical,
+
+    GetStringCritical,
+    ReleaseStringCritical,
+
+    NewWeakGlobalRef,
+    DeleteWeakGlobalRef,
+
+    ExceptionCheck,
+
+    NewDirectByteBuffer,
+    GetDirectBufferAddress,
+    GetDirectBufferCapacity,
+
+    GetObjectRefType
+};
+
+static const struct JNIInvokeInterface gInvokeInterface = {
+    NULL,
+    NULL,
+    NULL,
+
+    DestroyJavaVM,
+    AttachCurrentThread,
+    DetachCurrentThread,
+
+    GetEnv,
+
+    AttachCurrentThreadAsDaemon,
+};
+
+/*
+ * ===========================================================================
+ *      VM/Env creation
+ * ===========================================================================
+ */
+
+/*
+ * Create a new JNIEnv struct and add it to the VM's list.
+ *
+ * "self" will be NULL for the main thread, since the VM hasn't started
+ * yet; the value will be filled in later.
+ */
+JNIEnv* dvmCreateJNIEnv(Thread* self) {
+    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
+
+    //if (self != NULL)
+    //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
+
+    assert(vm != NULL);
+
+    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
+    newEnv->funcTable = &gNativeInterface;
+    if (self != NULL) {
+        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
+        assert(newEnv->envThreadId != 0);
+    } else {
+        /* make it obvious if we fail to initialize these later */
+        newEnv->envThreadId = 0x77777775;
+        newEnv->self = (Thread*) 0x77777779;
+    }
+    if (gDvmJni.useCheckJni) {
+        dvmUseCheckedJniEnv(newEnv);
+    }
+
+    ScopedPthreadMutexLock lock(&vm->envListLock);
+
+    /* insert at head of list */
+    newEnv->next = vm->envList;
+    assert(newEnv->prev == NULL);
+    if (vm->envList == NULL) {
+        // rare, but possible
+        vm->envList = newEnv;
+    } else {
+        vm->envList->prev = newEnv;
+    }
+    vm->envList = newEnv;
+
+    //if (self != NULL)
+    //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
+    return (JNIEnv*) newEnv;
+}
+
+/*
+ * Remove a JNIEnv struct from the list and free it.
+ */
+void dvmDestroyJNIEnv(JNIEnv* env) {
+    if (env == NULL) {
+        return;
+    }
+
+    //LOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
+
+    JNIEnvExt* extEnv = (JNIEnvExt*) env;
+    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
+
+    ScopedPthreadMutexLock lock(&vm->envListLock);
+
+    if (extEnv == vm->envList) {
+        assert(extEnv->prev == NULL);
+        vm->envList = extEnv->next;
+    } else {
+        assert(extEnv->prev != NULL);
+        extEnv->prev->next = extEnv->next;
+    }
+    if (extEnv->next != NULL) {
+        extEnv->next->prev = extEnv->prev;
+    }
+
+    free(env);
+    //LOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
+}
+
+/*
+ * 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() {
+    JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
+    if (extEnv == NULL) {
+        LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
+        return;
+    }
+    JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
+    assert(extVm != NULL);
+
+    if (!gDvmJni.useCheckJni) {
+        LOGD("Late-enabling CheckJNI");
+        dvmUseCheckedJniVm(extVm);
+        dvmUseCheckedJniEnv(extEnv);
+    } else {
+        LOGD("Not late-enabling CheckJNI (already on)");
+    }
+}
+
+/*
+ * Not supported.
+ */
+jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
+    return JNI_ERR;
+}
+
+/*
+ * Return a buffer full of created VMs.
+ *
+ * We always have zero or one.
+ */
+jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
+    if (gDvmJni.jniVm != NULL) {
+        *nVMs = 1;
+        if (bufLen > 0) {
+            *vmBuf++ = gDvmJni.jniVm;
+        }
+    } else {
+        *nVMs = 0;
+    }
+    return JNI_OK;
+}
+
+/*
+ * Create a new VM instance.
+ *
+ * The current thread becomes the main VM thread.  We return immediately,
+ * which effectively means the caller is executing in a native method.
+ */
+jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
+    const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
+    if (args->version < JNI_VERSION_1_2) {
+        return JNI_EVERSION;
+    }
+
+    // TODO: don't allow creation of multiple VMs -- one per customer for now
+
+    /* zero globals; not strictly necessary the first time a VM is started */
+    memset(&gDvm, 0, sizeof(gDvm));
+
+    /*
+     * Set up structures for JNIEnv and VM.
+     */
+    JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
+    memset(pVM, 0, sizeof(JavaVMExt));
+    pVM->funcTable = &gInvokeInterface;
+    pVM->envList = NULL;
+    dvmInitMutex(&pVM->envListLock);
+
+    UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
+    memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
+
+    /*
+     * Convert JNI args to argv.
+     *
+     * We have to pull out vfprintf/exit/abort, because they use the
+     * "extraInfo" field to pass function pointer "hooks" in.  We also
+     * look for the -Xcheck:jni stuff here.
+     */
+    int argc = 0;
+    for (int i = 0; i < args->nOptions; i++) {
+        const char* optStr = args->options[i].optionString;
+        if (optStr == NULL) {
+            dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
+            return JNI_ERR;
+        } else if (strcmp(optStr, "vfprintf") == 0) {
+            gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
+        } else if (strcmp(optStr, "exit") == 0) {
+            gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
+        } else if (strcmp(optStr, "abort") == 0) {
+            gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
+        } else if (strcmp(optStr, "sensitiveThread") == 0) {
+            gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
+        } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
+            gDvmJni.useCheckJni = true;
+        } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
+            char* jniOpts = strdup(optStr + 10);
+            size_t jniOptCount = 1;
+            for (char* p = jniOpts; *p != 0; ++p) {
+                if (*p == ',') {
+                    ++jniOptCount;
+                    *p = 0;
+                }
+            }
+            char* jniOpt = jniOpts;
+            for (size_t i = 0; i < jniOptCount; ++i) {
+                if (strcmp(jniOpt, "warnonly") == 0) {
+                    gDvmJni.warnOnly = true;
+                } else if (strcmp(jniOpt, "forcecopy") == 0) {
+                    gDvmJni.forceCopy = true;
+                } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
+                    gDvmJni.logThirdPartyJni = true;
+                } else {
+                    dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
+                            jniOpt);
+                    return JNI_ERR;
+                }
+                jniOpt += strlen(jniOpt) + 1;
+            }
+            free(jniOpts);
+        } else {
+            /* regular option */
+            argv[argc++] = optStr;
+        }
+    }
+
+    if (gDvmJni.useCheckJni) {
+        dvmUseCheckedJniVm(pVM);
+    }
+
+    if (gDvmJni.jniVm != NULL) {
+        dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
+        return JNI_ERR;
+    }
+    gDvmJni.jniVm = (JavaVM*) pVM;
+
+    /*
+     * Create a JNIEnv for the main thread.  We need to have something set up
+     * here because some of the class initialization we do when starting
+     * up the VM will call into native code.
+     */
+    JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
+
+    /* Initialize VM. */
+    gDvm.initializing = true;
+    std::string status =
+            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
+    gDvm.initializing = false;
+
+    if (!status.empty()) {
+        free(pEnv);
+        free(pVM);
+        LOGW("CreateJavaVM failed: %s", status.c_str());
+        return JNI_ERR;
+    }
+
+    /*
+     * Success!  Return stuff to caller.
+     */
+    dvmChangeStatus(NULL, THREAD_NATIVE);
+    *p_env = (JNIEnv*) pEnv;
+    *p_vm = (JavaVM*) pVM;
+    LOGV("CreateJavaVM succeeded");
+    return JNI_OK;
+}
diff --git a/vm/JniInternal.h b/vm/JniInternal.h
new file mode 100644
index 0000000..df92df6
--- /dev/null
+++ b/vm/JniInternal.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+/*
+ * JNI innards, common to the regular and "checked" interfaces.
+ */
+#ifndef DALVIK_JNIINTERNAL_H_
+#define DALVIK_JNIINTERNAL_H_
+
+#include "jni.h"
+
+/* system init/shutdown */
+bool dvmJniStartup(void);
+void dvmJniShutdown(void);
+
+/*
+ * Our data structures for JNIEnv and JavaVM.
+ *
+ * Native code thinks it has a pointer to a pointer.  We know better.
+ */
+struct JavaVMExt;
+
+struct JNIEnvExt {
+    const struct JNINativeInterface* funcTable;     /* must be first */
+
+    const struct JNINativeInterface* baseFuncTable;
+
+    u4      envThreadId;
+    Thread* self;
+
+    /* if nonzero, we are in a "critical" JNI call */
+    int     critical;
+
+    struct JNIEnvExt* prev;
+    struct JNIEnvExt* next;
+};
+
+struct JavaVMExt {
+    const struct JNIInvokeInterface* funcTable;     /* must be first */
+
+    const struct JNIInvokeInterface* baseFuncTable;
+
+    /* head of list of JNIEnvs associated with this VM */
+    JNIEnvExt*      envList;
+    pthread_mutex_t envListLock;
+};
+
+/*
+ * Native function return type; used by dvmPlatformInvoke().
+ *
+ * This is part of Method.jniArgInfo, and must fit in 3 bits.
+ * Note: Assembly code in arch/<arch>/Call<arch>.S relies on
+ * the enum values defined here.
+ */
+enum DalvikJniReturnType {
+    DALVIK_JNI_RETURN_VOID = 0,     /* must be zero */
+    DALVIK_JNI_RETURN_FLOAT = 1,
+    DALVIK_JNI_RETURN_DOUBLE = 2,
+    DALVIK_JNI_RETURN_S8 = 3,
+    DALVIK_JNI_RETURN_S4 = 4,
+    DALVIK_JNI_RETURN_S2 = 5,
+    DALVIK_JNI_RETURN_U2 = 6,
+    DALVIK_JNI_RETURN_S1 = 7
+};
+
+#define DALVIK_JNI_NO_ARG_INFO  0x80000000
+#define DALVIK_JNI_RETURN_MASK  0x70000000
+#define DALVIK_JNI_RETURN_SHIFT 28
+#define DALVIK_JNI_COUNT_MASK   0x0f000000
+#define DALVIK_JNI_COUNT_SHIFT  24
+
+
+/*
+ * Pop the JNI local stack when we return from a native method.  "saveArea"
+ * points to the StackSaveArea for the method we're leaving.
+ *
+ * (This may be implemented directly in assembly in mterp, so changes here
+ * may only affect the portable interpreter.)
+ */
+INLINE void dvmPopJniLocals(Thread* self, StackSaveArea* saveArea)
+{
+    self->jniLocalRefTable.segmentState.all = saveArea->xtra.localRefCookie;
+}
+
+/*
+ * Set the envThreadId field.
+ */
+INLINE void dvmSetJniEnvThreadId(JNIEnv* pEnv, Thread* self)
+{
+    ((JNIEnvExt*)pEnv)->envThreadId = self->threadId;
+    ((JNIEnvExt*)pEnv)->self = self;
+}
+
+void dvmCallJNIMethod(const u4* args, JValue* pResult,
+    const Method* method, Thread* self);
+void dvmCheckCallJNIMethod(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.
+ */
+void dvmUseCheckedJniEnv(JNIEnvExt* pEnv);
+void dvmUseCheckedJniVm(JavaVMExt* pVm);
+void dvmLateEnableCheckedJni(void);
+
+/*
+ * Decode a local, global, or weak-global reference.
+ */
+Object* dvmDecodeIndirectRef(Thread* self, jobject jobj);
+
+/*
+ * Verify that a reference passed in from native code is valid.  Returns
+ * an indication of local/global/invalid.
+ */
+jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj);
+
+/*
+ * Get the last method called on the interp stack.  This is the method
+ * "responsible" for calling into JNI.
+ */
+const Method* dvmGetCurrentJNIMethod(void);
+
+/*
+ * Create/destroy a JNIEnv for the current thread.
+ */
+JNIEnv* dvmCreateJNIEnv(Thread* self);
+void dvmDestroyJNIEnv(JNIEnv* env);
+
+/*
+ * Find the JNIEnv associated with the current thread.
+ */
+JNIEnvExt* dvmGetJNIEnvForThread(void);
+
+/*
+ * Release all MonitorEnter-acquired locks that are still held.  Called at
+ * DetachCurrentThread time.
+ */
+void dvmReleaseJniMonitors(Thread* self);
+
+/*
+ * Dump the contents of the JNI reference tables to the log file.
+ *
+ * The local ref tables associated with other threads are not included.
+ */
+void dvmDumpJniReferenceTables(void);
+
+#endif  // DALVIK_JNIINTERNAL_H_
diff --git a/vm/LinearAlloc.cpp b/vm/LinearAlloc.cpp
new file mode 100644
index 0000000..5a99e6d
--- /dev/null
+++ b/vm/LinearAlloc.cpp
@@ -0,0 +1,704 @@
+/*
+ * 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.
+ */
+
+/*
+ * Linear memory allocation, tied to class loaders.
+ */
+#include "Dalvik.h"
+
+#include <sys/mman.h>
+#include <limits.h>
+#include <errno.h>
+
+//#define DISABLE_LINEAR_ALLOC
+
+// Use ashmem to name the LinearAlloc section
+#define USE_ASHMEM 1
+
+#ifdef USE_ASHMEM
+#include <cutils/ashmem.h>
+#endif /* USE_ASHMEM */
+
+/*
+Overview
+
+This is intended to be a simple, fast allocator for "write-once" storage.
+The expectation is that this will hold small allocations that don't change,
+such as parts of classes (vtables, fields, methods, interfaces).  Because
+the lifetime of these items is tied to classes, which in turn are tied
+to class loaders, we associate the storage with a ClassLoader object.
+
+[ We don't yet support class unloading, and our ClassLoader implementation
+is in flux, so for now we just have a single global region and the
+"classLoader" argument is ignored. ]
+
+By storing the data here, rather than on the system heap, we reduce heap
+clutter, speed class loading, reduce the memory footprint (reduced heap
+structure overhead), and most importantly we increase the number of pages
+that remain shared between processes launched in "Zygote mode".
+
+The 4 bytes preceding each block contain the block length.  This allows us
+to support "free" and "realloc" calls in a limited way.  We don't free
+storage once it has been allocated, but in some circumstances it could be
+useful to erase storage to garbage values after a "free" or "realloc".
+(Bad idea if we're trying to share pages.)  We need to align to 8-byte
+boundaries for some architectures, so we have a 50-50 chance of getting
+this for free in a given block.
+
+A NULL value for the "classLoader" argument refers to the bootstrap class
+loader, which is never unloaded (until the VM shuts down).
+
+Because the memory is not expected to be updated, we can use mprotect to
+guard the pages on debug builds.  Handy when tracking down corruption.
+*/
+
+/* alignment for allocations; must be power of 2, and currently >= hdr_xtra */
+#define BLOCK_ALIGN         8
+
+/* default length of memory segment (worst case is probably "dexopt") */
+#define DEFAULT_MAX_LENGTH  (8*1024*1024)
+
+/* leave enough space for a length word */
+#define HEADER_EXTRA        4
+
+/* overload the length word */
+#define LENGTHFLAG_FREE    0x80000000
+#define LENGTHFLAG_RW      0x40000000
+#define LENGTHFLAG_MASK    (~(LENGTHFLAG_FREE|LENGTHFLAG_RW))
+
+
+/* fwd */
+static void checkAllFree(Object* classLoader);
+
+
+/*
+ * Someday, retrieve the linear alloc struct associated with a particular
+ * class loader.  For now, always use the boostrap loader's instance.
+ */
+static inline LinearAllocHdr* getHeader(Object* classLoader)
+{
+    return gDvm.pBootLoaderAlloc;
+}
+
+/*
+ * Convert a pointer to memory to a pointer to the block header (which is
+ * currently just a length word).
+ */
+static inline u4* getBlockHeader(void* mem)
+{
+    return ((u4*) mem) -1;
+}
+
+/*
+ * Create a new linear allocation block.
+ */
+LinearAllocHdr* dvmLinearAllocCreate(Object* classLoader)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return (LinearAllocHdr*) 0x12345;
+#endif
+    LinearAllocHdr* pHdr;
+
+    pHdr = (LinearAllocHdr*) malloc(sizeof(*pHdr));
+
+
+    /*
+     * "curOffset" points to the location of the next pre-block header,
+     * which means we have to advance to the next BLOCK_ALIGN address and
+     * back up.
+     *
+     * Note we leave the first page empty (see below), and start the
+     * first entry on the second page at an offset that ensures the next
+     * chunk of data will be properly aligned.
+     */
+    assert(BLOCK_ALIGN >= HEADER_EXTRA);
+    pHdr->curOffset = pHdr->firstOffset =
+        (BLOCK_ALIGN-HEADER_EXTRA) + SYSTEM_PAGE_SIZE;
+    pHdr->mapLength = DEFAULT_MAX_LENGTH;
+
+#ifdef USE_ASHMEM
+    int fd;
+
+    fd = ashmem_create_region("dalvik-LinearAlloc", DEFAULT_MAX_LENGTH);
+    if (fd < 0) {
+        LOGE("ashmem LinearAlloc failed %s", strerror(errno));
+        free(pHdr);
+        return NULL;
+    }
+
+    pHdr->mapAddr = (char*)mmap(NULL, pHdr->mapLength, PROT_READ | PROT_WRITE,
+        MAP_PRIVATE, fd, 0);
+    if (pHdr->mapAddr == MAP_FAILED) {
+        LOGE("LinearAlloc mmap(%d) failed: %s", pHdr->mapLength,
+            strerror(errno));
+        free(pHdr);
+        close(fd);
+        return NULL;
+    }
+
+    close(fd);
+#else /*USE_ASHMEM*/
+    // MAP_ANON is listed as "deprecated" on Linux,
+    // but MAP_ANONYMOUS is not defined under Mac OS X.
+    pHdr->mapAddr = mmap(NULL, pHdr->mapLength, PROT_READ | PROT_WRITE,
+        MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (pHdr->mapAddr == MAP_FAILED) {
+        LOGE("LinearAlloc mmap(%d) failed: %s", pHdr->mapLength,
+            strerror(errno));
+        free(pHdr);
+        return NULL;
+    }
+#endif /*USE_ASHMEM*/
+
+    /* region expected to begin on a page boundary */
+    assert(((int) pHdr->mapAddr & (SYSTEM_PAGE_SIZE-1)) == 0);
+
+    /* the system should initialize newly-mapped memory to zero */
+    assert(*(u4*) (pHdr->mapAddr + pHdr->curOffset) == 0);
+
+    /*
+     * Disable access to all except starting page.  We will enable pages
+     * as we use them.  This helps prevent bad pointers from working.  The
+     * pages start out PROT_NONE, become read/write while we access them,
+     * then go to read-only after we finish our changes.
+     *
+     * We have to make the first page readable because we have 4 pad bytes,
+     * followed by 4 length bytes, giving an initial offset of 8.  The
+     * generic code below assumes that there could have been a previous
+     * allocation that wrote into those 4 pad bytes, therefore the page
+     * must have been marked readable by the previous allocation.
+     *
+     * We insert an extra page in here to force a break in the memory map
+     * so we can see ourselves more easily in "showmap".  Otherwise this
+     * stuff blends into the neighboring pages.  [TODO: do we still need
+     * the extra page now that we have ashmem?]
+     */
+    if (mprotect(pHdr->mapAddr, pHdr->mapLength, PROT_NONE) != 0) {
+        LOGW("LinearAlloc init mprotect failed: %s", strerror(errno));
+        free(pHdr);
+        return NULL;
+    }
+    if (mprotect(pHdr->mapAddr + SYSTEM_PAGE_SIZE, SYSTEM_PAGE_SIZE,
+            ENFORCE_READ_ONLY ? PROT_READ : PROT_READ|PROT_WRITE) != 0)
+    {
+        LOGW("LinearAlloc init mprotect #2 failed: %s", strerror(errno));
+        free(pHdr);
+        return NULL;
+    }
+
+    if (ENFORCE_READ_ONLY) {
+        /* allocate the per-page ref count */
+        int numPages = (pHdr->mapLength+SYSTEM_PAGE_SIZE-1) / SYSTEM_PAGE_SIZE;
+        pHdr->writeRefCount = (short*)calloc(numPages, sizeof(short));
+        if (pHdr->writeRefCount == NULL) {
+            free(pHdr);
+            return NULL;
+        }
+    }
+
+    dvmInitMutex(&pHdr->lock);
+
+    LOGV("LinearAlloc: created region at %p-%p",
+        pHdr->mapAddr, pHdr->mapAddr + pHdr->mapLength-1);
+
+    return pHdr;
+}
+
+/*
+ * Destroy a linear allocation area.
+ *
+ * We do a trivial "has everything been freed?" check before unmapping the
+ * memory and freeing the LinearAllocHdr.
+ */
+void dvmLinearAllocDestroy(Object* classLoader)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return;
+#endif
+    LinearAllocHdr* pHdr = getHeader(classLoader);
+    if (pHdr == NULL)
+        return;
+
+    checkAllFree(classLoader);
+
+    //dvmLinearAllocDump(classLoader);
+
+    if (gDvm.verboseShutdown) {
+        LOGV("Unmapping linear allocator base=%p", pHdr->mapAddr);
+        LOGD("LinearAlloc %p used %d of %d (%d%%)",
+            classLoader, pHdr->curOffset, pHdr->mapLength,
+            (pHdr->curOffset * 100) / pHdr->mapLength);
+    }
+
+    if (munmap(pHdr->mapAddr, pHdr->mapLength) != 0) {
+        LOGW("LinearAlloc munmap(%p, %d) failed: %s",
+            pHdr->mapAddr, pHdr->mapLength, strerror(errno));
+    }
+    free(pHdr);
+}
+
+/*
+ * Allocate "size" bytes of storage, associated with a particular class
+ * loader.
+ *
+ * It's okay for size to be zero.
+ *
+ * We always leave "curOffset" pointing at the next place where we will
+ * store the header that precedes the returned storage.
+ *
+ * This aborts the VM on failure, so it's not necessary to check for a
+ * NULL return value.
+ */
+void* dvmLinearAlloc(Object* classLoader, size_t size)
+{
+    LinearAllocHdr* pHdr = getHeader(classLoader);
+    int startOffset, nextOffset;
+    int lastGoodOff, firstWriteOff, lastWriteOff;
+
+#ifdef DISABLE_LINEAR_ALLOC
+    return calloc(1, size);
+#endif
+
+    LOGVV("--- LinearAlloc(%p, %d)", classLoader, size);
+
+    /*
+     * What we'd like to do is just determine the new end-of-alloc size
+     * and atomic-swap the updated value in.  The trouble is that, the
+     * first time we reach a new page, we need to call mprotect() to
+     * make the page available, and we don't want to call mprotect() on
+     * every allocation.  The troubled situation is:
+     *  - thread A allocs across a page boundary, but gets preempted
+     *    before mprotect() completes
+     *  - thread B allocs within the new page, and doesn't call mprotect()
+     */
+    dvmLockMutex(&pHdr->lock);
+
+    startOffset = pHdr->curOffset;
+    assert(((startOffset + HEADER_EXTRA) & (BLOCK_ALIGN-1)) == 0);
+
+    /*
+     * Compute the new offset.  The old offset points at the address where
+     * we will store the hidden block header, so we advance past that,
+     * add the size of data they want, add another header's worth so we
+     * know we have room for that, and round up to BLOCK_ALIGN.  That's
+     * the next location where we'll put user data.  We then subtract the
+     * chunk header size off so we're back to the header pointer.
+     *
+     * Examples:
+     *   old=12 size=3 new=((12+(4*2)+3+7) & ~7)-4 = 24-4 --> 20
+     *   old=12 size=5 new=((12+(4*2)+5+7) & ~7)-4 = 32-4 --> 28
+     */
+    nextOffset = ((startOffset + HEADER_EXTRA*2 + size + (BLOCK_ALIGN-1))
+                    & ~(BLOCK_ALIGN-1)) - HEADER_EXTRA;
+    LOGVV("--- old=%d size=%d new=%d", startOffset, size, nextOffset);
+
+    if (nextOffset > pHdr->mapLength) {
+        /*
+         * We don't have to abort here.  We could fall back on the system
+         * malloc(), and have our "free" call figure out what to do.  Only
+         * works if the users of these functions actually free everything
+         * they allocate.
+         */
+        LOGE("LinearAlloc exceeded capacity (%d), last=%d",
+            pHdr->mapLength, (int) size);
+        dvmAbort();
+    }
+
+    /*
+     * Round up "size" to encompass the entire region, including the 0-7
+     * pad bytes before the next chunk header.  This way we get maximum
+     * utility out of "realloc", and when we're doing ENFORCE_READ_ONLY
+     * stuff we always treat the full extent.
+     */
+    size = nextOffset - (startOffset + HEADER_EXTRA);
+    LOGVV("--- (size now %d)", size);
+
+    /*
+     * See if we are starting on or have crossed into a new page.  If so,
+     * call mprotect on the page(s) we're about to write to.  We have to
+     * page-align the start address, but don't have to make the length a
+     * SYSTEM_PAGE_SIZE multiple (but we do it anyway).
+     *
+     * Note that "startOffset" is not the last *allocated* byte, but rather
+     * the offset of the first *unallocated* byte (which we are about to
+     * write the chunk header to).  "nextOffset" is similar.
+     *
+     * If ENFORCE_READ_ONLY is enabled, we have to call mprotect even if
+     * we've written to this page before, because it might be read-only.
+     */
+    lastGoodOff = (startOffset-1) & ~(SYSTEM_PAGE_SIZE-1);
+    firstWriteOff = startOffset & ~(SYSTEM_PAGE_SIZE-1);
+    lastWriteOff = (nextOffset-1) & ~(SYSTEM_PAGE_SIZE-1);
+    LOGVV("---  lastGood=0x%04x firstWrite=0x%04x lastWrite=0x%04x",
+        lastGoodOff, firstWriteOff, lastWriteOff);
+    if (lastGoodOff != lastWriteOff || ENFORCE_READ_ONLY) {
+        int cc, start, len;
+
+        start = firstWriteOff;
+        assert(start <= nextOffset);
+        len = (lastWriteOff - firstWriteOff) + SYSTEM_PAGE_SIZE;
+
+        LOGVV("---    calling mprotect(start=%d len=%d RW)", start, len);
+        cc = mprotect(pHdr->mapAddr + start, len, PROT_READ | PROT_WRITE);
+        if (cc != 0) {
+            LOGE("LinearAlloc mprotect (+%d %d) failed: %s",
+                start, len, strerror(errno));
+            /* we're going to fail soon, might as do it now */
+            dvmAbort();
+        }
+    }
+
+    /* update the ref counts on the now-writable pages */
+    if (ENFORCE_READ_ONLY) {
+        int i, start, end;
+
+        start = firstWriteOff / SYSTEM_PAGE_SIZE;
+        end = lastWriteOff / SYSTEM_PAGE_SIZE;
+
+        LOGVV("---  marking pages %d-%d RW (alloc %d at %p)",
+            start, end, size, pHdr->mapAddr + startOffset + HEADER_EXTRA);
+        for (i = start; i <= end; i++)
+            pHdr->writeRefCount[i]++;
+    }
+
+    /* stow the size in the header */
+    if (ENFORCE_READ_ONLY)
+        *(u4*)(pHdr->mapAddr + startOffset) = size | LENGTHFLAG_RW;
+    else
+        *(u4*)(pHdr->mapAddr + startOffset) = size;
+
+    /*
+     * Update data structure.
+     */
+    pHdr->curOffset = nextOffset;
+
+    dvmUnlockMutex(&pHdr->lock);
+    return pHdr->mapAddr + startOffset + HEADER_EXTRA;
+}
+
+/*
+ * Helper function, replaces strdup().
+ */
+char* dvmLinearStrdup(Object* classLoader, const char* str)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return strdup(str);
+#endif
+    int len = strlen(str);
+    void* mem = dvmLinearAlloc(classLoader, len+1);
+    memcpy(mem, str, len+1);
+    if (ENFORCE_READ_ONLY)
+        dvmLinearSetReadOnly(classLoader, mem);
+    return (char*) mem;
+}
+
+/*
+ * "Reallocate" a piece of memory.
+ *
+ * If the new size is <= the old size, we return the original pointer
+ * without doing anything.
+ *
+ * If the new size is > the old size, we allocate new storage, copy the
+ * old stuff over, and mark the new stuff as free.
+ */
+void* dvmLinearRealloc(Object* classLoader, void* mem, size_t newSize)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return realloc(mem, newSize);
+#endif
+    /* make sure we have the right region (and mem != NULL) */
+    assert(mem != NULL);
+    assert(mem >= (void*) getHeader(classLoader)->mapAddr &&
+           mem < (void*) (getHeader(classLoader)->mapAddr +
+                          getHeader(classLoader)->curOffset));
+
+    const u4* pLen = getBlockHeader(mem);
+    LOGV("--- LinearRealloc(%d) old=%d", newSize, *pLen);
+
+    /* handle size reduction case */
+    if (*pLen >= newSize) {
+        if (ENFORCE_READ_ONLY)
+            dvmLinearSetReadWrite(classLoader, mem);
+        return mem;
+    }
+
+    void* newMem;
+
+    newMem = dvmLinearAlloc(classLoader, newSize);
+    assert(newMem != NULL);
+    memcpy(newMem, mem, *pLen);
+    dvmLinearFree(classLoader, mem);
+
+    return newMem;
+}
+
+
+/*
+ * Update the read/write status of one or more pages.
+ */
+static void updatePages(Object* classLoader, void* mem, int direction)
+{
+    LinearAllocHdr* pHdr = getHeader(classLoader);
+    dvmLockMutex(&pHdr->lock);
+
+    /* make sure we have the right region */
+    assert(mem >= (void*) pHdr->mapAddr &&
+           mem < (void*) (pHdr->mapAddr + pHdr->curOffset));
+
+    u4* pLen = getBlockHeader(mem);
+    u4 len = *pLen & LENGTHFLAG_MASK;
+    int firstPage, lastPage;
+
+    firstPage = ((u1*)pLen - (u1*)pHdr->mapAddr) / SYSTEM_PAGE_SIZE;
+    lastPage = ((u1*)mem - (u1*)pHdr->mapAddr + (len-1)) / SYSTEM_PAGE_SIZE;
+    LOGVV("--- updating pages %d-%d (%d)", firstPage, lastPage, direction);
+
+    int i, cc;
+
+    /*
+     * Update individual pages.  We could do some sort of "lazy update" to
+     * combine mprotect calls, but that's almost certainly more trouble
+     * than it's worth.
+     */
+    for (i = firstPage; i <= lastPage; i++) {
+        if (direction < 0) {
+            /*
+             * Trying to mark read-only.
+             */
+            if (i == firstPage) {
+                if ((*pLen & LENGTHFLAG_RW) == 0) {
+                    LOGW("Double RO on %p", mem);
+                    dvmAbort();
+                } else
+                    *pLen &= ~LENGTHFLAG_RW;
+            }
+
+            if (pHdr->writeRefCount[i] == 0) {
+                LOGE("Can't make page %d any less writable", i);
+                dvmAbort();
+            }
+            pHdr->writeRefCount[i]--;
+            if (pHdr->writeRefCount[i] == 0) {
+                LOGVV("---  prot page %d RO", i);
+                cc = mprotect(pHdr->mapAddr + SYSTEM_PAGE_SIZE * i,
+                        SYSTEM_PAGE_SIZE, PROT_READ);
+                assert(cc == 0);
+            }
+        } else {
+            /*
+             * Trying to mark writable.
+             */
+            if (pHdr->writeRefCount[i] >= 32767) {
+                LOGE("Can't make page %d any more writable", i);
+                dvmAbort();
+            }
+            if (pHdr->writeRefCount[i] == 0) {
+                LOGVV("---  prot page %d RW", i);
+                cc = mprotect(pHdr->mapAddr + SYSTEM_PAGE_SIZE * i,
+                        SYSTEM_PAGE_SIZE, PROT_READ | PROT_WRITE);
+                assert(cc == 0);
+            }
+            pHdr->writeRefCount[i]++;
+
+            if (i == firstPage) {
+                if ((*pLen & LENGTHFLAG_RW) != 0) {
+                    LOGW("Double RW on %p", mem);
+                    dvmAbort();
+                } else
+                    *pLen |= LENGTHFLAG_RW;
+            }
+        }
+    }
+
+    dvmUnlockMutex(&pHdr->lock);
+}
+
+/*
+ * Try to mark the pages in which a chunk of memory lives as read-only.
+ * Whether or not the pages actually change state depends on how many
+ * others are trying to access the same pages.
+ *
+ * Only call here if ENFORCE_READ_ONLY is true.
+ */
+void dvmLinearSetReadOnly(Object* classLoader, void* mem)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return;
+#endif
+    updatePages(classLoader, mem, -1);
+}
+
+/*
+ * Make the pages on which "mem" sits read-write.
+ *
+ * This covers the header as well as the data itself.  (We could add a
+ * "header-only" mode for dvmLinearFree.)
+ *
+ * Only call here if ENFORCE_READ_ONLY is true.
+ */
+void dvmLinearSetReadWrite(Object* classLoader, void* mem)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return;
+#endif
+    updatePages(classLoader, mem, 1);
+}
+
+/*
+ * Mark an allocation as free.
+ */
+void dvmLinearFree(Object* classLoader, void* mem)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    free(mem);
+    return;
+#endif
+    if (mem == NULL)
+        return;
+
+    /* make sure we have the right region */
+    assert(mem >= (void*) getHeader(classLoader)->mapAddr &&
+           mem < (void*) (getHeader(classLoader)->mapAddr +
+                          getHeader(classLoader)->curOffset));
+
+    if (ENFORCE_READ_ONLY)
+        dvmLinearSetReadWrite(classLoader, mem);
+
+    u4* pLen = getBlockHeader(mem);
+    *pLen |= LENGTHFLAG_FREE;
+
+    if (ENFORCE_READ_ONLY)
+        dvmLinearSetReadOnly(classLoader, mem);
+}
+
+/*
+ * For debugging, dump the contents of a linear alloc area.
+ *
+ * We grab the lock so that the header contents and list output are
+ * consistent.
+ */
+void dvmLinearAllocDump(Object* classLoader)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return;
+#endif
+    LinearAllocHdr* pHdr = getHeader(classLoader);
+
+    dvmLockMutex(&pHdr->lock);
+
+    LOGI("LinearAlloc classLoader=%p", classLoader);
+    LOGI("  mapAddr=%p mapLength=%d firstOffset=%d",
+        pHdr->mapAddr, pHdr->mapLength, pHdr->firstOffset);
+    LOGI("  curOffset=%d", pHdr->curOffset);
+
+    int off = pHdr->firstOffset;
+    u4 rawLen, fullLen;
+
+    while (off < pHdr->curOffset) {
+        rawLen = *(u4*) (pHdr->mapAddr + off);
+        fullLen = ((HEADER_EXTRA*2 + (rawLen & LENGTHFLAG_MASK))
+                    & ~(BLOCK_ALIGN-1));
+
+        LOGI("  %p (%3d): %clen=%d%s", pHdr->mapAddr + off + HEADER_EXTRA,
+            (int) ((off + HEADER_EXTRA) / SYSTEM_PAGE_SIZE),
+            (rawLen & LENGTHFLAG_FREE) != 0 ? '*' : ' ',
+            rawLen & LENGTHFLAG_MASK,
+            (rawLen & LENGTHFLAG_RW) != 0 ? " [RW]" : "");
+
+        off += fullLen;
+    }
+
+    if (ENFORCE_READ_ONLY) {
+        LOGI("writeRefCount map:");
+
+        int numPages = (pHdr->mapLength+SYSTEM_PAGE_SIZE-1) / SYSTEM_PAGE_SIZE;
+        int zstart = 0;
+        int i;
+
+        for (i = 0; i < numPages; i++) {
+            int count = pHdr->writeRefCount[i];
+
+            if (count != 0) {
+                if (zstart < i-1)
+                    printf(" %d-%d: zero\n", zstart, i-1);
+                else if (zstart == i-1)
+                    printf(" %d: zero\n", zstart);
+                zstart = i+1;
+                printf(" %d: %d\n", i, count);
+            }
+        }
+        if (zstart < i)
+            printf(" %d-%d: zero\n", zstart, i-1);
+    }
+
+    LOGD("LinearAlloc %p using %d of %d (%d%%)",
+        classLoader, pHdr->curOffset, pHdr->mapLength,
+        (pHdr->curOffset * 100) / pHdr->mapLength);
+
+    dvmUnlockMutex(&pHdr->lock);
+}
+
+/*
+ * Verify that all blocks are freed.
+ *
+ * This should only be done as we're shutting down, but there could be a
+ * daemon thread that's still trying to do something, so we grab the locks.
+ */
+static void checkAllFree(Object* classLoader)
+{
+#ifdef DISABLE_LINEAR_ALLOC
+    return;
+#endif
+    LinearAllocHdr* pHdr = getHeader(classLoader);
+
+    dvmLockMutex(&pHdr->lock);
+
+    int off = pHdr->firstOffset;
+    u4 rawLen, fullLen;
+
+    while (off < pHdr->curOffset) {
+        rawLen = *(u4*) (pHdr->mapAddr + off);
+        fullLen = ((HEADER_EXTRA*2 + (rawLen & LENGTHFLAG_MASK))
+                    & ~(BLOCK_ALIGN-1));
+
+        if ((rawLen & LENGTHFLAG_FREE) == 0) {
+            LOGW("LinearAlloc %p not freed: %p len=%d", classLoader,
+                pHdr->mapAddr + off + HEADER_EXTRA, rawLen & LENGTHFLAG_MASK);
+        }
+
+        off += fullLen;
+    }
+
+    dvmUnlockMutex(&pHdr->lock);
+}
+
+/*
+ * Determine if [start, start+length) is contained in the in-use area of
+ * a single LinearAlloc.  The full set of linear allocators is scanned.
+ *
+ * [ Since we currently only have one region, this is pretty simple.  In
+ * the future we'll need to traverse a table of class loaders. ]
+ */
+bool dvmLinearAllocContains(const void* start, size_t length)
+{
+    LinearAllocHdr* pHdr = getHeader(NULL);
+
+    if (pHdr == NULL)
+        return false;
+
+    return (char*) start >= pHdr->mapAddr &&
+           ((char*)start + length) <= (pHdr->mapAddr + pHdr->curOffset);
+}
diff --git a/vm/LinearAlloc.h b/vm/LinearAlloc.h
new file mode 100644
index 0000000..743b7cc
--- /dev/null
+++ b/vm/LinearAlloc.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+/*
+ * Simple linear memory allocator.
+ */
+#ifndef DALVIK_LINEARALLOC_H_
+#define DALVIK_LINEARALLOC_H_
+
+/*
+ * If this is set, we create additional data structures and make many
+ * additional mprotect() calls.
+ */
+#define ENFORCE_READ_ONLY   false
+
+/*
+ * Linear allocation state.  We could tuck this into the start of the
+ * allocated region, but that would prevent us from sharing the rest of
+ * that first page.
+ */
+struct LinearAllocHdr {
+    int     curOffset;          /* offset where next data goes */
+    pthread_mutex_t lock;       /* controls updates to this struct */
+
+    char*   mapAddr;            /* start of mmap()ed region */
+    int     mapLength;          /* length of region */
+    int     firstOffset;        /* for chasing through */
+
+    short*  writeRefCount;      /* for ENFORCE_READ_ONLY */
+};
+
+
+/*
+ * Create a new alloc region.
+ */
+LinearAllocHdr* dvmLinearAllocCreate(Object* classLoader);
+
+/*
+ * Destroy a region.
+ */
+void dvmLinearAllocDestroy(Object* classLoader);
+
+/*
+ * Allocate a chunk of memory.  The memory will be zeroed out.
+ *
+ * For ENFORCE_READ_ONLY, call dvmLinearReadOnly on the result.
+ */
+void* dvmLinearAlloc(Object* classLoader, size_t size);
+
+/*
+ * Reallocate a chunk.  The original storage is not released, but may be
+ * erased to aid debugging.
+ *
+ * For ENFORCE_READ_ONLY, call dvmLinearReadOnly on the result.  Also, the
+ * caller should probably mark the "mem" argument read-only before calling.
+ */
+void* dvmLinearRealloc(Object* classLoader, void* mem, size_t newSize);
+
+/* don't call these directly */
+void dvmLinearSetReadOnly(Object* classLoader, void* mem);
+void dvmLinearSetReadWrite(Object* classLoader, void* mem);
+
+/*
+ * Mark a chunk of memory from Alloc or Realloc as read-only.  This must
+ * be done after all changes to the block of memory have been made.  This
+ * actually operates on a page granularity.
+ */
+INLINE void dvmLinearReadOnly(Object* classLoader, void* mem)
+{
+    if (ENFORCE_READ_ONLY && mem != NULL)
+        dvmLinearSetReadOnly(classLoader, mem);
+}
+
+/*
+ * Make a chunk of memory writable again.
+ */
+INLINE void dvmLinearReadWrite(Object* classLoader, void* mem)
+{
+    if (ENFORCE_READ_ONLY && mem != NULL)
+        dvmLinearSetReadWrite(classLoader, mem);
+}
+
+/*
+ * Free a chunk.  Does not increase available storage, but the freed area
+ * may be erased to aid debugging.
+ */
+void dvmLinearFree(Object* classLoader, void* mem);
+
+/*
+ * Helper function; allocates new storage and copies "str" into it.
+ *
+ * For ENFORCE_READ_ONLY, do *not* call dvmLinearReadOnly on the result.
+ * This is done automatically.
+ */
+char* dvmLinearStrdup(Object* classLoader, const char* str);
+
+/*
+ * Dump the contents of a linear alloc area.
+ */
+void dvmLinearAllocDump(Object* classLoader);
+
+/*
+ * Determine if [start, start+length) is contained in the in-use area of
+ * a single LinearAlloc.  The full set of linear allocators is scanned.
+ */
+bool dvmLinearAllocContains(const void* start, size_t length);
+
+#endif  // DALVIK_LINEARALLOC_H_
diff --git a/vm/Misc.cpp b/vm/Misc.cpp
new file mode 100644
index 0000000..1365516
--- /dev/null
+++ b/vm/Misc.cpp
@@ -0,0 +1,824 @@
+/*
+ * 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.
+ */
+
+/*
+ * Miscellaneous utility functions.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <cutils/ashmem.h>
+#include <sys/mman.h>
+
+/*
+ * Print a hex dump in this format:
+ *
+01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff  0123456789abcdef\n
+ *
+ * If "mode" is kHexDumpLocal, we start at offset zero, and show a full
+ * 16 bytes on the first line.  If it's kHexDumpMem, we make this look
+ * like a memory dump, using the actual address, outputting a partial line
+ * if "vaddr" isn't aligned on a 16-byte boundary.
+ *
+ * "priority" and "tag" determine the values passed to the log calls.
+ *
+ * Does not use printf() or other string-formatting calls.
+ */
+void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
+    size_t length, HexDumpMode mode)
+{
+    static const char gHexDigit[] = "0123456789abcdef";
+    const unsigned char* addr = (const unsigned char*)vaddr;
+    char out[77];           /* exact fit */
+    unsigned int offset;    /* offset to show while printing */
+    char* hex;
+    char* asc;
+    int gap;
+    //int trickle = 0;
+
+    if (mode == kHexDumpLocal)
+        offset = 0;
+    else
+        offset = (int) addr;
+
+    memset(out, ' ', sizeof(out)-1);
+    out[8] = ':';
+    out[sizeof(out)-2] = '\n';
+    out[sizeof(out)-1] = '\0';
+
+    gap = (int) offset & 0x0f;
+    while (length) {
+        unsigned int lineOffset = offset & ~0x0f;
+        int i, count;
+
+        hex = out;
+        asc = out + 59;
+
+        for (i = 0; i < 8; i++) {
+            *hex++ = gHexDigit[lineOffset >> 28];
+            lineOffset <<= 4;
+        }
+        hex++;
+        hex++;
+
+        count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */
+        assert(count != 0);
+        assert(count+gap <= 16);
+
+        if (gap) {
+            /* only on first line */
+            hex += gap * 3;
+            asc += gap;
+        }
+
+        for (i = gap ; i < count+gap; i++) {
+            *hex++ = gHexDigit[*addr >> 4];
+            *hex++ = gHexDigit[*addr & 0x0f];
+            hex++;
+            if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/)
+                *asc++ = *addr;
+            else
+                *asc++ = '.';
+            addr++;
+        }
+        for ( ; i < 16; i++) {
+            /* erase extra stuff; only happens on last line */
+            *hex++ = ' ';
+            *hex++ = ' ';
+            hex++;
+            *asc++ = ' ';
+        }
+
+        LOG_PRI(priority, tag, "%s", out);
+#if 0 //def HAVE_ANDROID_OS
+        /*
+         * We can overrun logcat easily by writing at full speed.  On the
+         * other hand, we can make Eclipse time out if we're showing
+         * packet dumps while debugging JDWP.
+         */
+        {
+            if (trickle++ == 8) {
+                trickle = 0;
+                usleep(20000);
+            }
+        }
+#endif
+
+        gap = 0;
+        length -= count;
+        offset += count;
+    }
+}
+
+
+/*
+ * Fill out a DebugOutputTarget, suitable for printing to the log.
+ */
+void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
+    const char* tag)
+{
+    assert(target != NULL);
+    assert(tag != NULL);
+
+    target->which = kDebugTargetLog;
+    target->data.log.priority = priority;
+    target->data.log.tag = tag;
+}
+
+/*
+ * Fill out a DebugOutputTarget suitable for printing to a file pointer.
+ */
+void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp)
+{
+    assert(target != NULL);
+    assert(fp != NULL);
+
+    target->which = kDebugTargetFile;
+    target->data.file.fp = fp;
+}
+
+/*
+ * Free "target" and any associated data.
+ */
+void dvmFreeOutputTarget(DebugOutputTarget* target)
+{
+    free(target);
+}
+
+/*
+ * Print a debug message, to either a file or the log.
+ */
+void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
+    ...)
+{
+    va_list args;
+
+    va_start(args, format);
+
+    switch (target->which) {
+    case kDebugTargetLog:
+        LOG_PRI_VA(target->data.log.priority, target->data.log.tag,
+            format, args);
+        break;
+    case kDebugTargetFile:
+        vfprintf(target->data.file.fp, format, args);
+        break;
+    default:
+        LOGE("unexpected 'which' %d", target->which);
+        break;
+    }
+
+    va_end(args);
+}
+
+
+/*
+ * Return a newly-allocated string in which all occurrences of '.' have
+ * been changed to '/'.  If we find a '/' in the original string, NULL
+ * is returned to avoid ambiguity.
+ */
+char* dvmDotToSlash(const char* str)
+{
+    char* newStr = strdup(str);
+    char* cp = newStr;
+
+    if (newStr == NULL)
+        return NULL;
+
+    while (*cp != '\0') {
+        if (*cp == '/') {
+            assert(false);
+            return NULL;
+        }
+        if (*cp == '.')
+            *cp = '/';
+        cp++;
+    }
+
+    return newStr;
+}
+
+std::string dvmHumanReadableDescriptor(const char* descriptor) {
+    // Count the number of '['s to get the dimensionality.
+    const char* c = descriptor;
+    size_t dim = 0;
+    while (*c == '[') {
+        dim++;
+        c++;
+    }
+
+    // Reference or primitive?
+    if (*c == 'L') {
+        // "[[La/b/C;" -> "a.b.C[][]".
+        c++; // Skip the 'L'.
+    } else {
+        // "[[B" -> "byte[][]".
+        // To make life easier, we make primitives look like unqualified
+        // reference types.
+        switch (*c) {
+        case 'B': c = "byte;"; break;
+        case 'C': c = "char;"; break;
+        case 'D': c = "double;"; break;
+        case 'F': c = "float;"; break;
+        case 'I': c = "int;"; break;
+        case 'J': c = "long;"; break;
+        case 'S': c = "short;"; break;
+        case 'Z': c = "boolean;"; break;
+        default: return descriptor;
+        }
+    }
+
+    // At this point, 'c' is a string of the form "fully/qualified/Type;"
+    // or "primitive;". Rewrite the type with '.' instead of '/':
+    std::string result;
+    const char* p = c;
+    while (*p != ';') {
+        char ch = *p++;
+        if (ch == '/') {
+          ch = '.';
+        }
+        result.push_back(ch);
+    }
+    // ...and replace the semicolon with 'dim' "[]" pairs:
+    while (dim--) {
+        result += "[]";
+    }
+    return result;
+}
+
+std::string dvmHumanReadableType(const Object* obj)
+{
+    if (obj == NULL) {
+        return "null";
+    }
+    if (obj->clazz == NULL) {
+        /* should only be possible right after a plain dvmMalloc() */
+        return "(raw)";
+    }
+    std::string result(dvmHumanReadableDescriptor(obj->clazz->descriptor));
+    if (dvmIsClassObject(obj)) {
+        const ClassObject* clazz = reinterpret_cast<const ClassObject*>(obj);
+        result += "<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">";
+    }
+    return result;
+}
+
+std::string dvmHumanReadableField(const Field* field)
+{
+    if (field == NULL) {
+        return "(null)";
+    }
+    std::string result(dvmHumanReadableDescriptor(field->clazz->descriptor));
+    result += '.';
+    result += field->name;
+    return result;
+}
+
+std::string dvmHumanReadableMethod(const Method* method, bool withSignature)
+{
+    if (method == NULL) {
+        return "(null)";
+    }
+    std::string result(dvmHumanReadableDescriptor(method->clazz->descriptor));
+    result += '.';
+    result += method->name;
+    if (withSignature) {
+        // TODO: the types in this aren't human readable!
+        char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
+        result += signature;
+        free(signature);
+    }
+    return result;
+}
+
+/*
+ * Return a newly-allocated string for the "dot version" of the class
+ * name for the given type descriptor. That is, The initial "L" and
+ * final ";" (if any) have been removed and all occurrences of '/'
+ * have been changed to '.'.
+ *
+ * "Dot version" names are used in the class loading machinery.
+ * See also dvmHumanReadableDescriptor.
+ */
+char* dvmDescriptorToDot(const char* str)
+{
+    size_t at = strlen(str);
+    char* newStr;
+
+    if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
+        at -= 2; /* Two fewer chars to copy. */
+        str++; /* Skip the 'L'. */
+    }
+
+    newStr = (char*)malloc(at + 1); /* Add one for the '\0'. */
+    if (newStr == NULL)
+        return NULL;
+
+    newStr[at] = '\0';
+
+    while (at > 0) {
+        at--;
+        newStr[at] = (str[at] == '/') ? '.' : str[at];
+    }
+
+    return newStr;
+}
+
+/*
+ * Return a newly-allocated string for the type descriptor
+ * corresponding to the "dot version" of the given class name. That
+ * is, non-array names are surrounded by "L" and ";", and all
+ * occurrences of '.' have been changed to '/'.
+ *
+ * "Dot version" names are used in the class loading machinery.
+ */
+char* dvmDotToDescriptor(const char* str)
+{
+    size_t length = strlen(str);
+    int wrapElSemi = 0;
+    char* newStr;
+    char* at;
+
+    if (str[0] != '[') {
+        length += 2; /* for "L" and ";" */
+        wrapElSemi = 1;
+    }
+
+    newStr = at = (char*)malloc(length + 1); /* + 1 for the '\0' */
+
+    if (newStr == NULL) {
+        return NULL;
+    }
+
+    if (wrapElSemi) {
+        *(at++) = 'L';
+    }
+
+    while (*str) {
+        char c = *(str++);
+        if (c == '.') {
+            c = '/';
+        }
+        *(at++) = c;
+    }
+
+    if (wrapElSemi) {
+        *(at++) = ';';
+    }
+
+    *at = '\0';
+    return newStr;
+}
+
+/*
+ * Return a newly-allocated string for the internal-form class name for
+ * the given type descriptor. That is, the initial "L" and final ";" (if
+ * any) have been removed.
+ */
+char* dvmDescriptorToName(const char* str)
+{
+    if (str[0] == 'L') {
+        size_t length = strlen(str) - 1;
+        char* newStr = (char*)malloc(length);
+
+        if (newStr == NULL) {
+            return NULL;
+        }
+
+        strlcpy(newStr, str + 1, length);
+        return newStr;
+    }
+
+    return strdup(str);
+}
+
+/*
+ * Return a newly-allocated string for the type descriptor for the given
+ * internal-form class name. That is, a non-array class name will get
+ * surrounded by "L" and ";", while array names are left as-is.
+ */
+char* dvmNameToDescriptor(const char* str)
+{
+    if (str[0] != '[') {
+        size_t length = strlen(str);
+        char* descriptor = (char*)malloc(length + 3);
+
+        if (descriptor == NULL) {
+            return NULL;
+        }
+
+        descriptor[0] = 'L';
+        strcpy(descriptor + 1, str);
+        descriptor[length + 1] = ';';
+        descriptor[length + 2] = '\0';
+
+        return descriptor;
+    }
+
+    return strdup(str);
+}
+
+/*
+ * Get a notion of the current time, in nanoseconds.  This is meant for
+ * computing durations (e.g. "operation X took 52nsec"), so the result
+ * should not be used to get the current date/time.
+ */
+u8 dvmGetRelativeTimeNsec()
+{
+#ifdef HAVE_POSIX_CLOCKS
+    struct timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
+#else
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
+#endif
+}
+
+/*
+ * Get the per-thread CPU time, in nanoseconds.
+ *
+ * Only useful for time deltas.
+ */
+u8 dvmGetThreadCpuTimeNsec()
+{
+#ifdef HAVE_POSIX_CLOCKS
+    struct timespec now;
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
+    return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
+#else
+    return (u8) -1;
+#endif
+}
+
+/*
+ * Get the per-thread CPU time, in nanoseconds, for the specified thread.
+ */
+u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
+{
+#if 0 /*def HAVE_POSIX_CLOCKS*/
+    int clockId;
+
+    if (pthread_getcpuclockid(thread, &clockId) != 0)
+        return (u8) -1;
+
+    struct timespec now;
+    clock_gettime(clockId, &now);
+    return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
+#else
+    return (u8) -1;
+#endif
+}
+
+
+/*
+ * Call this repeatedly, with successively higher values for "iteration",
+ * to sleep for a period of time not to exceed "maxTotalSleep".
+ *
+ * For example, when called with iteration==0 we will sleep for a very
+ * brief time.  On the next call we will sleep for a longer time.  When
+ * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
+ *
+ * The initial start time value for "relStartTime" MUST come from the
+ * dvmGetRelativeTimeUsec call.  On the device this must come from the
+ * monotonic clock source, not the wall clock.
+ *
+ * This should be used wherever you might be tempted to call sched_yield()
+ * in a loop.  The problem with sched_yield is that, for a high-priority
+ * thread, the kernel might not actually transfer control elsewhere.
+ *
+ * Returns "false" if we were unable to sleep because our time was up.
+ */
+bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
+{
+    const int minSleep = 10000;
+    u8 curTime;
+    int curDelay;
+
+    /*
+     * Get current time, and see if we've already exceeded the limit.
+     */
+    curTime = dvmGetRelativeTimeUsec();
+    if (curTime >= relStartTime + maxTotalSleep) {
+        LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)",
+            relStartTime, maxTotalSleep, curTime);
+        return false;
+    }
+
+    /*
+     * Compute current delay.  We're bounded by "maxTotalSleep", so no
+     * real risk of overflow assuming "usleep" isn't returning early.
+     * (Besides, 2^30 usec is about 18 minutes by itself.)
+     *
+     * For iteration==0 we just call sched_yield(), so the first sleep
+     * at iteration==1 is actually (minSleep * 2).
+     */
+    curDelay = minSleep;
+    while (iteration-- > 0)
+        curDelay *= 2;
+    assert(curDelay > 0);
+
+    if (curTime + curDelay >= relStartTime + maxTotalSleep) {
+        LOGVV("exsl: reduced delay from %d to %d",
+            curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
+        curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
+    }
+
+    if (iteration == 0) {
+        LOGVV("exsl: yield");
+        sched_yield();
+    } else {
+        LOGVV("exsl: sleep for %d", curDelay);
+        usleep(curDelay);
+    }
+    return true;
+}
+
+
+/*
+ * Set the "close on exec" flag so we don't expose our file descriptors
+ * to processes launched by us.
+ */
+bool dvmSetCloseOnExec(int fd)
+{
+    int flags;
+
+    /*
+     * There's presently only one flag defined, so getting the previous
+     * value of the fd flags is probably unnecessary.
+     */
+    flags = fcntl(fd, F_GETFD);
+    if (flags < 0) {
+        LOGW("Unable to get fd flags for fd %d", fd);
+        return false;
+    }
+    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
+        LOGW("Unable to set close-on-exec for fd %d", fd);
+        return false;
+    }
+    return true;
+}
+
+#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) {
+    size_t srcLength = strlen(src);
+    size_t copyLength = srcLength;
+
+    if (srcLength > (size - 1)) {
+        copyLength = size - 1;
+    }
+
+    if (size != 0) {
+        strncpy(dst, src, copyLength);
+        dst[copyLength] = '\0';
+    }
+
+    return srcLength;
+}
+#endif
+
+/*
+ *  Allocates a memory region using ashmem and mmap, initialized to
+ *  zero.  Actual allocation rounded up to page multiple.  Returns
+ *  NULL on failure.
+ */
+void *dvmAllocRegion(size_t byteCount, int prot, const char *name) {
+    void *base;
+    int fd, ret;
+
+    byteCount = ALIGN_UP_TO_PAGE_SIZE(byteCount);
+    fd = ashmem_create_region(name, byteCount);
+    if (fd == -1) {
+        return NULL;
+    }
+    base = mmap(NULL, byteCount, prot, MAP_PRIVATE, fd, 0);
+    ret = close(fd);
+    if (base == MAP_FAILED) {
+        return NULL;
+    }
+    if (ret == -1) {
+        return NULL;
+    }
+    return base;
+}
+
+/*
+ * Get some per-thread stats.
+ *
+ * This is currently generated by opening the appropriate "stat" file
+ * in /proc and reading the pile of stuff that comes out.
+ */
+bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
+{
+    /*
+    int pid;
+    char comm[128];
+    char state;
+    int ppid, pgrp, session, tty_nr, tpgid;
+    unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
+    long cutime, cstime, priority, nice, zero, itrealvalue;
+    unsigned long starttime, vsize;
+    long rss;
+    unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
+    unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
+    int exit_signal, processor;
+    unsigned long rt_priority, policy;
+
+    scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
+          "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
+          "%lu %lu %lu %d %d %lu %lu",
+        &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
+        &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
+        &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
+        &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
+        &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
+        &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
+        &rt_priority, &policy);
+
+        (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
+    */
+
+    char nameBuf[64];
+    int i, fd;
+
+    /*
+     * Open and read the appropriate file.  This is expected to work on
+     * Linux but will fail on other platforms (e.g. Mac sim).
+     */
+    sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
+    fd = open(nameBuf, O_RDONLY);
+    if (fd < 0) {
+        LOGV("Unable to open '%s': %s", nameBuf, strerror(errno));
+        return false;
+    }
+
+    char lineBuf[512];      /* > 2x typical */
+    int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
+    if (cc <= 0) {
+        const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
+        LOGI("Unable to read '%s': %s", nameBuf, msg);
+        close(fd);
+        return false;
+    }
+    close(fd);
+    lineBuf[cc] = '\0';
+
+    /*
+     * Skip whitespace-separated tokens.  For the most part we can assume
+     * that tokens do not contain spaces, and are separated by exactly one
+     * space character.  The only exception is the second field ("comm")
+     * which may contain spaces but is surrounded by parenthesis.
+     */
+    char* cp = strchr(lineBuf, ')');
+    if (cp == NULL)
+        goto parse_fail;
+    cp++;
+    for (i = 2; i < 13; i++) {
+        cp = strchr(cp+1, ' ');
+        if (cp == NULL)
+            goto parse_fail;
+    }
+
+    /*
+     * Grab utime/stime.
+     */
+    char* endp;
+    pData->utime = strtoul(cp+1, &endp, 10);
+    if (endp == cp+1)
+        LOGI("Warning: strtoul failed on utime ('%.30s...')", cp);
+
+    cp = strchr(cp+1, ' ');
+    if (cp == NULL)
+        goto parse_fail;
+
+    pData->stime = strtoul(cp+1, &endp, 10);
+    if (endp == cp+1)
+        LOGI("Warning: strtoul failed on stime ('%.30s...')", cp);
+
+    /*
+     * Skip more stuff we don't care about.
+     */
+    for (i = 14; i < 38; i++) {
+        cp = strchr(cp+1, ' ');
+        if (cp == NULL)
+            goto parse_fail;
+    }
+
+    /*
+     * Grab processor number.
+     */
+    pData->processor = strtol(cp+1, &endp, 10);
+    if (endp == cp+1)
+        LOGI("Warning: strtoul failed on processor ('%.30s...')", cp);
+
+    return true;
+
+parse_fail:
+    LOGI("stat parse failed (%s)", lineBuf);
+    return false;
+}
+
+/* documented in header file */
+const char* dvmPathToAbsolutePortion(const char* path) {
+    if (path == NULL) {
+        return NULL;
+    }
+
+    if (path[0] == '/') {
+        /* It's a regular absolute path. Return it. */
+        return path;
+    }
+
+    const char* sentinel = strstr(path, "/./");
+
+    if (sentinel != NULL) {
+        /* It's got the sentinel. Return a pointer to the second slash. */
+        return sentinel + 2;
+    }
+
+    return NULL;
+}
+
+// From RE2.
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+    // First try with a small fixed size buffer
+    char space[1024];
+
+    // It's possible for methods that use a va_list to invalidate
+    // the data in it upon use.  The fix is to make a copy
+    // of the structure before using it and use that copy instead.
+    va_list backup_ap;
+    va_copy(backup_ap, ap);
+    int result = vsnprintf(space, sizeof(space), format, backup_ap);
+    va_end(backup_ap);
+
+    if ((result >= 0) && ((size_t) result < sizeof(space))) {
+        // It fit
+        dst->append(space, result);
+        return;
+    }
+
+    // Repeatedly increase buffer size until it fits
+    int length = sizeof(space);
+    while (true) {
+        if (result < 0) {
+            // Older behavior: just try doubling the buffer size
+            length *= 2;
+        } else {
+            // We need exactly "result+1" characters
+            length = result+1;
+        }
+        char* buf = new char[length];
+
+        // Restore the va_list before we use it again
+        va_copy(backup_ap, ap);
+        result = vsnprintf(buf, length, format, backup_ap);
+        va_end(backup_ap);
+
+        if ((result >= 0) && (result < length)) {
+            // It fit
+            dst->append(buf, result);
+            delete[] buf;
+            return;
+        }
+        delete[] buf;
+    }
+}
+
+std::string StringPrintf(const char* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    std::string result;
+    StringAppendV(&result, fmt, ap);
+    va_end(ap);
+    return result;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    StringAppendV(dst, format, ap);
+    va_end(ap);
+}
diff --git a/vm/Misc.h b/vm/Misc.h
new file mode 100644
index 0000000..86e0a71
--- /dev/null
+++ b/vm/Misc.h
@@ -0,0 +1,345 @@
+/*
+ * 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.
+ */
+
+/*
+ * Miscellaneous utility functions.
+ */
+#ifndef DALVIK_MISC_H_
+#define DALVIK_MISC_H_
+
+#include <string>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "Inlines.h"
+
+/*
+ * Used to shut up the compiler when a parameter isn't used.
+ */
+#define UNUSED_PARAMETER(p)     (void)(p)
+
+/*
+ * Floating point conversion functions.  These are necessary to avoid
+ * strict-aliasing problems ("dereferencing type-punned pointer will break
+ * strict-aliasing rules").  According to the gcc info page, this usage
+ * is allowed, even with "-fstrict-aliasing".
+ *
+ * The code generated by gcc-4.1.1 appears to be much better than a
+ * type cast dereference ("int foo = *(int*)&myfloat") when the conversion
+ * function is inlined.  It also allows us to take advantage of the
+ * optimizations that strict aliasing rules allow.
+ */
+INLINE float dvmU4ToFloat(u4 val) {
+    union { u4 in; float out; } conv;
+    conv.in = val;
+    return conv.out;
+}
+INLINE u4 dvmFloatToU4(float val) {
+    union { float in; u4 out; } conv;
+    conv.in = val;
+    return conv.out;
+}
+
+/*
+ * Print a hex dump to the log file.
+ *
+ * "local" mode prints a hex dump starting from offset 0 (roughly equivalent
+ * to "xxd -g1").
+ *
+ * "mem" mode shows the actual memory address, and will offset the start
+ * so that the low nibble of the address is always zero.
+ *
+ * If "tag" is NULL the default tag ("dalvikvm") will be used.
+ */
+enum HexDumpMode { kHexDumpLocal, kHexDumpMem };
+void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
+    size_t length, HexDumpMode mode);
+
+/*
+ * Print a hex dump, at INFO level.
+ */
+INLINE void dvmPrintHexDump(const void* vaddr, size_t length) {
+    dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
+        vaddr, length, kHexDumpLocal);
+}
+
+/*
+ * Print a hex dump at VERBOSE level. This does nothing in non-debug builds.
+ */
+INLINE void dvmPrintHexDumpDbg(const void* vaddr, size_t length,const char* tag)
+{
+#if !LOG_NDEBUG
+    dvmPrintHexDumpEx(ANDROID_LOG_VERBOSE, (tag != NULL) ? tag : LOG_TAG,
+        vaddr, length, kHexDumpLocal);
+#endif
+}
+
+enum DebugTargetKind {
+    kDebugTargetUnknown = 0,
+    kDebugTargetLog,
+    kDebugTargetFile,
+};
+
+/*
+ * We pass one of these around when we want code to be able to write debug
+ * info to either the log or to a file (or stdout/stderr).
+ */
+struct DebugOutputTarget {
+    /* where to? */
+    DebugTargetKind which;
+
+    /* additional bits */
+    union {
+        struct {
+            int priority;
+            const char* tag;
+        } log;
+        struct {
+            FILE* fp;
+        } file;
+    } data;
+};
+
+/*
+ * Fill in a DebugOutputTarget struct.
+ */
+void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
+    const char* tag);
+void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp);
+
+/*
+ * Print a debug message.
+ */
+void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
+    ...)
+#if defined(__GNUC__)
+    __attribute__ ((format(printf, 2, 3)))
+#endif
+    ;
+
+/*
+ * Return a newly-allocated string in which all occurrences of '.' have
+ * been changed to '/'.  If we find a '/' in the original string, NULL
+ * is returned to avoid ambiguity.
+ */
+char* dvmDotToSlash(const char* str);
+
+/*
+ * Return a newly-allocated string containing a human-readable equivalent
+ * of 'descriptor'. So "I" would be "int", "[[I" would be "int[][]",
+ * "[Ljava/lang/String;" would be "java.lang.String[]", and so forth.
+ */
+std::string dvmHumanReadableDescriptor(const char* descriptor);
+
+/**
+ * Returns a human-readable string form of the name of the class of
+ * the given object. So given a java.lang.String, the output would
+ * be "java.lang.String". Given an array of int, the output would be "int[]".
+ * Given String.class, the output would be "java.lang.Class<java.lang.String>".
+ */
+std::string dvmHumanReadableType(const Object* obj);
+
+/**
+ * Returns a human-readable string of the form "package.Class.fieldName".
+ */
+struct Field;
+std::string dvmHumanReadableField(const Field* field);
+
+/**
+ * Returns a human-readable string of the form "package.Class.methodName"
+ * or "package.Class.methodName(Ljava/lang/String;I)V".
+ */
+struct Method;
+std::string dvmHumanReadableMethod(const Method* method, bool withSignature);
+
+/*
+ * Return a newly-allocated string for the "dot version" of the class
+ * name for the given type descriptor. That is, The initial "L" and
+ * final ";" (if any) have been removed and all occurrences of '/'
+ * have been changed to '.'.
+ *
+ * "Dot version" names are used in the class loading machinery.
+ * See also dvmHumanReadableDescriptor.
+ */
+char* dvmDescriptorToDot(const char* str);
+
+/*
+ * Return a newly-allocated string for the type descriptor
+ * corresponding to the "dot version" of the given class name. That
+ * is, non-array names are surrounded by "L" and ";", and all
+ * occurrences of '.' have been changed to '/'.
+ *
+ * "Dot version" names are used in the class loading machinery.
+ */
+char* dvmDotToDescriptor(const char* str);
+
+/*
+ * Return a newly-allocated string for the internal-form class name for
+ * the given type descriptor. That is, the initial "L" and final ";" (if
+ * any) have been removed.
+ */
+char* dvmDescriptorToName(const char* str);
+
+/*
+ * Return a newly-allocated string for the type descriptor for the given
+ * internal-form class name. That is, a non-array class name will get
+ * surrounded by "L" and ";", while array names are left as-is.
+ */
+char* dvmNameToDescriptor(const char* str);
+
+/*
+ * Get the current time, in nanoseconds.  This is "relative" time, meaning
+ * it could be wall-clock time or a monotonic counter, and is only suitable
+ * for computing time deltas.
+ */
+u8 dvmGetRelativeTimeNsec(void);
+
+/*
+ * Get the current time, in microseconds.  This is "relative" time, meaning
+ * it could be wall-clock time or a monotonic counter, and is only suitable
+ * for computing time deltas.
+ */
+INLINE u8 dvmGetRelativeTimeUsec(void) {
+    return dvmGetRelativeTimeNsec() / 1000;
+}
+
+/*
+ * Get the current time, in milliseconds.  This is "relative" time,
+ * meaning it could be wall-clock time or a monotonic counter, and is
+ * only suitable for computing time deltas.  The value returned from
+ * this function is a u4 and should only be used for debugging
+ * messages.  TODO: make this value relative to the start-up time of
+ * the VM.
+ */
+INLINE u4 dvmGetRelativeTimeMsec(void) {
+    return (u4)(dvmGetRelativeTimeUsec() / 1000);
+}
+
+/*
+ * Get the current per-thread CPU time.  This clock increases monotonically
+ * when the thread is running, but not when it's sleeping or blocked on a
+ * synchronization object.
+ *
+ * The absolute value of the clock may not be useful, so this should only
+ * be used for time deltas.
+ *
+ * If the thread CPU clock is not available, this always returns (u8)-1.
+ */
+u8 dvmGetThreadCpuTimeNsec(void);
+
+/*
+ * Per-thread CPU time, in micros.
+ */
+INLINE u8 dvmGetThreadCpuTimeUsec(void) {
+    return dvmGetThreadCpuTimeNsec() / 1000;
+}
+
+/*
+ * Like dvmGetThreadCpuTimeNsec, but for a different thread.
+ */
+u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread);
+INLINE u8 dvmGetOtherThreadCpuTimeUsec(pthread_t thread) {
+    return dvmGetOtherThreadCpuTimeNsec(thread) / 1000;
+}
+
+/*
+ * Sleep for increasingly longer periods, until "maxTotalSleep" microseconds
+ * have elapsed.  Pass in the start time, which must be a value returned by
+ * dvmGetRelativeTimeUsec().
+ *
+ * Returns "false" if we were unable to sleep because our time is up.
+ */
+bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime);
+
+/*
+ * Set the "close on exec" flag on a file descriptor.
+ */
+bool dvmSetCloseOnExec(int fd);
+
+/*
+ * Unconditionally abort the entire VM.  Try not to use this.
+ *
+ * NOTE: if this is marked ((noreturn)), gcc will merge multiple dvmAbort()
+ * calls in a single function together.  This is good, in that it reduces
+ * code size slightly, but also bad, because the native stack trace we
+ * get from the abort may point at the wrong call site.  Best to leave
+ * it undecorated.
+ */
+extern "C" void dvmAbort(void);
+void dvmPrintNativeBackTrace(void);
+
+#if (!HAVE_STRLCPY)
+/* Implementation of strlcpy() for platforms that don't already have it. */
+extern "C" size_t strlcpy(char *dst, const char *src, size_t size);
+#endif
+
+/*
+ *  Allocates a memory region using ashmem and mmap, initialized to
+ *  zero.  Actual allocation rounded up to page multiple.  Returns
+ *  NULL on failure.
+ */
+void *dvmAllocRegion(size_t size, int prot, const char *name);
+
+/*
+ * Get some per-thread stats from /proc/self/task/N/stat.
+ */
+struct ProcStatData {
+    unsigned long utime;    /* number of jiffies scheduled in user mode */
+    unsigned long stime;    /* number of jiffies scheduled in kernel mode */
+    int processor;          /* number of CPU that last executed thread */
+};
+bool dvmGetThreadStats(ProcStatData* pData, pid_t tid);
+
+/*
+ * Returns the pointer to the "absolute path" part of the given path
+ * string, treating first (if any) instance of "/./" as a sentinel
+ * indicating the start of the absolute path. If the path isn't absolute
+ * in the usual way (i.e., starts with "/") and doesn't have the sentinel,
+ * then this returns NULL.
+ *
+ * For example:
+ *     "/foo/bar/baz" returns "/foo/bar/baz"
+ *     "foo/./bar/baz" returns "/bar/baz"
+ *     "foo/bar/baz" returns NULL
+ *
+ * The sentinel is used specifically to aid in cross-optimization, where
+ * a host is processing dex files in a build tree, and where we don't want
+ * the build tree's directory structure to be baked into the output (such
+ * as, for example, in the dependency paths of optimized dex files).
+ */
+const char* dvmPathToAbsolutePortion(const char* path);
+
+/**
+ * Returns a string corresponding to printf-like formatting of the arguments.
+ */
+std::string StringPrintf(const char* fmt, ...)
+        __attribute__((__format__ (__printf__, 1, 2)));
+
+/**
+ * Appends a printf-like formatting of the arguments to 'dst'.
+ */
+void StringAppendF(std::string* dst, const char* fmt, ...)
+        __attribute__((__format__ (__printf__, 2, 3)));
+
+/**
+ * Appends a printf-like formatting of the arguments to 'dst'.
+ */
+void StringAppendV(std::string* dst, const char* format, va_list ap);
+
+#endif  // DALVIK_MISC_H_
diff --git a/vm/Native.cpp b/vm/Native.cpp
new file mode 100644
index 0000000..23c2132
--- /dev/null
+++ b/vm/Native.cpp
@@ -0,0 +1,761 @@
+/*
+ * 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.
+ */
+
+/*
+ * Native method resolution.
+ *
+ * Currently the "Dalvik native" methods are only used for internal methods.
+ * Someday we may want to export the interface as a faster but riskier
+ * alternative to JNI.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+
+static void freeSharedLibEntry(void* ptr);
+static void* lookupSharedLibMethod(const Method* method);
+
+
+/*
+ * Initialize the native code loader.
+ */
+bool dvmNativeStartup()
+{
+    gDvm.nativeLibs = dvmHashTableCreate(4, freeSharedLibEntry);
+    if (gDvm.nativeLibs == NULL)
+        return false;
+
+    return true;
+}
+
+/*
+ * Free up our tables.
+ */
+void dvmNativeShutdown()
+{
+    dvmHashTableFree(gDvm.nativeLibs);
+    gDvm.nativeLibs = NULL;
+}
+
+
+/*
+ * Resolve a native method and invoke it.
+ *
+ * This is executed as if it were a native bridge or function.  If the
+ * resolution succeeds, method->insns is replaced, and we don't go through
+ * here again unless the method is unregistered.
+ *
+ * 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)
+{
+    ClassObject* clazz = method->clazz;
+
+    /*
+     * If this is a static method, it could be called before the class
+     * has been initialized.
+     */
+    if (dvmIsStaticMethod(method)) {
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            return;
+        }
+    } else {
+        assert(dvmIsClassInitialized(clazz) ||
+               dvmIsClassInitializing(clazz));
+    }
+
+    /* start with our internal-native methods */
+    DalvikNativeFunc infunc = dvmLookupInternalNativeMethod(method);
+    if (infunc != NULL) {
+        /* resolution always gets the same answer, so no race here */
+        IF_LOGVV() {
+            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+            LOGVV("+++ resolved native %s.%s %s, invoking",
+                clazz->descriptor, method->name, desc);
+            free(desc);
+        }
+        if (dvmIsSynchronizedMethod(method)) {
+            LOGE("ERROR: internal-native can't be declared 'synchronized'");
+            LOGE("Failing on %s.%s", method->clazz->descriptor, method->name);
+            dvmAbort();     // harsh, but this is VM-internal problem
+        }
+        DalvikBridgeFunc dfunc = (DalvikBridgeFunc) infunc;
+        dvmSetNativeFunc((Method*) method, dfunc, NULL);
+        dfunc(args, pResult, method, self);
+        return;
+    }
+
+    /* now scan any DLLs we have loaded for JNI signatures */
+    void* func = lookupSharedLibMethod(method);
+    if (func != NULL) {
+        /* found it, point it at the JNI bridge and then call it */
+        dvmUseJNIBridge((Method*) method, func);
+        (*method->nativeFunc)(args, pResult, method, self);
+        return;
+    }
+
+    IF_LOGW() {
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGW("No implementation found for native %s.%s %s",
+            clazz->descriptor, method->name, desc);
+        free(desc);
+    }
+
+    dvmThrowUnsatisfiedLinkError(method->name);
+}
+
+
+/*
+ * ===========================================================================
+ *      Native shared library support
+ * ===========================================================================
+ */
+
+// TODO? if a ClassLoader is unloaded, we need to unload all DLLs that
+// are associated with it.  (Or not -- can't determine if native code
+// is still using parts of it.)
+
+enum OnLoadState {
+    kOnLoadPending = 0,     /* initial state, must be zero */
+    kOnLoadFailed,
+    kOnLoadOkay,
+};
+
+/*
+ * We add one of these to the hash table for every library we load.  The
+ * hash is on the "pathName" field.
+ */
+struct SharedLib {
+    char*       pathName;           /* absolute path to library */
+    void*       handle;             /* from dlopen */
+    Object*     classLoader;        /* ClassLoader we are associated with */
+
+    pthread_mutex_t onLoadLock;     /* guards remaining items */
+    pthread_cond_t  onLoadCond;     /* wait for JNI_OnLoad in other thread */
+    u4              onLoadThreadId; /* recursive invocation guard */
+    OnLoadState     onLoadResult;   /* result of earlier JNI_OnLoad */
+};
+
+/*
+ * (This is a dvmHashTableLookup callback.)
+ *
+ * Find an entry that matches the string.
+ */
+static int hashcmpNameStr(const void* ventry, const void* vname)
+{
+    const SharedLib* pLib = (const SharedLib*) ventry;
+    const char* name = (const char*) vname;
+
+    return strcmp(pLib->pathName, name);
+}
+
+/*
+ * (This is a dvmHashTableLookup callback.)
+ *
+ * Find an entry that matches the new entry.
+ *
+ * We don't compare the class loader here, because you're not allowed to
+ * have the same shared library associated with more than one CL.
+ */
+static int hashcmpSharedLib(const void* ventry, const void* vnewEntry)
+{
+    const SharedLib* pLib = (const SharedLib*) ventry;
+    const SharedLib* pNewLib = (const SharedLib*) vnewEntry;
+
+    LOGD("--- comparing %p '%s' %p '%s'",
+        pLib, pLib->pathName, pNewLib, pNewLib->pathName);
+    return strcmp(pLib->pathName, pNewLib->pathName);
+}
+
+/*
+ * Check to see if an entry with the same pathname already exists.
+ */
+static SharedLib* findSharedLibEntry(const char* pathName)
+{
+    u4 hash = dvmComputeUtf8Hash(pathName);
+    void* ent;
+
+    ent = dvmHashTableLookup(gDvm.nativeLibs, hash, (void*)pathName,
+                hashcmpNameStr, false);
+    return (SharedLib*)ent;
+}
+
+/*
+ * Add the new entry to the table.
+ *
+ * Returns the table entry, which will not be the same as "pLib" if the
+ * entry already exists.
+ */
+static SharedLib* addSharedLibEntry(SharedLib* pLib)
+{
+    u4 hash = dvmComputeUtf8Hash(pLib->pathName);
+
+    /*
+     * Do the lookup with the "add" flag set.  If we add it, we will get
+     * our own pointer back.  If somebody beat us to the punch, we'll get
+     * their pointer back instead.
+     */
+    return (SharedLib*)dvmHashTableLookup(gDvm.nativeLibs, hash, pLib,
+                hashcmpSharedLib, true);
+}
+
+/*
+ * Free up an entry.  (This is a dvmHashTableFree callback.)
+ */
+static void freeSharedLibEntry(void* ptr)
+{
+    SharedLib* pLib = (SharedLib*) ptr;
+
+    /*
+     * Calling dlclose() here is somewhat dangerous, because it's possible
+     * that a thread outside the VM is still accessing the code we loaded.
+     */
+    if (false)
+        dlclose(pLib->handle);
+    free(pLib->pathName);
+    free(pLib);
+}
+
+/*
+ * Convert library name to system-dependent form, e.g. "jpeg" becomes
+ * "libjpeg.so".
+ *
+ * (Should we have this take buffer+len and avoid the alloc?  It gets
+ * called very rarely.)
+ */
+char* dvmCreateSystemLibraryName(char* libName)
+{
+    char buf[256];
+    int len;
+
+    len = snprintf(buf, sizeof(buf), OS_SHARED_LIB_FORMAT_STR, libName);
+    if (len >= (int) sizeof(buf))
+        return NULL;
+    else
+        return strdup(buf);
+}
+
+/*
+ * Check the result of an earlier call to JNI_OnLoad on this library.  If
+ * the call has not yet finished in another thread, wait for it.
+ */
+static bool checkOnLoadResult(SharedLib* pEntry)
+{
+    Thread* self = dvmThreadSelf();
+    if (pEntry->onLoadThreadId == self->threadId) {
+        /*
+         * Check this so we don't end up waiting for ourselves.  We need
+         * to return "true" so the caller can continue.
+         */
+        LOGI("threadid=%d: recursive native library load attempt (%s)",
+            self->threadId, pEntry->pathName);
+        return true;
+    }
+
+    LOGV("+++ retrieving %s OnLoad status", pEntry->pathName);
+    bool result;
+
+    dvmLockMutex(&pEntry->onLoadLock);
+    while (pEntry->onLoadResult == kOnLoadPending) {
+        LOGD("threadid=%d: waiting for %s OnLoad status",
+            self->threadId, pEntry->pathName);
+        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+        pthread_cond_wait(&pEntry->onLoadCond, &pEntry->onLoadLock);
+        dvmChangeStatus(self, oldStatus);
+    }
+    if (pEntry->onLoadResult == kOnLoadOkay) {
+        LOGV("+++ earlier OnLoad(%s) okay", pEntry->pathName);
+        result = true;
+    } else {
+        LOGV("+++ earlier OnLoad(%s) failed", pEntry->pathName);
+        result = false;
+    }
+    dvmUnlockMutex(&pEntry->onLoadLock);
+    return result;
+}
+
+typedef int (*OnLoadFunc)(JavaVM*, void*);
+
+/*
+ * Load native code from the specified absolute pathname.  Per the spec,
+ * if we've already loaded a library with the specified pathname, we
+ * return without doing anything.
+ *
+ * TODO? for better results we should absolutify the pathname.  For fully
+ * correct results we should stat to get the inode and compare that.  The
+ * existing implementation is fine so long as everybody is using
+ * System.loadLibrary.
+ *
+ * The library will be associated with the specified class loader.  The JNI
+ * spec says we can't load the same library into more than one class loader.
+ *
+ * Returns "true" on success. On failure, sets *detail to a
+ * human-readable description of the error or NULL if no detail is
+ * available; ownership of the string is transferred to the caller.
+ */
+bool dvmLoadNativeCode(const char* pathName, Object* classLoader,
+        char** detail)
+{
+    SharedLib* pEntry;
+    void* handle;
+    bool verbose;
+
+    /* reduce noise by not chattering about system libraries */
+    verbose = !!strncmp(pathName, "/system", sizeof("/system")-1);
+    verbose = verbose && !!strncmp(pathName, "/vendor", sizeof("/vendor")-1);
+
+    if (verbose)
+        LOGD("Trying to load lib %s %p", pathName, classLoader);
+
+    *detail = NULL;
+
+    /*
+     * See if we've already loaded it.  If we have, and the class loader
+     * matches, return successfully without doing anything.
+     */
+    pEntry = findSharedLibEntry(pathName);
+    if (pEntry != NULL) {
+        if (pEntry->classLoader != classLoader) {
+            LOGW("Shared lib '%s' already opened by CL %p; can't open in %p",
+                pathName, pEntry->classLoader, classLoader);
+            return false;
+        }
+        if (verbose) {
+            LOGD("Shared lib '%s' already loaded in same CL %p",
+                pathName, classLoader);
+        }
+        if (!checkOnLoadResult(pEntry))
+            return false;
+        return true;
+    }
+
+    /*
+     * Open the shared library.  Because we're using a full path, the system
+     * 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
+     * and we have to hunt for the lib.
+     *
+     * The current version of the dynamic linker prints detailed information
+     * about dlopen() failures.  Some things to check if the message is
+     * cryptic:
+     *   - 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 (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 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();
+    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+    handle = dlopen(pathName, RTLD_LAZY);
+    dvmChangeStatus(self, oldStatus);
+
+    if (handle == NULL) {
+        *detail = strdup(dlerror());
+        return false;
+    }
+
+    /* create a new entry */
+    SharedLib* pNewEntry;
+    pNewEntry = (SharedLib*) calloc(1, sizeof(SharedLib));
+    pNewEntry->pathName = strdup(pathName);
+    pNewEntry->handle = handle;
+    pNewEntry->classLoader = classLoader;
+    dvmInitMutex(&pNewEntry->onLoadLock);
+    pthread_cond_init(&pNewEntry->onLoadCond, NULL);
+    pNewEntry->onLoadThreadId = self->threadId;
+
+    /* try to add it to the list */
+    SharedLib* pActualEntry = addSharedLibEntry(pNewEntry);
+
+    if (pNewEntry != pActualEntry) {
+        LOGI("WOW: we lost a race to add a shared lib (%s CL=%p)",
+            pathName, classLoader);
+        freeSharedLibEntry(pNewEntry);
+        return checkOnLoadResult(pActualEntry);
+    } else {
+        if (verbose)
+            LOGD("Added shared lib %s %p", pathName, classLoader);
+
+        bool result = true;
+        void* vonLoad;
+        int version;
+
+        vonLoad = dlsym(handle, "JNI_OnLoad");
+        if (vonLoad == NULL) {
+            LOGD("No JNI_OnLoad found in %s %p, skipping init",
+                pathName, classLoader);
+        } else {
+            /*
+             * Call JNI_OnLoad.  We have to override the current class
+             * loader, which will always be "null" since the stuff at the
+             * top of the stack is around Runtime.loadLibrary().  (See
+             * the comments in the JNI FindClass function.)
+             */
+            OnLoadFunc func = (OnLoadFunc)vonLoad;
+            Object* prevOverride = self->classLoaderOverride;
+
+            self->classLoaderOverride = classLoader;
+            oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
+            if (gDvm.verboseJni) {
+                LOGI("[Calling JNI_OnLoad for \"%s\"]", pathName);
+            }
+            version = (*func)(gDvmJni.jniVm, NULL);
+            dvmChangeStatus(self, oldStatus);
+            self->classLoaderOverride = prevOverride;
+
+            if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 &&
+                version != JNI_VERSION_1_6)
+            {
+                LOGW("JNI_OnLoad returned bad version (%d) in %s %p",
+                    version, pathName, classLoader);
+                /*
+                 * It's unwise to call dlclose() here, but we can mark it
+                 * as bad and ensure that future load attempts will fail.
+                 *
+                 * We don't know how far JNI_OnLoad got, so there could
+                 * be some partially-initialized stuff accessible through
+                 * newly-registered native method calls.  We could try to
+                 * unregister them, but that doesn't seem worthwhile.
+                 */
+                result = false;
+            } else {
+                if (gDvm.verboseJni) {
+                    LOGI("[Returned from JNI_OnLoad for \"%s\"]", pathName);
+                }
+            }
+        }
+
+        if (result)
+            pNewEntry->onLoadResult = kOnLoadOkay;
+        else
+            pNewEntry->onLoadResult = kOnLoadFailed;
+
+        pNewEntry->onLoadThreadId = 0;
+
+        /*
+         * Broadcast a wakeup to anybody sleeping on the condition variable.
+         */
+        dvmLockMutex(&pNewEntry->onLoadLock);
+        pthread_cond_broadcast(&pNewEntry->onLoadCond);
+        dvmUnlockMutex(&pNewEntry->onLoadLock);
+        return result;
+    }
+}
+
+
+/*
+ * Un-register JNI native methods.
+ *
+ * There are two relevant fields in struct Method, "nativeFunc" and
+ * "insns".  The former holds a function pointer to a "bridge" function
+ * (or, for internal native, the actual implementation).  The latter holds
+ * a pointer to the actual JNI method.
+ *
+ * The obvious approach is to reset both fields to their initial state
+ * (nativeFunc points at dvmResolveNativeMethod, insns holds NULL), but
+ * that creates some unpleasant race conditions.  In particular, if another
+ * thread is executing inside the call bridge for the method in question,
+ * and we reset insns to NULL, the VM will crash.  (See the comments above
+ * dvmSetNativeFunc() for additional commentary.)
+ *
+ * We can't rely on being able to update two 32-bit fields in one atomic
+ * operation (e.g. no 64-bit atomic ops on ARMv5TE), so we want to change
+ * only one field.  It turns out we can simply reset nativeFunc to its
+ * initial state, leaving insns alone, because dvmResolveNativeMethod
+ * ignores "insns" entirely.
+ *
+ * When the method is re-registered, both fields will be updated, but
+ * dvmSetNativeFunc guarantees that "insns" is updated first.  This means
+ * we shouldn't be in a situation where we have a "live" call bridge and
+ * a stale implementation pointer.
+ */
+static void unregisterJNINativeMethods(Method* methods, size_t count)
+{
+    while (count != 0) {
+        count--;
+
+        Method* meth = &methods[count];
+        if (!dvmIsNativeMethod(meth))
+            continue;
+        if (dvmIsAbstractMethod(meth))      /* avoid abstract method stubs */
+            continue;
+
+        /*
+         * Strictly speaking this ought to test the function pointer against
+         * the various JNI bridge functions to ensure that we only undo
+         * methods that were registered through JNI.  In practice, any
+         * native method with a non-NULL "insns" is a registered JNI method.
+         *
+         * If we inadvertently unregister an internal-native, it'll get
+         * re-resolved on the next call; unregistering an unregistered
+         * JNI method is a no-op.  So we don't really need to test for
+         * anything.
+         */
+
+        LOGD("Unregistering JNI method %s.%s:%s",
+            meth->clazz->descriptor, meth->name, meth->shorty);
+        dvmSetNativeFunc(meth, dvmResolveNativeMethod, NULL);
+    }
+}
+
+/*
+ * Un-register all JNI native methods from a class.
+ */
+void dvmUnregisterJNINativeMethods(ClassObject* clazz)
+{
+    unregisterJNINativeMethods(clazz->directMethods, clazz->directMethodCount);
+    unregisterJNINativeMethods(clazz->virtualMethods, clazz->virtualMethodCount);
+}
+
+
+/*
+ * ===========================================================================
+ *      Signature-based method lookup
+ * ===========================================================================
+ */
+
+/*
+ * Create the pre-mangled form of the class+method string.
+ *
+ * Returns a newly-allocated string, and sets "*pLen" to the length.
+ */
+static char* createJniNameString(const char* classDescriptor,
+    const char* methodName, int* pLen)
+{
+    char* result;
+    size_t descriptorLength = strlen(classDescriptor);
+
+    *pLen = 4 + descriptorLength + strlen(methodName);
+
+    result = (char*)malloc(*pLen +1);
+    if (result == NULL)
+        return NULL;
+
+    /*
+     * Add one to classDescriptor to skip the "L", and then replace
+     * the final ";" with a "/" after the sprintf() call.
+     */
+    sprintf(result, "Java/%s%s", classDescriptor + 1, methodName);
+    result[5 + (descriptorLength - 2)] = '/';
+
+    return result;
+}
+
+/*
+ * Returns a newly-allocated, mangled copy of "str".
+ *
+ * "str" is a "modified UTF-8" string.  We convert it to UTF-16 first to
+ * make life simpler.
+ */
+static char* mangleString(const char* str, int len)
+{
+    //LOGI("mangling '%s' %d", str, len);
+
+    assert(str[len] == '\0');
+
+    size_t charLen = dvmUtf8Len(str);
+    u2* utf16 = (u2*) malloc(sizeof(u2) * charLen);
+    if (utf16 == NULL)
+        return NULL;
+
+    dvmConvertUtf8ToUtf16(utf16, str);
+
+    /*
+     * Compute the length of the mangled string.
+     */
+    size_t mangleLen = 0;
+    for (size_t i = 0; i < charLen; i++) {
+        u2 ch = utf16[i];
+
+        if (ch == '$' || ch > 127) {
+            mangleLen += 6;
+        } else {
+            switch (ch) {
+            case '_':
+            case ';':
+            case '[':
+                mangleLen += 2;
+                break;
+            default:
+                mangleLen++;
+                break;
+            }
+        }
+    }
+
+    char* mangle = (char*) malloc(mangleLen +1);
+    if (mangle == NULL) {
+        free(utf16);
+        return NULL;
+    }
+
+    char* cp = mangle;
+    for (size_t i = 0; i < charLen; i++) {
+        u2 ch = utf16[i];
+
+        if (ch == '$' || ch > 127) {
+            sprintf(cp, "_0%04x", ch);
+            cp += 6;
+        } else {
+            switch (ch) {
+            case '_':
+                *cp++ = '_';
+                *cp++ = '1';
+                break;
+            case ';':
+                *cp++ = '_';
+                *cp++ = '2';
+                break;
+            case '[':
+                *cp++ = '_';
+                *cp++ = '3';
+                break;
+            case '/':
+                *cp++ = '_';
+                break;
+            default:
+                *cp++ = (char) ch;
+                break;
+            }
+        }
+    }
+
+    *cp = '\0';
+
+    free(utf16);
+    return mangle;
+}
+
+/*
+ * Create the mangled form of the parameter types.
+ */
+static char* createMangledSignature(const DexProto* proto)
+{
+    DexStringCache sigCache;
+    const char* interim;
+    char* result;
+
+    dexStringCacheInit(&sigCache);
+    interim = dexProtoGetParameterDescriptors(proto, &sigCache);
+    result = mangleString(interim, strlen(interim));
+    dexStringCacheRelease(&sigCache);
+
+    return result;
+}
+
+/*
+ * (This is a dvmHashForeach callback.)
+ *
+ * Search for a matching method in this shared library.
+ *
+ * TODO: we may want to skip libraries for which JNI_OnLoad failed.
+ */
+static int findMethodInLib(void* vlib, void* vmethod)
+{
+    const SharedLib* pLib = (const SharedLib*) vlib;
+    const Method* meth = (const Method*) vmethod;
+    char* preMangleCM = NULL;
+    char* mangleCM = NULL;
+    char* mangleSig = NULL;
+    char* mangleCMSig = NULL;
+    void* func = NULL;
+    int len;
+
+    if (meth->clazz->classLoader != pLib->classLoader) {
+        LOGV("+++ not scanning '%s' for '%s' (wrong CL)",
+            pLib->pathName, meth->name);
+        return 0;
+    } else
+        LOGV("+++ scanning '%s' for '%s'", pLib->pathName, meth->name);
+
+    /*
+     * First, we try it without the signature.
+     */
+    preMangleCM =
+        createJniNameString(meth->clazz->descriptor, meth->name, &len);
+    if (preMangleCM == NULL)
+        goto bail;
+
+    mangleCM = mangleString(preMangleCM, len);
+    if (mangleCM == NULL)
+        goto bail;
+
+    LOGV("+++ calling dlsym(%s)", mangleCM);
+    func = dlsym(pLib->handle, mangleCM);
+    if (func == NULL) {
+        mangleSig =
+            createMangledSignature(&meth->prototype);
+        if (mangleSig == NULL)
+            goto bail;
+
+        mangleCMSig = (char*) malloc(strlen(mangleCM) + strlen(mangleSig) +3);
+        if (mangleCMSig == NULL)
+            goto bail;
+
+        sprintf(mangleCMSig, "%s__%s", mangleCM, mangleSig);
+
+        LOGV("+++ calling dlsym(%s)", mangleCMSig);
+        func = dlsym(pLib->handle, mangleCMSig);
+        if (func != NULL) {
+            LOGV("Found '%s' with dlsym", mangleCMSig);
+        }
+    } else {
+        LOGV("Found '%s' with dlsym", mangleCM);
+    }
+
+bail:
+    free(preMangleCM);
+    free(mangleCM);
+    free(mangleSig);
+    free(mangleCMSig);
+    return (int) func;
+}
+
+/*
+ * See if the requested method lives in any of the currently-loaded
+ * shared libraries.  We do this by checking each of them for the expected
+ * method signature.
+ */
+static void* lookupSharedLibMethod(const Method* method)
+{
+    if (gDvm.nativeLibs == NULL) {
+        LOGE("Unexpected init state: nativeLibs not ready");
+        dvmAbort();
+    }
+    return (void*) dvmHashForeach(gDvm.nativeLibs, findMethodInLib,
+        (void*) method);
+}
diff --git a/vm/Native.h b/vm/Native.h
new file mode 100644
index 0000000..65ff8dc
--- /dev/null
+++ b/vm/Native.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+/*
+ * Dalvik's native call interface.
+ *
+ * You should follow the JNI function naming conventions, but prefix with
+ * "Dalvik_" instead of "Java_".
+ */
+#ifndef DALVIK_NATIVE_H_
+#define DALVIK_NATIVE_H_
+
+/*
+ * Method description; equivalent to a JNI struct.
+ */
+struct DalvikNativeMethod {
+    const char* name;
+    const char* signature;
+    DalvikNativeFunc  fnPtr;
+};
+
+/*
+ * All methods for one class.  The last "methodInfo" has a NULL "name".
+ */
+struct DalvikNativeClass {
+    const char* classDescriptor;
+    const DalvikNativeMethod* methodInfo;
+    u4          classDescriptorHash;          /* initialized at runtime */
+};
+
+
+/* init/shutdown */
+bool dvmNativeStartup(void);
+void dvmNativeShutdown(void);
+
+
+/*
+ * Convert argc/argv into a function call.  This is platform-specific.
+ */
+extern "C" void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo,
+    int argc, const u4* argv, const char* signature, void* func, JValue* pResult);
+
+/*
+ * Generate hints to speed native calls.  This is platform specific.
+ */
+u4 dvmPlatformInvokeHints(const DexProto* proto);
+
+/*
+ * Convert a short library name ("jpeg") to a system-dependent name
+ * ("libjpeg.so").  Returns a newly-allocated string.
+ */
+char* dvmCreateSystemLibraryName(char* libName);
+bool dvmLoadNativeCode(const char* fileName, Object* classLoader,
+        char** detail);
+
+
+/*
+ * Resolve a native method.  This uses the same prototype as a
+ * DalvikBridgeFunc, because it takes the place of the actual function
+ * until the first time that it's invoked.
+ *
+ * Causes the method's class to be initialized.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+void dvmResolveNativeMethod(const u4* args, JValue* pResult,
+    const Method* method, struct Thread* self);
+
+/*
+ * Unregister all JNI native methods associated with a class.
+ */
+void dvmUnregisterJNINativeMethods(ClassObject* clazz);
+
+#define GET_ARG_LONG(_args, _elem)          dvmGetArgLong(_args, _elem)
+
+/*
+ * Helpful function for accessing long integers in "u4* args".
+ *
+ * We can't just return *(s8*)(&args[elem]), because that breaks if our
+ * architecture requires 64-bit alignment of 64-bit values.
+ *
+ * Big/little endian shouldn't matter here -- ordering of words within a
+ * long seems consistent across our supported platforms.
+ */
+INLINE s8 dvmGetArgLong(const u4* args, int elem)
+{
+    s8 val;
+    memcpy(&val, &args[elem], sizeof(val));
+    return val;
+}
+
+#endif  // DALVIK_NATIVE_H_
diff --git a/vm/PointerSet.cpp b/vm/PointerSet.cpp
new file mode 100644
index 0000000..4f3d7d5
--- /dev/null
+++ b/vm/PointerSet.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+/*
+ * Maintain an expanding set of unique pointer values.
+ */
+#include "Dalvik.h"
+
+/*
+ * Sorted, expanding list of pointers.
+ */
+struct PointerSet {
+    u2          alloc;
+    u2          count;
+    const void** list;
+};
+
+/*
+ * Verify that the set is in sorted order.
+ */
+#ifndef NDEBUG
+static bool verifySorted(PointerSet* pSet)
+{
+    const void* last = NULL;
+    int i;
+
+    for (i = 0; i < pSet->count; i++) {
+        const void* cur = pSet->list[i];
+        if (cur < last)
+            return false;
+        last = cur;
+    }
+
+    return true;
+}
+#endif
+
+/*
+ * Allocate a new PointerSet.
+ *
+ * Returns NULL on failure.
+ */
+PointerSet* dvmPointerSetAlloc(int initialSize)
+{
+    PointerSet* pSet = (PointerSet*)calloc(1, sizeof(PointerSet));
+    if (pSet != NULL) {
+        if (initialSize > 0) {
+            pSet->list = (const void**)malloc(sizeof(void*) * initialSize);
+            if (pSet->list == NULL) {
+                free(pSet);
+                return NULL;
+            }
+            pSet->alloc = initialSize;
+        }
+    }
+
+    return pSet;
+}
+
+/*
+ * Free up a PointerSet.
+ */
+void dvmPointerSetFree(PointerSet* pSet)
+{
+    if (pSet == NULL)
+        return;
+
+    if (pSet->list != NULL) {
+        free(pSet->list);
+        pSet->list = NULL;
+    }
+    free(pSet);
+}
+
+/*
+ * Clear the contents of a pointer set.
+ */
+void dvmPointerSetClear(PointerSet* pSet)
+{
+    pSet->count = 0;
+}
+
+/*
+ * Get the number of pointers currently stored in the list.
+ */
+int dvmPointerSetGetCount(const PointerSet* pSet)
+{
+    return pSet->count;
+}
+
+/*
+ * Get the Nth entry from the list.
+ */
+const void* dvmPointerSetGetEntry(const PointerSet* pSet, int i)
+{
+    return pSet->list[i];
+}
+
+/*
+ * Insert a new entry into the list.  If it already exists, this returns
+ * without doing anything.
+ *
+ * Returns "true" if the value was added.
+ */
+bool dvmPointerSetAddEntry(PointerSet* pSet, const void* ptr)
+{
+    int nearby;
+
+    if (dvmPointerSetHas(pSet, ptr, &nearby))
+        return false;
+
+    /* ensure we have space to add one more */
+    if (pSet->count == pSet->alloc) {
+        /* time to expand */
+        const void** newList;
+
+        if (pSet->alloc == 0)
+            pSet->alloc = 4;
+        else
+            pSet->alloc *= 2;
+        LOGVV("expanding %p to %d", pSet, pSet->alloc);
+        newList = (const void**)realloc(pSet->list, pSet->alloc * sizeof(void*));
+        if (newList == NULL) {
+            LOGE("Failed expanding ptr set (alloc=%d)", pSet->alloc);
+            dvmAbort();
+        }
+        pSet->list = newList;
+    }
+
+    if (pSet->count == 0) {
+        /* empty list */
+        assert(nearby == 0);
+    } else {
+        /*
+         * Determine the insertion index.  The binary search might have
+         * terminated "above" or "below" the value.
+         */
+        if (nearby != 0 && ptr < pSet->list[nearby-1]) {
+            //LOGD("nearby-1=%d %p, inserting %p at -1",
+            //    nearby-1, pSet->list[nearby-1], ptr);
+            nearby--;
+        } else if (ptr < pSet->list[nearby]) {
+            //LOGD("nearby=%d %p, inserting %p at +0",
+            //    nearby, pSet->list[nearby], ptr);
+        } else {
+            //LOGD("nearby+1=%d %p, inserting %p at +1",
+            //    nearby+1, pSet->list[nearby+1], ptr);
+            nearby++;
+        }
+
+        /*
+         * Move existing values, if necessary.
+         */
+        if (nearby != pSet->count) {
+            /* shift up */
+            memmove(&pSet->list[nearby+1], &pSet->list[nearby],
+                (pSet->count - nearby) * sizeof(pSet->list[0]));
+        }
+    }
+
+    pSet->list[nearby] = ptr;
+    pSet->count++;
+
+    assert(verifySorted(pSet));
+    return true;
+}
+
+/*
+ * Returns "true" if the element was successfully removed.
+ */
+bool dvmPointerSetRemoveEntry(PointerSet* pSet, const void* ptr)
+{
+    int where;
+
+    if (!dvmPointerSetHas(pSet, ptr, &where))
+        return false;
+
+    if (where != pSet->count-1) {
+        /* shift down */
+        memmove(&pSet->list[where], &pSet->list[where+1],
+            (pSet->count-1 - where) * sizeof(pSet->list[0]));
+    }
+
+    pSet->count--;
+    pSet->list[pSet->count] = (const void*) 0xdecadead;     // debug
+    return true;
+}
+
+/*
+ * Returns the index if "ptr" appears in the list.  If it doesn't appear,
+ * this returns a negative index for a nearby element.
+ */
+bool dvmPointerSetHas(const PointerSet* pSet, const void* ptr, int* pIndex)
+{
+    int hi, lo, mid;
+
+    lo = mid = 0;
+    hi = pSet->count-1;
+
+    /* array is sorted, use a binary search */
+    while (lo <= hi) {
+        mid = (lo + hi) / 2;
+        const void* listVal = pSet->list[mid];
+
+        if (ptr > listVal) {
+            lo = mid + 1;
+        } else if (ptr < listVal) {
+            hi = mid - 1;
+        } else /* listVal == ptr */ {
+            if (pIndex != NULL)
+                *pIndex = mid;
+            return true;
+        }
+    }
+
+    if (pIndex != NULL)
+        *pIndex = mid;
+    return false;
+}
+
+/*
+ * Compute the intersection of the set and the array of pointers passed in.
+ *
+ * Any pointer in "pSet" that does not appear in "ptrArray" is removed.
+ */
+void dvmPointerSetIntersect(PointerSet* pSet, const void** ptrArray, int count)
+{
+    int i, j;
+
+    for (i = 0; i < pSet->count; i++) {
+        for (j = 0; j < count; j++) {
+            if (pSet->list[i] == ptrArray[j]) {
+                /* match, keep this one */
+                break;
+            }
+        }
+
+        if (j == count) {
+            /* no match, remove entry */
+            if (i != pSet->count-1) {
+                /* shift down */
+                memmove(&pSet->list[i], &pSet->list[i+1],
+                    (pSet->count-1 - i) * sizeof(pSet->list[0]));
+            }
+
+            pSet->count--;
+            pSet->list[pSet->count] = (const void*) 0xdecadead;     // debug
+            i--;        /* adjust loop counter */
+        }
+    }
+}
+
+/*
+ * Print the list contents to stdout.  For debugging.
+ */
+void dvmPointerSetDump(const PointerSet* pSet)
+{
+    LOGI("PointerSet %p", pSet);
+    int i;
+    for (i = 0; i < pSet->count; i++)
+        LOGI(" %2d: %p", i, pSet->list[i]);
+}
diff --git a/vm/PointerSet.h b/vm/PointerSet.h
new file mode 100644
index 0000000..7a1cddf
--- /dev/null
+++ b/vm/PointerSet.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+/*
+ * Maintain an expanding set of unique pointer values.  The set is
+ * kept in sorted order.
+ */
+#ifndef DALVIK_POINTERSET_H_
+#define DALVIK_POINTERSET_H_
+
+struct PointerSet;   /* private */
+
+/*
+ * Allocate a new PointerSet.
+ *
+ * Returns NULL on failure.
+ */
+PointerSet* dvmPointerSetAlloc(int initialSize);
+
+/*
+ * Free up a PointerSet.
+ */
+void dvmPointerSetFree(PointerSet* pSet);
+
+/*
+ * Clear the contents of a pointer set.
+ */
+void dvmPointerSetClear(PointerSet* pSet);
+
+/*
+ * Get the number of pointers currently stored in the list.
+ */
+int dvmPointerSetGetCount(const PointerSet* pSet);
+
+/*
+ * Get the Nth entry from the list.
+ */
+const void* dvmPointerSetGetEntry(const PointerSet* pSet, int i);
+
+/*
+ * Insert a new entry into the list.  If it already exists, this returns
+ * without doing anything.
+ *
+ * Returns "true" if the pointer was added.
+ */
+bool dvmPointerSetAddEntry(PointerSet* pSet, const void* ptr);
+
+/*
+ * Returns "true" if the element was successfully removed.
+ */
+bool dvmPointerSetRemoveEntry(PointerSet* pSet, const void* ptr);
+
+/*
+ * Returns "true" if the value appears, "false" otherwise.  If "pIndex" is
+ * non-NULL, it will receive the matching index or the index of a nearby
+ * element.
+ */
+bool dvmPointerSetHas(const PointerSet* pSet, const void* ptr, int* pIndex);
+
+/*
+ * Find an entry in the set.  Returns the index, or -1 if not found.
+ */
+INLINE int dvmPointerSetFind(const PointerSet* pSet, const void* ptr) {
+    int idx;
+    if (!dvmPointerSetHas(pSet, ptr, &idx))
+        idx = -1;
+    return idx;
+}
+
+/*
+ * Compute the intersection of the set and the array of pointers passed in.
+ *
+ * Any pointer in "pSet" that does not appear in "ptrArray" is removed.
+ */
+void dvmPointerSetIntersect(PointerSet* pSet, const void** ptrArray, int count);
+
+/*
+ * Print the list contents to stdout.  For debugging.
+ */
+void dvmPointerSetDump(const PointerSet* pSet);
+
+#endif  // DALVIK_POINTERSET_H_
diff --git a/vm/Profile.cpp b/vm/Profile.cpp
new file mode 100644
index 0000000..e1dfc43
--- /dev/null
+++ b/vm/Profile.cpp
@@ -0,0 +1,1008 @@
+/*
+ * 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.
+ */
+
+/*
+ * Android's method call profiling goodies.
+ */
+#include "Dalvik.h"
+#include <interp/InterpDefs.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sched.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <cutils/open_memstream.h>
+
+#ifdef HAVE_ANDROID_OS
+# define UPDATE_MAGIC_PAGE      1
+#endif
+
+/*
+ * File format:
+ *  header
+ *  record 0
+ *  record 1
+ *  ...
+ *
+ * Header format:
+ *  u4  magic ('SLOW')
+ *  u2  version
+ *  u2  offset to data
+ *  u8  start date/time in usec
+ *  u2  record size in bytes (version >= 2 only)
+ *  ... padding to 32 bytes
+ *
+ * Record format v1:
+ *  u1  thread ID
+ *  u4  method ID | method action
+ *  u4  time delta since start, in usec
+ *
+ * Record format v2:
+ *  u2  thread ID
+ *  u4  method ID | method action
+ *  u4  time delta since start, in usec
+ *
+ * Record format v3:
+ *  u2  thread ID
+ *  u4  method ID | method action
+ *  u4  time delta since start, in usec
+ *  u4  wall time since start, in usec (when clock == "dual" only)
+ *
+ * 32 bits of microseconds is 70 minutes.
+ *
+ * All values are stored in little-endian order.
+ */
+#define TRACE_REC_SIZE_SINGLE_CLOCK  10 // using v2
+#define TRACE_REC_SIZE_DUAL_CLOCK    14 // using v3 with two timestamps
+#define TRACE_MAGIC         0x574f4c53
+#define TRACE_HEADER_LEN    32
+
+#define FILL_PATTERN        0xeeeeeeee
+
+
+/*
+ * Returns true if the thread CPU clock should be used.
+ */
+static inline bool useThreadCpuClock() {
+#if defined(HAVE_POSIX_CLOCKS)
+    return gDvm.profilerClockSource != kProfilerClockSourceWall;
+#else
+    return false;
+#endif
+}
+
+/*
+ * Returns true if the wall clock should be used.
+ */
+static inline bool useWallClock() {
+#if defined(HAVE_POSIX_CLOCKS)
+    return gDvm.profilerClockSource != kProfilerClockSourceThreadCpu;
+#else
+    return true;
+#endif
+}
+
+/*
+ * Get the wall-clock date/time, in usec.
+ */
+static inline u8 getWallTimeInUsec()
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+
+#if defined(HAVE_POSIX_CLOCKS)
+/*
+ * Get the thread-cpu time, in usec.
+ * We use this clock when we can because it enables us to track the time that
+ * a thread spends running and not blocked.
+ */
+static inline u8 getThreadCpuTimeInUsec()
+{
+    struct timespec tm;
+
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
+    if (!(tm.tv_nsec >= 0 && tm.tv_nsec < 1*1000*1000*1000)) {
+        LOGE("bad nsec: %ld", tm.tv_nsec);
+        dvmAbort();
+    }
+    return tm.tv_sec * 1000000LL + tm.tv_nsec / 1000;
+}
+#endif
+
+/*
+ * Get the clock used for stopwatch-like timing measurements on a single thread.
+ */
+static inline u8 getStopwatchClock()
+{
+#if defined(HAVE_POSIX_CLOCKS)
+    return getThreadCpuTimeInUsec();
+#else
+    return getWallTimeInUsec();
+#endif
+}
+
+/*
+ * Write little-endian data.
+ */
+static inline void storeShortLE(u1* buf, u2 val)
+{
+    *buf++ = (u1) val;
+    *buf++ = (u1) (val >> 8);
+}
+static inline void storeIntLE(u1* buf, u4 val)
+{
+    *buf++ = (u1) val;
+    *buf++ = (u1) (val >> 8);
+    *buf++ = (u1) (val >> 16);
+    *buf++ = (u1) (val >> 24);
+}
+static inline void storeLongLE(u1* buf, u8 val)
+{
+    *buf++ = (u1) val;
+    *buf++ = (u1) (val >> 8);
+    *buf++ = (u1) (val >> 16);
+    *buf++ = (u1) (val >> 24);
+    *buf++ = (u1) (val >> 32);
+    *buf++ = (u1) (val >> 40);
+    *buf++ = (u1) (val >> 48);
+    *buf++ = (u1) (val >> 56);
+}
+
+/*
+ * Boot-time init.
+ */
+bool dvmProfilingStartup()
+{
+    /*
+     * Initialize "dmtrace" method profiling.
+     */
+    memset(&gDvm.methodTrace, 0, sizeof(gDvm.methodTrace));
+    dvmInitMutex(&gDvm.methodTrace.startStopLock);
+    pthread_cond_init(&gDvm.methodTrace.threadExitCond, NULL);
+
+    assert(!dvmCheckException(dvmThreadSelf()));
+
+    /*
+     * Allocate storage for instruction counters.
+     */
+    gDvm.executedInstrCounts = (int*) malloc(kNumPackedOpcodes * sizeof(int));
+    if (gDvm.executedInstrCounts == NULL)
+        return false;
+    memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
+
+#ifdef UPDATE_MAGIC_PAGE
+    /*
+     * If we're running on the emulator, there's a magic page into which
+     * we can put interpreted method information.  This allows interpreted
+     * methods to show up in the emulator's code traces.
+     *
+     * We could key this off of the "ro.kernel.qemu" property, but there's
+     * no real harm in doing this on a real device.
+     */
+    int fd = open("/dev/qemu_trace", O_RDWR);
+    if (fd < 0) {
+        LOGV("Unable to open /dev/qemu_trace");
+    } else {
+        gDvm.emulatorTracePage = mmap(0, SYSTEM_PAGE_SIZE, PROT_READ|PROT_WRITE,
+                                      MAP_SHARED, fd, 0);
+        close(fd);
+        if (gDvm.emulatorTracePage == MAP_FAILED) {
+            LOGE("Unable to mmap /dev/qemu_trace");
+            gDvm.emulatorTracePage = NULL;
+        } else {
+            *(u4*) gDvm.emulatorTracePage = 0;
+        }
+    }
+#else
+    assert(gDvm.emulatorTracePage == NULL);
+#endif
+
+    return true;
+}
+
+/*
+ * Free up profiling resources.
+ */
+void dvmProfilingShutdown()
+{
+#ifdef UPDATE_MAGIC_PAGE
+    if (gDvm.emulatorTracePage != NULL)
+        munmap(gDvm.emulatorTracePage, SYSTEM_PAGE_SIZE);
+#endif
+    free(gDvm.executedInstrCounts);
+}
+
+/*
+ * Update the set of active profilers
+ */
+static void updateActiveProfilers(ExecutionSubModes newMode, bool enable)
+{
+    int oldValue, newValue;
+
+    // Update global count
+    do {
+        oldValue = gDvm.activeProfilers;
+        newValue = oldValue + (enable ? 1 : -1);
+        if (newValue < 0) {
+            LOGE("Can't have %d active profilers", newValue);
+            dvmAbort();
+        }
+    } while (android_atomic_release_cas(oldValue, newValue,
+            &gDvm.activeProfilers) != 0);
+
+    // Tell the threads
+    if (enable) {
+        dvmEnableAllSubMode(newMode);
+    } else {
+        dvmDisableAllSubMode(newMode);
+    }
+
+#if defined(WITH_JIT)
+    dvmCompilerUpdateGlobalState();
+#endif
+
+    LOGD("+++ active profiler count now %d", newValue);
+}
+
+
+/*
+ * Reset the "cpuClockBase" field in all threads.
+ */
+static void resetCpuClockBase()
+{
+    Thread* thread;
+
+    dvmLockThreadList(NULL);
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        thread->cpuClockBaseSet = false;
+        thread->cpuClockBase = 0;
+    }
+    dvmUnlockThreadList();
+}
+
+/*
+ * Dump the thread list to the specified file.
+ */
+static void dumpThreadList(FILE* fp) {
+    dvmLockThreadList(NULL);
+    for (Thread* thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        std::string threadName(dvmGetThreadName(thread));
+        fprintf(fp, "%d\t%s\n", thread->threadId, threadName.c_str());
+    }
+    dvmUnlockThreadList();
+}
+
+/*
+ * This is a dvmHashForeach callback.
+ */
+static int dumpMarkedMethods(void* vclazz, void* vfp)
+{
+    DexStringCache stringCache;
+    ClassObject* clazz = (ClassObject*) vclazz;
+    FILE* fp = (FILE*) vfp;
+    Method* meth;
+    char* name;
+    int i;
+
+    dexStringCacheInit(&stringCache);
+
+    for (i = 0; i < clazz->virtualMethodCount; i++) {
+        meth = &clazz->virtualMethods[i];
+        if (meth->inProfile) {
+            name = dvmDescriptorToName(meth->clazz->descriptor);
+            fprintf(fp, "0x%08x\t%s\t%s\t%s\t%s\t%d\n", (int) meth,
+                name, meth->name,
+                dexProtoGetMethodDescriptor(&meth->prototype, &stringCache),
+                dvmGetMethodSourceFile(meth), dvmLineNumFromPC(meth, 0));
+            meth->inProfile = false;
+            free(name);
+        }
+    }
+
+    for (i = 0; i < clazz->directMethodCount; i++) {
+        meth = &clazz->directMethods[i];
+        if (meth->inProfile) {
+            name = dvmDescriptorToName(meth->clazz->descriptor);
+            fprintf(fp, "0x%08x\t%s\t%s\t%s\t%s\t%d\n", (int) meth,
+                name, meth->name,
+                dexProtoGetMethodDescriptor(&meth->prototype, &stringCache),
+                dvmGetMethodSourceFile(meth), dvmLineNumFromPC(meth, 0));
+            meth->inProfile = false;
+            free(name);
+        }
+    }
+
+    dexStringCacheRelease(&stringCache);
+
+    return 0;
+}
+
+/*
+ * Dump the list of "marked" methods to the specified file.
+ */
+static void dumpMethodList(FILE* fp)
+{
+    dvmHashTableLock(gDvm.loadedClasses);
+    dvmHashForeach(gDvm.loadedClasses, dumpMarkedMethods, (void*) fp);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+}
+
+/*
+ * Start method tracing.  Method tracing is global to the VM (i.e. we
+ * trace all threads).
+ *
+ * This opens the output file (if an already open fd has not been supplied,
+ * and we're not going direct to DDMS) and allocates the data buffer.  This
+ * takes ownership of the file descriptor, closing it on completion.
+ *
+ * On failure, we throw an exception and return.
+ */
+void dvmMethodTraceStart(const char* traceFileName, int traceFd, int bufferSize,
+    int flags, bool directToDdms)
+{
+    MethodTraceState* state = &gDvm.methodTrace;
+
+    assert(bufferSize > 0);
+
+    dvmLockMutex(&state->startStopLock);
+    while (state->traceEnabled != 0) {
+        LOGI("TRACE start requested, but already in progress; stopping");
+        dvmUnlockMutex(&state->startStopLock);
+        dvmMethodTraceStop();
+        dvmLockMutex(&state->startStopLock);
+    }
+    LOGI("TRACE STARTED: '%s' %dKB", traceFileName, bufferSize / 1024);
+
+    /*
+     * Allocate storage and open files.
+     *
+     * We don't need to initialize the buffer, but doing so might remove
+     * some fault overhead if the pages aren't mapped until touched.
+     */
+    state->buf = (u1*) malloc(bufferSize);
+    if (state->buf == NULL) {
+        dvmThrowInternalError("buffer alloc failed");
+        goto fail;
+    }
+    if (!directToDdms) {
+        if (traceFd < 0) {
+            state->traceFile = fopen(traceFileName, "w");
+        } else {
+            state->traceFile = fdopen(traceFd, "w");
+        }
+        if (state->traceFile == NULL) {
+            int err = errno;
+            LOGE("Unable to open trace file '%s': %s",
+                traceFileName, strerror(err));
+            dvmThrowExceptionFmt(gDvm.exRuntimeException,
+                "Unable to open trace file '%s': %s",
+                traceFileName, strerror(err));
+            goto fail;
+        }
+    }
+    traceFd = -1;
+    memset(state->buf, (char)FILL_PATTERN, bufferSize);
+
+    state->directToDdms = directToDdms;
+    state->bufferSize = bufferSize;
+    state->overflow = false;
+
+    /*
+     * Enable alloc counts if we've been requested to do so.
+     */
+    state->flags = flags;
+    if ((flags & TRACE_ALLOC_COUNTS) != 0)
+        dvmStartAllocCounting();
+
+    /* reset our notion of the start time for all CPU threads */
+    resetCpuClockBase();
+
+    state->startWhen = getWallTimeInUsec();
+
+    if (useThreadCpuClock() && useWallClock()) {
+        state->traceVersion = 3;
+        state->recordSize = TRACE_REC_SIZE_DUAL_CLOCK;
+    } else {
+        state->traceVersion = 2;
+        state->recordSize = TRACE_REC_SIZE_SINGLE_CLOCK;
+    }
+
+    /*
+     * Output the header.
+     */
+    memset(state->buf, 0, TRACE_HEADER_LEN);
+    storeIntLE(state->buf + 0, TRACE_MAGIC);
+    storeShortLE(state->buf + 4, state->traceVersion);
+    storeShortLE(state->buf + 6, TRACE_HEADER_LEN);
+    storeLongLE(state->buf + 8, state->startWhen);
+    if (state->traceVersion >= 3) {
+        storeShortLE(state->buf + 16, state->recordSize);
+    }
+    state->curOffset = TRACE_HEADER_LEN;
+
+    /*
+     * Set the "enabled" flag.  Once we do this, threads will wait to be
+     * signaled before exiting, so we have to make sure we wake them up.
+     */
+    android_atomic_release_store(true, &state->traceEnabled);
+
+    /*
+     * ENHANCEMENT: To trace just a single thread, modify the
+     * following to take a Thread* argument, and set the appropriate
+     * interpBreak flags only on the target thread.
+     */
+    updateActiveProfilers(kSubModeMethodTrace, true);
+
+    dvmUnlockMutex(&state->startStopLock);
+    return;
+
+fail:
+    if (state->traceFile != NULL) {
+        fclose(state->traceFile);
+        state->traceFile = NULL;
+    }
+    if (state->buf != NULL) {
+        free(state->buf);
+        state->buf = NULL;
+    }
+    if (traceFd >= 0)
+        close(traceFd);
+    dvmUnlockMutex(&state->startStopLock);
+}
+
+/*
+ * 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(int endOffset)
+{
+    u1* ptr = gDvm.methodTrace.buf + TRACE_HEADER_LEN;
+    u1* end = gDvm.methodTrace.buf + endOffset;
+    size_t recordSize = gDvm.methodTrace.recordSize;
+    unsigned int methodVal;
+    Method* method;
+
+    while (ptr < end) {
+        methodVal = ptr[2] | (ptr[3] << 8) | (ptr[4] << 16)
+                    | (ptr[5] << 24);
+        method = (Method*) METHOD_ID(methodVal);
+
+        method->inProfile = true;
+        ptr += recordSize;
+    }
+}
+
+/*
+ * Exercises the clocks in the same way they will be during profiling.
+ */
+static inline void measureClockOverhead()
+{
+#if defined(HAVE_POSIX_CLOCKS)
+    if (useThreadCpuClock()) {
+        getThreadCpuTimeInUsec();
+    }
+#endif
+    if (useWallClock()) {
+        getWallTimeInUsec();
+    }
+}
+
+/*
+ * Compute the amount of overhead in a clock call, in nsec.
+ *
+ * This value is going to vary depending on what else is going on in the
+ * system.  When examined across several runs a pattern should emerge.
+ */
+static u4 getClockOverhead()
+{
+    u8 calStart, calElapsed;
+    int i;
+
+    calStart = getStopwatchClock();
+    for (i = 1000 * 4; i > 0; i--) {
+        measureClockOverhead();
+        measureClockOverhead();
+        measureClockOverhead();
+        measureClockOverhead();
+        measureClockOverhead();
+        measureClockOverhead();
+        measureClockOverhead();
+        measureClockOverhead();
+    }
+
+    calElapsed = getStopwatchClock() - calStart;
+    return (int) (calElapsed / (8*4));
+}
+
+/*
+ * Returns "true" if method tracing is currently active.
+ */
+bool dvmIsMethodTraceActive()
+{
+    const MethodTraceState* state = &gDvm.methodTrace;
+    return state->traceEnabled;
+}
+
+/*
+ * Stop method tracing.  We write the buffer to disk and generate a key
+ * file so we can interpret it.
+ */
+void dvmMethodTraceStop()
+{
+    MethodTraceState* state = &gDvm.methodTrace;
+    u8 elapsed;
+
+    /*
+     * We need this to prevent somebody from starting a new trace while
+     * we're in the process of stopping the old.
+     */
+    dvmLockMutex(&state->startStopLock);
+
+    if (!state->traceEnabled) {
+        /* somebody already stopped it, or it was never started */
+        LOGD("TRACE stop requested, but not running");
+        dvmUnlockMutex(&state->startStopLock);
+        return;
+    } else {
+        updateActiveProfilers(kSubModeMethodTrace, false);
+    }
+
+    /* compute elapsed time */
+    elapsed = getWallTimeInUsec() - state->startWhen;
+
+    /*
+     * Globally disable it, and allow other threads to notice.  We want
+     * to stall here for at least as long as dvmMethodTraceAdd needs
+     * to finish.  There's no real risk though -- it will take a while to
+     * write the data to disk, and we don't clear the buffer pointer until
+     * after that completes.
+     */
+    state->traceEnabled = false;
+    ANDROID_MEMBAR_FULL();
+    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;
+
+    size_t recordSize = state->recordSize;
+    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[2] | (scanPtr[3] << 8) | (scanPtr[4] << 16)
+                        | (scanPtr[5] << 24);
+            if (METHOD_ID(methodVal) == fillVal) {
+                u1* scanBase = state->buf + TRACE_HEADER_LEN;
+                LOGW("Found unfilled record at %d (of %d)",
+                    (scanPtr - scanBase) / recordSize,
+                    (finalCurOffset - TRACE_HEADER_LEN) / recordSize);
+                finalCurOffset = scanPtr - state->buf;
+                break;
+            }
+
+            scanPtr += recordSize;
+        }
+    }
+
+    LOGI("TRACE STOPPED%s: writing %d records",
+        state->overflow ? " (NOTE: overflowed buffer)" : "",
+        (finalCurOffset - TRACE_HEADER_LEN) / recordSize);
+    if (gDvm.debuggerActive) {
+        LOGW("WARNING: a debugger is active; method-tracing results "
+             "will be skewed");
+    }
+
+    /*
+     * Do a quick calibration test to see how expensive our clock call is.
+     */
+    u4 clockNsec = getClockOverhead();
+
+    markTouchedMethods(finalCurOffset);
+
+    char* memStreamPtr;
+    size_t memStreamSize;
+    if (state->directToDdms) {
+        assert(state->traceFile == NULL);
+        state->traceFile = open_memstream(&memStreamPtr, &memStreamSize);
+        if (state->traceFile == NULL) {
+            /* not expected */
+            LOGE("Unable to open memstream");
+            dvmAbort();
+        }
+    }
+    assert(state->traceFile != NULL);
+
+    fprintf(state->traceFile, "%cversion\n", TOKEN_CHAR);
+    fprintf(state->traceFile, "%d\n", state->traceVersion);
+    fprintf(state->traceFile, "data-file-overflow=%s\n",
+        state->overflow ? "true" : "false");
+    if (useThreadCpuClock()) {
+        if (useWallClock()) {
+            fprintf(state->traceFile, "clock=dual\n");
+        } else {
+            fprintf(state->traceFile, "clock=thread-cpu\n");
+        }
+    } else {
+        fprintf(state->traceFile, "clock=wall\n");
+    }
+    fprintf(state->traceFile, "elapsed-time-usec=%llu\n", elapsed);
+    fprintf(state->traceFile, "num-method-calls=%d\n",
+        (finalCurOffset - TRACE_HEADER_LEN) / state->recordSize);
+    fprintf(state->traceFile, "clock-call-overhead-nsec=%d\n", clockNsec);
+    fprintf(state->traceFile, "vm=dalvik\n");
+    if ((state->flags & TRACE_ALLOC_COUNTS) != 0) {
+        fprintf(state->traceFile, "alloc-count=%d\n",
+            gDvm.allocProf.allocCount);
+        fprintf(state->traceFile, "alloc-size=%d\n",
+            gDvm.allocProf.allocSize);
+        fprintf(state->traceFile, "gc-count=%d\n",
+            gDvm.allocProf.gcCount);
+    }
+    fprintf(state->traceFile, "%cthreads\n", TOKEN_CHAR);
+    dumpThreadList(state->traceFile);
+    fprintf(state->traceFile, "%cmethods\n", TOKEN_CHAR);
+    dumpMethodList(state->traceFile);
+    fprintf(state->traceFile, "%cend\n", TOKEN_CHAR);
+
+    if (state->directToDdms) {
+        /*
+         * Data is in two places: memStreamPtr and state->buf.  Send
+         * the whole thing to DDMS, wrapped in an MPSE packet.
+         */
+        fflush(state->traceFile);
+
+        struct iovec iov[2];
+        iov[0].iov_base = memStreamPtr;
+        iov[0].iov_len = memStreamSize;
+        iov[1].iov_base = state->buf;
+        iov[1].iov_len = finalCurOffset;
+        dvmDbgDdmSendChunkV(CHUNK_TYPE("MPSE"), iov, 2);
+    } else {
+        /* append the profiling data */
+        if (fwrite(state->buf, finalCurOffset, 1, state->traceFile) != 1) {
+            int err = errno;
+            LOGE("trace fwrite(%d) failed: %s",
+                finalCurOffset, strerror(err));
+            dvmThrowExceptionFmt(gDvm.exRuntimeException,
+                "Trace data write failed: %s", strerror(err));
+        }
+    }
+
+    /* done! */
+    free(state->buf);
+    state->buf = NULL;
+    fclose(state->traceFile);
+    state->traceFile = NULL;
+
+    /* wake any threads that were waiting for profiling to complete */
+    dvmBroadcastCond(&state->threadExitCond);
+    dvmUnlockMutex(&state->startStopLock);
+}
+
+/*
+ * We just did something with a method.  Emit a record.
+ *
+ * Multiple threads may be banging on this all at once.  We use atomic ops
+ * rather than mutexes for speed.
+ */
+void dvmMethodTraceAdd(Thread* self, const Method* method, int action)
+{
+    MethodTraceState* state = &gDvm.methodTrace;
+    u4 methodVal;
+    int oldOffset, newOffset;
+    u1* ptr;
+
+    assert(method != NULL);
+
+#if defined(HAVE_POSIX_CLOCKS)
+    /*
+     * We can only access the per-thread CPU clock from within the
+     * thread, so we have to initialize the base time on the first use.
+     * (Looks like pthread_getcpuclockid(thread, &id) will do what we
+     * want, but it doesn't appear to be defined on the device.)
+     */
+    if (!self->cpuClockBaseSet) {
+        self->cpuClockBase = getThreadCpuTimeInUsec();
+        self->cpuClockBaseSet = true;
+        //LOGI("thread base id=%d 0x%llx",
+        //    self->threadId, self->cpuClockBase);
+    }
+#endif
+
+    /*
+     * Advance "curOffset" atomically.
+     */
+    do {
+        oldOffset = state->curOffset;
+        newOffset = oldOffset + state->recordSize;
+        if (newOffset > state->bufferSize) {
+            state->overflow = true;
+            return;
+        }
+    } while (android_atomic_release_cas(oldOffset, newOffset,
+            &state->curOffset) != 0);
+
+    //assert(METHOD_ACTION((u4) method) == 0);
+
+    methodVal = METHOD_COMBINE((u4) method, action);
+
+    /*
+     * Write data into "oldOffset".
+     */
+    ptr = state->buf + oldOffset;
+    *ptr++ = (u1) self->threadId;
+    *ptr++ = (u1) (self->threadId >> 8);
+    *ptr++ = (u1) methodVal;
+    *ptr++ = (u1) (methodVal >> 8);
+    *ptr++ = (u1) (methodVal >> 16);
+    *ptr++ = (u1) (methodVal >> 24);
+
+#if defined(HAVE_POSIX_CLOCKS)
+    if (useThreadCpuClock()) {
+        u4 cpuClockDiff = (u4) (getThreadCpuTimeInUsec() - self->cpuClockBase);
+        *ptr++ = (u1) cpuClockDiff;
+        *ptr++ = (u1) (cpuClockDiff >> 8);
+        *ptr++ = (u1) (cpuClockDiff >> 16);
+        *ptr++ = (u1) (cpuClockDiff >> 24);
+    }
+#endif
+
+    if (useWallClock()) {
+        u4 wallClockDiff = (u4) (getWallTimeInUsec() - state->startWhen);
+        *ptr++ = (u1) wallClockDiff;
+        *ptr++ = (u1) (wallClockDiff >> 8);
+        *ptr++ = (u1) (wallClockDiff >> 16);
+        *ptr++ = (u1) (wallClockDiff >> 24);
+    }
+}
+
+
+/*
+ * Register the METHOD_TRACE_ENTER action for the fast interpreter and
+ * JIT'ed code.
+ */
+void dvmFastMethodTraceEnter(const Method* method, Thread* self)
+{
+    if (self->interpBreak.ctl.subMode & kSubModeMethodTrace) {
+        dvmMethodTraceAdd(self, method, METHOD_TRACE_ENTER);
+    }
+}
+
+/*
+ * Register the METHOD_TRACE_EXIT action for the fast interpreter and
+ * JIT'ed code for methods. The about-to-return callee method can be
+ * retrieved from self->interpSave.method.
+ */
+void dvmFastMethodTraceExit(Thread* self)
+{
+    if (self->interpBreak.ctl.subMode & kSubModeMethodTrace) {
+        dvmMethodTraceAdd(self, self->interpSave.method,
+                          METHOD_TRACE_EXIT);
+    }
+}
+
+/*
+ * Register the METHOD_TRACE_EXIT action for the fast interpreter and
+ * JIT'ed code for JNI methods. The about-to-return JNI callee method is passed
+ * in explicitly.  Also used for inline-execute.
+ */
+void dvmFastNativeMethodTraceExit(const Method* method, Thread* self)
+{
+    if (self->interpBreak.ctl.subMode & kSubModeMethodTrace) {
+        dvmMethodTraceAdd(self, method, METHOD_TRACE_EXIT);
+    }
+}
+
+/*
+ * We just did something with a method.  Emit a record by setting a value
+ * in a magic memory location.
+ */
+void dvmEmitEmulatorTrace(const Method* method, int action)
+{
+#ifdef UPDATE_MAGIC_PAGE
+    /*
+     * We store the address of the Dalvik bytecodes to the memory-mapped
+     * trace page for normal methods.  We also trace calls to native
+     * functions by storing the address of the native function to the
+     * trace page.
+     * Abstract methods don't have any bytecodes, so we don't trace them.
+     * (Abstract methods are never called, but in Dalvik they can be
+     * because we do a "late trap" to a native method to generate the
+     * abstract method exception.)
+     */
+    if (dvmIsAbstractMethod(method))
+        return;
+
+    u4* pMagic = (u4*) gDvm.emulatorTracePage;
+    u4 addr;
+
+    if (dvmIsNativeMethod(method)) {
+        /*
+         * The "action" parameter is one of:
+         *   0 = ENTER
+         *   1 = EXIT
+         *   2 = UNROLL
+         * To help the trace tools reconstruct the runtime stack containing
+         * a mix of normal plus native methods, we add 4 to the action if this
+         * is a native method.
+         */
+        action += 4;
+
+        /*
+         * Get the address of the native function.
+         * This isn't the right address -- how do I get it?
+         * Fortunately, the trace tools can get by without the address, but
+         * it would be nice to fix this.
+         */
+         addr = (u4) method->nativeFunc;
+    } else {
+        /*
+         * The dexlist output shows the &DexCode.insns offset value, which
+         * is offset from the start of the base DEX header. Method.insns
+         * is the absolute address, effectively offset from the start of
+         * the optimized DEX header. We either need to return the
+         * optimized DEX base file address offset by the right amount, or
+         * take the "real" address and subtract off the size of the
+         * optimized DEX header.
+         *
+         * Would be nice to factor this out at dexlist time, but we can't count
+         * on having access to the correct optimized DEX file.
+         */
+        assert(method->insns != NULL);
+        const DexOptHeader* pOptHdr = method->clazz->pDvmDex->pDexFile->pOptHeader;
+        addr = (u4) method->insns - pOptHdr->dexOffset;
+    }
+
+    *(pMagic+action) = addr;
+    LOGVV("Set %p = 0x%08x (%s.%s)",
+        pMagic+action, addr, method->clazz->descriptor, method->name);
+#endif
+}
+
+/*
+ * The GC calls this when it's about to start.  We add a marker to the
+ * trace output so the tool can exclude the GC cost from the results.
+ */
+void dvmMethodTraceGCBegin()
+{
+    TRACE_METHOD_ENTER(dvmThreadSelf(), gDvm.methodTraceGcMethod);
+}
+void dvmMethodTraceGCEnd()
+{
+    TRACE_METHOD_EXIT(dvmThreadSelf(), gDvm.methodTraceGcMethod);
+}
+
+/*
+ * The class loader calls this when it's loading or initializing a class.
+ */
+void dvmMethodTraceClassPrepBegin()
+{
+    TRACE_METHOD_ENTER(dvmThreadSelf(), gDvm.methodTraceClassPrepMethod);
+}
+void dvmMethodTraceClassPrepEnd()
+{
+    TRACE_METHOD_EXIT(dvmThreadSelf(), gDvm.methodTraceClassPrepMethod);
+}
+
+
+/*
+ * Enable emulator trace info.
+ */
+void dvmEmulatorTraceStart()
+{
+    /* If we could not map the emulator trace page, then do not enable tracing */
+    if (gDvm.emulatorTracePage == NULL)
+        return;
+
+    /* in theory we should make this an atomic inc; in practice not important */
+    gDvm.emulatorTraceEnableCount++;
+    if (gDvm.emulatorTraceEnableCount == 1)
+        LOGD("--- emulator method traces enabled");
+    updateActiveProfilers(kSubModeEmulatorTrace, true);
+}
+
+/*
+ * Disable emulator trace info.
+ */
+void dvmEmulatorTraceStop()
+{
+    if (gDvm.emulatorTraceEnableCount == 0) {
+        LOGE("ERROR: emulator tracing not enabled");
+        return;
+    }
+    /* in theory we should make this an atomic inc; in practice not important */
+    gDvm.emulatorTraceEnableCount--;
+    if (gDvm.emulatorTraceEnableCount == 0)
+        LOGD("--- emulator method traces disabled");
+    updateActiveProfilers(kSubModeEmulatorTrace,
+                          (gDvm.emulatorTraceEnableCount != 0));
+}
+
+
+/*
+ * Start instruction counting.
+ */
+void dvmStartInstructionCounting()
+{
+    /* in theory we should make this an atomic inc; in practice not important */
+    gDvm.instructionCountEnableCount++;
+    updateActiveProfilers(kSubModeInstCounting, true);
+}
+
+/*
+ * Stop instruction counting.
+ */
+void dvmStopInstructionCounting()
+{
+    if (gDvm.instructionCountEnableCount == 0) {
+        LOGE("ERROR: instruction counting not enabled");
+        dvmAbort();
+    }
+    gDvm.instructionCountEnableCount--;
+    updateActiveProfilers(kSubModeInstCounting,
+                          (gDvm.instructionCountEnableCount != 0));
+}
+
+
+/*
+ * Start alloc counting.  Note this doesn't affect the "active profilers"
+ * count, since the interpreter loop is not involved.
+ */
+void dvmStartAllocCounting()
+{
+    gDvm.allocProf.enabled = true;
+}
+
+/*
+ * Stop alloc counting.
+ */
+void dvmStopAllocCounting()
+{
+    gDvm.allocProf.enabled = false;
+}
diff --git a/vm/Profile.h b/vm/Profile.h
new file mode 100644
index 0000000..6c9e1c7
--- /dev/null
+++ b/vm/Profile.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+/*
+ * Android's method call profiling goodies.
+ */
+#ifndef DALVIK_PROFILE_H_
+#define DALVIK_PROFILE_H_
+
+#ifndef NOT_VM      /* for utilities that sneakily include this file */
+
+#include <stdio.h>
+
+struct Thread;      // extern
+
+
+/* boot init */
+bool dvmProfilingStartup(void);
+void dvmProfilingShutdown(void);
+
+/*
+ * Method trace state.  This is currently global.  In theory we could make
+ * most of this per-thread.
+ */
+struct MethodTraceState {
+    /* active state */
+    pthread_mutex_t startStopLock;
+    pthread_cond_t  threadExitCond;
+    FILE*   traceFile;
+    bool    directToDdms;
+    int     bufferSize;
+    int     flags;
+
+    int     traceEnabled;
+    u1*     buf;
+    volatile int curOffset;
+    u8      startWhen;
+    int     overflow;
+
+    int     traceVersion;
+    size_t  recordSize;
+};
+
+/*
+ * Memory allocation profiler state.  This is used both globally and
+ * per-thread.
+ *
+ * If you add a field here, zero it out in dvmStartAllocCounting().
+ */
+struct AllocProfState {
+    bool    enabled;            // is allocation tracking enabled?
+
+    int     allocCount;         // #of objects allocated
+    int     allocSize;          // cumulative size of objects
+
+    int     failedAllocCount;   // #of times an allocation failed
+    int     failedAllocSize;    // cumulative size of failed allocations
+
+    int     freeCount;          // #of objects freed
+    int     freeSize;           // cumulative size of freed objects
+
+    int     gcCount;            // #of times an allocation triggered a GC
+
+    int     classInitCount;     // #of initialized classes
+    u8      classInitTime;      // cumulative time spent in class init (nsec)
+};
+
+
+/*
+ * Start/stop method tracing.
+ */
+void dvmMethodTraceStart(const char* traceFileName, int traceFd, int bufferSize,
+        int flags, bool directToDdms);
+bool dvmIsMethodTraceActive(void);
+void dvmMethodTraceStop(void);
+
+/*
+ * Start/stop emulator tracing.
+ */
+void dvmEmulatorTraceStart(void);
+void dvmEmulatorTraceStop(void);
+
+/*
+ * Start/stop Dalvik instruction counting.
+ */
+void dvmStartInstructionCounting();
+void dvmStopInstructionCounting();
+
+/*
+ * Bit flags for dvmMethodTraceStart "flags" argument.  These must match
+ * the values in android.os.Debug.
+ */
+enum {
+    TRACE_ALLOC_COUNTS      = 0x01,
+};
+
+/*
+ * Call these when a method enters or exits.
+ */
+#define TRACE_METHOD_ENTER(_self, _method)                                  \
+    do {                                                                    \
+        if (_self->interpBreak.ctl.subMode & kSubModeMethodTrace)           \
+            dvmMethodTraceAdd(_self, _method, METHOD_TRACE_ENTER);          \
+        if (_self->interpBreak.ctl.subMode & kSubModeEmulatorTrace)         \
+            dvmEmitEmulatorTrace(_method, METHOD_TRACE_ENTER);              \
+    } while(0);
+#define TRACE_METHOD_EXIT(_self, _method)                                   \
+    do {                                                                    \
+        if (_self->interpBreak.ctl.subMode & kSubModeMethodTrace)           \
+            dvmMethodTraceAdd(_self, _method, METHOD_TRACE_EXIT);           \
+        if (_self->interpBreak.ctl.subMode & kSubModeEmulatorTrace)         \
+            dvmEmitEmulatorTrace(_method, METHOD_TRACE_EXIT);               \
+    } while(0);
+#define TRACE_METHOD_UNROLL(_self, _method)                                 \
+    do {                                                                    \
+        if (_self->interpBreak.ctl.subMode & kSubModeMethodTrace)           \
+            dvmMethodTraceAdd(_self, _method, METHOD_TRACE_UNROLL);         \
+        if (_self->interpBreak.ctl.subMode & kSubModeEmulatorTrace)         \
+            dvmEmitEmulatorTrace(_method, METHOD_TRACE_UNROLL);             \
+    } while(0);
+
+void dvmMethodTraceAdd(struct Thread* self, const Method* method, int action);
+void dvmEmitEmulatorTrace(const Method* method, int action);
+
+void dvmMethodTraceGCBegin(void);
+void dvmMethodTraceGCEnd(void);
+void dvmMethodTraceClassPrepBegin(void);
+void dvmMethodTraceClassPrepEnd(void);
+
+extern "C" void dvmFastMethodTraceEnter(const Method* method, struct Thread* self);
+extern "C" void dvmFastMethodTraceExit(struct Thread* self);
+extern "C" void dvmFastNativeMethodTraceExit(const Method* method, struct Thread* self);
+
+/*
+ * Start/stop alloc counting.
+ */
+void dvmStartAllocCounting(void);
+void dvmStopAllocCounting(void);
+
+#endif
+
+
+/*
+ * Enumeration for the two "action" bits.
+ */
+enum {
+    METHOD_TRACE_ENTER = 0x00,      // method entry
+    METHOD_TRACE_EXIT = 0x01,       // method exit
+    METHOD_TRACE_UNROLL = 0x02,     // method exited by exception unrolling
+    // 0x03 currently unused
+};
+
+#define TOKEN_CHAR      '*'
+
+/*
+ * Common definitions, shared with the dump tool.
+ */
+#define METHOD_ACTION_MASK      0x03            /* two bits */
+#define METHOD_ID(_method)      ((_method) & (~METHOD_ACTION_MASK))
+#define METHOD_ACTION(_method)  (((unsigned int)(_method)) & METHOD_ACTION_MASK)
+#define METHOD_COMBINE(_method, _action)    ((_method) | (_action))
+
+#endif  // DALVIK_PROFILE_H_
diff --git a/vm/README.txt b/vm/README.txt
new file mode 100644
index 0000000..1be1a63
--- /dev/null
+++ b/vm/README.txt
@@ -0,0 +1,19 @@
+Dalvik Virtual Machine
+
+
+Source code rules of the road:
+
+- All externally-visible function names must start with "dvm" to avoid
+namespace clashes.  Use static functions when possible.
+
+- Do not create static variables (globally or locally).  Do not create
+global variables.  Keep everything with non-local lifespan in "gDvm",
+defined in Globals.h, so that all global VM state is in one place.
+
+- Use "startup" and "shutdown" functions to clean up gDvm.  The VM must
+exit cleanly in valgrind.
+
+- The primary target is ARM Linux.  Others are secondary, but must still
+work correctly.
+
+- Use of gcc-specific and C99 constructs is allowed.
diff --git a/vm/RawDexFile.cpp b/vm/RawDexFile.cpp
new file mode 100644
index 0000000..9fef57c
--- /dev/null
+++ b/vm/RawDexFile.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+/*
+ * Open an unoptimized DEX file.
+ */
+
+#include "Dalvik.h"
+#include "libdex/OptInvocation.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * Copy the given number of bytes from one fd to another, first
+ * seeking the source fd to the start of the file.
+ */
+static int copyFileToFile(int destFd, int srcFd, size_t size)
+{
+    if (lseek(srcFd, 0, SEEK_SET) != 0) {
+        LOGE("lseek failure: %s", strerror(errno));
+        return -1;
+    }
+
+    return sysCopyFileToFile(destFd, srcFd, size);
+}
+
+/*
+ * Get the modification time and size in bytes for the given fd.
+ */
+static int getModTimeAndSize(int fd, u4* modTime, size_t* size)
+{
+    struct stat buf;
+    int result = fstat(fd, &buf);
+
+    if (result < 0) {
+        LOGE("Unable to determine mod time: %s", strerror(errno));
+        return -1;
+    }
+
+    *modTime = (u4) buf.st_mtime;
+    *size = (size_t) buf.st_size;
+    assert((size_t) buf.st_size == buf.st_size);
+
+    return 0;
+}
+
+/*
+ * Verify the dex file magic number, and get the adler32 checksum out
+ * of the given fd, which is presumed to be a reference to a dex file
+ * with the cursor at the start of the file. The fd's cursor is
+ * modified by this operation.
+ */
+static int verifyMagicAndGetAdler32(int fd, u4 *adler32)
+{
+    /*
+     * The start of a dex file is eight bytes of magic followed by
+     * four bytes of checksum.
+     */
+    u1 headerStart[12];
+    ssize_t amt = read(fd, headerStart, sizeof(headerStart));
+
+    if (amt < 0) {
+        LOGE("Unable to read header: %s", strerror(errno));
+        return -1;
+    }
+
+    if (amt != sizeof(headerStart)) {
+        LOGE("Unable to read full header (only got %d bytes)", (int) amt);
+        return -1;
+    }
+
+    if (!dexHasValidMagic((DexHeader*) (void*) headerStart)) {
+        return -1;
+    }
+
+    /*
+     * We can't just cast the data to a u4 and read it, since the
+     * platform might be big-endian (also, because that would make the
+     * compiler complain about type-punned pointers). We assume here
+     * that the dex file is in the standard little-endian format; if
+     * that assumption turns out to be invalid, code that runs later
+     * will notice and complain.
+     */
+    *adler32 = (u4) headerStart[8]
+        | (((u4) headerStart[9]) << 8)
+        | (((u4) headerStart[10]) << 16)
+        | (((u4) headerStart[11]) << 24);
+
+    return 0;
+}
+
+/* See documentation comment in header. */
+int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
+    RawDexFile** ppRawDexFile, bool isBootstrap)
+{
+    /*
+     * TODO: This duplicates a lot of code from dvmJarFileOpen() in
+     * JarFile.c. This should be refactored.
+     */
+
+    DvmDex* pDvmDex = NULL;
+    char* cachedName = NULL;
+    int result = -1;
+    int dexFd = -1;
+    int optFd = -1;
+    u4 modTime = 0;
+    u4 adler32 = 0;
+    size_t fileSize = 0;
+    bool newFile = false;
+    bool locked = false;
+
+    dexFd = open(fileName, O_RDONLY);
+    if (dexFd < 0) goto bail;
+
+    /* If we fork/exec into dexopt, don't let it inherit the open fd. */
+    dvmSetCloseOnExec(dexFd);
+
+    if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) {
+        LOGE("Error with header for %s", fileName);
+        goto bail;
+    }
+
+    if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) {
+        LOGE("Error with stat for %s", fileName);
+        goto bail;
+    }
+
+    /*
+     * See if the cached file matches. If so, optFd will become a reference
+     * to the cached file and will have been seeked to just past the "opt"
+     * header.
+     */
+
+    if (odexOutputName == NULL) {
+        cachedName = dexOptGenerateCacheFileName(fileName, NULL);
+        if (cachedName == NULL)
+            goto bail;
+    } else {
+        cachedName = strdup(odexOutputName);
+    }
+
+    LOGV("dvmRawDexFileOpen: Checking cache for %s (%s)",
+            fileName, cachedName);
+
+    optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime,
+        adler32, isBootstrap, &newFile, /*createIfMissing=*/true);
+
+    if (optFd < 0) {
+        LOGI("Unable to open or create cache for %s (%s)",
+                fileName, cachedName);
+        goto bail;
+    }
+    locked = true;
+
+    /*
+     * If optFd points to a new file (because there was no cached
+     * version, or the cached version was stale), generate the
+     * optimized DEX. The file descriptor returned is still locked,
+     * and is positioned just past the optimization header.
+     */
+    if (newFile) {
+        u8 startWhen, copyWhen, endWhen;
+        bool result;
+        off_t dexOffset;
+
+        dexOffset = lseek(optFd, 0, SEEK_CUR);
+        result = (dexOffset > 0);
+
+        if (result) {
+            startWhen = dvmGetRelativeTimeUsec();
+            result = copyFileToFile(optFd, dexFd, fileSize) == 0;
+            copyWhen = dvmGetRelativeTimeUsec();
+        }
+
+        if (result) {
+            result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
+                fileName, modTime, adler32, isBootstrap);
+        }
+
+        if (!result) {
+            LOGE("Unable to extract+optimize DEX from '%s'", fileName);
+            goto bail;
+        }
+
+        endWhen = dvmGetRelativeTimeUsec();
+        LOGD("DEX prep '%s': copy in %dms, rewrite %dms",
+            fileName,
+            (int) (copyWhen - startWhen) / 1000,
+            (int) (endWhen - copyWhen) / 1000);
+    }
+
+    /*
+     * Map the cached version.  This immediately rewinds the fd, so it
+     * doesn't have to be seeked anywhere in particular.
+     */
+    if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) {
+        LOGI("Unable to map cached %s", fileName);
+        goto bail;
+    }
+
+    if (locked) {
+        /* unlock the fd */
+        if (!dvmUnlockCachedDexFile(optFd)) {
+            /* uh oh -- this process needs to exit or we'll wedge the system */
+            LOGE("Unable to unlock DEX file");
+            goto bail;
+        }
+        locked = false;
+    }
+
+    LOGV("Successfully opened '%s'", fileName);
+
+    *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
+    (*ppRawDexFile)->cacheFileName = cachedName;
+    (*ppRawDexFile)->pDvmDex = pDvmDex;
+    cachedName = NULL;      // don't free it below
+    result = 0;
+
+bail:
+    free(cachedName);
+    if (dexFd >= 0) {
+        close(dexFd);
+    }
+    if (optFd >= 0) {
+        if (locked)
+            (void) dvmUnlockCachedDexFile(optFd);
+        close(optFd);
+    }
+    return result;
+}
+
+/* See documentation comment in header. */
+int dvmRawDexFileOpenArray(u1* pBytes, u4 length, RawDexFile** ppRawDexFile)
+{
+    DvmDex* pDvmDex = NULL;
+
+    if (!dvmPrepareDexInMemory(pBytes, length, &pDvmDex)) {
+        LOGD("Unable to open raw DEX from array");
+        return -1;
+    }
+    assert(pDvmDex != NULL);
+
+    *ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
+    (*ppRawDexFile)->pDvmDex = pDvmDex;
+
+    return 0;
+}
+
+/*
+ * Close a RawDexFile and free the struct.
+ */
+void dvmRawDexFileFree(RawDexFile* pRawDexFile)
+{
+    if (pRawDexFile == NULL)
+        return;
+
+    dvmDexFileFree(pRawDexFile->pDvmDex);
+    free(pRawDexFile->cacheFileName);
+    free(pRawDexFile);
+}
diff --git a/vm/RawDexFile.h b/vm/RawDexFile.h
new file mode 100644
index 0000000..358c669
--- /dev/null
+++ b/vm/RawDexFile.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+/*
+ * This represents a "raw" unswapped, unoptimized DEX file.  We don't open
+ * them directly, except to create the optimized version that we tuck in
+ * the cache area.
+ */
+#ifndef DALVIK_RAWDEXFILE_H_
+#define DALVIK_RAWDEXFILE_H_
+
+/*
+ * Structure representing a "raw" DEX file, in its unswapped unoptimized
+ * state.
+ */
+struct RawDexFile {
+    char*       cacheFileName;
+    DvmDex*     pDvmDex;
+};
+
+/*
+ * Open a raw ".dex" file, optimize it, and load it.
+ *
+ * On success, returns 0 and sets "*ppDexFile" to a newly-allocated DexFile.
+ * On failure, returns a meaningful error code [currently just -1].
+ */
+int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
+    RawDexFile** ppDexFile, bool isBootstrap);
+
+/*
+ * Open a raw ".dex" file based on the given chunk of memory, and load
+ * it. The bytes are assumed to be owned by the caller for the
+ * purposes of memory management and further assumed to not be touched
+ * by the caller while the raw dex file remains open. The bytes *may*
+ * be modified as the result of issuing this call.
+ *
+ * On success, returns 0 and sets "*ppDexFile" to a newly-allocated DexFile.
+ * On failure, returns a meaningful error code [currently just -1].
+ */
+int dvmRawDexFileOpenArray(u1* pBytes, u4 length, RawDexFile** ppDexFile);
+
+/*
+ * Free a RawDexFile structure, along with any associated structures.
+ */
+void dvmRawDexFileFree(RawDexFile* pRawDexFile);
+
+/*
+ * Pry the DexFile out of a RawDexFile.
+ */
+INLINE DvmDex* dvmGetRawDexFileDex(RawDexFile* pRawDexFile) {
+    return pRawDexFile->pDvmDex;
+}
+
+/* get full path of optimized DEX file */
+INLINE const char* dvmGetRawDexFileCacheFileName(RawDexFile* pRawDexFile) {
+    return pRawDexFile->cacheFileName;
+}
+
+#endif  // DALVIK_RAWDEXFILE_H_
diff --git a/vm/ReconfigureDvm.mk b/vm/ReconfigureDvm.mk
new file mode 100644
index 0000000..20e5626
--- /dev/null
+++ b/vm/ReconfigureDvm.mk
@@ -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 $(CLEAR_VARS)
+
+# Variables used in the included Dvm.mk.
+dvm_os := $(TARGET_OS)
+dvm_arch := $(TARGET_ARCH)
+dvm_arch_variant := $(TARGET_ARCH_VARIANT)
+
+# for now, disable x86-atom variant
+ifeq ($(dvm_arch_variant),x86-atom)
+dvm_arch_variant := x86
+endif
+
+include $(LOCAL_PATH)/Dvm.mk
+
+LOCAL_SHARED_LIBRARIES += liblog libcutils libnativehelper libz libdl
+
+LOCAL_STATIC_LIBRARIES += libdex
+
+LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
+LOCAL_SHARED_LIBRARIES += libstlport
+
+# Don't install on any build by default
+LOCAL_MODULE_TAGS := optional
diff --git a/vm/ReferenceTable.cpp b/vm/ReferenceTable.cpp
new file mode 100644
index 0000000..99d613e
--- /dev/null
+++ b/vm/ReferenceTable.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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.
+ */
+
+/*
+ * Reference table management.
+ */
+#include "Dalvik.h"
+
+/*
+ * Initialize a ReferenceTable structure.
+ */
+bool dvmInitReferenceTable(ReferenceTable* pRef, int initialCount,
+    int maxCount)
+{
+    assert(initialCount > 0);
+    assert(initialCount <= maxCount);
+
+    pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
+    if (pRef->table == NULL)
+        return false;
+#ifndef NDEBUG
+    memset(pRef->table, 0xdd, initialCount * sizeof(Object*));
+#endif
+    pRef->nextEntry = pRef->table;
+    pRef->allocEntries = initialCount;
+    pRef->maxEntries = maxCount;
+
+    return true;
+}
+
+/*
+ * Clears out the contents of a ReferenceTable, freeing allocated storage.
+ */
+void dvmClearReferenceTable(ReferenceTable* pRef)
+{
+    free(pRef->table);
+    pRef->table = pRef->nextEntry = NULL;
+    pRef->allocEntries = pRef->maxEntries = -1;
+}
+
+/*
+ * Add "obj" to "pRef".
+ */
+bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj)
+{
+    assert(obj != NULL);
+    assert(dvmIsHeapAddress(obj));
+    assert(pRef->table != NULL);
+    assert(pRef->allocEntries <= pRef->maxEntries);
+
+    if (pRef->nextEntry == pRef->table + pRef->allocEntries) {
+        /* reached end of allocated space; did we hit buffer max? */
+        if (pRef->nextEntry == pRef->table + pRef->maxEntries) {
+            LOGW("ReferenceTable overflow (max=%d)", pRef->maxEntries);
+            return false;
+        }
+
+        Object** newTable;
+        int newSize;
+
+        newSize = pRef->allocEntries * 2;
+        if (newSize > pRef->maxEntries)
+            newSize = pRef->maxEntries;
+        assert(newSize > pRef->allocEntries);
+
+        newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
+        if (newTable == NULL) {
+            LOGE("Unable to expand ref table (from %d to %d %d-byte entries)",
+                pRef->allocEntries, newSize, sizeof(Object*));
+            return false;
+        }
+        LOGVV("Growing %p from %d to %d", pRef, pRef->allocEntries, newSize);
+
+        /* update entries; adjust "nextEntry" in case memory moved */
+        pRef->nextEntry = newTable + (pRef->nextEntry - pRef->table);
+        pRef->table = newTable;
+        pRef->allocEntries = newSize;
+    }
+
+    *pRef->nextEntry++ = obj;
+    return true;
+}
+
+/*
+ * Returns NULL if not found.
+ */
+Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** bottom,
+    Object* obj)
+{
+    Object** ptr;
+
+    ptr = pRef->nextEntry;
+    while (--ptr >= bottom) {
+        if (*ptr == obj)
+            return ptr;
+    }
+    return NULL;
+}
+
+/*
+ * Remove "obj" from "pRef".  We start at the end of the list (where the
+ * most-recently-added element is), and stop searching for a match after
+ * examining the element at "bottom".
+ *
+ * Most of the time "obj" is at or near the end of the list.  If not, we
+ * compact it down.
+ */
+bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** bottom,
+    Object* obj)
+{
+    Object** ptr;
+
+    assert(pRef->table != NULL);
+
+    /*
+     * Scan from the most-recently-added entry up to the bottom entry for
+     * this frame.
+     */
+    ptr = dvmFindInReferenceTable(pRef, bottom, obj);
+    if (ptr == NULL)
+        return false;
+
+    /*
+     * Delete the entry.
+     */
+    pRef->nextEntry--;
+    int moveCount = pRef->nextEntry - ptr;
+    if (moveCount != 0) {
+        /* remove from middle, slide the rest down */
+        memmove(ptr, ptr+1, moveCount * sizeof(Object*));
+        //LOGV("LREF delete %p, shift %d down", obj, moveCount);
+    } else {
+        /* last entry, falls off the end */
+        //LOGV("LREF delete %p from end", obj);
+    }
+
+    return true;
+}
+
+/*
+ * If "obj" is an array, return the number of elements in the array.
+ * Otherwise, return zero.
+ */
+static size_t getElementCount(const Object* obj)
+{
+    const ArrayObject* arrayObj = (ArrayObject*) obj;
+    if (arrayObj == NULL || arrayObj == kClearedJniWeakGlobal ||
+            arrayObj->clazz == NULL || !dvmIsArray(arrayObj)) {
+        return 0;
+    }
+    return arrayObj->length;
+}
+
+/*
+ * This is a qsort() callback.  We sort Object* by class, allocation size,
+ * and then by the Object* itself.
+ */
+static int compareObject(const void* vobj1, const void* vobj2)
+{
+    const Object* obj1 = *((Object* const*) vobj1);
+    const Object* obj2 = *((Object* const*) vobj2);
+
+    // Ensure null references and cleared jweaks appear at the end.
+    if (obj1 == NULL) {
+        if (obj2 == NULL) {
+            return 0;
+        } else {
+            return 1;
+        }
+    } else if (obj2 == NULL) {
+        return -1;
+    }
+    if (obj1 == kClearedJniWeakGlobal) {
+        if (obj2 == kClearedJniWeakGlobal) {
+            return 0;
+        } else {
+            return 1;
+        }
+    } else if (obj2 == kClearedJniWeakGlobal) {
+        return -1;
+    }
+
+    if (obj1->clazz != obj2->clazz) {
+        return (u1*)obj1->clazz - (u1*)obj2->clazz;
+    } else {
+        size_t count1 = getElementCount(obj1);
+        size_t count2 = getElementCount(obj2);
+        if (count1 != count2) {
+            return count1 - count2;
+        } else {
+            return (u1*)obj1 - (u1*)obj2;
+        }
+    }
+}
+
+/*
+ * Log an object with some additional info.
+ *
+ * Pass in the number of elements in the array (or 0 if this is not an
+ * array object), and the number of additional objects that are identical
+ * or equivalent to the original.
+ */
+static void logSummaryLine(const Object* obj, size_t elems, int identical, int equiv)
+{
+    if (obj == NULL) {
+        LOGW("    NULL reference (count=%d)", equiv);
+        return;
+    }
+    if (obj == kClearedJniWeakGlobal) {
+        LOGW("    cleared jweak (count=%d)", equiv);
+        return;
+    }
+
+    std::string className(dvmHumanReadableType(obj));
+    if (obj->clazz == gDvm.classJavaLangClass) {
+        // We're summarizing multiple instances, so using the exemplar
+        // Class' type parameter here would be misleading.
+        className = "java.lang.Class";
+    }
+    if (elems != 0) {
+        StringAppendF(&className, " (%zd elements)", elems);
+    }
+
+    size_t total = identical + equiv + 1;
+    std::string msg(StringPrintf("%5d of %s", total, className.c_str()));
+    if (identical + equiv != 0) {
+        StringAppendF(&msg, " (%d unique instances)", equiv + 1);
+    }
+    LOGW("    %s", msg.c_str());
+}
+
+/*
+ * Dump a summary of an array of references to the log file.
+ *
+ * This is used to dump the contents of ReferenceTable and IndirectRefTable
+ * structs.
+ */
+void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
+    const char* descr)
+{
+    LOGW("%s reference table (%p) dump:", descr, refs);
+
+    if (count == 0) {
+        LOGW("  (empty)");
+        return;
+    }
+
+    // Dump the most recent N entries.
+    const size_t kLast = 10;
+    int first = count - kLast;
+    if (first < 0) {
+        first = 0;
+    }
+    LOGW("  Last %d entries (of %d):", (count - first), count);
+    for (int idx = count - 1; idx >= first; --idx) {
+        const Object* ref = refs[idx];
+        if (ref == NULL) {
+            continue;
+        }
+        if (ref == kClearedJniWeakGlobal) {
+            LOGW("    %5d: cleared jweak", idx);
+            continue;
+        }
+        if (ref->clazz == NULL) {
+            // should only be possible right after a plain dvmMalloc().
+            size_t size = dvmObjectSizeInHeap(ref);
+            LOGW("    %5d: %p (raw) (%zd bytes)", idx, ref, size);
+            continue;
+        }
+
+        std::string className(dvmHumanReadableType(ref));
+
+        std::string extras;
+        size_t elems = getElementCount(ref);
+        if (elems != 0) {
+            StringAppendF(&extras, " (%zd elements)", elems);
+        } else if (ref->clazz == gDvm.classJavaLangString) {
+            const StringObject* str =
+                    reinterpret_cast<const StringObject*>(ref);
+            extras += " \"";
+            size_t count = 0;
+            char* s = dvmCreateCstrFromString(str);
+            char* p = s;
+            for (; *p && count < 16; ++p, ++count) {
+                extras += *p;
+            }
+            if (*p == 0) {
+                extras += "\"";
+            } else {
+                StringAppendF(&extras, "... (%d chars)", str->length());
+            }
+            free(s);
+        }
+        LOGW("    %5d: %p %s%s", idx, ref, className.c_str(), extras.c_str());
+    }
+
+    // Make a copy of the table, and sort it.
+    Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
+    if (tableCopy == NULL) {
+        LOGE("Unable to copy table with %d elements", count);
+        return;
+    }
+    memcpy(tableCopy, refs, sizeof(Object*) * count);
+    qsort(tableCopy, count, sizeof(Object*), compareObject);
+    refs = tableCopy;       // use sorted list
+
+    // Remove any uninteresting stuff from the list. The sort moved them all to the end.
+    while (count > 0 && refs[count-1] == NULL) {
+        --count;
+    }
+    while (count > 0 && refs[count-1] == kClearedJniWeakGlobal) {
+        --count;
+    }
+    if (count == 0) {
+        return;
+    }
+
+    // Dump a summary of the whole table.
+    LOGW("  Summary:");
+    size_t equiv, identical;
+    equiv = identical = 0;
+    size_t idx;
+    size_t elems;
+    for (idx = 1; idx < count; idx++) {
+        elems = getElementCount(refs[idx-1]);
+
+        if (refs[idx] == refs[idx-1]) {
+            // same reference, added more than once.
+            identical++;
+        } else if (refs[idx]->clazz == refs[idx-1]->clazz &&
+            getElementCount(refs[idx]) == elems)
+        {
+            // same class / element count, different object.
+            equiv++;
+        } else {
+            // different class.
+            logSummaryLine(refs[idx-1], elems, identical, equiv);
+            equiv = identical = 0;
+        }
+    }
+
+    // Handle the last entry (everything above outputs refs[i-1]).
+    elems = getElementCount(refs[idx-1]);
+    logSummaryLine(refs[count-1], elems, identical, equiv);
+
+    free(tableCopy);
+}
+
+/*
+ * Dump the contents of a ReferenceTable to the log.
+ */
+void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
+{
+    dvmDumpReferenceTableContents(pRef->table, dvmReferenceTableEntries(pRef),
+        descr);
+}
diff --git a/vm/ReferenceTable.h b/vm/ReferenceTable.h
new file mode 100644
index 0000000..100a918
--- /dev/null
+++ b/vm/ReferenceTable.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/*
+ * Maintain a table of references.  Used for internal local references,
+ * JNI monitor references, and JNI pinned array references.
+ *
+ * None of the table functions are synchronized.
+ */
+#ifndef DALVIK_REFERENCETABLE_H_
+#define DALVIK_REFERENCETABLE_H_
+
+/*
+ * Table definition.
+ *
+ * The expected common operations are adding a new entry and removing a
+ * recently-added entry (usually the most-recently-added entry).
+ *
+ * If "allocEntries" is not equal to "maxEntries", the table may expand when
+ * entries are added, which means the memory may move.  If you want to keep
+ * pointers into "table" rather than offsets, use a fixed-size table.
+ *
+ * (This structure is still somewhat transparent; direct access to
+ * table/nextEntry is allowed.)
+ */
+struct ReferenceTable {
+    Object**        nextEntry;          /* top of the list */
+    Object**        table;              /* bottom of the list */
+
+    int             allocEntries;       /* #of entries we have space for */
+    int             maxEntries;         /* max #of entries allowed */
+};
+
+/*
+ * Initialize a ReferenceTable.
+ *
+ * If "initialCount" != "maxCount", the table will expand as required.
+ *
+ * Returns "false" if table allocation fails.
+ */
+bool dvmInitReferenceTable(ReferenceTable* pRef, int initialCount,
+    int maxCount);
+
+/*
+ * Clears out the contents of a ReferenceTable, freeing allocated storage.
+ * Does not free "pRef".
+ *
+ * You must call dvmInitReferenceTable() before you can re-use this table.
+ */
+void dvmClearReferenceTable(ReferenceTable* pRef);
+
+/*
+ * Return the #of entries currently stored in the ReferenceTable.
+ */
+INLINE size_t dvmReferenceTableEntries(const ReferenceTable* pRef)
+{
+    return pRef->nextEntry - pRef->table;
+}
+
+/*
+ * Returns "true" if the table is full.  The table is considered full if
+ * we would need to expand it to add another entry.
+ */
+INLINE size_t dvmIsReferenceTableFull(const ReferenceTable* pRef)
+{
+    return dvmReferenceTableEntries(pRef) == (size_t)pRef->allocEntries;
+}
+
+/*
+ * Add a new entry.  "obj" must be a valid non-NULL object reference
+ * (though it's okay if it's not fully-formed, e.g. the result from
+ * dvmMalloc doesn't have obj->clazz set).
+ *
+ * Returns "false" if the table is full.
+ */
+bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj);
+
+/*
+ * Determine if "obj" is present in "pRef".  Stops searching when we hit
+ * "bottom".  To include the entire table, pass in "pRef->table" as the
+ * bottom.
+ *
+ * Returns NULL if "obj" was not found.
+ */
+Object** dvmFindInReferenceTable(const ReferenceTable* pRef, Object** bottom,
+    Object* obj);
+
+/*
+ * Remove an existing entry.
+ *
+ * We stop searching for a match after examining the element at "bottom".
+ * This is useful when entries are associated with a stack frame.
+ *
+ * Returns "false" if the entry was not found.
+ */
+bool dvmRemoveFromReferenceTable(ReferenceTable* pRef, Object** bottom,
+    Object* obj);
+
+/*
+ * Dump the contents of a reference table to the log file.
+ *
+ * The caller should lock any external sync before calling.
+ */
+void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr);
+
+/*
+ * Internal function, shared with IndirectRefTable.
+ */
+void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
+    const char* descr);
+
+#endif  // DALVIK_REFERENCETABLE_H_
diff --git a/vm/SignalCatcher.cpp b/vm/SignalCatcher.cpp
new file mode 100644
index 0000000..0b4c3c0
--- /dev/null
+++ b/vm/SignalCatcher.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is a thread that catches signals and does something useful.  For
+ * example, when a SIGQUIT (Ctrl-\) arrives, suspend the VM and dump the
+ * status of all threads.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <cutils/open_memstream.h>
+
+static void* signalCatcherThreadStart(void* arg);
+
+/*
+ * Crank up the signal catcher thread.
+ *
+ * Returns immediately.
+ */
+bool dvmSignalCatcherStartup()
+{
+    gDvm.haltSignalCatcher = false;
+
+    if (!dvmCreateInternalThread(&gDvm.signalCatcherHandle,
+                "Signal Catcher", signalCatcherThreadStart, NULL))
+        return false;
+
+    return true;
+}
+
+/*
+ * Shut down the signal catcher thread if it was started.
+ *
+ * Since we know the thread is just sitting around waiting for signals
+ * to arrive, send it one.
+ */
+void dvmSignalCatcherShutdown()
+{
+    gDvm.haltSignalCatcher = true;
+    if (gDvm.signalCatcherHandle == 0)      // not started yet
+        return;
+
+    pthread_kill(gDvm.signalCatcherHandle, SIGQUIT);
+
+    pthread_join(gDvm.signalCatcherHandle, NULL);
+    LOGV("signal catcher has shut down");
+}
+
+
+/*
+ * Print the name of the current process, if we can get it.
+ */
+static void printProcessName(const DebugOutputTarget* target)
+{
+    int fd = -1;
+
+    fd = open("/proc/self/cmdline", O_RDONLY, 0);
+    if (fd < 0)
+        goto bail;
+
+    char tmpBuf[256];
+    ssize_t actual;
+
+    actual = read(fd, tmpBuf, sizeof(tmpBuf)-1);
+    if (actual <= 0)
+        goto bail;
+
+    tmpBuf[actual] = '\0';
+    dvmPrintDebugMessage(target, "Cmd line: %s\n", tmpBuf);
+
+bail:
+    if (fd >= 0)
+        close(fd);
+}
+
+/*
+ * Dump the stack traces for all threads to the supplied file, putting
+ * a timestamp header on it.
+ */
+static void logThreadStacks(FILE* fp)
+{
+    DebugOutputTarget target;
+
+    dvmCreateFileOutputTarget(&target, fp);
+
+    pid_t pid = getpid();
+    time_t now = time(NULL);
+    struct tm* ptm;
+#ifdef HAVE_LOCALTIME_R
+    struct tm tmbuf;
+    ptm = localtime_r(&now, &tmbuf);
+#else
+    ptm = localtime(&now);
+#endif
+    dvmPrintDebugMessage(&target,
+        "\n\n----- pid %d at %04d-%02d-%02d %02d:%02d:%02d -----\n",
+        pid, ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday,
+        ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
+    printProcessName(&target);
+    dvmPrintDebugMessage(&target, "\n");
+    dvmDumpAllThreadsEx(&target, true);
+    fprintf(fp, "----- end %d -----\n", pid);
+}
+
+
+/*
+ * Respond to a SIGQUIT by dumping the thread stacks.  Optionally dump
+ * a few other things while we're at it.
+ *
+ * Thread stacks can either go to the log or to a file designated for holding
+ * ANR traces.  If we're writing to a file, we want to do it in one shot,
+ * so we can use a single O_APPEND write instead of contending for exclusive
+ * access with flock().  There may be an advantage in resuming the VM
+ * before doing the file write, so we don't stall the VM if disk I/O is
+ * bottlenecked.
+ *
+ * If JIT tuning is compiled in, dump compiler stats as well.
+ */
+static void handleSigQuit()
+{
+    char* traceBuf = NULL;
+    size_t traceLen;
+
+    dvmSuspendAllThreads(SUSPEND_FOR_STACK_DUMP);
+
+    dvmDumpLoaderStats("sig");
+
+    if (gDvm.stackTraceFile == NULL) {
+        /* just dump to log */
+        DebugOutputTarget target;
+        dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG);
+        dvmDumpAllThreadsEx(&target, true);
+    } else {
+        /* write to memory buffer */
+        FILE* memfp = open_memstream(&traceBuf, &traceLen);
+        if (memfp == NULL) {
+            LOGE("Unable to create memstream for stack traces");
+            traceBuf = NULL;        /* make sure it didn't touch this */
+            /* continue on */
+        } else {
+            logThreadStacks(memfp);
+            fclose(memfp);
+        }
+    }
+
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+    dvmCompilerDumpStats();
+#endif
+
+    if (false) dvmDumpTrackedAllocations(true);
+
+    dvmResumeAllThreads(SUSPEND_FOR_STACK_DUMP);
+
+    if (traceBuf != NULL) {
+        /*
+         * We don't know how long it will take to do the disk I/O, so put us
+         * into VMWAIT for the duration.
+         */
+        ThreadStatus oldStatus = dvmChangeStatus(dvmThreadSelf(), THREAD_VMWAIT);
+
+        /*
+         * Open the stack trace output file, creating it if necessary.  It
+         * needs to be world-writable so other processes can write to it.
+         */
+        int fd = open(gDvm.stackTraceFile, O_WRONLY | O_APPEND | O_CREAT, 0666);
+        if (fd < 0) {
+            LOGE("Unable to open stack trace file '%s': %s",
+                gDvm.stackTraceFile, strerror(errno));
+        } else {
+            ssize_t actual = write(fd, traceBuf, traceLen);
+            if (actual != (ssize_t) traceLen) {
+                LOGE("Failed to write stack traces to %s (%d of %zd): %s",
+                    gDvm.stackTraceFile, (int) actual, traceLen,
+                    strerror(errno));
+            } else {
+                LOGI("Wrote stack traces to '%s'", gDvm.stackTraceFile);
+            }
+            close(fd);
+        }
+
+        free(traceBuf);
+        dvmChangeStatus(dvmThreadSelf(), oldStatus);
+    }
+}
+
+/*
+ * Respond to a SIGUSR1 by forcing a GC.
+ */
+static void handleSigUsr1()
+{
+    LOGI("SIGUSR1 forcing GC (no HPROF)");
+    dvmCollectGarbage();
+}
+
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+/* Sample callback function for dvmJitScanAllClassPointers */
+void printAllClass(void *ptr)
+{
+    ClassObject **classPP = (ClassObject **) ptr;
+    LOGE("class %s", (*classPP)->descriptor);
+
+}
+
+/*
+ * Respond to a SIGUSR2 by dumping some JIT stats and possibly resetting
+ * the code cache.
+ */
+static void handleSigUsr2()
+{
+    static int codeCacheResetCount = 0;
+    gDvmJit.receivedSIGUSR2 ^= true;
+    if ((--codeCacheResetCount & 7) == 0) {
+        /* Dump all class pointers in the traces */
+        dvmJitScanAllClassPointers(printAllClass);
+        gDvmJit.codeCacheFull = true;
+    } else {
+        dvmCompilerDumpStats();
+        /* Stress-test unchain all */
+        dvmJitUnchainAll();
+        LOGD("Send %d more signals to reset the code cache",
+             codeCacheResetCount & 7);
+    }
+    dvmCheckInterpStateConsistency();
+}
+#endif
+
+/*
+ * Sleep in sigwait() until a signal arrives.
+ */
+static void* signalCatcherThreadStart(void* arg)
+{
+    Thread* self = dvmThreadSelf();
+    sigset_t mask;
+    int cc;
+
+    UNUSED_PARAMETER(arg);
+
+    LOGV("Signal catcher thread started (threadid=%d)", self->threadId);
+
+    /* set up mask with signals we want to handle */
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGQUIT);
+    sigaddset(&mask, SIGUSR1);
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+    sigaddset(&mask, SIGUSR2);
+#endif
+
+    while (true) {
+        int rcvd;
+
+        dvmChangeStatus(self, THREAD_VMWAIT);
+
+        /*
+         * Signals for sigwait() must be blocked but not ignored.  We
+         * block signals like SIGQUIT for all threads, so the condition
+         * is met.  When the signal hits, we wake up, without any signal
+         * handlers being invoked.
+         *
+         * When running under GDB we occasionally return from sigwait()
+         * with EINTR (e.g. when other threads exit).
+         */
+loop:
+        cc = sigwait(&mask, &rcvd);
+        if (cc != 0) {
+            if (cc == EINTR) {
+                //LOGV("sigwait: EINTR");
+                goto loop;
+            }
+            assert(!"bad result from sigwait");
+        }
+
+        if (!gDvm.haltSignalCatcher) {
+            LOGI("threadid=%d: reacting to signal %d",
+                dvmThreadSelf()->threadId, rcvd);
+        }
+
+        /* set our status to RUNNING, self-suspending if GC in progress */
+        dvmChangeStatus(self, THREAD_RUNNING);
+
+        if (gDvm.haltSignalCatcher)
+            break;
+
+        switch (rcvd) {
+        case SIGQUIT:
+            handleSigQuit();
+            break;
+        case SIGUSR1:
+            handleSigUsr1();
+            break;
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+        case SIGUSR2:
+            handleSigUsr2();
+            break;
+#endif
+        default:
+            LOGE("unexpected signal %d", rcvd);
+            break;
+        }
+    }
+
+    return NULL;
+}
diff --git a/vm/SignalCatcher.h b/vm/SignalCatcher.h
new file mode 100644
index 0000000..d1d7a18
--- /dev/null
+++ b/vm/SignalCatcher.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/*
+ * Signal catcher thread.
+ */
+#ifndef DALVIK_SIGNALCATCHER_H_
+#define DALVIK_SIGNALCATCHER_H_
+
+bool dvmSignalCatcherStartup(void);
+void dvmSignalCatcherShutdown(void);
+
+#endif  // DALVIK_SIGNALCATCHER_H_
diff --git a/vm/StdioConverter.cpp b/vm/StdioConverter.cpp
new file mode 100644
index 0000000..c2ddc79
--- /dev/null
+++ b/vm/StdioConverter.cpp
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+/*
+ * Thread that reads from stdout/stderr and converts them to log messages.
+ * (Sort of a hack.)
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define kFilenoStdout   1
+#define kFilenoStderr   2
+
+#define kMaxLine    512
+
+/*
+ * Hold some data.
+ */
+struct BufferedData {
+    char    buf[kMaxLine+1];
+    int     count;
+};
+
+// fwd
+static void* stdioConverterThreadStart(void* arg);
+static bool readAndLog(int fd, BufferedData* data, const char* tag);
+
+
+/*
+ * Crank up the stdout/stderr converter thread.
+ *
+ * Returns immediately.
+ */
+bool dvmStdioConverterStartup()
+{
+    gDvm.haltStdioConverter = false;
+
+    dvmInitMutex(&gDvm.stdioConverterLock);
+    pthread_cond_init(&gDvm.stdioConverterCond, NULL);
+
+    if (pipe(gDvm.stdoutPipe) != 0) {
+        LOGW("pipe failed: %s", strerror(errno));
+        return false;
+    }
+    if (pipe(gDvm.stderrPipe) != 0) {
+        LOGW("pipe failed: %s", strerror(errno));
+        return false;
+    }
+
+    if (dup2(gDvm.stdoutPipe[1], kFilenoStdout) != kFilenoStdout) {
+        LOGW("dup2(1) failed: %s", strerror(errno));
+        return false;
+    }
+    close(gDvm.stdoutPipe[1]);
+    gDvm.stdoutPipe[1] = -1;
+#ifdef HAVE_ANDROID_OS
+    /* don't redirect stderr on sim -- logs get written there! */
+    /* (don't need this on the sim anyway) */
+    if (dup2(gDvm.stderrPipe[1], kFilenoStderr) != kFilenoStderr) {
+        LOGW("dup2(2) failed: %d %s", errno, strerror(errno));
+        return false;
+    }
+    close(gDvm.stderrPipe[1]);
+    gDvm.stderrPipe[1] = -1;
+#endif
+
+
+    /*
+     * Create the thread.
+     */
+    dvmLockMutex(&gDvm.stdioConverterLock);
+
+    if (!dvmCreateInternalThread(&gDvm.stdioConverterHandle,
+                                 "Stdio Converter",
+                                 stdioConverterThreadStart,
+                                 NULL)) {
+        return false;
+    }
+
+    while (!gDvm.stdioConverterReady) {
+        dvmWaitCond(&gDvm.stdioConverterCond, &gDvm.stdioConverterLock);
+    }
+    dvmUnlockMutex(&gDvm.stdioConverterLock);
+
+    return true;
+}
+
+/*
+ * Shut down the stdio converter thread if it was started.
+ *
+ * Since we know the thread is just sitting around waiting for something
+ * to arrive on stdout, print something.
+ */
+void dvmStdioConverterShutdown()
+{
+    gDvm.haltStdioConverter = true;
+    if (gDvm.stdioConverterHandle == 0)    // not started, or still starting
+        return;
+
+    /* print something to wake it up */
+    printf("Shutting down\n");
+    fflush(stdout);
+
+    LOGD("Joining stdio converter...");
+    pthread_join(gDvm.stdioConverterHandle, NULL);
+}
+
+/*
+ * Select on stdout/stderr pipes, waiting for activity.
+ *
+ * DO NOT use printf from here.
+ */
+static void* stdioConverterThreadStart(void* arg)
+{
+    int cc;
+
+    /* tell the main thread that we're ready */
+    dvmLockMutex(&gDvm.stdioConverterLock);
+    gDvm.stdioConverterReady = true;
+    cc = pthread_cond_signal(&gDvm.stdioConverterCond);
+    assert(cc == 0);
+    dvmUnlockMutex(&gDvm.stdioConverterLock);
+
+    /* we never do anything that affects the rest of the VM */
+    dvmChangeStatus(NULL, THREAD_VMWAIT);
+
+    /*
+     * Allocate read buffers.
+     */
+    BufferedData* stdoutData = new BufferedData;
+    BufferedData* stderrData = new BufferedData;
+    stdoutData->count = stderrData->count = 0;
+
+    /*
+     * Read until shutdown time.
+     */
+    while (!gDvm.haltStdioConverter) {
+        fd_set readfds;
+        int maxFd, fdCount;
+
+        FD_ZERO(&readfds);
+        FD_SET(gDvm.stdoutPipe[0], &readfds);
+        FD_SET(gDvm.stderrPipe[0], &readfds);
+        maxFd = MAX(gDvm.stdoutPipe[0], gDvm.stderrPipe[0]);
+
+        fdCount = select(maxFd+1, &readfds, NULL, NULL, NULL);
+
+        if (fdCount < 0) {
+            if (errno != EINTR) {
+                LOGE("select on stdout/stderr failed");
+                break;
+            }
+            LOGD("Got EINTR, ignoring");
+        } else if (fdCount == 0) {
+            LOGD("WEIRD: select returned zero");
+        } else {
+            bool err = false;
+            if (FD_ISSET(gDvm.stdoutPipe[0], &readfds)) {
+                err |= !readAndLog(gDvm.stdoutPipe[0], stdoutData,
+                    "stdout");
+            }
+            if (FD_ISSET(gDvm.stderrPipe[0], &readfds)) {
+                err |= !readAndLog(gDvm.stderrPipe[0], stderrData,
+                    "stderr");
+            }
+
+            /* probably EOF; give up */
+            if (err) {
+                LOGW("stdio converter got read error; shutting it down");
+                break;
+            }
+        }
+    }
+
+    close(gDvm.stdoutPipe[0]);
+    close(gDvm.stderrPipe[0]);
+
+    delete stdoutData;
+    delete stderrData;
+
+    /* change back for shutdown sequence */
+    dvmChangeStatus(NULL, THREAD_RUNNING);
+    return NULL;
+}
+
+/*
+ * Data is pending on "fd".  Read as much as will fit in "data", then
+ * write out any full lines and compact "data".
+ */
+static bool readAndLog(int fd, BufferedData* data, const char* tag)
+{
+    ssize_t actual;
+    size_t want;
+
+    assert(data->count < kMaxLine);
+
+    want = kMaxLine - data->count;
+    actual = read(fd, data->buf + data->count, want);
+    if (actual <= 0) {
+        LOGW("read %s: (%d,%d) failed (%d): %s",
+            tag, fd, want, (int)actual, strerror(errno));
+        return false;
+    } else {
+        //LOGI("read %s: %d at %d", tag, actual, data->count);
+    }
+    data->count += actual;
+
+    /*
+     * Got more data, look for an EOL.  We expect LF or CRLF, but will
+     * try to handle a standalone CR.
+     */
+    char* cp = data->buf;
+    const char* start = data->buf;
+    int i = data->count;
+    for (i = data->count; i > 0; i--, cp++) {
+        if (*cp == '\n' || (*cp == '\r' && i != 0 && *(cp+1) != '\n')) {
+            *cp = '\0';
+            //LOGW("GOT %d at %d '%s'", cp - start, start - data->buf, start);
+            LOG(LOG_INFO, tag, "%s", start);
+            start = cp+1;
+        }
+    }
+
+    /*
+     * See if we overflowed.  If so, cut it off.
+     */
+    if (start == data->buf && data->count == kMaxLine) {
+        data->buf[kMaxLine] = '\0';
+        LOG(LOG_INFO, tag, "%s!", start);
+        start = cp + kMaxLine;
+    }
+
+    /*
+     * Update "data" if we consumed some output.  If there's anything left
+     * in the buffer, it's because we didn't see an EOL and need to keep
+     * reading until we see one.
+     */
+    if (start != data->buf) {
+        if (start >= data->buf + data->count) {
+            /* consumed all available */
+            data->count = 0;
+        } else {
+            /* some left over */
+            int remaining = data->count - (start - data->buf);
+            memmove(data->buf, start, remaining);
+            data->count = remaining;
+        }
+    }
+
+    return true;
+}
diff --git a/vm/StdioConverter.h b/vm/StdioConverter.h
new file mode 100644
index 0000000..bd5d879
--- /dev/null
+++ b/vm/StdioConverter.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/*
+ * Stdout/stderr conversion thread.
+ */
+#ifndef DALVIK_STDOUTCONVERTER_H_
+#define DALVIK_STDOUTCONVERTER_H_
+
+bool dvmStdioConverterStartup(void);
+void dvmStdioConverterShutdown(void);
+
+#endif  // DALVIK_STDOUTCONVERTER_H_
diff --git a/vm/Sync.cpp b/vm/Sync.cpp
new file mode 100644
index 0000000..80cc6af
--- /dev/null
+++ b/vm/Sync.cpp
@@ -0,0 +1,1373 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <errno.h>
+
+/*
+ * Every Object has a monitor associated with it, but not every Object is
+ * actually locked.  Even the ones that are locked do not need a
+ * full-fledged monitor until a) there is actual contention or b) wait()
+ * is called on the Object.
+ *
+ * For Dalvik, we have implemented a scheme similar to the one described
+ * in Bacon et al.'s "Thin locks: featherweight synchronization for Java"
+ * (ACM 1998).  Things are even easier for us, though, because we have
+ * a full 32 bits to work with.
+ *
+ * The two states of an Object's lock are referred to as "thin" and
+ * "fat".  A lock may transition from the "thin" state to the "fat"
+ * state and this transition is referred to as inflation.  Once a lock
+ * has been inflated it remains in the "fat" state indefinitely.
+ *
+ * The lock value itself is stored in Object.lock.  The LSB of the
+ * lock encodes its state.  When cleared, the lock is in the "thin"
+ * state and its bits are formatted as follows:
+ *
+ *    [31 ---- 19] [18 ---- 3] [2 ---- 1] [0]
+ *     lock count   thread id  hash state  0
+ *
+ * When set, the lock is in the "fat" state and its bits are formatted
+ * as follows:
+ *
+ *    [31 ---- 3] [2 ---- 1] [0]
+ *      pointer   hash state  1
+ *
+ * For an in-depth description of the mechanics of thin-vs-fat locking,
+ * read the paper referred to above.
+ */
+
+/*
+ * Monitors provide:
+ *  - mutually exclusive access to resources
+ *  - a way for multiple threads to wait for notification
+ *
+ * In effect, they fill the role of both mutexes and condition variables.
+ *
+ * Only one thread can own the monitor at any time.  There may be several
+ * threads waiting on it (the wait call unlocks it).  One or more waiting
+ * threads may be getting interrupted or notified at any given time.
+ *
+ * TODO: the various members of monitor are not SMP-safe.
+ */
+struct Monitor {
+    Thread*     owner;          /* which thread currently owns the lock? */
+    int         lockCount;      /* owner's recursive lock depth */
+    Object*     obj;            /* what object are we part of [debug only] */
+
+    Thread*     waitSet;	/* threads currently waiting on this monitor */
+
+    pthread_mutex_t lock;
+
+    Monitor*    next;
+
+    /*
+     * Who last acquired this monitor, when lock sampling is enabled.
+     * Even when enabled, ownerMethod may be NULL.
+     */
+    const Method* ownerMethod;
+    u4 ownerPc;
+};
+
+
+/*
+ * Create and initialize a monitor.
+ */
+Monitor* dvmCreateMonitor(Object* obj)
+{
+    Monitor* mon;
+
+    mon = (Monitor*) calloc(1, sizeof(Monitor));
+    if (mon == NULL) {
+        LOGE("Unable to allocate monitor");
+        dvmAbort();
+    }
+    if (((u4)mon & 7) != 0) {
+        LOGE("Misaligned monitor: %p", mon);
+        dvmAbort();
+    }
+    mon->obj = obj;
+    dvmInitMutex(&mon->lock);
+
+    /* replace the head of the list with the new monitor */
+    do {
+        mon->next = gDvm.monitorList;
+    } while (android_atomic_release_cas((int32_t)mon->next, (int32_t)mon,
+            (int32_t*)(void*)&gDvm.monitorList) != 0);
+
+    return mon;
+}
+
+/*
+ * Free the monitor list.  Only used when shutting the VM down.
+ */
+void dvmFreeMonitorList()
+{
+    Monitor* mon;
+    Monitor* nextMon;
+
+    mon = gDvm.monitorList;
+    while (mon != NULL) {
+        nextMon = mon->next;
+        free(mon);
+        mon = nextMon;
+    }
+}
+
+/*
+ * Get the object that a monitor is part of.
+ */
+Object* dvmGetMonitorObject(Monitor* mon)
+{
+    if (mon == NULL)
+        return NULL;
+    else
+        return mon->obj;
+}
+
+/*
+ * Returns the thread id of the thread owning the given lock.
+ */
+static u4 lockOwner(Object* obj)
+{
+    Thread *owner;
+    u4 lock;
+
+    assert(obj != NULL);
+    /*
+     * Since we're reading the lock value multiple times, latch it so
+     * that it doesn't change out from under us if we get preempted.
+     */
+    lock = obj->lock;
+    if (LW_SHAPE(lock) == LW_SHAPE_THIN) {
+        return LW_LOCK_OWNER(lock);
+    } else {
+        owner = LW_MONITOR(lock)->owner;
+        return owner ? owner->threadId : 0;
+    }
+}
+
+/*
+ * Get the thread that holds the lock on the specified object.  The
+ * object may be unlocked, thin-locked, or fat-locked.
+ *
+ * The caller must lock the thread list before calling here.
+ */
+Thread* dvmGetObjectLockHolder(Object* obj)
+{
+    u4 threadId = lockOwner(obj);
+
+    if (threadId == 0)
+        return NULL;
+    return dvmGetThreadByThreadId(threadId);
+}
+
+/*
+ * Checks whether the given thread holds the given
+ * objects's lock.
+ */
+bool dvmHoldsLock(Thread* thread, Object* obj)
+{
+    if (thread == NULL || obj == NULL) {
+        return false;
+    } else {
+        return thread->threadId == lockOwner(obj);
+    }
+}
+
+/*
+ * Free the monitor associated with an object and make the object's lock
+ * thin again.  This is called during garbage collection.
+ */
+static void freeMonitor(Monitor *mon)
+{
+    assert(mon != NULL);
+    assert(mon->obj != NULL);
+    assert(LW_SHAPE(mon->obj->lock) == LW_SHAPE_FAT);
+
+    /* This lock is associated with an object
+     * that's being swept.  The only possible way
+     * anyone could be holding this lock would be
+     * if some JNI code locked but didn't unlock
+     * the object, in which case we've got some bad
+     * native code somewhere.
+     */
+    assert(pthread_mutex_trylock(&mon->lock) == 0);
+    assert(pthread_mutex_unlock(&mon->lock) == 0);
+    dvmDestroyMutex(&mon->lock);
+    free(mon);
+}
+
+/*
+ * Frees monitor objects belonging to unmarked objects.
+ */
+void dvmSweepMonitorList(Monitor** mon, int (*isUnmarkedObject)(void*))
+{
+    Monitor handle;
+    Monitor *prev, *curr;
+    Object *obj;
+
+    assert(mon != NULL);
+    assert(isUnmarkedObject != NULL);
+    prev = &handle;
+    prev->next = curr = *mon;
+    while (curr != NULL) {
+        obj = curr->obj;
+        if (obj != NULL && (*isUnmarkedObject)(obj) != 0) {
+            prev->next = curr->next;
+            freeMonitor(curr);
+            curr = prev->next;
+        } else {
+            prev = curr;
+            curr = curr->next;
+        }
+    }
+    *mon = handle.next;
+}
+
+static char *logWriteInt(char *dst, int value)
+{
+    *dst++ = EVENT_TYPE_INT;
+    set4LE((u1 *)dst, value);
+    return dst + 4;
+}
+
+static char *logWriteString(char *dst, const char *value, size_t len)
+{
+    *dst++ = EVENT_TYPE_STRING;
+    len = len < 32 ? len : 32;
+    set4LE((u1 *)dst, len);
+    dst += 4;
+    memcpy(dst, value, len);
+    return dst + len;
+}
+
+#define EVENT_LOG_TAG_dvm_lock_sample 20003
+
+static void logContentionEvent(Thread *self, u4 waitMs, u4 samplePercent,
+                               const char *ownerFileName, u4 ownerLineNumber)
+{
+    const StackSaveArea *saveArea;
+    const Method *meth;
+    u4 relativePc;
+    char eventBuffer[174];
+    const char *fileName;
+    char procName[33];
+    char *cp;
+    size_t len;
+    int fd;
+
+    saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    meth = saveArea->method;
+    cp = eventBuffer;
+
+    /* Emit the event list length, 1 byte. */
+    *cp++ = 9;
+
+    /* Emit the process name, <= 37 bytes. */
+    fd = open("/proc/self/cmdline", O_RDONLY);
+    memset(procName, 0, sizeof(procName));
+    read(fd, procName, sizeof(procName) - 1);
+    close(fd);
+    len = strlen(procName);
+    cp = logWriteString(cp, procName, len);
+
+    /* Emit the sensitive thread ("main thread") status, 5 bytes. */
+    bool isSensitive = false;
+    if (gDvm.isSensitiveThreadHook != NULL) {
+        isSensitive = gDvm.isSensitiveThreadHook();
+    }
+    cp = logWriteInt(cp, isSensitive);
+
+    /* Emit self thread name string, <= 37 bytes. */
+    std::string selfName = dvmGetThreadName(self);
+    cp = logWriteString(cp, selfName.c_str(), selfName.size());
+
+    /* Emit the wait time, 5 bytes. */
+    cp = logWriteInt(cp, waitMs);
+
+    /* Emit the source code file name, <= 37 bytes. */
+    fileName = dvmGetMethodSourceFile(meth);
+    if (fileName == NULL) fileName = "";
+    cp = logWriteString(cp, fileName, strlen(fileName));
+
+    /* Emit the source code line number, 5 bytes. */
+    relativePc = saveArea->xtra.currentPc - saveArea->method->insns;
+    cp = logWriteInt(cp, dvmLineNumFromPC(meth, relativePc));
+
+    /* Emit the lock owner source code file name, <= 37 bytes. */
+    if (ownerFileName == NULL) {
+        ownerFileName = "";
+    } else if (strcmp(fileName, ownerFileName) == 0) {
+        /* Common case, so save on log space. */
+        ownerFileName = "-";
+    }
+    cp = logWriteString(cp, ownerFileName, strlen(ownerFileName));
+
+    /* Emit the source code line number, 5 bytes. */
+    cp = logWriteInt(cp, ownerLineNumber);
+
+    /* Emit the sample percentage, 5 bytes. */
+    cp = logWriteInt(cp, samplePercent);
+
+    assert((size_t)(cp - eventBuffer) <= sizeof(eventBuffer));
+    android_btWriteLog(EVENT_LOG_TAG_dvm_lock_sample,
+                       EVENT_TYPE_LIST,
+                       eventBuffer,
+                       (size_t)(cp - eventBuffer));
+}
+
+/*
+ * Lock a monitor.
+ */
+static void lockMonitor(Thread* self, Monitor* mon)
+{
+    ThreadStatus oldStatus;
+    u4 waitThreshold, samplePercent;
+    u8 waitStart, waitEnd, waitMs;
+
+    if (mon->owner == self) {
+        mon->lockCount++;
+        return;
+    }
+    if (dvmTryLockMutex(&mon->lock) != 0) {
+        oldStatus = dvmChangeStatus(self, THREAD_MONITOR);
+        waitThreshold = gDvm.lockProfThreshold;
+        if (waitThreshold) {
+            waitStart = dvmGetRelativeTimeUsec();
+        }
+
+        const Method* currentOwnerMethod = mon->ownerMethod;
+        u4 currentOwnerPc = mon->ownerPc;
+
+        dvmLockMutex(&mon->lock);
+        if (waitThreshold) {
+            waitEnd = dvmGetRelativeTimeUsec();
+        }
+        dvmChangeStatus(self, oldStatus);
+        if (waitThreshold) {
+            waitMs = (waitEnd - waitStart) / 1000;
+            if (waitMs >= waitThreshold) {
+                samplePercent = 100;
+            } else {
+                samplePercent = 100 * waitMs / waitThreshold;
+            }
+            if (samplePercent != 0 && ((u4)rand() % 100 < samplePercent)) {
+                const char* currentOwnerFileName = "no_method";
+                u4 currentOwnerLineNumber = 0;
+                if (currentOwnerMethod != NULL) {
+                    currentOwnerFileName = dvmGetMethodSourceFile(currentOwnerMethod);
+                    if (currentOwnerFileName == NULL) {
+                        currentOwnerFileName = "no_method_file";
+                    }
+                    currentOwnerLineNumber = dvmLineNumFromPC(currentOwnerMethod, currentOwnerPc);
+                }
+                logContentionEvent(self, waitMs, samplePercent,
+                                   currentOwnerFileName, currentOwnerLineNumber);
+            }
+        }
+    }
+    mon->owner = self;
+    assert(mon->lockCount == 0);
+
+    // When debugging, save the current monitor holder for future
+    // acquisition failures to use in sampled logging.
+    if (gDvm.lockProfThreshold > 0) {
+        mon->ownerMethod = NULL;
+        mon->ownerPc = 0;
+        if (self->interpSave.curFrame == NULL) {
+            return;
+        }
+        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+        if (saveArea == NULL) {
+            return;
+        }
+        mon->ownerMethod = saveArea->method;
+        mon->ownerPc = (saveArea->xtra.currentPc - saveArea->method->insns);
+    }
+}
+
+/*
+ * Try to lock a monitor.
+ *
+ * Returns "true" on success.
+ */
+#ifdef WITH_COPYING_GC
+static bool tryLockMonitor(Thread* self, Monitor* mon)
+{
+    if (mon->owner == self) {
+        mon->lockCount++;
+        return true;
+    } else {
+        if (dvmTryLockMutex(&mon->lock) == 0) {
+            mon->owner = self;
+            assert(mon->lockCount == 0);
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
+#endif
+
+/*
+ * Unlock a monitor.
+ *
+ * Returns true if the unlock succeeded.
+ * If the unlock failed, an exception will be pending.
+ */
+static bool unlockMonitor(Thread* self, Monitor* mon)
+{
+    assert(self != NULL);
+    assert(mon != NULL);
+    if (mon->owner == self) {
+        /*
+         * We own the monitor, so nobody else can be in here.
+         */
+        if (mon->lockCount == 0) {
+            mon->owner = NULL;
+            mon->ownerMethod = NULL;
+            mon->ownerPc = 0;
+            dvmUnlockMutex(&mon->lock);
+        } else {
+            mon->lockCount--;
+        }
+    } else {
+        /*
+         * We don't own this, so we're not allowed to unlock it.
+         * The JNI spec says that we should throw IllegalMonitorStateException
+         * in this case.
+         */
+        dvmThrowIllegalMonitorStateException("unlock of unowned monitor");
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Checks the wait set for circular structure.  Returns 0 if the list
+ * is not circular.  Otherwise, returns 1.  Used only by asserts.
+ */
+#ifndef NDEBUG
+static int waitSetCheck(Monitor *mon)
+{
+    Thread *fast, *slow;
+    size_t n;
+
+    assert(mon != NULL);
+    fast = slow = mon->waitSet;
+    n = 0;
+    for (;;) {
+        if (fast == NULL) return 0;
+        if (fast->waitNext == NULL) return 0;
+        if (fast == slow && n > 0) return 1;
+        n += 2;
+        fast = fast->waitNext->waitNext;
+        slow = slow->waitNext;
+    }
+}
+#endif
+
+/*
+ * Links a thread into a monitor's wait set.  The monitor lock must be
+ * held by the caller of this routine.
+ */
+static void waitSetAppend(Monitor *mon, Thread *thread)
+{
+    Thread *elt;
+
+    assert(mon != NULL);
+    assert(mon->owner == dvmThreadSelf());
+    assert(thread != NULL);
+    assert(thread->waitNext == NULL);
+    assert(waitSetCheck(mon) == 0);
+    if (mon->waitSet == NULL) {
+        mon->waitSet = thread;
+        return;
+    }
+    elt = mon->waitSet;
+    while (elt->waitNext != NULL) {
+        elt = elt->waitNext;
+    }
+    elt->waitNext = thread;
+}
+
+/*
+ * Unlinks a thread from a monitor's wait set.  The monitor lock must
+ * be held by the caller of this routine.
+ */
+static void waitSetRemove(Monitor *mon, Thread *thread)
+{
+    Thread *elt;
+
+    assert(mon != NULL);
+    assert(mon->owner == dvmThreadSelf());
+    assert(thread != NULL);
+    assert(waitSetCheck(mon) == 0);
+    if (mon->waitSet == NULL) {
+        return;
+    }
+    if (mon->waitSet == thread) {
+        mon->waitSet = thread->waitNext;
+        thread->waitNext = NULL;
+        return;
+    }
+    elt = mon->waitSet;
+    while (elt->waitNext != NULL) {
+        if (elt->waitNext == thread) {
+            elt->waitNext = thread->waitNext;
+            thread->waitNext = NULL;
+            return;
+        }
+        elt = elt->waitNext;
+    }
+}
+
+/*
+ * Converts the given relative waiting time into an absolute time.
+ */
+static void absoluteTime(s8 msec, s4 nsec, struct timespec *ts)
+{
+    s8 endSec;
+
+#ifdef HAVE_TIMEDWAIT_MONOTONIC
+    clock_gettime(CLOCK_MONOTONIC, ts);
+#else
+    {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        ts->tv_sec = tv.tv_sec;
+        ts->tv_nsec = tv.tv_usec * 1000;
+    }
+#endif
+    endSec = ts->tv_sec + msec / 1000;
+    if (endSec >= 0x7fffffff) {
+        LOGV("NOTE: end time exceeds epoch");
+        endSec = 0x7ffffffe;
+    }
+    ts->tv_sec = endSec;
+    ts->tv_nsec = (ts->tv_nsec + (msec % 1000) * 1000000) + nsec;
+
+    /* catch rollover */
+    if (ts->tv_nsec >= 1000000000L) {
+        ts->tv_sec++;
+        ts->tv_nsec -= 1000000000L;
+    }
+}
+
+int dvmRelativeCondWait(pthread_cond_t* cond, pthread_mutex_t* mutex,
+                        s8 msec, s4 nsec)
+{
+    int ret;
+    struct timespec ts;
+    absoluteTime(msec, nsec, &ts);
+#if defined(HAVE_TIMEDWAIT_MONOTONIC)
+    ret = pthread_cond_timedwait_monotonic(cond, mutex, &ts);
+#else
+    ret = pthread_cond_timedwait(cond, mutex, &ts);
+#endif
+    assert(ret == 0 || ret == ETIMEDOUT);
+    return ret;
+}
+
+/*
+ * Wait on a monitor until timeout, interrupt, or notification.  Used for
+ * Object.wait() and (somewhat indirectly) Thread.sleep() and Thread.join().
+ *
+ * If another thread calls Thread.interrupt(), we throw InterruptedException
+ * and return immediately if one of the following are true:
+ *  - blocked in wait(), wait(long), or wait(long, int) methods of Object
+ *  - blocked in join(), join(long), or join(long, int) methods of Thread
+ *  - blocked in sleep(long), or sleep(long, int) methods of Thread
+ * Otherwise, we set the "interrupted" flag.
+ *
+ * Checks to make sure that "nsec" is in the range 0-999999
+ * (i.e. fractions of a millisecond) and throws the appropriate
+ * exception if it isn't.
+ *
+ * The spec allows "spurious wakeups", and recommends that all code using
+ * Object.wait() do so in a loop.  This appears to derive from concerns
+ * about pthread_cond_wait() on multiprocessor systems.  Some commentary
+ * on the web casts doubt on whether these can/should occur.
+ *
+ * Since we're allowed to wake up "early", we clamp extremely long durations
+ * to return at the end of the 32-bit time epoch.
+ */
+static void waitMonitor(Thread* self, Monitor* mon, s8 msec, s4 nsec,
+    bool interruptShouldThrow)
+{
+    struct timespec ts;
+    bool wasInterrupted = false;
+    bool timed;
+    int ret;
+
+    assert(self != NULL);
+    assert(mon != NULL);
+
+    /* Make sure that we hold the lock. */
+    if (mon->owner != self) {
+        dvmThrowIllegalMonitorStateException(
+            "object not locked by thread before wait()");
+        return;
+    }
+
+    /*
+     * Enforce the timeout range.
+     */
+    if (msec < 0 || nsec < 0 || nsec > 999999) {
+        dvmThrowIllegalArgumentException("timeout arguments out of range");
+        return;
+    }
+
+    /*
+     * Compute absolute wakeup time, if necessary.
+     */
+    if (msec == 0 && nsec == 0) {
+        timed = false;
+    } else {
+        absoluteTime(msec, nsec, &ts);
+        timed = true;
+    }
+
+    /*
+     * Add ourselves to the set of threads waiting on this monitor, and
+     * release our hold.  We need to let it go even if we're a few levels
+     * deep in a recursive lock, and we need to restore that later.
+     *
+     * We append to the wait set ahead of clearing the count and owner
+     * fields so the subroutine can check that the calling thread owns
+     * the monitor.  Aside from that, the order of member updates is
+     * not order sensitive as we hold the pthread mutex.
+     */
+    waitSetAppend(mon, self);
+    int prevLockCount = mon->lockCount;
+    mon->lockCount = 0;
+    mon->owner = NULL;
+
+    const Method* savedMethod = mon->ownerMethod;
+    u4 savedPc = mon->ownerPc;
+    mon->ownerMethod = NULL;
+    mon->ownerPc = 0;
+
+    /*
+     * Update thread status.  If the GC wakes up, it'll ignore us, knowing
+     * that we won't touch any references in this state, and we'll check
+     * our suspend mode before we transition out.
+     */
+    if (timed)
+        dvmChangeStatus(self, THREAD_TIMED_WAIT);
+    else
+        dvmChangeStatus(self, THREAD_WAIT);
+
+    dvmLockMutex(&self->waitMutex);
+
+    /*
+     * Set waitMonitor to the monitor object we will be waiting on.
+     * When waitMonitor is non-NULL a notifying or interrupting thread
+     * must signal the thread's waitCond to wake it up.
+     */
+    assert(self->waitMonitor == NULL);
+    self->waitMonitor = mon;
+
+    /*
+     * Handle the case where the thread was interrupted before we called
+     * wait().
+     */
+    if (self->interrupted) {
+        wasInterrupted = true;
+        self->waitMonitor = NULL;
+        dvmUnlockMutex(&self->waitMutex);
+        goto done;
+    }
+
+    /*
+     * Release the monitor lock and wait for a notification or
+     * a timeout to occur.
+     */
+    dvmUnlockMutex(&mon->lock);
+
+    if (!timed) {
+        ret = pthread_cond_wait(&self->waitCond, &self->waitMutex);
+        assert(ret == 0);
+    } else {
+#ifdef HAVE_TIMEDWAIT_MONOTONIC
+        ret = pthread_cond_timedwait_monotonic(&self->waitCond, &self->waitMutex, &ts);
+#else
+        ret = pthread_cond_timedwait(&self->waitCond, &self->waitMutex, &ts);
+#endif
+        assert(ret == 0 || ret == ETIMEDOUT);
+    }
+    if (self->interrupted) {
+        wasInterrupted = true;
+    }
+
+    self->interrupted = false;
+    self->waitMonitor = NULL;
+
+    dvmUnlockMutex(&self->waitMutex);
+
+    /* Reacquire the monitor lock. */
+    lockMonitor(self, mon);
+
+done:
+    /*
+     * We remove our thread from wait set after restoring the count
+     * and owner fields so the subroutine can check that the calling
+     * thread owns the monitor. Aside from that, the order of member
+     * updates is not order sensitive as we hold the pthread mutex.
+     */
+    mon->owner = self;
+    mon->lockCount = prevLockCount;
+    mon->ownerMethod = savedMethod;
+    mon->ownerPc = savedPc;
+    waitSetRemove(mon, self);
+
+    /* set self->status back to THREAD_RUNNING, and self-suspend if needed */
+    dvmChangeStatus(self, THREAD_RUNNING);
+
+    if (wasInterrupted) {
+        /*
+         * We were interrupted while waiting, or somebody interrupted an
+         * un-interruptible thread earlier and we're bailing out immediately.
+         *
+         * The doc sayeth: "The interrupted status of the current thread is
+         * cleared when this exception is thrown."
+         */
+        self->interrupted = false;
+        if (interruptShouldThrow) {
+            dvmThrowInterruptedException(NULL);
+        }
+    }
+}
+
+/*
+ * Notify one thread waiting on this monitor.
+ */
+static void notifyMonitor(Thread* self, Monitor* mon)
+{
+    Thread* thread;
+
+    assert(self != NULL);
+    assert(mon != NULL);
+
+    /* Make sure that we hold the lock. */
+    if (mon->owner != self) {
+        dvmThrowIllegalMonitorStateException(
+            "object not locked by thread before notify()");
+        return;
+    }
+    /* Signal the first waiting thread in the wait set. */
+    while (mon->waitSet != NULL) {
+        thread = mon->waitSet;
+        mon->waitSet = thread->waitNext;
+        thread->waitNext = NULL;
+        dvmLockMutex(&thread->waitMutex);
+        /* Check to see if the thread is still waiting. */
+        if (thread->waitMonitor != NULL) {
+            pthread_cond_signal(&thread->waitCond);
+            dvmUnlockMutex(&thread->waitMutex);
+            return;
+        }
+        dvmUnlockMutex(&thread->waitMutex);
+    }
+}
+
+/*
+ * Notify all threads waiting on this monitor.
+ */
+static void notifyAllMonitor(Thread* self, Monitor* mon)
+{
+    Thread* thread;
+
+    assert(self != NULL);
+    assert(mon != NULL);
+
+    /* Make sure that we hold the lock. */
+    if (mon->owner != self) {
+        dvmThrowIllegalMonitorStateException(
+            "object not locked by thread before notifyAll()");
+        return;
+    }
+    /* Signal all threads in the wait set. */
+    while (mon->waitSet != NULL) {
+        thread = mon->waitSet;
+        mon->waitSet = thread->waitNext;
+        thread->waitNext = NULL;
+        dvmLockMutex(&thread->waitMutex);
+        /* Check to see if the thread is still waiting. */
+        if (thread->waitMonitor != NULL) {
+            pthread_cond_signal(&thread->waitCond);
+        }
+        dvmUnlockMutex(&thread->waitMutex);
+    }
+}
+
+/*
+ * Changes the shape of a monitor from thin to fat, preserving the
+ * internal lock state.  The calling thread must own the lock.
+ */
+static void inflateMonitor(Thread *self, Object *obj)
+{
+    Monitor *mon;
+    u4 thin;
+
+    assert(self != NULL);
+    assert(obj != NULL);
+    assert(LW_SHAPE(obj->lock) == LW_SHAPE_THIN);
+    assert(LW_LOCK_OWNER(obj->lock) == self->threadId);
+    /* Allocate and acquire a new monitor. */
+    mon = dvmCreateMonitor(obj);
+    lockMonitor(self, mon);
+    /* Propagate the lock state. */
+    thin = obj->lock;
+    mon->lockCount = LW_LOCK_COUNT(thin);
+    thin &= LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT;
+    thin |= (u4)mon | LW_SHAPE_FAT;
+    /* Publish the updated lock word. */
+    android_atomic_release_store(thin, (int32_t *)&obj->lock);
+}
+
+/*
+ * Implements monitorenter for "synchronized" stuff.
+ *
+ * This does not fail or throw an exception (unless deadlock prediction
+ * is enabled and set to "err" mode).
+ */
+void dvmLockObject(Thread* self, Object *obj)
+{
+    volatile u4 *thinp;
+    ThreadStatus oldStatus;
+    struct timespec tm;
+    long sleepDelayNs;
+    long minSleepDelayNs = 1000000;  /* 1 millisecond */
+    long maxSleepDelayNs = 1000000000;  /* 1 second */
+    u4 thin, newThin, threadId;
+
+    assert(self != NULL);
+    assert(obj != NULL);
+    threadId = self->threadId;
+    thinp = &obj->lock;
+retry:
+    thin = *thinp;
+    if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
+        /*
+         * The lock is a thin lock.  The owner field is used to
+         * determine the acquire method, ordered by cost.
+         */
+        if (LW_LOCK_OWNER(thin) == threadId) {
+            /*
+             * The calling thread owns the lock.  Increment the
+             * value of the recursion count field.
+             */
+            obj->lock += 1 << LW_LOCK_COUNT_SHIFT;
+            if (LW_LOCK_COUNT(obj->lock) == LW_LOCK_COUNT_MASK) {
+                /*
+                 * The reacquisition limit has been reached.  Inflate
+                 * the lock so the next acquire will not overflow the
+                 * recursion count field.
+                 */
+                inflateMonitor(self, obj);
+            }
+        } else if (LW_LOCK_OWNER(thin) == 0) {
+            /*
+             * The lock is unowned.  Install the thread id of the
+             * calling thread into the owner field.  This is the
+             * common case.  In performance critical code the JIT
+             * will have tried this before calling out to the VM.
+             */
+            newThin = thin | (threadId << LW_LOCK_OWNER_SHIFT);
+            if (android_atomic_acquire_cas(thin, newThin,
+                    (int32_t*)thinp) != 0) {
+                /*
+                 * The acquire failed.  Try again.
+                 */
+                goto retry;
+            }
+        } else {
+            LOGV("(%d) spin on lock %p: %#x (%#x) %#x",
+                 threadId, &obj->lock, 0, *thinp, thin);
+            /*
+             * The lock is owned by another thread.  Notify the VM
+             * that we are about to wait.
+             */
+            oldStatus = dvmChangeStatus(self, THREAD_MONITOR);
+            /*
+             * Spin until the thin lock is released or inflated.
+             */
+            sleepDelayNs = 0;
+            for (;;) {
+                thin = *thinp;
+                /*
+                 * Check the shape of the lock word.  Another thread
+                 * may have inflated the lock while we were waiting.
+                 */
+                if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
+                    if (LW_LOCK_OWNER(thin) == 0) {
+                        /*
+                         * The lock has been released.  Install the
+                         * thread id of the calling thread into the
+                         * owner field.
+                         */
+                        newThin = thin | (threadId << LW_LOCK_OWNER_SHIFT);
+                        if (android_atomic_acquire_cas(thin, newThin,
+                                (int32_t *)thinp) == 0) {
+                            /*
+                             * The acquire succeed.  Break out of the
+                             * loop and proceed to inflate the lock.
+                             */
+                            break;
+                        }
+                    } else {
+                        /*
+                         * The lock has not been released.  Yield so
+                         * the owning thread can run.
+                         */
+                        if (sleepDelayNs == 0) {
+                            sched_yield();
+                            sleepDelayNs = minSleepDelayNs;
+                        } else {
+                            tm.tv_sec = 0;
+                            tm.tv_nsec = sleepDelayNs;
+                            nanosleep(&tm, NULL);
+                            /*
+                             * Prepare the next delay value.  Wrap to
+                             * avoid once a second polls for eternity.
+                             */
+                            if (sleepDelayNs < maxSleepDelayNs / 2) {
+                                sleepDelayNs *= 2;
+                            } else {
+                                sleepDelayNs = minSleepDelayNs;
+                            }
+                        }
+                    }
+                } else {
+                    /*
+                     * The thin lock was inflated by another thread.
+                     * Let the VM know we are no longer waiting and
+                     * try again.
+                     */
+                    LOGV("(%d) lock %p surprise-fattened",
+                             threadId, &obj->lock);
+                    dvmChangeStatus(self, oldStatus);
+                    goto retry;
+                }
+            }
+            LOGV("(%d) spin on lock done %p: %#x (%#x) %#x",
+                 threadId, &obj->lock, 0, *thinp, thin);
+            /*
+             * We have acquired the thin lock.  Let the VM know that
+             * we are no longer waiting.
+             */
+            dvmChangeStatus(self, oldStatus);
+            /*
+             * Fatten the lock.
+             */
+            inflateMonitor(self, obj);
+            LOGV("(%d) lock %p fattened", threadId, &obj->lock);
+        }
+    } else {
+        /*
+         * The lock is a fat lock.
+         */
+        assert(LW_MONITOR(obj->lock) != NULL);
+        lockMonitor(self, LW_MONITOR(obj->lock));
+    }
+}
+
+/*
+ * Implements monitorexit for "synchronized" stuff.
+ *
+ * On failure, throws an exception and returns "false".
+ */
+bool dvmUnlockObject(Thread* self, Object *obj)
+{
+    u4 thin;
+
+    assert(self != NULL);
+    assert(self->status == THREAD_RUNNING);
+    assert(obj != NULL);
+    /*
+     * Cache the lock word as its value can change while we are
+     * examining its state.
+     */
+    thin = *(volatile u4 *)&obj->lock;
+    if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
+        /*
+         * The lock is thin.  We must ensure that the lock is owned
+         * by the given thread before unlocking it.
+         */
+        if (LW_LOCK_OWNER(thin) == self->threadId) {
+            /*
+             * We are the lock owner.  It is safe to update the lock
+             * without CAS as lock ownership guards the lock itself.
+             */
+            if (LW_LOCK_COUNT(thin) == 0) {
+                /*
+                 * The lock was not recursively acquired, the common
+                 * case.  Unlock by clearing all bits except for the
+                 * hash state.
+                 */
+                thin &= (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT);
+                android_atomic_release_store(thin, (int32_t*)&obj->lock);
+            } else {
+                /*
+                 * The object was recursively acquired.  Decrement the
+                 * lock recursion count field.
+                 */
+                obj->lock -= 1 << LW_LOCK_COUNT_SHIFT;
+            }
+        } else {
+            /*
+             * We do not own the lock.  The JVM spec requires that we
+             * throw an exception in this case.
+             */
+            dvmThrowIllegalMonitorStateException("unlock of unowned monitor");
+            return false;
+        }
+    } else {
+        /*
+         * The lock is fat.  We must check to see if unlockMonitor has
+         * raised any exceptions before continuing.
+         */
+        assert(LW_MONITOR(obj->lock) != NULL);
+        if (!unlockMonitor(self, LW_MONITOR(obj->lock))) {
+            /*
+             * An exception has been raised.  Do not fall through.
+             */
+            return false;
+        }
+    }
+    return true;
+}
+
+/*
+ * Object.wait().  Also called for class init.
+ */
+void dvmObjectWait(Thread* self, Object *obj, s8 msec, s4 nsec,
+    bool interruptShouldThrow)
+{
+    Monitor* mon;
+    u4 thin = *(volatile u4 *)&obj->lock;
+
+    /* If the lock is still thin, we need to fatten it.
+     */
+    if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
+        /* Make sure that 'self' holds the lock.
+         */
+        if (LW_LOCK_OWNER(thin) != self->threadId) {
+            dvmThrowIllegalMonitorStateException(
+                "object not locked by thread before wait()");
+            return;
+        }
+
+        /* This thread holds the lock.  We need to fatten the lock
+         * so 'self' can block on it.  Don't update the object lock
+         * field yet, because 'self' needs to acquire the lock before
+         * any other thread gets a chance.
+         */
+        inflateMonitor(self, obj);
+        LOGV("(%d) lock %p fattened by wait()", self->threadId, &obj->lock);
+    }
+    mon = LW_MONITOR(obj->lock);
+    waitMonitor(self, mon, msec, nsec, interruptShouldThrow);
+}
+
+/*
+ * Object.notify().
+ */
+void dvmObjectNotify(Thread* self, Object *obj)
+{
+    u4 thin = *(volatile u4 *)&obj->lock;
+
+    /* If the lock is still thin, there aren't any waiters;
+     * waiting on an object forces lock fattening.
+     */
+    if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
+        /* Make sure that 'self' holds the lock.
+         */
+        if (LW_LOCK_OWNER(thin) != self->threadId) {
+            dvmThrowIllegalMonitorStateException(
+                "object not locked by thread before notify()");
+            return;
+        }
+
+        /* no-op;  there are no waiters to notify.
+         */
+    } else {
+        /* It's a fat lock.
+         */
+        notifyMonitor(self, LW_MONITOR(thin));
+    }
+}
+
+/*
+ * Object.notifyAll().
+ */
+void dvmObjectNotifyAll(Thread* self, Object *obj)
+{
+    u4 thin = *(volatile u4 *)&obj->lock;
+
+    /* If the lock is still thin, there aren't any waiters;
+     * waiting on an object forces lock fattening.
+     */
+    if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
+        /* Make sure that 'self' holds the lock.
+         */
+        if (LW_LOCK_OWNER(thin) != self->threadId) {
+            dvmThrowIllegalMonitorStateException(
+                "object not locked by thread before notifyAll()");
+            return;
+        }
+
+        /* no-op;  there are no waiters to notify.
+         */
+    } else {
+        /* It's a fat lock.
+         */
+        notifyAllMonitor(self, LW_MONITOR(thin));
+    }
+}
+
+/*
+ * This implements java.lang.Thread.sleep(long msec, int nsec).
+ *
+ * The sleep is interruptible by other threads, which means we can't just
+ * plop into an OS sleep call.  (We probably could if we wanted to send
+ * signals around and rely on EINTR, but that's inefficient and relies
+ * on native code respecting our signal mask.)
+ *
+ * We have to do all of this stuff for Object.wait() as well, so it's
+ * easiest to just sleep on a private Monitor.
+ *
+ * It appears that we want sleep(0,0) to go through the motions of sleeping
+ * for a very short duration, rather than just returning.
+ */
+void dvmThreadSleep(u8 msec, u4 nsec)
+{
+    Thread* self = dvmThreadSelf();
+    Monitor* mon = gDvm.threadSleepMon;
+
+    /* sleep(0,0) wakes up immediately, wait(0,0) means wait forever; adjust */
+    if (msec == 0 && nsec == 0)
+        nsec++;
+
+    lockMonitor(self, mon);
+    waitMonitor(self, mon, msec, nsec, true);
+    unlockMonitor(self, mon);
+}
+
+/*
+ * Implement java.lang.Thread.interrupt().
+ */
+void dvmThreadInterrupt(Thread* thread)
+{
+    assert(thread != NULL);
+
+    dvmLockMutex(&thread->waitMutex);
+
+    /*
+     * If the interrupted flag is already set no additional action is
+     * required.
+     */
+    if (thread->interrupted == true) {
+        dvmUnlockMutex(&thread->waitMutex);
+        return;
+    }
+
+    /*
+     * Raise the "interrupted" flag.  This will cause it to bail early out
+     * of the next wait() attempt, if it's not currently waiting on
+     * something.
+     */
+    thread->interrupted = true;
+
+    /*
+     * Is the thread waiting?
+     *
+     * Note that fat vs. thin doesn't matter here;  waitMonitor
+     * is only set when a thread actually waits on a monitor,
+     * which implies that the monitor has already been fattened.
+     */
+    if (thread->waitMonitor != NULL) {
+        pthread_cond_signal(&thread->waitCond);
+    }
+
+    dvmUnlockMutex(&thread->waitMutex);
+}
+
+#ifndef WITH_COPYING_GC
+u4 dvmIdentityHashCode(Object *obj)
+{
+    return (u4)obj;
+}
+#else
+/*
+ * Returns the identity hash code of the given object.
+ */
+u4 dvmIdentityHashCode(Object *obj)
+{
+    Thread *self, *thread;
+    volatile u4 *lw;
+    size_t size;
+    u4 lock, owner, hashState;
+
+    if (obj == NULL) {
+        /*
+         * Null is defined to have an identity hash code of 0.
+         */
+        return 0;
+    }
+    lw = &obj->lock;
+retry:
+    hashState = LW_HASH_STATE(*lw);
+    if (hashState == LW_HASH_STATE_HASHED) {
+        /*
+         * The object has been hashed but has not had its hash code
+         * relocated by the garbage collector.  Use the raw object
+         * address.
+         */
+        return (u4)obj >> 3;
+    } else if (hashState == LW_HASH_STATE_HASHED_AND_MOVED) {
+        /*
+         * The object has been hashed and its hash code has been
+         * relocated by the collector.  Use the value of the naturally
+         * aligned word following the instance data.
+         */
+        assert(!dvmIsClassObject(obj));
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+            size = dvmArrayObjectSize((ArrayObject *)obj);
+            size = (size + 2) & ~2;
+        } else {
+            size = obj->clazz->objectSize;
+        }
+        return *(u4 *)(((char *)obj) + size);
+    } else if (hashState == LW_HASH_STATE_UNHASHED) {
+        /*
+         * The object has never been hashed.  Change the hash state to
+         * hashed and use the raw object address.
+         */
+        self = dvmThreadSelf();
+        if (self->threadId == lockOwner(obj)) {
+            /*
+             * We already own the lock so we can update the hash state
+             * directly.
+             */
+            *lw |= (LW_HASH_STATE_HASHED << LW_HASH_STATE_SHIFT);
+            return (u4)obj >> 3;
+        }
+        /*
+         * We do not own the lock.  Try acquiring the lock.  Should
+         * this fail, we must suspend the owning thread.
+         */
+        if (LW_SHAPE(*lw) == LW_SHAPE_THIN) {
+            /*
+             * If the lock is thin assume it is unowned.  We simulate
+             * an acquire, update, and release with a single CAS.
+             */
+            lock = (LW_HASH_STATE_HASHED << LW_HASH_STATE_SHIFT);
+            if (android_atomic_acquire_cas(
+                                0,
+                                (int32_t)lock,
+                                (int32_t *)lw) == 0) {
+                /*
+                 * A new lockword has been installed with a hash state
+                 * of hashed.  Use the raw object address.
+                 */
+                return (u4)obj >> 3;
+            }
+        } else {
+            if (tryLockMonitor(self, LW_MONITOR(*lw))) {
+                /*
+                 * The monitor lock has been acquired.  Change the
+                 * hash state to hashed and use the raw object
+                 * address.
+                 */
+                *lw |= (LW_HASH_STATE_HASHED << LW_HASH_STATE_SHIFT);
+                unlockMonitor(self, LW_MONITOR(*lw));
+                return (u4)obj >> 3;
+            }
+        }
+        /*
+         * At this point we have failed to acquire the lock.  We must
+         * identify the owning thread and suspend it.
+         */
+        dvmLockThreadList(self);
+        /*
+         * Cache the lock word as its value can change between
+         * determining its shape and retrieving its owner.
+         */
+        lock = *lw;
+        if (LW_SHAPE(lock) == LW_SHAPE_THIN) {
+            /*
+             * Find the thread with the corresponding thread id.
+             */
+            owner = LW_LOCK_OWNER(lock);
+            assert(owner != self->threadId);
+            /*
+             * If the lock has no owner do not bother scanning the
+             * thread list and fall through to the failure handler.
+             */
+            thread = owner ? gDvm.threadList : NULL;
+            while (thread != NULL) {
+                if (thread->threadId == owner) {
+                    break;
+                }
+                thread = thread->next;
+            }
+        } else {
+            thread = LW_MONITOR(lock)->owner;
+        }
+        /*
+         * If thread is NULL the object has been released since the
+         * thread list lock was acquired.  Try again.
+         */
+        if (thread == NULL) {
+            dvmUnlockThreadList();
+            goto retry;
+        }
+        /*
+         * Wait for the owning thread to suspend.
+         */
+        dvmSuspendThread(thread);
+        if (dvmHoldsLock(thread, obj)) {
+            /*
+             * The owning thread has been suspended.  We can safely
+             * change the hash state to hashed.
+             */
+            *lw |= (LW_HASH_STATE_HASHED << LW_HASH_STATE_SHIFT);
+            dvmResumeThread(thread);
+            dvmUnlockThreadList();
+            return (u4)obj >> 3;
+        }
+        /*
+         * The wrong thread has been suspended.  Try again.
+         */
+        dvmResumeThread(thread);
+        dvmUnlockThreadList();
+        goto retry;
+    }
+    LOGE("object %p has an unknown hash state %#x", obj, hashState);
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmAbort();
+    return 0;  /* Quiet the compiler. */
+}
+#endif  /* WITH_COPYING_GC */
diff --git a/vm/Sync.h b/vm/Sync.h
new file mode 100644
index 0000000..2016c03
--- /dev/null
+++ b/vm/Sync.h
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+/*
+ * Object synchronization functions.
+ */
+#ifndef DALVIK_SYNC_H_
+#define DALVIK_SYNC_H_
+
+/*
+ * Monitor shape field.  Used to distinguish immediate thin locks from
+ * indirecting fat locks.
+ */
+#define LW_SHAPE_THIN 0
+#define LW_SHAPE_FAT 1
+#define LW_SHAPE_MASK 0x1
+#define LW_SHAPE(x) ((x) & LW_SHAPE_MASK)
+
+/*
+ * Hash state field.  Used to signify that an object has had its
+ * identity hash code exposed or relocated.
+ */
+#define LW_HASH_STATE_UNHASHED 0
+#define LW_HASH_STATE_HASHED 1
+#define LW_HASH_STATE_HASHED_AND_MOVED 3
+#define LW_HASH_STATE_MASK 0x3
+#define LW_HASH_STATE_SHIFT 1
+#define LW_HASH_STATE(x) (((x) >> LW_HASH_STATE_SHIFT) & LW_HASH_STATE_MASK)
+
+/*
+ * Monitor accessor.  Extracts a monitor structure pointer from a fat
+ * lock.  Performs no error checking.
+ */
+#define LW_MONITOR(x) \
+  ((Monitor*)((x) & ~((LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT) | \
+                      LW_SHAPE_MASK)))
+
+/*
+ * Lock owner field.  Contains the thread id of the thread currently
+ * holding the lock.
+ */
+#define LW_LOCK_OWNER_MASK 0xffff
+#define LW_LOCK_OWNER_SHIFT 3
+#define LW_LOCK_OWNER(x) (((x) >> LW_LOCK_OWNER_SHIFT) & LW_LOCK_OWNER_MASK)
+
+/*
+ * Lock recursion count field.  Contains a count of the numer of times
+ * a lock has been recursively acquired.
+ */
+#define LW_LOCK_COUNT_MASK 0x1fff
+#define LW_LOCK_COUNT_SHIFT 19
+#define LW_LOCK_COUNT(x) (((x) >> LW_LOCK_COUNT_SHIFT) & LW_LOCK_COUNT_MASK)
+
+struct Object;
+struct Monitor;
+struct Thread;
+
+/*
+ * Returns true if the lock has been fattened.
+ */
+#define IS_LOCK_FAT(lock)   (LW_SHAPE(*(lock)) == LW_SHAPE_FAT)
+
+/*
+ * Acquire the object's monitor.
+ */
+extern "C" void dvmLockObject(Thread* self, Object* obj);
+
+/* Returns true if the unlock succeeded.
+ * If the unlock failed, an exception will be pending.
+ */
+extern "C" bool dvmUnlockObject(Thread* self, Object* obj);
+
+/*
+ * Implementations of some java/lang/Object calls.
+ */
+void dvmObjectWait(Thread* self, Object* obj,
+    s8 timeout, s4 nanos, bool interruptShouldThrow);
+void dvmObjectNotify(Thread* self, Object* obj);
+void dvmObjectNotifyAll(Thread* self, Object* obj);
+
+/*
+ * Implementation of System.identityHashCode().
+ */
+u4 dvmIdentityHashCode(Object* obj);
+
+/*
+ * Implementation of Thread.sleep().
+ */
+void dvmThreadSleep(u8 msec, u4 nsec);
+
+/*
+ * Implementation of Thread.interrupt().
+ *
+ * Interrupt a thread.  If it's waiting on a monitor, wake it up.
+ */
+void dvmThreadInterrupt(Thread* thread);
+
+/* create a new Monitor struct */
+Monitor* dvmCreateMonitor(Object* obj);
+
+/*
+ * Frees unmarked monitors from the monitor list.  The given callback
+ * routine should return a non-zero value when passed a pointer to an
+ * unmarked object.
+ */
+void dvmSweepMonitorList(Monitor** mon, int (*isUnmarkedObject)(void*));
+
+/* free monitor list */
+void dvmFreeMonitorList(void);
+
+/*
+ * Get the object a monitor is part of.
+ *
+ * Returns NULL if "mon" is NULL or the monitor is not part of an object
+ * (which should only happen for Thread.sleep() in the current implementation).
+ */
+Object* dvmGetMonitorObject(Monitor* mon);
+
+/*
+ * Get the thread that holds the lock on the specified object.  The
+ * object may be unlocked, thin-locked, or fat-locked.
+ *
+ * The caller must lock the thread list before calling here.
+ */
+Thread* dvmGetObjectLockHolder(Object* obj);
+
+/*
+ * Checks whether the object is held by the specified thread.
+ */
+bool dvmHoldsLock(Thread* thread, Object* obj);
+
+/*
+ * Relative timed wait on condition
+ */
+int dvmRelativeCondWait(pthread_cond_t* cond, pthread_mutex_t* mutex,
+                         s8 msec, s4 nsec);
+
+#endif  // DALVIK_SYNC_H_
diff --git a/vm/Thread.cpp b/vm/Thread.cpp
new file mode 100644
index 0000000..5122adf
--- /dev/null
+++ b/vm/Thread.cpp
@@ -0,0 +1,3452 @@
+/*
+ * 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.
+ */
+
+/*
+ * Thread support.
+ */
+#include "Dalvik.h"
+#include "os/os.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+#include "interp/Jit.h"         // need for self verification
+#endif
+
+
+/* desktop Linux needs a little help with gettid() */
+#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
+#define __KERNEL__
+# include <linux/unistd.h>
+#ifdef _syscall0
+_syscall0(pid_t,gettid)
+#else
+pid_t gettid() { return syscall(__NR_gettid);}
+#endif
+#undef __KERNEL__
+#endif
+
+// Change this to enable logging on cgroup errors
+#define ENABLE_CGROUP_ERR_LOGGING 0
+
+// change this to LOGV/LOGD to debug thread activity
+#define LOG_THREAD  LOGVV
+
+/*
+Notes on Threading
+
+All threads are native pthreads.  All threads, except the JDWP debugger
+thread, are visible to code running in the VM and to the debugger.  (We
+don't want the debugger to try to manipulate the thread that listens for
+instructions from the debugger.)  Internal VM threads are in the "system"
+ThreadGroup, all others are in the "main" ThreadGroup, per convention.
+
+The GC only runs when all threads have been suspended.  Threads are
+expected to suspend themselves, using a "safe point" mechanism.  We check
+for a suspend request at certain points in the main interpreter loop,
+and on requests coming in from native code (e.g. all JNI functions).
+Certain debugger events may inspire threads to self-suspend.
+
+Native methods must use JNI calls to modify object references to avoid
+clashes with the GC.  JNI doesn't provide a way for native code to access
+arrays of objects as such -- code must always get/set individual entries --
+so it should be possible to fully control access through JNI.
+
+Internal native VM threads, such as the finalizer thread, must explicitly
+check for suspension periodically.  In most cases they will be sound
+asleep on a condition variable, and won't notice the suspension anyway.
+
+Threads may be suspended by the GC, debugger, or the SIGQUIT listener
+thread.  The debugger may suspend or resume individual threads, while the
+GC always suspends all threads.  Each thread has a "suspend count" that
+is incremented on suspend requests and decremented on resume requests.
+When the count is zero, the thread is runnable.  This allows us to fulfill
+a debugger requirement: if the debugger suspends a thread, the thread is
+not allowed to run again until the debugger resumes it (or disconnects,
+in which case we must resume all debugger-suspended threads).
+
+Paused threads sleep on a condition variable, and are awoken en masse.
+Certain "slow" VM operations, such as starting up a new thread, will be
+done in a separate "VMWAIT" state, so that the rest of the VM doesn't
+freeze up waiting for the operation to finish.  Threads must check for
+pending suspension when leaving VMWAIT.
+
+Because threads suspend themselves while interpreting code or when native
+code makes JNI calls, there is no risk of suspending while holding internal
+VM locks.  All threads can enter a suspended (or native-code-only) state.
+Also, we don't have to worry about object references existing solely
+in hardware registers.
+
+We do, however, have to worry about objects that were allocated internally
+and aren't yet visible to anything else in the VM.  If we allocate an
+object, and then go to sleep on a mutex after changing to a non-RUNNING
+state (e.g. while trying to allocate a second object), the first object
+could be garbage-collected out from under us while we sleep.  To manage
+this, we automatically add all allocated objects to an internal object
+tracking list, and only remove them when we know we won't be suspended
+before the object appears in the GC root set.
+
+The debugger may choose to suspend or resume a single thread, which can
+lead to application-level deadlocks; this is expected behavior.  The VM
+will only check for suspension of single threads when the debugger is
+active (the java.lang.Thread calls for this are deprecated and hence are
+not supported).  Resumption of a single thread is handled by decrementing
+the thread's suspend count and sending a broadcast signal to the condition
+variable.  (This will cause all threads to wake up and immediately go back
+to sleep, which isn't tremendously efficient, but neither is having the
+debugger attached.)
+
+The debugger is not allowed to resume threads suspended by the GC.  This
+is trivially enforced by ignoring debugger requests while the GC is running
+(the JDWP thread is suspended during GC).
+
+The VM maintains a Thread struct for every pthread known to the VM.  There
+is a java/lang/Thread object associated with every Thread.  At present,
+there is no safe way to go from a Thread object to a Thread struct except by
+locking and scanning the list; this is necessary because the lifetimes of
+the two are not closely coupled.  We may want to change this behavior,
+though at present the only performance impact is on the debugger (see
+threadObjToThread()).  See also notes about dvmDetachCurrentThread().
+*/
+/*
+Alternate implementation (signal-based):
+
+Threads run without safe points -- zero overhead.  The VM uses a signal
+(e.g. pthread_kill(SIGUSR1)) to notify threads of suspension or resumption.
+
+The trouble with using signals to suspend threads is that it means a thread
+can be in the middle of an operation when garbage collection starts.
+To prevent some sticky situations, we have to introduce critical sections
+to the VM code.
+
+Critical sections temporarily block suspension for a given thread.
+The thread must move to a non-blocked state (and self-suspend) after
+finishing its current task.  If the thread blocks on a resource held
+by a suspended thread, we're hosed.
+
+One approach is to require that no blocking operations, notably
+acquisition of mutexes, can be performed within a critical section.
+This is too limiting.  For example, if thread A gets suspended while
+holding the thread list lock, it will prevent the GC or debugger from
+being able to safely access the thread list.  We need to wrap the critical
+section around the entire operation (enter critical, get lock, do stuff,
+release lock, exit critical).
+
+A better approach is to declare that certain resources can only be held
+within critical sections.  A thread that enters a critical section and
+then gets blocked on the thread list lock knows that the thread it is
+waiting for is also in a critical section, and will release the lock
+before suspending itself.  Eventually all threads will complete their
+operations and self-suspend.  For this to work, the VM must:
+
+ (1) Determine the set of resources that may be accessed from the GC or
+     debugger threads.  The mutexes guarding those go into the "critical
+     resource set" (CRS).
+ (2) Ensure that no resource in the CRS can be acquired outside of a
+     critical section.  This can be verified with an assert().
+ (3) Ensure that only resources in the CRS can be held while in a critical
+     section.  This is harder to enforce.
+
+If any of these conditions are not met, deadlock can ensue when grabbing
+resources in the GC or debugger (#1) or waiting for threads to suspend
+(#2,#3).  (You won't actually deadlock in the GC, because if the semantics
+above are followed you don't need to lock anything in the GC.  The risk is
+rather that the GC will access data structures in an intermediate state.)
+
+This approach requires more care and awareness in the VM than
+safe-pointing.  Because the GC and debugger are fairly intrusive, there
+really aren't any internal VM resources that aren't shared.  Thus, the
+enter/exit critical calls can be added to internal mutex wrappers, which
+makes it easy to get #1 and #2 right.
+
+An ordering should be established for all locks to avoid deadlocks.
+
+Monitor locks, which are also implemented with pthread calls, should not
+cause any problems here.  Threads fighting over such locks will not be in
+critical sections and can be suspended freely.
+
+This can get tricky if we ever need exclusive access to VM and non-VM
+resources at the same time.  It's not clear if this is a real concern.
+
+There are (at least) two ways to handle the incoming signals:
+
+ (a) Always accept signals.  If we're in a critical section, the signal
+     handler just returns without doing anything (the "suspend level"
+     should have been incremented before the signal was sent).  Otherwise,
+     if the "suspend level" is nonzero, we go to sleep.
+ (b) Block signals in critical sections.  This ensures that we can't be
+     interrupted in a critical section, but requires pthread_sigmask()
+     calls on entry and exit.
+
+This is a choice between blocking the message and blocking the messenger.
+Because UNIX signals are unreliable (you can only know that you have been
+signaled, not whether you were signaled once or 10 times), the choice is
+not significant for correctness.  The choice depends on the efficiency
+of pthread_sigmask() and the desire to actually block signals.  Either way,
+it is best to ensure that there is only one indication of "blocked";
+having two (i.e. block signals and set a flag, then only send a signal
+if the flag isn't set) can lead to race conditions.
+
+The signal handler must take care to copy registers onto the stack (via
+setjmp), so that stack scans find all references.  Because we have to scan
+native stacks, "exact" GC is not possible with this approach.
+
+Some other concerns with flinging signals around:
+ - Odd interactions with some debuggers (e.g. gdb on the Mac)
+ - Restrictions on some standard library calls during GC (e.g. don't
+   use printf on stdout to print GC debug messages)
+*/
+
+#define kMaxThreadId        ((1 << 16) - 1)
+#define kMainThreadId       1
+
+
+static Thread* allocThread(int interpStackSize);
+static bool prepareThread(Thread* thread);
+static void setThreadSelf(Thread* thread);
+static void unlinkThread(Thread* thread);
+static void freeThread(Thread* thread);
+static void assignThreadId(Thread* thread);
+static bool createFakeEntryFrame(Thread* thread);
+static bool createFakeRunFrame(Thread* thread);
+static void* interpThreadStart(void* arg);
+static void* internalThreadStart(void* arg);
+static void threadExitUncaughtException(Thread* thread, Object* group);
+static void threadExitCheck(void* arg);
+static void waitForThreadSuspend(Thread* self, Thread* thread);
+
+/*
+ * Initialize thread list and main thread's environment.  We need to set
+ * up some basic stuff so that dvmThreadSelf() will work when we start
+ * loading classes (e.g. to check for exceptions).
+ */
+bool dvmThreadStartup()
+{
+    Thread* thread;
+
+    /* allocate a TLS slot */
+    if (pthread_key_create(&gDvm.pthreadKeySelf, threadExitCheck) != 0) {
+        LOGE("ERROR: pthread_key_create failed");
+        return false;
+    }
+
+    /* test our pthread lib */
+    if (pthread_getspecific(gDvm.pthreadKeySelf) != NULL)
+        LOGW("WARNING: newly-created pthread TLS slot is not NULL");
+
+    /* prep thread-related locks and conditions */
+    dvmInitMutex(&gDvm.threadListLock);
+    pthread_cond_init(&gDvm.threadStartCond, NULL);
+    pthread_cond_init(&gDvm.vmExitCond, NULL);
+    dvmInitMutex(&gDvm._threadSuspendLock);
+    dvmInitMutex(&gDvm.threadSuspendCountLock);
+    pthread_cond_init(&gDvm.threadSuspendCountCond, NULL);
+
+    /*
+     * Dedicated monitor for Thread.sleep().
+     * TODO: change this to an Object* so we don't have to expose this
+     * call, and we interact better with JDWP monitor calls.  Requires
+     * deferring the object creation to much later (e.g. final "main"
+     * thread prep) or until first use.
+     */
+    gDvm.threadSleepMon = dvmCreateMonitor(NULL);
+
+    gDvm.threadIdMap = dvmAllocBitVector(kMaxThreadId, false);
+
+    thread = allocThread(gDvm.stackSize);
+    if (thread == NULL)
+        return false;
+
+    /* switch mode for when we run initializers */
+    thread->status = THREAD_RUNNING;
+
+    /*
+     * We need to assign the threadId early so we can lock/notify
+     * object monitors.  We'll set the "threadObj" field later.
+     */
+    prepareThread(thread);
+    gDvm.threadList = thread;
+
+#ifdef COUNT_PRECISE_METHODS
+    gDvm.preciseMethods = dvmPointerSetAlloc(200);
+#endif
+
+    return true;
+}
+
+/*
+ * All threads should be stopped by now.  Clean up some thread globals.
+ */
+void dvmThreadShutdown()
+{
+    if (gDvm.threadList != NULL) {
+        /*
+         * If we walk through the thread list and try to free the
+         * lingering thread structures (which should only be for daemon
+         * threads), the daemon threads may crash if they execute before
+         * the process dies.  Let them leak.
+         */
+        freeThread(gDvm.threadList);
+        gDvm.threadList = NULL;
+    }
+
+    dvmFreeBitVector(gDvm.threadIdMap);
+
+    dvmFreeMonitorList();
+
+    pthread_key_delete(gDvm.pthreadKeySelf);
+}
+
+
+/*
+ * Grab the suspend count global lock.
+ */
+static inline void lockThreadSuspendCount()
+{
+    /*
+     * Don't try to change to VMWAIT here.  When we change back to RUNNING
+     * we have to check for a pending suspend, which results in grabbing
+     * this lock recursively.  Doesn't work with "fast" pthread mutexes.
+     *
+     * This lock is always held for very brief periods, so as long as
+     * mutex ordering is respected we shouldn't stall.
+     */
+    dvmLockMutex(&gDvm.threadSuspendCountLock);
+}
+
+/*
+ * Release the suspend count global lock.
+ */
+static inline void unlockThreadSuspendCount()
+{
+    dvmUnlockMutex(&gDvm.threadSuspendCountLock);
+}
+
+/*
+ * Grab the thread list global lock.
+ *
+ * This is held while "suspend all" is trying to make everybody stop.  If
+ * the shutdown is in progress, and somebody tries to grab the lock, they'll
+ * have to wait for the GC to finish.  Therefore it's important that the
+ * thread not be in RUNNING mode.
+ *
+ * We don't have to check to see if we should be suspended once we have
+ * the lock.  Nobody can suspend all threads without holding the thread list
+ * lock while they do it, so by definition there isn't a GC in progress.
+ *
+ * This function deliberately avoids the use of dvmChangeStatus(),
+ * which could grab threadSuspendCountLock.  To avoid deadlock, threads
+ * are required to grab the thread list lock before the thread suspend
+ * count lock.  (See comment in DvmGlobals.)
+ *
+ * TODO: consider checking for suspend after acquiring the lock, and
+ * backing off if set.  As stated above, it can't happen during normal
+ * execution, but it *can* happen during shutdown when daemon threads
+ * are being suspended.
+ */
+void dvmLockThreadList(Thread* self)
+{
+    ThreadStatus oldStatus;
+
+    if (self == NULL)       /* try to get it from TLS */
+        self = dvmThreadSelf();
+
+    if (self != NULL) {
+        oldStatus = self->status;
+        self->status = THREAD_VMWAIT;
+    } else {
+        /* happens during VM shutdown */
+        oldStatus = THREAD_UNDEFINED;  // shut up gcc
+    }
+
+    dvmLockMutex(&gDvm.threadListLock);
+
+    if (self != NULL)
+        self->status = oldStatus;
+}
+
+/*
+ * Try to lock the thread list.
+ *
+ * Returns "true" if we locked it.  This is a "fast" mutex, so if the
+ * current thread holds the lock this will fail.
+ */
+bool dvmTryLockThreadList()
+{
+    return (dvmTryLockMutex(&gDvm.threadListLock) == 0);
+}
+
+/*
+ * Release the thread list global lock.
+ */
+void dvmUnlockThreadList()
+{
+    dvmUnlockMutex(&gDvm.threadListLock);
+}
+
+/*
+ * Convert SuspendCause to a string.
+ */
+static const char* getSuspendCauseStr(SuspendCause why)
+{
+    switch (why) {
+    case SUSPEND_NOT:               return "NOT?";
+    case SUSPEND_FOR_GC:            return "gc";
+    case SUSPEND_FOR_DEBUG:         return "debug";
+    case SUSPEND_FOR_DEBUG_EVENT:   return "debug-event";
+    case SUSPEND_FOR_STACK_DUMP:    return "stack-dump";
+    case SUSPEND_FOR_VERIFY:        return "verify";
+    case SUSPEND_FOR_HPROF:         return "hprof";
+#if defined(WITH_JIT)
+    case SUSPEND_FOR_TBL_RESIZE:    return "table-resize";
+    case SUSPEND_FOR_IC_PATCH:      return "inline-cache-patch";
+    case SUSPEND_FOR_CC_RESET:      return "reset-code-cache";
+    case SUSPEND_FOR_REFRESH:       return "refresh jit status";
+#endif
+    default:                        return "UNKNOWN";
+    }
+}
+
+/*
+ * Grab the "thread suspend" lock.  This is required to prevent the
+ * GC and the debugger from simultaneously suspending all threads.
+ *
+ * If we fail to get the lock, somebody else is trying to suspend all
+ * threads -- including us.  If we go to sleep on the lock we'll deadlock
+ * the VM.  Loop until we get it or somebody puts us to sleep.
+ */
+static void lockThreadSuspend(const char* who, SuspendCause why)
+{
+    const int kSpinSleepTime = 3*1000*1000;        /* 3s */
+    u8 startWhen = 0;       // init req'd to placate gcc
+    int sleepIter = 0;
+    int cc;
+
+    do {
+        cc = dvmTryLockMutex(&gDvm._threadSuspendLock);
+        if (cc != 0) {
+            Thread* self = dvmThreadSelf();
+
+            if (!dvmCheckSuspendPending(self)) {
+                /*
+                 * Could be that a resume-all is in progress, and something
+                 * grabbed the CPU when the wakeup was broadcast.  The thread
+                 * 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.
+                 *
+                 * Could be the debugger telling us to resume at roughly
+                 * the same time we're posting an event.
+                 *
+                 * Could be two app threads both want to patch predicted
+                 * chaining cells around the same time.
+                 */
+                LOGI("threadid=%d ODD: want thread-suspend lock (%s:%s),"
+                     " it's held, no suspend pending",
+                    self->threadId, who, getSuspendCauseStr(why));
+            } else {
+                /* we suspended; reset timeout */
+                sleepIter = 0;
+            }
+
+            /* give the lock-holder a chance to do some work */
+            if (sleepIter == 0)
+                startWhen = dvmGetRelativeTimeUsec();
+            if (!dvmIterativeSleep(sleepIter++, kSpinSleepTime, startWhen)) {
+                LOGE("threadid=%d: couldn't get thread-suspend lock (%s:%s),"
+                     " bailing",
+                    self->threadId, who, getSuspendCauseStr(why));
+                /* threads are not suspended, thread dump could crash */
+                dvmDumpAllThreads(false);
+                dvmAbort();
+            }
+        }
+    } while (cc != 0);
+    assert(cc == 0);
+}
+
+/*
+ * Release the "thread suspend" lock.
+ */
+static inline void unlockThreadSuspend()
+{
+    dvmUnlockMutex(&gDvm._threadSuspendLock);
+}
+
+
+/*
+ * Kill any daemon threads that still exist.  All of ours should be
+ * stopped, so these should be Thread objects or JNI-attached threads
+ * started by the application.  Actively-running threads are likely
+ * to crash the process if they continue to execute while the VM
+ * shuts down, so we really need to kill or suspend them.  (If we want
+ * the VM to restart within this process, we need to kill them, but that
+ * leaves open the possibility of orphaned resources.)
+ *
+ * Waiting for the thread to suspend may be unwise at this point, but
+ * if one of these is wedged in a critical section then we probably
+ * would've locked up on the last GC attempt.
+ *
+ * It's possible for this function to get called after a failed
+ * initialization, so be careful with assumptions about the environment.
+ *
+ * This will be called from whatever thread calls DestroyJavaVM, usually
+ * but not necessarily the main thread.  It's likely, but not guaranteed,
+ * that the current thread has already been cleaned up.
+ */
+void dvmSlayDaemons()
+{
+    Thread* self = dvmThreadSelf();     // may be null
+    Thread* target;
+    int threadId = 0;
+    bool doWait = false;
+
+    dvmLockThreadList(self);
+
+    if (self != NULL)
+        threadId = self->threadId;
+
+    target = gDvm.threadList;
+    while (target != NULL) {
+        if (target == self) {
+            target = target->next;
+            continue;
+        }
+
+        if (!dvmGetFieldBoolean(target->threadObj,
+                gDvm.offJavaLangThread_daemon))
+        {
+            /* should never happen; suspend it with the rest */
+            LOGW("threadid=%d: non-daemon id=%d still running at shutdown?!",
+                threadId, target->threadId);
+        }
+
+        std::string threadName(dvmGetThreadName(target));
+        LOGV("threadid=%d: suspending daemon id=%d name='%s'",
+                threadId, target->threadId, threadName.c_str());
+
+        /* mark as suspended */
+        lockThreadSuspendCount();
+        dvmAddToSuspendCounts(target, 1, 0);
+        unlockThreadSuspendCount();
+        doWait = true;
+
+        target = target->next;
+    }
+
+    //dvmDumpAllThreads(false);
+
+    /*
+     * Unlock the thread list, relocking it later if necessary.  It's
+     * possible a thread is in VMWAIT after calling dvmLockThreadList,
+     * and that function *doesn't* check for pending suspend after
+     * acquiring the lock.  We want to let them finish their business
+     * and see the pending suspend before we continue here.
+     *
+     * There's no guarantee of mutex fairness, so this might not work.
+     * (The alternative is to have dvmLockThreadList check for suspend
+     * after acquiring the lock and back off, something we should consider.)
+     */
+    dvmUnlockThreadList();
+
+    if (doWait) {
+        bool complained = false;
+
+        usleep(200 * 1000);
+
+        dvmLockThreadList(self);
+
+        /*
+         * Sleep for a bit until the threads have suspended.  We're trying
+         * to exit, so don't wait for too long.
+         */
+        int i;
+        for (i = 0; i < 10; i++) {
+            bool allSuspended = true;
+
+            target = gDvm.threadList;
+            while (target != NULL) {
+                if (target == self) {
+                    target = target->next;
+                    continue;
+                }
+
+                if (target->status == THREAD_RUNNING) {
+                    if (!complained)
+                        LOGD("threadid=%d not ready yet", target->threadId);
+                    allSuspended = false;
+                    /* keep going so we log each running daemon once */
+                }
+
+                target = target->next;
+            }
+
+            if (allSuspended) {
+                LOGV("threadid=%d: all daemons have suspended", threadId);
+                break;
+            } else {
+                if (!complained) {
+                    complained = true;
+                    LOGD("threadid=%d: waiting briefly for daemon suspension",
+                        threadId);
+                }
+            }
+
+            usleep(200 * 1000);
+        }
+        dvmUnlockThreadList();
+    }
+
+#if 0   /* bad things happen if they come out of JNI or "spuriously" wake up */
+    /*
+     * Abandon the threads and recover their resources.
+     */
+    target = gDvm.threadList;
+    while (target != NULL) {
+        Thread* nextTarget = target->next;
+        unlinkThread(target);
+        freeThread(target);
+        target = nextTarget;
+    }
+#endif
+
+    //dvmDumpAllThreads(true);
+}
+
+
+/*
+ * Finish preparing the parts of the Thread struct required to support
+ * JNI registration.
+ */
+bool dvmPrepMainForJni(JNIEnv* pEnv)
+{
+    Thread* self;
+
+    /* main thread is always first in list at this point */
+    self = gDvm.threadList;
+    assert(self->threadId == kMainThreadId);
+
+    /* create a "fake" JNI frame at the top of the main thread interp stack */
+    if (!createFakeEntryFrame(self))
+        return false;
+
+    /* fill these in, since they weren't ready at dvmCreateJNIEnv time */
+    dvmSetJniEnvThreadId(pEnv, self);
+    dvmSetThreadJNIEnv(self, (JNIEnv*) pEnv);
+
+    return true;
+}
+
+
+/*
+ * Finish preparing the main thread, allocating some objects to represent
+ * it.  As part of doing so, we finish initializing Thread and ThreadGroup.
+ * This will execute some interpreted code (e.g. class initializers).
+ */
+bool dvmPrepMainThread()
+{
+    Thread* thread;
+    Object* groupObj;
+    Object* threadObj;
+    Object* vmThreadObj;
+    StringObject* threadNameStr;
+    Method* init;
+    JValue unused;
+
+    LOGV("+++ finishing prep on main VM thread");
+
+    /* main thread is always first in list at this point */
+    thread = gDvm.threadList;
+    assert(thread->threadId == kMainThreadId);
+
+    /*
+     * Make sure the classes are initialized.  We have to do this before
+     * we create an instance of them.
+     */
+    if (!dvmInitClass(gDvm.classJavaLangClass)) {
+        LOGE("'Class' class failed to initialize");
+        return false;
+    }
+    if (!dvmInitClass(gDvm.classJavaLangThreadGroup) ||
+        !dvmInitClass(gDvm.classJavaLangThread) ||
+        !dvmInitClass(gDvm.classJavaLangVMThread))
+    {
+        LOGE("thread classes failed to initialize");
+        return false;
+    }
+
+    groupObj = dvmGetMainThreadGroup();
+    if (groupObj == NULL)
+        return false;
+
+    /*
+     * Allocate and construct a Thread with the internal-creation
+     * constructor.
+     */
+    threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);
+    if (threadObj == NULL) {
+        LOGE("unable to allocate main thread object");
+        return false;
+    }
+    dvmReleaseTrackedAlloc(threadObj, NULL);
+
+    threadNameStr = dvmCreateStringFromCstr("main");
+    if (threadNameStr == NULL)
+        return false;
+    dvmReleaseTrackedAlloc((Object*)threadNameStr, NULL);
+
+    init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangThread, "<init>",
+            "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
+    assert(init != NULL);
+    dvmCallMethod(thread, init, threadObj, &unused, groupObj, threadNameStr,
+        THREAD_NORM_PRIORITY, false);
+    if (dvmCheckException(thread)) {
+        LOGE("exception thrown while constructing main thread object");
+        return false;
+    }
+
+    /*
+     * Allocate and construct a VMThread.
+     */
+    vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
+    if (vmThreadObj == NULL) {
+        LOGE("unable to allocate main vmthread object");
+        return false;
+    }
+    dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+
+    init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangVMThread, "<init>",
+            "(Ljava/lang/Thread;)V");
+    dvmCallMethod(thread, init, vmThreadObj, &unused, threadObj);
+    if (dvmCheckException(thread)) {
+        LOGE("exception thrown while constructing main vmthread object");
+        return false;
+    }
+
+    /* set the VMThread.vmData field to our Thread struct */
+    assert(gDvm.offJavaLangVMThread_vmData != 0);
+    dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)thread);
+
+    /*
+     * Stuff the VMThread back into the Thread.  From this point on, other
+     * Threads will see that this Thread is running (at least, they would,
+     * if there were any).
+     */
+    dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread,
+        vmThreadObj);
+
+    thread->threadObj = threadObj;
+
+    /*
+     * Set the "context class loader" field in the system class loader.
+     *
+     * Retrieving the system class loader will cause invocation of
+     * ClassLoader.getSystemClassLoader(), which could conceivably call
+     * Thread.currentThread(), so we want the Thread to be fully configured
+     * before we do this.
+     */
+    Object* systemLoader = dvmGetSystemClassLoader();
+    if (systemLoader == NULL) {
+        LOGW("WARNING: system class loader is NULL (setting main ctxt)");
+        /* keep going? */
+    } else {
+        dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_contextClassLoader,
+            systemLoader);
+        dvmReleaseTrackedAlloc(systemLoader, NULL);
+    }
+
+    /* include self in non-daemon threads (mainly for AttachCurrentThread) */
+    gDvm.nonDaemonThreadCount++;
+
+    return true;
+}
+
+
+/*
+ * Alloc and initialize a Thread struct.
+ *
+ * Does not create any objects, just stuff on the system (malloc) heap.
+ */
+static Thread* allocThread(int interpStackSize)
+{
+    Thread* thread;
+    u1* stackBottom;
+
+    thread = (Thread*) calloc(1, sizeof(Thread));
+    if (thread == NULL)
+        return NULL;
+
+    /* Check sizes and alignment */
+    assert((((uintptr_t)&thread->interpBreak.all) & 0x7) == 0);
+    assert(sizeof(thread->interpBreak) == sizeof(thread->interpBreak.all));
+
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (dvmSelfVerificationShadowSpaceAlloc(thread) == NULL)
+        return NULL;
+#endif
+
+    assert(interpStackSize >= kMinStackSize && interpStackSize <=kMaxStackSize);
+
+    thread->status = THREAD_INITIALIZING;
+
+    /*
+     * Allocate and initialize the interpreted code stack.  We essentially
+     * "lose" the alloc pointer, which points at the bottom of the stack,
+     * but we can get it back later because we know how big the stack is.
+     *
+     * The stack must be aligned on a 4-byte boundary.
+     */
+#ifdef MALLOC_INTERP_STACK
+    stackBottom = (u1*) malloc(interpStackSize);
+    if (stackBottom == NULL) {
+#if defined(WITH_SELF_VERIFICATION)
+        dvmSelfVerificationShadowSpaceFree(thread);
+#endif
+        free(thread);
+        return NULL;
+    }
+    memset(stackBottom, 0xc5, interpStackSize);     // stop valgrind complaints
+#else
+    stackBottom = (u1*) mmap(NULL, interpStackSize, PROT_READ | PROT_WRITE,
+        MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (stackBottom == MAP_FAILED) {
+#if defined(WITH_SELF_VERIFICATION)
+        dvmSelfVerificationShadowSpaceFree(thread);
+#endif
+        free(thread);
+        return NULL;
+    }
+#endif
+
+    assert(((u4)stackBottom & 0x03) == 0); // looks like our malloc ensures this
+    thread->interpStackSize = interpStackSize;
+    thread->interpStackStart = stackBottom + interpStackSize;
+    thread->interpStackEnd = stackBottom + STACK_OVERFLOW_RESERVE;
+
+#ifndef DVM_NO_ASM_INTERP
+    thread->mainHandlerTable = dvmAsmInstructionStart;
+    thread->altHandlerTable = dvmAsmAltInstructionStart;
+    thread->interpBreak.ctl.curHandlerTable = thread->mainHandlerTable;
+#endif
+
+    /* give the thread code a chance to set things up */
+    dvmInitInterpStack(thread, interpStackSize);
+
+    /* One-time setup for interpreter/JIT state */
+    dvmInitInterpreterState(thread);
+
+    return thread;
+}
+
+/*
+ * Get a meaningful thread ID.  At present this only has meaning under Linux,
+ * where getpid() and gettid() sometimes agree and sometimes don't depending
+ * on your thread model (try "export LD_ASSUME_KERNEL=2.4.19").
+ */
+pid_t dvmGetSysThreadId()
+{
+#ifdef HAVE_GETTID
+    return gettid();
+#else
+    return getpid();
+#endif
+}
+
+/*
+ * Finish initialization of a Thread struct.
+ *
+ * This must be called while executing in the new thread, but before the
+ * thread is added to the thread list.
+ *
+ * NOTE: The threadListLock must be held by the caller (needed for
+ * assignThreadId()).
+ */
+static bool prepareThread(Thread* thread)
+{
+    assignThreadId(thread);
+    thread->handle = pthread_self();
+    thread->systemTid = dvmGetSysThreadId();
+
+    //LOGI("SYSTEM TID IS %d (pid is %d)", (int) thread->systemTid,
+    //    (int) getpid());
+    /*
+     * If we were called by dvmAttachCurrentThread, the self value is
+     * already correctly established as "thread".
+     */
+    setThreadSelf(thread);
+
+    LOGV("threadid=%d: interp stack at %p",
+        thread->threadId, thread->interpStackStart - thread->interpStackSize);
+
+    /*
+     * Initialize invokeReq.
+     */
+    dvmInitMutex(&thread->invokeReq.lock);
+    pthread_cond_init(&thread->invokeReq.cv, NULL);
+
+    /*
+     * Initialize our reference tracking tables.
+     *
+     * Most threads won't use jniMonitorRefTable, so we clear out the
+     * structure but don't call the init function (which allocs storage).
+     */
+    if (!thread->jniLocalRefTable.init(kJniLocalRefMin,
+            kJniLocalRefMax, kIndirectKindLocal)) {
+        return false;
+    }
+    if (!dvmInitReferenceTable(&thread->internalLocalRefTable,
+            kInternalRefDefault, kInternalRefMax))
+        return false;
+
+    memset(&thread->jniMonitorRefTable, 0, sizeof(thread->jniMonitorRefTable));
+
+    pthread_cond_init(&thread->waitCond, NULL);
+    dvmInitMutex(&thread->waitMutex);
+
+    /* Initialize safepoint callback mechanism */
+    dvmInitMutex(&thread->callbackMutex);
+
+    return true;
+}
+
+/*
+ * Remove a thread from the internal list.
+ * Clear out the links to make it obvious that the thread is
+ * no longer on the list.  Caller must hold gDvm.threadListLock.
+ */
+static void unlinkThread(Thread* thread)
+{
+    LOG_THREAD("threadid=%d: removing from list", thread->threadId);
+    if (thread == gDvm.threadList) {
+        assert(thread->prev == NULL);
+        gDvm.threadList = thread->next;
+    } else {
+        assert(thread->prev != NULL);
+        thread->prev->next = thread->next;
+    }
+    if (thread->next != NULL)
+        thread->next->prev = thread->prev;
+    thread->prev = thread->next = NULL;
+}
+
+/*
+ * Free a Thread struct, and all the stuff allocated within.
+ */
+static void freeThread(Thread* thread)
+{
+    if (thread == NULL)
+        return;
+
+    /* thread->threadId is zero at this point */
+    LOGVV("threadid=%d: freeing", thread->threadId);
+
+    if (thread->interpStackStart != NULL) {
+        u1* interpStackBottom;
+
+        interpStackBottom = thread->interpStackStart;
+        interpStackBottom -= thread->interpStackSize;
+#ifdef MALLOC_INTERP_STACK
+        free(interpStackBottom);
+#else
+        if (munmap(interpStackBottom, thread->interpStackSize) != 0)
+            LOGW("munmap(thread stack) failed");
+#endif
+    }
+
+    thread->jniLocalRefTable.destroy();
+    dvmClearReferenceTable(&thread->internalLocalRefTable);
+    if (&thread->jniMonitorRefTable.table != NULL)
+        dvmClearReferenceTable(&thread->jniMonitorRefTable);
+
+#if defined(WITH_SELF_VERIFICATION)
+    dvmSelfVerificationShadowSpaceFree(thread);
+#endif
+    free(thread);
+}
+
+/*
+ * Like pthread_self(), but on a Thread*.
+ */
+Thread* dvmThreadSelf()
+{
+    return (Thread*) pthread_getspecific(gDvm.pthreadKeySelf);
+}
+
+/*
+ * Explore our sense of self.  Stuffs the thread pointer into TLS.
+ */
+static void setThreadSelf(Thread* thread)
+{
+    int cc;
+
+    cc = pthread_setspecific(gDvm.pthreadKeySelf, thread);
+    if (cc != 0) {
+        /*
+         * Sometimes this fails under Bionic with EINVAL during shutdown.
+         * This can happen if the timing is just right, e.g. a thread
+         * fails to attach during shutdown, but the "fail" path calls
+         * here to ensure we clean up after ourselves.
+         */
+        if (thread != NULL) {
+            LOGE("pthread_setspecific(%p) failed, err=%d", thread, cc);
+            dvmAbort();     /* the world is fundamentally hosed */
+        }
+    }
+}
+
+/*
+ * This is associated with the pthreadKeySelf key.  It's called by the
+ * pthread library when a thread is exiting and the "self" pointer in TLS
+ * is non-NULL, meaning the VM hasn't had a chance to clean up.  In normal
+ * operation this will not be called.
+ *
+ * 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).
+ *
+ * Because some implementations may want to use the pthread destructor
+ * to initiate the detach, and the ordering of destructors is not defined,
+ * we want to iterate a couple of times to give those a chance to run.
+ */
+static void threadExitCheck(void* arg)
+{
+    const int kMaxCount = 2;
+
+    Thread* self = (Thread*) arg;
+    assert(self != NULL);
+
+    LOGV("threadid=%d: threadExitCheck(%p) count=%d",
+        self->threadId, arg, self->threadExitCheckCount);
+
+    if (self->status == THREAD_ZOMBIE) {
+        LOGW("threadid=%d: Weird -- shouldn't be in threadExitCheck",
+            self->threadId);
+        return;
+    }
+
+    if (self->threadExitCheckCount < kMaxCount) {
+        /*
+         * Spin a couple of times to let other destructors fire.
+         */
+        LOGD("threadid=%d: thread exiting, not yet detached (count=%d)",
+            self->threadId, self->threadExitCheckCount);
+        self->threadExitCheckCount++;
+        int cc = pthread_setspecific(gDvm.pthreadKeySelf, self);
+        if (cc != 0) {
+            LOGE("threadid=%d: unable to re-add thread to TLS",
+                self->threadId);
+            dvmAbort();
+        }
+    } else {
+        LOGE("threadid=%d: native thread exited without detaching",
+            self->threadId);
+        dvmAbort();
+    }
+}
+
+
+/*
+ * Assign the threadId.  This needs to be a small integer so that our
+ * "thin" locks fit in a small number of bits.
+ *
+ * We reserve zero for use as an invalid ID.
+ *
+ * This must be called with threadListLock held.
+ */
+static void assignThreadId(Thread* thread)
+{
+    /*
+     * Find a small unique integer.  threadIdMap is a vector of
+     * kMaxThreadId bits;  dvmAllocBit() returns the index of a
+     * bit, meaning that it will always be < kMaxThreadId.
+     */
+    int num = dvmAllocBit(gDvm.threadIdMap);
+    if (num < 0) {
+        LOGE("Ran out of thread IDs");
+        dvmAbort();     // TODO: make this a non-fatal error result
+    }
+
+    thread->threadId = num + 1;
+
+    assert(thread->threadId != 0);
+}
+
+/*
+ * Give back the thread ID.
+ */
+static void releaseThreadId(Thread* thread)
+{
+    assert(thread->threadId > 0);
+    dvmClearBit(gDvm.threadIdMap, thread->threadId - 1);
+    thread->threadId = 0;
+}
+
+
+/*
+ * Add a stack frame that makes it look like the native code in the main
+ * thread was originally invoked from interpreted code.  This gives us a
+ * place to hang JNI local references.  The VM spec says (v2 5.2) that the
+ * VM begins by executing "main" in a class, so in a way this brings us
+ * closer to the spec.
+ */
+static bool createFakeEntryFrame(Thread* thread)
+{
+    /*
+     * Because we are creating a frame that represents application code, we
+     * want to stuff the application class loader into the method's class
+     * loader field, even though we're using the system class loader to
+     * load it.  This makes life easier over in JNI FindClass (though it
+     * could bite us in other ways).
+     *
+     * Unfortunately this is occurring too early in the initialization,
+     * of necessity coming before JNI is initialized, and we're not quite
+     * ready to set up the application class loader.  Also, overwriting
+     * the class' defining classloader pointer seems unwise.
+     *
+     * Instead, we save a pointer to the method and explicitly check for
+     * it in FindClass.  The method is private so nobody else can call it.
+     */
+
+    assert(thread->threadId == kMainThreadId);      /* main thread only */
+
+    if (!dvmPushJNIFrame(thread, gDvm.methDalvikSystemNativeStart_main))
+        return false;
+
+    /*
+     * Null out the "String[] args" argument.
+     */
+    assert(gDvm.methDalvikSystemNativeStart_main->registersSize == 1);
+    u4* framePtr = (u4*) thread->interpSave.curFrame;
+    framePtr[0] = 0;
+
+    return true;
+}
+
+
+/*
+ * Add a stack frame that makes it look like the native thread has been
+ * executing interpreted code.  This gives us a place to hang JNI local
+ * references.
+ */
+static bool createFakeRunFrame(Thread* thread)
+{
+    return dvmPushJNIFrame(thread, gDvm.methDalvikSystemNativeStart_run);
+}
+
+/*
+ * Helper function to set the name of the current thread
+ */
+static void setThreadName(const char *threadName)
+{
+    int hasAt = 0;
+    int hasDot = 0;
+    const char *s = threadName;
+    while (*s) {
+        if (*s == '.') hasDot = 1;
+        else if (*s == '@') hasAt = 1;
+        s++;
+    }
+    int len = s - threadName;
+    if (len < 15 || hasAt || !hasDot) {
+        s = threadName;
+    } else {
+        s = threadName + len - 15;
+    }
+#if defined(HAVE_ANDROID_PTHREAD_SETNAME_NP)
+    /* pthread_setname_np fails rather than truncating long strings */
+    char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+    strncpy(buf, s, sizeof(buf)-1);
+    buf[sizeof(buf)-1] = '\0';
+    int err = pthread_setname_np(pthread_self(), buf);
+    if (err != 0) {
+        LOGW("Unable to set the name of current thread to '%s': %s",
+            buf, strerror(err));
+    }
+#elif defined(HAVE_PRCTL)
+    prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
+#else
+    LOGD("No way to set current thread's name (%s)", s);
+#endif
+}
+
+/*
+ * Create a thread as a result of java.lang.Thread.start().
+ *
+ * We do have to worry about some concurrency problems, e.g. programs
+ * that try to call Thread.start() on the same object from multiple threads.
+ * (This will fail for all but one, but we have to make sure that it succeeds
+ * for exactly one.)
+ *
+ * Some of the complexity here arises from our desire to mimic the
+ * Thread vs. VMThread class decomposition we inherited.  We've been given
+ * a Thread, and now we need to create a VMThread and then populate both
+ * objects.  We also need to create one of our internal Thread objects.
+ *
+ * Pass in a stack size of 0 to get the default.
+ *
+ * The "threadObj" reference must be pinned by the caller to prevent the GC
+ * from moving it around (e.g. added to the tracked allocation list).
+ */
+bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
+{
+    assert(threadObj != NULL);
+
+    Thread* self = dvmThreadSelf();
+    int stackSize;
+    if (reqStackSize == 0)
+        stackSize = gDvm.stackSize;
+    else if (reqStackSize < kMinStackSize)
+        stackSize = kMinStackSize;
+    else if (reqStackSize > kMaxStackSize)
+        stackSize = kMaxStackSize;
+    else
+        stackSize = reqStackSize;
+
+    pthread_attr_t threadAttr;
+    pthread_attr_init(&threadAttr);
+    pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
+
+    /*
+     * To minimize the time spent in the critical section, we allocate the
+     * vmThread object here.
+     */
+    Object* vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
+    if (vmThreadObj == NULL)
+        return false;
+
+    Thread* newThread = allocThread(stackSize);
+    if (newThread == NULL) {
+        dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+        return false;
+    }
+
+    newThread->threadObj = threadObj;
+
+    assert(newThread->status == THREAD_INITIALIZING);
+
+    /*
+     * We need to lock out other threads while we test and set the
+     * "vmThread" field in java.lang.Thread, because we use that to determine
+     * if this thread has been started before.  We use the thread list lock
+     * because it's handy and we're going to need to grab it again soon
+     * anyway.
+     */
+    dvmLockThreadList(self);
+
+    if (dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread) != NULL) {
+        dvmUnlockThreadList();
+        dvmThrowIllegalThreadStateException(
+            "thread has already been started");
+        freeThread(newThread);
+        dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+    }
+
+    /*
+     * There are actually three data structures: Thread (object), VMThread
+     * (object), and Thread (C struct).  All of them point to at least one
+     * other.
+     *
+     * As soon as "VMThread.vmData" is assigned, other threads can start
+     * making calls into us (e.g. setPriority).
+     */
+    dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)newThread);
+    dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj);
+
+    /*
+     * Thread creation might take a while, so release the lock.
+     */
+    dvmUnlockThreadList();
+
+    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+    pthread_t threadHandle;
+    int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart,
+                            newThread);
+    dvmChangeStatus(self, oldStatus);
+
+    if (cc != 0) {
+        /*
+         * Failure generally indicates that we have exceeded system
+         * resource limits.  VirtualMachineError is probably too severe,
+         * so use OutOfMemoryError.
+         */
+        LOGE("Thread creation failed (err=%s)", strerror(errno));
+
+        dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, NULL);
+
+        dvmThrowOutOfMemoryError("thread creation failed");
+        goto fail;
+    }
+
+    /*
+     * We need to wait for the thread to start.  Otherwise, depending on
+     * the whims of the OS scheduler, we could return and the code in our
+     * thread could try to do operations on the new thread before it had
+     * finished starting.
+     *
+     * The new thread will lock the thread list, change its state to
+     * THREAD_STARTING, broadcast to gDvm.threadStartCond, and then sleep
+     * on gDvm.threadStartCond (which uses the thread list lock).  This
+     * thread (the parent) will either see that the thread is already ready
+     * after we grab the thread list lock, or will be awakened from the
+     * condition variable on the broadcast.
+     *
+     * We don't want to stall the rest of the VM while the new thread
+     * starts, which can happen if the GC wakes up at the wrong moment.
+     * So, we change our own status to VMWAIT, and self-suspend if
+     * necessary after we finish adding the new thread.
+     *
+     *
+     * We have to deal with an odd race with the GC/debugger suspension
+     * mechanism when creating a new thread.  The information about whether
+     * or not a thread should be suspended is contained entirely within
+     * the Thread struct; this is usually cleaner to deal with than having
+     * one or more globally-visible suspension flags.  The trouble is that
+     * we could create the thread while the VM is trying to suspend all
+     * threads.  The suspend-count won't be nonzero for the new thread,
+     * so dvmChangeStatus(THREAD_RUNNING) won't cause a suspension.
+     *
+     * 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 (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
+     *  - put self into THREAD_VMWAIT so GC doesn't wait for us
+     *  - sleep on condition var (mutex = thread list lock) until child starts
+     *  + GC triggered by another thread
+     *  + thread list locked; suspend counts updated; thread list unlocked
+     *  + loop waiting for all runnable threads to suspend
+     *  + success, start GC
+     *  o child thread wakes, signals condition var to wake parent
+     *  o child waits for parent ack on condition variable
+     *  - we wake up, locking thread list
+     *  - add child to thread list
+     *  - unlock thread list
+     *  - change our state back to THREAD_RUNNING; GC causes us to suspend
+     *  + GC finishes; all threads in thread list are resumed
+     *  - lock thread list
+     *  - set child to THREAD_VMWAIT, and signal it to start
+     *  - unlock thread list
+     *  o child resumes
+     *  o child changes state to THREAD_RUNNING
+     *
+     * The above shows the GC starting up during thread creation, but if
+     * it starts anywhere after VMThread.create() is called it will
+     * produce the same series of events.
+     *
+     * Once the child is in the thread list, it will be suspended and
+     * resumed like any other thread.  In the above scenario the resume-all
+     * code will try to resume the new thread, which was never actually
+     * suspended, and try to decrement the child's thread suspend count to -1.
+     * We can catch this in the resume-all code.
+     *
+     * Bouncing back and forth between threads like this adds a small amount
+     * of scheduler overhead to thread startup.
+     *
+     * One alternative to having the child wait for the parent would be
+     * to have the child inherit the parents' suspension count.  This
+     * would work for a GC, since we can safely assume that the parent
+     * thread didn't cause it, but we must only do so if the parent suspension
+     * was caused by a suspend-all.  If the parent was being asked to
+     * suspend singly by the debugger, the child should not inherit the value.
+     *
+     * We could also have a global "new thread suspend count" that gets
+     * picked up by new threads before changing state to THREAD_RUNNING.
+     * This would be protected by the thread list lock and set by a
+     * suspend-all.
+     */
+    dvmLockThreadList(self);
+    assert(self->status == THREAD_RUNNING);
+    self->status = THREAD_VMWAIT;
+    while (newThread->status != THREAD_STARTING)
+        pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock);
+
+    LOG_THREAD("threadid=%d: adding to list", newThread->threadId);
+    newThread->next = gDvm.threadList->next;
+    if (newThread->next != NULL)
+        newThread->next->prev = newThread;
+    newThread->prev = gDvm.threadList;
+    gDvm.threadList->next = newThread;
+
+    /* Add any existing global modes to the interpBreak control */
+    dvmInitializeInterpBreak(newThread);
+
+    if (!dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon))
+        gDvm.nonDaemonThreadCount++;        // guarded by thread list lock
+
+    dvmUnlockThreadList();
+
+    /* change status back to RUNNING, self-suspending if necessary */
+    dvmChangeStatus(self, THREAD_RUNNING);
+
+    /*
+     * Tell the new thread to start.
+     *
+     * We must hold the thread list lock before messing with another thread.
+     * In the general case we would also need to verify that newThread was
+     * still in the thread list, but in our case the thread has not started
+     * executing user code and therefore has not had a chance to exit.
+     *
+     * We move it to VMWAIT, and it then shifts itself to RUNNING, which
+     * comes with a suspend-pending check.
+     */
+    dvmLockThreadList(self);
+
+    assert(newThread->status == THREAD_STARTING);
+    newThread->status = THREAD_VMWAIT;
+    pthread_cond_broadcast(&gDvm.threadStartCond);
+
+    dvmUnlockThreadList();
+
+    dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+    return true;
+
+fail:
+    freeThread(newThread);
+    dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+    return false;
+}
+
+/*
+ * pthread entry function for threads started from interpreted code.
+ */
+static void* interpThreadStart(void* arg)
+{
+    Thread* self = (Thread*) arg;
+
+    std::string threadName(dvmGetThreadName(self));
+    setThreadName(threadName.c_str());
+
+    /*
+     * Finish initializing the Thread struct.
+     */
+    dvmLockThreadList(self);
+    prepareThread(self);
+
+    LOG_THREAD("threadid=%d: created from interp", self->threadId);
+
+    /*
+     * Change our status and wake our parent, who will add us to the
+     * thread list and advance our state to VMWAIT.
+     */
+    self->status = THREAD_STARTING;
+    pthread_cond_broadcast(&gDvm.threadStartCond);
+
+    /*
+     * Wait until the parent says we can go.  Assuming there wasn't a
+     * suspend pending, this will happen immediately.  When it completes,
+     * we're full-fledged citizens of the VM.
+     *
+     * We have to use THREAD_VMWAIT here rather than THREAD_RUNNING
+     * because the pthread_cond_wait below needs to reacquire a lock that
+     * suspend-all is also interested in.  If we get unlucky, the parent could
+     * change us to THREAD_RUNNING, then a GC could start before we get
+     * signaled, and suspend-all will grab the thread list lock and then
+     * wait for us to suspend.  We'll be in the tail end of pthread_cond_wait
+     * trying to get the lock.
+     */
+    while (self->status != THREAD_VMWAIT)
+        pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock);
+
+    dvmUnlockThreadList();
+
+    /*
+     * Add a JNI context.
+     */
+    self->jniEnv = dvmCreateJNIEnv(self);
+
+    /*
+     * Change our state so the GC will wait for us from now on.  If a GC is
+     * in progress this call will suspend us.
+     */
+    dvmChangeStatus(self, THREAD_RUNNING);
+
+    /*
+     * Notify the debugger & DDM.  The debugger notification may cause
+     * us to suspend ourselves (and others).  The thread state may change
+     * to VMWAIT briefly if network packets are sent.
+     */
+    if (gDvm.debuggerConnected)
+        dvmDbgPostThreadStart(self);
+
+    /*
+     * Set the system thread priority according to the Thread object's
+     * priority level.  We don't usually need to do this, because both the
+     * Thread object and system thread priorities inherit from parents.  The
+     * tricky case is when somebody creates a Thread object, calls
+     * setPriority(), and then starts the thread.  We could manage this with
+     * a "needs priority update" flag to avoid the redundant call.
+     */
+    int priority = dvmGetFieldInt(self->threadObj,
+                        gDvm.offJavaLangThread_priority);
+    dvmChangeThreadPriority(self, priority);
+
+    /*
+     * Execute the "run" method.
+     *
+     * At this point our stack is empty, so somebody who comes looking for
+     * stack traces right now won't have much to look at.  This is normal.
+     */
+    Method* run = self->threadObj->clazz->vtable[gDvm.voffJavaLangThread_run];
+    JValue unused;
+
+    LOGV("threadid=%d: calling run()", self->threadId);
+    assert(strcmp(run->name, "run") == 0);
+    dvmCallMethod(self, run, self->threadObj, &unused);
+    LOGV("threadid=%d: exiting", self->threadId);
+
+    /*
+     * Remove the thread from various lists, report its death, and free
+     * its resources.
+     */
+    dvmDetachCurrentThread();
+
+    return NULL;
+}
+
+/*
+ * The current thread is exiting with an uncaught exception.  The
+ * Java programming language allows the application to provide a
+ * thread-exit-uncaught-exception handler for the VM, for a specific
+ * Thread, and for all threads in a ThreadGroup.
+ *
+ * Version 1.5 added the per-thread handler.  We need to call
+ * "uncaughtException" in the handler object, which is either the
+ * ThreadGroup object or the Thread-specific handler.
+ *
+ * This should only be called when an exception is pending.  Before
+ * returning, the exception will be cleared.
+ */
+static void threadExitUncaughtException(Thread* self, Object* group)
+{
+    Object* exception;
+    Object* handlerObj;
+    Method* uncaughtHandler;
+
+    LOGW("threadid=%d: thread exiting with uncaught exception (group=%p)",
+        self->threadId, group);
+    assert(group != NULL);
+
+    /*
+     * Get a pointer to the exception, then clear out the one in the
+     * thread.  We don't want to have it set when executing interpreted code.
+     */
+    exception = dvmGetException(self);
+    assert(exception != NULL);
+    dvmAddTrackedAlloc(exception, self);
+    dvmClearException(self);
+
+    /*
+     * Get the Thread's "uncaughtHandler" object.  Use it if non-NULL;
+     * else use "group" (which is an instance of UncaughtExceptionHandler).
+     * The ThreadGroup will handle it directly or call the default
+     * uncaught exception handler.
+     */
+    handlerObj = dvmGetFieldObject(self->threadObj,
+            gDvm.offJavaLangThread_uncaughtHandler);
+    if (handlerObj == NULL)
+        handlerObj = group;
+
+    /*
+     * Find the "uncaughtException" method in this object.  The method
+     * was declared in the Thread.UncaughtExceptionHandler interface.
+     */
+    uncaughtHandler = dvmFindVirtualMethodHierByDescriptor(handlerObj->clazz,
+            "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
+
+    if (uncaughtHandler != NULL) {
+        //LOGI("+++ calling %s.uncaughtException",
+        //     handlerObj->clazz->descriptor);
+        JValue unused;
+        dvmCallMethod(self, uncaughtHandler, handlerObj, &unused,
+            self->threadObj, exception);
+    } else {
+        /* should be impossible, but handle it anyway */
+        LOGW("WARNING: no 'uncaughtException' method in class %s",
+            handlerObj->clazz->descriptor);
+        dvmSetException(self, exception);
+        dvmLogExceptionStackTrace();
+    }
+
+    /* if the uncaught handler threw, clear it */
+    dvmClearException(self);
+
+    dvmReleaseTrackedAlloc(exception, self);
+
+    /* Remove this thread's suspendCount from global suspendCount sum */
+    lockThreadSuspendCount();
+    dvmAddToSuspendCounts(self, -self->suspendCount, 0);
+    unlockThreadSuspendCount();
+}
+
+
+/*
+ * Create an internal VM thread, for things like JDWP and finalizers.
+ *
+ * The easiest way to do this is create a new thread and then use the
+ * JNI AttachCurrentThread implementation.
+ *
+ * This does not return until after the new thread has begun executing.
+ */
+bool dvmCreateInternalThread(pthread_t* pHandle, const char* name,
+    InternalThreadStart func, void* funcArg)
+{
+    InternalStartArgs* pArgs;
+    Object* systemGroup;
+    pthread_attr_t threadAttr;
+    volatile Thread* newThread = NULL;
+    volatile int createStatus = 0;
+
+    systemGroup = dvmGetSystemThreadGroup();
+    if (systemGroup == NULL)
+        return false;
+
+    pArgs = (InternalStartArgs*) malloc(sizeof(*pArgs));
+    pArgs->func = func;
+    pArgs->funcArg = funcArg;
+    pArgs->name = strdup(name);     // storage will be owned by new thread
+    pArgs->group = systemGroup;
+    pArgs->isDaemon = true;
+    pArgs->pThread = &newThread;
+    pArgs->pCreateStatus = &createStatus;
+
+    pthread_attr_init(&threadAttr);
+    //pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
+
+    if (pthread_create(pHandle, &threadAttr, internalThreadStart,
+            pArgs) != 0)
+    {
+        LOGE("internal thread creation failed");
+        free(pArgs->name);
+        free(pArgs);
+        return false;
+    }
+
+    /*
+     * Wait for the child to start.  This gives us an opportunity to make
+     * sure that the thread started correctly, and allows our caller to
+     * assume that the thread has started running.
+     *
+     * Because we aren't holding a lock across the thread creation, it's
+     * possible that the child will already have completed its
+     * initialization.  Because the child only adjusts "createStatus" while
+     * holding the thread list lock, the initial condition on the "while"
+     * loop will correctly avoid the wait if this occurs.
+     *
+     * It's also possible that we'll have to wait for the thread to finish
+     * being created, and as part of allocating a Thread object it might
+     * need to initiate a GC.  We switch to VMWAIT while we pause.
+     */
+    Thread* self = dvmThreadSelf();
+    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+    dvmLockThreadList(self);
+    while (createStatus == 0)
+        pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock);
+
+    if (newThread == NULL) {
+        LOGW("internal thread create failed (createStatus=%d)", createStatus);
+        assert(createStatus < 0);
+        /* don't free pArgs -- if pthread_create succeeded, child owns it */
+        dvmUnlockThreadList();
+        dvmChangeStatus(self, oldStatus);
+        return false;
+    }
+
+    /* thread could be in any state now (except early init states) */
+    //assert(newThread->status == THREAD_RUNNING);
+
+    dvmUnlockThreadList();
+    dvmChangeStatus(self, oldStatus);
+
+    return true;
+}
+
+/*
+ * pthread entry function for internally-created threads.
+ *
+ * We are expected to free "arg" and its contents.  If we're a daemon
+ * thread, and we get cancelled abruptly when the VM shuts down, the
+ * storage won't be freed.  If this becomes a concern we can make a copy
+ * on the stack.
+ */
+static void* internalThreadStart(void* arg)
+{
+    InternalStartArgs* pArgs = (InternalStartArgs*) arg;
+    JavaVMAttachArgs jniArgs;
+
+    jniArgs.version = JNI_VERSION_1_2;
+    jniArgs.name = pArgs->name;
+    jniArgs.group = reinterpret_cast<jobject>(pArgs->group);
+
+    setThreadName(pArgs->name);
+
+    /* use local jniArgs as stack top */
+    if (dvmAttachCurrentThread(&jniArgs, pArgs->isDaemon)) {
+        /*
+         * Tell the parent of our success.
+         *
+         * threadListLock is the mutex for threadStartCond.
+         */
+        dvmLockThreadList(dvmThreadSelf());
+        *pArgs->pCreateStatus = 1;
+        *pArgs->pThread = dvmThreadSelf();
+        pthread_cond_broadcast(&gDvm.threadStartCond);
+        dvmUnlockThreadList();
+
+        LOG_THREAD("threadid=%d: internal '%s'",
+            dvmThreadSelf()->threadId, pArgs->name);
+
+        /* execute */
+        (*pArgs->func)(pArgs->funcArg);
+
+        /* detach ourselves */
+        dvmDetachCurrentThread();
+    } else {
+        /*
+         * Tell the parent of our failure.  We don't have a Thread struct,
+         * so we can't be suspended, so we don't need to enter a critical
+         * section.
+         */
+        dvmLockThreadList(dvmThreadSelf());
+        *pArgs->pCreateStatus = -1;
+        assert(*pArgs->pThread == NULL);
+        pthread_cond_broadcast(&gDvm.threadStartCond);
+        dvmUnlockThreadList();
+
+        assert(*pArgs->pThread == NULL);
+    }
+
+    free(pArgs->name);
+    free(pArgs);
+    return NULL;
+}
+
+/*
+ * Attach the current thread to the VM.
+ *
+ * Used for internally-created threads and JNI's AttachCurrentThread.
+ */
+bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon)
+{
+    Thread* self = NULL;
+    Object* threadObj = NULL;
+    Object* vmThreadObj = NULL;
+    StringObject* threadNameStr = NULL;
+    Method* init;
+    bool ok, ret;
+
+    /* allocate thread struct, and establish a basic sense of self */
+    self = allocThread(gDvm.stackSize);
+    if (self == NULL)
+        goto fail;
+    setThreadSelf(self);
+
+    /*
+     * Finish our thread prep.  We need to do this before adding ourselves
+     * to the thread list or invoking any interpreted code.  prepareThread()
+     * requires that we hold the thread list lock.
+     */
+    dvmLockThreadList(self);
+    ok = prepareThread(self);
+    dvmUnlockThreadList();
+    if (!ok)
+        goto fail;
+
+    self->jniEnv = dvmCreateJNIEnv(self);
+    if (self->jniEnv == NULL)
+        goto fail;
+
+    /*
+     * Create a "fake" JNI frame at the top of the main thread interp stack.
+     * It isn't really necessary for the internal threads, but it gives
+     * the debugger something to show.  It is essential for the JNI-attached
+     * threads.
+     */
+    if (!createFakeRunFrame(self))
+        goto fail;
+
+    /*
+     * The native side of the thread is ready; add it to the list.  Once
+     * it's on the list the thread is visible to the JDWP code and the GC.
+     */
+    LOG_THREAD("threadid=%d: adding to list (attached)", self->threadId);
+
+    dvmLockThreadList(self);
+
+    self->next = gDvm.threadList->next;
+    if (self->next != NULL)
+        self->next->prev = self;
+    self->prev = gDvm.threadList;
+    gDvm.threadList->next = self;
+    if (!isDaemon)
+        gDvm.nonDaemonThreadCount++;
+
+    dvmUnlockThreadList();
+
+    /*
+     * Switch state from initializing to running.
+     *
+     * It's possible that a GC began right before we added ourselves
+     * to the thread list, and is still going.  That means our thread
+     * suspend count won't reflect the fact that we should be suspended.
+     * To deal with this, we transition to VMWAIT, pulse the heap lock,
+     * and then advance to RUNNING.  That will ensure that we stall until
+     * the GC completes.
+     *
+     * Once we're in RUNNING, we're like any other thread in the VM (except
+     * for the lack of an initialized threadObj).  We're then free to
+     * allocate and initialize objects.
+     */
+    assert(self->status == THREAD_INITIALIZING);
+    dvmChangeStatus(self, THREAD_VMWAIT);
+    dvmLockMutex(&gDvm.gcHeapLock);
+    dvmUnlockMutex(&gDvm.gcHeapLock);
+    dvmChangeStatus(self, THREAD_RUNNING);
+
+    /*
+     * Create Thread and VMThread objects.
+     */
+    threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);
+    vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
+    if (threadObj == NULL || vmThreadObj == NULL)
+        goto fail_unlink;
+
+    /*
+     * This makes threadObj visible to the GC.  We still have it in the
+     * tracked allocation table, so it can't move around on us.
+     */
+    self->threadObj = threadObj;
+    dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)self);
+
+    /*
+     * Create a string for the thread name.
+     */
+    if (pArgs->name != NULL) {
+        threadNameStr = dvmCreateStringFromCstr(pArgs->name);
+        if (threadNameStr == NULL) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            goto fail_unlink;
+        }
+    }
+
+    init = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangThread, "<init>",
+            "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
+    if (init == NULL) {
+        assert(dvmCheckException(self));
+        goto fail_unlink;
+    }
+
+    /*
+     * Now we're ready to run some interpreted code.
+     *
+     * We need to construct the Thread object and set the VMThread field.
+     * Setting VMThread tells interpreted code that we're alive.
+     *
+     * Call the (group, name, priority, daemon) constructor on the Thread.
+     * This sets the thread's name and adds it to the specified group, and
+     * provides values for priority and daemon (which are normally inherited
+     * from the current thread).
+     */
+    JValue unused;
+    dvmCallMethod(self, init, threadObj, &unused, (Object*)pArgs->group,
+            threadNameStr, os_getThreadPriorityFromSystem(), isDaemon);
+    if (dvmCheckException(self)) {
+        LOGE("exception thrown while constructing attached thread object");
+        goto fail_unlink;
+    }
+
+    /*
+     * Set the VMThread field, which tells interpreted code that we're alive.
+     *
+     * The risk of a thread start collision here is very low; somebody
+     * would have to be deliberately polling the ThreadGroup list and
+     * trying to start threads against anything it sees, which would
+     * generally cause problems for all thread creation.  However, for
+     * correctness we test "vmThread" before setting it.
+     *
+     * TODO: this still has a race, it's just smaller.  Not sure this is
+     * worth putting effort into fixing.  Need to hold a lock while
+     * fiddling with the field, or maybe initialize the Thread object in a
+     * way that ensures another thread can't call start() on it.
+     */
+    if (dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread) != NULL) {
+        LOGW("WOW: thread start hijack");
+        dvmThrowIllegalThreadStateException(
+            "thread has already been started");
+        /* We don't want to free anything associated with the thread
+         * because someone is obviously interested in it.  Just let
+         * it go and hope it will clean itself up when its finished.
+         * This case should never happen anyway.
+         *
+         * Since we're letting it live, we need to finish setting it up.
+         * We just have to let the caller know that the intended operation
+         * has failed.
+         *
+         * [ This seems strange -- stepping on the vmThread object that's
+         * already present seems like a bad idea.  TODO: figure this out. ]
+         */
+        ret = false;
+    } else {
+        ret = true;
+    }
+    dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj);
+
+    /* we can now safely un-pin these */
+    dvmReleaseTrackedAlloc(threadObj, self);
+    dvmReleaseTrackedAlloc(vmThreadObj, self);
+    dvmReleaseTrackedAlloc((Object*)threadNameStr, self);
+
+    LOG_THREAD("threadid=%d: attached from native, name=%s",
+        self->threadId, pArgs->name);
+
+    /* tell the debugger & DDM */
+    if (gDvm.debuggerConnected)
+        dvmDbgPostThreadStart(self);
+
+    return ret;
+
+fail_unlink:
+    dvmLockThreadList(self);
+    unlinkThread(self);
+    if (!isDaemon)
+        gDvm.nonDaemonThreadCount--;
+    dvmUnlockThreadList();
+    /* fall through to "fail" */
+fail:
+    dvmReleaseTrackedAlloc(threadObj, self);
+    dvmReleaseTrackedAlloc(vmThreadObj, self);
+    dvmReleaseTrackedAlloc((Object*)threadNameStr, self);
+    if (self != NULL) {
+        if (self->jniEnv != NULL) {
+            dvmDestroyJNIEnv(self->jniEnv);
+            self->jniEnv = NULL;
+        }
+        freeThread(self);
+    }
+    setThreadSelf(NULL);
+    return false;
+}
+
+/*
+ * Detach the thread from the various data structures, notify other threads
+ * that are waiting to "join" it, and free up all heap-allocated storage.
+ *
+ * Used for all threads.
+ *
+ * When we get here the interpreted stack should be empty.  The JNI 1.6 spec
+ * requires us to enforce this for the DetachCurrentThread call, probably
+ * because it also says that DetachCurrentThread causes all monitors
+ * associated with the thread to be released.  (Because the stack is empty,
+ * we only have to worry about explicit JNI calls to MonitorEnter.)
+ *
+ * THOUGHT:
+ * We might want to avoid freeing our internal Thread structure until the
+ * associated Thread/VMThread objects get GCed.  Our Thread is impossible to
+ * get to once the thread shuts down, but there is a small possibility of
+ * an operation starting in another thread before this thread halts, and
+ * finishing much later (perhaps the thread got stalled by a weird OS bug).
+ * We don't want something like Thread.isInterrupted() crawling through
+ * freed storage.  Can do with a Thread finalizer, or by creating a
+ * dedicated ThreadObject class for java/lang/Thread and moving all of our
+ * state into that.
+ */
+void dvmDetachCurrentThread()
+{
+    Thread* self = dvmThreadSelf();
+    Object* vmThread;
+    Object* group;
+
+    /*
+     * Make sure we're not detaching a thread that's still running.  (This
+     * could happen with an explicit JNI detach call.)
+     *
+     * A thread created by interpreted code will finish with a depth of
+     * zero, while a JNI-attached thread will have the synthetic "stack
+     * starter" native method at the top.
+     */
+    int curDepth = dvmComputeExactFrameDepth(self->interpSave.curFrame);
+    if (curDepth != 0) {
+        bool topIsNative = false;
+
+        if (curDepth == 1) {
+            /* not expecting a lingering break frame; just look at curFrame */
+            assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
+            StackSaveArea* ssa = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+            if (dvmIsNativeMethod(ssa->method))
+                topIsNative = true;
+        }
+
+        if (!topIsNative) {
+            LOGE("ERROR: detaching thread with interp frames (count=%d)",
+                curDepth);
+            dvmDumpThread(self, false);
+            dvmAbort();
+        }
+    }
+
+    group = dvmGetFieldObject(self->threadObj, gDvm.offJavaLangThread_group);
+    LOG_THREAD("threadid=%d: detach (group=%p)", self->threadId, group);
+
+    /*
+     * Release any held monitors.  Since there are no interpreted stack
+     * frames, the only thing left are the monitors held by JNI MonitorEnter
+     * calls.
+     */
+    dvmReleaseJniMonitors(self);
+
+    /*
+     * Do some thread-exit uncaught exception processing if necessary.
+     */
+    if (dvmCheckException(self))
+        threadExitUncaughtException(self, group);
+
+    /*
+     * Remove the thread from the thread group.
+     */
+    if (group != NULL) {
+        Method* removeThread =
+            group->clazz->vtable[gDvm.voffJavaLangThreadGroup_removeThread];
+        JValue unused;
+        dvmCallMethod(self, removeThread, group, &unused, self->threadObj);
+    }
+
+    /*
+     * Clear the vmThread reference in the Thread object.  Interpreted code
+     * will now see that this Thread is not running.  As this may be the
+     * only reference to the VMThread object that the VM knows about, we
+     * have to create an internal reference to it first.
+     */
+    vmThread = dvmGetFieldObject(self->threadObj,
+                    gDvm.offJavaLangThread_vmThread);
+    dvmAddTrackedAlloc(vmThread, self);
+    dvmSetFieldObject(self->threadObj, gDvm.offJavaLangThread_vmThread, NULL);
+
+    /* clear out our struct Thread pointer, since it's going away */
+    dvmSetFieldObject(vmThread, gDvm.offJavaLangVMThread_vmData, NULL);
+
+    /*
+     * Tell the debugger & DDM.  This may cause the current thread or all
+     * threads to suspend.
+     *
+     * The JDWP spec is somewhat vague about when this happens, other than
+     * that it's issued by the dying thread, which may still appear in
+     * an "all threads" listing.
+     */
+    if (gDvm.debuggerConnected)
+        dvmDbgPostThreadDeath(self);
+
+    /*
+     * Thread.join() is implemented as an Object.wait() on the VMThread
+     * object.  Signal anyone who is waiting.
+     */
+    dvmLockObject(self, vmThread);
+    dvmObjectNotifyAll(self, vmThread);
+    dvmUnlockObject(self, vmThread);
+
+    dvmReleaseTrackedAlloc(vmThread, self);
+    vmThread = NULL;
+
+    /*
+     * We're done manipulating objects, so it's okay if the GC runs in
+     * parallel with us from here out.  It's important to do this if
+     * profiling is enabled, since we can wait indefinitely.
+     */
+    volatile void* raw = reinterpret_cast<volatile void*>(&self->status);
+    volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw);
+    android_atomic_release_store(THREAD_VMWAIT, addr);
+
+    /*
+     * If we're doing method trace profiling, we don't want threads to exit,
+     * because if they do we'll end up reusing thread IDs.  This complicates
+     * analysis and makes it impossible to have reasonable output in the
+     * "threads" section of the "key" file.
+     *
+     * We need to do this after Thread.join() completes, or other threads
+     * could get wedged.  Since self->threadObj is still valid, the Thread
+     * object will not get GCed even though we're no longer in the ThreadGroup
+     * list (which is important since the profiling thread needs to get
+     * the thread's name).
+     */
+    MethodTraceState* traceState = &gDvm.methodTrace;
+
+    dvmLockMutex(&traceState->startStopLock);
+    if (traceState->traceEnabled) {
+        LOGI("threadid=%d: waiting for method trace to finish",
+            self->threadId);
+        while (traceState->traceEnabled) {
+            dvmWaitCond(&traceState->threadExitCond,
+                        &traceState->startStopLock);
+        }
+    }
+    dvmUnlockMutex(&traceState->startStopLock);
+
+    dvmLockThreadList(self);
+
+    /*
+     * Lose the JNI context.
+     */
+    dvmDestroyJNIEnv(self->jniEnv);
+    self->jniEnv = NULL;
+
+    self->status = THREAD_ZOMBIE;
+
+    /*
+     * Remove ourselves from the internal thread list.
+     */
+    unlinkThread(self);
+
+    /*
+     * If we're the last one standing, signal anybody waiting in
+     * DestroyJavaVM that it's okay to exit.
+     */
+    if (!dvmGetFieldBoolean(self->threadObj, gDvm.offJavaLangThread_daemon)) {
+        gDvm.nonDaemonThreadCount--;        // guarded by thread list lock
+
+        if (gDvm.nonDaemonThreadCount == 0) {
+            int cc;
+
+            LOGV("threadid=%d: last non-daemon thread", self->threadId);
+            //dvmDumpAllThreads(false);
+            // cond var guarded by threadListLock, which we already hold
+            cc = pthread_cond_signal(&gDvm.vmExitCond);
+            assert(cc == 0);
+        }
+    }
+
+    LOGV("threadid=%d: bye!", self->threadId);
+    releaseThreadId(self);
+    dvmUnlockThreadList();
+
+    setThreadSelf(NULL);
+
+    freeThread(self);
+}
+
+
+/*
+ * Suspend a single thread.  Do not use to suspend yourself.
+ *
+ * This is used primarily for debugger/DDMS activity.  Does not return
+ * until the thread has suspended or is in a "safe" state (e.g. executing
+ * native code outside the VM).
+ *
+ * The thread list lock should be held before calling here -- it's not
+ * entirely safe to hang on to a Thread* from another thread otherwise.
+ * (We'd need to grab it here anyway to avoid clashing with a suspend-all.)
+ */
+void dvmSuspendThread(Thread* thread)
+{
+    assert(thread != NULL);
+    assert(thread != dvmThreadSelf());
+    //assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState));
+
+    lockThreadSuspendCount();
+    dvmAddToSuspendCounts(thread, 1, 1);
+
+    LOG_THREAD("threadid=%d: suspend++, now=%d",
+        thread->threadId, thread->suspendCount);
+    unlockThreadSuspendCount();
+
+    waitForThreadSuspend(dvmThreadSelf(), thread);
+}
+
+/*
+ * Reduce the suspend count of a thread.  If it hits zero, tell it to
+ * resume.
+ *
+ * Used primarily for debugger/DDMS activity.  The thread in question
+ * might have been suspended singly or as part of a suspend-all operation.
+ *
+ * The thread list lock should be held before calling here -- it's not
+ * entirely safe to hang on to a Thread* from another thread otherwise.
+ * (We'd need to grab it here anyway to avoid clashing with a suspend-all.)
+ */
+void dvmResumeThread(Thread* thread)
+{
+    assert(thread != NULL);
+    assert(thread != dvmThreadSelf());
+    //assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState));
+
+    lockThreadSuspendCount();
+    if (thread->suspendCount > 0) {
+        dvmAddToSuspendCounts(thread, -1, -1);
+    } else {
+        LOG_THREAD("threadid=%d:  suspendCount already zero",
+            thread->threadId);
+    }
+
+    LOG_THREAD("threadid=%d: suspend--, now=%d",
+        thread->threadId, thread->suspendCount);
+
+    if (thread->suspendCount == 0) {
+        dvmBroadcastCond(&gDvm.threadSuspendCountCond);
+    }
+
+    unlockThreadSuspendCount();
+}
+
+/*
+ * Suspend yourself, as a result of debugger activity.
+ */
+void dvmSuspendSelf(bool jdwpActivity)
+{
+    Thread* self = dvmThreadSelf();
+
+    /* debugger thread must not suspend itself due to debugger activity! */
+    assert(gDvm.jdwpState != NULL);
+    if (self->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) {
+        assert(false);
+        return;
+    }
+
+    /*
+     * Collisions with other suspends aren't really interesting.  We want
+     * to ensure that we're the only one fiddling with the suspend count
+     * though.
+     */
+    lockThreadSuspendCount();
+    dvmAddToSuspendCounts(self, 1, 1);
+
+    /*
+     * Suspend ourselves.
+     */
+    assert(self->suspendCount > 0);
+    self->status = THREAD_SUSPENDED;
+    LOG_THREAD("threadid=%d: self-suspending (dbg)", self->threadId);
+
+    /*
+     * Tell JDWP that we've completed suspension.  The JDWP thread can't
+     * tell us to resume before we're fully asleep because we hold the
+     * suspend count lock.
+     *
+     * If we got here via waitForDebugger(), don't do this part.
+     */
+    if (jdwpActivity) {
+        //LOGI("threadid=%d: clearing wait-for-event (my handle=%08x)",
+        //    self->threadId, (int) self->handle);
+        dvmJdwpClearWaitForEventThread(gDvm.jdwpState);
+    }
+
+    while (self->suspendCount != 0) {
+        dvmWaitCond(&gDvm.threadSuspendCountCond,
+                    &gDvm.threadSuspendCountLock);
+        if (self->suspendCount != 0) {
+            /*
+             * The condition was signaled but we're still suspended.  This
+             * can happen if the debugger lets go while a SIGQUIT thread
+             * dump event is pending (assuming SignalCatcher was resumed for
+             * just long enough to try to grab the thread-suspend lock).
+             */
+            LOGD("threadid=%d: still suspended after undo (sc=%d dc=%d)",
+                self->threadId, self->suspendCount, self->dbgSuspendCount);
+        }
+    }
+    assert(self->suspendCount == 0 && self->dbgSuspendCount == 0);
+    self->status = THREAD_RUNNING;
+    LOG_THREAD("threadid=%d: self-reviving (dbg), status=%d",
+        self->threadId, self->status);
+
+    unlockThreadSuspendCount();
+}
+
+/*
+ * Dump the state of the current thread and that of another thread that
+ * we think is wedged.
+ */
+static void dumpWedgedThread(Thread* thread)
+{
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmPrintNativeBackTrace();
+
+    // dumping a running thread is risky, but could be useful
+    dvmDumpThread(thread, true);
+
+    // stop now and get a core dump
+    //abort();
+}
+
+/*
+ * If the thread is running at below-normal priority, temporarily elevate
+ * it to "normal".
+ *
+ * Returns zero if no changes were made.  Otherwise, returns bit flags
+ * indicating what was changed, storing the previous values in the
+ * provided locations.
+ */
+int dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
+    SchedPolicy* pSavedThreadPolicy)
+{
+    errno = 0;
+    *pSavedThreadPrio = getpriority(PRIO_PROCESS, thread->systemTid);
+    if (errno != 0) {
+        LOGW("Unable to get priority for threadid=%d sysTid=%d",
+            thread->threadId, thread->systemTid);
+        return 0;
+    }
+    if (get_sched_policy(thread->systemTid, pSavedThreadPolicy) != 0) {
+        LOGW("Unable to get policy for threadid=%d sysTid=%d",
+            thread->threadId, thread->systemTid);
+        return 0;
+    }
+
+    int changeFlags = 0;
+
+    /*
+     * Change the priority if we're in the background group.
+     */
+    if (*pSavedThreadPolicy == SP_BACKGROUND) {
+        if (set_sched_policy(thread->systemTid, SP_FOREGROUND) != 0) {
+            LOGW("Couldn't set fg policy on tid %d", thread->systemTid);
+        } else {
+            changeFlags |= kChangedPolicy;
+            LOGD("Temporarily moving tid %d to fg (was %d)",
+                thread->systemTid, *pSavedThreadPolicy);
+        }
+    }
+
+    /*
+     * getpriority() returns the "nice" value, so larger numbers indicate
+     * lower priority, with 0 being normal.
+     */
+    if (*pSavedThreadPrio > 0) {
+        const int kHigher = 0;
+        if (setpriority(PRIO_PROCESS, thread->systemTid, kHigher) != 0) {
+            LOGW("Couldn't raise priority on tid %d to %d",
+                thread->systemTid, kHigher);
+        } else {
+            changeFlags |= kChangedPriority;
+            LOGD("Temporarily raised priority on tid %d (%d -> %d)",
+                thread->systemTid, *pSavedThreadPrio, kHigher);
+        }
+    }
+
+    return changeFlags;
+}
+
+/*
+ * Reset the priority values for the thread in question.
+ */
+void dvmResetThreadPriority(Thread* thread, int changeFlags,
+    int savedThreadPrio, SchedPolicy savedThreadPolicy)
+{
+    if ((changeFlags & kChangedPolicy) != 0) {
+        if (set_sched_policy(thread->systemTid, savedThreadPolicy) != 0) {
+            LOGW("NOTE: couldn't reset tid %d to (%d)",
+                thread->systemTid, savedThreadPolicy);
+        } else {
+            LOGD("Restored policy of %d to %d",
+                thread->systemTid, savedThreadPolicy);
+        }
+    }
+
+    if ((changeFlags & kChangedPriority) != 0) {
+        if (setpriority(PRIO_PROCESS, thread->systemTid, savedThreadPrio) != 0)
+        {
+            LOGW("NOTE: couldn't reset priority on thread %d to %d",
+                thread->systemTid, savedThreadPrio);
+        } else {
+            LOGD("Restored priority on %d to %d",
+                thread->systemTid, savedThreadPrio);
+        }
+    }
+}
+
+/*
+ * Wait for another thread to see the pending suspension and stop running.
+ * It can either suspend itself or go into a non-running state such as
+ * VMWAIT or NATIVE in which it cannot interact with the GC.
+ *
+ * If we're running at a higher priority, sched_yield() may not do anything,
+ * so we need to sleep for "long enough" to guarantee that the other
+ * thread has a chance to finish what it's doing.  Sleeping for too short
+ * a period (e.g. less than the resolution of the sleep clock) might cause
+ * the scheduler to return immediately, so we want to start with a
+ * "reasonable" value and expand.
+ *
+ * This does not return until the other thread has stopped running.
+ * Eventually we time out and the VM aborts.
+ *
+ * This does not try to detect the situation where two threads are
+ * waiting for each other to suspend.  In normal use this is part of a
+ * suspend-all, which implies that the suspend-all lock is held, or as
+ * part of a debugger action in which the JDWP thread is always the one
+ * doing the suspending.  (We may need to re-evaluate this now that
+ * getThreadStackTrace is implemented as suspend-snapshot-resume.)
+ *
+ * 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;
+    int spinSleepTime = FIRST_SLEEP;
+    bool complained = false;
+    int priChangeFlags = 0;
+    int savedThreadPrio = -500;
+    SchedPolicy savedThreadPolicy = SP_FOREGROUND;
+
+    int sleepIter = 0;
+    int retryCount = 0;
+    u8 startWhen = 0;       // init req'd to placate gcc
+    u8 firstStartWhen = 0;
+
+    while (thread->status == THREAD_RUNNING) {
+        if (sleepIter == 0) {           // get current time on first iteration
+            startWhen = dvmGetRelativeTimeUsec();
+            if (firstStartWhen == 0)    // first iteration of first attempt
+                firstStartWhen = startWhen;
+
+            /*
+             * After waiting for a bit, check to see if the target thread is
+             * running at a reduced priority.  If so, bump it up temporarily
+             * to give it more CPU time.
+             */
+            if (retryCount == 2) {
+                assert(thread->systemTid != 0);
+                priChangeFlags = dvmRaiseThreadPriorityIfNeeded(thread,
+                    &savedThreadPrio, &savedThreadPolicy);
+            }
+        }
+
+#if defined (WITH_JIT)
+        /*
+         * If we're still waiting after the first timeout, unchain all
+         * translations iff:
+         *   1) There are new chains formed since the last unchain
+         *   2) The top VM frame of the running thread is running JIT'ed code
+         */
+        if (gDvmJit.pJitEntryTable && retryCount > 0 &&
+            gDvmJit.hasNewChain && thread->inJitCodeCache) {
+            LOGD("JIT unchain all for threadid=%d", thread->threadId);
+            dvmJitUnchainAll();
+        }
+#endif
+
+        /*
+         * Sleep briefly.  The iterative sleep call returns false if we've
+         * exceeded the total time limit for this round of sleeping.
+         */
+        if (!dvmIterativeSleep(sleepIter++, spinSleepTime, startWhen)) {
+            if (spinSleepTime != FIRST_SLEEP) {
+                LOGW("threadid=%d: spin on suspend #%d threadid=%d (pcf=%d)",
+                    self->threadId, retryCount,
+                    thread->threadId, priChangeFlags);
+                if (retryCount > 1) {
+                    /* stack trace logging is slow; skip on first iter */
+                    dumpWedgedThread(thread);
+                }
+                complained = true;
+            }
+
+            // keep going; could be slow due to valgrind
+            sleepIter = 0;
+            spinSleepTime = MORE_SLEEP;
+
+            if (retryCount++ == kMaxRetries) {
+                LOGE("Fatal spin-on-suspend, dumping threads");
+                dvmDumpAllThreads(false);
+
+                /* log this after -- long traces will scroll off log */
+                LOGE("threadid=%d: stuck on threadid=%d, giving up",
+                    self->threadId, thread->threadId);
+
+                /* try to get a debuggerd dump from the spinning thread */
+                dvmNukeThread(thread);
+                /* abort the VM */
+                dvmAbort();
+            }
+        }
+    }
+
+    if (complained) {
+        LOGW("threadid=%d: spin on suspend resolved in %lld msec",
+            self->threadId,
+            (dvmGetRelativeTimeUsec() - firstStartWhen) / 1000);
+        //dvmDumpThread(thread, false);   /* suspended, so dump is safe */
+    }
+    if (priChangeFlags != 0) {
+        dvmResetThreadPriority(thread, priChangeFlags, savedThreadPrio,
+            savedThreadPolicy);
+    }
+}
+
+/*
+ * Suspend all threads except the current one.  This is used by the GC,
+ * the debugger, and by any thread that hits a "suspend all threads"
+ * debugger event (e.g. breakpoint or exception).
+ *
+ * If thread N hits a "suspend all threads" breakpoint, we don't want it
+ * to suspend the JDWP thread.  For the GC, we do, because the debugger can
+ * create objects and even execute arbitrary code.  The "why" argument
+ * allows the caller to say why the suspension is taking place.
+ *
+ * This can be called when a global suspend has already happened, due to
+ * various debugger gymnastics, so keeping an "everybody is suspended" flag
+ * doesn't work.
+ *
+ * DO NOT grab any locks before calling here.  We grab & release the thread
+ * lock and suspend lock here (and we're not using recursive threads), and
+ * we might have to self-suspend if somebody else beats us here.
+ *
+ * We know the current thread is in the thread list, because we attach the
+ * thread before doing anything that could cause VM suspension (like object
+ * allocation).
+ */
+void dvmSuspendAllThreads(SuspendCause why)
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+
+    assert(why != 0);
+
+    /*
+     * Start by grabbing the thread suspend lock.  If we can't get it, most
+     * likely somebody else is in the process of performing a suspend or
+     * resume, so lockThreadSuspend() will cause us to self-suspend.
+     *
+     * We keep the lock until all other threads are suspended.
+     */
+    lockThreadSuspend("susp-all", why);
+
+    LOG_THREAD("threadid=%d: SuspendAll starting", self->threadId);
+
+    /*
+     * This is possible if the current thread was in VMWAIT mode when a
+     * suspend-all happened, and then decided to do its own suspend-all.
+     * This can happen when a couple of threads have simultaneous events
+     * of interest to the debugger.
+     */
+    //assert(self->suspendCount == 0);
+
+    /*
+     * Increment everybody's suspend count (except our own).
+     */
+    dvmLockThreadList(self);
+
+    lockThreadSuspendCount();
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread == self)
+            continue;
+
+        /* debugger events don't suspend JDWP thread */
+        if ((why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) &&
+            thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState))
+            continue;
+
+        dvmAddToSuspendCounts(thread, 1,
+                              (why == SUSPEND_FOR_DEBUG ||
+                              why == SUSPEND_FOR_DEBUG_EVENT)
+                              ? 1 : 0);
+    }
+    unlockThreadSuspendCount();
+
+    /*
+     * Wait for everybody in THREAD_RUNNING state to stop.  Other states
+     * indicate the code is either running natively or sleeping quietly.
+     * Any attempt to transition back to THREAD_RUNNING will cause a check
+     * for suspension, so it should be impossible for anything to execute
+     * interpreted code or modify objects (assuming native code plays nicely).
+     *
+     * It's also okay if the thread transitions to a non-RUNNING state.
+     *
+     * Note we released the threadSuspendCountLock before getting here,
+     * so if another thread is fiddling with its suspend count (perhaps
+     * self-suspending for the debugger) it won't block while we're waiting
+     * in here.
+     */
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread == self)
+            continue;
+
+        /* debugger events don't suspend JDWP thread */
+        if ((why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) &&
+            thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState))
+            continue;
+
+        /* wait for the other thread to see the pending suspend */
+        waitForThreadSuspend(self, thread);
+
+        LOG_THREAD("threadid=%d:   threadid=%d status=%d sc=%d dc=%d",
+            self->threadId, thread->threadId, thread->status,
+            thread->suspendCount, thread->dbgSuspendCount);
+    }
+
+    dvmUnlockThreadList();
+    unlockThreadSuspend();
+
+    LOG_THREAD("threadid=%d: SuspendAll complete", self->threadId);
+}
+
+/*
+ * Resume all threads that are currently suspended.
+ *
+ * The "why" must match with the previous suspend.
+ */
+void dvmResumeAllThreads(SuspendCause why)
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+    int cc;
+
+    lockThreadSuspend("res-all", why);  /* one suspend/resume at a time */
+    LOG_THREAD("threadid=%d: ResumeAll starting", self->threadId);
+
+    /*
+     * Decrement the suspend counts for all threads.  No need for atomic
+     * writes, since nobody should be moving until we decrement the count.
+     * We do need to hold the thread list because of JNI attaches.
+     */
+    dvmLockThreadList(self);
+    lockThreadSuspendCount();
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread == self)
+            continue;
+
+        /* 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) {
+            dvmAddToSuspendCounts(thread, -1,
+                                  (why == SUSPEND_FOR_DEBUG ||
+                                  why == SUSPEND_FOR_DEBUG_EVENT)
+                                  ? -1 : 0);
+        } else {
+            LOG_THREAD("threadid=%d:  suspendCount already zero",
+                thread->threadId);
+        }
+    }
+    unlockThreadSuspendCount();
+    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", 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.
+     */
+    lockThreadSuspendCount();
+    cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
+    assert(cc == 0);
+    unlockThreadSuspendCount();
+
+    LOG_THREAD("threadid=%d: ResumeAll complete", self->threadId);
+}
+
+/*
+ * Undo any debugger suspensions.  This is called when the debugger
+ * disconnects.
+ */
+void dvmUndoDebuggerSuspensions()
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+    int cc;
+
+    lockThreadSuspend("undo", SUSPEND_FOR_DEBUG);
+    LOG_THREAD("threadid=%d: UndoDebuggerSusp starting", self->threadId);
+
+    /*
+     * Decrement the suspend counts for all threads.  No need for atomic
+     * writes, since nobody should be moving until we decrement the count.
+     * We do need to hold the thread list because of JNI attaches.
+     */
+    dvmLockThreadList(self);
+    lockThreadSuspendCount();
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread == self)
+            continue;
+
+        /* debugger events don't suspend JDWP thread */
+        if (thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState)) {
+            assert(thread->dbgSuspendCount == 0);
+            continue;
+        }
+
+        assert(thread->suspendCount >= thread->dbgSuspendCount);
+        dvmAddToSuspendCounts(thread, -thread->dbgSuspendCount,
+                              -thread->dbgSuspendCount);
+    }
+    unlockThreadSuspendCount();
+    dvmUnlockThreadList();
+
+    /*
+     * Broadcast a notification to all suspended threads, some or all of
+     * which may choose to wake up.  No need to wait for them.
+     */
+    lockThreadSuspendCount();
+    cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
+    assert(cc == 0);
+    unlockThreadSuspendCount();
+
+    unlockThreadSuspend();
+
+    LOG_THREAD("threadid=%d: UndoDebuggerSusp complete", self->threadId);
+}
+
+/*
+ * Determine if a thread is suspended.
+ *
+ * As with all operations on foreign threads, the caller should hold
+ * the thread list lock before calling.
+ *
+ * If the thread is suspending or waking, these fields could be changing
+ * out from under us (or the thread could change state right after we
+ * examine it), making this generally unreliable.  This is chiefly
+ * intended for use by the debugger.
+ */
+bool dvmIsSuspended(const Thread* thread)
+{
+    /*
+     * The thread could be:
+     *  (1) Running happily.  status is RUNNING, suspendCount is zero.
+     *      Return "false".
+     *  (2) Pending suspend.  status is RUNNING, suspendCount is nonzero.
+     *      Return "false".
+     *  (3) Suspended.  suspendCount is nonzero, and status is !RUNNING.
+     *      Return "true".
+     *  (4) Waking up.  suspendCount is zero, status is SUSPENDED
+     *      Return "false" (since it could change out from under us, unless
+     *      we hold suspendCountLock).
+     */
+
+    return (thread->suspendCount != 0 &&
+            thread->status != THREAD_RUNNING);
+}
+
+/*
+ * Wait until another thread self-suspends.  This is specifically for
+ * synchronization between the JDWP thread and a thread that has decided
+ * to suspend itself after sending an event to the debugger.
+ *
+ * Threads that encounter "suspend all" events work as well -- the thread
+ * in question suspends everybody else and then itself.
+ *
+ * We can't hold a thread lock here or in the caller, because we could
+ * get here just before the to-be-waited-for-thread issues a "suspend all".
+ * There's an opportunity for badness if the thread we're waiting for exits
+ * and gets cleaned up, but since the thread in question is processing a
+ * debugger event, that's not really a possibility.  (To avoid deadlock,
+ * it's important that we not be in THREAD_RUNNING while we wait.)
+ */
+void dvmWaitForSuspend(Thread* thread)
+{
+    Thread* self = dvmThreadSelf();
+
+    LOG_THREAD("threadid=%d: waiting for threadid=%d to sleep",
+        self->threadId, thread->threadId);
+
+    assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState));
+    assert(thread != self);
+    assert(self->status != THREAD_RUNNING);
+
+    waitForThreadSuspend(self, thread);
+
+    LOG_THREAD("threadid=%d: threadid=%d is now asleep",
+        self->threadId, thread->threadId);
+}
+
+/*
+ * Check to see if we need to suspend ourselves.  If so, go to sleep on
+ * a condition variable.
+ *
+ * Returns "true" if we suspended ourselves.
+ */
+static bool fullSuspendCheck(Thread* self)
+{
+    assert(self != NULL);
+    assert(self->suspendCount >= 0);
+
+    /*
+     * Grab gDvm.threadSuspendCountLock.  This gives us exclusive write
+     * access to self->suspendCount.
+     */
+    lockThreadSuspendCount();   /* grab gDvm.threadSuspendCountLock */
+
+    bool needSuspend = (self->suspendCount != 0);
+    if (needSuspend) {
+        LOG_THREAD("threadid=%d: self-suspending", self->threadId);
+        ThreadStatus oldStatus = self->status;      /* should be RUNNING */
+        self->status = THREAD_SUSPENDED;
+
+        while (self->suspendCount != 0) {
+            /*
+             * Wait for wakeup signal, releasing lock.  The act of releasing
+             * and re-acquiring the lock provides the memory barriers we
+             * need for correct behavior on SMP.
+             */
+            dvmWaitCond(&gDvm.threadSuspendCountCond,
+                    &gDvm.threadSuspendCountLock);
+        }
+        assert(self->suspendCount == 0 && self->dbgSuspendCount == 0);
+        self->status = oldStatus;
+        LOG_THREAD("threadid=%d: self-reviving, status=%d",
+            self->threadId, self->status);
+    }
+
+    unlockThreadSuspendCount();
+
+    return needSuspend;
+}
+
+/*
+ * Check to see if a suspend is pending.  If so, suspend the current
+ * thread, and return "true" after we have been resumed.
+ */
+bool dvmCheckSuspendPending(Thread* self)
+{
+    assert(self != NULL);
+    if (self->suspendCount == 0) {
+        return false;
+    } else {
+        return fullSuspendCheck(self);
+    }
+}
+
+/*
+ * Update our status.
+ *
+ * The "self" argument, which may be NULL, is accepted as an optimization.
+ *
+ * Returns the old status.
+ */
+ThreadStatus dvmChangeStatus(Thread* self, ThreadStatus newStatus)
+{
+    ThreadStatus oldStatus;
+
+    if (self == NULL)
+        self = dvmThreadSelf();
+
+    LOGVV("threadid=%d: (status %d -> %d)",
+        self->threadId, self->status, newStatus);
+
+    oldStatus = self->status;
+    if (oldStatus == newStatus)
+        return oldStatus;
+
+    if (newStatus == THREAD_RUNNING) {
+        /*
+         * Change our status to THREAD_RUNNING.  The transition requires
+         * that we check for pending suspension, because the VM considers
+         * us to be "asleep" in all other states, and another thread could
+         * be performing a GC now.
+         *
+         * The order of operations is very significant here.  One way to
+         * do this wrong is:
+         *
+         *   GCing thread                   Our thread (in NATIVE)
+         *   ------------                   ----------------------
+         *                                  check suspend count (== 0)
+         *   dvmSuspendAllThreads()
+         *   grab suspend-count lock
+         *   increment all suspend counts
+         *   release suspend-count lock
+         *   check thread state (== NATIVE)
+         *   all are suspended, begin GC
+         *                                  set state to RUNNING
+         *                                  (continue executing)
+         *
+         * We can correct this by grabbing the suspend-count lock and
+         * performing both of our operations (check suspend count, set
+         * state) while holding it, now we need to grab a mutex on every
+         * transition to RUNNING.
+         *
+         * What we do instead is change the order of operations so that
+         * the transition to RUNNING happens first.  If we then detect
+         * that the suspend count is nonzero, we switch to SUSPENDED.
+         *
+         * Appropriate compiler and memory barriers are required to ensure
+         * that the operations are observed in the expected order.
+         *
+         * This does create a small window of opportunity where a GC in
+         * progress could observe what appears to be a running thread (if
+         * it happens to look between when we set to RUNNING and when we
+         * switch to SUSPENDED).  At worst this only affects assertions
+         * and thread logging.  (We could work around it with some sort
+         * of intermediate "pre-running" state that is generally treated
+         * as equivalent to running, but that doesn't seem worthwhile.)
+         *
+         * We can also solve this by combining the "status" and "suspend
+         * count" fields into a single 32-bit value.  This trades the
+         * store/load barrier on transition to RUNNING for an atomic RMW
+         * op on all transitions and all suspend count updates (also, all
+         * accesses to status or the thread count require bit-fiddling).
+         * It also eliminates the brief transition through RUNNING when
+         * the thread is supposed to be suspended.  This is possibly faster
+         * on SMP and slightly more correct, but less convenient.
+         */
+        volatile void* raw = reinterpret_cast<volatile void*>(&self->status);
+        volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw);
+        android_atomic_acquire_store(newStatus, addr);
+        if (self->suspendCount != 0) {
+            fullSuspendCheck(self);
+        }
+    } else {
+        /*
+         * Not changing to THREAD_RUNNING.  No additional work required.
+         *
+         * We use a releasing store to ensure that, if we were RUNNING,
+         * any updates we previously made to objects on the managed heap
+         * will be observed before the state change.
+         */
+        assert(newStatus != THREAD_SUSPENDED);
+        volatile void* raw = reinterpret_cast<volatile void*>(&self->status);
+        volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw);
+        android_atomic_release_store(newStatus, addr);
+    }
+
+    return oldStatus;
+}
+
+/*
+ * Get a statically defined thread group from a field in the ThreadGroup
+ * Class object.  Expected arguments are "mMain" and "mSystem".
+ */
+static Object* getStaticThreadGroup(const char* fieldName)
+{
+    StaticField* groupField;
+    Object* groupObj;
+
+    groupField = dvmFindStaticField(gDvm.classJavaLangThreadGroup,
+        fieldName, "Ljava/lang/ThreadGroup;");
+    if (groupField == NULL) {
+        LOGE("java.lang.ThreadGroup does not have an '%s' field", fieldName);
+        dvmThrowInternalError("bad definition for ThreadGroup");
+        return NULL;
+    }
+    groupObj = dvmGetStaticFieldObject(groupField);
+    if (groupObj == NULL) {
+        LOGE("java.lang.ThreadGroup.%s not initialized", fieldName);
+        dvmThrowInternalError(NULL);
+        return NULL;
+    }
+
+    return groupObj;
+}
+Object* dvmGetSystemThreadGroup()
+{
+    return getStaticThreadGroup("mSystem");
+}
+Object* dvmGetMainThreadGroup()
+{
+    return getStaticThreadGroup("mMain");
+}
+
+/*
+ * Given a VMThread object, return the associated Thread*.
+ *
+ * NOTE: if the thread detaches, the struct Thread will disappear, and
+ * we will be touching invalid data.  For safety, lock the thread list
+ * before calling this.
+ */
+Thread* dvmGetThreadFromThreadObject(Object* vmThreadObj)
+{
+    int vmData;
+
+    vmData = dvmGetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData);
+
+    if (false) {
+        Thread* thread = gDvm.threadList;
+        while (thread != NULL) {
+            if ((Thread*)vmData == thread)
+                break;
+
+            thread = thread->next;
+        }
+
+        if (thread == NULL) {
+            LOGW("WARNING: vmThreadObj=%p has thread=%p, not in thread list",
+                vmThreadObj, (Thread*)vmData);
+            vmData = 0;
+        }
+    }
+
+    return (Thread*) vmData;
+}
+
+/*
+ * Given a pthread handle, return the associated Thread*.
+ * Caller must hold the thread list lock.
+ *
+ * Returns NULL if the thread was not found.
+ */
+Thread* dvmGetThreadByHandle(pthread_t handle)
+{
+    Thread* thread;
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread->handle == handle)
+            break;
+    }
+    return thread;
+}
+
+/*
+ * Given a threadId, return the associated Thread*.
+ * Caller must hold the thread list lock.
+ *
+ * Returns NULL if the thread was not found.
+ */
+Thread* dvmGetThreadByThreadId(u4 threadId)
+{
+    Thread* thread;
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread->threadId == threadId)
+            break;
+    }
+    return thread;
+}
+
+void dvmChangeThreadPriority(Thread* thread, int newPriority)
+{
+    os_changeThreadPriority(thread, newPriority);
+}
+
+/*
+ * Return true if the thread is on gDvm.threadList.
+ * Caller should not hold gDvm.threadListLock.
+ */
+bool dvmIsOnThreadList(const Thread* thread)
+{
+    bool ret = false;
+
+    dvmLockThreadList(NULL);
+    if (thread == gDvm.threadList) {
+        ret = true;
+    } else {
+        ret = thread->prev != NULL || thread->next != NULL;
+    }
+    dvmUnlockThreadList();
+
+    return ret;
+}
+
+/*
+ * Dump a thread to the log file -- just calls dvmDumpThreadEx() with an
+ * output target.
+ */
+void dvmDumpThread(Thread* thread, bool isRunning)
+{
+    DebugOutputTarget target;
+
+    dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG);
+    dvmDumpThreadEx(&target, thread, isRunning);
+}
+
+/*
+ * Try to get the scheduler group.
+ *
+ * The data from /proc/<pid>/cgroup looks (something) like:
+ *  2:cpu:/bg_non_interactive
+ *  1:cpuacct:/
+ *
+ * We return the part on the "cpu" line after the '/', which will be an
+ * empty string for the default cgroup.  If the string is longer than
+ * "bufLen", the string will be truncated.
+ *
+ * On error, -1 is returned, and an error description will be stored in
+ * the buffer.
+ */
+static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
+{
+#ifdef HAVE_ANDROID_OS
+    char pathBuf[32];
+    char lineBuf[256];
+    FILE *fp;
+
+    snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
+    if ((fp = fopen(pathBuf, "r")) == NULL) {
+        snprintf(buf, bufLen, "[fopen-error:%d]", errno);
+        return -1;
+    }
+
+    while (fgets(lineBuf, sizeof(lineBuf) -1, fp) != NULL) {
+        char* subsys;
+        char* grp;
+        size_t len;
+
+        /* Junk the first field */
+        subsys = strchr(lineBuf, ':');
+        if (subsys == NULL) {
+            goto out_bad_data;
+        }
+
+        if (strncmp(subsys, ":cpu:", 5) != 0) {
+            /* Not the subsys we're looking for */
+            continue;
+        }
+
+        grp = strchr(subsys, '/');
+        if (grp == NULL) {
+            goto out_bad_data;
+        }
+        grp++; /* Drop the leading '/' */
+
+        len = strlen(grp);
+        grp[len-1] = '\0'; /* Drop the trailing '\n' */
+
+        if (bufLen <= len) {
+            len = bufLen - 1;
+        }
+        strncpy(buf, grp, len);
+        buf[len] = '\0';
+        fclose(fp);
+        return 0;
+    }
+
+    snprintf(buf, bufLen, "[no-cpu-subsys]");
+    fclose(fp);
+    return -1;
+
+out_bad_data:
+    LOGE("Bad cgroup data {%s}", lineBuf);
+    snprintf(buf, bufLen, "[data-parse-failed]");
+    fclose(fp);
+    return -1;
+
+#else
+    snprintf(buf, bufLen, "[n/a]");
+    return -1;
+#endif
+}
+
+/*
+ * Convert ThreadStatus to a string.
+ */
+const char* dvmGetThreadStatusStr(ThreadStatus status)
+{
+    switch (status) {
+    case THREAD_ZOMBIE:         return "ZOMBIE";
+    case THREAD_RUNNING:        return "RUNNABLE";
+    case THREAD_TIMED_WAIT:     return "TIMED_WAIT";
+    case THREAD_MONITOR:        return "MONITOR";
+    case THREAD_WAIT:           return "WAIT";
+    case THREAD_INITIALIZING:   return "INITIALIZING";
+    case THREAD_STARTING:       return "STARTING";
+    case THREAD_NATIVE:         return "NATIVE";
+    case THREAD_VMWAIT:         return "VMWAIT";
+    case THREAD_SUSPENDED:      return "SUSPENDED";
+    default:                    return "UNKNOWN";
+    }
+}
+
+/*
+ * Print information about the specified thread.
+ *
+ * Works best when the thread in question is "self" or has been suspended.
+ * When dumping a separate thread that's still running, set "isRunning" to
+ * use a more cautious thread dump function.
+ */
+void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
+    bool isRunning)
+{
+    Object* threadObj;
+    Object* groupObj;
+    StringObject* nameStr;
+    char* threadName = NULL;
+    char* groupName = NULL;
+    char schedulerGroupBuf[32];
+    bool isDaemon;
+    int priority;               // java.lang.Thread priority
+    int policy;                 // pthread policy
+    struct sched_param sp;      // pthread scheduling parameters
+    char schedstatBuf[64];      // contents of /proc/[pid]/task/[tid]/schedstat
+
+    /*
+     * Get the java.lang.Thread object.  This function gets called from
+     * some weird debug contexts, so it's possible that there's a GC in
+     * progress on some other thread.  To decrease the chances of the
+     * thread object being moved out from under us, we add the reference
+     * to the tracked allocation list, which pins it in place.
+     *
+     * If threadObj is NULL, the thread is still in the process of being
+     * attached to the VM, and there's really nothing interesting to
+     * say about it yet.
+     */
+    threadObj = thread->threadObj;
+    if (threadObj == NULL) {
+        LOGI("Can't dump thread %d: threadObj not set", thread->threadId);
+        return;
+    }
+    dvmAddTrackedAlloc(threadObj, NULL);
+
+    nameStr = (StringObject*) dvmGetFieldObject(threadObj,
+                gDvm.offJavaLangThread_name);
+    threadName = dvmCreateCstrFromString(nameStr);
+
+    priority = dvmGetFieldInt(threadObj, gDvm.offJavaLangThread_priority);
+    isDaemon = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
+
+    if (pthread_getschedparam(pthread_self(), &policy, &sp) != 0) {
+        LOGW("Warning: pthread_getschedparam failed");
+        policy = -1;
+        sp.sched_priority = -1;
+    }
+    if (getSchedulerGroup(thread->systemTid, schedulerGroupBuf,
+                sizeof(schedulerGroupBuf)) == 0 &&
+            schedulerGroupBuf[0] == '\0') {
+        strcpy(schedulerGroupBuf, "default");
+    }
+
+    /* a null value for group is not expected, but deal with it anyway */
+    groupObj = (Object*) dvmGetFieldObject(threadObj,
+                gDvm.offJavaLangThread_group);
+    if (groupObj != NULL) {
+        nameStr = (StringObject*)
+            dvmGetFieldObject(groupObj, gDvm.offJavaLangThreadGroup_name);
+        groupName = dvmCreateCstrFromString(nameStr);
+    }
+    if (groupName == NULL)
+        groupName = strdup("(null; initializing?)");
+
+    dvmPrintDebugMessage(target,
+        "\"%s\"%s prio=%d tid=%d %s%s\n",
+        threadName, isDaemon ? " daemon" : "",
+        priority, thread->threadId, dvmGetThreadStatusStr(thread->status),
+#if defined(WITH_JIT)
+        thread->inJitCodeCache ? " JIT" : ""
+#else
+        ""
+#endif
+        );
+    dvmPrintDebugMessage(target,
+        "  | group=\"%s\" sCount=%d dsCount=%d obj=%p self=%p\n",
+        groupName, thread->suspendCount, thread->dbgSuspendCount,
+        thread->threadObj, thread);
+    dvmPrintDebugMessage(target,
+        "  | sysTid=%d nice=%d sched=%d/%d cgrp=%s handle=%d\n",
+        thread->systemTid, getpriority(PRIO_PROCESS, thread->systemTid),
+        policy, sp.sched_priority, schedulerGroupBuf, (int)thread->handle);
+
+    /* get some bits from /proc/self/stat */
+    ProcStatData procStatData;
+    if (!dvmGetThreadStats(&procStatData, thread->systemTid)) {
+        /* failed, use zeroed values */
+        memset(&procStatData, 0, sizeof(procStatData));
+    }
+
+    /* grab the scheduler stats for this thread */
+    snprintf(schedstatBuf, sizeof(schedstatBuf), "/proc/self/task/%d/schedstat",
+             thread->systemTid);
+    int schedstatFd = open(schedstatBuf, O_RDONLY);
+    strcpy(schedstatBuf, "0 0 0");          /* show this if open/read fails */
+    if (schedstatFd >= 0) {
+        ssize_t bytes;
+        bytes = read(schedstatFd, schedstatBuf, sizeof(schedstatBuf) - 1);
+        close(schedstatFd);
+        if (bytes >= 1) {
+            schedstatBuf[bytes-1] = '\0';   /* remove trailing newline */
+        }
+    }
+
+    /* show what we got */
+    dvmPrintDebugMessage(target,
+        "  | schedstat=( %s ) utm=%lu stm=%lu core=%d\n",
+        schedstatBuf, procStatData.utime, procStatData.stime,
+        procStatData.processor);
+
+    if (isRunning)
+        dvmDumpRunningThreadStack(target, thread);
+    else
+        dvmDumpThreadStack(target, thread);
+
+    dvmReleaseTrackedAlloc(threadObj, NULL);
+    free(threadName);
+    free(groupName);
+}
+
+std::string dvmGetThreadName(Thread* thread) {
+    if (thread->threadObj == NULL) {
+        LOGW("threadObj is NULL, name not available");
+        return "-unknown-";
+    }
+
+    StringObject* nameObj = (StringObject*)
+        dvmGetFieldObject(thread->threadObj, gDvm.offJavaLangThread_name);
+    return dvmCreateCstrFromString(nameObj);
+}
+
+/*
+ * Dump all threads to the log file -- just calls dvmDumpAllThreadsEx() with
+ * an output target.
+ */
+void dvmDumpAllThreads(bool grabLock)
+{
+    DebugOutputTarget target;
+
+    dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG);
+    dvmDumpAllThreadsEx(&target, grabLock);
+}
+
+/*
+ * Print information about all known threads.  Assumes they have been
+ * suspended (or are in a non-interpreting state, e.g. WAIT or NATIVE).
+ *
+ * If "grabLock" is true, we grab the thread lock list.  This is important
+ * to do unless the caller already holds the lock.
+ */
+void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock)
+{
+    Thread* thread;
+
+    dvmPrintDebugMessage(target, "DALVIK THREADS:\n");
+
+#ifdef HAVE_ANDROID_OS
+    dvmPrintDebugMessage(target,
+        "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x)\n",
+        gDvm.threadListLock.value,
+        gDvm._threadSuspendLock.value,
+        gDvm.threadSuspendCountLock.value,
+        gDvm.gcHeapLock.value);
+#endif
+
+    if (grabLock)
+        dvmLockThreadList(dvmThreadSelf());
+
+    thread = gDvm.threadList;
+    while (thread != NULL) {
+        dvmDumpThreadEx(target, thread, false);
+
+        /* verify link */
+        assert(thread->next == NULL || thread->next->prev == thread);
+
+        thread = thread->next;
+    }
+
+    if (grabLock)
+        dvmUnlockThreadList();
+}
+
+/*
+ * Nuke the target thread from orbit.
+ *
+ * The idea is to send a "crash" signal to the target thread so that
+ * debuggerd will take notice and dump an appropriate stack trace.
+ * Because of the way debuggerd works, we have to throw the same signal
+ * at it twice.
+ *
+ * This does not necessarily cause the entire process to stop, but once a
+ * thread has been nuked the rest of the system is likely to be unstable.
+ * This returns so that some limited set of additional operations may be
+ * performed, but it's advisable (and expected) to call dvmAbort soon.
+ * (This is NOT a way to simply cancel a thread.)
+ */
+void dvmNukeThread(Thread* thread)
+{
+    int killResult;
+
+    /* suppress the heapworker watchdog to assist anyone using a debugger */
+    gDvm.nativeDebuggerActive = true;
+
+    /*
+     * Send the signals, separated by a brief interval to allow debuggerd
+     * to work its magic.  An uncommon signal like SIGFPE or SIGSTKFLT
+     * can be used instead of SIGSEGV to avoid making it look like the
+     * code actually crashed at the current point of execution.
+     *
+     * (Observed behavior: with SIGFPE, debuggerd will dump the target
+     * thread and then the thread that calls dvmAbort.  With SIGSEGV,
+     * you don't get the second stack trace; possibly something in the
+     * kernel decides that a signal has already been sent and it's time
+     * to just kill the process.  The position in the current thread is
+     * generally known, so the second dump is not useful.)
+     *
+     * The target thread can continue to execute between the two signals.
+     * (The first just causes debuggerd to attach to it.)
+     */
+    LOGD("threadid=%d: sending two SIGSTKFLTs to threadid=%d (tid=%d) to"
+         " cause debuggerd dump",
+        dvmThreadSelf()->threadId, thread->threadId, thread->systemTid);
+    killResult = pthread_kill(thread->handle, SIGSTKFLT);
+    if (killResult != 0) {
+        LOGD("NOTE: pthread_kill #1 failed: %s", strerror(killResult));
+    }
+    usleep(2 * 1000 * 1000);    // TODO: timed-wait until debuggerd attaches
+    killResult = pthread_kill(thread->handle, SIGSTKFLT);
+    if (killResult != 0) {
+        LOGD("NOTE: pthread_kill #2 failed: %s", strerror(killResult));
+    }
+    LOGD("Sent, pausing to let debuggerd run");
+    usleep(8 * 1000 * 1000);    // TODO: timed-wait until debuggerd finishes
+
+    /* ignore SIGSEGV so the eventual dmvAbort() doesn't notify debuggerd */
+    signal(SIGSEGV, SIG_IGN);
+    LOGD("Continuing");
+}
diff --git a/vm/Thread.h b/vm/Thread.h
new file mode 100644
index 0000000..7f14ce5
--- /dev/null
+++ b/vm/Thread.h
@@ -0,0 +1,602 @@
+/*
+ * 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.
+ */
+
+/*
+ * VM thread support.
+ */
+#ifndef DALVIK_THREAD_H_
+#define DALVIK_THREAD_H_
+
+#include "jni.h"
+#include "interp/InterpState.h"
+
+#include <errno.h>
+#include <cutils/sched_policy.h>
+
+#if defined(CHECK_MUTEX) && !defined(__USE_UNIX98)
+/* glibc lacks this unless you #define __USE_UNIX98 */
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
+enum { PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP };
+#endif
+
+/*
+ * Current status; these map to JDWP constants, so don't rearrange them.
+ * (If you do alter this, update the strings in dvmDumpThread and the
+ * conversion table in VMThread.java.)
+ *
+ * Note that "suspended" is orthogonal to these values (so says JDWP).
+ */
+enum ThreadStatus {
+    THREAD_UNDEFINED    = -1,       /* makes enum compatible with int32_t */
+
+    /* these match up with JDWP values */
+    THREAD_ZOMBIE       = 0,        /* TERMINATED */
+    THREAD_RUNNING      = 1,        /* RUNNABLE or running now */
+    THREAD_TIMED_WAIT   = 2,        /* TIMED_WAITING in Object.wait() */
+    THREAD_MONITOR      = 3,        /* BLOCKED on a monitor */
+    THREAD_WAIT         = 4,        /* WAITING in Object.wait() */
+    /* non-JDWP states */
+    THREAD_INITIALIZING = 5,        /* allocated, not yet running */
+    THREAD_STARTING     = 6,        /* started, not yet on thread list */
+    THREAD_NATIVE       = 7,        /* off in a JNI native method */
+    THREAD_VMWAIT       = 8,        /* waiting on a VM resource */
+    THREAD_SUSPENDED    = 9,        /* suspended, usually by GC or debugger */
+};
+
+/* thread priorities, from java.lang.Thread */
+enum {
+    THREAD_MIN_PRIORITY     = 1,
+    THREAD_NORM_PRIORITY    = 5,
+    THREAD_MAX_PRIORITY     = 10,
+};
+
+
+/* initialization */
+bool dvmThreadStartup(void);
+void dvmThreadShutdown(void);
+void dvmSlayDaemons(void);
+
+
+#define kJniLocalRefMin         64
+#define kJniLocalRefMax         512     /* arbitrary; should be plenty */
+#define kInternalRefDefault     32      /* equally arbitrary */
+#define kInternalRefMax         4096    /* mainly a sanity check */
+
+#define kMinStackSize       (512 + STACK_OVERFLOW_RESERVE)
+#define kDefaultStackSize   (16*1024)   /* four 4K pages */
+#define kMaxStackSize       (256*1024 + STACK_OVERFLOW_RESERVE)
+
+/*
+ * Interpreter control struction.  Packed into a long long to enable
+ * atomic updates.
+ */
+union InterpBreak {
+    volatile int64_t   all;
+    struct {
+        uint16_t   subMode;
+        uint8_t    breakFlags;
+        int8_t     unused;   /* for future expansion */
+#ifndef DVM_NO_ASM_INTERP
+        void* curHandlerTable;
+#else
+        void* unused;
+#endif
+    } ctl;
+};
+
+/*
+ * Our per-thread data.
+ *
+ * These are allocated on the system heap.
+ */
+struct Thread {
+    /*
+     * Interpreter state which must be preserved across nested
+     * interpreter invocations (via JNI callbacks).  Must be the first
+     * element in Thread.
+     */
+    InterpSaveState interpSave;
+
+    /* small unique integer; useful for "thin" locks and debug messages */
+    u4          threadId;
+
+    /*
+     * Begin interpreter state which does not need to be preserved, but should
+     * be located towards the beginning of the Thread structure for
+     * efficiency.
+     */
+
+    /*
+     * interpBreak contains info about the interpreter mode, as well as
+     * a count of the number of times the thread has been suspended.  When
+     * the count drops to zero, the thread resumes.
+     */
+    InterpBreak interpBreak;
+
+    /*
+     * "dbgSuspendCount" is the portion of the suspend count that the
+     * debugger is responsible for.  This has to be tracked separately so
+     * that we can recover correctly if the debugger abruptly disconnects
+     * (suspendCount -= dbgSuspendCount).  The debugger should not be able
+     * to resume GC-suspended threads, because we ignore the debugger while
+     * a GC is in progress.
+     *
+     * Both of these are guarded by gDvm.threadSuspendCountLock.
+     *
+     * Note the non-debug component will rarely be other than 1 or 0 -- (not
+     * sure it's even possible with the way mutexes are currently used.)
+     */
+
+    int suspendCount;
+    int dbgSuspendCount;
+
+    u1*         cardTable;
+
+    /* current limit of stack; flexes for StackOverflowError */
+    const u1*   interpStackEnd;
+
+    /* FP of bottom-most (currently executing) stack frame on interp stack */
+    void*       XcurFrame;
+    /* current exception, or NULL if nothing pending */
+    Object*     exception;
+
+    bool        debugIsMethodEntry;
+    /* interpreter stack size; our stacks are fixed-length */
+    int         interpStackSize;
+    bool        stackOverflowed;
+
+    /* thread handle, as reported by pthread_self() */
+    pthread_t   handle;
+
+    /* Assembly interpreter handler tables */
+#ifndef DVM_NO_ASM_INTERP
+    void*       mainHandlerTable;   // Table of actual instruction handler
+    void*       altHandlerTable;    // Table of breakout handlers
+#else
+    void*       unused0;            // Consume space to keep offsets
+    void*       unused1;            //   the same between builds with
+#endif
+
+    /*
+     * singleStepCount is a countdown timer used with the breakFlag
+     * kInterpSingleStep.  If kInterpSingleStep is set in breakFlags,
+     * singleStepCount will decremented each instruction execution.
+     * Once it reaches zero, the kInterpSingleStep flag in breakFlags
+     * will be cleared.  This can be used to temporarily prevent
+     * execution from re-entering JIT'd code or force inter-instruction
+     * checks by delaying the reset of curHandlerTable to mainHandlerTable.
+     */
+    int         singleStepCount;
+
+#ifdef WITH_JIT
+    struct JitToInterpEntries jitToInterpEntries;
+    /*
+     * Whether the current top VM frame is in the interpreter or JIT cache:
+     *   NULL    : in the interpreter
+     *   non-NULL: entry address of the JIT'ed code (the actual value doesn't
+     *             matter)
+     */
+    void*             inJitCodeCache;
+    unsigned char*    pJitProfTable;
+    int               jitThreshold;
+    const void*       jitResumeNPC;     // Translation return point
+    const u4*         jitResumeNSP;     // Native SP at return point
+    const u2*         jitResumeDPC;     // Dalvik inst following single-step
+    JitState    jitState;
+    int         icRechainCount;
+    const void* pProfileCountdown;
+    const ClassObject* callsiteClass;
+    const Method*     methodToCall;
+#endif
+
+    /* JNI local reference tracking */
+    IndirectRefTable jniLocalRefTable;
+
+#if defined(WITH_JIT)
+#if defined(WITH_SELF_VERIFICATION)
+    /* Buffer for register state during self verification */
+    struct ShadowSpace* shadowSpace;
+#endif
+    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
+    const u2*   lastPC;         // Stage the PC for the threaded interpreter
+    const Method*  traceMethod; // Starting method of current trace
+    intptr_t    threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
+    JitTraceRun trace[MAX_JIT_RUN_LEN];
+#endif
+
+    /*
+     * Thread's current status.  Can only be changed by the thread itself
+     * (i.e. don't mess with this from other threads).
+     */
+    volatile ThreadStatus status;
+
+    /* thread ID, only useful under Linux */
+    pid_t       systemTid;
+
+    /* start (high addr) of interp stack (subtract size to get malloc addr) */
+    u1*         interpStackStart;
+
+    /* the java/lang/Thread that we are associated with */
+    Object*     threadObj;
+
+    /* the JNIEnv pointer associated with this thread */
+    JNIEnv*     jniEnv;
+
+    /* internal reference tracking */
+    ReferenceTable  internalLocalRefTable;
+
+
+    /* JNI native monitor reference tracking (initialized on first use) */
+    ReferenceTable  jniMonitorRefTable;
+
+    /* hack to make JNI_OnLoad work right */
+    Object*     classLoaderOverride;
+
+    /* mutex to guard the interrupted and the waitMonitor members */
+    pthread_mutex_t    waitMutex;
+
+    /* pointer to the monitor lock we're currently waiting on */
+    /* guarded by waitMutex */
+    /* TODO: consider changing this to Object* for better JDWP interaction */
+    Monitor*    waitMonitor;
+
+    /* thread "interrupted" status; stays raised until queried or thrown */
+    /* guarded by waitMutex */
+    bool        interrupted;
+
+    /* links to the next thread in the wait set this thread is part of */
+    struct Thread*     waitNext;
+
+    /* object to sleep on while we are waiting for a monitor */
+    pthread_cond_t     waitCond;
+
+    /*
+     * Set to true when the thread is in the process of throwing an
+     * OutOfMemoryError.
+     */
+    bool        throwingOOME;
+
+    /* links to rest of thread list; grab global lock before traversing */
+    struct Thread* prev;
+    struct Thread* next;
+
+    /* used by threadExitCheck when a thread exits without detaching */
+    int         threadExitCheckCount;
+
+    /* JDWP invoke-during-breakpoint support */
+    DebugInvokeReq  invokeReq;
+
+    /* base time for per-thread CPU timing (used by method profiling) */
+    bool        cpuClockBaseSet;
+    u8          cpuClockBase;
+
+    /* memory allocation profiling state */
+    AllocProfState allocProf;
+
+#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
+
+    /* Safepoint callback state */
+    pthread_mutex_t   callbackMutex;
+    SafePointCallback callback;
+    void*             callbackArg;
+};
+
+/* start point for an internal thread; mimics pthread args */
+typedef void* (*InternalThreadStart)(void* arg);
+
+/* args for internal thread creation */
+struct InternalStartArgs {
+    /* inputs */
+    InternalThreadStart func;
+    void*       funcArg;
+    char*       name;
+    Object*     group;
+    bool        isDaemon;
+    /* result */
+    volatile Thread** pThread;
+    volatile int*     pCreateStatus;
+};
+
+/* finish init */
+bool dvmPrepMainForJni(JNIEnv* pEnv);
+bool dvmPrepMainThread(void);
+
+/* utility function to get the tid */
+pid_t dvmGetSysThreadId(void);
+
+/*
+ * Get our Thread* from TLS.
+ *
+ * Returns NULL if this isn't a thread that the VM is aware of.
+ */
+Thread* dvmThreadSelf(void);
+
+/* grab the thread list global lock */
+void dvmLockThreadList(Thread* self);
+/* try to grab the thread list global lock */
+bool dvmTryLockThreadList(void);
+/* release the thread list global lock */
+void dvmUnlockThreadList(void);
+
+/*
+ * Thread suspend/resume, used by the GC and debugger.
+ */
+enum SuspendCause {
+    SUSPEND_NOT = 0,
+    SUSPEND_FOR_GC,
+    SUSPEND_FOR_DEBUG,
+    SUSPEND_FOR_DEBUG_EVENT,
+    SUSPEND_FOR_STACK_DUMP,
+    SUSPEND_FOR_DEX_OPT,
+    SUSPEND_FOR_VERIFY,
+    SUSPEND_FOR_HPROF,
+#if defined(WITH_JIT)
+    SUSPEND_FOR_TBL_RESIZE,  // jit-table resize
+    SUSPEND_FOR_IC_PATCH,    // polymorphic callsite inline-cache patch
+    SUSPEND_FOR_CC_RESET,    // code-cache reset
+    SUSPEND_FOR_REFRESH,     // Reload data cached in interpState
+#endif
+};
+void dvmSuspendThread(Thread* thread);
+void dvmSuspendSelf(bool jdwpActivity);
+void dvmResumeThread(Thread* thread);
+void dvmSuspendAllThreads(SuspendCause why);
+void dvmResumeAllThreads(SuspendCause why);
+void dvmUndoDebuggerSuspensions(void);
+
+/*
+ * Check suspend state.  Grab threadListLock before calling.
+ */
+bool dvmIsSuspended(const Thread* thread);
+
+/*
+ * Wait until a thread has suspended.  (Used by debugger support.)
+ */
+void dvmWaitForSuspend(Thread* thread);
+
+/*
+ * Check to see if we should be suspended now.  If so, suspend ourselves
+ * by sleeping on a condition variable.
+ */
+extern "C" bool dvmCheckSuspendPending(Thread* self);
+
+/*
+ * Fast test for use in the interpreter.  Returns "true" if our suspend
+ * count is nonzero.
+ */
+INLINE bool dvmCheckSuspendQuick(Thread* self) {
+    return (self->interpBreak.ctl.subMode & kSubModeSuspendPending);
+}
+
+/*
+ * Used when changing thread state.  Threads may only change their own.
+ * The "self" argument, which may be NULL, is accepted as an optimization.
+ *
+ * If you're calling this before waiting on a resource (e.g. THREAD_WAIT
+ * or THREAD_MONITOR), do so in the same function as the wait -- this records
+ * the current stack depth for the GC.
+ *
+ * If you're changing to THREAD_RUNNING, this will check for suspension.
+ *
+ * Returns the old status.
+ */
+ThreadStatus dvmChangeStatus(Thread* self, ThreadStatus newStatus);
+
+/*
+ * Initialize a mutex.
+ */
+INLINE void dvmInitMutex(pthread_mutex_t* pMutex)
+{
+#ifdef CHECK_MUTEX
+    pthread_mutexattr_t attr;
+    int cc;
+
+    pthread_mutexattr_init(&attr);
+    cc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
+    assert(cc == 0);
+    pthread_mutex_init(pMutex, &attr);
+    pthread_mutexattr_destroy(&attr);
+#else
+    pthread_mutex_init(pMutex, NULL);       // default=PTHREAD_MUTEX_FAST_NP
+#endif
+}
+
+/*
+ * Grab a plain mutex.
+ */
+INLINE void dvmLockMutex(pthread_mutex_t* pMutex)
+{
+    int cc __attribute__ ((__unused__)) = pthread_mutex_lock(pMutex);
+    assert(cc == 0);
+}
+
+/*
+ * Try grabbing a plain mutex.  Returns 0 if successful.
+ */
+INLINE int dvmTryLockMutex(pthread_mutex_t* pMutex)
+{
+    int cc = pthread_mutex_trylock(pMutex);
+    assert(cc == 0 || cc == EBUSY);
+    return cc;
+}
+
+/*
+ * Unlock pthread mutex.
+ */
+INLINE void dvmUnlockMutex(pthread_mutex_t* pMutex)
+{
+    int cc __attribute__ ((__unused__)) = pthread_mutex_unlock(pMutex);
+    assert(cc == 0);
+}
+
+/*
+ * Destroy a mutex.
+ */
+INLINE void dvmDestroyMutex(pthread_mutex_t* pMutex)
+{
+    int cc __attribute__ ((__unused__)) = pthread_mutex_destroy(pMutex);
+    assert(cc == 0);
+}
+
+INLINE void dvmBroadcastCond(pthread_cond_t* pCond)
+{
+    int cc __attribute__ ((__unused__)) = pthread_cond_broadcast(pCond);
+    assert(cc == 0);
+}
+
+INLINE void dvmSignalCond(pthread_cond_t* pCond)
+{
+    int cc __attribute__ ((__unused__)) = pthread_cond_signal(pCond);
+    assert(cc == 0);
+}
+
+INLINE void dvmWaitCond(pthread_cond_t* pCond, pthread_mutex_t* pMutex)
+{
+    int cc __attribute__ ((__unused__)) = pthread_cond_wait(pCond, pMutex);
+    assert(cc == 0);
+}
+
+/*
+ * Create a thread as a result of java.lang.Thread.start().
+ */
+bool dvmCreateInterpThread(Object* threadObj, int reqStackSize);
+
+/*
+ * Create a thread internal to the VM.  It's visible to interpreted code,
+ * but found in the "system" thread group rather than "main".
+ */
+bool dvmCreateInternalThread(pthread_t* pHandle, const char* name,
+    InternalThreadStart func, void* funcArg);
+
+/*
+ * Attach or detach the current thread from the VM.
+ */
+bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon);
+void dvmDetachCurrentThread(void);
+
+/*
+ * Get the "main" or "system" thread group.
+ */
+Object* dvmGetMainThreadGroup(void);
+Object* dvmGetSystemThreadGroup(void);
+
+/*
+ * Given a java/lang/VMThread object, return our Thread.
+ */
+Thread* dvmGetThreadFromThreadObject(Object* vmThreadObj);
+
+/*
+ * Given a pthread handle, return the associated Thread*.
+ * Caller must hold the thread list lock.
+ *
+ * Returns NULL if the thread was not found.
+ */
+Thread* dvmGetThreadByHandle(pthread_t handle);
+
+/*
+ * Given a thread ID, return the associated Thread*.
+ * Caller must hold the thread list lock.
+ *
+ * Returns NULL if the thread was not found.
+ */
+Thread* dvmGetThreadByThreadId(u4 threadId);
+
+/*
+ * Sleep in a thread.  Returns when the sleep timer returns or the thread
+ * is interrupted.
+ */
+void dvmThreadSleep(u8 msec, u4 nsec);
+
+/*
+ * Get the name of a thread.
+ *
+ * For correctness, the caller should hold the thread list lock to ensure
+ * that the thread doesn't go away mid-call.
+ */
+std::string dvmGetThreadName(Thread* thread);
+
+/*
+ * Convert ThreadStatus to a string.
+ */
+const char* dvmGetThreadStatusStr(ThreadStatus status);
+
+/*
+ * Return true if a thread is on the internal list.  If it is, the
+ * thread is part of the GC's root set.
+ */
+bool dvmIsOnThreadList(const Thread* thread);
+
+/*
+ * Get/set the JNIEnv field.
+ */
+INLINE JNIEnv* dvmGetThreadJNIEnv(Thread* self) { return self->jniEnv; }
+INLINE void dvmSetThreadJNIEnv(Thread* self, JNIEnv* env) { self->jniEnv = env;}
+
+/*
+ * Update the priority value of the underlying pthread.
+ */
+void dvmChangeThreadPriority(Thread* thread, int newPriority);
+
+/* "change flags" values for raise/reset thread priority calls */
+#define kChangedPriority    0x01
+#define kChangedPolicy      0x02
+
+/*
+ * If necessary, raise the thread's priority to nice=0 cgroup=fg.
+ *
+ * Returns bit flags indicating changes made (zero if nothing was done).
+ */
+int dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
+    SchedPolicy* pSavedThreadPolicy);
+
+/*
+ * Drop the thread priority to what it was before an earlier call to
+ * dvmRaiseThreadPriorityIfNeeded().
+ */
+void dvmResetThreadPriority(Thread* thread, int changeFlags,
+    int savedThreadPrio, SchedPolicy savedThreadPolicy);
+
+/*
+ * Debug: dump information about a single thread.
+ */
+void dvmDumpThread(Thread* thread, bool isRunning);
+void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
+    bool isRunning);
+
+/*
+ * Debug: dump information about all threads.
+ */
+void dvmDumpAllThreads(bool grabLock);
+void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock);
+
+/*
+ * Debug: kill a thread to get a debuggerd stack trace.  Leaves the VM
+ * in an uncertain state.
+ */
+void dvmNukeThread(Thread* thread);
+
+#endif  // DALVIK_THREAD_H_
diff --git a/vm/UtfString.cpp b/vm/UtfString.cpp
new file mode 100644
index 0000000..63d116e
--- /dev/null
+++ b/vm/UtfString.cpp
@@ -0,0 +1,412 @@
+/*
+ * 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.
+ */
+
+/*
+ * UTF-8 and Unicode string manipulation, plus java/lang/String convenience
+ * functions.
+ *
+ * In most cases we populate the fields in the String object directly,
+ * rather than going through an instance field lookup.
+ */
+#include "Dalvik.h"
+#include <stdlib.h>
+
+/*
+ * Allocate a new instance of the class String, performing first-use
+ * initialization of the class if necessary. Upon success, the
+ * returned value will have all its fields except hashCode already
+ * filled in, including a reference to a newly-allocated char[] for
+ * the contents, sized as given. Additionally, a reference to the
+ * chars array is stored to the pChars pointer. Callers must
+ * subsequently call dvmReleaseTrackedAlloc() on the result pointer.
+ * This function returns NULL on failure.
+ */
+static StringObject* makeStringObject(u4 charsLength, ArrayObject** pChars)
+{
+    /*
+     * The String class should have already gotten found (but not
+     * necessarily initialized) before making it here. We assert it
+     * explicitly, since historically speaking, we have had bugs with
+     * regard to when the class String gets set up. The assert helps
+     * make any regressions easier to diagnose.
+     */
+    assert(gDvm.classJavaLangString != NULL);
+
+    if (!dvmIsClassInitialized(gDvm.classJavaLangString)) {
+        /* Perform first-time use initialization of the class. */
+        if (!dvmInitClass(gDvm.classJavaLangString)) {
+            LOGE("FATAL: Could not initialize class String");
+            dvmAbort();
+        }
+    }
+
+    Object* result = dvmAllocObject(gDvm.classJavaLangString, ALLOC_DEFAULT);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    ArrayObject* chars = dvmAllocPrimitiveArray('C', charsLength, ALLOC_DEFAULT);
+    if (chars == NULL) {
+        dvmReleaseTrackedAlloc(result, NULL);
+        return NULL;
+    }
+
+    dvmSetFieldInt(result, STRING_FIELDOFF_COUNT, charsLength);
+    dvmSetFieldObject(result, STRING_FIELDOFF_VALUE, (Object*) chars);
+    dvmReleaseTrackedAlloc((Object*) chars, NULL);
+    /* Leave offset and hashCode set to zero. */
+
+    *pChars = chars;
+    return (StringObject*) result;
+}
+
+/*
+ * Compute a hash code on a UTF-8 string, for use with internal hash tables.
+ *
+ * This may or may not yield the same results as the java/lang/String
+ * computeHashCode() function.  (To make sure this doesn't get abused,
+ * I'm initializing the hash code to 1 so they *don't* match up.)
+ *
+ * It would be more correct to invoke dexGetUtf16FromUtf8() here and compute
+ * the hash with the result.  That way, if something encoded the same
+ * character in two different ways, the hash value would be the same.  For
+ * our purposes that isn't necessary.
+ */
+u4 dvmComputeUtf8Hash(const char* utf8Str)
+{
+    u4 hash = 1;
+
+    while (*utf8Str != '\0')
+        hash = hash * 31 + *utf8Str++;
+
+    return hash;
+}
+
+/*
+ * Like "strlen", but for strings encoded with "modified" UTF-8.
+ *
+ * The value returned is the number of characters, which may or may not
+ * be the same as the number of bytes.
+ *
+ * (If this needs optimizing, try: mask against 0xa0, shift right 5,
+ * get increment {1-3} from table of 8 values.)
+ */
+size_t dvmUtf8Len(const char* utf8Str)
+{
+    size_t len = 0;
+    int ic;
+
+    while ((ic = *utf8Str++) != '\0') {
+        len++;
+        if ((ic & 0x80) != 0) {
+            /* two- or three-byte encoding */
+            utf8Str++;
+            if ((ic & 0x20) != 0) {
+                /* three-byte encoding */
+                utf8Str++;
+            }
+        }
+    }
+
+    return len;
+}
+
+/*
+ * Convert a "modified" UTF-8 string to UTF-16.
+ */
+void dvmConvertUtf8ToUtf16(u2* utf16Str, const char* utf8Str)
+{
+    while (*utf8Str != '\0')
+        *utf16Str++ = dexGetUtf16FromUtf8(&utf8Str);
+}
+
+/*
+ * Given a UTF-16 string, compute the length of the corresponding UTF-8
+ * string in bytes.
+ */
+static int utf16_utf8ByteLen(const u2* utf16Str, int len)
+{
+    int utf8Len = 0;
+
+    while (len--) {
+        unsigned int uic = *utf16Str++;
+
+        /*
+         * The most common case is (uic > 0 && uic <= 0x7f).
+         */
+        if (uic == 0 || uic > 0x7f) {
+            if (uic > 0x07ff)
+                utf8Len += 3;
+            else /*(uic > 0x7f || uic == 0) */
+                utf8Len += 2;
+        } else
+            utf8Len++;
+    }
+    return utf8Len;
+}
+
+/*
+ * Convert a UTF-16 string to UTF-8.
+ *
+ * Make sure you allocate "utf8Str" with the result of utf16_utf8ByteLen(),
+ * not just "len".
+ */
+static void convertUtf16ToUtf8(char* utf8Str, const u2* utf16Str, int len)
+{
+    assert(len >= 0);
+
+    while (len--) {
+        unsigned int uic = *utf16Str++;
+
+        /*
+         * The most common case is (uic > 0 && uic <= 0x7f).
+         */
+        if (uic == 0 || uic > 0x7f) {
+            if (uic > 0x07ff) {
+                *utf8Str++ = (uic >> 12) | 0xe0;
+                *utf8Str++ = ((uic >> 6) & 0x3f) | 0x80;
+                *utf8Str++ = (uic & 0x3f) | 0x80;
+            } else /*(uic > 0x7f || uic == 0)*/ {
+                *utf8Str++ = (uic >> 6) | 0xc0;
+                *utf8Str++ = (uic & 0x3f) | 0x80;
+            }
+        } else {
+            *utf8Str++ = uic;
+        }
+    }
+
+    *utf8Str = '\0';
+}
+
+/*
+ * Use the java/lang/String.computeHashCode() algorithm.
+ */
+static inline u4 computeUtf16Hash(const u2* utf16Str, size_t len)
+{
+    u4 hash = 0;
+
+    while (len--)
+        hash = hash * 31 + *utf16Str++;
+
+    return hash;
+}
+
+u4 dvmComputeStringHash(StringObject* strObj) {
+    int hashCode = dvmGetFieldInt(strObj, STRING_FIELDOFF_HASHCODE);
+    if (hashCode != 0) {
+      return hashCode;
+    }
+    int len = dvmGetFieldInt(strObj, STRING_FIELDOFF_COUNT);
+    int offset = dvmGetFieldInt(strObj, STRING_FIELDOFF_OFFSET);
+    ArrayObject* chars =
+            (ArrayObject*) dvmGetFieldObject(strObj, STRING_FIELDOFF_VALUE);
+    hashCode = computeUtf16Hash((u2*)(void*)chars->contents + offset, len);
+    dvmSetFieldInt(strObj, STRING_FIELDOFF_HASHCODE, hashCode);
+    return hashCode;
+}
+
+StringObject* dvmCreateStringFromCstr(const char* utf8Str) {
+    assert(utf8Str != NULL);
+    return dvmCreateStringFromCstrAndLength(utf8Str, dvmUtf8Len(utf8Str));
+}
+
+StringObject* dvmCreateStringFromCstr(const std::string& utf8Str) {
+    return dvmCreateStringFromCstr(utf8Str.c_str());
+}
+
+/*
+ * Create a java/lang/String from a C string, given its UTF-16 length
+ * (number of UTF-16 code points).
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+StringObject* dvmCreateStringFromCstrAndLength(const char* utf8Str,
+    size_t utf16Length)
+{
+    assert(utf8Str != NULL);
+
+    ArrayObject* chars;
+    StringObject* newObj = makeStringObject(utf16Length, &chars);
+    if (newObj == NULL) {
+        return NULL;
+    }
+
+    dvmConvertUtf8ToUtf16((u2*)(void*)chars->contents, utf8Str);
+
+    u4 hashCode = computeUtf16Hash((u2*)(void*)chars->contents, utf16Length);
+    dvmSetFieldInt((Object*) newObj, STRING_FIELDOFF_HASHCODE, hashCode);
+
+    return newObj;
+}
+
+/*
+ * Create a new java/lang/String object, using the given Unicode data.
+ */
+StringObject* dvmCreateStringFromUnicode(const u2* unichars, int len)
+{
+    /* We allow a NULL pointer if the length is zero. */
+    assert(len == 0 || unichars != NULL);
+
+    ArrayObject* chars;
+    StringObject* newObj = makeStringObject(len, &chars);
+    if (newObj == NULL) {
+        return NULL;
+    }
+
+    if (len > 0) memcpy(chars->contents, unichars, len * sizeof(u2));
+
+    u4 hashCode = computeUtf16Hash((u2*)(void*)chars->contents, len);
+    dvmSetFieldInt((Object*)newObj, STRING_FIELDOFF_HASHCODE, hashCode);
+
+    return newObj;
+}
+
+/*
+ * Create a new C string from a java/lang/String object.
+ *
+ * Returns NULL if the object is NULL.
+ */
+char* dvmCreateCstrFromString(const StringObject* jstr)
+{
+    assert(gDvm.classJavaLangString != NULL);
+    if (jstr == NULL) {
+        return NULL;
+    }
+
+    int len = dvmGetFieldInt(jstr, STRING_FIELDOFF_COUNT);
+    int offset = dvmGetFieldInt(jstr, STRING_FIELDOFF_OFFSET);
+    ArrayObject* chars =
+            (ArrayObject*) dvmGetFieldObject(jstr, STRING_FIELDOFF_VALUE);
+    const u2* data = (const u2*)(void*)chars->contents + offset;
+    assert(offset + len <= (int) chars->length);
+
+    int byteLen = utf16_utf8ByteLen(data, len);
+    char* newStr = (char*) malloc(byteLen+1);
+    if (newStr == NULL) {
+        return NULL;
+    }
+    convertUtf16ToUtf8(newStr, data, len);
+
+    return newStr;
+}
+
+void dvmGetStringUtfRegion(const StringObject* jstr,
+        int start, int len, char* buf)
+{
+    const u2* data = jstr->chars() + start;
+    convertUtf16ToUtf8(buf, data, len);
+}
+
+int StringObject::utfLength() const
+{
+    assert(gDvm.classJavaLangString != NULL);
+
+    int len = dvmGetFieldInt(this, STRING_FIELDOFF_COUNT);
+    int offset = dvmGetFieldInt(this, STRING_FIELDOFF_OFFSET);
+    ArrayObject* chars =
+            (ArrayObject*) dvmGetFieldObject(this, STRING_FIELDOFF_VALUE);
+    const u2* data = (const u2*)(void*)chars->contents + offset;
+    assert(offset + len <= (int) chars->length);
+
+    return utf16_utf8ByteLen(data, len);
+}
+
+int StringObject::length() const
+{
+    return dvmGetFieldInt(this, STRING_FIELDOFF_COUNT);
+}
+
+ArrayObject* StringObject::array() const
+{
+    return (ArrayObject*) dvmGetFieldObject(this, STRING_FIELDOFF_VALUE);
+}
+
+const u2* StringObject::chars() const
+{
+    int offset = dvmGetFieldInt(this, STRING_FIELDOFF_OFFSET);
+    ArrayObject* chars =
+            (ArrayObject*) dvmGetFieldObject(this, STRING_FIELDOFF_VALUE);
+    return (const u2*)(void*)chars->contents + offset;
+}
+
+
+/*
+ * Compare two String objects.
+ *
+ * This is a dvmHashTableLookup() callback.  The function has already
+ * compared their hash values; we need to do a full compare to ensure
+ * that the strings really match.
+ */
+int dvmHashcmpStrings(const void* vstrObj1, const void* vstrObj2)
+{
+    const StringObject* strObj1 = (const StringObject*) vstrObj1;
+    const StringObject* strObj2 = (const StringObject*) vstrObj2;
+
+    assert(gDvm.classJavaLangString != NULL);
+
+    /* get offset and length into char array; all values are in 16-bit units */
+    int len1 = dvmGetFieldInt(strObj1, STRING_FIELDOFF_COUNT);
+    int offset1 = dvmGetFieldInt(strObj1, STRING_FIELDOFF_OFFSET);
+    int len2 = dvmGetFieldInt(strObj2, STRING_FIELDOFF_COUNT);
+    int offset2 = dvmGetFieldInt(strObj2, STRING_FIELDOFF_OFFSET);
+    if (len1 != len2) {
+        return len1 - len2;
+    }
+
+    ArrayObject* chars1 =
+            (ArrayObject*) dvmGetFieldObject(strObj1, STRING_FIELDOFF_VALUE);
+    ArrayObject* chars2 =
+            (ArrayObject*) dvmGetFieldObject(strObj2, STRING_FIELDOFF_VALUE);
+
+    /* damage here actually indicates a broken java/lang/String */
+    assert(offset1 + len1 <= (int) chars1->length);
+    assert(offset2 + len2 <= (int) chars2->length);
+
+    return memcmp((const u2*)(void*)chars1->contents + offset1,
+                  (const u2*)(void*)chars2->contents + offset2,
+                  len1 * sizeof(u2));
+}
+
+ArrayObject* dvmCreateStringArray(const std::vector<std::string>& strings) {
+    Thread* self = dvmThreadSelf();
+
+    // Allocate an array to hold the String objects.
+    ClassObject* elementClass = dvmFindArrayClassForElement(gDvm.classJavaLangString);
+    ArrayObject* stringArray = dvmAllocArrayByClass(elementClass, strings.size(), ALLOC_DEFAULT);
+    if (stringArray == NULL) {
+        // Probably OOM.
+        assert(dvmCheckException(self));
+        return NULL;
+    }
+
+    // Create the individual String objects and add them to the array.
+    for (size_t i = 0; i < strings.size(); i++) {
+        Object* str = (Object*) dvmCreateStringFromCstr(strings[i]);
+        if (str == NULL) {
+            // Probably OOM; drop out now.
+            assert(dvmCheckException(self));
+            dvmReleaseTrackedAlloc((Object*) stringArray, self);
+            return NULL;
+        }
+        dvmSetObjectArrayElement(stringArray, i, str);
+        /* stored in tracked array, okay to release */
+        dvmReleaseTrackedAlloc(str, self);
+    }
+
+    return stringArray;
+}
diff --git a/vm/UtfString.h b/vm/UtfString.h
new file mode 100644
index 0000000..352948c
--- /dev/null
+++ b/vm/UtfString.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/*
+ * UTF-8 and Unicode string manipulation functions, plus convenience
+ * functions for working with java/lang/String.
+ */
+#ifndef DALVIK_STRING_H_
+#define DALVIK_STRING_H_
+
+#include <string>
+#include <vector>
+
+/*
+ * (This is private to UtfString.c, but we cheat a bit and also use it
+ * for InlineNative.c.  Not really worth creating a separate header.)
+ *
+ * We can avoid poking around in gDvm by hard-coding the expected values of
+ * the String field offsets.  This will be annoying if String is in flux
+ * or the VM field layout is changing, so we use defines here to make it
+ * easy to switch back to the gDvm version.
+ *
+ * The values are checked for correctness during startup.
+ */
+//#define USE_GLOBAL_STRING_DEFS
+#ifdef USE_GLOBAL_STRING_DEFS
+# define STRING_FIELDOFF_VALUE      gDvm.offJavaLangString_value
+# define STRING_FIELDOFF_OFFSET     gDvm.offJavaLangString_offset
+# define STRING_FIELDOFF_COUNT      gDvm.offJavaLangString_count
+# define STRING_FIELDOFF_HASHCODE   gDvm.offJavaLangString_hashCode
+#else
+# define STRING_FIELDOFF_VALUE      8
+# define STRING_FIELDOFF_HASHCODE   12
+# define STRING_FIELDOFF_OFFSET     16
+# define STRING_FIELDOFF_COUNT      20
+#endif
+
+/*
+ * Hash function for modified UTF-8 strings.
+ */
+u4 dvmComputeUtf8Hash(const char* str);
+
+/*
+ * Hash function for string objects. Ensures the hash code field is
+ * populated and returns its value.
+ */
+u4 dvmComputeStringHash(StringObject* strObj);
+
+/*
+ * Create a java.lang.String[] from a vector of C++ strings.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the returned array,
+ * but not on the individual elements.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+ArrayObject* dvmCreateStringArray(const std::vector<std::string>& strings);
+
+/*
+ * Create a java/lang/String from a C string.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+StringObject* dvmCreateStringFromCstr(const char* utf8Str);
+
+/*
+ * Create a java/lang/String from a C++ string.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+StringObject* dvmCreateStringFromCstr(const std::string& utf8Str);
+
+/*
+ * Create a java/lang/String from a C string, given its UTF-16 length
+ * (number of UTF-16 code points).
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+StringObject* dvmCreateStringFromCstrAndLength(const char* utf8Str,
+    u4 utf16Length);
+
+/*
+ * Compute the number of characters in a "modified UTF-8" string.  This will
+ * match the result from strlen() so long as there are no multi-byte chars.
+ */
+size_t dvmUtf8Len(const char* utf8Str);
+
+/*
+ * Convert a UTF-8 string to UTF-16.  "utf16Str" must have enough room
+ * to hold the output.
+ */
+void dvmConvertUtf8ToUtf16(u2* utf16Str, const char* utf8Str);
+
+/*
+ * Create a java/lang/String from a Unicode string.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
+ */
+StringObject* dvmCreateStringFromUnicode(const u2* unichars, int len);
+
+/*
+ * Create a UTF-8 C string from a java/lang/String.  Caller must free
+ * the result.
+ *
+ * Returns NULL if "jstr" is NULL.
+ */
+char* dvmCreateCstrFromString(const StringObject* jstr);
+
+/*
+ * Create a UTF-8 C string from a region of a java/lang/String.  (Used by
+ * the JNI GetStringUTFRegion call.)
+ */
+void dvmGetStringUtfRegion(const StringObject* jstr,
+        int start, int len, char* buf);
+
+/*
+ * Compare two string objects.  (This is a dvmHashTableLookup() callback.)
+ */
+int dvmHashcmpStrings(const void* vstrObj1, const void* vstrObj2);
+
+#endif  // DALVIK_STRING_H_
diff --git a/vm/alloc/Alloc.cpp b/vm/alloc/Alloc.cpp
new file mode 100644
index 0000000..d2c3336
--- /dev/null
+++ b/vm/alloc/Alloc.cpp
@@ -0,0 +1,359 @@
+/*
+ * 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.
+ */
+/*
+ * Garbage-collecting memory allocator.
+ */
+#include "Dalvik.h"
+#include "alloc/Heap.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/HeapSource.h"
+
+/*
+ * Initialize the GC universe.
+ *
+ * We're currently using a memory-mapped arena to keep things off of the
+ * main heap.  This needs to be replaced with something real.
+ */
+bool dvmGcStartup()
+{
+    dvmInitMutex(&gDvm.gcHeapLock);
+    pthread_cond_init(&gDvm.gcHeapCond, NULL);
+    return dvmHeapStartup();
+}
+
+/*
+ * Post-zygote heap initialization, including starting
+ * the HeapWorker thread.
+ */
+bool dvmGcStartupAfterZygote()
+{
+    return dvmHeapStartupAfterZygote();
+}
+
+/*
+ * Shutdown the threads internal to the garbage collector.
+ */
+void dvmGcThreadShutdown()
+{
+    dvmHeapThreadShutdown();
+}
+
+/*
+ * Shut the GC down.
+ */
+void dvmGcShutdown()
+{
+    //TODO: grab and destroy the lock
+    dvmHeapShutdown();
+}
+
+/*
+ * Do any last-minute preparation before we call fork() for the first time.
+ */
+bool dvmGcPreZygoteFork()
+{
+    return dvmHeapSourceStartupBeforeFork();
+}
+
+bool dvmGcStartupClasses()
+{
+    ClassObject *klass = dvmFindSystemClass("Ljava/lang/Daemons;");
+    if (klass == NULL) {
+        return false;
+    }
+    Method *method = dvmFindDirectMethodByDescriptor(klass, "start", "()V");
+    if (method == NULL) {
+        return false;
+    }
+    Thread *self = dvmThreadSelf();
+    assert(self != NULL);
+    JValue unusedResult;
+    dvmCallMethod(self, method, NULL, &unusedResult);
+    return true;
+}
+
+/*
+ * Create a "stock instance" of an exception class.
+ */
+static Object* createStockException(const char* descriptor, const char* msg)
+{
+    Thread* self = dvmThreadSelf();
+    StringObject* msgStr = NULL;
+    ClassObject* clazz;
+    Method* init;
+    Object* obj;
+
+    /* find class, initialize if necessary */
+    clazz = dvmFindSystemClass(descriptor);
+    if (clazz == NULL) {
+        LOGE("Unable to find %s", descriptor);
+        return NULL;
+    }
+
+    init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
+            "(Ljava/lang/String;)V");
+    if (init == NULL) {
+        LOGE("Unable to find String-arg constructor for %s", descriptor);
+        return NULL;
+    }
+
+    obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
+    if (obj == NULL)
+        return NULL;
+
+    if (msg == NULL) {
+        msgStr = NULL;
+    } else {
+        msgStr = dvmCreateStringFromCstr(msg);
+        if (msgStr == NULL) {
+            LOGW("Could not allocate message string \"%s\"", msg);
+            dvmReleaseTrackedAlloc(obj, self);
+            return NULL;
+        }
+    }
+
+    JValue unused;
+    dvmCallMethod(self, init, obj, &unused, msgStr);
+    if (dvmCheckException(self)) {
+        dvmReleaseTrackedAlloc((Object*) msgStr, self);
+        dvmReleaseTrackedAlloc(obj, self);
+        return NULL;
+    }
+
+    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
+    return obj;
+}
+
+/*
+ * Create some "stock" exceptions.  These can be thrown when the system is
+ * too screwed up to allocate and initialize anything, or when we don't
+ * need a meaningful stack trace.
+ *
+ * We can't do this during the initial startup because we need to execute
+ * the constructors.
+ */
+bool dvmCreateStockExceptions()
+{
+    /*
+     * Pre-allocate some throwables.  These need to be explicitly added
+     * to the GC's root set (see dvmHeapMarkRootSet()).
+     */
+    gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
+        "[memory exhausted]");
+    dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
+    gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
+        "[pre-allocated]");
+    dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
+    gDvm.noClassDefFoundErrorObj =
+        createStockException("Ljava/lang/NoClassDefFoundError;",
+            "[generic]");
+    dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
+
+    if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
+        gDvm.noClassDefFoundErrorObj == NULL)
+    {
+        LOGW("Unable to create stock exceptions");
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Create an instance of the specified class.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+Object* dvmAllocObject(ClassObject* clazz, int flags)
+{
+    Object* newObj;
+
+    assert(clazz != NULL);
+    assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
+
+    /* allocate on GC heap; memory is zeroed out */
+    newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
+    if (newObj != NULL) {
+        DVM_OBJECT_INIT(newObj, clazz);
+        dvmTrackAllocation(clazz, clazz->objectSize);   /* notify DDMS */
+    }
+
+    return newObj;
+}
+
+/*
+ * Create a copy of an object, for Object.clone().
+ *
+ * We use the size actually allocated, rather than obj->clazz->objectSize,
+ * because the latter doesn't work for array objects.
+ */
+Object* dvmCloneObject(Object* obj, int flags)
+{
+    assert(dvmIsValidObject(obj));
+    ClassObject* clazz = obj->clazz;
+
+    /* Class.java shouldn't let us get here (java.lang.Class is final
+     * and does not implement Clonable), but make extra sure.
+     * A memcpy() clone will wreak havoc on a ClassObject's "innards".
+     */
+    assert(!dvmIsTheClassClass(clazz));
+
+    size_t size;
+    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
+        size = dvmArrayObjectSize((ArrayObject *)obj);
+    } else {
+        size = clazz->objectSize;
+    }
+
+    Object* copy = (Object*)dvmMalloc(size, flags);
+    if (copy == NULL)
+        return NULL;
+
+    DVM_OBJECT_INIT(copy, clazz);
+    size_t offset = sizeof(Object);
+    /* Copy instance data.  We assume memcpy copies by words. */
+    memcpy((char*)copy + offset, (char*)obj + offset, size - offset);
+
+    /* Mark the clone as finalizable if appropriate. */
+    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
+        dvmSetFinalizable(copy);
+    }
+
+    dvmTrackAllocation(clazz, size);    /* notify DDMS */
+
+    return copy;
+}
+
+
+/*
+ * Track an object that was allocated internally and isn't yet part of the
+ * VM root set.
+ *
+ * We could do this per-thread or globally.  If it's global we don't have
+ * to do the thread lookup but we do have to synchronize access to the list.
+ *
+ * "obj" must not be NULL.
+ *
+ * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
+ * usually be NULL since we're being called from dvmMalloc().
+ */
+void dvmAddTrackedAlloc(Object* obj, Thread* self)
+{
+    if (self == NULL)
+        self = dvmThreadSelf();
+
+    assert(obj != NULL);
+    assert(self != NULL);
+    if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
+        LOGE("threadid=%d: unable to add %p to internal ref table",
+            self->threadId, obj);
+        dvmDumpThread(self, false);
+        dvmAbort();
+    }
+}
+
+/*
+ * Stop tracking an object.
+ *
+ * We allow attempts to delete NULL "obj" so that callers don't have to wrap
+ * calls with "if != NULL".
+ */
+void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
+{
+    if (obj == NULL)
+        return;
+
+    if (self == NULL)
+        self = dvmThreadSelf();
+    assert(self != NULL);
+
+    if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
+            self->internalLocalRefTable.table, obj))
+    {
+        LOGE("threadid=%d: failed to remove %p from internal ref table",
+            self->threadId, obj);
+        dvmAbort();
+    }
+}
+
+
+/*
+ * Explicitly initiate garbage collection.
+ */
+void dvmCollectGarbage()
+{
+    if (gDvm.disableExplicitGc) {
+        return;
+    }
+    dvmLockHeap();
+    dvmWaitForConcurrentGcToComplete();
+    dvmCollectGarbageInternal(GC_EXPLICIT);
+    dvmUnlockHeap();
+}
+
+struct CountContext {
+    const ClassObject *clazz;
+    size_t count;
+};
+
+static void countInstancesOfClassCallback(Object *obj, void *arg)
+{
+    CountContext *ctx = (CountContext *)arg;
+    assert(ctx != NULL);
+    if (obj->clazz == ctx->clazz) {
+        ctx->count += 1;
+    }
+}
+
+size_t dvmCountInstancesOfClass(const ClassObject *clazz)
+{
+    CountContext ctx = { clazz, 0 };
+    dvmLockHeap();
+    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
+    dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
+    dvmUnlockHeap();
+    return ctx.count;
+}
+
+static void countAssignableInstancesOfClassCallback(Object *obj, void *arg)
+{
+    CountContext *ctx = (CountContext *)arg;
+    assert(ctx != NULL);
+    if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
+        ctx->count += 1;
+    }
+}
+
+size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
+{
+    CountContext ctx = { clazz, 0 };
+    dvmLockHeap();
+    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
+    dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
+    dvmUnlockHeap();
+    return ctx.count;
+}
+
+bool dvmIsHeapAddress(void *address)
+{
+    return address != NULL && (((uintptr_t) address & (8-1)) == 0);
+}
+
+bool dvmIsNonMovingObject(const Object* object)
+{
+    return true;
+}
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
new file mode 100644
index 0000000..efee1bd
--- /dev/null
+++ b/vm/alloc/Alloc.h
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+/*
+ * Garbage-collecting allocator.
+ */
+#ifndef DALVIK_ALLOC_ALLOC_H_
+#define DALVIK_ALLOC_ALLOC_H_
+
+#include <stddef.h>
+
+/* flags for dvmMalloc */
+enum {
+    ALLOC_DEFAULT = 0x00,
+    ALLOC_DONT_TRACK = 0x01,  /* don't add to internal tracking list */
+    ALLOC_NON_MOVING = 0x02,
+};
+
+/*
+ * Initialization.
+ */
+bool dvmGcStartup(void);
+bool dvmCreateStockExceptions(void);
+bool dvmGcStartupAfterZygote(void);
+void dvmGcShutdown(void);
+void dvmGcThreadShutdown(void);
+bool dvmGcStartupClasses(void);
+
+/*
+ * Do any last-minute preparation before we call fork() for the first time.
+ */
+bool dvmGcPreZygoteFork(void);
+
+/*
+ * Basic allocation function.
+ *
+ * The new object will be added to the "tracked alloc" table unless
+ * flags is ALLOC_DONT_TRACK.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+void* dvmMalloc(size_t size, int flags);
+
+/*
+ * Allocate a new object.
+ *
+ * The new object will be added to the "tracked alloc" table unless
+ * flags is ALLOC_DONT_TRACK.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+extern "C" Object* dvmAllocObject(ClassObject* clazz, int flags);
+
+/*
+ * Track an object reference that is currently only visible internally.
+ * This is called automatically by dvmMalloc() unless ALLOC_DONT_TRACK
+ * is set.
+ *
+ * The "self" argument is allowed as an optimization; it may be NULL.
+ */
+extern "C" void dvmAddTrackedAlloc(Object* obj, Thread* self);
+
+/*
+ * Remove an object from the internal tracking list.
+ *
+ * Does nothing if "obj" is NULL.
+ *
+ * The "self" argument is allowed as an optimization; it may be NULL.
+ */
+extern "C" void dvmReleaseTrackedAlloc(Object* obj, Thread* self);
+
+/*
+ * Returns true iff <obj> points to a zygote allocated object.
+ */
+bool dvmIsZygoteObject(const Object* obj);
+
+/*
+ * Create a copy of an object.
+ *
+ * Returns NULL and throws an exception on failure.
+ */
+Object* dvmCloneObject(Object* obj, int flags);
+
+/*
+ * Make the object finalizable.
+ */
+extern "C" void dvmSetFinalizable(Object* obj);
+
+/*
+ * Determine the exact number of GC heap bytes used by an object.  (Internal
+ * to heap code except for debugging.)
+ */
+size_t dvmObjectSizeInHeap(const Object* obj);
+
+/*
+ * Gets the current ideal heap utilization, represented as a number
+ * between zero and one.
+ */
+float dvmGetTargetHeapUtilization(void);
+
+/*
+ * Sets the new ideal heap utilization, represented as a number
+ * between zero and one.
+ */
+void dvmSetTargetHeapUtilization(float newTarget);
+
+/*
+ * Initiate garbage collection.
+ *
+ * This usually happens automatically, but can also be caused by
+ * Runtime.gc().
+ */
+void dvmCollectGarbage(void);
+
+/*
+ * Returns a count of the direct instances of a class.
+ */
+size_t dvmCountInstancesOfClass(const ClassObject *clazz);
+
+/*
+ * Returns a count of the instances of a class and its subclasses.
+ */
+size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz);
+
+/*
+ * Removes any growth limits from the heap.
+ */
+void dvmClearGrowthLimit(void);
+
+/*
+ * Returns true if the address is aligned appropriately for a heap object.
+ * Does not require the caller to hold the heap lock, and does not take the
+ * heap lock internally.
+ */
+bool dvmIsHeapAddress(void *address);
+
+bool dvmIsNonMovingObject(const Object* object);
+
+#endif  // DALVIK_ALLOC_ALLOC_H_
diff --git a/vm/alloc/CardTable.cpp b/vm/alloc/CardTable.cpp
new file mode 100644
index 0000000..333b9f9
--- /dev/null
+++ b/vm/alloc/CardTable.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/mman.h>  /* for PROT_* */
+
+#include "Dalvik.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapBitmapInlines.h"
+#include "alloc/HeapSource.h"
+#include "alloc/Visit.h"
+
+/*
+ * Maintain a card table from the the write barrier. All writes of
+ * non-NULL values to heap addresses should go through an entry in
+ * WriteBarrier, and from there to here.
+ *
+ * The heap is divided into "cards" of GC_CARD_SIZE bytes, as
+ * determined by GC_CARD_SHIFT. The card table contains one byte of
+ * data per card, to be used by the GC. The value of the byte will be
+ * one of GC_CARD_CLEAN or GC_CARD_DIRTY.
+ *
+ * After any store of a non-NULL object pointer into a heap object,
+ * code is obliged to mark the card dirty. The setters in
+ * ObjectInlines.h [such as dvmSetFieldObject] do this for you. The
+ * JIT and fast interpreters also contain code to mark cards as dirty.
+ *
+ * The card table's base [the "biased card table"] gets set to a
+ * rather strange value.  In order to keep the JIT from having to
+ * fabricate or load GC_DIRTY_CARD to store into the card table,
+ * biased base is within the mmap allocation at a point where it's low
+ * byte is equal to GC_DIRTY_CARD. See dvmCardTableStartup for details.
+ */
+
+/*
+ * Initializes the card table; must be called before any other
+ * dvmCardTable*() functions.
+ */
+bool dvmCardTableStartup(size_t heapMaximumSize, size_t growthLimit)
+{
+    size_t length;
+    void *allocBase;
+    u1 *biasedBase;
+    GcHeap *gcHeap = gDvm.gcHeap;
+    void *heapBase = dvmHeapSourceGetBase();
+    assert(gcHeap != NULL);
+    assert(heapBase != NULL);
+
+    /* Set up the card table */
+    length = heapMaximumSize / GC_CARD_SIZE;
+    /* Allocate an extra 256 bytes to allow fixed low-byte of base */
+    allocBase = dvmAllocRegion(length + 0x100, PROT_READ | PROT_WRITE,
+                            "dalvik-card-table");
+    if (allocBase == NULL) {
+        return false;
+    }
+    gcHeap->cardTableBase = (u1*)allocBase;
+    gcHeap->cardTableLength = growthLimit / GC_CARD_SIZE;
+    gcHeap->cardTableMaxLength = length;
+    gcHeap->cardTableOffset = 0;
+    /* All zeros is the correct initial value; all clean. */
+    assert(GC_CARD_CLEAN == 0);
+
+    biasedBase = (u1 *)((uintptr_t)allocBase -
+                        ((uintptr_t)heapBase >> GC_CARD_SHIFT));
+    if (((uintptr_t)biasedBase & 0xff) != GC_CARD_DIRTY) {
+        int offset = GC_CARD_DIRTY - ((uintptr_t)biasedBase & 0xff);
+        gcHeap->cardTableOffset = offset + (offset < 0 ? 0x100 : 0);
+        biasedBase += gcHeap->cardTableOffset;
+    }
+    assert(((uintptr_t)biasedBase & 0xff) == GC_CARD_DIRTY);
+    gDvm.biasedCardTableBase = biasedBase;
+
+    return true;
+}
+
+/*
+ * Tears down the entire CardTable.
+ */
+void dvmCardTableShutdown()
+{
+    gDvm.biasedCardTableBase = NULL;
+    munmap(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength);
+}
+
+void dvmClearCardTable()
+{
+    /*
+     * The goal is to zero out some mmap-allocated pages.  We can accomplish
+     * this with memset() or madvise(MADV_DONTNEED).  The latter has some
+     * useful properties, notably that the pages are returned to the system,
+     * so cards for parts of the heap we haven't expanded into won't be
+     * allocated physical pages.  On the other hand, if we un-map the card
+     * area, we'll have to fault it back in as we resume dirtying objects,
+     * which reduces performance.
+     *
+     * We don't cause any correctness issues by failing to clear cards; we
+     * just take a performance hit during the second pause of the concurrent
+     * collection.  The "advisory" nature of madvise() isn't a big problem.
+     *
+     * What we really want to do is:
+     * (1) zero out all cards that were touched
+     * (2) use madvise() to release any pages that won't be used in the near
+     *     future
+     *
+     * For #1, we don't really know which cards were touched, but we can
+     * approximate it with the "live bits max" value, which tells us the
+     * highest start address at which an object was allocated.  This may
+     * leave vestigial nonzero entries at the end if temporary objects are
+     * created during a concurrent GC, but that should be harmless.  (We
+     * can round up to the end of the card table page to reduce this.)
+     *
+     * For #2, we don't know which pages will be used in the future.  Some
+     * simple experiments suggested that a "typical" app will touch about
+     * 60KB of pages while initializing, but drops down to 20-24KB while
+     * idle.  We can save a few hundred KB system-wide with aggressive
+     * use of madvise().  The cost of mapping those pages back in is paid
+     * outside of the GC pause, which reduces the impact.  (We might be
+     * able to get the benefits by only doing this occasionally, e.g. if
+     * the heap shrinks a lot or we somehow notice that we've been idle.)
+     *
+     * Note that cardTableLength is initially set to the growth limit, and
+     * on request will be expanded to the heap maximum.
+     */
+    assert(gDvm.gcHeap->cardTableBase != NULL);
+
+#if 1
+    // zero out cards with memset(), using liveBits as an estimate
+    const HeapBitmap* liveBits = dvmHeapSourceGetLiveBits();
+    size_t maxLiveCard = (liveBits->max - liveBits->base) / GC_CARD_SIZE;
+    maxLiveCard = ALIGN_UP_TO_PAGE_SIZE(maxLiveCard);
+    if (maxLiveCard > gDvm.gcHeap->cardTableLength) {
+        maxLiveCard = gDvm.gcHeap->cardTableLength;
+    }
+
+    memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, maxLiveCard);
+#else
+    // zero out cards with madvise(), discarding all pages in the card table
+    madvise(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength,
+        MADV_DONTNEED);
+#endif
+}
+
+/*
+ * Returns true iff the address is within the bounds of the card table.
+ */
+bool dvmIsValidCard(const u1 *cardAddr)
+{
+    GcHeap *h = gDvm.gcHeap;
+    u1* begin = h->cardTableBase + h->cardTableOffset;
+    u1* end = &begin[h->cardTableLength];
+    return cardAddr >= begin && cardAddr < end;
+}
+
+/*
+ * Returns the address of the relevent byte in the card table, given
+ * an address on the heap.
+ */
+u1 *dvmCardFromAddr(const void *addr)
+{
+    u1 *biasedBase = gDvm.biasedCardTableBase;
+    u1 *cardAddr = biasedBase + ((uintptr_t)addr >> GC_CARD_SHIFT);
+    assert(dvmIsValidCard(cardAddr));
+    return cardAddr;
+}
+
+/*
+ * Returns the first address in the heap which maps to this card.
+ */
+void *dvmAddrFromCard(const u1 *cardAddr)
+{
+    assert(dvmIsValidCard(cardAddr));
+    uintptr_t offset = cardAddr - gDvm.biasedCardTableBase;
+    return (void *)(offset << GC_CARD_SHIFT);
+}
+
+/*
+ * Dirties the card for the given address.
+ */
+void dvmMarkCard(const void *addr)
+{
+    u1 *cardAddr = dvmCardFromAddr(addr);
+    *cardAddr = GC_CARD_DIRTY;
+}
+
+/*
+ * Returns true if the object is on a dirty card.
+ */
+static bool isObjectDirty(const Object *obj)
+{
+    assert(obj != NULL);
+    assert(dvmIsValidObject(obj));
+    u1 *card = dvmCardFromAddr(obj);
+    return *card == GC_CARD_DIRTY;
+}
+
+/*
+ * Context structure for verifying the card table.
+ */
+struct WhiteReferenceCounter {
+    HeapBitmap *markBits;
+    size_t whiteRefs;
+};
+
+/*
+ * Visitor that counts white referents.
+ */
+static void countWhiteReferenceVisitor(void *addr, void *arg)
+{
+    WhiteReferenceCounter *ctx;
+    Object *obj;
+
+    assert(addr != NULL);
+    assert(arg != NULL);
+    obj = *(Object **)addr;
+    if (obj == NULL) {
+        return;
+    }
+    assert(dvmIsValidObject(obj));
+    ctx = (WhiteReferenceCounter *)arg;
+    if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
+        return;
+    }
+    ctx->whiteRefs += 1;
+}
+
+/*
+ * Visitor that logs white references.
+ */
+static void dumpWhiteReferenceVisitor(void *addr, void *arg)
+{
+    WhiteReferenceCounter *ctx;
+    Object *obj;
+
+    assert(addr != NULL);
+    assert(arg != NULL);
+    obj = *(Object **)addr;
+    if (obj == NULL) {
+        return;
+    }
+    assert(dvmIsValidObject(obj));
+    ctx = (WhiteReferenceCounter*)arg;
+    if (dvmHeapBitmapIsObjectBitSet(ctx->markBits, obj)) {
+        return;
+    }
+    LOGE("object %p is white", obj);
+}
+
+/*
+ * Visitor that signals the caller when a matching reference is found.
+ */
+static void dumpReferencesVisitor(void *pObj, void *arg)
+{
+    Object *obj = *(Object **)pObj;
+    Object *lookingFor = *(Object **)arg;
+    if (lookingFor != NULL && lookingFor == obj) {
+        *(Object **)arg = NULL;
+    }
+}
+
+static void dumpReferencesCallback(Object *obj, void *arg)
+{
+    if (obj == (Object *)arg) {
+        return;
+    }
+    dvmVisitObject(dumpReferencesVisitor, obj, &arg);
+    if (arg == NULL) {
+        LOGD("Found %p in the heap @ %p", arg, obj);
+        dvmDumpObject(obj);
+    }
+}
+
+/*
+ * Root visitor that looks for matching references.
+ */
+static void dumpReferencesRootVisitor(void *ptr, u4 threadId,
+                                      RootType type, void *arg)
+{
+    Object *obj = *(Object **)ptr;
+    Object *lookingFor = *(Object **)arg;
+    if (obj == lookingFor) {
+        LOGD("Found %p in a root @ %p", arg, ptr);
+    }
+}
+
+/*
+ * Invokes visitors to search for references to an object.
+ */
+static void dumpReferences(const Object *obj)
+{
+    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
+    void *arg = (void *)obj;
+    dvmVisitRoots(dumpReferencesRootVisitor, arg);
+    dvmHeapBitmapWalk(bitmap, dumpReferencesCallback, arg);
+}
+
+/*
+ * Returns true if the given object is a reference object and the
+ * just the referent is unmarked.
+ */
+static bool isReferentUnmarked(const Object *obj,
+                               const WhiteReferenceCounter* ctx)
+{
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(ctx != NULL);
+    if (ctx->whiteRefs != 1) {
+        return false;
+    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
+        size_t offset = gDvm.offJavaLangRefReference_referent;
+        const Object *referent = dvmGetFieldObject(obj, offset);
+        return !dvmHeapBitmapIsObjectBitSet(ctx->markBits, referent);
+    } else {
+        return false;
+    }
+}
+
+/*
+ * Returns true if the given object is a string and has been interned
+ * by the user.
+ */
+static bool isWeakInternedString(const Object *obj)
+{
+    assert(obj != NULL);
+    if (obj->clazz == gDvm.classJavaLangString) {
+        return dvmIsWeakInternedString((StringObject *)obj);
+    } else {
+        return false;
+    }
+}
+
+/*
+ * Returns true if the given object has been pushed on the mark stack
+ * by root marking.
+ */
+static bool isPushedOnMarkStack(const Object *obj)
+{
+    GcMarkStack *stack = &gDvm.gcHeap->markContext.stack;
+    for (const Object **ptr = stack->base; ptr < stack->top; ++ptr) {
+        if (*ptr == obj) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Callback applied to marked objects.  If the object is gray and on
+ * an unmarked card an error is logged and the VM is aborted.  Card
+ * table verification occurs between root marking and weak reference
+ * processing.  We treat objects marked from the roots and weak
+ * references specially as it is permissible for these objects to be
+ * gray and on an unmarked card.
+ */
+static void verifyCardTableCallback(Object *obj, void *arg)
+{
+    WhiteReferenceCounter ctx = { (HeapBitmap *)arg, 0 };
+
+    dvmVisitObject(countWhiteReferenceVisitor, obj, &ctx);
+    if (ctx.whiteRefs == 0) {
+        return;
+    } else if (isObjectDirty(obj)) {
+        return;
+    } else if (isReferentUnmarked(obj, &ctx)) {
+        return;
+    } else if (isWeakInternedString(obj)) {
+        return;
+    } else if (isPushedOnMarkStack(obj)) {
+        return;
+    } else {
+        LOGE("Verify failed, object %p is gray and on an unmarked card", obj);
+        dvmDumpObject(obj);
+        dvmVisitObject(dumpWhiteReferenceVisitor, obj, &ctx);
+        dumpReferences(obj);
+        dvmAbort();
+    }
+}
+
+/*
+ * Verifies that gray objects are on a dirty card.
+ */
+void dvmVerifyCardTable()
+{
+    HeapBitmap *markBits = gDvm.gcHeap->markContext.bitmap;
+    dvmHeapBitmapWalk(markBits, verifyCardTableCallback, markBits);
+}
diff --git a/vm/alloc/CardTable.h b/vm/alloc/CardTable.h
new file mode 100644
index 0000000..43b0563
--- /dev/null
+++ b/vm/alloc/CardTable.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Maintain a card table from the the write barrier. All writes of
+ * non-NULL values to heap addresses should go through an entry in
+ * WriteBarrier, and from there to here.
+ */
+
+#ifndef DALVIK_ALLOC_CARDTABLE_H_
+#define DALVIK_ALLOC_CARDTABLE_H_
+
+#define GC_CARD_SHIFT 7
+#define GC_CARD_SIZE (1 << GC_CARD_SHIFT)
+#define GC_CARD_CLEAN 0
+#define GC_CARD_DIRTY 0x70
+
+/*
+ * Initializes the card table; must be called before any other
+ * dvmCardTable*() functions.
+ */
+bool dvmCardTableStartup(size_t heapMaximumSize, size_t growthLimit);
+
+/*
+ * Tears down the entire CardTable structure.
+ */
+void dvmCardTableShutdown(void);
+
+/*
+ * Resets all of the bytes in the card table to clean.
+ */
+void dvmClearCardTable(void);
+
+/*
+ * Returns the address of the relevent byte in the card table, given
+ * an address on the heap.
+ */
+u1 *dvmCardFromAddr(const void *addr);
+
+/*
+ * Returns the first address in the heap which maps to this card.
+ */
+void *dvmAddrFromCard(const u1 *card);
+
+/*
+ * Returns true if addr points to a valid card.
+ */
+bool dvmIsValidCard(const u1 *card);
+
+/*
+ * Set the card associated with the given address to GC_CARD_DIRTY.
+ */
+void dvmMarkCard(const void *addr);
+
+/*
+ * Verifies that all gray objects are on a dirty card.
+ */
+void dvmVerifyCardTable(void);
+
+#endif  // DALVIK_ALLOC_CARDTABLE_H_
diff --git a/vm/alloc/Copying.cpp b/vm/alloc/Copying.cpp
new file mode 100644
index 0000000..6d219ec
--- /dev/null
+++ b/vm/alloc/Copying.cpp
@@ -0,0 +1,2239 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/mman.h>
+
+#include "Dalvik.h"
+#include "alloc/Heap.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/HeapSource.h"
+#include "alloc/Verify.h"
+
+/*
+ * A "mostly copying", generational, garbage collector.
+ *
+ * TODO: we allocate our own contiguous tract of page frames to back
+ * object allocations.  To cooperate with other heaps active in the
+ * virtual machine we need to move the responsibility of allocating
+ * pages someplace outside of this code.
+ *
+ * The other major data structures that maintain the state of the heap
+ * are the block space table and the block queue.
+ *
+ * The block space table records the state of a block.  We must track
+ * whether a block is:
+ *
+ * - Free or allocated in some space.
+ *
+ * - If the block holds part of a large object allocation, whether the
+ *   block is the initial or a continued block of the allocation.
+ *
+ * - Whether the block is pinned, that is to say whether at least one
+ *   object in the block must remain stationary.  Only needed during a
+ *   GC.
+ *
+ * - Which space the object belongs to.  At present this means
+ *   from-space or to-space.
+ *
+ * The block queue is used during garbage collection.  Unlike Cheney's
+ * algorithm, from-space and to-space are not contiguous.  Therefore,
+ * one cannot maintain the state of the copy with just two pointers.
+ * The block queue exists to thread lists of blocks from the various
+ * spaces together.
+ *
+ * Additionally, we record the free space frontier of the heap, as
+ * well as the address of the first object within a block, which is
+ * required to copy objects following a large object (not currently
+ * implemented).  This is stored in the heap source structure.  This
+ * should be moved elsewhere to support in-line allocations from Java
+ * threads.
+ *
+ * Allocation requests are satisfied by reserving storage from one or
+ * more contiguous blocks.  Objects that are small enough to fit
+ * inside a block are packed together within a block.  Objects that
+ * are larger than a block are allocated from contiguous sequences of
+ * blocks.  When half the available blocks are filled, a garbage
+ * collection occurs.  We "flip" spaces (exchange from- and to-space),
+ * copy live objects into to space, and perform pointer adjustment.
+ *
+ * Copying is made more complicated by the requirement that some
+ * objects must not be moved.  This property is known as "pinning".
+ * These objects must be dealt with specially.  We use Bartlett's
+ * scheme; blocks containing such objects are grayed (promoted) at the
+ * start of a garbage collection.  By virtue of this trick, tracing
+ * from the roots proceeds as usual but all objects on those pages are
+ * considered promoted and therefore not moved.
+ *
+ * TODO: there is sufficient information within the garbage collector
+ * to implement Attardi's scheme for evacuating unpinned objects from
+ * a page that is otherwise pinned.  This would eliminate false
+ * retention caused by the large pinning granularity.
+ *
+ * We need a scheme for medium and large objects.  Ignore that for
+ * now, we can return to this later.
+ *
+ * Eventually we need to worry about promoting objects out of the
+ * copy-collected heap (tenuring) into a less volatile space.  Copying
+ * may not always be the best policy for such spaces.  We should
+ * consider a variant of mark, sweep, compact.
+ *
+ * The block scheme allows us to use VM page faults to maintain a
+ * write barrier.  Consider having a special leaf state for a page.
+ *
+ * Bibliography:
+ *
+ * C. J. Cheney. 1970. A non-recursive list compacting
+ * algorithm. CACM. 13-11 pp677--678.
+ *
+ * Joel F. Bartlett. 1988. Compacting Garbage Collection with
+ * Ambiguous Roots. Digital Equipment Corporation.
+ *
+ * Joel F. Bartlett. 1989. Mostly-Copying Garbage Collection Picks Up
+ * Generations and C++. Digital Equipment Corporation.
+ *
+ * G. May Yip. 1991. Incremental, Generational Mostly-Copying Garbage
+ * Collection in Uncooperative Environments. Digital Equipment
+ * Corporation.
+ *
+ * Giuseppe Attardi, Tito Flagella. 1994. A Customisable Memory
+ * Management Framework. TR-94-010
+ *
+ * Giuseppe Attardi, Tito Flagella, Pietro Iglio. 1998. A customisable
+ * memory management framework for C++. Software -- Practice and
+ * Experience. 28(11), 1143-1183.
+ *
+ */
+
+#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#if 0
+#define LOG_ALLOC LOGI
+#define LOG_PIN LOGI
+#define LOG_PROM LOGI
+#define LOG_REF LOGI
+#define LOG_SCAV LOGI
+#define LOG_TRAN LOGI
+#define LOG_VER LOGI
+#else
+#define LOG_ALLOC(...) ((void)0)
+#define LOG_PIN(...) ((void)0)
+#define LOG_PROM(...) ((void)0)
+#define LOG_REF(...) ((void)0)
+#define LOG_SCAV(...) ((void)0)
+#define LOG_TRAN(...) ((void)0)
+#define LOG_VER(...) ((void)0)
+#endif
+
+static void enqueueBlock(HeapSource *heapSource, size_t block);
+static void scavengeReference(Object **obj);
+static bool toSpaceContains(const void *addr);
+static bool fromSpaceContains(const void *addr);
+static size_t sumHeapBitmap(const HeapBitmap *bitmap);
+static size_t objectSize(const Object *obj);
+static void scavengeDataObject(Object *obj);
+static void scavengeBlockQueue();
+
+/*
+ * We use 512-byte blocks.
+ */
+enum { BLOCK_SHIFT = 9 };
+enum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
+
+/*
+ * Space identifiers, stored into the blockSpace array.
+ */
+enum {
+    BLOCK_FREE = 0,
+    BLOCK_FROM_SPACE = 1,
+    BLOCK_TO_SPACE = 2,
+    BLOCK_CONTINUED = 7
+};
+
+/*
+ * Alignment for all allocations, in bytes.
+ */
+enum { ALLOC_ALIGNMENT = 8 };
+
+/*
+ * Sentinel value for the queue end.
+ */
+#define QUEUE_TAIL (~(size_t)0)
+
+struct HeapSource {
+
+    /* The base address of backing store. */
+    u1 *blockBase;
+
+    /* Total number of blocks available for allocation. */
+    size_t totalBlocks;
+    size_t allocBlocks;
+
+    /*
+     * The scavenger work queue.  Implemented as an array of index
+     * values into the queue.
+     */
+    size_t *blockQueue;
+
+    /*
+     * Base and limit blocks.  Basically the shifted start address of
+     * the block.  We convert blocks to a relative number when
+     * indexing in the block queue.  TODO: make the block queue base
+     * relative rather than the index into the block queue.
+     */
+    size_t baseBlock, limitBlock;
+
+    size_t queueHead;
+    size_t queueTail;
+    size_t queueSize;
+
+    /* The space of the current block 0 (free), 1 or 2. */
+    char *blockSpace;
+
+    /* Start of free space in the current block. */
+    u1 *allocPtr;
+    /* Exclusive limit of free space in the current block. */
+    u1 *allocLimit;
+
+    HeapBitmap allocBits;
+
+    /*
+     * The starting size of the heap.  This value is the same as the
+     * value provided to the -Xms flag.
+     */
+    size_t minimumSize;
+
+    /*
+     * The maximum size of the heap.  This value is the same as the
+     * -Xmx flag.
+     */
+    size_t maximumSize;
+
+    /*
+     * The current, committed size of the heap.  At present, this is
+     * equivalent to the maximumSize.
+     */
+    size_t currentSize;
+
+    size_t bytesAllocated;
+};
+
+static unsigned long alignDown(unsigned long x, unsigned long n)
+{
+    return x & -n;
+}
+
+static unsigned long alignUp(unsigned long x, unsigned long n)
+{
+    return alignDown(x + (n - 1), n);
+}
+
+static void describeBlocks(const HeapSource *heapSource)
+{
+    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
+        if ((i % 32) == 0) putchar('\n');
+        printf("%d ", heapSource->blockSpace[i]);
+    }
+    putchar('\n');
+}
+
+/*
+ * Virtual memory interface.
+ */
+
+static void *virtualAlloc(size_t length)
+{
+    int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+    int prot = PROT_READ | PROT_WRITE;
+    void *addr = mmap(NULL, length, prot, flags, -1, 0);
+    if (addr == MAP_FAILED) {
+        LOGE_HEAP("mmap: %s", strerror(errno));
+        addr = NULL;
+    }
+    return addr;
+}
+
+static void virtualFree(void *addr, size_t length)
+{
+    assert(addr != NULL);
+    assert((uintptr_t)addr % SYSTEM_PAGE_SIZE == 0);
+    int res = munmap(addr, length);
+    if (res == -1) {
+        LOGE_HEAP("munmap: %s", strerror(errno));
+    }
+}
+
+#ifndef NDEBUG
+static int isValidAddress(const HeapSource *heapSource, const u1 *addr)
+{
+    size_t block;
+
+    block = (uintptr_t)addr >> BLOCK_SHIFT;
+    return heapSource->baseBlock <= block &&
+           heapSource->limitBlock > block;
+}
+#endif
+
+/*
+ * Iterate over the block map looking for a contiguous run of free
+ * blocks.
+ */
+static void *allocateBlocks(HeapSource *heapSource, size_t blocks)
+{
+    size_t allocBlocks = heapSource->allocBlocks;
+    size_t totalBlocks = heapSource->totalBlocks;
+    /* Check underflow. */
+    assert(blocks != 0);
+    /* Check overflow. */
+    if (allocBlocks + blocks > totalBlocks / 2) {
+        return NULL;
+    }
+    /* Scan block map. */
+    for (size_t i = 0; i < totalBlocks; ++i) {
+        /* Check fit. */
+        for (size_t j = 0; j < blocks; ++j) { /* runs over totalBlocks */
+            if (heapSource->blockSpace[i+j] != BLOCK_FREE) {
+                break;
+            }
+        }
+        /* No fit? */
+        if (j != blocks) {
+            i += j;
+            continue;
+        }
+        /* Fit, allocate. */
+        heapSource->blockSpace[i] = BLOCK_TO_SPACE; /* why to-space? */
+        for (size_t j = 1; j < blocks; ++j) {
+            heapSource->blockSpace[i+j] = BLOCK_CONTINUED;
+        }
+        heapSource->allocBlocks += blocks;
+        void *addr = &heapSource->blockBase[i*BLOCK_SIZE];
+        memset(addr, 0, blocks*BLOCK_SIZE);
+        /* Collecting? */
+        if (heapSource->queueHead != QUEUE_TAIL) {
+            LOG_ALLOC("allocateBlocks allocBlocks=%zu,block#=%zu", heapSource->allocBlocks, i);
+            /*
+             * This allocated was on behalf of the transporter when it
+             * shaded a white object gray.  We enqueue the block so
+             * the scavenger can further shade the gray objects black.
+             */
+            enqueueBlock(heapSource, i);
+        }
+
+        return addr;
+    }
+    /* Insufficient space, fail. */
+    LOGE("Insufficient space, %zu blocks, %zu blocks allocated and %zu bytes allocated",
+         heapSource->totalBlocks,
+         heapSource->allocBlocks,
+         heapSource->bytesAllocated);
+    return NULL;
+}
+
+/* Converts an absolute address to a relative block number. */
+static size_t addressToBlock(const HeapSource *heapSource, const void *addr)
+{
+    assert(heapSource != NULL);
+    assert(isValidAddress(heapSource, addr));
+    return (((uintptr_t)addr) >> BLOCK_SHIFT) - heapSource->baseBlock;
+}
+
+/* Converts a relative block number to an absolute address. */
+static u1 *blockToAddress(const HeapSource *heapSource, size_t block)
+{
+    u1 *addr;
+
+    addr = (u1 *) (((uintptr_t) heapSource->baseBlock + block) * BLOCK_SIZE);
+    assert(isValidAddress(heapSource, addr));
+    return addr;
+}
+
+static void clearBlock(HeapSource *heapSource, size_t block)
+{
+    assert(heapSource != NULL);
+    assert(block < heapSource->totalBlocks);
+    u1 *addr = heapSource->blockBase + block*BLOCK_SIZE;
+    memset(addr, 0xCC, BLOCK_SIZE);
+    for (size_t i = 0; i < BLOCK_SIZE; i += 8) {
+        dvmHeapBitmapClearObjectBit(&heapSource->allocBits, addr + i);
+    }
+}
+
+static void clearFromSpace(HeapSource *heapSource)
+{
+    assert(heapSource != NULL);
+    size_t i = 0;
+    size_t count = 0;
+    while (i < heapSource->totalBlocks) {
+        if (heapSource->blockSpace[i] != BLOCK_FROM_SPACE) {
+            ++i;
+            continue;
+        }
+        heapSource->blockSpace[i] = BLOCK_FREE;
+        clearBlock(heapSource, i);
+        ++i;
+        ++count;
+        while (i < heapSource->totalBlocks &&
+               heapSource->blockSpace[i] == BLOCK_CONTINUED) {
+            heapSource->blockSpace[i] = BLOCK_FREE;
+            clearBlock(heapSource, i);
+            ++i;
+            ++count;
+        }
+    }
+    LOG_SCAV("freed %zu blocks (%zu bytes)", count, count*BLOCK_SIZE);
+}
+
+/*
+ * Appends the given block to the block queue.  The block queue is
+ * processed in-order by the scavenger.
+ */
+static void enqueueBlock(HeapSource *heapSource, size_t block)
+{
+    assert(heapSource != NULL);
+    assert(block < heapSource->totalBlocks);
+    if (heapSource->queueHead != QUEUE_TAIL) {
+        heapSource->blockQueue[heapSource->queueTail] = block;
+    } else {
+        heapSource->queueHead = block;
+    }
+    heapSource->blockQueue[block] = QUEUE_TAIL;
+    heapSource->queueTail = block;
+    ++heapSource->queueSize;
+}
+
+/*
+ * Grays all objects within the block corresponding to the given
+ * address.
+ */
+static void promoteBlockByAddr(HeapSource *heapSource, const void *addr)
+{
+    size_t block;
+
+    block = addressToBlock(heapSource, (const u1 *)addr);
+    if (heapSource->blockSpace[block] != BLOCK_TO_SPACE) {
+        // LOG_PROM("promoting block %zu %d @ %p", block, heapSource->blockSpace[block], obj);
+        heapSource->blockSpace[block] = BLOCK_TO_SPACE;
+        enqueueBlock(heapSource, block);
+        /* TODO(cshapiro): count continued blocks?*/
+        heapSource->allocBlocks += 1;
+    } else {
+        // LOG_PROM("NOT promoting block %zu %d @ %p", block, heapSource->blockSpace[block], obj);
+    }
+}
+
+GcHeap *dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
+{
+    GcHeap* gcHeap;
+    HeapSource *heapSource;
+
+    assert(startSize <= absoluteMaxSize);
+
+    heapSource = malloc(sizeof(*heapSource));
+    assert(heapSource != NULL);
+    memset(heapSource, 0, sizeof(*heapSource));
+
+    heapSource->minimumSize = alignUp(startSize, BLOCK_SIZE);
+    heapSource->maximumSize = alignUp(absoluteMaxSize, BLOCK_SIZE);
+
+    heapSource->currentSize = heapSource->maximumSize;
+
+    /* Allocate underlying storage for blocks. */
+    heapSource->blockBase = virtualAlloc(heapSource->maximumSize);
+    assert(heapSource->blockBase != NULL);
+    heapSource->baseBlock = (uintptr_t) heapSource->blockBase >> BLOCK_SHIFT;
+    heapSource->limitBlock = ((uintptr_t) heapSource->blockBase + heapSource->maximumSize) >> BLOCK_SHIFT;
+
+    heapSource->allocBlocks = 0;
+    heapSource->totalBlocks = (heapSource->limitBlock - heapSource->baseBlock);
+
+    assert(heapSource->totalBlocks = heapSource->maximumSize / BLOCK_SIZE);
+
+    {
+        size_t size = sizeof(heapSource->blockQueue[0]);
+        heapSource->blockQueue = malloc(heapSource->totalBlocks*size);
+        assert(heapSource->blockQueue != NULL);
+        memset(heapSource->blockQueue, 0xCC, heapSource->totalBlocks*size);
+        heapSource->queueHead = QUEUE_TAIL;
+    }
+
+    /* Byte indicating space residence or free status of block. */
+    {
+        size_t size = sizeof(heapSource->blockSpace[0]);
+        heapSource->blockSpace = malloc(heapSource->totalBlocks*size);
+        assert(heapSource->blockSpace != NULL);
+        memset(heapSource->blockSpace, 0, heapSource->totalBlocks*size);
+    }
+
+    dvmHeapBitmapInit(&heapSource->allocBits,
+                      heapSource->blockBase,
+                      heapSource->maximumSize,
+                      "blockBase");
+
+    /* Initialize allocation pointers. */
+    heapSource->allocPtr = allocateBlocks(heapSource, 1);
+    heapSource->allocLimit = heapSource->allocPtr + BLOCK_SIZE;
+
+    gcHeap = malloc(sizeof(*gcHeap));
+    assert(gcHeap != NULL);
+    memset(gcHeap, 0, sizeof(*gcHeap));
+    gcHeap->heapSource = heapSource;
+
+    return gcHeap;
+}
+
+/*
+ * Perform any required heap initializations after forking from the
+ * zygote process.  This is a no-op for the time being.  Eventually
+ * this will demarcate the shared region of the heap.
+ */
+bool dvmHeapSourceStartupAfterZygote()
+{
+    return true;
+}
+
+bool dvmHeapSourceStartupBeforeFork()
+{
+    assert(!"implemented");
+    return false;
+}
+
+void dvmHeapSourceShutdown(GcHeap **gcHeap)
+{
+    if (*gcHeap == NULL || (*gcHeap)->heapSource == NULL)
+        return;
+    free((*gcHeap)->heapSource->blockQueue);
+    free((*gcHeap)->heapSource->blockSpace);
+    virtualFree((*gcHeap)->heapSource->blockBase,
+                (*gcHeap)->heapSource->maximumSize);
+    free((*gcHeap)->heapSource);
+    (*gcHeap)->heapSource = NULL;
+    free(*gcHeap);
+    *gcHeap = NULL;
+}
+
+size_t dvmHeapSourceGetValue(HeapSourceValueSpec spec,
+                             size_t perHeapStats[],
+                             size_t arrayLen)
+{
+    HeapSource *heapSource;
+    size_t value;
+
+    heapSource = gDvm.gcHeap->heapSource;
+    switch (spec) {
+    case HS_FOOTPRINT:
+        value = heapSource->maximumSize;
+        break;
+    case HS_ALLOWED_FOOTPRINT:
+        value = heapSource->maximumSize;
+        break;
+    case HS_BYTES_ALLOCATED:
+        value = heapSource->bytesAllocated;
+        break;
+    case HS_OBJECTS_ALLOCATED:
+        value = sumHeapBitmap(&heapSource->allocBits);
+        break;
+    default:
+        assert(!"implemented");
+        value = 0;
+    }
+    if (perHeapStats) {
+        *perHeapStats = value;
+    }
+    return value;
+}
+
+/*
+ * Performs a shallow copy of the allocation bitmap into the given
+ * vector of heap bitmaps.
+ */
+void dvmHeapSourceGetObjectBitmaps(HeapBitmap objBits[], HeapBitmap markBits[],
+                                   size_t numHeaps)
+{
+    assert(!"implemented");
+}
+
+HeapBitmap *dvmHeapSourceGetLiveBits()
+{
+    return &gDvm.gcHeap->heapSource->allocBits;
+}
+
+/*
+ * Allocate the specified number of bytes from the heap.  The
+ * allocation cursor points into a block of free storage.  If the
+ * given allocation fits in the remaining space of the block, we
+ * advance the cursor and return a pointer to the free storage.  If
+ * the allocation cannot fit in the current block but is smaller than
+ * a block we request a new block and allocate from it instead.  If
+ * the allocation is larger than a block we must allocate from a span
+ * of contiguous blocks.
+ */
+void *dvmHeapSourceAlloc(size_t length)
+{
+    HeapSource *heapSource;
+    unsigned char *addr;
+    size_t aligned, available, blocks;
+
+    heapSource = gDvm.gcHeap->heapSource;
+    assert(heapSource != NULL);
+    assert(heapSource->allocPtr != NULL);
+    assert(heapSource->allocLimit != NULL);
+
+    aligned = alignUp(length, ALLOC_ALIGNMENT);
+    available = heapSource->allocLimit - heapSource->allocPtr;
+
+    /* Try allocating inside the current block. */
+    if (aligned <= available) {
+        addr = heapSource->allocPtr;
+        heapSource->allocPtr += aligned;
+        heapSource->bytesAllocated += aligned;
+        dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
+        return addr;
+    }
+
+    /* Try allocating in a new block. */
+    if (aligned <= BLOCK_SIZE) {
+        addr =  allocateBlocks(heapSource, 1);
+        if (addr != NULL) {
+            heapSource->allocLimit = addr + BLOCK_SIZE;
+            heapSource->allocPtr = addr + aligned;
+            heapSource->bytesAllocated += aligned;
+            dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
+            /* TODO(cshapiro): pad out the current block. */
+        }
+        return addr;
+    }
+
+    /* Try allocating in a span of blocks. */
+    blocks = alignUp(aligned, BLOCK_SIZE) / BLOCK_SIZE;
+
+    addr = allocateBlocks(heapSource, blocks);
+    /* Propagate failure upward. */
+    if (addr != NULL) {
+        heapSource->bytesAllocated += aligned;
+        dvmHeapBitmapSetObjectBit(&heapSource->allocBits, addr);
+        /* TODO(cshapiro): pad out free space in the last block. */
+    }
+    return addr;
+}
+
+void *dvmHeapSourceAllocAndGrow(size_t size)
+{
+    return dvmHeapSourceAlloc(size);
+}
+
+/* TODO: refactor along with dvmHeapSourceAlloc */
+void *allocateGray(size_t size)
+{
+    HeapSource *heapSource;
+    void *addr;
+    size_t block;
+
+    /* TODO: add a check that we are in a GC. */
+    heapSource = gDvm.gcHeap->heapSource;
+    addr = dvmHeapSourceAlloc(size);
+    assert(addr != NULL);
+    block = addressToBlock(heapSource, (const u1 *)addr);
+    if (heapSource->queueHead == QUEUE_TAIL) {
+        /*
+         * Forcibly append the underlying block to the queue.  This
+         * condition occurs when referents are transported following
+         * the initial trace.
+         */
+        enqueueBlock(heapSource, block);
+        LOG_PROM("forced promoting block %zu %d @ %p", block, heapSource->blockSpace[block], addr);
+    }
+    return addr;
+}
+
+bool dvmHeapSourceContainsAddress(const void *ptr)
+{
+    HeapSource *heapSource = gDvm.gcHeap->heapSource;
+    return dvmHeapBitmapCoversAddress(&heapSource->allocBits, ptr);
+}
+
+/*
+ * Returns true if the given address is within the heap and points to
+ * the header of a live object.
+ */
+bool dvmHeapSourceContains(const void *addr)
+{
+    HeapSource *heapSource;
+    HeapBitmap *bitmap;
+
+    heapSource = gDvm.gcHeap->heapSource;
+    bitmap = &heapSource->allocBits;
+    if (!dvmHeapBitmapCoversAddress(bitmap, addr)) {
+        return false;
+    } else {
+        return dvmHeapBitmapIsObjectBitSet(bitmap, addr);
+    }
+}
+
+bool dvmHeapSourceGetPtrFlag(const void *ptr, HeapSourcePtrFlag flag)
+{
+    assert(!"implemented");
+    return false;
+}
+
+size_t dvmHeapSourceChunkSize(const void *ptr)
+{
+    assert(!"implemented");
+    return 0;
+}
+
+size_t dvmHeapSourceFootprint()
+{
+    assert(!"implemented");
+    return 0;
+}
+
+/*
+ * Returns the "ideal footprint" which appears to be the number of
+ * bytes currently committed to the heap.  This starts out at the
+ * start size of the heap and grows toward the maximum size.
+ */
+size_t dvmHeapSourceGetIdealFootprint()
+{
+    return gDvm.gcHeap->heapSource->currentSize;
+}
+
+float dvmGetTargetHeapUtilization()
+{
+    return 0.5f;
+}
+
+void dvmSetTargetHeapUtilization(float newTarget)
+{
+    assert(newTarget > 0.0f && newTarget < 1.0f);
+}
+
+/*
+ * Expands the size of the heap after a collection.  At present we
+ * commit the pages for maximum size of the heap so this routine is
+ * just a no-op.  Eventually, we will either allocate or commit pages
+ * on an as-need basis.
+ */
+void dvmHeapSourceGrowForUtilization()
+{
+    /* do nothing */
+}
+
+void dvmHeapSourceWalk(void (*callback)(const void *chunkptr, size_t chunklen,
+                                        const void *userptr, size_t userlen,
+                                        void *arg),
+                       void *arg)
+{
+    assert(!"implemented");
+}
+
+size_t dvmHeapSourceGetNumHeaps()
+{
+    return 1;
+}
+
+bool dvmTrackExternalAllocation(size_t n)
+{
+    /* do nothing */
+    return true;
+}
+
+void dvmTrackExternalFree(size_t n)
+{
+    /* do nothing */
+}
+
+size_t dvmGetExternalBytesAllocated()
+{
+    assert(!"implemented");
+    return 0;
+}
+
+void dvmHeapSourceFlip()
+{
+    HeapSource *heapSource = gDvm.gcHeap->heapSource;
+
+    /* Reset the block queue. */
+    heapSource->allocBlocks = 0;
+    heapSource->queueSize = 0;
+    heapSource->queueHead = QUEUE_TAIL;
+
+    /* TODO(cshapiro): pad the current (prev) block. */
+
+    heapSource->allocPtr = NULL;
+    heapSource->allocLimit = NULL;
+
+    /* Whiten all allocated blocks. */
+    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
+        if (heapSource->blockSpace[i] == BLOCK_TO_SPACE) {
+            heapSource->blockSpace[i] = BLOCK_FROM_SPACE;
+        }
+    }
+}
+
+static void room(size_t *alloc, size_t *avail, size_t *total)
+{
+    HeapSource *heapSource = gDvm.gcHeap->heapSource;
+    *total = heapSource->totalBlocks*BLOCK_SIZE;
+    *alloc = heapSource->allocBlocks*BLOCK_SIZE;
+    *avail = *total - *alloc;
+}
+
+static bool isSpaceInternal(u1 *addr, int space)
+{
+    HeapSource *heapSource;
+    u1 *base, *limit;
+    size_t offset;
+    char space2;
+
+    heapSource = gDvm.gcHeap->heapSource;
+    base = heapSource->blockBase;
+    assert(addr >= base);
+    limit = heapSource->blockBase + heapSource->maximumSize;
+    assert(addr < limit);
+    offset = addr - base;
+    space2 = heapSource->blockSpace[offset >> BLOCK_SHIFT];
+    return space == space2;
+}
+
+static bool fromSpaceContains(const void *addr)
+{
+    return isSpaceInternal((u1 *)addr, BLOCK_FROM_SPACE);
+}
+
+static bool toSpaceContains(const void *addr)
+{
+    return isSpaceInternal((u1 *)addr, BLOCK_TO_SPACE);
+}
+
+/*
+ * Notifies the collector that the object at the given address must
+ * remain stationary during the current collection.
+ */
+static void pinObject(const Object *obj)
+{
+    promoteBlockByAddr(gDvm.gcHeap->heapSource, obj);
+}
+
+static size_t sumHeapBitmap(const HeapBitmap *bitmap)
+{
+    size_t sum = 0;
+    for (size_t i = 0; i < bitmap->bitsLen >> 2; ++i) {
+        sum += CLZ(bitmap->bits[i]);
+    }
+    return sum;
+}
+
+/*
+ * Miscellaneous functionality.
+ */
+
+static int isForward(const void *addr)
+{
+    return (uintptr_t)addr & 0x1;
+}
+
+static void setForward(const void *toObj, void *fromObj)
+{
+    *(unsigned long *)fromObj = (uintptr_t)toObj | 0x1;
+}
+
+static void* getForward(const void *fromObj)
+{
+    return (void *)((uintptr_t)fromObj & ~0x1);
+}
+
+/* Beware, uses the same encoding as a forwarding pointers! */
+static int isPermanentString(const StringObject *obj) {
+    return (uintptr_t)obj & 0x1;
+}
+
+static void* getPermanentString(const StringObject *obj)
+{
+    return (void *)((uintptr_t)obj & ~0x1);
+}
+
+
+/*
+ * Scavenging and transporting routines follow.  A transporter grays
+ * an object.  A scavenger blackens an object.  We define these
+ * routines for each fundamental object type.  Dispatch is performed
+ * in scavengeObject.
+ */
+
+/*
+ * Class object scavenging.
+ */
+static void scavengeClassObject(ClassObject *obj)
+{
+    LOG_SCAV("scavengeClassObject(obj=%p)", obj);
+    assert(obj != NULL);
+    assert(obj->obj.clazz != NULL);
+    assert(obj->obj.clazz->descriptor != NULL);
+    assert(!strcmp(obj->obj.clazz->descriptor, "Ljava/lang/Class;"));
+    assert(obj->descriptor != NULL);
+    LOG_SCAV("scavengeClassObject: descriptor='%s',vtableCount=%zu",
+             obj->descriptor, obj->vtableCount);
+    /* Delegate class object and instance field scavenging. */
+    scavengeDataObject((Object *)obj);
+    /* Scavenge the array element class object. */
+    if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) {
+        scavengeReference((Object **)(void *)&obj->elementClass);
+    }
+    /* Scavenge the superclass. */
+    scavengeReference((Object **)(void *)&obj->super);
+    /* Scavenge the class loader. */
+    scavengeReference(&obj->classLoader);
+    /* Scavenge static fields. */
+    for (int i = 0; i < obj->sfieldCount; ++i) {
+        char ch = obj->sfields[i].field.signature[0];
+        if (ch == '[' || ch == 'L') {
+            scavengeReference((Object **)(void *)&obj->sfields[i].value.l);
+        }
+    }
+    /* Scavenge interface class objects. */
+    for (int i = 0; i < obj->interfaceCount; ++i) {
+        scavengeReference((Object **) &obj->interfaces[i]);
+    }
+}
+
+/*
+ * Array object scavenging.
+ */
+static size_t scavengeArrayObject(ArrayObject *array)
+{
+    LOG_SCAV("scavengeArrayObject(array=%p)", array);
+    /* Scavenge the class object. */
+    assert(toSpaceContains(array));
+    assert(array != NULL);
+    assert(array->obj.clazz != NULL);
+    scavengeReference((Object **) array);
+    size_t length = dvmArrayObjectSize(array);
+    /* Scavenge the array contents. */
+    if (IS_CLASS_FLAG_SET(array->obj.clazz, CLASS_ISOBJECTARRAY)) {
+        Object **contents = (Object **)array->contents;
+        for (size_t i = 0; i < array->length; ++i) {
+            scavengeReference(&contents[i]);
+        }
+    }
+    return length;
+}
+
+/*
+ * Reference object scavenging.
+ */
+
+static int getReferenceFlags(const Object *obj)
+{
+    int flags;
+
+    flags = CLASS_ISREFERENCE |
+            CLASS_ISWEAKREFERENCE |
+            CLASS_ISPHANTOMREFERENCE;
+    return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
+}
+
+static int isSoftReference(const Object *obj)
+{
+    return getReferenceFlags(obj) == CLASS_ISREFERENCE;
+}
+
+static int isWeakReference(const Object *obj)
+{
+    return getReferenceFlags(obj) & CLASS_ISWEAKREFERENCE;
+}
+
+#ifndef NDEBUG
+static bool isPhantomReference(const Object *obj)
+{
+    return getReferenceFlags(obj) & CLASS_ISPHANTOMREFERENCE;
+}
+#endif
+
+/*
+ * Returns true if the reference was registered with a reference queue
+ * but has not yet been appended to it.
+ */
+static bool isReferenceEnqueuable(const Object *ref)
+{
+    Object *queue, *queueNext;
+
+    queue = dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue);
+    queueNext = dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext);
+    if (queue == NULL || queueNext != NULL) {
+        /*
+         * There is no queue, or the reference has already
+         * been enqueued.  The Reference.enqueue() method
+         * will do nothing even if we call it.
+         */
+        return false;
+    }
+
+    /*
+     * We need to call enqueue(), but if we called it from
+     * here we'd probably deadlock.  Schedule a call.
+     */
+    return true;
+}
+
+/*
+ * Schedules a reference to be appended to its reference queue.
+ */
+static void enqueueReference(Object *ref)
+{
+    assert(ref != NULL);
+    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
+    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
+    if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
+        LOGE("no room for any more reference operations");
+        dvmAbort();
+    }
+}
+
+/*
+ * Sets the referent field of a reference object to NULL.
+ */
+static void clearReference(Object *obj)
+{
+    dvmSetFieldObject(obj, gDvm.offJavaLangRefReference_referent, NULL);
+}
+
+/*
+ * Clears reference objects with white referents.
+ */
+void clearWhiteReferences(Object **list)
+{
+    size_t referentOffset, queueNextOffset;
+    bool doSignal;
+
+    queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
+    referentOffset = gDvm.offJavaLangRefReference_referent;
+    doSignal = false;
+    while (*list != NULL) {
+        Object *ref = *list;
+        JValue *field = dvmFieldPtr(ref, referentOffset);
+        Object *referent = field->l;
+        *list = dvmGetFieldObject(ref, queueNextOffset);
+        dvmSetFieldObject(ref, queueNextOffset, NULL);
+        assert(referent != NULL);
+        if (isForward(referent->clazz)) {
+            field->l = referent = getForward(referent->clazz);
+            continue;
+        }
+        if (fromSpaceContains(referent)) {
+            /* Referent is white, clear it. */
+            clearReference(ref);
+            if (isReferenceEnqueuable(ref)) {
+                enqueueReference(ref);
+                doSignal = true;
+            }
+        }
+    }
+    /*
+     * If we cleared a reference with a reference queue we must notify
+     * the heap worker to append the reference.
+     */
+    if (doSignal) {
+        dvmSignalHeapWorker(false);
+    }
+    assert(*list == NULL);
+}
+
+/*
+ * Blackens referents subject to the soft reference preservation
+ * policy.
+ */
+void preserveSoftReferences(Object **list)
+{
+    Object *ref;
+    Object *prev, *next;
+    size_t referentOffset, queueNextOffset;
+    unsigned counter;
+    bool white;
+
+    queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
+    referentOffset = gDvm.offJavaLangRefReference_referent;
+    counter = 0;
+    prev = next = NULL;
+    ref = *list;
+    while (ref != NULL) {
+        JValue *field = dvmFieldPtr(ref, referentOffset);
+        Object *referent = field->l;
+        next = dvmGetFieldObject(ref, queueNextOffset);
+        assert(referent != NULL);
+        if (isForward(referent->clazz)) {
+            /* Referent is black. */
+            field->l = referent = getForward(referent->clazz);
+            white = false;
+        } else {
+            white = fromSpaceContains(referent);
+        }
+        if (!white && ((++counter) & 1)) {
+            /* Referent is white and biased toward saving, gray it. */
+            scavengeReference((Object **)(void *)&field->l);
+            white = true;
+        }
+        if (white) {
+            /* Referent is black, unlink it. */
+            if (prev != NULL) {
+                dvmSetFieldObject(ref, queueNextOffset, NULL);
+                dvmSetFieldObject(prev, queueNextOffset, next);
+            }
+        } else {
+            /* Referent is white, skip over it. */
+            prev = ref;
+        }
+        ref = next;
+    }
+    /*
+     * Restart the trace with the newly gray references added to the
+     * root set.
+     */
+    scavengeBlockQueue();
+}
+
+void processFinalizableReferences()
+{
+    HeapRefTable newPendingRefs;
+    LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs;
+    Object **ref;
+    Object **lastRef;
+    size_t totalPendCount;
+
+    /*
+     * All strongly, reachable objects are black.
+     * Any white finalizable objects need to be finalized.
+     */
+
+    /* Create a table that the new pending refs will
+     * be added to.
+     */
+    if (!dvmHeapInitHeapRefTable(&newPendingRefs)) {
+        //TODO: mark all finalizable refs and hope that
+        //      we can schedule them next time.  Watch out,
+        //      because we may be expecting to free up space
+        //      by calling finalizers.
+        LOG_REF("no room for pending finalizations");
+        dvmAbort();
+    }
+
+    /*
+     * Walk through finalizableRefs and move any white references to
+     * the list of new pending refs.
+     */
+    totalPendCount = 0;
+    while (finRefs != NULL) {
+        Object **gapRef;
+        size_t newPendCount = 0;
+
+        gapRef = ref = finRefs->refs.table;
+        lastRef = finRefs->refs.nextEntry;
+        while (ref < lastRef) {
+            if (fromSpaceContains(*ref)) {
+                if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) {
+                    //TODO: add the current table and allocate
+                    //      a new, smaller one.
+                    LOG_REF("no room for any more pending finalizations: %zd",
+                            dvmHeapNumHeapRefTableEntries(&newPendingRefs));
+                    dvmAbort();
+                }
+                newPendCount++;
+            } else {
+                /* This ref is black, so will remain on finalizableRefs.
+                 */
+                if (newPendCount > 0) {
+                    /* Copy it up to fill the holes.
+                     */
+                    *gapRef++ = *ref;
+                } else {
+                    /* No holes yet; don't bother copying.
+                     */
+                    gapRef++;
+                }
+            }
+            ref++;
+        }
+        finRefs->refs.nextEntry = gapRef;
+        //TODO: if the table is empty when we're done, free it.
+        totalPendCount += newPendCount;
+        finRefs = finRefs->next;
+    }
+    LOG_REF("%zd finalizers triggered.", totalPendCount);
+    if (totalPendCount == 0) {
+        /* No objects required finalization.
+         * Free the empty temporary table.
+         */
+        dvmClearReferenceTable(&newPendingRefs);
+        return;
+    }
+
+    /* Add the new pending refs to the main list.
+     */
+    if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs,
+                &newPendingRefs))
+    {
+        LOG_REF("can't insert new pending finalizations");
+        dvmAbort();
+    }
+
+    //TODO: try compacting the main list with a memcpy loop
+
+    /* Blacken the refs we just moved; we don't want them or their
+     * children to get swept yet.
+     */
+    ref = newPendingRefs.table;
+    lastRef = newPendingRefs.nextEntry;
+    assert(ref < lastRef);
+    HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
+    while (ref < lastRef) {
+        scavengeReference(ref);
+        ref++;
+    }
+    HPROF_CLEAR_GC_SCAN_STATE();
+    scavengeBlockQueue();
+    dvmSignalHeapWorker(false);
+}
+
+/*
+ * If a reference points to from-space and has been forwarded, we snap
+ * the pointer to its new to-space address.  If the reference points
+ * to an unforwarded from-space address we must enqueue the reference
+ * for later processing.  TODO: implement proper reference processing
+ * and move the referent scavenging elsewhere.
+ */
+static void scavengeReferenceObject(Object *obj)
+{
+    Object *referent;
+    Object **queue;
+    size_t referentOffset, queueNextOffset;
+
+    assert(obj != NULL);
+    LOG_SCAV("scavengeReferenceObject(obj=%p),'%s'", obj, obj->clazz->descriptor);
+    scavengeDataObject(obj);
+    referentOffset = gDvm.offJavaLangRefReference_referent;
+    referent = dvmGetFieldObject(obj, referentOffset);
+    if (referent == NULL || toSpaceContains(referent)) {
+        return;
+    }
+    if (isSoftReference(obj)) {
+        queue = &gDvm.gcHeap->softReferences;
+    } else if (isWeakReference(obj)) {
+        queue = &gDvm.gcHeap->weakReferences;
+    } else {
+        assert(isPhantomReference(obj));
+        queue = &gDvm.gcHeap->phantomReferences;
+    }
+    queueNextOffset = gDvm.offJavaLangRefReference_queueNext;
+    dvmSetFieldObject(obj, queueNextOffset, *queue);
+    *queue = obj;
+    LOG_SCAV("scavengeReferenceObject: enqueueing %p", obj);
+}
+
+/*
+ * Data object scavenging.
+ */
+static void scavengeDataObject(Object *obj)
+{
+    // LOG_SCAV("scavengeDataObject(obj=%p)", obj);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(obj->clazz->objectSize != 0);
+    assert(toSpaceContains(obj));
+    /* Scavenge the class object. */
+    ClassObject *clazz = obj->clazz;
+    scavengeReference((Object **) obj);
+    /* Scavenge instance fields. */
+    if (clazz->refOffsets != CLASS_WALK_SUPER) {
+        size_t refOffsets = clazz->refOffsets;
+        while (refOffsets != 0) {
+            size_t rshift = CLZ(refOffsets);
+            size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
+            Object **ref = (Object **)((u1 *)obj + offset);
+            scavengeReference(ref);
+            refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
+        }
+    } else {
+        for (; clazz != NULL; clazz = clazz->super) {
+            InstField *field = clazz->ifields;
+            for (int i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
+                size_t offset = field->byteOffset;
+                Object **ref = (Object **)((u1 *)obj + offset);
+                scavengeReference(ref);
+            }
+        }
+    }
+}
+
+static Object *transportObject(const Object *fromObj)
+{
+    Object *toObj;
+    size_t allocSize, copySize;
+
+    LOG_TRAN("transportObject(fromObj=%p) allocBlocks=%zu",
+                  fromObj,
+                  gDvm.gcHeap->heapSource->allocBlocks);
+    assert(fromObj != NULL);
+    assert(fromSpaceContains(fromObj));
+    allocSize = copySize = objectSize(fromObj);
+    if (LW_HASH_STATE(fromObj->lock) != LW_HASH_STATE_UNHASHED) {
+        /*
+         * The object has been hashed or hashed and moved.  We must
+         * reserve an additional word for a hash code.
+         */
+        allocSize += sizeof(u4);
+    }
+    if (LW_HASH_STATE(fromObj->lock) == LW_HASH_STATE_HASHED_AND_MOVED) {
+        /*
+         * The object has its hash code allocated.  Ensure the hash
+         * code is copied along with the instance data.
+         */
+        copySize += sizeof(u4);
+    }
+    /* TODO(cshapiro): don't copy, re-map large data objects. */
+    assert(copySize <= allocSize);
+    toObj = allocateGray(allocSize);
+    assert(toObj != NULL);
+    assert(toSpaceContains(toObj));
+    memcpy(toObj, fromObj, copySize);
+    if (LW_HASH_STATE(fromObj->lock) == LW_HASH_STATE_HASHED) {
+        /*
+         * The object has had its hash code exposed.  Append it to the
+         * instance and set a bit so we know to look for it there.
+         */
+        *(u4 *)(((char *)toObj) + copySize) = (u4)fromObj >> 3;
+        toObj->lock |= LW_HASH_STATE_HASHED_AND_MOVED << LW_HASH_STATE_SHIFT;
+    }
+    LOG_TRAN("transportObject: from %p/%zu to %p/%zu (%zu,%zu) %s",
+             fromObj, addressToBlock(gDvm.gcHeap->heapSource,fromObj),
+             toObj, addressToBlock(gDvm.gcHeap->heapSource,toObj),
+             copySize, allocSize, copySize < allocSize ? "DIFFERENT" : "");
+    return toObj;
+}
+
+/*
+ * Generic reference scavenging.
+ */
+
+/*
+ * Given a reference to an object, the scavenge routine will gray the
+ * reference.  Any objects pointed to by the scavenger object will be
+ * transported to new space and a forwarding pointer will be installed
+ * in the header of the object.
+ */
+
+/*
+ * Blacken the given pointer.  If the pointer is in from space, it is
+ * transported to new space.  If the object has a forwarding pointer
+ * installed it has already been transported and the referent is
+ * snapped to the new address.
+ */
+static void scavengeReference(Object **obj)
+{
+    ClassObject *clazz;
+    Object *fromObj, *toObj;
+
+    assert(obj);
+
+    if (*obj == NULL) return;
+
+    assert(dvmIsValidObject(*obj));
+
+    /* The entire block is black. */
+    if (toSpaceContains(*obj)) {
+        LOG_SCAV("scavengeReference skipping pinned object @ %p", *obj);
+        return;
+    }
+    LOG_SCAV("scavengeReference(*obj=%p)", *obj);
+
+    assert(fromSpaceContains(*obj));
+
+    clazz = (*obj)->clazz;
+
+    if (isForward(clazz)) {
+        // LOG_SCAV("forwarding %p @ %p to %p", *obj, obj, (void *)((uintptr_t)clazz & ~0x1));
+        *obj = (Object *)getForward(clazz);
+        return;
+    }
+    fromObj = *obj;
+    if (clazz == NULL) {
+        // LOG_SCAV("scavangeReference %p has a NULL class object", fromObj);
+        assert(!"implemented");
+        toObj = NULL;
+    } else {
+        toObj = transportObject(fromObj);
+    }
+    setForward(toObj, fromObj);
+    *obj = (Object *)toObj;
+}
+
+/*
+ * Generic object scavenging.
+ */
+static void scavengeObject(Object *obj)
+{
+    ClassObject *clazz;
+
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(!((uintptr_t)obj->clazz & 0x1));
+    clazz = obj->clazz;
+    if (dvmIsTheClassClass(clazz)) {
+        scavengeClassObject((ClassObject *)obj);
+    } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
+        scavengeArrayObject((ArrayObject *)obj);
+    } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISREFERENCE)) {
+        scavengeReferenceObject(obj);
+    } else {
+        scavengeDataObject(obj);
+    }
+}
+
+/*
+ * External root scavenging routines.
+ */
+
+static void pinHashTableEntries(HashTable *table)
+{
+    LOG_PIN(">>> pinHashTableEntries(table=%p)", table);
+    if (table == NULL) {
+        return;
+    }
+    dvmHashTableLock(table);
+    for (int i = 0; i < table->tableSize; ++i) {
+        HashEntry *entry = &table->pEntries[i];
+        void *obj = entry->data;
+        if (obj == NULL || obj == HASH_TOMBSTONE) {
+            continue;
+        }
+        pinObject(entry->data);
+    }
+    dvmHashTableUnlock(table);
+    LOG_PIN("<<< pinHashTableEntries(table=%p)", table);
+}
+
+static void pinPrimitiveClasses()
+{
+    size_t length = ARRAYSIZE(gDvm.primitiveClass);
+    for (size_t i = 0; i < length; i++) {
+        if (gDvm.primitiveClass[i] != NULL) {
+            pinObject((Object *)gDvm.primitiveClass[i]);
+        }
+    }
+}
+
+/*
+ * Scavenge interned strings.  Permanent interned strings will have
+ * been pinned and are therefore ignored.  Non-permanent strings that
+ * have been forwarded are snapped.  All other entries are removed.
+ */
+static void scavengeInternedStrings()
+{
+    HashTable *table = gDvm.internedStrings;
+    if (table == NULL) {
+        return;
+    }
+    dvmHashTableLock(table);
+    for (int i = 0; i < table->tableSize; ++i) {
+        HashEntry *entry = &table->pEntries[i];
+        Object *obj = (Object *)entry->data;
+        if (obj == NULL || obj == HASH_TOMBSTONE) {
+            continue;
+        } else if (!isPermanentString((StringObject *)obj)) {
+            // LOG_SCAV("entry->data=%p", entry->data);
+            LOG_SCAV(">>> string obj=%p", entry->data);
+            /* TODO(cshapiro): detach white string objects */
+            scavengeReference((Object **)(void *)&entry->data);
+            LOG_SCAV("<<< string obj=%p", entry->data);
+        }
+    }
+    dvmHashTableUnlock(table);
+}
+
+static void pinInternedStrings()
+{
+    HashTable *table = gDvm.internedStrings;
+    if (table == NULL) {
+        return;
+    }
+    dvmHashTableLock(table);
+    for (int i = 0; i < table->tableSize; ++i) {
+        HashEntry *entry = &table->pEntries[i];
+        Object *obj = (Object *)entry->data;
+        if (obj == NULL || obj == HASH_TOMBSTONE) {
+            continue;
+        } else if (isPermanentString((StringObject *)obj)) {
+            obj = (Object *)getPermanentString((StringObject*)obj);
+            LOG_PROM(">>> pin string obj=%p", obj);
+            pinObject(obj);
+            LOG_PROM("<<< pin string obj=%p", obj);
+        }
+     }
+    dvmHashTableUnlock(table);
+}
+
+/*
+ * At present, reference tables contain references that must not be
+ * moved by the collector.  Instead of scavenging each reference in
+ * the table we pin each referenced object.
+ */
+static void pinReferenceTable(const ReferenceTable *table)
+{
+    assert(table != NULL);
+    assert(table->table != NULL);
+    assert(table->nextEntry != NULL);
+    for (Object **entry = table->table; entry < table->nextEntry; ++entry) {
+        assert(entry != NULL);
+        assert(!isForward(*entry));
+        pinObject(*entry);
+    }
+}
+
+static void scavengeLargeHeapRefTable(LargeHeapRefTable *table)
+{
+    for (; table != NULL; table = table->next) {
+        Object **ref = table->refs.table;
+        for (; ref < table->refs.nextEntry; ++ref) {
+            scavengeReference(ref);
+        }
+    }
+}
+
+/* This code was copied from Thread.c */
+static void scavengeThreadStack(Thread *thread)
+{
+    const u4 *framePtr;
+#if WITH_EXTRA_GC_CHECKS > 1
+    bool first = true;
+#endif
+
+    framePtr = (const u4 *)thread->interpSave.curFrame;
+    while (framePtr != NULL) {
+        const StackSaveArea *saveArea;
+        const Method *method;
+
+        saveArea = SAVEAREA_FROM_FP(framePtr);
+        method = saveArea->method;
+        if (method != NULL && !dvmIsNativeMethod(method)) {
+#ifdef COUNT_PRECISE_METHODS
+            /* the GC is running, so no lock required */
+            if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
+                LOG_SCAV("PGC: added %s.%s %p",
+                             method->clazz->descriptor, method->name, method);
+#endif
+#if WITH_EXTRA_GC_CHECKS > 1
+            /*
+             * May also want to enable the memset() in the "invokeMethod"
+             * goto target in the portable interpreter.  That sets the stack
+             * to a pattern that makes referring to uninitialized data
+             * very obvious.
+             */
+
+            if (first) {
+                /*
+                 * First frame, isn't native, check the "alternate" saved PC
+                 * as a sanity check.
+                 *
+                 * It seems like we could check the second frame if the first
+                 * is native, since the PCs should be the same.  It turns out
+                 * this doesn't always work.  The problem is that we could
+                 * have calls in the sequence:
+                 *   interp method #2
+                 *   native method
+                 *   interp method #1
+                 *
+                 * and then GC while in the native method after returning
+                 * from interp method #2.  The currentPc on the stack is
+                 * for interp method #1, but thread->currentPc2 is still
+                 * set for the last thing interp method #2 did.
+                 *
+                 * This can also happen in normal execution:
+                 * - sget-object on not-yet-loaded class
+                 * - class init updates currentPc2
+                 * - static field init is handled by parsing annotations;
+                 *   static String init requires creation of a String object,
+                 *   which can cause a GC
+                 *
+                 * Essentially, any pattern that involves executing
+                 * interpreted code and then causes an allocation without
+                 * executing instructions in the original method will hit
+                 * this.  These are rare enough that the test still has
+                 * some value.
+                 */
+                if (saveArea->xtra.currentPc != thread->currentPc2) {
+                    LOGW("PGC: savedPC(%p) != current PC(%p), %s.%s ins=%p",
+                        saveArea->xtra.currentPc, thread->currentPc2,
+                        method->clazz->descriptor, method->name, method->insns);
+                    if (saveArea->xtra.currentPc != NULL)
+                        LOGE("  pc inst = 0x%04x", *saveArea->xtra.currentPc);
+                    if (thread->currentPc2 != NULL)
+                        LOGE("  pc2 inst = 0x%04x", *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;
+
+            Method* nonConstMethod = (Method*) method;  // quiet gcc
+            pMap = dvmGetExpandedRegisterMap(nonConstMethod);
+
+            //LOG_SCAV("PGC: %s.%s", method->clazz->descriptor, method->name);
+
+            if (pMap != NULL) {
+                /* found map, get registers for this address */
+                int addr = saveArea->xtra.currentPc - method->insns;
+                regVector = dvmRegisterMapGetLine(pMap, addr);
+                /*
+                if (regVector == NULL) {
+                    LOG_SCAV("PGC: map but no entry for %s.%s addr=0x%04x",
+                                 method->clazz->descriptor, method->name, addr);
+                } else {
+                    LOG_SCAV("PGC: found map for %s.%s 0x%04x (t=%d)",
+                                 method->clazz->descriptor, method->name, addr,
+                                 thread->threadId);
+                }
+                */
+            } else {
+                /*
+                 * No map found.  If precise GC is disabled this is
+                 * expected -- we don't create pointers to the map data even
+                 * if it's present -- but if it's enabled it means we're
+                 * unexpectedly falling back on a conservative scan, so it's
+                 * worth yelling a little.
+                 */
+                if (gDvm.preciseGc) {
+                    LOG_SCAV("PGC: no map for %s.%s", method->clazz->descriptor, method->name);
+                }
+                regVector = NULL;
+            }
+            if (regVector == NULL) {
+                /*
+                 * There are no roots to scavenge.  Skip over the entire frame.
+                 */
+                framePtr += method->registersSize;
+            } else {
+                /*
+                 * Precise scan.  v0 is at the lowest address on the
+                 * interpreted stack, and is the first bit in the register
+                 * vector, so we can walk through the register map and
+                 * memory in the same direction.
+                 *
+                 * A '1' bit indicates a live reference.
+                 */
+                u2 bits = 1 << 1;
+                for (int i = method->registersSize - 1; i >= 0; i--) {
+                    u4 rval = *framePtr;
+
+                    bits >>= 1;
+                    if (bits == 1) {
+                        /* set bit 9 so we can tell when we're empty */
+                        bits = *regVector++ | 0x0100;
+                    }
+
+                    if (rval != 0 && (bits & 0x01) != 0) {
+                        /*
+                         * Non-null, register marked as live reference.  This
+                         * should always be a valid object.
+                         */
+#if WITH_EXTRA_GC_CHECKS > 0
+                        if ((rval & 0x3) != 0 || !dvmIsValidObject((Object*) rval)) {
+                            /* this is very bad */
+                            LOGE("PGC: invalid ref in reg %d: 0x%08x",
+                                method->registersSize-1 - i, rval);
+                        } else
+#endif
+                        {
+
+                            // LOG_SCAV("stack reference %u@%p", *framePtr, framePtr);
+                            /* dvmMarkObjectNonNull((Object *)rval); */
+                            scavengeReference((Object **) framePtr);
+                        }
+                    } else {
+                        /*
+                         * Null or non-reference, do nothing at all.
+                         */
+#if WITH_EXTRA_GC_CHECKS > 1
+                        if (dvmIsValidObject((Object*) rval)) {
+                            /* this is normal, but we feel chatty */
+                            LOGD("PGC: ignoring valid ref in reg %d: 0x%08x",
+                                 method->registersSize-1 - i, rval);
+                        }
+#endif
+                    }
+                    ++framePtr;
+                }
+                dvmReleaseRegisterMapLine(pMap, regVector);
+            }
+        }
+        /* else this is a break frame and there is nothing to gray, or
+         * this is a native method and the registers are just the "ins",
+         * copied from various registers in the caller's set.
+         */
+
+#if WITH_EXTRA_GC_CHECKS > 1
+        first = false;
+#endif
+
+        /* Don't fall into an infinite loop if things get corrupted.
+         */
+        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
+               saveArea->prevFrame == NULL);
+        framePtr = saveArea->prevFrame;
+    }
+}
+
+static void scavengeThread(Thread *thread)
+{
+    // LOG_SCAV("scavengeThread(thread=%p)", thread);
+
+    // LOG_SCAV("Scavenging threadObj=%p", thread->threadObj);
+    scavengeReference(&thread->threadObj);
+
+    // LOG_SCAV("Scavenging exception=%p", thread->exception);
+    scavengeReference(&thread->exception);
+
+    scavengeThreadStack(thread);
+}
+
+static void scavengeThreadList()
+{
+    Thread *thread;
+
+    dvmLockThreadList(dvmThreadSelf());
+    thread = gDvm.threadList;
+    while (thread) {
+        scavengeThread(thread);
+        thread = thread->next;
+    }
+    dvmUnlockThreadList();
+}
+
+static void pinThreadStack(const Thread *thread)
+{
+    const u4 *framePtr;
+    const StackSaveArea *saveArea;
+    Method *method;
+    const char *shorty;
+    Object *obj;
+
+    saveArea = NULL;
+    framePtr = (const u4 *)thread->interpSave.curFrame;
+    for (; framePtr != NULL; framePtr = saveArea->prevFrame) {
+        saveArea = SAVEAREA_FROM_FP(framePtr);
+        method = (Method *)saveArea->method;
+        if (method != NULL && dvmIsNativeMethod(method)) {
+            /*
+             * This is native method, pin its arguments.
+             *
+             * For purposes of graying references, we don't need to do
+             * anything here, because all of the native "ins" were copied
+             * from registers in the caller's stack frame and won't be
+             * changed (an interpreted method can freely use registers
+             * with parameters like any other register, but natives don't
+             * work that way).
+             *
+             * However, we need to ensure that references visible to
+             * native methods don't move around.  We can do a precise scan
+             * of the arguments by examining the method signature.
+             */
+            LOG_PIN("+++ native scan %s.%s",
+                    method->clazz->descriptor, method->name);
+            assert(method->registersSize == method->insSize);
+            if (!dvmIsStaticMethod(method)) {
+                /* grab the "this" pointer */
+                obj = (Object *)*framePtr++;
+                if (obj == NULL) {
+                    /*
+                     * This can happen for the "fake" entry frame inserted
+                     * for threads created outside the VM.  There's no actual
+                     * call so there's no object.  If we changed the fake
+                     * entry method to be declared "static" then this
+                     * situation should never occur.
+                     */
+                } else {
+                    assert(dvmIsValidObject(obj));
+                    pinObject(obj);
+                }
+            }
+            shorty = method->shorty+1;      // skip return value
+            for (int i = method->registersSize - 1; i >= 0; i--, framePtr++) {
+                switch (*shorty++) {
+                case 'L':
+                    obj = (Object *)*framePtr;
+                    if (obj != NULL) {
+                        assert(dvmIsValidObject(obj));
+                        pinObject(obj);
+                    }
+                    break;
+                case 'D':
+                case 'J':
+                    framePtr++;
+                    break;
+                default:
+                    /* 32-bit non-reference value */
+                    obj = (Object *)*framePtr;          // debug, remove
+                    if (dvmIsValidObject(obj)) {        // debug, remove
+                        /* if we see a lot of these, our scan might be off */
+                        LOG_PIN("+++ did NOT pin obj %p", obj);
+                    }
+                    break;
+                }
+            }
+        } else if (method != NULL && !dvmIsNativeMethod(method)) {
+            const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
+            const u1* regVector = NULL;
+
+            LOGI("conservative : %s.%s", method->clazz->descriptor, method->name);
+
+            if (pMap != NULL) {
+                int addr = saveArea->xtra.currentPc - method->insns;
+                regVector = dvmRegisterMapGetLine(pMap, addr);
+            }
+            if (regVector == NULL) {
+                /*
+                 * No register info for this frame, conservatively pin.
+                 */
+                for (int i = 0; i < method->registersSize; ++i) {
+                    u4 regValue = framePtr[i];
+                    if (regValue != 0 && (regValue & 0x3) == 0 && dvmIsValidObject((Object *)regValue)) {
+                        pinObject((Object *)regValue);
+                    }
+                }
+            }
+        }
+        /*
+         * Don't fall into an infinite loop if things get corrupted.
+         */
+        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
+               saveArea->prevFrame == NULL);
+    }
+}
+
+static void pinThread(const Thread *thread)
+{
+    assert(thread != NULL);
+    LOG_PIN("pinThread(thread=%p)", thread);
+
+    LOG_PIN("Pin native method arguments");
+    pinThreadStack(thread);
+
+    LOG_PIN("Pin internalLocalRefTable");
+    pinReferenceTable(&thread->internalLocalRefTable);
+
+    LOG_PIN("Pin jniLocalRefTable");
+    pinReferenceTable(&thread->jniLocalRefTable);
+
+    /* Can the check be pushed into the promote routine? */
+    if (thread->jniMonitorRefTable.table) {
+        LOG_PIN("Pin jniMonitorRefTable");
+        pinReferenceTable(&thread->jniMonitorRefTable);
+    }
+}
+
+static void pinThreadList()
+{
+    Thread *thread;
+
+    dvmLockThreadList(dvmThreadSelf());
+    thread = gDvm.threadList;
+    while (thread) {
+        pinThread(thread);
+        thread = thread->next;
+    }
+    dvmUnlockThreadList();
+}
+
+/*
+ * Heap block scavenging.
+ */
+
+/*
+ * Scavenge objects in the current block.  Scavenging terminates when
+ * the pointer reaches the highest address in the block or when a run
+ * of zero words that continues to the highest address is reached.
+ */
+static void scavengeBlock(HeapSource *heapSource, size_t block)
+{
+    u1 *cursor;
+    u1 *end;
+    size_t size;
+
+    LOG_SCAV("scavengeBlock(heapSource=%p,block=%zu)", heapSource, block);
+
+    assert(heapSource != NULL);
+    assert(block < heapSource->totalBlocks);
+    assert(heapSource->blockSpace[block] == BLOCK_TO_SPACE);
+
+    cursor = blockToAddress(heapSource, block);
+    end = cursor + BLOCK_SIZE;
+    LOG_SCAV("scavengeBlock start=%p, end=%p", cursor, end);
+
+    /* Parse and scavenge the current block. */
+    size = 0;
+    while (cursor < end) {
+        u4 word = *(u4 *)cursor;
+        if (word != 0) {
+            scavengeObject((Object *)cursor);
+            size = objectSize((Object *)cursor);
+            size = alignUp(size, ALLOC_ALIGNMENT);
+            cursor += size;
+        } else {
+            /* Check for padding. */
+            while (*(u4 *)cursor == 0) {
+                cursor += 4;
+                if (cursor == end) break;
+            }
+            /* Punt if something went wrong. */
+            assert(cursor == end);
+        }
+    }
+}
+
+static size_t objectSize(const Object *obj)
+{
+    size_t size;
+
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    if (obj->clazz == gDvm.classJavaLangClass) {
+        size = dvmClassObjectSize((ClassObject *)obj);
+    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+        size = dvmArrayObjectSize((ArrayObject *)obj);
+    } else {
+        assert(obj->clazz->objectSize != 0);
+        size = obj->clazz->objectSize;
+    }
+    if (LW_HASH_STATE(obj->lock) == LW_HASH_STATE_HASHED_AND_MOVED) {
+        size += sizeof(u4);
+    }
+    return size;
+}
+
+static void verifyBlock(HeapSource *heapSource, size_t block)
+{
+    u1 *cursor;
+    u1 *end;
+    size_t size;
+
+    // LOG_VER("verifyBlock(heapSource=%p,block=%zu)", heapSource, block);
+
+    assert(heapSource != NULL);
+    assert(block < heapSource->totalBlocks);
+    assert(heapSource->blockSpace[block] == BLOCK_TO_SPACE);
+
+    cursor = blockToAddress(heapSource, block);
+    end = cursor + BLOCK_SIZE;
+    // LOG_VER("verifyBlock start=%p, end=%p", cursor, end);
+
+    /* Parse and scavenge the current block. */
+    size = 0;
+    while (cursor < end) {
+        u4 word = *(u4 *)cursor;
+        if (word != 0) {
+            dvmVerifyObject((Object *)cursor);
+            size = objectSize((Object *)cursor);
+            size = alignUp(size, ALLOC_ALIGNMENT);
+            cursor += size;
+        } else {
+            /* Check for padding. */
+            while (*(unsigned long *)cursor == 0) {
+                cursor += 4;
+                if (cursor == end) break;
+            }
+            /* Punt if something went wrong. */
+            assert(cursor == end);
+        }
+    }
+}
+
+static void describeBlockQueue(const HeapSource *heapSource)
+{
+    size_t block, count;
+    char space;
+
+    block = heapSource->queueHead;
+    count = 0;
+    LOG_SCAV(">>> describeBlockQueue(heapSource=%p)", heapSource);
+    /* Count the number of blocks enqueued. */
+    while (block != QUEUE_TAIL) {
+        block = heapSource->blockQueue[block];
+        ++count;
+    }
+    LOG_SCAV("blockQueue %zu elements, enqueued %zu",
+                 count, heapSource->queueSize);
+    block = heapSource->queueHead;
+    while (block != QUEUE_TAIL) {
+        space = heapSource->blockSpace[block];
+        LOG_SCAV("block=%zu@%p,space=%zu", block, blockToAddress(heapSource,block), space);
+        block = heapSource->blockQueue[block];
+    }
+
+    LOG_SCAV("<<< describeBlockQueue(heapSource=%p)", heapSource);
+}
+
+/*
+ * Blackens promoted objects.
+ */
+static void scavengeBlockQueue()
+{
+    HeapSource *heapSource;
+    size_t block;
+
+    LOG_SCAV(">>> scavengeBlockQueue()");
+    heapSource = gDvm.gcHeap->heapSource;
+    describeBlockQueue(heapSource);
+    while (heapSource->queueHead != QUEUE_TAIL) {
+        block = heapSource->queueHead;
+        LOG_SCAV("Dequeueing block %zu", block);
+        scavengeBlock(heapSource, block);
+        heapSource->queueHead = heapSource->blockQueue[block];
+        LOG_SCAV("New queue head is %zu", heapSource->queueHead);
+    }
+    LOG_SCAV("<<< scavengeBlockQueue()");
+}
+
+/*
+ * Scan the block list and verify all blocks that are marked as being
+ * in new space.  This should be parametrized so we can invoke this
+ * routine outside of the context of a collection.
+ */
+static void verifyNewSpace()
+{
+    HeapSource *heapSource = gDvm.gcHeap->heapSource;
+    size_t c0 = 0, c1 = 0, c2 = 0, c7 = 0;
+    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
+        switch (heapSource->blockSpace[i]) {
+        case BLOCK_FREE: ++c0; break;
+        case BLOCK_TO_SPACE: ++c1; break;
+        case BLOCK_FROM_SPACE: ++c2; break;
+        case BLOCK_CONTINUED: ++c7; break;
+        default: assert(!"reached");
+        }
+    }
+    LOG_VER("Block Demographics: "
+            "Free=%zu,ToSpace=%zu,FromSpace=%zu,Continued=%zu",
+            c0, c1, c2, c7);
+    for (size_t i = 0; i < heapSource->totalBlocks; ++i) {
+        if (heapSource->blockSpace[i] != BLOCK_TO_SPACE) {
+            continue;
+        }
+        verifyBlock(heapSource, i);
+    }
+}
+
+void describeHeap()
+{
+    HeapSource *heapSource = gDvm.gcHeap->heapSource;
+    describeBlocks(heapSource);
+}
+
+/*
+ * The collection interface.  Collection has a few distinct phases.
+ * The first is flipping AKA condemning AKA whitening the heap.  The
+ * second is to promote all objects which are pointed to by pinned or
+ * ambiguous references.  The third phase is tracing from the stacks,
+ * registers and various globals.  Lastly, a verification of the heap
+ * is performed.  The last phase should be optional.
+ */
+void dvmScavengeRoots()  /* Needs a new name badly */
+{
+    GcHeap *gcHeap;
+
+    {
+        size_t alloc, unused, total;
+
+        room(&alloc, &unused, &total);
+        LOG_SCAV("BEFORE GC: %zu alloc, %zu free, %zu total.",
+                     alloc, unused, total);
+    }
+
+    gcHeap = gDvm.gcHeap;
+    dvmHeapSourceFlip();
+
+    /*
+     * Promote blocks with stationary objects.
+     */
+    pinThreadList();
+    pinReferenceTable(&gDvm.jniGlobalRefTable);
+    pinReferenceTable(&gDvm.jniPinRefTable);
+    pinHashTableEntries(gDvm.loadedClasses);
+    pinHashTableEntries(gDvm.dbgRegistry);
+    pinPrimitiveClasses();
+    pinInternedStrings();
+
+    // describeBlocks(gcHeap->heapSource);
+
+    /*
+     * Create first, open new-space page right here.
+     */
+
+    /* Reset allocation to an unallocated block. */
+    gDvm.gcHeap->heapSource->allocPtr = allocateBlocks(gDvm.gcHeap->heapSource, 1);
+    gDvm.gcHeap->heapSource->allocLimit = gDvm.gcHeap->heapSource->allocPtr + BLOCK_SIZE;
+    /*
+     * Hack: promote the empty block allocated above.  If the
+     * promotions that occurred above did not actually gray any
+     * objects, the block queue may be empty.  We must force a
+     * promotion to be safe.
+     */
+    promoteBlockByAddr(gDvm.gcHeap->heapSource, gDvm.gcHeap->heapSource->allocPtr);
+
+    /*
+     * Scavenge blocks and relocate movable objects.
+     */
+
+    LOG_SCAV("Scavenging gDvm.threadList");
+    scavengeThreadList();
+
+    LOG_SCAV("Scavenging gDvm.gcHeap->referenceOperations");
+    scavengeLargeHeapRefTable(gcHeap->referenceOperations);
+
+    LOG_SCAV("Scavenging gDvm.gcHeap->pendingFinalizationRefs");
+    scavengeLargeHeapRefTable(gcHeap->pendingFinalizationRefs);
+
+    LOG_SCAV("Scavenging random global stuff");
+    scavengeReference(&gDvm.outOfMemoryObj);
+    scavengeReference(&gDvm.internalErrorObj);
+    scavengeReference(&gDvm.noClassDefFoundErrorObj);
+
+    // LOG_SCAV("Scavenging gDvm.internedString");
+    scavengeInternedStrings();
+
+    LOG_SCAV("Root scavenge has completed.");
+
+    scavengeBlockQueue();
+
+    // LOG_SCAV("Re-snap global class pointers.");
+    // scavengeGlobals();
+
+    LOG_SCAV("New space scavenge has completed.");
+
+    /*
+     * Process reference objects in strength order.
+     */
+
+    LOG_REF("Processing soft references...");
+    preserveSoftReferences(&gDvm.gcHeap->softReferences);
+    clearWhiteReferences(&gDvm.gcHeap->softReferences);
+
+    LOG_REF("Processing weak references...");
+    clearWhiteReferences(&gDvm.gcHeap->weakReferences);
+
+    LOG_REF("Finding finalizations...");
+    processFinalizableReferences();
+
+    LOG_REF("Processing f-reachable soft references...");
+    clearWhiteReferences(&gDvm.gcHeap->softReferences);
+
+    LOG_REF("Processing f-reachable weak references...");
+    clearWhiteReferences(&gDvm.gcHeap->weakReferences);
+
+    LOG_REF("Processing phantom references...");
+    clearWhiteReferences(&gDvm.gcHeap->phantomReferences);
+
+    /*
+     * Verify the stack and heap.
+     */
+    dvmVerifyRoots();
+    verifyNewSpace();
+
+    //describeBlocks(gcHeap->heapSource);
+
+    clearFromSpace(gcHeap->heapSource);
+
+    {
+        size_t alloc, rem, total;
+
+        room(&alloc, &rem, &total);
+        LOG_SCAV("AFTER GC: %zu alloc, %zu free, %zu total.", alloc, rem, total);
+    }
+}
+
+/*
+ * Interface compatibility routines.
+ */
+
+void dvmClearWhiteRefs(Object **list)
+{
+    /* do nothing */
+    assert(*list == NULL);
+}
+
+void dvmHandleSoftRefs(Object **list)
+{
+    /* do nothing */
+    assert(*list == NULL);
+}
+
+bool dvmHeapBeginMarkStep(GcMode mode)
+{
+    /* do nothing */
+    return true;
+}
+
+void dvmHeapFinishMarkStep()
+{
+    /* do nothing */
+}
+
+void dvmHeapMarkRootSet()
+{
+    /* do nothing */
+}
+
+void dvmHeapScanMarkedObjects()
+{
+    dvmScavengeRoots();
+}
+
+void dvmHeapScheduleFinalizations()
+{
+    /* do nothing */
+}
+
+void dvmHeapSweepUnmarkedObjects(GcMode mode, int *numFreed, size_t *sizeFreed)
+{
+    *numFreed = 0;
+    *sizeFreed = 0;
+    /* do nothing */
+}
+
+void dvmMarkDirtyObjects()
+{
+    assert(!"implemented");
+}
+
+void dvmHeapSourceThreadShutdown()
+{
+    /* do nothing */
+}
diff --git a/vm/alloc/DdmHeap.cpp b/vm/alloc/DdmHeap.cpp
new file mode 100644
index 0000000..62b8037
--- /dev/null
+++ b/vm/alloc/DdmHeap.cpp
@@ -0,0 +1,490 @@
+/*
+ * 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.
+ */
+/*
+ * DDM-related heap functions
+ */
+#include <sys/time.h>
+#include <time.h>
+
+#include "Dalvik.h"
+#include "alloc/Heap.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/DdmHeap.h"
+#include "alloc/HeapSource.h"
+
+#define DEFAULT_HEAP_ID  1
+
+enum HpifWhen {
+    HPIF_WHEN_NEVER = 0,
+    HPIF_WHEN_NOW = 1,
+    HPIF_WHEN_NEXT_GC = 2,
+    HPIF_WHEN_EVERY_GC = 3
+};
+
+/*
+ * Chunk HPIF (client --> server)
+ *
+ * Heap Info. General information about the heap,
+ * suitable for a summary display.
+ *
+ *   [u4]: number of heaps
+ *
+ *   For each heap:
+ *     [u4]: heap ID
+ *     [u8]: timestamp in ms since Unix epoch
+ *     [u1]: capture reason (same as 'when' value from server)
+ *     [u4]: max heap size in bytes (-Xmx)
+ *     [u4]: current heap size in bytes
+ *     [u4]: current number of bytes allocated
+ *     [u4]: current number of objects allocated
+ */
+#define HPIF_SIZE(numHeaps) \
+        (sizeof(u4) + (numHeaps) * (5 * sizeof(u4) + sizeof(u1) + sizeof(u8)))
+void dvmDdmSendHeapInfo(int reason, bool shouldLock)
+{
+    struct timeval now;
+    u8 nowMs;
+    u1 *buf, *b;
+
+    buf = (u1 *)malloc(HPIF_SIZE(1));
+    if (buf == NULL) {
+        return;
+    }
+    b = buf;
+
+    /* If there's a one-shot 'when', reset it.
+     */
+    if (reason == gDvm.gcHeap->ddmHpifWhen) {
+        if (shouldLock && ! dvmLockHeap()) {
+            LOGW("%s(): can't lock heap to clear when", __func__);
+            goto skip_when;
+        }
+        if (reason == gDvm.gcHeap->ddmHpifWhen) {
+            if (gDvm.gcHeap->ddmHpifWhen == HPIF_WHEN_NEXT_GC) {
+                gDvm.gcHeap->ddmHpifWhen = HPIF_WHEN_NEVER;
+            }
+        }
+        if (shouldLock) {
+            dvmUnlockHeap();
+        }
+    }
+skip_when:
+
+    /* The current time, in milliseconds since 0:00 GMT, 1/1/70.
+     */
+    if (gettimeofday(&now, NULL) < 0) {
+        nowMs = 0;
+    } else {
+        nowMs = (u8)now.tv_sec * 1000 + now.tv_usec / 1000;
+    }
+
+    /* number of heaps */
+    set4BE(b, 1); b += 4;
+
+    /* For each heap (of which there is one) */
+    {
+        /* heap ID */
+        set4BE(b, DEFAULT_HEAP_ID); b += 4;
+
+        /* timestamp */
+        set8BE(b, nowMs); b += 8;
+
+        /* 'when' value */
+        *b++ = (u1)reason;
+
+        /* max allowed heap size in bytes */
+        set4BE(b, dvmHeapSourceGetMaximumSize()); b += 4;
+
+        /* current heap size in bytes */
+        set4BE(b, dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0)); b += 4;
+
+        /* number of bytes allocated */
+        set4BE(b, dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0)); b += 4;
+
+        /* number of objects allocated */
+        set4BE(b, dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED, NULL, 0)); b += 4;
+    }
+    assert((intptr_t)b == (intptr_t)buf + (intptr_t)HPIF_SIZE(1));
+
+    dvmDbgDdmSendChunk(CHUNK_TYPE("HPIF"), b - buf, buf);
+}
+
+bool dvmDdmHandleHpifChunk(int when)
+{
+    switch (when) {
+    case HPIF_WHEN_NOW:
+        dvmDdmSendHeapInfo(when, true);
+        break;
+    case HPIF_WHEN_NEVER:
+    case HPIF_WHEN_NEXT_GC:
+    case HPIF_WHEN_EVERY_GC:
+        if (dvmLockHeap()) {
+            gDvm.gcHeap->ddmHpifWhen = when;
+            dvmUnlockHeap();
+        } else {
+            LOGI("%s(): can't lock heap to set when", __func__);
+            return false;
+        }
+        break;
+    default:
+        LOGI("%s(): bad when value 0x%08x", __func__, when);
+        return false;
+    }
+
+    return true;
+}
+
+enum HpsgSolidity {
+    SOLIDITY_FREE = 0,
+    SOLIDITY_HARD = 1,
+    SOLIDITY_SOFT = 2,
+    SOLIDITY_WEAK = 3,
+    SOLIDITY_PHANTOM = 4,
+    SOLIDITY_FINALIZABLE = 5,
+    SOLIDITY_SWEEP = 6,
+};
+
+enum HpsgKind {
+    KIND_OBJECT = 0,
+    KIND_CLASS_OBJECT = 1,
+    KIND_ARRAY_1 = 2,
+    KIND_ARRAY_2 = 3,
+    KIND_ARRAY_4 = 4,
+    KIND_ARRAY_8 = 5,
+    KIND_UNKNOWN = 6,
+    KIND_NATIVE = 7,
+};
+
+#define HPSG_PARTIAL (1<<7)
+#define HPSG_STATE(solidity, kind) \
+    ((u1)((((kind) & 0x7) << 3) | ((solidity) & 0x7)))
+
+struct HeapChunkContext {
+    u1 *buf;
+    u1 *p;
+    u1 *pieceLenField;
+    size_t bufLen;
+    size_t totalAllocationUnits;
+    int type;
+    bool merge;
+    bool needHeader;
+};
+
+#define ALLOCATION_UNIT_SIZE 8
+
+static void flush_hpsg_chunk(HeapChunkContext *ctx)
+{
+    /* Patch the "length of piece" field.
+     */
+    assert(ctx->buf <= ctx->pieceLenField &&
+            ctx->pieceLenField <= ctx->p);
+    set4BE(ctx->pieceLenField, ctx->totalAllocationUnits);
+
+    /* Send the chunk.
+     */
+    dvmDbgDdmSendChunk(ctx->type, ctx->p - ctx->buf, ctx->buf);
+
+    /* Reset the context.
+     */
+    ctx->p = ctx->buf;
+    ctx->totalAllocationUnits = 0;
+    ctx->needHeader = true;
+    ctx->pieceLenField = NULL;
+}
+
+static void heap_chunk_callback(const void *chunkptr, size_t chunklen,
+                                const void *userptr, size_t userlen, void *arg)
+{
+    HeapChunkContext *ctx = (HeapChunkContext *)arg;
+    u1 state;
+
+    UNUSED_PARAMETER(userlen);
+
+    assert((chunklen & (ALLOCATION_UNIT_SIZE-1)) == 0);
+
+    /* Make sure there's enough room left in the buffer.
+     * We need to use two bytes for every fractional 256
+     * 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 < 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)",
+                chunklen, needed);
+            return;
+        }
+    }
+
+//TODO: notice when there's a gap and start a new heap, or at least a new range.
+    if (ctx->needHeader) {
+        /*
+         * Start a new HPSx chunk.
+         */
+
+        /* [u4]: heap ID */
+        set4BE(ctx->p, DEFAULT_HEAP_ID); ctx->p += 4;
+
+        /* [u1]: size of allocation unit, in bytes */
+        *ctx->p++ = 8;
+
+        /* [u4]: virtual address of segment start */
+        set4BE(ctx->p, (uintptr_t)chunkptr); ctx->p += 4;
+
+        /* [u4]: offset of this piece (relative to the virtual address) */
+        set4BE(ctx->p, 0); ctx->p += 4;
+
+        /* [u4]: length of piece, in allocation units
+         * We won't know this until we're done, so save the offset
+         * and stuff in a dummy value.
+         */
+        ctx->pieceLenField = ctx->p;
+        set4BE(ctx->p, 0x55555555); ctx->p += 4;
+
+        ctx->needHeader = false;
+    }
+
+    /* Determine the type of this chunk.
+     */
+    if (userptr == NULL) {
+        /* It's a free chunk.
+         */
+        state = HPSG_STATE(SOLIDITY_FREE, 0);
+    } else {
+        const Object *obj = (const Object *)userptr;
+        /* If we're looking at the native heap, we'll just return
+         * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
+         */
+        bool native = ctx->type == CHUNK_TYPE("NHSG");
+
+        /* It's an allocated chunk.  Figure out what it is.
+         */
+//TODO: if ctx.merge, see if this chunk is different from the last chunk.
+//      If it's the same, we should combine them.
+        if (!native && dvmIsValidObject(obj)) {
+            ClassObject *clazz = obj->clazz;
+            if (clazz == NULL) {
+                /* The object was probably just created
+                 * but hasn't been initialized yet.
+                 */
+                state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
+            } else if (dvmIsTheClassClass(clazz)) {
+                state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
+            } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
+                if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
+                    state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
+                } else {
+                    switch (clazz->elementClass->primitiveType) {
+                    case PRIM_BOOLEAN:
+                    case PRIM_BYTE:
+                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1);
+                        break;
+                    case PRIM_CHAR:
+                    case PRIM_SHORT:
+                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2);
+                        break;
+                    case PRIM_INT:
+                    case PRIM_FLOAT:
+                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
+                        break;
+                    case PRIM_DOUBLE:
+                    case PRIM_LONG:
+                        state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8);
+                        break;
+                    default:
+                        assert(!"Unknown GC heap object type");
+                        state = HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN);
+                        break;
+                    }
+                }
+            } else {
+                state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
+            }
+        } else {
+            obj = NULL; // it's not actually an object
+            state = HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
+        }
+    }
+
+    /* Write out the chunk description.
+     */
+    chunklen /= ALLOCATION_UNIT_SIZE;   // convert to allocation units
+    ctx->totalAllocationUnits += chunklen;
+    while (chunklen > 256) {
+        *ctx->p++ = state | HPSG_PARTIAL;
+        *ctx->p++ = 255;     // length - 1
+        chunklen -= 256;
+    }
+    *ctx->p++ = state;
+    *ctx->p++ = chunklen - 1;
+}
+
+enum HpsgWhen {
+    HPSG_WHEN_NEVER = 0,
+    HPSG_WHEN_EVERY_GC = 1,
+};
+enum HpsgWhat {
+    HPSG_WHAT_MERGED_OBJECTS = 0,
+    HPSG_WHAT_DISTINCT_OBJECTS = 1,
+};
+
+/*
+ * Maximum chunk size.  Obtain this from the formula:
+ *
+ * (((maximum_heap_size / ALLOCATION_UNIT_SIZE) + 255) / 256) * 2
+ */
+#define HPSx_CHUNK_SIZE (16384 - 16)
+
+extern "C" void dlmalloc_walk_heap(void(*)(const void*, size_t, const void*, size_t, void*),void*);
+
+static void walkHeap(bool merge, bool native)
+{
+    HeapChunkContext ctx;
+
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.bufLen = HPSx_CHUNK_SIZE;
+    ctx.buf = (u1 *)malloc(ctx.bufLen);
+    if (ctx.buf == NULL) {
+        return;
+    }
+
+    ctx.merge = merge;
+    if (native) {
+        ctx.type = CHUNK_TYPE("NHSG");
+    } else {
+        if (ctx.merge) {
+            ctx.type = CHUNK_TYPE("HPSG");
+        } else {
+            ctx.type = CHUNK_TYPE("HPSO");
+        }
+    }
+
+    ctx.p = ctx.buf;
+    ctx.needHeader = true;
+    if (native) {
+        dlmalloc_walk_heap(heap_chunk_callback, (void *)&ctx);
+    } else {
+        dvmHeapSourceWalk(heap_chunk_callback, (void *)&ctx);
+    }
+    if (ctx.p > ctx.buf) {
+        flush_hpsg_chunk(&ctx);
+    }
+
+    free(ctx.buf);
+}
+
+void dvmDdmSendHeapSegments(bool shouldLock, bool native)
+{
+    u1 heapId[sizeof(u4)];
+    GcHeap *gcHeap = gDvm.gcHeap;
+    int when, what;
+    bool merge;
+
+    /* Don't even grab the lock if there's nothing to do when we're called.
+     */
+    if (!native) {
+        when = gcHeap->ddmHpsgWhen;
+        what = gcHeap->ddmHpsgWhat;
+        if (when == HPSG_WHEN_NEVER) {
+            return;
+        }
+    } else {
+        when = gcHeap->ddmNhsgWhen;
+        what = gcHeap->ddmNhsgWhat;
+        if (when == HPSG_WHEN_NEVER) {
+            return;
+        }
+    }
+    if (shouldLock && !dvmLockHeap()) {
+        LOGW("Can't lock heap for DDM HPSx dump");
+        return;
+    }
+
+    /* Figure out what kind of chunks we'll be sending.
+     */
+    if (what == HPSG_WHAT_MERGED_OBJECTS) {
+        merge = true;
+    } else if (what == HPSG_WHAT_DISTINCT_OBJECTS) {
+        merge = false;
+    } else {
+        assert(!"bad HPSG.what value");
+        return;
+    }
+
+    /* First, send a heap start chunk.
+     */
+    set4BE(heapId, DEFAULT_HEAP_ID);
+    dvmDbgDdmSendChunk(native ? CHUNK_TYPE("NHST") : CHUNK_TYPE("HPST"),
+        sizeof(u4), heapId);
+
+    /* Send a series of heap segment chunks.
+     */
+    walkHeap(merge, native);
+
+    /* Finally, send a heap end chunk.
+     */
+    dvmDbgDdmSendChunk(native ? CHUNK_TYPE("NHEN") : CHUNK_TYPE("HPEN"),
+        sizeof(u4), heapId);
+
+    if (shouldLock) {
+        dvmUnlockHeap();
+    }
+}
+
+bool dvmDdmHandleHpsgNhsgChunk(int when, int what, bool native)
+{
+    LOGI("dvmDdmHandleHpsgChunk(when %d, what %d, heap %d)", when, what,
+         native);
+    switch (when) {
+    case HPSG_WHEN_NEVER:
+    case HPSG_WHEN_EVERY_GC:
+        break;
+    default:
+        LOGI("%s(): bad when value 0x%08x", __func__, when);
+        return false;
+    }
+
+    switch (what) {
+    case HPSG_WHAT_MERGED_OBJECTS:
+    case HPSG_WHAT_DISTINCT_OBJECTS:
+        break;
+    default:
+        LOGI("%s(): bad what value 0x%08x", __func__, what);
+        return false;
+    }
+
+    if (dvmLockHeap()) {
+        if (!native) {
+            gDvm.gcHeap->ddmHpsgWhen = when;
+            gDvm.gcHeap->ddmHpsgWhat = what;
+        } else {
+            gDvm.gcHeap->ddmNhsgWhen = when;
+            gDvm.gcHeap->ddmNhsgWhat = what;
+        }
+//TODO: if what says we should dump immediately, signal (or do) it from here
+        dvmUnlockHeap();
+    } else {
+        LOGI("%s(): can't lock heap to set when/what", __func__);
+        return false;
+    }
+
+    return true;
+}
diff --git a/vm/alloc/DdmHeap.h b/vm/alloc/DdmHeap.h
new file mode 100644
index 0000000..32be78d
--- /dev/null
+++ b/vm/alloc/DdmHeap.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+/*
+ * DDM-specific internal heap functions.
+ */
+#ifndef DALVIK_ALLOC_DDMHEAP_H_
+#define DALVIK_ALLOC_DDMHEAP_H_
+
+/*
+ * Sends the current heap info to the DDM server.
+ * Should be called after a GC when gcHeap->ddmHpifWhen
+ * is non-zero.
+ */
+void dvmDdmSendHeapInfo(int reason, bool shouldLock);
+
+/*
+ * Walks through the heap and sends a series of
+ * HPST/NHST, HPSG/HPSO/NHSG, and HPEN/NHEN chunks that describe
+ * the contents of the GC or native heap.
+ *
+ * @param shouldLock If true, grab the heap lock.  If false,
+ *                   the heap lock must already be held.
+ * @param heap       If false, dump the GC heap; if true, dump the
+ *                   native heap.
+ */
+void dvmDdmSendHeapSegments(bool shouldLock, bool native);
+
+#endif  // DALVIK_ALLOC_DDMHEAP_H_
diff --git a/vm/alloc/Heap.cpp b/vm/alloc/Heap.cpp
new file mode 100644
index 0000000..9eee817
--- /dev/null
+++ b/vm/alloc/Heap.cpp
@@ -0,0 +1,721 @@
+/*
+ * 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.
+ */
+/*
+ * Garbage-collecting memory allocator.
+ */
+#include "Dalvik.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/Verify.h"
+#include "alloc/Heap.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/DdmHeap.h"
+#include "alloc/HeapSource.h"
+#include "alloc/MarkSweep.h"
+#include "os/os.h"
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <limits.h>
+#include <errno.h>
+
+static const GcSpec kGcForMallocSpec = {
+    true,  /* isPartial */
+    false,  /* isConcurrent */
+    true,  /* doPreserve */
+    "GC_FOR_ALLOC"
+};
+
+const GcSpec *GC_FOR_MALLOC = &kGcForMallocSpec;
+
+static const GcSpec kGcConcurrentSpec  = {
+    true,  /* isPartial */
+    true,  /* isConcurrent */
+    true,  /* doPreserve */
+    "GC_CONCURRENT"
+};
+
+const GcSpec *GC_CONCURRENT = &kGcConcurrentSpec;
+
+static const GcSpec kGcExplicitSpec = {
+    false,  /* isPartial */
+    true,  /* isConcurrent */
+    true,  /* doPreserve */
+    "GC_EXPLICIT"
+};
+
+const GcSpec *GC_EXPLICIT = &kGcExplicitSpec;
+
+static const GcSpec kGcBeforeOomSpec = {
+    false,  /* isPartial */
+    false,  /* isConcurrent */
+    false,  /* doPreserve */
+    "GC_BEFORE_OOM"
+};
+
+const GcSpec *GC_BEFORE_OOM = &kGcBeforeOomSpec;
+
+/*
+ * Initialize the GC heap.
+ *
+ * Returns true if successful, false otherwise.
+ */
+bool dvmHeapStartup()
+{
+    GcHeap *gcHeap;
+
+    if (gDvm.heapGrowthLimit == 0) {
+        gDvm.heapGrowthLimit = gDvm.heapMaximumSize;
+    }
+
+    gcHeap = dvmHeapSourceStartup(gDvm.heapStartingSize,
+                                  gDvm.heapMaximumSize,
+                                  gDvm.heapGrowthLimit);
+    if (gcHeap == NULL) {
+        return false;
+    }
+    gcHeap->ddmHpifWhen = 0;
+    gcHeap->ddmHpsgWhen = 0;
+    gcHeap->ddmHpsgWhat = 0;
+    gcHeap->ddmNhsgWhen = 0;
+    gcHeap->ddmNhsgWhat = 0;
+    gDvm.gcHeap = gcHeap;
+
+    /* Set up the lists we'll use for cleared reference objects.
+     */
+    gcHeap->clearedReferences = NULL;
+
+    if (!dvmCardTableStartup(gDvm.heapMaximumSize, gDvm.heapGrowthLimit)) {
+        LOGE_HEAP("card table startup failed.");
+        return false;
+    }
+
+    return true;
+}
+
+bool dvmHeapStartupAfterZygote()
+{
+    return dvmHeapSourceStartupAfterZygote();
+}
+
+void dvmHeapShutdown()
+{
+//TODO: make sure we're locked
+    if (gDvm.gcHeap != NULL) {
+        dvmCardTableShutdown();
+        /* Destroy the heap.  Any outstanding pointers will point to
+         * unmapped memory (unless/until someone else maps it).  This
+         * frees gDvm.gcHeap as a side-effect.
+         */
+        dvmHeapSourceShutdown(&gDvm.gcHeap);
+    }
+}
+
+/*
+ * Shutdown any threads internal to the heap.
+ */
+void dvmHeapThreadShutdown()
+{
+    dvmHeapSourceThreadShutdown();
+}
+
+/*
+ * Grab the lock, but put ourselves into THREAD_VMWAIT if it looks like
+ * we're going to have to wait on the mutex.
+ */
+bool dvmLockHeap()
+{
+    if (dvmTryLockMutex(&gDvm.gcHeapLock) != 0) {
+        Thread *self;
+        ThreadStatus oldStatus;
+
+        self = dvmThreadSelf();
+        oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+        dvmLockMutex(&gDvm.gcHeapLock);
+        dvmChangeStatus(self, oldStatus);
+    }
+
+    return true;
+}
+
+void dvmUnlockHeap()
+{
+    dvmUnlockMutex(&gDvm.gcHeapLock);
+}
+
+/* Do a full garbage collection, which may grow the
+ * heap as a side-effect if the live set is large.
+ */
+static void gcForMalloc(bool clearSoftReferences)
+{
+    if (gDvm.allocProf.enabled) {
+        Thread* self = dvmThreadSelf();
+        gDvm.allocProf.gcCount++;
+        if (self != NULL) {
+            self->allocProf.gcCount++;
+        }
+    }
+    /* This may adjust the soft limit as a side-effect.
+     */
+    const GcSpec *spec = clearSoftReferences ? GC_BEFORE_OOM : GC_FOR_MALLOC;
+    dvmCollectGarbageInternal(spec);
+}
+
+/* Try as hard as possible to allocate some memory.
+ */
+static void *tryMalloc(size_t size)
+{
+    void *ptr;
+
+    /* Don't try too hard if there's no way the allocation is
+     * going to succeed.  We have to collect SoftReferences before
+     * throwing an OOME, though.
+     */
+    if (size >= gDvm.heapGrowthLimit) {
+        LOGW("%zd byte allocation exceeds the %zd byte maximum heap size",
+             size, gDvm.heapGrowthLimit);
+        ptr = NULL;
+        goto collect_soft_refs;
+    }
+
+//TODO: figure out better heuristics
+//    There will be a lot of churn if someone allocates a bunch of
+//    big objects in a row, and we hit the frag case each time.
+//    A full GC for each.
+//    Maybe we grow the heap in bigger leaps
+//    Maybe we skip the GC if the size is large and we did one recently
+//      (number of allocations ago) (watch for thread effects)
+//    DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
+//      (or, at least, there are only 0-5 objects swept each time)
+
+    ptr = dvmHeapSourceAlloc(size);
+    if (ptr != NULL) {
+        return ptr;
+    }
+
+    /*
+     * The allocation failed.  If the GC is running, block until it
+     * completes and retry.
+     */
+    if (gDvm.gcHeap->gcRunning) {
+        /*
+         * The GC is concurrently tracing the heap.  Release the heap
+         * lock, wait for the GC to complete, and retrying allocating.
+         */
+        dvmWaitForConcurrentGcToComplete();
+        ptr = dvmHeapSourceAlloc(size);
+        if (ptr != NULL) {
+            return ptr;
+        }
+    }
+    /*
+     * Another failure.  Our thread was starved or there may be too
+     * many live objects.  Try a foreground GC.  This will have no
+     * effect if the concurrent GC is already running.
+     */
+    gcForMalloc(false);
+    ptr = dvmHeapSourceAlloc(size);
+    if (ptr != NULL) {
+        return ptr;
+    }
+
+    /* Even that didn't work;  this is an exceptional state.
+     * Try harder, growing the heap if necessary.
+     */
+    ptr = dvmHeapSourceAllocAndGrow(size);
+    if (ptr != NULL) {
+        size_t newHeapSize;
+
+        newHeapSize = dvmHeapSourceGetIdealFootprint();
+//TODO: may want to grow a little bit more so that the amount of free
+//      space is equal to the old free space + the utilization slop for
+//      the new allocation.
+        LOGI_HEAP("Grow heap (frag case) to "
+                "%zu.%03zuMB for %zu-byte allocation",
+                FRACTIONAL_MB(newHeapSize), size);
+        return ptr;
+    }
+
+    /* Most allocations should have succeeded by now, so the heap
+     * is really full, really fragmented, or the requested size is
+     * really big.  Do another GC, collecting SoftReferences this
+     * time.  The VM spec requires that all SoftReferences have
+     * been collected and cleared before throwing an OOME.
+     */
+//TODO: wait for the finalizers from the previous GC to finish
+collect_soft_refs:
+    LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation",
+            size);
+    gcForMalloc(true);
+    ptr = dvmHeapSourceAllocAndGrow(size);
+    if (ptr != NULL) {
+        return ptr;
+    }
+//TODO: maybe wait for finalizers and try one last time
+
+    LOGE_HEAP("Out of memory on a %zd-byte allocation.", size);
+//TODO: tell the HeapSource to dump its state
+    dvmDumpThread(dvmThreadSelf(), false);
+
+    return NULL;
+}
+
+/* Throw an OutOfMemoryError if there's a thread to attach it to.
+ * Avoid recursing.
+ *
+ * The caller must not be holding the heap lock, or else the allocations
+ * in dvmThrowException() will deadlock.
+ */
+static void throwOOME()
+{
+    Thread *self;
+
+    if ((self = dvmThreadSelf()) != NULL) {
+        /* If the current (failing) dvmMalloc() happened as part of thread
+         * creation/attachment before the thread became part of the root set,
+         * we can't rely on the thread-local trackedAlloc table, so
+         * we can't keep track of a real allocated OOME object.  But, since
+         * the thread is in the process of being created, it won't have
+         * a useful stack anyway, so we may as well make things easier
+         * by throwing the (stackless) pre-built OOME.
+         */
+        if (dvmIsOnThreadList(self) && !self->throwingOOME) {
+            /* Let ourselves know that we tried to throw an OOM
+             * error in the normal way in case we run out of
+             * memory trying to allocate it inside dvmThrowException().
+             */
+            self->throwingOOME = true;
+
+            /* Don't include a description string;
+             * one fewer allocation.
+             */
+            dvmThrowOutOfMemoryError(NULL);
+        } else {
+            /*
+             * This thread has already tried to throw an OutOfMemoryError,
+             * which probably means that we're running out of memory
+             * while recursively trying to throw.
+             *
+             * To avoid any more allocation attempts, "throw" a pre-built
+             * OutOfMemoryError object (which won't have a useful stack trace).
+             *
+             * Note that since this call can't possibly allocate anything,
+             * we don't care about the state of self->throwingOOME
+             * (which will usually already be set).
+             */
+            dvmSetException(self, gDvm.outOfMemoryObj);
+        }
+        /* We're done with the possible recursion.
+         */
+        self->throwingOOME = false;
+    }
+}
+
+/*
+ * Allocate storage on the GC heap.  We guarantee 8-byte alignment.
+ *
+ * The new storage is zeroed out.
+ *
+ * Note that, in rare cases, this could get called while a GC is in
+ * progress.  If a non-VM thread tries to attach itself through JNI,
+ * it will need to allocate some objects.  If this becomes annoying to
+ * deal with, we can block it at the source, but holding the allocation
+ * mutex should be enough.
+ *
+ * In rare circumstances (JNI AttachCurrentThread) we can be called
+ * from a non-VM thread.
+ *
+ * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
+ * (because it's being done for the interpreter "new" operation and will
+ * be part of the root set immediately) or we can't (because this allocation
+ * is for a brand new thread).
+ *
+ * Returns NULL and throws an exception on failure.
+ *
+ * TODO: don't do a GC if the debugger thinks all threads are suspended
+ */
+void* dvmMalloc(size_t size, int flags)
+{
+    void *ptr;
+
+    dvmLockHeap();
+
+    /* Try as hard as possible to allocate some memory.
+     */
+    ptr = tryMalloc(size);
+    if (ptr != NULL) {
+        /* We've got the memory.
+         */
+        if (gDvm.allocProf.enabled) {
+            Thread* self = dvmThreadSelf();
+            gDvm.allocProf.allocCount++;
+            gDvm.allocProf.allocSize += size;
+            if (self != NULL) {
+                self->allocProf.allocCount++;
+                self->allocProf.allocSize += size;
+            }
+        }
+    } else {
+        /* The allocation failed.
+         */
+
+        if (gDvm.allocProf.enabled) {
+            Thread* self = dvmThreadSelf();
+            gDvm.allocProf.failedAllocCount++;
+            gDvm.allocProf.failedAllocSize += size;
+            if (self != NULL) {
+                self->allocProf.failedAllocCount++;
+                self->allocProf.failedAllocSize += size;
+            }
+        }
+    }
+
+    dvmUnlockHeap();
+
+    if (ptr != NULL) {
+        /*
+         * If caller hasn't asked us not to track it, add it to the
+         * internal tracking list.
+         */
+        if ((flags & ALLOC_DONT_TRACK) == 0) {
+            dvmAddTrackedAlloc((Object*)ptr, NULL);
+        }
+    } else {
+        /*
+         * The allocation failed; throw an OutOfMemoryError.
+         */
+        throwOOME();
+    }
+
+    return ptr;
+}
+
+/*
+ * Returns true iff <obj> points to a valid allocated object.
+ */
+bool dvmIsValidObject(const Object* obj)
+{
+    /* Don't bother if it's NULL or not 8-byte aligned.
+     */
+    if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
+        /* Even if the heap isn't locked, this shouldn't return
+         * any false negatives.  The only mutation that could
+         * be happening is allocation, which means that another
+         * thread could be in the middle of a read-modify-write
+         * to add a new bit for a new object.  However, that
+         * RMW will have completed by the time any other thread
+         * could possibly see the new pointer, so there is no
+         * danger of dvmIsValidObject() being called on a valid
+         * pointer whose bit isn't set.
+         *
+         * Freeing will only happen during the sweep phase, which
+         * only happens while the heap is locked.
+         */
+        return dvmHeapSourceContains(obj);
+    }
+    return false;
+}
+
+size_t dvmObjectSizeInHeap(const Object *obj)
+{
+    return dvmHeapSourceChunkSize(obj);
+}
+
+static void verifyRootsAndHeap()
+{
+    dvmVerifyRoots();
+    dvmVerifyBitmap(dvmHeapSourceGetLiveBits());
+}
+
+/*
+ * Initiate garbage collection.
+ *
+ * NOTES:
+ * - If we don't hold gDvm.threadListLock, it's possible for a thread to
+ *   be added to the thread list while we work.  The thread should NOT
+ *   start executing, so this is only interesting when we start chasing
+ *   thread stacks.  (Before we do so, grab the lock.)
+ *
+ * We are not allowed to GC when the debugger has suspended the VM, which
+ * is awkward because debugger requests can cause allocations.  The easiest
+ * way to enforce this is to refuse to GC on an allocation made by the
+ * JDWP thread -- we have to expand the heap or fail.
+ */
+void dvmCollectGarbageInternal(const GcSpec* spec)
+{
+    GcHeap *gcHeap = gDvm.gcHeap;
+    u4 rootStart = 0 , rootEnd = 0;
+    u4 dirtyStart = 0, dirtyEnd = 0;
+    size_t numObjectsFreed, numBytesFreed;
+    size_t currAllocated, currFootprint;
+    size_t percentFree;
+    int oldThreadPriority = INT_MAX;
+
+    /* The heap lock must be held.
+     */
+
+    if (gcHeap->gcRunning) {
+        LOGW_HEAP("Attempted recursive GC");
+        return;
+    }
+
+    gcHeap->gcRunning = true;
+
+    dvmSuspendAllThreads(SUSPEND_FOR_GC);
+    rootStart = dvmGetRelativeTimeMsec();
+
+    /*
+     * If we are not marking concurrently raise the priority of the
+     * thread performing the garbage collection.
+     */
+    if (!spec->isConcurrent) {
+        oldThreadPriority = os_raiseThreadPriority();
+    }
+    if (gDvm.preVerify) {
+        LOGV_HEAP("Verifying roots and heap before GC");
+        verifyRootsAndHeap();
+    }
+
+    dvmMethodTraceGCBegin();
+
+    /* Set up the marking context.
+     */
+    if (!dvmHeapBeginMarkStep(spec->isPartial)) {
+        LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting");
+        dvmAbort();
+    }
+
+    /* Mark the set of objects that are strongly reachable from the roots.
+     */
+    LOGD_HEAP("Marking...");
+    dvmHeapMarkRootSet();
+
+    /* dvmHeapScanMarkedObjects() will build the lists of known
+     * instances of the Reference classes.
+     */
+    assert(gcHeap->softReferences == NULL);
+    assert(gcHeap->weakReferences == NULL);
+    assert(gcHeap->finalizerReferences == NULL);
+    assert(gcHeap->phantomReferences == NULL);
+    assert(gcHeap->clearedReferences == NULL);
+
+    if (spec->isConcurrent) {
+        /*
+         * Resume threads while tracing from the roots.  We unlock the
+         * heap to allow mutator threads to allocate from free space.
+         */
+        rootEnd = dvmGetRelativeTimeMsec();
+        dvmClearCardTable();
+        dvmUnlockHeap();
+        dvmResumeAllThreads(SUSPEND_FOR_GC);
+    }
+
+    /* Recursively mark any objects that marked objects point to strongly.
+     * If we're not collecting soft references, soft-reachable
+     * objects will also be marked.
+     */
+    LOGD_HEAP("Recursing...");
+    dvmHeapScanMarkedObjects();
+
+    if (spec->isConcurrent) {
+        /*
+         * Re-acquire the heap lock and perform the final thread
+         * suspension.
+         */
+        dvmLockHeap();
+        dvmSuspendAllThreads(SUSPEND_FOR_GC);
+        dirtyStart = dvmGetRelativeTimeMsec();
+        /*
+         * As no barrier intercepts root updates, we conservatively
+         * assume all roots may be gray and re-mark them.
+         */
+        dvmHeapReMarkRootSet();
+        /*
+         * With the exception of reference objects and weak interned
+         * strings, all gray objects should now be on dirty cards.
+         */
+        if (gDvm.verifyCardTable) {
+            dvmVerifyCardTable();
+        }
+        /*
+         * Recursively mark gray objects pointed to by the roots or by
+         * heap objects dirtied during the concurrent mark.
+         */
+        dvmHeapReScanMarkedObjects();
+    }
+
+    /*
+     * All strongly-reachable objects have now been marked.  Process
+     * weakly-reachable objects discovered while tracing.
+     */
+    dvmHeapProcessReferences(&gcHeap->softReferences,
+                             spec->doPreserve == false,
+                             &gcHeap->weakReferences,
+                             &gcHeap->finalizerReferences,
+                             &gcHeap->phantomReferences);
+
+#if defined(WITH_JIT)
+    /*
+     * Patching a chaining cell is very cheap as it only updates 4 words. It's
+     * the overhead of stopping all threads and synchronizing the I/D cache
+     * that makes it expensive.
+     *
+     * Therefore we batch those work orders in a queue and go through them
+     * when threads are suspended for GC.
+     */
+    dvmCompilerPerformSafePointChecks();
+#endif
+
+    LOGD_HEAP("Sweeping...");
+
+    dvmHeapSweepSystemWeaks();
+
+    /*
+     * Live objects have a bit set in the mark bitmap, swap the mark
+     * and live bitmaps.  The sweep can proceed concurrently viewing
+     * the new live bitmap as the old mark bitmap, and vice versa.
+     */
+    dvmHeapSourceSwapBitmaps();
+
+    if (gDvm.postVerify) {
+        LOGV_HEAP("Verifying roots and heap after GC");
+        verifyRootsAndHeap();
+    }
+
+    if (spec->isConcurrent) {
+        dirtyEnd = dvmGetRelativeTimeMsec();
+        dvmUnlockHeap();
+        dvmResumeAllThreads(SUSPEND_FOR_GC);
+    }
+    dvmHeapSweepUnmarkedObjects(spec->isPartial, spec->isConcurrent,
+                                &numObjectsFreed, &numBytesFreed);
+    LOGD_HEAP("Cleaning up...");
+    dvmHeapFinishMarkStep();
+    if (spec->isConcurrent) {
+        dvmLockHeap();
+    }
+
+    LOGD_HEAP("Done.");
+
+    /* Now's a good time to adjust the heap size, since
+     * we know what our utilization is.
+     *
+     * This doesn't actually resize any memory;
+     * it just lets the heap grow more when necessary.
+     */
+    dvmHeapSourceGrowForUtilization();
+
+    currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
+    currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
+
+    dvmMethodTraceGCEnd();
+    LOGV_HEAP("GC finished");
+
+    gcHeap->gcRunning = false;
+
+    LOGV_HEAP("Resuming threads");
+
+    if (spec->isConcurrent) {
+        /*
+         * Wake-up any threads that blocked after a failed allocation
+         * request.
+         */
+        dvmBroadcastCond(&gDvm.gcHeapCond);
+    }
+
+    if (!spec->isConcurrent) {
+        dirtyEnd = dvmGetRelativeTimeMsec();
+        dvmResumeAllThreads(SUSPEND_FOR_GC);
+        /*
+         * Restore the original thread scheduling priority if it was
+         * changed at the start of the current garbage collection.
+         */
+        if (oldThreadPriority != INT_MAX) {
+            os_lowerThreadPriority(oldThreadPriority);
+        }
+    }
+
+    /*
+     * Move queue of pending references back into Java.
+     */
+    dvmEnqueueClearedReferences(&gDvm.gcHeap->clearedReferences);
+
+    percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint);
+    if (!spec->isConcurrent) {
+        u4 markSweepTime = dirtyEnd - rootStart;
+        bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
+        LOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, paused %ums",
+             spec->reason,
+             isSmall ? "<" : "",
+             numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
+             percentFree,
+             currAllocated / 1024, currFootprint / 1024,
+             markSweepTime);
+    } else {
+        u4 rootTime = rootEnd - rootStart;
+        u4 dirtyTime = dirtyEnd - dirtyStart;
+        bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
+        LOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, paused %ums+%ums",
+             spec->reason,
+             isSmall ? "<" : "",
+             numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
+             percentFree,
+             currAllocated / 1024, currFootprint / 1024,
+             rootTime, dirtyTime);
+    }
+    if (gcHeap->ddmHpifWhen != 0) {
+        LOGD_HEAP("Sending VM heap info to DDM");
+        dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
+    }
+    if (gcHeap->ddmHpsgWhen != 0) {
+        LOGD_HEAP("Dumping VM heap to DDM");
+        dvmDdmSendHeapSegments(false, false);
+    }
+    if (gcHeap->ddmNhsgWhen != 0) {
+        LOGD_HEAP("Dumping native heap to DDM");
+        dvmDdmSendHeapSegments(false, true);
+    }
+}
+
+/*
+ * If the concurrent GC is running, wait for it to finish.  The caller
+ * must hold the heap lock.
+ *
+ * Note: the second dvmChangeStatus() could stall if we were in RUNNING
+ * on entry, and some other thread has asked us to suspend.  In that
+ * case we will be suspended with the heap lock held, which can lead to
+ * deadlock if the other thread tries to do something with the managed heap.
+ * For example, the debugger might suspend us and then execute a method that
+ * allocates memory.  We can avoid this situation by releasing the lock
+ * before self-suspending.  (The developer can work around this specific
+ * situation by single-stepping the VM.  Alternatively, we could disable
+ * concurrent GC when the debugger is attached, but that might change
+ * behavior more than is desirable.)
+ *
+ * This should not be a problem in production, because any GC-related
+ * activity will grab the lock before issuing a suspend-all.  (We may briefly
+ * suspend when the GC thread calls dvmUnlockHeap before dvmResumeAllThreads,
+ * but there's no risk of deadlock.)
+ */
+void dvmWaitForConcurrentGcToComplete()
+{
+    Thread *self = dvmThreadSelf();
+    assert(self != NULL);
+    while (gDvm.gcHeap->gcRunning) {
+        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+        dvmWaitCond(&gDvm.gcHeapCond, &gDvm.gcHeapLock);
+        dvmChangeStatus(self, oldStatus);
+    }
+}
diff --git a/vm/alloc/Heap.h b/vm/alloc/Heap.h
new file mode 100644
index 0000000..9875951
--- /dev/null
+++ b/vm/alloc/Heap.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+/*
+ * Internal heap functions
+ */
+#ifndef DALVIK_ALLOC_HEAP_H_
+#define DALVIK_ALLOC_HEAP_H_
+
+struct GcSpec {
+  /* If true, only the application heap is threatened. */
+  bool isPartial;
+  /* If true, the trace is run concurrently with the mutator. */
+  bool isConcurrent;
+  /* Toggles for the soft reference clearing policy. */
+  bool doPreserve;
+  /* A name for this garbage collection mode. */
+  const char *reason;
+};
+
+/* Not enough space for an "ordinary" Object to be allocated. */
+extern const GcSpec *GC_FOR_MALLOC;
+
+/* Automatic GC triggered by exceeding a heap occupancy threshold. */
+extern const GcSpec *GC_CONCURRENT;
+
+/* Explicit GC via Runtime.gc(), VMRuntime.gc(), or SIGUSR1. */
+extern const GcSpec *GC_EXPLICIT;
+
+/* Final attempt to reclaim memory before throwing an OOM. */
+extern const GcSpec *GC_BEFORE_OOM;
+
+/*
+ * Initialize the GC heap.
+ *
+ * Returns true if successful, false otherwise.
+ */
+bool dvmHeapStartup(void);
+
+/*
+ * Initialization that needs to wait until after leaving zygote mode.
+ * This needs to be called before the first allocation or GC that
+ * happens after forking.
+ */
+bool dvmHeapStartupAfterZygote(void);
+
+/*
+ * Tear down the GC heap.
+ *
+ * Frees all memory allocated via dvmMalloc() as
+ * a side-effect.
+ */
+void dvmHeapShutdown(void);
+
+/*
+ * Stops any threads internal to the garbage collector.  Called before
+ * the heap itself is shutdown.
+ */
+void dvmHeapThreadShutdown(void);
+
+#if 0       // needs to be in Alloc.h so debug code can find it.
+/*
+ * Returns a number of bytes greater than or
+ * equal to the size of the named object in the heap.
+ *
+ * Specifically, it returns the size of the heap
+ * chunk which contains the object.
+ */
+size_t dvmObjectSizeInHeap(const Object *obj);
+#endif
+
+/*
+ * Run the garbage collector without doing any locking.
+ */
+void dvmCollectGarbageInternal(const GcSpec *spec);
+
+/*
+ * Blocks the calling thread until the garbage collector is inactive.
+ * The caller must hold the heap lock as this call releases and
+ * re-acquires the heap lock.  After returning, no garbage collection
+ * will be in progress and the heap lock will be held by the caller.
+ */
+void dvmWaitForConcurrentGcToComplete(void);
+
+/*
+ * Returns true iff <obj> points to a valid allocated object.
+ */
+bool dvmIsValidObject(const Object* obj);
+
+#endif  // DALVIK_ALLOC_HEAP_H_
diff --git a/vm/alloc/HeapBitmap.cpp b/vm/alloc/HeapBitmap.cpp
new file mode 100644
index 0000000..8b65287
--- /dev/null
+++ b/vm/alloc/HeapBitmap.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "HeapBitmap.h"
+#include <sys/mman.h>   /* for PROT_* */
+
+/*
+ * Initialize a HeapBitmap so that it points to a bitmap large
+ * enough to cover a heap at <base> of <maxSize> bytes, where
+ * objects are guaranteed to be HB_OBJECT_ALIGNMENT-aligned.
+ */
+bool dvmHeapBitmapInit(HeapBitmap *hb, const void *base, size_t maxSize,
+                       const char *name)
+{
+    void *bits;
+    size_t bitsLen;
+
+    assert(hb != NULL);
+    assert(name != NULL);
+    bitsLen = HB_OFFSET_TO_INDEX(maxSize) * sizeof(*hb->bits);
+    bits = dvmAllocRegion(bitsLen, PROT_READ | PROT_WRITE, name);
+    if (bits == NULL) {
+        LOGE("Could not mmap %zd-byte ashmem region '%s'", bitsLen, name);
+        return false;
+    }
+    hb->bits = (unsigned long *)bits;
+    hb->bitsLen = hb->allocLen = bitsLen;
+    hb->base = (uintptr_t)base;
+    hb->max = hb->base - 1;
+    return true;
+}
+
+/*
+ * Clean up any resources associated with the bitmap.
+ */
+void dvmHeapBitmapDelete(HeapBitmap *hb)
+{
+    assert(hb != NULL);
+
+    if (hb->bits != NULL) {
+        munmap((char *)hb->bits, hb->allocLen);
+    }
+    memset(hb, 0, sizeof(*hb));
+}
+
+/*
+ * Fill the bitmap with zeroes.  Returns the bitmap's memory to
+ * the system as a side-effect.
+ */
+void dvmHeapBitmapZero(HeapBitmap *hb)
+{
+    assert(hb != NULL);
+
+    if (hb->bits != NULL) {
+        /* This returns the memory to the system.
+         * Successive page faults will return zeroed memory.
+         */
+        madvise(hb->bits, hb->bitsLen, MADV_DONTNEED);
+        hb->max = hb->base - 1;
+    }
+}
+
+/*
+ * Return true iff <obj> is within the range of pointers that this
+ * bitmap could potentially cover, even if a bit has not been set
+ * for it.
+ */
+bool dvmHeapBitmapCoversAddress(const HeapBitmap *hb, const void *obj)
+{
+    assert(hb != NULL);
+    if (obj != NULL) {
+        const uintptr_t offset = (uintptr_t)obj - hb->base;
+        const size_t index = HB_OFFSET_TO_INDEX(offset);
+        return index < hb->bitsLen / sizeof(*hb->bits);
+    }
+    return false;
+}
+
+/*
+ * Visits set bits in address order.  The callback is not permitted to
+ * change the bitmap bits or max during the traversal.
+ */
+void dvmHeapBitmapWalk(const HeapBitmap *bitmap, BitmapCallback *callback,
+                       void *arg)
+{
+    assert(bitmap != NULL);
+    assert(bitmap->bits != NULL);
+    assert(callback != NULL);
+    uintptr_t end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
+    for (uintptr_t i = 0; i <= end; ++i) {
+        unsigned long word = bitmap->bits[i];
+        if (UNLIKELY(word != 0)) {
+            unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
+            uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
+            while (word != 0) {
+                const int shift = CLZ(word);
+                Object* obj = (Object *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
+                (*callback)(obj, arg);
+                word &= ~(highBit >> shift);
+            }
+        }
+    }
+}
+
+/*
+ * Similar to dvmHeapBitmapWalk but the callback routine is permitted
+ * to change the bitmap bits and max during traversal.  Used by the
+ * the root marking scan exclusively.
+ *
+ * The callback is invoked with a finger argument.  The finger is a
+ * pointer to an address not yet visited by the traversal.  If the
+ * callback sets a bit for an address at or above the finger, this
+ * address will be visited by the traversal.  If the callback sets a
+ * bit for an address below the finger, this address will not be
+ * visited.
+ */
+void dvmHeapBitmapScanWalk(HeapBitmap *bitmap,
+                           BitmapScanCallback *callback, void *arg)
+{
+    assert(bitmap != NULL);
+    assert(bitmap->bits != NULL);
+    assert(callback != NULL);
+    uintptr_t end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
+    uintptr_t i;
+    for (i = 0; i <= end; ++i) {
+        unsigned long word = bitmap->bits[i];
+        if (UNLIKELY(word != 0)) {
+            unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
+            uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
+            void *finger = (void *)(HB_INDEX_TO_OFFSET(i + 1) + bitmap->base);
+            while (word != 0) {
+                const int shift = CLZ(word);
+                Object *obj = (Object *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
+                (*callback)(obj, finger, arg);
+                word &= ~(highBit >> shift);
+            }
+            end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
+        }
+    }
+}
+
+/*
+ * Walk through the bitmaps in increasing address order, and find the
+ * object pointers that correspond to garbage objects.  Call
+ * <callback> zero or more times with lists of these object pointers.
+ *
+ * The callback is not permitted to increase the max of either bitmap.
+ */
+void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
+                            uintptr_t base, uintptr_t max,
+                            BitmapSweepCallback *callback, void *callbackArg)
+{
+    assert(liveHb != NULL);
+    assert(liveHb->bits != NULL);
+    assert(markHb != NULL);
+    assert(markHb->bits != NULL);
+    assert(liveHb->base == markHb->base);
+    assert(liveHb->bitsLen == markHb->bitsLen);
+    assert(callback != NULL);
+    assert(base <= max);
+    assert(base >= liveHb->base);
+    assert(max <= liveHb->max);
+    if (liveHb->max < liveHb->base) {
+        /* Easy case; both are obviously empty.
+         */
+        return;
+    }
+    void *pointerBuf[4 * HB_BITS_PER_WORD];
+    void **pb = pointerBuf;
+    size_t start = HB_OFFSET_TO_INDEX(base - liveHb->base);
+    size_t end = HB_OFFSET_TO_INDEX(max - liveHb->base);
+    unsigned long *live = liveHb->bits;
+    unsigned long *mark = markHb->bits;
+    for (size_t i = start; i <= end; i++) {
+        unsigned long garbage = live[i] & ~mark[i];
+        if (UNLIKELY(garbage != 0)) {
+            unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
+            uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + liveHb->base;
+            while (garbage != 0) {
+                int shift = CLZ(garbage);
+                garbage &= ~(highBit >> shift);
+                *pb++ = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
+            }
+            /* Make sure that there are always enough slots available */
+            /* for an entire word of 1s. */
+            if (pb >= &pointerBuf[NELEM(pointerBuf) - HB_BITS_PER_WORD]) {
+                (*callback)(pb - pointerBuf, pointerBuf, callbackArg);
+                pb = pointerBuf;
+            }
+        }
+    }
+    if (pb > pointerBuf) {
+        (*callback)(pb - pointerBuf, pointerBuf, callbackArg);
+    }
+}
diff --git a/vm/alloc/HeapBitmap.h b/vm/alloc/HeapBitmap.h
new file mode 100644
index 0000000..9f2a0a1
--- /dev/null
+++ b/vm/alloc/HeapBitmap.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+#ifndef DALVIK_HEAP_BITMAP_H_
+#define DALVIK_HEAP_BITMAP_H_
+
+#include <limits.h>
+#include <stdint.h>
+
+#define HB_OBJECT_ALIGNMENT 8
+#define HB_BITS_PER_WORD (sizeof(unsigned long) * CHAR_BIT)
+
+/* <offset> is the difference from .base to a pointer address.
+ * <index> is the index of .bits that contains the bit representing
+ *         <offset>.
+ */
+#define HB_OFFSET_TO_INDEX(offset_) \
+    ((uintptr_t)(offset_) / HB_OBJECT_ALIGNMENT / HB_BITS_PER_WORD)
+#define HB_INDEX_TO_OFFSET(index_) \
+    ((uintptr_t)(index_) * HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD)
+
+#define HB_OFFSET_TO_BYTE_INDEX(offset_) \
+  (HB_OFFSET_TO_INDEX(offset_) * sizeof(*((HeapBitmap *)0)->bits))
+
+/* Pack the bits in backwards so they come out in address order
+ * when using CLZ.
+ */
+#define HB_OFFSET_TO_MASK(offset_) \
+    (1 << \
+        (31-(((uintptr_t)(offset_) / HB_OBJECT_ALIGNMENT) % HB_BITS_PER_WORD)))
+
+struct HeapBitmap {
+    /* The bitmap data, which points to an mmap()ed area of zeroed
+     * anonymous memory.
+     */
+    unsigned long *bits;
+
+    /* The size of the used memory pointed to by bits, in bytes.  This
+     * value changes when the bitmap is shrunk.
+     */
+    size_t bitsLen;
+
+    /* The real size of the memory pointed to by bits.  This is the
+     * number of bytes we requested from the allocator and does not
+     * change.
+     */
+    size_t allocLen;
+
+    /* The base address, which corresponds to the first bit in
+     * the bitmap.
+     */
+    uintptr_t base;
+
+    /* The highest pointer value ever returned by an allocation
+     * from this heap.  I.e., the highest address that may correspond
+     * to a set bit.  If there are no bits set, (max < base).
+     */
+    uintptr_t max;
+};
+
+/*
+ * Callback types used by the walking routines.
+ */
+typedef void BitmapCallback(Object *obj, void *arg);
+typedef void BitmapScanCallback(Object *obj, void *finger, void *arg);
+typedef void BitmapSweepCallback(size_t numPtrs, void **ptrs, void *arg);
+
+/*
+ * Initialize a HeapBitmap so that it points to a bitmap large
+ * enough to cover a heap at <base> of <maxSize> bytes, where
+ * objects are guaranteed to be HB_OBJECT_ALIGNMENT-aligned.
+ */
+bool dvmHeapBitmapInit(HeapBitmap *hb, const void *base, size_t maxSize,
+        const char *name);
+
+/*
+ * Clean up any resources associated with the bitmap.
+ */
+void dvmHeapBitmapDelete(HeapBitmap *hb);
+
+/*
+ * Fill the bitmap with zeroes.  Returns the bitmap's memory to
+ * the system as a side-effect.
+ */
+void dvmHeapBitmapZero(HeapBitmap *hb);
+
+/*
+ * Returns true if the address range of the bitmap covers the object
+ * address.
+ */
+bool dvmHeapBitmapCoversAddress(const HeapBitmap *hb, const void *obj);
+
+/*
+ * Applies the callback function to each set address in the bitmap.
+ */
+void dvmHeapBitmapWalk(const HeapBitmap *bitmap,
+                       BitmapCallback *callback, void *callbackArg);
+
+/*
+ * Like dvmHeapBitmapWalk but takes a callback function with a finger
+ * address.
+ */
+void dvmHeapBitmapScanWalk(HeapBitmap *bitmap,
+                           BitmapScanCallback *callback, void *arg);
+
+/*
+ * Walk through the bitmaps in increasing address order, and find the
+ * object pointers that correspond to garbage objects.  Call
+ * <callback> zero or more times with lists of these object pointers.
+ *
+ * The callback is not permitted to increase the max of either bitmap.
+ */
+void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
+                            uintptr_t base, uintptr_t max,
+                            BitmapSweepCallback *callback, void *callbackArg);
+
+#endif  // DALVIK_HEAP_BITMAP_H_
diff --git a/vm/alloc/HeapBitmapInlines.h b/vm/alloc/HeapBitmapInlines.h
new file mode 100644
index 0000000..a5e9be4
--- /dev/null
+++ b/vm/alloc/HeapBitmapInlines.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef DALVIK_HEAP_BITMAPINLINES_H_
+#define DALVIK_HEAP_BITMAPINLINES_H_
+
+static unsigned long dvmHeapBitmapSetAndReturnObjectBit(HeapBitmap *hb, const void *obj) __attribute__((used));
+static void dvmHeapBitmapSetObjectBit(HeapBitmap *hb, const void *obj) __attribute__((used));
+static void dvmHeapBitmapClearObjectBit(HeapBitmap *hb, const void *obj) __attribute__((used));
+
+/*
+ * Internal function; do not call directly.
+ */
+static unsigned long _heapBitmapModifyObjectBit(HeapBitmap *hb, const void *obj,
+                                                bool setBit, bool returnOld)
+{
+    const uintptr_t offset = (uintptr_t)obj - hb->base;
+    const size_t index = HB_OFFSET_TO_INDEX(offset);
+    const unsigned long mask = HB_OFFSET_TO_MASK(offset);
+
+    assert(hb->bits != NULL);
+    assert((uintptr_t)obj >= hb->base);
+    assert(index < hb->bitsLen / sizeof(*hb->bits));
+    if (setBit) {
+        if ((uintptr_t)obj > hb->max) {
+            hb->max = (uintptr_t)obj;
+        }
+        if (returnOld) {
+            unsigned long *p = hb->bits + index;
+            const unsigned long word = *p;
+            *p |= mask;
+            return word & mask;
+        } else {
+            hb->bits[index] |= mask;
+        }
+    } else {
+        hb->bits[index] &= ~mask;
+    }
+    return false;
+}
+
+/*
+ * Sets the bit corresponding to <obj>, and returns the previous value
+ * of that bit (as zero or non-zero). Does no range checking to see if
+ * <obj> is outside of the coverage of the bitmap.
+ *
+ * NOTE: casting this value to a bool is dangerous, because higher
+ * set bits will be lost.
+ */
+static unsigned long dvmHeapBitmapSetAndReturnObjectBit(HeapBitmap *hb,
+                                                        const void *obj)
+{
+    return _heapBitmapModifyObjectBit(hb, obj, true, true);
+}
+
+/*
+ * Sets the bit corresponding to <obj>, and widens the range of seen
+ * pointers if necessary.  Does no range checking.
+ */
+static void dvmHeapBitmapSetObjectBit(HeapBitmap *hb, const void *obj)
+{
+    _heapBitmapModifyObjectBit(hb, obj, true, false);
+}
+
+/*
+ * Clears the bit corresponding to <obj>.  Does no range checking.
+ */
+static void dvmHeapBitmapClearObjectBit(HeapBitmap *hb, const void *obj)
+{
+    _heapBitmapModifyObjectBit(hb, obj, false, false);
+}
+
+/*
+ * Returns the current value of the bit corresponding to <obj>,
+ * as zero or non-zero.  Does no range checking.
+ *
+ * NOTE: casting this value to a bool is dangerous, because higher
+ * set bits will be lost.
+ */
+static unsigned long dvmHeapBitmapIsObjectBitSet(const HeapBitmap *hb,
+                                                 const void *obj)
+{
+    assert(dvmHeapBitmapCoversAddress(hb, obj));
+    assert(hb->bits != NULL);
+    assert((uintptr_t)obj >= hb->base);
+    if ((uintptr_t)obj <= hb->max) {
+        const uintptr_t offset = (uintptr_t)obj - hb->base;
+        return hb->bits[HB_OFFSET_TO_INDEX(offset)] & HB_OFFSET_TO_MASK(offset);
+    } else {
+        return 0;
+    }
+}
+
+#endif  // DALVIK_HEAP_BITMAPINLINES_H_
diff --git a/vm/alloc/HeapDebug.cpp b/vm/alloc/HeapDebug.cpp
new file mode 100644
index 0000000..9bd6799
--- /dev/null
+++ b/vm/alloc/HeapDebug.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "HeapSource.h"
+
+int dvmGetHeapDebugInfo(HeapDebugInfoType info)
+{
+    switch (info) {
+    case kVirtualHeapSize:
+        return (int)dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
+    case kVirtualHeapAllocated:
+        return (int)dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
+    case kVirtualHeapMaximumSize:
+        return dvmHeapSourceGetMaximumSize();
+    default:
+        return -1;
+    }
+}
diff --git a/vm/alloc/HeapDebug.h b/vm/alloc/HeapDebug.h
new file mode 100644
index 0000000..de4d65b
--- /dev/null
+++ b/vm/alloc/HeapDebug.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef DALVIK_HEAPDEBUG_H_
+#define DALVIK_HEAPDEBUG_H_
+
+enum HeapDebugInfoType {
+    kVirtualHeapSize = 0,
+    kNativeHeapSize = 1,
+    kVirtualHeapAllocated = 2,
+    kNativeHeapAllocated = 3,
+    kVirtualHeapMaximumSize = 4
+};
+
+/* Return the specified value.
+ * Returns -1 if the type is unknown.
+ */
+int dvmGetHeapDebugInfo(HeapDebugInfoType info);
+
+#endif  // DALVIK_HEAPDEBUG_H_
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
new file mode 100644
index 0000000..185af1c
--- /dev/null
+++ b/vm/alloc/HeapInternal.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+/*
+ * Types and macros used internally by the heap.
+ */
+#ifndef DALVIK_ALLOC_HEAP_INTERNAL_H_
+#define DALVIK_ALLOC_HEAP_INTERNAL_H_
+
+#include "MarkSweep.h"
+
+struct HeapSource;
+
+struct GcHeap {
+    HeapSource *heapSource;
+
+    /* Linked lists of subclass instances of java/lang/ref/Reference
+     * that we find while recursing.  The "next" pointers are hidden
+     * in the Reference objects' pendingNext fields.  These lists are
+     * cleared and rebuilt each time the GC runs.
+     */
+    Object *softReferences;
+    Object *weakReferences;
+    Object *finalizerReferences;
+    Object *phantomReferences;
+
+    /* The list of Reference objects that need to be enqueued.
+     */
+    Object *clearedReferences;
+
+    /* The current state of the mark step.
+     * Only valid during a GC.
+     */
+    GcMarkContext markContext;
+
+    /* GC's card table */
+    u1* cardTableBase;
+    size_t cardTableLength;
+    size_t cardTableMaxLength;
+    size_t cardTableOffset;
+
+    /* Is the GC running?  Used to avoid recursive calls to GC.
+     */
+    bool gcRunning;
+
+    /*
+     * Debug control values
+     */
+    int ddmHpifWhen;
+    int ddmHpsgWhen;
+    int ddmHpsgWhat;
+    int ddmNhsgWhen;
+    int ddmNhsgWhat;
+};
+
+bool dvmLockHeap(void);
+void dvmUnlockHeap(void);
+
+/*
+ * Logging helpers
+ */
+
+#define HEAP_LOG_TAG      LOG_TAG "-heap"
+
+#if LOG_NDEBUG
+#define LOGV_HEAP(...)    ((void)0)
+#define LOGD_HEAP(...)    ((void)0)
+#else
+#define LOGV_HEAP(...)    LOG(LOG_VERBOSE, HEAP_LOG_TAG, __VA_ARGS__)
+#define LOGD_HEAP(...)    LOG(LOG_DEBUG, HEAP_LOG_TAG, __VA_ARGS__)
+#endif
+#define LOGI_HEAP(...) \
+    do { \
+        if (!gDvm.zygote) { LOG(LOG_INFO, HEAP_LOG_TAG, __VA_ARGS__); } \
+    } while (0)
+
+#define LOGW_HEAP(...)    LOG(LOG_WARN, HEAP_LOG_TAG, __VA_ARGS__)
+#define LOGE_HEAP(...)    LOG(LOG_ERROR, HEAP_LOG_TAG, __VA_ARGS__)
+
+#define FRACTIONAL_MB(n)    (n) / (1024 * 1024), \
+                            ((((n) % (1024 * 1024)) / 1024) * 1000) / 1024
+#define FRACTIONAL_PCT(n,max)    ((n) * 100) / (max), \
+                                 (((n) * 1000) / (max)) % 10
+
+#endif  // DALVIK_ALLOC_HEAP_INTERNAL_H_
diff --git a/vm/alloc/HeapSource.cpp b/vm/alloc/HeapSource.cpp
new file mode 100644
index 0000000..f61724a
--- /dev/null
+++ b/vm/alloc/HeapSource.cpp
@@ -0,0 +1,1374 @@
+/*
+ * 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.
+ */
+
+#include <cutils/mspace.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#define SIZE_MAX UINT_MAX  // TODO: get SIZE_MAX from stdint.h
+
+#include "Dalvik.h"
+#include "alloc/Heap.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/HeapSource.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapBitmapInlines.h"
+
+// TODO: find a real header file for these.
+extern "C" int dlmalloc_trim(size_t);
+extern "C" void dlmalloc_walk_free_pages(void(*)(void*, void*, void*), void*);
+
+static void snapIdealFootprint();
+static void setIdealFootprint(size_t max);
+static size_t getMaximumSize(const HeapSource *hs);
+static void trimHeaps();
+
+#define HEAP_UTILIZATION_MAX        1024
+#define DEFAULT_HEAP_UTILIZATION    512     // Range 1..HEAP_UTILIZATION_MAX
+#define HEAP_IDEAL_FREE             (2 * 1024 * 1024)
+#define HEAP_MIN_FREE               (HEAP_IDEAL_FREE / 4)
+
+/* Number of seconds to wait after a GC before performing a heap trim
+ * operation to reclaim unused pages.
+ */
+#define HEAP_TRIM_IDLE_TIME_SECONDS 5
+
+/* Start a concurrent collection when free memory falls under this
+ * many bytes.
+ */
+#define CONCURRENT_START (128 << 10)
+
+/* The next GC will not be concurrent when free memory after a GC is
+ * under this many bytes.
+ */
+#define CONCURRENT_MIN_FREE (CONCURRENT_START + (128 << 10))
+
+#define HS_BOILERPLATE() \
+    do { \
+        assert(gDvm.gcHeap != NULL); \
+        assert(gDvm.gcHeap->heapSource != NULL); \
+        assert(gHs == gDvm.gcHeap->heapSource); \
+    } while (0)
+
+struct Heap {
+    /* The mspace to allocate from.
+     */
+    mspace msp;
+
+    /* The largest size that this heap is allowed to grow to.
+     */
+    size_t maximumSize;
+
+    /* Number of bytes allocated from this mspace for objects,
+     * including any overhead.  This value is NOT exact, and
+     * should only be used as an input for certain heuristics.
+     */
+    size_t bytesAllocated;
+
+    /* Number of bytes allocated from this mspace at which a
+     * concurrent garbage collection will be started.
+     */
+    size_t concurrentStartBytes;
+
+    /* Number of objects currently allocated from this mspace.
+     */
+    size_t objectsAllocated;
+
+    /*
+     * The lowest address of this heap, inclusive.
+     */
+    char *base;
+
+    /*
+     * The highest address of this heap, exclusive.
+     */
+    char *limit;
+};
+
+struct HeapSource {
+    /* Target ideal heap utilization ratio; range 1..HEAP_UTILIZATION_MAX
+     */
+    size_t targetUtilization;
+
+    /* The starting heap size.
+     */
+    size_t startSize;
+
+    /* The largest that the heap source as a whole is allowed to grow.
+     */
+    size_t maximumSize;
+
+    /*
+     * The largest size we permit the heap to grow.  This value allows
+     * the user to limit the heap growth below the maximum size.  This
+     * is a work around until we can dynamically set the maximum size.
+     * This value can range between the starting size and the maximum
+     * size but should never be set below the current footprint of the
+     * heap.
+     */
+    size_t growthLimit;
+
+    /* The desired max size of the heap source as a whole.
+     */
+    size_t idealSize;
+
+    /* The maximum number of bytes allowed to be allocated from the
+     * active heap before a GC is forced.  This is used to "shrink" the
+     * heap in lieu of actual compaction.
+     */
+    size_t softLimit;
+
+    /* The heaps; heaps[0] is always the active heap,
+     * which new objects should be allocated from.
+     */
+    Heap heaps[HEAP_SOURCE_MAX_HEAP_COUNT];
+
+    /* The current number of heaps.
+     */
+    size_t numHeaps;
+
+    /* True if zygote mode was active when the HeapSource was created.
+     */
+    bool sawZygote;
+
+    /*
+     * The base address of the virtual memory reservation.
+     */
+    char *heapBase;
+
+    /*
+     * The length in bytes of the virtual memory reservation.
+     */
+    size_t heapLength;
+
+    /*
+     * The live object bitmap.
+     */
+    HeapBitmap liveBits;
+
+    /*
+     * The mark bitmap.
+     */
+    HeapBitmap markBits;
+
+    /*
+     * State for the GC daemon.
+     */
+    bool hasGcThread;
+    pthread_t gcThread;
+    bool gcThreadShutdown;
+    pthread_mutex_t gcThreadMutex;
+    pthread_cond_t gcThreadCond;
+    bool gcThreadTrimNeeded;
+};
+
+#define hs2heap(hs_) (&((hs_)->heaps[0]))
+
+/*
+ * Returns true iff a soft limit is in effect for the active heap.
+ */
+static bool isSoftLimited(const HeapSource *hs)
+{
+    /* softLimit will be either SIZE_MAX or the limit for the
+     * active mspace.  idealSize can be greater than softLimit
+     * if there is more than one heap.  If there is only one
+     * heap, a non-SIZE_MAX softLimit should always be the same
+     * as idealSize.
+     */
+    return hs->softLimit <= hs->idealSize;
+}
+
+/*
+ * Returns approximately the maximum number of bytes allowed to be
+ * allocated from the active heap before a GC is forced.
+ */
+static size_t getAllocLimit(const HeapSource *hs)
+{
+    if (isSoftLimited(hs)) {
+        return hs->softLimit;
+    } else {
+        return mspace_max_allowed_footprint(hs2heap(hs)->msp);
+    }
+}
+
+/*
+ * Returns the current footprint of all heaps.  If includeActive
+ * is false, don't count the heap at index 0.
+ */
+static size_t oldHeapOverhead(const HeapSource *hs, bool includeActive)
+{
+    size_t footprint = 0;
+    size_t i;
+
+    if (includeActive) {
+        i = 0;
+    } else {
+        i = 1;
+    }
+    for (/* i = i */; i < hs->numHeaps; i++) {
+//TODO: include size of bitmaps?  If so, don't use bitsLen, listen to .max
+        footprint += mspace_footprint(hs->heaps[i].msp);
+    }
+    return footprint;
+}
+
+/*
+ * Returns the heap that <ptr> could have come from, or NULL
+ * if it could not have come from any heap.
+ */
+static Heap *ptr2heap(const HeapSource *hs, const void *ptr)
+{
+    const size_t numHeaps = hs->numHeaps;
+
+    if (ptr != NULL) {
+        for (size_t i = 0; i < numHeaps; i++) {
+            const Heap *const heap = &hs->heaps[i];
+
+            if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) {
+                return (Heap *)heap;
+            }
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Functions to update heapSource->bytesAllocated when an object
+ * is allocated or freed.  mspace_usable_size() will give
+ * us a much more accurate picture of heap utilization than
+ * the requested byte sizes would.
+ *
+ * These aren't exact, and should not be treated as such.
+ */
+static void countAllocation(Heap *heap, const void *ptr)
+{
+    assert(heap->bytesAllocated < mspace_footprint(heap->msp));
+
+    heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
+            HEAP_SOURCE_CHUNK_OVERHEAD;
+    heap->objectsAllocated++;
+    HeapSource* hs = gDvm.gcHeap->heapSource;
+    dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr);
+
+    assert(heap->bytesAllocated < mspace_footprint(heap->msp));
+}
+
+static void countFree(Heap *heap, const void *ptr, size_t *numBytes)
+{
+    size_t delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
+    assert(delta > 0);
+    if (delta < heap->bytesAllocated) {
+        heap->bytesAllocated -= delta;
+    } else {
+        heap->bytesAllocated = 0;
+    }
+    HeapSource* hs = gDvm.gcHeap->heapSource;
+    dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr);
+    if (heap->objectsAllocated > 0) {
+        heap->objectsAllocated--;
+    }
+    *numBytes += delta;
+}
+
+static HeapSource *gHs = NULL;
+
+static mspace createMspace(void *base, size_t startSize, size_t maximumSize)
+{
+    /* Create an unlocked dlmalloc mspace to use as
+     * a heap source.
+     *
+     * We start off reserving startSize / 2 bytes but
+     * letting the heap grow to startSize.  This saves
+     * memory in the case where a process uses even less
+     * than the starting size.
+     */
+    LOGV_HEAP("Creating VM heap of size %zu", startSize);
+    errno = 0;
+
+    mspace msp = create_contiguous_mspace_with_base(startSize/2,
+            maximumSize, /*locked=*/false, base);
+    if (msp != NULL) {
+        /* Don't let the heap grow past the starting size without
+         * our intervention.
+         */
+        mspace_set_max_allowed_footprint(msp, startSize);
+    } else {
+        /* There's no guarantee that errno has meaning when the call
+         * fails, but it often does.
+         */
+        LOGE_HEAP("Can't create VM heap of size (%zu,%zu): %s",
+            startSize/2, maximumSize, strerror(errno));
+    }
+
+    return msp;
+}
+
+/*
+ * Add the initial heap.  Returns false if the initial heap was
+ * already added to the heap source.
+ */
+static bool addInitialHeap(HeapSource *hs, mspace msp, size_t maximumSize)
+{
+    assert(hs != NULL);
+    assert(msp != NULL);
+    if (hs->numHeaps != 0) {
+        return false;
+    }
+    hs->heaps[0].msp = msp;
+    hs->heaps[0].maximumSize = maximumSize;
+    hs->heaps[0].concurrentStartBytes = SIZE_MAX;
+    hs->heaps[0].base = hs->heapBase;
+    hs->heaps[0].limit = hs->heapBase + hs->heaps[0].maximumSize;
+    hs->numHeaps = 1;
+    return true;
+}
+
+/*
+ * Adds an additional heap to the heap source.  Returns false if there
+ * are too many heaps or insufficient free space to add another heap.
+ */
+static bool addNewHeap(HeapSource *hs)
+{
+    Heap heap;
+
+    assert(hs != NULL);
+    if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
+        LOGE("Attempt to create too many heaps (%zd >= %zd)",
+                hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT);
+        dvmAbort();
+        return false;
+    }
+
+    memset(&heap, 0, sizeof(heap));
+
+    /*
+     * Heap storage comes from a common virtual memory reservation.
+     * The new heap will start on the page after the old heap.
+     */
+    void *sbrk0 = contiguous_mspace_sbrk0(hs->heaps[0].msp);
+    char *base = (char *)ALIGN_UP_TO_PAGE_SIZE(sbrk0);
+    size_t overhead = base - hs->heaps[0].base;
+    assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
+
+    if (overhead + HEAP_MIN_FREE >= hs->maximumSize) {
+        LOGE_HEAP("No room to create any more heaps "
+                  "(%zd overhead, %zd max)",
+                  overhead, hs->maximumSize);
+        return false;
+    }
+
+    heap.maximumSize = hs->growthLimit - overhead;
+    heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
+    heap.base = base;
+    heap.limit = heap.base + heap.maximumSize;
+    heap.msp = createMspace(base, HEAP_MIN_FREE, hs->maximumSize - overhead);
+    if (heap.msp == NULL) {
+        return false;
+    }
+
+    /* Don't let the soon-to-be-old heap grow any further.
+     */
+    hs->heaps[0].maximumSize = overhead;
+    hs->heaps[0].limit = base;
+    mspace msp = hs->heaps[0].msp;
+    mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
+
+    /* Put the new heap in the list, at heaps[0].
+     * Shift existing heaps down.
+     */
+    memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0]));
+    hs->heaps[0] = heap;
+    hs->numHeaps++;
+
+    return true;
+}
+
+/*
+ * The garbage collection daemon.  Initiates a concurrent collection
+ * when signaled.  Also periodically trims the heaps when a few seconds
+ * have elapsed since the last concurrent GC.
+ */
+static void *gcDaemonThread(void* arg)
+{
+    dvmChangeStatus(NULL, THREAD_VMWAIT);
+    dvmLockMutex(&gHs->gcThreadMutex);
+    while (gHs->gcThreadShutdown != true) {
+        bool trim = false;
+        if (gHs->gcThreadTrimNeeded) {
+            int result = dvmRelativeCondWait(&gHs->gcThreadCond, &gHs->gcThreadMutex,
+                    HEAP_TRIM_IDLE_TIME_SECONDS, 0);
+            if (result == ETIMEDOUT) {
+                /* Timed out waiting for a GC request, schedule a heap trim. */
+                trim = true;
+            }
+        } else {
+            dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex);
+        }
+
+        dvmLockHeap();
+        /*
+         * Another thread may have started a concurrent garbage
+         * collection before we were scheduled.  Check for this
+         * condition before proceeding.
+         */
+        if (!gDvm.gcHeap->gcRunning) {
+            dvmChangeStatus(NULL, THREAD_RUNNING);
+            if (trim) {
+                trimHeaps();
+                gHs->gcThreadTrimNeeded = false;
+            } else {
+                dvmCollectGarbageInternal(GC_CONCURRENT);
+                gHs->gcThreadTrimNeeded = true;
+            }
+            dvmChangeStatus(NULL, THREAD_VMWAIT);
+        }
+        dvmUnlockHeap();
+    }
+    dvmChangeStatus(NULL, THREAD_RUNNING);
+    return NULL;
+}
+
+static bool gcDaemonStartup()
+{
+    dvmInitMutex(&gHs->gcThreadMutex);
+    pthread_cond_init(&gHs->gcThreadCond, NULL);
+    gHs->gcThreadShutdown = false;
+    gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC",
+                                               gcDaemonThread, NULL);
+    return gHs->hasGcThread;
+}
+
+static void gcDaemonShutdown()
+{
+    if (gHs->hasGcThread) {
+        dvmLockMutex(&gHs->gcThreadMutex);
+        gHs->gcThreadShutdown = true;
+        dvmSignalCond(&gHs->gcThreadCond);
+        dvmUnlockMutex(&gHs->gcThreadMutex);
+        pthread_join(gHs->gcThread, NULL);
+    }
+}
+
+/*
+ * Create a stack big enough for the worst possible case, where the
+ * heap is perfectly full of the smallest object.
+ * TODO: be better about memory usage; use a smaller stack with
+ *       overflow detection and recovery.
+ */
+static bool allocMarkStack(GcMarkStack *stack, size_t maximumSize)
+{
+    const char *name = "dalvik-mark-stack";
+    void *addr;
+
+    assert(stack != NULL);
+    stack->length = maximumSize * sizeof(Object*) /
+        (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
+    addr = dvmAllocRegion(stack->length, PROT_READ | PROT_WRITE, name);
+    if (addr == NULL) {
+        return false;
+    }
+    stack->base = (const Object **)addr;
+    stack->limit = (const Object **)((char *)addr + stack->length);
+    stack->top = NULL;
+    madvise(stack->base, stack->length, MADV_DONTNEED);
+    return true;
+}
+
+static void freeMarkStack(GcMarkStack *stack)
+{
+    assert(stack != NULL);
+    munmap(stack->base, stack->length);
+    memset(stack, 0, sizeof(*stack));
+}
+
+/*
+ * Initializes the heap source; must be called before any other
+ * dvmHeapSource*() functions.  Returns a GcHeap structure
+ * allocated from the heap source.
+ */
+GcHeap* dvmHeapSourceStartup(size_t startSize, size_t maximumSize,
+                             size_t growthLimit)
+{
+    GcHeap *gcHeap;
+    HeapSource *hs;
+    mspace msp;
+    size_t length;
+    void *base;
+
+    assert(gHs == NULL);
+
+    if (!(startSize <= growthLimit && growthLimit <= maximumSize)) {
+        LOGE("Bad heap size parameters (start=%zd, max=%zd, limit=%zd)",
+             startSize, maximumSize, growthLimit);
+        return NULL;
+    }
+
+    /*
+     * Allocate a contiguous region of virtual memory to subdivided
+     * among the heaps managed by the garbage collector.
+     */
+    length = ALIGN_UP_TO_PAGE_SIZE(maximumSize);
+    base = dvmAllocRegion(length, PROT_NONE, "dalvik-heap");
+    if (base == NULL) {
+        return NULL;
+    }
+
+    /* Create an unlocked dlmalloc mspace to use as
+     * a heap source.
+     */
+    msp = createMspace(base, startSize, maximumSize);
+    if (msp == NULL) {
+        goto fail;
+    }
+
+    gcHeap = (GcHeap *)malloc(sizeof(*gcHeap));
+    if (gcHeap == NULL) {
+        LOGE_HEAP("Can't allocate heap descriptor");
+        goto fail;
+    }
+    memset(gcHeap, 0, sizeof(*gcHeap));
+
+    hs = (HeapSource *)malloc(sizeof(*hs));
+    if (hs == NULL) {
+        LOGE_HEAP("Can't allocate heap source");
+        free(gcHeap);
+        goto fail;
+    }
+    memset(hs, 0, sizeof(*hs));
+
+    hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
+    hs->startSize = startSize;
+    hs->maximumSize = maximumSize;
+    hs->growthLimit = growthLimit;
+    hs->idealSize = startSize;
+    hs->softLimit = SIZE_MAX;    // no soft limit at first
+    hs->numHeaps = 0;
+    hs->sawZygote = gDvm.zygote;
+    hs->hasGcThread = false;
+    hs->heapBase = (char *)base;
+    hs->heapLength = length;
+    if (!addInitialHeap(hs, msp, growthLimit)) {
+        LOGE_HEAP("Can't add initial heap");
+        goto fail;
+    }
+    if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) {
+        LOGE_HEAP("Can't create liveBits");
+        goto fail;
+    }
+    if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) {
+        LOGE_HEAP("Can't create markBits");
+        dvmHeapBitmapDelete(&hs->liveBits);
+        goto fail;
+    }
+    if (!allocMarkStack(&gcHeap->markContext.stack, hs->maximumSize)) {
+        LOGE("Can't create markStack");
+        dvmHeapBitmapDelete(&hs->markBits);
+        dvmHeapBitmapDelete(&hs->liveBits);
+        goto fail;
+    }
+    gcHeap->markContext.bitmap = &hs->markBits;
+    gcHeap->heapSource = hs;
+
+    gHs = hs;
+    return gcHeap;
+
+fail:
+    munmap(base, length);
+    return NULL;
+}
+
+bool dvmHeapSourceStartupAfterZygote()
+{
+    return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true;
+}
+
+/*
+ * This is called while in zygote mode, right before we fork() for the
+ * first time.  We create a heap for all future zygote process allocations,
+ * in an attempt to avoid touching pages in the zygote heap.  (This would
+ * probably be unnecessary if we had a compacting GC -- the source of our
+ * troubles is small allocations filling in the gaps from larger ones.)
+ */
+bool dvmHeapSourceStartupBeforeFork()
+{
+    HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
+
+    HS_BOILERPLATE();
+
+    assert(gDvm.zygote);
+
+    if (!gDvm.newZygoteHeapAllocated) {
+        /* Create a new heap for post-fork zygote allocations.  We only
+         * try once, even if it fails.
+         */
+        LOGV("Splitting out new zygote heap");
+        gDvm.newZygoteHeapAllocated = true;
+        return addNewHeap(hs);
+    }
+    return true;
+}
+
+void dvmHeapSourceThreadShutdown()
+{
+    if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) {
+        gcDaemonShutdown();
+    }
+}
+
+/*
+ * Tears down the entire GcHeap structure and all of the substructures
+ * attached to it.  This call has the side effect of setting the given
+ * gcHeap pointer and gHs to NULL.
+ */
+void dvmHeapSourceShutdown(GcHeap **gcHeap)
+{
+    assert(gcHeap != NULL);
+    if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
+        HeapSource *hs = (*gcHeap)->heapSource;
+        dvmHeapBitmapDelete(&hs->liveBits);
+        dvmHeapBitmapDelete(&hs->markBits);
+        freeMarkStack(&(*gcHeap)->markContext.stack);
+        munmap(hs->heapBase, hs->heapLength);
+        free(hs);
+        gHs = NULL;
+        free(*gcHeap);
+        *gcHeap = NULL;
+    }
+}
+
+/*
+ * Gets the begining of the allocation for the HeapSource.
+ */
+void *dvmHeapSourceGetBase()
+{
+    return gHs->heapBase;
+}
+
+/*
+ * Returns the requested value. If the per-heap stats are requested, fill
+ * them as well.
+ *
+ * Caller must hold the heap lock.
+ */
+size_t dvmHeapSourceGetValue(HeapSourceValueSpec spec, size_t perHeapStats[],
+                             size_t arrayLen)
+{
+    HeapSource *hs = gHs;
+    size_t value = 0;
+    size_t total = 0;
+
+    HS_BOILERPLATE();
+
+    assert(arrayLen >= hs->numHeaps || perHeapStats == NULL);
+    for (size_t i = 0; i < hs->numHeaps; i++) {
+        Heap *const heap = &hs->heaps[i];
+
+        switch (spec) {
+        case HS_FOOTPRINT:
+            value = mspace_footprint(heap->msp);
+            break;
+        case HS_ALLOWED_FOOTPRINT:
+            value = mspace_max_allowed_footprint(heap->msp);
+            break;
+        case HS_BYTES_ALLOCATED:
+            value = heap->bytesAllocated;
+            break;
+        case HS_OBJECTS_ALLOCATED:
+            value = heap->objectsAllocated;
+            break;
+        default:
+            // quiet gcc
+            break;
+        }
+        if (perHeapStats) {
+            perHeapStats[i] = value;
+        }
+        total += value;
+    }
+    return total;
+}
+
+void dvmHeapSourceGetRegions(uintptr_t *base, uintptr_t *max, size_t numHeaps)
+{
+    HeapSource *hs = gHs;
+
+    HS_BOILERPLATE();
+
+    assert(numHeaps <= hs->numHeaps);
+    for (size_t i = 0; i < numHeaps; ++i) {
+        base[i] = (uintptr_t)hs->heaps[i].base;
+        max[i] = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max);
+    }
+}
+
+/*
+ * Get the bitmap representing all live objects.
+ */
+HeapBitmap *dvmHeapSourceGetLiveBits()
+{
+    HS_BOILERPLATE();
+
+    return &gHs->liveBits;
+}
+
+/*
+ * Get the bitmap representing all marked objects.
+ */
+HeapBitmap *dvmHeapSourceGetMarkBits()
+{
+    HS_BOILERPLATE();
+
+    return &gHs->markBits;
+}
+
+void dvmHeapSourceSwapBitmaps()
+{
+    HeapBitmap tmp = gHs->liveBits;
+    gHs->liveBits = gHs->markBits;
+    gHs->markBits = tmp;
+}
+
+void dvmHeapSourceZeroMarkBitmap()
+{
+    HS_BOILERPLATE();
+
+    dvmHeapBitmapZero(&gHs->markBits);
+}
+
+void dvmMarkImmuneObjects(const char *immuneLimit)
+{
+    /*
+     * Copy the contents of the live bit vector for immune object
+     * range into the mark bit vector.
+     */
+    /* The only values generated by dvmHeapSourceGetImmuneLimit() */
+    assert(immuneLimit == gHs->heaps[0].base ||
+           immuneLimit == NULL);
+    assert(gHs->liveBits.base == gHs->markBits.base);
+    assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen);
+    /* heap[0] is never immune */
+    assert(gHs->heaps[0].base >= immuneLimit);
+    assert(gHs->heaps[0].limit > immuneLimit);
+
+    for (size_t i = 1; i < gHs->numHeaps; ++i) {
+        if (gHs->heaps[i].base < immuneLimit) {
+            assert(gHs->heaps[i].limit <= immuneLimit);
+            /* Compute the number of words to copy in the bitmap. */
+            size_t index = HB_OFFSET_TO_INDEX(
+                (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base);
+            /* Compute the starting offset in the live and mark bits. */
+            char *src = (char *)(gHs->liveBits.bits + index);
+            char *dst = (char *)(gHs->markBits.bits + index);
+            /* Compute the number of bytes of the live bitmap to copy. */
+            size_t length = HB_OFFSET_TO_BYTE_INDEX(
+                gHs->heaps[i].limit - gHs->heaps[i].base);
+            /* Do the copy. */
+            memcpy(dst, src, length);
+            /* Make sure max points to the address of the highest set bit. */
+            if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) {
+                gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit;
+            }
+        }
+    }
+}
+
+/*
+ * Allocates <n> bytes of zeroed data.
+ */
+void* dvmHeapSourceAlloc(size_t n)
+{
+    HS_BOILERPLATE();
+
+    HeapSource *hs = gHs;
+    Heap* heap = hs2heap(hs);
+    if (heap->bytesAllocated + n > hs->softLimit) {
+        /*
+         * This allocation would push us over the soft limit; act as
+         * if the heap is full.
+         */
+        LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation",
+                  FRACTIONAL_MB(hs->softLimit), n);
+        return NULL;
+    }
+    void* ptr = mspace_calloc(heap->msp, 1, n);
+    if (ptr == NULL) {
+        return NULL;
+    }
+    countAllocation(heap, ptr);
+    /*
+     * Check to see if a concurrent GC should be initiated.
+     */
+    if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
+        /*
+         * The garbage collector thread is already running or has yet
+         * to be started.  Do nothing.
+         */
+        return ptr;
+    }
+    if (heap->bytesAllocated > heap->concurrentStartBytes) {
+        /*
+         * We have exceeded the allocation threshold.  Wake up the
+         * garbage collector.
+         */
+        dvmSignalCond(&gHs->gcThreadCond);
+    }
+    return ptr;
+}
+
+/* Remove any hard limits, try to allocate, and shrink back down.
+ * Last resort when trying to allocate an object.
+ */
+static void* heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
+{
+    /* Grow as much as possible, but don't let the real footprint
+     * go over the absolute max.
+     */
+    size_t max = heap->maximumSize;
+
+    mspace_set_max_allowed_footprint(heap->msp, max);
+    void* ptr = dvmHeapSourceAlloc(n);
+
+    /* Shrink back down as small as possible.  Our caller may
+     * readjust max_allowed to a more appropriate value.
+     */
+    mspace_set_max_allowed_footprint(heap->msp,
+                                     mspace_footprint(heap->msp));
+    return ptr;
+}
+
+/*
+ * Allocates <n> bytes of zeroed data, growing as much as possible
+ * if necessary.
+ */
+void* dvmHeapSourceAllocAndGrow(size_t n)
+{
+    HS_BOILERPLATE();
+
+    HeapSource *hs = gHs;
+    Heap* heap = hs2heap(hs);
+    void* ptr = dvmHeapSourceAlloc(n);
+    if (ptr != NULL) {
+        return ptr;
+    }
+
+    size_t oldIdealSize = hs->idealSize;
+    if (isSoftLimited(hs)) {
+        /* We're soft-limited.  Try removing the soft limit to
+         * see if we can allocate without actually growing.
+         */
+        hs->softLimit = SIZE_MAX;
+        ptr = dvmHeapSourceAlloc(n);
+        if (ptr != NULL) {
+            /* Removing the soft limit worked;  fix things up to
+             * reflect the new effective ideal size.
+             */
+            snapIdealFootprint();
+            return ptr;
+        }
+        // softLimit intentionally left at SIZE_MAX.
+    }
+
+    /* We're not soft-limited.  Grow the heap to satisfy the request.
+     * If this call fails, no footprints will have changed.
+     */
+    ptr = heapAllocAndGrow(hs, heap, n);
+    if (ptr != NULL) {
+        /* The allocation succeeded.  Fix up the ideal size to
+         * reflect any footprint modifications that had to happen.
+         */
+        snapIdealFootprint();
+    } else {
+        /* We just couldn't do it.  Restore the original ideal size,
+         * fixing up softLimit if necessary.
+         */
+        setIdealFootprint(oldIdealSize);
+    }
+    return ptr;
+}
+
+/*
+ * Frees the first numPtrs objects in the ptrs list and returns the
+ * amount of reclaimed storage. The list must contain addresses all in
+ * the same mspace, and must be in increasing order. This implies that
+ * there are no duplicates, and no entries are NULL.
+ */
+size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
+{
+    HS_BOILERPLATE();
+
+    if (numPtrs == 0) {
+        return 0;
+    }
+
+    assert(ptrs != NULL);
+    assert(*ptrs != NULL);
+    Heap* heap = ptr2heap(gHs, *ptrs);
+    size_t numBytes = 0;
+    if (heap != NULL) {
+        mspace msp = heap->msp;
+        // Calling mspace_free on shared heaps disrupts sharing too
+        // much. For heap[0] -- the 'active heap' -- we call
+        // mspace_free, but on the other heaps we only do some
+        // accounting.
+        if (heap == gHs->heaps) {
+            // mspace_merge_objects takes two allocated objects, and
+            // if the second immediately follows the first, will merge
+            // them, returning a larger object occupying the same
+            // memory. This is a local operation, and doesn't require
+            // dlmalloc to manipulate any freelists. It's pretty
+            // inexpensive compared to free().
+
+            // ptrs is an array of objects all in memory order, and if
+            // client code has been allocating lots of short-lived
+            // objects, this is likely to contain runs of objects all
+            // now garbage, and thus highly amenable to this optimization.
+
+            // Unroll the 0th iteration around the loop below,
+            // countFree ptrs[0] and initializing merged.
+            assert(ptrs[0] != NULL);
+            assert(ptr2heap(gHs, ptrs[0]) == heap);
+            countFree(heap, ptrs[0], &numBytes);
+            void *merged = ptrs[0];
+            for (size_t i = 1; i < numPtrs; i++) {
+                assert(merged != NULL);
+                assert(ptrs[i] != NULL);
+                assert((intptr_t)merged < (intptr_t)ptrs[i]);
+                assert(ptr2heap(gHs, ptrs[i]) == heap);
+                countFree(heap, ptrs[i], &numBytes);
+                // Try to merge. If it works, merged now includes the
+                // memory of ptrs[i]. If it doesn't, free merged, and
+                // see if ptrs[i] starts a new run of adjacent
+                // objects to merge.
+                if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
+                    mspace_free(msp, merged);
+                    merged = ptrs[i];
+                }
+            }
+            assert(merged != NULL);
+            mspace_free(msp, merged);
+        } else {
+            // This is not an 'active heap'. Only do the accounting.
+            for (size_t i = 0; i < numPtrs; i++) {
+                assert(ptrs[i] != NULL);
+                assert(ptr2heap(gHs, ptrs[i]) == heap);
+                countFree(heap, ptrs[i], &numBytes);
+            }
+        }
+    }
+    return numBytes;
+}
+
+/*
+ * Returns true iff <ptr> is in the heap source.
+ */
+bool dvmHeapSourceContainsAddress(const void *ptr)
+{
+    HS_BOILERPLATE();
+
+    return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
+}
+
+/*
+ * Returns true iff <ptr> was allocated from the heap source.
+ */
+bool dvmHeapSourceContains(const void *ptr)
+{
+    HS_BOILERPLATE();
+
+    if (dvmHeapSourceContainsAddress(ptr)) {
+        return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
+    }
+    return false;
+}
+
+bool dvmIsZygoteObject(const Object* obj)
+{
+    HeapSource *hs = gHs;
+
+    HS_BOILERPLATE();
+
+    if (dvmHeapSourceContains(obj) && hs->sawZygote) {
+        Heap *heap = ptr2heap(hs, obj);
+        if (heap != NULL) {
+            /* If the object is not in the active heap, we assume that
+             * it was allocated as part of zygote.
+             */
+            return heap != hs->heaps;
+        }
+    }
+    /* The pointer is outside of any known heap, or we are not
+     * running in zygote mode.
+     */
+    return false;
+}
+
+/*
+ * Returns the number of usable bytes in an allocated chunk; the size
+ * may be larger than the size passed to dvmHeapSourceAlloc().
+ */
+size_t dvmHeapSourceChunkSize(const void *ptr)
+{
+    HS_BOILERPLATE();
+
+    Heap* heap = ptr2heap(gHs, ptr);
+    if (heap != NULL) {
+        return mspace_usable_size(heap->msp, ptr);
+    }
+    return 0;
+}
+
+/*
+ * Returns the number of bytes that the heap source has allocated
+ * from the system using sbrk/mmap, etc.
+ *
+ * Caller must hold the heap lock.
+ */
+size_t dvmHeapSourceFootprint()
+{
+    HS_BOILERPLATE();
+
+//TODO: include size of bitmaps?
+    return oldHeapOverhead(gHs, true);
+}
+
+static size_t getMaximumSize(const HeapSource *hs)
+{
+    return hs->growthLimit;
+}
+
+/*
+ * Returns the current maximum size of the heap source respecting any
+ * growth limits.
+ */
+size_t dvmHeapSourceGetMaximumSize()
+{
+    HS_BOILERPLATE();
+    return getMaximumSize(gHs);
+}
+
+/*
+ * Removes any growth limits.  Allows the user to allocate up to the
+ * maximum heap size.
+ */
+void dvmClearGrowthLimit()
+{
+    HS_BOILERPLATE();
+    dvmLockHeap();
+    dvmWaitForConcurrentGcToComplete();
+    gDvm.gcHeap->cardTableLength = gDvm.gcHeap->cardTableMaxLength;
+    gHs->growthLimit = gHs->maximumSize;
+    size_t overhead = oldHeapOverhead(gHs, false);
+    gHs->heaps[0].maximumSize = gHs->maximumSize - overhead;
+    gHs->heaps[0].limit = gHs->heaps[0].base + gHs->heaps[0].maximumSize;
+    dvmUnlockHeap();
+}
+
+/*
+ * Return the real bytes used by old heaps plus the soft usage of the
+ * current heap.  When a soft limit is in effect, this is effectively
+ * what it's compared against (though, in practice, it only looks at
+ * the current heap).
+ */
+static size_t getSoftFootprint(bool includeActive)
+{
+    HS_BOILERPLATE();
+
+    HeapSource *hs = gHs;
+    size_t ret = oldHeapOverhead(hs, false);
+    if (includeActive) {
+        ret += hs->heaps[0].bytesAllocated;
+    }
+
+    return ret;
+}
+
+/*
+ * Gets the maximum number of bytes that the heap source is allowed
+ * to allocate from the system.
+ */
+size_t dvmHeapSourceGetIdealFootprint()
+{
+    HeapSource *hs = gHs;
+
+    HS_BOILERPLATE();
+
+    return hs->idealSize;
+}
+
+/*
+ * Sets the soft limit, handling any necessary changes to the allowed
+ * footprint of the active heap.
+ */
+static void setSoftLimit(HeapSource *hs, size_t softLimit)
+{
+    /* Compare against the actual footprint, rather than the
+     * max_allowed, because the heap may not have grown all the
+     * way to the allowed size yet.
+     */
+    mspace msp = hs->heaps[0].msp;
+    size_t currentHeapSize = mspace_footprint(msp);
+    if (softLimit < currentHeapSize) {
+        /* Don't let the heap grow any more, and impose a soft limit.
+         */
+        mspace_set_max_allowed_footprint(msp, currentHeapSize);
+        hs->softLimit = softLimit;
+    } else {
+        /* Let the heap grow to the requested max, and remove any
+         * soft limit, if set.
+         */
+        mspace_set_max_allowed_footprint(msp, softLimit);
+        hs->softLimit = SIZE_MAX;
+    }
+}
+
+/*
+ * Sets the maximum number of bytes that the heap source is allowed
+ * to allocate from the system.  Clamps to the appropriate maximum
+ * value.
+ */
+static void setIdealFootprint(size_t max)
+{
+    HS_BOILERPLATE();
+
+    HeapSource *hs = gHs;
+    size_t maximumSize = getMaximumSize(hs);
+    if (max > maximumSize) {
+        LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB",
+                FRACTIONAL_MB(max),
+                FRACTIONAL_MB(maximumSize));
+        max = maximumSize;
+    }
+
+    /* Convert max into a size that applies to the active heap.
+     * Old heaps will count against the ideal size.
+     */
+    size_t overhead = getSoftFootprint(false);
+    size_t activeMax;
+    if (overhead < max) {
+        activeMax = max - overhead;
+    } else {
+        activeMax = 0;
+    }
+
+    setSoftLimit(hs, activeMax);
+    hs->idealSize = max;
+}
+
+/*
+ * Make the ideal footprint equal to the current footprint.
+ */
+static void snapIdealFootprint()
+{
+    HS_BOILERPLATE();
+
+    setIdealFootprint(getSoftFootprint(true));
+}
+
+/*
+ * Gets the current ideal heap utilization, represented as a number
+ * between zero and one.
+ */
+float dvmGetTargetHeapUtilization()
+{
+    HeapSource *hs = gHs;
+
+    HS_BOILERPLATE();
+
+    return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX;
+}
+
+/*
+ * Sets the new ideal heap utilization, represented as a number
+ * between zero and one.
+ */
+void dvmSetTargetHeapUtilization(float newTarget)
+{
+    HeapSource *hs = gHs;
+
+    HS_BOILERPLATE();
+
+    /* Clamp it to a reasonable range.
+     */
+    // TODO: This may need some tuning.
+    if (newTarget < 0.2) {
+        newTarget = 0.2;
+    } else if (newTarget > 0.8) {
+        newTarget = 0.8;
+    }
+
+    hs->targetUtilization =
+            (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
+    LOGV("Set heap target utilization to %zd/%d (%f)",
+            hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
+}
+
+/*
+ * Given the size of a live set, returns the ideal heap size given
+ * the current target utilization and MIN/MAX values.
+ *
+ * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
+ */
+static size_t getUtilizationTarget(size_t liveSize, size_t targetUtilization)
+{
+    /* Use the current target utilization ratio to determine the
+     * ideal heap size based on the size of the live set.
+     */
+    size_t targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
+
+    /* Cap the amount of free space, though, so we don't end up
+     * with, e.g., 8MB of free space when the live set size hits 8MB.
+     */
+    if (targetSize > liveSize + HEAP_IDEAL_FREE) {
+        targetSize = liveSize + HEAP_IDEAL_FREE;
+    } else if (targetSize < liveSize + HEAP_MIN_FREE) {
+        targetSize = liveSize + HEAP_MIN_FREE;
+    }
+    return targetSize;
+}
+
+/*
+ * Given the current contents of the active heap, increase the allowed
+ * heap footprint to match the target utilization ratio.  This
+ * should only be called immediately after a full mark/sweep.
+ */
+void dvmHeapSourceGrowForUtilization()
+{
+    HS_BOILERPLATE();
+
+    HeapSource *hs = gHs;
+    Heap* heap = hs2heap(hs);
+
+    /* Use the current target utilization ratio to determine the
+     * ideal heap size based on the size of the live set.
+     * Note that only the active heap plays any part in this.
+     *
+     * Avoid letting the old heaps influence the target free size,
+     * because they may be full of objects that aren't actually
+     * in the working set.  Just look at the allocated size of
+     * the current heap.
+     */
+    size_t currentHeapUsed = heap->bytesAllocated;
+    size_t targetHeapSize =
+            getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
+
+    /* The ideal size includes the old heaps; add overhead so that
+     * it can be immediately subtracted again in setIdealFootprint().
+     * If the target heap size would exceed the max, setIdealFootprint()
+     * will clamp it to a legal value.
+     */
+    size_t overhead = getSoftFootprint(false);
+    setIdealFootprint(targetHeapSize + overhead);
+
+    size_t freeBytes = getAllocLimit(hs);
+    if (freeBytes < CONCURRENT_MIN_FREE) {
+        /* Not enough free memory to allow a concurrent GC. */
+        heap->concurrentStartBytes = SIZE_MAX;
+    } else {
+        heap->concurrentStartBytes = freeBytes - CONCURRENT_START;
+    }
+}
+
+/*
+ * Return free pages to the system.
+ * TODO: move this somewhere else, especially the native heap part.
+ */
+static void releasePagesInRange(void *start, void *end, void *nbytes)
+{
+    /* Linux requires that the madvise() start address is page-aligned.
+    * We also align the end address.
+    */
+    start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
+    end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
+    if (start < end) {
+        size_t length = (char *)end - (char *)start;
+        madvise(start, length, MADV_DONTNEED);
+        *(size_t *)nbytes += length;
+    }
+}
+
+/*
+ * Return unused memory to the system if possible.
+ */
+static void trimHeaps()
+{
+    HS_BOILERPLATE();
+
+    HeapSource *hs = gHs;
+    size_t heapBytes = 0;
+    for (size_t i = 0; i < hs->numHeaps; i++) {
+        Heap *heap = &hs->heaps[i];
+
+        /* Return the wilderness chunk to the system.
+         */
+        mspace_trim(heap->msp, 0);
+
+        /* Return any whole free pages to the system.
+         */
+        mspace_walk_free_pages(heap->msp, releasePagesInRange, &heapBytes);
+    }
+
+    /* Same for the native heap.
+     */
+    dlmalloc_trim(0);
+    size_t nativeBytes = 0;
+    dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
+
+    LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes",
+            heapBytes, nativeBytes, heapBytes + nativeBytes);
+}
+
+/*
+ * Walks over the heap source and passes every allocated and
+ * free chunk to the callback.
+ */
+void dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
+                                       const void *userptr, size_t userlen,
+                                       void *arg),
+                       void *arg)
+{
+    HS_BOILERPLATE();
+
+    /* Walk the heaps from oldest to newest.
+     */
+//TODO: do this in address order
+    HeapSource *hs = gHs;
+    for (size_t i = hs->numHeaps; i > 0; --i) {
+        mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
+    }
+}
+
+/*
+ * Gets the number of heaps available in the heap source.
+ *
+ * Caller must hold the heap lock, because gHs caches a field
+ * in gDvm.gcHeap.
+ */
+size_t dvmHeapSourceGetNumHeaps()
+{
+    HS_BOILERPLATE();
+
+    return gHs->numHeaps;
+}
+
+void *dvmHeapSourceGetImmuneLimit(bool isPartial)
+{
+    if (isPartial) {
+        return hs2heap(gHs)->base;
+    } else {
+        return NULL;
+    }
+}
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
new file mode 100644
index 0000000..66f2a6a
--- /dev/null
+++ b/vm/alloc/HeapSource.h
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+#ifndef DALVIK_HEAP_SOURCE_H_
+#define DALVIK_HEAP_SOURCE_H_
+
+#include "alloc/Heap.h"
+#include "alloc/HeapInternal.h" // for GcHeap
+
+/* dlmalloc uses one size_t per allocated chunk.
+ */
+#define HEAP_SOURCE_CHUNK_OVERHEAD         (1 * sizeof (size_t))
+#define HEAP_SOURCE_WORST_CHUNK_OVERHEAD   (32 * sizeof (size_t))
+
+/* The largest number of separate heaps we can handle.
+ */
+#define HEAP_SOURCE_MAX_HEAP_COUNT 2
+
+enum HeapSourceValueSpec {
+    HS_FOOTPRINT,
+    HS_ALLOWED_FOOTPRINT,
+    HS_BYTES_ALLOCATED,
+    HS_OBJECTS_ALLOCATED
+};
+
+/*
+ * Initializes the heap source; must be called before any other
+ * dvmHeapSource*() functions.
+ */
+GcHeap *dvmHeapSourceStartup(size_t startingSize,
+                             size_t maximumSize,
+                             size_t growthLimit);
+
+/*
+ * If the HeapSource was created while in zygote mode, this
+ * will create a new heap for post-zygote allocations.
+ * Having a separate heap should maximize the number of pages
+ * that a given app_process shares with the zygote process.
+ */
+bool dvmHeapSourceStartupAfterZygote(void);
+
+/*
+ * If the HeapSource was created while in zygote mode, this
+ * will create an additional zygote heap before the first fork().
+ * Having a separate heap should reduce the number of shared
+ * pages subsequently touched by the zygote process.
+ */
+bool dvmHeapSourceStartupBeforeFork(void);
+
+/*
+ * Shutdown any threads internal to the heap source.  This should be
+ * called before the heap source itself is shutdown.
+ */
+void dvmHeapSourceThreadShutdown(void);
+
+/*
+ * Tears down the heap source and frees any resources associated with it.
+ */
+void dvmHeapSourceShutdown(GcHeap **gcHeap);
+
+/*
+ * Returns the base and inclusive max addresses of the heap source
+ * heaps.  The base and max values are suitable for passing directly
+ * to the bitmap sweeping routine.
+ */
+void dvmHeapSourceGetRegions(uintptr_t *base, uintptr_t *max, size_t numHeaps);
+
+/*
+ * Get the bitmap representing all live objects.
+ */
+HeapBitmap *dvmHeapSourceGetLiveBits(void);
+
+/*
+ * Get the bitmap representing all marked objects.
+ */
+HeapBitmap *dvmHeapSourceGetMarkBits(void);
+
+/*
+ * Gets the begining of the allocation for the HeapSource.
+ */
+void *dvmHeapSourceGetBase(void);
+
+/*
+ * Returns the requested value. If the per-heap stats are requested, fill
+ * them as well.
+ */
+size_t dvmHeapSourceGetValue(HeapSourceValueSpec spec,
+                             size_t perHeapStats[], size_t arrayLen);
+
+/*
+ * Allocates <n> bytes of zeroed data.
+ */
+void *dvmHeapSourceAlloc(size_t n);
+
+/*
+ * Allocates <n> bytes of zeroed data, growing up to absoluteMaxSize
+ * if necessary.
+ */
+void *dvmHeapSourceAllocAndGrow(size_t n);
+
+/*
+ * Frees the first numPtrs objects in the ptrs list and returns the
+ * amount of reclaimed storage.  The list must contain addresses all
+ * in the same mspace, and must be in increasing order. This implies
+ * that there are no duplicates, and no entries are NULL.
+ */
+size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs);
+
+/*
+ * Returns true iff <ptr> was allocated from the heap source.
+ */
+bool dvmHeapSourceContains(const void *ptr);
+
+/*
+ * Returns true iff <ptr> is within the address space managed by heap source.
+ */
+bool dvmHeapSourceContainsAddress(const void *ptr);
+
+/*
+ * Returns the number of usable bytes in an allocated chunk; the size
+ * may be larger than the size passed to dvmHeapSourceAlloc().
+ */
+size_t dvmHeapSourceChunkSize(const void *ptr);
+
+/*
+ * Returns the number of bytes that the heap source has allocated
+ * from the system using sbrk/mmap, etc.
+ */
+size_t dvmHeapSourceFootprint(void);
+
+/*
+ * Gets the maximum number of bytes that the heap source is allowed
+ * to allocate from the system.
+ */
+size_t dvmHeapSourceGetIdealFootprint(void);
+
+/*
+ * Given the current contents of the heap, increase the allowed
+ * heap footprint to match the target utilization ratio.  This
+ * should only be called immediately after a full mark/sweep.
+ */
+void dvmHeapSourceGrowForUtilization(void);
+
+/*
+ * Walks over the heap source and passes every allocated and
+ * free chunk to the callback.
+ */
+void dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
+                                      const void *userptr, size_t userlen,
+                                      void *arg),
+                       void *arg);
+/*
+ * Gets the number of heaps available in the heap source.
+ */
+size_t dvmHeapSourceGetNumHeaps(void);
+
+/*
+ * Exchanges the mark and object bitmaps.
+ */
+void dvmHeapSourceSwapBitmaps(void);
+
+/*
+ * Zeroes the mark bitmap.
+ */
+void dvmHeapSourceZeroMarkBitmap(void);
+
+/*
+ * Marks all objects inside the immune region of the heap. Addresses
+ * at or above this pointer are threatened, addresses below this
+ * pointer are immune.
+ */
+void dvmMarkImmuneObjects(const char *immuneLimit);
+
+/*
+ * Returns a pointer that demarcates the threatened region of the
+ * heap.  Addresses at or above this pointer are threatened, addresses
+ * below this pointer are immune.
+ */
+void *dvmHeapSourceGetImmuneLimit(bool isPartial);
+
+/*
+ * Returns the maximum size of the heap.  This value will be either
+ * the value of -Xmx or a user supplied growth limit.
+ */
+size_t dvmHeapSourceGetMaximumSize(void);
+
+#endif  // DALVIK_HEAP_SOURCE_H_
diff --git a/vm/alloc/MarkSweep.cpp b/vm/alloc/MarkSweep.cpp
new file mode 100644
index 0000000..d4f4669
--- /dev/null
+++ b/vm/alloc/MarkSweep.cpp
@@ -0,0 +1,946 @@
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "alloc/CardTable.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapBitmapInlines.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/HeapSource.h"
+#include "alloc/MarkSweep.h"
+#include "alloc/Visit.h"
+#include <limits.h>     // for ULONG_MAX
+#include <sys/mman.h>   // for madvise(), mmap()
+#include <errno.h>
+
+typedef unsigned long Word;
+const size_t kWordSize = sizeof(Word);
+
+/*
+ * Returns true if the given object is marked.
+ */
+static bool isMarked(const Object *obj, const GcMarkContext *ctx)
+{
+    return dvmHeapBitmapIsObjectBitSet(ctx->bitmap, obj);
+}
+
+/*
+ * Initializes the stack top and advises the mark stack pages as needed.
+ */
+static bool createMarkStack(GcMarkStack *stack)
+{
+    assert(stack != NULL);
+    size_t length = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
+        (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
+    madvise(stack->base, length, MADV_NORMAL);
+    stack->top = stack->base;
+    return true;
+}
+
+/*
+ * Assigns NULL to the stack top and advises the mark stack pages as
+ * not needed.
+ */
+static void destroyMarkStack(GcMarkStack *stack)
+{
+    assert(stack != NULL);
+    madvise(stack->base, stack->length, MADV_DONTNEED);
+    stack->top = NULL;
+}
+
+/*
+ * Pops an object from the mark stack.
+ */
+static void markStackPush(GcMarkStack *stack, const Object *obj)
+{
+    assert(stack != NULL);
+    assert(stack->base <= stack->top);
+    assert(stack->limit > stack->top);
+    assert(obj != NULL);
+    *stack->top = obj;
+    ++stack->top;
+}
+
+/*
+ * Pushes an object on the mark stack.
+ */
+static const Object *markStackPop(GcMarkStack *stack)
+{
+    assert(stack != NULL);
+    assert(stack->base < stack->top);
+    assert(stack->limit > stack->top);
+    --stack->top;
+    return *stack->top;
+}
+
+bool dvmHeapBeginMarkStep(bool isPartial)
+{
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+
+    if (!createMarkStack(&ctx->stack)) {
+        return false;
+    }
+    ctx->finger = NULL;
+    ctx->immuneLimit = (char*)dvmHeapSourceGetImmuneLimit(isPartial);
+    return true;
+}
+
+static long setAndReturnMarkBit(GcMarkContext *ctx, const void *obj)
+{
+    return dvmHeapBitmapSetAndReturnObjectBit(ctx->bitmap, obj);
+}
+
+static void markObjectNonNull(const Object *obj, GcMarkContext *ctx,
+                              bool checkFinger)
+{
+    assert(ctx != NULL);
+    assert(obj != NULL);
+    assert(dvmIsValidObject(obj));
+    if (obj < (Object *)ctx->immuneLimit) {
+        assert(isMarked(obj, ctx));
+        return;
+    }
+    if (!setAndReturnMarkBit(ctx, obj)) {
+        /* This object was not previously marked.
+         */
+        if (checkFinger && (void *)obj < ctx->finger) {
+            /* This object will need to go on the mark stack.
+             */
+            markStackPush(&ctx->stack, obj);
+        }
+    }
+}
+
+/* Used to mark objects when recursing.  Recursion is done by moving
+ * the finger across the bitmaps in address order and marking child
+ * objects.  Any newly-marked objects whose addresses are lower than
+ * the finger won't be visited by the bitmap scan, so those objects
+ * need to be added to the mark stack.
+ */
+static void markObject(const Object *obj, GcMarkContext *ctx)
+{
+    if (obj != NULL) {
+        markObjectNonNull(obj, ctx, true);
+    }
+}
+
+/*
+ * Callback applied to root references during the initial root
+ * marking.  Marks white objects but does not push them on the mark
+ * stack.
+ */
+static void rootMarkObjectVisitor(void *addr, u4 thread, RootType type,
+                                  void *arg)
+{
+    assert(addr != NULL);
+    assert(arg != NULL);
+    Object *obj = *(Object **)addr;
+    GcMarkContext *ctx = (GcMarkContext *)arg;
+    if (obj != NULL) {
+        markObjectNonNull(obj, ctx, false);
+    }
+}
+
+/* Mark the set of root objects.
+ *
+ * Things we need to scan:
+ * - System classes defined by root classloader
+ * - For each thread:
+ *   - Interpreted stack, from top to "curFrame"
+ *     - Dalvik registers (args + local vars)
+ *   - JNI local references
+ *   - Automatic VM local references (TrackedAlloc)
+ *   - Associated Thread/VMThread object
+ *   - ThreadGroups (could track & start with these instead of working
+ *     upward from Threads)
+ *   - Exception currently being thrown, if present
+ * - JNI global references
+ * - Interned string table
+ * - Primitive classes
+ * - Special objects
+ *   - gDvm.outOfMemoryObj
+ * - Objects in debugger object registry
+ *
+ * Don't need:
+ * - Native stack (for in-progress stuff in the VM)
+ *   - The TrackedAlloc stuff watches all native VM references.
+ */
+void dvmHeapMarkRootSet()
+{
+    GcHeap *gcHeap = gDvm.gcHeap;
+    dvmMarkImmuneObjects(gcHeap->markContext.immuneLimit);
+    dvmVisitRoots(rootMarkObjectVisitor, &gcHeap->markContext);
+}
+
+/*
+ * Callback applied to root references during root remarking.  Marks
+ * white objects and pushes them on the mark stack.
+ */
+static void rootReMarkObjectVisitor(void *addr, u4 thread, RootType type,
+                                    void *arg)
+{
+    assert(addr != NULL);
+    assert(arg != NULL);
+    Object *obj = *(Object **)addr;
+    GcMarkContext *ctx = (GcMarkContext *)arg;
+    if (obj != NULL) {
+        markObjectNonNull(obj, ctx, true);
+    }
+}
+
+/*
+ * Grays all references in the roots.
+ */
+void dvmHeapReMarkRootSet()
+{
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+    assert(ctx->finger == (void *)ULONG_MAX);
+    dvmVisitRoots(rootReMarkObjectVisitor, ctx);
+}
+
+/*
+ * Scans instance fields.
+ */
+static void scanFields(const Object *obj, GcMarkContext *ctx)
+{
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(ctx != NULL);
+    if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
+        unsigned int refOffsets = obj->clazz->refOffsets;
+        while (refOffsets != 0) {
+            size_t rshift = CLZ(refOffsets);
+            size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
+            Object *ref = dvmGetFieldObject(obj, offset);
+            markObject(ref, ctx);
+            refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
+        }
+    } else {
+        for (ClassObject *clazz = obj->clazz;
+             clazz != NULL;
+             clazz = clazz->super) {
+            InstField *field = clazz->ifields;
+            for (int i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
+                void *addr = BYTE_OFFSET(obj, field->byteOffset);
+                Object *ref = ((JValue *)addr)->l;
+                markObject(ref, ctx);
+            }
+        }
+    }
+}
+
+/*
+ * Scans the static fields of a class object.
+ */
+static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
+{
+    assert(clazz != NULL);
+    assert(ctx != NULL);
+    for (int i = 0; i < clazz->sfieldCount; ++i) {
+        char ch = clazz->sfields[i].signature[0];
+        if (ch == '[' || ch == 'L') {
+            Object *obj = clazz->sfields[i].value.l;
+            markObject(obj, ctx);
+        }
+    }
+}
+
+/*
+ * Visit the interfaces of a class object.
+ */
+static void scanInterfaces(const ClassObject *clazz, GcMarkContext *ctx)
+{
+    assert(clazz != NULL);
+    assert(ctx != NULL);
+    for (int i = 0; i < clazz->interfaceCount; ++i) {
+        markObject((const Object *)clazz->interfaces[i], ctx);
+    }
+}
+
+/*
+ * Scans the header, static field references, and interface
+ * pointers of a class object.
+ */
+static void scanClassObject(const Object *obj, GcMarkContext *ctx)
+{
+    assert(obj != NULL);
+    assert(dvmIsClassObject(obj));
+    assert(ctx != NULL);
+    markObject((const Object *)obj->clazz, ctx);
+    const ClassObject *asClass = (const ClassObject *)obj;
+    if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
+        markObject((const Object *)asClass->elementClass, ctx);
+    }
+    /* Do super and the interfaces contain Objects and not dex idx values? */
+    if (asClass->status > CLASS_IDX) {
+        markObject((const Object *)asClass->super, ctx);
+    }
+    markObject((const Object *)asClass->classLoader, ctx);
+    scanFields(obj, ctx);
+    scanStaticFields(asClass, ctx);
+    if (asClass->status > CLASS_IDX) {
+        scanInterfaces(asClass, ctx);
+    }
+}
+
+/*
+ * Scans the header of all array objects.  If the array object is
+ * specialized to a reference type, scans the array data as well.
+ */
+static void scanArrayObject(const Object *obj, GcMarkContext *ctx)
+{
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(ctx != NULL);
+    markObject((const Object *)obj->clazz, ctx);
+    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
+        const ArrayObject *array = (const ArrayObject *)obj;
+        const Object **contents = (const Object **)(void *)array->contents;
+        for (size_t i = 0; i < array->length; ++i) {
+            markObject(contents[i], ctx);
+        }
+    }
+}
+
+/*
+ * Returns class flags relating to Reference subclasses.
+ */
+static int referenceClassFlags(const Object *obj)
+{
+    int flags = CLASS_ISREFERENCE |
+                CLASS_ISWEAKREFERENCE |
+                CLASS_ISFINALIZERREFERENCE |
+                CLASS_ISPHANTOMREFERENCE;
+    return GET_CLASS_FLAG_GROUP(obj->clazz, flags);
+}
+
+/*
+ * Returns true if the object derives from SoftReference.
+ */
+static bool isSoftReference(const Object *obj)
+{
+    return referenceClassFlags(obj) == CLASS_ISREFERENCE;
+}
+
+/*
+ * Returns true if the object derives from WeakReference.
+ */
+static bool isWeakReference(const Object *obj)
+{
+    return referenceClassFlags(obj) & CLASS_ISWEAKREFERENCE;
+}
+
+/*
+ * Returns true if the object derives from FinalizerReference.
+ */
+static bool isFinalizerReference(const Object *obj)
+{
+    return referenceClassFlags(obj) & CLASS_ISFINALIZERREFERENCE;
+}
+
+/*
+ * Returns true if the object derives from PhantomReference.
+ */
+static bool isPhantomReference(const Object *obj)
+{
+    return referenceClassFlags(obj) & CLASS_ISPHANTOMREFERENCE;
+}
+
+/*
+ * Adds a reference to the tail of a circular queue of references.
+ */
+static void enqueuePendingReference(Object *ref, Object **list)
+{
+    assert(ref != NULL);
+    assert(list != NULL);
+    size_t offset = gDvm.offJavaLangRefReference_pendingNext;
+    if (*list == NULL) {
+        dvmSetFieldObject(ref, offset, ref);
+        *list = ref;
+    } else {
+        Object *head = dvmGetFieldObject(*list, offset);
+        dvmSetFieldObject(ref, offset, head);
+        dvmSetFieldObject(*list, offset, ref);
+    }
+}
+
+/*
+ * Removes the reference at the head of a circular queue of
+ * references.
+ */
+static Object *dequeuePendingReference(Object **list)
+{
+    assert(list != NULL);
+    assert(*list != NULL);
+    size_t offset = gDvm.offJavaLangRefReference_pendingNext;
+    Object *head = dvmGetFieldObject(*list, offset);
+    Object *ref;
+    if (*list == head) {
+        ref = *list;
+        *list = NULL;
+    } else {
+        Object *next = dvmGetFieldObject(head, offset);
+        dvmSetFieldObject(*list, offset, next);
+        ref = head;
+    }
+    dvmSetFieldObject(ref, offset, NULL);
+    return ref;
+}
+
+/*
+ * Process the "referent" field in a java.lang.ref.Reference.  If the
+ * referent has not yet been marked, put it on the appropriate list in
+ * the gcHeap for later processing.
+ */
+static void delayReferenceReferent(Object *obj, GcMarkContext *ctx)
+{
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
+    assert(ctx != NULL);
+    GcHeap *gcHeap = gDvm.gcHeap;
+    size_t pendingNextOffset = gDvm.offJavaLangRefReference_pendingNext;
+    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
+    Object *pending = dvmGetFieldObject(obj, pendingNextOffset);
+    Object *referent = dvmGetFieldObject(obj, referentOffset);
+    if (pending == NULL && referent != NULL && !isMarked(referent, ctx)) {
+        Object **list = NULL;
+        if (isSoftReference(obj)) {
+            list = &gcHeap->softReferences;
+        } else if (isWeakReference(obj)) {
+            list = &gcHeap->weakReferences;
+        } else if (isFinalizerReference(obj)) {
+            list = &gcHeap->finalizerReferences;
+        } else if (isPhantomReference(obj)) {
+            list = &gcHeap->phantomReferences;
+        }
+        assert(list != NULL);
+        enqueuePendingReference(obj, list);
+    }
+}
+
+/*
+ * Scans the header and field references of a data object.
+ */
+static void scanDataObject(const Object *obj, GcMarkContext *ctx)
+{
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(ctx != NULL);
+    markObject((const Object *)obj->clazz, ctx);
+    scanFields(obj, ctx);
+    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
+        delayReferenceReferent((Object *)obj, ctx);
+    }
+}
+
+/*
+ * Scans an object reference.  Determines the type of the reference
+ * and dispatches to a specialized scanning routine.
+ */
+static void scanObject(const Object *obj, GcMarkContext *ctx)
+{
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    if (obj->clazz == gDvm.classJavaLangClass) {
+        scanClassObject(obj, ctx);
+    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+        scanArrayObject(obj, ctx);
+    } else {
+        scanDataObject(obj, ctx);
+    }
+}
+
+/*
+ * Scan anything that's on the mark stack.  We can't use the bitmaps
+ * anymore, so use a finger that points past the end of them.
+ */
+static void processMarkStack(GcMarkContext *ctx)
+{
+    assert(ctx != NULL);
+    assert(ctx->finger == (void *)ULONG_MAX);
+    assert(ctx->stack.top >= ctx->stack.base);
+    GcMarkStack *stack = &ctx->stack;
+    while (stack->top > stack->base) {
+        const Object *obj = markStackPop(stack);
+        scanObject(obj, ctx);
+    }
+}
+
+static size_t objectSize(const Object *obj)
+{
+    assert(dvmIsValidObject(obj));
+    assert(dvmIsValidObject((Object *)obj->clazz));
+    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+        return dvmArrayObjectSize((ArrayObject *)obj);
+    } else if (obj->clazz == gDvm.classJavaLangClass) {
+        return dvmClassObjectSize((ClassObject *)obj);
+    } else {
+        return obj->clazz->objectSize;
+    }
+}
+
+/*
+ * Scans forward to the header of the next marked object between start
+ * and limit.  Returns NULL if no marked objects are in that region.
+ */
+static Object *nextGrayObject(const u1 *base, const u1 *limit,
+                              const HeapBitmap *markBits)
+{
+    const u1 *ptr;
+
+    assert(base < limit);
+    assert(limit - base <= GC_CARD_SIZE);
+    for (ptr = base; ptr < limit; ptr += HB_OBJECT_ALIGNMENT) {
+        if (dvmHeapBitmapIsObjectBitSet(markBits, ptr))
+            return (Object *)ptr;
+    }
+    return NULL;
+}
+
+/*
+ * Scans range of dirty cards between start and end.  A range of dirty
+ * cards is composed consecutively dirty cards or dirty cards spanned
+ * by a gray object.  Returns the address of a clean card if the scan
+ * reached a clean card or NULL if the scan reached the end.
+ */
+const u1 *scanDirtyCards(const u1 *start, const u1 *end,
+                         GcMarkContext *ctx)
+{
+    const HeapBitmap *markBits = ctx->bitmap;
+    const u1 *card = start, *prevAddr = NULL;
+    while (card < end) {
+        if (*card != GC_CARD_DIRTY) {
+            return card;
+        }
+        const u1 *ptr = prevAddr ? prevAddr : (u1*)dvmAddrFromCard(card);
+        const u1 *limit = ptr + GC_CARD_SIZE;
+        while (ptr < limit) {
+            Object *obj = nextGrayObject(ptr, limit, markBits);
+            if (obj == NULL) {
+                break;
+            }
+            scanObject(obj, ctx);
+            ptr = (u1*)obj + ALIGN_UP(objectSize(obj), HB_OBJECT_ALIGNMENT);
+        }
+        if (ptr < limit) {
+            /* Ended within the current card, advance to the next card. */
+            ++card;
+            prevAddr = NULL;
+        } else {
+            /* Ended past the current card, skip ahead. */
+            card = dvmCardFromAddr(ptr);
+            prevAddr = ptr;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Blackens gray objects found on dirty cards.
+ */
+static void scanGrayObjects(GcMarkContext *ctx)
+{
+    GcHeap *h = gDvm.gcHeap;
+    const u1 *base, *limit, *ptr, *dirty;
+    size_t footprint;
+
+    footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
+    base = &h->cardTableBase[0];
+    limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetBase() + footprint);
+    assert(limit <= &h->cardTableBase[h->cardTableLength]);
+
+    ptr = base;
+    for (;;) {
+        dirty = (const u1 *)memchr(ptr, GC_CARD_DIRTY, limit - ptr);
+        if (dirty == NULL) {
+            break;
+        }
+        assert((dirty > ptr) && (dirty < limit));
+        ptr = scanDirtyCards(dirty, limit, ctx);
+        if (ptr == NULL) {
+            break;
+        }
+        assert((ptr > dirty) && (ptr < limit));
+    }
+}
+
+/*
+ * Callback for scanning each object in the bitmap.  The finger is set
+ * to the address corresponding to the lowest address in the next word
+ * of bits in the bitmap.
+ */
+static void scanBitmapCallback(Object *obj, void *finger, void *arg)
+{
+    GcMarkContext *ctx = (GcMarkContext *)arg;
+    ctx->finger = (void *)finger;
+    scanObject(obj, ctx);
+}
+
+/* Given bitmaps with the root set marked, find and mark all
+ * reachable objects.  When this returns, the entire set of
+ * live objects will be marked and the mark stack will be empty.
+ */
+void dvmHeapScanMarkedObjects(void)
+{
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+
+    assert(ctx->finger == NULL);
+
+    /* The bitmaps currently have bits set for the root set.
+     * Walk across the bitmaps and scan each object.
+     */
+    dvmHeapBitmapScanWalk(ctx->bitmap, scanBitmapCallback, ctx);
+
+    ctx->finger = (void *)ULONG_MAX;
+
+    /* We've walked the mark bitmaps.  Scan anything that's
+     * left on the mark stack.
+     */
+    processMarkStack(ctx);
+}
+
+void dvmHeapReScanMarkedObjects()
+{
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+
+    /*
+     * The finger must have been set to the maximum value to ensure
+     * that gray objects will be pushed onto the mark stack.
+     */
+    assert(ctx->finger == (void *)ULONG_MAX);
+    scanGrayObjects(ctx);
+    processMarkStack(ctx);
+}
+
+/*
+ * Clear the referent field.
+ */
+static void clearReference(Object *reference)
+{
+    size_t offset = gDvm.offJavaLangRefReference_referent;
+    dvmSetFieldObject(reference, offset, NULL);
+}
+
+/*
+ * Returns true if the reference was registered with a reference queue
+ * and has not yet been enqueued.
+ */
+static bool isEnqueuable(const Object *reference)
+{
+    assert(reference != NULL);
+    Object *queue = dvmGetFieldObject(reference,
+            gDvm.offJavaLangRefReference_queue);
+    Object *queueNext = dvmGetFieldObject(reference,
+            gDvm.offJavaLangRefReference_queueNext);
+    return queue != NULL && queueNext == NULL;
+}
+
+/*
+ * Schedules a reference to be appended to its reference queue.
+ */
+static void enqueueReference(Object *ref)
+{
+    assert(ref != NULL);
+    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
+    assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
+    enqueuePendingReference(ref, &gDvm.gcHeap->clearedReferences);
+}
+
+/*
+ * Walks the reference list marking any references subject to the
+ * reference clearing policy.  References with a black referent are
+ * removed from the list.  References with white referents biased
+ * toward saving are blackened and also removed from the list.
+ */
+static void preserveSomeSoftReferences(Object **list)
+{
+    assert(list != NULL);
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
+    Object *clear = NULL;
+    size_t counter = 0;
+    while (*list != NULL) {
+        Object *ref = dequeuePendingReference(list);
+        Object *referent = dvmGetFieldObject(ref, referentOffset);
+        if (referent == NULL) {
+            /* Referent was cleared by the user during marking. */
+            continue;
+        }
+        bool marked = isMarked(referent, ctx);
+        if (!marked && ((++counter) & 1)) {
+            /* Referent is white and biased toward saving, mark it. */
+            markObject(referent, ctx);
+            marked = true;
+        }
+        if (!marked) {
+            /* Referent is white, queue it for clearing. */
+            enqueuePendingReference(ref, &clear);
+        }
+    }
+    *list = clear;
+    /*
+     * Restart the mark with the newly black references added to the
+     * root set.
+     */
+    processMarkStack(ctx);
+}
+
+/*
+ * Unlink the reference list clearing references objects with white
+ * referents.  Cleared references registered to a reference queue are
+ * scheduled for appending by the heap worker thread.
+ */
+static void clearWhiteReferences(Object **list)
+{
+    assert(list != NULL);
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
+    while (*list != NULL) {
+        Object *ref = dequeuePendingReference(list);
+        Object *referent = dvmGetFieldObject(ref, referentOffset);
+        if (referent != NULL && !isMarked(referent, ctx)) {
+            /* Referent is white, clear it. */
+            clearReference(ref);
+            if (isEnqueuable(ref)) {
+                enqueueReference(ref);
+            }
+        }
+    }
+    assert(*list == NULL);
+}
+
+/*
+ * Enqueues finalizer references with white referents.  White
+ * referents are blackened, moved to the zombie field, and the
+ * referent field is cleared.
+ */
+static void enqueueFinalizerReferences(Object **list)
+{
+    assert(list != NULL);
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+    size_t referentOffset = gDvm.offJavaLangRefReference_referent;
+    size_t zombieOffset = gDvm.offJavaLangRefFinalizerReference_zombie;
+    bool hasEnqueued = false;
+    while (*list != NULL) {
+        Object *ref = dequeuePendingReference(list);
+        Object *referent = dvmGetFieldObject(ref, referentOffset);
+        if (referent != NULL && !isMarked(referent, ctx)) {
+            markObject(referent, ctx);
+            /* If the referent is non-null the reference must queuable. */
+            assert(isEnqueuable(ref));
+            dvmSetFieldObject(ref, zombieOffset, referent);
+            clearReference(ref);
+            enqueueReference(ref);
+            hasEnqueued = true;
+        }
+    }
+    if (hasEnqueued) {
+        processMarkStack(ctx);
+    }
+    assert(*list == NULL);
+}
+
+/*
+ * This object is an instance of a class that overrides finalize().  Mark
+ * it as finalizable.
+ *
+ * This is called when Object.<init> completes normally.  It's also
+ * called for clones of finalizable objects.
+ */
+void dvmSetFinalizable(Object *obj)
+{
+    assert(obj != NULL);
+    Thread *self = dvmThreadSelf();
+    assert(self != NULL);
+    Method *meth = gDvm.methJavaLangRefFinalizerReferenceAdd;
+    assert(meth != NULL);
+    JValue unusedResult;
+    dvmCallMethod(self, meth, NULL, &unusedResult, obj);
+}
+
+/*
+ * Process reference class instances and schedule finalizations.
+ */
+void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs,
+                              Object **weakReferences,
+                              Object **finalizerReferences,
+                              Object **phantomReferences)
+{
+    assert(softReferences != NULL);
+    assert(weakReferences != NULL);
+    assert(finalizerReferences != NULL);
+    assert(phantomReferences != NULL);
+    /*
+     * Unless we are in the zygote or required to clear soft
+     * references with white references, preserve some white
+     * referents.
+     */
+    if (!gDvm.zygote && !clearSoftRefs) {
+        preserveSomeSoftReferences(softReferences);
+    }
+    /*
+     * Clear all remaining soft and weak references with white
+     * referents.
+     */
+    clearWhiteReferences(softReferences);
+    clearWhiteReferences(weakReferences);
+    /*
+     * Preserve all white objects with finalize methods and schedule
+     * them for finalization.
+     */
+    enqueueFinalizerReferences(finalizerReferences);
+    /*
+     * Clear all f-reachable soft and weak references with white
+     * referents.
+     */
+    clearWhiteReferences(softReferences);
+    clearWhiteReferences(weakReferences);
+    /*
+     * Clear all phantom references with white referents.
+     */
+    clearWhiteReferences(phantomReferences);
+    /*
+     * At this point all reference lists should be empty.
+     */
+    assert(*softReferences == NULL);
+    assert(*weakReferences == NULL);
+    assert(*finalizerReferences == NULL);
+    assert(*phantomReferences == NULL);
+}
+
+/*
+ * Pushes a list of cleared references out to the managed heap.
+ */
+void dvmEnqueueClearedReferences(Object **cleared)
+{
+    assert(cleared != NULL);
+    if (*cleared != NULL) {
+        Thread *self = dvmThreadSelf();
+        assert(self != NULL);
+        Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
+        assert(meth != NULL);
+        JValue unused;
+        Object *reference = *cleared;
+        dvmCallMethod(self, meth, NULL, &unused, reference);
+        *cleared = NULL;
+    }
+}
+
+void dvmHeapFinishMarkStep()
+{
+    GcMarkContext *ctx = &gDvm.gcHeap->markContext;
+
+    /* The mark bits are now not needed.
+     */
+    dvmHeapSourceZeroMarkBitmap();
+
+    /* Clean up everything else associated with the marking process.
+     */
+    destroyMarkStack(&ctx->stack);
+
+    ctx->finger = NULL;
+}
+
+struct SweepContext {
+    size_t numObjects;
+    size_t numBytes;
+    bool isConcurrent;
+};
+
+static void sweepBitmapCallback(size_t numPtrs, void **ptrs, void *arg)
+{
+    assert(arg != NULL);
+    SweepContext *ctx = (SweepContext *)arg;
+    if (ctx->isConcurrent) {
+        dvmLockHeap();
+    }
+    ctx->numBytes += dvmHeapSourceFreeList(numPtrs, ptrs);
+    ctx->numObjects += numPtrs;
+    if (ctx->isConcurrent) {
+        dvmUnlockHeap();
+    }
+}
+
+/*
+ * Returns true if the given object is unmarked.  This assumes that
+ * the bitmaps have not yet been swapped.
+ */
+static int isUnmarkedObject(void *obj)
+{
+    return !isMarked((Object *)obj, &gDvm.gcHeap->markContext);
+}
+
+static void sweepWeakJniGlobals()
+{
+    IndirectRefTable* table = &gDvm.jniWeakGlobalRefTable;
+    GcMarkContext* ctx = &gDvm.gcHeap->markContext;
+    typedef IndirectRefTable::iterator It; // TODO: C++0x auto
+    for (It it = table->begin(), end = table->end(); it != end; ++it) {
+        Object** entry = *it;
+        if (!isMarked(*entry, ctx)) {
+            *entry = kClearedJniWeakGlobal;
+        }
+    }
+}
+
+/*
+ * Process all the internal system structures that behave like
+ * weakly-held objects.
+ */
+void dvmHeapSweepSystemWeaks()
+{
+    dvmGcDetachDeadInternedStrings(isUnmarkedObject);
+    dvmSweepMonitorList(&gDvm.monitorList, isUnmarkedObject);
+    sweepWeakJniGlobals();
+}
+
+/*
+ * Walk through the list of objects that haven't been marked and free
+ * them.  Assumes the bitmaps have been swapped.
+ */
+void dvmHeapSweepUnmarkedObjects(bool isPartial, bool isConcurrent,
+                                 size_t *numObjects, size_t *numBytes)
+{
+    uintptr_t base[HEAP_SOURCE_MAX_HEAP_COUNT];
+    uintptr_t max[HEAP_SOURCE_MAX_HEAP_COUNT];
+    SweepContext ctx;
+    HeapBitmap *prevLive, *prevMark;
+    size_t numHeaps, numSweepHeaps;
+
+    numHeaps = dvmHeapSourceGetNumHeaps();
+    dvmHeapSourceGetRegions(base, max, numHeaps);
+    if (isPartial) {
+        assert((uintptr_t)gDvm.gcHeap->markContext.immuneLimit == base[0]);
+        numSweepHeaps = 1;
+    } else {
+        numSweepHeaps = numHeaps;
+    }
+    ctx.numObjects = ctx.numBytes = 0;
+    ctx.isConcurrent = isConcurrent;
+    prevLive = dvmHeapSourceGetMarkBits();
+    prevMark = dvmHeapSourceGetLiveBits();
+    for (size_t i = 0; i < numSweepHeaps; ++i) {
+        dvmHeapBitmapSweepWalk(prevLive, prevMark, base[i], max[i],
+                               sweepBitmapCallback, &ctx);
+    }
+    *numObjects = ctx.numObjects;
+    *numBytes = ctx.numBytes;
+    if (gDvm.allocProf.enabled) {
+        gDvm.allocProf.freeCount += ctx.numObjects;
+        gDvm.allocProf.freeSize += ctx.numBytes;
+    }
+}
diff --git a/vm/alloc/MarkSweep.h b/vm/alloc/MarkSweep.h
new file mode 100644
index 0000000..b14333a
--- /dev/null
+++ b/vm/alloc/MarkSweep.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+#ifndef DALVIK_ALLOC_MARK_SWEEP_H_
+#define DALVIK_ALLOC_MARK_SWEEP_H_
+
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapSource.h"
+
+struct GcMarkStack {
+    /* Highest address (exclusive)
+     */
+    const Object **limit;
+
+    /* Current top of the stack (exclusive)
+     */
+    const Object **top;
+
+    /* Lowest address (inclusive)
+     */
+    const Object **base;
+
+    /* Maximum stack size, in bytes.
+     */
+    size_t length;
+};
+
+/* This is declared publicly so that it can be included in gDvm.gcHeap.
+ */
+struct GcMarkContext {
+    HeapBitmap *bitmap;
+    GcMarkStack stack;
+    const char *immuneLimit;
+    const void *finger;   // only used while scanning/recursing.
+};
+
+bool dvmHeapBeginMarkStep(bool isPartial);
+void dvmHeapMarkRootSet(void);
+void dvmHeapReMarkRootSet(void);
+void dvmHeapScanMarkedObjects(void);
+void dvmHeapReScanMarkedObjects(void);
+void dvmHeapProcessReferences(Object **softReferences, bool clearSoftRefs,
+                              Object **weakReferences,
+                              Object **finalizerReferences,
+                              Object **phantomReferences);
+void dvmHeapFinishMarkStep(void);
+void dvmHeapSweepSystemWeaks(void);
+void dvmHeapSweepUnmarkedObjects(bool isPartial, bool isConcurrent,
+                                 size_t *numObjects, size_t *numBytes);
+void dvmEnqueueClearedReferences(Object **references);
+
+#endif  // DALVIK_ALLOC_MARK_SWEEP_H_
diff --git a/vm/alloc/TEST/HeapBitmapTest/Makefile b/vm/alloc/TEST/HeapBitmapTest/Makefile
new file mode 100644
index 0000000..969eb63
--- /dev/null
+++ b/vm/alloc/TEST/HeapBitmapTest/Makefile
@@ -0,0 +1,25 @@
+.PHONY: all
+all: runtest
+
+$(shell mkdir -p out)
+
+CC := gcc
+CFLAGS := -g -Wall -Werror
+#CFLAGS += -O2
+
+out/main.o: main.c ../../HeapBitmap.h
+	$(CC) $(CFLAGS) -c $< -o $@ -I ../..
+
+out/HeapBitmap.o: ../../HeapBitmap.c ../../HeapBitmap.h include/cutils/ashmem.h include/Dalvik.h
+	$(CC) $(CFLAGS) -c $< -o $@ -I ../.. -I include
+
+out/hbtest: out/main.o out/HeapBitmap.o out/clz.o
+	$(CC) $^ -o $@
+
+.PHONY: runtest
+runtest: out/hbtest
+	out/hbtest
+
+.PHONY: clean
+clean:
+	rm -rf out
diff --git a/vm/alloc/TEST/HeapBitmapTest/include/Dalvik.h b/vm/alloc/TEST/HeapBitmapTest/include/Dalvik.h
new file mode 100644
index 0000000..4c9f608
--- /dev/null
+++ b/vm/alloc/TEST/HeapBitmapTest/include/Dalvik.h
@@ -0,0 +1,18 @@
+#ifndef DALVIK_H_
+#define DALVIK_H_
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#define LOGW(...) printf("W/" __VA_ARGS__)
+#define LOGE(...) printf("E/" __VA_ARGS__)
+
+inline void dvmAbort(void) {
+    exit(1);
+}
+
+#endif  // DALVIK_H_
diff --git a/vm/alloc/TEST/HeapBitmapTest/include/cutils/ashmem.h b/vm/alloc/TEST/HeapBitmapTest/include/cutils/ashmem.h
new file mode 100644
index 0000000..8680c77
--- /dev/null
+++ b/vm/alloc/TEST/HeapBitmapTest/include/cutils/ashmem.h
@@ -0,0 +1,14 @@
+#ifndef ASHMEM_H_
+#define ASHMEM_H_
+
+#include <fcntl.h>
+
+#define ASHMEM_NAME_LEN 128
+
+inline int
+ashmem_create_region(const char *name, size_t len)
+{
+    return open("/dev/zero", O_RDWR);
+}
+
+#endif
diff --git a/vm/alloc/TEST/HeapBitmapTest/main.c b/vm/alloc/TEST/HeapBitmapTest/main.c
new file mode 100644
index 0000000..10fa7f8
--- /dev/null
+++ b/vm/alloc/TEST/HeapBitmapTest/main.c
@@ -0,0 +1,496 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#define __attribute(x) /* disable inlining */
+#include "HeapBitmap.h"
+#undef __attribute
+
+#define PAGE_SIZE 4096
+#define HEAP_BASE ((void *)0x10000)
+#define HEAP_SIZE (5 * PAGE_SIZE + 888)
+
+#define VERBOSE 1
+#if VERBOSE
+#define TRACE(...) printf(__VA_ARGS__)
+#else
+#define TRACE(...) /**/
+#endif
+
+void
+test_init()
+{
+    HeapBitmap hb;
+    bool ok;
+
+    memset(&hb, 0x55, sizeof(hb));
+
+    ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
+    assert(ok);
+
+    assert(hb.bits != NULL);
+    assert(hb.bitsLen >= HB_OFFSET_TO_INDEX(HEAP_SIZE));
+    assert(hb.base == (uintptr_t)HEAP_BASE);
+    assert(hb.max < hb.base);
+
+    /* Make sure hb.bits is mapped.
+     */
+    *hb.bits = 0x55;
+    assert(*hb.bits = 0x55);
+    *hb.bits = 0;
+
+#define TEST_UNMAP 0
+#if TEST_UNMAP
+    /* Hold onto this to make sure it's unmapped later.
+     */
+    unsigned long int *bits = hb.bits;
+#endif
+
+    dvmHeapBitmapDelete(&hb);
+
+    assert(hb.bits == NULL);
+    assert(hb.bitsLen == 0);
+    assert(hb.base == 0);
+    assert(hb.max == 0);
+
+#if TEST_UNMAP
+    /* This pointer shouldn't be mapped anymore.
+     */
+    *bits = 0x55;
+    assert(!"Should have segfaulted");
+#endif
+}
+
+bool is_zeroed(const HeapBitmap *hb)
+{
+    int i;
+
+    for (i = 0; i < hb->bitsLen / sizeof (*hb->bits); i++) {
+        if (hb->bits[i] != 0L) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void assert_empty(const HeapBitmap *hb)
+{
+    assert(hb->bits != NULL);
+    assert(hb->bitsLen >= HB_OFFSET_TO_INDEX(HEAP_SIZE));
+    assert(hb->base == (uintptr_t)HEAP_BASE);
+    assert(hb->max < hb->base);
+
+    assert(is_zeroed(hb));
+
+    assert(!dvmHeapBitmapMayContainObject(hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapMayContainObject(hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(!dvmHeapBitmapIsObjectBitSet(hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapIsObjectBitSet(hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+}
+
+void
+test_bits()
+{
+    HeapBitmap hb;
+    bool ok;
+
+    ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
+    assert(ok);
+
+    assert_empty(&hb);
+
+    /* Set the lowest address.
+     */
+    dvmHeapBitmapSetObjectBit(&hb, HEAP_BASE);
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+
+    /* Set the highest address.
+     */
+    dvmHeapBitmapSetObjectBit(&hb, HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE));
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+
+    /* Clear the lowest address.
+     */
+    dvmHeapBitmapClearObjectBit(&hb, HEAP_BASE);
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!is_zeroed(&hb));
+
+    /* Clear the highest address.
+     */
+    dvmHeapBitmapClearObjectBit(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(is_zeroed(&hb));
+
+    /* Clean up.
+     */
+    dvmHeapBitmapDelete(&hb);
+}
+
+void
+test_clear()
+{
+    HeapBitmap hb;
+    bool ok;
+
+    ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
+    assert(ok);
+    assert_empty(&hb);
+
+    /* Set the highest address.
+     */
+    dvmHeapBitmapSetObjectBit(&hb, HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
+    assert(!is_zeroed(&hb));
+
+    /* Clear the bitmap.
+     */
+    dvmHeapBitmapZero(&hb);
+    assert_empty(&hb);
+
+    /* Clean up.
+     */
+    dvmHeapBitmapDelete(&hb);
+}
+
+void
+test_modify()
+{
+    HeapBitmap hb;
+    bool ok;
+    unsigned long bit;
+
+    ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
+    assert(ok);
+    assert_empty(&hb);
+
+    /* Set the lowest address.
+     */
+    bit = dvmHeapBitmapSetAndReturnObjectBit(&hb, HEAP_BASE);
+    assert(bit == 0);
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+
+    /* Set the lowest address again.
+     */
+    bit = dvmHeapBitmapSetAndReturnObjectBit(&hb, HEAP_BASE);
+    assert(bit != 0);
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+
+    /* Set the highest address.
+     */
+    bit = dvmHeapBitmapSetAndReturnObjectBit(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
+    assert(bit == 0);
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE));
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+
+    /* Set the highest address again.
+     */
+    bit = dvmHeapBitmapSetAndReturnObjectBit(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
+    assert(bit != 0);
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE));
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+    assert(!dvmHeapBitmapMayContainObject(&hb,
+            HEAP_BASE + HEAP_SIZE));
+
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE));
+    assert(!dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HB_OBJECT_ALIGNMENT));
+    assert(dvmHeapBitmapIsObjectBitSet(&hb,
+            HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
+
+    /* Clean up.
+     */
+    dvmHeapBitmapDelete(&hb);
+}
+
+/*
+ * xor test support functions
+ */
+
+static void *gCallbackArg = NULL;
+
+#define NUM_XOR_PTRS  128
+static size_t gNumPtrs;
+static void *gXorPtrs[NUM_XOR_PTRS];
+static bool gClearedPtrs[NUM_XOR_PTRS];
+static bool gSeenPtrs[NUM_XOR_PTRS];
+
+bool
+xorCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
+{
+    assert(numPtrs > 0);
+    assert(ptrs != NULL);
+    assert(arg == gCallbackArg);
+
+size_t i;
+    for (i = 0; i < numPtrs; i++) {
+        assert(ptrs[i] < finger);
+        printf("callback: 0x%08x ( < 0x%08x )\n",
+                (uintptr_t)ptrs[i], (uintptr_t)finger);
+    }
+
+    return true;
+}
+
+bool
+seenAndClearedMatch()
+{
+    size_t i;
+    for (i = 0; i < gNumPtrs; i++) {
+        if (gClearedPtrs[i] != gSeenPtrs[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void
+run_xor(ssize_t offset, size_t step)
+{
+    assert(step != 0);
+    assert(step < HEAP_SIZE);
+
+    /* Figure out the range.
+     */
+uintptr_t base;
+uintptr_t top;
+    if (offset >= 0) {
+        base = (uintptr_t)HEAP_BASE + offset;
+    } else {
+        base = (uintptr_t)HEAP_BASE + (uintptr_t)HEAP_SIZE + offset;
+    }
+    if (base < (uintptr_t)HEAP_BASE) {
+        base = (uintptr_t)HEAP_BASE;
+    } else if (base > (uintptr_t)(HEAP_BASE + HEAP_SIZE)) {
+        base = (uintptr_t)(HEAP_BASE + HEAP_SIZE);
+    } else {
+        base = (base + HB_OBJECT_ALIGNMENT - 1) & ~(HB_OBJECT_ALIGNMENT - 1);
+    }
+    step *= HB_OBJECT_ALIGNMENT;
+    top = base + step * NUM_XOR_PTRS;
+    if (top > (uintptr_t)(HEAP_BASE + HEAP_SIZE)) {
+        top = (uintptr_t)(HEAP_BASE + HEAP_SIZE);
+    }
+
+    /* Create the pointers.
+     */
+    gNumPtrs = 0;
+    memset(gXorPtrs, 0, sizeof(gXorPtrs));
+    memset(gClearedPtrs, 0, sizeof(gClearedPtrs));
+    memset(gSeenPtrs, 0, sizeof(gSeenPtrs));
+
+uintptr_t addr;
+void **p = gXorPtrs;
+    for (addr = base; addr < top; addr += step) {
+        *p++ = (void *)addr;
+        gNumPtrs++;
+    }
+    assert(seenAndClearedMatch());
+
+    /* Set up the bitmaps.
+     */
+HeapBitmap hb1, hb2;
+bool ok;
+
+    ok = dvmHeapBitmapInit(&hb1, HEAP_BASE, HEAP_SIZE, "test1");
+    assert(ok);
+    ok = dvmHeapBitmapInitFromTemplate(&hb2, &hb1, "test2");
+    assert(ok);
+
+    /* Walk two empty bitmaps.
+     */
+TRACE("walk 0\n");
+    ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
+    assert(ok);
+    assert(seenAndClearedMatch());
+
+    /* Walk one empty bitmap.
+     */
+TRACE("walk 1\n");
+    dvmHeapBitmapSetObjectBit(&hb1, (void *)base);
+    ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
+    assert(ok);
+
+    /* Make the bitmaps match.
+     */
+TRACE("walk 2\n");
+    dvmHeapBitmapSetObjectBit(&hb2, (void *)base);
+    ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
+    assert(ok);
+
+    /* Clear the bitmaps.
+     */
+    dvmHeapBitmapZero(&hb1);
+    assert_empty(&hb1);
+    dvmHeapBitmapZero(&hb2);
+    assert_empty(&hb2);
+
+    /* Set the pointers we created in one of the bitmaps,
+     * then visit them.
+     */
+size_t i;
+    for (i = 0; i < gNumPtrs; i++) {
+        dvmHeapBitmapSetObjectBit(&hb1, gXorPtrs[i]);
+    }
+TRACE("walk 3\n");
+    ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
+    assert(ok);
+
+    /* Set every third pointer in the other bitmap, and visit again.
+     */
+    for (i = 0; i < gNumPtrs; i += 3) {
+        dvmHeapBitmapSetObjectBit(&hb2, gXorPtrs[i]);
+    }
+TRACE("walk 4\n");
+    ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
+    assert(ok);
+
+    /* Set every other pointer in the other bitmap, and visit again.
+     */
+    for (i = 0; i < gNumPtrs; i += 2) {
+        dvmHeapBitmapSetObjectBit(&hb2, gXorPtrs[i]);
+    }
+TRACE("walk 5\n");
+    ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
+    assert(ok);
+
+    /* Walk just one bitmap.
+     */
+TRACE("walk 6\n");
+    ok = dvmHeapBitmapWalk(&hb2, xorCallback, gCallbackArg);
+    assert(ok);
+
+//xxx build an expect list for the callback
+//xxx test where max points to beginning, middle, and end of a word
+
+    /* Clean up.
+     */
+    dvmHeapBitmapDelete(&hb1);
+    dvmHeapBitmapDelete(&hb2);
+}
+
+void
+test_xor()
+{
+    run_xor(0, 1);
+    run_xor(100, 34);
+}
+
+int main(int argc, char *argv[])
+{
+    printf("test_init...\n");
+    test_init();
+
+    printf("test_bits...\n");
+    test_bits();
+
+    printf("test_clear...\n");
+    test_clear();
+
+    printf("test_modify...\n");
+    test_modify();
+
+    printf("test_xor...\n");
+    test_xor();
+
+    printf("done.\n");
+    return 0;
+}
diff --git a/vm/alloc/Verify.cpp b/vm/alloc/Verify.cpp
new file mode 100644
index 0000000..6d830c7
--- /dev/null
+++ b/vm/alloc/Verify.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "alloc/HeapBitmap.h"
+#include "alloc/HeapSource.h"
+#include "alloc/Verify.h"
+#include "alloc/Visit.h"
+
+/*
+ * Visitor applied to each reference field when searching for things
+ * that point to an object.  Sets the argument to NULL when a match is
+ * found.
+ */
+static void dumpReferencesVisitor(void *pObj, void *arg)
+{
+    Object *obj = *(Object **)pObj;
+    Object *lookingFor = *(Object **)arg;
+    if (lookingFor != NULL && lookingFor == obj) {
+        *(Object **)arg = NULL;
+    }
+}
+
+/*
+ * Visitor applied to each bitmap element to search for things that
+ * point to an object.  Logs a message when a match is found.
+ */
+static void dumpReferencesCallback(Object *obj, void *arg)
+{
+    if (obj == (Object *)arg) {
+        return;
+    }
+    dvmVisitObject(dumpReferencesVisitor, obj, &arg);
+    if (arg == NULL) {
+        LOGD("Found %p in the heap @ %p", arg, obj);
+        dvmDumpObject(obj);
+    }
+}
+
+/*
+ * Visitor applied to each root to search for things that point to an
+ * object.  Logs a message when a match is found.
+ */
+static void dumpReferencesRootVisitor(void *ptr, u4 threadId,
+                                      RootType type, void *arg)
+{
+    Object *obj = *(Object **)ptr;
+    Object *lookingFor = *(Object **)arg;
+    if (obj == lookingFor) {
+        LOGD("Found %p in a root @ %p", arg, ptr);
+    }
+}
+
+/*
+ * Searches the roots and heap for object references.
+ */
+static void dumpReferences(const Object *obj)
+{
+    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
+    void *arg = (void *)obj;
+    dvmVisitRoots(dumpReferencesRootVisitor, arg);
+    dvmHeapBitmapWalk(bitmap, dumpReferencesCallback, arg);
+}
+
+/*
+ * Checks that the given reference points to a valid object.
+ */
+static void verifyReference(void *addr, void *arg)
+{
+    Object *obj;
+    bool isValid;
+
+    assert(addr != NULL);
+    obj = *(Object **)addr;
+    if (obj == NULL) {
+        isValid = true;
+    } else {
+        isValid = dvmIsValidObject(obj);
+    }
+    if (!isValid) {
+        Object **parent = (Object **)arg;
+        if (*parent != NULL) {
+            LOGE("Verify of object %p failed", *parent);
+            dvmDumpObject(*parent);
+            *parent = NULL;
+        }
+        LOGE("Verify of reference %p @ %p failed", obj, addr);
+        dvmDumpObject(obj);
+    }
+}
+
+/*
+ * Verifies an object reference.
+ */
+void dvmVerifyObject(const Object *obj)
+{
+    Object *arg = const_cast<Object*>(obj);
+    dvmVisitObject(verifyReference, arg, &arg);
+    if (arg == NULL) {
+        dumpReferences(obj);
+        dvmAbort();
+    }
+}
+
+/*
+ * Helper function to call dvmVerifyObject from a bitmap walker.
+ */
+static void verifyBitmapCallback(Object *obj, void *arg)
+{
+    dvmVerifyObject(obj);
+}
+
+/*
+ * Verifies the object references in a heap bitmap. Assumes the VM is
+ * suspended.
+ */
+void dvmVerifyBitmap(const HeapBitmap *bitmap)
+{
+    dvmHeapBitmapWalk(bitmap, verifyBitmapCallback, NULL);
+}
+
+/*
+ * Helper function to call verifyReference from the root verifier.
+ */
+static void verifyRootReference(void *addr, u4 threadId,
+                                RootType type, void *arg)
+{
+    verifyReference(addr, arg);
+}
+
+/*
+ * Verifies references in the roots.
+ */
+void dvmVerifyRoots()
+{
+    dvmVisitRoots(verifyRootReference, NULL);
+}
diff --git a/vm/alloc/Verify.h b/vm/alloc/Verify.h
new file mode 100644
index 0000000..b9370ff
--- /dev/null
+++ b/vm/alloc/Verify.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_ALLOC_VERIFY_H_
+#define DALVIK_ALLOC_VERIFY_H_
+
+/*
+ * Verifies an object reference.
+ */
+void dvmVerifyObject(const Object *obj);
+
+/*
+ * Verifies the object references in a heap bitmap. Assumes the VM is
+ * suspended.
+ */
+void dvmVerifyBitmap(const HeapBitmap *bitmap);
+
+/*
+ * Verifies the contents of various global roots.
+ */
+void dvmVerifyRoots(void);
+
+#endif  // DALVIK_ALLOC_VERIFY_H_
diff --git a/vm/alloc/Visit.cpp b/vm/alloc/Visit.cpp
new file mode 100644
index 0000000..7eaff07
--- /dev/null
+++ b/vm/alloc/Visit.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/Visit.h"
+#include "alloc/VisitInlines.h"
+
+/*
+ * Visits all of the reference locations in an object.
+ */
+void dvmVisitObject(Visitor *visitor, Object *obj, void *arg)
+{
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    visitObject(visitor, obj, arg);
+}
+
+/*
+ * Applies a verification function to all present values in the hash table.
+ */
+static void visitHashTable(RootVisitor *visitor, HashTable *table,
+                           RootType type, void *arg)
+{
+    assert(visitor != NULL);
+    assert(table != NULL);
+    dvmHashTableLock(table);
+    for (int i = 0; i < table->tableSize; ++i) {
+        HashEntry *entry = &table->pEntries[i];
+        if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
+            (*visitor)(&entry->data, 0, type, arg);
+        }
+    }
+    dvmHashTableUnlock(table);
+}
+
+/*
+ * Visits all entries in the reference table.
+ */
+static void visitReferenceTable(RootVisitor *visitor, ReferenceTable *table,
+                                u4 threadId, RootType type, void *arg)
+{
+    assert(visitor != NULL);
+    assert(table != NULL);
+    for (Object **entry = table->table; entry < table->nextEntry; ++entry) {
+        assert(entry != NULL);
+        (*visitor)(entry, threadId, type, arg);
+    }
+}
+
+/*
+ * Visits all entries in the indirect reference table.
+ */
+static void visitIndirectRefTable(RootVisitor *visitor, IndirectRefTable *table,
+                                  u4 threadId, RootType type, void *arg)
+{
+    assert(visitor != NULL);
+    assert(table != NULL);
+    typedef IndirectRefTable::iterator It; // TODO: C++0x auto
+    for (It it = table->begin(), end = table->end(); it != end; ++it) {
+        (*visitor)(*it, threadId, type, arg);
+    }
+}
+
+/*
+ * Visits all stack slots except those belonging to native method
+ * arguments.
+ */
+static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg)
+{
+    assert(visitor != NULL);
+    assert(thread != NULL);
+    u4 threadId = thread->threadId;
+    const StackSaveArea *saveArea;
+    for (u4 *fp = (u4 *)thread->interpSave.curFrame;
+         fp != NULL;
+         fp = (u4 *)saveArea->prevFrame) {
+        Method *method;
+        saveArea = SAVEAREA_FROM_FP(fp);
+        method = (Method *)saveArea->method;
+        if (method != NULL && !dvmIsNativeMethod(method)) {
+            const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
+            const u1* regVector = NULL;
+            if (pMap != NULL) {
+                /* found map, get registers for this address */
+                int addr = saveArea->xtra.currentPc - method->insns;
+                regVector = dvmRegisterMapGetLine(pMap, addr);
+            }
+            if (regVector == NULL) {
+                /*
+                 * Either there was no register map or there is no
+                 * info for the current PC.  Perform a conservative
+                 * scan.
+                 */
+                for (size_t i = 0; i < method->registersSize; ++i) {
+                    if (dvmIsValidObject((Object *)fp[i])) {
+                        (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg);
+                    }
+                }
+            } else {
+                /*
+                 * Precise scan.  v0 is at the lowest address on the
+                 * interpreted stack, and is the first bit in the
+                 * register vector, so we can walk through the
+                 * register map and memory in the same direction.
+                 *
+                 * A '1' bit indicates a live reference.
+                 */
+                u2 bits = 1 << 1;
+                for (size_t i = 0; i < method->registersSize; ++i) {
+                    bits >>= 1;
+                    if (bits == 1) {
+                        /* set bit 9 so we can tell when we're empty */
+                        bits = *regVector++ | 0x0100;
+                    }
+                    if ((bits & 0x1) != 0) {
+                        /*
+                         * Register is marked as live, it's a valid root.
+                         */
+#if WITH_EXTRA_GC_CHECKS
+                        if (fp[i] != 0 && !dvmIsValidObject((Object *)fp[i])) {
+                            /* this is very bad */
+                            LOGE("PGC: invalid ref in reg %d: %#x",
+                                 method->registersSize - 1 - i, fp[i]);
+                            LOGE("PGC: %s.%s addr %#x",
+                                 method->clazz->descriptor, method->name,
+                                 saveArea->xtra.currentPc - method->insns);
+                            continue;
+                        }
+#endif
+                        (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg);
+                    }
+                }
+                dvmReleaseRegisterMapLine(pMap, regVector);
+            }
+        }
+        /*
+         * Don't fall into an infinite loop if things get corrupted.
+         */
+        assert((uintptr_t)saveArea->prevFrame > (uintptr_t)fp ||
+               saveArea->prevFrame == NULL);
+    }
+}
+
+/*
+ * Visits all roots associated with a thread.
+ */
+static void visitThread(RootVisitor *visitor, Thread *thread, void *arg)
+{
+    u4 threadId;
+
+    assert(visitor != NULL);
+    assert(thread != NULL);
+    threadId = thread->threadId;
+    (*visitor)(&thread->threadObj, threadId, ROOT_THREAD_OBJECT, arg);
+    (*visitor)(&thread->exception, threadId, ROOT_NATIVE_STACK, arg);
+    visitReferenceTable(visitor, &thread->internalLocalRefTable, threadId, ROOT_NATIVE_STACK, arg);
+    visitIndirectRefTable(visitor, &thread->jniLocalRefTable, threadId, ROOT_JNI_LOCAL, arg);
+    if (thread->jniMonitorRefTable.table != NULL) {
+        visitReferenceTable(visitor, &thread->jniMonitorRefTable, threadId, ROOT_JNI_MONITOR, arg);
+    }
+    visitThreadStack(visitor, thread, arg);
+}
+
+/*
+ * Visits all threads on the thread list.
+ */
+static void visitThreads(RootVisitor *visitor, void *arg)
+{
+    Thread *thread;
+
+    assert(visitor != NULL);
+    dvmLockThreadList(dvmThreadSelf());
+    thread = gDvm.threadList;
+    while (thread) {
+        visitThread(visitor, thread, arg);
+        thread = thread->next;
+    }
+    dvmUnlockThreadList();
+}
+
+static void visitPrimitiveTypes(RootVisitor *visitor, void *arg)
+{
+    (*visitor)(&gDvm.typeVoid, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeBoolean, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeByte, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeShort, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeChar, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeInt, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeLong, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeFloat, 0, ROOT_STICKY_CLASS, arg);
+    (*visitor)(&gDvm.typeDouble, 0, ROOT_STICKY_CLASS, arg);
+}
+
+/*
+ * Visits roots.  TODO: visit cached global references.
+ */
+void dvmVisitRoots(RootVisitor *visitor, void *arg)
+{
+    assert(visitor != NULL);
+    visitHashTable(visitor, gDvm.loadedClasses, ROOT_STICKY_CLASS, arg);
+    visitPrimitiveTypes(visitor, arg);
+    if (gDvm.dbgRegistry != NULL) {
+        visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg);
+    }
+    if (gDvm.literalStrings != NULL) {
+        visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg);
+    }
+    dvmLockMutex(&gDvm.jniGlobalRefLock);
+    visitIndirectRefTable(visitor, &gDvm.jniGlobalRefTable, 0, ROOT_JNI_GLOBAL, arg);
+    dvmUnlockMutex(&gDvm.jniGlobalRefLock);
+    dvmLockMutex(&gDvm.jniPinRefLock);
+    visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg);
+    dvmUnlockMutex(&gDvm.jniPinRefLock);
+    visitThreads(visitor, arg);
+    (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
+    (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
+    (*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg);
+}
diff --git a/vm/alloc/Visit.h b/vm/alloc/Visit.h
new file mode 100644
index 0000000..ff69a63
--- /dev/null
+++ b/vm/alloc/Visit.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_ALLOC_VISIT_H_
+#define DALVIK_ALLOC_VISIT_H_
+
+#include "Dalvik.h"
+
+enum RootType {
+  ROOT_UNKNOWN = 0,
+  ROOT_JNI_GLOBAL,
+  ROOT_JNI_LOCAL,
+  ROOT_JAVA_FRAME,
+  ROOT_NATIVE_STACK,
+  ROOT_STICKY_CLASS,
+  ROOT_THREAD_BLOCK,
+  ROOT_MONITOR_USED,
+  ROOT_THREAD_OBJECT,
+  ROOT_INTERNED_STRING,
+  ROOT_DEBUGGER,
+  ROOT_VM_INTERNAL,
+  ROOT_JNI_MONITOR,
+};
+
+/*
+ * Callback invoked with the address of a reference and a user
+ * supplied context argument.
+ */
+typedef void Visitor(void *addr, void *arg);
+
+/*
+ * Like a Visitor, but passes root specific information such as the
+ * containing thread id and the root type.  In cases where a root is
+ * not specific to a thread, 0, an invalid thread id is provided.
+ */
+typedef void RootVisitor(void *addr, u4 threadId, RootType type, void *arg);
+
+/*
+ * Visits references in an object.
+ */
+void dvmVisitObject(Visitor *visitor, Object *obj, void *arg);
+
+/*
+ * Visits references in the root set.
+ */
+void dvmVisitRoots(RootVisitor *visitor, void *arg);
+
+#endif  // DALVIK_ALLOC_VISIT_H_
diff --git a/vm/alloc/VisitInlines.h b/vm/alloc/VisitInlines.h
new file mode 100644
index 0000000..c6204ac
--- /dev/null
+++ b/vm/alloc/VisitInlines.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_ALLOC_VISITINLINES_H_
+#define DALVIK_ALLOC_VISITINLINES_H_
+
+/*
+ * Visits the instance fields of a class or data object.
+ */
+static void visitFields(Visitor *visitor, Object *obj, void *arg)
+{
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    if (obj->clazz->refOffsets != CLASS_WALK_SUPER) {
+        size_t refOffsets = obj->clazz->refOffsets;
+        while (refOffsets != 0) {
+            size_t rshift = CLZ(refOffsets);
+            size_t offset = CLASS_OFFSET_FROM_CLZ(rshift);
+            Object **ref = (Object **)BYTE_OFFSET(obj, offset);
+            (*visitor)(ref, arg);
+            refOffsets &= ~(CLASS_HIGH_BIT >> rshift);
+        }
+    } else {
+        for (ClassObject *clazz = obj->clazz;
+             clazz != NULL;
+             clazz = clazz->super) {
+            InstField *field = clazz->ifields;
+            for (int i = 0; i < clazz->ifieldRefCount; ++i, ++field) {
+                size_t offset = field->byteOffset;
+                Object **ref = (Object **)BYTE_OFFSET(obj, offset);
+                (*visitor)(ref, arg);
+            }
+        }
+    }
+}
+
+/*
+ * Visits the static fields of a class object.
+ */
+static void visitStaticFields(Visitor *visitor, ClassObject *clazz,
+                              void *arg)
+{
+    assert(visitor != NULL);
+    assert(clazz != NULL);
+    for (int i = 0; i < clazz->sfieldCount; ++i) {
+        char ch = clazz->sfields[i].signature[0];
+        if (ch == '[' || ch == 'L') {
+            (*visitor)(&clazz->sfields[i].value.l, arg);
+        }
+    }
+}
+
+/*
+ * Visit the interfaces of a class object.
+ */
+static void visitInterfaces(Visitor *visitor, ClassObject *clazz,
+                            void *arg)
+{
+    assert(visitor != NULL);
+    assert(clazz != NULL);
+    for (int i = 0; i < clazz->interfaceCount; ++i) {
+        (*visitor)(&clazz->interfaces[i], arg);
+    }
+}
+
+/*
+ * Visits all the references stored in a class object instance.
+ */
+static void visitClassObject(Visitor *visitor, Object *obj, void *arg)
+{
+    ClassObject *asClass;
+
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    assert(!strcmp(obj->clazz->descriptor, "Ljava/lang/Class;"));
+    (*visitor)(&obj->clazz, arg);
+    asClass = (ClassObject *)obj;
+    if (IS_CLASS_FLAG_SET(asClass, CLASS_ISARRAY)) {
+        (*visitor)(&asClass->elementClass, arg);
+    }
+    if (asClass->status > CLASS_IDX) {
+        (*visitor)(&asClass->super, arg);
+    }
+    (*visitor)(&asClass->classLoader, arg);
+    visitFields(visitor, obj, arg);
+    visitStaticFields(visitor, asClass, arg);
+    if (asClass->status > CLASS_IDX) {
+      visitInterfaces(visitor, asClass, arg);
+    }
+}
+
+/*
+ * Visits the class object and, if the array is typed as an object
+ * array, all of the array elements.
+ */
+static void visitArrayObject(Visitor *visitor, Object *obj, void *arg)
+{
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    (*visitor)(&obj->clazz, arg);
+    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISOBJECTARRAY)) {
+        ArrayObject *array = (ArrayObject *)obj;
+        Object **contents = (Object **)(void *)array->contents;
+        for (size_t i = 0; i < array->length; ++i) {
+            (*visitor)(&contents[i], arg);
+        }
+    }
+}
+
+/*
+ * Visits the class object and reference typed instance fields of a
+ * data object.
+ */
+static void visitDataObject(Visitor *visitor, Object *obj, void *arg)
+{
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    (*visitor)(&obj->clazz, arg);
+    visitFields(visitor, obj, arg);
+}
+
+/*
+ * Like visitDataObject, but visits the hidden referent field that
+ * belongings to the subclasses of java.lang.Reference.
+ */
+static void visitReferenceObject(Visitor *visitor, Object *obj, void *arg)
+{
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    visitDataObject(visitor, obj, arg);
+    size_t offset = gDvm.offJavaLangRefReference_referent;
+    Object **ref = (Object **)BYTE_OFFSET(obj, offset);
+    (*visitor)(ref, arg);
+}
+
+/*
+ * Visits all of the reference stored in an object.
+ */
+static void visitObject(Visitor *visitor, Object *obj, void *arg)
+{
+    assert(visitor != NULL);
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    if (dvmIsClassObject(obj)) {
+        visitClassObject(visitor, obj, arg);
+    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
+        visitArrayObject(visitor, obj, arg);
+    } else if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE)) {
+        visitReferenceObject(visitor, obj, arg);
+    } else {
+        visitDataObject(visitor, obj, arg);
+    }
+}
+
+#endif  // DALVIK_ALLOC_VISITINLINES_H_
diff --git a/vm/alloc/WriteBarrier.h b/vm/alloc/WriteBarrier.h
new file mode 100644
index 0000000..31b3482
--- /dev/null
+++ b/vm/alloc/WriteBarrier.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_ALLOC_WRITEBARRIER_H_
+#define DALVIK_ALLOC_WRITEBARRIER_H_
+
+/*
+ * Note writes to the heap. These functions must be called if a field
+ * of an Object in the heap changes, and before any GC safe-point. The
+ * call is not needed if NULL is stored in the field.
+ */
+
+/*
+ * The address within the Object has been written, and perhaps changed.
+ */
+INLINE void dvmWriteBarrierField(const Object *obj, void *addr)
+{
+    dvmMarkCard(obj);
+}
+
+/*
+ * All of the Object may have changed.
+ */
+INLINE void dvmWriteBarrierObject(const Object *obj)
+{
+    dvmMarkCard(obj);
+}
+
+/*
+ * Some or perhaps all of the array indexes in the Array, greater than
+ * or equal to start and strictly less than end, have been written,
+ * and perhaps changed.
+ */
+INLINE void dvmWriteBarrierArray(const ArrayObject *obj,
+                                 size_t start, size_t end)
+{
+    dvmMarkCard((Object *)obj);
+}
+
+#endif  // DALVIK_ALLOC_WRITEBARRIER_H_
diff --git a/vm/analysis/CodeVerify.cpp b/vm/analysis/CodeVerify.cpp
new file mode 100644
index 0000000..1149307
--- /dev/null
+++ b/vm/analysis/CodeVerify.cpp
@@ -0,0 +1,6524 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik bytecode structural verifier.  The only public entry point
+ * (except for a few shared utility functions) is dvmVerifyCodeFlow().
+ *
+ * TODO: might benefit from a signature-->class lookup cache.  Could avoid
+ * some string-peeling and wouldn't need to compute hashes.
+ */
+#include "Dalvik.h"
+#include "analysis/Liveness.h"
+#include "analysis/CodeVerify.h"
+#include "analysis/Optimize.h"
+#include "analysis/RegisterMap.h"
+#include "libdex/DexCatch.h"
+#include "libdex/InstrUtils.h"
+
+#include <stddef.h>
+
+
+/*
+ * We don't need to store the register data for many instructions, because
+ * we either only need it at branch points (for verification) or GC points
+ * and branches (for verification + type-precise register analysis).
+ */
+enum RegisterTrackingMode {
+    kTrackRegsBranches,
+    kTrackRegsGcPoints,
+    kTrackRegsAll
+};
+
+/*
+ * Set this to enable dead code scanning.  This is not required, but it's
+ * very useful when testing changes to the verifier (to make sure we're not
+ * skipping over stuff) and for checking the optimized output from "dx".
+ * The only reason not to do it is that it slightly increases the time
+ * required to perform verification.
+ */
+#ifndef NDEBUG
+# define DEAD_CODE_SCAN  true
+#else
+# define DEAD_CODE_SCAN  false
+#endif
+
+static bool gDebugVerbose = false;
+
+#define SHOW_REG_DETAILS \
+    (0 | DRT_SHOW_LIVENESS /*| DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS*/)
+
+/*
+ * We need an extra "pseudo register" to hold the return type briefly.  It
+ * can be category 1 or 2, so we need two slots.
+ */
+#define kExtraRegs  2
+#define RESULT_REGISTER(_insnRegCount)  (_insnRegCount)
+
+/*
+ * Big fat collection of register data.
+ */
+typedef struct RegisterTable {
+    /*
+     * Array of RegisterLine structs, one per address in the method.  We only
+     * set the pointers for certain addresses, based on instruction widths
+     * and what we're trying to accomplish.
+     */
+    RegisterLine* registerLines;
+
+    /*
+     * Number of registers we track for each instruction.  This is equal
+     * to the method's declared "registersSize" plus kExtraRegs.
+     */
+    size_t      insnRegCountPlus;
+
+    /*
+     * Storage for a register line we're currently working on.
+     */
+    RegisterLine workLine;
+
+    /*
+     * Storage for a register line we're saving for later.
+     */
+    RegisterLine savedLine;
+
+    /*
+     * A single large alloc, with all of the storage needed for RegisterLine
+     * data (RegType array, MonitorEntries array, monitor stack).
+     */
+    void*       lineAlloc;
+} RegisterTable;
+
+
+/* fwd */
+#ifndef NDEBUG
+static void checkMergeTab();
+#endif
+static bool isInitMethod(const Method* meth);
+static RegType getInvocationThis(const RegisterLine* registerLine,\
+    const DecodedInstruction* pDecInsn, VerifyError* pFailure);
+static void verifyRegisterType(RegisterLine* registerLine, \
+    u4 vsrc, RegType checkType, VerifyError* pFailure);
+static bool doCodeVerification(VerifierData* vdata, RegisterTable* regTable);
+static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
+    RegisterTable* regTable, int insnIdx, UninitInstanceMap* uninitMap,
+    int* pStartGuess);
+static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
+static void dumpRegTypes(const VerifierData* vdata, \
+    const RegisterLine* registerLine, int addr, const char* addrName,
+    const UninitInstanceMap* uninitMap, int displayFlags);
+
+/* bit values for dumpRegTypes() "displayFlags" */
+enum {
+    DRT_SIMPLE          = 0,
+    DRT_SHOW_REF_TYPES  = 0x01,
+    DRT_SHOW_LOCALS     = 0x02,
+    DRT_SHOW_LIVENESS   = 0x04,
+};
+
+
+/*
+ * ===========================================================================
+ *      RegType and UninitInstanceMap utility functions
+ * ===========================================================================
+ */
+
+#define __  kRegTypeUnknown
+#define _U  kRegTypeUninit
+#define _X  kRegTypeConflict
+#define _0  kRegTypeZero
+#define _1  kRegTypeOne
+#define _Z  kRegTypeBoolean
+#define _y  kRegTypeConstPosByte
+#define _Y  kRegTypeConstByte
+#define _h  kRegTypeConstPosShort
+#define _H  kRegTypeConstShort
+#define _c  kRegTypeConstChar
+#define _i  kRegTypeConstInteger
+#define _b  kRegTypePosByte
+#define _B  kRegTypeByte
+#define _s  kRegTypePosShort
+#define _S  kRegTypeShort
+#define _C  kRegTypeChar
+#define _I  kRegTypeInteger
+#define _F  kRegTypeFloat
+#define _N  kRegTypeConstLo
+#define _n  kRegTypeConstHi
+#define _J  kRegTypeLongLo
+#define _j  kRegTypeLongHi
+#define _D  kRegTypeDoubleLo
+#define _d  kRegTypeDoubleHi
+
+/*
+ * Merge result table for primitive values.  The table is symmetric along
+ * the diagonal.
+ *
+ * Note that 32-bit int/float do not merge into 64-bit long/double.  This
+ * is a register merge, not a widening conversion.  Only the "implicit"
+ * widening within a category, e.g. byte to short, is allowed.
+ *
+ * Dalvik does not draw a distinction between int and float, but we enforce
+ * that once a value is used as int, it can't be used as float, and vice
+ * versa. We do not allow free exchange between 32-bit int/float and 64-bit
+ * long/double.
+ *
+ * Note that Uninit+Uninit=Uninit.  This holds true because we only
+ * use this when the RegType value is exactly equal to kRegTypeUninit, which
+ * can only happen for the zeroeth entry in the table.
+ *
+ * "Unknown" never merges with anything known.  The only time a register
+ * transitions from "unknown" to "known" is when we're executing code
+ * for the first time, and we handle that with a simple copy.
+ */
+const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
+{
+    /* chk:  _  U  X  0  1  Z  y  Y  h  H  c  i  b  B  s  S  C  I  F  N  n  J  j  D  d */
+    { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
+    { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
+    { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
+    { /*0*/ _X,_X,_X,_0,_Z,_Z,_y,_Y,_h,_H,_c,_i,_b,_B,_s,_S,_C,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*1*/ _X,_X,_X,_Z,_1,_Z,_y,_Y,_h,_H,_c,_i,_b,_B,_s,_S,_C,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*Z*/ _X,_X,_X,_Z,_Z,_Z,_y,_Y,_h,_H,_c,_i,_b,_B,_s,_S,_C,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*y*/ _X,_X,_X,_y,_y,_y,_y,_Y,_h,_H,_c,_i,_b,_B,_s,_S,_C,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*Y*/ _X,_X,_X,_Y,_Y,_Y,_Y,_Y,_h,_H,_c,_i,_B,_B,_S,_S,_I,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*h*/ _X,_X,_X,_h,_h,_h,_h,_h,_h,_H,_c,_i,_s,_S,_s,_S,_C,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*H*/ _X,_X,_X,_H,_H,_H,_H,_H,_H,_H,_c,_i,_S,_S,_S,_S,_I,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*c*/ _X,_X,_X,_c,_c,_c,_c,_c,_c,_c,_c,_i,_C,_I,_C,_I,_C,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*i*/ _X,_X,_X,_i,_i,_i,_i,_i,_i,_i,_i,_i,_I,_I,_I,_I,_I,_I,_F,_X,_X,_X,_X,_X,_X },
+    { /*b*/ _X,_X,_X,_b,_b,_b,_b,_B,_s,_S,_C,_I,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X,_X,_X,_X },
+    { /*B*/ _X,_X,_X,_B,_B,_B,_B,_B,_S,_S,_I,_I,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X,_X,_X,_X },
+    { /*s*/ _X,_X,_X,_s,_s,_s,_s,_S,_s,_S,_C,_I,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X,_X,_X,_X },
+    { /*S*/ _X,_X,_X,_S,_S,_S,_S,_S,_S,_S,_I,_I,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X,_X,_X,_X },
+    { /*C*/ _X,_X,_X,_C,_C,_C,_C,_I,_C,_I,_C,_I,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X,_X,_X,_X },
+    { /*I*/ _X,_X,_X,_I,_I,_I,_I,_I,_I,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X,_X,_X,_X },
+    { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X,_X,_X,_F,_X,_X,_X,_X,_X,_X },
+    { /*N*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_N,_X,_J,_X,_D,_X },
+    { /*n*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_n,_X,_j,_X,_d },
+    { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X,_X,_X },
+    { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j,_X,_X },
+    { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_D,_X,_X,_X,_D,_X },
+    { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_d,_X,_X,_X,_d },
+};
+
+#undef __
+#undef _U
+#undef _X
+#undef _0
+#undef _1
+#undef _Z
+#undef _y
+#undef _Y
+#undef _h
+#undef _H
+#undef _c
+#undef _i
+#undef _b
+#undef _B
+#undef _s
+#undef _S
+#undef _C
+#undef _I
+#undef _F
+#undef _N
+#undef _n
+#undef _J
+#undef _j
+#undef _D
+#undef _d
+
+#ifndef NDEBUG
+/*
+ * Verify symmetry in the conversion table.
+ */
+static void checkMergeTab()
+{
+    int i, j;
+
+    for (i = 0; i < kRegTypeMAX; i++) {
+        for (j = i; j < kRegTypeMAX; j++) {
+            if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
+                LOGE("Symmetry violation: %d,%d vs %d,%d", i, j, j, i);
+                dvmAbort();
+            }
+        }
+    }
+}
+#endif
+
+/*
+ * Determine whether we can convert "srcType" to "checkType", where
+ * "checkType" is one of the category-1 non-reference types.
+ *
+ * Constant derived types may become floats, but other values may not.
+ */
+static bool canConvertTo1nr(RegType srcType, RegType checkType)
+{
+    static const char convTab
+        [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
+    {
+        /* chk: 0  1  Z  y  Y  h  H  c  i  b  B  s  S  C  I  F */
+        { /*0*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+        { /*1*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+        { /*Z*/ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+        { /*y*/ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+        { /*Y*/ 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1 },
+        { /*h*/ 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1 },
+        { /*H*/ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1 },
+        { /*c*/ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1 },
+        { /*i*/ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1 },
+        { /*b*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
+        { /*B*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0 },
+        { /*s*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 },
+        { /*S*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0 },
+        { /*C*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
+        { /*I*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
+        { /*F*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+    };
+
+    assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
+#if 0
+    if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
+        LOG_VFY("Unexpected checkType %d (srcType=%d)", checkType, srcType);
+        assert(false);
+        return false;
+    }
+#endif
+
+    //printf("convTab[%d][%d] = %d\n", srcType, checkType,
+    //    convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
+    if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
+        return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
+
+    return false;
+}
+
+/*
+ * Determine whether the category-2 types are compatible.
+ */
+static bool canConvertTo2(RegType srcType, RegType checkType)
+{
+    return ((srcType == kRegTypeConstLo || srcType == checkType) &&
+            (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
+}
+
+/*
+ * Determine whether or not "instrType" and "targetType" are compatible,
+ * for purposes of getting or setting a value in a field or array.  The
+ * idea is that an instruction with a category 1nr type (say, aget-short
+ * or iput-boolean) is accessing a static field, instance field, or array
+ * entry, and we want to make sure sure that the operation is legal.
+ *
+ * At a minimum, source and destination must have the same width.  We
+ * further refine this to assert that "short" and "char" are not
+ * compatible, because the sign-extension is different on the "get"
+ * operations.
+ *
+ * We're not considering the actual contents of the register, so we'll
+ * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort.  We
+ * could get kRegTypeUnknown in "targetType" if a field or array class
+ * lookup failed.  Category 2 types and references are checked elsewhere.
+ */
+static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
+{
+    return (instrType == targetType);
+}
+
+/*
+ * Convert a VM PrimitiveType enum value to the equivalent RegType value.
+ */
+static RegType primitiveTypeToRegType(PrimitiveType primType)
+{
+    switch (primType) {
+        case PRIM_BOOLEAN: return kRegTypeBoolean;
+        case PRIM_BYTE:    return kRegTypeByte;
+        case PRIM_SHORT:   return kRegTypeShort;
+        case PRIM_CHAR:    return kRegTypeChar;
+        case PRIM_INT:     return kRegTypeInteger;
+        case PRIM_LONG:    return kRegTypeLongLo;
+        case PRIM_FLOAT:   return kRegTypeFloat;
+        case PRIM_DOUBLE:  return kRegTypeDoubleLo;
+        case PRIM_VOID:
+        default: {
+            assert(false);
+            return kRegTypeUnknown;
+        }
+    }
+}
+
+/*
+ * Convert a const derived RegType to the equivalent non-const RegType value.
+ * Does nothing if the argument type isn't const derived.
+ */
+static RegType constTypeToRegType(RegType constType)
+{
+    switch (constType) {
+        case kRegTypeConstPosByte: return kRegTypePosByte;
+        case kRegTypeConstByte: return kRegTypeByte;
+        case kRegTypeConstPosShort: return kRegTypePosShort;
+        case kRegTypeConstShort: return kRegTypeShort;
+        case kRegTypeConstChar: return kRegTypeChar;
+        case kRegTypeConstInteger: return kRegTypeInteger;
+        default: {
+            return constType;
+        }
+    }
+}
+
+/*
+ * Given a 32-bit constant, return the most-restricted RegType enum entry
+ * that can hold the value. The types used here indicate the value came
+ * from a const instruction, and may not correctly represent the real type
+ * of the value. Upon use, a constant derived type is updated with the
+ * type from the use, which will be unambiguous.
+ */
+static char determineCat1Const(s4 value)
+{
+    if (value < -32768)
+        return kRegTypeConstInteger;
+    else if (value < -128)
+        return kRegTypeConstShort;
+    else if (value < 0)
+        return kRegTypeConstByte;
+    else if (value == 0)
+        return kRegTypeZero;
+    else if (value == 1)
+        return kRegTypeOne;
+    else if (value < 128)
+        return kRegTypeConstPosByte;
+    else if (value < 32768)
+        return kRegTypeConstPosShort;
+    else if (value < 65536)
+        return kRegTypeConstChar;
+    else
+        return kRegTypeConstInteger;
+}
+
+/*
+ * Create a new uninitialized instance map.
+ *
+ * The map is allocated and populated with address entries.  The addresses
+ * appear in ascending order to allow binary searching.
+ *
+ * Very few methods have 10 or more new-instance instructions; the
+ * majority have 0 or 1.  Occasionally a static initializer will have 200+.
+ *
+ * TODO: merge this into the static pass or initRegisterTable; want to
+ * avoid walking through the instructions yet again just to set up this table
+ */
+UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
+    const InsnFlags* insnFlags, int newInstanceCount)
+{
+    const int insnsSize = dvmGetMethodInsnsSize(meth);
+    const u2* insns = meth->insns;
+    UninitInstanceMap* uninitMap;
+    bool isInit = false;
+    int idx, addr;
+
+    if (isInitMethod(meth)) {
+        newInstanceCount++;
+        isInit = true;
+    }
+
+    /*
+     * Allocate the header and map as a single unit.
+     *
+     * TODO: consider having a static instance so we can avoid allocations.
+     * I don't think the verifier is guaranteed to be single-threaded when
+     * running in the VM (rather than dexopt), so that must be taken into
+     * account.
+     */
+    int size = offsetof(UninitInstanceMap, map) +
+                newInstanceCount * sizeof(uninitMap->map[0]);
+    uninitMap = (UninitInstanceMap*)calloc(1, size);
+    if (uninitMap == NULL)
+        return NULL;
+    uninitMap->numEntries = newInstanceCount;
+
+    idx = 0;
+    if (isInit) {
+        uninitMap->map[idx++].addr = kUninitThisArgAddr;
+    }
+
+    /*
+     * Run through and find the new-instance instructions.
+     */
+    for (addr = 0; addr < insnsSize; /**/) {
+        int width = dvmInsnGetWidth(insnFlags, addr);
+
+        Opcode opcode = dexOpcodeFromCodeUnit(*insns);
+        if (opcode == OP_NEW_INSTANCE || opcode == OP_NEW_INSTANCE_JUMBO)
+            uninitMap->map[idx++].addr = addr;
+
+        addr += width;
+        insns += width;
+    }
+
+    assert(idx == newInstanceCount);
+    return uninitMap;
+}
+
+/*
+ * Free the map.
+ */
+void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
+{
+    free(uninitMap);
+}
+
+/*
+ * Set the class object associated with the instruction at "addr".
+ *
+ * Returns the map slot index, or -1 if the address isn't listed in the map
+ * (shouldn't happen) or if a class is already associated with the address
+ * (bad bytecode).
+ *
+ * Entries, once set, do not change -- a given address can only allocate
+ * one type of object.
+ */
+static int setUninitInstance(UninitInstanceMap* uninitMap, int addr,
+    ClassObject* clazz)
+{
+    int idx;
+
+    assert(clazz != NULL);
+
+#ifdef VERIFIER_STATS
+    gDvm.verifierStats.uninitSearches++;
+#endif
+
+    /* TODO: binary search when numEntries > 8 */
+    for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
+        if (uninitMap->map[idx].addr == addr) {
+            if (uninitMap->map[idx].clazz != NULL &&
+                uninitMap->map[idx].clazz != clazz)
+            {
+                LOG_VFY("VFY: addr %d already set to %p, not setting to %p",
+                    addr, uninitMap->map[idx].clazz, clazz);
+                return -1;          // already set to something else??
+            }
+            uninitMap->map[idx].clazz = clazz;
+            return idx;
+        }
+    }
+
+    LOG_VFY("VFY: addr %d not found in uninit map", addr);
+    assert(false);      // shouldn't happen
+    return -1;
+}
+
+/*
+ * Get the class object at the specified index.
+ */
+static ClassObject* getUninitInstance(const UninitInstanceMap* uninitMap,
+    int idx)
+{
+    assert(idx >= 0 && idx < uninitMap->numEntries);
+    return uninitMap->map[idx].clazz;
+}
+
+/* determine if "type" is actually an object reference (init/uninit/zero) */
+static inline bool regTypeIsReference(RegType type) {
+    return (type > kRegTypeMAX || type == kRegTypeUninit ||
+            type == kRegTypeZero);
+}
+
+/* determine if "type" is an uninitialized object reference */
+static inline bool regTypeIsUninitReference(RegType type) {
+    return ((type & kRegTypeUninitMask) == kRegTypeUninit);
+}
+
+/* convert the initialized reference "type" to a ClassObject pointer */
+/* (does not expect uninit ref types or "zero") */
+static ClassObject* regTypeInitializedReferenceToClass(RegType type)
+{
+    assert(regTypeIsReference(type) && type != kRegTypeZero);
+    if ((type & 0x01) == 0) {
+        return (ClassObject*) type;
+    } else {
+        //LOG_VFY("VFY: attempted to use uninitialized reference");
+        return NULL;
+    }
+}
+
+/* extract the index into the uninitialized instance map table */
+static inline int regTypeToUninitIndex(RegType type) {
+    assert(regTypeIsUninitReference(type));
+    return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
+}
+
+/* convert the reference "type" to a ClassObject pointer */
+static ClassObject* regTypeReferenceToClass(RegType type,
+    const UninitInstanceMap* uninitMap)
+{
+    assert(regTypeIsReference(type) && type != kRegTypeZero);
+    if (regTypeIsUninitReference(type)) {
+        assert(uninitMap != NULL);
+        return getUninitInstance(uninitMap, regTypeToUninitIndex(type));
+    } else {
+        return (ClassObject*) type;
+    }
+}
+
+/* convert the ClassObject pointer to an (initialized) register type */
+static inline RegType regTypeFromClass(ClassObject* clazz) {
+    return (u4) clazz;
+}
+
+/* return the RegType for the uninitialized reference in slot "uidx" */
+static RegType regTypeFromUninitIndex(int uidx) {
+    return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
+}
+
+
+/*
+ * ===========================================================================
+ *      Signature operations
+ * ===========================================================================
+ */
+
+/*
+ * Is this method a constructor?
+ */
+static bool isInitMethod(const Method* meth)
+{
+    return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
+}
+
+/*
+ * Is this method a class initializer?
+ */
+#if 0
+static bool isClassInitMethod(const Method* meth)
+{
+    return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
+}
+#endif
+
+/*
+ * Look up a class reference given as a simple string descriptor.
+ *
+ * If we can't find it, return a generic substitute when possible.
+ */
+static ClassObject* lookupClassByDescriptor(const Method* meth,
+    const char* pDescriptor, VerifyError* pFailure)
+{
+    /*
+     * The javac compiler occasionally puts references to nonexistent
+     * classes in signatures.  For example, if you have a non-static
+     * inner class with no constructor, the compiler provides
+     * a private <init> for you.  Constructing the class
+     * requires <init>(parent), but the outer class can't call
+     * that because the method is private.  So the compiler
+     * generates a package-scope <init>(parent,bogus) method that
+     * just calls the regular <init> (the "bogus" part being necessary
+     * to distinguish the signature of the synthetic method).
+     * Treating the bogus class as an instance of java.lang.Object
+     * allows the verifier to process the class successfully.
+     */
+
+    //LOGI("Looking up '%s'", typeStr);
+    ClassObject* clazz;
+    clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
+    if (clazz == NULL) {
+        dvmClearOptException(dvmThreadSelf());
+        if (strchr(pDescriptor, '$') != NULL) {
+            LOGV("VFY: unable to find class referenced in signature (%s)",
+                pDescriptor);
+        } else {
+            LOG_VFY("VFY: unable to find class referenced in signature (%s)",
+                pDescriptor);
+        }
+
+        if (pDescriptor[0] == '[') {
+            /* We are looking at an array descriptor. */
+
+            /*
+             * There should never be a problem loading primitive arrays.
+             */
+            if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
+                LOG_VFY("VFY: invalid char in signature in '%s'",
+                    pDescriptor);
+                *pFailure = VERIFY_ERROR_GENERIC;
+            }
+
+            /*
+             * Try to continue with base array type.  This will let
+             * us pass basic stuff (e.g. get array len) that wouldn't
+             * fly with an Object.  This is NOT correct if the
+             * missing type is a primitive array, but we should never
+             * have a problem loading those.  (I'm not convinced this
+             * is correct or even useful.  Just use Object here?)
+             */
+            clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
+                meth->clazz->classLoader);
+        } else if (pDescriptor[0] == 'L') {
+            /*
+             * We are looking at a non-array reference descriptor;
+             * try to continue with base reference type.
+             */
+            clazz = gDvm.classJavaLangObject;
+        } else {
+            /* We are looking at a primitive type. */
+            LOG_VFY("VFY: invalid char in signature in '%s'", pDescriptor);
+            *pFailure = VERIFY_ERROR_GENERIC;
+        }
+
+        if (clazz == NULL) {
+            *pFailure = VERIFY_ERROR_GENERIC;
+        }
+    }
+
+    if (dvmIsPrimitiveClass(clazz)) {
+        LOG_VFY("VFY: invalid use of primitive type '%s'", pDescriptor);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        clazz = NULL;
+    }
+
+    return clazz;
+}
+
+/*
+ * Look up a class reference in a signature.  Could be an arg or the
+ * return value.
+ *
+ * Advances "*pSig" to the last character in the signature (that is, to
+ * the ';').
+ *
+ * NOTE: this is also expected to verify the signature.
+ */
+static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
+    VerifyError* pFailure)
+{
+    const char* sig = *pSig;
+    const char* endp = sig;
+
+    assert(sig != NULL && *sig == 'L');
+
+    while (*++endp != ';' && *endp != '\0')
+        ;
+    if (*endp != ';') {
+        LOG_VFY("VFY: bad signature component '%s' (missing ';')", sig);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return NULL;
+    }
+
+    endp++;    /* Advance past the ';'. */
+    int typeLen = endp - sig;
+    char typeStr[typeLen+1]; /* +1 for the '\0' */
+    memcpy(typeStr, sig, typeLen);
+    typeStr[typeLen] = '\0';
+
+    *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
+
+    return lookupClassByDescriptor(meth, typeStr, pFailure);
+}
+
+/*
+ * Look up an array class reference in a signature.  Could be an arg or the
+ * return value.
+ *
+ * Advances "*pSig" to the last character in the signature.
+ *
+ * NOTE: this is also expected to verify the signature.
+ */
+static ClassObject* lookupSignatureArrayClass(const Method* meth,
+    const char** pSig, VerifyError* pFailure)
+{
+    const char* sig = *pSig;
+    const char* endp = sig;
+
+    assert(sig != NULL && *sig == '[');
+
+    /* find the end */
+    while (*++endp == '[' && *endp != '\0')
+        ;
+
+    if (*endp == 'L') {
+        while (*++endp != ';' && *endp != '\0')
+            ;
+        if (*endp != ';') {
+            LOG_VFY("VFY: bad signature component '%s' (missing ';')", sig);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            return NULL;
+        }
+    }
+
+    int typeLen = endp - sig +1;
+    char typeStr[typeLen+1];
+    memcpy(typeStr, sig, typeLen);
+    typeStr[typeLen] = '\0';
+
+    *pSig = endp;
+
+    return lookupClassByDescriptor(meth, typeStr, pFailure);
+}
+
+/*
+ * Set the register types for the first instruction in the method based on
+ * the method signature.
+ *
+ * This has the side-effect of validating the signature.
+ *
+ * Returns "true" on success.
+ */
+static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
+    UninitInstanceMap* uninitMap)
+{
+    DexParameterIterator iterator;
+    int actualArgs, expectedArgs, argStart;
+    VerifyError failure = VERIFY_ERROR_NONE;
+    const char* descriptor;
+
+    dexParameterIteratorInit(&iterator, &meth->prototype);
+    argStart = meth->registersSize - meth->insSize;
+    expectedArgs = meth->insSize;     /* long/double count as two */
+    actualArgs = 0;
+
+    assert(argStart >= 0);      /* should have been verified earlier */
+
+    /*
+     * Include the "this" pointer.
+     */
+    if (!dvmIsStaticMethod(meth)) {
+        /*
+         * If this is a constructor for a class other than java.lang.Object,
+         * mark the first ("this") argument as uninitialized.  This restricts
+         * field access until the superclass constructor is called.
+         */
+        if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
+            int uidx = setUninitInstance(uninitMap, kUninitThisArgAddr,
+                            meth->clazz);
+            assert(uidx == 0);
+            regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
+        } else {
+            regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
+        }
+        actualArgs++;
+    }
+
+    for (;;) {
+        descriptor = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (descriptor == NULL) {
+            break;
+        }
+
+        if (actualArgs >= expectedArgs) {
+            LOG_VFY("VFY: expected %d args, found more (%s)",
+                expectedArgs, descriptor);
+            goto bad_sig;
+        }
+
+        switch (*descriptor) {
+        case 'L':
+        case '[':
+            /*
+             * We assume that reference arguments are initialized.  The
+             * only way it could be otherwise (assuming the caller was
+             * verified) is if the current method is <init>, but in that
+             * case it's effectively considered initialized the instant
+             * we reach here (in the sense that we can return without
+             * doing anything or call virtual methods).
+             */
+            {
+                ClassObject* clazz =
+                    lookupClassByDescriptor(meth, descriptor, &failure);
+                if (!VERIFY_OK(failure))
+                    goto bad_sig;
+                regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
+            }
+            actualArgs++;
+            break;
+        case 'Z':
+            regTypes[argStart + actualArgs] = kRegTypeBoolean;
+            actualArgs++;
+            break;
+        case 'C':
+            regTypes[argStart + actualArgs] = kRegTypeChar;
+            actualArgs++;
+            break;
+        case 'B':
+            regTypes[argStart + actualArgs] = kRegTypeByte;
+            actualArgs++;
+            break;
+        case 'I':
+            regTypes[argStart + actualArgs] = kRegTypeInteger;
+            actualArgs++;
+            break;
+        case 'S':
+            regTypes[argStart + actualArgs] = kRegTypeShort;
+            actualArgs++;
+            break;
+        case 'F':
+            regTypes[argStart + actualArgs] = kRegTypeFloat;
+            actualArgs++;
+            break;
+        case 'D':
+            regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
+            regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
+            actualArgs += 2;
+            break;
+        case 'J':
+            regTypes[argStart + actualArgs] = kRegTypeLongLo;
+            regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
+            actualArgs += 2;
+            break;
+        default:
+            LOG_VFY("VFY: unexpected signature type char '%c'", *descriptor);
+            goto bad_sig;
+        }
+    }
+
+    if (actualArgs != expectedArgs) {
+        LOG_VFY("VFY: expected %d args, found %d", expectedArgs, actualArgs);
+        goto bad_sig;
+    }
+
+    descriptor = dexProtoGetReturnType(&meth->prototype);
+
+    /*
+     * Validate return type.  We don't do the type lookup; just want to make
+     * sure that it has the right format.  Only major difference from the
+     * method argument format is that 'V' is supported.
+     */
+    switch (*descriptor) {
+    case 'I':
+    case 'C':
+    case 'S':
+    case 'B':
+    case 'Z':
+    case 'V':
+    case 'F':
+    case 'D':
+    case 'J':
+        if (*(descriptor+1) != '\0')
+            goto bad_sig;
+        break;
+    case '[':
+        /* single/multi, object/primitive */
+        while (*++descriptor == '[')
+            ;
+        if (*descriptor == 'L') {
+            while (*++descriptor != ';' && *descriptor != '\0')
+                ;
+            if (*descriptor != ';')
+                goto bad_sig;
+        } else {
+            if (*(descriptor+1) != '\0')
+                goto bad_sig;
+        }
+        break;
+    case 'L':
+        /* could be more thorough here, but shouldn't be required */
+        while (*++descriptor != ';' && *descriptor != '\0')
+            ;
+        if (*descriptor != ';')
+            goto bad_sig;
+        break;
+    default:
+        goto bad_sig;
+    }
+
+    return true;
+
+//fail:
+//    LOG_VFY_METH(meth, "VFY:  bad sig");
+//    return false;
+
+bad_sig:
+    {
+        char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+        LOG_VFY("VFY: bad signature '%s' for %s.%s",
+            desc, meth->clazz->descriptor, meth->name);
+        free(desc);
+    }
+    return false;
+}
+
+/*
+ * Return the register type for the method.  We can't just use the
+ * already-computed DalvikJniReturnType, because if it's a reference type
+ * we need to do the class lookup.
+ *
+ * Returned references are assumed to be initialized.
+ *
+ * Returns kRegTypeUnknown for "void".
+ */
+static RegType getMethodReturnType(const Method* meth)
+{
+    RegType type;
+    const char* descriptor = dexProtoGetReturnType(&meth->prototype);
+
+    switch (*descriptor) {
+    case 'I':
+        type = kRegTypeInteger;
+        break;
+    case 'C':
+        type = kRegTypeChar;
+        break;
+    case 'S':
+        type = kRegTypeShort;
+        break;
+    case 'B':
+        type = kRegTypeByte;
+        break;
+    case 'Z':
+        type = kRegTypeBoolean;
+        break;
+    case 'V':
+        type = kRegTypeUnknown;
+        break;
+    case 'F':
+        type = kRegTypeFloat;
+        break;
+    case 'D':
+        type = kRegTypeDoubleLo;
+        break;
+    case 'J':
+        type = kRegTypeLongLo;
+        break;
+    case 'L':
+    case '[':
+        {
+            VerifyError failure = VERIFY_ERROR_NONE;
+            ClassObject* clazz =
+                lookupClassByDescriptor(meth, descriptor, &failure);
+            assert(VERIFY_OK(failure));
+            type = regTypeFromClass(clazz);
+        }
+        break;
+    default:
+        /* we verified signature return type earlier, so this is impossible */
+        assert(false);
+        type = kRegTypeConflict;
+        break;
+    }
+
+    return type;
+}
+
+/*
+ * Convert a single-character signature value (i.e. a primitive type) to
+ * the corresponding RegType.  This is intended for access to object fields
+ * holding primitive types.
+ *
+ * Returns kRegTypeUnknown for objects, arrays, and void.
+ */
+static RegType primSigCharToRegType(char sigChar)
+{
+    RegType type;
+
+    switch (sigChar) {
+    case 'I':
+        type = kRegTypeInteger;
+        break;
+    case 'C':
+        type = kRegTypeChar;
+        break;
+    case 'S':
+        type = kRegTypeShort;
+        break;
+    case 'B':
+        type = kRegTypeByte;
+        break;
+    case 'Z':
+        type = kRegTypeBoolean;
+        break;
+    case 'F':
+        type = kRegTypeFloat;
+        break;
+    case 'D':
+        type = kRegTypeDoubleLo;
+        break;
+    case 'J':
+        type = kRegTypeLongLo;
+        break;
+    case 'V':
+    case 'L':
+    case '[':
+        type = kRegTypeUnknown;
+        break;
+    default:
+        assert(false);
+        type = kRegTypeUnknown;
+        break;
+    }
+
+    return type;
+}
+
+/*
+ * See if the method matches the MethodType.
+ */
+static bool isCorrectInvokeKind(MethodType methodType, Method* resMethod)
+{
+    switch (methodType) {
+    case METHOD_DIRECT:
+        return dvmIsDirectMethod(resMethod);
+    case METHOD_STATIC:
+        return dvmIsStaticMethod(resMethod);
+    case METHOD_VIRTUAL:
+    case METHOD_INTERFACE:
+        return !dvmIsDirectMethod(resMethod);
+    default:
+        return false;
+    }
+}
+
+/*
+ * Verify the arguments to a method.  We're executing in "method", making
+ * a call to the method reference in vB.
+ *
+ * If this is a "direct" invoke, we allow calls to <init>.  For calls to
+ * <init>, the first argument may be an uninitialized reference.  Otherwise,
+ * calls to anything starting with '<' will be rejected, as will any
+ * uninitialized reference arguments.
+ *
+ * For non-static method calls, this will verify that the method call is
+ * appropriate for the "this" argument.
+ *
+ * The method reference is in vBBBB.  The "isRange" parameter determines
+ * whether we use 0-4 "args" values or a range of registers defined by
+ * vAA and vCCCC.
+ *
+ * Widening conversions on integers and references are allowed, but
+ * narrowing conversions are not.
+ *
+ * Returns the resolved method on success, NULL on failure (with *pFailure
+ * set appropriately).
+ */
+static Method* verifyInvocationArgs(const Method* meth,
+    RegisterLine* registerLine, const int insnRegCount,
+    const DecodedInstruction* pDecInsn, UninitInstanceMap* uninitMap,
+    MethodType methodType, bool isRange, bool isSuper, VerifyError* pFailure)
+{
+    Method* resMethod;
+    char* sigOriginal = NULL;
+    const char* sig;
+    int expectedArgs;
+    int actualArgs;
+
+    /*
+     * Resolve the method.  This could be an abstract or concrete method
+     * depending on what sort of call we're making.
+     */
+    if (methodType == METHOD_INTERFACE) {
+        resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
+    } else {
+        resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
+            pFailure);
+    }
+    if (resMethod == NULL) {
+        /* failed; print a meaningful failure message */
+        DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+
+        const DexMethodId* pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
+        const char* methodName = dexStringById(pDexFile, pMethodId->nameIdx);
+        char* methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
+        const char* classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+
+        if (!gDvm.optimizing) {
+            std::string dotMissingClass =
+                dvmHumanReadableDescriptor(classDescriptor);
+            std::string dotMethClass =
+                dvmHumanReadableDescriptor(meth->clazz->descriptor);
+
+            LOGI("Could not find method %s.%s, referenced from method %s.%s",
+                    dotMissingClass.c_str(), methodName,
+                    dotMethClass.c_str(), meth->name);
+        }
+
+        LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s",
+            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;
+    }
+
+    /*
+     * Only time you can explicitly call a method starting with '<' is when
+     * making a "direct" invocation on "<init>".  There are additional
+     * restrictions but we don't enforce them here.
+     */
+    if (resMethod->name[0] == '<') {
+        if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
+            LOG_VFY("VFY: invalid call to %s.%s",
+                    resMethod->clazz->descriptor, resMethod->name);
+            goto bad_sig;
+        }
+    }
+
+    /*
+     * See if the method type implied by the invoke instruction matches the
+     * access flags for the target method.
+     */
+    if (!isCorrectInvokeKind(methodType, resMethod)) {
+        LOG_VFY("VFY: invoke type does not match method type of %s.%s",
+            resMethod->clazz->descriptor, resMethod->name);
+        goto fail;
+    }
+
+    /*
+     * If we're using invoke-super(method), make sure that the executing
+     * method's class' superclass has a vtable entry for the target method.
+     */
+    if (isSuper) {
+        assert(methodType == METHOD_VIRTUAL);
+        ClassObject* super = meth->clazz->super;
+        if (super == NULL || resMethod->methodIndex > super->vtableCount) {
+            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+            LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s",
+                    meth->clazz->descriptor, meth->name,
+                    (super == NULL) ? "-" : super->descriptor,
+                    resMethod->name, desc);
+            free(desc);
+            *pFailure = VERIFY_ERROR_NO_METHOD;
+            goto fail;
+        }
+    }
+
+    /*
+     * We use vAA as our expected arg count, rather than resMethod->insSize,
+     * because we need to match the call to the signature.  Also, we might
+     * might be calling through an abstract method definition (which doesn't
+     * have register count values).
+     */
+    sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+    sig = sigOriginal;
+    expectedArgs = pDecInsn->vA;
+    actualArgs = 0;
+
+    /* caught by static verifier */
+    assert(isRange || expectedArgs <= 5);
+
+    if (expectedArgs > meth->outsSize) {
+        LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)",
+            expectedArgs, meth->outsSize);
+        goto fail;
+    }
+
+    if (*sig++ != '(')
+        goto bad_sig;
+
+    /*
+     * Check the "this" argument, which must be an instance of the class
+     * that declared the method.  For an interface class, we don't do the
+     * full interface merge, so we can't do a rigorous check here (which
+     * is okay since we have to do it at runtime).
+     */
+    if (!dvmIsStaticMethod(resMethod)) {
+        ClassObject* actualThisRef;
+        RegType actualArgType;
+
+        actualArgType = getInvocationThis(registerLine, pDecInsn, pFailure);
+        if (!VERIFY_OK(*pFailure))
+            goto fail;
+
+        if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
+        {
+            LOG_VFY("VFY: 'this' arg must be initialized");
+            goto fail;
+        }
+        if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
+            actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
+            if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
+                LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'",
+                        actualThisRef->descriptor,
+                        resMethod->clazz->descriptor);
+                goto fail;
+            }
+        }
+        actualArgs++;
+    }
+
+    /*
+     * Process the target method's signature.  This signature may or may not
+     * have been verified, so we can't assume it's properly formed.
+     */
+    while (*sig != '\0' && *sig != ')') {
+        if (actualArgs >= expectedArgs) {
+            LOG_VFY("VFY: expected %d args, found more (%c)",
+                expectedArgs, *sig);
+            goto bad_sig;
+        }
+
+        u4 getReg;
+        if (isRange)
+            getReg = pDecInsn->vC + actualArgs;
+        else
+            getReg = pDecInsn->arg[actualArgs];
+
+        switch (*sig) {
+        case 'L':
+            {
+                ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
+                if (!VERIFY_OK(*pFailure))
+                    goto bad_sig;
+                verifyRegisterType(registerLine, getReg,
+                    regTypeFromClass(clazz), pFailure);
+                if (!VERIFY_OK(*pFailure)) {
+                    LOG_VFY("VFY: bad arg %d (into %s)",
+                            actualArgs, clazz->descriptor);
+                    goto bad_sig;
+                }
+            }
+            actualArgs++;
+            break;
+        case '[':
+            {
+                ClassObject* clazz =
+                    lookupSignatureArrayClass(meth, &sig, pFailure);
+                if (!VERIFY_OK(*pFailure))
+                    goto bad_sig;
+                verifyRegisterType(registerLine, getReg,
+                    regTypeFromClass(clazz), pFailure);
+                if (!VERIFY_OK(*pFailure)) {
+                    LOG_VFY("VFY: bad arg %d (into %s)",
+                            actualArgs, clazz->descriptor);
+                    goto bad_sig;
+                }
+            }
+            actualArgs++;
+            break;
+        case 'Z':
+            verifyRegisterType(registerLine, getReg, kRegTypeBoolean, pFailure);
+            actualArgs++;
+            break;
+        case 'C':
+            verifyRegisterType(registerLine, getReg, kRegTypeChar, pFailure);
+            actualArgs++;
+            break;
+        case 'B':
+            verifyRegisterType(registerLine, getReg, kRegTypeByte, pFailure);
+            actualArgs++;
+            break;
+        case 'I':
+            verifyRegisterType(registerLine, getReg, kRegTypeInteger, pFailure);
+            actualArgs++;
+            break;
+        case 'S':
+            verifyRegisterType(registerLine, getReg, kRegTypeShort, pFailure);
+            actualArgs++;
+            break;
+        case 'F':
+            verifyRegisterType(registerLine, getReg, kRegTypeFloat, pFailure);
+            actualArgs++;
+            break;
+        case 'D':
+            verifyRegisterType(registerLine, getReg, kRegTypeDoubleLo, pFailure);
+            actualArgs += 2;
+            break;
+        case 'J':
+            verifyRegisterType(registerLine, getReg, kRegTypeLongLo, pFailure);
+            actualArgs += 2;
+            break;
+        default:
+            LOG_VFY("VFY: invocation target: bad signature type char '%c'",
+                *sig);
+            goto bad_sig;
+        }
+
+        sig++;
+    }
+    if (*sig != ')') {
+        char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+        LOG_VFY("VFY: invocation target: bad signature '%s'", desc);
+        free(desc);
+        goto bad_sig;
+    }
+
+    if (actualArgs != expectedArgs) {
+        LOG_VFY("VFY: expected %d args, found %d", expectedArgs, actualArgs);
+        goto bad_sig;
+    }
+
+    free(sigOriginal);
+    return resMethod;
+
+bad_sig:
+    if (resMethod != NULL) {
+        char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+        LOG_VFY("VFY:  rejecting call to %s.%s %s",
+            resMethod->clazz->descriptor, resMethod->name, desc);
+        free(desc);
+    }
+
+fail:
+    free(sigOriginal);
+    if (*pFailure == VERIFY_ERROR_NONE)
+        *pFailure = VERIFY_ERROR_GENERIC;
+    return NULL;
+}
+
+/*
+ * Get the class object for the type of data stored in a field.  This isn't
+ * stored in the Field struct, so we have to recover it from the signature.
+ *
+ * This only works for reference types.  Don't call this for primitive types.
+ *
+ * If we can't find the class, we return java.lang.Object, so that
+ * verification can continue if a field is only accessed in trivial ways.
+ */
+static ClassObject* getFieldClass(const Method* meth, const Field* field)
+{
+    ClassObject* fieldClass;
+    const char* signature = field->signature;
+
+    if ((*signature == 'L') || (*signature == '[')) {
+        fieldClass = dvmFindClassNoInit(signature,
+                meth->clazz->classLoader);
+    } else {
+        return NULL;
+    }
+
+    if (fieldClass == NULL) {
+        dvmClearOptException(dvmThreadSelf());
+        LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object",
+            field->signature, meth->clazz->descriptor, field->name);
+        fieldClass = gDvm.classJavaLangObject;
+    } else {
+        assert(!dvmIsPrimitiveClass(fieldClass));
+    }
+    return fieldClass;
+}
+
+
+/*
+ * ===========================================================================
+ *      Register operations
+ * ===========================================================================
+ */
+
+/*
+ * Get the type of register N.
+ *
+ * The register index was validated during the static pass, so we don't
+ * need to check it here.
+ */
+static inline RegType getRegisterType(const RegisterLine* registerLine, u4 vsrc)
+{
+    return registerLine->regTypes[vsrc];
+}
+
+/*
+ * Get the value from a register, and cast it to a ClassObject.  Sets
+ * "*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 RegisterLine* registerLine,
+    u4 vsrc, VerifyError* pFailure)
+{
+    ClassObject* clazz = NULL;
+    RegType type;
+
+    /* get the element type of the array held in vsrc */
+    type = getRegisterType(registerLine, vsrc);
+
+    /* if "always zero", we allow it to fail at runtime */
+    if (type == kRegTypeZero)
+        goto bail;
+
+    if (!regTypeIsReference(type)) {
+        LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)",
+            vsrc, type);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        goto bail;
+    }
+    if (regTypeIsUninitReference(type)) {
+        LOG_VFY("VFY: register %u holds uninitialized reference", vsrc);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        goto bail;
+    }
+
+    clazz = regTypeInitializedReferenceToClass(type);
+
+bail:
+    return clazz;
+}
+
+/*
+ * Get the "this" pointer from a non-static method invocation.  This
+ * returns the RegType so the caller can decide whether it needs the
+ * reference to be initialized or not.  (Can also return kRegTypeZero
+ * if the reference can only be zero at this point.)
+ *
+ * The argument count is in vA, and the first argument is in vC, for both
+ * "simple" and "range" versions.  We just need to make sure vA is >= 1
+ * and then return vC.
+ */
+static RegType getInvocationThis(const RegisterLine* registerLine,
+    const DecodedInstruction* pDecInsn, VerifyError* pFailure)
+{
+    RegType thisType = kRegTypeUnknown;
+
+    if (pDecInsn->vA < 1) {
+        LOG_VFY("VFY: invoke lacks 'this'");
+        *pFailure = VERIFY_ERROR_GENERIC;
+        goto bail;
+    }
+
+    /* get the element type of the array held in vsrc */
+    thisType = getRegisterType(registerLine, pDecInsn->vC);
+    if (!regTypeIsReference(thisType)) {
+        LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)",
+            pDecInsn->vC, thisType);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        goto bail;
+    }
+
+bail:
+    return thisType;
+}
+
+/*
+ * Set the type of register N, verifying that the register is valid.  If
+ * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
+ * set to "newType+1".
+ *
+ * The register index was validated during the static pass, so we don't
+ * need to check it here.
+ *
+ * TODO: clear mon stack bits
+ */
+static void setRegisterType(RegisterLine* registerLine, u4 vdst,
+    RegType newType)
+{
+    RegType* insnRegs = registerLine->regTypes;
+
+    switch (newType) {
+    case kRegTypeUnknown:
+    case kRegTypeBoolean:
+    case kRegTypeOne:
+    case kRegTypeConstByte:
+    case kRegTypeConstPosByte:
+    case kRegTypeConstShort:
+    case kRegTypeConstPosShort:
+    case kRegTypeConstChar:
+    case kRegTypeConstInteger:
+    case kRegTypeByte:
+    case kRegTypePosByte:
+    case kRegTypeShort:
+    case kRegTypePosShort:
+    case kRegTypeChar:
+    case kRegTypeInteger:
+    case kRegTypeFloat:
+    case kRegTypeZero:
+    case kRegTypeUninit:
+        insnRegs[vdst] = newType;
+        break;
+    case kRegTypeConstLo:
+    case kRegTypeLongLo:
+    case kRegTypeDoubleLo:
+        insnRegs[vdst] = newType;
+        insnRegs[vdst+1] = newType+1;
+        break;
+    case kRegTypeConstHi:
+    case kRegTypeLongHi:
+    case kRegTypeDoubleHi:
+        /* should never set these explicitly */
+        LOGE("BUG: explicit set of high register type");
+        dvmAbort();
+        break;
+
+    default:
+        /* can't switch for ref types, so we check explicitly */
+        if (regTypeIsReference(newType)) {
+            insnRegs[vdst] = newType;
+
+            /*
+             * In most circumstances we won't see a reference to a primitive
+             * class here (e.g. "D"), since that would mean the object in the
+             * register is actually a primitive type.  It can happen as the
+             * result of an assumed-successful check-cast instruction in
+             * which the second argument refers to a primitive class.  (In
+             * practice, such an instruction will always throw an exception.)
+             *
+             * This is not an issue for instructions like const-class, where
+             * the object in the register is a java.lang.Class instance.
+             */
+            break;
+        }
+        /* bad type - fall through */
+
+    case kRegTypeConflict:      // should only be set during a merge
+        LOGE("BUG: set register to unknown type %d", newType);
+        dvmAbort();
+        break;
+    }
+
+    /*
+     * Clear the monitor entry bits for this register.
+     */
+    if (registerLine->monitorEntries != NULL)
+        registerLine->monitorEntries[vdst] = 0;
+}
+
+/*
+ * Verify that the contents of the specified register have the specified
+ * type (or can be converted to it through an implicit widening conversion).
+ *
+ * This will modify the type of the source register if it was originally
+ * derived from a constant to prevent mixing of int/float and long/double.
+ *
+ * If "vsrc" is a reference, both it and the "vsrc" register must be
+ * initialized ("vsrc" may be Zero).  This will verify that the value in
+ * the register is an instance of checkType, or if checkType is an
+ * interface, verify that the register implements checkType.
+ */
+static void verifyRegisterType(RegisterLine* registerLine, u4 vsrc,
+    RegType checkType, VerifyError* pFailure)
+{
+    const RegType* insnRegs = registerLine->regTypes;
+    RegType srcType = insnRegs[vsrc];
+
+    //LOGD("check-reg v%u = %d", vsrc, checkType);
+    switch (checkType) {
+    case kRegTypeFloat:
+    case kRegTypeBoolean:
+    case kRegTypePosByte:
+    case kRegTypeByte:
+    case kRegTypePosShort:
+    case kRegTypeShort:
+    case kRegTypeChar:
+    case kRegTypeInteger:
+        if (!canConvertTo1nr(srcType, checkType)) {
+            LOG_VFY("VFY: register1 v%u type %d, wanted %d",
+                vsrc, srcType, checkType);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        /* Update type if result is float */
+        if (checkType == kRegTypeFloat) {
+            setRegisterType(registerLine, vsrc, checkType);
+        } else {
+            /* Update const type to actual type after use */
+            setRegisterType(registerLine, vsrc, constTypeToRegType(srcType));
+        }
+        break;
+    case kRegTypeLongLo:
+    case kRegTypeDoubleLo:
+        if (insnRegs[vsrc+1] != srcType+1) {
+            LOG_VFY("VFY: register2 v%u-%u values %d,%d",
+                vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        } else if (!canConvertTo2(srcType, checkType)) {
+            LOG_VFY("VFY: register2 v%u type %d, wanted %d",
+                vsrc, srcType, checkType);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        /* Update type if source is from const */
+        if (srcType == kRegTypeConstLo) {
+            setRegisterType(registerLine, vsrc, checkType);
+        }
+        break;
+    case kRegTypeConstLo:
+    case kRegTypeConstHi:
+    case kRegTypeLongHi:
+    case kRegTypeDoubleHi:
+    case kRegTypeZero:
+    case kRegTypeOne:
+    case kRegTypeUnknown:
+    case kRegTypeConflict:
+        /* should never be checking for these explicitly */
+        assert(false);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    case kRegTypeUninit:
+    default:
+        /* make sure checkType is initialized reference */
+        if (!regTypeIsReference(checkType)) {
+            LOG_VFY("VFY: unexpected check type %d", checkType);
+            assert(false);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        if (regTypeIsUninitReference(checkType)) {
+            LOG_VFY("VFY: uninitialized ref not expected as reg check");
+            *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", vsrc, srcType);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        if (regTypeIsUninitReference(srcType)) {
+            LOG_VFY("VFY: register1 v%u holds uninitialized ref", vsrc);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        /* if the register isn't Zero, make sure it's an instance of check */
+        if (srcType != kRegTypeZero) {
+            ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
+            ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
+            assert(srcClass != NULL);
+            assert(checkClass != NULL);
+
+            if (dvmIsInterfaceClass(checkClass)) {
+                /*
+                 * All objects implement all interfaces as far as the
+                 * verifier is concerned.  The runtime has to sort it out.
+                 * See comments above findCommonSuperclass.
+                 */
+                /*
+                if (srcClass != checkClass &&
+                    !dvmImplements(srcClass, checkClass))
+                {
+                    LOG_VFY("VFY: %s does not implement %s",
+                            srcClass->descriptor, checkClass->descriptor);
+                    *pFailure = VERIFY_ERROR_GENERIC;
+                }
+                */
+            } else {
+                if (!dvmInstanceof(srcClass, checkClass)) {
+                    LOG_VFY("VFY: %s is not instance of %s",
+                            srcClass->descriptor, checkClass->descriptor);
+                    *pFailure = VERIFY_ERROR_GENERIC;
+                }
+            }
+        }
+        break;
+    }
+}
+
+/*
+ * Set the type of the "result" register.
+ */
+static void setResultRegisterType(RegisterLine* registerLine,
+    const int insnRegCount, RegType newType)
+{
+    setRegisterType(registerLine, RESULT_REGISTER(insnRegCount), newType);
+}
+
+
+/*
+ * Update all registers holding "uninitType" to instead hold the
+ * corresponding initialized reference type.  This is called when an
+ * appropriate <init> method is invoked -- all copies of the reference
+ * must be marked as initialized.
+ */
+static void markRefsAsInitialized(RegisterLine* registerLine, int insnRegCount,
+    UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
+{
+    RegType* insnRegs = registerLine->regTypes;
+    ClassObject* clazz;
+    RegType initType;
+    int i, changed;
+
+    clazz = getUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
+    if (clazz == NULL) {
+        LOGE("VFY: unable to find type=%#x (idx=%d)",
+            uninitType, regTypeToUninitIndex(uninitType));
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    }
+    initType = regTypeFromClass(clazz);
+
+    changed = 0;
+    for (i = 0; i < insnRegCount; i++) {
+        if (insnRegs[i] == uninitType) {
+            insnRegs[i] = initType;
+            changed++;
+        }
+    }
+    //LOGD("VFY: marked %d registers as initialized", changed);
+    assert(changed > 0);
+
+    return;
+}
+
+/*
+ * We're creating a new instance of class C at address A.  Any registers
+ * holding instances previously created at address A must be initialized
+ * by now.  If not, we mark them as "conflict" to prevent them from being
+ * used (otherwise, markRefsAsInitialized would mark the old ones and the
+ * new ones at the same time).
+ */
+static void markUninitRefsAsInvalid(RegisterLine* registerLine,
+    int insnRegCount, UninitInstanceMap* uninitMap, RegType uninitType)
+{
+    RegType* insnRegs = registerLine->regTypes;
+    int i, changed;
+
+    changed = 0;
+    for (i = 0; i < insnRegCount; i++) {
+        if (insnRegs[i] == uninitType) {
+            insnRegs[i] = kRegTypeConflict;
+            if (registerLine->monitorEntries != NULL)
+                registerLine->monitorEntries[i] = 0;
+            changed++;
+        }
+    }
+
+    //if (changed)
+    //    LOGD("VFY: marked %d uninitialized registers as invalid", changed);
+}
+
+/*
+ * Find the register line for the specified instruction in the current method.
+ */
+static inline RegisterLine* getRegisterLine(const RegisterTable* regTable,
+    int insnIdx)
+{
+    return &regTable->registerLines[insnIdx];
+}
+
+/*
+ * Copy a register line.
+ */
+static inline void copyRegisterLine(RegisterLine* dst, const RegisterLine* src,
+    size_t numRegs)
+{
+    memcpy(dst->regTypes, src->regTypes, numRegs * sizeof(RegType));
+
+    assert((src->monitorEntries == NULL && dst->monitorEntries == NULL) ||
+           (src->monitorEntries != NULL && dst->monitorEntries != NULL));
+    if (dst->monitorEntries != NULL) {
+        assert(dst->monitorStack != NULL);
+        memcpy(dst->monitorEntries, src->monitorEntries,
+            numRegs * sizeof(MonitorEntries));
+        memcpy(dst->monitorStack, src->monitorStack,
+            kMaxMonitorStackDepth * sizeof(u4));
+        dst->monitorStackTop = src->monitorStackTop;
+    }
+}
+
+/*
+ * Copy a register line into the table.
+ */
+static inline void copyLineToTable(RegisterTable* regTable, int insnIdx,
+    const RegisterLine* src)
+{
+    RegisterLine* dst = getRegisterLine(regTable, insnIdx);
+    assert(dst->regTypes != NULL);
+    copyRegisterLine(dst, src, regTable->insnRegCountPlus);
+}
+
+/*
+ * Copy a register line out of the table.
+ */
+static inline void copyLineFromTable(RegisterLine* dst,
+    const RegisterTable* regTable, int insnIdx)
+{
+    RegisterLine* src = getRegisterLine(regTable, insnIdx);
+    assert(src->regTypes != NULL);
+    copyRegisterLine(dst, src, regTable->insnRegCountPlus);
+}
+
+
+#ifndef NDEBUG
+/*
+ * Compare two register lines.  Returns 0 if they match.
+ *
+ * Using this for a sort is unwise, since the value can change based on
+ * machine endianness.
+ */
+static inline int compareLineToTable(const RegisterTable* regTable,
+    int insnIdx, const RegisterLine* line2)
+{
+    const RegisterLine* line1 = getRegisterLine(regTable, insnIdx);
+    if (line1->monitorEntries != NULL) {
+        int result;
+
+        if (line2->monitorEntries == NULL)
+            return 1;
+        result = memcmp(line1->monitorEntries, line2->monitorEntries,
+            regTable->insnRegCountPlus * sizeof(MonitorEntries));
+        if (result != 0) {
+            LOG_VFY("monitorEntries mismatch");
+            return result;
+        }
+        result = line1->monitorStackTop - line2->monitorStackTop;
+        if (result != 0) {
+            LOG_VFY("monitorStackTop mismatch");
+            return result;
+        }
+        result = memcmp(line1->monitorStack, line2->monitorStack,
+            line1->monitorStackTop);
+        if (result != 0) {
+            LOG_VFY("monitorStack mismatch");
+            return result;
+        }
+    }
+    return memcmp(line1->regTypes, line2->regTypes,
+            regTable->insnRegCountPlus * sizeof(RegType));
+}
+#endif
+
+/*
+ * Register type categories, for type checking.
+ *
+ * The spec says category 1 includes boolean, byte, char, short, int, float,
+ * reference, and returnAddress.  Category 2 includes long and double.
+ *
+ * We treat object references separately, so we have "category1nr".  We
+ * don't support jsr/ret, so there is no "returnAddress" type.
+ */
+enum TypeCategory {
+    kTypeCategoryUnknown = 0,
+    kTypeCategory1nr,           // boolean, byte, char, short, int, float
+    kTypeCategory2,             // long, double
+    kTypeCategoryRef,           // object reference
+};
+
+/*
+ * See if "type" matches "cat".  All we're really looking for here is that
+ * we're not mixing and matching 32-bit and 64-bit quantities, and we're
+ * not mixing references with numerics.  (For example, the arguments to
+ * "a < b" could be integers of different sizes, but they must both be
+ * integers.  Dalvik is less specific about int vs. float, so we treat them
+ * as equivalent here.)
+ *
+ * For category 2 values, "type" must be the "low" half of the value.
+ *
+ * Sets "*pFailure" if something looks wrong.
+ */
+static void checkTypeCategory(RegType type, TypeCategory cat,
+    VerifyError* pFailure)
+{
+    switch (cat) {
+    case kTypeCategory1nr:
+        switch (type) {
+        case kRegTypeZero:
+        case kRegTypeOne:
+        case kRegTypeBoolean:
+        case kRegTypeConstPosByte:
+        case kRegTypeConstByte:
+        case kRegTypeConstPosShort:
+        case kRegTypeConstShort:
+        case kRegTypeConstChar:
+        case kRegTypeConstInteger:
+        case kRegTypePosByte:
+        case kRegTypeByte:
+        case kRegTypePosShort:
+        case kRegTypeShort:
+        case kRegTypeChar:
+        case kRegTypeInteger:
+        case kRegTypeFloat:
+            break;
+        default:
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        break;
+
+    case kTypeCategory2:
+        switch (type) {
+        case kRegTypeConstLo:
+        case kRegTypeLongLo:
+        case kRegTypeDoubleLo:
+            break;
+        default:
+            *pFailure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        break;
+
+    case kTypeCategoryRef:
+        if (type != kRegTypeZero && !regTypeIsReference(type))
+            *pFailure = VERIFY_ERROR_GENERIC;
+        break;
+
+    default:
+        assert(false);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        break;
+    }
+}
+
+/*
+ * For a category 2 register pair, verify that "typeh" is the appropriate
+ * high part for "typel".
+ *
+ * Does not verify that "typel" is in fact the low part of a 64-bit
+ * register pair.
+ */
+static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
+{
+    if ((typeh != typel+1))
+        *pFailure = VERIFY_ERROR_GENERIC;
+}
+
+/*
+ * Implement category-1 "move" instructions.  Copy a 32-bit value from
+ * "vsrc" to "vdst".
+ */
+static void copyRegister1(RegisterLine* registerLine, u4 vdst, u4 vsrc,
+    TypeCategory cat, VerifyError* pFailure)
+{
+    assert(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
+    RegType type = getRegisterType(registerLine, vsrc);
+    checkTypeCategory(type, cat, pFailure);
+    if (!VERIFY_OK(*pFailure)) {
+        LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d", vdst, vsrc, type, cat);
+    } else {
+        setRegisterType(registerLine, vdst, type);
+        if (cat == kTypeCategoryRef && registerLine->monitorEntries != NULL) {
+            registerLine->monitorEntries[vdst] =
+                registerLine->monitorEntries[vsrc];
+        }
+    }
+}
+
+/*
+ * Implement category-2 "move" instructions.  Copy a 64-bit value from
+ * "vsrc" to "vdst".  This copies both halves of the register.
+ */
+static void copyRegister2(RegisterLine* registerLine, u4 vdst, u4 vsrc,
+    VerifyError* pFailure)
+{
+    RegType typel = getRegisterType(registerLine, vsrc);
+    RegType typeh = getRegisterType(registerLine, vsrc+1);
+
+    checkTypeCategory(typel, kTypeCategory2, pFailure);
+    checkWidePair(typel, typeh, pFailure);
+    if (!VERIFY_OK(*pFailure)) {
+        LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d", vdst, vsrc, typel, typeh);
+    } else {
+        setRegisterType(registerLine, vdst, typel);
+        /* target monitor stack bits will be cleared */
+    }
+}
+
+/*
+ * Implement "move-result".  Copy the category-1 value from the result
+ * register to another register, and reset the result register.
+ */
+static void copyResultRegister1(RegisterLine* registerLine,
+    const int insnRegCount, u4 vdst, TypeCategory cat, VerifyError* pFailure)
+{
+    RegType type;
+    u4 vsrc;
+
+    assert(vdst < (u4) insnRegCount);
+
+    vsrc = RESULT_REGISTER(insnRegCount);
+    type = getRegisterType(registerLine, vsrc);
+    checkTypeCategory(type, cat, pFailure);
+    if (!VERIFY_OK(*pFailure)) {
+        LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d",
+            vdst, vsrc, cat, type);
+    } else {
+        setRegisterType(registerLine, vdst, type);
+        setRegisterType(registerLine, vsrc, kRegTypeUnknown);
+        /* target monitor stack bits will be cleared */
+    }
+}
+
+/*
+ * Implement "move-result-wide".  Copy the category-2 value from the result
+ * register to another register, and reset the result register.
+ */
+static void copyResultRegister2(RegisterLine* registerLine,
+    const int insnRegCount, u4 vdst, VerifyError* pFailure)
+{
+    RegType typel, typeh;
+    u4 vsrc;
+
+    assert(vdst < (u4) insnRegCount);
+
+    vsrc = RESULT_REGISTER(insnRegCount);
+    typel = getRegisterType(registerLine, vsrc);
+    typeh = getRegisterType(registerLine, vsrc+1);
+    checkTypeCategory(typel, kTypeCategory2, pFailure);
+    checkWidePair(typel, typeh, pFailure);
+    if (!VERIFY_OK(*pFailure)) {
+        LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d",
+            vdst, vsrc, typel, typeh);
+    } else {
+        setRegisterType(registerLine, vdst, typel);
+        setRegisterType(registerLine, vsrc, kRegTypeUnknown);
+        setRegisterType(registerLine, vsrc+1, kRegTypeUnknown);
+        /* target monitor stack bits will be cleared */
+    }
+}
+
+/*
+ * Verify types for a simple two-register instruction (e.g. "neg-int").
+ * "dstType" is stored into vA, and "srcType" is verified against vB.
+ */
+static void checkUnop(RegisterLine* registerLine, DecodedInstruction* pDecInsn,
+    RegType dstType, RegType srcType, VerifyError* pFailure)
+{
+    verifyRegisterType(registerLine, pDecInsn->vB, srcType, pFailure);
+    setRegisterType(registerLine, pDecInsn->vA, dstType);
+}
+
+/*
+ * We're performing an operation like "and-int/2addr" that can be
+ * performed on booleans as well as integers.  We get no indication of
+ * boolean-ness, but we can infer it from the types of the arguments.
+ *
+ * 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(RegisterLine* registerLine, u4 reg1, u4 reg2)
+{
+    RegType type1, type2;
+
+    type1 = getRegisterType(registerLine, reg1);
+    type2 = getRegisterType(registerLine, reg2);
+
+    if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
+            type1 == kRegTypeOne) &&
+        (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
+            type2 == kRegTypeOne))
+    {
+        return true;
+    }
+    return false;
+}
+
+/*
+ * Verify types for A two-register instruction with a literal constant
+ * (e.g. "add-int/lit8").  "dstType" is stored into vA, and "srcType" is
+ * verified against vB.
+ *
+ * If "checkBooleanOp" is set, we use the constant value in vC.
+ */
+static void checkLitop(RegisterLine* registerLine, DecodedInstruction* pDecInsn,
+    RegType dstType, RegType srcType, bool checkBooleanOp,
+    VerifyError* pFailure)
+{
+    verifyRegisterType(registerLine, pDecInsn->vB, srcType, pFailure);
+    if (VERIFY_OK(*pFailure) && checkBooleanOp) {
+        assert(dstType == kRegTypeInteger);
+        /* check vB with the call, then check the constant manually */
+        if (upcastBooleanOp(registerLine, pDecInsn->vB, pDecInsn->vB)
+            && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
+        {
+            dstType = kRegTypeBoolean;
+        }
+    }
+    setRegisterType(registerLine, pDecInsn->vA, dstType);
+}
+
+/*
+ * Verify types for a simple three-register instruction (e.g. "add-int").
+ * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
+ * against vB/vC.
+ */
+static void checkBinop(RegisterLine* registerLine, DecodedInstruction* pDecInsn,
+    RegType dstType, RegType srcType1, RegType srcType2, bool checkBooleanOp,
+    VerifyError* pFailure)
+{
+    verifyRegisterType(registerLine, pDecInsn->vB, srcType1, pFailure);
+    verifyRegisterType(registerLine, pDecInsn->vC, srcType2, pFailure);
+    if (VERIFY_OK(*pFailure) && checkBooleanOp) {
+        assert(dstType == kRegTypeInteger);
+        if (upcastBooleanOp(registerLine, pDecInsn->vB, pDecInsn->vC))
+            dstType = kRegTypeBoolean;
+    }
+    setRegisterType(registerLine, pDecInsn->vA, dstType);
+}
+
+/*
+ * Verify types for a binary "2addr" operation.  "srcType1"/"srcType2"
+ * are verified against vA/vB, then "dstType" is stored into vA.
+ */
+static void checkBinop2addr(RegisterLine* registerLine,
+    DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
+    RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
+{
+    verifyRegisterType(registerLine, pDecInsn->vA, srcType1, pFailure);
+    verifyRegisterType(registerLine, pDecInsn->vB, srcType2, pFailure);
+    if (VERIFY_OK(*pFailure) && checkBooleanOp) {
+        assert(dstType == kRegTypeInteger);
+        if (upcastBooleanOp(registerLine, pDecInsn->vA, pDecInsn->vB))
+            dstType = kRegTypeBoolean;
+    }
+    setRegisterType(registerLine, pDecInsn->vA, dstType);
+}
+
+/*
+ * 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(RegisterLine* registerLine, int reg,
+    unsigned int shiftCount, bool isUnsignedShift, VerifyError* pFailure)
+{
+    RegType srcType = getRegisterType(registerLine, reg);
+    RegType newType;
+
+    /* convert const derived types to their actual types */
+    srcType = constTypeToRegType(srcType);
+
+    /* 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", shiftCount);
+        /* fail? */
+        return newType;
+    }
+
+    switch (srcType) {
+    case kRegTypeInteger:               /* 32-bit signed value */
+        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",
+            shiftCount, isUnsignedShift, srcType, newType);
+    } else {
+        LOGVV("not narrowed: %d(%d) --> %d",
+            shiftCount, isUnsignedShift, srcType);
+    }
+    return newType;
+}
+
+
+/*
+ * ===========================================================================
+ *      Register merge
+ * ===========================================================================
+ */
+
+/*
+ * Compute the "class depth" of a class.  This is the distance from the
+ * class to the top of the tree, chasing superclass links.  java.lang.Object
+ * has a class depth of 0.
+ */
+static int getClassDepth(ClassObject* clazz)
+{
+    int depth = 0;
+
+    while (clazz->super != NULL) {
+        clazz = clazz->super;
+        depth++;
+    }
+    return depth;
+}
+
+/*
+ * Given two classes, walk up the superclass tree to find a common
+ * ancestor.  (Called from findCommonSuperclass().)
+ *
+ * TODO: consider caching the class depth in the class object so we don't
+ * have to search for it here.
+ */
+static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
+{
+    int depth1, depth2;
+
+    depth1 = getClassDepth(c1);
+    depth2 = getClassDepth(c2);
+
+    if (gDebugVerbose) {
+        LOGVV("COMMON: %s(%d) + %s(%d)",
+            c1->descriptor, depth1, c2->descriptor, depth2);
+    }
+
+    /* pull the deepest one up */
+    if (depth1 > depth2) {
+        while (depth1 > depth2) {
+            c1 = c1->super;
+            depth1--;
+        }
+    } else {
+        while (depth2 > depth1) {
+            c2 = c2->super;
+            depth2--;
+        }
+    }
+
+    /* walk up in lock-step */
+    while (c1 != c2) {
+        c1 = c1->super;
+        c2 = c2->super;
+
+        assert(c1 != NULL && c2 != NULL);
+    }
+
+    if (gDebugVerbose) {
+        LOGVV("      : --> %s", c1->descriptor);
+    }
+    return c1;
+}
+
+/*
+ * Merge two array classes.  We can't use the general "walk up to the
+ * superclass" merge because the superclass of an array is always Object.
+ * We want String[] + Integer[] = Object[].  This works for higher dimensions
+ * as well, e.g. String[][] + Integer[][] = Object[][].
+ *
+ * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
+ *
+ * If Class implements Type, Class[] + Type[] = Type[].
+ *
+ * If the dimensions don't match, we want to convert to an array of Object
+ * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
+ *
+ * Arrays of primitive types effectively have one less dimension when
+ * merging.  int[] + float[] = Object, int[] + String[] = Object,
+ * int[][] + float[][] = Object[], int[][] + String[] = Object[].  (The
+ * only time this function doesn't return an array class is when one of
+ * the arguments is a 1-dimensional primitive array.)
+ *
+ * This gets a little awkward because we may have to ask the VM to create
+ * a new array type with the appropriate element and dimensions.  However, we
+ * shouldn't be doing this often.
+ */
+static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
+{
+    ClassObject* arrayClass = NULL;
+    ClassObject* commonElem;
+    int arrayDim1, arrayDim2;
+    int i, numDims;
+    bool hasPrimitive = false;
+
+    arrayDim1 = c1->arrayDim;
+    arrayDim2 = c2->arrayDim;
+    assert(c1->arrayDim > 0);
+    assert(c2->arrayDim > 0);
+
+    if (dvmIsPrimitiveClass(c1->elementClass)) {
+        arrayDim1--;
+        hasPrimitive = true;
+    }
+    if (dvmIsPrimitiveClass(c2->elementClass)) {
+        arrayDim2--;
+        hasPrimitive = true;
+    }
+
+    if (!hasPrimitive && arrayDim1 == arrayDim2) {
+        /*
+         * Two arrays of reference types with equal dimensions.  Try to
+         * find a good match.
+         */
+        commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
+        numDims = arrayDim1;
+    } else {
+        /*
+         * Mismatched array depths and/or array(s) of primitives.  We want
+         * Object, or an Object array with appropriate dimensions.
+         *
+         * We initialize arrayClass to Object here, because it's possible
+         * for us to set numDims=0.
+         */
+        if (arrayDim1 < arrayDim2)
+            numDims = arrayDim1;
+        else
+            numDims = arrayDim2;
+        arrayClass = commonElem = c1->super;     // == java.lang.Object
+    }
+
+    /*
+     * Find an appropriately-dimensioned array class.  This is easiest
+     * to do iteratively, using the array class found by the current round
+     * as the element type for the next round.
+     */
+    for (i = 0; i < numDims; i++) {
+        arrayClass = dvmFindArrayClassForElement(commonElem);
+        commonElem = arrayClass;
+    }
+    assert(arrayClass != NULL);
+
+    LOGVV("ArrayMerge '%s' + '%s' --> '%s'",
+        c1->descriptor, c2->descriptor, arrayClass->descriptor);
+    return arrayClass;
+}
+
+/*
+ * Find the first common superclass of the two classes.  We're not
+ * interested in common interfaces.
+ *
+ * The easiest way to do this for concrete classes is to compute the "class
+ * depth" of each, move up toward the root of the deepest one until they're
+ * at the same depth, then walk both up to the root until they match.
+ *
+ * If both classes are arrays, we need to merge based on array depth and
+ * element type.
+ *
+ * If one class is an interface, we check to see if the other class/interface
+ * (or one of its predecessors) implements the interface.  If so, we return
+ * the interface; otherwise, we return Object.
+ *
+ * NOTE: we continue the tradition of "lazy interface handling".  To wit,
+ * suppose we have three classes:
+ *   One implements Fancy, Free
+ *   Two implements Fancy, Free
+ *   Three implements Free
+ * where Fancy and Free are unrelated interfaces.  The code requires us
+ * to merge One into Two.  Ideally we'd use a common interface, which
+ * gives us a choice between Fancy and Free, and no guidance on which to
+ * use.  If we use Free, we'll be okay when Three gets merged in, but if
+ * we choose Fancy, we're hosed.  The "ideal" solution is to create a
+ * set of common interfaces and carry that around, merging further references
+ * into it.  This is a pain.  The easy solution is to simply boil them
+ * down to Objects and let the runtime invokeinterface call fail, which
+ * is what we do.
+ */
+static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
+{
+    assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
+
+    if (c1 == c2)
+        return c1;
+
+    if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
+        if (gDebugVerbose)
+            LOGVV("COMMON/I1: %s + %s --> %s",
+                c1->descriptor, c2->descriptor, c1->descriptor);
+        return c1;
+    }
+    if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
+        if (gDebugVerbose)
+            LOGVV("COMMON/I2: %s + %s --> %s",
+                c1->descriptor, c2->descriptor, c2->descriptor);
+        return c2;
+    }
+
+    if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2)) {
+        return findCommonArraySuperclass(c1, c2);
+    }
+
+    return digForSuperclass(c1, c2);
+}
+
+/*
+ * Merge two RegType values.
+ *
+ * Sets "*pChanged" to "true" if the result doesn't match "type1".
+ */
+static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
+{
+    RegType result;
+
+    /*
+     * Check for trivial case so we don't have to hit memory.
+     */
+    if (type1 == type2)
+        return type1;
+
+    /*
+     * Use the table if we can, and reject any attempts to merge something
+     * from the table with a reference type.
+     *
+     * Uninitialized references are composed of the enum ORed with an
+     * index value.  The uninitialized table entry at index zero *will*
+     * show up as a simple kRegTypeUninit value.  Since this cannot be
+     * merged with anything but itself, the rules do the right thing.
+     */
+    if (type1 < kRegTypeMAX) {
+        if (type2 < kRegTypeMAX) {
+            result = gDvmMergeTab[type1][type2];
+        } else {
+            /* simple + reference == conflict, usually */
+            if (type1 == kRegTypeZero)
+                result = type2;
+            else
+                result = kRegTypeConflict;
+        }
+    } else {
+        if (type2 < kRegTypeMAX) {
+            /* reference + simple == conflict, usually */
+            if (type2 == kRegTypeZero)
+                result = type1;
+            else
+                result = kRegTypeConflict;
+        } else {
+            /* merging two references */
+            if (regTypeIsUninitReference(type1) ||
+                regTypeIsUninitReference(type2))
+            {
+                /* can't merge uninit with anything but self */
+                result = kRegTypeConflict;
+            } else {
+                ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
+                ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
+                ClassObject* mergedClass;
+
+                mergedClass = findCommonSuperclass(clazz1, clazz2);
+                assert(mergedClass != NULL);
+                result = regTypeFromClass(mergedClass);
+            }
+        }
+    }
+
+    if (result != type1)
+        *pChanged = true;
+    return result;
+}
+
+/*
+ * Merge the bits that indicate which monitor entry addresses on the stack
+ * are associated with this register.
+ *
+ * The merge is a simple bitwise AND.
+ *
+ * Sets "*pChanged" to "true" if the result doesn't match "ents1".
+ */
+static MonitorEntries mergeMonitorEntries(MonitorEntries ents1,
+    MonitorEntries ents2, bool* pChanged)
+{
+    MonitorEntries result = ents1 & ents2;
+    if (result != ents1)
+        *pChanged = true;
+    return result;
+}
+
+/*
+ * Control can transfer to "nextInsn".
+ *
+ * Merge the registers from "workLine" into "regTable" at "nextInsn", and
+ * set the "changed" flag on the target address if any of the registers
+ * has changed.
+ *
+ * Returns "false" if we detect mis-matched monitor stacks.
+ */
+static bool updateRegisters(const Method* meth, InsnFlags* insnFlags,
+    RegisterTable* regTable, int nextInsn, const RegisterLine* workLine)
+{
+    const size_t insnRegCountPlus = regTable->insnRegCountPlus;
+    assert(workLine != NULL);
+    const RegType* workRegs = workLine->regTypes;
+
+    if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
+        /*
+         * We haven't processed this instruction before, and we haven't
+         * touched the registers here, so there's nothing to "merge".  Copy
+         * the registers over and mark it as changed.  (This is the only
+         * way a register can transition out of "unknown", so this is not
+         * just an optimization.)
+         */
+        LOGVV("COPY into 0x%04x", nextInsn);
+        copyLineToTable(regTable, nextInsn, workLine);
+        dvmInsnSetChanged(insnFlags, nextInsn, true);
+#ifdef VERIFIER_STATS
+        gDvm.verifierStats.copyRegCount++;
+#endif
+    } else {
+        if (gDebugVerbose) {
+            LOGVV("MERGE into 0x%04x", nextInsn);
+            //dumpRegTypes(vdata, targetRegs, 0, "targ", NULL, 0);
+            //dumpRegTypes(vdata, workRegs, 0, "work", NULL, 0);
+        }
+        /* merge registers, set Changed only if different */
+        RegisterLine* targetLine = getRegisterLine(regTable, nextInsn);
+        RegType* targetRegs = targetLine->regTypes;
+        MonitorEntries* workMonEnts = workLine->monitorEntries;
+        MonitorEntries* targetMonEnts = targetLine->monitorEntries;
+        bool changed = false;
+        unsigned int idx;
+
+        assert(targetRegs != NULL);
+
+        if (targetMonEnts != NULL) {
+            /*
+             * Monitor stacks must be identical.
+             */
+            if (targetLine->monitorStackTop != workLine->monitorStackTop) {
+                LOG_VFY_METH(meth,
+                    "VFY: mismatched stack depth %d vs. %d at 0x%04x",
+                    targetLine->monitorStackTop, workLine->monitorStackTop,
+                    nextInsn);
+                return false;
+            }
+            if (memcmp(targetLine->monitorStack, workLine->monitorStack,
+                    targetLine->monitorStackTop * sizeof(u4)) != 0)
+            {
+                LOG_VFY_METH(meth, "VFY: mismatched monitor stacks at 0x%04x",
+                    nextInsn);
+                return false;
+            }
+        }
+
+        for (idx = 0; idx < insnRegCountPlus; idx++) {
+            targetRegs[idx] =
+                    mergeTypes(targetRegs[idx], workRegs[idx], &changed);
+
+            if (targetMonEnts != NULL) {
+                targetMonEnts[idx] = mergeMonitorEntries(targetMonEnts[idx],
+                    workMonEnts[idx], &changed);
+            }
+        }
+
+        if (gDebugVerbose) {
+            //LOGI(" RESULT (changed=%d)", changed);
+            //dumpRegTypes(vdata, targetRegs, 0, "rslt", NULL, 0);
+        }
+#ifdef VERIFIER_STATS
+        gDvm.verifierStats.mergeRegCount++;
+        if (changed)
+            gDvm.verifierStats.mergeRegChanged++;
+#endif
+
+        if (changed)
+            dvmInsnSetChanged(insnFlags, nextInsn, true);
+    }
+
+    return true;
+}
+
+
+/*
+ * ===========================================================================
+ *      Utility functions
+ * ===========================================================================
+ */
+
+/*
+ * Look up an instance field, specified by "fieldIdx", that is going to be
+ * accessed in object "objType".  This resolves the field and then verifies
+ * that the class containing the field is an instance of the reference in
+ * "objType".
+ *
+ * It is possible for "objType" to be kRegTypeZero, meaning that we might
+ * have a null reference.  This is a runtime problem, so we allow it,
+ * skipping some of the type checks.
+ *
+ * In general, "objType" must be an initialized reference.  However, we
+ * 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 "*pFailure"
+ * on failure.
+ */
+static InstField* getInstField(const Method* meth,
+    const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
+    VerifyError* pFailure)
+{
+    InstField* instField = NULL;
+    ClassObject* objClass;
+    bool mustBeLocal = false;
+
+    if (!regTypeIsReference(objType)) {
+        LOG_VFY("VFY: attempt to access field in non-reference type %d",
+            objType);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        goto bail;
+    }
+
+    instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
+    if (instField == NULL) {
+        LOG_VFY("VFY: unable to resolve instance field %u", fieldIdx);
+        assert(!VERIFY_OK(*pFailure));
+        goto bail;
+    }
+
+    if (objType == kRegTypeZero)
+        goto bail;
+
+    /*
+     * Access to fields in uninitialized objects is allowed if this is
+     * the <init> method for the object and the field in question is
+     * declared by this class.
+     */
+    objClass = regTypeReferenceToClass(objType, uninitMap);
+    assert(objClass != NULL);
+    if (regTypeIsUninitReference(objType)) {
+        if (!isInitMethod(meth) || meth->clazz != objClass) {
+            LOG_VFY("VFY: attempt to access field via uninitialized ref");
+            *pFailure = VERIFY_ERROR_GENERIC;
+            goto bail;
+        }
+        mustBeLocal = true;
+    }
+
+    if (!dvmInstanceof(objClass, instField->clazz)) {
+        LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)",
+                instField->clazz->descriptor, instField->name,
+                objClass->descriptor);
+        *pFailure = VERIFY_ERROR_NO_FIELD;
+        goto bail;
+    }
+
+    if (mustBeLocal) {
+        /* for uninit ref, make sure it's defined by this class, not super */
+        if (instField < objClass->ifields ||
+            instField >= objClass->ifields + objClass->ifieldCount)
+        {
+            LOG_VFY("VFY: invalid constructor field access (field %s in %s)",
+                    instField->name, objClass->descriptor);
+            *pFailure = VERIFY_ERROR_GENERIC;
+            goto bail;
+        }
+    }
+
+bail:
+    return instField;
+}
+
+/*
+ * Look up a static field.
+ *
+ * Returns a StaticField on success, returns NULL and sets "*pFailure"
+ * on failure.
+ */
+static StaticField* getStaticField(const Method* meth, int fieldIdx,
+    VerifyError* pFailure)
+{
+    StaticField* staticField;
+
+    staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
+    if (staticField == NULL) {
+        DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+        const DexFieldId* pFieldId;
+
+        pFieldId = dexGetFieldId(pDexFile, fieldIdx);
+
+        LOG_VFY("VFY: unable to resolve static field %u (%s) in %s", fieldIdx,
+            dexStringById(pDexFile, pFieldId->nameIdx),
+            dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
+        assert(!VERIFY_OK(*pFailure));
+        goto bail;
+    }
+
+bail:
+    return staticField;
+}
+
+/*
+ * If "field" is marked "final", make sure this is the either <clinit>
+ * or <init> as appropriate.
+ *
+ * Sets "*pFailure" on failure.
+ */
+static void checkFinalFieldAccess(const Method* meth, const Field* field,
+    VerifyError* pFailure)
+{
+    if (!dvmIsFinalField(field))
+        return;
+
+    /* make sure we're in the same class */
+    if (meth->clazz != field->clazz) {
+        LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s",
+            field->clazz->descriptor, field->name);
+        *pFailure = VERIFY_ERROR_ACCESS_FIELD;
+        return;
+    }
+
+    /*
+     * 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 */
+    if (dvmIsStaticField(field)) {
+        if (!isClassInitMethod(meth)) {
+            LOG_VFY_METH(meth,
+                "VFY: can't modify final static field outside <clinit>");
+            *pFailure = VERIFY_ERROR_GENERIC;
+        }
+    } else {
+        if (!isInitMethod(meth)) {
+            LOG_VFY_METH(meth,
+                "VFY: can't modify final field outside <init>");
+            *pFailure = VERIFY_ERROR_GENERIC;
+        }
+    }
+#endif
+}
+
+/*
+ * Make sure that the register type is suitable for use as an array index.
+ *
+ * Sets "*pFailure" if not.
+ */
+static void checkArrayIndexType(const Method* meth, RegType regType,
+    VerifyError* pFailure)
+{
+    if (VERIFY_OK(*pFailure)) {
+        /*
+         * The 1nr types are interchangeable at this level. However,
+         * check that a float is not used as the index.
+         */
+        checkTypeCategory(regType, kTypeCategory1nr, pFailure);
+        if (regType == kRegTypeFloat) {
+          *pFailure = VERIFY_ERROR_GENERIC;
+        }
+        if (!VERIFY_OK(*pFailure)) {
+            LOG_VFY_METH(meth, "Invalid reg type for array index (%d)",
+                regType);
+        }
+    }
+}
+
+/*
+ * Check constraints on constructor return.  Specifically, make sure that
+ * the "this" argument got initialized.
+ *
+ * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
+ * puts it at the start of the list in slot 0.  If we see a register with
+ * an uninitialized slot 0 reference, we know it somehow didn't get
+ * initialized.
+ *
+ * Returns "true" if all is well.
+ */
+static bool checkConstructorReturn(const Method* meth,
+    const RegisterLine* registerLine, const int insnRegCount)
+{
+    const RegType* insnRegs = registerLine->regTypes;
+    int i;
+
+    if (!isInitMethod(meth))
+        return true;
+
+    RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
+
+    for (i = 0; i < insnRegCount; i++) {
+        if (insnRegs[i] == uninitThis) {
+            LOG_VFY("VFY: <init> returning without calling superclass init");
+            return false;
+        }
+    }
+    return true;
+}
+
+/*
+ * Verify that the target instruction is not "move-exception".  It's important
+ * that the only way to execute a move-exception is as the first instruction
+ * of an exception handler.
+ *
+ * Returns "true" if all is well, "false" if the target instruction is
+ * move-exception.
+ */
+static bool checkMoveException(const Method* meth, int insnIdx,
+    const char* logNote)
+{
+    assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
+
+    if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
+        LOG_VFY("VFY: invalid use of move-exception");
+        return false;
+    }
+    return true;
+}
+
+/*
+ * For the "move-exception" instruction at "insnIdx", which must be at an
+ * exception handler address, determine the first common superclass of
+ * all exceptions that can land here.  (For javac output, we're probably
+ * looking at multiple spans of bytecode covered by one "try" that lands
+ * at an exception-specific "catch", but in general the handler could be
+ * shared for multiple exceptions.)
+ *
+ * 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,
+    VerifyError* pFailure)
+{
+    VerifyError localFailure;
+    const DexCode* pCode;
+    DexFile* pDexFile;
+    ClassObject* commonSuper = NULL;
+    u4 handlersSize;
+    u4 offset;
+    u4 i;
+
+    pDexFile = meth->clazz->pDvmDex->pDexFile;
+    pCode = dvmGetMethodCode(meth);
+
+    if (pCode->triesSize != 0) {
+        handlersSize = dexGetHandlersSize(pCode);
+        offset = dexGetFirstHandlerOffset(pCode);
+    } else {
+        handlersSize = 0;
+        offset = 0;
+    }
+
+    for (i = 0; i < handlersSize; i++) {
+        DexCatchIterator iterator;
+        dexCatchIteratorInit(&iterator, pCode, offset);
+
+        for (;;) {
+            const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+
+            if (handler == NULL) {
+                break;
+            }
+
+            if (handler->address == (u4) insnIdx) {
+                ClassObject* clazz;
+
+                if (handler->typeIdx == kDexNoIndex)
+                    clazz = gDvm.exThrowable;
+                else
+                    clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
+                                &localFailure);
+
+                if (clazz == NULL) {
+                    LOG_VFY("VFY: unable to resolve exception class %u (%s)",
+                        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;
+                    else
+                        commonSuper = findCommonSuperclass(clazz, commonSuper);
+                }
+            }
+        }
+
+        offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
+    }
+
+    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 %#x", insnIdx);
+        *pFailure = VERIFY_ERROR_GENERIC;
+    } else {
+        // TODO: verify the class is an instance of Throwable?
+    }
+
+    return commonSuper;
+}
+
+/*
+ * Helper for initRegisterTable.
+ *
+ * Returns an updated copy of "storage".
+ */
+static u1* assignLineStorage(u1* storage, RegisterLine* line,
+    bool trackMonitors, size_t regTypeSize, size_t monEntSize, size_t stackSize)
+{
+    line->regTypes = (RegType*) storage;
+    storage += regTypeSize;
+
+    if (trackMonitors) {
+        line->monitorEntries = (MonitorEntries*) storage;
+        storage += monEntSize;
+        line->monitorStack = (u4*) storage;
+        storage += stackSize;
+
+        assert(line->monitorStackTop == 0);
+    }
+
+    return storage;
+}
+
+/*
+ * Initialize the RegisterTable.
+ *
+ * Every instruction address can have a different set of information about
+ * what's in which register, but for verification purposes we only need to
+ * store it at branch target addresses (because we merge into that).
+ *
+ * By zeroing out the regType storage we are effectively initializing the
+ * register information to kRegTypeUnknown.
+ *
+ * We jump through some hoops here to minimize the total number of
+ * allocations we have to perform per method verified.
+ */
+static bool initRegisterTable(const VerifierData* vdata,
+    RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
+{
+    const Method* meth = vdata->method;
+    const int insnsSize = vdata->insnsSize;
+    const InsnFlags* insnFlags = vdata->insnFlags;
+    const int kExtraLines = 2;  /* workLine, savedLine */
+    int i;
+
+    /*
+     * Every address gets a RegisterLine struct.  This is wasteful, but
+     * not so much that it's worth chasing through an extra level of
+     * indirection.
+     */
+    regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
+    regTable->registerLines =
+        (RegisterLine*) calloc(insnsSize, sizeof(RegisterLine));
+    if (regTable->registerLines == NULL)
+        return false;
+
+    assert(insnsSize > 0);
+
+    /*
+     * Count up the number of "interesting" instructions.
+     *
+     * "All" means "every address that holds the start of an instruction".
+     * "Branches" and "GcPoints" mean just those addresses.
+     *
+     * "GcPoints" fills about half the addresses, "Branches" about 15%.
+     */
+    int interestingCount = kExtraLines;
+
+    for (i = 0; i < insnsSize; i++) {
+        bool interesting;
+
+        switch (trackRegsFor) {
+        case kTrackRegsAll:
+            interesting = dvmInsnIsOpcode(insnFlags, i);
+            break;
+        case kTrackRegsGcPoints:
+            interesting = dvmInsnIsGcPoint(insnFlags, i) ||
+                          dvmInsnIsBranchTarget(insnFlags, i);
+            break;
+        case kTrackRegsBranches:
+            interesting = dvmInsnIsBranchTarget(insnFlags, i);
+            break;
+        default:
+            dvmAbort();
+            return false;
+        }
+
+        if (interesting)
+            interestingCount++;
+
+        /* count instructions, for display only */
+        //if (dvmInsnIsOpcode(insnFlags, i))
+        //    insnCount++;
+    }
+
+    /*
+     * Allocate storage for the register type arrays.
+     * TODO: set trackMonitors based on global config option
+     */
+    size_t regTypeSize = regTable->insnRegCountPlus * sizeof(RegType);
+    size_t monEntSize = regTable->insnRegCountPlus * sizeof(MonitorEntries);
+    size_t stackSize = kMaxMonitorStackDepth * sizeof(u4);
+    bool trackMonitors;
+
+    if (gDvm.monitorVerification) {
+        trackMonitors = (vdata->monitorEnterCount != 0);
+    } else {
+        trackMonitors = false;
+    }
+
+    size_t spacePerEntry = regTypeSize +
+        (trackMonitors ? monEntSize + stackSize : 0);
+    regTable->lineAlloc = calloc(interestingCount, spacePerEntry);
+    if (regTable->lineAlloc == NULL)
+        return false;
+
+#ifdef VERIFIER_STATS
+    size_t totalSpace = interestingCount * spacePerEntry +
+        insnsSize * sizeof(RegisterLine);
+    if (gDvm.verifierStats.biggestAlloc < totalSpace)
+        gDvm.verifierStats.biggestAlloc = totalSpace;
+#endif
+
+    /*
+     * Populate the sparse register line table.
+     *
+     * There is a RegisterLine associated with every address, but not
+     * every RegisterLine has non-NULL pointers to storage for its fields.
+     */
+    u1* storage = (u1*)regTable->lineAlloc;
+    for (i = 0; i < insnsSize; i++) {
+        bool interesting;
+
+        switch (trackRegsFor) {
+        case kTrackRegsAll:
+            interesting = dvmInsnIsOpcode(insnFlags, i);
+            break;
+        case kTrackRegsGcPoints:
+            interesting = dvmInsnIsGcPoint(insnFlags, i) ||
+                          dvmInsnIsBranchTarget(insnFlags, i);
+            break;
+        case kTrackRegsBranches:
+            interesting = dvmInsnIsBranchTarget(insnFlags, i);
+            break;
+        default:
+            dvmAbort();
+            return false;
+        }
+
+        if (interesting) {
+            storage = assignLineStorage(storage, &regTable->registerLines[i],
+                trackMonitors, regTypeSize, monEntSize, stackSize);
+        }
+    }
+
+    /*
+     * Grab storage for our "temporary" register lines.
+     */
+    storage = assignLineStorage(storage, &regTable->workLine,
+        trackMonitors, regTypeSize, monEntSize, stackSize);
+    storage = assignLineStorage(storage, &regTable->savedLine,
+        trackMonitors, regTypeSize, monEntSize, stackSize);
+
+    //LOGD("Tracking registers for [%d], total %d in %d units",
+    //    trackRegsFor, interestingCount-kExtraLines, insnsSize);
+
+    assert(storage - (u1*)regTable->lineAlloc ==
+        (int) (interestingCount * spacePerEntry));
+    assert(regTable->registerLines[0].regTypes != NULL);
+    return true;
+}
+
+/*
+ * Free up any "hairy" structures associated with register lines.
+ */
+static void freeRegisterLineInnards(VerifierData* vdata)
+{
+    unsigned int idx;
+
+    if (vdata->registerLines == NULL)
+        return;
+
+    for (idx = 0; idx < vdata->insnsSize; idx++) {
+        BitVector* liveRegs = vdata->registerLines[idx].liveRegs;
+        if (liveRegs != NULL)
+            dvmFreeBitVector(liveRegs);
+    }
+}
+
+
+/*
+ * Verify that the arguments in a filled-new-array instruction are valid.
+ *
+ * "resClass" is the class refered to by pDecInsn->vB.
+ */
+static void verifyFilledNewArrayRegs(const Method* meth,
+    RegisterLine* registerLine, const DecodedInstruction* pDecInsn,
+    ClassObject* resClass, bool isRange, VerifyError* pFailure)
+{
+    u4 argCount = pDecInsn->vA;
+    RegType expectedType;
+    PrimitiveType elemType;
+    unsigned int ui;
+
+    assert(dvmIsArrayClass(resClass));
+    elemType = resClass->elementClass->primitiveType;
+    if (elemType == PRIM_NOT) {
+        expectedType = regTypeFromClass(resClass->elementClass);
+    } else {
+        expectedType = primitiveTypeToRegType(elemType);
+    }
+    //LOGI("filled-new-array: %s -> %d", resClass->descriptor, expectedType);
+
+    /*
+     * Verify each register.  If "argCount" is bad, verifyRegisterType()
+     * will run off the end of the list and fail.  It's legal, if silly,
+     * for argCount to be zero.
+     */
+    for (ui = 0; ui < argCount; ui++) {
+        u4 getReg;
+
+        if (isRange)
+            getReg = pDecInsn->vC + ui;
+        else
+            getReg = pDecInsn->arg[ui];
+
+        verifyRegisterType(registerLine, getReg, expectedType, pFailure);
+        if (!VERIFY_OK(*pFailure)) {
+            LOG_VFY("VFY: filled-new-array arg %u(%u) not valid", ui, getReg);
+            return;
+        }
+    }
+}
+
+
+/*
+ * Replace an instruction with "throw-verification-error".  This allows us to
+ * defer error reporting until the code path is first used.
+ *
+ * This is expected to be called during "just in time" verification, not
+ * from within dexopt.  (Verification failures in dexopt will result in
+ * postponement of verification to first use of the class.)
+ *
+ * The throw-verification-error instruction requires two code units.  Some
+ * of the replaced instructions require three; the third code unit will
+ * receive a "nop".  The instruction's length will be left unchanged
+ * in "insnFlags".  If the erroring instruction is a jumbo instruction,
+ * the throw-verification-error-jumbo instruction requires four code units.
+ * Some jumbo instructions require five, and the fifth code unit will become
+ * a "nop".
+ *
+ * The VM postpones setting of debugger breakpoints in unverified classes,
+ * so there should be no clashes with the debugger.
+ *
+ * Returns "true" on success.
+ */
+static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
+    int insnIdx, VerifyError failure)
+{
+    VerifyErrorRefType refType;
+    u2* oldInsns = (u2*) meth->insns + insnIdx;
+    int width;
+    bool result = false;
+
+    if (gDvm.optimizing)
+        LOGD("Weird: RFI during dexopt?");
+
+    /*
+     * Generate the new instruction out of the old.
+     *
+     * First, make sure this is an instruction we're expecting to stomp on.
+     */
+    Opcode opcode = dexOpcodeFromCodeUnit(*oldInsns);
+    switch (opcode) {
+    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_CONST_CLASS_JUMBO:          // insn[1/2] == class ref, 4 bytes
+    case OP_CHECK_CAST_JUMBO:
+    case OP_NEW_INSTANCE_JUMBO:
+    case OP_INSTANCE_OF_JUMBO:          // insn[1/2] == class ref, 5 bytes
+    case OP_NEW_ARRAY_JUMBO:
+    case OP_FILLED_NEW_ARRAY_JUMBO:
+        refType = VERIFY_ERROR_REF_CLASS;
+        break;
+
+    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_SGET_JUMBO:                 // insn[1/2] == field ref, 4 bytes
+    case OP_SGET_BOOLEAN_JUMBO:
+    case OP_SGET_BYTE_JUMBO:
+    case OP_SGET_CHAR_JUMBO:
+    case OP_SGET_SHORT_JUMBO:
+    case OP_SGET_WIDE_JUMBO:
+    case OP_SGET_OBJECT_JUMBO:
+    case OP_SPUT_JUMBO:
+    case OP_SPUT_BOOLEAN_JUMBO:
+    case OP_SPUT_BYTE_JUMBO:
+    case OP_SPUT_CHAR_JUMBO:
+    case OP_SPUT_SHORT_JUMBO:
+    case OP_SPUT_WIDE_JUMBO:
+    case OP_SPUT_OBJECT_JUMBO:
+    case OP_IGET_JUMBO:                 // insn[1/2] == field ref, 5 bytes
+    case OP_IGET_BOOLEAN_JUMBO:
+    case OP_IGET_BYTE_JUMBO:
+    case OP_IGET_CHAR_JUMBO:
+    case OP_IGET_SHORT_JUMBO:
+    case OP_IGET_WIDE_JUMBO:
+    case OP_IGET_OBJECT_JUMBO:
+    case OP_IPUT_JUMBO:
+    case OP_IPUT_BOOLEAN_JUMBO:
+    case OP_IPUT_BYTE_JUMBO:
+    case OP_IPUT_CHAR_JUMBO:
+    case OP_IPUT_SHORT_JUMBO:
+    case OP_IPUT_WIDE_JUMBO:
+    case OP_IPUT_OBJECT_JUMBO:
+        refType = VERIFY_ERROR_REF_FIELD;
+        break;
+
+    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:
+    case OP_INVOKE_VIRTUAL_JUMBO:       // insn[1/2] == method ref, 5 bytes
+    case OP_INVOKE_SUPER_JUMBO:
+    case OP_INVOKE_DIRECT_JUMBO:
+    case OP_INVOKE_STATIC_JUMBO:
+    case OP_INVOKE_INTERFACE_JUMBO:
+        refType = VERIFY_ERROR_REF_METHOD;
+        break;
+
+    default:
+        /* could handle this in a generic way, but this is probably safer */
+        LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x", opcode);
+        goto bail;
+    }
+
+    assert((dexGetFlagsFromOpcode(opcode) & kInstrCanThrow) != 0);
+
+    /* write a NOP over the third code unit, if necessary */
+    width = dvmInsnGetWidth(insnFlags, insnIdx);
+    switch (width) {
+    case 2:
+    case 4:
+        /* nothing to do */
+        break;
+    case 3:
+        dvmUpdateCodeUnit(meth, oldInsns+2, OP_NOP);
+        break;
+    case 5:
+        dvmUpdateCodeUnit(meth, oldInsns+4, OP_NOP);
+        break;
+    default:
+        /* whoops */
+        LOGE("ERROR: stomped a %d-unit instruction with a verifier error",
+            width);
+        dvmAbort();
+    }
+
+    /* check for jumbo opcodes */
+    if (opcode > OP_DISPATCH_FF) {
+        /* replace opcode and failure code */
+        assert(width == 4 || width == 5);
+        u2 newVal = (u2) ((OP_THROW_VERIFICATION_ERROR_JUMBO << 8) |
+                           OP_DISPATCH_FF);
+        dvmUpdateCodeUnit(meth, oldInsns, newVal);
+        newVal = failure | (refType << kVerifyErrorRefTypeShift);
+        dvmUpdateCodeUnit(meth, oldInsns+3, newVal);
+    } else {
+        /* encode the opcode, with the failure code in the high byte */
+        assert(width == 2 || width == 3);
+        u2 newVal = OP_THROW_VERIFICATION_ERROR |
+            (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
+        dvmUpdateCodeUnit(meth, oldInsns, newVal);
+    }
+
+    result = true;
+
+bail:
+    return result;
+}
+
+/*
+ * Handle a monitor-enter instruction.
+ */
+void handleMonitorEnter(RegisterLine* workLine, u4 regIdx, u4 insnIdx,
+    VerifyError* pFailure)
+{
+    if (!regTypeIsReference(getRegisterType(workLine, regIdx))) {
+        LOG_VFY("VFY: monitor-enter on non-object");
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    }
+
+    if (workLine->monitorEntries == NULL) {
+        /* should only be true if monitor verification is disabled */
+        assert(!gDvm.monitorVerification);
+        return;
+    }
+
+    if (workLine->monitorStackTop == kMaxMonitorStackDepth) {
+        LOG_VFY("VFY: monitor-enter stack overflow (%d)",
+            kMaxMonitorStackDepth);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    }
+
+    /*
+     * Push an entry on the stack, and set a bit in the register flags to
+     * indicate that it's associated with this register.
+     */
+    workLine->monitorEntries[regIdx] |= 1 << workLine->monitorStackTop;
+    workLine->monitorStack[workLine->monitorStackTop++] = insnIdx;
+}
+
+/*
+ * Handle a monitor-exit instruction.
+ */
+void handleMonitorExit(RegisterLine* workLine, u4 regIdx, u4 insnIdx,
+    VerifyError* pFailure)
+{
+    if (!regTypeIsReference(getRegisterType(workLine, regIdx))) {
+        LOG_VFY("VFY: monitor-exit on non-object");
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    }
+
+    if (workLine->monitorEntries == NULL) {
+        /* should only be true if monitor verification is disabled */
+        assert(!gDvm.monitorVerification);
+        return;
+    }
+
+    if (workLine->monitorStackTop == 0) {
+        LOG_VFY("VFY: monitor-exit stack underflow");
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    }
+
+    /*
+     * Confirm that the entry at the top of the stack is associated with
+     * the register.  Pop the top entry off.
+     */
+    workLine->monitorStackTop--;
+#ifdef BUG_3215458_FIXED
+    /*
+     * TODO: This code can safely be enabled if know we are working on
+     * a dex file of format version 036 or later. (That is, we'll need to
+     * add a check for the version number.)
+     */
+    if ((workLine->monitorEntries[regIdx] & (1 << workLine->monitorStackTop))
+            == 0)
+    {
+        LOG_VFY("VFY: monitor-exit bit %d not set: addr=0x%04x (bits[%d]=%#x)",
+            workLine->monitorStackTop, insnIdx, regIdx,
+            workLine->monitorEntries[regIdx]);
+        *pFailure = VERIFY_ERROR_GENERIC;
+        return;
+    }
+#endif
+    workLine->monitorStack[workLine->monitorStackTop] = 0;
+
+    /*
+     * Clear the bit from the register flags.
+     */
+    workLine->monitorEntries[regIdx] &= ~(1 << workLine->monitorStackTop);
+}
+
+
+/*
+ * ===========================================================================
+ *      Entry point and driver loop
+ * ===========================================================================
+ */
+
+/*
+ * One-time preparation.
+ */
+static void verifyPrep()
+{
+#ifndef NDEBUG
+    /* only need to do this if the table was updated */
+    checkMergeTab();
+#endif
+}
+
+/*
+ * Entry point for the detailed code-flow analysis of a single method.
+ */
+bool dvmVerifyCodeFlow(VerifierData* vdata)
+{
+    bool result = false;
+    const Method* meth = vdata->method;
+    const int insnsSize = vdata->insnsSize;
+    const bool generateRegisterMap = gDvm.generateRegisterMaps;
+    RegisterTable regTable;
+
+    memset(&regTable, 0, sizeof(regTable));
+
+#ifdef VERIFIER_STATS
+    gDvm.verifierStats.methodsExamined++;
+    if (vdata->monitorEnterCount)
+        gDvm.verifierStats.monEnterMethods++;
+#endif
+
+    /* TODO: move this elsewhere -- we don't need to do this for every method */
+    verifyPrep();
+
+    if (meth->registersSize * insnsSize > 4*1024*1024) {
+        LOG_VFY_METH(meth,
+            "VFY: warning: method is huge (regs=%d insnsSize=%d)",
+            meth->registersSize, insnsSize);
+        /* might be bogus data, might be some huge generated method */
+    }
+
+    /*
+     * Create register lists, and initialize them to "Unknown".  If we're
+     * also going to create the register map, we need to retain the
+     * register lists for a larger set of addresses.
+     */
+    if (!initRegisterTable(vdata, &regTable,
+            generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
+        goto bail;
+
+    vdata->registerLines = regTable.registerLines;
+
+    /*
+     * Perform liveness analysis.
+     *
+     * We can do this before or after the main verifier pass.  The choice
+     * affects whether or not we see the effects of verifier instruction
+     * changes, i.e. substitution of throw-verification-error.
+     *
+     * In practice the ordering doesn't really matter, because T-V-E
+     * just prunes "can continue", creating regions of dead code (with
+     * corresponding register map data that will never be used).
+     */
+    if (generateRegisterMap &&
+        gDvm.registerMapMode == kRegisterMapModeLivePrecise)
+    {
+        /*
+         * Compute basic blocks and predecessor lists.
+         */
+        if (!dvmComputeVfyBasicBlocks(vdata))
+            goto bail;
+
+        /*
+         * Compute liveness.
+         */
+        if (!dvmComputeLiveness(vdata))
+            goto bail;
+    }
+
+    /*
+     * Initialize the types of the registers that correspond to the
+     * method arguments.  We can determine this from the method signature.
+     */
+    if (!setTypesFromSignature(meth, regTable.registerLines[0].regTypes,
+            vdata->uninitMap))
+        goto bail;
+
+    /*
+     * Run the verifier.
+     */
+    if (!doCodeVerification(vdata, &regTable))
+        goto bail;
+
+    /*
+     * Generate a register map.
+     */
+    if (generateRegisterMap) {
+        RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
+        if (pMap != NULL) {
+            /*
+             * Tuck it into the Method struct.  It will either get used
+             * directly or, if we're in dexopt, will be packed up and
+             * appended to the DEX file.
+             */
+            dvmSetRegisterMap((Method*)meth, pMap);
+        }
+    }
+
+    /*
+     * Success.
+     */
+    result = true;
+
+bail:
+    freeRegisterLineInnards(vdata);
+    free(regTable.registerLines);
+    free(regTable.lineAlloc);
+    return result;
+}
+
+/*
+ * Grind through the instructions.
+ *
+ * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
+ * on the first instruction, process it (setting additional "changed" bits),
+ * and repeat until there are no more.
+ *
+ * v3 4.11.1.1
+ * - (N/A) operand stack is always the same size
+ * - operand stack [registers] contain the correct types of values
+ * - local variables [registers] contain the correct types of values
+ * - methods are invoked with the appropriate arguments
+ * - fields are assigned using values of appropriate types
+ * - opcodes have the correct type values in operand registers
+ * - there is never an uninitialized class instance in a local variable in
+ *   code protected by an exception handler (operand stack is okay, because
+ *   the operand stack is discarded when an exception is thrown) [can't
+ *   know what's a local var w/o the debug info -- should fall out of
+ *   register typing]
+ *
+ * v3 4.11.1.2
+ * - execution cannot fall off the end of the code
+ *
+ * (We also do many of the items described in the "static checks" sections,
+ * because it's easier to do them here.)
+ *
+ * We need an array of RegType values, one per register, for every
+ * instruction.  If the method uses monitor-enter, we need extra data
+ * for every register, and a stack for every "interesting" instruction.
+ * In theory this could become quite large -- up to several megabytes for
+ * a monster function.
+ *
+ * NOTE:
+ * The spec forbids backward branches when there's an uninitialized reference
+ * in a register.  The idea is to prevent something like this:
+ *   loop:
+ *     move r1, r0
+ *     new-instance r0, MyClass
+ *     ...
+ *     if-eq rN, loop  // once
+ *   initialize r0
+ *
+ * This leaves us with two different instances, both allocated by the
+ * same instruction, but only one is initialized.  The scheme outlined in
+ * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
+ * backward branches.  We achieve identical results without restricting
+ * code reordering by specifying that you can't execute the new-instance
+ * instruction if a register contains an uninitialized instance created
+ * by that same instrutcion.
+ */
+static bool doCodeVerification(VerifierData* vdata, RegisterTable* regTable)
+{
+    const Method* meth = vdata->method;
+    InsnFlags* insnFlags = vdata->insnFlags;
+    UninitInstanceMap* uninitMap = vdata->uninitMap;
+    const int insnsSize = dvmGetMethodInsnsSize(meth);
+    bool result = false;
+    bool debugVerbose = false;
+    int insnIdx, startGuess;
+
+    /*
+     * Begin by marking the first instruction as "changed".
+     */
+    dvmInsnSetChanged(insnFlags, 0, true);
+
+    if (dvmWantVerboseVerification(meth)) {
+        IF_LOGI() {
+            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+            LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)",
+                meth->clazz->descriptor, meth->name, desc,
+                meth->insSize, meth->registersSize);
+            LOGI(" ------ [0    4    8    12   16   20   24   28   32   36");
+            free(desc);
+        }
+        debugVerbose = true;
+        gDebugVerbose = true;
+    } else {
+        gDebugVerbose = false;
+    }
+
+    startGuess = 0;
+
+    /*
+     * Continue until no instructions are marked "changed".
+     */
+    while (true) {
+        /*
+         * Find the first marked one.  Use "startGuess" as a way to find
+         * one quickly.
+         */
+        for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
+            if (dvmInsnIsChanged(insnFlags, insnIdx))
+                break;
+        }
+
+        if (insnIdx == insnsSize) {
+            if (startGuess != 0) {
+                /* try again, starting from the top */
+                startGuess = 0;
+                continue;
+            } else {
+                /* all flags are clear */
+                break;
+            }
+        }
+
+        /*
+         * We carry the working set of registers from instruction to
+         * instruction.  If this address can be the target of a branch
+         * (or throw) instruction, or if we're skipping around chasing
+         * "changed" flags, we need to load the set of registers from
+         * the table.
+         *
+         * Because we always prefer to continue on to the next instruction,
+         * we should never have a situation where we have a stray
+         * "changed" flag set on an instruction that isn't a branch target.
+         */
+        if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
+            RegisterLine* workLine = &regTable->workLine;
+
+            copyLineFromTable(workLine, regTable, insnIdx);
+        } else {
+#ifndef NDEBUG
+            /*
+             * Sanity check: retrieve the stored register line (assuming
+             * a full table) and make sure it actually matches.
+             */
+            RegisterLine* registerLine = getRegisterLine(regTable, insnIdx);
+            if (registerLine->regTypes != NULL &&
+                compareLineToTable(regTable, insnIdx, &regTable->workLine) != 0)
+            {
+                char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+                LOG_VFY("HUH? workLine diverged in %s.%s %s",
+                        meth->clazz->descriptor, meth->name, desc);
+                free(desc);
+                dumpRegTypes(vdata, registerLine, 0, "work",
+                    uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
+                dumpRegTypes(vdata, registerLine, 0, "insn",
+                    uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
+            }
+#endif
+        }
+        if (debugVerbose) {
+            dumpRegTypes(vdata, &regTable->workLine, insnIdx,
+                NULL, uninitMap, SHOW_REG_DETAILS);
+        }
+
+        //LOGI("process %s.%s %s %d",
+        //    meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
+        if (!verifyInstruction(meth, insnFlags, regTable, insnIdx,
+                uninitMap, &startGuess))
+        {
+            //LOGD("+++ %s bailing at %d", meth->name, insnIdx);
+            goto bail;
+        }
+
+        /*
+         * Clear "changed" and mark as visited.
+         */
+        dvmInsnSetVisited(insnFlags, insnIdx, true);
+        dvmInsnSetChanged(insnFlags, insnIdx, false);
+    }
+
+    if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
+        /*
+         * 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 substituted "always throw" instructions into the stream,
+         * we are almost certainly going to have some dead code.
+         */
+        int deadStart = -1;
+        for (insnIdx = 0; insnIdx < insnsSize;
+            insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
+        {
+            /*
+             * Switch-statement data doesn't get "visited" by scanner.  It
+             * may or may not be preceded by a padding NOP (for alignment).
+             */
+            int instr = meth->insns[insnIdx];
+            if (instr == kPackedSwitchSignature ||
+                instr == kSparseSwitchSignature ||
+                instr == kArrayDataSignature ||
+                (instr == OP_NOP &&
+                 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
+                  meth->insns[insnIdx+1] == kSparseSwitchSignature ||
+                  meth->insns[insnIdx+1] == kArrayDataSignature)))
+            {
+                dvmInsnSetVisited(insnFlags, insnIdx, true);
+            }
+
+            if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
+                if (deadStart < 0)
+                    deadStart = insnIdx;
+            } else if (deadStart >= 0) {
+                IF_LOGD() {
+                    char* desc =
+                        dexProtoCopyMethodDescriptor(&meth->prototype);
+                    LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s",
+                        deadStart, insnIdx-1,
+                        meth->clazz->descriptor, meth->name, desc);
+                    free(desc);
+                }
+
+                deadStart = -1;
+            }
+        }
+        if (deadStart >= 0) {
+            IF_LOGD() {
+                char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+                LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s",
+                    deadStart, insnIdx-1,
+                    meth->clazz->descriptor, meth->name, desc);
+                free(desc);
+            }
+        }
+    }
+
+    result = true;
+
+bail:
+    return result;
+}
+
+
+/*
+ * Perform verification for a single instruction.
+ *
+ * This requires fully decoding the instruction to determine the effect
+ * it has on registers.
+ *
+ * Finds zero or more following instructions and sets the "changed" flag
+ * 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,
+    RegisterTable* regTable, int insnIdx, UninitInstanceMap* uninitMap,
+    int* pStartGuess)
+{
+    const int insnsSize = dvmGetMethodInsnsSize(meth);
+    const u2* insns = meth->insns + insnIdx;
+    bool result = false;
+
+#ifdef VERIFIER_STATS
+    if (dvmInsnIsVisited(insnFlags, insnIdx)) {
+        gDvm.verifierStats.instrsReexamined++;
+    } else {
+        gDvm.verifierStats.instrsExamined++;
+    }
+#endif
+
+    /*
+     * Once we finish decoding the instruction, we need to figure out where
+     * we can go from here.  There are three possible ways to transfer
+     * control to another statement:
+     *
+     * (1) Continue to the next instruction.  Applies to all but
+     *     unconditional branches, method returns, and exception throws.
+     * (2) Branch to one or more possible locations.  Applies to branches
+     *     and switch statements.
+     * (3) Exception handlers.  Applies to any instruction that can
+     *     throw an exception that is handled by an encompassing "try"
+     *     block.
+     *
+     * We can also return, in which case there is no successor instruction
+     * from this point.
+     *
+     * The behavior can be determined from the OpcodeFlags.
+     */
+
+    RegisterLine* workLine = &regTable->workLine;
+    const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+    ClassObject* resClass;
+    s4 branchTarget = 0;
+    const int insnRegCount = meth->registersSize;
+    RegType tmpType;
+    DecodedInstruction decInsn;
+    bool justSetResult = false;
+    VerifyError failure = VERIFY_ERROR_NONE;
+
+#ifndef NDEBUG
+    memset(&decInsn, 0x81, sizeof(decInsn));
+#endif
+    dexDecodeInstruction(insns, &decInsn);
+
+    int nextFlags = dexGetFlagsFromOpcode(decInsn.opcode);
+
+    /*
+     * Make a copy of the previous register state.  If the instruction
+     * can throw an exception, we will copy/merge this into the "catch"
+     * address rather than workLine, because we don't want the result
+     * from the "successful" code path (e.g. a check-cast that "improves"
+     * a type) to be visible to the exception handler.
+     */
+    if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
+    {
+        copyRegisterLine(&regTable->savedLine, workLine,
+            regTable->insnRegCountPlus);
+    } else {
+#ifndef NDEBUG
+        memset(regTable->savedLine.regTypes, 0xdd,
+            regTable->insnRegCountPlus * sizeof(RegType));
+#endif
+    }
+
+    switch (decInsn.opcode) {
+    case OP_NOP:
+        /*
+         * A "pure" NOP has no effect on anything.  Data tables start with
+         * a signature that looks like a NOP; if we see one of these in
+         * the course of executing code then we have a problem.
+         */
+        if (decInsn.vA != 0) {
+            LOG_VFY("VFY: encountered data table in instruction stream");
+            failure = VERIFY_ERROR_GENERIC;
+        }
+        break;
+
+    case OP_MOVE:
+    case OP_MOVE_FROM16:
+    case OP_MOVE_16:
+        copyRegister1(workLine, decInsn.vA, decInsn.vB, kTypeCategory1nr,
+            &failure);
+        break;
+    case OP_MOVE_WIDE:
+    case OP_MOVE_WIDE_FROM16:
+    case OP_MOVE_WIDE_16:
+        copyRegister2(workLine, decInsn.vA, decInsn.vB, &failure);
+        break;
+    case OP_MOVE_OBJECT:
+    case OP_MOVE_OBJECT_FROM16:
+    case OP_MOVE_OBJECT_16:
+        copyRegister1(workLine, decInsn.vA, decInsn.vB, kTypeCategoryRef,
+            &failure);
+        break;
+
+    /*
+     * The move-result instructions copy data out of a "pseudo-register"
+     * with the results from the last method invocation.  In practice we
+     * might want to hold the result in an actual CPU register, so the
+     * Dalvik spec requires that these only appear immediately after an
+     * invoke or filled-new-array.
+     *
+     * These calls invalidate the "result" register.  (This is now
+     * redundant with the reset done below, but it can make the debug info
+     * easier to read in some cases.)
+     */
+    case OP_MOVE_RESULT:
+        copyResultRegister1(workLine, insnRegCount, decInsn.vA,
+            kTypeCategory1nr, &failure);
+        break;
+    case OP_MOVE_RESULT_WIDE:
+        copyResultRegister2(workLine, insnRegCount, decInsn.vA, &failure);
+        break;
+    case OP_MOVE_RESULT_OBJECT:
+        copyResultRegister1(workLine, insnRegCount, decInsn.vA,
+            kTypeCategoryRef, &failure);
+        break;
+
+    case OP_MOVE_EXCEPTION:
+        /*
+         * This statement can only appear as the first instruction in an
+         * exception handler (though not all exception handlers need to
+         * have one of these).  We verify that as part of extracting the
+         * exception type from the catch block list.
+         *
+         * "resClass" will hold the closest common superclass of all
+         * exceptions that can be handled here.
+         */
+        resClass = getCaughtExceptionType(meth, insnIdx, &failure);
+        if (resClass == NULL) {
+            assert(!VERIFY_OK(failure));
+        } else {
+            setRegisterType(workLine, decInsn.vA, regTypeFromClass(resClass));
+        }
+        break;
+
+    case OP_RETURN_VOID:
+        if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
+            failure = VERIFY_ERROR_GENERIC;
+        } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
+            LOG_VFY("VFY: return-void not expected");
+            failure = VERIFY_ERROR_GENERIC;
+        }
+        break;
+    case OP_RETURN:
+        if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
+            failure = VERIFY_ERROR_GENERIC;
+        } else {
+            /* check the method signature */
+            RegType returnType = getMethodReturnType(meth);
+            checkTypeCategory(returnType, kTypeCategory1nr, &failure);
+            if (!VERIFY_OK(failure))
+                LOG_VFY("VFY: return-1nr not expected");
+
+            /*
+             * javac generates synthetic functions that write byte values
+             * into boolean fields. Also, it may use integer values for
+             * boolean, byte, short, and character return types.
+             */
+            RegType srcType = getRegisterType(workLine, decInsn.vA);
+            if ((returnType == kRegTypeBoolean && srcType == kRegTypeByte) ||
+                ((returnType == kRegTypeBoolean || returnType == kRegTypeByte ||
+                  returnType == kRegTypeShort || returnType == kRegTypeChar) &&
+                 srcType == kRegTypeInteger))
+                returnType = srcType;
+
+            /* check the register contents */
+            verifyRegisterType(workLine, decInsn.vA, returnType, &failure);
+            if (!VERIFY_OK(failure)) {
+                LOG_VFY("VFY: return-1nr on invalid register v%d",
+                    decInsn.vA);
+            }
+        }
+        break;
+    case OP_RETURN_WIDE:
+        if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
+            failure = VERIFY_ERROR_GENERIC;
+        } else {
+            RegType returnType;
+
+            /* check the method signature */
+            returnType = getMethodReturnType(meth);
+            checkTypeCategory(returnType, kTypeCategory2, &failure);
+            if (!VERIFY_OK(failure))
+                LOG_VFY("VFY: return-wide not expected");
+
+            /* check the register contents */
+            verifyRegisterType(workLine, decInsn.vA, returnType, &failure);
+            if (!VERIFY_OK(failure)) {
+                LOG_VFY("VFY: return-wide on invalid register pair v%d",
+                    decInsn.vA);
+            }
+        }
+        break;
+    case OP_RETURN_OBJECT:
+        if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
+            failure = VERIFY_ERROR_GENERIC;
+        } else {
+            RegType returnType = getMethodReturnType(meth);
+            checkTypeCategory(returnType, kTypeCategoryRef, &failure);
+            if (!VERIFY_OK(failure)) {
+                LOG_VFY("VFY: return-object not expected");
+                break;
+            }
+
+            /* returnType is the *expected* return type, not register value */
+            assert(returnType != kRegTypeZero);
+            assert(!regTypeIsUninitReference(returnType));
+
+            /*
+             * Verify that the reference in vAA is an instance of the type
+             * in "returnType".  The Zero type is allowed here.  If the
+             * method is declared to return an interface, then any
+             * initialized reference is acceptable.
+             *
+             * Note getClassFromRegister fails if the register holds an
+             * uninitialized reference, so we do not allow them to be
+             * returned.
+             */
+            ClassObject* declClass;
+
+            declClass = regTypeInitializedReferenceToClass(returnType);
+            resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            if (resClass != NULL) {
+                if (!dvmIsInterfaceClass(declClass) &&
+                    !dvmInstanceof(resClass, declClass))
+                {
+                    LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)",
+                            resClass->descriptor, resClass->classLoader,
+                            declClass->descriptor, declClass->classLoader);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case OP_CONST_4:
+    case OP_CONST_16:
+    case OP_CONST:
+        /* could be boolean, int, float, or a null reference */
+        setRegisterType(workLine, decInsn.vA,
+            determineCat1Const((s4)decInsn.vB));
+        break;
+    case OP_CONST_HIGH16:
+        /* could be boolean, int, float, or a null reference */
+        setRegisterType(workLine, decInsn.vA,
+            determineCat1Const((s4) decInsn.vB << 16));
+        break;
+    case OP_CONST_WIDE_16:
+    case OP_CONST_WIDE_32:
+    case OP_CONST_WIDE:
+    case OP_CONST_WIDE_HIGH16:
+        /* could be long or double; resolved upon use */
+        setRegisterType(workLine, decInsn.vA, kRegTypeConstLo);
+        break;
+    case OP_CONST_STRING:
+    case OP_CONST_STRING_JUMBO:
+        assert(gDvm.classJavaLangString != NULL);
+        setRegisterType(workLine, decInsn.vA,
+            regTypeFromClass(gDvm.classJavaLangString));
+        break;
+    case OP_CONST_CLASS:
+    case OP_CONST_CLASS_JUMBO:
+        assert(gDvm.classJavaLangClass != NULL);
+        /* make sure we can resolve the class; access check is important */
+        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",
+                decInsn.vB, badClassDesc, meth->clazz->descriptor);
+            assert(failure != VERIFY_ERROR_GENERIC);
+        } else {
+            setRegisterType(workLine, decInsn.vA,
+                regTypeFromClass(gDvm.classJavaLangClass));
+        }
+        break;
+
+    case OP_MONITOR_ENTER:
+        handleMonitorEnter(workLine, decInsn.vA, insnIdx, &failure);
+        break;
+    case OP_MONITOR_EXIT:
+        /*
+         * monitor-exit instructions are odd.  They can throw exceptions,
+         * but when they do they act as if they succeeded and the PC is
+         * pointing to the following instruction.  (This behavior goes back
+         * to the need to handle asynchronous exceptions, a now-deprecated
+         * feature that Dalvik doesn't support.)
+         *
+         * In practice we don't need to worry about this.  The only
+         * exceptions that can be thrown from monitor-exit are for a
+         * null reference and -exit without a matching -enter.  If the
+         * structured locking checks are working, the former would have
+         * failed on the -enter instruction, and the latter is impossible.
+         *
+         * This is fortunate, because issue 3221411 prevents us from
+         * chasing the "can throw" path when monitor verification is
+         * enabled.  If we can fully verify the locking we can ignore
+         * some catch blocks (which will show up as "dead" code when
+         * we skip them here); if we can't, then the code path could be
+         * "live" so we still need to check it.
+         */
+        if (workLine->monitorEntries != NULL)
+            nextFlags &= ~kInstrCanThrow;
+        handleMonitorExit(workLine, decInsn.vA, insnIdx, &failure);
+        break;
+
+    case OP_CHECK_CAST:
+    case OP_CHECK_CAST_JUMBO:
+        /*
+         * If this instruction succeeds, we will promote register vA to
+         * the type in vB.  (This could be a demotion -- not expected, so
+         * we don't try to address it.)
+         *
+         * 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, &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",
+                decInsn.vB, badClassDesc, meth->clazz->descriptor);
+            assert(failure != VERIFY_ERROR_GENERIC);
+        } else {
+            RegType origType;
+
+            origType = getRegisterType(workLine, decInsn.vA);
+            if (!regTypeIsReference(origType)) {
+                LOG_VFY("VFY: check-cast on non-reference in v%u",decInsn.vA);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            setRegisterType(workLine, decInsn.vA, regTypeFromClass(resClass));
+        }
+        break;
+    case OP_INSTANCE_OF:
+    case OP_INSTANCE_OF_JUMBO:
+        /* make sure we're checking a reference type */
+        tmpType = getRegisterType(workLine, decInsn.vB);
+        if (!regTypeIsReference(tmpType)) {
+            LOG_VFY("VFY: vB not a reference (%d)", tmpType);
+            failure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+
+        /* make sure we can resolve the class; access check is important */
+        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",
+                decInsn.vC, badClassDesc, meth->clazz->descriptor);
+            assert(failure != VERIFY_ERROR_GENERIC);
+        } else {
+            /* result is boolean */
+            setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
+        }
+        break;
+
+    case OP_ARRAY_LENGTH:
+        resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+        if (resClass != NULL && !dvmIsArrayClass(resClass)) {
+            LOG_VFY("VFY: array-length on non-array");
+            failure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        setRegisterType(workLine, decInsn.vA, kRegTypeInteger);
+        break;
+
+    case OP_NEW_INSTANCE:
+    case OP_NEW_INSTANCE_JUMBO:
+        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",
+                decInsn.vB, badClassDesc, meth->clazz->descriptor);
+            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",
+                    resClass->descriptor);
+                failure = VERIFY_ERROR_INSTANTIATION;
+                break;
+            }
+
+            /* add resolved class to uninit map if not already there */
+            int uidx = setUninitInstance(uninitMap, insnIdx, resClass);
+            assert(uidx >= 0);
+            uninitType = regTypeFromUninitIndex(uidx);
+
+            /*
+             * Any registers holding previous allocations from this address
+             * that have not yet been initialized must be marked invalid.
+             */
+            markUninitRefsAsInvalid(workLine, insnRegCount, uninitMap,
+                uninitType);
+
+            /* add the new uninitialized reference to the register ste */
+            setRegisterType(workLine, decInsn.vA, uninitType);
+        }
+        break;
+    case OP_NEW_ARRAY:
+    case OP_NEW_ARRAY_JUMBO:
+        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",
+                decInsn.vC, badClassDesc, meth->clazz->descriptor);
+            assert(failure != VERIFY_ERROR_GENERIC);
+        } else if (!dvmIsArrayClass(resClass)) {
+            LOG_VFY("VFY: new-array on non-array class");
+            failure = VERIFY_ERROR_GENERIC;
+        } else {
+            /* make sure "size" register is valid type */
+            verifyRegisterType(workLine, decInsn.vB, kRegTypeInteger, &failure);
+            /* set register type to array class */
+            setRegisterType(workLine, decInsn.vA, regTypeFromClass(resClass));
+        }
+        break;
+    case OP_FILLED_NEW_ARRAY:
+    case OP_FILLED_NEW_ARRAY_RANGE:
+    case OP_FILLED_NEW_ARRAY_JUMBO:
+        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",
+                decInsn.vB, badClassDesc, meth->clazz->descriptor);
+            assert(failure != VERIFY_ERROR_GENERIC);
+        } else if (!dvmIsArrayClass(resClass)) {
+            LOG_VFY("VFY: filled-new-array on non-array class");
+            failure = VERIFY_ERROR_GENERIC;
+        } else {
+            bool isRange = (decInsn.opcode == OP_FILLED_NEW_ARRAY_RANGE ||
+                            decInsn.opcode == OP_FILLED_NEW_ARRAY_JUMBO);
+
+            /* check the arguments to the instruction */
+            verifyFilledNewArrayRegs(meth, workLine, &decInsn,
+                resClass, isRange, &failure);
+            /* filled-array result goes into "result" register */
+            setResultRegisterType(workLine, insnRegCount,
+                regTypeFromClass(resClass));
+            justSetResult = true;
+        }
+        break;
+
+    case OP_CMPL_FLOAT:
+    case OP_CMPG_FLOAT:
+        verifyRegisterType(workLine, decInsn.vB, kRegTypeFloat, &failure);
+        verifyRegisterType(workLine, decInsn.vC, kRegTypeFloat, &failure);
+        setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
+        break;
+    case OP_CMPL_DOUBLE:
+    case OP_CMPG_DOUBLE:
+        verifyRegisterType(workLine, decInsn.vB, kRegTypeDoubleLo, &failure);
+        verifyRegisterType(workLine, decInsn.vC, kRegTypeDoubleLo, &failure);
+        setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
+        break;
+    case OP_CMP_LONG:
+        verifyRegisterType(workLine, decInsn.vB, kRegTypeLongLo, &failure);
+        verifyRegisterType(workLine, decInsn.vC, kRegTypeLongLo, &failure);
+        setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
+        break;
+
+    case OP_THROW:
+        resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
+        if (VERIFY_OK(failure) && resClass != NULL) {
+            if (!dvmInstanceof(resClass, gDvm.exThrowable)) {
+                LOG_VFY("VFY: thrown class %s not instanceof Throwable",
+                        resClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+            }
+        }
+        break;
+
+    case OP_GOTO:
+    case OP_GOTO_16:
+    case OP_GOTO_32:
+        /* no effect on or use of registers */
+        break;
+
+    case OP_PACKED_SWITCH:
+    case OP_SPARSE_SWITCH:
+        /* verify that vAA is an integer, or can be converted to one */
+        verifyRegisterType(workLine, decInsn.vA, kRegTypeInteger, &failure);
+        break;
+
+    case OP_FILL_ARRAY_DATA:
+        {
+            RegType valueType;
+            const u2 *arrayData;
+            u2 elemWidth;
+
+            /* Similar to the verification done for APUT */
+            resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /* resClass can be null if the reg type is Zero */
+            if (resClass == NULL)
+                break;
+
+            if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
+                resClass->elementClass->primitiveType == PRIM_NOT ||
+                resClass->elementClass->primitiveType == PRIM_VOID)
+            {
+                LOG_VFY("VFY: invalid fill-array-data on %s",
+                        resClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            valueType = primitiveTypeToRegType(
+                                    resClass->elementClass->primitiveType);
+            assert(valueType != kRegTypeUnknown);
+
+            /*
+             * Now verify if the element width in the table matches the element
+             * width declared in the array
+             */
+            arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
+            if (arrayData[0] != kArrayDataSignature) {
+                LOG_VFY("VFY: invalid magic for array-data");
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            switch (resClass->elementClass->primitiveType) {
+                case PRIM_BOOLEAN:
+                case PRIM_BYTE:
+                     elemWidth = 1;
+                     break;
+                case PRIM_CHAR:
+                case PRIM_SHORT:
+                     elemWidth = 2;
+                     break;
+                case PRIM_FLOAT:
+                case PRIM_INT:
+                     elemWidth = 4;
+                     break;
+                case PRIM_DOUBLE:
+                case PRIM_LONG:
+                     elemWidth = 8;
+                     break;
+                default:
+                     elemWidth = 0;
+                     break;
+            }
+
+            /*
+             * Since we don't compress the data in Dex, expect to see equal
+             * width of data stored in the table and expected from the array
+             * class.
+             */
+            if (arrayData[1] != elemWidth) {
+                LOG_VFY("VFY: array-data size mismatch (%d vs %d)",
+                        arrayData[1], elemWidth);
+                failure = VERIFY_ERROR_GENERIC;
+            }
+        }
+        break;
+
+    case OP_IF_EQ:
+    case OP_IF_NE:
+        {
+            RegType type1, type2;
+
+            type1 = getRegisterType(workLine, decInsn.vA);
+            type2 = getRegisterType(workLine, decInsn.vB);
+
+            /* both references? */
+            if (regTypeIsReference(type1) && regTypeIsReference(type2))
+                break;
+
+            /* both category-1nr? */
+            checkTypeCategory(type1, kTypeCategory1nr, &failure);
+            checkTypeCategory(type2, kTypeCategory1nr, &failure);
+            if (type1 == kRegTypeFloat || type2 == kRegTypeFloat) {
+              failure = VERIFY_ERROR_GENERIC;
+            }
+            if (!VERIFY_OK(failure)) {
+                LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1");
+                break;
+            }
+        }
+        break;
+    case OP_IF_LT:
+    case OP_IF_GE:
+    case OP_IF_GT:
+    case OP_IF_LE:
+        tmpType = getRegisterType(workLine, decInsn.vA);
+        checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+        if (tmpType == kRegTypeFloat) {
+          failure = VERIFY_ERROR_GENERIC;
+        }
+        if (!VERIFY_OK(failure)) {
+            LOG_VFY("VFY: args to 'if' must be cat-1nr and not float");
+            break;
+        }
+        tmpType = getRegisterType(workLine, decInsn.vB);
+        checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+        if (tmpType == kRegTypeFloat) {
+          failure = VERIFY_ERROR_GENERIC;
+        }
+        if (!VERIFY_OK(failure)) {
+            LOG_VFY("VFY: args to 'if' must be cat-1nr and not float");
+            break;
+        }
+        break;
+    case OP_IF_EQZ:
+    case OP_IF_NEZ:
+        tmpType = getRegisterType(workLine, decInsn.vA);
+        if (regTypeIsReference(tmpType))
+            break;
+        checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+        if (tmpType == kRegTypeFloat) {
+          failure = VERIFY_ERROR_GENERIC;
+        }
+        if (!VERIFY_OK(failure))
+            LOG_VFY("VFY: expected non-float cat-1 arg to if");
+        break;
+    case OP_IF_LTZ:
+    case OP_IF_GEZ:
+    case OP_IF_GTZ:
+    case OP_IF_LEZ:
+        tmpType = getRegisterType(workLine, decInsn.vA);
+        checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+        if (tmpType == kRegTypeFloat) {
+          failure = VERIFY_ERROR_GENERIC;
+        }
+        if (!VERIFY_OK(failure))
+            LOG_VFY("VFY: expected non-float cat-1 arg to if");
+        break;
+
+    case OP_AGET:
+        tmpType = kRegTypeInteger;
+        goto aget_1nr_common;
+    case OP_AGET_BOOLEAN:
+        tmpType = kRegTypeBoolean;
+        goto aget_1nr_common;
+    case OP_AGET_BYTE:
+        tmpType = kRegTypeByte;
+        goto aget_1nr_common;
+    case OP_AGET_CHAR:
+        tmpType = kRegTypeChar;
+        goto aget_1nr_common;
+    case OP_AGET_SHORT:
+        tmpType = kRegTypeShort;
+        goto aget_1nr_common;
+aget_1nr_common:
+        {
+            RegType srcType, indexType;
+
+            indexType = getRegisterType(workLine, decInsn.vC);
+            checkArrayIndexType(meth, indexType, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            if (resClass != NULL) {
+                /* verify the class */
+                if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
+                    resClass->elementClass->primitiveType == PRIM_NOT)
+                {
+                    LOG_VFY("VFY: invalid aget-1nr target %s",
+                        resClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                /* make sure array type matches instruction */
+                srcType = primitiveTypeToRegType(
+                                        resClass->elementClass->primitiveType);
+
+                /* correct if float */
+                if (srcType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                    tmpType = kRegTypeFloat;
+
+                if (!checkFieldArrayStore1nr(tmpType, srcType)) {
+                    LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
+                            " inst type=%d (on %s)",
+                        srcType, tmpType, resClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+            }
+            setRegisterType(workLine, decInsn.vA, tmpType);
+        }
+        break;
+
+    case OP_AGET_WIDE:
+        {
+            RegType dstType, indexType;
+
+            indexType = getRegisterType(workLine, decInsn.vC);
+            checkArrayIndexType(meth, indexType, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            if (resClass != NULL) {
+                /* verify the class */
+                if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
+                    resClass->elementClass->primitiveType == PRIM_NOT)
+                {
+                    LOG_VFY("VFY: invalid aget-wide target %s",
+                        resClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                /* try to refine "dstType" */
+                switch (resClass->elementClass->primitiveType) {
+                case PRIM_LONG:
+                    dstType = kRegTypeLongLo;
+                    break;
+                case PRIM_DOUBLE:
+                    dstType = kRegTypeDoubleLo;
+                    break;
+                default:
+                    LOG_VFY("VFY: invalid aget-wide on %s",
+                        resClass->descriptor);
+                    dstType = kRegTypeUnknown;
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+            } else {
+                /*
+                 * Null array ref; this code path will fail at runtime.  We
+                 * know this is either long or double, so label it const.
+                 */
+                dstType = kRegTypeConstLo;
+            }
+            setRegisterType(workLine, decInsn.vA, dstType);
+        }
+        break;
+
+    case OP_AGET_OBJECT:
+        {
+            RegType dstType, indexType;
+
+            indexType = getRegisterType(workLine, decInsn.vC);
+            checkArrayIndexType(meth, indexType, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /* get the class of the array we're pulling an object from */
+            resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            if (resClass != NULL) {
+                ClassObject* elementClass;
+
+                assert(resClass != NULL);
+                if (!dvmIsArrayClass(resClass)) {
+                    LOG_VFY("VFY: aget-object on non-array class");
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+                assert(resClass->elementClass != NULL);
+
+                /*
+                 * Find the element class.  resClass->elementClass indicates
+                 * the basic type, which won't be what we want for a
+                 * multi-dimensional array.
+                 */
+                if (resClass->descriptor[1] == '[') {
+                    assert(resClass->arrayDim > 1);
+                    elementClass = dvmFindArrayClass(&resClass->descriptor[1],
+                                        resClass->classLoader);
+                } else if (resClass->descriptor[1] == 'L') {
+                    assert(resClass->arrayDim == 1);
+                    elementClass = resClass->elementClass;
+                } else {
+                    LOG_VFY("VFY: aget-object on non-ref array class (%s)",
+                        resClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                dstType = regTypeFromClass(elementClass);
+            } else {
+                /*
+                 * The array reference is NULL, so the current code path will
+                 * throw an exception.  For proper merging with later code
+                 * paths, and correct handling of "if-eqz" tests on the
+                 * result of the array get, we want to treat this as a null
+                 * reference.
+                 */
+                dstType = kRegTypeZero;
+            }
+            setRegisterType(workLine, decInsn.vA, dstType);
+        }
+        break;
+    case OP_APUT:
+        tmpType = kRegTypeInteger;
+        goto aput_1nr_common;
+    case OP_APUT_BOOLEAN:
+        tmpType = kRegTypeBoolean;
+        goto aput_1nr_common;
+    case OP_APUT_BYTE:
+        tmpType = kRegTypeByte;
+        goto aput_1nr_common;
+    case OP_APUT_CHAR:
+        tmpType = kRegTypeChar;
+        goto aput_1nr_common;
+    case OP_APUT_SHORT:
+        tmpType = kRegTypeShort;
+        goto aput_1nr_common;
+aput_1nr_common:
+        {
+            RegType srcType, dstType, indexType;
+
+            indexType = getRegisterType(workLine, decInsn.vC);
+            checkArrayIndexType(meth, indexType, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            srcType = getRegisterType(workLine, decInsn.vA);
+
+            /* correct if float */
+            if (srcType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                tmpType = kRegTypeFloat;
+
+            /* make sure the source register has the correct type */
+            if (!canConvertTo1nr(srcType, tmpType)) {
+                LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)",
+                    srcType, tmpType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /* resClass can be null if the reg type is Zero */
+            if (resClass == NULL)
+                break;
+
+            if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
+                resClass->elementClass->primitiveType == PRIM_NOT)
+            {
+                LOG_VFY("VFY: invalid aput-1nr on %s", resClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            /* verify that instruction matches array */
+            dstType = primitiveTypeToRegType(
+                                    resClass->elementClass->primitiveType);
+
+            /* correct if float */
+            if (dstType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                tmpType = kRegTypeFloat;
+
+            verifyRegisterType(workLine, decInsn.vA, dstType, &failure);
+
+            if (dstType == kRegTypeUnknown ||
+                !checkFieldArrayStore1nr(tmpType, dstType)) {
+                LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)",
+                        resClass->descriptor, tmpType, dstType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+        }
+        break;
+    case OP_APUT_WIDE:
+        tmpType = getRegisterType(workLine, decInsn.vC);
+        checkArrayIndexType(meth, tmpType, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+
+        resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+        if (resClass != NULL) {
+            /* verify the class and try to refine "dstType" */
+            if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
+                resClass->elementClass->primitiveType == PRIM_NOT)
+            {
+                LOG_VFY("VFY: invalid aput-wide on %s",
+                        resClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            switch (resClass->elementClass->primitiveType) {
+            case PRIM_LONG:
+                verifyRegisterType(workLine, decInsn.vA, kRegTypeLongLo, &failure);
+                break;
+            case PRIM_DOUBLE:
+                verifyRegisterType(workLine, decInsn.vA, kRegTypeDoubleLo, &failure);
+                break;
+            default:
+                LOG_VFY("VFY: invalid aput-wide on %s",
+                        resClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+        }
+        break;
+    case OP_APUT_OBJECT:
+        tmpType = getRegisterType(workLine, decInsn.vC);
+        checkArrayIndexType(meth, tmpType, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+
+        /* get the ref we're storing; Zero is okay, Uninit is not */
+        resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+        if (resClass != NULL) {
+            ClassObject* arrayClass;
+            ClassObject* elementClass;
+
+            /*
+             * Get the array class.  If the array ref is null, we won't
+             * have type information (and we'll crash at runtime with a
+             * null pointer exception).
+             */
+            arrayClass = getClassFromRegister(workLine, 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",
+                            arrayClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                /*
+                 * Find the element class.  resClass->elementClass indicates
+                 * the basic type, which won't be what we want for a
+                 * multi-dimensional array.
+                 *
+                 * All we want to check here is that the element type is a
+                 * reference class.  We *don't* check instanceof here, because
+                 * you can still put a String into a String[] after the latter
+                 * has been cast to an Object[].
+                 */
+                if (arrayClass->descriptor[1] == '[') {
+                    assert(arrayClass->arrayDim > 1);
+                    elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
+                                        arrayClass->classLoader);
+                } else {
+                    assert(arrayClass->arrayDim == 1);
+                    elementClass = arrayClass->elementClass;
+                }
+                if (elementClass->primitiveType != PRIM_NOT) {
+                    LOG_VFY("VFY: invalid aput-object of %s into %s",
+                            resClass->descriptor, arrayClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case OP_IGET:
+    case OP_IGET_JUMBO:
+        tmpType = kRegTypeInteger;
+        goto iget_1nr_common;
+    case OP_IGET_BOOLEAN:
+    case OP_IGET_BOOLEAN_JUMBO:
+        tmpType = kRegTypeBoolean;
+        goto iget_1nr_common;
+    case OP_IGET_BYTE:
+    case OP_IGET_BYTE_JUMBO:
+        tmpType = kRegTypeByte;
+        goto iget_1nr_common;
+    case OP_IGET_CHAR:
+    case OP_IGET_CHAR_JUMBO:
+        tmpType = kRegTypeChar;
+        goto iget_1nr_common;
+    case OP_IGET_SHORT:
+    case OP_IGET_SHORT_JUMBO:
+        tmpType = kRegTypeShort;
+        goto iget_1nr_common;
+iget_1nr_common:
+        {
+            InstField* instField;
+            RegType objType, fieldType;
+
+            objType = getRegisterType(workLine, decInsn.vB);
+            instField = getInstField(meth, uninitMap, objType, decInsn.vC,
+                            &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /* make sure the field's type is compatible with expectation */
+            fieldType = primSigCharToRegType(instField->signature[0]);
+
+            /* correct if float */
+            if (fieldType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                tmpType = kRegTypeFloat;
+
+            if (fieldType == kRegTypeUnknown ||
+                !checkFieldArrayStore1nr(tmpType, fieldType))
+            {
+                LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)",
+                        instField->clazz->descriptor,
+                        instField->name, tmpType, fieldType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            setRegisterType(workLine, decInsn.vA, tmpType);
+        }
+        break;
+    case OP_IGET_WIDE:
+    case OP_IGET_WIDE_JUMBO:
+        {
+            RegType dstType;
+            InstField* instField;
+            RegType objType;
+
+            objType = getRegisterType(workLine, decInsn.vB);
+            instField = getInstField(meth, uninitMap, objType, decInsn.vC,
+                            &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            /* check the type, which should be prim */
+            switch (instField->signature[0]) {
+            case 'D':
+                dstType = kRegTypeDoubleLo;
+                break;
+            case 'J':
+                dstType = kRegTypeLongLo;
+                break;
+            default:
+                LOG_VFY("VFY: invalid iget-wide of %s.%s",
+                        instField->clazz->descriptor,
+                        instField->name);
+                dstType = kRegTypeUnknown;
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            if (VERIFY_OK(failure)) {
+                setRegisterType(workLine, decInsn.vA, dstType);
+            }
+        }
+        break;
+    case OP_IGET_OBJECT:
+    case OP_IGET_OBJECT_JUMBO:
+        {
+            ClassObject* fieldClass;
+            InstField* instField;
+            RegType objType;
+
+            objType = getRegisterType(workLine, decInsn.vB);
+            instField = getInstField(meth, uninitMap, objType, decInsn.vC,
+                            &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            fieldClass = getFieldClass(meth, instField);
+            if (fieldClass == NULL) {
+                /* class not found or primitive type */
+                LOG_VFY("VFY: unable to recover field class from '%s'",
+                    instField->signature);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            if (VERIFY_OK(failure)) {
+                assert(!dvmIsPrimitiveClass(fieldClass));
+                setRegisterType(workLine, decInsn.vA,
+                    regTypeFromClass(fieldClass));
+            }
+        }
+        break;
+    case OP_IPUT:
+    case OP_IPUT_JUMBO:
+        tmpType = kRegTypeInteger;
+        goto iput_1nr_common;
+    case OP_IPUT_BOOLEAN:
+    case OP_IPUT_BOOLEAN_JUMBO:
+        tmpType = kRegTypeBoolean;
+        goto iput_1nr_common;
+    case OP_IPUT_BYTE:
+    case OP_IPUT_BYTE_JUMBO:
+        tmpType = kRegTypeByte;
+        goto iput_1nr_common;
+    case OP_IPUT_CHAR:
+    case OP_IPUT_CHAR_JUMBO:
+        tmpType = kRegTypeChar;
+        goto iput_1nr_common;
+    case OP_IPUT_SHORT:
+    case OP_IPUT_SHORT_JUMBO:
+        tmpType = kRegTypeShort;
+        goto iput_1nr_common;
+iput_1nr_common:
+        {
+            RegType srcType, fieldType, objType;
+            InstField* instField;
+
+            srcType = getRegisterType(workLine, decInsn.vA);
+
+            /*
+             * javac generates synthetic functions that write byte values
+             * into boolean fields.
+             */
+            if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
+                tmpType = kRegTypeByte;
+
+            /* correct if float */
+            if (srcType == kRegTypeFloat && tmpType == kRegTypeInteger)
+              tmpType = kRegTypeFloat;
+
+            /* 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)",
+                    srcType, tmpType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            objType = getRegisterType(workLine, decInsn.vB);
+            instField = getInstField(meth, uninitMap, objType, decInsn.vC,
+                            &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            checkFinalFieldAccess(meth, instField, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /* get type of field we're storing into */
+            fieldType = primSigCharToRegType(instField->signature[0]);
+
+            /* correct if float */
+            if (fieldType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                tmpType = kRegTypeFloat;
+
+            if (fieldType == kRegTypeBoolean && srcType == kRegTypeByte)
+                fieldType = kRegTypeByte;
+
+            verifyRegisterType(workLine, decInsn.vA, fieldType, &failure);
+
+            if (fieldType == kRegTypeUnknown ||
+                !checkFieldArrayStore1nr(tmpType, fieldType))
+            {
+                LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)",
+                        instField->clazz->descriptor,
+                        instField->name, tmpType, fieldType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+        }
+        break;
+    case OP_IPUT_WIDE:
+    case OP_IPUT_WIDE_JUMBO:
+        tmpType = getRegisterType(workLine, decInsn.vA);
+        {
+            RegType typeHi = getRegisterType(workLine, decInsn.vA + 1);
+            checkTypeCategory(tmpType, kTypeCategory2, &failure);
+            checkWidePair(tmpType, typeHi, &failure);
+        }
+        if (!VERIFY_OK(failure))
+            break;
+
+        InstField* instField;
+        RegType objType;
+
+        objType = getRegisterType(workLine, decInsn.vB);
+        instField = getInstField(meth, uninitMap, objType, decInsn.vC,
+                        &failure);
+        if (!VERIFY_OK(failure))
+            break;
+        checkFinalFieldAccess(meth, instField, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+
+        /* check the type, which should be prim */
+        switch (instField->signature[0]) {
+        case 'D':
+            verifyRegisterType(workLine, decInsn.vA, kRegTypeDoubleLo, &failure);
+            break;
+        case 'J':
+            verifyRegisterType(workLine, decInsn.vA, kRegTypeLongLo, &failure);
+            break;
+        default:
+            LOG_VFY("VFY: invalid iput-wide of %s.%s",
+                    instField->clazz->descriptor,
+                    instField->name);
+            failure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        break;
+    case OP_IPUT_OBJECT:
+    case OP_IPUT_OBJECT_JUMBO:
+        {
+            ClassObject* fieldClass;
+            ClassObject* valueClass;
+            InstField* instField;
+            RegType objType, valueType;
+
+            objType = getRegisterType(workLine, decInsn.vB);
+            instField = getInstField(meth, uninitMap, objType, decInsn.vC,
+                            &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            checkFinalFieldAccess(meth, instField, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            fieldClass = getFieldClass(meth, instField);
+            if (fieldClass == NULL) {
+                LOG_VFY("VFY: unable to recover field class from '%s'",
+                    instField->signature);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            valueType = getRegisterType(workLine, decInsn.vA);
+            if (!regTypeIsReference(valueType)) {
+                LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)",
+                        decInsn.vA, instField->name,
+                        fieldClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            if (valueType != kRegTypeZero) {
+                valueClass = regTypeInitializedReferenceToClass(valueType);
+                if (valueClass == NULL) {
+                    LOG_VFY("VFY: storing uninit ref v%d into ref field",
+                        decInsn.vA);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+                /* allow if field is any interface or field is base class */
+                if (!dvmIsInterfaceClass(fieldClass) &&
+                    !dvmInstanceof(valueClass, fieldClass))
+                {
+                    LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)",
+                            valueClass->descriptor, fieldClass->descriptor,
+                            instField->clazz->descriptor,
+                            instField->name);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case OP_SGET:
+    case OP_SGET_JUMBO:
+        tmpType = kRegTypeInteger;
+        goto sget_1nr_common;
+    case OP_SGET_BOOLEAN:
+    case OP_SGET_BOOLEAN_JUMBO:
+        tmpType = kRegTypeBoolean;
+        goto sget_1nr_common;
+    case OP_SGET_BYTE:
+    case OP_SGET_BYTE_JUMBO:
+        tmpType = kRegTypeByte;
+        goto sget_1nr_common;
+    case OP_SGET_CHAR:
+    case OP_SGET_CHAR_JUMBO:
+        tmpType = kRegTypeChar;
+        goto sget_1nr_common;
+    case OP_SGET_SHORT:
+    case OP_SGET_SHORT_JUMBO:
+        tmpType = kRegTypeShort;
+        goto sget_1nr_common;
+sget_1nr_common:
+        {
+            StaticField* staticField;
+            RegType fieldType;
+
+            staticField = getStaticField(meth, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /*
+             * Make sure the field's type is compatible with expectation.
+             * We can get ourselves into trouble if we mix & match loads
+             * and stores with different widths, so rather than just checking
+             * "canConvertTo1nr" we require that the field types have equal
+             * widths.
+             */
+            fieldType = primSigCharToRegType(staticField->signature[0]);
+
+            /* correct if float */
+            if (fieldType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                tmpType = kRegTypeFloat;
+
+            if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
+                LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)",
+                    staticField->clazz->descriptor,
+                    staticField->name, tmpType, fieldType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            setRegisterType(workLine, decInsn.vA, tmpType);
+        }
+        break;
+    case OP_SGET_WIDE:
+    case OP_SGET_WIDE_JUMBO:
+        {
+            StaticField* staticField;
+            RegType dstType;
+
+            staticField = getStaticField(meth, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            /* check the type, which should be prim */
+            switch (staticField->signature[0]) {
+            case 'D':
+                dstType = kRegTypeDoubleLo;
+                break;
+            case 'J':
+                dstType = kRegTypeLongLo;
+                break;
+            default:
+                LOG_VFY("VFY: invalid sget-wide of %s.%s",
+                        staticField->clazz->descriptor,
+                        staticField->name);
+                dstType = kRegTypeUnknown;
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            if (VERIFY_OK(failure)) {
+                setRegisterType(workLine, decInsn.vA, dstType);
+            }
+        }
+        break;
+    case OP_SGET_OBJECT:
+    case OP_SGET_OBJECT_JUMBO:
+        {
+            StaticField* staticField;
+            ClassObject* fieldClass;
+
+            staticField = getStaticField(meth, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            fieldClass = getFieldClass(meth, staticField);
+            if (fieldClass == NULL) {
+                LOG_VFY("VFY: unable to recover field class from '%s'",
+                    staticField->signature);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            if (dvmIsPrimitiveClass(fieldClass)) {
+                LOG_VFY("VFY: attempt to get prim field with sget-object");
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            setRegisterType(workLine, decInsn.vA, regTypeFromClass(fieldClass));
+        }
+        break;
+    case OP_SPUT:
+    case OP_SPUT_JUMBO:
+        tmpType = kRegTypeInteger;
+        goto sput_1nr_common;
+    case OP_SPUT_BOOLEAN:
+    case OP_SPUT_BOOLEAN_JUMBO:
+        tmpType = kRegTypeBoolean;
+        goto sput_1nr_common;
+    case OP_SPUT_BYTE:
+    case OP_SPUT_BYTE_JUMBO:
+        tmpType = kRegTypeByte;
+        goto sput_1nr_common;
+    case OP_SPUT_CHAR:
+    case OP_SPUT_CHAR_JUMBO:
+        tmpType = kRegTypeChar;
+        goto sput_1nr_common;
+    case OP_SPUT_SHORT:
+    case OP_SPUT_SHORT_JUMBO:
+        tmpType = kRegTypeShort;
+        goto sput_1nr_common;
+sput_1nr_common:
+        {
+            RegType srcType, fieldType;
+            StaticField* staticField;
+
+            srcType = getRegisterType(workLine, decInsn.vA);
+
+            /*
+             * javac generates synthetic functions that write byte values
+             * into boolean fields.
+             */
+            if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
+                tmpType = kRegTypeByte;
+
+            /* correct if float */
+            if (srcType == kRegTypeFloat && tmpType == kRegTypeInteger)
+              tmpType = kRegTypeFloat;
+
+            /* make sure the source register has the correct type */
+            if (!canConvertTo1nr(srcType, tmpType)) {
+                LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)",
+                    srcType, tmpType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            staticField = getStaticField(meth, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            checkFinalFieldAccess(meth, staticField, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /*
+             * Get type of field we're storing into.  We know that the
+             * contents of the register match the instruction, but we also
+             * need to ensure that the instruction matches the field type.
+             * Using e.g. sput-short to write into a 32-bit integer field
+             * can lead to trouble if we do 16-bit writes.
+             */
+            fieldType = primSigCharToRegType(staticField->signature[0]);
+
+            /* correct if float */
+            if (fieldType == kRegTypeFloat && tmpType == kRegTypeInteger)
+                tmpType = kRegTypeFloat;
+
+            if (fieldType == kRegTypeBoolean && srcType == kRegTypeByte)
+                fieldType = kRegTypeByte;
+
+            verifyRegisterType(workLine, decInsn.vA, fieldType, &failure);
+
+            if (fieldType == kRegTypeUnknown ||
+                !checkFieldArrayStore1nr(tmpType, fieldType)) {
+                LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)",
+                    staticField->clazz->descriptor,
+                    staticField->name, tmpType, fieldType);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+        }
+        break;
+    case OP_SPUT_WIDE:
+    case OP_SPUT_WIDE_JUMBO:
+        tmpType = getRegisterType(workLine, decInsn.vA);
+        {
+            RegType typeHi = getRegisterType(workLine, decInsn.vA + 1);
+            checkTypeCategory(tmpType, kTypeCategory2, &failure);
+            checkWidePair(tmpType, typeHi, &failure);
+        }
+        if (!VERIFY_OK(failure))
+            break;
+
+        StaticField* staticField;
+
+        staticField = getStaticField(meth, decInsn.vB, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+        checkFinalFieldAccess(meth, staticField, &failure);
+        if (!VERIFY_OK(failure))
+            break;
+
+        /* check the type, which should be prim */
+        switch (staticField->signature[0]) {
+        case 'D':
+            verifyRegisterType(workLine, decInsn.vA, kRegTypeDoubleLo, &failure);
+            break;
+        case 'J':
+            verifyRegisterType(workLine, decInsn.vA, kRegTypeLongLo, &failure);
+            break;
+        default:
+            LOG_VFY("VFY: invalid sput-wide of %s.%s",
+                    staticField->clazz->descriptor,
+                    staticField->name);
+            failure = VERIFY_ERROR_GENERIC;
+            break;
+        }
+        break;
+    case OP_SPUT_OBJECT:
+    case OP_SPUT_OBJECT_JUMBO:
+        {
+            ClassObject* fieldClass;
+            ClassObject* valueClass;
+            StaticField* staticField;
+            RegType valueType;
+
+            staticField = getStaticField(meth, decInsn.vB, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            checkFinalFieldAccess(meth, staticField, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            fieldClass = getFieldClass(meth, staticField);
+            if (fieldClass == NULL) {
+                LOG_VFY("VFY: unable to recover field class from '%s'",
+                    staticField->signature);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+
+            valueType = getRegisterType(workLine, decInsn.vA);
+            if (!regTypeIsReference(valueType)) {
+                LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)",
+                        decInsn.vA, staticField->name,
+                        fieldClass->descriptor);
+                failure = VERIFY_ERROR_GENERIC;
+                break;
+            }
+            if (valueType != kRegTypeZero) {
+                valueClass = regTypeInitializedReferenceToClass(valueType);
+                if (valueClass == NULL) {
+                    LOG_VFY("VFY: storing uninit ref v%d into ref field",
+                        decInsn.vA);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+                /* allow if field is any interface or field is base class */
+                if (!dvmIsInterfaceClass(fieldClass) &&
+                    !dvmInstanceof(valueClass, fieldClass))
+                {
+                    LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)",
+                            valueClass->descriptor, fieldClass->descriptor,
+                            staticField->clazz->descriptor,
+                            staticField->name);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case OP_INVOKE_VIRTUAL:
+    case OP_INVOKE_VIRTUAL_RANGE:
+    case OP_INVOKE_VIRTUAL_JUMBO:
+    case OP_INVOKE_SUPER:
+    case OP_INVOKE_SUPER_RANGE:
+    case OP_INVOKE_SUPER_JUMBO:
+        {
+            Method* calledMethod;
+            RegType returnType;
+            bool isRange;
+            bool isSuper;
+
+            isRange =  (decInsn.opcode == OP_INVOKE_VIRTUAL_RANGE ||
+                        decInsn.opcode == OP_INVOKE_VIRTUAL_JUMBO ||
+                        decInsn.opcode == OP_INVOKE_SUPER_RANGE ||
+                        decInsn.opcode == OP_INVOKE_SUPER_JUMBO);
+            isSuper =  (decInsn.opcode == OP_INVOKE_SUPER ||
+                        decInsn.opcode == OP_INVOKE_SUPER_RANGE ||
+                        decInsn.opcode == OP_INVOKE_SUPER_JUMBO);
+
+            calledMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
+                            &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
+                            isSuper, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+            returnType = getMethodReturnType(calledMethod);
+            setResultRegisterType(workLine, insnRegCount, returnType);
+            justSetResult = true;
+        }
+        break;
+    case OP_INVOKE_DIRECT:
+    case OP_INVOKE_DIRECT_RANGE:
+    case OP_INVOKE_DIRECT_JUMBO:
+        {
+            RegType returnType;
+            Method* calledMethod;
+            bool isRange;
+
+            isRange =  (decInsn.opcode == OP_INVOKE_DIRECT_RANGE ||
+                        decInsn.opcode == OP_INVOKE_DIRECT_JUMBO);
+            calledMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
+                            &decInsn, uninitMap, METHOD_DIRECT, isRange,
+                            false, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            /*
+             * Some additional checks when calling <init>.  We know from
+             * the invocation arg check that the "this" argument is an
+             * instance of calledMethod->clazz.  Now we further restrict
+             * that to require that calledMethod->clazz is the same as
+             * this->clazz or this->super, allowing the latter only if
+             * the "this" argument is the same as the "this" argument to
+             * this method (which implies that we're in <init> ourselves).
+             */
+            if (isInitMethod(calledMethod)) {
+                RegType thisType;
+                thisType = getInvocationThis(workLine, &decInsn, &failure);
+                if (!VERIFY_OK(failure))
+                    break;
+
+                /* no null refs allowed (?) */
+                if (thisType == kRegTypeZero) {
+                    LOG_VFY("VFY: unable to initialize null ref");
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                ClassObject* thisClass;
+
+                thisClass = regTypeReferenceToClass(thisType, uninitMap);
+                assert(thisClass != NULL);
+
+                /* must be in same class or in superclass */
+                if (calledMethod->clazz == thisClass->super) {
+                    if (thisClass != meth->clazz) {
+                        LOG_VFY("VFY: invoke-direct <init> on super only "
+                            "allowed for 'this' in <init>");
+                        failure = VERIFY_ERROR_GENERIC;
+                        break;
+                    }
+                }  else if (calledMethod->clazz != thisClass) {
+                    LOG_VFY("VFY: invoke-direct <init> must be on current "
+                            "class or super");
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                /* arg must be an uninitialized reference */
+                if (!regTypeIsUninitReference(thisType)) {
+                    LOG_VFY("VFY: can only initialize the uninitialized");
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                /*
+                 * Replace the uninitialized reference with an initialized
+                 * one, and clear the entry in the uninit map.  We need to
+                 * do this for all registers that have the same object
+                 * instance in them, not just the "this" register.
+                 */
+                markRefsAsInitialized(workLine, insnRegCount, uninitMap,
+                    thisType, &failure);
+                if (!VERIFY_OK(failure))
+                    break;
+            }
+            returnType = getMethodReturnType(calledMethod);
+            setResultRegisterType(workLine, insnRegCount, returnType);
+            justSetResult = true;
+        }
+        break;
+    case OP_INVOKE_STATIC:
+    case OP_INVOKE_STATIC_RANGE:
+    case OP_INVOKE_STATIC_JUMBO:
+        {
+            RegType returnType;
+            Method* calledMethod;
+            bool isRange;
+
+            isRange =  (decInsn.opcode == OP_INVOKE_STATIC_RANGE ||
+                        decInsn.opcode == OP_INVOKE_STATIC_JUMBO);
+            calledMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
+                            &decInsn, uninitMap, METHOD_STATIC, isRange,
+                            false, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            returnType = getMethodReturnType(calledMethod);
+            setResultRegisterType(workLine, insnRegCount, returnType);
+            justSetResult = true;
+        }
+        break;
+    case OP_INVOKE_INTERFACE:
+    case OP_INVOKE_INTERFACE_RANGE:
+    case OP_INVOKE_INTERFACE_JUMBO:
+        {
+            RegType /*thisType,*/ returnType;
+            Method* absMethod;
+            bool isRange;
+
+            isRange =  (decInsn.opcode == OP_INVOKE_INTERFACE_RANGE ||
+                        decInsn.opcode == OP_INVOKE_INTERFACE_JUMBO);
+            absMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
+                            &decInsn, uninitMap, METHOD_INTERFACE, isRange,
+                            false, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+#if 0       /* can't do this here, fails on dalvik test 052-verifier-fun */
+            /*
+             * Get the type of the "this" arg, which should always be an
+             * interface class.  Because we don't do a full merge on
+             * interface classes, this might have reduced to Object.
+             */
+            thisType = getInvocationThis(workLine, &decInsn, &failure);
+            if (!VERIFY_OK(failure))
+                break;
+
+            if (thisType == kRegTypeZero) {
+                /* null pointer always passes (and always fails at runtime) */
+            } else {
+                ClassObject* thisClass;
+
+                thisClass = regTypeInitializedReferenceToClass(thisType);
+                if (thisClass == NULL) {
+                    LOG_VFY("VFY: interface call on uninitialized");
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+
+                /*
+                 * Either "thisClass" needs to be the interface class that
+                 * defined absMethod, or absMethod's class needs to be one
+                 * of the interfaces implemented by "thisClass".  (Or, if
+                 * we couldn't complete the merge, this will be Object.)
+                 */
+                if (thisClass != absMethod->clazz &&
+                    thisClass != gDvm.classJavaLangObject &&
+                    !dvmImplements(thisClass, absMethod->clazz))
+                {
+                    LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces",
+                            absMethod->name, thisClass->descriptor);
+                    failure = VERIFY_ERROR_GENERIC;
+                    break;
+                }
+            }
+#endif
+
+            /*
+             * We don't have an object instance, so we can't find the
+             * concrete method.  However, all of the type information is
+             * in the abstract method, so we're good.
+             */
+            returnType = getMethodReturnType(absMethod);
+            setResultRegisterType(workLine, insnRegCount, returnType);
+            justSetResult = true;
+        }
+        break;
+
+    case OP_NEG_INT:
+    case OP_NOT_INT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, &failure);
+        break;
+    case OP_NEG_LONG:
+    case OP_NOT_LONG:
+        checkUnop(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeLongLo, &failure);
+        break;
+    case OP_NEG_FLOAT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeFloat, kRegTypeFloat, &failure);
+        break;
+    case OP_NEG_DOUBLE:
+        checkUnop(workLine, &decInsn,
+            kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
+        break;
+    case OP_INT_TO_LONG:
+        checkUnop(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeInteger, &failure);
+        break;
+    case OP_INT_TO_FLOAT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeFloat, kRegTypeInteger, &failure);
+        break;
+    case OP_INT_TO_DOUBLE:
+        checkUnop(workLine, &decInsn,
+            kRegTypeDoubleLo, kRegTypeInteger, &failure);
+        break;
+    case OP_LONG_TO_INT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeLongLo, &failure);
+        break;
+    case OP_LONG_TO_FLOAT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeFloat, kRegTypeLongLo, &failure);
+        break;
+    case OP_LONG_TO_DOUBLE:
+        checkUnop(workLine, &decInsn,
+            kRegTypeDoubleLo, kRegTypeLongLo, &failure);
+        break;
+    case OP_FLOAT_TO_INT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeFloat, &failure);
+        break;
+    case OP_FLOAT_TO_LONG:
+        checkUnop(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeFloat, &failure);
+        break;
+    case OP_FLOAT_TO_DOUBLE:
+        checkUnop(workLine, &decInsn,
+            kRegTypeDoubleLo, kRegTypeFloat, &failure);
+        break;
+    case OP_DOUBLE_TO_INT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeDoubleLo, &failure);
+        break;
+    case OP_DOUBLE_TO_LONG:
+        checkUnop(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeDoubleLo, &failure);
+        break;
+    case OP_DOUBLE_TO_FLOAT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeFloat, kRegTypeDoubleLo, &failure);
+        break;
+    case OP_INT_TO_BYTE:
+        checkUnop(workLine, &decInsn,
+            kRegTypeByte, kRegTypeInteger, &failure);
+        break;
+    case OP_INT_TO_CHAR:
+        checkUnop(workLine, &decInsn,
+            kRegTypeChar, kRegTypeInteger, &failure);
+        break;
+    case OP_INT_TO_SHORT:
+        checkUnop(workLine, &decInsn,
+            kRegTypeShort, kRegTypeInteger, &failure);
+        break;
+
+    case OP_ADD_INT:
+    case OP_SUB_INT:
+    case OP_MUL_INT:
+    case OP_REM_INT:
+    case OP_DIV_INT:
+    case OP_SHL_INT:
+    case OP_SHR_INT:
+    case OP_USHR_INT:
+        checkBinop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
+        break;
+    case OP_AND_INT:
+    case OP_OR_INT:
+    case OP_XOR_INT:
+        checkBinop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
+        break;
+    case OP_ADD_LONG:
+    case OP_SUB_LONG:
+    case OP_MUL_LONG:
+    case OP_DIV_LONG:
+    case OP_REM_LONG:
+    case OP_AND_LONG:
+    case OP_OR_LONG:
+    case OP_XOR_LONG:
+        checkBinop(workLine, &decInsn,
+            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(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
+        break;
+    case OP_ADD_FLOAT:
+    case OP_SUB_FLOAT:
+    case OP_MUL_FLOAT:
+    case OP_DIV_FLOAT:
+    case OP_REM_FLOAT:
+        checkBinop(workLine, &decInsn,
+            kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
+        break;
+    case OP_ADD_DOUBLE:
+    case OP_SUB_DOUBLE:
+    case OP_MUL_DOUBLE:
+    case OP_DIV_DOUBLE:
+    case OP_REM_DOUBLE:
+        checkBinop(workLine, &decInsn,
+            kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
+            &failure);
+        break;
+    case OP_ADD_INT_2ADDR:
+    case OP_SUB_INT_2ADDR:
+    case OP_MUL_INT_2ADDR:
+    case OP_REM_INT_2ADDR:
+    case OP_SHL_INT_2ADDR:
+    case OP_SHR_INT_2ADDR:
+    case OP_USHR_INT_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
+        break;
+    case OP_AND_INT_2ADDR:
+    case OP_OR_INT_2ADDR:
+    case OP_XOR_INT_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
+        break;
+    case OP_DIV_INT_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
+        break;
+    case OP_ADD_LONG_2ADDR:
+    case OP_SUB_LONG_2ADDR:
+    case OP_MUL_LONG_2ADDR:
+    case OP_DIV_LONG_2ADDR:
+    case OP_REM_LONG_2ADDR:
+    case OP_AND_LONG_2ADDR:
+    case OP_OR_LONG_2ADDR:
+    case OP_XOR_LONG_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
+        break;
+    case OP_SHL_LONG_2ADDR:
+    case OP_SHR_LONG_2ADDR:
+    case OP_USHR_LONG_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
+        break;
+    case OP_ADD_FLOAT_2ADDR:
+    case OP_SUB_FLOAT_2ADDR:
+    case OP_MUL_FLOAT_2ADDR:
+    case OP_DIV_FLOAT_2ADDR:
+    case OP_REM_FLOAT_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
+        break;
+    case OP_ADD_DOUBLE_2ADDR:
+    case OP_SUB_DOUBLE_2ADDR:
+    case OP_MUL_DOUBLE_2ADDR:
+    case OP_DIV_DOUBLE_2ADDR:
+    case OP_REM_DOUBLE_2ADDR:
+        checkBinop2addr(workLine, &decInsn,
+            kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
+            &failure);
+        break;
+    case OP_ADD_INT_LIT16:
+    case OP_RSUB_INT:
+    case OP_MUL_INT_LIT16:
+    case OP_DIV_INT_LIT16:
+    case OP_REM_INT_LIT16:
+        checkLitop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, false, &failure);
+        break;
+    case OP_AND_INT_LIT16:
+    case OP_OR_INT_LIT16:
+    case OP_XOR_INT_LIT16:
+        checkLitop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, true, &failure);
+        break;
+    case OP_ADD_INT_LIT8:
+    case OP_RSUB_INT_LIT8:
+    case OP_MUL_INT_LIT8:
+    case OP_DIV_INT_LIT8:
+    case OP_REM_INT_LIT8:
+    case OP_SHL_INT_LIT8:
+        checkLitop(workLine, &decInsn,
+            kRegTypeInteger, kRegTypeInteger, false, &failure);
+        break;
+    case OP_SHR_INT_LIT8:
+        tmpType = adjustForRightShift(workLine,
+            decInsn.vB, decInsn.vC, false, &failure);
+        checkLitop(workLine, &decInsn,
+            tmpType, kRegTypeInteger, false, &failure);
+        break;
+    case OP_USHR_INT_LIT8:
+        tmpType = adjustForRightShift(workLine,
+            decInsn.vB, decInsn.vC, true, &failure);
+        checkLitop(workLine, &decInsn,
+            tmpType, kRegTypeInteger, false, &failure);
+        break;
+    case OP_AND_INT_LIT8:
+    case OP_OR_INT_LIT8:
+    case OP_XOR_INT_LIT8:
+        checkLitop(workLine, &decInsn,
+            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:
+    case OP_THROW_VERIFICATION_ERROR_JUMBO:
+        break;
+
+    /*
+     * Verifying "quickened" instructions is tricky, because we have
+     * discarded the original field/method information.  The byte offsets
+     * and vtable indices only have meaning in the context of an object
+     * instance.
+     *
+     * If a piece of code declares a local reference variable, assigns
+     * null to it, and then issues a virtual method call on it, we
+     * cannot evaluate the method call during verification.  This situation
+     * isn't hard to handle, since we know the call will always result in an
+     * NPE, and the arguments and return value don't matter.  Any code that
+     * depends on the result of the method call is inaccessible, so the
+     * fact that we can't fully verify anything that comes after the bad
+     * call is not a problem.
+     *
+     * We must also consider the case of multiple code paths, only some of
+     * which involve a null reference.  We can completely verify the method
+     * if we sidestep the results of executing with a null reference.
+     * For example, if on the first pass through the code we try to do a
+     * virtual method invocation through a null ref, we have to skip the
+     * method checks and have the method return a "wildcard" type (which
+     * merges with anything to become that other thing).  The move-result
+     * will tell us if it's a reference, single-word numeric, or double-word
+     * value.  We continue to perform the verification, and at the end of
+     * the function any invocations that were never fully exercised are
+     * marked as null-only.
+     *
+     * We would do something similar for the field accesses.  The field's
+     * type, once known, can be used to recover the width of short integers.
+     * If the object reference was null, the field-get returns the "wildcard"
+     * type, which is acceptable for any operation.
+     */
+    case OP_EXECUTE_INLINE:
+    case OP_EXECUTE_INLINE_RANGE:
+    case OP_IGET_QUICK:
+    case OP_IGET_WIDE_QUICK:
+    case OP_IGET_OBJECT_QUICK:
+    case OP_IPUT_QUICK:
+    case OP_IPUT_WIDE_QUICK:
+    case OP_IPUT_OBJECT_QUICK:
+    case OP_INVOKE_VIRTUAL_QUICK:
+    case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+    case OP_INVOKE_SUPER_QUICK:
+    case OP_INVOKE_SUPER_QUICK_RANGE:
+        /* fall through to failure */
+
+    /*
+     * These instructions are equivalent (from the verifier's point of view)
+     * to the original form.  The change was made for correctness rather
+     * than improved performance (except for invoke-object-init, which
+     * provides both).  The substitution takes place after verification
+     * completes, though, so we don't expect to see them here.
+     */
+    case OP_INVOKE_OBJECT_INIT_RANGE:
+    case OP_INVOKE_OBJECT_INIT_JUMBO:
+    case OP_RETURN_VOID_BARRIER:
+    case OP_IGET_VOLATILE:
+    case OP_IGET_VOLATILE_JUMBO:
+    case OP_IGET_WIDE_VOLATILE:
+    case OP_IGET_WIDE_VOLATILE_JUMBO:
+    case OP_IGET_OBJECT_VOLATILE:
+    case OP_IGET_OBJECT_VOLATILE_JUMBO:
+    case OP_IPUT_VOLATILE:
+    case OP_IPUT_VOLATILE_JUMBO:
+    case OP_IPUT_WIDE_VOLATILE:
+    case OP_IPUT_WIDE_VOLATILE_JUMBO:
+    case OP_IPUT_OBJECT_VOLATILE:
+    case OP_IPUT_OBJECT_VOLATILE_JUMBO:
+    case OP_SGET_VOLATILE:
+    case OP_SGET_VOLATILE_JUMBO:
+    case OP_SGET_WIDE_VOLATILE:
+    case OP_SGET_WIDE_VOLATILE_JUMBO:
+    case OP_SGET_OBJECT_VOLATILE:
+    case OP_SGET_OBJECT_VOLATILE_JUMBO:
+    case OP_SPUT_VOLATILE:
+    case OP_SPUT_VOLATILE_JUMBO:
+    case OP_SPUT_WIDE_VOLATILE:
+    case OP_SPUT_WIDE_VOLATILE_JUMBO:
+    case OP_SPUT_OBJECT_VOLATILE:
+    case OP_SPUT_OBJECT_VOLATILE_JUMBO:
+        /* fall through to failure */
+
+    /* these should never appear during verification */
+    case OP_UNUSED_3E:
+    case OP_UNUSED_3F:
+    case OP_UNUSED_40:
+    case OP_UNUSED_41:
+    case OP_UNUSED_42:
+    case OP_UNUSED_43:
+    case OP_UNUSED_73:
+    case OP_UNUSED_79:
+    case OP_UNUSED_7A:
+    case OP_BREAKPOINT:
+    case OP_DISPATCH_FF:
+    case OP_UNUSED_27FF:
+    case OP_UNUSED_28FF:
+    case OP_UNUSED_29FF:
+    case OP_UNUSED_2AFF:
+    case OP_UNUSED_2BFF:
+    case OP_UNUSED_2CFF:
+    case OP_UNUSED_2DFF:
+    case OP_UNUSED_2EFF:
+    case OP_UNUSED_2FFF:
+    case OP_UNUSED_30FF:
+    case OP_UNUSED_31FF:
+    case OP_UNUSED_32FF:
+    case OP_UNUSED_33FF:
+    case OP_UNUSED_34FF:
+    case OP_UNUSED_35FF:
+    case OP_UNUSED_36FF:
+    case OP_UNUSED_37FF:
+    case OP_UNUSED_38FF:
+    case OP_UNUSED_39FF:
+    case OP_UNUSED_3AFF:
+    case OP_UNUSED_3BFF:
+    case OP_UNUSED_3CFF:
+    case OP_UNUSED_3DFF:
+    case OP_UNUSED_3EFF:
+    case OP_UNUSED_3FFF:
+    case OP_UNUSED_40FF:
+    case OP_UNUSED_41FF:
+    case OP_UNUSED_42FF:
+    case OP_UNUSED_43FF:
+    case OP_UNUSED_44FF:
+    case OP_UNUSED_45FF:
+    case OP_UNUSED_46FF:
+    case OP_UNUSED_47FF:
+    case OP_UNUSED_48FF:
+    case OP_UNUSED_49FF:
+    case OP_UNUSED_4AFF:
+    case OP_UNUSED_4BFF:
+    case OP_UNUSED_4CFF:
+    case OP_UNUSED_4DFF:
+    case OP_UNUSED_4EFF:
+    case OP_UNUSED_4FFF:
+    case OP_UNUSED_50FF:
+    case OP_UNUSED_51FF:
+    case OP_UNUSED_52FF:
+    case OP_UNUSED_53FF:
+    case OP_UNUSED_54FF:
+    case OP_UNUSED_55FF:
+    case OP_UNUSED_56FF:
+    case OP_UNUSED_57FF:
+    case OP_UNUSED_58FF:
+    case OP_UNUSED_59FF:
+    case OP_UNUSED_5AFF:
+    case OP_UNUSED_5BFF:
+    case OP_UNUSED_5CFF:
+    case OP_UNUSED_5DFF:
+    case OP_UNUSED_5EFF:
+    case OP_UNUSED_5FFF:
+    case OP_UNUSED_60FF:
+    case OP_UNUSED_61FF:
+    case OP_UNUSED_62FF:
+    case OP_UNUSED_63FF:
+    case OP_UNUSED_64FF:
+    case OP_UNUSED_65FF:
+    case OP_UNUSED_66FF:
+    case OP_UNUSED_67FF:
+    case OP_UNUSED_68FF:
+    case OP_UNUSED_69FF:
+    case OP_UNUSED_6AFF:
+    case OP_UNUSED_6BFF:
+    case OP_UNUSED_6CFF:
+    case OP_UNUSED_6DFF:
+    case OP_UNUSED_6EFF:
+    case OP_UNUSED_6FFF:
+    case OP_UNUSED_70FF:
+    case OP_UNUSED_71FF:
+    case OP_UNUSED_72FF:
+    case OP_UNUSED_73FF:
+    case OP_UNUSED_74FF:
+    case OP_UNUSED_75FF:
+    case OP_UNUSED_76FF:
+    case OP_UNUSED_77FF:
+    case OP_UNUSED_78FF:
+    case OP_UNUSED_79FF:
+    case OP_UNUSED_7AFF:
+    case OP_UNUSED_7BFF:
+    case OP_UNUSED_7CFF:
+    case OP_UNUSED_7DFF:
+    case OP_UNUSED_7EFF:
+    case OP_UNUSED_7FFF:
+    case OP_UNUSED_80FF:
+    case OP_UNUSED_81FF:
+    case OP_UNUSED_82FF:
+    case OP_UNUSED_83FF:
+    case OP_UNUSED_84FF:
+    case OP_UNUSED_85FF:
+    case OP_UNUSED_86FF:
+    case OP_UNUSED_87FF:
+    case OP_UNUSED_88FF:
+    case OP_UNUSED_89FF:
+    case OP_UNUSED_8AFF:
+    case OP_UNUSED_8BFF:
+    case OP_UNUSED_8CFF:
+    case OP_UNUSED_8DFF:
+    case OP_UNUSED_8EFF:
+    case OP_UNUSED_8FFF:
+    case OP_UNUSED_90FF:
+    case OP_UNUSED_91FF:
+    case OP_UNUSED_92FF:
+    case OP_UNUSED_93FF:
+    case OP_UNUSED_94FF:
+    case OP_UNUSED_95FF:
+    case OP_UNUSED_96FF:
+    case OP_UNUSED_97FF:
+    case OP_UNUSED_98FF:
+    case OP_UNUSED_99FF:
+    case OP_UNUSED_9AFF:
+    case OP_UNUSED_9BFF:
+    case OP_UNUSED_9CFF:
+    case OP_UNUSED_9DFF:
+    case OP_UNUSED_9EFF:
+    case OP_UNUSED_9FFF:
+    case OP_UNUSED_A0FF:
+    case OP_UNUSED_A1FF:
+    case OP_UNUSED_A2FF:
+    case OP_UNUSED_A3FF:
+    case OP_UNUSED_A4FF:
+    case OP_UNUSED_A5FF:
+    case OP_UNUSED_A6FF:
+    case OP_UNUSED_A7FF:
+    case OP_UNUSED_A8FF:
+    case OP_UNUSED_A9FF:
+    case OP_UNUSED_AAFF:
+    case OP_UNUSED_ABFF:
+    case OP_UNUSED_ACFF:
+    case OP_UNUSED_ADFF:
+    case OP_UNUSED_AEFF:
+    case OP_UNUSED_AFFF:
+    case OP_UNUSED_B0FF:
+    case OP_UNUSED_B1FF:
+    case OP_UNUSED_B2FF:
+    case OP_UNUSED_B3FF:
+    case OP_UNUSED_B4FF:
+    case OP_UNUSED_B5FF:
+    case OP_UNUSED_B6FF:
+    case OP_UNUSED_B7FF:
+    case OP_UNUSED_B8FF:
+    case OP_UNUSED_B9FF:
+    case OP_UNUSED_BAFF:
+    case OP_UNUSED_BBFF:
+    case OP_UNUSED_BCFF:
+    case OP_UNUSED_BDFF:
+    case OP_UNUSED_BEFF:
+    case OP_UNUSED_BFFF:
+    case OP_UNUSED_C0FF:
+    case OP_UNUSED_C1FF:
+    case OP_UNUSED_C2FF:
+    case OP_UNUSED_C3FF:
+    case OP_UNUSED_C4FF:
+    case OP_UNUSED_C5FF:
+    case OP_UNUSED_C6FF:
+    case OP_UNUSED_C7FF:
+    case OP_UNUSED_C8FF:
+    case OP_UNUSED_C9FF:
+    case OP_UNUSED_CAFF:
+    case OP_UNUSED_CBFF:
+    case OP_UNUSED_CCFF:
+    case OP_UNUSED_CDFF:
+    case OP_UNUSED_CEFF:
+    case OP_UNUSED_CFFF:
+    case OP_UNUSED_D0FF:
+    case OP_UNUSED_D1FF:
+    case OP_UNUSED_D2FF:
+    case OP_UNUSED_D3FF:
+    case OP_UNUSED_D4FF:
+    case OP_UNUSED_D5FF:
+    case OP_UNUSED_D6FF:
+    case OP_UNUSED_D7FF:
+    case OP_UNUSED_D8FF:
+    case OP_UNUSED_D9FF:
+    case OP_UNUSED_DAFF:
+    case OP_UNUSED_DBFF:
+    case OP_UNUSED_DCFF:
+    case OP_UNUSED_DDFF:
+    case OP_UNUSED_DEFF:
+    case OP_UNUSED_DFFF:
+    case OP_UNUSED_E0FF:
+    case OP_UNUSED_E1FF:
+    case OP_UNUSED_E2FF:
+    case OP_UNUSED_E3FF:
+    case OP_UNUSED_E4FF:
+    case OP_UNUSED_E5FF:
+    case OP_UNUSED_E6FF:
+    case OP_UNUSED_E7FF:
+    case OP_UNUSED_E8FF:
+    case OP_UNUSED_E9FF:
+    case OP_UNUSED_EAFF:
+    case OP_UNUSED_EBFF:
+    case OP_UNUSED_ECFF:
+    case OP_UNUSED_EDFF:
+    case OP_UNUSED_EEFF:
+    case OP_UNUSED_EFFF:
+    case OP_UNUSED_F0FF:
+    case OP_UNUSED_F1FF:
+        failure = VERIFY_ERROR_GENERIC;
+        break;
+
+    /*
+     * DO NOT add a "default" clause here.  Without it the compiler will
+     * complain if an instruction is missing (which is desirable).
+     */
+    }
+
+    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",
+                decInsn.opcode, insnIdx);
+            goto bail;
+        } else {
+            /* replace opcode and continue on */
+            LOGD("VFY: replacing opcode 0x%02x at 0x%04x",
+                decInsn.opcode, insnIdx);
+            if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
+                LOG_VFY_METH(meth, "VFY:  rejecting opcode 0x%02x at 0x%04x",
+                    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;
+        }
+    }
+
+    /*
+     * If we didn't just set the result register, clear it out.  This
+     * ensures that you can only use "move-result" immediately after the
+     * result is set.  (We could check this statically, but it's not
+     * expensive and it makes our debugging output cleaner.)
+     */
+    if (!justSetResult) {
+        int reg = RESULT_REGISTER(insnRegCount);
+        setRegisterType(workLine, reg, kRegTypeUnknown);
+        setRegisterType(workLine, reg+1, kRegTypeUnknown);
+    }
+
+    /*
+     * Handle "continue".  Tag the next consecutive instruction.
+     */
+    if ((nextFlags & kInstrCanContinue) != 0) {
+        int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
+        if (insnIdx+insnWidth >= insnsSize) {
+            LOG_VFY_METH(meth,
+                "VFY: execution can walk off end of code area (from %#x)",
+                insnIdx);
+            goto bail;
+        }
+
+        /*
+         * The only way to get to a move-exception instruction is to get
+         * thrown there.  Make sure the next instruction isn't one.
+         */
+        if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
+            goto bail;
+
+        if (getRegisterLine(regTable, insnIdx+insnWidth)->regTypes != NULL) {
+            /*
+             * Merge registers into what we have for the next instruction,
+             * and set the "changed" flag if needed.
+             */
+            if (!updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
+                    workLine))
+                goto bail;
+        } else {
+            /*
+             * We're not recording register data for the next instruction,
+             * so we don't know what the prior state was.  We have to
+             * assume that something has changed and re-evaluate it.
+             */
+            dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
+        }
+    }
+
+    /*
+     * Handle "branch".  Tag the branch target.
+     *
+     * NOTE: instructions like OP_EQZ provide information about the state
+     * of the register when the branch is taken or not taken.  For example,
+     * somebody could get a reference field, check it for zero, and if the
+     * branch is taken immediately store that register in a boolean field
+     * since the value is known to be zero.  We do not currently account for
+     * that, and will reject the code.
+     *
+     * TODO: avoid re-fetching the branch target
+     */
+    if ((nextFlags & kInstrCanBranch) != 0) {
+        bool isConditional;
+
+        if (!dvmGetBranchOffset(meth, insnFlags, insnIdx, &branchTarget,
+                &isConditional))
+        {
+            /* should never happen after static verification */
+            LOG_VFY_METH(meth, "VFY: bad branch at %d", insnIdx);
+            goto bail;
+        }
+        assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
+        assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
+
+        if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
+            goto bail;
+
+        /* update branch target, set "changed" if appropriate */
+        if (!updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
+                workLine))
+            goto bail;
+    }
+
+    /*
+     * Handle "switch".  Tag all possible branch targets.
+     *
+     * We've already verified that the table is structurally sound, so we
+     * just need to walk through and tag the targets.
+     */
+    if ((nextFlags & kInstrCanSwitch) != 0) {
+        int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
+        const u2* switchInsns = insns + offsetToSwitch;
+        int switchCount = switchInsns[1];
+        int offsetToTargets, targ;
+
+        if ((*insns & 0xff) == OP_PACKED_SWITCH) {
+            /* 0=sig, 1=count, 2/3=firstKey */
+            offsetToTargets = 4;
+        } else {
+            /* 0=sig, 1=count, 2..count*2 = keys */
+            assert((*insns & 0xff) == OP_SPARSE_SWITCH);
+            offsetToTargets = 2 + 2*switchCount;
+        }
+
+        /* verify each switch target */
+        for (targ = 0; targ < switchCount; targ++) {
+            int offset, absOffset;
+
+            /* offsets are 32-bit, and only partly endian-swapped */
+            offset = switchInsns[offsetToTargets + targ*2] |
+                     (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
+            absOffset = insnIdx + offset;
+
+            assert(absOffset >= 0 && absOffset < insnsSize);
+
+            if (!checkMoveException(meth, absOffset, "switch"))
+                goto bail;
+
+            if (!updateRegisters(meth, insnFlags, regTable, absOffset,
+                    workLine))
+                goto bail;
+        }
+    }
+
+    /*
+     * Handle instructions that can throw and that are sitting in a
+     * "try" block.  (If they're not in a "try" block when they throw,
+     * control transfers out of the method.)
+     */
+    if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
+    {
+        const DexCode* pCode = dvmGetMethodCode(meth);
+        DexCatchIterator iterator;
+        bool hasCatchAll = false;
+
+        if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
+            for (;;) {
+                DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+
+                if (handler == NULL) {
+                    break;
+                }
+
+                if (handler->typeIdx == kDexNoIndex)
+                    hasCatchAll = true;
+
+                /*
+                 * Merge registers into the "catch" block.  We want to
+                 * use the "savedRegs" rather than "workRegs", because
+                 * at runtime the exception will be thrown before the
+                 * instruction modifies any registers.
+                 */
+                if (!updateRegisters(meth, insnFlags, regTable,
+                        handler->address, &regTable->savedLine))
+                    goto bail;
+            }
+        }
+
+        /*
+         * If the monitor stack depth is nonzero, there must be a "catch all"
+         * handler for this instruction.  This does apply to monitor-exit
+         * because of async exception handling.
+         */
+        if (workLine->monitorStackTop != 0 && !hasCatchAll) {
+            /*
+             * The state in workLine reflects the post-execution state.
+             * If the current instruction is a monitor-enter and the monitor
+             * stack was empty, we don't need a catch-all (if it throws,
+             * it will do so before grabbing the lock).
+             */
+            if (!(decInsn.opcode == OP_MONITOR_ENTER &&
+                  workLine->monitorStackTop == 1))
+            {
+                LOG_VFY_METH(meth,
+                    "VFY: no catch-all for instruction at 0x%04x", insnIdx);
+                goto bail;
+            }
+        }
+    }
+
+    /*
+     * If we're returning from the method, make sure our monitor stack
+     * is empty.
+     */
+    if ((nextFlags & kInstrCanReturn) != 0 && workLine->monitorStackTop != 0) {
+        LOG_VFY_METH(meth, "VFY: return with stack depth=%d at 0x%04x",
+            workLine->monitorStackTop, insnIdx);
+        goto bail;
+    }
+
+    /*
+     * Update startGuess.  Advance to the next instruction of that's
+     * possible, otherwise use the branch target if one was found.  If
+     * neither of those exists we're in a return or throw; leave startGuess
+     * alone and let the caller sort it out.
+     */
+    if ((nextFlags & kInstrCanContinue) != 0) {
+        *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
+    } else if ((nextFlags & kInstrCanBranch) != 0) {
+        /* we're still okay if branchTarget is zero */
+        *pStartGuess = insnIdx + branchTarget;
+    }
+
+    assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
+        dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
+
+    result = true;
+
+bail:
+    return result;
+}
+
+
+/*
+ * callback function used in dumpRegTypes to print local vars
+ * valid at a given address.
+ */
+static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
+        const char *name, const char *descriptor,
+        const char *signature)
+{
+    int addr = *((int *)cnxt);
+
+    if (addr >= (int) startAddress && addr < (int) endAddress)
+    {
+        LOGI("        %2d: '%s' %s", reg, name, descriptor);
+    }
+}
+
+/*
+ * Dump the register types for the specifed address to the log file.
+ */
+static void dumpRegTypes(const VerifierData* vdata,
+    const RegisterLine* registerLine, int addr, const char* addrName,
+    const UninitInstanceMap* uninitMap, int displayFlags)
+{
+    const Method* meth = vdata->method;
+    const InsnFlags* insnFlags = vdata->insnFlags;
+    const RegType* addrRegs = registerLine->regTypes;
+    int regCount = meth->registersSize;
+    int fullRegCount = regCount + kExtraRegs;
+    bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
+    int i;
+
+    assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
+
+    int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
+    char regChars[regCharSize +1];
+    memset(regChars, ' ', regCharSize);
+    regChars[0] = '[';
+    if (regCount == 0)
+        regChars[1] = ']';
+    else
+        regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
+    regChars[regCharSize] = '\0';
+
+    for (i = 0; i < regCount + kExtraRegs; i++) {
+        char tch;
+
+        switch (addrRegs[i]) {
+        case kRegTypeUnknown:       tch = '.';  break;
+        case kRegTypeConflict:      tch = 'X';  break;
+        case kRegTypeZero:          tch = '0';  break;
+        case kRegTypeOne:           tch = '1';  break;
+        case kRegTypeBoolean:       tch = 'Z';  break;
+        case kRegTypeConstPosByte:  tch = 'y';  break;
+        case kRegTypeConstByte:     tch = 'Y';  break;
+        case kRegTypeConstPosShort: tch = 'h';  break;
+        case kRegTypeConstShort:    tch = 'H';  break;
+        case kRegTypeConstChar:     tch = 'c';  break;
+        case kRegTypeConstInteger:  tch = 'i';  break;
+        case kRegTypePosByte:       tch = 'b';  break;
+        case kRegTypeByte:          tch = 'B';  break;
+        case kRegTypePosShort:      tch = 's';  break;
+        case kRegTypeShort:         tch = 'S';  break;
+        case kRegTypeChar:          tch = 'C';  break;
+        case kRegTypeInteger:       tch = 'I';  break;
+        case kRegTypeFloat:         tch = 'F';  break;
+        case kRegTypeConstLo:       tch = 'N';  break;
+        case kRegTypeConstHi:       tch = 'n';  break;
+        case kRegTypeLongLo:        tch = 'J';  break;
+        case kRegTypeLongHi:        tch = 'j';  break;
+        case kRegTypeDoubleLo:      tch = 'D';  break;
+        case kRegTypeDoubleHi:      tch = 'd';  break;
+        default:
+            if (regTypeIsReference(addrRegs[i])) {
+                if (regTypeIsUninitReference(addrRegs[i]))
+                    tch = 'U';
+                else
+                    tch = 'L';
+            } else {
+                tch = '*';
+                assert(false);
+            }
+            break;
+        }
+
+        if (i < regCount)
+            regChars[1 + i + (i/4)] = tch;
+        else
+            regChars[1 + i + (i/4) + 2] = tch;
+    }
+
+    if (addr == 0 && addrName != NULL) {
+        LOGI("%c%s %s mst=%d", branchTarget ? '>' : ' ',
+            addrName, regChars, registerLine->monitorStackTop);
+    } else {
+        LOGI("%c0x%04x %s mst=%d", branchTarget ? '>' : ' ',
+            addr, regChars, registerLine->monitorStackTop);
+    }
+    if (displayFlags & DRT_SHOW_LIVENESS) {
+        /*
+         * We can't use registerLine->liveRegs because it might be the
+         * "work line" rather than the copy from RegisterTable.
+         */
+        BitVector* liveRegs = vdata->registerLines[addr].liveRegs;
+        if (liveRegs != NULL)  {
+            char liveChars[regCharSize + 1];
+            memset(liveChars, ' ', regCharSize);
+            liveChars[regCharSize] = '\0';
+
+            for (i = 0; i < regCount; i++) {
+                bool isLive = dvmIsBitSet(liveRegs, i);
+                liveChars[i + 1 + (i / 4)] = isLive ? '+' : '-';
+            }
+            LOGI("        %s", liveChars);
+        } else {
+            LOGI("        %c", '#');
+        }
+    }
+
+    if (displayFlags & DRT_SHOW_REF_TYPES) {
+        for (i = 0; i < regCount + kExtraRegs; i++) {
+            if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
+            {
+                ClassObject* clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
+                assert(dvmIsHeapAddress((Object*)clazz));
+                if (i < regCount) {
+                    LOGI("        %2d: 0x%08x %s%s",
+                        i, addrRegs[i],
+                        regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
+                        clazz->descriptor);
+                } else {
+                    LOGI("        RS: 0x%08x %s%s",
+                        addrRegs[i],
+                        regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
+                        clazz->descriptor);
+                }
+            }
+        }
+    }
+    if (displayFlags & DRT_SHOW_LOCALS) {
+        dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
+                dvmGetMethodCode(meth),
+                meth->clazz->descriptor,
+                meth->prototype.protoIdx,
+                meth->accessFlags,
+                NULL, logLocalsCb, &addr);
+    }
+}
diff --git a/vm/analysis/CodeVerify.h b/vm/analysis/CodeVerify.h
new file mode 100644
index 0000000..5857895
--- /dev/null
+++ b/vm/analysis/CodeVerify.h
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik bytecode verifier.
+ */
+#ifndef DALVIK_CODEVERIFY_H_
+#define DALVIK_CODEVERIFY_H_
+
+#include "analysis/VerifySubs.h"
+#include "analysis/VfyBasicBlock.h"
+
+/*
+ * Enumeration for register type values.  The "hi" piece of a 64-bit value
+ * MUST immediately follow the "lo" piece in the enumeration, so we can check
+ * that hi==lo+1.
+ *
+ * Assignment of constants:
+ *   [-MAXINT,-32768)   : integer
+ *   [-32768,-128)      : short
+ *   [-128,0)           : byte
+ *   0                  : zero
+ *   1                  : one
+ *   [2,128)            : posbyte
+ *   [128,32768)        : posshort
+ *   [32768,65536)      : char
+ *   [65536,MAXINT]     : integer
+ *
+ * Allowed "implicit" widening conversions:
+ *   zero -> boolean, posbyte, byte, posshort, short, char, integer, ref (null)
+ *   one -> boolean, posbyte, byte, posshort, short, char, integer
+ *   boolean -> posbyte, byte, posshort, short, char, integer
+ *   posbyte -> posshort, short, integer, char
+ *   byte -> short, integer
+ *   posshort -> integer, char
+ *   short -> integer
+ *   char -> integer
+ *
+ * In addition, all of the above can convert to "float".
+ *
+ * We're more careful with integer values than the spec requires.  The
+ * motivation is to restrict byte/char/short to the correct range of values.
+ * For example, if a method takes a byte argument, we don't want to allow
+ * the code to load the constant "1024" and pass it in.
+ */
+enum {
+    kRegTypeUnknown = 0,    /* initial state; use value=0 so calloc works */
+    kRegTypeUninit = 1,     /* MUST be odd to distinguish from pointer */
+    kRegTypeConflict,       /* merge clash makes this reg's type unknowable */
+
+    /*
+     * Category-1nr types.  The order of these is chiseled into a couple
+     * of tables, so don't add, remove, or reorder if you can avoid it.
+     */
+#define kRegType1nrSTART    kRegTypeZero
+    kRegTypeZero,           /* 32-bit 0, could be Boolean, Int, Float, or Ref */
+    kRegTypeOne,            /* 32-bit 1, could be Boolean, Int, Float */
+    kRegTypeBoolean,        /* must be 0 or 1 */
+    kRegTypeConstPosByte,   /* const derived byte, known positive */
+    kRegTypeConstByte,      /* const derived byte */
+    kRegTypeConstPosShort,  /* const derived short, known positive */
+    kRegTypeConstShort,     /* const derived short */
+    kRegTypeConstChar,      /* const derived char */
+    kRegTypeConstInteger,   /* const derived integer */
+    kRegTypePosByte,        /* byte, known positive (can become char) */
+    kRegTypeByte,
+    kRegTypePosShort,       /* short, known positive (can become char) */
+    kRegTypeShort,
+    kRegTypeChar,
+    kRegTypeInteger,
+    kRegTypeFloat,
+#define kRegType1nrEND      kRegTypeFloat
+
+    kRegTypeConstLo,        /* const derived wide, lower half */
+    kRegTypeConstHi,        /* const derived wide, upper half */
+    kRegTypeLongLo,         /* lower-numbered register; endian-independent */
+    kRegTypeLongHi,
+    kRegTypeDoubleLo,
+    kRegTypeDoubleHi,
+
+    /*
+     * Enumeration max; this is used with "full" (32-bit) RegType values.
+     *
+     * Anything larger than this is a ClassObject or uninit ref.  Mask off
+     * all but the low 8 bits; if you're left with kRegTypeUninit, pull
+     * the uninit index out of the high 24.  Because kRegTypeUninit has an
+     * odd value, there is no risk of a particular ClassObject pointer bit
+     * pattern being confused for it (assuming our class object allocator
+     * uses word alignment).
+     */
+    kRegTypeMAX
+};
+#define kRegTypeUninitMask  0xff
+#define kRegTypeUninitShift 8
+
+/*
+ * RegType holds information about the type of data held in a register.
+ * For most types it's a simple enum.  For reference types it holds a
+ * pointer to the ClassObject, and for uninitialized references it holds
+ * an index into the UninitInstanceMap.
+ */
+typedef u4 RegType;
+
+/*
+ * A bit vector indicating which entries in the monitor stack are
+ * associated with this register.  The low bit corresponds to the stack's
+ * bottom-most entry.
+ */
+typedef u4 MonitorEntries;
+#define kMaxMonitorStackDepth   (sizeof(MonitorEntries) * 8)
+
+/*
+ * During verification, we associate one of these with every "interesting"
+ * instruction.  We track the status of all registers, and (if the method
+ * has any monitor-enter instructions) maintain a stack of entered monitors
+ * (identified by code unit offset).
+ *
+ * If live-precise register maps are enabled, the "liveRegs" vector will
+ * be populated.  Unlike the other lists of registers here, we do not
+ * track the liveness of the method result register (which is not visible
+ * to the GC).
+ */
+struct RegisterLine {
+    RegType*        regTypes;
+    MonitorEntries* monitorEntries;
+    u4*             monitorStack;
+    unsigned int    monitorStackTop;
+    BitVector*      liveRegs;
+};
+
+/*
+ * Table that maps uninitialized instances to classes, based on the
+ * address of the new-instance instruction.  One per method.
+ */
+struct UninitInstanceMap {
+    int numEntries;
+    struct {
+        int             addr;   /* code offset, or -1 for method arg ("this") */
+        ClassObject*    clazz;  /* class created at this address */
+    } map[1];
+};
+#define kUninitThisArgAddr  (-1)
+#define kUninitThisArgSlot  0
+
+/*
+ * Various bits of data used by the verifier and register map generator.
+ */
+struct VerifierData {
+    /*
+     * The method we're working on.
+     */
+    const Method*   method;
+
+    /*
+     * Number of code units of instructions in the method.  A cache of the
+     * value calculated by dvmGetMethodInsnsSize().
+     */
+    u4              insnsSize;
+
+    /*
+     * Number of registers we track for each instruction.  This is equal
+     * to the method's declared "registersSize".  (Does not include the
+     * pending return value.)
+     */
+    u4              insnRegCount;
+
+    /*
+     * Instruction widths and flags, one entry per code unit.
+     */
+    InsnFlags*      insnFlags;
+
+    /*
+     * Uninitialized instance map, used for tracking the movement of
+     * objects that have been allocated but not initialized.
+     */
+    UninitInstanceMap* uninitMap;
+
+    /*
+     * Array of RegisterLine structs, one entry per code unit.  We only need
+     * entries for code units that hold the start of an "interesting"
+     * instruction.  For register map generation, we're only interested
+     * in GC points.
+     */
+    RegisterLine*   registerLines;
+
+    /*
+     * The number of occurrences of specific opcodes.
+     */
+    size_t          newInstanceCount;
+    size_t          monitorEnterCount;
+
+    /*
+     * Array of pointers to basic blocks, one entry per code unit.  Used
+     * for liveness analysis.
+     */
+    VfyBasicBlock** basicBlocks;
+};
+
+
+/* table with static merge logic for primitive types */
+extern const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX];
+
+
+/*
+ * Returns "true" if the flags indicate that this address holds the start
+ * of an instruction.
+ */
+INLINE bool dvmInsnIsOpcode(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & kInsnFlagWidthMask) != 0;
+}
+
+/*
+ * Extract the unsigned 16-bit instruction width from "flags".
+ */
+INLINE int dvmInsnGetWidth(const InsnFlags* insnFlags, int addr) {
+    return insnFlags[addr] & kInsnFlagWidthMask;
+}
+
+/*
+ * Changed?
+ */
+INLINE bool dvmInsnIsChanged(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & kInsnFlagChanged) != 0;
+}
+INLINE void dvmInsnSetChanged(InsnFlags* insnFlags, int addr, bool changed)
+{
+    if (changed)
+        insnFlags[addr] |= kInsnFlagChanged;
+    else
+        insnFlags[addr] &= ~kInsnFlagChanged;
+}
+
+/*
+ * Visited?
+ */
+INLINE bool dvmInsnIsVisited(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & kInsnFlagVisited) != 0;
+}
+INLINE void dvmInsnSetVisited(InsnFlags* insnFlags, int addr, bool changed)
+{
+    if (changed)
+        insnFlags[addr] |= kInsnFlagVisited;
+    else
+        insnFlags[addr] &= ~kInsnFlagVisited;
+}
+
+/*
+ * Visited or changed?
+ */
+INLINE bool dvmInsnIsVisitedOrChanged(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & (kInsnFlagVisited|kInsnFlagChanged)) != 0;
+}
+
+/*
+ * In a "try" block?
+ */
+INLINE bool dvmInsnIsInTry(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & kInsnFlagInTry) != 0;
+}
+INLINE void dvmInsnSetInTry(InsnFlags* insnFlags, int addr, bool inTry)
+{
+    assert(inTry);
+    //if (inTry)
+        insnFlags[addr] |= kInsnFlagInTry;
+    //else
+    //    insnFlags[addr] &= ~kInsnFlagInTry;
+}
+
+/*
+ * Instruction is a branch target or exception handler?
+ */
+INLINE bool dvmInsnIsBranchTarget(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & kInsnFlagBranchTarget) != 0;
+}
+INLINE void dvmInsnSetBranchTarget(InsnFlags* insnFlags, int addr,
+    bool isBranch)
+{
+    assert(isBranch);
+    //if (isBranch)
+        insnFlags[addr] |= kInsnFlagBranchTarget;
+    //else
+    //    insnFlags[addr] &= ~kInsnFlagBranchTarget;
+}
+
+/*
+ * Instruction is a GC point?
+ */
+INLINE bool dvmInsnIsGcPoint(const InsnFlags* insnFlags, int addr) {
+    return (insnFlags[addr] & kInsnFlagGcPoint) != 0;
+}
+INLINE void dvmInsnSetGcPoint(InsnFlags* insnFlags, int addr,
+    bool isGcPoint)
+{
+    assert(isGcPoint);
+    //if (isGcPoint)
+        insnFlags[addr] |= kInsnFlagGcPoint;
+    //else
+    //    insnFlags[addr] &= ~kInsnFlagGcPoint;
+}
+
+
+/*
+ * Create a new UninitInstanceMap.
+ */
+UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
+    const InsnFlags* insnFlags, int newInstanceCount);
+
+/*
+ * Release the storage associated with an UninitInstanceMap.
+ */
+void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap);
+
+/*
+ * Verify bytecode in "meth".  "insnFlags" should be populated with
+ * instruction widths and "in try" flags.
+ */
+bool dvmVerifyCodeFlow(VerifierData* vdata);
+
+#endif  // DALVIK_CODEVERIFY_H_
diff --git a/vm/analysis/DexPrepare.cpp b/vm/analysis/DexPrepare.cpp
new file mode 100644
index 0000000..e5c78d3
--- /dev/null
+++ b/vm/analysis/DexPrepare.cpp
@@ -0,0 +1,1562 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Prepare a DEX file for use by the VM.  Depending upon the VM options
+ * we will attempt to verify and/or optimize the code, possibly appending
+ * register maps.
+ *
+ * TODO: the format of the optimized header is currently "whatever we
+ * happen to write", since the VM that writes it is by definition the same
+ * as the VM that reads it.  Still, it should be better documented and
+ * more rigorously structured.
+ */
+#include "Dalvik.h"
+#include "libdex/OptInvocation.h"
+#include "analysis/RegisterMap.h"
+#include "analysis/Optimize.h"
+
+#include <string>
+
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <zlib.h>
+
+/* fwd */
+static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,
+    DexClassLookup** ppClassLookup, DvmDex** ppDvmDex);
+static bool loadAllClasses(DvmDex* pDvmDex);
+static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
+    bool doOpt);
+static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
+    const DexClassDef* pClassDef, bool doVerify, bool doOpt);
+static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
+static int writeDependencies(int fd, u4 modWhen, u4 crc);
+static bool writeOptData(int fd, const DexClassLookup* pClassLookup,\
+    const RegisterMapBuilder* pRegMapBuilder);
+static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
+
+/*
+ * Get just the directory portion of the given path. Equivalent to dirname(3).
+ */
+static std::string saneDirName(const std::string& path) {
+    size_t n = path.rfind('/');
+    if (n == std::string::npos) {
+        return ".";
+    }
+    return path.substr(0, n);
+}
+
+/*
+ * Helper for dvmOpenCacheDexFile() in a known-error case: Check to
+ * see if the directory part of the given path (all but the last
+ * component) exists and is writable. Complain to the log if not.
+ */
+static bool directoryIsValid(const std::string& fileName)
+{
+    std::string dirName(saneDirName(fileName));
+
+    struct stat sb;
+    if (stat(dirName.c_str(), &sb) < 0) {
+        LOGE("Could not stat dex cache directory '%s': %s", dirName.c_str(), strerror(errno));
+        return false;
+    }
+
+    if (!S_ISDIR(sb.st_mode)) {
+        LOGE("Dex cache directory isn't a directory: %s", dirName.c_str());
+        return false;
+    }
+
+    if (access(dirName.c_str(), W_OK) < 0) {
+        LOGE("Dex cache directory isn't writable: %s", dirName.c_str());
+        return false;
+    }
+
+    if (access(dirName.c_str(), R_OK) < 0) {
+        LOGE("Dex cache directory isn't readable: %s", dirName.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Return the fd of an open file in the DEX file cache area.  If the cache
+ * file doesn't exist or is out of date, this will remove the old entry,
+ * create a new one (writing only the file header), and return with the
+ * "new file" flag set.
+ *
+ * It's possible to execute from an unoptimized DEX file directly,
+ * assuming the byte ordering and structure alignment is correct, but
+ * disadvantageous because some significant optimizations are not possible.
+ * It's not generally possible to do the same from an uncompressed Jar
+ * file entry, because we have to guarantee 32-bit alignment in the
+ * memory-mapped file.
+ *
+ * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
+ * and "crc32" come from the Zip directory entry.  For a stand-alone DEX
+ * file, it's the modification date of the file and the Adler32 from the
+ * DEX header (which immediately follows the magic).  If these don't
+ * match what's stored in the opt header, we reject the file immediately.
+ *
+ * On success, the file descriptor will be positioned just past the "opt"
+ * file header, and will be locked with flock.  "*pCachedName" will point
+ * to newly-allocated storage.
+ */
+int dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
+    u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
+{
+    int fd, cc;
+    struct stat fdStat, fileStat;
+    bool readOnly = false;
+
+    *pNewFile = false;
+
+retry:
+    /*
+     * Try to open the cache file.  If we've been asked to,
+     * create it if it doesn't exist.
+     */
+    fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
+    if (fd < 0) {
+        fd = open(cacheFileName, O_RDONLY, 0);
+        if (fd < 0) {
+            if (createIfMissing) {
+                // TODO: write an equivalent of strerror_r that returns a std::string.
+                const std::string errnoString(strerror(errno));
+                if (directoryIsValid(cacheFileName)) {
+                    LOGE("Can't open dex cache file '%s': %s", cacheFileName, errnoString.c_str());
+                }
+            }
+            return fd;
+        }
+        readOnly = true;
+    } else {
+        fchmod(fd, 0644);
+    }
+
+    /*
+     * Grab an exclusive lock on the cache file.  If somebody else is
+     * working on it, we'll block here until they complete.  Because
+     * we're waiting on an external resource, we go into VMWAIT mode.
+     */
+    LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)",
+        cacheFileName, fd, isBootstrap);
+    ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
+    cc = flock(fd, LOCK_EX | LOCK_NB);
+    if (cc != 0) {
+        LOGD("DexOpt: sleeping on flock(%s)", cacheFileName);
+        cc = flock(fd, LOCK_EX);
+    }
+    dvmChangeStatus(NULL, oldStatus);
+    if (cc != 0) {
+        LOGE("Can't lock dex cache '%s': %d", cacheFileName, cc);
+        close(fd);
+        return -1;
+    }
+    LOGV("DexOpt:  locked cache file");
+
+    /*
+     * Check to see if the fd we opened and locked matches the file in
+     * the filesystem.  If they don't, then somebody else unlinked ours
+     * and created a new file, and we need to use that one instead.  (If
+     * we caught them between the unlink and the create, we'll get an
+     * ENOENT from the file stat.)
+     */
+    cc = fstat(fd, &fdStat);
+    if (cc != 0) {
+        LOGE("Can't stat open file '%s'", cacheFileName);
+        LOGVV("DexOpt: unlocking cache file %s", cacheFileName);
+        goto close_fail;
+    }
+    cc = stat(cacheFileName, &fileStat);
+    if (cc != 0 ||
+        fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
+    {
+        LOGD("DexOpt: our open cache file is stale; sleeping and retrying");
+        LOGVV("DexOpt: unlocking cache file %s", cacheFileName);
+        flock(fd, LOCK_UN);
+        close(fd);
+        usleep(250 * 1000);     /* if something is hosed, don't peg machine */
+        goto retry;
+    }
+
+    /*
+     * We have the correct file open and locked.  If the file size is zero,
+     * then it was just created by us, and we want to fill in some fields
+     * in the "opt" header and set "*pNewFile".  Otherwise, we want to
+     * verify that the fields in the header match our expectations, and
+     * reset the file if they don't.
+     */
+    if (fdStat.st_size == 0) {
+        if (readOnly) {
+            LOGW("DexOpt: file has zero length and isn't writable");
+            goto close_fail;
+        }
+        cc = dexOptCreateEmptyHeader(fd);
+        if (cc != 0)
+            goto close_fail;
+        *pNewFile = true;
+        LOGV("DexOpt: successfully initialized new cache file");
+    } else {
+        bool expectVerify, expectOpt;
+
+        if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
+            expectVerify = false;
+        } else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE) {
+            expectVerify = !isBootstrap;
+        } else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/ {
+            expectVerify = true;
+        }
+
+        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE) {
+            expectOpt = false;
+        } else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
+                   gDvm.dexOptMode == OPTIMIZE_MODE_FULL) {
+            expectOpt = expectVerify;
+        } else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/ {
+            expectOpt = true;
+        }
+
+        LOGV("checking deps, expecting vfy=%d opt=%d",
+            expectVerify, expectOpt);
+
+        if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
+                expectVerify, expectOpt))
+        {
+            if (readOnly) {
+                /*
+                 * We could unlink and rewrite the file if we own it or
+                 * the "sticky" bit isn't set on the directory.  However,
+                 * we're not able to truncate it, which spoils things.  So,
+                 * give up now.
+                 */
+                if (createIfMissing) {
+                    LOGW("Cached DEX '%s' (%s) is stale and not writable",
+                        fileName, cacheFileName);
+                }
+                goto close_fail;
+            }
+
+            /*
+             * If we truncate the existing file before unlinking it, any
+             * process that has it mapped will fail when it tries to touch
+             * the pages.
+             *
+             * This is very important.  The zygote process will have the
+             * boot DEX files (core, framework, etc.) mapped early.  If
+             * (say) core.dex gets updated, and somebody launches an app
+             * that uses App.dex, then App.dex gets reoptimized because it's
+             * dependent upon the boot classes.  However, dexopt will be
+             * using the *new* core.dex to do the optimizations, while the
+             * app will actually be running against the *old* core.dex
+             * because it starts from zygote.
+             *
+             * Even without zygote, it's still possible for a class loader
+             * to pull in an APK that was optimized against an older set
+             * of DEX files.  We must ensure that everything fails when a
+             * boot DEX gets updated, and for general "why aren't my
+             * changes doing anything" purposes its best if we just make
+             * everything crash when a DEX they're using gets updated.
+             */
+            LOGD("ODEX file is stale or bad; removing and retrying (%s)",
+                cacheFileName);
+            if (ftruncate(fd, 0) != 0) {
+                LOGW("Warning: unable to truncate cache file '%s': %s",
+                    cacheFileName, strerror(errno));
+                /* keep going */
+            }
+            if (unlink(cacheFileName) != 0) {
+                LOGW("Warning: unable to remove cache file '%s': %d %s",
+                    cacheFileName, errno, strerror(errno));
+                /* keep going; permission failure should probably be fatal */
+            }
+            LOGVV("DexOpt: unlocking cache file %s", cacheFileName);
+            flock(fd, LOCK_UN);
+            close(fd);
+            goto retry;
+        } else {
+            LOGV("DexOpt: good deps in cache file");
+        }
+    }
+
+    assert(fd >= 0);
+    return fd;
+
+close_fail:
+    flock(fd, LOCK_UN);
+    close(fd);
+    return -1;
+}
+
+/*
+ * Unlock the file descriptor.
+ *
+ * Returns "true" on success.
+ */
+bool dvmUnlockCachedDexFile(int fd)
+{
+    LOGVV("DexOpt: unlocking cache file fd=%d", fd);
+    return (flock(fd, LOCK_UN) == 0);
+}
+
+
+/*
+ * Given a descriptor for a file with DEX data in it, produce an
+ * optimized version.
+ *
+ * The file pointed to by "fd" is expected to be a locked shared resource
+ * (or private); we make no efforts to enforce multi-process correctness
+ * here.
+ *
+ * "fileName" is only used for debug output.  "modWhen" and "crc" are stored
+ * in the dependency set.
+ *
+ * The "isBootstrap" flag determines how the optimizer and verifier handle
+ * package-scope access checks.  When optimizing, we only load the bootstrap
+ * class DEX files and the target DEX, so the flag determines whether the
+ * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
+ * This only really matters if the target DEX contains classes that claim to
+ * be in the same package as bootstrap classes.
+ *
+ * The optimizer will need to load every class in the target DEX file.
+ * This is generally undesirable, so we start a subprocess to do the
+ * work and wait for it to complete.
+ *
+ * Returns "true" on success.  All data will have been written to "fd".
+ */
+bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
+    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
+{
+    const char* lastPart = strrchr(fileName, '/');
+    if (lastPart != NULL)
+        lastPart++;
+    else
+        lastPart = fileName;
+
+    LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---", lastPart, isBootstrap);
+
+    pid_t pid;
+
+    /*
+     * This could happen if something in our bootclasspath, which we thought
+     * was all optimized, got rejected.
+     */
+    if (gDvm.optimizing) {
+        LOGW("Rejecting recursive optimization attempt on '%s'", fileName);
+        return false;
+    }
+
+    pid = fork();
+    if (pid == 0) {
+        static const int kUseValgrind = 0;
+        static const char* kDexOptBin = "/bin/dexopt";
+        static const char* kValgrinder = "/usr/bin/valgrind";
+        static const int kFixedArgCount = 10;
+        static const int kValgrindArgCount = 5;
+        static const int kMaxIntLen = 12;   // '-'+10dig+'\0' -OR- 0x+8dig
+        int bcpSize = dvmGetBootPathSize();
+        int argc = kFixedArgCount + bcpSize
+            + (kValgrindArgCount * kUseValgrind);
+        const char* argv[argc+1];             // last entry is NULL
+        char values[argc][kMaxIntLen];
+        char* execFile;
+        const char* androidRoot;
+        int flags;
+
+        /* change process groups, so we don't clash with ProcessManager */
+        setpgid(0, 0);
+
+        /* full path to optimizer */
+        androidRoot = getenv("ANDROID_ROOT");
+        if (androidRoot == NULL) {
+            LOGW("ANDROID_ROOT not set, defaulting to /system");
+            androidRoot = "/system";
+        }
+        execFile = (char*)alloca(strlen(androidRoot) + strlen(kDexOptBin) + 1);
+        strcpy(execFile, androidRoot);
+        strcat(execFile, kDexOptBin);
+
+        /*
+         * Create arg vector.
+         */
+        int curArg = 0;
+
+        if (kUseValgrind) {
+            /* probably shouldn't ship the hard-coded path */
+            argv[curArg++] = (char*)kValgrinder;
+            argv[curArg++] = "--tool=memcheck";
+            argv[curArg++] = "--leak-check=yes";        // check for leaks too
+            argv[curArg++] = "--leak-resolution=med";   // increase from 2 to 4
+            argv[curArg++] = "--num-callers=16";        // default is 12
+            assert(curArg == kValgrindArgCount);
+        }
+        argv[curArg++] = execFile;
+
+        argv[curArg++] = "--dex";
+
+        sprintf(values[2], "%d", DALVIK_VM_BUILD);
+        argv[curArg++] = values[2];
+
+        sprintf(values[3], "%d", fd);
+        argv[curArg++] = values[3];
+
+        sprintf(values[4], "%d", (int) dexOffset);
+        argv[curArg++] = values[4];
+
+        sprintf(values[5], "%d", (int) dexLength);
+        argv[curArg++] = values[5];
+
+        argv[curArg++] = (char*)fileName;
+
+        sprintf(values[7], "%d", (int) modWhen);
+        argv[curArg++] = values[7];
+
+        sprintf(values[8], "%d", (int) crc);
+        argv[curArg++] = values[8];
+
+        flags = 0;
+        if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
+            flags |= DEXOPT_OPT_ENABLED;
+            if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
+                flags |= DEXOPT_OPT_ALL;
+        }
+        if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
+            flags |= DEXOPT_VERIFY_ENABLED;
+            if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
+                flags |= DEXOPT_VERIFY_ALL;
+        }
+        if (isBootstrap)
+            flags |= DEXOPT_IS_BOOTSTRAP;
+        if (gDvm.generateRegisterMaps)
+            flags |= DEXOPT_GEN_REGISTER_MAPS;
+        sprintf(values[9], "%d", flags);
+        argv[curArg++] = values[9];
+
+        assert(((!kUseValgrind && curArg == kFixedArgCount) ||
+               ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
+
+        ClassPathEntry* cpe;
+        for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+            argv[curArg++] = cpe->fileName;
+        }
+        assert(curArg == argc);
+
+        argv[curArg] = NULL;
+
+        if (kUseValgrind)
+            execv(kValgrinder, const_cast<char**>(argv));
+        else
+            execv(execFile, const_cast<char**>(argv));
+
+        LOGE("execv '%s'%s failed: %s", execFile,
+            kUseValgrind ? " [valgrind]" : "", strerror(errno));
+        exit(1);
+    } else {
+        LOGV("DexOpt: waiting for verify+opt, pid=%d", (int) pid);
+        int status;
+        pid_t gotPid;
+
+        /*
+         * Wait for the optimization process to finish.  We go into VMWAIT
+         * mode here so GC suspension won't have to wait for us.
+         */
+        ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
+        while (true) {
+            gotPid = waitpid(pid, &status, 0);
+            if (gotPid == -1 && errno == EINTR) {
+                LOGD("waitpid interrupted, retrying");
+            } else {
+                break;
+            }
+        }
+        dvmChangeStatus(NULL, oldStatus);
+        if (gotPid != pid) {
+            LOGE("waitpid failed: wanted %d, got %d: %s",
+                (int) pid, (int) gotPid, strerror(errno));
+            return false;
+        }
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            LOGD("DexOpt: --- END '%s' (success) ---", lastPart);
+            return true;
+        } else {
+            LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed",
+                lastPart, status);
+            return false;
+        }
+    }
+}
+
+/*
+ * Do the actual optimization.  This is executed in the dexopt process.
+ *
+ * For best use of disk/memory, we want to extract once and perform
+ * optimizations in place.  If the file has to expand or contract
+ * to match local structure padding/alignment expectations, we want
+ * to do the rewrite as part of the extract, rather than extracting
+ * into a temp file and slurping it back out.  (The structure alignment
+ * is currently correct for all platforms, and this isn't expected to
+ * change, so we should be okay with having it already extracted.)
+ *
+ * Returns "true" on success.
+ */
+bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
+    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
+{
+    DexClassLookup* pClassLookup = NULL;
+    RegisterMapBuilder* pRegMapBuilder = NULL;
+
+    assert(gDvm.optimizing);
+
+    LOGV("Continuing optimization (%s, isb=%d)", fileName, isBootstrap);
+
+    assert(dexOffset >= 0);
+
+    /* quick test so we don't blow up on empty file */
+    if (dexLength < (int) sizeof(DexHeader)) {
+        LOGE("too small to be DEX");
+        return false;
+    }
+    if (dexOffset < (int) sizeof(DexOptHeader)) {
+        LOGE("not enough room for opt header");
+        return false;
+    }
+
+    bool result = false;
+
+    /*
+     * Drop this into a global so we don't have to pass it around.  We could
+     * also add a field to DexFile, but since it only pertains to DEX
+     * creation that probably doesn't make sense.
+     */
+    gDvm.optimizingBootstrapClass = isBootstrap;
+
+    {
+        /*
+         * Map the entire file (so we don't have to worry about page
+         * alignment).  The expectation is that the output file contains
+         * our DEX data plus room for a small header.
+         */
+        bool success;
+        void* mapAddr;
+        mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
+                    MAP_SHARED, fd, 0);
+        if (mapAddr == MAP_FAILED) {
+            LOGE("unable to mmap DEX cache: %s", strerror(errno));
+            goto bail;
+        }
+
+        bool doVerify, doOpt;
+        if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
+            doVerify = false;
+        } else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE) {
+            doVerify = !gDvm.optimizingBootstrapClass;
+        } else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/ {
+            doVerify = true;
+        }
+
+        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE) {
+            doOpt = false;
+        } else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
+                   gDvm.dexOptMode == OPTIMIZE_MODE_FULL) {
+            doOpt = doVerify;
+        } else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/ {
+            doOpt = true;
+        }
+
+        /*
+         * 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 creates the class lookup table as part of doing the processing.
+         */
+        success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
+                    doVerify, doOpt, &pClassLookup, NULL);
+
+        if (success) {
+            DvmDex* pDvmDex = NULL;
+            u1* dexAddr = ((u1*) mapAddr) + dexOffset;
+
+            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
+                LOGE("Unable to create DexFile");
+                success = false;
+            } else {
+                /*
+                 * If configured to do so, generate register map output
+                 * for all verified classes.  The register maps were
+                 * generated during verification, and will now be serialized.
+                 */
+                if (gDvm.generateRegisterMaps) {
+                    pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
+                    if (pRegMapBuilder == NULL) {
+                        LOGE("Failed generating register maps");
+                        success = false;
+                    }
+                }
+
+                DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
+                updateChecksum(dexAddr, dexLength, pHeader);
+
+                dvmDexFileFree(pDvmDex);
+            }
+        }
+
+        /* unmap the read-write version, forcing writes to disk */
+        if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
+            LOGW("msync failed: %s", strerror(errno));
+            // weird, but keep going
+        }
+#if 1
+        /*
+         * This causes clean shutdown to fail, because we have loaded classes
+         * that point into it.  For the optimizer this isn't a problem,
+         * because it's more efficient for the process to simply exit.
+         * Exclude this code when doing clean shutdown for valgrind.
+         */
+        if (munmap(mapAddr, dexOffset + dexLength) != 0) {
+            LOGE("munmap failed: %s", strerror(errno));
+            goto bail;
+        }
+#endif
+
+        if (!success)
+            goto bail;
+    }
+
+    /* get start offset, and adjust deps start for 64-bit alignment */
+    off_t depsOffset, optOffset, endOffset, adjOffset;
+    int depsLength, optLength;
+    u4 optChecksum;
+
+    depsOffset = lseek(fd, 0, SEEK_END);
+    if (depsOffset < 0) {
+        LOGE("lseek to EOF failed: %s", strerror(errno));
+        goto bail;
+    }
+    adjOffset = (depsOffset + 7) & ~(0x07);
+    if (adjOffset != depsOffset) {
+        LOGV("Adjusting deps start from %d to %d",
+            (int) depsOffset, (int) adjOffset);
+        depsOffset = adjOffset;
+        lseek(fd, depsOffset, SEEK_SET);
+    }
+
+    /*
+     * Append the dependency list.
+     */
+    if (writeDependencies(fd, modWhen, crc) != 0) {
+        LOGW("Failed writing dependencies");
+        goto bail;
+    }
+
+    /* compute deps length, then adjust opt start for 64-bit alignment */
+    optOffset = lseek(fd, 0, SEEK_END);
+    depsLength = optOffset - depsOffset;
+
+    adjOffset = (optOffset + 7) & ~(0x07);
+    if (adjOffset != optOffset) {
+        LOGV("Adjusting opt start from %d to %d",
+            (int) optOffset, (int) adjOffset);
+        optOffset = adjOffset;
+        lseek(fd, optOffset, SEEK_SET);
+    }
+
+    /*
+     * Append any optimized pre-computed data structures.
+     */
+    if (!writeOptData(fd, pClassLookup, pRegMapBuilder)) {
+        LOGW("Failed writing opt data");
+        goto bail;
+    }
+
+    endOffset = lseek(fd, 0, SEEK_END);
+    optLength = endOffset - optOffset;
+
+    /* compute checksum from start of deps to end of opt area */
+    if (!computeFileChecksum(fd, depsOffset,
+            (optOffset+optLength) - depsOffset, &optChecksum))
+    {
+        goto bail;
+    }
+
+    /*
+     * Output the "opt" header with all values filled in and a correct
+     * magic number.
+     */
+    DexOptHeader optHdr;
+    memset(&optHdr, 0xff, sizeof(optHdr));
+    memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
+    memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
+    optHdr.dexOffset = (u4) dexOffset;
+    optHdr.dexLength = (u4) dexLength;
+    optHdr.depsOffset = (u4) depsOffset;
+    optHdr.depsLength = (u4) depsLength;
+    optHdr.optOffset = (u4) optOffset;
+    optHdr.optLength = (u4) optLength;
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+    optHdr.flags = DEX_OPT_FLAG_BIG;
+#else
+    optHdr.flags = 0;
+#endif
+    optHdr.checksum = optChecksum;
+
+    fsync(fd);      /* ensure previous writes go before header is written */
+
+    lseek(fd, 0, SEEK_SET);
+    if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
+        goto bail;
+
+    LOGV("Successfully wrote DEX header");
+    result = true;
+
+    //dvmRegisterMapDumpStats();
+
+bail:
+    dvmFreeRegisterMapBuilder(pRegMapBuilder);
+    free(pClassLookup);
+    return result;
+}
+
+/*
+ * Prepare an in-memory DEX file.
+ *
+ * The data was presented to the VM as a byte array rather than a file.
+ * We want to do the same basic set of operations, but we can just leave
+ * them in memory instead of writing them out to a cached optimized DEX file.
+ */
+bool dvmPrepareDexInMemory(u1* addr, size_t len, DvmDex** ppDvmDex)
+{
+    DexClassLookup* pClassLookup = NULL;
+
+    /*
+     * Byte-swap, realign, verify basic DEX file structure.
+     *
+     * We could load + verify + optimize here as well, but that's probably
+     * not desirable.
+     *
+     * (The bulk-verification code is currently only setting the DEX
+     * file's "verified" flag, not updating the ClassObject.  This would
+     * also need to be changed, or we will try to verify the class twice,
+     * and possibly reject it when optimized opcodes are encountered.)
+     */
+    if (!rewriteDex(addr, len, false, false, &pClassLookup, ppDvmDex)) {
+        return false;
+    }
+
+    (*ppDvmDex)->pDexFile->pClassLookup = pClassLookup;
+
+    return true;
+}
+
+/*
+ * Perform in-place rewrites on a memory-mapped DEX file.
+ *
+ * If this is called from a short-lived child process (dexopt), we can
+ * go nutty with loading classes and allocating memory.  When it's
+ * called to prepare classes provided in a byte array, we may want to
+ * be more conservative.
+ *
+ * If "ppClassLookup" is non-NULL, a pointer to a newly-allocated
+ * DexClassLookup will be returned on success.
+ *
+ * If "ppDvmDex" is non-NULL, a newly-allocated DvmDex struct will be
+ * returned on success.
+ */
+static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,
+    DexClassLookup** ppClassLookup, DvmDex** ppDvmDex)
+{
+    DexClassLookup* pClassLookup = NULL;
+    u8 prepWhen, loadWhen, verifyOptWhen;
+    DvmDex* pDvmDex = NULL;
+    bool result = false;
+    const char* msgStr = "???";
+
+    /* if the DEX is in the wrong byte order, swap it now */
+    if (dexSwapAndVerify(addr, len) != 0)
+        goto bail;
+
+    /*
+     * Now that the DEX file can be read directly, create a DexFile struct
+     * for it.
+     */
+    if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
+        LOGE("Unable to create DexFile");
+        goto bail;
+    }
+
+    /*
+     * Create the class lookup table.  This will eventually be appended
+     * to the end of the .odex.
+     *
+     * We create a temporary link from the DexFile for the benefit of
+     * class loading, below.
+     */
+    pClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
+    if (pClassLookup == NULL)
+        goto bail;
+    pDvmDex->pDexFile->pClassLookup = pClassLookup;
+
+    /*
+     * If we're not going to attempt to verify or optimize the classes,
+     * there's no value in loading them, so bail out early.
+     */
+    if (!doVerify && !doOpt) {
+        result = true;
+        goto bail;
+    }
+
+    prepWhen = dvmGetRelativeTimeUsec();
+
+    /*
+     * Load all classes found in this DEX file.  If they fail to load for
+     * some reason, they won't get verified (which is as it should be).
+     */
+    if (!loadAllClasses(pDvmDex))
+        goto bail;
+    loadWhen = dvmGetRelativeTimeUsec();
+
+    /*
+     * Create a data structure for use by the bytecode optimizer.
+     * We need to look up methods in a few classes, so this may cause
+     * a bit of class loading.  We usually do this during VM init, but
+     * for dexopt on core.jar the order of operations gets a bit tricky,
+     * so we defer it to here.
+     */
+    if (!dvmCreateInlineSubsTable())
+        goto bail;
+
+    /*
+     * Verify and optimize all classes in the DEX file (command-line
+     * options permitting).
+     *
+     * This is best-effort, so there's really no way for dexopt to
+     * fail at this point.
+     */
+    verifyAndOptimizeClasses(pDvmDex->pDexFile, doVerify, doOpt);
+    verifyOptWhen = dvmGetRelativeTimeUsec();
+
+    if (doVerify && doOpt)
+        msgStr = "verify+opt";
+    else if (doVerify)
+        msgStr = "verify";
+    else if (doOpt)
+        msgStr = "opt";
+    LOGD("DexOpt: load %dms, %s %dms",
+        (int) (loadWhen - prepWhen) / 1000,
+        msgStr,
+        (int) (verifyOptWhen - loadWhen) / 1000);
+
+    result = true;
+
+bail:
+    /*
+     * On success, return the pieces that the caller asked for.
+     */
+
+    if (pDvmDex != NULL) {
+        /* break link between the two */
+        pDvmDex->pDexFile->pClassLookup = NULL;
+    }
+
+    if (ppDvmDex == NULL || !result) {
+        dvmDexFileFree(pDvmDex);
+    } else {
+        *ppDvmDex = pDvmDex;
+    }
+
+    if (ppClassLookup == NULL || !result) {
+        free(pClassLookup);
+    } else {
+        *ppClassLookup = pClassLookup;
+    }
+
+    return result;
+}
+
+/*
+ * Try to load all classes in the specified DEX.  If they have some sort
+ * of broken dependency, e.g. their superclass lives in a different DEX
+ * that wasn't previously loaded into the bootstrap class path, loading
+ * will fail.  This is the desired behavior.
+ *
+ * We have no notion of class loader at this point, so we load all of
+ * the classes with the bootstrap class loader.  It turns out this has
+ * exactly the behavior we want, and has no ill side effects because we're
+ * running in a separate process and anything we load here will be forgotten.
+ *
+ * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
+ * This works because we only call here as part of optimization / pre-verify,
+ * not during verification as part of loading a class into a running VM.
+ *
+ * This returns "false" if the world is too screwed up to do anything
+ * useful at all.
+ */
+static bool loadAllClasses(DvmDex* pDvmDex)
+{
+    u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
+    u4 idx;
+    int loaded = 0;
+
+    LOGV("DexOpt: +++ trying to load %d classes", count);
+
+    dvmSetBootPathExtraDex(pDvmDex);
+
+    /*
+     * At this point, it is safe -- and necessary! -- to look up the
+     * VM's required classes and members, even when what we are in the
+     * process of processing is the core library that defines these
+     * classes itself. (The reason it is necessary is that in the act
+     * of initializing the class Class, below, the system will end up
+     * referring to many of the class references that got set up by
+     * this call.)
+     */
+    if (!dvmFindRequiredClassesAndMembers()) {
+        return false;
+    }
+
+    /*
+     * We have some circularity issues with Class and Object that are
+     * most easily avoided by ensuring that Object is never the first
+     * thing we try to find-and-initialize. The call to
+     * dvmFindSystemClass() here takes care of that situation. (We
+     * only need to do this when loading classes from the DEX file
+     * that contains Object, and only when Object comes first in the
+     * list, but it costs very little to do it in all cases.)
+     */
+    if (!dvmInitClass(gDvm.classJavaLangClass)) {
+        LOGE("ERROR: failed to initialize the class Class!");
+        return false;
+    }
+
+    for (idx = 0; idx < count; idx++) {
+        const DexClassDef* pClassDef;
+        const char* classDescriptor;
+        ClassObject* newClass;
+
+        pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
+        classDescriptor =
+            dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
+
+        LOGV("+++  loading '%s'", classDescriptor);
+        //newClass = dvmDefineClass(pDexFile, classDescriptor,
+        //        NULL);
+        newClass = dvmFindSystemClassNoInit(classDescriptor);
+        if (newClass == NULL) {
+            LOGV("DexOpt: failed loading '%s'", classDescriptor);
+            dvmClearOptException(dvmThreadSelf());
+        } else if (newClass->pDvmDex != pDvmDex) {
+            /*
+             * We don't load the new one, and we tag the first one found
+             * with the "multiple def" flag so the resolver doesn't try
+             * to make it available.
+             */
+            LOGD("DexOpt: '%s' has an earlier definition; blocking out",
+                classDescriptor);
+            SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
+        } else {
+            loaded++;
+        }
+    }
+    LOGV("DexOpt: +++ successfully loaded %d classes", loaded);
+
+    dvmSetBootPathExtraDex(NULL);
+    return true;
+}
+
+/*
+ * Verify and/or optimize all classes that were successfully loaded from
+ * this DEX file.
+ */
+static void verifyAndOptimizeClasses(DexFile* pDexFile, bool doVerify,
+    bool doOpt)
+{
+    u4 count = pDexFile->pHeader->classDefsSize;
+    u4 idx;
+
+    for (idx = 0; idx < count; idx++) {
+        const DexClassDef* pClassDef;
+        const char* classDescriptor;
+        ClassObject* clazz;
+
+        pClassDef = dexGetClassDef(pDexFile, idx);
+        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+        /* all classes are loaded into the bootstrap class loader */
+        clazz = dvmLookupClass(classDescriptor, NULL, false);
+        if (clazz != NULL) {
+            verifyAndOptimizeClass(pDexFile, clazz, pClassDef, doVerify, doOpt);
+
+        } else {
+            // TODO: log when in verbose mode
+            LOGV("DexOpt: not optimizing unavailable class '%s'",
+                classDescriptor);
+        }
+    }
+
+#ifdef VERIFIER_STATS
+    LOGI("Verifier stats:");
+    LOGI(" methods examined        : %u", gDvm.verifierStats.methodsExamined);
+    LOGI(" monitor-enter methods   : %u", gDvm.verifierStats.monEnterMethods);
+    LOGI(" instructions examined   : %u", gDvm.verifierStats.instrsExamined);
+    LOGI(" instructions re-examined: %u", gDvm.verifierStats.instrsReexamined);
+    LOGI(" copying of register sets: %u", gDvm.verifierStats.copyRegCount);
+    LOGI(" merging of register sets: %u", gDvm.verifierStats.mergeRegCount);
+    LOGI(" ...that caused changes  : %u", gDvm.verifierStats.mergeRegChanged);
+    LOGI(" uninit searches         : %u", gDvm.verifierStats.uninitSearches);
+    LOGI(" max memory required     : %u", gDvm.verifierStats.biggestAlloc);
+#endif
+}
+
+/*
+ * Verify and/or optimize a specific class.
+ */
+static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
+    const DexClassDef* pClassDef, bool doVerify, bool doOpt)
+{
+    const char* classDescriptor;
+    bool verified = false;
+
+    if (clazz->pDvmDex->pDexFile != pDexFile) {
+        /*
+         * The current DEX file defined a class that is also present in the
+         * bootstrap class path.  The class loader favored the bootstrap
+         * version, which means that we have a pointer to a class that is
+         * (a) not the one we want to examine, and (b) mapped read-only,
+         * so we will seg fault if we try to rewrite instructions inside it.
+         */
+        LOGD("DexOpt: not verifying/optimizing '%s': multiple definitions",
+            clazz->descriptor);
+        return;
+    }
+
+    classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+    /*
+     * First, try to verify it.
+     */
+    if (doVerify) {
+        if (dvmVerifyClass(clazz)) {
+            /*
+             * Set the "is preverified" flag in the DexClassDef.  We
+             * do it here, rather than in the ClassObject structure,
+             * because the DexClassDef is part of the odex file.
+             */
+            assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
+                pClassDef->accessFlags);
+            ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED;
+            verified = true;
+        } else {
+            // TODO: log when in verbose mode
+            LOGV("DexOpt: '%s' failed verification", classDescriptor);
+        }
+    }
+
+    if (doOpt) {
+        bool needVerify = (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
+                           gDvm.dexOptMode == OPTIMIZE_MODE_FULL);
+        if (!verified && needVerify) {
+            LOGV("DexOpt: not optimizing '%s': not verified",
+                classDescriptor);
+        } else {
+            dvmOptimizeClass(clazz, false);
+
+            /* set the flag whether or not we actually changed anything */
+            ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISOPTIMIZED;
+        }
+    }
+}
+
+
+/*
+ * Get the cache file name from a ClassPathEntry.
+ */
+static const char* getCacheFileName(const ClassPathEntry* cpe)
+{
+    switch (cpe->kind) {
+    case kCpeJar:
+        return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
+    case kCpeDex:
+        return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
+    default:
+        LOGE("DexOpt: unexpected cpe kind %d", cpe->kind);
+        dvmAbort();
+        return NULL;
+    }
+}
+
+/*
+ * Get the SHA-1 signature.
+ */
+static const u1* getSignature(const ClassPathEntry* cpe)
+{
+    DvmDex* pDvmDex;
+
+    switch (cpe->kind) {
+    case kCpeJar:
+        pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
+        break;
+    case kCpeDex:
+        pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
+        break;
+    default:
+        LOGE("unexpected cpe kind %d", cpe->kind);
+        dvmAbort();
+        pDvmDex = NULL;         // make gcc happy
+    }
+
+    assert(pDvmDex != NULL);
+    return pDvmDex->pDexFile->pHeader->signature;
+}
+
+
+/*
+ * Dependency layout:
+ *  4b  Source file modification time, in seconds since 1970 UTC
+ *  4b  CRC-32 from Zip entry, or Adler32 from source DEX header
+ *  4b  Dalvik VM build number
+ *  4b  Number of dependency entries that follow
+ *  Dependency entries:
+ *    4b  Name length (including terminating null)
+ *    var Full path of cache entry (null terminated)
+ *    20b SHA-1 signature from source DEX file
+ *
+ * If this changes, update DEX_OPT_MAGIC_VERS.
+ */
+static const size_t kMinDepSize = 4 * 4;
+static const size_t kMaxDepSize = 4 * 4 + 2048;     // sanity check
+
+/*
+ * Read the "opt" header, verify it, then read the dependencies section
+ * and verify that data as well.
+ *
+ * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
+ * match up with what is stored in the header.  If they don't, we reject
+ * the file so that it can be recreated from the updated original.  If
+ * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
+ *
+ * On successful return, the file will be seeked immediately past the
+ * "opt" header.
+ */
+bool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
+    u4 crc, bool expectVerify, bool expectOpt)
+{
+    DexOptHeader optHdr;
+    u1* depData = NULL;
+    const u1* magic;
+    off_t posn;
+    int result = false;
+    ssize_t actual;
+
+    /*
+     * Start at the start.  The "opt" header, when present, will always be
+     * the first thing in the file.
+     */
+    if (lseek(fd, 0, SEEK_SET) != 0) {
+        LOGE("DexOpt: failed to seek to start of file: %s", strerror(errno));
+        goto bail;
+    }
+
+    /*
+     * Read and do trivial verification on the opt header.  The header is
+     * always in host byte order.
+     */
+    actual = read(fd, &optHdr, sizeof(optHdr));
+    if (actual < 0) {
+        LOGE("DexOpt: failed reading opt header: %s", strerror(errno));
+        goto bail;
+    } else if (actual != sizeof(optHdr)) {
+        LOGE("DexOpt: failed reading opt header (got %d of %zd)",
+            (int) actual, sizeof(optHdr));
+        goto bail;
+    }
+
+    magic = optHdr.magic;
+    if (memcmp(magic, DEX_MAGIC, 4) == 0) {
+        /* somebody probably pointed us at the wrong file */
+        LOGD("DexOpt: expected optimized DEX, found unoptimized");
+        goto bail;
+    } else if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
+        /* not a DEX file, or previous attempt was interrupted */
+        LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)",
+            magic[0], magic[1], magic[2], magic[3]);
+        goto bail;
+    }
+    if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
+        LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)",
+            magic[4], magic[5], magic[6], magic[7]);
+        goto bail;
+    }
+    if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
+        LOGW("DexOpt: weird deps length %d, bailing", optHdr.depsLength);
+        goto bail;
+    }
+
+    /*
+     * Do the header flags match up with what we want?
+     *
+     * The only thing we really can't handle is incorrect byte ordering.
+     */
+    {
+        const u4 matchMask = DEX_OPT_FLAG_BIG;
+        u4 expectedFlags = 0;
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+        expectedFlags |= DEX_OPT_FLAG_BIG;
+#endif
+        if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
+            LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)",
+                expectedFlags, optHdr.flags, matchMask);
+            goto bail;
+        }
+    }
+
+    posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
+    if (posn < 0) {
+        LOGW("DexOpt: seek to deps failed: %s", strerror(errno));
+        goto bail;
+    }
+
+    /*
+     * Read all of the dependency stuff into memory.
+     */
+    depData = (u1*) malloc(optHdr.depsLength);
+    if (depData == NULL) {
+        LOGW("DexOpt: unable to allocate %d bytes for deps",
+            optHdr.depsLength);
+        goto bail;
+    }
+    actual = read(fd, depData, optHdr.depsLength);
+    if (actual < 0) {
+        LOGW("DexOpt: failed reading deps: %s", strerror(errno));
+        goto bail;
+    } else if (actual != (ssize_t) optHdr.depsLength) {
+        LOGW("DexOpt: failed reading deps: got %d of %d",
+            (int) actual, optHdr.depsLength);
+        goto bail;
+    }
+
+    /*
+     * Verify simple items.
+     */
+    const u1* ptr;
+    u4 val;
+
+    ptr = depData;
+    val = read4LE(&ptr);
+    if (sourceAvail && val != modWhen) {
+        LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)",
+            val, modWhen);
+        goto bail;
+    }
+    val = read4LE(&ptr);
+    if (sourceAvail && val != crc) {
+        LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)", val, crc);
+        goto bail;
+    }
+    val = read4LE(&ptr);
+    if (val != DALVIK_VM_BUILD) {
+        LOGD("DexOpt: VM build version mismatch (%d vs %d)",
+            val, DALVIK_VM_BUILD);
+        goto bail;
+    }
+
+    /*
+     * Verify dependencies on other cached DEX files.  It must match
+     * exactly with what is currently defined in the bootclasspath.
+     */
+    ClassPathEntry* cpe;
+    u4 numDeps;
+
+    numDeps = read4LE(&ptr);
+    LOGV("+++ DexOpt: numDeps = %d", numDeps);
+    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+        const char* cacheFileName =
+            dvmPathToAbsolutePortion(getCacheFileName(cpe));
+        assert(cacheFileName != NULL); /* guaranteed by Class.c */
+
+        const u1* signature = getSignature(cpe);
+        size_t len = strlen(cacheFileName) +1;
+        u4 storedStrLen;
+
+        if (numDeps == 0) {
+            /* more entries in bootclasspath than in deps list */
+            LOGI("DexOpt: not all deps represented");
+            goto bail;
+        }
+
+        storedStrLen = read4LE(&ptr);
+        if (len != storedStrLen ||
+            strcmp(cacheFileName, (const char*) ptr) != 0)
+        {
+            LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'",
+                cacheFileName, ptr);
+            goto bail;
+        }
+
+        ptr += storedStrLen;
+
+        if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
+            LOGI("DexOpt: mismatch dep signature for '%s'", cacheFileName);
+            goto bail;
+        }
+        ptr += kSHA1DigestLen;
+
+        LOGV("DexOpt: dep match on '%s'", cacheFileName);
+
+        numDeps--;
+    }
+
+    if (numDeps != 0) {
+        /* more entries in deps list than in classpath */
+        LOGI("DexOpt: Some deps went away");
+        goto bail;
+    }
+
+    // consumed all data and no more?
+    if (ptr != depData + optHdr.depsLength) {
+        LOGW("DexOpt: Spurious dep data? %d vs %d",
+            (int) (ptr - depData), optHdr.depsLength);
+        assert(false);
+    }
+
+    result = true;
+
+bail:
+    free(depData);
+    return result;
+}
+
+/*
+ * Write the dependency info to "fd" at the current file position.
+ */
+static int writeDependencies(int fd, u4 modWhen, u4 crc)
+{
+    u1* buf = NULL;
+    int result = -1;
+    ssize_t bufLen;
+    ClassPathEntry* cpe;
+    int numDeps;
+
+    /*
+     * Count up the number of completed entries in the bootclasspath.
+     */
+    numDeps = 0;
+    bufLen = 0;
+    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+        const char* cacheFileName =
+            dvmPathToAbsolutePortion(getCacheFileName(cpe));
+        assert(cacheFileName != NULL); /* guaranteed by Class.c */
+
+        LOGV("+++ DexOpt: found dep '%s'", cacheFileName);
+
+        numDeps++;
+        bufLen += strlen(cacheFileName) +1;
+    }
+
+    bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
+
+    buf = (u1*)malloc(bufLen);
+
+    set4LE(buf+0, modWhen);
+    set4LE(buf+4, crc);
+    set4LE(buf+8, DALVIK_VM_BUILD);
+    set4LE(buf+12, numDeps);
+
+    // TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
+    // help us if somebody replaces an existing entry, but it'd catch
+    // additions/removals.
+
+    u1* ptr = buf + 4*4;
+    for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
+        const char* cacheFileName =
+            dvmPathToAbsolutePortion(getCacheFileName(cpe));
+        assert(cacheFileName != NULL); /* guaranteed by Class.c */
+
+        const u1* signature = getSignature(cpe);
+        int len = strlen(cacheFileName) +1;
+
+        if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
+            LOGE("DexOpt: overran buffer");
+            dvmAbort();
+        }
+
+        set4LE(ptr, len);
+        ptr += 4;
+        memcpy(ptr, cacheFileName, len);
+        ptr += len;
+        memcpy(ptr, signature, kSHA1DigestLen);
+        ptr += kSHA1DigestLen;
+    }
+
+    assert(ptr == buf + bufLen);
+
+    result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
+
+    free(buf);
+    return result;
+}
+
+
+/*
+ * Write a block of data in "chunk" format.
+ *
+ * The chunk header fields are always in "native" byte order.  If "size"
+ * is not a multiple of 8 bytes, the data area is padded out.
+ */
+static bool writeChunk(int fd, u4 type, const void* data, size_t size)
+{
+    union {             /* save a syscall by grouping these together */
+        char raw[8];
+        struct {
+            u4 type;
+            u4 size;
+        } ts;
+    } header;
+
+    assert(sizeof(header) == 8);
+
+    LOGV("Writing chunk, type=%.4s size=%d", (char*) &type, size);
+
+    header.ts.type = type;
+    header.ts.size = (u4) size;
+    if (sysWriteFully(fd, &header, sizeof(header),
+            "DexOpt opt chunk header write") != 0)
+    {
+        return false;
+    }
+
+    if (size > 0) {
+        if (sysWriteFully(fd, data, size, "DexOpt opt chunk write") != 0)
+            return false;
+    }
+
+    /* if necessary, pad to 64-bit alignment */
+    if ((size & 7) != 0) {
+        int padSize = 8 - (size & 7);
+        LOGV("size was %d, inserting %d pad bytes", size, padSize);
+        lseek(fd, padSize, SEEK_CUR);
+    }
+
+    assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
+
+    return true;
+}
+
+/*
+ * Write opt data.
+ *
+ * We have different pieces, some of which may be optional.  To make the
+ * most effective use of space, we use a "chunk" format, with a 4-byte
+ * type and a 4-byte length.  We guarantee 64-bit alignment for the data,
+ * so it can be used directly when the file is mapped for reading.
+ */
+static bool writeOptData(int fd, const DexClassLookup* pClassLookup,
+    const RegisterMapBuilder* pRegMapBuilder)
+{
+    /* pre-computed class lookup hash table */
+    if (!writeChunk(fd, (u4) kDexChunkClassLookup,
+            pClassLookup, pClassLookup->size))
+    {
+        return false;
+    }
+
+    /* register maps (optional) */
+    if (pRegMapBuilder != NULL) {
+        if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
+                pRegMapBuilder->data, pRegMapBuilder->size))
+        {
+            return false;
+        }
+    }
+
+    /* write the end marker */
+    if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Compute a checksum on a piece of an open file.
+ *
+ * File will be positioned at end of checksummed area.
+ *
+ * Returns "true" on success.
+ */
+static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum)
+{
+    unsigned char readBuf[8192];
+    ssize_t actual;
+    uLong adler;
+
+    if (lseek(fd, start, SEEK_SET) != start) {
+        LOGE("Unable to seek to start of checksum area (%ld): %s",
+            (long) start, strerror(errno));
+        return false;
+    }
+
+    adler = adler32(0L, Z_NULL, 0);
+
+    while (length != 0) {
+        size_t wanted = (length < sizeof(readBuf)) ? length : sizeof(readBuf);
+        actual = read(fd, readBuf, wanted);
+        if (actual <= 0) {
+            LOGE("Read failed (%d) while computing checksum (len=%zu): %s",
+                (int) actual, length, strerror(errno));
+            return false;
+        }
+
+        adler = adler32(adler, readBuf, actual);
+
+        length -= actual;
+    }
+
+    *pSum = adler;
+    return true;
+}
+
+/*
+ * Update the Adler-32 checksum stored in the DEX file.  This covers the
+ * swapped and optimized DEX data, but does not include the opt header
+ * or optimized data.
+ */
+static void updateChecksum(u1* addr, int len, DexHeader* pHeader)
+{
+    /*
+     * Rewrite the checksum.  We leave the SHA-1 signature alone.
+     */
+    uLong adler = adler32(0L, Z_NULL, 0);
+    const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
+
+    adler = adler32(adler, addr + nonSum, len - nonSum);
+    pHeader->checksum = adler;
+}
diff --git a/vm/analysis/DexPrepare.h b/vm/analysis/DexPrepare.h
new file mode 100644
index 0000000..297bbc6
--- /dev/null
+++ b/vm/analysis/DexPrepare.h
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+/*
+ * DEX preparation declarations.
+ */
+#ifndef DALVIK_DEXPREPARE_H_
+#define DALVIK_DEXPREPARE_H_
+
+/*
+ * Global DEX optimizer control.  Determines the circumstances in which we
+ * try to rewrite instructions in the DEX file.
+ *
+ * Optimizing is performed ahead-of-time by dexopt and, in some cases, at
+ * load time by the VM.
+ */
+enum DexOptimizerMode {
+    OPTIMIZE_MODE_UNKNOWN = 0,
+    OPTIMIZE_MODE_NONE,         /* never optimize (except "essential") */
+    OPTIMIZE_MODE_VERIFIED,     /* only optimize verified classes (default) */
+    OPTIMIZE_MODE_ALL,          /* optimize verified & unverified (risky) */
+    OPTIMIZE_MODE_FULL          /* fully opt verified classes at load time */
+};
+
+/* some additional bit flags for dexopt */
+enum DexoptFlags {
+    DEXOPT_OPT_ENABLED       = 1,       /* optimizations enabled? */
+    DEXOPT_OPT_ALL           = 1 << 1,  /* optimize when verify fails? */
+    DEXOPT_VERIFY_ENABLED    = 1 << 2,  /* verification enabled? */
+    DEXOPT_VERIFY_ALL        = 1 << 3,  /* verify bootstrap classes? */
+    DEXOPT_IS_BOOTSTRAP      = 1 << 4,  /* is dex in bootstrap class path? */
+    DEXOPT_GEN_REGISTER_MAPS = 1 << 5,  /* generate register maps during vfy */
+    DEXOPT_UNIPROCESSOR      = 1 << 6,  /* specify uniprocessor target */
+    DEXOPT_SMP               = 1 << 7   /* specify SMP target */
+};
+
+/*
+ * An enumeration of problems that can turn up during verification.
+ */
+enum VerifyError {
+    VERIFY_ERROR_NONE = 0,      /* no error; must be zero */
+    VERIFY_ERROR_GENERIC,       /* VerifyError */
+
+    VERIFY_ERROR_NO_CLASS,      /* NoClassDefFoundError */
+    VERIFY_ERROR_NO_FIELD,      /* NoSuchFieldError */
+    VERIFY_ERROR_NO_METHOD,     /* NoSuchMethodError */
+    VERIFY_ERROR_ACCESS_CLASS,  /* IllegalAccessError */
+    VERIFY_ERROR_ACCESS_FIELD,  /* IllegalAccessError */
+    VERIFY_ERROR_ACCESS_METHOD, /* IllegalAccessError */
+    VERIFY_ERROR_CLASS_CHANGE,  /* IncompatibleClassChangeError */
+    VERIFY_ERROR_INSTANTIATION, /* InstantiationError */
+};
+
+/*
+ * Identifies the type of reference in the instruction that generated the
+ * verify error (e.g. VERIFY_ERROR_ACCESS_CLASS could come from a method,
+ * field, or class reference).
+ *
+ * This must fit in two bits.
+ */
+enum VerifyErrorRefType {
+    VERIFY_ERROR_REF_CLASS  = 0,
+    VERIFY_ERROR_REF_FIELD  = 1,
+    VERIFY_ERROR_REF_METHOD = 2,
+};
+
+#define kVerifyErrorRefTypeShift 6
+
+#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.
+ *
+ * If "*pNewFile" is set, a new file has been created with only a stub
+ * "opt" header, and the caller is expected to fill in the blanks.
+ *
+ * Returns the file descriptor, locked and seeked past the "opt" header.
+ */
+int dvmOpenCachedDexFile(const char* fileName, const char* cachedFile,
+    u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing);
+
+/*
+ * Unlock the specified file descriptor.  Use in conjunction with
+ * dvmOpenCachedDexFile().
+ *
+ * Returns true on success.
+ */
+bool dvmUnlockCachedDexFile(int fd);
+
+/*
+ * Verify the contents of the "opt" header, and check the DEX file's
+ * dependencies on its source zip (if available).
+ */
+bool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
+    u4 crc, bool expectVerify, bool expectOpt);
+
+/*
+ * Optimize a DEX file.  The file must start with the "opt" header, followed
+ * by the plain DEX data.  It must be mmap()able.
+ *
+ * "fileName" is only used for debug output.
+ */
+bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLen,
+    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap);
+
+/*
+ * Continue the optimization process on the other side of a fork/exec.
+ */
+bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
+    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap);
+
+/*
+ * Prepare DEX data that is only available to the VM as in-memory data.
+ */
+bool dvmPrepareDexInMemory(u1* addr, size_t len, DvmDex** ppDvmDex);
+
+/*
+ * Prep data structures.
+ */
+bool dvmCreateInlineSubsTable(void);
+void dvmFreeInlineSubsTable(void);
+
+#endif  // DALVIK_DEXPREPARE_H_
diff --git a/vm/analysis/DexVerify.cpp b/vm/analysis/DexVerify.cpp
new file mode 100644
index 0000000..172a227
--- /dev/null
+++ b/vm/analysis/DexVerify.cpp
@@ -0,0 +1,1482 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik classfile verification.  This file contains the verifier entry
+ * points and the static constraint checks.
+ */
+#include "Dalvik.h"
+#include "analysis/CodeVerify.h"
+#include "libdex/DexCatch.h"
+
+
+/* fwd */
+static bool verifyMethod(Method* meth);
+static bool verifyInstructions(VerifierData* vdata);
+
+
+/*
+ * Verify a class.
+ *
+ * By the time we get here, the value of gDvm.classVerifyMode should already
+ * have been factored in.  If you want to call into the verifier even
+ * though verification is disabled, that's your business.
+ *
+ * Returns "true" on success.
+ */
+bool dvmVerifyClass(ClassObject* clazz)
+{
+    int i;
+
+    if (dvmIsClassVerified(clazz)) {
+        LOGD("Ignoring duplicate verify attempt on %s", clazz->descriptor);
+        return true;
+    }
+
+    for (i = 0; i < clazz->directMethodCount; i++) {
+        if (!verifyMethod(&clazz->directMethods[i])) {
+            LOG_VFY("Verifier rejected class %s", clazz->descriptor);
+            return false;
+        }
+    }
+    for (i = 0; i < clazz->virtualMethodCount; i++) {
+        if (!verifyMethod(&clazz->virtualMethods[i])) {
+            LOG_VFY("Verifier rejected class %s", clazz->descriptor);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+/*
+ * Compute the width of the instruction at each address in the instruction
+ * stream, and store it in vdata->insnFlags.  Addresses that are in the
+ * middle of an instruction, or that are part of switch table data, are not
+ * touched (so the caller should probably initialize "insnFlags" to zero).
+ *
+ * The "newInstanceCount" and "monitorEnterCount" fields in vdata are
+ * also set.
+ *
+ * Performs some static checks, notably:
+ * - opcode of first instruction begins at index 0
+ * - only documented instructions may appear
+ * - each instruction follows the last
+ * - last byte of last instruction is at (code_length-1)
+ *
+ * Logs an error and returns "false" on failure.
+ */
+static bool computeWidthsAndCountOps(VerifierData* vdata)
+{
+    const Method* meth = vdata->method;
+    InsnFlags* insnFlags = vdata->insnFlags;
+    size_t insnCount = vdata->insnsSize;
+    const u2* insns = meth->insns;
+    bool result = false;
+    int newInstanceCount = 0;
+    int monitorEnterCount = 0;
+    int i;
+
+    for (i = 0; i < (int) insnCount; /**/) {
+        size_t width = dexGetWidthFromInstruction(insns);
+        if (width == 0) {
+            LOG_VFY_METH(meth, "VFY: invalid instruction (0x%04x)", *insns);
+            goto bail;
+        } else if (width > 65535) {
+            LOG_VFY_METH(meth,
+                "VFY: warning: unusually large instr width (%d)", width);
+        }
+
+        Opcode opcode = dexOpcodeFromCodeUnit(*insns);
+        if (opcode == OP_NEW_INSTANCE || opcode == OP_NEW_INSTANCE_JUMBO)
+            newInstanceCount++;
+        if (opcode == OP_MONITOR_ENTER)
+            monitorEnterCount++;
+
+        insnFlags[i] |= width;
+        i += width;
+        insns += width;
+    }
+    if (i != (int) vdata->insnsSize) {
+        LOG_VFY_METH(meth, "VFY: code did not end where expected (%d vs. %d)",
+            i, dvmGetMethodInsnsSize(meth));
+        goto bail;
+    }
+
+    result = true;
+    vdata->newInstanceCount = newInstanceCount;
+    vdata->monitorEnterCount = monitorEnterCount;
+
+bail:
+    return result;
+}
+
+/*
+ * Set the "in try" flags for all instructions protected by "try" statements.
+ * Also sets the "branch target" flags for exception handlers.
+ *
+ * Call this after widths have been set in "insnFlags".
+ *
+ * Returns "false" if something in the exception table looks fishy, but
+ * we're expecting the exception table to be somewhat sane.
+ */
+static bool scanTryCatchBlocks(const Method* meth, InsnFlags* insnFlags)
+{
+    u4 insnsSize = dvmGetMethodInsnsSize(meth);
+    const DexCode* pCode = dvmGetMethodCode(meth);
+    u4 triesSize = pCode->triesSize;
+    const DexTry* pTries;
+    u4 idx;
+
+    if (triesSize == 0) {
+        return true;
+    }
+
+    pTries = dexGetTries(pCode);
+
+    for (idx = 0; idx < triesSize; idx++) {
+        const DexTry* pTry = &pTries[idx];
+        u4 start = pTry->startAddr;
+        u4 end = start + pTry->insnCount;
+        u4 addr;
+
+        if ((start >= end) || (start >= insnsSize) || (end > insnsSize)) {
+            LOG_VFY_METH(meth,
+                "VFY: bad exception entry: startAddr=%d endAddr=%d (size=%d)",
+                start, end, insnsSize);
+            return false;
+        }
+
+        if (dvmInsnGetWidth(insnFlags, start) == 0) {
+            LOG_VFY_METH(meth,
+                "VFY: 'try' block starts inside an instruction (%d)",
+                start);
+            return false;
+        }
+
+        for (addr = start; addr < end;
+            addr += dvmInsnGetWidth(insnFlags, addr))
+        {
+            assert(dvmInsnGetWidth(insnFlags, addr) != 0);
+            dvmInsnSetInTry(insnFlags, addr, true);
+        }
+    }
+
+    /* Iterate over each of the handlers to verify target addresses. */
+    u4 handlersSize = dexGetHandlersSize(pCode);
+    u4 offset = dexGetFirstHandlerOffset(pCode);
+    for (idx = 0; idx < handlersSize; idx++) {
+        DexCatchIterator iterator;
+        dexCatchIteratorInit(&iterator, pCode, offset);
+
+        for (;;) {
+            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+            u4 addr;
+
+            if (handler == NULL) {
+                break;
+            }
+
+            addr = handler->address;
+            if (dvmInsnGetWidth(insnFlags, addr) == 0) {
+                LOG_VFY_METH(meth,
+                    "VFY: exception handler starts at bad address (%d)",
+                    addr);
+                return false;
+            }
+
+            dvmInsnSetBranchTarget(insnFlags, addr, true);
+        }
+
+        offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
+    }
+
+    return true;
+}
+
+/*
+ * Perform verification on a single method.
+ *
+ * We do this in three passes:
+ *  (1) Walk through all code units, determining instruction locations,
+ *      widths, and other characteristics.
+ *  (2) Walk through all code units, performing static checks on
+ *      operands.
+ *  (3) Iterate through the method, checking type safety and looking
+ *      for code flow problems.
+ *
+ * Some checks may be bypassed depending on the verification mode.  We can't
+ * turn this stuff off completely if we want to do "exact" GC.
+ *
+ * TODO: cite source?
+ * Confirmed here:
+ * - code array must not be empty
+ * - (N/A) code_length must be less than 65536
+ * Confirmed by computeWidthsAndCountOps():
+ * - opcode of first instruction begins at index 0
+ * - only documented instructions may appear
+ * - each instruction follows the last
+ * - last byte of last instruction is at (code_length-1)
+ */
+static bool verifyMethod(Method* meth)
+{
+    bool result = false;
+
+    /*
+     * Verifier state blob.  Various values will be cached here so we
+     * can avoid expensive lookups and pass fewer arguments around.
+     */
+    VerifierData vdata;
+#if 1   // ndef NDEBUG
+    memset(&vdata, 0x99, sizeof(vdata));
+#endif
+
+    vdata.method = meth;
+    vdata.insnsSize = dvmGetMethodInsnsSize(meth);
+    vdata.insnRegCount = meth->registersSize;
+    vdata.insnFlags = NULL;
+    vdata.uninitMap = NULL;
+    vdata.basicBlocks = NULL;
+
+    /*
+     * If there aren't any instructions, make sure that's expected, then
+     * exit successfully.  Note: for native methods, meth->insns gets set
+     * to a native function pointer on first call, so don't use that as
+     * an indicator.
+     */
+    if (vdata.insnsSize == 0) {
+        if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
+            LOG_VFY_METH(meth,
+                "VFY: zero-length code in concrete non-native method");
+            goto bail;
+        }
+
+        goto success;
+    }
+
+    /*
+     * Sanity-check the register counts.  ins + locals = registers, so make
+     * sure that ins <= registers.
+     */
+    if (meth->insSize > meth->registersSize) {
+        LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)",
+            meth->insSize, meth->registersSize);
+        goto bail;
+    }
+
+    /*
+     * Allocate and populate an array to hold instruction data.
+     *
+     * TODO: Consider keeping a reusable pre-allocated array sitting
+     * around for smaller methods.
+     */
+    vdata.insnFlags = (InsnFlags*) calloc(vdata.insnsSize, sizeof(InsnFlags));
+    if (vdata.insnFlags == NULL)
+        goto bail;
+
+    /*
+     * Compute the width of each instruction and store the result in insnFlags.
+     * Count up the #of occurrences of certain opcodes while we're at it.
+     */
+    if (!computeWidthsAndCountOps(&vdata))
+        goto bail;
+
+    /*
+     * Allocate a map to hold the classes of uninitialized instances.
+     */
+    vdata.uninitMap = dvmCreateUninitInstanceMap(meth, vdata.insnFlags,
+        vdata.newInstanceCount);
+    if (vdata.uninitMap == NULL)
+        goto bail;
+
+    /*
+     * Set the "in try" flags for all instructions guarded by a "try" block.
+     * Also sets the "branch target" flag on exception handlers.
+     */
+    if (!scanTryCatchBlocks(meth, vdata.insnFlags))
+        goto bail;
+
+    /*
+     * Perform static instruction verification.  Also sets the "branch
+     * target" flags.
+     */
+    if (!verifyInstructions(&vdata))
+        goto bail;
+
+    /*
+     * Do code-flow analysis.
+     *
+     * We could probably skip this for a method with no registers, but
+     * that's so rare that there's little point in checking.
+     */
+    if (!dvmVerifyCodeFlow(&vdata)) {
+        //LOGD("+++ %s failed code flow", meth->name);
+        goto bail;
+    }
+
+success:
+    result = true;
+
+bail:
+    dvmFreeVfyBasicBlocks(&vdata);
+    dvmFreeUninitInstanceMap(vdata.uninitMap);
+    free(vdata.insnFlags);
+    return result;
+}
+
+
+/*
+ * Verify an array data table.  "curOffset" is the offset of the
+ * fill-array-data instruction.
+ */
+static bool checkArrayData(const Method* meth, u4 curOffset)
+{
+    const u4 insnCount = dvmGetMethodInsnsSize(meth);
+    const u2* insns = meth->insns + curOffset;
+    const u2* arrayData;
+    u4 valueCount, valueWidth, tableSize;
+    s4 offsetToArrayData;
+
+    assert(curOffset < insnCount);
+
+    /* make sure the start of the array data table is in range */
+    offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
+    if ((s4)curOffset + offsetToArrayData < 0 ||
+        curOffset + offsetToArrayData + 2 >= insnCount)
+    {
+        LOG_VFY("VFY: invalid array data start: at %d, data offset %d, "
+                "count %d",
+            curOffset, offsetToArrayData, insnCount);
+        return false;
+    }
+
+    /* offset to array data table is a relative branch-style offset */
+    arrayData = insns + offsetToArrayData;
+
+    /* make sure the table is 32-bit aligned */
+    if ((((u4) arrayData) & 0x03) != 0) {
+        LOG_VFY("VFY: unaligned array data table: at %d, data offset %d",
+            curOffset, offsetToArrayData);
+        return false;
+    }
+
+    valueWidth = arrayData[1];
+    valueCount = *(u4*)(&arrayData[2]);
+
+    tableSize = 4 + (valueWidth * valueCount + 1) / 2;
+
+    /* make sure the end of the switch is in range */
+    if (curOffset + offsetToArrayData + tableSize > insnCount) {
+        LOG_VFY("VFY: invalid array data end: at %d, data offset %d, end %d, "
+                "count %d",
+            curOffset, offsetToArrayData,
+            curOffset + offsetToArrayData + tableSize, insnCount);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Perform static checks on a "new-instance" instruction.  Specifically,
+ * make sure the class reference isn't for an array class.
+ *
+ * We don't need the actual class, just a pointer to the class name.
+ */
+static bool checkNewInstance(const DvmDex* pDvmDex, u4 idx)
+{
+    const char* classDescriptor;
+
+    if (idx >= pDvmDex->pHeader->typeIdsSize) {
+        LOG_VFY("VFY: bad type index %d (max %d)",
+            idx, pDvmDex->pHeader->typeIdsSize);
+        return false;
+    }
+
+    classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
+    if (classDescriptor[0] != 'L') {
+        LOG_VFY("VFY: can't call new-instance on type '%s'",
+            classDescriptor);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Perform static checks on a "new-array" instruction.  Specifically, make
+ * sure they aren't creating an array of arrays that causes the number of
+ * dimensions to exceed 255.
+ */
+static bool checkNewArray(const DvmDex* pDvmDex, u4 idx)
+{
+    const char* classDescriptor;
+
+    if (idx >= pDvmDex->pHeader->typeIdsSize) {
+        LOG_VFY("VFY: bad type index %d (max %d)",
+            idx, pDvmDex->pHeader->typeIdsSize);
+        return false;
+    }
+
+    classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
+
+    int bracketCount = 0;
+    const char* cp = classDescriptor;
+    while (*cp++ == '[')
+        bracketCount++;
+
+    if (bracketCount == 0) {
+        /* The given class must be an array type. */
+        LOG_VFY("VFY: can't new-array class '%s' (not an array)",
+            classDescriptor);
+        return false;
+    } else if (bracketCount > 255) {
+        /* It is illegal to create an array of more than 255 dimensions. */
+        LOG_VFY("VFY: can't new-array class '%s' (exceeds limit)",
+            classDescriptor);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Perform static checks on an instruction that takes a class constant.
+ * Ensure that the class index is in the valid range.
+ */
+static bool checkTypeIndex(const DvmDex* pDvmDex, u4 idx)
+{
+    if (idx >= pDvmDex->pHeader->typeIdsSize) {
+        LOG_VFY("VFY: bad type index %d (max %d)",
+            idx, pDvmDex->pHeader->typeIdsSize);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Perform static checks on a field get or set instruction.  All we do
+ * here is ensure that the field index is in the valid range.
+ */
+static bool checkFieldIndex(const DvmDex* pDvmDex, u4 idx)
+{
+    if (idx >= pDvmDex->pHeader->fieldIdsSize) {
+        LOG_VFY("VFY: bad field index %d (max %d)",
+            idx, pDvmDex->pHeader->fieldIdsSize);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Perform static checks on a method invocation instruction.  All we do
+ * here is ensure that the method index is in the valid range.
+ */
+static bool checkMethodIndex(const DvmDex* pDvmDex, u4 idx)
+{
+    if (idx >= pDvmDex->pHeader->methodIdsSize) {
+        LOG_VFY("VFY: bad method index %d (max %d)",
+            idx, pDvmDex->pHeader->methodIdsSize);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Ensure that the string index is in the valid range.
+ */
+static bool checkStringIndex(const DvmDex* pDvmDex, u4 idx)
+{
+    if (idx >= pDvmDex->pHeader->stringIdsSize) {
+        LOG_VFY("VFY: bad string index %d (max %d)",
+            idx, pDvmDex->pHeader->stringIdsSize);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Ensure that the register index is valid for this method.
+ */
+static bool checkRegisterIndex(const Method* meth, u4 idx)
+{
+    if (idx >= meth->registersSize) {
+        LOG_VFY("VFY: register index out of range (%d >= %d)",
+            idx, meth->registersSize);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Ensure that the wide register index is valid for this method.
+ */
+static bool checkWideRegisterIndex(const Method* meth, u4 idx)
+{
+    if (idx+1 >= meth->registersSize) {
+        LOG_VFY("VFY: wide register index out of range (%d+1 >= %d)",
+            idx, meth->registersSize);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Check the register indices used in a "vararg" instruction, such as
+ * invoke-virtual or filled-new-array.
+ *
+ * vA holds word count (0-5), args[] have values.
+ *
+ * There are some tests we don't do here, e.g. we don't try to verify
+ * that invoking a method that takes a double is done with consecutive
+ * registers.  This requires parsing the target method signature, which
+ * we will be doing later on during the code flow analysis.
+ */
+static bool checkVarargRegs(const Method* meth,
+    const DecodedInstruction* pDecInsn)
+{
+    u2 registersSize = meth->registersSize;
+    unsigned int idx;
+
+    if (pDecInsn->vA > 5) {
+        LOG_VFY("VFY: invalid arg count (%d) in non-range invoke)",
+            pDecInsn->vA);
+        return false;
+    }
+
+    for (idx = 0; idx < pDecInsn->vA; idx++) {
+        if (pDecInsn->arg[idx] > registersSize) {
+            LOG_VFY("VFY: invalid reg index (%d) in non-range invoke (> %d)",
+                pDecInsn->arg[idx], registersSize);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Check the register indices used in a "vararg/range" instruction, such as
+ * invoke-virtual/range or filled-new-array/range.
+ *
+ * vA holds word count, vC holds index of first reg.
+ */
+static bool checkVarargRangeRegs(const Method* meth,
+    const DecodedInstruction* pDecInsn)
+{
+    u2 registersSize = meth->registersSize;
+
+    /*
+     * vA/vC are unsigned 8-bit/16-bit quantities for /range instructions,
+     * so there's no risk of integer overflow when adding them here.
+     */
+    if (pDecInsn->vA + pDecInsn->vC > registersSize) {
+        LOG_VFY("VFY: invalid reg index %d+%d in range invoke (> %d)",
+            pDecInsn->vA, pDecInsn->vC, registersSize);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Verify a switch table.  "curOffset" is the offset of the switch
+ * instruction.
+ *
+ * Updates "insnFlags", setting the "branch target" flag.
+ */
+static bool checkSwitchTargets(const Method* meth, InsnFlags* insnFlags,
+    u4 curOffset)
+{
+    const u4 insnCount = dvmGetMethodInsnsSize(meth);
+    const u2* insns = meth->insns + curOffset;
+    const u2* switchInsns;
+    u2 expectedSignature;
+    u4 switchCount, tableSize;
+    s4 offsetToSwitch, offsetToKeys, offsetToTargets;
+    s4 offset, absOffset;
+    u4 targ;
+
+    assert(curOffset < insnCount);
+
+    /* make sure the start of the switch is in range */
+    offsetToSwitch = insns[1] | ((s4) insns[2]) << 16;
+    if ((s4) curOffset + offsetToSwitch < 0 ||
+        curOffset + offsetToSwitch + 2 >= insnCount)
+    {
+        LOG_VFY("VFY: invalid switch start: at %d, switch offset %d, "
+                "count %d",
+            curOffset, offsetToSwitch, insnCount);
+        return false;
+    }
+
+    /* offset to switch table is a relative branch-style offset */
+    switchInsns = insns + offsetToSwitch;
+
+    /* make sure the table is 32-bit aligned */
+    if ((((u4) switchInsns) & 0x03) != 0) {
+        LOG_VFY("VFY: unaligned switch table: at %d, switch offset %d",
+            curOffset, offsetToSwitch);
+        return false;
+    }
+
+    switchCount = switchInsns[1];
+
+    if ((*insns & 0xff) == OP_PACKED_SWITCH) {
+        /* 0=sig, 1=count, 2/3=firstKey */
+        offsetToTargets = 4;
+        offsetToKeys = -1;
+        expectedSignature = kPackedSwitchSignature;
+    } else {
+        /* 0=sig, 1=count, 2..count*2 = keys */
+        offsetToKeys = 2;
+        offsetToTargets = 2 + 2*switchCount;
+        expectedSignature = kSparseSwitchSignature;
+    }
+    tableSize = offsetToTargets + switchCount*2;
+
+    if (switchInsns[0] != expectedSignature) {
+        LOG_VFY("VFY: wrong signature for switch table (0x%04x, wanted 0x%04x)",
+            switchInsns[0], expectedSignature);
+        return false;
+    }
+
+    /* make sure the end of the switch is in range */
+    if (curOffset + offsetToSwitch + tableSize > (u4) insnCount) {
+        LOG_VFY("VFY: invalid switch end: at %d, switch offset %d, end %d, "
+                "count %d",
+            curOffset, offsetToSwitch, curOffset + offsetToSwitch + tableSize,
+            insnCount);
+        return false;
+    }
+
+    /* for a sparse switch, verify the keys are in ascending order */
+    if (offsetToKeys > 0 && switchCount > 1) {
+        s4 lastKey;
+
+        lastKey = switchInsns[offsetToKeys] |
+                  (switchInsns[offsetToKeys+1] << 16);
+        for (targ = 1; targ < switchCount; targ++) {
+            s4 key = (s4) switchInsns[offsetToKeys + targ*2] |
+                    (s4) (switchInsns[offsetToKeys + targ*2 +1] << 16);
+            if (key <= lastKey) {
+                LOG_VFY("VFY: invalid packed switch: last key=%d, this=%d",
+                    lastKey, key);
+                return false;
+            }
+
+            lastKey = key;
+        }
+    }
+
+    /* verify each switch target */
+    for (targ = 0; targ < switchCount; targ++) {
+        offset = (s4) switchInsns[offsetToTargets + targ*2] |
+                (s4) (switchInsns[offsetToTargets + targ*2 +1] << 16);
+        absOffset = curOffset + offset;
+
+        if (absOffset < 0 || absOffset >= (s4)insnCount ||
+            !dvmInsnIsOpcode(insnFlags, absOffset))
+        {
+            LOG_VFY("VFY: invalid switch target %d (-> %#x) at %#x[%d]",
+                offset, absOffset, curOffset, targ);
+            return false;
+        }
+        dvmInsnSetBranchTarget(insnFlags, absOffset, true);
+    }
+
+    return true;
+}
+
+/*
+ * Verify that the target of a branch instruction is valid.
+ *
+ * We don't expect code to jump directly into an exception handler, but
+ * it's valid to do so as long as the target isn't a "move-exception"
+ * instruction.  We verify that in a later stage.
+ *
+ * The VM spec doesn't forbid an instruction from branching to itself,
+ * but the Dalvik spec declares that only certain instructions can do so.
+ *
+ * Updates "insnFlags", setting the "branch target" flag.
+ */
+static bool checkBranchTarget(const Method* meth, InsnFlags* insnFlags,
+    int curOffset, bool selfOkay)
+{
+    const int insnCount = dvmGetMethodInsnsSize(meth);
+    s4 offset, absOffset;
+    bool isConditional;
+
+    if (!dvmGetBranchOffset(meth, insnFlags, curOffset, &offset,
+            &isConditional))
+        return false;
+
+    if (!selfOkay && offset == 0) {
+        LOG_VFY_METH(meth, "VFY: branch offset of zero not allowed at %#x",
+            curOffset);
+        return false;
+    }
+
+    /*
+     * Check for 32-bit overflow.  This isn't strictly necessary if we can
+     * depend on the VM to have identical "wrap-around" behavior, but
+     * it's unwise to depend on that.
+     */
+    if (((s8) curOffset + (s8) offset) != (s8)(curOffset + offset)) {
+        LOG_VFY_METH(meth, "VFY: branch target overflow %#x +%d",
+            curOffset, offset);
+        return false;
+    }
+    absOffset = curOffset + offset;
+    if (absOffset < 0 || absOffset >= insnCount ||
+        !dvmInsnIsOpcode(insnFlags, absOffset))
+    {
+        LOG_VFY_METH(meth,
+            "VFY: invalid branch target %d (-> %#x) at %#x",
+            offset, absOffset, curOffset);
+        return false;
+    }
+    dvmInsnSetBranchTarget(insnFlags, absOffset, true);
+
+    return true;
+}
+
+
+/*
+ * Perform static verification on instructions.
+ *
+ * As a side effect, this sets the "branch target" flags in InsnFlags.
+ *
+ * "(CF)" items are handled during code-flow analysis.
+ *
+ * v3 4.10.1
+ * - target of each jump and branch instruction must be valid
+ * - targets of switch statements must be valid
+ * - operands referencing constant pool entries must be valid
+ * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
+ * - (new) verify operands of "quick" field ops
+ * - (CF) operands of method invocation instructions must be valid
+ * - (new) verify operands of "quick" method invoke ops
+ * - (CF) only invoke-direct can call a method starting with '<'
+ * - (CF) <clinit> must never be called explicitly
+ * - operands of instanceof, checkcast, new (and variants) must be valid
+ * - new-array[-type] limited to 255 dimensions
+ * - can't use "new" on an array class
+ * - (?) limit dimensions in multi-array creation
+ * - local variable load/store register values must be in valid range
+ *
+ * v3 4.11.1.2
+ * - branches must be within the bounds of the code array
+ * - targets of all control-flow instructions are the start of an instruction
+ * - register accesses fall within range of allocated registers
+ * - (N/A) access to constant pool must be of appropriate type
+ * - code does not end in the middle of an instruction
+ * - execution cannot fall off the end of the code
+ * - (earlier) for each exception handler, the "try" area must begin and
+ *   end at the start of an instruction (end can be at the end of the code)
+ * - (earlier) for each exception handler, the handler must start at a valid
+ *   instruction
+ */
+static bool verifyInstructions(VerifierData* vdata)
+{
+    const Method* meth = vdata->method;
+    const DvmDex* pDvmDex = meth->clazz->pDvmDex;
+    InsnFlags* insnFlags = vdata->insnFlags;
+    const u2* insns = meth->insns;
+    unsigned int codeOffset;
+
+    /* the start of the method is a "branch target" */
+    dvmInsnSetBranchTarget(insnFlags, 0, true);
+
+    for (codeOffset = 0; codeOffset < vdata->insnsSize; /**/) {
+        /*
+         * Pull the instruction apart.
+         */
+        int width = dvmInsnGetWidth(insnFlags, codeOffset);
+        DecodedInstruction decInsn;
+        bool okay = true;
+
+        dexDecodeInstruction(meth->insns + codeOffset, &decInsn);
+
+        /*
+         * Check register, type, class, field, method, and string indices
+         * for out-of-range values.  Do additional checks on branch targets
+         * and some special cases like new-instance and new-array.
+         */
+        switch (decInsn.opcode) {
+        case OP_NOP:
+        case OP_RETURN_VOID:
+            /* nothing to check */
+            break;
+        case OP_MOVE_RESULT:
+        case OP_MOVE_RESULT_OBJECT:
+        case OP_MOVE_EXCEPTION:
+        case OP_RETURN:
+        case OP_RETURN_OBJECT:
+        case OP_CONST_4:
+        case OP_CONST_16:
+        case OP_CONST:
+        case OP_CONST_HIGH16:
+        case OP_MONITOR_ENTER:
+        case OP_MONITOR_EXIT:
+        case OP_THROW:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            break;
+        case OP_MOVE_RESULT_WIDE:
+        case OP_RETURN_WIDE:
+        case OP_CONST_WIDE_16:
+        case OP_CONST_WIDE_32:
+        case OP_CONST_WIDE:
+        case OP_CONST_WIDE_HIGH16:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            break;
+        case OP_GOTO:
+        case OP_GOTO_16:
+            okay &= checkBranchTarget(meth, insnFlags, codeOffset, false);
+            break;
+        case OP_GOTO_32:
+            okay &= checkBranchTarget(meth, insnFlags, codeOffset, true);
+            break;
+        case OP_MOVE:
+        case OP_MOVE_FROM16:
+        case OP_MOVE_16:
+        case OP_MOVE_OBJECT:
+        case OP_MOVE_OBJECT_FROM16:
+        case OP_MOVE_OBJECT_16:
+        case OP_ARRAY_LENGTH:
+        case OP_NEG_INT:
+        case OP_NOT_INT:
+        case OP_NEG_FLOAT:
+        case OP_INT_TO_FLOAT:
+        case OP_FLOAT_TO_INT:
+        case OP_INT_TO_BYTE:
+        case OP_INT_TO_CHAR:
+        case OP_INT_TO_SHORT:
+        case OP_ADD_INT_2ADDR:
+        case OP_SUB_INT_2ADDR:
+        case OP_MUL_INT_2ADDR:
+        case OP_DIV_INT_2ADDR:
+        case OP_REM_INT_2ADDR:
+        case OP_AND_INT_2ADDR:
+        case OP_OR_INT_2ADDR:
+        case OP_XOR_INT_2ADDR:
+        case OP_SHL_INT_2ADDR:
+        case OP_SHR_INT_2ADDR:
+        case OP_USHR_INT_2ADDR:
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_REM_FLOAT_2ADDR:
+        case OP_ADD_INT_LIT16:
+        case OP_RSUB_INT:
+        case OP_MUL_INT_LIT16:
+        case OP_DIV_INT_LIT16:
+        case OP_REM_INT_LIT16:
+        case OP_AND_INT_LIT16:
+        case OP_OR_INT_LIT16:
+        case OP_XOR_INT_LIT16:
+        case OP_ADD_INT_LIT8:
+        case OP_RSUB_INT_LIT8:
+        case OP_MUL_INT_LIT8:
+        case OP_DIV_INT_LIT8:
+        case OP_REM_INT_LIT8:
+        case OP_AND_INT_LIT8:
+        case OP_OR_INT_LIT8:
+        case OP_XOR_INT_LIT8:
+        case OP_SHL_INT_LIT8:
+        case OP_SHR_INT_LIT8:
+        case OP_USHR_INT_LIT8:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            break;
+        case OP_INT_TO_LONG:
+        case OP_INT_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_FLOAT_TO_DOUBLE:
+        case OP_SHL_LONG_2ADDR:
+        case OP_SHR_LONG_2ADDR:
+        case OP_USHR_LONG_2ADDR:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            break;
+        case OP_LONG_TO_INT:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_INT:
+        case OP_DOUBLE_TO_FLOAT:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkWideRegisterIndex(meth, decInsn.vB);
+            break;
+        case OP_MOVE_WIDE:
+        case OP_MOVE_WIDE_FROM16:
+        case OP_MOVE_WIDE_16:
+        case OP_DOUBLE_TO_LONG:
+        case OP_LONG_TO_DOUBLE:
+        case OP_NEG_DOUBLE:
+        case OP_NEG_LONG:
+        case OP_NOT_LONG:
+        case OP_ADD_LONG_2ADDR:
+        case OP_SUB_LONG_2ADDR:
+        case OP_MUL_LONG_2ADDR:
+        case OP_DIV_LONG_2ADDR:
+        case OP_REM_LONG_2ADDR:
+        case OP_AND_LONG_2ADDR:
+        case OP_OR_LONG_2ADDR:
+        case OP_XOR_LONG_2ADDR:
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE_2ADDR:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkWideRegisterIndex(meth, decInsn.vB);
+            break;
+        case OP_CONST_STRING:
+        case OP_CONST_STRING_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkStringIndex(pDvmDex, decInsn.vB);
+            break;
+        case OP_CONST_CLASS:
+        case OP_CONST_CLASS_JUMBO:
+        case OP_CHECK_CAST:
+        case OP_CHECK_CAST_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkTypeIndex(pDvmDex, decInsn.vB);
+            break;
+        case OP_INSTANCE_OF:
+        case OP_INSTANCE_OF_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkTypeIndex(pDvmDex, decInsn.vC);
+            break;
+        case OP_NEW_INSTANCE:
+        case OP_NEW_INSTANCE_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkNewInstance(pDvmDex, decInsn.vB);
+            break;
+        case OP_NEW_ARRAY:
+        case OP_NEW_ARRAY_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkNewArray(pDvmDex, decInsn.vC);
+            break;
+        case OP_FILL_ARRAY_DATA:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkArrayData(meth, codeOffset);
+            break;
+        case OP_PACKED_SWITCH:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkSwitchTargets(meth, insnFlags, codeOffset);
+            break;
+        case OP_SPARSE_SWITCH:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkSwitchTargets(meth, insnFlags, codeOffset);
+            break;
+        case OP_CMPL_FLOAT:
+        case OP_CMPG_FLOAT:
+        case OP_AGET:
+        case OP_AGET_OBJECT:
+        case OP_AGET_BOOLEAN:
+        case OP_AGET_BYTE:
+        case OP_AGET_CHAR:
+        case OP_AGET_SHORT:
+        case OP_APUT:
+        case OP_APUT_OBJECT:
+        case OP_APUT_BOOLEAN:
+        case OP_APUT_BYTE:
+        case OP_APUT_CHAR:
+        case OP_APUT_SHORT:
+        case OP_ADD_INT:
+        case OP_SUB_INT:
+        case OP_MUL_INT:
+        case OP_DIV_INT:
+        case OP_REM_INT:
+        case OP_AND_INT:
+        case OP_OR_INT:
+        case OP_XOR_INT:
+        case OP_SHL_INT:
+        case OP_SHR_INT:
+        case OP_USHR_INT:
+        case OP_ADD_FLOAT:
+        case OP_SUB_FLOAT:
+        case OP_MUL_FLOAT:
+        case OP_DIV_FLOAT:
+        case OP_REM_FLOAT:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkRegisterIndex(meth, decInsn.vC);
+            break;
+        case OP_AGET_WIDE:
+        case OP_APUT_WIDE:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkRegisterIndex(meth, decInsn.vC);
+            break;
+        case OP_CMPL_DOUBLE:
+        case OP_CMPG_DOUBLE:
+        case OP_CMP_LONG:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkWideRegisterIndex(meth, decInsn.vB);
+            okay &= checkWideRegisterIndex(meth, decInsn.vC);
+            break;
+        case OP_ADD_DOUBLE:
+        case OP_SUB_DOUBLE:
+        case OP_MUL_DOUBLE:
+        case OP_DIV_DOUBLE:
+        case OP_REM_DOUBLE:
+        case OP_ADD_LONG:
+        case OP_SUB_LONG:
+        case OP_MUL_LONG:
+        case OP_DIV_LONG:
+        case OP_REM_LONG:
+        case OP_AND_LONG:
+        case OP_OR_LONG:
+        case OP_XOR_LONG:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkWideRegisterIndex(meth, decInsn.vB);
+            okay &= checkWideRegisterIndex(meth, decInsn.vC);
+            break;
+        case OP_SHL_LONG:
+        case OP_SHR_LONG:
+        case OP_USHR_LONG:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkWideRegisterIndex(meth, decInsn.vB);
+            okay &= checkRegisterIndex(meth, decInsn.vC);
+            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:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkBranchTarget(meth, insnFlags, codeOffset, false);
+            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:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkBranchTarget(meth, insnFlags, codeOffset, false);
+            break;
+        case OP_IGET:
+        case OP_IGET_JUMBO:
+        case OP_IGET_OBJECT:
+        case OP_IGET_OBJECT_JUMBO:
+        case OP_IGET_BOOLEAN:
+        case OP_IGET_BOOLEAN_JUMBO:
+        case OP_IGET_BYTE:
+        case OP_IGET_BYTE_JUMBO:
+        case OP_IGET_CHAR:
+        case OP_IGET_CHAR_JUMBO:
+        case OP_IGET_SHORT:
+        case OP_IGET_SHORT_JUMBO:
+        case OP_IPUT:
+        case OP_IPUT_JUMBO:
+        case OP_IPUT_OBJECT:
+        case OP_IPUT_OBJECT_JUMBO:
+        case OP_IPUT_BOOLEAN:
+        case OP_IPUT_BOOLEAN_JUMBO:
+        case OP_IPUT_BYTE:
+        case OP_IPUT_BYTE_JUMBO:
+        case OP_IPUT_CHAR:
+        case OP_IPUT_CHAR_JUMBO:
+        case OP_IPUT_SHORT:
+        case OP_IPUT_SHORT_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkFieldIndex(pDvmDex, decInsn.vC);
+            break;
+        case OP_IGET_WIDE:
+        case OP_IGET_WIDE_JUMBO:
+        case OP_IPUT_WIDE:
+        case OP_IPUT_WIDE_JUMBO:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkRegisterIndex(meth, decInsn.vB);
+            okay &= checkFieldIndex(pDvmDex, decInsn.vC);
+            break;
+        case OP_SGET:
+        case OP_SGET_JUMBO:
+        case OP_SGET_OBJECT:
+        case OP_SGET_OBJECT_JUMBO:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_BOOLEAN_JUMBO:
+        case OP_SGET_BYTE:
+        case OP_SGET_BYTE_JUMBO:
+        case OP_SGET_CHAR:
+        case OP_SGET_CHAR_JUMBO:
+        case OP_SGET_SHORT:
+        case OP_SGET_SHORT_JUMBO:
+        case OP_SPUT:
+        case OP_SPUT_JUMBO:
+        case OP_SPUT_OBJECT:
+        case OP_SPUT_OBJECT_JUMBO:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_BOOLEAN_JUMBO:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_BYTE_JUMBO:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_CHAR_JUMBO:
+        case OP_SPUT_SHORT:
+        case OP_SPUT_SHORT_JUMBO:
+            okay &= checkRegisterIndex(meth, decInsn.vA);
+            okay &= checkFieldIndex(pDvmDex, decInsn.vB);
+            break;
+        case OP_SGET_WIDE:
+        case OP_SGET_WIDE_JUMBO:
+        case OP_SPUT_WIDE:
+        case OP_SPUT_WIDE_JUMBO:
+            okay &= checkWideRegisterIndex(meth, decInsn.vA);
+            okay &= checkFieldIndex(pDvmDex, decInsn.vB);
+            break;
+        case OP_FILLED_NEW_ARRAY:
+            /* decoder uses B, not C, for type ref */
+            okay &= checkTypeIndex(pDvmDex, decInsn.vB);
+            okay &= checkVarargRegs(meth, &decInsn);
+            break;
+        case OP_FILLED_NEW_ARRAY_RANGE:
+        case OP_FILLED_NEW_ARRAY_JUMBO:
+            okay &= checkTypeIndex(pDvmDex, decInsn.vB);
+            okay &= checkVarargRangeRegs(meth, &decInsn);
+            break;
+        case OP_INVOKE_VIRTUAL:
+        case OP_INVOKE_SUPER:
+        case OP_INVOKE_DIRECT:
+        case OP_INVOKE_STATIC:
+        case OP_INVOKE_INTERFACE:
+            /* decoder uses B, not C, for type ref */
+            okay &= checkMethodIndex(pDvmDex, decInsn.vB);
+            okay &= checkVarargRegs(meth, &decInsn);
+            break;
+        case OP_INVOKE_VIRTUAL_RANGE:
+        case OP_INVOKE_VIRTUAL_JUMBO:
+        case OP_INVOKE_SUPER_RANGE:
+        case OP_INVOKE_SUPER_JUMBO:
+        case OP_INVOKE_DIRECT_RANGE:
+        case OP_INVOKE_DIRECT_JUMBO:
+        case OP_INVOKE_STATIC_RANGE:
+        case OP_INVOKE_STATIC_JUMBO:
+        case OP_INVOKE_INTERFACE_RANGE:
+        case OP_INVOKE_INTERFACE_JUMBO:
+            okay &= checkMethodIndex(pDvmDex, decInsn.vB);
+            okay &= checkVarargRangeRegs(meth, &decInsn);
+            break;
+
+        /* verifier/optimizer output; we should never see these */
+        case OP_IGET_VOLATILE:
+        case OP_IPUT_VOLATILE:
+        case OP_SGET_VOLATILE:
+        case OP_SPUT_VOLATILE:
+        case OP_IGET_OBJECT_VOLATILE:
+        case OP_IPUT_OBJECT_VOLATILE:
+        case OP_SGET_OBJECT_VOLATILE:
+        case OP_SPUT_OBJECT_VOLATILE:
+        case OP_IGET_WIDE_VOLATILE:
+        case OP_IPUT_WIDE_VOLATILE:
+        case OP_SGET_WIDE_VOLATILE:
+        case OP_SPUT_WIDE_VOLATILE:
+        case OP_IGET_VOLATILE_JUMBO:
+        case OP_IPUT_VOLATILE_JUMBO:
+        case OP_SGET_VOLATILE_JUMBO:
+        case OP_SPUT_VOLATILE_JUMBO:
+        case OP_IGET_OBJECT_VOLATILE_JUMBO:
+        case OP_IPUT_OBJECT_VOLATILE_JUMBO:
+        case OP_SGET_OBJECT_VOLATILE_JUMBO:
+        case OP_SPUT_OBJECT_VOLATILE_JUMBO:
+        case OP_IGET_WIDE_VOLATILE_JUMBO:
+        case OP_IPUT_WIDE_VOLATILE_JUMBO:
+        case OP_SGET_WIDE_VOLATILE_JUMBO:
+        case OP_SPUT_WIDE_VOLATILE_JUMBO:
+        case OP_BREAKPOINT:
+        case OP_THROW_VERIFICATION_ERROR:
+        case OP_THROW_VERIFICATION_ERROR_JUMBO:
+        case OP_EXECUTE_INLINE:
+        case OP_EXECUTE_INLINE_RANGE:
+        case OP_INVOKE_OBJECT_INIT_RANGE:
+        case OP_INVOKE_OBJECT_INIT_JUMBO:
+        case OP_RETURN_VOID_BARRIER:
+        case OP_IGET_QUICK:
+        case OP_IGET_WIDE_QUICK:
+        case OP_IGET_OBJECT_QUICK:
+        case OP_IPUT_QUICK:
+        case OP_IPUT_WIDE_QUICK:
+        case OP_IPUT_OBJECT_QUICK:
+        case OP_INVOKE_VIRTUAL_QUICK:
+        case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+        case OP_INVOKE_SUPER_QUICK:
+        case OP_INVOKE_SUPER_QUICK_RANGE:
+        case OP_UNUSED_3E:
+        case OP_UNUSED_3F:
+        case OP_UNUSED_40:
+        case OP_UNUSED_41:
+        case OP_UNUSED_42:
+        case OP_UNUSED_43:
+        case OP_UNUSED_73:
+        case OP_UNUSED_79:
+        case OP_UNUSED_7A:
+        case OP_DISPATCH_FF:
+        case OP_UNUSED_27FF:
+        case OP_UNUSED_28FF:
+        case OP_UNUSED_29FF:
+        case OP_UNUSED_2AFF:
+        case OP_UNUSED_2BFF:
+        case OP_UNUSED_2CFF:
+        case OP_UNUSED_2DFF:
+        case OP_UNUSED_2EFF:
+        case OP_UNUSED_2FFF:
+        case OP_UNUSED_30FF:
+        case OP_UNUSED_31FF:
+        case OP_UNUSED_32FF:
+        case OP_UNUSED_33FF:
+        case OP_UNUSED_34FF:
+        case OP_UNUSED_35FF:
+        case OP_UNUSED_36FF:
+        case OP_UNUSED_37FF:
+        case OP_UNUSED_38FF:
+        case OP_UNUSED_39FF:
+        case OP_UNUSED_3AFF:
+        case OP_UNUSED_3BFF:
+        case OP_UNUSED_3CFF:
+        case OP_UNUSED_3DFF:
+        case OP_UNUSED_3EFF:
+        case OP_UNUSED_3FFF:
+        case OP_UNUSED_40FF:
+        case OP_UNUSED_41FF:
+        case OP_UNUSED_42FF:
+        case OP_UNUSED_43FF:
+        case OP_UNUSED_44FF:
+        case OP_UNUSED_45FF:
+        case OP_UNUSED_46FF:
+        case OP_UNUSED_47FF:
+        case OP_UNUSED_48FF:
+        case OP_UNUSED_49FF:
+        case OP_UNUSED_4AFF:
+        case OP_UNUSED_4BFF:
+        case OP_UNUSED_4CFF:
+        case OP_UNUSED_4DFF:
+        case OP_UNUSED_4EFF:
+        case OP_UNUSED_4FFF:
+        case OP_UNUSED_50FF:
+        case OP_UNUSED_51FF:
+        case OP_UNUSED_52FF:
+        case OP_UNUSED_53FF:
+        case OP_UNUSED_54FF:
+        case OP_UNUSED_55FF:
+        case OP_UNUSED_56FF:
+        case OP_UNUSED_57FF:
+        case OP_UNUSED_58FF:
+        case OP_UNUSED_59FF:
+        case OP_UNUSED_5AFF:
+        case OP_UNUSED_5BFF:
+        case OP_UNUSED_5CFF:
+        case OP_UNUSED_5DFF:
+        case OP_UNUSED_5EFF:
+        case OP_UNUSED_5FFF:
+        case OP_UNUSED_60FF:
+        case OP_UNUSED_61FF:
+        case OP_UNUSED_62FF:
+        case OP_UNUSED_63FF:
+        case OP_UNUSED_64FF:
+        case OP_UNUSED_65FF:
+        case OP_UNUSED_66FF:
+        case OP_UNUSED_67FF:
+        case OP_UNUSED_68FF:
+        case OP_UNUSED_69FF:
+        case OP_UNUSED_6AFF:
+        case OP_UNUSED_6BFF:
+        case OP_UNUSED_6CFF:
+        case OP_UNUSED_6DFF:
+        case OP_UNUSED_6EFF:
+        case OP_UNUSED_6FFF:
+        case OP_UNUSED_70FF:
+        case OP_UNUSED_71FF:
+        case OP_UNUSED_72FF:
+        case OP_UNUSED_73FF:
+        case OP_UNUSED_74FF:
+        case OP_UNUSED_75FF:
+        case OP_UNUSED_76FF:
+        case OP_UNUSED_77FF:
+        case OP_UNUSED_78FF:
+        case OP_UNUSED_79FF:
+        case OP_UNUSED_7AFF:
+        case OP_UNUSED_7BFF:
+        case OP_UNUSED_7CFF:
+        case OP_UNUSED_7DFF:
+        case OP_UNUSED_7EFF:
+        case OP_UNUSED_7FFF:
+        case OP_UNUSED_80FF:
+        case OP_UNUSED_81FF:
+        case OP_UNUSED_82FF:
+        case OP_UNUSED_83FF:
+        case OP_UNUSED_84FF:
+        case OP_UNUSED_85FF:
+        case OP_UNUSED_86FF:
+        case OP_UNUSED_87FF:
+        case OP_UNUSED_88FF:
+        case OP_UNUSED_89FF:
+        case OP_UNUSED_8AFF:
+        case OP_UNUSED_8BFF:
+        case OP_UNUSED_8CFF:
+        case OP_UNUSED_8DFF:
+        case OP_UNUSED_8EFF:
+        case OP_UNUSED_8FFF:
+        case OP_UNUSED_90FF:
+        case OP_UNUSED_91FF:
+        case OP_UNUSED_92FF:
+        case OP_UNUSED_93FF:
+        case OP_UNUSED_94FF:
+        case OP_UNUSED_95FF:
+        case OP_UNUSED_96FF:
+        case OP_UNUSED_97FF:
+        case OP_UNUSED_98FF:
+        case OP_UNUSED_99FF:
+        case OP_UNUSED_9AFF:
+        case OP_UNUSED_9BFF:
+        case OP_UNUSED_9CFF:
+        case OP_UNUSED_9DFF:
+        case OP_UNUSED_9EFF:
+        case OP_UNUSED_9FFF:
+        case OP_UNUSED_A0FF:
+        case OP_UNUSED_A1FF:
+        case OP_UNUSED_A2FF:
+        case OP_UNUSED_A3FF:
+        case OP_UNUSED_A4FF:
+        case OP_UNUSED_A5FF:
+        case OP_UNUSED_A6FF:
+        case OP_UNUSED_A7FF:
+        case OP_UNUSED_A8FF:
+        case OP_UNUSED_A9FF:
+        case OP_UNUSED_AAFF:
+        case OP_UNUSED_ABFF:
+        case OP_UNUSED_ACFF:
+        case OP_UNUSED_ADFF:
+        case OP_UNUSED_AEFF:
+        case OP_UNUSED_AFFF:
+        case OP_UNUSED_B0FF:
+        case OP_UNUSED_B1FF:
+        case OP_UNUSED_B2FF:
+        case OP_UNUSED_B3FF:
+        case OP_UNUSED_B4FF:
+        case OP_UNUSED_B5FF:
+        case OP_UNUSED_B6FF:
+        case OP_UNUSED_B7FF:
+        case OP_UNUSED_B8FF:
+        case OP_UNUSED_B9FF:
+        case OP_UNUSED_BAFF:
+        case OP_UNUSED_BBFF:
+        case OP_UNUSED_BCFF:
+        case OP_UNUSED_BDFF:
+        case OP_UNUSED_BEFF:
+        case OP_UNUSED_BFFF:
+        case OP_UNUSED_C0FF:
+        case OP_UNUSED_C1FF:
+        case OP_UNUSED_C2FF:
+        case OP_UNUSED_C3FF:
+        case OP_UNUSED_C4FF:
+        case OP_UNUSED_C5FF:
+        case OP_UNUSED_C6FF:
+        case OP_UNUSED_C7FF:
+        case OP_UNUSED_C8FF:
+        case OP_UNUSED_C9FF:
+        case OP_UNUSED_CAFF:
+        case OP_UNUSED_CBFF:
+        case OP_UNUSED_CCFF:
+        case OP_UNUSED_CDFF:
+        case OP_UNUSED_CEFF:
+        case OP_UNUSED_CFFF:
+        case OP_UNUSED_D0FF:
+        case OP_UNUSED_D1FF:
+        case OP_UNUSED_D2FF:
+        case OP_UNUSED_D3FF:
+        case OP_UNUSED_D4FF:
+        case OP_UNUSED_D5FF:
+        case OP_UNUSED_D6FF:
+        case OP_UNUSED_D7FF:
+        case OP_UNUSED_D8FF:
+        case OP_UNUSED_D9FF:
+        case OP_UNUSED_DAFF:
+        case OP_UNUSED_DBFF:
+        case OP_UNUSED_DCFF:
+        case OP_UNUSED_DDFF:
+        case OP_UNUSED_DEFF:
+        case OP_UNUSED_DFFF:
+        case OP_UNUSED_E0FF:
+        case OP_UNUSED_E1FF:
+        case OP_UNUSED_E2FF:
+        case OP_UNUSED_E3FF:
+        case OP_UNUSED_E4FF:
+        case OP_UNUSED_E5FF:
+        case OP_UNUSED_E6FF:
+        case OP_UNUSED_E7FF:
+        case OP_UNUSED_E8FF:
+        case OP_UNUSED_E9FF:
+        case OP_UNUSED_EAFF:
+        case OP_UNUSED_EBFF:
+        case OP_UNUSED_ECFF:
+        case OP_UNUSED_EDFF:
+        case OP_UNUSED_EEFF:
+        case OP_UNUSED_EFFF:
+        case OP_UNUSED_F0FF:
+        case OP_UNUSED_F1FF:
+            LOGE("VFY: unexpected opcode %04x", decInsn.opcode);
+            okay = false;
+            break;
+
+        /*
+         * DO NOT add a "default" clause here.  Without it the compiler will
+         * complain if an instruction is missing (which is desirable).
+         */
+        }
+
+        if (!okay) {
+            LOG_VFY_METH(meth, "VFY:  rejecting opcode 0x%02x at 0x%04x",
+                decInsn.opcode, codeOffset);
+            return false;
+        }
+
+        OpcodeFlags opFlags = dexGetFlagsFromOpcode(decInsn.opcode);
+        if ((opFlags & VERIFY_GC_INST_MASK) != 0) {
+            /*
+             * This instruction is a GC point.  If space is a concern,
+             * the set of GC points could be reduced by eliminating
+             * foward branches.
+             *
+             * TODO: we could also scan the targets of a "switch" statement,
+             * and if none of them branch backward we could ignore that
+             * instruction as well.
+             */
+            dvmInsnSetGcPoint(insnFlags, codeOffset, true);
+        }
+
+        assert(width > 0);
+        codeOffset += width;
+        insns += width;
+    }
+
+    /* make sure the last instruction ends at the end of the insn area */
+    if (codeOffset != vdata->insnsSize) {
+        LOG_VFY_METH(meth,
+            "VFY: code did not end when expected (end at %d, count %d)",
+            codeOffset, vdata->insnsSize);
+        return false;
+    }
+
+    return true;
+}
diff --git a/vm/analysis/DexVerify.h b/vm/analysis/DexVerify.h
new file mode 100644
index 0000000..4487720
--- /dev/null
+++ b/vm/analysis/DexVerify.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik classfile verification.
+ */
+#ifndef DALVIK_DEXVERIFY_H_
+#define DALVIK_DEXVERIFY_H_
+
+/*
+ * Global verification mode.  These must be in order from least verification
+ * to most.  If we're using "exact GC", we may need to perform some of
+ * the verification steps anyway.
+ */
+enum DexClassVerifyMode {
+    VERIFY_MODE_UNKNOWN = 0,
+    VERIFY_MODE_NONE,
+    VERIFY_MODE_REMOTE,
+    VERIFY_MODE_ALL
+};
+
+/* some verifier counters, for debugging */
+struct VerifierStats {
+    size_t methodsExamined;    /* number of methods examined */
+    size_t monEnterMethods;    /* number of methods with monitor-enter */
+    size_t instrsExamined;     /* incr on first visit of instruction */
+    size_t instrsReexamined;   /* incr on each repeat visit of instruction */
+    size_t copyRegCount;       /* calls from updateRegisters->copyRegisters */
+    size_t mergeRegCount;      /* calls from updateRegisters->merge */
+    size_t mergeRegChanged;    /* calls from updateRegisters->merge, changed */
+    size_t uninitSearches;     /* times we've had to search the uninit table */
+    size_t biggestAlloc;       /* largest RegisterLine table alloc */
+};
+
+/*
+ * Certain 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.
+ */
+#define VERIFY_GC_INST_MASK (kInstrCanBranch | kInstrCanSwitch |\
+                             kInstrCanThrow | kInstrCanReturn)
+
+/*
+ * Verify a single class.
+ */
+bool dvmVerifyClass(ClassObject* clazz);
+
+/*
+ * Release the storage associated with a RegisterMap.
+ */
+void dvmFreeRegisterMap(RegisterMap* pMap);
+
+#endif  // DALVIK_DEXVERIFY_H_
diff --git a/vm/analysis/Liveness.cpp b/vm/analysis/Liveness.cpp
new file mode 100644
index 0000000..fe9fdd8
--- /dev/null
+++ b/vm/analysis/Liveness.cpp
@@ -0,0 +1,1079 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Liveness analysis for Dalvik bytecode.
+ */
+#include "Dalvik.h"
+#include "analysis/Liveness.h"
+#include "analysis/CodeVerify.h"
+
+static bool processInstruction(VerifierData* vdata, u4 curIdx,
+    BitVector* workBits);
+static bool markDebugLocals(VerifierData* vdata);
+static void dumpLiveState(const VerifierData* vdata, u4 curIdx,
+    const BitVector* workBits);
+
+
+/*
+ * Create a table of instruction widths that indicate the width of the
+ * *previous* instruction.  The values are copied from the width table
+ * in "vdata", not derived from the instruction stream.
+ *
+ * Caller must free the return value.
+ */
+static InstructionWidth* createBackwardWidthTable(VerifierData* vdata)
+{
+    InstructionWidth* widths;
+
+    widths = (InstructionWidth*)
+            calloc(vdata->insnsSize, sizeof(InstructionWidth));
+    if (widths == NULL)
+        return NULL;
+
+    u4 insnWidth = 0;
+    for (u4 idx = 0; idx < vdata->insnsSize; ) {
+        widths[idx] = insnWidth;
+        insnWidth = dvmInsnGetWidth(vdata->insnFlags, idx);
+        idx += insnWidth;
+    }
+
+    return widths;
+}
+
+/*
+ * Compute the "liveness" of every register at all GC points.
+ */
+bool dvmComputeLiveness(VerifierData* vdata)
+{
+    const InsnFlags* insnFlags = vdata->insnFlags;
+    InstructionWidth* backwardWidth;
+    VfyBasicBlock* startGuess = NULL;
+    BitVector* workBits;
+    bool result = false;
+
+    bool verbose = false; //= dvmWantVerboseVerification(vdata->method);
+    if (verbose) {
+        const Method* meth = vdata->method;
+        LOGI("Computing liveness for %s.%s:%s",
+            meth->clazz->descriptor, meth->name, meth->shorty);
+    }
+
+    assert(vdata->registerLines != NULL);
+
+    backwardWidth = createBackwardWidthTable(vdata);
+    if (backwardWidth == NULL)
+        goto bail;
+
+    /*
+     * Allocate space for intra-block work set.  Does not include space
+     * for method result "registers", which aren't visible to the GC.
+     * (They would be made live by move-result and then die on the
+     * instruction immediately before it.)
+     */
+    workBits = dvmAllocBitVector(vdata->insnRegCount, false);
+    if (workBits == NULL)
+        goto bail;
+
+    /*
+     * We continue until all blocks have been visited, and no block
+     * requires further attention ("visited" is set and "changed" is
+     * clear).
+     *
+     * TODO: consider creating a "dense" array of basic blocks to make
+     * the walking faster.
+     */
+    for (int iter = 0;;) {
+        VfyBasicBlock* workBlock = NULL;
+
+        if (iter++ > 100000) {
+            LOG_VFY_METH(vdata->method, "oh dear");
+            dvmAbort();
+        }
+
+        /*
+         * If a block is marked "changed", we stop and handle it.  If it
+         * just hasn't been visited yet, we remember it but keep searching
+         * for one that has been changed.
+         *
+         * The thought here is that this is more likely to let us work
+         * from end to start, which reduces the amount of re-evaluation
+         * required (both by using "changed" as a work list, and by picking
+         * un-visited blocks from the tail end of the method).
+         */
+        if (startGuess != NULL) {
+            assert(startGuess->changed);
+            workBlock = startGuess;
+        } else {
+            for (u4 idx = 0; idx < vdata->insnsSize; idx++) {
+                VfyBasicBlock* block = vdata->basicBlocks[idx];
+                if (block == NULL)
+                    continue;
+
+                if (block->changed) {
+                    workBlock = block;
+                    break;
+                } else if (!block->visited) {
+                    workBlock = block;
+                }
+            }
+        }
+
+        if (workBlock == NULL) {
+            /* all done */
+            break;
+        }
+
+        assert(workBlock->changed || !workBlock->visited);
+        startGuess = NULL;
+
+        /*
+         * Load work bits.  These represent the liveness of registers
+         * after the last instruction in the block has finished executing.
+         */
+        assert(workBlock->liveRegs != NULL);
+        dvmCopyBitVector(workBits, workBlock->liveRegs);
+        if (verbose) {
+            LOGI("Loaded work bits from last=0x%04x", workBlock->lastAddr);
+            dumpLiveState(vdata, 0xfffd, workBlock->liveRegs);
+            dumpLiveState(vdata, 0xffff, workBits);
+        }
+
+        /*
+         * Process a single basic block.
+         *
+         * If this instruction is a GC point, we want to save the result
+         * in the RegisterLine.
+         *
+         * We don't break basic blocks on every GC point -- in particular,
+         * instructions that might throw but have no "try" block don't
+         * end a basic block -- so there could be more than one GC point
+         * in a given basic block.
+         *
+         * We could change this, but it turns out to be not all that useful.
+         * At first glance it appears that we could share the liveness bit
+         * vector between the basic block struct and the register line,
+         * but the basic block needs to reflect the state *after* the
+         * instruction has finished, while the GC points need to describe
+         * the state before the instruction starts.
+         */
+        u4 curIdx = workBlock->lastAddr;
+        while (true) {
+            if (!processInstruction(vdata, curIdx, workBits))
+                goto bail;
+
+            if (verbose) {
+                dumpLiveState(vdata, curIdx + 0x8000, workBits);
+            }
+
+            if (dvmInsnIsGcPoint(insnFlags, curIdx)) {
+                BitVector* lineBits = vdata->registerLines[curIdx].liveRegs;
+                if (lineBits == NULL) {
+                    lineBits = vdata->registerLines[curIdx].liveRegs =
+                        dvmAllocBitVector(vdata->insnRegCount, false);
+                }
+                dvmCopyBitVector(lineBits, workBits);
+            }
+
+            if (curIdx == workBlock->firstAddr)
+                break;
+            assert(curIdx >= backwardWidth[curIdx]);
+            curIdx -= backwardWidth[curIdx];
+        }
+
+        workBlock->visited = true;
+        workBlock->changed = false;
+
+        if (verbose) {
+            dumpLiveState(vdata, curIdx, workBits);
+        }
+
+        /*
+         * Merge changes to all predecessors.  If the new bits don't match
+         * the old bits, set the "changed" flag.
+         */
+        PointerSet* preds = workBlock->predecessors;
+        size_t numPreds = dvmPointerSetGetCount(preds);
+        unsigned int predIdx;
+
+        for (predIdx = 0; predIdx < numPreds; predIdx++) {
+            VfyBasicBlock* pred =
+                    (VfyBasicBlock*) dvmPointerSetGetEntry(preds, predIdx);
+
+            pred->changed = dvmCheckMergeBitVectors(pred->liveRegs, workBits);
+            if (verbose) {
+                LOGI("merging cur=%04x into pred last=%04x (ch=%d)",
+                    curIdx, pred->lastAddr, pred->changed);
+                dumpLiveState(vdata, 0xfffa, pred->liveRegs);
+                dumpLiveState(vdata, 0xfffb, workBits);
+            }
+
+            /*
+             * We want to set the "changed" flag on unvisited predecessors
+             * as a way of guiding the verifier through basic blocks in
+             * a reasonable order.  We can't count on variable liveness
+             * changing, so we force "changed" to true even if it hasn't.
+             */
+            if (!pred->visited)
+                pred->changed = true;
+
+            /*
+             * Keep track of one of the changed blocks so we can start
+             * there instead of having to scan through the list.
+             */
+            if (pred->changed)
+                startGuess = pred;
+        }
+    }
+
+#ifndef NDEBUG
+    /*
+     * Sanity check: verify that all GC point register lines have a
+     * liveness bit vector allocated.  Also, we're not expecting non-GC
+     * points to have them.
+     */
+    u4 checkIdx;
+    for (checkIdx = 0; checkIdx < vdata->insnsSize; ) {
+        if (dvmInsnIsGcPoint(insnFlags, checkIdx)) {
+            if (vdata->registerLines[checkIdx].liveRegs == NULL) {
+                LOG_VFY_METH(vdata->method,
+                    "GLITCH: no liveRegs for GC point 0x%04x", checkIdx);
+                dvmAbort();
+            }
+        } else if (vdata->registerLines[checkIdx].liveRegs != NULL) {
+            LOG_VFY_METH(vdata->method,
+                "GLITCH: liveRegs for non-GC point 0x%04x", checkIdx);
+            dvmAbort();
+        }
+        u4 insnWidth = dvmInsnGetWidth(insnFlags, checkIdx);
+        checkIdx += insnWidth;
+    }
+#endif
+
+    /*
+     * Factor in the debug info, if any.
+     */
+    if (!markDebugLocals(vdata))
+        goto bail;
+
+    result = true;
+
+bail:
+    free(backwardWidth);
+    return result;
+}
+
+
+/*
+ * Add a register to the LIVE set.
+ */
+static inline void GEN(BitVector* workBits, u4 regIndex)
+{
+    dvmSetBit(workBits, regIndex);
+}
+
+/*
+ * Add a register pair to the LIVE set.
+ */
+static inline void GENW(BitVector* workBits, u4 regIndex)
+{
+    dvmSetBit(workBits, regIndex);
+    dvmSetBit(workBits, regIndex+1);
+}
+
+/*
+ * Remove a register from the LIVE set.
+ */
+static inline void KILL(BitVector* workBits, u4 regIndex)
+{
+    dvmClearBit(workBits, regIndex);
+}
+
+/*
+ * Remove a register pair from the LIVE set.
+ */
+static inline void KILLW(BitVector* workBits, u4 regIndex)
+{
+    dvmClearBit(workBits, regIndex);
+    dvmClearBit(workBits, regIndex+1);
+}
+
+/*
+ * Process a single instruction.
+ *
+ * Returns "false" if something goes fatally wrong.
+ */
+static bool processInstruction(VerifierData* vdata, u4 insnIdx,
+    BitVector* workBits)
+{
+    const Method* meth = vdata->method;
+    const u2* insns = meth->insns + insnIdx;
+    DecodedInstruction decInsn;
+
+    dexDecodeInstruction(insns, &decInsn);
+
+    /*
+     * Add registers to the "GEN" or "KILL" sets.  We want to do KILL
+     * before GEN to handle cases where the source and destination
+     * register is the same.
+     */
+    switch (decInsn.opcode) {
+    case OP_NOP:
+    case OP_RETURN_VOID:
+    case OP_GOTO:
+    case OP_GOTO_16:
+    case OP_GOTO_32:
+        /* no registers are used */
+        break;
+
+    case OP_RETURN:
+    case OP_RETURN_OBJECT:
+    case OP_MONITOR_ENTER:
+    case OP_MONITOR_EXIT:
+    case OP_CHECK_CAST:
+    case OP_CHECK_CAST_JUMBO:
+    case OP_THROW:
+    case OP_PACKED_SWITCH:
+    case OP_SPARSE_SWITCH:
+    case OP_FILL_ARRAY_DATA:
+    case OP_IF_EQZ:
+    case OP_IF_NEZ:
+    case OP_IF_LTZ:
+    case OP_IF_GEZ:
+    case OP_IF_GTZ:
+    case OP_IF_LEZ:
+    case OP_SPUT:
+    case OP_SPUT_JUMBO:
+    case OP_SPUT_BOOLEAN:
+    case OP_SPUT_BOOLEAN_JUMBO:
+    case OP_SPUT_BYTE:
+    case OP_SPUT_BYTE_JUMBO:
+    case OP_SPUT_CHAR:
+    case OP_SPUT_CHAR_JUMBO:
+    case OP_SPUT_SHORT:
+    case OP_SPUT_SHORT_JUMBO:
+    case OP_SPUT_OBJECT:
+    case OP_SPUT_OBJECT_JUMBO:
+        /* action <- vA */
+        GEN(workBits, decInsn.vA);
+        break;
+
+    case OP_RETURN_WIDE:
+    case OP_SPUT_WIDE:
+    case OP_SPUT_WIDE_JUMBO:
+        /* action <- vA(wide) */
+        GENW(workBits, decInsn.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:
+    case OP_IPUT:
+    case OP_IPUT_JUMBO:
+    case OP_IPUT_BOOLEAN:
+    case OP_IPUT_BOOLEAN_JUMBO:
+    case OP_IPUT_BYTE:
+    case OP_IPUT_BYTE_JUMBO:
+    case OP_IPUT_CHAR:
+    case OP_IPUT_CHAR_JUMBO:
+    case OP_IPUT_SHORT:
+    case OP_IPUT_SHORT_JUMBO:
+    case OP_IPUT_OBJECT:
+    case OP_IPUT_OBJECT_JUMBO:
+        /* action <- vA, vB */
+        GEN(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        break;
+
+    case OP_IPUT_WIDE:
+    case OP_IPUT_WIDE_JUMBO:
+        /* action <- vA(wide), vB */
+        GENW(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        break;
+
+    case OP_APUT:
+    case OP_APUT_BOOLEAN:
+    case OP_APUT_BYTE:
+    case OP_APUT_CHAR:
+    case OP_APUT_SHORT:
+    case OP_APUT_OBJECT:
+        /* action <- vA, vB, vC */
+        GEN(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        GEN(workBits, decInsn.vC);
+        break;
+
+    case OP_APUT_WIDE:
+        /* action <- vA(wide), vB, vC */
+        GENW(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        GEN(workBits, decInsn.vC);
+        break;
+
+    case OP_FILLED_NEW_ARRAY:
+    case OP_INVOKE_VIRTUAL:
+    case OP_INVOKE_SUPER:
+    case OP_INVOKE_DIRECT:
+    case OP_INVOKE_STATIC:
+    case OP_INVOKE_INTERFACE:
+        /* action <- vararg */
+        {
+            unsigned int idx;
+            for (idx = 0; idx < decInsn.vA; idx++) {
+                GEN(workBits, decInsn.arg[idx]);
+            }
+        }
+        break;
+
+    case OP_FILLED_NEW_ARRAY_RANGE:
+    case OP_FILLED_NEW_ARRAY_JUMBO:
+    case OP_INVOKE_VIRTUAL_RANGE:
+    case OP_INVOKE_VIRTUAL_JUMBO:
+    case OP_INVOKE_SUPER_RANGE:
+    case OP_INVOKE_SUPER_JUMBO:
+    case OP_INVOKE_DIRECT_RANGE:
+    case OP_INVOKE_DIRECT_JUMBO:
+    case OP_INVOKE_STATIC_RANGE:
+    case OP_INVOKE_STATIC_JUMBO:
+    case OP_INVOKE_INTERFACE_RANGE:
+    case OP_INVOKE_INTERFACE_JUMBO:
+        /* action <- vararg/range */
+        {
+            unsigned int idx;
+            for (idx = 0; idx < decInsn.vA; idx++) {
+                GEN(workBits, decInsn.vC + idx);
+            }
+        }
+        break;
+
+    case OP_MOVE_RESULT:
+    case OP_MOVE_RESULT_WIDE:
+    case OP_MOVE_RESULT_OBJECT:
+    case OP_MOVE_EXCEPTION:
+    case OP_CONST_4:
+    case OP_CONST_16:
+    case OP_CONST:
+    case OP_CONST_HIGH16:
+    case OP_CONST_STRING:
+    case OP_CONST_STRING_JUMBO:
+    case OP_CONST_CLASS:
+    case OP_CONST_CLASS_JUMBO:
+    case OP_NEW_INSTANCE:
+    case OP_NEW_INSTANCE_JUMBO:
+    case OP_SGET:
+    case OP_SGET_JUMBO:
+    case OP_SGET_BOOLEAN:
+    case OP_SGET_BOOLEAN_JUMBO:
+    case OP_SGET_BYTE:
+    case OP_SGET_BYTE_JUMBO:
+    case OP_SGET_CHAR:
+    case OP_SGET_CHAR_JUMBO:
+    case OP_SGET_SHORT:
+    case OP_SGET_SHORT_JUMBO:
+    case OP_SGET_OBJECT:
+    case OP_SGET_OBJECT_JUMBO:
+        /* vA <- value */
+        KILL(workBits, decInsn.vA);
+        break;
+
+    case OP_CONST_WIDE_16:
+    case OP_CONST_WIDE_32:
+    case OP_CONST_WIDE:
+    case OP_CONST_WIDE_HIGH16:
+    case OP_SGET_WIDE:
+    case OP_SGET_WIDE_JUMBO:
+        /* vA(wide) <- value */
+        KILLW(workBits, decInsn.vA);
+        break;
+
+    case OP_MOVE:
+    case OP_MOVE_FROM16:
+    case OP_MOVE_16:
+    case OP_MOVE_OBJECT:
+    case OP_MOVE_OBJECT_FROM16:
+    case OP_MOVE_OBJECT_16:
+    case OP_INSTANCE_OF:
+    case OP_INSTANCE_OF_JUMBO:
+    case OP_ARRAY_LENGTH:
+    case OP_NEW_ARRAY:
+    case OP_NEW_ARRAY_JUMBO:
+    case OP_IGET:
+    case OP_IGET_JUMBO:
+    case OP_IGET_BOOLEAN:
+    case OP_IGET_BOOLEAN_JUMBO:
+    case OP_IGET_BYTE:
+    case OP_IGET_BYTE_JUMBO:
+    case OP_IGET_CHAR:
+    case OP_IGET_CHAR_JUMBO:
+    case OP_IGET_SHORT:
+    case OP_IGET_SHORT_JUMBO:
+    case OP_IGET_OBJECT:
+    case OP_IGET_OBJECT_JUMBO:
+    case OP_NEG_INT:
+    case OP_NOT_INT:
+    case OP_NEG_FLOAT:
+    case OP_INT_TO_FLOAT:
+    case OP_FLOAT_TO_INT:
+    case OP_INT_TO_BYTE:
+    case OP_INT_TO_CHAR:
+    case OP_INT_TO_SHORT:
+    case OP_ADD_INT_LIT16:
+    case OP_RSUB_INT:
+    case OP_MUL_INT_LIT16:
+    case OP_DIV_INT_LIT16:
+    case OP_REM_INT_LIT16:
+    case OP_AND_INT_LIT16:
+    case OP_OR_INT_LIT16:
+    case OP_XOR_INT_LIT16:
+    case OP_ADD_INT_LIT8:
+    case OP_RSUB_INT_LIT8:
+    case OP_MUL_INT_LIT8:
+    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:
+    case OP_AND_INT_LIT8:
+    case OP_OR_INT_LIT8:
+    case OP_XOR_INT_LIT8:
+        /* vA <- vB */
+        KILL(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        break;
+
+    case OP_IGET_WIDE:
+    case OP_IGET_WIDE_JUMBO:
+    case OP_INT_TO_LONG:
+    case OP_INT_TO_DOUBLE:
+    case OP_FLOAT_TO_LONG:
+    case OP_FLOAT_TO_DOUBLE:
+        /* vA(wide) <- vB */
+        KILLW(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        break;
+
+    case OP_LONG_TO_INT:
+    case OP_LONG_TO_FLOAT:
+    case OP_DOUBLE_TO_INT:
+    case OP_DOUBLE_TO_FLOAT:
+        /* vA <- vB(wide) */
+        KILL(workBits, decInsn.vA);
+        GENW(workBits, decInsn.vB);
+        break;
+
+    case OP_MOVE_WIDE:
+    case OP_MOVE_WIDE_FROM16:
+    case OP_MOVE_WIDE_16:
+    case OP_NEG_LONG:
+    case OP_NOT_LONG:
+    case OP_NEG_DOUBLE:
+    case OP_LONG_TO_DOUBLE:
+    case OP_DOUBLE_TO_LONG:
+        /* vA(wide) <- vB(wide) */
+        KILLW(workBits, decInsn.vA);
+        GENW(workBits, decInsn.vB);
+        break;
+
+    case OP_CMPL_FLOAT:
+    case OP_CMPG_FLOAT:
+    case OP_AGET:
+    case OP_AGET_BOOLEAN:
+    case OP_AGET_BYTE:
+    case OP_AGET_CHAR:
+    case OP_AGET_SHORT:
+    case OP_AGET_OBJECT:
+    case OP_ADD_INT:
+    case OP_SUB_INT:
+    case OP_MUL_INT:
+    case OP_REM_INT:
+    case OP_DIV_INT:
+    case OP_AND_INT:
+    case OP_OR_INT:
+    case OP_XOR_INT:
+    case OP_SHL_INT:
+    case OP_SHR_INT:
+    case OP_USHR_INT:
+    case OP_ADD_FLOAT:
+    case OP_SUB_FLOAT:
+    case OP_MUL_FLOAT:
+    case OP_DIV_FLOAT:
+    case OP_REM_FLOAT:
+        /* vA <- vB, vC */
+        KILL(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        GEN(workBits, decInsn.vC);
+        break;
+
+    case OP_AGET_WIDE:
+        /* vA(wide) <- vB, vC */
+        KILLW(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        GEN(workBits, decInsn.vC);
+        break;
+
+    case OP_CMPL_DOUBLE:
+    case OP_CMPG_DOUBLE:
+    case OP_CMP_LONG:
+        /* vA <- vB(wide), vC(wide) */
+        KILL(workBits, decInsn.vA);
+        GENW(workBits, decInsn.vB);
+        GENW(workBits, decInsn.vC);
+        break;
+
+    case OP_SHL_LONG:
+    case OP_SHR_LONG:
+    case OP_USHR_LONG:
+        /* vA(wide) <- vB(wide), vC */
+        KILLW(workBits, decInsn.vA);
+        GENW(workBits, decInsn.vB);
+        GEN(workBits, decInsn.vC);
+        break;
+
+    case OP_ADD_LONG:
+    case OP_SUB_LONG:
+    case OP_MUL_LONG:
+    case OP_DIV_LONG:
+    case OP_REM_LONG:
+    case OP_AND_LONG:
+    case OP_OR_LONG:
+    case OP_XOR_LONG:
+    case OP_ADD_DOUBLE:
+    case OP_SUB_DOUBLE:
+    case OP_MUL_DOUBLE:
+    case OP_DIV_DOUBLE:
+    case OP_REM_DOUBLE:
+        /* vA(wide) <- vB(wide), vC(wide) */
+        KILLW(workBits, decInsn.vA);
+        GENW(workBits, decInsn.vB);
+        GENW(workBits, decInsn.vC);
+        break;
+
+    case OP_ADD_INT_2ADDR:
+    case OP_SUB_INT_2ADDR:
+    case OP_MUL_INT_2ADDR:
+    case OP_REM_INT_2ADDR:
+    case OP_SHL_INT_2ADDR:
+    case OP_SHR_INT_2ADDR:
+    case OP_USHR_INT_2ADDR:
+    case OP_AND_INT_2ADDR:
+    case OP_OR_INT_2ADDR:
+    case OP_XOR_INT_2ADDR:
+    case OP_DIV_INT_2ADDR:
+        /* vA <- vA, vB */
+        /* KILL(workBits, decInsn.vA); */
+        GEN(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        break;
+
+    case OP_SHL_LONG_2ADDR:
+    case OP_SHR_LONG_2ADDR:
+    case OP_USHR_LONG_2ADDR:
+        /* vA(wide) <- vA(wide), vB */
+        /* KILLW(workBits, decInsn.vA); */
+        GENW(workBits, decInsn.vA);
+        GEN(workBits, decInsn.vB);
+        break;
+
+    case OP_ADD_LONG_2ADDR:
+    case OP_SUB_LONG_2ADDR:
+    case OP_MUL_LONG_2ADDR:
+    case OP_DIV_LONG_2ADDR:
+    case OP_REM_LONG_2ADDR:
+    case OP_AND_LONG_2ADDR:
+    case OP_OR_LONG_2ADDR:
+    case OP_XOR_LONG_2ADDR:
+    case OP_ADD_FLOAT_2ADDR:
+    case OP_SUB_FLOAT_2ADDR:
+    case OP_MUL_FLOAT_2ADDR:
+    case OP_DIV_FLOAT_2ADDR:
+    case OP_REM_FLOAT_2ADDR:
+    case OP_ADD_DOUBLE_2ADDR:
+    case OP_SUB_DOUBLE_2ADDR:
+    case OP_MUL_DOUBLE_2ADDR:
+    case OP_DIV_DOUBLE_2ADDR:
+    case OP_REM_DOUBLE_2ADDR:
+        /* vA(wide) <- vA(wide), vB(wide) */
+        /* KILLW(workBits, decInsn.vA); */
+        GENW(workBits, decInsn.vA);
+        GENW(workBits, decInsn.vB);
+        break;
+
+    /* we will only see this if liveness analysis is done after general vfy */
+    case OP_THROW_VERIFICATION_ERROR:
+    case OP_THROW_VERIFICATION_ERROR_JUMBO:
+        /* no registers used */
+        break;
+
+    /* quickened instructions, not expected to appear */
+    case OP_EXECUTE_INLINE:
+    case OP_EXECUTE_INLINE_RANGE:
+    case OP_IGET_QUICK:
+    case OP_IGET_WIDE_QUICK:
+    case OP_IGET_OBJECT_QUICK:
+    case OP_IPUT_QUICK:
+    case OP_IPUT_WIDE_QUICK:
+    case OP_IPUT_OBJECT_QUICK:
+    case OP_INVOKE_VIRTUAL_QUICK:
+    case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+    case OP_INVOKE_SUPER_QUICK:
+    case OP_INVOKE_SUPER_QUICK_RANGE:
+        /* fall through to failure */
+
+    /* correctness fixes, not expected to appear */
+    case OP_INVOKE_OBJECT_INIT_RANGE:
+    case OP_INVOKE_OBJECT_INIT_JUMBO:
+    case OP_RETURN_VOID_BARRIER:
+    case OP_SPUT_VOLATILE:
+    case OP_SPUT_VOLATILE_JUMBO:
+    case OP_SPUT_OBJECT_VOLATILE:
+    case OP_SPUT_OBJECT_VOLATILE_JUMBO:
+    case OP_SPUT_WIDE_VOLATILE:
+    case OP_SPUT_WIDE_VOLATILE_JUMBO:
+    case OP_IPUT_VOLATILE:
+    case OP_IPUT_VOLATILE_JUMBO:
+    case OP_IPUT_OBJECT_VOLATILE:
+    case OP_IPUT_OBJECT_VOLATILE_JUMBO:
+    case OP_IPUT_WIDE_VOLATILE:
+    case OP_IPUT_WIDE_VOLATILE_JUMBO:
+    case OP_SGET_VOLATILE:
+    case OP_SGET_VOLATILE_JUMBO:
+    case OP_SGET_OBJECT_VOLATILE:
+    case OP_SGET_OBJECT_VOLATILE_JUMBO:
+    case OP_SGET_WIDE_VOLATILE:
+    case OP_SGET_WIDE_VOLATILE_JUMBO:
+    case OP_IGET_VOLATILE:
+    case OP_IGET_VOLATILE_JUMBO:
+    case OP_IGET_OBJECT_VOLATILE:
+    case OP_IGET_OBJECT_VOLATILE_JUMBO:
+    case OP_IGET_WIDE_VOLATILE:
+    case OP_IGET_WIDE_VOLATILE_JUMBO:
+        /* fall through to failure */
+
+    /* these should never appear during verification */
+    case OP_UNUSED_3E:
+    case OP_UNUSED_3F:
+    case OP_UNUSED_40:
+    case OP_UNUSED_41:
+    case OP_UNUSED_42:
+    case OP_UNUSED_43:
+    case OP_UNUSED_73:
+    case OP_UNUSED_79:
+    case OP_UNUSED_7A:
+    case OP_BREAKPOINT:
+    case OP_DISPATCH_FF:
+    case OP_UNUSED_27FF:
+    case OP_UNUSED_28FF:
+    case OP_UNUSED_29FF:
+    case OP_UNUSED_2AFF:
+    case OP_UNUSED_2BFF:
+    case OP_UNUSED_2CFF:
+    case OP_UNUSED_2DFF:
+    case OP_UNUSED_2EFF:
+    case OP_UNUSED_2FFF:
+    case OP_UNUSED_30FF:
+    case OP_UNUSED_31FF:
+    case OP_UNUSED_32FF:
+    case OP_UNUSED_33FF:
+    case OP_UNUSED_34FF:
+    case OP_UNUSED_35FF:
+    case OP_UNUSED_36FF:
+    case OP_UNUSED_37FF:
+    case OP_UNUSED_38FF:
+    case OP_UNUSED_39FF:
+    case OP_UNUSED_3AFF:
+    case OP_UNUSED_3BFF:
+    case OP_UNUSED_3CFF:
+    case OP_UNUSED_3DFF:
+    case OP_UNUSED_3EFF:
+    case OP_UNUSED_3FFF:
+    case OP_UNUSED_40FF:
+    case OP_UNUSED_41FF:
+    case OP_UNUSED_42FF:
+    case OP_UNUSED_43FF:
+    case OP_UNUSED_44FF:
+    case OP_UNUSED_45FF:
+    case OP_UNUSED_46FF:
+    case OP_UNUSED_47FF:
+    case OP_UNUSED_48FF:
+    case OP_UNUSED_49FF:
+    case OP_UNUSED_4AFF:
+    case OP_UNUSED_4BFF:
+    case OP_UNUSED_4CFF:
+    case OP_UNUSED_4DFF:
+    case OP_UNUSED_4EFF:
+    case OP_UNUSED_4FFF:
+    case OP_UNUSED_50FF:
+    case OP_UNUSED_51FF:
+    case OP_UNUSED_52FF:
+    case OP_UNUSED_53FF:
+    case OP_UNUSED_54FF:
+    case OP_UNUSED_55FF:
+    case OP_UNUSED_56FF:
+    case OP_UNUSED_57FF:
+    case OP_UNUSED_58FF:
+    case OP_UNUSED_59FF:
+    case OP_UNUSED_5AFF:
+    case OP_UNUSED_5BFF:
+    case OP_UNUSED_5CFF:
+    case OP_UNUSED_5DFF:
+    case OP_UNUSED_5EFF:
+    case OP_UNUSED_5FFF:
+    case OP_UNUSED_60FF:
+    case OP_UNUSED_61FF:
+    case OP_UNUSED_62FF:
+    case OP_UNUSED_63FF:
+    case OP_UNUSED_64FF:
+    case OP_UNUSED_65FF:
+    case OP_UNUSED_66FF:
+    case OP_UNUSED_67FF:
+    case OP_UNUSED_68FF:
+    case OP_UNUSED_69FF:
+    case OP_UNUSED_6AFF:
+    case OP_UNUSED_6BFF:
+    case OP_UNUSED_6CFF:
+    case OP_UNUSED_6DFF:
+    case OP_UNUSED_6EFF:
+    case OP_UNUSED_6FFF:
+    case OP_UNUSED_70FF:
+    case OP_UNUSED_71FF:
+    case OP_UNUSED_72FF:
+    case OP_UNUSED_73FF:
+    case OP_UNUSED_74FF:
+    case OP_UNUSED_75FF:
+    case OP_UNUSED_76FF:
+    case OP_UNUSED_77FF:
+    case OP_UNUSED_78FF:
+    case OP_UNUSED_79FF:
+    case OP_UNUSED_7AFF:
+    case OP_UNUSED_7BFF:
+    case OP_UNUSED_7CFF:
+    case OP_UNUSED_7DFF:
+    case OP_UNUSED_7EFF:
+    case OP_UNUSED_7FFF:
+    case OP_UNUSED_80FF:
+    case OP_UNUSED_81FF:
+    case OP_UNUSED_82FF:
+    case OP_UNUSED_83FF:
+    case OP_UNUSED_84FF:
+    case OP_UNUSED_85FF:
+    case OP_UNUSED_86FF:
+    case OP_UNUSED_87FF:
+    case OP_UNUSED_88FF:
+    case OP_UNUSED_89FF:
+    case OP_UNUSED_8AFF:
+    case OP_UNUSED_8BFF:
+    case OP_UNUSED_8CFF:
+    case OP_UNUSED_8DFF:
+    case OP_UNUSED_8EFF:
+    case OP_UNUSED_8FFF:
+    case OP_UNUSED_90FF:
+    case OP_UNUSED_91FF:
+    case OP_UNUSED_92FF:
+    case OP_UNUSED_93FF:
+    case OP_UNUSED_94FF:
+    case OP_UNUSED_95FF:
+    case OP_UNUSED_96FF:
+    case OP_UNUSED_97FF:
+    case OP_UNUSED_98FF:
+    case OP_UNUSED_99FF:
+    case OP_UNUSED_9AFF:
+    case OP_UNUSED_9BFF:
+    case OP_UNUSED_9CFF:
+    case OP_UNUSED_9DFF:
+    case OP_UNUSED_9EFF:
+    case OP_UNUSED_9FFF:
+    case OP_UNUSED_A0FF:
+    case OP_UNUSED_A1FF:
+    case OP_UNUSED_A2FF:
+    case OP_UNUSED_A3FF:
+    case OP_UNUSED_A4FF:
+    case OP_UNUSED_A5FF:
+    case OP_UNUSED_A6FF:
+    case OP_UNUSED_A7FF:
+    case OP_UNUSED_A8FF:
+    case OP_UNUSED_A9FF:
+    case OP_UNUSED_AAFF:
+    case OP_UNUSED_ABFF:
+    case OP_UNUSED_ACFF:
+    case OP_UNUSED_ADFF:
+    case OP_UNUSED_AEFF:
+    case OP_UNUSED_AFFF:
+    case OP_UNUSED_B0FF:
+    case OP_UNUSED_B1FF:
+    case OP_UNUSED_B2FF:
+    case OP_UNUSED_B3FF:
+    case OP_UNUSED_B4FF:
+    case OP_UNUSED_B5FF:
+    case OP_UNUSED_B6FF:
+    case OP_UNUSED_B7FF:
+    case OP_UNUSED_B8FF:
+    case OP_UNUSED_B9FF:
+    case OP_UNUSED_BAFF:
+    case OP_UNUSED_BBFF:
+    case OP_UNUSED_BCFF:
+    case OP_UNUSED_BDFF:
+    case OP_UNUSED_BEFF:
+    case OP_UNUSED_BFFF:
+    case OP_UNUSED_C0FF:
+    case OP_UNUSED_C1FF:
+    case OP_UNUSED_C2FF:
+    case OP_UNUSED_C3FF:
+    case OP_UNUSED_C4FF:
+    case OP_UNUSED_C5FF:
+    case OP_UNUSED_C6FF:
+    case OP_UNUSED_C7FF:
+    case OP_UNUSED_C8FF:
+    case OP_UNUSED_C9FF:
+    case OP_UNUSED_CAFF:
+    case OP_UNUSED_CBFF:
+    case OP_UNUSED_CCFF:
+    case OP_UNUSED_CDFF:
+    case OP_UNUSED_CEFF:
+    case OP_UNUSED_CFFF:
+    case OP_UNUSED_D0FF:
+    case OP_UNUSED_D1FF:
+    case OP_UNUSED_D2FF:
+    case OP_UNUSED_D3FF:
+    case OP_UNUSED_D4FF:
+    case OP_UNUSED_D5FF:
+    case OP_UNUSED_D6FF:
+    case OP_UNUSED_D7FF:
+    case OP_UNUSED_D8FF:
+    case OP_UNUSED_D9FF:
+    case OP_UNUSED_DAFF:
+    case OP_UNUSED_DBFF:
+    case OP_UNUSED_DCFF:
+    case OP_UNUSED_DDFF:
+    case OP_UNUSED_DEFF:
+    case OP_UNUSED_DFFF:
+    case OP_UNUSED_E0FF:
+    case OP_UNUSED_E1FF:
+    case OP_UNUSED_E2FF:
+    case OP_UNUSED_E3FF:
+    case OP_UNUSED_E4FF:
+    case OP_UNUSED_E5FF:
+    case OP_UNUSED_E6FF:
+    case OP_UNUSED_E7FF:
+    case OP_UNUSED_E8FF:
+    case OP_UNUSED_E9FF:
+    case OP_UNUSED_EAFF:
+    case OP_UNUSED_EBFF:
+    case OP_UNUSED_ECFF:
+    case OP_UNUSED_EDFF:
+    case OP_UNUSED_EEFF:
+    case OP_UNUSED_EFFF:
+    case OP_UNUSED_F0FF:
+    case OP_UNUSED_F1FF:
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * This is a dexDecodeDebugInfo callback, used by markDebugLocals().
+ */
+static void markLocalsCb(void* ctxt, u2 reg, u4 startAddress, u4 endAddress,
+    const char* name, const char* descriptor, const char* signature)
+{
+    VerifierData* vdata = (VerifierData*) ctxt;
+    bool verbose = dvmWantVerboseVerification(vdata->method);
+
+    if (verbose) {
+        LOGI("%04x-%04x %2d (%s %s)",
+            startAddress, endAddress, reg, name, descriptor);
+    }
+
+    bool wide = (descriptor[0] == 'D' || descriptor[0] == 'J');
+    assert(reg <= vdata->insnRegCount + (wide ? 1 : 0));
+
+    /*
+     * Set the bit in all GC point instructions in the range
+     * [startAddress, endAddress).
+     */
+    unsigned int idx;
+    for (idx = startAddress; idx < endAddress; idx++) {
+        BitVector* liveRegs = vdata->registerLines[idx].liveRegs;
+        if (liveRegs != NULL) {
+            if (wide) {
+                GENW(liveRegs, reg);
+            } else {
+                GEN(liveRegs, reg);
+            }
+        }
+    }
+}
+
+/*
+ * Mark all debugger-visible locals as live.
+ *
+ * The "locals" table describes the positions of the various locals in the
+ * stack frame based on the current execution address.  If the debugger
+ * wants to display one, it issues a request by "slot number".  We need
+ * to ensure that references in stack slots that might be queried by the
+ * debugger aren't GCed.
+ *
+ * (If the GC had some way to mark the slot as invalid we wouldn't have
+ * to do this.  We could also have the debugger interface check the
+ * register map and simply refuse to return a "dead" value, but that's
+ * potentially confusing since the referred-to object might actually be
+ * alive, and being able to see it without having to hunt around for a
+ * "live" stack frame is useful.)
+ */
+static bool markDebugLocals(VerifierData* vdata)
+{
+    const Method* meth = vdata->method;
+
+    dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile, dvmGetMethodCode(meth),
+        meth->clazz->descriptor, meth->prototype.protoIdx, meth->accessFlags,
+        NULL, markLocalsCb, vdata);
+
+    return true;
+}
+
+
+/*
+ * Dump the liveness bits to the log.
+ *
+ * "curIdx" is for display only.
+ */
+static void dumpLiveState(const VerifierData* vdata, u4 curIdx,
+    const BitVector* workBits)
+{
+    u4 insnRegCount = vdata->insnRegCount;
+    size_t regCharSize = insnRegCount + (insnRegCount-1)/4 + 2 +1;
+    char regChars[regCharSize +1];
+    unsigned int idx;
+
+    memset(regChars, ' ', regCharSize);
+    regChars[0] = '[';
+    if (insnRegCount == 0)
+        regChars[1] = ']';
+    else
+        regChars[1 + (insnRegCount-1) + (insnRegCount-1)/4 +1] = ']';
+    regChars[regCharSize] = '\0';
+
+    for (idx = 0; idx < insnRegCount; idx++) {
+        char ch = dvmIsBitSet(workBits, idx) ? '+' : '-';
+        regChars[1 + idx + (idx/4)] = ch;
+    }
+
+    LOGI("0x%04x %s", curIdx, regChars);
+}
diff --git a/vm/analysis/Liveness.h b/vm/analysis/Liveness.h
new file mode 100644
index 0000000..5f4acfe
--- /dev/null
+++ b/vm/analysis/Liveness.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Liveness analysis.
+ */
+#ifndef DALVIK_LIVENESS_H_
+#define DALVIK_LIVENESS_H_
+
+struct VerifierData;
+
+bool dvmComputeLiveness(struct VerifierData* vdata);
+
+#endif  // DALVIK_LIVENESS_H_
diff --git a/vm/analysis/Optimize.cpp b/vm/analysis/Optimize.cpp
new file mode 100644
index 0000000..ccef01e
--- /dev/null
+++ b/vm/analysis/Optimize.cpp
@@ -0,0 +1,1335 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Perform some simple bytecode optimizations, chiefly "quickening" of
+ * opcodes.
+ */
+#include "Dalvik.h"
+#include "libdex/InstrUtils.h"
+#include "Optimize.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+
+/*
+ * Virtual/direct calls to "method" are replaced with an execute-inline
+ * instruction with index "idx".
+ */
+struct InlineSub {
+    Method* method;
+    int     inlineIdx;
+};
+
+
+/* fwd */
+static void optimizeMethod(Method* method, bool essentialOnly);
+static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
+    Opcode volatileOpc);
+static void rewriteJumboInstField(Method* method, u2* insns,
+    Opcode volatileOpc);
+static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
+static void rewriteJumboStaticField(Method* method, u2* insns,
+    Opcode volatileOpc);
+static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
+static bool rewriteInvokeObjectInit(Method* method, u2* insns);
+static bool rewriteJumboInvokeObjectInit(Method* method, u2* insns);
+static bool rewriteExecuteInline(Method* method, u2* insns,
+    MethodType methodType);
+static bool rewriteExecuteInlineRange(Method* method, u2* insns,
+    MethodType methodType);
+static void rewriteReturnVoid(Method* method, u2* insns);
+static bool needsReturnBarrier(Method* method);
+
+
+/*
+ * Create a table of inline substitutions.  Sets gDvm.inlineSubs.
+ *
+ * TODO: this is currently just a linear array.  We will want to put this
+ * into a hash table as the list size increases.
+ */
+bool dvmCreateInlineSubsTable()
+{
+    const InlineOperation* ops = dvmGetInlineOpsTable();
+    const int count = dvmGetInlineOpsTableLength();
+    InlineSub* table;
+    int i, tableIndex;
+
+    assert(gDvm.inlineSubs == NULL);
+
+    /*
+     * One slot per entry, plus an end-of-list marker.
+     */
+    table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
+
+    tableIndex = 0;
+    for (i = 0; i < count; i++) {
+        Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
+            ops[i].methodName, ops[i].methodSignature);
+        if (method == NULL) {
+            /*
+             * Not expected.  We only use this for key methods in core
+             * classes, so we should always be able to find them.
+             */
+            LOGE("Unable to find method for inlining: %s.%s:%s",
+                ops[i].classDescriptor, ops[i].methodName,
+                ops[i].methodSignature);
+            return false;
+        }
+
+        table[tableIndex].method = method;
+        table[tableIndex].inlineIdx = i;
+        tableIndex++;
+    }
+
+    /* mark end of table */
+    table[tableIndex].method = NULL;
+
+    gDvm.inlineSubs = table;
+    return true;
+}
+
+/*
+ * Release inline sub data structure.
+ */
+void dvmFreeInlineSubsTable()
+{
+    free(gDvm.inlineSubs);
+    gDvm.inlineSubs = NULL;
+}
+
+
+/*
+ * Optimize the specified class.
+ *
+ * If "essentialOnly" is true, we only do essential optimizations.  For
+ * example, accesses to volatile 64-bit fields must be replaced with
+ * "-wide-volatile" instructions or the program could behave incorrectly.
+ * (Skipping non-essential optimizations makes us a little bit faster, and
+ * more importantly avoids dirtying DEX pages.)
+ */
+void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
+{
+    int i;
+
+    for (i = 0; i < clazz->directMethodCount; i++) {
+        optimizeMethod(&clazz->directMethods[i], essentialOnly);
+    }
+    for (i = 0; i < clazz->virtualMethodCount; i++) {
+        optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
+    }
+}
+
+/*
+ * Optimize instructions in a method.
+ *
+ * This does a single pass through the code, examining each instruction.
+ *
+ * This is not expected to fail if the class was successfully verified.
+ * The only significant failure modes on unverified code occur when an
+ * "essential" update fails, but we can't generally identify those: if we
+ * can't look up a field, we can't know if the field access was supposed
+ * to be handled as volatile.
+ *
+ * Instead, we give it our best effort, and hope for the best.  For 100%
+ * reliability, only optimize a class after verification succeeds.
+ */
+static void optimizeMethod(Method* method, bool essentialOnly)
+{
+    bool needRetBar, forSmp;
+    u4 insnsSize;
+    u2* insns;
+
+    if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
+        return;
+
+    forSmp = gDvm.dexOptForSmp;
+    needRetBar = needsReturnBarrier(method);
+
+    insns = (u2*) method->insns;
+    assert(insns != NULL);
+    insnsSize = dvmGetMethodInsnsSize(method);
+
+    while (insnsSize > 0) {
+        Opcode opc, quickOpc, volatileOpc;
+        size_t width;
+        bool matched = true;
+
+        opc = dexOpcodeFromCodeUnit(*insns);
+        width = dexGetWidthFromInstruction(insns);
+        volatileOpc = OP_NOP;
+
+        /*
+         * Each instruction may have:
+         * - "volatile" replacement
+         *   - may be essential or essential-on-SMP
+         * - correctness replacement
+         *   - may be essential or essential-on-SMP
+         * - performance replacement
+         *   - always non-essential
+         *
+         * Replacements are considered in the order shown, and the first
+         * match is applied.  For example, iget-wide will convert to
+         * iget-wide-volatile rather than iget-wide-quick if the target
+         * field is volatile.
+         */
+
+        /*
+         * essential substitutions:
+         *  {iget,iput,sget,sput}-wide[/jumbo] --> {op}-wide-volatile
+         *  invoke-direct[/jumbo][/range] --> invoke-object-init/range
+         *
+         * essential-on-SMP substitutions:
+         *  {iget,iput,sget,sput}-*[/jumbo] --> {op}-volatile
+         *  return-void --> return-void-barrier
+         *
+         * non-essential substitutions:
+         *  {iget,iput}-* --> {op}-quick
+         *
+         * TODO: might be time to merge this with the other two switches
+         */
+        switch (opc) {
+        case OP_IGET:
+        case OP_IGET_BOOLEAN:
+        case OP_IGET_BYTE:
+        case OP_IGET_CHAR:
+        case OP_IGET_SHORT:
+            quickOpc = OP_IGET_QUICK;
+            if (forSmp)
+                volatileOpc = OP_IGET_VOLATILE;
+            goto rewrite_inst_field;
+        case OP_IGET_WIDE:
+            quickOpc = OP_IGET_WIDE_QUICK;
+            volatileOpc = OP_IGET_WIDE_VOLATILE;
+            goto rewrite_inst_field;
+        case OP_IGET_OBJECT:
+            quickOpc = OP_IGET_OBJECT_QUICK;
+            if (forSmp)
+                volatileOpc = OP_IGET_OBJECT_VOLATILE;
+            goto rewrite_inst_field;
+        case OP_IPUT:
+        case OP_IPUT_BOOLEAN:
+        case OP_IPUT_BYTE:
+        case OP_IPUT_CHAR:
+        case OP_IPUT_SHORT:
+            quickOpc = OP_IPUT_QUICK;
+            if (forSmp)
+                volatileOpc = OP_IPUT_VOLATILE;
+            goto rewrite_inst_field;
+        case OP_IPUT_WIDE:
+            quickOpc = OP_IPUT_WIDE_QUICK;
+            volatileOpc = OP_IPUT_WIDE_VOLATILE;
+            goto rewrite_inst_field;
+        case OP_IPUT_OBJECT:
+            quickOpc = OP_IPUT_OBJECT_QUICK;
+            if (forSmp)
+                volatileOpc = OP_IPUT_OBJECT_VOLATILE;
+            /* fall through */
+rewrite_inst_field:
+            if (essentialOnly)
+                quickOpc = OP_NOP;      /* if essential-only, no "-quick" sub */
+            if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
+                rewriteInstField(method, insns, quickOpc, volatileOpc);
+            break;
+
+        case OP_IGET_JUMBO:
+        case OP_IGET_BOOLEAN_JUMBO:
+        case OP_IGET_BYTE_JUMBO:
+        case OP_IGET_CHAR_JUMBO:
+        case OP_IGET_SHORT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_IGET_VOLATILE_JUMBO;
+            goto rewrite_jumbo_inst_field;
+        case OP_IGET_WIDE_JUMBO:
+            volatileOpc = OP_IGET_WIDE_VOLATILE_JUMBO;
+            goto rewrite_jumbo_inst_field;
+        case OP_IGET_OBJECT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_IGET_OBJECT_VOLATILE_JUMBO;
+            goto rewrite_jumbo_inst_field;
+        case OP_IPUT_JUMBO:
+        case OP_IPUT_BOOLEAN_JUMBO:
+        case OP_IPUT_BYTE_JUMBO:
+        case OP_IPUT_CHAR_JUMBO:
+        case OP_IPUT_SHORT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_IPUT_VOLATILE_JUMBO;
+            goto rewrite_jumbo_inst_field;
+        case OP_IPUT_WIDE_JUMBO:
+            volatileOpc = OP_IPUT_WIDE_VOLATILE_JUMBO;
+            goto rewrite_jumbo_inst_field;
+        case OP_IPUT_OBJECT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_IPUT_OBJECT_VOLATILE_JUMBO;
+            /* fall through */
+rewrite_jumbo_inst_field:
+            if (volatileOpc != OP_NOP)
+                rewriteJumboInstField(method, insns, volatileOpc);
+            break;
+
+        case OP_SGET:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_BYTE:
+        case OP_SGET_CHAR:
+        case OP_SGET_SHORT:
+            if (forSmp)
+                volatileOpc = OP_SGET_VOLATILE;
+            goto rewrite_static_field;
+        case OP_SGET_WIDE:
+            volatileOpc = OP_SGET_WIDE_VOLATILE;
+            goto rewrite_static_field;
+        case OP_SGET_OBJECT:
+            if (forSmp)
+                volatileOpc = OP_SGET_OBJECT_VOLATILE;
+            goto rewrite_static_field;
+        case OP_SPUT:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_SHORT:
+            if (forSmp)
+                volatileOpc = OP_SPUT_VOLATILE;
+            goto rewrite_static_field;
+        case OP_SPUT_WIDE:
+            volatileOpc = OP_SPUT_WIDE_VOLATILE;
+            goto rewrite_static_field;
+        case OP_SPUT_OBJECT:
+            if (forSmp)
+                volatileOpc = OP_SPUT_OBJECT_VOLATILE;
+            /* fall through */
+rewrite_static_field:
+            if (volatileOpc != OP_NOP)
+                rewriteStaticField(method, insns, volatileOpc);
+            break;
+
+        case OP_SGET_JUMBO:
+        case OP_SGET_BOOLEAN_JUMBO:
+        case OP_SGET_BYTE_JUMBO:
+        case OP_SGET_CHAR_JUMBO:
+        case OP_SGET_SHORT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_SGET_VOLATILE_JUMBO;
+            goto rewrite_jumbo_static_field;
+        case OP_SGET_WIDE_JUMBO:
+            volatileOpc = OP_SGET_WIDE_VOLATILE_JUMBO;
+            goto rewrite_jumbo_static_field;
+        case OP_SGET_OBJECT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_SGET_OBJECT_VOLATILE_JUMBO;
+            goto rewrite_jumbo_static_field;
+        case OP_SPUT_JUMBO:
+        case OP_SPUT_BOOLEAN_JUMBO:
+        case OP_SPUT_BYTE_JUMBO:
+        case OP_SPUT_CHAR_JUMBO:
+        case OP_SPUT_SHORT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_SPUT_VOLATILE_JUMBO;
+            goto rewrite_jumbo_static_field;
+        case OP_SPUT_WIDE_JUMBO:
+            volatileOpc = OP_SPUT_WIDE_VOLATILE_JUMBO;
+            goto rewrite_jumbo_static_field;
+        case OP_SPUT_OBJECT_JUMBO:
+            if (forSmp)
+                volatileOpc = OP_SPUT_OBJECT_VOLATILE_JUMBO;
+            /* fall through */
+rewrite_jumbo_static_field:
+            if (volatileOpc != OP_NOP)
+                rewriteJumboStaticField(method, insns, volatileOpc);
+            break;
+
+        case OP_INVOKE_DIRECT:
+        case OP_INVOKE_DIRECT_RANGE:
+            if (!rewriteInvokeObjectInit(method, insns)) {
+                /* may want to try execute-inline, below */
+                matched = false;
+            }
+            break;
+        case OP_INVOKE_DIRECT_JUMBO:
+            rewriteJumboInvokeObjectInit(method, insns);
+            break;
+        case OP_RETURN_VOID:
+            if (needRetBar)
+                rewriteReturnVoid(method, insns);
+            break;
+        default:
+            matched = false;
+            break;
+        }
+
+
+        /*
+         * non-essential substitutions:
+         *  invoke-{virtual,direct,static}[/range] --> execute-inline
+         *  invoke-{virtual,super}[/range] --> invoke-*-quick
+         */
+        if (!matched && !essentialOnly) {
+            switch (opc) {
+            case OP_INVOKE_VIRTUAL:
+                if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
+                    rewriteVirtualInvoke(method, insns,
+                        OP_INVOKE_VIRTUAL_QUICK);
+                }
+                break;
+            case OP_INVOKE_VIRTUAL_RANGE:
+                if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
+                    rewriteVirtualInvoke(method, insns,
+                        OP_INVOKE_VIRTUAL_QUICK_RANGE);
+                }
+                break;
+            case OP_INVOKE_SUPER:
+                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
+                break;
+            case OP_INVOKE_SUPER_RANGE:
+                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
+                break;
+            case OP_INVOKE_DIRECT:
+                rewriteExecuteInline(method, insns, METHOD_DIRECT);
+                break;
+            case OP_INVOKE_DIRECT_RANGE:
+                rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
+                break;
+            case OP_INVOKE_STATIC:
+                rewriteExecuteInline(method, insns, METHOD_STATIC);
+                break;
+            case OP_INVOKE_STATIC_RANGE:
+                rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
+                break;
+            default:
+                /* nothing to do for this instruction */
+                ;
+            }
+        }
+
+        assert(width > 0);
+        assert(width <= insnsSize);
+        assert(width == dexGetWidthFromInstruction(insns));
+
+        insns += width;
+        insnsSize -= width;
+    }
+
+    assert(insnsSize == 0);
+}
+
+/*
+ * Update a 16-bit code unit in "meth".  The way in which the DEX data was
+ * loaded determines how we go about the write.
+ *
+ * This will be operating on post-byte-swap DEX data, so values will
+ * be in host order.
+ */
+void dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
+{
+    DvmDex* pDvmDex = meth->clazz->pDvmDex;
+
+    if (!pDvmDex->isMappedReadOnly) {
+        /* in-memory DEX (dexopt or byte[]), alter the output directly */
+        *ptr = newVal;
+    } else {
+        /* memory-mapped file, toggle the page read/write status */
+        dvmDexChangeDex2(pDvmDex, ptr, newVal);
+    }
+}
+
+/*
+ * Update an instruction's opcode.
+ *
+ * If "opcode" is an 8-bit op, we just replace that portion.  If it's a
+ * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to
+ * bytecode form (e.g. 0x08ff).
+ */
+static inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
+{
+    if (opcode >= 256) {
+        /* opcode low byte becomes high byte, low byte becomes 0xff */
+        assert((ptr[0] & 0xff) == 0xff);
+        dvmUpdateCodeUnit(meth, ptr, (u2) (opcode << 8) | 0x00ff);
+    } else {
+        /* 8-bit op, just replace the low byte */
+        assert((ptr[0] & 0xff) != 0xff);
+        dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
+    }
+}
+
+/*
+ * If "referrer" and "resClass" don't come from the same DEX file, and
+ * the DEX we're working on is not destined for the bootstrap class path,
+ * tweak the class loader so package-access checks work correctly.
+ *
+ * Only do this if we're doing pre-verification or optimization.
+ */
+static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
+{
+    if (!gDvm.optimizing)
+        return;
+    assert(referrer->classLoader == NULL);
+    assert(resClass->classLoader == NULL);
+
+    if (!gDvm.optimizingBootstrapClass) {
+        /* class loader for an array class comes from element type */
+        if (dvmIsArrayClass(resClass))
+            resClass = resClass->elementClass;
+        if (referrer->pDvmDex != resClass->pDvmDex)
+            resClass->classLoader = (Object*) 0xdead3333;
+    }
+}
+
+/*
+ * Undo the effects of tweakLoader.
+ */
+static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
+{
+    if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
+        return;
+
+    if (dvmIsArrayClass(resClass))
+        resClass = resClass->elementClass;
+    resClass->classLoader = NULL;
+}
+
+
+/*
+ * Alternate version of dvmResolveClass for use with verification and
+ * optimization.  Performs access checks on every resolve, and refuses
+ * to acknowledge the existence of classes defined in more than one DEX
+ * file.
+ *
+ * Exceptions caused by failures are cleared before returning.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+    VerifyError* pFailure)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    ClassObject* resClass;
+
+    /*
+     * Check the table first.  If not there, do the lookup by name.
+     */
+    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
+    if (resClass == NULL) {
+        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
+        if (className[0] != '\0' && className[1] == '\0') {
+            /* primitive type */
+            resClass = dvmFindPrimitiveClass(className[0]);
+        } else {
+            resClass = dvmFindClassNoInit(className, referrer->classLoader);
+        }
+        if (resClass == NULL) {
+            /* not found, exception should be raised */
+            LOGV("DexOpt: class %d (%s) not found",
+                classIdx,
+                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
+            if (pFailure != NULL) {
+                /* dig through the wrappers to find the original failure */
+                Object* excep = dvmGetException(dvmThreadSelf());
+                while (true) {
+                    Object* cause = dvmGetExceptionCause(excep);
+                    if (cause == NULL)
+                        break;
+                    excep = cause;
+                }
+                if (strcmp(excep->clazz->descriptor,
+                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
+                {
+                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+                } else {
+                    *pFailure = VERIFY_ERROR_NO_CLASS;
+                }
+            }
+            dvmClearOptException(dvmThreadSelf());
+            return NULL;
+        }
+
+        /*
+         * Add it to the resolved table so we're faster on the next lookup.
+         */
+        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
+    }
+
+    /* multiple definitions? */
+    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
+        LOGI("DexOpt: not resolving ambiguous class '%s'",
+            resClass->descriptor);
+        if (pFailure != NULL)
+            *pFailure = VERIFY_ERROR_NO_CLASS;
+        return NULL;
+    }
+
+    /* access allowed? */
+    tweakLoader(referrer, resClass);
+    bool allowed = dvmCheckClassAccess(referrer, resClass);
+    untweakLoader(referrer, resClass);
+    if (!allowed) {
+        LOGW("DexOpt: resolve class illegal access: %s -> %s",
+            referrer->descriptor, resClass->descriptor);
+        if (pFailure != NULL)
+            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
+        return NULL;
+    }
+
+    return resClass;
+}
+
+/*
+ * Alternate version of dvmResolveInstField().
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+    VerifyError* pFailure)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    InstField* resField;
+
+    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
+    if (resField == NULL) {
+        const DexFieldId* pFieldId;
+        ClassObject* resClass;
+
+        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
+
+        /*
+         * Find the field's class.
+         */
+        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
+        if (resClass == NULL) {
+            //dvmClearOptException(dvmThreadSelf());
+            assert(!dvmCheckException(dvmThreadSelf()));
+            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
+            return NULL;
+        }
+
+        resField = (InstField*)dvmFindFieldHier(resClass,
+            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
+            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
+        if (resField == NULL) {
+            LOGD("DexOpt: couldn't find field %s.%s",
+                resClass->descriptor,
+                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_NO_FIELD;
+            return NULL;
+        }
+        if (dvmIsStaticField(resField)) {
+            LOGD("DexOpt: wanted instance, got static for field %s.%s",
+                resClass->descriptor,
+                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+            return NULL;
+        }
+
+        /*
+         * Add it to the resolved table so we're faster on the next lookup.
+         */
+        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
+    }
+
+    /* access allowed? */
+    tweakLoader(referrer, resField->clazz);
+    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
+    untweakLoader(referrer, resField->clazz);
+    if (!allowed) {
+        LOGI("DexOpt: access denied from %s to field %s.%s",
+            referrer->descriptor, resField->clazz->descriptor,
+            resField->name);
+        if (pFailure != NULL)
+            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
+        return NULL;
+    }
+
+    return resField;
+}
+
+/*
+ * Alternate version of dvmResolveStaticField().
+ *
+ * Does not force initialization of the resolved field's class.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+    VerifyError* pFailure)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    StaticField* resField;
+
+    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
+    if (resField == NULL) {
+        const DexFieldId* pFieldId;
+        ClassObject* resClass;
+
+        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
+
+        /*
+         * Find the field's class.
+         */
+        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
+        if (resClass == NULL) {
+            //dvmClearOptException(dvmThreadSelf());
+            assert(!dvmCheckException(dvmThreadSelf()));
+            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
+            return NULL;
+        }
+
+        const char* fieldName =
+            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
+
+        resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
+                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
+        if (resField == NULL) {
+            LOGD("DexOpt: couldn't find static field %s.%s",
+                resClass->descriptor, fieldName);
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_NO_FIELD;
+            return NULL;
+        }
+        if (!dvmIsStaticField(resField)) {
+            LOGD("DexOpt: wanted static, got instance for field %s.%s",
+                resClass->descriptor, fieldName);
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+            return NULL;
+        }
+
+        /*
+         * Add it to the resolved table so we're faster on the next lookup.
+         *
+         * We can only do this if we're in "dexopt", because the presence
+         * of a valid value in the resolution table implies that the class
+         * containing the static field has been initialized.
+         */
+        if (gDvm.optimizing)
+            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
+    }
+
+    /* access allowed? */
+    tweakLoader(referrer, resField->clazz);
+    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
+    untweakLoader(referrer, resField->clazz);
+    if (!allowed) {
+        LOGI("DexOpt: access denied from %s to field %s.%s",
+            referrer->descriptor, resField->clazz->descriptor,
+            resField->name);
+        if (pFailure != NULL)
+            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
+        return NULL;
+    }
+
+    return resField;
+}
+
+
+/*
+ * Rewrite an iget/iput instruction if appropriate.  These all have the form:
+ *   op vA, vB, field@CCCC
+ *
+ * Where vA holds the value, vB holds the object reference, and CCCC is
+ * the field reference constant pool offset.  For a non-volatile field,
+ * we want to replace the opcode with "quickOpc" and replace CCCC with
+ * the byte offset from the start of the object.  For a volatile field,
+ * we just want to replace the opcode with "volatileOpc".
+ *
+ * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
+ * field.  If "quickOpc" is OP_NOP, and this is a non-volatile field,
+ * we don't do anything.
+ *
+ * "method" is the referring method.
+ */
+static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
+    Opcode volatileOpc)
+{
+    ClassObject* clazz = method->clazz;
+    u2 fieldIdx = insns[1];
+    InstField* instField;
+
+    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
+    if (instField == NULL) {
+        LOGI("DexOpt: unable to optimize instance field ref "
+             "0x%04x at 0x%02x in %s.%s",
+            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
+            method->name);
+        return;
+    }
+
+    if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) {
+        updateOpcode(method, insns, volatileOpc);
+        LOGV("DexOpt: rewrote ifield access %s.%s --> volatile",
+            instField->clazz->descriptor, instField->name);
+    } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) {
+        updateOpcode(method, insns, quickOpc);
+        dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset);
+        LOGV("DexOpt: rewrote ifield access %s.%s --> %d",
+            instField->clazz->descriptor, instField->name,
+            instField->byteOffset);
+    } else {
+        LOGV("DexOpt: no rewrite of ifield access %s.%s",
+            instField->clazz->descriptor, instField->name);
+    }
+
+    return;
+}
+
+/*
+ * Rewrite a jumbo instance field access instruction if appropriate.  If
+ * the target field is volatile, we replace the opcode with "volatileOpc".
+ *
+ * "method" is the referring method.
+ */
+static void rewriteJumboInstField(Method* method, u2* insns, Opcode volatileOpc)
+{
+    ClassObject* clazz = method->clazz;
+    u4 fieldIdx = insns[1] | (u4) insns[2] << 16;
+    InstField* instField;
+
+    assert(volatileOpc != OP_NOP);
+
+    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
+    if (instField == NULL) {
+        LOGI("DexOpt: unable to optimize instance field ref "
+             "0x%04x at 0x%02x in %s.%s",
+            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
+            method->name);
+        return;
+    }
+
+    if (dvmIsVolatileField(instField)) {
+        updateOpcode(method, insns, volatileOpc);
+        LOGV("DexOpt: rewrote jumbo ifield access %s.%s --> volatile",
+            instField->clazz->descriptor, instField->name);
+    } else {
+        LOGV("DexOpt: no rewrite of jumbo ifield access %s.%s",
+            instField->clazz->descriptor, instField->name);
+    }
+}
+
+/*
+ * Rewrite a static [jumbo] field access instruction if appropriate.  If
+ * the target field is volatile, we replace the opcode with "volatileOpc".
+ *
+ * "method" is the referring method.
+ */
+static void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc,
+    u4 fieldIdx)
+{
+    ClassObject* clazz = method->clazz;
+    StaticField* staticField;
+
+    assert(volatileOpc != OP_NOP);
+
+    staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
+    if (staticField == NULL) {
+        LOGI("DexOpt: unable to optimize static field ref "
+             "0x%04x at 0x%02x in %s.%s",
+            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
+            method->name);
+        return;
+    }
+
+    if (dvmIsVolatileField(staticField)) {
+        updateOpcode(method, insns, volatileOpc);
+        LOGV("DexOpt: rewrote sfield access %s.%s --> volatile",
+            staticField->clazz->descriptor, staticField->name);
+    }
+}
+
+static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
+{
+    u2 fieldIdx = insns[1];
+    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
+}
+static void rewriteJumboStaticField(Method* method, u2* insns,
+    Opcode volatileOpc)
+{
+    u4 fieldIdx = insns[1] | (u4) insns[2] << 16;
+    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
+}
+
+
+/*
+ * Alternate version of dvmResolveMethod().
+ *
+ * Doesn't throw exceptions, and checks access on every lookup.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
+ */
+Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
+    MethodType methodType, VerifyError* pFailure)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    Method* resMethod;
+
+    assert(methodType == METHOD_DIRECT ||
+           methodType == METHOD_VIRTUAL ||
+           methodType == METHOD_STATIC);
+
+    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
+        referrer->descriptor);
+
+    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
+    if (resMethod == NULL) {
+        const DexMethodId* pMethodId;
+        ClassObject* resClass;
+
+        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
+
+        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
+        if (resClass == NULL) {
+            /*
+             * Can't find the class that the method is a part of, or don't
+             * have permission to access the class.
+             */
+            LOGV("DexOpt: can't find called method's class (?.%s)",
+                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");
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_GENERIC;
+            return NULL;
+        }
+
+        /*
+         * We need to chase up the class hierarchy to find methods defined
+         * in super-classes.  (We only want to check the current class
+         * if we're looking for a constructor.)
+         */
+        DexProto proto;
+        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
+
+        if (methodType == METHOD_DIRECT) {
+            resMethod = dvmFindDirectMethod(resClass,
+                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
+        } else {
+            /* METHOD_STATIC or METHOD_VIRTUAL */
+            resMethod = dvmFindMethodHier(resClass,
+                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
+        }
+
+        if (resMethod == NULL) {
+            LOGV("DexOpt: couldn't find method '%s'",
+                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_NO_METHOD;
+            return NULL;
+        }
+        if (methodType == METHOD_STATIC) {
+            if (!dvmIsStaticMethod(resMethod)) {
+                LOGD("DexOpt: wanted static, got instance for method %s.%s",
+                    resClass->descriptor, resMethod->name);
+                if (pFailure != NULL)
+                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+                return NULL;
+            }
+        } else if (methodType == METHOD_VIRTUAL) {
+            if (dvmIsStaticMethod(resMethod)) {
+                LOGD("DexOpt: wanted instance, got static for method %s.%s",
+                    resClass->descriptor, resMethod->name);
+                if (pFailure != NULL)
+                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
+                return NULL;
+            }
+        }
+
+        /* see if this is a pure-abstract method */
+        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
+            LOGW("DexOpt: pure-abstract method '%s' in %s",
+                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
+                resClass->descriptor);
+            if (pFailure != NULL)
+                *pFailure = VERIFY_ERROR_GENERIC;
+            return NULL;
+        }
+
+        /*
+         * Add it to the resolved table so we're faster on the next lookup.
+         *
+         * We can only do this for static methods if we're not in "dexopt",
+         * because the presence of a valid value in the resolution table
+         * implies that the class containing the static field has been
+         * initialized.
+         */
+        if (methodType != METHOD_STATIC || gDvm.optimizing)
+            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+    }
+
+    LOGVV("--- found method %d (%s.%s)",
+        methodIdx, resMethod->clazz->descriptor, resMethod->name);
+
+    /* access allowed? */
+    tweakLoader(referrer, resMethod->clazz);
+    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
+    untweakLoader(referrer, resMethod->clazz);
+    if (!allowed) {
+        IF_LOGI() {
+            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+            LOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
+                resMethod->clazz->descriptor, resMethod->name, desc,
+                referrer->descriptor);
+            free(desc);
+        }
+        if (pFailure != NULL)
+            *pFailure = VERIFY_ERROR_ACCESS_METHOD;
+        return NULL;
+    }
+
+    return resMethod;
+}
+
+/*
+ * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
+ * invoke-super/range if appropriate.  These all have the form:
+ *   op vAA, meth@BBBB, reg stuff @CCCC
+ *
+ * We want to replace the method constant pool index BBBB with the
+ * vtable index.
+ */
+static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
+{
+    ClassObject* clazz = method->clazz;
+    Method* baseMethod;
+    u2 methodIdx = insns[1];
+
+    baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
+    if (baseMethod == NULL) {
+        LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s",
+            methodIdx,
+            (int) (insns - method->insns), clazz->descriptor,
+            method->name);
+        return;
+    }
+
+    assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
+           (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
+           (insns[0] & 0xff) == OP_INVOKE_SUPER ||
+           (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
+
+    /*
+     * Note: Method->methodIndex is a u2 and is range checked during the
+     * initial load.
+     */
+    updateOpcode(method, insns, newOpc);
+    dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex);
+
+    //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s",
+    //    method->clazz->descriptor, method->name,
+    //    baseMethod->clazz->descriptor, baseMethod->name);
+
+    return;
+}
+
+/*
+ * Rewrite invoke-direct[/range] if the target is Object.<init>.
+ *
+ * This is useful as an optimization, because otherwise every object
+ * instantiation will cause us to call a method that does nothing.
+ * It also allows us to inexpensively mark objects as finalizable at the
+ * correct time.
+ *
+ * TODO: verifier should ensure Object.<init> contains only return-void,
+ * and issue a warning if not.
+ */
+static bool rewriteInvokeObjectInit(Method* method, u2* insns)
+{
+    ClassObject* clazz = method->clazz;
+    Method* calledMethod;
+    u2 methodIdx = insns[1];
+
+    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
+    if (calledMethod == NULL) {
+        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
+            methodIdx, (int) (insns - method->insns),
+            clazz->descriptor, method->name);
+        return false;
+    }
+
+    if (calledMethod->clazz == gDvm.classJavaLangObject &&
+        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
+    {
+        /*
+         * Replace the instruction.  If the debugger is attached, the
+         * interpreter will forward execution to the invoke-direct/range
+         * handler.  If this was an invoke-direct/range instruction we can
+         * just replace the opcode, but if it was an invoke-direct we
+         * have to set the argument count (high 8 bits of first code unit)
+         * to 1.
+         */
+        u1 origOp = insns[0] & 0xff;
+        if (origOp == OP_INVOKE_DIRECT) {
+            dvmUpdateCodeUnit(method, insns,
+                OP_INVOKE_OBJECT_INIT_RANGE | 0x100);
+        } else {
+            assert(origOp == OP_INVOKE_DIRECT_RANGE);
+            assert((insns[0] >> 8) == 1);
+            updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE);
+        }
+
+        LOGVV("DexOpt: replaced Object.<init> in %s.%s",
+            method->clazz->descriptor, method->name);
+    }
+
+    return true;
+}
+
+/*
+ * Rewrite invoke-direct/jumbo if the target is Object.<init>.
+ */
+static bool rewriteJumboInvokeObjectInit(Method* method, u2* insns)
+{
+    ClassObject* clazz = method->clazz;
+    Method* calledMethod;
+    u4 methodIdx = insns[1] | (u4) insns[2] << 16;
+
+    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",
+            methodIdx, (int) (insns - method->insns),
+            clazz->descriptor, method->name);
+        return false;
+    }
+
+    if (calledMethod->clazz == gDvm.classJavaLangObject &&
+        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
+    {
+        assert(insns[0] == ((u2) (OP_INVOKE_DIRECT_JUMBO << 8) | 0xff));
+        updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_JUMBO);
+
+        LOGVV("DexOpt: replaced jumbo Object.<init> in %s.%s",
+            method->clazz->descriptor, method->name);
+    }
+
+    return true;
+}
+
+/*
+ * Resolve an interface method reference.
+ *
+ * No method access check here -- interface methods are always public.
+ *
+ * Returns NULL if the method was not found.  Does not throw an exception.
+ */
+Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    Method* resMethod;
+
+    LOGVV("--- resolving interface method %d (referrer=%s)",
+        methodIdx, referrer->descriptor);
+
+    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
+    if (resMethod == NULL) {
+        const DexMethodId* pMethodId;
+        ClassObject* resClass;
+
+        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
+
+        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
+        if (resClass == NULL) {
+            /* can't find the class that the method is a part of */
+            dvmClearOptException(dvmThreadSelf());
+            return NULL;
+        }
+        if (!dvmIsInterfaceClass(resClass)) {
+            /* whoops */
+            LOGI("Interface method not part of interface class");
+            return NULL;
+        }
+
+        const char* methodName =
+            dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
+        DexProto proto;
+        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
+
+        LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
+            methodName, methodSig, resClass->descriptor);
+        resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
+        if (resMethod == NULL) {
+            return NULL;
+        }
+
+        /* we're expecting this to be abstract */
+        if (!dvmIsAbstractMethod(resMethod)) {
+            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
+            LOGW("Found non-abstract interface method %s.%s %s",
+                resMethod->clazz->descriptor, resMethod->name, desc);
+            free(desc);
+            return NULL;
+        }
+
+        /*
+         * Add it to the resolved table so we're faster on the next lookup.
+         */
+        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+    }
+
+    LOGVV("--- found interface method %d (%s.%s)",
+        methodIdx, resMethod->clazz->descriptor, resMethod->name);
+
+    /* interface methods are always public; no need to check access */
+
+    return resMethod;
+}
+
+/*
+ * Replace invoke-virtual, invoke-direct, or invoke-static with an
+ * execute-inline operation if appropriate.
+ *
+ * Returns "true" if we replace it.
+ */
+static bool rewriteExecuteInline(Method* method, u2* insns,
+    MethodType methodType)
+{
+    const InlineSub* inlineSubs = gDvm.inlineSubs;
+    ClassObject* clazz = method->clazz;
+    Method* calledMethod;
+    u2 methodIdx = insns[1];
+
+    //return false;
+
+    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
+    if (calledMethod == NULL) {
+        LOGV("+++ DexOpt inline: can't find %d", methodIdx);
+        return false;
+    }
+
+    while (inlineSubs->method != NULL) {
+        /*
+        if (extra) {
+            LOGI("comparing %p vs %p %s.%s %s",
+                inlineSubs->method, calledMethod,
+                inlineSubs->method->clazz->descriptor,
+                inlineSubs->method->name,
+                inlineSubs->method->signature);
+        }
+        */
+        if (inlineSubs->method == calledMethod) {
+            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
+                   (insns[0] & 0xff) == OP_INVOKE_STATIC ||
+                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
+            updateOpcode(method, insns, OP_EXECUTE_INLINE);
+            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
+
+            //LOGI("DexOpt: execute-inline %s.%s --> %s.%s",
+            //    method->clazz->descriptor, method->name,
+            //    calledMethod->clazz->descriptor, calledMethod->name);
+            return true;
+        }
+
+        inlineSubs++;
+    }
+
+    return false;
+}
+
+/*
+ * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range
+ * with an execute-inline operation if appropriate.
+ *
+ * Returns "true" if we replace it.
+ */
+static bool rewriteExecuteInlineRange(Method* method, u2* insns,
+    MethodType methodType)
+{
+    const InlineSub* inlineSubs = gDvm.inlineSubs;
+    ClassObject* clazz = method->clazz;
+    Method* calledMethod;
+    u2 methodIdx = insns[1];
+
+    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
+    if (calledMethod == NULL) {
+        LOGV("+++ DexOpt inline/range: can't find %d", methodIdx);
+        return false;
+    }
+
+    while (inlineSubs->method != NULL) {
+        if (inlineSubs->method == calledMethod) {
+            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
+                   (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
+                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
+            updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
+            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
+
+            //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s",
+            //    method->clazz->descriptor, method->name,
+            //    calledMethod->clazz->descriptor, calledMethod->name);
+            return true;
+        }
+
+        inlineSubs++;
+    }
+
+    return false;
+}
+
+/*
+ * Returns "true" if the return-void instructions in this method should
+ * be converted to return-void-barrier.
+ *
+ * This is needed to satisfy a Java Memory Model requirement regarding
+ * the construction of objects with final fields.  (This does not apply
+ * to <clinit> or static fields, since appropriate barriers are guaranteed
+ * by the class initialization process.)
+ */
+static bool needsReturnBarrier(Method* method)
+{
+    if (!gDvm.dexOptForSmp)
+        return false;
+    if (strcmp(method->name, "<init>") != 0)
+        return false;
+
+    /*
+     * Check to see if the class is finalizable.  The loader sets a flag
+     * if the class or one of its superclasses overrides finalize().
+     */
+    const ClassObject* clazz = method->clazz;
+    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
+        return true;
+
+    /*
+     * Check to see if the class has any final fields.  If not, we don't
+     * need to generate a barrier instruction.
+     *
+     * In theory, we only need to do this if the method actually modifies
+     * a final field.  In practice, non-constructor methods are allowed
+     * to modify final fields, and there are 3rd-party tools that rely on
+     * this behavior.  (The compiler does not allow it, but the VM does.)
+     *
+     * If we alter the verifier to restrict final-field updates to
+     * constructors, we can tighten this up as well.
+     */
+    int idx = clazz->ifieldCount;
+    while (--idx >= 0) {
+        if (dvmIsFinalField(&clazz->ifields[idx]))
+            return true;
+    }
+
+    return false;
+}
+
+/*
+ * Convert a return-void to a return-void-barrier.
+ */
+static void rewriteReturnVoid(Method* method, u2* insns)
+{
+    assert((insns[0] & 0xff) == OP_RETURN_VOID);
+    updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);
+}
diff --git a/vm/analysis/Optimize.h b/vm/analysis/Optimize.h
new file mode 100644
index 0000000..e1825d0
--- /dev/null
+++ b/vm/analysis/Optimize.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Bytecode optimization declarations.
+ */
+#ifndef DALVIK_OPTIMIZE_H_
+#define DALVIK_OPTIMIZE_H_
+
+/*
+ * Entry point from DEX preparation.
+ */
+void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly);
+
+/*
+ * Update a 16-bit code unit.
+ */
+void dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal);
+
+/*
+ * Abbreviated resolution functions, for use by optimization and verification
+ * code.
+ */
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+    VerifyError* pFailure);
+Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
+    MethodType methodType, VerifyError* pFailure);
+Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx);
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+    VerifyError* pFailure);
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+    VerifyError* pFailure);
+
+#endif  // DALVIK_OPTIMIZE_H_
diff --git a/vm/analysis/RegisterMap.cpp b/vm/analysis/RegisterMap.cpp
new file mode 100644
index 0000000..298887d
--- /dev/null
+++ b/vm/analysis/RegisterMap.cpp
@@ -0,0 +1,1833 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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
+ * precision in the garbage collector when scanning references in the
+ * interpreter thread stacks.
+ */
+#include "Dalvik.h"
+#include "UniquePtr.h"
+#include "analysis/CodeVerify.h"
+#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     false
+
+/* verbose logging */
+#define REGISTER_MAP_VERBOSE    false
+
+//#define REGISTER_MAP_STATS
+
+// fwd
+static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data);
+static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap);
+static int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2);
+
+#ifdef REGISTER_MAP_STATS
+static void computeMapStats(RegisterMap* pMap, const Method* method);
+#endif
+static RegisterMap* compressMapDifferential(const RegisterMap* pMap,\
+    const Method* meth);
+static RegisterMap* uncompressMapDifferential(const RegisterMap* pMap);
+
+#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
+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;
+};
+#endif
+
+/*
+ * Prepare some things.
+ */
+bool dvmRegisterMapStartup()
+{
+#ifdef REGISTER_MAP_STATS
+    MapStats* pStats = calloc(1, sizeof(MapStats));
+    gDvm.registerMapStats = pStats;
+#endif
+    return true;
+}
+
+/*
+ * Clean up.
+ */
+void dvmRegisterMapShutdown()
+{
+#ifdef REGISTER_MAP_STATS
+    free(gDvm.registerMapStats);
+#endif
+}
+
+/*
+ * Write stats to log file.
+ */
+void dvmRegisterMapDumpStats()
+{
+#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):",
+        pStats->gcGapCount, pStats->totalGcPointCount);
+    assert(pStats->gcPointGap[0] == 0);
+    for (i = 1; i <= end; i++) {
+        LOGI(" %2d %d", i, pStats->gcPointGap[i]);
+    }
+
+
+    for (end = kMaxDiffBits-1; end >= 0; end--) {
+        if (pStats->numDiffBits[end] != 0)
+            break;
+    }
+
+    LOGI("Register Map bit difference stats:");
+    for (i = 0; i <= end; i++) {
+        LOGI(" %2d %d", i, pStats->numDiffBits[i]);
+    }
+
+
+    LOGI("Register Map update position stats (lt16=%d ge16=%d):",
+        pStats->updateLT16, pStats->updateGE16);
+    for (i = 0; i < kNumUpdatePosns; i++) {
+        LOGI(" %2d %d", 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",
+            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 < (int) 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",
+            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)",
+        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 < (int) vdata->insnsSize; i++) {
+        if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
+            assert(vdata->registerLines[i].regTypes != NULL);
+            if (format == kRegMapFormatCompact8) {
+                *mapData++ = i;
+            } else /*kRegMapFormatCompact16*/ {
+                *mapData++ = i & 0xff;
+                *mapData++ = i >> 8;
+            }
+            outputTypeVector(vdata->registerLines[i].regTypes,
+                vdata->insnRegCount, mapData);
+            mapData += regWidth;
+        }
+    }
+
+    LOGV("mapData=%p pMap=%p bufSize=%d", mapData, pMap, bufSize);
+    assert(mapData - (const u1*) pMap == bufSize);
+
+    if (REGISTER_MAP_VERIFY && !verifyMap(vdata, pMap))
+        goto bail;
+#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",
+                    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",
+                        vdata->method->clazz->descriptor,
+                        vdata->method->name);
+                    free(pCompMap);
+                    /* bad - compression is broken */
+                    dvmAbort();
+                }
+
+                /* verify succeeded */
+                delete pUncompMap;
+            }
+        }
+
+        if (REGISTER_MAP_VERBOSE) {
+            LOGD("Good compress on %s.%s",
+                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)",
+                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)", 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", 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";
+        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", 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",
+            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 RegType* regs = vdata->registerLines[addr].regTypes;
+        if (regs == NULL) {
+            LOGE("GLITCH: addr %d has no data", 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)",
+                    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", 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",
+                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", 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)",
+                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", clazz->descriptor,
+                clazz->directMethodCount, clazz->virtualMethodCount,
+                (ptr - basePtr) - offsetTable[idx]);
+        } else {
+            LOGV("%4d NOT mapadding '%s'", idx, classDescriptor);
+            assert(offsetTable[idx] == 0);
+        }
+    }
+
+    if (ptr - basePtr >= (int)length) {
+        /* a bit late */
+        LOGE("Buffer overrun");
+        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", 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)", classIdx, pClassPool->numClasses);
+        dvmAbort();
+    }
+
+    u4 classOffset = pClassPool->classDataOffset[classIdx];
+    if (classOffset == 0) {
+        LOGV("+++ no map for classIdx=%d", 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 = (const RegisterMap*) *pPtr;
+
+    *pPtr = /*align32*/(((u1*) pMap) + computeRegisterMapSize(pMap));
+    LOGVV("getNext: %p -> %p (f=%#x w=%d e=%d)",
+        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", 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 = NULL;
+    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;
+        }
+        assert(data == pMap->data + lineWidth * numEntries);
+    } 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;
+            }
+        }
+    }
+
+    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)", size1, size2);
+        return -1;
+    }
+
+    if (memcmp(pMap1, pMap2, size1) != 0) {
+        LOGI("compareMaps: content mismatch");
+        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 && dvmTryLockMutex(&gDvm.gcHeapLock) == 0) {
+            LOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time");
+            dvmAbort();
+        }
+    }
+
+    RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
+    switch (format) {
+    case kRegMapFormatCompact8:
+    case kRegMapFormatCompact16:
+        if (REGISTER_MAP_VERBOSE) {
+            if (dvmRegisterMapGetOnHeap(curMap)) {
+                LOGD("RegMap: already expanded: %s.%s",
+                    method->clazz->descriptor, method->name);
+            } else {
+                LOGD("RegMap: stored w/o compression: %s.%s",
+                    method->clazz->descriptor, method->name);
+            }
+        }
+        return curMap;
+    case kRegMapFormatDifferential:
+        newMap = uncompressMapDifferential(curMap);
+        break;
+    default:
+        LOGE("Unknown format %d in dvmGetExpandedRegisterMap", format);
+        dvmAbort();
+        newMap = NULL;      // make gcc happy
+    }
+
+    if (newMap == NULL) {
+        LOGE("Map failed to uncompress (fmt=%d) %s.%s",
+            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",
+            pStats->numExpandedMaps, pStats->totalExpandedMapSize);
+    }
+#endif
+
+    IF_LOGV() {
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGV("Expanding map -> %s.%s:%s",
+            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.
+ */
+#ifdef REGISTER_MAP_STATS
+static void computeMapStats(RegisterMap* pMap, const Method* method)
+{
+    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)",
+                    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)",
+                        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",
+                                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",
+                                bitNum, method->registersSize, div, idx);
+                            assert(false);
+                        }
+                        pStats->updatePosn[idx]++;
+                    }
+                }
+            }
+
+            if (numDiff > kMaxDiffBits) {
+                if (REGISTER_MAP_VERBOSE) {
+                    LOGI("WOW: numDiff is %d, max %d", 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* 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", format);
+        return NULL;
+    }
+
+    regWidth = dvmRegisterMapGetRegWidth(pMap);
+    numEntries = dvmRegisterMapGetNumEntries(pMap);
+
+    if (debug) {
+        LOGI("COMPRESS: %s.%s aw=%d rw=%d ne=%d",
+            meth->clazz->descriptor, meth->name,
+            addrWidth, regWidth, numEntries);
+        dumpRegisterMap(pMap, -1);
+    }
+
+    if (numEntries <= 1) {
+        LOGV("Can't compress map with 0 or 1 entries");
+        return NULL;
+    }
+
+    /*
+     * 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.
+     */
+    UniquePtr<u1[]> tmpBuf(new u1[origSize + (1 + 3 + regWidth)]);
+    if (tmpBuf.get() == NULL)
+        return NULL;
+
+    tmpPtr = tmpBuf.get();
+
+    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");
+        return NULL;
+    }
+
+    /*
+     * 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.
+     */
+    for (int 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)", 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", addrDiff, key);
+        } else {
+            /* large difference, output escape code */
+            key = 0x07;                 /* escape code for AAA */
+            if (debug)
+                LOGI(" : large %d, key=0x%02x", 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)",
+                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");
+        } 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");
+        } 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");
+        } else {
+            /* set B to 1 and CCCC to 0x0f so we store the entire vector */
+            key |= 0x08 | 0xf0;
+            if (debug) LOGI(" : encode original");
+        }
+
+        /*
+         * 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.get() >= origSize) {
+            if (debug) {
+                LOGD("Compressed size >= original (%d vs %d): %s.%s",
+                    tmpPtr - tmpBuf.get(), origSize,
+                    meth->clazz->descriptor, meth->name);
+            }
+            return NULL;
+        }
+    }
+
+    /*
+     * 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.get();
+    int newMapSize;
+
+    newMapSize = kHeaderSize + unsignedLeb128Size(newDataSize) + newDataSize;
+    if (newMapSize >= origSize) {
+        if (debug) {
+            LOGD("Final comp size >= original (%d vs %d): %s.%s",
+                newMapSize, origSize, meth->clazz->descriptor, meth->name);
+        }
+        return NULL;
+    }
+
+    pNewMap = (RegisterMap*) malloc(newMapSize);
+    if (pNewMap == NULL)
+        return NULL;
+    dvmRegisterMapSetFormat(pNewMap, kRegMapFormatDifferential);
+    dvmRegisterMapSetOnHeap(pNewMap, true);
+    dvmRegisterMapSetRegWidth(pNewMap, regWidth);
+    dvmRegisterMapSetNumEntries(pNewMap, numEntries);
+
+    tmpPtr = pNewMap->data;
+    tmpPtr = writeUnsignedLeb128(tmpPtr, newDataSize);
+    memcpy(tmpPtr, tmpBuf.get(), newDataSize);
+
+    if (REGISTER_MAP_VERBOSE) {
+        LOGD("Compression successful (%d -> %d) from aw=%d rw=%d ne=%d",
+            computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap),
+            addrWidth, regWidth, numEntries);
+    }
+
+    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)
+{
+    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)", format);
+        return NULL;
+    }
+
+    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",
+            newAddrWidth, regWidth, numEntries);
+    }
+    newMapSize = kHeaderSize + (newAddrWidth + regWidth) * numEntries;
+    RegisterMap* pNewMap = (RegisterMap*) malloc(newMapSize);
+
+    if (pNewMap == NULL)
+      return NULL;
+
+    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",
+            dstPtr - (u1*) pNewMap, newMapSize);
+        free(pNewMap);
+        return NULL;
+    }
+
+    if (srcPtr - srcStart != expectedSrcLen) {
+        LOGE("ERROR: consumed %d bytes, expected %d",
+            srcPtr - srcStart, expectedSrcLen);
+        free(pNewMap);
+        return NULL;
+    }
+
+    if (REGISTER_MAP_VERBOSE) {
+        LOGD("Expansion successful (%d -> %d)",
+            computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap));
+    }
+
+    return pNewMap;
+}
diff --git a/vm/analysis/RegisterMap.h b/vm/analysis/RegisterMap.h
new file mode 100644
index 0000000..2046899
--- /dev/null
+++ b/vm/analysis/RegisterMap.h
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+/*
+ * Declaration of register map data structure and related functions.
+ *
+ * These structures should be treated as opaque through most of the VM.
+ */
+#ifndef DALVIK_REGISTERMAP_H_
+#define DALVIK_REGISTERMAP_H_
+
+#include "analysis/VerifySubs.h"
+#include "analysis/CodeVerify.h"
+
+/*
+ * Format enumeration for RegisterMap data area.
+ */
+enum RegisterMapFormat {
+    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 */
+};
+
+/*
+ * 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; MUST be first entry */
+    u1      regWidth;       /* bytes per register line, 1+ */
+    u1      numEntries[2];  /* number of entries */
+
+    /* 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 (RegisterMapFormat)(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.
+ */
+struct RegisterMapMethodPool {
+    u2      methodCount;            /* chiefly used as a sanity check */
+
+    /* stream of per-method data starts here */
+    u4      methodData[1];
+};
+
+/*
+ * 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.
+ */
+struct RegisterMapClassPool {
+    u4      numClasses;
+
+    /* offset table starts here, 32-bit aligned; offset==0 means no data */
+    u4      classDataOffset[1];
+};
+
+/*
+ * 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.
+ */
+struct RegisterMapBuilder {
+    /* public */
+    void*       data;
+    size_t      size;
+
+    /* private */
+    MemMapping  memMap;
+};
+
+/*
+ * 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 method that has just been verified
+ * (i.e. we're doing this as part of verification).
+ *
+ * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
+ */
+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_H_
diff --git a/vm/analysis/VerifySubs.cpp b/vm/analysis/VerifySubs.cpp
new file mode 100644
index 0000000..2651c68
--- /dev/null
+++ b/vm/analysis/VerifySubs.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik verification subroutines.
+ */
+#include "Dalvik.h"
+#include "analysis/CodeVerify.h"
+#include "libdex/InstrUtils.h"
+
+
+/*
+ * This is used when debugging to apply a magnifying glass to the
+ * verification of a particular method.
+ */
+bool dvmWantVerboseVerification(const Method* meth)
+{
+    return false;       /* COMMENT OUT to enable verbose debugging */
+
+    const char* cd = "Lcom/android/server/am/ActivityManagerService;";
+    const char* mn = "trimApplications";
+    const char* sg = "()V";
+    return (strcmp(meth->clazz->descriptor, cd) == 0 &&
+            dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0);
+}
+
+/*
+ * Output a code verifier warning message.  For the pre-verifier it's not
+ * a big deal if something fails (and it may even be expected), but if
+ * we're doing just-in-time verification it's significant.
+ */
+void dvmLogVerifyFailure(const Method* meth, const char* format, ...)
+{
+    va_list ap;
+    int logLevel;
+
+    if (gDvm.optimizing) {
+        return;
+        //logLevel = ANDROID_LOG_DEBUG;
+    } else {
+        logLevel = ANDROID_LOG_WARN;
+    }
+
+    va_start(ap, format);
+    LOG_PRI_VA(logLevel, LOG_TAG, format, ap);
+    if (meth != NULL) {
+        char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+        LOG_PRI(logLevel, LOG_TAG, "VFY:  rejected %s.%s %s",
+            meth->clazz->descriptor, meth->name, desc);
+        free(desc);
+    }
+}
+
+/*
+ * Show a relatively human-readable message describing the failure to
+ * resolve a class.
+ *
+ * TODO: this is somewhat misleading when resolution fails because of
+ * illegal access rather than nonexistent class.
+ */
+void dvmLogUnableToResolveClass(const char* missingClassDescr,
+    const Method* meth)
+{
+    if (gDvm.optimizing) {
+        return;
+    }
+
+    std::string dotMissingClass = dvmHumanReadableDescriptor(missingClassDescr);
+    std::string dotFromClass = dvmHumanReadableDescriptor(meth->clazz->descriptor);
+    LOGE("Could not find class '%s', referenced from method %s.%s",
+            dotMissingClass.c_str(), dotFromClass.c_str(), meth->name);
+}
+
+/*
+ * Extract the relative offset from a branch instruction.
+ *
+ * Returns "false" on failure (e.g. this isn't a branch instruction).
+ */
+bool dvmGetBranchOffset(const Method* meth, const InsnFlags* insnFlags,
+    int curOffset, s4* pOffset, bool* pConditional)
+{
+    const u2* insns = meth->insns + curOffset;
+
+    switch (*insns & 0xff) {
+    case OP_GOTO:
+        *pOffset = ((s2) *insns) >> 8;
+        *pConditional = false;
+        break;
+    case OP_GOTO_32:
+        *pOffset = insns[1] | (((u4) insns[2]) << 16);
+        *pConditional = false;
+        break;
+    case OP_GOTO_16:
+        *pOffset = (s2) insns[1];
+        *pConditional = false;
+        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:
+    case OP_IF_EQZ:
+    case OP_IF_NEZ:
+    case OP_IF_LTZ:
+    case OP_IF_GEZ:
+    case OP_IF_GTZ:
+    case OP_IF_LEZ:
+        *pOffset = (s2) insns[1];
+        *pConditional = true;
+        break;
+    default:
+        return false;
+        break;
+    }
+
+    return true;
+}
diff --git a/vm/analysis/VerifySubs.h b/vm/analysis/VerifySubs.h
new file mode 100644
index 0000000..330be57
--- /dev/null
+++ b/vm/analysis/VerifySubs.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik bytecode verification subroutines.
+ */
+#ifndef DALVIK_VERIFYSUBS_H_
+#define DALVIK_VERIFYSUBS_H_
+
+/*
+ * InsnFlags is a 32-bit integer with the following layout:
+ *   0-15  instruction length (or 0 if this address doesn't hold an opcode)
+ *  16-31  single bit flags:
+ *    InTry: in "try" block; exceptions thrown here may be caught locally
+ *    BranchTarget: other instructions can branch to this instruction
+ *    GcPoint: this instruction is a GC safe point
+ *    Visited: verifier has examined this instruction at least once
+ *    Changed: set/cleared as bytecode verifier runs
+ */
+typedef u4 InsnFlags;
+
+#define kInsnFlagWidthMask      0x0000ffff
+#define kInsnFlagInTry          (1 << 16)
+#define kInsnFlagBranchTarget   (1 << 17)
+#define kInsnFlagGcPoint        (1 << 18)
+#define kInsnFlagVisited        (1 << 30)
+#define kInsnFlagChanged        (1 << 31)
+
+/* add opcode widths to InsnFlags */
+bool dvmComputeCodeWidths(const Method* meth, InsnFlags* insnFlags,
+    int* pNewInstanceCount);
+
+/* set the "in try" flag for sections of code wrapped with a "try" block */
+bool dvmSetTryFlags(const Method* meth, InsnFlags* insnFlags);
+
+/* verification failure reporting */
+#define LOG_VFY(...)                dvmLogVerifyFailure(NULL, __VA_ARGS__)
+#define LOG_VFY_METH(_meth, ...)    dvmLogVerifyFailure(_meth, __VA_ARGS__)
+
+/* log verification failure with optional method info */
+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,
+    const Method* meth);
+
+/* extract the relative branch offset from a branch instruction */
+bool dvmGetBranchOffset(const Method* meth, const InsnFlags* insnFlags,
+    int curOffset, s4* pOffset, bool* pConditional);
+
+/* return a RegType enumeration value that "value" just fits into */
+char dvmDetermineCat1Const(s4 value);
+
+/* debugging */
+bool dvmWantVerboseVerification(const Method* meth);
+
+#endif  // DALVIK_VERIFYSUBS_H_
diff --git a/vm/analysis/VfyBasicBlock.cpp b/vm/analysis/VfyBasicBlock.cpp
new file mode 100644
index 0000000..8976353
--- /dev/null
+++ b/vm/analysis/VfyBasicBlock.cpp
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Verifier basic block functions.
+ */
+#include "Dalvik.h"
+#include "analysis/VfyBasicBlock.h"
+#include "analysis/CodeVerify.h"
+#include "analysis/VerifySubs.h"
+#include "libdex/DexCatch.h"
+#include "libdex/InstrUtils.h"
+
+
+/*
+ * Extract the list of catch handlers from "pTry" into "addrBuf".
+ *
+ * Returns the size of the catch handler list.  If the return value
+ * exceeds "addrBufSize", the items at the end of the list will not be
+ * represented in the output array, and this function should be called
+ * again with a larger buffer.
+ */
+static u4 extractCatchHandlers(const DexCode* pCode, const DexTry* pTry,
+    u4* addrBuf, size_t addrBufSize)
+{
+    DexCatchIterator iterator;
+    unsigned int idx = 0;
+
+    dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
+    while (true) {
+        DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+        if (handler == NULL)
+            break;
+
+        if (idx < addrBufSize) {
+            addrBuf[idx] = handler->address;
+        }
+        idx++;
+    }
+
+    return idx;
+}
+
+/*
+ * Returns "true" if the instruction represents a data chunk, such as a
+ * switch statement block.
+ */
+static bool isDataChunk(u2 insn)
+{
+    return (insn == kPackedSwitchSignature ||
+            insn == kSparseSwitchSignature ||
+            insn == kArrayDataSignature);
+}
+
+/*
+ * Alloc a basic block in the specified slot.  The storage will be
+ * initialized.
+ */
+static VfyBasicBlock* allocVfyBasicBlock(VerifierData* vdata, u4 idx)
+{
+    VfyBasicBlock* newBlock = (VfyBasicBlock*) calloc(1, sizeof(VfyBasicBlock));
+    if (newBlock == NULL)
+        return NULL;
+
+    /*
+     * TODO: there is no good default size here -- the problem is that most
+     * addresses will only have one predecessor, but a fair number will
+     * have 10+, and a few will have 100+ (e.g. the synthetic "finally"
+     * in a large synchronized method).  We probably want to use a small
+     * base allocation (perhaps two) and then have the first overflow
+     * allocation jump dramatically (to 32 or thereabouts).
+     */
+    newBlock->predecessors = dvmPointerSetAlloc(32);
+    if (newBlock->predecessors == NULL) {
+        free(newBlock);
+        return NULL;
+    }
+
+    newBlock->firstAddr = (u4) -1;      // DEBUG
+
+    newBlock->liveRegs = dvmAllocBitVector(vdata->insnRegCount, false);
+    if (newBlock->liveRegs == NULL) {
+        dvmPointerSetFree(newBlock->predecessors);
+        free(newBlock);
+        return NULL;
+    }
+
+    return newBlock;
+}
+
+/*
+ * Add "curBlock" to the predecessor list in "targetIdx".
+ */
+static bool addToPredecessor(VerifierData* vdata, VfyBasicBlock* curBlock,
+    u4 targetIdx)
+{
+    assert(targetIdx < vdata->insnsSize);
+
+    /*
+     * Allocate the target basic block if necessary.  This will happen
+     * on e.g. forward branches.
+     *
+     * We can't fill in all the fields, but that will happen automatically
+     * when we get to that part of the code.
+     */
+    VfyBasicBlock* targetBlock = vdata->basicBlocks[targetIdx];
+    if (targetBlock == NULL) {
+        targetBlock = allocVfyBasicBlock(vdata, targetIdx);
+        if (targetBlock == NULL)
+            return false;
+        vdata->basicBlocks[targetIdx] = targetBlock;
+    }
+
+    PointerSet* preds = targetBlock->predecessors;
+    bool added = dvmPointerSetAddEntry(preds, curBlock);
+    if (!added) {
+        /*
+         * This happens sometimes for packed-switch instructions, where
+         * the same target address appears more than once.  Also, a
+         * (pointless) conditional branch to the next instruction will
+         * trip over this.
+         */
+        LOGV("ODD: point set for targ=0x%04x (%p) already had block "
+             "fir=0x%04x (%p)",
+            targetIdx, targetBlock, curBlock->firstAddr, curBlock);
+    }
+
+    return true;
+}
+
+/*
+ * Add ourselves to the predecessor list in all blocks we might transfer
+ * control to.
+ *
+ * There are four ways to proceed to a new instruction:
+ *  (1) continue to the following instruction
+ *  (2) [un]conditionally branch to a specific location
+ *  (3) conditionally branch through a "switch" statement
+ *  (4) throw an exception
+ *
+ * Returning from the method (via a return statement or an uncaught
+ * exception) are not interesting for liveness analysis.
+ */
+static bool setPredecessors(VerifierData* vdata, VfyBasicBlock* curBlock,
+    u4 curIdx, OpcodeFlags opFlags, u4 nextIdx, u4* handlerList,
+    size_t numHandlers)
+{
+    const InsnFlags* insnFlags = vdata->insnFlags;
+    const Method* meth = vdata->method;
+
+    unsigned int handlerIdx;
+    for (handlerIdx = 0; handlerIdx < numHandlers; handlerIdx++) {
+        if (!addToPredecessor(vdata, curBlock, handlerList[handlerIdx]))
+            return false;
+    }
+
+    if ((opFlags & kInstrCanContinue) != 0) {
+        if (!addToPredecessor(vdata, curBlock, nextIdx))
+            return false;
+    }
+    if ((opFlags & kInstrCanBranch) != 0) {
+        bool unused, gotBranch;
+        s4 branchOffset, absOffset;
+
+        gotBranch = dvmGetBranchOffset(meth, insnFlags, curIdx,
+                &branchOffset, &unused);
+        assert(gotBranch);
+        absOffset = curIdx + branchOffset;
+        assert(absOffset >= 0 && (u4) absOffset < vdata->insnsSize);
+
+        if (!addToPredecessor(vdata, curBlock, absOffset))
+            return false;
+    }
+
+    if ((opFlags & kInstrCanSwitch) != 0) {
+        const u2* curInsn = &meth->insns[curIdx];
+        const u2* dataPtr;
+
+        /* these values have already been verified, so we can trust them */
+        s4 offsetToData = curInsn[1] | ((s4) curInsn[2]) << 16;
+        dataPtr = curInsn + offsetToData;
+
+        /*
+         * dataPtr points to the start of the switch data.  The first
+         * item is the NOP+magic, the second is the number of entries in
+         * the switch table.
+         */
+        u2 switchCount = dataPtr[1];
+
+        /*
+         * Skip past the ident field, size field, and the first_key field
+         * (for packed) or the key list (for sparse).
+         */
+        if (dexOpcodeFromCodeUnit(meth->insns[curIdx]) == OP_PACKED_SWITCH) {
+            dataPtr += 4;
+        } else {
+            assert(dexOpcodeFromCodeUnit(meth->insns[curIdx]) ==
+                    OP_SPARSE_SWITCH);
+            dataPtr += 2 + 2 * switchCount;
+        }
+
+        u4 switchIdx;
+        for (switchIdx = 0; switchIdx < switchCount; switchIdx++) {
+            s4 offset, absOffset;
+
+            offset = (s4) dataPtr[switchIdx*2] |
+                     (s4) (dataPtr[switchIdx*2 +1] << 16);
+            absOffset = curIdx + offset;
+            assert(absOffset >= 0 && (u4) absOffset < vdata->insnsSize);
+
+            if (!addToPredecessor(vdata, curBlock, absOffset))
+                return false;
+        }
+    }
+
+    if (false) {
+        if (dvmPointerSetGetCount(curBlock->predecessors) > 256) {
+            LOGI("Lots of preds at 0x%04x in %s.%s:%s", curIdx,
+                meth->clazz->descriptor, meth->name, meth->shorty);
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Dump the contents of the basic blocks.
+ */
+static void dumpBasicBlocks(const VerifierData* vdata)
+{
+    char printBuf[256];
+    unsigned int idx;
+    int count;
+
+    LOGI("Basic blocks for %s.%s:%s", vdata->method->clazz->descriptor,
+        vdata->method->name, vdata->method->shorty);
+    for (idx = 0; idx < vdata->insnsSize; idx++) {
+        VfyBasicBlock* block = vdata->basicBlocks[idx];
+        if (block == NULL)
+            continue;
+
+        assert(block->firstAddr == idx);
+        count = snprintf(printBuf, sizeof(printBuf), " %04x-%04x ",
+            block->firstAddr, block->lastAddr);
+
+        PointerSet* preds = block->predecessors;
+        size_t numPreds = dvmPointerSetGetCount(preds);
+
+        if (numPreds > 0) {
+            count += snprintf(printBuf + count, sizeof(printBuf) - count,
+                    "preds:");
+
+            unsigned int predIdx;
+            for (predIdx = 0; predIdx < numPreds; predIdx++) {
+                if (count >= (int) sizeof(printBuf))
+                    break;
+                const VfyBasicBlock* pred =
+                    (const VfyBasicBlock*) dvmPointerSetGetEntry(preds, predIdx);
+                count += snprintf(printBuf + count, sizeof(printBuf) - count,
+                        "%04x(%p),", pred->firstAddr, pred);
+            }
+        } else {
+            count += snprintf(printBuf + count, sizeof(printBuf) - count,
+                    "(no preds)");
+        }
+
+        printBuf[sizeof(printBuf)-2] = '!';
+        printBuf[sizeof(printBuf)-1] = '\0';
+
+        LOGI("%s", printBuf);
+    }
+
+    usleep(100 * 1000);      /* ugh...let logcat catch up */
+}
+
+
+/*
+ * Generate a list of basic blocks and related information.
+ *
+ * On success, returns "true" with vdata->basicBlocks initialized.
+ */
+bool dvmComputeVfyBasicBlocks(VerifierData* vdata)
+{
+    const InsnFlags* insnFlags = vdata->insnFlags;
+    const Method* meth = vdata->method;
+    const u4 insnsSize = vdata->insnsSize;
+    const DexCode* pCode = dvmGetMethodCode(meth);
+    const DexTry* pTries = NULL;
+    const size_t kHandlerStackAllocSize = 16;   /* max seen so far is 7 */
+    u4 handlerAddrs[kHandlerStackAllocSize];
+    u4* handlerListAlloc = NULL;
+    u4* handlerList = NULL;
+    size_t numHandlers = 0;
+    u4 idx, blockStartAddr;
+    bool result = false;
+
+    bool verbose = false; //dvmWantVerboseVerification(meth);
+    if (verbose) {
+        LOGI("Basic blocks for %s.%s:%s",
+            meth->clazz->descriptor, meth->name, meth->shorty);
+    }
+
+    /*
+     * Allocate a data structure that allows us to map from an address to
+     * the corresponding basic block.  Initially all pointers are NULL.
+     * They are populated on demand as we proceed (either when we reach a
+     * new BB, or when we need to add an item to the predecessor list in
+     * a not-yet-reached BB).
+     *
+     * Only the first instruction in the block points to the BB structure;
+     * the rest remain NULL.
+     */
+    vdata->basicBlocks =
+        (VfyBasicBlock**) calloc(insnsSize, sizeof(VfyBasicBlock*));
+    if (vdata->basicBlocks == NULL)
+      return false;
+
+    /*
+     * The "tries" list is a series of non-overlapping regions with a list
+     * of "catch" handlers.  Rather than do the "find a matching try block"
+     * computation at each step, we just walk the "try" list in parallel.
+     *
+     * Not all methods have "try" blocks.  If this one does, we init tryEnd
+     * to zero, so that the (exclusive bound) range check trips immediately.
+     */
+    u4 tryIndex = 0, tryStart = 0, tryEnd = 0;
+    if (pCode->triesSize != 0) {
+        pTries = dexGetTries(pCode);
+    }
+
+    u4 debugBBIndex = 0;
+
+    /*
+     * The address associated with a basic block is the start address.
+     */
+    blockStartAddr = 0;
+
+    for (idx = 0; idx < insnsSize; ) {
+        /*
+         * Make sure we're pointing at the right "try" block.  It should
+         * not be possible to "jump over" a block, so if we're no longer
+         * in the correct one we can just advance to the next.
+         */
+        if (pTries != NULL && idx >= tryEnd) {
+            if (tryIndex == pCode->triesSize) {
+                /* no more try blocks in this method */
+                pTries = NULL;
+                numHandlers = 0;
+            } else {
+                /*
+                 * Extract the set of handlers.  We want to avoid doing
+                 * this for each block, so we copy them to local storage.
+                 * If it doesn't fit in the small stack area, we'll use
+                 * the heap instead.
+                 *
+                 * It's rare to encounter a method with more than half a
+                 * dozen possible handlers.
+                 */
+                tryStart = pTries[tryIndex].startAddr;
+                tryEnd = tryStart + pTries[tryIndex].insnCount;
+
+                if (handlerListAlloc != NULL) {
+                    free(handlerListAlloc);
+                    handlerListAlloc = NULL;
+                }
+                numHandlers = extractCatchHandlers(pCode, &pTries[tryIndex],
+                    handlerAddrs, kHandlerStackAllocSize);
+                assert(numHandlers > 0);    // TODO make sure this is verified
+                if (numHandlers <= kHandlerStackAllocSize) {
+                    handlerList = handlerAddrs;
+                } else {
+                    LOGD("overflow, numHandlers=%d", numHandlers);
+                    handlerListAlloc = (u4*) malloc(sizeof(u4) * numHandlers);
+                    if (handlerListAlloc == NULL)
+                        return false;
+                    extractCatchHandlers(pCode, &pTries[tryIndex],
+                        handlerListAlloc, numHandlers);
+                    handlerList = handlerListAlloc;
+                }
+
+                LOGV("+++ start=%x end=%x numHan=%d",
+                    tryStart, tryEnd, numHandlers);
+
+                tryIndex++;
+            }
+        }
+
+        /*
+         * Check the current instruction, and possibly aspects of the
+         * next instruction, to see if this instruction ends the current
+         * basic block.
+         *
+         * Instructions that can throw only end the block if there is the
+         * possibility of a local handler catching the exception.
+         */
+        Opcode opcode = dexOpcodeFromCodeUnit(meth->insns[idx]);
+        OpcodeFlags opFlags = dexGetFlagsFromOpcode(opcode);
+        size_t nextIdx = idx + dexGetWidthFromInstruction(&meth->insns[idx]);
+        bool endBB = false;
+        bool ignoreInstr = false;
+
+        if ((opFlags & kInstrCanContinue) == 0) {
+            /* does not continue */
+            endBB = true;
+        } else if ((opFlags & (kInstrCanBranch | kInstrCanSwitch)) != 0) {
+            /* conditionally branches elsewhere */
+            endBB = true;
+        } else if ((opFlags & kInstrCanThrow) != 0 &&
+                dvmInsnIsInTry(insnFlags, idx))
+        {
+            /* throws an exception that might be caught locally */
+            endBB = true;
+        } else if (isDataChunk(meth->insns[idx])) {
+            /*
+             * If this is a data chunk (e.g. switch data) we want to skip
+             * over it entirely.  Set endBB so we don't carry this along as
+             * the start of a block, and ignoreInstr so we don't try to
+             * open a basic block for this instruction.
+             */
+            endBB = ignoreInstr = true;
+        } else if (dvmInsnIsBranchTarget(insnFlags, nextIdx)) {
+            /*
+             * We also need to end it if the next instruction is a branch
+             * target.  Note we've tagged exception catch blocks as such.
+             *
+             * If we're this far along in the "else" chain, we know that
+             * this isn't a data-chunk NOP, and control can continue to
+             * the next instruction, so we're okay examining "nextIdx".
+             */
+            assert(nextIdx < insnsSize);
+            endBB = true;
+        } else if (opcode == OP_NOP && isDataChunk(meth->insns[nextIdx])) {
+            /*
+             * Handle an odd special case: if this is NOP padding before a
+             * data chunk, also treat it as "ignore".  Otherwise it'll look
+             * like a block that starts and doesn't end.
+             */
+            endBB = ignoreInstr = true;
+        } else {
+            /* check: return ops should be caught by absence of can-continue */
+            assert((opFlags & kInstrCanReturn) == 0);
+        }
+
+        if (verbose) {
+            char btc = dvmInsnIsBranchTarget(insnFlags, idx) ? '>' : ' ';
+            char tryc =
+                (pTries != NULL && idx >= tryStart && idx < tryEnd) ? 't' : ' ';
+            bool startBB = (idx == blockStartAddr);
+            const char* startEnd;
+
+
+            if (ignoreInstr)
+                startEnd = "IGNORE";
+            else if (startBB && endBB)
+                startEnd = "START/END";
+            else if (startBB)
+                startEnd = "START";
+            else if (endBB)
+                startEnd = "END";
+            else
+                startEnd = "-";
+
+            LOGI("%04x: %c%c%s #%d", idx, tryc, btc, startEnd, debugBBIndex);
+
+            if (pTries != NULL && idx == tryStart) {
+                assert(numHandlers > 0);
+                LOGI("  EXC block: [%04x, %04x) %d:(%04x...)",
+                    tryStart, tryEnd, numHandlers, handlerList[0]);
+            }
+        }
+
+        if (idx != blockStartAddr) {
+            /* should not be a basic block struct associated with this addr */
+            assert(vdata->basicBlocks[idx] == NULL);
+        }
+        if (endBB) {
+            if (!ignoreInstr) {
+                /*
+                 * Create a new BB if one doesn't already exist.
+                 */
+                VfyBasicBlock* curBlock = vdata->basicBlocks[blockStartAddr];
+                if (curBlock == NULL) {
+                    curBlock = allocVfyBasicBlock(vdata, blockStartAddr);
+                    if (curBlock == NULL)
+                        return false;
+                    vdata->basicBlocks[blockStartAddr] = curBlock;
+                }
+
+                curBlock->firstAddr = blockStartAddr;
+                curBlock->lastAddr = idx;
+
+                if (!setPredecessors(vdata, curBlock, idx, opFlags, nextIdx,
+                        handlerList, numHandlers))
+                {
+                    goto bail;
+                }
+            }
+
+            blockStartAddr = nextIdx;
+            debugBBIndex++;
+        }
+
+        idx = nextIdx;
+    }
+
+    assert(idx == insnsSize);
+
+    result = true;
+
+    if (verbose)
+        dumpBasicBlocks(vdata);
+
+bail:
+    free(handlerListAlloc);
+    return result;
+}
+
+/*
+ * Free the storage used by basic blocks.
+ */
+void dvmFreeVfyBasicBlocks(VerifierData* vdata)
+{
+    unsigned int idx;
+
+    if (vdata->basicBlocks == NULL)
+        return;
+
+    for (idx = 0; idx < vdata->insnsSize; idx++) {
+        VfyBasicBlock* block = vdata->basicBlocks[idx];
+        if (block == NULL)
+            continue;
+
+        dvmPointerSetFree(block->predecessors);
+        free(block);
+    }
+}
diff --git a/vm/analysis/VfyBasicBlock.h b/vm/analysis/VfyBasicBlock.h
new file mode 100644
index 0000000..0fc7428
--- /dev/null
+++ b/vm/analysis/VfyBasicBlock.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Basic block functions, as used by the verifier.  (The names were chosen
+ * to avoid conflicts with similar structures used by the compiler.)
+ */
+#ifndef DALVIK_VFYBASICBLOCK_H_
+#define DALVIK_VFYBASICBLOCK_H_
+
+#include "PointerSet.h"
+
+struct VerifierData;
+
+
+/*
+ * Structure representing a basic block.
+ *
+ * This is used for liveness analysis, which is a reverse-flow algorithm,
+ * so we need to mantain a list of predecessors for each block.
+ *
+ * "liveRegs" indicates the set of registers that are live at the end of
+ * the basic block (after the last instruction has executed).  Successor
+ * blocks will compare their results with this to see if this block needs
+ * to be re-evaluated.  Note that this is not the same as the contents of
+ * the RegisterLine for the last instruction in the block (which reflects
+ * the state *before* the instruction has executed).
+ */
+struct VfyBasicBlock {
+    u4              firstAddr;      /* address of first instruction */
+    u4              lastAddr;       /* address of last instruction */
+    PointerSet*     predecessors;   /* set of basic blocks that can flow here */
+    BitVector*      liveRegs;       /* liveness for each register */
+    bool            changed;        /* input set has changed, must re-eval */
+    bool            visited;        /* block has been visited at least once */
+};
+
+/*
+ * Generate a list of basic blocks.
+ */
+bool dvmComputeVfyBasicBlocks(struct VerifierData* vdata);
+
+/*
+ * Free storage allocated by dvmComputeVfyBasicBlocks.
+ */
+void dvmFreeVfyBasicBlocks(struct VerifierData* vdata);
+
+#endif  // DALVIK_VFYBASICBLOCK_H_
diff --git a/vm/arch/arm/CallEABI.S b/vm/arch/arm/CallEABI.S
new file mode 100644
index 0000000..9971b5d
--- /dev/null
+++ b/vm/arch/arm/CallEABI.S
@@ -0,0 +1,444 @@
+/*
+ * 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.
+ */
+
+/*
+ * JNI method invocation.  This is used to call a C/C++ JNI method.  The
+ * argument list has to be pushed onto the native stack according to
+ * local calling conventions.
+ *
+ * This version supports the "new" ARM EABI.
+ */
+
+#include <machine/cpu-features.h>
+
+#ifdef __ARM_EABI__
+
+#ifdef EXTENDED_EABI_DEBUG
+# define DBG
+#else
+# define DBG @
+#endif
+
+
+/*
+Function prototype:
+
+void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
+    const u4* argv, const char* signature, void* func, JValue* pReturn)
+
+The method we are calling has the form:
+
+  return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
+    -or-
+  return_type func(JNIEnv* pEnv, Object* this, ...)
+
+We receive a collection of 32-bit values which correspond to arguments from
+the interpreter (e.g. float occupies one, double occupies two).  It's up to
+us to convert these into local calling conventions.
+*/
+
+/*
+ARM EABI notes:
+
+r0-r3 hold first 4 args to a method
+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.  This means
+we have to scan the method signature, identify arguments that must be
+padded, and fix them up appropriately.
+*/
+
+    .text
+    .align  2
+    .global dvmPlatformInvoke
+    .type   dvmPlatformInvoke, %function
+
+/*
+ * On entry:
+ *   r0  JNIEnv (can be left alone)
+ *   r1  clazz (NULL for virtual method calls, non-NULL for static)
+ *   r2  arg info
+ *   r3  argc (number of 32-bit values in argv)
+ *   [sp]     argv
+ *   [sp,#4]  short signature
+ *   [sp,#8]  func
+ *   [sp,#12] pReturn
+ *
+ * For a virtual method call, the "this" reference is in argv[0].
+ *
+ * argInfo (32-bit int) layout:
+ *   SRRRLLLL FFFFFFFF FFFFFFFF FFFFFFFF
+ *
+ *   S - if set, do things the hard way (scan the signature)
+ *   R - return-type enumeration, really only important for "hard" FP ABI
+ *   L - number of double-words of storage required on stack (0-30 words)
+ *   F - pad flag -- if set, write a pad word to the stack
+ *
+ * With this arrangement we can efficiently push up to 24 words of arguments
+ * onto the stack.  Anything requiring more than that -- which should happen
+ * rarely to never -- can do the slow signature scan.
+ *
+ * (We could pack the Fs more efficiently -- we know we never push two pads
+ * in a row, and the first word can never be a pad -- but there's really
+ * no need for it.)
+ *
+ * NOTE: if the called function has more than 4 words of arguments, gdb
+ * will not be able to unwind the stack past this method.  The only way
+ * around this is to convince gdb to respect an explicit frame pointer.
+ * The stack unwinder in debuggerd *does* pay attention to fp if we set it
+ * up appropriately, so at least that will work.
+ */
+dvmPlatformInvoke:
+    .fnstart
+
+    /*
+     * Save regs.
+     *
+     * On entry to a function, "sp" must be 64-bit aligned.  This means
+     * we have to adjust sp manually if we push an odd number of regs here
+     * (both here and when exiting).
+     *
+     * The ARM spec doesn't specify anything about the frame pointer.  gcc
+     * points fp at the first saved argument, so our "full descending"
+     * stack looks like:
+     *
+     *  pReturn
+     *  func
+     *  shorty
+     *  argv        <-- sp on entry
+     *  lr          <-- fp
+     *  fp
+     *  r9...r7
+     *  r6          <-- sp after reg save
+     *
+     * Any arguments that need to be pushed on for the target method
+     * come after this.  The last argument is pushed first.
+     */
+SAVED_REG_COUNT = 6                     @ push 6 regs
+FP_STACK_OFFSET = (SAVED_REG_COUNT-1) * 4 @ offset between fp and post-save sp
+FP_ADJ = 4                              @ fp is initial sp +4
+
+    .save        {r6, r7, r8, r9, fp, lr}
+    stmfd   sp!, {r6, r7, r8, r9, fp, lr}
+
+    .setfp  fp, sp, #FP_STACK_OFFSET    @ point fp at first saved reg
+    add     fp, sp, #FP_STACK_OFFSET
+
+    @.pad    #4                          @ adjust for 64-bit align
+    @sub     sp, sp, #4                  @ (if we save odd number of regs)
+
+    @ Ensure 64-bit alignment.  EABI guarantees sp is aligned on entry, make
+    @ sure we're aligned properly now.
+DBG tst     sp, #4                      @ 64-bit aligned?
+DBG bne     dvmAbort                    @ no, fail
+
+    ldr     r9, [fp, #0+FP_ADJ]         @ r9<- argv
+    cmp     r1, #0                      @ calling a static method?
+
+    @ Not static, grab the "this" pointer.  Note "this" is not explicitly
+    @ described by the method signature.
+    subeq   r3, r3, #1                  @ argc--
+    ldreq   r1, [r9], #4                @ r1<- *argv++
+
+    @ Do we have arg padding flags in "argInfo"? (just need to check hi bit)
+    teq     r2, #0
+    bmi     .Lno_arg_info
+
+    /*
+     * "Fast" path.
+     *
+     * Make room on the stack for the arguments and copy them over,
+     * inserting pad words when appropriate.
+     *
+     * Currently:
+     *  r0  don't touch
+     *  r1  don't touch
+     *  r2  arg info
+     *  r3  argc
+     *  r4-r5  don't touch (not saved)
+     *  r6-r8 (available)
+     *  r9  argv
+     *  fp  frame pointer
+     */
+.Lhave_arg_info:
+    @ Expand the stack by the specified amount.  We want to extract the
+    @ count of double-words from r2, multiply it by 8, and subtract that
+    @ from the stack pointer.
+    and     ip, r2, #0x0f000000         @ ip<- double-words required
+    mov     r6, r2, lsr #28             @ r6<- return type
+    sub     sp, sp, ip, lsr #21         @ shift right 24, then left 3
+    mov     r8, sp                      @ r8<- sp  (arg copy dest)
+
+    @ Stick argv in r7 and advance it past the argv values that will be
+    @ held in r2-r3.  It's possible r3 will hold a pad, so check the
+    @ bit in r2.  We do this by ignoring the first bit (which would
+    @ indicate a pad in r2) and shifting the second into the carry flag.
+    @ If the carry is set, r3 will hold a pad, so we adjust argv less.
+    @
+    @ (This is harmless if argc==0)
+    mov     r7, r9
+    movs    r2, r2, lsr #2
+    addcc   r7, r7, #8                  @ skip past 2 words, for r2 and r3
+    subcc   r3, r3, #2
+    addcs   r7, r7, #4                  @ skip past 1 word, for r2
+    subcs   r3, r3, #1
+
+.Lfast_copy_loop:
+    @ if (--argc < 0) goto invoke
+    subs    r3, r3, #1
+    bmi     .Lcopy_done                 @ NOTE: expects original argv in r9
+
+.Lfast_copy_loop2:
+    @ Get pad flag into carry bit.  If it's set, we don't pull a value
+    @ out of argv.
+    movs    r2, r2, lsr #1
+    ldrcc   ip, [r7], #4                @ ip = *r7++ (pull from argv)
+    strcc   ip, [r8], #4                @ *r8++ = ip (write to stack)
+    bcc     .Lfast_copy_loop
+
+DBG movcs   ip, #-3                     @ DEBUG DEBUG - make pad word obvious
+DBG strcs   ip, [r8]                    @ DEBUG DEBUG
+    add     r8, r8, #4                  @ if pad, just advance ip without store
+    b       .Lfast_copy_loop2           @ don't adjust argc after writing pad
+
+
+.Lcopy_done:
+    /*
+     * Currently:
+     *  r0-r3  args (JNIEnv*, thisOrClass, arg0, arg1)
+     *  r6  return type (enum DalvikJniReturnType)
+     *  r9  original argv
+     *  fp  frame pointer
+     *
+     * The stack copy is complete.  Grab the first two words off of argv
+     * and tuck them into r2/r3.  If the first arg is 32-bit and the second
+     * arg is 64-bit, then r3 "holds" a pad word and the load is unnecessary
+     * but harmless.
+     *
+     * If there are 0 or 1 arg words in argv, we will be loading uninitialized
+     * data into the registers, but since nothing tries to use it it's also
+     * harmless (assuming argv[0] and argv[1] point to valid memory, which
+     * is a reasonable assumption for Dalvik's interpreted stacks).
+     */
+    ldmia   r9, {r2-r3}                 @ r2/r3<- argv[0]/argv[1]
+
+    ldr     ip, [fp, #8+FP_ADJ]         @ ip<- func
+#ifdef __ARM_HAVE_BLX
+    blx     ip                          @ call func
+#else
+    mov     lr, pc                      @ call func the old-fashioned way
+    bx      ip
+#endif
+
+    @ We're back, result is in r0 or (for long/double) r0-r1.
+    @
+    @ In theory, we need to use the "return type" arg to figure out what
+    @ we have and how to return it.  However, unless we have an FPU and
+    @ "hard" fp calling conventions, all we need to do is copy r0-r1 into
+    @ the JValue union.
+    @
+    @ Thought: could redefine DalvikJniReturnType such that single-word
+    @ and double-word values occupy different ranges; simple comparison
+    @ allows us to choose between str and stm.  Probably not worthwhile.
+    @
+    cmp     r6, #0                      @ DALVIK_JNI_RETURN_VOID?
+    ldrne   ip, [fp, #12+FP_ADJ]        @ pReturn
+    sub     sp, fp, #FP_STACK_OFFSET    @ restore sp to post-reg-save offset
+    stmneia ip, {r0-r1}                 @ pReturn->j <- r0/r1
+
+    @ Restore the registers we saved and return.  On >= ARMv5TE we can
+    @ restore PC directly from the saved LR.
+#ifdef __ARM_HAVE_PC_INTERWORK
+    ldmfd   sp!, {r6, r7, r8, r9, fp, pc}
+#else
+    ldmfd   sp!, {r6, r7, r8, r9, fp, lr}
+    bx      lr
+#endif
+
+
+
+    /*
+     * "Slow" path.
+     * Walk through the argument list, counting up the number of 32-bit words
+     * required to contain it.  Then walk through it a second time, copying
+     * values out to the stack.  (We could pre-compute the size to save
+     * ourselves a trip, but we'd have to store that somewhere -- this is
+     * sufficiently unlikely that it's not worthwhile.)
+     *
+     * Try not to make any assumptions about the number of args -- I think
+     * the class file format allows up to 64K words (need to verify that).
+     *
+     * Currently:
+     *  r0  don't touch
+     *  r1  don't touch
+     *  r2  (available)
+     *  r3  argc
+     *  r4-r5 don't touch (not saved)
+     *  r6-r8 (available)
+     *  r9  argv
+     *  fp  frame pointer
+     */
+.Lno_arg_info:
+    mov     ip, r2, lsr #28             @ ip<- return type
+    ldr     r6, [fp, #4+FP_ADJ]         @ r6<- short signature
+    add     r6, r6, #1                  @ advance past return type
+    mov     r2, #0                      @ r2<- word count, init to zero
+
+.Lcount_loop:
+    ldrb    ip, [r6], #1                @ ip<- *signature++
+    cmp     ip, #0                      @ end?
+    beq     .Lcount_done                @ all done, bail
+    add     r2, r2, #1                  @ count++
+    cmp     ip, #'D'                    @ look for 'D' or 'J', which are 64-bit
+    cmpne   ip, #'J'
+    bne     .Lcount_loop
+
+    @ 64-bit value, insert padding if we're not aligned
+    tst     r2, #1                      @ odd after initial incr?
+    addne   r2, #1                      @ no, add 1 more to cover 64 bits
+    addeq   r2, #2                      @ yes, treat prev as pad, incr 2 now
+    b       .Lcount_loop
+.Lcount_done:
+
+    @ We have the padded-out word count in r2.  We subtract 2 from it
+    @ because we don't push the first two arg words on the stack (they're
+    @ destined for r2/r3).  Pushing them on and popping them off would be
+    @ simpler but slower.
+    subs    r2, r2, #2                  @ subtract 2 (for contents of r2/r3)
+    movmis  r2, #0                      @ if negative, peg at zero, set Z-flag
+    beq     .Lcopy_done                 @ zero args, skip stack copy
+
+DBG tst     sp, #7                      @ DEBUG - make sure sp is aligned now
+DBG bne     dvmAbort                    @ DEBUG
+
+    @ Set up to copy from r7 to r8.  We copy from the second arg to the
+    @ last arg, which means reading and writing to ascending addresses.
+    sub     sp, sp, r2, asl #2          @ sp<- sp - r2*4
+    bic     sp, #4                      @ subtract another 4 ifn
+    mov     r7, r9                      @ r7<- argv
+    mov     r8, sp                      @ r8<- sp
+
+    @ We need to copy words from [r7] to [r8].  We walk forward through
+    @ the signature again, "copying" pad words when appropriate, storing
+    @ upward into the stack.
+    ldr     r6, [fp, #4+FP_ADJ]         @ r6<- signature
+    add     r6, r6, #1                  @ advance past return type
+    add     r7, r7, #8                  @ r7<- r7+8 (assume argv 0/1 in r2/r3)
+
+    @ Eat first arg or two, for the stuff that goes into r2/r3.
+    ldrb    ip, [r6], #1                @ ip<- *signature++
+    cmp     ip, #'D'
+    cmpne   ip, #'J'
+    beq     .Lstack_copy_loop           @ 64-bit arg fills r2+r3
+
+    @ First arg was 32-bit, check the next
+    ldrb    ip, [r6], #1                @ ip<- *signature++
+    cmp     ip, #'D'
+    cmpne   ip, #'J'
+    subeq   r7, #4                      @ r7<- r7-4 (take it back - pad word)
+    beq     .Lstack_copy_loop2          @ start with char we already have
+
+    @ Two 32-bit args, fall through and start with next arg
+
+.Lstack_copy_loop:
+    ldrb    ip, [r6], #1                @ ip<- *signature++
+.Lstack_copy_loop2:
+    cmp     ip, #0                      @ end of shorty?
+    beq     .Lcopy_done                 @ yes
+
+    cmp     ip, #'D'
+    cmpne   ip, #'J'
+    beq     .Lcopy64
+
+    @ Copy a 32-bit value.  [r8] is initially at the end of the stack.  We
+    @ use "full descending" stacks, so we store into [r8] and incr as we
+    @ move toward the end of the arg list.
+.Lcopy32:
+    ldr     ip, [r7], #4
+    str     ip, [r8], #4
+    b       .Lstack_copy_loop
+
+.Lcopy64:
+    @ Copy a 64-bit value.  If necessary, leave a hole in the stack to
+    @ ensure alignment.  We know the [r8] output area is 64-bit aligned,
+    @ so we can just mask the address.
+    add     r8, r8, #7          @ r8<- (r8+7) & ~7
+    ldr     ip, [r7], #4
+    bic     r8, r8, #7
+    ldr     r2, [r7], #4
+    str     ip, [r8], #4
+    str     r2, [r8], #4
+    b       .Lstack_copy_loop
+
+    .fnend
+    .size   dvmPlatformInvoke, .-dvmPlatformInvoke
+
+#if 0
+
+/*
+ * 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
+#ifdef __ARM_HAVE_PC_INTERWORK
+    ldmfd   sp!, {r0, r1, r2, r3, ip, pc}
+#else
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+#endif
+    .endm
+
+    SQUEAK  0
+    SQUEAK  1
+    SQUEAK  2
+    SQUEAK  3
+    SQUEAK  4
+    SQUEAK  5
+
+strSqueak:
+    .word   .LstrSqueak
+.LstrSqueak:
+    .asciz  "<%d>"
+
+    .align  2
+
+#endif
+
+#endif /*__ARM_EABI__*/
diff --git a/vm/arch/arm/CallOldABI.S b/vm/arch/arm/CallOldABI.S
new file mode 100644
index 0000000..2463d3c
--- /dev/null
+++ b/vm/arch/arm/CallOldABI.S
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+/*
+ * JNI method invocation.  This is used to call a C/C++ JNI method.  The
+ * argument list has to be pushed onto the native stack according to
+ * local calling conventions.
+ *
+ * This version supports the "old" ARM ABI.
+ */
+
+#include <machine/cpu-features.h>
+
+#ifndef __ARM_EABI__
+
+/*
+Function prototype:
+
+void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
+    const u4* argv, const char* signature, void* func, JValue* pReturn)
+
+The method we are calling has the form:
+
+  return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
+    -or-
+  return_type func(JNIEnv* pEnv, Object* this, ...)
+
+We receive a collection of 32-bit values which correspond to arguments from
+the interpreter (e.g. float occupies one, double occupies two).  It's up to
+us to convert these into local calling conventions.
+ */
+
+/*
+ARM ABI notes:
+
+r0-r3 hold first 4 args to a method
+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
+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 <= 4 bytes
+r0-r1 hold returns of 5-8 bytes, low word in r0
+
+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.
+
+Happily we don't have to do anything special here -- the args from the
+interpreter work directly as C/C++ args on ARM (with the "classic" ABI).
+*/
+
+    .text
+    .align  2
+    .global dvmPlatformInvoke
+    .type   dvmPlatformInvoke, %function
+
+/*
+On entry:
+  r0  JNIEnv
+  r1  clazz (NULL for virtual method calls, non-NULL for static)
+  r2  arg info (ignored)
+  r3  argc
+  [sp]     argv
+  [sp,#4]  signature (ignored)
+  [sp,#8]  func
+  [sp,#12] pReturn
+*/
+dvmPlatformInvoke:
+    @ Standard gcc stack frame setup.  We don't need to push the original
+    @ sp or the current pc if "-fomit-frame-pointer" is in use for the
+    @ rest of the code.  If we don't plan to use a debugger we can speed
+    @ this up a little.
+    mov     ip, sp
+    stmfd   sp!, {r4, r5, r6, fp, ip, lr, pc}
+    sub     fp, ip, #4          @ set up fp, same way gdb does
+
+    @ We need to push a variable number of arguments onto the stack.
+    @ Rather than keep a count and pop them off after, we just hold on to
+    @ the stack pointers.
+    @
+    @ In theory we don't need to keep sp -- we can do an ldmdb instead of
+    @ an ldmia -- but we're doing the gcc frame trick where we push the
+    @ pc on with stmfd and don't pop it off.
+    mov     r4, ip
+    mov     r5, sp
+
+    @ argc is already in a scratch register (r3).  Put argv into one.  Note
+    @ argv can't go into r0-r3 because we need to use it to load those.
+    ldr     ip, [r4, #0]        @ ip <-- argv
+
+    @ Is this a static method?
+    cmp     r1, #0
+
+    @ No: set r1 to *argv++, and set argc--.
+    @ (r0=pEnv, r1=this)
+    ldreq   r1, [ip], #4
+    subeq   r3, r3, #1
+
+    @ While we still have the use of r2/r3, copy excess args from argv
+    @ to the stack.  We need to push the last item in argv first, and we
+    @ want the first two items in argv to end up in r2/r3.
+    subs    r3, r3, #2
+    ble     .Lno_copy
+
+    @ If there are N args, we want to skip 0 and 1, and push (N-1)..2.  We
+    @ have N-2 in r3.  If we set argv=argv+1, we can count from N-2 to 1
+    @ inclusive and get the right set of args.
+    add     r6, ip, #4
+
+.Lcopy:
+    @ *--sp = argv[count]
+    ldr     r2, [r6, r3, lsl #2]
+    str     r2, [sp, #-4]!
+    subs    r3, r3, #1
+    bne     .Lcopy
+
+.Lno_copy:
+    @ Load the last two args.  These are coming out of the interpreted stack,
+    @ and the VM preserves an overflow region at the bottom, so it should be
+    @ safe to load two items out of argv even if we're at the end.
+    ldr     r2, [ip]
+    ldr     r3, [ip, #4]
+
+    @ Show time.  Tuck the pc into lr and load the pc from the method
+    @ address supplied by the caller.  The value for "pc" is offset by 8
+    @ due to instruction prefetching.
+    @
+#ifdef __ARM_HAVE_PC_INTERWORK
+    mov     lr, pc
+    ldr     pc, [r4, #8]
+#else
+    ldr     ip, [r4, #8]
+    blx     ip
+#endif
+
+    @ We're back, result is in r0 or (for long/double) r0-r1.
+    @
+    @ In theory, we need to use the "return type" arg to figure out what
+    @ we have and how to return it.  However, unless we have an FPU,
+    @ all we need to do is copy r0-r1 into the JValue union.
+    ldr     ip, [r4, #12]
+    stmia   ip, {r0-r1}
+
+#ifdef __ARM_HAVE_PC_INTERWORK
+    @ Restore the registers we saved and return.  Note this remaps stuff,
+    @ so that "sp" comes from "ip", "pc" comes from "lr", and the "pc"
+    @ we pushed on evaporates when we restore "sp".
+    ldmfd   r5, {r4, r5, r6, fp, sp, pc}
+#else
+    ldmfd   r5, {r4, r5, r6, fp, sp, lr}
+    bx      lr
+#endif
+
+#endif /*__ARM_EABI__*/
diff --git a/vm/arch/arm/HintsEABI.cpp b/vm/arch/arm/HintsEABI.cpp
new file mode 100644
index 0000000..3e27e5a
--- /dev/null
+++ b/vm/arch/arm/HintsEABI.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+/*
+ * Target-specific optimization and run-time hints
+ */
+
+
+#include "Dalvik.h"
+#include "libdex/DexClass.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+
+/*
+ * The class loader will associate with each method a 32-bit info word
+ * (jniArgInfo) to support JNI calls.  The high order 4 bits of this word
+ * are the same for all targets, while the lower 28 are used for hints to
+ * allow accelerated JNI bridge transfers.
+ *
+ * jniArgInfo (32-bit int) layout:
+ *
+ *    SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+ *
+ *    S - if set, ignore the hints and do things the hard way (scan signature)
+ *    R - return-type enumeration
+ *    H - target-specific hints (see below for details)
+ *
+ * This function produces arm-specific hints - specifically a description
+ * of padding required to keep all 64-bit parameters properly aligned.
+ *
+ * ARM JNI hint format
+ *
+ *       LLLL FFFFFFFF FFFFFFFF FFFFFFFF
+ *
+ *   L - number of double-words of storage required on the stack (0-30 words)
+ *   F - pad flag -- if set, write a pad word to the stack before copying
+ *       the next 32 bits
+ *
+ * If there are too many arguments to construct valid hints, this function will
+ * return a result with the S bit set.
+ */
+u4 dvmPlatformInvokeHints(const DexProto* proto)
+{
+    const char* sig = dexProtoGetShorty(proto);
+    int padFlags, jniHints;
+    char sigByte;
+    int stackOffset, padMask;
+
+    stackOffset = padFlags = 0;
+    padMask = 0x00000001;
+
+    /* Skip past the return type */
+    sig++;
+
+    while (true) {
+        sigByte = *(sig++);
+
+        if (sigByte == '\0')
+            break;
+
+        if (sigByte == 'D' || sigByte == 'J') {
+            if ((stackOffset & 1) != 0) {
+                padFlags |= padMask;
+                stackOffset++;
+                padMask <<= 1;
+            }
+            stackOffset += 2;
+            padMask <<= 2;
+        } else {
+            stackOffset++;
+            padMask <<= 1;
+        }
+    }
+
+    jniHints = 0;
+
+    if (stackOffset > DALVIK_JNI_COUNT_SHIFT) {
+        /* too big for "fast" version */
+        jniHints = DALVIK_JNI_NO_ARG_INFO;
+    } else {
+        assert((padFlags & (0xffffffff << DALVIK_JNI_COUNT_SHIFT)) == 0);
+        stackOffset -= 2;           // r2/r3 holds first two items
+        if (stackOffset < 0)
+            stackOffset = 0;
+        jniHints |= ((stackOffset+1) / 2) << DALVIK_JNI_COUNT_SHIFT;
+        jniHints |= padFlags;
+    }
+
+    return jniHints;
+}
diff --git a/vm/arch/generic/Call.cpp b/vm/arch/generic/Call.cpp
new file mode 100644
index 0000000..c23e7c8
--- /dev/null
+++ b/vm/arch/generic/Call.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/*
+ * This uses the FFI (Foreign Function Interface) library to abstract away
+ * the system-dependent stuff.  The FFI code is slower than a custom
+ * assembly version, but has the distinct advantage of having been
+ * written already for several platforms.
+ */
+#include "Dalvik.h"
+#include "ffi.h"
+
+/*
+ * Convert a signature type character to an FFI type.
+ */
+static ffi_type* getFfiType(char sigType)
+{
+    switch (sigType) {
+    case 'V': return &ffi_type_void;
+    case 'Z': return &ffi_type_uint8;
+    case 'B': return &ffi_type_sint8;
+    case 'C': return &ffi_type_uint16;
+    case 'S': return &ffi_type_sint16;
+    case 'I': return &ffi_type_sint32;
+    case 'F': return &ffi_type_float;
+    case 'J': return &ffi_type_sint64;
+    case 'D': return &ffi_type_double;
+    case '[':
+    case 'L': return &ffi_type_pointer;
+    default:
+        LOGE("bad ffitype 0x%02x", sigType);
+        dvmAbort();
+        return NULL;
+    }
+}
+
+/*
+ * Call "func" with the specified arguments.
+ *
+ * The second argument to JNI native functions is either the object (the
+ * "this" pointer) or, for static functions, a pointer to the class object.
+ * The Dalvik instructions will push "this" into argv[0], but it's up to
+ * us to insert the class object.
+ *
+ * Because there is no such thing in as a null "this" pointer, we use
+ * the non-NULL state of "clazz" to determine whether or not it's static.
+ *
+ * For maximum efficiency we should compute the CIF once and save it with
+ * the method.  However, this requires storing the data with every native
+ * method.  Since the goal is to have custom assembly versions of this
+ * on the platforms where performance matters, I'm recomputing the CIF on
+ * every call.
+ */
+void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
+    const u4* argv, const char* shorty, void* func, JValue* pReturn)
+{
+    const int kMaxArgs = argc+2;    /* +1 for env, maybe +1 for clazz */
+    ffi_cif cif;
+    ffi_type* types[kMaxArgs];
+    void* values[kMaxArgs];
+    ffi_type* retType;
+    char sigByte;
+    int srcArg, dstArg;
+
+    types[0] = &ffi_type_pointer;
+    values[0] = &pEnv;
+
+    types[1] = &ffi_type_pointer;
+    if (clazz != NULL) {
+        values[1] = &clazz;
+        srcArg = 0;
+    } else {
+        values[1] = (void*) argv++;
+        srcArg = 1;
+    }
+    dstArg = 2;
+
+    /*
+     * Scan the types out of the short signature.  Use them to fill out the
+     * "types" array.  Store the start address of the argument in "values".
+     */
+    retType = getFfiType(*shorty);
+    while ((sigByte = *++shorty) != '\0') {
+        types[dstArg] = getFfiType(sigByte);
+        values[dstArg++] = (void*) argv++;
+        if (sigByte == 'D' || sigByte == 'J')
+            argv++;
+    }
+
+    /*
+     * Prep the CIF (Call InterFace object).
+     */
+    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, dstArg, retType, types) != FFI_OK) {
+        LOGE("ffi_prep_cif failed");
+        dvmAbort();
+    }
+
+    ffi_call(&cif, FFI_FN(func), pReturn, values);
+}
diff --git a/vm/arch/generic/Hints.cpp b/vm/arch/generic/Hints.cpp
new file mode 100644
index 0000000..7b08aeb
--- /dev/null
+++ b/vm/arch/generic/Hints.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+/*
+ * Target-specific optimization and run-time hints
+ */
+
+
+#include "Dalvik.h"
+#include "libdex/DexClass.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+
+/*
+ * The class loader will associate with each method a 32-bit info word
+ * (jniArgInfo) to support JNI calls.  The high order 4 bits of this word
+ * are the same for all targets, while the lower 28 are used for hints to
+ * allow accelerated JNI bridge transfers.
+ *
+ * jniArgInfo (32-bit int) layout:
+ *
+ *    SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+ *
+ *    S - if set, ignore the hints and do things the hard way (scan signature)
+ *    R - return-type enumeration
+ *    H - target-specific hints
+ *
+ * This function is a placeholder/template and should be duplicated in the
+ * appropriate arch/<target>/ directory for new target ports.  The hints
+ * field should be defined and constructed in conjunction with
+ * dvmPlatformInvoke.
+
+ * If valid hints can't be constructed, this function should return a negative
+ * value.  In that case, the caller will set the S bit in the jniArgInfo word
+ * and convert the arguments the slow way.
+ */
+u4 dvmPlatformInvokeHints( const DexProto* proto)
+{
+    /* No hints for generic target - force argument walk at run-time */
+    return DALVIK_JNI_NO_ARG_INFO;
+}
diff --git a/vm/arch/sh/CallSH4ABI.S b/vm/arch/sh/CallSH4ABI.S
new file mode 100644
index 0000000..f8b2ddc
--- /dev/null
+++ b/vm/arch/sh/CallSH4ABI.S
@@ -0,0 +1,400 @@
+/*
+ * 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.
+ */
+/*
+ * Invoking JNI native method via SH4 ABI.
+ * This inplementation follows the spec found in following URL.
+ * http://www.ecos.sourceware.org/docs-1.3.1/ref/gnupro-ref/sh/SH_ch01.html#pgfId-461254
+
+ * This version supports SH4A little endian.
+ */
+    .text
+    .align 4
+    .type  dvmPlatformInvoke, #function
+    .globl dvmPlatformInvoke
+
+/*
+ * @param r4 void* pEnv  (used as scrach after invoking method)
+ * @param r5 ClassObject* clazz
+ * @param r6 int argInfo
+ * @param r7 int argc
+ * @param r15[0] const u4 * argv
+ * @param r15[1] const char * shorty
+ * @param r15[2] void * func
+ * @param r15[3] JValue * pReturn
+ *
+ * @remark r0,r1  Scratch before invoking method.
+ *                Return value after invoking method.
+ * @remark r2  shorty pointer
+ * @remark r3  argv pointer before invoking method.
+ *             pReturn after invoking method.
+ * @remark r8-11 Don't touch.
+ * @remark r12 status of r5-7
+ * @remark r13 status of fr4-11
+ * @remark r14 Keep stack pointer.
+ */
+dvmPlatformInvoke:
+    ## save preserved regsiters
+    mov.l   r14, @-r15
+    mov     r15, r14
+    add     #4, r14             /* r14 = original r15 = stack pointer */
+    mov.l   r13, @-r15
+    mov.l   r12, @-r15
+    sts.l   pr, @-r15
+
+    # fetch arguments
+    mov.l   @r14, r3            /* argv */
+    mov.l   @(4,r14), r2        /* shorty for argumnets */
+    mov     #1, r0              /* shorty's 1st byte specify ret value type. */
+    add     r0, r2
+
+### initialize local variables
+
+    ## r12 ... status of r6, and r7
+    ##          bit 1 << 0 : if r6 is available, it contains 1.
+    ##          bit 1 << 1 : if r7 is available, it contains 1.
+    ##  Note : r4 is always used to pass pEnv.
+    ##         r5 is always used for clazz or object
+    mov     #3, r12             /* b0000-0111 : r5-7 avialble. */
+
+    ## r13 ... status of fr4-fr11
+    ##          bit 1 << 0 : if fr4 is available, it contains 1.
+    ##          bit 1 << 1 : if fr5 is available, it contains 1.
+    ##      ...
+    ##          bit 1 << 7 : if fr11 is available, it contains 1.
+    mov     #0xFF, r13          /* b1111-1111 : fr4-11 avialble. */
+
+### put arguments
+
+    ## ... keep pEnv in r4 as is.
+
+    ## check clazz
+    mov     #0, r0
+    cmp/eq  r0, r5
+    bf      arg_loop            /* if r5 has clazz, keep it as is */
+    mov.l   @r3+, r5            /* put object arg in r5 */
+
+    ## other args
+arg_loop:
+one_arg_handled:
+    mov.b   @r2+, r0
+    cmp/eq  #0, r0              /* if (*shorty == '\0) */
+    bf      process_one_arg
+    bra     arg_end             /* no argument left */
+    nop
+
+process_one_arg:
+
+    ## check arg type
+
+    cmp/eq  #'F', r0
+    bt      jfloat_arg
+
+    cmp/eq  #'D', r0
+    bt      jdouble_arg
+
+    cmp/eq  #'J', r0
+    bt      jlong_arg
+
+    ## other 32bit arg types
+    mov     r12, r0
+    cmp/eq  #0, r0
+    bt      put_32bit_on_stack  /* r6-7 not available */
+
+    tst     #1, r0
+    bt      j32_arg_1
+    mov.l   @r3+, r6            /* put one arg in r6 */
+    mov     #1, r0              /* r6 is not available now. */
+    not     r0, r0
+    and     r0, r12
+    bra     one_arg_handled
+    nop
+j32_arg_1:
+    tst     #2, r0
+    bt      j32_arg_fatal_error
+    mov.l   @r3+, r7            /* put one arg in r7 */
+    mov     #2, r0              /* r7 is not available now. */
+    not     r0, r0
+    and     r0, r12
+    bra     one_arg_handled
+    nop
+
+j32_arg_fatal_error:
+    bra     j32_arg_fatal_error
+    nop
+
+jlong_arg:
+    mov     r12, r0
+    cmp/eq  #0, r0
+    bt      put_64bit_on_stack  /* r6-7 not available */
+
+    and     #3, r0
+    cmp/eq  #3, r0
+    bf      put_64bit_on_stack  /* consequent two registers not available. */
+    mov.l   @r3+, r6            /* put one arg in r6 and r7 */
+    mov.l   @r3+, r7
+    mov     #3, r0              /* r6 and r7 are not available now. */
+    not     r0, r0
+    and     r0, r12
+    bra     one_arg_handled
+    nop
+
+    # utility routines are placed here make short range jumps available.
+put_32bit_on_stack:
+    mov.l   @r3+, r0
+    mov.l   r0, @-r15
+    bra     one_arg_handled
+    nop
+
+put_64bit_on_stack:
+    mov.l   @r3+, r0
+    mov.l   r0, @-r15           /* Pay attention that the endianness is */
+    mov.l   @r3+, r0            /* once reversed.  It is corrected when the */
+    mov.l   r0, @-r15           /* arguments on stack are revesred before */
+    bra     one_arg_handled     /* jni call */
+    nop
+
+jdouble_arg:
+    mov     r13, r0
+    cmp/eq  #0, r0
+    bt      put_64bit_on_stack  /* fr4-11 not available */
+
+    and     #3, r0
+    cmp/eq  #3, r0
+    bf      jdouble_arg_1
+
+    fmov.s  @r3+, fr5           /* put one arg to drX */
+    fmov.s  @r3+, fr4
+    mov     #3, r0              /* fr4-frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jdouble_arg_1:
+    mov     r13, r0
+    and     #12, r0
+    cmp/eq  #12, r0
+    bf      jdouble_arg_2
+
+    fmov.s  @r3+, fr7           /* put one arg to drX */
+    fmov.s  @r3+, fr6
+    mov     #15, r0             /* fr4-frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jdouble_arg_2:
+    mov     r13, r0
+    and     #48, r0
+    cmp/eq  #48, r0
+    bf      jdouble_arg_3
+    fmov.s  @r3+, fr9           /* put one arg to drX */
+    fmov.s  @r3+, fr8
+    mov     #63, r0             /* fr4-frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jdouble_arg_3:
+    mov     r13, r0
+    and     #192, r0
+    cmp/eq  #192, r0
+    bf      put_64bit_on_stack
+    fmov.s  @r3+, fr11          /* put one arg to drX */
+    fmov.s  @r3+, fr10
+    mov     #0, r13             /* fr4-fr11 all not available now. */
+    bra     one_arg_handled
+    nop
+
+jfloat_arg:
+    mov     r13, r0
+    cmp/eq  #0, r0
+    bt      put_32bit_on_stack  /* fr4-11 not available */
+
+    tst     #2, r0
+    bt      jfloat_arg_1
+    fmov.s  @r3+, fr5           /* put one arg to frX */
+    mov     #2, r0              /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_1:
+    tst     #1, r0
+    bt      jfloat_arg_2
+    fmov.s  @r3+, fr4           /* put one arg to frX */
+    mov     #1, r0              /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_2:
+    tst     #8, r0
+    bt      jfloat_arg_3
+    fmov.s  @r3+, fr7           /* put one arg to frX */
+    mov     #8, r0              /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_3:
+    tst     #4, r0
+    bt      jfloat_arg_4
+    fmov.s  @r3+, fr6           /* put one arg to frX */
+    mov     #4, r0              /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_4:
+    tst     #32, r0
+    bt      jfloat_arg_5
+    fmov.s  @r3+, fr9           /* put one arg to frX */
+    mov     #32, r0             /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_5:
+    tst     #16, r0
+    bt      jfloat_arg_6
+    fmov.s  @r3+, fr8           /* put one arg to frX */
+    mov     #16, r0             /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_6:
+    tst     #128, r0
+    bt      jfloat_arg_7
+    fmov.s  @r3+, fr11          /* put one arg to frX */
+    mov     #127, r0            /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_arg_7:
+    tst     #64, r0
+    bt      jfloat_fatal_error
+    fmov.s  @r3+, fr10          /* put one arg to frX */
+    mov     #64, r0             /* frX not available now. */
+    not     r0, r0
+    and     r0, r13
+    bra     one_arg_handled
+    nop
+
+jfloat_fatal_error:
+    bra     jfloat_fatal_error:
+    nop
+
+arg_end:
+
+
+### reverse the variables on stack
+    mov     r14, r12            /* points to first arg on stack */
+    add     #-20, r12
+    mov     r15, r13            /* points to last arg on stack */
+arg_rev_loop:
+    cmp/hs  r12, r13            /* When r13 >= r12 (unsigned), 1->T */
+    bt      arg_rev_end
+    mov.l   @r12, r0
+    mov.l   @r13, r1
+    mov.l   r0, @r13
+    mov.l   r1, @r12
+    add     #-4, r12
+    add     #4, r13
+    bra     arg_rev_loop
+    nop
+
+arg_rev_end:
+
+### invoke the JNI function.
+
+    mov.l   @(8,r14), r0
+    jsr     @r0
+    nop
+
+### pass the return value
+
+    /*
+     * r0 and r1 keep return value.
+     */
+
+    ## fetch data
+    mov.l   @(4,r14), r2        /* reload shorty */
+    mov.b   @r2, r2             /* first byte specifyes return value type. */
+    mov.l   @(12,r14), r3       /* pReturn */
+
+    ## check return value types
+
+    mov     #'V', r4
+    cmp/eq  r4, r2
+    bt      end
+
+    mov     #'F', r4
+    cmp/eq  r4, r2
+    bt      jfloat_ret
+
+    mov     #'D', r4
+    cmp/eq  r4, r2
+    bt      jdouble_ret
+
+    mov     #'J', r4
+    cmp/eq  r4, r2
+    bt      jlong_ret
+
+    ## fall-through for other 32 bit java types.
+
+    ## load return values
+j32_ret:
+    bra     end
+    mov.l   r0, @r3             /* delay slot */
+
+jfloat_ret:
+    bra     end
+    fmov.s  fr0, @r3            /* delay slot */
+
+jdouble_ret:
+    fmov.s  fr1, @r3
+    mov     #4, r0
+    bra     end
+    fmov.s  fr0, @(r0,r3)       /* delay slot */
+
+jlong_ret:
+    mov.l   r0, @r3
+    bra     end
+    mov.l   r1, @(4,r3)         /* delay slot */
+
+end:
+    ## restore preserved registers
+    mov     r14, r15
+    add     #-16, r15
+    lds.l   @r15+, pr
+    mov.l   @r15+, r12
+    mov.l   @r15+, r13
+    mov.l   @r15+, r14
+
+    rts                         /* dvmPlatformInvoke returns void. */
+    nop
diff --git a/vm/arch/x86-atom/Call386ABI.S b/vm/arch/x86-atom/Call386ABI.S
new file mode 100644
index 0000000..f996168
--- /dev/null
+++ b/vm/arch/x86-atom/Call386ABI.S
@@ -0,0 +1,189 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: CallABI.S
+    *
+    * Code: facilitates call to native code C and C++ routines.
+    *
+    */
+
+   /*
+    * Function prototype:
+    *
+    * void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
+    * const u4* argv, const char* signature, void* func, JValue* pReturn)
+    *
+    * The method we are calling has the form:
+    *
+    * return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
+    * -or-
+    * return_type func(JNIEnv* pEnv, Object* this, ...)
+    *
+    * We receive a collection of 32-bit values which correspond to arguments from
+    * the interpreter (e.g. float occupies one, double occupies two).  It's up to
+    * us to convert these into local calling conventions.
+    */
+
+   /*
+    * On entry:
+    *   4(%sp)    JNIEnv (can be left alone)
+    *   8(%esp)   clazz (NULL for virtual method calls, non-NULL for static)
+    *   12(%esp)  arg info
+    *   16(%esp)  argc (number of 32-bit values in argv)
+    *   20(%esp)  argv
+    *   24(%esp)  short signature
+    *   28(%esp)  func
+    *   32(%esp)  pReturn
+    *
+    * For a virtual method call, the "this" reference is in argv[0].
+    *
+    * argInfo (32-bit int) layout:
+    *
+    *   SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+    *
+    *   S - if set, argInfo hints are invalid
+    *   R - return type enumeration (see jniInternal.h)
+    *       VOID   -> 0
+    *       FLOAT  -> 1
+    *       DOUBLE -> 2
+    *       S8     -> 3
+    *       S4     -> 4
+    *    H - target-specific hints (see below for details)
+    *
+    * IA32 ABI JNI hint format
+    *
+    *       ZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
+    *
+    *   Z - reserved
+    *   A - size of the variable argument block in 32-bit words
+    */
+
+    .text
+    .align  4
+    .global dvmPlatformInvoke
+    .type   dvmPlatformInvoke, %function
+
+
+dvmPlatformInvoke:
+CallABI_ENTER:
+
+   /*
+    * Save registers.
+    */
+
+    movl        %ebp, -4(%esp)
+    movl        %ebx, -8(%esp)          # save %ebx
+    movl        %esi, -12(%esp)         # save %esi
+    movl        %edi, -16(%esp)         # save %edi
+    lea         (%esp), %ebp
+
+   /*
+    * Check if argInfo is valid. Is always valid so should remove this check?
+    */
+
+    movzwl      12(%ebp), %ecx          # %ecx<- argsize in words
+    movl        12(%ebp), %ebx          # %ebx<- argInfo
+
+    shl         $2, %ecx                # %ecx<- argsize in bytes
+    subl        %ecx, %esp              # %esp<- expanded for arg region
+
+   /*
+    * Prepare for 16 byte alignment
+    */
+
+    and         $0xfffffff0, %esp
+    subl        $24, %esp
+
+
+    movl        8(%ebp), %eax           # %eax<- clazz
+    cmpl        $0, %eax                # Check virtual or static
+    movl        4(%ebp), %ecx           # %ecx<- JNIEnv
+    movl        20(%ebp), %esi          # %esi<- argV
+    jne         1f                      # Branch if static
+    movl        (%esi), %eax            # get the this pointer
+    addl        $4, %esi                # %esi<- update past this
+
+1:
+    movl        %ecx, -8(%esp)          # push JNIEnv as arg #1
+    movl        %eax, -4(%esp)          # push clazz or this as arg #2
+    lea         -8(%esp), %esp
+
+   /*
+    * Copy arguments
+    */
+
+    movzwl      %bx, %ecx               # %ecx<- %bx; argsize in words
+    lea         8(%esp), %edi           # %edi<- stack location for arguments
+    cld
+    rep         movsl                   # move %ecx arguments to 8(%esp)
+    call        *28(%ebp)
+    sarl        $28, %ebx               # %ebx<- SRRR (low 4 bits)
+    je          CallABI_EXIT            # exit call
+    cmpl        $2, %ebx
+    movl        32(%ebp), %ecx          # %ecx<- return pointer
+    je          2f                      # handle double return
+    jl          1f                      # handle float return
+
+   /*
+    *  If a native function returns a result smaller than 8-bytes
+    *  then higher bytes may contain garbage.
+    *  This code does type-checking based on size of return result.
+    *  We zero higher bytes instead of allowing the garbage to go through.
+    */
+
+    cmpl        $3,%ebx
+    je          S8
+    cmpl        $4,%ebx
+    je          S4
+    cmpl        $7,%ebx
+    je          S1
+    cmpl        $6,%ebx
+    jne         S2
+U2:
+    movzwl      %ax, %eax
+    movl        %eax, (%ecx)            # save 32-bit return
+    jmp         CallABI_EXIT            # exit call
+
+S1:
+    movsbl      %al, %eax
+    movl        %eax, (%ecx)            # save 32-bit return
+    jmp         CallABI_EXIT            # exit call
+S2:
+    movswl      %ax, %eax
+    movl        %eax, (%ecx)            # save 32-bit return
+    jmp         CallABI_EXIT            # exit call
+S4:
+    cltd
+    movl        %eax, (%ecx)            # save 32-bit return
+    jmp         CallABI_EXIT            # exit call
+S8:
+    movl        %edx, 4(%ecx)           # save 64-bit return
+    movl        %eax, (%ecx)            # save 32-bit return
+    jmp         CallABI_EXIT            # exit call
+
+2:
+    fstpl       (%ecx)                  # save double return
+    jmp         CallABI_EXIT            # exit call
+1:
+    fstps       (%ecx)                  # save float return
+
+CallABI_EXIT:
+    lea         (%ebp), %esp
+    movl        -16(%ebp), %edi         # restore %edi
+    movl        -12(%ebp), %esi         # restore %esi
+    movl        -8(%ebp), %ebx          # restore %ebx
+    movl        -4(%ebp), %ebp          # restore caller base pointer
+    ret                                 # return
diff --git a/vm/arch/x86-atom/Hints386ABI.cpp b/vm/arch/x86-atom/Hints386ABI.cpp
new file mode 100644
index 0000000..dd2fc69
--- /dev/null
+++ b/vm/arch/x86-atom/Hints386ABI.cpp
@@ -0,0 +1,79 @@
+   /* 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 class loader will associate with each method a 32-bit info word
+    * (jniArgInfo) to support JNI calls.  The high order 4 bits of this word
+    * are the same for all targets, while the lower 28 are used for hints to
+    * allow accelerated JNI bridge transfers.
+    *
+    * jniArgInfo (32-bit int) layout:
+    *
+    *    SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+    *
+    *    S - if set, ignore the hints and do things the hard way (scan signature)
+    *    R - return-type enumeration
+    *    H - target-specific hints (see below for details)
+    *
+    * This function produces IA32-specific hints for the standard 32-bit 386 ABI.
+    * All arguments have 32-bit alignment.  Padding is not an issue.
+    *
+    * IA32 ABI JNI hint format
+    *
+    *       ZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
+    *
+    *   Z - reserved, must be 0
+    *   A - size of variable argument block in 32-bit words (note - does not
+    *       include JNIEnv or clazz)
+    *
+    * For the 386 ABI, valid hints should always be generated.
+    */
+
+
+#include "Dalvik.h"
+#include "libdex/DexClass.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+u4 dvmPlatformInvokeHints(const DexProto* proto)  {
+
+const char* sig = dexProtoGetShorty(proto);
+unsigned int wordCount = 0;
+char sigByte;
+
+ while (1) {
+
+   /*
+    * Move past return type; dereference sigByte
+    */
+
+    sigByte = *(++sig);
+    if (sigByte == '\0') { break; }
+    ++wordCount;
+
+    if (sigByte == 'D' || sigByte == 'J') {
+      ++wordCount;
+    }
+ }
+
+/*
+ * Check for Dex file limitation and return
+ */
+
+ if (wordCount > 0xFFFF) { return DALVIK_JNI_NO_ARG_INFO; }
+ return wordCount;
+
+}
diff --git a/vm/arch/x86/Call386ABI.S b/vm/arch/x86/Call386ABI.S
new file mode 100644
index 0000000..39a0e93
--- /dev/null
+++ b/vm/arch/x86/Call386ABI.S
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+/*
+ * JNI method invocation.  This is used to call a C/C++ JNI method.  The
+ * argument list has to be pushed onto the native stack according to
+ * local calling conventions.
+ *
+ * This version supports 32-bit x86
+ */
+
+/*
+Function prototype:
+
+void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
+    const u4* argv, const char* signature, void* func, JValue* pReturn)
+
+The method we are calling has the form:
+
+  return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
+    -or-
+  return_type func(JNIEnv* pEnv, Object* this, ...)
+
+We receive a collection of 32-bit values which correspond to arguments from
+the interpreter (e.g. float occupies one, double occupies two).  It's up to
+us to convert these into local calling conventions.
+*/
+
+/*
+x86 notes:
+
+The native code expects arguments on the stack, pushed from right to left.
+This matches what Dalvik is passing here.
+
+EAX, EDX and ECX are scratch.
+
+4-byte alignment is required for long long and double, so we won't pad
+
+Non-FP return types <= 4 bytes come back in EAX
+Non-FP return types of 8 bytes come back in EAX:EDX, with lsw in EAX.
+Float and double returned on top of FP stack.
+
+*/
+
+    .text
+    .global dvmPlatformInvoke
+    .type   dvmPlatformInvoke, @function
+
+/*
+ * On entry:
+ *  [ 8]  arg0  JNIEnv (can be left alone)
+ *  [12]  arg1  clazz (NULL for virtual method calls, non-NULL for static)
+ *  [16]  arg2  arg info
+ *  [20]  arg3  argc
+ *  [24]  arg4  argv
+ *  [28]  arg5  short signature
+ *  [32]  arg6  func
+ *  [36]  arg7  pReturn
+ *
+ * For a virtual method call, the "this" reference is in argv[0].
+ *
+ * argInfo (32-bit int) layout:
+ *   SRRRZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
+ *
+ *   Z - reserved
+ *   S - if set, argInfo hints are invalid
+ *   R - return type enumeration (see jniInternal.h)
+ *       VOID   -> 0
+ *       FLOAT  -> 1
+ *       DOUBLE -> 2
+ *       S8     -> 3
+ *       S4     -> 4
+ *   A - size of the variable argument block in 32-bit words
+ *
+ */
+dvmPlatformInvoke:
+/* Establish the frame pointer, spill & align to 16b */
+    pushl    %ebp
+    movl     %esp,%ebp
+    pushl    %edi
+    pushl    %esi
+    pushl    %ebx
+    subl     $12,%esp
+/* For 386 ABI, argInfo hints should always be valid.  Abort if not. */
+    movl     16(%ebp),%ebx
+    testl    %ebx,%ebx
+    js       dvmAbort
+/*
+ * Get the size of the variable region, add two more slots for the first
+ * two arguments and grow (preserving alignment)
+ */
+    movl     %ebx,%ecx
+    leal     20(,%ecx,4),%ecx
+    andl     $0x0003FFF0,%ecx
+    subl     %ecx,%esp
+/* Handle this/class */
+    movl     8(%ebp),%ecx
+    movl     12(%ebp),%eax
+    movl     24(%ebp),%esi
+    testl    %eax,%eax
+    jne      isClass
+    movl     (%esi),%eax
+    addl     $4,%esi
+isClass:
+    movl     %eax,4(%esp)
+    movl     %ecx,0(%esp)
+/* Now, copy the variable arguments region */
+    movl     %ebx,%ecx
+    andl     $0x0000FFFF,%ecx
+    leal     8(%esp),%edi
+    cld
+    rep
+    movsd
+/* Ready to go - call the native code */
+    call     *32(%ebp)
+/* Store the result. */
+    sarl      $28,%ebx
+    /* Is void? */
+    testl     %ebx,%ebx
+    je       cleanUpAndExit
+    movl     36(%ebp),%ecx
+    /* Is FP? */
+    cmpl     $2,%ebx
+    jle      isFP
+    cmpl     $4,%ebx  /* smaller than 32-bits? */
+    jg       isSmall
+storeRetval:
+    /* Blindly storing 64-bits won't hurt 32-bit case */
+    movl     %eax,(%ecx)
+    movl     %edx,4(%ecx)
+    jmp      cleanUpAndExit
+isSmall:
+    cmpl     $7,%ebx  /* S1? */
+    jne      checkShort
+    movsbl   %al,%eax
+    movl     %eax,(%ecx)
+    jmp      cleanUpAndExit
+checkShort:
+    cmpl     $6,%ebx  /* U2? */
+    jne      isSignedShort
+    movzwl   %ax,%eax
+    movl     %eax,(%ecx)
+    jmp      cleanUpAndExit
+isSignedShort:
+    /* Must be S2 */
+    movswl   %ax,%eax
+    movl     %eax,(%ecx)
+    jmp      cleanUpAndExit
+isFP:
+    /* Is Float? */
+    cmpl    $1,%ebx
+    je       saveFloat
+    fstpl    (%ecx)
+    jmp      cleanUpAndExit
+saveFloat:
+    fstps    (%ecx)
+cleanUpAndExit:
+    leal     -12(%ebp),%esp
+    pop      %ebx
+    pop      %esi
+    pop      %edi
+    pop      %ebp
+    ret
+    .size    dvmPlatformInvoke, .-dvmPlatformInvoke
+    .section .note.GNU-stack,"",@progbits
diff --git a/vm/arch/x86/Hints386ABI.cpp b/vm/arch/x86/Hints386ABI.cpp
new file mode 100644
index 0000000..2a0a1d8
--- /dev/null
+++ b/vm/arch/x86/Hints386ABI.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+/*
+ * Target-specific optimization and run-time hints
+ */
+
+
+#include "Dalvik.h"
+#include "libdex/DexClass.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+
+/*
+ * The class loader will associate with each method a 32-bit info word
+ * (jniArgInfo) to support JNI calls.  The high order 4 bits of this word
+ * are the same for all targets, while the lower 28 are used for hints to
+ * allow accelerated JNI bridge transfers.
+ *
+ * jniArgInfo (32-bit int) layout:
+ *
+ *    SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+ *
+ *    S - if set, ignore the hints and do things the hard way (scan signature)
+ *    R - return-type enumeration
+ *    H - target-specific hints (see below for details)
+ *
+ * This function produces x86-specific hints for the standard 32-bit 386 ABI.
+ * Note that the JNI requirements are very close to the 386 runtime model.  In
+ * particular, natural datatype alignments do not apply to passed arguments.
+ * All arguments have 32-bit alignment.  As a result, we don't have to worry
+ * about padding - just total size.  The only tricky bit is that floating point
+ * return values come back on the FP stack.
+ *
+ *
+ * 386 ABI JNI hint format
+ *
+ *       ZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
+ *
+ *   Z - reserved, must be 0
+ *   A - size of variable argument block in 32-bit words (note - does not
+ *       include JNIEnv or clazz)
+ *
+ * For the 386 ABI, valid hints should always be generated.
+ */
+u4 dvmPlatformInvokeHints( const DexProto* proto)
+{
+    const char* sig = dexProtoGetShorty(proto);
+    unsigned int jniHints, wordCount;
+    char sigByte;
+
+    wordCount = 0;
+    while (true) {
+        sigByte = *(sig++);
+
+        if (sigByte == '\0')
+            break;
+
+        wordCount++;
+
+        if (sigByte == 'D' || sigByte == 'J') {
+            wordCount++;
+        }
+    }
+
+    if (wordCount > 0xFFFF) {
+        /* Invalid - Dex file limitation */
+        jniHints = DALVIK_JNI_NO_ARG_INFO;
+    } else {
+        jniHints = wordCount;
+    }
+
+    return jniHints;
+}
diff --git a/vm/compiler/Compiler.cpp b/vm/compiler/Compiler.cpp
new file mode 100644
index 0000000..c08d42d
--- /dev/null
+++ b/vm/compiler/Compiler.cpp
@@ -0,0 +1,857 @@
+/*
+ * 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 <cutils/ashmem.h>
+
+#include "Dalvik.h"
+#include "interp/Jit.h"
+#include "CompilerInternals.h"
+
+extern "C" void dvmCompilerTemplateStart(void);
+extern "C" void dmvCompilerTemplateEnd(void);
+
+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--;
+    if (gDvmJit.compilerQueueLength == 0) {
+        dvmSignalCond(&gDvmJit.compilerQueueEmpty);
+    }
+
+    /* Remember the high water mark of the queue length */
+    if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
+        gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
+
+    return work;
+}
+
+/*
+ * Enqueue a work order - retrying until successful.  If attempt to enqueue
+ * is repeatedly unsuccessful, assume the JIT is in a bad state and force a
+ * code cache reset.
+ */
+#define ENQUEUE_MAX_RETRIES 20
+void dvmCompilerForceWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
+{
+    bool success;
+    int retries = 0;
+    do {
+        success = dvmCompilerWorkEnqueue(pc, kind, info);
+        if (!success) {
+            retries++;
+            if (retries > ENQUEUE_MAX_RETRIES) {
+                LOGE("JIT: compiler queue wedged - forcing reset");
+                gDvmJit.codeCacheFull = true;  // Force reset
+                success = true;  // Because we'll drop the order now anyway
+            } else {
+                dvmLockMutex(&gDvmJit.compilerLock);
+                pthread_cond_wait(&gDvmJit.compilerQueueActivity,
+                                  &gDvmJit.compilerLock);
+                dvmUnlockMutex(&gDvmJit.compilerLock);
+
+            }
+        }
+    } while (!success);
+}
+
+/*
+ * Attempt to enqueue a work order, returning true if successful.
+ *
+ * NOTE: Make sure that the caller frees the info pointer if the return value
+ * is false.
+ */
+bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
+{
+    int cc;
+    int i;
+    int numWork;
+    bool result = true;
+
+    dvmLockMutex(&gDvmJit.compilerLock);
+
+    /*
+     * Return if queue or code cache is 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) {
+            dvmUnlockMutex(&gDvmJit.compilerLock);
+            return true;
+        }
+        /* Wrap around */
+        if (i == COMPILER_WORK_QUEUE_SIZE)
+            i = 0;
+    }
+
+    CompilerWorkOrder *newOrder =
+        &gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex];
+    newOrder->pc = pc;
+    newOrder->kind = kind;
+    newOrder->info = info;
+    newOrder->result.methodCompilationAborted = NULL;
+    newOrder->result.codeAddress = NULL;
+    newOrder->result.discardResult =
+        (kind == kWorkOrderTraceDebug) ? true : false;
+    newOrder->result.cacheVersion = gDvmJit.cacheVersion;
+    newOrder->result.requestingThread = dvmThreadSelf();
+
+    gDvmJit.compilerWorkEnqueueIndex++;
+    if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
+        gDvmJit.compilerWorkEnqueueIndex = 0;
+    gDvmJit.compilerQueueLength++;
+    cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
+    assert(cc == 0);
+
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+    return result;
+}
+
+/* Block until the queue length is 0, or there is a pending suspend request */
+void dvmCompilerDrainQueue(void)
+{
+    Thread *self = dvmThreadSelf();
+
+    dvmLockMutex(&gDvmJit.compilerLock);
+    while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread &&
+           self->suspendCount == 0) {
+        /*
+         * Use timed wait here - more than one mutator threads may be blocked
+         * but the compiler thread will only signal once when the queue is
+         * emptied. Furthermore, the compiler thread may have been shutdown
+         * so the blocked thread may never get the wakeup signal.
+         */
+        dvmRelativeCondWait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock,                             1000, 0);
+    }
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+}
+
+bool dvmCompilerSetupCodeCache(void)
+{
+    int fd;
+
+    /* Allocate the code cache */
+    fd = ashmem_create_region("dalvik-jit-code-cache", gDvmJit.codeCacheSize);
+    if (fd < 0) {
+        LOGE("Could not create %u-byte ashmem region for the JIT code cache",
+             gDvmJit.codeCacheSize);
+        return false;
+    }
+    gDvmJit.codeCache = mmap(NULL, gDvmJit.codeCacheSize,
+                             PROT_READ | PROT_WRITE | PROT_EXEC,
+                             MAP_PRIVATE , fd, 0);
+    close(fd);
+    if (gDvmJit.codeCache == MAP_FAILED) {
+        LOGE("Failed to mmap the JIT code cache: %s", strerror(errno));
+        return false;
+    }
+
+    gDvmJit.pageSizeMask = getpagesize() - 1;
+
+    /* This can be found through "dalvik-jit-code-cache" in /proc/<pid>/maps */
+    // LOGD("Code cache starts at %p", gDvmJit.codeCache);
+
+    /* 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);
+
+    /*
+     * Work around a CPU bug by keeping the 32-bit ARM handler code in its own
+     * page.
+     */
+    if (dvmCompilerInstructionSet() == DALVIK_JIT_THUMB2) {
+        templateSize = (templateSize + 4095) & ~4095;
+    }
+
+    gDvmJit.templateSize = templateSize;
+    gDvmJit.codeCacheByteUsed = templateSize;
+
+    /* Only flush the part in the code cache that is being used now */
+    dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
+                          (intptr_t) gDvmJit.codeCache + templateSize, 0);
+
+    int result = mprotect(gDvmJit.codeCache, gDvmJit.codeCacheSize,
+                          PROTECT_CODE_CACHE_ATTRS);
+
+    if (result == -1) {
+        LOGE("Failed to remove the write permission for the code cache");
+        dvmAbort();
+    }
+
+    return true;
+}
+
+static void crawlDalvikStack(Thread *thread, bool print)
+{
+    void *fp = thread->interpSave.curFrame;
+    StackSaveArea* saveArea = NULL;
+    int stackLevel = 0;
+
+    if (print) {
+        LOGD("Crawling tid %d (%s / %p %s)", thread->systemTid,
+             dvmGetThreadStatusStr(thread->status),
+             thread->inJitCodeCache,
+             thread->inJitCodeCache ? "jit" : "interp");
+    }
+    /* Crawl the Dalvik stack frames to clear the returnAddr field */
+    while (fp != NULL) {
+        saveArea = SAVEAREA_FROM_FP(fp);
+
+        if (print) {
+            if (dvmIsBreakFrame((u4*)fp)) {
+                LOGD("  #%d: break frame (%p)",
+                     stackLevel, saveArea->returnAddr);
+            }
+            else {
+                LOGD("  #%d: %s.%s%s (%p)",
+                     stackLevel,
+                     saveArea->method->clazz->descriptor,
+                     saveArea->method->name,
+                     dvmIsNativeMethod(saveArea->method) ?
+                         " (native)" : "",
+                     saveArea->returnAddr);
+            }
+        }
+        stackLevel++;
+        saveArea->returnAddr = NULL;
+        assert(fp != saveArea->prevFrame);
+        fp = saveArea->prevFrame;
+    }
+    /* Make sure the stack is fully unwound to the bottom */
+    assert(saveArea == NULL ||
+           (u1 *) (saveArea+1) == thread->interpStackStart);
+}
+
+static void resetCodeCache(void)
+{
+    Thread* thread;
+    u8 startTime = dvmGetRelativeTimeUsec();
+    int inJit = 0;
+    int byteUsed = gDvmJit.codeCacheByteUsed;
+
+    /* If any thread is found stuck in the JIT state, don't reset the cache  */
+    dvmLockThreadList(NULL);
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        /*
+         * Crawl the stack to wipe out the returnAddr field so that
+         * 1) the soon-to-be-deleted code in the JIT cache won't be used
+         * 2) or the thread stuck in the JIT land will soon return
+         *    to the interpreter land
+         */
+        crawlDalvikStack(thread, false);
+        if (thread->inJitCodeCache) {
+            inJit++;
+        }
+        /* Cancel any ongoing trace selection */
+        dvmDisableSubMode(thread, kSubModeJitTraceBuild);
+    }
+    dvmUnlockThreadList();
+
+    if (inJit) {
+        LOGD("JIT code cache reset delayed (%d bytes %d/%d)",
+             gDvmJit.codeCacheByteUsed, gDvmJit.numCodeCacheReset,
+             ++gDvmJit.numCodeCacheResetDelayed);
+        return;
+    }
+
+    /* Lock the mutex to clean up the work queue */
+    dvmLockMutex(&gDvmJit.compilerLock);
+
+    /* Update the translation cache version */
+    gDvmJit.cacheVersion++;
+
+    /* Drain the work queue to free the work orders */
+    while (workQueueLength()) {
+        CompilerWorkOrder work = workDequeue();
+        free(work.info);
+    }
+
+    /* Reset the JitEntry table contents to the initial unpopulated state */
+    dvmJitResetTable();
+
+    UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+    /*
+     * Wipe out the code cache content to force immediate crashes if
+     * stale JIT'ed code is invoked.
+     */
+    memset((char *) gDvmJit.codeCache + gDvmJit.templateSize,
+           0,
+           gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
+    dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
+                          (intptr_t) gDvmJit.codeCache +
+                          gDvmJit.codeCacheByteUsed, 0);
+
+    PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+    /* Reset the current mark of used bytes to the end of template code */
+    gDvmJit.codeCacheByteUsed = gDvmJit.templateSize;
+    gDvmJit.numCompilations = 0;
+
+    /* Reset the work queue */
+    memset(gDvmJit.compilerWorkQueue, 0,
+           sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
+    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
+    gDvmJit.compilerQueueLength = 0;
+
+    /* Reset the IC patch work queue */
+    dvmLockMutex(&gDvmJit.compilerICPatchLock);
+    gDvmJit.compilerICPatchIndex = 0;
+    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+
+    /*
+     * Reset the inflight compilation address (can only be done in safe points
+     * or by the compiler thread when its thread state is RUNNING).
+     */
+    gDvmJit.inflightBaseAddr = NULL;
+
+    /* All clear now */
+    gDvmJit.codeCacheFull = false;
+
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
+    LOGD("JIT code cache reset in %lld ms (%d bytes %d/%d)",
+         (dvmGetRelativeTimeUsec() - startTime) / 1000,
+         byteUsed, ++gDvmJit.numCodeCacheReset,
+         gDvmJit.numCodeCacheResetDelayed);
+}
+
+/*
+ * Perform actions that are only safe when all threads are suspended. Currently
+ * we do:
+ * 1) Check if the code cache is full. If so reset it and restart populating it
+ *    from scratch.
+ * 2) Patch predicted chaining cells by consuming recorded work orders.
+ */
+void dvmCompilerPerformSafePointChecks(void)
+{
+    if (gDvmJit.codeCacheFull) {
+        resetCodeCache();
+    }
+    dvmCompilerPatchInlineCache();
+}
+
+static bool compilerThreadStartup(void)
+{
+    JitEntry *pJitTable = NULL;
+    unsigned char *pJitProfTable = NULL;
+    JitTraceProfCounters *pJitTraceProfCounters = NULL;
+    unsigned int i;
+
+    if (!dvmCompilerArchInit())
+        goto fail;
+
+    /*
+     * Setup the code cache if we have not inherited a valid code cache
+     * from the zygote.
+     */
+    if (gDvmJit.codeCache == NULL) {
+        if (!dvmCompilerSetupCodeCache())
+            goto fail;
+    }
+
+    /* Allocate the initial arena block */
+    if (dvmCompilerHeapInit() == false) {
+        goto fail;
+    }
+
+    /* Cache the thread pointer */
+    gDvmJit.compilerThread = dvmThreadSelf();
+
+    dvmLockMutex(&gDvmJit.compilerLock);
+
+    /* Track method-level compilation statistics */
+    gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
+
+#if defined(WITH_JIT_TUNING)
+    gDvm.verboseShutdown = true;
+#endif
+
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
+    /* Set up the JitTable */
+
+    /* Power of 2? */
+    assert(gDvmJit.jitTableSize &&
+           !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
+
+    dvmInitMutex(&gDvmJit.tableLock);
+    dvmLockMutex(&gDvmJit.tableLock);
+    pJitTable = (JitEntry*)
+                calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
+    if (!pJitTable) {
+        LOGE("jit table allocation failed");
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        goto fail;
+    }
+    /*
+     * 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 synchronized 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");
+        free(pJitProfTable);
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        goto fail;
+    }
+    memset(pJitProfTable, gDvmJit.threshold, JIT_PROF_SIZE);
+    for (i=0; i < gDvmJit.jitTableSize; i++) {
+       pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
+    }
+    /* Is chain field wide enough for termination pattern? */
+    assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
+
+    /* Allocate the trace profiling structure */
+    pJitTraceProfCounters = (JitTraceProfCounters*)
+                             calloc(1, sizeof(*pJitTraceProfCounters));
+    if (!pJitTraceProfCounters) {
+        LOGE("jit trace prof counters allocation failed");
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        goto fail;
+    }
+
+    gDvmJit.pJitEntryTable = pJitTable;
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.jitTableEntriesUsed = 0;
+    gDvmJit.compilerHighWater =
+        COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
+    /*
+     * If the VM is launched with wait-on-the-debugger, we will need to hide
+     * the profile table here
+     */
+    gDvmJit.pProfTable = dvmDebuggerOrProfilerActive() ? NULL : pJitProfTable;
+    gDvmJit.pProfTableCopy = pJitProfTable;
+    gDvmJit.pJitTraceProfCounters = pJitTraceProfCounters;
+    dvmJitUpdateThreadStateAll();
+    dvmUnlockMutex(&gDvmJit.tableLock);
+
+    /* Signal running threads to refresh their cached pJitTable pointers */
+    dvmSuspendAllThreads(SUSPEND_FOR_REFRESH);
+    dvmResumeAllThreads(SUSPEND_FOR_REFRESH);
+
+    /* Enable signature breakpoints by customizing the following code */
+#if defined(SIGNATURE_BREAKPOINT)
+    /*
+     * Suppose one sees the following native crash in the bugreport:
+     * I/DEBUG   ( 1638): Build fingerprint: 'unknown'
+     * I/DEBUG   ( 1638): pid: 2468, tid: 2507  >>> com.google.android.gallery3d
+     * I/DEBUG   ( 1638): signal 11 (SIGSEGV), fault addr 00001400
+     * I/DEBUG   ( 1638):  r0 44ea7190  r1 44e4f7b8  r2 44ebc710  r3 00000000
+     * I/DEBUG   ( 1638):  r4 00000a00  r5 41862dec  r6 4710dc10  r7 00000280
+     * I/DEBUG   ( 1638):  r8 ad010f40  r9 46a37a12  10 001116b0  fp 42a78208
+     * I/DEBUG   ( 1638):  ip 00000090  sp 4710dbc8  lr ad060e67  pc 46b90682
+     * cpsr 00000030
+     * I/DEBUG   ( 1638):  #00  pc 46b90682 /dev/ashmem/dalvik-jit-code-cache
+     * I/DEBUG   ( 1638):  #01  pc 00060e62  /system/lib/libdvm.so
+     *
+     * I/DEBUG   ( 1638): code around pc:
+     * I/DEBUG   ( 1638): 46b90660 6888d01c 34091dcc d2174287 4a186b68
+     * I/DEBUG   ( 1638): 46b90670 d0052800 68006809 28004790 6b68d00e
+     * I/DEBUG   ( 1638): 46b90680 512000bc 37016eaf 6ea866af 6f696028
+     * I/DEBUG   ( 1638): 46b90690 682a6069 429a686b e003da08 6df1480b
+     * I/DEBUG   ( 1638): 46b906a0 1c2d4788 47806d70 46a378fa 47806d70
+     *
+     * Clearly it is a JIT bug. To find out which translation contains the
+     * offending code, the content of the memory dump around the faulting PC
+     * can be pasted into the gDvmJit.signatureBreakpoint[] array and next time
+     * when a similar compilation is being created, the JIT compiler replay the
+     * trace in the verbose mode and one can investigate the instruction
+     * sequence in details.
+     *
+     * The length of the signature may need additional experiments to determine.
+     * The rule of thumb is don't include PC-relative instructions in the
+     * signature since it may be affected by the alignment of the compiled code.
+     * However, a signature that's too short might increase the chance of false
+     * positive matches. Using gdbjithelper to disassembly the memory content
+     * first might be a good companion approach.
+     *
+     * For example, if the next 4 words starting from 46b90680 is pasted into
+     * the data structure:
+     */
+
+    gDvmJit.signatureBreakpointSize = 4;
+    gDvmJit.signatureBreakpoint =
+        malloc(sizeof(u4) * gDvmJit.signatureBreakpointSize);
+    gDvmJit.signatureBreakpoint[0] = 0x512000bc;
+    gDvmJit.signatureBreakpoint[1] = 0x37016eaf;
+    gDvmJit.signatureBreakpoint[2] = 0x6ea866af;
+    gDvmJit.signatureBreakpoint[3] = 0x6f696028;
+
+    /*
+     * The following log will be printed when a match is found in subsequent
+     * testings:
+     *
+     * D/dalvikvm( 2468): Signature match starting from offset 0x34 (4 words)
+     * D/dalvikvm( 2468): --------
+     * D/dalvikvm( 2468): Compiler: Building trace for computeVisibleItems,
+     * offset 0x1f7
+     * D/dalvikvm( 2468): 0x46a37a12: 0x0090 add-int v42, v5, v26
+     * D/dalvikvm( 2468): 0x46a37a16: 0x004d aput-object v13, v14, v42
+     * D/dalvikvm( 2468): 0x46a37a1a: 0x0028 goto, (#0), (#0)
+     * D/dalvikvm( 2468): 0x46a3794e: 0x00d8 add-int/lit8 v26, v26, (#1)
+     * D/dalvikvm( 2468): 0x46a37952: 0x0028 goto, (#0), (#0)
+     * D/dalvikvm( 2468): 0x46a378ee: 0x0002 move/from16 v0, v26, (#0)
+     * D/dalvikvm( 2468): 0x46a378f2: 0x0002 move/from16 v1, v29, (#0)
+     * D/dalvikvm( 2468): 0x46a378f6: 0x0035 if-ge v0, v1, (#10)
+     * D/dalvikvm( 2468): TRACEINFO (554): 0x46a37624
+     * Lcom/cooliris/media/GridLayer;computeVisibleItems 0x1f7 14 of 934, 8
+     * blocks
+     *     :
+     *     :
+     * D/dalvikvm( 2468): 0x20 (0020): ldr     r0, [r5, #52]
+     * D/dalvikvm( 2468): 0x22 (0022): ldr     r2, [pc, #96]
+     * D/dalvikvm( 2468): 0x24 (0024): cmp     r0, #0
+     * D/dalvikvm( 2468): 0x26 (0026): beq     0x00000034
+     * D/dalvikvm( 2468): 0x28 (0028): ldr     r1, [r1, #0]
+     * D/dalvikvm( 2468): 0x2a (002a): ldr     r0, [r0, #0]
+     * D/dalvikvm( 2468): 0x2c (002c): blx     r2
+     * D/dalvikvm( 2468): 0x2e (002e): cmp     r0, #0
+     * D/dalvikvm( 2468): 0x30 (0030): beq     0x00000050
+     * D/dalvikvm( 2468): 0x32 (0032): ldr     r0, [r5, #52]
+     * D/dalvikvm( 2468): 0x34 (0034): lsls    r4, r7, #2
+     * D/dalvikvm( 2468): 0x36 (0036): str     r0, [r4, r4]
+     * D/dalvikvm( 2468): -------- dalvik offset: 0x01fb @ goto, (#0), (#0)
+     * D/dalvikvm( 2468): L0x0195:
+     * D/dalvikvm( 2468): -------- dalvik offset: 0x0195 @ add-int/lit8 v26,
+     * v26, (#1)
+     * D/dalvikvm( 2468): 0x38 (0038): ldr     r7, [r5, #104]
+     * D/dalvikvm( 2468): 0x3a (003a): adds    r7, r7, #1
+     * D/dalvikvm( 2468): 0x3c (003c): str     r7, [r5, #104]
+     * D/dalvikvm( 2468): -------- dalvik offset: 0x0197 @ goto, (#0), (#0)
+     * D/dalvikvm( 2468): L0x0165:
+     * D/dalvikvm( 2468): -------- dalvik offset: 0x0165 @ move/from16 v0, v26,
+     * (#0)
+     * D/dalvikvm( 2468): 0x3e (003e): ldr     r0, [r5, #104]
+     * D/dalvikvm( 2468): 0x40 (0040): str     r0, [r5, #0]
+     *
+     * The "str r0, [r4, r4]" is indeed the culprit of the native crash.
+     */
+#endif
+
+    return true;
+
+fail:
+    return false;
+
+}
+
+static void *compilerThreadStart(void *arg)
+{
+    dvmChangeStatus(NULL, THREAD_VMWAIT);
+
+    /*
+     * If we're not running stand-alone, wait a little before
+     * recieving translation requests on the assumption that process start
+     * up code isn't worth compiling.  We'll resume when the framework
+     * signals us that the first screen draw has happened, or the timer
+     * below expires (to catch daemons).
+     *
+     * There is a theoretical race between the callback to
+     * VMRuntime.startJitCompiation and when the compiler thread reaches this
+     * point. In case the callback happens earlier, in order not to permanently
+     * hold the system_server (which is not using the timed wait) in
+     * interpreter-only mode we bypass the delay here.
+     */
+    if (gDvmJit.runningInAndroidFramework &&
+        !gDvmJit.alreadyEnabledViaFramework) {
+        /*
+         * If the current VM instance is the system server (detected by having
+         * 0 in gDvm.systemServerPid), we will use the indefinite wait on the
+         * conditional variable to determine whether to start the JIT or not.
+         * If the system server detects that the whole system is booted in
+         * safe mode, the conditional variable will never be signaled and the
+         * system server will remain in the interpreter-only mode. All
+         * subsequent apps will be started with the --enable-safemode flag
+         * explicitly appended.
+         */
+        if (gDvm.systemServerPid == 0) {
+            dvmLockMutex(&gDvmJit.compilerLock);
+            pthread_cond_wait(&gDvmJit.compilerQueueActivity,
+                              &gDvmJit.compilerLock);
+            dvmUnlockMutex(&gDvmJit.compilerLock);
+            LOGD("JIT started for system_server");
+        } else {
+            dvmLockMutex(&gDvmJit.compilerLock);
+            /*
+             * TUNING: experiment with the delay & perhaps make it
+             * target-specific
+             */
+            dvmRelativeCondWait(&gDvmJit.compilerQueueActivity,
+                                 &gDvmJit.compilerLock, 3000, 0);
+            dvmUnlockMutex(&gDvmJit.compilerLock);
+        }
+        if (gDvmJit.haltCompilerThread) {
+             return NULL;
+        }
+    }
+
+    compilerThreadStartup();
+
+    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.
+     */
+    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 {
+                CompilerWorkOrder work = workDequeue();
+                dvmUnlockMutex(&gDvmJit.compilerLock);
+#if defined(WITH_JIT_TUNING)
+                /*
+                 * This is live across setjmp().  Mark it volatile to suppress
+                 * a gcc warning.  We should not need this since it is assigned
+                 * only once but gcc is not smart enough.
+                 */
+                volatile u8 startTime = dvmGetRelativeTimeUsec();
+#endif
+                /*
+                 * Check whether there is a suspend request on me.  This
+                 * is necessary to allow a clean shutdown.
+                 *
+                 * However, in the blocking stress testing mode, let the
+                 * compiler thread continue doing compilations to unblock
+                 * other requesting threads. This may occasionally cause
+                 * shutdown from proceeding cleanly in the standalone invocation
+                 * of the vm but this should be acceptable.
+                 */
+                if (!gDvmJit.blockingMode)
+                    dvmCheckSuspendPending(dvmThreadSelf());
+                /* Is JitTable filling up? */
+                if (gDvmJit.jitTableEntriesUsed >
+                    (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
+                    bool resizeFail =
+                        dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
+                    /*
+                     * If the jit table is full, consider it's time to reset
+                     * the code cache too.
+                     */
+                    gDvmJit.codeCacheFull |= resizeFail;
+                }
+                if (gDvmJit.haltCompilerThread) {
+                    LOGD("Compiler shutdown in progress - discarding request");
+                } else if (!gDvmJit.codeCacheFull) {
+                    jmp_buf jmpBuf;
+                    work.bailPtr = &jmpBuf;
+                    bool aborted = setjmp(jmpBuf);
+                    if (!aborted) {
+                        bool codeCompiled = dvmCompilerDoWork(&work);
+                        /*
+                         * Make sure we are still operating with the
+                         * same translation cache version.  See
+                         * Issue 4271784 for details.
+                         */
+                        dvmLockMutex(&gDvmJit.compilerLock);
+                        if ((work.result.cacheVersion ==
+                             gDvmJit.cacheVersion) &&
+                             codeCompiled &&
+                             !work.result.discardResult &&
+                             work.result.codeAddress) {
+                            dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
+                                              work.result.instructionSet,
+                                              false, /* not method entry */
+                                              work.result.profileCodeSize);
+                        }
+                        dvmUnlockMutex(&gDvmJit.compilerLock);
+                    }
+                    dvmCompilerArenaReset();
+                }
+                free(work.info);
+#if defined(WITH_JIT_TUNING)
+                gDvmJit.jitTime += dvmGetRelativeTimeUsec() - startTime;
+#endif
+                dvmLockMutex(&gDvmJit.compilerLock);
+            } while (workQueueLength() != 0);
+        }
+    }
+    pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
+    /*
+     * As part of detaching the thread we need to call into Java code to update
+     * the ThreadGroup, and we should not be in VMWAIT state while executing
+     * interpreted code.
+     */
+    dvmChangeStatus(NULL, THREAD_RUNNING);
+
+    if (gDvm.verboseShutdown)
+        LOGD("Compiler thread shutting down");
+    return NULL;
+}
+
+bool dvmCompilerStartup(void)
+{
+
+    dvmInitMutex(&gDvmJit.compilerLock);
+    dvmInitMutex(&gDvmJit.compilerICPatchLock);
+    dvmInitMutex(&gDvmJit.codeCacheProtectionLock);
+    dvmLockMutex(&gDvmJit.compilerLock);
+    pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
+    pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
+
+    /* Reset the work queue */
+    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
+    gDvmJit.compilerQueueLength = 0;
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
+    /*
+     * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
+     * the compiler thread, which will do the real initialization if and
+     * when it is signalled to do so.
+     */
+    return dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
+                                   compilerThreadStart, NULL);
+}
+
+void dvmCompilerShutdown(void)
+{
+    void *threadReturn;
+
+    /* Disable new translation requests */
+    gDvmJit.pProfTable = NULL;
+    gDvmJit.pProfTableCopy = NULL;
+    dvmJitUpdateThreadStateAll();
+
+    if (gDvm.verboseShutdown ||
+            gDvmJit.profileMode == kTraceProfilingContinuous) {
+        dvmCompilerDumpStats();
+        while (gDvmJit.compilerQueueLength)
+          sleep(5);
+    }
+
+    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");
+        else if (gDvm.verboseShutdown)
+            LOGD("Compiler thread has shut down");
+    }
+
+    /* Break loops within the translation cache */
+    dvmJitUnchainAll();
+
+    /*
+     * NOTE: our current implementatation doesn't allow for the compiler
+     * thread to be restarted after it exits here.  We aren't freeing
+     * the JitTable or the ProfTable because threads which still may be
+     * running or in the process of shutting down may hold references to
+     * them.
+     */
+}
+
+void dvmCompilerUpdateGlobalState()
+{
+    bool jitActive;
+    bool jitActivate;
+    bool needUnchain = false;
+
+    /*
+     * The tableLock might not be initialized yet by the compiler thread if
+     * debugger is attached from the very beginning of the VM launch. If
+     * pProfTableCopy is NULL, the lock is not initialized yet and we don't
+     * need to refresh anything either.
+     */
+    if (gDvmJit.pProfTableCopy == NULL) {
+        return;
+    }
+
+    /*
+     * On the first enabling of method tracing, switch the compiler
+     * into a mode that includes trace support for invokes and returns.
+     * If there are any existing translations, flush them.  NOTE:  we
+     * can't blindly flush the translation cache because this code
+     * may be executed before the compiler thread has finished
+     * initialization.
+     */
+    if ((gDvm.activeProfilers != 0) &&
+        !gDvmJit.methodTraceSupport) {
+        bool resetRequired;
+        /*
+         * compilerLock will prevent new compilations from being
+         * installed while we are working.
+         */
+        dvmLockMutex(&gDvmJit.compilerLock);
+        gDvmJit.cacheVersion++; // invalidate compilations in flight
+        gDvmJit.methodTraceSupport = true;
+        resetRequired = (gDvmJit.numCompilations != 0);
+        dvmUnlockMutex(&gDvmJit.compilerLock);
+        if (resetRequired) {
+            dvmSuspendAllThreads(SUSPEND_FOR_CC_RESET);
+            resetCodeCache();
+            dvmResumeAllThreads(SUSPEND_FOR_CC_RESET);
+        }
+    }
+
+    dvmLockMutex(&gDvmJit.tableLock);
+    jitActive = gDvmJit.pProfTable != NULL;
+    jitActivate = !dvmDebuggerOrProfilerActive();
+
+    if (jitActivate && !jitActive) {
+        gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
+    } else if (!jitActivate && jitActive) {
+        gDvmJit.pProfTable = NULL;
+        needUnchain = true;
+    }
+    dvmUnlockMutex(&gDvmJit.tableLock);
+    if (needUnchain)
+        dvmJitUnchainAll();
+    // Make sure all threads have current values
+    dvmJitUpdateThreadStateAll();
+}
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
new file mode 100644
index 0000000..fc23254
--- /dev/null
+++ b/vm/compiler/Compiler.h
@@ -0,0 +1,245 @@
+/*
+ * 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_H_
+#define DALVIK_VM_COMPILER_H_
+
+#include <setjmp.h>
+#include "Thread.h"
+
+/*
+ * Uncomment the following to enable JIT signature breakpoint
+ * #define SIGNATURE_BREAKPOINT
+ */
+
+#define COMPILER_WORK_QUEUE_SIZE        100
+#define COMPILER_IC_PATCH_QUEUE_SIZE    64
+
+/* Architectural-independent parameters for predicted chains */
+#define PREDICTED_CHAIN_CLAZZ_INIT       0
+#define PREDICTED_CHAIN_METHOD_INIT      0
+#define PREDICTED_CHAIN_COUNTER_INIT     0
+/* A fake value which will avoid initialization and won't match any class */
+#define PREDICTED_CHAIN_FAKE_CLAZZ       0xdeadc001
+/* Has to be positive */
+#define PREDICTED_CHAIN_COUNTER_AVOID    0x7fffffff
+/* Rechain after this many misses - shared globally and has to be positive */
+#define PREDICTED_CHAIN_COUNTER_RECHAIN  8192
+
+#define COMPILER_TRACED(X)
+#define COMPILER_TRACEE(X)
+#define COMPILER_TRACE_CHAINING(X)
+
+/* Macro to change the permissions applied to a chunk of the code cache */
+#define PROTECT_CODE_CACHE_ATTRS       (PROT_READ | PROT_EXEC)
+#define UNPROTECT_CODE_CACHE_ATTRS     (PROT_READ | PROT_EXEC | PROT_WRITE)
+
+/* Acquire the lock before removing PROT_WRITE from the specified mem region */
+#define UNPROTECT_CODE_CACHE(addr, size)                                       \
+    {                                                                          \
+        dvmLockMutex(&gDvmJit.codeCacheProtectionLock);                        \
+        mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask),       \
+                 (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask),        \
+                 (UNPROTECT_CODE_CACHE_ATTRS));                                \
+    }
+
+/* Add the PROT_WRITE to the specified memory region then release the lock */
+#define PROTECT_CODE_CACHE(addr, size)                                         \
+    {                                                                          \
+        mprotect((void *) (((intptr_t) (addr)) & ~gDvmJit.pageSizeMask),       \
+                 (size) + (((intptr_t) (addr)) & gDvmJit.pageSizeMask),        \
+                 (PROTECT_CODE_CACHE_ATTRS));                                  \
+        dvmUnlockMutex(&gDvmJit.codeCacheProtectionLock);                      \
+    }
+
+#define SINGLE_STEP_OP(opcode)                                                 \
+    (gDvmJit.includeSelectedOp !=                                              \
+     ((gDvmJit.opList[opcode >> 3] & (1 << (opcode & 0x7))) != 0))
+
+typedef enum JitInstructionSetType {
+    DALVIK_JIT_NONE = 0,
+    DALVIK_JIT_ARM,
+    DALVIK_JIT_THUMB,
+    DALVIK_JIT_THUMB2,
+    DALVIK_JIT_IA32
+} JitInstructionSetType;
+
+/* Description of a compiled trace. */
+typedef struct JitTranslationInfo {
+    void *codeAddress;
+    JitInstructionSetType instructionSet;
+    int profileCodeSize;
+    bool discardResult;         // Used for debugging divergence and IC patching
+    bool methodCompilationAborted;  // Cannot compile the whole method
+    Thread *requestingThread;   // For debugging purpose
+    int cacheVersion;           // Used to identify stale trace requests
+} JitTranslationInfo;
+
+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)
+    kWorkOrderTraceDebug = 3,   // Work is to compile/debug code fragment(s)
+    kWorkOrderProfileMode = 4,  // Change profiling mode
+} WorkOrderKind;
+
+typedef struct CompilerWorkOrder {
+    const u2* pc;
+    WorkOrderKind kind;
+    void* info;
+    JitTranslationInfo result;
+    jmp_buf *bailPtr;
+} CompilerWorkOrder;
+
+/* Chain cell for predicted method invocation */
+typedef struct PredictedChainingCell {
+    u4 branch;                  /* Branch to chained destination */
+    const ClassObject *clazz;   /* key for prediction */
+    const Method *method;       /* to lookup native PC from dalvik PC */
+    const ClassObject *stagedClazz;   /* possible next key for prediction */
+} PredictedChainingCell;
+
+/* Work order for inline cache patching */
+typedef struct ICPatchWorkOrder {
+    PredictedChainingCell *cellAddr;    /* Address to be patched */
+    PredictedChainingCell cellContent;  /* content of the new cell */
+    const char *classDescriptor;        /* Descriptor of the class object */
+    Object *classLoader;                /* Class loader */
+    u4 serialNumber;                    /* Serial # (for verification only) */
+} ICPatchWorkOrder;
+
+/*
+ * 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[0];       // Variable-length trace descriptors
+} JitTraceDescription;
+
+typedef enum JitMethodAttributes {
+    kIsCallee = 0,      /* Code is part of a callee (invoked by a hot trace) */
+    kIsHot,             /* Code is part of a hot trace */
+    kIsLeaf,            /* Method is leaf */
+    kIsEmpty,           /* Method is empty */
+    kIsThrowFree,       /* Method doesn't throw */
+    kIsGetter,          /* Method fits the getter pattern */
+    kIsSetter,          /* Method fits the setter pattern */
+    kCannotCompile,     /* Method cannot be compiled */
+} JitMethodAttributes;
+
+#define METHOD_IS_CALLEE        (1 << kIsCallee)
+#define METHOD_IS_HOT           (1 << kIsHot)
+#define METHOD_IS_LEAF          (1 << kIsLeaf)
+#define METHOD_IS_EMPTY         (1 << kIsEmpty)
+#define METHOD_IS_THROW_FREE    (1 << kIsThrowFree)
+#define METHOD_IS_GETTER        (1 << kIsGetter)
+#define METHOD_IS_SETTER        (1 << kIsSetter)
+#define METHOD_CANNOT_COMPILE   (1 << kCannotCompile)
+
+/* Vectors to provide optimization hints */
+typedef enum JitOptimizationHints {
+    kJitOptNoLoop = 0,          // Disable loop formation/optimization
+} JitOptimizationHints;
+
+#define JIT_OPT_NO_LOOP         (1 << kJitOptNoLoop)
+
+/* Customized node traversal orders for different needs */
+typedef enum DataFlowAnalysisMode {
+    kAllNodes = 0,              // All nodes
+    kReachableNodes,            // All reachable nodes
+    kPreOrderDFSTraversal,      // Depth-First-Search / Pre-Order
+    kPostOrderDFSTraversal,     // Depth-First-Search / Post-Order
+    kPostOrderDOMTraversal,     // Dominator tree / Post-Order
+} DataFlowAnalysisMode;
+
+typedef struct CompilerMethodStats {
+    const Method *method;       // Used as hash entry signature
+    int dalvikSize;             // # of bytes for dalvik bytecodes
+    int compiledDalvikSize;     // # of compiled dalvik bytecodes
+    int nativeSize;             // # of bytes for produced native code
+    int attributes;             // attribute vector
+} CompilerMethodStats;
+
+struct CompilationUnit;
+struct BasicBlock;
+struct SSARepresentation;
+struct GrowableList;
+struct JitEntry;
+struct MIR;
+
+bool dvmCompilerSetupCodeCache(void);
+bool dvmCompilerArchInit(void);
+void dvmCompilerArchDump(void);
+bool dvmCompilerStartup(void);
+void dvmCompilerShutdown(void);
+void dvmCompilerForceWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
+bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
+void *dvmCheckCodeCache(void *method);
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+                                                  bool isCallee);
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+                                          const DecodedInstruction *insn);
+bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
+bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
+                     JitTranslationInfo *info, jmp_buf *bailPtr, int optHints);
+void dvmCompilerDumpStats(void);
+void dvmCompilerDrainQueue(void);
+void dvmJitUnchainAll(void);
+void dvmJitScanAllClassPointers(void (*callback)(void *ptr));
+void dvmCompilerSortAndPrintTraceProfiles(void);
+void dvmCompilerPerformSafePointChecks(void);
+void dvmCompilerInlineMIR(struct CompilationUnit *cUnit,
+                          JitTranslationInfo *info);
+void dvmInitializeSSAConversion(struct CompilationUnit *cUnit);
+int dvmConvertSSARegToDalvik(const struct CompilationUnit *cUnit, int ssaReg);
+bool dvmCompilerLoopOpt(struct CompilationUnit *cUnit);
+void dvmCompilerInsertBackwardChaining(struct CompilationUnit *cUnit);
+void dvmCompilerNonLoopAnalysis(struct CompilationUnit *cUnit);
+bool dvmCompilerFindLocalLiveIn(struct CompilationUnit *cUnit,
+                                struct BasicBlock *bb);
+bool dvmCompilerDoSSAConversion(struct CompilationUnit *cUnit,
+                                struct BasicBlock *bb);
+bool dvmCompilerDoConstantPropagation(struct CompilationUnit *cUnit,
+                                      struct BasicBlock *bb);
+bool dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
+                                       struct BasicBlock *bb);
+/* Clear the visited flag for each BB */
+bool dvmCompilerClearVisitedFlag(struct CompilationUnit *cUnit,
+                                 struct BasicBlock *bb);
+char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn,
+                                      const char *note);
+char *dvmCompilerFullDisassembler(const struct CompilationUnit *cUnit,
+                                  const struct MIR *mir);
+char *dvmCompilerGetSSAString(struct CompilationUnit *cUnit,
+                              struct SSARepresentation *ssaRep);
+void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
+                bool (*func)(struct CompilationUnit *, struct BasicBlock *),
+                DataFlowAnalysisMode dfaMode,
+                bool isIterative);
+void dvmCompilerMethodSSATransformation(struct CompilationUnit *cUnit);
+bool dvmCompilerBuildLoop(struct CompilationUnit *cUnit);
+void dvmCompilerUpdateGlobalState(void);
+JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
+                                            const struct JitEntry *desc);
+extern "C" void *dvmCompilerGetInterpretTemplate();
+JitInstructionSetType dvmCompilerGetInterpretTemplateSet();
+u8 dvmGetRegResourceMask(int reg);
+void dvmDumpCFG(struct CompilationUnit *cUnit, const char *dirPrefix);
+
+#endif  // DALVIK_VM_COMPILER_H_
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
new file mode 100644
index 0000000..23dea33
--- /dev/null
+++ b/vm/compiler/CompilerIR.h
@@ -0,0 +1,302 @@
+/*
+ * 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_IR_H_
+#define DALVIK_VM_COMPILER_IR_H_
+
+#include "codegen/Optimizer.h"
+
+typedef enum RegisterClass {
+    kCoreReg,
+    kFPReg,
+    kAnyReg,
+} RegisterClass;
+
+typedef enum RegLocationType {
+    kLocDalvikFrame = 0,
+    kLocPhysReg,
+    kLocRetval,          // Return region in interpState
+    kLocSpill,
+} RegLocationType;
+
+typedef struct RegLocation {
+    RegLocationType location:2;
+    unsigned wide:1;
+    unsigned fp:1;      // Hint for float/double
+    u1 lowReg:6;        // First physical register
+    u1 highReg:6;       // 2nd physical register (if wide)
+    s2 sRegLow;         // SSA name for low Dalvik word
+} RegLocation;
+
+#define INVALID_SREG (-1)
+#define INVALID_REG (0x3F)
+
+typedef enum BBType {
+    /* For coding convenience reasons chaining cell types should appear first */
+    kChainingCellNormal = 0,
+    kChainingCellHot,
+    kChainingCellInvokeSingleton,
+    kChainingCellInvokePredicted,
+    kChainingCellBackwardBranch,
+    kChainingCellGap,
+    /* Don't insert new fields between Gap and Last */
+    kChainingCellLast = kChainingCellGap + 1,
+    kEntryBlock,
+    kDalvikByteCode,
+    kExitBlock,
+    kPCReconstruction,
+    kExceptionHandling,
+    kCatchEntry,
+} BBType;
+
+typedef enum JitMode {
+    kJitTrace = 0, // Acyclic - all instructions come from the trace descriptor
+    kJitLoop,      // Cycle - trace descriptor is used as a hint
+    kJitMethod,    // Whole method
+} JitMode;
+
+typedef struct ChainCellCounts {
+    union {
+        u1 count[kChainingCellLast]; /* include one more space for the gap # */
+        u4 dummyForAlignment;
+    } u;
+} ChainCellCounts;
+
+typedef struct LIR {
+    int offset;
+    struct LIR *next;
+    struct LIR *prev;
+    struct LIR *target;
+} LIR;
+
+enum ExtendedMIROpcode {
+    kMirOpFirst = kNumPackedOpcodes,
+    kMirOpPhi = kMirOpFirst,
+    kMirOpNullNRangeUpCheck,
+    kMirOpNullNRangeDownCheck,
+    kMirOpLowerBound,
+    kMirOpPunt,
+    kMirOpCheckInlinePrediction,        // Gen checks for predicted inlining
+    kMirOpLast,
+};
+
+struct SSARepresentation;
+
+typedef enum {
+    kMIRIgnoreNullCheck = 0,
+    kMIRNullCheckOnly,
+    kMIRIgnoreRangeCheck,
+    kMIRRangeCheckOnly,
+    kMIRInlined,                        // Invoke is inlined (ie dead)
+    kMIRInlinedPred,                    // Invoke is inlined via prediction
+    kMIRCallee,                         // Instruction is inlined from callee
+    kMIRInvokeMethodJIT,                // Callee is JIT'ed as a whole method
+} MIROptimizationFlagPositons;
+
+#define MIR_IGNORE_NULL_CHECK           (1 << kMIRIgnoreNullCheck)
+#define MIR_NULL_CHECK_ONLY             (1 << kMIRNullCheckOnly)
+#define MIR_IGNORE_RANGE_CHECK          (1 << kMIRIgnoreRangeCheck)
+#define MIR_RANGE_CHECK_ONLY            (1 << kMIRRangeCheckOnly)
+#define MIR_INLINED                     (1 << kMIRInlined)
+#define MIR_INLINED_PRED                (1 << kMIRInlinedPred)
+#define MIR_CALLEE                      (1 << kMIRCallee)
+#define MIR_INVOKE_METHOD_JIT           (1 << kMIRInvokeMethodJIT)
+
+typedef struct CallsiteInfo {
+    const char *classDescriptor;
+    Object *classLoader;
+    const Method *method;
+    LIR *misPredBranchOver;
+} CallsiteInfo;
+
+typedef struct MIR {
+    DecodedInstruction dalvikInsn;
+    unsigned int width;
+    unsigned int offset;
+    struct MIR *prev;
+    struct MIR *next;
+    struct SSARepresentation *ssaRep;
+    int OptimizationFlags;
+    int seqNum;
+    union {
+        // Used by the inlined insn from the callee to find the mother method
+        const Method *calleeMethod;
+        // Used by the inlined invoke to find the class and method pointers
+        CallsiteInfo *callsiteInfo;
+    } meta;
+} MIR;
+
+struct BasicBlockDataFlow;
+
+/* For successorBlockList */
+typedef enum BlockListType {
+    kNotUsed = 0,
+    kCatch,
+    kPackedSwitch,
+    kSparseSwitch,
+} BlockListType;
+
+typedef struct BasicBlock {
+    int id;
+    bool visited;
+    bool hidden;
+    unsigned int startOffset;
+    const Method *containingMethod;     // For blocks from the callee
+    BBType blockType;
+    bool needFallThroughBranch;         // For blocks ended due to length limit
+    bool isFallThroughFromInvoke;       // True means the block needs alignment
+    MIR *firstMIRInsn;
+    MIR *lastMIRInsn;
+    struct BasicBlock *fallThrough;
+    struct BasicBlock *taken;
+    struct BasicBlock *iDom;            // Immediate dominator
+    struct BasicBlockDataFlow *dataFlowInfo;
+    BitVector *predecessors;
+    BitVector *dominators;
+    BitVector *iDominated;              // Set nodes being immediately dominated
+    BitVector *domFrontier;             // Dominance frontier
+    struct {                            // For one-to-many successors like
+        BlockListType blockListType;    // switch and exception handling
+        GrowableList blocks;
+    } successorBlockList;
+} BasicBlock;
+
+/*
+ * The "blocks" field in "successorBlockList" points to an array of
+ * elements with the type "SuccessorBlockInfo".
+ * For catch blocks, key is type index for the exception.
+ * For swtich blocks, key is the case value.
+ */
+typedef struct SuccessorBlockInfo {
+    BasicBlock *block;
+    int key;
+} SuccessorBlockInfo;
+
+struct LoopAnalysis;
+struct RegisterPool;
+
+typedef enum AssemblerStatus {
+    kSuccess,
+    kRetryAll,
+    kRetryHalve
+} AssemblerStatus;
+
+typedef struct CompilationUnit {
+    int numInsts;
+    int numBlocks;
+    GrowableList blockList;
+    const Method *method;
+    const JitTraceDescription *traceDesc;
+    LIR *firstLIRInsn;
+    LIR *lastLIRInsn;
+    LIR *literalList;                   // Constants
+    LIR *classPointerList;              // Relocatable
+    int numClassPointers;
+    LIR *chainCellOffsetLIR;
+    GrowableList pcReconstructionList;
+    int headerSize;                     // bytes before the first code ptr
+    int dataOffset;                     // starting offset of literal pool
+    int totalSize;                      // header + code size
+    AssemblerStatus assemblerStatus;    // Success or fix and retry
+    int assemblerRetries;               // How many times tried to fix assembly
+    unsigned char *codeBuffer;
+    void *baseAddr;
+    bool printMe;
+    bool allSingleStep;
+    bool hasClassLiterals;              // Contains class ptrs used as literals
+    bool hasLoop;                       // Contains a loop
+    bool hasInvoke;                     // Contains an invoke instruction
+    bool heapMemOp;                     // Mark mem ops for self verification
+    bool usesLinkRegister;              // For self-verification only
+    int profileCodeSize;                // Size of the profile prefix in bytes
+    int numChainingCells[kChainingCellGap];
+    LIR *firstChainingLIR[kChainingCellGap];
+    LIR *chainingCellBottom;
+    struct RegisterPool *regPool;
+    int optRound;                       // round number to tell an LIR's age
+    jmp_buf *bailPtr;
+    JitInstructionSetType instructionSet;
+    /* Number of total regs used in the whole cUnit after SSA transformation */
+    int numSSARegs;
+    /* Map SSA reg i to the Dalvik[15..0]/Sub[31..16] pair. */
+    GrowableList *ssaToDalvikMap;
+
+    /* The following are new data structures to support SSA representations */
+    /* Map original Dalvik reg i to the SSA[15..0]/Sub[31..16] pair */
+    int *dalvikToSSAMap;                // length == method->registersSize
+    BitVector *isConstantV;             // length == numSSAReg
+    int *constantValues;                // length == numSSAReg
+
+    /* Data structure for loop analysis and optimizations */
+    struct LoopAnalysis *loopAnalysis;
+
+    /* Map SSA names to location */
+    RegLocation *regLocation;
+    int sequenceNumber;
+
+    /*
+     * Set to the Dalvik PC of the switch instruction if it has more than
+     * MAX_CHAINED_SWITCH_CASES cases.
+     */
+    const u2 *switchOverflowPad;
+
+    JitMode jitMode;
+    int numReachableBlocks;
+    int numDalvikRegisters;             // method->registersSize + inlined
+    BasicBlock *entryBlock;
+    BasicBlock *exitBlock;
+    BasicBlock *puntBlock;              // punting to interp for exceptions
+    BasicBlock *backChainBlock;         // for loop-trace
+    BasicBlock *curBlock;
+    BasicBlock *nextCodegenBlock;       // for extended trace codegen
+    GrowableList dfsOrder;
+    GrowableList domPostOrderTraversal;
+    BitVector *tryBlockAddr;
+    BitVector **defBlockMatrix;         // numDalvikRegister x numBlocks
+    BitVector *tempBlockV;
+    BitVector *tempDalvikRegisterV;
+    BitVector *tempSSARegisterV;        // numSSARegs
+    bool printSSANames;
+    void *blockLabelList;
+    bool quitLoopMode;                  // cold path/complex bytecode
+} CompilationUnit;
+
+#if defined(WITH_SELF_VERIFICATION)
+#define HEAP_ACCESS_SHADOW(_state) cUnit->heapMemOp = _state
+#else
+#define HEAP_ACCESS_SHADOW(_state)
+#endif
+
+BasicBlock *dvmCompilerNewBB(BBType blockType, int blockId);
+
+void dvmCompilerAppendMIR(BasicBlock *bb, MIR *mir);
+
+void dvmCompilerPrependMIR(BasicBlock *bb, MIR *mir);
+
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR);
+
+void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir);
+
+void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR);
+
+void dvmCompilerInsertLIRAfter(LIR *currentLIR, LIR *newLIR);
+
+void dvmCompilerAbort(CompilationUnit *cUnit);
+
+/* Debug Utilities */
+void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit);
+
+#endif  // DALVIK_VM_COMPILER_IR_H_
diff --git a/vm/compiler/CompilerInternals.h b/vm/compiler/CompilerInternals.h
new file mode 100644
index 0000000..d635286
--- /dev/null
+++ b/vm/compiler/CompilerInternals.h
@@ -0,0 +1,25 @@
+/*
+ * 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_H_
+#define DALVIK_VM_COMPILER_INTERNAL_H_
+
+#include "Dalvik.h"
+#include "CompilerUtility.h"
+#include "codegen/CompilerCodegen.h"
+#include "interp/Jit.h"
+
+#endif  // DALVIK_VM_COMPILER_INTERNAL_H_
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
new file mode 100644
index 0000000..8a674b8
--- /dev/null
+++ b/vm/compiler/CompilerUtility.h
@@ -0,0 +1,79 @@
+/*
+ * 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_H_
+#define DALVIK_VM_COMPILER_UTILITY_H_
+
+#include "Dalvik.h"
+
+/* Each arena page has some overhead, so take a few bytes off 8k */
+#define ARENA_DEFAULT_SIZE 8100
+
+/* Allocate the initial memory block for arena-based allocation */
+bool dvmCompilerHeapInit(void);
+
+typedef struct ArenaMemBlock {
+    size_t blockSize;
+    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;
+    intptr_t *elemList;
+} GrowableList;
+
+typedef struct GrowableListIterator {
+    GrowableList *list;
+    size_t idx;
+    size_t size;
+} GrowableListIterator;
+
+#define GET_ELEM_N(LIST, TYPE, N) (((TYPE*) LIST->elemList)[N])
+
+#define BLOCK_NAME_LEN 80
+
+/* Forward declarations */
+struct LIR;
+struct BasicBlock;
+
+void dvmInitGrowableList(GrowableList *gList, size_t initLength);
+void dvmInsertGrowableList(GrowableList *gList, intptr_t elem);
+void dvmGrowableListIteratorInit(GrowableList *gList,
+                                 GrowableListIterator *iterator);
+intptr_t dvmGrowableListIteratorNext(GrowableListIterator *iterator);
+intptr_t dvmGrowableListGetElement(const GrowableList *gList, size_t idx);
+
+BitVector* dvmCompilerAllocBitVector(unsigned int startBits, bool expandable);
+bool dvmCompilerSetBit(BitVector* pBits, unsigned int num);
+bool dvmCompilerClearBit(BitVector* pBits, unsigned int num);
+void dvmCompilerMarkAllBits(BitVector *pBits, bool set);
+void dvmDebugBitVector(char *msg, const BitVector *bv, int length);
+void dvmDumpLIRInsn(struct LIR *lir, unsigned char *baseAddr);
+void dvmDumpResourceMask(struct LIR *lir, u8 mask, const char *prefix);
+void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg,
+                           const BitVector *bv, int length);
+void dvmGetBlockName(struct BasicBlock *bb, char *name);
+int dvmCompilerCacheFlush(long start, long end, long flags);
+
+
+#endif  // DALVIK_COMPILER_UTILITY_H_
diff --git a/vm/compiler/Dataflow.cpp b/vm/compiler/Dataflow.cpp
new file mode 100644
index 0000000..7f164cb
--- /dev/null
+++ b/vm/compiler/Dataflow.cpp
@@ -0,0 +1,2514 @@
+/*
+ * 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 "Dataflow.h"
+#include "Loop.h"
+#include "libdex/DexOpcodes.h"
+
+/*
+ * Main table containing data flow attributes for each bytecode. The
+ * first kNumPackedOpcodes entries are for Dalvik bytecode
+ * instructions, where extended opcode at the MIR level are appended
+ * afterwards.
+ *
+ * TODO - many optimization flags are incomplete - they will only limit the
+ * scope of optimizations but will not cause mis-optimizations.
+ */
+int dvmCompilerDataFlowAttributes[kMirOpLast] = {
+    // 00 OP_NOP
+    DF_NOP,
+
+    // 01 OP_MOVE vA, vB
+    DF_DA | DF_UB | DF_IS_MOVE,
+
+    // 02 OP_MOVE_FROM16 vAA, vBBBB
+    DF_DA | DF_UB | DF_IS_MOVE,
+
+    // 03 OP_MOVE_16 vAAAA, vBBBB
+    DF_DA | DF_UB | DF_IS_MOVE,
+
+    // 04 OP_MOVE_WIDE vA, vB
+    DF_DA_WIDE | DF_UB_WIDE | DF_IS_MOVE,
+
+    // 05 OP_MOVE_WIDE_FROM16 vAA, vBBBB
+    DF_DA_WIDE | DF_UB_WIDE | DF_IS_MOVE,
+
+    // 06 OP_MOVE_WIDE_16 vAAAA, vBBBB
+    DF_DA_WIDE | DF_UB_WIDE | DF_IS_MOVE,
+
+    // 07 OP_MOVE_OBJECT vA, vB
+    DF_DA | DF_UB | DF_IS_MOVE,
+
+    // 08 OP_MOVE_OBJECT_FROM16 vAA, vBBBB
+    DF_DA | DF_UB | DF_IS_MOVE,
+
+    // 09 OP_MOVE_OBJECT_16 vAAAA, vBBBB
+    DF_DA | DF_UB | DF_IS_MOVE,
+
+    // 0A OP_MOVE_RESULT vAA
+    DF_DA,
+
+    // 0B OP_MOVE_RESULT_WIDE vAA
+    DF_DA_WIDE,
+
+    // 0C OP_MOVE_RESULT_OBJECT vAA
+    DF_DA,
+
+    // 0D OP_MOVE_EXCEPTION vAA
+    DF_DA,
+
+    // 0E OP_RETURN_VOID
+    DF_NOP,
+
+    // 0F OP_RETURN vAA
+    DF_UA,
+
+    // 10 OP_RETURN_WIDE vAA
+    DF_UA_WIDE,
+
+    // 11 OP_RETURN_OBJECT vAA
+    DF_UA,
+
+    // 12 OP_CONST_4 vA, #+B
+    DF_DA | DF_SETS_CONST,
+
+    // 13 OP_CONST_16 vAA, #+BBBB
+    DF_DA | DF_SETS_CONST,
+
+    // 14 OP_CONST vAA, #+BBBBBBBB
+    DF_DA | DF_SETS_CONST,
+
+    // 15 OP_CONST_HIGH16 VAA, #+BBBB0000
+    DF_DA | DF_SETS_CONST,
+
+    // 16 OP_CONST_WIDE_16 vAA, #+BBBB
+    DF_DA_WIDE | DF_SETS_CONST,
+
+    // 17 OP_CONST_WIDE_32 vAA, #+BBBBBBBB
+    DF_DA_WIDE | DF_SETS_CONST,
+
+    // 18 OP_CONST_WIDE vAA, #+BBBBBBBBBBBBBBBB
+    DF_DA_WIDE | DF_SETS_CONST,
+
+    // 19 OP_CONST_WIDE_HIGH16 vAA, #+BBBB000000000000
+    DF_DA_WIDE | DF_SETS_CONST,
+
+    // 1A OP_CONST_STRING vAA, string@BBBB
+    DF_DA,
+
+    // 1B OP_CONST_STRING_JUMBO vAA, string@BBBBBBBB
+    DF_DA,
+
+    // 1C OP_CONST_CLASS vAA, type@BBBB
+    DF_DA,
+
+    // 1D OP_MONITOR_ENTER vAA
+    DF_UA,
+
+    // 1E OP_MONITOR_EXIT vAA
+    DF_UA,
+
+    // 1F OP_CHECK_CAST vAA, type@BBBB
+    DF_UA,
+
+    // 20 OP_INSTANCE_OF vA, vB, type@CCCC
+    DF_DA | DF_UB,
+
+    // 21 OP_ARRAY_LENGTH vA, vB
+    DF_DA | DF_UB,
+
+    // 22 OP_NEW_INSTANCE vAA, type@BBBB
+    DF_DA,
+
+    // 23 OP_NEW_ARRAY vA, vB, type@CCCC
+    DF_DA | DF_UB,
+
+    // 24 OP_FILLED_NEW_ARRAY {vD, vE, vF, vG, vA}
+    DF_FORMAT_35C,
+
+    // 25 OP_FILLED_NEW_ARRAY_RANGE {vCCCC .. vNNNN}, type@BBBB
+    DF_FORMAT_3RC,
+
+    // 26 OP_FILL_ARRAY_DATA vAA, +BBBBBBBB
+    DF_UA,
+
+    // 27 OP_THROW vAA
+    DF_UA,
+
+    // 28 OP_GOTO
+    DF_NOP,
+
+    // 29 OP_GOTO_16
+    DF_NOP,
+
+    // 2A OP_GOTO_32
+    DF_NOP,
+
+    // 2B OP_PACKED_SWITCH vAA, +BBBBBBBB
+    DF_UA,
+
+    // 2C OP_SPARSE_SWITCH vAA, +BBBBBBBB
+    DF_UA,
+
+    // 2D OP_CMPL_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C,
+
+    // 2E OP_CMPG_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C,
+
+    // 2F OP_CMPL_DOUBLE vAA, vBB, vCC
+    DF_DA | DF_UB_WIDE | DF_UC_WIDE | DF_FP_B | DF_FP_C,
+
+    // 30 OP_CMPG_DOUBLE vAA, vBB, vCC
+    DF_DA | DF_UB_WIDE | DF_UC_WIDE | DF_FP_B | DF_FP_C,
+
+    // 31 OP_CMP_LONG vAA, vBB, vCC
+    DF_DA | DF_UB_WIDE | DF_UC_WIDE,
+
+    // 32 OP_IF_EQ vA, vB, +CCCC
+    DF_UA | DF_UB,
+
+    // 33 OP_IF_NE vA, vB, +CCCC
+    DF_UA | DF_UB,
+
+    // 34 OP_IF_LT vA, vB, +CCCC
+    DF_UA | DF_UB,
+
+    // 35 OP_IF_GE vA, vB, +CCCC
+    DF_UA | DF_UB,
+
+    // 36 OP_IF_GT vA, vB, +CCCC
+    DF_UA | DF_UB,
+
+    // 37 OP_IF_LE vA, vB, +CCCC
+    DF_UA | DF_UB,
+
+
+    // 38 OP_IF_EQZ vAA, +BBBB
+    DF_UA,
+
+    // 39 OP_IF_NEZ vAA, +BBBB
+    DF_UA,
+
+    // 3A OP_IF_LTZ vAA, +BBBB
+    DF_UA,
+
+    // 3B OP_IF_GEZ vAA, +BBBB
+    DF_UA,
+
+    // 3C OP_IF_GTZ vAA, +BBBB
+    DF_UA,
+
+    // 3D OP_IF_LEZ vAA, +BBBB
+    DF_UA,
+
+    // 3E OP_UNUSED_3E
+    DF_NOP,
+
+    // 3F OP_UNUSED_3F
+    DF_NOP,
+
+    // 40 OP_UNUSED_40
+    DF_NOP,
+
+    // 41 OP_UNUSED_41
+    DF_NOP,
+
+    // 42 OP_UNUSED_42
+    DF_NOP,
+
+    // 43 OP_UNUSED_43
+    DF_NOP,
+
+    // 44 OP_AGET vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 45 OP_AGET_WIDE vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 46 OP_AGET_OBJECT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 47 OP_AGET_BOOLEAN vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 48 OP_AGET_BYTE vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 49 OP_AGET_CHAR vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 4A OP_AGET_SHORT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+
+    // 4B OP_APUT vAA, vBB, vCC
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+
+    // 4C OP_APUT_WIDE vAA, vBB, vCC
+    DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2 | DF_IS_SETTER,
+
+    // 4D OP_APUT_OBJECT vAA, vBB, vCC
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+
+    // 4E OP_APUT_BOOLEAN vAA, vBB, vCC
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+
+    // 4F OP_APUT_BYTE vAA, vBB, vCC
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+
+    // 50 OP_APUT_CHAR vAA, vBB, vCC
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+
+    // 51 OP_APUT_SHORT vAA, vBB, vCC
+    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+
+    // 52 OP_IGET vA, vB, field@CCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 53 OP_IGET_WIDE vA, vB, field@CCCC
+    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+
+    // 54 OP_IGET_OBJECT vA, vB, field@CCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 55 OP_IGET_BOOLEAN vA, vB, field@CCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 56 OP_IGET_BYTE vA, vB, field@CCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 57 OP_IGET_CHAR vA, vB, field@CCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 58 OP_IGET_SHORT vA, vB, field@CCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 59 OP_IPUT vA, vB, field@CCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 5A OP_IPUT_WIDE vA, vB, field@CCCC
+    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+
+    // 5B OP_IPUT_OBJECT vA, vB, field@CCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 5C OP_IPUT_BOOLEAN vA, vB, field@CCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 5D OP_IPUT_BYTE vA, vB, field@CCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 5E OP_IPUT_CHAR vA, vB, field@CCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 5F OP_IPUT_SHORT vA, vB, field@CCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 60 OP_SGET vAA, field@BBBB
+    DF_DA | DF_IS_GETTER,
+
+    // 61 OP_SGET_WIDE vAA, field@BBBB
+    DF_DA_WIDE | DF_IS_GETTER,
+
+    // 62 OP_SGET_OBJECT vAA, field@BBBB
+    DF_DA | DF_IS_GETTER,
+
+    // 63 OP_SGET_BOOLEAN vAA, field@BBBB
+    DF_DA | DF_IS_GETTER,
+
+    // 64 OP_SGET_BYTE vAA, field@BBBB
+    DF_DA | DF_IS_GETTER,
+
+    // 65 OP_SGET_CHAR vAA, field@BBBB
+    DF_DA | DF_IS_GETTER,
+
+    // 66 OP_SGET_SHORT vAA, field@BBBB
+    DF_DA | DF_IS_GETTER,
+
+    // 67 OP_SPUT vAA, field@BBBB
+    DF_UA | DF_IS_SETTER,
+
+    // 68 OP_SPUT_WIDE vAA, field@BBBB
+    DF_UA_WIDE | DF_IS_SETTER,
+
+    // 69 OP_SPUT_OBJECT vAA, field@BBBB
+    DF_UA | DF_IS_SETTER,
+
+    // 6A OP_SPUT_BOOLEAN vAA, field@BBBB
+    DF_UA | DF_IS_SETTER,
+
+    // 6B OP_SPUT_BYTE vAA, field@BBBB
+    DF_UA | DF_IS_SETTER,
+
+    // 6C OP_SPUT_CHAR vAA, field@BBBB
+    DF_UA | DF_IS_SETTER,
+
+    // 6D OP_SPUT_SHORT vAA, field@BBBB
+    DF_UA | DF_IS_SETTER,
+
+    // 6E OP_INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
+    DF_FORMAT_35C,
+
+    // 6F OP_INVOKE_SUPER {vD, vE, vF, vG, vA}
+    DF_FORMAT_35C,
+
+    // 70 OP_INVOKE_DIRECT {vD, vE, vF, vG, vA}
+    DF_FORMAT_35C,
+
+    // 71 OP_INVOKE_STATIC {vD, vE, vF, vG, vA}
+    DF_FORMAT_35C,
+
+    // 72 OP_INVOKE_INTERFACE {vD, vE, vF, vG, vA}
+    DF_FORMAT_35C,
+
+    // 73 OP_UNUSED_73
+    DF_NOP,
+
+    // 74 OP_INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
+    DF_FORMAT_3RC,
+
+    // 75 OP_INVOKE_SUPER_RANGE {vCCCC .. vNNNN}
+    DF_FORMAT_3RC,
+
+    // 76 OP_INVOKE_DIRECT_RANGE {vCCCC .. vNNNN}
+    DF_FORMAT_3RC,
+
+    // 77 OP_INVOKE_STATIC_RANGE {vCCCC .. vNNNN}
+    DF_FORMAT_3RC,
+
+    // 78 OP_INVOKE_INTERFACE_RANGE {vCCCC .. vNNNN}
+    DF_FORMAT_3RC,
+
+    // 79 OP_UNUSED_79
+    DF_NOP,
+
+    // 7A OP_UNUSED_7A
+    DF_NOP,
+
+    // 7B OP_NEG_INT vA, vB
+    DF_DA | DF_UB,
+
+    // 7C OP_NOT_INT vA, vB
+    DF_DA | DF_UB,
+
+    // 7D OP_NEG_LONG vA, vB
+    DF_DA_WIDE | DF_UB_WIDE,
+
+    // 7E OP_NOT_LONG vA, vB
+    DF_DA_WIDE | DF_UB_WIDE,
+
+    // 7F OP_NEG_FLOAT vA, vB
+    DF_DA | DF_UB | DF_FP_A | DF_FP_B,
+
+    // 80 OP_NEG_DOUBLE vA, vB
+    DF_DA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // 81 OP_INT_TO_LONG vA, vB
+    DF_DA_WIDE | DF_UB,
+
+    // 82 OP_INT_TO_FLOAT vA, vB
+    DF_DA | DF_UB | DF_FP_A,
+
+    // 83 OP_INT_TO_DOUBLE vA, vB
+    DF_DA_WIDE | DF_UB | DF_FP_A,
+
+    // 84 OP_LONG_TO_INT vA, vB
+    DF_DA | DF_UB_WIDE,
+
+    // 85 OP_LONG_TO_FLOAT vA, vB
+    DF_DA | DF_UB_WIDE | DF_FP_A,
+
+    // 86 OP_LONG_TO_DOUBLE vA, vB
+    DF_DA_WIDE | DF_UB_WIDE | DF_FP_A,
+
+    // 87 OP_FLOAT_TO_INT vA, vB
+    DF_DA | DF_UB | DF_FP_B,
+
+    // 88 OP_FLOAT_TO_LONG vA, vB
+    DF_DA_WIDE | DF_UB | DF_FP_B,
+
+    // 89 OP_FLOAT_TO_DOUBLE vA, vB
+    DF_DA_WIDE | DF_UB | DF_FP_A | DF_FP_B,
+
+    // 8A OP_DOUBLE_TO_INT vA, vB
+    DF_DA | DF_UB_WIDE | DF_FP_B,
+
+    // 8B OP_DOUBLE_TO_LONG vA, vB
+    DF_DA_WIDE | DF_UB_WIDE | DF_FP_B,
+
+    // 8C OP_DOUBLE_TO_FLOAT vA, vB
+    DF_DA | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // 8D OP_INT_TO_BYTE vA, vB
+    DF_DA | DF_UB,
+
+    // 8E OP_INT_TO_CHAR vA, vB
+    DF_DA | DF_UB,
+
+    // 8F OP_INT_TO_SHORT vA, vB
+    DF_DA | DF_UB,
+
+    // 90 OP_ADD_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_IS_LINEAR,
+
+    // 91 OP_SUB_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_IS_LINEAR,
+
+    // 92 OP_MUL_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 93 OP_DIV_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 94 OP_REM_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 95 OP_AND_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 96 OP_OR_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 97 OP_XOR_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 98 OP_SHL_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 99 OP_SHR_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 9A OP_USHR_INT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC,
+
+    // 9B OP_ADD_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // 9C OP_SUB_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // 9D OP_MUL_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // 9E OP_DIV_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // 9F OP_REM_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // A0 OP_AND_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // A1 OP_OR_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // A2 OP_XOR_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+
+    // A3 OP_SHL_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC,
+
+    // A4 OP_SHR_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC,
+
+    // A5 OP_USHR_LONG vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC,
+
+    // A6 OP_ADD_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // A7 OP_SUB_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // A8 OP_MUL_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // A9 OP_DIV_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // AA OP_REM_FLOAT vAA, vBB, vCC
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // AB OP_ADD_DOUBLE vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // AC OP_SUB_DOUBLE vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // AD OP_MUL_DOUBLE vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // AE OP_DIV_DOUBLE vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // AF OP_REM_DOUBLE vAA, vBB, vCC
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
+
+    // B0 OP_ADD_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B1 OP_SUB_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B2 OP_MUL_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B3 OP_DIV_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B4 OP_REM_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B5 OP_AND_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B6 OP_OR_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B7 OP_XOR_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B8 OP_SHL_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // B9 OP_SHR_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // BA OP_USHR_INT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB,
+
+    // BB OP_ADD_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // BC OP_SUB_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // BD OP_MUL_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // BE OP_DIV_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // BF OP_REM_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // C0 OP_AND_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // C1 OP_OR_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // C2 OP_XOR_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+
+    // C3 OP_SHL_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB,
+
+    // C4 OP_SHR_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB,
+
+    // C5 OP_USHR_LONG_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB,
+
+    // C6 OP_ADD_FLOAT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
+
+    // C7 OP_SUB_FLOAT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
+
+    // C8 OP_MUL_FLOAT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
+
+    // C9 OP_DIV_FLOAT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
+
+    // CA OP_REM_FLOAT_2ADDR vA, vB
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
+
+    // CB OP_ADD_DOUBLE_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // CC OP_SUB_DOUBLE_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // CD OP_MUL_DOUBLE_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // CE OP_DIV_DOUBLE_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // CF OP_REM_DOUBLE_2ADDR vA, vB
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
+
+    // D0 OP_ADD_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D1 OP_RSUB_INT vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D2 OP_MUL_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D3 OP_DIV_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D4 OP_REM_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D5 OP_AND_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D6 OP_OR_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D7 OP_XOR_INT_LIT16 vA, vB, #+CCCC
+    DF_DA | DF_UB,
+
+    // D8 OP_ADD_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB | DF_IS_LINEAR,
+
+    // D9 OP_RSUB_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // DA OP_MUL_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // DB OP_DIV_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // DC OP_REM_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // DD OP_AND_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // DE OP_OR_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // DF OP_XOR_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // E0 OP_SHL_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // E1 OP_SHR_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // E2 OP_USHR_INT_LIT8 vAA, vBB, #+CC
+    DF_DA | DF_UB,
+
+    // E3 OP_IGET_VOLATILE
+    DF_DA | DF_UB,
+
+    // E4 OP_IPUT_VOLATILE
+    DF_UA | DF_UB,
+
+    // E5 OP_SGET_VOLATILE
+    DF_DA,
+
+    // E6 OP_SPUT_VOLATILE
+    DF_UA,
+
+    // E7 OP_IGET_OBJECT_VOLATILE
+    DF_DA | DF_UB,
+
+    // E8 OP_IGET_WIDE_VOLATILE
+    DF_DA_WIDE | DF_UB,
+
+    // E9 OP_IPUT_WIDE_VOLATILE
+    DF_UA_WIDE | DF_UB,
+
+    // EA OP_SGET_WIDE_VOLATILE
+    DF_DA_WIDE,
+
+    // EB OP_SPUT_WIDE_VOLATILE
+    DF_UA_WIDE,
+
+    // EC OP_BREAKPOINT
+    DF_NOP,
+
+    // ED OP_THROW_VERIFICATION_ERROR
+    DF_NOP,
+
+    // EE OP_EXECUTE_INLINE
+    DF_FORMAT_35C,
+
+    // EF OP_EXECUTE_INLINE_RANGE
+    DF_FORMAT_3RC,
+
+    // F0 OP_INVOKE_OBJECT_INIT_RANGE
+    DF_NOP,
+
+    // F1 OP_RETURN_VOID_BARRIER
+    DF_NOP,
+
+    // F2 OP_IGET_QUICK
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // F3 OP_IGET_WIDE_QUICK
+    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+
+    // F4 OP_IGET_OBJECT_QUICK
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // F5 OP_IPUT_QUICK
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // F6 OP_IPUT_WIDE_QUICK
+    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+
+    // F7 OP_IPUT_OBJECT_QUICK
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // F8 OP_INVOKE_VIRTUAL_QUICK
+    DF_FORMAT_35C,
+
+    // F9 OP_INVOKE_VIRTUAL_QUICK_RANGE
+    DF_FORMAT_3RC,
+
+    // FA OP_INVOKE_SUPER_QUICK
+    DF_FORMAT_35C,
+
+    // FB OP_INVOKE_SUPER_QUICK_RANGE
+    DF_FORMAT_3RC,
+
+    // FC OP_IPUT_OBJECT_VOLATILE
+    DF_UA | DF_UB,
+
+    // FD OP_SGET_OBJECT_VOLATILE
+    DF_DA,
+
+    // FE OP_SPUT_OBJECT_VOLATILE
+    DF_UA,
+
+    // FF OP_DISPATCH_FF
+    DF_NOP,
+
+    // 100 OP_CONST_CLASS_JUMBO vAAAA, type@BBBBBBBB
+    DF_DA,
+
+    // 101 OP_CHECK_CAST_JUMBO vAAAA, type@BBBBBBBB
+    DF_UA,
+
+    // 102 OP_INSTANCE_OF_JUMBO vAAAA, vBBBB, type@CCCCCCCC
+    DF_DA | DF_UB,
+
+    // 103 OP_NEW_INSTANCE_JUMBO vAAAA, type@BBBBBBBB
+    DF_DA,
+
+    // 104 OP_NEW_ARRAY_JUMBO vAAAA, vBBBB, type@CCCCCCCC
+    DF_DA | DF_UB,
+
+    // 105 OP_FILLED_NEW_ARRAY_JUMBO {vCCCC .. vNNNN}, type@BBBBBBBB
+    DF_FORMAT_3RC,
+
+    // 106 OP_IGET_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 107 OP_IGET_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+
+    // 108 OP_IGET_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 109 OP_IGET_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 10A OP_IGET_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 10B OP_IGET_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 10C OP_IGET_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_UB | DF_IS_GETTER,
+
+    // 10D OP_IPUT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 10E OP_IPUT_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+
+    // 10F OP_IPUT_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 110 OP_IPUT_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 111 OP_IPUT_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 112 OP_IPUT_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 113 OP_IPUT_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_UB | DF_IS_SETTER,
+
+    // 114 OP_SGET_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_IS_GETTER,
+
+    // 115 OP_SGET_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA_WIDE | DF_IS_GETTER,
+
+    // 116 OP_SGET_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_IS_GETTER,
+
+    // 117 OP_SGET_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_IS_GETTER,
+
+    // 118 OP_SGET_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_IS_GETTER,
+
+    // 119 OP_SGET_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_IS_GETTER,
+
+    // 11A OP_SGET_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_DA | DF_IS_GETTER,
+
+    // 11B OP_SPUT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_IS_SETTER,
+
+    // 11C OP_SPUT_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA_WIDE | DF_IS_SETTER,
+
+    // 11D OP_SPUT_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_IS_SETTER,
+
+    // 11E OP_SPUT_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_IS_SETTER,
+
+    // 11F OP_SPUT_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_IS_SETTER,
+
+    // 120 OP_SPUT_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_IS_SETTER,
+
+    // 121 OP_SPUT_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
+    DF_UA | DF_IS_SETTER,
+
+    // 122 OP_INVOKE_VIRTUAL_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
+    DF_FORMAT_3RC,
+
+    // 123 OP_INVOKE_SUPER_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
+    DF_FORMAT_3RC,
+
+    // 124 OP_INVOKE_DIRECT_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
+    DF_FORMAT_3RC,
+
+    // 125 OP_INVOKE_STATIC_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
+    DF_FORMAT_3RC,
+
+    // 126 OP_INVOKE_INTERFACE_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
+    DF_FORMAT_3RC,
+
+    // 127 OP_UNUSED_27FF
+    DF_NOP,
+
+    // 128 OP_UNUSED_28FF
+    DF_NOP,
+
+    // 129 OP_UNUSED_29FF
+    DF_NOP,
+
+    // 12A OP_UNUSED_2AFF
+    DF_NOP,
+
+    // 12B OP_UNUSED_2BFF
+    DF_NOP,
+
+    // 12C OP_UNUSED_2CFF
+    DF_NOP,
+
+    // 12D OP_UNUSED_2DFF
+    DF_NOP,
+
+    // 12E OP_UNUSED_2EFF
+    DF_NOP,
+
+    // 12F OP_UNUSED_2FFF
+    DF_NOP,
+
+    // 130 OP_UNUSED_30FF
+    DF_NOP,
+
+    // 131 OP_UNUSED_31FF
+    DF_NOP,
+
+    // 132 OP_UNUSED_32FF
+    DF_NOP,
+
+    // 133 OP_UNUSED_33FF
+    DF_NOP,
+
+    // 134 OP_UNUSED_34FF
+    DF_NOP,
+
+    // 135 OP_UNUSED_35FF
+    DF_NOP,
+
+    // 136 OP_UNUSED_36FF
+    DF_NOP,
+
+    // 137 OP_UNUSED_37FF
+    DF_NOP,
+
+    // 138 OP_UNUSED_38FF
+    DF_NOP,
+
+    // 139 OP_UNUSED_39FF
+    DF_NOP,
+
+    // 13A OP_UNUSED_3AFF
+    DF_NOP,
+
+    // 13B OP_UNUSED_3BFF
+    DF_NOP,
+
+    // 13C OP_UNUSED_3CFF
+    DF_NOP,
+
+    // 13D OP_UNUSED_3DFF
+    DF_NOP,
+
+    // 13E OP_UNUSED_3EFF
+    DF_NOP,
+
+    // 13F OP_UNUSED_3FFF
+    DF_NOP,
+
+    // 140 OP_UNUSED_40FF
+    DF_NOP,
+
+    // 141 OP_UNUSED_41FF
+    DF_NOP,
+
+    // 142 OP_UNUSED_42FF
+    DF_NOP,
+
+    // 143 OP_UNUSED_43FF
+    DF_NOP,
+
+    // 144 OP_UNUSED_44FF
+    DF_NOP,
+
+    // 145 OP_UNUSED_45FF
+    DF_NOP,
+
+    // 146 OP_UNUSED_46FF
+    DF_NOP,
+
+    // 147 OP_UNUSED_47FF
+    DF_NOP,
+
+    // 148 OP_UNUSED_48FF
+    DF_NOP,
+
+    // 149 OP_UNUSED_49FF
+    DF_NOP,
+
+    // 14A OP_UNUSED_4AFF
+    DF_NOP,
+
+    // 14B OP_UNUSED_4BFF
+    DF_NOP,
+
+    // 14C OP_UNUSED_4CFF
+    DF_NOP,
+
+    // 14D OP_UNUSED_4DFF
+    DF_NOP,
+
+    // 14E OP_UNUSED_4EFF
+    DF_NOP,
+
+    // 14F OP_UNUSED_4FFF
+    DF_NOP,
+
+    // 150 OP_UNUSED_50FF
+    DF_NOP,
+
+    // 151 OP_UNUSED_51FF
+    DF_NOP,
+
+    // 152 OP_UNUSED_52FF
+    DF_NOP,
+
+    // 153 OP_UNUSED_53FF
+    DF_NOP,
+
+    // 154 OP_UNUSED_54FF
+    DF_NOP,
+
+    // 155 OP_UNUSED_55FF
+    DF_NOP,
+
+    // 156 OP_UNUSED_56FF
+    DF_NOP,
+
+    // 157 OP_UNUSED_57FF
+    DF_NOP,
+
+    // 158 OP_UNUSED_58FF
+    DF_NOP,
+
+    // 159 OP_UNUSED_59FF
+    DF_NOP,
+
+    // 15A OP_UNUSED_5AFF
+    DF_NOP,
+
+    // 15B OP_UNUSED_5BFF
+    DF_NOP,
+
+    // 15C OP_UNUSED_5CFF
+    DF_NOP,
+
+    // 15D OP_UNUSED_5DFF
+    DF_NOP,
+
+    // 15E OP_UNUSED_5EFF
+    DF_NOP,
+
+    // 15F OP_UNUSED_5FFF
+    DF_NOP,
+
+    // 160 OP_UNUSED_60FF
+    DF_NOP,
+
+    // 161 OP_UNUSED_61FF
+    DF_NOP,
+
+    // 162 OP_UNUSED_62FF
+    DF_NOP,
+
+    // 163 OP_UNUSED_63FF
+    DF_NOP,
+
+    // 164 OP_UNUSED_64FF
+    DF_NOP,
+
+    // 165 OP_UNUSED_65FF
+    DF_NOP,
+
+    // 166 OP_UNUSED_66FF
+    DF_NOP,
+
+    // 167 OP_UNUSED_67FF
+    DF_NOP,
+
+    // 168 OP_UNUSED_68FF
+    DF_NOP,
+
+    // 169 OP_UNUSED_69FF
+    DF_NOP,
+
+    // 16A OP_UNUSED_6AFF
+    DF_NOP,
+
+    // 16B OP_UNUSED_6BFF
+    DF_NOP,
+
+    // 16C OP_UNUSED_6CFF
+    DF_NOP,
+
+    // 16D OP_UNUSED_6DFF
+    DF_NOP,
+
+    // 16E OP_UNUSED_6EFF
+    DF_NOP,
+
+    // 16F OP_UNUSED_6FFF
+    DF_NOP,
+
+    // 170 OP_UNUSED_70FF
+    DF_NOP,
+
+    // 171 OP_UNUSED_71FF
+    DF_NOP,
+
+    // 172 OP_UNUSED_72FF
+    DF_NOP,
+
+    // 173 OP_UNUSED_73FF
+    DF_NOP,
+
+    // 174 OP_UNUSED_74FF
+    DF_NOP,
+
+    // 175 OP_UNUSED_75FF
+    DF_NOP,
+
+    // 176 OP_UNUSED_76FF
+    DF_NOP,
+
+    // 177 OP_UNUSED_77FF
+    DF_NOP,
+
+    // 178 OP_UNUSED_78FF
+    DF_NOP,
+
+    // 179 OP_UNUSED_79FF
+    DF_NOP,
+
+    // 17A OP_UNUSED_7AFF
+    DF_NOP,
+
+    // 17B OP_UNUSED_7BFF
+    DF_NOP,
+
+    // 17C OP_UNUSED_7CFF
+    DF_NOP,
+
+    // 17D OP_UNUSED_7DFF
+    DF_NOP,
+
+    // 17E OP_UNUSED_7EFF
+    DF_NOP,
+
+    // 17F OP_UNUSED_7FFF
+    DF_NOP,
+
+    // 180 OP_UNUSED_80FF
+    DF_NOP,
+
+    // 181 OP_UNUSED_81FF
+    DF_NOP,
+
+    // 182 OP_UNUSED_82FF
+    DF_NOP,
+
+    // 183 OP_UNUSED_83FF
+    DF_NOP,
+
+    // 184 OP_UNUSED_84FF
+    DF_NOP,
+
+    // 185 OP_UNUSED_85FF
+    DF_NOP,
+
+    // 186 OP_UNUSED_86FF
+    DF_NOP,
+
+    // 187 OP_UNUSED_87FF
+    DF_NOP,
+
+    // 188 OP_UNUSED_88FF
+    DF_NOP,
+
+    // 189 OP_UNUSED_89FF
+    DF_NOP,
+
+    // 18A OP_UNUSED_8AFF
+    DF_NOP,
+
+    // 18B OP_UNUSED_8BFF
+    DF_NOP,
+
+    // 18C OP_UNUSED_8CFF
+    DF_NOP,
+
+    // 18D OP_UNUSED_8DFF
+    DF_NOP,
+
+    // 18E OP_UNUSED_8EFF
+    DF_NOP,
+
+    // 18F OP_UNUSED_8FFF
+    DF_NOP,
+
+    // 190 OP_UNUSED_90FF
+    DF_NOP,
+
+    // 191 OP_UNUSED_91FF
+    DF_NOP,
+
+    // 192 OP_UNUSED_92FF
+    DF_NOP,
+
+    // 193 OP_UNUSED_93FF
+    DF_NOP,
+
+    // 194 OP_UNUSED_94FF
+    DF_NOP,
+
+    // 195 OP_UNUSED_95FF
+    DF_NOP,
+
+    // 196 OP_UNUSED_96FF
+    DF_NOP,
+
+    // 197 OP_UNUSED_97FF
+    DF_NOP,
+
+    // 198 OP_UNUSED_98FF
+    DF_NOP,
+
+    // 199 OP_UNUSED_99FF
+    DF_NOP,
+
+    // 19A OP_UNUSED_9AFF
+    DF_NOP,
+
+    // 19B OP_UNUSED_9BFF
+    DF_NOP,
+
+    // 19C OP_UNUSED_9CFF
+    DF_NOP,
+
+    // 19D OP_UNUSED_9DFF
+    DF_NOP,
+
+    // 19E OP_UNUSED_9EFF
+    DF_NOP,
+
+    // 19F OP_UNUSED_9FFF
+    DF_NOP,
+
+    // 1A0 OP_UNUSED_A0FF
+    DF_NOP,
+
+    // 1A1 OP_UNUSED_A1FF
+    DF_NOP,
+
+    // 1A2 OP_UNUSED_A2FF
+    DF_NOP,
+
+    // 1A3 OP_UNUSED_A3FF
+    DF_NOP,
+
+    // 1A4 OP_UNUSED_A4FF
+    DF_NOP,
+
+    // 1A5 OP_UNUSED_A5FF
+    DF_NOP,
+
+    // 1A6 OP_UNUSED_A6FF
+    DF_NOP,
+
+    // 1A7 OP_UNUSED_A7FF
+    DF_NOP,
+
+    // 1A8 OP_UNUSED_A8FF
+    DF_NOP,
+
+    // 1A9 OP_UNUSED_A9FF
+    DF_NOP,
+
+    // 1AA OP_UNUSED_AAFF
+    DF_NOP,
+
+    // 1AB OP_UNUSED_ABFF
+    DF_NOP,
+
+    // 1AC OP_UNUSED_ACFF
+    DF_NOP,
+
+    // 1AD OP_UNUSED_ADFF
+    DF_NOP,
+
+    // 1AE OP_UNUSED_AEFF
+    DF_NOP,
+
+    // 1AF OP_UNUSED_AFFF
+    DF_NOP,
+
+    // 1B0 OP_UNUSED_B0FF
+    DF_NOP,
+
+    // 1B1 OP_UNUSED_B1FF
+    DF_NOP,
+
+    // 1B2 OP_UNUSED_B2FF
+    DF_NOP,
+
+    // 1B3 OP_UNUSED_B3FF
+    DF_NOP,
+
+    // 1B4 OP_UNUSED_B4FF
+    DF_NOP,
+
+    // 1B5 OP_UNUSED_B5FF
+    DF_NOP,
+
+    // 1B6 OP_UNUSED_B6FF
+    DF_NOP,
+
+    // 1B7 OP_UNUSED_B7FF
+    DF_NOP,
+
+    // 1B8 OP_UNUSED_B8FF
+    DF_NOP,
+
+    // 1B9 OP_UNUSED_B9FF
+    DF_NOP,
+
+    // 1BA OP_UNUSED_BAFF
+    DF_NOP,
+
+    // 1BB OP_UNUSED_BBFF
+    DF_NOP,
+
+    // 1BC OP_UNUSED_BCFF
+    DF_NOP,
+
+    // 1BD OP_UNUSED_BDFF
+    DF_NOP,
+
+    // 1BE OP_UNUSED_BEFF
+    DF_NOP,
+
+    // 1BF OP_UNUSED_BFFF
+    DF_NOP,
+
+    // 1C0 OP_UNUSED_C0FF
+    DF_NOP,
+
+    // 1C1 OP_UNUSED_C1FF
+    DF_NOP,
+
+    // 1C2 OP_UNUSED_C2FF
+    DF_NOP,
+
+    // 1C3 OP_UNUSED_C3FF
+    DF_NOP,
+
+    // 1C4 OP_UNUSED_C4FF
+    DF_NOP,
+
+    // 1C5 OP_UNUSED_C5FF
+    DF_NOP,
+
+    // 1C6 OP_UNUSED_C6FF
+    DF_NOP,
+
+    // 1C7 OP_UNUSED_C7FF
+    DF_NOP,
+
+    // 1C8 OP_UNUSED_C8FF
+    DF_NOP,
+
+    // 1C9 OP_UNUSED_C9FF
+    DF_NOP,
+
+    // 1CA OP_UNUSED_CAFF
+    DF_NOP,
+
+    // 1CB OP_UNUSED_CBFF
+    DF_NOP,
+
+    // 1CC OP_UNUSED_CCFF
+    DF_NOP,
+
+    // 1CD OP_UNUSED_CDFF
+    DF_NOP,
+
+    // 1CE OP_UNUSED_CEFF
+    DF_NOP,
+
+    // 1CF OP_UNUSED_CFFF
+    DF_NOP,
+
+    // 1D0 OP_UNUSED_D0FF
+    DF_NOP,
+
+    // 1D1 OP_UNUSED_D1FF
+    DF_NOP,
+
+    // 1D2 OP_UNUSED_D2FF
+    DF_NOP,
+
+    // 1D3 OP_UNUSED_D3FF
+    DF_NOP,
+
+    // 1D4 OP_UNUSED_D4FF
+    DF_NOP,
+
+    // 1D5 OP_UNUSED_D5FF
+    DF_NOP,
+
+    // 1D6 OP_UNUSED_D6FF
+    DF_NOP,
+
+    // 1D7 OP_UNUSED_D7FF
+    DF_NOP,
+
+    // 1D8 OP_UNUSED_D8FF
+    DF_NOP,
+
+    // 1D9 OP_UNUSED_D9FF
+    DF_NOP,
+
+    // 1DA OP_UNUSED_DAFF
+    DF_NOP,
+
+    // 1DB OP_UNUSED_DBFF
+    DF_NOP,
+
+    // 1DC OP_UNUSED_DCFF
+    DF_NOP,
+
+    // 1DD OP_UNUSED_DDFF
+    DF_NOP,
+
+    // 1DE OP_UNUSED_DEFF
+    DF_NOP,
+
+    // 1DF OP_UNUSED_DFFF
+    DF_NOP,
+
+    // 1E0 OP_UNUSED_E0FF
+    DF_NOP,
+
+    // 1E1 OP_UNUSED_E1FF
+    DF_NOP,
+
+    // 1E2 OP_UNUSED_E2FF
+    DF_NOP,
+
+    // 1E3 OP_UNUSED_E3FF
+    DF_NOP,
+
+    // 1E4 OP_UNUSED_E4FF
+    DF_NOP,
+
+    // 1E5 OP_UNUSED_E5FF
+    DF_NOP,
+
+    // 1E6 OP_UNUSED_E6FF
+    DF_NOP,
+
+    // 1E7 OP_UNUSED_E7FF
+    DF_NOP,
+
+    // 1E8 OP_UNUSED_E8FF
+    DF_NOP,
+
+    // 1E9 OP_UNUSED_E9FF
+    DF_NOP,
+
+    // 1EA OP_UNUSED_EAFF
+    DF_NOP,
+
+    // 1EB OP_UNUSED_EBFF
+    DF_NOP,
+
+    // 1EC OP_UNUSED_ECFF
+    DF_NOP,
+
+    // 1ED OP_UNUSED_EDFF
+    DF_NOP,
+
+    // 1EE OP_UNUSED_EEFF
+    DF_NOP,
+
+    // 1EF OP_UNUSED_EFFF
+    DF_NOP,
+
+    // 1F0 OP_UNUSED_F0FF
+    DF_NOP,
+
+    // 1F1 OP_UNUSED_F1FF
+    DF_NOP,
+
+    // 1F2 OP_INVOKE_OBJECT_INIT_JUMBO
+    DF_NOP,
+
+    // 1F3 OP_IGET_VOLATILE_JUMBO
+    DF_DA | DF_UB,
+
+    // 1F4 OP_IGET_WIDE_VOLATILE_JUMBO
+    DF_DA_WIDE | DF_UB,
+
+    // 1F5 OP_IGET_OBJECT_VOLATILE_JUMBO
+    DF_DA | DF_UB,
+
+    // 1F6 OP_IPUT_VOLATILE_JUMBO
+    DF_UA | DF_UB,
+
+    // 1F7 OP_IPUT_WIDE_VOLATILE_JUMBO
+    DF_UA_WIDE | DF_UB,
+
+    // 1F8 OP_IPUT_OBJECT_VOLATILE_JUMBO
+    DF_UA | DF_UB,
+
+    // 1F9 OP_SGET_VOLATILE_JUMBO
+    DF_DA,
+
+    // 1FA OP_SGET_WIDE_VOLATILE_JUMBO
+    DF_DA_WIDE,
+
+    // 1FB OP_SGET_OBJECT_VOLATILE_JUMBO
+    DF_DA,
+
+    // 1FC OP_SPUT_VOLATILE_JUMBO
+    DF_UA,
+
+    // 1FD OP_SPUT_WIDE_VOLATILE_JUMBO
+    DF_UA_WIDE,
+
+    // 1FE OP_SPUT_OBJECT_VOLATILE_JUMBO
+    DF_UA,
+
+    // 1FF OP_THROW_VERIFICATION_ERROR_JUMBO
+    DF_NOP,
+
+    // Beginning of extended MIR opcodes
+    // 200 OP_MIR_PHI
+    DF_PHI | DF_DA,
+    /*
+     * For extended MIR inserted at the MIR2LIR stage, it is okay to have
+     * undefined values here.
+     */
+};
+
+/* Return the Dalvik register/subscript pair of a given SSA register */
+int dvmConvertSSARegToDalvik(const CompilationUnit *cUnit, int ssaReg)
+{
+      return GET_ELEM_N(cUnit->ssaToDalvikMap, int, ssaReg);
+}
+
+/*
+ * Utility function to convert encoded SSA register value into Dalvik register
+ * and subscript pair. Each SSA register can be used to index the
+ * ssaToDalvikMap list to get the subscript[31..16]/dalvik_reg[15..0] mapping.
+ */
+char *dvmCompilerGetDalvikDisassembly(const DecodedInstruction *insn,
+                                      const char *note)
+{
+    char buffer[256];
+    Opcode opcode = insn->opcode;
+    int dfAttributes = dvmCompilerDataFlowAttributes[opcode];
+    int flags;
+    char *ret;
+
+    buffer[0] = 0;
+    if ((int)opcode >= (int)kMirOpFirst) {
+        if ((int)opcode == (int)kMirOpPhi) {
+            strcpy(buffer, "PHI");
+        }
+        else {
+            sprintf(buffer, "Opcode %#x", opcode);
+        }
+        flags = 0;
+    } else {
+        strcpy(buffer, dexGetOpcodeName(opcode));
+        flags = dexGetFlagsFromOpcode(insn->opcode);
+    }
+
+    if (note)
+        strcat(buffer, note);
+
+    /* For branches, decode the instructions to print out the branch targets */
+    if (flags & kInstrCanBranch) {
+        InstructionFormat dalvikFormat = dexGetFormatFromOpcode(insn->opcode);
+        int offset = 0;
+        switch (dalvikFormat) {
+            case kFmt21t:
+                snprintf(buffer + strlen(buffer), 256, " v%d,", insn->vA);
+                offset = (int) insn->vB;
+                break;
+            case kFmt22t:
+                snprintf(buffer + strlen(buffer), 256, " v%d, v%d,",
+                         insn->vA, insn->vB);
+                offset = (int) insn->vC;
+                break;
+            case kFmt10t:
+            case kFmt20t:
+            case kFmt30t:
+                offset = (int) insn->vA;
+                break;
+            default:
+                LOGE("Unexpected branch format %d / opcode %#x", dalvikFormat,
+                     opcode);
+                dvmAbort();
+                break;
+        }
+        snprintf(buffer + strlen(buffer), 256, " (%c%x)",
+                 offset > 0 ? '+' : '-',
+                 offset > 0 ? offset : -offset);
+    } else if (dfAttributes & DF_FORMAT_35C) {
+        unsigned int i;
+        for (i = 0; i < insn->vA; i++) {
+            if (i != 0) strcat(buffer, ",");
+            snprintf(buffer + strlen(buffer), 256, " v%d", insn->arg[i]);
+        }
+    }
+    else if (dfAttributes & DF_FORMAT_3RC) {
+        snprintf(buffer + strlen(buffer), 256,
+                 " v%d..v%d", insn->vC, insn->vC + insn->vA - 1);
+    }
+    else {
+        if (dfAttributes & DF_A_IS_REG) {
+            snprintf(buffer + strlen(buffer), 256, " v%d", insn->vA);
+        }
+        if (dfAttributes & DF_B_IS_REG) {
+            snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vB);
+        }
+        else if ((int)opcode < (int)kMirOpFirst) {
+            snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vB);
+        }
+        if (dfAttributes & DF_C_IS_REG) {
+            snprintf(buffer + strlen(buffer), 256, ", v%d", insn->vC);
+        }
+        else if ((int)opcode < (int)kMirOpFirst) {
+            snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn->vC);
+        }
+    }
+    int length = strlen(buffer) + 1;
+    ret = (char *)dvmCompilerNew(length, false);
+    memcpy(ret, buffer, length);
+    return ret;
+}
+
+char *getSSAName(const CompilationUnit *cUnit, int ssaReg, char *name)
+{
+    int ssa2DalvikValue = dvmConvertSSARegToDalvik(cUnit, ssaReg);
+
+    sprintf(name, "v%d_%d",
+            DECODE_REG(ssa2DalvikValue), DECODE_SUB(ssa2DalvikValue));
+    return name;
+}
+
+/*
+ * Dalvik instruction disassembler with optional SSA printing.
+ */
+char *dvmCompilerFullDisassembler(const CompilationUnit *cUnit,
+                                  const MIR *mir)
+{
+    char buffer[256];
+    char operand0[256], operand1[256];
+    const DecodedInstruction *insn = &mir->dalvikInsn;
+    int opcode = insn->opcode;
+    int dfAttributes = dvmCompilerDataFlowAttributes[opcode];
+    char *ret;
+    int length;
+    OpcodeFlags flags;
+
+    buffer[0] = 0;
+    if (opcode >= kMirOpFirst) {
+        if (opcode == kMirOpPhi) {
+            snprintf(buffer, 256, "PHI %s = (%s",
+                     getSSAName(cUnit, mir->ssaRep->defs[0], operand0),
+                     getSSAName(cUnit, mir->ssaRep->uses[0], operand1));
+            int i;
+            for (i = 1; i < mir->ssaRep->numUses; i++) {
+                snprintf(buffer + strlen(buffer), 256, ", %s",
+                         getSSAName(cUnit, mir->ssaRep->uses[i], operand0));
+            }
+            snprintf(buffer + strlen(buffer), 256, ")");
+        }
+        else {
+            sprintf(buffer, "Opcode %#x", opcode);
+        }
+        goto done;
+    } else {
+        strcpy(buffer, dexGetOpcodeName((Opcode)opcode));
+    }
+
+    flags = dexGetFlagsFromOpcode((Opcode)opcode);
+    /* For branches, decode the instructions to print out the branch targets */
+    if (flags & kInstrCanBranch) {
+        InstructionFormat dalvikFormat = dexGetFormatFromOpcode(insn->opcode);
+        int delta = 0;
+        switch (dalvikFormat) {
+            case kFmt21t:
+                snprintf(buffer + strlen(buffer), 256, " %s, ",
+                         getSSAName(cUnit, mir->ssaRep->uses[0], operand0));
+                delta = (int) insn->vB;
+                break;
+            case kFmt22t:
+                snprintf(buffer + strlen(buffer), 256, " %s, %s, ",
+                         getSSAName(cUnit, mir->ssaRep->uses[0], operand0),
+                         getSSAName(cUnit, mir->ssaRep->uses[1], operand1));
+                delta = (int) insn->vC;
+                break;
+            case kFmt10t:
+            case kFmt20t:
+            case kFmt30t:
+                delta = (int) insn->vA;
+                break;
+            default:
+                LOGE("Unexpected branch format: %d", dalvikFormat);
+                dvmAbort();
+                break;
+        }
+        snprintf(buffer + strlen(buffer), 256, " %04x",
+                 mir->offset + delta);
+    } else if (dfAttributes & (DF_FORMAT_35C | DF_FORMAT_3RC)) {
+        unsigned int i;
+        for (i = 0; i < insn->vA; i++) {
+            if (i != 0) strcat(buffer, ",");
+            snprintf(buffer + strlen(buffer), 256, " %s",
+                     getSSAName(cUnit, mir->ssaRep->uses[i], operand0));
+        }
+    } else {
+        int udIdx;
+        if (mir->ssaRep->numDefs) {
+
+            for (udIdx = 0; udIdx < mir->ssaRep->numDefs; udIdx++) {
+                snprintf(buffer + strlen(buffer), 256, " %s",
+                         getSSAName(cUnit, mir->ssaRep->defs[udIdx], operand0));
+            }
+            strcat(buffer, ",");
+        }
+        if (mir->ssaRep->numUses) {
+            /* No leading ',' for the first use */
+            snprintf(buffer + strlen(buffer), 256, " %s",
+                     getSSAName(cUnit, mir->ssaRep->uses[0], operand0));
+            for (udIdx = 1; udIdx < mir->ssaRep->numUses; udIdx++) {
+                snprintf(buffer + strlen(buffer), 256, ", %s",
+                         getSSAName(cUnit, mir->ssaRep->uses[udIdx], operand0));
+            }
+        }
+        if (opcode < kMirOpFirst) {
+            InstructionFormat dalvikFormat =
+                dexGetFormatFromOpcode((Opcode)opcode);
+            switch (dalvikFormat) {
+                case kFmt11n:        // op vA, #+B
+                case kFmt21s:        // op vAA, #+BBBB
+                case kFmt21h:        // op vAA, #+BBBB00000[00000000]
+                case kFmt31i:        // op vAA, #+BBBBBBBB
+                case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB
+                    snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vB);
+                    break;
+                case kFmt21c:        // op vAA, thing@BBBB
+                case kFmt31c:        // op vAA, thing@BBBBBBBB
+                    snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vB);
+                    break;
+                case kFmt22b:        // op vAA, vBB, #+CC
+                case kFmt22s:        // op vA, vB, #+CCCC
+                    snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vC);
+                    break;
+                case kFmt22c:        // op vA, vB, thing@CCCC
+                case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
+                    snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vC);
+                    break;
+                    /* No need for special printing */
+                default:
+                    break;
+            }
+        }
+    }
+
+done:
+    length = strlen(buffer) + 1;
+    ret = (char *) dvmCompilerNew(length, false);
+    memcpy(ret, buffer, length);
+    return ret;
+}
+
+/*
+ * Utility function to convert encoded SSA register value into Dalvik register
+ * and subscript pair. Each SSA register can be used to index the
+ * ssaToDalvikMap list to get the subscript[31..16]/dalvik_reg[15..0] mapping.
+ */
+char *dvmCompilerGetSSAString(CompilationUnit *cUnit, SSARepresentation *ssaRep)
+{
+    char buffer[256];
+    char *ret;
+    int i;
+
+    buffer[0] = 0;
+    for (i = 0; i < ssaRep->numDefs; i++) {
+        int ssa2DalvikValue = dvmConvertSSARegToDalvik(cUnit, ssaRep->defs[i]);
+
+        sprintf(buffer + strlen(buffer), "s%d(v%d_%d) ",
+                ssaRep->defs[i], DECODE_REG(ssa2DalvikValue),
+                DECODE_SUB(ssa2DalvikValue));
+    }
+
+    if (ssaRep->numDefs) {
+        strcat(buffer, "<- ");
+    }
+
+    for (i = 0; i < ssaRep->numUses; i++) {
+        int ssa2DalvikValue = dvmConvertSSARegToDalvik(cUnit, ssaRep->uses[i]);
+        int len = strlen(buffer);
+
+        if (snprintf(buffer + len, 250 - len, "s%d(v%d_%d) ",
+                     ssaRep->uses[i], DECODE_REG(ssa2DalvikValue),
+                     DECODE_SUB(ssa2DalvikValue)) >= (250 - len)) {
+            strcat(buffer, "...");
+            break;
+        }
+    }
+
+    int length = strlen(buffer) + 1;
+    ret = (char *)dvmCompilerNew(length, false);
+    memcpy(ret, buffer, length);
+    return ret;
+}
+
+/* Any register that is used before being defined is considered live-in */
+static inline void handleLiveInUse(BitVector *useV, BitVector *defV,
+                                   BitVector *liveInV, int dalvikRegId)
+{
+    dvmCompilerSetBit(useV, dalvikRegId);
+    if (!dvmIsBitSet(defV, dalvikRegId)) {
+        dvmCompilerSetBit(liveInV, dalvikRegId);
+    }
+}
+
+/* Mark a reg as being defined */
+static inline void handleDef(BitVector *defV, int dalvikRegId)
+{
+    dvmCompilerSetBit(defV, dalvikRegId);
+}
+
+/*
+ * Find out live-in variables for natural loops. Variables that are live-in in
+ * the main loop body are considered to be defined in the entry block.
+ */
+bool dvmCompilerFindLocalLiveIn(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+    BitVector *useV, *defV, *liveInV;
+
+    if (bb->dataFlowInfo == NULL) return false;
+
+    useV = bb->dataFlowInfo->useV =
+        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+    defV = bb->dataFlowInfo->defV =
+        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+    liveInV = bb->dataFlowInfo->liveInV =
+        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        int dfAttributes =
+            dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+        DecodedInstruction *dInsn = &mir->dalvikInsn;
+
+        if (dfAttributes & DF_HAS_USES) {
+            if (dfAttributes & DF_UA) {
+                handleLiveInUse(useV, defV, liveInV, dInsn->vA);
+            } else if (dfAttributes & DF_UA_WIDE) {
+                handleLiveInUse(useV, defV, liveInV, dInsn->vA);
+                handleLiveInUse(useV, defV, liveInV, dInsn->vA+1);
+            }
+            if (dfAttributes & DF_UB) {
+                handleLiveInUse(useV, defV, liveInV, dInsn->vB);
+            } else if (dfAttributes & DF_UB_WIDE) {
+                handleLiveInUse(useV, defV, liveInV, dInsn->vB);
+                handleLiveInUse(useV, defV, liveInV, dInsn->vB+1);
+            }
+            if (dfAttributes & DF_UC) {
+                handleLiveInUse(useV, defV, liveInV, dInsn->vC);
+            } else if (dfAttributes & DF_UC_WIDE) {
+                handleLiveInUse(useV, defV, liveInV, dInsn->vC);
+                handleLiveInUse(useV, defV, liveInV, dInsn->vC+1);
+            }
+        }
+        if (dfAttributes & DF_HAS_DEFS) {
+            handleDef(defV, dInsn->vA);
+            if (dfAttributes & DF_DA_WIDE) {
+                handleDef(defV, dInsn->vA+1);
+            }
+        }
+    }
+    return true;
+}
+
+/* Find out the latest SSA register for a given Dalvik register */
+static void handleSSAUse(CompilationUnit *cUnit, int *uses, int dalvikReg,
+                         int regIndex)
+{
+    int encodedValue = cUnit->dalvikToSSAMap[dalvikReg];
+    int ssaReg = DECODE_REG(encodedValue);
+    uses[regIndex] = ssaReg;
+}
+
+/* Setup a new SSA register for a given Dalvik register */
+static void handleSSADef(CompilationUnit *cUnit, int *defs, int dalvikReg,
+                         int regIndex)
+{
+    int encodedValue = cUnit->dalvikToSSAMap[dalvikReg];
+    int ssaReg = cUnit->numSSARegs++;
+    /* Bump up the subscript */
+    int dalvikSub = DECODE_SUB(encodedValue) + 1;
+    int newD2SMapping = ENCODE_REG_SUB(ssaReg, dalvikSub);
+
+    cUnit->dalvikToSSAMap[dalvikReg] = newD2SMapping;
+
+    int newS2DMapping = ENCODE_REG_SUB(dalvikReg, dalvikSub);
+    dvmInsertGrowableList(cUnit->ssaToDalvikMap, newS2DMapping);
+
+    defs[regIndex] = ssaReg;
+}
+
+/* Loop up new SSA names for format_35c instructions */
+static void dataFlowSSAFormat35C(CompilationUnit *cUnit, MIR *mir)
+{
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    int numUses = dInsn->vA;
+    int i;
+
+    mir->ssaRep->numUses = numUses;
+    mir->ssaRep->uses = (int *)dvmCompilerNew(sizeof(int) * numUses, false);
+
+    for (i = 0; i < numUses; i++) {
+        handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->arg[i], i);
+    }
+}
+
+/* Loop up new SSA names for format_3rc instructions */
+static void dataFlowSSAFormat3RC(CompilationUnit *cUnit, MIR *mir)
+{
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    int numUses = dInsn->vA;
+    int i;
+
+    mir->ssaRep->numUses = numUses;
+    mir->ssaRep->uses = (int *)dvmCompilerNew(sizeof(int) * numUses, false);
+
+    for (i = 0; i < numUses; i++) {
+        handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC+i, i);
+    }
+}
+
+/* Entry function to convert a block into SSA representation */
+bool dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+
+    if (bb->dataFlowInfo == NULL) return false;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        mir->ssaRep = (struct SSARepresentation *)
+            dvmCompilerNew(sizeof(SSARepresentation), true);
+
+        int dfAttributes =
+            dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+
+        int numUses = 0;
+
+        if (dfAttributes & DF_FORMAT_35C) {
+            dataFlowSSAFormat35C(cUnit, mir);
+            continue;
+        }
+
+        if (dfAttributes & DF_FORMAT_3RC) {
+            dataFlowSSAFormat3RC(cUnit, mir);
+            continue;
+        }
+
+        if (dfAttributes & DF_HAS_USES) {
+            if (dfAttributes & DF_UA) {
+                numUses++;
+            } else if (dfAttributes & DF_UA_WIDE) {
+                numUses += 2;
+            }
+            if (dfAttributes & DF_UB) {
+                numUses++;
+            } else if (dfAttributes & DF_UB_WIDE) {
+                numUses += 2;
+            }
+            if (dfAttributes & DF_UC) {
+                numUses++;
+            } else if (dfAttributes & DF_UC_WIDE) {
+                numUses += 2;
+            }
+        }
+
+        if (numUses) {
+            mir->ssaRep->numUses = numUses;
+            mir->ssaRep->uses = (int *)dvmCompilerNew(sizeof(int) * numUses,
+                                                      false);
+            mir->ssaRep->fpUse = (bool *)dvmCompilerNew(sizeof(bool) * numUses,
+                                                false);
+        }
+
+        int numDefs = 0;
+
+        if (dfAttributes & DF_HAS_DEFS) {
+            numDefs++;
+            if (dfAttributes & DF_DA_WIDE) {
+                numDefs++;
+            }
+        }
+
+        if (numDefs) {
+            mir->ssaRep->numDefs = numDefs;
+            mir->ssaRep->defs = (int *)dvmCompilerNew(sizeof(int) * numDefs,
+                                                      false);
+            mir->ssaRep->fpDef = (bool *)dvmCompilerNew(sizeof(bool) * numDefs,
+                                                        false);
+        }
+
+        DecodedInstruction *dInsn = &mir->dalvikInsn;
+
+        if (dfAttributes & DF_HAS_USES) {
+            numUses = 0;
+            if (dfAttributes & DF_UA) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA, numUses++);
+            } else if (dfAttributes & DF_UA_WIDE) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA, numUses++);
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA+1, numUses++);
+            }
+            if (dfAttributes & DF_UB) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB, numUses++);
+            } else if (dfAttributes & DF_UB_WIDE) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB, numUses++);
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB+1, numUses++);
+            }
+            if (dfAttributes & DF_UC) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC, numUses++);
+            } else if (dfAttributes & DF_UC_WIDE) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC, numUses++);
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
+                handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC+1, numUses++);
+            }
+        }
+        if (dfAttributes & DF_HAS_DEFS) {
+            mir->ssaRep->fpDef[0] = dfAttributes & DF_FP_A;
+            handleSSADef(cUnit, mir->ssaRep->defs, dInsn->vA, 0);
+            if (dfAttributes & DF_DA_WIDE) {
+                mir->ssaRep->fpDef[1] = dfAttributes & DF_FP_A;
+                handleSSADef(cUnit, mir->ssaRep->defs, dInsn->vA+1, 1);
+            }
+        }
+    }
+
+    /*
+     * Take a snapshot of Dalvik->SSA mapping at the end of each block. The
+     * input to PHI nodes can be derived from the snapshot of all predecessor
+     * blocks.
+     */
+    bb->dataFlowInfo->dalvikToSSAMap =
+        (int *)dvmCompilerNew(sizeof(int) * cUnit->method->registersSize,
+                              false);
+
+    memcpy(bb->dataFlowInfo->dalvikToSSAMap, cUnit->dalvikToSSAMap,
+           sizeof(int) * cUnit->method->registersSize);
+    return true;
+}
+
+/* Setup a constant value for opcodes thare have the DF_SETS_CONST attribute */
+static void setConstant(CompilationUnit *cUnit, int ssaReg, int value)
+{
+    dvmSetBit(cUnit->isConstantV, ssaReg);
+    cUnit->constantValues[ssaReg] = value;
+}
+
+bool dvmCompilerDoConstantPropagation(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+    BitVector *isConstantV = cUnit->isConstantV;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        int dfAttributes =
+            dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+
+        DecodedInstruction *dInsn = &mir->dalvikInsn;
+
+        if (!(dfAttributes & DF_HAS_DEFS)) continue;
+
+        /* Handle instructions that set up constants directly */
+        if (dfAttributes & DF_SETS_CONST) {
+            if (dfAttributes & DF_DA) {
+                switch (dInsn->opcode) {
+                    case OP_CONST_4:
+                    case OP_CONST_16:
+                    case OP_CONST:
+                        setConstant(cUnit, mir->ssaRep->defs[0], dInsn->vB);
+                        break;
+                    case OP_CONST_HIGH16:
+                        setConstant(cUnit, mir->ssaRep->defs[0],
+                                    dInsn->vB << 16);
+                        break;
+                    default:
+                        break;
+                }
+            } else if (dfAttributes & DF_DA_WIDE) {
+                switch (dInsn->opcode) {
+                    case OP_CONST_WIDE_16:
+                    case OP_CONST_WIDE_32:
+                        setConstant(cUnit, mir->ssaRep->defs[0], dInsn->vB);
+                        setConstant(cUnit, mir->ssaRep->defs[1], 0);
+                        break;
+                    case OP_CONST_WIDE:
+                        setConstant(cUnit, mir->ssaRep->defs[0],
+                                    (int) dInsn->vB_wide);
+                        setConstant(cUnit, mir->ssaRep->defs[1],
+                                    (int) (dInsn->vB_wide >> 32));
+                        break;
+                    case OP_CONST_WIDE_HIGH16:
+                        setConstant(cUnit, mir->ssaRep->defs[0], 0);
+                        setConstant(cUnit, mir->ssaRep->defs[1],
+                                    dInsn->vB << 16);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        /* Handle instructions that set up constants directly */
+        } else if (dfAttributes & DF_IS_MOVE) {
+            int i;
+
+            for (i = 0; i < mir->ssaRep->numUses; i++) {
+                if (!dvmIsBitSet(isConstantV, mir->ssaRep->uses[i])) break;
+            }
+            /* Move a register holding a constant to another register */
+            if (i == mir->ssaRep->numUses) {
+                setConstant(cUnit, mir->ssaRep->defs[0],
+                            cUnit->constantValues[mir->ssaRep->uses[0]]);
+                if (dfAttributes & DF_DA_WIDE) {
+                    setConstant(cUnit, mir->ssaRep->defs[1],
+                                cUnit->constantValues[mir->ssaRep->uses[1]]);
+                }
+            }
+        }
+    }
+    /* TODO: implement code to handle arithmetic operations */
+    return true;
+}
+
+bool dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
+                                       struct BasicBlock *bb)
+{
+    BitVector *isIndVarV = cUnit->loopAnalysis->isIndVarV;
+    BitVector *isConstantV = cUnit->isConstantV;
+    GrowableList *ivList = cUnit->loopAnalysis->ivList;
+    MIR *mir;
+
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock) {
+        return false;
+    }
+
+    /* If the bb doesn't have a phi it cannot contain an induction variable */
+    if (bb->firstMIRInsn == NULL ||
+        (int)bb->firstMIRInsn->dalvikInsn.opcode != (int)kMirOpPhi) {
+        return false;
+    }
+
+    /* Find basic induction variable first */
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        int dfAttributes =
+            dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+
+        if (!(dfAttributes & DF_IS_LINEAR)) continue;
+
+        /*
+         * For a basic induction variable:
+         *   1) use[0] should belong to the output of a phi node
+         *   2) def[0] should belong to the input of the same phi node
+         *   3) the value added/subtracted is a constant
+         */
+        MIR *phi;
+        for (phi = bb->firstMIRInsn; phi; phi = phi->next) {
+            if ((int)phi->dalvikInsn.opcode != (int)kMirOpPhi) break;
+
+            if (phi->ssaRep->defs[0] == mir->ssaRep->uses[0] &&
+                phi->ssaRep->uses[1] == mir->ssaRep->defs[0]) {
+                bool deltaIsConstant = false;
+                int deltaValue;
+
+                switch (mir->dalvikInsn.opcode) {
+                    case OP_ADD_INT:
+                        if (dvmIsBitSet(isConstantV,
+                                        mir->ssaRep->uses[1])) {
+                            deltaValue =
+                                cUnit->constantValues[mir->ssaRep->uses[1]];
+                            deltaIsConstant = true;
+                        }
+                        break;
+                    case OP_SUB_INT:
+                        if (dvmIsBitSet(isConstantV,
+                                        mir->ssaRep->uses[1])) {
+                            deltaValue =
+                                -cUnit->constantValues[mir->ssaRep->uses[1]];
+                            deltaIsConstant = true;
+                        }
+                        break;
+                    case OP_ADD_INT_LIT8:
+                        deltaValue = mir->dalvikInsn.vC;
+                        deltaIsConstant = true;
+                        break;
+                    default:
+                        break;
+                }
+                if (deltaIsConstant) {
+                    dvmSetBit(isIndVarV, mir->ssaRep->uses[0]);
+                    InductionVariableInfo *ivInfo = (InductionVariableInfo *)
+                        dvmCompilerNew(sizeof(InductionVariableInfo),
+                                       false);
+
+                    ivInfo->ssaReg = mir->ssaRep->uses[0];
+                    ivInfo->basicSSAReg = mir->ssaRep->uses[0];
+                    ivInfo->m = 1;         // always 1 to basic iv
+                    ivInfo->c = 0;         // N/A to basic iv
+                    ivInfo->inc = deltaValue;
+                    dvmInsertGrowableList(ivList, (intptr_t) ivInfo);
+                    cUnit->loopAnalysis->numBasicIV++;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* Find dependent induction variable now */
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        int dfAttributes =
+            dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+
+        if (!(dfAttributes & DF_IS_LINEAR)) continue;
+
+        /* Skip already identified induction variables */
+        if (dvmIsBitSet(isIndVarV, mir->ssaRep->defs[0])) continue;
+
+        /*
+         * For a dependent induction variable:
+         *  1) use[0] should be an induction variable (basic/dependent)
+         *  2) operand2 should be a constant
+         */
+        if (dvmIsBitSet(isIndVarV, mir->ssaRep->uses[0])) {
+            int srcDalvikReg = dvmConvertSSARegToDalvik(cUnit,
+                                                        mir->ssaRep->uses[0]);
+            int dstDalvikReg = dvmConvertSSARegToDalvik(cUnit,
+                                                        mir->ssaRep->defs[0]);
+
+            bool cIsConstant = false;
+            int c = 0;
+
+            switch (mir->dalvikInsn.opcode) {
+                case OP_ADD_INT:
+                    if (dvmIsBitSet(isConstantV,
+                                    mir->ssaRep->uses[1])) {
+                        c = cUnit->constantValues[mir->ssaRep->uses[1]];
+                        cIsConstant = true;
+                    }
+                    break;
+                case OP_SUB_INT:
+                    if (dvmIsBitSet(isConstantV,
+                                    mir->ssaRep->uses[1])) {
+                        c = -cUnit->constantValues[mir->ssaRep->uses[1]];
+                        cIsConstant = true;
+                    }
+                    break;
+                case OP_ADD_INT_LIT8:
+                    c = mir->dalvikInsn.vC;
+                    cIsConstant = true;
+                    break;
+                default:
+                    break;
+            }
+
+            /* Ignore the update to the basic induction variable itself */
+            if (DECODE_REG(srcDalvikReg) == DECODE_REG(dstDalvikReg))  {
+                cUnit->loopAnalysis->ssaBIV = mir->ssaRep->defs[0];
+                cIsConstant = false;
+            }
+
+            if (cIsConstant) {
+                unsigned int i;
+                dvmSetBit(isIndVarV, mir->ssaRep->defs[0]);
+                InductionVariableInfo *ivInfo = (InductionVariableInfo *)
+                    dvmCompilerNew(sizeof(InductionVariableInfo),
+                                   false);
+                InductionVariableInfo *ivInfoOld = NULL ;
+
+                for (i = 0; i < ivList->numUsed; i++) {
+                    ivInfoOld = (InductionVariableInfo *) ivList->elemList[i];
+                    if (ivInfoOld->ssaReg == mir->ssaRep->uses[0]) break;
+                }
+
+                /* Guaranteed to find an element */
+                assert(i < ivList->numUsed);
+
+                ivInfo->ssaReg = mir->ssaRep->defs[0];
+                ivInfo->basicSSAReg = ivInfoOld->basicSSAReg;
+                ivInfo->m = ivInfoOld->m;
+                ivInfo->c = c + ivInfoOld->c;
+                ivInfo->inc = ivInfoOld->inc;
+                dvmInsertGrowableList(ivList, (intptr_t) ivInfo);
+            }
+        }
+    }
+    return true;
+}
+
+/* Setup the basic data structures for SSA conversion */
+void dvmInitializeSSAConversion(CompilationUnit *cUnit)
+{
+    int i;
+    int numDalvikReg = cUnit->method->registersSize;
+
+    cUnit->ssaToDalvikMap = (GrowableList *)dvmCompilerNew(sizeof(GrowableList),
+                                                           false);
+    dvmInitGrowableList(cUnit->ssaToDalvikMap, numDalvikReg);
+
+    /*
+     * Initial number of SSA registers is equal to the number of Dalvik
+     * registers.
+     */
+    cUnit->numSSARegs = numDalvikReg;
+
+    /*
+     * Initialize the SSA2Dalvik map list. For the first numDalvikReg elements,
+     * the subscript is 0 so we use the ENCODE_REG_SUB macro to encode the value
+     * into "(0 << 16) | i"
+     */
+    for (i = 0; i < numDalvikReg; i++) {
+        dvmInsertGrowableList(cUnit->ssaToDalvikMap, ENCODE_REG_SUB(i, 0));
+    }
+
+    /*
+     * Initialize the DalvikToSSAMap map. The low 16 bit is the SSA register id,
+     * while the high 16 bit is the current subscript. The original Dalvik
+     * register N is mapped to SSA register N with subscript 0.
+     */
+    cUnit->dalvikToSSAMap = (int *)dvmCompilerNew(sizeof(int) * numDalvikReg,
+                                                  false);
+    for (i = 0; i < numDalvikReg; i++) {
+        cUnit->dalvikToSSAMap[i] = i;
+    }
+
+    /*
+     * Allocate the BasicBlockDataFlow structure for the entry and code blocks
+     */
+    GrowableListIterator iterator;
+
+    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+
+    while (true) {
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        if (bb->hidden == true) continue;
+        if (bb->blockType == kDalvikByteCode ||
+            bb->blockType == kEntryBlock ||
+            bb->blockType == kExitBlock) {
+            bb->dataFlowInfo = (BasicBlockDataFlow *)
+                dvmCompilerNew(sizeof(BasicBlockDataFlow),
+                               true);
+        }
+    }
+}
+
+/* Clear the visited flag for each BB */
+bool dvmCompilerClearVisitedFlag(struct CompilationUnit *cUnit,
+                                 struct BasicBlock *bb)
+{
+    bb->visited = false;
+    return true;
+}
+
+void dvmCompilerDataFlowAnalysisDispatcher(CompilationUnit *cUnit,
+                bool (*func)(CompilationUnit *, BasicBlock *),
+                DataFlowAnalysisMode dfaMode,
+                bool isIterative)
+{
+    bool change = true;
+
+    while (change) {
+        change = false;
+
+        /* Scan all blocks and perform the operations specified in func */
+        if (dfaMode == kAllNodes) {
+            GrowableListIterator iterator;
+            dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+            while (true) {
+                BasicBlock *bb =
+                    (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+                if (bb == NULL) break;
+                if (bb->hidden == true) continue;
+                change |= (*func)(cUnit, bb);
+            }
+        }
+        /*
+         * Scan all reachable blocks and perform the operations specified in
+         * func.
+         */
+        else if (dfaMode == kReachableNodes) {
+            int numReachableBlocks = cUnit->numReachableBlocks;
+            int idx;
+            const GrowableList *blockList = &cUnit->blockList;
+
+            for (idx = 0; idx < numReachableBlocks; idx++) {
+                int blockIdx = cUnit->dfsOrder.elemList[idx];
+                BasicBlock *bb =
+                    (BasicBlock *) dvmGrowableListGetElement(blockList,
+                                                             blockIdx);
+                change |= (*func)(cUnit, bb);
+            }
+        }
+        /*
+         * Scan all reachable blocks by the pre-order in the depth-first-search
+         * CFG and perform the operations specified in func.
+         */
+        else if (dfaMode == kPreOrderDFSTraversal) {
+            int numReachableBlocks = cUnit->numReachableBlocks;
+            int idx;
+            const GrowableList *blockList = &cUnit->blockList;
+
+            for (idx = 0; idx < numReachableBlocks; idx++) {
+                int dfsIdx = cUnit->dfsOrder.elemList[idx];
+                BasicBlock *bb =
+                    (BasicBlock *) dvmGrowableListGetElement(blockList, dfsIdx);
+                change |= (*func)(cUnit, bb);
+            }
+        }
+        /*
+         * Scan all reachable blocks by the post-order in the depth-first-search
+         * CFG and perform the operations specified in func.
+         */
+        else if (dfaMode == kPostOrderDFSTraversal) {
+            int numReachableBlocks = cUnit->numReachableBlocks;
+            int idx;
+            const GrowableList *blockList = &cUnit->blockList;
+
+            for (idx = numReachableBlocks - 1; idx >= 0; idx--) {
+                int dfsIdx = cUnit->dfsOrder.elemList[idx];
+                BasicBlock *bb =
+                    (BasicBlock *) dvmGrowableListGetElement(blockList, dfsIdx);
+                change |= (*func)(cUnit, bb);
+            }
+        }
+        /*
+         * Scan all reachable blocks by the post-order in the dominator tree
+         * and perform the operations specified in func.
+         */
+        else if (dfaMode == kPostOrderDOMTraversal) {
+            int numReachableBlocks = cUnit->numReachableBlocks;
+            int idx;
+            const GrowableList *blockList = &cUnit->blockList;
+
+            for (idx = 0; idx < numReachableBlocks; idx++) {
+                int domIdx = cUnit->domPostOrderTraversal.elemList[idx];
+                BasicBlock *bb =
+                    (BasicBlock *) dvmGrowableListGetElement(blockList, domIdx);
+                change |= (*func)(cUnit, bb);
+            }
+        }
+        /* If isIterative is false, exit the loop after the first iteration */
+        change &= isIterative;
+    }
+}
+
+/* Main entry point to do SSA conversion for non-loop traces */
+void dvmCompilerNonLoopAnalysis(CompilationUnit *cUnit)
+{
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion,
+                                          kAllNodes,
+                                          false /* isIterative */);
+}
diff --git a/vm/compiler/Dataflow.h b/vm/compiler/Dataflow.h
new file mode 100644
index 0000000..f04c91c
--- /dev/null
+++ b/vm/compiler/Dataflow.h
@@ -0,0 +1,128 @@
+/*
+ * 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_DATAFLOW_H_
+#define DALVIK_VM_DATAFLOW_H_
+
+#include "Dalvik.h"
+#include "CompilerInternals.h"
+
+typedef enum DataFlowAttributePos {
+    kUA = 0,
+    kUB,
+    kUC,
+    kUAWide,
+    kUBWide,
+    kUCWide,
+    kDA,
+    kDAWide,
+    kIsMove,
+    kIsLinear,
+    kSetsConst,
+    kFormat35c,
+    kFormat3rc,
+    kPhi,
+    kNullNRangeCheck0,
+    kNullNRangeCheck1,
+    kNullNRangeCheck2,
+    kFPA,
+    kFPB,
+    kFPC,
+    kGetter,
+    kSetter,
+} DataFlowAttributes;
+
+#define DF_NOP                  0
+#define DF_UA                   (1 << kUA)
+#define DF_UB                   (1 << kUB)
+#define DF_UC                   (1 << kUC)
+#define DF_UA_WIDE              (1 << kUAWide)
+#define DF_UB_WIDE              (1 << kUBWide)
+#define DF_UC_WIDE              (1 << kUCWide)
+#define DF_DA                   (1 << kDA)
+#define DF_DA_WIDE              (1 << kDAWide)
+#define DF_IS_MOVE              (1 << kIsMove)
+#define DF_IS_LINEAR            (1 << kIsLinear)
+#define DF_SETS_CONST           (1 << kSetsConst)
+#define DF_FORMAT_35C           (1 << kFormat35c)
+#define DF_FORMAT_3RC           (1 << kFormat3rc)
+#define DF_PHI                  (1 << kPhi)
+#define DF_NULL_N_RANGE_CHECK_0 (1 << kNullNRangeCheck0)
+#define DF_NULL_N_RANGE_CHECK_1 (1 << kNullNRangeCheck1)
+#define DF_NULL_N_RANGE_CHECK_2 (1 << kNullNRangeCheck2)
+#define DF_FP_A                 (1 << kFPA)
+#define DF_FP_B                 (1 << kFPB)
+#define DF_FP_C                 (1 << kFPC)
+#define DF_IS_GETTER            (1 << kGetter)
+#define DF_IS_SETTER            (1 << kSetter)
+
+#define DF_HAS_USES             (DF_UA | DF_UB | DF_UC | DF_UA_WIDE | \
+                                 DF_UB_WIDE | DF_UC_WIDE)
+
+#define DF_HAS_DEFS             (DF_DA | DF_DA_WIDE)
+
+#define DF_HAS_NR_CHECKS        (DF_NULL_N_RANGE_CHECK_0 | \
+                                 DF_NULL_N_RANGE_CHECK_1 | \
+                                 DF_NULL_N_RANGE_CHECK_2)
+
+#define DF_A_IS_REG             (DF_UA | DF_UA_WIDE | DF_DA | DF_DA_WIDE)
+#define DF_B_IS_REG             (DF_UB | DF_UB_WIDE)
+#define DF_C_IS_REG             (DF_UC | DF_UC_WIDE)
+#define DF_IS_GETTER_OR_SETTER  (DF_IS_GETTER | DF_IS_SETTER)
+
+extern int dvmCompilerDataFlowAttributes[kMirOpLast];
+
+typedef struct BasicBlockDataFlow {
+    BitVector *useV;
+    BitVector *defV;
+    BitVector *liveInV;
+    BitVector *phiV;
+    int *dalvikToSSAMap;
+} BasicBlockDataFlow;
+
+typedef struct SSARepresentation {
+    int numUses;
+    int *uses;
+    bool *fpUse;
+    int numDefs;
+    int *defs;
+    bool *fpDef;
+} SSARepresentation;
+
+/*
+ * An induction variable is represented by "m*i + c", where i is a basic
+ * induction variable.
+ */
+typedef struct InductionVariableInfo {
+    int ssaReg;
+    int basicSSAReg;
+    int m;      // multiplier
+    int c;      // constant
+    int inc;    // loop incriment
+} InductionVariableInfo;
+
+typedef struct ArrayAccessInfo {
+    int arrayReg;
+    int ivReg;
+    int maxC;                   // For DIV - will affect upper bound checking
+    int minC;                   // For DIV - will affect lower bound checking
+} ArrayAccessInfo;
+
+#define ENCODE_REG_SUB(r,s)             ((s<<16) | r)
+#define DECODE_REG(v)                   (v & 0xffff)
+#define DECODE_SUB(v)                   (((unsigned int) v) >> 16)
+
+#endif  // DALVIK_VM_DATAFLOW_H_
diff --git a/vm/compiler/Frontend.cpp b/vm/compiler/Frontend.cpp
new file mode 100644
index 0000000..723de86
--- /dev/null
+++ b/vm/compiler/Frontend.cpp
@@ -0,0 +1,2145 @@
+/*
+ * 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/DexOpcodes.h"
+#include "libdex/DexCatch.h"
+#include "interp/Jit.h"
+#include "CompilerInternals.h"
+#include "Dataflow.h"
+
+static inline bool contentIsInsn(const u2 *codePtr) {
+    u2 instr = *codePtr;
+    Opcode opcode = (Opcode)(instr & 0xff);
+
+    /*
+     * Since the low 8-bit in metadata may look like OP_NOP, we need to check
+     * both the low and whole sub-word to determine whether it is code or data.
+     */
+    return (opcode != OP_NOP || instr == 0);
+}
+
+/*
+ * Parse an instruction, return the length of the instruction
+ */
+static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
+                            bool printMe)
+{
+    // Don't parse instruction data
+    if (!contentIsInsn(codePtr)) {
+        return 0;
+    }
+
+    u2 instr = *codePtr;
+    Opcode opcode = dexOpcodeFromCodeUnit(instr);
+
+    dexDecodeInstruction(codePtr, decInsn);
+    if (printMe) {
+        char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
+        LOGD("%p: %#06x %s", codePtr, opcode, decodedString);
+    }
+    return dexGetWidthFromOpcode(opcode);
+}
+
+#define UNKNOWN_TARGET 0xffffffff
+
+/*
+ * 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:
+          *target = UNKNOWN_TARGET;
+          break;
+        case OP_INVOKE_VIRTUAL:
+        case OP_INVOKE_VIRTUAL_RANGE:
+        case OP_INVOKE_VIRTUAL_JUMBO:
+        case OP_INVOKE_INTERFACE:
+        case OP_INVOKE_INTERFACE_RANGE:
+        case OP_INVOKE_INTERFACE_JUMBO:
+        case OP_INVOKE_VIRTUAL_QUICK:
+        case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+            *isInvoke = true;
+            break;
+        case OP_INVOKE_SUPER:
+        case OP_INVOKE_SUPER_RANGE:
+        case OP_INVOKE_SUPER_JUMBO: {
+            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:
+        case OP_INVOKE_STATIC_JUMBO: {
+            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:
+        case OP_INVOKE_DIRECT_JUMBO: {
+            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;
+}
+
+static inline bool isGoto(MIR *insn)
+{
+    switch (insn->dalvikInsn.opcode) {
+        case OP_GOTO:
+        case OP_GOTO_16:
+        case OP_GOTO_32:
+            return true;
+        default:
+            return false;
+    }
+}
+
+/*
+ * Identify unconditional 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:
+            return true;
+        default:
+            return isGoto(insn);
+    }
+}
+
+/*
+ * dvmHashTableLookup() callback
+ */
+static int compareMethod(const CompilerMethodStats *m1,
+                         const CompilerMethodStats *m2)
+{
+    return (int) m1->method - (int) m2->method;
+}
+
+/*
+ * Analyze the body of the method to collect high-level information regarding
+ * inlining:
+ * - is empty method?
+ * - is getter/setter?
+ * - can throw exception?
+ *
+ * Currently the inliner only handles getters and setters. When its capability
+ * becomes more sophisticated more information will be retrieved here.
+ */
+static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
+                               int offset)
+{
+    int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode);
+    int dalvikOpcode = dalvikInsn->opcode;
+
+    if (flags & kInstrInvoke) {
+        attributes &= ~METHOD_IS_LEAF;
+    }
+
+    if (!(flags & kInstrCanReturn)) {
+        if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
+              DF_IS_GETTER)) {
+            attributes &= ~METHOD_IS_GETTER;
+        }
+        if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
+              DF_IS_SETTER)) {
+            attributes &= ~METHOD_IS_SETTER;
+        }
+    }
+
+    /*
+     * The expected instruction sequence is setter will never return value and
+     * getter will also do. Clear the bits if the behavior is discovered
+     * otherwise.
+     */
+    if (flags & kInstrCanReturn) {
+        if (dalvikOpcode == OP_RETURN_VOID) {
+            attributes &= ~METHOD_IS_GETTER;
+        }
+        else {
+            attributes &= ~METHOD_IS_SETTER;
+        }
+    }
+
+    if (flags & kInstrCanThrow) {
+        attributes &= ~METHOD_IS_THROW_FREE;
+    }
+
+    if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) {
+        attributes |= METHOD_IS_EMPTY;
+    }
+
+    /*
+     * Check if this opcode is selected for single stepping.
+     * If so, don't inline the callee as there is no stack frame for the
+     * interpreter to single-step through the instruction.
+     */
+    if (SINGLE_STEP_OP(dalvikOpcode)) {
+        attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
+    }
+
+    return attributes;
+}
+
+/*
+ * Analyze each method whose traces are ever compiled. Collect a variety of
+ * statistics like the ratio of exercised vs overall code and code bloat
+ * ratios. If isCallee is true, also analyze each instruction in more details
+ * to see if it is suitable for inlining.
+ */
+CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
+                                                  bool isCallee)
+{
+    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 = (CompilerMethodStats *)
+        dvmHashTableLookup(gDvmJit.methodStatsTable,
+                           hashValue,
+                           &dummyMethodEntry,
+                           (HashCompareFunc) compareMethod,
+                           false);
+
+    /* This method has never been analyzed before - create an entry */
+    if (realMethodEntry == NULL) {
+        realMethodEntry =
+            (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
+        realMethodEntry->method = method;
+
+        dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+                           realMethodEntry,
+                           (HashCompareFunc) compareMethod,
+                           true);
+    }
+
+    /* This method is invoked as a callee and has been analyzed - just return */
+    if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
+        return realMethodEntry;
+
+    /*
+     * Similarly, return if this method has been compiled before as a hot
+     * method already.
+     */
+    if ((isCallee == false) &&
+        (realMethodEntry->attributes & METHOD_IS_HOT))
+        return realMethodEntry;
+
+    int attributes;
+
+    /* Method hasn't been analyzed for the desired purpose yet */
+    if (isCallee) {
+        /* Aggressively set the attributes until proven otherwise */
+        attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
+                     METHOD_IS_GETTER | METHOD_IS_SETTER;
+    } else {
+        attributes = METHOD_IS_HOT;
+    }
+
+    /* Count the number of instructions */
+    while (codePtr < codeEnd) {
+        DecodedInstruction dalvikInsn;
+        int width = parseInsn(codePtr, &dalvikInsn, false);
+
+        /* Terminate when the data section is seen */
+        if (width == 0)
+            break;
+
+        if (isCallee) {
+            attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
+        }
+
+        insnSize += width;
+        codePtr += width;
+    }
+
+    /*
+     * Only handle simple getters/setters with one instruction followed by
+     * return
+     */
+    if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
+        (insnSize != 3)) {
+        attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
+    }
+
+    realMethodEntry->dalvikSize = insnSize * 2;
+    realMethodEntry->attributes |= attributes;
+
+#if 0
+    /* Uncomment the following to explore various callee patterns */
+    if (attributes & METHOD_IS_THROW_FREE) {
+        LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
+             (attributes & METHOD_IS_EMPTY) ? " empty" : "");
+    }
+
+    if (attributes & METHOD_IS_LEAF) {
+        LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
+             insnSize, insnSize < 5 ? " (small)" : "");
+    }
+
+    if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
+        LOGE("%s%s is %s", method->clazz->descriptor, method->name,
+             attributes & METHOD_IS_GETTER ? "getter": "setter");
+    }
+    if (attributes ==
+        (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
+        LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
+             method->name);
+    }
+#endif
+
+    return realMethodEntry;
+}
+
+/*
+ * Crawl the stack of the thread that requesed compilation to see if any of the
+ * ancestors are on the blacklist.
+ */
+static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
+{
+    /* Crawl the Dalvik stack frames and compare the method name*/
+    StackSaveArea *ssaPtr = ((StackSaveArea *) thread->interpSave.curFrame) - 1;
+    while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
+        const Method *method = ssaPtr->method;
+        if (method) {
+            int hashValue = dvmComputeUtf8Hash(method->name);
+            bool found =
+                dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+                               (char *) method->name,
+                               (HashCompareFunc) strcmp, false) !=
+                NULL;
+            if (found) {
+                LOGD("Method %s (--> %s) found on the JIT %s list",
+                     method->name, curMethodName,
+                     gDvmJit.includeSelectedMethod ? "white" : "black");
+                return true;
+            }
+
+        }
+        ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
+    };
+    return false;
+}
+
+/*
+ * Since we are including instructions from possibly a cold method into the
+ * current trace, we need to make sure that all the associated information
+ * with the callee is properly initialized. If not, we punt on this inline
+ * target.
+ *
+ * TODO: volatile instructions will be handled later.
+ */
+bool dvmCompilerCanIncludeThisInstruction(const Method *method,
+                                          const DecodedInstruction *insn)
+{
+    switch (insn->opcode) {
+        case OP_NEW_INSTANCE:
+        case OP_NEW_INSTANCE_JUMBO:
+        case OP_CHECK_CAST:
+        case OP_CHECK_CAST_JUMBO: {
+            ClassObject *classPtr = (ClassObject *)(void*)
+              (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+            /* Class hasn't been initialized yet */
+            if (classPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_SGET:
+        case OP_SGET_JUMBO:
+        case OP_SGET_WIDE:
+        case OP_SGET_WIDE_JUMBO:
+        case OP_SGET_OBJECT:
+        case OP_SGET_OBJECT_JUMBO:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_BOOLEAN_JUMBO:
+        case OP_SGET_BYTE:
+        case OP_SGET_BYTE_JUMBO:
+        case OP_SGET_CHAR:
+        case OP_SGET_CHAR_JUMBO:
+        case OP_SGET_SHORT:
+        case OP_SGET_SHORT_JUMBO:
+        case OP_SPUT:
+        case OP_SPUT_JUMBO:
+        case OP_SPUT_WIDE:
+        case OP_SPUT_WIDE_JUMBO:
+        case OP_SPUT_OBJECT:
+        case OP_SPUT_OBJECT_JUMBO:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_BOOLEAN_JUMBO:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_BYTE_JUMBO:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_CHAR_JUMBO:
+        case OP_SPUT_SHORT:
+        case OP_SPUT_SHORT_JUMBO: {
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[insn->vB]);
+
+            if (fieldPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_INVOKE_SUPER:
+        case OP_INVOKE_SUPER_RANGE:
+        case OP_INVOKE_SUPER_JUMBO: {
+            int mIndex = method->clazz->pDvmDex->
+                pResMethods[insn->vB]->methodIndex;
+            const Method *calleeMethod = method->clazz->super->vtable[mIndex];
+            if (calleeMethod == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_INVOKE_SUPER_QUICK:
+        case OP_INVOKE_SUPER_QUICK_RANGE: {
+            const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
+            if (calleeMethod == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_INVOKE_STATIC:
+        case OP_INVOKE_STATIC_RANGE:
+        case OP_INVOKE_STATIC_JUMBO:
+        case OP_INVOKE_DIRECT:
+        case OP_INVOKE_DIRECT_RANGE:
+        case OP_INVOKE_DIRECT_JUMBO: {
+            const Method *calleeMethod =
+                method->clazz->pDvmDex->pResMethods[insn->vB];
+            if (calleeMethod == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_CONST_CLASS:
+        case OP_CONST_CLASS_JUMBO: {
+            void *classPtr = (void*)
+                (method->clazz->pDvmDex->pResClasses[insn->vB]);
+
+            if (classPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        case OP_CONST_STRING_JUMBO:
+        case OP_CONST_STRING: {
+            void *strPtr = (void*)
+                (method->clazz->pDvmDex->pResStrings[insn->vB]);
+
+            if (strPtr == NULL) {
+                return false;
+            }
+            return true;
+        }
+        default:
+            return true;
+    }
+}
+
+/* Split an existing block from the specified code offset into two */
+static BasicBlock *splitBlock(CompilationUnit *cUnit,
+                              unsigned int codeOffset,
+                              BasicBlock *origBlock,
+                              BasicBlock **immedPredBlockP)
+{
+    MIR *insn = origBlock->firstMIRInsn;
+    while (insn) {
+        if (insn->offset == codeOffset) break;
+        insn = insn->next;
+    }
+    if (insn == NULL) {
+        LOGE("Break split failed");
+        dvmAbort();
+    }
+    BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
+                                               cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
+
+    bottomBlock->startOffset = codeOffset;
+    bottomBlock->firstMIRInsn = insn;
+    bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
+
+    /* Handle the taken path */
+    bottomBlock->taken = origBlock->taken;
+    if (bottomBlock->taken) {
+        origBlock->taken = NULL;
+        dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
+        dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
+    }
+
+    /* Handle the fallthrough path */
+    bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
+    bottomBlock->fallThrough = origBlock->fallThrough;
+    origBlock->fallThrough = bottomBlock;
+    origBlock->needFallThroughBranch = true;
+    dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
+    if (bottomBlock->fallThrough) {
+        dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
+                            origBlock->id);
+        dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
+                          bottomBlock->id);
+    }
+
+    /* Handle the successor list */
+    if (origBlock->successorBlockList.blockListType != kNotUsed) {
+        bottomBlock->successorBlockList = origBlock->successorBlockList;
+        origBlock->successorBlockList.blockListType = kNotUsed;
+        GrowableListIterator iterator;
+
+        dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
+                                    &iterator);
+        while (true) {
+            SuccessorBlockInfo *successorBlockInfo =
+                (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
+            if (successorBlockInfo == NULL) break;
+            BasicBlock *bb = successorBlockInfo->block;
+            dvmCompilerClearBit(bb->predecessors, origBlock->id);
+            dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
+        }
+    }
+
+    origBlock->lastMIRInsn = insn->prev;
+
+    insn->prev->next = NULL;
+    insn->prev = NULL;
+
+    /*
+     * Update the immediate predecessor block pointer so that outgoing edges
+     * can be applied to the proper block.
+     */
+    if (immedPredBlockP) {
+        assert(*immedPredBlockP == origBlock);
+        *immedPredBlockP = bottomBlock;
+    }
+    return bottomBlock;
+}
+
+/*
+ * Given a code offset, find out the block that starts with it. If the offset
+ * is in the middle of an existing block, split it into two. If immedPredBlockP
+ * is non-null and is the block being split, update *immedPredBlockP to point
+ * to the bottom block so that outgoing edges can be setup properly (by the
+ * caller).
+ */
+static BasicBlock *findBlock(CompilationUnit *cUnit,
+                             unsigned int codeOffset,
+                             bool split, bool create,
+                             BasicBlock **immedPredBlockP)
+{
+    GrowableList *blockList = &cUnit->blockList;
+    BasicBlock *bb;
+    unsigned int i;
+
+    for (i = 0; i < blockList->numUsed; i++) {
+        bb = (BasicBlock *) blockList->elemList[i];
+        if (bb->blockType != kDalvikByteCode) continue;
+        if (bb->startOffset == codeOffset) return bb;
+        /* Check if a branch jumps into the middle of an existing block */
+        if ((split == true) && (codeOffset > bb->startOffset) &&
+            (bb->lastMIRInsn != NULL) &&
+            (codeOffset <= bb->lastMIRInsn->offset)) {
+            BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
+                                           bb == *immedPredBlockP ?
+                                               immedPredBlockP : NULL);
+            return newBB;
+        }
+    }
+    if (create) {
+          bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
+          dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+          bb->startOffset = codeOffset;
+          return bb;
+    }
+    return NULL;
+}
+
+/* Dump the CFG into a DOT graph */
+void dvmDumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
+{
+    const Method *method = cUnit->method;
+    FILE *file;
+    char *signature = dexProtoCopyMethodDescriptor(&method->prototype);
+    char startOffset[80];
+    sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
+    char *fileName = (char *) dvmCompilerNew(
+                                  strlen(dirPrefix) +
+                                  strlen(method->clazz->descriptor) +
+                                  strlen(method->name) +
+                                  strlen(signature) +
+                                  strlen(startOffset) +
+                                  strlen(".dot") + 1, true);
+    sprintf(fileName, "%s%s%s%s%s.dot", dirPrefix,
+            method->clazz->descriptor, method->name, signature, startOffset);
+    free(signature);
+
+    /*
+     * Convert the special characters into a filesystem- and shell-friendly
+     * format.
+     */
+    int i;
+    for (i = strlen(dirPrefix); fileName[i]; i++) {
+        if (fileName[i] == '/') {
+            fileName[i] = '_';
+        } else if (fileName[i] == ';') {
+            fileName[i] = '#';
+        } else if (fileName[i] == '$') {
+            fileName[i] = '+';
+        } else if (fileName[i] == '(' || fileName[i] == ')') {
+            fileName[i] = '@';
+        } else if (fileName[i] == '<' || fileName[i] == '>') {
+            fileName[i] = '=';
+        }
+    }
+    file = fopen(fileName, "w");
+    if (file == NULL) {
+        return;
+    }
+    fprintf(file, "digraph G {\n");
+
+    fprintf(file, "  rankdir=TB\n");
+
+    int numReachableBlocks = cUnit->numReachableBlocks;
+    int idx;
+    const GrowableList *blockList = &cUnit->blockList;
+
+    for (idx = 0; idx < numReachableBlocks; idx++) {
+        int blockIdx = cUnit->dfsOrder.elemList[idx];
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
+                                                                  blockIdx);
+        if (bb == NULL) break;
+        if (bb->blockType == kEntryBlock) {
+            fprintf(file, "  entry [shape=Mdiamond];\n");
+        } else if (bb->blockType == kExitBlock) {
+            fprintf(file, "  exit [shape=Mdiamond];\n");
+        } else if (bb->blockType == kDalvikByteCode) {
+            fprintf(file, "  block%04x [shape=record,label = \"{ \\\n",
+                    bb->startOffset);
+            const MIR *mir;
+            fprintf(file, "    {block id %d\\l}%s\\\n", bb->id,
+                    bb->firstMIRInsn ? " | " : " ");
+            for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+                fprintf(file, "    {%04x %s\\l}%s\\\n", mir->offset,
+                        mir->ssaRep ?
+                            dvmCompilerFullDisassembler(cUnit, mir) :
+                            dexGetOpcodeName(mir->dalvikInsn.opcode),
+                        mir->next ? " | " : " ");
+            }
+            fprintf(file, "  }\"];\n\n");
+        } else if (bb->blockType == kExceptionHandling) {
+            char blockName[BLOCK_NAME_LEN];
+
+            dvmGetBlockName(bb, blockName);
+            fprintf(file, "  %s [shape=invhouse];\n", blockName);
+        }
+
+        char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
+
+        if (bb->taken) {
+            dvmGetBlockName(bb, blockName1);
+            dvmGetBlockName(bb->taken, blockName2);
+            fprintf(file, "  %s:s -> %s:n [style=dotted]\n",
+                    blockName1, blockName2);
+        }
+        if (bb->fallThrough) {
+            dvmGetBlockName(bb, blockName1);
+            dvmGetBlockName(bb->fallThrough, blockName2);
+            fprintf(file, "  %s:s -> %s:n\n", blockName1, blockName2);
+        }
+
+        if (bb->successorBlockList.blockListType != kNotUsed) {
+            fprintf(file, "  succ%04x [shape=%s,label = \"{ \\\n",
+                    bb->startOffset,
+                    (bb->successorBlockList.blockListType == kCatch) ?
+                        "Mrecord" : "record");
+            GrowableListIterator iterator;
+            dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
+                                        &iterator);
+            SuccessorBlockInfo *successorBlockInfo =
+                (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
+
+            int succId = 0;
+            while (true) {
+                if (successorBlockInfo == NULL) break;
+
+                BasicBlock *destBlock = successorBlockInfo->block;
+                SuccessorBlockInfo *nextSuccessorBlockInfo =
+                  (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
+
+                fprintf(file, "    {<f%d> %04x: %04x\\l}%s\\\n",
+                        succId++,
+                        successorBlockInfo->key,
+                        destBlock->startOffset,
+                        (nextSuccessorBlockInfo != NULL) ? " | " : " ");
+
+                successorBlockInfo = nextSuccessorBlockInfo;
+            }
+            fprintf(file, "  }\"];\n\n");
+
+            dvmGetBlockName(bb, blockName1);
+            fprintf(file, "  %s:s -> succ%04x:n [style=dashed]\n",
+                    blockName1, bb->startOffset);
+
+            if (bb->successorBlockList.blockListType == kPackedSwitch ||
+                bb->successorBlockList.blockListType == kSparseSwitch) {
+
+                dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
+                                            &iterator);
+
+                succId = 0;
+                while (true) {
+                    SuccessorBlockInfo *successorBlockInfo =
+                        (SuccessorBlockInfo *)
+                            dvmGrowableListIteratorNext(&iterator);
+                    if (successorBlockInfo == NULL) break;
+
+                    BasicBlock *destBlock = successorBlockInfo->block;
+
+                    dvmGetBlockName(destBlock, blockName2);
+                    fprintf(file, "  succ%04x:f%d:e -> %s:n\n",
+                            bb->startOffset, succId++,
+                            blockName2);
+                }
+            }
+        }
+        fprintf(file, "\n");
+
+        /*
+         * If we need to debug the dominator tree, uncomment the following code
+         */
+#if 1
+        dvmGetBlockName(bb, blockName1);
+        fprintf(file, "  cfg%s [label=\"%s\", shape=none];\n",
+                blockName1, blockName1);
+        if (bb->iDom) {
+            dvmGetBlockName(bb->iDom, blockName2);
+            fprintf(file, "  cfg%s:s -> cfg%s:n\n\n",
+                    blockName2, blockName1);
+        }
+#endif
+    }
+    fprintf(file, "}\n");
+    fclose(file);
+}
+
+/* Verify if all the successor is connected with all the claimed predecessors */
+static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    BitVectorIterator bvIterator;
+
+    dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
+    while (true) {
+        int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
+        if (blockIdx == -1) break;
+        BasicBlock *predBB = (BasicBlock *)
+            dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
+        bool found = false;
+        if (predBB->taken == bb) {
+            found = true;
+        } else if (predBB->fallThrough == bb) {
+            found = true;
+        } else if (predBB->successorBlockList.blockListType != kNotUsed) {
+            GrowableListIterator iterator;
+            dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
+                                        &iterator);
+            while (true) {
+                SuccessorBlockInfo *successorBlockInfo =
+                    (SuccessorBlockInfo *)
+                        dvmGrowableListIteratorNext(&iterator);
+                if (successorBlockInfo == NULL) break;
+                BasicBlock *succBB = successorBlockInfo->block;
+                if (succBB == bb) {
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (found == false) {
+            char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
+            dvmGetBlockName(bb, blockName1);
+            dvmGetBlockName(predBB, blockName2);
+            dvmDumpCFG(cUnit, "/sdcard/cfg/");
+            LOGE("Successor %s not found from %s",
+                 blockName1, blockName2);
+            dvmAbort();
+        }
+    }
+    return true;
+}
+
+/* Identify code range in try blocks and set up the empty catch blocks */
+static void processTryCatchBlocks(CompilationUnit *cUnit)
+{
+    const Method *meth = cUnit->method;
+    const DexCode *pCode = dvmGetMethodCode(meth);
+    int triesSize = pCode->triesSize;
+    int i;
+    int offset;
+
+    if (triesSize == 0) {
+        return;
+    }
+
+    const DexTry *pTries = dexGetTries(pCode);
+    BitVector *tryBlockAddr = cUnit->tryBlockAddr;
+
+    /* Mark all the insn offsets in Try blocks */
+    for (i = 0; i < triesSize; i++) {
+        const DexTry* pTry = &pTries[i];
+        /* all in 16-bit units */
+        int startOffset = pTry->startAddr;
+        int endOffset = startOffset + pTry->insnCount;
+
+        for (offset = startOffset; offset < endOffset; offset++) {
+            dvmCompilerSetBit(tryBlockAddr, offset);
+        }
+    }
+
+    /* Iterate over each of the handlers to enqueue the empty Catch blocks */
+    offset = dexGetFirstHandlerOffset(pCode);
+    int handlersSize = dexGetHandlersSize(pCode);
+
+    for (i = 0; i < handlersSize; i++) {
+        DexCatchIterator iterator;
+        dexCatchIteratorInit(&iterator, pCode, offset);
+
+        for (;;) {
+            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+
+            if (handler == NULL) {
+                break;
+            }
+
+            /*
+             * Create dummy catch blocks first. Since these are created before
+             * other blocks are processed, "split" is specified as false.
+             */
+            findBlock(cUnit, handler->address,
+                      /* split */
+                      false,
+                      /* create */
+                      true,
+                      /* immedPredBlockP */
+                      NULL);
+        }
+
+        offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
+    }
+}
+
+/* Process instructions with the kInstrCanBranch flag */
+static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
+                             MIR *insn, int curOffset, int width, int flags,
+                             const u2* codePtr, const u2* codeEnd)
+{
+    int target = curOffset;
+    switch (insn->dalvikInsn.opcode) {
+        case OP_GOTO:
+        case OP_GOTO_16:
+        case OP_GOTO_32:
+            target += (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 += (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 += (int) insn->dalvikInsn.vB;
+            break;
+        default:
+            LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
+                 insn->dalvikInsn.opcode);
+            dvmAbort();
+    }
+    BasicBlock *takenBlock = findBlock(cUnit, target,
+                                       /* split */
+                                       true,
+                                       /* create */
+                                       true,
+                                       /* immedPredBlockP */
+                                       &curBlock);
+    curBlock->taken = takenBlock;
+    dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
+
+    /* Always terminate the current block for conditional branches */
+    if (flags & kInstrCanContinue) {
+        BasicBlock *fallthroughBlock = findBlock(cUnit,
+                                                 curOffset +  width,
+                                                 /*
+                                                  * If the method is processed
+                                                  * in sequential order from the
+                                                  * beginning, we don't need to
+                                                  * specify split for continue
+                                                  * blocks. However, this
+                                                  * routine can be called by
+                                                  * compileLoop, which starts
+                                                  * parsing the method from an
+                                                  * arbitrary address in the
+                                                  * method body.
+                                                  */
+                                                 true,
+                                                 /* create */
+                                                 true,
+                                                 /* immedPredBlockP */
+                                                 &curBlock);
+        curBlock->fallThrough = fallthroughBlock;
+        dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
+    } else if (codePtr < codeEnd) {
+        /* Create a fallthrough block for real instructions (incl. OP_NOP) */
+        if (contentIsInsn(codePtr)) {
+            findBlock(cUnit, curOffset + width,
+                      /* split */
+                      false,
+                      /* create */
+                      true,
+                      /* immedPredBlockP */
+                      NULL);
+        }
+    }
+}
+
+/* Process instructions with the kInstrCanSwitch flag */
+static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
+                             MIR *insn, int curOffset, int width, int flags)
+{
+    u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
+                            insn->dalvikInsn.vB);
+    int size;
+    int *keyTable;
+    int *targetTable;
+    int i;
+    int firstKey;
+
+    /*
+     * Packed switch data format:
+     *  ushort ident = 0x0100   magic value
+     *  ushort size             number of entries in the table
+     *  int first_key           first (and lowest) switch case value
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (4+size*2) 16-bit code units.
+     */
+    if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
+        assert(switchData[0] == kPackedSwitchSignature);
+        size = switchData[1];
+        firstKey = switchData[2] | (switchData[3] << 16);
+        targetTable = (int *) &switchData[4];
+        keyTable = NULL;        // Make the compiler happy
+    /*
+     * Sparse switch data format:
+     *  ushort ident = 0x0200   magic value
+     *  ushort size             number of entries in the table; > 0
+     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (2+size*4) 16-bit code units.
+     */
+    } else {
+        assert(switchData[0] == kSparseSwitchSignature);
+        size = switchData[1];
+        keyTable = (int *) &switchData[2];
+        targetTable = (int *) &switchData[2 + size*2];
+        firstKey = 0;   // To make the compiler happy
+    }
+
+    if (curBlock->successorBlockList.blockListType != kNotUsed) {
+        LOGE("Successor block list already in use: %d",
+             curBlock->successorBlockList.blockListType);
+        dvmAbort();
+    }
+    curBlock->successorBlockList.blockListType =
+        (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
+        kPackedSwitch : kSparseSwitch;
+    dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
+
+    for (i = 0; i < size; i++) {
+        BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
+                                          /* split */
+                                          true,
+                                          /* create */
+                                          true,
+                                          /* immedPredBlockP */
+                                          &curBlock);
+        SuccessorBlockInfo *successorBlockInfo =
+            (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
+                                                  false);
+        successorBlockInfo->block = caseBlock;
+        successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
+                                  firstKey + i : keyTable[i];
+        dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
+                              (intptr_t) successorBlockInfo);
+        dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
+    }
+
+    /* Fall-through case */
+    BasicBlock *fallthroughBlock = findBlock(cUnit,
+                                             curOffset +  width,
+                                             /* split */
+                                             false,
+                                             /* create */
+                                             true,
+                                             /* immedPredBlockP */
+                                             NULL);
+    curBlock->fallThrough = fallthroughBlock;
+    dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
+}
+
+/* Process instructions with the kInstrCanThrow flag */
+static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
+                            MIR *insn, int curOffset, int width, int flags,
+                            BitVector *tryBlockAddr, const u2 *codePtr,
+                            const u2* codeEnd)
+{
+    const Method *method = cUnit->method;
+    const DexCode *dexCode = dvmGetMethodCode(method);
+
+    /* In try block */
+    if (dvmIsBitSet(tryBlockAddr, curOffset)) {
+        DexCatchIterator iterator;
+
+        if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
+            LOGE("Catch block not found in dexfile for insn %x in %s",
+                 curOffset, method->name);
+            dvmAbort();
+
+        }
+        if (curBlock->successorBlockList.blockListType != kNotUsed) {
+            LOGE("Successor block list already in use: %d",
+                 curBlock->successorBlockList.blockListType);
+            dvmAbort();
+        }
+        curBlock->successorBlockList.blockListType = kCatch;
+        dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
+
+        for (;;) {
+            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
+
+            if (handler == NULL) {
+                break;
+            }
+
+            BasicBlock *catchBlock = findBlock(cUnit, handler->address,
+                                               /* split */
+                                               false,
+                                               /* create */
+                                               false,
+                                               /* immedPredBlockP */
+                                               NULL);
+
+            SuccessorBlockInfo *successorBlockInfo =
+              (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
+                                                    false);
+            successorBlockInfo->block = catchBlock;
+            successorBlockInfo->key = handler->typeIdx;
+            dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
+                                  (intptr_t) successorBlockInfo);
+            dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
+        }
+    } else {
+        BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
+                                               cUnit->numBlocks++);
+        curBlock->taken = ehBlock;
+        dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
+        ehBlock->startOffset = curOffset;
+        dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
+    }
+
+    /*
+     * Force the current block to terminate.
+     *
+     * Data may be present before codeEnd, so we need to parse it to know
+     * whether it is code or data.
+     */
+    if (codePtr < codeEnd) {
+        /* Create a fallthrough block for real instructions (incl. OP_NOP) */
+        if (contentIsInsn(codePtr)) {
+            BasicBlock *fallthroughBlock = findBlock(cUnit,
+                                                     curOffset + width,
+                                                     /* split */
+                                                     false,
+                                                     /* create */
+                                                     true,
+                                                     /* immedPredBlockP */
+                                                     NULL);
+            /*
+             * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
+             * branches.
+             */
+            if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
+                insn->dalvikInsn.opcode != OP_THROW) {
+                curBlock->fallThrough = fallthroughBlock;
+                dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
+            }
+        }
+    }
+}
+
+/*
+ * Similar to dvmCompileTrace, but the entity processed here is the whole
+ * method.
+ *
+ * TODO: implementation will be revisited when the trace builder can provide
+ * whole-method traces.
+ */
+bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
+{
+    CompilationUnit cUnit;
+    const DexCode *dexCode = dvmGetMethodCode(method);
+    const u2 *codePtr = dexCode->insns;
+    const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
+    int numBlocks = 0;
+    unsigned int curOffset = 0;
+
+    /* Method already compiled */
+    if (dvmJitGetMethodAddr(codePtr)) {
+        info->codeAddress = NULL;
+        return false;
+    }
+
+    memset(&cUnit, 0, sizeof(cUnit));
+    cUnit.method = method;
+
+    cUnit.jitMode = kJitMethod;
+
+    /* Initialize the block list */
+    dvmInitGrowableList(&cUnit.blockList, 4);
+
+    /*
+     * FIXME - PC reconstruction list won't be needed after the codegen routines
+     * are enhanced to true method mode.
+     */
+    /* Initialize the PC reconstruction list */
+    dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
+    /* Allocate the bit-vector to track the beginning of basic blocks */
+    BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
+                                                        true /* expandable */);
+    cUnit.tryBlockAddr = tryBlockAddr;
+
+    /* Create the default entry and exit blocks and enter them to the list */
+    BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
+    BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
+
+    cUnit.entryBlock = entryBlock;
+    cUnit.exitBlock = exitBlock;
+
+    dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
+    dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
+
+    /* Current block to record parsed instructions */
+    BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
+    curBlock->startOffset = 0;
+    dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
+    entryBlock->fallThrough = curBlock;
+    dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
+
+    /*
+     * Store back the number of blocks since new blocks may be created of
+     * accessing cUnit.
+     */
+    cUnit.numBlocks = numBlocks;
+
+    /* Identify code range in try blocks and set up the empty catch blocks */
+    processTryCatchBlocks(&cUnit);
+
+    /* Parse all instructions and put them into containing basic blocks */
+    while (codePtr < codeEnd) {
+        MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
+        insn->offset = curOffset;
+        int width = parseInsn(codePtr, &insn->dalvikInsn, false);
+        insn->width = width;
+
+        /* Terminate when the data section is seen */
+        if (width == 0)
+            break;
+
+        dvmCompilerAppendMIR(curBlock, insn);
+
+        codePtr += width;
+        int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
+
+        if (flags & kInstrCanBranch) {
+            processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
+                             codePtr, codeEnd);
+        } else if (flags & kInstrCanReturn) {
+            curBlock->fallThrough = exitBlock;
+            dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
+            /*
+             * Terminate the current block if there are instructions
+             * afterwards.
+             */
+            if (codePtr < codeEnd) {
+                /*
+                 * Create a fallthrough block for real instructions
+                 * (incl. OP_NOP).
+                 */
+                if (contentIsInsn(codePtr)) {
+                    findBlock(&cUnit, curOffset + width,
+                              /* split */
+                              false,
+                              /* create */
+                              true,
+                              /* immedPredBlockP */
+                              NULL);
+                }
+            }
+        } else if (flags & kInstrCanThrow) {
+            processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
+                            tryBlockAddr, codePtr, codeEnd);
+        } else if (flags & kInstrCanSwitch) {
+            processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
+        }
+        curOffset += width;
+        BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
+                                          /* split */
+                                          false,
+                                          /* create */
+                                          false,
+                                          /* immedPredBlockP */
+                                          NULL);
+        if (nextBlock) {
+            /*
+             * The next instruction could be the target of a previously parsed
+             * forward branch so a block is already created. If the current
+             * instruction is not an unconditional branch, connect them through
+             * the fall-through link.
+             */
+            assert(curBlock->fallThrough == NULL ||
+                   curBlock->fallThrough == nextBlock ||
+                   curBlock->fallThrough == exitBlock);
+
+            if ((curBlock->fallThrough == NULL) &&
+                (flags & kInstrCanContinue)) {
+                curBlock->fallThrough = nextBlock;
+                dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
+            }
+            curBlock = nextBlock;
+        }
+    }
+
+    if (cUnit.printMe) {
+        dvmCompilerDumpCompilationUnit(&cUnit);
+    }
+
+    /* Adjust this value accordingly once inlining is performed */
+    cUnit.numDalvikRegisters = cUnit.method->registersSize;
+
+    /* Verify if all blocks are connected as claimed */
+    /* FIXME - to be disabled in the future */
+    dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
+                                          kAllNodes,
+                                          false /* isIterative */);
+
+
+    /* Perform SSA transformation for the whole method */
+    dvmCompilerMethodSSATransformation(&cUnit);
+
+    dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
+
+    /* Allocate Registers using simple local allocation scheme */
+    dvmCompilerLocalRegAlloc(&cUnit);
+
+    /* Convert MIR to LIR, etc. */
+    dvmCompilerMethodMIR2LIR(&cUnit);
+
+    // Debugging only
+    //dvmDumpCFG(&cUnit, "/sdcard/cfg/");
+
+    /* Method is not empty */
+    if (cUnit.firstLIRInsn) {
+        /* Convert LIR into machine code. Loop for recoverable retries */
+        do {
+            dvmCompilerAssembleLIR(&cUnit, info);
+            cUnit.assemblerRetries++;
+            if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
+                LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
+                      cUnit.assemblerStatus);
+        } while (cUnit.assemblerStatus == kRetryAll);
+
+        if (cUnit.printMe) {
+            dvmCompilerCodegenDump(&cUnit);
+        }
+
+        if (info->codeAddress) {
+            dvmJitSetCodeAddr(dexCode->insns, info->codeAddress,
+                              info->instructionSet, true, 0);
+            /*
+             * Clear the codeAddress for the enclosing trace to reuse the info
+             */
+            info->codeAddress = NULL;
+        }
+    }
+
+    return false;
+}
+
+/* Extending the trace by crawling the code from curBlock */
+static bool exhaustTrace(CompilationUnit *cUnit, BasicBlock *curBlock)
+{
+    unsigned int curOffset = curBlock->startOffset;
+    const u2 *codePtr = cUnit->method->insns + curOffset;
+
+    if (curBlock->visited == true) return false;
+
+    curBlock->visited = true;
+
+    if (curBlock->blockType == kEntryBlock ||
+        curBlock->blockType == kExitBlock) {
+        return false;
+    }
+
+    /*
+     * Block has been parsed - check the taken/fallThrough in case it is a split
+     * block.
+     */
+    if (curBlock->firstMIRInsn != NULL) {
+          bool changed = false;
+          if (curBlock->taken)
+              changed |= exhaustTrace(cUnit, curBlock->taken);
+          if (curBlock->fallThrough)
+              changed |= exhaustTrace(cUnit, curBlock->fallThrough);
+          return changed;
+    }
+    while (true) {
+        MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
+        insn->offset = curOffset;
+        int width = parseInsn(codePtr, &insn->dalvikInsn, false);
+        insn->width = width;
+
+        /* Terminate when the data section is seen */
+        if (width == 0)
+            break;
+
+        dvmCompilerAppendMIR(curBlock, insn);
+
+        codePtr += width;
+        int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
+
+        /* Stop extending the trace after seeing these instructions */
+        if (flags & (kInstrCanReturn | kInstrCanSwitch | kInstrInvoke)) {
+            curBlock->fallThrough = cUnit->exitBlock;
+            dvmCompilerSetBit(cUnit->exitBlock->predecessors, curBlock->id);
+            break;
+        } else if (flags & kInstrCanBranch) {
+            processCanBranch(cUnit, curBlock, insn, curOffset, width, flags,
+                             codePtr, NULL);
+            if (curBlock->taken) {
+                exhaustTrace(cUnit, curBlock->taken);
+            }
+            if (curBlock->fallThrough) {
+                exhaustTrace(cUnit, curBlock->fallThrough);
+            }
+            break;
+        }
+        curOffset += width;
+        BasicBlock *nextBlock = findBlock(cUnit, curOffset,
+                                          /* split */
+                                          false,
+                                          /* create */
+                                          false,
+                                          /* immedPredBlockP */
+                                          NULL);
+        if (nextBlock) {
+            /*
+             * The next instruction could be the target of a previously parsed
+             * forward branch so a block is already created. If the current
+             * instruction is not an unconditional branch, connect them through
+             * the fall-through link.
+             */
+            assert(curBlock->fallThrough == NULL ||
+                   curBlock->fallThrough == nextBlock ||
+                   curBlock->fallThrough == cUnit->exitBlock);
+
+            if ((curBlock->fallThrough == NULL) &&
+                (flags & kInstrCanContinue)) {
+                curBlock->needFallThroughBranch = true;
+                curBlock->fallThrough = nextBlock;
+                dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
+            }
+            /* Block has been visited - no more parsing needed */
+            if (nextBlock->visited == true) {
+                return true;
+            }
+            curBlock = nextBlock;
+        }
+    }
+    return true;
+}
+
+/* Compile a loop */
+static bool compileLoop(CompilationUnit *cUnit, unsigned int startOffset,
+                        JitTraceDescription *desc, int numMaxInsts,
+                        JitTranslationInfo *info, jmp_buf *bailPtr,
+                        int optHints)
+{
+    int numBlocks = 0;
+    unsigned int curOffset = startOffset;
+    bool changed;
+    BasicBlock *bb;
+#if defined(WITH_JIT_TUNING)
+    CompilerMethodStats *methodStats;
+#endif
+
+    cUnit->jitMode = kJitLoop;
+
+    /* Initialize the block list */
+    dvmInitGrowableList(&cUnit->blockList, 4);
+
+    /* Initialize the PC reconstruction list */
+    dvmInitGrowableList(&cUnit->pcReconstructionList, 8);
+
+    /* Create the default entry and exit blocks and enter them to the list */
+    BasicBlock *entryBlock = dvmCompilerNewBB(kEntryBlock, numBlocks++);
+    entryBlock->startOffset = curOffset;
+    BasicBlock *exitBlock = dvmCompilerNewBB(kExitBlock, numBlocks++);
+
+    cUnit->entryBlock = entryBlock;
+    cUnit->exitBlock = exitBlock;
+
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
+
+    /* Current block to record parsed instructions */
+    BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
+    curBlock->startOffset = curOffset;
+
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
+    entryBlock->fallThrough = curBlock;
+    dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
+
+    /*
+     * Store back the number of blocks since new blocks may be created of
+     * accessing cUnit.
+     */
+    cUnit->numBlocks = numBlocks;
+
+    do {
+        dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+                                              dvmCompilerClearVisitedFlag,
+                                              kAllNodes,
+                                              false /* isIterative */);
+        changed = exhaustTrace(cUnit, curBlock);
+    } while (changed);
+
+    /* Backward chaining block */
+    bb = dvmCompilerNewBB(kChainingCellBackwardBranch, cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+    cUnit->backChainBlock = bb;
+
+    /* A special block to host PC reconstruction code */
+    bb = dvmCompilerNewBB(kPCReconstruction, cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+
+    /* And one final block that publishes the PC and raises the exception */
+    bb = dvmCompilerNewBB(kExceptionHandling, cUnit->numBlocks++);
+    dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
+    cUnit->puntBlock = bb;
+
+    cUnit->numDalvikRegisters = cUnit->method->registersSize;
+
+    /* Verify if all blocks are connected as claimed */
+    /* FIXME - to be disabled in the future */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, verifyPredInfo,
+                                          kAllNodes,
+                                          false /* isIterative */);
+
+
+    /* Try to identify a loop */
+    if (!dvmCompilerBuildLoop(cUnit))
+        goto bail;
+
+    dvmCompilerLoopOpt(cUnit);
+
+    /*
+     * Change the backward branch to the backward chaining cell after dataflow
+     * analsys/optimizations are done.
+     */
+    dvmCompilerInsertBackwardChaining(cUnit);
+
+    dvmCompilerInitializeRegAlloc(cUnit);
+
+    /* Allocate Registers using simple local allocation scheme */
+    dvmCompilerLocalRegAlloc(cUnit);
+
+    /* Convert MIR to LIR, etc. */
+    dvmCompilerMIR2LIR(cUnit);
+
+    /* Loop contains never executed blocks / heavy instructions */
+    if (cUnit->quitLoopMode) {
+        if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
+            LOGD("Loop trace @ offset %04x aborted due to unresolved code info",
+                 cUnit->entryBlock->startOffset);
+        }
+        goto bail;
+    }
+
+    /* Convert LIR into machine code. Loop for recoverable retries */
+    do {
+        dvmCompilerAssembleLIR(cUnit, info);
+        cUnit->assemblerRetries++;
+        if (cUnit->printMe && cUnit->assemblerStatus != kSuccess)
+            LOGD("Assembler abort #%d on %d", cUnit->assemblerRetries,
+                  cUnit->assemblerStatus);
+    } while (cUnit->assemblerStatus == kRetryAll);
+
+    /* Loop is too big - bail out */
+    if (cUnit->assemblerStatus == kRetryHalve) {
+        goto bail;
+    }
+
+    if (cUnit->printMe || gDvmJit.receivedSIGUSR2) {
+        LOGD("Loop trace @ offset %04x", cUnit->entryBlock->startOffset);
+        dvmCompilerCodegenDump(cUnit);
+    }
+
+    /*
+     * If this trace uses class objects as constants,
+     * dvmJitInstallClassObjectPointers will switch the thread state
+     * to running and look up the class pointers using the descriptor/loader
+     * tuple stored in the callsite info structure. We need to make this window
+     * as short as possible since it is blocking GC.
+     */
+    if (cUnit->hasClassLiterals && info->codeAddress) {
+        dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress);
+    }
+
+    /*
+     * Since callsiteinfo is allocated from the arena, delay the reset until
+     * class pointers are resolved.
+     */
+    dvmCompilerArenaReset();
+
+    assert(cUnit->assemblerStatus == kSuccess);
+#if defined(WITH_JIT_TUNING)
+    /* Locate the entry to store compilation statistics for this method */
+    methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
+    methodStats->nativeSize += cUnit->totalSize;
+#endif
+    return info->codeAddress != NULL;
+
+bail:
+    /* Retry the original trace with JIT_OPT_NO_LOOP disabled */
+    dvmCompilerArenaReset();
+    return dvmCompileTrace(desc, numMaxInsts, info, bailPtr,
+                           optHints | JIT_OPT_NO_LOOP);
+}
+
+/*
+ * 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.
+ */
+bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
+                     JitTranslationInfo *info, jmp_buf *bailPtr,
+                     int optHints)
+{
+    const DexCode *dexCode = dvmGetMethodCode(desc->method);
+    const JitTraceRun* currRun = &desc->trace[0];
+    unsigned int curOffset = currRun->info.frag.startOffset;
+    unsigned int startOffset = curOffset;
+    unsigned int numInsts = currRun->info.frag.numInsts;
+    const u2 *codePtr = dexCode->insns + curOffset;
+    int traceSize = 0;  // # of half-words
+    const u2 *startCodePtr = codePtr;
+    BasicBlock *curBB, *entryCodeBB;
+    int numBlocks = 0;
+    static int compilationId;
+    CompilationUnit cUnit;
+    GrowableList *blockList;
+#if defined(WITH_JIT_TUNING)
+    CompilerMethodStats *methodStats;
+#endif
+
+    /* If we've already compiled this trace, just return success */
+    if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) {
+        /*
+         * Make sure the codeAddress is NULL so that it won't clobber the
+         * existing entry.
+         */
+        info->codeAddress = NULL;
+        return true;
+    }
+
+    /* If the work order is stale, discard it */
+    if (info->cacheVersion != gDvmJit.cacheVersion) {
+        return false;
+    }
+
+    compilationId++;
+    memset(&cUnit, 0, sizeof(CompilationUnit));
+
+#if defined(WITH_JIT_TUNING)
+    /* Locate the entry to store compilation statistics for this method */
+    methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
+#endif
+
+    /* Set the recover buffer pointer */
+    cUnit.bailPtr = bailPtr;
+
+    /* Initialize the printMe flag */
+    cUnit.printMe = gDvmJit.printMe;
+
+    /* Setup the method */
+    cUnit.method = desc->method;
+
+    /* Store the trace descriptor and set the initial mode */
+    cUnit.traceDesc = desc;
+    cUnit.jitMode = kJitTrace;
+
+    /* Initialize the PC reconstruction list */
+    dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+
+    /* Initialize the basic block list */
+    blockList = &cUnit.blockList;
+    dvmInitGrowableList(blockList, 8);
+
+    /* 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 = (char *)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;
+
+                /*
+                 * Debug by call-graph is enabled. Check if the debug list
+                 * covers any methods on the VM stack.
+                 */
+                if (methodFound == false && gDvmJit.checkCallGraph == true) {
+                    methodFound =
+                        filterMethodByCallGraph(info->requestingThread,
+                                                desc->method->name);
+                }
+            }
+        }
+
+        /*
+         * 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 entry block */
+    curBB = dvmCompilerNewBB(kEntryBlock, numBlocks++);
+    dvmInsertGrowableList(blockList, (intptr_t) curBB);
+    curBB->startOffset = curOffset;
+
+    entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
+    dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
+    entryCodeBB->startOffset = curOffset;
+    curBB->fallThrough = entryCodeBB;
+    curBB = entryCodeBB;
+
+    if (cUnit.printMe) {
+        LOGD("--------\nCompiler: Building trace for %s, offset %#x",
+             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 = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+        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++;
+
+        int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
+
+        if (flags & kInstrInvoke) {
+            const Method *calleeMethod = (const Method *)
+                currRun[JIT_TRACE_CUR_METHOD].info.meta;
+            assert(numInsts == 1);
+            CallsiteInfo *callsiteInfo =
+                (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
+            callsiteInfo->classDescriptor = (const char *)
+                currRun[JIT_TRACE_CLASS_DESC].info.meta;
+            callsiteInfo->classLoader = (Object *)
+                currRun[JIT_TRACE_CLASS_LOADER].info.meta;
+            callsiteInfo->method = calleeMethod;
+            insn->meta.callsiteInfo = callsiteInfo;
+        }
+
+        /* Instruction limit reached - terminate the trace here */
+        if (cUnit.numInsts >= numMaxInsts) {
+            break;
+        }
+        if (--numInsts == 0) {
+            if (currRun->info.frag.runEnd) {
+                break;
+            } else {
+                /* Advance to the next trace description (ie non-meta info) */
+                do {
+                    currRun++;
+                } while (!currRun->isCode);
+
+                /* Dummy end-of-run marker seen */
+                if (currRun->info.frag.numInsts == 0) {
+                    break;
+                }
+
+                curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
+                dvmInsertGrowableList(blockList, (intptr_t) curBB);
+                curOffset = currRun->info.frag.startOffset;
+                numInsts = currRun->info.frag.numInsts;
+                curBB->startOffset = curOffset;
+                codePtr = dexCode->insns + curOffset;
+            }
+        } else {
+            curOffset += width;
+            codePtr += width;
+        }
+    }
+
+#if defined(WITH_JIT_TUNING)
+    /* Convert # of half-word to bytes */
+    methodStats->compiledDalvikSize += traceSize * 2;
+#endif
+
+    /*
+     * Now scan basic blocks containing real code to connect the
+     * taken/fallthrough links. Also create chaining cells for code not included
+     * in the trace.
+     */
+    size_t blockId;
+    for (blockId = 0; blockId < blockList->numUsed; blockId++) {
+        curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
+        MIR *lastInsn = curBB->lastMIRInsn;
+        /* Skip empty blocks */
+        if (lastInsn == NULL) {
+            continue;
+        }
+        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;
+
+        int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
+
+        if (flags & kInstrInvoke) {
+            cUnit.hasInvoke = true;
+        }
+
+        /* Backward branch seen */
+        if (isInvoke == false &&
+            (flags & kInstrCanBranch) != 0 &&
+            targetOffset < curOffset &&
+            (optHints & JIT_OPT_NO_LOOP) == 0) {
+            dvmCompilerArenaReset();
+            return compileLoop(&cUnit, startOffset, desc, numMaxInsts,
+                               info, bailPtr, optHints);
+        }
+
+        /* No backward branch in the trace - start searching the next BB */
+        size_t searchBlockId;
+        for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
+             searchBlockId++) {
+            searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
+                                                                searchBlockId);
+            if (targetOffset == searchBB->startOffset) {
+                curBB->taken = searchBB;
+                dvmCompilerSetBit(searchBB->predecessors, curBB->id);
+            }
+            if (fallThroughOffset == searchBB->startOffset) {
+                curBB->fallThrough = searchBB;
+                dvmCompilerSetBit(searchBB->predecessors, curBB->id);
+
+                /*
+                 * Fallthrough block of an invoke instruction needs to be
+                 * aligned to 4-byte boundary (alignment instruction to be
+                 * inserted later.
+                 */
+                if (flags & kInstrInvoke) {
+                    searchBB->isFallThroughFromInvoke = true;
+                }
+            }
+        }
+
+        /*
+         * 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);
+        if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
+            lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
+            int i;
+            const u2 *switchData = desc->method->insns + lastInsn->offset +
+                             lastInsn->dalvikInsn.vB;
+            int size = switchData[1];
+            int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
+
+            /*
+             * Generate the landing pad for cases whose ranks are higher than
+             * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
+             * through the NoChain point.
+             */
+            if (maxChains != size) {
+                cUnit.switchOverflowPad =
+                    desc->method->insns + lastInsn->offset;
+            }
+
+            s4 *targets = (s4 *) (switchData + 2 +
+                    (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
+                     2 : size * 2));
+
+            /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
+            for (i = 0; i < maxChains; i++) {
+                BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
+                                                         numBlocks++);
+                dvmInsertGrowableList(blockList, (intptr_t) caseChain);
+                caseChain->startOffset = lastInsn->offset + targets[i];
+            }
+
+            /* One more chaining cell for the default case */
+            BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
+                                                     numBlocks++);
+            dvmInsertGrowableList(blockList, (intptr_t) caseChain);
+            caseChain->startOffset = lastInsn->offset + lastInsn->width;
+        /* Fallthrough block not included in the trace */
+        } else if (!isUnconditionalBranch(lastInsn) &&
+                   curBB->fallThrough == NULL) {
+            BasicBlock *fallThroughBB;
+            /*
+             * 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) {
+                fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
+            } else {
+                fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
+                                                 numBlocks++);
+            }
+            dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
+            fallThroughBB->startOffset = fallThroughOffset;
+            curBB->fallThrough = fallThroughBB;
+            dvmCompilerSetBit(fallThroughBB->predecessors, curBB->id);
+        }
+        /* Target block not included in the trace */
+        if (curBB->taken == NULL &&
+            (isGoto(lastInsn) || isInvoke ||
+            (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
+            BasicBlock *newBB = NULL;
+            if (isInvoke) {
+                /* Monomorphic callee */
+                if (callee) {
+                    /* JNI call doesn't need a chaining cell */
+                    if (!dvmIsNativeMethod(callee)) {
+                        newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
+                                                 numBlocks++);
+                        newBB->startOffset = 0;
+                        newBB->containingMethod = callee;
+                    }
+                /* Will resolve at runtime */
+                } else {
+                    newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
+                                             numBlocks++);
+                    newBB->startOffset = 0;
+                }
+            /* For unconditional branches, request a hot chaining cell */
+            } else {
+#if !defined(WITH_SELF_VERIFICATION)
+                newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
+                                                  kChainingCellHot :
+                                                  kChainingCellNormal,
+                                         numBlocks++);
+                newBB->startOffset = targetOffset;
+#else
+                /* Handle branches that branch back into the block */
+                if (targetOffset >= curBB->firstMIRInsn->offset &&
+                    targetOffset <= curBB->lastMIRInsn->offset) {
+                    newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
+                                             numBlocks++);
+                } else {
+                    newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
+                                                      kChainingCellHot :
+                                                      kChainingCellNormal,
+                                             numBlocks++);
+                }
+                newBB->startOffset = targetOffset;
+#endif
+            }
+            if (newBB) {
+                curBB->taken = newBB;
+                dvmCompilerSetBit(newBB->predecessors, curBB->id);
+                dvmInsertGrowableList(blockList, (intptr_t) newBB);
+            }
+        }
+    }
+
+    /* Now create a special block to host PC reconstruction code */
+    curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
+    dvmInsertGrowableList(blockList, (intptr_t) curBB);
+
+    /* And one final block that publishes the PC and raise the exception */
+    curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
+    dvmInsertGrowableList(blockList, (intptr_t) curBB);
+    cUnit.puntBlock = curBB;
+
+    if (cUnit.printMe) {
+        char* signature =
+            dexProtoCopyMethodDescriptor(&desc->method->prototype);
+        LOGD("TRACEINFO (%d): 0x%08x %s%s.%s %#x %d of %d, %d blocks",
+            compilationId,
+            (intptr_t) desc->method->insns,
+            desc->method->clazz->descriptor,
+            desc->method->name,
+            signature,
+            desc->trace[0].info.frag.startOffset,
+            traceSize,
+            dexCode->insnsSize,
+            numBlocks);
+        free(signature);
+    }
+
+    cUnit.numBlocks = numBlocks;
+
+    /* Set the instruction set to use (NOTE: later components may change it) */
+    cUnit.instructionSet = dvmCompilerInstructionSet();
+
+    /* Inline transformation @ the MIR level */
+    if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
+        dvmCompilerInlineMIR(&cUnit, info);
+    }
+
+    cUnit.numDalvikRegisters = cUnit.method->registersSize;
+
+    /* Preparation for SSA conversion */
+    dvmInitializeSSAConversion(&cUnit);
+
+    dvmCompilerNonLoopAnalysis(&cUnit);
+
+    dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
+
+    if (cUnit.printMe) {
+        dvmCompilerDumpCompilationUnit(&cUnit);
+    }
+
+    /* Allocate Registers using simple local allocation scheme */
+    dvmCompilerLocalRegAlloc(&cUnit);
+
+    /* Convert MIR to LIR, etc. */
+    dvmCompilerMIR2LIR(&cUnit);
+
+    /* Convert LIR into machine code. Loop for recoverable retries */
+    do {
+        dvmCompilerAssembleLIR(&cUnit, info);
+        cUnit.assemblerRetries++;
+        if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
+            LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
+                  cUnit.assemblerStatus);
+    } while (cUnit.assemblerStatus == kRetryAll);
+
+    if (cUnit.printMe) {
+        LOGD("Trace Dalvik PC: %p", startCodePtr);
+        dvmCompilerCodegenDump(&cUnit);
+        LOGD("End %s%s, %d Dalvik instructions",
+             desc->method->clazz->descriptor, desc->method->name,
+             cUnit.numInsts);
+    }
+
+    if (cUnit.assemblerStatus == kRetryHalve) {
+        /* Reset the compiler resource pool before retry */
+        dvmCompilerArenaReset();
+
+        /* Halve the instruction count and start from the top */
+        return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
+                               optHints);
+    }
+
+    /*
+     * If this trace uses class objects as constants,
+     * dvmJitInstallClassObjectPointers will switch the thread state
+     * to running and look up the class pointers using the descriptor/loader
+     * tuple stored in the callsite info structure. We need to make this window
+     * as short as possible since it is blocking GC.
+     */
+    if (cUnit.hasClassLiterals && info->codeAddress) {
+        dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress);
+    }
+
+    /*
+     * Since callsiteinfo is allocated from the arena, delay the reset until
+     * class pointers are resolved.
+     */
+    dvmCompilerArenaReset();
+
+    assert(cUnit.assemblerStatus == kSuccess);
+#if defined(WITH_JIT_TUNING)
+    methodStats->nativeSize += cUnit.totalSize;
+#endif
+
+    return info->codeAddress != NULL;
+}
diff --git a/vm/compiler/InlineTransformation.cpp b/vm/compiler/InlineTransformation.cpp
new file mode 100644
index 0000000..53278a7
--- /dev/null
+++ b/vm/compiler/InlineTransformation.cpp
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "Dataflow.h"
+#include "libdex/DexOpcodes.h"
+
+/* Convert the reg id from the callee to the original id passed by the caller */
+static inline u4 convertRegId(const DecodedInstruction *invoke,
+                              const Method *calleeMethod,
+                              int calleeRegId, bool isRange)
+{
+    /* The order in the original arg passing list */
+    int rank = calleeRegId -
+               (calleeMethod->registersSize - calleeMethod->insSize);
+    assert(rank >= 0);
+    if (!isRange) {
+        return invoke->arg[rank];
+    } else {
+        return invoke->vC + rank;
+    }
+}
+
+static bool inlineGetter(CompilationUnit *cUnit,
+                         const Method *calleeMethod,
+                         MIR *invokeMIR,
+                         BasicBlock *invokeBB,
+                         bool isPredicted,
+                         bool isRange)
+{
+    BasicBlock *moveResultBB = invokeBB->fallThrough;
+    MIR *moveResultMIR = moveResultBB->firstMIRInsn;
+    MIR *newGetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+    DecodedInstruction getterInsn;
+
+    /*
+     * Not all getter instructions have vC but vC will be read by
+     * dvmCompilerGetDalvikDisassembly unconditionally.
+     * Initialize it here to get Valgrind happy.
+     */
+    getterInsn.vC = 0;
+
+    dexDecodeInstruction(calleeMethod->insns, &getterInsn);
+
+    if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
+        return false;
+
+    /*
+     * Some getters (especially invoked through interface) are not followed
+     * by a move result.
+     */
+    if ((moveResultMIR == NULL) ||
+        (moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT &&
+         moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_OBJECT &&
+         moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_WIDE)) {
+        return false;
+    }
+
+    int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opcode];
+
+    /* Expecting vA to be the destination register */
+    if (dfFlags & (DF_UA | DF_UA_WIDE)) {
+        LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opcode);
+        dvmAbort();
+    }
+
+    if (dfFlags & DF_UB) {
+        getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     getterInsn.vB, isRange);
+    }
+
+    if (dfFlags & DF_UC) {
+        getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     getterInsn.vC, isRange);
+    }
+
+    getterInsn.vA = moveResultMIR->dalvikInsn.vA;
+
+    /* Now setup the Dalvik instruction with converted src/dst registers */
+    newGetterMIR->dalvikInsn = getterInsn;
+
+    newGetterMIR->width = dexGetWidthFromOpcode(getterInsn.opcode);
+
+    newGetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+    /*
+     * If the getter instruction is about to raise any exception, punt to the
+     * interpreter and re-execute the invoke.
+     */
+    newGetterMIR->offset = invokeMIR->offset;
+
+    newGetterMIR->meta.calleeMethod = calleeMethod;
+
+    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
+
+    if (isPredicted) {
+        MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+        *invokeMIRSlow = *invokeMIR;
+        invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
+
+        /* Use vC to denote the first argument (ie this) */
+        if (!isRange) {
+            invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+        }
+
+        moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
+
+        dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
+        invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokePolyGetterInlined++;
+#endif
+    } else {
+        invokeMIR->OptimizationFlags |= MIR_INLINED;
+        moveResultMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokeMonoGetterInlined++;
+#endif
+    }
+
+    return true;
+}
+
+static bool inlineSetter(CompilationUnit *cUnit,
+                         const Method *calleeMethod,
+                         MIR *invokeMIR,
+                         BasicBlock *invokeBB,
+                         bool isPredicted,
+                         bool isRange)
+{
+    MIR *newSetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+    DecodedInstruction setterInsn;
+
+    /*
+     * Not all setter instructions have vC but vC will be read by
+     * dvmCompilerGetDalvikDisassembly unconditionally.
+     * Initialize it here to get Valgrind happy.
+     */
+    setterInsn.vC = 0;
+
+    dexDecodeInstruction(calleeMethod->insns, &setterInsn);
+
+    if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
+        return false;
+
+    int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opcode];
+
+    if (dfFlags & (DF_UA | DF_UA_WIDE)) {
+        setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     setterInsn.vA, isRange);
+
+    }
+
+    if (dfFlags & DF_UB) {
+        setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     setterInsn.vB, isRange);
+
+    }
+
+    if (dfFlags & DF_UC) {
+        setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
+                                     setterInsn.vC, isRange);
+    }
+
+    /* Now setup the Dalvik instruction with converted src/dst registers */
+    newSetterMIR->dalvikInsn = setterInsn;
+
+    newSetterMIR->width = dexGetWidthFromOpcode(setterInsn.opcode);
+
+    newSetterMIR->OptimizationFlags |= MIR_CALLEE;
+
+    /*
+     * If the setter instruction is about to raise any exception, punt to the
+     * interpreter and re-execute the invoke.
+     */
+    newSetterMIR->offset = invokeMIR->offset;
+
+    newSetterMIR->meta.calleeMethod = calleeMethod;
+
+    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
+
+    if (isPredicted) {
+        MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+        *invokeMIRSlow = *invokeMIR;
+        invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
+
+        /* Use vC to denote the first argument (ie this) */
+        if (!isRange) {
+            invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
+        }
+
+        dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
+        invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokePolySetterInlined++;
+#endif
+    } else {
+        /*
+         * The invoke becomes no-op so it needs an explicit branch to jump to
+         * the chaining cell.
+         */
+        invokeBB->needFallThroughBranch = true;
+        invokeMIR->OptimizationFlags |= MIR_INLINED;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokeMonoSetterInlined++;
+#endif
+    }
+
+    return true;
+}
+
+static bool tryInlineSingletonCallsite(CompilationUnit *cUnit,
+                                       const Method *calleeMethod,
+                                       MIR *invokeMIR,
+                                       BasicBlock *invokeBB,
+                                       bool isRange)
+{
+    /* Not a Java method */
+    if (dvmIsNativeMethod(calleeMethod)) return false;
+
+    CompilerMethodStats *methodStats =
+        dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+
+    /* Empty callee - do nothing */
+    if (methodStats->attributes & METHOD_IS_EMPTY) {
+        /* The original invoke instruction is effectively turned into NOP */
+        invokeMIR->OptimizationFlags |= MIR_INLINED;
+        /*
+         * Need to insert an explicit branch to catch the falling knife (into
+         * the PC reconstruction or chaining cell).
+         */
+        invokeBB->needFallThroughBranch = true;
+        return true;
+    }
+
+    if (methodStats->attributes & METHOD_IS_GETTER) {
+        return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
+                            isRange);
+    } else if (methodStats->attributes & METHOD_IS_SETTER) {
+        return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
+                            isRange);
+    }
+    return false;
+}
+
+static bool inlineEmptyVirtualCallee(CompilationUnit *cUnit,
+                                     const Method *calleeMethod,
+                                     MIR *invokeMIR,
+                                     BasicBlock *invokeBB)
+{
+    MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+    *invokeMIRSlow = *invokeMIR;
+    invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
+
+    dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
+    invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
+    return true;
+}
+
+static bool tryInlineVirtualCallsite(CompilationUnit *cUnit,
+                                     const Method *calleeMethod,
+                                     MIR *invokeMIR,
+                                     BasicBlock *invokeBB,
+                                     bool isRange)
+{
+    /* Not a Java method */
+    if (dvmIsNativeMethod(calleeMethod)) return false;
+
+    CompilerMethodStats *methodStats =
+        dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+
+    /* Empty callee - do nothing by checking the clazz pointer */
+    if (methodStats->attributes & METHOD_IS_EMPTY) {
+        return inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR,
+                                        invokeBB);
+    }
+
+    if (methodStats->attributes & METHOD_IS_GETTER) {
+        return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
+                            isRange);
+    } else if (methodStats->attributes & METHOD_IS_SETTER) {
+        return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
+                            isRange);
+    }
+    return false;
+}
+
+
+void dvmCompilerInlineMIR(CompilationUnit *cUnit, JitTranslationInfo *info)
+{
+    bool isRange = false;
+    GrowableListIterator iterator;
+
+    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+    /*
+     * Analyze the basic block containing an invoke to see if it can be inlined
+     */
+    while (true) {
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        if (bb->blockType != kDalvikByteCode)
+            continue;
+        MIR *lastMIRInsn = bb->lastMIRInsn;
+        Opcode opcode = lastMIRInsn->dalvikInsn.opcode;
+        int flags = (int)dexGetFlagsFromOpcode(opcode);
+
+        /* No invoke - continue */
+        if ((flags & kInstrInvoke) == 0)
+            continue;
+
+        /* Disable inlining when doing method tracing */
+        if (gDvmJit.methodTraceSupport)
+            continue;
+
+        /*
+         * If the invoke itself is selected for single stepping, don't bother
+         * to inline it.
+         */
+        if (SINGLE_STEP_OP(opcode))
+            continue;
+
+        const Method *calleeMethod;
+
+        switch (opcode) {
+            case OP_INVOKE_SUPER:
+            case OP_INVOKE_DIRECT:
+            case OP_INVOKE_STATIC:
+            case OP_INVOKE_SUPER_QUICK:
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            case OP_INVOKE_SUPER_RANGE:
+            case OP_INVOKE_DIRECT_RANGE:
+            case OP_INVOKE_STATIC_RANGE:
+            case OP_INVOKE_SUPER_QUICK_RANGE:
+                isRange = true;
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            default:
+                calleeMethod = NULL;
+                break;
+        }
+
+        if (calleeMethod) {
+            bool inlined = tryInlineSingletonCallsite(cUnit, calleeMethod,
+                                                      lastMIRInsn, bb, isRange);
+            if (!inlined &&
+                !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
+                !dvmIsNativeMethod(calleeMethod)) {
+                CompilerMethodStats *methodStats =
+                    dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+                if ((methodStats->attributes & METHOD_IS_LEAF) &&
+                    !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
+                    /* Callee has been previously compiled */
+                    if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                        lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
+                    } else {
+                        /* Compile the callee first */
+                        dvmCompileMethod(calleeMethod, info);
+                        if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                            lastMIRInsn->OptimizationFlags |=
+                                MIR_INVOKE_METHOD_JIT;
+                        } else {
+                            methodStats->attributes |= METHOD_CANNOT_COMPILE;
+                        }
+                    }
+                }
+            }
+            return;
+        }
+
+        switch (opcode) {
+            case OP_INVOKE_VIRTUAL:
+            case OP_INVOKE_VIRTUAL_QUICK:
+            case OP_INVOKE_INTERFACE:
+                isRange = false;
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            case OP_INVOKE_VIRTUAL_RANGE:
+            case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+            case OP_INVOKE_INTERFACE_RANGE:
+                isRange = true;
+                calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
+                break;
+            default:
+                break;
+        }
+
+        if (calleeMethod) {
+            bool inlined = tryInlineVirtualCallsite(cUnit, calleeMethod,
+                                                    lastMIRInsn, bb, isRange);
+            if (!inlined &&
+                !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
+                !dvmIsNativeMethod(calleeMethod)) {
+                CompilerMethodStats *methodStats =
+                    dvmCompilerAnalyzeMethodBody(calleeMethod, true);
+                if ((methodStats->attributes & METHOD_IS_LEAF) &&
+                    !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
+                    /* Callee has been previously compiled */
+                    if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                        lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
+                    } else {
+                        /* Compile the callee first */
+                        dvmCompileMethod(calleeMethod, info);
+                        if (dvmJitGetMethodAddr(calleeMethod->insns)) {
+                            lastMIRInsn->OptimizationFlags |=
+                                MIR_INVOKE_METHOD_JIT;
+                        } else {
+                            methodStats->attributes |= METHOD_CANNOT_COMPILE;
+                        }
+                    }
+                }
+            }
+            return;
+        }
+    }
+}
diff --git a/vm/compiler/IntermediateRep.cpp b/vm/compiler/IntermediateRep.cpp
new file mode 100644
index 0000000..db68c3c
--- /dev/null
+++ b/vm/compiler/IntermediateRep.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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, int blockId)
+{
+    BasicBlock *bb = (BasicBlock *)dvmCompilerNew(sizeof(BasicBlock), true);
+    bb->blockType = blockType;
+    bb->id = blockId;
+    bb->predecessors = dvmCompilerAllocBitVector(blockId > 32 ? blockId : 32,
+                                                 true /* expandable */);
+    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->lastMIRInsn == 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;
+    }
+}
+
+/* Insert an MIR instruction to the head of a basic block */
+void dvmCompilerPrependMIR(BasicBlock *bb, MIR *mir)
+{
+    if (bb->firstMIRInsn == NULL) {
+        assert(bb->lastMIRInsn == NULL);
+        bb->lastMIRInsn = bb->firstMIRInsn = mir;
+        mir->prev = mir->next = NULL;
+    } else {
+        bb->firstMIRInsn->prev = mir;
+        mir->next = bb->firstMIRInsn;
+        mir->prev = NULL;
+        bb->firstMIRInsn = mir;
+    }
+}
+
+/* Insert an MIR instruction after the specified MIR */
+void dvmCompilerInsertMIRAfter(BasicBlock *bb, MIR *currentMIR, MIR *newMIR)
+{
+    newMIR->prev = currentMIR;
+    newMIR->next = currentMIR->next;
+    currentMIR->next = newMIR;
+
+    if (newMIR->next) {
+        /* Is not the last MIR in the block */
+        newMIR->next->prev = newMIR;
+    } else {
+        /* Is the last MIR in the block */
+        bb->lastMIRInsn = newMIR;
+    }
+}
+
+/*
+ * Append an LIR instruction to the LIR list maintained by a compilation
+ * unit
+ */
+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)
+{
+    assert(currentLIR->prev != NULL);
+    LIR *prevLIR = currentLIR->prev;
+
+    prevLIR->next = newLIR;
+    newLIR->prev = prevLIR;
+    newLIR->next = currentLIR;
+    currentLIR->prev = newLIR;
+}
+
+/*
+ * Insert an LIR instruction after the current instruction, which cannot be the
+ * first instruction.
+ *
+ * currentLIR -> newLIR -> oldNext
+ */
+void dvmCompilerInsertLIRAfter(LIR *currentLIR, LIR *newLIR)
+{
+    newLIR->prev = currentLIR;
+    newLIR->next = currentLIR->next;
+    currentLIR->next = newLIR;
+    newLIR->next->prev = newLIR;
+}
diff --git a/vm/compiler/Loop.cpp b/vm/compiler/Loop.cpp
new file mode 100644
index 0000000..90c97d7
--- /dev/null
+++ b/vm/compiler/Loop.cpp
@@ -0,0 +1,752 @@
+/*
+ * 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"
+#include "Dataflow.h"
+#include "Loop.h"
+
+#define DEBUG_LOOP(X)
+
+#if 0
+/* Debugging routines */
+static void dumpConstants(CompilationUnit *cUnit)
+{
+    int i;
+    LOGE("LOOP starting offset: %x", cUnit->entryBlock->startOffset);
+    for (i = 0; i < cUnit->numSSARegs; i++) {
+        if (dvmIsBitSet(cUnit->isConstantV, i)) {
+            int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
+            LOGE("CONST: s%d(v%d_%d) has %d", i,
+                 DECODE_REG(subNReg), DECODE_SUB(subNReg),
+                 cUnit->constantValues[i]);
+        }
+    }
+}
+
+static void dumpIVList(CompilationUnit *cUnit)
+{
+    unsigned int i;
+    GrowableList *ivList = cUnit->loopAnalysis->ivList;
+
+    for (i = 0; i < ivList->numUsed; i++) {
+        InductionVariableInfo *ivInfo =
+            (InductionVariableInfo *) ivList->elemList[i];
+        int iv = dvmConvertSSARegToDalvik(cUnit, ivInfo->ssaReg);
+        /* Basic IV */
+        if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
+            LOGE("BIV %d: s%d(v%d_%d) + %d", i,
+                 ivInfo->ssaReg,
+                 DECODE_REG(iv), DECODE_SUB(iv),
+                 ivInfo->inc);
+        /* Dependent IV */
+        } else {
+            int biv = dvmConvertSSARegToDalvik(cUnit, ivInfo->basicSSAReg);
+
+            LOGE("DIV %d: s%d(v%d_%d) = %d * s%d(v%d_%d) + %d", i,
+                 ivInfo->ssaReg,
+                 DECODE_REG(iv), DECODE_SUB(iv),
+                 ivInfo->m,
+                 ivInfo->basicSSAReg,
+                 DECODE_REG(biv), DECODE_SUB(biv),
+                 ivInfo->c);
+        }
+    }
+}
+
+static void dumpHoistedChecks(CompilationUnit *cUnit)
+{
+    LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+    unsigned int i;
+
+    for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
+        ArrayAccessInfo *arrayAccessInfo =
+            GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+                       ArrayAccessInfo*, i);
+        int arrayReg = DECODE_REG(
+            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
+        int idxReg = DECODE_REG(
+            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
+        LOGE("Array access %d", i);
+        LOGE("  arrayReg %d", arrayReg);
+        LOGE("  idxReg %d", idxReg);
+        LOGE("  endReg %d", loopAnalysis->endConditionReg);
+        LOGE("  maxC %d", arrayAccessInfo->maxC);
+        LOGE("  minC %d", arrayAccessInfo->minC);
+        LOGE("  opcode %d", loopAnalysis->loopBranchOpcode);
+    }
+}
+
+#endif
+
+static BasicBlock *findPredecessorBlock(const CompilationUnit *cUnit,
+                                        const BasicBlock *bb)
+{
+    int numPred = dvmCountSetBits(bb->predecessors);
+    BitVectorIterator bvIterator;
+    dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
+
+    if (numPred == 1) {
+        int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+        return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+                                                        predIdx);
+    /* First loop block */
+    } else if ((numPred == 2) &&
+               dvmIsBitSet(bb->predecessors, cUnit->entryBlock->id)) {
+        while (true) {
+            int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+            if (predIdx == cUnit->entryBlock->id) continue;
+            return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+                                                            predIdx);
+        }
+    /* Doesn't support other shape of control flow yet */
+    } else {
+        return NULL;
+    }
+}
+
+/* Used for normalized loop exit condition checks */
+static Opcode negateOpcode(Opcode opcode)
+{
+    switch (opcode) {
+        /* reg/reg cmp */
+        case OP_IF_EQ:
+            return OP_IF_NE;
+        case OP_IF_NE:
+            return OP_IF_EQ;
+        case OP_IF_LT:
+            return OP_IF_GE;
+        case OP_IF_GE:
+            return OP_IF_LT;
+        case OP_IF_GT:
+            return OP_IF_LE;
+        case OP_IF_LE:
+            return OP_IF_GT;
+        /* reg/zero cmp */
+        case OP_IF_EQZ:
+            return OP_IF_NEZ;
+        case OP_IF_NEZ:
+            return OP_IF_EQZ;
+        case OP_IF_LTZ:
+            return OP_IF_GEZ;
+        case OP_IF_GEZ:
+            return OP_IF_LTZ;
+        case OP_IF_GTZ:
+            return OP_IF_LEZ;
+        case OP_IF_LEZ:
+            return OP_IF_GTZ;
+        default:
+            LOGE("opcode %d cannot be negated", opcode);
+            dvmAbort();
+            break;
+    }
+    return (Opcode)-1;  // unreached
+}
+
+/*
+ * A loop is considered optimizable if:
+ * 1) It has one basic induction variable.
+ * 2) The loop back branch compares the BIV with a constant.
+ * 3) We need to normalize the loop exit condition so that the loop is exited
+ *    via the taken path.
+ * 4) If it is a count-up loop, the condition is GE/GT. Otherwise it is
+ *    LE/LT/LEZ/LTZ for a count-down loop.
+ *
+ * Return false for loops that fail the above tests.
+ */
+static bool isSimpleCountedLoop(CompilationUnit *cUnit)
+{
+    unsigned int i;
+    BasicBlock *loopBackBlock = cUnit->entryBlock->fallThrough;
+    LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+
+    if (loopAnalysis->numBasicIV != 1) return false;
+    for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
+        InductionVariableInfo *ivInfo;
+
+        ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
+        /* Count up or down loop? */
+        if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
+            /* Infinite loop */
+            if (ivInfo->inc == 0) {
+                return false;
+            }
+            loopAnalysis->isCountUpLoop = ivInfo->inc > 0;
+            break;
+        }
+    }
+
+    /* Find the block that ends with a branch to exit the loop */
+    while (true) {
+        loopBackBlock = findPredecessorBlock(cUnit, loopBackBlock);
+        /* Loop structure not recognized as counted blocks */
+        if (loopBackBlock == NULL) {
+            return false;
+        }
+        /* Unconditional goto - continue to trace up the predecessor chain */
+        if (loopBackBlock->taken == NULL) {
+            continue;
+        }
+        break;
+    }
+
+    MIR *branch = loopBackBlock->lastMIRInsn;
+    Opcode opcode = branch->dalvikInsn.opcode;
+
+    /* Last instruction is not a conditional branch - bail */
+    if (dexGetFlagsFromOpcode(opcode) != (kInstrCanContinue|kInstrCanBranch)) {
+        return false;
+    }
+
+    int endSSAReg;
+    int endDalvikReg;
+
+    /* reg/reg comparison */
+    if (branch->ssaRep->numUses == 2) {
+        if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
+            endSSAReg = branch->ssaRep->uses[1];
+        } else if (branch->ssaRep->uses[1] == loopAnalysis->ssaBIV) {
+            endSSAReg = branch->ssaRep->uses[0];
+            opcode = negateOpcode(opcode);
+        } else {
+            return false;
+        }
+        endDalvikReg = dvmConvertSSARegToDalvik(cUnit, endSSAReg);
+        /*
+         * If the comparison is not between the BIV and a loop invariant,
+         * return false. endDalvikReg is loop invariant if one of the
+         * following is true:
+         * - It is not defined in the loop (ie DECODE_SUB returns 0)
+         * - It is reloaded with a constant
+         */
+        if ((DECODE_SUB(endDalvikReg) != 0) &&
+            !dvmIsBitSet(cUnit->isConstantV, endSSAReg)) {
+            return false;
+        }
+    /* Compare against zero */
+    } else if (branch->ssaRep->numUses == 1) {
+        if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
+            /* Keep the compiler happy */
+            endDalvikReg = -1;
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+
+    /* Normalize the loop exit check as "if (iv op end) exit;" */
+    if (loopBackBlock->taken->blockType == kDalvikByteCode) {
+        opcode = negateOpcode(opcode);
+    }
+
+    if (loopAnalysis->isCountUpLoop) {
+        /*
+         * If the normalized condition op is not > or >=, this is not an
+         * optimization candidate.
+         */
+        switch (opcode) {
+            case OP_IF_GT:
+            case OP_IF_GE:
+                break;
+            default:
+                return false;
+        }
+        loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
+    } else  {
+        /*
+         * If the normalized condition op is not < or <=, this is not an
+         * optimization candidate.
+         */
+        switch (opcode) {
+            case OP_IF_LT:
+            case OP_IF_LE:
+                loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
+                break;
+            case OP_IF_LTZ:
+            case OP_IF_LEZ:
+                break;
+            default:
+                return false;
+        }
+    }
+    /*
+     * Remember the normalized opcode, which will be used to determine the end
+     * value used for the yanked range checks.
+     */
+    loopAnalysis->loopBranchOpcode = opcode;
+    return true;
+}
+
+/*
+ * Record the upper and lower bound information for range checks for each
+ * induction variable. If array A is accessed by index "i+5", the upper and
+ * lower bound will be len(A)-5 and -5, respectively.
+ */
+static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg,
+                                 int idxReg)
+{
+    InductionVariableInfo *ivInfo;
+    LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+    unsigned int i, j;
+
+    for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
+        ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
+        if (ivInfo->ssaReg == idxReg) {
+            ArrayAccessInfo *arrayAccessInfo = NULL;
+            for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) {
+                ArrayAccessInfo *existingArrayAccessInfo =
+                    GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+                               ArrayAccessInfo*,
+                               j);
+                if (existingArrayAccessInfo->arrayReg == arrayReg) {
+                    if (ivInfo->c > existingArrayAccessInfo->maxC) {
+                        existingArrayAccessInfo->maxC = ivInfo->c;
+                    }
+                    if (ivInfo->c < existingArrayAccessInfo->minC) {
+                        existingArrayAccessInfo->minC = ivInfo->c;
+                    }
+                    arrayAccessInfo = existingArrayAccessInfo;
+                    break;
+                }
+            }
+            if (arrayAccessInfo == NULL) {
+                arrayAccessInfo =
+                    (ArrayAccessInfo *)dvmCompilerNew(sizeof(ArrayAccessInfo),
+                                                      false);
+                arrayAccessInfo->ivReg = ivInfo->basicSSAReg;
+                arrayAccessInfo->arrayReg = arrayReg;
+                arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
+                arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
+                dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
+                                      (intptr_t) arrayAccessInfo);
+            }
+            break;
+        }
+    }
+}
+
+/* Returns true if the loop body cannot throw any exceptions */
+static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
+{
+    BasicBlock *loopBody = cUnit->entryBlock->fallThrough;
+    MIR *mir;
+    bool loopBodyCanThrow = false;
+
+    for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
+        DecodedInstruction *dInsn = &mir->dalvikInsn;
+        int dfAttributes =
+            dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+
+        /* Skip extended MIR instructions */
+        if (dInsn->opcode >= kNumPackedOpcodes) continue;
+
+        int instrFlags = dexGetFlagsFromOpcode(dInsn->opcode);
+
+        /* Instruction is clean */
+        if ((instrFlags & kInstrCanThrow) == 0) continue;
+
+        /*
+         * Currently we can only optimize away null and range checks. Punt on
+         * instructions that can throw due to other exceptions.
+         */
+        if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
+            loopBodyCanThrow = true;
+            continue;
+        }
+
+        /*
+         * This comparison is redundant now, but we will have more than one
+         * group of flags to check soon.
+         */
+        if (dfAttributes & DF_HAS_NR_CHECKS) {
+            /*
+             * Check if the null check is applied on a loop invariant register?
+             * If the register's SSA id is less than the number of Dalvik
+             * registers, then it is loop invariant.
+             */
+            int refIdx;
+            switch (dfAttributes & DF_HAS_NR_CHECKS) {
+                case DF_NULL_N_RANGE_CHECK_0:
+                    refIdx = 0;
+                    break;
+                case DF_NULL_N_RANGE_CHECK_1:
+                    refIdx = 1;
+                    break;
+                case DF_NULL_N_RANGE_CHECK_2:
+                    refIdx = 2;
+                    break;
+                default:
+                    refIdx = 0;
+                    LOGE("Jit: bad case in doLoopBodyCodeMotion");
+                    dvmCompilerAbort(cUnit);
+            }
+
+            int useIdx = refIdx + 1;
+            int subNRegArray =
+                dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
+            int arraySub = DECODE_SUB(subNRegArray);
+
+            /*
+             * If the register is never updated in the loop (ie subscript == 0),
+             * it is an optimization candidate.
+             */
+            if (arraySub != 0) {
+                loopBodyCanThrow = true;
+                continue;
+            }
+
+            /*
+             * Then check if the range check can be hoisted out of the loop if
+             * it is basic or dependent induction variable.
+             */
+            if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
+                            mir->ssaRep->uses[useIdx])) {
+                mir->OptimizationFlags |=
+                    MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
+                updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
+                                     mir->ssaRep->uses[useIdx]);
+            }
+        }
+    }
+
+    return !loopBodyCanThrow;
+}
+
+static void genHoistedChecks(CompilationUnit *cUnit)
+{
+    unsigned int i;
+    BasicBlock *entry = cUnit->entryBlock;
+    LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+    int globalMaxC = 0;
+    int globalMinC = 0;
+    /* Should be loop invariant */
+    int idxReg = 0;
+
+    for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
+        ArrayAccessInfo *arrayAccessInfo =
+            GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+                       ArrayAccessInfo*, i);
+        int arrayReg = DECODE_REG(
+            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
+        idxReg = DECODE_REG(
+            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
+
+        MIR *rangeCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+        rangeCheckMIR->dalvikInsn.opcode = (loopAnalysis->isCountUpLoop) ?
+            (Opcode)kMirOpNullNRangeUpCheck : (Opcode)kMirOpNullNRangeDownCheck;
+        rangeCheckMIR->dalvikInsn.vA = arrayReg;
+        rangeCheckMIR->dalvikInsn.vB = idxReg;
+        rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
+        rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
+        rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
+        rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
+        dvmCompilerAppendMIR(entry, rangeCheckMIR);
+        if (arrayAccessInfo->maxC > globalMaxC) {
+            globalMaxC = arrayAccessInfo->maxC;
+        }
+        if (arrayAccessInfo->minC < globalMinC) {
+            globalMinC = arrayAccessInfo->minC;
+        }
+    }
+
+    if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
+        if (loopAnalysis->isCountUpLoop) {
+            MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+            boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpLowerBound;
+            boundCheckMIR->dalvikInsn.vA = idxReg;
+            boundCheckMIR->dalvikInsn.vB = globalMinC;
+            dvmCompilerAppendMIR(entry, boundCheckMIR);
+        } else {
+            if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
+                loopAnalysis->loopBranchOpcode == OP_IF_LE) {
+                MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+                boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpLowerBound;
+                boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
+                boundCheckMIR->dalvikInsn.vB = globalMinC;
+                /*
+                 * If the end condition is ">" in the source, the check in the
+                 * Dalvik bytecode is OP_IF_LE. In this case add 1 back to the
+                 * constant field to reflect the fact that the smallest index
+                 * value is "endValue + constant + 1".
+                 */
+                if (loopAnalysis->loopBranchOpcode == OP_IF_LE) {
+                    boundCheckMIR->dalvikInsn.vB++;
+                }
+                dvmCompilerAppendMIR(entry, boundCheckMIR);
+            } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
+                /* Array index will fall below 0 */
+                if (globalMinC < 0) {
+                    MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
+                                                               true);
+                    boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpPunt;
+                    dvmCompilerAppendMIR(entry, boundCheckMIR);
+                }
+            } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
+                /* Array index will fall below 0 */
+                if (globalMinC < -1) {
+                    MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
+                                                               true);
+                    boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpPunt;
+                    dvmCompilerAppendMIR(entry, boundCheckMIR);
+                }
+            } else {
+                LOGE("Jit: bad case in genHoistedChecks");
+                dvmCompilerAbort(cUnit);
+            }
+        }
+    }
+}
+
+void resetBlockEdges(BasicBlock *bb)
+{
+    bb->taken = NULL;
+    bb->fallThrough = NULL;
+    bb->successorBlockList.blockListType = kNotUsed;
+}
+
+static bool clearPredecessorVector(struct CompilationUnit *cUnit,
+                                   struct BasicBlock *bb)
+{
+    dvmClearAllBits(bb->predecessors);
+    return false;
+}
+
+bool dvmCompilerFilterLoopBlocks(CompilationUnit *cUnit)
+{
+    BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
+
+    int numPred = dvmCountSetBits(firstBB->predecessors);
+    /*
+     * A loop body should have at least two incoming edges.
+     */
+    if (numPred < 2) return false;
+
+    GrowableList *blockList = &cUnit->blockList;
+
+    /* Record blocks included in the loop */
+    dvmClearAllBits(cUnit->tempBlockV);
+
+    dvmCompilerSetBit(cUnit->tempBlockV, cUnit->entryBlock->id);
+    dvmCompilerSetBit(cUnit->tempBlockV, firstBB->id);
+
+    BasicBlock *bodyBB = firstBB;
+
+    /*
+     * First try to include the fall-through block in the loop, then the taken
+     * block. Stop loop formation on the first backward branch that enters the
+     * first block (ie only include the inner-most loop).
+     */
+    while (true) {
+        /* Loop formed */
+        if (bodyBB->taken == firstBB) {
+            /* Check if the fallThrough edge will cause a nested loop */
+            if (bodyBB->fallThrough &&
+                dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
+                return false;
+            }
+            /* Single loop formed */
+            break;
+        } else if (bodyBB->fallThrough == firstBB) {
+            /* Check if the taken edge will cause a nested loop */
+            if (bodyBB->taken &&
+                dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
+                return false;
+            }
+            /* Single loop formed */
+            break;
+        }
+
+        /* Inner loops formed first - quit */
+        if (bodyBB->fallThrough &&
+            dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
+            return false;
+        }
+        if (bodyBB->taken &&
+            dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
+            return false;
+        }
+
+        if (bodyBB->fallThrough) {
+            if (bodyBB->fallThrough->iDom == bodyBB) {
+                bodyBB = bodyBB->fallThrough;
+                dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
+                /*
+                 * Loop formation to be detected at the beginning of next
+                 * iteration.
+                 */
+                continue;
+            }
+        }
+        if (bodyBB->taken) {
+            if (bodyBB->taken->iDom == bodyBB) {
+                bodyBB = bodyBB->taken;
+                dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
+                /*
+                 * Loop formation to be detected at the beginning of next
+                 * iteration.
+                 */
+                continue;
+            }
+        }
+        /*
+         * Current block is not the immediate dominator of either fallthrough
+         * nor taken block - bail out of loop formation.
+         */
+        return false;
+    }
+
+
+    /* Now mark blocks not included in the loop as hidden */
+    GrowableListIterator iterator;
+    dvmGrowableListIteratorInit(blockList, &iterator);
+    while (true) {
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        if (!dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
+            bb->hidden = true;
+            /* Clear the insn list */
+            bb->firstMIRInsn = bb->lastMIRInsn = NULL;
+            resetBlockEdges(bb);
+        }
+    }
+
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, clearPredecessorVector,
+                                          kAllNodes, false /* isIterative */);
+
+    dvmGrowableListIteratorInit(blockList, &iterator);
+    while (true) {
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        if (dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
+            if (bb->taken) {
+                /*
+                 * exit block means we run into control-flow that we don't want
+                 * to handle.
+                 */
+                if (bb->taken == cUnit->exitBlock) {
+                    return false;
+                }
+                if (bb->taken->hidden) {
+                    bb->taken->blockType = kChainingCellNormal;
+                    bb->taken->hidden = false;
+                }
+                dvmCompilerSetBit(bb->taken->predecessors, bb->id);
+            }
+            if (bb->fallThrough) {
+                /*
+                 * exit block means we run into control-flow that we don't want
+                 * to handle.
+                 */
+                if (bb->fallThrough == cUnit->exitBlock) {
+                    return false;
+                }
+                if (bb->fallThrough->hidden) {
+                    bb->fallThrough->blockType = kChainingCellNormal;
+                    bb->fallThrough->hidden = false;
+                }
+                dvmCompilerSetBit(bb->fallThrough->predecessors, bb->id);
+            }
+            /* Loop blocks shouldn't contain any successor blocks (yet) */
+            assert(bb->successorBlockList.blockListType == kNotUsed);
+        }
+    }
+    return true;
+}
+
+/*
+ * Main entry point to do loop optimization.
+ * Return false if sanity checks for loop formation/optimization failed.
+ */
+bool dvmCompilerLoopOpt(CompilationUnit *cUnit)
+{
+    LoopAnalysis *loopAnalysis =
+        (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true);
+    cUnit->loopAnalysis = loopAnalysis;
+
+    /* Constant propagation */
+    cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
+    cUnit->constantValues =
+        (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
+                              true);
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+                                          dvmCompilerDoConstantPropagation,
+                                          kAllNodes,
+                                          false /* isIterative */);
+    DEBUG_LOOP(dumpConstants(cUnit);)
+
+    /* Find induction variables - basic and dependent */
+    loopAnalysis->ivList =
+        (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
+    dvmInitGrowableList(loopAnalysis->ivList, 4);
+    loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+                                          dvmCompilerFindInductionVariables,
+                                          kAllNodes,
+                                          false /* isIterative */);
+    DEBUG_LOOP(dumpIVList(cUnit);)
+
+    /* Only optimize array accesses for simple counted loop for now */
+    if (!isSimpleCountedLoop(cUnit))
+        return false;
+
+    loopAnalysis->arrayAccessInfo =
+        (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
+    dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
+    loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
+    DEBUG_LOOP(dumpHoistedChecks(cUnit);)
+
+    /*
+     * Convert the array access information into extended MIR code in the loop
+     * header.
+     */
+    genHoistedChecks(cUnit);
+    return true;
+}
+
+/*
+ * Select the target block of the backward branch.
+ */
+void dvmCompilerInsertBackwardChaining(CompilationUnit *cUnit)
+{
+    /*
+     * If we are not in self-verification or profiling mode, the backward
+     * branch can go to the entryBlock->fallThrough directly. Suspend polling
+     * code will be generated along the backward branch to honor the suspend
+     * requests.
+     */
+#if !defined(WITH_SELF_VERIFICATION)
+    if (gDvmJit.profileMode != kTraceProfilingContinuous &&
+        gDvmJit.profileMode != kTraceProfilingPeriodicOn) {
+        return;
+    }
+#endif
+    /*
+     * In self-verification or profiling mode, the backward branch is altered
+     * to go to the backward chaining cell. Without using the backward chaining
+     * cell we won't be able to do check-pointing on the target PC, or count the
+     * number of iterations accurately.
+     */
+    BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
+    BasicBlock *backBranchBB = findPredecessorBlock(cUnit, firstBB);
+    if (backBranchBB->taken == firstBB) {
+        backBranchBB->taken = cUnit->backChainBlock;
+    } else {
+        assert(backBranchBB->fallThrough == firstBB);
+        backBranchBB->fallThrough = cUnit->backChainBlock;
+    }
+    cUnit->backChainBlock->startOffset = firstBB->startOffset;
+}
diff --git a/vm/compiler/Loop.h b/vm/compiler/Loop.h
new file mode 100644
index 0000000..8032093
--- /dev/null
+++ b/vm/compiler/Loop.h
@@ -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.
+ */
+
+#ifndef DALVIK_VM_LOOP_H_
+#define DALVIK_VM_LOOP_H_
+
+#include "Dalvik.h"
+#include "CompilerInternals.h"
+
+typedef struct LoopAnalysis {
+    BitVector *isIndVarV;               // length == numSSAReg
+    GrowableList *ivList;               // induction variables
+    GrowableList *arrayAccessInfo;      // hoisted checks for array accesses
+    int numBasicIV;                     // number of basic induction variables
+    int ssaBIV;                         // basic IV in SSA name
+    bool isCountUpLoop;                 // count up or down loop
+    Opcode loopBranchOpcode;            // OP_IF_XXX for the loop back branch
+    int endConditionReg;                // vB in "vA op vB"
+    LIR *branchToBody;                  // branch over to the body from entry
+    LIR *branchToPCR;                   // branch over to the PCR cell
+    bool bodyIsClean;                   // loop body cannot throw any exceptions
+} LoopAnalysis;
+
+bool dvmCompilerFilterLoopBlocks(CompilationUnit *cUnit);
+
+/*
+ * An unexecuted code path may contain unresolved fields or classes. Before we
+ * have a quiet resolver we simply bail out of the loop compilation mode.
+ */
+#define BAIL_LOOP_COMPILATION() if (cUnit->jitMode == kJitLoop) {       \
+                                    cUnit->quitLoopMode = true;         \
+                                    return false;                       \
+                                }
+
+#endif  // DALVIK_VM_LOOP_H_
diff --git a/vm/compiler/Ralloc.cpp b/vm/compiler/Ralloc.cpp
new file mode 100644
index 0000000..e2752b1
--- /dev/null
+++ b/vm/compiler/Ralloc.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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"
+#include "Dataflow.h"
+
+/*
+ * Quick & dirty - make FP usage sticky.  This is strictly a hint - local
+ * code generation will handle misses.  It might be worthwhile to collaborate
+ * with dx/dexopt to avoid reusing the same Dalvik temp for values of
+ * different types.
+ */
+static void inferTypes(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock)
+        return;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        SSARepresentation *ssaRep = mir->ssaRep;
+        if (ssaRep) {
+            int i;
+            for (i=0; ssaRep->fpUse && i< ssaRep->numUses; i++) {
+                if (ssaRep->fpUse[i])
+                    cUnit->regLocation[ssaRep->uses[i]].fp = true;
+            }
+            for (i=0; ssaRep->fpDef && i< ssaRep->numDefs; i++) {
+                if (ssaRep->fpDef[i])
+                    cUnit->regLocation[ssaRep->defs[i]].fp = true;
+            }
+        }
+    }
+}
+
+static const RegLocation freshLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
+                                     INVALID_REG, INVALID_SREG};
+
+/*
+ * Local register allocation for simple traces.  Most of the work for
+ * local allocation is done on the fly.  Here we do some initialization
+ * and type inference.
+ */
+void dvmCompilerLocalRegAlloc(CompilationUnit *cUnit)
+{
+    int i;
+    RegLocation *loc;
+
+    /* Allocate the location map */
+    loc = (RegLocation*)dvmCompilerNew(cUnit->numSSARegs * sizeof(*loc), true);
+    for (i=0; i< cUnit->numSSARegs; i++) {
+        loc[i] = freshLoc;
+        loc[i].sRegLow = i;
+    }
+    cUnit->regLocation = loc;
+
+    GrowableListIterator iterator;
+
+    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+    /* Do type inference pass */
+    while (true) {
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        inferTypes(cUnit, bb);
+    }
+
+    /* Remap SSA names back to original frame locations. */
+    for (i=0; i < cUnit->numSSARegs; i++) {
+        cUnit->regLocation[i].sRegLow =
+                DECODE_REG(dvmConvertSSARegToDalvik(cUnit, loc[i].sRegLow));
+    }
+}
diff --git a/vm/compiler/SSATransformation.cpp b/vm/compiler/SSATransformation.cpp
new file mode 100644
index 0000000..542fff5
--- /dev/null
+++ b/vm/compiler/SSATransformation.cpp
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "Dataflow.h"
+#include "Loop.h"
+#include "libdex/DexOpcodes.h"
+
+/* Enter the node to the dfsOrder list then visit its successors */
+static void recordDFSPreOrder(CompilationUnit *cUnit, BasicBlock *block)
+{
+
+    if (block->visited || block->hidden) return;
+    block->visited = true;
+
+    /* Enqueue the block id */
+    dvmInsertGrowableList(&cUnit->dfsOrder, block->id);
+
+    if (block->fallThrough) recordDFSPreOrder(cUnit, block->fallThrough);
+    if (block->taken) recordDFSPreOrder(cUnit, block->taken);
+    if (block->successorBlockList.blockListType != kNotUsed) {
+        GrowableListIterator iterator;
+        dvmGrowableListIteratorInit(&block->successorBlockList.blocks,
+                                    &iterator);
+        while (true) {
+            SuccessorBlockInfo *successorBlockInfo =
+                (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
+            if (successorBlockInfo == NULL) break;
+            BasicBlock *succBB = successorBlockInfo->block;
+            recordDFSPreOrder(cUnit, succBB);
+        }
+    }
+    return;
+}
+
+/* Sort the blocks by the Depth-First-Search pre-order */
+static void computeDFSOrder(CompilationUnit *cUnit)
+{
+    /* Initialize or reset the DFS order list */
+    if (cUnit->dfsOrder.elemList == NULL) {
+        dvmInitGrowableList(&cUnit->dfsOrder, cUnit->numBlocks);
+    } else {
+        /* Just reset the used length on the counter */
+        cUnit->dfsOrder.numUsed = 0;
+    }
+
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag,
+                                          kAllNodes,
+                                          false /* isIterative */);
+
+    recordDFSPreOrder(cUnit, cUnit->entryBlock);
+    cUnit->numReachableBlocks = cUnit->dfsOrder.numUsed;
+}
+
+/*
+ * Mark block bit on the per-Dalvik register vector to denote that Dalvik
+ * register idx is defined in BasicBlock bb.
+ */
+static bool fillDefBlockMatrix(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    if (bb->dataFlowInfo == NULL) return false;
+
+    BitVectorIterator iterator;
+
+    dvmBitVectorIteratorInit(bb->dataFlowInfo->defV, &iterator);
+    while (true) {
+        int idx = dvmBitVectorIteratorNext(&iterator);
+        if (idx == -1) break;
+        /* Block bb defines register idx */
+        dvmCompilerSetBit(cUnit->defBlockMatrix[idx], bb->id);
+    }
+    return true;
+}
+
+static void computeDefBlockMatrix(CompilationUnit *cUnit)
+{
+    int numRegisters = cUnit->numDalvikRegisters;
+    /* Allocate numDalvikRegisters bit vector pointers */
+    cUnit->defBlockMatrix = (BitVector **)
+        dvmCompilerNew(sizeof(BitVector *) * numRegisters, true);
+    int i;
+
+    /* Initialize numRegister vectors with numBlocks bits each */
+    for (i = 0; i < numRegisters; i++) {
+        cUnit->defBlockMatrix[i] = dvmCompilerAllocBitVector(cUnit->numBlocks,
+                                                             false);
+    }
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLocalLiveIn,
+                                          kAllNodes,
+                                          false /* isIterative */);
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, fillDefBlockMatrix,
+                                          kAllNodes,
+                                          false /* isIterative */);
+
+    if (cUnit->jitMode == kJitMethod) {
+        /*
+         * Also set the incoming parameters as defs in the entry block.
+         * Only need to handle the parameters for the outer method.
+         */
+        int inReg = cUnit->method->registersSize - cUnit->method->insSize;
+        for (; inReg < cUnit->method->registersSize; inReg++) {
+            dvmCompilerSetBit(cUnit->defBlockMatrix[inReg],
+                              cUnit->entryBlock->id);
+        }
+    }
+}
+
+/* Compute the post-order traversal of the CFG */
+static void computeDomPostOrderTraversal(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    BitVectorIterator bvIterator;
+    dvmBitVectorIteratorInit(bb->iDominated, &bvIterator);
+    GrowableList *blockList = &cUnit->blockList;
+
+    /* Iterate through the dominated blocks first */
+    while (true) {
+        int bbIdx = dvmBitVectorIteratorNext(&bvIterator);
+        if (bbIdx == -1) break;
+        BasicBlock *dominatedBB =
+            (BasicBlock *) dvmGrowableListGetElement(blockList, bbIdx);
+        computeDomPostOrderTraversal(cUnit, dominatedBB);
+    }
+
+    /* Enter the current block id */
+    dvmInsertGrowableList(&cUnit->domPostOrderTraversal, bb->id);
+
+    /* hacky loop detection */
+    if (bb->taken && dvmIsBitSet(bb->dominators, bb->taken->id)) {
+        cUnit->hasLoop = true;
+    }
+}
+
+static void checkForDominanceFrontier(BasicBlock *domBB,
+                                      const BasicBlock *succBB)
+{
+    /*
+     * TODO - evaluate whether phi will ever need to be inserted into exit
+     * blocks.
+     */
+    if (succBB->iDom != domBB &&
+        succBB->blockType == kDalvikByteCode &&
+        succBB->hidden == false) {
+        dvmSetBit(domBB->domFrontier, succBB->id);
+    }
+}
+
+/* Worker function to compute the dominance frontier */
+static bool computeDominanceFrontier(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    GrowableList *blockList = &cUnit->blockList;
+
+    /* Calculate DF_local */
+    if (bb->taken) {
+        checkForDominanceFrontier(bb, bb->taken);
+    }
+    if (bb->fallThrough) {
+        checkForDominanceFrontier(bb, bb->fallThrough);
+    }
+    if (bb->successorBlockList.blockListType != kNotUsed) {
+        GrowableListIterator iterator;
+        dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
+                                    &iterator);
+        while (true) {
+            SuccessorBlockInfo *successorBlockInfo =
+                (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
+            if (successorBlockInfo == NULL) break;
+            BasicBlock *succBB = successorBlockInfo->block;
+            checkForDominanceFrontier(bb, succBB);
+        }
+    }
+
+    /* Calculate DF_up */
+    BitVectorIterator bvIterator;
+    dvmBitVectorIteratorInit(bb->iDominated, &bvIterator);
+    while (true) {
+        int dominatedIdx = dvmBitVectorIteratorNext(&bvIterator);
+        if (dominatedIdx == -1) break;
+        BasicBlock *dominatedBB = (BasicBlock *)
+            dvmGrowableListGetElement(blockList, dominatedIdx);
+        BitVectorIterator dfIterator;
+        dvmBitVectorIteratorInit(dominatedBB->domFrontier, &dfIterator);
+        while (true) {
+            int dfUpIdx = dvmBitVectorIteratorNext(&dfIterator);
+            if (dfUpIdx == -1) break;
+            BasicBlock *dfUpBlock = (BasicBlock *)
+                dvmGrowableListGetElement(blockList, dfUpIdx);
+            checkForDominanceFrontier(bb, dfUpBlock);
+        }
+    }
+
+    return true;
+}
+
+/* Worker function for initializing domination-related data structures */
+static bool initializeDominationInfo(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    int numTotalBlocks = cUnit->blockList.numUsed;
+
+    if (bb->dominators == NULL ) {
+        bb->dominators = dvmCompilerAllocBitVector(numTotalBlocks,
+                                                   false /* expandable */);
+        bb->iDominated = dvmCompilerAllocBitVector(numTotalBlocks,
+                                                   false /* expandable */);
+        bb->domFrontier = dvmCompilerAllocBitVector(numTotalBlocks,
+                                                   false /* expandable */);
+    } else {
+        dvmClearAllBits(bb->dominators);
+        dvmClearAllBits(bb->iDominated);
+        dvmClearAllBits(bb->domFrontier);
+    }
+    /* Set all bits in the dominator vector */
+    dvmSetInitialBits(bb->dominators, numTotalBlocks);
+
+    return true;
+}
+
+/* Worker function to compute each block's dominators */
+static bool computeBlockDominators(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    GrowableList *blockList = &cUnit->blockList;
+    int numTotalBlocks = blockList->numUsed;
+    BitVector *tempBlockV = cUnit->tempBlockV;
+    BitVectorIterator bvIterator;
+
+    /*
+     * The dominator of the entry block has been preset to itself and we need
+     * to skip the calculation here.
+     */
+    if (bb == cUnit->entryBlock) return false;
+
+    dvmSetInitialBits(tempBlockV, numTotalBlocks);
+
+    /* Iterate through the predecessors */
+    dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
+    while (true) {
+        int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+        if (predIdx == -1) break;
+        BasicBlock *predBB = (BasicBlock *) dvmGrowableListGetElement(
+                                 blockList, predIdx);
+        /* tempBlockV = tempBlockV ^ dominators */
+        dvmIntersectBitVectors(tempBlockV, tempBlockV, predBB->dominators);
+    }
+    dvmSetBit(tempBlockV, bb->id);
+    if (dvmCompareBitVectors(tempBlockV, bb->dominators)) {
+        dvmCopyBitVector(bb->dominators, tempBlockV);
+        return true;
+    }
+    return false;
+}
+
+/* Worker function to compute the idom */
+static bool computeImmediateDominator(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    GrowableList *blockList = &cUnit->blockList;
+    BitVector *tempBlockV = cUnit->tempBlockV;
+    BitVectorIterator bvIterator;
+    BasicBlock *iDom;
+
+    if (bb == cUnit->entryBlock) return false;
+
+    dvmCopyBitVector(tempBlockV, bb->dominators);
+    dvmClearBit(tempBlockV, bb->id);
+    dvmBitVectorIteratorInit(tempBlockV, &bvIterator);
+
+    /* Should not see any dead block */
+    assert(dvmCountSetBits(tempBlockV) != 0);
+    if (dvmCountSetBits(tempBlockV) == 1) {
+        iDom = (BasicBlock *) dvmGrowableListGetElement(
+                       blockList, dvmBitVectorIteratorNext(&bvIterator));
+        bb->iDom = iDom;
+    } else {
+        int iDomIdx = dvmBitVectorIteratorNext(&bvIterator);
+        assert(iDomIdx != -1);
+        while (true) {
+            int nextDom = dvmBitVectorIteratorNext(&bvIterator);
+            if (nextDom == -1) break;
+            BasicBlock *nextDomBB = (BasicBlock *)
+                dvmGrowableListGetElement(blockList, nextDom);
+            /* iDom dominates nextDom - set new iDom */
+            if (dvmIsBitSet(nextDomBB->dominators, iDomIdx)) {
+                iDomIdx = nextDom;
+            }
+
+        }
+        iDom = (BasicBlock *) dvmGrowableListGetElement(blockList, iDomIdx);
+        /* Set the immediate dominator block for bb */
+        bb->iDom = iDom;
+    }
+    /* Add bb to the iDominated set of the immediate dominator block */
+    dvmCompilerSetBit(iDom->iDominated, bb->id);
+    return true;
+}
+
+/* Compute dominators, immediate dominator, and dominance fronter */
+static void computeDominators(CompilationUnit *cUnit)
+{
+    int numReachableBlocks = cUnit->numReachableBlocks;
+    int numTotalBlocks = cUnit->blockList.numUsed;
+
+    /* Initialize domination-related data structures */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, initializeDominationInfo,
+                                          kReachableNodes,
+                                          false /* isIterative */);
+
+    /* Set the dominator for the root node */
+    dvmClearAllBits(cUnit->entryBlock->dominators);
+    dvmSetBit(cUnit->entryBlock->dominators, cUnit->entryBlock->id);
+
+    if (cUnit->tempBlockV == NULL) {
+        cUnit->tempBlockV = dvmCompilerAllocBitVector(numTotalBlocks,
+                                                  false /* expandable */);
+    } else {
+        dvmClearAllBits(cUnit->tempBlockV);
+    }
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeBlockDominators,
+                                          kPreOrderDFSTraversal,
+                                          true /* isIterative */);
+
+    cUnit->entryBlock->iDom = NULL;
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeImmediateDominator,
+                                          kReachableNodes,
+                                          false /* isIterative */);
+
+    /*
+     * Now go ahead and compute the post order traversal based on the
+     * iDominated sets.
+     */
+    if (cUnit->domPostOrderTraversal.elemList == NULL) {
+        dvmInitGrowableList(&cUnit->domPostOrderTraversal, numReachableBlocks);
+    } else {
+        cUnit->domPostOrderTraversal.numUsed = 0;
+    }
+
+    computeDomPostOrderTraversal(cUnit, cUnit->entryBlock);
+    assert(cUnit->domPostOrderTraversal.numUsed ==
+           (unsigned) cUnit->numReachableBlocks);
+
+    /* Now compute the dominance frontier for each block */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeDominanceFrontier,
+                                          kPostOrderDOMTraversal,
+                                          false /* isIterative */);
+}
+
+/*
+ * Perform dest U= src1 ^ ~src2
+ * This is probably not general enough to be placed in BitVector.[ch].
+ */
+static void computeSuccLiveIn(BitVector *dest,
+                              const BitVector *src1,
+                              const BitVector *src2)
+{
+    if (dest->storageSize != src1->storageSize ||
+        dest->storageSize != src2->storageSize ||
+        dest->expandable != src1->expandable ||
+        dest->expandable != src2->expandable) {
+        LOGE("Incompatible set properties");
+        dvmAbort();
+    }
+
+    unsigned int idx;
+    for (idx = 0; idx < dest->storageSize; idx++) {
+        dest->storage[idx] |= src1->storage[idx] & ~src2->storage[idx];
+    }
+}
+
+/*
+ * Iterate through all successor blocks and propagate up the live-in sets.
+ * The calculated result is used for phi-node pruning - where we only need to
+ * insert a phi node if the variable is live-in to the block.
+ */
+static bool computeBlockLiveIns(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    BitVector *tempDalvikRegisterV = cUnit->tempDalvikRegisterV;
+
+    if (bb->dataFlowInfo == NULL) return false;
+    dvmCopyBitVector(tempDalvikRegisterV, bb->dataFlowInfo->liveInV);
+    if (bb->taken && bb->taken->dataFlowInfo)
+        computeSuccLiveIn(tempDalvikRegisterV, bb->taken->dataFlowInfo->liveInV,
+                          bb->dataFlowInfo->defV);
+    if (bb->fallThrough && bb->fallThrough->dataFlowInfo)
+        computeSuccLiveIn(tempDalvikRegisterV,
+                          bb->fallThrough->dataFlowInfo->liveInV,
+                          bb->dataFlowInfo->defV);
+    if (bb->successorBlockList.blockListType != kNotUsed) {
+        GrowableListIterator iterator;
+        dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
+                                    &iterator);
+        while (true) {
+            SuccessorBlockInfo *successorBlockInfo =
+                (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
+            if (successorBlockInfo == NULL) break;
+            BasicBlock *succBB = successorBlockInfo->block;
+            if (succBB->dataFlowInfo) {
+                computeSuccLiveIn(tempDalvikRegisterV,
+                                  succBB->dataFlowInfo->liveInV,
+                                  bb->dataFlowInfo->defV);
+            }
+        }
+    }
+    if (dvmCompareBitVectors(tempDalvikRegisterV, bb->dataFlowInfo->liveInV)) {
+        dvmCopyBitVector(bb->dataFlowInfo->liveInV, tempDalvikRegisterV);
+        return true;
+    }
+    return false;
+}
+
+/* Insert phi nodes to for each variable to the dominance frontiers */
+static void insertPhiNodes(CompilationUnit *cUnit)
+{
+    int dalvikReg;
+    const GrowableList *blockList = &cUnit->blockList;
+    BitVector *phiBlocks =
+        dvmCompilerAllocBitVector(cUnit->numBlocks, false);
+    BitVector *tmpBlocks =
+        dvmCompilerAllocBitVector(cUnit->numBlocks, false);
+    BitVector *inputBlocks =
+        dvmCompilerAllocBitVector(cUnit->numBlocks, false);
+
+    cUnit->tempDalvikRegisterV =
+        dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false);
+
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeBlockLiveIns,
+                                          kPostOrderDFSTraversal,
+                                          true /* isIterative */);
+
+    /* Iterate through each Dalvik register */
+    for (dalvikReg = 0; dalvikReg < cUnit->numDalvikRegisters; dalvikReg++) {
+        bool change;
+        BitVectorIterator iterator;
+
+        dvmCopyBitVector(inputBlocks, cUnit->defBlockMatrix[dalvikReg]);
+        dvmClearAllBits(phiBlocks);
+
+        /* Calculate the phi blocks for each Dalvik register */
+        do {
+            change = false;
+            dvmClearAllBits(tmpBlocks);
+            dvmBitVectorIteratorInit(inputBlocks, &iterator);
+
+            while (true) {
+                int idx = dvmBitVectorIteratorNext(&iterator);
+                if (idx == -1) break;
+                BasicBlock *defBB =
+                    (BasicBlock *) dvmGrowableListGetElement(blockList, idx);
+
+                /* Merge the dominance frontier to tmpBlocks */
+                dvmUnifyBitVectors(tmpBlocks, tmpBlocks, defBB->domFrontier);
+            }
+            if (dvmCompareBitVectors(phiBlocks, tmpBlocks)) {
+                change = true;
+                dvmCopyBitVector(phiBlocks, tmpBlocks);
+
+                /*
+                 * Iterate through the original blocks plus the new ones in
+                 * the dominance frontier.
+                 */
+                dvmCopyBitVector(inputBlocks, phiBlocks);
+                dvmUnifyBitVectors(inputBlocks, inputBlocks,
+                                   cUnit->defBlockMatrix[dalvikReg]);
+            }
+        } while (change);
+
+        /*
+         * Insert a phi node for dalvikReg in the phiBlocks if the Dalvik
+         * register is in the live-in set.
+         */
+        dvmBitVectorIteratorInit(phiBlocks, &iterator);
+        while (true) {
+            int idx = dvmBitVectorIteratorNext(&iterator);
+            if (idx == -1) break;
+            BasicBlock *phiBB =
+                (BasicBlock *) dvmGrowableListGetElement(blockList, idx);
+            /* Variable will be clobbered before being used - no need for phi */
+            if (!dvmIsBitSet(phiBB->dataFlowInfo->liveInV, dalvikReg)) continue;
+            MIR *phi = (MIR *) dvmCompilerNew(sizeof(MIR), true);
+            phi->dalvikInsn.opcode = (Opcode)kMirOpPhi;
+            phi->dalvikInsn.vA = dalvikReg;
+            phi->offset = phiBB->startOffset;
+            dvmCompilerPrependMIR(phiBB, phi);
+        }
+    }
+}
+
+/*
+ * Worker function to insert phi-operands with latest SSA names from
+ * predecessor blocks
+ */
+static bool insertPhiNodeOperands(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    BitVector *ssaRegV = cUnit->tempSSARegisterV;
+    BitVectorIterator bvIterator;
+    GrowableList *blockList = &cUnit->blockList;
+    MIR *mir;
+
+    /* Phi nodes are at the beginning of each block */
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        if (mir->dalvikInsn.opcode != (Opcode)kMirOpPhi)
+            return true;
+        int ssaReg = mir->ssaRep->defs[0];
+        int encodedDalvikValue =
+            (int) dvmGrowableListGetElement(cUnit->ssaToDalvikMap, ssaReg);
+        int dalvikReg = DECODE_REG(encodedDalvikValue);
+
+        dvmClearAllBits(ssaRegV);
+
+        /* Iterate through the predecessors */
+        dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
+        while (true) {
+            int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+            if (predIdx == -1) break;
+            BasicBlock *predBB = (BasicBlock *) dvmGrowableListGetElement(
+                                     blockList, predIdx);
+            int encodedSSAValue =
+                predBB->dataFlowInfo->dalvikToSSAMap[dalvikReg];
+            int ssaReg = DECODE_REG(encodedSSAValue);
+            dvmSetBit(ssaRegV, ssaReg);
+        }
+
+        /* Count the number of SSA registers for a Dalvik register */
+        int numUses = dvmCountSetBits(ssaRegV);
+        mir->ssaRep->numUses = numUses;
+        mir->ssaRep->uses =
+            (int *) dvmCompilerNew(sizeof(int) * numUses, false);
+        mir->ssaRep->fpUse =
+            (bool *) dvmCompilerNew(sizeof(bool) * numUses, true);
+
+        BitVectorIterator phiIterator;
+
+        dvmBitVectorIteratorInit(ssaRegV, &phiIterator);
+        int *usePtr = mir->ssaRep->uses;
+
+        /* Set the uses array for the phi node */
+        while (true) {
+            int ssaRegIdx = dvmBitVectorIteratorNext(&phiIterator);
+            if (ssaRegIdx == -1) break;
+            *usePtr++ = ssaRegIdx;
+        }
+    }
+
+    return true;
+}
+
+/* Perform SSA transformation for the whole method */
+void dvmCompilerMethodSSATransformation(CompilationUnit *cUnit)
+{
+    /* Compute the DFS order */
+    computeDFSOrder(cUnit);
+
+    /* Compute the dominator info */
+    computeDominators(cUnit);
+
+    /* Allocate data structures in preparation for SSA conversion */
+    dvmInitializeSSAConversion(cUnit);
+
+    /* Find out the "Dalvik reg def x block" relation */
+    computeDefBlockMatrix(cUnit);
+
+    /* Insert phi nodes to dominance frontiers for all variables */
+    insertPhiNodes(cUnit);
+
+    /* Rename register names by local defs and phi nodes */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion,
+                                          kPreOrderDFSTraversal,
+                                          false /* isIterative */);
+
+    /*
+     * Shared temp bit vector used by each block to count the number of defs
+     * from all the predecessor blocks.
+     */
+    cUnit->tempSSARegisterV = dvmCompilerAllocBitVector(cUnit->numSSARegs,
+                                                        false);
+
+    /* Insert phi-operands with latest SSA names from predecessor blocks */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, insertPhiNodeOperands,
+                                          kReachableNodes,
+                                          false /* isIterative */);
+}
+
+/* Build a loop. Return true if a loop structure is successfully identified. */
+bool dvmCompilerBuildLoop(CompilationUnit *cUnit)
+{
+    /* Compute the DFS order */
+    computeDFSOrder(cUnit);
+
+    /* Compute the dominator info */
+    computeDominators(cUnit);
+
+    /* Loop structure not recognized/supported - return false */
+    if (dvmCompilerFilterLoopBlocks(cUnit) == false)
+        return false;
+
+    /* Re-compute the DFS order just for the loop */
+    computeDFSOrder(cUnit);
+
+    /* Re-compute the dominator info just for the loop */
+    computeDominators(cUnit);
+
+    /* Allocate data structures in preparation for SSA conversion */
+    dvmInitializeSSAConversion(cUnit);
+
+    /* Find out the "Dalvik reg def x block" relation */
+    computeDefBlockMatrix(cUnit);
+
+    /* Insert phi nodes to dominance frontiers for all variables */
+    insertPhiNodes(cUnit);
+
+    /* Rename register names by local defs and phi nodes */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion,
+                                          kPreOrderDFSTraversal,
+                                          false /* isIterative */);
+
+    /*
+     * Shared temp bit vector used by each block to count the number of defs
+     * from all the predecessor blocks.
+     */
+    cUnit->tempSSARegisterV = dvmCompilerAllocBitVector(cUnit->numSSARegs,
+                                                        false);
+
+    /* Insert phi-operands with latest SSA names from predecessor blocks */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, insertPhiNodeOperands,
+                                          kReachableNodes,
+                                          false /* isIterative */);
+
+    if (gDvmJit.receivedSIGUSR2 || gDvmJit.printMe) {
+        dvmDumpCFG(cUnit, "/sdcard/cfg/");
+    }
+
+    return true;
+}
diff --git a/vm/compiler/Utility.cpp b/vm/compiler/Utility.cpp
new file mode 100644
index 0000000..b69faba
--- /dev/null
+++ b/vm/compiler/Utility.cpp
@@ -0,0 +1,409 @@
+/*
+ * 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");
+        return false;
+    }
+    arenaHead->blockSize = ARENA_DEFAULT_SIZE;
+    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 <= currentArena->blockSize) {
+        void *ptr;
+        ptr = &currentArena->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;
+        }
+
+        size_t blockSize = (size < ARENA_DEFAULT_SIZE) ?
+                          ARENA_DEFAULT_SIZE : size;
+        /* Time to allocate a new arena */
+        ArenaMemBlock *newArena = (ArenaMemBlock *)
+            malloc(sizeof(ArenaMemBlock) + blockSize);
+        if (newArena == NULL) {
+            LOGE("Arena allocation failure");
+            dvmAbort();
+        }
+        newArena->blockSize = blockSize;
+        newArena->bytesAllocated = 0;
+        newArena->next = NULL;
+        currentArena->next = newArena;
+        currentArena = newArena;
+        numArenaBlocks++;
+        if (numArenaBlocks > 10)
+            LOGI("Total arena pages for JIT: %d", numArenaBlocks);
+        goto retry;
+    }
+    /* Should not reach here */
+    dvmAbort();
+}
+
+/* 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 = (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * 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;
+    }
+    intptr_t *newArray =
+        (intptr_t *) dvmCompilerNew(sizeof(intptr_t) * newLength, true);
+    memcpy(newArray, gList->elemList, sizeof(intptr_t) * gList->numAllocated);
+    gList->numAllocated = newLength;
+    gList->elemList = newArray;
+}
+
+/* Insert a new element into the growable list */
+void dvmInsertGrowableList(GrowableList *gList, intptr_t elem)
+{
+    assert(gList->numAllocated != 0);
+    if (gList->numUsed == gList->numAllocated) {
+        expandGrowableList(gList);
+    }
+    gList->elemList[gList->numUsed++] = elem;
+}
+
+void dvmGrowableListIteratorInit(GrowableList *gList,
+                                 GrowableListIterator *iterator)
+{
+    iterator->list = gList;
+    iterator->idx = 0;
+    iterator->size = gList->numUsed;
+}
+
+intptr_t dvmGrowableListIteratorNext(GrowableListIterator *iterator)
+{
+    assert(iterator->size == iterator->list->numUsed);
+    if (iterator->idx == iterator->size) return 0;
+    return iterator->list->elemList[iterator->idx++];
+}
+
+intptr_t dvmGrowableListGetElement(const GrowableList *gList, size_t idx)
+{
+    assert(idx < gList->numUsed);
+    return gList->elemList[idx];
+}
+
+/* Debug Utility - dump a compilation unit */
+void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
+{
+    BasicBlock *bb;
+    const char *blockTypeNames[] = {
+        "Normal Chaining Cell",
+        "Hot Chaining Cell",
+        "Singleton Chaining Cell",
+        "Predicted Chaining Cell",
+        "Backward Branch",
+        "Chaining Cell Gap",
+        "N/A",
+        "Entry Block",
+        "Code Block",
+        "Exit Block",
+        "PC Reconstruction",
+        "Exception Handling",
+    };
+
+    LOGD("Compiling %s %s", cUnit->method->clazz->descriptor,
+         cUnit->method->name);
+    LOGD("%d insns", dvmGetMethodInsnsSize(cUnit->method));
+    LOGD("%d blocks in total", cUnit->numBlocks);
+    GrowableListIterator iterator;
+
+    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+
+    while (true) {
+        bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        LOGD("Block %d (%s) (insn %04x - %04x%s)",
+             bb->id,
+             blockTypeNames[bb->blockType],
+             bb->startOffset,
+             bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
+             bb->lastMIRInsn ? "" : " empty");
+        if (bb->taken) {
+            LOGD("  Taken branch: block %d (%04x)",
+                 bb->taken->id, bb->taken->startOffset);
+        }
+        if (bb->fallThrough) {
+            LOGD("  Fallthrough : block %d (%04x)",
+                 bb->fallThrough->id, bb->fallThrough->startOffset);
+        }
+    }
+}
+
+/*
+ * dvmHashForeach callback.
+ */
+static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
+{
+    CompilerMethodStats *methodStats =
+        (CompilerMethodStats *) compilerMethodStats;
+    CompilerMethodStats *totalStats =
+        (CompilerMethodStats *) totalMethodStats;
+
+    totalStats->dalvikSize += methodStats->dalvikSize;
+    totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
+    totalStats->nativeSize += methodStats->nativeSize;
+
+    /* Enable the following when fine-tuning the JIT performance */
+#if 0
+    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)",
+             methodStats->method->clazz->descriptor,
+             methodStats->method->name,
+             methodStats->compiledDalvikSize,
+             methodStats->dalvikSize,
+             methodStats->nativeSize);
+    }
+#endif
+    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();
+    if (gDvmJit.methodStatsTable) {
+        dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
+                       &totalMethodStats);
+        LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
+             totalMethodStats.compiledDalvikSize,
+             totalMethodStats.dalvikSize,
+             totalMethodStats.nativeSize);
+    }
+}
+
+/*
+ * Allocate a bit vector with enough space to hold at least the specified
+ * number of bits.
+ *
+ * NOTE: this is the sister implementation of dvmAllocBitVector. In this version
+ * memory is allocated from the compiler arena.
+ */
+BitVector* dvmCompilerAllocBitVector(unsigned int startBits, bool expandable)
+{
+    BitVector* bv;
+    unsigned int count;
+
+    assert(sizeof(bv->storage[0]) == 4);        /* assuming 32-bit units */
+
+    bv = (BitVector*) dvmCompilerNew(sizeof(BitVector), false);
+
+    count = (startBits + 31) >> 5;
+
+    bv->storageSize = count;
+    bv->expandable = expandable;
+    bv->storage = (u4*) dvmCompilerNew(count * sizeof(u4), true);
+    return bv;
+}
+
+/*
+ * Mark the specified bit as "set".
+ *
+ * Returns "false" if the bit is outside the range of the vector and we're
+ * not allowed to expand.
+ *
+ * NOTE: this is the sister implementation of dvmSetBit. In this version
+ * memory is allocated from the compiler arena.
+ */
+bool dvmCompilerSetBit(BitVector *pBits, unsigned int num)
+{
+    if (num >= pBits->storageSize * sizeof(u4) * 8) {
+        if (!pBits->expandable)
+            dvmAbort();
+
+        /* Round up to word boundaries for "num+1" bits */
+        unsigned int newSize = (num + 1 + 31) >> 5;
+        assert(newSize > pBits->storageSize);
+        u4 *newStorage = (u4*)dvmCompilerNew(newSize * sizeof(u4), false);
+        memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(u4));
+        memset(&newStorage[pBits->storageSize], 0,
+               (newSize - pBits->storageSize) * sizeof(u4));
+        pBits->storage = newStorage;
+        pBits->storageSize = newSize;
+    }
+
+    pBits->storage[num >> 5] |= 1 << (num & 0x1f);
+    return true;
+}
+
+/*
+ * Mark the specified bit as "unset".
+ *
+ * Returns "false" if the bit is outside the range of the vector and we're
+ * not allowed to expand.
+ *
+ * NOTE: this is the sister implementation of dvmClearBit. In this version
+ * memory is allocated from the compiler arena.
+ */
+bool dvmCompilerClearBit(BitVector *pBits, unsigned int num)
+{
+    if (num >= pBits->storageSize * sizeof(u4) * 8) {
+        LOGE("Trying to clear a bit that is not set in the vector yet!");
+        dvmAbort();
+    }
+
+    pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
+    return true;
+}
+
+/*
+ * If set is true, mark all bits as 1. Otherwise mark all bits as 0.
+ */
+void dvmCompilerMarkAllBits(BitVector *pBits, bool set)
+{
+    int value = set ? -1 : 0;
+    memset(pBits->storage, value, pBits->storageSize * (int)sizeof(u4));
+}
+
+void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
+{
+    int i;
+
+    LOGE("%s", msg);
+    for (i = 0; i < length; i++) {
+        if (dvmIsBitSet(bv, i)) {
+            LOGE("    Bit %d is set", i);
+        }
+    }
+}
+
+void dvmCompilerAbort(CompilationUnit *cUnit)
+{
+    LOGE("Jit: aborting trace compilation, reverting to interpreter");
+    /* Force a traceback in debug builds */
+    assert(0);
+    /*
+     * Abort translation and force to interpret-only for this trace
+     * Matching setjmp in compiler thread work loop in Compiler.c.
+     */
+    longjmp(*cUnit->bailPtr, 1);
+}
+
+void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg,
+                           const BitVector *bv, int length)
+{
+    int i;
+
+    LOGE("%s", msg);
+    for (i = 0; i < length; i++) {
+        if (dvmIsBitSet(bv, i)) {
+            BasicBlock *bb =
+                (BasicBlock *) dvmGrowableListGetElement(blocks, i);
+            char blockName[BLOCK_NAME_LEN];
+            dvmGetBlockName(bb, blockName);
+            LOGE("Bit %d / %s is set", i, blockName);
+        }
+    }
+}
+
+void dvmGetBlockName(BasicBlock *bb, char *name)
+{
+    switch (bb->blockType) {
+        case kEntryBlock:
+            snprintf(name, BLOCK_NAME_LEN, "entry");
+            break;
+        case kExitBlock:
+            snprintf(name, BLOCK_NAME_LEN, "exit");
+            break;
+        case kDalvikByteCode:
+            snprintf(name, BLOCK_NAME_LEN, "block%04x", bb->startOffset);
+            break;
+        case kChainingCellNormal:
+            snprintf(name, BLOCK_NAME_LEN, "chain%04x", bb->startOffset);
+            break;
+        case kExceptionHandling:
+            snprintf(name, BLOCK_NAME_LEN, "exception%04x", bb->startOffset);
+            break;
+        default:
+            snprintf(name, BLOCK_NAME_LEN, "??");
+            break;
+    }
+}
diff --git a/vm/compiler/codegen/CodegenFactory.cpp b/vm/compiler/codegen/CodegenFactory.cpp
new file mode 100644
index 0000000..f42ae74
--- /dev/null
+++ b/vm/compiler/codegen/CodegenFactory.cpp
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains target-independent codegen and support, and is
+ * included by:
+ *
+ *        $(TARGET_ARCH)/Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directories below this one.
+ *
+ * Prior to including this file, TGT_LIR should be #defined.
+ * For example, for arm:
+ *    #define TGT_LIR ArmLIR
+ * and for x86:
+ *    #define TGT_LIR X86LIR
+ */
+
+
+/* Load a word at base + displacement.  Displacement must be word multiple */
+static TGT_LIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rDest)
+{
+    return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
+                        INVALID_SREG);
+}
+
+static TGT_LIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc)
+{
+    return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
+}
+
+/*
+ * Load a Dalvik register into a physical register.  Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness.  That is the responsibility of the caller.
+ */
+static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
+                            int reg1)
+{
+    rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopy(cUnit, reg1, rlSrc.lowReg);
+    } else  if (rlSrc.location == kLocRetval) {
+        loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
+    } else {
+        assert(rlSrc.location == kLocDalvikFrame);
+        loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
+                     reg1);
+    }
+}
+
+/*
+ * Similar to loadValueDirect, but clobbers and allocates the target
+ * register.  Should be used when loading to a fixed register (for example,
+ * loading arguments to an out of line call.
+ */
+static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+                                 int reg1)
+{
+    dvmCompilerClobber(cUnit, reg1);
+    dvmCompilerMarkInUse(cUnit, reg1);
+    loadValueDirect(cUnit, rlSrc, reg1);
+}
+
+/*
+ * Load a Dalvik register pair into a physical register[s].  Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness.  That is the responsibility of the caller.
+ */
+static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
+                                int regLo, int regHi)
+{
+    rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
+    } else if (rlSrc.location == kLocRetval) {
+        loadBaseDispWide(cUnit, NULL, rSELF,
+                         offsetof(Thread, interpSave.retval),
+                         regLo, regHi, INVALID_SREG);
+    } else {
+        assert(rlSrc.location == kLocDalvikFrame);
+            loadBaseDispWide(cUnit, NULL, rFP,
+                             dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
+                             regLo, regHi, INVALID_SREG);
+    }
+}
+
+/*
+ * Similar to loadValueDirect, but clobbers and allocates the target
+ * registers.  Should be used when loading to a fixed registers (for example,
+ * loading arguments to an out of line call.
+ */
+static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+                                     int regLo, int regHi)
+{
+    dvmCompilerClobber(cUnit, regLo);
+    dvmCompilerClobber(cUnit, regHi);
+    dvmCompilerMarkInUse(cUnit, regLo);
+    dvmCompilerMarkInUse(cUnit, regHi);
+    loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
+}
+
+static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
+                             RegisterClass opKind)
+{
+    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
+    if (rlSrc.location == kLocDalvikFrame) {
+        loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
+        rlSrc.location = kLocPhysReg;
+        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+    } else if (rlSrc.location == kLocRetval) {
+        loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
+                     rlSrc.lowReg);
+        rlSrc.location = kLocPhysReg;
+        dvmCompilerClobber(cUnit, rlSrc.lowReg);
+    }
+    return rlSrc;
+}
+
+static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc)
+{
+    LIR *defStart;
+    LIR *defEnd;
+    assert(!rlDest.wide);
+    assert(!rlSrc.wide);
+    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
+    rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
+    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
+    if (rlSrc.location == kLocPhysReg) {
+        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
+            (rlDest.location == kLocPhysReg)) {
+            // Src is live or Dest has assigned reg.
+            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+            genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
+        } else {
+            // Just re-assign the registers.  Dest gets Src's regs
+            rlDest.lowReg = rlSrc.lowReg;
+            dvmCompilerClobber(cUnit, rlSrc.lowReg);
+        }
+    } else {
+        // Load Src either into promoted Dest or temps allocated for Dest
+        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+        loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
+    }
+
+    // Dest is now live and dirty (until/if we flush it to home location)
+    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
+
+
+    if (rlDest.location == kLocRetval) {
+        storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
+                      rlDest.lowReg, kWord);
+        dvmCompilerClobber(cUnit, rlDest.lowReg);
+    } else {
+        dvmCompilerResetDefLoc(cUnit, rlDest);
+        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
+            defStart = (LIR *)cUnit->lastLIRInsn;
+            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
+            storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
+            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
+            defEnd = (LIR *)cUnit->lastLIRInsn;
+            dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
+        }
+    }
+}
+
+static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
+                                 RegisterClass opKind)
+{
+    assert(rlSrc.wide);
+    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
+    if (rlSrc.location == kLocDalvikFrame) {
+        loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
+        rlSrc.location = kLocPhysReg;
+        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+        dvmCompilerMarkLive(cUnit, rlSrc.highReg,
+                            dvmCompilerSRegHi(rlSrc.sRegLow));
+    } else if (rlSrc.location == kLocRetval) {
+        loadBaseDispWide(cUnit, NULL, rSELF,
+                         offsetof(Thread, interpSave.retval),
+                         rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
+        rlSrc.location = kLocPhysReg;
+        dvmCompilerClobber(cUnit, rlSrc.lowReg);
+        dvmCompilerClobber(cUnit, rlSrc.highReg);
+    }
+    return rlSrc;
+}
+
+static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
+                           RegLocation rlSrc)
+{
+    LIR *defStart;
+    LIR *defEnd;
+    assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
+    assert(rlDest.wide);
+    assert(rlSrc.wide);
+    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
+    if (rlSrc.location == kLocPhysReg) {
+        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
+            dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
+            (rlDest.location == kLocPhysReg)) {
+            // Src is live or Dest has assigned reg.
+            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+            genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
+                           rlSrc.lowReg, rlSrc.highReg);
+        } else {
+            // Just re-assign the registers.  Dest gets Src's regs
+            rlDest.lowReg = rlSrc.lowReg;
+            rlDest.highReg = rlSrc.highReg;
+            dvmCompilerClobber(cUnit, rlSrc.lowReg);
+            dvmCompilerClobber(cUnit, rlSrc.highReg);
+        }
+    } else {
+        // Load Src either into promoted Dest or temps allocated for Dest
+        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
+        loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
+                            rlDest.highReg);
+    }
+
+    // Dest is now live and dirty (until/if we flush it to home location)
+    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+    dvmCompilerMarkLive(cUnit, rlDest.highReg,
+                        dvmCompilerSRegHi(rlDest.sRegLow));
+    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
+    dvmCompilerMarkDirty(cUnit, rlDest.highReg);
+    dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
+
+
+    if (rlDest.location == kLocRetval) {
+        storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
+                          rlDest.lowReg, rlDest.highReg);
+        dvmCompilerClobber(cUnit, rlDest.lowReg);
+        dvmCompilerClobber(cUnit, rlDest.highReg);
+    } else {
+        dvmCompilerResetDefLocWide(cUnit, rlDest);
+        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
+            dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
+            defStart = (LIR *)cUnit->lastLIRInsn;
+            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
+            assert((vReg+1) == dvmCompilerS2VReg(cUnit,
+                                     dvmCompilerSRegHi(rlDest.sRegLow)));
+            storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
+                              rlDest.highReg);
+            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
+            dvmCompilerMarkClean(cUnit, rlDest.highReg);
+            defEnd = (LIR *)cUnit->lastLIRInsn;
+            dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
+        }
+    }
+}
diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h
new file mode 100644
index 0000000..6495d07
--- /dev/null
+++ b/vm/compiler/codegen/CompilerCodegen.h
@@ -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.
+ */
+
+#ifndef DALVIK_VM_COMPILERCODEGEN_H_
+#define DALVIK_VM_COMPILERCODEGEN_H_
+
+#include "compiler/CompilerIR.h"
+
+/* Maximal number of switch cases to have inline chains */
+#define MAX_CHAINED_SWITCH_CASES 64
+
+/* Work unit is architecture dependent */
+bool dvmCompilerDoWork(CompilerWorkOrder *work);
+
+/* Lower middle-level IR to low-level IR */
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit);
+
+/* Lower middle-level IR to low-level IR for the whole method */
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit);
+
+/* Assemble LIR into machine code */
+void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info);
+
+/* Perform translation chain operation. */
+extern "C" void* dvmJitChain(void* tgtAddr, u4* branchAddr);
+
+/* Install class objects in the literal pool */
+void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit,
+                                      char *codeAddress);
+
+/* Patch inline cache content for polymorphic callsites */
+bool dvmJitPatchInlineCache(void *cellPtr, void *contentPtr);
+
+/* Implemented in the codegen/<target>/ArchUtility.c */
+void dvmCompilerCodegenDump(CompilationUnit *cUnit);
+
+/* Implemented in the codegen/<target>/Assembler.c */
+void dvmCompilerPatchInlineCache(void);
+
+/* Implemented in codegen/<target>/Ralloc.c */
+void dvmCompilerLocalRegAlloc(CompilationUnit *cUnit);
+
+/* Implemented in codegen/<target>/Thumb<version>Util.c */
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit);
+
+/* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
+JitInstructionSetType dvmCompilerInstructionSet(void);
+
+/*
+ * Implemented in codegen/<target>/<target_variant>/ArchVariant.c
+ * Architecture-specific initializations and checks
+ */
+bool dvmCompilerArchVariantInit(void);
+
+/* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
+int dvmCompilerTargetOptHint(int key);
+
+/* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind);
+
+#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..43d98ed
--- /dev/null
+++ b/vm/compiler/codegen/Optimizer.h
@@ -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.
+ */
+
+#ifndef DALVIK_VM_COMPILER_OPTIMIZATION_H_
+#define DALVIK_VM_COMPILER_OPTIMIZATION_H_
+
+#include "Dalvik.h"
+
+/*
+ * If the corresponding bit is set in gDvmJit.disableOpt, the selected
+ * optimization will be suppressed.
+ */
+enum optControlVector {
+    kLoadStoreElimination = 0,
+    kLoadHoisting,
+    kTrackLiveTemps,
+    kSuppressLoads,
+    kMethodInlining,
+    kMethodJit,
+};
+
+/* Forward declarations */
+struct CompilationUnit;
+struct LIR;
+
+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/Ralloc.h b/vm/compiler/codegen/Ralloc.h
new file mode 100644
index 0000000..2296fbc
--- /dev/null
+++ b/vm/compiler/codegen/Ralloc.h
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains target independent register alloction support.
+ */
+
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+
+/*
+ * Return most flexible allowed register class based on size.
+ * Bug: 2813841
+ * Must use a core register for data types narrower than word (due
+ * to possible unaligned load/store.
+ */
+static inline RegisterClass dvmCompilerRegClassBySize(OpSize size)
+{
+    return (size == kUnsignedHalf ||
+            size == kSignedHalf ||
+            size == kUnsignedByte ||
+            size == kSignedByte ) ? kCoreReg : kAnyReg;
+}
+
+static inline int dvmCompilerS2VReg(CompilationUnit *cUnit, int sReg)
+{
+    assert(sReg != INVALID_SREG);
+    return DECODE_REG(dvmConvertSSARegToDalvik(cUnit, sReg));
+}
+
+/* Reset the tracker to unknown state */
+static inline void dvmCompilerResetNullCheck(CompilationUnit *cUnit)
+{
+    dvmClearAllBits(cUnit->regPool->nullCheckedRegs);
+}
+
+/*
+ * Get the "real" sreg number associated with an sReg slot.  In general,
+ * sReg values passed through codegen are the SSA names created by
+ * dataflow analysis and refer to slot numbers in the cUnit->regLocation
+ * array.  However, renaming is accomplished by simply replacing RegLocation
+ * entries in the cUnit->reglocation[] array.  Therefore, when location
+ * records for operands are first created, we need to ask the locRecord
+ * identified by the dataflow pass what it's new name is.
+ */
+
+static inline int dvmCompilerSRegHi(int lowSreg) {
+    return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
+}
+
+
+static inline bool dvmCompilerLiveOut(CompilationUnit *cUnit, int sReg)
+{
+    //TODO: fully implement
+    return true;
+}
+
+static inline int dvmCompilerSSASrc(MIR *mir, int num)
+{
+    assert(mir->ssaRep->numUses > num);
+    return mir->ssaRep->uses[num];
+}
+
+extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
+                                      int regClass, bool update);
+/* Mark a temp register as dead.  Does not affect allocation state. */
+extern void dvmCompilerClobber(CompilationUnit *cUnit, int reg);
+
+extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit,
+                                        RegLocation loc);
+
+/* see comments for updateLoc */
+extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit,
+                                            RegLocation loc);
+
+/* Clobber all of the temps that might be used by a handler. */
+extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit);
+
+extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg);
+
+extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg,
+                                int highReg);
+
+extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl);
+
+/* Set up temp & preserved register pools specialized by target */
+extern void dvmCompilerInitPool(RegisterInfo *regs, int *regNums, int num);
+
+/*
+ * Mark the beginning and end LIR of a def sequence.  Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl,
+                               LIR *start, LIR *finish);
+/*
+ * Mark the beginning and end LIR of a def sequence.  Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
+                                   LIR *start, LIR *finish);
+
+extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
+                                         int low, int high);
+
+extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
+                                          int low, int high);
+// Get the LocRecord associated with an SSA name use.
+extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num);
+
+// Get the LocRecord associated with an SSA name def.
+extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir,
+                                      int num);
+
+extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit);
+
+/* Clobber all regs that might be used by an external C call */
+extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit);
+
+extern RegisterInfo *dvmCompilerIsTemp(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg);
+
+extern int dvmCompilerAllocTemp(CompilationUnit *cUnit);
+
+extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit);
+
+//REDO: too many assumptions.
+extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit);
+
+extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg);
+
+extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl);
+
+extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit);
+
+/* Kill the corresponding bit in the null-checked register list */
+extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
+                                          RegLocation loc);
+
+//FIXME - this needs to also check the preserved pool.
+extern RegisterInfo *dvmCompilerIsLive(CompilationUnit *cUnit, int reg);
+
+/* To be used when explicitly managing register use */
+extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit);
+
+extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit);
+
+extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit);
+
+extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit);
+
+extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit);
+
+/* Clobber any temp associated with an sReg.  Could be in either class */
+extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg);
+
+/* Return a temp if one is available, -1 otherwise */
+extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit);
+
+/*
+ * Similar to dvmCompilerAllocTemp(), but forces the allocation of a specific
+ * register.  No check is made to see if the register was previously
+ * allocated.  Use with caution.
+ */
+extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg);
+
+extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit,
+                                           RegLocation rl);
+
+/*
+ * Free all allocated temps in the temp pools.  Note that this does
+ * not affect the "liveness" of a temp register, which will stay
+ * live until it is either explicitly killed or reallocated.
+ */
+extern void dvmCompilerResetRegPool(CompilationUnit *cUnit);
+
+extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit);
+
+extern void dvmCompilerFlushRegWide(CompilationUnit *cUnit, int reg1, int reg2);
+
+extern void dvmCompilerFlushReg(CompilationUnit *cUnit, int reg);
+
+/*
+ * Architecture-dependent register allocation routines implemented in
+ * ${TARGET_ARCH}/${TARGET_ARCH_VARIANT}/Ralloc.c
+ */
+extern int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit,
+                                         bool fpHint, int regClass);
+
+extern int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint,
+                                     int regClass);
+
+extern ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
+
+extern void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo,
+                                   int destHi, int srcLo, int srcHi);
+
+extern void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
+                                    int displacement, int rSrc, OpSize size);
+
+extern void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
+                                        int displacement, int rSrcLo,
+                                        int rSrcHi);
diff --git a/vm/compiler/codegen/RallocUtil.cpp b/vm/compiler/codegen/RallocUtil.cpp
new file mode 100644
index 0000000..27d1f05
--- /dev/null
+++ b/vm/compiler/codegen/RallocUtil.cpp
@@ -0,0 +1,904 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "Ralloc.h"
+
+#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
+/*
+ * Get the "real" sreg number associated with an sReg slot.  In general,
+ * sReg values passed through codegen are the SSA names created by
+ * dataflow analysis and refer to slot numbers in the cUnit->regLocation
+ * array.  However, renaming is accomplished by simply replacing RegLocation
+ * entries in the cUnit->reglocation[] array.  Therefore, when location
+ * records for operands are first created, we need to ask the locRecord
+ * identified by the dataflow pass what it's new name is.
+ */
+
+/*
+ * Free all allocated temps in the temp pools.  Note that this does
+ * not affect the "liveness" of a temp register, which will stay
+ * live until it is either explicitly killed or reallocated.
+ */
+extern void dvmCompilerResetRegPool(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
+        cUnit->regPool->coreTemps[i].inUse = false;
+    }
+    for (i=0; i < cUnit->regPool->numFPTemps; i++) {
+        cUnit->regPool->FPTemps[i].inUse = false;
+    }
+}
+
+ /* Set up temp & preserved register pools specialized by target */
+extern void dvmCompilerInitPool(RegisterInfo *regs, int *regNums, int num)
+{
+    int i;
+    for (i=0; i < num; i++) {
+        regs[i].reg = regNums[i];
+        regs[i].inUse = false;
+        regs[i].pair = false;
+        regs[i].live = false;
+        regs[i].dirty = false;
+        regs[i].sReg = INVALID_SREG;
+    }
+}
+
+static void dumpRegPool(RegisterInfo *p, int numRegs)
+{
+    int i;
+    LOGE("================================================");
+    for (i=0; i < numRegs; i++ ){
+        LOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
+           p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live,
+           p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd);
+    }
+    LOGE("================================================");
+}
+
+static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
+{
+    int numTemps = cUnit->regPool->numCoreTemps;
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    LOGE("Tried to get info on a non-existant temp: r%d",reg);
+    dvmCompilerAbort(cUnit);
+    return NULL;
+}
+
+void dvmCompilerFlushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
+{
+    RegisterInfo *info1 = getRegInfo(cUnit, reg1);
+    RegisterInfo *info2 = getRegInfo(cUnit, reg2);
+    assert(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        info1->dirty = false;
+        info2->dirty = false;
+        if (dvmCompilerS2VReg(cUnit, info2->sReg) <
+            dvmCompilerS2VReg(cUnit, info1->sReg))
+            info1 = info2;
+        dvmCompilerFlushRegWideImpl(cUnit, rFP,
+                                    dvmCompilerS2VReg(cUnit, info1->sReg) << 2,
+                                    info1->reg, info1->partner);
+    }
+}
+
+void dvmCompilerFlushReg(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        dvmCompilerFlushRegImpl(cUnit, rFP,
+                                dvmCompilerS2VReg(cUnit, info->sReg) << 2,
+                                reg, kWord);
+    }
+}
+
+/* return true if found reg to clobber */
+static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
+                           int numTemps, int reg)
+{
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            if (p[i].live && p[i].dirty) {
+                if (p[i].pair) {
+                    dvmCompilerFlushRegWide(cUnit, p[i].reg, p[i].partner);
+                } else {
+                    dvmCompilerFlushReg(cUnit, p[i].reg);
+                }
+            }
+            p[i].live = false;
+            p[i].sReg = INVALID_SREG;
+            p[i].defStart = NULL;
+            p[i].defEnd = NULL;
+            if (p[i].pair) {
+                p[i].pair = false;
+                /* partners should be in same pool */
+                clobberRegBody(cUnit, p, numTemps, p[i].partner);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+/* Mark a temp register as dead.  Does not affect allocation state. */
+void dvmCompilerClobber(CompilationUnit *cUnit, int reg)
+{
+    if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
+                        cUnit->regPool->numCoreTemps, reg)) {
+        clobberRegBody(cUnit, cUnit->regPool->FPTemps,
+                       cUnit->regPool->numFPTemps, reg);
+    }
+}
+
+static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
+{
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].sReg == sReg) {
+            p[i].live = false;
+            p[i].defStart = NULL;
+            p[i].defEnd = NULL;
+        }
+    }
+}
+
+/* Clobber any temp associated with an sReg.  Could be in either class */
+extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg)
+{
+    clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
+                    sReg);
+    clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
+                    sReg);
+}
+
+static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
+                         int *nextTemp, bool required)
+{
+    int i;
+    int next = *nextTemp;
+    for (i=0; i< numTemps; i++) {
+        if (next >= numTemps)
+            next = 0;
+        if (!p[next].inUse && !p[next].live) {
+            dvmCompilerClobber(cUnit, p[next].reg);
+            p[next].inUse = true;
+            p[next].pair = false;
+            *nextTemp = next + 1;
+            return p[next].reg;
+        }
+        next++;
+    }
+    next = *nextTemp;
+    for (i=0; i< numTemps; i++) {
+        if (next >= numTemps)
+            next = 0;
+        if (!p[next].inUse) {
+            dvmCompilerClobber(cUnit, p[next].reg);
+            p[next].inUse = true;
+            p[next].pair = false;
+            *nextTemp = next + 1;
+            return p[next].reg;
+        }
+        next++;
+    }
+    if (required) {
+        LOGE("No free temp registers");
+        dvmCompilerAbort(cUnit);
+    }
+    return -1;  // No register available
+}
+
+//REDO: too many assumptions.
+extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit)
+{
+    RegisterInfo *p = cUnit->regPool->FPTemps;
+    int numTemps = cUnit->regPool->numFPTemps;
+    int next = cUnit->regPool->nextFPTemp;
+    int i;
+
+    for (i=0; i < numTemps; i+=2) {
+        /* Cleanup - not all targets need aligned regs */
+        if (next & 1)
+            next++;
+        if (next >= numTemps)
+            next = 0;
+        if ((!p[next].inUse && !p[next].live) &&
+            (!p[next+1].inUse && !p[next+1].live)) {
+            dvmCompilerClobber(cUnit, p[next].reg);
+            dvmCompilerClobber(cUnit, p[next+1].reg);
+            p[next].inUse = true;
+            p[next+1].inUse = true;
+            assert((p[next].reg+1) == p[next+1].reg);
+            assert((p[next].reg & 0x1) == 0);
+            cUnit->regPool->nextFPTemp += 2;
+            return p[next].reg;
+        }
+        next += 2;
+    }
+    next = cUnit->regPool->nextFPTemp;
+    for (i=0; i < numTemps; i+=2) {
+        if (next >= numTemps)
+            next = 0;
+        if (!p[next].inUse && !p[next+1].inUse) {
+            dvmCompilerClobber(cUnit, p[next].reg);
+            dvmCompilerClobber(cUnit, p[next+1].reg);
+            p[next].inUse = true;
+            p[next+1].inUse = true;
+            assert((p[next].reg+1) == p[next+1].reg);
+            assert((p[next].reg & 0x1) == 0);
+            cUnit->regPool->nextFPTemp += 2;
+            return p[next].reg;
+        }
+        next += 2;
+    }
+    LOGE("No free temp registers");
+    dvmCompilerAbort(cUnit);
+    return -1;
+}
+
+/* Return a temp if one is available, -1 otherwise */
+extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit)
+{
+    return allocTempBody(cUnit, cUnit->regPool->coreTemps,
+                         cUnit->regPool->numCoreTemps,
+                         &cUnit->regPool->nextCoreTemp, true);
+}
+
+extern int dvmCompilerAllocTemp(CompilationUnit *cUnit)
+{
+    return allocTempBody(cUnit, cUnit->regPool->coreTemps,
+                         cUnit->regPool->numCoreTemps,
+                         &cUnit->regPool->nextCoreTemp, true);
+}
+
+extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit)
+{
+    return allocTempBody(cUnit, cUnit->regPool->FPTemps,
+                         cUnit->regPool->numFPTemps,
+                         &cUnit->regPool->nextFPTemp, true);
+}
+
+static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg)
+{
+    int i;
+    if (sReg == -1)
+        return NULL;
+    for (i=0; i < numTemps; i++) {
+        if (p[i].live && (p[i].sReg == sReg)) {
+            p[i].inUse = true;
+            return &p[i];
+        }
+    }
+    return NULL;
+}
+
+static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
+                               int regClass)
+{
+    RegisterInfo *res = NULL;
+    switch(regClass) {
+        case kAnyReg:
+            res = allocLiveBody(cUnit->regPool->FPTemps,
+                                cUnit->regPool->numFPTemps, sReg);
+            if (res)
+                break;
+            /* Intentional fallthrough */
+        case kCoreReg:
+            res = allocLiveBody(cUnit->regPool->coreTemps,
+                                cUnit->regPool->numCoreTemps, sReg);
+            break;
+        case kFPReg:
+            res = allocLiveBody(cUnit->regPool->FPTemps,
+                                cUnit->regPool->numFPTemps, sReg);
+            break;
+        default:
+            LOGE("Invalid register type");
+            dvmCompilerAbort(cUnit);
+    }
+    return res;
+}
+
+extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = false;
+            p[i].pair = false;
+            return;
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = false;
+            p[i].pair = false;
+            return;
+        }
+    }
+    LOGE("Tried to free a non-existant temp: r%d",reg);
+    dvmCompilerAbort(cUnit);
+}
+
+extern RegisterInfo *dvmCompilerIsLive(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return p[i].live ? &p[i] : NULL;
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return p[i].live ? &p[i] : NULL;
+        }
+    }
+    return NULL;
+}
+
+extern RegisterInfo *dvmCompilerIsTemp(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Similar to dvmCompilerAllocTemp(), but forces the allocation of a specific
+ * register.  No check is made to see if the register was previously
+ * allocated.  Use with caution.
+ */
+extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = true;
+            p[i].live = false;
+            return;
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = true;
+            p[i].live = false;
+            return;
+        }
+    }
+    LOGE("Tried to lock a non-existant temp: r%d",reg);
+    dvmCompilerAbort(cUnit);
+}
+
+extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = getRegInfo(cUnit, reg);
+    p->defStart = NULL;
+    p->defEnd = NULL;
+}
+
+static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
+                         int sReg1, int sReg2)
+{
+    if (start && finish) {
+        LIR *p;
+        assert(sReg1 == sReg2);
+        for (p = start; ;p = p->next) {
+            ((ArmLIR *)p)->flags.isNop = true;
+            if (p == finish)
+                break;
+        }
+    }
+}
+
+/*
+ * Mark the beginning and end LIR of a def sequence.  Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl,
+                    LIR *start, LIR *finish)
+{
+    assert(!rl.wide);
+    assert(start && start->next);
+    assert(finish);
+    RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+    p->defStart = start->next;
+    p->defEnd = finish;
+}
+
+/*
+ * Mark the beginning and end LIR of a def sequence.  Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
+                        LIR *start, LIR *finish)
+{
+    assert(rl.wide);
+    assert(start && start->next);
+    assert(finish);
+    RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+    dvmCompilerResetDef(cUnit, rl.highReg);  // Only track low of pair
+    p->defStart = start->next;
+    p->defEnd = finish;
+}
+
+extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit,
+                                           RegLocation rl)
+{
+    assert(rl.wide);
+    if (rl.location == kLocPhysReg) {
+        RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
+        RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
+        if (!infoLo->pair) {
+            dumpRegPool(cUnit->regPool->coreTemps,
+                        cUnit->regPool->numCoreTemps);
+            assert(infoLo->pair);
+        }
+        if (!infoHi->pair) {
+            dumpRegPool(cUnit->regPool->coreTemps,
+                        cUnit->regPool->numCoreTemps);
+            assert(infoHi->pair);
+        }
+        assert(infoLo->pair);
+        assert(infoHi->pair);
+        assert(infoLo->partner == infoHi->reg);
+        assert(infoHi->partner == infoLo->reg);
+        infoLo->pair = false;
+        infoHi->pair = false;
+        infoLo->defStart = NULL;
+        infoLo->defEnd = NULL;
+        infoHi->defStart = NULL;
+        infoHi->defEnd = NULL;
+    }
+    rl.wide = false;
+    return rl;
+}
+
+extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl)
+{
+    assert(!rl.wide);
+    if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
+        RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+        assert(!p->pair);
+        nullifyRange(cUnit, p->defStart, p->defEnd,
+                     p->sReg, rl.sRegLow);
+    }
+    dvmCompilerResetDef(cUnit, rl.lowReg);
+}
+
+extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
+{
+    assert(rl.wide);
+    if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
+        RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+        assert(p->pair);
+        nullifyRange(cUnit, p->defStart, p->defEnd,
+                     p->sReg, rl.sRegLow);
+    }
+    dvmCompilerResetDef(cUnit, rl.lowReg);
+    dvmCompilerResetDef(cUnit, rl.highReg);
+}
+
+extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+        dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
+    }
+    for (i=0; i< cUnit->regPool->numFPTemps; i++) {
+        dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
+    }
+}
+
+extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+        dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg);
+    }
+    for (i=0; i< cUnit->regPool->numFPTemps; i++) {
+        dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg);
+    }
+}
+
+/* To be used when explicitly managing register use */
+extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+        dvmCompilerLockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
+    }
+}
+
+// Make sure nothing is live and dirty
+static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
+                             int numRegs)
+{
+    int i;
+    for (i=0; i < numRegs; i++) {
+        if (info[i].live && info[i].dirty) {
+            if (info[i].pair) {
+                dvmCompilerFlushRegWide(cUnit, info[i].reg, info[i].partner);
+            } else {
+                dvmCompilerFlushReg(cUnit, info[i].reg);
+            }
+        }
+    }
+}
+
+extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit)
+{
+    flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
+                     cUnit->regPool->numCoreTemps);
+    flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
+                     cUnit->regPool->numFPTemps);
+    dvmCompilerClobberAllRegs(cUnit);
+}
+
+
+//TUNING: rewrite all of this reg stuff.  Probably use an attribute table
+static bool regClassMatches(int regClass, int reg)
+{
+    if (regClass == kAnyReg) {
+        return true;
+    } else if (regClass == kCoreReg) {
+        return !FPREG(reg);
+    } else {
+        return FPREG(reg);
+    }
+}
+
+extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
+        return;  /* already live */
+    } else if (sReg != INVALID_SREG) {
+        dvmCompilerClobberSReg(cUnit, sReg);
+        info->live = true;
+    } else {
+        /* Can't be live if no associated sReg */
+        info->live = false;
+    }
+    info->sReg = sReg;
+}
+
+extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg, int highReg)
+{
+    RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
+    RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
+    infoLo->pair = infoHi->pair = true;
+    infoLo->partner = highReg;
+    infoHi->partner = lowReg;
+}
+
+extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    info->dirty = false;
+}
+
+extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    info->dirty = true;
+}
+
+extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
+{
+      RegisterInfo *info = getRegInfo(cUnit, reg);
+          info->inUse = true;
+}
+
+static void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
+{
+    RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
+    RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
+    *newInfo = *oldInfo;
+    newInfo->reg = newReg;
+}
+
+/*
+ * Return an updated location record with current in-register status.
+ * If the value lives in live temps, reflect that fact.  No code
+ * is generated.  The the live value is part of an older pair,
+ * clobber both low and high.
+ * TUNING: clobbering both is a bit heavy-handed, but the alternative
+ * is a bit complex when dealing with FP regs.  Examine code to see
+ * if it's worthwhile trying to be more clever here.
+ */
+extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc)
+{
+    assert(!loc.wide);
+    if (loc.location == kLocDalvikFrame) {
+        RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+        if (infoLo) {
+            if (infoLo->pair) {
+                dvmCompilerClobber(cUnit, infoLo->reg);
+                dvmCompilerClobber(cUnit, infoLo->partner);
+            } else {
+                loc.lowReg = infoLo->reg;
+                loc.location = kLocPhysReg;
+            }
+        }
+    }
+
+    return loc;
+}
+
+/* see comments for updateLoc */
+extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit,
+                                            RegLocation loc)
+{
+    assert(loc.wide);
+    if (loc.location == kLocDalvikFrame) {
+        // Are the dalvik regs already live in physical registers?
+        RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+        RegisterInfo *infoHi = allocLive(cUnit,
+              dvmCompilerSRegHi(loc.sRegLow), kAnyReg);
+        bool match = true;
+        match = match && (infoLo != NULL);
+        match = match && (infoHi != NULL);
+        // Are they both core or both FP?
+        match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+        // If a pair of floating point singles, are they properly aligned?
+        if (match && FPREG(infoLo->reg)) {
+            match &= ((infoLo->reg & 0x1) == 0);
+            match &= ((infoHi->reg - infoLo->reg) == 1);
+        }
+        // If previously used as a pair, it is the same pair?
+        if (match && (infoLo->pair || infoHi->pair)) {
+            match = (infoLo->pair == infoHi->pair);
+            match &= ((infoLo->reg == infoHi->partner) &&
+                      (infoHi->reg == infoLo->partner));
+        }
+        if (match) {
+            // Can reuse - update the register usage info
+            loc.lowReg = infoLo->reg;
+            loc.highReg = infoHi->reg;
+            loc.location = kLocPhysReg;
+            dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
+            assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+            return loc;
+        }
+        // Can't easily reuse - clobber any overlaps
+        if (infoLo) {
+            dvmCompilerClobber(cUnit, infoLo->reg);
+            if (infoLo->pair)
+                dvmCompilerClobber(cUnit, infoLo->partner);
+        }
+        if (infoHi) {
+            dvmCompilerClobber(cUnit, infoHi->reg);
+            if (infoHi->pair)
+                dvmCompilerClobber(cUnit, infoHi->partner);
+        }
+    }
+
+    return loc;
+}
+
+static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
+                               int regClass, bool update)
+{
+    assert(loc.wide);
+    int newRegs;
+    int lowReg;
+    int highReg;
+
+    loc = dvmCompilerUpdateLocWide(cUnit, loc);
+
+    /* If already in registers, we can assume proper form.  Right reg class? */
+    if (loc.location == kLocPhysReg) {
+        assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
+        assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+        if (!regClassMatches(regClass, loc.lowReg)) {
+            /* Wrong register class.  Reallocate and copy */
+            newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
+            lowReg = newRegs & 0xff;
+            highReg = (newRegs >> 8) & 0xff;
+            dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
+                                   loc.highReg);
+            copyRegInfo(cUnit, lowReg, loc.lowReg);
+            copyRegInfo(cUnit, highReg, loc.highReg);
+            dvmCompilerClobber(cUnit, loc.lowReg);
+            dvmCompilerClobber(cUnit, loc.highReg);
+            loc.lowReg = lowReg;
+            loc.highReg = highReg;
+            dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
+            assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+        }
+        return loc;
+    }
+
+    assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
+    assert((loc.location != kLocRetval) ||
+           (dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG));
+
+    newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
+    loc.lowReg = newRegs & 0xff;
+    loc.highReg = (newRegs >> 8) & 0xff;
+
+    dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
+    if (update) {
+        loc.location = kLocPhysReg;
+        dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
+        dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow));
+    }
+    assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+    return loc;
+}
+
+extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
+                                      int regClass, bool update)
+{
+    int newReg;
+    if (loc.wide)
+        return evalLocWide(cUnit, loc, regClass, update);
+    loc = dvmCompilerUpdateLoc(cUnit, loc);
+
+    if (loc.location == kLocPhysReg) {
+        if (!regClassMatches(regClass, loc.lowReg)) {
+            /* Wrong register class.  Realloc, copy and transfer ownership */
+            newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
+            dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
+            copyRegInfo(cUnit, newReg, loc.lowReg);
+            dvmCompilerClobber(cUnit, loc.lowReg);
+            loc.lowReg = newReg;
+        }
+        return loc;
+    }
+
+    assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
+
+    newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
+    loc.lowReg = newReg;
+
+    if (update) {
+        loc.location = kLocPhysReg;
+        dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
+    }
+    return loc;
+}
+
+static inline int getDestSSAName(MIR *mir, int num)
+{
+    assert(mir->ssaRep->numDefs > num);
+    return mir->ssaRep->defs[num];
+}
+
+// Get the LocRecord associated with an SSA name use.
+extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num)
+{
+    RegLocation loc = cUnit->regLocation[
+         SREG(cUnit, dvmCompilerSSASrc(mir, num))];
+    loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp;
+    loc.wide = false;
+    return loc;
+}
+
+// Get the LocRecord associated with an SSA name def.
+extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir,
+                                      int num)
+{
+    RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
+    loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
+    loc.wide = false;
+    return loc;
+}
+
+static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
+                              int low, int high, bool isSrc)
+{
+    RegLocation lowLoc;
+    RegLocation highLoc;
+    /* Copy loc record for low word and patch in data from high word */
+    if (isSrc) {
+        lowLoc = dvmCompilerGetSrc(cUnit, mir, low);
+        highLoc = dvmCompilerGetSrc(cUnit, mir, high);
+    } else {
+        lowLoc = dvmCompilerGetDest(cUnit, mir, low);
+        highLoc = dvmCompilerGetDest(cUnit, mir, high);
+    }
+    /* Avoid this case by either promoting both or neither. */
+    assert(lowLoc.location == highLoc.location);
+    if (lowLoc.location == kLocPhysReg) {
+        /* This case shouldn't happen if we've named correctly */
+        assert(lowLoc.fp == highLoc.fp);
+    }
+    lowLoc.wide = true;
+    lowLoc.highReg = highLoc.lowReg;
+    return lowLoc;
+}
+
+extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
+                                          int low, int high)
+{
+    return getLocWide(cUnit, mir, low, high, false);
+}
+
+extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
+                                         int low, int high)
+{
+    return getLocWide(cUnit, mir, low, high, true);
+}
+
+/* Kill the corresponding bit in the null-checked register list */
+extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
+                                          RegLocation loc)
+{
+    if (loc.location != kLocRetval) {
+        assert(loc.sRegLow != INVALID_SREG);
+        dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
+        if (loc.wide) {
+            assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG);
+            dvmClearBit(cUnit->regPool->nullCheckedRegs,
+                        dvmCompilerSRegHi(loc.sRegLow));
+        }
+    }
+}
diff --git a/vm/compiler/codegen/arm/ArchFactory.cpp b/vm/compiler/codegen/arm/ArchFactory.cpp
new file mode 100644
index 0000000..5a03b17
--- /dev/null
+++ b/vm/compiler/codegen/arm/ArchFactory.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains arm-specific codegen factory support.
+ * It is included by
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static TGT_LIR *genRegImmCheck(CompilationUnit *cUnit,
+                               ArmConditionCode cond, int reg,
+                               int checkValue, int dOffset,
+                               TGT_LIR *pcrLabel)
+{
+    TGT_LIR *branch = genCmpImmBranch(cUnit, cond, reg, checkValue);
+    if (cUnit->jitMode == kJitMethod) {
+        BasicBlock *bb = cUnit->curBlock;
+        if (bb->taken) {
+            ArmLIR  *exceptionLabel = (ArmLIR *) cUnit->blockLabelList;
+            exceptionLabel += bb->taken->id;
+            branch->generic.target = (LIR *) exceptionLabel;
+            return exceptionLabel;
+        } else {
+            LOGE("Catch blocks not handled yet");
+            dvmAbort();
+            return NULL;
+        }
+    } else {
+        return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+    }
+}
+
+/*
+ * Perform null-check on a register. sReg is the ssa register being checked,
+ * and mReg is the machine register holding the actual value. If internal state
+ * indicates that sReg has been checked before the check request is ignored.
+ */
+static TGT_LIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
+                             int dOffset, TGT_LIR *pcrLabel)
+{
+    /* This particular Dalvik register has been null-checked */
+    if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
+        return pcrLabel;
+    }
+    dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
+    return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
+}
+
+/*
+ * Perform a "reg cmp reg" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static TGT_LIR *genRegRegCheck(CompilationUnit *cUnit,
+                               ArmConditionCode cond,
+                               int reg1, int reg2, int dOffset,
+                               TGT_LIR *pcrLabel)
+{
+    TGT_LIR *res;
+    res = opRegReg(cUnit, kOpCmp, reg1, reg2);
+    TGT_LIR *branch = opCondBranch(cUnit, cond);
+    genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+    return res;
+}
+
+/*
+ * Perform zero-check on a register. Similar to genNullCheck but the value being
+ * checked does not have a corresponding Dalvik register.
+ */
+static TGT_LIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
+                             int dOffset, TGT_LIR *pcrLabel)
+{
+    return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
+}
+
+/* Perform bound check on two registers */
+static TGT_LIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
+                               int rBound, int dOffset, TGT_LIR *pcrLabel)
+{
+    return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
+                          pcrLabel);
+}
+
+/*
+ * 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)
+{
+    /*
+     * 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].
+     */
+    dvmCompilerClobberHandlerRegs(cUnit);
+    newLIR2(cUnit, kThumbBlx1,
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+    newLIR2(cUnit, kThumbBlx2,
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+}
diff --git a/vm/compiler/codegen/arm/ArchUtility.cpp b/vm/compiler/codegen/arm/ArchUtility.cpp
new file mode 100644
index 0000000..0bbb875
--- /dev/null
+++ b/vm/compiler/codegen/arm/ArchUtility.cpp
@@ -0,0 +1,427 @@
+/*
+ * 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 "libdex/DexOpcodes.h"
+#include "ArmLIR.h"
+
+static const char *shiftNames[4] = {
+    "lsl",
+    "lsr",
+    "asr",
+    "ror"};
+
+/* Decode and print a ARM register name */
+static char * decodeRegList(ArmOpcode opcode, int vector, char *buf)
+{
+    int i;
+    bool printed = false;
+    buf[0] = 0;
+    for (i = 0; i < 16; i++, vector >>= 1) {
+        if (vector & 0x1) {
+            int regId = i;
+            if (opcode == kThumbPush && i == 8) {
+                regId = r14lr;
+            } else if (opcode == kThumbPop && i == 8) {
+                regId = r15pc;
+            }
+            if (printed) {
+                sprintf(buf + strlen(buf), ", r%d", regId);
+            } else {
+                printed = true;
+                sprintf(buf, "r%d", regId);
+            }
+        }
+    }
+    return buf;
+}
+
+static int expandImmediate(int value)
+{
+    int mode = (value & 0xf00) >> 8;
+    u4 bits = value & 0xff;
+    switch(mode) {
+        case 0:
+            return bits;
+       case 1:
+            return (bits << 16) | bits;
+       case 2:
+            return (bits << 24) | (bits << 8);
+       case 3:
+            return (bits << 24) | (bits << 16) | (bits << 8) | bits;
+      default:
+            break;
+    }
+    bits = (bits | 0x80) << 24;
+    return bits >> (((value & 0xf80) >> 7) - 8);
+}
+
+/*
+ * Interpret a format string and build a string no longer than size
+ * See format key in Assemble.c.
+ */
+static void buildInsnString(const char *fmt, ArmLIR *lir, char* buf,
+                            unsigned char *baseAddr, int size)
+{
+    int i;
+    char *bufEnd = &buf[size-1];
+    const char *fmtEnd = &fmt[strlen(fmt)];
+    char tbuf[256];
+    const char *name;
+    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') < 4);
+               operand = lir->operands[nc-'0'];
+               switch(*fmt++) {
+                   case 'H':
+                       if (operand != 0) {
+                           sprintf(tbuf, ", %s %d",shiftNames[operand & 0x3],
+                                   operand >> 2);
+                       } else {
+                           strcpy(tbuf,"");
+                       }
+                       break;
+                   case 'B':
+                       switch (operand) {
+                           case kSY:
+                               name = "sy";
+                               break;
+                           case kST:
+                               name = "st";
+                               break;
+                           case kISH:
+                               name = "ish";
+                               break;
+                           case kISHST:
+                               name = "ishst";
+                               break;
+                           case kNSH:
+                               name = "nsh";
+                               break;
+                           case kNSHST:
+                               name = "shst";
+                               break;
+                           default:
+                               name = "DecodeError";
+                               break;
+                       }
+                       strcpy(tbuf, name);
+                       break;
+                   case 'b':
+                       strcpy(tbuf,"0000");
+                       for (i=3; i>= 0; i--) {
+                           tbuf[i] += operand & 1;
+                           operand >>= 1;
+                       }
+                       break;
+                   case 'n':
+                       operand = ~expandImmediate(operand);
+                       sprintf(tbuf,"%d [%#x]", operand, operand);
+                       break;
+                   case 'm':
+                       operand = expandImmediate(operand);
+                       sprintf(tbuf,"%d [%#x]", operand, operand);
+                       break;
+                   case 's':
+                       sprintf(tbuf,"s%d",operand & FP_REG_MASK);
+                       break;
+                   case 'S':
+                       sprintf(tbuf,"d%d",(operand & FP_REG_MASK) >> 1);
+                       break;
+                   case 'h':
+                       sprintf(tbuf,"%04x", operand);
+                       break;
+                   case 'M':
+                   case 'd':
+                       sprintf(tbuf,"%d", operand);
+                       break;
+                   case 'E':
+                       sprintf(tbuf,"%d", operand*4);
+                       break;
+                   case 'F':
+                       sprintf(tbuf,"%d", operand*2);
+                       break;
+                   case 'c':
+                       switch (operand) {
+                           case kArmCondEq:
+                               strcpy(tbuf, "eq");
+                               break;
+                           case kArmCondNe:
+                               strcpy(tbuf, "ne");
+                               break;
+                           case kArmCondLt:
+                               strcpy(tbuf, "lt");
+                               break;
+                           case kArmCondGe:
+                               strcpy(tbuf, "ge");
+                               break;
+                           case kArmCondGt:
+                               strcpy(tbuf, "gt");
+                               break;
+                           case kArmCondLe:
+                               strcpy(tbuf, "le");
+                               break;
+                           case kArmCondCs:
+                               strcpy(tbuf, "cs");
+                               break;
+                           case kArmCondMi:
+                               strcpy(tbuf, "mi");
+                               break;
+                           default:
+                               strcpy(tbuf, "");
+                               break;
+                       }
+                       break;
+                   case 't':
+                       sprintf(tbuf,"0x%08x (L%p)",
+                               (int) baseAddr + lir->generic.offset + 4 +
+                               (operand << 1),
+                               lir->generic.target);
+                       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(lir->opcode, 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;
+}
+
+void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
+{
+    char buf[256];
+    buf[0] = 0;
+    ArmLIR *armLIR = (ArmLIR *) lir;
+
+    if (mask == ENCODE_ALL) {
+        strcpy(buf, "all");
+    } else {
+        char num[8];
+        int i;
+
+        for (i = 0; i < kRegEnd; i++) {
+            if (mask & (1ULL << i)) {
+                sprintf(num, "%d ", i);
+                strcat(buf, num);
+            }
+        }
+
+        if (mask & ENCODE_CCODE) {
+            strcat(buf, "cc ");
+        }
+        if (mask & ENCODE_FP_STATUS) {
+            strcat(buf, "fpcc ");
+        }
+
+        /* Memory bits */
+        if (armLIR && (mask & ENCODE_DALVIK_REG)) {
+            sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff,
+                    (armLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
+        }
+        if (mask & ENCODE_LITERAL) {
+            strcat(buf, "lit ");
+        }
+
+        if (mask & ENCODE_HEAP_REF) {
+            strcat(buf, "heap ");
+        }
+        if (mask & ENCODE_MUST_NOT_ALIAS) {
+            strcat(buf, "noalias ");
+        }
+    }
+    if (buf[0]) {
+        LOGD("%s: %s", prefix, buf);
+    }
+}
+
+/*
+ * Debugging macros
+ */
+#define DUMP_RESOURCE_MASK(X)
+#define DUMP_SSA_REP(X)
+
+/* Pretty-print a LIR instruction */
+void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
+{
+    ArmLIR *lir = (ArmLIR *) arg;
+    char buf[256];
+    char opName[256];
+    int offset = lir->generic.offset;
+    int dest = lir->operands[0];
+    const bool dumpNop = false;
+
+    /* Handle pseudo-ops individually, and all regular insns as a group */
+    switch(lir->opcode) {
+        case kArmChainingCellBottom:
+            LOGD("-------- end of chaining cells (0x%04x)", offset);
+            break;
+        case kArmPseudoBarrier:
+            LOGD("-------- BARRIER");
+            break;
+        case kArmPseudoExtended:
+            LOGD("-------- %s", (char *) dest);
+            break;
+        case kArmPseudoSSARep:
+            DUMP_SSA_REP(LOGD("-------- %s", (char *) dest));
+            break;
+        case kArmPseudoChainingCellBackwardBranch:
+            LOGD("L%p:", lir);
+            LOGD("-------- chaining cell (backward branch): 0x%04x", dest);
+            break;
+        case kArmPseudoChainingCellNormal:
+            LOGD("L%p:", lir);
+            LOGD("-------- chaining cell (normal): 0x%04x", dest);
+            break;
+        case kArmPseudoChainingCellHot:
+            LOGD("L%p:", lir);
+            LOGD("-------- chaining cell (hot): 0x%04x", dest);
+            break;
+        case kArmPseudoChainingCellInvokePredicted:
+            LOGD("L%p:", lir);
+            LOGD("-------- chaining cell (predicted): %s%s",
+                 dest ? ((Method *) dest)->clazz->descriptor : "",
+                 dest ? ((Method *) dest)->name : "N/A");
+            break;
+        case kArmPseudoChainingCellInvokeSingleton:
+            LOGD("L%p:", lir);
+            LOGD("-------- chaining cell (invoke singleton): %s%s/%p",
+                 ((Method *)dest)->clazz->descriptor,
+                 ((Method *)dest)->name,
+                 ((Method *)dest)->insns);
+            break;
+        case kArmPseudoEntryBlock:
+            LOGD("-------- entry offset: 0x%04x", dest);
+            break;
+        case kArmPseudoDalvikByteCodeBoundary:
+            LOGD("-------- dalvik offset: 0x%04x @ %s", dest,
+                 (char *) lir->operands[1]);
+            break;
+        case kArmPseudoExitBlock:
+            LOGD("-------- exit offset: 0x%04x", dest);
+            break;
+        case kArmPseudoPseudoAlign4:
+            LOGD("%p (%04x): .align4", baseAddr + offset, offset);
+            break;
+        case kArmPseudoPCReconstructionCell:
+            LOGD("L%p:", lir);
+            LOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x", dest,
+                 lir->operands[1]);
+            break;
+        case kArmPseudoPCReconstructionBlockLabel:
+            /* Do nothing */
+            break;
+        case kArmPseudoEHBlockLabel:
+            LOGD("Exception_Handling:");
+            break;
+        case kArmPseudoTargetLabel:
+        case kArmPseudoNormalBlockLabel:
+            LOGD("L%p:", lir);
+            break;
+        default:
+            if (lir->flags.isNop && !dumpNop) {
+                break;
+            }
+            buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
+                            baseAddr, 256);
+            buildInsnString(EncodingMap[lir->opcode].fmt, lir, buf, baseAddr,
+                            256);
+            LOGD("%p (%04x): %-8s%s%s",
+                 baseAddr + offset, offset, opName, buf,
+                 lir->flags.isNop ? "(nop)" : "");
+            break;
+    }
+
+    if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
+        DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
+                                               lir->useMask, "use"));
+    }
+    if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
+        DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
+                                               lir->defMask, "def"));
+    }
+}
+
+/* Dump instructions and constant pool contents */
+void dvmCompilerCodegenDump(CompilationUnit *cUnit)
+{
+    LOGD("Dumping LIR insns");
+    LIR *lirInsn;
+    ArmLIR *armLIR;
+
+    LOGD("installed code is at %p", cUnit->baseAddr);
+    LOGD("total size is %d bytes", cUnit->totalSize);
+    for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
+        dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr);
+    }
+    for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
+        armLIR = (ArmLIR *) lirInsn;
+        LOGD("%p (%04x): .class (%s)",
+             (char*)cUnit->baseAddr + armLIR->generic.offset,
+             armLIR->generic.offset,
+             ((CallsiteInfo *) armLIR->operands[0])->classDescriptor);
+    }
+    for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
+        armLIR = (ArmLIR *) lirInsn;
+        LOGD("%p (%04x): .word (%#x)",
+             (char*)cUnit->baseAddr + armLIR->generic.offset,
+             armLIR->generic.offset,
+             armLIR->operands[0]);
+    }
+}
+
+/* Target-specific cache flushing */
+int dvmCompilerCacheFlush(long start, long end, long flags)
+{
+    return cacheflush(start, end, flags);
+}
diff --git a/vm/compiler/codegen/arm/ArmLIR.h b/vm/compiler/codegen/arm/ArmLIR.h
new file mode 100644
index 0000000..cbd4c70
--- /dev/null
+++ b/vm/compiler/codegen/arm/ArmLIR.h
@@ -0,0 +1,795 @@
+/*
+ * 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_CODEGEN_ARM_ARMLIR_H_
+#define DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H_
+
+#include "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+
+/*
+ * r0, r1, r2, r3 are always scratch
+ * r4 (rPC) is scratch for Jit, but most be restored when resuming interp
+ * r5 (rFP) is reserved [holds Dalvik frame pointer]
+ * r6 (rSELF) is reserved [holds current &Thread]
+ * r7 (rINST) is scratch for Jit
+ * r8 (rIBASE) is scratch for Jit, but must be restored when resuming interp
+ * r9 is reserved
+ * r10 is always scratch
+ * r11 (fp) used by gcc unless -fomit-frame-pointer set [available for jit?]
+ * r12 is always scratch
+ * r13 (sp) is reserved
+ * r14 (lr) is scratch for Jit
+ * r15 (pc) is reserved
+ *
+ * Preserved across C calls: r4, r5, r6, r7, r8, r10, r11
+ * Trashed across C calls: r0, r1, r2, r3, r12, r14
+ *
+ * Floating pointer registers
+ * s0-s31
+ * d0-d15, where d0={s0,s1}, d1={s2,s3}, ... , d15={s30,s31}
+ *
+ * s16-s31 (d8-d15) preserved across C calls
+ * s0-s15 (d0-d7) trashed across C calls
+ *
+ * For Thumb code use:
+ *       r0, r1, r2, r3 to hold operands/results
+ *       r4, r7 for temps
+ *
+ * For Thumb2 code use:
+ *       r0, r1, r2, r3, r8, r9, r10, r11, r12, r14 for operands/results
+ *       r4, r7 for temps
+ *       s16-s31/d8-d15 for operands/results
+ *       s0-s15/d0-d7 for temps
+ *
+ * When transitioning from code cache to interp:
+ *       restore rIBASE
+ *       restore rPC
+ *       restore r11?
+ */
+
+/* Offset to distingish FP regs */
+#define FP_REG_OFFSET 32
+/* Offset to distinguish DP FP regs */
+#define FP_DOUBLE 64
+/* Reg types */
+#define REGTYPE(x) (x & (FP_REG_OFFSET | FP_DOUBLE))
+#define FPREG(x) ((x & FP_REG_OFFSET) == FP_REG_OFFSET)
+#define LOWREG(x) ((x & 0x7) == x)
+#define DOUBLEREG(x) ((x & FP_DOUBLE) == FP_DOUBLE)
+#define SINGLEREG(x) (FPREG(x) && !DOUBLEREG(x))
+/*
+ * Note: the low register of a floating point pair is sufficient to
+ * create the name of a double, but require both names to be passed to
+ * allow for asserts to verify that the pair is consecutive if significant
+ * rework is done in this area.  Also, it is a good reminder in the calling
+ * code that reg locations always describe doubles as a pair of singles.
+ */
+#define S2D(x,y) ((x) | FP_DOUBLE)
+/* Mask to strip off fp flags */
+#define FP_REG_MASK (FP_REG_OFFSET-1)
+/* non-existent Dalvik register */
+#define vNone   (-1)
+/* non-existant physical register */
+#define rNone   (-1)
+
+/* RegisterLocation templates return values (r0, or r0/r1) */
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, r0, 0, -1}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, r0, r1, -1}
+/* RegisterLocation templates for interpState->retVal; */
+#define LOC_DALVIK_RETURN_VAL {kLocRetval, 0, 0, 0, 0, -1}
+#define LOC_DALVIK_RETURN_VAL_WIDE {kLocRetval, 1, 0, 0, 0, -1}
+
+ /*
+ * 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 RegisterInfo {
+    int reg;                    // Reg number
+    bool inUse;                 // Has it been allocated?
+    bool pair;                  // Part of a register pair?
+    int partner;                // If pair, other reg of pair
+    bool live;                  // Is there an associated SSA name?
+    bool dirty;                 // If live, is it dirty?
+    int sReg;                   // Name of live value
+    struct LIR *defStart;       // Starting inst in last def sequence
+    struct LIR *defEnd;         // Ending inst in last def sequence
+} RegisterInfo;
+
+typedef struct RegisterPool {
+    BitVector *nullCheckedRegs; // Track which registers have been null-checked
+    int numCoreTemps;
+    RegisterInfo *coreTemps;
+    int nextCoreTemp;
+    int numFPTemps;
+    RegisterInfo *FPTemps;
+    int nextFPTemp;
+} RegisterPool;
+
+typedef enum ResourceEncodingPos {
+    kGPReg0     = 0,
+    kRegSP      = 13,
+    kRegLR      = 14,
+    kRegPC      = 15,
+    kFPReg0     = 16,
+    kRegEnd     = 48,
+    kCCode      = kRegEnd,
+    kFPStatus,          // FP status word
+    // The following four bits are for memory disambiguation
+    kDalvikReg,         // 1 Dalvik Frame (can be fully disambiguated)
+    kLiteral,           // 2 Literal pool (can be fully disambiguated)
+    kHeapRef,           // 3 Somewhere on the heap (alias with any other heap)
+    kMustNotAlias,      // 4 Guaranteed to be non-alias (eg *(r6+x))
+} ResourceEncodingPos;
+
+#define ENCODE_REG_LIST(N)      ((u8) N)
+#define ENCODE_REG_SP           (1ULL << kRegSP)
+#define ENCODE_REG_LR           (1ULL << kRegLR)
+#define ENCODE_REG_PC           (1ULL << kRegPC)
+#define ENCODE_CCODE            (1ULL << kCCode)
+#define ENCODE_FP_STATUS        (1ULL << kFPStatus)
+
+/* Abstract memory locations */
+#define ENCODE_DALVIK_REG       (1ULL << kDalvikReg)
+#define ENCODE_LITERAL          (1ULL << kLiteral)
+#define ENCODE_HEAP_REF         (1ULL << kHeapRef)
+#define ENCODE_MUST_NOT_ALIAS   (1ULL << kMustNotAlias)
+
+#define ENCODE_ALL              (~0ULL)
+#define ENCODE_MEM              (ENCODE_DALVIK_REG | ENCODE_LITERAL | \
+                                 ENCODE_HEAP_REF | ENCODE_MUST_NOT_ALIAS)
+
+#define DECODE_ALIAS_INFO_REG(X)        (X & 0xffff)
+#define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
+
+typedef enum OpSize {
+    kWord,
+    kLong,
+    kSingle,
+    kDouble,
+    kUnsignedHalf,
+    kSignedHalf,
+    kUnsignedByte,
+    kSignedByte,
+} OpSize;
+
+typedef enum OpKind {
+    kOpMov,
+    kOpMvn,
+    kOpCmp,
+    kOpLsl,
+    kOpLsr,
+    kOpAsr,
+    kOpRor,
+    kOpNot,
+    kOpAnd,
+    kOpOr,
+    kOpXor,
+    kOpNeg,
+    kOpAdd,
+    kOpAdc,
+    kOpSub,
+    kOpSbc,
+    kOpRsub,
+    kOpMul,
+    kOpDiv,
+    kOpRem,
+    kOpBic,
+    kOpCmn,
+    kOpTst,
+    kOpBkpt,
+    kOpBlx,
+    kOpPush,
+    kOpPop,
+    kOp2Char,
+    kOp2Short,
+    kOp2Byte,
+    kOpCondBr,
+    kOpUncondBr,
+} OpKind;
+
+/*
+ * Annotate special-purpose core registers:
+ *   - VM: r4PC, r5FP, and r6SELF
+ *   - ARM architecture: r13sp, r14lr, and r15pc
+ *
+ * rPC, rFP, and rSELF are for architecture-independent code to use.
+ */
+typedef enum NativeRegisterPool {
+    r0     = 0,
+    r1     = 1,
+    r2     = 2,
+    r3     = 3,
+    rPC    = 4,
+    r4PC   = rPC,
+    rFP    = 5,
+    r5FP   = rFP,
+    rSELF  = 6,
+    r6SELF = rSELF,
+    r7     = 7,
+    r8     = 8,
+    r9     = 9,
+    r10    = 10,
+    r11    = 11,
+    r12    = 12,
+    r13sp  = 13,
+    r14lr  = 14,
+    r15pc  = 15,
+    fr0  =  0 + FP_REG_OFFSET,
+    fr1  =  1 + FP_REG_OFFSET,
+    fr2  =  2 + FP_REG_OFFSET,
+    fr3  =  3 + FP_REG_OFFSET,
+    fr4  =  4 + FP_REG_OFFSET,
+    fr5  =  5 + FP_REG_OFFSET,
+    fr6  =  6 + FP_REG_OFFSET,
+    fr7  =  7 + FP_REG_OFFSET,
+    fr8  =  8 + FP_REG_OFFSET,
+    fr9  =  9 + FP_REG_OFFSET,
+    fr10 = 10 + FP_REG_OFFSET,
+    fr11 = 11 + FP_REG_OFFSET,
+    fr12 = 12 + FP_REG_OFFSET,
+    fr13 = 13 + FP_REG_OFFSET,
+    fr14 = 14 + FP_REG_OFFSET,
+    fr15 = 15 + FP_REG_OFFSET,
+    fr16 = 16 + FP_REG_OFFSET,
+    fr17 = 17 + FP_REG_OFFSET,
+    fr18 = 18 + FP_REG_OFFSET,
+    fr19 = 19 + FP_REG_OFFSET,
+    fr20 = 20 + FP_REG_OFFSET,
+    fr21 = 21 + FP_REG_OFFSET,
+    fr22 = 22 + FP_REG_OFFSET,
+    fr23 = 23 + FP_REG_OFFSET,
+    fr24 = 24 + FP_REG_OFFSET,
+    fr25 = 25 + FP_REG_OFFSET,
+    fr26 = 26 + FP_REG_OFFSET,
+    fr27 = 27 + FP_REG_OFFSET,
+    fr28 = 28 + FP_REG_OFFSET,
+    fr29 = 29 + FP_REG_OFFSET,
+    fr30 = 30 + FP_REG_OFFSET,
+    fr31 = 31 + FP_REG_OFFSET,
+    dr0 = fr0 + FP_DOUBLE,
+    dr1 = fr2 + FP_DOUBLE,
+    dr2 = fr4 + FP_DOUBLE,
+    dr3 = fr6 + FP_DOUBLE,
+    dr4 = fr8 + FP_DOUBLE,
+    dr5 = fr10 + FP_DOUBLE,
+    dr6 = fr12 + FP_DOUBLE,
+    dr7 = fr14 + FP_DOUBLE,
+    dr8 = fr16 + FP_DOUBLE,
+    dr9 = fr18 + FP_DOUBLE,
+    dr10 = fr20 + FP_DOUBLE,
+    dr11 = fr22 + FP_DOUBLE,
+    dr12 = fr24 + FP_DOUBLE,
+    dr13 = fr26 + FP_DOUBLE,
+    dr14 = fr28 + FP_DOUBLE,
+    dr15 = fr30 + FP_DOUBLE,
+} NativeRegisterPool;
+
+/* Shift encodings */
+typedef enum ArmShiftEncodings {
+    kArmLsl = 0x0,
+    kArmLsr = 0x1,
+    kArmAsr = 0x2,
+    kArmRor = 0x3
+} ArmShiftEncodings;
+
+/* Thumb condition encodings */
+typedef enum ArmConditionCode {
+    kArmCondEq = 0x0,    /* 0000 */
+    kArmCondNe = 0x1,    /* 0001 */
+    kArmCondCs = 0x2,    /* 0010 */
+    kArmCondCc = 0x3,    /* 0011 */
+    kArmCondMi = 0x4,    /* 0100 */
+    kArmCondPl = 0x5,    /* 0101 */
+    kArmCondVs = 0x6,    /* 0110 */
+    kArmCondVc = 0x7,    /* 0111 */
+    kArmCondHi = 0x8,    /* 1000 */
+    kArmCondLs = 0x9,    /* 1001 */
+    kArmCondGe = 0xa,    /* 1010 */
+    kArmCondLt = 0xb,    /* 1011 */
+    kArmCondGt = 0xc,    /* 1100 */
+    kArmCondLe = 0xd,    /* 1101 */
+    kArmCondAl = 0xe,    /* 1110 */
+    kArmCondNv = 0xf,    /* 1111 */
+} ArmConditionCode;
+
+#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 ArmOpcode {
+    kArmChainingCellBottom = -18,
+    kArmPseudoBarrier = -17,
+    kArmPseudoExtended = -16,
+    kArmPseudoSSARep = -15,
+    kArmPseudoEntryBlock = -14,
+    kArmPseudoExitBlock = -13,
+    kArmPseudoTargetLabel = -12,
+    kArmPseudoChainingCellBackwardBranch = -11,
+    kArmPseudoChainingCellHot = -10,
+    kArmPseudoChainingCellInvokePredicted = -9,
+    kArmPseudoChainingCellInvokeSingleton = -8,
+    kArmPseudoChainingCellNormal = -7,
+    kArmPseudoDalvikByteCodeBoundary = -6,
+    kArmPseudoPseudoAlign4 = -5,
+    kArmPseudoPCReconstructionCell = -4,
+    kArmPseudoPCReconstructionBlockLabel = -3,
+    kArmPseudoEHBlockLabel = -2,
+    kArmPseudoNormalBlockLabel = -1,
+    /************************************************************************/
+    kArm16BitData,       /* DATA   [0] rd[15..0] */
+    kThumbAdcRR,         /* adc     [0100000101] rm[5..3] rd[2..0] */
+    kThumbAddRRI3,       /* add(1)  [0001110] imm_3[8..6] rn[5..3] rd[2..0]*/
+    kThumbAddRI8,        /* add(2)  [00110] rd[10..8] imm_8[7..0] */
+    kThumbAddRRR,        /* add(3)  [0001100] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbAddRRLH,       /* add(4)  [01000100] H12[01] rm[5..3] rd[2..0] */
+    kThumbAddRRHL,       /* add(4)  [01001000] H12[10] rm[5..3] rd[2..0] */
+    kThumbAddRRHH,       /* add(4)  [01001100] H12[11] rm[5..3] rd[2..0] */
+    kThumbAddPcRel,      /* add(5)  [10100] rd[10..8] imm_8[7..0] */
+    kThumbAddSpRel,      /* add(6)  [10101] rd[10..8] imm_8[7..0] */
+    kThumbAddSpI7,       /* add(7)  [101100000] imm_7[6..0] */
+    kThumbAndRR,         /* and     [0100000000] rm[5..3] rd[2..0] */
+    kThumbAsrRRI5,       /* asr(1)  [00010] imm_5[10..6] rm[5..3] rd[2..0] */
+    kThumbAsrRR,         /* asr(2)  [0100000100] rs[5..3] rd[2..0] */
+    kThumbBCond,         /* b(1)    [1101] cond[11..8] offset_8[7..0] */
+    kThumbBUncond,       /* b(2)    [11100] offset_11[10..0] */
+    kThumbBicRR,         /* bic     [0100001110] rm[5..3] rd[2..0] */
+    kThumbBkpt,          /* bkpt    [10111110] imm_8[7..0] */
+    kThumbBlx1,          /* blx(1)  [111] H[10] offset_11[10..0] */
+    kThumbBlx2,          /* blx(1)  [111] H[01] offset_11[10..0] */
+    kThumbBl1,           /* blx(1)  [111] H[10] offset_11[10..0] */
+    kThumbBl2,           /* blx(1)  [111] H[11] offset_11[10..0] */
+    kThumbBlxR,          /* blx(2)  [010001111] rm[6..3] [000] */
+    kThumbBx,            /* bx      [010001110] H2[6..6] rm[5..3] SBZ[000] */
+    kThumbCmnRR,         /* cmn     [0100001011] rm[5..3] rd[2..0] */
+    kThumbCmpRI8,        /* cmp(1)  [00101] rn[10..8] imm_8[7..0] */
+    kThumbCmpRR,         /* cmp(2)  [0100001010] rm[5..3] rd[2..0] */
+    kThumbCmpLH,         /* cmp(3)  [01000101] H12[01] rm[5..3] rd[2..0] */
+    kThumbCmpHL,         /* cmp(3)  [01000110] H12[10] rm[5..3] rd[2..0] */
+    kThumbCmpHH,         /* cmp(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
+    kThumbEorRR,         /* eor     [0100000001] rm[5..3] rd[2..0] */
+    kThumbLdmia,         /* ldmia   [11001] rn[10..8] reglist [7..0] */
+    kThumbLdrRRI5,       /* ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbLdrRRR,        /* ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrPcRel,      /* ldr(3)  [01001] rd[10..8] imm_8[7..0] */
+    kThumbLdrSpRel,      /* ldr(4)  [10011] rd[10..8] imm_8[7..0] */
+    kThumbLdrbRRI5,      /* ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbLdrbRRR,       /* ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrhRRI5,      /* ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbLdrhRRR,       /* ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrsbRRR,      /* ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrshRRR,      /* ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLslRRI5,       /* lsl(1)  [00000] imm_5[10..6] rm[5..3] rd[2..0] */
+    kThumbLslRR,         /* lsl(2)  [0100000010] rs[5..3] rd[2..0] */
+    kThumbLsrRRI5,       /* lsr(1)  [00001] imm_5[10..6] rm[5..3] rd[2..0] */
+    kThumbLsrRR,         /* lsr(2)  [0100000011] rs[5..3] rd[2..0] */
+    kThumbMovImm,        /* mov(1)  [00100] rd[10..8] imm_8[7..0] */
+    kThumbMovRR,         /* mov(2)  [0001110000] rn[5..3] rd[2..0] */
+    kThumbMovRR_H2H,     /* mov(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
+    kThumbMovRR_H2L,     /* mov(3)  [01000110] H12[01] rm[5..3] rd[2..0] */
+    kThumbMovRR_L2H,     /* mov(3)  [01000101] H12[10] rm[5..3] rd[2..0] */
+    kThumbMul,           /* mul     [0100001101] rm[5..3] rd[2..0] */
+    kThumbMvn,           /* mvn     [0100001111] rm[5..3] rd[2..0] */
+    kThumbNeg,           /* neg     [0100001001] rm[5..3] rd[2..0] */
+    kThumbOrr,           /* orr     [0100001100] rm[5..3] rd[2..0] */
+    kThumbPop,           /* pop     [1011110] r[8..8] rl[7..0] */
+    kThumbPush,          /* push    [1011010] r[8..8] rl[7..0] */
+    kThumbRorRR,         /* ror     [0100000111] rs[5..3] rd[2..0] */
+    kThumbSbc,           /* sbc     [0100000110] rm[5..3] rd[2..0] */
+    kThumbStmia,         /* stmia   [11000] rn[10..8] reglist [7.. 0] */
+    kThumbStrRRI5,       /* str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbStrRRR,        /* str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbStrSpRel,      /* str(3)  [10010] rd[10..8] imm_8[7..0] */
+    kThumbStrbRRI5,      /* strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbStrbRRR,       /* strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbStrhRRI5,      /* strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbStrhRRR,       /* strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbSubRRI3,       /* sub(1)  [0001111] imm_3[8..6] rn[5..3] rd[2..0]*/
+    kThumbSubRI8,        /* sub(2)  [00111] rd[10..8] imm_8[7..0] */
+    kThumbSubRRR,        /* sub(3)  [0001101] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbSubSpI7,       /* sub(4)  [101100001] imm_7[6..0] */
+    kThumbSwi,           /* swi     [11011111] imm_8[7..0] */
+    kThumbTst,           /* tst     [0100001000] rm[5..3] rn[2..0] */
+    kThumb2Vldrs,        /* vldr low  sx [111011011001] rn[19..16] rd[15-12]
+                                    [1010] imm_8[7..0] */
+    kThumb2Vldrd,        /* vldr low  dx [111011011001] rn[19..16] rd[15-12]
+                                    [1011] imm_8[7..0] */
+    kThumb2Vmuls,        /* vmul vd, vn, vm [111011100010] rn[19..16]
+                                    rd[15-12] [10100000] rm[3..0] */
+    kThumb2Vmuld,        /* vmul vd, vn, vm [111011100010] rn[19..16]
+                                    rd[15-12] [10110000] rm[3..0] */
+    kThumb2Vstrs,        /* vstr low  sx [111011011000] rn[19..16] rd[15-12]
+                                    [1010] imm_8[7..0] */
+    kThumb2Vstrd,        /* vstr low  dx [111011011000] rn[19..16] rd[15-12]
+                                    [1011] imm_8[7..0] */
+    kThumb2Vsubs,        /* vsub vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10100040] rm[3..0] */
+    kThumb2Vsubd,        /* vsub vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10110040] rm[3..0] */
+    kThumb2Vadds,        /* vadd vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10100000] rm[3..0] */
+    kThumb2Vaddd,        /* vadd vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10110000] rm[3..0] */
+    kThumb2Vdivs,        /* vdiv vd, vn, vm [111011101000] rn[19..16]
+                                    rd[15-12] [10100000] rm[3..0] */
+    kThumb2Vdivd,        /* vdiv vd, vn, vm [111011101000] rn[19..16]
+                                    rd[15-12] [10110000] rm[3..0] */
+    kThumb2VcvtIF,       /* vcvt.F32 vd, vm [1110111010111000] vd[15..12]
+                                    [10101100] vm[3..0] */
+    kThumb2VcvtID,       /* vcvt.F64 vd, vm [1110111010111000] vd[15..12]
+                                       [10111100] vm[3..0] */
+    kThumb2VcvtFI,       /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
+                                       [10101100] vm[3..0] */
+    kThumb2VcvtDI,       /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
+                                       [10111100] vm[3..0] */
+    kThumb2VcvtFd,       /* vcvt.F64.F32 vd, vm [1110111010110111] vd[15..12]
+                                       [10101100] vm[3..0] */
+    kThumb2VcvtDF,       /* vcvt.F32.F64 vd, vm [1110111010110111] vd[15..12]
+                                       [10111100] vm[3..0] */
+    kThumb2Vsqrts,       /* vsqrt.f32 vd, vm [1110111010110001] vd[15..12]
+                                       [10101100] vm[3..0] */
+    kThumb2Vsqrtd,       /* vsqrt.f64 vd, vm [1110111010110001] vd[15..12]
+                                       [10111100] vm[3..0] */
+    kThumb2MovImmShift,  /* mov(T2) rd, #<const> [11110] i [00001001111]
+                                       imm3 rd[11..8] imm8 */
+    kThumb2MovImm16,     /* mov(T3) rd, #<const> [11110] i [0010100] imm4 [0]
+                                       imm3 rd[11..8] imm8 */
+    kThumb2StrRRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+                                       rn[19..16] rt[15..12] imm12[11..0] */
+    kThumb2LdrRRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+                                       rn[19..16] rt[15..12] imm12[11..0] */
+    kThumb2StrRRI8Predec, /* str(Imm,T4) rd,[rn,#-imm8] [111110000100]
+                                       rn[19..16] rt[15..12] [1100] imm[7..0]*/
+    kThumb2LdrRRI8Predec, /* ldr(Imm,T4) rd,[rn,#-imm8] [111110000101]
+                                       rn[19..16] rt[15..12] [1100] imm[7..0]*/
+    kThumb2Cbnz,         /* cbnz rd,<label> [101110] i [1] imm5[7..3]
+                                       rn[2..0] */
+    kThumb2Cbz,          /* cbn rd,<label> [101100] i [1] imm5[7..3]
+                                       rn[2..0] */
+    kThumb2AddRRI12,     /* add rd, rn, #imm12 [11110] i [100000] rn[19..16]
+                                       [0] imm3[14..12] rd[11..8] imm8[7..0] */
+    kThumb2MovRR,        /* mov rd, rm [11101010010011110000] rd[11..8]
+                                       [0000] rm[3..0] */
+    kThumb2Vmovs,        /* vmov.f32 vd, vm [111011101] D [110000]
+                                       vd[15..12] 101001] M [0] vm[3..0] */
+    kThumb2Vmovd,        /* vmov.f64 vd, vm [111011101] D [110000]
+                                       vd[15..12] 101101] M [0] vm[3..0] */
+    kThumb2Ldmia,        /* ldmia  [111010001001[ rn[19..16] mask[15..0] */
+    kThumb2Stmia,        /* stmia  [111010001000[ rn[19..16] mask[15..0] */
+    kThumb2AddRRR,       /* add [111010110000] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2SubRRR,       /* sub [111010111010] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2SbcRRR,       /* sbc [111010110110] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2CmpRR,        /* cmp [111010111011] rn[19..16] [0000] [1111]
+                                   [0000] rm[3..0] */
+    kThumb2SubRRI12,     /* sub rd, rn, #imm12 [11110] i [01010] rn[19..16]
+                                       [0] imm3[14..12] rd[11..8] imm8[7..0] */
+    kThumb2MvnImmShift,  /* mov(T2) rd, #<const> [11110] i [00011011110]
+                                       imm3 rd[11..8] imm8 */
+    kThumb2Sel,          /* sel rd, rn, rm [111110101010] rn[19-16] rd[11-8]
+                                       rm[3-0] */
+    kThumb2Ubfx,         /* ubfx rd,rn,#lsb,#width [111100111100] rn[19..16]
+                                       [0] imm3[14-12] rd[11-8] w[4-0] */
+    kThumb2Sbfx,         /* ubfx rd,rn,#lsb,#width [111100110100] rn[19..16]
+                                       [0] imm3[14-12] rd[11-8] w[4-0] */
+    kThumb2LdrRRR,       /* ldr rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2LdrhRRR,      /* ldrh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2LdrshRRR,     /* ldrsh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2LdrbRRR,      /* ldrb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2LdrsbRRR,     /* ldrsb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2StrRRR,       /* str rt,[rn,rm,LSL #imm] [111110000100] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2StrhRRR,      /* str rt,[rn,rm,LSL #imm] [111110000010] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2StrbRRR,      /* str rt,[rn,rm,LSL #imm] [111110000000] rn[19-16]
+                                       rt[15-12] [000000] imm[5-4] rm[3-0] */
+    kThumb2LdrhRRI12,    /* ldrh rt,[rn,#imm12] [111110001011]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+    kThumb2LdrshRRI12,   /* ldrsh rt,[rn,#imm12] [111110011011]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+    kThumb2LdrbRRI12,    /* ldrb rt,[rn,#imm12] [111110001001]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+    kThumb2LdrsbRRI12,   /* ldrsb rt,[rn,#imm12] [111110011001]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+    kThumb2StrhRRI12,    /* strh rt,[rn,#imm12] [111110001010]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+    kThumb2StrbRRI12,    /* strb rt,[rn,#imm12] [111110001000]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+    kThumb2Pop,          /* pop     [1110100010111101] list[15-0]*/
+    kThumb2Push,         /* push    [1110100100101101] list[15-0]*/
+    kThumb2CmpRI8,       /* cmp rn, #<const> [11110] i [011011] rn[19-16] [0]
+                                       imm3 [1111] imm8[7..0] */
+    kThumb2AdcRRR,       /* adc [111010110101] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2AndRRR,       /* and [111010100000] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2BicRRR,       /* bic [111010100010] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2CmnRR,        /* cmn [111010110001] rn[19..16] [0000] [1111]
+                                   [0000] rm[3..0] */
+    kThumb2EorRRR,       /* eor [111010101000] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2MulRRR,       /* mul [111110110000] rn[19..16] [1111] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2MnvRR,        /* mvn [11101010011011110] rd[11-8] [0000]
+                                   rm[3..0] */
+    kThumb2RsubRRI8,     /* rsub [111100011100] rn[19..16] [0000] rd[11..8]
+                                   imm8[7..0] */
+    kThumb2NegRR,        /* actually rsub rd, rn, #0 */
+    kThumb2OrrRRR,       /* orr [111010100100] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2TstRR,        /* tst [111010100001] rn[19..16] [0000] [1111]
+                                   [0000] rm[3..0] */
+    kThumb2LslRRR,       /* lsl [111110100000] rn[19..16] [1111] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2LsrRRR,       /* lsr [111110100010] rn[19..16] [1111] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2AsrRRR,       /* asr [111110100100] rn[19..16] [1111] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2RorRRR,       /* ror [111110100110] rn[19..16] [1111] rd[11..8]
+                                   [0000] rm[3..0] */
+    kThumb2LslRRI5,      /* lsl [11101010010011110] imm[14.12] rd[11..8]
+                                   [00] rm[3..0] */
+    kThumb2LsrRRI5,      /* lsr [11101010010011110] imm[14.12] rd[11..8]
+                                   [01] rm[3..0] */
+    kThumb2AsrRRI5,      /* asr [11101010010011110] imm[14.12] rd[11..8]
+                                   [10] rm[3..0] */
+    kThumb2RorRRI5,      /* ror [11101010010011110] imm[14.12] rd[11..8]
+                                   [11] rm[3..0] */
+    kThumb2BicRRI8,      /* bic [111100000010] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2AndRRI8,      /* bic [111100000000] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2OrrRRI8,      /* orr [111100000100] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2EorRRI8,      /* eor [111100001000] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2AddRRI8,      /* add [111100001000] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2AdcRRI8,      /* adc [111100010101] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2SubRRI8,      /* sub [111100011011] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2SbcRRI8,      /* sbc [111100010111] rn[19..16] [0] imm3
+                                   rd[11..8] imm8 */
+    kThumb2It,           /* it [10111111] firstcond[7-4] mask[3-0] */
+    kThumb2Fmstat,       /* fmstat [11101110111100011111101000010000] */
+    kThumb2Vcmpd,        /* vcmp [111011101] D [11011] rd[15-12] [1011]
+                                   E [1] M [0] rm[3-0] */
+    kThumb2Vcmps,        /* vcmp [111011101] D [11010] rd[15-12] [1011]
+                                   E [1] M [0] rm[3-0] */
+    kThumb2LdrPcRel12,   /* ldr rd,[pc,#imm12] [1111100011011111] rt[15-12]
+                                  imm12[11-0] */
+    kThumb2BCond,        /* b<c> [1110] S cond[25-22] imm6[21-16] [10]
+                                  J1 [0] J2 imm11[10..0] */
+    kThumb2Vmovd_RR,     /* vmov [111011101] D [110000] vd[15-12 [101101]
+                                  M [0] vm[3-0] */
+    kThumb2Vmovs_RR,     /* vmov [111011101] D [110000] vd[15-12 [101001]
+                                  M [0] vm[3-0] */
+    kThumb2Fmrs,         /* vmov [111011100000] vn[19-16] rt[15-12] [1010]
+                                  N [0010000] */
+    kThumb2Fmsr,         /* vmov [111011100001] vn[19-16] rt[15-12] [1010]
+                                  N [0010000] */
+    kThumb2Fmrrd,        /* vmov [111011000100] rt2[19-16] rt[15-12]
+                                  [101100] M [1] vm[3-0] */
+    kThumb2Fmdrr,        /* vmov [111011000101] rt2[19-16] rt[15-12]
+                                  [101100] M [1] vm[3-0] */
+    kThumb2Vabsd,        /* vabs.f64 [111011101] D [110000] rd[15-12]
+                                  [1011110] M [0] vm[3-0] */
+    kThumb2Vabss,        /* vabs.f32 [111011101] D [110000] rd[15-12]
+                                  [1010110] M [0] vm[3-0] */
+    kThumb2Vnegd,        /* vneg.f64 [111011101] D [110000] rd[15-12]
+                                  [1011110] M [0] vm[3-0] */
+    kThumb2Vnegs,        /* vneg.f32 [111011101] D [110000] rd[15-12]
+                                 [1010110] M [0] vm[3-0] */
+    kThumb2Vmovs_IMM8,   /* vmov.f32 [111011101] D [11] imm4h[19-16] vd[15-12]
+                                  [10100000] imm4l[3-0] */
+    kThumb2Vmovd_IMM8,   /* vmov.f64 [111011101] D [11] imm4h[19-16] vd[15-12]
+                                  [10110000] imm4l[3-0] */
+    kThumb2Mla,          /* mla [111110110000] rn[19-16] ra[15-12] rd[7-4]
+                                  [0000] rm[3-0] */
+    kThumb2Umull,        /* umull [111110111010] rn[19-16], rdlo[15-12]
+                                  rdhi[11-8] [0000] rm[3-0] */
+    kThumb2Ldrex,        /* ldrex [111010000101] rn[19-16] rt[11-8] [1111]
+                                  imm8[7-0] */
+    kThumb2Strex,        /* strex [111010000100] rn[19-16] rt[11-8] rd[11-8]
+                                  imm8[7-0] */
+    kThumb2Clrex,        /* clrex [111100111011111110000111100101111] */
+    kThumb2Bfi,          /* bfi [111100110110] rn[19-16] [0] imm3[14-12]
+                                  rd[11-8] imm2[7-6] [0] msb[4-0] */
+    kThumb2Bfc,          /* bfc [11110011011011110] [0] imm3[14-12]
+                                  rd[11-8] imm2[7-6] [0] msb[4-0] */
+    kThumb2Dmb,          /* dmb [1111001110111111100011110101] option[3-0] */
+    kThumb2LdrPcReln12,  /* ldr rd,[pc,-#imm12] [1111100011011111] rt[15-12]
+                                  imm12[11-0] */
+    kThumbUndefined,     /* undefined [11011110xxxxxxxx] */
+    kArmLast,
+} ArmOpcode;
+
+/* DMB option encodings */
+typedef enum ArmOpDmbOptions {
+    kSY = 0xf,
+    kST = 0xe,
+    kISH = 0xb,
+    kISHST = 0xa,
+    kNSH = 0x7,
+    kNSHST = 0x6
+} ArmOpDmbOptions;
+
+/* Bit flags describing the behavior of each native opcode */
+typedef enum ArmOpFeatureFlags {
+    kIsBranch = 0,
+    kRegDef0,
+    kRegDef1,
+    kRegDefSP,
+    kRegDefLR,
+    kRegDefList0,
+    kRegDefList1,
+    kRegUse0,
+    kRegUse1,
+    kRegUse2,
+    kRegUse3,
+    kRegUseSP,
+    kRegUsePC,
+    kRegUseList0,
+    kRegUseList1,
+    kNoOperand,
+    kIsUnaryOp,
+    kIsBinaryOp,
+    kIsTertiaryOp,
+    kIsQuadOp,
+    kIsIT,
+    kSetsCCodes,
+    kUsesCCodes,
+    kMemLoad,
+    kMemStore,
+} ArmOpFeatureFlags;
+
+#define IS_LOAD         (1 << kMemLoad)
+#define IS_STORE        (1 << kMemStore)
+#define IS_BRANCH       (1 << kIsBranch)
+#define REG_DEF0        (1 << kRegDef0)
+#define REG_DEF1        (1 << kRegDef1)
+#define REG_DEF_SP      (1 << kRegDefSP)
+#define REG_DEF_LR      (1 << kRegDefLR)
+#define REG_DEF_LIST0   (1 << kRegDefList0)
+#define REG_DEF_LIST1   (1 << kRegDefList1)
+#define REG_USE0        (1 << kRegUse0)
+#define REG_USE1        (1 << kRegUse1)
+#define REG_USE2        (1 << kRegUse2)
+#define REG_USE3        (1 << kRegUse3)
+#define REG_USE_SP      (1 << kRegUseSP)
+#define REG_USE_PC      (1 << kRegUsePC)
+#define REG_USE_LIST0   (1 << kRegUseList0)
+#define REG_USE_LIST1   (1 << kRegUseList1)
+#define NO_OPERAND      (1 << kNoOperand)
+#define IS_UNARY_OP     (1 << kIsUnaryOp)
+#define IS_BINARY_OP    (1 << kIsBinaryOp)
+#define IS_TERTIARY_OP  (1 << kIsTertiaryOp)
+#define IS_QUAD_OP      (1 << kIsQuadOp)
+#define IS_IT           (1 << kIsIT)
+#define SETS_CCODES     (1 << kSetsCCodes)
+#define USES_CCODES     (1 << kUsesCCodes)
+
+/* Common combo register usage patterns */
+#define REG_USE01       (REG_USE0 | REG_USE1)
+#define REG_USE012      (REG_USE01 | REG_USE2)
+#define REG_USE12       (REG_USE1 | REG_USE2)
+#define REG_DEF0_USE0   (REG_DEF0 | REG_USE0)
+#define REG_DEF0_USE1   (REG_DEF0 | REG_USE1)
+#define REG_DEF0_USE01  (REG_DEF0 | REG_USE01)
+#define REG_DEF0_USE12  (REG_DEF0 | REG_USE12)
+#define REG_DEF01_USE2  (REG_DEF0 | REG_DEF1 | REG_USE2)
+
+/* Instruction assembly fieldLoc kind */
+typedef enum ArmEncodingKind {
+    kFmtUnused,
+    kFmtBitBlt,        /* Bit string using end/start */
+    kFmtDfp,           /* Double FP reg */
+    kFmtSfp,           /* Single FP reg */
+    kFmtModImm,        /* Shifted 8-bit immed using [26,14..12,7..0] */
+    kFmtImm16,         /* Zero-extended immed using [26,19..16,14..12,7..0] */
+    kFmtImm6,          /* Encoded branch target using [9,7..3]0 */
+    kFmtImm12,         /* Zero-extended immediate using [26,14..12,7..0] */
+    kFmtShift,         /* Shift descriptor, [14..12,7..4] */
+    kFmtLsb,           /* least significant bit using [14..12][7..6] */
+    kFmtBWidth,        /* bit-field width, encoded as width-1 */
+    kFmtShift5,        /* Shift count, [14..12,7..6] */
+    kFmtBrOffset,      /* Signed extended [26,11,13,21-16,10-0]:0 */
+    kFmtFPImm,         /* Encoded floating point immediate */
+} ArmEncodingKind;
+
+/* Struct used to define the snippet positions for each Thumb opcode */
+typedef struct ArmEncodingMap {
+    u4 skeleton;
+    struct {
+        ArmEncodingKind kind;
+        int end;   /* end for kFmtBitBlt, 1-bit slice end for FP regs */
+        int start; /* start for kFmtBitBlt, 4-bit slice end for FP regs */
+    } fieldLoc[4];
+    ArmOpcode opcode;
+    int flags;
+    const char* name;
+    const char* fmt;
+    int size;
+} ArmEncodingMap;
+
+/* Keys for target-specific scheduling and other optimization hints */
+typedef enum ArmTargetOptHints {
+    kMaxHoistDistance,
+} ArmTargetOptHints;
+
+extern ArmEncodingMap EncodingMap[kArmLast];
+
+/*
+ * Each instance of this struct holds a pseudo or real LIR instruction:
+ * - pseudo ones (eg labels and marks) and will be discarded by the assembler.
+ * - real ones will be assembled into Thumb instructions.
+ *
+ * Machine resources are encoded into a 64-bit vector, where the encodings are
+ * as following:
+ * - [ 0..15]: general purpose registers including PC, SP, and LR
+ * - [16..47]: floating-point registers where d0 is expanded to s[01] and s0
+ *   starts at bit 16
+ * - [48]: IT block
+ * - [49]: integer condition code
+ * - [50]: floatint-point status word
+ */
+typedef struct ArmLIR {
+    LIR generic;
+    ArmOpcode opcode;
+    int operands[4];            // [0..3] = [dest, src1, src2, extra]
+    struct {
+        bool isNop:1;           // LIR is optimized away
+        bool insertWrapper:1;   // insert branch to emulate memory accesses
+        unsigned int age:4;     // default is 0, set lazily by the optimizer
+        unsigned int size:3;    // bytes (2 for thumb, 2/4 for thumb2)
+        unsigned int unused:23;
+    } flags;
+    int aliasInfo;              // For Dalvik register & litpool disambiguation
+    u8 useMask;                 // Resource mask for use
+    u8 defMask;                 // Resource mask for def
+} ArmLIR;
+
+/* Init values when a predicted chain is initially assembled */
+/* E7FE is branch to self */
+#define PREDICTED_CHAIN_BX_PAIR_INIT     0xe7fe
+
+/* Utility macros to traverse the LIR/ArmLIR list */
+#define NEXT_LIR(lir) ((ArmLIR *) lir->generic.next)
+#define PREV_LIR(lir) ((ArmLIR *) 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
+
+#define CHAIN_CELL_NORMAL_SIZE 12
+#define CHAIN_CELL_PREDICTED_SIZE 16
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H_
diff --git a/vm/compiler/codegen/arm/ArmRallocUtil.cpp b/vm/compiler/codegen/arm/ArmRallocUtil.cpp
new file mode 100644
index 0000000..3a5afa2
--- /dev/null
+++ b/vm/compiler/codegen/arm/ArmRallocUtil.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains Arm-specific register alloction support.
+ */
+
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "ArmLIR.h"
+#include "Codegen.h"
+#include "compiler/codegen/Ralloc.h"
+
+/*
+ * Register usage for 16-bit Thumb systems:
+ *     r0-r3: Temp/argument
+ *     lr(r14):      Temp for translations, return address for handlers
+ *     rSELF(r6):    Pointer to Thread
+ *     rFP(r5):      Dalvik frame pointer
+ *     r4, r7:       Temp for translations
+ *     r8, r9, r10:   Temp preserved across C calls
+ *     r11, ip(r12):  Temp not preserved across C calls
+ *
+ * Register usage for 32-bit Thumb systems:
+ *     r0-r3: Temp/argument
+ *     lr(r14):      Temp for translations, return address for handlers
+ *     rSELF(r6):    Pointer to Thread
+ *     rFP(r5):      Dalvik frame pointer
+ *     r4, r7:       Temp for translations
+ *     r8, r9, r10   Temp preserved across C calls
+ *     r11, ip(r12):      Temp not preserved across C calls
+ *     fp0-fp15:     Hot temps, not preserved across C calls
+ *     fp16-fp31:    Promotion pool
+ *
+ */
+
+/* Clobber all regs that might be used by an external C call */
+extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
+{
+    dvmCompilerClobber(cUnit, r0);
+    dvmCompilerClobber(cUnit, r1);
+    dvmCompilerClobber(cUnit, r2);
+    dvmCompilerClobber(cUnit, r3);
+    dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative
+    dvmCompilerClobber(cUnit, r11);
+    dvmCompilerClobber(cUnit, r12);
+    dvmCompilerClobber(cUnit, r14lr);
+}
+
+/* Clobber all of the temps that might be used by a handler. */
+extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit)
+{
+    //TUNING: reduce the set of regs used by handlers.  Only a few need lots.
+    dvmCompilerClobberCallRegs(cUnit);
+    dvmCompilerClobber(cUnit, r4PC);
+    dvmCompilerClobber(cUnit, r7);
+    dvmCompilerClobber(cUnit, r8);
+    dvmCompilerClobber(cUnit, r9);
+    dvmCompilerClobber(cUnit, r10);
+}
+
+extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    dvmCompilerClobber(cUnit, r0);
+    dvmCompilerClobber(cUnit, r1);
+    dvmCompilerMarkInUse(cUnit, r0);
+    dvmCompilerMarkInUse(cUnit, r1);
+    dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    res.lowReg = r2;
+    res.highReg = r3;
+    dvmCompilerClobber(cUnit, r2);
+    dvmCompilerClobber(cUnit, r3);
+    dvmCompilerMarkInUse(cUnit, r2);
+    dvmCompilerMarkInUse(cUnit, r3);
+    dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    dvmCompilerClobber(cUnit, r0);
+    dvmCompilerMarkInUse(cUnit, r0);
+    return res;
+}
+
+extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    res.lowReg = r1;
+    dvmCompilerClobber(cUnit, r1);
+    dvmCompilerMarkInUse(cUnit, r1);
+    return res;
+}
diff --git a/vm/compiler/codegen/arm/Assemble.cpp b/vm/compiler/codegen/arm/Assemble.cpp
new file mode 100644
index 0000000..312e7c1
--- /dev/null
+++ b/vm/compiler/codegen/arm/Assemble.cpp
@@ -0,0 +1,2943 @@
+/*
+ * 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/DexOpcodes.h"
+
+#include "../../CompilerInternals.h"
+#include "ArmLIR.h"
+#include "Codegen.h"
+#include <sys/mman.h>           /* for protection change */
+
+#define MAX_ASSEMBLER_RETRIES 10
+
+/*
+ * opcode: ArmOpcode enum
+ * skeleton: pre-designated bit-pattern for this opcode
+ * k0: key to applying ds/de
+ * ds: dest start bit position
+ * de: dest end bit position
+ * k1: key to applying s1s/s1e
+ * s1s: src1 start bit position
+ * s1e: src1 end bit position
+ * k2: key to applying s2s/s2e
+ * s2s: src2 start bit position
+ * s2e: src2 end bit position
+ * operands: number of operands (for sanity check purposes)
+ * name: mnemonic name
+ * fmt: for pretty-printing
+ */
+#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
+                     k3, k3s, k3e, flags, name, fmt, size) \
+        {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
+                    {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
+
+/* 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)
+ *     3 -> operands[3] (extra)
+ *
+ * [f]ormats:
+ *     h -> 4-digit hex
+ *     d -> decimal
+ *     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
+ *     s -> single precision floating point register
+ *     S -> double precision floating point register
+ *     m -> Thumb2 modified immediate
+ *     n -> complimented Thumb2 modified immediate
+ *     M -> Thumb2 16-bit zero-extended immediate
+ *     b -> 4-digit binary
+ *     B -> dmb option string (sy, st, ish, ishst, nsh, hshst)
+ *     H -> operand shift
+ *
+ *  [!] escape.  To insert "!", use "!!"
+ */
+/* NOTE: must be kept in sync with enum ArmOpcode from ArmLIR.h */
+ArmEncodingMap EncodingMap[kArmLast] = {
+    ENCODING_MAP(kArm16BitData,    0x0000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 1),
+    ENCODING_MAP(kThumbAdcRR,        0x4140,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES | USES_CCODES,
+                 "adcs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbAddRRI3,      0x1c00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "adds", "r!0d, r!1d, #!2d", 1),
+    ENCODING_MAP(kThumbAddRI8,       0x3000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
+                 "adds", "r!0d, r!0d, #!1d", 1),
+    ENCODING_MAP(kThumbAddRRR,       0x1800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
+                 "adds", "r!0d, r!1d, r!2d", 1),
+    ENCODING_MAP(kThumbAddRRLH,     0x4440,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
+                 "add", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbAddRRHL,     0x4480,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
+                 "add", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbAddRRHH,     0x44c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
+                 "add", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbAddPcRel,    0xa000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | IS_BRANCH,
+                 "add", "r!0d, pc, #!1E", 1),
+    ENCODING_MAP(kThumbAddSpRel,    0xa800,
+                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP,
+                 "add", "r!0d, sp, #!2E", 1),
+    ENCODING_MAP(kThumbAddSpI7,      0xb000,
+                 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
+                 "add", "sp, #!0d*4", 1),
+    ENCODING_MAP(kThumbAndRR,        0x4000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "ands", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbAsrRRI5,      0x1000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "asrs", "r!0d, r!1d, #!2d", 1),
+    ENCODING_MAP(kThumbAsrRR,        0x4100,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "asrs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbBCond,        0xd000,
+                 kFmtBitBlt, 7, 0, kFmtBitBlt, 11, 8, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES,
+                 "b!1c", "!0t", 1),
+    ENCODING_MAP(kThumbBUncond,      0xe000,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
+                 "b", "!0t", 1),
+    ENCODING_MAP(kThumbBicRR,        0x4380,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "bics", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbBkpt,          0xbe00,
+                 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
+                 "bkpt", "!0d", 1),
+    ENCODING_MAP(kThumbBlx1,         0xf000,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
+                 "blx_1", "!0u", 1),
+    ENCODING_MAP(kThumbBlx2,         0xe800,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
+                 "blx_2", "!0v", 1),
+    ENCODING_MAP(kThumbBl1,          0xf000,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+                 "bl_1", "!0u", 1),
+    ENCODING_MAP(kThumbBl2,          0xf800,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+                 "bl_2", "!0v", 1),
+    ENCODING_MAP(kThumbBlxR,         0x4780,
+                 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR,
+                 "blx", "r!0d", 1),
+    ENCODING_MAP(kThumbBx,            0x4700,
+                 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
+                 "bx", "r!0d", 1),
+    ENCODING_MAP(kThumbCmnRR,        0x42c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+                 "cmn", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbCmpRI8,       0x2800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES,
+                 "cmp", "r!0d, #!1d", 1),
+    ENCODING_MAP(kThumbCmpRR,        0x4280,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+                 "cmp", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbCmpLH,        0x4540,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+                 "cmp", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbCmpHL,        0x4580,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+                 "cmp", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbCmpHH,        0x45c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+                 "cmp", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbEorRR,        0x4040,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "eors", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbLdmia,         0xc800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
+                 "ldmia", "r!0d!!, <!1R>", 1),
+    ENCODING_MAP(kThumbLdrRRI5,      0x6800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldr", "r!0d, [r!1d, #!2E]", 1),
+    ENCODING_MAP(kThumbLdrRRR,       0x5800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldr", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbLdrPcRel,    0x4800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC
+                 | IS_LOAD, "ldr", "r!0d, [pc, #!1E]", 1),
+    ENCODING_MAP(kThumbLdrSpRel,    0x9800,
+                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP
+                 | IS_LOAD, "ldr", "r!0d, [sp, #!2E]", 1),
+    ENCODING_MAP(kThumbLdrbRRI5,     0x7800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrb", "r!0d, [r!1d, #2d]", 1),
+    ENCODING_MAP(kThumbLdrbRRR,      0x5c00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrb", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbLdrhRRI5,     0x8800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrh", "r!0d, [r!1d, #!2F]", 1),
+    ENCODING_MAP(kThumbLdrhRRR,      0x5a00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrh", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbLdrsbRRR,     0x5600,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrsb", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbLdrshRRR,     0x5e00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrsh", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbLslRRI5,      0x0000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "lsls", "r!0d, r!1d, #!2d", 1),
+    ENCODING_MAP(kThumbLslRR,        0x4080,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "lsls", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbLsrRRI5,      0x0800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "lsrs", "r!0d, r!1d, #!2d", 1),
+    ENCODING_MAP(kThumbLsrRR,        0x40c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "lsrs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbMovImm,       0x2000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0 | SETS_CCODES,
+                 "movs", "r!0d, #!1d", 1),
+    ENCODING_MAP(kThumbMovRR,        0x1c00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "movs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbMovRR_H2H,    0x46c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbMovRR_H2L,    0x4640,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbMovRR_L2H,    0x4680,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbMul,           0x4340,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "muls", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbMvn,           0x43c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "mvns", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbNeg,           0x4240,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "negs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbOrr,           0x4300,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "orrs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbPop,           0xbc00,
+                 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
+                 | IS_LOAD, "pop", "<!0R>", 1),
+    ENCODING_MAP(kThumbPush,          0xb400,
+                 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
+                 | IS_STORE, "push", "<!0R>", 1),
+    ENCODING_MAP(kThumbRorRR,        0x41c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
+                 "rors", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbSbc,           0x4180,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE01 | USES_CCODES | SETS_CCODES,
+                 "sbcs", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumbStmia,         0xc000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1 | IS_STORE,
+                 "stmia", "r!0d!!, <!1R>", 1),
+    ENCODING_MAP(kThumbStrRRI5,      0x6000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "str", "r!0d, [r!1d, #!2E]", 1),
+    ENCODING_MAP(kThumbStrRRR,       0x5000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
+                 "str", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbStrSpRel,    0x9000,
+                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_SP
+                 | IS_STORE, "str", "r!0d, [sp, #!2E]", 1),
+    ENCODING_MAP(kThumbStrbRRI5,     0x7000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "strb", "r!0d, [r!1d, #!2d]", 1),
+    ENCODING_MAP(kThumbStrbRRR,      0x5400,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
+                 "strb", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbStrhRRI5,     0x8000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "strh", "r!0d, [r!1d, #!2F]", 1),
+    ENCODING_MAP(kThumbStrhRRR,      0x5200,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE,
+                 "strh", "r!0d, [r!1d, r!2d]", 1),
+    ENCODING_MAP(kThumbSubRRI3,      0x1e00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "subs", "r!0d, r!1d, #!2d]", 1),
+    ENCODING_MAP(kThumbSubRI8,       0x3800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
+                 "subs", "r!0d, #!1d", 1),
+    ENCODING_MAP(kThumbSubRRR,       0x1a00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
+                 "subs", "r!0d, r!1d, r!2d", 1),
+    ENCODING_MAP(kThumbSubSpI7,      0xb080,
+                 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
+                 "sub", "sp, #!0d", 1),
+    ENCODING_MAP(kThumbSwi,           0xdf00,
+                 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,                       kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
+                 "swi", "!0d", 1),
+    ENCODING_MAP(kThumbTst,           0x4200,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE01 | SETS_CCODES,
+                 "tst", "r!0d, r!1d", 1),
+    ENCODING_MAP(kThumb2Vldrs,       0xed900a00,
+                 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "vldr", "!0s, [r!1d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Vldrd,       0xed900b00,
+                 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "vldr", "!0S, [r!1d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Vmuls,        0xee200a00,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vmuls", "!0s, !1s, !2s", 2),
+    ENCODING_MAP(kThumb2Vmuld,        0xee200b00,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vmuld", "!0S, !1S, !2S", 2),
+    ENCODING_MAP(kThumb2Vstrs,       0xed800a00,
+                 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "vstr", "!0s, [r!1d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Vstrd,       0xed800b00,
+                 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "vstr", "!0S, [r!1d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Vsubs,        0xee300a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vsub", "!0s, !1s, !2s", 2),
+    ENCODING_MAP(kThumb2Vsubd,        0xee300b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vsub", "!0S, !1S, !2S", 2),
+    ENCODING_MAP(kThumb2Vadds,        0xee300a00,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vadd", "!0s, !1s, !2s", 2),
+    ENCODING_MAP(kThumb2Vaddd,        0xee300b00,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vadd", "!0S, !1S, !2S", 2),
+    ENCODING_MAP(kThumb2Vdivs,        0xee800a00,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vdivs", "!0s, !1s, !2s", 2),
+    ENCODING_MAP(kThumb2Vdivd,        0xee800b00,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "vdivd", "!0S, !1S, !2S", 2),
+    ENCODING_MAP(kThumb2VcvtIF,       0xeeb80ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vcvt.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2VcvtID,       0xeeb80bc0,
+                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vcvt.f64", "!0S, !1s", 2),
+    ENCODING_MAP(kThumb2VcvtFI,       0xeebd0ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vcvt.s32.f32 ", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2VcvtDI,       0xeebd0bc0,
+                 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vcvt.s32.f64 ", "!0s, !1S", 2),
+    ENCODING_MAP(kThumb2VcvtFd,       0xeeb70ac0,
+                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vcvt.f64.f32 ", "!0S, !1s", 2),
+    ENCODING_MAP(kThumb2VcvtDF,       0xeeb70bc0,
+                 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vcvt.f32.f64 ", "!0s, !1S", 2),
+    ENCODING_MAP(kThumb2Vsqrts,       0xeeb10ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vsqrt.f32 ", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Vsqrtd,       0xeeb10bc0,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vsqrt.f64 ", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2MovImmShift, 0xf04f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "mov", "r!0d, #!1m", 2),
+    ENCODING_MAP(kThumb2MovImm16,       0xf2400000,
+                 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "mov", "r!0d, #!1M", 2),
+    ENCODING_MAP(kThumb2StrRRI12,       0xf8c00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "str", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrRRI12,       0xf8d00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldr", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2StrRRI8Predec,       0xf8400c00,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "str", "r!0d, [r!1d, #-!2d]", 2),
+    ENCODING_MAP(kThumb2LdrRRI8Predec,       0xf8500c00,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldr", "r!0d, [r!1d, #-!2d]", 2),
+    ENCODING_MAP(kThumb2Cbnz,       0xb900, /* Note: does not affect flags */
+                 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
+                 "cbnz", "r!0d,!1t", 1),
+    ENCODING_MAP(kThumb2Cbz,       0xb100, /* Note: does not affect flags */
+                 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
+                 "cbz", "r!0d,!1t", 1),
+    ENCODING_MAP(kThumb2AddRRI12,       0xf2000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
+                 "add", "r!0d,r!1d,#!2d", 2),
+    ENCODING_MAP(kThumb2MovRR,       0xea4f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov", "r!0d, r!1d", 2),
+    ENCODING_MAP(kThumb2Vmovs,       0xeeb00a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vmov.f32 ", " !0s, !1s", 2),
+    ENCODING_MAP(kThumb2Vmovd,       0xeeb00b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vmov.f64 ", " !0S, !1S", 2),
+    ENCODING_MAP(kThumb2Ldmia,         0xe8900000,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
+                 "ldmia", "r!0d!!, <!1R>", 2),
+    ENCODING_MAP(kThumb2Stmia,         0xe8800000,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1 | IS_STORE,
+                 "stmia", "r!0d!!, <!1R>", 2),
+    ENCODING_MAP(kThumb2AddRRR,  0xeb100000, /* setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
+                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
+                 "adds", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2SubRRR,       0xebb00000, /* setflags enconding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
+                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
+                 "subs", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2SbcRRR,       0xeb700000, /* setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
+                 IS_QUAD_OP | REG_DEF0_USE12 | USES_CCODES | SETS_CCODES,
+                 "sbcs", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2CmpRR,       0xebb00f00,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
+                 "cmp", "r!0d, r!1d", 2),
+    ENCODING_MAP(kThumb2SubRRI12,       0xf2a00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
+                 "sub", "r!0d,r!1d,#!2d", 2),
+    ENCODING_MAP(kThumb2MvnImmShift,  0xf06f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "mvn", "r!0d, #!1n", 2),
+    ENCODING_MAP(kThumb2Sel,       0xfaa0f080,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE12 | USES_CCODES,
+                 "sel", "r!0d, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2Ubfx,       0xf3c00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
+                 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
+                 "ubfx", "r!0d, r!1d, #!2d, #!3d", 2),
+    ENCODING_MAP(kThumb2Sbfx,       0xf3400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
+                 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
+                 "sbfx", "r!0d, r!1d, #!2d, #!3d", 2),
+    ENCODING_MAP(kThumb2LdrRRR,    0xf8500000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldr", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2LdrhRRR,    0xf8300000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2LdrshRRR,    0xf9300000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrsh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2LdrbRRR,    0xf8100000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2LdrsbRRR,    0xf9100000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD,
+                 "ldrsb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2StrRRR,    0xf8400000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
+                 "str", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2StrhRRR,    0xf8200000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
+                 "strh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2StrbRRR,    0xf8000000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE,
+                 "strb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2),
+    ENCODING_MAP(kThumb2LdrhRRI12,       0xf8b00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrh", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrshRRI12,       0xf9b00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrsh", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrbRRI12,       0xf8900000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrb", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrsbRRI12,       0xf9900000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrsb", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2StrhRRI12,       0xf8a00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "strh", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2StrbRRI12,       0xf8800000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE,
+                 "strb", "r!0d, [r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2Pop,           0xe8bd0000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
+                 | IS_LOAD, "pop", "<!0R>", 2),
+    ENCODING_MAP(kThumb2Push,          0xe92d0000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
+                 | IS_STORE, "push", "<!0R>", 2),
+    ENCODING_MAP(kThumb2CmpRI8, 0xf1b00f00,
+                 kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_USE0 | SETS_CCODES,
+                 "cmp", "r!0d, #!1m", 2),
+    ENCODING_MAP(kThumb2AdcRRR,  0xeb500000, /* setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
+                 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
+                 "adcs", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2AndRRR,  0xea000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
+                 "and", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2BicRRR,  0xea200000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
+                 "bic", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2CmnRR,  0xeb000000,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "cmn", "r!0d, r!1d, shift !2d", 2),
+    ENCODING_MAP(kThumb2EorRRR,  0xea800000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
+                 "eor", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2MulRRR,  0xfb00f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul", "r!0d, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2MnvRR,  0xea6f0000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "mvn", "r!0d, r!1d, shift !2d", 2),
+    ENCODING_MAP(kThumb2RsubRRI8,       0xf1d00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "rsb", "r!0d,r!1d,#!2m", 2),
+    ENCODING_MAP(kThumb2NegRR,       0xf1d00000, /* instance of rsub */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "neg", "r!0d,r!1d", 2),
+    ENCODING_MAP(kThumb2OrrRRR,  0xea400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
+                 "orr", "r!0d, r!1d, r!2d!3H", 2),
+    ENCODING_MAP(kThumb2TstRR,       0xea100f00,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
+                 "tst", "r!0d, r!1d, shift !2d", 2),
+    ENCODING_MAP(kThumb2LslRRR,  0xfa00f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "lsl", "r!0d, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2LsrRRR,  0xfa20f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "lsr", "r!0d, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2AsrRRR,  0xfa40f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "asr", "r!0d, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2RorRRR,  0xfa60f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "ror", "r!0d, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2LslRRI5,  0xea4f0000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "lsl", "r!0d, r!1d, #!2d", 2),
+    ENCODING_MAP(kThumb2LsrRRI5,  0xea4f0010,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "lsr", "r!0d, r!1d, #!2d", 2),
+    ENCODING_MAP(kThumb2AsrRRI5,  0xea4f0020,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "asr", "r!0d, r!1d, #!2d", 2),
+    ENCODING_MAP(kThumb2RorRRI5,  0xea4f0030,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ror", "r!0d, r!1d, #!2d", 2),
+    ENCODING_MAP(kThumb2BicRRI8,  0xf0200000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "bic", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2AndRRI8,  0xf0000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "and", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2OrrRRI8,  0xf0400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "orr", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2EorRRI8,  0xf0800000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "eor", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2AddRRI8,  0xf1100000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "adds", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2AdcRRI8,  0xf1500000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
+                 "adcs", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2SubRRI8,  0xf1b00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
+                 "subs", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2SbcRRI8,  0xf1700000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
+                 "sbcs", "r!0d, r!1d, #!2m", 2),
+    ENCODING_MAP(kThumb2It,  0xbf00,
+                 kFmtBitBlt, 7, 4, kFmtBitBlt, 3, 0, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_IT | USES_CCODES,
+                 "it:!1b", "!0c", 1),
+    ENCODING_MAP(kThumb2Fmstat,  0xeef1fa10,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | SETS_CCODES,
+                 "fmstat", "", 2),
+    ENCODING_MAP(kThumb2Vcmpd,        0xeeb40b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
+                 "vcmp.f64", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2Vcmps,        0xeeb40a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
+                 "vcmp.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2LdrPcRel12,       0xf8df0000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
+                 "ldr", "r!0d, [r15pc, #!1d]", 2),
+    ENCODING_MAP(kThumb2BCond,        0xf0008000,
+                 kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | IS_BRANCH | USES_CCODES,
+                 "b!1c", "!0t", 2),
+    ENCODING_MAP(kThumb2Vmovd_RR,       0xeeb00b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vmov.f64", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2Vmovs_RR,       0xeeb00a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vmov.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Fmrs,       0xee100a10,
+                 kFmtBitBlt, 15, 12, kFmtSfp, 7, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "fmrs", "r!0d, !1s", 2),
+    ENCODING_MAP(kThumb2Fmsr,       0xee000a10,
+                 kFmtSfp, 7, 16, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "fmsr", "!0s, r!1d", 2),
+    ENCODING_MAP(kThumb2Fmrrd,       0xec500b10,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF01_USE2,
+                 "fmrrd", "r!0d, r!1d, !2S", 2),
+    ENCODING_MAP(kThumb2Fmdrr,       0xec400b10,
+                 kFmtDfp, 5, 0, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "fmdrr", "!0S, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2Vabsd,       0xeeb00bc0,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vabs.f64", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2Vabss,       0xeeb00ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vabs.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Vnegd,       0xeeb10b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vneg.f64", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2Vnegs,       0xeeb10a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vneg.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Vmovs_IMM8,       0xeeb00a00,
+                 kFmtSfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "vmov.f32", "!0s, #0x!1h", 2),
+    ENCODING_MAP(kThumb2Vmovd_IMM8,       0xeeb00b00,
+                 kFmtDfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "vmov.f64", "!0S, #0x!1h", 2),
+    ENCODING_MAP(kThumb2Mla,  0xfb000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 15, 12,
+                 IS_QUAD_OP | REG_DEF0 | REG_USE1 | REG_USE2 | REG_USE3,
+                 "mla", "r!0d, r!1d, r!2d, r!3d", 2),
+    ENCODING_MAP(kThumb2Umull,  0xfba00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16,
+                 kFmtBitBlt, 3, 0,
+                 IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3,
+                 "umull", "r!0d, r!1d, r!2d, r!3d", 2),
+    ENCODING_MAP(kThumb2Ldrex,       0xe8500f00,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD,
+                 "ldrex", "r!0d, [r!1d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Strex,       0xe8400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
+                 kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12 | IS_STORE,
+                 "strex", "r!0d,r!1d, [r!2d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Clrex,       0xf3bf8f2f,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "clrex", "", 2),
+    ENCODING_MAP(kThumb2Bfi,         0xf3600000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtShift5, -1, -1,
+                 kFmtBitBlt, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
+                 "bfi", "r!0d,r!1d,#!2d,#!3d", 2),
+    ENCODING_MAP(kThumb2Bfc,         0xf36f0000,
+                 kFmtBitBlt, 11, 8, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0,
+                 "bfc", "r!0d,#!1d,#!2d", 2),
+    ENCODING_MAP(kThumb2Dmb,         0xf3bf8f50,
+                 kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP,
+                 "dmb","#!0B",2),
+    ENCODING_MAP(kThumb2LdrPcReln12,       0xf85f0000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
+                 IS_BINARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
+                 "ldr", "r!0d, [r15pc, -#!1d]", 2),
+    ENCODING_MAP(kThumbUndefined,       0xde00,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "undefined", "", 1),
+};
+
+/*
+ * The fake NOP of moving r0 to r0 actually will incur data stalls if r0 is
+ * not ready. Since r5FP is not updated often, it is less likely to
+ * generate unnecessary stall cycles.
+ */
+#define PADDING_MOV_R5_R5               0x1C2D
+
+/* Track the number of times that the code cache is patched */
+#if defined(WITH_JIT_TUNING)
+#define UPDATE_CODE_CACHE_PATCHES()    (gDvmJit.codeCachePatches++)
+#else
+#define UPDATE_CODE_CACHE_PATCHES()
+#endif
+
+/* Write the numbers in the constant and class pool to the output stream */
+static void installLiteralPools(CompilationUnit *cUnit)
+{
+    int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset);
+    /* Install number of class pointer literals */
+    *dataPtr++ = cUnit->numClassPointers;
+    ArmLIR *dataLIR = (ArmLIR *) cUnit->classPointerList;
+    while (dataLIR) {
+        /*
+         * Install the callsiteinfo pointers into the cells for now. They will
+         * be converted into real pointers in dvmJitInstallClassObjectPointers.
+         */
+        *dataPtr++ = dataLIR->operands[0];
+        dataLIR = NEXT_LIR(dataLIR);
+    }
+    dataLIR = (ArmLIR *) cUnit->literalList;
+    while (dataLIR) {
+        *dataPtr++ = dataLIR->operands[0];
+        dataLIR = NEXT_LIR(dataLIR);
+    }
+}
+
+/*
+ * Assemble the LIR into binary instruction format.  Note that we may
+ * discover that pc-relative displacements may not fit the selected
+ * instruction.  In those cases we will try to substitute a new code
+ * sequence or request that the trace be shortened and retried.
+ */
+static AssemblerStatus assembleInstructions(CompilationUnit *cUnit,
+                                            intptr_t startAddr)
+{
+    short *bufferAddr = (short *) cUnit->codeBuffer;
+    ArmLIR *lir;
+
+    for (lir = (ArmLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
+        if (lir->opcode < 0) {
+            if ((lir->opcode == kArmPseudoPseudoAlign4) &&
+                /* 1 means padding is needed */
+                (lir->operands[0] == 1)) {
+                *bufferAddr++ = PADDING_MOV_R5_R5;
+            }
+            continue;
+        }
+
+        if (lir->flags.isNop) {
+            continue;
+        }
+
+        if (lir->opcode == kThumbLdrPcRel ||
+            lir->opcode == kThumb2LdrPcRel12 ||
+            lir->opcode == kThumbAddPcRel ||
+            ((lir->opcode == kThumb2Vldrs) && (lir->operands[1] == r15pc))) {
+            ArmLIR *lirTarget = (ArmLIR *) 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", delta);
+                dvmCompilerAbort(cUnit);
+            }
+            if ((lir->opcode == kThumb2LdrPcRel12) && (delta > 4091)) {
+                if (cUnit->printMe) {
+                    LOGD("kThumb2LdrPcRel12@%x: delta=%d", lir->generic.offset,
+                         delta);
+                    dvmCompilerCodegenDump(cUnit);
+                }
+                return kRetryHalve;
+            } else if (delta > 1020) {
+                if (cUnit->printMe) {
+                    LOGD("kThumbLdrPcRel@%x: delta=%d", lir->generic.offset,
+                         delta);
+                    dvmCompilerCodegenDump(cUnit);
+                }
+                return kRetryHalve;
+            }
+            if (lir->opcode == kThumb2Vldrs) {
+                lir->operands[2] = delta >> 2;
+            } else {
+                lir->operands[1] = (lir->opcode == kThumb2LdrPcRel12) ?
+                                    delta : delta >> 2;
+            }
+        } else if (lir->opcode == kThumb2Cbnz || lir->opcode == kThumb2Cbz) {
+            ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta > 126 || delta < 0) {
+                /* Convert to cmp rx,#0 / b[eq/ne] tgt pair */
+                ArmLIR *newInst =
+                    (ArmLIR *)dvmCompilerNew(sizeof(ArmLIR), true);
+                /* Make new branch instruction and insert after */
+                newInst->opcode = kThumbBCond;
+                newInst->operands[0] = 0;
+                newInst->operands[1] = (lir->opcode == kThumb2Cbz) ?
+                                        kArmCondEq : kArmCondNe;
+                newInst->generic.target = lir->generic.target;
+                dvmCompilerSetupResourceMasks(newInst);
+                dvmCompilerInsertLIRAfter((LIR *)lir, (LIR *)newInst);
+                /* Convert the cb[n]z to a cmp rx, #0 ] */
+                lir->opcode = kThumbCmpRI8;
+                /* operand[0] is src1 in both cb[n]z & CmpRI8 */
+                lir->operands[1] = 0;
+                lir->generic.target = 0;
+                dvmCompilerSetupResourceMasks(lir);
+                if (cUnit->printMe) {
+                    LOGD("kThumb2Cbnz/kThumb2Cbz@%x: delta=%d",
+                         lir->generic.offset, delta);
+                    dvmCompilerCodegenDump(cUnit);
+                }
+                return kRetryAll;
+            } else {
+                lir->operands[1] = delta >> 1;
+            }
+        } else if (lir->opcode == kThumbBCond ||
+                   lir->opcode == kThumb2BCond) {
+            ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
+                if (cUnit->printMe) {
+                    LOGD("kThumbBCond@%x: delta=%d", lir->generic.offset,
+                         delta);
+                    dvmCompilerCodegenDump(cUnit);
+                }
+                return kRetryHalve;
+            }
+            lir->operands[0] = delta >> 1;
+        } else if (lir->opcode == kThumbBUncond) {
+            ArmLIR *targetLIR = (ArmLIR *) 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", delta);
+                dvmCompilerAbort(cUnit);
+            }
+            lir->operands[0] = delta >> 1;
+        } else if (lir->opcode == kThumbBlx1) {
+            assert(NEXT_LIR(lir)->opcode == kThumbBlx2);
+            /* 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;
+        } else if (lir->opcode == kThumbBl1) {
+            assert(NEXT_LIR(lir)->opcode == kThumbBl2);
+            /* Both curPC and target are Thumb */
+            intptr_t curPC = startAddr + lir->generic.offset + 4;
+            intptr_t target = lir->operands[1];
+
+            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;
+        }
+
+        ArmEncodingMap *encoder = &EncodingMap[lir->opcode];
+        u4 bits = encoder->skeleton;
+        int i;
+        for (i = 0; i < 4; i++) {
+            u4 operand;
+            u4 value;
+            operand = lir->operands[i];
+            switch(encoder->fieldLoc[i].kind) {
+                case kFmtUnused:
+                    break;
+                case kFmtFPImm:
+                    value = ((operand & 0xF0) >> 4) << encoder->fieldLoc[i].end;
+                    value |= (operand & 0x0F) << encoder->fieldLoc[i].start;
+                    bits |= value;
+                    break;
+                case kFmtBrOffset:
+                    value = ((operand  & 0x80000) >> 19) << 26;
+                    value |= ((operand & 0x40000) >> 18) << 11;
+                    value |= ((operand & 0x20000) >> 17) << 13;
+                    value |= ((operand & 0x1f800) >> 11) << 16;
+                    value |= (operand  & 0x007ff);
+                    bits |= value;
+                    break;
+                case kFmtShift5:
+                    value = ((operand & 0x1c) >> 2) << 12;
+                    value |= (operand & 0x03) << 6;
+                    bits |= value;
+                    break;
+                case kFmtShift:
+                    value = ((operand & 0x70) >> 4) << 12;
+                    value |= (operand & 0x0f) << 4;
+                    bits |= value;
+                    break;
+                case kFmtBWidth:
+                    value = operand - 1;
+                    bits |= value;
+                    break;
+                case kFmtLsb:
+                    value = ((operand & 0x1c) >> 2) << 12;
+                    value |= (operand & 0x03) << 6;
+                    bits |= value;
+                    break;
+                case kFmtImm6:
+                    value = ((operand & 0x20) >> 5) << 9;
+                    value |= (operand & 0x1f) << 3;
+                    bits |= value;
+                    break;
+                case kFmtBitBlt:
+                    value = (operand << encoder->fieldLoc[i].start) &
+                            ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    bits |= value;
+                    break;
+                case kFmtDfp: {
+                    assert(DOUBLEREG(operand));
+                    assert((operand & 0x1) == 0);
+                    int regName = (operand & FP_REG_MASK) >> 1;
+                    /* Snag the 1-bit slice and position it */
+                    value = ((regName & 0x10) >> 4) <<
+                            encoder->fieldLoc[i].end;
+                    /* Extract and position the 4-bit slice */
+                    value |= (regName & 0x0f) <<
+                            encoder->fieldLoc[i].start;
+                    bits |= value;
+                    break;
+                }
+                case kFmtSfp:
+                    assert(SINGLEREG(operand));
+                    /* Snag the 1-bit slice and position it */
+                    value = (operand & 0x1) <<
+                            encoder->fieldLoc[i].end;
+                    /* Extract and position the 4-bit slice */
+                    value |= ((operand & 0x1e) >> 1) <<
+                            encoder->fieldLoc[i].start;
+                    bits |= value;
+                    break;
+                case kFmtImm12:
+                case kFmtModImm:
+                    value = ((operand & 0x800) >> 11) << 26;
+                    value |= ((operand & 0x700) >> 8) << 12;
+                    value |= operand & 0x0ff;
+                    bits |= value;
+                    break;
+                case kFmtImm16:
+                    value = ((operand & 0x0800) >> 11) << 26;
+                    value |= ((operand & 0xf000) >> 12) << 16;
+                    value |= ((operand & 0x0700) >> 8) << 12;
+                    value |= operand & 0x0ff;
+                    bits |= value;
+                    break;
+                default:
+                    assert(0);
+            }
+        }
+        if (encoder->size == 2) {
+            *bufferAddr++ = (bits >> 16) & 0xffff;
+        }
+        *bufferAddr++ = bits & 0xffff;
+    }
+    return kSuccess;
+}
+
+static int assignLiteralOffsetCommon(LIR *lir, int offset)
+{
+    for (;lir != NULL; lir = lir->next) {
+        lir->offset = offset;
+        offset += 4;
+    }
+    return offset;
+}
+
+/* Determine the offset of each literal field */
+static int assignLiteralOffset(CompilationUnit *cUnit, int offset)
+{
+    /* Reserved for the size field of class pointer pool */
+    offset += 4;
+    offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset);
+    offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
+    return offset;
+}
+
+/*
+ * 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 the address of the trace profile
+ * counter is at codeAddress - 6.
+ *
+ *      +----------------------------+
+ *      | Trace Profile Counter addr |  -> 4 bytes (PROF_COUNTER_ADDR_SIZE)
+ *      +----------------------------+
+ *   +--| Offset to chain cell counts|  -> 2 bytes (CHAIN_CELL_OFFSET_SIZE)
+ *   |  +----------------------------+
+ *   |  | Trace profile code         |  <- entry point when profiling
+ *   |  .  -   -   -   -   -   -   - .
+ *   |  | Code body                  |  <- entry point when not profiling
+ *   |  .                            .
+ *   |  |                            |
+ *   |  +----------------------------+
+ *   |  | Chaining Cells             |  -> 12/16 bytes, 4 byte aligned
+ *   |  .                            .
+ *   |  .                            .
+ *   |  |                            |
+ *   |  +----------------------------+
+ *   |  | Gap for large switch stmt  |  -> # cases >= MAX_CHAINED_SWITCH_CASES
+ *   |  +----------------------------+
+ *   +->| Chaining cell counts       |  -> 8 bytes, chain cell counts by type
+ *      +----------------------------+
+ *      | Trace description          |  -> variable sized
+ *      .                            .
+ *      |                            |
+ *      +----------------------------+
+ *      | # Class pointer pool size  |  -> 4 bytes
+ *      +----------------------------+
+ *      | Class pointer pool         |  -> 4-byte aligned, variable size
+ *      .                            .
+ *      .                            .
+ *      |                            |
+ *      +----------------------------+
+ *      | Literal pool               |  -> 4-byte aligned, variable size
+ *      .                            .
+ *      .                            .
+ *      |                            |
+ *      +----------------------------+
+ *
+ */
+
+#define PROF_COUNTER_ADDR_SIZE 4
+#define CHAIN_CELL_OFFSET_SIZE 2
+
+/*
+ * Utility functions to navigate various parts in a trace. If we change the
+ * layout/offset in the future, we just modify these functions and we don't need
+ * to propagate the changes to all the use cases.
+ */
+static inline char *getTraceBase(const JitEntry *p)
+{
+    return (char*)p->codeAddress -
+        (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE +
+         (p->u.info.instructionSet == DALVIK_JIT_ARM ? 0 : 1));
+}
+
+/* Handy function to retrieve the profile count */
+static inline JitTraceCounter_t getProfileCount(const JitEntry *entry)
+{
+    if (entry->dPC == 0 || entry->codeAddress == 0 ||
+        entry->codeAddress == dvmCompilerGetInterpretTemplate())
+        return 0;
+
+    JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
+
+    return **p;
+}
+
+/* Handy function to reset the profile count */
+static inline void resetProfileCount(const JitEntry *entry)
+{
+    if (entry->dPC == 0 || entry->codeAddress == 0 ||
+        entry->codeAddress == dvmCompilerGetInterpretTemplate())
+        return;
+
+    JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
+
+    **p = 0;
+}
+
+/* Get the pointer of the chain cell count */
+static inline ChainCellCounts* getChainCellCountsPointer(const char *base)
+{
+    /* 4 is the size of the profile count */
+    u2 *chainCellOffsetP = (u2 *) (base + PROF_COUNTER_ADDR_SIZE);
+    u2 chainCellOffset = *chainCellOffsetP;
+    return (ChainCellCounts *) ((char *) chainCellOffsetP + chainCellOffset);
+}
+
+/* Get the size of all chaining cells */
+static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts)
+{
+    int cellSize = 0;
+    int i;
+
+    /* Get total count of chain cells */
+    for (i = 0; i < kChainingCellGap; i++) {
+        if (i != kChainingCellInvokePredicted) {
+            cellSize += pChainCellCounts->u.count[i] *
+                        (CHAIN_CELL_NORMAL_SIZE >> 2);
+        } else {
+            cellSize += pChainCellCounts->u.count[i] *
+                (CHAIN_CELL_PREDICTED_SIZE >> 2);
+        }
+    }
+    return cellSize;
+}
+
+/* Get the starting pointer of the trace description section */
+static JitTraceDescription* getTraceDescriptionPointer(const char *base)
+{
+    ChainCellCounts* pCellCounts = getChainCellCountsPointer(base);
+    return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts));
+}
+
+/* Get the size of a trace description */
+static int getTraceDescriptionSize(const JitTraceDescription *desc)
+{
+    int runCount;
+    /* Trace end is always of non-meta type (ie isCode == true) */
+    for (runCount = 0; ; runCount++) {
+        if (desc->trace[runCount].isCode &&
+            desc->trace[runCount].info.frag.runEnd)
+           break;
+    }
+    return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
+}
+
+#if defined(SIGNATURE_BREAKPOINT)
+/* Inspect the assembled instruction stream to find potential matches */
+static void matchSignatureBreakpoint(const CompilationUnit *cUnit,
+                                     unsigned int size)
+{
+    unsigned int i, j;
+    u4 *ptr = (u4 *) cUnit->codeBuffer;
+
+    for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) {
+        if (ptr[i] == gDvmJit.signatureBreakpoint[0]) {
+            for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) {
+                if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) {
+                    break;
+                }
+            }
+            if (j == gDvmJit.signatureBreakpointSize) {
+                LOGD("Signature match starting from offset %#x (%d words)",
+                     i*4, gDvmJit.signatureBreakpointSize);
+                int descSize = getTraceDescriptionSize(cUnit->traceDesc);
+                JitTraceDescription *newCopy =
+                    (JitTraceDescription *) malloc(descSize);
+                memcpy(newCopy, cUnit->traceDesc, descSize);
+                dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy);
+                break;
+            }
+        }
+    }
+}
+#endif
+
+/*
+ * 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, JitTranslationInfo *info)
+{
+    ArmLIR *armLIR;
+    int offset = 0;
+    int i;
+    ChainCellCounts chainCellCounts;
+    int descSize = (cUnit->jitMode == kJitMethod) ?
+        0 : getTraceDescriptionSize(cUnit->traceDesc);
+    int chainingCellGap = 0;
+
+    info->instructionSet = cUnit->instructionSet;
+
+    /* Beginning offset needs to allow space for chain cell offset */
+    for (armLIR = (ArmLIR *) cUnit->firstLIRInsn;
+         armLIR;
+         armLIR = NEXT_LIR(armLIR)) {
+        armLIR->generic.offset = offset;
+        if (armLIR->opcode >= 0 && !armLIR->flags.isNop) {
+            armLIR->flags.size = EncodingMap[armLIR->opcode].size * 2;
+            offset += armLIR->flags.size;
+        } else if (armLIR->opcode == kArmPseudoPseudoAlign4) {
+            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;
+
+    u4 chainCellOffset = offset;
+    ArmLIR *chainCellOffsetLIR = NULL;
+
+    if (cUnit->jitMode != kJitMethod) {
+        /*
+         * Get the gap (# of u4) between the offset of chaining cell count and
+         * the bottom of real chaining cells. If the translation has chaining
+         * cells, the gap is guaranteed to be multiples of 4.
+         */
+        chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
+
+        /* Add space for chain cell counts & trace description */
+        chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
+        assert(chainCellOffsetLIR);
+        assert(chainCellOffset < 0x10000);
+        assert(chainCellOffsetLIR->opcode == kArm16BitData &&
+               chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
+
+        /*
+         * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
+         * space occupied by the pointer to the trace profiling counter.
+         */
+        chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
+
+        offset += sizeof(chainCellCounts) + descSize;
+
+        assert((offset & 0x3) == 0);  /* Should still be word aligned */
+    }
+
+    /* Set up offsets for literals */
+    cUnit->dataOffset = offset;
+
+    /*
+     * Assign each class pointer/constant an offset from the beginning of the
+     * compilation unit.
+     */
+    offset = assignLiteralOffset(cUnit, offset);
+
+    cUnit->totalSize = offset;
+
+    if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > gDvmJit.codeCacheSize) {
+        gDvmJit.codeCacheFull = true;
+        info->discardResult = true;
+        return;
+    }
+
+    /* Allocate enough space for the code block */
+    cUnit->codeBuffer = (unsigned char *)dvmCompilerNew(chainCellOffset, true);
+    if (cUnit->codeBuffer == NULL) {
+        LOGE("Code buffer allocation failure");
+        info->discardResult = true;
+        return;
+    }
+
+    /*
+     * Attempt to assemble the trace.  Note that assembleInstructions
+     * may rewrite the code sequence and request a retry.
+     */
+    cUnit->assemblerStatus = assembleInstructions(cUnit,
+          (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
+
+    switch(cUnit->assemblerStatus) {
+        case kSuccess:
+            break;
+        case kRetryAll:
+            if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) {
+                if (cUnit->jitMode != kJitMethod) {
+                    /* Restore pristine chain cell marker on retry */
+                    chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
+                }
+                return;
+            }
+            /* Too many retries - reset and try cutting the trace in half */
+            cUnit->assemblerRetries = 0;
+            cUnit->assemblerStatus = kRetryHalve;
+            return;
+        case kRetryHalve:
+            return;
+        default:
+             LOGE("Unexpected assembler status: %d", cUnit->assemblerStatus);
+             dvmAbort();
+    }
+
+#if defined(SIGNATURE_BREAKPOINT)
+    if (info->discardResult == false && gDvmJit.signatureBreakpoint != NULL &&
+        chainCellOffset/4 >= gDvmJit.signatureBreakpointSize) {
+        matchSignatureBreakpoint(cUnit, chainCellOffset/4);
+    }
+#endif
+
+    /* Don't go all the way if the goal is just to get the verbose output */
+    if (info->discardResult) return;
+
+    /*
+     * The cache might disappear - acquire lock and check version
+     * Continue holding lock until translation cache update is complete.
+     * These actions are required here in the compiler thread because
+     * it is unaffected by suspend requests and doesn't know if a
+     * translation cache flush is in progress.
+     */
+    dvmLockMutex(&gDvmJit.compilerLock);
+    if (info->cacheVersion != gDvmJit.cacheVersion) {
+        /* Cache changed - discard current translation */
+        info->discardResult = true;
+        info->codeAddress = NULL;
+        dvmUnlockMutex(&gDvmJit.compilerLock);
+        return;
+    }
+
+    cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
+    gDvmJit.codeCacheByteUsed += offset;
+
+    UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset);
+
+    /* Install the code block */
+    memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
+    gDvmJit.numCompilations++;
+
+    if (cUnit->jitMode != kJitMethod) {
+        /* Install the chaining cell counts */
+        for (i=0; i< kChainingCellGap; i++) {
+            chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+        }
+
+        /* Set the gap number in the chaining cell count structure */
+        chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
+
+        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 */
+    installLiteralPools(cUnit);
+
+    /* Flush dcache and invalidate the icache to maintain coherence */
+    dvmCompilerCacheFlush((long)cUnit->baseAddr,
+                          (long)((char *) cUnit->baseAddr + offset), 0);
+    UPDATE_CODE_CACHE_PATCHES();
+
+    PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
+
+    /* Translation cache update complete - release lock */
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
+    /* Record code entry point and instruction set */
+    info->codeAddress = (char*)cUnit->baseAddr + cUnit->headerSize;
+    /* If applicable, mark low bit to denote thumb */
+    if (info->instructionSet != DALVIK_JIT_ARM)
+        info->codeAddress = (char*)info->codeAddress + 1;
+    /* transfer the size of the profiling code */
+    info->profileCodeSize = cUnit->profileCodeSize;
+}
+
+/*
+ * Returns the skeleton bit pattern associated with an opcode.  All
+ * variable fields are zeroed.
+ */
+static u4 getSkeleton(ArmOpcode op)
+{
+    return EncodingMap[op].skeleton;
+}
+
+static u4 assembleChainingBranch(int branchOffset, bool thumbTarget)
+{
+    u4 thumb1, thumb2;
+
+    if (!thumbTarget) {
+        thumb1 =  (getSkeleton(kThumbBlx1) | ((branchOffset>>12) & 0x7ff));
+        thumb2 =  (getSkeleton(kThumbBlx2) | ((branchOffset>> 1) & 0x7ff));
+    } else if ((branchOffset < -2048) | (branchOffset > 2046)) {
+        thumb1 =  (getSkeleton(kThumbBl1) | ((branchOffset>>12) & 0x7ff));
+        thumb2 =  (getSkeleton(kThumbBl2) | ((branchOffset>> 1) & 0x7ff));
+    } else {
+        thumb1 =  (getSkeleton(kThumbBUncond) | ((branchOffset>> 1) & 0x7ff));
+        thumb2 =  getSkeleton(kThumbOrr);  /* nop -> or r0, r0 */
+    }
+
+    return thumb2<<16 | thumb1;
+}
+
+/*
+ * 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, because the generic "interpret" translation needs
+ * the link register to find the dalvik pc of teh target.
+ *     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 newInst;
+    bool thumbTarget;
+
+    /*
+     * Only chain translations when there is no urge to ask all threads to
+     * suspend themselves via the interpreter.
+     */
+    if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) &&
+        (gDvmJit.codeCacheFull == false)) {
+        assert((branchOffset >= -(1<<22)) && (branchOffset <= ((1<<22)-2)));
+
+        gDvmJit.translationChains++;
+
+        COMPILER_TRACE_CHAINING(
+            LOGD("Jit Runtime: chaining %#x to %#x",
+                 (int) branchAddr, (int) tgtAddr & -2));
+
+        /*
+         * NOTE: normally, all translations are Thumb[2] mode, with
+         * a single exception: the default TEMPLATE_INTERPRET
+         * pseudo-translation.  If the need ever arises to
+         * mix Arm & Thumb[2] translations, the following code should be
+         * generalized.
+         */
+        thumbTarget = (tgtAddr != dvmCompilerGetInterpretTemplate());
+
+        newInst = assembleChainingBranch(branchOffset, thumbTarget);
+
+        /*
+         * The second half-word instruction of the chaining cell must
+         * either be a nop (which represents initial state), or is the
+         * same exact branch halfword that we are trying to install.
+         */
+        assert( ((*branchAddr >> 16) == getSkeleton(kThumbOrr)) ||
+                ((*branchAddr >> 16) == (newInst >> 16)));
+
+        UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
+        *branchAddr = newInst;
+        dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
+        UPDATE_CODE_CACHE_PATCHES();
+
+        PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
+
+        gDvmJit.hasNewChain = true;
+    }
+
+    return tgtAddr;
+}
+
+#if !defined(WITH_SELF_VERIFICATION)
+/*
+ * Attempt to enqueue a work order to patch an inline cache for a predicted
+ * chaining cell for virtual/interface calls.
+ */
+static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
+                                    PredictedChainingCell *newContent)
+{
+    /*
+     * Make sure only one thread gets here since updating the cell (ie fast
+     * path and queueing the request (ie the queued path) have to be done
+     * in an atomic fashion.
+     */
+    dvmLockMutex(&gDvmJit.compilerICPatchLock);
+
+    /* Fast path for uninitialized chaining cell */
+    if (cellAddr->clazz == NULL &&
+        cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
+
+        UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+        cellAddr->method = newContent->method;
+        cellAddr->branch = newContent->branch;
+        /*
+         * The update order matters - make sure clazz is updated last since it
+         * will bring the uninitialized chaining cell to life.
+         */
+        android_atomic_release_store((int32_t)newContent->clazz,
+            (volatile int32_t *)(void *)&cellAddr->clazz);
+        dvmCompilerCacheFlush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0);
+        UPDATE_CODE_CACHE_PATCHES();
+
+        PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.icPatchInit++;
+#endif
+    /* Check if this is a frequently missed clazz */
+    } else if (cellAddr->stagedClazz != newContent->clazz) {
+        /* Not proven to be frequent yet - build up the filter cache */
+        UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+        cellAddr->stagedClazz = newContent->clazz;
+
+        UPDATE_CODE_CACHE_PATCHES();
+        PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.icPatchRejected++;
+#endif
+    /*
+     * Different classes but same method implementation - it is safe to just
+     * patch the class value without the need to stop the world.
+     */
+    } else if (cellAddr->method == newContent->method) {
+        UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+        cellAddr->clazz = newContent->clazz;
+        /* No need to flush the cache here since the branch is not patched */
+        UPDATE_CODE_CACHE_PATCHES();
+
+        PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
+
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.icPatchLockFree++;
+#endif
+    /*
+     * Cannot patch the chaining cell inline - queue it until the next safe
+     * point.
+     */
+    } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
+        int index = gDvmJit.compilerICPatchIndex++;
+        const ClassObject *clazz = newContent->clazz;
+
+        gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr;
+        gDvmJit.compilerICPatchQueue[index].cellContent = *newContent;
+        gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor;
+        gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader;
+        /* For verification purpose only */
+        gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber;
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.icPatchQueued++;
+#endif
+    } else {
+    /* Queue is full - just drop this patch request */
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.icPatchDropped++;
+#endif
+    }
+
+    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+}
+#endif
+
+/*
+ * This method is called from the invoke templates for virtual and interface
+ * methods to speculatively setup a chain to the callee. The templates are
+ * written in assembly and have setup method, cell, and clazz at r0, r2, and
+ * r3 respectively, so there is a unused argument in the list. Upon return one
+ * of the following three results may happen:
+ *   1) Chain is not setup because the callee is native. Reset the rechain
+ *      count to a big number so that it will take a long time before the next
+ *      rechain attempt to happen.
+ *   2) Chain is not setup because the callee has not been created yet. Reset
+ *      the rechain count to a small number and retry in the near future.
+ *   3) Enqueue the new content for the chaining cell which will be appled in
+ *      next safe point.
+ */
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+                                          Thread *self,
+                                          PredictedChainingCell *cell,
+                                          const ClassObject *clazz)
+{
+    int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
+#if defined(WITH_SELF_VERIFICATION)
+    newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID;
+    goto done;
+#else
+    PredictedChainingCell newCell;
+    int baseAddr, branchOffset, tgtAddr;
+    if (dvmIsNativeMethod(method)) {
+        UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
+
+        /*
+         * Put a non-zero/bogus value in the clazz field so that it won't
+         * trigger immediate patching and will continue to fail to match with
+         * a real clazz pointer.
+         */
+        cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ;
+
+        UPDATE_CODE_CACHE_PATCHES();
+        PROTECT_CODE_CACHE(cell, sizeof(*cell));
+        goto done;
+    }
+    tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
+
+    /*
+     * Compilation not made yet for the callee. Reset the counter to a small
+     * value and come back to check soon.
+     */
+    if ((tgtAddr == 0) ||
+        ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
+        COMPILER_TRACE_CHAINING(
+            LOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
+                 cell, method->clazz->descriptor, method->name));
+        goto done;
+    }
+
+    if (cell->clazz == NULL) {
+        newRechainCount = self->icRechainCount;
+    }
+
+    baseAddr = (int) cell + 4;   // PC is cur_addr + 4
+    branchOffset = tgtAddr - baseAddr;
+
+    newCell.branch = assembleChainingBranch(branchOffset, true);
+    newCell.clazz = clazz;
+    newCell.method = method;
+    newCell.stagedClazz = NULL;
+
+    /*
+     * Enter the work order to the queue and the chaining cell will be patched
+     * the next time a safe point is entered.
+     *
+     * If the enqueuing fails reset the rechain count to a normal value so that
+     * it won't get indefinitely delayed.
+     */
+    inlineCachePatchEnqueue(cell, &newCell);
+#endif
+done:
+    self->icRechainCount = newRechainCount;
+    return method;
+}
+
+/*
+ * Patch the inline cache content based on the content passed from the work
+ * order.
+ */
+void dvmCompilerPatchInlineCache(void)
+{
+    int i;
+    PredictedChainingCell *minAddr, *maxAddr;
+
+    /* Nothing to be done */
+    if (gDvmJit.compilerICPatchIndex == 0) return;
+
+    /*
+     * Since all threads are already stopped we don't really need to acquire
+     * the lock. But race condition can be easily introduced in the future w/o
+     * paying attention so we still acquire the lock here.
+     */
+    dvmLockMutex(&gDvmJit.compilerICPatchLock);
+
+    UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+    //LOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
+
+    /* Initialize the min/max address range */
+    minAddr = (PredictedChainingCell *)
+        ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize);
+    maxAddr = (PredictedChainingCell *) gDvmJit.codeCache;
+
+    for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) {
+        ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i];
+        PredictedChainingCell *cellAddr = workOrder->cellAddr;
+        PredictedChainingCell *cellContent = &workOrder->cellContent;
+        ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor,
+                                                workOrder->classLoader);
+
+        assert(clazz->serialNumber == workOrder->serialNumber);
+
+        /* Use the newly resolved clazz pointer */
+        cellContent->clazz = clazz;
+
+        COMPILER_TRACE_CHAINING(
+            LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
+                 "patched",
+                 cellAddr,
+                 cellAddr->clazz->descriptor,
+                 cellContent->clazz->descriptor,
+                 cellContent->method->name));
+
+        /* Patch the chaining cell */
+        *cellAddr = *cellContent;
+        minAddr = (cellAddr < minAddr) ? cellAddr : minAddr;
+        maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr;
+    }
+
+    /* Then synchronize the I/D cache */
+    dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
+    UPDATE_CODE_CACHE_PATCHES();
+
+    PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+    gDvmJit.compilerICPatchIndex = 0;
+    dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
+}
+
+/*
+ * 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.
+ */
+static u4* unchainSingle(JitEntry *trace)
+{
+    const char *base = getTraceBase(trace);
+    ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
+    int cellSize = getChainCellSize(pChainCellCounts);
+    u4* pChainCells;
+    u4 newInst;
+    int i,j;
+    PredictedChainingCell *predChainCell;
+
+    if (cellSize == 0)
+        return (u4 *) pChainCellCounts;
+
+    /* Locate the beginning of the chain cell region */
+    pChainCells = ((u4 *) pChainCellCounts) - cellSize -
+                  pChainCellCounts->u.count[kChainingCellGap];
+
+    /* The cells are sorted in order - walk through them and reset */
+    for (i = 0; i < kChainingCellGap; i++) {
+        int elemSize = CHAIN_CELL_NORMAL_SIZE >> 2;  /* In 32-bit words */
+        if (i == kChainingCellInvokePredicted) {
+            elemSize = CHAIN_CELL_PREDICTED_SIZE >> 2;
+        }
+
+        for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
+            switch(i) {
+                case kChainingCellNormal:
+                case kChainingCellHot:
+                case kChainingCellInvokeSingleton:
+                case kChainingCellBackwardBranch:
+                    /*
+                     * Replace the 1st half-word of the cell with an
+                     * unconditional branch, leaving the 2nd half-word
+                     * untouched.  This avoids problems with a thread
+                     * that is suspended between the two halves when
+                     * this unchaining takes place.
+                     */
+                    newInst = *pChainCells;
+                    newInst &= 0xFFFF0000;
+                    newInst |= getSkeleton(kThumbBUncond); /* b offset is 0 */
+                    *pChainCells = newInst;
+                    break;
+                case kChainingCellInvokePredicted:
+                    predChainCell = (PredictedChainingCell *) pChainCells;
+                    /*
+                     * There could be a race on another mutator thread to use
+                     * this particular predicted cell and the check has passed
+                     * the clazz comparison. So we cannot safely wipe the
+                     * method and branch but it is safe to clear the clazz,
+                     * which serves as the key.
+                     */
+                    predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
+                    break;
+                default:
+                    LOGE("Unexpected chaining type: %d", i);
+                    dvmAbort();  // dvmAbort OK here - can't safely recover
+            }
+            COMPILER_TRACE_CHAINING(
+                LOGD("Jit Runtime: unchaining %#x", (int)pChainCells));
+            pChainCells += elemSize;  /* Advance by a fixed number of 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);
+
+        UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+        for (i = 0; i < gDvmJit.jitTableSize; i++) {
+            if (gDvmJit.pJitEntryTable[i].dPC &&
+                !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
+                gDvmJit.pJitEntryTable[i].codeAddress &&
+                (gDvmJit.pJitEntryTable[i].codeAddress !=
+                 dvmCompilerGetInterpretTemplate())) {
+                u4* lastAddress;
+                lastAddress = unchainSingle(&gDvmJit.pJitEntryTable[i]);
+                if (lowAddress == NULL ||
+                      (u4*)gDvmJit.pJitEntryTable[i].codeAddress <
+                      lowAddress)
+                    lowAddress = lastAddress;
+                if (lastAddress > highAddress)
+                    highAddress = lastAddress;
+            }
+        }
+        dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
+        UPDATE_CODE_CACHE_PATCHES();
+
+        PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        gDvmJit.translationChains = 0;
+    }
+    gDvmJit.hasNewChain = false;
+}
+
+typedef struct jitProfileAddrToLine {
+    u4 lineNum;
+    u4 bytecodeOffset;
+} jitProfileAddrToLine;
+
+
+/* Callback function to track the bytecode offset/line number relationiship */
+static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum)
+{
+    jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt;
+
+    /* Best match so far for this offset */
+    if (addrToLine->bytecodeOffset >= bytecodeOffset) {
+        addrToLine->lineNum = lineNum;
+    }
+    return 0;
+}
+
+/* Dumps profile info for a single trace */
+static int dumpTraceProfile(JitEntry *p, bool silent, bool reset,
+                            unsigned long sum)
+{
+    int idx;
+
+    if (p->codeAddress == NULL) {
+        if (!silent)
+            LOGD("TRACEPROFILE NULL");
+        return 0;
+    }
+    if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
+        if (!silent)
+            LOGD("TRACEPROFILE INTERPRET_ONLY");
+        return 0;
+    }
+    JitTraceCounter_t count = getProfileCount(p);
+    if (reset) {
+        resetProfileCount(p);
+    }
+    if (silent) {
+        return count;
+    }
+    JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p));
+    const Method *method = desc->method;
+    char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
+    jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset};
+
+    /*
+     * We may end up decoding the debug information for the same method
+     * multiple times, but the tradeoff is we don't need to allocate extra
+     * space to store the addr/line mapping. Since this is a debugging feature
+     * and done infrequently so the slower but simpler mechanism should work
+     * just fine.
+     */
+    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
+                       dvmGetMethodCode(method),
+                       method->clazz->descriptor,
+                       method->prototype.protoIdx,
+                       method->accessFlags,
+                       addrToLineCb, NULL, &addrToLine);
+
+    LOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s",
+         (int) getTraceBase(p),
+         count,
+         ((float ) count) / sum * 100.0,
+         desc->trace[0].info.frag.startOffset,
+         desc->trace[0].info.frag.numInsts,
+         addrToLine.lineNum,
+         method->clazz->descriptor, method->name, methodDesc);
+    free(methodDesc);
+
+    /* Find the last fragment (ie runEnd is set) */
+    for (idx = 0;
+         desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd;
+         idx++) {
+    }
+
+    /*
+     * runEnd must comes with a JitCodeDesc frag. If isCode is false it must
+     * be a meta info field (only used by callsite info for now).
+     */
+    if (!desc->trace[idx].isCode) {
+        const Method *method = (const Method *)
+            desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta;
+        char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
+        /* Print the callee info in the trace */
+        LOGD("    -> %s%s;%s", method->clazz->descriptor, method->name,
+             methodDesc);
+    }
+
+    return count;
+}
+
+/* Create a copy of the trace descriptor of an existing compilation */
+JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
+                                            const JitEntry *knownEntry)
+{
+    const JitEntry *jitEntry = knownEntry ? knownEntry
+                                          : dvmJitFindEntry(pc, false);
+    if ((jitEntry == NULL) || (jitEntry->codeAddress == 0))
+        return NULL;
+
+    JitTraceDescription *desc =
+        getTraceDescriptionPointer(getTraceBase(jitEntry));
+
+    /* Now make a copy and return */
+    int descSize = getTraceDescriptionSize(desc);
+    JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize);
+    memcpy(newCopy, desc, descSize);
+    return newCopy;
+}
+
+/* qsort callback function */
+static int sortTraceProfileCount(const void *entry1, const void *entry2)
+{
+    const JitEntry *jitEntry1 = (const JitEntry *)entry1;
+    const JitEntry *jitEntry2 = (const JitEntry *)entry2;
+
+    JitTraceCounter_t count1 = getProfileCount(jitEntry1);
+    JitTraceCounter_t count2 = getProfileCount(jitEntry2);
+    return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
+}
+
+/* Sort the trace profile counts and dump them */
+void dvmCompilerSortAndPrintTraceProfiles()
+{
+    JitEntry *sortedEntries;
+    int numTraces = 0;
+    unsigned long sum = 0;
+    unsigned int i;
+
+    /* Make sure that the table is not changing */
+    dvmLockMutex(&gDvmJit.tableLock);
+
+    /* Sort the entries by descending order */
+    sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
+    if (sortedEntries == NULL)
+        goto done;
+    memcpy(sortedEntries, gDvmJit.pJitEntryTable,
+           sizeof(JitEntry) * gDvmJit.jitTableSize);
+    qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
+          sortTraceProfileCount);
+
+    /* Analyze the sorted entries */
+    for (i=0; i < gDvmJit.jitTableSize; i++) {
+        if (sortedEntries[i].dPC != 0) {
+            sum += dumpTraceProfile(&sortedEntries[i],
+                                       true /* silent */,
+                                       false /* reset */,
+                                       0);
+            numTraces++;
+        }
+    }
+    if (numTraces == 0)
+        numTraces = 1;
+    if (sum == 0) {
+        sum = 1;
+    }
+
+    LOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
+
+    /* Dump the sorted entries. The count of each trace will be reset to 0. */
+    for (i=0; i < gDvmJit.jitTableSize; i++) {
+        if (sortedEntries[i].dPC != 0) {
+            dumpTraceProfile(&sortedEntries[i],
+                             false /* silent */,
+                             true /* reset */,
+                             sum);
+        }
+    }
+
+    for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
+        /* Stip interpreter stubs */
+        if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
+            continue;
+        }
+        JitTraceDescription* desc =
+            dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
+        if (desc) {
+            dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
+                                   kWorkOrderTraceDebug, desc);
+        }
+    }
+
+    free(sortedEntries);
+done:
+    dvmUnlockMutex(&gDvmJit.tableLock);
+    return;
+}
+
+static void findClassPointersSingleTrace(char *base, void (*callback)(void *))
+{
+    unsigned int chainTypeIdx, chainIdx;
+    ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
+    int cellSize = getChainCellSize(pChainCellCounts);
+    /* Scan the chaining cells */
+    if (cellSize) {
+        /* Locate the beginning of the chain cell region */
+        u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize -
+            pChainCellCounts->u.count[kChainingCellGap];
+        /* The cells are sorted in order - walk through them */
+        for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap;
+             chainTypeIdx++) {
+            if (chainTypeIdx != kChainingCellInvokePredicted) {
+                /* In 32-bit words */
+                pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) *
+                    pChainCellCounts->u.count[chainTypeIdx];
+                continue;
+            }
+            for (chainIdx = 0;
+                 chainIdx < pChainCellCounts->u.count[chainTypeIdx];
+                 chainIdx++) {
+                PredictedChainingCell *cell =
+                    (PredictedChainingCell *) pChainCells;
+                /*
+                 * Report the cell if it contains a sane class
+                 * pointer.
+                 */
+                if (cell->clazz != NULL &&
+                    cell->clazz !=
+                      (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) {
+                    callback(&cell->clazz);
+                }
+                pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2;
+            }
+        }
+    }
+
+    /* Scan the class pointer pool */
+    JitTraceDescription *desc = getTraceDescriptionPointer(base);
+    int descSize = getTraceDescriptionSize(desc);
+    int *classPointerP = (int *) ((char *) desc + descSize);
+    int numClassPointers = *classPointerP++;
+    for (; numClassPointers; numClassPointers--, classPointerP++) {
+        callback(classPointerP);
+    }
+}
+
+/*
+ * Scan class pointers in each translation and pass its address to the callback
+ * function. Currently such a pointers can be found in the pointer pool and the
+ * clazz field in the predicted chaining cells.
+ */
+void dvmJitScanAllClassPointers(void (*callback)(void *))
+{
+    UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+
+    /* Handle the inflight compilation first */
+    if (gDvmJit.inflightBaseAddr)
+        findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr,
+                                     callback);
+
+    if (gDvmJit.pJitEntryTable != NULL) {
+        unsigned int traceIdx;
+        dvmLockMutex(&gDvmJit.tableLock);
+        for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) {
+            const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx];
+            if (entry->dPC &&
+                !entry->u.info.isMethodEntry &&
+                entry->codeAddress &&
+                (entry->codeAddress != dvmCompilerGetInterpretTemplate())) {
+                char *base = getTraceBase(entry);
+                findClassPointersSingleTrace(base, callback);
+            }
+        }
+        dvmUnlockMutex(&gDvmJit.tableLock);
+    }
+    UPDATE_CODE_CACHE_PATCHES();
+
+    PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
+}
+
+/*
+ * Provide the final touch on the class object pointer pool to install the
+ * actual pointers. The thread has to be in the running state.
+ */
+void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
+{
+    char *base = codeAddress - cUnit->headerSize -
+                 (cUnit->instructionSet == DALVIK_JIT_ARM ? 0 : 1);
+
+    /* Scan the class pointer pool */
+    JitTraceDescription *desc = getTraceDescriptionPointer(base);
+    int descSize = getTraceDescriptionSize(desc);
+    intptr_t *classPointerP = (int *) ((char *) desc + descSize);
+    int numClassPointers = *(int *)classPointerP++;
+    intptr_t *startClassPointerP = classPointerP;
+
+    /*
+     * Change the thread state to VM_RUNNING so that GC won't be happening
+     * when the assembler looks up the class pointers. May suspend the current
+     * thread if there is a pending request before the state is actually
+     * changed to RUNNING.
+     */
+    dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING);
+
+    /*
+     * Unprotecting the code cache will need to acquire the code cache
+     * protection lock first. Doing so after the state change may increase the
+     * time spent in the RUNNING state (which may delay the next GC request
+     * should there be contention on codeCacheProtectionLock). In practice
+     * this is probably not going to happen often since a GC is just served.
+     * More importantly, acquiring the lock before the state change will
+     * cause deadlock (b/4192964).
+     */
+    UNPROTECT_CODE_CACHE(startClassPointerP,
+                         numClassPointers * sizeof(intptr_t));
+#if defined(WITH_JIT_TUNING)
+    u8 startTime = dvmGetRelativeTimeUsec();
+#endif
+    for (;numClassPointers; numClassPointers--) {
+        CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP;
+        ClassObject *clazz = dvmFindClassNoInit(
+            callsiteInfo->classDescriptor, callsiteInfo->classLoader);
+        assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor));
+        *classPointerP++ = (intptr_t) clazz;
+    }
+
+    /*
+     * Register the base address so that if GC kicks in after the thread state
+     * has been changed to VMWAIT and before the compiled code is registered
+     * in the JIT table, its content can be patched if class objects are
+     * moved.
+     */
+    gDvmJit.inflightBaseAddr = base;
+
+#if defined(WITH_JIT_TUNING)
+    u8 blockTime = dvmGetRelativeTimeUsec() - startTime;
+    gDvmJit.compilerThreadBlockGCTime += blockTime;
+    if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime)
+        gDvmJit.maxCompilerThreadBlockGCTime = blockTime;
+    gDvmJit.numCompilerThreadBlockGC++;
+#endif
+    UPDATE_CODE_CACHE_PATCHES();
+
+    PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t));
+
+    /* Change the thread state back to VMWAIT */
+    dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT);
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * The following are used to keep compiled loads and stores from modifying
+ * memory during self verification mode.
+ *
+ * Stores do not modify memory. Instead, the address and value pair are stored
+ * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
+ * than a word, the word containing the address is loaded first before being
+ * updated.
+ *
+ * Loads check heapSpace first and return data from there if an entry exists.
+ * Otherwise, data is loaded from memory as usual.
+ */
+
+/* Used to specify sizes of memory operations */
+enum {
+    kSVByte,
+    kSVSignedByte,
+    kSVHalfword,
+    kSVSignedHalfword,
+    kSVWord,
+    kSVDoubleword,
+    kSVVariable,
+};
+
+/* Load the value of a decoded register from the stack */
+static int selfVerificationMemRegLoad(int* sp, int reg)
+{
+    return *(sp + reg);
+}
+
+/* Load the value of a decoded doubleword register from the stack */
+static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
+{
+    return *((s8*)(sp + reg));
+}
+
+/* Store the value of a decoded register out to the stack */
+static void selfVerificationMemRegStore(int* sp, int data, int reg)
+{
+    *(sp + reg) = data;
+}
+
+/* Store the value of a decoded doubleword register out to the stack */
+static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
+{
+    *((s8*)(sp + reg)) = data;
+}
+
+/*
+ * Load the specified size of data from the specified address, checking
+ * heapSpace first if Self Verification mode wrote to it previously, and
+ * falling back to actual memory otherwise.
+ */
+static int selfVerificationLoad(int addr, int size)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    ShadowHeap *heapSpacePtr;
+
+    int data;
+    int maskedAddr = addr & 0xFFFFFFFC;
+    int alignment = addr & 0x3;
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == maskedAddr) {
+            addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
+            break;
+        }
+    }
+
+    switch (size) {
+        case kSVByte:
+            data = *((u1*) addr);
+            break;
+        case kSVSignedByte:
+            data = *((s1*) addr);
+            break;
+        case kSVHalfword:
+            data = *((u2*) addr);
+            break;
+        case kSVSignedHalfword:
+            data = *((s2*) addr);
+            break;
+        case kSVWord:
+            data = *((u4*) addr);
+            break;
+        default:
+            LOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size);
+            data = 0;
+            dvmAbort();
+    }
+
+    //LOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size);
+    return data;
+}
+
+/* Like selfVerificationLoad, but specifically for doublewords */
+static s8 selfVerificationLoadDoubleword(int addr)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace* shadowSpace = self->shadowSpace;
+    ShadowHeap* heapSpacePtr;
+
+    int addr2 = addr+4;
+    unsigned int data = *((unsigned int*) addr);
+    unsigned int data2 = *((unsigned int*) addr2);
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == addr) {
+            data = heapSpacePtr->data;
+        } else if (heapSpacePtr->addr == addr2) {
+            data2 = heapSpacePtr->data;
+        }
+    }
+
+    //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x",
+    //    addr, data, data2);
+    return (((s8) data2) << 32) | data;
+}
+
+/*
+ * Handles a store of a specified size of data to a specified address.
+ * This gets logged as an addr/data pair in heapSpace instead of modifying
+ * memory.  Addresses in heapSpace are unique, and accesses smaller than a
+ * word pull the entire word from memory first before updating.
+ */
+static void selfVerificationStore(int addr, int data, int size)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    ShadowHeap *heapSpacePtr;
+
+    int maskedAddr = addr & 0xFFFFFFFC;
+    int alignment = addr & 0x3;
+
+    //LOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size);
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == maskedAddr) break;
+    }
+
+    if (heapSpacePtr == shadowSpace->heapSpaceTail) {
+        heapSpacePtr->addr = maskedAddr;
+        heapSpacePtr->data = *((unsigned int*) maskedAddr);
+        shadowSpace->heapSpaceTail++;
+    }
+
+    addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
+    switch (size) {
+        case kSVByte:
+            *((u1*) addr) = data;
+            break;
+        case kSVSignedByte:
+            *((s1*) addr) = data;
+            break;
+        case kSVHalfword:
+            *((u2*) addr) = data;
+            break;
+        case kSVSignedHalfword:
+            *((s2*) addr) = data;
+            break;
+        case kSVWord:
+            *((u4*) addr) = data;
+            break;
+        default:
+            LOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size);
+            dvmAbort();
+    }
+}
+
+/* Like selfVerificationStore, but specifically for doublewords */
+static void selfVerificationStoreDoubleword(int addr, s8 double_data)
+{
+    Thread *self = dvmThreadSelf();
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    ShadowHeap *heapSpacePtr;
+
+    int addr2 = addr+4;
+    int data = double_data;
+    int data2 = double_data >> 32;
+    bool store1 = false, store2 = false;
+
+    //LOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x",
+    //    addr, data, data2);
+
+    for (heapSpacePtr = shadowSpace->heapSpace;
+         heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+        if (heapSpacePtr->addr == addr) {
+            heapSpacePtr->data = data;
+            store1 = true;
+        } else if (heapSpacePtr->addr == addr2) {
+            heapSpacePtr->data = data2;
+            store2 = true;
+        }
+    }
+
+    if (!store1) {
+        shadowSpace->heapSpaceTail->addr = addr;
+        shadowSpace->heapSpaceTail->data = data;
+        shadowSpace->heapSpaceTail++;
+    }
+    if (!store2) {
+        shadowSpace->heapSpaceTail->addr = addr2;
+        shadowSpace->heapSpaceTail->data = data2;
+        shadowSpace->heapSpaceTail++;
+    }
+}
+
+/*
+ * Decodes the memory instruction at the address specified in the link
+ * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored
+ * consecutively on the stack beginning at the specified stack pointer.
+ * Calls the proper Self Verification handler for the memory instruction and
+ * updates the link register to point past the decoded memory instruction.
+ */
+void dvmSelfVerificationMemOpDecode(int lr, int* sp)
+{
+    enum {
+        kMemOpLdrPcRel = 0x09, // ldr(3)  [01001] rd[10..8] imm_8[7..0]
+        kMemOpRRR      = 0x0A, // Full opcode is 7 bits
+        kMemOp2Single  = 0x0A, // Used for Vstrs and Vldrs
+        kMemOpRRR2     = 0x0B, // Full opcode is 7 bits
+        kMemOp2Double  = 0x0B, // Used for Vstrd and Vldrd
+        kMemOpStrRRI5  = 0x0C, // str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrRRI5  = 0x0D, // ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0]
+        kMemOpLdrSpRel = 0x13, // ldr(4)  [10011] rd[10..8] imm_8[7..0]
+        kMemOpStmia    = 0x18, // stmia   [11000] rn[10..8] reglist [7..0]
+        kMemOpLdmia    = 0x19, // ldmia   [11001] rn[10..8] reglist [7..0]
+        kMemOpStrRRR   = 0x28, // str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpStrhRRR  = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpStrbRRR  = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrsbRRR = 0x2B, // ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrRRR   = 0x2C, // ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrhRRR  = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrbRRR  = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0]
+        kMemOpLdrshRRR = 0x2F, // ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0]
+        kMemOp2Stmia   = 0xE88, // stmia  [111010001000[ rn[19..16] mask[15..0]
+        kMemOp2Ldmia   = 0xE89, // ldmia  [111010001001[ rn[19..16] mask[15..0]
+        kMemOp2Stmia2  = 0xE8A, // stmia  [111010001010[ rn[19..16] mask[15..0]
+        kMemOp2Ldmia2  = 0xE8B, // ldmia  [111010001011[ rn[19..16] mask[15..0]
+        kMemOp2Vstr    = 0xED8, // Used for Vstrs and Vstrd
+        kMemOp2Vldr    = 0xED9, // Used for Vldrs and Vldrd
+        kMemOp2Vstr2   = 0xEDC, // Used for Vstrs and Vstrd
+        kMemOp2Vldr2   = 0xEDD, // Used for Vstrs and Vstrd
+        kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2StrRRR  = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrRRR  = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+                                       rn[19..16] rt[15..12] imm12[11..0] */
+        kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101]
+                                       rn[19..16] rt[15..12] imm12[11..0] */
+        kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011]
+                                rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
+        kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011]
+                                       rt[15..12] rn[19..16] imm12[11..0] */
+        kMemOp2        = 0xE000, // top 3 bits set indicates Thumb2
+    };
+
+    int addr, offset, data;
+    long long double_data;
+    int size = kSVWord;
+    bool store = false;
+    unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
+    unsigned int insn = *lr_masked;
+
+    int old_lr;
+    old_lr = selfVerificationMemRegLoad(sp, 13);
+
+    if ((insn & kMemOp2) == kMemOp2) {
+        insn = (insn << 16) | (insn >> 16);
+        //LOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn);
+
+        int opcode12 = (insn >> 20) & 0xFFF;
+        int opcode4 = (insn >> 8) & 0xF;
+        int imm2 = (insn >> 4) & 0x3;
+        int imm8 = insn & 0xFF;
+        int imm12 = insn & 0xFFF;
+        int rd = (insn >> 12) & 0xF;
+        int rm = insn & 0xF;
+        int rn = (insn >> 16) & 0xF;
+        int rt = (insn >> 12) & 0xF;
+        bool wBack = true;
+
+        // Update the link register
+        selfVerificationMemRegStore(sp, old_lr+4, 13);
+
+        // Determine whether the mem op is a store or load
+        switch (opcode12) {
+            case kMemOp2Stmia:
+            case kMemOp2Stmia2:
+            case kMemOp2Vstr:
+            case kMemOp2Vstr2:
+            case kMemOp2StrbRRR:
+            case kMemOp2StrhRRR:
+            case kMemOp2StrRRR:
+            case kMemOp2StrbRRI12:
+            case kMemOp2StrhRRI12:
+            case kMemOp2StrRRI12:
+                store = true;
+        }
+
+        // Determine the size of the mem access
+        switch (opcode12) {
+            case kMemOp2StrbRRR:
+            case kMemOp2LdrbRRR:
+            case kMemOp2StrbRRI12:
+            case kMemOp2LdrbRRI12:
+                size = kSVByte;
+                break;
+            case kMemOp2LdrsbRRR:
+            case kMemOp2LdrsbRRI12:
+                size = kSVSignedByte;
+                break;
+            case kMemOp2StrhRRR:
+            case kMemOp2LdrhRRR:
+            case kMemOp2StrhRRI12:
+            case kMemOp2LdrhRRI12:
+                size = kSVHalfword;
+                break;
+            case kMemOp2LdrshRRR:
+            case kMemOp2LdrshRRI12:
+                size = kSVSignedHalfword;
+                break;
+            case kMemOp2Vstr:
+            case kMemOp2Vstr2:
+            case kMemOp2Vldr:
+            case kMemOp2Vldr2:
+                if (opcode4 == kMemOp2Double) size = kSVDoubleword;
+                break;
+            case kMemOp2Stmia:
+            case kMemOp2Ldmia:
+            case kMemOp2Stmia2:
+            case kMemOp2Ldmia2:
+                size = kSVVariable;
+                break;
+        }
+
+        // Load the value of the address
+        addr = selfVerificationMemRegLoad(sp, rn);
+
+        // Figure out the offset
+        switch (opcode12) {
+            case kMemOp2Vstr:
+            case kMemOp2Vstr2:
+            case kMemOp2Vldr:
+            case kMemOp2Vldr2:
+                offset = imm8 << 2;
+                if (opcode4 == kMemOp2Single) {
+                    rt = rd << 1;
+                    if (insn & 0x400000) rt |= 0x1;
+                } else if (opcode4 == kMemOp2Double) {
+                    if (insn & 0x400000) rt |= 0x10;
+                    rt = rt << 1;
+                } else {
+                    LOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4);
+                    dvmAbort();
+                }
+                rt += 14;
+                break;
+            case kMemOp2StrbRRR:
+            case kMemOp2LdrbRRR:
+            case kMemOp2StrhRRR:
+            case kMemOp2LdrhRRR:
+            case kMemOp2StrRRR:
+            case kMemOp2LdrRRR:
+            case kMemOp2LdrsbRRR:
+            case kMemOp2LdrshRRR:
+                offset = selfVerificationMemRegLoad(sp, rm) << imm2;
+                break;
+            case kMemOp2StrbRRI12:
+            case kMemOp2LdrbRRI12:
+            case kMemOp2StrhRRI12:
+            case kMemOp2LdrhRRI12:
+            case kMemOp2StrRRI12:
+            case kMemOp2LdrRRI12:
+            case kMemOp2LdrsbRRI12:
+            case kMemOp2LdrshRRI12:
+                offset = imm12;
+                break;
+            case kMemOp2Stmia:
+            case kMemOp2Ldmia:
+                wBack = false;
+            case kMemOp2Stmia2:
+            case kMemOp2Ldmia2:
+                offset = 0;
+                break;
+            default:
+                LOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12);
+                offset = 0;
+                dvmAbort();
+        }
+
+        // Handle the decoded mem op accordingly
+        if (store) {
+            if (size == kSVVariable) {
+                LOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)");
+                int i;
+                int regList = insn & 0xFFFF;
+                for (i = 0; i < 16; i++) {
+                    if (regList & 0x1) {
+                        data = selfVerificationMemRegLoad(sp, i);
+                        selfVerificationStore(addr, data, kSVWord);
+                        addr += 4;
+                    }
+                    regList = regList >> 1;
+                }
+                if (wBack) selfVerificationMemRegStore(sp, addr, rn);
+            } else if (size == kSVDoubleword) {
+                double_data = selfVerificationMemRegLoadDouble(sp, rt);
+                selfVerificationStoreDoubleword(addr+offset, double_data);
+            } else {
+                data = selfVerificationMemRegLoad(sp, rt);
+                selfVerificationStore(addr+offset, data, size);
+            }
+        } else {
+            if (size == kSVVariable) {
+                LOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)");
+                int i;
+                int regList = insn & 0xFFFF;
+                for (i = 0; i < 16; i++) {
+                    if (regList & 0x1) {
+                        data = selfVerificationLoad(addr, kSVWord);
+                        selfVerificationMemRegStore(sp, data, i);
+                        addr += 4;
+                    }
+                    regList = regList >> 1;
+                }
+                if (wBack) selfVerificationMemRegStore(sp, addr, rn);
+            } else if (size == kSVDoubleword) {
+                double_data = selfVerificationLoadDoubleword(addr+offset);
+                selfVerificationMemRegStoreDouble(sp, double_data, rt);
+            } else {
+                data = selfVerificationLoad(addr+offset, size);
+                selfVerificationMemRegStore(sp, data, rt);
+            }
+        }
+    } else {
+        //LOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn);
+
+        // Update the link register
+        selfVerificationMemRegStore(sp, old_lr+2, 13);
+
+        int opcode5 = (insn >> 11) & 0x1F;
+        int opcode7 = (insn >> 9) & 0x7F;
+        int imm = (insn >> 6) & 0x1F;
+        int rd = (insn >> 8) & 0x7;
+        int rm = (insn >> 6) & 0x7;
+        int rn = (insn >> 3) & 0x7;
+        int rt = insn & 0x7;
+
+        // Determine whether the mem op is a store or load
+        switch (opcode5) {
+            case kMemOpRRR:
+                switch (opcode7) {
+                    case kMemOpStrRRR:
+                    case kMemOpStrhRRR:
+                    case kMemOpStrbRRR:
+                        store = true;
+                }
+                break;
+            case kMemOpStrRRI5:
+            case kMemOpStrbRRI5:
+            case kMemOpStrhRRI5:
+            case kMemOpStmia:
+                store = true;
+        }
+
+        // Determine the size of the mem access
+        switch (opcode5) {
+            case kMemOpRRR:
+            case kMemOpRRR2:
+                switch (opcode7) {
+                    case kMemOpStrbRRR:
+                    case kMemOpLdrbRRR:
+                        size = kSVByte;
+                        break;
+                    case kMemOpLdrsbRRR:
+                        size = kSVSignedByte;
+                        break;
+                    case kMemOpStrhRRR:
+                    case kMemOpLdrhRRR:
+                        size = kSVHalfword;
+                        break;
+                    case kMemOpLdrshRRR:
+                        size = kSVSignedHalfword;
+                        break;
+                }
+                break;
+            case kMemOpStrbRRI5:
+            case kMemOpLdrbRRI5:
+                size = kSVByte;
+                break;
+            case kMemOpStrhRRI5:
+            case kMemOpLdrhRRI5:
+                size = kSVHalfword;
+                break;
+            case kMemOpStmia:
+            case kMemOpLdmia:
+                size = kSVVariable;
+                break;
+        }
+
+        // Load the value of the address
+        if (opcode5 == kMemOpLdrPcRel)
+            addr = selfVerificationMemRegLoad(sp, 4);
+        else if (opcode5 == kMemOpStmia || opcode5 == kMemOpLdmia)
+            addr = selfVerificationMemRegLoad(sp, rd);
+        else
+            addr = selfVerificationMemRegLoad(sp, rn);
+
+        // Figure out the offset
+        switch (opcode5) {
+            case kMemOpLdrPcRel:
+                offset = (insn & 0xFF) << 2;
+                rt = rd;
+                break;
+            case kMemOpRRR:
+            case kMemOpRRR2:
+                offset = selfVerificationMemRegLoad(sp, rm);
+                break;
+            case kMemOpStrRRI5:
+            case kMemOpLdrRRI5:
+                offset = imm << 2;
+                break;
+            case kMemOpStrhRRI5:
+            case kMemOpLdrhRRI5:
+                offset = imm << 1;
+                break;
+            case kMemOpStrbRRI5:
+            case kMemOpLdrbRRI5:
+                offset = imm;
+                break;
+            case kMemOpStmia:
+            case kMemOpLdmia:
+                offset = 0;
+                break;
+            default:
+                LOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5);
+                offset = 0;
+                dvmAbort();
+        }
+
+        // Handle the decoded mem op accordingly
+        if (store) {
+            if (size == kSVVariable) {
+                int i;
+                int regList = insn & 0xFF;
+                for (i = 0; i < 8; i++) {
+                    if (regList & 0x1) {
+                        data = selfVerificationMemRegLoad(sp, i);
+                        selfVerificationStore(addr, data, kSVWord);
+                        addr += 4;
+                    }
+                    regList = regList >> 1;
+                }
+                selfVerificationMemRegStore(sp, addr, rd);
+            } else {
+                data = selfVerificationMemRegLoad(sp, rt);
+                selfVerificationStore(addr+offset, data, size);
+            }
+        } else {
+            if (size == kSVVariable) {
+                bool wBack = true;
+                int i;
+                int regList = insn & 0xFF;
+                for (i = 0; i < 8; i++) {
+                    if (regList & 0x1) {
+                        if (i == rd) wBack = false;
+                        data = selfVerificationLoad(addr, kSVWord);
+                        selfVerificationMemRegStore(sp, data, i);
+                        addr += 4;
+                    }
+                    regList = regList >> 1;
+                }
+                if (wBack) selfVerificationMemRegStore(sp, addr, rd);
+            } else {
+                data = selfVerificationLoad(addr+offset, size);
+                selfVerificationMemRegStore(sp, data, rt);
+            }
+        }
+    }
+}
+#endif
diff --git a/vm/compiler/codegen/arm/CalloutHelper.h b/vm/compiler/codegen/arm/CalloutHelper.h
new file mode 100644
index 0000000..cc4c0ae
--- /dev/null
+++ b/vm/compiler/codegen/arm/CalloutHelper.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_ARM_CALLOUT_HELPER_H_
+#define DALVIK_VM_COMPILER_CODEGEN_ARM_CALLOUT_HELPER_H_
+
+#include "Dalvik.h"
+
+/*
+ * Declare/comment prototypes of all native callout functions invoked by the
+ * JIT'ed code here and use the LOAD_FUNC_ADDR macro to load the address into
+ * a register. In this way we have a centralized place to find out all native
+ * helper functions and we can grep for LOAD_FUNC_ADDR to find out all the
+ * callsites.
+ */
+
+/* Load a statically compiled function address as a constant */
+#define LOAD_FUNC_ADDR(cUnit, reg, addr) loadConstant(cUnit, reg, addr)
+
+/* Conversions */
+extern "C" float __aeabi_i2f(int op1);             // OP_INT_TO_FLOAT
+extern "C" int __aeabi_f2iz(float op1);            // OP_FLOAT_TO_INT
+extern "C" float __aeabi_d2f(double op1);          // OP_DOUBLE_TO_FLOAT
+extern "C" double __aeabi_f2d(float op1);          // OP_FLOAT_TO_DOUBLE
+extern "C" double __aeabi_i2d(int op1);            // OP_INT_TO_DOUBLE
+extern "C" int __aeabi_d2iz(double op1);           // OP_DOUBLE_TO_INT
+extern "C" float __aeabi_l2f(long op1);            // OP_LONG_TO_FLOAT
+extern "C" double __aeabi_l2d(long op1);           // OP_LONG_TO_DOUBLE
+s8 dvmJitf2l(float op1);                // OP_FLOAT_TO_LONG
+s8 dvmJitd2l(double op1);               // OP_DOUBLE_TO_LONG
+
+/* Single-precision FP arithmetics */
+extern "C" float __aeabi_fadd(float a, float b);   // OP_ADD_FLOAT[_2ADDR]
+extern "C" float __aeabi_fsub(float a, float b);   // OP_SUB_FLOAT[_2ADDR]
+extern "C" float __aeabi_fdiv(float a, float b);   // OP_DIV_FLOAT[_2ADDR]
+extern "C" float __aeabi_fmul(float a, float b);   // OP_MUL_FLOAT[_2ADDR]
+extern "C" float fmodf(float a, float b);          // OP_REM_FLOAT[_2ADDR]
+
+/* Double-precision FP arithmetics */
+extern "C" double __aeabi_dadd(double a, double b); // OP_ADD_DOUBLE[_2ADDR]
+extern "C" double __aeabi_dsub(double a, double b); // OP_SUB_DOUBLE[_2ADDR]
+extern "C" double __aeabi_ddiv(double a, double b); // OP_DIV_DOUBLE[_2ADDR]
+extern "C" double __aeabi_dmul(double a, double b); // OP_MUL_DOUBLE[_2ADDR]
+extern "C" double fmod(double a, double b);         // OP_REM_DOUBLE[_2ADDR]
+
+/* Integer arithmetics */
+extern "C" int __aeabi_idivmod(int op1, int op2);  // OP_REM_INT[_2ADDR|_LIT8|_LIT16]
+extern "C" int __aeabi_idiv(int op1, int op2);     // OP_DIV_INT[_2ADDR|_LIT8|_LIT16]
+
+/* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
+extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
+
+/* Originally declared in Sync.h */
+bool dvmUnlockObject(struct Thread* self, struct Object* obj); //OP_MONITOR_EXIT
+
+/* Originally declared in oo/TypeCheck.h */
+bool dvmCanPutArrayElement(const ClassObject* elemClass,   // OP_APUT_OBJECT
+                           const ClassObject* arrayClass);
+int dvmInstanceofNonTrivial(const ClassObject* instance,   // OP_CHECK_CAST &&
+                            const ClassObject* clazz);     // OP_INSTANCE_OF
+
+/* Originally declared in oo/Array.h */
+ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass, // OP_NEW_ARRAY
+                                  size_t length, int allocFlags);
+
+/* Originally declared in interp/InterpDefs.h */
+bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
+                                  const u2* arrayData);
+
+/* Originally declared in compiler/codegen/arm/Assemble.c */
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+                                          Thread *self,
+                                          PredictedChainingCell *cell,
+                                          const ClassObject *clazz);
+
+/*
+ * Switch dispatch offset calculation for OP_PACKED_SWITCH & OP_SPARSE_SWITCH
+ * Used in CodegenDriver.c
+ * static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc);
+ * static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc);
+ */
+
+/*
+ * Resolve interface callsites - OP_INVOKE_INTERFACE & OP_INVOKE_INTERFACE_RANGE
+ *
+ * Originally declared in mterp/common/FindInterface.h and only comment it here
+ * due to the INLINE attribute.
+ *
+ * INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
+ *  u4 methodIdx, const Method* method, DvmDex* methodClassDex)
+ */
+
+/* Originally declared in alloc/Alloc.h */
+Object* dvmAllocObject(ClassObject* clazz, int flags);  // OP_NEW_INSTANCE
+
+/*
+ * Functions declared in gDvmInlineOpsTable[] are used for
+ * OP_EXECUTE_INLINE & OP_EXECUTE_INLINE_RANGE.
+ */
+extern "C" double sqrt(double x);  // INLINE_MATH_SQRT
+
+/*
+ * The following functions are invoked through the compiler templates (declared
+ * in compiler/template/armv5te/footer.S:
+ *
+ *      __aeabi_cdcmple         // CMPG_DOUBLE
+ *      __aeabi_cfcmple         // CMPG_FLOAT
+ *      dvmLockObject           // MONITOR_ENTER
+ */
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_CALLOUT_HELPER_H_
diff --git a/vm/compiler/codegen/arm/Codegen.h b/vm/compiler/codegen/arm/Codegen.h
new file mode 100644
index 0000000..e67f3d8
--- /dev/null
+++ b/vm/compiler/codegen/arm/Codegen.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerIR.h"
+#include "CalloutHelper.h"
+
+#if defined(_CODEGEN_C)
+/*
+ * loadConstant() sometimes needs to add a small imm to a pre-existing constant
+ */
+static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int value);
+static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2);
+
+/* Forward decalraton the portable versions due to circular dependency */
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+                                    RegLocation rlDest, RegLocation rlSrc1,
+                                    RegLocation rlSrc2);
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+                                     RegLocation rlDest, RegLocation rlSrc1,
+                                     RegLocation rlSrc2);
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
+
+#if defined(__ARM_ARCH_5__)
+static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir);
+#endif
+
+static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir);
+
+#endif
+
+
+#if defined(WITH_SELF_VERIFICATION)
+/* Self Verification memory instruction decoder */
+extern "C" void dvmSelfVerificationMemOpDecode(int lr, int* sp);
+#endif
+
+extern void dvmCompilerSetupResourceMasks(ArmLIR *lir);
+
+extern ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest,
+                                          int rSrc);
diff --git a/vm/compiler/codegen/arm/CodegenCommon.cpp b/vm/compiler/codegen/arm/CodegenCommon.cpp
new file mode 100644
index 0000000..ae41fe9
--- /dev/null
+++ b/vm/compiler/codegen/arm/CodegenCommon.cpp
@@ -0,0 +1,447 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen and support common to all supported
+ * ARM variants.  It is included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+#include "compiler/Loop.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[kNumPackedOpcodes];
+
+static void setMemRefType(ArmLIR *lir, bool isLoad, int memType)
+{
+    u8 *maskPtr;
+    u8 mask = ENCODE_MEM;;
+    assert(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
+    if (isLoad) {
+        maskPtr = &lir->useMask;
+    } else {
+        maskPtr = &lir->defMask;
+    }
+    /* Clear out the memref flags */
+    *maskPtr &= ~mask;
+    /* ..and then add back the one we need */
+    switch(memType) {
+        case kLiteral:
+            assert(isLoad);
+            *maskPtr |= ENCODE_LITERAL;
+            break;
+        case kDalvikReg:
+            *maskPtr |= ENCODE_DALVIK_REG;
+            break;
+        case kHeapRef:
+            *maskPtr |= ENCODE_HEAP_REF;
+            break;
+        case kMustNotAlias:
+            /* Currently only loads can be marked as kMustNotAlias */
+            assert(!(EncodingMap[lir->opcode].flags & IS_STORE));
+            *maskPtr |= ENCODE_MUST_NOT_ALIAS;
+            break;
+        default:
+            LOGE("Jit: invalid memref kind - %d", memType);
+            assert(0);  // Bail if debug build, set worst-case in the field
+            *maskPtr |= ENCODE_ALL;
+    }
+}
+
+/*
+ * Mark load/store instructions that access Dalvik registers through r5FP +
+ * offset.
+ */
+static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
+{
+    setMemRefType(lir, isLoad, kDalvikReg);
+
+    /*
+     * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
+     * access.
+     */
+    lir->aliasInfo = regId;
+    if (DOUBLEREG(lir->operands[0])) {
+        lir->aliasInfo |= 0x80000000;
+    }
+}
+
+/*
+ * Decode the register id.
+ */
+static inline u8 getRegMaskCommon(int reg)
+{
+    u8 seed;
+    int shift;
+    int regId = reg & 0x1f;
+
+    /*
+     * Each double register is equal to a pair of single-precision FP registers
+     */
+    seed = DOUBLEREG(reg) ? 3 : 1;
+    /* FP register starts at bit position 16 */
+    shift = FPREG(reg) ? kFPReg0 : 0;
+    /* Expand the double register id into single offset */
+    shift += regId;
+    return (seed << shift);
+}
+
+/* External version of getRegMaskCommon */
+u8 dvmGetRegResourceMask(int reg)
+{
+    return getRegMaskCommon(reg);
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+static inline void setupRegMask(u8 *mask, int reg)
+{
+    *mask |= getRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+static void setupResourceMasks(ArmLIR *lir)
+{
+    int opcode = lir->opcode;
+    int flags;
+
+    if (opcode <= 0) {
+        lir->useMask = lir->defMask = 0;
+        return;
+    }
+
+    flags = EncodingMap[lir->opcode].flags;
+
+    /* Set up the mask for resources that are updated */
+    if (flags & (IS_LOAD | IS_STORE)) {
+        /* Default to heap - will catch specialized classes later */
+        setMemRefType(lir, flags & IS_LOAD, kHeapRef);
+    }
+
+    /*
+     * Conservatively assume the branch here will call out a function that in
+     * turn will trash everything.
+     */
+    if (flags & IS_BRANCH) {
+        lir->defMask = lir->useMask = ENCODE_ALL;
+        return;
+    }
+
+    if (flags & REG_DEF0) {
+        setupRegMask(&lir->defMask, lir->operands[0]);
+    }
+
+    if (flags & REG_DEF1) {
+        setupRegMask(&lir->defMask, lir->operands[1]);
+    }
+
+    if (flags & REG_DEF_SP) {
+        lir->defMask |= ENCODE_REG_SP;
+    }
+
+    if (flags & REG_DEF_LR) {
+        lir->defMask |= ENCODE_REG_LR;
+    }
+
+    if (flags & REG_DEF_LIST0) {
+        lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
+    }
+
+    if (flags & REG_DEF_LIST1) {
+        lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
+    }
+
+    if (flags & SETS_CCODES) {
+        lir->defMask |= ENCODE_CCODE;
+    }
+
+    /* Conservatively treat the IT block */
+    if (flags & IS_IT) {
+        lir->defMask = ENCODE_ALL;
+    }
+
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+        int i;
+
+        for (i = 0; i < 4; i++) {
+            if (flags & (1 << (kRegUse0 + i))) {
+                setupRegMask(&lir->useMask, lir->operands[i]);
+            }
+        }
+    }
+
+    if (flags & REG_USE_PC) {
+        lir->useMask |= ENCODE_REG_PC;
+    }
+
+    if (flags & REG_USE_SP) {
+        lir->useMask |= ENCODE_REG_SP;
+    }
+
+    if (flags & REG_USE_LIST0) {
+        lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
+    }
+
+    if (flags & REG_USE_LIST1) {
+        lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
+    }
+
+    if (flags & USES_CCODES) {
+        lir->useMask |= ENCODE_CCODE;
+    }
+
+    /* Fixup for kThumbPush/lr and kThumbPop/pc */
+    if (opcode == kThumbPush || opcode == kThumbPop) {
+        u8 r8Mask = getRegMaskCommon(r8);
+        if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
+            lir->useMask &= ~r8Mask;
+            lir->useMask |= ENCODE_REG_LR;
+        } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
+            lir->defMask &= ~r8Mask;
+            lir->defMask |= ENCODE_REG_PC;
+        }
+    }
+}
+
+/*
+ * Set up the accurate resource mask for branch instructions
+ */
+static void relaxBranchMasks(ArmLIR *lir)
+{
+    int flags = EncodingMap[lir->opcode].flags;
+
+    /* Make sure only branch instructions are passed here */
+    assert(flags & IS_BRANCH);
+
+    lir->useMask = lir->defMask = ENCODE_REG_PC;
+
+    if (flags & REG_DEF_LR) {
+        lir->defMask |= ENCODE_REG_LR;
+    }
+
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+        int i;
+
+        for (i = 0; i < 4; i++) {
+            if (flags & (1 << (kRegUse0 + i))) {
+                setupRegMask(&lir->useMask, lir->operands[i]);
+            }
+        }
+    }
+
+    if (flags & USES_CCODES) {
+        lir->useMask |= ENCODE_CCODE;
+    }
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpcode opcode)
+{
+    ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    assert(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
+    insn->opcode = opcode;
+    setupResourceMasks(insn);
+    dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpcode opcode,
+                           int dest)
+{
+    ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    assert(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    setupResourceMasks(insn);
+    dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpcode opcode,
+                           int dest, int src1)
+{
+    ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    assert(isPseudoOpcode(opcode) ||
+           (EncodingMap[opcode].flags & IS_BINARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    setupResourceMasks(insn);
+    dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpcode opcode,
+                           int dest, int src1, int src2)
+{
+    ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
+        LOGE("Bad LIR3: %s[%d]",EncodingMap[opcode].name,opcode);
+    }
+    assert(isPseudoOpcode(opcode) ||
+           (EncodingMap[opcode].flags & IS_TERTIARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    insn->operands[2] = src2;
+    setupResourceMasks(insn);
+    dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
+static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpcode opcode,
+                           int dest, int src1, int src2, int info)
+{
+    ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    assert(isPseudoOpcode(opcode) ||
+           (EncodingMap[opcode].flags & IS_QUAD_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    insn->operands[2] = src2;
+    insn->operands[3] = info;
+    setupResourceMasks(insn);
+    dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+#endif
+
+/*
+ * If the next instruction is a move-result or move-result-long,
+ * return the target Dalvik sReg[s] and convert the next to a
+ * nop.  Otherwise, return INVALID_SREG.  Used to optimize method inlining.
+ */
+static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
+                                  bool fpHint)
+{
+    if (mir->next &&
+        ((mir->next->dalvikInsn.opcode == OP_MOVE_RESULT) ||
+         (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_OBJECT))) {
+        mir->next->dalvikInsn.opcode = OP_NOP;
+        return dvmCompilerGetDest(cUnit, mir->next, 0);
+    } else {
+        RegLocation res = LOC_DALVIK_RETURN_VAL;
+        res.fp = fpHint;
+        return res;
+    }
+}
+
+/*
+ * Search the existing constants in the literal pool for an exact or close match
+ * within specified delta (greater or equal to 0).
+ */
+static ArmLIR *scanLiteralPool(LIR *dataTarget, int value, unsigned int delta)
+{
+    while (dataTarget) {
+        if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
+            delta)
+            return (ArmLIR *) dataTarget;
+        dataTarget = dataTarget->next;
+    }
+    return NULL;
+}
+
+/*
+ * 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 ArmLIR *addWordData(CompilationUnit *cUnit, LIR **constantListP,
+                           int value)
+{
+    /* Add the constant to the literal pool */
+    if (constantListP) {
+        ArmLIR *newValue = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+        newValue->operands[0] = value;
+        newValue->generic.next = *constantListP;
+        *constantListP = (LIR *) newValue;
+        return newValue;
+    } else {
+        /* Add the constant in the middle of code stream */
+        newLIR1(cUnit, kArm16BitData, (value & 0xffff));
+        newLIR1(cUnit, kArm16BitData, (value >> 16));
+    }
+    return NULL;
+}
+
+static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
+                                      bool fpHint)
+{
+    if (mir->next &&
+        (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_WIDE)) {
+        mir->next->dalvikInsn.opcode = OP_NOP;
+        return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
+    } else {
+        RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
+        res.fp = fpHint;
+        return res;
+    }
+}
+
+
+/*
+ * Generate an kArmPseudoBarrier marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+    ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
+    /* Mark all resources as being clobbered */
+    barrier->defMask = -1;
+}
+
+/* Create the PC reconstruction slot if not already done */
+static ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
+                              ArmLIR *branch,
+                              ArmLIR *pcrLabel)
+{
+    /* Forget all def info (because we might rollback here.  Bug #2367397 */
+    dvmCompilerResetDefTracking(cUnit);
+
+    /* Set up the place holder to reconstruct this Dalvik PC */
+    if (pcrLabel == NULL) {
+        int dPC = (int) (cUnit->method->insns + dOffset);
+        pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+        pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+        pcrLabel->operands[0] = dPC;
+        pcrLabel->operands[1] = dOffset;
+        /* Insert the place holder to the growable list */
+        dvmInsertGrowableList(&cUnit->pcReconstructionList,
+                              (intptr_t) pcrLabel);
+    }
+    /* Branch to the PC reconstruction code */
+    branch->generic.target = (LIR *) pcrLabel;
+
+    /* Clear the conservative flags for branches that punt to the interpreter */
+    relaxBranchMasks(branch);
+
+    return pcrLabel;
+}
diff --git a/vm/compiler/codegen/arm/CodegenDriver.cpp b/vm/compiler/codegen/arm/CodegenDriver.cpp
new file mode 100644
index 0000000..85ecb78
--- /dev/null
+++ b/vm/compiler/codegen/arm/CodegenDriver.cpp
@@ -0,0 +1,4827 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen and support common to all supported
+ * ARM variants.  It is included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
+{
+    int regCardBase = dvmCompilerAllocTemp(cUnit);
+    int regCardNo = dvmCompilerAllocTemp(cUnit);
+    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
+    loadWordDisp(cUnit, r6SELF, offsetof(Thread, cardTable),
+                 regCardBase);
+    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+                     kUnsignedByte);
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR *)target;
+    dvmCompilerFreeTemp(cUnit, regCardBase);
+    dvmCompilerFreeTemp(cUnit, regCardNo);
+}
+
+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
+     */
+    RegLocation rlSrc;
+    RegLocation rlDest;
+    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+    if (srcSize == 1) {
+        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+        loadValueDirectFixed(cUnit, rlSrc, r0);
+    } else {
+        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+        loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
+    }
+    LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
+    opReg(cUnit, kOpBlx, r2);
+    dvmCompilerClobberCallRegs(cUnit);
+    if (tgtSize == 1) {
+        RegLocation rlResult;
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+        rlResult = dvmCompilerGetReturn(cUnit);
+        storeValue(cUnit, rlDest, rlResult);
+    } else {
+        RegLocation rlResult;
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+        rlResult = dvmCompilerGetReturnWide(cUnit);
+        storeValueWide(cUnit, rlDest, rlResult);
+    }
+    return false;
+}
+
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+                                    RegLocation rlDest, RegLocation rlSrc1,
+                                    RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    void* funct;
+
+    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: {
+            genNegFloat(cUnit, rlDest, rlSrc1);
+            return false;
+        }
+        default:
+            return true;
+    }
+    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+    loadValueDirectFixed(cUnit, rlSrc1, r0);
+    loadValueDirectFixed(cUnit, rlSrc2, r1);
+    LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
+    opReg(cUnit, kOpBlx, r2);
+    dvmCompilerClobberCallRegs(cUnit);
+    rlResult = dvmCompilerGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+                                     RegLocation rlDest, RegLocation rlSrc1,
+                                     RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    void* funct;
+
+    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*) (double (*)(double, double)) fmod;
+            break;
+        case OP_NEG_DOUBLE: {
+            genNegDouble(cUnit, rlDest, rlSrc1);
+            return false;
+        }
+        default:
+            return true;
+    }
+    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+    LOAD_FUNC_ADDR(cUnit, r14lr, (int)funct);
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+    opReg(cUnit, kOpBlx, r14lr);
+    dvmCompilerClobberCallRegs(cUnit);
+    rlResult = dvmCompilerGetReturnWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->usesLinkRegister = true;
+#endif
+    return false;
+}
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+
+    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*)dvmJitf2l, 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*)dvmJitd2l, 2, 2);
+        case OP_LONG_TO_DOUBLE:
+            return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
+        default:
+            return true;
+    }
+    return false;
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpcode opcode,
+                          int dest, int src1)
+{
+     ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+     insn->opcode = opcode;
+     insn->operands[0] = dest;
+     insn->operands[1] = src1;
+     setupResourceMasks(insn);
+     dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
+}
+
+/*
+ * Example where r14 (LR) is preserved around a heap access under
+ * self-verification mode in Thumb2:
+ *
+ * D/dalvikvm( 1538): 0x59414c5e (0026): ldr     r14, [r15pc, #220] <-hoisted
+ * D/dalvikvm( 1538): 0x59414c62 (002a): mla     r4, r0, r8, r4
+ * D/dalvikvm( 1538): 0x59414c66 (002e): adds    r3, r4, r3
+ * D/dalvikvm( 1538): 0x59414c6a (0032): push    <r5, r14>    ---+
+ * D/dalvikvm( 1538): 0x59414c6c (0034): blx_1   0x5940f494      |
+ * D/dalvikvm( 1538): 0x59414c6e (0036): blx_2   see above       <-MEM_OP_DECODE
+ * D/dalvikvm( 1538): 0x59414c70 (0038): ldr     r10, [r9, #0]   |
+ * D/dalvikvm( 1538): 0x59414c74 (003c): pop     <r5, r14>    ---+
+ * D/dalvikvm( 1538): 0x59414c78 (0040): mov     r11, r10
+ * D/dalvikvm( 1538): 0x59414c7a (0042): asr     r12, r11, #31
+ * D/dalvikvm( 1538): 0x59414c7e (0046): movs    r0, r2
+ * D/dalvikvm( 1538): 0x59414c80 (0048): movs    r1, r3
+ * D/dalvikvm( 1538): 0x59414c82 (004a): str     r2, [r5, #16]
+ * D/dalvikvm( 1538): 0x59414c84 (004c): mov     r2, r11
+ * D/dalvikvm( 1538): 0x59414c86 (004e): str     r3, [r5, #20]
+ * D/dalvikvm( 1538): 0x59414c88 (0050): mov     r3, r12
+ * D/dalvikvm( 1538): 0x59414c8a (0052): str     r11, [r5, #24]
+ * D/dalvikvm( 1538): 0x59414c8e (0056): str     r12, [r5, #28]
+ * D/dalvikvm( 1538): 0x59414c92 (005a): blx     r14             <-use of LR
+ *
+ */
+static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
+{
+    ArmLIR *thisLIR;
+    TemplateOpcode opcode = TEMPLATE_MEM_OP_DECODE;
+
+    for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
+         thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+        if (!thisLIR->flags.isNop && thisLIR->flags.insertWrapper) {
+            /*
+             * Push r5(FP) and r14(LR) onto stack. We need to make sure that
+             * SP is 8-byte aligned, and we use r5 as a temp to restore LR
+             * for Thumb-only target since LR cannot be directly accessed in
+             * Thumb mode. Another reason to choose r5 here is it is the Dalvik
+             * frame pointer and cannot be the target of the emulated heap
+             * load.
+             */
+            if (cUnit->usesLinkRegister) {
+                genSelfVerificationPreBranch(cUnit, thisLIR);
+            }
+
+            /* Branch to mem op decode template */
+            selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+            selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+
+            /* Restore LR */
+            if (cUnit->usesLinkRegister) {
+                genSelfVerificationPostBranch(cUnit, thisLIR);
+            }
+        }
+    }
+}
+#endif
+
+/* Generate conditional branch instructions */
+static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
+                                    ArmConditionCode cond,
+                                    ArmLIR *target)
+{
+    ArmLIR *branch = opCondBranch(cUnit, cond);
+    branch->generic.target = (LIR *) target;
+    return branch;
+}
+
+/* Generate a unconditional branch to go to the interpreter */
+static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
+                                  ArmLIR *pcrLabel)
+{
+    ArmLIR *branch = opNone(cUnit, kOpUncondBr);
+    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+}
+
+/* Load a wide field from an object instance */
+static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
+{
+    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    RegLocation rlResult;
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    int regPtr = dvmCompilerAllocTemp(cUnit);
+
+    assert(rlDest.wide);
+
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
+    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+
+    HEAP_ACCESS_SHADOW(true);
+    loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+    HEAP_ACCESS_SHADOW(false);
+
+    dvmCompilerFreeTemp(cUnit, regPtr);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+/* Store a wide field to an object instance */
+static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
+{
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    int regPtr;
+    rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
+    regPtr = dvmCompilerAllocTemp(cUnit);
+    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+
+    HEAP_ACCESS_SHADOW(true);
+    storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+    HEAP_ACCESS_SHADOW(false);
+
+    dvmCompilerFreeTemp(cUnit, regPtr);
+}
+
+/*
+ * Load a field from an object instance
+ *
+ */
+static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
+                    int fieldOffset, bool isVolatile)
+{
+    RegLocation rlResult;
+    RegisterClass regClass = dvmCompilerRegClassBySize(size);
+    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
+
+    HEAP_ACCESS_SHADOW(true);
+    loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+                 size, rlObj.sRegLow);
+    HEAP_ACCESS_SHADOW(false);
+    if (isVolatile) {
+        dvmCompilerGenMemBarrier(cUnit, kSY);
+    }
+
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+/*
+ * Store a field to an object instance
+ *
+ */
+static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
+                    int fieldOffset, bool isObject, bool isVolatile)
+{
+    RegisterClass regClass = dvmCompilerRegClassBySize(size);
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    rlSrc = loadValue(cUnit, rlSrc, regClass);
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
+
+    if (isVolatile) {
+        dvmCompilerGenMemBarrier(cUnit, kST);
+    }
+    HEAP_ACCESS_SHADOW(true);
+    storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
+    HEAP_ACCESS_SHADOW(false);
+    if (isVolatile) {
+        dvmCompilerGenMemBarrier(cUnit, kSY);
+    }
+    if (isObject) {
+        /* NOTE: marking card based on object head */
+        markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
+    }
+}
+
+
+/*
+ * Generate array load
+ */
+static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlDest, int scale)
+{
+    RegisterClass regClass = dvmCompilerRegClassBySize(size);
+    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
+    RegLocation rlResult;
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
+    int regPtr;
+
+    /* null object? */
+    ArmLIR * pcrLabel = NULL;
+
+    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
+                                rlArray.lowReg, mir->offset, NULL);
+    }
+
+    regPtr = dvmCompilerAllocTemp(cUnit);
+
+    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+        int regLen = dvmCompilerAllocTemp(cUnit);
+        /* Get len */
+        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
+        /* regPtr -> array data */
+        opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
+        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
+                       pcrLabel);
+        dvmCompilerFreeTemp(cUnit, regLen);
+    } else {
+        /* regPtr -> array data */
+        opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
+    }
+    if ((size == kLong) || (size == kDouble)) {
+        if (scale) {
+            int rNewIndex = dvmCompilerAllocTemp(cUnit);
+            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
+            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
+            dvmCompilerFreeTemp(cUnit, rNewIndex);
+        } else {
+            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
+        }
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
+
+        HEAP_ACCESS_SHADOW(true);
+        loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+        HEAP_ACCESS_SHADOW(false);
+
+        dvmCompilerFreeTemp(cUnit, regPtr);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else {
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
+
+        HEAP_ACCESS_SHADOW(true);
+        loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
+                        scale, size);
+        HEAP_ACCESS_SHADOW(false);
+
+        dvmCompilerFreeTemp(cUnit, regPtr);
+        storeValue(cUnit, rlDest, rlResult);
+    }
+}
+
+/*
+ * Generate array store
+ *
+ */
+static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlSrc, int scale)
+{
+    RegisterClass regClass = dvmCompilerRegClassBySize(size);
+    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
+
+    int regPtr;
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
+
+    if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
+        dvmCompilerClobber(cUnit, rlArray.lowReg);
+        regPtr = rlArray.lowReg;
+    } else {
+        regPtr = dvmCompilerAllocTemp(cUnit);
+        genRegCopy(cUnit, regPtr, rlArray.lowReg);
+    }
+
+    /* null object? */
+    ArmLIR * pcrLabel = NULL;
+
+    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
+                                mir->offset, NULL);
+    }
+
+    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+        int regLen = dvmCompilerAllocTemp(cUnit);
+        //NOTE: max live temps(4) here.
+        /* Get len */
+        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
+        /* regPtr -> array data */
+        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
+        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
+                       pcrLabel);
+        dvmCompilerFreeTemp(cUnit, regLen);
+    } else {
+        /* regPtr -> array data */
+        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
+    }
+    /* at this point, regPtr points to array, 2 live temps */
+    if ((size == kLong) || (size == kDouble)) {
+        //TODO: need specific wide routine that can handle fp regs
+        if (scale) {
+            int rNewIndex = dvmCompilerAllocTemp(cUnit);
+            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
+            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
+            dvmCompilerFreeTemp(cUnit, rNewIndex);
+        } else {
+            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
+        }
+        rlSrc = loadValueWide(cUnit, rlSrc, regClass);
+
+        HEAP_ACCESS_SHADOW(true);
+        storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+        HEAP_ACCESS_SHADOW(false);
+
+        dvmCompilerFreeTemp(cUnit, regPtr);
+    } else {
+        rlSrc = loadValue(cUnit, rlSrc, regClass);
+
+        HEAP_ACCESS_SHADOW(true);
+        storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
+                         scale, size);
+        HEAP_ACCESS_SHADOW(false);
+    }
+}
+
+/*
+ * Generate array object store
+ * Must use explicit register allocation here because of
+ * call-out to dvmCanPutArrayElement
+ */
+static void genArrayObjectPut(CompilationUnit *cUnit, MIR *mir,
+                              RegLocation rlArray, RegLocation rlIndex,
+                              RegLocation rlSrc, int scale)
+{
+    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
+
+    dvmCompilerFlushAllRegs(cUnit);
+
+    int regLen = r0;
+    int regPtr = r4PC;  /* Preserved across call */
+    int regArray = r1;
+    int regIndex = r7;  /* Preserved across call */
+
+    loadValueDirectFixed(cUnit, rlArray, regArray);
+    loadValueDirectFixed(cUnit, rlIndex, regIndex);
+
+    /* null object? */
+    ArmLIR * pcrLabel = NULL;
+
+    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, regArray,
+                                mir->offset, NULL);
+    }
+
+    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+        /* Get len */
+        loadWordDisp(cUnit, regArray, lenOffset, regLen);
+        /* regPtr -> array data */
+        opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
+        genBoundsCheck(cUnit, regIndex, regLen, mir->offset,
+                       pcrLabel);
+    } else {
+        /* regPtr -> array data */
+        opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
+    }
+
+    /* Get object to store */
+    loadValueDirectFixed(cUnit, rlSrc, r0);
+    LOAD_FUNC_ADDR(cUnit, r2, (int)dvmCanPutArrayElement);
+
+    /* Are we storing null?  If so, avoid check */
+    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
+
+    /* Make sure the types are compatible */
+    loadWordDisp(cUnit, regArray, offsetof(Object, clazz), r1);
+    loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
+    opReg(cUnit, kOpBlx, r2);
+    dvmCompilerClobberCallRegs(cUnit);
+
+    /*
+     * Using fixed registers here, and counting on r4 and r7 being
+     * preserved across the above call.  Tell the register allocation
+     * utilities about the regs we are using directly
+     */
+    dvmCompilerLockTemp(cUnit, regPtr);   // r4PC
+    dvmCompilerLockTemp(cUnit, regIndex); // r7
+    dvmCompilerLockTemp(cUnit, r0);
+    dvmCompilerLockTemp(cUnit, r1);
+
+    /* Bad? - roll back and re-execute if so */
+    genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel);
+
+    /* Resume here - must reload element & array, regPtr & index preserved */
+    loadValueDirectFixed(cUnit, rlSrc, r0);
+    loadValueDirectFixed(cUnit, rlArray, r1);
+
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR *) target;
+
+    HEAP_ACCESS_SHADOW(true);
+    storeBaseIndexed(cUnit, regPtr, regIndex, r0,
+                     scale, kWord);
+    HEAP_ACCESS_SHADOW(false);
+
+    dvmCompilerFreeTemp(cUnit, regPtr);
+    dvmCompilerFreeTemp(cUnit, regIndex);
+
+    /* NOTE: marking card here based on object head */
+    markCard(cUnit, r0, r1);
+}
+
+static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
+                           RegLocation rlDest, RegLocation rlSrc1,
+                           RegLocation rlShift)
+{
+    /*
+     * Don't mess with the regsiters here as there is a particular calling
+     * convention to the out-of-line handler.
+     */
+    RegLocation rlResult;
+
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirect(cUnit, rlShift, r2);
+    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;
+    }
+    rlResult = dvmCompilerGetReturnWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
+                           RegLocation rlDest, RegLocation rlSrc1,
+                           RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    OpKind firstOp = kOpBkpt;
+    OpKind secondOp = kOpBkpt;
+    bool callOut = false;
+    void *callTgt;
+    int retReg = r0;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_NOT_LONG:
+            rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
+            opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
+            storeValueWide(cUnit, rlDest, rlResult);
+            return false;
+            break;
+        case OP_ADD_LONG:
+        case OP_ADD_LONG_2ADDR:
+            firstOp = kOpAdd;
+            secondOp = kOpAdc;
+            break;
+        case OP_SUB_LONG:
+        case OP_SUB_LONG_2ADDR:
+            firstOp = kOpSub;
+            secondOp = kOpSbc;
+            break;
+        case OP_MUL_LONG:
+        case OP_MUL_LONG_2ADDR:
+            genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
+            return false;
+        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_2ADDR:
+        case OP_AND_LONG:
+            firstOp = kOpAnd;
+            secondOp = kOpAnd;
+            break;
+        case OP_OR_LONG:
+        case OP_OR_LONG_2ADDR:
+            firstOp = kOpOr;
+            secondOp = kOpOr;
+            break;
+        case OP_XOR_LONG:
+        case OP_XOR_LONG_2ADDR:
+            firstOp = kOpXor;
+            secondOp = kOpXor;
+            break;
+        case OP_NEG_LONG: {
+            //TUNING: can improve this using Thumb2 code
+            int tReg = dvmCompilerAllocTemp(cUnit);
+            rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantNoClobber(cUnit, tReg, 0);
+            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+                        tReg, rlSrc2.lowReg);
+            opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
+            genRegCopy(cUnit, rlResult.highReg, tReg);
+            storeValueWide(cUnit, rlDest, rlResult);
+            return false;
+        }
+        default:
+            LOGE("Invalid long arith op");
+            dvmCompilerAbort(cUnit);
+    }
+    if (!callOut) {
+        genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
+    } else {
+        // Adjust return regs in to handle case of rem returning r2/r3
+        dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+        loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+        LOAD_FUNC_ADDR(cUnit, r14lr, (int) callTgt);
+        loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+        opReg(cUnit, kOpBlx, r14lr);
+        dvmCompilerClobberCallRegs(cUnit);
+        if (retReg == r0)
+            rlResult = dvmCompilerGetReturnWide(cUnit);
+        else
+            rlResult = dvmCompilerGetReturnWideAlt(cUnit);
+        storeValueWide(cUnit, rlDest, rlResult);
+#if defined(WITH_SELF_VERIFICATION)
+        cUnit->usesLinkRegister = true;
+#endif
+    }
+    return false;
+}
+
+static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
+                          RegLocation rlDest, RegLocation rlSrc1,
+                          RegLocation rlSrc2)
+{
+    OpKind op = kOpBkpt;
+    bool callOut = false;
+    bool checkZero = false;
+    bool unary = false;
+    int retReg = r0;
+    int (*callTgt)(int, int);
+    RegLocation rlResult;
+    bool shiftOp = false;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_NEG_INT:
+            op = kOpNeg;
+            unary = true;
+            break;
+        case OP_NOT_INT:
+            op = kOpMvn;
+            unary = true;
+            break;
+        case OP_ADD_INT:
+        case OP_ADD_INT_2ADDR:
+            op = kOpAdd;
+            break;
+        case OP_SUB_INT:
+        case OP_SUB_INT_2ADDR:
+            op = kOpSub;
+            break;
+        case OP_MUL_INT:
+        case OP_MUL_INT_2ADDR:
+            op = kOpMul;
+            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:
+            op = kOpAnd;
+            break;
+        case OP_OR_INT:
+        case OP_OR_INT_2ADDR:
+            op = kOpOr;
+            break;
+        case OP_XOR_INT:
+        case OP_XOR_INT_2ADDR:
+            op = kOpXor;
+            break;
+        case OP_SHL_INT:
+        case OP_SHL_INT_2ADDR:
+            shiftOp = true;
+            op = kOpLsl;
+            break;
+        case OP_SHR_INT:
+        case OP_SHR_INT_2ADDR:
+            shiftOp = true;
+            op = kOpAsr;
+            break;
+        case OP_USHR_INT:
+        case OP_USHR_INT_2ADDR:
+            shiftOp = true;
+            op = kOpLsr;
+            break;
+        default:
+            LOGE("Invalid word arith op: %#x(%d)",
+                 mir->dalvikInsn.opcode, mir->dalvikInsn.opcode);
+            dvmCompilerAbort(cUnit);
+    }
+    if (!callOut) {
+        rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+        if (unary) {
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, op, rlResult.lowReg,
+                     rlSrc1.lowReg);
+        } else {
+            rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+            if (shiftOp) {
+                int tReg = dvmCompilerAllocTemp(cUnit);
+                opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
+                rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+                opRegRegReg(cUnit, op, rlResult.lowReg,
+                            rlSrc1.lowReg, tReg);
+                dvmCompilerFreeTemp(cUnit, tReg);
+            } else {
+                rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+                opRegRegReg(cUnit, op, rlResult.lowReg,
+                            rlSrc1.lowReg, rlSrc2.lowReg);
+            }
+        }
+        storeValue(cUnit, rlDest, rlResult);
+    } else {
+        RegLocation rlResult;
+        dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+        loadValueDirectFixed(cUnit, rlSrc2, r1);
+        LOAD_FUNC_ADDR(cUnit, r2, (int) callTgt);
+        loadValueDirectFixed(cUnit, rlSrc1, r0);
+        if (checkZero) {
+            genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
+        }
+        opReg(cUnit, kOpBlx, r2);
+        dvmCompilerClobberCallRegs(cUnit);
+        if (retReg == r0)
+            rlResult = dvmCompilerGetReturn(cUnit);
+        else
+            rlResult = dvmCompilerGetReturnAlt(cUnit);
+        storeValue(cUnit, rlDest, rlResult);
+    }
+    return false;
+}
+
+static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    RegLocation rlDest;
+    RegLocation rlSrc1;
+    RegLocation rlSrc2;
+    /* Deduce sizes of operands */
+    if (mir->ssaRep->numUses == 2) {
+        rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+        rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+    } else if (mir->ssaRep->numUses == 3) {
+        rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+        rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
+    } else {
+        rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+        rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
+        assert(mir->ssaRep->numUses == 4);
+    }
+    if (mir->ssaRep->numDefs == 1) {
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+    } else {
+        assert(mir->ssaRep->numDefs == 2);
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    }
+
+    if ((opcode >= OP_ADD_LONG_2ADDR) && (opcode <= OP_XOR_LONG_2ADDR)) {
+        return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_LONG) && (opcode <= OP_XOR_LONG)) {
+        return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_SHL_LONG_2ADDR) && (opcode <= OP_USHR_LONG_2ADDR)) {
+        return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_SHL_LONG) && (opcode <= OP_USHR_LONG)) {
+        return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_USHR_INT_2ADDR)) {
+        return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_INT) && (opcode <= OP_USHR_INT)) {
+        return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_FLOAT_2ADDR) && (opcode <= OP_REM_FLOAT_2ADDR)) {
+        return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_FLOAT) && (opcode <= OP_REM_FLOAT)) {
+        return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_DOUBLE_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
+        return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    if ((opcode >= OP_ADD_DOUBLE) && (opcode <= OP_REM_DOUBLE)) {
+        return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+    }
+    return true;
+}
+
+/* Generate unconditional branch instructions */
+static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
+{
+    ArmLIR *branch = opNone(cUnit, kOpUncondBr);
+    branch->generic.target = (LIR *) target;
+    return branch;
+}
+
+/* Perform the actual operation for OP_RETURN_* */
+static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
+{
+    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+                         TEMPLATE_RETURN_PROF : TEMPLATE_RETURN);
+#if defined(WITH_JIT_TUNING)
+    gDvmJit.returnOp++;
+#endif
+    int dPC = (int) (cUnit->method->insns + mir->offset);
+    /* Insert branch, but defer setting of target */
+    ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
+    /* Set up the place holder to reconstruct this Dalvik PC */
+    ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+    pcrLabel->operands[0] = dPC;
+    pcrLabel->operands[1] = mir->offset;
+    /* Insert the place holder to the growable list */
+    dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
+    /* Branch to the PC reconstruction code */
+    branch->generic.target = (LIR *) pcrLabel;
+}
+
+static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
+                                  DecodedInstruction *dInsn,
+                                  ArmLIR **pcrLabel)
+{
+    unsigned int i;
+    unsigned int regMask = 0;
+    RegLocation rlArg;
+    int numDone = 0;
+
+    /*
+     * Load arguments to r0..r4.  Note that these registers may contain
+     * live values, so we clobber them immediately after loading to prevent
+     * them from being used as sources for subsequent loads.
+     */
+    dvmCompilerLockAllTemps(cUnit);
+    for (i = 0; i < dInsn->vA; i++) {
+        regMask |= 1 << i;
+        rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
+        loadValueDirectFixed(cUnit, rlArg, i);
+    }
+    if (regMask) {
+        /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
+        opRegRegImm(cUnit, kOpSub, r7, r5FP,
+                    sizeof(StackSaveArea) + (dInsn->vA << 2));
+        /* generate null check */
+        if (pcrLabel) {
+            *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
+                                     mir->offset, NULL);
+        }
+        storeMultiple(cUnit, r7, regMask);
+    }
+}
+
+static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
+                                DecodedInstruction *dInsn,
+                                ArmLIR **pcrLabel)
+{
+    int srcOffset = dInsn->vC << 2;
+    int numArgs = dInsn->vA;
+    int regMask;
+
+    /*
+     * Note: here, all promoted registers will have been flushed
+     * back to the Dalvik base locations, so register usage restrictins
+     * are lifted.  All parms loaded from original Dalvik register
+     * region - even though some might conceivably have valid copies
+     * cached in a preserved register.
+     */
+    dvmCompilerLockAllTemps(cUnit);
+
+    /*
+     * r4PC     : &r5FP[vC]
+     * r7: &newFP[0]
+     */
+    opRegRegImm(cUnit, kOpAdd, r4PC, r5FP, srcOffset);
+    /* load [r0 .. min(numArgs,4)] */
+    regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
+    /*
+     * Protect the loadMultiple instruction from being reordered with other
+     * Dalvik stack accesses.
+     *
+     * This code is also shared by the invoke jumbo instructions, and this
+     * does not need to be done if the invoke jumbo has no arguments.
+     */
+    if (numArgs != 0) loadMultiple(cUnit, r4PC, regMask);
+
+    opRegRegImm(cUnit, kOpSub, r7, r5FP,
+                sizeof(StackSaveArea) + (numArgs << 2));
+    /* generate null check */
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
+                                 mir->offset, NULL);
+    }
+
+    /*
+     * Handle remaining 4n arguments:
+     * store previously loaded 4 values and load the next 4 values
+     */
+    if (numArgs >= 8) {
+        ArmLIR *loopLabel = NULL;
+        /*
+         * r0 contains "this" and it will be used later, so push it to the stack
+         * first. Pushing r5FP is just for stack alignment purposes.
+         */
+        opImm(cUnit, kOpPush, (1 << r0 | 1 << r5FP));
+        /* No need to generate the loop structure if numArgs <= 11 */
+        if (numArgs > 11) {
+            loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
+            loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
+            loopLabel->defMask = ENCODE_ALL;
+        }
+        storeMultiple(cUnit, r7, regMask);
+        /*
+         * Protect the loadMultiple instruction from being reordered with other
+         * Dalvik stack accesses.
+         */
+        loadMultiple(cUnit, r4PC, regMask);
+        /* No need to generate the loop structure if numArgs <= 11 */
+        if (numArgs > 11) {
+            opRegImm(cUnit, kOpSub, r5FP, 4);
+            genConditionalBranch(cUnit, kArmCondNe, loopLabel);
+        }
+    }
+
+    /* Save the last batch of loaded values */
+    if (numArgs != 0) storeMultiple(cUnit, r7, regMask);
+
+    /* Generate the loop epilogue - don't use r0 */
+    if ((numArgs > 4) && (numArgs % 4)) {
+        regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
+        /*
+         * Protect the loadMultiple instruction from being reordered with other
+         * Dalvik stack accesses.
+         */
+        loadMultiple(cUnit, r4PC, regMask);
+    }
+    if (numArgs >= 8)
+        opImm(cUnit, kOpPop, (1 << r0 | 1 << r5FP));
+
+    /* Save the modulo 4 arguments */
+    if ((numArgs > 4) && (numArgs % 4)) {
+        storeMultiple(cUnit, r7, regMask);
+    }
+}
+
+/*
+ * Generate code to setup the call stack then jump to the chaining cell if it
+ * is not a native method.
+ */
+static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
+                                     BasicBlock *bb, ArmLIR *labelList,
+                                     ArmLIR *pcrLabel,
+                                     const Method *calleeMethod)
+{
+    /*
+     * Note: all Dalvik register state should be flushed to
+     * memory by the point, so register usage restrictions no
+     * longer apply.  All temp & preserved registers may be used.
+     */
+    dvmCompilerLockAllTemps(cUnit);
+    ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
+
+    /* r1 = &retChainingCell */
+    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
+
+    /* r4PC = dalvikCallsite */
+    loadConstant(cUnit, r4PC,
+                 (int) (cUnit->method->insns + mir->offset));
+    addrRetChain->generic.target = (LIR *) retChainingCell;
+
+    /* r7 = calleeMethod->registersSize */
+    loadConstant(cUnit, r7, calleeMethod->registersSize);
+    /*
+     * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
+     * r1 = &ChainingCell
+     * r2 = calleeMethod->outsSize (to be loaded later for Java callees)
+     * r4PC = callsiteDPC
+     * r7 = calleeMethod->registersSize
+     */
+    if (dvmIsNativeMethod(calleeMethod)) {
+        genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+            TEMPLATE_INVOKE_METHOD_NATIVE_PROF :
+            TEMPLATE_INVOKE_METHOD_NATIVE);
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokeNative++;
+#endif
+    } else {
+        /* For Java callees, set up r2 to be calleeMethod->outsSize */
+        loadConstant(cUnit, r2, calleeMethod->outsSize);
+        genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+            TEMPLATE_INVOKE_METHOD_CHAIN_PROF :
+            TEMPLATE_INVOKE_METHOD_CHAIN);
+#if defined(WITH_JIT_TUNING)
+        gDvmJit.invokeMonomorphic++;
+#endif
+        /* Branch to the chaining cell */
+        genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+    }
+    /* Handle exceptions using the interpreter */
+    genTrap(cUnit, mir->offset, pcrLabel);
+}
+
+/*
+ * Generate code to check the validity of a predicted chain and take actions
+ * based on the result.
+ *
+ * 0x426a99aa : ldr     r4, [pc, #72] --> r4 <- dalvikPC of this invoke
+ * 0x426a99ac : add     r1, pc, #32   --> r1 <- &retChainingCell
+ * 0x426a99ae : add     r2, pc, #40   --> r2 <- &predictedChainingCell
+ * 0x426a99b0 : blx_1   0x426a918c    --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+ * 0x426a99b2 : blx_2   see above     --+
+ * 0x426a99b4 : b       0x426a99d8    --> off to the predicted chain
+ * 0x426a99b6 : b       0x426a99c8    --> punt to the interpreter
+ * 0x426a99b8 : ldr     r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
+ * 0x426a99ba : cmp     r1, #0        --> compare r1 (rechain count) against 0
+ * 0x426a99bc : bgt     0x426a99c2    --> >=0? don't rechain
+ * 0x426a99be : ldr     r7, [pc, #off]--+ dvmJitToPatchPredictedChain
+ * 0x426a99c0 : blx     r7            --+
+ * 0x426a99c2 : add     r1, pc, #12   --> r1 <- &retChainingCell
+ * 0x426a99c4 : blx_1   0x426a9098    --+ TEMPLATE_INVOKE_METHOD_NO_OPT
+ * 0x426a99c6 : blx_2   see above     --+
+ */
+static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
+                                   int methodIndex,
+                                   ArmLIR *retChainingCell,
+                                   ArmLIR *predChainingCell,
+                                   ArmLIR *pcrLabel)
+{
+    /*
+     * Note: all Dalvik register state should be flushed to
+     * memory by the point, so register usage restrictions no
+     * longer apply.  Lock temps to prevent them from being
+     * allocated by utility routines.
+     */
+    dvmCompilerLockAllTemps(cUnit);
+
+    /*
+     * For verbose printing, store the method pointer in operands[1] first as
+     * operands[0] will be clobbered in dvmCompilerMIR2LIR.
+     */
+    predChainingCell->operands[1] = (int) mir->meta.callsiteInfo->method;
+
+    /* "this" is already left in r0 by genProcessArgs* */
+
+    /* r4PC = dalvikCallsite */
+    loadConstant(cUnit, r4PC,
+                 (int) (cUnit->method->insns + mir->offset));
+
+    /* r1 = &retChainingCell */
+    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
+    addrRetChain->generic.target = (LIR *) retChainingCell;
+
+    /* r2 = &predictedChainingCell */
+    ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0);
+    predictedChainingCell->generic.target = (LIR *) predChainingCell;
+
+    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+        TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
+        TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
+
+    /* return through lr - jump to the chaining cell */
+    genUnconditionalBranch(cUnit, predChainingCell);
+
+    /*
+     * null-check on "this" may have been eliminated, but we still need a PC-
+     * reconstruction label for stack overflow bailout.
+     */
+    if (pcrLabel == NULL) {
+        int dPC = (int) (cUnit->method->insns + mir->offset);
+        pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+        pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+        pcrLabel->operands[0] = dPC;
+        pcrLabel->operands[1] = mir->offset;
+        /* Insert the place holder to the growable list */
+        dvmInsertGrowableList(&cUnit->pcReconstructionList,
+                              (intptr_t) pcrLabel);
+    }
+
+    /* return through lr+2 - punt to the interpreter */
+    genUnconditionalBranch(cUnit, pcrLabel);
+
+    /*
+     * return through lr+4 - fully resolve the callee method.
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+
+    /* r0 <- calleeMethod */
+    loadWordDisp(cUnit, r7, methodIndex * 4, r0);
+
+    /* Check if rechain limit is reached */
+    ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt, r1, 0);
+
+    LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain);
+
+    genRegCopy(cUnit, r1, r6SELF);
+
+    /*
+     * r0 = calleeMethod
+     * r2 = &predictedChainingCell
+     * r3 = class
+     *
+     * &returnChainingCell has been loaded into r1 but is not needed
+     * when patching the chaining cell and will be clobbered upon
+     * returning so it will be reconstructed again.
+     */
+    opReg(cUnit, kOpBlx, r7);
+
+    /* r1 = &retChainingCell */
+    addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
+    addrRetChain->generic.target = (LIR *) retChainingCell;
+
+    bypassRechaining->generic.target = (LIR *) addrRetChain;
+    /*
+     * r0 = calleeMethod,
+     * r1 = &ChainingCell,
+     * r4PC = callsiteDPC,
+     */
+    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+        TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
+        TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(WITH_JIT_TUNING)
+    gDvmJit.invokePolymorphic++;
+#endif
+    /* Handle exceptions using the interpreter */
+    genTrap(cUnit, mir->offset, pcrLabel);
+}
+
+/* "this" pointer is already in r0 */
+static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit,
+                                        MIR *mir,
+                                        void *calleeAddr,
+                                        ArmLIR *retChainingCell)
+{
+    CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+    dvmCompilerLockAllTemps(cUnit);
+
+    loadClassPointer(cUnit, r1, (int) callsiteInfo);
+
+    loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2);
+    /* Branch to the slow path if classes are not equal */
+    opRegReg(cUnit, kOpCmp, r1, r2);
+    /*
+     * Set the misPredBranchOver target so that it will be generated when the
+     * code for the non-optimized invoke is generated.
+     */
+    ArmLIR *classCheck = opCondBranch(cUnit, kArmCondNe);
+
+    /* r0 = the Dalvik PC of the callsite */
+    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
+
+    newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr);
+    newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr);
+    genUnconditionalBranch(cUnit, retChainingCell);
+
+    /* Target of slow path */
+    ArmLIR *slowPathLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
+
+    slowPathLabel->defMask = ENCODE_ALL;
+    classCheck->generic.target = (LIR *) slowPathLabel;
+
+    // FIXME
+    cUnit->printMe = true;
+}
+
+static void genInvokeSingletonWholeMethod(CompilationUnit *cUnit,
+                                          MIR *mir,
+                                          void *calleeAddr,
+                                          ArmLIR *retChainingCell)
+{
+    /* r0 = the Dalvik PC of the callsite */
+    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
+
+    newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr);
+    newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr);
+    genUnconditionalBranch(cUnit, retChainingCell);
+
+    // FIXME
+    cUnit->printMe = true;
+}
+
+/* Geneate a branch to go back to the interpreter */
+static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
+{
+    /* r0 = dalvik pc */
+    dvmCompilerFlushAllRegs(cUnit);
+    loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
+    loadWordDisp(cUnit, r6SELF, offsetof(Thread,
+                 jitToInterpEntries.dvmJitToInterpPunt), r1);
+    opReg(cUnit, kOpBlx, 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 = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
+    int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn;
+
+    // Single stepping is considered loop mode breaker
+    if (cUnit->jitMode == kJitLoop) {
+        cUnit->quitLoopMode = true;
+        return;
+    }
+
+    //If already optimized out, just ignore
+    if (mir->dalvikInsn.opcode == OP_NOP)
+        return;
+
+    //Ugly, but necessary.  Flush all Dalvik regs so Interp can find them
+    dvmCompilerFlushAllRegs(cUnit);
+
+    if ((mir->next == NULL) || (flags & flagsToCheck)) {
+       genPuntToInterp(cUnit, mir->offset);
+       return;
+    }
+    int entryAddr = offsetof(Thread,
+                             jitToInterpEntries.dvmJitToInterpSingleStep);
+    loadWordDisp(cUnit, r6SELF, entryAddr, r2);
+    /* 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));
+    opReg(cUnit, kOpBlx, r2);
+}
+
+#if defined(_ARMV5TE) || defined(_ARMV5TE_VFP)
+/*
+ * To prevent a thread in a monitor wait from blocking the Jit from
+ * resetting the code cache, heavyweight monitor lock will not
+ * be allowed to return to an existing translation.  Instead, we will
+ * handle them by branching to a handler, which will in turn call the
+ * runtime lock routine and then branch directly back to the
+ * interpreter main loop.  Given the high cost of the heavyweight
+ * lock operation, this additional cost should be slight (especially when
+ * considering that we expect the vast majority of lock operations to
+ * use the fast-path thin lock bypass).
+ */
+static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
+{
+    bool isEnter = (mir->dalvikInsn.opcode == OP_MONITOR_ENTER);
+    genExportPC(cUnit, mir);
+    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    loadValueDirectFixed(cUnit, rlSrc, r1);
+    genRegCopy(cUnit, r0, r6SELF);
+    genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+    if (isEnter) {
+        /* Get dPC of next insn */
+        loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
+                 dexGetWidthFromOpcode(OP_MONITOR_ENTER)));
+        genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
+    } else {
+        LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject);
+        /* Do the call */
+        opReg(cUnit, kOpBlx, r2);
+        /* Did we throw? */
+        ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+        loadConstant(cUnit, r0,
+                     (int) (cUnit->method->insns + mir->offset +
+                     dexGetWidthFromOpcode(OP_MONITOR_EXIT)));
+        genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+        ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        branchOver->generic.target = (LIR *) target;
+        dvmCompilerClobberCallRegs(cUnit);
+    }
+}
+#endif
+
+/*
+ * Fetch *self->info.breakFlags. If the breakFlags are non-zero,
+ * punt to the interpreter.
+ */
+static void genSuspendPoll(CompilationUnit *cUnit, MIR *mir)
+{
+    int rTemp = dvmCompilerAllocTemp(cUnit);
+    ArmLIR *ld;
+    ld = loadBaseDisp(cUnit, NULL, r6SELF,
+                      offsetof(Thread, interpBreak.ctl.breakFlags),
+                      rTemp, kUnsignedByte, INVALID_SREG);
+    setMemRefType(ld, true /* isLoad */, kMustNotAlias);
+    genRegImmCheck(cUnit, kArmCondNe, rTemp, 0, mir->offset, NULL);
+}
+
+/*
+ * 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, ArmLIR *labelList)
+{
+    /* backward branch? */
+    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+    if (backwardBranch &&
+        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
+        genSuspendPoll(cUnit, mir);
+    }
+
+    int numPredecessors = dvmCountSetBits(bb->taken->predecessors);
+    /*
+     * Things could be hoisted out of the taken block into the predecessor, so
+     * make sure it is dominated by the predecessor.
+     */
+    if (numPredecessors == 1 && bb->taken->visited == false &&
+        bb->taken->blockType == kDalvikByteCode) {
+        cUnit->nextCodegenBlock = bb->taken;
+    } else {
+        /* 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)) {
+        LOGE("Codegen: got unused opcode %#x",dalvikOpcode);
+        return true;
+    }
+    switch (dalvikOpcode) {
+        case OP_RETURN_VOID_BARRIER:
+            dvmCompilerGenMemBarrier(cUnit, kST);
+            // Intentional fallthrough
+        case OP_RETURN_VOID:
+            genReturnCommon(cUnit,mir);
+            break;
+        case OP_UNUSED_73:
+        case OP_UNUSED_79:
+        case OP_UNUSED_7A:
+        case OP_DISPATCH_FF:
+            LOGE("Codegen: got unused opcode %#x",dalvikOpcode);
+            return true;
+        case OP_NOP:
+            break;
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlDest;
+    RegLocation rlResult;
+    if (mir->ssaRep->numDefs == 2) {
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+    }
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_CONST:
+        case OP_CONST_4: {
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_CONST_WIDE_32: {
+            //TUNING: single routine to load constant pair for support doubles
+            //TUNING: load 0/-1 separately to avoid load dependency
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                        rlResult.lowReg, 31);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+        }
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlDest;
+    RegLocation rlResult;
+    if (mir->ssaRep->numDefs == 2) {
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+    }
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_CONST_HIGH16: {
+            loadConstantNoClobber(cUnit, rlResult.lowReg,
+                                  mir->dalvikInsn.vB << 16);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_CONST_WIDE_HIGH16: {
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                                  0, mir->dalvikInsn.vB << 16);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+        }
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool handleFmt20bc_Fmt40sc(CompilationUnit *cUnit, MIR *mir)
+{
+    /* For OP_THROW_VERIFICATION_ERROR & OP_THROW_VERIFICATION_ERROR_JUMBO */
+    genInterpSingleStep(cUnit, mir);
+    return false;
+}
+
+static bool handleFmt21c_Fmt31c_Fmt41c(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlResult;
+    RegLocation rlDest;
+    RegLocation rlSrc;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_CONST_STRING_JUMBO:
+        case OP_CONST_STRING: {
+            void *strPtr = (void*)
+              (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
+
+            if (strPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null string");
+                dvmAbort();
+            }
+
+            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_CONST_CLASS:
+        case OP_CONST_CLASS_JUMBO: {
+            void *classPtr = (void*)
+              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+
+            if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null class");
+                dvmAbort();
+            }
+
+            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_SGET:
+        case OP_SGET_VOLATILE:
+        case OP_SGET_VOLATILE_JUMBO:
+        case OP_SGET_JUMBO:
+        case OP_SGET_OBJECT:
+        case OP_SGET_OBJECT_VOLATILE:
+        case OP_SGET_OBJECT_VOLATILE_JUMBO:
+        case OP_SGET_OBJECT_JUMBO:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_BOOLEAN_JUMBO:
+        case OP_SGET_CHAR:
+        case OP_SGET_CHAR_JUMBO:
+        case OP_SGET_BYTE:
+        case OP_SGET_BYTE_JUMBO:
+        case OP_SGET_SHORT:
+        case OP_SGET_SHORT_JUMBO: {
+            int valOffset = OFFSETOF_MEMBER(StaticField, value);
+            int tReg = dvmCompilerAllocTemp(cUnit);
+            bool isVolatile;
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+            if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null static field");
+                dvmAbort();
+            }
+
+            /*
+             * On SMP systems, Dalvik opcodes found to be referencing
+             * volatile fields are rewritten to their _VOLATILE variant.
+             * However, this does not happen on non-SMP systems. The JIT
+             * still needs to know about volatility to avoid unsafe
+             * optimizations so we determine volatility based on either
+             * the opcode or the field access flags.
+             */
+#if ANDROID_SMP != 0
+            Opcode opcode = mir->dalvikInsn.opcode;
+            isVolatile = (opcode == OP_SGET_VOLATILE) ||
+                         (opcode == OP_SGET_VOLATILE_JUMBO) ||
+                         (opcode == OP_SGET_OBJECT_VOLATILE) ||
+                         (opcode == OP_SGET_OBJECT_VOLATILE_JUMBO);
+            assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
+#else
+            isVolatile = dvmIsVolatileField((Field *) fieldPtr);
+#endif
+
+            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
+
+            if (isVolatile) {
+                dvmCompilerGenMemBarrier(cUnit, kSY);
+            }
+            HEAP_ACCESS_SHADOW(true);
+            loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
+            HEAP_ACCESS_SHADOW(false);
+
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_SGET_WIDE:
+        case OP_SGET_WIDE_JUMBO: {
+            int valOffset = OFFSETOF_MEMBER(StaticField, value);
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+            if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null static field");
+                dvmAbort();
+            }
+
+            int tReg = dvmCompilerAllocTemp(cUnit);
+            rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
+
+            HEAP_ACCESS_SHADOW(true);
+            loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
+            HEAP_ACCESS_SHADOW(false);
+
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_SPUT:
+        case OP_SPUT_VOLATILE:
+        case OP_SPUT_VOLATILE_JUMBO:
+        case OP_SPUT_JUMBO:
+        case OP_SPUT_OBJECT:
+        case OP_SPUT_OBJECT_VOLATILE:
+        case OP_SPUT_OBJECT_VOLATILE_JUMBO:
+        case OP_SPUT_OBJECT_JUMBO:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_BOOLEAN_JUMBO:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_CHAR_JUMBO:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_BYTE_JUMBO:
+        case OP_SPUT_SHORT:
+        case OP_SPUT_SHORT_JUMBO: {
+            int valOffset = OFFSETOF_MEMBER(StaticField, value);
+            int tReg = dvmCompilerAllocTemp(cUnit);
+            int objHead;
+            bool isVolatile;
+            bool isSputObject;
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+            Opcode opcode = mir->dalvikInsn.opcode;
+
+            if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null static field");
+                dvmAbort();
+            }
+
+#if ANDROID_SMP != 0
+            isVolatile = (opcode == OP_SPUT_VOLATILE) ||
+                         (opcode == OP_SPUT_VOLATILE_JUMBO) ||
+                         (opcode == OP_SPUT_OBJECT_VOLATILE) ||
+                         (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
+            assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
+#else
+            isVolatile = dvmIsVolatileField((Field *) fieldPtr);
+#endif
+
+            isSputObject = (opcode == OP_SPUT_OBJECT) ||
+                           (opcode == OP_SPUT_OBJECT_JUMBO) ||
+                           (opcode == OP_SPUT_OBJECT_VOLATILE) ||
+                           (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
+
+            rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+            loadConstant(cUnit, tReg,  (int) fieldPtr);
+            if (isSputObject) {
+                objHead = dvmCompilerAllocTemp(cUnit);
+                loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead);
+            }
+            if (isVolatile) {
+                dvmCompilerGenMemBarrier(cUnit, kST);
+            }
+            HEAP_ACCESS_SHADOW(true);
+            storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
+            dvmCompilerFreeTemp(cUnit, tReg);
+            HEAP_ACCESS_SHADOW(false);
+            if (isVolatile) {
+                dvmCompilerGenMemBarrier(cUnit, kSY);
+            }
+            if (isSputObject) {
+                /* NOTE: marking card based sfield->clazz */
+                markCard(cUnit, rlSrc.lowReg, objHead);
+                dvmCompilerFreeTemp(cUnit, objHead);
+            }
+
+            break;
+        }
+        case OP_SPUT_WIDE:
+        case OP_SPUT_WIDE_JUMBO: {
+            int tReg = dvmCompilerAllocTemp(cUnit);
+            int valOffset = OFFSETOF_MEMBER(StaticField, value);
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
+            void *fieldPtr = (void*)
+              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+            if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null static field");
+                dvmAbort();
+            }
+
+            rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
+
+            HEAP_ACCESS_SHADOW(true);
+            storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
+            HEAP_ACCESS_SHADOW(false);
+            break;
+        }
+        case OP_NEW_INSTANCE:
+        case OP_NEW_INSTANCE_JUMBO: {
+            /*
+             * Obey the calling convention and don't mess with the register
+             * usage.
+             */
+            ClassObject *classPtr = (ClassObject *)
+              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+
+            if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null class");
+                dvmAbort();
+            }
+
+            /*
+             * If it is going to throw, it should not make to the trace to begin
+             * with.  However, Alloc might throw, so we need to genExportPC()
+             */
+            assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            genExportPC(cUnit, mir);
+            LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject);
+            loadConstant(cUnit, r0, (int) classPtr);
+            loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
+            opReg(cUnit, kOpBlx, r2);
+            dvmCompilerClobberCallRegs(cUnit);
+            /* generate a branch over if allocation is successful */
+            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+            /*
+             * OOM exception needs to be thrown here and cannot re-execute
+             */
+            loadConstant(cUnit, r0,
+                         (int) (cUnit->method->insns + mir->offset));
+            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+            /* noreturn */
+
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+            target->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR *) target;
+            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            rlResult = dvmCompilerGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_CHECK_CAST:
+        case OP_CHECK_CAST_JUMBO: {
+            /*
+             * Obey the calling convention and don't mess with the register
+             * usage.
+             */
+            ClassObject *classPtr =
+              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+            /*
+             * Note: It is possible that classPtr is NULL at this point,
+             * even though this instruction has been successfully interpreted.
+             * If the previous interpretation had a null source, the
+             * interpreter would not have bothered to resolve the clazz.
+             * Bail out to the interpreter in this case, and log it
+             * so that we can tell if it happens frequently.
+             */
+            if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
+                genInterpSingleStep(cUnit, mir);
+                return false;
+            }
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            loadConstant(cUnit, r1, (int) classPtr );
+            rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            /* Null? */
+            ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq,
+                                              rlSrc.lowReg, 0);
+            /*
+             *  rlSrc.lowReg now contains object->clazz.  Note that
+             *  it could have been allocated r0, but we're okay so long
+             *  as we don't do anything desctructive until r0 is loaded
+             *  with clazz.
+             */
+            /* r0 now contains object->clazz */
+            loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
+            LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial);
+            opRegReg(cUnit, kOpCmp, r0, r1);
+            ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
+            opReg(cUnit, kOpBlx, r2);
+            dvmCompilerClobberCallRegs(cUnit);
+            /*
+             * If null, check cast failed - punt to the interpreter.  Because
+             * interpreter will be the one throwing, we don't need to
+             * genExportPC() here.
+             */
+            genZeroCheck(cUnit, r0, mir->offset, NULL);
+            /* check cast passed - branch target here */
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+            target->defMask = ENCODE_ALL;
+            branch1->generic.target = (LIR *)target;
+            branch2->generic.target = (LIR *)target;
+            break;
+        }
+        case OP_SGET_WIDE_VOLATILE:
+        case OP_SGET_WIDE_VOLATILE_JUMBO:
+        case OP_SPUT_WIDE_VOLATILE:
+        case OP_SPUT_WIDE_VOLATILE_JUMBO:
+            genInterpSingleStep(cUnit, mir);
+            break;
+        default:
+            return true;
+    }
+    return false;
+}
+
+/*
+ * A typical example of inlined getter/setter from a monomorphic callsite:
+ *
+ * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ invoke-static (I)
+ * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ...
+ * D/dalvikvm(  289): 0x4427fc22 (0002): ldr     r0, [pc, #56]
+ * D/dalvikvm(  289): 0x4427fc24 (0004): ldr     r1, [r0, #0]
+ * D/dalvikvm(  289): 0x4427fc26 (0006): str     r1, [r5, #0]
+ * D/dalvikvm(  289): 0x4427fc28 (0008): .align4
+ * D/dalvikvm(  289): L0x0003:
+ * D/dalvikvm(  289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0
+ *
+ * Note the invoke-static and move-result-object with the (I) notation are
+ * turned into no-op.
+ */
+static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    RegLocation rlResult;
+    switch (dalvikOpcode) {
+        case OP_MOVE_EXCEPTION: {
+            int exOffset = offsetof(Thread, exception);
+            int resetReg = dvmCompilerAllocTemp(cUnit);
+            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, r6SELF, exOffset, rlResult.lowReg);
+            loadConstant(cUnit, resetReg, 0);
+            storeWordDisp(cUnit, r6SELF, exOffset, resetReg);
+            storeValue(cUnit, rlDest, rlResult);
+           break;
+        }
+        case OP_MOVE_RESULT:
+        case OP_MOVE_RESULT_OBJECT: {
+            /* An inlined move result is effectively no-op */
+            if (mir->OptimizationFlags & MIR_INLINED)
+                break;
+            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
+            rlSrc.fp = rlDest.fp;
+            storeValue(cUnit, rlDest, rlSrc);
+            break;
+        }
+        case OP_MOVE_RESULT_WIDE: {
+            /* An inlined move result is effectively no-op */
+            if (mir->OptimizationFlags & MIR_INLINED)
+                break;
+            RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+            RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
+            rlSrc.fp = rlDest.fp;
+            storeValueWide(cUnit, rlDest, rlSrc);
+            break;
+        }
+        case OP_RETURN_WIDE: {
+            RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+            RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+            rlDest.fp = rlSrc.fp;
+            storeValueWide(cUnit, rlDest, rlSrc);
+            genReturnCommon(cUnit,mir);
+            break;
+        }
+        case OP_RETURN:
+        case OP_RETURN_OBJECT: {
+            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
+            rlDest.fp = rlSrc.fp;
+            storeValue(cUnit, rlDest, rlSrc);
+            genReturnCommon(cUnit, mir);
+            break;
+        }
+        case OP_MONITOR_EXIT:
+        case OP_MONITOR_ENTER:
+            genMonitor(cUnit, mir);
+            break;
+        case OP_THROW:
+            genInterpSingleStep(cUnit, mir);
+            break;
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    RegLocation rlDest;
+    RegLocation rlSrc;
+    RegLocation rlResult;
+
+    if ( (opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
+        return genArithOp( cUnit, mir );
+    }
+
+    if (mir->ssaRep->numUses == 2)
+        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    else
+        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    if (mir->ssaRep->numDefs == 2)
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    else
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+
+    switch (opcode) {
+        case OP_DOUBLE_TO_INT:
+        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_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+        case OP_LONG_TO_DOUBLE:
+            return genConversion(cUnit, mir);
+        case OP_NEG_INT:
+        case OP_NOT_INT:
+            return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
+        case OP_NEG_LONG:
+        case OP_NOT_LONG:
+            return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
+        case OP_NEG_FLOAT:
+            return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
+        case OP_NEG_DOUBLE:
+            return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
+        case OP_MOVE_WIDE:
+            storeValueWide(cUnit, rlDest, rlSrc);
+            break;
+        case OP_INT_TO_LONG:
+            rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            //TUNING: shouldn't loadValueDirect already check for phys reg?
+            if (rlSrc.location == kLocPhysReg) {
+                genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+            } else {
+                loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+            }
+            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                        rlResult.lowReg, 31);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+        case OP_LONG_TO_INT:
+            rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
+            rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
+            // Intentional fallthrough
+        case OP_MOVE:
+        case OP_MOVE_OBJECT:
+            storeValue(cUnit, rlDest, rlSrc);
+            break;
+        case OP_INT_TO_BYTE:
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        case OP_INT_TO_SHORT:
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        case OP_INT_TO_CHAR:
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        case OP_ARRAY_LENGTH: {
+            int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
+                         mir->offset, NULL);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
+                         rlResult.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    RegLocation rlDest;
+    RegLocation rlResult;
+    int BBBB = mir->dalvikInsn.vB;
+    if (dalvikOpcode == OP_CONST_WIDE_16) {
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+        loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
+        //TUNING: do high separately to avoid load dependency
+        opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else if (dalvikOpcode == OP_CONST_16) {
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
+        loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
+        storeValue(cUnit, rlDest, rlResult);
+    } else
+        return true;
+    return false;
+}
+
+/* Compare agaist zero */
+static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                         ArmLIR *labelList)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    ArmConditionCode cond;
+    /* backward branch? */
+    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+    if (backwardBranch &&
+        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
+        genSuspendPoll(cUnit, mir);
+    }
+
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+
+    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
+
+//TUNING: break this out to allow use of Thumb2 CB[N]Z
+    switch (dalvikOpcode) {
+        case OP_IF_EQZ:
+            cond = kArmCondEq;
+            break;
+        case OP_IF_NEZ:
+            cond = kArmCondNe;
+            break;
+        case OP_IF_LTZ:
+            cond = kArmCondLt;
+            break;
+        case OP_IF_GEZ:
+            cond = kArmCondGe;
+            break;
+        case OP_IF_GTZ:
+            cond = kArmCondGt;
+            break;
+        case OP_IF_LEZ:
+            cond = kArmCondLe;
+            break;
+        default:
+            cond = (ArmConditionCode)0;
+            LOGE("Unexpected opcode (%d) for Fmt21t", dalvikOpcode);
+            dvmCompilerAbort(cUnit);
+    }
+    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 isPowerOfTwo(int x)
+{
+    return (x & (x - 1)) == 0;
+}
+
+// Returns true if no more than two bits are set in 'x'.
+static bool isPopCountLE2(unsigned int x)
+{
+    x &= x - 1;
+    return (x & (x - 1)) == 0;
+}
+
+// Returns the index of the lowest set bit in 'x'.
+static int lowestSetBit(unsigned int x) {
+    int bit_posn = 0;
+    while ((x & 0xf) == 0) {
+        bit_posn += 4;
+        x >>= 4;
+    }
+    while ((x & 1) == 0) {
+        bit_posn++;
+        x >>= 1;
+    }
+    return bit_posn;
+}
+
+// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
+// and store the result in 'rlDest'.
+static bool handleEasyDivide(CompilationUnit *cUnit, Opcode dalvikOpcode,
+                             RegLocation rlSrc, RegLocation rlDest, int lit)
+{
+    if (lit < 2 || !isPowerOfTwo(lit)) {
+        return false;
+    }
+    int k = lowestSetBit(lit);
+    if (k >= 30) {
+        // Avoid special cases.
+        return false;
+    }
+    bool div = (dalvikOpcode == OP_DIV_INT_LIT8 || dalvikOpcode == OP_DIV_INT_LIT16);
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (div) {
+        int tReg = dvmCompilerAllocTemp(cUnit);
+        if (lit == 2) {
+            // Division by 2 is by far the most common division by constant.
+            opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
+            opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+            opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+        } else {
+            opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
+            opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
+            opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+            opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+        }
+    } else {
+        int cReg = dvmCompilerAllocTemp(cUnit);
+        loadConstant(cUnit, cReg, lit - 1);
+        int tReg1 = dvmCompilerAllocTemp(cUnit);
+        int tReg2 = dvmCompilerAllocTemp(cUnit);
+        if (lit == 2) {
+            opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
+            opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+            opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+            opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+        } else {
+            opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
+            opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
+            opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+            opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+            opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+        }
+    }
+    storeValue(cUnit, rlDest, rlResult);
+    return true;
+}
+
+// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
+// and store the result in 'rlDest'.
+static bool handleEasyMultiply(CompilationUnit *cUnit,
+                               RegLocation rlSrc, RegLocation rlDest, int lit)
+{
+    // Can we simplify this multiplication?
+    bool powerOfTwo = false;
+    bool popCountLE2 = false;
+    bool powerOfTwoMinusOne = false;
+    if (lit < 2) {
+        // Avoid special cases.
+        return false;
+    } else if (isPowerOfTwo(lit)) {
+        powerOfTwo = true;
+    } else if (isPopCountLE2(lit)) {
+        popCountLE2 = true;
+    } else if (isPowerOfTwo(lit + 1)) {
+        powerOfTwoMinusOne = true;
+    } else {
+        return false;
+    }
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (powerOfTwo) {
+        // Shift.
+        opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
+                    lowestSetBit(lit));
+    } else if (popCountLE2) {
+        // Shift and add and shift.
+        int firstBit = lowestSetBit(lit);
+        int secondBit = lowestSetBit(lit ^ (1 << firstBit));
+        genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
+                                      firstBit, secondBit);
+    } else {
+        // Reverse subtract: (src << (shift + 1)) - src.
+        assert(powerOfTwoMinusOne);
+        // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
+        int tReg = dvmCompilerAllocTemp(cUnit);
+        opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
+        opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
+    }
+    storeValue(cUnit, rlDest, rlResult);
+    return true;
+}
+
+static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+    RegLocation rlResult;
+    int lit = mir->dalvikInsn.vC;
+    OpKind op = (OpKind)0;      /* Make gcc happy */
+    int shiftOp = false;
+    bool isDiv = false;
+
+    switch (dalvikOpcode) {
+        case OP_RSUB_INT_LIT8:
+        case OP_RSUB_INT: {
+            int tReg;
+            //TUNING: add support for use of Arm rsub op
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            tReg = dvmCompilerAllocTemp(cUnit);
+            loadConstant(cUnit, tReg, lit);
+            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+                        tReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            return false;
+            break;
+        }
+
+        case OP_ADD_INT_LIT8:
+        case OP_ADD_INT_LIT16:
+            op = kOpAdd;
+            break;
+        case OP_MUL_INT_LIT8:
+        case OP_MUL_INT_LIT16: {
+            if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
+                return false;
+            }
+            op = kOpMul;
+            break;
+        }
+        case OP_AND_INT_LIT8:
+        case OP_AND_INT_LIT16:
+            op = kOpAnd;
+            break;
+        case OP_OR_INT_LIT8:
+        case OP_OR_INT_LIT16:
+            op = kOpOr;
+            break;
+        case OP_XOR_INT_LIT8:
+        case OP_XOR_INT_LIT16:
+            op = kOpXor;
+            break;
+        case OP_SHL_INT_LIT8:
+            lit &= 31;
+            shiftOp = true;
+            op = kOpLsl;
+            break;
+        case OP_SHR_INT_LIT8:
+            lit &= 31;
+            shiftOp = true;
+            op = kOpAsr;
+            break;
+        case OP_USHR_INT_LIT8:
+            lit &= 31;
+            shiftOp = true;
+            op = kOpLsr;
+            break;
+
+        case OP_DIV_INT_LIT8:
+        case OP_DIV_INT_LIT16:
+        case OP_REM_INT_LIT8:
+        case OP_REM_INT_LIT16:
+            if (lit == 0) {
+                /* Let the interpreter deal with div by 0 */
+                genInterpSingleStep(cUnit, mir);
+                return false;
+            }
+            if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
+                return false;
+            }
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            loadValueDirectFixed(cUnit, rlSrc, r0);
+            dvmCompilerClobber(cUnit, r0);
+            if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
+                (dalvikOpcode == OP_DIV_INT_LIT16)) {
+                LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv);
+                isDiv = true;
+            } else {
+                LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod);
+                isDiv = false;
+            }
+            loadConstant(cUnit, r1, lit);
+            opReg(cUnit, kOpBlx, r2);
+            dvmCompilerClobberCallRegs(cUnit);
+            if (isDiv)
+                rlResult = dvmCompilerGetReturn(cUnit);
+            else
+                rlResult = dvmCompilerGetReturnAlt(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+            return false;
+            break;
+        default:
+            return true;
+    }
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
+    if (shiftOp && (lit == 0)) {
+        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    } else {
+        opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
+    }
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool handleFmt22c_Fmt52c(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    int fieldOffset = -1;
+    bool isVolatile = false;
+    switch (dalvikOpcode) {
+        /*
+         * Wide volatiles currently handled via single step.
+         * Add them here if generating in-line code.
+         *     case OP_IGET_WIDE_VOLATILE:
+         *     case OP_IGET_WIDE_VOLATILE_JUMBO:
+         *     case OP_IPUT_WIDE_VOLATILE:
+         *     case OP_IPUT_WIDE_VOLATILE_JUMBO:
+         */
+        case OP_IGET_VOLATILE:
+        case OP_IGET_VOLATILE_JUMBO:
+        case OP_IGET_OBJECT_VOLATILE:
+        case OP_IGET_OBJECT_VOLATILE_JUMBO:
+        case OP_IPUT_VOLATILE:
+        case OP_IPUT_VOLATILE_JUMBO:
+        case OP_IPUT_OBJECT_VOLATILE:
+        case OP_IPUT_OBJECT_VOLATILE_JUMBO:
+#if ANDROID_SMP != 0
+            isVolatile = true;
+        // NOTE: intentional fallthrough
+#endif
+        case OP_IGET:
+        case OP_IGET_JUMBO:
+        case OP_IGET_WIDE:
+        case OP_IGET_WIDE_JUMBO:
+        case OP_IGET_OBJECT:
+        case OP_IGET_OBJECT_JUMBO:
+        case OP_IGET_BOOLEAN:
+        case OP_IGET_BOOLEAN_JUMBO:
+        case OP_IGET_BYTE:
+        case OP_IGET_BYTE_JUMBO:
+        case OP_IGET_CHAR:
+        case OP_IGET_CHAR_JUMBO:
+        case OP_IGET_SHORT:
+        case OP_IGET_SHORT_JUMBO:
+        case OP_IPUT:
+        case OP_IPUT_JUMBO:
+        case OP_IPUT_WIDE:
+        case OP_IPUT_WIDE_JUMBO:
+        case OP_IPUT_OBJECT:
+        case OP_IPUT_OBJECT_JUMBO:
+        case OP_IPUT_BOOLEAN:
+        case OP_IPUT_BOOLEAN_JUMBO:
+        case OP_IPUT_BYTE:
+        case OP_IPUT_BYTE_JUMBO:
+        case OP_IPUT_CHAR:
+        case OP_IPUT_CHAR_JUMBO:
+        case OP_IPUT_SHORT:
+        case OP_IPUT_SHORT_JUMBO: {
+            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
+                mir->meta.calleeMethod : cUnit->method;
+            Field *fieldPtr =
+                method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
+
+            if (fieldPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null instance field");
+                dvmAbort();
+            }
+
+#if ANDROID_SMP != 0
+            assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
+#else
+            isVolatile = dvmIsVolatileField((Field *) fieldPtr);
+#endif
+            fieldOffset = ((InstField *)fieldPtr)->byteOffset;
+            break;
+        }
+        default:
+            break;
+    }
+
+    switch (dalvikOpcode) {
+        case OP_NEW_ARRAY:
+        case OP_NEW_ARRAY_JUMBO: {
+            // Generates a call - use explicit registers
+            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            RegLocation rlResult;
+            void *classPtr = (void*)
+              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
+
+            if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGE("Unexpected null class");
+                dvmAbort();
+            }
+
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            genExportPC(cUnit, mir);
+            loadValueDirectFixed(cUnit, rlSrc, r1);   /* Len */
+            loadConstant(cUnit, r0, (int) classPtr );
+            LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass);
+            /*
+             * "len < 0": bail to the interpreter to re-execute the
+             * instruction
+             */
+            genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
+            loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
+            opReg(cUnit, kOpBlx, r3);
+            dvmCompilerClobberCallRegs(cUnit);
+            /* generate a branch over if allocation is successful */
+            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+            /*
+             * OOM exception needs to be thrown here and cannot re-execute
+             */
+            loadConstant(cUnit, r0,
+                         (int) (cUnit->method->insns + mir->offset));
+            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+            /* noreturn */
+
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+            target->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR *) target;
+            rlResult = dvmCompilerGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        }
+        case OP_INSTANCE_OF:
+        case OP_INSTANCE_OF_JUMBO: {
+            // May generate a call - use explicit registers
+            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+            RegLocation rlResult;
+            ClassObject *classPtr =
+              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
+            /*
+             * Note: It is possible that classPtr is NULL at this point,
+             * even though this instruction has been successfully interpreted.
+             * If the previous interpretation had a null source, the
+             * interpreter would not have bothered to resolve the clazz.
+             * Bail out to the interpreter in this case, and log it
+             * so that we can tell if it happens frequently.
+             */
+            if (classPtr == NULL) {
+                BAIL_LOOP_COMPILATION();
+                LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
+                genInterpSingleStep(cUnit, mir);
+                break;
+            }
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
+            loadConstant(cUnit, r2, (int) classPtr );
+            /* When taken r0 has NULL which can be used for store directly */
+            ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
+            /* r1 now contains object->clazz */
+            loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
+            /* r1 now contains object->clazz */
+            LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial);
+            loadConstant(cUnit, r0, 1);                /* Assume true */
+            opRegReg(cUnit, kOpCmp, r1, r2);
+            ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
+            genRegCopy(cUnit, r0, r1);
+            genRegCopy(cUnit, r1, r2);
+            opReg(cUnit, kOpBlx, r3);
+            dvmCompilerClobberCallRegs(cUnit);
+            /* branch target here */
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+            target->defMask = ENCODE_ALL;
+            rlResult = dvmCompilerGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+            branch1->generic.target = (LIR *)target;
+            branch2->generic.target = (LIR *)target;
+            break;
+        }
+        case OP_IGET_WIDE:
+        case OP_IGET_WIDE_JUMBO:
+            genIGetWide(cUnit, mir, fieldOffset);
+            break;
+        case OP_IGET_VOLATILE:
+        case OP_IGET_VOLATILE_JUMBO:
+        case OP_IGET_OBJECT_VOLATILE:
+        case OP_IGET_OBJECT_VOLATILE_JUMBO:
+        case OP_IGET:
+        case OP_IGET_JUMBO:
+        case OP_IGET_OBJECT:
+        case OP_IGET_OBJECT_JUMBO:
+        case OP_IGET_BOOLEAN:
+        case OP_IGET_BOOLEAN_JUMBO:
+        case OP_IGET_BYTE:
+        case OP_IGET_BYTE_JUMBO:
+        case OP_IGET_CHAR:
+        case OP_IGET_CHAR_JUMBO:
+        case OP_IGET_SHORT:
+        case OP_IGET_SHORT_JUMBO:
+            genIGet(cUnit, mir, kWord, fieldOffset, isVolatile);
+            break;
+        case OP_IPUT_WIDE:
+        case OP_IPUT_WIDE_JUMBO:
+            genIPutWide(cUnit, mir, fieldOffset);
+            break;
+        case OP_IPUT_VOLATILE:
+        case OP_IPUT_VOLATILE_JUMBO:
+        case OP_IPUT:
+        case OP_IPUT_JUMBO:
+        case OP_IPUT_BOOLEAN:
+        case OP_IPUT_BOOLEAN_JUMBO:
+        case OP_IPUT_BYTE:
+        case OP_IPUT_BYTE_JUMBO:
+        case OP_IPUT_CHAR:
+        case OP_IPUT_CHAR_JUMBO:
+        case OP_IPUT_SHORT:
+        case OP_IPUT_SHORT_JUMBO:
+            genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile);
+            break;
+        case OP_IPUT_OBJECT_VOLATILE:
+        case OP_IPUT_OBJECT_VOLATILE_JUMBO:
+        case OP_IPUT_OBJECT:
+        case OP_IPUT_OBJECT_JUMBO:
+            genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile);
+            break;
+        case OP_IGET_WIDE_VOLATILE:
+        case OP_IGET_WIDE_VOLATILE_JUMBO:
+        case OP_IPUT_WIDE_VOLATILE:
+        case OP_IPUT_WIDE_VOLATILE_JUMBO:
+            genInterpSingleStep(cUnit, mir);
+            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, kWord, fieldOffset, false);
+            break;
+        case OP_IPUT_QUICK:
+            genIPut(cUnit, mir, kWord, fieldOffset, false, false);
+            break;
+        case OP_IPUT_OBJECT_QUICK:
+            genIPut(cUnit, mir, kWord, fieldOffset, true, false);
+            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,
+                         ArmLIR *labelList)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    ArmConditionCode cond;
+    /* backward branch? */
+    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+    if (backwardBranch &&
+        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
+        genSuspendPoll(cUnit, mir);
+    }
+
+    RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+
+    switch (dalvikOpcode) {
+        case OP_IF_EQ:
+            cond = kArmCondEq;
+            break;
+        case OP_IF_NE:
+            cond = kArmCondNe;
+            break;
+        case OP_IF_LT:
+            cond = kArmCondLt;
+            break;
+        case OP_IF_GE:
+            cond = kArmCondGe;
+            break;
+        case OP_IF_GT:
+            cond = kArmCondGt;
+            break;
+        case OP_IF_LE:
+            cond = kArmCondLe;
+            break;
+        default:
+            cond = (ArmConditionCode)0;
+            LOGE("Unexpected opcode (%d) for Fmt22t", dalvikOpcode);
+            dvmCompilerAbort(cUnit);
+    }
+    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;
+
+    switch (opcode) {
+        case OP_MOVE_16:
+        case OP_MOVE_OBJECT_16:
+        case OP_MOVE_FROM16:
+        case OP_MOVE_OBJECT_FROM16: {
+            storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
+                       dvmCompilerGetSrc(cUnit, mir, 0));
+            break;
+        }
+        case OP_MOVE_WIDE_16:
+        case OP_MOVE_WIDE_FROM16: {
+            storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
+                           dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
+            break;
+        }
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    RegLocation rlSrc1;
+    RegLocation rlSrc2;
+    RegLocation rlDest;
+
+    if ( (opcode >= OP_ADD_INT) && (opcode <= OP_REM_DOUBLE)) {
+        return genArithOp( cUnit, mir );
+    }
+
+    /* APUTs have 3 sources and no targets */
+    if (mir->ssaRep->numDefs == 0) {
+        if (mir->ssaRep->numUses == 3) {
+            rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
+            rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
+            rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
+        } else {
+            assert(mir->ssaRep->numUses == 4);
+            rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
+            rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
+        }
+    } else {
+        /* Two sources and 1 dest.  Deduce the operand sizes */
+        if (mir->ssaRep->numUses == 4) {
+            rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
+        } else {
+            assert(mir->ssaRep->numUses == 2);
+            rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+            rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+        }
+        if (mir->ssaRep->numDefs == 2) {
+            rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+        } else {
+            assert(mir->ssaRep->numDefs == 1);
+            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+        }
+    }
+
+
+    switch (opcode) {
+        case OP_CMPL_FLOAT:
+        case OP_CMPG_FLOAT:
+        case OP_CMPL_DOUBLE:
+        case OP_CMPG_DOUBLE:
+            return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        case OP_CMP_LONG:
+            genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+            break;
+        case OP_AGET_WIDE:
+            genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
+            break;
+        case OP_AGET:
+        case OP_AGET_OBJECT:
+            genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
+            break;
+        case OP_AGET_BOOLEAN:
+            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
+            break;
+        case OP_AGET_BYTE:
+            genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
+            break;
+        case OP_AGET_CHAR:
+            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
+            break;
+        case OP_AGET_SHORT:
+            genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
+            break;
+        case OP_APUT_WIDE:
+            genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
+            break;
+        case OP_APUT:
+            genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
+            break;
+        case OP_APUT_OBJECT:
+            genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2);
+            break;
+        case OP_APUT_SHORT:
+        case OP_APUT_CHAR:
+            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
+            break;
+        case OP_APUT_BYTE:
+        case OP_APUT_BOOLEAN:
+            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
+            break;
+        default:
+            return true;
+    }
+    return false;
+}
+
+/*
+ * Find the matching case.
+ *
+ * return values:
+ * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
+ *    including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
+ * r1 (high 32-bit): the branch offset of the matching case (only for indexes
+ *    above MAX_CHAINED_SWITCH_CASES).
+ *
+ * Instructions around the call are:
+ *
+ * mov r2, pc
+ * blx &findPackedSwitchIndex
+ * mov pc, r0
+ * .align4
+ * chaining cell for case 0 [12 bytes]
+ * chaining cell for case 1 [12 bytes]
+ *               :
+ * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes]
+ * chaining cell for case default [8 bytes]
+ * noChain exit
+ */
+static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
+{
+    int size;
+    int firstKey;
+    const int *entries;
+    int index;
+    int jumpIndex;
+    int caseDPCOffset = 0;
+    /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
+    int chainingPC = (pc + 4) & ~3;
+
+    /*
+     * Packed switch data format:
+     *  ushort ident = 0x0100   magic value
+     *  ushort size             number of entries in the table
+     *  int first_key           first (and lowest) switch case value
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (4+size*2) 16-bit code units.
+     */
+    size = switchData[1];
+    assert(size > 0);
+
+    firstKey = switchData[2];
+    firstKey |= switchData[3] << 16;
+
+
+    /* The entries are guaranteed to be aligned on a 32-bit boundary;
+     * we can treat them as a native int array.
+     */
+    entries = (const int*) &switchData[4];
+    assert(((u4)entries & 0x3) == 0);
+
+    index = testVal - firstKey;
+
+    /* Jump to the default cell */
+    if (index < 0 || index >= size) {
+        jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
+    /* Jump to the non-chaining exit point */
+    } else if (index >= MAX_CHAINED_SWITCH_CASES) {
+        jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
+        caseDPCOffset = entries[index];
+    /* Jump to the inline chaining cell */
+    } else {
+        jumpIndex = index;
+    }
+
+    chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
+    return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
+}
+
+/* See comments for findPackedSwitchIndex */
+static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
+{
+    int size;
+    const int *keys;
+    const int *entries;
+    int chainingPC = (pc + 4) & ~3;
+    int i;
+
+    /*
+     * Sparse switch data format:
+     *  ushort ident = 0x0200   magic value
+     *  ushort size             number of entries in the table; > 0
+     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (2+size*4) 16-bit code units.
+     */
+
+    size = switchData[1];
+    assert(size > 0);
+
+    /* The keys are guaranteed to be aligned on a 32-bit boundary;
+     * we can treat them as a native int array.
+     */
+    keys = (const int*) &switchData[2];
+    assert(((u4)keys & 0x3) == 0);
+
+    /* The entries are guaranteed to be aligned on a 32-bit boundary;
+     * we can treat them as a native int array.
+     */
+    entries = keys + size;
+    assert(((u4)entries & 0x3) == 0);
+
+    /*
+     * Run through the list of keys, which are guaranteed to
+     * be sorted low-to-high.
+     *
+     * Most tables have 3-4 entries.  Few have more than 10.  A binary
+     * search here is probably not useful.
+     */
+    for (i = 0; i < size; i++) {
+        int k = keys[i];
+        if (k == testVal) {
+            /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
+            int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
+                           i : MAX_CHAINED_SWITCH_CASES + 1;
+            chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
+            return (((s8) entries[i]) << 32) | (u8) chainingPC;
+        } else if (k > testVal) {
+            break;
+        }
+    }
+    return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) *
+           CHAIN_CELL_NORMAL_SIZE;
+}
+
+static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    switch (dalvikOpcode) {
+        case OP_FILL_ARRAY_DATA: {
+            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            // Making a call - use explicit registers
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            genExportPC(cUnit, mir);
+            loadValueDirectFixed(cUnit, rlSrc, r0);
+            LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData);
+            loadConstant(cUnit, r1,
+               (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
+            opReg(cUnit, kOpBlx, r2);
+            dvmCompilerClobberCallRegs(cUnit);
+            /* generate a branch over if successful */
+            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+            loadConstant(cUnit, r0,
+                         (int) (cUnit->method->insns + mir->offset));
+            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+            target->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR *) target;
+            break;
+        }
+        /*
+         * Compute the goto target of up to
+         * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
+         * See the comment before findPackedSwitchIndex for the code layout.
+         */
+        case OP_PACKED_SWITCH:
+        case OP_SPARSE_SWITCH: {
+            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+            loadValueDirectFixed(cUnit, rlSrc, r1);
+            dvmCompilerLockAllTemps(cUnit);
+            if (dalvikOpcode == OP_PACKED_SWITCH) {
+                LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex);
+            } else {
+                LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex);
+            }
+            /* r0 <- Addr of the switch data */
+            loadConstant(cUnit, r0,
+               (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
+            /* r2 <- pc of the instruction following the blx */
+            opRegReg(cUnit, kOpMov, r2, r15pc);
+            opReg(cUnit, kOpBlx, r4PC);
+            dvmCompilerClobberCallRegs(cUnit);
+            /* pc <- computed goto target */
+            opRegReg(cUnit, kOpMov, r15pc, r0);
+            break;
+        }
+        default:
+            return true;
+    }
+    return false;
+}
+
+/*
+ * See the example of predicted inlining listed before the
+ * genValidationForPredictedInline function. The function here takes care the
+ * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
+ */
+static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
+                                               BasicBlock *bb,
+                                               ArmLIR *labelList)
+{
+    BasicBlock *fallThrough = bb->fallThrough;
+
+    /* Bypass the move-result block if there is one */
+    if (fallThrough->firstMIRInsn) {
+        assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
+        fallThrough = fallThrough->fallThrough;
+    }
+    /* Generate a branch over if the predicted inlining is correct */
+    genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
+
+    /* Reset the register state */
+    dvmCompilerResetRegPool(cUnit);
+    dvmCompilerClobberAllRegs(cUnit);
+    dvmCompilerResetNullCheck(cUnit);
+
+    /* Target for the slow invoke path */
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    /* Hook up the target to the verification branch */
+    mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
+}
+
+static bool handleFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir,
+                             BasicBlock *bb, ArmLIR *labelList)
+{
+    ArmLIR *retChainingCell = NULL;
+    ArmLIR *pcrLabel = NULL;
+
+    /* An invoke with the MIR_INLINED is effectively a no-op */
+    if (mir->OptimizationFlags & MIR_INLINED)
+        return false;
+
+    if (bb->fallThrough != NULL)
+        retChainingCell = &labelList[bb->fallThrough->id];
+
+    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:
+        case OP_INVOKE_VIRTUAL_JUMBO: {
+            ArmLIR *predChainingCell = &labelList[bb->taken->id];
+            int methodIndex =
+                cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
+                methodIndex;
+
+            /*
+             * If the invoke has non-null misPredBranchOver, we need to generate
+             * the non-inlined version of the invoke here to handle the
+             * mispredicted case.
+             */
+            if (mir->meta.callsiteInfo->misPredBranchOver) {
+                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+            }
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
+                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+            genInvokeVirtualCommon(cUnit, mir, methodIndex,
+                                   retChainingCell,
+                                   predChainingCell,
+                                   pcrLabel);
+            break;
+        }
+        /*
+         * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
+         *                ->pResMethods[BBBB]->methodIndex]
+         */
+        case OP_INVOKE_SUPER:
+        case OP_INVOKE_SUPER_RANGE:
+        case OP_INVOKE_SUPER_JUMBO: {
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod == cUnit->method->clazz->super->vtable[
+                                     cUnit->method->clazz->pDvmDex->
+                                       pResMethods[dInsn->vB]->methodIndex]);
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
+                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+                const Method *calleeMethod = mir->meta.callsiteInfo->method;
+                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+                assert(calleeAddr);
+                genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
+                                              retChainingCell);
+            } else {
+                /* r0 = calleeMethod */
+                loadConstant(cUnit, r0, (int) calleeMethod);
+
+                genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+                                         calleeMethod);
+            }
+            break;
+        }
+        /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
+        case OP_INVOKE_DIRECT:
+        case OP_INVOKE_DIRECT_RANGE:
+        case OP_INVOKE_DIRECT_JUMBO: {
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod ==
+                   cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
+                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+            /* r0 = calleeMethod */
+            loadConstant(cUnit, r0, (int) calleeMethod);
+
+            genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+                                     calleeMethod);
+            break;
+        }
+        /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
+        case OP_INVOKE_STATIC:
+        case OP_INVOKE_STATIC_RANGE:
+        case OP_INVOKE_STATIC_JUMBO: {
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod ==
+                   cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC)
+                genProcessArgsNoRange(cUnit, mir, dInsn,
+                                      NULL /* no null check */);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn,
+                                    NULL /* no null check */);
+
+            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+                const Method *calleeMethod = mir->meta.callsiteInfo->method;
+                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+                assert(calleeAddr);
+                genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
+                                              retChainingCell);
+            } else {
+                /* r0 = calleeMethod */
+                loadConstant(cUnit, r0, (int) calleeMethod);
+
+                genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+                                         calleeMethod);
+            }
+            break;
+        }
+        /*
+         * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
+         *                    BBBB, method, method->clazz->pDvmDex)
+         *
+         * The following is an example of generated code for
+         *      "invoke-interface v0"
+         *
+         * -------- dalvik offset: 0x0008 @ invoke-interface v0
+         * 0x47357e36 : ldr     r0, [r5, #0]   --+
+         * 0x47357e38 : sub     r7,r5,#24        |
+         * 0x47357e3c : cmp     r0, #0           | genProcessArgsNoRange
+         * 0x47357e3e : beq     0x47357e82       |
+         * 0x47357e40 : stmia   r7, <r0>       --+
+         * 0x47357e42 : ldr     r4, [pc, #120] --> r4 <- dalvikPC of this invoke
+         * 0x47357e44 : add     r1, pc, #64    --> r1 <- &retChainingCell
+         * 0x47357e46 : add     r2, pc, #72    --> r2 <- &predictedChainingCell
+         * 0x47357e48 : blx_1   0x47348190     --+ TEMPLATE_INVOKE_METHOD_
+         * 0x47357e4a : blx_2   see above      --+     PREDICTED_CHAIN
+         * 0x47357e4c : b       0x47357e90     --> off to the predicted chain
+         * 0x47357e4e : b       0x47357e82     --> punt to the interpreter
+         * 0x47357e50 : mov     r8, r1         --+
+         * 0x47357e52 : mov     r9, r2           |
+         * 0x47357e54 : ldr     r2, [pc, #96]    |
+         * 0x47357e56 : mov     r10, r3          |
+         * 0x47357e58 : movs    r0, r3           | dvmFindInterfaceMethodInCache
+         * 0x47357e5a : ldr     r3, [pc, #88]    |
+         * 0x47357e5c : ldr     r7, [pc, #80]    |
+         * 0x47357e5e : mov     r1, #1452        |
+         * 0x47357e62 : blx     r7             --+
+         * 0x47357e64 : cmp     r0, #0         --> calleeMethod == NULL?
+         * 0x47357e66 : bne     0x47357e6e     --> branch over the throw if !r0
+         * 0x47357e68 : ldr     r0, [pc, #80]  --> load Dalvik PC of the invoke
+         * 0x47357e6a : blx_1   0x47348494     --+ TEMPLATE_THROW_EXCEPTION_
+         * 0x47357e6c : blx_2   see above      --+     COMMON
+         * 0x47357e6e : mov     r1, r8         --> r1 <- &retChainingCell
+         * 0x47357e70 : cmp     r1, #0         --> compare against 0
+         * 0x47357e72 : bgt     0x47357e7c     --> >=0? don't rechain
+         * 0x47357e74 : ldr     r7, [pc, #off] --+
+         * 0x47357e76 : mov     r2, r9           | dvmJitToPatchPredictedChain
+         * 0x47357e78 : mov     r3, r10          |
+         * 0x47357e7a : blx     r7             --+
+         * 0x47357e7c : add     r1, pc, #8     --> r1 <- &retChainingCell
+         * 0x47357e7e : blx_1   0x4734809c     --+ TEMPLATE_INVOKE_METHOD_NO_OPT
+         * 0x47357e80 : blx_2   see above      --+
+         * -------- reconstruct dalvik PC : 0x425719dc @ +0x0008
+         * 0x47357e82 : ldr     r0, [pc, #56]
+         * Exception_Handling:
+         * 0x47357e84 : ldr     r1, [r6, #92]
+         * 0x47357e86 : blx     r1
+         * 0x47357e88 : .align4
+         * -------- chaining cell (hot): 0x000b
+         * 0x47357e88 : ldr     r0, [r6, #104]
+         * 0x47357e8a : blx     r0
+         * 0x47357e8c : data    0x19e2(6626)
+         * 0x47357e8e : data    0x4257(16983)
+         * 0x47357e90 : .align4
+         * -------- chaining cell (predicted)
+         * 0x47357e90 : data    0xe7fe(59390)  --> will be patched into bx
+         * 0x47357e92 : data    0x0000(0)
+         * 0x47357e94 : data    0x0000(0)      --> class
+         * 0x47357e96 : data    0x0000(0)
+         * 0x47357e98 : data    0x0000(0)      --> method
+         * 0x47357e9a : data    0x0000(0)
+         * 0x47357e9c : data    0x0000(0)      --> rechain count
+         * 0x47357e9e : data    0x0000(0)
+         * -------- end of chaining cells (0x006c)
+         * 0x47357eb0 : .word (0xad03e369)
+         * 0x47357eb4 : .word (0x28a90)
+         * 0x47357eb8 : .word (0x41a63394)
+         * 0x47357ebc : .word (0x425719dc)
+         */
+        case OP_INVOKE_INTERFACE:
+        case OP_INVOKE_INTERFACE_RANGE:
+        case OP_INVOKE_INTERFACE_JUMBO: {
+            ArmLIR *predChainingCell = &labelList[bb->taken->id];
+
+            /*
+             * If the invoke has non-null misPredBranchOver, we need to generate
+             * the non-inlined version of the invoke here to handle the
+             * mispredicted case.
+             */
+            if (mir->meta.callsiteInfo->misPredBranchOver) {
+                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+            }
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
+                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+            /* "this" is already left in r0 by genProcessArgs* */
+
+            /* r4PC = dalvikCallsite */
+            loadConstant(cUnit, r4PC,
+                         (int) (cUnit->method->insns + mir->offset));
+
+            /* r1 = &retChainingCell */
+            ArmLIR *addrRetChain =
+                opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
+            addrRetChain->generic.target = (LIR *) retChainingCell;
+
+            /* r2 = &predictedChainingCell */
+            ArmLIR *predictedChainingCell =
+                opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0);
+            predictedChainingCell->generic.target = (LIR *) predChainingCell;
+
+            genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+                TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
+                TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
+
+            /* return through lr - jump to the chaining cell */
+            genUnconditionalBranch(cUnit, predChainingCell);
+
+            /*
+             * null-check on "this" may have been eliminated, but we still need
+             * a PC-reconstruction label for stack overflow bailout.
+             */
+            if (pcrLabel == NULL) {
+                int dPC = (int) (cUnit->method->insns + mir->offset);
+                pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+                pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+                pcrLabel->operands[0] = dPC;
+                pcrLabel->operands[1] = mir->offset;
+                /* Insert the place holder to the growable list */
+                dvmInsertGrowableList(&cUnit->pcReconstructionList,
+                                      (intptr_t) pcrLabel);
+            }
+
+            /* return through lr+2 - punt to the interpreter */
+            genUnconditionalBranch(cUnit, pcrLabel);
+
+            /*
+             * return through lr+4 - fully resolve the callee method.
+             * r1 <- count
+             * r2 <- &predictedChainCell
+             * r3 <- this->class
+             * r4 <- dPC
+             * r7 <- this->class->vtable
+             */
+
+            /* Save count, &predictedChainCell, and class to high regs first */
+            genRegCopy(cUnit, r8, r1);
+            genRegCopy(cUnit, r9, r2);
+            genRegCopy(cUnit, r10, r3);
+
+            /* r0 now contains this->clazz */
+            genRegCopy(cUnit, r0, r3);
+
+            /* 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);
+
+            LOAD_FUNC_ADDR(cUnit, r7,
+                           (intptr_t) dvmFindInterfaceMethodInCache);
+            opReg(cUnit, kOpBlx, r7);
+            /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
+
+            dvmCompilerClobberCallRegs(cUnit);
+            /* generate a branch over if the interface method is resolved */
+            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+            /*
+             * calleeMethod == NULL -> throw
+             */
+            loadConstant(cUnit, r0,
+                         (int) (cUnit->method->insns + mir->offset));
+            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+            /* noreturn */
+
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+            target->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR *) target;
+
+            genRegCopy(cUnit, r1, r8);
+
+            /* Check if rechain limit is reached */
+            ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt,
+                                                       r1, 0);
+
+            LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain);
+
+            genRegCopy(cUnit, r1, r6SELF);
+            genRegCopy(cUnit, r2, r9);
+            genRegCopy(cUnit, r3, r10);
+
+            /*
+             * r0 = calleeMethod
+             * r2 = &predictedChainingCell
+             * r3 = class
+             *
+             * &returnChainingCell has been loaded into r1 but is not needed
+             * when patching the chaining cell and will be clobbered upon
+             * returning so it will be reconstructed again.
+             */
+            opReg(cUnit, kOpBlx, r7);
+
+            /* r1 = &retChainingCell */
+            addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
+            addrRetChain->generic.target = (LIR *) retChainingCell;
+
+            bypassRechaining->generic.target = (LIR *) addrRetChain;
+
+            /*
+             * r0 = this, r1 = calleeMethod,
+             * r1 = &ChainingCell,
+             * r4PC = callsiteDPC,
+             */
+            genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
+                TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
+                TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(WITH_JIT_TUNING)
+            gDvmJit.invokePolymorphic++;
+#endif
+            /* Handle exceptions using the interpreter */
+            genTrap(cUnit, mir->offset, pcrLabel);
+            break;
+        }
+        case OP_INVOKE_OBJECT_INIT_JUMBO:
+        case OP_INVOKE_OBJECT_INIT_RANGE:
+        case OP_FILLED_NEW_ARRAY:
+        case OP_FILLED_NEW_ARRAY_RANGE:
+        case OP_FILLED_NEW_ARRAY_JUMBO: {
+            /* 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, ArmLIR *labelList)
+{
+    ArmLIR *pcrLabel = NULL;
+
+    /* An invoke with the MIR_INLINED is effectively a no-op */
+    if (mir->OptimizationFlags & MIR_INLINED)
+        return false;
+
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    switch (mir->dalvikInsn.opcode) {
+        /* calleeMethod = this->clazz->vtable[BBBB] */
+        case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+        case OP_INVOKE_VIRTUAL_QUICK: {
+            int methodIndex = dInsn->vB;
+            ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
+            ArmLIR *predChainingCell = &labelList[bb->taken->id];
+
+            /*
+             * If the invoke has non-null misPredBranchOver, we need to generate
+             * the non-inlined version of the invoke here to handle the
+             * mispredicted case.
+             */
+            if (mir->meta.callsiteInfo->misPredBranchOver) {
+                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
+            }
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL_QUICK)
+                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+
+            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
+                const Method *calleeMethod = mir->meta.callsiteInfo->method;
+                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
+                assert(calleeAddr);
+                genInvokeVirtualWholeMethod(cUnit, mir, calleeAddr,
+                                            retChainingCell);
+            }
+
+            genInvokeVirtualCommon(cUnit, mir, methodIndex,
+                                   retChainingCell,
+                                   predChainingCell,
+                                   pcrLabel);
+            break;
+        }
+        /* calleeMethod = method->clazz->super->vtable[BBBB] */
+        case OP_INVOKE_SUPER_QUICK:
+        case OP_INVOKE_SUPER_QUICK_RANGE: {
+            /* Grab the method ptr directly from what the interpreter sees */
+            const Method *calleeMethod = mir->meta.callsiteInfo->method;
+            assert(calleeMethod ==
+                   cUnit->method->clazz->super->vtable[dInsn->vB]);
+
+            if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER_QUICK)
+                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+            else
+                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+            /* r0 = calleeMethod */
+            loadConstant(cUnit, r0, (int) calleeMethod);
+
+            genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
+                                     calleeMethod);
+            break;
+        }
+        default:
+            return true;
+    }
+    return false;
+}
+
+/*
+ * This operation is complex enough that we'll do it partly inline
+ * and partly with a handler.  NOTE: the handler uses hardcoded
+ * values for string object offsets and must be revisitied if the
+ * layout changes.
+ */
+static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
+{
+#if defined(USE_GLOBAL_STRING_DEFS)
+    return handleExecuteInlineC(cUnit, mir);
+#else
+    ArmLIR *rollback;
+    RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
+
+    loadValueDirectFixed(cUnit, rlThis, r0);
+    loadValueDirectFixed(cUnit, rlComp, r1);
+    /* Test objects for NULL */
+    rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
+    genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
+    /*
+     * TUNING: we could check for object pointer equality before invoking
+     * handler. Unclear whether the gain would be worth the added code size
+     * expansion.
+     */
+    genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
+    storeValue(cUnit, inlinedTarget(cUnit, mir, false),
+               dvmCompilerGetReturn(cUnit));
+    return false;
+#endif
+}
+
+static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
+{
+#if defined(USE_GLOBAL_STRING_DEFS)
+    return handleExecuteInlineC(cUnit, mir);
+#else
+    RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
+
+    loadValueDirectFixed(cUnit, rlThis, r0);
+    loadValueDirectFixed(cUnit, rlChar, r1);
+    RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
+    loadValueDirectFixed(cUnit, rlStart, r2);
+    /* Test objects for NULL */
+    genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
+    genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
+    storeValue(cUnit, inlinedTarget(cUnit, mir, false),
+               dvmCompilerGetReturn(cUnit));
+    return false;
+#endif
+}
+
+// Generates an inlined String.isEmpty or String.length.
+static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
+                                            bool isEmpty)
+{
+    // dst = src.length();
+    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
+                 rlResult.lowReg);
+    if (isEmpty) {
+        // dst = (dst == 0);
+        int tReg = dvmCompilerAllocTemp(cUnit);
+        opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg);
+        opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg);
+    }
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+    return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
+}
+
+static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
+{
+    return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
+}
+
+static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
+{
+    int contents = OFFSETOF_MEMBER(ArrayObject, contents);
+    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    RegLocation rlResult;
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
+    int regMax = dvmCompilerAllocTemp(cUnit);
+    int regOff = dvmCompilerAllocTemp(cUnit);
+    int regPtr = dvmCompilerAllocTemp(cUnit);
+    ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
+                                    mir->offset, NULL);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
+    genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
+    dvmCompilerFreeTemp(cUnit, regMax);
+    opRegImm(cUnit, kOpAdd, regPtr, contents);
+    opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    int signReg = dvmCompilerAllocTemp(cUnit);
+    /*
+     * abs(x) = y<=x>>31, (x+y)^y.
+     * Thumb2's IT block also yields 3 instructions, but imposes
+     * scheduling constraints.
+     */
+    opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
+    opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+    opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
+    rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    int signReg = dvmCompilerAllocTemp(cUnit);
+    /*
+     * abs(x) = y<=x>>31, (x+y)^y.
+     * Thumb2 IT block allows slightly shorter sequence,
+     * but introduces a scheduling barrier.  Stick with this
+     * mechanism for now.
+     */
+    opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
+    opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+    opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
+    opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+    opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    // Just move from source to destination...
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    storeValue(cUnit, rlDest, rlSrc);
+    return false;
+}
+
+static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    // Just move from source to destination...
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
+    storeValueWide(cUnit, rlDest, rlSrc);
+    return false;
+}
+
+/*
+ * JITs a call to a C function.
+ * TODO: use this for faster native method invocation for simple native
+ * methods (http://b/3069458).
+ */
+static bool handleExecuteInlineC(CompilationUnit *cUnit, MIR *mir)
+{
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    int operation = dInsn->vB;
+    unsigned int i;
+    const InlineOperation* inLineTable = dvmGetInlineOpsTable();
+    uintptr_t fn = (int) inLineTable[operation].func;
+    if (fn == 0) {
+        dvmCompilerAbort(cUnit);
+    }
+    dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
+    dvmCompilerClobberCallRegs(cUnit);
+    dvmCompilerClobber(cUnit, r4PC);
+    dvmCompilerClobber(cUnit, r7);
+    int offset = offsetof(Thread, interpSave.retval);
+    opRegRegImm(cUnit, kOpAdd, r4PC, r6SELF, offset);
+    opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
+    LOAD_FUNC_ADDR(cUnit, r4PC, fn);
+    genExportPC(cUnit, mir);
+    for (i=0; i < dInsn->vA; i++) {
+        loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
+    }
+    opReg(cUnit, kOpBlx, r4PC);
+    opRegImm(cUnit, kOpAdd, r13sp, 8);
+    /* NULL? */
+    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
+    genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR *) target;
+    return false;
+}
+
+/*
+ * NOTE: Handles both range and non-range versions (arguments
+ * have already been normalized by this point).
+ */
+static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
+{
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    assert(dInsn->opcode == OP_EXECUTE_INLINE_RANGE ||
+           dInsn->opcode == OP_EXECUTE_INLINE);
+    switch (dInsn->vB) {
+        case INLINE_EMPTYINLINEMETHOD:
+            return false;  /* Nop */
+
+        /* These ones we potentially JIT inline. */
+        case INLINE_STRING_LENGTH:
+            return genInlinedStringLength(cUnit, mir);
+        case INLINE_STRING_IS_EMPTY:
+            return genInlinedStringIsEmpty(cUnit, mir);
+        case INLINE_MATH_ABS_INT:
+            return genInlinedAbsInt(cUnit, mir);
+        case INLINE_MATH_ABS_LONG:
+            return genInlinedAbsLong(cUnit, mir);
+        case INLINE_MATH_MIN_INT:
+            return genInlinedMinMaxInt(cUnit, mir, true);
+        case INLINE_MATH_MAX_INT:
+            return genInlinedMinMaxInt(cUnit, mir, false);
+        case INLINE_STRING_CHARAT:
+            return genInlinedStringCharAt(cUnit, mir);
+        case INLINE_MATH_SQRT:
+            return genInlineSqrt(cUnit, mir);
+        case INLINE_MATH_ABS_FLOAT:
+            return genInlinedAbsFloat(cUnit, mir);
+        case INLINE_MATH_ABS_DOUBLE:
+            return genInlinedAbsDouble(cUnit, mir);
+        case INLINE_STRING_COMPARETO:
+            return genInlinedCompareTo(cUnit, mir);
+        case INLINE_STRING_FASTINDEXOF_II:
+            return genInlinedFastIndexOf(cUnit, mir);
+        case INLINE_FLOAT_TO_RAW_INT_BITS:
+        case INLINE_INT_BITS_TO_FLOAT:
+            return genInlinedIntFloatConversion(cUnit, mir);
+        case INLINE_DOUBLE_TO_RAW_LONG_BITS:
+        case INLINE_LONG_BITS_TO_DOUBLE:
+            return genInlinedLongDoubleConversion(cUnit, mir);
+
+        /*
+         * These ones we just JIT a call to a C function for.
+         * TODO: special-case these in the other "invoke" call paths.
+         */
+        case INLINE_STRING_EQUALS:
+        case INLINE_MATH_COS:
+        case INLINE_MATH_SIN:
+        case INLINE_FLOAT_TO_INT_BITS:
+        case INLINE_DOUBLE_TO_LONG_BITS:
+            return handleExecuteInlineC(cUnit, mir);
+    }
+    dvmCompilerAbort(cUnit);
+    return false; // Not reachable; keeps compiler happy.
+}
+
+static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
+{
+    //TUNING: We're using core regs here - not optimal when target is a double
+    RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    loadConstantNoClobber(cUnit, rlResult.lowReg,
+                          mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
+    loadConstantNoClobber(cUnit, rlResult.highReg,
+                          (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
+    storeValueWide(cUnit, rlDest, rlResult);
+    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.
+ */
+
+/*
+ * Insert a
+ *    b   .+4
+ *    nop
+ * pair at the beginning of a chaining cell.  This serves as the
+ * switch branch that selects between reverting to the interpreter or
+ * not.  Once the cell is chained to a translation, the cell will
+ * contain a 32-bit branch.  Subsequent chain/unchain operations will
+ * then only alter that first 16-bits - the "b .+4" for unchaining,
+ * and the restoration of the first half of the 32-bit branch for
+ * rechaining.
+ */
+static void insertChainingSwitch(CompilationUnit *cUnit)
+{
+    ArmLIR *branch = newLIR0(cUnit, kThumbBUncond);
+    newLIR2(cUnit, kThumbOrr, r0, r0);
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branch->generic.target = (LIR *) target;
+}
+
+/* Chaining cell for code that may need warmup. */
+static void handleNormalChainingCell(CompilationUnit *cUnit,
+                                     unsigned int offset)
+{
+    /*
+     * Use raw instruction constructors to guarantee that the generated
+     * instructions fit the predefined cell size.
+     */
+    insertChainingSwitch(cUnit);
+    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
+            offsetof(Thread,
+                     jitToInterpEntries.dvmJitToInterpNormal) >> 2);
+    newLIR1(cUnit, kThumbBlxR, r0);
+    addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
+}
+
+/*
+ * Chaining cell for instructions that immediately following already translated
+ * code.
+ */
+static void handleHotChainingCell(CompilationUnit *cUnit,
+                                  unsigned int offset)
+{
+    /*
+     * Use raw instruction constructors to guarantee that the generated
+     * instructions fit the predefined cell size.
+     */
+    insertChainingSwitch(cUnit);
+    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
+            offsetof(Thread,
+                     jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
+    newLIR1(cUnit, kThumbBlxR, r0);
+    addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
+}
+
+/* Chaining cell for branches that branch back into the same basic block */
+static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
+                                             unsigned int offset)
+{
+    /*
+     * Use raw instruction constructors to guarantee that the generated
+     * instructions fit the predefined cell size.
+     */
+    insertChainingSwitch(cUnit);
+#if defined(WITH_SELF_VERIFICATION)
+    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
+        offsetof(Thread,
+                 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
+#else
+    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
+        offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
+#endif
+    newLIR1(cUnit, kThumbBlxR, r0);
+    addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
+}
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
+                                              const Method *callee)
+{
+    /*
+     * Use raw instruction constructors to guarantee that the generated
+     * instructions fit the predefined cell size.
+     */
+    insertChainingSwitch(cUnit);
+    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
+            offsetof(Thread,
+                     jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
+    newLIR1(cUnit, kThumbBlxR, r0);
+    addWordData(cUnit, NULL, (int) (callee->insns));
+}
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
+{
+
+    /* Should not be executed in the initial state */
+    addWordData(cUnit, NULL, PREDICTED_CHAIN_BX_PAIR_INIT);
+    /* To be filled: class */
+    addWordData(cUnit, NULL, PREDICTED_CHAIN_CLAZZ_INIT);
+    /* To be filled: method */
+    addWordData(cUnit, NULL, PREDICTED_CHAIN_METHOD_INIT);
+    /*
+     * Rechain count. The initial value of 0 here will trigger chaining upon
+     * the first invocation of this callsite.
+     */
+    addWordData(cUnit, NULL, PREDICTED_CHAIN_COUNTER_INIT);
+}
+
+/* Load the Dalvik PC into r0 and jump to the specified target */
+static void handlePCReconstruction(CompilationUnit *cUnit,
+                                   ArmLIR *targetLabel)
+{
+    ArmLIR **pcrLabel =
+        (ArmLIR **) cUnit->pcReconstructionList.elemList;
+    int numElems = cUnit->pcReconstructionList.numUsed;
+    int i;
+
+    /*
+     * We should never reach here through fall-through code, so insert
+     * a bomb to signal troubles immediately.
+     */
+    if (numElems) {
+        newLIR0(cUnit, kThumbUndefined);
+    }
+
+    for (i = 0; i < numElems; i++) {
+        dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
+        /* r0 = dalvik PC */
+        loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
+        genUnconditionalBranch(cUnit, targetLabel);
+    }
+}
+
+static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
+    "kMirOpPhi",
+    "kMirOpNullNRangeUpCheck",
+    "kMirOpNullNRangeDownCheck",
+    "kMirOpLowerBound",
+    "kMirOpPunt",
+    "kMirOpCheckInlinePrediction",
+};
+
+/*
+ * vA = arrayReg;
+ * vB = idxReg;
+ * vC = endConditionReg;
+ * arg[0] = maxC
+ * arg[1] = minC
+ * arg[2] = loopBranchConditionCode
+ */
+static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
+{
+    /*
+     * NOTE: these synthesized blocks don't have ssa names assigned
+     * for Dalvik registers.  However, because they dominate the following
+     * blocks we can simply use the Dalvik name w/ subscript 0 as the
+     * ssa name.
+     */
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+    const int maxC = dInsn->arg[0];
+    int regLength;
+    RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
+    RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
+
+    /* regArray <- arrayRef */
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
+    genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
+                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
+
+    /* regLength <- len(arrayRef) */
+    regLength = dvmCompilerAllocTemp(cUnit);
+    loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
+
+    int delta = maxC;
+    /*
+     * If the loop end condition is ">=" instead of ">", then the largest value
+     * of the index is "endCondition - 1".
+     */
+    if (dInsn->arg[2] == OP_IF_GE) {
+        delta--;
+    }
+
+    if (delta) {
+        int tReg = dvmCompilerAllocTemp(cUnit);
+        opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
+        rlIdxEnd.lowReg = tReg;
+        dvmCompilerFreeTemp(cUnit, tReg);
+    }
+    /* Punt if "regIdxEnd < len(Array)" is false */
+    genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
+                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
+}
+
+/*
+ * vA = arrayReg;
+ * vB = idxReg;
+ * vC = endConditionReg;
+ * arg[0] = maxC
+ * arg[1] = minC
+ * arg[2] = loopBranchConditionCode
+ */
+static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
+{
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
+    const int regLength = dvmCompilerAllocTemp(cUnit);
+    const int maxC = dInsn->arg[0];
+    RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
+    RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
+
+    /* regArray <- arrayRef */
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
+    genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
+                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
+
+    /* regLength <- len(arrayRef) */
+    loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
+
+    if (maxC) {
+        int tReg = dvmCompilerAllocTemp(cUnit);
+        opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
+        rlIdxInit.lowReg = tReg;
+        dvmCompilerFreeTemp(cUnit, tReg);
+    }
+
+    /* Punt if "regIdxInit < len(Array)" is false */
+    genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
+                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
+}
+
+/*
+ * vA = idxReg;
+ * vB = minC;
+ */
+static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
+{
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    const int minC = dInsn->vB;
+    RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
+
+    /* regIdx <- initial index value */
+    rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
+
+    /* Punt if "regIdxInit + minC >= 0" is false */
+    genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
+                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
+}
+
+/*
+ * vC = this
+ *
+ * A predicted inlining target looks like the following, where instructions
+ * between 0x4858de66 and 0x4858de72 are checking if the predicted class
+ * matches "this", and the verificaion code is generated by this routine.
+ *
+ * (C) means the instruction is inlined from the callee, and (PI) means the
+ * instruction is the predicted inlined invoke, whose corresponding
+ * instructions are still generated to handle the mispredicted case.
+ *
+ * D/dalvikvm(   86): -------- kMirOpCheckInlinePrediction
+ * D/dalvikvm(   86): 0x4858de66 (0002): ldr     r0, [r5, #68]
+ * D/dalvikvm(   86): 0x4858de68 (0004): ldr     r1, [pc, #140]
+ * D/dalvikvm(   86): 0x4858de6a (0006): cmp     r0, #0
+ * D/dalvikvm(   86): 0x4858de6c (0008): beq     0x4858deb2
+ * D/dalvikvm(   86): 0x4858de6e (000a): ldr     r2, [r0, #0]
+ * D/dalvikvm(   86): 0x4858de70 (000c): cmp     r1, r2
+ * D/dalvikvm(   86): 0x4858de72 (000e): bne     0x4858de7a
+ * D/dalvikvm(   86): -------- dalvik offset: 0x004c @ +iget-object-quick (C)
+ * v4, v17, (#8)
+ * D/dalvikvm(   86): 0x4858de74 (0010): ldr     r3, [r0, #8]
+ * D/dalvikvm(   86): 0x4858de76 (0012): str     r3, [r5, #16]
+ * D/dalvikvm(   86): -------- dalvik offset: 0x004c @
+ * +invoke-virtual-quick/range (PI) v17..v17
+ * D/dalvikvm(   86): 0x4858de78 (0014): b       0x4858debc
+ * D/dalvikvm(   86): 0x4858de7a (0016): add     r4,r5,#68
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de7e (001a): ldmia   r4, <r0>
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de80 (001c): sub     r7,r5,#24
+ * D/dalvikvm(   86): 0x4858de84 (0020): cmp     r0, #0
+ * D/dalvikvm(   86): 0x4858de86 (0022): beq     0x4858deb6
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de88 (0024): stmia   r7, <r0>
+ * D/dalvikvm(   86): -------- BARRIER
+ * D/dalvikvm(   86): 0x4858de8a (0026): ldr     r4, [pc, #104]
+ * D/dalvikvm(   86): 0x4858de8c (0028): add     r1, pc, #28
+ * D/dalvikvm(   86): 0x4858de8e (002a): add     r2, pc, #56
+ * D/dalvikvm(   86): 0x4858de90 (002c): blx_1   0x48589198
+ * D/dalvikvm(   86): 0x4858de92 (002e): blx_2   see above
+ * D/dalvikvm(   86): 0x4858de94 (0030): b       0x4858dec8
+ * D/dalvikvm(   86): 0x4858de96 (0032): b       0x4858deb6
+ * D/dalvikvm(   86): 0x4858de98 (0034): ldr     r0, [r7, #72]
+ * D/dalvikvm(   86): 0x4858de9a (0036): cmp     r1, #0
+ * D/dalvikvm(   86): 0x4858de9c (0038): bgt     0x4858dea4
+ * D/dalvikvm(   86): 0x4858de9e (003a): ldr     r7, [r6, #116]
+ * D/dalvikvm(   86): 0x4858dea0 (003c): movs    r1, r6
+ * D/dalvikvm(   86): 0x4858dea2 (003e): blx     r7
+ * D/dalvikvm(   86): 0x4858dea4 (0040): add     r1, pc, #4
+ * D/dalvikvm(   86): 0x4858dea6 (0042): blx_1   0x485890a0
+ * D/dalvikvm(   86): 0x4858dea8 (0044): blx_2   see above
+ * D/dalvikvm(   86): 0x4858deaa (0046): b       0x4858deb6
+ * D/dalvikvm(   86): 0x4858deac (0048): .align4
+ * D/dalvikvm(   86): L0x004f:
+ * D/dalvikvm(   86): -------- dalvik offset: 0x004f @ move-result-object (PI)
+ * v4, (#0), (#0)
+ * D/dalvikvm(   86): 0x4858deac (0048): ldr     r4, [r6, #8]
+ * D/dalvikvm(   86): 0x4858deae (004a): str     r4, [r5, #16]
+ * D/dalvikvm(   86): 0x4858deb0 (004c): b       0x4858debc
+ * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm(   86): 0x4858deb2 (004e): ldr     r0, [pc, #64]
+ * D/dalvikvm(   86): 0x4858deb4 (0050): b       0x4858deb8
+ * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
+ * D/dalvikvm(   86): 0x4858deb6 (0052): ldr     r0, [pc, #60]
+ * D/dalvikvm(   86): Exception_Handling:
+ * D/dalvikvm(   86): 0x4858deb8 (0054): ldr     r1, [r6, #100]
+ * D/dalvikvm(   86): 0x4858deba (0056): blx     r1
+ * D/dalvikvm(   86): 0x4858debc (0058): .align4
+ * D/dalvikvm(   86): -------- chaining cell (hot): 0x0050
+ * D/dalvikvm(   86): 0x4858debc (0058): b       0x4858dec0
+ * D/dalvikvm(   86): 0x4858debe (005a): orrs    r0, r0
+ * D/dalvikvm(   86): 0x4858dec0 (005c): ldr     r0, [r6, #112]
+ * D/dalvikvm(   86): 0x4858dec2 (005e): blx     r0
+ * D/dalvikvm(   86): 0x4858dec4 (0060): data    0xefd4(61396)
+ * D/dalvikvm(   86): 0x4858dec6 (0062): data    0x42be(17086)
+ * D/dalvikvm(   86): 0x4858dec8 (0064): .align4
+ * D/dalvikvm(   86): -------- chaining cell (predicted)
+ * D/dalvikvm(   86): 0x4858dec8 (0064): data    0xe7fe(59390)
+ * D/dalvikvm(   86): 0x4858deca (0066): data    0x0000(0)
+ * D/dalvikvm(   86): 0x4858decc (0068): data    0x0000(0)
+ * D/dalvikvm(   86): 0x4858dece (006a): data    0x0000(0)
+ * :
+ */
+static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
+{
+    CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
+    RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
+
+    rlThis = loadValue(cUnit, rlThis, kCoreReg);
+    int regPredictedClass = dvmCompilerAllocTemp(cUnit);
+    loadClassPointer(cUnit, regPredictedClass, (int) callsiteInfo);
+    genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
+                 NULL);/* null object? */
+    int regActualClass = dvmCompilerAllocTemp(cUnit);
+    loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
+    opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
+    /*
+     * Set the misPredBranchOver target so that it will be generated when the
+     * code for the non-optimized invoke is generated.
+     */
+    callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe);
+}
+
+/* Extended MIR instructions like PHI */
+static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
+{
+    int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
+    char *msg = (char *)dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
+                                        false);
+    strcpy(msg, extendedMIROpNames[opOffset]);
+    newLIR1(cUnit, kArmPseudoExtended, (int) msg);
+
+    switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
+        case kMirOpPhi: {
+            char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+            break;
+        }
+        case kMirOpNullNRangeUpCheck: {
+            genHoistedChecksForCountUpLoop(cUnit, mir);
+            break;
+        }
+        case kMirOpNullNRangeDownCheck: {
+            genHoistedChecksForCountDownLoop(cUnit, mir);
+            break;
+        }
+        case kMirOpLowerBound: {
+            genHoistedLowerBoundCheck(cUnit, mir);
+            break;
+        }
+        case kMirOpPunt: {
+            genUnconditionalBranch(cUnit,
+                                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
+            break;
+        }
+        case kMirOpCheckInlinePrediction: {
+            genValidationForPredictedInline(cUnit, mir);
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+/*
+ * Create a PC-reconstruction cell for the starting offset of this trace.
+ * Since the PCR cell is placed near the end of the compiled code which is
+ * usually out of range for a conditional branch, we put two branches (one
+ * branch over to the loop body and one layover branch to the actual PCR) at the
+ * end of the entry block.
+ */
+static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
+                                ArmLIR *bodyLabel)
+{
+    /* Set up the place holder to reconstruct this Dalvik PC */
+    ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    pcrLabel->opcode = kArmPseudoPCReconstructionCell;
+    pcrLabel->operands[0] =
+        (int) (cUnit->method->insns + entry->startOffset);
+    pcrLabel->operands[1] = entry->startOffset;
+    /* Insert the place holder to the growable list */
+    dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
+
+    /*
+     * Next, create two branches - one branch over to the loop body and the
+     * other branch to the PCR cell to punt.
+     */
+    ArmLIR *branchToBody = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    branchToBody->opcode = kThumbBUncond;
+    branchToBody->generic.target = (LIR *) bodyLabel;
+    setupResourceMasks(branchToBody);
+    cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
+
+    ArmLIR *branchToPCR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    branchToPCR->opcode = kThumbBUncond;
+    branchToPCR->generic.target = (LIR *) pcrLabel;
+    setupResourceMasks(branchToPCR);
+    cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static bool selfVerificationPuntOps(MIR *mir)
+{
+    DecodedInstruction *decInsn = &mir->dalvikInsn;
+
+    /*
+     * All opcodes that can throw exceptions and use the
+     * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
+     * under self-verification mode.
+     */
+    switch (decInsn->opcode) {
+        case OP_MONITOR_ENTER:
+        case OP_MONITOR_EXIT:
+        case OP_NEW_INSTANCE:
+        case OP_NEW_INSTANCE_JUMBO:
+        case OP_NEW_ARRAY:
+        case OP_NEW_ARRAY_JUMBO:
+        case OP_CHECK_CAST:
+        case OP_CHECK_CAST_JUMBO:
+        case OP_MOVE_EXCEPTION:
+        case OP_FILL_ARRAY_DATA:
+        case OP_EXECUTE_INLINE:
+        case OP_EXECUTE_INLINE_RANGE:
+            return true;
+        default:
+            return false;
+    }
+}
+#endif
+
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
+{
+    /* Used to hold the labels of each block */
+    ArmLIR *labelList =
+        (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
+    ArmLIR *headLIR = NULL;
+    GrowableList chainingListByType[kChainingCellGap];
+    int i;
+
+    /*
+     * Initialize various types chaining lists.
+     */
+    for (i = 0; i < kChainingCellGap; i++) {
+        dvmInitGrowableList(&chainingListByType[i], 2);
+    }
+
+    /* Clear the visited flag for each block */
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag,
+                                          kAllNodes, false /* isIterative */);
+
+    GrowableListIterator iterator;
+    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
+
+    /* Traces start with a profiling entry point.  Generate it here */
+    cUnit->profileCodeSize = genTraceProfileEntry(cUnit);
+
+    /* Handle the content in each basic block */
+    for (i = 0; ; i++) {
+        MIR *mir;
+        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        if (bb->visited == true) continue;
+
+        labelList[i].operands[0] = bb->startOffset;
+
+        if (bb->blockType >= kChainingCellGap) {
+            if (bb->isFallThroughFromInvoke == true) {
+                /* Align this block first since it is a return chaining cell */
+                newLIR0(cUnit, kArmPseudoPseudoAlign4);
+            }
+            /*
+             * Append the label pseudo LIR first. Chaining cells will be handled
+             * separately afterwards.
+             */
+            dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
+        }
+
+        if (bb->blockType == kEntryBlock) {
+            labelList[i].opcode = kArmPseudoEntryBlock;
+            if (bb->firstMIRInsn == NULL) {
+                continue;
+            } else {
+              setupLoopEntryBlock(cUnit, bb,
+                                  &labelList[bb->fallThrough->id]);
+            }
+        } else if (bb->blockType == kExitBlock) {
+            labelList[i].opcode = kArmPseudoExitBlock;
+            goto gen_fallthrough;
+        } else if (bb->blockType == kDalvikByteCode) {
+            if (bb->hidden == true) continue;
+            labelList[i].opcode = kArmPseudoNormalBlockLabel;
+            /* Reset the register state */
+            dvmCompilerResetRegPool(cUnit);
+            dvmCompilerClobberAllRegs(cUnit);
+            dvmCompilerResetNullCheck(cUnit);
+        } else {
+            switch (bb->blockType) {
+                case kChainingCellNormal:
+                    labelList[i].opcode = kArmPseudoChainingCellNormal;
+                    /* handle the codegen later */
+                    dvmInsertGrowableList(
+                        &chainingListByType[kChainingCellNormal], i);
+                    break;
+                case kChainingCellInvokeSingleton:
+                    labelList[i].opcode =
+                        kArmPseudoChainingCellInvokeSingleton;
+                    labelList[i].operands[0] =
+                        (int) bb->containingMethod;
+                    /* handle the codegen later */
+                    dvmInsertGrowableList(
+                        &chainingListByType[kChainingCellInvokeSingleton], i);
+                    break;
+                case kChainingCellInvokePredicted:
+                    labelList[i].opcode =
+                        kArmPseudoChainingCellInvokePredicted;
+                    /*
+                     * Move the cached method pointer from operand 1 to 0.
+                     * Operand 0 was clobbered earlier in this routine to store
+                     * the block starting offset, which is not applicable to
+                     * predicted chaining cell.
+                     */
+                    labelList[i].operands[0] = labelList[i].operands[1];
+                    /* handle the codegen later */
+                    dvmInsertGrowableList(
+                        &chainingListByType[kChainingCellInvokePredicted], i);
+                    break;
+                case kChainingCellHot:
+                    labelList[i].opcode =
+                        kArmPseudoChainingCellHot;
+                    /* handle the codegen later */
+                    dvmInsertGrowableList(
+                        &chainingListByType[kChainingCellHot], i);
+                    break;
+                case kPCReconstruction:
+                    /* Make sure exception handling block is next */
+                    labelList[i].opcode =
+                        kArmPseudoPCReconstructionBlockLabel;
+                    handlePCReconstruction(cUnit,
+                                           &labelList[cUnit->puntBlock->id]);
+                    break;
+                case kExceptionHandling:
+                    labelList[i].opcode = kArmPseudoEHBlockLabel;
+                    if (cUnit->pcReconstructionList.numUsed) {
+                        loadWordDisp(cUnit, r6SELF, offsetof(Thread,
+                                     jitToInterpEntries.dvmJitToInterpPunt),
+                                     r1);
+                        opReg(cUnit, kOpBlx, r1);
+                    }
+                    break;
+                case kChainingCellBackwardBranch:
+                    labelList[i].opcode =
+                        kArmPseudoChainingCellBackwardBranch;
+                    /* handle the codegen later */
+                    dvmInsertGrowableList(
+                        &chainingListByType[kChainingCellBackwardBranch],
+                        i);
+                    break;
+                default:
+                    break;
+            }
+            continue;
+        }
+
+        /*
+         * Try to build a longer optimization unit. Currently if the previous
+         * block ends with a goto, we continue adding instructions and don't
+         * reset the register allocation pool.
+         */
+        for (BasicBlock *nextBB = bb; nextBB != NULL; nextBB = cUnit->nextCodegenBlock) {
+            bb = nextBB;
+            bb->visited = true;
+            cUnit->nextCodegenBlock = NULL;
+
+            for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+                dvmCompilerResetRegPool(cUnit);
+                if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
+                    dvmCompilerClobberAllRegs(cUnit);
+                }
+
+                if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
+                    dvmCompilerResetDefTracking(cUnit);
+                }
+
+                if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+                    handleExtendedMIR(cUnit, mir);
+                    continue;
+                }
+
+                Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+                InstructionFormat dalvikFormat =
+                    dexGetFormatFromOpcode(dalvikOpcode);
+                const char *note;
+                if (mir->OptimizationFlags & MIR_INLINED) {
+                    note = " (I)";
+                } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
+                    note = " (PI)";
+                } else if (mir->OptimizationFlags & MIR_CALLEE) {
+                    note = " (C)";
+                } else {
+                    note = NULL;
+                }
+
+                ArmLIR *boundaryLIR;
+
+                /*
+                 * Don't generate the boundary LIR unless we are debugging this
+                 * trace or we need a scheduling barrier.
+                 */
+                if (headLIR == NULL || cUnit->printMe == true) {
+                    boundaryLIR =
+                        newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
+                                mir->offset,
+                                (int) dvmCompilerGetDalvikDisassembly(
+                                    &mir->dalvikInsn, note));
+                    /* Remember the first LIR for this block */
+                    if (headLIR == NULL) {
+                        headLIR = boundaryLIR;
+                        /* Set the first boundaryLIR as a scheduling barrier */
+                        headLIR->defMask = ENCODE_ALL;
+                    }
+                }
+
+                /*
+                 * Don't generate the SSA annotation unless verbose mode is on
+                 */
+                if (cUnit->printMe && mir->ssaRep) {
+                    char *ssaString = dvmCompilerGetSSAString(cUnit,
+                                                              mir->ssaRep);
+                    newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+                }
+
+                bool notHandled;
+                /*
+                 * Debugging: screen the opcode first to see if it is in the
+                 * do[-not]-compile list
+                 */
+                bool singleStepMe = SINGLE_STEP_OP(dalvikOpcode);
+#if defined(WITH_SELF_VERIFICATION)
+              if (singleStepMe == false) {
+                  singleStepMe = selfVerificationPuntOps(mir);
+              }
+#endif
+                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, bb, 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:
+                        case kFmt40sc:
+                            notHandled = handleFmt20bc_Fmt40sc(cUnit, mir);
+                            break;
+                        case kFmt21c:
+                        case kFmt31c:
+                        case kFmt41c:
+                            notHandled = handleFmt21c_Fmt31c_Fmt41c(cUnit, mir);
+                            break;
+                        case kFmt21h:
+                            notHandled = handleFmt21h(cUnit, mir);
+                            break;
+                        case kFmt21s:
+                            notHandled = handleFmt21s(cUnit, mir);
+                            break;
+                        case kFmt21t:
+                            notHandled = handleFmt21t(cUnit, mir, bb,
+                                                      labelList);
+                            break;
+                        case kFmt22b:
+                        case kFmt22s:
+                            notHandled = handleFmt22b_Fmt22s(cUnit, mir);
+                            break;
+                        case kFmt22c:
+                        case kFmt52c:
+                            notHandled = handleFmt22c_Fmt52c(cUnit, mir);
+                            break;
+                        case kFmt22cs:
+                            notHandled = handleFmt22cs(cUnit, mir);
+                            break;
+                        case kFmt22t:
+                            notHandled = handleFmt22t(cUnit, mir, bb,
+                                                      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:
+                        case kFmt5rc:
+                            notHandled = handleFmt35c_3rc_5rc(cUnit, mir, bb,
+                                                          labelList);
+                            break;
+                        case kFmt3rms:
+                        case kFmt35ms:
+                            notHandled = handleFmt35ms_3rms(cUnit, mir, bb,
+                                                            labelList);
+                            break;
+                        case kFmt35mi:
+                        case kFmt3rmi:
+                            notHandled = handleExecuteInline(cUnit, mir);
+                            break;
+                        case kFmt51l:
+                            notHandled = handleFmt51l(cUnit, mir);
+                            break;
+                        default:
+                            notHandled = true;
+                            break;
+                    }
+                }
+                if (notHandled) {
+                    LOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled",
+                         mir->offset,
+                         dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+                         dalvikFormat);
+                    dvmCompilerAbort(cUnit);
+                    break;
+                }
+            }
+        }
+
+        if (bb->blockType == kEntryBlock) {
+            dvmCompilerAppendLIR(cUnit,
+                                 (LIR *) cUnit->loopAnalysis->branchToBody);
+            dvmCompilerAppendLIR(cUnit,
+                                 (LIR *) cUnit->loopAnalysis->branchToPCR);
+        }
+
+        if (headLIR) {
+            /*
+             * Eliminate redundant loads/stores and delay stores into later
+             * slots
+             */
+            dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+                                               cUnit->lastLIRInsn);
+            /* Reset headLIR which is also the optimization boundary */
+            headLIR = NULL;
+        }
+
+gen_fallthrough:
+        /*
+         * Check if the block is terminated due to trace length constraint -
+         * insert an unconditional branch to the chaining cell.
+         */
+        if (bb->needFallThroughBranch) {
+            genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+        }
+    }
+
+    /* Handle the chaining cells in predefined order */
+    for (i = 0; i < kChainingCellGap; 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];
+            BasicBlock *chainingBlock =
+                (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+                                                         blockId);
+
+            /* Align this chaining cell first */
+            newLIR0(cUnit, kArmPseudoPseudoAlign4);
+
+            /* Insert the pseudo chaining instruction */
+            dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+
+            switch (chainingBlock->blockType) {
+                case kChainingCellNormal:
+                    handleNormalChainingCell(cUnit, chainingBlock->startOffset);
+                    break;
+                case kChainingCellInvokeSingleton:
+                    handleInvokeSingletonChainingCell(cUnit,
+                        chainingBlock->containingMethod);
+                    break;
+                case kChainingCellInvokePredicted:
+                    handleInvokePredictedChainingCell(cUnit);
+                    break;
+                case kChainingCellHot:
+                    handleHotChainingCell(cUnit, chainingBlock->startOffset);
+                    break;
+                case kChainingCellBackwardBranch:
+                    handleBackwardBranchChainingCell(cUnit,
+                        chainingBlock->startOffset);
+                    break;
+                default:
+                    LOGE("Bad blocktype %d", chainingBlock->blockType);
+                    dvmCompilerAbort(cUnit);
+            }
+        }
+    }
+
+    /* Mark the bottom of chaining cells */
+    cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
+
+    /*
+     * Generate the branch to the dvmJitToInterpNoChain entry point at the end
+     * of all chaining cells for the overflow cases.
+     */
+    if (cUnit->switchOverflowPad) {
+        loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
+        loadWordDisp(cUnit, r6SELF, offsetof(Thread,
+                     jitToInterpEntries.dvmJitToInterpNoChain), r2);
+        opRegReg(cUnit, kOpAdd, r1, r1);
+        opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
+#if defined(WITH_JIT_TUNING)
+        loadConstant(cUnit, r0, kSwitchOverflow);
+#endif
+        opReg(cUnit, kOpBlx, r2);
+    }
+
+    dvmCompilerApplyGlobalOptimizations(cUnit);
+
+#if defined(WITH_SELF_VERIFICATION)
+    selfVerificationBranchInsertPass(cUnit);
+#endif
+}
+
+/*
+ * Accept the work and start compiling.  Returns true if compilation
+ * is attempted.
+ */
+bool dvmCompilerDoWork(CompilerWorkOrder *work)
+{
+    JitTraceDescription *desc;
+    bool isCompile;
+    bool success = true;
+
+    if (gDvmJit.codeCacheFull) {
+        return false;
+    }
+
+    switch (work->kind) {
+        case kWorkOrderTrace:
+            isCompile = true;
+            /* Start compilation with maximally allowed trace length */
+            desc = (JitTraceDescription *)work->info;
+            success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+                                        work->bailPtr, 0 /* no hints */);
+            break;
+        case kWorkOrderTraceDebug: {
+            bool oldPrintMe = gDvmJit.printMe;
+            gDvmJit.printMe = true;
+            isCompile = true;
+            /* Start compilation with maximally allowed trace length */
+            desc = (JitTraceDescription *)work->info;
+            success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+                                        work->bailPtr, 0 /* no hints */);
+            gDvmJit.printMe = oldPrintMe;
+            break;
+        }
+        case kWorkOrderProfileMode:
+            dvmJitChangeProfileMode((TraceProfilingModes)(int)work->info);
+            isCompile = false;
+            break;
+        default:
+            isCompile = false;
+            LOGE("Jit: unknown work order type");
+            assert(0);  // Bail if debug build, discard otherwise
+    }
+    if (!success)
+        work->result.codeAddress = NULL;
+    return isCompile;
+}
+
+/* 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 < kNumPackedOpcodes) {
+        i++;
+    }
+    if (i == kNumPackedOpcodes) {
+        return;
+    }
+    for (start = i++, streak = 1; i < kNumPackedOpcodes; 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 < kNumPackedOpcodes) {
+                i++;
+            }
+            if (i < kNumPackedOpcodes) {
+                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);
+    }
+}
+
+/* Common initialization routine for an architecture family */
+bool dvmCompilerArchInit()
+{
+    int i;
+
+    for (i = 0; i < kArmLast; i++) {
+        if (EncodingMap[i].opcode != i) {
+            LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
+                 EncodingMap[i].name, i, EncodingMap[i].opcode);
+            dvmAbort();  // OK to dvmAbort - build error
+        }
+    }
+
+    return dvmCompilerArchVariantInit();
+}
+
+void *dvmCompilerGetInterpretTemplate()
+{
+      return (void*) ((int)gDvmJit.codeCache +
+                      templateEntryOffsets[TEMPLATE_INTERPRET]);
+}
+
+JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
+{
+    return DALVIK_JIT_ARM;
+}
+
+/* Needed by the Assembler */
+void dvmCompilerSetupResourceMasks(ArmLIR *lir)
+{
+    setupResourceMasks(lir);
+}
+
+/* Needed by the ld/st optmizatons */
+ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    return genRegCopyNoInsert(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    return genRegCopy(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                            int srcLo, int srcHi)
+{
+    genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
+}
+
+void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
+}
+
+void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
+}
diff --git a/vm/compiler/codegen/arm/FP/Thumb2VFP.cpp b/vm/compiler/codegen/arm/FP/Thumb2VFP.cpp
new file mode 100644
index 0000000..abbf2c9
--- /dev/null
+++ b/vm/compiler/codegen/arm/FP/Thumb2VFP.cpp
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2)
+{
+    int op = kThumbBkpt;
+    RegLocation rlResult;
+
+    /*
+     * 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:
+            op = kThumb2Vadds;
+            break;
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_SUB_FLOAT:
+            op = kThumb2Vsubs;
+            break;
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_DIV_FLOAT:
+            op = kThumb2Vdivs;
+            break;
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_MUL_FLOAT:
+            op = kThumb2Vmuls;
+            break;
+        case OP_REM_FLOAT_2ADDR:
+        case OP_REM_FLOAT:
+        case OP_NEG_FLOAT: {
+            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1,
+                                              rlSrc2);
+        }
+        default:
+            return true;
+    }
+    rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR3(cUnit, (ArmOpcode)op, rlResult.lowReg, rlSrc1.lowReg,
+            rlSrc2.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                             RegLocation rlDest, RegLocation rlSrc1,
+                             RegLocation rlSrc2)
+{
+    int op = kThumbBkpt;
+    RegLocation rlResult;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_ADD_DOUBLE:
+            op = kThumb2Vaddd;
+            break;
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE:
+            op = kThumb2Vsubd;
+            break;
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE:
+            op = kThumb2Vdivd;
+            break;
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE:
+            op = kThumb2Vmuld;
+            break;
+        case OP_REM_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE:
+        case OP_NEG_DOUBLE: {
+            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+                                               rlSrc2);
+        }
+        default:
+            return true;
+    }
+
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+    assert(rlSrc1.wide);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+    assert(rlSrc2.wide);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    assert(rlDest.wide);
+    assert(rlResult.wide);
+    newLIR3(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc1.lowReg, rlSrc1.highReg),
+            S2D(rlSrc2.lowReg, rlSrc2.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    int op = kThumbBkpt;
+    bool longSrc = false;
+    bool longDest = false;
+    int srcReg;
+    RegLocation rlSrc;
+    RegLocation rlDest;
+    RegLocation rlResult;
+
+    switch (opcode) {
+        case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
+            op = kThumb2VcvtIF;
+            break;
+        case OP_FLOAT_TO_INT:
+            longSrc = false;
+            longDest = false;
+            op = kThumb2VcvtFI;
+            break;
+        case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
+            op = kThumb2VcvtDF;
+            break;
+        case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            op = kThumb2VcvtFd;
+            break;
+        case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            op = kThumb2VcvtID;
+            break;
+        case OP_DOUBLE_TO_INT:
+            longSrc = true;
+            longDest = false;
+            op = kThumb2VcvtDI;
+            break;
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+            return genConversionPortable(cUnit, mir);
+        default:
+            return true;
+    }
+    if (longSrc) {
+        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+        rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+        srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
+    } else {
+        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+        rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+        srcReg = rlSrc.lowReg;
+    }
+    if (longDest) {
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg),
+                srcReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else {
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, (ArmOpcode)op, rlResult.lowReg, srcReg);
+        storeValue(cUnit, rlDest, rlResult);
+    }
+    return false;
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+    ArmLIR *branch;
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
+    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc.lowReg, rlSrc.highReg));
+    newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlResult.lowReg, rlResult.highReg));
+    newLIR0(cUnit, kThumb2Fmstat);
+    branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
+    dvmCompilerClobberCallRegs(cUnit);
+    LOAD_FUNC_ADDR(cUnit, r2, (int) (double (*)(double)) sqrt);
+    newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg));
+    newLIR1(cUnit, kThumbBlxR, r2);
+    newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg),
+            r0, r1);
+    ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel);
+    label->defMask = ENCODE_ALL;
+    branch->generic.target = (LIR *)label;
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                     RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    bool isDouble;
+    int defaultResult;
+    RegLocation rlResult;
+
+    switch(mir->dalvikInsn.opcode) {
+        case OP_CMPL_FLOAT:
+            isDouble = false;
+            defaultResult = -1;
+            break;
+        case OP_CMPG_FLOAT:
+            isDouble = false;
+            defaultResult = 1;
+            break;
+        case OP_CMPL_DOUBLE:
+            isDouble = true;
+            defaultResult = -1;
+            break;
+        case OP_CMPG_DOUBLE:
+            isDouble = true;
+            defaultResult = 1;
+            break;
+        default:
+            return true;
+    }
+    if (isDouble) {
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+        dvmCompilerClobberSReg(cUnit, rlDest.sRegLow);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+        loadConstant(cUnit, rlResult.lowReg, defaultResult);
+        newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
+                S2D(rlSrc2.lowReg, rlSrc2.highReg));
+    } else {
+        rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+        rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+        dvmCompilerClobberSReg(cUnit, rlDest.sRegLow);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+        loadConstant(cUnit, rlResult.lowReg, defaultResult);
+        newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
+    }
+    assert(!FPREG(rlResult.lowReg));
+    newLIR0(cUnit, kThumb2Fmstat);
+
+    genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
+    newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
+            modifiedImmediate(-defaultResult)); // Must not alter ccodes
+    genBarrier(cUnit);
+
+    genIT(cUnit, kArmCondEq, "");
+    loadConstant(cUnit, rlResult.lowReg, 0);
+    genBarrier(cUnit);
+
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
diff --git a/vm/compiler/codegen/arm/FP/ThumbPortableFP.cpp b/vm/compiler/codegen/arm/FP/ThumbPortableFP.cpp
new file mode 100644
index 0000000..7aac8e6
--- /dev/null
+++ b/vm/compiler/codegen/arm/FP/ThumbPortableFP.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/* Forward-declare the portable versions due to circular dependency */
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+                                    RegLocation rlDest, RegLocation rlSrc1,
+                                    RegLocation rlSrc2);
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+                                     RegLocation rlDest, RegLocation rlSrc1,
+                                     RegLocation rlSrc2);
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
+
+static bool handleExecuteInlineC(CompilationUnit *cUnit, MIR *mir);
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    return genConversionPortable(cUnit, mir);
+}
+
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2)
+{
+    return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                             RegLocation rlDest, RegLocation rlSrc1,
+                             RegLocation rlSrc2)
+{
+    return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleExecuteInlineC(cUnit, mir);
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                     RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult = LOC_C_RETURN;
+    /*
+     * Don't attempt to optimize register usage since these opcodes call out to
+     * the handlers.
+     */
+    switch (mir->dalvikInsn.opcode) {
+        case OP_CMPL_FLOAT:
+            loadValueDirectFixed(cUnit, rlSrc1, r0);
+            loadValueDirectFixed(cUnit, rlSrc2, r1);
+            genDispatchToHandler(cUnit, TEMPLATE_CMPL_FLOAT);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        case OP_CMPG_FLOAT:
+            loadValueDirectFixed(cUnit, rlSrc1, r0);
+            loadValueDirectFixed(cUnit, rlSrc2, r1);
+            genDispatchToHandler(cUnit, TEMPLATE_CMPG_FLOAT);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        case OP_CMPL_DOUBLE:
+            loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+            genDispatchToHandler(cUnit, TEMPLATE_CMPL_DOUBLE);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        case OP_CMPG_DOUBLE:
+            loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+            genDispatchToHandler(cUnit, TEMPLATE_CMPG_DOUBLE);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+        default:
+            return true;
+    }
+    return false;
+}
diff --git a/vm/compiler/codegen/arm/FP/ThumbVFP.cpp b/vm/compiler/codegen/arm/FP/ThumbVFP.cpp
new file mode 100644
index 0000000..f685f24
--- /dev/null
+++ b/vm/compiler/codegen/arm/FP/ThumbVFP.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is included by Codegen-armv5te-vfp.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Take the address of a Dalvik register and store it into rDest.
+ * Clobber any live values associated either with the Dalvik value
+ * or the target register and lock the target fixed register.
+ */
+static void loadValueAddressDirect(CompilationUnit *cUnit, RegLocation rlSrc,
+                                   int rDest)
+{
+     rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) :
+                          dvmCompilerUpdateLoc(cUnit, rlSrc);
+     if (rlSrc.location == kLocPhysReg) {
+         if (rlSrc.wide) {
+             dvmCompilerFlushRegWide(cUnit, rlSrc.lowReg, rlSrc.highReg);
+         } else {
+             dvmCompilerFlushReg(cUnit, rlSrc.lowReg);
+         }
+     }
+     dvmCompilerClobber(cUnit, rDest);
+     dvmCompilerLockTemp(cUnit, rDest);
+     opRegRegImm(cUnit, kOpAdd, rDest, r5FP,
+                 dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation rlResult = LOC_C_RETURN_WIDE;
+    RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+    loadValueAddressDirect(cUnit, rlSrc, r2);
+    genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+}
+
+/*
+ * TUNING: On some implementations, it is quicker to pass addresses
+ * to the handlers rather than load the operands into core registers
+ * and then move the values to FP regs in the handlers.  Other implementations
+ * may prefer passing data in registers (and the latter approach would
+ * yield cleaner register handling - avoiding the requirement that operands
+ * be flushed to memory prior to the call).
+ */
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2)
+{
+    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;
+            break;
+        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 genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    loadValueAddressDirect(cUnit, rlDest, r0);
+    loadValueAddressDirect(cUnit, rlSrc1, r1);
+    loadValueAddressDirect(cUnit, rlSrc2, r2);
+    genDispatchToHandler(cUnit, opcode);
+    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        dvmCompilerClobber(cUnit, rlDest.lowReg);
+    }
+    return false;
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                             RegLocation rlDest, RegLocation rlSrc1,
+                             RegLocation rlSrc2)
+{
+    TemplateOpcode opcode;
+
+    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 genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+                                               rlSrc2);
+        }
+        default:
+            return true;
+    }
+    loadValueAddressDirect(cUnit, rlDest, r0);
+    loadValueAddressDirect(cUnit, rlSrc1, r1);
+    loadValueAddressDirect(cUnit, rlSrc2, r2);
+    genDispatchToHandler(cUnit, opcode);
+    rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        dvmCompilerClobber(cUnit, rlDest.lowReg);
+        dvmCompilerClobber(cUnit, rlDest.highReg);
+    }
+    return false;
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    bool longSrc = false;
+    bool longDest = false;
+    RegLocation rlSrc;
+    RegLocation rlDest;
+    TemplateOpcode templateOpcode;
+    switch (opcode) {
+        case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
+            templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
+            break;
+        case OP_FLOAT_TO_INT:
+            longSrc = false;
+            longDest = false;
+            templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
+            break;
+        case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
+            templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
+            break;
+        case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
+            break;
+        case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
+            break;
+        case OP_DOUBLE_TO_INT:
+            longSrc = true;
+            longDest = false;
+            templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
+            break;
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+            return genConversionPortable(cUnit, mir);
+        default:
+            return true;
+    }
+
+    if (longSrc) {
+        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    } else {
+        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    }
+
+    if (longDest) {
+        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
+    }
+    loadValueAddressDirect(cUnit, rlDest, r0);
+    loadValueAddressDirect(cUnit, rlSrc, r1);
+    genDispatchToHandler(cUnit, templateOpcode);
+    if (rlDest.wide) {
+        rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
+        dvmCompilerClobber(cUnit, rlDest.highReg);
+    } else {
+        rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
+    }
+    dvmCompilerClobber(cUnit, rlDest.lowReg);
+    return false;
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                     RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    TemplateOpcode templateOpcode;
+    RegLocation rlResult = dvmCompilerGetReturn(cUnit);
+    bool wide = true;
+
+    switch(mir->dalvikInsn.opcode) {
+        case OP_CMPL_FLOAT:
+            templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
+            wide = false;
+            break;
+        case OP_CMPG_FLOAT:
+            templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
+            wide = false;
+            break;
+        case OP_CMPL_DOUBLE:
+            templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
+            break;
+        case OP_CMPG_DOUBLE:
+            templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
+            break;
+        default:
+            return true;
+    }
+    loadValueAddressDirect(cUnit, rlSrc1, r0);
+    loadValueAddressDirect(cUnit, rlSrc2, r1);
+    genDispatchToHandler(cUnit, templateOpcode);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
diff --git a/vm/compiler/codegen/arm/GlobalOptimizations.cpp b/vm/compiler/codegen/arm/GlobalOptimizations.cpp
new file mode 100644
index 0000000..e52bd8a
--- /dev/null
+++ b/vm/compiler/codegen/arm/GlobalOptimizations.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 "ArmLIR.h"
+
+/*
+ * Identify unconditional branches that jump to the immediate successor of the
+ * branch itself.
+ */
+static void applyRedundantBranchElimination(CompilationUnit *cUnit)
+{
+    ArmLIR *thisLIR;
+
+    for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
+         thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+
+        /* Branch to the next instruction */
+        if (thisLIR->opcode == kThumbBUncond) {
+            ArmLIR *nextLIR = thisLIR;
+
+            while (true) {
+                nextLIR = NEXT_LIR(nextLIR);
+
+                /*
+                 * Is the branch target the next instruction?
+                 */
+                if (nextLIR == (ArmLIR *) thisLIR->generic.target) {
+                    thisLIR->flags.isNop = true;
+                    break;
+                }
+
+                /*
+                 * Found real useful stuff between the branch and the target.
+                 * Need to explicitly check the lastLIRInsn here since with
+                 * method-based JIT the branch might be the last real
+                 * instruction.
+                 */
+                if (!isPseudoOpcode(nextLIR->opcode) ||
+                    (nextLIR = (ArmLIR *) cUnit->lastLIRInsn))
+                    break;
+            }
+        }
+    }
+}
+
+void dvmCompilerApplyGlobalOptimizations(CompilationUnit *cUnit)
+{
+    applyRedundantBranchElimination(cUnit);
+}
diff --git a/vm/compiler/codegen/arm/LocalOptimizations.cpp b/vm/compiler/codegen/arm/LocalOptimizations.cpp
new file mode 100644
index 0000000..b89437e
--- /dev/null
+++ b/vm/compiler/codegen/arm/LocalOptimizations.cpp
@@ -0,0 +1,460 @@
+/*
+ * 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 "ArmLIR.h"
+#include "Codegen.h"
+
+#define DEBUG_OPT(X)
+
+/* Check RAW, WAR, and WAR dependency on the register operands */
+#define CHECK_REG_DEP(use, def, check) ((def & check->useMask) || \
+                                        ((use | def) & check->defMask))
+
+/* Scheduler heuristics */
+#define MAX_HOIST_DISTANCE 20
+#define LDLD_DISTANCE 4
+#define LD_LATENCY 2
+
+static inline bool isDalvikRegisterClobbered(ArmLIR *lir1, ArmLIR *lir2)
+{
+    int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
+    int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
+    int reg2Lo = DECODE_ALIAS_INFO_REG(lir2->aliasInfo);
+    int reg2Hi = reg2Lo + DECODE_ALIAS_INFO_WIDE(lir2->aliasInfo);
+
+    return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
+}
+
+#if 0
+/* Debugging utility routine */
+static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
+                                  const char *optimization)
+{
+    LOGD("************ %s ************", optimization);
+    dvmDumpLIRInsn((LIR *) thisLIR, 0);
+    dvmDumpLIRInsn((LIR *) checkLIR, 0);
+}
+#endif
+
+/* Convert a more expensive instruction (ie load) into a move */
+static void convertMemOpIntoMove(CompilationUnit *cUnit, ArmLIR *origLIR,
+                                 int dest, int src)
+{
+    /* Insert a move to replace the load */
+    ArmLIR *moveLIR;
+    moveLIR = dvmCompilerRegCopyNoInsert( cUnit, dest, src);
+    /*
+     * Insert the converted instruction after the original since the
+     * optimization is scannng in the top-down order and the new instruction
+     * will need to be re-checked (eg the new dest clobbers the src used in
+     * thisLIR).
+     */
+    dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) moveLIR);
+}
+
+/*
+ * Perform a pass of top-down walk, from the second-last instruction in the
+ * superblock, to eliminate redundant loads and stores.
+ *
+ * An earlier load can eliminate a later load iff
+ *   1) They are must-aliases
+ *   2) The native register is not clobbered in between
+ *   3) The memory location is not written to in between
+ *
+ * An earlier store can eliminate a later load iff
+ *   1) They are must-aliases
+ *   2) The native register is not clobbered in between
+ *   3) The memory location is not written to in between
+ *
+ * A later store can be eliminated by an earlier store iff
+ *   1) They are must-aliases
+ *   2) The memory location is not written to in between
+ */
+static void applyLoadStoreElimination(CompilationUnit *cUnit,
+                                      ArmLIR *headLIR,
+                                      ArmLIR *tailLIR)
+{
+    ArmLIR *thisLIR;
+
+    if (headLIR == tailLIR) return;
+
+    for (thisLIR = PREV_LIR(tailLIR);
+         thisLIR != headLIR;
+         thisLIR = PREV_LIR(thisLIR)) {
+        int sinkDistance = 0;
+
+        /* Skip non-interesting instructions */
+        if ((thisLIR->flags.isNop == true) ||
+            isPseudoOpcode(thisLIR->opcode) ||
+            !(EncodingMap[thisLIR->opcode].flags & (IS_LOAD | IS_STORE))) {
+            continue;
+        }
+
+        int nativeRegId = thisLIR->operands[0];
+        bool isThisLIRLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD;
+        ArmLIR *checkLIR;
+        /* Use the mem mask to determine the rough memory location */
+        u8 thisMemMask = (thisLIR->useMask | thisLIR->defMask) & ENCODE_MEM;
+
+        /*
+         * Currently only eliminate redundant ld/st for constant and Dalvik
+         * register accesses.
+         */
+        if (!(thisMemMask & (ENCODE_LITERAL | ENCODE_DALVIK_REG))) continue;
+
+        /*
+         * Add r15 (pc) to the resource mask to prevent this instruction
+         * from sinking past branch instructions. Also take out the memory
+         * region bits since stopMask is used to check data/control
+         * dependencies.
+         */
+        u8 stopUseRegMask = (ENCODE_REG_PC | thisLIR->useMask) &
+                            ~ENCODE_MEM;
+        u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM;
+
+        for (checkLIR = NEXT_LIR(thisLIR);
+             checkLIR != tailLIR;
+             checkLIR = NEXT_LIR(checkLIR)) {
+
+            /*
+             * Skip already dead instructions (whose dataflow information is
+             * outdated and misleading).
+             */
+            if (checkLIR->flags.isNop) continue;
+
+            u8 checkMemMask = (checkLIR->useMask | checkLIR->defMask) &
+                              ENCODE_MEM;
+            u8 aliasCondition = thisMemMask & checkMemMask;
+            bool stopHere = false;
+
+            /*
+             * Potential aliases seen - check the alias relations
+             */
+            if (checkMemMask != ENCODE_MEM && aliasCondition != 0) {
+                bool isCheckLIRLoad = EncodingMap[checkLIR->opcode].flags &
+                                      IS_LOAD;
+                if  (aliasCondition == ENCODE_LITERAL) {
+                    /*
+                     * Should only see literal loads in the instruction
+                     * stream.
+                     */
+                    assert(!(EncodingMap[checkLIR->opcode].flags &
+                             IS_STORE));
+                    /* Same value && same register type */
+                    if (checkLIR->aliasInfo == thisLIR->aliasInfo &&
+                        REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId)){
+                        /*
+                         * Different destination register - insert
+                         * a move
+                         */
+                        if (checkLIR->operands[0] != nativeRegId) {
+                            convertMemOpIntoMove(cUnit, checkLIR,
+                                                 checkLIR->operands[0],
+                                                 nativeRegId);
+                        }
+                        checkLIR->flags.isNop = true;
+                    }
+                } else if (aliasCondition == ENCODE_DALVIK_REG) {
+                    /* Must alias */
+                    if (checkLIR->aliasInfo == thisLIR->aliasInfo) {
+                        /* Only optimize compatible registers */
+                        bool regCompatible =
+                            REGTYPE(checkLIR->operands[0]) ==
+                            REGTYPE(nativeRegId);
+                        if ((isThisLIRLoad && isCheckLIRLoad) ||
+                            (!isThisLIRLoad && isCheckLIRLoad)) {
+                            /* RAR or RAW */
+                            if (regCompatible) {
+                                /*
+                                 * Different destination register -
+                                 * insert a move
+                                 */
+                                if (checkLIR->operands[0] !=
+                                    nativeRegId) {
+                                    convertMemOpIntoMove(cUnit,
+                                                 checkLIR,
+                                                 checkLIR->operands[0],
+                                                 nativeRegId);
+                                }
+                                checkLIR->flags.isNop = true;
+                            } else {
+                                /*
+                                 * Destinaions are of different types -
+                                 * something complicated going on so
+                                 * stop looking now.
+                                 */
+                                stopHere = true;
+                            }
+                        } else if (isThisLIRLoad && !isCheckLIRLoad) {
+                            /* WAR - register value is killed */
+                            stopHere = true;
+                        } else if (!isThisLIRLoad && !isCheckLIRLoad) {
+                            /* WAW - nuke the earlier store */
+                            thisLIR->flags.isNop = true;
+                            stopHere = true;
+                        }
+                    /* Partial overlap */
+                    } else if (isDalvikRegisterClobbered(thisLIR, checkLIR)) {
+                        /*
+                         * It is actually ok to continue if checkLIR
+                         * is a read. But it is hard to make a test
+                         * case for this so we just stop here to be
+                         * conservative.
+                         */
+                        stopHere = true;
+                    }
+                }
+                /* Memory content may be updated. Stop looking now. */
+                if (stopHere) {
+                    break;
+                /* The checkLIR has been transformed - check the next one */
+                } else if (checkLIR->flags.isNop) {
+                    continue;
+                }
+            }
+
+
+            /*
+             * this and check LIRs have no memory dependency. Now check if
+             * their register operands have any RAW, WAR, and WAW
+             * dependencies. If so, stop looking.
+             */
+            if (stopHere == false) {
+                stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask,
+                                         checkLIR);
+            }
+
+            if (stopHere == true) {
+                DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
+                                                "REG CLOBBERED"));
+                /* Only sink store instructions */
+                if (sinkDistance && !isThisLIRLoad) {
+                    ArmLIR *newStoreLIR =
+                        (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+                    *newStoreLIR = *thisLIR;
+                    /*
+                     * Stop point found - insert *before* the checkLIR
+                     * since the instruction list is scanned in the
+                     * top-down order.
+                     */
+                    dvmCompilerInsertLIRBefore((LIR *) checkLIR,
+                                               (LIR *) newStoreLIR);
+                    thisLIR->flags.isNop = true;
+                }
+                break;
+            } else if (!checkLIR->flags.isNop) {
+                sinkDistance++;
+            }
+        }
+    }
+}
+
+/*
+ * Perform a pass of bottom-up walk, from the second instruction in the
+ * superblock, to try to hoist loads to earlier slots.
+ */
+static void applyLoadHoisting(CompilationUnit *cUnit,
+                              ArmLIR *headLIR,
+                              ArmLIR *tailLIR)
+{
+    ArmLIR *thisLIR, *checkLIR;
+    /*
+     * Store the list of independent instructions that can be hoisted past.
+     * Will decide the best place to insert later.
+     */
+    ArmLIR *prevInstList[MAX_HOIST_DISTANCE];
+
+    /* Empty block */
+    if (headLIR == tailLIR) return;
+
+    /* Start from the second instruction */
+    for (thisLIR = NEXT_LIR(headLIR);
+         thisLIR != tailLIR;
+         thisLIR = NEXT_LIR(thisLIR)) {
+
+        /* Skip non-interesting instructions */
+        if ((thisLIR->flags.isNop == true) ||
+            isPseudoOpcode(thisLIR->opcode) ||
+            !(EncodingMap[thisLIR->opcode].flags & IS_LOAD)) {
+            continue;
+        }
+
+        u8 stopUseAllMask = thisLIR->useMask;
+
+        /*
+         * Branches for null/range checks are marked with the true resource
+         * bits, and loads to Dalvik registers, constant pools, and non-alias
+         * locations are safe to be hoisted. So only mark the heap references
+         * conservatively here.
+         */
+        if (stopUseAllMask & ENCODE_HEAP_REF) {
+            stopUseAllMask |= ENCODE_REG_PC;
+        }
+
+        /* Similar as above, but just check for pure register dependency */
+        u8 stopUseRegMask = stopUseAllMask & ~ENCODE_MEM;
+        u8 stopDefRegMask = thisLIR->defMask & ~ENCODE_MEM;
+
+        int nextSlot = 0;
+        bool stopHere = false;
+
+        /* Try to hoist the load to a good spot */
+        for (checkLIR = PREV_LIR(thisLIR);
+             checkLIR != headLIR;
+             checkLIR = PREV_LIR(checkLIR)) {
+
+            /*
+             * Skip already dead instructions (whose dataflow information is
+             * outdated and misleading).
+             */
+            if (checkLIR->flags.isNop) continue;
+
+            u8 checkMemMask = checkLIR->defMask & ENCODE_MEM;
+            u8 aliasCondition = stopUseAllMask & checkMemMask;
+            stopHere = false;
+
+            /* Potential WAR alias seen - check the exact relation */
+            if (checkMemMask != ENCODE_MEM && aliasCondition != 0) {
+                /* We can fully disambiguate Dalvik references */
+                if (aliasCondition == ENCODE_DALVIK_REG) {
+                    /* Must alias or partually overlap */
+                    if ((checkLIR->aliasInfo == thisLIR->aliasInfo) ||
+                        isDalvikRegisterClobbered(thisLIR, checkLIR)) {
+                        stopHere = true;
+                    }
+                /* Conservatively treat all heap refs as may-alias */
+                } else {
+                    assert(aliasCondition == ENCODE_HEAP_REF);
+                    stopHere = true;
+                }
+                /* Memory content may be updated. Stop looking now. */
+                if (stopHere) {
+                    prevInstList[nextSlot++] = checkLIR;
+                    break;
+                }
+            }
+
+            if (stopHere == false) {
+                stopHere = CHECK_REG_DEP(stopUseRegMask, stopDefRegMask,
+                                         checkLIR);
+            }
+
+            /*
+             * Store the dependent or non-pseudo/indepedent instruction to the
+             * list.
+             */
+            if (stopHere || !isPseudoOpcode(checkLIR->opcode)) {
+                prevInstList[nextSlot++] = checkLIR;
+                if (nextSlot == MAX_HOIST_DISTANCE) break;
+            }
+
+            /* Found a new place to put the load - move it here */
+            if (stopHere == true) {
+                DEBUG_OPT(dumpDependentInsnPair(checkLIR, thisLIR
+                                                "HOIST STOP"));
+                break;
+            }
+        }
+
+        /*
+         * Reached the top - use headLIR as the dependent marker as all labels
+         * are barriers.
+         */
+        if (stopHere == false && nextSlot < MAX_HOIST_DISTANCE) {
+            prevInstList[nextSlot++] = headLIR;
+        }
+
+        /*
+         * At least one independent instruction is found. Scan in the reversed
+         * direction to find a beneficial slot.
+         */
+        if (nextSlot >= 2) {
+            int firstSlot = nextSlot - 2;
+            int slot;
+            ArmLIR *depLIR = prevInstList[nextSlot-1];
+            /* If there is ld-ld dependency, wait LDLD_DISTANCE cycles */
+            if (!isPseudoOpcode(depLIR->opcode) &&
+                (EncodingMap[depLIR->opcode].flags & IS_LOAD)) {
+                firstSlot -= LDLD_DISTANCE;
+            }
+            /*
+             * Make sure we check slot >= 0 since firstSlot may be negative
+             * when the loop is first entered.
+             */
+            for (slot = firstSlot; slot >= 0; slot--) {
+                ArmLIR *curLIR = prevInstList[slot];
+                ArmLIR *prevLIR = prevInstList[slot+1];
+
+                /* Check the highest instruction */
+                if (prevLIR->defMask == ENCODE_ALL) {
+                    /*
+                     * If the first instruction is a load, don't hoist anything
+                     * above it since it is unlikely to be beneficial.
+                     */
+                    if (EncodingMap[curLIR->opcode].flags & IS_LOAD) continue;
+                    /*
+                     * If the remaining number of slots is less than LD_LATENCY,
+                     * insert the hoisted load here.
+                     */
+                    if (slot < LD_LATENCY) break;
+                }
+
+                /*
+                 * NOTE: now prevLIR is guaranteed to be a non-pseudo
+                 * instruction (ie accessing EncodingMap[prevLIR->opcode] is
+                 * safe).
+                 *
+                 * Try to find two instructions with load/use dependency until
+                 * the remaining instructions are less than LD_LATENCY.
+                 */
+                if (((curLIR->useMask & prevLIR->defMask) &&
+                     (EncodingMap[prevLIR->opcode].flags & IS_LOAD)) ||
+                    (slot < LD_LATENCY)) {
+                    break;
+                }
+            }
+
+            /* Found a slot to hoist to */
+            if (slot >= 0) {
+                ArmLIR *curLIR = prevInstList[slot];
+                ArmLIR *newLoadLIR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR),
+                                                               true);
+                *newLoadLIR = *thisLIR;
+                /*
+                 * Insertion is guaranteed to succeed since checkLIR
+                 * is never the first LIR on the list
+                 */
+                dvmCompilerInsertLIRBefore((LIR *) curLIR,
+                                           (LIR *) newLoadLIR);
+                thisLIR->flags.isNop = true;
+            }
+        }
+    }
+}
+
+void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
+                                        LIR *tailLIR)
+{
+    if (!(gDvmJit.disableOpt & (1 << kLoadStoreElimination))) {
+        applyLoadStoreElimination(cUnit, (ArmLIR *) headLIR,
+                                  (ArmLIR *) tailLIR);
+    }
+    if (!(gDvmJit.disableOpt & (1 << kLoadHoisting))) {
+        applyLoadHoisting(cUnit, (ArmLIR *) headLIR, (ArmLIR *) tailLIR);
+    }
+}
diff --git a/vm/compiler/codegen/arm/README.txt b/vm/compiler/codegen/arm/README.txt
new file mode 100644
index 0000000..1bb4603
--- /dev/null
+++ b/vm/compiler/codegen/arm/README.txt
@@ -0,0 +1,48 @@
+The codegen file for the ARM-based JIT is composed by files broken by
+functionality hierarchies. The goal is to separate architectural dependent
+and independent components to facilitate maintenance and future extension.
+
+For example, the codegen file for armv7-a is assembled by the following
+components:
+
+--
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.cpp"
+
+/* Thumb2-specific factory utilities */
+#include "../Thumb2/Factory.cpp"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.cpp"
+
+/* Thumb2-specific codegen routines */
+#include "../Thumb2/Gen.cpp"
+/* Thumb2+VFP codegen routines */
+#include "../FP/Thumb2VFP.cpp"
+
+/* Thumb2-specific register allocation */
+#include "../Thumb2/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
+
+--
+
+For the Thumb/Thumb2 directories, each contain the followin three files:
+
+- Factory.c (low-level routines for instruction selections)
+- Gen.c     (invoke the ISA-specific instruction selection routines)
+- Ralloc.c  (arch-dependent register pools)
+
+The FP directory contains FP-specific codegen routines depending on
+Thumb/Thumb2/VFP/PortableFP:
+
+- Thumb2VFP.c
+- ThumbVFP.c
+- ThumbPortableFP.c
+
+In this way the dependency between generic and specific code tied to
+particular architectures can be explicitly represented.
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.cpp b/vm/compiler/codegen/arm/Thumb/Factory.cpp
new file mode 100644
index 0000000..9cdd75f
--- /dev/null
+++ b/vm/compiler/codegen/arm/Thumb/Factory.cpp
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg,
+                      int highReg);
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
+static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+                            int rDest);
+static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc);
+static ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
+                              ArmConditionCode cond,
+                              int reg1, int reg2, int dOffset,
+                              ArmLIR *pcrLabel);
+
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool.  If target is
+ * a high register, build constant into a low register and copy.
+ *
+ * No additional register clobbering operation performed. Use this version when
+ * 1) rDest is freshly returned from dvmCompilerAllocTemp or
+ * 2) The codegen is under fixed register usage
+ */
+static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
+                                     int value)
+{
+    ArmLIR *res;
+    int tDest = LOWREG(rDest) ? rDest : dvmCompilerAllocTemp(cUnit);
+    /* See if the value can be constructed cheaply */
+    if ((value >= 0) && (value <= 255)) {
+        res = newLIR2(cUnit, kThumbMovImm, tDest, value);
+        if (rDest != tDest) {
+           opRegReg(cUnit, kOpMov, rDest, tDest);
+           dvmCompilerFreeTemp(cUnit, tDest);
+        }
+        return res;
+    } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
+        res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
+        newLIR2(cUnit, kThumbMvn, tDest, tDest);
+        if (rDest != tDest) {
+           opRegReg(cUnit, kOpMov, rDest, tDest);
+           dvmCompilerFreeTemp(cUnit, tDest);
+        }
+        return res;
+    }
+    /* No shortcut - go ahead and use literal pool */
+    ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 255);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, &cUnit->literalList, value);
+    }
+    ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opcode = kThumbLdrPcRel;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = tDest;
+    setupResourceMasks(loadPcRel);
+    setMemRefType(loadPcRel, true, kLiteral);
+    loadPcRel->aliasInfo = dataTarget->operands[0];
+    res = loadPcRel;
+    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, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
+    }
+    if (rDest != tDest) {
+       opRegReg(cUnit, kOpMov, rDest, tDest);
+       dvmCompilerFreeTemp(cUnit, tDest);
+    }
+    return res;
+}
+
+/*
+ * Load an immediate value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+    if (dvmCompilerIsTemp(cUnit, rDest)) {
+        dvmCompilerClobber(cUnit, rDest);
+        dvmCompilerMarkInUse(cUnit, rDest);
+    }
+    return loadConstantNoClobber(cUnit, rDest, value);
+}
+
+/*
+ * Load a class pointer value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
+{
+    ArmLIR *res;
+    cUnit->hasClassLiterals = true;
+    if (dvmCompilerIsTemp(cUnit, rDest)) {
+        dvmCompilerClobber(cUnit, rDest);
+        dvmCompilerMarkInUse(cUnit, rDest);
+    }
+    ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, &cUnit->classPointerList, value);
+        /* Counts the number of class pointers in this translation */
+        cUnit->numClassPointers++;
+    }
+    ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opcode = kThumbLdrPcRel;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = rDest;
+    setupResourceMasks(loadPcRel);
+    setMemRefType(loadPcRel, true, kLiteral);
+    loadPcRel->aliasInfo = dataTarget->operands[0];
+    res = loadPcRel;
+    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+    return res;
+}
+
+static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpUncondBr:
+            opcode = kThumbBUncond;
+            break;
+        default:
+            LOGE("Jit: bad case in opNone");
+            dvmCompilerAbort(cUnit);
+    }
+    return newLIR0(cUnit, opcode);
+}
+
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
+{
+    return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
+}
+
+static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpPush:
+            opcode = kThumbPush;
+            break;
+        case kOpPop:
+            opcode = kThumbPop;
+            break;
+        default:
+            LOGE("Jit: bad case in opCondBranch");
+            dvmCompilerAbort(cUnit);
+    }
+    return newLIR1(cUnit, opcode, value);
+}
+
+static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpBlx:
+            opcode = kThumbBlxR;
+            break;
+        default:
+            LOGE("Jit: bad case in opReg");
+            dvmCompilerAbort(cUnit);
+    }
+    return newLIR1(cUnit, opcode, rDestSrc);
+}
+
+static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int value)
+{
+    ArmLIR *res;
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    bool shortForm = (absValue & 0xff) == absValue;
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpAdd:
+            if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
+                assert((value & 0x3) == 0);
+                return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
+            } else if (shortForm) {
+                opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
+            } else
+                opcode = kThumbAddRRR;
+            break;
+        case kOpSub:
+            if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
+                assert((value & 0x3) == 0);
+                return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
+            } else if (shortForm) {
+                opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
+            } else
+                opcode = kThumbSubRRR;
+            break;
+        case kOpCmp:
+            if (neg)
+               shortForm = false;
+            if (LOWREG(rDestSrc1) && shortForm) {
+                opcode = kThumbCmpRI8;
+            } else if (LOWREG(rDestSrc1)) {
+                opcode = kThumbCmpRR;
+            } else {
+                shortForm = false;
+                opcode = kThumbCmpHL;
+            }
+            break;
+        default:
+            LOGE("Jit: bad case in opRegImm");
+            dvmCompilerAbort(cUnit);
+            break;
+    }
+    if (shortForm)
+        res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
+    else {
+        int rScratch = dvmCompilerAllocTemp(cUnit);
+        res = loadConstant(cUnit, rScratch, value);
+        if (op == kOpCmp)
+            newLIR2(cUnit, opcode, rDestSrc1, rScratch);
+        else
+            newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
+    }
+    return res;
+}
+
+static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int rSrc2)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpAdd:
+            opcode = kThumbAddRRR;
+            break;
+        case kOpSub:
+            opcode = kThumbSubRRR;
+            break;
+        default:
+            if (rDest == rSrc1) {
+                return opRegReg(cUnit, op, rDest, rSrc2);
+            } else if (rDest == rSrc2) {
+                assert(dvmCompilerIsTemp(cUnit, rSrc1));
+                dvmCompilerClobber(cUnit, rSrc1);
+                opRegReg(cUnit, op, rSrc1, rSrc2);
+                return opRegReg(cUnit, kOpMov, rDest, rSrc1);
+            } else {
+                opRegReg(cUnit, kOpMov, rDest, rSrc1);
+                return opRegReg(cUnit, op, rDest, rSrc2);
+            }
+            break;
+    }
+    return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
+}
+
+static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value)
+{
+    ArmLIR *res;
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    ArmOpcode opcode = kThumbBkpt;
+    bool shortForm = (absValue & 0x7) == absValue;
+    switch(op) {
+        case kOpAdd:
+            if (rDest == rSrc1)
+                return opRegImm(cUnit, op, rDest, value);
+            if ((rSrc1 == r13sp) && (value <= 1020)) { /* sp */
+                assert((value & 0x3) == 0);
+                shortForm = true;
+                opcode = kThumbAddSpRel;
+                value >>= 2;
+            } else if ((rSrc1 == r15pc) && (value <= 1020)) { /* pc */
+                assert((value & 0x3) == 0);
+                shortForm = true;
+                opcode = kThumbAddPcRel;
+                value >>= 2;
+            } else if (shortForm) {
+                opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
+            } else if ((absValue > 0) && (absValue <= (255 + 7))) {
+                /* Two shots - 1st handle the 7 */
+                opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
+                res = newLIR3(cUnit, opcode, rDest, rSrc1, 7);
+                opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
+                newLIR2(cUnit, opcode, rDest, absValue - 7);
+                return res;
+            } else
+                opcode = kThumbAddRRR;
+            break;
+
+        case kOpSub:
+            if (rDest == rSrc1)
+                return opRegImm(cUnit, op, rDest, value);
+            if (shortForm) {
+                opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
+            } else if ((absValue > 0) && (absValue <= (255 + 7))) {
+                /* Two shots - 1st handle the 7 */
+                opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
+                res = newLIR3(cUnit, opcode, rDest, rSrc1, 7);
+                opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
+                newLIR2(cUnit, opcode, rDest, absValue - 7);
+                return res;
+            } else
+                opcode = kThumbSubRRR;
+            break;
+        case kOpLsl:
+                shortForm = (!neg && value <= 31);
+                opcode = kThumbLslRRI5;
+                break;
+        case kOpLsr:
+                shortForm = (!neg && value <= 31);
+                opcode = kThumbLsrRRI5;
+                break;
+        case kOpAsr:
+                shortForm = (!neg && value <= 31);
+                opcode = kThumbAsrRRI5;
+                break;
+        case kOpMul:
+        case kOpAnd:
+        case kOpOr:
+        case kOpXor:
+                if (rDest == rSrc1) {
+                    int rScratch = dvmCompilerAllocTemp(cUnit);
+                    res = loadConstant(cUnit, rScratch, value);
+                    opRegReg(cUnit, op, rDest, rScratch);
+                } else {
+                    res = loadConstant(cUnit, rDest, value);
+                    opRegReg(cUnit, op, rDest, rSrc1);
+                }
+                return res;
+        default:
+            LOGE("Jit: bad case in opRegRegImm");
+            dvmCompilerAbort(cUnit);
+            break;
+    }
+    if (shortForm)
+        res = newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
+    else {
+        if (rDest != rSrc1) {
+            res = loadConstant(cUnit, rDest, value);
+            newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
+        } else {
+            int rScratch = dvmCompilerAllocTemp(cUnit);
+            res = loadConstant(cUnit, rScratch, value);
+            newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
+        }
+    }
+    return res;
+}
+
+static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2)
+{
+    ArmLIR *res;
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpAdc:
+            opcode = kThumbAdcRR;
+            break;
+        case kOpAnd:
+            opcode = kThumbAndRR;
+            break;
+        case kOpBic:
+            opcode = kThumbBicRR;
+            break;
+        case kOpCmn:
+            opcode = kThumbCmnRR;
+            break;
+        case kOpCmp:
+            opcode = kThumbCmpRR;
+            break;
+        case kOpXor:
+            opcode = kThumbEorRR;
+            break;
+        case kOpMov:
+            if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
+                opcode = kThumbMovRR;
+            else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
+                opcode = kThumbMovRR_H2H;
+            else if (LOWREG(rDestSrc1))
+                opcode = kThumbMovRR_H2L;
+            else
+                opcode = kThumbMovRR_L2H;
+            break;
+        case kOpMul:
+            opcode = kThumbMul;
+            break;
+        case kOpMvn:
+            opcode = kThumbMvn;
+            break;
+        case kOpNeg:
+            opcode = kThumbNeg;
+            break;
+        case kOpOr:
+            opcode = kThumbOrr;
+            break;
+        case kOpSbc:
+            opcode = kThumbSbc;
+            break;
+        case kOpTst:
+            opcode = kThumbTst;
+            break;
+        case kOpLsl:
+            opcode = kThumbLslRR;
+            break;
+        case kOpLsr:
+            opcode = kThumbLsrRR;
+            break;
+        case kOpAsr:
+            opcode = kThumbAsrRR;
+            break;
+        case kOpRor:
+            opcode = kThumbRorRR;
+        case kOpAdd:
+        case kOpSub:
+            return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
+        case kOp2Byte:
+             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
+             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
+             return res;
+        case kOp2Short:
+             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
+             return res;
+        case kOp2Char:
+             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+             opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
+             return res;
+        default:
+            LOGE("Jit: bad case in opRegReg");
+            dvmCompilerAbort(cUnit);
+            break;
+    }
+    return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
+}
+
+static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+                                     int rDestHi, int valLo, int valHi)
+{
+    ArmLIR *res;
+    res = loadConstantNoClobber(cUnit, rDestLo, valLo);
+    loadConstantNoClobber(cUnit, rDestHi, valHi);
+    return res;
+}
+
+/* Load value from base + scaled index. */
+static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+                               int rIndex, int rDest, int scale, OpSize size)
+{
+    ArmLIR *first = NULL;
+    ArmLIR *res;
+    ArmOpcode opcode = kThumbBkpt;
+    int rNewIndex = rIndex;
+    if (scale) {
+        // Scale the index, but can't trash the original.
+        rNewIndex = dvmCompilerAllocTemp(cUnit);
+        first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
+    }
+    switch (size) {
+        case kWord:
+            opcode = kThumbLdrRRR;
+            break;
+        case kUnsignedHalf:
+            opcode = kThumbLdrhRRR;
+            break;
+        case kSignedHalf:
+            opcode = kThumbLdrshRRR;
+            break;
+        case kUnsignedByte:
+            opcode = kThumbLdrbRRR;
+            break;
+        case kSignedByte:
+            opcode = kThumbLdrsbRRR;
+            break;
+        default:
+            LOGE("Jit: bad case in loadBaseIndexed");
+            dvmCompilerAbort(cUnit);
+    }
+    res = newLIR3(cUnit, opcode, rDest, rBase, rNewIndex);
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->flags.insertWrapper = true;
+#endif
+    if (scale)
+        dvmCompilerFreeTemp(cUnit, rNewIndex);
+    return (first) ? first : res;
+}
+
+/* store value base base + scaled index. */
+static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+                                int rIndex, int rSrc, int scale, OpSize size)
+{
+    ArmLIR *first = NULL;
+    ArmLIR *res;
+    ArmOpcode opcode = kThumbBkpt;
+    int rNewIndex = rIndex;
+    if (scale) {
+        rNewIndex = dvmCompilerAllocTemp(cUnit);
+        first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
+    }
+    switch (size) {
+        case kWord:
+            opcode = kThumbStrRRR;
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opcode = kThumbStrhRRR;
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opcode = kThumbStrbRRR;
+            break;
+        default:
+            LOGE("Jit: bad case in storeBaseIndexed");
+            dvmCompilerAbort(cUnit);
+    }
+    res = newLIR3(cUnit, opcode, rSrc, rBase, rNewIndex);
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->flags.insertWrapper = true;
+#endif
+    if (scale)
+        dvmCompilerFreeTemp(cUnit, rNewIndex);
+    return (first) ? first : res;
+}
+
+static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->flags.insertWrapper = true;
+#endif
+    genBarrier(cUnit);
+    return res;
+}
+
+static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->flags.insertWrapper = true;
+#endif
+    genBarrier(cUnit);
+    return res;
+}
+
+static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDest, int rDestHi,
+                                OpSize size, int sReg)
+/*
+ * Load value from base + displacement.  Optionally perform null check
+ * on base (which must have an associated sReg and MIR).  If not
+ * performing null check, incoming MIR can be null. IMPORTANT: this
+ * code must not allocate any new temps.  If a new register is needed
+ * and base and dest are the same, spill some other register to
+ * rlp and then restore.
+ */
+{
+    ArmLIR *res;
+    ArmLIR *load = NULL;
+    ArmLIR *load2 = NULL;
+    ArmOpcode opcode = kThumbBkpt;
+    bool shortForm = false;
+    int encodedDisp = displacement;
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            if ((displacement < 124) && (displacement >= 0)) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrRRI5;
+            } else {
+                opcode = kThumbLdrRRR;
+            }
+            break;
+        case kWord:
+            if (LOWREG(rDest) && (rBase == r15pc) &&
+                (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrPcRel;
+            } else if (LOWREG(rDest) && (rBase == r13sp) &&
+                      (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrSpRel;
+            } else if (displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrRRI5;
+            } else {
+                opcode = kThumbLdrRRR;
+            }
+            break;
+        case kUnsignedHalf:
+            if (displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opcode = kThumbLdrhRRI5;
+            } else {
+                opcode = kThumbLdrhRRR;
+            }
+            break;
+        case kSignedHalf:
+            opcode = kThumbLdrshRRR;
+            break;
+        case kUnsignedByte:
+            if (displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opcode = kThumbLdrbRRI5;
+            } else {
+                opcode = kThumbLdrbRRR;
+            }
+            break;
+        case kSignedByte:
+            opcode = kThumbLdrsbRRR;
+            break;
+        default:
+            LOGE("Jit: bad case in loadBaseIndexedBody");
+            dvmCompilerAbort(cUnit);
+    }
+    if (shortForm) {
+        load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
+        if (pair) {
+            load2 = newLIR3(cUnit, opcode, rDestHi, rBase, encodedDisp+1);
+        }
+    } else {
+        if (pair) {
+            int rTmp = dvmCompilerAllocFreeTemp(cUnit);
+            res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
+            load = newLIR3(cUnit, kThumbLdrRRI5, rDest, rTmp, 0);
+            load2 = newLIR3(cUnit, kThumbLdrRRI5, rDestHi, rTmp, 1);
+            dvmCompilerFreeTemp(cUnit, rTmp);
+        } else {
+            int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
+                                        : rDest;
+            res = loadConstant(cUnit, rTmp, displacement);
+            load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
+            if (rBase == r5FP)
+                annotateDalvikRegAccess(load, displacement >> 2,
+                                        true /* isLoad */);
+            if (rTmp != rDest)
+                dvmCompilerFreeTemp(cUnit, rTmp);
+        }
+    }
+    if (rBase == r5FP) {
+        if (load != NULL)
+            annotateDalvikRegAccess(load, displacement >> 2,
+                                    true /* isLoad */);
+        if (load2 != NULL)
+            annotateDalvikRegAccess(load2, (displacement >> 2) + 1,
+                                    true /* isLoad */);
+    }
+#if defined(WITH_SELF_VERIFICATION)
+    if (load != NULL && cUnit->heapMemOp)
+        load->flags.insertWrapper = true;
+    if (load2 != NULL && cUnit->heapMemOp)
+        load2->flags.insertWrapper = true;
+#endif
+    return load;
+}
+
+static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+                            int displacement, int rDest, OpSize size,
+                            int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+                            size, sReg);
+}
+
+static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDestLo, int rDestHi,
+                                int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+                            kLong, sReg);
+}
+
+static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrc, int rSrcHi,
+                                 OpSize size)
+{
+    ArmLIR *res;
+    ArmLIR *store = NULL;
+    ArmLIR *store2 = NULL;
+    ArmOpcode opcode = kThumbBkpt;
+    bool shortForm = false;
+    int encodedDisp = displacement;
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            if ((displacement < 124) && (displacement >= 0)) {
+                assert((displacement & 0x3) == 0);
+                pair = true;
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbStrRRI5;
+            } else {
+                opcode = kThumbStrRRR;
+            }
+            break;
+        case kWord:
+            if (displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbStrRRI5;
+            } else {
+                opcode = kThumbStrRRR;
+            }
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            if (displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opcode = kThumbStrhRRI5;
+            } else {
+                opcode = kThumbStrhRRR;
+            }
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            if (displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opcode = kThumbStrbRRI5;
+            } else {
+                opcode = kThumbStrbRRR;
+            }
+            break;
+        default:
+            LOGE("Jit: bad case in storeBaseIndexedBody");
+            dvmCompilerAbort(cUnit);
+    }
+    if (shortForm) {
+        store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
+        if (pair) {
+            store2 = newLIR3(cUnit, opcode, rSrcHi, rBase, encodedDisp + 1);
+        }
+    } else {
+        int rScratch = dvmCompilerAllocTemp(cUnit);
+        if (pair) {
+            res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
+            store =  newLIR3(cUnit, kThumbStrRRI5, rSrc, rScratch, 0);
+            store2 = newLIR3(cUnit, kThumbStrRRI5, rSrcHi, rScratch, 1);
+        } else {
+            res = loadConstant(cUnit, rScratch, displacement);
+            store = newLIR3(cUnit, opcode, rSrc, rBase, rScratch);
+        }
+        dvmCompilerFreeTemp(cUnit, rScratch);
+    }
+    if (rBase == r5FP) {
+        if (store != NULL)
+            annotateDalvikRegAccess(store, displacement >> 2,
+                                    false /* isLoad */);
+        if (store2 != NULL)
+            annotateDalvikRegAccess(store2, (displacement >> 2) + 1,
+                                    false /* isLoad */);
+    }
+#if defined(WITH_SELF_VERIFICATION)
+    if (store != NULL && cUnit->heapMemOp)
+        store->flags.insertWrapper = true;
+    if (store2 != NULL && cUnit->heapMemOp)
+        store2->flags.insertWrapper = true;
+#endif
+    return res;
+}
+
+static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    if (lowReg < highReg) {
+        storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
+    } else {
+        storeWordDisp(cUnit, base, 0, lowReg);
+        storeWordDisp(cUnit, base, 4, highReg);
+    }
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    if (lowReg < highReg) {
+        loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
+    } else {
+        loadWordDisp(cUnit, base, 0 , lowReg);
+        loadWordDisp(cUnit, base, 4 , highReg);
+    }
+}
+
+static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    ArmLIR* res;
+    ArmOpcode opcode;
+    res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    if (LOWREG(rDest) && LOWREG(rSrc))
+        opcode = kThumbMovRR;
+    else if (!LOWREG(rDest) && !LOWREG(rSrc))
+         opcode = kThumbMovRR_H2H;
+    else if (LOWREG(rDest))
+         opcode = kThumbMovRR_H2L;
+    else
+         opcode = kThumbMovRR_L2H;
+
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    res->opcode = opcode;
+    setupResourceMasks(res);
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    }
+    return res;
+}
+
+static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+    dvmCompilerAppendLIR(cUnit, (LIR*)res);
+    return res;
+}
+
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                           int srcLo, int srcHi)
+{
+    // Handle overlap
+    if (srcHi == destLo) {
+        genRegCopy(cUnit, destHi, srcHi);
+        genRegCopy(cUnit, destLo, srcLo);
+    } else {
+        genRegCopy(cUnit, destLo, srcLo);
+        genRegCopy(cUnit, destHi, srcHi);
+    }
+}
+
+static ArmLIR *genCmpImmBranch(CompilationUnit *cUnit,
+                                     ArmConditionCode cond, int reg,
+                                     int checkValue)
+{
+    if ((checkValue & 0xff) != checkValue) {
+        int tReg = dvmCompilerAllocTemp(cUnit);
+        loadConstant(cUnit, tReg, checkValue);
+        newLIR2(cUnit, kThumbCmpRR, reg, tReg);
+        dvmCompilerFreeTemp(cUnit, tReg);
+    } else {
+        newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
+    }
+    ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
+    return branch;
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
+                                         ArmLIR *origLIR) {
+    /*
+     * We need two separate pushes, since we want r5 to be pushed first.
+     * Store multiple will push LR first.
+     */
+    ArmLIR *pushFP = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    pushFP->opcode = kThumbPush;
+    pushFP->operands[0] = 1 << r5FP;
+    setupResourceMasks(pushFP);
+    dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP);
+
+    ArmLIR *pushLR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    pushLR->opcode = kThumbPush;
+    /* Thumb push can handle LR, but is encoded differently at bit 8 */
+    pushLR->operands[0] = 1 << 8;
+    setupResourceMasks(pushLR);
+    dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR);
+}
+
+static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
+                                         ArmLIR *origLIR) {
+    /*
+     * Since Thumb cannot pop memory content into LR, we have to pop LR
+     * to a temp first (r5 in this case). Then we move r5 to LR, then pop the
+     * original r5 from stack.
+     */
+    /* Pop memory content(LR) into r5 first */
+    ArmLIR *popForLR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    popForLR->opcode = kThumbPop;
+    popForLR->operands[0] = 1 << r5FP;
+    setupResourceMasks(popForLR);
+    dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR);
+
+    ArmLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP);
+    dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy);
+
+    /* Now restore the original r5 */
+    ArmLIR *popFP = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    popFP->opcode = kThumbPop;
+    popFP->operands[0] = 1 << r5FP;
+    setupResourceMasks(popFP);
+    dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP);
+}
+#endif
diff --git a/vm/compiler/codegen/arm/Thumb/Gen.cpp b/vm/compiler/codegen/arm/Thumb/Gen.cpp
new file mode 100644
index 0000000..abc4420
--- /dev/null
+++ b/vm/compiler/codegen/arm/Thumb/Gen.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Reserve 6 bytes at the beginning of the trace
+ *        +----------------------------+
+ *        | prof count addr (4 bytes)  |
+ *        +----------------------------+
+ *        | chain cell offset (2 bytes)|
+ *        +----------------------------+
+ *
+ * ...and then code to increment the execution
+ *
+ * For continuous profiling (12 bytes):
+ *
+ *       mov   r0, pc       @ move adr of "mov r0,pc" + 4 to r0
+ *       sub   r0, #10      @ back up to addr prof count pointer
+ *       ldr   r0, [r0]     @ get address of counter
+ *       ldr   r1, [r0]
+ *       add   r1, #1
+ *       str   r1, [r0]
+ *
+ * For periodic profiling (4 bytes):
+ *       call  TEMPLATE_PERIODIC_PROFILING
+ *
+ * and return the size (in bytes) of the generated code.
+ */
+
+static int genTraceProfileEntry(CompilationUnit *cUnit)
+{
+    intptr_t addr = (intptr_t)dvmJitNextTraceCounter();
+    assert(__BYTE_ORDER == __LITTLE_ENDIAN);
+    newLIR1(cUnit, kArm16BitData, addr & 0xffff);
+    newLIR1(cUnit, kArm16BitData, (addr >> 16) & 0xffff);
+    cUnit->chainCellOffsetLIR =
+        (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
+    cUnit->headerSize = 6;
+    if ((gDvmJit.profileMode == kTraceProfilingContinuous) ||
+        (gDvmJit.profileMode == kTraceProfilingDisabled)) {
+        /* Thumb instruction used directly here to ensure correct size */
+        newLIR2(cUnit, kThumbMovRR_H2L, r0, r15pc);
+        newLIR2(cUnit, kThumbSubRI8, r0, 10);
+        newLIR3(cUnit, kThumbLdrRRI5, r0, r0, 0);
+        newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
+        newLIR2(cUnit, kThumbAddRI8, r1, 1);
+        newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
+        return 12;
+    } else {
+        int opcode = TEMPLATE_PERIODIC_PROFILING;
+        newLIR2(cUnit, kThumbBlx1,
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+        newLIR2(cUnit, kThumbBlx2,
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+        return 4;
+    }
+}
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
+                rlSrc.lowReg, 0x80000000);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
+                        0x80000000);
+    genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+    genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+    rlResult = dvmCompilerGetReturnWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static bool partialOverlap(int sreg1, int sreg2)
+{
+    return abs(sreg1 - sreg2) == 1;
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
+                         OpKind secondOp, RegLocation rlDest,
+                         RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
+        partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
+        partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
+        // Rare case - not enough registers to properly handle
+        genInterpSingleStep(cUnit, mir);
+    } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
+        // Already 2-operand
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
+        opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+        // Bad case - must use/clobber Src1 and reassign Dest
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
+        opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
+        // Old reg assignments are now invalid
+        dvmCompilerClobber(cUnit, rlResult.lowReg);
+        dvmCompilerClobber(cUnit, rlResult.highReg);
+        dvmCompilerClobber(cUnit, rlSrc1.lowReg);
+        dvmCompilerClobber(cUnit, rlSrc1.highReg);
+        rlDest.location = kLocDalvikFrame;
+        assert(rlSrc1.location == kLocPhysReg);
+        // Reassign registers - rlDest will now get rlSrc1's old regs
+        storeValueWide(cUnit, rlDest, rlSrc1);
+    } else {
+        // Copy Src1 to Dest
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, false);
+        loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
+                            rlResult.highReg);
+        rlResult.location = kLocPhysReg;
+        opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
+        opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    }
+}
+
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
+{
+    int numTemps = sizeof(coreTemps)/sizeof(int);
+    RegisterPool *pool = (RegisterPool *) dvmCompilerNew(sizeof(*pool), true);
+    cUnit->regPool = pool;
+    pool->numCoreTemps = numTemps;
+    pool->coreTemps = (RegisterInfo *)
+            dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
+    pool->numFPTemps = 0;
+    pool->FPTemps = NULL;
+    dvmCompilerInitPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+    dvmCompilerInitPool(pool->FPTemps, NULL, 0);
+    pool->nullCheckedRegs =
+        dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
+}
+
+/* Export the Dalvik PC assicated with an instruction to the StackSave area */
+static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
+{
+    ArmLIR *res;
+    int rDPC = dvmCompilerAllocTemp(cUnit);
+    int rAddr = dvmCompilerAllocTemp(cUnit);
+    int offset = offsetof(StackSaveArea, xtra.currentPc);
+    res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
+    newLIR2(cUnit, kThumbMovRR, rAddr, r5FP);
+    newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset);
+    storeWordDisp( cUnit, rAddr, 0, rDPC);
+    return res;
+}
+
+static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+    genMonitorPortable(cUnit, mir);
+}
+
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+    genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+    rlResult = dvmCompilerGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+{
+    int offset = offsetof(Thread, interpSave.retval);
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
+    int signMask = dvmCompilerAllocTemp(cUnit);
+    loadConstant(cUnit, signMask, 0x7fffffff);
+    newLIR2(cUnit, kThumbAndRR, reg0, signMask);
+    dvmCompilerFreeTemp(cUnit, signMask);
+    storeWordDisp(cUnit, r6SELF, offset, reg0);
+    //TUNING: rewrite this to not clobber
+    dvmCompilerClobber(cUnit, reg0);
+    return false;
+}
+
+static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
+{
+    int offset = offsetof(Thread, interpSave.retval);
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    int reglo = regSrc.lowReg;
+    int reghi = regSrc.highReg;
+    int signMask = dvmCompilerAllocTemp(cUnit);
+    loadConstant(cUnit, signMask, 0x7fffffff);
+    storeWordDisp(cUnit, r6SELF, offset, reglo);
+    newLIR2(cUnit, kThumbAndRR, reghi, signMask);
+    dvmCompilerFreeTemp(cUnit, signMask);
+    storeWordDisp(cUnit, r6SELF, offset + 4, reghi);
+    //TUNING: rewrite this to not clobber
+    dvmCompilerClobber(cUnit, reghi);
+    return false;
+}
+
+/* No select in thumb, so we need to branch.  Thumb2 will do better */
+static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+{
+    int offset = offsetof(Thread, interpSave.retval);
+    RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+    int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
+    int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
+    newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
+    ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
+           isMin ? kArmCondLt : kArmCondGt);
+    newLIR2(cUnit, kThumbMovRR, reg0, reg1);
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    newLIR3(cUnit, kThumbStrRRI5, reg0, r6SELF, offset >> 2);
+    branch1->generic.target = (LIR *)target;
+    //TUNING: rewrite this to not clobber
+    dvmCompilerClobber(cUnit,reg0);
+    return false;
+}
+
+static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
+        RegLocation rlSrc, RegLocation rlResult, int lit,
+        int firstBit, int secondBit)
+{
+    // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
+    // to do a regular multiply.
+    opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
+}
diff --git a/vm/compiler/codegen/arm/Thumb/Ralloc.cpp b/vm/compiler/codegen/arm/Thumb/Ralloc.cpp
new file mode 100644
index 0000000..6769972
--- /dev/null
+++ b/vm/compiler/codegen/arm/Thumb/Ralloc.cpp
@@ -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.
+ */
+
+/*
+ * This file contains codegen for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double.  Low reg in low byte,
+ * high reg in next byte.
+ */
+int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+                                  int regClass)
+{
+    int highReg;
+    int lowReg;
+    int res = 0;
+    lowReg = dvmCompilerAllocTemp(cUnit);
+    highReg = dvmCompilerAllocTemp(cUnit);
+    res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+    return res;
+}
+
+int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+    return dvmCompilerAllocTemp(cUnit);
+}
diff --git a/vm/compiler/codegen/arm/Thumb2/Factory.cpp b/vm/compiler/codegen/arm/Thumb2/Factory.cpp
new file mode 100644
index 0000000..9c9ce13
--- /dev/null
+++ b/vm/compiler/codegen/arm/Thumb2/Factory.cpp
@@ -0,0 +1,1267 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
+static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
+                        fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
+
+static int encodeImmSingle(int value)
+{
+    int res;
+    int bitA =    (value & 0x80000000) >> 31;
+    int notBitB = (value & 0x40000000) >> 30;
+    int bitB =    (value & 0x20000000) >> 29;
+    int bSmear =  (value & 0x3e000000) >> 25;
+    int slice =   (value & 0x01f80000) >> 19;
+    int zeroes =  (value & 0x0007ffff);
+    if (zeroes != 0)
+        return -1;
+    if (bitB) {
+        if ((notBitB != 0) || (bSmear != 0x1f))
+            return -1;
+    } else {
+        if ((notBitB != 1) || (bSmear != 0x0))
+            return -1;
+    }
+    res = (bitA << 7) | (bitB << 6) | slice;
+    return res;
+}
+
+static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
+                                   int value)
+{
+    int encodedImm = encodeImmSingle(value);
+    assert(SINGLEREG(rDest));
+    if (encodedImm >= 0) {
+        return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
+    }
+    ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, &cUnit->literalList, value);
+    }
+    ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opcode = kThumb2Vldrs;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = rDest;
+    loadPcRel->operands[1] = r15pc;
+    setupResourceMasks(loadPcRel);
+    setMemRefType(loadPcRel, true, kLiteral);
+    loadPcRel->aliasInfo = dataTarget->operands[0];
+    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+    return loadPcRel;
+}
+
+static int leadingZeros(u4 val)
+{
+    u4 alt;
+    int n;
+    int count;
+
+    count = 16;
+    n = 32;
+    do {
+        alt = val >> count;
+        if (alt != 0) {
+            n = n - count;
+            val = alt;
+        }
+        count >>= 1;
+    } while (count);
+    return n - val;
+}
+
+/*
+ * Determine whether value can be encoded as a Thumb2 modified
+ * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
+ */
+static int modifiedImmediate(u4 value)
+{
+   int zLeading;
+   int zTrailing;
+   u4 b0 = value & 0xff;
+
+   /* Note: case of value==0 must use 0:000:0:0000000 encoding */
+   if (value <= 0xFF)
+       return b0;  // 0:000:a:bcdefgh
+   if (value == ((b0 << 16) | b0))
+       return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
+   if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
+       return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
+   b0 = (value >> 8) & 0xff;
+   if (value == ((b0 << 24) | (b0 << 8)))
+       return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
+   /* Can we do it with rotation? */
+   zLeading = leadingZeros(value);
+   zTrailing = 32 - leadingZeros(~value & (value - 1));
+   /* A run of eight or fewer active bits? */
+   if ((zLeading + zTrailing) < 24)
+       return -1;  /* No - bail */
+   /* left-justify the constant, discarding msb (known to be 1) */
+   value <<= zLeading + 1;
+   /* Create bcdefgh */
+   value >>= 25;
+   /* Put it all together */
+   return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
+}
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool.
+ *
+ * No additional register clobbering operation performed. Use this version when
+ * 1) rDest is freshly returned from dvmCompilerAllocTemp or
+ * 2) The codegen is under fixed register usage
+ */
+static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
+                                     int value)
+{
+    ArmLIR *res;
+    int modImm;
+
+    if (FPREG(rDest)) {
+        return loadFPConstantValue(cUnit, rDest, value);
+    }
+
+    /* See if the value can be constructed cheaply */
+    if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
+        return newLIR2(cUnit, kThumbMovImm, rDest, value);
+    }
+    /* Check Modified immediate special cases */
+    modImm = modifiedImmediate(value);
+    if (modImm >= 0) {
+        res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
+        return res;
+    }
+    modImm = modifiedImmediate(~value);
+    if (modImm >= 0) {
+        res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
+        return res;
+    }
+    /* 16-bit immediate? */
+    if ((value & 0xffff) == value) {
+        res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
+        return res;
+    }
+    /* No shortcut - go ahead and use literal pool */
+    ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, &cUnit->literalList, value);
+    }
+    ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opcode = kThumb2LdrPcRel12;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = rDest;
+    setupResourceMasks(loadPcRel);
+    setMemRefType(loadPcRel, true, kLiteral);
+    loadPcRel->aliasInfo = dataTarget->operands[0];
+    res = loadPcRel;
+    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) {
+        opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
+    }
+    return res;
+}
+
+/*
+ * Load an immediate value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+    if (dvmCompilerIsTemp(cUnit, rDest)) {
+        dvmCompilerClobber(cUnit, rDest);
+        dvmCompilerMarkInUse(cUnit, rDest);
+    }
+    return loadConstantNoClobber(cUnit, rDest, value);
+}
+
+/*
+ * Load a class pointer value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
+{
+    ArmLIR *res;
+    cUnit->hasClassLiterals = true;
+    if (dvmCompilerIsTemp(cUnit, rDest)) {
+        dvmCompilerClobber(cUnit, rDest);
+        dvmCompilerMarkInUse(cUnit, rDest);
+    }
+    ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, &cUnit->classPointerList, value);
+        /* Counts the number of class pointers in this translation */
+        cUnit->numClassPointers++;
+    }
+    ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opcode = kThumb2LdrPcRel12;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = rDest;
+    setupResourceMasks(loadPcRel);
+    setMemRefType(loadPcRel, true, kLiteral);
+    loadPcRel->aliasInfo = dataTarget->operands[0];
+    res = loadPcRel;
+    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+    return res;
+}
+
+static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpUncondBr:
+            opcode = kThumbBUncond;
+            break;
+        default:
+            assert(0);
+    }
+    return newLIR0(cUnit, opcode);
+}
+
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
+{
+    return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
+}
+
+static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpPush: {
+            if ((value & 0xff00) == 0) {
+                opcode = kThumbPush;
+            } else if ((value & 0xff00) == (1 << r14lr)) {
+                /* Thumb push can handle lr, which is encoded by bit 8 */
+                opcode = kThumbPush;
+                value = (value & 0xff) | (1<<8);
+            } else {
+                opcode = kThumb2Push;
+            }
+            break;
+        }
+        case kOpPop: {
+            if ((value & 0xff00) == 0) {
+                opcode = kThumbPop;
+            } else if ((value & 0xff00) == (1 << r15pc)) {
+                /* Thumb pop can handle pc, which is encoded by bit 8 */
+                opcode = kThumbPop;
+                value = (value & 0xff) | (1<<8);
+            } else {
+                opcode = kThumb2Pop;
+            }
+            break;
+        }
+        default:
+            assert(0);
+    }
+    return newLIR1(cUnit, opcode, value);
+}
+
+static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpBlx:
+            opcode = kThumbBlxR;
+            break;
+        default:
+            assert(0);
+    }
+    return newLIR1(cUnit, opcode, rDestSrc);
+}
+
+static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2, int shift)
+{
+    bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpAdc:
+            opcode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
+            break;
+        case kOpAnd:
+            opcode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
+            break;
+        case kOpBic:
+            opcode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
+            break;
+        case kOpCmn:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
+            break;
+        case kOpCmp:
+            if (thumbForm)
+                opcode = kThumbCmpRR;
+            else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
+                opcode = kThumbCmpHH;
+            else if ((shift == 0) && LOWREG(rDestSrc1))
+                opcode = kThumbCmpLH;
+            else if (shift == 0)
+                opcode = kThumbCmpHL;
+            else
+                opcode = kThumb2CmpRR;
+            break;
+        case kOpXor:
+            opcode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
+            break;
+        case kOpMov:
+            assert(shift == 0);
+            if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
+                opcode = kThumbMovRR;
+            else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
+                opcode = kThumbMovRR_H2H;
+            else if (LOWREG(rDestSrc1))
+                opcode = kThumbMovRR_H2L;
+            else
+                opcode = kThumbMovRR_L2H;
+            break;
+        case kOpMul:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
+            break;
+        case kOpMvn:
+            opcode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
+            break;
+        case kOpNeg:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
+            break;
+        case kOpOr:
+            opcode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
+            break;
+        case kOpSbc:
+            opcode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
+            break;
+        case kOpTst:
+            opcode = (thumbForm) ? kThumbTst : kThumb2TstRR;
+            break;
+        case kOpLsl:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
+            break;
+        case kOpLsr:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
+            break;
+        case kOpAsr:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
+            break;
+        case kOpRor:
+            assert(shift == 0);
+            opcode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
+            break;
+        case kOpAdd:
+            opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
+            break;
+        case kOpSub:
+            opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
+            break;
+        case kOp2Byte:
+            assert(shift == 0);
+            return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
+        case kOp2Short:
+            assert(shift == 0);
+            return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
+        case kOp2Char:
+            assert(shift == 0);
+            return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
+        default:
+            assert(0);
+            break;
+    }
+    assert(opcode >= 0);
+    if (EncodingMap[opcode].flags & IS_BINARY_OP)
+        return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
+    else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
+        if (EncodingMap[opcode].fieldLoc[2].kind == kFmtShift)
+            return newLIR3(cUnit, opcode, rDestSrc1, rSrc2, shift);
+        else
+            return newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2);
+    } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
+        return newLIR4(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2, shift);
+    else {
+        assert(0);
+        return NULL;
+    }
+}
+
+static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2)
+{
+    return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
+}
+
+static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
+                                int rDest, int rSrc1, int rSrc2, int shift)
+{
+    ArmOpcode opcode = kThumbBkpt;
+    bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
+                      LOWREG(rSrc2);
+    switch (op) {
+        case kOpAdd:
+            opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
+            break;
+        case kOpSub:
+            opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
+            break;
+        case kOpAdc:
+            opcode = kThumb2AdcRRR;
+            break;
+        case kOpAnd:
+            opcode = kThumb2AndRRR;
+            break;
+        case kOpBic:
+            opcode = kThumb2BicRRR;
+            break;
+        case kOpXor:
+            opcode = kThumb2EorRRR;
+            break;
+        case kOpMul:
+            assert(shift == 0);
+            opcode = kThumb2MulRRR;
+            break;
+        case kOpOr:
+            opcode = kThumb2OrrRRR;
+            break;
+        case kOpSbc:
+            opcode = kThumb2SbcRRR;
+            break;
+        case kOpLsl:
+            assert(shift == 0);
+            opcode = kThumb2LslRRR;
+            break;
+        case kOpLsr:
+            assert(shift == 0);
+            opcode = kThumb2LsrRRR;
+            break;
+        case kOpAsr:
+            assert(shift == 0);
+            opcode = kThumb2AsrRRR;
+            break;
+        case kOpRor:
+            assert(shift == 0);
+            opcode = kThumb2RorRRR;
+            break;
+        default:
+            assert(0);
+            break;
+    }
+    assert(opcode >= 0);
+    if (EncodingMap[opcode].flags & IS_QUAD_OP)
+        return newLIR4(cUnit, opcode, rDest, rSrc1, rSrc2, shift);
+    else {
+        assert(EncodingMap[opcode].flags & IS_TERTIARY_OP);
+        return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
+    }
+}
+
+static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int rSrc2)
+{
+    return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
+}
+
+static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value)
+{
+    ArmLIR *res;
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    ArmOpcode opcode = kThumbBkpt;
+    ArmOpcode altOpcode = kThumbBkpt;
+    bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
+    int modImm = modifiedImmediate(value);
+    int modImmNeg = modifiedImmediate(-value);
+
+    switch(op) {
+        case kOpLsl:
+            if (allLowRegs)
+                return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
+            else
+                return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
+        case kOpLsr:
+            if (allLowRegs)
+                return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
+            else
+                return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
+        case kOpAsr:
+            if (allLowRegs)
+                return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
+            else
+                return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
+        case kOpRor:
+            return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
+        case kOpAdd:
+            if (LOWREG(rDest) && (rSrc1 == r13sp) &&
+                (value <= 1020) && ((value & 0x3)==0)) {
+                return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
+                               value >> 2);
+            } else if (LOWREG(rDest) && (rSrc1 == r15pc) &&
+                       (value <= 1020) && ((value & 0x3)==0)) {
+                return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
+                               value >> 2);
+            }
+            opcode = kThumb2AddRRI8;
+            altOpcode = kThumb2AddRRR;
+            // Note: intentional fallthrough
+        case kOpSub:
+            if (allLowRegs && ((absValue & 0x7) == absValue)) {
+                if (op == kOpAdd)
+                    opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
+                else
+                    opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
+                return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
+            } else if ((absValue & 0xff) == absValue) {
+                if (op == kOpAdd)
+                    opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
+                else
+                    opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
+                return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
+            }
+            if (modImmNeg >= 0) {
+                op = (op == kOpAdd) ? kOpSub : kOpAdd;
+                modImm = modImmNeg;
+            }
+            if (op == kOpSub) {
+                opcode = kThumb2SubRRI8;
+                altOpcode = kThumb2SubRRR;
+            }
+            break;
+        case kOpAdc:
+            opcode = kThumb2AdcRRI8;
+            altOpcode = kThumb2AdcRRR;
+            break;
+        case kOpSbc:
+            opcode = kThumb2SbcRRI8;
+            altOpcode = kThumb2SbcRRR;
+            break;
+        case kOpOr:
+            opcode = kThumb2OrrRRI8;
+            altOpcode = kThumb2OrrRRR;
+            break;
+        case kOpAnd:
+            opcode = kThumb2AndRRI8;
+            altOpcode = kThumb2AndRRR;
+            break;
+        case kOpXor:
+            opcode = kThumb2EorRRI8;
+            altOpcode = kThumb2EorRRR;
+            break;
+        case kOpMul:
+            //TUNING: power of 2, shift & add
+            modImm = -1;
+            altOpcode = kThumb2MulRRR;
+            break;
+        case kOpCmp: {
+            int modImm = modifiedImmediate(value);
+            ArmLIR *res;
+            if (modImm >= 0) {
+                res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
+            } else {
+                int rTmp = dvmCompilerAllocTemp(cUnit);
+                res = loadConstant(cUnit, rTmp, value);
+                opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
+                dvmCompilerFreeTemp(cUnit, rTmp);
+            }
+            return res;
+        }
+        default:
+            assert(0);
+    }
+
+    if (modImm >= 0) {
+        return newLIR3(cUnit, opcode, rDest, rSrc1, modImm);
+    } else {
+        int rScratch = dvmCompilerAllocTemp(cUnit);
+        loadConstant(cUnit, rScratch, value);
+        if (EncodingMap[altOpcode].flags & IS_QUAD_OP)
+            res = newLIR4(cUnit, altOpcode, rDest, rSrc1, rScratch, 0);
+        else
+            res = newLIR3(cUnit, altOpcode, rDest, rSrc1, rScratch);
+        dvmCompilerFreeTemp(cUnit, rScratch);
+        return res;
+    }
+}
+
+/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
+static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int value)
+{
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
+    ArmOpcode opcode = kThumbBkpt;
+    switch (op) {
+        case kOpAdd:
+            if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
+                assert((value & 0x3) == 0);
+                return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
+            } else if (shortForm) {
+                opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
+            }
+            break;
+        case kOpSub:
+            if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
+                assert((value & 0x3) == 0);
+                return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
+            } else if (shortForm) {
+                opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
+            }
+            break;
+        case kOpCmp:
+            if (LOWREG(rDestSrc1) && shortForm)
+                opcode = (shortForm) ?  kThumbCmpRI8 : kThumbCmpRR;
+            else if (LOWREG(rDestSrc1))
+                opcode = kThumbCmpRR;
+            else {
+                shortForm = false;
+                opcode = kThumbCmpHL;
+            }
+            break;
+        default:
+            /* Punt to opRegRegImm - if bad case catch it there */
+            shortForm = false;
+            break;
+    }
+    if (shortForm)
+        return newLIR2(cUnit, opcode, rDestSrc1, absValue);
+    else {
+        return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+    }
+}
+
+/*
+ * Determine whether value can be encoded as a Thumb2 floating point
+ * immediate.  If not, return -1.  If so return encoded 8-bit value.
+ */
+static int encodeImmDoubleHigh(int value)
+{
+    int res;
+    int bitA =    (value & 0x80000000) >> 31;
+    int notBitB = (value & 0x40000000) >> 30;
+    int bitB =    (value & 0x20000000) >> 29;
+    int bSmear =  (value & 0x3fc00000) >> 22;
+    int slice =   (value & 0x003f0000) >> 16;
+    int zeroes =  (value & 0x0000ffff);
+    if (zeroes != 0)
+        return -1;
+    if (bitB) {
+        if ((notBitB != 0) || (bSmear != 0x1f))
+            return -1;
+    } else {
+        if ((notBitB != 1) || (bSmear != 0x0))
+            return -1;
+    }
+    res = (bitA << 7) | (bitB << 6) | slice;
+    return res;
+}
+
+static int encodeImmDouble(int valLo, int valHi)
+{
+    int res = -1;
+    if (valLo == 0)
+        res = encodeImmDoubleHigh(valHi);
+    return res;
+}
+
+static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+                                     int rDestHi, int valLo, int valHi)
+{
+    int encodedImm = encodeImmDouble(valLo, valHi);
+    ArmLIR *res;
+    if (FPREG(rDestLo) && (encodedImm >= 0)) {
+        res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
+                      encodedImm);
+    } else {
+        res = loadConstantNoClobber(cUnit, rDestLo, valLo);
+        loadConstantNoClobber(cUnit, rDestHi, valHi);
+    }
+    return res;
+}
+
+static int encodeShift(int code, int amount) {
+    return ((amount & 0x1f) << 2) | code;
+}
+
+static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+                               int rIndex, int rDest, int scale, OpSize size)
+{
+    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
+    ArmLIR *load;
+    ArmOpcode opcode = kThumbBkpt;
+    bool thumbForm = (allLowRegs && (scale == 0));
+    int regPtr;
+
+    if (FPREG(rDest)) {
+        assert(SINGLEREG(rDest));
+        assert((size == kWord) || (size == kSingle));
+        opcode = kThumb2Vldrs;
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+
+    switch (size) {
+        case kSingle:
+            regPtr = dvmCompilerAllocTemp(cUnit);
+            if (scale) {
+                newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
+                        encodeShift(kArmLsl, scale));
+            } else {
+                opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
+            }
+            load = newLIR3(cUnit, opcode, rDest, regPtr, 0);
+#if defined(WITH_SELF_VERIFICATION)
+            if (cUnit->heapMemOp)
+                load->flags.insertWrapper = true;
+#endif
+            return load;
+        case kWord:
+            opcode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
+            break;
+        case kUnsignedHalf:
+            opcode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
+            break;
+        case kSignedHalf:
+            opcode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
+            break;
+        case kUnsignedByte:
+            opcode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
+            break;
+        case kSignedByte:
+            opcode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
+            break;
+        default:
+            assert(0);
+    }
+    if (thumbForm)
+        load = newLIR3(cUnit, opcode, rDest, rBase, rIndex);
+    else
+        load = newLIR4(cUnit, opcode, rDest, rBase, rIndex, scale);
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        load->flags.insertWrapper = true;
+#endif
+    return load;
+}
+
+static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+                                int rIndex, int rSrc, int scale, OpSize size)
+{
+    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
+    ArmLIR *store;
+    ArmOpcode opcode = kThumbBkpt;
+    bool thumbForm = (allLowRegs && (scale == 0));
+    int regPtr;
+
+    if (FPREG(rSrc)) {
+        assert(SINGLEREG(rSrc));
+        assert((size == kWord) || (size == kSingle));
+        opcode = kThumb2Vstrs;
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+
+    switch (size) {
+        case kSingle:
+            regPtr = dvmCompilerAllocTemp(cUnit);
+            if (scale) {
+                newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
+                        encodeShift(kArmLsl, scale));
+            } else {
+                opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
+            }
+            store = newLIR3(cUnit, opcode, rSrc, regPtr, 0);
+#if defined(WITH_SELF_VERIFICATION)
+            if (cUnit->heapMemOp)
+                store->flags.insertWrapper = true;
+#endif
+            return store;
+        case kWord:
+            opcode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opcode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opcode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
+            break;
+        default:
+            assert(0);
+    }
+    if (thumbForm)
+        store = newLIR3(cUnit, opcode, rSrc, rBase, rIndex);
+    else
+        store = newLIR4(cUnit, opcode, rSrc, rBase, rIndex, scale);
+
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        store->flags.insertWrapper = true;
+#endif
+    return store;
+}
+
+/*
+ * Load value from base + displacement.  Optionally perform null check
+ * on base (which must have an associated sReg and MIR).  If not
+ * performing null check, incoming MIR can be null.
+ */
+static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDest, int rDestHi,
+                                OpSize size, int sReg)
+{
+    ArmLIR *res, *load;
+    ArmOpcode opcode = kThumbBkpt;
+    bool shortForm = false;
+    bool thumb2Form = (displacement < 4092 && displacement >= 0);
+    bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
+    int encodedDisp = displacement;
+
+    switch (size) {
+        case kDouble:
+        case kLong:
+            if (FPREG(rDest)) {
+                if (SINGLEREG(rDest)) {
+                    assert(FPREG(rDestHi));
+                    rDest = S2D(rDest, rDestHi);
+                }
+                opcode = kThumb2Vldrd;
+                if (displacement <= 1020) {
+                    shortForm = true;
+                    encodedDisp >>= 2;
+                }
+                break;
+            } else {
+                res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
+                                       -1, kWord, sReg);
+                loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
+                                 -1, kWord, INVALID_SREG);
+                return res;
+            }
+        case kSingle:
+        case kWord:
+            if (FPREG(rDest)) {
+                opcode = kThumb2Vldrs;
+                if (displacement <= 1020) {
+                    shortForm = true;
+                    encodedDisp >>= 2;
+                }
+                break;
+            }
+            if (LOWREG(rDest) && (rBase == r15pc) &&
+                (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrPcRel;
+            } else if (LOWREG(rDest) && (rBase == r13sp) &&
+                      (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrSpRel;
+            } else if (allLowRegs && displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbLdrRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2LdrRRI12;
+            }
+            break;
+        case kUnsignedHalf:
+            if (allLowRegs && displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opcode = kThumbLdrhRRI5;
+            } else if (displacement < 4092 && displacement >= 0) {
+                shortForm = true;
+                opcode = kThumb2LdrhRRI12;
+            }
+            break;
+        case kSignedHalf:
+            if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2LdrshRRI12;
+            }
+            break;
+        case kUnsignedByte:
+            if (allLowRegs && displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opcode = kThumbLdrbRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2LdrbRRI12;
+            }
+            break;
+        case kSignedByte:
+            if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2LdrsbRRI12;
+            }
+            break;
+        default:
+            assert(0);
+    }
+
+    if (shortForm) {
+        load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
+    } else {
+        int regOffset = dvmCompilerAllocTemp(cUnit);
+        res = loadConstant(cUnit, regOffset, encodedDisp);
+        load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
+        dvmCompilerFreeTemp(cUnit, regOffset);
+    }
+
+    if (rBase == r5FP) {
+        annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
+    }
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        load->flags.insertWrapper = true;
+#endif
+    return load;
+}
+
+static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+                            int displacement, int rDest, OpSize size,
+                            int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+                            size, sReg);
+}
+
+static  ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                 int displacement, int rDestLo, int rDestHi,
+                                 int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+                            kLong, sReg);
+}
+
+
+static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrc, int rSrcHi,
+                                 OpSize size)
+{
+    ArmLIR *res, *store;
+    ArmOpcode opcode = kThumbBkpt;
+    bool shortForm = false;
+    bool thumb2Form = (displacement < 4092 && displacement >= 0);
+    bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
+    int encodedDisp = displacement;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            if (!FPREG(rSrc)) {
+                res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
+                                        -1, kWord);
+                storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
+                                  -1, kWord);
+                return res;
+            }
+            if (SINGLEREG(rSrc)) {
+                assert(FPREG(rSrcHi));
+                rSrc = S2D(rSrc, rSrcHi);
+            }
+            opcode = kThumb2Vstrd;
+            if (displacement <= 1020) {
+                shortForm = true;
+                encodedDisp >>= 2;
+            }
+            break;
+        case kSingle:
+        case kWord:
+            if (FPREG(rSrc)) {
+                assert(SINGLEREG(rSrc));
+                opcode = kThumb2Vstrs;
+                if (displacement <= 1020) {
+                    shortForm = true;
+                    encodedDisp >>= 2;
+                }
+            break;
+            }
+            if (allLowRegs && displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opcode = kThumbStrRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2StrRRI12;
+            }
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            if (allLowRegs && displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opcode = kThumbStrhRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2StrhRRI12;
+            }
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            if (allLowRegs && displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opcode = kThumbStrbRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opcode = kThumb2StrbRRI12;
+            }
+            break;
+        default:
+            assert(0);
+    }
+    if (shortForm) {
+        store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
+    } else {
+        int rScratch = dvmCompilerAllocTemp(cUnit);
+        res = loadConstant(cUnit, rScratch, encodedDisp);
+        store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
+        dvmCompilerFreeTemp(cUnit, rScratch);
+    }
+
+    if (rBase == r5FP) {
+        annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
+    }
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        store->flags.insertWrapper = true;
+#endif
+    return res;
+}
+
+static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
+        res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
+    } else {
+        res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask);
+    }
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->flags.insertWrapper = true;
+#endif
+    genBarrier(cUnit);
+    return res;
+}
+
+static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
+        res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
+    } else {
+        res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask);
+    }
+#if defined(WITH_SELF_VERIFICATION)
+    if (cUnit->heapMemOp)
+        res->flags.insertWrapper = true;
+#endif
+    genBarrier(cUnit);
+    return res;
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
+}
+
+/*
+ * Generate a register comparison to an immediate and branch.  Caller
+ * is responsible for setting branch target field.
+ */
+static ArmLIR *genCmpImmBranch(CompilationUnit *cUnit,
+                              ArmConditionCode cond, int reg,
+                              int checkValue)
+{
+    ArmLIR *branch;
+    int modImm;
+    if ((LOWREG(reg)) && (checkValue == 0) &&
+       ((cond == kArmCondEq) || (cond == kArmCondNe))) {
+        branch = newLIR2(cUnit,
+                         (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
+                         reg, 0);
+    } else {
+        modImm = modifiedImmediate(checkValue);
+        if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
+            newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
+        } else if (modImm >= 0) {
+            newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
+        } else {
+            int tReg = dvmCompilerAllocTemp(cUnit);
+            loadConstant(cUnit, tReg, checkValue);
+            opRegReg(cUnit, kOpCmp, reg, tReg);
+        }
+        branch = newLIR2(cUnit, kThumbBCond, 0, cond);
+    }
+    return branch;
+}
+
+static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    ArmLIR* res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    } else {
+        assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
+        if (DOUBLEREG(rDest)) {
+            res->opcode = kThumb2Vmovd;
+        } else {
+            if (SINGLEREG(rDest)) {
+                res->opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
+            } else {
+                assert(SINGLEREG(rSrc));
+                res->opcode = kThumb2Fmrs;
+            }
+        }
+        res->operands[0] = rDest;
+        res->operands[1] = rSrc;
+    }
+    setupResourceMasks(res);
+    return res;
+}
+
+static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    ArmLIR* res;
+    ArmOpcode opcode;
+    if (FPREG(rDest) || FPREG(rSrc))
+        return fpRegCopy(cUnit, rDest, rSrc);
+    res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    if (LOWREG(rDest) && LOWREG(rSrc))
+        opcode = kThumbMovRR;
+    else if (!LOWREG(rDest) && !LOWREG(rSrc))
+         opcode = kThumbMovRR_H2H;
+    else if (LOWREG(rDest))
+         opcode = kThumbMovRR_H2L;
+    else
+         opcode = kThumbMovRR_L2H;
+
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    res->opcode = opcode;
+    setupResourceMasks(res);
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    }
+    return res;
+}
+
+static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+    dvmCompilerAppendLIR(cUnit, (LIR*)res);
+    return res;
+}
+
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                           int srcLo, int srcHi)
+{
+    bool destFP = FPREG(destLo) && FPREG(destHi);
+    bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+    assert(FPREG(srcLo) == FPREG(srcHi));
+    assert(FPREG(destLo) == FPREG(destHi));
+    if (destFP) {
+        if (srcFP) {
+            genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+        } else {
+            newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
+        }
+    } else {
+        if (srcFP) {
+            newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
+        } else {
+            // Handle overlap
+            if (srcHi == destLo) {
+                genRegCopy(cUnit, destHi, srcHi);
+                genRegCopy(cUnit, destLo, srcLo);
+            } else {
+                genRegCopy(cUnit, destLo, srcLo);
+                genRegCopy(cUnit, destHi, srcHi);
+            }
+        }
+    }
+}
+
+#if defined(WITH_SELF_VERIFICATION)
+static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
+                                         ArmLIR *origLIR) {
+    ArmLIR *push = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    push->opcode = kThumbPush;
+    /* Thumb push can handle LR (encoded at bit 8) */
+    push->operands[0] = (1 << r5FP | 1 << 8);
+    setupResourceMasks(push);
+    dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) push);
+}
+
+static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
+                                         ArmLIR *origLIR) {
+    ArmLIR *pop = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
+    /* Thumb pop cannot store into LR - use Thumb2 here */
+    pop->opcode = kThumb2Pop;
+    pop->operands[0] = (1 << r5FP | 1 << r14lr);
+    setupResourceMasks(pop);
+    dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) pop);
+}
+#endif
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.cpp b/vm/compiler/codegen/arm/Thumb2/Gen.cpp
new file mode 100644
index 0000000..fcf0fe3
--- /dev/null
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.cpp
@@ -0,0 +1,455 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Thumb2 ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Reserve 6 bytes at the beginning of the trace
+ *        +----------------------------+
+ *        | prof count addr (4 bytes)  |
+ *        +----------------------------+
+ *        | chain cell offset (2 bytes)|
+ *        +----------------------------+
+ *
+ * ...and then code to increment the execution
+ *
+ * For continuous profiling (10 bytes)
+ *       ldr   r0, [pc-8]   @ get prof count addr    [4 bytes]
+ *       ldr   r1, [r0]     @ load counter           [2 bytes]
+ *       add   r1, #1       @ increment              [2 bytes]
+ *       str   r1, [r0]     @ store                  [2 bytes]
+ *
+ * For periodic profiling (4 bytes)
+ *       call  TEMPLATE_PERIODIC_PROFILING
+ *
+ * and return the size (in bytes) of the generated code.
+ */
+
+static int genTraceProfileEntry(CompilationUnit *cUnit)
+{
+    intptr_t addr = (intptr_t)dvmJitNextTraceCounter();
+    assert(__BYTE_ORDER == __LITTLE_ENDIAN);
+    newLIR1(cUnit, kArm16BitData, addr & 0xffff);
+    newLIR1(cUnit, kArm16BitData, (addr >> 16) & 0xffff);
+    cUnit->chainCellOffsetLIR =
+        (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
+    cUnit->headerSize = 6;
+    if ((gDvmJit.profileMode == kTraceProfilingContinuous) ||
+        (gDvmJit.profileMode == kTraceProfilingDisabled)) {
+        /* Thumb[2] instruction used directly here to ensure correct size */
+        newLIR2(cUnit, kThumb2LdrPcReln12, r0, 8);
+        newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
+        newLIR2(cUnit, kThumbAddRI8, r1, 1);
+        newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
+        return 10;
+    } else {
+        int opcode = TEMPLATE_PERIODIC_PROFILING;
+        newLIR2(cUnit, kThumbBlx1,
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+        newLIR2(cUnit, kThumbBlx2,
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
+            (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
+        return 4;
+    }
+}
+
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc.lowReg, rlSrc.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+/*
+ * To avoid possible conflicts, we use a lot of temps here.  Note that
+ * our usage of Thumb2 instruction forms avoids the problems with register
+ * reuse for multiply instructions prior to arm6.
+ */
+static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    int resLo = dvmCompilerAllocTemp(cUnit);
+    int resHi = dvmCompilerAllocTemp(cUnit);
+    int tmp1 = dvmCompilerAllocTemp(cUnit);
+
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+
+    newLIR3(cUnit, kThumb2MulRRR, tmp1, rlSrc2.lowReg, rlSrc1.highReg);
+    newLIR4(cUnit, kThumb2Umull, resLo, resHi, rlSrc2.lowReg, rlSrc1.lowReg);
+    newLIR4(cUnit, kThumb2Mla, tmp1, rlSrc1.lowReg, rlSrc2.highReg, tmp1);
+    newLIR4(cUnit, kThumb2AddRRR, resHi, tmp1, resHi, 0);
+    dvmCompilerFreeTemp(cUnit, tmp1);
+
+    rlResult = dvmCompilerGetReturnWide(cUnit);  // Just as a template, will patch
+    rlResult.lowReg = resLo;
+    rlResult.highReg = resHi;
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
+                         OpKind secondOp, RegLocation rlDest,
+                         RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
+                rlSrc2.highReg);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
+{
+    int numTemps = sizeof(coreTemps)/sizeof(int);
+    int numFPTemps = sizeof(fpTemps)/sizeof(int);
+    RegisterPool *pool = (RegisterPool *)dvmCompilerNew(sizeof(*pool), true);
+    cUnit->regPool = pool;
+    pool->numCoreTemps = numTemps;
+    pool->coreTemps = (RegisterInfo *)
+            dvmCompilerNew(numTemps * sizeof(*cUnit->regPool->coreTemps), true);
+    pool->numFPTemps = numFPTemps;
+    pool->FPTemps = (RegisterInfo *)
+            dvmCompilerNew(numFPTemps * sizeof(*cUnit->regPool->FPTemps), true);
+    dvmCompilerInitPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+    dvmCompilerInitPool(pool->FPTemps, fpTemps, pool->numFPTemps);
+    pool->nullCheckedRegs =
+        dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
+}
+
+/*
+ * Generate a Thumb2 IT instruction, which can nullify up to
+ * four subsequent instructions based on a condition and its
+ * inverse.  The condition applies to the first instruction, which
+ * is executed if the condition is met.  The string "guide" consists
+ * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
+ * A "T" means the instruction is executed if the condition is
+ * met, and an "E" means the instruction is executed if the condition
+ * is not met.
+ */
+static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
+                     const char *guide)
+{
+    int mask;
+    int condBit = code & 1;
+    int altBit = condBit ^ 1;
+    int mask3 = 0;
+    int mask2 = 0;
+    int mask1 = 0;
+
+    //Note: case fallthroughs intentional
+    switch(strlen(guide)) {
+        case 3:
+            mask1 = (guide[2] == 'T') ? condBit : altBit;
+        case 2:
+            mask2 = (guide[1] == 'T') ? condBit : altBit;
+        case 1:
+            mask3 = (guide[0] == 'T') ? condBit : altBit;
+            break;
+        case 0:
+            break;
+        default:
+            LOGE("Jit: bad case in genIT");
+            dvmCompilerAbort(cUnit);
+    }
+    mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
+           (1 << (3 - strlen(guide)));
+    return newLIR2(cUnit, kThumb2It, code, mask);
+}
+
+/* Export the Dalvik PC assicated with an instruction to the StackSave area */
+static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
+{
+    ArmLIR *res;
+    int offset = offsetof(StackSaveArea, xtra.currentPc);
+    int rDPC = dvmCompilerAllocTemp(cUnit);
+    res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
+    newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, r5FP,
+            sizeof(StackSaveArea) - offset);
+    dvmCompilerFreeTemp(cUnit, rDPC);
+    return res;
+}
+
+/*
+ * Handle simple case (thin lock) inline.  If it's complicated, bail
+ * out to the heavyweight lock/unlock routines.  We'll use dedicated
+ * registers here in order to be in the right position in case we
+ * to bail to dvm[Lock/Unlock]Object(self, object)
+ *
+ * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
+ * r1 -> object [arg1 for dvm[Lock/Unlock]Object
+ * r2 -> intial contents of object->lock, later result of strex
+ * r3 -> self->threadId
+ * r7 -> temp to hold new lock value [unlock only]
+ * r4 -> allow to be used by utilities as general temp
+ *
+ * The result of the strex is 0 if we acquire the lock.
+ *
+ * See comments in Sync.c for the layout of the lock word.
+ * Of particular interest to this code is the test for the
+ * simple case - which we handle inline.  For monitor enter, the
+ * simple case is thin lock, held by no-one.  For monitor exit,
+ * the simple case is thin lock, held by the unlocking thread with
+ * a recurse count of 0.
+ *
+ * A minor complication is that there is a field in the lock word
+ * unrelated to locking: the hash state.  This field must be ignored, but
+ * preserved.
+ *
+ */
+static void genMonitorEnter(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    ArmLIR *target;
+    ArmLIR *hopTarget;
+    ArmLIR *branch;
+    ArmLIR *hopBranch;
+
+    assert(LW_SHAPE_THIN == 0);
+    loadValueDirectFixed(cUnit, rlSrc, r1);  // Get obj
+    dvmCompilerLockAllTemps(cUnit);  // Prepare for explicit register usage
+    dvmCompilerFreeTemp(cUnit, r4PC);  // Free up r4 for general use
+    genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+    loadWordDisp(cUnit, r6SELF, offsetof(Thread, threadId), r3); // Get threadId
+    newLIR3(cUnit, kThumb2Ldrex, r2, r1,
+            offsetof(Object, lock) >> 2); // Get object->lock
+    opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner
+    // Is lock unheld on lock or held by us (==threadId) on unlock?
+    newLIR4(cUnit, kThumb2Bfi, r3, r2, 0, LW_LOCK_OWNER_SHIFT - 1);
+    newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT,
+            LW_LOCK_OWNER_SHIFT - 1);
+    hopBranch = newLIR2(cUnit, kThumb2Cbnz, r2, 0);
+    newLIR4(cUnit, kThumb2Strex, r2, r3, r1, offsetof(Object, lock) >> 2);
+    dvmCompilerGenMemBarrier(cUnit, kSY);
+    branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
+
+    hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+    hopTarget->defMask = ENCODE_ALL;
+    hopBranch->generic.target = (LIR *)hopTarget;
+
+    // Export PC (part 1)
+    loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset));
+
+    /* Get dPC of next insn */
+    loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
+                 dexGetWidthFromOpcode(OP_MONITOR_ENTER)));
+    // Export PC (part 2)
+    newLIR3(cUnit, kThumb2StrRRI8Predec, r3, r5FP,
+            sizeof(StackSaveArea) -
+            offsetof(StackSaveArea, xtra.currentPc));
+    /* Call template, and don't return */
+    genRegCopy(cUnit, r0, r6SELF);
+    genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
+    // Resume here
+    target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branch->generic.target = (LIR *)target;
+}
+
+/*
+ * For monitor unlock, we don't have to use ldrex/strex.  Once
+ * we've determined that the lock is thin and that we own it with
+ * a zero recursion count, it's safe to punch it back to the
+ * initial, unlock thin state with a store word.
+ */
+static void genMonitorExit(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    ArmLIR *target;
+    ArmLIR *branch;
+    ArmLIR *hopTarget;
+    ArmLIR *hopBranch;
+
+    assert(LW_SHAPE_THIN == 0);
+    loadValueDirectFixed(cUnit, rlSrc, r1);  // Get obj
+    dvmCompilerLockAllTemps(cUnit);  // Prepare for explicit register usage
+    dvmCompilerFreeTemp(cUnit, r4PC);  // Free up r4 for general use
+    genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+    loadWordDisp(cUnit, r1, offsetof(Object, lock), r2); // Get object->lock
+    loadWordDisp(cUnit, r6SELF, offsetof(Thread, threadId), r3); // Get threadId
+    // Is lock unheld on lock or held by us (==threadId) on unlock?
+    opRegRegImm(cUnit, kOpAnd, r7, r2,
+                (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
+    opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner
+    newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT,
+            LW_LOCK_OWNER_SHIFT - 1);
+    opRegReg(cUnit, kOpSub, r2, r3);
+    hopBranch = opCondBranch(cUnit, kArmCondNe);
+    dvmCompilerGenMemBarrier(cUnit, kSY);
+    storeWordDisp(cUnit, r1, offsetof(Object, lock), r7);
+    branch = opNone(cUnit, kOpUncondBr);
+
+    hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+    hopTarget->defMask = ENCODE_ALL;
+    hopBranch->generic.target = (LIR *)hopTarget;
+
+    // Export PC (part 1)
+    loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset));
+
+    LOAD_FUNC_ADDR(cUnit, r7, (int)dvmUnlockObject);
+    genRegCopy(cUnit, r0, r6SELF);
+    // Export PC (part 2)
+    newLIR3(cUnit, kThumb2StrRRI8Predec, r3, r5FP,
+            sizeof(StackSaveArea) -
+            offsetof(StackSaveArea, xtra.currentPc));
+    opReg(cUnit, kOpBlx, r7);
+    /* Did we throw? */
+    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+    loadConstant(cUnit, r0,
+                 (int) (cUnit->method->insns + mir->offset +
+                 dexGetWidthFromOpcode(OP_MONITOR_EXIT)));
+    genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+
+    // Resume here
+    target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branch->generic.target = (LIR *)target;
+    branchOver->generic.target = (LIR *) target;
+}
+
+static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+    if (mir->dalvikInsn.opcode == OP_MONITOR_ENTER)
+        genMonitorEnter(cUnit, mir);
+    else
+        genMonitorExit(cUnit, mir);
+}
+
+/*
+ * 64-bit 3way compare function.
+ *     mov   r7, #-1
+ *     cmp   op1hi, op2hi
+ *     blt   done
+ *     bgt   flip
+ *     sub   r7, op1lo, op2lo (treat as unsigned)
+ *     beq   done
+ *     ite   hi
+ *     mov(hi)   r7, #-1
+ *     mov(!hi)  r7, #1
+ * flip:
+ *     neg   r7
+ * done:
+ */
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
+                       RegLocation rlDest, RegLocation rlSrc1,
+                       RegLocation rlSrc2)
+{
+    RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
+    ArmLIR *target1;
+    ArmLIR *target2;
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+    rlTemp.lowReg = dvmCompilerAllocTemp(cUnit);
+    loadConstant(cUnit, rlTemp.lowReg, -1);
+    opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
+    ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt);
+    ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt);
+    opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq);
+
+    genIT(cUnit, kArmCondHi, "E");
+    newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1));
+    loadConstant(cUnit, rlTemp.lowReg, 1);
+    genBarrier(cUnit);
+
+    target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target2->defMask = -1;
+    opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg);
+
+    target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target1->defMask = -1;
+
+    storeValue(cUnit, rlDest, rlTemp);
+
+    branch1->generic.target = (LIR *)target1;
+    branch2->generic.target = (LIR *)target2;
+    branch3->generic.target = branch1->generic.target;
+}
+
+static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, true);
+    rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vabss, rlResult.lowReg, rlSrc.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
+{
+    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
+    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vabsd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc.lowReg, rlSrc.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+{
+    RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
+    RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+    genIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
+    opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
+    opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
+    genBarrier(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+}
+
+static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
+        RegLocation rlSrc, RegLocation rlResult, int lit,
+        int firstBit, int secondBit)
+{
+    opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
+                     encodeShift(kArmLsl, secondBit - firstBit));
+    if (firstBit != 0) {
+        opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
+    }
+}
diff --git a/vm/compiler/codegen/arm/Thumb2/Ralloc.cpp b/vm/compiler/codegen/arm/Thumb2/Ralloc.cpp
new file mode 100644
index 0000000..6adfd62
--- /dev/null
+++ b/vm/compiler/codegen/arm/Thumb2/Ralloc.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains codegen for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/* Stress mode for testing: if defined will reverse corereg/floatreg hint */
+//#define REGCLASS_STRESS_MODE
+
+/*
+ * Alloc a pair of core registers, or a double.  Low reg in low byte,
+ * high reg in next byte.
+ */
+int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit,
+                                         bool fpHint, int regClass)
+{
+    int highReg;
+    int lowReg;
+    int res = 0;
+
+#if defined(REGCLASS_STRESS_MODE)
+    fpHint = !fpHint;
+#endif
+
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+        lowReg = dvmCompilerAllocTempDouble(cUnit);
+        highReg = lowReg + 1;
+    } else {
+        lowReg = dvmCompilerAllocTemp(cUnit);
+        highReg = dvmCompilerAllocTemp(cUnit);
+    }
+    res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+    return res;
+}
+
+int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint,
+                                     int regClass)
+{
+#if defined(REGCLASS_STRESS_MODE)
+    fpHint = !fpHint;
+#endif
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+        return dvmCompilerAllocTempFloat(cUnit);
+    return dvmCompilerAllocTemp(cUnit);
+}
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.cpp b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.cpp
new file mode 100644
index 0000000..5188417
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+extern "C" void dvmCompilerTemplateStart(void);
+
+/*
+ * This file is included by Codegen-armv5te-vfp.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+    return DALVIK_JIT_THUMB;
+}
+
+/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+    int i = 0;
+
+    /*
+     * 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-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+    /* Target-specific configuration */
+    gDvmJit.jitTableSize = 1 << 9; // 512
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.threshold = 200;
+    gDvmJit.codeCacheSize = 512*1024;
+
+#if defined(WITH_SELF_VERIFICATION)
+    /* Force into blocking mode */
+    gDvmJit.blockingMode = true;
+    gDvm.nativeDebuggerActive = true;
+#endif
+
+    /* Codegen-specific assumptions */
+    assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
+           (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
+           (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(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". Make sure that the last
+     * offset from the struct is less than 128.
+     */
+    if ((offsetof(Thread, jitToInterpEntries) +
+         sizeof(struct JitToInterpEntries)) >= 128) {
+        LOGE("Thread.jitToInterpEntries size overflow");
+        dvmAbort();
+    }
+
+    /* No method JIT for Thumb backend */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
+    // Make sure all threads have current values
+    dvmJitUpdateThreadStateAll();
+
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 2;
+            break;
+        default:
+            LOGE("Unknown target optimization hint key: %d",key);
+            res = 0;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+#if ANDROID_SMP != 0
+#error armv5+smp not supported
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.h b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.h
new file mode 100644
index 0000000..727c521
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.h
@@ -0,0 +1,34 @@
+/*
+ * 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_CODEGEN_ARM_ARMV5TE_VFP_ARCHVARIANT_H_
+#define DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV5TE_VFP_ARCHVARIANT_H_
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+enum TemplateOpcode {
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+/*
+ * For example,
+ *     TEMPLATE_CMP_LONG,
+ *     TEMPLATE_RETURN,
+ *     ...
+ */
+    TEMPLATE_LAST_MARK,
+};
+#undef JIT_TEMPLATE
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV5TE_VFP_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/CallingConvention.S b/vm/compiler/codegen/arm/armv5te-vfp/CallingConvention.S
new file mode 100644
index 0000000..4f12395
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te-vfp/CallingConvention.S
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    vstmia r0, {d8-d15}
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    vldmia r0, {d8-d15}
+    bx     lr
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.cpp b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.cpp
new file mode 100644
index 0000000..55321bb
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+#define _CODEGEN_C
+#define _ARMV5TE_VFP
+#define TGT_LIR ArmLIR
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Arm codegen building blocks */
+#include "../CodegenCommon.cpp"
+
+/* Thumb-specific factory utilities */
+#include "../Thumb/Factory.cpp"
+/* Target independent factory utilities */
+#include "../../CodegenFactory.cpp"
+/* Arm-specific factory utilities */
+#include "../ArchFactory.cpp"
+
+/* Thumb-specific codegen routines */
+#include "../Thumb/Gen.cpp"
+/* Thumb+VFP codegen routines */
+#include "../FP/ThumbVFP.cpp"
+
+/* Thumb-specific register allocation */
+#include "../Thumb/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Dummy driver for method-based JIT */
+#include "../armv5te/MethodCodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
diff --git a/vm/compiler/codegen/arm/armv5te/ArchVariant.cpp b/vm/compiler/codegen/arm/armv5te/ArchVariant.cpp
new file mode 100644
index 0000000..f394aa1
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/ArchVariant.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+extern "C" void dvmCompilerTemplateStart(void);
+
+/*
+ * This file is included by Codegen-armv5te.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+    return DALVIK_JIT_THUMB;
+}
+
+/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/armv5te/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+    int i = 0;
+
+    /*
+     * 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
+
+    /* Target-specific configuration */
+    gDvmJit.jitTableSize = 1 << 9; // 512
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.threshold = 200;
+    gDvmJit.codeCacheSize = 512*1024;
+
+#if defined(WITH_SELF_VERIFICATION)
+    /* Force into blocking mode */
+    gDvmJit.blockingMode = true;
+    gDvm.nativeDebuggerActive = true;
+#endif
+
+    /* Codegen-specific assumptions */
+    assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
+           (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
+           (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(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". Make sure that the last
+     * offset from the struct is less than 128.
+     */
+    if ((offsetof(Thread, jitToInterpEntries) +
+         sizeof(struct JitToInterpEntries)) >= 128) {
+        LOGE("Thread.jitToInterpEntries size overflow");
+        dvmAbort();
+    }
+
+    /* No method JIT for Thumb backend */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
+    // Make sure all threads have current values
+    dvmJitUpdateThreadStateAll();
+
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 2;
+            break;
+        default:
+            LOGE("Unknown target optimization hint key: %d",key);
+            res = 0;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+#if ANDROID_SMP != 0
+#error armv5+smp not supported
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv5te/ArchVariant.h b/vm/compiler/codegen/arm/armv5te/ArchVariant.h
new file mode 100644
index 0000000..39a9548
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/ArchVariant.h
@@ -0,0 +1,34 @@
+/*
+ * 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_CODEGEN_ARM_ARMV5TE_ARCHVARIANT_H_
+#define DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV5TE_ARCHVARIANT_H_
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+enum TemplateOpcode {
+#include "../../../template/armv5te/TemplateOpList.h"
+/*
+ * For example,
+ *     TEMPLATE_CMP_LONG,
+ *     TEMPLATE_RETURN,
+ *     ...
+ */
+    TEMPLATE_LAST_MARK,
+};
+#undef JIT_TEMPLATE
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV5TE_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/arm/armv5te/CallingConvention.S b/vm/compiler/codegen/arm/armv5te/CallingConvention.S
new file mode 100644
index 0000000..0cbc64f
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/CallingConvention.S
@@ -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.
+ */
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    bx     lr
diff --git a/vm/compiler/codegen/arm/armv5te/Codegen.cpp b/vm/compiler/codegen/arm/armv5te/Codegen.cpp
new file mode 100644
index 0000000..a379c2a
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/Codegen.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+#define _CODEGEN_C
+#define _ARMV5TE
+#define TGT_LIR ArmLIR
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Arm codegen building blocks */
+#include "../CodegenCommon.cpp"
+
+/* Thumb-specific building blocks */
+#include "../Thumb/Factory.cpp"
+/* Target independent factory utilities */
+#include "../../CodegenFactory.cpp"
+/* Arm-specific factory utilities */
+#include "../ArchFactory.cpp"
+
+/* Thumb-specific codegen routines */
+#include "../Thumb/Gen.cpp"
+/* Thumb+Portable FP codegen routines */
+#include "../FP/ThumbPortableFP.cpp"
+
+/* Thumb-specific register allocation */
+#include "../Thumb/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Dummy driver for method-based JIT */
+#include "MethodCodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
diff --git a/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.cpp b/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.cpp
new file mode 100644
index 0000000..20779f3
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv5te/MethodCodegenDriver.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+    LOGE("Method-based JIT not supported for the v5te target");
+    dvmAbort();
+}
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.cpp b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.cpp
new file mode 100644
index 0000000..c3fe518
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.cpp
@@ -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.
+ */
+
+extern "C" void dvmCompilerTemplateStart(void);
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+    return DALVIK_JIT_THUMB2;
+}
+
+/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+    int i = 0;
+
+    /*
+     * 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-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+    /* Target-specific configuration */
+    gDvmJit.jitTableSize = 1 << 12; // 4096
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.threshold = 40;
+    gDvmJit.codeCacheSize = 1024*1024;
+
+#if defined(WITH_SELF_VERIFICATION)
+    /* Force into blocking */
+    gDvmJit.blockingMode = true;
+    gDvm.nativeDebuggerActive = true;
+#endif
+
+    /* Codegen-specific assumptions */
+    assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
+           (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
+           (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(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". Make sure that the last
+     * offset from the struct is less than 128.
+     */
+    if ((offsetof(Thread, jitToInterpEntries) +
+         sizeof(struct JitToInterpEntries)) >= 128) {
+        LOGE("Thread.jitToInterpEntries size overflow");
+        dvmAbort();
+    }
+
+    /* FIXME - comment out the following to enable method-based JIT */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
+    // Make sure all threads have current values
+    dvmJitUpdateThreadStateAll();
+
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 7;
+            break;
+        default:
+            LOGE("Unknown target optimization hint key: %d",key);
+            res = 0;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+#if ANDROID_SMP != 0
+    ArmLIR *dmb = newLIR1(cUnit, kThumb2Dmb, barrierKind);
+    dmb->defMask = ENCODE_ALL;
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.h b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.h
new file mode 100644
index 0000000..33e262c
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.h
@@ -0,0 +1,34 @@
+/*
+ * 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_CODEGEN_ARM_ARMV5TE_VFP_ARCHVARIANT_H_
+#define DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV5TE_VFP_ARCHVARIANT_H_
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+typedef enum {
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+/*
+ * For example,
+ *     TEMPLATE_CMP_LONG,
+ *     TEMPLATE_RETURN,
+ *     ...
+ */
+    TEMPLATE_LAST_MARK,
+} TemplateOpcode;
+#undef JIT_TEMPLATE
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV5TE_VFP_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/CallingConvention.S b/vm/compiler/codegen/arm/armv7-a-neon/CallingConvention.S
new file mode 100644
index 0000000..4f12395
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/CallingConvention.S
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    vstmia r0, {d8-d15}
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    vldmia r0, {d8-d15}
+    bx     lr
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.cpp b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.cpp
new file mode 100644
index 0000000..8f15174
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+#define _CODEGEN_C
+#define _ARMV7_A_NEON
+#define TGT_LIR ArmLIR
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Arm codegen building blocks */
+#include "../CodegenCommon.cpp"
+
+/* Thumb2-specific factory utilities */
+#include "../Thumb2/Factory.cpp"
+/* Target indepedent factory utilities */
+#include "../../CodegenFactory.cpp"
+/* Arm-specific factory utilities */
+#include "../ArchFactory.cpp"
+
+/* Thumb2-specific codegen routines */
+#include "../Thumb2/Gen.cpp"
+/* Thumb2+VFP codegen routines */
+#include "../FP/Thumb2VFP.cpp"
+
+/* Thumb2-specific register allocation */
+#include "../Thumb2/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Driver for method-based JIT */
+#include "MethodCodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp
new file mode 100644
index 0000000..4ddad69
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2011 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 the interpreter frame then punt to the interpreter to execute
+ * instruction at specified PC.
+ *
+ * Currently parameters are passed to the current frame, so we just need to
+ * grow the stack save area above it, fill certain fields in StackSaveArea and
+ * Thread that are skipped during whole-method invocation (specified below),
+ * then return to the interpreter.
+ *
+ * StackSaveArea:
+ *  - prevSave
+ *  - prevFrame
+ *  - savedPc
+ *  - returnAddr
+ *  - method
+ *
+ * Thread:
+ *  - method
+ *  - methodClassDex
+ *  - curFrame
+ */
+static void genMethodInflateAndPunt(CompilationUnit *cUnit, MIR *mir,
+                                    BasicBlock *bb)
+{
+    int oldStackSave = r0;
+    int newStackSave = r1;
+    int oldFP = r2;
+    int savedPC = r3;
+    int currentPC = r4PC;
+    int returnAddr = r7;
+    int method = r8;
+    int pDvmDex = r9;
+
+    /*
+     * TODO: check whether to raise the stack overflow exception when growing
+     * the stack save area.
+     */
+
+    /* Send everything to home location */
+    dvmCompilerFlushAllRegs(cUnit);
+
+    /* oldStackSave = r5FP + sizeof(current frame) */
+    opRegRegImm(cUnit, kOpAdd, oldStackSave, r5FP,
+                cUnit->method->registersSize * 4);
+    /* oldFP = oldStackSave + sizeof(stackSaveArea) */
+    opRegRegImm(cUnit, kOpAdd, oldFP, oldStackSave, sizeof(StackSaveArea));
+    /* newStackSave = r5FP - sizeof(StackSaveArea) */
+    opRegRegImm(cUnit, kOpSub, newStackSave, r5FP, sizeof(StackSaveArea));
+
+    loadWordDisp(cUnit, r13sp, 0, savedPC);
+    loadConstant(cUnit, currentPC, (int) (cUnit->method->insns + mir->offset));
+    loadConstant(cUnit, method, (int) cUnit->method);
+    loadConstant(cUnit, pDvmDex, (int) cUnit->method->clazz->pDvmDex);
+#ifdef EASY_GDB
+    /* newStackSave->prevSave = oldStackSave */
+    storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevSave),
+                  oldStackSave);
+#endif
+    /* newStackSave->prevSave = oldStackSave */
+    storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevFrame),
+                  oldFP);
+    /* newStackSave->savedPc = savedPC */
+    storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, savedPc),
+                  savedPC);
+    /* return address */
+    loadConstant(cUnit, returnAddr, 0);
+    storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, returnAddr),
+                  returnAddr);
+    /* newStackSave->method = method */
+    storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, method), method);
+    /* thread->method = method */
+    storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, method), method);
+    /* thread->interpSave.curFrame = current FP */
+    storeWordDisp(cUnit, r6SELF, offsetof(Thread, interpSave.curFrame), r5FP);
+    /* thread->methodClassDex = pDvmDex */
+    storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, methodClassDex),
+                  pDvmDex);
+    /* Restore the stack pointer */
+    opRegImm(cUnit, kOpAdd, r13sp, 16);
+    genPuntToInterp(cUnit, mir->offset);
+}
+
+/*
+ * 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.
+ *
+ * TODO - most them are just pass-through to the trace-based versions for now
+ */
+static bool handleMethodFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
+                                             BasicBlock *bb, ArmLIR *labelList)
+{
+    /* backward branch? */
+    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
+
+    if (backwardBranch && gDvmJit.genSuspendPoll) {
+        genSuspendPoll(cUnit, mir);
+    }
+
+    /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
+    genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+    return false;
+}
+
+static bool handleMethodFmt10x(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    switch (dalvikOpcode) {
+        case OP_RETURN_VOID:
+            return false;
+        default:
+            return handleFmt10x(cUnit, mir);
+    }
+}
+
+static bool handleMethodFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt11n_Fmt31i(cUnit, mir);
+}
+
+static bool handleMethodFmt11x(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                               ArmLIR *labelList)
+{
+    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+    switch (dalvikOpcode) {
+        case OP_THROW:
+            genMethodInflateAndPunt(cUnit, mir, bb);
+            return false;
+        default:
+            return handleFmt11x(cUnit, mir);
+    }
+}
+
+static bool handleMethodFmt12x(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt12x(cUnit, mir);
+}
+
+static bool handleMethodFmt20bc_Fmt40sc(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt20bc_Fmt40sc(cUnit, mir);
+}
+
+static bool handleMethodFmt21c_Fmt31c_Fmt41c(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt21c_Fmt31c_Fmt41c(cUnit, mir);
+}
+
+static bool handleMethodFmt21h(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt21h(cUnit, mir);
+}
+
+static bool handleMethodFmt21s(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt21s(cUnit, mir);
+}
+
+static bool handleMethodFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                               ArmLIR *labelList)
+{
+    return handleFmt21t(cUnit, mir, bb, labelList);
+}
+
+static bool handleMethodFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt22b_Fmt22s(cUnit, mir);
+}
+
+static bool handleMethodFmt22c_Fmt52c(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt22c_Fmt52c(cUnit, mir);
+}
+
+static bool handleMethodFmt22cs(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt22cs(cUnit, mir);
+}
+
+static bool handleMethodFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                               ArmLIR *labelList)
+{
+    return handleFmt22t(cUnit, mir, bb, labelList);
+}
+
+static bool handleMethodFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt22x_Fmt32x(cUnit, mir);
+}
+
+static bool handleMethodFmt23x(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt23x(cUnit, mir);
+}
+
+static bool handleMethodFmt31t(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt31t(cUnit, mir);
+}
+
+static bool handleMethodFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir,
+                                       BasicBlock *bb, ArmLIR *labelList)
+{
+    return handleFmt35c_3rc_5rc(cUnit, mir, bb, labelList);
+}
+
+static bool handleMethodFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
+                                     BasicBlock *bb, ArmLIR *labelList)
+{
+    return handleFmt35ms_3rms(cUnit, mir, bb, labelList);
+}
+
+static bool handleMethodExecuteInline(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleExecuteInline(cUnit, mir);
+}
+
+static bool handleMethodFmt51l(CompilationUnit *cUnit, MIR *mir)
+{
+    return handleFmt51l(cUnit, mir);
+}
+
+/* Handle the content in each basic block */
+static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+    ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList;
+    int blockId = bb->id;
+
+    cUnit->curBlock = bb;
+    labelList[blockId].operands[0] = bb->startOffset;
+
+    /* Insert the block label */
+    labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
+    dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+    dvmCompilerClobberAllRegs(cUnit);
+    dvmCompilerResetNullCheck(cUnit);
+
+    ArmLIR *headLIR = NULL;
+
+    if (bb->blockType == kEntryBlock) {
+        /* r0 = callsitePC */
+        opImm(cUnit, kOpPush, (1 << r0 | 1 << r1 | 1 << r5FP | 1 << r14lr));
+        opRegImm(cUnit, kOpSub, r5FP,
+                 sizeof(StackSaveArea) + cUnit->method->registersSize * 4);
+
+    } else if (bb->blockType == kExitBlock) {
+        /* No need to pop r0 and r1 */
+        opRegImm(cUnit, kOpAdd, r13sp, 8);
+        opImm(cUnit, kOpPop, (1 << r5FP | 1 << r15pc));
+    }
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+        dvmCompilerResetRegPool(cUnit);
+        if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
+            dvmCompilerClobberAllRegs(cUnit);
+        }
+
+        if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
+            dvmCompilerResetDefTracking(cUnit);
+        }
+
+        Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+        InstructionFormat dalvikFormat =
+            dexGetFormatFromOpcode(dalvikOpcode);
+
+        ArmLIR *boundaryLIR;
+
+        /*
+         * Don't generate the boundary LIR unless we are debugging this
+         * trace or we need a scheduling barrier.
+         */
+        if (headLIR == NULL || cUnit->printMe == true) {
+            boundaryLIR =
+                newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
+                        mir->offset,
+                        (int) dvmCompilerGetDalvikDisassembly(
+                            &mir->dalvikInsn, ""));
+            /* Remember the first LIR for this block */
+            if (headLIR == NULL) {
+                headLIR = boundaryLIR;
+                /* Set the first boundaryLIR as a scheduling barrier */
+                headLIR->defMask = ENCODE_ALL;
+            }
+        }
+
+        /* Don't generate the SSA annotation unless verbose mode is on */
+        if (cUnit->printMe && mir->ssaRep) {
+            char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+        }
+
+        bool notHandled;
+        switch (dalvikFormat) {
+            case kFmt10t:
+            case kFmt20t:
+            case kFmt30t:
+                notHandled = handleMethodFmt10t_Fmt20t_Fmt30t(cUnit, mir, bb,
+                                                              labelList);
+                break;
+            case kFmt10x:
+                notHandled = handleMethodFmt10x(cUnit, mir);
+                break;
+            case kFmt11n:
+            case kFmt31i:
+                notHandled = handleMethodFmt11n_Fmt31i(cUnit, mir);
+                break;
+            case kFmt11x:
+                notHandled = handleMethodFmt11x(cUnit, mir, bb, labelList);
+                break;
+            case kFmt12x:
+                notHandled = handleMethodFmt12x(cUnit, mir);
+                break;
+            case kFmt20bc:
+            case kFmt40sc:
+                notHandled = handleMethodFmt20bc_Fmt40sc(cUnit, mir);
+                break;
+            case kFmt21c:
+            case kFmt31c:
+            case kFmt41c:
+                notHandled = handleMethodFmt21c_Fmt31c_Fmt41c(cUnit, mir);
+                break;
+            case kFmt21h:
+                notHandled = handleMethodFmt21h(cUnit, mir);
+                break;
+            case kFmt21s:
+                notHandled = handleMethodFmt21s(cUnit, mir);
+                break;
+            case kFmt21t:
+                notHandled = handleMethodFmt21t(cUnit, mir, bb, labelList);
+                break;
+            case kFmt22b:
+            case kFmt22s:
+                notHandled = handleMethodFmt22b_Fmt22s(cUnit, mir);
+                break;
+            case kFmt22c:
+            case kFmt52c:
+                notHandled = handleMethodFmt22c_Fmt52c(cUnit, mir);
+                break;
+            case kFmt22cs:
+                notHandled = handleMethodFmt22cs(cUnit, mir);
+                break;
+            case kFmt22t:
+                notHandled = handleMethodFmt22t(cUnit, mir, bb, labelList);
+                break;
+            case kFmt22x:
+            case kFmt32x:
+                notHandled = handleMethodFmt22x_Fmt32x(cUnit, mir);
+                break;
+            case kFmt23x:
+                notHandled = handleMethodFmt23x(cUnit, mir);
+                break;
+            case kFmt31t:
+                notHandled = handleMethodFmt31t(cUnit, mir);
+                break;
+            case kFmt3rc:
+            case kFmt35c:
+            case kFmt5rc:
+                notHandled = handleMethodFmt35c_3rc_5rc(cUnit, mir, bb,
+                                                        labelList);
+                break;
+            case kFmt3rms:
+            case kFmt35ms:
+                notHandled = handleMethodFmt35ms_3rms(cUnit, mir, bb,
+                                                      labelList);
+                break;
+            case kFmt35mi:
+            case kFmt3rmi:
+                notHandled = handleMethodExecuteInline(cUnit, mir);
+                break;
+            case kFmt51l:
+                notHandled = handleMethodFmt51l(cUnit, mir);
+                break;
+            default:
+                notHandled = true;
+                break;
+        }
+
+        /* FIXME - to be implemented */
+        if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) {
+            notHandled = false;
+        }
+
+        if (notHandled) {
+            LOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled",
+                 mir->offset,
+                 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+                 dalvikFormat);
+            dvmCompilerAbort(cUnit);
+            break;
+        }
+    }
+
+    if (headLIR) {
+        /*
+         * Eliminate redundant loads/stores and delay stores into later
+         * slots
+         */
+        dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+                                           cUnit->lastLIRInsn);
+
+        /*
+         * Generate an unconditional branch to the fallthrough block.
+         */
+        if (bb->fallThrough) {
+            genUnconditionalBranch(cUnit,
+                                   &labelList[bb->fallThrough->id]);
+        }
+    }
+    return false;
+}
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
+{
+    // FIXME - enable method compilation for selected routines here
+    if (strcmp(cUnit->method->name, "add")) return;
+
+    /* Used to hold the labels of each block */
+    cUnit->blockLabelList =
+        (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
+
+    dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
+                                          kPreOrderDFSTraversal,
+                                          false /* isIterative */);
+
+    dvmCompilerApplyGlobalOptimizations(cUnit);
+
+    // FIXME - temporarily enable verbose printing for all methods
+    cUnit->printMe = true;
+
+#if defined(WITH_SELF_VERIFICATION)
+    selfVerificationBranchInsertPass(cUnit);
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.cpp b/vm/compiler/codegen/arm/armv7-a/ArchVariant.cpp
new file mode 100644
index 0000000..c3fe518
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.cpp
@@ -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.
+ */
+
+extern "C" void dvmCompilerTemplateStart(void);
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+    return DALVIK_JIT_THUMB2;
+}
+
+/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+    int i = 0;
+
+    /*
+     * 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-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+    /* Target-specific configuration */
+    gDvmJit.jitTableSize = 1 << 12; // 4096
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.threshold = 40;
+    gDvmJit.codeCacheSize = 1024*1024;
+
+#if defined(WITH_SELF_VERIFICATION)
+    /* Force into blocking */
+    gDvmJit.blockingMode = true;
+    gDvm.nativeDebuggerActive = true;
+#endif
+
+    /* Codegen-specific assumptions */
+    assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
+           (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
+           (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(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". Make sure that the last
+     * offset from the struct is less than 128.
+     */
+    if ((offsetof(Thread, jitToInterpEntries) +
+         sizeof(struct JitToInterpEntries)) >= 128) {
+        LOGE("Thread.jitToInterpEntries size overflow");
+        dvmAbort();
+    }
+
+    /* FIXME - comment out the following to enable method-based JIT */
+    gDvmJit.disableOpt |= (1 << kMethodJit);
+
+    // Make sure all threads have current values
+    dvmJitUpdateThreadStateAll();
+
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 7;
+            break;
+        default:
+            LOGE("Unknown target optimization hint key: %d",key);
+            res = 0;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+#if ANDROID_SMP != 0
+    ArmLIR *dmb = newLIR1(cUnit, kThumb2Dmb, barrierKind);
+    dmb->defMask = ENCODE_ALL;
+#endif
+}
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.h b/vm/compiler/codegen/arm/armv7-a/ArchVariant.h
new file mode 100644
index 0000000..b4f4eb7
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.h
@@ -0,0 +1,34 @@
+/*
+ * 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_CODEGEN_ARM_ARMV7_A_ARCHVARIANT_H_
+#define DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV7_A_ARCHVARIANT_H_
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+enum TemplateOpcode {
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+/*
+ * For example,
+ *     TEMPLATE_CMP_LONG,
+ *     TEMPLATE_RETURN,
+ *     ...
+ */
+    TEMPLATE_LAST_MARK,
+};
+#undef JIT_TEMPLATE
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_ARM_ARMV7_A_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/arm/armv7-a/CallingConvention.S b/vm/compiler/codegen/arm/armv7-a/CallingConvention.S
new file mode 100644
index 0000000..4f12395
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a/CallingConvention.S
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    r0 : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    vstmia r0, {d8-d15}
+    bx     lr
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    vldmia r0, {d8-d15}
+    bx     lr
diff --git a/vm/compiler/codegen/arm/armv7-a/Codegen.cpp b/vm/compiler/codegen/arm/armv7-a/Codegen.cpp
new file mode 100644
index 0000000..e1b0ee9
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a/Codegen.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+#define _CODEGEN_C
+#define _ARMV7_A
+#define TGT_LIR ArmLIR
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Arm codegen building blocks */
+#include "../CodegenCommon.cpp"
+
+/* Thumb2-specific factory utilities */
+#include "../Thumb2/Factory.cpp"
+/* Target independent factory utilities */
+#include "../../CodegenFactory.cpp"
+/* Arm-specific factory utilities */
+#include "../ArchFactory.cpp"
+
+/* Thumb2-specific codegen routines */
+#include "../Thumb2/Gen.cpp"
+/* Thumb2+VFP codegen routines */
+#include "../FP/Thumb2VFP.cpp"
+
+/* Thumb2-specific register allocation */
+#include "../Thumb2/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Driver for method-based JIT */
+#include "../armv7-a-neon/MethodCodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
diff --git a/vm/compiler/codegen/x86/ArchUtility.cpp b/vm/compiler/codegen/x86/ArchUtility.cpp
new file mode 100644
index 0000000..f7c48d6
--- /dev/null
+++ b/vm/compiler/codegen/x86/ArchUtility.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../../CompilerInternals.h"
+#include "libdex/DexOpcodes.h"
+#include "X86LIR.h"
+
+/* Dump instructions and constant pool contents */
+void dvmCompilerCodegenDump(CompilationUnit *cUnit)
+{
+}
+
+/* Target-specific cache flushing (not needed for x86 */
+int dvmCompilerCacheFlush(long start, long end, long flags)
+{
+    return 0;
+}
diff --git a/vm/compiler/codegen/x86/Assemble.cpp b/vm/compiler/codegen/x86/Assemble.cpp
new file mode 100644
index 0000000..03edbf1
--- /dev/null
+++ b/vm/compiler/codegen/x86/Assemble.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "libdex/DexOpcodes.h"
+
+#include "../../CompilerInternals.h"
+#include "X86LIR.h"
+#include "Codegen.h"
+#include <sys/mman.h>           /* for protection change */
+
+#define MAX_ASSEMBLER_RETRIES 10
+
+
+/* Track the number of times that the code cache is patched */
+#if defined(WITH_JIT_TUNING)
+#define UPDATE_CODE_CACHE_PATCHES()    (gDvmJit.codeCachePatches++)
+#else
+#define UPDATE_CODE_CACHE_PATCHES()
+#endif
+
+/*
+ * 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             |  -> 16 bytes each, 8 byte aligned
+ *   |  .                            .
+ *   |  .                            .
+ *   |  |                            |
+ *   |  +----------------------------+
+ *   |  | Gap for large switch stmt  |  -> # cases >= MAX_CHAINED_SWITCH_CASES
+ *   |  +----------------------------+
+ *   +->| Chaining cell counts       |  -> 8 bytes, chain cell counts by type
+ *      +----------------------------+
+ *      | Trace description          |  -> variable sized
+ *      .                            .
+ *      |                            |
+ *      +----------------------------+
+ *      | Literal pool               |  -> 4-byte aligned, variable size
+ *      .                            .     Note: for x86 literals will
+ *      .                            .     generally appear inline.
+ *      |                            |
+ *      +----------------------------+
+ *
+ * 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, JitTranslationInfo *info)
+{
+}
+
+/*
+ * Perform translation chain operation.
+ */
+void* dvmJitChain(void* tgtAddr, u4* branchAddr)
+{
+    return 0;
+}
+
+/*
+ * This method is called from the invoke templates for virtual and interface
+ * methods to speculatively setup a chain to the callee. The templates are
+ * written in assembly and have setup method, cell, and clazz at r0, r2, and
+ * r3 respectively, so there is a unused argument in the list. Upon return one
+ * of the following three results may happen:
+ *   1) Chain is not setup because the callee is native. Reset the rechain
+ *      count to a big number so that it will take a long time before the next
+ *      rechain attempt to happen.
+ *   2) Chain is not setup because the callee has not been created yet. Reset
+ *      the rechain count to a small number and retry in the near future.
+ *   3) Enqueue the new content for the chaining cell which will be appled in
+ *      next safe point.
+ */
+const Method *dvmJitToPatchPredictedChain(const Method *method,
+                                          Thread *self,
+                                          PredictedChainingCell *cell,
+                                          const ClassObject *clazz)
+{
+    return 0;
+}
+
+/*
+ * Patch the inline cache content based on the content passed from the work
+ * order.
+ */
+void dvmCompilerPatchInlineCache(void)
+{
+}
+
+/*
+ * 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)
+{
+    return 0;
+}
+
+/* Unchain all translation in the cache. */
+void dvmJitUnchainAll()
+{
+}
+
+/* Create a copy of the trace descriptor of an existing compilation */
+JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
+                                            const JitEntry *knownEntry)
+{
+    return 0;
+}
+
+/* Sort the trace profile counts and dump them */
+void dvmCompilerSortAndPrintTraceProfiles()
+{
+}
+
+void dvmJitScanAllClassPointers(void (*callback)(void *))
+{
+}
diff --git a/vm/compiler/codegen/x86/CalloutHelper.h b/vm/compiler/codegen/x86/CalloutHelper.h
new file mode 100644
index 0000000..3490f04
--- /dev/null
+++ b/vm/compiler/codegen/x86/CalloutHelper.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_CALLOUT_HELPER_H_
+#define DALVIK_VM_COMPILER_CODEGEN_X86_CALLOUT_HELPER_H_
+
+#include "Dalvik.h"
+
+/*
+ * Declare/comment prototypes of all native callout functions invoked by the
+ * JIT'ed code here and use the LOAD_FUNC_ADDR macro to load the address into
+ * a register. In this way we have a centralized place to find out all native
+ * helper functions and we can grep for LOAD_FUNC_ADDR to find out all the
+ * callsites.
+ */
+
+/* Load a statically compiled function address as a constant */
+#define LOAD_FUNC_ADDR(cUnit, reg, addr) loadConstant(cUnit, reg, addr)
+
+/* Originally declared in Sync.h */
+bool dvmUnlockObject(struct Thread* self, struct Object* obj); //OP_MONITOR_EXIT
+
+/* Originally declared in oo/TypeCheck.h */
+bool dvmCanPutArrayElement(const ClassObject* elemClass,   // OP_APUT_OBJECT
+                           const ClassObject* arrayClass);
+int dvmInstanceofNonTrivial(const ClassObject* instance,   // OP_CHECK_CAST &&
+                            const ClassObject* clazz);     // OP_INSTANCE_OF
+
+/* Originally declared in oo/Array.h */
+ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass, // OP_NEW_ARRAY
+                                  size_t length, int allocFlags);
+
+/* Originally declared in interp/InterpDefs.h */
+bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
+                                  const u2* arrayData);
+
+/* Originally declared in alloc/Alloc.h */
+Object* dvmAllocObject(ClassObject* clazz, int flags);  // OP_NEW_INSTANCE
+
+/*
+ * Functions declared in gDvmInlineOpsTable[] are used for
+ * OP_EXECUTE_INLINE & OP_EXECUTE_INLINE_RANGE.
+ */
+extern "C" double sqrt(double x);  // INLINE_MATH_SQRT
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_X86_CALLOUT_HELPER_H_
diff --git a/vm/compiler/codegen/x86/Codegen.h b/vm/compiler/codegen/x86/Codegen.h
new file mode 100644
index 0000000..1ccdad3
--- /dev/null
+++ b/vm/compiler/codegen/x86/Codegen.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerIR.h"
+#include "CalloutHelper.h"
diff --git a/vm/compiler/codegen/x86/CodegenDriver.cpp b/vm/compiler/codegen/x86/CodegenDriver.cpp
new file mode 100644
index 0000000..a5ef56a
--- /dev/null
+++ b/vm/compiler/codegen/x86/CodegenDriver.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains codegen and support common to all supported
+ * X86 variants.  It is included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+extern X86LIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
+extern X86LIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
+                            int displacement, int rDest);
+extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit);
+extern void storeWordDisp(CompilationUnit *cUnit, int rBase,
+                          int displacement, int rSrc);
+extern X86LIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
+
+static int opcodeCoverage[kNumPackedOpcodes];
+static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
+
+#if 0   // Avoid compiler warnings when x86 disabled during development
+/*
+ * Bail to the interpreter.  Will not return to this trace.
+ * On entry, rPC must be set correctly.
+ */
+static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
+{
+    dvmCompilerFlushAllRegs(cUnit);
+    loadConstant(cUnit, rPC, (int)(cUnit->method->insns + offset));
+    loadWordDisp(cUnit, rEBP, 0, rECX);  // Get glue
+    loadWordDisp(cUnit, rECX,
+                 offsetof(Thread, jitToInterpEntries.dvmJitToInterpPunt),
+                 rEAX);
+    opReg(cUnit, kOpUncondBr, rEAX);
+}
+
+static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
+{
+    int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
+    int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
+                       kInstrCanThrow;
+
+    //If already optimized out, just ignore
+    if (mir->dalvikInsn.opcode == OP_NOP)
+        return;
+
+    //Ugly, but necessary.  Flush all Dalvik regs so Interp can find them
+    dvmCompilerFlushAllRegs(cUnit);
+
+    if ((mir->next == NULL) || (flags & flagsToCheck)) {
+       genPuntToInterp(cUnit, mir->offset);
+       return;
+    }
+    int entryAddr = offsetof(Thread,
+                             jitToInterpEntries.dvmJitToInterpSingleStep);
+    loadWordDisp(cUnit, rEBP, 0, rECX);  // Get glue
+    loadWordDisp(cUnit, rECX, entryAddr, rEAX); // rEAX<- entry address
+    /* rPC = dalvik pc */
+    loadConstant(cUnit, rPC, (int) (cUnit->method->insns + mir->offset));
+    /* rECX = dalvik pc of following instruction */
+    loadConstant(cUnit, rECX, (int) (cUnit->method->insns + mir->next->offset));
+    /* Pass on the stack */
+    storeWordDisp(cUnit, rESP, OUT_ARG0, rECX);
+    opReg(cUnit, kOpCall, rEAX);
+}
+#endif
+
+/*
+ * 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.
+ */
+
+#if 0
+static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
+                                       BasicBlock *bb, X86LIR *labelList)
+{
+    /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
+    return true;
+}
+
+static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                         X86LIR *labelList)
+{
+    return true;
+}
+
+static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                         X86LIR *labelList)
+{
+    return true;
+}
+
+static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+                             X86LIR *labelList)
+{
+    return true;
+}
+
+static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
+                               BasicBlock *bb, X86LIR *labelList)
+{
+    return true;
+}
+
+/*
+ * NOTE: Handles both range and non-range versions (arguments
+ * have already been normalized by this point).
+ */
+static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+
+static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
+{
+    return true;
+}
+#endif
+
+
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
+{
+}
+
+/* Accept the work and start compiling */
+bool dvmCompilerDoWork(CompilerWorkOrder *work)
+{
+    JitTraceDescription *desc;
+    bool res;
+
+    if (gDvmJit.codeCacheFull) {
+        return false;
+    }
+
+    switch (work->kind) {
+        case kWorkOrderTrace:
+            /* Start compilation with maximally allowed trace length */
+            desc = (JitTraceDescription *)work->info;
+            res = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+                                  work->bailPtr, 0 /* no hints */);
+            break;
+        case kWorkOrderTraceDebug: {
+            bool oldPrintMe = gDvmJit.printMe;
+            gDvmJit.printMe = true;
+            /* Start compilation with maximally allowed trace length */
+            desc = (JitTraceDescription *)work->info;
+            res = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
+                                  work->bailPtr, 0 /* no hints */);
+            gDvmJit.printMe = oldPrintMe;
+            break;
+        }
+        default:
+            res = false;
+            LOGE("Jit: unknown work order type");
+            assert(0);  // Bail if debug build, discard otherwise
+    }
+    return res;
+}
+
+/* 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 < kNumPackedOpcodes) {
+        i++;
+    }
+    if (i == kNumPackedOpcodes) {
+        return;
+    }
+    for (start = i++, streak = 1; i < kNumPackedOpcodes; 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 < kNumPackedOpcodes) {
+                i++;
+            }
+            if (i < kNumPackedOpcodes) {
+                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);
+    }
+}
+
+/* Common initialization routine for an architecture family */
+bool dvmCompilerArchInit()
+{
+    return dvmCompilerArchVariantInit();
+}
+
+void *dvmCompilerGetInterpretTemplate()
+{
+      return (void*) ((int)gDvmJit.codeCache +
+                      templateEntryOffsets[TEMPLATE_INTERPRET]);
+}
+
+JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
+{
+    return DALVIK_JIT_X86;
+}
+
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
+{
+}
diff --git a/vm/compiler/codegen/x86/X86LIR.h b/vm/compiler/codegen/x86/X86LIR.h
new file mode 100644
index 0000000..863aeab
--- /dev/null
+++ b/vm/compiler/codegen/x86/X86LIR.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
+#define DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
+
+#include "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+
+/*
+ * For both JIT & interpreter:
+ *     esi is Dalvik FP
+ *     ebp is native FP
+ *     esp is native SP
+ *
+ * For interpreter:
+ *     edi is Dalvik PC (rPC)
+ *     ebx is rINST
+ *
+ * For JIT:
+ *     eax, edx, ecx are scratch & caller-save
+ *     ebx, edi are scratch & callee-save
+ *
+ * Calling conventions:
+ *     32-bit return in eax
+ *     64-bit return in edx:eax
+ *     fp on top of fp stack st(0)
+ *     Parameters passed on stack, pushed left to right
+ *     On entry to target, first parm is at 4(%esp).
+ *     For performance, we'll maintain 16-byte stack alignment
+ *
+ * When transitioning from code cache to interp:
+ *       materialize Dalvik PC of target in rPC/%edx
+ *       Preload rINST/%ebx such that high 24 bits are zero and
+ *           bl contains the non-opcode 8-bits of the 16-bit Dalvik
+ *           instruction at (rPC)
+ */
+
+/* Keys for target-specific scheduling and other optimizations here */
+typedef enum X86TargetOptHints {
+   kMaxHoistDistance,
+} X86TargetOptHints;
+
+ /*
+ * 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 RegisterInfo {
+    int reg;                    // Reg number
+    bool inUse;                 // Has it been allocated?
+    bool pair;                  // Part of a register pair?
+    int partner;                // If pair, other reg of pair
+    bool live;                  // Is there an associated SSA name?
+    bool dirty;                 // If live, is it dirty?
+    int sReg;                   // Name of live value
+    struct LIR *defStart;       // Starting inst in last def sequence
+    struct LIR *defEnd;         // Ending inst in last def sequence
+} RegisterInfo;
+
+typedef struct RegisterPool {
+    BitVector *nullCheckedRegs; // Track which registers have been null-checked
+    int numCoreTemps;
+    RegisterInfo *coreTemps;
+    int nextCoreTemp;
+    int numFPTemps;
+    RegisterInfo *FPTemps;
+    int nextFPTemp;
+} RegisterPool;
+
+typedef enum OpSize {
+    kWord,
+    kLong,
+    kSingle,
+    kDouble,
+    kUnsignedHalf,
+    kSignedHalf,
+    kUnsignedByte,
+    kSignedByte,
+} OpSize;
+
+typedef enum OpKind {
+    kOpMov,
+    kOpCmp,
+    kOpLsl,
+    kOpLsr,
+    kOpAsr,
+    kOpRor,
+    kOpNot,
+    kOpAnd,
+    kOpOr,
+    kOpXor,
+    kOpNeg,
+    kOpAdd,
+    kOpAdc,
+    kOpSub,
+    kOpSbc,
+    kOpMul,
+    kOpDiv,
+    kOpRem,
+    kOpTst,
+    kOpCall,
+    kOpPush,
+    kOpPop,
+    kOp2Char,
+    kOp2Short,
+    kOp2Byte,
+    kOpCondBr,
+    kOpUncondBr,
+} OpKind;
+
+#define FP_REG_OFFSET 8
+
+typedef enum NativeRegisterPool {
+    rEAX = 0,
+    rECX = 1,
+    rEDX = 2,
+    rEBX = 3,
+    rESP = 4,
+    rEBP = 5,
+    rESI = 6,
+    rEDI = 7,
+    rXMM0 = 0 + FP_REG_OFFSET,
+    rXMM1 = 1 + FP_REG_OFFSET,
+    rXMM2 = 2 + FP_REG_OFFSET,
+    rXMM3 = 3 + FP_REG_OFFSET,
+    rXMM4 = 4 + FP_REG_OFFSET,
+    rXMM5 = 5 + FP_REG_OFFSET,
+    rXMM6 = 6 + FP_REG_OFFSET,
+    rXMM7 = 7 + FP_REG_OFFSET,
+} NativeRegisterPool;
+
+#define rPC rEDI
+#define rFP rESI
+#define rINST rEBX
+
+#define OUT_ARG0 0
+#define OUT_ARG1 4
+#define OUT_ARG2 8
+#define OUT_ARG3 12
+#define OUT_ARG4 16
+
+typedef struct X86LIR {
+    LIR generic;
+    //X86Opcode opcode;
+    int operands[4];    // [0..3] = [dest, src1, src2, extra]
+    bool isNop;         // LIR is optimized away
+    bool branchInsertSV;// mark for insertion of branch before this instruction,
+                        // used to identify mem ops for self verification mode
+    int age;            // default is 0, set lazily by the optimizer
+    int aliasInfo;      // For Dalvik register access & litpool disambiguation
+    u8 useMask;         // Resource mask for use
+    u8 defMask;         // Resource mask for def
+} X86LIR;
+
+/* Utility macros to traverse the LIR/X86LIR list */
+#define NEXT_LIR(lir) ((X86LIR *) lir->generic.next)
+#define PREV_LIR(lir) ((X86LIR *) 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
+
+#define CHAIN_CELL_NORMAL_SIZE 12
+#define CHAIN_CELL_PREDICTED_SIZE 16
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_X86_X86LIR_H_
diff --git a/vm/compiler/codegen/x86/ia32/ArchVariant.cpp b/vm/compiler/codegen/x86/ia32/ArchVariant.cpp
new file mode 100644
index 0000000..9f17522
--- /dev/null
+++ b/vm/compiler/codegen/x86/ia32/ArchVariant.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" void dvmCompilerTemplateStart(void);
+
+/*
+ * This file is included by Codegen-x86.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType dvmCompilerInstructionSet(void)
+{
+    return DALVIK_JIT_IA32;
+}
+
+/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern "C" void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/ia32/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+    int i = 0;
+
+    /*
+     * 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/ia32/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+    /* Target-specific configuration */
+    gDvmJit.jitTableSize = 1 << 9; // 512
+    gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+    gDvmJit.threshold = 200;
+    gDvmJit.codeCacheSize = 512*1024;
+
+#if defined(WITH_SELF_VERIFICATION)
+    /* Force into blocking mode */
+    gDvmJit.blockingMode = true;
+    gDvm.nativeDebuggerActive = true;
+#endif
+
+    /* Codegen-specific assumptions */
+    assert(OFFSETOF_MEMBER(ClassObject, vtable) < 128 &&
+           (OFFSETOF_MEMBER(ClassObject, vtable) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(ArrayObject, length) < 128 &&
+           (OFFSETOF_MEMBER(ArrayObject, length) & 0x3) == 0);
+    assert(OFFSETOF_MEMBER(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", make sure that the last
+     * offset from the struct is less than 128.
+     */
+    assert((offsetof(Thread, jitToInterpEntries) +
+            sizeof(struct JitToInterpEntries)) <= 128);
+
+    // Make sure all threads have current values
+    dvmJitUpdateThreadStateAll();
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 2;
+            break;
+        default:
+            LOGE("Unknown target optimization hint key: %d",key);
+            res = 0;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+}
diff --git a/vm/compiler/codegen/x86/ia32/ArchVariant.h b/vm/compiler/codegen/x86/ia32/ArchVariant.h
new file mode 100644
index 0000000..f1c21d3
--- /dev/null
+++ b/vm/compiler/codegen/x86/ia32/ArchVariant.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DALVIK_VM_COMPILER_CODEGEN_X86_IA32_ARCHVARIANT_H_
+#define DALVIK_VM_COMPILER_CODEGEN_X86_IA32_ARCHVARIANT_H_
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+enum TemplateOpcode {
+#include "../../../template/ia32/TemplateOpList.h"
+/*
+ * For example,
+ *     TEMPLATE_CMP_LONG,
+ *     TEMPLATE_RETURN,
+ *     ...
+ */
+    TEMPLATE_LAST_MARK,
+};
+#undef JIT_TEMPLATE
+
+#endif  // DALVIK_VM_COMPILER_CODEGEN_X86_IA32_ARCHVARIANT_H_
diff --git a/vm/compiler/codegen/x86/ia32/CallingConvention.S b/vm/compiler/codegen/x86/ia32/CallingConvention.S
new file mode 100644
index 0000000..cc4187a
--- /dev/null
+++ b/vm/compiler/codegen/x86/ia32/CallingConvention.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Save & restore for callee-save FP registers.
+ * On entry:
+ *    tos : pointer to save area of JIT_CALLEE_SAVE_WORD_SIZE
+ */
+    .text
+    .align 2
+    .global dvmJitCalleeSave
+    .type dvmJitCalleeSave, %function
+dvmJitCalleeSave:
+    ret
+
+    .global dvmJitCalleeRestore
+    .type dvmJitCalleeRestore, %function
+dvmJitCalleeRestore:
+    ret
diff --git a/vm/compiler/codegen/x86/ia32/Codegen.cpp b/vm/compiler/codegen/x86/ia32/Codegen.cpp
new file mode 100644
index 0000000..ae55cd1
--- /dev/null
+++ b/vm/compiler/codegen/x86/ia32/Codegen.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _CODEGEN_C
+#define _IA32
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/DexOpcodes.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/x86/X86LIR.h"
+#include "mterp/common/FindInterface.h"
+//#include "compiler/codegen/x86/Ralloc.h"
+#include "compiler/codegen/x86/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Architectural independent building blocks */
+//#include "../CodegenCommon.cpp"
+
+/* Architectural independent building blocks */
+//#include "../Thumb/Factory.cpp"
+/* Factory utilities dependent on arch-specific features */
+//#include "../CodegenFactory.cpp"
+
+/* ia32 register allocation */
+//#include "../ia32/Ralloc.cpp"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.cpp"
+
+/* Architecture manifest */
+#include "ArchVariant.cpp"
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-vfp/TEMPLATE_ADD_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_ADD_DOUBLE_VFP.S
new file mode 100644
index 0000000..51693fa
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_ADD_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinopWide.S" {"instr":"faddd   d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_ADD_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_ADD_FLOAT_VFP.S
new file mode 100644
index 0000000..ad1e122
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_ADD_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinop.S" {"instr":"fadds   s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S
new file mode 100644
index 0000000..992c894
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_DOUBLE_VFP.S
@@ -0,0 +1,33 @@
+%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
+    fcmpd  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-vfp/TEMPLATE_CMPG_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPG_FLOAT_VFP.S
new file mode 100644
index 0000000..0510ef6
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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
+    fcmps  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-vfp/TEMPLATE_CMPL_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPL_DOUBLE_VFP.S
new file mode 100644
index 0000000..7241af1
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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-vfp/TEMPLATE_CMPL_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_CMPL_FLOAT_VFP.S
new file mode 100644
index 0000000..bdb42d6
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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
+    fcmps  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-vfp/TEMPLATE_DIV_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_DIV_DOUBLE_VFP.S
new file mode 100644
index 0000000..8fa58b8
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_DIV_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinopWide.S" {"instr":"fdivd   d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_DIV_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_DIV_FLOAT_VFP.S
new file mode 100644
index 0000000..fc125ce
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_DIV_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinop.S" {"instr":"fdivs   s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S
new file mode 100644
index 0000000..dba3b08
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/funopNarrower.S" {"instr":"fcvtsd  s0, d0"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_DOUBLE_TO_INT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_DOUBLE_TO_INT_VFP.S
new file mode 100644
index 0000000..4d910aa
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_DOUBLE_TO_INT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/funopNarrower.S" {"instr":"ftosizd  s0, d0"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S
new file mode 100644
index 0000000..a5157dd
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/funopWider.S" {"instr":"fcvtds  d0, s0"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_FLOAT_TO_INT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_FLOAT_TO_INT_VFP.S
new file mode 100644
index 0000000..90900aa
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_FLOAT_TO_INT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/funop.S" {"instr":"ftosizs s1, s0"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_INT_TO_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_INT_TO_DOUBLE_VFP.S
new file mode 100644
index 0000000..c9f4fd6
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_INT_TO_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/funopWider.S" {"instr":"fsitod  d0, s0"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_INT_TO_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_INT_TO_FLOAT_VFP.S
new file mode 100644
index 0000000..a8f57b5
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_INT_TO_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/funop.S" {"instr":"fsitos  s1, s0"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S
new file mode 100644
index 0000000..8bee853
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S
@@ -0,0 +1,19 @@
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_MUL_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_MUL_DOUBLE_VFP.S
new file mode 100644
index 0000000..459e796
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_MUL_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinopWide.S" {"instr":"fmuld   d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_MUL_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_MUL_FLOAT_VFP.S
new file mode 100644
index 0000000..301fa84
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_MUL_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinop.S" {"instr":"fmuls   s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_RESTORE_STATE.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_RESTORE_STATE.S
new file mode 100644
index 0000000..196d082
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_RESTORE_STATE.S
@@ -0,0 +1,11 @@
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rSELF to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rSELF               @ pointer to heapArgSpace.coreRegs[0]
+    add     r0, #64                     @ pointer to heapArgSpace.fpRegs[0]
+    vldmia  r0, {d0-d15}
+    sub     r0, #64                     @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    bx      lr
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_SAVE_STATE.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_SAVE_STATE.S
new file mode 100644
index 0000000..11f62b7
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_SAVE_STATE.S
@@ -0,0 +1,23 @@
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rSELF to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rSELF               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    add     r0, #12                     @ move to start of FP save regio
+    vstmia  r0, {d0-d15}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_SQRT_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_SQRT_DOUBLE_VFP.S
new file mode 100644
index 0000000..1c6bb46
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_SQRT_DOUBLE_VFP.S
@@ -0,0 +1,23 @@
+%verify "executed"
+    /*
+     * 64-bit floating point vfp sqrt operation.
+     * If the result is a NaN, bail out to library code to do
+     * the right thing.
+     *
+     * On entry:
+     *     r2 src addr of op1
+     * On exit:
+     *     r0,r1 = res
+     */
+    fldd    d0, [r2]
+    fsqrtd  d1, d0
+    fcmpd   d1, d1
+    fmstat
+    fmrrd   r0, r1, d1
+    bxeq    lr   @ Result OK - return
+    ldr     r2, .Lsqrt
+    fmrrd   r0, r1, d0   @ reload orig operand
+    bx      r2   @ tail call to sqrt library routine
+
+.Lsqrt:
+    .word   sqrt
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_SUB_DOUBLE_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_SUB_DOUBLE_VFP.S
new file mode 100644
index 0000000..8fa20a0
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_SUB_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinopWide.S" {"instr":"fsubd   d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_SUB_FLOAT_VFP.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_SUB_FLOAT_VFP.S
new file mode 100644
index 0000000..5e17e51
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TEMPLATE_SUB_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te-vfp/fbinop.S" {"instr":"fsubs   s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te-vfp/TemplateOpList.h b/vm/compiler/template/armv5te-vfp/TemplateOpList.h
new file mode 100644
index 0000000..0365ba4
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/TemplateOpList.h
@@ -0,0 +1,65 @@
+/*
+ * 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(INVOKE_METHOD_PREDICTED_CHAIN)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE)
+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)
+JIT_TEMPLATE(SQRT_DOUBLE_VFP)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(MEM_OP_DECODE)
+JIT_TEMPLATE(STRING_COMPARETO)
+JIT_TEMPLATE(STRING_INDEXOF)
+JIT_TEMPLATE(INTERPRET)
+JIT_TEMPLATE(MONITOR_ENTER)
+JIT_TEMPLATE(MONITOR_ENTER_DEBUG)
+JIT_TEMPLATE(PERIODIC_PROFILING)
+JIT_TEMPLATE(RETURN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_PREDICTED_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE_PROF)
diff --git a/vm/compiler/template/armv5te-vfp/fbinop.S b/vm/compiler/template/armv5te-vfp/fbinop.S
new file mode 100644
index 0000000..3bc4b52
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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-vfp/fbinopWide.S b/vm/compiler/template/armv5te-vfp/fbinopWide.S
new file mode 100644
index 0000000..3774646
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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-vfp/funop.S b/vm/compiler/template/armv5te-vfp/funop.S
new file mode 100644
index 0000000..8409c28
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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-vfp/funopNarrower.S b/vm/compiler/template/armv5te-vfp/funopNarrower.S
new file mode 100644
index 0000000..8566fca
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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-vfp/funopWider.S b/vm/compiler/template/armv5te-vfp/funopWider.S
new file mode 100644
index 0000000..dbe745c
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/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-vfp/platform.S b/vm/compiler/template/armv5te-vfp/platform.S
new file mode 100644
index 0000000..e0666a5
--- /dev/null
+++ b/vm/compiler/template/armv5te-vfp/platform.S
@@ -0,0 +1,5 @@
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
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_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_CMPL_DOUBLE.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
new file mode 100644
index 0000000..4fd5a71
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
@@ -0,0 +1,38 @@
+%default { "naninst":"mvn     r0, #0" }
+    /*
+     * For the JIT: incoming arguments in r0-r1, r2-r3
+     *              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 */
+    push    {r0-r3}                     @ save operands
+    mov     r11, lr                     @ save return address
+    mov     lr, pc
+    ldr     pc, .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
+    add     sp, #16                     @ drop unused operands
+    bx      r11
+
+    @ 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:
+    pop     {r2-r3}                     @ restore operands in reverse order
+    pop     {r0-r1}                     @ restore operands in reverse order
+    mov     lr, pc
+    ldr     pc, .L__aeabi_cdcmple       @ r0<- Z set if eq, C clear if <
+    movcc   r0, #1                      @ (greater than) r1<- 1
+    bxcc    r11
+    $naninst                            @ r1<- 1 or -1 for NaN
+    bx      r11
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
new file mode 100644
index 0000000..d0f2bec
--- /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, r2-r3
+     *              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     r9, r0                      @ Save copies - we may need to redo
+    mov     r10, r1
+    mov     r11, lr                     @ save return address
+    mov     lr, pc
+    ldr     pc, .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      r11
+    @ 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     r0, r10                     @ restore in reverse order
+    mov     r1, r9
+    mov     lr, pc
+    ldr     pc, .L__aeabi_cfcmple       @ r0<- Z set if eq, C clear if <
+    movcc   r0, #1                      @ (greater than) r1<- 1
+    bxcc    r11
+    $naninst                            @ r1<- 1 or -1 for NaN
+    bx      r11
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
new file mode 100644
index 0000000..e5e8196
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
@@ -0,0 +1,33 @@
+    /*
+     * 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_INTERPRET.S b/vm/compiler/template/armv5te/TEMPLATE_INTERPRET.S
new file mode 100644
index 0000000..9f24887
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INTERPRET.S
@@ -0,0 +1,30 @@
+    /*
+     * This handler transfers control to the interpeter without performing
+     * any lookups.  It may be called either as part of a normal chaining
+     * operation, or from the transition code in header.S.  We distinquish
+     * the two cases by looking at the link register.  If called from a
+     * translation chain, it will point to the chaining Dalvik PC -3.
+     * On entry:
+     *    lr - if NULL:
+     *        r1 - the Dalvik PC to begin interpretation.
+     *    else
+     *        [lr, #3] contains Dalvik PC to begin interpretation
+     *    rSELF - pointer to thread
+     *    rFP - Dalvik frame pointer
+     */
+    cmp     lr, #0
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     101f
+    ldr     r1,[lr, #3]
+101:
+#else
+    ldrne   r1,[lr, #3]
+#endif
+    ldr     r2, .LinterpPunt
+    mov     r0, r1                       @ set Dalvik PC
+    bx      r2
+    @ doesn't return
+
+.LinterpPunt:
+    .word   dvmJitToInterpPunt
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..03b97a4
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
@@ -0,0 +1,49 @@
+%default { "chaintgt" : ".LinvokeChain" }
+    /*
+     * 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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+$chaintgt:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S
new file mode 100644
index 0000000..d1be4fd
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S" { "chaintgt" : ".LinvokeChainProf" }
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
new file mode 100644
index 0000000..2a73c22
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
@@ -0,0 +1,83 @@
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S
new file mode 100644
index 0000000..816277a
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S"
+#undef TEMPLATE_INLINE_PROFILING
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..a7a0961
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
@@ -0,0 +1,60 @@
+    /*
+     * 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S
new file mode 100644
index 0000000..bfea7d9
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S"
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
new file mode 100644
index 0000000..9dd4ff8
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S
@@ -0,0 +1,60 @@
+%default { "chaintgt" : ".LinvokeChain" }
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     $chaintgt   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S
new file mode 100644
index 0000000..6ca5bdd
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S" { "chaintgt" : ".LinvokeChainProf" }
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MEM_OP_DECODE.S b/vm/compiler/template/armv5te/TEMPLATE_MEM_OP_DECODE.S
new file mode 100644
index 0000000..03926b6
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MEM_OP_DECODE.S
@@ -0,0 +1,17 @@
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    push    {r0-r12,lr}                 @ save out all registers
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    bx      lr                          @ return to compiled code
+#endif
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S
new file mode 100644
index 0000000..1ed3fb1
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER.S
@@ -0,0 +1,21 @@
+    /*
+     * Call out to the runtime to lock an object.  Because this thread
+     * may have been suspended in THREAD_MONITOR state and the Jit's
+     * translation cache subsequently cleared, we cannot return directly.
+     * Instead, unconditionally transition to the interpreter to resume.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2                           @ dvmLockObject(self, obj)
+    ldr     r2, .LdvmJitToInterpNoChain
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    bx      r2
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S
new file mode 100644
index 0000000..2695483
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S
@@ -0,0 +1,28 @@
+    /*
+     * To support deadlock prediction, this version of MONITOR_ENTER
+     * will always call the heavyweight dvmLockObject, check for an
+     * exception and then bail out to the interpreter.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     *
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2             @ dvmLockObject(self, obj)
+    @ test for exception
+    ldr     r1, [rSELF, #offThread_exception]
+    cmp     r1, #0
+    beq     1f
+    ldr     r2, .LhandleException
+    sub     r0, r4, #2     @ roll dPC back to this monitor instruction
+    bx      r2
+1:
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    ldr     pc, .LdvmJitToInterpNoChain
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_PERIODIC_PROFILING.S b/vm/compiler/template/armv5te/TEMPLATE_PERIODIC_PROFILING.S
new file mode 100644
index 0000000..c0f7d6e
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_PERIODIC_PROFILING.S
@@ -0,0 +1,26 @@
+    /*
+     * Increment profile counter for this trace, and decrement
+     * sample counter.  If sample counter goes below zero, turn
+     * off profiling.
+     *
+     * On entry
+     * (lr-11) is address of pointer to counter.  Note: the counter
+     *    actually exists 10 bytes before the return target, but because
+     *    we are arriving from thumb mode, lr will have its low bit set.
+     */
+     ldr    r0, [lr,#-11]
+     ldr    r1, [rSELF, #offThread_pProfileCountdown]
+     ldr    r2, [r0]                    @ get counter
+     ldr    r3, [r1]                    @ get countdown timer
+     add    r2, #1
+     subs   r2, #1
+     blt    .L${opcode}_disable_profiling
+     str    r2, [r0]
+     str    r3, [r1]
+     bx     lr
+
+.L${opcode}_disable_profiling:
+     mov    r4, lr                     @ preserve lr
+     ldr    r0, .LdvmJitTraceProfilingOff
+     blx    r0
+     bx     r4
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RESTORE_STATE.S b/vm/compiler/template/armv5te/TEMPLATE_RESTORE_STATE.S
new file mode 100644
index 0000000..25b4ffa
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_RESTORE_STATE.S
@@ -0,0 +1,8 @@
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rSELF to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rSELF               @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    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..d074c9e
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
@@ -0,0 +1,57 @@
+    /*
+     * 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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF in r0
+    blx     r2                          @ exit the interpreter
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RETURN_PROF.S b/vm/compiler/template/armv5te/TEMPLATE_RETURN_PROF.S
new file mode 100644
index 0000000..d7af0bd
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN_PROF.S
@@ -0,0 +1,3 @@
+#define TEMPLATE_INLINE_PROFILING
+%include "armv5te/TEMPLATE_RETURN.S"
+#undef TEMPLATE_INLINE_PROFILING
diff --git a/vm/compiler/template/armv5te/TEMPLATE_SAVE_STATE.S b/vm/compiler/template/armv5te/TEMPLATE_SAVE_STATE.S
new file mode 100644
index 0000000..1c3aa4d
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_SAVE_STATE.S
@@ -0,0 +1,21 @@
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rSELF to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rSELF               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
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..c737840
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_SHR_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.
+     */
+    /* 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_STRING_COMPARETO.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S
new file mode 100644
index 0000000..54bde47
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S
@@ -0,0 +1,133 @@
+    /*
+     * String's compareTo.
+     *
+     * Requires r0/r1 to have been previously checked for null.  Will
+     * return negative if this's string is < comp, 0 if they are the
+     * same and positive if >.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync with definitions in UtfString.h.  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   this object pointer
+     *    r1:   comp object pointer
+     *
+     */
+
+    mov    r2, r0         @ this to r2, opening up r0 for return value
+    subs   r0, r2, r1     @ Same?
+    bxeq   lr
+
+    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
+    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
+    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
+    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
+    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
+    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    value:  r2/r1
+     *    offset: r4/r9
+     *    count:  r7/r10
+     * We're going to compute
+     *    r11 <- countDiff
+     *    r10 <- minCount
+     */
+     subs  r11, r7, r10
+     movls r10, r7
+
+     /* Now, build pointers to the string data */
+     add   r2, r2, r4, lsl #1
+     add   r1, r1, r9, lsl #1
+     /*
+      * Note: data pointers point to previous element so we can use pre-index
+      * mode with base writeback.
+      */
+     add   r2, #16-2   @ offset to contents[-1]
+     add   r1, #16-2   @ offset to contents[-1]
+
+     /*
+      * At this point we have:
+      *   r2: *this string data
+      *   r1: *comp string data
+      *   r10: iteration count for comparison
+      *   r11: value to return if the first part of the string is equal
+      *   r0: reserved for result
+      *   r3, r4, r7, r8, r9, r12 available for loading string data
+      */
+
+    subs  r10, #2
+    blt   do_remainder2
+
+      /*
+       * Unroll the first two checks so we can quickly catch early mismatch
+       * on long strings (but preserve incoming alignment)
+       */
+
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    bxne  lr
+    cmp   r10, #28
+    bgt   do_memcmp16
+    subs  r10, #3
+    blt   do_remainder
+
+loopback_triple:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    ldrh  r9, [r2, #2]!
+    ldrh  r12,[r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    subeqs  r0, r9, r12
+    bxne  lr
+    subs  r10, #3
+    bge   loopback_triple
+
+do_remainder:
+    adds  r10, #3
+    beq   returnDiff
+
+loopback_single:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    subs  r0, r3, r4
+    bxne  lr
+    subs  r10, #1
+    bne     loopback_single
+
+returnDiff:
+    mov   r0, r11
+    bx    lr
+
+do_remainder2:
+    adds  r10, #2
+    bne   loopback_single
+    mov   r0, r11
+    bx    lr
+
+    /* Long string case */
+do_memcmp16:
+    mov   r4, lr
+    ldr   lr, .Lmemcmp16
+    mov   r7, r11
+    add   r0, r2, #2
+    add   r1, r1, #2
+    mov   r2, r10
+    blx   lr
+    cmp   r0, #0
+    bxne  r4
+    mov   r0, r7
+    bx    r4
+
+.Lmemcmp16:
+    .word __memcmp16
diff --git a/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S
new file mode 100644
index 0000000..bdfdf28
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S
@@ -0,0 +1,112 @@
+    /*
+     * String's indexOf.
+     *
+     * Requires r0 to have been previously checked for null.  Will
+     * return index of match of r1 in r0.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync wth definitions in UtfString.h  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   string object pointer
+     *    r1:   char to match
+     *    r2:   Starting offset in string data
+     */
+
+    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
+    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
+    ldr    r0, [r0, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    r0: object pointer
+     *    r1: char to match
+     *    r2: starting offset
+     *    r7: offset
+     *    r8: string length
+     */
+
+     /* Build pointer to start of string data */
+     add   r0, #16
+     add   r0, r0, r7, lsl #1
+
+     /* Save a copy of starting data in r7 */
+     mov   r7, r0
+
+     /* Clamp start to [0..count] */
+     cmp   r2, #0
+     movlt r2, #0
+     cmp   r2, r8
+     movgt r2, r8
+
+     /* Build pointer to start of data to compare and pre-bias */
+     add   r0, r0, r2, lsl #1
+     sub   r0, #2
+
+     /* Compute iteration count */
+     sub   r8, r2
+
+     /*
+      * At this point we have:
+      *   r0: start of data to test
+      *   r1: chat to compare
+      *   r8: iteration count
+      *   r7: original start of string
+      *   r3, r4, r9, r10, r11, r12 available for loading string data
+      */
+
+    subs  r8, #4
+    blt   indexof_remainder
+
+indexof_loop4:
+    ldrh  r3, [r0, #2]!
+    ldrh  r4, [r0, #2]!
+    ldrh  r10, [r0, #2]!
+    ldrh  r11, [r0, #2]!
+    cmp   r3, r1
+    beq   match_0
+    cmp   r4, r1
+    beq   match_1
+    cmp   r10, r1
+    beq   match_2
+    cmp   r11, r1
+    beq   match_3
+    subs  r8, #4
+    bge   indexof_loop4
+
+indexof_remainder:
+    adds    r8, #4
+    beq     indexof_nomatch
+
+indexof_loop1:
+    ldrh  r3, [r0, #2]!
+    cmp   r3, r1
+    beq   match_3
+    subs  r8, #1
+    bne   indexof_loop1
+
+indexof_nomatch:
+    mov   r0, #-1
+    bx    lr
+
+match_0:
+    sub   r0, #6
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_1:
+    sub   r0, #4
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_2:
+    sub   r0, #2
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_3:
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S b/vm/compiler/template/armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S
new file mode 100644
index 0000000..b737798
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S
@@ -0,0 +1,6 @@
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
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..8a48df2
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_USHR_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.
+     */
+    /* 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..abfec4b
--- /dev/null
+++ b/vm/compiler/template/armv5te/TemplateOpList.h
@@ -0,0 +1,50 @@
+/*
+ * 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(INVOKE_METHOD_PREDICTED_CHAIN)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE)
+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(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(MEM_OP_DECODE)
+JIT_TEMPLATE(STRING_COMPARETO)
+JIT_TEMPLATE(STRING_INDEXOF)
+JIT_TEMPLATE(INTERPRET)
+JIT_TEMPLATE(MONITOR_ENTER)
+JIT_TEMPLATE(MONITOR_ENTER_DEBUG)
+JIT_TEMPLATE(PERIODIC_PROFILING)
+JIT_TEMPLATE(RETURN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_PREDICTED_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE_PROF)
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
new file mode 100644
index 0000000..16660ae
--- /dev/null
+++ b/vm/compiler/template/armv5te/footer.S
@@ -0,0 +1,129 @@
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+.LinvokeNative:
+    @ Prep for the native call
+    @ r1 = newFP, r0 = methodToCall
+    mov     r2, #0
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in jit code cache
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+    ands    lr, #kSubModeMethodTrace
+    beq     121f                        @ hop if not profiling
+    @ r2: methodToCall, r6: rSELF
+    stmfd   sp!, {r2,r6}
+    stmfd   sp!, {r0-r3}
+    mov     r0, r2
+    mov     r1, r6
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}
+
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+
+    ldmfd   sp!, {r0-r1}
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+    b       212f
+121:
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+212:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the new mode
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+    ldr     pc, .LdeadFood @ should not see this under self-verification mode
+.LdeadFood:
+    .word   0xdeadf00d
+#endif
+    mov     r2, #0
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ in interpreter land
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
+
+    .align  2
+.LdvmAsmInstructionStart:
+    .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+    .word   dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+    .word   dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+    .word   dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+    .word   dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+    .word   dvmLockObject
+.LdvmJitTraceProfilingOff:
+    .word   dvmJitTraceProfilingOff
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+    .word   gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
+.LdvmFastMethodTraceEnter:
+    .word   dvmFastMethodTraceEnter
+.LdvmFastNativeMethodTraceExit:
+    .word   dvmFastNativeMethodTraceExit
+.LdvmFastMethodTraceExit:
+    .word   dvmFastMethodTraceExit
+.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/header.S b/vm/compiler/template/armv5te/header.S
new file mode 100644
index 0000000..6dcf5b9
--- /dev/null
+++ b/vm/compiler/template/armv5te/header.S
@@ -0,0 +1,95 @@
+/*
+ * 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  rSELF     thread 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 rSELF   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
+
+#define EXPORT_PC() \
+    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * 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..e0666a5
--- /dev/null
+++ b/vm/compiler/template/armv5te/platform.S
@@ -0,0 +1,5 @@
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
diff --git a/vm/compiler/template/armv7-a-neon/TemplateOpList.h b/vm/compiler/template/armv7-a-neon/TemplateOpList.h
new file mode 100644
index 0000000..0365ba4
--- /dev/null
+++ b/vm/compiler/template/armv7-a-neon/TemplateOpList.h
@@ -0,0 +1,65 @@
+/*
+ * 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(INVOKE_METHOD_PREDICTED_CHAIN)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE)
+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)
+JIT_TEMPLATE(SQRT_DOUBLE_VFP)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(MEM_OP_DECODE)
+JIT_TEMPLATE(STRING_COMPARETO)
+JIT_TEMPLATE(STRING_INDEXOF)
+JIT_TEMPLATE(INTERPRET)
+JIT_TEMPLATE(MONITOR_ENTER)
+JIT_TEMPLATE(MONITOR_ENTER_DEBUG)
+JIT_TEMPLATE(PERIODIC_PROFILING)
+JIT_TEMPLATE(RETURN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_PREDICTED_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE_PROF)
diff --git a/vm/compiler/template/armv7-a/TemplateOpList.h b/vm/compiler/template/armv7-a/TemplateOpList.h
new file mode 100644
index 0000000..0365ba4
--- /dev/null
+++ b/vm/compiler/template/armv7-a/TemplateOpList.h
@@ -0,0 +1,65 @@
+/*
+ * 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(INVOKE_METHOD_PREDICTED_CHAIN)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE)
+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)
+JIT_TEMPLATE(SQRT_DOUBLE_VFP)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(MEM_OP_DECODE)
+JIT_TEMPLATE(STRING_COMPARETO)
+JIT_TEMPLATE(STRING_INDEXOF)
+JIT_TEMPLATE(INTERPRET)
+JIT_TEMPLATE(MONITOR_ENTER)
+JIT_TEMPLATE(MONITOR_ENTER_DEBUG)
+JIT_TEMPLATE(PERIODIC_PROFILING)
+JIT_TEMPLATE(RETURN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_PREDICTED_CHAIN_PROF)
+JIT_TEMPLATE(INVOKE_METHOD_NATIVE_PROF)
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/config-armv5te-vfp b/vm/compiler/template/config-armv5te-vfp
new file mode 100644
index 0000000..774bd96
--- /dev/null
+++ b/vm/compiler/template/config-armv5te-vfp
@@ -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.
+
+#
+# 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-vfp/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-vfp
+    op TEMPLATE_CMP_LONG armv5te
+    op TEMPLATE_INVOKE_METHOD_CHAIN armv5te
+    op TEMPLATE_INVOKE_METHOD_NATIVE armv5te
+    op TEMPLATE_INVOKE_METHOD_NO_OPT armv5te
+    op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN armv5te
+    op TEMPLATE_MUL_LONG armv5te
+    op TEMPLATE_RETURN armv5te
+    op TEMPLATE_SHL_LONG armv5te
+    op TEMPLATE_SHR_LONG armv5te
+    op TEMPLATE_USHR_LONG armv5te
+    op TEMPLATE_THROW_EXCEPTION_COMMON armv5te
+    op TEMPLATE_STRING_COMPARETO armv5te
+    op TEMPLATE_STRING_INDEXOF armv5te
+    op TEMPLATE_INTERPRET armv5te
+    op TEMPLATE_MONITOR_ENTER armv5te
+    op TEMPLATE_MONITOR_ENTER_DEBUG armv5te
+    op TEMPLATE_PERIODIC_PROFILING armv5te
+    op TEMPLATE_INVOKE_METHOD_CHAIN_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_NATIVE_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_NO_OPT_PROF armv5te
+    op TEMPLATE_RETURN_PROF 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/config-armv7-a b/vm/compiler/template/config-armv7-a
new file mode 100644
index 0000000..9d66e55
--- /dev/null
+++ b/vm/compiler/template/config-armv7-a
@@ -0,0 +1,67 @@
+
+# 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 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-vfp/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-vfp
+    op TEMPLATE_CMP_LONG armv5te
+    op TEMPLATE_INVOKE_METHOD_CHAIN armv5te
+    op TEMPLATE_INVOKE_METHOD_NATIVE armv5te
+    op TEMPLATE_INVOKE_METHOD_NO_OPT armv5te
+    op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN armv5te
+    op TEMPLATE_MUL_LONG armv5te
+    op TEMPLATE_RETURN armv5te
+    op TEMPLATE_SHL_LONG armv5te
+    op TEMPLATE_SHR_LONG armv5te
+    op TEMPLATE_USHR_LONG armv5te
+    op TEMPLATE_THROW_EXCEPTION_COMMON armv5te
+    op TEMPLATE_STRING_COMPARETO armv5te
+    op TEMPLATE_STRING_INDEXOF armv5te
+    op TEMPLATE_INTERPRET armv5te
+    op TEMPLATE_MONITOR_ENTER armv5te
+    op TEMPLATE_MONITOR_ENTER_DEBUG armv5te
+    op TEMPLATE_PERIODIC_PROFILING armv5te
+    op TEMPLATE_INVOKE_METHOD_CHAIN_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_NATIVE_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_NO_OPT_PROF armv5te
+    op TEMPLATE_RETURN_PROF 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/config-armv7-a-neon b/vm/compiler/template/config-armv7-a-neon
new file mode 100644
index 0000000..9d66e55
--- /dev/null
+++ b/vm/compiler/template/config-armv7-a-neon
@@ -0,0 +1,67 @@
+
+# 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 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-vfp/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-vfp
+    op TEMPLATE_CMP_LONG armv5te
+    op TEMPLATE_INVOKE_METHOD_CHAIN armv5te
+    op TEMPLATE_INVOKE_METHOD_NATIVE armv5te
+    op TEMPLATE_INVOKE_METHOD_NO_OPT armv5te
+    op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN armv5te
+    op TEMPLATE_MUL_LONG armv5te
+    op TEMPLATE_RETURN armv5te
+    op TEMPLATE_SHL_LONG armv5te
+    op TEMPLATE_SHR_LONG armv5te
+    op TEMPLATE_USHR_LONG armv5te
+    op TEMPLATE_THROW_EXCEPTION_COMMON armv5te
+    op TEMPLATE_STRING_COMPARETO armv5te
+    op TEMPLATE_STRING_INDEXOF armv5te
+    op TEMPLATE_INTERPRET armv5te
+    op TEMPLATE_MONITOR_ENTER armv5te
+    op TEMPLATE_MONITOR_ENTER_DEBUG armv5te
+    op TEMPLATE_PERIODIC_PROFILING armv5te
+    op TEMPLATE_INVOKE_METHOD_CHAIN_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_NATIVE_PROF armv5te
+    op TEMPLATE_INVOKE_METHOD_NO_OPT_PROF armv5te
+    op TEMPLATE_RETURN_PROF 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/config-ia32 b/vm/compiler/template/config-ia32
new file mode 100644
index 0000000..5709017
--- /dev/null
+++ b/vm/compiler/template/config-ia32
@@ -0,0 +1,45 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Configuration for ARMv5TE architecture targets.
+#
+
+# file header and basic definitions
+#import c/header.c
+import ia32/header.S
+
+# C pre-processor defines for stub C instructions
+#import cstubs/stubdefs.c
+
+# highly-platform-specific defs
+import ia32/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 ia32
+
+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 ia32/footer.S
diff --git a/vm/compiler/template/gen-template.py b/vm/compiler/template/gen-template.py
new file mode 100755
index 0000000..02e9107
--- /dev/null
+++ b/vm/compiler/template/gen-template.py
@@ -0,0 +1,423 @@
+#!/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 kNumPackedOpcodes
+# 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 kNumPackedOpcodes 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/ia32/TEMPLATE_INTERPRET.S b/vm/compiler/template/ia32/TEMPLATE_INTERPRET.S
new file mode 100644
index 0000000..5c7bf7c
--- /dev/null
+++ b/vm/compiler/template/ia32/TEMPLATE_INTERPRET.S
@@ -0,0 +1,38 @@
+    /*
+     * This handler is a bit odd - it may be called via chaining or
+     * from static code and is expected to cause control to flow
+     * to the interpreter.  The problem is where to find the Dalvik
+     * PC of the next instruction.  When called via chaining, the dPC
+     * will be located at *rp.  When called from static code, rPC is
+     * valid and rp is a real return pointer (that should be ignored).
+     * The Arm target deals with this by using the link register as
+     * a flag.  If it is zero, we know we were called from static code.
+     * If non-zero, it points to the chain cell containing dPC.
+     * For x86, we'll infer the source by looking where rp points.
+     * If it points to anywhere within the code cache, we'll assume
+     * we got here via chaining.  Otherwise, we'll assume rPC is valid.
+     *
+     * On entry:
+     *    (TOS)<- return pointer or pointer to dPC
+     */
+
+/*
+ * FIXME - this won't work as-is.  The cache boundaries are not
+ * set up until later.  Perhaps rething this whole thing.  Do we
+ * really need an interpret teplate?
+ */
+
+
+     movl   rSELF,%ecx
+     movl   $$.LinterpPunt,%edx
+     pop    %eax
+     /*cmpl   %eax,offThread_jitCacheEnd(%ecx)*/
+     ja     1f
+     /*cmpl   %eax,offThread_jitCacheStart(%ecx)*/
+     jb     1f
+     movl   %eax,rPC
+1:
+     jmp    *(%edx)
+
+.LinterpPunt:
+    .long   dvmJitToInterpPunt
diff --git a/vm/compiler/template/ia32/TemplateOpList.h b/vm/compiler/template/ia32/TemplateOpList.h
new file mode 100644
index 0000000..a5000da
--- /dev/null
+++ b/vm/compiler/template/ia32/TemplateOpList.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Dalvik opcode list that uses additional templates to complete JIT execution.
+ */
+#ifndef JIT_TEMPLATE
+#define JIT_TEMPLATE(X)
+#endif
+
+JIT_TEMPLATE(INTERPRET)
diff --git a/vm/compiler/template/ia32/footer.S b/vm/compiler/template/ia32/footer.S
new file mode 100644
index 0000000..d350c77
--- /dev/null
+++ b/vm/compiler/template/ia32/footer.S
@@ -0,0 +1,13 @@
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  4
+
+    .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
diff --git a/vm/compiler/template/ia32/header.S b/vm/compiler/template/ia32/header.S
new file mode 100644
index 0000000..ea2cc0f
--- /dev/null
+++ b/vm/compiler/template/ia32/header.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(WITH_JIT)
+
+/* Subset of defines from mterp/x86/header.S */
+#define rSELF (%ebp)
+#define rPC   %esi
+#define rFP   %edi
+#define rINST %ebx
+
+/*
+ * 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/ia32/platform.S b/vm/compiler/template/ia32/platform.S
new file mode 100644
index 0000000..a84e62d
--- /dev/null
+++ b/vm/compiler/template/ia32/platform.S
@@ -0,0 +1,7 @@
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
new file mode 100644
index 0000000..331d902
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -0,0 +1,1981 @@
+/*
+ * This file was generated automatically by gen-template.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.
+ */
+
+#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  rSELF     thread 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 rSELF   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
+
+#define EXPORT_PC() \
+    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * 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-vfp/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+
+    .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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+/* ------------------------------ */
+    .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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChain:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChain   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/* ------------------------------ */
+    .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-vfp/TEMPLATE_ADD_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_SUB_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_MUL_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DIV_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_ADD_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_SUB_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_MUL_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DIV_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DOUBLE_TO_INT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S */
+/* File: armv5te-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
+     *
+     * 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-vfp/TEMPLATE_FLOAT_TO_INT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_INT_TO_DOUBLE_VFP.S */
+/* File: armv5te-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
+     *
+     * 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-vfp/TEMPLATE_INT_TO_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/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
+    fcmpd  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-vfp/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-vfp/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
+    fcmps  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-vfp/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
+    fcmps  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
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP
+dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
+/* File: armv5te-vfp/TEMPLATE_SQRT_DOUBLE_VFP.S */
+    /*
+     * 64-bit floating point vfp sqrt operation.
+     * If the result is a NaN, bail out to library code to do
+     * the right thing.
+     *
+     * On entry:
+     *     r2 src addr of op1
+     * On exit:
+     *     r0,r1 = res
+     */
+    fldd    d0, [r2]
+    fsqrtd  d1, d0
+    fcmpd   d1, d1
+    fmstat
+    fmrrd   r0, r1, d1
+    bxeq    lr   @ Result OK - return
+    ldr     r2, .Lsqrt
+    fmrrd   r0, r1, d0   @ reload orig operand
+    bx      r2   @ tail call to sqrt library routine
+
+.Lsqrt:
+    .word   sqrt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_COMPARETO
+dvmCompiler_TEMPLATE_STRING_COMPARETO:
+/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */
+    /*
+     * String's compareTo.
+     *
+     * Requires r0/r1 to have been previously checked for null.  Will
+     * return negative if this's string is < comp, 0 if they are the
+     * same and positive if >.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync with definitions in UtfString.h.  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   this object pointer
+     *    r1:   comp object pointer
+     *
+     */
+
+    mov    r2, r0         @ this to r2, opening up r0 for return value
+    subs   r0, r2, r1     @ Same?
+    bxeq   lr
+
+    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
+    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
+    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
+    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
+    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
+    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    value:  r2/r1
+     *    offset: r4/r9
+     *    count:  r7/r10
+     * We're going to compute
+     *    r11 <- countDiff
+     *    r10 <- minCount
+     */
+     subs  r11, r7, r10
+     movls r10, r7
+
+     /* Now, build pointers to the string data */
+     add   r2, r2, r4, lsl #1
+     add   r1, r1, r9, lsl #1
+     /*
+      * Note: data pointers point to previous element so we can use pre-index
+      * mode with base writeback.
+      */
+     add   r2, #16-2   @ offset to contents[-1]
+     add   r1, #16-2   @ offset to contents[-1]
+
+     /*
+      * At this point we have:
+      *   r2: *this string data
+      *   r1: *comp string data
+      *   r10: iteration count for comparison
+      *   r11: value to return if the first part of the string is equal
+      *   r0: reserved for result
+      *   r3, r4, r7, r8, r9, r12 available for loading string data
+      */
+
+    subs  r10, #2
+    blt   do_remainder2
+
+      /*
+       * Unroll the first two checks so we can quickly catch early mismatch
+       * on long strings (but preserve incoming alignment)
+       */
+
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    bxne  lr
+    cmp   r10, #28
+    bgt   do_memcmp16
+    subs  r10, #3
+    blt   do_remainder
+
+loopback_triple:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    ldrh  r9, [r2, #2]!
+    ldrh  r12,[r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    subeqs  r0, r9, r12
+    bxne  lr
+    subs  r10, #3
+    bge   loopback_triple
+
+do_remainder:
+    adds  r10, #3
+    beq   returnDiff
+
+loopback_single:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    subs  r0, r3, r4
+    bxne  lr
+    subs  r10, #1
+    bne     loopback_single
+
+returnDiff:
+    mov   r0, r11
+    bx    lr
+
+do_remainder2:
+    adds  r10, #2
+    bne   loopback_single
+    mov   r0, r11
+    bx    lr
+
+    /* Long string case */
+do_memcmp16:
+    mov   r4, lr
+    ldr   lr, .Lmemcmp16
+    mov   r7, r11
+    add   r0, r2, #2
+    add   r1, r1, #2
+    mov   r2, r10
+    blx   lr
+    cmp   r0, #0
+    bxne  r4
+    mov   r0, r7
+    bx    r4
+
+.Lmemcmp16:
+    .word __memcmp16
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_INDEXOF
+dvmCompiler_TEMPLATE_STRING_INDEXOF:
+/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */
+    /*
+     * String's indexOf.
+     *
+     * Requires r0 to have been previously checked for null.  Will
+     * return index of match of r1 in r0.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync wth definitions in UtfString.h  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   string object pointer
+     *    r1:   char to match
+     *    r2:   Starting offset in string data
+     */
+
+    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
+    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
+    ldr    r0, [r0, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    r0: object pointer
+     *    r1: char to match
+     *    r2: starting offset
+     *    r7: offset
+     *    r8: string length
+     */
+
+     /* Build pointer to start of string data */
+     add   r0, #16
+     add   r0, r0, r7, lsl #1
+
+     /* Save a copy of starting data in r7 */
+     mov   r7, r0
+
+     /* Clamp start to [0..count] */
+     cmp   r2, #0
+     movlt r2, #0
+     cmp   r2, r8
+     movgt r2, r8
+
+     /* Build pointer to start of data to compare and pre-bias */
+     add   r0, r0, r2, lsl #1
+     sub   r0, #2
+
+     /* Compute iteration count */
+     sub   r8, r2
+
+     /*
+      * At this point we have:
+      *   r0: start of data to test
+      *   r1: chat to compare
+      *   r8: iteration count
+      *   r7: original start of string
+      *   r3, r4, r9, r10, r11, r12 available for loading string data
+      */
+
+    subs  r8, #4
+    blt   indexof_remainder
+
+indexof_loop4:
+    ldrh  r3, [r0, #2]!
+    ldrh  r4, [r0, #2]!
+    ldrh  r10, [r0, #2]!
+    ldrh  r11, [r0, #2]!
+    cmp   r3, r1
+    beq   match_0
+    cmp   r4, r1
+    beq   match_1
+    cmp   r10, r1
+    beq   match_2
+    cmp   r11, r1
+    beq   match_3
+    subs  r8, #4
+    bge   indexof_loop4
+
+indexof_remainder:
+    adds    r8, #4
+    beq     indexof_nomatch
+
+indexof_loop1:
+    ldrh  r3, [r0, #2]!
+    cmp   r3, r1
+    beq   match_3
+    subs  r8, #1
+    bne   indexof_loop1
+
+indexof_nomatch:
+    mov   r0, #-1
+    bx    lr
+
+match_0:
+    sub   r0, #6
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_1:
+    sub   r0, #4
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_2:
+    sub   r0, #2
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_3:
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INTERPRET
+dvmCompiler_TEMPLATE_INTERPRET:
+/* File: armv5te/TEMPLATE_INTERPRET.S */
+    /*
+     * This handler transfers control to the interpeter without performing
+     * any lookups.  It may be called either as part of a normal chaining
+     * operation, or from the transition code in header.S.  We distinquish
+     * the two cases by looking at the link register.  If called from a
+     * translation chain, it will point to the chaining Dalvik PC -3.
+     * On entry:
+     *    lr - if NULL:
+     *        r1 - the Dalvik PC to begin interpretation.
+     *    else
+     *        [lr, #3] contains Dalvik PC to begin interpretation
+     *    rSELF - pointer to thread
+     *    rFP - Dalvik frame pointer
+     */
+    cmp     lr, #0
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     101f
+    ldr     r1,[lr, #3]
+101:
+#else
+    ldrne   r1,[lr, #3]
+#endif
+    ldr     r2, .LinterpPunt
+    mov     r0, r1                       @ set Dalvik PC
+    bx      r2
+    @ doesn't return
+
+.LinterpPunt:
+    .word   dvmJitToInterpPunt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER
+dvmCompiler_TEMPLATE_MONITOR_ENTER:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER.S */
+    /*
+     * Call out to the runtime to lock an object.  Because this thread
+     * may have been suspended in THREAD_MONITOR state and the Jit's
+     * translation cache subsequently cleared, we cannot return directly.
+     * Instead, unconditionally transition to the interpreter to resume.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2                           @ dvmLockObject(self, obj)
+    ldr     r2, .LdvmJitToInterpNoChain
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    bx      r2
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
+dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S */
+    /*
+     * To support deadlock prediction, this version of MONITOR_ENTER
+     * will always call the heavyweight dvmLockObject, check for an
+     * exception and then bail out to the interpreter.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     *
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2             @ dvmLockObject(self, obj)
+    @ test for exception
+    ldr     r1, [rSELF, #offThread_exception]
+    cmp     r1, #0
+    beq     1f
+    ldr     r2, .LhandleException
+    sub     r0, r4, #2     @ roll dPC back to this monitor instruction
+    bx      r2
+1:
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    ldr     pc, .LdvmJitToInterpNoChain
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_PERIODIC_PROFILING
+dvmCompiler_TEMPLATE_PERIODIC_PROFILING:
+/* File: armv5te/TEMPLATE_PERIODIC_PROFILING.S */
+    /*
+     * Increment profile counter for this trace, and decrement
+     * sample counter.  If sample counter goes below zero, turn
+     * off profiling.
+     *
+     * On entry
+     * (lr-11) is address of pointer to counter.  Note: the counter
+     *    actually exists 10 bytes before the return target, but because
+     *    we are arriving from thumb mode, lr will have its low bit set.
+     */
+     ldr    r0, [lr,#-11]
+     ldr    r1, [rSELF, #offThread_pProfileCountdown]
+     ldr    r2, [r0]                    @ get counter
+     ldr    r3, [r1]                    @ get countdown timer
+     add    r2, #1
+     subs   r2, #1
+     blt    .LTEMPLATE_PERIODIC_PROFILING_disable_profiling
+     str    r2, [r0]
+     str    r3, [r1]
+     bx     lr
+
+.LTEMPLATE_PERIODIC_PROFILING_disable_profiling:
+     mov    r4, lr                     @ preserve lr
+     ldr    r0, .LdvmJitTraceProfilingOff
+     blx    r0
+     bx     r4
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RETURN_PROF
+dvmCompiler_TEMPLATE_RETURN_PROF:
+/* File: armv5te/TEMPLATE_RETURN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF in r0
+    blx     r2                          @ exit the interpreter
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChainProf:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChainProf   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+#undef TEMPLATE_INLINE_PROFILING
+
+    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+.LinvokeNative:
+    @ Prep for the native call
+    @ r1 = newFP, r0 = methodToCall
+    mov     r2, #0
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in jit code cache
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+    ands    lr, #kSubModeMethodTrace
+    beq     121f                        @ hop if not profiling
+    @ r2: methodToCall, r6: rSELF
+    stmfd   sp!, {r2,r6}
+    stmfd   sp!, {r0-r3}
+    mov     r0, r2
+    mov     r1, r6
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}
+
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+
+    ldmfd   sp!, {r0-r1}
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+    b       212f
+121:
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+212:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the new mode
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+    ldr     pc, .LdeadFood @ should not see this under self-verification mode
+.LdeadFood:
+    .word   0xdeadf00d
+#endif
+    mov     r2, #0
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ in interpreter land
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
+
+    .align  2
+.LdvmAsmInstructionStart:
+    .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+    .word   dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+    .word   dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+    .word   dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+    .word   dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+    .word   dvmLockObject
+.LdvmJitTraceProfilingOff:
+    .word   dvmJitTraceProfilingOff
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+    .word   gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
+.LdvmFastMethodTraceEnter:
+    .word   dvmFastMethodTraceEnter
+.LdvmFastNativeMethodTraceExit:
+    .word   dvmFastNativeMethodTraceExit
+.LdvmFastMethodTraceExit:
+    .word   dvmFastMethodTraceExit
+.L__aeabi_cdcmple:
+    .word   __aeabi_cdcmple
+.L__aeabi_cfcmple:
+    .word   __aeabi_cfcmple
+
+    .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
new file mode 100644
index 0000000..044843e
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -0,0 +1,1712 @@
+/*
+ * 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  rSELF     thread 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 rSELF   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
+
+#define EXPORT_PC() \
+    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * 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 and utility
+ * ===========================================================================
+ */
+
+
+    .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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+/* ------------------------------ */
+    .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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChain:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChain   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/* ------------------------------ */
+    .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 in r0-r1, r2-r3
+     *              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 */
+    push    {r0-r3}                     @ save operands
+    mov     r11, lr                     @ save return address
+    mov     lr, pc
+    ldr     pc, .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
+    add     sp, #16                     @ drop unused operands
+    bx      r11
+
+    @ 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:
+    pop     {r2-r3}                     @ restore operands in reverse order
+    pop     {r0-r1}                     @ restore operands in reverse order
+    mov     lr, pc
+    ldr     pc, .L__aeabi_cdcmple       @ r0<- Z set if eq, C clear if <
+    movcc   r0, #1                      @ (greater than) r1<- 1
+    bxcc    r11
+    mov     r0, #1                            @ r1<- 1 or -1 for NaN
+    bx      r11
+
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_CMPL_DOUBLE
+dvmCompiler_TEMPLATE_CMPL_DOUBLE:
+/* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
+    /*
+     * For the JIT: incoming arguments in r0-r1, r2-r3
+     *              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 */
+    push    {r0-r3}                     @ save operands
+    mov     r11, lr                     @ save return address
+    mov     lr, pc
+    ldr     pc, .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
+    add     sp, #16                     @ drop unused operands
+    bx      r11
+
+    @ 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:
+    pop     {r2-r3}                     @ restore operands in reverse order
+    pop     {r0-r1}                     @ restore operands in reverse order
+    mov     lr, pc
+    ldr     pc, .L__aeabi_cdcmple       @ r0<- Z set if eq, C clear if <
+    movcc   r0, #1                      @ (greater than) r1<- 1
+    bxcc    r11
+    mvn     r0, #0                            @ r1<- 1 or -1 for NaN
+    bx      r11
+
+/* ------------------------------ */
+    .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, r2-r3
+     *              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     r9, r0                      @ Save copies - we may need to redo
+    mov     r10, r1
+    mov     r11, lr                     @ save return address
+    mov     lr, pc
+    ldr     pc, .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      r11
+    @ 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     r0, r10                     @ restore in reverse order
+    mov     r1, r9
+    mov     lr, pc
+    ldr     pc, .L__aeabi_cfcmple       @ r0<- Z set if eq, C clear if <
+    movcc   r0, #1                      @ (greater than) r1<- 1
+    bxcc    r11
+    mov     r0, #1                            @ r1<- 1 or -1 for NaN
+    bx      r11
+
+
+/* ------------------------------ */
+    .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, r2-r3
+     *              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     r9, r0                      @ Save copies - we may need to redo
+    mov     r10, r1
+    mov     r11, lr                     @ save return address
+    mov     lr, pc
+    ldr     pc, .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      r11
+    @ 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     r0, r10                     @ restore in reverse order
+    mov     r1, r9
+    mov     lr, pc
+    ldr     pc, .L__aeabi_cfcmple       @ r0<- Z set if eq, C clear if <
+    movcc   r0, #1                      @ (greater than) r1<- 1
+    bxcc    r11
+    mvn     r0, #0                            @ r1<- 1 or -1 for NaN
+    bx      r11
+
+/* ------------------------------ */
+    .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_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    push    {r0-r12,lr}                 @ save out all registers
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    bx      lr                          @ return to compiled code
+#endif
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_COMPARETO
+dvmCompiler_TEMPLATE_STRING_COMPARETO:
+/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */
+    /*
+     * String's compareTo.
+     *
+     * Requires r0/r1 to have been previously checked for null.  Will
+     * return negative if this's string is < comp, 0 if they are the
+     * same and positive if >.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync with definitions in UtfString.h.  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   this object pointer
+     *    r1:   comp object pointer
+     *
+     */
+
+    mov    r2, r0         @ this to r2, opening up r0 for return value
+    subs   r0, r2, r1     @ Same?
+    bxeq   lr
+
+    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
+    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
+    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
+    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
+    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
+    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    value:  r2/r1
+     *    offset: r4/r9
+     *    count:  r7/r10
+     * We're going to compute
+     *    r11 <- countDiff
+     *    r10 <- minCount
+     */
+     subs  r11, r7, r10
+     movls r10, r7
+
+     /* Now, build pointers to the string data */
+     add   r2, r2, r4, lsl #1
+     add   r1, r1, r9, lsl #1
+     /*
+      * Note: data pointers point to previous element so we can use pre-index
+      * mode with base writeback.
+      */
+     add   r2, #16-2   @ offset to contents[-1]
+     add   r1, #16-2   @ offset to contents[-1]
+
+     /*
+      * At this point we have:
+      *   r2: *this string data
+      *   r1: *comp string data
+      *   r10: iteration count for comparison
+      *   r11: value to return if the first part of the string is equal
+      *   r0: reserved for result
+      *   r3, r4, r7, r8, r9, r12 available for loading string data
+      */
+
+    subs  r10, #2
+    blt   do_remainder2
+
+      /*
+       * Unroll the first two checks so we can quickly catch early mismatch
+       * on long strings (but preserve incoming alignment)
+       */
+
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    bxne  lr
+    cmp   r10, #28
+    bgt   do_memcmp16
+    subs  r10, #3
+    blt   do_remainder
+
+loopback_triple:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    ldrh  r9, [r2, #2]!
+    ldrh  r12,[r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    subeqs  r0, r9, r12
+    bxne  lr
+    subs  r10, #3
+    bge   loopback_triple
+
+do_remainder:
+    adds  r10, #3
+    beq   returnDiff
+
+loopback_single:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    subs  r0, r3, r4
+    bxne  lr
+    subs  r10, #1
+    bne     loopback_single
+
+returnDiff:
+    mov   r0, r11
+    bx    lr
+
+do_remainder2:
+    adds  r10, #2
+    bne   loopback_single
+    mov   r0, r11
+    bx    lr
+
+    /* Long string case */
+do_memcmp16:
+    mov   r4, lr
+    ldr   lr, .Lmemcmp16
+    mov   r7, r11
+    add   r0, r2, #2
+    add   r1, r1, #2
+    mov   r2, r10
+    blx   lr
+    cmp   r0, #0
+    bxne  r4
+    mov   r0, r7
+    bx    r4
+
+.Lmemcmp16:
+    .word __memcmp16
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_INDEXOF
+dvmCompiler_TEMPLATE_STRING_INDEXOF:
+/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */
+    /*
+     * String's indexOf.
+     *
+     * Requires r0 to have been previously checked for null.  Will
+     * return index of match of r1 in r0.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync wth definitions in UtfString.h  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   string object pointer
+     *    r1:   char to match
+     *    r2:   Starting offset in string data
+     */
+
+    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
+    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
+    ldr    r0, [r0, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    r0: object pointer
+     *    r1: char to match
+     *    r2: starting offset
+     *    r7: offset
+     *    r8: string length
+     */
+
+     /* Build pointer to start of string data */
+     add   r0, #16
+     add   r0, r0, r7, lsl #1
+
+     /* Save a copy of starting data in r7 */
+     mov   r7, r0
+
+     /* Clamp start to [0..count] */
+     cmp   r2, #0
+     movlt r2, #0
+     cmp   r2, r8
+     movgt r2, r8
+
+     /* Build pointer to start of data to compare and pre-bias */
+     add   r0, r0, r2, lsl #1
+     sub   r0, #2
+
+     /* Compute iteration count */
+     sub   r8, r2
+
+     /*
+      * At this point we have:
+      *   r0: start of data to test
+      *   r1: chat to compare
+      *   r8: iteration count
+      *   r7: original start of string
+      *   r3, r4, r9, r10, r11, r12 available for loading string data
+      */
+
+    subs  r8, #4
+    blt   indexof_remainder
+
+indexof_loop4:
+    ldrh  r3, [r0, #2]!
+    ldrh  r4, [r0, #2]!
+    ldrh  r10, [r0, #2]!
+    ldrh  r11, [r0, #2]!
+    cmp   r3, r1
+    beq   match_0
+    cmp   r4, r1
+    beq   match_1
+    cmp   r10, r1
+    beq   match_2
+    cmp   r11, r1
+    beq   match_3
+    subs  r8, #4
+    bge   indexof_loop4
+
+indexof_remainder:
+    adds    r8, #4
+    beq     indexof_nomatch
+
+indexof_loop1:
+    ldrh  r3, [r0, #2]!
+    cmp   r3, r1
+    beq   match_3
+    subs  r8, #1
+    bne   indexof_loop1
+
+indexof_nomatch:
+    mov   r0, #-1
+    bx    lr
+
+match_0:
+    sub   r0, #6
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_1:
+    sub   r0, #4
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_2:
+    sub   r0, #2
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_3:
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INTERPRET
+dvmCompiler_TEMPLATE_INTERPRET:
+/* File: armv5te/TEMPLATE_INTERPRET.S */
+    /*
+     * This handler transfers control to the interpeter without performing
+     * any lookups.  It may be called either as part of a normal chaining
+     * operation, or from the transition code in header.S.  We distinquish
+     * the two cases by looking at the link register.  If called from a
+     * translation chain, it will point to the chaining Dalvik PC -3.
+     * On entry:
+     *    lr - if NULL:
+     *        r1 - the Dalvik PC to begin interpretation.
+     *    else
+     *        [lr, #3] contains Dalvik PC to begin interpretation
+     *    rSELF - pointer to thread
+     *    rFP - Dalvik frame pointer
+     */
+    cmp     lr, #0
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     101f
+    ldr     r1,[lr, #3]
+101:
+#else
+    ldrne   r1,[lr, #3]
+#endif
+    ldr     r2, .LinterpPunt
+    mov     r0, r1                       @ set Dalvik PC
+    bx      r2
+    @ doesn't return
+
+.LinterpPunt:
+    .word   dvmJitToInterpPunt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER
+dvmCompiler_TEMPLATE_MONITOR_ENTER:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER.S */
+    /*
+     * Call out to the runtime to lock an object.  Because this thread
+     * may have been suspended in THREAD_MONITOR state and the Jit's
+     * translation cache subsequently cleared, we cannot return directly.
+     * Instead, unconditionally transition to the interpreter to resume.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2                           @ dvmLockObject(self, obj)
+    ldr     r2, .LdvmJitToInterpNoChain
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    bx      r2
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
+dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S */
+    /*
+     * To support deadlock prediction, this version of MONITOR_ENTER
+     * will always call the heavyweight dvmLockObject, check for an
+     * exception and then bail out to the interpreter.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     *
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2             @ dvmLockObject(self, obj)
+    @ test for exception
+    ldr     r1, [rSELF, #offThread_exception]
+    cmp     r1, #0
+    beq     1f
+    ldr     r2, .LhandleException
+    sub     r0, r4, #2     @ roll dPC back to this monitor instruction
+    bx      r2
+1:
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    ldr     pc, .LdvmJitToInterpNoChain
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_PERIODIC_PROFILING
+dvmCompiler_TEMPLATE_PERIODIC_PROFILING:
+/* File: armv5te/TEMPLATE_PERIODIC_PROFILING.S */
+    /*
+     * Increment profile counter for this trace, and decrement
+     * sample counter.  If sample counter goes below zero, turn
+     * off profiling.
+     *
+     * On entry
+     * (lr-11) is address of pointer to counter.  Note: the counter
+     *    actually exists 10 bytes before the return target, but because
+     *    we are arriving from thumb mode, lr will have its low bit set.
+     */
+     ldr    r0, [lr,#-11]
+     ldr    r1, [rSELF, #offThread_pProfileCountdown]
+     ldr    r2, [r0]                    @ get counter
+     ldr    r3, [r1]                    @ get countdown timer
+     add    r2, #1
+     subs   r2, #1
+     blt    .LTEMPLATE_PERIODIC_PROFILING_disable_profiling
+     str    r2, [r0]
+     str    r3, [r1]
+     bx     lr
+
+.LTEMPLATE_PERIODIC_PROFILING_disable_profiling:
+     mov    r4, lr                     @ preserve lr
+     ldr    r0, .LdvmJitTraceProfilingOff
+     blx    r0
+     bx     r4
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RETURN_PROF
+dvmCompiler_TEMPLATE_RETURN_PROF:
+/* File: armv5te/TEMPLATE_RETURN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF in r0
+    blx     r2                          @ exit the interpreter
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChainProf:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChainProf   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+#undef TEMPLATE_INLINE_PROFILING
+
+    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+.LinvokeNative:
+    @ Prep for the native call
+    @ r1 = newFP, r0 = methodToCall
+    mov     r2, #0
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in jit code cache
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+    ands    lr, #kSubModeMethodTrace
+    beq     121f                        @ hop if not profiling
+    @ r2: methodToCall, r6: rSELF
+    stmfd   sp!, {r2,r6}
+    stmfd   sp!, {r0-r3}
+    mov     r0, r2
+    mov     r1, r6
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}
+
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+
+    ldmfd   sp!, {r0-r1}
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+    b       212f
+121:
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+212:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the new mode
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+    ldr     pc, .LdeadFood @ should not see this under self-verification mode
+.LdeadFood:
+    .word   0xdeadf00d
+#endif
+    mov     r2, #0
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ in interpreter land
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
+
+    .align  2
+.LdvmAsmInstructionStart:
+    .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+    .word   dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+    .word   dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+    .word   dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+    .word   dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+    .word   dvmLockObject
+.LdvmJitTraceProfilingOff:
+    .word   dvmJitTraceProfilingOff
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+    .word   gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
+.LdvmFastMethodTraceEnter:
+    .word   dvmFastMethodTraceEnter
+.LdvmFastNativeMethodTraceExit:
+    .word   dvmFastNativeMethodTraceExit
+.LdvmFastMethodTraceExit:
+    .word   dvmFastMethodTraceExit
+.L__aeabi_cdcmple:
+    .word   __aeabi_cdcmple
+.L__aeabi_cfcmple:
+    .word   __aeabi_cfcmple
+
+    .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
new file mode 100644
index 0000000..ba798e0
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
@@ -0,0 +1,1981 @@
+/*
+ * This file was generated automatically by gen-template.py for 'armv7-a-neon'.
+ *
+ * --> 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  rSELF     thread 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 rSELF   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
+
+#define EXPORT_PC() \
+    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * 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-vfp/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+
+    .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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+/* ------------------------------ */
+    .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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChain:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChain   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/* ------------------------------ */
+    .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-vfp/TEMPLATE_ADD_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_SUB_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_MUL_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DIV_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_ADD_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_SUB_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_MUL_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DIV_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DOUBLE_TO_INT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S */
+/* File: armv5te-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
+     *
+     * 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-vfp/TEMPLATE_FLOAT_TO_INT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_INT_TO_DOUBLE_VFP.S */
+/* File: armv5te-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
+     *
+     * 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-vfp/TEMPLATE_INT_TO_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/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
+    fcmpd  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-vfp/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-vfp/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
+    fcmps  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-vfp/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
+    fcmps  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
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP
+dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
+/* File: armv5te-vfp/TEMPLATE_SQRT_DOUBLE_VFP.S */
+    /*
+     * 64-bit floating point vfp sqrt operation.
+     * If the result is a NaN, bail out to library code to do
+     * the right thing.
+     *
+     * On entry:
+     *     r2 src addr of op1
+     * On exit:
+     *     r0,r1 = res
+     */
+    fldd    d0, [r2]
+    fsqrtd  d1, d0
+    fcmpd   d1, d1
+    fmstat
+    fmrrd   r0, r1, d1
+    bxeq    lr   @ Result OK - return
+    ldr     r2, .Lsqrt
+    fmrrd   r0, r1, d0   @ reload orig operand
+    bx      r2   @ tail call to sqrt library routine
+
+.Lsqrt:
+    .word   sqrt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_COMPARETO
+dvmCompiler_TEMPLATE_STRING_COMPARETO:
+/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */
+    /*
+     * String's compareTo.
+     *
+     * Requires r0/r1 to have been previously checked for null.  Will
+     * return negative if this's string is < comp, 0 if they are the
+     * same and positive if >.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync with definitions in UtfString.h.  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   this object pointer
+     *    r1:   comp object pointer
+     *
+     */
+
+    mov    r2, r0         @ this to r2, opening up r0 for return value
+    subs   r0, r2, r1     @ Same?
+    bxeq   lr
+
+    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
+    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
+    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
+    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
+    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
+    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    value:  r2/r1
+     *    offset: r4/r9
+     *    count:  r7/r10
+     * We're going to compute
+     *    r11 <- countDiff
+     *    r10 <- minCount
+     */
+     subs  r11, r7, r10
+     movls r10, r7
+
+     /* Now, build pointers to the string data */
+     add   r2, r2, r4, lsl #1
+     add   r1, r1, r9, lsl #1
+     /*
+      * Note: data pointers point to previous element so we can use pre-index
+      * mode with base writeback.
+      */
+     add   r2, #16-2   @ offset to contents[-1]
+     add   r1, #16-2   @ offset to contents[-1]
+
+     /*
+      * At this point we have:
+      *   r2: *this string data
+      *   r1: *comp string data
+      *   r10: iteration count for comparison
+      *   r11: value to return if the first part of the string is equal
+      *   r0: reserved for result
+      *   r3, r4, r7, r8, r9, r12 available for loading string data
+      */
+
+    subs  r10, #2
+    blt   do_remainder2
+
+      /*
+       * Unroll the first two checks so we can quickly catch early mismatch
+       * on long strings (but preserve incoming alignment)
+       */
+
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    bxne  lr
+    cmp   r10, #28
+    bgt   do_memcmp16
+    subs  r10, #3
+    blt   do_remainder
+
+loopback_triple:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    ldrh  r9, [r2, #2]!
+    ldrh  r12,[r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    subeqs  r0, r9, r12
+    bxne  lr
+    subs  r10, #3
+    bge   loopback_triple
+
+do_remainder:
+    adds  r10, #3
+    beq   returnDiff
+
+loopback_single:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    subs  r0, r3, r4
+    bxne  lr
+    subs  r10, #1
+    bne     loopback_single
+
+returnDiff:
+    mov   r0, r11
+    bx    lr
+
+do_remainder2:
+    adds  r10, #2
+    bne   loopback_single
+    mov   r0, r11
+    bx    lr
+
+    /* Long string case */
+do_memcmp16:
+    mov   r4, lr
+    ldr   lr, .Lmemcmp16
+    mov   r7, r11
+    add   r0, r2, #2
+    add   r1, r1, #2
+    mov   r2, r10
+    blx   lr
+    cmp   r0, #0
+    bxne  r4
+    mov   r0, r7
+    bx    r4
+
+.Lmemcmp16:
+    .word __memcmp16
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_INDEXOF
+dvmCompiler_TEMPLATE_STRING_INDEXOF:
+/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */
+    /*
+     * String's indexOf.
+     *
+     * Requires r0 to have been previously checked for null.  Will
+     * return index of match of r1 in r0.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync wth definitions in UtfString.h  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   string object pointer
+     *    r1:   char to match
+     *    r2:   Starting offset in string data
+     */
+
+    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
+    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
+    ldr    r0, [r0, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    r0: object pointer
+     *    r1: char to match
+     *    r2: starting offset
+     *    r7: offset
+     *    r8: string length
+     */
+
+     /* Build pointer to start of string data */
+     add   r0, #16
+     add   r0, r0, r7, lsl #1
+
+     /* Save a copy of starting data in r7 */
+     mov   r7, r0
+
+     /* Clamp start to [0..count] */
+     cmp   r2, #0
+     movlt r2, #0
+     cmp   r2, r8
+     movgt r2, r8
+
+     /* Build pointer to start of data to compare and pre-bias */
+     add   r0, r0, r2, lsl #1
+     sub   r0, #2
+
+     /* Compute iteration count */
+     sub   r8, r2
+
+     /*
+      * At this point we have:
+      *   r0: start of data to test
+      *   r1: chat to compare
+      *   r8: iteration count
+      *   r7: original start of string
+      *   r3, r4, r9, r10, r11, r12 available for loading string data
+      */
+
+    subs  r8, #4
+    blt   indexof_remainder
+
+indexof_loop4:
+    ldrh  r3, [r0, #2]!
+    ldrh  r4, [r0, #2]!
+    ldrh  r10, [r0, #2]!
+    ldrh  r11, [r0, #2]!
+    cmp   r3, r1
+    beq   match_0
+    cmp   r4, r1
+    beq   match_1
+    cmp   r10, r1
+    beq   match_2
+    cmp   r11, r1
+    beq   match_3
+    subs  r8, #4
+    bge   indexof_loop4
+
+indexof_remainder:
+    adds    r8, #4
+    beq     indexof_nomatch
+
+indexof_loop1:
+    ldrh  r3, [r0, #2]!
+    cmp   r3, r1
+    beq   match_3
+    subs  r8, #1
+    bne   indexof_loop1
+
+indexof_nomatch:
+    mov   r0, #-1
+    bx    lr
+
+match_0:
+    sub   r0, #6
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_1:
+    sub   r0, #4
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_2:
+    sub   r0, #2
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_3:
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INTERPRET
+dvmCompiler_TEMPLATE_INTERPRET:
+/* File: armv5te/TEMPLATE_INTERPRET.S */
+    /*
+     * This handler transfers control to the interpeter without performing
+     * any lookups.  It may be called either as part of a normal chaining
+     * operation, or from the transition code in header.S.  We distinquish
+     * the two cases by looking at the link register.  If called from a
+     * translation chain, it will point to the chaining Dalvik PC -3.
+     * On entry:
+     *    lr - if NULL:
+     *        r1 - the Dalvik PC to begin interpretation.
+     *    else
+     *        [lr, #3] contains Dalvik PC to begin interpretation
+     *    rSELF - pointer to thread
+     *    rFP - Dalvik frame pointer
+     */
+    cmp     lr, #0
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     101f
+    ldr     r1,[lr, #3]
+101:
+#else
+    ldrne   r1,[lr, #3]
+#endif
+    ldr     r2, .LinterpPunt
+    mov     r0, r1                       @ set Dalvik PC
+    bx      r2
+    @ doesn't return
+
+.LinterpPunt:
+    .word   dvmJitToInterpPunt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER
+dvmCompiler_TEMPLATE_MONITOR_ENTER:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER.S */
+    /*
+     * Call out to the runtime to lock an object.  Because this thread
+     * may have been suspended in THREAD_MONITOR state and the Jit's
+     * translation cache subsequently cleared, we cannot return directly.
+     * Instead, unconditionally transition to the interpreter to resume.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2                           @ dvmLockObject(self, obj)
+    ldr     r2, .LdvmJitToInterpNoChain
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    bx      r2
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
+dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S */
+    /*
+     * To support deadlock prediction, this version of MONITOR_ENTER
+     * will always call the heavyweight dvmLockObject, check for an
+     * exception and then bail out to the interpreter.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     *
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2             @ dvmLockObject(self, obj)
+    @ test for exception
+    ldr     r1, [rSELF, #offThread_exception]
+    cmp     r1, #0
+    beq     1f
+    ldr     r2, .LhandleException
+    sub     r0, r4, #2     @ roll dPC back to this monitor instruction
+    bx      r2
+1:
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    ldr     pc, .LdvmJitToInterpNoChain
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_PERIODIC_PROFILING
+dvmCompiler_TEMPLATE_PERIODIC_PROFILING:
+/* File: armv5te/TEMPLATE_PERIODIC_PROFILING.S */
+    /*
+     * Increment profile counter for this trace, and decrement
+     * sample counter.  If sample counter goes below zero, turn
+     * off profiling.
+     *
+     * On entry
+     * (lr-11) is address of pointer to counter.  Note: the counter
+     *    actually exists 10 bytes before the return target, but because
+     *    we are arriving from thumb mode, lr will have its low bit set.
+     */
+     ldr    r0, [lr,#-11]
+     ldr    r1, [rSELF, #offThread_pProfileCountdown]
+     ldr    r2, [r0]                    @ get counter
+     ldr    r3, [r1]                    @ get countdown timer
+     add    r2, #1
+     subs   r2, #1
+     blt    .LTEMPLATE_PERIODIC_PROFILING_disable_profiling
+     str    r2, [r0]
+     str    r3, [r1]
+     bx     lr
+
+.LTEMPLATE_PERIODIC_PROFILING_disable_profiling:
+     mov    r4, lr                     @ preserve lr
+     ldr    r0, .LdvmJitTraceProfilingOff
+     blx    r0
+     bx     r4
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RETURN_PROF
+dvmCompiler_TEMPLATE_RETURN_PROF:
+/* File: armv5te/TEMPLATE_RETURN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF in r0
+    blx     r2                          @ exit the interpreter
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChainProf:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChainProf   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+#undef TEMPLATE_INLINE_PROFILING
+
+    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+.LinvokeNative:
+    @ Prep for the native call
+    @ r1 = newFP, r0 = methodToCall
+    mov     r2, #0
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in jit code cache
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+    ands    lr, #kSubModeMethodTrace
+    beq     121f                        @ hop if not profiling
+    @ r2: methodToCall, r6: rSELF
+    stmfd   sp!, {r2,r6}
+    stmfd   sp!, {r0-r3}
+    mov     r0, r2
+    mov     r1, r6
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}
+
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+
+    ldmfd   sp!, {r0-r1}
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+    b       212f
+121:
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+212:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the new mode
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+    ldr     pc, .LdeadFood @ should not see this under self-verification mode
+.LdeadFood:
+    .word   0xdeadf00d
+#endif
+    mov     r2, #0
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ in interpreter land
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
+
+    .align  2
+.LdvmAsmInstructionStart:
+    .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+    .word   dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+    .word   dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+    .word   dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+    .word   dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+    .word   dvmLockObject
+.LdvmJitTraceProfilingOff:
+    .word   dvmJitTraceProfilingOff
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+    .word   gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
+.LdvmFastMethodTraceEnter:
+    .word   dvmFastMethodTraceEnter
+.LdvmFastNativeMethodTraceExit:
+    .word   dvmFastNativeMethodTraceExit
+.LdvmFastMethodTraceExit:
+    .word   dvmFastMethodTraceExit
+.L__aeabi_cdcmple:
+    .word   __aeabi_cdcmple
+.L__aeabi_cfcmple:
+    .word   __aeabi_cfcmple
+
+    .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
new file mode 100644
index 0000000..825ac40
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -0,0 +1,1981 @@
+/*
+ * This file was generated automatically by gen-template.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.
+ */
+
+#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  rSELF     thread 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 rSELF   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
+
+#define EXPORT_PC() \
+    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * 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-vfp/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+
+    .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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+/* ------------------------------ */
+    .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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChain:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChain   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/* ------------------------------ */
+    .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-vfp/TEMPLATE_ADD_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_SUB_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_MUL_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DIV_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_ADD_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_SUB_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_MUL_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DIV_DOUBLE_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_DOUBLE_TO_INT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S */
+/* File: armv5te-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
+     *
+     * 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-vfp/TEMPLATE_FLOAT_TO_INT_VFP.S */
+/* File: armv5te-vfp/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-vfp/TEMPLATE_INT_TO_DOUBLE_VFP.S */
+/* File: armv5te-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
+     *
+     * 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-vfp/TEMPLATE_INT_TO_FLOAT_VFP.S */
+/* File: armv5te-vfp/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-vfp/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
+    fcmpd  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-vfp/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-vfp/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
+    fcmps  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-vfp/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
+    fcmps  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
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP
+dvmCompiler_TEMPLATE_SQRT_DOUBLE_VFP:
+/* File: armv5te-vfp/TEMPLATE_SQRT_DOUBLE_VFP.S */
+    /*
+     * 64-bit floating point vfp sqrt operation.
+     * If the result is a NaN, bail out to library code to do
+     * the right thing.
+     *
+     * On entry:
+     *     r2 src addr of op1
+     * On exit:
+     *     r0,r1 = res
+     */
+    fldd    d0, [r2]
+    fsqrtd  d1, d0
+    fcmpd   d1, d1
+    fmstat
+    fmrrd   r0, r1, d1
+    bxeq    lr   @ Result OK - return
+    ldr     r2, .Lsqrt
+    fmrrd   r0, r1, d0   @ reload orig operand
+    bx      r2   @ tail call to sqrt library routine
+
+.Lsqrt:
+    .word   sqrt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
+dvmCompiler_TEMPLATE_MEM_OP_DECODE:
+/* File: armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S */
+#if defined(WITH_SELF_VERIFICATION)
+    /*
+     * This handler encapsulates heap memory ops for selfVerification mode.
+     *
+     * The call to the handler is inserted prior to a heap memory operation.
+     * This handler then calls a function to decode the memory op, and process
+     * it accordingly. Afterwards, the handler changes the return address to
+     * skip the memory op so it never gets executed.
+     */
+    vpush   {d0-d15}                    @ save out all fp registers
+    push    {r0-r12,lr}                 @ save out all registers
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    blx     r2                          @ decode and handle the mem op
+    pop     {r0-r12,lr}                 @ restore all registers
+    vpop    {d0-d15}                    @ restore all fp registers
+    bx      lr                          @ return to compiled code
+#endif
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_COMPARETO
+dvmCompiler_TEMPLATE_STRING_COMPARETO:
+/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */
+    /*
+     * String's compareTo.
+     *
+     * Requires r0/r1 to have been previously checked for null.  Will
+     * return negative if this's string is < comp, 0 if they are the
+     * same and positive if >.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync with definitions in UtfString.h.  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   this object pointer
+     *    r1:   comp object pointer
+     *
+     */
+
+    mov    r2, r0         @ this to r2, opening up r0 for return value
+    subs   r0, r2, r1     @ Same?
+    bxeq   lr
+
+    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
+    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
+    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
+    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
+    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
+    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    value:  r2/r1
+     *    offset: r4/r9
+     *    count:  r7/r10
+     * We're going to compute
+     *    r11 <- countDiff
+     *    r10 <- minCount
+     */
+     subs  r11, r7, r10
+     movls r10, r7
+
+     /* Now, build pointers to the string data */
+     add   r2, r2, r4, lsl #1
+     add   r1, r1, r9, lsl #1
+     /*
+      * Note: data pointers point to previous element so we can use pre-index
+      * mode with base writeback.
+      */
+     add   r2, #16-2   @ offset to contents[-1]
+     add   r1, #16-2   @ offset to contents[-1]
+
+     /*
+      * At this point we have:
+      *   r2: *this string data
+      *   r1: *comp string data
+      *   r10: iteration count for comparison
+      *   r11: value to return if the first part of the string is equal
+      *   r0: reserved for result
+      *   r3, r4, r7, r8, r9, r12 available for loading string data
+      */
+
+    subs  r10, #2
+    blt   do_remainder2
+
+      /*
+       * Unroll the first two checks so we can quickly catch early mismatch
+       * on long strings (but preserve incoming alignment)
+       */
+
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    bxne  lr
+    cmp   r10, #28
+    bgt   do_memcmp16
+    subs  r10, #3
+    blt   do_remainder
+
+loopback_triple:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    ldrh  r7, [r2, #2]!
+    ldrh  r8, [r1, #2]!
+    ldrh  r9, [r2, #2]!
+    ldrh  r12,[r1, #2]!
+    subs  r0, r3, r4
+    subeqs  r0, r7, r8
+    subeqs  r0, r9, r12
+    bxne  lr
+    subs  r10, #3
+    bge   loopback_triple
+
+do_remainder:
+    adds  r10, #3
+    beq   returnDiff
+
+loopback_single:
+    ldrh  r3, [r2, #2]!
+    ldrh  r4, [r1, #2]!
+    subs  r0, r3, r4
+    bxne  lr
+    subs  r10, #1
+    bne     loopback_single
+
+returnDiff:
+    mov   r0, r11
+    bx    lr
+
+do_remainder2:
+    adds  r10, #2
+    bne   loopback_single
+    mov   r0, r11
+    bx    lr
+
+    /* Long string case */
+do_memcmp16:
+    mov   r4, lr
+    ldr   lr, .Lmemcmp16
+    mov   r7, r11
+    add   r0, r2, #2
+    add   r1, r1, #2
+    mov   r2, r10
+    blx   lr
+    cmp   r0, #0
+    bxne  r4
+    mov   r0, r7
+    bx    r4
+
+.Lmemcmp16:
+    .word __memcmp16
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_STRING_INDEXOF
+dvmCompiler_TEMPLATE_STRING_INDEXOF:
+/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */
+    /*
+     * String's indexOf.
+     *
+     * Requires r0 to have been previously checked for null.  Will
+     * return index of match of r1 in r0.
+     *
+     * IMPORTANT NOTE:
+     *
+     * This code relies on hard-coded offsets for string objects, and must be
+     * kept in sync wth definitions in UtfString.h  See asm-constants.h
+     *
+     * On entry:
+     *    r0:   string object pointer
+     *    r1:   char to match
+     *    r2:   Starting offset in string data
+     */
+
+    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
+    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
+    ldr    r0, [r0, #STRING_FIELDOFF_VALUE]
+
+    /*
+     * At this point, we have:
+     *    r0: object pointer
+     *    r1: char to match
+     *    r2: starting offset
+     *    r7: offset
+     *    r8: string length
+     */
+
+     /* Build pointer to start of string data */
+     add   r0, #16
+     add   r0, r0, r7, lsl #1
+
+     /* Save a copy of starting data in r7 */
+     mov   r7, r0
+
+     /* Clamp start to [0..count] */
+     cmp   r2, #0
+     movlt r2, #0
+     cmp   r2, r8
+     movgt r2, r8
+
+     /* Build pointer to start of data to compare and pre-bias */
+     add   r0, r0, r2, lsl #1
+     sub   r0, #2
+
+     /* Compute iteration count */
+     sub   r8, r2
+
+     /*
+      * At this point we have:
+      *   r0: start of data to test
+      *   r1: chat to compare
+      *   r8: iteration count
+      *   r7: original start of string
+      *   r3, r4, r9, r10, r11, r12 available for loading string data
+      */
+
+    subs  r8, #4
+    blt   indexof_remainder
+
+indexof_loop4:
+    ldrh  r3, [r0, #2]!
+    ldrh  r4, [r0, #2]!
+    ldrh  r10, [r0, #2]!
+    ldrh  r11, [r0, #2]!
+    cmp   r3, r1
+    beq   match_0
+    cmp   r4, r1
+    beq   match_1
+    cmp   r10, r1
+    beq   match_2
+    cmp   r11, r1
+    beq   match_3
+    subs  r8, #4
+    bge   indexof_loop4
+
+indexof_remainder:
+    adds    r8, #4
+    beq     indexof_nomatch
+
+indexof_loop1:
+    ldrh  r3, [r0, #2]!
+    cmp   r3, r1
+    beq   match_3
+    subs  r8, #1
+    bne   indexof_loop1
+
+indexof_nomatch:
+    mov   r0, #-1
+    bx    lr
+
+match_0:
+    sub   r0, #6
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_1:
+    sub   r0, #4
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_2:
+    sub   r0, #2
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+match_3:
+    sub   r0, r7
+    asr   r0, r0, #1
+    bx    lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INTERPRET
+dvmCompiler_TEMPLATE_INTERPRET:
+/* File: armv5te/TEMPLATE_INTERPRET.S */
+    /*
+     * This handler transfers control to the interpeter without performing
+     * any lookups.  It may be called either as part of a normal chaining
+     * operation, or from the transition code in header.S.  We distinquish
+     * the two cases by looking at the link register.  If called from a
+     * translation chain, it will point to the chaining Dalvik PC -3.
+     * On entry:
+     *    lr - if NULL:
+     *        r1 - the Dalvik PC to begin interpretation.
+     *    else
+     *        [lr, #3] contains Dalvik PC to begin interpretation
+     *    rSELF - pointer to thread
+     *    rFP - Dalvik frame pointer
+     */
+    cmp     lr, #0
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     101f
+    ldr     r1,[lr, #3]
+101:
+#else
+    ldrne   r1,[lr, #3]
+#endif
+    ldr     r2, .LinterpPunt
+    mov     r0, r1                       @ set Dalvik PC
+    bx      r2
+    @ doesn't return
+
+.LinterpPunt:
+    .word   dvmJitToInterpPunt
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER
+dvmCompiler_TEMPLATE_MONITOR_ENTER:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER.S */
+    /*
+     * Call out to the runtime to lock an object.  Because this thread
+     * may have been suspended in THREAD_MONITOR state and the Jit's
+     * translation cache subsequently cleared, we cannot return directly.
+     * Instead, unconditionally transition to the interpreter to resume.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2                           @ dvmLockObject(self, obj)
+    ldr     r2, .LdvmJitToInterpNoChain
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    bx      r2
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
+dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
+/* File: armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S */
+    /*
+     * To support deadlock prediction, this version of MONITOR_ENTER
+     * will always call the heavyweight dvmLockObject, check for an
+     * exception and then bail out to the interpreter.
+     *
+     * On entry:
+     *    r0 - self pointer
+     *    r1 - the object (which has already been null-checked by the caller
+     *    r4 - the Dalvik PC of the following instruction.
+     *
+     */
+    ldr     r2, .LdvmLockObject
+    mov     r3, #0                       @ Record that we're not returning
+    str     r3, [r0, #offThread_inJitCodeCache]
+    blx     r2             @ dvmLockObject(self, obj)
+    @ test for exception
+    ldr     r1, [rSELF, #offThread_exception]
+    cmp     r1, #0
+    beq     1f
+    ldr     r2, .LhandleException
+    sub     r0, r4, #2     @ roll dPC back to this monitor instruction
+    bx      r2
+1:
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    ldr     pc, .LdvmJitToInterpNoChain
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_PERIODIC_PROFILING
+dvmCompiler_TEMPLATE_PERIODIC_PROFILING:
+/* File: armv5te/TEMPLATE_PERIODIC_PROFILING.S */
+    /*
+     * Increment profile counter for this trace, and decrement
+     * sample counter.  If sample counter goes below zero, turn
+     * off profiling.
+     *
+     * On entry
+     * (lr-11) is address of pointer to counter.  Note: the counter
+     *    actually exists 10 bytes before the return target, but because
+     *    we are arriving from thumb mode, lr will have its low bit set.
+     */
+     ldr    r0, [lr,#-11]
+     ldr    r1, [rSELF, #offThread_pProfileCountdown]
+     ldr    r2, [r0]                    @ get counter
+     ldr    r3, [r1]                    @ get countdown timer
+     add    r2, #1
+     subs   r2, #1
+     blt    .LTEMPLATE_PERIODIC_PROFILING_disable_profiling
+     str    r2, [r0]
+     str    r3, [r1]
+     bx     lr
+
+.LTEMPLATE_PERIODIC_PROFILING_disable_profiling:
+     mov    r4, lr                     @ preserve lr
+     ldr    r0, .LdvmJitTraceProfilingOff
+     blx    r0
+     bx     r4
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RETURN_PROF
+dvmCompiler_TEMPLATE_RETURN_PROF:
+/* File: armv5te/TEMPLATE_RETURN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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.
+     */
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
+    mov     r0, r6
+    @ r0=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceExit
+    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
+#endif
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#if !defined(WITH_SELF_VERIFICATION)
+    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+#else
+    mov     r9, #0                      @ disable chaining
+#endif
+    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ break frame?
+#if !defined(WITH_SELF_VERIFICATION)
+    beq     1f                          @ bail to interpreter
+#else
+    blxeq   lr                          @ punt to interpreter and compare state
+#endif
+    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rSELF, #offThread_methodClassDex]
+    cmp     r8, #0                      @ check the break flags
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    mov     r0, #0
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
+    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r0, rSELF                   @ Expecting rSELF in r0
+    blx     r2                          @ exit the interpreter
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    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                      @ breakFlags != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     .LinvokeNative
+#else
+    bxne    lr                          @ bail to the interpreter
+#endif
+
+    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
+#endif
+
+    @ Start executing the callee
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kInlineCacheMiss
+#endif
+    mov     pc, r10                         @ dvmJitToInterpTraceSelectNoChain
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* 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, r2 = methodToCall->outsSize
+    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChainProf:
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+
+    @ Update "thread" values for the new method
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
+#if defined(TEMPLATE_INLINE_PROFILING)
+    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
+    mov     r1, r6
+    @ r0=methodToCall, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r2,lr}             @ restore registers
+#endif
+
+    bx      lr                              @ return to the callee-chaining cell
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
+    /*
+     * For polymorphic callsite, check whether the cached class pointer matches
+     * the current one. If so 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.
+     *
+     * The predicted chaining cell is declared in ArmLIR.h with the
+     * following layout:
+     *
+     *  typedef struct PredictedChainingCell {
+     *      u4 branch;
+     *      const ClassObject *clazz;
+     *      const Method *method;
+     *      u4 counter;
+     *  } PredictedChainingCell;
+     *
+     * Upon returning to the callsite:
+     *    - lr  : to branch to the chaining cell
+     *    - lr+2: to punt to the interpreter
+     *    - lr+4: to fully resolve the callee and may rechain.
+     *            r3 <- class
+     *            r9 <- counter
+     */
+    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
+    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
+    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
+    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
+    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
+    cmp     r3, r8          @ predicted class == actual class?
+#if defined(WITH_JIT_TUNING)
+    ldr     r7, .LdvmICHitCount
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    bne     101f
+    ldr     r10, [r7, #0]
+101:
+#else
+    ldreq   r10, [r7, #0]
+#endif
+    add     r10, r10, #1
+    streq   r10, [r7, #0]
+#endif
+    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    beq     .LinvokeChainProf   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    cmp     r8, #0          @ initialized class or not
+    moveq   r1, #0
+    subne   r1, r9, #1      @ count--
+    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
+    add     lr, lr, #4      @ return to fully-resolve landing pad
+    /*
+     * r1 <- count
+     * r2 <- &predictedChainCell
+     * r3 <- this->class
+     * r4 <- dPC
+     * r7 <- this->class->vtable
+     */
+    bx      lr
+
+#undef TEMPLATE_INLINE_PROFILING
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S */
+#define TEMPLATE_INLINE_PROFILING
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    @ r7 = methodToCall->registersSize
+    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
+    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
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlo    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ breakFlags != 0
+    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    lr                          @ bail to the interpreter
+#else
+    bx      lr                          @ bail to interpreter unconditionally
+#endif
+
+    @ go ahead and transfer control to the native code
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    mov     r2, #0
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                        @ arg2<- methodToCall
+    mov     r0, r1                        @ arg0<- newFP
+    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
+    mov     r3, rSELF                     @ arg3<- self
+#if defined(TEMPLATE_INLINE_PROFILING)
+    @ r2=methodToCall, r6=rSELF
+    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    mov     r0, r2
+    mov     r1, r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+#endif
+
+    blx     r8                          @ off to the native code
+
+#if defined(TEMPLATE_INLINE_PROFILING)
+    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
+    @ r0=JNIMethod, r1=rSELF
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+#endif
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+#undef TEMPLATE_INLINE_PROFILING
+
+    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+.LinvokeNative:
+    @ Prep for the native call
+    @ r1 = newFP, r0 = methodToCall
+    mov     r2, #0
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in jit code cache
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+    ands    lr, #kSubModeMethodTrace
+    beq     121f                        @ hop if not profiling
+    @ r2: methodToCall, r6: rSELF
+    stmfd   sp!, {r2,r6}
+    stmfd   sp!, {r0-r3}
+    mov     r0, r2
+    mov     r1, r6
+    mov     lr, pc
+    ldr     pc, .LdvmFastMethodTraceEnter
+    ldmfd   sp!, {r0-r3}
+
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+
+    ldmfd   sp!, {r0-r1}
+    mov     lr, pc
+    ldr     pc, .LdvmFastNativeMethodTraceExit
+    b       212f
+121:
+    mov     lr, pc
+    ldr     pc, [r2, #offMethod_nativeFunc]
+212:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the new mode
+    cmp     r2, #0                      @ return chaining cell still exists?
+    bxne    r2                          @ yes - go ahead
+
+    @ continue executing the next instruction through the interpreter
+    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
+    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
+#if defined(WITH_JIT_TUNING)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
+.LhandleException:
+#if defined(WITH_SELF_VERIFICATION)
+    ldr     pc, .LdeadFood @ should not see this under self-verification mode
+.LdeadFood:
+    .word   0xdeadf00d
+#endif
+    mov     r2, #0
+    str     r2, [rSELF, #offThread_inJitCodeCache] @ in interpreter land
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
+
+    .align  2
+.LdvmAsmInstructionStart:
+    .word   dvmAsmInstructionStart
+.LdvmJitToInterpNoChainNoProfile:
+    .word   dvmJitToInterpNoChainNoProfile
+.LdvmJitToInterpTraceSelectNoChain:
+    .word   dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+    .word   dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+    .word   dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+    .word   dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+    .word   dvmLockObject
+.LdvmJitTraceProfilingOff:
+    .word   dvmJitTraceProfilingOff
+#if defined(WITH_JIT_TUNING)
+.LdvmICHitCount:
+    .word   gDvmICHitCount
+#endif
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
+.LdvmFastMethodTraceEnter:
+    .word   dvmFastMethodTraceEnter
+.LdvmFastNativeMethodTraceExit:
+    .word   dvmFastNativeMethodTraceExit
+.LdvmFastMethodTraceExit:
+    .word   dvmFastMethodTraceExit
+.L__aeabi_cdcmple:
+    .word   __aeabi_cdcmple
+.L__aeabi_cfcmple:
+    .word   __aeabi_cfcmple
+
+    .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-ia32.S b/vm/compiler/template/out/CompilerTemplateAsm-ia32.S
new file mode 100644
index 0000000..4e86d09
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-ia32.S
@@ -0,0 +1,113 @@
+/*
+ * This file was generated automatically by gen-template.py for 'ia32'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: ia32/header.S */
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(WITH_JIT)
+
+/* Subset of defines from mterp/x86/header.S */
+#define rSELF (%ebp)
+#define rPC   %esi
+#define rFP   %edi
+#define rINST %ebx
+
+/*
+ * 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: ia32/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines and utility
+ * ===========================================================================
+ */
+
+
+
+
+    .global dvmCompilerTemplateStart
+    .type   dvmCompilerTemplateStart, %function
+    .text
+
+dvmCompilerTemplateStart:
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INTERPRET
+dvmCompiler_TEMPLATE_INTERPRET:
+/* File: ia32/TEMPLATE_INTERPRET.S */
+    /*
+     * This handler is a bit odd - it may be called via chaining or
+     * from static code and is expected to cause control to flow
+     * to the interpreter.  The problem is where to find the Dalvik
+     * PC of the next instruction.  When called via chaining, the dPC
+     * will be located at *rp.  When called from static code, rPC is
+     * valid and rp is a real return pointer (that should be ignored).
+     * The Arm target deals with this by using the link register as
+     * a flag.  If it is zero, we know we were called from static code.
+     * If non-zero, it points to the chain cell containing dPC.
+     * For x86, we'll infer the source by looking where rp points.
+     * If it points to anywhere within the code cache, we'll assume
+     * we got here via chaining.  Otherwise, we'll assume rPC is valid.
+     *
+     * On entry:
+     *    (TOS)<- return pointer or pointer to dPC
+     */
+
+/*
+ * FIXME - this won't work as-is.  The cache boundaries are not
+ * set up until later.  Perhaps rething this whole thing.  Do we
+ * really need an interpret teplate?
+ */
+
+
+     movl   rSELF,%ecx
+     movl   $.LinterpPunt,%edx
+     pop    %eax
+     /*cmpl   %eax,offThread_jitCacheEnd(%ecx)*/
+     ja     1f
+     /*cmpl   %eax,offThread_jitCacheStart(%ecx)*/
+     jb     1f
+     movl   %eax,rPC
+1:
+     jmp    *(%edx)
+
+.LinterpPunt:
+    .long   dvmJitToInterpPunt
+
+    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: ia32/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  4
+
+    .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..f04d097
--- /dev/null
+++ b/vm/compiler/template/rebuild.sh
@@ -0,0 +1,22 @@
+#!/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 ia32 armv5te armv5te-vfp armv7-a armv7-a-neon; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
diff --git a/vm/dalvik b/vm/dalvik
new file mode 100644
index 0000000..5569db9
--- /dev/null
+++ b/vm/dalvik
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (C) 2011 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.
+
+mkdir -p /tmp/android-data/dalvik-cache
+ANDROID_PRINTF_LOG=tag \
+ANDROID_LOG_TAGS="" \
+ANDROID_DATA=/tmp/android-data \
+ANDROID_ROOT=$ANDROID_BUILD_TOP/out/host/linux-x86 \
+LD_LIBRARY_PATH=$ANDROID_BUILD_TOP/out/host/linux-x86/lib \
+$ANDROID_BUILD_TOP/out/host/linux-x86/bin/dalvikvm \
+-Xbootclasspath\
+:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-hostdex.jar\
+:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/bouncycastle-hostdex.jar\
+:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/apache-xml-hostdex.jar \
+$*
+
diff --git a/vm/hprof/Hprof.cpp b/vm/hprof/Hprof.cpp
new file mode 100644
index 0000000..4a6b1a6
--- /dev/null
+++ b/vm/hprof/Hprof.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ */
+
+/*
+ * Preparation and completion of hprof data generation.  The output is
+ * written into two files and then combined.  This is necessary because
+ * we generate some of the data (strings and classes) while we dump the
+ * heap, and some analysis tools require that the class and string data
+ * appear first.
+ */
+
+#include "Hprof.h"
+#include "alloc/HeapInternal.h"
+#include "alloc/Visit.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define kHeadSuffix "-hptemp"
+
+hprof_context_t* hprofStartup(const char *outputFileName, int fd,
+                              bool directToDdms)
+{
+    hprofStartup_String();
+    hprofStartup_Class();
+
+    hprof_context_t *ctx = (hprof_context_t *)malloc(sizeof(*ctx));
+    if (ctx == NULL) {
+        LOGE("hprof: can't allocate context.");
+        return NULL;
+    }
+
+    /* pass in name or descriptor of the output file */
+    hprofContextInit(ctx, strdup(outputFileName), fd, false, directToDdms);
+
+    assert(ctx->memFp != NULL);
+
+    return ctx;
+}
+
+/*
+ * Finish up the hprof dump.  Returns true on success.
+ */
+bool hprofShutdown(hprof_context_t *tailCtx)
+{
+    /* flush the "tail" portion of the output */
+    hprofFlushCurrentRecord(tailCtx);
+
+    /*
+     * Create a new context struct for the start of the file.  We
+     * heap-allocate it so we can share the "free" function.
+     */
+    hprof_context_t *headCtx = (hprof_context_t *)malloc(sizeof(*headCtx));
+    if (headCtx == NULL) {
+        LOGE("hprof: can't allocate context.");
+        hprofFreeContext(tailCtx);
+        return false;
+    }
+    hprofContextInit(headCtx, strdup(tailCtx->fileName), tailCtx->fd, true,
+        tailCtx->directToDdms);
+
+    LOGI("hprof: dumping heap strings to \"%s\".", tailCtx->fileName);
+    hprofDumpStrings(headCtx);
+    hprofDumpClasses(headCtx);
+
+    /* Write a dummy stack trace record so the analysis
+     * tools don't freak out.
+     */
+    hprofStartNewRecord(headCtx, HPROF_TAG_STACK_TRACE, HPROF_TIME);
+    hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_STACK_TRACE);
+    hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_THREAD);
+    hprofAddU4ToRecord(&headCtx->curRec, 0);    // no frames
+
+    hprofFlushCurrentRecord(headCtx);
+
+    hprofShutdown_Class();
+    hprofShutdown_String();
+
+    /* flush to ensure memstream pointer and size are updated */
+    fflush(headCtx->memFp);
+    fflush(tailCtx->memFp);
+
+    if (tailCtx->directToDdms) {
+        /* send the data off to DDMS */
+        struct iovec iov[2];
+        iov[0].iov_base = headCtx->fileDataPtr;
+        iov[0].iov_len = headCtx->fileDataSize;
+        iov[1].iov_base = tailCtx->fileDataPtr;
+        iov[1].iov_len = tailCtx->fileDataSize;
+        dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
+    } else {
+        /*
+         * Open the output file, and copy the head and tail to it.
+         */
+        assert(headCtx->fd == tailCtx->fd);
+
+        int outFd;
+        if (headCtx->fd >= 0) {
+            outFd = dup(headCtx->fd);
+            if (outFd < 0) {
+                LOGE("dup(%d) failed: %s", headCtx->fd, strerror(errno));
+                /* continue to fail-handler below */
+            }
+        } else {
+            outFd = open(tailCtx->fileName, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+            if (outFd < 0) {
+                LOGE("can't open %s: %s", headCtx->fileName, strerror(errno));
+                /* continue to fail-handler below */
+            }
+        }
+        if (outFd < 0) {
+            hprofFreeContext(headCtx);
+            hprofFreeContext(tailCtx);
+            return false;
+        }
+
+        int result;
+        result = sysWriteFully(outFd, headCtx->fileDataPtr,
+            headCtx->fileDataSize, "hprof-head");
+        result |= sysWriteFully(outFd, tailCtx->fileDataPtr,
+            tailCtx->fileDataSize, "hprof-tail");
+        close(outFd);
+        if (result != 0) {
+            hprofFreeContext(headCtx);
+            hprofFreeContext(tailCtx);
+            return false;
+        }
+    }
+
+    /* throw out a log message for the benefit of "runhat" */
+    LOGI("hprof: heap dump completed (%dKB)",
+        (headCtx->fileDataSize + tailCtx->fileDataSize + 1023) / 1024);
+
+    hprofFreeContext(headCtx);
+    hprofFreeContext(tailCtx);
+
+    return true;
+}
+
+/*
+ * Free any heap-allocated items in "ctx", and then free "ctx" itself.
+ */
+void hprofFreeContext(hprof_context_t *ctx)
+{
+    assert(ctx != NULL);
+
+    /* we don't own ctx->fd, do not close */
+
+    if (ctx->memFp != NULL)
+        fclose(ctx->memFp);
+    free(ctx->curRec.body);
+    free(ctx->fileName);
+    free(ctx->fileDataPtr);
+    free(ctx);
+}
+
+/*
+ * Visitor invoked on every root reference.
+ */
+static void hprofRootVisitor(void *addr, u4 threadId, RootType type, void *arg)
+{
+    static const hprof_heap_tag_t xlate[] = {
+        HPROF_ROOT_UNKNOWN,
+        HPROF_ROOT_JNI_GLOBAL,
+        HPROF_ROOT_JNI_LOCAL,
+        HPROF_ROOT_JAVA_FRAME,
+        HPROF_ROOT_NATIVE_STACK,
+        HPROF_ROOT_STICKY_CLASS,
+        HPROF_ROOT_THREAD_BLOCK,
+        HPROF_ROOT_MONITOR_USED,
+        HPROF_ROOT_THREAD_OBJECT,
+        HPROF_ROOT_INTERNED_STRING,
+        HPROF_ROOT_FINALIZING,
+        HPROF_ROOT_DEBUGGER,
+        HPROF_ROOT_REFERENCE_CLEANUP,
+        HPROF_ROOT_VM_INTERNAL,
+        HPROF_ROOT_JNI_MONITOR,
+    };
+    hprof_context_t *ctx;
+    Object *obj;
+
+    assert(addr != NULL);
+    assert(arg != NULL);
+    assert(type < NELEM(xlate));
+    obj = *(Object **)addr;
+    if (obj == NULL) {
+        return;
+    }
+    ctx = (hprof_context_t *)arg;
+    ctx->gcScanState = xlate[type];
+    ctx->gcThreadSerialNumber = threadId;
+    hprofMarkRootObject(ctx, obj, 0);
+    ctx->gcScanState = 0;
+    ctx->gcThreadSerialNumber = 0;
+}
+
+/*
+ * Visitor invoked on every heap object.
+ */
+static void hprofBitmapCallback(Object *obj, void *arg)
+{
+    assert(obj != NULL);
+    assert(arg != NULL);
+    hprof_context_t *ctx = (hprof_context_t *)arg;
+    hprofDumpHeapObject(ctx, obj);
+}
+
+/*
+ * Walk the roots and heap writing heap information to the specified
+ * file.
+ *
+ * If "fd" is >= 0, the output will be written to that file descriptor.
+ * Otherwise, "fileName" is used to create an output file.
+ *
+ * If "directToDdms" is set, the other arguments are ignored, and data is
+ * sent directly to DDMS.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
+int hprofDumpHeap(const char* fileName, int fd, bool directToDdms)
+{
+    hprof_context_t *ctx;
+    int success;
+
+    assert(fileName != NULL);
+    dvmLockHeap();
+    dvmSuspendAllThreads(SUSPEND_FOR_HPROF);
+    ctx = hprofStartup(fileName, fd, directToDdms);
+    if (ctx == NULL) {
+        return -1;
+    }
+    dvmVisitRoots(hprofRootVisitor, ctx);
+    dvmHeapBitmapWalk(dvmHeapSourceGetLiveBits(), hprofBitmapCallback, ctx);
+    hprofFinishHeapDump(ctx);
+//TODO: write a HEAP_SUMMARY record
+    success = hprofShutdown(ctx) ? 0 : -1;
+    dvmResumeAllThreads(SUSPEND_FOR_HPROF);
+    dvmUnlockHeap();
+    return success;
+}
diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h
new file mode 100644
index 0000000..3ee8c61
--- /dev/null
+++ b/vm/hprof/Hprof.h
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+#ifndef DALVIK_HPROF_HPROF_H_
+#define DALVIK_HPROF_HPROF_H_
+
+#include "Dalvik.h"
+
+#define HPROF_ID_SIZE (sizeof (u4))
+
+#define UNIQUE_ERROR() \
+    -((((uintptr_t)__func__) << 16 | __LINE__) & (0x7fffffff))
+
+#define HPROF_TIME 0
+#define HPROF_NULL_STACK_TRACE   0
+#define HPROF_NULL_THREAD        0
+
+typedef u4 hprof_id;
+typedef hprof_id hprof_string_id;
+typedef hprof_id hprof_object_id;
+typedef hprof_id hprof_class_object_id;
+
+enum hprof_basic_type {
+    hprof_basic_object = 2,
+    hprof_basic_boolean = 4,
+    hprof_basic_char = 5,
+    hprof_basic_float = 6,
+    hprof_basic_double = 7,
+    hprof_basic_byte = 8,
+    hprof_basic_short = 9,
+    hprof_basic_int = 10,
+    hprof_basic_long = 11,
+};
+
+enum hprof_tag_t {
+    HPROF_TAG_STRING = 0x01,
+    HPROF_TAG_LOAD_CLASS = 0x02,
+    HPROF_TAG_UNLOAD_CLASS = 0x03,
+    HPROF_TAG_STACK_FRAME = 0x04,
+    HPROF_TAG_STACK_TRACE = 0x05,
+    HPROF_TAG_ALLOC_SITES = 0x06,
+    HPROF_TAG_HEAP_SUMMARY = 0x07,
+    HPROF_TAG_START_THREAD = 0x0A,
+    HPROF_TAG_END_THREAD = 0x0B,
+    HPROF_TAG_HEAP_DUMP = 0x0C,
+    HPROF_TAG_HEAP_DUMP_SEGMENT = 0x1C,
+    HPROF_TAG_HEAP_DUMP_END = 0x2C,
+    HPROF_TAG_CPU_SAMPLES = 0x0D,
+    HPROF_TAG_CONTROL_SETTINGS = 0x0E,
+};
+
+/* Values for the first byte of
+ * HEAP_DUMP and HEAP_DUMP_SEGMENT
+ * records:
+ */
+enum hprof_heap_tag_t {
+    /* standard */
+    HPROF_ROOT_UNKNOWN = 0xFF,
+    HPROF_ROOT_JNI_GLOBAL = 0x01,
+    HPROF_ROOT_JNI_LOCAL = 0x02,
+    HPROF_ROOT_JAVA_FRAME = 0x03,
+    HPROF_ROOT_NATIVE_STACK = 0x04,
+    HPROF_ROOT_STICKY_CLASS = 0x05,
+    HPROF_ROOT_THREAD_BLOCK = 0x06,
+    HPROF_ROOT_MONITOR_USED = 0x07,
+    HPROF_ROOT_THREAD_OBJECT = 0x08,
+    HPROF_CLASS_DUMP = 0x20,
+    HPROF_INSTANCE_DUMP = 0x21,
+    HPROF_OBJECT_ARRAY_DUMP = 0x22,
+    HPROF_PRIMITIVE_ARRAY_DUMP = 0x23,
+
+    /* Android */
+    HPROF_HEAP_DUMP_INFO = 0xfe,
+    HPROF_ROOT_INTERNED_STRING = 0x89,
+    HPROF_ROOT_FINALIZING = 0x8a,  /* obsolete */
+    HPROF_ROOT_DEBUGGER = 0x8b,
+    HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,  /* obsolete */
+    HPROF_ROOT_VM_INTERNAL = 0x8d,
+    HPROF_ROOT_JNI_MONITOR = 0x8e,
+    HPROF_UNREACHABLE = 0x90,  /* obsolete */
+    HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
+};
+
+/* Represents a top-level hprof record, whose serialized
+ * format is:
+ *
+ *     u1     TAG: denoting the type of the record
+ *     u4     TIME: number of microseconds since the time stamp in the header
+ *     u4     LENGTH: number of bytes that follow this u4 field
+ *                    and belong to this record
+ *     [u1]*  BODY: as many bytes as specified in the above u4 field
+ */
+struct hprof_record_t {
+    unsigned char *body;
+    u4 time;
+    u4 length;
+    size_t allocLen;
+    u1 tag;
+    bool dirty;
+};
+
+enum HprofHeapId {
+    HPROF_HEAP_DEFAULT = 0,
+    HPROF_HEAP_ZYGOTE = 'Z',
+    HPROF_HEAP_APP = 'A'
+};
+
+struct hprof_context_t {
+    /* curRec *must* be first so that we
+     * can cast from a context to a record.
+     */
+    hprof_record_t curRec;
+
+    u4 gcThreadSerialNumber;
+    u1 gcScanState;
+    HprofHeapId currentHeap;    // which heap we're currently emitting
+    u4 stackTraceSerialNumber;
+    size_t objectsInSegment;
+
+    /*
+     * If directToDdms is set, "fileName" and "fd" will be ignored.
+     * Otherwise, "fileName" must be valid, though if "fd" >= 0 it will
+     * only be used for debug messages.
+     */
+    bool directToDdms;
+    char *fileName;
+    char *fileDataPtr;          // for open_memstream
+    size_t fileDataSize;        // for open_memstream
+    FILE *memFp;
+    int fd;
+};
+
+
+/*
+ * HprofString.cpp functions
+ */
+
+hprof_string_id hprofLookupStringId(const char *str);
+
+int hprofDumpStrings(hprof_context_t *ctx);
+
+int hprofStartup_String(void);
+int hprofShutdown_String(void);
+
+
+/*
+ * HprofClass.cpp functions
+ */
+
+hprof_class_object_id hprofLookupClassId(const ClassObject *clazz);
+
+int hprofDumpClasses(hprof_context_t *ctx);
+
+int hprofStartup_Class(void);
+int hprofShutdown_Class(void);
+
+
+/*
+ * HprofHeap.cpp functions
+ */
+
+int hprofStartHeapDump(hprof_context_t *ctx);
+int hprofFinishHeapDump(hprof_context_t *ctx);
+
+int hprofSetGcScanState(hprof_context_t *ctx,
+                        hprof_heap_tag_t state, u4 threadSerialNumber);
+int hprofMarkRootObject(hprof_context_t *ctx,
+                        const Object *obj, jobject jniObj);
+
+int hprofDumpHeapObject(hprof_context_t *ctx, const Object *obj);
+
+/*
+ * HprofOutput.cpp functions
+ */
+
+void hprofContextInit(hprof_context_t *ctx, char *fileName, int fd,
+                      bool writeHeader, bool directToDdms);
+
+int hprofFlushRecord(hprof_record_t *rec, FILE *fp);
+int hprofFlushCurrentRecord(hprof_context_t *ctx);
+int hprofStartNewRecord(hprof_context_t *ctx, u1 tag, u4 time);
+
+int hprofAddU1ToRecord(hprof_record_t *rec, u1 value);
+int hprofAddU1ListToRecord(hprof_record_t *rec,
+                           const u1 *values, size_t numValues);
+
+int hprofAddUtf8StringToRecord(hprof_record_t *rec, const char *str);
+
+int hprofAddU2ToRecord(hprof_record_t *rec, u2 value);
+int hprofAddU2ListToRecord(hprof_record_t *rec,
+                           const u2 *values, size_t numValues);
+
+int hprofAddU4ToRecord(hprof_record_t *rec, u4 value);
+int hprofAddU4ListToRecord(hprof_record_t *rec,
+                           const u4 *values, size_t numValues);
+
+int hprofAddU8ToRecord(hprof_record_t *rec, u8 value);
+int hprofAddU8ListToRecord(hprof_record_t *rec,
+                           const u8 *values, size_t numValues);
+
+#define hprofAddIdToRecord(rec, id) hprofAddU4ToRecord((rec), (u4)(id))
+#define hprofAddIdListToRecord(rec, values, numValues) \
+            hprofAddU4ListToRecord((rec), (const u4 *)(values), (numValues))
+
+/*
+ * Hprof.cpp functions
+ */
+
+hprof_context_t* hprofStartup(const char *outputFileName, int fd,
+    bool directToDdms);
+bool hprofShutdown(hprof_context_t *ctx);
+void hprofFreeContext(hprof_context_t *ctx);
+int hprofDumpHeap(const char* fileName, int fd, bool directToDdms);
+
+#endif  // DALVIK_HPROF_HPROF_H_
diff --git a/vm/hprof/HprofClass.cpp b/vm/hprof/HprofClass.cpp
new file mode 100644
index 0000000..023efdb
--- /dev/null
+++ b/vm/hprof/HprofClass.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+/*
+ * Class object pool
+ */
+
+#include "Hprof.h"
+
+static HashTable *gClassHashTable;
+
+int hprofStartup_Class()
+{
+    gClassHashTable = dvmHashTableCreate(128, NULL);
+    if (gClassHashTable == NULL) {
+        return UNIQUE_ERROR();
+    }
+    return 0;
+}
+
+int hprofShutdown_Class()
+{
+    dvmHashTableFree(gClassHashTable);
+
+    return 0;
+}
+
+static u4 computeClassHash(const ClassObject *clazz)
+{
+    u4 hash;
+    const char *cp;
+    char c;
+
+    cp = clazz->descriptor;
+    hash = (u4)clazz->classLoader;
+    while ((c = *cp++) != '\0') {
+        hash = hash * 31 + c;
+    }
+
+    return hash;
+}
+
+static int classCmp(const void *v1, const void *v2)
+{
+    const ClassObject *c1 = (const ClassObject *)v1;
+    const ClassObject *c2 = (const ClassObject *)v2;
+    intptr_t diff;
+
+    diff = (uintptr_t)c1->classLoader - (uintptr_t)c2->classLoader;
+    if (diff == 0) {
+        return strcmp(c1->descriptor, c2->descriptor);
+    }
+    return diff;
+}
+
+static int getPrettyClassNameId(const char *descriptor) {
+    std::string name(dvmHumanReadableDescriptor(descriptor));
+    return hprofLookupStringId(name.c_str());
+}
+
+hprof_class_object_id hprofLookupClassId(const ClassObject *clazz)
+{
+    void *val;
+
+    if (clazz == NULL) {
+        /* Someone's probably looking up the superclass
+         * of java.lang.Object or of a primitive class.
+         */
+        return (hprof_class_object_id)0;
+    }
+
+    dvmHashTableLock(gClassHashTable);
+
+    /* We're using the hash table as a list.
+     * TODO: replace the hash table with a more suitable structure
+     */
+    val = dvmHashTableLookup(gClassHashTable, computeClassHash(clazz),
+            (void *)clazz, classCmp, true);
+    assert(val != NULL);
+
+    dvmHashTableUnlock(gClassHashTable);
+
+    /* Make sure that the class's name is in the string table.
+     * This is a bunch of extra work that we only have to do
+     * because of the order of tables in the output file
+     * (strings need to be dumped before classes).
+     */
+    getPrettyClassNameId(clazz->descriptor);
+
+    return (hprof_class_object_id)clazz;
+}
+
+int hprofDumpClasses(hprof_context_t *ctx)
+{
+    HashIter iter;
+    hprof_record_t *rec = &ctx->curRec;
+    int err;
+
+    dvmHashTableLock(gClassHashTable);
+
+    for (err = 0, dvmHashIterBegin(gClassHashTable, &iter);
+         err == 0 && !dvmHashIterDone(&iter);
+         dvmHashIterNext(&iter))
+    {
+        err = hprofStartNewRecord(ctx, HPROF_TAG_LOAD_CLASS, HPROF_TIME);
+        if (err == 0) {
+            const ClassObject *clazz;
+
+            clazz = (const ClassObject *)dvmHashIterData(&iter);
+            assert(clazz != NULL);
+
+            /* LOAD CLASS format:
+             *
+             * u4:     class serial number (always > 0)
+             * ID:     class object ID
+             * u4:     stack trace serial number
+             * ID:     class name string ID
+             *
+             * We use the address of the class object structure as its ID.
+             */
+            hprofAddU4ToRecord(rec, clazz->serialNumber);
+            hprofAddIdToRecord(rec, (hprof_class_object_id)clazz);
+            hprofAddU4ToRecord(rec, HPROF_NULL_STACK_TRACE);
+            hprofAddIdToRecord(rec, getPrettyClassNameId(clazz->descriptor));
+        }
+    }
+
+    dvmHashTableUnlock(gClassHashTable);
+
+    return err;
+}
diff --git a/vm/hprof/HprofHeap.cpp b/vm/hprof/HprofHeap.cpp
new file mode 100644
index 0000000..40e773b
--- /dev/null
+++ b/vm/hprof/HprofHeap.cpp
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+/*
+ * Heap object dump
+ */
+#include "Hprof.h"
+
+/* Set DUMP_PRIM_DATA to 1 if you want to include the contents
+ * of primitive arrays (byte arrays, character arrays, etc.)
+ * in heap dumps.  This can be a large amount of data.
+ */
+#define DUMP_PRIM_DATA 1
+
+#define OBJECTS_PER_SEGMENT     ((size_t)128)
+#define BYTES_PER_SEGMENT       ((size_t)4096)
+
+/* The static field-name for the synthetic object generated to account
+ * for class Static overhead.
+ */
+#define STATIC_OVERHEAD_NAME    "$staticOverhead"
+/* The ID for the synthetic object generated to account for class
+ * Static overhead.
+ */
+#define CLASS_STATICS_ID(clazz) ((hprof_object_id)(((u4)(clazz)) | 1))
+
+int hprofStartHeapDump(hprof_context_t *ctx)
+{
+    UNUSED_PARAMETER(ctx);
+
+    ctx->objectsInSegment = OBJECTS_PER_SEGMENT;
+    ctx->currentHeap = HPROF_HEAP_DEFAULT;
+    return 0;
+}
+
+int hprofFinishHeapDump(hprof_context_t *ctx)
+{
+    return hprofStartNewRecord(ctx, HPROF_TAG_HEAP_DUMP_END, HPROF_TIME);
+}
+
+int hprofSetGcScanState(hprof_context_t *ctx,
+                        hprof_heap_tag_t state,
+                        u4 threadSerialNumber)
+{
+    /* Used by hprofMarkRootObject()
+     */
+    ctx->gcScanState = state;
+    ctx->gcThreadSerialNumber = threadSerialNumber;
+    return 0;
+}
+
+static hprof_basic_type signatureToBasicTypeAndSize(const char *sig,
+                                                    size_t *sizeOut)
+{
+    char c = sig[0];
+    hprof_basic_type ret;
+    size_t size;
+
+    switch (c) {
+    case '[':
+    case 'L': ret = hprof_basic_object;  size = 4; break;
+    case 'Z': ret = hprof_basic_boolean; size = 1; break;
+    case 'C': ret = hprof_basic_char;    size = 2; break;
+    case 'F': ret = hprof_basic_float;   size = 4; break;
+    case 'D': ret = hprof_basic_double;  size = 8; break;
+    case 'B': ret = hprof_basic_byte;    size = 1; break;
+    case 'S': ret = hprof_basic_short;   size = 2; break;
+    default: assert(false);
+    case 'I': ret = hprof_basic_int;     size = 4; break;
+    case 'J': ret = hprof_basic_long;    size = 8; break;
+    }
+
+    if (sizeOut != NULL) {
+        *sizeOut = size;
+    }
+
+    return ret;
+}
+
+static hprof_basic_type primitiveToBasicTypeAndSize(PrimitiveType prim,
+                                                    size_t *sizeOut)
+{
+    hprof_basic_type ret;
+    size_t size;
+
+    switch (prim) {
+    case PRIM_BOOLEAN: ret = hprof_basic_boolean; size = 1; break;
+    case PRIM_CHAR:    ret = hprof_basic_char;    size = 2; break;
+    case PRIM_FLOAT:   ret = hprof_basic_float;   size = 4; break;
+    case PRIM_DOUBLE:  ret = hprof_basic_double;  size = 8; break;
+    case PRIM_BYTE:    ret = hprof_basic_byte;    size = 1; break;
+    case PRIM_SHORT:   ret = hprof_basic_short;   size = 2; break;
+    default: assert(false);
+    case PRIM_INT:     ret = hprof_basic_int;     size = 4; break;
+    case PRIM_LONG:    ret = hprof_basic_long;    size = 8; break;
+    }
+
+    if (sizeOut != NULL) {
+        *sizeOut = size;
+    }
+
+    return ret;
+}
+
+/* Always called when marking objects, but only does
+ * something when ctx->gcScanState is non-zero, which is usually
+ * only true when marking the root set or unreachable
+ * objects.  Used to add rootset references to obj.
+ */
+int hprofMarkRootObject(hprof_context_t *ctx, const Object *obj, jobject jniObj)
+{
+    hprof_record_t *rec = &ctx->curRec;
+    int err;
+    hprof_heap_tag_t heapTag = (hprof_heap_tag_t)ctx->gcScanState;
+
+    if (heapTag == 0) {
+        return 0;
+    }
+
+    if (ctx->objectsInSegment >= OBJECTS_PER_SEGMENT ||
+        rec->length >= BYTES_PER_SEGMENT)
+    {
+        /* This flushes the old segment and starts a new one.
+         */
+        hprofStartNewRecord(ctx, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
+        ctx->objectsInSegment = 0;
+    }
+
+    switch (heapTag) {
+    /* ID: object ID
+     */
+    case HPROF_ROOT_UNKNOWN:
+    case HPROF_ROOT_STICKY_CLASS:
+    case HPROF_ROOT_MONITOR_USED:
+    case HPROF_ROOT_INTERNED_STRING:
+    case HPROF_ROOT_FINALIZING:
+    case HPROF_ROOT_DEBUGGER:
+    case HPROF_ROOT_REFERENCE_CLEANUP:
+    case HPROF_ROOT_VM_INTERNAL:
+        hprofAddU1ToRecord(rec, heapTag);
+        hprofAddIdToRecord(rec, (hprof_object_id)obj);
+        break;
+
+    /* ID: object ID
+     * ID: JNI global ref ID
+     */
+    case HPROF_ROOT_JNI_GLOBAL:
+        hprofAddU1ToRecord(rec, heapTag);
+        hprofAddIdToRecord(rec, (hprof_object_id)obj);
+        hprofAddIdToRecord(rec, (hprof_id)jniObj);
+        break;
+
+    /* ID: object ID
+     * u4: thread serial number
+     * u4: frame number in stack trace (-1 for empty)
+     */
+    case HPROF_ROOT_JNI_LOCAL:
+    case HPROF_ROOT_JNI_MONITOR:
+    case HPROF_ROOT_JAVA_FRAME:
+        hprofAddU1ToRecord(rec, heapTag);
+        hprofAddIdToRecord(rec, (hprof_object_id)obj);
+        hprofAddU4ToRecord(rec, ctx->gcThreadSerialNumber);
+        hprofAddU4ToRecord(rec, (u4)-1);
+        break;
+
+    /* ID: object ID
+     * u4: thread serial number
+     */
+    case HPROF_ROOT_NATIVE_STACK:
+    case HPROF_ROOT_THREAD_BLOCK:
+        hprofAddU1ToRecord(rec, heapTag);
+        hprofAddIdToRecord(rec, (hprof_object_id)obj);
+        hprofAddU4ToRecord(rec, ctx->gcThreadSerialNumber);
+        break;
+
+    /* ID: thread object ID
+     * u4: thread serial number
+     * u4: stack trace serial number
+     */
+    case HPROF_ROOT_THREAD_OBJECT:
+        hprofAddU1ToRecord(rec, heapTag);
+        hprofAddIdToRecord(rec, (hprof_object_id)obj);
+        hprofAddU4ToRecord(rec, ctx->gcThreadSerialNumber);
+        hprofAddU4ToRecord(rec, (u4)-1);    //xxx
+        break;
+
+    default:
+        err = 0;
+        break;
+    }
+
+    ctx->objectsInSegment++;
+
+    return err;
+}
+
+static int stackTraceSerialNumber(const void *obj)
+{
+    return HPROF_NULL_STACK_TRACE;
+}
+
+int hprofDumpHeapObject(hprof_context_t *ctx, const Object *obj)
+{
+    const ClassObject *clazz;
+    hprof_record_t *rec = &ctx->curRec;
+    HprofHeapId desiredHeap;
+
+    desiredHeap = dvmIsZygoteObject(obj) ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP;
+
+    if (ctx->objectsInSegment >= OBJECTS_PER_SEGMENT ||
+        rec->length >= BYTES_PER_SEGMENT)
+    {
+        /* This flushes the old segment and starts a new one.
+         */
+        hprofStartNewRecord(ctx, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
+        ctx->objectsInSegment = 0;
+
+        /* Starting a new HEAP_DUMP resets the heap to default.
+         */
+        ctx->currentHeap = HPROF_HEAP_DEFAULT;
+    }
+
+    if (desiredHeap != ctx->currentHeap) {
+        hprof_string_id nameId;
+
+        /* This object is in a different heap than the current one.
+         * Emit a HEAP_DUMP_INFO tag to change heaps.
+         */
+        hprofAddU1ToRecord(rec, HPROF_HEAP_DUMP_INFO);
+        hprofAddU4ToRecord(rec, (u4)desiredHeap);   // u4: heap id
+        switch (desiredHeap) {
+        case HPROF_HEAP_APP:
+            nameId = hprofLookupStringId("app");
+            break;
+        case HPROF_HEAP_ZYGOTE:
+            nameId = hprofLookupStringId("zygote");
+            break;
+        default:
+            /* Internal error. */
+            assert(!"Unexpected desiredHeap");
+            nameId = hprofLookupStringId("<ILLEGAL>");
+            break;
+        }
+        hprofAddIdToRecord(rec, nameId);
+        ctx->currentHeap = desiredHeap;
+    }
+
+    clazz = obj->clazz;
+
+    if (clazz == NULL) {
+        /* This object will bother HprofReader, because it has a NULL
+         * class, so just don't dump it. It could be
+         * gDvm.unlinkedJavaLangClass or it could be an object just
+         * allocated which hasn't been initialized yet.
+         */
+    } else {
+        if (dvmIsClassObject(obj)) {
+            const ClassObject *thisClass = (const ClassObject *)obj;
+            /* obj is a ClassObject.
+             */
+            int sFieldCount = thisClass->sfieldCount;
+            if (sFieldCount != 0) {
+                int byteLength = sFieldCount*sizeof(StaticField);
+                /* Create a byte array to reflect the allocation of the
+                 * StaticField array at the end of this class.
+                 */
+                hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
+                hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+                hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+                hprofAddU4ToRecord(rec, byteLength);
+                hprofAddU1ToRecord(rec, hprof_basic_byte);
+                for (int i = 0; i < byteLength; i++) {
+                    hprofAddU1ToRecord(rec, 0);
+                }
+            }
+
+            hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
+            hprofAddIdToRecord(rec, hprofLookupClassId(thisClass));
+            hprofAddU4ToRecord(rec, stackTraceSerialNumber(thisClass));
+            hprofAddIdToRecord(rec, hprofLookupClassId(thisClass->super));
+            hprofAddIdToRecord(rec, (hprof_object_id)thisClass->classLoader);
+            hprofAddIdToRecord(rec, (hprof_object_id)0);    // no signer
+            hprofAddIdToRecord(rec, (hprof_object_id)0);    // no prot domain
+            hprofAddIdToRecord(rec, (hprof_id)0);           // reserved
+            hprofAddIdToRecord(rec, (hprof_id)0);           // reserved
+            if (obj == (Object *)gDvm.classJavaLangClass) {
+                // ClassObjects have their static fields appended, so
+                // aren't all the same size. But they're at least this
+                // size.
+                hprofAddU4ToRecord(rec, sizeof(ClassObject)); // instance size
+            } else {
+                hprofAddU4ToRecord(rec, thisClass->objectSize); // instance size
+            }
+
+            hprofAddU2ToRecord(rec, 0);                     // empty const pool
+
+            /* Static fields
+             */
+            if (sFieldCount == 0) {
+                hprofAddU2ToRecord(rec, (u2)0);
+            } else {
+                hprofAddU2ToRecord(rec, (u2)(sFieldCount+1));
+                hprofAddIdToRecord(rec,
+                                   hprofLookupStringId(STATIC_OVERHEAD_NAME));
+                hprofAddU1ToRecord(rec, hprof_basic_object);
+                hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+                for (int i = 0; i < sFieldCount; i++) {
+                    hprof_basic_type t;
+                    size_t size;
+                    const StaticField *f = &thisClass->sfields[i];
+
+                    t = signatureToBasicTypeAndSize(f->signature, &size);
+                    hprofAddIdToRecord(rec, hprofLookupStringId(f->name));
+                    hprofAddU1ToRecord(rec, t);
+                    if (size == 1) {
+                        hprofAddU1ToRecord(rec, (u1)f->value.b);
+                    } else if (size == 2) {
+                        hprofAddU2ToRecord(rec, (u2)f->value.c);
+                    } else if (size == 4) {
+                        hprofAddU4ToRecord(rec, (u4)f->value.i);
+                    } else if (size == 8) {
+                        hprofAddU8ToRecord(rec, (u8)f->value.j);
+                    } else {
+                        assert(false);
+                    }
+                }
+            }
+
+            /* Instance fields for this class (no superclass fields)
+             */
+            int iFieldCount = thisClass->ifieldCount;
+            hprofAddU2ToRecord(rec, (u2)iFieldCount);
+            for (int i = 0; i < iFieldCount; i++) {
+                const InstField *f = &thisClass->ifields[i];
+                hprof_basic_type t;
+
+                t = signatureToBasicTypeAndSize(f->signature, NULL);
+                hprofAddIdToRecord(rec, hprofLookupStringId(f->name));
+                hprofAddU1ToRecord(rec, t);
+            }
+        } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
+            const ArrayObject *aobj = (const ArrayObject *)obj;
+            u4 length = aobj->length;
+
+            if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) {
+                /* obj is an object array.
+                 */
+                hprofAddU1ToRecord(rec, HPROF_OBJECT_ARRAY_DUMP);
+
+                hprofAddIdToRecord(rec, (hprof_object_id)obj);
+                hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+                hprofAddU4ToRecord(rec, length);
+                hprofAddIdToRecord(rec, hprofLookupClassId(clazz));
+
+                /* Dump the elements, which are always objects or NULL.
+                 */
+                hprofAddIdListToRecord(rec,
+                        (const hprof_object_id *)(void *)aobj->contents, length);
+            } else {
+                hprof_basic_type t;
+                size_t size;
+
+                t = primitiveToBasicTypeAndSize(clazz->elementClass->
+                                                primitiveType, &size);
+
+                /* obj is a primitive array.
+                 */
+#if DUMP_PRIM_DATA
+                hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
+#else
+                hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_NODATA_DUMP);
+#endif
+
+                hprofAddIdToRecord(rec, (hprof_object_id)obj);
+                hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+                hprofAddU4ToRecord(rec, length);
+                hprofAddU1ToRecord(rec, t);
+
+#if DUMP_PRIM_DATA
+                /* Dump the raw, packed element values.
+                 */
+                if (size == 1) {
+                    hprofAddU1ListToRecord(rec, (const u1 *)aobj->contents,
+                            length);
+                } else if (size == 2) {
+                    hprofAddU2ListToRecord(rec, (const u2 *)(void *)aobj->contents,
+                            length);
+                } else if (size == 4) {
+                    hprofAddU4ListToRecord(rec, (const u4 *)(void *)aobj->contents,
+                            length);
+                } else if (size == 8) {
+                    hprofAddU8ListToRecord(rec, (const u8 *)aobj->contents,
+                            length);
+                }
+#endif
+            }
+        } else {
+            const ClassObject *sclass;
+            size_t sizePatchOffset, savedLen;
+
+            /* obj is an instance object.
+             */
+            hprofAddU1ToRecord(rec, HPROF_INSTANCE_DUMP);
+            hprofAddIdToRecord(rec, (hprof_object_id)obj);
+            hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+            hprofAddIdToRecord(rec, hprofLookupClassId(clazz));
+
+            /* Reserve some space for the length of the instance
+             * data, which we won't know until we're done writing
+             * it.
+             */
+            sizePatchOffset = rec->length;
+            hprofAddU4ToRecord(rec, 0x77777777);
+
+            /* Write the instance data;  fields for this
+             * class, followed by super class fields, and so on.
+             */
+            sclass = clazz;
+            while (sclass != NULL) {
+                int ifieldCount = sclass->ifieldCount;
+                for (int i = 0; i < ifieldCount; i++) {
+                    const InstField *f = &sclass->ifields[i];
+                    size_t size;
+
+                    (void) signatureToBasicTypeAndSize(f->signature, &size);
+                    if (size == 1) {
+                        hprofAddU1ToRecord(rec,
+                                (u1)dvmGetFieldByte(obj, f->byteOffset));
+                    } else if (size == 2) {
+                        hprofAddU2ToRecord(rec,
+                                (u2)dvmGetFieldChar(obj, f->byteOffset));
+                    } else if (size == 4) {
+                        hprofAddU4ToRecord(rec,
+                                (u4)dvmGetFieldInt(obj, f->byteOffset));
+                    } else if (size == 8) {
+                        hprofAddU8ToRecord(rec,
+                                (u8)dvmGetFieldLong(obj, f->byteOffset));
+                    } else {
+                        assert(false);
+                    }
+                }
+
+                sclass = sclass->super;
+            }
+
+            /* Patch the instance field length.
+             */
+            savedLen = rec->length;
+            rec->length = sizePatchOffset;
+            hprofAddU4ToRecord(rec, savedLen - (sizePatchOffset + 4));
+            rec->length = savedLen;
+        }
+    }
+
+    ctx->objectsInSegment++;
+
+    return 0;
+}
diff --git a/vm/hprof/HprofOutput.cpp b/vm/hprof/HprofOutput.cpp
new file mode 100644
index 0000000..6393438
--- /dev/null
+++ b/vm/hprof/HprofOutput.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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.
+ */
+#include <sys/time.h>
+#include <cutils/open_memstream.h>
+#include <time.h>
+#include <errno.h>
+#include "Hprof.h"
+
+#define HPROF_MAGIC_STRING  "JAVA PROFILE 1.0.3"
+
+#define U2_TO_BUF_BE(buf, offset, value) \
+    do { \
+        unsigned char *buf_ = (unsigned char *)(buf); \
+        int offset_ = (int)(offset); \
+        u2 value_ = (u2)(value); \
+        buf_[offset_ + 0] = (unsigned char)(value_ >>  8); \
+        buf_[offset_ + 1] = (unsigned char)(value_      ); \
+    } while (0)
+
+#define U4_TO_BUF_BE(buf, offset, value) \
+    do { \
+        unsigned char *buf_ = (unsigned char *)(buf); \
+        int offset_ = (int)(offset); \
+        u4 value_ = (u4)(value); \
+        buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
+        buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
+        buf_[offset_ + 2] = (unsigned char)(value_ >>  8); \
+        buf_[offset_ + 3] = (unsigned char)(value_      ); \
+    } while (0)
+
+#define U8_TO_BUF_BE(buf, offset, value) \
+    do { \
+        unsigned char *buf_ = (unsigned char *)(buf); \
+        int offset_ = (int)(offset); \
+        u8 value_ = (u8)(value); \
+        buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
+        buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
+        buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
+        buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
+        buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
+        buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
+        buf_[offset_ + 6] = (unsigned char)(value_ >>  8); \
+        buf_[offset_ + 7] = (unsigned char)(value_      ); \
+    } while (0)
+
+/*
+ * Initialize an hprof context struct.
+ *
+ * This will take ownership of "fileName".
+ */
+void hprofContextInit(hprof_context_t *ctx, char *fileName, int fd,
+                      bool writeHeader, bool directToDdms)
+{
+    memset(ctx, 0, sizeof (*ctx));
+
+    /*
+     * Have to do this here, because it must happen after we
+     * memset the struct (want to treat fileDataPtr/fileDataSize
+     * as read-only while the file is open).
+     */
+    FILE* fp = open_memstream(&ctx->fileDataPtr, &ctx->fileDataSize);
+    if (fp == NULL) {
+        /* not expected */
+        LOGE("hprof: open_memstream failed: %s", strerror(errno));
+        dvmAbort();
+    }
+
+    ctx->directToDdms = directToDdms;
+    ctx->fileName = fileName;
+    ctx->memFp = fp;
+    ctx->fd = fd;
+
+    ctx->curRec.allocLen = 128;
+    ctx->curRec.body = (unsigned char *)malloc(ctx->curRec.allocLen);
+//xxx check for/return an error
+
+    if (writeHeader) {
+        char magic[] = HPROF_MAGIC_STRING;
+        unsigned char buf[4];
+        struct timeval now;
+        u8 nowMs;
+
+        /* Write the file header.
+         *
+         * [u1]*: NUL-terminated magic string.
+         */
+        fwrite(magic, 1, sizeof(magic), fp);
+
+        /* u4: size of identifiers.  We're using addresses
+         *     as IDs, so make sure a pointer fits.
+         */
+        U4_TO_BUF_BE(buf, 0, sizeof(void *));
+        fwrite(buf, 1, sizeof(u4), fp);
+
+        /* The current time, in milliseconds since 0:00 GMT, 1/1/70.
+         */
+        if (gettimeofday(&now, NULL) < 0) {
+            nowMs = 0;
+        } else {
+            nowMs = (u8)now.tv_sec * 1000 + now.tv_usec / 1000;
+        }
+
+        /* u4: high word of the 64-bit time.
+         */
+        U4_TO_BUF_BE(buf, 0, (u4)(nowMs >> 32));
+        fwrite(buf, 1, sizeof(u4), fp);
+
+        /* u4: low word of the 64-bit time.
+         */
+        U4_TO_BUF_BE(buf, 0, (u4)(nowMs & 0xffffffffULL));
+        fwrite(buf, 1, sizeof(u4), fp); //xxx fix the time
+    }
+}
+
+int hprofFlushRecord(hprof_record_t *rec, FILE *fp)
+{
+    if (rec->dirty) {
+        unsigned char headBuf[sizeof (u1) + 2 * sizeof (u4)];
+        int nb;
+
+        headBuf[0] = rec->tag;
+        U4_TO_BUF_BE(headBuf, 1, rec->time);
+        U4_TO_BUF_BE(headBuf, 5, rec->length);
+
+        nb = fwrite(headBuf, 1, sizeof(headBuf), fp);
+        if (nb != sizeof(headBuf)) {
+            return UNIQUE_ERROR();
+        }
+        nb = fwrite(rec->body, 1, rec->length, fp);
+        if (nb != (int)rec->length) {
+            return UNIQUE_ERROR();
+        }
+
+        rec->dirty = false;
+    }
+//xxx if we used less than half (or whatever) of allocLen, shrink the buffer.
+
+    return 0;
+}
+
+int hprofFlushCurrentRecord(hprof_context_t *ctx)
+{
+    return hprofFlushRecord(&ctx->curRec, ctx->memFp);
+}
+
+int hprofStartNewRecord(hprof_context_t *ctx, u1 tag, u4 time)
+{
+    hprof_record_t *rec = &ctx->curRec;
+    int err;
+
+    err = hprofFlushRecord(rec, ctx->memFp);
+    if (err != 0) {
+        return err;
+    } else if (rec->dirty) {
+        return UNIQUE_ERROR();
+    }
+
+    rec->dirty = true;
+    rec->tag = tag;
+    rec->time = time;
+    rec->length = 0;
+
+    return 0;
+}
+
+static inline int guaranteeRecordAppend(hprof_record_t *rec, size_t nmore)
+{
+    size_t minSize;
+
+    minSize = rec->length + nmore;
+    if (minSize > rec->allocLen) {
+        unsigned char *newBody;
+        size_t newAllocLen;
+
+        newAllocLen = rec->allocLen * 2;
+        if (newAllocLen < minSize) {
+            newAllocLen = rec->allocLen + nmore + nmore/2;
+        }
+        newBody = (unsigned char *)realloc(rec->body, newAllocLen);
+        if (newBody != NULL) {
+            rec->body = newBody;
+            rec->allocLen = newAllocLen;
+        } else {
+//TODO: set an error flag so future ops will fail
+            return UNIQUE_ERROR();
+        }
+    }
+
+    assert(rec->length + nmore <= rec->allocLen);
+    return 0;
+}
+
+int hprofAddU1ListToRecord(hprof_record_t *rec, const u1 *values,
+                           size_t numValues)
+{
+    int err;
+
+    err = guaranteeRecordAppend(rec, numValues);
+    if (err != 0) {
+        return err;
+    }
+
+    memcpy(rec->body + rec->length, values, numValues);
+    rec->length += numValues;
+
+    return 0;
+}
+
+int hprofAddU1ToRecord(hprof_record_t *rec, u1 value)
+{
+    int err;
+
+    err = guaranteeRecordAppend(rec, 1);
+    if (err != 0) {
+        return err;
+    }
+
+    rec->body[rec->length++] = value;
+
+    return 0;
+}
+
+int hprofAddUtf8StringToRecord(hprof_record_t *rec, const char *str)
+{
+    /* The terminating NUL character is NOT written.
+     */
+//xxx don't do a strlen;  add and grow as necessary, until NUL
+    return hprofAddU1ListToRecord(rec, (const u1 *)str, strlen(str));
+}
+
+int hprofAddU2ListToRecord(hprof_record_t *rec, const u2 *values,
+                           size_t numValues)
+{
+    int err = guaranteeRecordAppend(rec, numValues * 2);
+    if (err != 0) {
+        return err;
+    }
+
+//xxx this can be way smarter
+//xxx also, don't do this bytewise if aligned and on a matching-endian arch
+    unsigned char *insert = rec->body + rec->length;
+    for (size_t i = 0; i < numValues; i++) {
+        U2_TO_BUF_BE(insert, 0, *values++);
+        insert += sizeof(*values);
+    }
+    rec->length += numValues * 2;
+
+    return 0;
+}
+
+int hprofAddU2ToRecord(hprof_record_t *rec, u2 value)
+{
+    return hprofAddU2ListToRecord(rec, &value, 1);
+}
+
+int hprofAddU4ListToRecord(hprof_record_t *rec, const u4 *values,
+                           size_t numValues)
+{
+    int err = guaranteeRecordAppend(rec, numValues * 4);
+    if (err != 0) {
+        return err;
+    }
+
+//xxx this can be way smarter
+//xxx also, don't do this bytewise if aligned and on a matching-endian arch
+    unsigned char *insert = rec->body + rec->length;
+    for (size_t i = 0; i < numValues; i++) {
+        U4_TO_BUF_BE(insert, 0, *values++);
+        insert += sizeof(*values);
+    }
+    rec->length += numValues * 4;
+
+    return 0;
+}
+
+int hprofAddU4ToRecord(hprof_record_t *rec, u4 value)
+{
+    return hprofAddU4ListToRecord(rec, &value, 1);
+}
+
+int hprofAddU8ListToRecord(hprof_record_t *rec, const u8 *values,
+                           size_t numValues)
+{
+    int err = guaranteeRecordAppend(rec, numValues * 8);
+    if (err != 0) {
+        return err;
+    }
+
+//xxx this can be way smarter
+//xxx also, don't do this bytewise if aligned and on a matching-endian arch
+    unsigned char *insert = rec->body + rec->length;
+    for (size_t i = 0; i < numValues; i++) {
+        U8_TO_BUF_BE(insert, 0, *values++);
+        insert += sizeof(*values);
+    }
+    rec->length += numValues * 8;
+
+    return 0;
+}
+
+int hprofAddU8ToRecord(hprof_record_t *rec, u8 value)
+{
+    return hprofAddU8ListToRecord(rec, &value, 1);
+}
diff --git a/vm/hprof/HprofString.cpp b/vm/hprof/HprofString.cpp
new file mode 100644
index 0000000..3534f07
--- /dev/null
+++ b/vm/hprof/HprofString.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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 string pool for the profiler
+ */
+#include "Hprof.h"
+
+static HashTable *gStringHashTable;
+
+int hprofStartup_String()
+{
+    gStringHashTable = dvmHashTableCreate(512, free);
+    if (gStringHashTable == NULL) {
+        return UNIQUE_ERROR();
+    }
+    return 0;
+}
+
+int hprofShutdown_String()
+{
+    dvmHashTableFree(gStringHashTable);
+    return 0;
+}
+
+static u4 computeUtf8Hash(const char *str)
+{
+    u4 hash = 0;
+    const char *cp;
+    char c;
+
+    cp = str;
+    while ((c = *cp++) != '\0') {
+        hash = hash * 31 + c;
+    }
+
+    return hash;
+}
+
+hprof_string_id hprofLookupStringId(const char *str)
+{
+    void *val;
+    u4 hashValue;
+
+    dvmHashTableLock(gStringHashTable);
+
+    hashValue = computeUtf8Hash(str);
+    val = dvmHashTableLookup(gStringHashTable, hashValue, (void *)str,
+            (HashCompareFunc)strcmp, false);
+    if (val == NULL) {
+        const char *newStr;
+
+        newStr = strdup(str);
+        val = dvmHashTableLookup(gStringHashTable, hashValue, (void *)newStr,
+                (HashCompareFunc)strcmp, true);
+        assert(val != NULL);
+    }
+
+    dvmHashTableUnlock(gStringHashTable);
+
+    return (hprof_string_id)val;
+}
+
+int hprofDumpStrings(hprof_context_t *ctx)
+{
+    HashIter iter;
+    hprof_record_t *rec = &ctx->curRec;
+    int err;
+
+    dvmHashTableLock(gStringHashTable);
+
+    for (err = 0, dvmHashIterBegin(gStringHashTable, &iter);
+         err == 0 && !dvmHashIterDone(&iter);
+         dvmHashIterNext(&iter))
+    {
+        err = hprofStartNewRecord(ctx, HPROF_TAG_STRING, HPROF_TIME);
+        if (err == 0) {
+            const char *str;
+
+            str = (const char *)dvmHashIterData(&iter);
+            assert(str != NULL);
+
+            /* STRING format:
+             *
+             * ID:     ID for this string
+             * [u1]*:  UTF8 characters for string (NOT NULL terminated)
+             *         (the record format encodes the length)
+             *
+             * We use the address of the string data as its ID.
+             */
+            err = hprofAddU4ToRecord(rec, (u4)str);
+            if (err == 0) {
+                err = hprofAddUtf8StringToRecord(rec, str);
+            }
+        }
+    }
+
+    dvmHashTableUnlock(gStringHashTable);
+
+    return err;
+}
diff --git a/vm/interp/Interp.cpp b/vm/interp/Interp.cpp
new file mode 100644
index 0000000..de85fa1
--- /dev/null
+++ b/vm/interp/Interp.cpp
@@ -0,0 +1,1977 @@
+/*
+ * 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.
+ */
+
+/*
+ * Main interpreter entry point and support functions.
+ *
+ * The entry point selects the "standard" or "debug" interpreter and
+ * facilitates switching between them.  The standard interpreter may
+ * use the "fast" or "portable" implementation.
+ *
+ * Some debugger support functions are included here.
+ */
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#if defined(WITH_JIT)
+#include "interp/Jit.h"
+#endif
+
+
+/*
+ * ===========================================================================
+ *      Debugger support
+ * ===========================================================================
+ */
+
+// fwd
+static BreakpointSet* dvmBreakpointSetAlloc();
+static void dvmBreakpointSetFree(BreakpointSet* pSet);
+
+#if defined(WITH_JIT)
+/* Target-specific save/restore */
+extern "C" void dvmJitCalleeSave(double *saveArea);
+extern "C" void dvmJitCalleeRestore(double *saveArea);
+/* Interpreter entry points from compiled code */
+extern "C" void dvmJitToInterpNormal();
+extern "C" void dvmJitToInterpNoChain();
+extern "C" void dvmJitToInterpPunt();
+extern "C" void dvmJitToInterpSingleStep();
+extern "C" void dvmJitToInterpTraceSelect();
+#if defined(WITH_SELF_VERIFICATION)
+extern "C" void dvmJitToInterpBackwardBranch();
+#endif
+#endif
+
+/*
+ * Initialize global breakpoint structures.
+ */
+bool dvmBreakpointStartup()
+{
+    gDvm.breakpointSet = dvmBreakpointSetAlloc();
+    return (gDvm.breakpointSet != NULL);
+}
+
+/*
+ * Free resources.
+ */
+void dvmBreakpointShutdown()
+{
+    dvmBreakpointSetFree(gDvm.breakpointSet);
+}
+
+
+/*
+ * This represents a breakpoint inserted in the instruction stream.
+ *
+ * The debugger may ask us to create the same breakpoint multiple times.
+ * We only remove the breakpoint when the last instance is cleared.
+ */
+struct Breakpoint {
+    Method*     method;                 /* method we're associated with */
+    u2*         addr;                   /* absolute memory address */
+    u1          originalOpcode;         /* original 8-bit opcode value */
+    int         setCount;               /* #of times this breakpoint was set */
+};
+
+/*
+ * Set of breakpoints.
+ */
+struct BreakpointSet {
+    /* grab lock before reading or writing anything else in here */
+    pthread_mutex_t lock;
+
+    /* vector of breakpoint structures */
+    int         alloc;
+    int         count;
+    Breakpoint* breakpoints;
+};
+
+/*
+ * Initialize a BreakpointSet.  Initially empty.
+ */
+static BreakpointSet* dvmBreakpointSetAlloc()
+{
+    BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet));
+
+    dvmInitMutex(&pSet->lock);
+    /* leave the rest zeroed -- will alloc on first use */
+
+    return pSet;
+}
+
+/*
+ * Free storage associated with a BreakpointSet.
+ */
+static void dvmBreakpointSetFree(BreakpointSet* pSet)
+{
+    if (pSet == NULL)
+        return;
+
+    free(pSet->breakpoints);
+    free(pSet);
+}
+
+/*
+ * Lock the breakpoint set.
+ *
+ * It's not currently necessary to switch to VMWAIT in the event of
+ * contention, because nothing in here can block.  However, it's possible
+ * that the bytecode-updater code could become fancier in the future, so
+ * we do the trylock dance as a bit of future-proofing.
+ */
+static void dvmBreakpointSetLock(BreakpointSet* pSet)
+{
+    if (dvmTryLockMutex(&pSet->lock) != 0) {
+        Thread* self = dvmThreadSelf();
+        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+        dvmLockMutex(&pSet->lock);
+        dvmChangeStatus(self, oldStatus);
+    }
+}
+
+/*
+ * Unlock the breakpoint set.
+ */
+static void dvmBreakpointSetUnlock(BreakpointSet* pSet)
+{
+    dvmUnlockMutex(&pSet->lock);
+}
+
+/*
+ * Return the #of breakpoints.
+ */
+static int dvmBreakpointSetCount(const BreakpointSet* pSet)
+{
+    return pSet->count;
+}
+
+/*
+ * See if we already have an entry for this address.
+ *
+ * The BreakpointSet's lock must be acquired before calling here.
+ *
+ * Returns the index of the breakpoint entry, or -1 if not found.
+ */
+static int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr)
+{
+    int i;
+
+    for (i = 0; i < pSet->count; i++) {
+        Breakpoint* pBreak = &pSet->breakpoints[i];
+        if (pBreak->addr == addr)
+            return i;
+    }
+
+    return -1;
+}
+
+/*
+ * Retrieve the opcode that was originally at the specified location.
+ *
+ * The BreakpointSet's lock must be acquired before calling here.
+ *
+ * Returns "true" with the opcode in *pOrig on success.
+ */
+static bool dvmBreakpointSetOriginalOpcode(const BreakpointSet* pSet,
+    const u2* addr, u1* pOrig)
+{
+    int idx = dvmBreakpointSetFind(pSet, addr);
+    if (idx < 0)
+        return false;
+
+    *pOrig = pSet->breakpoints[idx].originalOpcode;
+    return true;
+}
+
+/*
+ * Check the opcode.  If it's a "magic" NOP, indicating the start of
+ * switch or array data in the instruction stream, we don't want to set
+ * a breakpoint.
+ *
+ * This can happen because the line number information dx generates
+ * associates the switch data with the switch statement's line number,
+ * and some debuggers put breakpoints at every address associated with
+ * a given line.  The result is that the breakpoint stomps on the NOP
+ * instruction that doubles as a data table magic number, and an explicit
+ * check in the interpreter results in an exception being thrown.
+ *
+ * We don't want to simply refuse to add the breakpoint to the table,
+ * because that confuses the housekeeping.  We don't want to reject the
+ * debugger's event request, and we want to be sure that there's exactly
+ * one un-set operation for every set op.
+ */
+static bool instructionIsMagicNop(const u2* addr)
+{
+    u2 curVal = *addr;
+    return ((GET_OPCODE(curVal)) == OP_NOP && (curVal >> 8) != 0);
+}
+
+/*
+ * Add a breakpoint at a specific address.  If the address is already
+ * present in the table, this just increments the count.
+ *
+ * For a new entry, this will extract and preserve the current opcode from
+ * the instruction stream, and replace it with a breakpoint opcode.
+ *
+ * The BreakpointSet's lock must be acquired before calling here.
+ *
+ * Returns "true" on success.
+ */
+static bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method,
+    unsigned int instrOffset)
+{
+    const int kBreakpointGrowth = 10;
+    const u2* addr = method->insns + instrOffset;
+    int idx = dvmBreakpointSetFind(pSet, addr);
+    Breakpoint* pBreak;
+
+    if (idx < 0) {
+        if (pSet->count == pSet->alloc) {
+            int newSize = pSet->alloc + kBreakpointGrowth;
+            Breakpoint* newVec;
+
+            LOGV("+++ increasing breakpoint set size to %d", newSize);
+
+            /* pSet->breakpoints will be NULL on first entry */
+            newVec = (Breakpoint*)realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
+            if (newVec == NULL)
+                return false;
+
+            pSet->breakpoints = newVec;
+            pSet->alloc = newSize;
+        }
+
+        pBreak = &pSet->breakpoints[pSet->count++];
+        pBreak->method = method;
+        pBreak->addr = (u2*)addr;
+        pBreak->originalOpcode = *(u1*)addr;
+        pBreak->setCount = 1;
+
+        /*
+         * Change the opcode.  We must ensure that the BreakpointSet
+         * updates happen before we change the opcode.
+         *
+         * If the method has not been verified, we do NOT insert the
+         * breakpoint yet, since that will screw up the verifier.  The
+         * debugger is allowed to insert breakpoints in unverified code,
+         * but since we don't execute unverified code we don't need to
+         * alter the bytecode yet.
+         *
+         * The class init code will "flush" all pending opcode writes
+         * before verification completes.
+         */
+        assert(*(u1*)addr != OP_BREAKPOINT);
+        if (dvmIsClassVerified(method->clazz)) {
+            LOGV("Class %s verified, adding breakpoint at %p",
+                method->clazz->descriptor, addr);
+            if (instructionIsMagicNop(addr)) {
+                LOGV("Refusing to set breakpoint on %04x at %s.%s + %#x",
+                    *addr, method->clazz->descriptor, method->name,
+                    instrOffset);
+            } else {
+                ANDROID_MEMBAR_FULL();
+                dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
+                    OP_BREAKPOINT);
+            }
+        } else {
+            LOGV("Class %s NOT verified, deferring breakpoint at %p",
+                method->clazz->descriptor, addr);
+        }
+    } else {
+        /*
+         * Breakpoint already exists, just increase the count.
+         */
+        pBreak = &pSet->breakpoints[idx];
+        pBreak->setCount++;
+    }
+
+    return true;
+}
+
+/*
+ * Remove one instance of the specified breakpoint.  When the count
+ * reaches zero, the entry is removed from the table, and the original
+ * opcode is restored.
+ *
+ * The BreakpointSet's lock must be acquired before calling here.
+ */
+static void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method,
+    unsigned int instrOffset)
+{
+    const u2* addr = method->insns + instrOffset;
+    int idx = dvmBreakpointSetFind(pSet, addr);
+
+    if (idx < 0) {
+        /* breakpoint not found in set -- unexpected */
+        if (*(u1*)addr == OP_BREAKPOINT) {
+            LOGE("Unable to restore breakpoint opcode (%s.%s +%#x)",
+                method->clazz->descriptor, method->name, instrOffset);
+            dvmAbort();
+        } else {
+            LOGW("Breakpoint was already restored? (%s.%s +%#x)",
+                method->clazz->descriptor, method->name, instrOffset);
+        }
+    } else {
+        Breakpoint* pBreak = &pSet->breakpoints[idx];
+        if (pBreak->setCount == 1) {
+            /*
+             * Must restore opcode before removing set entry.
+             *
+             * If the breakpoint was never flushed, we could be ovewriting
+             * a value with the same value.  Not a problem, though we
+             * could end up causing a copy-on-write here when we didn't
+             * need to.  (Not worth worrying about.)
+             */
+            dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
+                pBreak->originalOpcode);
+            ANDROID_MEMBAR_FULL();
+
+            if (idx != pSet->count-1) {
+                /* shift down */
+                memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1],
+                    (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0]));
+            }
+            pSet->count--;
+            pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug
+        } else {
+            pBreak->setCount--;
+            assert(pBreak->setCount > 0);
+        }
+    }
+}
+
+/*
+ * Flush any breakpoints associated with methods in "clazz".  We want to
+ * change the opcode, which might not have happened when the breakpoint
+ * was initially set because the class was in the process of being
+ * verified.
+ *
+ * The BreakpointSet's lock must be acquired before calling here.
+ */
+static void dvmBreakpointSetFlush(BreakpointSet* pSet, ClassObject* clazz)
+{
+    int i;
+    for (i = 0; i < pSet->count; i++) {
+        Breakpoint* pBreak = &pSet->breakpoints[i];
+        if (pBreak->method->clazz == clazz) {
+            /*
+             * The breakpoint is associated with a method in this class.
+             * It might already be there or it might not; either way,
+             * flush it out.
+             */
+            LOGV("Flushing breakpoint at %p for %s",
+                pBreak->addr, clazz->descriptor);
+            if (instructionIsMagicNop(pBreak->addr)) {
+                LOGV("Refusing to flush breakpoint on %04x at %s.%s + %#x",
+                    *pBreak->addr, pBreak->method->clazz->descriptor,
+                    pBreak->method->name, pBreak->addr - pBreak->method->insns);
+            } else {
+                dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr,
+                    OP_BREAKPOINT);
+            }
+        }
+    }
+}
+
+
+/*
+ * Do any debugger-attach-time initialization.
+ */
+void dvmInitBreakpoints()
+{
+    /* quick sanity check */
+    BreakpointSet* pSet = gDvm.breakpointSet;
+    dvmBreakpointSetLock(pSet);
+    if (dvmBreakpointSetCount(pSet) != 0) {
+        LOGW("WARNING: %d leftover breakpoints", dvmBreakpointSetCount(pSet));
+        /* generally not good, but we can keep going */
+    }
+    dvmBreakpointSetUnlock(pSet);
+}
+
+/*
+ * Add an address to the list, putting it in the first non-empty slot.
+ *
+ * Sometimes the debugger likes to add two entries for one breakpoint.
+ * We add two entries here, so that we get the right behavior when it's
+ * removed twice.
+ *
+ * This will only be run from the JDWP thread, and it will happen while
+ * we are updating the event list, which is synchronized.  We're guaranteed
+ * to be the only one adding entries, and the lock ensures that nobody
+ * will be trying to remove them while we're in here.
+ *
+ * "addr" is the absolute address of the breakpoint bytecode.
+ */
+void dvmAddBreakAddr(Method* method, unsigned int instrOffset)
+{
+    BreakpointSet* pSet = gDvm.breakpointSet;
+    dvmBreakpointSetLock(pSet);
+    dvmBreakpointSetAdd(pSet, method, instrOffset);
+    dvmBreakpointSetUnlock(pSet);
+}
+
+/*
+ * Remove an address from the list by setting the entry to NULL.
+ *
+ * This can be called from the JDWP thread (because the debugger has
+ * cancelled the breakpoint) or from an event thread (because it's a
+ * single-shot breakpoint, e.g. "run to line").  We only get here as
+ * the result of removing an entry from the event list, which is
+ * synchronized, so it should not be possible for two threads to be
+ * updating breakpoints at the same time.
+ */
+void dvmClearBreakAddr(Method* method, unsigned int instrOffset)
+{
+    BreakpointSet* pSet = gDvm.breakpointSet;
+    dvmBreakpointSetLock(pSet);
+    dvmBreakpointSetRemove(pSet, method, instrOffset);
+    dvmBreakpointSetUnlock(pSet);
+}
+
+/*
+ * Get the original opcode from under a breakpoint.
+ *
+ * On SMP hardware it's possible one core might try to execute a breakpoint
+ * after another core has cleared it.  We need to handle the case where
+ * there's no entry in the breakpoint set.  (The memory barriers in the
+ * locks and in the breakpoint update code should ensure that, once we've
+ * observed the absence of a breakpoint entry, we will also now observe
+ * the restoration of the original opcode.  The fact that we're holding
+ * the lock prevents other threads from confusing things further.)
+ */
+u1 dvmGetOriginalOpcode(const u2* addr)
+{
+    BreakpointSet* pSet = gDvm.breakpointSet;
+    u1 orig = 0;
+
+    dvmBreakpointSetLock(pSet);
+    if (!dvmBreakpointSetOriginalOpcode(pSet, addr, &orig)) {
+        orig = *(u1*)addr;
+        if (orig == OP_BREAKPOINT) {
+            LOGE("GLITCH: can't find breakpoint, opcode is still set");
+            dvmAbort();
+        }
+    }
+    dvmBreakpointSetUnlock(pSet);
+
+    return orig;
+}
+
+/*
+ * Flush any breakpoints associated with methods in "clazz".
+ *
+ * We don't want to modify the bytecode of a method before the verifier
+ * gets a chance to look at it, so we postpone opcode replacement until
+ * after verification completes.
+ */
+void dvmFlushBreakpoints(ClassObject* clazz)
+{
+    BreakpointSet* pSet = gDvm.breakpointSet;
+
+    if (pSet == NULL)
+        return;
+
+    assert(dvmIsClassVerified(clazz));
+    dvmBreakpointSetLock(pSet);
+    dvmBreakpointSetFlush(pSet, clazz);
+    dvmBreakpointSetUnlock(pSet);
+}
+
+/*
+ * Add a single step event.  Currently this is a global item.
+ *
+ * We set up some initial values based on the thread's current state.  This
+ * won't work well if the thread is running, so it's up to the caller to
+ * verify that it's suspended.
+ *
+ * This is only called from the JDWP thread.
+ */
+bool dvmAddSingleStep(Thread* thread, int size, int depth)
+{
+    StepControl* pCtrl = &gDvm.stepControl;
+
+    if (pCtrl->active && thread != pCtrl->thread) {
+        LOGW("WARNING: single-step active for %p; adding %p",
+            pCtrl->thread, thread);
+
+        /*
+         * Keep going, overwriting previous.  This can happen if you
+         * suspend a thread in Object.wait, hit the single-step key, then
+         * switch to another thread and do the same thing again.
+         * The first thread's step is still pending.
+         *
+         * TODO: consider making single-step per-thread.  Adds to the
+         * overhead, but could be useful in rare situations.
+         */
+    }
+
+    pCtrl->size = static_cast<JdwpStepSize>(size);
+    pCtrl->depth = static_cast<JdwpStepDepth>(depth);
+    pCtrl->thread = thread;
+
+    /*
+     * We may be stepping into or over method calls, or running until we
+     * return from the current method.  To make this work we need to track
+     * the current line, current method, and current stack depth.  We need
+     * to be checking these after most instructions, notably those that
+     * call methods, return from methods, or are on a different line from the
+     * previous instruction.
+     *
+     * We have to start with a snapshot of the current state.  If we're in
+     * an interpreted method, everything we need is in the current frame.  If
+     * we're in a native method, possibly with some extra JNI frames pushed
+     * on by PushLocalFrame, we want to use the topmost native method.
+     */
+    const StackSaveArea* saveArea;
+    u4* fp;
+    u4* prevFp = NULL;
+
+    for (fp = thread->interpSave.curFrame; fp != NULL;
+         fp = saveArea->prevFrame) {
+        const Method* method;
+
+        saveArea = SAVEAREA_FROM_FP(fp);
+        method = saveArea->method;
+
+        if (!dvmIsBreakFrame((u4*)fp) && !dvmIsNativeMethod(method))
+            break;
+        prevFp = fp;
+    }
+    if (fp == NULL) {
+        LOGW("Unexpected: step req in native-only threadid=%d",
+            thread->threadId);
+        return false;
+    }
+    if (prevFp != NULL) {
+        /*
+         * First interpreted frame wasn't the one at the bottom.  Break
+         * frames are only inserted when calling from native->interp, so we
+         * don't need to worry about one being here.
+         */
+        LOGV("##### init step while in native method");
+        fp = prevFp;
+        assert(!dvmIsBreakFrame((u4*)fp));
+        assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
+        saveArea = SAVEAREA_FROM_FP(fp);
+    }
+
+    /*
+     * Pull the goodies out.  "xtra.currentPc" should be accurate since
+     * we update it on every instruction while the debugger is connected.
+     */
+    pCtrl->method = saveArea->method;
+    // Clear out any old address set
+    if (pCtrl->pAddressSet != NULL) {
+        // (discard const)
+        free((void *)pCtrl->pAddressSet);
+        pCtrl->pAddressSet = NULL;
+    }
+    if (dvmIsNativeMethod(pCtrl->method)) {
+        pCtrl->line = -1;
+    } else {
+        pCtrl->line = dvmLineNumFromPC(saveArea->method,
+                        saveArea->xtra.currentPc - saveArea->method->insns);
+        pCtrl->pAddressSet
+                = dvmAddressSetForLine(saveArea->method, pCtrl->line);
+    }
+    pCtrl->frameDepth =
+        dvmComputeVagueFrameDepth(thread, thread->interpSave.curFrame);
+    pCtrl->active = true;
+
+    LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s",
+        pCtrl->thread, pCtrl->method, pCtrl->method->name,
+        pCtrl->line, pCtrl->frameDepth,
+        dvmJdwpStepDepthStr(pCtrl->depth),
+        dvmJdwpStepSizeStr(pCtrl->size));
+
+    return true;
+}
+
+/*
+ * Disable a single step event.
+ */
+void dvmClearSingleStep(Thread* thread)
+{
+    UNUSED_PARAMETER(thread);
+
+    gDvm.stepControl.active = false;
+}
+
+/*
+ * The interpreter just threw.  Handle any special subMode requirements.
+ * All interpSave state must be valid on entry.
+ */
+void dvmReportExceptionThrow(Thread* self, Object* exception)
+{
+    const Method* curMethod = self->interpSave.method;
+#if defined(WITH_JIT)
+    if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {
+        dvmJitEndTraceSelect(self, self->interpSave.pc);
+    }
+    if (self->interpBreak.ctl.breakFlags & kInterpSingleStep) {
+        /* Discard any single-step native returns to translation */
+        self->jitResumeNPC = NULL;
+    }
+#endif
+    if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+        void *catchFrame;
+        int offset = self->interpSave.pc - curMethod->insns;
+        int catchRelPc = dvmFindCatchBlock(self, offset, exception,
+                                           true, &catchFrame);
+        dvmDbgPostException(self->interpSave.curFrame, offset, catchFrame,
+                            catchRelPc, exception);
+    }
+}
+
+/*
+ * The interpreter is preparing to do an invoke (both native & normal).
+ * Handle any special subMode requirements.  All interpSave state
+ * must be valid on entry.
+ */
+void dvmReportInvoke(Thread* self, const Method* methodToCall)
+{
+    TRACE_METHOD_ENTER(self, methodToCall);
+}
+
+/*
+ * The interpreter is preparing to do a native invoke. Handle any
+ * special subMode requirements.  NOTE: for a native invoke,
+ * dvmReportInvoke() and dvmReportPreNativeInvoke() will both
+ * be called prior to the invoke.  fp is the Dalvik FP of the calling
+ * method.
+ */
+void dvmReportPreNativeInvoke(const Method* methodToCall, Thread* self, u4* fp)
+{
+#if defined(WITH_JIT)
+    /*
+     * Actively building a trace?  If so, end it now.   The trace
+     * builder can't follow into or through a native method.
+     */
+    if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {
+        dvmCheckJit(self->interpSave.pc, self);
+    }
+#endif
+    if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+        Object* thisPtr = dvmGetThisPtr(self->interpSave.method, fp);
+        assert(thisPtr == NULL || dvmIsHeapAddress(thisPtr));
+        dvmDbgPostLocationEvent(methodToCall, -1, thisPtr, DBG_METHOD_ENTRY);
+    }
+}
+
+/*
+ * The interpreter has returned from a native invoke. Handle any
+ * special subMode requirements.  fp is the Dalvik FP of the calling
+ * method.
+ */
+void dvmReportPostNativeInvoke(const Method* methodToCall, Thread* self, u4* fp)
+{
+    if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+        Object* thisPtr = dvmGetThisPtr(self->interpSave.method, fp);
+        assert(thisPtr == NULL || dvmIsHeapAddress(thisPtr));
+        dvmDbgPostLocationEvent(methodToCall, -1, thisPtr, DBG_METHOD_EXIT);
+    }
+    if (self->interpBreak.ctl.subMode & kSubModeMethodTrace) {
+        dvmFastNativeMethodTraceExit(methodToCall, self);
+    }
+}
+
+/*
+ * The interpreter has returned from a normal method.  Handle any special
+ * subMode requirements.  All interpSave state must be valid on entry.
+ */
+void dvmReportReturn(Thread* self)
+{
+    TRACE_METHOD_EXIT(self, self->interpSave.method);
+#if defined(WITH_JIT)
+    if (dvmIsBreakFrame(self->interpSave.curFrame) &&
+        (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild)) {
+        dvmCheckJit(self->interpSave.pc, self);
+    }
+#endif
+}
+
+/*
+ * Update the debugger on interesting events, such as hitting a breakpoint
+ * or a single-step point.  This is called from the top of the interpreter
+ * loop, before the current instruction is processed.
+ *
+ * Set "methodEntry" if we've just entered the method.  This detects
+ * method exit by checking to see if the next instruction is "return".
+ *
+ * This can't catch native method entry/exit, so we have to handle that
+ * at the point of invocation.  We also need to catch it in dvmCallMethod
+ * if we want to capture native->native calls made through JNI.
+ *
+ * Notes to self:
+ * - Don't want to switch to VMWAIT while posting events to the debugger.
+ *   Let the debugger code decide if we need to change state.
+ * - We may want to check for debugger-induced thread suspensions on
+ *   every instruction.  That would make a "suspend all" more responsive
+ *   and reduce the chances of multiple simultaneous events occurring.
+ *   However, it could change the behavior some.
+ *
+ * TODO: method entry/exit events are probably less common than location
+ * breakpoints.  We may be able to speed things up a bit if we don't query
+ * the event list unless we know there's at least one lurking within.
+ */
+static void updateDebugger(const Method* method, const u2* pc, const u4* fp,
+                           Thread* self)
+{
+    int eventFlags = 0;
+
+    /*
+     * Update xtra.currentPc on every instruction.  We need to do this if
+     * there's a chance that we could get suspended.  This can happen if
+     * eventFlags != 0 here, or somebody manually requests a suspend
+     * (which gets handled at PERIOD_CHECKS time).  One place where this
+     * needs to be correct is in dvmAddSingleStep().
+     */
+    dvmExportPC(pc, fp);
+
+    if (self->debugIsMethodEntry) {
+        eventFlags |= DBG_METHOD_ENTRY;
+        self->debugIsMethodEntry = false;
+    }
+
+    /*
+     * See if we have a breakpoint here.
+     *
+     * Depending on the "mods" associated with event(s) on this address,
+     * we may or may not actually send a message to the debugger.
+     */
+    if (GET_OPCODE(*pc) == OP_BREAKPOINT) {
+        LOGV("+++ breakpoint hit at %p", pc);
+        eventFlags |= DBG_BREAKPOINT;
+    }
+
+    /*
+     * If the debugger is single-stepping one of our threads, check to
+     * see if we're that thread and we've reached a step point.
+     */
+    const StepControl* pCtrl = &gDvm.stepControl;
+    if (pCtrl->active && pCtrl->thread == self) {
+        int frameDepth;
+        bool doStop = false;
+        const char* msg = NULL;
+
+        assert(!dvmIsNativeMethod(method));
+
+        if (pCtrl->depth == SD_INTO) {
+            /*
+             * Step into method calls.  We break when the line number
+             * or method pointer changes.  If we're in SS_MIN mode, we
+             * always stop.
+             */
+            if (pCtrl->method != method) {
+                doStop = true;
+                msg = "new method";
+            } else if (pCtrl->size == SS_MIN) {
+                doStop = true;
+                msg = "new instruction";
+            } else if (!dvmAddressSetGet(
+                    pCtrl->pAddressSet, pc - method->insns)) {
+                doStop = true;
+                msg = "new line";
+            }
+        } else if (pCtrl->depth == SD_OVER) {
+            /*
+             * Step over method calls.  We break when the line number is
+             * different and the frame depth is <= the original frame
+             * depth.  (We can't just compare on the method, because we
+             * might get unrolled past it by an exception, and it's tricky
+             * to identify recursion.)
+             */
+            frameDepth = dvmComputeVagueFrameDepth(self, fp);
+            if (frameDepth < pCtrl->frameDepth) {
+                /* popped up one or more frames, always trigger */
+                doStop = true;
+                msg = "method pop";
+            } else if (frameDepth == pCtrl->frameDepth) {
+                /* same depth, see if we moved */
+                if (pCtrl->size == SS_MIN) {
+                    doStop = true;
+                    msg = "new instruction";
+                } else if (!dvmAddressSetGet(pCtrl->pAddressSet,
+                            pc - method->insns)) {
+                    doStop = true;
+                    msg = "new line";
+                }
+            }
+        } else {
+            assert(pCtrl->depth == SD_OUT);
+            /*
+             * Return from the current method.  We break when the frame
+             * depth pops up.
+             *
+             * This differs from the "method exit" break in that it stops
+             * with the PC at the next instruction in the returned-to
+             * function, rather than the end of the returning function.
+             */
+            frameDepth = dvmComputeVagueFrameDepth(self, fp);
+            if (frameDepth < pCtrl->frameDepth) {
+                doStop = true;
+                msg = "method pop";
+            }
+        }
+
+        if (doStop) {
+            LOGV("#####S %s", msg);
+            eventFlags |= DBG_SINGLE_STEP;
+        }
+    }
+
+    /*
+     * Check to see if this is a "return" instruction.  JDWP says we should
+     * send the event *after* the code has been executed, but it also says
+     * the location we provide is the last instruction.  Since the "return"
+     * instruction has no interesting side effects, we should be safe.
+     * (We can't just move this down to the returnFromMethod label because
+     * we potentially need to combine it with other events.)
+     *
+     * We're also not supposed to generate a method exit event if the method
+     * terminates "with a thrown exception".
+     */
+    u2 opcode = GET_OPCODE(*pc);
+    if (opcode == OP_RETURN_VOID || opcode == OP_RETURN ||
+        opcode == OP_RETURN_WIDE ||opcode == OP_RETURN_OBJECT)
+    {
+        eventFlags |= DBG_METHOD_EXIT;
+    }
+
+    /*
+     * If there's something interesting going on, see if it matches one
+     * of the debugger filters.
+     */
+    if (eventFlags != 0) {
+        Object* thisPtr = dvmGetThisPtr(method, fp);
+        if (thisPtr != NULL && !dvmIsHeapAddress(thisPtr)) {
+            /*
+             * TODO: remove this check if we're confident that the "this"
+             * pointer is where it should be -- slows us down, especially
+             * during single-step.
+             */
+            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+            LOGE("HEY: invalid 'this' ptr %p (%s.%s %s)", thisPtr,
+                method->clazz->descriptor, method->name, desc);
+            free(desc);
+            dvmAbort();
+        }
+        dvmDbgPostLocationEvent(method, pc - method->insns, thisPtr,
+            eventFlags);
+    }
+}
+
+/*
+ * Recover the "this" pointer from the current interpreted method.  "this"
+ * is always in "in0" for non-static methods.
+ *
+ * The "ins" start at (#of registers - #of ins).  Note in0 != v0.
+ *
+ * This works because "dx" guarantees that it will work.  It's probably
+ * fairly common to have a virtual method that doesn't use its "this"
+ * pointer, in which case we're potentially wasting a register.  However,
+ * the debugger doesn't treat "this" as just another argument.  For
+ * example, events (such as breakpoints) can be enabled for specific
+ * values of "this".  There is also a separate StackFrame.ThisObject call
+ * in JDWP that is expected to work for any non-native non-static method.
+ *
+ * Because we need it when setting up debugger event filters, we want to
+ * be able to do this quickly.
+ */
+Object* dvmGetThisPtr(const Method* method, const u4* fp)
+{
+    if (dvmIsStaticMethod(method))
+        return NULL;
+    return (Object*)fp[method->registersSize - method->insSize];
+}
+
+
+#if defined(WITH_TRACKREF_CHECKS)
+/*
+ * Verify that all internally-tracked references have been released.  If
+ * they haven't, print them and abort the VM.
+ *
+ * "debugTrackedRefStart" indicates how many refs were on the list when
+ * we were first invoked.
+ */
+void dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
+    int debugTrackedRefStart)
+{
+    if (dvmReferenceTableEntries(&self->internalLocalRefTable)
+        != (size_t) debugTrackedRefStart)
+    {
+        char* desc;
+        Object** top;
+        int count;
+
+        count = dvmReferenceTableEntries(&self->internalLocalRefTable);
+
+        LOGE("TRACK: unreleased internal reference (prev=%d total=%d)",
+            debugTrackedRefStart, count);
+        desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGE("       current method is %s.%s %s", method->clazz->descriptor,
+            method->name, desc);
+        free(desc);
+        top = self->internalLocalRefTable.table + debugTrackedRefStart;
+        while (top < self->internalLocalRefTable.nextEntry) {
+            LOGE("  %p (%s)",
+                 *top,
+                 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : "");
+            top++;
+        }
+        dvmDumpThread(self, false);
+
+        dvmAbort();
+    }
+    //LOGI("TRACK OK");
+}
+#endif
+
+
+#ifdef LOG_INSTR
+/*
+ * Dump the v-registers.  Sent to the ILOG log tag.
+ */
+void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly)
+{
+    int i, localCount;
+
+    localCount = method->registersSize - method->insSize;
+
+    LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):", framePtr);
+    for (i = method->registersSize-1; i >= 0; i--) {
+        if (i >= localCount) {
+            LOG(LOG_VERBOSE, LOG_TAG"i", "  v%-2d in%-2d : 0x%08x",
+                i, i-localCount, framePtr[i]);
+        } else {
+            if (inOnly) {
+                LOG(LOG_VERBOSE, LOG_TAG"i", "  [...]");
+                break;
+            }
+            const char* name = "";
+#if 0   // "locals" structure has changed -- need to rewrite this
+            int j;
+            DexFile* pDexFile = method->clazz->pDexFile;
+            const DexCode* pDexCode = dvmGetMethodCode(method);
+            int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
+            const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode);
+            for (j = 0; j < localsSize, j++) {
+                if (locals[j].registerNum == (u4) i) {
+                    name = dvmDexStringStr(locals[j].pName);
+                    break;
+                }
+            }
+#endif
+            LOG(LOG_VERBOSE, LOG_TAG"i", "  v%-2d      : 0x%08x %s",
+                i, framePtr[i], name);
+        }
+    }
+}
+#endif
+
+
+/*
+ * ===========================================================================
+ *      Entry point and general support functions
+ * ===========================================================================
+ */
+
+/*
+ * Construct an s4 from two consecutive half-words of switch data.
+ * This needs to check endianness because the DEX optimizer only swaps
+ * half-words in instruction stream.
+ *
+ * "switchData" must be 32-bit aligned.
+ */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline s4 s4FromSwitchData(const void* switchData) {
+    return *(s4*) switchData;
+}
+#else
+static inline s4 s4FromSwitchData(const void* switchData) {
+    u2* data = switchData;
+    return data[0] | (((s4) data[1]) << 16);
+}
+#endif
+
+/*
+ * Find the matching case.  Returns the offset to the handler instructions.
+ *
+ * Returns 3 if we don't find a match (it's the size of the packed-switch
+ * instruction).
+ */
+s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal)
+{
+    const int kInstrLen = 3;
+    u2 size;
+    s4 firstKey;
+    const s4* entries;
+
+    /*
+     * Packed switch data format:
+     *  ushort ident = 0x0100   magic value
+     *  ushort size             number of entries in the table
+     *  int first_key           first (and lowest) switch case value
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (4+size*2) 16-bit code units.
+     */
+    if (*switchData++ != kPackedSwitchSignature) {
+        /* should have been caught by verifier */
+        dvmThrowInternalError("bad packed switch magic");
+        return kInstrLen;
+    }
+
+    size = *switchData++;
+    assert(size > 0);
+
+    firstKey = *switchData++;
+    firstKey |= (*switchData++) << 16;
+
+    if (testVal < firstKey || testVal >= firstKey + size) {
+        LOGVV("Value %d not found in switch (%d-%d)",
+            testVal, firstKey, firstKey+size-1);
+        return kInstrLen;
+    }
+
+    /* The entries are guaranteed to be aligned on a 32-bit boundary;
+     * we can treat them as a native int array.
+     */
+    entries = (const s4*) switchData;
+    assert(((u4)entries & 0x3) == 0);
+
+    assert(testVal - firstKey >= 0 && testVal - firstKey < size);
+    LOGVV("Value %d found in slot %d (goto 0x%02x)",
+        testVal, testVal - firstKey,
+        s4FromSwitchData(&entries[testVal - firstKey]));
+    return s4FromSwitchData(&entries[testVal - firstKey]);
+}
+
+/*
+ * Find the matching case.  Returns the offset to the handler instructions.
+ *
+ * Returns 3 if we don't find a match (it's the size of the sparse-switch
+ * instruction).
+ */
+s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
+{
+    const int kInstrLen = 3;
+    u2 size;
+    const s4* keys;
+    const s4* entries;
+
+    /*
+     * Sparse switch data format:
+     *  ushort ident = 0x0200   magic value
+     *  ushort size             number of entries in the table; > 0
+     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (2+size*4) 16-bit code units.
+     */
+
+    if (*switchData++ != kSparseSwitchSignature) {
+        /* should have been caught by verifier */
+        dvmThrowInternalError("bad sparse switch magic");
+        return kInstrLen;
+    }
+
+    size = *switchData++;
+    assert(size > 0);
+
+    /* The keys are guaranteed to be aligned on a 32-bit boundary;
+     * we can treat them as a native int array.
+     */
+    keys = (const s4*) switchData;
+    assert(((u4)keys & 0x3) == 0);
+
+    /* The entries are guaranteed to be aligned on a 32-bit boundary;
+     * we can treat them as a native int array.
+     */
+    entries = keys + size;
+    assert(((u4)entries & 0x3) == 0);
+
+    /*
+     * Binary-search through the array of keys, which are guaranteed to
+     * be sorted low-to-high.
+     */
+    int lo = 0;
+    int hi = size - 1;
+    while (lo <= hi) {
+        int mid = (lo + hi) >> 1;
+
+        s4 foundVal = s4FromSwitchData(&keys[mid]);
+        if (testVal < foundVal) {
+            hi = mid - 1;
+        } else if (testVal > foundVal) {
+            lo = mid + 1;
+        } else {
+            LOGVV("Value %d found in entry %d (goto 0x%02x)",
+                testVal, mid, s4FromSwitchData(&entries[mid]));
+            return s4FromSwitchData(&entries[mid]);
+        }
+    }
+
+    LOGVV("Value %d not found in switch", testVal);
+    return kInstrLen;
+}
+
+/*
+ * 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", width);
+        dvmAbort();
+        break;
+    }
+#endif
+}
+
+/*
+ * Fill the array with predefined constant values.
+ *
+ * Returns true if job is completed, otherwise false to indicate that
+ * an exception has been thrown.
+ */
+bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData)
+{
+    u2 width;
+    u4 size;
+
+    if (arrayObj == NULL) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+    assert (!IS_CLASS_FLAG_SET(((Object *)arrayObj)->clazz,
+                               CLASS_ISOBJECTARRAY));
+
+    /*
+     * Array data table format:
+     *  ushort ident = 0x0300   magic value
+     *  ushort width            width of each element in the table
+     *  uint   size             number of elements in the table
+     *  ubyte  data[size*width] table of data values (may contain a single-byte
+     *                          padding at the end)
+     *
+     * Total size is 4+(width * size + 1)/2 16-bit code units.
+     */
+    if (arrayData[0] != kArrayDataSignature) {
+        dvmThrowInternalError("bad array data magic");
+        return false;
+    }
+
+    width = arrayData[1];
+    size = arrayData[2] | (((u4)arrayData[3]) << 16);
+
+    if (size > arrayObj->length) {
+        dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, size);
+        return false;
+    }
+    copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
+    return true;
+}
+
+/*
+ * Find the concrete method that corresponds to "methodIdx".  The code in
+ * "method" is executing invoke-method with "thisClass" as its first argument.
+ *
+ * Returns NULL with an exception raised on failure.
+ */
+Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
+    const Method* method, DvmDex* methodClassDex)
+{
+    Method* absMethod;
+    Method* methodToCall;
+    int i, vtableIndex;
+
+    /*
+     * Resolve the method.  This gives us the abstract method from the
+     * interface class declaration.
+     */
+    absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx);
+    if (absMethod == NULL) {
+        absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx);
+        if (absMethod == NULL) {
+            LOGV("+ unknown method");
+            return NULL;
+        }
+    }
+
+    /* make sure absMethod->methodIndex means what we think it means */
+    assert(dvmIsAbstractMethod(absMethod));
+
+    /*
+     * Run through the "this" object's iftable.  Find the entry for
+     * absMethod's class, then use absMethod->methodIndex to find
+     * the method's entry.  The value there is the offset into our
+     * vtable of the actual method to execute.
+     *
+     * The verifier does not guarantee that objects stored into
+     * interface references actually implement the interface, so this
+     * check cannot be eliminated.
+     */
+    for (i = 0; i < thisClass->iftableCount; i++) {
+        if (thisClass->iftable[i].clazz == absMethod->clazz)
+            break;
+    }
+    if (i == thisClass->iftableCount) {
+        /* impossible in verified DEX, need to check for it in unverified */
+        dvmThrowIncompatibleClassChangeError("interface not implemented");
+        return NULL;
+    }
+
+    assert(absMethod->methodIndex <
+        thisClass->iftable[i].clazz->virtualMethodCount);
+
+    vtableIndex =
+        thisClass->iftable[i].methodIndexArray[absMethod->methodIndex];
+    assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount);
+    methodToCall = thisClass->vtable[vtableIndex];
+
+#if 0
+    /* this can happen when there's a stale class file */
+    if (dvmIsAbstractMethod(methodToCall)) {
+        dvmThrowAbstractMethodError("interface method not implemented");
+        return NULL;
+    }
+#else
+    assert(!dvmIsAbstractMethod(methodToCall) ||
+        methodToCall->nativeFunc != NULL);
+#endif
+
+    LOGVV("+++ interface=%s.%s concrete=%s.%s",
+        absMethod->clazz->descriptor, absMethod->name,
+        methodToCall->clazz->descriptor, methodToCall->name);
+    assert(methodToCall != NULL);
+
+    return methodToCall;
+}
+
+
+
+/*
+ * Helpers for dvmThrowVerificationError().
+ *
+ * Each returns a newly-allocated string.
+ */
+#define kThrowShow_accessFromClass     1
+static std::string classNameFromIndex(const Method* method, int ref,
+    VerifyErrorRefType refType, int flags)
+{
+    const DvmDex* pDvmDex = method->clazz->pDvmDex;
+    if (refType == VERIFY_ERROR_REF_FIELD) {
+        /* get class ID from field ID */
+        const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
+        ref = pFieldId->classIdx;
+    } else if (refType == VERIFY_ERROR_REF_METHOD) {
+        /* get class ID from method ID */
+        const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
+        ref = pMethodId->classIdx;
+    }
+
+    const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
+    std::string dotClassName(dvmHumanReadableDescriptor(className));
+    if (flags == 0) {
+        return dotClassName;
+    }
+
+    std::string result;
+    if ((flags & kThrowShow_accessFromClass) != 0) {
+        result += "tried to access class " + dotClassName;
+        result += " from class " + dvmHumanReadableDescriptor(method->clazz->descriptor);
+    } else {
+        assert(false);      // should've been caught above
+    }
+
+    return result;
+}
+static std::string fieldNameFromIndex(const Method* method, int ref,
+    VerifyErrorRefType refType, int flags)
+{
+    if (refType != VERIFY_ERROR_REF_FIELD) {
+        LOGW("Expected ref type %d, got %d", VERIFY_ERROR_REF_FIELD, refType);
+        return NULL;    /* no message */
+    }
+
+    const DvmDex* pDvmDex = method->clazz->pDvmDex;
+    const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
+    const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
+    const char* fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
+
+    std::string dotName(dvmHumanReadableDescriptor(className));
+
+    if ((flags & kThrowShow_accessFromClass) != 0) {
+        std::string result;
+        result += "tried to access field ";
+        result += dotName + "." + fieldName;
+        result += " from class ";
+        result += dvmHumanReadableDescriptor(method->clazz->descriptor);
+        return result;
+    }
+    return dotName + "." + fieldName;
+}
+static std::string methodNameFromIndex(const Method* method, int ref,
+    VerifyErrorRefType refType, int flags)
+{
+    if (refType != VERIFY_ERROR_REF_METHOD) {
+        LOGW("Expected ref type %d, got %d", VERIFY_ERROR_REF_METHOD,refType);
+        return NULL;    /* no message */
+    }
+
+    const DvmDex* pDvmDex = method->clazz->pDvmDex;
+    const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
+    const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
+    const char* methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
+
+    std::string dotName(dvmHumanReadableDescriptor(className));
+
+    if ((flags & kThrowShow_accessFromClass) != 0) {
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        std::string result;
+        result += "tried to access method ";
+        result += dotName + "." + methodName + ":" + desc;
+        result += " from class " + dvmHumanReadableDescriptor(method->clazz->descriptor);
+        free(desc);
+        return result;
+    }
+    return dotName + "." + methodName;
+}
+
+/*
+ * 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.  It
+ * has two parts, an error code and an indication of the reference type.
+ */
+void dvmThrowVerificationError(const Method* method, int kind, int ref)
+{
+    int errorPart = kind & ~(0xff << kVerifyErrorRefTypeShift);
+    int errorRefPart = kind >> kVerifyErrorRefTypeShift;
+    VerifyError errorKind = static_cast<VerifyError>(errorPart);
+    VerifyErrorRefType refType = static_cast<VerifyErrorRefType>(errorRefPart);
+    ClassObject* exceptionClass = gDvm.exVerifyError;
+    std::string msg;
+
+    switch ((VerifyError) errorKind) {
+    case VERIFY_ERROR_NO_CLASS:
+        exceptionClass = gDvm.exNoClassDefFoundError;
+        msg = classNameFromIndex(method, ref, refType, 0);
+        break;
+    case VERIFY_ERROR_NO_FIELD:
+        exceptionClass = gDvm.exNoSuchFieldError;
+        msg = fieldNameFromIndex(method, ref, refType, 0);
+        break;
+    case VERIFY_ERROR_NO_METHOD:
+        exceptionClass = gDvm.exNoSuchMethodError;
+        msg = methodNameFromIndex(method, ref, refType, 0);
+        break;
+    case VERIFY_ERROR_ACCESS_CLASS:
+        exceptionClass = gDvm.exIllegalAccessError;
+        msg = classNameFromIndex(method, ref, refType,
+            kThrowShow_accessFromClass);
+        break;
+    case VERIFY_ERROR_ACCESS_FIELD:
+        exceptionClass = gDvm.exIllegalAccessError;
+        msg = fieldNameFromIndex(method, ref, refType,
+            kThrowShow_accessFromClass);
+        break;
+    case VERIFY_ERROR_ACCESS_METHOD:
+        exceptionClass = gDvm.exIllegalAccessError;
+        msg = methodNameFromIndex(method, ref, refType,
+            kThrowShow_accessFromClass);
+        break;
+    case VERIFY_ERROR_CLASS_CHANGE:
+        exceptionClass = gDvm.exIncompatibleClassChangeError;
+        msg = classNameFromIndex(method, ref, refType, 0);
+        break;
+    case VERIFY_ERROR_INSTANTIATION:
+        exceptionClass = gDvm.exInstantiationError;
+        msg = classNameFromIndex(method, ref, refType, 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(exceptionClass, msg.c_str());
+}
+
+/*
+ * Update interpBreak for a single thread.
+ */
+void updateInterpBreak(Thread* thread, ExecutionSubModes subMode, bool enable)
+{
+    InterpBreak oldValue, newValue;
+    do {
+        oldValue = newValue = thread->interpBreak;
+        newValue.ctl.breakFlags = kInterpNoBreak;  // Assume full reset
+        if (enable)
+            newValue.ctl.subMode |= subMode;
+        else
+            newValue.ctl.subMode &= ~subMode;
+        if (newValue.ctl.subMode & SINGLESTEP_BREAK_MASK)
+            newValue.ctl.breakFlags |= kInterpSingleStep;
+        if (newValue.ctl.subMode & SAFEPOINT_BREAK_MASK)
+            newValue.ctl.breakFlags |= kInterpSafePoint;
+        newValue.ctl.curHandlerTable = (newValue.ctl.breakFlags) ?
+            thread->altHandlerTable : thread->mainHandlerTable;
+    } while (dvmQuasiAtomicCas64(oldValue.all, newValue.all,
+             &thread->interpBreak.all) != 0);
+}
+
+/*
+ * Update interpBreak for all threads.
+ */
+void updateAllInterpBreak(ExecutionSubModes subMode, bool enable)
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+
+    dvmLockThreadList(self);
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        updateInterpBreak(thread, subMode, enable);
+    }
+    dvmUnlockThreadList();
+}
+
+/*
+ * Update the normal and debugger suspend counts for a thread.
+ * threadSuspendCount must be acquired before calling this to
+ * ensure a clean update of suspendCount, dbgSuspendCount and
+ * sumThreadSuspendCount.
+ *
+ * CLEANUP TODO: Currently only the JIT is using sumThreadSuspendCount.
+ * Move under WITH_JIT ifdefs.
+*/
+void dvmAddToSuspendCounts(Thread* thread, int delta, int dbgDelta)
+{
+    thread->suspendCount += delta;
+    thread->dbgSuspendCount += dbgDelta;
+    updateInterpBreak(thread, kSubModeSuspendPending,
+                      (thread->suspendCount != 0));
+    // Update the global suspend count total
+    gDvm.sumThreadSuspendCount += delta;
+}
+
+
+void dvmDisableSubMode(Thread* thread, ExecutionSubModes subMode)
+{
+    updateInterpBreak(thread, subMode, false);
+}
+
+void dvmEnableSubMode(Thread* thread, ExecutionSubModes subMode)
+{
+    updateInterpBreak(thread, subMode, true);
+}
+
+void dvmEnableAllSubMode(ExecutionSubModes subMode)
+{
+    updateAllInterpBreak(subMode, true);
+}
+
+void dvmDisableAllSubMode(ExecutionSubModes subMode)
+{
+    updateAllInterpBreak(subMode, false);
+}
+
+/*
+ * Do a sanity check on interpreter state saved to Thread.
+ * A failure here doesn't necessarily mean that something is wrong,
+ * so this code should only be used during development to suggest
+ * a possible problem.
+ */
+void dvmCheckInterpStateConsistency()
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+    uint8_t breakFlags;
+    uint8_t subMode;
+    void* handlerTable;
+
+    dvmLockThreadList(self);
+    breakFlags = self->interpBreak.ctl.breakFlags;
+    subMode = self->interpBreak.ctl.subMode;
+    handlerTable = self->interpBreak.ctl.curHandlerTable;
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (subMode != thread->interpBreak.ctl.subMode) {
+            LOGD("Warning: subMode mismatch - %#x:%#x, tid[%d]",
+                subMode,thread->interpBreak.ctl.subMode,thread->threadId);
+         }
+        if (breakFlags != thread->interpBreak.ctl.breakFlags) {
+            LOGD("Warning: breakFlags mismatch - %#x:%#x, tid[%d]",
+                breakFlags,thread->interpBreak.ctl.breakFlags,thread->threadId);
+         }
+        if (handlerTable != thread->interpBreak.ctl.curHandlerTable) {
+            LOGD("Warning: curHandlerTable mismatch - %#x:%#x, tid[%d]",
+                (int)handlerTable,(int)thread->interpBreak.ctl.curHandlerTable,
+                thread->threadId);
+         }
+#if defined(WITH_JIT)
+         if (thread->pJitProfTable != gDvmJit.pProfTable) {
+             LOGD("Warning: pJitProfTable mismatch - %#x:%#x, tid[%d]",
+                  (int)thread->pJitProfTable,(int)gDvmJit.pProfTable,
+                  thread->threadId);
+         }
+         if (thread->jitThreshold != gDvmJit.threshold) {
+             LOGD("Warning: jitThreshold mismatch - %#x:%#x, tid[%d]",
+                  (int)thread->jitThreshold,(int)gDvmJit.threshold,
+                  thread->threadId);
+         }
+#endif
+    }
+    dvmUnlockThreadList();
+}
+
+/*
+ * Arm a safepoint callback for a thread.  If funct is null,
+ * clear any pending callback.
+ * TODO: only gc is currently using this feature, and will have
+ * at most a single outstanding callback request.  Until we need
+ * something more capable and flexible, enforce this limit.
+ */
+void dvmArmSafePointCallback(Thread* thread, SafePointCallback funct,
+                             void* arg)
+{
+    dvmLockMutex(&thread->callbackMutex);
+    if ((funct == NULL) || (thread->callback == NULL)) {
+        thread->callback = funct;
+        thread->callbackArg = arg;
+        if (funct != NULL) {
+            dvmEnableSubMode(thread, kSubModeCallbackPending);
+        } else {
+            dvmDisableSubMode(thread, kSubModeCallbackPending);
+        }
+    } else {
+        // Already armed.  Different?
+        if ((funct != thread->callback) ||
+            (arg != thread->callbackArg)) {
+            // Yes - report failure and die
+            LOGE("ArmSafePointCallback failed, thread %d", thread->threadId);
+            dvmUnlockMutex(&thread->callbackMutex);
+            dvmAbort();
+        }
+    }
+    dvmUnlockMutex(&thread->callbackMutex);
+}
+
+/*
+ * One-time initialization at thread creation.  Here we initialize
+ * useful constants.
+ */
+void dvmInitInterpreterState(Thread* self)
+{
+#if defined(WITH_JIT)
+    /*
+     * 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,
+        dvmJitToInterpTraceSelect,
+#if defined(WITH_SELF_VERIFICATION)
+        dvmJitToInterpBackwardBranch,
+#else
+        NULL,
+#endif
+    };
+#endif
+
+    // Begin initialization
+    self->cardTable = gDvm.biasedCardTableBase;
+#if defined(WITH_JIT)
+    // One-time initializations
+    self->jitToInterpEntries = jitToInterpEntries;
+    self->icRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
+    self->pProfileCountdown = &gDvmJit.profileCountdown;
+    // Jit state that can change
+    dvmJitUpdateThreadStateSingle(self);
+#endif
+    dvmInitializeInterpBreak(self);
+}
+
+/*
+ * For a newly-created thread, we need to start off with interpBreak
+ * set to any existing global modes.  The caller must hold the
+ * thread list lock.
+ */
+void dvmInitializeInterpBreak(Thread* thread)
+{
+    if (gDvm.instructionCountEnableCount > 0) {
+        dvmEnableSubMode(thread, kSubModeInstCounting);
+    }
+    if (dvmIsMethodTraceActive()) {
+        dvmEnableSubMode(thread, kSubModeMethodTrace);
+    }
+    if (gDvm.emulatorTraceEnableCount > 0) {
+        dvmEnableSubMode(thread, kSubModeEmulatorTrace);
+    }
+    if (gDvm.debuggerActive) {
+        dvmEnableSubMode(thread, kSubModeDebuggerActive);
+    }
+#if 0
+    // Debugging stress mode - force checkBefore
+    dvmEnableSubMode(thread, kSubModeCheckAlways);
+#endif
+}
+
+/*
+ * Inter-instruction handler invoked in between instruction interpretations
+ * to handle exceptional events such as debugging housekeeping, instruction
+ * count profiling, JIT trace building, etc.  Dalvik PC has been exported
+ * prior to call, but Thread copy of dPC & fp are not current.
+ */
+void dvmCheckBefore(const u2 *pc, u4 *fp, Thread* self)
+{
+    const Method* method = self->interpSave.method;
+    assert(self->interpBreak.ctl.breakFlags != 0);
+    assert(pc >= method->insns && pc <
+           method->insns + dvmGetMethodInsnsSize(method));
+
+#if 0
+    /*
+     * When we hit a specific method, enable verbose instruction logging.
+     * Sometimes it's helpful to use the debugger attach as a trigger too.
+     */
+    if (*pIsMethodEntry) {
+        static const char* cd = "Landroid/test/Arithmetic;";
+        static const char* mn = "shiftTest2";
+        static const char* sg = "()V";
+
+        if (/*self->interpBreak.ctl.subMode & kSubModeDebuggerActive &&*/
+            strcmp(method->clazz->descriptor, cd) == 0 &&
+            strcmp(method->name, mn) == 0 &&
+            strcmp(method->shorty, sg) == 0)
+        {
+            LOGW("Reached %s.%s, enabling verbose mode",
+                method->clazz->descriptor, method->name);
+            android_setMinPriority(LOG_TAG"i", ANDROID_LOG_VERBOSE);
+            dumpRegs(method, fp, true);
+        }
+
+        if (!gDvm.debuggerActive)
+            *pIsMethodEntry = false;
+    }
+#endif
+
+    /* Safe point handling */
+    if (self->suspendCount ||
+        (self->interpBreak.ctl.subMode & kSubModeCallbackPending)) {
+        // Are we are a safe point?
+        int flags;
+        flags = dexGetFlagsFromOpcode(dexOpcodeFromCodeUnit(*pc));
+        if (flags & (VERIFY_GC_INST_MASK & ~kInstrCanThrow)) {
+            // Yes, at a safe point.  Pending callback?
+            if (self->interpBreak.ctl.subMode & kSubModeCallbackPending) {
+                SafePointCallback callback;
+                void* arg;
+                // Get consistent funct/arg pair
+                dvmLockMutex(&self->callbackMutex);
+                callback = self->callback;
+                arg = self->callbackArg;
+                dvmUnlockMutex(&self->callbackMutex);
+                // Update Thread structure
+                self->interpSave.pc = pc;
+                self->interpSave.curFrame = fp;
+                if (callback != NULL) {
+                    // Do the callback
+                    if (!callback(self,arg)) {
+                        // disarm
+                        dvmArmSafePointCallback(self, NULL, NULL);
+                    }
+                }
+            }
+            // Need to suspend?
+            if (self->suspendCount) {
+                dvmExportPC(pc, fp);
+                dvmCheckSuspendPending(self);
+            }
+        }
+    }
+
+    if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+        updateDebugger(method, pc, fp, self);
+    }
+    if (gDvm.instructionCountEnableCount != 0) {
+        /*
+         * Count up the #of executed instructions.  This isn't synchronized
+         * for thread-safety; if we need that we should make this
+         * thread-local and merge counts into the global area when threads
+         * exit (perhaps suspending all other threads GC-style and pulling
+         * the data out of them).
+         */
+        gDvm.executedInstrCounts[GET_OPCODE(*pc)]++;
+    }
+
+
+#if defined(WITH_TRACKREF_CHECKS)
+    dvmInterpCheckTrackedRefs(self, method,
+                              self->interpSave.debugTrackedRefStart);
+#endif
+
+#if defined(WITH_JIT)
+    // Does the JIT need anything done now?
+    if (self->interpBreak.ctl.subMode &
+            (kSubModeJitTraceBuild | kSubModeJitSV)) {
+        // Are we building a trace?
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {
+            dvmCheckJit(pc, self);
+        }
+
+#if defined(WITH_SELF_VERIFICATION)
+        // Are we replaying a trace?
+        if (self->interpBreak.ctl.subMode & kSubModeJitSV) {
+            dvmCheckSelfVerification(pc, self);
+        }
+#endif
+    }
+#endif
+
+    /*
+     * CountedStep processing.  NOTE: must be the last here to allow
+     * preceeding special case handler to manipulate single-step count.
+     */
+    if (self->interpBreak.ctl.subMode & kSubModeCountedStep) {
+        if (self->singleStepCount == 0) {
+            // We've exhausted our single step count
+            dvmDisableSubMode(self, kSubModeCountedStep);
+#if defined(WITH_JIT)
+#if 0
+            /*
+             * For debugging.  If jitResumeDPC is non-zero, then
+             * we expect to return to a trace in progress.   There
+             * are valid reasons why we wouldn't (such as an exception
+             * throw), but here we can keep track.
+             */
+            if (self->jitResumeDPC != NULL) {
+                if (self->jitResumeDPC == pc) {
+                    if (self->jitResumeNPC != NULL) {
+                        LOGD("SS return to trace - pc:%#x to 0x:%x",
+                             (int)pc, (int)self->jitResumeNPC);
+                    } else {
+                        LOGD("SS return to interp - pc:%#x",(int)pc);
+                    }
+                } else {
+                    LOGD("SS failed to return.  Expected %#x, now at %#x",
+                         (int)self->jitResumeDPC, (int)pc);
+                }
+            }
+#endif
+#if 0
+            // TODO - fix JIT single-stepping resume mode (b/5551114)
+            // self->jitResumeNPC needs to be cleared in callPrep
+
+            // If we've got a native return and no other reasons to
+            // remain in singlestep/break mode, do a long jump
+            if (self->jitResumeNPC != NULL &&
+                self->interpBreak.ctl.breakFlags == 0) {
+                assert(self->jitResumeDPC == pc);
+                self->jitResumeDPC = NULL;
+                dvmJitResumeTranslation(self, pc, fp);
+                // Doesn't return
+                dvmAbort();
+            }
+            // In case resume is blocked by non-zero breakFlags, clear
+            // jitResumeNPC here.
+            self->jitResumeNPC = NULL;
+            self->jitResumeDPC = NULL;
+            self->inJitCodeCache = NULL;
+#endif
+#endif
+        } else {
+            self->singleStepCount--;
+#if defined(WITH_JIT)
+            if ((self->singleStepCount > 0) && (self->jitResumeNPC != NULL)) {
+                /*
+                 * Direct return to an existing translation following a
+                 * single step is valid only if we step once.  If we're
+                 * here, an additional step was added so we need to invalidate
+                 * the return to translation.
+                 */
+                self->jitResumeNPC = NULL;
+                self->inJitCodeCache = NULL;
+            }
+#endif
+        }
+    }
+}
+
+/*
+ * Main interpreter loop entry point.
+ *
+ * This begins executing code at the start of "method".  On exit, "pResult"
+ * holds the return value of the method (or, if "method" returns NULL, it
+ * holds an undefined value).
+ *
+ * The interpreted stack frame, which holds the method arguments, has
+ * already been set up.
+ */
+void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
+{
+    InterpSaveState interpSaveState;
+    ExecutionSubModes savedSubModes;
+
+#if defined(WITH_JIT)
+    /* Target-specific save/restore */
+    double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT];
+    /*
+     * If the previous VM left the code cache through single-stepping the
+     * inJitCodeCache flag will be set when the VM is re-entered (for example,
+     * in self-verification mode we single-step NEW_INSTANCE which may re-enter
+     * the VM through findClassFromLoaderNoInit). Because of that, we cannot
+     * assert that self->inJitCodeCache is NULL here.
+     */
+#endif
+
+    /*
+     * Save interpreter state from previous activation, linking
+     * new to last.
+     */
+    interpSaveState = self->interpSave;
+    self->interpSave.prev = &interpSaveState;
+    /*
+     * Strip out and save any flags that should not be inherited by
+     * nested interpreter activation.
+     */
+    savedSubModes = (ExecutionSubModes)(
+              self->interpBreak.ctl.subMode & LOCAL_SUBMODE);
+    if (savedSubModes != kSubModeNormal) {
+        dvmDisableSubMode(self, savedSubModes);
+    }
+#if defined(WITH_JIT)
+    dvmJitCalleeSave(calleeSave);
+#endif
+
+
+#if defined(WITH_TRACKREF_CHECKS)
+    self->interpSave.debugTrackedRefStart =
+        dvmReferenceTableEntries(&self->internalLocalRefTable);
+#endif
+    self->debugIsMethodEntry = true;
+#if defined(WITH_JIT)
+    dvmJitCalleeSave(calleeSave);
+    /* Initialize the state to kJitNot */
+    self->jitState = kJitNot;
+#endif
+
+    /*
+     * Initialize working state.
+     *
+     * No need to initialize "retval".
+     */
+    self->interpSave.method = method;
+    self->interpSave.curFrame = (u4*) self->interpSave.curFrame;
+    self->interpSave.pc = method->insns;
+
+    assert(!dvmIsNativeMethod(method));
+
+    /*
+     * Make sure the class is ready to go.  Shouldn't be possible to get
+     * here otherwise.
+     */
+    if (method->clazz->status < CLASS_INITIALIZING ||
+        method->clazz->status == CLASS_ERROR)
+    {
+        LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)",
+            method->clazz->descriptor, method->clazz->status);
+        dvmDumpThread(self, false);
+        dvmAbort();
+    }
+
+    typedef void (*Interpreter)(Thread*);
+    Interpreter stdInterp;
+    if (gDvm.executionMode == kExecutionModeInterpFast)
+        stdInterp = dvmMterpStd;
+#if defined(WITH_JIT)
+    else if (gDvm.executionMode == kExecutionModeJit)
+        stdInterp = dvmMterpStd;
+#endif
+    else
+        stdInterp = dvmInterpretPortable;
+
+    // Call the interpreter
+    (*stdInterp)(self);
+
+    *pResult = self->interpSave.retval;
+
+    /* Restore interpreter state from previous activation */
+    self->interpSave = interpSaveState;
+#if defined(WITH_JIT)
+    dvmJitCalleeRestore(calleeSave);
+#endif
+    if (savedSubModes != kSubModeNormal) {
+        dvmEnableSubMode(self, savedSubModes);
+    }
+}
diff --git a/vm/interp/Interp.h b/vm/interp/Interp.h
new file mode 100644
index 0000000..060f86a
--- /dev/null
+++ b/vm/interp/Interp.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik interpreter public definitions.
+ */
+#ifndef DALVIK_INTERP_INTERP_H_
+#define DALVIK_INTERP_INTERP_H_
+
+/*
+ * Stash the dalvik PC in the frame.  Called  during interpretation.
+ */
+INLINE void dvmExportPC(const u2* pc, const u4* fp)
+{
+    SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc;
+}
+
+/*
+ * Extract the Dalvik opcode
+ */
+#define GET_OPCODE(_inst) (((_inst & 0xff) == OP_DISPATCH_FF) ? \
+                           (0x100 + ((_inst >> 8) & 0xff)) : (_inst & 0xff))
+
+/*
+ * Interpreter entry point.  Call here after setting up the interpreted
+ * stack (most code will want to get here via dvmCallMethod().)
+ */
+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.
+ */
+extern "C" void dvmThrowVerificationError(const Method* method,
+                                          int kind, int ref);
+
+/*
+ * One-time initialization and shutdown.
+ */
+bool dvmBreakpointStartup(void);
+void dvmBreakpointShutdown(void);
+void dvmInitInterpreterState(Thread* self);
+
+/*
+ * Breakpoint implementation.
+ */
+void dvmInitBreakpoints();
+void dvmAddBreakAddr(Method* method, unsigned int instrOffset);
+void dvmClearBreakAddr(Method* method, unsigned int instrOffset);
+bool dvmAddSingleStep(Thread* thread, int size, int depth);
+void dvmClearSingleStep(Thread* thread);
+
+/*
+ * Recover the opcode that was replaced by a breakpoint.
+ */
+extern "C" u1 dvmGetOriginalOpcode(const u2* addr);
+
+/*
+ * Flush any breakpoints associated with methods in "clazz".
+ */
+void dvmFlushBreakpoints(ClassObject* clazz);
+
+/*
+ * Debugger support
+ */
+extern "C" void dvmCheckBefore(const u2 *dPC, u4 *fp, Thread* self);
+extern "C" void dvmReportExceptionThrow(Thread* self, Object* exception);
+extern "C" void dvmReportPreNativeInvoke(const Method* methodToCall, Thread* self, u4* fp);
+extern "C" void dvmReportPostNativeInvoke(const Method* methodToCall, Thread* self, u4* fp);
+extern "C" void dvmReportInvoke(Thread* self, const Method* methodToCall);
+extern "C" void dvmReportReturn(Thread* self);
+
+/*
+ * InterpBreak & subMode control
+ */
+void dvmDisableSubMode(Thread* thread, ExecutionSubModes subMode);
+extern "C" void dvmEnableSubMode(Thread* thread, ExecutionSubModes subMode);
+void dvmDisableAllSubMode(ExecutionSubModes subMode);
+void dvmEnableAllSubMode(ExecutionSubModes subMode);
+void dvmAddToSuspendCounts(Thread* thread, int delta, int dbgDelta);
+void dvmCheckInterpStateConsistency();
+void dvmInitializeInterpBreak(Thread* thread);
+
+/*
+ * Register a callback to occur at the next safe point for a single thread.
+ * If funct is NULL, the previous registration is cancelled.
+ *
+ * The callback prototype is:
+ *        bool funct(Thread* thread, void* arg)
+ *
+ *  If funct returns false, the callback will be disarmed.  If true,
+ *  it will stay in effect.
+ */
+void dvmArmSafePointCallback(Thread* thread, SafePointCallback funct,
+                             void* arg);
+
+
+#ifndef DVM_NO_ASM_INTERP
+extern void* dvmAsmInstructionStart[];
+extern void* dvmAsmAltInstructionStart[];
+#endif
+
+#endif  // DALVIK_INTERP_INTERP_H_
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
new file mode 100644
index 0000000..acec648
--- /dev/null
+++ b/vm/interp/InterpDefs.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+/*
+ * Dalvik interpreter definitions.  These are internal to the interpreter.
+ *
+ * This includes defines, types, function declarations, and inline functions
+ * that are common to all interpreter implementations.
+ *
+ * Functions and globals declared here are defined in Interp.c.
+ */
+#ifndef DALVIK_INTERP_DEFS_H_
+#define DALVIK_INTERP_DEFS_H_
+
+#if defined(WITH_JIT)
+/*
+ * Size of save area for callee-save FP regs, which are not automatically
+ * saved by interpreter main because it doesn't use them (but Jit'd code
+ * may). Save/restore routine is defined by target, and size should
+ * be >= max needed by any target.
+ */
+#define JIT_CALLEE_SAVE_DOUBLE_COUNT 8
+
+#endif
+
+/*
+ * Portable interpreter.
+ */
+extern void dvmInterpretPortable(Thread* self);
+
+/*
+ * "mterp" interpreter.
+ */
+extern void dvmMterpStd(Thread* self);
+
+/*
+ * Get the "this" pointer from the current frame.
+ */
+Object* dvmGetThisPtr(const Method* method, const u4* fp);
+
+/*
+ * Verify that our tracked local references are valid.
+ */
+void dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
+    int debugTrackedRefStart);
+
+/*
+ * Process switch statement.
+ */
+extern "C" s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal);
+extern "C" s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal);
+
+/*
+ * Process fill-array-data.
+ */
+extern "C" bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,
+                                  const u2* arrayData);
+
+/*
+ * Find an interface method.
+ */
+Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
+    const Method* method, DvmDex* methodClassDex);
+
+/*
+ * Determine if the debugger or profiler is currently active.
+ */
+static inline bool dvmDebuggerOrProfilerActive()
+{
+    return gDvm.debuggerActive || gDvm.activeProfilers != 0;
+}
+
+#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()
+{
+    return (gDvmJit.pProfTable != NULL) || dvmDebuggerOrProfilerActive();
+}
+
+/*
+ * Hide the translations and stick with the interpreter as long as one of the
+ * following conditions is true.
+ */
+static inline bool dvmJitHideTranslation()
+{
+    return (gDvm.sumThreadSuspendCount != 0) ||
+           (gDvmJit.codeCacheFull == true) ||
+           (gDvmJit.pProfTable == NULL);
+}
+
+#endif
+
+#endif  // DALVIK_INTERP_DEFS_H_
diff --git a/vm/interp/InterpState.h b/vm/interp/InterpState.h
new file mode 100644
index 0000000..37b7fdd
--- /dev/null
+++ b/vm/interp/InterpState.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2011 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 interpreter definitions.  These are internal to the interpreter.
+ *
+ * This includes defines, types, function declarations, and inline functions
+ * that are common to all interpreter implementations.
+ *
+ * Functions and globals declared here are defined in Interp.c.
+ */
+#ifndef DALVIK_INTERP_STATE_H_
+#define DALVIK_INTERP_STATE_H_
+
+/*
+ * Execution mode, e.g. interpreter vs. JIT.
+ */
+enum ExecutionMode {
+    kExecutionModeUnknown = 0,
+    kExecutionModeInterpPortable,
+    kExecutionModeInterpFast,
+#if defined(WITH_JIT)
+    kExecutionModeJit,
+#endif
+};
+
+/*
+ * Execution sub modes, e.g. debugging, profiling, etc.
+ * Treated as bit flags for fast access.  These values are used directly
+ * by assembly code in the mterp interpeter and may also be used by
+ * code generated by the JIT.  Take care when changing.
+ */
+enum ExecutionSubModes {
+    kSubModeNormal            = 0x0000,   /* No active subMode */
+    kSubModeMethodTrace       = 0x0001,
+    kSubModeEmulatorTrace     = 0x0002,
+    kSubModeInstCounting      = 0x0004,
+    kSubModeDebuggerActive    = 0x0008,
+    kSubModeSuspendPending    = 0x0010,
+    kSubModeCallbackPending   = 0x0020,
+    kSubModeCountedStep       = 0x0040,
+    kSubModeCheckAlways       = 0x0080,
+    kSubModeJitTraceBuild     = 0x4000,
+    kSubModeJitSV             = 0x8000,
+    kSubModeDebugProfile   = (kSubModeMethodTrace |
+                              kSubModeEmulatorTrace |
+                              kSubModeInstCounting |
+                              kSubModeDebuggerActive)
+};
+
+/*
+ * Interpreter break flags.  When set, causes the interpreter to
+ * break from normal execution and invoke the associated callback
+ * handler.
+ */
+
+enum InterpBreakFlags {
+    kInterpNoBreak            = 0x00,    /* Don't check */
+    kInterpSingleStep         = 0x01,    /* Check between each inst */
+    kInterpSafePoint          = 0x02,    /* Check at safe points */
+};
+
+/*
+ * Mapping between subModes and required check intervals.  Note: in
+ * the future we might want to make this mapping target-dependent.
+ */
+#define SINGLESTEP_BREAK_MASK ( kSubModeInstCounting | \
+                                kSubModeDebuggerActive | \
+                                kSubModeCountedStep | \
+                                kSubModeCheckAlways | \
+                                kSubModeJitSV | \
+                                kSubModeJitTraceBuild )
+
+#define SAFEPOINT_BREAK_MASK  ( kSubModeSuspendPending | \
+                                kSubModeCallbackPending )
+
+typedef bool (*SafePointCallback)(struct Thread* thread, void* arg);
+
+/*
+ * Identify which break and submode flags should be local
+ * to an interpreter activation.
+ */
+#define LOCAL_SUBMODE (kSubModeJitTraceBuild)
+
+struct InterpSaveState {
+    const u2*       pc;         // Dalvik PC
+    u4*             curFrame;   // Dalvik frame pointer
+    const Method    *method;    // Method being executed
+    DvmDex*         methodClassDex;
+    JValue          retval;
+    void*           bailPtr;
+#if defined(WITH_TRACKREF_CHECKS)
+    int             debugTrackedRefStart;
+#else
+    int             unused;        // Keep struct size constant
+#endif
+    struct InterpSaveState* prev;  // To follow nested activations
+} __attribute__ ((__packed__));
+
+#ifdef WITH_JIT
+/*
+ * NOTE: Only entry points dispatched via [self + #offset] are put
+ * in this struct, and there are six of them:
+ * 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. If the destination trace doesn't exist, update
+ *    the profile count for that Dalvik PC.
+ * 2) dvmJitToInterpNoChain: similar to dvmJitToInterpNormal but chaining is
+ *    not performed.
+ * 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: Similar to dvmJitToInterpNormal except for the
+ *    profiling operation. If the new Dalvik PC is dominated by an already
+ *    translated trace, directly request a new translation if the destinaion
+ *    trace doesn't exist.
+ * 6) dvmJitToBackwardBranch: special case for SELF_VERIFICATION when the
+ *    destination Dalvik PC is included by the trace itself.
+ */
+struct JitToInterpEntries {
+    void (*dvmJitToInterpNormal)(void);
+    void (*dvmJitToInterpNoChain)(void);
+    void (*dvmJitToInterpPunt)(void);
+    void (*dvmJitToInterpSingleStep)(void);
+    void (*dvmJitToInterpTraceSelect)(void);
+#if defined(WITH_SELF_VERIFICATION)
+    void (*dvmJitToInterpBackwardBranch)(void);
+#else
+    void (*unused)(void);  // Keep structure size constant
+#endif
+};
+
+/* States of the interpreter when serving a JIT-related request */
+enum JitState {
+    /* Entering states in the debug interpreter */
+    kJitNot = 0,               // Non-JIT related reasons */
+    kJitTSelectRequest = 1,    // Request a trace (subject to filtering)
+    kJitTSelectRequestHot = 2, // Request a hot trace (bypass the filter)
+    kJitSelfVerification = 3,  // Self Verification Mode
+
+    /* Operational states in the debug interpreter */
+    kJitTSelect = 4,           // Actively selecting a trace
+    kJitTSelectEnd = 5,        // Done with the trace - wrap it up
+    kJitDone = 6,              // No further JIT actions for interpBreak
+};
+
+#if defined(WITH_SELF_VERIFICATION)
+enum SelfVerificationState {
+    kSVSIdle = 0,           // Idle
+    kSVSStart = 1,          // Shadow space set up, running compiled code
+    kSVSPunt = 2,           // Exiting compiled code by punting
+    kSVSSingleStep = 3,     // Exiting compiled code by single stepping
+    kSVSNoProfile = 4,      // Exiting compiled code and don't collect profiles
+    kSVSTraceSelect = 5,    // Exiting compiled code and compile the next pc
+    kSVSNormal = 6,         // Exiting compiled code normally
+    kSVSNoChain = 7,        // Exiting compiled code by no chain
+    kSVSBackwardBranch = 8, // Exiting compiled code with backward branch trace
+    kSVSDebugInterp = 9,    // Normal state restored, running debug interpreter
+};
+#endif
+
+/* Number of entries in the 2nd level JIT profiler filter cache */
+#define JIT_TRACE_THRESH_FILTER_SIZE 32
+/* Number of low dalvik pc address bits to include in 2nd level filter key */
+#define JIT_TRACE_THRESH_FILTER_PC_BITS 4
+#define MAX_JIT_RUN_LEN 64
+
+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
+};
+
+/*
+ * Element of a Jit trace description. If the isCode bit is set, it describes
+ * a contiguous sequence of Dalvik byte codes.
+ */
+struct JitCodeDesc {
+    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
+    u2 startOffset;          // Starting offset for trace run
+};
+
+/*
+ * A complete list of trace runs passed to the compiler looks like the
+ * following:
+ *   frag1
+ *   frag2
+ *   frag3
+ *   meta1
+ *     :
+ *   metan
+ *   frag4
+ *
+ * frags 1-4 have the "isCode" field set and describe the location/length of
+ * real code traces, while metas 1-n are misc information.
+ * The meaning of the meta content is loosely defined. It is usually the code
+ * fragment right before the first meta field (frag3 in this case) to
+ * understand and parse them. Frag4 could be a dummy one with 0 "numInsts" but
+ * the "runEnd" field set.
+ *
+ * For example, if a trace run contains a method inlining target, the class
+ * descriptor/loader of "this" and the currently resolved method pointer are
+ * three instances of meta information stored there.
+ */
+struct JitTraceRun {
+    union {
+        JitCodeDesc frag;
+        void*       meta;
+    } info;
+    u4 isCode:1;
+    u4 unused:31;
+};
+
+#endif
+
+#endif  // DALVIK_INTERP_STATE_H_
diff --git a/vm/interp/Jit.cpp b/vm/interp/Jit.cpp
new file mode 100644
index 0000000..494aae1
--- /dev/null
+++ b/vm/interp/Jit.cpp
@@ -0,0 +1,1509 @@
+/*
+ * 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 "libdex/DexOpcodes.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>
+
+#if defined(WITH_SELF_VERIFICATION)
+/* Allocate space for per-thread ShadowSpace data structures */
+void* dvmSelfVerificationShadowSpaceAlloc(Thread* self)
+{
+    self->shadowSpace = (ShadowSpace*) calloc(1, sizeof(ShadowSpace));
+    if (self->shadowSpace == NULL)
+        return NULL;
+
+    self->shadowSpace->registerSpaceSize = REG_SPACE;
+    self->shadowSpace->registerSpace =
+        (int*) calloc(self->shadowSpace->registerSpaceSize, sizeof(int));
+
+    return self->shadowSpace->registerSpace;
+}
+
+/* Free per-thread ShadowSpace data structures */
+void dvmSelfVerificationShadowSpaceFree(Thread* self)
+{
+    free(self->shadowSpace->registerSpace);
+    free(self->shadowSpace);
+}
+
+/*
+ * Save out PC, FP, thread state, and registers to shadow space.
+ * Return a pointer to the shadow space for JIT to use.
+ *
+ * The set of saved state from the Thread structure is:
+ *     pc  (Dalvik PC)
+ *     fp  (Dalvik FP)
+ *     retval
+ *     method
+ *     methodClassDex
+ *     interpStackEnd
+ */
+void* dvmSelfVerificationSaveState(const u2* pc, u4* fp,
+                                   Thread* self, int targetTrace)
+{
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    unsigned preBytes = self->interpSave.method->outsSize*4 +
+        sizeof(StackSaveArea);
+    unsigned postBytes = self->interpSave.method->registersSize*4;
+
+    //LOGD("### selfVerificationSaveState(%d) pc: %#x fp: %#x",
+    //    self->threadId, (int)pc, (int)fp);
+
+    if (shadowSpace->selfVerificationState != kSVSIdle) {
+        LOGD("~~~ Save: INCORRECT PREVIOUS STATE(%d): %d",
+            self->threadId, shadowSpace->selfVerificationState);
+        LOGD("********** SHADOW STATE DUMP **********");
+        LOGD("PC: %#x FP: %#x", (int)pc, (int)fp);
+    }
+    shadowSpace->selfVerificationState = kSVSStart;
+
+    // Dynamically grow shadow register space if necessary
+    if (preBytes + postBytes > shadowSpace->registerSpaceSize * sizeof(u4)) {
+        free(shadowSpace->registerSpace);
+        shadowSpace->registerSpaceSize = (preBytes + postBytes) / sizeof(u4);
+        shadowSpace->registerSpace =
+            (int*) calloc(shadowSpace->registerSpaceSize, sizeof(u4));
+    }
+
+    // Remember original state
+    shadowSpace->startPC = pc;
+    shadowSpace->fp = fp;
+    shadowSpace->retval = self->interpSave.retval;
+    shadowSpace->interpStackEnd = self->interpStackEnd;
+
+    /*
+     * Store the original method here in case the trace ends with a
+     * return/invoke, the last method.
+     */
+    shadowSpace->method = self->interpSave.method;
+    shadowSpace->methodClassDex = self->interpSave.methodClassDex;
+
+    shadowSpace->shadowFP = shadowSpace->registerSpace +
+                            shadowSpace->registerSpaceSize - postBytes/4;
+
+    self->interpSave.curFrame = (u4*)shadowSpace->shadowFP;
+    self->interpStackEnd = (u1*)shadowSpace->registerSpace;
+
+    // Create a copy of the stack
+    memcpy(((char*)shadowSpace->shadowFP)-preBytes, ((char*)fp)-preBytes,
+        preBytes+postBytes);
+
+    // Setup the shadowed heap space
+    shadowSpace->heapSpaceTail = shadowSpace->heapSpace;
+
+    // Reset trace length
+    shadowSpace->traceLength = 0;
+
+    return shadowSpace;
+}
+
+/*
+ * Save ending PC, FP and compiled code exit point to shadow space.
+ * Return a pointer to the shadow space for JIT to restore state.
+ */
+void* dvmSelfVerificationRestoreState(const u2* pc, u4* fp,
+                                      SelfVerificationState exitState,
+                                      Thread* self)
+{
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    shadowSpace->endPC = pc;
+    shadowSpace->endShadowFP = fp;
+    shadowSpace->jitExitState = exitState;
+
+    //LOGD("### selfVerificationRestoreState(%d) pc: %#x fp: %#x endPC: %#x",
+    //    self->threadId, (int)shadowSpace->startPC, (int)shadowSpace->fp,
+    //    (int)pc);
+
+    if (shadowSpace->selfVerificationState != kSVSStart) {
+        LOGD("~~~ Restore: INCORRECT PREVIOUS STATE(%d): %d",
+            self->threadId, shadowSpace->selfVerificationState);
+        LOGD("********** SHADOW STATE DUMP **********");
+        LOGD("Dalvik PC: %#x endPC: %#x", (int)shadowSpace->startPC,
+            (int)shadowSpace->endPC);
+        LOGD("Interp FP: %#x", (int)shadowSpace->fp);
+        LOGD("Shadow FP: %#x endFP: %#x", (int)shadowSpace->shadowFP,
+            (int)shadowSpace->endShadowFP);
+    }
+
+    // Special case when punting after a single instruction
+    if (exitState == kSVSPunt && pc == shadowSpace->startPC) {
+        shadowSpace->selfVerificationState = kSVSIdle;
+    } else {
+        shadowSpace->selfVerificationState = exitState;
+    }
+
+    /* Restore state before returning */
+    self->interpSave.pc = shadowSpace->startPC;
+    self->interpSave.curFrame = shadowSpace->fp;
+    self->interpSave.method = shadowSpace->method;
+    self->interpSave.methodClassDex = shadowSpace->methodClassDex;
+    self->interpSave.retval = shadowSpace->retval;
+    self->interpStackEnd = shadowSpace->interpStackEnd;
+
+    return shadowSpace;
+}
+
+/* Print contents of virtual registers */
+static void selfVerificationPrintRegisters(int* addr, int* addrRef,
+                                           int numWords)
+{
+    int i;
+    for (i = 0; i < numWords; i++) {
+        LOGD("(v%d) 0x%8x%s", i, addr[i], addr[i] != addrRef[i] ? " X" : "");
+    }
+}
+
+/* Print values maintained in shadowSpace */
+static void selfVerificationDumpState(const u2* pc, Thread* self)
+{
+    ShadowSpace* shadowSpace = self->shadowSpace;
+    StackSaveArea* stackSave = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    int frameBytes = (int) shadowSpace->registerSpace +
+                     shadowSpace->registerSpaceSize*4 -
+                     (int) shadowSpace->shadowFP;
+    int localRegs = 0;
+    int frameBytes2 = 0;
+    if ((uintptr_t)self->interpSave.curFrame < (uintptr_t)shadowSpace->fp) {
+        localRegs = (stackSave->method->registersSize -
+                     stackSave->method->insSize)*4;
+        frameBytes2 = (int) shadowSpace->fp -
+                      (int)self->interpSave.curFrame - localRegs;
+    }
+    LOGD("********** SHADOW STATE DUMP **********");
+    LOGD("CurrentPC: %#x, Offset: 0x%04x", (int)pc,
+        (int)(pc - stackSave->method->insns));
+    LOGD("Class: %s", shadowSpace->method->clazz->descriptor);
+    LOGD("Method: %s", shadowSpace->method->name);
+    LOGD("Dalvik PC: %#x endPC: %#x", (int)shadowSpace->startPC,
+        (int)shadowSpace->endPC);
+    LOGD("Interp FP: %#x endFP: %#x", (int)shadowSpace->fp,
+        (int)self->interpSave.curFrame);
+    LOGD("Shadow FP: %#x endFP: %#x", (int)shadowSpace->shadowFP,
+        (int)shadowSpace->endShadowFP);
+    LOGD("Frame1 Bytes: %d Frame2 Local: %d Bytes: %d", frameBytes,
+        localRegs, frameBytes2);
+    LOGD("Trace length: %d State: %d", shadowSpace->traceLength,
+        shadowSpace->selfVerificationState);
+}
+
+/* Print decoded instructions in the current trace */
+static void selfVerificationDumpTrace(const u2* pc, Thread* self)
+{
+    ShadowSpace* shadowSpace = self->shadowSpace;
+    StackSaveArea* stackSave = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    int i, addr, offset;
+    DecodedInstruction *decInsn;
+
+    LOGD("********** SHADOW TRACE DUMP **********");
+    for (i = 0; i < shadowSpace->traceLength; i++) {
+        addr = shadowSpace->trace[i].addr;
+        offset =  (int)((u2*)addr - stackSave->method->insns);
+        decInsn = &(shadowSpace->trace[i].decInsn);
+        /* Not properly decoding instruction, some registers may be garbage */
+        LOGD("%#x: (0x%04x) %s",
+            addr, offset, dexGetOpcodeName(decInsn->opcode));
+    }
+}
+
+/* Code is forced into this spin loop when a divergence is detected */
+static void selfVerificationSpinLoop(ShadowSpace *shadowSpace)
+{
+    const u2 *startPC = shadowSpace->startPC;
+    JitTraceDescription* desc = dvmCopyTraceDescriptor(startPC, NULL);
+    if (desc) {
+        dvmCompilerWorkEnqueue(startPC, kWorkOrderTraceDebug, desc);
+        /*
+         * This function effectively terminates the VM right here, so not
+         * freeing the desc pointer when the enqueuing fails is acceptable.
+         */
+    }
+    gDvmJit.selfVerificationSpin = true;
+    while(gDvmJit.selfVerificationSpin) sleep(10);
+}
+
+/*
+ * If here, we're re-interpreting an instruction that was included
+ * in a trace that was just executed.  This routine is called for
+ * each instruction in the original trace, and compares state
+ * when it reaches the end point.
+ *
+ * TUNING: the interpretation mechanism now supports a counted
+ * single-step mechanism.  If we were to associate an instruction
+ * count with each trace exit, we could just single-step the right
+ * number of cycles and then compare.  This would improve detection
+ * of control divergences, as well as (slightly) simplify this code.
+ */
+void dvmCheckSelfVerification(const u2* pc, Thread* self)
+{
+    ShadowSpace *shadowSpace = self->shadowSpace;
+    SelfVerificationState state = shadowSpace->selfVerificationState;
+
+    DecodedInstruction decInsn;
+    dexDecodeInstruction(pc, &decInsn);
+
+    //LOGD("### DbgIntp(%d): PC: %#x endPC: %#x state: %d len: %d %s",
+    //    self->threadId, (int)pc, (int)shadowSpace->endPC, state,
+    //    shadowSpace->traceLength, dexGetOpcodeName(decInsn.opcode));
+
+    if (state == kSVSIdle || state == kSVSStart) {
+        LOGD("~~~ DbgIntrp: INCORRECT PREVIOUS STATE(%d): %d",
+            self->threadId, state);
+        selfVerificationDumpState(pc, self);
+        selfVerificationDumpTrace(pc, self);
+    }
+
+    /*
+     * Generalize the self verification state to kSVSDebugInterp unless the
+     * entry reason is kSVSBackwardBranch or kSVSSingleStep.
+     */
+    if (state != kSVSBackwardBranch && state != kSVSSingleStep) {
+        shadowSpace->selfVerificationState = kSVSDebugInterp;
+    }
+
+    /*
+     * Check if the current pc matches the endPC. Only check for non-zero
+     * trace length when backward branches are involved.
+     */
+    if (pc == shadowSpace->endPC &&
+        (state == kSVSDebugInterp || state == kSVSSingleStep ||
+         (state == kSVSBackwardBranch && shadowSpace->traceLength != 0))) {
+
+        shadowSpace->selfVerificationState = kSVSIdle;
+
+        /* Check register space */
+        int frameBytes = (int) shadowSpace->registerSpace +
+                         shadowSpace->registerSpaceSize*4 -
+                         (int) shadowSpace->shadowFP;
+        if (memcmp(shadowSpace->fp, shadowSpace->shadowFP, frameBytes)) {
+            if (state == kSVSBackwardBranch) {
+                /* State mismatch on backward branch - try one more iteration */
+                shadowSpace->selfVerificationState = kSVSDebugInterp;
+                goto log_and_continue;
+            }
+            LOGD("~~~ DbgIntp(%d): REGISTERS DIVERGENCE!", self->threadId);
+            selfVerificationDumpState(pc, self);
+            selfVerificationDumpTrace(pc, self);
+            LOGD("*** Interp Registers: addr: %#x bytes: %d",
+                (int)shadowSpace->fp, frameBytes);
+            selfVerificationPrintRegisters((int*)shadowSpace->fp,
+                                           (int*)shadowSpace->shadowFP,
+                                           frameBytes/4);
+            LOGD("*** Shadow Registers: addr: %#x bytes: %d",
+                (int)shadowSpace->shadowFP, frameBytes);
+            selfVerificationPrintRegisters((int*)shadowSpace->shadowFP,
+                                           (int*)shadowSpace->fp,
+                                           frameBytes/4);
+            selfVerificationSpinLoop(shadowSpace);
+        }
+        /* Check new frame if it exists (invokes only) */
+        if ((uintptr_t)self->interpSave.curFrame < (uintptr_t)shadowSpace->fp) {
+            StackSaveArea* stackSave =
+                SAVEAREA_FROM_FP(self->interpSave.curFrame);
+            int localRegs = (stackSave->method->registersSize -
+                             stackSave->method->insSize)*4;
+            int frameBytes2 = (int) shadowSpace->fp -
+                              (int) self->interpSave.curFrame - localRegs;
+            if (memcmp(((char*)self->interpSave.curFrame)+localRegs,
+                ((char*)shadowSpace->endShadowFP)+localRegs, frameBytes2)) {
+                if (state == kSVSBackwardBranch) {
+                    /*
+                     * State mismatch on backward branch - try one more
+                     * iteration.
+                     */
+                    shadowSpace->selfVerificationState = kSVSDebugInterp;
+                    goto log_and_continue;
+                }
+                LOGD("~~~ DbgIntp(%d): REGISTERS (FRAME2) DIVERGENCE!",
+                    self->threadId);
+                selfVerificationDumpState(pc, self);
+                selfVerificationDumpTrace(pc, self);
+                LOGD("*** Interp Registers: addr: %#x l: %d bytes: %d",
+                    (int)self->interpSave.curFrame, localRegs, frameBytes2);
+                selfVerificationPrintRegisters((int*)self->interpSave.curFrame,
+                                               (int*)shadowSpace->endShadowFP,
+                                               (frameBytes2+localRegs)/4);
+                LOGD("*** Shadow Registers: addr: %#x l: %d bytes: %d",
+                    (int)shadowSpace->endShadowFP, localRegs, frameBytes2);
+                selfVerificationPrintRegisters((int*)shadowSpace->endShadowFP,
+                                               (int*)self->interpSave.curFrame,
+                                               (frameBytes2+localRegs)/4);
+                selfVerificationSpinLoop(shadowSpace);
+            }
+        }
+
+        /* Check memory space */
+        bool memDiff = false;
+        ShadowHeap* heapSpacePtr;
+        for (heapSpacePtr = shadowSpace->heapSpace;
+             heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+            int memData = *((unsigned int*) heapSpacePtr->addr);
+            if (heapSpacePtr->data != memData) {
+                if (state == kSVSBackwardBranch) {
+                    /*
+                     * State mismatch on backward branch - try one more
+                     * iteration.
+                     */
+                    shadowSpace->selfVerificationState = kSVSDebugInterp;
+                    goto log_and_continue;
+                }
+                LOGD("~~~ DbgIntp(%d): MEMORY DIVERGENCE!", self->threadId);
+                LOGD("Addr: %#x Intrp Data: %#x Jit Data: %#x",
+                    heapSpacePtr->addr, memData, heapSpacePtr->data);
+                selfVerificationDumpState(pc, self);
+                selfVerificationDumpTrace(pc, self);
+                memDiff = true;
+            }
+        }
+        if (memDiff) selfVerificationSpinLoop(shadowSpace);
+
+
+        /*
+         * Success.  If this shadowed trace included a single-stepped
+         * instruction, we need to stay in the interpreter for one
+         * more interpretation before resuming.
+         */
+        if (state == kSVSSingleStep) {
+            assert(self->jitResumeNPC != NULL);
+            assert(self->singleStepCount == 0);
+            self->singleStepCount = 1;
+            dvmEnableSubMode(self, kSubModeCountedStep);
+        }
+
+        /*
+         * Switch off shadow replay mode.  The next shadowed trace
+         * execution will turn it back on.
+         */
+        dvmDisableSubMode(self, kSubModeJitSV);
+
+        self->jitState = kJitDone;
+        return;
+    }
+log_and_continue:
+    /* If end not been reached, make sure max length not exceeded */
+    if (shadowSpace->traceLength >= JIT_MAX_TRACE_LEN) {
+        LOGD("~~~ DbgIntp(%d): CONTROL DIVERGENCE!", self->threadId);
+        LOGD("startPC: %#x endPC: %#x currPC: %#x",
+            (int)shadowSpace->startPC, (int)shadowSpace->endPC, (int)pc);
+        selfVerificationDumpState(pc, self);
+        selfVerificationDumpTrace(pc, self);
+        selfVerificationSpinLoop(shadowSpace);
+        return;
+    }
+    /* Log the instruction address and decoded instruction for debug */
+    shadowSpace->trace[shadowSpace->traceLength].addr = (int)pc;
+    shadowSpace->trace[shadowSpace->traceLength].decInsn = decInsn;
+    shadowSpace->traceLength++;
+}
+#endif
+
+/*
+ * 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 thread 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 = NULL;
+    dvmJitUpdateThreadStateAll();
+}
+
+#if defined(WITH_JIT_TUNING)
+/* Convenience function to increment counter from assembly code */
+void dvmBumpNoChain(int from)
+{
+    gDvmJit.noChainExit[from]++;
+}
+
+/* Convenience function to increment counter from assembly code */
+void dvmBumpNormal()
+{
+    gDvmJit.normalExit++;
+}
+
+/* Convenience function to increment counter from assembly code */
+void dvmBumpPunt(int from)
+{
+    gDvmJit.puntExit++;
+}
+#endif
+
+/* Dumps debugging & tuning stats to the log */
+void dvmJitStats()
+{
+    int i;
+    int hit;
+    int not_hit;
+    int chains;
+    int stubs;
+    if (gDvmJit.pJitEntryTable) {
+        for (i=0, stubs=chains=hit=not_hit=0;
+             i < (int) gDvmJit.jitTableSize;
+             i++) {
+            if (gDvmJit.pJitEntryTable[i].dPC != 0) {
+                hit++;
+                if (gDvmJit.pJitEntryTable[i].codeAddress ==
+                      dvmCompilerGetInterpretTemplate())
+                    stubs++;
+            } else
+                not_hit++;
+            if (gDvmJit.pJitEntryTable[i].u.info.chain != gDvmJit.jitTableSize)
+                chains++;
+        }
+        LOGD("JIT: table size is %d, entries used is %d",
+             gDvmJit.jitTableSize,  gDvmJit.jitTableEntriesUsed);
+        LOGD("JIT: %d traces, %d slots, %d chains, %d thresh, %s",
+             hit, not_hit + hit, chains, gDvmJit.threshold,
+             gDvmJit.blockingMode ? "Blocking" : "Non-blocking");
+
+#if defined(WITH_JIT_TUNING)
+        LOGD("JIT: Code cache patches: %d", gDvmJit.codeCachePatches);
+
+        LOGD("JIT: Lookups: %d hits, %d misses; %d normal, %d punt",
+             gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
+             gDvmJit.normalExit, gDvmJit.puntExit);
+
+        LOGD("JIT: ICHits: %d", gDvmICHitCount);
+
+        LOGD("JIT: noChainExit: %d IC miss, %d interp callsite, "
+             "%d switch overflow",
+             gDvmJit.noChainExit[kInlineCacheMiss],
+             gDvmJit.noChainExit[kCallsiteInterpreted],
+             gDvmJit.noChainExit[kSwitchOverflow]);
+
+        LOGD("JIT: ICPatch: %d init, %d rejected, %d lock-free, %d queued, "
+             "%d dropped",
+             gDvmJit.icPatchInit, gDvmJit.icPatchRejected,
+             gDvmJit.icPatchLockFree, gDvmJit.icPatchQueued,
+             gDvmJit.icPatchDropped);
+
+        LOGD("JIT: Invoke: %d mono, %d poly, %d native, %d return",
+             gDvmJit.invokeMonomorphic, gDvmJit.invokePolymorphic,
+             gDvmJit.invokeNative, gDvmJit.returnOp);
+        LOGD("JIT: Inline: %d mgetter, %d msetter, %d pgetter, %d psetter",
+             gDvmJit.invokeMonoGetterInlined, gDvmJit.invokeMonoSetterInlined,
+             gDvmJit.invokePolyGetterInlined, gDvmJit.invokePolySetterInlined);
+        LOGD("JIT: Total compilation time: %llu ms", gDvmJit.jitTime / 1000);
+        LOGD("JIT: Avg unit compilation time: %llu us",
+             gDvmJit.numCompilations == 0 ? 0 :
+             gDvmJit.jitTime / gDvmJit.numCompilations);
+        LOGD("JIT: Potential GC blocked by compiler: max %llu us / "
+             "avg %llu us (%d)",
+             gDvmJit.maxCompilerThreadBlockGCTime,
+             gDvmJit.numCompilerThreadBlockGC == 0 ?
+                 0 : gDvmJit.compilerThreadBlockGCTime /
+                     gDvmJit.numCompilerThreadBlockGC,
+             gDvmJit.numCompilerThreadBlockGC);
+#endif
+
+        LOGD("JIT: %d Translation chains, %d interp stubs",
+             gDvmJit.translationChains, stubs);
+        if (gDvmJit.profileMode == kTraceProfilingContinuous) {
+            dvmCompilerSortAndPrintTraceProfiles();
+        }
+    }
+}
+
+
+/* End current trace now & don't include current instruction */
+void dvmJitEndTraceSelect(Thread* self, const u2* dPC)
+{
+    if (self->jitState == kJitTSelect) {
+        self->jitState = kJitTSelectEnd;
+    }
+    if (self->jitState == kJitTSelectEnd) {
+        // Clean up and finish now.
+        dvmCheckJit(dPC, self);
+    }
+}
+
+/*
+ * Find an entry in the JitTable, creating if necessary.
+ * Returns null if table is full.
+ */
+static JitEntry *lookupAndAdd(const u2* dPC, bool callerLocked,
+                              bool isMethodEntry)
+{
+    u4 chainEndMarker = gDvmJit.jitTableSize;
+    u4 idx = dvmJitHash(dPC);
+
+    /*
+     * Walk the bucket chain to find an exact match for our PC and trace/method
+     * type
+     */
+    while ((gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) &&
+           ((gDvmJit.pJitEntryTable[idx].dPC != dPC) ||
+            (gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry !=
+             isMethodEntry))) {
+        idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
+    }
+
+    if (gDvmJit.pJitEntryTable[idx].dPC != dPC ||
+        gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry != isMethodEntry) {
+        /*
+         * 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 (perhaps even the dPC we're trying to enter).
+         */
+        if (!callerLocked)
+            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 common case).  Otherwise we're going
+         * to have to find a free slot and chain it.
+         */
+        ANDROID_MEMBAR_FULL(); /* Make sure we reload [].dPC after lock */
+        if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
+            u4 prev;
+            while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
+                if (gDvmJit.pJitEntryTable[idx].dPC == dPC &&
+                    gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry ==
+                        isMethodEntry) {
+                    /* Another thread got there first for this dPC */
+                    if (!callerLocked)
+                        dvmUnlockMutex(&gDvmJit.tableLock);
+                    return &gDvmJit.pJitEntryTable[idx];
+                }
+                idx = gDvmJit.pJitEntryTable[idx].u.info.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);
+            /* Linear walk to find a free cell and add it to the end */
+            prev = idx;
+            while (true) {
+                idx++;
+                if (idx == chainEndMarker)
+                    idx = 0;  /* Wraparound */
+                if ((gDvmJit.pJitEntryTable[idx].dPC == NULL) ||
+                    (idx == prev))
+                    break;
+            }
+            if (idx != prev) {
+                JitEntryInfoUnion oldValue;
+                JitEntryInfoUnion newValue;
+                /*
+                 * Although we hold the lock so that noone else will
+                 * be trying to update a chain field, the other fields
+                 * packed into the word may be in use by other threads.
+                 */
+                do {
+                    oldValue = gDvmJit.pJitEntryTable[prev].u;
+                    newValue = oldValue;
+                    newValue.info.chain = idx;
+                } while (android_atomic_release_cas(oldValue.infoWord,
+                        newValue.infoWord,
+                        &gDvmJit.pJitEntryTable[prev].u.infoWord) != 0);
+            }
+        }
+        if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
+            gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry = isMethodEntry;
+            /*
+             * Initialize codeAddress and allocate the slot.  Must
+             * happen in this order (since dPC is set, the entry is live.
+             */
+            android_atomic_release_store((int32_t)dPC,
+                 (volatile int32_t *)(void *)&gDvmJit.pJitEntryTable[idx].dPC);
+            gDvmJit.pJitEntryTable[idx].dPC = dPC;
+            gDvmJit.jitTableEntriesUsed++;
+        } else {
+            /* Table is full */
+            idx = chainEndMarker;
+        }
+        if (!callerLocked)
+            dvmUnlockMutex(&gDvmJit.tableLock);
+    }
+    return (idx == chainEndMarker) ? NULL : &gDvmJit.pJitEntryTable[idx];
+}
+
+/* Dump a trace description */
+void dvmJitDumpTraceDesc(JitTraceDescription *trace)
+{
+    int i;
+    bool done = false;
+    const u2* dpc;
+    const u2* dpcBase;
+    int curFrag = 0;
+    LOGD("===========================================");
+    LOGD("Trace dump %#x, Method %s off %#x",(int)trace,
+         trace->method->name,trace->trace[curFrag].info.frag.startOffset);
+    dpcBase = trace->method->insns;
+    while (!done) {
+        DecodedInstruction decInsn;
+        if (trace->trace[curFrag].isCode) {
+            LOGD("Frag[%d]- Insts: %d, start: %#x, hint: %#x, end: %d",
+                 curFrag, trace->trace[curFrag].info.frag.numInsts,
+                 trace->trace[curFrag].info.frag.startOffset,
+                 trace->trace[curFrag].info.frag.hint,
+                 trace->trace[curFrag].info.frag.runEnd);
+            dpc = dpcBase + trace->trace[curFrag].info.frag.startOffset;
+            for (i=0; i<trace->trace[curFrag].info.frag.numInsts; i++) {
+                dexDecodeInstruction(dpc, &decInsn);
+                LOGD("    0x%04x - %s %#x",(dpc-dpcBase),
+                     dexGetOpcodeName(decInsn.opcode),(int)dpc);
+                dpc += dexGetWidthFromOpcode(decInsn.opcode);
+            }
+            if (trace->trace[curFrag].info.frag.runEnd) {
+                done = true;
+            }
+        } else {
+            LOGD("Frag[%d]- META info: 0x%08x", curFrag,
+                 (int)trace->trace[curFrag].info.meta);
+        }
+        curFrag++;
+    }
+    LOGD("-------------------------------------------");
+}
+
+/*
+ * Append the class ptr of "this" and the current method ptr to the current
+ * trace. That is, the trace runs will contain the following components:
+ *  + trace run that ends with an invoke (existing entry)
+ *  + thisClass (new)
+ *  + calleeMethod (new)
+ */
+static void insertClassMethodInfo(Thread* self,
+                                  const ClassObject* thisClass,
+                                  const Method* calleeMethod,
+                                  const DecodedInstruction* insn)
+{
+    int currTraceRun = ++self->currTraceRun;
+    self->trace[currTraceRun].info.meta = thisClass ?
+                                    (void *) thisClass->descriptor : NULL;
+    self->trace[currTraceRun].isCode = false;
+
+    currTraceRun = ++self->currTraceRun;
+    self->trace[currTraceRun].info.meta = thisClass ?
+                                    (void *) thisClass->classLoader : NULL;
+    self->trace[currTraceRun].isCode = false;
+
+    currTraceRun = ++self->currTraceRun;
+    self->trace[currTraceRun].info.meta = (void *) calleeMethod;
+    self->trace[currTraceRun].isCode = false;
+}
+
+/*
+ * Check if the next instruction following the invoke is a move-result and if
+ * so add it to the trace. That is, this will add the trace run that includes
+ * the move-result to the trace list.
+ *
+ *  + trace run that ends with an invoke (existing entry)
+ *  + thisClass (existing entry)
+ *  + calleeMethod (existing entry)
+ *  + move result (new)
+ *
+ * lastPC, len, offset are all from the preceding invoke instruction
+ */
+static void insertMoveResult(const u2 *lastPC, int len, int offset,
+                             Thread *self)
+{
+    DecodedInstruction nextDecInsn;
+    const u2 *moveResultPC = lastPC + len;
+
+    dexDecodeInstruction(moveResultPC, &nextDecInsn);
+    if ((nextDecInsn.opcode != OP_MOVE_RESULT) &&
+        (nextDecInsn.opcode != OP_MOVE_RESULT_WIDE) &&
+        (nextDecInsn.opcode != OP_MOVE_RESULT_OBJECT))
+        return;
+
+    /* We need to start a new trace run */
+    int currTraceRun = ++self->currTraceRun;
+    self->currRunHead = moveResultPC;
+    self->trace[currTraceRun].info.frag.startOffset = offset + len;
+    self->trace[currTraceRun].info.frag.numInsts = 1;
+    self->trace[currTraceRun].info.frag.runEnd = false;
+    self->trace[currTraceRun].info.frag.hint = kJitHintNone;
+    self->trace[currTraceRun].isCode = true;
+    self->totalTraceLen++;
+
+    self->currRunLen = dexGetWidthFromInstruction(moveResultPC);
+}
+
+/*
+ * Adds to the current trace request one instruction at a time, just
+ * before that instruction is interpreted.  This is the primary trace
+ * selection function.  NOTE: return instruction are handled a little
+ * 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.
+ */
+void dvmCheckJit(const u2* pc, Thread* self)
+{
+    const ClassObject *thisClass = self->callsiteClass;
+    const Method* curMethod = self->methodToCall;
+    int flags, len;
+    int allDone = false;
+    /* Stay in break/single-stop mode for the next instruction */
+    bool stayOneMoreInst = false;
+
+    /* Prepare to handle last PC and stage the current PC & method*/
+    const u2 *lastPC = self->lastPC;
+
+    self->lastPC = pc;
+
+    switch (self->jitState) {
+        int offset;
+        DecodedInstruction decInsn;
+        case kJitTSelect:
+            /* First instruction - just remember the PC and exit */
+            if (lastPC == NULL) break;
+            /* Grow the trace around the last PC if jitState is kJitTSelect */
+            dexDecodeInstruction(lastPC, &decInsn);
+
+            /*
+             * Treat {PACKED,SPARSE}_SWITCH as trace-ending instructions due
+             * to the amount of space it takes to generate the chaining
+             * cells.
+             */
+            if (self->totalTraceLen != 0 &&
+                (decInsn.opcode == OP_PACKED_SWITCH ||
+                 decInsn.opcode == OP_SPARSE_SWITCH)) {
+                self->jitState = kJitTSelectEnd;
+                break;
+            }
+
+#if defined(SHOW_TRACE)
+            LOGD("TraceGen: adding %s. lpc:%#x, pc:%#x",
+                 dexGetOpcodeName(decInsn.opcode), (int)lastPC, (int)pc);
+#endif
+            flags = dexGetFlagsFromOpcode(decInsn.opcode);
+            len = dexGetWidthFromInstruction(lastPC);
+            offset = lastPC - self->traceMethod->insns;
+            assert((unsigned) offset <
+                   dvmGetMethodInsnsSize(self->traceMethod));
+            if (lastPC != self->currRunHead + self->currRunLen) {
+                int currTraceRun;
+                /* We need to start a new trace run */
+                currTraceRun = ++self->currTraceRun;
+                self->currRunLen = 0;
+                self->currRunHead = (u2*)lastPC;
+                self->trace[currTraceRun].info.frag.startOffset = offset;
+                self->trace[currTraceRun].info.frag.numInsts = 0;
+                self->trace[currTraceRun].info.frag.runEnd = false;
+                self->trace[currTraceRun].info.frag.hint = kJitHintNone;
+                self->trace[currTraceRun].isCode = true;
+            }
+            self->trace[self->currTraceRun].info.frag.numInsts++;
+            self->totalTraceLen++;
+            self->currRunLen += len;
+
+            /*
+             * If the last instruction is an invoke, we will try to sneak in
+             * the move-result* (if existent) into a separate trace run.
+             */
+            {
+              int needReservedRun = (flags & kInstrInvoke) ? 1 : 0;
+
+              /* Will probably never hit this with the current trace builder */
+              if (self->currTraceRun ==
+                   (MAX_JIT_RUN_LEN - 1 - needReservedRun)) {
+                self->jitState = kJitTSelectEnd;
+              }
+            }
+
+            if (!dexIsGoto(flags) &&
+                  ((flags & (kInstrCanBranch |
+                             kInstrCanSwitch |
+                             kInstrCanReturn |
+                             kInstrInvoke)) != 0)) {
+                    self->jitState = kJitTSelectEnd;
+#if defined(SHOW_TRACE)
+                LOGD("TraceGen: ending on %s, basic block end",
+                     dexGetOpcodeName(decInsn.opcode));
+#endif
+
+                /*
+                 * If the current invoke is a {virtual,interface}, get the
+                 * current class/method pair into the trace as well.
+                 * If the next instruction is a variant of move-result, insert
+                 * it to the trace too.
+                 */
+                if (flags & kInstrInvoke) {
+                    insertClassMethodInfo(self, thisClass, curMethod,
+                                          &decInsn);
+                    insertMoveResult(lastPC, len, offset, self);
+                }
+            }
+            /* Break on throw or self-loop */
+            if ((decInsn.opcode == OP_THROW) || (lastPC == pc)){
+                self->jitState = kJitTSelectEnd;
+            }
+            if (self->totalTraceLen >= JIT_MAX_TRACE_LEN) {
+                self->jitState = kJitTSelectEnd;
+            }
+            if ((flags & kInstrCanReturn) != kInstrCanReturn) {
+                break;
+            }
+            else {
+                /*
+                 * Last instruction is a return - stay in the dbg interpreter
+                 * for one more instruction if it is a non-void return, since
+                 * we don't want to start a trace with move-result as the first
+                 * instruction (which is already included in the trace
+                 * containing the invoke.
+                 */
+                if (decInsn.opcode != OP_RETURN_VOID) {
+                    stayOneMoreInst = true;
+                }
+            }
+            /* NOTE: intentional fallthrough for returns */
+        case kJitTSelectEnd:
+            {
+                /* Empty trace - set to bail to interpreter */
+                if (self->totalTraceLen == 0) {
+                    dvmJitSetCodeAddr(self->currTraceHead,
+                                      dvmCompilerGetInterpretTemplate(),
+                                      dvmCompilerGetInterpretTemplateSet(),
+                                      false /* Not method entry */, 0);
+                    self->jitState = kJitDone;
+                    allDone = true;
+                    break;
+                }
+
+                int lastTraceDesc = self->currTraceRun;
+
+                /* Extend a new empty desc if the last slot is meta info */
+                if (!self->trace[lastTraceDesc].isCode) {
+                    lastTraceDesc = ++self->currTraceRun;
+                    self->trace[lastTraceDesc].info.frag.startOffset = 0;
+                    self->trace[lastTraceDesc].info.frag.numInsts = 0;
+                    self->trace[lastTraceDesc].info.frag.hint = kJitHintNone;
+                    self->trace[lastTraceDesc].isCode = true;
+                }
+
+                /* Mark the end of the trace runs */
+                self->trace[lastTraceDesc].info.frag.runEnd = true;
+
+                JitTraceDescription* desc =
+                   (JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
+                     sizeof(JitTraceRun) * (self->currTraceRun+1));
+
+                if (desc == NULL) {
+                    LOGE("Out of memory in trace selection");
+                    dvmJitStopTranslationRequests();
+                    self->jitState = kJitDone;
+                    allDone = true;
+                    break;
+                }
+
+                desc->method = self->traceMethod;
+                memcpy((char*)&(desc->trace[0]),
+                    (char*)&(self->trace[0]),
+                    sizeof(JitTraceRun) * (self->currTraceRun+1));
+#if defined(SHOW_TRACE)
+                LOGD("TraceGen:  trace done, adding to queue");
+                dvmJitDumpTraceDesc(desc);
+#endif
+                if (dvmCompilerWorkEnqueue(
+                       self->currTraceHead,kWorkOrderTrace,desc)) {
+                    /* Work order successfully enqueued */
+                    if (gDvmJit.blockingMode) {
+                        dvmCompilerDrainQueue();
+                    }
+                } else {
+                    /*
+                     * Make sure the descriptor for the abandoned work order is
+                     * freed.
+                     */
+                    free(desc);
+                }
+                self->jitState = kJitDone;
+                allDone = true;
+            }
+            break;
+        case kJitDone:
+            allDone = true;
+            break;
+        case kJitNot:
+            allDone = true;
+            break;
+        default:
+            LOGE("Unexpected JIT state: %d", self->jitState);
+            dvmAbort();
+            break;
+    }
+
+    /*
+     * If we're done with trace selection, switch off the control flags.
+     */
+     if (allDone) {
+         dvmDisableSubMode(self, kSubModeJitTraceBuild);
+         if (stayOneMoreInst) {
+             // Clear jitResumeNPC explicitly since we know we don't need it
+             // here.
+             self->jitResumeNPC = NULL;
+             // Keep going in single-step mode for at least one more inst
+             if (self->singleStepCount == 0)
+                 self->singleStepCount = 1;
+             dvmEnableSubMode(self, kSubModeCountedStep);
+         }
+     }
+     return;
+}
+
+JitEntry *dvmJitFindEntry(const u2* pc, bool isMethodEntry)
+{
+    int idx = dvmJitHash(pc);
+
+    /* Expect a high hit rate on 1st shot */
+    if ((gDvmJit.pJitEntryTable[idx].dPC == pc) &&
+        (gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry == isMethodEntry))
+        return &gDvmJit.pJitEntryTable[idx];
+    else {
+        int chainEndMarker = gDvmJit.jitTableSize;
+        while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
+            idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
+            if ((gDvmJit.pJitEntryTable[idx].dPC == pc) &&
+                (gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry ==
+                isMethodEntry))
+                return &gDvmJit.pJitEntryTable[idx];
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Walk through the JIT profile table and find the corresponding JIT code, in
+ * the specified format (ie trace vs method). This routine needs to be fast.
+ */
+void* getCodeAddrCommon(const u2* dPC, bool methodEntry)
+{
+    int idx = dvmJitHash(dPC);
+    const u2* pc = gDvmJit.pJitEntryTable[idx].dPC;
+    if (pc != NULL) {
+        bool hideTranslation = dvmJitHideTranslation();
+        if (pc == dPC &&
+            gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry == methodEntry) {
+            int offset = (gDvmJit.profileMode >= kTraceProfilingContinuous) ?
+                 0 : gDvmJit.pJitEntryTable[idx].u.info.profileOffset;
+            intptr_t codeAddress =
+                (intptr_t)gDvmJit.pJitEntryTable[idx].codeAddress;
+#if defined(WITH_JIT_TUNING)
+            gDvmJit.addrLookupsFound++;
+#endif
+            return hideTranslation || !codeAddress ?  NULL :
+                  (void *)(codeAddress + offset);
+        } else {
+            int chainEndMarker = gDvmJit.jitTableSize;
+            while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
+                idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
+                if (gDvmJit.pJitEntryTable[idx].dPC == dPC &&
+                    gDvmJit.pJitEntryTable[idx].u.info.isMethodEntry ==
+                        methodEntry) {
+                    int offset = (gDvmJit.profileMode >=
+                        kTraceProfilingContinuous) ? 0 :
+                        gDvmJit.pJitEntryTable[idx].u.info.profileOffset;
+                    intptr_t codeAddress =
+                        (intptr_t)gDvmJit.pJitEntryTable[idx].codeAddress;
+#if defined(WITH_JIT_TUNING)
+                    gDvmJit.addrLookupsFound++;
+#endif
+                    return hideTranslation || !codeAddress ? NULL :
+                        (void *)(codeAddress + offset);
+                }
+            }
+        }
+    }
+#if defined(WITH_JIT_TUNING)
+    gDvmJit.addrLookupsNotFound++;
+#endif
+    return NULL;
+}
+
+/*
+ * If a translated code address, in trace format, exists for the davik byte code
+ * pointer return it.
+ */
+void* dvmJitGetTraceAddr(const u2* dPC)
+{
+    return getCodeAddrCommon(dPC, false /* method entry */);
+}
+
+/*
+ * If a translated code address, in whole-method format, exists for the davik
+ * byte code pointer return it.
+ */
+void* dvmJitGetMethodAddr(const u2* dPC)
+{
+    return getCodeAddrCommon(dPC, true /* method entry */);
+}
+
+/*
+ * Similar to dvmJitGetTraceAddr, but returns null if the calling
+ * thread is in a single-step mode.
+ */
+void* dvmJitGetTraceAddrThread(const u2* dPC, Thread* self)
+{
+    return (self->interpBreak.ctl.breakFlags != 0) ? NULL :
+            getCodeAddrCommon(dPC, false /* method entry */);
+}
+
+/*
+ * Similar to dvmJitGetMethodAddr, but returns null if the calling
+ * thread is in a single-step mode.
+ */
+void* dvmJitGetMethodAddrThread(const u2* dPC, Thread* self)
+{
+    return (self->interpBreak.ctl.breakFlags != 0) ? NULL :
+            getCodeAddrCommon(dPC, true /* method entry */);
+}
+
+/*
+ * Register the translated code pointer into the JitTable.
+ * NOTE: Once a codeAddress field transitions from initial state to
+ * JIT'd code, it must not be altered without first halting all
+ * threads.  We defer the setting of the profile prefix size until
+ * after the new code address is set to ensure that the prefix offset
+ * is never applied to the initial interpret-only translation.  All
+ * translations with non-zero profile prefixes will still be correct
+ * if entered as if the profile offset is 0, but the interpret-only
+ * template cannot handle a non-zero prefix.
+ * NOTE: JitTable must not be in danger of reset while this
+ * code is executing. see Issue 4271784 for details.
+ */
+void dvmJitSetCodeAddr(const u2* dPC, void *nPC, JitInstructionSetType set,
+                       bool isMethodEntry, int profilePrefixSize)
+{
+    JitEntryInfoUnion oldValue;
+    JitEntryInfoUnion newValue;
+    /*
+     * Get the JitTable slot for this dPC (or create one if JitTable
+     * has been reset between the time the trace was requested and
+     * now.
+     */
+    JitEntry *jitEntry = isMethodEntry ?
+        lookupAndAdd(dPC, false /* caller holds tableLock */, isMethodEntry) :
+                     dvmJitFindEntry(dPC, isMethodEntry);
+    assert(jitEntry);
+    /* Note: order of update is important */
+    do {
+        oldValue = jitEntry->u;
+        newValue = oldValue;
+        newValue.info.isMethodEntry = isMethodEntry;
+        newValue.info.instructionSet = set;
+        newValue.info.profileOffset = profilePrefixSize;
+    } while (android_atomic_release_cas(
+             oldValue.infoWord, newValue.infoWord,
+             &jitEntry->u.infoWord) != 0);
+    jitEntry->codeAddress = nPC;
+}
+
+/*
+ * Determine if valid trace-bulding request is active.  If so, set
+ * the proper flags in interpBreak and return.  Trace selection will
+ * then begin normally via dvmCheckBefore.
+ */
+void dvmJitCheckTraceRequest(Thread* self)
+{
+    int i;
+    /*
+     * A note on trace "hotness" filtering:
+     *
+     * Our first level trigger is intentionally loose - we need it to
+     * fire easily not just to identify potential traces to compile, but
+     * also to allow re-entry into the code cache.
+     *
+     * The 2nd level filter (done here) exists to be selective about
+     * what we actually compile.  It works by requiring the same
+     * trace head "key" (defined as filterKey below) to appear twice in
+     * a relatively short period of time.   The difficulty is defining the
+     * shape of the filterKey.  Unfortunately, there is no "one size fits
+     * all" approach.
+     *
+     * For spiky execution profiles dominated by a smallish
+     * number of very hot loops, we would want the second-level filter
+     * to be very selective.  A good selective filter is requiring an
+     * exact match of the Dalvik PC.  In other words, defining filterKey as:
+     *     intptr_t filterKey = (intptr_t)self->interpSave.pc
+     *
+     * However, for flat execution profiles we do best when aggressively
+     * translating.  A heuristically decent proxy for this is to use
+     * the value of the method pointer containing the trace as the filterKey.
+     * Intuitively, this is saying that once any trace in a method appears hot,
+     * immediately translate any other trace from that same method that
+     * survives the first-level filter.  Here, filterKey would be defined as:
+     *     intptr_t filterKey = (intptr_t)self->interpSave.method
+     *
+     * The problem is that we can't easily detect whether we're dealing
+     * with a spiky or flat profile.  If we go with the "pc" match approach,
+     * flat profiles perform poorly.  If we go with the loose "method" match,
+     * we end up generating a lot of useless translations.  Probably the
+     * best approach in the future will be to retain profile information
+     * across runs of each application in order to determine it's profile,
+     * and then choose once we have enough history.
+     *
+     * However, for now we've decided to chose a compromise filter scheme that
+     * includes elements of both.  The high order bits of the filter key
+     * are drawn from the enclosing method, and are combined with a slice
+     * of the low-order bits of the Dalvik pc of the trace head.  The
+     * looseness of the filter can be adjusted by changing with width of
+     * the Dalvik pc slice (JIT_TRACE_THRESH_FILTER_PC_BITS).  The wider
+     * the slice, the tighter the filter.
+     *
+     * Note: the fixed shifts in the function below reflect assumed word
+     * alignment for method pointers, and half-word alignment of the Dalvik pc.
+     * for method pointers and half-word alignment for dalvik pc.
+     */
+    u4 methodKey = (u4)self->interpSave.method <<
+                   (JIT_TRACE_THRESH_FILTER_PC_BITS - 2);
+    u4 pcKey = ((u4)self->interpSave.pc >> 1) &
+               ((1 << JIT_TRACE_THRESH_FILTER_PC_BITS) - 1);
+    intptr_t filterKey = (intptr_t)(methodKey | pcKey);
+
+    // Shouldn't be here if already building a trace.
+    assert((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild)==0);
+
+    /* Check if the JIT request can be handled now */
+    if ((gDvmJit.pJitEntryTable != NULL) &&
+        ((self->interpBreak.ctl.breakFlags & kInterpSingleStep) == 0)){
+        /* Bypass the filter for hot trace requests or during stress mode */
+        if (self->jitState == kJitTSelectRequest &&
+            gDvmJit.threshold > 6) {
+            /* Two-level filtering scheme */
+            for (i=0; i< JIT_TRACE_THRESH_FILTER_SIZE; i++) {
+                if (filterKey == self->threshFilter[i]) {
+                    self->threshFilter[i] = 0; // Reset filter entry
+                    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;
+                self->threshFilter[i] = filterKey;
+                self->jitState = kJitDone;
+            }
+        }
+
+        /* If the compiler is backlogged, cancel any JIT actions */
+        if (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater) {
+            self->jitState = kJitDone;
+        }
+
+        /*
+         * Check for additional reasons that might force the trace select
+         * request to be dropped
+         */
+        if (self->jitState == kJitTSelectRequest ||
+            self->jitState == kJitTSelectRequestHot) {
+            if (dvmJitFindEntry(self->interpSave.pc, false)) {
+                /* In progress - nothing do do */
+               self->jitState = kJitDone;
+            } else {
+                JitEntry *slot = lookupAndAdd(self->interpSave.pc,
+                                              false /* lock */,
+                                              false /* method entry */);
+                if (slot == NULL) {
+                    /*
+                     * Table is full.  This should have been
+                     * detected by the compiler thread and the table
+                     * resized before we run into it here.  Assume bad things
+                     * are afoot and disable profiling.
+                     */
+                    self->jitState = kJitDone;
+                    LOGD("JIT: JitTable full, disabling profiling");
+                    dvmJitStopTranslationRequests();
+                }
+            }
+        }
+
+        switch (self->jitState) {
+            case kJitTSelectRequest:
+            case kJitTSelectRequestHot:
+                self->jitState = kJitTSelect;
+                self->traceMethod = self->interpSave.method;
+                self->currTraceHead = self->interpSave.pc;
+                self->currTraceRun = 0;
+                self->totalTraceLen = 0;
+                self->currRunHead = self->interpSave.pc;
+                self->currRunLen = 0;
+                self->trace[0].info.frag.startOffset =
+                     self->interpSave.pc - self->interpSave.method->insns;
+                self->trace[0].info.frag.numInsts = 0;
+                self->trace[0].info.frag.runEnd = false;
+                self->trace[0].info.frag.hint = kJitHintNone;
+                self->trace[0].isCode = true;
+                self->lastPC = 0;
+                /* Turn on trace selection mode */
+                dvmEnableSubMode(self, kSubModeJitTraceBuild);
+#if defined(SHOW_TRACE)
+                LOGD("Starting trace for %s at %#x",
+                     self->interpSave.method->name, (int)self->interpSave.pc);
+#endif
+                break;
+            case kJitDone:
+                break;
+            default:
+                LOGE("Unexpected JIT state: %d", self->jitState);
+                dvmAbort();
+        }
+    } else {
+        /* Cannot build trace this time */
+        self->jitState = kJitDone;
+    }
+}
+
+/*
+ * Resizes the JitTable.  Must be a power of 2, and returns true on failure.
+ * Stops all threads, and thus is a heavyweight operation. May only be called
+ * by the compiler thread.
+ */
+bool dvmJitResizeJitTable( unsigned int size )
+{
+    JitEntry *pNewTable;
+    JitEntry *pOldTable;
+    JitEntry tempEntry;
+    unsigned int oldSize;
+    unsigned int i;
+
+    assert(gDvmJit.pJitEntryTable != NULL);
+    assert(size && !(size & (size - 1)));   /* Is power of 2? */
+
+    LOGI("Jit: resizing JitTable from %d to %d", gDvmJit.jitTableSize, size);
+
+    if (size <= gDvmJit.jitTableSize) {
+        return true;
+    }
+
+    /* Make sure requested size is compatible with chain field width */
+    tempEntry.u.info.chain = size;
+    if (tempEntry.u.info.chain != size) {
+        LOGD("Jit: JitTable request of %d too big", size);
+        return true;
+    }
+
+    pNewTable = (JitEntry*)calloc(size, sizeof(*pNewTable));
+    if (pNewTable == NULL) {
+        return true;
+    }
+    for (i=0; i< size; i++) {
+        pNewTable[i].u.info.chain = size;  /* Initialize chain termination */
+    }
+
+    /* Stop all other interpreting/jit'ng threads */
+    dvmSuspendAllThreads(SUSPEND_FOR_TBL_RESIZE);
+
+    pOldTable = gDvmJit.pJitEntryTable;
+    oldSize = gDvmJit.jitTableSize;
+
+    dvmLockMutex(&gDvmJit.tableLock);
+    gDvmJit.pJitEntryTable = pNewTable;
+    gDvmJit.jitTableSize = size;
+    gDvmJit.jitTableMask = size - 1;
+    gDvmJit.jitTableEntriesUsed = 0;
+
+    for (i=0; i < oldSize; i++) {
+        if (pOldTable[i].dPC) {
+            JitEntry *p;
+            u2 chain;
+            p = lookupAndAdd(pOldTable[i].dPC, true /* holds tableLock*/,
+                             pOldTable[i].u.info.isMethodEntry);
+            p->codeAddress = pOldTable[i].codeAddress;
+            /* We need to preserve the new chain field, but copy the rest */
+            chain = p->u.info.chain;
+            p->u = pOldTable[i].u;
+            p->u.info.chain = chain;
+        }
+    }
+
+    dvmUnlockMutex(&gDvmJit.tableLock);
+
+    free(pOldTable);
+
+    /* Restart the world */
+    dvmResumeAllThreads(SUSPEND_FOR_TBL_RESIZE);
+
+    return false;
+}
+
+/*
+ * Reset the JitTable to the initial clean state.
+ */
+void dvmJitResetTable()
+{
+    JitEntry *jitEntry = gDvmJit.pJitEntryTable;
+    unsigned int size = gDvmJit.jitTableSize;
+    unsigned int i;
+
+    dvmLockMutex(&gDvmJit.tableLock);
+
+    /* Note: If need to preserve any existing counts. Do so here. */
+    if (gDvmJit.pJitTraceProfCounters) {
+        for (i=0; i < JIT_PROF_BLOCK_BUCKETS; i++) {
+            if (gDvmJit.pJitTraceProfCounters->buckets[i])
+                memset((void *) gDvmJit.pJitTraceProfCounters->buckets[i],
+                       0, sizeof(JitTraceCounter_t) * JIT_PROF_BLOCK_ENTRIES);
+        }
+        gDvmJit.pJitTraceProfCounters->next = 0;
+    }
+
+    memset((void *) jitEntry, 0, sizeof(JitEntry) * size);
+    for (i=0; i< size; i++) {
+        jitEntry[i].u.info.chain = size;  /* Initialize chain termination */
+    }
+    gDvmJit.jitTableEntriesUsed = 0;
+    dvmUnlockMutex(&gDvmJit.tableLock);
+}
+
+/*
+ * Return the address of the next trace profile counter.  This address
+ * will be embedded in the generated code for the trace, and thus cannot
+ * change while the trace exists.
+ */
+JitTraceCounter_t *dvmJitNextTraceCounter()
+{
+    int idx = gDvmJit.pJitTraceProfCounters->next / JIT_PROF_BLOCK_ENTRIES;
+    int elem = gDvmJit.pJitTraceProfCounters->next % JIT_PROF_BLOCK_ENTRIES;
+    JitTraceCounter_t *res;
+    /* Lazily allocate blocks of counters */
+    if (!gDvmJit.pJitTraceProfCounters->buckets[idx]) {
+        JitTraceCounter_t *p =
+              (JitTraceCounter_t*) calloc(JIT_PROF_BLOCK_ENTRIES, sizeof(*p));
+        if (!p) {
+            LOGE("Failed to allocate block of trace profile counters");
+            dvmAbort();
+        }
+        gDvmJit.pJitTraceProfCounters->buckets[idx] = p;
+    }
+    res = &gDvmJit.pJitTraceProfCounters->buckets[idx][elem];
+    gDvmJit.pJitTraceProfCounters->next++;
+    return res;
+}
+
+/*
+ * Float/double conversion requires clamping to min and max of integer form.  If
+ * target doesn't support this normally, use these.
+ */
+s8 dvmJitd2l(double d)
+{
+    static const double kMaxLong = (double)(s8)0x7fffffffffffffffULL;
+    static const double kMinLong = (double)(s8)0x8000000000000000ULL;
+    if (d >= kMaxLong)
+        return (s8)0x7fffffffffffffffULL;
+    else if (d <= kMinLong)
+        return (s8)0x8000000000000000ULL;
+    else if (d != d) // NaN case
+        return 0;
+    else
+        return (s8)d;
+}
+
+s8 dvmJitf2l(float f)
+{
+    static const float kMaxLong = (float)(s8)0x7fffffffffffffffULL;
+    static const float kMinLong = (float)(s8)0x8000000000000000ULL;
+    if (f >= kMaxLong)
+        return (s8)0x7fffffffffffffffULL;
+    else if (f <= kMinLong)
+        return (s8)0x8000000000000000ULL;
+    else if (f != f) // NaN case
+        return 0;
+    else
+        return (s8)f;
+}
+
+/* Should only be called by the compiler thread */
+void dvmJitChangeProfileMode(TraceProfilingModes newState)
+{
+    if (gDvmJit.profileMode != newState) {
+        gDvmJit.profileMode = newState;
+        dvmJitUnchainAll();
+    }
+}
+
+void dvmJitTraceProfilingOn()
+{
+    if (gDvmJit.profileMode == kTraceProfilingPeriodicOff)
+        dvmCompilerForceWorkEnqueue(NULL, kWorkOrderProfileMode,
+                                    (void*) kTraceProfilingPeriodicOn);
+    else if (gDvmJit.profileMode == kTraceProfilingDisabled)
+        dvmCompilerForceWorkEnqueue(NULL, kWorkOrderProfileMode,
+                                    (void*) kTraceProfilingContinuous);
+}
+
+void dvmJitTraceProfilingOff()
+{
+    if (gDvmJit.profileMode == kTraceProfilingPeriodicOn)
+        dvmCompilerForceWorkEnqueue(NULL, kWorkOrderProfileMode,
+                                    (void*) kTraceProfilingPeriodicOff);
+    else if (gDvmJit.profileMode == kTraceProfilingContinuous)
+        dvmCompilerForceWorkEnqueue(NULL, kWorkOrderProfileMode,
+                                    (void*) kTraceProfilingDisabled);
+}
+
+/*
+ * Update JIT-specific info in Thread structure for a single thread
+ */
+void dvmJitUpdateThreadStateSingle(Thread* thread)
+{
+    thread->pJitProfTable = gDvmJit.pProfTable;
+    thread->jitThreshold = gDvmJit.threshold;
+}
+
+/*
+ * Walk through the thread list and refresh all local copies of
+ * JIT global state (which was placed there for fast access).
+ */
+void dvmJitUpdateThreadStateAll()
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+
+    dvmLockThreadList(self);
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        dvmJitUpdateThreadStateSingle(thread);
+    }
+    dvmUnlockThreadList();
+
+}
+#endif /* WITH_JIT */
diff --git a/vm/interp/Jit.h b/vm/interp/Jit.h
new file mode 100644
index 0000000..962040b
--- /dev/null
+++ b/vm/interp/Jit.h
@@ -0,0 +1,180 @@
+/*
+ * 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_H_
+#define DALVIK_INTERP_JIT_H_
+
+#include "InterpDefs.h"
+#include "mterp/common/jit-config.h"
+
+#define JIT_MAX_TRACE_LEN 100
+
+#if defined (WITH_SELF_VERIFICATION)
+
+#define REG_SPACE 256                /* default size of shadow space */
+#define HEAP_SPACE JIT_MAX_TRACE_LEN /* default size of heap space */
+
+struct ShadowHeap {
+    int addr;
+    int data;
+};
+
+struct InstructionTrace {
+    int addr;
+    DecodedInstruction decInsn;
+};
+
+struct ShadowSpace {
+    const u2* startPC;          /* starting pc of jitted region */
+    u4* fp;                     /* starting fp of jitted region */
+    const Method *method;
+    DvmDex* methodClassDex;
+    JValue retval;
+    const u1* interpStackEnd;
+    SelfVerificationState jitExitState;  /* exit point for JIT'ed code */
+    SelfVerificationState selfVerificationState;  /* current SV running state */
+    const u2* endPC;            /* ending pc of jitted region */
+    void* shadowFP;       /* pointer to fp in shadow space */
+    int* registerSpace;         /* copy of register state */
+    int registerSpaceSize;      /* current size of register space */
+    ShadowHeap heapSpace[HEAP_SPACE]; /* copy of heap space */
+    ShadowHeap* heapSpaceTail;        /* tail pointer to heapSpace */
+    const void* endShadowFP;    /* ending fp in shadow space */
+    InstructionTrace trace[JIT_MAX_TRACE_LEN]; /* opcode trace for debugging */
+    int traceLength;            /* counter for current trace length */
+};
+
+/*
+ * Self verification functions.
+ */
+extern "C" {
+void* dvmSelfVerificationShadowSpaceAlloc(Thread* self);
+void dvmSelfVerificationShadowSpaceFree(Thread* self);
+void* dvmSelfVerificationSaveState(const u2* pc, u4* fp,
+                                   Thread* self,
+                                   int targetTrace);
+void* dvmSelfVerificationRestoreState(const u2* pc, u4* fp,
+                                      SelfVerificationState exitPoint,
+                                      Thread *self);
+void dvmCheckSelfVerification(const u2* pc, Thread* self);
+}
+#endif
+
+/*
+ * Offsets for metadata in the trace run array from the trace that ends with
+ * invoke instructions.
+ */
+#define JIT_TRACE_CLASS_DESC    1
+#define JIT_TRACE_CLASS_LOADER  2
+#define JIT_TRACE_CUR_METHOD    3
+
+/*
+ * 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 );
+}
+
+/*
+ * The width of the chain field in JitEntryInfo sets the upper
+ * bound on the number of translations.  Be careful if changing
+ * the size of JitEntry struct - the Dalvik PC to JitEntry
+ * hash functions have built-in knowledge of the size.
+ */
+#define JIT_ENTRY_CHAIN_WIDTH 2
+#define JIT_MAX_ENTRIES (1 << (JIT_ENTRY_CHAIN_WIDTH * 8))
+
+/*
+ * The trace profiling counters are allocated in blocks and individual
+ * counters must not move so long as any referencing trace exists.
+ */
+#define JIT_PROF_BLOCK_ENTRIES 1024
+#define JIT_PROF_BLOCK_BUCKETS (JIT_MAX_ENTRIES / JIT_PROF_BLOCK_ENTRIES)
+
+typedef s4 JitTraceCounter_t;
+
+struct JitTraceProfCounters {
+    unsigned int           next;
+    JitTraceCounter_t      *buckets[JIT_PROF_BLOCK_BUCKETS];
+};
+
+/*
+ * Entries in the JIT's address lookup hash table.
+ * Fields which may be updated by multiple threads packed into a
+ * single 32-bit word to allow use of atomic update.
+ */
+
+struct JitEntryInfo {
+    unsigned int           isMethodEntry:1;
+    unsigned int           inlineCandidate:1;
+    unsigned int           profileEnabled:1;
+    JitInstructionSetType  instructionSet:3;
+    unsigned int           profileOffset:5;
+    unsigned int           unused:5;
+    u2                     chain;                 /* Index of next in chain */
+};
+
+union JitEntryInfoUnion {
+    JitEntryInfo info;
+    volatile int infoWord;
+};
+
+struct JitEntry {
+    JitEntryInfoUnion   u;
+    const u2*           dPC;            /* Dalvik code address */
+    void*               codeAddress;    /* Code address of native translation */
+};
+
+extern "C" {
+void dvmCheckJit(const u2* pc, Thread* self);
+void* dvmJitGetTraceAddr(const u2* dPC);
+void* dvmJitGetMethodAddr(const u2* dPC);
+void* dvmJitGetTraceAddrThread(const u2* dPC, Thread* self);
+void* dvmJitGetMethodAddrThread(const u2* dPC, Thread* self);
+void dvmJitCheckTraceRequest(Thread* self);
+void dvmJitStopTranslationRequests(void);
+#if defined(WITH_JIT_TUNING)
+void dvmBumpNoChain(int from);
+void dvmBumpNormal(void);
+void dvmBumpPunt(int from);
+#endif
+void dvmJitStats(void);
+bool dvmJitResizeJitTable(unsigned int size);
+void dvmJitResetTable(void);
+JitEntry *dvmJitFindEntry(const u2* pc, bool isMethodEntry);
+s8 dvmJitd2l(double d);
+s8 dvmJitf2l(float f);
+void dvmJitSetCodeAddr(const u2* dPC, void *nPC, JitInstructionSetType set,
+                       bool isMethodEntry, int profilePrefixSize);
+void dvmJitEndTraceSelect(Thread* self, const u2* dPC);
+JitTraceCounter_t *dvmJitNextTraceCounter(void);
+void dvmJitTraceProfilingOff(void);
+void dvmJitTraceProfilingOn(void);
+void dvmJitChangeProfileMode(TraceProfilingModes newState);
+void dvmJitDumpTraceDesc(JitTraceDescription *trace);
+void dvmJitUpdateThreadStateSingle(Thread* threead);
+void dvmJitUpdateThreadStateAll(void);
+void dvmJitResumeTranslation(Thread* self, const u2* pc, const u4* fp);
+}
+
+#endif  // DALVIK_INTERP_JIT_H_
diff --git a/vm/interp/README.txt b/vm/interp/README.txt
new file mode 100644
index 0000000..170d2b1
--- /dev/null
+++ b/vm/interp/README.txt
@@ -0,0 +1,3 @@
+Dalvik interpreter entry point.
+
+The "mterp" directory now holds the interpreter implementation.
diff --git a/vm/interp/Stack.cpp b/vm/interp/Stack.cpp
new file mode 100644
index 0000000..49e68f1
--- /dev/null
+++ b/vm/interp/Stack.cpp
@@ -0,0 +1,1378 @@
+/*
+ * 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.
+ */
+
+/*
+ * Stacks and their uses (e.g. native --> interpreted method calls).
+ *
+ * See the majestic ASCII art in Stack.h.
+ */
+#include "Dalvik.h"
+#include "jni.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+/*
+ * Initialize the interpreter stack in a new thread.
+ *
+ * Currently this doesn't do much, since we don't need to zero out the
+ * stack (and we really don't want to if it was created with mmap).
+ */
+bool dvmInitInterpStack(Thread* thread, int stackSize)
+{
+    assert(thread->interpStackStart != NULL);
+
+    assert(thread->interpSave.curFrame == NULL);
+
+    return true;
+}
+
+/*
+ * We're calling an interpreted method from an internal VM function or
+ * via reflection.
+ *
+ * Push a frame for an interpreted method onto the stack.  This is only
+ * used when calling into interpreted code from native code.  (The
+ * interpreter does its own stack frame manipulation for interp-->interp
+ * calls.)
+ *
+ * The size we need to reserve is the sum of parameters, local variables,
+ * saved goodies, and outbound parameters.
+ *
+ * We start by inserting a "break" frame, which ensures that the interpreter
+ * hands control back to us after the function we call returns or an
+ * uncaught exception is thrown.
+ */
+static bool dvmPushInterpFrame(Thread* self, const Method* method)
+{
+    StackSaveArea* saveBlock;
+    StackSaveArea* breakSaveBlock;
+    int stackReq;
+    u1* stackPtr;
+
+    assert(!dvmIsNativeMethod(method));
+    assert(!dvmIsAbstractMethod(method));
+
+    stackReq = method->registersSize * 4        // params + locals
+                + sizeof(StackSaveArea) * 2     // break frame + regular frame
+                + method->outsSize * 4;         // args to other methods
+
+    if (self->interpSave.curFrame != NULL)
+        stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    else
+        stackPtr = self->interpStackStart;
+
+    if (stackPtr - stackReq < self->interpStackEnd) {
+        /* not enough space */
+        LOGW("Stack overflow on call to interp "
+             "(req=%d top=%p cur=%p size=%d %s.%s)",
+            stackReq, self->interpStackStart, self->interpSave.curFrame,
+            self->interpStackSize, method->clazz->descriptor, method->name);
+        dvmHandleStackOverflow(self, method);
+        assert(dvmCheckException(self));
+        return false;
+    }
+
+    /*
+     * Shift the stack pointer down, leaving space for the function's
+     * args/registers and save area.
+     */
+    stackPtr -= sizeof(StackSaveArea);
+    breakSaveBlock = (StackSaveArea*)stackPtr;
+    stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
+    saveBlock = (StackSaveArea*) stackPtr;
+
+#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
+    /* debug -- memset the new stack, unless we want valgrind's help */
+    memset(stackPtr - (method->outsSize*4), 0xaf, stackReq);
+#endif
+#ifdef EASY_GDB
+    breakSaveBlock->prevSave =
+       (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
+    saveBlock->prevSave = breakSaveBlock;
+#endif
+
+    breakSaveBlock->prevFrame = self->interpSave.curFrame;
+    breakSaveBlock->savedPc = NULL;             // not required
+    breakSaveBlock->xtra.localRefCookie = 0;    // not required
+    breakSaveBlock->method = NULL;
+    saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
+    saveBlock->savedPc = NULL;                  // not required
+    saveBlock->xtra.currentPc = NULL;           // not required?
+    saveBlock->method = method;
+
+    LOGVV("PUSH frame: old=%p new=%p (size=%d)",
+        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
+        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
+
+    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
+
+    return true;
+}
+
+/*
+ * We're calling a JNI native method from an internal VM fuction or
+ * via reflection.  This is also used to create the "fake" native-method
+ * frames at the top of the interpreted stack.
+ *
+ * This actually pushes two frames; the first is a "break" frame.
+ *
+ * The top frame has additional space for JNI local reference tracking.
+ */
+bool dvmPushJNIFrame(Thread* self, const Method* method)
+{
+    StackSaveArea* saveBlock;
+    StackSaveArea* breakSaveBlock;
+    int stackReq;
+    u1* stackPtr;
+
+    assert(dvmIsNativeMethod(method));
+
+    stackReq = method->registersSize * 4        // params only
+                + sizeof(StackSaveArea) * 2;    // break frame + regular frame
+
+    if (self->interpSave.curFrame != NULL)
+        stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    else
+        stackPtr = self->interpStackStart;
+
+    if (stackPtr - stackReq < self->interpStackEnd) {
+        /* not enough space */
+        LOGW("Stack overflow on call to native "
+             "(req=%d top=%p cur=%p size=%d '%s')",
+            stackReq, self->interpStackStart, self->interpSave.curFrame,
+            self->interpStackSize, method->name);
+        dvmHandleStackOverflow(self, method);
+        assert(dvmCheckException(self));
+        return false;
+    }
+
+    /*
+     * Shift the stack pointer down, leaving space for just the stack save
+     * area for the break frame, then shift down farther for the full frame.
+     * We leave space for the method args, which are copied in later.
+     */
+    stackPtr -= sizeof(StackSaveArea);
+    breakSaveBlock = (StackSaveArea*)stackPtr;
+    stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
+    saveBlock = (StackSaveArea*) stackPtr;
+
+#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
+    /* debug -- memset the new stack */
+    memset(stackPtr, 0xaf, stackReq);
+#endif
+#ifdef EASY_GDB
+    if (self->interpSave.curFrame == NULL)
+        breakSaveBlock->prevSave = NULL;
+    else {
+        void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame);
+        breakSaveBlock->prevSave = (StackSaveArea*)fp;
+    }
+    saveBlock->prevSave = breakSaveBlock;
+#endif
+
+    breakSaveBlock->prevFrame = self->interpSave.curFrame;
+    breakSaveBlock->savedPc = NULL;             // not required
+    breakSaveBlock->xtra.localRefCookie = 0;    // not required
+    breakSaveBlock->method = NULL;
+    saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
+    saveBlock->savedPc = NULL;                  // not required
+    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+    saveBlock->method = method;
+
+    LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)",
+        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
+        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
+
+    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
+
+    return true;
+}
+
+/*
+ * This is used by the JNI PushLocalFrame call.  We push a new frame onto
+ * the stack that has no ins, outs, or locals, and no break frame above it.
+ * It's strictly used for tracking JNI local refs, and will be popped off
+ * by dvmPopFrame if it's not removed explicitly.
+ */
+bool dvmPushLocalFrame(Thread* self, const Method* method)
+{
+    StackSaveArea* saveBlock;
+    int stackReq;
+    u1* stackPtr;
+
+    assert(dvmIsNativeMethod(method));
+
+    stackReq = sizeof(StackSaveArea);       // regular frame
+
+    assert(self->interpSave.curFrame != NULL);
+    stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
+
+    if (stackPtr - stackReq < self->interpStackEnd) {
+        /* not enough space; let JNI throw the exception */
+        LOGW("Stack overflow on PushLocal "
+             "(req=%d top=%p cur=%p size=%d '%s')",
+            stackReq, self->interpStackStart, self->interpSave.curFrame,
+            self->interpStackSize, method->name);
+        dvmHandleStackOverflow(self, method);
+        assert(dvmCheckException(self));
+        return false;
+    }
+
+    /*
+     * Shift the stack pointer down, leaving space for just the stack save
+     * area for the break frame, then shift down farther for the full frame.
+     */
+    stackPtr -= sizeof(StackSaveArea);
+    saveBlock = (StackSaveArea*) stackPtr;
+
+#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
+    /* debug -- memset the new stack */
+    memset(stackPtr, 0xaf, stackReq);
+#endif
+#ifdef EASY_GDB
+    saveBlock->prevSave =
+        (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
+#endif
+
+    saveBlock->prevFrame = self->interpSave.curFrame;
+    saveBlock->savedPc = NULL;                  // not required
+    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+    saveBlock->method = method;
+
+    LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)",
+        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
+        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
+
+    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
+
+    return true;
+}
+
+/*
+ * Pop one frame pushed on by JNI PushLocalFrame.
+ *
+ * If we've gone too far, the previous frame is either a break frame or
+ * an interpreted frame.  Either way, the method pointer won't match.
+ */
+bool dvmPopLocalFrame(Thread* self)
+{
+    StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+
+    assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
+    if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
+        /*
+         * The previous frame doesn't have the same method pointer -- we've
+         * been asked to pop too much.
+         */
+        assert(dvmIsBreakFrame((u4*)saveBlock->prevFrame) ||
+               !dvmIsNativeMethod(
+                       SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
+        return false;
+    }
+
+    LOGVV("POP JNI local frame: removing %s, now %s",
+        saveBlock->method->name,
+        SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
+    dvmPopJniLocals(self, saveBlock);
+    self->interpSave.curFrame = saveBlock->prevFrame;
+
+    return true;
+}
+
+/*
+ * Pop a frame we added.  There should be one method frame and one break
+ * frame.
+ *
+ * If JNI Push/PopLocalFrame calls were mismatched, we might end up
+ * popping multiple method frames before we find the break.
+ *
+ * Returns "false" if there was no frame to pop.
+ */
+static bool dvmPopFrame(Thread* self)
+{
+    StackSaveArea* saveBlock;
+
+    if (self->interpSave.curFrame == NULL)
+        return false;
+
+    saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
+
+    /*
+     * Remove everything up to the break frame.  If this was a call into
+     * native code, pop the JNI local references table.
+     */
+    while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
+        /* probably a native->native JNI call */
+
+        if (dvmIsNativeMethod(saveBlock->method)) {
+            LOGVV("Popping JNI stack frame for %s.%s%s",
+                saveBlock->method->clazz->descriptor,
+                saveBlock->method->name,
+                (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
+                "" : " (JNI local)");
+            dvmPopJniLocals(self, saveBlock);
+        }
+
+        saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
+    }
+    if (saveBlock->method != NULL) {
+        LOGE("PopFrame missed the break");
+        assert(false);
+        dvmAbort();     // stack trashed -- nowhere to go in this thread
+    }
+
+    LOGVV("POP frame: cur=%p new=%p",
+        self->interpSave.curFrame, saveBlock->prevFrame);
+
+    self->interpSave.curFrame = saveBlock->prevFrame;
+    return true;
+}
+
+/*
+ * Common code for dvmCallMethodV/A and dvmInvokeMethod.
+ *
+ * Pushes a call frame on, advancing self->interpSave.curFrame.
+ */
+static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
+    bool checkAccess)
+{
+    ClassObject* clazz;
+
+#ifndef NDEBUG
+    if (self->status != THREAD_RUNNING) {
+        LOGW("threadid=%d: status=%d on call to %s.%s -",
+            self->threadId, self->status,
+            method->clazz->descriptor, method->name);
+    }
+#endif
+
+    assert(self != NULL);
+    assert(method != NULL);
+
+    if (obj != NULL)
+        clazz = obj->clazz;
+    else
+        clazz = method->clazz;
+
+    IF_LOGVV() {
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGVV("thread=%d native code calling %s.%s %s", self->threadId,
+            clazz->descriptor, method->name, desc);
+        free(desc);
+    }
+
+    if (checkAccess) {
+        /* needed for java.lang.reflect.Method.invoke */
+        if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame),
+                method))
+        {
+            /* note this throws IAException, not IAError */
+            dvmThrowIllegalAccessException("access to method denied");
+            return NULL;
+        }
+    }
+
+    /*
+     * Push a call frame on.  If there isn't enough room for ins, locals,
+     * outs, and the saved state, it will throw an exception.
+     *
+     * This updates self->interpSave.curFrame.
+     */
+    if (dvmIsNativeMethod(method)) {
+        /* native code calling native code the hard way */
+        if (!dvmPushJNIFrame(self, method)) {
+            assert(dvmCheckException(self));
+            return NULL;
+        }
+    } else {
+        /* native code calling interpreted code */
+        if (!dvmPushInterpFrame(self, method)) {
+            assert(dvmCheckException(self));
+            return NULL;
+        }
+    }
+
+    return clazz;
+}
+
+/*
+ * Issue a method call.
+ *
+ * Pass in NULL for "obj" on calls to static methods.
+ *
+ * (Note this can't be inlined because it takes a variable number of args.)
+ */
+void dvmCallMethod(Thread* self, const Method* method, Object* obj,
+    JValue* pResult, ...)
+{
+    va_list args;
+    va_start(args, pResult);
+    dvmCallMethodV(self, method, obj, false, pResult, args);
+    va_end(args);
+}
+
+/*
+ * Issue a method call with a variable number of arguments.  We process
+ * the contents of "args" by scanning the method signature.
+ *
+ * Pass in NULL for "obj" on calls to static methods.
+ *
+ * We don't need to take the class as an argument because, in Dalvik,
+ * we don't need to worry about static synchronized methods.
+ */
+void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
+    bool fromJni, JValue* pResult, va_list args)
+{
+    const char* desc = &(method->shorty[1]); // [0] is the return type.
+    int verifyCount = 0;
+    ClassObject* clazz;
+    u4* ins;
+
+    clazz = callPrep(self, method, obj, false);
+    if (clazz == NULL)
+        return;
+
+    /* "ins" for new frame start at frame pointer plus locals */
+    ins = ((u4*)self->interpSave.curFrame) +
+           (method->registersSize - method->insSize);
+
+    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
+
+    /* put "this" pointer into in0 if appropriate */
+    if (!dvmIsStaticMethod(method)) {
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+        assert(obj != NULL && dvmIsHeapAddress(obj));
+#endif
+        *ins++ = (u4) obj;
+        verifyCount++;
+    }
+
+    while (*desc != '\0') {
+        switch (*(desc++)) {
+            case 'D': case 'J': {
+                u8 val = va_arg(args, u8);
+                memcpy(ins, &val, 8);       // EABI prevents direct store
+                ins += 2;
+                verifyCount += 2;
+                break;
+            }
+            case 'F': {
+                /* floats were normalized to doubles; convert back */
+                float f = (float) va_arg(args, double);
+                *ins++ = dvmFloatToU4(f);
+                verifyCount++;
+                break;
+            }
+            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
+                void* arg = va_arg(args, void*);
+                assert(obj == NULL || dvmIsHeapAddress(obj));
+                jobject argObj = reinterpret_cast<jobject>(arg);
+                if (fromJni)
+                    *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
+                else
+                    *ins++ = (u4) argObj;
+                verifyCount++;
+                break;
+            }
+            default: {
+                /* Z B C S I -- all passed as 32-bit integers */
+                *ins++ = va_arg(args, u4);
+                verifyCount++;
+                break;
+            }
+        }
+    }
+
+#ifndef NDEBUG
+    if (verifyCount != method->insSize) {
+        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
+            method->insSize, clazz->descriptor, method->name);
+        assert(false);
+        goto bail;
+    }
+#endif
+
+    //dvmDumpThreadStack(dvmThreadSelf());
+
+    if (dvmIsNativeMethod(method)) {
+        TRACE_METHOD_ENTER(self, method);
+        /*
+         * Because we leave no space for local variables, "curFrame" points
+         * directly at the method arguments.
+         */
+        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
+                              method, self);
+        TRACE_METHOD_EXIT(self, method);
+    } else {
+        dvmInterpret(self, method, pResult);
+    }
+
+#ifndef NDEBUG
+bail:
+#endif
+    dvmPopFrame(self);
+}
+
+/*
+ * Issue a method call with arguments provided in an array.  We process
+ * the contents of "args" by scanning the method signature.
+ *
+ * The values were likely placed into an uninitialized jvalue array using
+ * the field specifiers, which means that sub-32-bit fields (e.g. short,
+ * boolean) may not have 32 or 64 bits of valid data.  This is different
+ * from the varargs invocation where the C compiler does a widening
+ * conversion when calling a function.  As a result, we have to be a
+ * little more precise when pulling stuff out.
+ *
+ * "args" may be NULL if the method has no arguments.
+ */
+void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
+    bool fromJni, JValue* pResult, const jvalue* args)
+{
+    const char* desc = &(method->shorty[1]); // [0] is the return type.
+    int verifyCount = 0;
+    ClassObject* clazz;
+    u4* ins;
+
+    clazz = callPrep(self, method, obj, false);
+    if (clazz == NULL)
+        return;
+
+    /* "ins" for new frame start at frame pointer plus locals */
+    ins = ((u4*)self->interpSave.curFrame) +
+        (method->registersSize - method->insSize);
+
+    /* put "this" pointer into in0 if appropriate */
+    if (!dvmIsStaticMethod(method)) {
+        assert(obj != NULL);
+        *ins++ = (u4) obj;              /* obj is a "real" ref */
+        verifyCount++;
+    }
+
+    while (*desc != '\0') {
+        switch (*desc++) {
+        case 'D':                       /* 64-bit quantity; have to use */
+        case 'J':                       /*  memcpy() in case of mis-alignment */
+            memcpy(ins, &args->j, 8);
+            ins += 2;
+            verifyCount++;              /* this needs an extra push */
+            break;
+        case 'L':                       /* includes array refs */
+            if (fromJni)
+                *ins++ = (u4) dvmDecodeIndirectRef(self, args->l);
+            else
+                *ins++ = (u4) args->l;
+            break;
+        case 'F':
+        case 'I':
+            *ins++ = args->i;           /* full 32 bits */
+            break;
+        case 'S':
+            *ins++ = args->s;           /* 16 bits, sign-extended */
+            break;
+        case 'C':
+            *ins++ = args->c;           /* 16 bits, unsigned */
+            break;
+        case 'B':
+            *ins++ = args->b;           /* 8 bits, sign-extended */
+            break;
+        case 'Z':
+            *ins++ = args->z;           /* 8 bits, zero or non-zero */
+            break;
+        default:
+            LOGE("Invalid char %c in short signature of %s.%s",
+                *(desc-1), clazz->descriptor, method->name);
+            assert(false);
+            goto bail;
+        }
+
+        verifyCount++;
+        args++;
+    }
+
+#ifndef NDEBUG
+    if (verifyCount != method->insSize) {
+        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
+            method->insSize, clazz->descriptor, method->name);
+        assert(false);
+        goto bail;
+    }
+#endif
+
+    if (dvmIsNativeMethod(method)) {
+        TRACE_METHOD_ENTER(self, method);
+        /*
+         * Because we leave no space for local variables, "curFrame" points
+         * directly at the method arguments.
+         */
+        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
+                              method, self);
+        TRACE_METHOD_EXIT(self, method);
+    } else {
+        dvmInterpret(self, method, pResult);
+    }
+
+bail:
+    dvmPopFrame(self);
+}
+
+static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) {
+    std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
+    std::string actualClassName = dvmHumanReadableType(arg);
+    dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s",
+            argIndex + 1, expectedClassName.c_str(), actualClassName.c_str());
+}
+
+/*
+ * Invoke a method, using the specified arguments and return type, through
+ * one of the reflection interfaces.  Could be a virtual or direct method
+ * (including constructors).  Used for reflection.
+ *
+ * Deals with boxing/unboxing primitives and performs widening conversions.
+ *
+ * "invokeObj" will be null for a static method.
+ *
+ * If the invocation returns with an exception raised, we have to wrap it.
+ */
+Object* dvmInvokeMethod(Object* obj, const Method* method,
+    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
+    bool noAccessCheck)
+{
+    ClassObject* clazz;
+    Object* retObj = NULL;
+    Thread* self = dvmThreadSelf();
+    s4* ins;
+    int verifyCount, argListLength;
+    JValue retval;
+    bool needPop = false;
+
+    /* verify arg count */
+    if (argList != NULL)
+        argListLength = argList->length;
+    else
+        argListLength = 0;
+    if (argListLength != (int) params->length) {
+        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
+            "wrong number of arguments; expected %d, got %d",
+            params->length, argListLength);
+        return NULL;
+    }
+
+    clazz = callPrep(self, method, obj, !noAccessCheck);
+    if (clazz == NULL)
+        return NULL;
+    needPop = true;
+
+    /* "ins" for new frame start at frame pointer plus locals */
+    ins = ((s4*)self->interpSave.curFrame) +
+        (method->registersSize - method->insSize);
+    verifyCount = 0;
+
+    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
+
+    /* put "this" pointer into in0 if appropriate */
+    if (!dvmIsStaticMethod(method)) {
+        assert(obj != NULL);
+        *ins++ = (s4) obj;
+        verifyCount++;
+    }
+
+    /*
+     * Copy the args onto the stack.  Primitive types are converted when
+     * necessary, and object types are verified.
+     */
+    DataObject** args = (DataObject**)(void*)argList->contents;
+    ClassObject** types = (ClassObject**)(void*)params->contents;
+    for (int i = 0; i < argListLength; i++) {
+        int width = dvmConvertArgument(*args++, *types++, ins);
+        if (width < 0) {
+            dvmPopFrame(self);      // throw wants to pull PC out of stack
+            needPop = false;
+            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
+            goto bail;
+        }
+
+        ins += width;
+        verifyCount += width;
+    }
+
+#ifndef NDEBUG
+    if (verifyCount != method->insSize) {
+        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
+            method->insSize, clazz->descriptor, method->name);
+        assert(false);
+        goto bail;
+    }
+#endif
+
+    if (dvmIsNativeMethod(method)) {
+        TRACE_METHOD_ENTER(self, method);
+        /*
+         * Because we leave no space for local variables, "curFrame" points
+         * directly at the method arguments.
+         */
+        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
+                              method, self);
+        TRACE_METHOD_EXIT(self, method);
+    } else {
+        dvmInterpret(self, method, &retval);
+    }
+
+    /*
+     * Pop the frame immediately.  The "wrap" calls below can cause
+     * allocations, and we don't want the GC to walk the now-dead frame.
+     */
+    dvmPopFrame(self);
+    needPop = false;
+
+    /*
+     * If an exception is raised, wrap and replace.  This is necessary
+     * because the invoked method could have thrown a checked exception
+     * that the caller wasn't prepared for.
+     *
+     * We might be able to do this up in the interpreted code, but that will
+     * leave us with a shortened stack trace in the top-level exception.
+     */
+    if (dvmCheckException(self)) {
+        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
+    } else {
+        /*
+         * If this isn't a void method or constructor, convert the return type
+         * to an appropriate object.
+         *
+         * We don't do this when an exception is raised because the value
+         * in "retval" is undefined.
+         */
+        if (returnType != NULL) {
+            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
+            dvmReleaseTrackedAlloc(retObj, NULL);
+        }
+    }
+
+bail:
+    if (needPop) {
+        dvmPopFrame(self);
+    }
+    return retObj;
+}
+
+struct LineNumFromPcContext {
+    u4 address;
+    u4 lineNum;
+};
+
+static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
+{
+    LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
+
+    // We know that this callback will be called in
+    // ascending address order, so keep going until we find
+    // a match or we've just gone past it.
+
+    if (address > pContext->address) {
+        // The line number from the previous positions callback
+        // wil be the final result.
+        return 1;
+    }
+
+    pContext->lineNum = lineNum;
+
+    return (address == pContext->address) ? 1 : 0;
+}
+
+/*
+ * Determine the source file line number based on the program counter.
+ * "pc" is an offset, in 16-bit units, from the start of the method's code.
+ *
+ * Returns -1 if no match was found (possibly because the source files were
+ * compiled without "-g", so no line number information is present).
+ * Returns -2 for native methods (as expected in exception traces).
+ */
+int dvmLineNumFromPC(const Method* method, u4 relPc)
+{
+    const DexCode* pDexCode = dvmGetMethodCode(method);
+
+    if (pDexCode == NULL) {
+        if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
+            return -2;
+        return -1;      /* can happen for abstract method stub */
+    }
+
+    LineNumFromPcContext context;
+    memset(&context, 0, sizeof(context));
+    context.address = relPc;
+    // A method with no line number info should return -1
+    context.lineNum = -1;
+
+    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
+            method->clazz->descriptor,
+            method->prototype.protoIdx,
+            method->accessFlags,
+            lineNumForPcCb, NULL, &context);
+
+    return context.lineNum;
+}
+
+/*
+ * Compute the frame depth.
+ *
+ * Excludes "break" frames.
+ */
+int dvmComputeExactFrameDepth(const void* fp)
+{
+    int count = 0;
+
+    for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
+        if (!dvmIsBreakFrame((u4*)fp))
+            count++;
+    }
+
+    return count;
+}
+
+/*
+ * Compute the "vague" frame depth, which is just a pointer subtraction.
+ * The result is NOT an overly generous assessment of the number of
+ * frames; the only meaningful use is to compare against the result of
+ * an earlier invocation.
+ *
+ * Useful for implementing single-step debugger modes, which may need to
+ * call this for every instruction.
+ */
+int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
+{
+    const u1* interpStackStart = thread->interpStackStart;
+
+    assert((u1*) fp >= interpStackStart - thread->interpStackSize);
+    assert((u1*) fp < interpStackStart);
+    return interpStackStart - (u1*) fp;
+}
+
+/*
+ * Get the calling frame.  Pass in the current fp.
+ *
+ * Skip "break" frames and reflection invoke frames.
+ */
+void* dvmGetCallerFP(const void* curFrame)
+{
+    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
+    StackSaveArea* saveArea;
+
+retry:
+    if (dvmIsBreakFrame((u4*)caller)) {
+        /* pop up one more */
+        caller = SAVEAREA_FROM_FP(caller)->prevFrame;
+        if (caller == NULL)
+            return NULL;        /* hit the top */
+
+        /*
+         * If we got here by java.lang.reflect.Method.invoke(), we don't
+         * want to return Method's class loader.  Shift up one and try
+         * again.
+         */
+        saveArea = SAVEAREA_FROM_FP(caller);
+        if (dvmIsReflectionMethod(saveArea->method)) {
+            caller = saveArea->prevFrame;
+            assert(caller != NULL);
+            goto retry;
+        }
+    }
+
+    return caller;
+}
+
+/*
+ * Get the caller's class.  Pass in the current fp.
+ *
+ * This is used by e.g. java.lang.Class.
+ */
+ClassObject* dvmGetCallerClass(const void* curFrame)
+{
+    void* caller;
+
+    caller = dvmGetCallerFP(curFrame);
+    if (caller == NULL)
+        return NULL;
+
+    return SAVEAREA_FROM_FP(caller)->method->clazz;
+}
+
+/*
+ * Get the caller's caller's class.  Pass in the current fp.
+ *
+ * This is used by e.g. java.lang.Class, which wants to know about the
+ * class loader of the method that called it.
+ */
+ClassObject* dvmGetCaller2Class(const void* curFrame)
+{
+    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
+    void* callerCaller;
+
+    /* at the top? */
+    if (dvmIsBreakFrame((u4*)caller) &&
+        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
+        return NULL;
+
+    /* go one more */
+    callerCaller = dvmGetCallerFP(caller);
+    if (callerCaller == NULL)
+        return NULL;
+
+    return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
+}
+
+/*
+ * Get the caller's caller's caller's class.  Pass in the current fp.
+ *
+ * This is used by e.g. java.lang.Class, which wants to know about the
+ * class loader of the method that called it.
+ */
+ClassObject* dvmGetCaller3Class(const void* curFrame)
+{
+    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
+    int i;
+
+    /* at the top? */
+    if (dvmIsBreakFrame((u4*)caller) &&
+        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
+        return NULL;
+
+    /* Walk up two frames if possible. */
+    for (i = 0; i < 2; i++) {
+        caller = dvmGetCallerFP(caller);
+        if (caller == NULL)
+            return NULL;
+    }
+
+    return SAVEAREA_FROM_FP(caller)->method->clazz;
+}
+
+/*
+ * Fill a flat array of methods that comprise the current interpreter
+ * stack trace.  Pass in the current frame ptr.  Break frames are
+ * skipped, but reflection invocations are not.
+ *
+ * The current frame will be in element 0.
+ */
+void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
+{
+    assert(fp != NULL);
+    assert(array != NULL);
+    size_t i = 0;
+    while (fp != NULL) {
+        if (!dvmIsBreakFrame((u4*)fp)) {
+            assert(i < length);
+            array[i++] = SAVEAREA_FROM_FP(fp)->method;
+        }
+        fp = SAVEAREA_FROM_FP(fp)->prevFrame;
+    }
+}
+
+/*
+ * Open up the reserved area and throw an exception.  The reserved area
+ * should only be needed to create and initialize the exception itself.
+ *
+ * If we already opened it and we're continuing to overflow, abort the VM.
+ *
+ * We have to leave the "reserved" area open until the "catch" handler has
+ * finished doing its processing.  This is because the catch handler may
+ * need to resolve classes, which requires calling into the class loader if
+ * the classes aren't already in the "initiating loader" list.
+ */
+void dvmHandleStackOverflow(Thread* self, const Method* method)
+{
+    /*
+     * Can we make the reserved area available?
+     */
+    if (self->stackOverflowed) {
+        /*
+         * Already did, nothing to do but bail.
+         */
+        LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
+            self->threadId);
+        dvmDumpThread(self, false);
+        dvmAbort();
+    }
+
+    /* open it up to the full range */
+    LOGI("threadid=%d: stack overflow on call to %s.%s:%s",
+        self->threadId,
+        method->clazz->descriptor, method->name, method->shorty);
+    StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+    LOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
+        method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
+        (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
+        saveArea, (u1*) saveArea - self->interpStackEnd);
+    LOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
+        self->interpStackStart - self->interpStackSize);
+    //dvmDumpThread(self, false);
+    self->interpStackEnd = self->interpStackStart - self->interpStackSize;
+    self->stackOverflowed = true;
+
+    /*
+     * If we were trying to throw an exception when the stack overflowed,
+     * we will blow up when doing the class lookup on StackOverflowError
+     * because of the pending exception.  So, we clear it and make it
+     * the cause of the SOE.
+     */
+    Object* excep = dvmGetException(self);
+    if (excep != NULL) {
+        LOGW("Stack overflow while throwing exception");
+        dvmClearException(self);
+    }
+    dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
+}
+
+/*
+ * Reduce the available stack size.  By this point we should have finished
+ * our overflow processing.
+ */
+void dvmCleanupStackOverflow(Thread* self, const Object* exception)
+{
+    const u1* newStackEnd;
+
+    assert(self->stackOverflowed);
+
+    if (exception->clazz != gDvm.exStackOverflowError) {
+        /* exception caused during SOE, not the SOE itself */
+        return;
+    }
+
+    newStackEnd = (self->interpStackStart - self->interpStackSize)
+        + STACK_OVERFLOW_RESERVE;
+    if ((u1*)self->interpSave.curFrame <= newStackEnd) {
+        LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
+            self->interpStackEnd, self->interpSave.curFrame);
+        dvmDumpThread(self, false);
+        dvmAbort();
+    }
+
+    self->interpStackEnd = newStackEnd;
+    self->stackOverflowed = false;
+
+    LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
+        self->interpSave.curFrame);
+}
+
+
+/*
+ * Extract the object that is the target of a monitor-enter instruction
+ * in the top stack frame of "thread".
+ *
+ * The other thread might be alive, so this has to work carefully.
+ *
+ * The thread list lock must be held.
+ *
+ * Returns "true" if we successfully recover the object.  "*pOwner" will
+ * be NULL if we can't determine the owner for some reason (e.g. race
+ * condition on ownership transfer).
+ */
+static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
+    Thread** pOwner)
+{
+    void* framePtr = thread->interpSave.curFrame;
+
+    if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
+        return false;
+
+    const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
+    const Method* method = saveArea->method;
+    const u2* currentPc = saveArea->xtra.currentPc;
+
+    /* check Method* */
+    if (!dvmLinearAllocContains(method, sizeof(Method))) {
+        LOGD("ExtrMon: method %p not valid", method);
+        return false;
+    }
+
+    /* check currentPc */
+    u4 insnsSize = dvmGetMethodInsnsSize(method);
+    if (currentPc < method->insns ||
+        currentPc >= method->insns + insnsSize)
+    {
+        LOGD("ExtrMon: insns %p not valid (%p - %p)",
+            currentPc, method->insns, method->insns + insnsSize);
+        return false;
+    }
+
+    /* check the instruction */
+    if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
+        LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
+            currentPc, *currentPc & 0xff);
+        return false;
+    }
+
+    /* get and check the register index */
+    unsigned int reg = *currentPc >> 8;
+    if (reg >= method->registersSize) {
+        LOGD("ExtrMon: invalid register %d (max %d)",
+            reg, method->registersSize);
+        return false;
+    }
+
+    /* get and check the object in that register */
+    u4* fp = (u4*) framePtr;
+    Object* obj = (Object*) fp[reg];
+    if (obj != NULL && !dvmIsHeapAddress(obj)) {
+        LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
+        return false;
+    }
+    *pLockObj = obj;
+
+    /*
+     * Try to determine the object's lock holder; it's okay if this fails.
+     *
+     * We're assuming the thread list lock is already held by this thread.
+     * If it's not, we may be living dangerously if we have to scan through
+     * the thread list to find a match.  (The VM will generally be in a
+     * suspended state when executing here, so this is a minor concern
+     * unless we're dumping while threads are running, in which case there's
+     * a good chance of stuff blowing up anyway.)
+     */
+    *pOwner = dvmGetObjectLockHolder(obj);
+
+    return true;
+}
+
+static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
+        Thread* thread)
+{
+    std::string msg(StringPrintf("  - waiting %s <%p> ", detail, obj));
+
+    if (obj->clazz != gDvm.classJavaLangClass) {
+        // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
+        // I(16573)   - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
+        msg += "(a " + dvmHumanReadableType(obj) + ")";
+    }
+
+    if (thread != NULL) {
+        std::string threadName(dvmGetThreadName(thread));
+        StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str());
+    }
+
+    dvmPrintDebugMessage(target, "%s\n", msg.c_str());
+}
+
+/*
+ * Dump stack frames, starting from the specified frame and moving down.
+ *
+ * Each frame holds a pointer to the currently executing method, and the
+ * saved program counter from the caller ("previous" frame).  This means
+ * we don't have the PC for the current method on the stack, which is
+ * pretty reasonable since it's in the "PC register" for the VM.  Because
+ * exceptions need to show the correct line number we actually *do* have
+ * an updated version in the fame's "xtra.currentPc", but it's unreliable.
+ *
+ * Note "framePtr" could be NULL in rare circumstances.
+ */
+static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
+    Thread* thread)
+{
+    const StackSaveArea* saveArea;
+    const Method* method;
+    int checkCount = 0;
+    const u2* currentPc = NULL;
+    bool first = true;
+
+    /*
+     * We call functions that require us to be holding the thread list lock.
+     * It's probable that the caller has already done so, but it's not
+     * guaranteed.  If it's not locked, lock it now.
+     */
+    bool needThreadUnlock = dvmTryLockThreadList();
+
+    /*
+     * The "currentPc" is updated whenever we execute an instruction that
+     * might throw an exception.  Show it here.
+     */
+    if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
+        saveArea = SAVEAREA_FROM_FP(framePtr);
+
+        if (saveArea->xtra.currentPc != NULL)
+            currentPc = saveArea->xtra.currentPc;
+    }
+
+    while (framePtr != NULL) {
+        saveArea = SAVEAREA_FROM_FP(framePtr);
+        method = saveArea->method;
+
+        if (dvmIsBreakFrame((u4*)framePtr)) {
+            //dvmPrintDebugMessage(target, "  (break frame)\n");
+        } else {
+            int relPc;
+
+            if (currentPc != NULL)
+                relPc = currentPc - saveArea->method->insns;
+            else
+                relPc = -1;
+
+            std::string methodName(dvmHumanReadableMethod(method, false));
+            if (dvmIsNativeMethod(method)) {
+                dvmPrintDebugMessage(target, "  at %s(Native Method)\n",
+                        methodName.c_str());
+            } else {
+                dvmPrintDebugMessage(target, "  at %s(%s:%s%d)\n",
+                        methodName.c_str(), dvmGetMethodSourceFile(method),
+                        (relPc >= 0 && first) ? "~" : "",
+                        relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
+            }
+
+            if (first) {
+                /*
+                 * Decorate WAIT and MONITOR threads with some detail on
+                 * the first frame.
+                 *
+                 * warning: wait status not stable, even in suspend
+                 */
+                if (thread->status == THREAD_WAIT ||
+                    thread->status == THREAD_TIMED_WAIT)
+                {
+                    Monitor* mon = thread->waitMonitor;
+                    Object* obj = dvmGetMonitorObject(mon);
+                    if (obj != NULL) {
+                        Thread* joinThread = NULL;
+                        if (obj->clazz == gDvm.classJavaLangVMThread) {
+                            joinThread = dvmGetThreadFromThreadObject(obj);
+                        }
+                        printWaitMessage(target, "on", obj, joinThread);
+                    }
+                } else if (thread->status == THREAD_MONITOR) {
+                    Object* obj;
+                    Thread* owner;
+                    if (extractMonitorEnterObject(thread, &obj, &owner)) {
+                        printWaitMessage(target, "to lock", obj, owner);
+                    }
+                }
+            }
+        }
+
+        /*
+         * Get saved PC for previous frame.  There's no savedPc in a "break"
+         * frame, because that represents native or interpreted code
+         * invoked by the VM.  The saved PC is sitting in the "PC register",
+         * a local variable on the native stack.
+         */
+        currentPc = saveArea->savedPc;
+
+        first = false;
+
+        if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
+            LOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
+                checkCount, framePtr, saveArea->prevFrame);
+            break;
+        }
+        framePtr = saveArea->prevFrame;
+
+        checkCount++;
+        if (checkCount > 300) {
+            dvmPrintDebugMessage(target,
+                "  ***** printed %d frames, not showing any more\n",
+                checkCount);
+            break;
+        }
+    }
+    dvmPrintDebugMessage(target, "\n");
+
+    if (needThreadUnlock) {
+        dvmUnlockThreadList();
+    }
+}
+
+
+/*
+ * Dump the stack for the specified thread.
+ */
+void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
+{
+    dumpFrames(target, thread->interpSave.curFrame, thread);
+}
+
+/*
+ * Dump the stack for the specified thread, which is still running.
+ *
+ * This is very dangerous, because stack frames are being pushed on and
+ * popped off, and if the thread exits we'll be looking at freed memory.
+ * The plan here is to take a snapshot of the stack and then dump that
+ * to try to minimize the chances of catching it mid-update.  This should
+ * work reasonably well on a single-CPU system.
+ *
+ * There is a small chance that calling here will crash the VM.
+ */
+void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
+{
+    StackSaveArea* saveArea;
+    const u1* origStack;
+    u1* stackCopy = NULL;
+    int origSize, fpOffset;
+    void* fp;
+    int depthLimit = 200;
+
+    if (thread == NULL || thread->interpSave.curFrame == NULL) {
+        dvmPrintDebugMessage(target,
+            "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
+            thread, (thread != NULL) ? thread->threadId : 0);
+        return;
+    }
+
+    /* wait for a full quantum */
+    sched_yield();
+
+    /* copy the info we need, then the stack itself */
+    origSize = thread->interpStackSize;
+    origStack = (const u1*) thread->interpStackStart - origSize;
+    stackCopy = (u1*) malloc(origSize);
+    fpOffset = (u1*) thread->interpSave.curFrame - origStack;
+    memcpy(stackCopy, origStack, origSize);
+
+    /*
+     * Run through the stack and rewrite the "prev" pointers.
+     */
+    //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
+    //     thread->interpSave.curFrame);
+    fp = stackCopy + fpOffset;
+    while (true) {
+        int prevOffset;
+
+        if (depthLimit-- < 0) {
+            /* we're probably screwed */
+            dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
+            dvmAbort();
+        }
+        saveArea = SAVEAREA_FROM_FP(fp);
+        if (saveArea->prevFrame == NULL)
+            break;
+
+        prevOffset = (u1*) saveArea->prevFrame - origStack;
+        if (prevOffset < 0 || prevOffset > origSize) {
+            dvmPrintDebugMessage(target,
+                "DumpRunning: bad offset found: %d (from %p %p)\n",
+                prevOffset, origStack, saveArea->prevFrame);
+            saveArea->prevFrame = NULL;
+            break;
+        }
+
+        saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
+        fp = saveArea->prevFrame;
+    }
+
+    /*
+     * We still need to pass the Thread for some monitor wait stuff.
+     */
+    dumpFrames(target, stackCopy + fpOffset, thread);
+    free(stackCopy);
+}
diff --git a/vm/interp/Stack.h b/vm/interp/Stack.h
new file mode 100644
index 0000000..ef3db4a
--- /dev/null
+++ b/vm/interp/Stack.h
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+/*
+ * Stack frames, and uses thereof.
+ */
+#ifndef DALVIK_INTERP_STACK_H_
+#define DALVIK_INTERP_STACK_H_
+
+#include "jni.h"
+#include <stdarg.h>
+
+/*
+Stack layout
+
+In what follows, the "top" of the stack is at a low position in memory,
+and the "bottom" of the stack is in a high position (put more simply,
+they grow downward).  They may be merged with the native stack at a
+later date.  The interpreter assumes that they have a fixed size,
+determined when the thread is created.
+
+Dalvik's registers (of which there can be up to 64K) map to the "ins"
+(method arguments) and "locals" (local variables).  The "outs" (arguments
+to called methods) are specified by the "invoke" operand.  The return
+value, which is passed through the interpreter rather than on the stack,
+is retrieved with a "move-result" instruction.
+
+    Low addresses (0x00000000)
+
+                     +- - - - - - - - -+
+                     -  out0           -
+                     +-----------------+  <-- stack ptr (top of stack)
+                     +  VM-specific    +
+                     +  internal goop  +
+                     +-----------------+  <-- curFrame: FP for cur function
+                     +  v0 == local0   +
++-----------------+  +-----------------+
++  out0           +  +  v1 == in0      +
++-----------------+  +-----------------+
++  out1           +  +  v2 == in1      +
++-----------------+  +-----------------+
++  VM-specific    +
++  internal goop  +
++-----------------+  <-- frame ptr (FP) for previous function
++  v0 == local0   +
++-----------------+
++  v1 == local1   +
++-----------------+
++  v2 == in0      +
++-----------------+
++  v3 == in1      +
++-----------------+
++  v4 == in2      +
++-----------------+
+-                 -
+-                 -
+-                 -
++-----------------+  <-- interpStackStart
+
+    High addresses (0xffffffff)
+
+Note the "ins" and "outs" overlap -- values pushed into the "outs" area
+become the parameters to the called method.  The VM guarantees that there
+will be enough room for all possible "outs" on the stack before calling
+into a method.
+
+All "V registers" are 32 bits, and all stack entries are 32-bit aligned.
+Registers are accessed as a positive offset from the frame pointer,
+e.g. register v2 is fp[2].  64-bit quantities are stored in two adjacent
+registers, addressed by the lower-numbered register, and are in host order.
+64-bit quantities do not need to start in an even-numbered register.
+
+We push two stack frames on when calling an interpreted or native method
+directly from the VM (e.g. invoking <clinit> or via reflection "invoke()").
+The first is a "break" frame, which allows us to tell when a call return or
+exception unroll has reached the VM call site.  Without the break frame the
+stack might look like an uninterrupted series of interpreted method calls.
+The second frame is for the method itself.
+
+The "break" frame is used as an alternative to adding additional fields
+to the StackSaveArea struct itself.  They are recognized by having a
+NULL method pointer.
+
+When calling a native method from interpreted code, the stack setup is
+essentially identical to calling an interpreted method.  Because it's a
+native method, though, there are never any "locals" or "outs".
+
+For native calls into JNI, we want to store a table of local references
+on the stack.  The GC needs to scan them while the native code is running,
+and we want to trivially discard them when the method returns.  See JNI.c
+for a discussion of how this is managed.  In particular note that it is
+possible to push additional call frames on without calling a method.
+*/
+
+
+struct StackSaveArea;
+
+//#define PAD_SAVE_AREA       /* help debug stack trampling */
+
+/*
+ * The VM-specific internal goop.
+ *
+ * The idea is to mimic a typical native stack frame, with copies of the
+ * saved PC and FP.  At some point we'd like to have interpreted and
+ * native code share the same stack, though this makes portability harder.
+ */
+struct StackSaveArea {
+#ifdef PAD_SAVE_AREA
+    u4          pad0, pad1, pad2;
+#endif
+
+#ifdef EASY_GDB
+    /* make it easier to trek through stack frames in GDB */
+    StackSaveArea* prevSave;
+#endif
+
+    /* saved frame pointer for previous frame, or NULL if this is at bottom */
+    u4*         prevFrame;
+
+    /* saved program counter (from method in caller's frame) */
+    const u2*   savedPc;
+
+    /* pointer to method we're *currently* executing; handy for exceptions */
+    const Method* method;
+
+    union {
+        /* for JNI native methods: bottom of local reference segment */
+        u4          localRefCookie;
+
+        /* for interpreted methods: saved current PC, for exception stack
+         * traces and debugger traces */
+        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
+};
+
+/* move between the stack save area and the frame pointer */
+#define SAVEAREA_FROM_FP(_fp)   ((StackSaveArea*)(_fp) -1)
+#define FP_FROM_SAVEAREA(_save) ((u4*) ((StackSaveArea*)(_save) +1))
+
+/* when calling a function, get a pointer to outs[0] */
+#define OUTS_FROM_FP(_fp, _argCount) \
+    ((u4*) ((u1*)SAVEAREA_FROM_FP(_fp) - sizeof(u4) * (_argCount)))
+
+/* reserve this many bytes for handling StackOverflowError */
+#define STACK_OVERFLOW_RESERVE  768
+
+/*
+ * Determine if the frame pointer points to a "break frame".
+ */
+INLINE bool dvmIsBreakFrame(const u4* fp)
+{
+    return SAVEAREA_FROM_FP(fp)->method == NULL;
+}
+
+/*
+ * Initialize the interp stack (call this after allocating storage and
+ * setting thread->interpStackStart).
+ */
+bool dvmInitInterpStack(Thread* thread, int stackSize);
+
+/*
+ * Push a native method frame directly onto the stack.  Used to push the
+ * "fake" native frames at the top of each thread stack.
+ */
+bool dvmPushJNIFrame(Thread* thread, const Method* method);
+
+/*
+ * JNI local frame management.
+ */
+bool dvmPushLocalFrame(Thread* thread, const Method* method);
+bool dvmPopLocalFrame(Thread* thread);
+
+/*
+ * Call an interpreted method from native code.  If this is being called
+ * from a JNI function, references in the argument list will be converted
+ * back to pointers.
+ *
+ * "obj" should be NULL for "direct" methods.
+ */
+void dvmCallMethod(Thread* self, const Method* method, Object* obj,
+    JValue* pResult, ...);
+void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
+    bool fromJni, JValue* pResult, va_list args);
+void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
+    bool fromJni, JValue* pResult, const jvalue* args);
+
+/*
+ * Invoke a method, using the specified arguments and return type, through
+ * a reflection interface.
+ *
+ * Deals with boxing/unboxing primitives and performs widening conversions.
+ *
+ * "obj" should be null for a static method.
+ *
+ * "params" and "returnType" come from the Method object, so we don't have
+ * to re-generate them from the method signature.  "returnType" should be
+ * NULL if we're invoking a constructor.
+ */
+Object* dvmInvokeMethod(Object* invokeObj, const Method* meth,
+    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
+    bool noAccessCheck);
+
+/*
+ * Determine the source file line number, given the program counter offset
+ * into the specified method.  Returns -2 for native methods, -1 if no
+ * match was found.
+ */
+extern "C" int dvmLineNumFromPC(const Method* method, u4 relPc);
+
+/*
+ * Given a frame pointer, compute the current call depth.  The value can be
+ * "exact" (a count of non-break frames) or "vague" (just subtracting
+ * pointers to give relative values).
+ */
+int dvmComputeExactFrameDepth(const void* fp);
+int dvmComputeVagueFrameDepth(Thread* thread, const void* fp);
+
+/*
+ * Get the frame pointer for the caller's stack frame.
+ */
+void* dvmGetCallerFP(const void* curFrame);
+
+/*
+ * Get the class of the method that called us.
+ */
+ClassObject* dvmGetCallerClass(const void* curFrame);
+
+/*
+ * Get the caller's caller's class.  Pass in the current fp.
+ *
+ * This is used by e.g. java.lang.Class, which wants to know about the
+ * class loader of the method that called it.
+ */
+ClassObject* dvmGetCaller2Class(const void* curFrame);
+
+/*
+ * Get the caller's caller's caller's class.  Pass in the current fp.
+ *
+ * This is used by e.g. java.lang.Class, which wants to know about the
+ * class loader of the method that called it.
+ */
+ClassObject* dvmGetCaller3Class(const void* curFrame);
+
+/*
+ * Fill an array of method pointers representing the current stack
+ * trace (element 0 is current frame).
+ */
+void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length);
+
+/*
+ * Common handling for stack overflow.
+ */
+extern "C" void dvmHandleStackOverflow(Thread* self, const Method* method);
+extern "C" void dvmCleanupStackOverflow(Thread* self, const Object* exception);
+
+/* debugging; dvmDumpThread() is probably a better starting point */
+void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread);
+void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread);
+
+#endif  // DALVIK_INTERP_STACK_H_
diff --git a/vm/jdwp/ExpandBuf.cpp b/vm/jdwp/ExpandBuf.cpp
new file mode 100644
index 0000000..b8ff933
--- /dev/null
+++ b/vm/jdwp/ExpandBuf.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+/*
+ * Implementation of an expandable byte buffer.  Designed for serializing
+ * primitive values, e.g. JDWP replies.
+ */
+#include "jdwp/ExpandBuf.h"
+#include "Bits.h"
+#include "Common.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Data structure used to track buffer use.
+ */
+struct ExpandBuf {
+    u1*     storage;
+    int     curLen;
+    int     maxLen;
+};
+
+#define kInitialStorage 64
+
+/*
+ * Allocate a JdwpBuf and some initial storage.
+ */
+ExpandBuf* expandBufAlloc()
+{
+    ExpandBuf* newBuf;
+
+    newBuf = (ExpandBuf*) malloc(sizeof(*newBuf));
+    newBuf->storage = (u1*) malloc(kInitialStorage);
+    newBuf->curLen = 0;
+    newBuf->maxLen = kInitialStorage;
+
+    return newBuf;
+}
+
+/*
+ * Free a JdwpBuf and associated storage.
+ */
+void expandBufFree(ExpandBuf* pBuf)
+{
+    if (pBuf == NULL)
+        return;
+
+    free(pBuf->storage);
+    free(pBuf);
+}
+
+/*
+ * Get a pointer to the start of the buffer.
+ */
+u1* expandBufGetBuffer(ExpandBuf* pBuf)
+{
+    return pBuf->storage;
+}
+
+/*
+ * Get the amount of data currently in the buffer.
+ */
+size_t expandBufGetLength(ExpandBuf* pBuf)
+{
+    return pBuf->curLen;
+}
+
+
+/*
+ * Ensure that the buffer has enough space to hold incoming data.  If it
+ * doesn't, resize the buffer.
+ */
+static void ensureSpace(ExpandBuf* pBuf, int newCount)
+{
+    u1* newPtr;
+
+    if (pBuf->curLen + newCount <= pBuf->maxLen)
+        return;
+
+    while (pBuf->curLen + newCount > pBuf->maxLen)
+        pBuf->maxLen *= 2;
+
+    newPtr = (u1*) realloc(pBuf->storage, pBuf->maxLen);
+    if (newPtr == NULL) {
+        LOGE("realloc(%d) failed", pBuf->maxLen);
+        abort();
+    }
+
+    pBuf->storage = newPtr;
+}
+
+/*
+ * Allocate some space in the buffer.
+ */
+u1* expandBufAddSpace(ExpandBuf* pBuf, int gapSize)
+{
+    u1* gapStart;
+
+    ensureSpace(pBuf, gapSize);
+    gapStart = pBuf->storage + pBuf->curLen;
+    /* do we want to garbage-fill the gap for debugging? */
+    pBuf->curLen += gapSize;
+
+    return gapStart;
+}
+
+/*
+ * Append a byte.
+ */
+void expandBufAdd1(ExpandBuf* pBuf, u1 val)
+{
+    ensureSpace(pBuf, sizeof(val));
+    *(pBuf->storage + pBuf->curLen) = val;
+    pBuf->curLen++;
+}
+
+/*
+ * Append two big-endian bytes.
+ */
+void expandBufAdd2BE(ExpandBuf* pBuf, u2 val)
+{
+    ensureSpace(pBuf, sizeof(val));
+    set2BE(pBuf->storage + pBuf->curLen, val);
+    pBuf->curLen += sizeof(val);
+}
+
+/*
+ * Append four big-endian bytes.
+ */
+void expandBufAdd4BE(ExpandBuf* pBuf, u4 val)
+{
+    ensureSpace(pBuf, sizeof(val));
+    set4BE(pBuf->storage + pBuf->curLen, val);
+    pBuf->curLen += sizeof(val);
+}
+
+/*
+ * Append eight big-endian bytes.
+ */
+void expandBufAdd8BE(ExpandBuf* pBuf, u8 val)
+{
+    ensureSpace(pBuf, sizeof(val));
+    set8BE(pBuf->storage + pBuf->curLen, val);
+    pBuf->curLen += sizeof(val);
+}
+
+/*
+ * Add a UTF8 string as a 4-byte length followed by a non-NULL-terminated
+ * string.
+ *
+ * Because these strings are coming out of the VM, it's safe to assume that
+ * they can be null-terminated (either they don't have null bytes or they
+ * have stored null bytes in a multi-byte encoding).
+ */
+void expandBufAddUtf8String(ExpandBuf* pBuf, const u1* str)
+{
+    int strLen = strlen((const char*)str);
+
+    ensureSpace(pBuf, sizeof(u4) + strLen);
+    setUtf8String(pBuf->storage + pBuf->curLen, str);
+    pBuf->curLen += sizeof(u4) + strLen;
+}
diff --git a/vm/jdwp/ExpandBuf.h b/vm/jdwp/ExpandBuf.h
new file mode 100644
index 0000000..0bbc0c6
--- /dev/null
+++ b/vm/jdwp/ExpandBuf.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+/*
+ * Expanding byte buffer, with primitives for appending basic data types.
+ */
+#ifndef DALVIK_JDWP_EXPANDBUF_H_
+#define DALVIK_JDWP_EXPANDBUF_H_
+
+#include "Common.h"     // need u1/u2/u4/u8 types
+
+struct ExpandBuf;   /* private */
+
+/* create a new struct */
+ExpandBuf* expandBufAlloc(void);
+/* free storage */
+void expandBufFree(ExpandBuf* pBuf);
+
+/*
+ * Accessors.  The buffer pointer and length will only be valid until more
+ * data is added.
+ */
+u1* expandBufGetBuffer(ExpandBuf* pBuf);
+size_t expandBufGetLength(ExpandBuf* pBuf);
+
+/*
+ * The "add" operations allocate additional storage and append the data.
+ *
+ * There are no "get" operations included with this "class", other than
+ * GetBuffer().  If you want to get or set data from a position other
+ * than the end, get a pointer to the buffer and use the inline functions
+ * defined elsewhere.
+ *
+ * expandBufAddSpace() returns a pointer to the *start* of the region
+ * added.
+ */
+u1* expandBufAddSpace(ExpandBuf* pBuf, int gapSize);
+void expandBufAdd1(ExpandBuf* pBuf, u1 val);
+void expandBufAdd2BE(ExpandBuf* pBuf, u2 val);
+void expandBufAdd4BE(ExpandBuf* pBuf, u4 val);
+void expandBufAdd8BE(ExpandBuf* pBuf, u8 val);
+void expandBufAddUtf8String(ExpandBuf* pBuf, const u1* str);
+
+#endif  // DALVIK_JDWP_EXPANDBUF_H_
diff --git a/vm/jdwp/Jdwp.h b/vm/jdwp/Jdwp.h
new file mode 100644
index 0000000..467cecd
--- /dev/null
+++ b/vm/jdwp/Jdwp.h
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ */
+/*
+ * JDWP "public" interface.  The main body of the VM should only use JDWP
+ * structures and functions declared here.
+ *
+ * The JDWP code follows the DalvikVM rules for naming conventions, but
+ * attempts to remain independent of VM innards (e.g. it doesn't access VM
+ * data structures directly).  All calls go through Debugger.c.
+ */
+#ifndef DALVIK_JDWP_JDWP_H_
+#define DALVIK_JDWP_JDWP_H_
+
+#include "jdwp/JdwpConstants.h"
+#include "jdwp/ExpandBuf.h"
+#include "Common.h"
+#include "Bits.h"
+#include <pthread.h>
+
+struct JdwpState;       /* opaque */
+
+/*
+ * Fundamental types.
+ *
+ * ObjectId and RefTypeId must be the same size.
+ */
+typedef u4 FieldId;     /* static or instance field */
+typedef u4 MethodId;    /* any kind of method, including constructors */
+typedef u8 ObjectId;    /* any object (threadID, stringID, arrayID, etc) */
+typedef u8 RefTypeId;   /* like ObjectID, but unique for Class objects */
+typedef u8 FrameId;     /* short-lived stack frame ID */
+
+/*
+ * Match these with the type sizes.  This way we don't have to pass
+ * a value and a length.
+ */
+INLINE FieldId dvmReadFieldId(const u1** pBuf)      { return read4BE(pBuf); }
+INLINE MethodId dvmReadMethodId(const u1** pBuf)    { return read4BE(pBuf); }
+INLINE ObjectId dvmReadObjectId(const u1** pBuf)    { return read8BE(pBuf); }
+INLINE RefTypeId dvmReadRefTypeId(const u1** pBuf)  { return read8BE(pBuf); }
+INLINE FrameId dvmReadFrameId(const u1** pBuf)      { return read8BE(pBuf); }
+INLINE void dvmSetFieldId(u1* buf, FieldId val)     { return set4BE(buf, val); }
+INLINE void dvmSetMethodId(u1* buf, MethodId val)   { return set4BE(buf, val); }
+INLINE void dvmSetObjectId(u1* buf, ObjectId val)   { return set8BE(buf, val); }
+INLINE void dvmSetRefTypeId(u1* buf, RefTypeId val) { return set8BE(buf, val); }
+INLINE void dvmSetFrameId(u1* buf, FrameId val)     { return set8BE(buf, val); }
+INLINE void expandBufAddFieldId(ExpandBuf* pReply, FieldId id) {
+    expandBufAdd4BE(pReply, id);
+}
+INLINE void expandBufAddMethodId(ExpandBuf* pReply, MethodId id) {
+    expandBufAdd4BE(pReply, id);
+}
+INLINE void expandBufAddObjectId(ExpandBuf* pReply, ObjectId id) {
+    expandBufAdd8BE(pReply, id);
+}
+INLINE void expandBufAddRefTypeId(ExpandBuf* pReply, RefTypeId id) {
+    expandBufAdd8BE(pReply, id);
+}
+INLINE void expandBufAddFrameId(ExpandBuf* pReply, FrameId id) {
+    expandBufAdd8BE(pReply, id);
+}
+
+
+/*
+ * Holds a JDWP "location".
+ */
+struct JdwpLocation {
+    u1          typeTag;        /* class or interface? */
+    RefTypeId   classId;        /* method->clazz */
+    MethodId    methodId;       /* method in which "idx" resides */
+    u8          idx;            /* relative index into code block */
+};
+
+/*
+ * How we talk to the debugger.
+ */
+enum JdwpTransportType {
+    kJdwpTransportUnknown = 0,
+    kJdwpTransportSocket,       /* transport=dt_socket */
+    kJdwpTransportAndroidAdb,   /* transport=dt_android_adb */
+};
+
+/*
+ * Holds collection of JDWP initialization parameters.
+ */
+struct JdwpStartupParams {
+    JdwpTransportType transport;
+    bool        server;
+    bool        suspend;
+    char        host[64];
+    short       port;
+    /* more will be here someday */
+};
+
+/*
+ * Perform one-time initialization.
+ *
+ * Among other things, this binds to a port to listen for a connection from
+ * the debugger.
+ *
+ * Returns a newly-allocated JdwpState struct on success, or NULL on failure.
+ */
+JdwpState* dvmJdwpStartup(const JdwpStartupParams* params);
+
+/*
+ * Shut everything down.
+ */
+void dvmJdwpShutdown(JdwpState* state);
+
+/*
+ * Returns "true" if a debugger or DDM is connected.
+ */
+bool dvmJdwpIsActive(JdwpState* state);
+
+/*
+ * Return the debugger thread's handle, or 0 if the debugger thread isn't
+ * running.
+ */
+pthread_t dvmJdwpGetDebugThread(JdwpState* state);
+
+/*
+ * Get time, in milliseconds, since the last debugger activity.
+ */
+s8 dvmJdwpLastDebuggerActivity(JdwpState* state);
+
+/*
+ * When we hit a debugger event that requires suspension, it's important
+ * that we wait for the thread to suspend itself before processing any
+ * additional requests.  (Otherwise, if the debugger immediately sends a
+ * "resume thread" command, the resume might arrive before the thread has
+ * suspended itself.)
+ *
+ * The thread should call the "set" function before sending the event to
+ * the debugger.  The main JDWP handler loop calls "get" before processing
+ * an event, and will wait for thread suspension if it's set.  Once the
+ * thread has suspended itself, the JDWP handler calls "clear" and
+ * continues processing the current event.  This works in the suspend-all
+ * case because the event thread doesn't suspend itself until everything
+ * else has suspended.
+ *
+ * It's possible that multiple threads could encounter thread-suspending
+ * events at the same time, so we grab a mutex in the "set" call, and
+ * release it in the "clear" call.
+ */
+//ObjectId dvmJdwpGetWaitForEventThread(JdwpState* state);
+void dvmJdwpSetWaitForEventThread(JdwpState* state, ObjectId threadId);
+void dvmJdwpClearWaitForEventThread(JdwpState* state);
+
+/*
+ * Network functions.
+ */
+bool dvmJdwpCheckConnection(JdwpState* state);
+bool dvmJdwpAcceptConnection(JdwpState* state);
+bool dvmJdwpEstablishConnection(JdwpState* state);
+void dvmJdwpCloseConnection(JdwpState* state);
+bool dvmJdwpProcessIncoming(JdwpState* state);
+
+
+/*
+ * These notify the debug code that something interesting has happened.  This
+ * could be a thread starting or ending, an exception, or an opportunity
+ * for a breakpoint.  These calls do not mean that an event the debugger
+ * is interested has happened, just that something has happened that the
+ * debugger *might* be interested in.
+ *
+ * The item of interest may trigger multiple events, some or all of which
+ * are grouped together in a single response.
+ *
+ * The event may cause the current thread or all threads (except the
+ * JDWP support thread) to be suspended.
+ */
+
+/*
+ * The VM has finished initializing.  Only called when the debugger is
+ * connected at the time initialization completes.
+ */
+bool dvmJdwpPostVMStart(JdwpState* state, bool suspend);
+
+/*
+ * A location of interest has been reached.  This is used for breakpoints,
+ * single-stepping, and method entry/exit.  (JDWP requires that these four
+ * events are grouped together in a single response.)
+ *
+ * In some cases "*pLoc" will just have a method and class name, e.g. when
+ * issuing a MethodEntry on a native method.
+ *
+ * "eventFlags" indicates the types of events that have occurred.
+ */
+bool dvmJdwpPostLocationEvent(JdwpState* state, const JdwpLocation* pLoc,
+    ObjectId thisPtr, int eventFlags);
+
+/*
+ * An exception has been thrown.
+ *
+ * Pass in a zeroed-out "*pCatchLoc" if the exception wasn't caught.
+ */
+bool dvmJdwpPostException(JdwpState* state, const JdwpLocation* pThrowLoc,
+    ObjectId excepId, RefTypeId excepClassId, const JdwpLocation* pCatchLoc,
+    ObjectId thisPtr);
+
+/*
+ * A thread has started or stopped.
+ */
+bool dvmJdwpPostThreadChange(JdwpState* state, ObjectId threadId, bool start);
+
+/*
+ * Class has been prepared.
+ */
+bool dvmJdwpPostClassPrepare(JdwpState* state, int tag, RefTypeId refTypeId,
+    const char* signature, int status);
+
+/*
+ * The VM is about to stop.
+ */
+bool dvmJdwpPostVMDeath(JdwpState* state);
+
+/*
+ * Send up a chunk of DDM data.
+ */
+void dvmJdwpDdmSendChunkV(JdwpState* state, int type, const struct iovec* iov,
+    int iovcnt);
+
+#endif  // DALVIK_JDWP_JDWP_H_
diff --git a/vm/jdwp/JdwpAdb.cpp b/vm/jdwp/JdwpAdb.cpp
new file mode 100644
index 0000000..f575a7d
--- /dev/null
+++ b/vm/jdwp/JdwpAdb.cpp
@@ -0,0 +1,746 @@
+/*
+ * 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.
+ */
+
+#include "jdwp/JdwpPriv.h"
+#include "jdwp/JdwpHandler.h"
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
+#include <cutils/sockets.h>
+
+/*
+ * The JDWP <-> ADB transport protocol is explained in detail
+ * in system/core/adb/jdwp_service.c. Here's a summary.
+ *
+ * 1/ when the JDWP thread starts, it tries to connect to a Unix
+ *    domain stream socket (@jdwp-control) that is opened by the
+ *    ADB daemon.
+ *
+ * 2/ it then sends the current process PID as a string of 4 hexadecimal
+ *    chars (no terminating zero)
+ *
+ * 3/ then, it uses recvmsg to receive file descriptors from the
+ *    daemon. each incoming file descriptor is a pass-through to
+ *    a given JDWP debugger, that can be used to read the usual
+ *    JDWP-handshake, etc...
+ */
+
+#define kInputBufferSize    8192
+
+#define kMagicHandshake     "JDWP-Handshake"
+#define kMagicHandshakeLen  (sizeof(kMagicHandshake)-1)
+
+#define kJdwpControlName    "\0jdwp-control"
+#define kJdwpControlNameLen (sizeof(kJdwpControlName)-1)
+
+struct JdwpNetState : public JdwpNetStateBase {
+    int                 controlSock;
+    bool                awaitingHandshake;
+    bool                shuttingDown;
+    int                 wakeFds[2];
+
+    int                 inputCount;
+    unsigned char       inputBuffer[kInputBufferSize];
+
+    socklen_t           controlAddrLen;
+    union {
+        struct sockaddr_un  controlAddrUn;
+        struct sockaddr     controlAddrPlain;
+    } controlAddr;
+
+    JdwpNetState()
+    {
+        controlSock = -1;
+        awaitingHandshake = false;
+        shuttingDown = false;
+        wakeFds[0] = -1;
+        wakeFds[1] = -1;
+
+        inputCount = 0;
+
+        controlAddr.controlAddrUn.sun_family = AF_UNIX;
+        controlAddrLen = sizeof(controlAddr.controlAddrUn.sun_family) +
+                kJdwpControlNameLen;
+        memcpy(controlAddr.controlAddrUn.sun_path, kJdwpControlName,
+                kJdwpControlNameLen);
+    }
+};
+
+static void
+adbStateFree( JdwpNetState*  netState )
+{
+    if (netState == NULL)
+        return;
+
+    if (netState->clientSock >= 0) {
+        shutdown(netState->clientSock, SHUT_RDWR);
+        close(netState->clientSock);
+    }
+    if (netState->controlSock >= 0) {
+        shutdown(netState->controlSock, SHUT_RDWR);
+        close(netState->controlSock);
+    }
+    if (netState->wakeFds[0] >= 0) {
+        close(netState->wakeFds[0]);
+        netState->wakeFds[0] = -1;
+    }
+    if (netState->wakeFds[1] >= 0) {
+        close(netState->wakeFds[1]);
+        netState->wakeFds[1] = -1;
+    }
+
+    delete netState;
+}
+
+/*
+ * Do initial prep work, e.g. binding to ports and opening files.  This
+ * runs in the main thread, before the JDWP thread starts, so it shouldn't
+ * do anything that might block forever.
+ */
+static bool startup(struct JdwpState* state, const JdwpStartupParams* pParams)
+{
+    JdwpNetState*  netState;
+
+    LOGV("ADB transport startup");
+
+    state->netState = netState = new JdwpNetState;
+    if (netState == NULL)
+        return false;
+
+    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;
+    struct cmsghdr*  cmsg;
+    struct iovec     iov;
+    char             dummy = '!';
+    union {
+        struct cmsghdr cm;
+        char buffer[CMSG_SPACE(sizeof(int))];
+    } cm_un;
+    int              ret;
+
+    iov.iov_base       = &dummy;
+    iov.iov_len        = 1;
+    msg.msg_name       = NULL;
+    msg.msg_namelen    = 0;
+    msg.msg_iov        = &iov;
+    msg.msg_iovlen     = 1;
+    msg.msg_flags      = 0;
+    msg.msg_control    = cm_un.buffer;
+    msg.msg_controllen = sizeof(cm_un.buffer);
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len   = msg.msg_controllen;
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type  = SCM_RIGHTS;
+    ((int*)(void*)CMSG_DATA(cmsg))[0] = -1;
+
+    do {
+        ret = recvmsg(netState->controlSock, &msg, 0);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret <= 0) {
+        if (ret < 0) {
+            LOGW("receiving file descriptor from ADB failed (socket %d): %s",
+                 netState->controlSock, strerror(errno));
+        }
+        close(netState->controlSock);
+        netState->controlSock = -1;
+        return -1;
+    }
+
+    return ((int*)(void*)CMSG_DATA(cmsg))[0];
+}
+
+/*
+ * Block forever, waiting for a debugger to connect to us.  Called from the
+ * JDWP thread.
+ *
+ * This needs to un-block and return "false" if the VM is shutting down.  It
+ * should return "true" when it successfully accepts a connection.
+ */
+static bool acceptConnection(struct JdwpState* state)
+{
+    JdwpNetState*  netState = state->netState;
+    int retryCount = 0;
+
+    /* first, ensure that we get a connection to the ADB daemon */
+
+retry:
+    if (netState->shuttingDown)
+        return false;
+
+    if (netState->controlSock < 0) {
+        int        sleep_ms     = 500;
+        const int  sleep_max_ms = 2*1000;
+        char       buff[5];
+
+        netState->controlSock = socket(PF_UNIX, SOCK_STREAM, 0);
+        if (netState->controlSock < 0) {
+            LOGE("Could not create ADB control socket:%s",
+                 strerror(errno));
+            return false;
+        }
+
+        if (pipe(netState->wakeFds) < 0) {
+            LOGE("pipe failed");
+            return false;
+        }
+
+        snprintf(buff, sizeof(buff), "%04x", getpid());
+        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);
+            if (!ret) {
+                if (!socket_peer_is_trusted(netState->controlSock)) {
+                    if (shutdown(netState->controlSock, SHUT_RDWR)) {
+                        LOGE("trouble shutting down socket: %s", strerror(errno));
+                    }
+                    return false;
+                }
+
+                /* now try to send our pid to the ADB daemon */
+                do {
+                    ret = send( netState->controlSock, buff, 4, 0 );
+                } while (ret < 0 && errno == EINTR);
+
+                if (ret >= 0) {
+                    LOGV("PID sent as '%.*s' to ADB", 4, buff);
+                    break;
+                }
+
+                LOGE("Weird, can't send JDWP process pid to ADB: %s",
+                     strerror(errno));
+                return false;
+            }
+            LOGV("Can't connect to ADB control socket:%s",
+                 strerror(errno));
+
+            usleep( sleep_ms*1000 );
+
+            sleep_ms += (sleep_ms >> 1);
+            if (sleep_ms > sleep_max_ms)
+                sleep_ms = sleep_max_ms;
+
+            if (netState->shuttingDown)
+                return false;
+        }
+    }
+
+    LOGV("trying to receive file descriptor from ADB");
+    /* now we can receive a client file descriptor */
+    netState->clientSock = receiveClientFd(netState);
+    if (netState->shuttingDown)
+        return false;       // suppress logs and additional activity
+
+    if (netState->clientSock < 0) {
+        if (++retryCount > 5) {
+            LOGE("adb connection max retries exceeded");
+            return false;
+        }
+        goto retry;
+    } else {
+        LOGV("received file descriptor %d from ADB", netState->clientSock);
+        netState->awaitingHandshake = 1;
+        netState->inputCount = 0;
+        return true;
+    }
+}
+
+/*
+ * Connect out to a debugger (for server=n).  Not required.
+ */
+static bool establishConnection(struct JdwpState* state)
+{
+    return false;
+}
+
+/*
+ * Close a connection from a debugger (which may have already dropped us).
+ * Only called from the JDWP thread.
+ */
+static void closeConnection(struct JdwpState* state)
+{
+    JdwpNetState* netState;
+
+    assert(state != NULL && state->netState != NULL);
+
+    netState = state->netState;
+    if (netState->clientSock < 0)
+        return;
+
+    LOGV("+++ closed JDWP <-> ADB connection");
+
+    close(netState->clientSock);
+    netState->clientSock = -1;
+}
+
+/*
+ * Close all network stuff, including the socket we use to listen for
+ * new connections.
+ *
+ * May be called from a non-JDWP thread, e.g. when the VM is shutting down.
+ */
+static void adbStateShutdown(struct JdwpNetState* netState)
+{
+    int  controlSock;
+    int  clientSock;
+
+    if (netState == NULL)
+        return;
+
+    netState->shuttingDown = true;
+
+    clientSock = netState->clientSock;
+    if (clientSock >= 0) {
+        shutdown(clientSock, SHUT_RDWR);
+        netState->clientSock = -1;
+    }
+
+    controlSock = netState->controlSock;
+    if (controlSock >= 0) {
+        shutdown(controlSock, SHUT_RDWR);
+        netState->controlSock = -1;
+    }
+
+    if (netState->wakeFds[1] >= 0) {
+        LOGV("+++ writing to wakePipe");
+        write(netState->wakeFds[1], "", 1);
+    }
+}
+
+static void netShutdown(JdwpState* state)
+{
+    adbStateShutdown(state->netState);
+}
+
+/*
+ * Free up anything we put in state->netState.  This is called after
+ * "netShutdown", after the JDWP thread has stopped.
+ */
+static void netFree(struct JdwpState* state)
+{
+    JdwpNetState*  netState = state->netState;
+
+    adbStateFree(netState);
+}
+
+/*
+ * Is a debugger connected to us?
+ */
+static bool isConnected(struct JdwpState* state)
+{
+    return (state->netState != NULL   &&
+            state->netState->clientSock >= 0);
+}
+
+/*
+ * Are we still waiting for the JDWP handshake?
+ */
+static bool awaitingHandshake(struct JdwpState* state)
+{
+    return state->netState->awaitingHandshake;
+}
+
+/*
+ * Figure out if we have a full packet in the buffer.
+ */
+static bool haveFullPacket(JdwpNetState* netState)
+{
+    long length;
+
+    if (netState->awaitingHandshake)
+        return (netState->inputCount >= (int) kMagicHandshakeLen);
+
+    if (netState->inputCount < 4)
+        return false;
+
+    length = get4BE(netState->inputBuffer);
+    return (netState->inputCount >= length);
+}
+
+/*
+ * Consume bytes from the buffer.
+ *
+ * This would be more efficient with a circular buffer.  However, we're
+ * usually only going to find one packet, which is trivial to handle.
+ */
+static void consumeBytes(JdwpNetState* netState, int count)
+{
+    assert(count > 0);
+    assert(count <= netState->inputCount);
+
+    if (count == netState->inputCount) {
+        netState->inputCount = 0;
+        return;
+    }
+
+    memmove(netState->inputBuffer, netState->inputBuffer + count,
+        netState->inputCount - count);
+    netState->inputCount -= count;
+}
+
+/*
+ * Handle a packet.  Returns "false" if we encounter a connection-fatal error.
+ */
+static bool handlePacket(JdwpState* state)
+{
+    JdwpNetState* netState = state->netState;
+    const unsigned char* buf = netState->inputBuffer;
+    JdwpReqHeader hdr;
+    u4 length, id;
+    u1 flags, cmdSet, cmd;
+    u2 error;
+    bool reply;
+    int dataLen;
+
+    cmd = cmdSet = 0;       // shut up gcc
+
+    length = read4BE(&buf);
+    id = read4BE(&buf);
+    flags = read1(&buf);
+    if ((flags & kJDWPFlagReply) != 0) {
+        reply = true;
+        error = read2BE(&buf);
+    } else {
+        reply = false;
+        cmdSet = read1(&buf);
+        cmd = read1(&buf);
+    }
+
+    assert((int) length <= netState->inputCount);
+    dataLen = length - (buf - netState->inputBuffer);
+
+    if (!reply) {
+        ExpandBuf* pReply = expandBufAlloc();
+
+        hdr.length = length;
+        hdr.id = id;
+        hdr.cmdSet = cmdSet;
+        hdr.cmd = cmd;
+        dvmJdwpProcessRequest(state, &hdr, buf, dataLen, pReply);
+        if (expandBufGetLength(pReply) > 0) {
+            ssize_t cc = netState->writePacket(pReply);
+
+            if (cc != (ssize_t) expandBufGetLength(pReply)) {
+                LOGE("Failed sending reply to debugger: %s", strerror(errno));
+                expandBufFree(pReply);
+                return false;
+            }
+        } else {
+            LOGW("No reply created for set=%d cmd=%d", cmdSet, cmd);
+        }
+        expandBufFree(pReply);
+    } else {
+        LOGV("reply?!");
+        assert(false);
+    }
+
+    LOGV("----------");
+
+    consumeBytes(netState, length);
+    return true;
+}
+
+/*
+ * Process incoming data.  If no data is available, this will block until
+ * some arrives.
+ *
+ * If we get a full packet, handle it.
+ *
+ * To take some of the mystery out of life, we want to reject incoming
+ * connections if we already have a debugger attached.  If we don't, the
+ * debugger will just mysteriously hang until it times out.  We could just
+ * close the listen socket, but there's a good chance we won't be able to
+ * bind to the same port again, which would confuse utilities.
+ *
+ * Returns "false" on error (indicating that the connection has been severed),
+ * "true" if things are still okay.
+ */
+static bool processIncoming(JdwpState* state)
+{
+    JdwpNetState* netState = state->netState;
+    int readCount;
+
+    assert(netState->clientSock >= 0);
+
+    if (!haveFullPacket(netState)) {
+        /* read some more, looping until we have data */
+        errno = 0;
+        while (1) {
+            int selCount;
+            fd_set readfds;
+            int maxfd = -1;
+            int fd;
+
+            FD_ZERO(&readfds);
+
+            /* configure fds; note these may get zapped by another thread */
+            fd = netState->controlSock;
+            if (fd >= 0) {
+                FD_SET(fd, &readfds);
+                if (maxfd < fd)
+                    maxfd = fd;
+            }
+            fd = netState->clientSock;
+            if (fd >= 0) {
+                FD_SET(fd, &readfds);
+                if (maxfd < fd)
+                    maxfd = fd;
+            }
+            fd = netState->wakeFds[0];
+            if (fd >= 0) {
+                FD_SET(fd, &readfds);
+                if (maxfd < fd)
+                    maxfd = fd;
+            } else {
+                LOGI("NOTE: entering select w/o wakepipe");
+            }
+
+            if (maxfd < 0) {
+                LOGV("+++ all fds are closed");
+                return false;
+            }
+
+            /*
+             * Select blocks until it sees activity on the file descriptors.
+             * Closing the local file descriptor does not count as activity,
+             * so we can't rely on that to wake us up (it works for read()
+             * and accept(), but not select()).
+             *
+             * We can do one of three things: (1) send a signal and catch
+             * EINTR, (2) open an additional fd ("wakePipe") and write to
+             * it when it's time to exit, or (3) time out periodically and
+             * re-issue the select.  We're currently using #2, as it's more
+             * reliable than #1 and generally better than #3.  Wastes two fds.
+             */
+            selCount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+            if (selCount < 0) {
+                if (errno == EINTR)
+                    continue;
+                LOGE("select failed: %s", strerror(errno));
+                goto fail;
+            }
+
+            if (netState->wakeFds[0] >= 0 &&
+                FD_ISSET(netState->wakeFds[0], &readfds))
+            {
+                LOGD("Got wake-up signal, bailing out of select");
+                goto fail;
+            }
+            if (netState->controlSock >= 0 &&
+                FD_ISSET(netState->controlSock, &readfds))
+            {
+                int  sock = receiveClientFd(netState);
+                if (sock >= 0) {
+                    LOGI("Ignoring second debugger -- accepting and dropping");
+                    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))
+            {
+                readCount = read(netState->clientSock,
+                                netState->inputBuffer + netState->inputCount,
+                    sizeof(netState->inputBuffer) - netState->inputCount);
+                if (readCount < 0) {
+                    /* read failed */
+                    if (errno != EINTR)
+                        goto fail;
+                    LOGD("+++ EINTR hit");
+                    return true;
+                } else if (readCount == 0) {
+                    /* EOF hit -- far end went away */
+                    LOGV("+++ peer disconnected");
+                    goto fail;
+                } else
+                    break;
+            }
+        }
+
+        netState->inputCount += readCount;
+        if (!haveFullPacket(netState))
+            return true;        /* still not there yet */
+    }
+
+    /*
+     * Special-case the initial handshake.  For some bizarre reason we're
+     * expected to emulate bad tty settings by echoing the request back
+     * exactly as it was sent.  Note the handshake is always initiated by
+     * the debugger, no matter who connects to whom.
+     *
+     * Other than this one case, the protocol [claims to be] stateless.
+     */
+    if (netState->awaitingHandshake) {
+        int cc;
+
+        if (memcmp(netState->inputBuffer,
+                kMagicHandshake, kMagicHandshakeLen) != 0)
+        {
+            LOGE("ERROR: bad handshake '%.14s'", netState->inputBuffer);
+            goto fail;
+        }
+
+        errno = 0;
+        cc = write(netState->clientSock, netState->inputBuffer,
+                kMagicHandshakeLen);
+        if (cc != kMagicHandshakeLen) {
+            LOGE("Failed writing handshake bytes: %s (%d of %d)",
+                strerror(errno), cc, (int) kMagicHandshakeLen);
+            goto fail;
+        }
+
+        consumeBytes(netState, kMagicHandshakeLen);
+        netState->awaitingHandshake = false;
+        LOGV("+++ handshake complete");
+        return true;
+    }
+
+    /*
+     * Handle this packet.
+     */
+    return handlePacket(state);
+
+fail:
+    closeConnection(state);
+    return false;
+}
+
+/*
+ * Send a request.
+ *
+ * The entire packet must be sent with a single write() call to avoid
+ * threading issues.
+ *
+ * Returns "true" if it was sent successfully.
+ */
+static bool sendRequest(JdwpState* state, ExpandBuf* pReq)
+{
+    JdwpNetState* netState = state->netState;
+
+    if (netState->clientSock < 0) {
+        /* can happen with some DDMS events */
+        LOGV("NOT sending request -- no debugger is attached");
+        return false;
+    }
+
+    errno = 0;
+
+    ssize_t cc = netState->writePacket(pReq);
+
+    if (cc != (ssize_t) expandBufGetLength(pReq)) {
+        LOGE("Failed sending req to debugger: %s (%d of %d)",
+            strerror(errno), (int) cc, (int) expandBufGetLength(pReq));
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Send a request that was split into multiple buffers.
+ *
+ * The entire packet must be sent with a single writev() call to avoid
+ * threading issues.
+ *
+ * Returns "true" if it was sent successfully.
+ */
+static bool sendBufferedRequest(JdwpState* state, const struct iovec* iov,
+    int iovcnt)
+{
+    JdwpNetState* netState = state->netState;
+
+    if (netState->clientSock < 0) {
+        /* can happen with some DDMS events */
+        LOGV("NOT sending request -- no debugger is attached");
+        return false;
+    }
+
+    size_t expected = 0;
+    int i;
+    for (i = 0; i < iovcnt; i++)
+        expected += iov[i].iov_len;
+
+    ssize_t actual = netState->writeBufferedPacket(iov, iovcnt);
+
+    if ((size_t)actual != expected) {
+        LOGE("Failed sending b-req to debugger: %s (%d of %zu)",
+            strerror(errno), (int) actual, expected);
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Our functions.
+ */
+static const JdwpTransport socketTransport = {
+    startup,
+    acceptConnection,
+    establishConnection,
+    closeConnection,
+    netShutdown,
+    netFree,
+    isConnected,
+    awaitingHandshake,
+    processIncoming,
+    sendRequest,
+    sendBufferedRequest
+};
+
+/*
+ * Return our set.
+ */
+const JdwpTransport* dvmJdwpAndroidAdbTransport()
+{
+    return &socketTransport;
+}
diff --git a/vm/jdwp/JdwpConstants.cpp b/vm/jdwp/JdwpConstants.cpp
new file mode 100644
index 0000000..e98ff43
--- /dev/null
+++ b/vm/jdwp/JdwpConstants.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+/*
+ * String constants to go along with enumerated values.  (Pity we don't
+ * have enumerated constant reflection in C.)  These are only needed for
+ * making the output human-readable.
+ */
+#include "jdwp/JdwpConstants.h"
+
+/*
+ * Return a string for the error code.
+ */
+const char* dvmJdwpErrorStr(JdwpError error)
+{
+    switch (error) {
+    case ERR_NONE:
+        return "NONE";
+    case ERR_INVALID_THREAD:
+        return "INVALID_THREAD";
+    case ERR_INVALID_THREAD_GROUP:
+        return "INVALID_THREAD_GROUP";
+    case ERR_INVALID_PRIORITY:
+        return "INVALID_PRIORITY";
+    case ERR_THREAD_NOT_SUSPENDED:
+        return "THREAD_NOT_SUSPENDED";
+    case ERR_THREAD_SUSPENDED:
+        return "THREAD_SUSPENDED";
+    case ERR_INVALID_OBJECT:
+        return "INVALID_OBJEC";
+    case ERR_INVALID_CLASS:
+        return "INVALID_CLASS";
+    case ERR_CLASS_NOT_PREPARED:
+        return "CLASS_NOT_PREPARED";
+    case ERR_INVALID_METHODID:
+        return "INVALID_METHODID";
+    case ERR_INVALID_LOCATION:
+        return "INVALID_LOCATION";
+    case ERR_INVALID_FIELDID:
+        return "INVALID_FIELDID";
+    case ERR_INVALID_FRAMEID:
+        return "INVALID_FRAMEID";
+    case ERR_NO_MORE_FRAMES:
+        return "NO_MORE_FRAMES";
+    case ERR_OPAQUE_FRAME:
+        return "OPAQUE_FRAME";
+    case ERR_NOT_CURRENT_FRAME:
+        return "NOT_CURRENT_FRAME";
+    case ERR_TYPE_MISMATCH:
+        return "TYPE_MISMATCH";
+    case ERR_INVALID_SLOT:
+        return "INVALID_SLOT";
+    case ERR_DUPLICATE:
+        return "DUPLICATE";
+    case ERR_NOT_FOUND:
+        return "NOT_FOUND";
+    case ERR_INVALID_MONITOR:
+        return "INVALID_MONITOR";
+    case ERR_NOT_MONITOR_OWNER:
+        return "NOT_MONITOR_OWNER";
+    case ERR_INTERRUPT:
+        return "INTERRUPT";
+    case ERR_INVALID_CLASS_FORMAT:
+        return "INVALID_CLASS_FORMAT";
+    case ERR_CIRCULAR_CLASS_DEFINITION:
+        return "CIRCULAR_CLASS_DEFINITION";
+    case ERR_FAILS_VERIFICATION:
+        return "FAILS_VERIFICATION";
+    case ERR_ADD_METHOD_NOT_IMPLEMENTED:
+        return "ADD_METHOD_NOT_IMPLEMENTED";
+    case ERR_SCHEMA_CHANGE_NOT_IMPLEMENTED:
+        return "SCHEMA_CHANGE_NOT_IMPLEMENTED";
+    case ERR_INVALID_TYPESTATE:
+        return "INVALID_TYPESTATE";
+    case ERR_HIERARCHY_CHANGE_NOT_IMPLEMENTED:
+        return "HIERARCHY_CHANGE_NOT_IMPLEMENTED";
+    case ERR_DELETE_METHOD_NOT_IMPLEMENTED:
+        return "DELETE_METHOD_NOT_IMPLEMENTED";
+    case ERR_UNSUPPORTED_VERSION:
+        return "UNSUPPORTED_VERSION";
+    case ERR_NAMES_DONT_MATCH:
+        return "NAMES_DONT_MATCH";
+    case ERR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED:
+        return "CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED";
+    case ERR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED:
+        return "METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED";
+    case ERR_NOT_IMPLEMENTED:
+        return "NOT_IMPLEMENTED";
+    case ERR_NULL_POINTER:
+        return "NULL_POINTER";
+    case ERR_ABSENT_INFORMATION:
+        return "ABSENT_INFORMATION";
+    case ERR_INVALID_EVENT_TYPE:
+        return "INVALID_EVENT_TYPE";
+    case ERR_ILLEGAL_ARGUMENT:
+        return "ILLEGAL_ARGUMENT";
+    case ERR_OUT_OF_MEMORY:
+        return "OUT_OF_MEMORY";
+    case ERR_ACCESS_DENIED:
+        return "ACCESS_DENIED";
+    case ERR_VM_DEAD:
+        return "VM_DEAD";
+    case ERR_INTERNAL:
+        return "INTERNAL";
+    case ERR_UNATTACHED_THREAD:
+        return "UNATTACHED_THREAD";
+    case ERR_INVALID_TAG:
+        return "INVALID_TAG";
+    case ERR_ALREADY_INVOKING:
+        return "ALREADY_INVOKING";
+    case ERR_INVALID_INDEX:
+        return "INVALID_INDEX";
+    case ERR_INVALID_LENGTH:
+        return "INVALID_LENGTH";
+    case ERR_INVALID_STRING:
+        return "INVALID_STRING";
+    case ERR_INVALID_CLASS_LOADER:
+        return "INVALID_CLASS_LOADER";
+    case ERR_INVALID_ARRAY:
+        return "INVALID_ARRAY";
+    case ERR_TRANSPORT_LOAD:
+        return "TRANSPORT_LOAD";
+    case ERR_TRANSPORT_INIT:
+        return "TRANSPORT_INIT";
+    case ERR_NATIVE_METHOD:
+        return "NATIVE_METHOD";
+    case ERR_INVALID_COUNT:
+        return "INVALID_COUNT";
+    default:
+        return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the EventKind.
+ */
+const char* dvmJdwpEventKindStr(JdwpEventKind kind)
+{
+    switch (kind) {
+    case EK_SINGLE_STEP:        return "SINGLE_STEP";
+    case EK_BREAKPOINT:         return "BREAKPOINT";
+    case EK_FRAME_POP:          return "FRAME_POP";
+    case EK_EXCEPTION:          return "EXCEPTION";
+    case EK_USER_DEFINED:       return "USER_DEFINED";
+    case EK_THREAD_START:       return "THREAD_START";
+    /*case EK_THREAD_END:         return "THREAD_END";*/
+    case EK_CLASS_PREPARE:      return "CLASS_PREPARE";
+    case EK_CLASS_UNLOAD:       return "CLASS_UNLOAD";
+    case EK_CLASS_LOAD:         return "CLASS_LOAD";
+    case EK_FIELD_ACCESS:       return "FIELD_ACCESS";
+    case EK_FIELD_MODIFICATION: return "FIELD_MODIFICATION";
+    case EK_EXCEPTION_CATCH:    return "EXCEPTION_CATCH";
+    case EK_METHOD_ENTRY:       return "METHOD_ENTRY";
+    case EK_METHOD_EXIT:        return "METHOD_EXIT";
+    case EK_VM_INIT:            return "VM_INIT";
+    case EK_VM_DEATH:           return "VM_DEATH";
+    case EK_VM_DISCONNECTED:    return "VM_DISCONNECTED";
+    /*case EK_VM_START:           return "VM_START";*/
+    case EK_THREAD_DEATH:       return "THREAD_DEATH";
+    default:                    return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the ModKind.
+ */
+const char* dvmJdwpModKindStr(JdwpModKind kind)
+{
+    switch (kind) {
+    case MK_COUNT:              return "COUNT";
+    case MK_CONDITIONAL:        return "CONDITIONAL";
+    case MK_THREAD_ONLY:        return "THREAD_ONLY";
+    case MK_CLASS_ONLY:         return "CLASS_ONLY";
+    case MK_CLASS_MATCH:        return "CLASS_MATCH";
+    case MK_CLASS_EXCLUDE:      return "CLASS_EXCLUDE";
+    case MK_LOCATION_ONLY:      return "LOCATION_ONLY";
+    case MK_EXCEPTION_ONLY:     return "EXCEPTION_ONLY";
+    case MK_FIELD_ONLY:         return "FIELD_ONLY";
+    case MK_STEP:               return "STEP";
+    case MK_INSTANCE_ONLY:      return "INSTANCE_ONLY";
+    default:                    return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the StepDepth.
+ */
+const char* dvmJdwpStepDepthStr(JdwpStepDepth depth)
+{
+    switch (depth) {
+    case SD_INTO:               return "INTO";
+    case SD_OVER:               return "OVER";
+    case SD_OUT:                return "OUT";
+    default:                    return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the StepSize.
+ */
+const char* dvmJdwpStepSizeStr(JdwpStepSize size)
+{
+    switch (size) {
+    case SS_MIN:                return "MIN";
+    case SS_LINE:               return "LINE";
+    default:                    return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the SuspendPolicy.
+ */
+const char* dvmJdwpSuspendPolicyStr(JdwpSuspendPolicy policy)
+{
+    switch (policy) {
+    case SP_NONE:               return "NONE";
+    case SP_EVENT_THREAD:       return "EVENT_THREAD";
+    case SP_ALL:                return "ALL";
+    default:                    return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the SuspendStatus.
+ */
+const char* dvmJdwpSuspendStatusStr(JdwpSuspendStatus status)
+{
+    switch (status) {
+    case SUSPEND_STATUS_NOT_SUSPENDED: return "Not SUSPENDED";
+    case SUSPEND_STATUS_SUSPENDED:     return "SUSPENDED";
+    default:                           return "?UNKNOWN?";
+    }
+}
+
+/*
+ * Return a string for the ThreadStatus.
+ */
+const char* dvmJdwpThreadStatusStr(JdwpThreadStatus status)
+{
+    switch (status) {
+    case TS_ZOMBIE:             return "ZOMBIE";
+    case TS_RUNNING:            return "RUNNING";
+    case TS_SLEEPING:           return "SLEEPING";
+    case TS_MONITOR:            return "MONITOR";
+    case TS_WAIT:               return "WAIT";
+    default:                    return "?UNKNOWN?";
+    }
+};
diff --git a/vm/jdwp/JdwpConstants.h b/vm/jdwp/JdwpConstants.h
new file mode 100644
index 0000000..9913759
--- /dev/null
+++ b/vm/jdwp/JdwpConstants.h
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+/*
+ * These come out of the JDWP documentation.
+ */
+#ifndef DALVIK_JDWP_JDWPCONSTANTS_H_
+#define DALVIK_JDWP_JDWPCONSTANTS_H_
+
+/*
+ * Error constants.
+ */
+enum JdwpError {
+    ERR_NONE                                        = 0,
+    ERR_INVALID_THREAD                              = 10,
+    ERR_INVALID_THREAD_GROUP                        = 11,
+    ERR_INVALID_PRIORITY                            = 12,
+    ERR_THREAD_NOT_SUSPENDED                        = 13,
+    ERR_THREAD_SUSPENDED                            = 14,
+    ERR_INVALID_OBJECT                              = 20,
+    ERR_INVALID_CLASS                               = 21,
+    ERR_CLASS_NOT_PREPARED                          = 22,
+    ERR_INVALID_METHODID                            = 23,
+    ERR_INVALID_LOCATION                            = 24,
+    ERR_INVALID_FIELDID                             = 25,
+    ERR_INVALID_FRAMEID                             = 30,
+    ERR_NO_MORE_FRAMES                              = 31,
+    ERR_OPAQUE_FRAME                                = 32,
+    ERR_NOT_CURRENT_FRAME                           = 33,
+    ERR_TYPE_MISMATCH                               = 34,
+    ERR_INVALID_SLOT                                = 35,
+    ERR_DUPLICATE                                   = 40,
+    ERR_NOT_FOUND                                   = 41,
+    ERR_INVALID_MONITOR                             = 50,
+    ERR_NOT_MONITOR_OWNER                           = 51,
+    ERR_INTERRUPT                                   = 52,
+    ERR_INVALID_CLASS_FORMAT                        = 60,
+    ERR_CIRCULAR_CLASS_DEFINITION                   = 61,
+    ERR_FAILS_VERIFICATION                          = 62,
+    ERR_ADD_METHOD_NOT_IMPLEMENTED                  = 63,
+    ERR_SCHEMA_CHANGE_NOT_IMPLEMENTED               = 64,
+    ERR_INVALID_TYPESTATE                           = 65,
+    ERR_HIERARCHY_CHANGE_NOT_IMPLEMENTED            = 66,
+    ERR_DELETE_METHOD_NOT_IMPLEMENTED               = 67,
+    ERR_UNSUPPORTED_VERSION                         = 68,
+    ERR_NAMES_DONT_MATCH                            = 69,
+    ERR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED      = 70,
+    ERR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED     = 71,
+    ERR_NOT_IMPLEMENTED                             = 99,
+    ERR_NULL_POINTER                                = 100,
+    ERR_ABSENT_INFORMATION                          = 101,
+    ERR_INVALID_EVENT_TYPE                          = 102,
+    ERR_ILLEGAL_ARGUMENT                            = 103,
+    ERR_OUT_OF_MEMORY                               = 110,
+    ERR_ACCESS_DENIED                               = 111,
+    ERR_VM_DEAD                                     = 112,
+    ERR_INTERNAL                                    = 113,
+    ERR_UNATTACHED_THREAD                           = 115,
+    ERR_INVALID_TAG                                 = 500,
+    ERR_ALREADY_INVOKING                            = 502,
+    ERR_INVALID_INDEX                               = 503,
+    ERR_INVALID_LENGTH                              = 504,
+    ERR_INVALID_STRING                              = 506,
+    ERR_INVALID_CLASS_LOADER                        = 507,
+    ERR_INVALID_ARRAY                               = 508,
+    ERR_TRANSPORT_LOAD                              = 509,
+    ERR_TRANSPORT_INIT                              = 510,
+    ERR_NATIVE_METHOD                               = 511,
+    ERR_INVALID_COUNT                               = 512,
+};
+const char* dvmJdwpErrorStr(JdwpError error);
+
+
+/*
+ * ClassStatus constants.  These are bit flags that can be ORed together.
+ */
+enum JdwpClassStatus {
+    CS_VERIFIED             = 0x01,
+    CS_PREPARED             = 0x02,
+    CS_INITIALIZED          = 0x04,
+    CS_ERROR                = 0x08,
+};
+
+/*
+ * EventKind constants.
+ */
+enum JdwpEventKind {
+    EK_SINGLE_STEP          = 1,
+    EK_BREAKPOINT           = 2,
+    EK_FRAME_POP            = 3,
+    EK_EXCEPTION            = 4,
+    EK_USER_DEFINED         = 5,
+    EK_THREAD_START         = 6,
+    EK_THREAD_END           = 7,
+    EK_CLASS_PREPARE        = 8,
+    EK_CLASS_UNLOAD         = 9,
+    EK_CLASS_LOAD           = 10,
+    EK_FIELD_ACCESS         = 20,
+    EK_FIELD_MODIFICATION   = 21,
+    EK_EXCEPTION_CATCH      = 30,
+    EK_METHOD_ENTRY         = 40,
+    EK_METHOD_EXIT          = 41,
+    EK_VM_INIT              = 90,
+    EK_VM_DEATH             = 99,
+    EK_VM_DISCONNECTED      = 100,  /* "Never sent across JDWP */
+    EK_VM_START             = EK_VM_INIT,
+    EK_THREAD_DEATH         = EK_THREAD_END,
+};
+const char* dvmJdwpEventKindStr(JdwpEventKind kind);
+
+/*
+ * Values for "modKind" in EventRequest.Set.
+ */
+enum JdwpModKind {
+    MK_COUNT                = 1,
+    MK_CONDITIONAL          = 2,
+    MK_THREAD_ONLY          = 3,
+    MK_CLASS_ONLY           = 4,
+    MK_CLASS_MATCH          = 5,
+    MK_CLASS_EXCLUDE        = 6,
+    MK_LOCATION_ONLY        = 7,
+    MK_EXCEPTION_ONLY       = 8,
+    MK_FIELD_ONLY           = 9,
+    MK_STEP                 = 10,
+    MK_INSTANCE_ONLY        = 11,
+};
+const char* dvmJdwpModKindStr(JdwpModKind kind);
+
+/*
+ * InvokeOptions constants (bit flags).
+ */
+enum JdwpInvokeOptions {
+    INVOKE_SINGLE_THREADED  = 0x01,
+    INVOKE_NONVIRTUAL       = 0x02,
+};
+
+/*
+ * StepDepth constants.
+ */
+enum JdwpStepDepth {
+    SD_INTO                 = 0,    /* step into method calls */
+    SD_OVER                 = 1,    /* step over method calls */
+    SD_OUT                  = 2,    /* step out of current method */
+};
+const char* dvmJdwpStepDepthStr(JdwpStepDepth depth);
+
+/*
+ * StepSize constants.
+ */
+enum JdwpStepSize {
+    SS_MIN                  = 0,    /* step by minimum (e.g. 1 bytecode inst) */
+    SS_LINE                 = 1,    /* if possible, step to next line */
+};
+const char* dvmJdwpStepSizeStr(JdwpStepSize size);
+
+/*
+ * SuspendPolicy constants.
+ */
+enum JdwpSuspendPolicy {
+    SP_NONE                 = 0,    /* suspend no threads */
+    SP_EVENT_THREAD         = 1,    /* suspend event thread */
+    SP_ALL                  = 2,    /* suspend all threads */
+};
+const char* dvmJdwpSuspendPolicyStr(JdwpSuspendPolicy policy);
+
+/*
+ * SuspendStatus constants.
+ */
+enum JdwpSuspendStatus {
+    SUSPEND_STATUS_NOT_SUSPENDED = 0,
+    SUSPEND_STATUS_SUSPENDED     = 1,
+};
+const char* dvmJdwpSuspendStatusStr(JdwpSuspendStatus status);
+
+/*
+ * ThreadStatus constants.
+ */
+enum JdwpThreadStatus {
+    TS_ZOMBIE               = 0,
+    TS_RUNNING              = 1,        // RUNNING
+    TS_SLEEPING             = 2,        // (in Thread.sleep())
+    TS_MONITOR              = 3,        // WAITING (monitor wait)
+    TS_WAIT                 = 4,        // (in Object.wait())
+};
+const char* dvmJdwpThreadStatusStr(JdwpThreadStatus status);
+
+/*
+ * TypeTag constants.
+ */
+enum JdwpTypeTag {
+    TT_CLASS                = 1,
+    TT_INTERFACE            = 2,
+    TT_ARRAY                = 3,
+};
+
+/*
+ * Tag constants.
+ */
+enum JdwpType {
+    JT_ARRAY                 = '[',
+    JT_BYTE                  = 'B',
+    JT_CHAR                  = 'C',
+    JT_OBJECT                = 'L',
+    JT_FLOAT                 = 'F',
+    JT_DOUBLE                = 'D',
+    JT_INT                   = 'I',
+    JT_LONG                  = 'J',
+    JT_SHORT                 = 'S',
+    JT_VOID                  = 'V',
+    JT_BOOLEAN               = 'Z',
+    JT_STRING                = 's',
+    JT_THREAD                = 't',
+    JT_THREAD_GROUP          = 'g',
+    JT_CLASS_LOADER          = 'l',
+    JT_CLASS_OBJECT          = 'c',
+};
+
+#endif  // DALVIK_JDWP_JDWPCONSTANTS_H_
diff --git a/vm/jdwp/JdwpEvent.cpp b/vm/jdwp/JdwpEvent.cpp
new file mode 100644
index 0000000..f11777b
--- /dev/null
+++ b/vm/jdwp/JdwpEvent.cpp
@@ -0,0 +1,1279 @@
+/*
+ * 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.
+ */
+/*
+ * Send events to the debugger.
+ */
+#include "jdwp/JdwpPriv.h"
+#include "jdwp/JdwpConstants.h"
+#include "jdwp/JdwpHandler.h"
+#include "jdwp/JdwpEvent.h"
+#include "jdwp/ExpandBuf.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>     /* for offsetof() */
+#include <unistd.h>
+
+/*
+General notes:
+
+The event add/remove stuff usually happens from the debugger thread,
+in response to requests from the debugger, but can also happen as the
+result of an event in an arbitrary thread (e.g. an event with a "count"
+mod expires).  It's important to keep the event list locked when processing
+events.
+
+Event posting can happen from any thread.  The JDWP thread will not usually
+post anything but VM start/death, but if a JDWP request causes a class
+to be loaded, the ClassPrepare event will come from the JDWP thread.
+
+
+We can have serialization issues when we post an event to the debugger.
+For example, a thread could send an "I hit a breakpoint and am suspending
+myself" message to the debugger.  Before it manages to suspend itself, the
+debugger's response ("not interested, resume thread") arrives and is
+processed.  We try to resume a thread that hasn't yet suspended.
+
+This means that, after posting an event to the debugger, we need to wait
+for the event thread to suspend itself (and, potentially, all other threads)
+before processing any additional requests from the debugger.  While doing
+so we need to be aware that multiple threads may be hitting breakpoints
+or other events simultaneously, so we either need to wait for all of them
+or serialize the events with each other.
+
+The current mechanism works like this:
+  Event thread:
+   - If I'm going to suspend, grab the "I am posting an event" token.  Wait
+     for it if it's not currently available.
+   - Post the event to the debugger.
+   - If appropriate, suspend others and then myself.  As part of suspending
+     myself, release the "I am posting" token.
+  JDWP thread:
+   - When an event arrives, see if somebody is posting an event.  If so,
+     sleep until we can acquire the "I am posting an event" token.  Release
+     it immediately and continue processing -- the event we have already
+     received should not interfere with other events that haven't yet
+     been posted.
+
+Some care must be taken to avoid deadlock:
+
+ - thread A and thread B exit near-simultaneously, and post thread-death
+   events with a "suspend all" clause
+ - thread A gets the event token, thread B sits and waits for it
+ - thread A wants to suspend all other threads, but thread B is waiting
+   for the token and can't be suspended
+
+So we need to mark thread B in such a way that thread A doesn't wait for it.
+
+If we just bracket the "grab event token" call with a change to VMWAIT
+before sleeping, the switch back to RUNNING state when we get the token
+will cause thread B to suspend (remember, thread A's global suspend is
+still in force, even after it releases the token).  Suspending while
+holding the event token is very bad, because it prevents the JDWP thread
+from processing incoming messages.
+
+We need to change to VMWAIT state at the *start* of posting an event,
+and stay there until we either finish posting the event or decide to
+put ourselves to sleep.  That way we don't interfere with anyone else and
+don't allow anyone else to interfere with us.
+*/
+
+
+#define kJdwpEventCommandSet    64
+#define kJdwpCompositeCommand   100
+
+/*
+ * Stuff to compare against when deciding if a mod matches.  Only the
+ * values for mods valid for the event being evaluated will be filled in.
+ * The rest will be zeroed.
+ */
+struct ModBasket {
+    const JdwpLocation* pLoc;           /* LocationOnly */
+    const char*         className;      /* ClassMatch/ClassExclude */
+    ObjectId            threadId;       /* ThreadOnly */
+    RefTypeId           classId;        /* ClassOnly */
+    RefTypeId           excepClassId;   /* ExceptionOnly */
+    bool                caught;         /* ExceptionOnly */
+    FieldId             field;          /* FieldOnly */
+    ObjectId            thisPtr;        /* InstanceOnly */
+    /* nothing for StepOnly -- handled differently */
+};
+
+/*
+ * Get the next "request" serial number.  We use this when sending
+ * packets to the debugger.
+ */
+u4 dvmJdwpNextRequestSerial(JdwpState* state)
+{
+    dvmDbgLockMutex(&state->serialLock);
+    u4 result = state->requestSerial++;
+    dvmDbgUnlockMutex(&state->serialLock);
+
+    return result;
+}
+
+/*
+ * Get the next "event" serial number.  We use this in the response to
+ * message type EventRequest.Set.
+ */
+u4 dvmJdwpNextEventSerial(JdwpState* state)
+{
+    dvmDbgLockMutex(&state->serialLock);
+    u4 result = state->eventSerial++;
+    dvmDbgUnlockMutex(&state->serialLock);
+
+    return result;
+}
+
+/*
+ * Lock the "event" mutex, which guards the list of registered events.
+ */
+static void lockEventMutex(JdwpState* state)
+{
+    //dvmDbgThreadWaiting();
+    dvmDbgLockMutex(&state->eventLock);
+    //dvmDbgThreadRunning();
+}
+
+/*
+ * Unlock the "event" mutex.
+ */
+static void unlockEventMutex(JdwpState* state)
+{
+    dvmDbgUnlockMutex(&state->eventLock);
+}
+
+/*
+ * Dump an event to the log file.
+ */
+static void dumpEvent(const JdwpEvent* pEvent)
+{
+    LOGI("Event id=0x%4x %p (prev=%p next=%p):",
+        pEvent->requestId, pEvent, pEvent->prev, pEvent->next);
+    LOGI("  kind=%s susp=%s modCount=%d",
+        dvmJdwpEventKindStr(pEvent->eventKind),
+        dvmJdwpSuspendPolicyStr(pEvent->suspendPolicy),
+        pEvent->modCount);
+
+    for (int i = 0; i < pEvent->modCount; i++) {
+        const JdwpEventMod* pMod = &pEvent->mods[i];
+        JdwpModKind kind = static_cast<JdwpModKind>(pMod->modKind);
+        LOGI("  %s", dvmJdwpModKindStr(kind));
+        /* TODO - show details */
+    }
+}
+
+/*
+ * Add an event to the list.  Ordering is not important.
+ *
+ * If something prevents the event from being registered, e.g. it's a
+ * single-step request on a thread that doesn't exist, the event will
+ * not be added to the list, and an appropriate error will be returned.
+ */
+JdwpError dvmJdwpRegisterEvent(JdwpState* state, JdwpEvent* pEvent)
+{
+    lockEventMutex(state);
+
+    assert(state != NULL);
+    assert(pEvent != NULL);
+    assert(pEvent->prev == NULL);
+    assert(pEvent->next == NULL);
+
+    /*
+     * If one or more "break"-type mods are used, register them with
+     * the interpreter.
+     */
+    for (int i = 0; i < pEvent->modCount; i++) {
+        const JdwpEventMod* pMod = &pEvent->mods[i];
+        if (pMod->modKind == MK_LOCATION_ONLY) {
+            /* should only be for Breakpoint, Step, and Exception */
+            dvmDbgWatchLocation(&pMod->locationOnly.loc);
+        } else if (pMod->modKind == MK_STEP) {
+            /* should only be for EK_SINGLE_STEP; should only be one */
+            JdwpStepSize size = static_cast<JdwpStepSize>(pMod->step.size);
+            JdwpStepDepth depth = static_cast<JdwpStepDepth>(pMod->step.depth);
+            dvmDbgConfigureStep(pMod->step.threadId, size, depth);
+        } else if (pMod->modKind == MK_FIELD_ONLY) {
+            /* should be for EK_FIELD_ACCESS or EK_FIELD_MODIFICATION */
+            dumpEvent(pEvent);  /* TODO - need for field watches */
+        }
+    }
+
+    /*
+     * Add to list.
+     */
+    if (state->eventList != NULL) {
+        pEvent->next = state->eventList;
+        state->eventList->prev = pEvent;
+    }
+    state->eventList = pEvent;
+    state->numEvents++;
+
+    unlockEventMutex(state);
+
+    return ERR_NONE;
+}
+
+/*
+ * Remove an event from the list.  This will also remove the event from
+ * any optimization tables, e.g. breakpoints.
+ *
+ * Does not free the JdwpEvent.
+ *
+ * Grab the eventLock before calling here.
+ */
+static void unregisterEvent(JdwpState* state, JdwpEvent* pEvent)
+{
+    if (pEvent->prev == NULL) {
+        /* head of the list */
+        assert(state->eventList == pEvent);
+
+        state->eventList = pEvent->next;
+    } else {
+        pEvent->prev->next = pEvent->next;
+    }
+
+    if (pEvent->next != NULL) {
+        pEvent->next->prev = pEvent->prev;
+        pEvent->next = NULL;
+    }
+    pEvent->prev = NULL;
+
+    /*
+     * Unhook us from the interpreter, if necessary.
+     */
+    for (int i = 0; i < pEvent->modCount; i++) {
+        JdwpEventMod* pMod = &pEvent->mods[i];
+        if (pMod->modKind == MK_LOCATION_ONLY) {
+            /* should only be for Breakpoint, Step, and Exception */
+            dvmDbgUnwatchLocation(&pMod->locationOnly.loc);
+        }
+        if (pMod->modKind == MK_STEP) {
+            /* should only be for EK_SINGLE_STEP; should only be one */
+            dvmDbgUnconfigureStep(pMod->step.threadId);
+        }
+    }
+
+    state->numEvents--;
+    assert(state->numEvents != 0 || state->eventList == NULL);
+}
+
+/*
+ * Remove the event with the given ID from the list.
+ *
+ * Failure to find the event isn't really an error, but it is a little
+ * weird.  (It looks like Eclipse will try to be extra careful and will
+ * explicitly remove one-off single-step events.)
+ */
+void dvmJdwpUnregisterEventById(JdwpState* state, u4 requestId)
+{
+    lockEventMutex(state);
+
+    JdwpEvent* pEvent = state->eventList;
+    while (pEvent != NULL) {
+        if (pEvent->requestId == requestId) {
+            unregisterEvent(state, pEvent);
+            dvmJdwpEventFree(pEvent);
+            goto done;      /* there can be only one with a given ID */
+        }
+
+        pEvent = pEvent->next;
+    }
+
+    //LOGD("Odd: no match when removing event reqId=0x%04x", requestId);
+
+done:
+    unlockEventMutex(state);
+}
+
+/*
+ * Remove all entries from the event list.
+ */
+void dvmJdwpUnregisterAll(JdwpState* state)
+{
+    lockEventMutex(state);
+
+    JdwpEvent* pEvent = state->eventList;
+    while (pEvent != NULL) {
+        JdwpEvent* pNextEvent = pEvent->next;
+
+        unregisterEvent(state, pEvent);
+        dvmJdwpEventFree(pEvent);
+        pEvent = pNextEvent;
+    }
+
+    state->eventList = NULL;
+
+    unlockEventMutex(state);
+}
+
+
+
+/*
+ * Allocate a JdwpEvent struct with enough space to hold the specified
+ * number of mod records.
+ */
+JdwpEvent* dvmJdwpEventAlloc(int numMods)
+{
+    JdwpEvent* newEvent;
+    int allocSize = offsetof(JdwpEvent, mods) +
+                    numMods * sizeof(newEvent->mods[0]);
+
+    newEvent = (JdwpEvent*)malloc(allocSize);
+    memset(newEvent, 0, allocSize);
+    return newEvent;
+}
+
+/*
+ * Free a JdwpEvent.
+ *
+ * Do not call this until the event has been removed from the list.
+ */
+void dvmJdwpEventFree(JdwpEvent* pEvent)
+{
+    if (pEvent == NULL)
+        return;
+
+    /* make sure it was removed from the list */
+    assert(pEvent->prev == NULL);
+    assert(pEvent->next == NULL);
+    /* want to assert state->eventList != pEvent */
+
+    /*
+     * Free any hairy bits in the mods.
+     */
+    for (int i = 0; i < pEvent->modCount; i++) {
+        if (pEvent->mods[i].modKind == MK_CLASS_MATCH) {
+            free(pEvent->mods[i].classMatch.classPattern);
+            pEvent->mods[i].classMatch.classPattern = NULL;
+        }
+        if (pEvent->mods[i].modKind == MK_CLASS_EXCLUDE) {
+            free(pEvent->mods[i].classExclude.classPattern);
+            pEvent->mods[i].classExclude.classPattern = NULL;
+        }
+    }
+
+    free(pEvent);
+}
+
+/*
+ * Allocate storage for matching events.  To keep things simple we
+ * use an array with enough storage for the entire list.
+ *
+ * The state->eventLock should be held before calling.
+ */
+static JdwpEvent** allocMatchList(JdwpState* state)
+{
+    return (JdwpEvent**) malloc(sizeof(JdwpEvent*) * state->numEvents);
+}
+
+/*
+ * Run through the list and remove any entries with an expired "count" mod
+ * from the event list, then free the match list.
+ */
+static void cleanupMatchList(JdwpState* state, JdwpEvent** matchList,
+    int matchCount)
+{
+    JdwpEvent** ppEvent = matchList;
+
+    while (matchCount--) {
+        JdwpEvent* pEvent = *ppEvent;
+
+        for (int i = 0; i < pEvent->modCount; i++) {
+            if (pEvent->mods[i].modKind == MK_COUNT &&
+                pEvent->mods[i].count.count == 0)
+            {
+                LOGV("##### Removing expired event");
+                unregisterEvent(state, pEvent);
+                dvmJdwpEventFree(pEvent);
+                break;
+            }
+        }
+
+        ppEvent++;
+    }
+
+    free(matchList);
+}
+
+/*
+ * Match a string against a "restricted regular expression", which is just
+ * a string that may start or end with '*' (e.g. "*.Foo" or "java.*").
+ *
+ * ("Restricted name globbing" might have been a better term.)
+ */
+static bool patternMatch(const char* pattern, const char* target)
+{
+    int patLen = strlen(pattern);
+
+    if (pattern[0] == '*') {
+        int targetLen = strlen(target);
+        patLen--;
+        // TODO: remove printf when we find a test case to verify this
+        LOGE(">>> comparing '%s' to '%s'",
+            pattern+1, target + (targetLen-patLen));
+
+        if (targetLen < patLen)
+            return false;
+        return strcmp(pattern+1, target + (targetLen-patLen)) == 0;
+    } else if (pattern[patLen-1] == '*') {
+        return strncmp(pattern, target, patLen-1) == 0;
+    } else {
+        return strcmp(pattern, target) == 0;
+    }
+}
+
+/*
+ * See if two locations are equal.
+ *
+ * It's tempting to do a bitwise compare ("struct ==" or memcmp), but if
+ * the storage wasn't zeroed out there could be undefined values in the
+ * padding.  Besides, the odds of "idx" being equal while the others aren't
+ * is very small, so this is usually just a simple integer comparison.
+ */
+static inline bool locationMatch(const JdwpLocation* pLoc1,
+    const JdwpLocation* pLoc2)
+{
+    return pLoc1->idx == pLoc2->idx &&
+           pLoc1->methodId == pLoc2->methodId &&
+           pLoc1->classId == pLoc2->classId &&
+           pLoc1->typeTag == pLoc2->typeTag;
+}
+
+/*
+ * See if the event's mods match up with the contents of "basket".
+ *
+ * If we find a Count mod before rejecting an event, we decrement it.  We
+ * need to do this even if later mods cause us to ignore the event.
+ */
+static bool modsMatch(JdwpState* state, JdwpEvent* pEvent, ModBasket* basket)
+{
+    JdwpEventMod* pMod = pEvent->mods;
+
+    for (int i = pEvent->modCount; i > 0; i--, pMod++) {
+        switch (pMod->modKind) {
+        case MK_COUNT:
+            assert(pMod->count.count > 0);
+            pMod->count.count--;
+            break;
+        case MK_CONDITIONAL:
+            assert(false);  // should not be getting these
+            break;
+        case MK_THREAD_ONLY:
+            if (pMod->threadOnly.threadId != basket->threadId)
+                return false;
+            break;
+        case MK_CLASS_ONLY:
+            if (!dvmDbgMatchType(basket->classId, pMod->classOnly.refTypeId))
+                return false;
+            break;
+        case MK_CLASS_MATCH:
+            if (!patternMatch(pMod->classMatch.classPattern,
+                    basket->className))
+                return false;
+            break;
+        case MK_CLASS_EXCLUDE:
+            if (patternMatch(pMod->classMatch.classPattern,
+                    basket->className))
+                return false;
+            break;
+        case MK_LOCATION_ONLY:
+            if (!locationMatch(&pMod->locationOnly.loc, basket->pLoc))
+                return false;
+            break;
+        case MK_EXCEPTION_ONLY:
+            if (pMod->exceptionOnly.refTypeId != 0 &&
+                !dvmDbgMatchType(basket->excepClassId,
+                                 pMod->exceptionOnly.refTypeId))
+                return false;
+            if ((basket->caught && !pMod->exceptionOnly.caught) ||
+                (!basket->caught && !pMod->exceptionOnly.uncaught))
+                return false;
+            break;
+        case MK_FIELD_ONLY:
+            if (!dvmDbgMatchType(basket->classId, pMod->fieldOnly.refTypeId) ||
+                    pMod->fieldOnly.fieldId != basket->field)
+                return false;
+            break;
+        case MK_STEP:
+            if (pMod->step.threadId != basket->threadId)
+                return false;
+            break;
+        case MK_INSTANCE_ONLY:
+            if (pMod->instanceOnly.objectId != basket->thisPtr)
+                return false;
+            break;
+        default:
+            LOGE("unhandled mod kind %d", pMod->modKind);
+            assert(false);
+            break;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Find all events of type "eventKind" with mods that match up with the
+ * rest of the arguments.
+ *
+ * Found events are appended to "matchList", and "*pMatchCount" is advanced,
+ * so this may be called multiple times for grouped events.
+ *
+ * DO NOT call this multiple times for the same eventKind, as Count mods are
+ * decremented during the scan.
+ */
+static void findMatchingEvents(JdwpState* state, JdwpEventKind eventKind,
+    ModBasket* basket, JdwpEvent** matchList, int* pMatchCount)
+{
+    /* start after the existing entries */
+    matchList += *pMatchCount;
+
+    JdwpEvent* pEvent = state->eventList;
+    while (pEvent != NULL) {
+        if (pEvent->eventKind == eventKind && modsMatch(state, pEvent, basket))
+        {
+            *matchList++ = pEvent;
+            (*pMatchCount)++;
+        }
+
+        pEvent = pEvent->next;
+    }
+}
+
+/*
+ * Scan through the list of matches and determine the most severe
+ * suspension policy.
+ */
+static JdwpSuspendPolicy scanSuspendPolicy(JdwpEvent** matchList,
+    int matchCount)
+{
+    JdwpSuspendPolicy policy = SP_NONE;
+
+    while (matchCount--) {
+        if ((*matchList)->suspendPolicy > policy)
+            policy = (*matchList)->suspendPolicy;
+        matchList++;
+    }
+
+    return policy;
+}
+
+/*
+ * Three possibilities:
+ *  SP_NONE - do nothing
+ *  SP_EVENT_THREAD - suspend ourselves
+ *  SP_ALL - suspend everybody except JDWP support thread
+ */
+static void suspendByPolicy(JdwpState* state, JdwpSuspendPolicy suspendPolicy)
+{
+    if (suspendPolicy == SP_NONE)
+        return;
+
+    if (suspendPolicy == SP_ALL) {
+        dvmDbgSuspendVM(true);
+    } else {
+        assert(suspendPolicy == SP_EVENT_THREAD);
+    }
+
+    /* this is rare but possible -- see CLASS_PREPARE handling */
+    if (dvmDbgGetThreadSelfId() == state->debugThreadId) {
+        LOGI("NOTE: suspendByPolicy not suspending JDWP thread");
+        return;
+    }
+
+    DebugInvokeReq* pReq = dvmDbgGetInvokeReq();
+    while (true) {
+        pReq->ready = true;
+        dvmDbgSuspendSelf();
+        pReq->ready = false;
+
+        /*
+         * The JDWP thread has told us (and possibly all other threads) to
+         * resume.  See if it has left anything in our DebugInvokeReq mailbox.
+         */
+        if (!pReq->invokeNeeded) {
+            /*LOGD("suspendByPolicy: no invoke needed");*/
+            break;
+        }
+
+        /* grab this before posting/suspending again */
+        dvmJdwpSetWaitForEventThread(state, dvmDbgGetThreadSelfId());
+
+        /* leave pReq->invokeNeeded raised so we can check reentrancy */
+        LOGV("invoking method...");
+        dvmDbgExecuteMethod(pReq);
+
+        pReq->err = ERR_NONE;
+
+        /* clear this before signaling */
+        pReq->invokeNeeded = false;
+
+        LOGV("invoke complete, signaling and self-suspending");
+        dvmDbgLockMutex(&pReq->lock);
+        dvmDbgCondSignal(&pReq->cv);
+        dvmDbgUnlockMutex(&pReq->lock);
+    }
+}
+
+/*
+ * Determine if there is a method invocation in progress in the current
+ * thread.
+ *
+ * We look at the "invokeNeeded" flag in the per-thread DebugInvokeReq
+ * state.  If set, we're in the process of invoking a method.
+ */
+static bool invokeInProgress(JdwpState* state)
+{
+    DebugInvokeReq* pReq = dvmDbgGetInvokeReq();
+    return pReq->invokeNeeded;
+}
+
+/*
+ * We need the JDWP thread to hold off on doing stuff while we post an
+ * event and then suspend ourselves.
+ *
+ * Call this with a threadId of zero if you just want to wait for the
+ * current thread operation to complete.
+ *
+ * This could go to sleep waiting for another thread, so it's important
+ * that the thread be marked as VMWAIT before calling here.
+ */
+void dvmJdwpSetWaitForEventThread(JdwpState* state, ObjectId threadId)
+{
+    bool waited = false;
+
+    /* this is held for very brief periods; contention is unlikely */
+    dvmDbgLockMutex(&state->eventThreadLock);
+
+    /*
+     * If another thread is already doing stuff, wait for it.  This can
+     * go to sleep indefinitely.
+     */
+    while (state->eventThreadId != 0) {
+        LOGV("event in progress (0x%llx), 0x%llx sleeping",
+            state->eventThreadId, threadId);
+        waited = true;
+        dvmDbgCondWait(&state->eventThreadCond, &state->eventThreadLock);
+    }
+
+    if (waited || threadId != 0)
+        LOGV("event token grabbed (0x%llx)", threadId);
+    if (threadId != 0)
+        state->eventThreadId = threadId;
+
+    dvmDbgUnlockMutex(&state->eventThreadLock);
+}
+
+/*
+ * Clear the threadId and signal anybody waiting.
+ */
+void dvmJdwpClearWaitForEventThread(JdwpState* state)
+{
+    /*
+     * Grab the mutex.  Don't try to go in/out of VMWAIT mode, as this
+     * function is called by dvmSuspendSelf(), and the transition back
+     * to RUNNING would confuse it.
+     */
+    dvmDbgLockMutex(&state->eventThreadLock);
+
+    assert(state->eventThreadId != 0);
+    LOGV("cleared event token (0x%llx)", state->eventThreadId);
+
+    state->eventThreadId = 0;
+
+    dvmDbgCondSignal(&state->eventThreadCond);
+
+    dvmDbgUnlockMutex(&state->eventThreadLock);
+}
+
+
+/*
+ * Prep an event.  Allocates storage for the message and leaves space for
+ * the header.
+ */
+static ExpandBuf* eventPrep()
+{
+    ExpandBuf* pReq = expandBufAlloc();
+    expandBufAddSpace(pReq, kJDWPHeaderLen);
+
+    return pReq;
+}
+
+/*
+ * Write the header into the buffer and send the packet off to the debugger.
+ *
+ * Takes ownership of "pReq" (currently discards it).
+ */
+static void eventFinish(JdwpState* state, ExpandBuf* pReq)
+{
+    u1* buf = expandBufGetBuffer(pReq);
+
+    set4BE(buf, expandBufGetLength(pReq));
+    set4BE(buf+4, dvmJdwpNextRequestSerial(state));
+    set1(buf+8, 0);     /* flags */
+    set1(buf+9, kJdwpEventCommandSet);
+    set1(buf+10, kJdwpCompositeCommand);
+
+    dvmJdwpSendRequest(state, pReq);
+
+    expandBufFree(pReq);
+}
+
+
+/*
+ * Tell the debugger that we have finished initializing.  This is always
+ * sent, even if the debugger hasn't requested it.
+ *
+ * This should be sent "before the main thread is started and before
+ * any application code has been executed".  The thread ID in the message
+ * must be for the main thread.
+ */
+bool dvmJdwpPostVMStart(JdwpState* state, bool suspend)
+{
+    JdwpSuspendPolicy suspendPolicy;
+    ObjectId threadId = dvmDbgGetThreadSelfId();
+
+    if (suspend)
+        suspendPolicy = SP_ALL;
+    else
+        suspendPolicy = SP_NONE;
+
+    /* probably don't need this here */
+    lockEventMutex(state);
+
+    ExpandBuf* pReq = NULL;
+    if (true) {
+        LOGV("EVENT: %s", dvmJdwpEventKindStr(EK_VM_START));
+        LOGV("  suspendPolicy=%s", dvmJdwpSuspendPolicyStr(suspendPolicy));
+
+        pReq = eventPrep();
+        expandBufAdd1(pReq, suspendPolicy);
+        expandBufAdd4BE(pReq, 1);
+
+        expandBufAdd1(pReq, EK_VM_START);
+        expandBufAdd4BE(pReq, 0);       /* requestId */
+        expandBufAdd8BE(pReq, threadId);
+    }
+
+    unlockEventMutex(state);
+
+    /* send request and possibly suspend ourselves */
+    if (pReq != NULL) {
+        int oldStatus = dvmDbgThreadWaiting();
+        if (suspendPolicy != SP_NONE)
+            dvmJdwpSetWaitForEventThread(state, threadId);
+
+        eventFinish(state, pReq);
+
+        suspendByPolicy(state, suspendPolicy);
+        dvmDbgThreadContinuing(oldStatus);
+    }
+
+    return true;
+}
+
+/*
+ * A location of interest has been reached.  This handles:
+ *   Breakpoint
+ *   SingleStep
+ *   MethodEntry
+ *   MethodExit
+ * These four types must be grouped together in a single response.  The
+ * "eventFlags" indicates the type of event(s) that have happened.
+ *
+ * Valid mods:
+ *   Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude, InstanceOnly
+ *   LocationOnly (for breakpoint/step only)
+ *   Step (for step only)
+ *
+ * Interesting test cases:
+ *  - Put a breakpoint on a native method.  Eclipse creates METHOD_ENTRY
+ *    and METHOD_EXIT events with a ClassOnly mod on the method's class.
+ *  - Use "run to line".  Eclipse creates a BREAKPOINT with Count=1.
+ *  - Single-step to a line with a breakpoint.  Should get a single
+ *    event message with both events in it.
+ */
+bool dvmJdwpPostLocationEvent(JdwpState* state, const JdwpLocation* pLoc,
+    ObjectId thisPtr, int eventFlags)
+{
+    JdwpSuspendPolicy suspendPolicy = SP_NONE;
+    ModBasket basket;
+    char* nameAlloc = NULL;
+
+    memset(&basket, 0, sizeof(basket));
+    basket.pLoc = pLoc;
+    basket.classId = pLoc->classId;
+    basket.thisPtr = thisPtr;
+    basket.threadId = dvmDbgGetThreadSelfId();
+    basket.className = nameAlloc =
+        dvmDescriptorToName(dvmDbgGetClassDescriptor(pLoc->classId));
+
+    /*
+     * On rare occasions we may need to execute interpreted code in the VM
+     * while handling a request from the debugger.  Don't fire breakpoints
+     * while doing so.  (I don't think we currently do this at all, so
+     * this is mostly paranoia.)
+     */
+    if (basket.threadId == state->debugThreadId) {
+        LOGV("Ignoring location event in JDWP thread");
+        free(nameAlloc);
+        return false;
+    }
+
+    /*
+     * The debugger variable display tab may invoke the interpreter to format
+     * complex objects.  We want to ignore breakpoints and method entry/exit
+     * traps while working on behalf of the debugger.
+     *
+     * If we don't ignore them, the VM will get hung up, because we'll
+     * suspend on a breakpoint while the debugger is still waiting for its
+     * method invocation to complete.
+     */
+    if (invokeInProgress(state)) {
+        LOGV("Not checking breakpoints during invoke (%s)", basket.className);
+        free(nameAlloc);
+        return false;
+    }
+
+    /* don't allow the list to be updated while we scan it */
+    lockEventMutex(state);
+
+    JdwpEvent** matchList = allocMatchList(state);
+    int matchCount = 0;
+
+    if ((eventFlags & DBG_BREAKPOINT) != 0)
+        findMatchingEvents(state, EK_BREAKPOINT, &basket, matchList,
+            &matchCount);
+    if ((eventFlags & DBG_SINGLE_STEP) != 0)
+        findMatchingEvents(state, EK_SINGLE_STEP, &basket, matchList,
+            &matchCount);
+    if ((eventFlags & DBG_METHOD_ENTRY) != 0)
+        findMatchingEvents(state, EK_METHOD_ENTRY, &basket, matchList,
+            &matchCount);
+    if ((eventFlags & DBG_METHOD_EXIT) != 0)
+        findMatchingEvents(state, EK_METHOD_EXIT, &basket, matchList,
+            &matchCount);
+
+    ExpandBuf* pReq = NULL;
+    if (matchCount != 0) {
+        LOGV("EVENT: %s(%d total) %s.%s thread=%llx code=%llx)",
+            dvmJdwpEventKindStr(matchList[0]->eventKind), matchCount,
+            basket.className,
+            dvmDbgGetMethodName(pLoc->classId, pLoc->methodId),
+            basket.threadId, pLoc->idx);
+
+        suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+        LOGV("  suspendPolicy=%s",
+            dvmJdwpSuspendPolicyStr(suspendPolicy));
+
+        pReq = eventPrep();
+        expandBufAdd1(pReq, suspendPolicy);
+        expandBufAdd4BE(pReq, matchCount);
+
+        for (int i = 0; i < matchCount; i++) {
+            expandBufAdd1(pReq, matchList[i]->eventKind);
+            expandBufAdd4BE(pReq, matchList[i]->requestId);
+            expandBufAdd8BE(pReq, basket.threadId);
+            dvmJdwpAddLocation(pReq, pLoc);
+        }
+    }
+
+    cleanupMatchList(state, matchList, matchCount);
+    unlockEventMutex(state);
+
+    /* send request and possibly suspend ourselves */
+    if (pReq != NULL) {
+        int oldStatus = dvmDbgThreadWaiting();
+        if (suspendPolicy != SP_NONE)
+            dvmJdwpSetWaitForEventThread(state, basket.threadId);
+
+        eventFinish(state, pReq);
+
+        suspendByPolicy(state, suspendPolicy);
+        dvmDbgThreadContinuing(oldStatus);
+    }
+
+    free(nameAlloc);
+    return matchCount != 0;
+}
+
+/*
+ * A thread is starting or stopping.
+ *
+ * Valid mods:
+ *  Count, ThreadOnly
+ */
+bool dvmJdwpPostThreadChange(JdwpState* state, ObjectId threadId, bool start)
+{
+    JdwpSuspendPolicy suspendPolicy = SP_NONE;
+
+    assert(threadId = dvmDbgGetThreadSelfId());
+
+    /*
+     * I don't think this can happen.
+     */
+    if (invokeInProgress(state)) {
+        LOGW("Not posting thread change during invoke");
+        return false;
+    }
+
+    ModBasket basket;
+    memset(&basket, 0, sizeof(basket));
+    basket.threadId = threadId;
+
+    /* don't allow the list to be updated while we scan it */
+    lockEventMutex(state);
+
+    JdwpEvent** matchList = allocMatchList(state);
+    int matchCount = 0;
+
+    if (start)
+        findMatchingEvents(state, EK_THREAD_START, &basket, matchList,
+            &matchCount);
+    else
+        findMatchingEvents(state, EK_THREAD_DEATH, &basket, matchList,
+            &matchCount);
+
+    ExpandBuf* pReq = NULL;
+    if (matchCount != 0) {
+        LOGV("EVENT: %s(%d total) thread=%llx)",
+            dvmJdwpEventKindStr(matchList[0]->eventKind), matchCount,
+            basket.threadId);
+
+        suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+        LOGV("  suspendPolicy=%s",
+            dvmJdwpSuspendPolicyStr(suspendPolicy));
+
+        pReq = eventPrep();
+        expandBufAdd1(pReq, suspendPolicy);
+        expandBufAdd4BE(pReq, matchCount);
+
+        for (int i = 0; i < matchCount; i++) {
+            expandBufAdd1(pReq, matchList[i]->eventKind);
+            expandBufAdd4BE(pReq, matchList[i]->requestId);
+            expandBufAdd8BE(pReq, basket.threadId);
+        }
+
+    }
+
+    cleanupMatchList(state, matchList, matchCount);
+    unlockEventMutex(state);
+
+    /* send request and possibly suspend ourselves */
+    if (pReq != NULL) {
+        int oldStatus = dvmDbgThreadWaiting();
+        if (suspendPolicy != SP_NONE)
+            dvmJdwpSetWaitForEventThread(state, basket.threadId);
+
+        eventFinish(state, pReq);
+
+        suspendByPolicy(state, suspendPolicy);
+        dvmDbgThreadContinuing(oldStatus);
+    }
+
+    return matchCount != 0;
+}
+
+/*
+ * Send a polite "VM is dying" message to the debugger.
+ *
+ * Skips the usual "event token" stuff.
+ */
+bool dvmJdwpPostVMDeath(JdwpState* state)
+{
+    LOGV("EVENT: %s", dvmJdwpEventKindStr(EK_VM_DEATH));
+
+    ExpandBuf* pReq = eventPrep();
+    expandBufAdd1(pReq, SP_NONE);
+    expandBufAdd4BE(pReq, 1);
+
+    expandBufAdd1(pReq, EK_VM_DEATH);
+    expandBufAdd4BE(pReq, 0);
+    eventFinish(state, pReq);
+    return true;
+}
+
+
+/*
+ * An exception has been thrown.  It may or may not have been caught.
+ *
+ * Valid mods:
+ *  Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude, LocationOnly,
+ *    ExceptionOnly, InstanceOnly
+ *
+ * The "exceptionId" has not been added to the GC-visible object registry,
+ * because there's a pretty good chance that we're not going to send it
+ * up the debugger.
+ */
+bool dvmJdwpPostException(JdwpState* state, const JdwpLocation* pThrowLoc,
+    ObjectId exceptionId, RefTypeId exceptionClassId,
+    const JdwpLocation* pCatchLoc, ObjectId thisPtr)
+{
+    JdwpSuspendPolicy suspendPolicy = SP_NONE;
+    ModBasket basket;
+    char* nameAlloc = NULL;
+
+    memset(&basket, 0, sizeof(basket));
+    basket.pLoc = pThrowLoc;
+    basket.classId = pThrowLoc->classId;
+    basket.threadId = dvmDbgGetThreadSelfId();
+    basket.className = nameAlloc =
+        dvmDescriptorToName(dvmDbgGetClassDescriptor(basket.classId));
+    basket.excepClassId = exceptionClassId;
+    basket.caught = (pCatchLoc->classId != 0);
+    basket.thisPtr = thisPtr;
+
+    /* don't try to post an exception caused by the debugger */
+    if (invokeInProgress(state)) {
+        LOGV("Not posting exception hit during invoke (%s)",basket.className);
+        free(nameAlloc);
+        return false;
+    }
+
+    /* don't allow the list to be updated while we scan it */
+    lockEventMutex(state);
+
+    JdwpEvent** matchList = allocMatchList(state);
+    int matchCount = 0;
+
+    findMatchingEvents(state, EK_EXCEPTION, &basket, matchList, &matchCount);
+
+    ExpandBuf* pReq = NULL;
+    if (matchCount != 0) {
+        LOGV("EVENT: %s(%d total) thread=%llx exceptId=%llx caught=%d)",
+            dvmJdwpEventKindStr(matchList[0]->eventKind), matchCount,
+            basket.threadId, exceptionId, basket.caught);
+        LOGV("  throw: %d %llx %x %lld (%s.%s)", pThrowLoc->typeTag,
+            pThrowLoc->classId, pThrowLoc->methodId, pThrowLoc->idx,
+            dvmDbgGetClassDescriptor(pThrowLoc->classId),
+            dvmDbgGetMethodName(pThrowLoc->classId, pThrowLoc->methodId));
+        if (pCatchLoc->classId == 0) {
+            LOGV("  catch: (not caught)");
+        } else {
+            LOGV("  catch: %d %llx %x %lld (%s.%s)", pCatchLoc->typeTag,
+                pCatchLoc->classId, pCatchLoc->methodId, pCatchLoc->idx,
+                dvmDbgGetClassDescriptor(pCatchLoc->classId),
+                dvmDbgGetMethodName(pCatchLoc->classId, pCatchLoc->methodId));
+        }
+
+        suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+        LOGV("  suspendPolicy=%s",
+            dvmJdwpSuspendPolicyStr(suspendPolicy));
+
+        pReq = eventPrep();
+        expandBufAdd1(pReq, suspendPolicy);
+        expandBufAdd4BE(pReq, matchCount);
+
+        for (int i = 0; i < matchCount; i++) {
+            expandBufAdd1(pReq, matchList[i]->eventKind);
+            expandBufAdd4BE(pReq, matchList[i]->requestId);
+            expandBufAdd8BE(pReq, basket.threadId);
+
+            dvmJdwpAddLocation(pReq, pThrowLoc);
+            expandBufAdd1(pReq, JT_OBJECT);
+            expandBufAdd8BE(pReq, exceptionId);
+            dvmJdwpAddLocation(pReq, pCatchLoc);
+        }
+
+        /* don't let the GC discard it */
+        dvmDbgRegisterObjectId(exceptionId);
+    }
+
+    cleanupMatchList(state, matchList, matchCount);
+    unlockEventMutex(state);
+
+    /* send request and possibly suspend ourselves */
+    if (pReq != NULL) {
+        int oldStatus = dvmDbgThreadWaiting();
+        if (suspendPolicy != SP_NONE)
+            dvmJdwpSetWaitForEventThread(state, basket.threadId);
+
+        eventFinish(state, pReq);
+
+        suspendByPolicy(state, suspendPolicy);
+        dvmDbgThreadContinuing(oldStatus);
+    }
+
+    free(nameAlloc);
+    return matchCount != 0;
+}
+
+/*
+ * Announce that a class has been loaded.
+ *
+ * Valid mods:
+ *  Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude
+ */
+bool dvmJdwpPostClassPrepare(JdwpState* state, int tag, RefTypeId refTypeId,
+    const char* signature, int status)
+{
+    JdwpSuspendPolicy suspendPolicy = SP_NONE;
+    ModBasket basket;
+    char* nameAlloc = NULL;
+
+    memset(&basket, 0, sizeof(basket));
+    basket.classId = refTypeId;
+    basket.threadId = dvmDbgGetThreadSelfId();
+    basket.className = nameAlloc =
+        dvmDescriptorToName(dvmDbgGetClassDescriptor(basket.classId));
+
+    /* suppress class prep caused by debugger */
+    if (invokeInProgress(state)) {
+        LOGV("Not posting class prep caused by invoke (%s)",basket.className);
+        free(nameAlloc);
+        return false;
+    }
+
+    /* don't allow the list to be updated while we scan it */
+    lockEventMutex(state);
+
+    JdwpEvent** matchList = allocMatchList(state);
+    int matchCount = 0;
+
+    findMatchingEvents(state, EK_CLASS_PREPARE, &basket, matchList,
+        &matchCount);
+
+    ExpandBuf* pReq = NULL;
+    if (matchCount != 0) {
+        LOGV("EVENT: %s(%d total) thread=%llx)",
+            dvmJdwpEventKindStr(matchList[0]->eventKind), matchCount,
+            basket.threadId);
+
+        suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+        LOGV("  suspendPolicy=%s",
+            dvmJdwpSuspendPolicyStr(suspendPolicy));
+
+        if (basket.threadId == state->debugThreadId) {
+            /*
+             * JDWP says that, for a class prep in the debugger thread, we
+             * should set threadId to null and if any threads were supposed
+             * to be suspended then we suspend all other threads.
+             */
+            LOGV("  NOTE: class prepare in debugger thread!");
+            basket.threadId = 0;
+            if (suspendPolicy == SP_EVENT_THREAD)
+                suspendPolicy = SP_ALL;
+        }
+
+        pReq = eventPrep();
+        expandBufAdd1(pReq, suspendPolicy);
+        expandBufAdd4BE(pReq, matchCount);
+
+        for (int i = 0; i < matchCount; i++) {
+            expandBufAdd1(pReq, matchList[i]->eventKind);
+            expandBufAdd4BE(pReq, matchList[i]->requestId);
+            expandBufAdd8BE(pReq, basket.threadId);
+
+            expandBufAdd1(pReq, tag);
+            expandBufAdd8BE(pReq, refTypeId);
+            expandBufAddUtf8String(pReq, (const u1*) signature);
+            expandBufAdd4BE(pReq, status);
+        }
+    }
+
+    cleanupMatchList(state, matchList, matchCount);
+
+    unlockEventMutex(state);
+
+    /* send request and possibly suspend ourselves */
+    if (pReq != NULL) {
+        int oldStatus = dvmDbgThreadWaiting();
+        if (suspendPolicy != SP_NONE)
+            dvmJdwpSetWaitForEventThread(state, basket.threadId);
+
+        eventFinish(state, pReq);
+
+        suspendByPolicy(state, suspendPolicy);
+        dvmDbgThreadContinuing(oldStatus);
+    }
+
+    free(nameAlloc);
+    return matchCount != 0;
+}
+
+/*
+ * Unload a class.
+ *
+ * Valid mods:
+ *  Count, ClassMatch, ClassExclude
+ */
+bool dvmJdwpPostClassUnload(JdwpState* state, RefTypeId refTypeId)
+{
+    assert(false);      // TODO
+    return false;
+}
+
+/*
+ * Get or set a field.
+ *
+ * Valid mods:
+ *  Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude, FieldOnly,
+ *    InstanceOnly
+ */
+bool dvmJdwpPostFieldAccess(JdwpState* state, int STUFF, ObjectId thisPtr,
+    bool modified, JValue newValue)
+{
+    assert(false);      // TODO
+    return false;
+}
+
+/*
+ * Send up a chunk of DDM data.
+ *
+ * While this takes the form of a JDWP "event", it doesn't interact with
+ * other debugger traffic, and can't suspend the VM, so we skip all of
+ * the fun event token gymnastics.
+ */
+void dvmJdwpDdmSendChunkV(JdwpState* state, int type, const struct iovec* iov,
+    int iovcnt)
+{
+    u1 header[kJDWPHeaderLen + 8];
+    size_t dataLen = 0;
+
+    assert(iov != NULL);
+    assert(iovcnt > 0 && iovcnt < 10);
+
+    /*
+     * "Wrap" the contents of the iovec with a JDWP/DDMS header.  We do
+     * this by creating a new copy of the vector with space for the header.
+     */
+    struct iovec wrapiov[iovcnt+1];
+    for (int i = 0; i < iovcnt; i++) {
+        wrapiov[i+1].iov_base = iov[i].iov_base;
+        wrapiov[i+1].iov_len = iov[i].iov_len;
+        dataLen += iov[i].iov_len;
+    }
+
+    /* form the header (JDWP plus DDMS) */
+    set4BE(header, sizeof(header) + dataLen);
+    set4BE(header+4, dvmJdwpNextRequestSerial(state));
+    set1(header+8, 0);     /* flags */
+    set1(header+9, kJDWPDdmCmdSet);
+    set1(header+10, kJDWPDdmCmd);
+    set4BE(header+11, type);
+    set4BE(header+15, dataLen);
+
+    wrapiov[0].iov_base = header;
+    wrapiov[0].iov_len = sizeof(header);
+
+    /*
+     * Make sure we're in VMWAIT in case the write blocks.
+     */
+    int oldStatus = dvmDbgThreadWaiting();
+    dvmJdwpSendBufferedRequest(state, wrapiov, iovcnt+1);
+    dvmDbgThreadContinuing(oldStatus);
+}
diff --git a/vm/jdwp/JdwpEvent.h b/vm/jdwp/JdwpEvent.h
new file mode 100644
index 0000000..c7d3e3c
--- /dev/null
+++ b/vm/jdwp/JdwpEvent.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+/*
+ * Handle registration of events, and debugger event notification.
+ */
+#ifndef DALVIK_JDWP_JDWPEVENT_H_
+#define DALVIK_JDWP_JDWPEVENT_H_
+
+#include "JdwpConstants.h"
+#include "ExpandBuf.h"
+
+/*
+ * Event modifiers.  A JdwpEvent may have zero or more of these.
+ */
+union JdwpEventMod {
+    u1      modKind;                /* JdwpModKind */
+    struct {
+        u1          modKind;
+        int         count;
+    } count;
+    struct {
+        u1          modKind;
+        u4          exprId;
+    } conditional;
+    struct {
+        u1          modKind;
+        ObjectId    threadId;
+    } threadOnly;
+    struct {
+        u1          modKind;
+        RefTypeId   refTypeId;
+    } classOnly;
+    struct {
+        u1          modKind;
+        char*       classPattern;
+    } classMatch;
+    struct {
+        u1          modKind;
+        char*       classPattern;
+    } classExclude;
+    struct {
+        u1          modKind;
+        JdwpLocation loc;
+    } locationOnly;
+    struct {
+        u1          modKind;
+        u1          caught;
+        u1          uncaught;
+        RefTypeId   refTypeId;
+    } exceptionOnly;
+    struct {
+        u1          modKind;
+        RefTypeId   refTypeId;
+        FieldId     fieldId;
+    } fieldOnly;
+    struct {
+        u1          modKind;
+        ObjectId    threadId;
+        int         size;           /* JdwpStepSize */
+        int         depth;          /* JdwpStepDepth */
+    } step;
+    struct {
+        u1          modKind;
+        ObjectId    objectId;
+    } instanceOnly;
+};
+
+/*
+ * One of these for every registered event.
+ *
+ * We over-allocate the struct to hold the modifiers.
+ */
+struct JdwpEvent {
+    JdwpEvent* prev;           /* linked list */
+    JdwpEvent* next;
+
+    JdwpEventKind eventKind;      /* what kind of event is this? */
+    JdwpSuspendPolicy suspendPolicy;  /* suspend all, none, or self? */
+    int modCount;       /* #of entries in mods[] */
+    u4 requestId;      /* serial#, reported to debugger */
+
+    JdwpEventMod mods[1];        /* MUST be last field in struct */
+};
+
+/*
+ * Allocate an event structure with enough space.
+ */
+JdwpEvent* dvmJdwpEventAlloc(int numMods);
+void dvmJdwpEventFree(JdwpEvent* pEvent);
+
+/*
+ * Register an event by adding it to the event list.
+ *
+ * "*pEvent" must be storage allocated with jdwpEventAlloc().  The caller
+ * may discard its pointer after calling this.
+ */
+JdwpError dvmJdwpRegisterEvent(JdwpState* state, JdwpEvent* pEvent);
+
+/*
+ * Unregister an event, given the requestId.
+ */
+void dvmJdwpUnregisterEventById(JdwpState* state, u4 requestId);
+
+/*
+ * Unregister all events.
+ */
+void dvmJdwpUnregisterAll(JdwpState* state);
+
+/*
+ * Send an event, formatted into "pReq", to the debugger.
+ *
+ * (Messages are sent asynchronously, and do not receive a reply.)
+ */
+bool dvmJdwpSendRequest(JdwpState* state, ExpandBuf* pReq);
+
+#endif  // DALVIK_JDWP_JDWPEVENT_H_
diff --git a/vm/jdwp/JdwpHandler.cpp b/vm/jdwp/JdwpHandler.cpp
new file mode 100644
index 0000000..02958e9
--- /dev/null
+++ b/vm/jdwp/JdwpHandler.cpp
@@ -0,0 +1,1972 @@
+/*
+ * 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.
+ */
+
+/*
+ * Handle messages from debugger.
+ *
+ * GENERAL NOTE: we're not currently testing the message length for
+ * correctness.  This is usually a bad idea, but here we can probably
+ * get away with it so long as the debugger isn't broken.  We can
+ * change the "read" macros to use "dataLen" to avoid wandering into
+ * bad territory, and have a single "is dataLen correct" check at the
+ * end of each function.  Not needed at this time.
+ */
+#include "jdwp/JdwpPriv.h"
+#include "jdwp/JdwpHandler.h"
+#include "jdwp/JdwpEvent.h"
+#include "jdwp/JdwpConstants.h"
+#include "jdwp/ExpandBuf.h"
+
+#include "Bits.h"
+#include "Atomic.h"
+#include "DalvikVersion.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Helper function: read a "location" from an input buffer.
+ */
+static void jdwpReadLocation(const u1** pBuf, JdwpLocation* pLoc)
+{
+    memset(pLoc, 0, sizeof(*pLoc));     /* allows memcmp() later */
+    pLoc->typeTag = read1(pBuf);
+    pLoc->classId = dvmReadObjectId(pBuf);
+    pLoc->methodId = dvmReadMethodId(pBuf);
+    pLoc->idx = read8BE(pBuf);
+}
+
+/*
+ * Helper function: write a "location" into the reply buffer.
+ */
+void dvmJdwpAddLocation(ExpandBuf* pReply, const JdwpLocation* pLoc)
+{
+    expandBufAdd1(pReply, pLoc->typeTag);
+    expandBufAddObjectId(pReply, pLoc->classId);
+    expandBufAddMethodId(pReply, pLoc->methodId);
+    expandBufAdd8BE(pReply, pLoc->idx);
+}
+
+/*
+ * Helper function: read a variable-width value from the input buffer.
+ */
+static u8 jdwpReadValue(const u1** pBuf, int width)
+{
+    u8 value;
+
+    switch (width) {
+    case 1:     value = read1(pBuf);                break;
+    case 2:     value = read2BE(pBuf);              break;
+    case 4:     value = read4BE(pBuf);              break;
+    case 8:     value = read8BE(pBuf);              break;
+    default:    value = (u8) -1; assert(false);     break;
+    }
+
+    return value;
+}
+
+/*
+ * Helper function: write a variable-width value into the output input buffer.
+ */
+static void jdwpWriteValue(ExpandBuf* pReply, int width, u8 value)
+{
+    switch (width) {
+    case 1:     expandBufAdd1(pReply, value);       break;
+    case 2:     expandBufAdd2BE(pReply, value);     break;
+    case 4:     expandBufAdd4BE(pReply, value);     break;
+    case 8:     expandBufAdd8BE(pReply, value);     break;
+    default:    assert(false);                      break;
+    }
+}
+
+/*
+ * Common code for *_InvokeMethod requests.
+ *
+ * If "isConstructor" is set, this returns "objectId" rather than the
+ * expected-to-be-void return value of the called function.
+ */
+static JdwpError finishInvoke(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply,
+    ObjectId threadId, ObjectId objectId, RefTypeId classId, MethodId methodId,
+    bool isConstructor)
+{
+    assert(!isConstructor || objectId != 0);
+
+    u4 numArgs = read4BE(&buf);
+
+    LOGV("    --> threadId=%llx objectId=%llx", threadId, objectId);
+    LOGV("        classId=%llx methodId=%x %s.%s",
+        classId, methodId,
+        dvmDbgGetClassDescriptor(classId),
+        dvmDbgGetMethodName(classId, methodId));
+    LOGV("        %d args:", numArgs);
+
+    u8* argArray = NULL;
+    if (numArgs > 0)
+        argArray = (ObjectId*) malloc(sizeof(ObjectId) * numArgs);
+
+    for (u4 i = 0; i < numArgs; i++) {
+        u1 typeTag = read1(&buf);
+        int width = dvmDbgGetTagWidth(typeTag);
+        u8 value = jdwpReadValue(&buf, width);
+
+        LOGV("          '%c'(%d): 0x%llx", typeTag, width, value);
+        argArray[i] = value;
+    }
+
+    u4 options = read4BE(&buf);  /* enum InvokeOptions bit flags */
+    LOGV("        options=0x%04x%s%s", options,
+        (options & INVOKE_SINGLE_THREADED) ? " (SINGLE_THREADED)" : "",
+        (options & INVOKE_NONVIRTUAL) ? " (NONVIRTUAL)" : "");
+
+
+    u1 resultTag;
+    u8 resultValue;
+    ObjectId exceptObjId;
+    JdwpError err = dvmDbgInvokeMethod(threadId, objectId, classId, methodId,
+            numArgs, argArray, options,
+            &resultTag, &resultValue, &exceptObjId);
+    if (err != ERR_NONE)
+        goto bail;
+
+    if (err == ERR_NONE) {
+        if (isConstructor) {
+            expandBufAdd1(pReply, JT_OBJECT);
+            expandBufAddObjectId(pReply, objectId);
+        } else {
+            int width = dvmDbgGetTagWidth(resultTag);
+
+            expandBufAdd1(pReply, resultTag);
+            if (width != 0)
+                jdwpWriteValue(pReply, width, resultValue);
+        }
+        expandBufAdd1(pReply, JT_OBJECT);
+        expandBufAddObjectId(pReply, exceptObjId);
+
+        LOGV("  --> returned '%c' 0x%llx (except=%08llx)",
+            resultTag, resultValue, exceptObjId);
+
+        /* show detailed debug output */
+        if (resultTag == JT_STRING && exceptObjId == 0) {
+            if (resultValue != 0) {
+                char* str = dvmDbgStringToUtf8(resultValue);
+                LOGV("      string '%s'", str);
+                free(str);
+            } else {
+                LOGV("      string (null)");
+            }
+        }
+    }
+
+bail:
+    free(argArray);
+    return err;
+}
+
+
+/*
+ * Request for version info.
+ */
+static JdwpError handleVM_Version(JdwpState* state, const u1* buf,
+    int dataLen, ExpandBuf* pReply)
+{
+    char tmpBuf[128];
+
+    /* text information on VM version */
+    sprintf(tmpBuf, "Android DalvikVM %d.%d.%d",
+        DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
+    expandBufAddUtf8String(pReply, (const u1*) tmpBuf);
+    /* JDWP version numbers */
+    expandBufAdd4BE(pReply, 1);        // major
+    expandBufAdd4BE(pReply, 5);        // minor
+    /* VM JRE version */
+    expandBufAddUtf8String(pReply, (const u1*) "1.5.0");  /* e.g. 1.5.0_04 */
+    /* target VM name */
+    expandBufAddUtf8String(pReply, (const u1*) "DalvikVM");
+
+    return ERR_NONE;
+}
+
+/*
+ * Given a class JNI signature (e.g. "Ljava/lang/Error;"), return the
+ * referenceTypeID.  We need to send back more than one if the class has
+ * been loaded by multiple class loaders.
+ */
+static JdwpError handleVM_ClassesBySignature(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    size_t strLen;
+    char* classDescriptor = readNewUtf8String(&buf, &strLen);
+    LOGV("  Req for class by signature '%s'", classDescriptor);
+
+    /*
+     * TODO: if a class with the same name has been loaded multiple times
+     * (by different class loaders), we're supposed to return each of them.
+     *
+     * NOTE: this may mangle "className".
+     */
+    u4 numClasses;
+    RefTypeId refTypeId;
+    if (!dvmDbgFindLoadedClassBySignature(classDescriptor, &refTypeId)) {
+        /* not currently loaded */
+        LOGV("    --> no match!");
+        numClasses = 0;
+    } else {
+        /* just the one */
+        numClasses = 1;
+    }
+
+    expandBufAdd4BE(pReply, numClasses);
+
+    if (numClasses > 0) {
+        u1 typeTag;
+        u4 status;
+
+        /* get class vs. interface and status flags */
+        dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL);
+
+        expandBufAdd1(pReply, typeTag);
+        expandBufAddRefTypeId(pReply, refTypeId);
+        expandBufAdd4BE(pReply, status);
+    }
+
+    free(classDescriptor);
+
+    return ERR_NONE;
+}
+
+/*
+ * Handle request for the thread IDs of all running threads.
+ *
+ * We exclude ourselves from the list, because we don't allow ourselves
+ * to be suspended, and that violates some JDWP expectations.
+ */
+static JdwpError handleVM_AllThreads(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId* pThreadIds;
+    u4 threadCount;
+    dvmDbgGetAllThreads(&pThreadIds, &threadCount);
+
+    expandBufAdd4BE(pReply, threadCount);
+
+    ObjectId* walker = pThreadIds;
+    for (u4 i = 0; i < threadCount; i++) {
+        expandBufAddObjectId(pReply, *walker++);
+    }
+
+    free(pThreadIds);
+
+    return ERR_NONE;
+}
+
+/*
+ * List all thread groups that do not have a parent.
+ */
+static JdwpError handleVM_TopLevelThreadGroups(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    /*
+     * TODO: maintain a list of parentless thread groups in the VM.
+     *
+     * For now, just return "system".  Application threads are created
+     * in "main", which is a child of "system".
+     */
+    u4 groups = 1;
+    expandBufAdd4BE(pReply, groups);
+    //threadGroupId = debugGetMainThreadGroup();
+    //expandBufAdd8BE(pReply, threadGroupId);
+    ObjectId threadGroupId = dvmDbgGetSystemThreadGroupId();
+    expandBufAddObjectId(pReply, threadGroupId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Respond with the sizes of the basic debugger types.
+ *
+ * All IDs are 8 bytes.
+ */
+static JdwpError handleVM_IDSizes(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    expandBufAdd4BE(pReply, sizeof(FieldId));
+    expandBufAdd4BE(pReply, sizeof(MethodId));
+    expandBufAdd4BE(pReply, sizeof(ObjectId));
+    expandBufAdd4BE(pReply, sizeof(RefTypeId));
+    expandBufAdd4BE(pReply, sizeof(FrameId));
+    return ERR_NONE;
+}
+
+/*
+ * The debugger is politely asking to disconnect.  We're good with that.
+ *
+ * We could resume threads and clean up pinned references, but we can do
+ * that when the TCP connection drops.
+ */
+static JdwpError handleVM_Dispose(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    return ERR_NONE;
+}
+
+/*
+ * Suspend the execution of the application running in the VM (i.e. suspend
+ * all threads).
+ *
+ * This needs to increment the "suspend count" on all threads.
+ */
+static JdwpError handleVM_Suspend(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    dvmDbgSuspendVM(false);
+    return ERR_NONE;
+}
+
+/*
+ * Resume execution.  Decrements the "suspend count" of all threads.
+ */
+static JdwpError handleVM_Resume(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    dvmDbgResumeVM();
+    return ERR_NONE;
+}
+
+/*
+ * The debugger wants the entire VM to exit.
+ */
+static JdwpError handleVM_Exit(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    u4 exitCode = get4BE(buf);
+
+    LOGW("Debugger is telling the VM to exit with code=%d", exitCode);
+
+    dvmDbgExit(exitCode);
+    return ERR_NOT_IMPLEMENTED;     // shouldn't get here
+}
+
+/*
+ * Create a new string in the VM and return its ID.
+ *
+ * (Ctrl-Shift-I in Eclipse on an array of objects causes it to create the
+ * string "java.util.Arrays".)
+ */
+static JdwpError handleVM_CreateString(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    size_t strLen;
+    char* str = readNewUtf8String(&buf, &strLen);
+
+    LOGV("  Req to create string '%s'", str);
+
+    ObjectId stringId = dvmDbgCreateString(str);
+    if (stringId == 0)
+        return ERR_OUT_OF_MEMORY;
+
+    expandBufAddObjectId(pReply, stringId);
+    return ERR_NONE;
+}
+
+/*
+ * Tell the debugger what we are capable of.
+ */
+static JdwpError handleVM_Capabilities(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    expandBufAdd1(pReply, false);   /* canWatchFieldModification */
+    expandBufAdd1(pReply, false);   /* canWatchFieldAccess */
+    expandBufAdd1(pReply, false);   /* canGetBytecodes */
+    expandBufAdd1(pReply, true);    /* canGetSyntheticAttribute */
+    expandBufAdd1(pReply, false);   /* canGetOwnedMonitorInfo */
+    expandBufAdd1(pReply, false);   /* canGetCurrentContendedMonitor */
+    expandBufAdd1(pReply, false);   /* canGetMonitorInfo */
+    return ERR_NONE;
+}
+
+/*
+ * Return classpath and bootclasspath.
+ */
+static JdwpError handleVM_ClassPaths(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    char baseDir[2] = "/";
+
+    /*
+     * TODO: make this real.  Not important for remote debugging, but
+     * might be useful for local debugging.
+     */
+    u4 classPaths = 1;
+    u4 bootClassPaths = 0;
+
+    expandBufAddUtf8String(pReply, (const u1*) baseDir);
+    expandBufAdd4BE(pReply, classPaths);
+    for (u4 i = 0; i < classPaths; i++) {
+        expandBufAddUtf8String(pReply, (const u1*) ".");
+    }
+
+    expandBufAdd4BE(pReply, bootClassPaths);
+    for (u4 i = 0; i < classPaths; i++) {
+        /* add bootclasspath components as strings */
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Release a list of object IDs.  (Seen in jdb.)
+ *
+ * Currently does nothing.
+ */
+static JdwpError HandleVM_DisposeObjects(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    return ERR_NONE;
+}
+
+/*
+ * Tell the debugger what we are capable of.
+ */
+static JdwpError handleVM_CapabilitiesNew(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    expandBufAdd1(pReply, false);   /* canWatchFieldModification */
+    expandBufAdd1(pReply, false);   /* canWatchFieldAccess */
+    expandBufAdd1(pReply, false);   /* canGetBytecodes */
+    expandBufAdd1(pReply, true);    /* canGetSyntheticAttribute */
+    expandBufAdd1(pReply, false);   /* canGetOwnedMonitorInfo */
+    expandBufAdd1(pReply, false);   /* canGetCurrentContendedMonitor */
+    expandBufAdd1(pReply, false);   /* canGetMonitorInfo */
+    expandBufAdd1(pReply, false);   /* canRedefineClasses */
+    expandBufAdd1(pReply, false);   /* canAddMethod */
+    expandBufAdd1(pReply, false);   /* canUnrestrictedlyRedefineClasses */
+    expandBufAdd1(pReply, false);   /* canPopFrames */
+    expandBufAdd1(pReply, false);   /* canUseInstanceFilters */
+    expandBufAdd1(pReply, false);   /* canGetSourceDebugExtension */
+    expandBufAdd1(pReply, false);   /* canRequestVMDeathEvent */
+    expandBufAdd1(pReply, false);   /* canSetDefaultStratum */
+    expandBufAdd1(pReply, false);   /* 1.6: canGetInstanceInfo */
+    expandBufAdd1(pReply, false);   /* 1.6: canRequestMonitorEvents */
+    expandBufAdd1(pReply, false);   /* 1.6: canGetMonitorFrameInfo */
+    expandBufAdd1(pReply, false);   /* 1.6: canUseSourceNameFilters */
+    expandBufAdd1(pReply, false);   /* 1.6: canGetConstantPool */
+    expandBufAdd1(pReply, false);   /* 1.6: canForceEarlyReturn */
+
+    /* fill in reserved22 through reserved32; note count started at 1 */
+    for (int i = 22; i <= 32; i++)
+        expandBufAdd1(pReply, false);   /* reservedN */
+    return ERR_NONE;
+}
+
+/*
+ * Cough up the complete list of classes.
+ */
+static JdwpError handleVM_AllClassesWithGeneric(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    u4 numClasses = 0;
+    RefTypeId* classRefBuf = NULL;
+
+    dvmDbgGetClassList(&numClasses, &classRefBuf);
+
+    expandBufAdd4BE(pReply, numClasses);
+
+    for (u4 i = 0; i < numClasses; i++) {
+        static const u1 genericSignature[1] = "";
+        u1 refTypeTag;
+        const char* signature;
+        u4 status;
+
+        dvmDbgGetClassInfo(classRefBuf[i], &refTypeTag, &status, &signature);
+
+        expandBufAdd1(pReply, refTypeTag);
+        expandBufAddRefTypeId(pReply, classRefBuf[i]);
+        expandBufAddUtf8String(pReply, (const u1*) signature);
+        expandBufAddUtf8String(pReply, genericSignature);
+        expandBufAdd4BE(pReply, status);
+    }
+
+    free(classRefBuf);
+
+    return ERR_NONE;
+}
+
+/*
+ * Given a referenceTypeID, return a string with the JNI reference type
+ * signature (e.g. "Ljava/lang/Error;").
+ */
+static JdwpError handleRT_Signature(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    LOGV("  Req for signature of refTypeId=0x%llx", refTypeId);
+    const char* signature = dvmDbgGetSignature(refTypeId);
+    expandBufAddUtf8String(pReply, (const u1*) signature);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the modifiers (a/k/a access flags) for a reference type.
+ */
+static JdwpError handleRT_Modifiers(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+    u4 modBits = dvmDbgGetAccessFlags(refTypeId);
+
+    expandBufAdd4BE(pReply, modBits);
+
+    return ERR_NONE;
+}
+
+/*
+ * Get values from static fields in a reference type.
+ */
+static JdwpError handleRT_GetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+    u4 numFields = read4BE(&buf);
+
+    LOGV("  RT_GetValues %u:", numFields);
+
+    expandBufAdd4BE(pReply, numFields);
+    for (u4 i = 0; i < numFields; i++) {
+        FieldId fieldId = dvmReadFieldId(&buf);
+        dvmDbgGetStaticFieldValue(refTypeId, fieldId, pReply);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Get the name of the source file in which a reference type was declared.
+ */
+static JdwpError handleRT_SourceFile(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    const char* fileName = dvmDbgGetSourceFile(refTypeId);
+    if (fileName != NULL) {
+        expandBufAddUtf8String(pReply, (const u1*) fileName);
+        return ERR_NONE;
+    } else {
+        return ERR_ABSENT_INFORMATION;
+    }
+}
+
+/*
+ * Return the current status of the reference type.
+ */
+static JdwpError handleRT_Status(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    /* get status flags */
+    u1 typeTag;
+    u4 status;
+    dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL);
+    expandBufAdd4BE(pReply, status);
+    return ERR_NONE;
+}
+
+/*
+ * Return interfaces implemented directly by this class.
+ */
+static JdwpError handleRT_Interfaces(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    LOGV("  Req for interfaces in %llx (%s)", refTypeId,
+        dvmDbgGetClassDescriptor(refTypeId));
+
+    dvmDbgOutputAllInterfaces(refTypeId, pReply);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the class object corresponding to this type.
+ */
+static JdwpError handleRT_ClassObject(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+    ObjectId classObjId = dvmDbgGetClassObject(refTypeId);
+
+    LOGV("  RefTypeId %llx -> ObjectId %llx", refTypeId, classObjId);
+
+    expandBufAddObjectId(pReply, classObjId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Returns the value of the SourceDebugExtension attribute.
+ *
+ * JDB seems interested, but DEX files don't currently support this.
+ */
+static JdwpError handleRT_SourceDebugExtension(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    /* referenceTypeId in, string out */
+    return ERR_ABSENT_INFORMATION;
+}
+
+/*
+ * Like RT_Signature but with the possibility of a "generic signature".
+ */
+static JdwpError handleRT_SignatureWithGeneric(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    static const u1 genericSignature[1] = "";
+
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    LOGV("  Req for signature of refTypeId=0x%llx", refTypeId);
+    const char* signature = dvmDbgGetSignature(refTypeId);
+    if (signature != NULL) {
+        expandBufAddUtf8String(pReply, (const u1*) signature);
+    } else {
+        LOGW("No signature for refTypeId=0x%llx", refTypeId);
+        expandBufAddUtf8String(pReply, (const u1*) "Lunknown;");
+    }
+    expandBufAddUtf8String(pReply, genericSignature);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the instance of java.lang.ClassLoader that loaded the specified
+ * reference type, or null if it was loaded by the system loader.
+ */
+static JdwpError handleRT_ClassLoader(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    expandBufAddObjectId(pReply, dvmDbgGetClassLoader(refTypeId));
+
+    return ERR_NONE;
+}
+
+/*
+ * Given a referenceTypeId, return a block of stuff that describes the
+ * fields declared by a class.
+ */
+static JdwpError handleRT_FieldsWithGeneric(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+    LOGV("  Req for fields in refTypeId=0x%llx", refTypeId);
+    LOGV("  --> '%s'", dvmDbgGetSignature(refTypeId));
+
+    dvmDbgOutputAllFields(refTypeId, true, pReply);
+
+    return ERR_NONE;
+}
+
+/*
+ * Given a referenceTypeID, return a block of goodies describing the
+ * methods declared by a class.
+ */
+static JdwpError handleRT_MethodsWithGeneric(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+
+    LOGV("  Req for methods in refTypeId=0x%llx", refTypeId);
+    LOGV("  --> '%s'", dvmDbgGetSignature(refTypeId));
+
+    dvmDbgOutputAllMethods(refTypeId, true, pReply);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the immediate superclass of a class.
+ */
+static JdwpError handleCT_Superclass(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classId = dvmReadRefTypeId(&buf);
+
+    RefTypeId superClassId = dvmDbgGetSuperclass(classId);
+
+    expandBufAddRefTypeId(pReply, superClassId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Set static class values.
+ */
+static JdwpError handleCT_SetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classId = dvmReadRefTypeId(&buf);
+    u4 values = read4BE(&buf);
+
+    LOGV("  Req to set %d values in classId=%llx", values, classId);
+
+    for (u4 i = 0; i < values; i++) {
+        FieldId fieldId = dvmReadFieldId(&buf);
+        u1 fieldTag = dvmDbgGetStaticFieldBasicTag(classId, fieldId);
+        int width = dvmDbgGetTagWidth(fieldTag);
+        u8 value = jdwpReadValue(&buf, width);
+
+        LOGV("    --> field=%x tag=%c -> %lld", fieldId, fieldTag, value);
+        dvmDbgSetStaticFieldValue(classId, fieldId, value, width);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Invoke a static method.
+ *
+ * Example: Eclipse sometimes uses java/lang/Class.forName(String s) on
+ * values in the "variables" display.
+ */
+static JdwpError handleCT_InvokeMethod(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classId = dvmReadRefTypeId(&buf);
+    ObjectId threadId = dvmReadObjectId(&buf);
+    MethodId methodId = dvmReadMethodId(&buf);
+
+    return finishInvoke(state, buf, dataLen, pReply,
+            threadId, 0, classId, methodId, false);
+}
+
+/*
+ * Create a new object of the requested type, and invoke the specified
+ * constructor.
+ *
+ * Example: in IntelliJ, create a watch on "new String(myByteArray)" to
+ * see the contents of a byte[] as a string.
+ */
+static JdwpError handleCT_NewInstance(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classId = dvmReadRefTypeId(&buf);
+    ObjectId threadId = dvmReadObjectId(&buf);
+    MethodId methodId = dvmReadMethodId(&buf);
+
+    LOGV("Creating instance of %s", dvmDbgGetClassDescriptor(classId));
+    ObjectId objectId = dvmDbgCreateObject(classId);
+    if (objectId == 0)
+        return ERR_OUT_OF_MEMORY;
+
+    return finishInvoke(state, buf, dataLen, pReply,
+            threadId, objectId, classId, methodId, true);
+}
+
+/*
+ * Create a new array object of the requested type and length.
+ */
+static JdwpError handleAT_newInstance(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId arrayTypeId = dvmReadRefTypeId(&buf);
+    u4 length = read4BE(&buf);
+
+    LOGV("Creating array %s[%u]",
+        dvmDbgGetClassDescriptor(arrayTypeId), length);
+    ObjectId objectId = dvmDbgCreateArrayObject(arrayTypeId, length);
+    if (objectId == 0)
+        return ERR_OUT_OF_MEMORY;
+
+    expandBufAdd1(pReply, JT_ARRAY);
+    expandBufAddObjectId(pReply, objectId);
+    return ERR_NONE;
+}
+
+/*
+ * Return line number information for the method, if present.
+ */
+static JdwpError handleM_LineTable(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
+    MethodId methodId = dvmReadMethodId(&buf);
+
+    LOGV("  Req for line table in %s.%s",
+        dvmDbgGetClassDescriptor(refTypeId),
+        dvmDbgGetMethodName(refTypeId,methodId));
+
+    dvmDbgOutputLineTable(refTypeId, methodId, pReply);
+
+    return ERR_NONE;
+}
+
+/*
+ * Pull out the LocalVariableTable goodies.
+ */
+static JdwpError handleM_VariableTableWithGeneric(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classId = dvmReadRefTypeId(&buf);
+    MethodId methodId = dvmReadMethodId(&buf);
+
+    LOGV("  Req for LocalVarTab in class=%s method=%s",
+        dvmDbgGetClassDescriptor(classId),
+        dvmDbgGetMethodName(classId, methodId));
+
+    /*
+     * We could return ERR_ABSENT_INFORMATION here if the DEX file was
+     * built without local variable information.  That will cause Eclipse
+     * to make a best-effort attempt at displaying local variables
+     * anonymously.  However, the attempt isn't very good, so we're probably
+     * better off just not showing anything.
+     */
+    dvmDbgOutputVariableTable(classId, methodId, true, pReply);
+    return ERR_NONE;
+}
+
+/*
+ * Given an object reference, return the runtime type of the object
+ * (class or array).
+ *
+ * This can get called on different things, e.g. threadId gets
+ * passed in here.
+ */
+static JdwpError handleOR_ReferenceType(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId objectId = dvmReadObjectId(&buf);
+    LOGV("  Req for type of objectId=0x%llx", objectId);
+
+    u1 refTypeTag;
+    RefTypeId typeId;
+    dvmDbgGetObjectType(objectId, &refTypeTag, &typeId);
+
+    expandBufAdd1(pReply, refTypeTag);
+    expandBufAddRefTypeId(pReply, typeId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Get values from the fields of an object.
+ */
+static JdwpError handleOR_GetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId objectId = dvmReadObjectId(&buf);
+    u4 numFields = read4BE(&buf);
+
+    LOGV("  Req for %d fields from objectId=0x%llx", numFields, objectId);
+
+    expandBufAdd4BE(pReply, numFields);
+
+    for (u4 i = 0; i < numFields; i++) {
+        FieldId fieldId = dvmReadFieldId(&buf);
+        dvmDbgGetFieldValue(objectId, fieldId, pReply);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Set values in the fields of an object.
+ */
+static JdwpError handleOR_SetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId objectId = dvmReadObjectId(&buf);
+    u4 numFields = read4BE(&buf);
+
+    LOGV("  Req to set %d fields in objectId=0x%llx", numFields, objectId);
+
+    for (u4 i = 0; i < numFields; i++) {
+        FieldId fieldId = dvmReadFieldId(&buf);
+
+        u1 fieldTag = dvmDbgGetFieldBasicTag(objectId, fieldId);
+        int width = dvmDbgGetTagWidth(fieldTag);
+        u8 value = jdwpReadValue(&buf, width);
+
+        LOGV("    --> fieldId=%x tag='%c'(%d) value=%lld",
+            fieldId, fieldTag, width, value);
+
+        dvmDbgSetFieldValue(objectId, fieldId, value, width);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Invoke an instance method.  The invocation must occur in the specified
+ * thread, which must have been suspended by an event.
+ *
+ * The call is synchronous.  All threads in the VM are resumed, unless the
+ * SINGLE_THREADED flag is set.
+ *
+ * If you ask Eclipse to "inspect" an object (or ask JDB to "print" an
+ * object), it will try to invoke the object's toString() function.  This
+ * feature becomes crucial when examining ArrayLists with Eclipse.
+ */
+static JdwpError handleOR_InvokeMethod(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId objectId = dvmReadObjectId(&buf);
+    ObjectId threadId = dvmReadObjectId(&buf);
+    RefTypeId classId = dvmReadRefTypeId(&buf);
+    MethodId methodId = dvmReadMethodId(&buf);
+
+    return finishInvoke(state, buf, dataLen, pReply,
+            threadId, objectId, classId, methodId, false);
+}
+
+/*
+ * Disable garbage collection of the specified object.
+ */
+static JdwpError handleOR_DisableCollection(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    // this is currently a no-op
+    return ERR_NONE;
+}
+
+/*
+ * Enable garbage collection of the specified object.
+ */
+static JdwpError handleOR_EnableCollection(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    // this is currently a no-op
+    return ERR_NONE;
+}
+
+/*
+ * Determine whether an object has been garbage collected.
+ */
+static JdwpError handleOR_IsCollected(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId objectId;
+
+    objectId = dvmReadObjectId(&buf);
+    LOGV("  Req IsCollected(0x%llx)", objectId);
+
+    // TODO: currently returning false; must integrate with GC
+    expandBufAdd1(pReply, 0);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the string value in a string object.
+ */
+static JdwpError handleSR_Value(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId stringObject = dvmReadObjectId(&buf);
+    char* str = dvmDbgStringToUtf8(stringObject);
+
+    LOGV("  Req for str %llx --> '%s'", stringObject, str);
+
+    expandBufAddUtf8String(pReply, (u1*) str);
+    free(str);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return a thread's name.
+ */
+static JdwpError handleTR_Name(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    LOGV("  Req for name of thread 0x%llx", threadId);
+    char* name = dvmDbgGetThreadName(threadId);
+    if (name == NULL)
+        return ERR_INVALID_THREAD;
+
+    expandBufAddUtf8String(pReply, (u1*) name);
+    free(name);
+
+    return ERR_NONE;
+}
+
+/*
+ * Suspend the specified thread.
+ *
+ * It's supposed to remain suspended even if interpreted code wants to
+ * resume it; only the JDI is allowed to resume it.
+ */
+static JdwpError handleTR_Suspend(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    if (threadId == dvmDbgGetThreadSelfId()) {
+        LOGI("  Warning: ignoring request to suspend self");
+        return ERR_THREAD_NOT_SUSPENDED;
+    }
+    LOGV("  Req to suspend thread 0x%llx", threadId);
+
+    dvmDbgSuspendThread(threadId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Resume the specified thread.
+ */
+static JdwpError handleTR_Resume(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    if (threadId == dvmDbgGetThreadSelfId()) {
+        LOGI("  Warning: ignoring request to resume self");
+        return ERR_NONE;
+    }
+    LOGV("  Req to resume thread 0x%llx", threadId);
+
+    dvmDbgResumeThread(threadId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return status of specified thread.
+ */
+static JdwpError handleTR_Status(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    LOGV("  Req for status of thread 0x%llx", threadId);
+
+    u4 threadStatus;
+    u4 suspendStatus;
+    if (!dvmDbgGetThreadStatus(threadId, &threadStatus, &suspendStatus))
+        return ERR_INVALID_THREAD;
+
+    LOGV("    --> %s, %s", dvmJdwpThreadStatusStr(threadStatus),
+        dvmJdwpSuspendStatusStr(suspendStatus));
+
+    expandBufAdd4BE(pReply, threadStatus);
+    expandBufAdd4BE(pReply, suspendStatus);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the thread group that the specified thread is a member of.
+ */
+static JdwpError handleTR_ThreadGroup(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    /* currently not handling these */
+    ObjectId threadGroupId = dvmDbgGetThreadGroup(threadId);
+    expandBufAddObjectId(pReply, threadGroupId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the current call stack of a suspended thread.
+ *
+ * If the thread isn't suspended, the error code isn't defined, but should
+ * be THREAD_NOT_SUSPENDED.
+ */
+static JdwpError handleTR_Frames(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+    u4 startFrame = read4BE(&buf);
+    u4 length = read4BE(&buf);
+
+    if (!dvmDbgThreadExists(threadId))
+        return ERR_INVALID_THREAD;
+    if (!dvmDbgIsSuspended(threadId)) {
+        LOGV("  Rejecting req for frames in running thread '%s' (%llx)",
+            dvmDbgGetThreadName(threadId), threadId);
+        return ERR_THREAD_NOT_SUSPENDED;
+    }
+
+    int frameCount = dvmDbgGetThreadFrameCount(threadId);
+
+    LOGV("  Request for frames: threadId=%llx start=%d length=%d [count=%d]",
+        threadId, startFrame, length, frameCount);
+    if (frameCount <= 0)
+        return ERR_THREAD_NOT_SUSPENDED;    /* == 0 means 100% native */
+
+    if (length == (u4) -1)
+        length = frameCount;
+    assert((int) startFrame >= 0 && (int) startFrame < frameCount);
+    assert((int) (startFrame + length) <= frameCount);
+
+    u4 frames = length;
+    expandBufAdd4BE(pReply, frames);
+    for (u4 i = startFrame; i < (startFrame+length); i++) {
+        FrameId frameId;
+        JdwpLocation loc;
+
+        dvmDbgGetThreadFrame(threadId, i, &frameId, &loc);
+
+        expandBufAdd8BE(pReply, frameId);
+        dvmJdwpAddLocation(pReply, &loc);
+
+        LOGVV("    Frame %d: id=%llx loc={type=%d cls=%llx mth=%x loc=%llx}",
+            i, frameId, loc.typeTag, loc.classId, loc.methodId, loc.idx);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Returns the #of frames on the specified thread, which must be suspended.
+ */
+static JdwpError handleTR_FrameCount(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    if (!dvmDbgThreadExists(threadId))
+        return ERR_INVALID_THREAD;
+    if (!dvmDbgIsSuspended(threadId)) {
+        LOGV("  Rejecting req for frames in running thread '%s' (%llx)",
+            dvmDbgGetThreadName(threadId), threadId);
+        return ERR_THREAD_NOT_SUSPENDED;
+    }
+
+    int frameCount = dvmDbgGetThreadFrameCount(threadId);
+    if (frameCount < 0)
+        return ERR_INVALID_THREAD;
+    expandBufAdd4BE(pReply, (u4)frameCount);
+
+    return ERR_NONE;
+}
+
+/*
+ * Get the monitor that the thread is waiting on.
+ */
+static JdwpError handleTR_CurrentContendedMonitor(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId;
+
+    threadId = dvmReadObjectId(&buf);
+
+    // TODO: create an Object to represent the monitor (we're currently
+    // just using a raw Monitor struct in the VM)
+
+    return ERR_NOT_IMPLEMENTED;
+}
+
+/*
+ * Return the suspend count for the specified thread.
+ *
+ * (The thread *might* still be running -- it might not have examined
+ * its suspend count recently.)
+ */
+static JdwpError handleTR_SuspendCount(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+
+    u4 suspendCount = dvmDbgGetThreadSuspendCount(threadId);
+    expandBufAdd4BE(pReply, suspendCount);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the name of a thread group.
+ *
+ * The Eclipse debugger recognizes "main" and "system" as special.
+ */
+static JdwpError handleTGR_Name(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadGroupId = dvmReadObjectId(&buf);
+    LOGV("  Req for name of threadGroupId=0x%llx", threadGroupId);
+
+    char* name = dvmDbgGetThreadGroupName(threadGroupId);
+    if (name != NULL)
+        expandBufAddUtf8String(pReply, (u1*) name);
+    else {
+        expandBufAddUtf8String(pReply, (u1*) "BAD-GROUP-ID");
+        LOGW("bad thread group ID");
+    }
+
+    free(name);
+
+    return ERR_NONE;
+}
+
+/*
+ * Returns the thread group -- if any -- that contains the specified
+ * thread group.
+ */
+static JdwpError handleTGR_Parent(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId groupId = dvmReadObjectId(&buf);
+
+    ObjectId parentGroup = dvmDbgGetThreadGroupParent(groupId);
+    expandBufAddObjectId(pReply, parentGroup);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the active threads and thread groups that are part of the
+ * specified thread group.
+ */
+static JdwpError handleTGR_Children(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadGroupId = dvmReadObjectId(&buf);
+    LOGV("  Req for threads in threadGroupId=0x%llx", threadGroupId);
+
+    ObjectId* pThreadIds;
+    u4 threadCount;
+    dvmDbgGetThreadGroupThreads(threadGroupId, &pThreadIds, &threadCount);
+
+    expandBufAdd4BE(pReply, threadCount);
+
+    for (u4 i = 0; i < threadCount; i++)
+        expandBufAddObjectId(pReply, pThreadIds[i]);
+    free(pThreadIds);
+
+    /*
+     * TODO: finish support for child groups
+     *
+     * For now, just show that "main" is a child of "system".
+     */
+    if (threadGroupId == dvmDbgGetSystemThreadGroupId()) {
+        expandBufAdd4BE(pReply, 1);
+        expandBufAddObjectId(pReply, dvmDbgGetMainThreadGroupId());
+    } else {
+        expandBufAdd4BE(pReply, 0);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the #of components in the array.
+ */
+static JdwpError handleAR_Length(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId arrayId = dvmReadObjectId(&buf);
+    LOGV("  Req for length of array 0x%llx", arrayId);
+
+    u4 arrayLength = dvmDbgGetArrayLength(arrayId);
+
+    LOGV("    --> %d", arrayLength);
+
+    expandBufAdd4BE(pReply, arrayLength);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the values from an array.
+ */
+static JdwpError handleAR_GetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId arrayId = dvmReadObjectId(&buf);
+    u4 firstIndex = read4BE(&buf);
+    u4 length = read4BE(&buf);
+
+    u1 tag = dvmDbgGetArrayElementTag(arrayId);
+    LOGV("  Req for array values 0x%llx first=%d len=%d (elem tag=%c)",
+        arrayId, firstIndex, length, tag);
+
+    expandBufAdd1(pReply, tag);
+    expandBufAdd4BE(pReply, length);
+
+    if (!dvmDbgOutputArray(arrayId, firstIndex, length, pReply))
+        return ERR_INVALID_LENGTH;
+
+    return ERR_NONE;
+}
+
+/*
+ * Set values in an array.
+ */
+static JdwpError handleAR_SetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId arrayId = dvmReadObjectId(&buf);
+    u4 firstIndex = read4BE(&buf);
+    u4 values = read4BE(&buf);
+
+    LOGV("  Req to set array values 0x%llx first=%d count=%d",
+        arrayId, firstIndex, values);
+
+    if (!dvmDbgSetArrayElements(arrayId, firstIndex, values, buf))
+        return ERR_INVALID_LENGTH;
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the set of classes visible to a class loader.  All classes which
+ * have the class loader as a defining or initiating loader are returned.
+ */
+static JdwpError handleCLR_VisibleClasses(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId classLoaderObject;
+    u4 numClasses = 0;
+    RefTypeId* classRefBuf = NULL;
+    int i;
+
+    classLoaderObject = dvmReadObjectId(&buf);
+
+    dvmDbgGetVisibleClassList(classLoaderObject, &numClasses, &classRefBuf);
+
+    expandBufAdd4BE(pReply, numClasses);
+    for (i = 0; i < (int) numClasses; i++) {
+        u1 refTypeTag;
+
+        refTypeTag = dvmDbgGetClassObjectType(classRefBuf[i]);
+
+        expandBufAdd1(pReply, refTypeTag);
+        expandBufAddRefTypeId(pReply, classRefBuf[i]);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Set an event trigger.
+ *
+ * Reply with a requestID.
+ */
+static JdwpError handleER_Set(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    const u1* origBuf = buf;
+
+    u1 eventKind = read1(&buf);
+    u1 suspendPolicy = read1(&buf);
+    u4 modifierCount = read4BE(&buf);
+
+    LOGVV("  Set(kind=%s(%u) suspend=%s(%u) mods=%u)",
+        dvmJdwpEventKindStr(eventKind), eventKind,
+        dvmJdwpSuspendPolicyStr(suspendPolicy), suspendPolicy,
+        modifierCount);
+
+    assert(modifierCount < 256);    /* reasonableness check */
+
+    JdwpEvent* pEvent = dvmJdwpEventAlloc(modifierCount);
+    pEvent->eventKind = static_cast<JdwpEventKind>(eventKind);
+    pEvent->suspendPolicy = static_cast<JdwpSuspendPolicy>(suspendPolicy);
+    pEvent->modCount = modifierCount;
+
+    /*
+     * Read modifiers.  Ordering may be significant (see explanation of Count
+     * mods in JDWP doc).
+     */
+    for (u4 idx = 0; idx < modifierCount; idx++) {
+        u1 modKind = read1(&buf);
+
+        pEvent->mods[idx].modKind = modKind;
+
+        switch (modKind) {
+        case MK_COUNT:          /* report once, when "--count" reaches 0 */
+            {
+                u4 count = read4BE(&buf);
+                LOGVV("    Count: %u", count);
+                if (count == 0)
+                    return ERR_INVALID_COUNT;
+                pEvent->mods[idx].count.count = count;
+            }
+            break;
+        case MK_CONDITIONAL:    /* conditional on expression) */
+            {
+                u4 exprId = read4BE(&buf);
+                LOGVV("    Conditional: %d", exprId);
+                pEvent->mods[idx].conditional.exprId = exprId;
+            }
+            break;
+        case MK_THREAD_ONLY:    /* only report events in specified thread */
+            {
+                ObjectId threadId = dvmReadObjectId(&buf);
+                LOGVV("    ThreadOnly: %llx", threadId);
+                pEvent->mods[idx].threadOnly.threadId = threadId;
+            }
+            break;
+        case MK_CLASS_ONLY:     /* for ClassPrepare, MethodEntry */
+            {
+                RefTypeId clazzId = dvmReadRefTypeId(&buf);
+                LOGVV("    ClassOnly: %llx (%s)",
+                    clazzId, dvmDbgGetClassDescriptor(clazzId));
+                pEvent->mods[idx].classOnly.refTypeId = clazzId;
+            }
+            break;
+        case MK_CLASS_MATCH:    /* restrict events to matching classes */
+            {
+                char* pattern;
+                size_t strLen;
+
+                pattern = readNewUtf8String(&buf, &strLen);
+                LOGVV("    ClassMatch: '%s'", pattern);
+                /* pattern is "java.foo.*", we want "java/foo/ *" */
+                pEvent->mods[idx].classMatch.classPattern =
+                    dvmDotToSlash(pattern);
+                free(pattern);
+            }
+            break;
+        case MK_CLASS_EXCLUDE:  /* restrict events to non-matching classes */
+            {
+                char* pattern;
+                size_t strLen;
+
+                pattern = readNewUtf8String(&buf, &strLen);
+                LOGVV("    ClassExclude: '%s'", pattern);
+                pEvent->mods[idx].classExclude.classPattern =
+                    dvmDotToSlash(pattern);
+                free(pattern);
+            }
+            break;
+        case MK_LOCATION_ONLY:  /* restrict certain events based on loc */
+            {
+                JdwpLocation loc;
+
+                jdwpReadLocation(&buf, &loc);
+                LOGVV("    LocationOnly: typeTag=%d classId=%llx methodId=%x idx=%llx",
+                    loc.typeTag, loc.classId, loc.methodId, loc.idx);
+                pEvent->mods[idx].locationOnly.loc = loc;
+            }
+            break;
+        case MK_EXCEPTION_ONLY: /* modifies EK_EXCEPTION events */
+            {
+                RefTypeId exceptionOrNull;      /* null == all exceptions */
+                u1 caught, uncaught;
+
+                exceptionOrNull = dvmReadRefTypeId(&buf);
+                caught = read1(&buf);
+                uncaught = read1(&buf);
+                LOGVV("    ExceptionOnly: type=%llx(%s) caught=%d uncaught=%d",
+                    exceptionOrNull, (exceptionOrNull == 0) ? "null"
+                        : dvmDbgGetClassDescriptor(exceptionOrNull),
+                    caught, uncaught);
+
+                pEvent->mods[idx].exceptionOnly.refTypeId = exceptionOrNull;
+                pEvent->mods[idx].exceptionOnly.caught = caught;
+                pEvent->mods[idx].exceptionOnly.uncaught = uncaught;
+            }
+            break;
+        case MK_FIELD_ONLY:     /* for field access/mod events */
+            {
+                RefTypeId declaring = dvmReadRefTypeId(&buf);
+                FieldId fieldId = dvmReadFieldId(&buf);
+                LOGVV("    FieldOnly: %llx %x", declaring, fieldId);
+                pEvent->mods[idx].fieldOnly.refTypeId = declaring;
+                pEvent->mods[idx].fieldOnly.fieldId = fieldId;
+            }
+            break;
+        case MK_STEP:           /* for use with EK_SINGLE_STEP */
+            {
+                ObjectId threadId;
+                u4 size, depth;
+
+                threadId = dvmReadObjectId(&buf);
+                size = read4BE(&buf);
+                depth = read4BE(&buf);
+                LOGVV("    Step: thread=%llx size=%s depth=%s",
+                    threadId, dvmJdwpStepSizeStr(size),
+                    dvmJdwpStepDepthStr(depth));
+
+                pEvent->mods[idx].step.threadId = threadId;
+                pEvent->mods[idx].step.size = size;
+                pEvent->mods[idx].step.depth = depth;
+            }
+            break;
+        case MK_INSTANCE_ONLY:  /* report events related to a specific obj */
+            {
+                ObjectId instance = dvmReadObjectId(&buf);
+                LOGVV("    InstanceOnly: %llx", instance);
+                pEvent->mods[idx].instanceOnly.objectId = instance;
+            }
+            break;
+        default:
+            LOGW("GLITCH: unsupported modKind=%d", modKind);
+            break;
+        }
+    }
+
+    /*
+     * Make sure we consumed all data.  It is possible that the remote side
+     * has sent us bad stuff, but for now we blame ourselves.
+     */
+    if (buf != origBuf + dataLen) {
+        LOGW("GLITCH: dataLen is %d, we have consumed %d", dataLen,
+            (int) (buf - origBuf));
+    }
+
+    /*
+     * We reply with an integer "requestID".
+     */
+    u4 requestId = dvmJdwpNextEventSerial(state);
+    expandBufAdd4BE(pReply, requestId);
+
+    pEvent->requestId = requestId;
+
+    LOGV("    --> event requestId=%#x", requestId);
+
+    /* add it to the list */
+    JdwpError err = dvmJdwpRegisterEvent(state, pEvent);
+    if (err != ERR_NONE) {
+        /* registration failed, probably because event is bogus */
+        dvmJdwpEventFree(pEvent);
+        LOGW("WARNING: event request rejected");
+    }
+    return err;
+}
+
+/*
+ * Clear an event.  Failure to find an event with a matching ID is a no-op
+ * and does not return an error.
+ */
+static JdwpError handleER_Clear(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    u1 eventKind;
+    eventKind = read1(&buf);
+    u4 requestId = read4BE(&buf);
+
+    LOGV("  Req to clear eventKind=%d requestId=%#x", eventKind, requestId);
+
+    dvmJdwpUnregisterEventById(state, requestId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the values of arguments and local variables.
+ */
+static JdwpError handleSF_GetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+    FrameId frameId = dvmReadFrameId(&buf);
+    u4 slots = read4BE(&buf);
+
+    LOGV("  Req for %d slots in threadId=%llx frameId=%llx",
+        slots, threadId, frameId);
+
+    expandBufAdd4BE(pReply, slots);     /* "int values" */
+    for (u4 i = 0; i < slots; i++) {
+        u4 slot = read4BE(&buf);
+        u1 reqSigByte = read1(&buf);
+
+        LOGV("    --> slot %d '%c'", slot, reqSigByte);
+
+        int width = dvmDbgGetTagWidth(reqSigByte);
+        u1* ptr = expandBufAddSpace(pReply, width+1);
+        dvmDbgGetLocalValue(threadId, frameId, slot, reqSigByte, ptr, width);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Set the values of arguments and local variables.
+ */
+static JdwpError handleSF_SetValues(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+    FrameId frameId = dvmReadFrameId(&buf);
+    u4 slots = read4BE(&buf);
+
+    LOGV("  Req to set %d slots in threadId=%llx frameId=%llx",
+        slots, threadId, frameId);
+
+    for (u4 i = 0; i < slots; i++) {
+        u4 slot = read4BE(&buf);
+        u1 sigByte = read1(&buf);
+        int width = dvmDbgGetTagWidth(sigByte);
+        u8 value = jdwpReadValue(&buf, width);
+
+        LOGV("    --> slot %d '%c' %llx", slot, sigByte, value);
+        dvmDbgSetLocalValue(threadId, frameId, slot, sigByte, value, width);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+ * Returns the value of "this" for the specified frame.
+ */
+static JdwpError handleSF_ThisObject(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    ObjectId threadId = dvmReadObjectId(&buf);
+    FrameId frameId = dvmReadFrameId(&buf);
+
+    ObjectId objectId;
+    if (!dvmDbgGetThisObject(threadId, frameId, &objectId))
+        return ERR_INVALID_FRAMEID;
+
+    u1 objectTag = dvmDbgGetObjectTag(objectId);
+    LOGV("  Req for 'this' in thread=%llx frame=%llx --> %llx %s '%c'",
+        threadId, frameId, objectId, dvmDbgGetObjectTypeName(objectId),
+        (char)objectTag);
+
+    expandBufAdd1(pReply, objectTag);
+    expandBufAddObjectId(pReply, objectId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Return the reference type reflected by this class object.
+ *
+ * This appears to be required because ReferenceTypeId values are NEVER
+ * reused, whereas ClassIds can be recycled like any other object.  (Either
+ * that, or I have no idea what this is for.)
+ */
+static JdwpError handleCOR_ReflectedType(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    RefTypeId classObjectId = dvmReadRefTypeId(&buf);
+
+    LOGV("  Req for refTypeId for class=%llx (%s)",
+        classObjectId, dvmDbgGetClassDescriptor(classObjectId));
+
+    /* just hand the type back to them */
+    if (dvmDbgIsInterface(classObjectId))
+        expandBufAdd1(pReply, TT_INTERFACE);
+    else
+        expandBufAdd1(pReply, TT_CLASS);
+    expandBufAddRefTypeId(pReply, classObjectId);
+
+    return ERR_NONE;
+}
+
+/*
+ * Handle a DDM packet with a single chunk in it.
+ */
+static JdwpError handleDDM_Chunk(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    u1* replyBuf = NULL;
+    int replyLen = -1;
+
+    LOGV("  Handling DDM packet (%.4s)", buf);
+
+    /*
+     * On first DDM packet, notify all handlers that DDM is running.
+     */
+    if (!state->ddmActive) {
+        state->ddmActive = true;
+        dvmDbgDdmConnected();
+    }
+
+    /*
+     * If they want to send something back, we copy it into the buffer.
+     * A no-copy approach would be nicer.
+     *
+     * TODO: consider altering the JDWP stuff to hold the packet header
+     * in a separate buffer.  That would allow us to writev() DDM traffic
+     * instead of copying it into the expanding buffer.  The reduction in
+     * heap requirements is probably more valuable than the efficiency.
+     */
+    if (dvmDbgDdmHandlePacket(buf, dataLen, &replyBuf, &replyLen)) {
+        assert(replyLen > 0 && replyLen < 1*1024*1024);
+        memcpy(expandBufAddSpace(pReply, replyLen), replyBuf, replyLen);
+        free(replyBuf);
+    }
+    return ERR_NONE;
+}
+
+/*
+ * Handler map decl.
+ */
+typedef JdwpError (*JdwpRequestHandler)(JdwpState* state,
+    const u1* buf, int dataLen, ExpandBuf* reply);
+
+struct JdwpHandlerMap {
+    u1  cmdSet;
+    u1  cmd;
+    JdwpRequestHandler  func;
+    const char* descr;
+};
+
+/*
+ * Map commands to functions.
+ *
+ * Command sets 0-63 are incoming requests, 64-127 are outbound requests,
+ * and 128-256 are vendor-defined.
+ */
+static const JdwpHandlerMap gHandlerMap[] = {
+    /* VirtualMachine command set (1) */
+    { 1,    1,  handleVM_Version,       "VirtualMachine.Version" },
+    { 1,    2,  handleVM_ClassesBySignature,
+                                        "VirtualMachine.ClassesBySignature" },
+    //1,    3,  VirtualMachine.AllClasses
+    { 1,    4,  handleVM_AllThreads,    "VirtualMachine.AllThreads" },
+    { 1,    5,  handleVM_TopLevelThreadGroups,
+                                        "VirtualMachine.TopLevelThreadGroups" },
+    { 1,    6,  handleVM_Dispose,       "VirtualMachine.Dispose" },
+    { 1,    7,  handleVM_IDSizes,       "VirtualMachine.IDSizes" },
+    { 1,    8,  handleVM_Suspend,       "VirtualMachine.Suspend" },
+    { 1,    9,  handleVM_Resume,        "VirtualMachine.Resume" },
+    { 1,    10, handleVM_Exit,          "VirtualMachine.Exit" },
+    { 1,    11, handleVM_CreateString,  "VirtualMachine.CreateString" },
+    { 1,    12, handleVM_Capabilities,  "VirtualMachine.Capabilities" },
+    { 1,    13, handleVM_ClassPaths,    "VirtualMachine.ClassPaths" },
+    { 1,    14, HandleVM_DisposeObjects, "VirtualMachine.DisposeObjects" },
+    //1,    15, HoldEvents
+    //1,    16, ReleaseEvents
+    { 1,    17, handleVM_CapabilitiesNew,
+                                        "VirtualMachine.CapabilitiesNew" },
+    //1,    18, RedefineClasses
+    //1,    19, SetDefaultStratum
+    { 1,    20, handleVM_AllClassesWithGeneric,
+                                        "VirtualMachine.AllClassesWithGeneric"},
+    //1,    21, InstanceCounts
+
+    /* ReferenceType command set (2) */
+    { 2,    1,  handleRT_Signature,     "ReferenceType.Signature" },
+    { 2,    2,  handleRT_ClassLoader,   "ReferenceType.ClassLoader" },
+    { 2,    3,  handleRT_Modifiers,     "ReferenceType.Modifiers" },
+    //2,    4,  Fields
+    //2,    5,  Methods
+    { 2,    6,  handleRT_GetValues,     "ReferenceType.GetValues" },
+    { 2,    7,  handleRT_SourceFile,    "ReferenceType.SourceFile" },
+    //2,    8,  NestedTypes
+    { 2,    9,  handleRT_Status,        "ReferenceType.Status" },
+    { 2,    10, handleRT_Interfaces,    "ReferenceType.Interfaces" },
+    { 2,    11, handleRT_ClassObject,   "ReferenceType.ClassObject" },
+    { 2,    12, handleRT_SourceDebugExtension,
+                                        "ReferenceType.SourceDebugExtension" },
+    { 2,    13, handleRT_SignatureWithGeneric,
+                                        "ReferenceType.SignatureWithGeneric" },
+    { 2,    14, handleRT_FieldsWithGeneric,
+                                        "ReferenceType.FieldsWithGeneric" },
+    { 2,    15, handleRT_MethodsWithGeneric,
+                                        "ReferenceType.MethodsWithGeneric" },
+    //2,    16, Instances
+    //2,    17, ClassFileVersion
+    //2,    18, ConstantPool
+
+    /* ClassType command set (3) */
+    { 3,    1,  handleCT_Superclass,    "ClassType.Superclass" },
+    { 3,    2,  handleCT_SetValues,     "ClassType.SetValues" },
+    { 3,    3,  handleCT_InvokeMethod,  "ClassType.InvokeMethod" },
+    { 3,    4,  handleCT_NewInstance,   "ClassType.NewInstance" },
+
+    /* ArrayType command set (4) */
+    { 4,    1,  handleAT_newInstance,   "ArrayType.NewInstance" },
+
+    /* InterfaceType command set (5) */
+
+    /* Method command set (6) */
+    { 6,    1,  handleM_LineTable,      "Method.LineTable" },
+    //6,    2,  VariableTable
+    //6,    3,  Bytecodes
+    //6,    4,  IsObsolete
+    { 6,    5,  handleM_VariableTableWithGeneric,
+                                        "Method.VariableTableWithGeneric" },
+
+    /* Field command set (8) */
+
+    /* ObjectReference command set (9) */
+    { 9,    1,  handleOR_ReferenceType, "ObjectReference.ReferenceType" },
+    { 9,    2,  handleOR_GetValues,     "ObjectReference.GetValues" },
+    { 9,    3,  handleOR_SetValues,     "ObjectReference.SetValues" },
+    //9,    4,  (not defined)
+    //9,    5,  MonitorInfo
+    { 9,    6,  handleOR_InvokeMethod,  "ObjectReference.InvokeMethod" },
+    { 9,    7,  handleOR_DisableCollection,
+                                        "ObjectReference.DisableCollection" },
+    { 9,    8,  handleOR_EnableCollection,
+                                        "ObjectReference.EnableCollection" },
+    { 9,    9,  handleOR_IsCollected,   "ObjectReference.IsCollected" },
+    //9,    10, ReferringObjects
+
+    /* StringReference command set (10) */
+    { 10,   1,  handleSR_Value,         "StringReference.Value" },
+
+    /* ThreadReference command set (11) */
+    { 11,   1,  handleTR_Name,          "ThreadReference.Name" },
+    { 11,   2,  handleTR_Suspend,       "ThreadReference.Suspend" },
+    { 11,   3,  handleTR_Resume,        "ThreadReference.Resume" },
+    { 11,   4,  handleTR_Status,        "ThreadReference.Status" },
+    { 11,   5,  handleTR_ThreadGroup,   "ThreadReference.ThreadGroup" },
+    { 11,   6,  handleTR_Frames,        "ThreadReference.Frames" },
+    { 11,   7,  handleTR_FrameCount,    "ThreadReference.FrameCount" },
+    //11,   8,  OwnedMonitors
+    { 11,   9,  handleTR_CurrentContendedMonitor,
+                                    "ThreadReference.CurrentContendedMonitor" },
+    //11,   10, Stop
+    //11,   11, Interrupt
+    { 11,   12, handleTR_SuspendCount,  "ThreadReference.SuspendCount" },
+    //11,   13, OwnedMonitorsStackDepthInfo
+    //11,   14, ForceEarlyReturn
+
+    /* ThreadGroupReference command set (12) */
+    { 12,   1,  handleTGR_Name,         "ThreadGroupReference.Name" },
+    { 12,   2,  handleTGR_Parent,       "ThreadGroupReference.Parent" },
+    { 12,   3,  handleTGR_Children,     "ThreadGroupReference.Children" },
+
+    /* ArrayReference command set (13) */
+    { 13,   1,  handleAR_Length,        "ArrayReference.Length" },
+    { 13,   2,  handleAR_GetValues,     "ArrayReference.GetValues" },
+    { 13,   3,  handleAR_SetValues,     "ArrayReference.SetValues" },
+
+    /* ClassLoaderReference command set (14) */
+    { 14,   1,  handleCLR_VisibleClasses,
+                                        "ClassLoaderReference.VisibleClasses" },
+
+    /* EventRequest command set (15) */
+    { 15,   1,  handleER_Set,           "EventRequest.Set" },
+    { 15,   2,  handleER_Clear,         "EventRequest.Clear" },
+    //15,   3,  ClearAllBreakpoints
+
+    /* StackFrame command set (16) */
+    { 16,   1,  handleSF_GetValues,     "StackFrame.GetValues" },
+    { 16,   2,  handleSF_SetValues,     "StackFrame.SetValues" },
+    { 16,   3,  handleSF_ThisObject,    "StackFrame.ThisObject" },
+    //16,   4,  PopFrames
+
+    /* ClassObjectReference command set (17) */
+    { 17,   1,  handleCOR_ReflectedType,"ClassObjectReference.ReflectedType" },
+
+    /* Event command set (64) */
+    //64,  100, Composite   <-- sent from VM to debugger, never received by VM
+
+    { 199,  1,  handleDDM_Chunk,        "DDM.Chunk" },
+};
+
+
+/*
+ * Process a request from the debugger.
+ *
+ * On entry, the JDWP thread is in VMWAIT.
+ */
+void dvmJdwpProcessRequest(JdwpState* state, const JdwpReqHeader* pHeader,
+    const u1* buf, int dataLen, ExpandBuf* pReply)
+{
+    JdwpError result = ERR_NONE;
+    int i, respLen;
+
+    if (pHeader->cmdSet != kJDWPDdmCmdSet) {
+        /*
+         * Activity from a debugger, not merely ddms.  Mark us as having an
+         * active debugger session, and zero out the last-activity timestamp
+         * so waitForDebugger() doesn't return if we stall for a bit here.
+         */
+        dvmDbgActive();
+        dvmQuasiAtomicSwap64(0, &state->lastActivityWhen);
+    }
+
+    /*
+     * If a debugger event has fired in another thread, wait until the
+     * initiating thread has suspended itself before processing messages
+     * from the debugger.  Otherwise we (the JDWP thread) could be told to
+     * resume the thread before it has suspended.
+     *
+     * We call with an argument of zero to wait for the current event
+     * thread to finish, and then clear the block.  Depending on the thread
+     * suspend policy, this may allow events in other threads to fire,
+     * but those events have no bearing on what the debugger has sent us
+     * in the current request.
+     *
+     * Note that we MUST clear the event token before waking the event
+     * thread up, or risk waiting for the thread to suspend after we've
+     * told it to resume.
+     */
+    dvmJdwpSetWaitForEventThread(state, 0);
+
+    /*
+     * Tell the VM that we're running and shouldn't be interrupted by GC.
+     * Do this after anything that can stall indefinitely.
+     */
+    dvmDbgThreadRunning();
+
+    expandBufAddSpace(pReply, kJDWPHeaderLen);
+
+    for (i = 0; i < (int) NELEM(gHandlerMap); i++) {
+        if (gHandlerMap[i].cmdSet == pHeader->cmdSet &&
+            gHandlerMap[i].cmd == pHeader->cmd)
+        {
+            LOGV("REQ: %s (cmd=%d/%d dataLen=%d id=0x%06x)",
+                gHandlerMap[i].descr, pHeader->cmdSet, pHeader->cmd,
+                dataLen, pHeader->id);
+            result = (*gHandlerMap[i].func)(state, buf, dataLen, pReply);
+            break;
+        }
+    }
+    if (i == NELEM(gHandlerMap)) {
+        LOGE("REQ: UNSUPPORTED (cmd=%d/%d dataLen=%d id=0x%06x)",
+            pHeader->cmdSet, pHeader->cmd, dataLen, pHeader->id);
+        if (dataLen > 0)
+            dvmPrintHexDumpDbg(buf, dataLen, LOG_TAG);
+        assert(!"command not implemented");      // make it *really* obvious
+        result = ERR_NOT_IMPLEMENTED;
+    }
+
+    /*
+     * Set up the reply header.
+     *
+     * If we encountered an error, only send the header back.
+     */
+    u1* replyBuf = expandBufGetBuffer(pReply);
+    set4BE(replyBuf + 4, pHeader->id);
+    set1(replyBuf + 8, kJDWPFlagReply);
+    set2BE(replyBuf + 9, result);
+    if (result == ERR_NONE)
+        set4BE(replyBuf + 0, expandBufGetLength(pReply));
+    else
+        set4BE(replyBuf + 0, kJDWPHeaderLen);
+
+    respLen = expandBufGetLength(pReply) - kJDWPHeaderLen;
+    IF_LOG(LOG_VERBOSE, LOG_TAG) {
+        LOGV("reply: dataLen=%d err=%s(%d)%s", respLen,
+            dvmJdwpErrorStr(result), result,
+            result != ERR_NONE ? " **FAILED**" : "");
+        if (respLen > 0)
+            dvmPrintHexDumpDbg(expandBufGetBuffer(pReply) + kJDWPHeaderLen,
+                respLen, LOG_TAG);
+    }
+
+    /*
+     * Update last-activity timestamp.  We really only need this during
+     * the initial setup.  Only update if this is a non-DDMS packet.
+     */
+    if (pHeader->cmdSet != kJDWPDdmCmdSet) {
+        dvmQuasiAtomicSwap64(dvmJdwpGetNowMsec(), &state->lastActivityWhen);
+    }
+
+    /* tell the VM that GC is okay again */
+    dvmDbgThreadWaiting();
+}
diff --git a/vm/jdwp/JdwpHandler.h b/vm/jdwp/JdwpHandler.h
new file mode 100644
index 0000000..6381270
--- /dev/null
+++ b/vm/jdwp/JdwpHandler.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+/*
+ * Handle requests.
+ */
+#ifndef DALVIK_JDWP_JDWPHANDLER_H_
+#define DALVIK_JDWP_JDWPHANDLER_H_
+
+#include "Common.h"
+#include "ExpandBuf.h"
+
+/*
+ * JDWP message header for a request.
+ */
+struct JdwpReqHeader {
+    u4  length;
+    u4  id;
+    u1  cmdSet;
+    u1  cmd;
+};
+
+/*
+ * Process a request from the debugger.
+ *
+ * "buf" points past the header, to the content of the message.  "dataLen"
+ * can therefore be zero.
+ */
+void dvmJdwpProcessRequest(JdwpState* state, const JdwpReqHeader* pHeader,
+    const u1* buf, int dataLen, ExpandBuf* pReply);
+
+/* helper function */
+void dvmJdwpAddLocation(ExpandBuf* pReply, const JdwpLocation* pLoc);
+
+#endif  // DALVIK_JDWP_JDWPHANDLER_H_
diff --git a/vm/jdwp/JdwpMain.cpp b/vm/jdwp/JdwpMain.cpp
new file mode 100644
index 0000000..fb1e23d
--- /dev/null
+++ b/vm/jdwp/JdwpMain.cpp
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+/*
+ * JDWP initialization.
+ */
+#include "jdwp/JdwpPriv.h"
+#include "Dalvik.h"
+#include "Atomic.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+
+static void* jdwpThreadStart(void* arg);
+
+/*
+ * JdwpNetStateBase class implementation
+ */
+JdwpNetStateBase::JdwpNetStateBase()
+{
+    clientSock = -1;
+    dvmDbgInitMutex(&socketLock);
+}
+
+/*
+ * Write a packet. Grabs a mutex to assure atomicity.
+ */
+ssize_t JdwpNetStateBase::writePacket(ExpandBuf* pReply)
+{
+    dvmDbgLockMutex(&socketLock);
+    ssize_t cc = write(clientSock, expandBufGetBuffer(pReply),
+            expandBufGetLength(pReply));
+    dvmDbgUnlockMutex(&socketLock);
+
+    return cc;
+}
+
+/*
+ * Write a buffered packet. Grabs a mutex to assure atomicity.
+ */
+ssize_t JdwpNetStateBase::writeBufferedPacket(const struct iovec* iov,
+    int iovcnt)
+{
+    dvmDbgLockMutex(&socketLock);
+    ssize_t actual = writev(clientSock, iov, iovcnt);
+    dvmDbgUnlockMutex(&socketLock);
+
+    return actual;
+}
+
+/*
+ * Initialize JDWP.
+ *
+ * Does not return until JDWP thread is running, but may return before
+ * the thread is accepting network connections.
+ */
+JdwpState* dvmJdwpStartup(const JdwpStartupParams* pParams)
+{
+    JdwpState* state = NULL;
+
+    /* comment this out when debugging JDWP itself */
+    android_setMinPriority(LOG_TAG, ANDROID_LOG_DEBUG);
+
+    state = (JdwpState*) calloc(1, sizeof(JdwpState));
+
+    state->params = *pParams;
+
+    state->requestSerial = 0x10000000;
+    state->eventSerial = 0x20000000;
+    dvmDbgInitMutex(&state->threadStartLock);
+    dvmDbgInitMutex(&state->attachLock);
+    dvmDbgInitMutex(&state->serialLock);
+    dvmDbgInitMutex(&state->eventLock);
+    state->eventThreadId = 0;
+    dvmDbgInitMutex(&state->eventThreadLock);
+    dvmDbgInitCond(&state->threadStartCond);
+    dvmDbgInitCond(&state->attachCond);
+    dvmDbgInitCond(&state->eventThreadCond);
+
+    switch (pParams->transport) {
+    case kJdwpTransportSocket:
+        // LOGD("prepping for JDWP over TCP");
+        state->transport = dvmJdwpSocketTransport();
+        break;
+    case kJdwpTransportAndroidAdb:
+        // LOGD("prepping for JDWP over ADB");
+        state->transport = dvmJdwpAndroidAdbTransport();
+        /* TODO */
+        break;
+    default:
+        LOGE("Unknown transport %d", pParams->transport);
+        assert(false);
+        goto fail;
+    }
+
+    if (!dvmJdwpNetStartup(state, pParams))
+        goto fail;
+
+    /*
+     * Grab a mutex or two before starting the thread.  This ensures they
+     * won't signal the cond var before we're waiting.
+     */
+    dvmDbgLockMutex(&state->threadStartLock);
+    if (pParams->suspend)
+        dvmDbgLockMutex(&state->attachLock);
+
+    /*
+     * We have bound to a port, or are trying to connect outbound to a
+     * debugger.  Create the JDWP thread and let it continue the mission.
+     */
+    if (!dvmCreateInternalThread(&state->debugThreadHandle, "JDWP",
+            jdwpThreadStart, state))
+    {
+        /* state is getting tossed, but unlock these anyway for cleanliness */
+        dvmDbgUnlockMutex(&state->threadStartLock);
+        if (pParams->suspend)
+            dvmDbgUnlockMutex(&state->attachLock);
+        goto fail;
+    }
+
+    /*
+     * Wait until the thread finishes basic initialization.
+     * TODO: cond vars should be waited upon in a loop
+     */
+    dvmDbgCondWait(&state->threadStartCond, &state->threadStartLock);
+    dvmDbgUnlockMutex(&state->threadStartLock);
+
+
+    /*
+     * For suspend=y, wait for the debugger to connect to us or for us to
+     * connect to the debugger.
+     *
+     * The JDWP thread will signal us when it connects successfully or
+     * times out (for timeout=xxx), so we have to check to see what happened
+     * when we wake up.
+     */
+    if (pParams->suspend) {
+        dvmChangeStatus(NULL, THREAD_VMWAIT);
+        dvmDbgCondWait(&state->attachCond, &state->attachLock);
+        dvmDbgUnlockMutex(&state->attachLock);
+        dvmChangeStatus(NULL, THREAD_RUNNING);
+
+        if (!dvmJdwpIsActive(state)) {
+            LOGE("JDWP connection failed");
+            goto fail;
+        }
+
+        LOGI("JDWP connected");
+
+        /*
+         * Ordinarily we would pause briefly to allow the debugger to set
+         * breakpoints and so on, but for "suspend=y" the VM init code will
+         * pause the VM when it sends the VM_START message.
+         */
+    }
+
+    return state;
+
+fail:
+    dvmJdwpShutdown(state);     // frees state
+    return NULL;
+}
+
+/*
+ * Reset all session-related state.  There should not be an active connection
+ * to the client at this point.  The rest of the VM still thinks there is
+ * a debugger attached.
+ *
+ * This includes freeing up the debugger event list.
+ */
+void dvmJdwpResetState(JdwpState* state)
+{
+    /* could reset the serial numbers, but no need to */
+
+    dvmJdwpUnregisterAll(state);
+    assert(state->eventList == NULL);
+
+    /*
+     * Should not have one of these in progress.  If the debugger went away
+     * mid-request, though, we could see this.
+     */
+    if (state->eventThreadId != 0) {
+        LOGW("WARNING: resetting state while event in progress");
+        assert(false);
+    }
+}
+
+/*
+ * Tell the JDWP thread to shut down.  Frees "state".
+ */
+void dvmJdwpShutdown(JdwpState* state)
+{
+    void* threadReturn;
+
+    if (state == NULL)
+        return;
+
+    if (dvmJdwpIsTransportDefined(state)) {
+        if (dvmJdwpIsConnected(state))
+            dvmJdwpPostVMDeath(state);
+
+        /*
+         * Close down the network to inspire the thread to halt.
+         */
+        if (gDvm.verboseShutdown)
+            LOGD("JDWP shutting down net...");
+        dvmJdwpNetShutdown(state);
+
+        if (state->debugThreadStarted) {
+            state->run = false;
+            if (pthread_join(state->debugThreadHandle, &threadReturn) != 0) {
+                LOGW("JDWP thread join failed");
+            }
+        }
+
+        if (gDvm.verboseShutdown)
+            LOGD("JDWP freeing netstate...");
+        dvmJdwpNetFree(state);
+        state->netState = NULL;
+    }
+    assert(state->netState == NULL);
+
+    dvmJdwpResetState(state);
+    free(state);
+}
+
+/*
+ * Are we talking to a debugger?
+ */
+bool dvmJdwpIsActive(JdwpState* state)
+{
+    return dvmJdwpIsConnected(state);
+}
+
+/*
+ * Entry point for JDWP thread.  The thread was created through the VM
+ * mechanisms, so there is a java/lang/Thread associated with us.
+ */
+static void* jdwpThreadStart(void* arg)
+{
+    JdwpState* state = (JdwpState*) arg;
+
+    LOGV("JDWP: thread running");
+
+    /*
+     * Finish initializing "state", then notify the creating thread that
+     * we're running.
+     */
+    state->debugThreadHandle = dvmThreadSelf()->handle;
+    state->run = true;
+    android_atomic_release_store(true, &state->debugThreadStarted);
+
+    dvmDbgLockMutex(&state->threadStartLock);
+    dvmDbgCondBroadcast(&state->threadStartCond);
+    dvmDbgUnlockMutex(&state->threadStartLock);
+
+    /* set the thread state to VMWAIT so GCs don't wait for us */
+    dvmDbgThreadWaiting();
+
+    /*
+     * Loop forever if we're in server mode, processing connections.  In
+     * non-server mode, we bail out of the thread when the debugger drops
+     * us.
+     *
+     * We broadcast a notification when a debugger attaches, after we
+     * successfully process the handshake.
+     */
+    while (state->run) {
+        bool first;
+
+        if (state->params.server) {
+            /*
+             * Block forever, waiting for a connection.  To support the
+             * "timeout=xxx" option we'll need to tweak this.
+             */
+            if (!dvmJdwpAcceptConnection(state))
+                break;
+        } else {
+            /*
+             * If we're not acting as a server, we need to connect out to the
+             * debugger.  To support the "timeout=xxx" option we need to
+             * have a timeout if the handshake reply isn't received in a
+             * reasonable amount of time.
+             */
+            if (!dvmJdwpEstablishConnection(state)) {
+                /* wake anybody who was waiting for us to succeed */
+                dvmDbgLockMutex(&state->attachLock);
+                dvmDbgCondBroadcast(&state->attachCond);
+                dvmDbgUnlockMutex(&state->attachLock);
+                break;
+            }
+        }
+
+        /* prep debug code to handle the new connection */
+        dvmDbgConnected();
+
+        /* process requests until the debugger drops */
+        first = true;
+        while (true) {
+            // sanity check -- shouldn't happen?
+            if (dvmThreadSelf()->status != THREAD_VMWAIT) {
+                LOGE("JDWP thread no longer in VMWAIT (now %d); resetting",
+                    dvmThreadSelf()->status);
+                dvmDbgThreadWaiting();
+            }
+
+            if (!dvmJdwpProcessIncoming(state))     /* blocking read */
+                break;
+
+            if (first && !dvmJdwpAwaitingHandshake(state)) {
+                /* handshake worked, tell the interpreter that we're active */
+                first = false;
+
+                /* set thread ID; requires object registry to be active */
+                state->debugThreadId = dvmDbgGetThreadSelfId();
+
+                /* wake anybody who's waiting for us */
+                dvmDbgLockMutex(&state->attachLock);
+                dvmDbgCondBroadcast(&state->attachCond);
+                dvmDbgUnlockMutex(&state->attachLock);
+            }
+        }
+
+        dvmJdwpCloseConnection(state);
+
+        if (state->ddmActive) {
+            state->ddmActive = false;
+
+            /* broadcast the disconnect; must be in RUNNING state */
+            dvmDbgThreadRunning();
+            dvmDbgDdmDisconnected();
+            dvmDbgThreadWaiting();
+        }
+
+        /* release session state, e.g. remove breakpoint instructions */
+        dvmJdwpResetState(state);
+
+        /* tell the interpreter that the debugger is no longer around */
+        dvmDbgDisconnected();
+
+        /* if we had threads suspended, resume them now */
+        dvmUndoDebuggerSuspensions();
+
+        /* if we connected out, this was a one-shot deal */
+        if (!state->params.server)
+            state->run = false;
+    }
+
+    /* back to running, for thread shutdown */
+    dvmDbgThreadRunning();
+
+    LOGV("JDWP: thread exiting");
+    return NULL;
+}
+
+
+/*
+ * Return the thread handle, or (pthread_t)0 if the debugger isn't running.
+ */
+pthread_t dvmJdwpGetDebugThread(JdwpState* state)
+{
+    if (state == NULL)
+        return 0;
+
+    return state->debugThreadHandle;
+}
+
+
+/*
+ * Support routines for waitForDebugger().
+ *
+ * We can't have a trivial "waitForDebugger" function that returns the
+ * instant the debugger connects, because we run the risk of executing code
+ * before the debugger has had a chance to configure breakpoints or issue
+ * suspend calls.  It would be nice to just sit in the suspended state, but
+ * most debuggers don't expect any threads to be suspended when they attach.
+ *
+ * There's no JDWP event we can post to tell the debugger, "we've stopped,
+ * and we like it that way".  We could send a fake breakpoint, which should
+ * cause the debugger to immediately send a resume, but the debugger might
+ * send the resume immediately or might throw an exception of its own upon
+ * receiving a breakpoint event that it didn't ask for.
+ *
+ * What we really want is a "wait until the debugger is done configuring
+ * stuff" event.  We can approximate this with a "wait until the debugger
+ * has been idle for a brief period".
+ */
+
+/*
+ * Get a notion of the current time, in milliseconds.
+ */
+s8 dvmJdwpGetNowMsec()
+{
+#ifdef HAVE_POSIX_CLOCKS
+    struct timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
+#else
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
+#endif
+}
+
+/*
+ * Return the time, in milliseconds, since the last debugger activity.
+ *
+ * Returns -1 if no debugger is attached, or 0 if we're in the middle of
+ * processing a debugger request.
+ */
+s8 dvmJdwpLastDebuggerActivity(JdwpState* state)
+{
+    if (!gDvm.debuggerActive) {
+        LOGD("dvmJdwpLastDebuggerActivity: no active debugger");
+        return -1;
+    }
+
+    s8 last = dvmQuasiAtomicRead64(&state->lastActivityWhen);
+
+    /* initializing or in the middle of something? */
+    if (last == 0) {
+        LOGV("+++ last=busy");
+        return 0;
+    }
+
+    /* now get the current time */
+    s8 now = dvmJdwpGetNowMsec();
+    assert(now > last);
+
+    LOGV("+++ debugger interval=%lld", now - last);
+    return now - last;
+}
diff --git a/vm/jdwp/JdwpPriv.h b/vm/jdwp/JdwpPriv.h
new file mode 100644
index 0000000..67a953f
--- /dev/null
+++ b/vm/jdwp/JdwpPriv.h
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+/*
+ * JDWP internal interfaces.
+ */
+#ifndef DALVIK_JDWP_JDWPPRIV_H_
+#define DALVIK_JDWP_JDWPPRIV_H_
+
+#define LOG_TAG "jdwp"
+
+#include "jdwp/Jdwp.h"
+#include "jdwp/JdwpEvent.h"
+#include "Debugger.h"
+
+#include <pthread.h>
+#include <sys/uio.h>
+
+/*
+ * JDWP constants.
+ */
+#define kJDWPHeaderLen  11
+#define kJDWPFlagReply  0x80
+
+/* DDM support */
+#define kJDWPDdmCmdSet  199     /* 0xc7, or 'G'+128 */
+#define kJDWPDdmCmd     1
+
+
+/*
+ * Transport-specific network status.
+ */
+struct JdwpNetState;
+struct JdwpState;
+
+/*
+ * Transport functions.
+ */
+struct JdwpTransport {
+    bool (*startup)(struct JdwpState* state, const JdwpStartupParams* pParams);
+    bool (*accept)(struct JdwpState* state);
+    bool (*establish)(struct JdwpState* state);
+    void (*close)(struct JdwpState* state);
+    void (*shutdown)(struct JdwpState* state);
+    void (*free)(struct JdwpState* state);
+    bool (*isConnected)(struct JdwpState* state);
+    bool (*awaitingHandshake)(struct JdwpState* state);
+    bool (*processIncoming)(struct JdwpState* state);
+    bool (*sendRequest)(struct JdwpState* state, ExpandBuf* pReq);
+    bool (*sendBufferedRequest)(struct JdwpState* state,
+        const struct iovec* iov, int iovcnt);
+};
+
+const JdwpTransport* dvmJdwpSocketTransport();
+const JdwpTransport* dvmJdwpAndroidAdbTransport();
+
+
+/*
+ * State for JDWP functions.
+ */
+struct JdwpState {
+    JdwpStartupParams   params;
+
+    /* wait for creation of the JDWP thread */
+    pthread_mutex_t threadStartLock;
+    pthread_cond_t  threadStartCond;
+
+    int             debugThreadStarted;
+    pthread_t       debugThreadHandle;
+    ObjectId        debugThreadId;
+    bool            run;
+
+    const JdwpTransport*    transport;
+    JdwpNetState*   netState;
+
+    /* for wait-for-debugger */
+    pthread_mutex_t attachLock;
+    pthread_cond_t  attachCond;
+
+    /* time of last debugger activity, in milliseconds */
+    s8              lastActivityWhen;
+
+    /* global counters and a mutex to protect them */
+    u4              requestSerial;
+    u4              eventSerial;
+    pthread_mutex_t serialLock;
+
+    /*
+     * Events requested by the debugger (breakpoints, class prep, etc).
+     */
+    int             numEvents;      /* #of elements in eventList */
+    JdwpEvent*      eventList;      /* linked list of events */
+    pthread_mutex_t eventLock;      /* guards numEvents/eventList */
+
+    /*
+     * Synchronize suspension of event thread (to avoid receiving "resume"
+     * events before the thread has finished suspending itself).
+     */
+    pthread_mutex_t eventThreadLock;
+    pthread_cond_t  eventThreadCond;
+    ObjectId        eventThreadId;
+
+    /*
+     * DDM support.
+     */
+    bool            ddmActive;
+};
+
+/*
+ * Base class for JdwpNetState
+ */
+class JdwpNetStateBase {
+public:
+    int             clientSock;     /* active connection to debugger */
+
+    JdwpNetStateBase();
+    ssize_t writePacket(ExpandBuf* pReply);
+    ssize_t writeBufferedPacket(const struct iovec* iov, int iovcnt);
+
+private:
+    pthread_mutex_t socketLock;     /* socket synchronization */
+};
+
+
+/* reset all session-specific data */
+void dvmJdwpResetState(JdwpState* state);
+
+/* atomic ops to get next serial number */
+u4 dvmJdwpNextRequestSerial(JdwpState* state);
+u4 dvmJdwpNextEventSerial(JdwpState* state);
+
+/* get current time, in msec */
+s8 dvmJdwpGetNowMsec(void);
+
+
+/*
+ * Transport functions.
+ */
+INLINE bool dvmJdwpNetStartup(JdwpState* state,
+    const JdwpStartupParams* pParams)
+{
+    return (*state->transport->startup)(state, pParams);
+}
+INLINE bool dvmJdwpAcceptConnection(JdwpState* state) {
+    return (*state->transport->accept)(state);
+}
+INLINE bool dvmJdwpEstablishConnection(JdwpState* state) {
+    return (*state->transport->establish)(state);
+}
+INLINE void dvmJdwpCloseConnection(JdwpState* state) {
+    (*state->transport->close)(state);
+}
+INLINE void dvmJdwpNetShutdown(JdwpState* state) {
+    (*state->transport->shutdown)(state);
+}
+INLINE void dvmJdwpNetFree(JdwpState* state) {
+    (*state->transport->free)(state);
+}
+INLINE bool dvmJdwpIsTransportDefined(JdwpState* state) {
+    return state != NULL && state->transport != NULL;
+}
+INLINE bool dvmJdwpIsConnected(JdwpState* state) {
+    return state != NULL && (*state->transport->isConnected)(state);
+}
+INLINE bool dvmJdwpAwaitingHandshake(JdwpState* state) {
+    return (*state->transport->awaitingHandshake)(state);
+}
+INLINE bool dvmJdwpProcessIncoming(JdwpState* state) {
+    return (*state->transport->processIncoming)(state);
+}
+INLINE bool dvmJdwpSendRequest(JdwpState* state, ExpandBuf* pReq) {
+    return (*state->transport->sendRequest)(state, pReq);
+}
+INLINE bool dvmJdwpSendBufferedRequest(JdwpState* state,
+    const struct iovec* iov, int iovcnt)
+{
+    return (*state->transport->sendBufferedRequest)(state, iov, iovcnt);
+}
+
+#endif  // DALVIK_JDWP_JDWPPRIV_H_
diff --git a/vm/jdwp/JdwpSocket.cpp b/vm/jdwp/JdwpSocket.cpp
new file mode 100644
index 0000000..cb4ac34
--- /dev/null
+++ b/vm/jdwp/JdwpSocket.cpp
@@ -0,0 +1,910 @@
+/*
+ * 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.
+ */
+/*
+ * JDWP TCP socket network code.
+ */
+#include "jdwp/JdwpPriv.h"
+#include "jdwp/JdwpHandler.h"
+#include "Bits.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#define kBasePort           8000
+#define kMaxPort            8040
+
+#define kInputBufferSize    8192
+
+#define kMagicHandshake     "JDWP-Handshake"
+#define kMagicHandshakeLen  (sizeof(kMagicHandshake)-1)
+
+// fwd
+static void netShutdown(JdwpNetState* state);
+static void netFree(JdwpNetState* state);
+
+
+/*
+ * JDWP network state.
+ *
+ * We only talk to one debugger at a time.
+ */
+struct JdwpNetState : public JdwpNetStateBase {
+    short   listenPort;
+    int     listenSock;         /* listen for connection from debugger */
+    int     wakePipe[2];        /* break out of select */
+
+    struct in_addr remoteAddr;
+    unsigned short remotePort;
+
+    bool    awaitingHandshake;  /* waiting for "JDWP-Handshake" */
+
+    /* pending data from the network; would be more efficient as circular buf */
+    unsigned char  inputBuffer[kInputBufferSize];
+    int     inputCount;
+
+    JdwpNetState()
+    {
+        listenPort  = 0;
+        listenSock  = -1;
+        wakePipe[0] = -1;
+        wakePipe[1] = -1;
+
+        awaitingHandshake = false;
+
+        inputCount = 0;
+    }
+};
+
+static JdwpNetState* netStartup(short port);
+
+/*
+ * Set up some stuff for transport=dt_socket.
+ */
+static bool prepareSocket(JdwpState* state, const JdwpStartupParams* pParams)
+{
+    unsigned short port;
+
+    if (pParams->server) {
+        if (pParams->port != 0) {
+            /* try only the specified port */
+            port = pParams->port;
+            state->netState = netStartup(port);
+        } else {
+            /* scan through a range of ports, binding to the first available */
+            for (port = kBasePort; port <= kMaxPort; port++) {
+                state->netState = netStartup(port);
+                if (state->netState != NULL)
+                    break;
+            }
+        }
+        if (state->netState == NULL) {
+            LOGE("JDWP net startup failed (req port=%d)", pParams->port);
+            return false;
+        }
+    } else {
+        port = pParams->port;   // used in a debug msg later
+        state->netState = netStartup(-1);
+    }
+
+    if (pParams->suspend)
+        LOGI("JDWP will wait for debugger on port %d", port);
+    else
+        LOGD("JDWP will %s on port %d",
+            pParams->server ? "listen" : "connect", port);
+
+    return true;
+}
+
+
+/*
+ * Are we still waiting for the handshake string?
+ */
+static bool awaitingHandshake(JdwpState* state)
+{
+    return state->netState->awaitingHandshake;
+}
+
+/*
+ * Initialize JDWP stuff.
+ *
+ * Allocates a new state structure.  If "port" is non-negative, this also
+ * tries to bind to a listen port.  If "port" is less than zero, we assume
+ * we're preparing for an outbound connection, and return without binding
+ * to anything.
+ *
+ * This may be called several times if we're probing for a port.
+ *
+ * Returns 0 on success.
+ */
+static JdwpNetState* netStartup(short port)
+{
+    int one = 1;
+    JdwpNetState* netState = new JdwpNetState;
+
+    if (port < 0)
+        return netState;
+
+    assert(port != 0);
+
+    netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (netState->listenSock < 0) {
+        LOGE("Socket create failed: %s", strerror(errno));
+        goto fail;
+    }
+
+    /* allow immediate re-use */
+    if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one,
+            sizeof(one)) < 0)
+    {
+        LOGE("setsockopt(SO_REUSEADDR) failed: %s", strerror(errno));
+        goto fail;
+    }
+
+    union {
+        struct sockaddr_in  addrInet;
+        struct sockaddr     addrPlain;
+    } addr;
+    addr.addrInet.sin_family = AF_INET;
+    addr.addrInet.sin_port = htons(port);
+    inet_aton("127.0.0.1", &addr.addrInet.sin_addr);
+
+    if (bind(netState->listenSock, &addr.addrPlain, sizeof(addr)) != 0) {
+        LOGV("attempt to bind to port %u failed: %s", port, strerror(errno));
+        goto fail;
+    }
+
+    netState->listenPort = port;
+    LOGVV("+++ bound to port %d", netState->listenPort);
+
+    if (listen(netState->listenSock, 5) != 0) {
+        LOGE("Listen failed: %s", strerror(errno));
+        goto fail;
+    }
+
+    return netState;
+
+fail:
+    netShutdown(netState);
+    netFree(netState);
+    return NULL;
+}
+
+/*
+ * Shut down JDWP listener.  Don't free state.
+ *
+ * Note that "netState" may be partially initialized if "startup" failed.
+ *
+ * This may be called from a non-JDWP thread as part of shutting the
+ * JDWP thread down.
+ *
+ * (This is currently called several times during startup as we probe
+ * for an open port.)
+ */
+static void netShutdown(JdwpNetState* netState)
+{
+    if (netState == NULL)
+        return;
+
+    int listenSock = netState->listenSock;
+    int clientSock = netState->clientSock;
+
+    /* clear these out so it doesn't wake up and try to reuse them */
+    netState->listenSock = netState->clientSock = -1;
+
+    /* "shutdown" dislodges blocking read() and accept() calls */
+    if (listenSock >= 0) {
+        shutdown(listenSock, SHUT_RDWR);
+        close(listenSock);
+    }
+    if (clientSock >= 0) {
+        shutdown(clientSock, SHUT_RDWR);
+        close(clientSock);
+    }
+
+    /* if we might be sitting in select, kick us loose */
+    if (netState->wakePipe[1] >= 0) {
+        LOGV("+++ writing to wakePipe");
+        (void) write(netState->wakePipe[1], "", 1);
+    }
+}
+static void netShutdownExtern(JdwpState* state)
+{
+    netShutdown(state->netState);
+}
+
+/*
+ * Free JDWP state.
+ *
+ * Call this after shutting the network down with netShutdown().
+ */
+static void netFree(JdwpNetState* netState)
+{
+    if (netState == NULL)
+        return;
+    assert(netState->listenSock == -1);
+    assert(netState->clientSock == -1);
+
+    if (netState->wakePipe[0] >= 0) {
+        close(netState->wakePipe[0]);
+        netState->wakePipe[0] = -1;
+    }
+    if (netState->wakePipe[1] >= 0) {
+        close(netState->wakePipe[1]);
+        netState->wakePipe[1] = -1;
+    }
+
+    delete netState;
+}
+static void netFreeExtern(JdwpState* state)
+{
+    netFree(state->netState);
+}
+
+/*
+ * Returns "true" if we're connected to a debugger.
+ */
+static bool isConnected(JdwpState* state)
+{
+    return (state->netState != NULL &&
+            state->netState->clientSock >= 0);
+}
+
+/*
+ * Returns "true" if the fd is ready, "false" if not.
+ */
+#if 0
+static bool isFdReadable(int sock)
+{
+    fd_set readfds;
+    struct timeval tv;
+    int count;
+
+    FD_ZERO(&readfds);
+    FD_SET(sock, &readfds);
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    count = select(sock+1, &readfds, NULL, NULL, &tv);
+    if (count <= 0)
+        return false;
+
+    if (FD_ISSET(sock, &readfds))   /* make sure it's our fd */
+        return true;
+
+    LOGE("WEIRD: odd behavior in select (count=%d)", count);
+    return false;
+}
+#endif
+
+#if 0
+/*
+ * Check to see if we have a pending connection from the debugger.
+ *
+ * Returns true on success (meaning a connection is available).
+ */
+static bool checkConnection(JdwpState* state)
+{
+    JdwpNetState* netState = state->netState;
+
+    assert(netState->listenSock >= 0);
+    /* not expecting to be called when debugger is actively connected */
+    assert(netState->clientSock < 0);
+
+    if (!isFdReadable(netState->listenSock))
+        return false;
+    return true;
+}
+#endif
+
+/*
+ * Disable the TCP Nagle algorithm, which delays transmission of outbound
+ * packets until the previous transmissions have been acked.  JDWP does a
+ * lot of back-and-forth with small packets, so this may help.
+ */
+static int setNoDelay(int fd)
+{
+    int cc, on = 1;
+
+    cc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+    assert(cc == 0);
+    return cc;
+}
+
+/*
+ * Accept a connection.  This will block waiting for somebody to show up.
+ * If that's not desirable, use checkConnection() to make sure something
+ * is pending.
+ */
+static bool acceptConnection(JdwpState* state)
+{
+    JdwpNetState* netState = state->netState;
+    union {
+        struct sockaddr_in  addrInet;
+        struct sockaddr     addrPlain;
+    } addr;
+    socklen_t addrlen;
+    int sock;
+
+    if (netState->listenSock < 0)
+        return false;       /* you're not listening! */
+
+    assert(netState->clientSock < 0);      /* must not already be talking */
+
+    addrlen = sizeof(addr);
+    do {
+        sock = accept(netState->listenSock, &addr.addrPlain, &addrlen);
+        if (sock < 0 && errno != EINTR) {
+            // When we call shutdown() on the socket, accept() returns with
+            // EINVAL.  Don't gripe about it.
+            if (errno == EINVAL)
+                LOGVV("accept failed: %s", strerror(errno));
+            else
+                LOGE("accept failed: %s", strerror(errno));
+            return false;
+        }
+    } while (sock < 0);
+
+    netState->remoteAddr = addr.addrInet.sin_addr;
+    netState->remotePort = ntohs(addr.addrInet.sin_port);
+    LOGV("+++ accepted connection from %s:%u",
+        inet_ntoa(netState->remoteAddr), netState->remotePort);
+
+    netState->clientSock = sock;
+    netState->awaitingHandshake = true;
+    netState->inputCount = 0;
+
+    LOGV("Setting TCP_NODELAY on accepted socket");
+    setNoDelay(netState->clientSock);
+
+    if (pipe(netState->wakePipe) < 0) {
+        LOGE("pipe failed");
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Create a connection to a waiting debugger.
+ */
+static bool establishConnection(JdwpState* state)
+{
+    union {
+        struct sockaddr_in  addrInet;
+        struct sockaddr     addrPlain;
+    } addr;
+    struct hostent* pEntry;
+    int h_errno;
+
+    assert(state != NULL && state->netState != NULL);
+    assert(!state->params.server);
+    assert(state->params.host[0] != '\0');
+    assert(state->params.port != 0);
+
+    /*
+     * Start by resolving the host name.
+     */
+//#undef HAVE_GETHOSTBYNAME_R
+//#warning "forcing non-R"
+#ifdef HAVE_GETHOSTBYNAME_R
+    struct hostent he;
+    char auxBuf[128];
+    int cc = gethostbyname_r(state->params.host, &he, auxBuf, sizeof(auxBuf),
+            &pEntry, &h_errno);
+    if (cc != 0) {
+        LOGW("gethostbyname_r('%s') failed: %s",
+            state->params.host, strerror(errno));
+        return false;
+    }
+
+#else
+    h_errno = 0;
+    pEntry = gethostbyname(state->params.host);
+    if (pEntry == NULL) {
+        LOGW("gethostbyname('%s') failed: %s",
+            state->params.host, strerror(h_errno));
+        return false;
+    }
+#endif
+
+    /* copy it out ASAP to minimize risk of multithreaded annoyances */
+    memcpy(&addr.addrInet.sin_addr, pEntry->h_addr, pEntry->h_length);
+    addr.addrInet.sin_family = pEntry->h_addrtype;
+
+    addr.addrInet.sin_port = htons(state->params.port);
+
+    LOGI("Connecting out to '%s' %d",
+        inet_ntoa(addr.addrInet.sin_addr), ntohs(addr.addrInet.sin_port));
+
+    /*
+     * Create a socket.
+     */
+    JdwpNetState* netState;
+    netState = state->netState;
+    netState->clientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (netState->clientSock < 0) {
+        LOGE("Unable to create socket: %s", strerror(errno));
+        return false;
+    }
+
+    /*
+     * Try to connect.
+     */
+    if (connect(netState->clientSock, &addr.addrPlain, sizeof(addr)) != 0) {
+        LOGE("Unable to connect to %s:%d: %s",
+            inet_ntoa(addr.addrInet.sin_addr), ntohs(addr.addrInet.sin_port),
+            strerror(errno));
+        close(netState->clientSock);
+        netState->clientSock = -1;
+        return false;
+    }
+
+    LOGI("Connection established to %s (%s:%d)",
+        state->params.host, inet_ntoa(addr.addrInet.sin_addr),
+        ntohs(addr.addrInet.sin_port));
+    netState->awaitingHandshake = true;
+    netState->inputCount = 0;
+
+    setNoDelay(netState->clientSock);
+
+    if (pipe(netState->wakePipe) < 0) {
+        LOGE("pipe failed");
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Close the connection to the debugger.
+ *
+ * Reset the state so we're ready to receive a new connection.
+ */
+static void closeConnection(JdwpState* state)
+{
+    JdwpNetState* netState;
+
+    assert(state != NULL && state->netState != NULL);
+
+    netState = state->netState;
+    if (netState->clientSock < 0)
+        return;
+
+    LOGV("+++ closed connection to %s:%u",
+        inet_ntoa(netState->remoteAddr), netState->remotePort);
+
+    close(netState->clientSock);
+    netState->clientSock = -1;
+
+    return;
+}
+
+/*
+ * Figure out if we have a full packet in the buffer.
+ */
+static bool haveFullPacket(JdwpNetState* netState)
+{
+    long length;
+
+    if (netState->awaitingHandshake)
+        return (netState->inputCount >= (int) kMagicHandshakeLen);
+
+    if (netState->inputCount < 4)
+        return false;
+
+    length = get4BE(netState->inputBuffer);
+    return (netState->inputCount >= length);
+}
+
+/*
+ * Consume bytes from the buffer.
+ *
+ * This would be more efficient with a circular buffer.  However, we're
+ * usually only going to find one packet, which is trivial to handle.
+ */
+static void consumeBytes(JdwpNetState* netState, int count)
+{
+    assert(count > 0);
+    assert(count <= netState->inputCount);
+
+    if (count == netState->inputCount) {
+        netState->inputCount = 0;
+        return;
+    }
+
+    memmove(netState->inputBuffer, netState->inputBuffer + count,
+        netState->inputCount - count);
+    netState->inputCount -= count;
+}
+
+/*
+ * Dump the contents of a packet to stdout.
+ */
+#if 0
+static void dumpPacket(const unsigned char* packetBuf)
+{
+    const unsigned char* buf = packetBuf;
+    u4 length, id;
+    u1 flags, cmdSet, cmd;
+    u2 error;
+    bool reply;
+    int dataLen;
+
+    cmd = cmdSet = 0xcc;
+
+    length = read4BE(&buf);
+    id = read4BE(&buf);
+    flags = read1(&buf);
+    if ((flags & kJDWPFlagReply) != 0) {
+        reply = true;
+        error = read2BE(&buf);
+    } else {
+        reply = false;
+        cmdSet = read1(&buf);
+        cmd = read1(&buf);
+    }
+
+    dataLen = length - (buf - packetBuf);
+
+    LOGV("--- %s: dataLen=%u id=0x%08x flags=0x%02x cmd=%d/%d",
+        reply ? "reply" : "req",
+        dataLen, id, flags, cmdSet, cmd);
+    if (dataLen > 0)
+        dvmPrintHexDumpDbg(buf, dataLen, LOG_TAG);
+}
+#endif
+
+/*
+ * Handle a packet.  Returns "false" if we encounter a connection-fatal error.
+ */
+static bool handlePacket(JdwpState* state)
+{
+    JdwpNetState* netState = state->netState;
+    const unsigned char* buf = netState->inputBuffer;
+    JdwpReqHeader hdr;
+    u4 length, id;
+    u1 flags, cmdSet, cmd;
+    u2 error;
+    bool reply;
+    int dataLen;
+
+    cmd = cmdSet = 0;       // shut up gcc
+
+    /*dumpPacket(netState->inputBuffer);*/
+
+    length = read4BE(&buf);
+    id = read4BE(&buf);
+    flags = read1(&buf);
+    if ((flags & kJDWPFlagReply) != 0) {
+        reply = true;
+        error = read2BE(&buf);
+    } else {
+        reply = false;
+        cmdSet = read1(&buf);
+        cmd = read1(&buf);
+    }
+
+    assert((int) length <= netState->inputCount);
+    dataLen = length - (buf - netState->inputBuffer);
+
+    if (!reply) {
+        ExpandBuf* pReply = expandBufAlloc();
+
+        hdr.length = length;
+        hdr.id = id;
+        hdr.cmdSet = cmdSet;
+        hdr.cmd = cmd;
+        dvmJdwpProcessRequest(state, &hdr, buf, dataLen, pReply);
+        if (expandBufGetLength(pReply) > 0) {
+            ssize_t cc = netState->writePacket(pReply);
+
+            if (cc != (ssize_t) expandBufGetLength(pReply)) {
+                LOGE("Failed sending reply to debugger: %s", strerror(errno));
+                expandBufFree(pReply);
+                return false;
+            }
+        } else {
+            LOGW("No reply created for set=%d cmd=%d", cmdSet, cmd);
+        }
+        expandBufFree(pReply);
+    } else {
+        LOGV("reply?!");
+        assert(false);
+    }
+
+    LOGV("----------");
+
+    consumeBytes(netState, length);
+    return true;
+}
+
+/*
+ * Process incoming data.  If no data is available, this will block until
+ * some arrives.
+ *
+ * If we get a full packet, handle it.
+ *
+ * To take some of the mystery out of life, we want to reject incoming
+ * connections if we already have a debugger attached.  If we don't, the
+ * debugger will just mysteriously hang until it times out.  We could just
+ * close the listen socket, but there's a good chance we won't be able to
+ * bind to the same port again, which would confuse utilities.
+ *
+ * Returns "false" on error (indicating that the connection has been severed),
+ * "true" if things are still okay.
+ */
+static bool processIncoming(JdwpState* state)
+{
+    JdwpNetState* netState = state->netState;
+    int readCount;
+
+    assert(netState->clientSock >= 0);
+
+    if (!haveFullPacket(netState)) {
+        /* read some more, looping until we have data */
+        errno = 0;
+        while (1) {
+            int selCount;
+            fd_set readfds;
+            int maxfd;
+            int fd;
+
+            maxfd = netState->listenSock;
+            if (netState->clientSock > maxfd)
+                maxfd = netState->clientSock;
+            if (netState->wakePipe[0] > maxfd)
+                maxfd = netState->wakePipe[0];
+
+            if (maxfd < 0) {
+                LOGV("+++ all fds are closed");
+                return false;
+            }
+
+            FD_ZERO(&readfds);
+
+            /* configure fds; note these may get zapped by another thread */
+            fd = netState->listenSock;
+            if (fd >= 0)
+                FD_SET(fd, &readfds);
+            fd = netState->clientSock;
+            if (fd >= 0)
+                FD_SET(fd, &readfds);
+            fd = netState->wakePipe[0];
+            if (fd >= 0) {
+                FD_SET(fd, &readfds);
+            } else {
+                LOGI("NOTE: entering select w/o wakepipe");
+            }
+
+            /*
+             * Select blocks until it sees activity on the file descriptors.
+             * Closing the local file descriptor does not count as activity,
+             * so we can't rely on that to wake us up (it works for read()
+             * and accept(), but not select()).
+             *
+             * We can do one of three things: (1) send a signal and catch
+             * EINTR, (2) open an additional fd ("wakePipe") and write to
+             * it when it's time to exit, or (3) time out periodically and
+             * re-issue the select.  We're currently using #2, as it's more
+             * reliable than #1 and generally better than #3.  Wastes two fds.
+             */
+            selCount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+            if (selCount < 0) {
+                if (errno == EINTR)
+                    continue;
+                LOGE("select failed: %s", strerror(errno));
+                goto fail;
+            }
+
+            if (netState->wakePipe[0] >= 0 &&
+                FD_ISSET(netState->wakePipe[0], &readfds))
+            {
+                if (netState->listenSock >= 0)
+                    LOGE("Exit wake set, but not exiting?");
+                else
+                    LOGD("Got wake-up signal, bailing out of select");
+                goto fail;
+            }
+            if (netState->listenSock >= 0 &&
+                FD_ISSET(netState->listenSock, &readfds))
+            {
+                LOGI("Ignoring second debugger -- accepting and dropping");
+                union {
+                    struct sockaddr_in   addrInet;
+                    struct sockaddr      addrPlain;
+                } addr;
+                socklen_t addrlen;
+                int tmpSock;
+                tmpSock = accept(netState->listenSock, &addr.addrPlain,
+                                &addrlen);
+                if (tmpSock < 0)
+                    LOGI("Weird -- accept failed");
+                else
+                    close(tmpSock);
+            }
+            if (netState->clientSock >= 0 &&
+                FD_ISSET(netState->clientSock, &readfds))
+            {
+                readCount = read(netState->clientSock,
+                                netState->inputBuffer + netState->inputCount,
+                    sizeof(netState->inputBuffer) - netState->inputCount);
+                if (readCount < 0) {
+                    /* read failed */
+                    if (errno != EINTR)
+                        goto fail;
+                    LOGD("+++ EINTR hit");
+                    return true;
+                } else if (readCount == 0) {
+                    /* EOF hit -- far end went away */
+                    LOGD("+++ peer disconnected");
+                    goto fail;
+                } else
+                    break;
+            }
+        }
+
+        netState->inputCount += readCount;
+        if (!haveFullPacket(netState))
+            return true;        /* still not there yet */
+    }
+
+    /*
+     * Special-case the initial handshake.  For some bizarre reason we're
+     * expected to emulate bad tty settings by echoing the request back
+     * exactly as it was sent.  Note the handshake is always initiated by
+     * the debugger, no matter who connects to whom.
+     *
+     * Other than this one case, the protocol [claims to be] stateless.
+     */
+    if (netState->awaitingHandshake) {
+        int cc;
+
+        if (memcmp(netState->inputBuffer,
+                kMagicHandshake, kMagicHandshakeLen) != 0)
+        {
+            LOGE("ERROR: bad handshake '%.14s'", netState->inputBuffer);
+            goto fail;
+        }
+
+        errno = 0;
+        cc = write(netState->clientSock, netState->inputBuffer,
+                kMagicHandshakeLen);
+        if (cc != kMagicHandshakeLen) {
+            LOGE("Failed writing handshake bytes: %s (%d of %d)",
+                strerror(errno), cc, (int) kMagicHandshakeLen);
+            goto fail;
+        }
+
+        consumeBytes(netState, kMagicHandshakeLen);
+        netState->awaitingHandshake = false;
+        LOGV("+++ handshake complete");
+        return true;
+    }
+
+    /*
+     * Handle this packet.
+     */
+    return handlePacket(state);
+
+fail:
+    closeConnection(state);
+    return false;
+}
+
+/*
+ * Send a request.
+ *
+ * The entire packet must be sent with a single write() call to avoid
+ * threading issues.
+ *
+ * Returns "true" if it was sent successfully.
+ */
+static bool sendRequest(JdwpState* state, ExpandBuf* pReq)
+{
+    JdwpNetState* netState = state->netState;
+
+    /*dumpPacket(expandBufGetBuffer(pReq));*/
+    if (netState->clientSock < 0) {
+        /* can happen with some DDMS events */
+        LOGV("NOT sending request -- no debugger is attached");
+        return false;
+    }
+
+    errno = 0;
+    ssize_t cc = netState->writePacket(pReq);
+
+    if (cc != (ssize_t) expandBufGetLength(pReq)) {
+        LOGE("Failed sending req to debugger: %s (%d of %d)",
+            strerror(errno), (int) cc, (int) expandBufGetLength(pReq));
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Send a request that was split into multiple buffers.
+ *
+ * The entire packet must be sent with a single writev() call to avoid
+ * threading issues.
+ *
+ * Returns "true" if it was sent successfully.
+ */
+static bool sendBufferedRequest(JdwpState* state, const struct iovec* iov,
+    int iovcnt)
+{
+    JdwpNetState* netState = state->netState;
+
+    if (netState->clientSock < 0) {
+        /* can happen with some DDMS events */
+        LOGV("NOT sending request -- no debugger is attached");
+        return false;
+    }
+
+    size_t expected = 0;
+    int i;
+    for (i = 0; i < iovcnt; i++)
+        expected += iov[i].iov_len;
+
+    ssize_t actual = netState->writeBufferedPacket(iov, iovcnt);
+
+    if ((size_t)actual != expected) {
+        LOGE("Failed sending b-req to debugger: %s (%d of %zu)",
+            strerror(errno), (int) actual, expected);
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Our functions.
+ *
+ * We can't generally share the implementations with other transports,
+ * even if they're also socket-based, because our JdwpNetState will be
+ * different from theirs.
+ */
+static const JdwpTransport socketTransport = {
+    prepareSocket,
+    acceptConnection,
+    establishConnection,
+    closeConnection,
+    netShutdownExtern,
+    netFreeExtern,
+    isConnected,
+    awaitingHandshake,
+    processIncoming,
+    sendRequest,
+    sendBufferedRequest,
+};
+
+/*
+ * Return our set.
+ */
+const JdwpTransport* dvmJdwpSocketTransport()
+{
+    return &socketTransport;
+}
diff --git a/vm/jdwp/README.txt b/vm/jdwp/README.txt
new file mode 100644
index 0000000..c97a069
--- /dev/null
+++ b/vm/jdwp/README.txt
@@ -0,0 +1,12 @@
+Java Debug Wire Protocol support
+
+This is a reasonably complete implementation, but only messages that are
+actually generated by debuggers have been implemented.  The reasoning
+behind this is that it's better to leave a call unimplemented than have
+something that appears implemented but has never been tested.
+
+An attempt has been made to keep the implementation distinct from the VM,
+with Debugger.c acting as a sort of portability layer, so that the code
+might be useful in other projects.  Once you get multiple simultaneous
+events and debugger requests with thread suspension bouncing around,
+though, it's difficult to keep things "generic".
diff --git a/vm/mterp/Makefile-mterp b/vm/mterp/Makefile-mterp
new file mode 100644
index 0000000..2f96d59
--- /dev/null
+++ b/vm/mterp/Makefile-mterp
@@ -0,0 +1,51 @@
+# 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) \
+	../Android.mk ../../Android.mk
+
+# 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)/InterpC-$(TARGET_ARCH_EXT).c \
+	$(OUTPUT_DIR)/InterpAsm-$(TARGET_ARCH_EXT).S
+
+target: $(GEN_SOURCES)
+
+$(GEN_SOURCES): $(SOURCE_DEPS)
+	@mkdir -p out
+	./gen-mterp.py $(TARGET_ARCH_EXT) $(OUTPUT_DIR)
diff --git a/vm/mterp/Mterp.cpp b/vm/mterp/Mterp.cpp
new file mode 100644
index 0000000..6220e81
--- /dev/null
+++ b/vm/mterp/Mterp.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+/*
+ * Mterp entry point and support functions.
+ */
+#include "Dalvik.h"
+#include "mterp/Mterp.h"
+
+#include <stddef.h>
+
+
+/*
+ * Verify some constants used by the mterp interpreter.
+ */
+bool dvmCheckAsmConstants()
+{
+    bool failed = false;
+
+#ifndef DVM_NO_ASM_INTERP
+
+#ifndef DVM_JMP_TABLE_MTERP
+    extern void* dvmAsmInstructionStart[];
+    extern void* dvmAsmInstructionEnd[];
+#endif
+
+#define ASM_DEF_VERIFY
+#include "mterp/common/asm-constants.h"
+
+    if (failed) {
+        LOGE("Please correct the values in mterp/common/asm-constants.h");
+        dvmAbort();
+    }
+
+#ifndef DVM_JMP_TABLE_MTERP
+    /*
+     * If we're using computed goto instruction transitions, make sure
+     * none of the handlers overflows the 64-byte limit.  This won't tell
+     * which one did, but if any one is too big the total size will
+     * overflow.
+     */
+    const int width = 64;
+    int interpSize = (uintptr_t) dvmAsmInstructionEnd -
+                     (uintptr_t) dvmAsmInstructionStart;
+    if (interpSize != 0 && interpSize != kNumPackedOpcodes*width) {
+        LOGE("ERROR: unexpected asm interp size %d", interpSize);
+        LOGE("(did an instruction handler exceed %d bytes?)", width);
+        dvmAbort();
+    }
+#endif
+
+#endif // ndef DVM_NO_ASM_INTERP
+
+    return !failed;
+}
+
+
+/*
+ * "Mterp entry point.
+ */
+void dvmMterpStd(Thread* self)
+{
+    /* configure mterp items */
+    self->interpSave.methodClassDex = self->interpSave.method->clazz->pDvmDex;
+
+    IF_LOGVV() {
+        char* desc = dexProtoCopyMethodDescriptor(
+                         &self->interpSave.method->prototype);
+        LOGVV("mterp threadid=%d : %s.%s %s",
+            dvmThreadSelf()->threadId,
+            self->interpSave.method->clazz->descriptor,
+            self->interpSave.method->name,
+            desc);
+        free(desc);
+    }
+    //LOGI("self is %p, pc=%p, fp=%p", self, self->interpSave.pc,
+    //      self->interpSave.curFrame);
+    //LOGI("first instruction is 0x%04x", self->interpSave.pc[0]);
+
+    /*
+     * Handle any ongoing profiling and prep for debugging
+     */
+    if (self->interpBreak.ctl.subMode != 0) {
+        TRACE_METHOD_ENTER(self, self->interpSave.method);
+        self->debugIsMethodEntry = true;   // Always true on startup
+    }
+
+    dvmMterpStdRun(self);
+
+#ifdef LOG_INSTR
+    LOGD("|-- Leaving interpreter loop");
+#endif
+}
diff --git a/vm/mterp/Mterp.h b/vm/mterp/Mterp.h
new file mode 100644
index 0000000..b27e4f7
--- /dev/null
+++ b/vm/mterp/Mterp.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/*
+ * Some declarations used throughout mterp.
+ */
+#ifndef DALVIK_MTERP_MTERP_H_
+#define DALVIK_MTERP_MTERP_H_
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#if defined(WITH_JIT)
+#include "interp/Jit.h"
+#endif
+
+/*
+ * Call this during initialization to verify that the values in asm-constants.h
+ * are still correct.
+ */
+extern "C" bool dvmCheckAsmConstants(void);
+
+/*
+ * Local entry and exit points.  The platform-specific implementation must
+ * provide these two.
+ *
+ * dvmMterpStdRun() returns the "changeInterp" argument from dvmMterpStdBail(),
+ * indicating whether we want to bail out of the interpreter or just switch
+ * between "standard" and "debug" mode.
+ *
+ * The "mterp" interpreter is always "standard".
+ */
+extern "C" bool dvmMterpStdRun(Thread* self);
+extern "C" void dvmMterpStdBail(Thread* self, bool changeInterp);
+
+/*
+ * Helper for common_printMethod(), invoked from the assembly
+ * interpreter.
+ */
+extern "C" void dvmMterpPrintMethod(Method* method);
+
+#endif  // DALVIK_MTERP_MTERP_H_
diff --git a/vm/mterp/NOTES.txt b/vm/mterp/NOTES.txt
new file mode 100644
index 0000000..5dc7caa
--- /dev/null
+++ b/vm/mterp/NOTES.txt
@@ -0,0 +1,71 @@
+Interpreter Notes
+
+
+==== Thread suspension and GC points ====
+
+The interpreter is expected to use a safe-point mechanism to allow thread
+suspension for garbage collection and the debugger.  This typically
+means an explicit check of the thread-suspend flag on backward branches
+(including self-branches on certain instructions), exception throws,
+and method returns.  The interpreter must also be prepared to switch in
+and out of the "debug" interpreter at these points.
+
+There are other ways for a thread to be stopped when a GC happens, notably:
+
+ - object allocation (either while executing an instruction that performs
+   allocation, or indirectly by allocating an exception when something
+   goes wrong)
+ - transitions to native code or indefinite wait (e.g. monitor-enter)
+
+(A debugger can in theory cause the interpreter to advance one instruction
+at a time, but since that only happens in the "debug" interpreter it's not
+necessary for authors of platform-specific code to worry about it.)
+
+For the most part the implementation does not need to worry about these
+things, but they matter when considering the contents of Dalvik's virtual
+registers for "precise" garbage collection.  So, all opcode handlers must
+follow this rule:
+
+ * Do not modify the contents of a virtual register before executing
+   code that can pause the thread.
+
+This should be fairly hard to violate given the nature of essentially all
+instructions, which will compute a result and then finish by storing that
+result into the specified destination register.  Using a virtual register
+to hold a partial or temporary result is not allowed.  Virtual registers
+must not be modified if we abort the instruction with an exception.
+
+
+==== Method results and GC ====
+
+The return value from a method is held in local storage (on the native
+stack for the portable interpreter, and in glue->retval for asm).  It's not
+accessible to a GC.  In practice this isn't a problem, because if the
+following instruction is not a "move-result" then the result is ignored,
+and none of the move-result* instructions are GC points.
+
+(This is potentially an issue when debugging, since we can theoretically
+single-step by individual bytecodes, but in practice we always step by
+source lines and move-result is grouped with the method invoke.)
+
+This suggests a rule:
+
+ * Don't do anything that can cause a GC in the invoke-* handler after
+   a method returns successfully.
+
+Unsuccessful returns, such as a native method call that returns with an
+exception pending, are not interesting because the return value is ignored.
+
+If it's not possible to obey this rule, then we need to track the value
+used in a return-object instruction for a brief period.  The easiest way
+to accomplish this is to store it in the interpreted stack where the GC
+can find it, and use a live-precise GC to ignore the value.
+
+The "trackref" functions can also be used, but they add overhead to method
+calls returning objects, and ensuring that we stop tracking the reference
+when it's no longer needed can be awkward.
+
+Any solution must work correctly when returning into or returning from native
+code.  JNI handles returns from interp->native by adding the value to the
+local references table, but returns from native->interp are simply stored
+in the usual "retval".
diff --git a/vm/mterp/README.txt b/vm/mterp/README.txt
new file mode 100644
index 0000000..6106740
--- /dev/null
+++ b/vm/mterp/README.txt
@@ -0,0 +1,305 @@
+Dalvik "mterp" README
+
+NOTE: Find rebuilding instructions at the bottom of this file.
+
+
+==== Overview ====
+
+This is the source code for the Dalvik interpreter.  The core of the
+original version was implemented as a single C function, but to improve
+performance we rewrote it in assembly.  To make this and future assembly
+ports easier and less error-prone, we used a modular approach that allows
+development of platform-specific code one opcode at a time.
+
+The original all-in-one-function C version still exists as the "portable"
+interpreter, and is generated using the same sources and tools that
+generate the platform-specific versions.
+
+Every configuration has a "config-*" file that controls how the sources
+are generated.  The sources are written into the "out" directory, where
+they are picked up by the Android build system.
+
+The best way to become familiar with the interpreter is to look at the
+generated files in the "out" directory, such as out/InterpC-portstd.c,
+rather than trying to look at the various component pieces in (say)
+armv5te.
+
+
+==== Platform-specific source generation ====
+
+The architecture-specific config files determine what goes into two
+generated output files (InterpC-<arch>.c, InterpAsm-<arch>.S).  The goal is
+to make it easy to swap C and assembly sources during initial development
+and testing, and to provide a way to use architecture-specific versions of
+some operations (e.g. making use of PLD instructions on ARMv6 or avoiding
+CLZ on ARMv4T).
+
+Depending on architecture, instruction-to-instruction transitions may
+be done as either computed goto or jump table.  In the computed goto
+variant, each instruction handler is allocated a fixed-size area (e.g. 64
+byte).  "Overflow" code is tacked on to the end.  In the jump table variant,
+all of the instructions handlers are contiguous and may be of any size.
+The interpreter style is selected via the "handler-size" command (see below).
+
+When a C implementation for an instruction is desired, the assembly
+version packs all local state into the Thread structure and passes
+that to the C function.  Updates to the state are pulled out of
+"Thread" on return.
+
+The "arch" value should indicate an architecture family with common
+programming characteristics, so "armv5te" would work for all ARMv5TE CPUs,
+but might not be backward- or forward-compatible.  (We *might* want to
+specify the ABI model as well, e.g. "armv5te-eabi", but currently that adds
+verbosity without value.)
+
+
+==== Config file format ====
+
+The config files are parsed from top to bottom.  Each line in the file
+may be blank, hold a comment (line starts with '#'), or be a command.
+
+The commands are:
+
+  handler-style <computed-goto|jump-table|all-c>
+
+    Specify which style of interpreter to generate.  In computed-goto,
+    each handler is allocated a fixed region, allowing transitions to
+    be done via table-start-address + (opcode * handler-size). With
+    jump-table style, handlers may be of any length, and the generated
+    table is an array of pointers to the handlers. The "all-c" style is
+    for the portable interpreter (which is implemented completely in C).
+    [Note: all-c is distinct from an "allstubs" configuration.  In both
+    configurations, all handlers are the C versions, but the allstubs
+    configuration uses the assembly outer loop and assembly stubs to
+    transition to the handlers].  This command is required, and must be
+    the first command in the config file.
+
+  handler-size <bytes>
+
+    Specify the size of the fixed region, in bytes.  On most platforms
+    this will need to be a power of 2.  For jump-table and all-c
+    implementations, this command is ignored.
+
+  import <filename>
+
+    The specified file is included immediately, in its entirety.  No
+    substitutions are performed.  ".cpp" and ".h" files are copied to the
+    C output, ".S" files are copied to the asm output.
+
+  asm-stub <filename>
+
+    The named file will be included whenever an assembly "stub" is needed
+    to transfer control to a handler written in C.  Text substitution is
+    performed on the opcode name.  This command is not applicable to
+    to "all-c" configurations.
+
+  asm-alt-stub <filename>
+
+    When present, this command will cause the generation of an alternate
+    set of entry points (for computed-goto interpreters) or an alternate
+    jump table (for jump-table interpreters).
+
+  op-start <directory>
+
+    Indicates the start of the opcode list.  Must precede any "op"
+    commands.  The specified directory is the default location to pull
+    instruction files from.
+
+  op <opcode> <directory>
+
+    Can only appear after "op-start" and before "op-end".  Overrides the
+    default source file location of the specified opcode.  The opcode
+    definition will come from the specified file, e.g. "op OP_NOP armv5te"
+    will load from "armv5te/OP_NOP.S".  A substitution dictionary will be
+    applied (see below).
+
+  alt <opcode> <directory>
+
+    Can only appear after "op-start" and before "op-end".  Similar to the
+    "op" command above, but denotes a source file to override the entry
+    in the alternate handler table.  The opcode definition will come from
+    the specified file, e.g. "alt OP_NOP armv5te" will load from
+    "armv5te/ALT_OP_NOP.S".  A substitution dictionary will be applied
+    (see below).
+
+  op-end
+
+    Indicates the end of the opcode list.  All kNumPackedOpcodes
+    opcodes are emitted when this is seen, followed by any code that
+    didn't fit inside the fixed-size instruction handler space.
+
+The order of "op" and "alt" directives are not significant; the generation
+tool will extract ordering info from the VM sources.
+
+Typically the form in which most opcodes currently exist is used in
+the "op-start" directive.  For a new port you would start with "c",
+and add architecture-specific "op" entries as you write instructions.
+When complete it will default to the target architecture, and you insert
+"c" ops to stub out platform-specific code.
+
+For the <directory> specified in the "op" command, the "c" directory
+is special in two ways: (1) the sources are assumed to be C code, and
+will be inserted into the generated C file; (2) when a C implementation
+is emitted, a "glue stub" is emitted in the assembly source file.
+(The generator script always emits kNumPackedOpcodes assembly
+instructions, unless "asm-stub" was left blank, in which case it only
+emits some labels.)
+
+
+==== Instruction file format ====
+
+The assembly instruction files are simply fragments of assembly sources.
+The starting label will be provided by the generation tool, as will
+declarations for the segment type and alignment.  The expected target
+assembler is GNU "as", but others will work (may require fiddling with
+some of the pseudo-ops emitted by the generation tool).
+
+The C files do a bunch of fancy things with macros in an attempt to share
+code with the portable interpreter.  (This is expected to be reduced in
+the future.)
+
+A substitution dictionary is applied to all opcode fragments as they are
+appended to the output.  Substitutions can look like "$value" or "${value}".
+
+The dictionary always includes:
+
+  $opcode - opcode name, e.g. "OP_NOP"
+  $opnum - opcode number, e.g. 0 for OP_NOP
+  $handler_size_bytes - max size of an instruction handler, in bytes
+  $handler_size_bits - max size of an instruction handler, log 2
+
+Both C and assembly sources will be passed through the C pre-processor,
+so you can take advantage of C-style comments and preprocessor directives
+like "#define".
+
+Some generator operations are available.
+
+  %include "filename" [subst-dict]
+
+    Includes the file, which should look like "armv5te/OP_NOP.S".  You can
+    specify values for the substitution dictionary, using standard Python
+    syntax.  For example, this:
+      %include "armv5te/unop.S" {"result":"r1"}
+    would insert "armv5te/unop.S" at the current file position, replacing
+    occurrences of "$result" with "r1".
+
+  %default <subst-dict>
+
+    Specify default substitution dictionary values, using standard Python
+    syntax.  Useful if you want to have a "base" version and variants.
+
+  %break
+
+    Identifies the split between the main portion of the instruction
+    handler (which must fit in "handler-size" bytes) and the "sister"
+    code, which is appended to the end of the instruction handler block.
+    In jump table implementations, %break is ignored.
+
+  %verify "message"
+
+    Leave a note to yourself about what needs to be tested.  (This may
+    turn into something more interesting someday; for now, it just gets
+    stripped out before the output is generated.)
+
+The generation tool does *not* print a warning if your instructions
+exceed "handler-size", but the VM will abort on startup if it detects an
+oversized handler.  On architectures with fixed-width instructions this
+is easy to work with, on others this you will need to count bytes.
+
+
+==== Using C constants from assembly sources ====
+
+The file "common/asm-constants.h" has some definitions for constant
+values, structure sizes, and struct member offsets.  The format is fairly
+restricted, as simple macros are used to massage it for use with both C
+(where it is verified) and assembly (where the definitions are used).
+
+If a constant in the file becomes out of sync, the VM will log an error
+message and abort during startup.
+
+
+==== Development tips ====
+
+If you need to debug the initial piece of an opcode handler, and your
+debug code expands it beyond the handler size limit, you can insert a
+generic header at the top:
+
+    b       ${opcode}_start
+%break
+${opcode}_start:
+
+If you already have a %break, it's okay to leave it in place -- the second
+%break is ignored.
+
+
+==== Rebuilding ====
+
+If you change any of the source file fragments, you need to rebuild the
+combined source files in the "out" directory.  Make sure the files in
+"out" are editable, then:
+
+    $ cd mterp
+    $ ./rebuild.sh
+
+As of this writing, this requires Python 2.5. You may see inscrutible
+error messages or just general failure if you have a different version
+of Python installed.
+
+The ultimate goal is to have the build system generate the necessary
+output files without requiring this separate step, but we're not yet
+ready to require Python in the build.
+
+==== Interpreter Control ====
+
+The central mechanism for interpreter control is the InterpBreak struture
+that is found in each thread's Thread struct (see vm/Thread.h).  There
+is one mandatory field, and two optional fields:
+
+    subMode - required, describes debug/profile/special operation
+    breakFlags & curHandlerTable - optional, used lower subMode polling costs
+
+The subMode field is a bitmask which records all currently active
+special modes of operation.  For example, when Traceview profiling
+is active, kSubModeMethodTrace is set.  This bit informs the interpreter
+that it must notify the profiling subsystem on each method entry and
+return.  There are similar bits for an active debugging session,
+instruction count profiling, pending thread suspension request, etc.
+
+To support special subMode operation the simplest mechanism for the
+interpreter is to poll the subMode field before interpreting each Dalvik
+bytecode and take any required action.  In fact, this is precisely
+what the portable interpreter does.  The "FINISH" macro expands to
+include a test of subMode and subsequent call to the "dvmCheckBefore()".
+
+Per-instruction polling, however, is expensive and subMode operation is
+relative rare.  For normal operation we'd like to avoid having to perform
+any checks unless a special subMode is actually in effect.  This is
+where curHandlerTable and breakFlags come in to play.
+
+The mterp fast interpreter achieves much of its performance advantage
+over the portable interpreter through its efficient mechanism of
+transitioning from one Dalvik bytecode to the next.  Mterp for ARM targets
+uses a computed-goto mechanism, in which the handler entrypoints are
+located at the base of the handler table + (opcode * 64).  Mterp for x86
+targets instead uses a jump table of handler entry points indexed
+by the Dalvik opcode.  To support efficient handling of special subModes,
+mterp supports two sets of handler entries (for ARM) or two jump
+tables (for x86).  One handler set is optimized for speed and performs no
+inter-instruction checks (mainHandlerTable in the Thread structure), while
+the other includes a test of the subMode field (altHandlerTable).
+
+In normal operation (i.e. subMode == 0), the dedicated register rIBASE
+(r8 for ARM, edx for x86) holds a mainHandlerTable.  If we need to switch
+to a subMode that requires inter-instruction checking, rIBASE is changed
+to altHandlerTable.  Note that this change is not immediate.  What is actually
+changed is the value of curHandlerTable - which is part of the interpBreak
+structure.  Rather than explicitly check for changes, each thread will
+blindly refresh rIBASE at backward branches, exception throws and returns.
+
+The breakFlags field tells the interpreter control mechanism whether
+curHandlerTable should hold the real or alternate handler base.  If
+non-zero, we use the altHandlerBase.  The bits within breakFlags
+tells dvmCheckBefore which set of subModes need to be checked.
+
+See dvmCheckBefore() for subMode handling, and dvmEnableSubMode(),
+dvmDisableSubMode() for switching on and off.
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..b75216e
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S
@@ -0,0 +1,42 @@
+%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..eade97d
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPG_FLOAT.S
@@ -0,0 +1,42 @@
+%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..6e85fe7
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPL_DOUBLE.S
@@ -0,0 +1,42 @@
+%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..bdeb0be
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPL_FLOAT.S
@@ -0,0 +1,42 @@
+%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..c94e1e8
--- /dev/null
+++ b/vm/mterp/arm-vfp/README.txt
@@ -0,0 +1,7 @@
+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.  It assumes that word alignment is sufficient for double-word
+accesses (which is true for some ARMv5 and all ARMv6/v7), to avoid having
+to transfer double-precision values in two steps.
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/ALT_OP_DISPATCH_FF.S b/vm/mterp/armv5te/ALT_OP_DISPATCH_FF.S
new file mode 100644
index 0000000..0c542a0
--- /dev/null
+++ b/vm/mterp/armv5te/ALT_OP_DISPATCH_FF.S
@@ -0,0 +1,10 @@
+%verify "executed"
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
diff --git a/vm/mterp/armv5te/OP_ADD_DOUBLE.S b/vm/mterp/armv5te/OP_ADD_DOUBLE.S
new file mode 100644
index 0000000..de36691
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"instr":"bl      __aeabi_dadd"}
diff --git a/vm/mterp/armv5te/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/armv5te/OP_ADD_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..744b2ab
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"instr":"bl      __aeabi_dadd"}
diff --git a/vm/mterp/armv5te/OP_ADD_FLOAT.S b/vm/mterp/armv5te/OP_ADD_FLOAT.S
new file mode 100644
index 0000000..badf1f7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"bl      __aeabi_fadd"}
diff --git a/vm/mterp/armv5te/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/armv5te/OP_ADD_FLOAT_2ADDR.S
new file mode 100644
index 0000000..70f1fe8
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"bl      __aeabi_fadd"}
diff --git a/vm/mterp/armv5te/OP_ADD_INT.S b/vm/mterp/armv5te/OP_ADD_INT.S
new file mode 100644
index 0000000..97cb5fe
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"add     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_ADD_INT_2ADDR.S b/vm/mterp/armv5te/OP_ADD_INT_2ADDR.S
new file mode 100644
index 0000000..c424f0c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"add     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_ADD_INT_LIT16.S b/vm/mterp/armv5te/OP_ADD_INT_LIT16.S
new file mode 100644
index 0000000..f5a1603
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit16.S" {"instr":"add     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_ADD_INT_LIT8.S b/vm/mterp/armv5te/OP_ADD_INT_LIT8.S
new file mode 100644
index 0000000..93e57d3
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"instr":"add     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_ADD_LONG.S b/vm/mterp/armv5te/OP_ADD_LONG.S
new file mode 100644
index 0000000..b30cd05
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"preinstr":"adds    r0, r0, r2", "instr":"adc     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_ADD_LONG_2ADDR.S b/vm/mterp/armv5te/OP_ADD_LONG_2ADDR.S
new file mode 100644
index 0000000..ff34ed5
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ADD_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"preinstr":"adds    r0, r0, r2", "instr":"adc     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_AGET.S b/vm/mterp/armv5te/OP_AGET.S
new file mode 100644
index 0000000..8d8ed58
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET.S
@@ -0,0 +1,27 @@
+%default { "load":"ldr", "shift":"2" }
+%verify "executed"
+    /*
+     * 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 #$shift     @ 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
+    $load   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
diff --git a/vm/mterp/armv5te/OP_AGET_BOOLEAN.S b/vm/mterp/armv5te/OP_AGET_BOOLEAN.S
new file mode 100644
index 0000000..ccce848
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_AGET.S" { "load":"ldrb", "shift":"0" }
diff --git a/vm/mterp/armv5te/OP_AGET_BYTE.S b/vm/mterp/armv5te/OP_AGET_BYTE.S
new file mode 100644
index 0000000..c290922
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_AGET.S" { "load":"ldrsb", "shift":"0" }
diff --git a/vm/mterp/armv5te/OP_AGET_CHAR.S b/vm/mterp/armv5te/OP_AGET_CHAR.S
new file mode 100644
index 0000000..78c40a0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_AGET.S" { "load":"ldrh", "shift":"1" }
diff --git a/vm/mterp/armv5te/OP_AGET_OBJECT.S b/vm/mterp/armv5te/OP_AGET_OBJECT.S
new file mode 100644
index 0000000..9d64585
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_AGET.S"
diff --git a/vm/mterp/armv5te/OP_AGET_SHORT.S b/vm/mterp/armv5te/OP_AGET_SHORT.S
new file mode 100644
index 0000000..77951e6
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_AGET.S" { "load":"ldrsh", "shift":"1" }
diff --git a/vm/mterp/armv5te/OP_AGET_WIDE.S b/vm/mterp/armv5te/OP_AGET_WIDE.S
new file mode 100644
index 0000000..6f641dc
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AGET_WIDE.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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     .L${opcode}_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.
+%break
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_AND_INT.S b/vm/mterp/armv5te/OP_AND_INT.S
new file mode 100644
index 0000000..2a0022e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AND_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"and     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_AND_INT_2ADDR.S b/vm/mterp/armv5te/OP_AND_INT_2ADDR.S
new file mode 100644
index 0000000..24203aa
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AND_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"and     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_AND_INT_LIT16.S b/vm/mterp/armv5te/OP_AND_INT_LIT16.S
new file mode 100644
index 0000000..a06084d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AND_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit16.S" {"instr":"and     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_AND_INT_LIT8.S b/vm/mterp/armv5te/OP_AND_INT_LIT8.S
new file mode 100644
index 0000000..bd309bb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AND_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"instr":"and     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_AND_LONG.S b/vm/mterp/armv5te/OP_AND_LONG.S
new file mode 100644
index 0000000..c76bae8
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AND_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"preinstr":"and     r0, r0, r2", "instr":"and     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_AND_LONG_2ADDR.S b/vm/mterp/armv5te/OP_AND_LONG_2ADDR.S
new file mode 100644
index 0000000..6b7c830
--- /dev/null
+++ b/vm/mterp/armv5te/OP_AND_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"preinstr":"and     r0, r0, r2", "instr":"and     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_APUT.S b/vm/mterp/armv5te/OP_APUT.S
new file mode 100644
index 0000000..741aadd
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT.S
@@ -0,0 +1,27 @@
+%default { "store":"str", "shift":"2" }
+%verify "executed"
+    /*
+     * 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 #$shift     @ 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
+    $store  r2, [r0, #offArrayObject_contents]  @ vBB[vCC]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_APUT_BOOLEAN.S b/vm/mterp/armv5te/OP_APUT_BOOLEAN.S
new file mode 100644
index 0000000..d46650d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_APUT.S" { "store":"strb", "shift":"0" }
diff --git a/vm/mterp/armv5te/OP_APUT_BYTE.S b/vm/mterp/armv5te/OP_APUT_BYTE.S
new file mode 100644
index 0000000..d46650d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_APUT.S" { "store":"strb", "shift":"0" }
diff --git a/vm/mterp/armv5te/OP_APUT_CHAR.S b/vm/mterp/armv5te/OP_APUT_CHAR.S
new file mode 100644
index 0000000..2ff31be
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_APUT.S" { "store":"strh", "shift":"1" }
diff --git a/vm/mterp/armv5te/OP_APUT_OBJECT.S b/vm/mterp/armv5te/OP_APUT_OBJECT.S
new file mode 100644
index 0000000..918fcd0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT_OBJECT.S
@@ -0,0 +1,55 @@
+%verify "executed"
+    /*
+     * Store an object into an array.  vBB[vCC] <- vAA.
+     */
+    /* 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(rINST, r2)                 @ rINST<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     rINST, #0                   @ null array object?
+    GET_VREG(r9, r9)                    @ r9<- vAA
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [rINST, #offArrayObject_length]   @ r3<- arrayObj->length
+    add     r10, rINST, r1, lsl #2      @ r10<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcc     .L${opcode}_finish          @ we're okay, continue on
+    b       common_errArrayIndex        @ index >= length, bail
+
+%break
+    /*
+     * On entry:
+     *  rINST = vBB (arrayObj)
+     *  r9 = vAA (obj)
+     *  r10 = offset into array (vBB + vCC * width)
+     */
+.L${opcode}_finish:
+    cmp     r9, #0                      @ storing null reference?
+    beq     .L${opcode}_skip_check      @ yes, skip type checks
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    ldr     r1, [rINST, #offObject_clazz]  @ r1<- arrayObj->clazz
+    bl      dvmCanPutArrayElement       @ test object type vs. array type
+    cmp     r0, #0                      @ okay?
+    beq     .L${opcode}_throw           @ no
+    mov     r1, rINST                   @ r1<- arrayObj
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rSELF, #offThread_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r1, lsr #GC_CARD_SHIFT] @ mark card using object head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.L${opcode}_skip_check:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.L${opcode}_throw:
+    @ The types don't match.  We need to throw an ArrayStoreException.
+    ldr     r0, [r9, #offObject_clazz]
+    ldr     r1, [rINST, #offObject_clazz]
+    EXPORT_PC()
+    bl      dvmThrowArrayStoreExceptionIncompatibleElement
+    b       common_exceptionThrown
diff --git a/vm/mterp/armv5te/OP_APUT_SHORT.S b/vm/mterp/armv5te/OP_APUT_SHORT.S
new file mode 100644
index 0000000..2ff31be
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_APUT.S" { "store":"strh", "shift":"1" }
diff --git a/vm/mterp/armv5te/OP_APUT_WIDE.S b/vm/mterp/armv5te/OP_APUT_WIDE.S
new file mode 100644
index 0000000..cc9f332
--- /dev/null
+++ b/vm/mterp/armv5te/OP_APUT_WIDE.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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     .L${opcode}_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.
+%break
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_ARRAY_LENGTH.S b/vm/mterp/armv5te/OP_ARRAY_LENGTH.S
new file mode 100644
index 0000000..3a6faf3
--- /dev/null
+++ b/vm/mterp/armv5te/OP_ARRAY_LENGTH.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /*
+     * 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
diff --git a/vm/mterp/armv5te/OP_BREAKPOINT.S b/vm/mterp/armv5te/OP_BREAKPOINT.S
new file mode 100644
index 0000000..b4ea333
--- /dev/null
+++ b/vm/mterp/armv5te/OP_BREAKPOINT.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.
+     */
+    mov     r0, rPC
+    bl      dvmGetOriginalOpcode        @ (rPC)
+    FETCH(rINST, 0)                     @ reload OP_BREAKPOINT + rest of inst
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    and     rINST, #0xff00
+    orr     rINST, rINST, r0
+    GOTO_OPCODE_BASE(r1, r0)
diff --git a/vm/mterp/armv5te/OP_CHECK_CAST.S b/vm/mterp/armv5te/OP_CHECK_CAST.S
new file mode 100644
index 0000000..57df60e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CHECK_CAST.S
@@ -0,0 +1,68 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * 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, [rSELF, #offThread_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .L${opcode}_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     .L${opcode}_resolve         @ not resolved, do it now
+.L${opcode}_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .L${opcode}_fullcheck       @ no, do full check
+.L${opcode}_okay:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds desired class resolved from BBBB
+     *  r9 holds object
+     */
+.L${opcode}_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .L${opcode}_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    b       common_exceptionThrown
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds BBBB
+     *  r9 holds object
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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       .L${opcode}_resolved        @ pick up where we left off
diff --git a/vm/mterp/armv5te/OP_CHECK_CAST_JUMBO.S b/vm/mterp/armv5te/OP_CHECK_CAST_JUMBO.S
new file mode 100644
index 0000000..3140ec4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CHECK_CAST_JUMBO.S
@@ -0,0 +1,75 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r3, 3)                        @ r3<- BBBB
+    orr     r2, r0, r2, lsl #16         @ r2<- AAAAaaaa
+    GET_VREG(r9, r3)                    @ r9<- object
+    ldr     r0, [rSELF, #offThread_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .L${opcode}_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     .L${opcode}_resolve         @ not resolved, do it now
+.L${opcode}_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .L${opcode}_fullcheck       @ no, do full check
+    b       .L${opcode}_okay            @ yes, finish up
+%break
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds desired class resolved from AAAAAAAA
+     *  r9 holds object
+     */
+.L${opcode}_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .L${opcode}_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    b       common_exceptionThrown
+
+    /*
+     * Advance PC and get the next opcode.
+     */
+.L${opcode}_okay:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds AAAAAAAA
+     *  r9 holds object
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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 AAAAAAAA
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    b       .L${opcode}_resolved        @ pick up where we left off
diff --git a/vm/mterp/armv5te/OP_CMPG_DOUBLE.S b/vm/mterp/armv5te/OP_CMPG_DOUBLE.S
new file mode 100644
index 0000000..a18c186
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CMPG_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_CMPL_DOUBLE.S" { "naninst":"mov     r1, #1" }
diff --git a/vm/mterp/armv5te/OP_CMPG_FLOAT.S b/vm/mterp/armv5te/OP_CMPG_FLOAT.S
new file mode 100644
index 0000000..3f87470
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CMPG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_CMPL_FLOAT.S" { "naninst":"mov     r1, #1" }
diff --git a/vm/mterp/armv5te/OP_CMPL_DOUBLE.S b/vm/mterp/armv5te/OP_CMPL_DOUBLE.S
new file mode 100644
index 0000000..01a63f7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CMPL_DOUBLE.S
@@ -0,0 +1,48 @@
+%default { "naninst":"mvn     r1, #0" }
+%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.
+     *
+     * 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 */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r9, r0, #255                @ r9<- BB
+    mov     r10, r0, lsr #8             @ r10<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BB]
+    add     r10, rFP, r10, lsl #2       @ r10<- &fp[CC]
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r10, {r2-r3}                @ r2/r3<- vCC/vCC+1
+    bl      __aeabi_cdcmple             @ cmp <=: C clear if <, Z set if eq
+    bhi     .L${opcode}_gt_or_nan       @ C set and Z clear, disambiguate
+    mvncc   r1, #0                      @ (less than) r1<- -1
+    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
+.L${opcode}_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    @ 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}
+    bl      __aeabi_cdcmple             @ r0<- Z set if eq, C clear if <
+    @bleq    common_abort
+    movcc   r1, #1                      @ (greater than) r1<- 1
+    bcc     .L${opcode}_finish
+    $naninst                            @ r1<- 1 or -1 for NaN
+    b       .L${opcode}_finish
diff --git a/vm/mterp/armv5te/OP_CMPL_FLOAT.S b/vm/mterp/armv5te/OP_CMPL_FLOAT.S
new file mode 100644
index 0000000..657f0dc
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CMPL_FLOAT.S
@@ -0,0 +1,115 @@
+%default { "naninst":"mvn     r1, #0" }
+%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.
+     *
+     * 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 */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r9, r2)                    @ r9<- vBB
+    GET_VREG(r10, r3)                   @ r10<- vCC
+    mov     r0, r9                      @ copy to arg registers
+    mov     r1, r10
+    bl      __aeabi_cfcmple             @ cmp <=: C clear if <, Z set if eq
+    bhi     .L${opcode}_gt_or_nan       @ C set and Z clear, disambiguate
+    mvncc   r1, #0                      @ (less than) r1<- -1
+    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
+.L${opcode}_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    @ 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
+    bl      __aeabi_cfcmple             @ r0<- Z set if eq, C clear if <
+    @bleq    common_abort
+    movcc   r1, #1                      @ (greater than) r1<- 1
+    bcc     .L${opcode}_finish
+    $naninst                            @ r1<- 1 or -1 for NaN
+    b       .L${opcode}_finish
+
+
+#if 0       /* "clasic" form */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r9, r2)                    @ r9<- vBB
+    GET_VREG(r10, r3)                   @ r10<- vCC
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmpeq              @ r0<- (vBB == vCC)
+    cmp     r0, #0                      @ equal?
+    movne   r1, #0                      @ yes, result is 0
+    bne     ${opcode}_finish
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmplt              @ r0<- (vBB < vCC)
+    cmp     r0, #0                      @ less than?
+    b       ${opcode}_continue
+@%break
+
+${opcode}_continue:
+    mvnne   r1, #0                      @ yes, result is -1
+    bne     ${opcode}_finish
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmpgt              @ r0<- (vBB > vCC)
+    cmp     r0, #0                      @ greater than?
+    beq     ${opcode}_nan               @ no, must be NaN
+    mov     r1, #1                      @ yes, result is 1
+    @ fall through to _finish
+
+${opcode}_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * This is expected to be uncommon, so we double-branch (once to here,
+     * again back to _finish).
+     */
+${opcode}_nan:
+    $naninst                            @ r1<- 1 or -1 for NaN
+    b       ${opcode}_finish
+
+#endif
diff --git a/vm/mterp/armv5te/OP_CMP_LONG.S b/vm/mterp/armv5te/OP_CMP_LONG.S
new file mode 100644
index 0000000..084a3f2
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CMP_LONG.S
@@ -0,0 +1,60 @@
+%verify "executed"
+%verify "basic lt, gt, eq"
+%verify "hi equal, lo <=>"
+%verify "lo equal, hi <=>"
+    /*
+     * 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     .L${opcode}_less            @ signed compare on high part
+    bgt     .L${opcode}_greater
+    subs    r1, r0, r2                  @ r1<- r0 - r2
+    bhi     .L${opcode}_greater         @ unsigned compare on low part
+    bne     .L${opcode}_less
+    b       .L${opcode}_finish          @ equal; r1 already holds 0
+%break
+
+.L${opcode}_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
+
+.L${opcode}_greater:
+    mov     r1, #1                      @ r1<- 1
+    @ fall through to _finish
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_CONST.S b/vm/mterp/armv5te/OP_CONST.S
new file mode 100644
index 0000000..a813c52
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_16.S b/vm/mterp/armv5te/OP_CONST_16.S
new file mode 100644
index 0000000..b5654a3
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_16.S
@@ -0,0 +1,8 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_4.S b/vm/mterp/armv5te/OP_CONST_4.S
new file mode 100644
index 0000000..6dd53af
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_4.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_CLASS.S b/vm/mterp/armv5te/OP_CONST_CLASS.S
new file mode 100644
index 0000000..9256bf9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_CLASS.S
@@ -0,0 +1,35 @@
+%verify "executed"
+%verify "Class already resolved"
+%verify "Class not yet resolved"
+%verify "Class cannot be resolved"
+    /* const/class vAA, Class@BBBB */
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r2, [rSELF, #offThread_methodClassDex]  @ r2<- self->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     .L${opcode}_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
+%break
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: BBBB (Class ref)
+     *  r9: target register
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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
diff --git a/vm/mterp/armv5te/OP_CONST_CLASS_JUMBO.S b/vm/mterp/armv5te/OP_CONST_CLASS_JUMBO.S
new file mode 100644
index 0000000..4dd973e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_CLASS_JUMBO.S
@@ -0,0 +1,37 @@
+%verify "executed"
+%verify "Class already resolved"
+%verify "Class not yet resolved"
+%verify "Class cannot be resolved"
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<-self>methodClassDex
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]   @ r2<- dvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResClasses[AAAAaaaa]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .L${opcode}_resolve
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: AAAAAAAA (Class ref)
+     *  r9: target register
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_CONST_HIGH16.S b/vm/mterp/armv5te/OP_CONST_HIGH16.S
new file mode 100644
index 0000000..4536d3a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_HIGH16.S
@@ -0,0 +1,9 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_STRING.S b/vm/mterp/armv5te/OP_CONST_STRING.S
new file mode 100644
index 0000000..bad36e4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_STRING.S
@@ -0,0 +1,34 @@
+%verify "executed"
+%verify "String already resolved"
+%verify "String not yet resolved"
+%verify "String cannot be resolved"
+    /* const/string vAA, String@BBBB */
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r2, [rSELF, #offThread_methodClassDex]  @ r2<- self->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     .L${opcode}_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
+%break
+
+    /*
+     * Continuation if the String has not yet been resolved.
+     *  r1: BBBB (String ref)
+     *  r9: target register
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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
diff --git a/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S b/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S
new file mode 100644
index 0000000..05897f7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_STRING_JUMBO.S
@@ -0,0 +1,36 @@
+%verify "executed"
+%verify "String already resolved"
+%verify "String not yet resolved"
+%verify "String cannot be resolved"
+    /* const/string vAA, String@BBBBBBBB */
+    FETCH(r0, 1)                        @ r0<- bbbb (low)
+    FETCH(r1, 2)                        @ r1<- BBBB (high)
+    ldr     r2, [rSELF, #offThread_methodClassDex]  @ r2<- self->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     .L${opcode}_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
+%break
+
+    /*
+     * Continuation if the String has not yet been resolved.
+     *  r1: BBBBBBBB (String ref)
+     *  r9: target register
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE.S b/vm/mterp/armv5te/OP_CONST_WIDE.S
new file mode 100644
index 0000000..b724264
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_WIDE.S
@@ -0,0 +1,14 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE_16.S b/vm/mterp/armv5te/OP_CONST_WIDE_16.S
new file mode 100644
index 0000000..e3e4149
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_WIDE_16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE_32.S b/vm/mterp/armv5te/OP_CONST_WIDE_32.S
new file mode 100644
index 0000000..a86e042
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_WIDE_32.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S b/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S
new file mode 100644
index 0000000..11bf518
--- /dev/null
+++ b/vm/mterp/armv5te/OP_CONST_WIDE_HIGH16.S
@@ -0,0 +1,11 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_DISPATCH_FF.S b/vm/mterp/armv5te/OP_DISPATCH_FF.S
new file mode 100644
index 0000000..1ff7981
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DISPATCH_FF.S
@@ -0,0 +1,5 @@
+%verify "executed"
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
diff --git a/vm/mterp/armv5te/OP_DIV_DOUBLE.S b/vm/mterp/armv5te/OP_DIV_DOUBLE.S
new file mode 100644
index 0000000..2fb085b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"instr":"bl      __aeabi_ddiv"}
diff --git a/vm/mterp/armv5te/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/armv5te/OP_DIV_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..2dcef28
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"instr":"bl      __aeabi_ddiv"}
diff --git a/vm/mterp/armv5te/OP_DIV_FLOAT.S b/vm/mterp/armv5te/OP_DIV_FLOAT.S
new file mode 100644
index 0000000..8fc2fa9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"bl      __aeabi_fdiv"}
diff --git a/vm/mterp/armv5te/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/armv5te/OP_DIV_FLOAT_2ADDR.S
new file mode 100644
index 0000000..e2d57dd
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"bl      __aeabi_fdiv"}
diff --git a/vm/mterp/armv5te/OP_DIV_INT.S b/vm/mterp/armv5te/OP_DIV_INT.S
new file mode 100644
index 0000000..1e326d9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"bl     __aeabi_idiv","chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_DIV_INT_2ADDR.S b/vm/mterp/armv5te/OP_DIV_INT_2ADDR.S
new file mode 100644
index 0000000..22c8380
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"bl     __aeabi_idiv","chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_DIV_INT_LIT16.S b/vm/mterp/armv5te/OP_DIV_INT_LIT16.S
new file mode 100644
index 0000000..574594f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit16.S" {"instr":"bl     __aeabi_idiv","chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_DIV_INT_LIT8.S b/vm/mterp/armv5te/OP_DIV_INT_LIT8.S
new file mode 100644
index 0000000..8e56a4a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"instr":"bl     __aeabi_idiv","chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_DIV_LONG.S b/vm/mterp/armv5te/OP_DIV_LONG.S
new file mode 100644
index 0000000..ec5db4a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"instr":"bl      __aeabi_ldivmod", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_DIV_LONG_2ADDR.S b/vm/mterp/armv5te/OP_DIV_LONG_2ADDR.S
new file mode 100644
index 0000000..4651383
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DIV_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"instr":"bl      __aeabi_ldivmod", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/armv5te/OP_DOUBLE_TO_FLOAT.S
new file mode 100644
index 0000000..f0b1a33
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopNarrower.S" {"instr":"bl      __aeabi_d2f"}
diff --git a/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S b/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
new file mode 100644
index 0000000..3e0a26b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,54 @@
+%verify "executed"
+/* EABI appears to have Java-style conversions of +inf/-inf/NaN */
+%include "armv5te/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/armv5te/OP_DOUBLE_TO_LONG.S b/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
new file mode 100644
index 0000000..ff0fd2e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
@@ -0,0 +1,53 @@
+%verify "executed"
+@include "armv5te/unopWide.S" {"instr":"bl      __aeabi_d2lz"}
+%include "armv5te/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/armv5te/OP_EXECUTE_INLINE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
new file mode 100644
index 0000000..806eb98
--- /dev/null
+++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S
@@ -0,0 +1,98 @@
+%verify "executed"
+%verify "exception handled"
+    /*
+     * Execute a "native inline" instruction.
+     *
+     * We need to call an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     *
+     * TUNING: could maintain two tables, pointer in Thread and
+     * swap if profiler/debuggger active.
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .L${opcode}_debugmode       @ yes - take slow path
+.L${opcode}_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->retval
+    bl      .L${opcode}_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
+%break
+
+    /*
+     * 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.
+     */
+.L${opcode}_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(rINST, 2)                     @ rINST<- FEDC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  and     ip, rINST, #0xf000          @ isolate F
+    ldr     r3, [rFP, ip, lsr #10]      @ r3<- vF (shift right 12, left 2)
+3:  and     ip, rINST, #0x0f00          @ isolate E
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vE
+2:  and     ip, rINST, #0x00f0          @ isolate D
+    ldr     r1, [rFP, ip, lsr #2]       @ r1<- vD
+1:  and     ip, rINST, #0x000f          @ isolate C
+    ldr     r0, [rFP, ip, lsl #2]       @ r0<- vC
+0:
+    ldr     rINST, .L${opcode}_table    @ table of InlineOperation
+    ldr     pc, [rINST, r10, lsl #4]    @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.L${opcode}_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .L${opcode}_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->retval
+    bl      .L${opcode}_continue        @ make call; will return after
+    mov     rINST, r0                   @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, r9                      @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit @ (method, self)
+    cmp     rINST, #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
+
+
+
+
+.L${opcode}_table:
+    .word   gDvmInlineOpsTable
diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
new file mode 100644
index 0000000..bb4b0e8
--- /dev/null
+++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S
@@ -0,0 +1,93 @@
+%verify "executed"
+%verify "exception handled"
+    /*
+     * Execute a "native inline" instruction, using "/range" semantics.
+     * Same idea as execute-inline, but we get the args differently.
+     *
+     * We need to call an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     */
+    /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .L${opcode}_debugmode       @ yes - take slow path
+.L${opcode}_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    str     r1, [sp]                    @ push &self->retval
+    bl      .L${opcode}_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
+%break
+
+    /*
+     * 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]
+     */
+.L${opcode}_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(r9, 2)                        @ r9<- CCCC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  add     ip, r9, #3                  @ base+3
+    GET_VREG(r3, ip)                    @ r3<- vBase[3]
+3:  add     ip, r9, #2                  @ base+2
+    GET_VREG(r2, ip)                    @ r2<- vBase[2]
+2:  add     ip, r9, #1                  @ base+1
+    GET_VREG(r1, ip)                    @ r1<- vBase[1]
+1:  add     ip, r9, #0                  @ (nop)
+    GET_VREG(r0, ip)                    @ r0<- vBase[0]
+0:
+    ldr     r9, .L${opcode}_table       @ table of InlineOperation
+    ldr     pc, [r9, r10, lsl #4]       @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.L${opcode}_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .L${opcode}_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- B
+    mov     rINST, r9                   @ rINST<- method
+    str     r1, [sp]                    @ push &self->retval
+    bl      .L${opcode}_continue        @ make call; will return after
+    mov     r9, r0                      @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, rINST                   @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit  @ (method, self)
+    cmp     r9, #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
+
+
+
+
+.L${opcode}_table:
+    .word   gDvmInlineOpsTable
+
diff --git a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
new file mode 100644
index 0000000..f580d1c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY.S
@@ -0,0 +1,108 @@
+%default { "isrange":"0" }
+%verify "executed"
+%verify "unimplemented array type"
+    /*
+     * 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, [rSELF, #offThread_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     .L${opcode}_continue        @ yes, continue on
+8:  ldr     r3, [rSELF, #offThread_method] @ r3<- self->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       .L${opcode}_continue
+%break
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     *  r10 holds AA or BA
+     */
+.L${opcode}_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     $isrange
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .L${opcode}_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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     $isrange
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    GOTO_OPCODE(ip)                          @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.L${opcode}_notimpl:
+    ldr     r0, .L_strFilledNewArrayNotImpl_${opcode}
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_${opcode}:
+    .word   .LstrFilledNewArrayNotImpl
diff --git a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..32364f4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S
@@ -0,0 +1,85 @@
+%verify "executed"
+%verify "unimplemented array type"
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_FILLED_NEW_ARRAY.S.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    EXPORT_PC()                         @ need for resolve and alloc
+    cmp     r0, #0                      @ already resolved?
+    bne     .L${opcode}_continue        @ yes, continue on
+8:  ldr     r3, [rSELF, #offThread_method] @ r3<- self->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       .L${opcode}_continue
+%break
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     */
+.L${opcode}_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    FETCH(r1, 3)                        @ r1<- BBBB (length)
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .L${opcode}_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 4)                        @ r1<- CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(5)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC, r9=BBBB (length)
+    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
+
+2:  ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    GOTO_OPCODE(ip)                          @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.L${opcode}_notimpl:
+    ldr     r0, .L_strFilledNewArrayNotImpl_${opcode}
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_${opcode}:
+    .word   .LstrFilledNewArrayNotImpl
diff --git a/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY_RANGE.S b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY_RANGE.S
new file mode 100644
index 0000000..a2273c4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FILLED_NEW_ARRAY_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_FILLED_NEW_ARRAY.S" { "isrange":"1" }
diff --git a/vm/mterp/armv5te/OP_FILL_ARRAY_DATA.S b/vm/mterp/armv5te/OP_FILL_ARRAY_DATA.S
new file mode 100644
index 0000000..a0d8399
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FILL_ARRAY_DATA.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/armv5te/OP_FLOAT_TO_DOUBLE.S
new file mode 100644
index 0000000..b235e61
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FLOAT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWider.S" {"instr":"bl      __aeabi_f2d"}
diff --git a/vm/mterp/armv5te/OP_FLOAT_TO_INT.S b/vm/mterp/armv5te/OP_FLOAT_TO_INT.S
new file mode 100644
index 0000000..c9cb957
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FLOAT_TO_INT.S
@@ -0,0 +1,40 @@
+%verify "executed"
+/* EABI appears to have Java-style conversions of +inf/-inf/NaN */
+%include "armv5te/unop.S" {"instr":"bl      __aeabi_f2iz"}
+
+#if 0
+@include "armv5te/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/armv5te/OP_FLOAT_TO_LONG.S b/vm/mterp/armv5te/OP_FLOAT_TO_LONG.S
new file mode 100644
index 0000000..e42e1a4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_FLOAT_TO_LONG.S
@@ -0,0 +1,40 @@
+%verify "executed"
+@include "armv5te/unopWider.S" {"instr":"bl      __aeabi_f2lz"}
+%include "armv5te/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/armv5te/OP_GOTO.S b/vm/mterp/armv5te/OP_GOTO.S
new file mode 100644
index 0000000..7feca7b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_GOTO.S
@@ -0,0 +1,22 @@
+%verify "executed"
+%verify "forward and backward"
+    /*
+     * 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 */
+    /* tuning: use sbfx for 6t2+ targets */
+    mov     r0, rINST, lsl #16          @ r0<- AAxx0000
+    movs    r1, r0, asr #24             @ r1<- ssssssAA (sign-extended)
+    add     r2, r1, r1                  @ r2<- byte offset, set flags
+       @ If backwards branch refresh rIBASE
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) check for trace hotness
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_GOTO_16.S b/vm/mterp/armv5te/OP_GOTO_16.S
new file mode 100644
index 0000000..8b1f1bd
--- /dev/null
+++ b/vm/mterp/armv5te/OP_GOTO_16.S
@@ -0,0 +1,19 @@
+%verify "executed"
+%verify "forward and backward"
+    /*
+     * 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)
+    adds    r1, r0, r0                  @ r1<- byte offset, flags set
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) hot trace head?
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_GOTO_32.S b/vm/mterp/armv5te/OP_GOTO_32.S
new file mode 100644
index 0000000..6202d7e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_GOTO_32.S
@@ -0,0 +1,29 @@
+%verify "executed"
+%verify "forward, backward, self"
+    /*
+     * 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".  Because
+     * we need the V bit set, we'll use an adds to convert from Dalvik
+     * offset to byte offset.
+     */
+    /* goto/32 +AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    orr     r0, r0, r1, lsl #16         @ r0<- AAAAaaaa
+    adds    r1, r0, r0                  @ r1<- byte offset
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ble     common_testUpdateProfile    @ (r0) hot trace head?
+#else
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IF_EQ.S b/vm/mterp/armv5te/OP_IF_EQ.S
new file mode 100644
index 0000000..ecd2c55
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_EQ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/bincmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/armv5te/OP_IF_EQZ.S b/vm/mterp/armv5te/OP_IF_EQZ.S
new file mode 100644
index 0000000..2011a03
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_EQZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/zcmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/armv5te/OP_IF_GE.S b/vm/mterp/armv5te/OP_IF_GE.S
new file mode 100644
index 0000000..7424939
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_GE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/bincmp.S" { "revcmp":"lt" }
diff --git a/vm/mterp/armv5te/OP_IF_GEZ.S b/vm/mterp/armv5te/OP_IF_GEZ.S
new file mode 100644
index 0000000..2cae521
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_GEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/zcmp.S" { "revcmp":"lt" }
diff --git a/vm/mterp/armv5te/OP_IF_GT.S b/vm/mterp/armv5te/OP_IF_GT.S
new file mode 100644
index 0000000..553a74a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_GT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/bincmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/armv5te/OP_IF_GTZ.S b/vm/mterp/armv5te/OP_IF_GTZ.S
new file mode 100644
index 0000000..c82911f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_GTZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/zcmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/armv5te/OP_IF_LE.S b/vm/mterp/armv5te/OP_IF_LE.S
new file mode 100644
index 0000000..dd99709
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_LE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/bincmp.S" { "revcmp":"gt" }
diff --git a/vm/mterp/armv5te/OP_IF_LEZ.S b/vm/mterp/armv5te/OP_IF_LEZ.S
new file mode 100644
index 0000000..382c34d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_LEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/zcmp.S" { "revcmp":"gt" }
diff --git a/vm/mterp/armv5te/OP_IF_LT.S b/vm/mterp/armv5te/OP_IF_LT.S
new file mode 100644
index 0000000..34dc445
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_LT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/bincmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/armv5te/OP_IF_LTZ.S b/vm/mterp/armv5te/OP_IF_LTZ.S
new file mode 100644
index 0000000..6a0432f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_LTZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/zcmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/armv5te/OP_IF_NE.S b/vm/mterp/armv5te/OP_IF_NE.S
new file mode 100644
index 0000000..950c916
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_NE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/bincmp.S" { "revcmp":"eq" }
diff --git a/vm/mterp/armv5te/OP_IF_NEZ.S b/vm/mterp/armv5te/OP_IF_NEZ.S
new file mode 100644
index 0000000..226549c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IF_NEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/zcmp.S" { "revcmp":"eq" }
diff --git a/vm/mterp/armv5te/OP_IGET.S b/vm/mterp/armv5te/OP_IGET.S
new file mode 100644
index 0000000..a81467c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET.S
@@ -0,0 +1,47 @@
+%default { "load":"ldr", "barrier":"@ no-op ", "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, [rSELF, #offThread_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, [rSELF, #offThread_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)
+    $barrier                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IGET_BOOLEAN.S b/vm/mterp/armv5te/OP_IGET_BOOLEAN.S
new file mode 100644
index 0000000..0fbd0aa
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_BOOLEAN.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IGET.S" { "load":"ldrb", "sqnum":"1" }
+%include "armv5te/OP_IGET.S" { "load":"ldr", "sqnum":"1" }
diff --git a/vm/mterp/armv5te/OP_IGET_BOOLEAN_JUMBO.S b/vm/mterp/armv5te/OP_IGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..a1e2456
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_BOOLEAN_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrb", "sqnum":"1" }
+%include "armv5te/OP_IGET_JUMBO.S" { "load":"ldr", "sqnum":"1" }
diff --git a/vm/mterp/armv5te/OP_IGET_BYTE.S b/vm/mterp/armv5te/OP_IGET_BYTE.S
new file mode 100644
index 0000000..ef8fdfc
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_BYTE.S
@@ -0,0 +1,4 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+@include "armv5te/OP_IGET.S" { "load":"ldrsb", "sqnum":"2" }
+%include "armv5te/OP_IGET.S" { "load":"ldr", "sqnum":"2" }
diff --git a/vm/mterp/armv5te/OP_IGET_BYTE_JUMBO.S b/vm/mterp/armv5te/OP_IGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..302f67f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_BYTE_JUMBO.S
@@ -0,0 +1,4 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsb", "sqnum":"2" }
+%include "armv5te/OP_IGET_JUMBO.S" { "load":"ldr", "sqnum":"2" }
diff --git a/vm/mterp/armv5te/OP_IGET_CHAR.S b/vm/mterp/armv5te/OP_IGET_CHAR.S
new file mode 100644
index 0000000..b88b017
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_CHAR.S
@@ -0,0 +1,4 @@
+%verify "executed"
+%verify "large values are not sign-extended"
+@include "armv5te/OP_IGET.S" { "load":"ldrh", "sqnum":"3" }
+%include "armv5te/OP_IGET.S" { "load":"ldr", "sqnum":"3" }
diff --git a/vm/mterp/armv5te/OP_IGET_CHAR_JUMBO.S b/vm/mterp/armv5te/OP_IGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..c205ca6
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_CHAR_JUMBO.S
@@ -0,0 +1,4 @@
+%verify "executed"
+%verify "large values are not sign-extended"
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrh", "sqnum":"3" }
+%include "armv5te/OP_IGET_JUMBO.S" { "load":"ldr", "sqnum":"3" }
diff --git a/vm/mterp/armv5te/OP_IGET_JUMBO.S b/vm/mterp/armv5te/OP_IGET_JUMBO.S
new file mode 100644
index 0000000..6ed201f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_JUMBO.S
@@ -0,0 +1,57 @@
+%default { "load":"ldr", "barrier":"@ no-op ", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], 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, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .L${opcode}_resolved        @ resolved, continue
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to ${opcode}_finish
+
+    /*
+     * 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)
+    $barrier                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IGET_OBJECT.S b/vm/mterp/armv5te/OP_IGET_OBJECT.S
new file mode 100644
index 0000000..e5ca05f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET.S"
diff --git a/vm/mterp/armv5te/OP_IGET_OBJECT_JUMBO.S b/vm/mterp/armv5te/OP_IGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..d1260fe
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_OBJECT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_IGET_OBJECT_QUICK.S b/vm/mterp/armv5te/OP_IGET_OBJECT_QUICK.S
new file mode 100644
index 0000000..727b2aa
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_OBJECT_QUICK.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_QUICK.S"
diff --git a/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..acf9ac0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..fb4bf63
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_OBJECT_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IGET_QUICK.S b/vm/mterp/armv5te/OP_IGET_QUICK.S
new file mode 100644
index 0000000..c19f870
--- /dev/null
+++ b/vm/mterp/armv5te/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
+    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
diff --git a/vm/mterp/armv5te/OP_IGET_SHORT.S b/vm/mterp/armv5te/OP_IGET_SHORT.S
new file mode 100644
index 0000000..a1b60b1
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_SHORT.S
@@ -0,0 +1,4 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+@include "armv5te/OP_IGET.S" { "load":"ldrsh", "sqnum":"4" }
+%include "armv5te/OP_IGET.S" { "load":"ldr", "sqnum":"4" }
diff --git a/vm/mterp/armv5te/OP_IGET_SHORT_JUMBO.S b/vm/mterp/armv5te/OP_IGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..81c2f77
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_SHORT_JUMBO.S
@@ -0,0 +1,4 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsh", "sqnum":"4" }
+%include "armv5te/OP_IGET_JUMBO.S" { "load":"ldr", "sqnum":"4" }
diff --git a/vm/mterp/armv5te/OP_IGET_VOLATILE.S b/vm/mterp/armv5te/OP_IGET_VOLATILE.S
new file mode 100644
index 0000000..acf9ac0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IGET_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_IGET_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..6d2b5ff
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE.S b/vm/mterp/armv5te/OP_IGET_WIDE.S
new file mode 100644
index 0000000..c73edfd
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_WIDE.S
@@ -0,0 +1,49 @@
+%default {"volatile":"0"}
+%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, [rSELF, #offThread_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, [rSELF, #offThread_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
+    .if     $volatile
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE_JUMBO.S b/vm/mterp/armv5te/OP_IGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..40a6a96
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_WIDE_JUMBO.S
@@ -0,0 +1,58 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], 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
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .L${opcode}_resolved        @ resolved, continue
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to ${opcode}_finish
+
+    /*
+     * 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
+    .if     $volatile
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE_QUICK.S b/vm/mterp/armv5te/OP_IGET_WIDE_QUICK.S
new file mode 100644
index 0000000..b32e429
--- /dev/null
+++ b/vm/mterp/armv5te/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
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    FETCH(ip, 1)                        @ ip<- 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, ip]                @ 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
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..face363
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..c38a73d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IGET_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_INSTANCE_OF.S b/vm/mterp/armv5te/OP_INSTANCE_OF.S
new file mode 100644
index 0000000..73911b1
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INSTANCE_OF.S
@@ -0,0 +1,85 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * 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, [rSELF, #offThread_methodClassDex]    @ r2<- pDvmDex
+    beq     .L${opcode}_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     .L${opcode}_resolve         @ not resolved, do it now
+.L${opcode}_resolved: @ r0=obj->clazz, r1=resolved class
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .L${opcode}_trivial         @ yes, trivial finish
+    b       .L${opcode}_fullcheck       @ no, do full check
+%break
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from BBBB
+     *  r9 holds A
+     */
+.L${opcode}_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to ${opcode}_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds A
+     */
+.L${opcode}_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
+     */
+.L${opcode}_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b ${opcode}_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
+     */
+.L${opcode}_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->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       .L${opcode}_resolved        @ pick up where we left off
diff --git a/vm/mterp/armv5te/OP_INSTANCE_OF_JUMBO.S b/vm/mterp/armv5te/OP_INSTANCE_OF_JUMBO.S
new file mode 100644
index 0000000..1de1222
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INSTANCE_OF_JUMBO.S
@@ -0,0 +1,98 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * 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.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_INSTANCE_OF.S.
+     */
+    /* instance-of/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    FETCH(r9, 3)                        @ r9<- vBBBB
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- pDvmDex
+    cmp     r0, #0                      @ is object null?
+    beq     .L${opcode}_store           @ null obj, not an instance, store r0
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]    @ r2<- pDvmDex->pResClasses
+    orr     r3, r1, r3, lsl #16         @ r3<- AAAAaaaa
+    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     .L${opcode}_resolve         @ not resolved, do it now
+    b       .L${opcode}_resolved        @ resolved, continue
+%break
+
+    /*
+     * Class resolved, determine type of check necessary.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.L${opcode}_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .L${opcode}_trivial         @ yes, trivial finish
+    @ fall through to ${opcode}_fullcheck
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.L${opcode}_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to ${opcode}_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds BBBB
+     */
+.L${opcode}_store:
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.L${opcode}_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b ${opcode}_store, but copying is faster and cheaper
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- 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 AAAAAAAA
+     *  r9 holds BBBB
+     */
+
+.L${opcode}_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    mov     r1, r3                      @ r1<- AAAAAAAA
+    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
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    mov     r1, r0                      @ r1<- class resolved from AAAAAAAA
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    b       .L${opcode}_resolved        @ pick up where we left off
diff --git a/vm/mterp/armv5te/OP_INT_TO_BYTE.S b/vm/mterp/armv5te/OP_INT_TO_BYTE.S
new file mode 100644
index 0000000..cf1c981
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INT_TO_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"preinstr":"mov     r0, r0, asl #24", "instr":"mov     r0, r0, asr #24"}
diff --git a/vm/mterp/armv5te/OP_INT_TO_CHAR.S b/vm/mterp/armv5te/OP_INT_TO_CHAR.S
new file mode 100644
index 0000000..568cf08
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INT_TO_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"preinstr":"mov     r0, r0, asl #16", "instr":"mov     r0, r0, lsr #16"}
diff --git a/vm/mterp/armv5te/OP_INT_TO_DOUBLE.S b/vm/mterp/armv5te/OP_INT_TO_DOUBLE.S
new file mode 100644
index 0000000..8b00b64
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWider.S" {"instr":"bl      __aeabi_i2d"}
diff --git a/vm/mterp/armv5te/OP_INT_TO_FLOAT.S b/vm/mterp/armv5te/OP_INT_TO_FLOAT.S
new file mode 100644
index 0000000..53d49df
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INT_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"bl      __aeabi_i2f"}
diff --git a/vm/mterp/armv5te/OP_INT_TO_LONG.S b/vm/mterp/armv5te/OP_INT_TO_LONG.S
new file mode 100644
index 0000000..b744439
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INT_TO_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWider.S" {"instr":"mov     r1, r0, asr #31"}
diff --git a/vm/mterp/armv5te/OP_INT_TO_SHORT.S b/vm/mterp/armv5te/OP_INT_TO_SHORT.S
new file mode 100644
index 0000000..b6deb85
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INT_TO_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"preinstr":"mov     r0, r0, asl #16", "instr":"mov     r0, r0, asr #16"}
diff --git a/vm/mterp/armv5te/OP_INVOKE_DIRECT.S b/vm/mterp/armv5te/OP_INVOKE_DIRECT.S
new file mode 100644
index 0000000..7167a2b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_DIRECT.S
@@ -0,0 +1,46 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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, [rSELF, #offThread_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     (!$isrange)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    beq     .L${opcode}_resolve         @ not resolved, do it now
+.L${opcode}_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethod${routine}   @ r0=method, r9="this"
+    b       common_errNullObject        @ yes, throw exception
+%break
+
+    /*
+     * On entry:
+     *  r1 = reference (BBBB or CCCC)
+     *  r10 = "this" register
+     */
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .L${opcode}_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
diff --git a/vm/mterp/armv5te/OP_INVOKE_DIRECT_JUMBO.S b/vm/mterp/armv5te/OP_INVOKE_DIRECT_JUMBO.S
new file mode 100644
index 0000000..7f6c435
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_DIRECT_JUMBO.S
@@ -0,0 +1,42 @@
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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.)
+     *
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    beq     .L${opcode}_resolve         @ not resolved, do it now
+.L${opcode}_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodJumbo    @ (r0=method, r9="this")
+    b       common_errNullObject        @ yes, throw exception
+%break
+
+    /*
+     * On entry:
+     *  r1 = reference (CCCC)
+     *  r10 = "this" register
+     */
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .L${opcode}_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
diff --git a/vm/mterp/armv5te/OP_INVOKE_DIRECT_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_DIRECT_RANGE.S
new file mode 100644
index 0000000..0b799e5
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_DIRECT_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_DIRECT.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S b/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S
new file mode 100644
index 0000000..5ed35a8
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_INTERFACE.S
@@ -0,0 +1,27 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * 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     (!$isrange)
+    and     r2, r2, #15                 @ r2<- C (or stays CCCC)
+    .endif
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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_invokeMethod${routine} @ (r0=method, r9="this")
diff --git a/vm/mterp/armv5te/OP_INVOKE_INTERFACE_JUMBO.S b/vm/mterp/armv5te/OP_INVOKE_INTERFACE_JUMBO.S
new file mode 100644
index 0000000..34ccf86
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_INTERFACE_JUMBO.S
@@ -0,0 +1,22 @@
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * Handle an interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r2, 4)                        @ r2<- CCCC
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    EXPORT_PC()                         @ must export for invoke
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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_invokeMethodJumbo    @ (r0=method, r9="this")
diff --git a/vm/mterp/armv5te/OP_INVOKE_INTERFACE_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_INTERFACE_RANGE.S
new file mode 100644
index 0000000..f1eb27d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_INTERFACE_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_INTERFACE.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S b/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S
new file mode 100644
index 0000000..c0d7320
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S" {"jumbo":"1", "cccc":"4"}
diff --git a/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S
new file mode 100644
index 0000000..fb0e657
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S
@@ -0,0 +1,48 @@
+%default { "jumbo":"0", "cccc":"2" }
+%verify "executed"
+%verify "finalizable class"
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, ${cccc})                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .L${opcode}_setFinal        @ yes, go
+.L${opcode}_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .L${opcode}_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(${cccc}+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+%break
+
+.L${opcode}_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .L${opcode}_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.L${opcode}_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if $jumbo
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
diff --git a/vm/mterp/armv5te/OP_INVOKE_STATIC.S b/vm/mterp/armv5te/OP_INVOKE_STATIC.S
new file mode 100644
index 0000000..a89db03
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_STATIC.S
@@ -0,0 +1,54 @@
+%default { "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethod${routine} @ yes, continue on
+    b       .L${opcode}_resolve
+%break
+
+
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethod${routine}     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethod${routine}     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethod${routine}     @ whew, finally!
+#else
+    bne     common_invokeMethod${routine}     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
diff --git a/vm/mterp/armv5te/OP_INVOKE_STATIC_JUMBO.S b/vm/mterp/armv5te/OP_INVOKE_STATIC_JUMBO.S
new file mode 100644
index 0000000..171127d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_STATIC_JUMBO.S
@@ -0,0 +1,51 @@
+%verify "executed"
+%verify "unknown method"
+    /*
+     * Handle a static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodJumboNoThis   @ (r0=method)
+    b       .L${opcode}_resolve
+%break
+
+
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodJumboNoThis    @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodJumboNoThis    @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodJumboNoThis    @ whew, finally!
+#else
+    bne     common_invokeMethodJumboNoThis    @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
diff --git a/vm/mterp/armv5te/OP_INVOKE_STATIC_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_STATIC_RANGE.S
new file mode 100644
index 0000000..92b9ca5
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_STATIC_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_STATIC.S" { "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER.S b/vm/mterp/armv5te/OP_INVOKE_SUPER.S
new file mode 100644
index 0000000..b1d1411
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER.S
@@ -0,0 +1,60 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    .if     (!$isrange)
+    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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .L${opcode}_continue        @ resolved, continue on
+    b       .L${opcode}_resolve         @ do resolve now
+%break
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.L${opcode}_continue:
+    ldr     r1, [r10, #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     .L${opcode}_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_invokeMethod${routine} @ continue on
+
+.L${opcode}_resolve:
+    mov     r0, r10                     @ r0<- method->clazz
+    mov     r2, #METHOD_VIRTUAL         @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     .L${opcode}_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  r0 = resolved base method
+     */
+.L${opcode}_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER_JUMBO.S b/vm/mterp/armv5te/OP_INVOKE_SUPER_JUMBO.S
new file mode 100644
index 0000000..26ea063
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER_JUMBO.S
@@ -0,0 +1,55 @@
+%verify "executed"
+%verify "unknown method"
+    /*
+     * Handle a "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .L${opcode}_continue        @ resolved, continue on
+    b       .L${opcode}_resolve         @ do resolve now
+%break
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.L${opcode}_continue:
+    ldr     r1, [r10, #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     .L${opcode}_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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+.L${opcode}_resolve:
+    mov     r0, r10                     @ r0<- method->clazz
+    mov     r2, #METHOD_VIRTUAL         @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     .L${opcode}_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  r0 = resolved base method
+     */
+.L${opcode}_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S
new file mode 100644
index 0000000..4848b7e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK.S
@@ -0,0 +1,25 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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, [rSELF, #offThread_method]    @ r2<- current method
+    .if     (!$isrange)
+    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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #0                      @ null "this" ref?
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- super->vtable[BBBB]
+    beq     common_errNullObject        @ "this" is null, throw exception
+    bl      common_invokeMethod${routine} @ (r0=method, r9="this")
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S
new file mode 100644
index 0000000..77d43cb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_SUPER_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_INVOKE_SUPER_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_SUPER_RANGE.S
new file mode 100644
index 0000000..0a0f737
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_SUPER_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_SUPER.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S
new file mode 100644
index 0000000..58b0a42
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL.S
@@ -0,0 +1,45 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * 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, [rSELF, #offThread_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     (!$isrange)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .L${opcode}_continue        @ yes, continue on
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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     .L${opcode}_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+%break
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = C or CCCC (index of first arg, which is the "this" ptr)
+     */
+.L${opcode}_continue:
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethod${routine} @ (r0=method, r9="this")
diff --git a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_JUMBO.S b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_JUMBO.S
new file mode 100644
index 0000000..ba0184e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_JUMBO.S
@@ -0,0 +1,39 @@
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * Handle a virtual method call.
+     */
+    /* invoke-virtual/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .L${opcode}_continue        @ yes, continue on
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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     .L${opcode}_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+%break
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     */
+.L${opcode}_continue:
+    FETCH(r10, 4)                       @ r10<- CCCC
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodJumbo    @ (r0=method, r9="this")
diff --git a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_QUICK.S
new file mode 100644
index 0000000..4b425da
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_QUICK.S
@@ -0,0 +1,23 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "null object"
+    /*
+     * 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     (!$isrange)
+    and     r3, r3, #15                 @ r3<- C (or stays CCCC)
+    .endif
+    GET_VREG(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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_invokeMethod${routine} @ (r0=method, r9="this")
diff --git a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
new file mode 100644
index 0000000..d257f2b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_VIRTUAL_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_RANGE.S b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_RANGE.S
new file mode 100644
index 0000000..4f9ca50
--- /dev/null
+++ b/vm/mterp/armv5te/OP_INVOKE_VIRTUAL_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_INVOKE_VIRTUAL.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/armv5te/OP_IPUT.S b/vm/mterp/armv5te/OP_IPUT.S
new file mode 100644
index 0000000..72c05c0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT.S
@@ -0,0 +1,48 @@
+%default { "store":"str", "postbarrier":"@ no-op ", "prebarrier":"@ no-op ", "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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .L${opcode}_finish          @ yes, finish up
+    b       common_exceptionThrown
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_finish:
+    @bl      common_squeak${sqnum}
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    $store  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    $postbarrier
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_BOOLEAN.S b/vm/mterp/armv5te/OP_IPUT_BOOLEAN.S
new file mode 100644
index 0000000..9ac68ca
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_BOOLEAN.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"1" }
+%include "armv5te/OP_IPUT.S" { "store":"str", "sqnum":"1" }
diff --git a/vm/mterp/armv5te/OP_IPUT_BOOLEAN_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..9d89c9a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"1" }
+%include "armv5te/OP_IPUT_JUMBO.S" { "store":"str", "sqnum":"1" }
diff --git a/vm/mterp/armv5te/OP_IPUT_BYTE.S b/vm/mterp/armv5te/OP_IPUT_BYTE.S
new file mode 100644
index 0000000..3871999
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_BYTE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"2" }
+%include "armv5te/OP_IPUT.S" { "store":"str", "sqnum":"2" }
diff --git a/vm/mterp/armv5te/OP_IPUT_BYTE_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..8378f49
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_BYTE_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"2" }
+%include "armv5te/OP_IPUT_JUMBO.S" { "store":"str", "sqnum":"2" }
diff --git a/vm/mterp/armv5te/OP_IPUT_CHAR.S b/vm/mterp/armv5te/OP_IPUT_CHAR.S
new file mode 100644
index 0000000..60e136c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_CHAR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"3" }
+%include "armv5te/OP_IPUT.S" { "store":"str", "sqnum":"3" }
diff --git a/vm/mterp/armv5te/OP_IPUT_CHAR_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..9d6a5b0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_CHAR_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"3" }
+%include "armv5te/OP_IPUT_JUMBO.S" { "store":"str", "sqnum":"3" }
diff --git a/vm/mterp/armv5te/OP_IPUT_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_JUMBO.S
new file mode 100644
index 0000000..21f154c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_JUMBO.S
@@ -0,0 +1,58 @@
+%default { "store":"str", "postbarrier":"@ no-op ", "prebarrier":"@ no-op ", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], 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, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .L${opcode}_resolved        @ resolved, continue
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to ${opcode}_finish
+
+    /*
+     * 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
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                         @ releasing store
+    $store  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    $postbarrier
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT.S b/vm/mterp/armv5te/OP_IPUT_OBJECT.S
new file mode 100644
index 0000000..a514f04
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT.S
@@ -0,0 +1,51 @@
+%default { "postbarrier":"@ no-op ", "prebarrier":"@ no-op ", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .L${opcode}_finish          @ yes, finish up
+    b       common_exceptionThrown
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_finish:
+    @bl      common_squeak${sqnum}
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    $postbarrier
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..6d1e6a7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_JUMBO.S
@@ -0,0 +1,58 @@
+%default { "postbarrier":"@ no-op ", "prebarrier":"@ no-op ", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], 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, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .L${opcode}_resolved        @ resolved, continue
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to ${opcode}_finish
+
+    /*
+     * 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
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    $postbarrier
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
new file mode 100644
index 0000000..7bf9b21
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_QUICK.S
@@ -0,0 +1,19 @@
+%verify "executed"
+%verify "null object"
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card based on obj head
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..317c5b2
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_OBJECT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..4ae11ae
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_OBJECT_JUMBO.S"  {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_QUICK.S b/vm/mterp/armv5te/OP_IPUT_QUICK.S
new file mode 100644
index 0000000..ad76eca
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+    /* For: iput-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    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
diff --git a/vm/mterp/armv5te/OP_IPUT_SHORT.S b/vm/mterp/armv5te/OP_IPUT_SHORT.S
new file mode 100644
index 0000000..4844575
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_SHORT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"4" }
+%include "armv5te/OP_IPUT.S" { "store":"str", "sqnum":"4" }
diff --git a/vm/mterp/armv5te/OP_IPUT_SHORT_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..889c723
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_SHORT_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"4" }
+%include "armv5te/OP_IPUT_JUMBO.S" { "store":"str", "sqnum":"4" }
diff --git a/vm/mterp/armv5te/OP_IPUT_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_VOLATILE.S
new file mode 100644
index 0000000..1a7a098
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..0a7e2fe
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_JUMBO.S"  {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE.S b/vm/mterp/armv5te/OP_IPUT_WIDE.S
new file mode 100644
index 0000000..ec787f0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE.S
@@ -0,0 +1,46 @@
+%default {"volatile":"0"}
+%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, [rSELF, #offThread_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, [rSELF, #offThread_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:
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    cmp     r9, #0                      @ check object for null
+    and     r2, r2, #15                 @ r2<- A
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[A]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     $volatile
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..d5e557a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE_JUMBO.S
@@ -0,0 +1,55 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    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, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .L${opcode}_resolved        @ resolved, continue
+%break
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to ${opcode}_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.L${opcode}_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     $volatile
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S b/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S
new file mode 100644
index 0000000..b7dd703
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..944811b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..53b1030
--- /dev/null
+++ b/vm/mterp/armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_IPUT_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_LONG_TO_DOUBLE.S b/vm/mterp/armv5te/OP_LONG_TO_DOUBLE.S
new file mode 100644
index 0000000..842a8ff
--- /dev/null
+++ b/vm/mterp/armv5te/OP_LONG_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWide.S" {"instr":"bl      __aeabi_l2d"}
diff --git a/vm/mterp/armv5te/OP_LONG_TO_FLOAT.S b/vm/mterp/armv5te/OP_LONG_TO_FLOAT.S
new file mode 100644
index 0000000..ba250cb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_LONG_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopNarrower.S" {"instr":"bl      __aeabi_l2f"}
diff --git a/vm/mterp/armv5te/OP_LONG_TO_INT.S b/vm/mterp/armv5te/OP_LONG_TO_INT.S
new file mode 100644
index 0000000..4509546
--- /dev/null
+++ b/vm/mterp/armv5te/OP_LONG_TO_INT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+%include "armv5te/OP_MOVE.S"
diff --git a/vm/mterp/armv5te/OP_MONITOR_ENTER.S b/vm/mterp/armv5te/OP_MONITOR_ENTER.S
new file mode 100644
index 0000000..ba5a144
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MONITOR_ENTER.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "exception for null object"
+    /*
+     * Synchronize on an object.
+     */
+    /* monitor-enter vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    GET_VREG(r1, r2)                    @ r1<- vAA (object)
+    mov     r0, rSELF                   @ r0<- self
+    cmp     r1, #0                      @ null object?
+    EXPORT_PC()                         @ need for precise GC
+    beq     common_errNullObject        @ null object, throw an exception
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      dvmLockObject               @ call(self, obj)
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_MONITOR_EXIT.S b/vm/mterp/armv5te/OP_MONITOR_EXIT.S
new file mode 100644
index 0000000..9f36f0e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MONITOR_EXIT.S
@@ -0,0 +1,26 @@
+%verify "executed"
+%verify "exception for null object (impossible in javac)"
+%verify "dvmUnlockObject fails"
+    /*
+     * 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     1f                          @ yes
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
+    cmp     r0, #0                      @ failed?
+    FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
diff --git a/vm/mterp/armv5te/OP_MOVE.S b/vm/mterp/armv5te/OP_MOVE.S
new file mode 100644
index 0000000..efeddf4
--- /dev/null
+++ b/vm/mterp/armv5te/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
+    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
diff --git a/vm/mterp/armv5te/OP_MOVE_16.S b/vm/mterp/armv5te/OP_MOVE_16.S
new file mode 100644
index 0000000..3c08759
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S b/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S
new file mode 100644
index 0000000..e2fc66f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_EXCEPTION.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* move-exception vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    ldr     r3, [rSELF, #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, [rSELF, #offThread_exception]  @ dvmClearException bypass
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_MOVE_FROM16.S b/vm/mterp/armv5te/OP_MOVE_FROM16.S
new file mode 100644
index 0000000..fdcc64e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_FROM16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_MOVE_OBJECT.S b/vm/mterp/armv5te/OP_MOVE_OBJECT.S
new file mode 100644
index 0000000..0cd09df
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_MOVE.S"
diff --git a/vm/mterp/armv5te/OP_MOVE_OBJECT_16.S b/vm/mterp/armv5te/OP_MOVE_OBJECT_16.S
new file mode 100644
index 0000000..9f0f1a9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_OBJECT_16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_MOVE_16.S"
diff --git a/vm/mterp/armv5te/OP_MOVE_OBJECT_FROM16.S b/vm/mterp/armv5te/OP_MOVE_OBJECT_FROM16.S
new file mode 100644
index 0000000..c331a82
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_OBJECT_FROM16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_MOVE_FROM16.S"
diff --git a/vm/mterp/armv5te/OP_MOVE_RESULT.S b/vm/mterp/armv5te/OP_MOVE_RESULT.S
new file mode 100644
index 0000000..72377f8
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_RESULT.S
@@ -0,0 +1,9 @@
+%verify "executed"
+    /* 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, [rSELF, #offThread_retval]    @ r0<- self->retval.i
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[AA]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_MOVE_RESULT_OBJECT.S b/vm/mterp/armv5te/OP_MOVE_RESULT_OBJECT.S
new file mode 100644
index 0000000..a04cdb4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_RESULT_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_MOVE_RESULT.S"
diff --git a/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S b/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S
new file mode 100644
index 0000000..4eb0198
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_RESULT_WIDE.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* move-result-wide vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    add     r3, rSELF, #offThread_retval  @ r3<- &self->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
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE.S b/vm/mterp/armv5te/OP_MOVE_WIDE.S
new file mode 100644
index 0000000..05151e1
--- /dev/null
+++ b/vm/mterp/armv5te/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     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
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE_16.S b/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
new file mode 100644
index 0000000..172ef03
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S b/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S
new file mode 100644
index 0000000..81ae7dc
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MOVE_WIDE_FROM16.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /* 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
diff --git a/vm/mterp/armv5te/OP_MUL_DOUBLE.S b/vm/mterp/armv5te/OP_MUL_DOUBLE.S
new file mode 100644
index 0000000..69a10f9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"instr":"bl      __aeabi_dmul"}
diff --git a/vm/mterp/armv5te/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/armv5te/OP_MUL_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..2201414
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"instr":"bl      __aeabi_dmul"}
diff --git a/vm/mterp/armv5te/OP_MUL_FLOAT.S b/vm/mterp/armv5te/OP_MUL_FLOAT.S
new file mode 100644
index 0000000..13e64e0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"bl      __aeabi_fmul"}
diff --git a/vm/mterp/armv5te/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/armv5te/OP_MUL_FLOAT_2ADDR.S
new file mode 100644
index 0000000..d97e80f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"bl      __aeabi_fmul"}
diff --git a/vm/mterp/armv5te/OP_MUL_INT.S b/vm/mterp/armv5te/OP_MUL_INT.S
new file mode 100644
index 0000000..252114b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_INT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+%include "armv5te/binop.S" {"instr":"mul     r0, r1, r0"}
diff --git a/vm/mterp/armv5te/OP_MUL_INT_2ADDR.S b/vm/mterp/armv5te/OP_MUL_INT_2ADDR.S
new file mode 100644
index 0000000..a5a3754
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_INT_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+%include "armv5te/binop2addr.S" {"instr":"mul     r0, r1, r0"}
diff --git a/vm/mterp/armv5te/OP_MUL_INT_LIT16.S b/vm/mterp/armv5te/OP_MUL_INT_LIT16.S
new file mode 100644
index 0000000..1a28d8b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_INT_LIT16.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+%include "armv5te/binopLit16.S" {"instr":"mul     r0, r1, r0"}
diff --git a/vm/mterp/armv5te/OP_MUL_INT_LIT8.S b/vm/mterp/armv5te/OP_MUL_INT_LIT8.S
new file mode 100644
index 0000000..e714ed9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_INT_LIT8.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+%include "armv5te/binopLit8.S" {"instr":"mul     r0, r1, r0"}
diff --git a/vm/mterp/armv5te/OP_MUL_LONG.S b/vm/mterp/armv5te/OP_MUL_LONG.S
new file mode 100644
index 0000000..3a7aac1
--- /dev/null
+++ b/vm/mterp/armv5te/OP_MUL_LONG.S
@@ -0,0 +1,41 @@
+%verify "executed"
+    /*
+     * 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       .L${opcode}_finish
+%break
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_MUL_LONG_2ADDR.S b/vm/mterp/armv5te/OP_MUL_LONG_2ADDR.S
new file mode 100644
index 0000000..a561dc9
--- /dev/null
+++ b/vm/mterp/armv5te/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     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
diff --git a/vm/mterp/armv5te/OP_NEG_DOUBLE.S b/vm/mterp/armv5te/OP_NEG_DOUBLE.S
new file mode 100644
index 0000000..d371016
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEG_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWide.S" {"instr":"add     r1, r1, #0x80000000"}
diff --git a/vm/mterp/armv5te/OP_NEG_FLOAT.S b/vm/mterp/armv5te/OP_NEG_FLOAT.S
new file mode 100644
index 0000000..81b439c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"add     r0, r0, #0x80000000"}
diff --git a/vm/mterp/armv5te/OP_NEG_INT.S b/vm/mterp/armv5te/OP_NEG_INT.S
new file mode 100644
index 0000000..2f57540
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEG_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"rsb     r0, r0, #0"}
diff --git a/vm/mterp/armv5te/OP_NEG_LONG.S b/vm/mterp/armv5te/OP_NEG_LONG.S
new file mode 100644
index 0000000..215f056
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEG_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWide.S" {"preinstr":"rsbs    r0, r0, #0", "instr":"rsc     r1, r1, #0"}
diff --git a/vm/mterp/armv5te/OP_NEW_ARRAY.S b/vm/mterp/armv5te/OP_NEW_ARRAY.S
new file mode 100644
index 0000000..eca1ac6
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEW_ARRAY.S
@@ -0,0 +1,61 @@
+%verify "executed"
+%verify "negative array length"
+%verify "allocation fails"
+    /*
+     * 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, [rSELF, #offThread_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 - len in r1
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .L${opcode}_finish          @ resolved, continue
+    b       .L${opcode}_resolve         @ do resolve now
+%break
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref CCCC
+     */
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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 ${opcode}_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_NEW_ARRAY_JUMBO.S b/vm/mterp/armv5te/OP_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..568afb4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEW_ARRAY_JUMBO.S
@@ -0,0 +1,62 @@
+%verify "executed"
+%verify "negative array length"
+%verify "allocation fails"
+    /*
+     * 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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r2, 1)                        @ r2<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- vCCCC
+    orr     r2, r2, r3, lsl #16         @ r2<- AAAAaaaa
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    GET_VREG(r1, r0)                    @ r1<- vCCCC (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 - len in r1
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .L${opcode}_finish          @ resolved, continue
+    b       .L${opcode}_resolve         @ do resolve now
+%break
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref AAAAAAAA
+     */
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r9, r1                      @ r9<- length (save)
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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 ${opcode}_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.L${opcode}_finish:
+    mov     r2, #ALLOC_DONT_TRACK       @ don't track in local refs table
+    bl      dvmAllocArrayByClass        @ r0<- call(clazz, length, flags)
+    cmp     r0, #0                      @ failed?
+    FETCH(r2, 3)                        @ r2<- vBBBB
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_NEW_INSTANCE.S b/vm/mterp/armv5te/OP_NEW_INSTANCE.S
new file mode 100644
index 0000000..e280c4c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEW_INSTANCE.S
@@ -0,0 +1,101 @@
+%verify "executed"
+%verify "class not resolved"
+%verify "class cannot be resolved"
+%verify "class not initialized"
+%verify "class fails to initialize"
+%verify "class already resolved/initialized"
+%verify "class is abstract or interface"
+%verify "allocation fails"
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance vAA, class@BBBB */
+    ldr     r3, [rSELF, #offThread_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
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .L${opcode}_resolve         @ no, resolve it now
+.L${opcode}_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .L${opcode}_needinit        @ no, init class now
+.L${opcode}_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .L${opcode}_finish          @ continue
+%break
+
+    .balign 32                          @ minimize cache lines
+.L${opcode}_finish: @ r0=new object
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    cmp     r0, #0                      @ failed?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .L${opcode}_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.L${opcode}_end:
+    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
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.L${opcode}_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .L${opcode}_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.L${opcode}_needinit:
+    mov     r9, r0                      @ save r0
+    bl      dvmInitClass                @ initialize class
+    cmp     r0, #0                      @ check boolean result
+    mov     r0, r9                      @ restore r0
+    bne     .L${opcode}_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds BBBB
+     */
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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     .L${opcode}_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
diff --git a/vm/mterp/armv5te/OP_NEW_INSTANCE_JUMBO.S b/vm/mterp/armv5te/OP_NEW_INSTANCE_JUMBO.S
new file mode 100644
index 0000000..ce41bf3
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NEW_INSTANCE_JUMBO.S
@@ -0,0 +1,103 @@
+%verify "executed"
+%verify "class not resolved"
+%verify "class cannot be resolved"
+%verify "class not initialized"
+%verify "class fails to initialize"
+%verify "class already resolved/initialized"
+%verify "class is abstract or interface"
+%verify "allocation fails"
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .L${opcode}_resolve         @ no, resolve it now
+.L${opcode}_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .L${opcode}_needinit        @ no, init class now
+.L${opcode}_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .L${opcode}_finish          @ continue
+%break
+
+    .balign 32                          @ minimize cache lines
+.L${opcode}_finish: @ r0=new object
+    FETCH(r3, 3)                        @ r3<- BBBB
+    cmp     r0, #0                      @ failed?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .L${opcode}_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.L${opcode}_end:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.L${opcode}_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .L${opcode}_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.L${opcode}_needinit:
+    mov     r9, r0                      @ save r0
+    bl      dvmInitClass                @ initialize class
+    cmp     r0, #0                      @ check boolean result
+    mov     r0, r9                      @ restore r0
+    bne     .L${opcode}_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds AAAAAAAA
+     */
+.L${opcode}_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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     .L${opcode}_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
diff --git a/vm/mterp/armv5te/OP_NOP.S b/vm/mterp/armv5te/OP_NOP.S
new file mode 100644
index 0000000..ff4cf5a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NOP.S
@@ -0,0 +1,14 @@
+%verify "executed"
+    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
diff --git a/vm/mterp/armv5te/OP_NOT_INT.S b/vm/mterp/armv5te/OP_NOT_INT.S
new file mode 100644
index 0000000..7281cbe
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NOT_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"mvn     r0, r0"}
diff --git a/vm/mterp/armv5te/OP_NOT_LONG.S b/vm/mterp/armv5te/OP_NOT_LONG.S
new file mode 100644
index 0000000..fe741dd
--- /dev/null
+++ b/vm/mterp/armv5te/OP_NOT_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unopWide.S" {"preinstr":"mvn     r0, r0", "instr":"mvn     r1, r1"}
diff --git a/vm/mterp/armv5te/OP_OR_INT.S b/vm/mterp/armv5te/OP_OR_INT.S
new file mode 100644
index 0000000..f0e5b2d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_OR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"orr     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_OR_INT_2ADDR.S b/vm/mterp/armv5te/OP_OR_INT_2ADDR.S
new file mode 100644
index 0000000..3b2cf7f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_OR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"orr     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_OR_INT_LIT16.S b/vm/mterp/armv5te/OP_OR_INT_LIT16.S
new file mode 100644
index 0000000..9098c76
--- /dev/null
+++ b/vm/mterp/armv5te/OP_OR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit16.S" {"instr":"orr     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_OR_INT_LIT8.S b/vm/mterp/armv5te/OP_OR_INT_LIT8.S
new file mode 100644
index 0000000..b69e315
--- /dev/null
+++ b/vm/mterp/armv5te/OP_OR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"instr":"orr     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_OR_LONG.S b/vm/mterp/armv5te/OP_OR_LONG.S
new file mode 100644
index 0000000..43110a2
--- /dev/null
+++ b/vm/mterp/armv5te/OP_OR_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"preinstr":"orr     r0, r0, r2", "instr":"orr     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_OR_LONG_2ADDR.S b/vm/mterp/armv5te/OP_OR_LONG_2ADDR.S
new file mode 100644
index 0000000..97d5f5b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_OR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"preinstr":"orr     r0, r0, r2", "instr":"orr     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_PACKED_SWITCH.S b/vm/mterp/armv5te/OP_PACKED_SWITCH.S
new file mode 100644
index 0000000..6fa03c1
--- /dev/null
+++ b/vm/mterp/armv5te/OP_PACKED_SWITCH.S
@@ -0,0 +1,35 @@
+%default { "func":"dvmInterpHandlePackedSwitch" }
+%verify executed
+    /*
+     * 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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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      $func                       @ r0<- code-unit branch offset
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/OP_REM_DOUBLE.S b/vm/mterp/armv5te/OP_REM_DOUBLE.S
new file mode 100644
index 0000000..54e0214
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_DOUBLE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* EABI doesn't define a double remainder function, but libm does */
+%include "armv5te/binopWide.S" {"instr":"bl      fmod"}
diff --git a/vm/mterp/armv5te/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/armv5te/OP_REM_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..9808c56
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_DOUBLE_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* EABI doesn't define a double remainder function, but libm does */
+%include "armv5te/binopWide2addr.S" {"instr":"bl      fmod"}
diff --git a/vm/mterp/armv5te/OP_REM_FLOAT.S b/vm/mterp/armv5te/OP_REM_FLOAT.S
new file mode 100644
index 0000000..09cba5c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_FLOAT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* EABI doesn't define a float remainder function, but libm does */
+%include "armv5te/binop.S" {"instr":"bl      fmodf"}
diff --git a/vm/mterp/armv5te/OP_REM_FLOAT_2ADDR.S b/vm/mterp/armv5te/OP_REM_FLOAT_2ADDR.S
new file mode 100644
index 0000000..83af133
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_FLOAT_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* EABI doesn't define a float remainder function, but libm does */
+%include "armv5te/binop2addr.S" {"instr":"bl      fmodf"}
diff --git a/vm/mterp/armv5te/OP_REM_INT.S b/vm/mterp/armv5te/OP_REM_INT.S
new file mode 100644
index 0000000..fbe9ad3
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_INT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* idivmod returns quotient in r0 and remainder in r1 */
+%include "armv5te/binop.S" {"instr":"bl      __aeabi_idivmod", "result":"r1", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_REM_INT_2ADDR.S b/vm/mterp/armv5te/OP_REM_INT_2ADDR.S
new file mode 100644
index 0000000..42337c7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_INT_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* idivmod returns quotient in r0 and remainder in r1 */
+%include "armv5te/binop2addr.S" {"instr":"bl      __aeabi_idivmod", "result":"r1", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_REM_INT_LIT16.S b/vm/mterp/armv5te/OP_REM_INT_LIT16.S
new file mode 100644
index 0000000..396e890
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_INT_LIT16.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* idivmod returns quotient in r0 and remainder in r1 */
+%include "armv5te/binopLit16.S" {"instr":"bl      __aeabi_idivmod", "result":"r1", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_REM_INT_LIT8.S b/vm/mterp/armv5te/OP_REM_INT_LIT8.S
new file mode 100644
index 0000000..906c5c4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_INT_LIT8.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* idivmod returns quotient in r0 and remainder in r1 */
+%include "armv5te/binopLit8.S" {"instr":"bl      __aeabi_idivmod", "result":"r1", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_REM_LONG.S b/vm/mterp/armv5te/OP_REM_LONG.S
new file mode 100644
index 0000000..d703047
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_LONG.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+%include "armv5te/binopWide.S" {"instr":"bl      __aeabi_ldivmod", "result0":"r2", "result1":"r3", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_REM_LONG_2ADDR.S b/vm/mterp/armv5te/OP_REM_LONG_2ADDR.S
new file mode 100644
index 0000000..b62f093
--- /dev/null
+++ b/vm/mterp/armv5te/OP_REM_LONG_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+%include "armv5te/binopWide2addr.S" {"instr":"bl      __aeabi_ldivmod", "result0":"r2", "result1":"r3", "chkzero":"1"}
diff --git a/vm/mterp/armv5te/OP_RETURN.S b/vm/mterp/armv5te/OP_RETURN.S
new file mode 100644
index 0000000..5f7350a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_RETURN.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /*
+     * Return a 32-bit value.  Copies the return value into the "thread"
+     * 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, [rSELF, #offThread_retval] @ retval.i <- vAA
+    b       common_returnFromMethod
diff --git a/vm/mterp/armv5te/OP_RETURN_OBJECT.S b/vm/mterp/armv5te/OP_RETURN_OBJECT.S
new file mode 100644
index 0000000..7956b45
--- /dev/null
+++ b/vm/mterp/armv5te/OP_RETURN_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_RETURN.S"
diff --git a/vm/mterp/armv5te/OP_RETURN_VOID.S b/vm/mterp/armv5te/OP_RETURN_VOID.S
new file mode 100644
index 0000000..e09ebb0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_RETURN_VOID.S
@@ -0,0 +1,2 @@
+%verify "executed"
+    b       common_returnFromMethod
diff --git a/vm/mterp/armv5te/OP_RETURN_VOID_BARRIER.S b/vm/mterp/armv5te/OP_RETURN_VOID_BARRIER.S
new file mode 100644
index 0000000..1f51b62
--- /dev/null
+++ b/vm/mterp/armv5te/OP_RETURN_VOID_BARRIER.S
@@ -0,0 +1,3 @@
+%verify "executed"
+    SMP_DMB_ST
+    b       common_returnFromMethod
diff --git a/vm/mterp/armv5te/OP_RETURN_WIDE.S b/vm/mterp/armv5te/OP_RETURN_WIDE.S
new file mode 100644
index 0000000..c185077
--- /dev/null
+++ b/vm/mterp/armv5te/OP_RETURN_WIDE.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /*
+     * Return a 64-bit value.  Copies the return value into the "thread"
+     * 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, rSELF, #offThread_retval  @ r3<- &self->retval
+    ldmia   r2, {r0-r1}                 @ r0/r1 <- vAA/vAA+1
+    stmia   r3, {r0-r1}                 @ retval<- r0/r1
+    b       common_returnFromMethod
diff --git a/vm/mterp/armv5te/OP_RSUB_INT.S b/vm/mterp/armv5te/OP_RSUB_INT.S
new file mode 100644
index 0000000..8113456
--- /dev/null
+++ b/vm/mterp/armv5te/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 "armv5te/binopLit16.S" {"instr":"rsb     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_RSUB_INT_LIT8.S b/vm/mterp/armv5te/OP_RSUB_INT_LIT8.S
new file mode 100644
index 0000000..5d5e0fb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_RSUB_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"instr":"rsb     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_SGET.S b/vm/mterp/armv5te/OP_SGET.S
new file mode 100644
index 0000000..2e2453a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET.S
@@ -0,0 +1,50 @@
+%default { "barrier":"@ no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    $barrier                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish
diff --git a/vm/mterp/armv5te/OP_SGET_BOOLEAN.S b/vm/mterp/armv5te/OP_SGET_BOOLEAN.S
new file mode 100644
index 0000000..358fd09
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S"
diff --git a/vm/mterp/armv5te/OP_SGET_BOOLEAN_JUMBO.S b/vm/mterp/armv5te/OP_SGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..b38ce7c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SGET_BYTE.S b/vm/mterp/armv5te/OP_SGET_BYTE.S
new file mode 100644
index 0000000..358fd09
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S"
diff --git a/vm/mterp/armv5te/OP_SGET_BYTE_JUMBO.S b/vm/mterp/armv5te/OP_SGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..b38ce7c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SGET_CHAR.S b/vm/mterp/armv5te/OP_SGET_CHAR.S
new file mode 100644
index 0000000..358fd09
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S"
diff --git a/vm/mterp/armv5te/OP_SGET_CHAR_JUMBO.S b/vm/mterp/armv5te/OP_SGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..b38ce7c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SGET_JUMBO.S b/vm/mterp/armv5te/OP_SGET_JUMBO.S
new file mode 100644
index 0000000..90f3c68
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_JUMBO.S
@@ -0,0 +1,53 @@
+%default { "barrier":"@ no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    $barrier                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
diff --git a/vm/mterp/armv5te/OP_SGET_OBJECT.S b/vm/mterp/armv5te/OP_SGET_OBJECT.S
new file mode 100644
index 0000000..358fd09
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S"
diff --git a/vm/mterp/armv5te/OP_SGET_OBJECT_JUMBO.S b/vm/mterp/armv5te/OP_SGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..b38ce7c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_OBJECT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..8b9c103
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..bebc805
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_OBJECT_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SGET_SHORT.S b/vm/mterp/armv5te/OP_SGET_SHORT.S
new file mode 100644
index 0000000..358fd09
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S"
diff --git a/vm/mterp/armv5te/OP_SGET_SHORT_JUMBO.S b/vm/mterp/armv5te/OP_SGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..b38ce7c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SGET_VOLATILE.S b/vm/mterp/armv5te/OP_SGET_VOLATILE.S
new file mode 100644
index 0000000..8b9c103
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SGET_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_SGET_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..9075c28
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_JUMBO.S" {"barrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SGET_WIDE.S b/vm/mterp/armv5te/OP_SGET_WIDE.S
new file mode 100644
index 0000000..f79ec30
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_WIDE.S
@@ -0,0 +1,55 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 64-bit SGET handler.
+     */
+    /* sget-wide vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish:
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    .if $volatile
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
diff --git a/vm/mterp/armv5te/OP_SGET_WIDE_JUMBO.S b/vm/mterp/armv5te/OP_SGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..c1f5cc7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_WIDE_JUMBO.S
@@ -0,0 +1,46 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if $volatile
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .L${opcode}_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
diff --git a/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE.S
new file mode 100644
index 0000000..b852348
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..1e4b2de
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SGET_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_SHL_INT.S b/vm/mterp/armv5te/OP_SHL_INT.S
new file mode 100644
index 0000000..7470344
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHL_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, asl r1"}
diff --git a/vm/mterp/armv5te/OP_SHL_INT_2ADDR.S b/vm/mterp/armv5te/OP_SHL_INT_2ADDR.S
new file mode 100644
index 0000000..15b6579
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHL_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, asl r1"}
diff --git a/vm/mterp/armv5te/OP_SHL_INT_LIT8.S b/vm/mterp/armv5te/OP_SHL_INT_LIT8.S
new file mode 100644
index 0000000..4da9a0f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHL_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, asl r1"}
diff --git a/vm/mterp/armv5te/OP_SHL_LONG.S b/vm/mterp/armv5te/OP_SHL_LONG.S
new file mode 100644
index 0000000..b48ca5e
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHL_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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       .L${opcode}_finish
+%break
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_SHL_LONG_2ADDR.S b/vm/mterp/armv5te/OP_SHL_LONG_2ADDR.S
new file mode 100644
index 0000000..42a0904
--- /dev/null
+++ b/vm/mterp/armv5te/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     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       .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/armv5te/OP_SHR_INT.S b/vm/mterp/armv5te/OP_SHR_INT.S
new file mode 100644
index 0000000..586f294
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, asr r1"}
diff --git a/vm/mterp/armv5te/OP_SHR_INT_2ADDR.S b/vm/mterp/armv5te/OP_SHR_INT_2ADDR.S
new file mode 100644
index 0000000..8b97195
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, asr r1"}
diff --git a/vm/mterp/armv5te/OP_SHR_INT_LIT8.S b/vm/mterp/armv5te/OP_SHR_INT_LIT8.S
new file mode 100644
index 0000000..465b61f
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, asr r1"}
diff --git a/vm/mterp/armv5te/OP_SHR_LONG.S b/vm/mterp/armv5te/OP_SHR_LONG.S
new file mode 100644
index 0000000..e6489a0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SHR_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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       .L${opcode}_finish
+%break
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_SHR_LONG_2ADDR.S b/vm/mterp/armv5te/OP_SHR_LONG_2ADDR.S
new file mode 100644
index 0000000..9414ffb
--- /dev/null
+++ b/vm/mterp/armv5te/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     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       .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/armv5te/OP_SPARSE_SWITCH.S b/vm/mterp/armv5te/OP_SPARSE_SWITCH.S
new file mode 100644
index 0000000..2447286
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPARSE_SWITCH.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_PACKED_SWITCH.S" { "func":"dvmInterpHandleSparseSwitch" }
diff --git a/vm/mterp/armv5te/OP_SPUT.S b/vm/mterp/armv5te/OP_SPUT.S
new file mode 100644
index 0000000..986f06a
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT.S
@@ -0,0 +1,51 @@
+%default { "prebarrier":"@ no-op", "postbarrier":"@ no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    $postbarrier
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
diff --git a/vm/mterp/armv5te/OP_SPUT_BOOLEAN.S b/vm/mterp/armv5te/OP_SPUT_BOOLEAN.S
new file mode 100644
index 0000000..1048982
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_BOOLEAN_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..e8a64be
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_BYTE.S b/vm/mterp/armv5te/OP_SPUT_BYTE.S
new file mode 100644
index 0000000..1048982
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_BYTE_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..e8a64be
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_CHAR.S b/vm/mterp/armv5te/OP_SPUT_CHAR.S
new file mode 100644
index 0000000..1048982
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_CHAR_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..e8a64be
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_JUMBO.S
new file mode 100644
index 0000000..85dea34
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_JUMBO.S
@@ -0,0 +1,54 @@
+%default { "prebarrier":"@ no-op", "postbarrier":"@ no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    $postbarrier
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT.S b/vm/mterp/armv5te/OP_SPUT_OBJECT.S
new file mode 100644
index 0000000..77938d0
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT.S
@@ -0,0 +1,59 @@
+%default { "postbarrier":"@ no-op ", "prebarrier":"@ no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    b       .L${opcode}_end
+%break
+
+
+.L${opcode}_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    $postbarrier
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
+
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..6e5ebe2
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT_JUMBO.S
@@ -0,0 +1,59 @@
+%default { "postbarrier":"@ no-op ", "prebarrier":"@ no-op " }
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    $prebarrier                        @ releasing store
+    b       .L${opcode}_end
+%break
+
+
+.L${opcode}_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    $postbarrier
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
+
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..a9d69bb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_OBJECT.S"  {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..e8b2b1d
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_OBJECT_JUMBO.S"  {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SPUT_SHORT.S b/vm/mterp/armv5te/OP_SPUT_SHORT.S
new file mode 100644
index 0000000..1048982
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_SHORT_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..e8a64be
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/armv5te/OP_SPUT_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_VOLATILE.S
new file mode 100644
index 0000000..1b8dd25
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SPUT_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..5127051
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_JUMBO.S" {"prebarrier":"SMP_DMB_ST", "postbarrier":"SMP_DMB"}
diff --git a/vm/mterp/armv5te/OP_SPUT_WIDE.S b/vm/mterp/armv5te/OP_SPUT_WIDE.S
new file mode 100644
index 0000000..d0f65e6
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_WIDE.S
@@ -0,0 +1,57 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 64-bit SPUT handler.
+     */
+    /* sput-wide vAA, field@BBBB */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if $volatile
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
diff --git a/vm/mterp/armv5te/OP_SPUT_WIDE_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..03ea9f9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_WIDE_JUMBO.S
@@ -0,0 +1,59 @@
+%default {"volatile":"0"}
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .L${opcode}_resolve         @ yes, do resolve
+.L${opcode}_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if $volatile
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+%break
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.L${opcode}_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .L${opcode}_finish          @ resume
diff --git a/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE.S b/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE.S
new file mode 100644
index 0000000..a88de85
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_WIDE.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S b/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S
new file mode 100644
index 0000000..c1b0991
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/OP_SPUT_WIDE_JUMBO.S" {"volatile":"1"}
diff --git a/vm/mterp/armv5te/OP_SUB_DOUBLE.S b/vm/mterp/armv5te/OP_SUB_DOUBLE.S
new file mode 100644
index 0000000..fed41d2
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"instr":"bl      __aeabi_dsub"}
diff --git a/vm/mterp/armv5te/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/armv5te/OP_SUB_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..d8d51a7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"instr":"bl      __aeabi_dsub"}
diff --git a/vm/mterp/armv5te/OP_SUB_FLOAT.S b/vm/mterp/armv5te/OP_SUB_FLOAT.S
new file mode 100644
index 0000000..651669c
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"bl      __aeabi_fsub"}
diff --git a/vm/mterp/armv5te/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/armv5te/OP_SUB_FLOAT_2ADDR.S
new file mode 100644
index 0000000..e7d27c7
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"bl      __aeabi_fsub"}
diff --git a/vm/mterp/armv5te/OP_SUB_INT.S b/vm/mterp/armv5te/OP_SUB_INT.S
new file mode 100644
index 0000000..f25e643
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"sub     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_SUB_INT_2ADDR.S b/vm/mterp/armv5te/OP_SUB_INT_2ADDR.S
new file mode 100644
index 0000000..56ff9bc
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"sub     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_SUB_LONG.S b/vm/mterp/armv5te/OP_SUB_LONG.S
new file mode 100644
index 0000000..cfdcc88
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"preinstr":"subs    r0, r0, r2", "instr":"sbc     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_SUB_LONG_2ADDR.S b/vm/mterp/armv5te/OP_SUB_LONG_2ADDR.S
new file mode 100644
index 0000000..4fd6610
--- /dev/null
+++ b/vm/mterp/armv5te/OP_SUB_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"preinstr":"subs    r0, r0, r2", "instr":"sbc     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_THROW.S b/vm/mterp/armv5te/OP_THROW.S
new file mode 100644
index 0000000..6e157b4
--- /dev/null
+++ b/vm/mterp/armv5te/OP_THROW.S
@@ -0,0 +1,14 @@
+%verify "executed"
+%verify "exception for null object"
+    /*
+     * 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)
+    EXPORT_PC()                         @ exception handler can throw
+    cmp     r1, #0                      @ null object?
+    beq     common_errNullObject        @ yes, throw an NPE instead
+    @ bypass dvmSetException, just store it
+    str     r1, [rSELF, #offThread_exception]  @ thread->exception<- obj
+    b       common_exceptionThrown
diff --git a/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
new file mode 100644
index 0000000..afe9fd8
--- /dev/null
+++ b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
@@ -0,0 +1,13 @@
+%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, [rSELF, #offThread_method]    @ r0<- self->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_THROW_VERIFICATION_ERROR_JUMBO.S b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR_JUMBO.S
new file mode 100644
index 0000000..f42ba76
--- /dev/null
+++ b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR_JUMBO.S
@@ -0,0 +1,15 @@
+%verify executed
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, Class@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    orr     r2, r1, r2, lsl #16         @ r2<- AAAAaaaa
+    EXPORT_PC()                         @ export the PC
+    FETCH(r1, 3)                        @ r1<- BBBB
+    bl      dvmThrowVerificationError   @ always throws
+    b       common_exceptionThrown      @ handle exception
diff --git a/vm/mterp/armv5te/OP_UNUSED_27FF.S b/vm/mterp/armv5te/OP_UNUSED_27FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_27FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_28FF.S b/vm/mterp/armv5te/OP_UNUSED_28FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_28FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_29FF.S b/vm/mterp/armv5te/OP_UNUSED_29FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_29FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_2AFF.S b/vm/mterp/armv5te/OP_UNUSED_2AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_2AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_2BFF.S b/vm/mterp/armv5te/OP_UNUSED_2BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_2BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_2CFF.S b/vm/mterp/armv5te/OP_UNUSED_2CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_2CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_2DFF.S b/vm/mterp/armv5te/OP_UNUSED_2DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_2DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_2EFF.S b/vm/mterp/armv5te/OP_UNUSED_2EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_2EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_2FFF.S b/vm/mterp/armv5te/OP_UNUSED_2FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_2FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_30FF.S b/vm/mterp/armv5te/OP_UNUSED_30FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_30FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_31FF.S b/vm/mterp/armv5te/OP_UNUSED_31FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_31FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_32FF.S b/vm/mterp/armv5te/OP_UNUSED_32FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_32FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_33FF.S b/vm/mterp/armv5te/OP_UNUSED_33FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_33FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_34FF.S b/vm/mterp/armv5te/OP_UNUSED_34FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_34FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_35FF.S b/vm/mterp/armv5te/OP_UNUSED_35FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_35FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_36FF.S b/vm/mterp/armv5te/OP_UNUSED_36FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_36FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_37FF.S b/vm/mterp/armv5te/OP_UNUSED_37FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_37FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_38FF.S b/vm/mterp/armv5te/OP_UNUSED_38FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_38FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_39FF.S b/vm/mterp/armv5te/OP_UNUSED_39FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_39FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3AFF.S b/vm/mterp/armv5te/OP_UNUSED_3AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3BFF.S b/vm/mterp/armv5te/OP_UNUSED_3BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3CFF.S b/vm/mterp/armv5te/OP_UNUSED_3CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3DFF.S b/vm/mterp/armv5te/OP_UNUSED_3DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3E.S b/vm/mterp/armv5te/OP_UNUSED_3E.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3E.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3EFF.S b/vm/mterp/armv5te/OP_UNUSED_3EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3F.S b/vm/mterp/armv5te/OP_UNUSED_3F.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3F.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_3FFF.S b/vm/mterp/armv5te/OP_UNUSED_3FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_3FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_40.S b/vm/mterp/armv5te/OP_UNUSED_40.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_40.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_40FF.S b/vm/mterp/armv5te/OP_UNUSED_40FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_40FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_41.S b/vm/mterp/armv5te/OP_UNUSED_41.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_41.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_41FF.S b/vm/mterp/armv5te/OP_UNUSED_41FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_41FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_42.S b/vm/mterp/armv5te/OP_UNUSED_42.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_42.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_42FF.S b/vm/mterp/armv5te/OP_UNUSED_42FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_42FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_43.S b/vm/mterp/armv5te/OP_UNUSED_43.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_43.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_43FF.S b/vm/mterp/armv5te/OP_UNUSED_43FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_43FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_44FF.S b/vm/mterp/armv5te/OP_UNUSED_44FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_44FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_45FF.S b/vm/mterp/armv5te/OP_UNUSED_45FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_45FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_46FF.S b/vm/mterp/armv5te/OP_UNUSED_46FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_46FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_47FF.S b/vm/mterp/armv5te/OP_UNUSED_47FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_47FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_48FF.S b/vm/mterp/armv5te/OP_UNUSED_48FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_48FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_49FF.S b/vm/mterp/armv5te/OP_UNUSED_49FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_49FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_4AFF.S b/vm/mterp/armv5te/OP_UNUSED_4AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_4AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_4BFF.S b/vm/mterp/armv5te/OP_UNUSED_4BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_4BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_4CFF.S b/vm/mterp/armv5te/OP_UNUSED_4CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_4CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_4DFF.S b/vm/mterp/armv5te/OP_UNUSED_4DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_4DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_4EFF.S b/vm/mterp/armv5te/OP_UNUSED_4EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_4EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_4FFF.S b/vm/mterp/armv5te/OP_UNUSED_4FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_4FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_50FF.S b/vm/mterp/armv5te/OP_UNUSED_50FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_50FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_51FF.S b/vm/mterp/armv5te/OP_UNUSED_51FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_51FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_52FF.S b/vm/mterp/armv5te/OP_UNUSED_52FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_52FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_53FF.S b/vm/mterp/armv5te/OP_UNUSED_53FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_53FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_54FF.S b/vm/mterp/armv5te/OP_UNUSED_54FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_54FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_55FF.S b/vm/mterp/armv5te/OP_UNUSED_55FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_55FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_56FF.S b/vm/mterp/armv5te/OP_UNUSED_56FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_56FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_57FF.S b/vm/mterp/armv5te/OP_UNUSED_57FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_57FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_58FF.S b/vm/mterp/armv5te/OP_UNUSED_58FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_58FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_59FF.S b/vm/mterp/armv5te/OP_UNUSED_59FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_59FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_5AFF.S b/vm/mterp/armv5te/OP_UNUSED_5AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_5AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_5BFF.S b/vm/mterp/armv5te/OP_UNUSED_5BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_5BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_5CFF.S b/vm/mterp/armv5te/OP_UNUSED_5CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_5CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_5DFF.S b/vm/mterp/armv5te/OP_UNUSED_5DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_5DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_5EFF.S b/vm/mterp/armv5te/OP_UNUSED_5EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_5EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_5FFF.S b/vm/mterp/armv5te/OP_UNUSED_5FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_5FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_60FF.S b/vm/mterp/armv5te/OP_UNUSED_60FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_60FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_61FF.S b/vm/mterp/armv5te/OP_UNUSED_61FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_61FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_62FF.S b/vm/mterp/armv5te/OP_UNUSED_62FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_62FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_63FF.S b/vm/mterp/armv5te/OP_UNUSED_63FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_63FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_64FF.S b/vm/mterp/armv5te/OP_UNUSED_64FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_64FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_65FF.S b/vm/mterp/armv5te/OP_UNUSED_65FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_65FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_66FF.S b/vm/mterp/armv5te/OP_UNUSED_66FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_66FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_67FF.S b/vm/mterp/armv5te/OP_UNUSED_67FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_67FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_68FF.S b/vm/mterp/armv5te/OP_UNUSED_68FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_68FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_69FF.S b/vm/mterp/armv5te/OP_UNUSED_69FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_69FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_6AFF.S b/vm/mterp/armv5te/OP_UNUSED_6AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_6AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_6BFF.S b/vm/mterp/armv5te/OP_UNUSED_6BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_6BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_6CFF.S b/vm/mterp/armv5te/OP_UNUSED_6CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_6CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_6DFF.S b/vm/mterp/armv5te/OP_UNUSED_6DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_6DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_6EFF.S b/vm/mterp/armv5te/OP_UNUSED_6EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_6EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_6FFF.S b/vm/mterp/armv5te/OP_UNUSED_6FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_6FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_70FF.S b/vm/mterp/armv5te/OP_UNUSED_70FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_70FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_71FF.S b/vm/mterp/armv5te/OP_UNUSED_71FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_71FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_72FF.S b/vm/mterp/armv5te/OP_UNUSED_72FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_72FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_73.S b/vm/mterp/armv5te/OP_UNUSED_73.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_73.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_73FF.S b/vm/mterp/armv5te/OP_UNUSED_73FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_73FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_74FF.S b/vm/mterp/armv5te/OP_UNUSED_74FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_74FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_75FF.S b/vm/mterp/armv5te/OP_UNUSED_75FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_75FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_76FF.S b/vm/mterp/armv5te/OP_UNUSED_76FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_76FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_77FF.S b/vm/mterp/armv5te/OP_UNUSED_77FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_77FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_78FF.S b/vm/mterp/armv5te/OP_UNUSED_78FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_78FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_79.S b/vm/mterp/armv5te/OP_UNUSED_79.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_79.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_79FF.S b/vm/mterp/armv5te/OP_UNUSED_79FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_79FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7A.S b/vm/mterp/armv5te/OP_UNUSED_7A.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7A.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7AFF.S b/vm/mterp/armv5te/OP_UNUSED_7AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7BFF.S b/vm/mterp/armv5te/OP_UNUSED_7BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7CFF.S b/vm/mterp/armv5te/OP_UNUSED_7CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7DFF.S b/vm/mterp/armv5te/OP_UNUSED_7DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7EFF.S b/vm/mterp/armv5te/OP_UNUSED_7EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_7FFF.S b/vm/mterp/armv5te/OP_UNUSED_7FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_7FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_80FF.S b/vm/mterp/armv5te/OP_UNUSED_80FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_80FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_81FF.S b/vm/mterp/armv5te/OP_UNUSED_81FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_81FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_82FF.S b/vm/mterp/armv5te/OP_UNUSED_82FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_82FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_83FF.S b/vm/mterp/armv5te/OP_UNUSED_83FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_83FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_84FF.S b/vm/mterp/armv5te/OP_UNUSED_84FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_84FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_85FF.S b/vm/mterp/armv5te/OP_UNUSED_85FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_85FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_86FF.S b/vm/mterp/armv5te/OP_UNUSED_86FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_86FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_87FF.S b/vm/mterp/armv5te/OP_UNUSED_87FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_87FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_88FF.S b/vm/mterp/armv5te/OP_UNUSED_88FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_88FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_89FF.S b/vm/mterp/armv5te/OP_UNUSED_89FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_89FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_8AFF.S b/vm/mterp/armv5te/OP_UNUSED_8AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_8AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_8BFF.S b/vm/mterp/armv5te/OP_UNUSED_8BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_8BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_8CFF.S b/vm/mterp/armv5te/OP_UNUSED_8CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_8CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_8DFF.S b/vm/mterp/armv5te/OP_UNUSED_8DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_8DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_8EFF.S b/vm/mterp/armv5te/OP_UNUSED_8EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_8EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_8FFF.S b/vm/mterp/armv5te/OP_UNUSED_8FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_8FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_90FF.S b/vm/mterp/armv5te/OP_UNUSED_90FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_90FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_91FF.S b/vm/mterp/armv5te/OP_UNUSED_91FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_91FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_92FF.S b/vm/mterp/armv5te/OP_UNUSED_92FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_92FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_93FF.S b/vm/mterp/armv5te/OP_UNUSED_93FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_93FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_94FF.S b/vm/mterp/armv5te/OP_UNUSED_94FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_94FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_95FF.S b/vm/mterp/armv5te/OP_UNUSED_95FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_95FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_96FF.S b/vm/mterp/armv5te/OP_UNUSED_96FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_96FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_97FF.S b/vm/mterp/armv5te/OP_UNUSED_97FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_97FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_98FF.S b/vm/mterp/armv5te/OP_UNUSED_98FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_98FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_99FF.S b/vm/mterp/armv5te/OP_UNUSED_99FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_99FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_9AFF.S b/vm/mterp/armv5te/OP_UNUSED_9AFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_9AFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_9BFF.S b/vm/mterp/armv5te/OP_UNUSED_9BFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_9BFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_9CFF.S b/vm/mterp/armv5te/OP_UNUSED_9CFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_9CFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_9DFF.S b/vm/mterp/armv5te/OP_UNUSED_9DFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_9DFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_9EFF.S b/vm/mterp/armv5te/OP_UNUSED_9EFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_9EFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_9FFF.S b/vm/mterp/armv5te/OP_UNUSED_9FFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_9FFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A0FF.S b/vm/mterp/armv5te/OP_UNUSED_A0FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A0FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A1FF.S b/vm/mterp/armv5te/OP_UNUSED_A1FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A1FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A2FF.S b/vm/mterp/armv5te/OP_UNUSED_A2FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A2FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A3FF.S b/vm/mterp/armv5te/OP_UNUSED_A3FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A3FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A4FF.S b/vm/mterp/armv5te/OP_UNUSED_A4FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A4FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A5FF.S b/vm/mterp/armv5te/OP_UNUSED_A5FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A5FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A6FF.S b/vm/mterp/armv5te/OP_UNUSED_A6FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A6FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A7FF.S b/vm/mterp/armv5te/OP_UNUSED_A7FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A7FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A8FF.S b/vm/mterp/armv5te/OP_UNUSED_A8FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A8FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_A9FF.S b/vm/mterp/armv5te/OP_UNUSED_A9FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_A9FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_AAFF.S b/vm/mterp/armv5te/OP_UNUSED_AAFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_AAFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_ABFF.S b/vm/mterp/armv5te/OP_UNUSED_ABFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_ABFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_ACFF.S b/vm/mterp/armv5te/OP_UNUSED_ACFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_ACFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_ADFF.S b/vm/mterp/armv5te/OP_UNUSED_ADFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_ADFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_AEFF.S b/vm/mterp/armv5te/OP_UNUSED_AEFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_AEFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_AFFF.S b/vm/mterp/armv5te/OP_UNUSED_AFFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_AFFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B0FF.S b/vm/mterp/armv5te/OP_UNUSED_B0FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B0FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B1FF.S b/vm/mterp/armv5te/OP_UNUSED_B1FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B1FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B2FF.S b/vm/mterp/armv5te/OP_UNUSED_B2FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B2FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B3FF.S b/vm/mterp/armv5te/OP_UNUSED_B3FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B3FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B4FF.S b/vm/mterp/armv5te/OP_UNUSED_B4FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B4FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B5FF.S b/vm/mterp/armv5te/OP_UNUSED_B5FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B5FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B6FF.S b/vm/mterp/armv5te/OP_UNUSED_B6FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B6FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B7FF.S b/vm/mterp/armv5te/OP_UNUSED_B7FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B7FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B8FF.S b/vm/mterp/armv5te/OP_UNUSED_B8FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B8FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_B9FF.S b/vm/mterp/armv5te/OP_UNUSED_B9FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_B9FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_BAFF.S b/vm/mterp/armv5te/OP_UNUSED_BAFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_BAFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_BBFF.S b/vm/mterp/armv5te/OP_UNUSED_BBFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_BBFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_BCFF.S b/vm/mterp/armv5te/OP_UNUSED_BCFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_BCFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_BDFF.S b/vm/mterp/armv5te/OP_UNUSED_BDFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_BDFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_BEFF.S b/vm/mterp/armv5te/OP_UNUSED_BEFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_BEFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_BFFF.S b/vm/mterp/armv5te/OP_UNUSED_BFFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_BFFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C0FF.S b/vm/mterp/armv5te/OP_UNUSED_C0FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C0FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C1FF.S b/vm/mterp/armv5te/OP_UNUSED_C1FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C1FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C2FF.S b/vm/mterp/armv5te/OP_UNUSED_C2FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C2FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C3FF.S b/vm/mterp/armv5te/OP_UNUSED_C3FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C3FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C4FF.S b/vm/mterp/armv5te/OP_UNUSED_C4FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C4FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C5FF.S b/vm/mterp/armv5te/OP_UNUSED_C5FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C5FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C6FF.S b/vm/mterp/armv5te/OP_UNUSED_C6FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C6FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C7FF.S b/vm/mterp/armv5te/OP_UNUSED_C7FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C7FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C8FF.S b/vm/mterp/armv5te/OP_UNUSED_C8FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C8FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_C9FF.S b/vm/mterp/armv5te/OP_UNUSED_C9FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_C9FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_CAFF.S b/vm/mterp/armv5te/OP_UNUSED_CAFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_CAFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_CBFF.S b/vm/mterp/armv5te/OP_UNUSED_CBFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_CBFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_CCFF.S b/vm/mterp/armv5te/OP_UNUSED_CCFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_CCFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_CDFF.S b/vm/mterp/armv5te/OP_UNUSED_CDFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_CDFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_CEFF.S b/vm/mterp/armv5te/OP_UNUSED_CEFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_CEFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_CFFF.S b/vm/mterp/armv5te/OP_UNUSED_CFFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_CFFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D0FF.S b/vm/mterp/armv5te/OP_UNUSED_D0FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D0FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D1FF.S b/vm/mterp/armv5te/OP_UNUSED_D1FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D1FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D2FF.S b/vm/mterp/armv5te/OP_UNUSED_D2FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D2FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D3FF.S b/vm/mterp/armv5te/OP_UNUSED_D3FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D3FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D4FF.S b/vm/mterp/armv5te/OP_UNUSED_D4FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D4FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D5FF.S b/vm/mterp/armv5te/OP_UNUSED_D5FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D5FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D6FF.S b/vm/mterp/armv5te/OP_UNUSED_D6FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D6FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D7FF.S b/vm/mterp/armv5te/OP_UNUSED_D7FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D7FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D8FF.S b/vm/mterp/armv5te/OP_UNUSED_D8FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D8FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_D9FF.S b/vm/mterp/armv5te/OP_UNUSED_D9FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_D9FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_DAFF.S b/vm/mterp/armv5te/OP_UNUSED_DAFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_DAFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_DBFF.S b/vm/mterp/armv5te/OP_UNUSED_DBFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_DBFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_DCFF.S b/vm/mterp/armv5te/OP_UNUSED_DCFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_DCFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_DDFF.S b/vm/mterp/armv5te/OP_UNUSED_DDFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_DDFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_DEFF.S b/vm/mterp/armv5te/OP_UNUSED_DEFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_DEFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_DFFF.S b/vm/mterp/armv5te/OP_UNUSED_DFFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_DFFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E0FF.S b/vm/mterp/armv5te/OP_UNUSED_E0FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E0FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E1FF.S b/vm/mterp/armv5te/OP_UNUSED_E1FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E1FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E2FF.S b/vm/mterp/armv5te/OP_UNUSED_E2FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E2FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E3FF.S b/vm/mterp/armv5te/OP_UNUSED_E3FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E3FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E4FF.S b/vm/mterp/armv5te/OP_UNUSED_E4FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E4FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E5FF.S b/vm/mterp/armv5te/OP_UNUSED_E5FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E5FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E6FF.S b/vm/mterp/armv5te/OP_UNUSED_E6FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E6FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E7FF.S b/vm/mterp/armv5te/OP_UNUSED_E7FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E7FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E8FF.S b/vm/mterp/armv5te/OP_UNUSED_E8FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E8FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_E9FF.S b/vm/mterp/armv5te/OP_UNUSED_E9FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_E9FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EAFF.S b/vm/mterp/armv5te/OP_UNUSED_EAFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_EAFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EBFF.S b/vm/mterp/armv5te/OP_UNUSED_EBFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_EBFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_ECFF.S b/vm/mterp/armv5te/OP_UNUSED_ECFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_ECFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EDFF.S b/vm/mterp/armv5te/OP_UNUSED_EDFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_EDFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EEFF.S b/vm/mterp/armv5te/OP_UNUSED_EEFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_EEFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_EFFF.S b/vm/mterp/armv5te/OP_UNUSED_EFFF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_EFFF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_F0FF.S b/vm/mterp/armv5te/OP_UNUSED_F0FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_F0FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_UNUSED_F1FF.S b/vm/mterp/armv5te/OP_UNUSED_F1FF.S
new file mode 100644
index 0000000..faa7246
--- /dev/null
+++ b/vm/mterp/armv5te/OP_UNUSED_F1FF.S
@@ -0,0 +1 @@
+%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/OP_USHR_INT.S b/vm/mterp/armv5te/OP_USHR_INT.S
new file mode 100644
index 0000000..a72c2cb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_USHR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, lsr r1"}
diff --git a/vm/mterp/armv5te/OP_USHR_INT_2ADDR.S b/vm/mterp/armv5te/OP_USHR_INT_2ADDR.S
new file mode 100644
index 0000000..8ace5f9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_USHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, lsr r1"}
diff --git a/vm/mterp/armv5te/OP_USHR_INT_LIT8.S b/vm/mterp/armv5te/OP_USHR_INT_LIT8.S
new file mode 100644
index 0000000..9d038c5
--- /dev/null
+++ b/vm/mterp/armv5te/OP_USHR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"preinstr":"and     r1, r1, #31", "instr":"mov     r0, r0, lsr r1"}
diff --git a/vm/mterp/armv5te/OP_USHR_LONG.S b/vm/mterp/armv5te/OP_USHR_LONG.S
new file mode 100644
index 0000000..d9ae338
--- /dev/null
+++ b/vm/mterp/armv5te/OP_USHR_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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       .L${opcode}_finish
+%break
+
+.L${opcode}_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
diff --git a/vm/mterp/armv5te/OP_USHR_LONG_2ADDR.S b/vm/mterp/armv5te/OP_USHR_LONG_2ADDR.S
new file mode 100644
index 0000000..27592a4
--- /dev/null
+++ b/vm/mterp/armv5te/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     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       .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/armv5te/OP_XOR_INT.S b/vm/mterp/armv5te/OP_XOR_INT.S
new file mode 100644
index 0000000..81bfa00
--- /dev/null
+++ b/vm/mterp/armv5te/OP_XOR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop.S" {"instr":"eor     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_XOR_INT_2ADDR.S b/vm/mterp/armv5te/OP_XOR_INT_2ADDR.S
new file mode 100644
index 0000000..ead63c5
--- /dev/null
+++ b/vm/mterp/armv5te/OP_XOR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binop2addr.S" {"instr":"eor     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_XOR_INT_LIT16.S b/vm/mterp/armv5te/OP_XOR_INT_LIT16.S
new file mode 100644
index 0000000..fcb4abb
--- /dev/null
+++ b/vm/mterp/armv5te/OP_XOR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit16.S" {"instr":"eor     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_XOR_INT_LIT8.S b/vm/mterp/armv5te/OP_XOR_INT_LIT8.S
new file mode 100644
index 0000000..5ef0711
--- /dev/null
+++ b/vm/mterp/armv5te/OP_XOR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopLit8.S" {"instr":"eor     r0, r0, r1"}
diff --git a/vm/mterp/armv5te/OP_XOR_LONG.S b/vm/mterp/armv5te/OP_XOR_LONG.S
new file mode 100644
index 0000000..29a0075
--- /dev/null
+++ b/vm/mterp/armv5te/OP_XOR_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide.S" {"preinstr":"eor     r0, r0, r2", "instr":"eor     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/OP_XOR_LONG_2ADDR.S b/vm/mterp/armv5te/OP_XOR_LONG_2ADDR.S
new file mode 100644
index 0000000..7dc71c9
--- /dev/null
+++ b/vm/mterp/armv5te/OP_XOR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/binopWide2addr.S" {"preinstr":"eor     r0, r0, r2", "instr":"eor     r1, r1, r3"}
diff --git a/vm/mterp/armv5te/alt_stub.S b/vm/mterp/armv5te/alt_stub.S
new file mode 100644
index 0000000..4ab5f9f
--- /dev/null
+++ b/vm/mterp/armv5te/alt_stub.S
@@ -0,0 +1,18 @@
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (${opnum} * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
diff --git a/vm/mterp/armv5te/bincmp.S b/vm/mterp/armv5te/bincmp.S
new file mode 100644
index 0000000..12a2c8c
--- /dev/null
+++ b/vm/mterp/armv5te/bincmp.S
@@ -0,0 +1,30 @@
+%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     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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    mov${revcmp} r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv5te/binop.S b/vm/mterp/armv5te/binop.S
new file mode 100644
index 0000000..d169ed6
--- /dev/null
+++ b/vm/mterp/armv5te/binop.S
@@ -0,0 +1,35 @@
+%default {"preinstr":"", "result":"r0", "chkzero":"0"}
+    /*
+     * 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 $chkzero
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ 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
+    /* 11-14 instructions */
diff --git a/vm/mterp/armv5te/binop2addr.S b/vm/mterp/armv5te/binop2addr.S
new file mode 100644
index 0000000..061242a
--- /dev/null
+++ b/vm/mterp/armv5te/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     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 $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/armv5te/binopLit16.S b/vm/mterp/armv5te/binopLit16.S
new file mode 100644
index 0000000..df49929
--- /dev/null
+++ b/vm/mterp/armv5te/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
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    GET_VREG(r0, r2)                    @ r0<- vB
+    and     r9, r9, #15
+    .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/armv5te/binopLit8.S b/vm/mterp/armv5te/binopLit8.S
new file mode 100644
index 0000000..2addd26
--- /dev/null
+++ b/vm/mterp/armv5te/binopLit8.S
@@ -0,0 +1,32 @@
+%default {"preinstr":"", "result":"r0", "chkzero":"0"}
+    /*
+     * 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 $chkzero
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ 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-12 instructions */
diff --git a/vm/mterp/armv5te/binopWide.S b/vm/mterp/armv5te/binopWide.S
new file mode 100644
index 0000000..71fd3fe
--- /dev/null
+++ b/vm/mterp/armv5te/binopWide.S
@@ -0,0 +1,38 @@
+%default {"preinstr":"", "result0":"r0", "result1":"r1", "chkzero":"0"}
+    /*
+     * 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 $chkzero
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ 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
+    /* 14-17 instructions */
diff --git a/vm/mterp/armv5te/binopWide2addr.S b/vm/mterp/armv5te/binopWide2addr.S
new file mode 100644
index 0000000..3fd5747
--- /dev/null
+++ b/vm/mterp/armv5te/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     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 $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/armv5te/debug.cpp b/vm/mterp/armv5te/debug.cpp
new file mode 100644
index 0000000..1b54618
--- /dev/null
+++ b/vm/mterp/armv5te/debug.cpp
@@ -0,0 +1,79 @@
+#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 rSELF     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 rSELF=%08x rINST=%08x\n",
+        rPC, rFP, rSELF, rINST);
+    printf("    : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
+
+    //Thread* self = (Thread*) rSELF;
+    //const Method* method = self->method;
+    printf("    + self is %p\n", dvmThreadSelf());
+    //printf("    + currently in %s.%s %s\n",
+    //    method->clazz->descriptor, method->name, method->shorty);
+    //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/armv5te/entry.S b/vm/mterp/armv5te/entry.S
new file mode 100644
index 0000000..19b6d4b
--- /dev/null
+++ b/vm/mterp/armv5te/entry.S
@@ -0,0 +1,130 @@
+/*
+ * 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  Thread* self
+ *
+ * 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, #offThread_bailPtr]  @ save SP for eventual return
+
+    /* set up "named" registers, figure out entry point */
+    mov     rSELF, r0                   @ set rSELF
+    LOAD_PC_FP_FROM_SELF()              @ load rPC and rFP from "thread"
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable] @ set rIBASE
+
+#if defined(WITH_JIT)
+.LentryInstr:
+    /* Entry is always a possible trace start */
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [rSELF, #offThread_shadowSpace] @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    /* 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
+
+.Lbad_arg:
+    ldr     r0, strBadEntryPoint
+    @ r1 holds value of entryPoint
+    bl      printf
+    bl      dvmAbort
+    .fnend
+    .size   dvmMterpStdRun, .-dvmMterpStdRun
+
+
+    .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  Thread* self
+ */
+dvmMterpStdBail:
+    ldr     sp, [r0, #offThread_bailPtr]    @ sp<- saved SP
+    add     sp, sp, #4                      @ un-align 64
+    ldmfd   sp!, {r4-r10,fp,pc}             @ restore 9 regs and return
+
+
+/*
+ * String references.
+ */
+strBadEntryPoint:
+    .word   .LstrBadEntryPoint
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
new file mode 100644
index 0000000..4afe471
--- /dev/null
+++ b/vm/mterp/armv5te/footer.S
@@ -0,0 +1,1251 @@
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+
+#if defined(WITH_JIT)
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * "longjmp" to a translation after single-stepping.  Before returning
+ * to translation, must save state for self-verification.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    b      jitSVShadowRunStart                   @ resume as if cache hit
+                                                 @ expects resume addr in r10
+
+    .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
+    mov    r3, #0
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
+    b      jitSVShadowRunEnd            @ doesn't return
+
+
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+#else
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r0, [rSELF,#offThread_jitResumeNPC]
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    bx     r0                                    @ resume translation
+
+/*
+ * 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
+#if defined(WITH_JIT_TUNING)
+    mov    r0,lr
+    bl     dvmBumpPunt;
+#endif
+    EXPORT_PC()
+    mov    r0, #0
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * We'll use the normal single-stepping mechanism via interpBreak,
+ * but also save the native pc of the resume point in the translation
+ * and the native sp so that we can later do the equivalent of a
+ * longjmp() to resume.
+ * On entry:
+ *    dPC <= Dalvik PC of instrucion to interpret
+ *    lr <= resume point in translation
+ *    r1 <= Dalvik PC of next instruction
+ */
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r1, #1
+    str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
+    mov    r0, rSELF
+    mov    r1, #kSubModeCountedStep
+    bl     dvmEnableSubMode     @ (self, newMode)
+    ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used for callees.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0                    @ !0 means translation exists
+    bxne   r0                       @ continue native execution if so
+    b      2f                       @ branch over to use the interpreter
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used following
+ * invokes.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    rPC,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST, #-4              @  .. which is 9 bytes back
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    2f
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @ in case target is HANDLER_INTERPRET
+    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:
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    cmp    r0, #0
+    movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
+    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,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST,#-4               @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNormal
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    toInterpreter            @ go if not, otherwise do chain
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    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 dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+#endif
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & 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()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    @ NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+common_testUpdateProfile:
+    cmp     r0, #0               @ JIT switched off?
+    beq     4f                   @ return to interp if so
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ *    r0    <= pJitProfTable (verified non-NULL)
+ *    rPC   <= Dalvik PC
+ *    rINST <= next instruction
+ */
+common_updateProfile:
+    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+    lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
+    ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
+    GET_INST_OPCODE(ip)
+    subs    r1,r1,#1           @ decrement counter
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
+    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
+
+    /* Looks good, reset the counter */
+    ldr     r1, [rSELF, #offThread_jitThreshold]
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
+    EXPORT_PC()
+    mov     r0,rPC
+    mov     r1,rSELF
+    bl      dvmJitGetTraceAddrThread    @ (pc, self)
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov     r1, rPC                     @ arg1 of translation may need this
+    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
+    cmp     r0,#0
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    r0                          @ jump to the translation
+    mov     r2,#kJitTSelectRequest      @ ask for trace selection
+    @ fall-through to common_selectTrace
+#else
+    moveq   r2,#kJitTSelectRequest      @ ask for trace selection
+    beq     common_selectTrace
+    /*
+     * At this point, we have a target translation.  However, if
+     * that translation is actually the interpret-only pseudo-translation
+     * we want to treat it the same as no translation.
+     */
+    mov     r10, r0                     @ save target
+    bl      dvmCompilerGetInterpretTemplate
+    cmp     r0, r10                     @ special case?
+    bne     jitSVShadowRunStart         @ set up self verification shadow space
+    @ Need to clear the inJitCodeCache flag
+    mov    r3, #0                       @ 0 means not in the JIT code cache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+/*
+ * On entry:
+ *  r2 is jit state.
+ */
+common_selectTrace:
+    ldrh    r0,[rSELF,#offThread_subMode]
+    ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
+    bne     3f                         @ already doing JIT work, continue
+    str     r2,[rSELF,#offThread_jitState]
+    mov     r0, rSELF
+/*
+ * Call out to validate trace-building request.  If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+    EXPORT_PC()
+    SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
+    bl      dvmJitCheckTraceRequest
+3:
+    FETCH_INST()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+4:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ *    rPC, rFP, rSELF: the values that they should contain
+ *    r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+    mov     r0,rPC                      @ r0<- program counter
+    mov     r1,rFP                      @ r1<- frame pointer
+    mov     r2,rSELF                    @ r2<- self (Thread) pointer
+    mov     r3,r10                      @ r3<- target translation
+    bl      dvmSelfVerificationSaveState @ save registers to shadow space
+    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
+    bx      r10                         @ jump to the translation
+
+/*
+ * Restore PC, registers, and interpreter state to original values
+ * before jumping back to the interpreter.
+ * On entry:
+ *   r0:  dPC
+ *   r2:  self verification state
+ */
+jitSVShadowRunEnd:
+    mov    r1,rFP                        @ pass ending fp
+    mov    r3,rSELF                      @ pass self ptr for convenience
+    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
+    LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
+    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
+    cmp    r1,#0                         @ check for punt condition
+    beq    1f
+    @ Set up SV single-stepping
+    mov    r0, rSELF
+    mov    r1, #kSubModeJitSV
+    bl     dvmEnableSubMode              @ (self, subMode)
+    mov    r2,#kJitSelfVerification      @ ask for self verification
+    str    r2,[rSELF,#offThread_jitState]
+    @ intentional fallthrough
+1:                                       @ exit to interpreter without check
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+common_gotoBail:
+    SAVE_PC_FP_TO_SELF()                @ export state to "thread"
+    mov     r0, rSELF                   @ r0<- self ptr
+    b       dvmMterpStdBail             @ call(self, changeInterp)
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair.  Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+    cmp     r9, #0
+    ldrne   r9, [r9, #offObject_clazz]
+    str     r0, [rSELF, #offThread_methodToCall]
+    str     r9, [rSELF, #offThread_callsiteClass]
+    bx      lr
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: r0 is "Method* methodToCall */
+    mov     r9, #0                      @ clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: r0 is "Method* methodToCall, r9 is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ prepare to copy args to "outs" area of current frame
+    add     rPC, rPC, #4                @ adjust pc to make return consistent
+    FETCH(r2, 1)                        @ r2<- BBBB (arg count)
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    cmp     r2, #0                      @ no args?
+    beq     .LinvokeArgsDone            @ if no args, skip the rest
+    FETCH(r1, 2)                        @ r1<- CCCC
+    b       .LinvokeRangeArgs           @ handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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
+
+.LinvokeRangeArgs:
+    @ 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
+1:  ldr     r1, [r3], #4                @ val = *fp++
+    subs    r2, r2, #1                  @ count--
+    str     r1, [r10], #4               @ *outs++ = val
+    bne     1b                          @ ...while count != 0
+    b       .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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)
+    beq     .LinvokeArgsDone
+
+    @ r0=methodToCall, r1=GFED, r2=count, 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
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
+    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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
+    cmp     r3, r9                      @ bottom < interpStackEnd?
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
+    blo     .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]
+
+    @ Profiling?
+    cmp     lr, #0                      @ any special modes happening?
+    bne     2f                          @ go if so
+1:
+    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
+
+    @ Update state values for the new method
+    @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     r2, #1
+    str     r2, [rSELF, #offThread_debugIsMethodEntry]
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [rSELF, #offThread_curFrame]   @ 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, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#endif
+
+2:
+    @ Profiling - record method entry.  r0: methodToCall
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    mov     r1, r0
+    mov     r0, rSELF
+    bl      dvmReportInvoke             @ (self, method)
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+    b       1b
+
+.LinvokeNative:
+    @ Prep for the native call
+    @ r0=methodToCall, r1=newFp, r10=newSaveArea
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFp (points to args)
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+
+#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
+
+    cmp     lr, #0                      @ any special SubModes active?
+    bne     11f                         @ go handle them if so
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+7:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    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
+
+11:
+    @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
+    stmfd   sp!, {r0-r3}                @ save all but subModes
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
+    ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
+
+    @ Call the native method
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+
+    @ Restore the pre-call arguments
+    ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
+
+    @ Finish up any post-invoke subMode requirements
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
+    b       7b                          @ resume
+
+.LstackOverflow:    @ r0=methodToCall
+    mov     r1, r0                      @ r1<- methodToCall
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmHandleStackOverflow
+    b       common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+    .fnend
+    .size   dalvik_mterp, .-dalvik_mterp
+#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, rSELF                   @ A0<- self
+    SAVE_PC_FP_TO_SELF()                @ export state to "self"
+    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:
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r0, rFP)
+    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+    cmp     lr, #0                      @ any special subMode handling needed?
+    bne     19f
+14:
+    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ is this a break frame?
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     15f
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+15:
+#else
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+#endif
+    beq     common_gotoBail             @ break frame, bail out completely
+
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+#if defined(WITH_JIT)
+    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
+    cmp     r10, #0                      @ caller is compiled code
+    blxne   r10
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+19:
+    @ Handle special actions
+    @ On entry, r0: StackSaveArea
+    ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
+    mov     r0, rSELF
+    bl      dvmReportReturn             @ (self)
+    SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
+    b       14b                         @ continue
+
+    /*
+     * Return handling, calls through "glue code".
+     */
+     .if    0
+.LreturnOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ 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:
+
+    EXPORT_PC()
+
+    mov     r0, rSELF
+    bl      dvmCheckSuspendPending
+
+    ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
+    mov     r1, rSELF                   @ r1<- self
+    mov     r0, r9                      @ r0<- exception
+    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
+    ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
+    mov     r3, #0                      @ r3<- NULL
+    str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
+
+    @ Special subMode?
+    cmp     r2, #0                      @ any special subMode handling needed?
+    bne     7f                          @ go if so
+8:
+    /* 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, [rSELF, #offThread_method] @ r1<- self->method
+    mov     r0, rSELF                   @ r0<- self
+    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
+    ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags
+    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, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    beq     1f                          @ no, skip ahead
+    mov     rFP, r0                     @ save relPc result in rFP
+    mov     r0, rSELF                   @ r0<- self
+    mov     r1, r9                      @ r1<- exception
+    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->interpSave.curFrame and updated PC */
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
+    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
+    str     r1, [rSELF, #offThread_method]  @ self->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, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
+
+    /* release the tracked alloc on the exception */
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+
+    /* restore the exception if the handler wants it */
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    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, [rSELF, #offThread_exception] @ yes, restore the exception
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    @ Manage debugger bookkeeping
+7:
+    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
+    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
+    mov     r0, rSELF                       @ arg0<- self
+    mov     r1, r9                          @ arg1<- exception
+    bl      dvmReportExceptionThrow         @ (self, exception)
+    b       8b                              @ resume with normal handling
+
+.LnotCaughtLocally: @ r9=exception
+    /* fix stack overflow if necessary */
+    ldrb    r1, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    movne   r0, rSELF                   @ if yes: r0<- self
+    movne   r1, r9                      @ if yes: r1<- exception
+    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, [rSELF, #offThread_method]
+    ldr     r1, [r0, #offMethod_insns]
+    sub     r1, rPC, r1
+    asr     r1, r1, #1
+    bl      dvmLineNumFromPC
+    str     r0, [sp, #-4]!
+    @ dvmGetMethodSourceFile(method)
+    ldr     r0, [rSELF, #offThread_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, [rSELF, #offThread_exception] @ restore exception
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+    b       common_gotoBail             @ bail out
+
+
+    /*
+     * Exception handling, calls through "glue code".
+     */
+    .if     0
+.LexceptionOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ arg to function
+    bl      dvmMterp_exceptionThrown
+    b       common_resumeAfterGlueCall
+    .endif
+
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including the current
+     * instruction.
+     *
+     * On entry:
+     *     r10: &dvmDex->pResFields[field]
+     *     r0:  field pointer (must preserve)
+     */
+common_verifyField:
+    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
+    ands    r3, #kSubModeJitTraceBuild
+    bxeq    lr                          @ Not building trace, continue
+    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
+    cmp     r1, #0                      @ resolution complete?
+    bxne    lr                          @ yes, continue
+    stmfd   sp!, {r0-r2,lr}             @ save regs
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
+    ldmfd   sp!, {r0-r2, lr}
+    bx      lr                          @ return
+#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_SELF()              @ pull rPC and rFP out of thread
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use r1
+ * and r3 because those just happen to be the registers all our callers are
+ * using. We move r3 before calling the C function, but r1 happens to match.
+ * r1: index
+ * r3: size
+ */
+common_errArrayIndex:
+    EXPORT_PC()
+    mov     r0, r3
+    bl      dvmThrowArrayIndexOutOfBoundsException
+    b       common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+    EXPORT_PC()
+    ldr     r0, strDivideByZero
+    bl      dvmThrowArithmeticException
+    b       common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in r1
+ */
+common_errNegativeArraySize:
+    EXPORT_PC()
+    mov     r0, r1                                @ arg0 <- len
+    bl      dvmThrowNegativeArraySizeException    @ (len)
+    b       common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in r1
+ */
+common_errNoSuchMethod:
+    EXPORT_PC()
+    mov     r0, r1
+    bl      dvmThrowNoSuchMethodError
+    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()
+    mov     r0, #0
+    bl      dvmThrowNullPointerException
+    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
+strDivideByZero:
+    .word   .LstrDivideByZero
+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"
+.LstrFilledNewArrayNotImpl:
+    .asciz  "filled-new-array only implemented for objects and 'int'"
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrLogTag:
+    .asciz  "mterp"
+.LstrExceptionNotCaughtLocally:
+    .asciz  "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+    .asciz  "\n"
+.LstrSqueak:
+    .asciz  "<%d>"
+.LstrPrintHex:
+    .asciz  "<%#x>"
+.LstrPrintLong:
+    .asciz  "<%lld>"
diff --git a/vm/mterp/armv5te/header.S b/vm/mterp/armv5te/header.S
new file mode 100644
index 0000000..b3c8f0a
--- /dev/null
+++ b/vm/mterp/armv5te/header.S
@@ -0,0 +1,196 @@
+/*
+ * 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  rSELF     self (Thread) 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 rSELF   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF()     ldr     rPC, [rSELF, #offThread_pc]
+#define SAVE_PC_TO_SELF()       str     rPC, [rSELF, #offThread_pc]
+#define LOAD_FP_FROM_SELF()     ldr     rFP, [rSELF, #offThread_curFrame]
+#define SAVE_FP_TO_SELF()       str     rFP, [rSELF, #offThread_curFrame]
+#define LOAD_PC_FP_FROM_SELF()  ldmia   rSELF, {rPC, rFP}
+#define SAVE_PC_FP_TO_SELF()    stmia   rSELF, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects.  Must
+ * be done *before* something throws.
+ *
+ * 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 #1]!", 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 #${handler_size_bits}
+#define GOTO_OPCODE_BASE(_base,_reg)  add     pc, _base, _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.
+ */
+#define GET_VREG(_reg, _vreg)   ldr     _reg, [rFP, _vreg, lsl #2]
+#define SET_VREG(_reg, _vreg)   str     _reg, [rFP, _vreg, lsl #2]
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
diff --git a/vm/mterp/armv5te/platform.S b/vm/mterp/armv5te/platform.S
new file mode 100644
index 0000000..ff3150b
--- /dev/null
+++ b/vm/mterp/armv5te/platform.S
@@ -0,0 +1,17 @@
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro  SMP_DMB
+.endm
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro  SMP_DMB_ST
+.endm
diff --git a/vm/mterp/armv5te/stub.S b/vm/mterp/armv5te/stub.S
new file mode 100644
index 0000000..767427b
--- /dev/null
+++ b/vm/mterp/armv5te/stub.S
@@ -0,0 +1,8 @@
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF()            @ only need to export these two
+    mov     r0, rSELF               @ self is first arg to function
+    bl      dvmMterp_${opcode}      @ call
+    LOAD_PC_FP_FROM_SELF()          @ retrieve updated values
+    FETCH_INST()                    @ load next instruction from rPC
+    GET_INST_OPCODE(ip)             @ ...trim down to just the opcode
+    GOTO_OPCODE(ip)                 @ ...and jump to the handler
diff --git a/vm/mterp/armv5te/unop.S b/vm/mterp/armv5te/unop.S
new file mode 100644
index 0000000..12d8206
--- /dev/null
+++ b/vm/mterp/armv5te/unop.S
@@ -0,0 +1,21 @@
+%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
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    GET_VREG(r0, r3)                    @ r0<- vB
+    and     r9, r9, #15
+    $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
+    /* 9-10 instructions */
diff --git a/vm/mterp/armv5te/unopNarrower.S b/vm/mterp/armv5te/unopNarrower.S
new file mode 100644
index 0000000..f1ad902
--- /dev/null
+++ b/vm/mterp/armv5te/unopNarrower.S
@@ -0,0 +1,24 @@
+%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
+    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
+    $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
+    /* 10-11 instructions */
diff --git a/vm/mterp/armv5te/unopWide.S b/vm/mterp/armv5te/unopWide.S
new file mode 100644
index 0000000..0805fdf
--- /dev/null
+++ b/vm/mterp/armv5te/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     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
+    $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
+    /* 12-13 instructions */
diff --git a/vm/mterp/armv5te/unopWider.S b/vm/mterp/armv5te/unopWider.S
new file mode 100644
index 0000000..df1baea
--- /dev/null
+++ b/vm/mterp/armv5te/unopWider.S
@@ -0,0 +1,21 @@
+%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     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]
+    $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
+    /* 10-11 instructions */
diff --git a/vm/mterp/armv5te/unused.S b/vm/mterp/armv5te/unused.S
new file mode 100644
index 0000000..0194f58
--- /dev/null
+++ b/vm/mterp/armv5te/unused.S
@@ -0,0 +1 @@
+    bl      common_abort
diff --git a/vm/mterp/armv5te/zcmp.S b/vm/mterp/armv5te/zcmp.S
new file mode 100644
index 0000000..bd63fe4
--- /dev/null
+++ b/vm/mterp/armv5te/zcmp.S
@@ -0,0 +1,27 @@
+%verify "branch taken"
+%verify "branch not taken"
+    /*
+     * 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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    mov${revcmp} r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
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..05991be
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S
@@ -0,0 +1,14 @@
+%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..8ec67d7
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_CONST_4.S
@@ -0,0 +1,9 @@
+%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..f66dc5f
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,54 @@
+%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..ac751de
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_LONG.S
@@ -0,0 +1,53 @@
+%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..4ba28e7
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S
@@ -0,0 +1,40 @@
+%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..168e338
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_LONG.S
@@ -0,0 +1,40 @@
+%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..14ddf44
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET.S
@@ -0,0 +1,45 @@
+%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, [rSELF, #offThread_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, [rSELF, #offThread_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..0ce2ebc
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET_QUICK.S
@@ -0,0 +1,15 @@
+%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..3e826dd
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET_WIDE.S
@@ -0,0 +1,42 @@
+%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, [rSELF, #offThread_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, [rSELF, #offThread_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..067d40d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S
@@ -0,0 +1,15 @@
+%verify "executed"
+%verify "null object"
+    /* iget-wide-quick vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    FETCH(ip, 1)                        @ ip<- field byte offset
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r3, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    ldrd    r0, [r3, ip]                @ r0<- obj.field (64 bits, aligned)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
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..4bc8e1b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT.S
@@ -0,0 +1,45 @@
+%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, [rSELF, #offThread_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, [rSELF, #offThread_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..ad87b55
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT_QUICK.S
@@ -0,0 +1,15 @@
+%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..f4ddb43
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT_WIDE.S
@@ -0,0 +1,39 @@
+%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, [rSELF, #offThread_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, [rSELF, #offThread_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..09f7a8e
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT_WIDE_QUICK.S
@@ -0,0 +1,15 @@
+%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..3047158
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MOVE.S
@@ -0,0 +1,10 @@
+%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..adc2c95
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MOVE_WIDE.S
@@ -0,0 +1,12 @@
+%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..1526a1e
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S
@@ -0,0 +1,25 @@
+%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..502481e
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S
@@ -0,0 +1,27 @@
+%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..501b3f2
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S
@@ -0,0 +1,27 @@
+%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..a1fcef4
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S
@@ -0,0 +1,27 @@
+%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..8d8c48d
--- /dev/null
+++ b/vm/mterp/armv6t2/bincmp.S
@@ -0,0 +1,29 @@
+%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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    mov${revcmp} r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
diff --git a/vm/mterp/armv6t2/binop2addr.S b/vm/mterp/armv6t2/binop2addr.S
new file mode 100644
index 0000000..b402156
--- /dev/null
+++ b/vm/mterp/armv6t2/binop2addr.S
@@ -0,0 +1,32 @@
+%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..1f67524
--- /dev/null
+++ b/vm/mterp/armv6t2/binopLit16.S
@@ -0,0 +1,29 @@
+%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..0b4691f
--- /dev/null
+++ b/vm/mterp/armv6t2/binopWide2addr.S
@@ -0,0 +1,34 @@
+%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..e0a303e
--- /dev/null
+++ b/vm/mterp/armv6t2/unopWide.S
@@ -0,0 +1,21 @@
+%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/armv7-a/platform.S b/vm/mterp/armv7-a/platform.S
new file mode 100644
index 0000000..96ff2c2
--- /dev/null
+++ b/vm/mterp/armv7-a/platform.S
@@ -0,0 +1,31 @@
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier.
+ */
+.macro  SMP_DMB
+#if ANDROID_SMP != 0
+    dmb
+#else
+    /* not SMP */
+#endif
+.endm
+
+/*
+ * Macro for data memory barrier (store/store variant).
+ */
+.macro  SMP_DMB_ST
+#if ANDROID_SMP != 0
+    dmb     st
+#else
+    /* not SMP */
+#endif
+.endm
diff --git a/vm/mterp/c/OP_ADD_DOUBLE.cpp b/vm/mterp/c/OP_ADD_DOUBLE.cpp
new file mode 100644
index 0000000..571aeb8
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE(OP_ADD_DOUBLE, "add", +)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_DOUBLE_2ADDR.cpp b/vm/mterp/c/OP_ADD_DOUBLE_2ADDR.cpp
new file mode 100644
index 0000000..af952cb
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_DOUBLE_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE_2ADDR(OP_ADD_DOUBLE_2ADDR, "add", +)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_FLOAT.cpp b/vm/mterp/c/OP_ADD_FLOAT.cpp
new file mode 100644
index 0000000..dab7d33
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT(OP_ADD_FLOAT, "add", +)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_FLOAT_2ADDR.cpp b/vm/mterp/c/OP_ADD_FLOAT_2ADDR.cpp
new file mode 100644
index 0000000..a068fd0
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_FLOAT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT_2ADDR(OP_ADD_FLOAT_2ADDR, "add", +)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_INT.cpp b/vm/mterp/c/OP_ADD_INT.cpp
new file mode 100644
index 0000000..bfaa590
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_ADD_INT, "add", +, 0)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_INT_2ADDR.cpp b/vm/mterp/c/OP_ADD_INT_2ADDR.cpp
new file mode 100644
index 0000000..dfd3289
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_ADD_INT_2ADDR, "add", +, 0)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_INT_LIT16.cpp b/vm/mterp/c/OP_ADD_INT_LIT16.cpp
new file mode 100644
index 0000000..442ab40
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_ADD_INT_LIT16, "add", +, 0)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_INT_LIT8.cpp b/vm/mterp/c/OP_ADD_INT_LIT8.cpp
new file mode 100644
index 0000000..1455599
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_ADD_INT_LIT8,   "add", +, 0)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_LONG.cpp b/vm/mterp/c/OP_ADD_LONG.cpp
new file mode 100644
index 0000000..25d1f47
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_ADD_LONG, "add", +, 0)
+OP_END
diff --git a/vm/mterp/c/OP_ADD_LONG_2ADDR.cpp b/vm/mterp/c/OP_ADD_LONG_2ADDR.cpp
new file mode 100644
index 0000000..4ae71bb
--- /dev/null
+++ b/vm/mterp/c/OP_ADD_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_ADD_LONG_2ADDR, "add", +, 0)
+OP_END
diff --git a/vm/mterp/c/OP_AGET.cpp b/vm/mterp/c/OP_AGET.cpp
new file mode 100644
index 0000000..766beaf
--- /dev/null
+++ b/vm/mterp/c/OP_AGET.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET, "", u4, )
+OP_END
diff --git a/vm/mterp/c/OP_AGET_BOOLEAN.cpp b/vm/mterp/c/OP_AGET_BOOLEAN.cpp
new file mode 100644
index 0000000..d63bc10
--- /dev/null
+++ b/vm/mterp/c/OP_AGET_BOOLEAN.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET_BOOLEAN, "-boolean", u1, )
+OP_END
diff --git a/vm/mterp/c/OP_AGET_BYTE.cpp b/vm/mterp/c/OP_AGET_BYTE.cpp
new file mode 100644
index 0000000..61ecc05
--- /dev/null
+++ b/vm/mterp/c/OP_AGET_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET_BYTE, "-byte", s1, )
+OP_END
diff --git a/vm/mterp/c/OP_AGET_CHAR.cpp b/vm/mterp/c/OP_AGET_CHAR.cpp
new file mode 100644
index 0000000..55e16ef
--- /dev/null
+++ b/vm/mterp/c/OP_AGET_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET_CHAR, "-char", u2, )
+OP_END
diff --git a/vm/mterp/c/OP_AGET_OBJECT.cpp b/vm/mterp/c/OP_AGET_OBJECT.cpp
new file mode 100644
index 0000000..903637c
--- /dev/null
+++ b/vm/mterp/c/OP_AGET_OBJECT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET_OBJECT, "-object", u4, )
+OP_END
diff --git a/vm/mterp/c/OP_AGET_SHORT.cpp b/vm/mterp/c/OP_AGET_SHORT.cpp
new file mode 100644
index 0000000..176b4a6
--- /dev/null
+++ b/vm/mterp/c/OP_AGET_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET_SHORT, "-short", s2, )
+OP_END
diff --git a/vm/mterp/c/OP_AGET_WIDE.cpp b/vm/mterp/c/OP_AGET_WIDE.cpp
new file mode 100644
index 0000000..e7974cb
--- /dev/null
+++ b/vm/mterp/c/OP_AGET_WIDE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_AGET(OP_AGET_WIDE, "-wide", s8, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_AND_INT.cpp b/vm/mterp/c/OP_AND_INT.cpp
new file mode 100644
index 0000000..3cf31cb
--- /dev/null
+++ b/vm/mterp/c/OP_AND_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_AND_INT, "and", &, 0)
+OP_END
diff --git a/vm/mterp/c/OP_AND_INT_2ADDR.cpp b/vm/mterp/c/OP_AND_INT_2ADDR.cpp
new file mode 100644
index 0000000..9f69292
--- /dev/null
+++ b/vm/mterp/c/OP_AND_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_AND_INT_2ADDR, "and", &, 0)
+OP_END
diff --git a/vm/mterp/c/OP_AND_INT_LIT16.cpp b/vm/mterp/c/OP_AND_INT_LIT16.cpp
new file mode 100644
index 0000000..19f825b
--- /dev/null
+++ b/vm/mterp/c/OP_AND_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_AND_INT_LIT16, "and", &, 0)
+OP_END
diff --git a/vm/mterp/c/OP_AND_INT_LIT8.cpp b/vm/mterp/c/OP_AND_INT_LIT8.cpp
new file mode 100644
index 0000000..c0e1315
--- /dev/null
+++ b/vm/mterp/c/OP_AND_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_AND_INT_LIT8,   "and", &, 0)
+OP_END
diff --git a/vm/mterp/c/OP_AND_LONG.cpp b/vm/mterp/c/OP_AND_LONG.cpp
new file mode 100644
index 0000000..1c638fb
--- /dev/null
+++ b/vm/mterp/c/OP_AND_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_AND_LONG, "and", &, 0)
+OP_END
diff --git a/vm/mterp/c/OP_AND_LONG_2ADDR.cpp b/vm/mterp/c/OP_AND_LONG_2ADDR.cpp
new file mode 100644
index 0000000..23c464d
--- /dev/null
+++ b/vm/mterp/c/OP_AND_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_AND_LONG_2ADDR, "and", &, 0)
+OP_END
diff --git a/vm/mterp/c/OP_APUT.cpp b/vm/mterp/c/OP_APUT.cpp
new file mode 100644
index 0000000..07d3e04
--- /dev/null
+++ b/vm/mterp/c/OP_APUT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_APUT(OP_APUT, "", u4, )
+OP_END
diff --git a/vm/mterp/c/OP_APUT_BOOLEAN.cpp b/vm/mterp/c/OP_APUT_BOOLEAN.cpp
new file mode 100644
index 0000000..fc69147
--- /dev/null
+++ b/vm/mterp/c/OP_APUT_BOOLEAN.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_APUT(OP_APUT_BOOLEAN, "-boolean", u1, )
+OP_END
diff --git a/vm/mterp/c/OP_APUT_BYTE.cpp b/vm/mterp/c/OP_APUT_BYTE.cpp
new file mode 100644
index 0000000..45aeb0b
--- /dev/null
+++ b/vm/mterp/c/OP_APUT_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_APUT(OP_APUT_BYTE, "-byte", s1, )
+OP_END
diff --git a/vm/mterp/c/OP_APUT_CHAR.cpp b/vm/mterp/c/OP_APUT_CHAR.cpp
new file mode 100644
index 0000000..1553c27
--- /dev/null
+++ b/vm/mterp/c/OP_APUT_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_APUT(OP_APUT_CHAR, "-char", u2, )
+OP_END
diff --git a/vm/mterp/c/OP_APUT_OBJECT.cpp b/vm/mterp/c/OP_APUT_OBJECT.cpp
new file mode 100644
index 0000000..a6a8064
--- /dev/null
+++ b/vm/mterp/c/OP_APUT_OBJECT.cpp
@@ -0,0 +1,38 @@
+HANDLE_OPCODE(OP_APUT_OBJECT /*vAA, vBB, vCC*/)
+    {
+        ArrayObject* arrayObj;
+        Object* obj;
+        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", "-object", vdst, vsrc1, vsrc2);
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        if (!checkForNull((Object*) arrayObj))
+            GOTO_exceptionThrown();
+        if (GET_REGISTER(vsrc2) >= arrayObj->length) {
+            dvmThrowArrayIndexOutOfBoundsException(
+                arrayObj->length, GET_REGISTER(vsrc2));
+            GOTO_exceptionThrown();
+        }
+        obj = (Object*) GET_REGISTER(vdst);
+        if (obj != NULL) {
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+            if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
+                LOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
+                    obj->clazz->descriptor, obj,
+                    arrayObj->obj.clazz->descriptor, arrayObj);
+                dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_APUT_SHORT.cpp b/vm/mterp/c/OP_APUT_SHORT.cpp
new file mode 100644
index 0000000..a72b5ea
--- /dev/null
+++ b/vm/mterp/c/OP_APUT_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_APUT(OP_APUT_SHORT, "-short", s2, )
+OP_END
diff --git a/vm/mterp/c/OP_APUT_WIDE.cpp b/vm/mterp/c/OP_APUT_WIDE.cpp
new file mode 100644
index 0000000..39c8cfa
--- /dev/null
+++ b/vm/mterp/c/OP_APUT_WIDE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_APUT(OP_APUT_WIDE, "-wide", s8, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_ARRAY_LENGTH.cpp b/vm/mterp/c/OP_ARRAY_LENGTH.cpp
new file mode 100644
index 0000000..0d5a933
--- /dev/null
+++ b/vm/mterp/c/OP_ARRAY_LENGTH.cpp
@@ -0,0 +1,15 @@
+HANDLE_OPCODE(OP_ARRAY_LENGTH /*vA, vB*/)
+    {
+        ArrayObject* arrayObj;
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        ILOGV("|array-length v%d,v%d  (%p)", vdst, vsrc1, arrayObj);
+        if (!checkForNullExportPC((Object*) arrayObj, fp, pc))
+            GOTO_exceptionThrown();
+        /* verifier guarantees this is an array reference */
+        SET_REGISTER(vdst, arrayObj->length);
+    }
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_BREAKPOINT.cpp b/vm/mterp/c/OP_BREAKPOINT.cpp
new file mode 100644
index 0000000..47f9d4a
--- /dev/null
+++ b/vm/mterp/c/OP_BREAKPOINT.cpp
@@ -0,0 +1,24 @@
+HANDLE_OPCODE(OP_BREAKPOINT)
+    {
+        /*
+         * Restart this instruction with the original opcode.  We do
+         * this by simply jumping to the handler.
+         *
+         * It's probably not necessary to update "inst", but we do it
+         * for the sake of anything that needs to do disambiguation in a
+         * common handler with INST_INST.
+         *
+         * The breakpoint itself is handled over in updateDebugger(),
+         * because we need to detect other events (method entry, single
+         * step) and report them in the same event packet, and we're not
+         * yet handling those through breakpoint instructions.  By the
+         * time we get here, the breakpoint has already been handled and
+         * the thread resumed.
+         */
+        u1 originalOpcode = dvmGetOriginalOpcode(pc);
+        LOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
+            INST_REPLACE_OP(inst, originalOpcode));
+        inst = INST_REPLACE_OP(inst, originalOpcode);
+        FINISH_BKPT(originalOpcode);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_CHECK_CAST.cpp b/vm/mterp/c/OP_CHECK_CAST.cpp
new file mode 100644
index 0000000..2c4a304
--- /dev/null
+++ b/vm/mterp/c/OP_CHECK_CAST.cpp
@@ -0,0 +1,31 @@
+HANDLE_OPCODE(OP_CHECK_CAST /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ref = FETCH(1);         /* class to check against */
+        ILOGV("|check-cast v%d,class@0x%04x", vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj != NULL) {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                clazz = dvmResolveClass(curMethod->clazz, ref, false);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            if (!dvmInstanceof(obj->clazz, clazz)) {
+                dvmThrowClassCastException(obj->clazz, clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_CHECK_CAST_JUMBO.cpp b/vm/mterp/c/OP_CHECK_CAST_JUMBO.cpp
new file mode 100644
index 0000000..75c314b
--- /dev/null
+++ b/vm/mterp/c/OP_CHECK_CAST_JUMBO.cpp
@@ -0,0 +1,31 @@
+HANDLE_OPCODE(OP_CHECK_CAST_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;     /* class to check against */
+        vsrc1 = FETCH(3);
+        ILOGV("|check-cast/jumbo v%d,class@0x%08x", vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj != NULL) {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                clazz = dvmResolveClass(curMethod->clazz, ref, false);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            if (!dvmInstanceof(obj->clazz, clazz)) {
+                dvmThrowClassCastException(obj->clazz, clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+    }
+    FINISH(4);
+OP_END
diff --git a/vm/mterp/c/OP_CMPG_DOUBLE.cpp b/vm/mterp/c/OP_CMPG_DOUBLE.cpp
new file mode 100644
index 0000000..3f4082c
--- /dev/null
+++ b/vm/mterp/c/OP_CMPG_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_CMPX(OP_CMPG_DOUBLE, "g-double", double, _DOUBLE, 1)
+OP_END
diff --git a/vm/mterp/c/OP_CMPG_FLOAT.cpp b/vm/mterp/c/OP_CMPG_FLOAT.cpp
new file mode 100644
index 0000000..0bba49e
--- /dev/null
+++ b/vm/mterp/c/OP_CMPG_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_CMPX(OP_CMPG_FLOAT, "g-float", float, _FLOAT, 1)
+OP_END
diff --git a/vm/mterp/c/OP_CMPL_DOUBLE.cpp b/vm/mterp/c/OP_CMPL_DOUBLE.cpp
new file mode 100644
index 0000000..4da18b4
--- /dev/null
+++ b/vm/mterp/c/OP_CMPL_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_CMPX(OP_CMPL_DOUBLE, "l-double", double, _DOUBLE, -1)
+OP_END
diff --git a/vm/mterp/c/OP_CMPL_FLOAT.cpp b/vm/mterp/c/OP_CMPL_FLOAT.cpp
new file mode 100644
index 0000000..7916193
--- /dev/null
+++ b/vm/mterp/c/OP_CMPL_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_CMPX(OP_CMPL_FLOAT, "l-float", float, _FLOAT, -1)
+OP_END
diff --git a/vm/mterp/c/OP_CMP_LONG.cpp b/vm/mterp/c/OP_CMP_LONG.cpp
new file mode 100644
index 0000000..a0e412c
--- /dev/null
+++ b/vm/mterp/c/OP_CMP_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_CMPX(OP_CMP_LONG, "-long", s8, _WIDE, 0)
+OP_END
diff --git a/vm/mterp/c/OP_CONST.cpp b/vm/mterp/c/OP_CONST.cpp
new file mode 100644
index 0000000..e281a51
--- /dev/null
+++ b/vm/mterp/c/OP_CONST.cpp
@@ -0,0 +1,12 @@
+HANDLE_OPCODE(OP_CONST /*vAA, #+BBBBBBBB*/)
+    {
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const v%d,#0x%08x", vdst, tmp);
+        SET_REGISTER(vdst, tmp);
+    }
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_16.cpp b/vm/mterp/c/OP_CONST_16.cpp
new file mode 100644
index 0000000..f58f50c
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_16.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_CONST_16 /*vAA, #+BBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const/16 v%d,#0x%04x", vdst, (s2)vsrc1);
+    SET_REGISTER(vdst, (s2) vsrc1);
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_4.cpp b/vm/mterp/c/OP_CONST_4.cpp
new file mode 100644
index 0000000..800ef9a
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_4.cpp
@@ -0,0 +1,11 @@
+HANDLE_OPCODE(OP_CONST_4 /*vA, #+B*/)
+    {
+        s4 tmp;
+
+        vdst = INST_A(inst);
+        tmp = (s4) (INST_B(inst) << 28) >> 28;  // sign extend 4-bit value
+        ILOGV("|const/4 v%d,#0x%02x", vdst, (s4)tmp);
+        SET_REGISTER(vdst, tmp);
+    }
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_CLASS.cpp b/vm/mterp/c/OP_CONST_CLASS.cpp
new file mode 100644
index 0000000..9c60a27
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_CLASS.cpp
@@ -0,0 +1,18 @@
+HANDLE_OPCODE(OP_CONST_CLASS /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|const-class v%d class@0x%04x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            EXPORT_PC();
+            clazz = dvmResolveClass(curMethod->clazz, ref, true);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) clazz);
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_CLASS_JUMBO.cpp b/vm/mterp/c/OP_CONST_CLASS_JUMBO.cpp
new file mode 100644
index 0000000..4fb1431
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_CLASS_JUMBO.cpp
@@ -0,0 +1,18 @@
+HANDLE_OPCODE(OP_CONST_CLASS_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        ILOGV("|const-class/jumbo v%d class@0x%08x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            EXPORT_PC();
+            clazz = dvmResolveClass(curMethod->clazz, ref, true);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) clazz);
+    }
+    FINISH(4);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_HIGH16.cpp b/vm/mterp/c/OP_CONST_HIGH16.cpp
new file mode 100644
index 0000000..26b22f4
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_HIGH16.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_CONST_HIGH16 /*vAA, #+BBBB0000*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const/high16 v%d,#0x%04x0000", vdst, vsrc1);
+    SET_REGISTER(vdst, vsrc1 << 16);
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_STRING.cpp b/vm/mterp/c/OP_CONST_STRING.cpp
new file mode 100644
index 0000000..748119a
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_STRING.cpp
@@ -0,0 +1,18 @@
+HANDLE_OPCODE(OP_CONST_STRING /*vAA, string@BBBB*/)
+    {
+        StringObject* strObj;
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|const-string v%d string@0x%04x", vdst, ref);
+        strObj = dvmDexGetResolvedString(methodClassDex, ref);
+        if (strObj == NULL) {
+            EXPORT_PC();
+            strObj = dvmResolveString(curMethod->clazz, ref);
+            if (strObj == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) strObj);
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_STRING_JUMBO.cpp b/vm/mterp/c/OP_CONST_STRING_JUMBO.cpp
new file mode 100644
index 0000000..435b34c
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_STRING_JUMBO.cpp
@@ -0,0 +1,20 @@
+HANDLE_OPCODE(OP_CONST_STRING_JUMBO /*vAA, string@BBBBBBBB*/)
+    {
+        StringObject* strObj;
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const-string/jumbo v%d string@0x%08x", vdst, tmp);
+        strObj = dvmDexGetResolvedString(methodClassDex, tmp);
+        if (strObj == NULL) {
+            EXPORT_PC();
+            strObj = dvmResolveString(curMethod->clazz, tmp);
+            if (strObj == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) strObj);
+    }
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_WIDE.cpp b/vm/mterp/c/OP_CONST_WIDE.cpp
new file mode 100644
index 0000000..ccb3955
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_WIDE.cpp
@@ -0,0 +1,14 @@
+HANDLE_OPCODE(OP_CONST_WIDE /*vAA, #+BBBBBBBBBBBBBBBB*/)
+    {
+        u8 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u8)FETCH(2) << 16;
+        tmp |= (u8)FETCH(3) << 32;
+        tmp |= (u8)FETCH(4) << 48;
+        ILOGV("|const-wide v%d,#0x%08llx", vdst, tmp);
+        SET_REGISTER_WIDE(vdst, tmp);
+    }
+    FINISH(5);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_WIDE_16.cpp b/vm/mterp/c/OP_CONST_WIDE_16.cpp
new file mode 100644
index 0000000..da69f37
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_WIDE_16.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_CONST_WIDE_16 /*vAA, #+BBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const-wide/16 v%d,#0x%04x", vdst, (s2)vsrc1);
+    SET_REGISTER_WIDE(vdst, (s2)vsrc1);
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_WIDE_32.cpp b/vm/mterp/c/OP_CONST_WIDE_32.cpp
new file mode 100644
index 0000000..ad4acbb
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_WIDE_32.cpp
@@ -0,0 +1,12 @@
+HANDLE_OPCODE(OP_CONST_WIDE_32 /*vAA, #+BBBBBBBB*/)
+    {
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const-wide/32 v%d,#0x%08x", vdst, tmp);
+        SET_REGISTER_WIDE(vdst, (s4) tmp);
+    }
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_CONST_WIDE_HIGH16.cpp b/vm/mterp/c/OP_CONST_WIDE_HIGH16.cpp
new file mode 100644
index 0000000..bcc0664
--- /dev/null
+++ b/vm/mterp/c/OP_CONST_WIDE_HIGH16.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_CONST_WIDE_HIGH16 /*vAA, #+BBBB000000000000*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const-wide/high16 v%d,#0x%04x000000000000", vdst, vsrc1);
+    SET_REGISTER_WIDE(vdst, ((u8) vsrc1) << 48);
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_DISPATCH_FF.cpp b/vm/mterp/c/OP_DISPATCH_FF.cpp
new file mode 100644
index 0000000..53f50c5
--- /dev/null
+++ b/vm/mterp/c/OP_DISPATCH_FF.cpp
@@ -0,0 +1,6 @@
+HANDLE_OPCODE(OP_DISPATCH_FF)
+    /*
+     * Indicates extended opcode.  Use next 8 bits to choose where to branch.
+     */
+    DISPATCH_EXTENDED(INST_AA(inst));
+OP_END
diff --git a/vm/mterp/c/OP_DIV_DOUBLE.cpp b/vm/mterp/c/OP_DIV_DOUBLE.cpp
new file mode 100644
index 0000000..d6e4b55
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE(OP_DIV_DOUBLE, "div", /)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_DOUBLE_2ADDR.cpp b/vm/mterp/c/OP_DIV_DOUBLE_2ADDR.cpp
new file mode 100644
index 0000000..85a1523
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_DOUBLE_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE_2ADDR(OP_DIV_DOUBLE_2ADDR, "div", /)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_FLOAT.cpp b/vm/mterp/c/OP_DIV_FLOAT.cpp
new file mode 100644
index 0000000..2c5049b
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT(OP_DIV_FLOAT, "div", /)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_FLOAT_2ADDR.cpp b/vm/mterp/c/OP_DIV_FLOAT_2ADDR.cpp
new file mode 100644
index 0000000..cd7b4d9
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_FLOAT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT_2ADDR(OP_DIV_FLOAT_2ADDR, "div", /)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_INT.cpp b/vm/mterp/c/OP_DIV_INT.cpp
new file mode 100644
index 0000000..af6e8c6
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_DIV_INT, "div", /, 1)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_INT_2ADDR.cpp b/vm/mterp/c/OP_DIV_INT_2ADDR.cpp
new file mode 100644
index 0000000..80c0da7
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_DIV_INT_2ADDR, "div", /, 1)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_INT_LIT16.cpp b/vm/mterp/c/OP_DIV_INT_LIT16.cpp
new file mode 100644
index 0000000..4e8d901
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_DIV_INT_LIT16, "div", /, 1)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_INT_LIT8.cpp b/vm/mterp/c/OP_DIV_INT_LIT8.cpp
new file mode 100644
index 0000000..eec5389
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_DIV_INT_LIT8,   "div", /, 1)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_LONG.cpp b/vm/mterp/c/OP_DIV_LONG.cpp
new file mode 100644
index 0000000..557b56b
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_DIV_LONG, "div", /, 1)
+OP_END
diff --git a/vm/mterp/c/OP_DIV_LONG_2ADDR.cpp b/vm/mterp/c/OP_DIV_LONG_2ADDR.cpp
new file mode 100644
index 0000000..00e0e6c
--- /dev/null
+++ b/vm/mterp/c/OP_DIV_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_DIV_LONG_2ADDR, "div", /, 1)
+OP_END
diff --git a/vm/mterp/c/OP_DOUBLE_TO_FLOAT.cpp b/vm/mterp/c/OP_DOUBLE_TO_FLOAT.cpp
new file mode 100644
index 0000000..152e5fd
--- /dev/null
+++ b/vm/mterp/c/OP_DOUBLE_TO_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_DOUBLE_TO_FLOAT,      "double-to-float", _DOUBLE, _FLOAT)
+OP_END
diff --git a/vm/mterp/c/OP_DOUBLE_TO_INT.cpp b/vm/mterp/c/OP_DOUBLE_TO_INT.cpp
new file mode 100644
index 0000000..e210b92
--- /dev/null
+++ b/vm/mterp/c/OP_DOUBLE_TO_INT.cpp
@@ -0,0 +1,3 @@
+HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_INT,   "double-to-int",
+    double, _DOUBLE, s4, _INT)
+OP_END
diff --git a/vm/mterp/c/OP_DOUBLE_TO_LONG.cpp b/vm/mterp/c/OP_DOUBLE_TO_LONG.cpp
new file mode 100644
index 0000000..44d548c
--- /dev/null
+++ b/vm/mterp/c/OP_DOUBLE_TO_LONG.cpp
@@ -0,0 +1,3 @@
+HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_LONG,  "double-to-long",
+    double, _DOUBLE, s8, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_EXECUTE_INLINE.cpp b/vm/mterp/c/OP_EXECUTE_INLINE.cpp
new file mode 100644
index 0000000..8d20764
--- /dev/null
+++ b/vm/mterp/c/OP_EXECUTE_INLINE.cpp
@@ -0,0 +1,59 @@
+HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/)
+    {
+        /*
+         * This has the same form as other method calls, but we ignore
+         * the 5th argument (vA).  This is chiefly because the first four
+         * arguments to a function on ARM are in registers.
+         *
+         * We only set the arguments that are actually used, leaving
+         * the rest uninitialized.  We're assuming that, if the method
+         * needs them, they'll be specified in the call.
+         *
+         * However, this annoys gcc when optimizations are enabled,
+         * causing a "may be used uninitialized" warning.  Quieting
+         * the warnings incurs a slight penalty (5%: 373ns vs. 393ns
+         * on empty method).  Note that valgrind is perfectly happy
+         * either way as the uninitialiezd values are never actually
+         * used.
+         */
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_B(inst);       /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* 0-4 register indices */
+        ILOGV("|execute-inline args=%d @%d {regs=0x%04x}",
+            vsrc1, ref, vdst);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst >> 12);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER((vdst & 0x0f00) >> 8);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER((vdst & 0x00f0) >> 4);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst & 0x0f);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp b/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp
new file mode 100644
index 0000000..664ada4
--- /dev/null
+++ b/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.cpp
@@ -0,0 +1,43 @@
+HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
+    {
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;      /* placate gcc */
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* range base */
+        ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst+3);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER(vdst+2);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER(vdst+1);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst+0);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_FILLED_NEW_ARRAY.cpp b/vm/mterp/c/OP_FILLED_NEW_ARRAY.cpp
new file mode 100644
index 0000000..281318d
--- /dev/null
+++ b/vm/mterp/c/OP_FILLED_NEW_ARRAY.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
+    GOTO_invoke(filledNewArray, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_FILLED_NEW_ARRAY_JUMBO.cpp b/vm/mterp/c/OP_FILLED_NEW_ARRAY_JUMBO.cpp
new file mode 100644
index 0000000..dfbc31b
--- /dev/null
+++ b/vm/mterp/c/OP_FILLED_NEW_ARRAY_JUMBO.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, class@AAAAAAAA*/)
+    GOTO_invoke(filledNewArray, true, true);
+OP_END
diff --git a/vm/mterp/c/OP_FILLED_NEW_ARRAY_RANGE.cpp b/vm/mterp/c/OP_FILLED_NEW_ARRAY_RANGE.cpp
new file mode 100644
index 0000000..48bdf26
--- /dev/null
+++ b/vm/mterp/c/OP_FILLED_NEW_ARRAY_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_RANGE /*{vCCCC..v(CCCC+AA-1)}, class@BBBB*/)
+    GOTO_invoke(filledNewArray, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_FILL_ARRAY_DATA.cpp b/vm/mterp/c/OP_FILL_ARRAY_DATA.cpp
new file mode 100644
index 0000000..678bb32
--- /dev/null
+++ b/vm/mterp/c/OP_FILL_ARRAY_DATA.cpp
@@ -0,0 +1,27 @@
+HANDLE_OPCODE(OP_FILL_ARRAY_DATA)   /*vAA, +BBBBBBBB*/
+    {
+        const u2* arrayData;
+        s4 offset;
+        ArrayObject* arrayObj;
+
+        EXPORT_PC();
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|fill-array-data v%d +0x%04x", vsrc1, offset);
+        arrayData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (arrayData < curMethod->insns ||
+            arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            dvmThrowInternalError("bad fill array data");
+            GOTO_exceptionThrown();
+        }
+#endif
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        if (!dvmInterpHandleFillArrayData(arrayObj, arrayData)) {
+            GOTO_exceptionThrown();
+        }
+        FINISH(3);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_FLOAT_TO_DOUBLE.cpp b/vm/mterp/c/OP_FLOAT_TO_DOUBLE.cpp
new file mode 100644
index 0000000..ea5e7a6
--- /dev/null
+++ b/vm/mterp/c/OP_FLOAT_TO_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_FLOAT_TO_DOUBLE,      "float-to-double", _FLOAT, _DOUBLE)
+OP_END
diff --git a/vm/mterp/c/OP_FLOAT_TO_INT.cpp b/vm/mterp/c/OP_FLOAT_TO_INT.cpp
new file mode 100644
index 0000000..15522f8
--- /dev/null
+++ b/vm/mterp/c/OP_FLOAT_TO_INT.cpp
@@ -0,0 +1,3 @@
+HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_INT,    "float-to-int",
+    float, _FLOAT, s4, _INT)
+OP_END
diff --git a/vm/mterp/c/OP_FLOAT_TO_LONG.cpp b/vm/mterp/c/OP_FLOAT_TO_LONG.cpp
new file mode 100644
index 0000000..03bd30d
--- /dev/null
+++ b/vm/mterp/c/OP_FLOAT_TO_LONG.cpp
@@ -0,0 +1,3 @@
+HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_LONG,   "float-to-long",
+    float, _FLOAT, s8, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_GOTO.cpp b/vm/mterp/c/OP_GOTO.cpp
new file mode 100644
index 0000000..0e10384
--- /dev/null
+++ b/vm/mterp/c/OP_GOTO.cpp
@@ -0,0 +1,11 @@
+HANDLE_OPCODE(OP_GOTO /*+AA*/)
+    vdst = INST_AA(inst);
+    if ((s1)vdst < 0)
+        ILOGV("|goto -0x%02x", -((s1)vdst));
+    else
+        ILOGV("|goto +0x%02x", ((s1)vdst));
+    ILOGV("> branch taken");
+    if ((s1)vdst < 0)
+        PERIODIC_CHECKS((s1)vdst);
+    FINISH((s1)vdst);
+OP_END
diff --git a/vm/mterp/c/OP_GOTO_16.cpp b/vm/mterp/c/OP_GOTO_16.cpp
new file mode 100644
index 0000000..f0541fd
--- /dev/null
+++ b/vm/mterp/c/OP_GOTO_16.cpp
@@ -0,0 +1,14 @@
+HANDLE_OPCODE(OP_GOTO_16 /*+AAAA*/)
+    {
+        s4 offset = (s2) FETCH(1);          /* sign-extend next code unit */
+
+        if (offset < 0)
+            ILOGV("|goto/16 -0x%04x", -offset);
+        else
+            ILOGV("|goto/16 +0x%04x", offset);
+        ILOGV("> branch taken");
+        if (offset < 0)
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_GOTO_32.cpp b/vm/mterp/c/OP_GOTO_32.cpp
new file mode 100644
index 0000000..1b1815c
--- /dev/null
+++ b/vm/mterp/c/OP_GOTO_32.cpp
@@ -0,0 +1,15 @@
+HANDLE_OPCODE(OP_GOTO_32 /*+AAAAAAAA*/)
+    {
+        s4 offset = FETCH(1);               /* low-order 16 bits */
+        offset |= ((s4) FETCH(2)) << 16;    /* high-order 16 bits */
+
+        if (offset < 0)
+            ILOGV("|goto/32 -0x%08x", -offset);
+        else
+            ILOGV("|goto/32 +0x%08x", offset);
+        ILOGV("> branch taken");
+        if (offset <= 0)    /* allowed to branch to self */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_IF_EQ.cpp b/vm/mterp/c/OP_IF_EQ.cpp
new file mode 100644
index 0000000..2c3b9b5
--- /dev/null
+++ b/vm/mterp/c/OP_IF_EQ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XX(OP_IF_EQ, "eq", ==)
+OP_END
diff --git a/vm/mterp/c/OP_IF_EQZ.cpp b/vm/mterp/c/OP_IF_EQZ.cpp
new file mode 100644
index 0000000..d2dd1aa
--- /dev/null
+++ b/vm/mterp/c/OP_IF_EQZ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XXZ(OP_IF_EQZ, "eqz", ==)
+OP_END
diff --git a/vm/mterp/c/OP_IF_GE.cpp b/vm/mterp/c/OP_IF_GE.cpp
new file mode 100644
index 0000000..8aa85c4
--- /dev/null
+++ b/vm/mterp/c/OP_IF_GE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XX(OP_IF_GE, "ge", >=)
+OP_END
diff --git a/vm/mterp/c/OP_IF_GEZ.cpp b/vm/mterp/c/OP_IF_GEZ.cpp
new file mode 100644
index 0000000..8c4b78a
--- /dev/null
+++ b/vm/mterp/c/OP_IF_GEZ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XXZ(OP_IF_GEZ, "gez", >=)
+OP_END
diff --git a/vm/mterp/c/OP_IF_GT.cpp b/vm/mterp/c/OP_IF_GT.cpp
new file mode 100644
index 0000000..d35eb29
--- /dev/null
+++ b/vm/mterp/c/OP_IF_GT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XX(OP_IF_GT, "gt", >)
+OP_END
diff --git a/vm/mterp/c/OP_IF_GTZ.cpp b/vm/mterp/c/OP_IF_GTZ.cpp
new file mode 100644
index 0000000..63a0073
--- /dev/null
+++ b/vm/mterp/c/OP_IF_GTZ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XXZ(OP_IF_GTZ, "gtz", >)
+OP_END
diff --git a/vm/mterp/c/OP_IF_LE.cpp b/vm/mterp/c/OP_IF_LE.cpp
new file mode 100644
index 0000000..f4b213a
--- /dev/null
+++ b/vm/mterp/c/OP_IF_LE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XX(OP_IF_LE, "le", <=)
+OP_END
diff --git a/vm/mterp/c/OP_IF_LEZ.cpp b/vm/mterp/c/OP_IF_LEZ.cpp
new file mode 100644
index 0000000..1d57a50
--- /dev/null
+++ b/vm/mterp/c/OP_IF_LEZ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XXZ(OP_IF_LEZ, "lez", <=)
+OP_END
diff --git a/vm/mterp/c/OP_IF_LT.cpp b/vm/mterp/c/OP_IF_LT.cpp
new file mode 100644
index 0000000..0233892
--- /dev/null
+++ b/vm/mterp/c/OP_IF_LT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XX(OP_IF_LT, "lt", <)
+OP_END
diff --git a/vm/mterp/c/OP_IF_LTZ.cpp b/vm/mterp/c/OP_IF_LTZ.cpp
new file mode 100644
index 0000000..b4b9be2
--- /dev/null
+++ b/vm/mterp/c/OP_IF_LTZ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XXZ(OP_IF_LTZ, "ltz", <)
+OP_END
diff --git a/vm/mterp/c/OP_IF_NE.cpp b/vm/mterp/c/OP_IF_NE.cpp
new file mode 100644
index 0000000..8da70a5
--- /dev/null
+++ b/vm/mterp/c/OP_IF_NE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XX(OP_IF_NE, "ne", !=)
+OP_END
diff --git a/vm/mterp/c/OP_IF_NEZ.cpp b/vm/mterp/c/OP_IF_NEZ.cpp
new file mode 100644
index 0000000..209e836
--- /dev/null
+++ b/vm/mterp/c/OP_IF_NEZ.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_IF_XXZ(OP_IF_NEZ, "nez", !=)
+OP_END
diff --git a/vm/mterp/c/OP_IGET.cpp b/vm/mterp/c/OP_IGET.cpp
new file mode 100644
index 0000000..c6333e5
--- /dev/null
+++ b/vm/mterp/c/OP_IGET.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET,                  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_BOOLEAN.cpp b/vm/mterp/c/OP_IGET_BOOLEAN.cpp
new file mode 100644
index 0000000..a5a47be
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_BOOLEAN.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_BOOLEAN,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_BOOLEAN_JUMBO.cpp b/vm/mterp/c/OP_IGET_BOOLEAN_JUMBO.cpp
new file mode 100644
index 0000000..712ae91
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_BOOLEAN_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_BOOLEAN_JUMBO,  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_BYTE.cpp b/vm/mterp/c/OP_IGET_BYTE.cpp
new file mode 100644
index 0000000..647f311
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_BYTE,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_BYTE_JUMBO.cpp b/vm/mterp/c/OP_IGET_BYTE_JUMBO.cpp
new file mode 100644
index 0000000..ade7eb9
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_BYTE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_BYTE_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_CHAR.cpp b/vm/mterp/c/OP_IGET_CHAR.cpp
new file mode 100644
index 0000000..9a8adb0
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_CHAR,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_CHAR_JUMBO.cpp b/vm/mterp/c/OP_IGET_CHAR_JUMBO.cpp
new file mode 100644
index 0000000..a674059
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_CHAR_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_CHAR_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_JUMBO.cpp b/vm/mterp/c/OP_IGET_JUMBO.cpp
new file mode 100644
index 0000000..32eefc8
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_JUMBO,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_OBJECT.cpp b/vm/mterp/c/OP_IGET_OBJECT.cpp
new file mode 100644
index 0000000..03c9e50
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_OBJECT.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_OBJECT_JUMBO.cpp b/vm/mterp/c/OP_IGET_OBJECT_JUMBO.cpp
new file mode 100644
index 0000000..2b25dae
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_OBJECT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_OBJECT_QUICK.cpp b/vm/mterp/c/OP_IGET_OBJECT_QUICK.cpp
new file mode 100644
index 0000000..2ac3a54
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_OBJECT_QUICK.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_QUICK(OP_IGET_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_OBJECT_VOLATILE.cpp b/vm/mterp/c/OP_IGET_OBJECT_VOLATILE.cpp
new file mode 100644
index 0000000..3577552
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_OBJECT_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..705aefd
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_QUICK.cpp b/vm/mterp/c/OP_IGET_QUICK.cpp
new file mode 100644
index 0000000..b5724cc
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_QUICK.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_QUICK(OP_IGET_QUICK,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_SHORT.cpp b/vm/mterp/c/OP_IGET_SHORT.cpp
new file mode 100644
index 0000000..3e77789
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_SHORT,            "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_SHORT_JUMBO.cpp b/vm/mterp/c/OP_IGET_SHORT_JUMBO.cpp
new file mode 100644
index 0000000..30b3ff1
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_SHORT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_SHORT_JUMBO,    "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_VOLATILE.cpp b/vm/mterp/c/OP_IGET_VOLATILE.cpp
new file mode 100644
index 0000000..7a3be56
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_IGET_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..462279a
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_IGET_WIDE.cpp b/vm/mterp/c/OP_IGET_WIDE.cpp
new file mode 100644
index 0000000..cb1fcca
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_WIDE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_WIDE,             "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_WIDE_JUMBO.cpp b/vm/mterp/c/OP_IGET_WIDE_JUMBO.cpp
new file mode 100644
index 0000000..f607a77
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_WIDE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_WIDE_QUICK.cpp b/vm/mterp/c/OP_IGET_WIDE_QUICK.cpp
new file mode 100644
index 0000000..adb4fc1
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_WIDE_QUICK.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_QUICK(OP_IGET_WIDE_QUICK,     "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_WIDE_VOLATILE.cpp b/vm/mterp/c/OP_IGET_WIDE_VOLATILE.cpp
new file mode 100644
index 0000000..a080823
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_WIDE_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..5285a31
--- /dev/null
+++ b/vm/mterp/c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_INSTANCE_OF.cpp b/vm/mterp/c/OP_INSTANCE_OF.cpp
new file mode 100644
index 0000000..8b8f9d3
--- /dev/null
+++ b/vm/mterp/c/OP_INSTANCE_OF.cpp
@@ -0,0 +1,30 @@
+HANDLE_OPCODE(OP_INSTANCE_OF /*vA, vB, class@CCCC*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);   /* object to check */
+        ref = FETCH(1);         /* class to check against */
+        ILOGV("|instance-of v%d,v%d,class@0x%04x", vdst, vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj == NULL) {
+            SET_REGISTER(vdst, 0);
+        } else {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNullExportPC(obj, fp, pc))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                EXPORT_PC();
+                clazz = dvmResolveClass(curMethod->clazz, ref, true);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+        }
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_INSTANCE_OF_JUMBO.cpp b/vm/mterp/c/OP_INSTANCE_OF_JUMBO.cpp
new file mode 100644
index 0000000..0249d96
--- /dev/null
+++ b/vm/mterp/c/OP_INSTANCE_OF_JUMBO.cpp
@@ -0,0 +1,30 @@
+HANDLE_OPCODE(OP_INSTANCE_OF_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;     /* class to check against */
+        vdst = FETCH(3);
+        vsrc1 = FETCH(4);   /* object to check */
+        ILOGV("|instance-of/jumbo v%d,v%d,class@0x%08x", vdst, vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj == NULL) {
+            SET_REGISTER(vdst, 0);
+        } else {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNullExportPC(obj, fp, pc))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                EXPORT_PC();
+                clazz = dvmResolveClass(curMethod->clazz, ref, true);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+        }
+    }
+    FINISH(5);
+OP_END
diff --git a/vm/mterp/c/OP_INT_TO_BYTE.cpp b/vm/mterp/c/OP_INT_TO_BYTE.cpp
new file mode 100644
index 0000000..ea75747
--- /dev/null
+++ b/vm/mterp/c/OP_INT_TO_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_INT_TO_SMALL(OP_INT_TO_BYTE,     "byte", s1)
+OP_END
diff --git a/vm/mterp/c/OP_INT_TO_CHAR.cpp b/vm/mterp/c/OP_INT_TO_CHAR.cpp
new file mode 100644
index 0000000..45ae0df
--- /dev/null
+++ b/vm/mterp/c/OP_INT_TO_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_INT_TO_SMALL(OP_INT_TO_CHAR,     "char", u2)
+OP_END
diff --git a/vm/mterp/c/OP_INT_TO_DOUBLE.cpp b/vm/mterp/c/OP_INT_TO_DOUBLE.cpp
new file mode 100644
index 0000000..624c702
--- /dev/null
+++ b/vm/mterp/c/OP_INT_TO_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_INT_TO_DOUBLE,        "int-to-double", _INT, _DOUBLE)
+OP_END
diff --git a/vm/mterp/c/OP_INT_TO_FLOAT.cpp b/vm/mterp/c/OP_INT_TO_FLOAT.cpp
new file mode 100644
index 0000000..fd15199
--- /dev/null
+++ b/vm/mterp/c/OP_INT_TO_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_INT_TO_FLOAT,         "int-to-float", _INT, _FLOAT)
+OP_END
diff --git a/vm/mterp/c/OP_INT_TO_LONG.cpp b/vm/mterp/c/OP_INT_TO_LONG.cpp
new file mode 100644
index 0000000..8bc4223
--- /dev/null
+++ b/vm/mterp/c/OP_INT_TO_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_INT_TO_LONG,          "int-to-long", _INT, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_INT_TO_SHORT.cpp b/vm/mterp/c/OP_INT_TO_SHORT.cpp
new file mode 100644
index 0000000..0f06739
--- /dev/null
+++ b/vm/mterp/c/OP_INT_TO_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_INT_TO_SMALL(OP_INT_TO_SHORT,    "short", s2)    /* want sign bit */
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_DIRECT.cpp b/vm/mterp/c/OP_INVOKE_DIRECT.cpp
new file mode 100644
index 0000000..11a2c81
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_DIRECT.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_DIRECT /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeDirect, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_DIRECT_JUMBO.cpp b/vm/mterp/c/OP_INVOKE_DIRECT_JUMBO.cpp
new file mode 100644
index 0000000..e31e584
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_DIRECT_JUMBO.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_DIRECT_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeDirect, true, true);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_DIRECT_RANGE.cpp b/vm/mterp/c/OP_INVOKE_DIRECT_RANGE.cpp
new file mode 100644
index 0000000..6de06ee
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_DIRECT_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_DIRECT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeDirect, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_INTERFACE.cpp b/vm/mterp/c/OP_INVOKE_INTERFACE.cpp
new file mode 100644
index 0000000..1de99d1
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_INTERFACE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_INTERFACE /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeInterface, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_INTERFACE_JUMBO.cpp b/vm/mterp/c/OP_INVOKE_INTERFACE_JUMBO.cpp
new file mode 100644
index 0000000..720a9bf
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_INTERFACE_JUMBO.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_INTERFACE_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeInterface, true, true);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_INTERFACE_RANGE.cpp b/vm/mterp/c/OP_INVOKE_INTERFACE_RANGE.cpp
new file mode 100644
index 0000000..5cabdfb
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_INTERFACE_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_INTERFACE_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeInterface, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp b/vm/mterp/c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp
new file mode 100644
index 0000000..324e462
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp
@@ -0,0 +1,29 @@
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_JUMBO /*{vCCCC..vNNNN}, meth@AAAAAAAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(4);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, true);
+        }
+        FINISH(5);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.cpp b/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.cpp
new file mode 100644
index 0000000..20f0573
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_OBJECT_INIT_RANGE.cpp
@@ -0,0 +1,29 @@
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(2);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, false);
+        }
+        FINISH(3);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_STATIC.cpp b/vm/mterp/c/OP_INVOKE_STATIC.cpp
new file mode 100644
index 0000000..a162e0b
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_STATIC.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_STATIC /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeStatic, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_STATIC_JUMBO.cpp b/vm/mterp/c/OP_INVOKE_STATIC_JUMBO.cpp
new file mode 100644
index 0000000..29066e9
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_STATIC_JUMBO.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_STATIC_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeStatic, true, true);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_STATIC_RANGE.cpp b/vm/mterp/c/OP_INVOKE_STATIC_RANGE.cpp
new file mode 100644
index 0000000..103f745
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_STATIC_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_STATIC_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeStatic, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_SUPER.cpp b/vm/mterp/c/OP_INVOKE_SUPER.cpp
new file mode 100644
index 0000000..e70e8ed
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_SUPER.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeSuper, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_SUPER_JUMBO.cpp b/vm/mterp/c/OP_INVOKE_SUPER_JUMBO.cpp
new file mode 100644
index 0000000..e1e75c1
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_SUPER_JUMBO.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_SUPER_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeSuper, true, true);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_SUPER_QUICK.cpp b/vm/mterp/c/OP_INVOKE_SUPER_QUICK.cpp
new file mode 100644
index 0000000..1c9b16c
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_SUPER_QUICK.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeSuperQuick, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_SUPER_QUICK_RANGE.cpp b/vm/mterp/c/OP_INVOKE_SUPER_QUICK_RANGE.cpp
new file mode 100644
index 0000000..4b11ccc
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_SUPER_QUICK_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeSuperQuick, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_SUPER_RANGE.cpp b/vm/mterp/c/OP_INVOKE_SUPER_RANGE.cpp
new file mode 100644
index 0000000..fca6b3e
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_SUPER_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_SUPER_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeSuper, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_VIRTUAL.cpp b/vm/mterp/c/OP_INVOKE_VIRTUAL.cpp
new file mode 100644
index 0000000..894ad46
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_VIRTUAL.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeVirtual, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_VIRTUAL_JUMBO.cpp b/vm/mterp/c/OP_INVOKE_VIRTUAL_JUMBO.cpp
new file mode 100644
index 0000000..9fa61ec
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_VIRTUAL_JUMBO.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeVirtual, true, true);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_VIRTUAL_QUICK.cpp b/vm/mterp/c/OP_INVOKE_VIRTUAL_QUICK.cpp
new file mode 100644
index 0000000..7a6d540
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_VIRTUAL_QUICK.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeVirtualQuick, false, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_VIRTUAL_QUICK_RANGE.cpp b/vm/mterp/c/OP_INVOKE_VIRTUAL_QUICK_RANGE.cpp
new file mode 100644
index 0000000..e70446c
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_VIRTUAL_QUICK_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK_RANGE/*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeVirtualQuick, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_INVOKE_VIRTUAL_RANGE.cpp b/vm/mterp/c/OP_INVOKE_VIRTUAL_RANGE.cpp
new file mode 100644
index 0000000..4c66d56
--- /dev/null
+++ b/vm/mterp/c/OP_INVOKE_VIRTUAL_RANGE.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeVirtual, true, false);
+OP_END
diff --git a/vm/mterp/c/OP_IPUT.cpp b/vm/mterp/c/OP_IPUT.cpp
new file mode 100644
index 0000000..9d503ef
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT,                  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_BOOLEAN.cpp b/vm/mterp/c/OP_IPUT_BOOLEAN.cpp
new file mode 100644
index 0000000..7fe4929
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_BOOLEAN.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_BOOLEAN,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_BOOLEAN_JUMBO.cpp b/vm/mterp/c/OP_IPUT_BOOLEAN_JUMBO.cpp
new file mode 100644
index 0000000..405ee9d
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_BOOLEAN_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_BOOLEAN_JUMBO,  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_BYTE.cpp b/vm/mterp/c/OP_IPUT_BYTE.cpp
new file mode 100644
index 0000000..8a49fb7
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_BYTE,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_BYTE_JUMBO.cpp b/vm/mterp/c/OP_IPUT_BYTE_JUMBO.cpp
new file mode 100644
index 0000000..40a9969
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_BYTE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_BYTE_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_CHAR.cpp b/vm/mterp/c/OP_IPUT_CHAR.cpp
new file mode 100644
index 0000000..b2812c2
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_CHAR,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_CHAR_JUMBO.cpp b/vm/mterp/c/OP_IPUT_CHAR_JUMBO.cpp
new file mode 100644
index 0000000..170a353
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_CHAR_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_CHAR_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_JUMBO.cpp b/vm/mterp/c/OP_IPUT_JUMBO.cpp
new file mode 100644
index 0000000..2419bf2
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_JUMBO,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_OBJECT.cpp b/vm/mterp/c/OP_IPUT_OBJECT.cpp
new file mode 100644
index 0000000..dbfb5ab
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_OBJECT.cpp
@@ -0,0 +1,13 @@
+/*
+ * The VM spec says we should verify that the reference being stored into
+ * the field is assignment compatible.  In practice, many popular VMs don't
+ * do this because it slows down a very common operation.  It's not so bad
+ * for us, since "dexopt" quickens it whenever possible, but it's still an
+ * issue.
+ *
+ * To make this spec-complaint, we'd need to add a ClassObject pointer to
+ * the Field struct, resolve the field's type descriptor at link or class
+ * init time, and then verify the type here.
+ */
+HANDLE_IPUT_X(OP_IPUT_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_OBJECT_JUMBO.cpp b/vm/mterp/c/OP_IPUT_OBJECT_JUMBO.cpp
new file mode 100644
index 0000000..47a0576
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_OBJECT_JUMBO.cpp
@@ -0,0 +1,13 @@
+/*
+ * The VM spec says we should verify that the reference being stored into
+ * the field is assignment compatible.  In practice, many popular VMs don't
+ * do this because it slows down a very common operation.  It's not so bad
+ * for us, since "dexopt" quickens it whenever possible, but it's still an
+ * issue.
+ *
+ * To make this spec-complaint, we'd need to add a ClassObject pointer to
+ * the Field struct, resolve the field's type descriptor at link or class
+ * init time, and then verify the type here.
+ */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_OBJECT_QUICK.cpp b/vm/mterp/c/OP_IPUT_OBJECT_QUICK.cpp
new file mode 100644
index 0000000..8670188
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_OBJECT_QUICK.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_QUICK(OP_IPUT_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE.cpp b/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE.cpp
new file mode 100644
index 0000000..cce63c1
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..0af17e3
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_QUICK.cpp b/vm/mterp/c/OP_IPUT_QUICK.cpp
new file mode 100644
index 0000000..483b9b1
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_QUICK.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_QUICK(OP_IPUT_QUICK,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_SHORT.cpp b/vm/mterp/c/OP_IPUT_SHORT.cpp
new file mode 100644
index 0000000..0a63ebc
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_SHORT,            "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_SHORT_JUMBO.cpp b/vm/mterp/c/OP_IPUT_SHORT_JUMBO.cpp
new file mode 100644
index 0000000..41e0c44
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_SHORT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_SHORT_JUMBO,    "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_VOLATILE.cpp b/vm/mterp/c/OP_IPUT_VOLATILE.cpp
new file mode 100644
index 0000000..814379e
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_IPUT_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..82216c6
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_WIDE.cpp b/vm/mterp/c/OP_IPUT_WIDE.cpp
new file mode 100644
index 0000000..bb4926c
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_WIDE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_WIDE,             "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_WIDE_JUMBO.cpp b/vm/mterp/c/OP_IPUT_WIDE_JUMBO.cpp
new file mode 100644
index 0000000..72a4082
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_WIDE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_WIDE_QUICK.cpp b/vm/mterp/c/OP_IPUT_WIDE_QUICK.cpp
new file mode 100644
index 0000000..691630b
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_WIDE_QUICK.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_QUICK(OP_IPUT_WIDE_QUICK,     "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_WIDE_VOLATILE.cpp b/vm/mterp/c/OP_IPUT_WIDE_VOLATILE.cpp
new file mode 100644
index 0000000..d888b4a
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_WIDE_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..f4a2140
--- /dev/null
+++ b/vm/mterp/c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_LONG_TO_DOUBLE.cpp b/vm/mterp/c/OP_LONG_TO_DOUBLE.cpp
new file mode 100644
index 0000000..91b5eb2
--- /dev/null
+++ b/vm/mterp/c/OP_LONG_TO_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_LONG_TO_DOUBLE,       "long-to-double", _WIDE, _DOUBLE)
+OP_END
diff --git a/vm/mterp/c/OP_LONG_TO_FLOAT.cpp b/vm/mterp/c/OP_LONG_TO_FLOAT.cpp
new file mode 100644
index 0000000..ff1f5fb
--- /dev/null
+++ b/vm/mterp/c/OP_LONG_TO_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_LONG_TO_FLOAT,        "long-to-float", _WIDE, _FLOAT)
+OP_END
diff --git a/vm/mterp/c/OP_LONG_TO_INT.cpp b/vm/mterp/c/OP_LONG_TO_INT.cpp
new file mode 100644
index 0000000..87c9a2e
--- /dev/null
+++ b/vm/mterp/c/OP_LONG_TO_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_NUMCONV(OP_LONG_TO_INT,          "long-to-int", _WIDE, _INT)
+OP_END
diff --git a/vm/mterp/c/OP_MONITOR_ENTER.cpp b/vm/mterp/c/OP_MONITOR_ENTER.cpp
new file mode 100644
index 0000000..976aab3
--- /dev/null
+++ b/vm/mterp/c/OP_MONITOR_ENTER.cpp
@@ -0,0 +1,16 @@
+HANDLE_OPCODE(OP_MONITOR_ENTER /*vAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|monitor-enter v%d %s(0x%08x)",
+            vsrc1, kSpacing+6, GET_REGISTER(vsrc1));
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+        ILOGV("+ locking %p %s", obj, obj->clazz->descriptor);
+        EXPORT_PC();    /* need for precise GC */
+        dvmLockObject(self, obj);
+    }
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MONITOR_EXIT.cpp b/vm/mterp/c/OP_MONITOR_EXIT.cpp
new file mode 100644
index 0000000..c26585d
--- /dev/null
+++ b/vm/mterp/c/OP_MONITOR_EXIT.cpp
@@ -0,0 +1,30 @@
+HANDLE_OPCODE(OP_MONITOR_EXIT /*vAA*/)
+    {
+        Object* obj;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|monitor-exit v%d %s(0x%08x)",
+            vsrc1, kSpacing+5, GET_REGISTER(vsrc1));
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (!checkForNull(obj)) {
+            /*
+             * The exception needs to be processed at the *following*
+             * instruction, not the current instruction (see the Dalvik
+             * spec).  Because we're jumping to an exception handler,
+             * we're not actually at risk of skipping an instruction
+             * by doing so.
+             */
+            ADJUST_PC(1);           /* monitor-exit width is 1 */
+            GOTO_exceptionThrown();
+        }
+        ILOGV("+ unlocking %p %s", obj, obj->clazz->descriptor);
+        if (!dvmUnlockObject(self, obj)) {
+            assert(dvmCheckException(self));
+            ADJUST_PC(1);
+            GOTO_exceptionThrown();
+        }
+    }
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE.cpp b/vm/mterp/c/OP_MOVE.cpp
new file mode 100644
index 0000000..6666199
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE.cpp
@@ -0,0 +1,9 @@
+HANDLE_OPCODE($opcode /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_16.cpp b/vm/mterp/c/OP_MOVE_16.cpp
new file mode 100644
index 0000000..53af5d5
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_16.cpp
@@ -0,0 +1,9 @@
+HANDLE_OPCODE($opcode /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_EXCEPTION.cpp b/vm/mterp/c/OP_MOVE_EXCEPTION.cpp
new file mode 100644
index 0000000..86587ca
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_EXCEPTION.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_MOVE_EXCEPTION /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-exception v%d", vdst);
+    assert(self->exception != NULL);
+    SET_REGISTER(vdst, (u4)self->exception);
+    dvmClearException(self);
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_FROM16.cpp b/vm/mterp/c/OP_MOVE_FROM16.cpp
new file mode 100644
index 0000000..59fc285
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_FROM16.cpp
@@ -0,0 +1,9 @@
+HANDLE_OPCODE($opcode /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_OBJECT.cpp b/vm/mterp/c/OP_MOVE_OBJECT.cpp
new file mode 100644
index 0000000..579095f
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_OBJECT.cpp
@@ -0,0 +1 @@
+%include "c/OP_MOVE.cpp"
diff --git a/vm/mterp/c/OP_MOVE_OBJECT_16.cpp b/vm/mterp/c/OP_MOVE_OBJECT_16.cpp
new file mode 100644
index 0000000..89cfb77
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_OBJECT_16.cpp
@@ -0,0 +1 @@
+%include "c/OP_MOVE_16.cpp"
diff --git a/vm/mterp/c/OP_MOVE_OBJECT_FROM16.cpp b/vm/mterp/c/OP_MOVE_OBJECT_FROM16.cpp
new file mode 100644
index 0000000..9451b9e
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_OBJECT_FROM16.cpp
@@ -0,0 +1 @@
+%include "c/OP_MOVE_FROM16.cpp"
diff --git a/vm/mterp/c/OP_MOVE_RESULT.cpp b/vm/mterp/c/OP_MOVE_RESULT.cpp
new file mode 100644
index 0000000..ddf535b
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_RESULT.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE($opcode /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
+         (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
+         vdst, kSpacing+4, vdst,retval.i);
+    SET_REGISTER(vdst, retval.i);
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_RESULT_OBJECT.cpp b/vm/mterp/c/OP_MOVE_RESULT_OBJECT.cpp
new file mode 100644
index 0000000..08c5c02
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_RESULT_OBJECT.cpp
@@ -0,0 +1 @@
+%include "c/OP_MOVE_RESULT.cpp"
diff --git a/vm/mterp/c/OP_MOVE_RESULT_WIDE.cpp b/vm/mterp/c/OP_MOVE_RESULT_WIDE.cpp
new file mode 100644
index 0000000..f6ec8d9
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_RESULT_WIDE.cpp
@@ -0,0 +1,6 @@
+HANDLE_OPCODE(OP_MOVE_RESULT_WIDE /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result-wide v%d %s(0x%08llx)", vdst, kSpacing, retval.j);
+    SET_REGISTER_WIDE(vdst, retval.j);
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_WIDE.cpp b/vm/mterp/c/OP_MOVE_WIDE.cpp
new file mode 100644
index 0000000..9ee323d
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_WIDE.cpp
@@ -0,0 +1,10 @@
+HANDLE_OPCODE(OP_MOVE_WIDE /*vA, vB*/)
+    /* IMPORTANT: must correctly handle overlapping registers, e.g. both
+     * "move-wide v6, v7" and "move-wide v7, v6" */
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move-wide v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
+        kSpacing+5, vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_WIDE_16.cpp b/vm/mterp/c/OP_MOVE_WIDE_16.cpp
new file mode 100644
index 0000000..e3d0e16
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_WIDE_16.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_MOVE_WIDE_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move-wide/16 v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
+        kSpacing+8, vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(3);
+OP_END
diff --git a/vm/mterp/c/OP_MOVE_WIDE_FROM16.cpp b/vm/mterp/c/OP_MOVE_WIDE_FROM16.cpp
new file mode 100644
index 0000000..cdbaa2e
--- /dev/null
+++ b/vm/mterp/c/OP_MOVE_WIDE_FROM16.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_MOVE_WIDE_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move-wide/from16 v%d,v%d  (v%d=0x%08llx)", vdst, vsrc1,
+        vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_MUL_DOUBLE.cpp b/vm/mterp/c/OP_MUL_DOUBLE.cpp
new file mode 100644
index 0000000..3e65efa
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE(OP_MUL_DOUBLE, "mul", *)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_DOUBLE_2ADDR.cpp b/vm/mterp/c/OP_MUL_DOUBLE_2ADDR.cpp
new file mode 100644
index 0000000..905b6a7
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_DOUBLE_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE_2ADDR(OP_MUL_DOUBLE_2ADDR, "mul", *)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_FLOAT.cpp b/vm/mterp/c/OP_MUL_FLOAT.cpp
new file mode 100644
index 0000000..310495c
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT(OP_MUL_FLOAT, "mul", *)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_FLOAT_2ADDR.cpp b/vm/mterp/c/OP_MUL_FLOAT_2ADDR.cpp
new file mode 100644
index 0000000..03623ca
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_FLOAT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT_2ADDR(OP_MUL_FLOAT_2ADDR, "mul", *)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_INT.cpp b/vm/mterp/c/OP_MUL_INT.cpp
new file mode 100644
index 0000000..b723a29
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_MUL_INT, "mul", *, 0)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_INT_2ADDR.cpp b/vm/mterp/c/OP_MUL_INT_2ADDR.cpp
new file mode 100644
index 0000000..f7a179c
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_MUL_INT_2ADDR, "mul", *, 0)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_INT_LIT16.cpp b/vm/mterp/c/OP_MUL_INT_LIT16.cpp
new file mode 100644
index 0000000..3a34dbc
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_MUL_INT_LIT16, "mul", *, 0)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_INT_LIT8.cpp b/vm/mterp/c/OP_MUL_INT_LIT8.cpp
new file mode 100644
index 0000000..2ca0036
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_MUL_INT_LIT8,   "mul", *, 0)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_LONG.cpp b/vm/mterp/c/OP_MUL_LONG.cpp
new file mode 100644
index 0000000..768a2ad
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_MUL_LONG, "mul", *, 0)
+OP_END
diff --git a/vm/mterp/c/OP_MUL_LONG_2ADDR.cpp b/vm/mterp/c/OP_MUL_LONG_2ADDR.cpp
new file mode 100644
index 0000000..1469a22
--- /dev/null
+++ b/vm/mterp/c/OP_MUL_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_MUL_LONG_2ADDR, "mul", *, 0)
+OP_END
diff --git a/vm/mterp/c/OP_NEG_DOUBLE.cpp b/vm/mterp/c/OP_NEG_DOUBLE.cpp
new file mode 100644
index 0000000..805082c
--- /dev/null
+++ b/vm/mterp/c/OP_NEG_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_UNOP(OP_NEG_DOUBLE, "neg-double", -, , _DOUBLE)
+OP_END
diff --git a/vm/mterp/c/OP_NEG_FLOAT.cpp b/vm/mterp/c/OP_NEG_FLOAT.cpp
new file mode 100644
index 0000000..00e14f5
--- /dev/null
+++ b/vm/mterp/c/OP_NEG_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_UNOP(OP_NEG_FLOAT, "neg-float", -, , _FLOAT)
+OP_END
diff --git a/vm/mterp/c/OP_NEG_INT.cpp b/vm/mterp/c/OP_NEG_INT.cpp
new file mode 100644
index 0000000..9b97bef
--- /dev/null
+++ b/vm/mterp/c/OP_NEG_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_UNOP(OP_NEG_INT, "neg-int", -, , )
+OP_END
diff --git a/vm/mterp/c/OP_NEG_LONG.cpp b/vm/mterp/c/OP_NEG_LONG.cpp
new file mode 100644
index 0000000..52d553a
--- /dev/null
+++ b/vm/mterp/c/OP_NEG_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_NEW_ARRAY.cpp b/vm/mterp/c/OP_NEW_ARRAY.cpp
new file mode 100644
index 0000000..6d6771a
--- /dev/null
+++ b/vm/mterp/c/OP_NEW_ARRAY.cpp
@@ -0,0 +1,35 @@
+HANDLE_OPCODE(OP_NEW_ARRAY /*vA, vB, class@CCCC*/)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        s4 length;
+
+        EXPORT_PC();
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);       /* length reg */
+        ref = FETCH(1);
+        ILOGV("|new-array v%d,v%d,class@0x%04x  (%d elements)",
+            vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
+        length = (s4) GET_REGISTER(vsrc1);
+        if (length < 0) {
+            dvmThrowNegativeArraySizeException(length);
+            GOTO_exceptionThrown();
+        }
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newArray);
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_NEW_ARRAY_JUMBO.cpp b/vm/mterp/c/OP_NEW_ARRAY_JUMBO.cpp
new file mode 100644
index 0000000..7c0d551
--- /dev/null
+++ b/vm/mterp/c/OP_NEW_ARRAY_JUMBO.cpp
@@ -0,0 +1,35 @@
+HANDLE_OPCODE(OP_NEW_ARRAY_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        s4 length;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        vsrc1 = FETCH(4);       /* length reg */
+        ILOGV("|new-array/jumbo v%d,v%d,class@0x%08x  (%d elements)",
+            vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
+        length = (s4) GET_REGISTER(vsrc1);
+        if (length < 0) {
+            dvmThrowNegativeArraySizeException(length);
+            GOTO_exceptionThrown();
+        }
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newArray);
+    }
+    FINISH(5);
+OP_END
diff --git a/vm/mterp/c/OP_NEW_INSTANCE.cpp b/vm/mterp/c/OP_NEW_INSTANCE.cpp
new file mode 100644
index 0000000..b0b9c18
--- /dev/null
+++ b/vm/mterp/c/OP_NEW_INSTANCE.cpp
@@ -0,0 +1,48 @@
+HANDLE_OPCODE(OP_NEW_INSTANCE /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+        Object* newObj;
+
+        EXPORT_PC();
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|new-instance v%d,class@0x%04x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            clazz = dvmResolveClass(curMethod->clazz, ref, false);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
+            GOTO_exceptionThrown();
+
+#if defined(WITH_JIT)
+        /*
+         * The JIT needs dvmDexGetResolvedClass() to return non-null.
+         * Since we use the portable interpreter to build the trace, this extra
+         * check is not needed for mterp.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (!dvmDexGetResolvedClass(methodClassDex, ref))) {
+            /* Class initialization is still ongoing - end the trace */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+
+        /*
+         * Verifier now tests for interface/abstract class.
+         */
+        //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+        //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
+        //        clazz->descriptor);
+        //    GOTO_exceptionThrown();
+        //}
+        newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+        if (newObj == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newObj);
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_NEW_INSTANCE_JUMBO.cpp b/vm/mterp/c/OP_NEW_INSTANCE_JUMBO.cpp
new file mode 100644
index 0000000..aeffff4
--- /dev/null
+++ b/vm/mterp/c/OP_NEW_INSTANCE_JUMBO.cpp
@@ -0,0 +1,48 @@
+HANDLE_OPCODE(OP_NEW_INSTANCE_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* newObj;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        ILOGV("|new-instance/jumbo v%d,class@0x%08x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            clazz = dvmResolveClass(curMethod->clazz, ref, false);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
+            GOTO_exceptionThrown();
+
+#if defined(WITH_JIT)
+        /*
+         * The JIT needs dvmDexGetResolvedClass() to return non-null.
+         * Since we use the portable interpreter to build the trace, this extra
+         * check is not needed for mterp.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (!dvmDexGetResolvedClass(methodClassDex, ref))) {
+            /* Class initialization is still ongoing - end the trace */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+
+        /*
+         * Verifier now tests for interface/abstract class.
+         */
+        //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+        //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
+        //        clazz->descriptor);
+        //    GOTO_exceptionThrown();
+        //}
+        newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+        if (newObj == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newObj);
+    }
+    FINISH(4);
+OP_END
diff --git a/vm/mterp/c/OP_NOP.cpp b/vm/mterp/c/OP_NOP.cpp
new file mode 100644
index 0000000..d9fd744
--- /dev/null
+++ b/vm/mterp/c/OP_NOP.cpp
@@ -0,0 +1,3 @@
+HANDLE_OPCODE(OP_NOP)
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_NOT_INT.cpp b/vm/mterp/c/OP_NOT_INT.cpp
new file mode 100644
index 0000000..e585f62
--- /dev/null
+++ b/vm/mterp/c/OP_NOT_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_UNOP(OP_NOT_INT, "not-int", , ^ 0xffffffff, )
+OP_END
diff --git a/vm/mterp/c/OP_NOT_LONG.cpp b/vm/mterp/c/OP_NOT_LONG.cpp
new file mode 100644
index 0000000..4fb393a
--- /dev/null
+++ b/vm/mterp/c/OP_NOT_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_OR_INT.cpp b/vm/mterp/c/OP_OR_INT.cpp
new file mode 100644
index 0000000..19e397b
--- /dev/null
+++ b/vm/mterp/c/OP_OR_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_OR_INT,  "or",  |, 0)
+OP_END
diff --git a/vm/mterp/c/OP_OR_INT_2ADDR.cpp b/vm/mterp/c/OP_OR_INT_2ADDR.cpp
new file mode 100644
index 0000000..5d5fde0
--- /dev/null
+++ b/vm/mterp/c/OP_OR_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_OR_INT_2ADDR,  "or", |, 0)
+OP_END
diff --git a/vm/mterp/c/OP_OR_INT_LIT16.cpp b/vm/mterp/c/OP_OR_INT_LIT16.cpp
new file mode 100644
index 0000000..5a682fa
--- /dev/null
+++ b/vm/mterp/c/OP_OR_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_OR_INT_LIT16,  "or",  |, 0)
+OP_END
diff --git a/vm/mterp/c/OP_OR_INT_LIT8.cpp b/vm/mterp/c/OP_OR_INT_LIT8.cpp
new file mode 100644
index 0000000..40b9837
--- /dev/null
+++ b/vm/mterp/c/OP_OR_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_OR_INT_LIT8,    "or",  |, 0)
+OP_END
diff --git a/vm/mterp/c/OP_OR_LONG.cpp b/vm/mterp/c/OP_OR_LONG.cpp
new file mode 100644
index 0000000..62f4dd3
--- /dev/null
+++ b/vm/mterp/c/OP_OR_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_OR_LONG,  "or", |, 0)
+OP_END
diff --git a/vm/mterp/c/OP_OR_LONG_2ADDR.cpp b/vm/mterp/c/OP_OR_LONG_2ADDR.cpp
new file mode 100644
index 0000000..03a7c65
--- /dev/null
+++ b/vm/mterp/c/OP_OR_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_OR_LONG_2ADDR,  "or", |, 0)
+OP_END
diff --git a/vm/mterp/c/OP_PACKED_SWITCH.cpp b/vm/mterp/c/OP_PACKED_SWITCH.cpp
new file mode 100644
index 0000000..3922e46
--- /dev/null
+++ b/vm/mterp/c/OP_PACKED_SWITCH.cpp
@@ -0,0 +1,29 @@
+HANDLE_OPCODE(OP_PACKED_SWITCH /*vAA, +BBBB*/)
+    {
+        const u2* switchData;
+        u4 testVal;
+        s4 offset;
+
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
+        switchData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (switchData < curMethod->insns ||
+            switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            EXPORT_PC();
+            dvmThrowInternalError("bad packed switch");
+            GOTO_exceptionThrown();
+        }
+#endif
+        testVal = GET_REGISTER(vsrc1);
+
+        offset = dvmInterpHandlePackedSwitch(switchData, testVal);
+        ILOGV("> branch taken (0x%04x)", offset);
+        if (offset <= 0)  /* uncommon */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_REM_DOUBLE.cpp b/vm/mterp/c/OP_REM_DOUBLE.cpp
new file mode 100644
index 0000000..343e25e
--- /dev/null
+++ b/vm/mterp/c/OP_REM_DOUBLE.cpp
@@ -0,0 +1,13 @@
+HANDLE_OPCODE(OP_REM_DOUBLE /*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", "mod", vdst, vsrc1, vsrc2);
+        SET_REGISTER_DOUBLE(vdst,
+            fmod(GET_REGISTER_DOUBLE(vsrc1), GET_REGISTER_DOUBLE(vsrc2)));
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_REM_DOUBLE_2ADDR.cpp b/vm/mterp/c/OP_REM_DOUBLE_2ADDR.cpp
new file mode 100644
index 0000000..392eacf
--- /dev/null
+++ b/vm/mterp/c/OP_REM_DOUBLE_2ADDR.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_REM_DOUBLE_2ADDR /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|%s-double-2addr v%d,v%d", "mod", vdst, vsrc1);
+    SET_REGISTER_DOUBLE(vdst,
+        fmod(GET_REGISTER_DOUBLE(vdst), GET_REGISTER_DOUBLE(vsrc1)));
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_REM_FLOAT.cpp b/vm/mterp/c/OP_REM_FLOAT.cpp
new file mode 100644
index 0000000..9604b30
--- /dev/null
+++ b/vm/mterp/c/OP_REM_FLOAT.cpp
@@ -0,0 +1,13 @@
+HANDLE_OPCODE(OP_REM_FLOAT /*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", "mod", vdst, vsrc1, vsrc2);
+        SET_REGISTER_FLOAT(vdst,
+            fmodf(GET_REGISTER_FLOAT(vsrc1), GET_REGISTER_FLOAT(vsrc2)));
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_REM_FLOAT_2ADDR.cpp b/vm/mterp/c/OP_REM_FLOAT_2ADDR.cpp
new file mode 100644
index 0000000..87bb31e
--- /dev/null
+++ b/vm/mterp/c/OP_REM_FLOAT_2ADDR.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_REM_FLOAT_2ADDR /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|%s-float-2addr v%d,v%d", "mod", vdst, vsrc1);
+    SET_REGISTER_FLOAT(vdst,
+        fmodf(GET_REGISTER_FLOAT(vdst), GET_REGISTER_FLOAT(vsrc1)));
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_REM_INT.cpp b/vm/mterp/c/OP_REM_INT.cpp
new file mode 100644
index 0000000..0e3efe6
--- /dev/null
+++ b/vm/mterp/c/OP_REM_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_REM_INT, "rem", %, 2)
+OP_END
diff --git a/vm/mterp/c/OP_REM_INT_2ADDR.cpp b/vm/mterp/c/OP_REM_INT_2ADDR.cpp
new file mode 100644
index 0000000..5801f35
--- /dev/null
+++ b/vm/mterp/c/OP_REM_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_REM_INT_2ADDR, "rem", %, 2)
+OP_END
diff --git a/vm/mterp/c/OP_REM_INT_LIT16.cpp b/vm/mterp/c/OP_REM_INT_LIT16.cpp
new file mode 100644
index 0000000..a4dabe8
--- /dev/null
+++ b/vm/mterp/c/OP_REM_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_REM_INT_LIT16, "rem", %, 2)
+OP_END
diff --git a/vm/mterp/c/OP_REM_INT_LIT8.cpp b/vm/mterp/c/OP_REM_INT_LIT8.cpp
new file mode 100644
index 0000000..2bc88be
--- /dev/null
+++ b/vm/mterp/c/OP_REM_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_REM_INT_LIT8,   "rem", %, 2)
+OP_END
diff --git a/vm/mterp/c/OP_REM_LONG.cpp b/vm/mterp/c/OP_REM_LONG.cpp
new file mode 100644
index 0000000..fb2ba71
--- /dev/null
+++ b/vm/mterp/c/OP_REM_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_REM_LONG, "rem", %, 2)
+OP_END
diff --git a/vm/mterp/c/OP_REM_LONG_2ADDR.cpp b/vm/mterp/c/OP_REM_LONG_2ADDR.cpp
new file mode 100644
index 0000000..3049770
--- /dev/null
+++ b/vm/mterp/c/OP_REM_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_REM_LONG_2ADDR, "rem", %, 2)
+OP_END
diff --git a/vm/mterp/c/OP_RETURN.cpp b/vm/mterp/c/OP_RETURN.cpp
new file mode 100644
index 0000000..89d3b3b
--- /dev/null
+++ b/vm/mterp/c/OP_RETURN.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE($opcode /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return%s v%d",
+        (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
+    retval.i = GET_REGISTER(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
diff --git a/vm/mterp/c/OP_RETURN_OBJECT.cpp b/vm/mterp/c/OP_RETURN_OBJECT.cpp
new file mode 100644
index 0000000..d8bae43
--- /dev/null
+++ b/vm/mterp/c/OP_RETURN_OBJECT.cpp
@@ -0,0 +1 @@
+%include "c/OP_RETURN.cpp"
diff --git a/vm/mterp/c/OP_RETURN_VOID.cpp b/vm/mterp/c/OP_RETURN_VOID.cpp
new file mode 100644
index 0000000..7431f60
--- /dev/null
+++ b/vm/mterp/c/OP_RETURN_VOID.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_RETURN_VOID /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;    // placate valgrind
+#endif
+    GOTO_returnFromMethod();
+OP_END
diff --git a/vm/mterp/c/OP_RETURN_VOID_BARRIER.cpp b/vm/mterp/c/OP_RETURN_VOID_BARRIER.cpp
new file mode 100644
index 0000000..312402e
--- /dev/null
+++ b/vm/mterp/c/OP_RETURN_VOID_BARRIER.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;   /* placate valgrind */
+#endif
+    ANDROID_MEMBAR_STORE();
+    GOTO_returnFromMethod();
+OP_END
diff --git a/vm/mterp/c/OP_RETURN_WIDE.cpp b/vm/mterp/c/OP_RETURN_WIDE.cpp
new file mode 100644
index 0000000..a27bfd4
--- /dev/null
+++ b/vm/mterp/c/OP_RETURN_WIDE.cpp
@@ -0,0 +1,6 @@
+HANDLE_OPCODE(OP_RETURN_WIDE /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return-wide v%d", vsrc1);
+    retval.j = GET_REGISTER_WIDE(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
diff --git a/vm/mterp/c/OP_RSUB_INT.cpp b/vm/mterp/c/OP_RSUB_INT.cpp
new file mode 100644
index 0000000..336ca55
--- /dev/null
+++ b/vm/mterp/c/OP_RSUB_INT.cpp
@@ -0,0 +1,10 @@
+HANDLE_OPCODE(OP_RSUB_INT /*vA, vB, #+CCCC*/)
+    {
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);
+        vsrc2 = FETCH(1);
+        ILOGV("|rsub-int v%d,v%d,#+0x%04x", vdst, vsrc1, vsrc2);
+        SET_REGISTER(vdst, (s2) vsrc2 - (s4) GET_REGISTER(vsrc1));
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_RSUB_INT_LIT8.cpp b/vm/mterp/c/OP_RSUB_INT_LIT8.cpp
new file mode 100644
index 0000000..742854b
--- /dev/null
+++ b/vm/mterp/c/OP_RSUB_INT_LIT8.cpp
@@ -0,0 +1,12 @@
+HANDLE_OPCODE(OP_RSUB_INT_LIT8 /*vAA, vBB, #+CC*/)
+    {
+        u2 litInfo;
+        vdst = INST_AA(inst);
+        litInfo = FETCH(1);
+        vsrc1 = litInfo & 0xff;
+        vsrc2 = litInfo >> 8;
+        ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", "rsub", vdst, vsrc1, vsrc2);
+        SET_REGISTER(vdst, (s1) vsrc2 - (s4) GET_REGISTER(vsrc1));
+    }
+    FINISH(2);
+OP_END
diff --git a/vm/mterp/c/OP_SGET.cpp b/vm/mterp/c/OP_SGET.cpp
new file mode 100644
index 0000000..5297cd7
--- /dev/null
+++ b/vm/mterp/c/OP_SGET.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET,                  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_BOOLEAN.cpp b/vm/mterp/c/OP_SGET_BOOLEAN.cpp
new file mode 100644
index 0000000..7c5d45e
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_BOOLEAN.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_BOOLEAN,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_BOOLEAN_JUMBO.cpp b/vm/mterp/c/OP_SGET_BOOLEAN_JUMBO.cpp
new file mode 100644
index 0000000..b0a7525
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_BOOLEAN_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_BOOLEAN_JUMBO,  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_BYTE.cpp b/vm/mterp/c/OP_SGET_BYTE.cpp
new file mode 100644
index 0000000..b37cab4
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_BYTE,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_BYTE_JUMBO.cpp b/vm/mterp/c/OP_SGET_BYTE_JUMBO.cpp
new file mode 100644
index 0000000..421cac4
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_BYTE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_BYTE_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_CHAR.cpp b/vm/mterp/c/OP_SGET_CHAR.cpp
new file mode 100644
index 0000000..7ede5ec
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_CHAR,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_CHAR_JUMBO.cpp b/vm/mterp/c/OP_SGET_CHAR_JUMBO.cpp
new file mode 100644
index 0000000..71663f0
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_CHAR_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_CHAR_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_JUMBO.cpp b/vm/mterp/c/OP_SGET_JUMBO.cpp
new file mode 100644
index 0000000..460f06a
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_JUMBO,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_OBJECT.cpp b/vm/mterp/c/OP_SGET_OBJECT.cpp
new file mode 100644
index 0000000..9f3b63d
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_OBJECT.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_OBJECT_JUMBO.cpp b/vm/mterp/c/OP_SGET_OBJECT_JUMBO.cpp
new file mode 100644
index 0000000..0531c44
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_OBJECT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_OBJECT_VOLATILE.cpp b/vm/mterp/c/OP_SGET_OBJECT_VOLATILE.cpp
new file mode 100644
index 0000000..0a9049f
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_OBJECT_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..b96ef5d
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_SHORT.cpp b/vm/mterp/c/OP_SGET_SHORT.cpp
new file mode 100644
index 0000000..cd1fe4c
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_SHORT,            "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_SHORT_JUMBO.cpp b/vm/mterp/c/OP_SGET_SHORT_JUMBO.cpp
new file mode 100644
index 0000000..fdcc727
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_SHORT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_SHORT_JUMBO,    "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_VOLATILE.cpp b/vm/mterp/c/OP_SGET_VOLATILE.cpp
new file mode 100644
index 0000000..6713a54
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_SGET_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..5cf8975
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_SGET_WIDE.cpp b/vm/mterp/c/OP_SGET_WIDE.cpp
new file mode 100644
index 0000000..817c6e7
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_WIDE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_WIDE,             "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_WIDE_JUMBO.cpp b/vm/mterp/c/OP_SGET_WIDE_JUMBO.cpp
new file mode 100644
index 0000000..213b00f
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_WIDE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_WIDE_VOLATILE.cpp b/vm/mterp/c/OP_SGET_WIDE_VOLATILE.cpp
new file mode 100644
index 0000000..26a67bf
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_WIDE_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..4b75c75
--- /dev/null
+++ b/vm/mterp/c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SHL_INT.cpp b/vm/mterp/c/OP_SHL_INT.cpp
new file mode 100644
index 0000000..e32af49
--- /dev/null
+++ b/vm/mterp/c/OP_SHL_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT(OP_SHL_INT, "shl", (s4), <<)
+OP_END
diff --git a/vm/mterp/c/OP_SHL_INT_2ADDR.cpp b/vm/mterp/c/OP_SHL_INT_2ADDR.cpp
new file mode 100644
index 0000000..c5f5399
--- /dev/null
+++ b/vm/mterp/c/OP_SHL_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT_2ADDR(OP_SHL_INT_2ADDR, "shl", (s4), <<)
+OP_END
diff --git a/vm/mterp/c/OP_SHL_INT_LIT8.cpp b/vm/mterp/c/OP_SHL_INT_LIT8.cpp
new file mode 100644
index 0000000..009d14e
--- /dev/null
+++ b/vm/mterp/c/OP_SHL_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT_LIT8(OP_SHL_INT_LIT8,   "shl", (s4), <<)
+OP_END
diff --git a/vm/mterp/c/OP_SHL_LONG.cpp b/vm/mterp/c/OP_SHL_LONG.cpp
new file mode 100644
index 0000000..f6b502a
--- /dev/null
+++ b/vm/mterp/c/OP_SHL_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_LONG(OP_SHL_LONG, "shl", (s8), <<)
+OP_END
diff --git a/vm/mterp/c/OP_SHL_LONG_2ADDR.cpp b/vm/mterp/c/OP_SHL_LONG_2ADDR.cpp
new file mode 100644
index 0000000..b8a9954
--- /dev/null
+++ b/vm/mterp/c/OP_SHL_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_LONG_2ADDR(OP_SHL_LONG_2ADDR, "shl", (s8), <<)
+OP_END
diff --git a/vm/mterp/c/OP_SHR_INT.cpp b/vm/mterp/c/OP_SHR_INT.cpp
new file mode 100644
index 0000000..3834824
--- /dev/null
+++ b/vm/mterp/c/OP_SHR_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT(OP_SHR_INT, "shr", (s4), >>)
+OP_END
diff --git a/vm/mterp/c/OP_SHR_INT_2ADDR.cpp b/vm/mterp/c/OP_SHR_INT_2ADDR.cpp
new file mode 100644
index 0000000..c76c178
--- /dev/null
+++ b/vm/mterp/c/OP_SHR_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT_2ADDR(OP_SHR_INT_2ADDR, "shr", (s4), >>)
+OP_END
diff --git a/vm/mterp/c/OP_SHR_INT_LIT8.cpp b/vm/mterp/c/OP_SHR_INT_LIT8.cpp
new file mode 100644
index 0000000..e2657d7
--- /dev/null
+++ b/vm/mterp/c/OP_SHR_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT_LIT8(OP_SHR_INT_LIT8,   "shr", (s4), >>)
+OP_END
diff --git a/vm/mterp/c/OP_SHR_LONG.cpp b/vm/mterp/c/OP_SHR_LONG.cpp
new file mode 100644
index 0000000..357a666
--- /dev/null
+++ b/vm/mterp/c/OP_SHR_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_LONG(OP_SHR_LONG, "shr", (s8), >>)
+OP_END
diff --git a/vm/mterp/c/OP_SHR_LONG_2ADDR.cpp b/vm/mterp/c/OP_SHR_LONG_2ADDR.cpp
new file mode 100644
index 0000000..43e27ea
--- /dev/null
+++ b/vm/mterp/c/OP_SHR_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_LONG_2ADDR(OP_SHR_LONG_2ADDR, "shr", (s8), >>)
+OP_END
diff --git a/vm/mterp/c/OP_SPARSE_SWITCH.cpp b/vm/mterp/c/OP_SPARSE_SWITCH.cpp
new file mode 100644
index 0000000..f48d06e
--- /dev/null
+++ b/vm/mterp/c/OP_SPARSE_SWITCH.cpp
@@ -0,0 +1,29 @@
+HANDLE_OPCODE(OP_SPARSE_SWITCH /*vAA, +BBBB*/)
+    {
+        const u2* switchData;
+        u4 testVal;
+        s4 offset;
+
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
+        switchData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (switchData < curMethod->insns ||
+            switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            EXPORT_PC();
+            dvmThrowInternalError("bad sparse switch");
+            GOTO_exceptionThrown();
+        }
+#endif
+        testVal = GET_REGISTER(vsrc1);
+
+        offset = dvmInterpHandleSparseSwitch(switchData, testVal);
+        ILOGV("> branch taken (0x%04x)", offset);
+        if (offset <= 0)  /* uncommon */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
diff --git a/vm/mterp/c/OP_SPUT.cpp b/vm/mterp/c/OP_SPUT.cpp
new file mode 100644
index 0000000..286e64c
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT,                  "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_BOOLEAN.cpp b/vm/mterp/c/OP_SPUT_BOOLEAN.cpp
new file mode 100644
index 0000000..55ceb11
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_BOOLEAN.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_BOOLEAN,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_BOOLEAN_JUMBO.cpp b/vm/mterp/c/OP_SPUT_BOOLEAN_JUMBO.cpp
new file mode 100644
index 0000000..57b368e
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_BOOLEAN_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_BOOLEAN_JUMBO,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_BYTE.cpp b/vm/mterp/c/OP_SPUT_BYTE.cpp
new file mode 100644
index 0000000..d242fe1
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_BYTE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_BYTE,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_BYTE_JUMBO.cpp b/vm/mterp/c/OP_SPUT_BYTE_JUMBO.cpp
new file mode 100644
index 0000000..10dc04d
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_BYTE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_BYTE_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_CHAR.cpp b/vm/mterp/c/OP_SPUT_CHAR.cpp
new file mode 100644
index 0000000..18a2f06
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_CHAR.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_CHAR,             "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_CHAR_JUMBO.cpp b/vm/mterp/c/OP_SPUT_CHAR_JUMBO.cpp
new file mode 100644
index 0000000..1e64533
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_CHAR_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_CHAR_JUMBO,     "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_JUMBO.cpp b/vm/mterp/c/OP_SPUT_JUMBO.cpp
new file mode 100644
index 0000000..f2d90a5
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_JUMBO,          "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_OBJECT.cpp b/vm/mterp/c/OP_SPUT_OBJECT.cpp
new file mode 100644
index 0000000..fb223d6
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_OBJECT.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_OBJECT_JUMBO.cpp b/vm/mterp/c/OP_SPUT_OBJECT_JUMBO.cpp
new file mode 100644
index 0000000..e79e25a
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_OBJECT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE.cpp b/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE.cpp
new file mode 100644
index 0000000..38d6c0d
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..4f60a5d
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_SHORT.cpp b/vm/mterp/c/OP_SPUT_SHORT.cpp
new file mode 100644
index 0000000..c6cd8d6
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_SHORT.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_SHORT,            "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_SHORT_JUMBO.cpp b/vm/mterp/c/OP_SPUT_SHORT_JUMBO.cpp
new file mode 100644
index 0000000..8c82392
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_SHORT_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_SHORT_JUMBO,    "", Int, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_VOLATILE.cpp b/vm/mterp/c/OP_SPUT_VOLATILE.cpp
new file mode 100644
index 0000000..7899d05
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_SPUT_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..845cc83
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_VOLATILE_JUMBO, "-volatile", IntVolatile, )
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_WIDE.cpp b/vm/mterp/c/OP_SPUT_WIDE.cpp
new file mode 100644
index 0000000..0c74651
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_WIDE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_WIDE,             "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_WIDE_JUMBO.cpp b/vm/mterp/c/OP_SPUT_WIDE_JUMBO.cpp
new file mode 100644
index 0000000..965eeb6
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_WIDE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_WIDE_VOLATILE.cpp b/vm/mterp/c/OP_SPUT_WIDE_VOLATILE.cpp
new file mode 100644
index 0000000..bdf552c
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_WIDE_VOLATILE.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp b/vm/mterp/c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp
new file mode 100644
index 0000000..3a86294
--- /dev/null
+++ b/vm/mterp/c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp
@@ -0,0 +1,2 @@
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_DOUBLE.cpp b/vm/mterp/c/OP_SUB_DOUBLE.cpp
new file mode 100644
index 0000000..64a112d
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_DOUBLE.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE(OP_SUB_DOUBLE, "sub", -)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_DOUBLE_2ADDR.cpp b/vm/mterp/c/OP_SUB_DOUBLE_2ADDR.cpp
new file mode 100644
index 0000000..5870400
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_DOUBLE_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_DOUBLE_2ADDR(OP_SUB_DOUBLE_2ADDR, "sub", -)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_FLOAT.cpp b/vm/mterp/c/OP_SUB_FLOAT.cpp
new file mode 100644
index 0000000..96c5fbd
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_FLOAT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT(OP_SUB_FLOAT, "sub", -)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_FLOAT_2ADDR.cpp b/vm/mterp/c/OP_SUB_FLOAT_2ADDR.cpp
new file mode 100644
index 0000000..802935c
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_FLOAT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_FLOAT_2ADDR(OP_SUB_FLOAT_2ADDR, "sub", -)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_INT.cpp b/vm/mterp/c/OP_SUB_INT.cpp
new file mode 100644
index 0000000..2c1006d
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_SUB_INT, "sub", -, 0)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_INT_2ADDR.cpp b/vm/mterp/c/OP_SUB_INT_2ADDR.cpp
new file mode 100644
index 0000000..328ed33
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_SUB_INT_2ADDR, "sub", -, 0)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_LONG.cpp b/vm/mterp/c/OP_SUB_LONG.cpp
new file mode 100644
index 0000000..bace11a
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_SUB_LONG, "sub", -, 0)
+OP_END
diff --git a/vm/mterp/c/OP_SUB_LONG_2ADDR.cpp b/vm/mterp/c/OP_SUB_LONG_2ADDR.cpp
new file mode 100644
index 0000000..f234dd4
--- /dev/null
+++ b/vm/mterp/c/OP_SUB_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_SUB_LONG_2ADDR, "sub", -, 0)
+OP_END
diff --git a/vm/mterp/c/OP_THROW.cpp b/vm/mterp/c/OP_THROW.cpp
new file mode 100644
index 0000000..6fde0cc
--- /dev/null
+++ b/vm/mterp/c/OP_THROW.cpp
@@ -0,0 +1,24 @@
+HANDLE_OPCODE(OP_THROW /*vAA*/)
+    {
+        Object* obj;
+
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
+        obj = (Object*) GET_REGISTER(vsrc1);
+        if (!checkForNull(obj)) {
+            /* will throw a null pointer exception */
+            LOGVV("Bad exception");
+        } else {
+            /* use the requested exception */
+            dvmSetException(self, obj);
+        }
+        GOTO_exceptionThrown();
+    }
+OP_END
diff --git a/vm/mterp/c/OP_THROW_VERIFICATION_ERROR.cpp b/vm/mterp/c/OP_THROW_VERIFICATION_ERROR.cpp
new file mode 100644
index 0000000..85cc8fb
--- /dev/null
+++ b/vm/mterp/c/OP_THROW_VERIFICATION_ERROR.cpp
@@ -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_THROW_VERIFICATION_ERROR_JUMBO.cpp b/vm/mterp/c/OP_THROW_VERIFICATION_ERROR_JUMBO.cpp
new file mode 100644
index 0000000..c4607ec
--- /dev/null
+++ b/vm/mterp/c/OP_THROW_VERIFICATION_ERROR_JUMBO.cpp
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR_JUMBO)
+    EXPORT_PC();
+    vsrc1 = FETCH(3);
+    ref = FETCH(1) | (u4)FETCH(2) << 16;      /* class/field/method ref */
+    dvmThrowVerificationError(curMethod, vsrc1, ref);
+    GOTO_exceptionThrown();
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_27FF.cpp b/vm/mterp/c/OP_UNUSED_27FF.cpp
new file mode 100644
index 0000000..804138c
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_27FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_27FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_28FF.cpp b/vm/mterp/c/OP_UNUSED_28FF.cpp
new file mode 100644
index 0000000..f6e01f6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_28FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_28FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_29FF.cpp b/vm/mterp/c/OP_UNUSED_29FF.cpp
new file mode 100644
index 0000000..0a14c5f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_29FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_29FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_2AFF.cpp b/vm/mterp/c/OP_UNUSED_2AFF.cpp
new file mode 100644
index 0000000..701561a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_2AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_2AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_2BFF.cpp b/vm/mterp/c/OP_UNUSED_2BFF.cpp
new file mode 100644
index 0000000..a73366b
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_2BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_2BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_2CFF.cpp b/vm/mterp/c/OP_UNUSED_2CFF.cpp
new file mode 100644
index 0000000..a220b03
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_2CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_2CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_2DFF.cpp b/vm/mterp/c/OP_UNUSED_2DFF.cpp
new file mode 100644
index 0000000..2d4ba4e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_2DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_2DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_2EFF.cpp b/vm/mterp/c/OP_UNUSED_2EFF.cpp
new file mode 100644
index 0000000..49d7fa9
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_2EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_2EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_2FFF.cpp b/vm/mterp/c/OP_UNUSED_2FFF.cpp
new file mode 100644
index 0000000..9326d05
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_2FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_2FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_30FF.cpp b/vm/mterp/c/OP_UNUSED_30FF.cpp
new file mode 100644
index 0000000..f36814e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_30FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_30FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_31FF.cpp b/vm/mterp/c/OP_UNUSED_31FF.cpp
new file mode 100644
index 0000000..20ab58b
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_31FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_31FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_32FF.cpp b/vm/mterp/c/OP_UNUSED_32FF.cpp
new file mode 100644
index 0000000..459b165
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_32FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_32FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_33FF.cpp b/vm/mterp/c/OP_UNUSED_33FF.cpp
new file mode 100644
index 0000000..83fb82c
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_33FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_33FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_34FF.cpp b/vm/mterp/c/OP_UNUSED_34FF.cpp
new file mode 100644
index 0000000..d9e7bb0
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_34FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_34FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_35FF.cpp b/vm/mterp/c/OP_UNUSED_35FF.cpp
new file mode 100644
index 0000000..2ed7b34
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_35FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_35FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_36FF.cpp b/vm/mterp/c/OP_UNUSED_36FF.cpp
new file mode 100644
index 0000000..2770594
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_36FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_36FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_37FF.cpp b/vm/mterp/c/OP_UNUSED_37FF.cpp
new file mode 100644
index 0000000..206b6a6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_37FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_37FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_38FF.cpp b/vm/mterp/c/OP_UNUSED_38FF.cpp
new file mode 100644
index 0000000..68c94a0
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_38FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_38FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_39FF.cpp b/vm/mterp/c/OP_UNUSED_39FF.cpp
new file mode 100644
index 0000000..c003a87
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_39FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_39FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3AFF.cpp b/vm/mterp/c/OP_UNUSED_3AFF.cpp
new file mode 100644
index 0000000..b43e356
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3BFF.cpp b/vm/mterp/c/OP_UNUSED_3BFF.cpp
new file mode 100644
index 0000000..2188336
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3CFF.cpp b/vm/mterp/c/OP_UNUSED_3CFF.cpp
new file mode 100644
index 0000000..f446d40
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3DFF.cpp b/vm/mterp/c/OP_UNUSED_3DFF.cpp
new file mode 100644
index 0000000..f57cd64
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3E.cpp b/vm/mterp/c/OP_UNUSED_3E.cpp
new file mode 100644
index 0000000..9ecf8e3
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3E.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3E)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3EFF.cpp b/vm/mterp/c/OP_UNUSED_3EFF.cpp
new file mode 100644
index 0000000..b81647f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3F.cpp b/vm/mterp/c/OP_UNUSED_3F.cpp
new file mode 100644
index 0000000..9d1d68d
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3F.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3F)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_3FFF.cpp b/vm/mterp/c/OP_UNUSED_3FFF.cpp
new file mode 100644
index 0000000..adfd65e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_3FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_3FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_40.cpp b/vm/mterp/c/OP_UNUSED_40.cpp
new file mode 100644
index 0000000..f73a59c
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_40.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_40)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_40FF.cpp b/vm/mterp/c/OP_UNUSED_40FF.cpp
new file mode 100644
index 0000000..aa87b39
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_40FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_40FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_41.cpp b/vm/mterp/c/OP_UNUSED_41.cpp
new file mode 100644
index 0000000..38747e6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_41.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_41)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_41FF.cpp b/vm/mterp/c/OP_UNUSED_41FF.cpp
new file mode 100644
index 0000000..a2a3894
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_41FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_41FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_42.cpp b/vm/mterp/c/OP_UNUSED_42.cpp
new file mode 100644
index 0000000..154d293
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_42.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_42)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_42FF.cpp b/vm/mterp/c/OP_UNUSED_42FF.cpp
new file mode 100644
index 0000000..edd4393
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_42FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_42FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_43.cpp b/vm/mterp/c/OP_UNUSED_43.cpp
new file mode 100644
index 0000000..c7e702c
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_43.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_43)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_43FF.cpp b/vm/mterp/c/OP_UNUSED_43FF.cpp
new file mode 100644
index 0000000..6e616eb
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_43FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_43FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_44FF.cpp b/vm/mterp/c/OP_UNUSED_44FF.cpp
new file mode 100644
index 0000000..0eee91f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_44FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_44FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_45FF.cpp b/vm/mterp/c/OP_UNUSED_45FF.cpp
new file mode 100644
index 0000000..4a6b48e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_45FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_45FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_46FF.cpp b/vm/mterp/c/OP_UNUSED_46FF.cpp
new file mode 100644
index 0000000..e1c940e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_46FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_46FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_47FF.cpp b/vm/mterp/c/OP_UNUSED_47FF.cpp
new file mode 100644
index 0000000..94df8bd
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_47FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_47FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_48FF.cpp b/vm/mterp/c/OP_UNUSED_48FF.cpp
new file mode 100644
index 0000000..1e2acdb
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_48FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_48FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_49FF.cpp b/vm/mterp/c/OP_UNUSED_49FF.cpp
new file mode 100644
index 0000000..b86d451
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_49FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_49FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_4AFF.cpp b/vm/mterp/c/OP_UNUSED_4AFF.cpp
new file mode 100644
index 0000000..9827b34
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_4AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_4AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_4BFF.cpp b/vm/mterp/c/OP_UNUSED_4BFF.cpp
new file mode 100644
index 0000000..9e26529
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_4BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_4BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_4CFF.cpp b/vm/mterp/c/OP_UNUSED_4CFF.cpp
new file mode 100644
index 0000000..f21fa48
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_4CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_4CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_4DFF.cpp b/vm/mterp/c/OP_UNUSED_4DFF.cpp
new file mode 100644
index 0000000..d596149
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_4DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_4DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_4EFF.cpp b/vm/mterp/c/OP_UNUSED_4EFF.cpp
new file mode 100644
index 0000000..7636c23
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_4EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_4EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_4FFF.cpp b/vm/mterp/c/OP_UNUSED_4FFF.cpp
new file mode 100644
index 0000000..5d20689
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_4FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_4FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_50FF.cpp b/vm/mterp/c/OP_UNUSED_50FF.cpp
new file mode 100644
index 0000000..4c577be
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_50FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_50FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_51FF.cpp b/vm/mterp/c/OP_UNUSED_51FF.cpp
new file mode 100644
index 0000000..e4a50d8
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_51FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_51FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_52FF.cpp b/vm/mterp/c/OP_UNUSED_52FF.cpp
new file mode 100644
index 0000000..0338e92
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_52FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_52FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_53FF.cpp b/vm/mterp/c/OP_UNUSED_53FF.cpp
new file mode 100644
index 0000000..a19aec9
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_53FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_53FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_54FF.cpp b/vm/mterp/c/OP_UNUSED_54FF.cpp
new file mode 100644
index 0000000..5f1f708
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_54FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_54FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_55FF.cpp b/vm/mterp/c/OP_UNUSED_55FF.cpp
new file mode 100644
index 0000000..3cc25e6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_55FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_55FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_56FF.cpp b/vm/mterp/c/OP_UNUSED_56FF.cpp
new file mode 100644
index 0000000..b41be0f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_56FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_56FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_57FF.cpp b/vm/mterp/c/OP_UNUSED_57FF.cpp
new file mode 100644
index 0000000..c0e8dd5
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_57FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_57FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_58FF.cpp b/vm/mterp/c/OP_UNUSED_58FF.cpp
new file mode 100644
index 0000000..9c0b8b0
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_58FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_58FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_59FF.cpp b/vm/mterp/c/OP_UNUSED_59FF.cpp
new file mode 100644
index 0000000..7c28662
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_59FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_59FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_5AFF.cpp b/vm/mterp/c/OP_UNUSED_5AFF.cpp
new file mode 100644
index 0000000..50c77bc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_5AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_5AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_5BFF.cpp b/vm/mterp/c/OP_UNUSED_5BFF.cpp
new file mode 100644
index 0000000..a145bf4
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_5BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_5BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_5CFF.cpp b/vm/mterp/c/OP_UNUSED_5CFF.cpp
new file mode 100644
index 0000000..821bdcd
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_5CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_5CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_5DFF.cpp b/vm/mterp/c/OP_UNUSED_5DFF.cpp
new file mode 100644
index 0000000..982b1c2
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_5DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_5DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_5EFF.cpp b/vm/mterp/c/OP_UNUSED_5EFF.cpp
new file mode 100644
index 0000000..d0157f7
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_5EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_5EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_5FFF.cpp b/vm/mterp/c/OP_UNUSED_5FFF.cpp
new file mode 100644
index 0000000..3e18904
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_5FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_5FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_60FF.cpp b/vm/mterp/c/OP_UNUSED_60FF.cpp
new file mode 100644
index 0000000..96b15c6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_60FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_60FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_61FF.cpp b/vm/mterp/c/OP_UNUSED_61FF.cpp
new file mode 100644
index 0000000..91a8a30
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_61FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_61FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_62FF.cpp b/vm/mterp/c/OP_UNUSED_62FF.cpp
new file mode 100644
index 0000000..b3bb114
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_62FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_62FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_63FF.cpp b/vm/mterp/c/OP_UNUSED_63FF.cpp
new file mode 100644
index 0000000..ea14458
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_63FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_63FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_64FF.cpp b/vm/mterp/c/OP_UNUSED_64FF.cpp
new file mode 100644
index 0000000..713277e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_64FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_64FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_65FF.cpp b/vm/mterp/c/OP_UNUSED_65FF.cpp
new file mode 100644
index 0000000..6f73854
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_65FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_65FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_66FF.cpp b/vm/mterp/c/OP_UNUSED_66FF.cpp
new file mode 100644
index 0000000..a7ac805
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_66FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_66FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_67FF.cpp b/vm/mterp/c/OP_UNUSED_67FF.cpp
new file mode 100644
index 0000000..16d1155
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_67FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_67FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_68FF.cpp b/vm/mterp/c/OP_UNUSED_68FF.cpp
new file mode 100644
index 0000000..9b4eed7
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_68FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_68FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_69FF.cpp b/vm/mterp/c/OP_UNUSED_69FF.cpp
new file mode 100644
index 0000000..1bfdae9
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_69FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_69FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_6AFF.cpp b/vm/mterp/c/OP_UNUSED_6AFF.cpp
new file mode 100644
index 0000000..1f6dab0
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_6AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_6AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_6BFF.cpp b/vm/mterp/c/OP_UNUSED_6BFF.cpp
new file mode 100644
index 0000000..3739cfd
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_6BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_6BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_6CFF.cpp b/vm/mterp/c/OP_UNUSED_6CFF.cpp
new file mode 100644
index 0000000..28df1ff
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_6CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_6CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_6DFF.cpp b/vm/mterp/c/OP_UNUSED_6DFF.cpp
new file mode 100644
index 0000000..436064a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_6DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_6DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_6EFF.cpp b/vm/mterp/c/OP_UNUSED_6EFF.cpp
new file mode 100644
index 0000000..c5c3720
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_6EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_6EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_6FFF.cpp b/vm/mterp/c/OP_UNUSED_6FFF.cpp
new file mode 100644
index 0000000..5bab85a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_6FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_6FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_70FF.cpp b/vm/mterp/c/OP_UNUSED_70FF.cpp
new file mode 100644
index 0000000..15cb3cc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_70FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_70FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_71FF.cpp b/vm/mterp/c/OP_UNUSED_71FF.cpp
new file mode 100644
index 0000000..3669855
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_71FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_71FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_72FF.cpp b/vm/mterp/c/OP_UNUSED_72FF.cpp
new file mode 100644
index 0000000..66b42ba
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_72FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_72FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_73.cpp b/vm/mterp/c/OP_UNUSED_73.cpp
new file mode 100644
index 0000000..85aa95f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_73.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_73)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_73FF.cpp b/vm/mterp/c/OP_UNUSED_73FF.cpp
new file mode 100644
index 0000000..1832581
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_73FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_73FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_74FF.cpp b/vm/mterp/c/OP_UNUSED_74FF.cpp
new file mode 100644
index 0000000..7f73d09
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_74FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_74FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_75FF.cpp b/vm/mterp/c/OP_UNUSED_75FF.cpp
new file mode 100644
index 0000000..d96b4aa
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_75FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_75FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_76FF.cpp b/vm/mterp/c/OP_UNUSED_76FF.cpp
new file mode 100644
index 0000000..b38cdf1
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_76FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_76FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_77FF.cpp b/vm/mterp/c/OP_UNUSED_77FF.cpp
new file mode 100644
index 0000000..dc128bb
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_77FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_77FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_78FF.cpp b/vm/mterp/c/OP_UNUSED_78FF.cpp
new file mode 100644
index 0000000..5ae4223
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_78FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_78FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_79.cpp b/vm/mterp/c/OP_UNUSED_79.cpp
new file mode 100644
index 0000000..1fa86e9
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_79.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_79)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_79FF.cpp b/vm/mterp/c/OP_UNUSED_79FF.cpp
new file mode 100644
index 0000000..4d8f99d
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_79FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_79FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7A.cpp b/vm/mterp/c/OP_UNUSED_7A.cpp
new file mode 100644
index 0000000..beab006
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7A.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7A)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7AFF.cpp b/vm/mterp/c/OP_UNUSED_7AFF.cpp
new file mode 100644
index 0000000..93ea5a2
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7BFF.cpp b/vm/mterp/c/OP_UNUSED_7BFF.cpp
new file mode 100644
index 0000000..6e4d99b
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7CFF.cpp b/vm/mterp/c/OP_UNUSED_7CFF.cpp
new file mode 100644
index 0000000..f9bdd15
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7DFF.cpp b/vm/mterp/c/OP_UNUSED_7DFF.cpp
new file mode 100644
index 0000000..198d71f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7EFF.cpp b/vm/mterp/c/OP_UNUSED_7EFF.cpp
new file mode 100644
index 0000000..49dce13
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_7FFF.cpp b/vm/mterp/c/OP_UNUSED_7FFF.cpp
new file mode 100644
index 0000000..4e8588f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_7FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_7FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_80FF.cpp b/vm/mterp/c/OP_UNUSED_80FF.cpp
new file mode 100644
index 0000000..290d5d7
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_80FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_80FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_81FF.cpp b/vm/mterp/c/OP_UNUSED_81FF.cpp
new file mode 100644
index 0000000..21d8385
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_81FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_81FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_82FF.cpp b/vm/mterp/c/OP_UNUSED_82FF.cpp
new file mode 100644
index 0000000..6ae50cf
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_82FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_82FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_83FF.cpp b/vm/mterp/c/OP_UNUSED_83FF.cpp
new file mode 100644
index 0000000..807a1d3
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_83FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_83FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_84FF.cpp b/vm/mterp/c/OP_UNUSED_84FF.cpp
new file mode 100644
index 0000000..4764220
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_84FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_84FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_85FF.cpp b/vm/mterp/c/OP_UNUSED_85FF.cpp
new file mode 100644
index 0000000..2722a49
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_85FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_85FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_86FF.cpp b/vm/mterp/c/OP_UNUSED_86FF.cpp
new file mode 100644
index 0000000..7dadccc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_86FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_86FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_87FF.cpp b/vm/mterp/c/OP_UNUSED_87FF.cpp
new file mode 100644
index 0000000..7de2178
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_87FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_87FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_88FF.cpp b/vm/mterp/c/OP_UNUSED_88FF.cpp
new file mode 100644
index 0000000..e6cf015
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_88FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_88FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_89FF.cpp b/vm/mterp/c/OP_UNUSED_89FF.cpp
new file mode 100644
index 0000000..5f23acf
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_89FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_89FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_8AFF.cpp b/vm/mterp/c/OP_UNUSED_8AFF.cpp
new file mode 100644
index 0000000..9582011
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_8AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_8AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_8BFF.cpp b/vm/mterp/c/OP_UNUSED_8BFF.cpp
new file mode 100644
index 0000000..2c37dc3
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_8BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_8BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_8CFF.cpp b/vm/mterp/c/OP_UNUSED_8CFF.cpp
new file mode 100644
index 0000000..bd67024
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_8CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_8CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_8DFF.cpp b/vm/mterp/c/OP_UNUSED_8DFF.cpp
new file mode 100644
index 0000000..c379d2e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_8DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_8DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_8EFF.cpp b/vm/mterp/c/OP_UNUSED_8EFF.cpp
new file mode 100644
index 0000000..e78839b
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_8EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_8EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_8FFF.cpp b/vm/mterp/c/OP_UNUSED_8FFF.cpp
new file mode 100644
index 0000000..c911a0e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_8FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_8FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_90FF.cpp b/vm/mterp/c/OP_UNUSED_90FF.cpp
new file mode 100644
index 0000000..e8a35fc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_90FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_90FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_91FF.cpp b/vm/mterp/c/OP_UNUSED_91FF.cpp
new file mode 100644
index 0000000..e7fc01a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_91FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_91FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_92FF.cpp b/vm/mterp/c/OP_UNUSED_92FF.cpp
new file mode 100644
index 0000000..612bd57
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_92FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_92FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_93FF.cpp b/vm/mterp/c/OP_UNUSED_93FF.cpp
new file mode 100644
index 0000000..9b69187
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_93FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_93FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_94FF.cpp b/vm/mterp/c/OP_UNUSED_94FF.cpp
new file mode 100644
index 0000000..022c1eb
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_94FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_94FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_95FF.cpp b/vm/mterp/c/OP_UNUSED_95FF.cpp
new file mode 100644
index 0000000..51d7467
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_95FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_95FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_96FF.cpp b/vm/mterp/c/OP_UNUSED_96FF.cpp
new file mode 100644
index 0000000..4067af1
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_96FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_96FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_97FF.cpp b/vm/mterp/c/OP_UNUSED_97FF.cpp
new file mode 100644
index 0000000..b4b4a77
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_97FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_97FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_98FF.cpp b/vm/mterp/c/OP_UNUSED_98FF.cpp
new file mode 100644
index 0000000..364aa4c
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_98FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_98FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_99FF.cpp b/vm/mterp/c/OP_UNUSED_99FF.cpp
new file mode 100644
index 0000000..e4c2fd5
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_99FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_99FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_9AFF.cpp b/vm/mterp/c/OP_UNUSED_9AFF.cpp
new file mode 100644
index 0000000..bce58e5
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_9AFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_9AFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_9BFF.cpp b/vm/mterp/c/OP_UNUSED_9BFF.cpp
new file mode 100644
index 0000000..b875b6e
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_9BFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_9BFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_9CFF.cpp b/vm/mterp/c/OP_UNUSED_9CFF.cpp
new file mode 100644
index 0000000..9933e47
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_9CFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_9CFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_9DFF.cpp b/vm/mterp/c/OP_UNUSED_9DFF.cpp
new file mode 100644
index 0000000..425a685
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_9DFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_9DFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_9EFF.cpp b/vm/mterp/c/OP_UNUSED_9EFF.cpp
new file mode 100644
index 0000000..ae4b842
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_9EFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_9EFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_9FFF.cpp b/vm/mterp/c/OP_UNUSED_9FFF.cpp
new file mode 100644
index 0000000..fbb0564
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_9FFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_9FFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A0FF.cpp b/vm/mterp/c/OP_UNUSED_A0FF.cpp
new file mode 100644
index 0000000..546357a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A0FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A0FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A1FF.cpp b/vm/mterp/c/OP_UNUSED_A1FF.cpp
new file mode 100644
index 0000000..033c5ba
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A1FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A1FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A2FF.cpp b/vm/mterp/c/OP_UNUSED_A2FF.cpp
new file mode 100644
index 0000000..10ba36a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A2FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A2FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A3FF.cpp b/vm/mterp/c/OP_UNUSED_A3FF.cpp
new file mode 100644
index 0000000..e1eb866
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A3FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A3FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A4FF.cpp b/vm/mterp/c/OP_UNUSED_A4FF.cpp
new file mode 100644
index 0000000..515cde3
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A4FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A4FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A5FF.cpp b/vm/mterp/c/OP_UNUSED_A5FF.cpp
new file mode 100644
index 0000000..15999ba
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A5FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A5FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A6FF.cpp b/vm/mterp/c/OP_UNUSED_A6FF.cpp
new file mode 100644
index 0000000..2d85c0a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A6FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A6FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A7FF.cpp b/vm/mterp/c/OP_UNUSED_A7FF.cpp
new file mode 100644
index 0000000..9628590
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A7FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A7FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A8FF.cpp b/vm/mterp/c/OP_UNUSED_A8FF.cpp
new file mode 100644
index 0000000..11ace32
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A8FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A8FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_A9FF.cpp b/vm/mterp/c/OP_UNUSED_A9FF.cpp
new file mode 100644
index 0000000..71dfabc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_A9FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_A9FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_AAFF.cpp b/vm/mterp/c/OP_UNUSED_AAFF.cpp
new file mode 100644
index 0000000..01a7491
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_AAFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_AAFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_ABFF.cpp b/vm/mterp/c/OP_UNUSED_ABFF.cpp
new file mode 100644
index 0000000..942aa78
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_ABFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_ABFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_ACFF.cpp b/vm/mterp/c/OP_UNUSED_ACFF.cpp
new file mode 100644
index 0000000..82f1285
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_ACFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_ACFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_ADFF.cpp b/vm/mterp/c/OP_UNUSED_ADFF.cpp
new file mode 100644
index 0000000..3e11ea6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_ADFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_ADFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_AEFF.cpp b/vm/mterp/c/OP_UNUSED_AEFF.cpp
new file mode 100644
index 0000000..586e745
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_AEFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_AEFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_AFFF.cpp b/vm/mterp/c/OP_UNUSED_AFFF.cpp
new file mode 100644
index 0000000..5ed1161
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_AFFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_AFFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B0FF.cpp b/vm/mterp/c/OP_UNUSED_B0FF.cpp
new file mode 100644
index 0000000..3060736
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B0FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B0FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B1FF.cpp b/vm/mterp/c/OP_UNUSED_B1FF.cpp
new file mode 100644
index 0000000..87bb7a6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B1FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B1FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B2FF.cpp b/vm/mterp/c/OP_UNUSED_B2FF.cpp
new file mode 100644
index 0000000..2bca4cd
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B2FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B2FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B3FF.cpp b/vm/mterp/c/OP_UNUSED_B3FF.cpp
new file mode 100644
index 0000000..3f17d1f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B3FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B3FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B4FF.cpp b/vm/mterp/c/OP_UNUSED_B4FF.cpp
new file mode 100644
index 0000000..be957a6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B4FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B4FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B5FF.cpp b/vm/mterp/c/OP_UNUSED_B5FF.cpp
new file mode 100644
index 0000000..239da06
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B5FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B5FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B6FF.cpp b/vm/mterp/c/OP_UNUSED_B6FF.cpp
new file mode 100644
index 0000000..e8fabb4
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B6FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B6FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B7FF.cpp b/vm/mterp/c/OP_UNUSED_B7FF.cpp
new file mode 100644
index 0000000..bdd05bd
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B7FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B7FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B8FF.cpp b/vm/mterp/c/OP_UNUSED_B8FF.cpp
new file mode 100644
index 0000000..c856720
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B8FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B8FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_B9FF.cpp b/vm/mterp/c/OP_UNUSED_B9FF.cpp
new file mode 100644
index 0000000..c3a963b
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_B9FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_B9FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_BAFF.cpp b/vm/mterp/c/OP_UNUSED_BAFF.cpp
new file mode 100644
index 0000000..d75e1cc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_BAFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_BAFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_BBFF.cpp b/vm/mterp/c/OP_UNUSED_BBFF.cpp
new file mode 100644
index 0000000..3743698
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_BBFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_BBFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_BCFF.cpp b/vm/mterp/c/OP_UNUSED_BCFF.cpp
new file mode 100644
index 0000000..6358423
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_BCFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_BCFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_BDFF.cpp b/vm/mterp/c/OP_UNUSED_BDFF.cpp
new file mode 100644
index 0000000..36f176f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_BDFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_BDFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_BEFF.cpp b/vm/mterp/c/OP_UNUSED_BEFF.cpp
new file mode 100644
index 0000000..817adca
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_BEFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_BEFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_BFFF.cpp b/vm/mterp/c/OP_UNUSED_BFFF.cpp
new file mode 100644
index 0000000..d318588
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_BFFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_BFFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C0FF.cpp b/vm/mterp/c/OP_UNUSED_C0FF.cpp
new file mode 100644
index 0000000..c87f906
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C0FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C0FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C1FF.cpp b/vm/mterp/c/OP_UNUSED_C1FF.cpp
new file mode 100644
index 0000000..7c1be52
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C1FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C1FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C2FF.cpp b/vm/mterp/c/OP_UNUSED_C2FF.cpp
new file mode 100644
index 0000000..06e03f4
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C2FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C2FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C3FF.cpp b/vm/mterp/c/OP_UNUSED_C3FF.cpp
new file mode 100644
index 0000000..b480c30
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C3FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C3FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C4FF.cpp b/vm/mterp/c/OP_UNUSED_C4FF.cpp
new file mode 100644
index 0000000..b7afb1d
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C4FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C4FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C5FF.cpp b/vm/mterp/c/OP_UNUSED_C5FF.cpp
new file mode 100644
index 0000000..432a4cd
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C5FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C5FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C6FF.cpp b/vm/mterp/c/OP_UNUSED_C6FF.cpp
new file mode 100644
index 0000000..4f8f2a5
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C6FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C6FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C7FF.cpp b/vm/mterp/c/OP_UNUSED_C7FF.cpp
new file mode 100644
index 0000000..92f2c6a
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C7FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C7FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C8FF.cpp b/vm/mterp/c/OP_UNUSED_C8FF.cpp
new file mode 100644
index 0000000..33c4f59
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C8FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C8FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_C9FF.cpp b/vm/mterp/c/OP_UNUSED_C9FF.cpp
new file mode 100644
index 0000000..e04d233
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_C9FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_C9FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_CAFF.cpp b/vm/mterp/c/OP_UNUSED_CAFF.cpp
new file mode 100644
index 0000000..da3e0a5
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_CAFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_CAFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_CBFF.cpp b/vm/mterp/c/OP_UNUSED_CBFF.cpp
new file mode 100644
index 0000000..cf809b6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_CBFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_CBFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_CCFF.cpp b/vm/mterp/c/OP_UNUSED_CCFF.cpp
new file mode 100644
index 0000000..7d843d3
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_CCFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_CCFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_CDFF.cpp b/vm/mterp/c/OP_UNUSED_CDFF.cpp
new file mode 100644
index 0000000..553be78
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_CDFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_CDFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_CEFF.cpp b/vm/mterp/c/OP_UNUSED_CEFF.cpp
new file mode 100644
index 0000000..01e933f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_CEFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_CEFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_CFFF.cpp b/vm/mterp/c/OP_UNUSED_CFFF.cpp
new file mode 100644
index 0000000..806aa2f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_CFFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_CFFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D0FF.cpp b/vm/mterp/c/OP_UNUSED_D0FF.cpp
new file mode 100644
index 0000000..e2bb5a1
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D0FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D0FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D1FF.cpp b/vm/mterp/c/OP_UNUSED_D1FF.cpp
new file mode 100644
index 0000000..0d91cca
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D1FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D1FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D2FF.cpp b/vm/mterp/c/OP_UNUSED_D2FF.cpp
new file mode 100644
index 0000000..8a6db76
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D2FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D2FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D3FF.cpp b/vm/mterp/c/OP_UNUSED_D3FF.cpp
new file mode 100644
index 0000000..32205bb
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D3FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D3FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D4FF.cpp b/vm/mterp/c/OP_UNUSED_D4FF.cpp
new file mode 100644
index 0000000..0413ed6
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D4FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D4FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D5FF.cpp b/vm/mterp/c/OP_UNUSED_D5FF.cpp
new file mode 100644
index 0000000..cc67e9d
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D5FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D5FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D6FF.cpp b/vm/mterp/c/OP_UNUSED_D6FF.cpp
new file mode 100644
index 0000000..3711bbc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D6FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D6FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D7FF.cpp b/vm/mterp/c/OP_UNUSED_D7FF.cpp
new file mode 100644
index 0000000..6a17a2d
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D7FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D7FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D8FF.cpp b/vm/mterp/c/OP_UNUSED_D8FF.cpp
new file mode 100644
index 0000000..c934090
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D8FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D8FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_D9FF.cpp b/vm/mterp/c/OP_UNUSED_D9FF.cpp
new file mode 100644
index 0000000..78984af
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_D9FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_D9FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_DAFF.cpp b/vm/mterp/c/OP_UNUSED_DAFF.cpp
new file mode 100644
index 0000000..2a177f0
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_DAFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_DAFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_DBFF.cpp b/vm/mterp/c/OP_UNUSED_DBFF.cpp
new file mode 100644
index 0000000..5447dc7
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_DBFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_DBFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_DCFF.cpp b/vm/mterp/c/OP_UNUSED_DCFF.cpp
new file mode 100644
index 0000000..a6ae5de
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_DCFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_DCFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_DDFF.cpp b/vm/mterp/c/OP_UNUSED_DDFF.cpp
new file mode 100644
index 0000000..a18cbbe
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_DDFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_DDFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_DEFF.cpp b/vm/mterp/c/OP_UNUSED_DEFF.cpp
new file mode 100644
index 0000000..c9be0ed
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_DEFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_DEFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_DFFF.cpp b/vm/mterp/c/OP_UNUSED_DFFF.cpp
new file mode 100644
index 0000000..4d455ee
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_DFFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_DFFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E0FF.cpp b/vm/mterp/c/OP_UNUSED_E0FF.cpp
new file mode 100644
index 0000000..9507bcb
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E0FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E0FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E1FF.cpp b/vm/mterp/c/OP_UNUSED_E1FF.cpp
new file mode 100644
index 0000000..84f6eed
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E1FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E1FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E2FF.cpp b/vm/mterp/c/OP_UNUSED_E2FF.cpp
new file mode 100644
index 0000000..a6153cc
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E2FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E2FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E3FF.cpp b/vm/mterp/c/OP_UNUSED_E3FF.cpp
new file mode 100644
index 0000000..fc0181f
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E3FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E3FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E4FF.cpp b/vm/mterp/c/OP_UNUSED_E4FF.cpp
new file mode 100644
index 0000000..cc11656
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E4FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E4FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E5FF.cpp b/vm/mterp/c/OP_UNUSED_E5FF.cpp
new file mode 100644
index 0000000..1c40042
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E5FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E5FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E6FF.cpp b/vm/mterp/c/OP_UNUSED_E6FF.cpp
new file mode 100644
index 0000000..3686579
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E6FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E6FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E7FF.cpp b/vm/mterp/c/OP_UNUSED_E7FF.cpp
new file mode 100644
index 0000000..060be13
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E7FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E7FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E8FF.cpp b/vm/mterp/c/OP_UNUSED_E8FF.cpp
new file mode 100644
index 0000000..436883b
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E8FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E8FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_E9FF.cpp b/vm/mterp/c/OP_UNUSED_E9FF.cpp
new file mode 100644
index 0000000..7c0cd56
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_E9FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_E9FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EAFF.cpp b/vm/mterp/c/OP_UNUSED_EAFF.cpp
new file mode 100644
index 0000000..cb33407
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_EAFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_EAFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EBFF.cpp b/vm/mterp/c/OP_UNUSED_EBFF.cpp
new file mode 100644
index 0000000..16f7a20
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_EBFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_EBFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_ECFF.cpp b/vm/mterp/c/OP_UNUSED_ECFF.cpp
new file mode 100644
index 0000000..7ae6372
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_ECFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_ECFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EDFF.cpp b/vm/mterp/c/OP_UNUSED_EDFF.cpp
new file mode 100644
index 0000000..d6528a1
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_EDFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_EDFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EEFF.cpp b/vm/mterp/c/OP_UNUSED_EEFF.cpp
new file mode 100644
index 0000000..24918ef
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_EEFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_EEFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_EFFF.cpp b/vm/mterp/c/OP_UNUSED_EFFF.cpp
new file mode 100644
index 0000000..f15c2be
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_EFFF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_EFFF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_F0FF.cpp b/vm/mterp/c/OP_UNUSED_F0FF.cpp
new file mode 100644
index 0000000..f9049b5
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_F0FF.cpp
@@ -0,0 +1,2 @@
+HANDLE_OPCODE(OP_UNUSED_F0FF)
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_F1FF.cpp b/vm/mterp/c/OP_UNUSED_F1FF.cpp
new file mode 100644
index 0000000..34259d3
--- /dev/null
+++ b/vm/mterp/c/OP_UNUSED_F1FF.cpp
@@ -0,0 +1,8 @@
+HANDLE_OPCODE(OP_UNUSED_F1FF)
+    /*
+     * In portable interp, most unused opcodes will fall through to here.
+     */
+    LOGE("unknown opcode 0x%04x", inst);
+    dvmAbort();
+    FINISH(1);
+OP_END
diff --git a/vm/mterp/c/OP_USHR_INT.cpp b/vm/mterp/c/OP_USHR_INT.cpp
new file mode 100644
index 0000000..7596c94
--- /dev/null
+++ b/vm/mterp/c/OP_USHR_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT(OP_USHR_INT, "ushr", (u4), >>)
+OP_END
diff --git a/vm/mterp/c/OP_USHR_INT_2ADDR.cpp b/vm/mterp/c/OP_USHR_INT_2ADDR.cpp
new file mode 100644
index 0000000..5fa2b94
--- /dev/null
+++ b/vm/mterp/c/OP_USHR_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT_2ADDR(OP_USHR_INT_2ADDR, "ushr", (u4), >>)
+OP_END
diff --git a/vm/mterp/c/OP_USHR_INT_LIT8.cpp b/vm/mterp/c/OP_USHR_INT_LIT8.cpp
new file mode 100644
index 0000000..0d325d7
--- /dev/null
+++ b/vm/mterp/c/OP_USHR_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8,  "ushr", (u4), >>)
+OP_END
diff --git a/vm/mterp/c/OP_USHR_LONG.cpp b/vm/mterp/c/OP_USHR_LONG.cpp
new file mode 100644
index 0000000..9b7e757
--- /dev/null
+++ b/vm/mterp/c/OP_USHR_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_LONG(OP_USHR_LONG, "ushr", (u8), >>)
+OP_END
diff --git a/vm/mterp/c/OP_USHR_LONG_2ADDR.cpp b/vm/mterp/c/OP_USHR_LONG_2ADDR.cpp
new file mode 100644
index 0000000..4ac0598
--- /dev/null
+++ b/vm/mterp/c/OP_USHR_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_SHX_LONG_2ADDR(OP_USHR_LONG_2ADDR, "ushr", (u8), >>)
+OP_END
diff --git a/vm/mterp/c/OP_XOR_INT.cpp b/vm/mterp/c/OP_XOR_INT.cpp
new file mode 100644
index 0000000..d591909
--- /dev/null
+++ b/vm/mterp/c/OP_XOR_INT.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT(OP_XOR_INT, "xor", ^, 0)
+OP_END
diff --git a/vm/mterp/c/OP_XOR_INT_2ADDR.cpp b/vm/mterp/c/OP_XOR_INT_2ADDR.cpp
new file mode 100644
index 0000000..7d32879
--- /dev/null
+++ b/vm/mterp/c/OP_XOR_INT_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_2ADDR(OP_XOR_INT_2ADDR, "xor", ^, 0)
+OP_END
diff --git a/vm/mterp/c/OP_XOR_INT_LIT16.cpp b/vm/mterp/c/OP_XOR_INT_LIT16.cpp
new file mode 100644
index 0000000..c204b79
--- /dev/null
+++ b/vm/mterp/c/OP_XOR_INT_LIT16.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT16(OP_XOR_INT_LIT16, "xor", ^, 0)
+OP_END
diff --git a/vm/mterp/c/OP_XOR_INT_LIT8.cpp b/vm/mterp/c/OP_XOR_INT_LIT8.cpp
new file mode 100644
index 0000000..f01773a
--- /dev/null
+++ b/vm/mterp/c/OP_XOR_INT_LIT8.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_INT_LIT8(OP_XOR_INT_LIT8,   "xor", ^, 0)
+OP_END
diff --git a/vm/mterp/c/OP_XOR_LONG.cpp b/vm/mterp/c/OP_XOR_LONG.cpp
new file mode 100644
index 0000000..d3dbc4c
--- /dev/null
+++ b/vm/mterp/c/OP_XOR_LONG.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG(OP_XOR_LONG, "xor", ^, 0)
+OP_END
diff --git a/vm/mterp/c/OP_XOR_LONG_2ADDR.cpp b/vm/mterp/c/OP_XOR_LONG_2ADDR.cpp
new file mode 100644
index 0000000..e7a50f4
--- /dev/null
+++ b/vm/mterp/c/OP_XOR_LONG_2ADDR.cpp
@@ -0,0 +1,2 @@
+HANDLE_OP_X_LONG_2ADDR(OP_XOR_LONG_2ADDR, "xor", ^, 0)
+OP_END
diff --git a/vm/mterp/c/gotoTargets.cpp b/vm/mterp/c/gotoTargets.cpp
new file mode 100644
index 0000000..9d90046
--- /dev/null
+++ b/vm/mterp/c/gotoTargets.cpp
@@ -0,0 +1,1032 @@
+/*
+ * C footer.  This has some common code shared by the various targets.
+ */
+
+/*
+ * Everything from here on is a "goto target".  In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction.  Here, these are subroutines that return to the caller.
+ */
+
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool jumboFormat)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        u4* contents;
+        char typeCh;
+        int i;
+        u4 arg5;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* class ref */
+            vsrc1 = FETCH(3);                     /* #of elements */
+            vdst = FETCH(4);                      /* range base */
+            arg5 = -1;                            /* silence compiler warning */
+            ILOGV("|filled-new-array/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        } else {
+            ref = FETCH(1);             /* class ref */
+            vdst = FETCH(2);            /* first 4 regs -or- range base */
+
+            if (methodCallRange) {
+                vsrc1 = INST_AA(inst);  /* #of elements */
+                arg5 = -1;              /* silence compiler warning */
+                ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+            } else {
+                arg5 = INST_A(inst);
+                vsrc1 = INST_B(inst);   /* #of elements */
+                ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
+                   vsrc1, ref, vdst, arg5);
+            }
+        }
+
+        /*
+         * Resolve the array class.
+         */
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /*
+        if (!dvmIsArrayClass(arrayClass)) {
+            dvmThrowRuntimeException(
+                "filled-new-array needs array class");
+            GOTO_exceptionThrown();
+        }
+        */
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        /*
+         * Create an array of the specified type.
+         */
+        LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
+        typeCh = arrayClass->descriptor[1];
+        if (typeCh == 'D' || typeCh == 'J') {
+            /* category 2 primitives not allowed */
+            dvmThrowRuntimeException("bad filled array req");
+            GOTO_exceptionThrown();
+        } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
+            /* TODO: requires multiple "fill in" loops with different widths */
+            LOGE("non-int primitives not implemented");
+            dvmThrowInternalError(
+                "filled-new-array not implemented for anything but 'int'");
+            GOTO_exceptionThrown();
+        }
+
+        newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+
+        /*
+         * Fill in the elements.  It's legal for vsrc1 to be zero.
+         */
+        contents = (u4*)(void*)newArray->contents;
+        if (methodCallRange) {
+            for (i = 0; i < vsrc1; i++)
+                contents[i] = GET_REGISTER(vdst+i);
+        } else {
+            assert(vsrc1 <= 5);
+            if (vsrc1 == 5) {
+                contents[4] = GET_REGISTER(arg5);
+                vsrc1--;
+            }
+            for (i = 0; i < vsrc1; i++) {
+                contents[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+        }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
+
+        retval.l = (Object*)newArray;
+    }
+    if (jumboFormat) {
+        FINISH(5);
+    } else {
+        FINISH(3);
+    }
+GOTO_TARGET_END
+
+
+GOTO_TARGET(invokeVirtual, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-virtual/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->methodToCall = methodToCall;
+        self->callsiteClass = thisPtr->clazz;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            /*
+             * This can happen if you create two classes, Base and Sub, where
+             * Sub is a sub-class of Base.  Declare a protected abstract
+             * method foo() in Base, and invoke foo() from a method in Base.
+             * Base is an "abstract base class" and is never instantiated
+             * directly.  Now, Override foo() in Sub, and use Sub.  This
+             * Works fine unless Sub stops providing an implementation of
+             * the method.
+             */
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            (u4) baseMethod->methodIndex,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+#if 0
+        if (vsrc1 != methodToCall->insSize) {
+            LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
+                baseMethod->clazz->descriptor, baseMethod->name,
+                (u4) baseMethod->methodIndex,
+                methodToCall->clazz->descriptor, methodToCall->name);
+            //dvmDumpClass(baseMethod->clazz);
+            //dvmDumpClass(methodToCall->clazz);
+            dvmDumpAllClasses(0);
+        }
+#endif
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuper, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-super/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         * The first arg to dvmResolveMethod() is just the referring class
+         * (used for class loaders and such), so we don't want to pass
+         * the superclass into the resolution call.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in that class' superclass.
+         */
+        if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
+            /*
+             * Method does not exist in the superclass.  Could happen if
+             * superclass gets updated.
+             */
+            dvmThrowNoSuchMethodError(baseMethod->name);
+            GOTO_exceptionThrown();
+        }
+        methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ base=%s.%s super-virtual=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeInterface, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+        ClassObject* thisClass;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-interface/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        thisClass = thisPtr->clazz;
+
+
+        /*
+         * Given a class and a method index, find the Method* with the
+         * actual code we want to execute.
+         */
+        methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
+                        methodClassDex);
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisClass;
+        self->methodToCall = methodToCall;
+#endif
+        if (methodToCall == NULL) {
+            assert(dvmCheckException(self));
+            GOTO_exceptionThrown();
+        }
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeDirect, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-direct/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (methodToCall == NULL) {
+            methodToCall = dvmResolveMethod(curMethod->clazz, ref,
+                            METHOD_DIRECT);
+            if (methodToCall == NULL) {
+                ILOGV("+ unknown direct method");     // should be impossible
+                GOTO_exceptionThrown();
+            }
+        }
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeStatic, bool methodCallRange, bool jumboFormat)
+    EXPORT_PC();
+
+    if (jumboFormat) {
+        ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+        vsrc1 = FETCH(3);                     /* count */
+        vdst = FETCH(4);                      /* first reg */
+        ADJUST_PC(2);     /* advance pc partially to make returns easier */
+        ILOGV("|invoke-static/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+    } else {
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* method ref */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange)
+            ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        else
+            ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+    }
+
+    methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+    if (methodToCall == NULL) {
+        methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
+        if (methodToCall == NULL) {
+            ILOGV("+ unknown method");
+            GOTO_exceptionThrown();
+        }
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        /*
+         * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+         * Include the check if this code is being used as a stub
+         * called from the assembly interpreter.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
+            /* Class initialization is still ongoing */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+    }
+    GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeVirtualQuick, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        /*
+         * The object against which we are executing a method is always
+         * in the first argument.
+         */
+        if (methodCallRange) {
+            assert(vsrc1 > 0);
+            ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            assert((vsrc1>>4) > 0);
+            ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[ref];
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisPtr->clazz;
+        self->methodToCall = methodToCall;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuperQuick, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange) {
+            ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisReg = vdst & 0x0f;
+        }
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+#if 0   /* impossible in optimized + verified code */
+        if (ref >= curMethod->clazz->super->vtableCount) {
+            dvmThrowNoSuchMethodError(NULL);
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
+#endif
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in the method's class' superclass.
+         */
+        methodToCall = curMethod->clazz->super->vtable[ref];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ super-virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * General handling for return-void, return, and return-wide.  Put the
+     * return value in "retval" before jumping here.
+     */
+GOTO_TARGET(returnFromMethod)
+    {
+        StackSaveArea* saveArea;
+
+        /*
+         * We must do this BEFORE we pop the previous stack frame off, so
+         * that the GC can see the return value (if any) in the local vars.
+         *
+         * Since this is now an interpreter switch point, we must do it before
+         * we do anything at all.
+         */
+        PERIODIC_CHECKS(0);
+
+        ILOGV("> retval=0x%llx (leaving %s.%s %s)",
+            retval.j, curMethod->clazz->descriptor, curMethod->name,
+            curMethod->shorty);
+        //DUMP_REGS(curMethod, fp);
+
+        saveArea = SAVEAREA_FROM_FP(fp);
+
+#ifdef EASY_GDB
+        debugSaveArea = saveArea;
+#endif
+
+        /* back up to previous frame and see if we hit a break */
+        fp = (u4*)saveArea->prevFrame;
+        assert(fp != NULL);
+
+        /* Handle any special subMode requirements */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportReturn(self);
+        }
+
+        if (dvmIsBreakFrame(fp)) {
+            /* bail without popping the method frame from stack */
+            LOGVV("+++ returned into break frame");
+            GOTO_bail();
+        }
+
+        /* update thread FP, and reset local variables */
+        self->interpSave.curFrame = fp;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = saveArea->savedPc;
+        ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+
+        /* use FINISH on the caller's invoke instruction */
+        //u2 invokeInstr = INST_INST(FETCH(0));
+        if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+            invokeInstr <= OP_INVOKE_INTERFACE*/)
+        {
+            FINISH(3);
+        } else {
+            //LOGE("Unknown invoke instr %02x at %d",
+            //    invokeInstr, (int) (pc - curMethod->insns));
+            assert(false);
+        }
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * Jump here when the code throws an exception.
+     *
+     * By the time we get here, the Throwable has been created and the stack
+     * trace has been saved off.
+     */
+GOTO_TARGET(exceptionThrown)
+    {
+        Object* exception;
+        int catchRelPc;
+
+        PERIODIC_CHECKS(0);
+
+        /*
+         * We save off the exception and clear the exception status.  While
+         * processing the exception we might need to load some Throwable
+         * classes, and we don't want class loader exceptions to get
+         * confused with this one.
+         */
+        assert(dvmCheckException(self));
+        exception = dvmGetException(self);
+        dvmAddTrackedAlloc(exception, self);
+        dvmClearException(self);
+
+        LOGV("Handling exception %s at %s:%d",
+            exception->clazz->descriptor, curMethod->name,
+            dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+
+        /*
+         * Report the exception throw to any "subMode" watchers.
+         *
+         * TODO: if the exception was thrown by interpreted code, control
+         * fell through native, and then back to us, we will report the
+         * exception at the point of the throw and again here.  We can avoid
+         * this by not reporting exceptions when we jump here directly from
+         * the native call code above, but then we won't report exceptions
+         * that were thrown *from* the JNI code (as opposed to *through* it).
+         *
+         * The correct solution is probably to ignore from-native exceptions
+         * here, and have the JNI exception code do the reporting to the
+         * debugger.
+         */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportExceptionThrow(self, exception);
+        }
+
+        /*
+         * We need to unroll to the catch block or the nearest "break"
+         * frame.
+         *
+         * A break frame could indicate that we have reached an intermediate
+         * native call, or have gone off the top of the stack and the thread
+         * needs to exit.  Either way, we return from here, leaving the
+         * exception raised.
+         *
+         * If we do find a catch block, we want to transfer execution to
+         * that point.
+         *
+         * Note this can cause an exception while resolving classes in
+         * the "catch" blocks.
+         */
+        catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
+                    exception, false, (void**)(void*)&fp);
+
+        /*
+         * Restore the stack bounds after an overflow.  This isn't going to
+         * be correct in all circumstances, e.g. if JNI code devours the
+         * exception this won't happen until some other exception gets
+         * thrown.  If the code keeps pushing the stack bounds we'll end
+         * up aborting the VM.
+         *
+         * Note we want to do this *after* the call to dvmFindCatchBlock,
+         * because that may need extra stack space to resolve exception
+         * classes (e.g. through a class loader).
+         *
+         * It's possible for the stack overflow handling to cause an
+         * exception (specifically, class resolution in a "catch" block
+         * during the call above), so we could see the thread's overflow
+         * flag raised but actually be running in a "nested" interpreter
+         * frame.  We don't allow doubled-up StackOverflowErrors, so
+         * we can check for this by just looking at the exception type
+         * in the cleanup function.  Also, we won't unroll past the SOE
+         * point because the more-recent exception will hit a break frame
+         * as it unrolls to here.
+         */
+        if (self->stackOverflowed)
+            dvmCleanupStackOverflow(self, exception);
+
+        if (catchRelPc < 0) {
+            /* falling through to JNI code or off the bottom of the stack */
+#if DVM_SHOW_EXCEPTION >= 2
+            LOGD("Exception %s from %s:%d not caught locally",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+#endif
+            dvmSetException(self, exception);
+            dvmReleaseTrackedAlloc(exception, self);
+            GOTO_bail();
+        }
+
+#if DVM_SHOW_EXCEPTION >= 3
+        {
+            const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
+            LOGD("Exception %s thrown from %s:%d to %s:%d",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns),
+                dvmGetMethodSourceFile(catchMethod),
+                dvmLineNumFromPC(catchMethod, catchRelPc));
+        }
+#endif
+
+        /*
+         * Adjust local variables to match self->interpSave.curFrame and the
+         * updated PC.
+         */
+        //fp = (u4*) self->interpSave.curFrame;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = curMethod->insns + catchRelPc;
+        ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+        DUMP_REGS(curMethod, fp, false);            // show all regs
+
+        /*
+         * Restore the exception if the handler wants it.
+         *
+         * The Dalvik spec mandates that, if an exception handler wants to
+         * do something with the exception, the first instruction executed
+         * must be "move-exception".  We can pass the exception along
+         * through the thread struct, and let the move-exception instruction
+         * clear it for us.
+         *
+         * If the handler doesn't call move-exception, we don't want to
+         * finish here with an exception still pending.
+         */
+        if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
+            dvmSetException(self, exception);
+
+        dvmReleaseTrackedAlloc(exception, self);
+        FINISH(0);
+    }
+GOTO_TARGET_END
+
+
+
+    /*
+     * General handling for invoke-{virtual,super,direct,static,interface},
+     * including "quick" variants.
+     *
+     * Set "methodToCall" to the Method we're calling, and "methodCallRange"
+     * depending on whether this is a "/range" instruction.
+     *
+     * For a range call:
+     *  "vsrc1" holds the argument count (8 bits)
+     *  "vdst" holds the first argument in the range
+     * For a non-range call:
+     *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
+     *  "vdst" holds four 4-bit register indices
+     *
+     * The caller must EXPORT_PC before jumping here, because any method
+     * call can throw a stack overflow exception.
+     */
+GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
+    u2 count, u2 regs)
+    {
+        STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
+
+        //printf("range=%d call=%p count=%d regs=0x%04x\n",
+        //    methodCallRange, methodToCall, count, regs);
+        //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
+        //    methodToCall->name, methodToCall->shorty);
+
+        u4* outs;
+        int i;
+
+        /*
+         * Copy args.  This may corrupt vsrc1/vdst.
+         */
+        if (methodCallRange) {
+            // could use memcpy or a "Duff's device"; most functions have
+            // so few args it won't matter much
+            assert(vsrc1 <= curMethod->outsSize);
+            assert(vsrc1 == methodToCall->insSize);
+            outs = OUTS_FROM_FP(fp, vsrc1);
+            for (i = 0; i < vsrc1; i++)
+                outs[i] = GET_REGISTER(vdst+i);
+        } else {
+            u4 count = vsrc1 >> 4;
+
+            assert(count <= curMethod->outsSize);
+            assert(count == methodToCall->insSize);
+            assert(count <= 5);
+
+            outs = OUTS_FROM_FP(fp, count);
+#if 0
+            if (count == 5) {
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+                count--;
+            }
+            for (i = 0; i < (int) count; i++) {
+                outs[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+#else
+            // This version executes fewer instructions but is larger
+            // overall.  Seems to be a teensy bit faster.
+            assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
+            switch (count) {
+            case 5:
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+            case 4:
+                outs[3] = GET_REGISTER(vdst >> 12);
+            case 3:
+                outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
+            case 2:
+                outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
+            case 1:
+                outs[0] = GET_REGISTER(vdst & 0x0f);
+            default:
+                ;
+            }
+#endif
+        }
+    }
+
+    /*
+     * (This was originally a "goto" target; I've kept it separate from the
+     * stuff above in case we want to refactor things again.)
+     *
+     * At this point, we have the arguments stored in the "outs" area of
+     * the current method's stack frame, and the method to call in
+     * "methodToCall".  Push a new stack frame.
+     */
+    {
+        StackSaveArea* newSaveArea;
+        u4* newFp;
+
+        ILOGV("> %s%s.%s %s",
+            dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
+            methodToCall->clazz->descriptor, methodToCall->name,
+            methodToCall->shorty);
+
+        newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
+        newSaveArea = SAVEAREA_FROM_FP(newFp);
+
+        /* verify that we have enough space */
+        if (true) {
+            u1* bottom;
+            bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
+            if (bottom < self->interpStackEnd) {
+                /* stack overflow */
+                LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
+                    self->interpStackStart, self->interpStackEnd, bottom,
+                    (u1*) fp - bottom, self->interpStackSize,
+                    methodToCall->name);
+                dvmHandleStackOverflow(self, methodToCall);
+                assert(dvmCheckException(self));
+                GOTO_exceptionThrown();
+            }
+            //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
+            //    fp, newFp, newSaveArea, bottom);
+        }
+
+#ifdef LOG_INSTR
+        if (methodToCall->registersSize > methodToCall->insSize) {
+            /*
+             * This makes valgrind quiet when we print registers that
+             * haven't been initialized.  Turn it off when the debug
+             * messages are disabled -- we want valgrind to report any
+             * used-before-initialized issues.
+             */
+            memset(newFp, 0xcc,
+                (methodToCall->registersSize - methodToCall->insSize) * 4);
+        }
+#endif
+
+#ifdef EASY_GDB
+        newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
+#endif
+        newSaveArea->prevFrame = fp;
+        newSaveArea->savedPc = pc;
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        newSaveArea->returnAddr = 0;
+#endif
+        newSaveArea->method = methodToCall;
+
+        if (self->interpBreak.ctl.subMode != 0) {
+            /*
+             * We mark ENTER here for both native and non-native
+             * calls.  For native calls, we'll mark EXIT on return.
+             * For non-native calls, EXIT is marked in the RETURN op.
+             */
+            PC_TO_SELF();
+            dvmReportInvoke(self, methodToCall);
+        }
+
+        if (!dvmIsNativeMethod(methodToCall)) {
+            /*
+             * "Call" interpreted code.  Reposition the PC, update the
+             * frame pointer and other local state, and continue.
+             */
+            curMethod = methodToCall;
+            self->interpSave.method = curMethod;
+            methodClassDex = curMethod->clazz->pDvmDex;
+            pc = methodToCall->insns;
+            self->interpSave.curFrame = fp = newFp;
+#ifdef EASY_GDB
+            debugSaveArea = SAVEAREA_FROM_FP(newFp);
+#endif
+            self->debugIsMethodEntry = true;        // profiling, debugging
+            ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+                curMethod->name, curMethod->shorty);
+            DUMP_REGS(curMethod, fp, true);         // show input args
+            FINISH(0);                              // jump to method start
+        } else {
+            /* set this up for JNI locals, even if not a JNI native */
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+
+            self->interpSave.curFrame = newFp;
+
+            DUMP_REGS(methodToCall, newFp, true);   // show input args
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPreNativeInvoke(methodToCall, self, fp);
+            }
+
+            ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+                  methodToCall->name, methodToCall->shorty);
+
+            /*
+             * Jump through native call bridge.  Because we leave no
+             * space for locals on native calls, "newFp" points directly
+             * to the method arguments.
+             */
+            (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPostNativeInvoke(methodToCall, self, fp);
+            }
+
+            /* pop frame off */
+            dvmPopJniLocals(self, newSaveArea);
+            self->interpSave.curFrame = fp;
+
+            /*
+             * If the native code threw an exception, or interpreted code
+             * invoked by the native call threw one and nobody has cleared
+             * it, jump to our local exception handling.
+             */
+            if (dvmCheckException(self)) {
+                LOGV("Exception thrown by/below native code");
+                GOTO_exceptionThrown();
+            }
+
+            ILOGD("> retval=0x%llx (leaving native)", retval.j);
+            ILOGD("> (return from native %s.%s to %s.%s %s)",
+                methodToCall->clazz->descriptor, methodToCall->name,
+                curMethod->clazz->descriptor, curMethod->name,
+                curMethod->shorty);
+
+            //u2 invokeInstr = INST_INST(FETCH(0));
+            if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+                invokeInstr <= OP_INVOKE_INTERFACE*/)
+            {
+                FINISH(3);
+            } else {
+                //LOGE("Unknown invoke instr %02x at %d",
+                //    invokeInstr, (int) (pc - curMethod->insns));
+                assert(false);
+            }
+        }
+    }
+    assert(false);      // should not get here
+GOTO_TARGET_END
diff --git a/vm/mterp/c/header.cpp b/vm/mterp/c/header.cpp
new file mode 100644
index 0000000..c7e727e
--- /dev/null
+++ b/vm/mterp/c/header.cpp
@@ -0,0 +1,361 @@
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
diff --git a/vm/mterp/c/opcommon.cpp b/vm/mterp/c/opcommon.cpp
new file mode 100644
index 0000000..104d856
--- /dev/null
+++ b/vm/mterp/c/opcommon.cpp
@@ -0,0 +1,747 @@
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
diff --git a/vm/mterp/common/FindInterface.h b/vm/mterp/common/FindInterface.h
new file mode 100644
index 0000000..72d45ff
--- /dev/null
+++ b/vm/mterp/common/FindInterface.h
@@ -0,0 +1,41 @@
+/*
+ * 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"
+
+extern "C" {
+
+/*
+ * 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
new file mode 100644
index 0000000..af2275d
--- /dev/null
+++ b/vm/mterp/common/asm-constants.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2008 The Android Open Source Project
+ *
+ * Constants used by the assembler and verified by the C compiler.
+ */
+
+#if defined(ASM_DEF_VERIFY)
+  /*
+   * Generate C fragments that verify values; assumes "bool failed" exists.
+   * These are all constant expressions, so on success these will compile
+   * down to nothing.
+   */
+# define MTERP_OFFSET(_name, _type, _field, _offset)                        \
+    if (OFFSETOF_MEMBER(_type, _field) != _offset) {                        \
+        LOGE("Bad asm offset %s (%d), should be %d",                        \
+            #_name, _offset, OFFSETOF_MEMBER(_type, _field));               \
+        failed = true;                                                      \
+    }
+# define MTERP_SIZEOF(_name, _type, _size)                                  \
+    if (sizeof(_type) != (_size)) {                                         \
+        LOGE("Bad asm sizeof %s (%d), should be %d",                        \
+            #_name, (_size), sizeof(_type));                                \
+        failed = true;                                                      \
+    }
+# define MTERP_CONSTANT(_name, _value)                                      \
+    if ((_name) != (_value)) {                                              \
+        LOGE("Bad asm constant %s (%d), should be %d",                      \
+            #_name, (_value), (_name));                                     \
+        failed = true;                                                      \
+    }
+#else
+  /* generate constant labels for the assembly output */
+# define MTERP_OFFSET(name, type, field, offset)    name = offset
+# define MTERP_SIZEOF(name, type, size)             name = size
+# define MTERP_CONSTANT(name, value)                name = value
+#endif
+
+/*
+ * Platform dependencies.  Some platforms require 64-bit alignment of 64-bit
+ * data structures.  Some versions of gcc will hold small enumerated types
+ * in a char instead of an int.
+ */
+#if defined(__ARM_EABI__)
+# define MTERP_NO_UNALIGN_64
+#endif
+#if defined(HAVE_SHORT_ENUMS)
+# define MTERP_SMALL_ENUM   1
+#else
+# define MTERP_SMALL_ENUM   4
+#endif
+
+/*
+ * This file must only contain the following kinds of statements:
+ *
+ *  MTERP_OFFSET(name, StructType, fieldname, offset)
+ *
+ *   Declares that the expected offset of StructType.fieldname is "offset".
+ *   This will break whenever the contents of StructType are rearranged.
+ *
+ *  MTERP_SIZEOF(name, Type, size)
+ *
+ *   Declares that the expected size of Type is "size".
+ *
+ *  MTERP_CONSTANT(name, value)
+ *
+ *   Declares that the expected value of "name" is "value".  Useful for
+ *   enumerations and defined constants that are inaccessible to the
+ *   assembly source.  (Note this assumes you will use the same name in
+ *   both C and assembly, which is good practice.)
+ *
+ * In all cases the "name" field is the label you will use in the assembler.
+ *
+ * The "value" field must always be an actual number, not a symbol, unless
+ * you are sure that the symbol's value will be visible to both C and
+ * assembly sources.  There may be restrictions on the possible range of
+ * values (which are usually provided as immediate operands), so it's best
+ * to restrict numbers assuming a signed 8-bit field.
+ *
+ * On the assembly side, these just become "name=value" constants.  On the
+ * C side, these turn into assertions that cause the VM to abort if the
+ * values are incorrect.
+ */
+
+/* DvmDex fields */
+MTERP_OFFSET(offDvmDex_pResStrings,     DvmDex, pResStrings, 8)
+MTERP_OFFSET(offDvmDex_pResClasses,     DvmDex, pResClasses, 12)
+MTERP_OFFSET(offDvmDex_pResMethods,     DvmDex, pResMethods, 16)
+MTERP_OFFSET(offDvmDex_pResFields,      DvmDex, pResFields, 20)
+MTERP_OFFSET(offDvmDex_pInterfaceCache, DvmDex, pInterfaceCache, 24)
+
+/* StackSaveArea fields */
+#ifdef EASY_GDB
+MTERP_OFFSET(offStackSaveArea_prevSave, StackSaveArea, prevSave, 0)
+MTERP_OFFSET(offStackSaveArea_prevFrame, StackSaveArea, prevFrame, 4)
+MTERP_OFFSET(offStackSaveArea_savedPc,  StackSaveArea, savedPc, 8)
+MTERP_OFFSET(offStackSaveArea_method,   StackSaveArea, method, 12)
+MTERP_OFFSET(offStackSaveArea_currentPc, StackSaveArea, xtra.currentPc, 16)
+MTERP_OFFSET(offStackSaveArea_localRefCookie, \
+                                        StackSaveArea, xtra.localRefCookie, 16)
+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_localRefCookie, \
+                                        StackSaveArea, xtra.localRefCookie, 12)
+MTERP_OFFSET(offStackSaveArea_returnAddr, StackSaveArea, returnAddr, 16)
+MTERP_SIZEOF(sizeofStackSaveArea,       StackSaveArea, 20)
+#endif
+
+  /* ShadowSpace fields */
+#if defined(WITH_JIT) && defined(WITH_SELF_VERIFICATION)
+MTERP_OFFSET(offShadowSpace_startPC,     ShadowSpace, startPC, 0)
+MTERP_OFFSET(offShadowSpace_fp,          ShadowSpace, fp, 4)
+MTERP_OFFSET(offShadowSpace_method,      ShadowSpace, method, 8)
+MTERP_OFFSET(offShadowSpace_methodClassDex, ShadowSpace, methodClassDex, 12)
+MTERP_OFFSET(offShadowSpace_retval,      ShadowSpace, retval, 16)
+MTERP_OFFSET(offShadowSpace_interpStackEnd, ShadowSpace, interpStackEnd, 24)
+MTERP_OFFSET(offShadowSpace_jitExitState,ShadowSpace, jitExitState, 28)
+MTERP_OFFSET(offShadowSpace_svState,     ShadowSpace, selfVerificationState, 32)
+MTERP_OFFSET(offShadowSpace_shadowFP,    ShadowSpace, shadowFP, 40)
+#endif
+
+/* InstField fields */
+MTERP_OFFSET(offInstField_byteOffset,   InstField, byteOffset, 16)
+
+/* Field fields */
+MTERP_OFFSET(offField_clazz,            Field, clazz, 0)
+
+/* StaticField fields */
+MTERP_OFFSET(offStaticField_value,      StaticField, value, 16)
+
+/* Method fields */
+MTERP_OFFSET(offMethod_clazz,           Method, clazz, 0)
+MTERP_OFFSET(offMethod_accessFlags,     Method, accessFlags, 4)
+MTERP_OFFSET(offMethod_methodIndex,     Method, methodIndex, 8)
+MTERP_OFFSET(offMethod_registersSize,   Method, registersSize, 10)
+MTERP_OFFSET(offMethod_outsSize,        Method, outsSize, 12)
+MTERP_OFFSET(offMethod_name,            Method, name, 16)
+MTERP_OFFSET(offMethod_insns,           Method, insns, 32)
+MTERP_OFFSET(offMethod_nativeFunc,      Method, nativeFunc, 40)
+
+/* InlineOperation fields -- code assumes "func" offset is zero, do not alter */
+MTERP_OFFSET(offInlineOperation_func,   InlineOperation, func, 0)
+
+/* Thread fields */
+MTERP_OFFSET(offThread_pc,                Thread, interpSave.pc, 0)
+MTERP_OFFSET(offThread_curFrame,          Thread, interpSave.curFrame, 4)
+MTERP_OFFSET(offThread_method,            Thread, interpSave.method, 8)
+MTERP_OFFSET(offThread_methodClassDex,    Thread, interpSave.methodClassDex, 12)
+/* make sure all JValue union members are stored at the same offset */
+MTERP_OFFSET(offThread_retval,            Thread, interpSave.retval, 16)
+MTERP_OFFSET(offThread_retval_z,          Thread, interpSave.retval.z, 16)
+MTERP_OFFSET(offThread_retval_i,          Thread, interpSave.retval.i, 16)
+MTERP_OFFSET(offThread_retval_j,          Thread, interpSave.retval.j, 16)
+MTERP_OFFSET(offThread_retval_l,          Thread, interpSave.retval.l, 16)
+MTERP_OFFSET(offThread_bailPtr,           Thread, interpSave.bailPtr, 24)
+MTERP_OFFSET(offThread_threadId,          Thread, threadId, 36)
+
+//40
+MTERP_OFFSET(offThread_subMode, \
+                               Thread, interpBreak.ctl.subMode, 40)
+MTERP_OFFSET(offThread_breakFlags, \
+                               Thread, interpBreak.ctl.breakFlags, 42)
+MTERP_OFFSET(offThread_curHandlerTable, \
+                               Thread, interpBreak.ctl.curHandlerTable, 44)
+MTERP_OFFSET(offThread_suspendCount,      Thread, suspendCount, 48);
+MTERP_OFFSET(offThread_dbgSuspendCount,   Thread, dbgSuspendCount, 52);
+MTERP_OFFSET(offThread_cardTable,         Thread, cardTable, 56)
+MTERP_OFFSET(offThread_interpStackEnd,    Thread, interpStackEnd, 60)
+MTERP_OFFSET(offThread_exception,         Thread, exception, 68)
+MTERP_OFFSET(offThread_debugIsMethodEntry, Thread, debugIsMethodEntry, 72)
+MTERP_OFFSET(offThread_interpStackSize,   Thread, interpStackSize, 76)
+MTERP_OFFSET(offThread_stackOverflowed,   Thread, stackOverflowed, 80)
+MTERP_OFFSET(offThread_mainHandlerTable,  Thread, mainHandlerTable, 88)
+MTERP_OFFSET(offThread_singleStepCount,   Thread, singleStepCount, 96)
+
+#ifdef WITH_JIT
+MTERP_OFFSET(offThread_jitToInterpEntries,Thread, jitToInterpEntries, 100)
+MTERP_OFFSET(offThread_inJitCodeCache,    Thread, inJitCodeCache, 124)
+MTERP_OFFSET(offThread_pJitProfTable,     Thread, pJitProfTable, 128)
+MTERP_OFFSET(offThread_jitThreshold,      Thread, jitThreshold, 132)
+MTERP_OFFSET(offThread_jitResumeNPC,      Thread, jitResumeNPC, 136)
+MTERP_OFFSET(offThread_jitResumeNSP,      Thread, jitResumeNSP, 140)
+MTERP_OFFSET(offThread_jitResumeDPC,      Thread, jitResumeDPC, 144)
+MTERP_OFFSET(offThread_jitState,          Thread, jitState, 148)
+MTERP_OFFSET(offThread_icRechainCount,    Thread, icRechainCount, 152)
+MTERP_OFFSET(offThread_pProfileCountdown, Thread, pProfileCountdown, 156)
+MTERP_OFFSET(offThread_callsiteClass,     Thread, callsiteClass, 160)
+MTERP_OFFSET(offThread_methodToCall,      Thread, methodToCall, 164)
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+                                Thread, jniLocalRefTable.segmentState.all, 168)
+#if defined(WITH_SELF_VERIFICATION)
+MTERP_OFFSET(offThread_shadowSpace,       Thread, shadowSpace, 188)
+#endif
+#else
+MTERP_OFFSET(offThread_jniLocal_topCookie, \
+                                Thread, jniLocalRefTable.segmentState.all, 100)
+#endif
+
+/* Object fields */
+MTERP_OFFSET(offObject_clazz,           Object, clazz, 0)
+MTERP_OFFSET(offObject_lock,            Object, lock, 4)
+
+/* Lock shape */
+MTERP_CONSTANT(LW_LOCK_OWNER_SHIFT, 3)
+MTERP_CONSTANT(LW_HASH_STATE_SHIFT, 1)
+
+/* ArrayObject fields */
+MTERP_OFFSET(offArrayObject_length,     ArrayObject, length, 8)
+#ifdef MTERP_NO_UNALIGN_64
+MTERP_OFFSET(offArrayObject_contents,   ArrayObject, contents, 16)
+#else
+MTERP_OFFSET(offArrayObject_contents,   ArrayObject, contents, 12)
+#endif
+
+/* String fields */
+MTERP_CONSTANT(STRING_FIELDOFF_VALUE,     8)
+MTERP_CONSTANT(STRING_FIELDOFF_HASHCODE, 12)
+MTERP_CONSTANT(STRING_FIELDOFF_OFFSET,   16)
+MTERP_CONSTANT(STRING_FIELDOFF_COUNT,    20)
+
+#if defined(WITH_JIT)
+/*
+ * Reasons for the non-chaining interpreter entry points
+ * Enums defined in vm/Globals.h
+ */
+MTERP_CONSTANT(kInlineCacheMiss,        0)
+MTERP_CONSTANT(kCallsiteInterpreted,    1)
+MTERP_CONSTANT(kSwitchOverflow,         2)
+MTERP_CONSTANT(kHeavyweightMonitor,     3)
+
+/* Size of callee save area */
+MTERP_CONSTANT(JIT_CALLEE_SAVE_DOUBLE_COUNT,   8)
+#endif
+
+/* ClassObject fields */
+MTERP_OFFSET(offClassObject_descriptor, ClassObject, descriptor, 24)
+MTERP_OFFSET(offClassObject_accessFlags, ClassObject, accessFlags, 32)
+MTERP_OFFSET(offClassObject_pDvmDex,    ClassObject, pDvmDex, 40)
+MTERP_OFFSET(offClassObject_status,     ClassObject, status, 44)
+MTERP_OFFSET(offClassObject_super,      ClassObject, super, 72)
+MTERP_OFFSET(offClassObject_vtableCount, ClassObject, vtableCount, 112)
+MTERP_OFFSET(offClassObject_vtable,     ClassObject, vtable, 116)
+
+#if defined(WITH_JIT)
+MTERP_CONSTANT(kJitNot,                 0)
+MTERP_CONSTANT(kJitTSelectRequest,      1)
+MTERP_CONSTANT(kJitTSelectRequestHot,   2)
+MTERP_CONSTANT(kJitSelfVerification,    3)
+MTERP_CONSTANT(kJitTSelect,             4)
+MTERP_CONSTANT(kJitTSelectEnd,          5)
+MTERP_CONSTANT(kJitDone,                6)
+
+#if defined(WITH_SELF_VERIFICATION)
+MTERP_CONSTANT(kSVSIdle, 0)
+MTERP_CONSTANT(kSVSStart, 1)
+MTERP_CONSTANT(kSVSPunt, 2)
+MTERP_CONSTANT(kSVSSingleStep, 3)
+MTERP_CONSTANT(kSVSNoProfile, 4)
+MTERP_CONSTANT(kSVSTraceSelect, 5)
+MTERP_CONSTANT(kSVSNormal, 6)
+MTERP_CONSTANT(kSVSNoChain, 7)
+MTERP_CONSTANT(kSVSBackwardBranch, 8)
+MTERP_CONSTANT(kSVSDebugInterp, 9)
+#endif
+#endif
+
+/* ClassStatus enumeration */
+MTERP_SIZEOF(sizeofClassStatus,         ClassStatus, MTERP_SMALL_ENUM)
+MTERP_CONSTANT(CLASS_INITIALIZED,   7)
+
+/* MethodType enumeration */
+MTERP_SIZEOF(sizeofMethodType,          MethodType, MTERP_SMALL_ENUM)
+MTERP_CONSTANT(METHOD_DIRECT,       1)
+MTERP_CONSTANT(METHOD_STATIC,       2)
+MTERP_CONSTANT(METHOD_VIRTUAL,      3)
+MTERP_CONSTANT(METHOD_INTERFACE,    4)
+
+/* ClassObject constants */
+MTERP_CONSTANT(ACC_PRIVATE,         0x0002)
+MTERP_CONSTANT(ACC_STATIC,          0x0008)
+MTERP_CONSTANT(ACC_NATIVE,          0x0100)
+MTERP_CONSTANT(ACC_INTERFACE,       0x0200)
+MTERP_CONSTANT(ACC_ABSTRACT,        0x0400)
+MTERP_CONSTANT(CLASS_ISFINALIZABLE, 1<<31)
+
+/* flags for dvmMalloc */
+MTERP_CONSTANT(ALLOC_DONT_TRACK,    0x01)
+
+/* for GC */
+MTERP_CONSTANT(GC_CARD_SHIFT, 7)
+
+/* opcode number */
+MTERP_CONSTANT(OP_MOVE_EXCEPTION,   0x0d)
+MTERP_CONSTANT(OP_INVOKE_DIRECT_RANGE, 0x76)
+MTERP_CONSTANT(OP_INVOKE_DIRECT_JUMBO, 0x124)
+
+/* flags for interpBreak */
+MTERP_CONSTANT(kSubModeNormal,          0x0000)
+MTERP_CONSTANT(kSubModeMethodTrace,     0x0001)
+MTERP_CONSTANT(kSubModeEmulatorTrace,   0x0002)
+MTERP_CONSTANT(kSubModeInstCounting,    0x0004)
+MTERP_CONSTANT(kSubModeDebuggerActive,  0x0008)
+MTERP_CONSTANT(kSubModeSuspendPending,  0x0010)
+MTERP_CONSTANT(kSubModeCallbackPending, 0x0020)
+MTERP_CONSTANT(kSubModeCountedStep,     0x0040)
+MTERP_CONSTANT(kSubModeJitTraceBuild,   0x4000)
+MTERP_CONSTANT(kSubModeJitSV,           0x8000)
+MTERP_CONSTANT(kSubModeDebugProfile,    0x000f)
+
+MTERP_CONSTANT(kInterpNoBreak,            0x00)
+MTERP_CONSTANT(kInterpSingleStep,         0x01)
+MTERP_CONSTANT(kInterpSafePoint,          0x02)
+
+MTERP_CONSTANT(DBG_METHOD_ENTRY,          0x04)
+MTERP_CONSTANT(DBG_METHOD_EXIT,           0x08)
diff --git a/vm/mterp/common/jit-config.h b/vm/mterp/common/jit-config.h
new file mode 100644
index 0000000..8cc32e3
--- /dev/null
+++ b/vm/mterp/common/jit-config.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if __ARM_ARCH_5TE__
+#define JIT_PROF_SIZE_LOG_2     9
+#else
+#define JIT_PROF_SIZE_LOG_2     11
+#endif
+
+#define JIT_PROF_SIZE           (1 << JIT_PROF_SIZE_LOG_2)
diff --git a/vm/mterp/config-allstubs b/vm/mterp/config-allstubs
new file mode 100644
index 0000000..9df7b12
--- /dev/null
+++ b/vm/mterp/config-allstubs
@@ -0,0 +1,47 @@
+# 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.
+
+#
+# Configuration for "allstubs" target.  This is structured like the
+# assembly interpreters, but consists entirely of C stubs, making it
+# a handy if inefficient way to exercise all of the C handlers.  The
+# handler-style command should match the target assembly interpreter.
+#
+
+#handler-style jump-table
+handler-style computed-goto
+handler-size 64
+
+# C file header and basic definitions
+import c/header.cpp
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# common defs for the C opcodes
+import c/opcommon.cpp
+
+# opcode list; argument to op-start is default directory
+op-start c
+    # use nothing but C stubs
+op-end
+
+# arch-specific entry point to interpreter
+import cstubs/entry.cpp
+
+# "helper" code
+import c/gotoTargets.cpp
+
+# finish
+import cstubs/enddefs.cpp
diff --git a/vm/mterp/config-armv5te b/vm/mterp/config-armv5te
new file mode 100644
index 0000000..2af5618
--- /dev/null
+++ b/vm/mterp/config-armv5te
@@ -0,0 +1,59 @@
+# 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.
+
+#
+# Configuration for ARMv5TE architecture targets.
+#
+
+handler-style computed-goto
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# source for alternate entry stub
+asm-alt-stub armv5te/alt_stub.S
+
+# file header and basic definitions
+import c/header.cpp
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# highly-platform-specific defs
+import armv5te/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.cpp
+
+# arch-specific entry point to interpreter
+import armv5te/entry.S
+
+# opcode list; argument to op-start is default directory
+op-start armv5te
+    #op OP_FILL_ARRAY_DATA c
+    alt OP_DISPATCH_FF 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.cpp
+
+# end of defs; include this when cstubs/stubdefs.cpp is included
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import armv5te/footer.S
+import armv5te/debug.cpp
diff --git a/vm/mterp/config-armv5te-vfp b/vm/mterp/config-armv5te-vfp
new file mode 100644
index 0000000..64e943a
--- /dev/null
+++ b/vm/mterp/config-armv5te-vfp
@@ -0,0 +1,110 @@
+# 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-style computed-goto
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# source for alternate entry stub
+asm-alt-stub armv5te/alt_stub.S
+
+# file header and basic definitions
+import c/header.cpp
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# highly-platform-specific defs
+import armv5te/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.cpp
+
+# 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
+
+    alt OP_DISPATCH_FF armv5te
+
+    # 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.cpp
+
+# end of defs; include this when cstubs/stubdefs.cpp is included
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import armv5te/footer.S
+import armv5te/debug.cpp
diff --git a/vm/mterp/config-armv7-a b/vm/mterp/config-armv7-a
new file mode 100644
index 0000000..5e41e63
--- /dev/null
+++ b/vm/mterp/config-armv7-a
@@ -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.
+
+#
+# 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-style computed-goto
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# source for alternate entry stub
+asm-alt-stub armv5te/alt_stub.S
+
+# file header and basic definitions
+import c/header.cpp
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# highly-platform-specific defs
+import armv7-a/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.cpp
+
+# 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
+
+    alt OP_DISPATCH_FF 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)
+#
+# Add this if you see linker failures for stuff like "dvmMterp_exceptionThrown".
+##import c/gotoTargets.cpp
+
+# end of defs; include this when cstubs/stubdefs.cpp is included
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import armv5te/footer.S
+import armv5te/debug.cpp
diff --git a/vm/mterp/config-armv7-a-neon b/vm/mterp/config-armv7-a-neon
new file mode 100644
index 0000000..fc98d96
--- /dev/null
+++ b/vm/mterp/config-armv7-a-neon
@@ -0,0 +1,172 @@
+# 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-style computed-goto
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# source for alternate entry stub
+asm-alt-stub armv5te/alt_stub.S
+
+# file header and basic definitions
+import c/header.cpp
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# highly-platform-specific defs
+import armv7-a/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.cpp
+
+# 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
+
+    alt OP_DISPATCH_FF 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.cpp
+
+# end of defs; include this when cstubs/stubdefs.cpp is included
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import armv5te/footer.S
+import armv5te/debug.cpp
diff --git a/vm/mterp/config-portable b/vm/mterp/config-portable
new file mode 100644
index 0000000..8f696b7
--- /dev/null
+++ b/vm/mterp/config-portable
@@ -0,0 +1,42 @@
+# 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.
+
+#
+# Configuration for the portable interpreter.
+#
+
+handler-style all-c
+
+# C file header and basic definitions
+import c/header.cpp
+
+# C pre-processor defines for stub C instructions
+import portable/stubdefs.cpp
+
+# common defs for the C opcodes
+import c/opcommon.cpp
+
+# entry point
+import portable/entry.cpp
+
+# opcode list; argument to op-start is default directory
+op-start c
+    # concatenate all C implementations
+op-end
+
+# "helper" code
+import c/gotoTargets.cpp
+
+# finish
+import portable/enddefs.cpp
diff --git a/vm/mterp/config-x86 b/vm/mterp/config-x86
new file mode 100644
index 0000000..9291e81
--- /dev/null
+++ b/vm/mterp/config-x86
@@ -0,0 +1,77 @@
+# 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.
+
+#
+# Configuration for "desktop" targets.
+#
+
+handler-style jump-table
+
+# source for the instruction table stub
+asm-stub x86/stub.S
+
+# source for alternate entry stub
+asm-alt-stub x86/alt_stub.S
+
+# C file header and basic definitions
+import c/header.cpp
+import x86/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.cpp
+
+# common defs for the C opcodes
+import c/opcommon.cpp
+
+# opcode list; argument to op-start is default directory
+op-start x86
+    # stub -- need native impl
+    op OP_EXECUTE_INLINE_RANGE c
+    op OP_IGET_WIDE_VOLATILE c
+    op OP_IPUT_WIDE_VOLATILE c
+    op OP_SGET_WIDE_VOLATILE c
+    op OP_SPUT_WIDE_VOLATILE c
+    op OP_RETURN_VOID_BARRIER c
+    op OP_INVOKE_OBJECT_INIT_RANGE c
+
+    op OP_INVOKE_OBJECT_INIT_JUMBO c
+    op OP_IGET_VOLATILE_JUMBO c
+    op OP_IPUT_VOLATILE_JUMBO c
+    op OP_SGET_VOLATILE_JUMBO c
+    op OP_SPUT_VOLATILE_JUMBO c
+    op OP_IGET_OBJECT_VOLATILE_JUMBO c
+    op OP_IPUT_OBJECT_VOLATILE_JUMBO c
+    op OP_SGET_OBJECT_VOLATILE_JUMBO c
+    op OP_SPUT_OBJECT_VOLATILE_JUMBO c
+    op OP_IGET_WIDE_VOLATILE_JUMBO c
+    op OP_IPUT_WIDE_VOLATILE_JUMBO c
+    op OP_SGET_WIDE_VOLATILE_JUMBO c
+    op OP_SPUT_WIDE_VOLATILE_JUMBO c
+
+    alt OP_DISPATCH_FF x86
+op-end
+
+# arch-specific entry point to interpreter
+import x86/entry.S
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+# (asm code is currently calling into dvmMterp_exceptionThrown)
+import c/gotoTargets.cpp
+
+# end of defs; include this when cstubs/stubdefs.cpp is included
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import x86/footer.S
diff --git a/vm/mterp/config-x86-atom b/vm/mterp/config-x86-atom
new file mode 100644
index 0000000..b99310d
--- /dev/null
+++ b/vm/mterp/config-x86-atom
@@ -0,0 +1,319 @@
+# 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.
+
+# Specifies the size of the assembly region in bytes
+handler-style computed-goto
+handler-size 64
+
+# source for the instruction table stub
+asm-stub x86-atom/stub.S
+
+# file header, macros and definitions
+import c/header.cpp
+import x86-atom/header.S
+
+# common defs for the C helper; include this before the instruction handlers
+import cstubs/stubdefs.cpp
+import c/opcommon.cpp
+
+# start of opcode list; command gives default directory location of instruction files
+op-start x86-atom
+
+#op OP_ADD_DOUBLE_2ADDR c
+#op OP_ADD_DOUBLE c
+#op OP_ADD_FLOAT_2ADDR c
+#op OP_ADD_FLOAT c
+#op OP_ADD_INT_2ADDR c
+#op OP_ADD_INT_LIT16 c
+#op OP_ADD_INT_LIT8 c
+#op OP_ADD_INT c
+#op OP_ADD_LONG_2ADDR c
+#op OP_ADD_LONG c
+#op OP_AGET_BOOLEAN c
+#op OP_AGET_BYTE c
+#op OP_AGET_CHAR c
+#op OP_AGET_OBJECT c
+#op OP_AGET c
+#op OP_AGET_SHORT c
+#op OP_AGET_WIDE c
+#op OP_AND_INT_2ADDR c
+#op OP_AND_INT_LIT16 c
+#op OP_AND_INT_LIT8 c
+#op OP_AND_INT c
+#op OP_AND_LONG_2ADDR c
+#op OP_AND_LONG c
+#op OP_APUT_BOOLEAN c
+#op OP_APUT_BYTE c
+#op OP_APUT_CHAR c
+#op OP_APUT_OBJECT c
+#op OP_APUT c
+#op OP_APUT_SHORT c
+#op OP_APUT_WIDE c
+#op OP_ARRAY_LENGTH c
+#op OP_CHECK_CAST c
+#op OP_CMPG_DOUBLE c
+#op OP_CMPG_FLOAT c
+#op OP_CMPL_DOUBLE c
+#op OP_CMPL_FLOAT c
+#op OP_CMP_LONG c
+#op OP_CONST_16 c
+#op OP_CONST_4 c
+#op OP_CONST_CLASS c
+#op OP_CONST_HIGH16 c
+#op OP_CONST c
+#op OP_CONST_STRING_JUMBO c
+#op OP_CONST_STRING c
+#op OP_CONST_WIDE_16 c
+#op OP_CONST_WIDE_32 c
+#op OP_CONST_WIDE_HIGH16 c
+#op OP_CONST_WIDE c
+#op OP_DIV_DOUBLE_2ADDR c
+#op OP_DIV_DOUBLE c
+#op OP_DIV_FLOAT_2ADDR c
+#op OP_DIV_FLOAT c
+#op OP_DIV_INT_2ADDR c
+#op OP_DIV_INT_LIT16 c
+#op OP_DIV_INT_LIT8 c
+#op OP_DIV_INT c
+#op OP_DIV_LONG_2ADDR c
+#op OP_DIV_LONG c
+#op OP_DOUBLE_TO_FLOAT c
+#op OP_DOUBLE_TO_INT c
+#op OP_DOUBLE_TO_LONG c
+#op OP_EXECUTE_INLINE c
+#op OP_FILL_ARRAY_DATA c
+#op OP_FILLED_NEW_ARRAY_RANGE c
+#op OP_FILLED_NEW_ARRAY c
+#op OP_FLOAT_TO_DOUBLE c
+#op OP_FLOAT_TO_INT c
+#op OP_FLOAT_TO_LONG c
+#op OP_GOTO_16 c
+#op OP_GOTO_32 c
+#op OP_GOTO c
+#op OP_IF_EQ c
+#op OP_IF_EQZ c
+#op OP_IF_GE c
+#op OP_IF_GEZ c
+#op OP_IF_GT c
+#op OP_IF_GTZ c
+#op OP_IF_LE c
+#op OP_IF_LEZ c
+#op OP_IF_LT c
+#op OP_IF_LTZ c
+#op OP_IF_NE c
+#op OP_IF_NEZ c
+#op OP_IGET_BOOLEAN c
+#op OP_IGET_BYTE c
+#op OP_IGET_CHAR c
+#op OP_IGET_OBJECT_QUICK c
+#op OP_IGET_OBJECT c
+#op OP_IGET_QUICK c
+#op OP_IGET c
+#op OP_IGET_SHORT c
+#op OP_IGET_WIDE_QUICK c
+#op OP_IGET_WIDE c
+#op OP_INSTANCE_OF c
+#op OP_INT_TO_BYTE c
+#op OP_INT_TO_CHAR c
+#op OP_INT_TO_DOUBLE c
+#op OP_INT_TO_FLOAT c
+#op OP_INT_TO_LONG c
+#op OP_INT_TO_SHORT c
+#op OP_INVOKE_DIRECT_EMPTY c
+#op OP_INVOKE_DIRECT_RANGE c
+#op OP_INVOKE_DIRECT c
+#op OP_INVOKE_INTERFACE_RANGE c
+#op OP_INVOKE_INTERFACE c
+#op OP_INVOKE_STATIC_RANGE c
+#op OP_INVOKE_STATIC c
+#op OP_INVOKE_SUPER_QUICK_RANGE c
+#op OP_INVOKE_SUPER_QUICK c
+#op OP_INVOKE_SUPER_RANGE c
+#op OP_INVOKE_SUPER c
+#op OP_INVOKE_VIRTUAL_QUICK_RANGE c
+#op OP_INVOKE_VIRTUAL_QUICK c
+#op OP_INVOKE_VIRTUAL_RANGE c
+#op OP_INVOKE_VIRTUAL c
+#op OP_IPUT_BOOLEAN c
+#op OP_IPUT_BYTE c
+#op OP_IPUT_CHAR c
+#op OP_IPUT_OBJECT_QUICK c
+#op OP_IPUT_OBJECT c
+#op OP_IPUT_QUICK c
+#op OP_IPUT c
+#op OP_IPUT_SHORT c
+#op OP_IPUT_WIDE_QUICK c
+#op OP_IPUT_WIDE c
+#op OP_LONG_TO_DOUBLE c
+#op OP_LONG_TO_FLOAT c
+#op OP_LONG_TO_INT c
+#op OP_MONITOR_ENTER c
+#op OP_MONITOR_EXIT c
+#op OP_MOVE_16 c
+#op OP_MOVE_EXCEPTION c
+#op OP_MOVE_FROM16 c
+#op OP_MOVE_OBJECT_16 c
+#op OP_MOVE_OBJECT_FROM16 c
+#op OP_MOVE_OBJECT c
+#op OP_MOVE_RESULT_OBJECT c
+#op OP_MOVE_RESULT c
+#op OP_MOVE_RESULT_WIDE c
+#op OP_MOVE c
+#op OP_MOVE_WIDE_16 c
+#op OP_MOVE_WIDE_FROM16 c
+#op OP_MOVE_WIDE c
+#op OP_MUL_DOUBLE_2ADDR c
+#op OP_MUL_DOUBLE c
+#op OP_MUL_FLOAT_2ADDR c
+#op OP_MUL_FLOAT c
+#op OP_MUL_INT_2ADDR c
+#op OP_MUL_INT_LIT16 c
+#op OP_MUL_INT_LIT8 c
+#op OP_MUL_INT c
+#op OP_MUL_LONG_2ADDR c
+#op OP_MUL_LONG c
+#op OP_NEG_DOUBLE c
+#op OP_NEG_FLOAT c
+#op OP_NEG_INT c
+#op OP_NEG_LONG c
+#op OP_NEW_ARRAY c
+#op OP_NEW_INSTANCE c
+#op OP_NOP c
+#op OP_NOT_INT c
+#op OP_NOT_LONG c
+#op OP_OR_INT_2ADDR c
+#op OP_OR_INT_LIT16 c
+#op OP_OR_INT_LIT8 c
+#op OP_OR_INT c
+#op OP_OR_LONG_2ADDR c
+#op OP_OR_LONG c
+#op OP_PACKED_SWITCH c
+#op OP_REM_DOUBLE_2ADDR c
+#op OP_REM_DOUBLE c
+#op OP_REM_FLOAT_2ADDR c
+#op OP_REM_FLOAT c
+#op OP_REM_INT_2ADDR c
+#op OP_REM_INT_LIT16 c
+#op OP_REM_INT_LIT8 c
+#op OP_REM_INT c
+#op OP_REM_LONG_2ADDR c
+#op OP_REM_LONG c
+#op OP_RETURN_OBJECT c
+#op OP_RETURN c
+#op OP_RETURN_VOID c
+#op OP_RETURN_WIDE c
+#op OP_RSUB_INT_LIT8 c
+#op OP_RSUB_INT c
+#op OP_SGET_BOOLEAN c
+#op OP_SGET_BYTE c
+#op OP_SGET_CHAR c
+#op OP_SGET_OBJECT c
+#op OP_SGET c
+#op OP_SGET_SHORT c
+#op OP_SGET_WIDE c
+#op OP_SHL_INT_2ADDR c
+#op OP_SHL_INT_LIT8 c
+#op OP_SHL_INT c
+#op OP_SHL_LONG_2ADDR c
+#op OP_SHL_LONG c
+#op OP_SHR_INT_2ADDR c
+#op OP_SHR_INT_LIT8 c
+#op OP_SHR_INT c
+#op OP_SHR_LONG_2ADDR c
+#op OP_SHR_LONG c
+#op OP_SPARSE_SWITCH c
+#op OP_SPUT_BOOLEAN c
+#op OP_SPUT_BYTE c
+#op OP_SPUT_CHAR c
+#op OP_SPUT_OBJECT c
+#op OP_SPUT c
+#op OP_SPUT_SHORT c
+#op OP_SPUT_WIDE c
+#op OP_SUB_DOUBLE_2ADDR c
+#op OP_SUB_DOUBLE c
+#op OP_SUB_FLOAT_2ADDR c
+#op OP_SUB_FLOAT c
+#op OP_SUB_INT_2ADDR c
+#op OP_SUB_INT c
+#op OP_SUB_LONG_2ADDR c
+#op OP_SUB_LONG c
+#op OP_THROW c
+#op OP_UNUSED_3E c
+#op OP_UNUSED_3F c
+#op OP_UNUSED_40 c
+#op OP_UNUSED_41 c
+#op OP_UNUSED_42 c
+#op OP_UNUSED_43 c
+#op OP_UNUSED_73 c
+#op OP_UNUSED_79 c
+#op OP_UNUSED_7A c
+#op OP_UNUSED_F1 c
+#op OP_UNUSED_FC c
+#op OP_UNUSED_FD c
+#op OP_UNUSED_FE c
+#op OP_DISPATCH_FF c
+#op OP_USHR_INT_2ADDR c
+#op OP_USHR_INT_LIT8 c
+#op OP_USHR_INT c
+#op OP_USHR_LONG_2ADDR c
+#op OP_USHR_LONG c
+#op OP_XOR_INT_2ADDR c
+#op OP_XOR_INT_LIT16 c
+#op OP_XOR_INT_LIT8 c
+#op OP_XOR_INT c
+#op OP_XOR_LONG_2ADDR c
+#op OP_XOR_LONG c
+
+# TODO: provide native implementations
+op OP_BREAKPOINT c
+op OP_EXECUTE_INLINE_RANGE c
+op OP_IGET_VOLATILE c
+op OP_IPUT_VOLATILE c
+op OP_SGET_VOLATILE c
+op OP_SPUT_VOLATILE c
+op OP_IGET_OBJECT_VOLATILE c
+op OP_IPUT_OBJECT_VOLATILE c
+op OP_SGET_OBJECT_VOLATILE c
+op OP_SPUT_OBJECT_VOLATILE c
+op OP_IGET_WIDE_VOLATILE c
+op OP_IPUT_WIDE_VOLATILE c
+op OP_SGET_WIDE_VOLATILE c
+op OP_SPUT_WIDE_VOLATILE c
+op OP_RETURN_VOID_BARRIER c
+op OP_INVOKE_OBJECT_INIT_RANGE c
+
+op OP_INVOKE_OBJECT_INIT_JUMBO c
+op OP_IGET_VOLATILE_JUMBO c
+op OP_IPUT_VOLATILE_JUMBO c
+op OP_SGET_VOLATILE_JUMBO c
+op OP_SPUT_VOLATILE_JUMBO c
+op OP_IGET_OBJECT_VOLATILE_JUMBO c
+op OP_IPUT_OBJECT_VOLATILE_JUMBO c
+op OP_SGET_OBJECT_VOLATILE_JUMBO c
+op OP_SPUT_OBJECT_VOLATILE_JUMBO c
+op OP_IGET_WIDE_VOLATILE_JUMBO c
+op OP_IPUT_WIDE_VOLATILE_JUMBO c
+op OP_SGET_WIDE_VOLATILE_JUMBO c
+op OP_SPUT_WIDE_VOLATILE_JUMBO c
+op-end
+
+# arch-specific entry point to interpreter
+import x86-atom/entry.S
+
+# "helper" code for C; include this after the instruction handlers
+import c/gotoTargets.cpp
+import cstubs/enddefs.cpp
+
+# common subroutines for asm
+import x86-atom/footer.S
diff --git a/vm/mterp/cstubs/enddefs.cpp b/vm/mterp/cstubs/enddefs.cpp
new file mode 100644
index 0000000..cac74bf
--- /dev/null
+++ b/vm/mterp/cstubs/enddefs.cpp
@@ -0,0 +1,9 @@
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
diff --git a/vm/mterp/cstubs/entry.cpp b/vm/mterp/cstubs/entry.cpp
new file mode 100644
index 0000000..350bd86
--- /dev/null
+++ b/vm/mterp/cstubs/entry.cpp
@@ -0,0 +1,61 @@
+/*
+ * Handler function table, one entry per opcode.
+ */
+#undef H
+#define H(_op) dvmMterp_##_op
+DEFINE_GOTO_TABLE(gDvmMterpHandlers)
+
+#undef H
+#define H(_op) #_op
+DEFINE_GOTO_TABLE(gDvmMterpHandlerNames)
+
+#include <setjmp.h>
+
+/*
+ * C mterp entry point.  This just calls the various C fallbacks, making
+ * this a slow but portable interpeter.
+ *
+ * This is only used for the "allstubs" variant.
+ */
+void dvmMterpStdRun(Thread* self)
+{
+    jmp_buf jmpBuf;
+
+    self->bailPtr = &jmpBuf;
+
+    /* We exit via a longjmp */
+    if (setjmp(jmpBuf)) {
+        LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
+        return
+    }
+
+    /* run until somebody longjmp()s out */
+    while (true) {
+        typedef void (*Handler)(Thread* self);
+
+        u2 inst = /*self->interpSave.*/pc[0];
+        /*
+         * In mterp, dvmCheckBefore is handled via the altHandlerTable,
+         * while in the portable interpreter it is part of the handler
+         * FINISH code.  For allstubs, we must do an explicit check
+         * in the interpretation loop.
+         */
+        if (self-interpBreak.ctl.subMode) {
+            dvmCheckBefore(pc, fp, self, curMethod);
+        }
+        Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
+        (void) gDvmMterpHandlerNames;   /* avoid gcc "defined but not used" */
+        LOGVV("handler %p %s",
+            handler, (const char*) gDvmMterpHandlerNames[inst & 0xff]);
+        (*handler)(self);
+    }
+}
+
+/*
+ * C mterp exit point.  Call here to bail out of the interpreter.
+ */
+void dvmMterpStdBail(Thread* self)
+{
+    jmp_buf* pJmpBuf = self->bailPtr;
+    longjmp(*pJmpBuf, 1);
+}
diff --git a/vm/mterp/cstubs/stubdefs.cpp b/vm/mterp/cstubs/stubdefs.cpp
new file mode 100644
index 0000000..0bffd49
--- /dev/null
+++ b/vm/mterp/cstubs/stubdefs.cpp
@@ -0,0 +1,134 @@
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
diff --git a/vm/mterp/gen-mterp.py b/vm/mterp/gen-mterp.py
new file mode 100755
index 0000000..e0b1b2d
--- /dev/null
+++ b/vm/mterp/gen-mterp.py
@@ -0,0 +1,619 @@
+#!/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 interpreter.
+#
+
+import sys, string, re, time
+from string import Template
+
+interp_defs_file = "../../libdex/DexOpcodes.h" # need opcode list
+kNumPackedOpcodes = 512 # TODO: Derive this from DexOpcodes.h.
+
+verbose = False
+handler_size_bits = -1000
+handler_size_bytes = -1000
+in_op_start = 0             # 0=not started, 1=started, 2=ended
+in_alt_op_start = 0         # 0=not started, 1=started, 2=ended
+default_op_dir = None
+default_alt_stub = None
+opcode_locations = {}
+alt_opcode_locations = {}
+asm_stub_text = []
+label_prefix = ".L"         # use ".L" to hide labels from gdb
+alt_label_prefix = ".L_ALT" # use ".L" to hide labels from gdb
+style = None                # interpreter style
+generate_alt_table = False
+
+# 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 interpreter style.
+#
+def setHandlerStyle(tokens):
+    global style
+    if len(tokens) != 2:
+        raise DataParseError("handler-style requires one argument")
+    style = tokens[1]
+    if style != "computed-goto" and style != "jump-table" and style != "all-c":
+        raise DataParseError("handler-style (%s) invalid" % style)
+
+#
+# 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 0 or
+# a power of two.
+#
+def setHandlerSize(tokens):
+    global handler_size_bits, handler_size_bytes
+    if style != "computed-goto":
+        print "Warning: handler-size valid only for computed-goto interpreters"
+    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 0 or 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" \
+                % 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(".cpp"):
+        appendSourceFile(tokens[1], getGlobalSubDict(), c_fp, None)
+    elif source.endswith(".S"):
+        appendSourceFile(tokens[1], getGlobalSubDict(), asm_fp, None)
+    else:
+        raise DataParseError("don't know how to import %s (expecting .cpp/.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 style == "all-c":
+        print "Warning: asm-stub ignored for all-c interpreter"
+    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 --
+# Record location of default alt stub
+#
+def setAsmAltStub(tokens):
+    global default_alt_stub, generate_alt_table
+    if style == "all-c":
+        print "Warning: asm-alt-stub ingored for all-c interpreter"
+    if len(tokens) != 2:
+        raise DataParseError("import requires one argument")
+    default_alt_stub = tokens[1]
+    generate_alt_table = True
+
+#
+# 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 alt opcode's source file.
+#
+def altEntry(tokens):
+    global generate_alt_table
+    if len(tokens) != 3:
+        raise DataParseError("alt requires exactly two arguments")
+    if in_op_start != 1:
+        raise DataParseError("alt statements must be between opStart/opEnd")
+    try:
+        index = opcodes.index(tokens[1])
+    except ValueError:
+        raise DataParseError("unknown opcode %s" % tokens[1])
+    if alt_opcode_locations.has_key(tokens[1]):
+        print "Note: alt overrides earlier %s (%s -> %s)" \
+                % (tokens[1], alt_opcode_locations[tokens[1]], tokens[2])
+    alt_opcode_locations[tokens[1]] = tokens[2]
+    generate_alt_table = True
+
+#
+# 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])
+    if opcode_locations.has_key(tokens[1]):
+        print "Note: op overrides earlier %s (%s -> %s)" \
+                % (tokens[1], opcode_locations[tokens[1]], tokens[2])
+    opcode_locations[tokens[1]] = tokens[2]
+
+#
+# Emit jump table
+#
+def emitJmpTable(start_label, prefix):
+    asm_fp.write("\n    .global %s\n" % start_label)
+    asm_fp.write("    .text\n")
+    asm_fp.write("%s:\n" % start_label)
+    for i in xrange(kNumPackedOpcodes):
+        op = opcodes[i]
+        dict = getGlobalSubDict()
+        dict.update({ "opcode":op, "opnum":i })
+        asm_fp.write("    .long " + prefix + \
+                     "_%(opcode)s /* 0x%(opnum)02x */\n" % dict)
+
+#
+# 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()
+
+    if generate_alt_table:
+        loadAndEmitAltOpcodes()
+        if style == "jump-table":
+            emitJmpTable("dvmAsmInstructionStart", label_prefix);
+            emitJmpTable("dvmAsmAltInstructionStart", alt_label_prefix);
+
+
+#
+# Extract an ordered list of instructions from the VM sources.  We use the
+# "goto table" definition macro, which has exactly kNumPackedOpcodes
+# entries.
+#
+def getOpcodeList():
+    opcodes = []
+    opcode_fp = open(interp_defs_file)
+    opcode_re = re.compile(r"^\s*H\(OP_(\w+)\),.*", re.DOTALL)
+    for line in opcode_fp:
+        match = opcode_re.match(line)
+        if not match:
+            continue
+        opcodes.append("OP_" + match.group(1))
+    opcode_fp.close()
+
+    if len(opcodes) != kNumPackedOpcodes:
+        print "ERROR: found %d opcodes in Interp.h (expected %d)" \
+                % (len(opcodes), kNumPackedOpcodes)
+        raise SyntaxError, "bad opcode count"
+    return opcodes
+
+def emitAlign():
+    if style == "computed-goto":
+        asm_fp.write("    .balign %d\n" % handler_size_bytes)
+
+#
+# Load and emit opcodes for all kNumPackedOpcodes instructions.
+#
+def loadAndEmitOpcodes():
+    sister_list = []
+    assert len(opcodes) == kNumPackedOpcodes
+    need_dummy_start = False
+    if style == "jump-table":
+        start_label = "dvmAsmInstructionStartCode"
+        end_label = "dvmAsmInstructionEndCode"
+    else:
+        start_label = "dvmAsmInstructionStart"
+        end_label = "dvmAsmInstructionEnd"
+
+    # point dvmAsmInstructionStart at the first handler or stub
+    asm_fp.write("\n    .global %s\n" % start_label)
+    asm_fp.write("    .type   %s, %%function\n" % start_label)
+    asm_fp.write("%s = " % start_label + label_prefix + "_OP_NOP\n")
+    asm_fp.write("    .text\n\n")
+
+    for i in xrange(kNumPackedOpcodes):
+        op = opcodes[i]
+
+        if opcode_locations.has_key(op):
+            location = opcode_locations[op]
+        else:
+            location = default_op_dir
+
+        if location == "c":
+            loadAndEmitC(location, i)
+            if len(asm_stub_text) == 0:
+                need_dummy_start = True
+        else:
+            loadAndEmitAsm(location, i, sister_list)
+
+    # For a 100% C implementation, there are no asm handlers or stubs.  We
+    # need to have the dvmAsmInstructionStart label point at OP_NOP, and it's
+    # too annoying to try to slide it in after the alignment psuedo-op, so
+    # we take the low road and just emit a dummy OP_NOP here.
+    if need_dummy_start:
+        emitAlign()
+        asm_fp.write(label_prefix + "_OP_NOP:   /* dummy */\n");
+
+    emitAlign()
+    asm_fp.write("    .size   %s, .-%s\n" % (start_label, start_label))
+    asm_fp.write("    .global %s\n" % end_label)
+    asm_fp.write("%s:\n" % end_label)
+
+    if style == "computed-goto":
+        emitSectionComment("Sister implementations", asm_fp)
+        asm_fp.write("    .global dvmAsmSisterStart\n")
+        asm_fp.write("    .type   dvmAsmSisterStart, %function\n")
+        asm_fp.write("    .text\n")
+        asm_fp.write("    .balign 4\n")
+        asm_fp.write("dvmAsmSisterStart:\n")
+        asm_fp.writelines(sister_list)
+
+        asm_fp.write("\n    .size   dvmAsmSisterStart, .-dvmAsmSisterStart\n")
+        asm_fp.write("    .global dvmAsmSisterEnd\n")
+        asm_fp.write("dvmAsmSisterEnd:\n\n")
+
+#
+# Load an alternate entry stub
+#
+def loadAndEmitAltStub(source, opindex):
+    op = opcodes[opindex]
+    if verbose:
+        print " alt emit %s --> stub" % source
+    dict = getGlobalSubDict()
+    dict.update({ "opcode":op, "opnum":opindex })
+
+    emitAsmHeader(asm_fp, dict, alt_label_prefix)
+    appendSourceFile(source, dict, asm_fp, None)
+
+#
+# Load and emit alternate opcodes for all kNumPackedOpcodes instructions.
+#
+def loadAndEmitAltOpcodes():
+    assert len(opcodes) == kNumPackedOpcodes
+    if style == "jump-table":
+        start_label = "dvmAsmAltInstructionStartCode"
+        end_label = "dvmAsmAltInstructionEndCode"
+    else:
+        start_label = "dvmAsmAltInstructionStart"
+        end_label = "dvmAsmAltInstructionEnd"
+
+    # point dvmAsmInstructionStart at the first handler or stub
+    asm_fp.write("\n    .global %s\n" % start_label)
+    asm_fp.write("    .type   %s, %%function\n" % start_label)
+    asm_fp.write("    .text\n\n")
+    asm_fp.write("%s = " % start_label + label_prefix + "_ALT_OP_NOP\n")
+
+    for i in xrange(kNumPackedOpcodes):
+        op = opcodes[i]
+        if alt_opcode_locations.has_key(op):
+            source = "%s/ALT_%s.S" % (alt_opcode_locations[op], op)
+        else:
+            source = default_alt_stub
+        loadAndEmitAltStub(source, i)
+
+    emitAlign()
+    asm_fp.write("    .size   %s, .-%s\n" % (start_label, start_label))
+    asm_fp.write("    .global %s\n" % end_label)
+    asm_fp.write("%s:\n" % end_label)
+
+#
+# Load a C fragment and emit it, then output an assembly stub.
+#
+def loadAndEmitC(location, opindex):
+    op = opcodes[opindex]
+    source = "%s/%s.cpp" % (location, op)
+    if verbose:
+        print " emit %s --> C++" % source
+    dict = getGlobalSubDict()
+    dict.update({ "opcode":op, "opnum":opindex })
+
+    appendSourceFile(source, dict, c_fp, None)
+
+    if len(asm_stub_text) != 0:
+        emitAsmStub(asm_fp, dict)
+
+#
+# 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 })
+    if verbose:
+        print " emit %s --> asm" % source
+
+    emitAsmHeader(asm_fp, dict, label_prefix)
+    appendSourceFile(source, dict, asm_fp, sister_list)
+
+#
+# Output the alignment directive and label for an assembly piece.
+#
+def emitAsmHeader(outfp, dict, prefix):
+    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.
+    emitAlign()
+    # 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.
+    outfp.write(prefix + "_%(opcode)s: /* 0x%(opnum)02x */\n" % dict)
+
+#
+# Output a generic instruction stub that updates the "glue" struct and
+# calls the C implementation.
+#
+def emitAsmStub(outfp, dict):
+    emitAsmHeader(outfp, dict, label_prefix)
+    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 style == "computed-goto" and 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:
+    c_fp = open("%s/InterpC-%s.cpp" % (output_dir, target_arch), "w")
+    asm_fp = open("%s/InterpAsm-%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, %s" % (c_fp.name, asm_fp.name)
+
+file_header = """/*
+ * This file was generated automatically by gen-mterp.py for '%s'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+""" % (target_arch)
+
+c_fp.write(file_header)
+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] == "asm-alt-stub":
+                setAsmAltStub(tokens)
+            elif tokens[0] == "op-start":
+                opStart(tokens)
+            elif tokens[0] == "op-end":
+                opEnd(tokens)
+            elif tokens[0] == "alt":
+                altEntry(tokens)
+            elif tokens[0] == "op":
+                opEntry(tokens)
+            elif tokens[0] == "handler-style":
+                setHandlerStyle(tokens)
+            else:
+                raise DataParseError, "unrecognized command '%s'" % tokens[0]
+            if style == None:
+                print "tokens[0] = %s" % tokens[0]
+                raise DataParseError, "handler-style must be first command"
+except DataParseError, err:
+    print "Failed: " + str(err)
+    # TODO: remove output files so "make" doesn't get confused
+    failed = True
+    c_fp.close()
+    asm_fp.close()
+    c_fp = asm_fp = None
+
+config_fp.close()
+
+#
+# Done!
+#
+if c_fp:
+    c_fp.close()
+if asm_fp:
+    asm_fp.close()
+
+sys.exit(failed)
diff --git a/vm/mterp/out/InterpAsm-allstubs.S b/vm/mterp/out/InterpAsm-allstubs.S
new file mode 100644
index 0000000..779fd5f
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-allstubs.S
@@ -0,0 +1,34 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'allstubs'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+
+    .global dvmAsmInstructionStart
+    .type   dvmAsmInstructionStart, %function
+dvmAsmInstructionStart = .L_OP_NOP
+    .text
+
+    .balign 64
+.L_OP_NOP:   /* dummy */
+    .balign 64
+    .size   dvmAsmInstructionStart, .-dvmAsmInstructionStart
+    .global dvmAsmInstructionEnd
+dvmAsmInstructionEnd:
+
+/*
+ * ===========================================================================
+ *  Sister implementations
+ * ===========================================================================
+ */
+    .global dvmAsmSisterStart
+    .type   dvmAsmSisterStart, %function
+    .text
+    .balign 4
+dvmAsmSisterStart:
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
new file mode 100644
index 0000000..a0835f9
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -0,0 +1,27480 @@
+/*
+ * 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  rSELF     self (Thread) 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 rSELF   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF()     ldr     rPC, [rSELF, #offThread_pc]
+#define SAVE_PC_TO_SELF()       str     rPC, [rSELF, #offThread_pc]
+#define LOAD_FP_FROM_SELF()     ldr     rFP, [rSELF, #offThread_curFrame]
+#define SAVE_FP_TO_SELF()       str     rFP, [rSELF, #offThread_curFrame]
+#define LOAD_PC_FP_FROM_SELF()  ldmia   rSELF, {rPC, rFP}
+#define SAVE_PC_FP_TO_SELF()    stmia   rSELF, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects.  Must
+ * be done *before* something throws.
+ *
+ * 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 #1]!", 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_BASE(_base,_reg)  add     pc, _base, _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]
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+/* File: armv5te/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro  SMP_DMB
+.endm
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro  SMP_DMB_ST
+.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  Thread* self
+ *
+ * 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, #offThread_bailPtr]  @ save SP for eventual return
+
+    /* set up "named" registers, figure out entry point */
+    mov     rSELF, r0                   @ set rSELF
+    LOAD_PC_FP_FROM_SELF()              @ load rPC and rFP from "thread"
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable] @ set rIBASE
+
+#if defined(WITH_JIT)
+.LentryInstr:
+    /* Entry is always a possible trace start */
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [rSELF, #offThread_shadowSpace] @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    /* 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
+
+.Lbad_arg:
+    ldr     r0, strBadEntryPoint
+    @ r1 holds value of entryPoint
+    bl      printf
+    bl      dvmAbort
+    .fnend
+    .size   dvmMterpStdRun, .-dvmMterpStdRun
+
+
+    .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  Thread* self
+ */
+dvmMterpStdBail:
+    ldr     sp, [r0, #offThread_bailPtr]    @ sp<- saved SP
+    add     sp, sp, #4                      @ un-align 64
+    ldmfd   sp!, {r4-r10,fp,pc}             @ 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, [rSELF, #offThread_retval]    @ r0<- self->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, rSELF, #offThread_retval  @ r3<- &self->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, [rSELF, #offThread_retval]    @ r0<- self->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 */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    ldr     r3, [rSELF, #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, [rSELF, #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 "thread"
+     * 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, [rSELF, #offThread_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 "thread"
+     * 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, rSELF, #offThread_retval  @ r3<- &self->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 "thread"
+     * 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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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)
+    mov     r0, rSELF                   @ r0<- self
+    cmp     r1, #0                      @ null object?
+    EXPORT_PC()                         @ need for precise GC
+    beq     common_errNullObject        @ null object, throw an exception
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      dvmLockObject               @ call(self, obj)
+    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     1f                          @ yes
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
+    cmp     r0, #0                      @ failed?
+    FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    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, [rSELF, #offThread_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 - len in r1
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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)
+    EXPORT_PC()                         @ exception handler can throw
+    cmp     r1, #0                      @ null object?
+    beq     common_errNullObject        @ yes, throw an NPE instead
+    @ bypass dvmSetException, just store it
+    str     r1, [rSELF, #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 */
+    /* tuning: use sbfx for 6t2+ targets */
+    mov     r0, rINST, lsl #16          @ r0<- AAxx0000
+    movs    r1, r0, asr #24             @ r1<- ssssssAA (sign-extended)
+    add     r2, r1, r1                  @ r2<- byte offset, set flags
+       @ If backwards branch refresh rIBASE
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) check for trace hotness
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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)
+    adds    r1, r0, r0                  @ r1<- byte offset, flags set
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) hot trace head?
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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".  Because
+     * we need the V bit set, we'll use an adds to convert from Dalvik
+     * offset to byte offset.
+     */
+    /* goto/32 +AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    orr     r0, r0, r1, lsl #16         @ r0<- AAAAaaaa
+    adds    r1, r0, r0                  @ r1<- byte offset
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ble     common_testUpdateProfile    @ (r0) hot trace head?
+#else
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movne r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    moveq r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movge r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movlt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movle r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movgt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movne r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    moveq r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movge r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movlt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movle r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movgt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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.
+     */
+    /* 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(rINST, r2)                 @ rINST<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     rINST, #0                   @ null array object?
+    GET_VREG(r9, r9)                    @ r9<- vAA
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [rINST, #offArrayObject_length]   @ r3<- arrayObj->length
+    add     r10, rINST, r1, lsl #2      @ r10<- arrayObj + index*width
+    cmp     r1, 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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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 */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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     r9, rINST, lsr #8           @ r9<- AA
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_end
+
+/* ------------------------------ */
+    .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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodNoRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodNoRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_resolve
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_RANGE_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_RANGE_resolve
+
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+    /*
+     * Wide 32-bit instance field get.
+     */
+    /* iget-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_WIDE_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+    /* iput-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+    /*
+     * 64-bit SGET handler.
+     */
+    /* sget-wide vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+    /*
+     * 64-bit SPUT handler.
+     */
+    /* sput-wide vAA, field@BBBB */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/OP_BREAKPOINT.S */
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.
+     */
+    mov     r0, rPC
+    bl      dvmGetOriginalOpcode        @ (rPC)
+    FETCH(rINST, 0)                     @ reload OP_BREAKPOINT + rest of inst
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    and     rINST, #0xff00
+    orr     rINST, rINST, r0
+    GOTO_OPCODE_BASE(r1, r0)
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_method]    @ r0<- self->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 an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     *
+     * TUNING: could maintain two tables, pointer in Thread and
+     * swap if profiler/debuggger active.
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->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_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */
+    /*
+     * Execute a "native inline" instruction, using "/range" semantics.
+     * Same idea as execute-inline, but we get the args differently.
+     *
+     * We need to call an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     */
+    /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_RANGE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_RANGE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_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_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 2)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_RANGE_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(2+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/OP_RETURN_VOID_BARRIER.S */
+    SMP_DMB_ST
+    b       common_returnFromMethod
+
+/* ------------------------------ */
+    .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(ip, 1)                        @ ip<- 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, ip]                @ 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 */
+    /* 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 */
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card based on obj head
+    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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/OP_DISPATCH_FF.S */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/OP_CONST_CLASS_JUMBO.S */
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<-self>methodClassDex
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]   @ r2<- dvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResClasses[AAAAaaaa]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .LOP_CONST_CLASS_JUMBO_resolve
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/OP_CHECK_CAST_JUMBO.S */
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r3, 3)                        @ r3<- BBBB
+    orr     r2, r0, r2, lsl #16         @ r2<- AAAAaaaa
+    GET_VREG(r9, r3)                    @ r9<- object
+    ldr     r0, [rSELF, #offThread_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .LOP_CHECK_CAST_JUMBO_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_JUMBO_resolve         @ not resolved, do it now
+.LOP_CHECK_CAST_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .LOP_CHECK_CAST_JUMBO_fullcheck       @ no, do full check
+    b       .LOP_CHECK_CAST_JUMBO_okay            @ yes, finish up
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/OP_INSTANCE_OF_JUMBO.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.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_INSTANCE_OF.S.
+     */
+    /* instance-of/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    FETCH(r9, 3)                        @ r9<- vBBBB
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- pDvmDex
+    cmp     r0, #0                      @ is object null?
+    beq     .LOP_INSTANCE_OF_JUMBO_store           @ null obj, not an instance, store r0
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]    @ r2<- pDvmDex->pResClasses
+    orr     r3, r1, r3, lsl #16         @ r3<- AAAAaaaa
+    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_JUMBO_resolve         @ not resolved, do it now
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/OP_NEW_INSTANCE_JUMBO.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .LOP_NEW_INSTANCE_JUMBO_resolve         @ no, resolve it now
+.LOP_NEW_INSTANCE_JUMBO_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .LOP_NEW_INSTANCE_JUMBO_needinit        @ no, init class now
+.LOP_NEW_INSTANCE_JUMBO_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .LOP_NEW_INSTANCE_JUMBO_finish          @ continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/OP_NEW_ARRAY_JUMBO.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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r2, 1)                        @ r2<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- vCCCC
+    orr     r2, r2, r3, lsl #16         @ r2<- AAAAaaaa
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    GET_VREG(r1, r0)                    @ r1<- vCCCC (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 - len in r1
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .LOP_NEW_ARRAY_JUMBO_finish          @ resolved, continue
+    b       .LOP_NEW_ARRAY_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S */
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_FILLED_NEW_ARRAY.S.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    EXPORT_PC()                         @ need for resolve and alloc
+    cmp     r0, #0                      @ already resolved?
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_continue        @ yes, continue on
+8:  ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/OP_IGET_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrb", "sqnum":"1" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/OP_IGET_BYTE_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsb", "sqnum":"2" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/OP_IGET_CHAR_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrh", "sqnum":"3" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/OP_IGET_SHORT_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsh", "sqnum":"4" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    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_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/OP_IPUT_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/OP_IPUT_BYTE_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/OP_IPUT_CHAR_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/OP_IPUT_SHORT_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/OP_SGET_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BOOLEAN_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/OP_SGET_BYTE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BYTE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/OP_SGET_CHAR_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_CHAR_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/OP_SGET_SHORT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_SHORT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_JUMBO_end
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/OP_SPUT_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BOOLEAN_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/OP_SPUT_BYTE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BYTE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/OP_SPUT_CHAR_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_CHAR_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/OP_SPUT_SHORT_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_SHORT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_JUMBO.S */
+    /*
+     * Handle a virtual method call.
+     */
+    /* invoke-virtual/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_VIRTUAL_JUMBO_continue        @ yes, continue on
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/OP_INVOKE_SUPER_JUMBO.S */
+    /*
+     * Handle a "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_SUPER_JUMBO_continue        @ resolved, continue on
+    b       .LOP_INVOKE_SUPER_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/OP_INVOKE_DIRECT_JUMBO.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.)
+     *
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_JUMBO_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_JUMBO_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodJumbo    @ (r0=method, r9="this")
+    b       common_errNullObject        @ yes, throw exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/OP_INVOKE_STATIC_JUMBO.S */
+    /*
+     * Handle a static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodJumboNoThis   @ (r0=method)
+    b       .LOP_INVOKE_STATIC_JUMBO_resolve
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/OP_INVOKE_INTERFACE_JUMBO.S */
+    /*
+     * Handle an interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r2, 4)                        @ r2<- CCCC
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    EXPORT_PC()                         @ must export for invoke
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/OP_UNUSED_27FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/OP_UNUSED_28FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/OP_UNUSED_29FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/OP_UNUSED_2AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/OP_UNUSED_2BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/OP_UNUSED_2CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/OP_UNUSED_2DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/OP_UNUSED_2EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/OP_UNUSED_2FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/OP_UNUSED_30FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/OP_UNUSED_31FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/OP_UNUSED_32FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/OP_UNUSED_33FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/OP_UNUSED_34FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/OP_UNUSED_35FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/OP_UNUSED_36FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/OP_UNUSED_37FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/OP_UNUSED_38FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/OP_UNUSED_39FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/OP_UNUSED_3AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/OP_UNUSED_3BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/OP_UNUSED_3CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/OP_UNUSED_3DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/OP_UNUSED_3EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/OP_UNUSED_3FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/OP_UNUSED_40FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/OP_UNUSED_41FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/OP_UNUSED_42FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/OP_UNUSED_43FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/OP_UNUSED_44FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/OP_UNUSED_45FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/OP_UNUSED_46FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/OP_UNUSED_47FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/OP_UNUSED_48FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/OP_UNUSED_49FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/OP_UNUSED_4AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/OP_UNUSED_4BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/OP_UNUSED_4CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/OP_UNUSED_4DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/OP_UNUSED_4EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/OP_UNUSED_4FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/OP_UNUSED_50FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/OP_UNUSED_51FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/OP_UNUSED_52FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/OP_UNUSED_53FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/OP_UNUSED_54FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/OP_UNUSED_55FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/OP_UNUSED_56FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/OP_UNUSED_57FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/OP_UNUSED_58FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/OP_UNUSED_59FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/OP_UNUSED_5AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/OP_UNUSED_5BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/OP_UNUSED_5CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/OP_UNUSED_5DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/OP_UNUSED_5EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/OP_UNUSED_5FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/OP_UNUSED_60FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/OP_UNUSED_61FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/OP_UNUSED_62FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/OP_UNUSED_63FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/OP_UNUSED_64FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/OP_UNUSED_65FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/OP_UNUSED_66FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/OP_UNUSED_67FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/OP_UNUSED_68FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/OP_UNUSED_69FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/OP_UNUSED_6AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/OP_UNUSED_6BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/OP_UNUSED_6CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/OP_UNUSED_6DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/OP_UNUSED_6EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/OP_UNUSED_6FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/OP_UNUSED_70FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/OP_UNUSED_71FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/OP_UNUSED_72FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/OP_UNUSED_73FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/OP_UNUSED_74FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/OP_UNUSED_75FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/OP_UNUSED_76FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/OP_UNUSED_77FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/OP_UNUSED_78FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/OP_UNUSED_79FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/OP_UNUSED_7AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/OP_UNUSED_7BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/OP_UNUSED_7CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/OP_UNUSED_7DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/OP_UNUSED_7EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/OP_UNUSED_7FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/OP_UNUSED_80FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/OP_UNUSED_81FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/OP_UNUSED_82FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/OP_UNUSED_83FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/OP_UNUSED_84FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/OP_UNUSED_85FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/OP_UNUSED_86FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/OP_UNUSED_87FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/OP_UNUSED_88FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/OP_UNUSED_89FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/OP_UNUSED_8AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/OP_UNUSED_8BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/OP_UNUSED_8CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/OP_UNUSED_8DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/OP_UNUSED_8EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/OP_UNUSED_8FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/OP_UNUSED_90FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/OP_UNUSED_91FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/OP_UNUSED_92FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/OP_UNUSED_93FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/OP_UNUSED_94FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/OP_UNUSED_95FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/OP_UNUSED_96FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/OP_UNUSED_97FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/OP_UNUSED_98FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/OP_UNUSED_99FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/OP_UNUSED_9AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/OP_UNUSED_9BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/OP_UNUSED_9CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/OP_UNUSED_9DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/OP_UNUSED_9EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/OP_UNUSED_9FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/OP_UNUSED_A0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/OP_UNUSED_A1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/OP_UNUSED_A2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/OP_UNUSED_A3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/OP_UNUSED_A4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/OP_UNUSED_A5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/OP_UNUSED_A6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/OP_UNUSED_A7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/OP_UNUSED_A8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/OP_UNUSED_A9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/OP_UNUSED_AAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/OP_UNUSED_ABFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/OP_UNUSED_ACFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/OP_UNUSED_ADFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/OP_UNUSED_AEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/OP_UNUSED_AFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/OP_UNUSED_B0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/OP_UNUSED_B1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/OP_UNUSED_B2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/OP_UNUSED_B3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/OP_UNUSED_B4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/OP_UNUSED_B5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/OP_UNUSED_B6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/OP_UNUSED_B7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/OP_UNUSED_B8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/OP_UNUSED_B9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/OP_UNUSED_BAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/OP_UNUSED_BBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/OP_UNUSED_BCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/OP_UNUSED_BDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/OP_UNUSED_BEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/OP_UNUSED_BFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/OP_UNUSED_C0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/OP_UNUSED_C1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/OP_UNUSED_C2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/OP_UNUSED_C3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/OP_UNUSED_C4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/OP_UNUSED_C5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/OP_UNUSED_C6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/OP_UNUSED_C7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/OP_UNUSED_C8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/OP_UNUSED_C9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/OP_UNUSED_CAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/OP_UNUSED_CBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/OP_UNUSED_CCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/OP_UNUSED_CDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/OP_UNUSED_CEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/OP_UNUSED_CFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/OP_UNUSED_D0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/OP_UNUSED_D1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/OP_UNUSED_D2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/OP_UNUSED_D3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/OP_UNUSED_D4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/OP_UNUSED_D5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/OP_UNUSED_D6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/OP_UNUSED_D7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/OP_UNUSED_D8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/OP_UNUSED_D9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/OP_UNUSED_DAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/OP_UNUSED_DBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/OP_UNUSED_DCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/OP_UNUSED_DDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/OP_UNUSED_DEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/OP_UNUSED_DFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/OP_UNUSED_E0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/OP_UNUSED_E1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/OP_UNUSED_E2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/OP_UNUSED_E3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/OP_UNUSED_E4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/OP_UNUSED_E5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/OP_UNUSED_E6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/OP_UNUSED_E7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/OP_UNUSED_E8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/OP_UNUSED_E9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/OP_UNUSED_EAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/OP_UNUSED_EBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/OP_UNUSED_ECFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/OP_UNUSED_EDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/OP_UNUSED_EEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/OP_UNUSED_EFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/OP_UNUSED_F0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/OP_UNUSED_F1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 4)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_JUMBO_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(4+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/OP_IGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/OP_IPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/OP_SGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/OP_SPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR_JUMBO.S */
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, Class@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    orr     r2, r1, r2, lsl #16         @ r2<- AAAAaaaa
+    EXPORT_PC()                         @ export the PC
+    FETCH(r1, 3)                        @ r1<- BBBB
+    bl      dvmThrowVerificationError   @ always throws
+    b       common_exceptionThrown      @ handle exception
+
+    .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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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 desired class resolved from BBBB
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    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.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method]    @ r0<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_end:
+    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
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * 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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method] @ r3<- self->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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     0
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     1
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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:
+     *  rINST = 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, [rINST, #offObject_clazz]  @ r1<- arrayObj->clazz
+    bl      dvmCanPutArrayElement       @ test object type vs. array type
+    cmp     r0, #0                      @ okay?
+    beq     .LOP_APUT_OBJECT_throw           @ no
+    mov     r1, rINST                   @ r1<- arrayObj
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rSELF, #offThread_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r1, lsr #GC_CARD_SHIFT] @ mark card using object head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_skip_check:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_throw:
+    @ The types don't match.  We need to throw an ArrayStoreException.
+    ldr     r0, [r9, #offObject_clazz]
+    ldr     r1, [rINST, #offObject_clazz]
+    EXPORT_PC()
+    bl      dvmThrowArrayStoreExceptionIncompatibleElement
+    b       common_exceptionThrown
+
+/* 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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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
+    .if     0
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT */
+
+    /*
+     * 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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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(r10)                @ extract opcode from rINST
+    .if     0
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT */
+
+    /*
+     * 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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+    /*
+     * 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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_finish
+
+/* continuation for OP_SGET_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_finish          @ resume
+
+/* continuation for OP_SGET_OBJECT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_finish
+
+/* continuation for OP_SGET_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_finish
+
+/* continuation for OP_SGET_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_finish
+
+/* continuation for OP_SGET_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_finish
+
+/* continuation for OP_SGET_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_finish
+
+/* continuation for OP_SPUT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT */
+
+
+.LOP_SPUT_OBJECT_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_finish          @ resume
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodNoRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC */
+
+
+.LOP_INVOKE_STATIC_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodNoRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodNoRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodNoRange     @ whew, finally!
+#else
+    bne     common_invokeMethodNoRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_RANGE_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_RANGE_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_RANGE */
+
+
+.LOP_INVOKE_STATIC_RANGE_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodRange     @ whew, finally!
+#else
+    bne     common_invokeMethodRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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_IGET_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_finish
+
+/* continuation for OP_SPUT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_finish          @ resume
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    cmp     r9, #0                      @ check object for null
+    and     r2, r2, #15                 @ r2<- A
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[A]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_VOLATILE_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_finish          @ resume
+
+/* 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(rINST, 2)                     @ rINST<- FEDC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  and     ip, rINST, #0xf000          @ isolate F
+    ldr     r3, [rFP, ip, lsr #10]      @ r3<- vF (shift right 12, left 2)
+3:  and     ip, rINST, #0x0f00          @ isolate E
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vE
+2:  and     ip, rINST, #0x00f0          @ isolate D
+    ldr     r1, [rFP, ip, lsr #2]       @ r1<- vD
+1:  and     ip, rINST, #0x000f          @ isolate C
+    ldr     r0, [rFP, ip, lsl #2]       @ r0<- vC
+0:
+    ldr     rINST, .LOP_EXECUTE_INLINE_table    @ table of InlineOperation
+    ldr     pc, [rINST, r10, lsl #4]    @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_continue        @ make call; will return after
+    mov     rINST, r0                   @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, r9                      @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit @ (method, self)
+    cmp     rINST, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_table:
+    .word   gDvmInlineOpsTable
+
+/* continuation for OP_EXECUTE_INLINE_RANGE */
+
+    /*
+     * 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]
+     */
+.LOP_EXECUTE_INLINE_RANGE_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(r9, 2)                        @ r9<- CCCC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  add     ip, r9, #3                  @ base+3
+    GET_VREG(r3, ip)                    @ r3<- vBase[3]
+3:  add     ip, r9, #2                  @ base+2
+    GET_VREG(r2, ip)                    @ r2<- vBase[2]
+2:  add     ip, r9, #1                  @ base+1
+    GET_VREG(r1, ip)                    @ r1<- vBase[1]
+1:  add     ip, r9, #0                  @ (nop)
+    GET_VREG(r0, ip)                    @ r0<- vBase[0]
+0:
+    ldr     r9, .LOP_EXECUTE_INLINE_RANGE_table       @ table of InlineOperation
+    ldr     pc, [r9, r10, lsl #4]       @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_RANGE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_RANGE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- B
+    mov     rINST, r9                   @ rINST<- method
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_continue        @ make call; will return after
+    mov     r9, r0                      @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, rINST                   @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit  @ (method, self)
+    cmp     r9, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_RANGE_table:
+    .word   gDvmInlineOpsTable
+
+
+/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
+
+.LOP_INVOKE_OBJECT_INIT_RANGE_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_RANGE_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_RANGE_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 0
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_finish
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_finish          @ resume
+
+
+/* continuation for OP_CONST_CLASS_JUMBO */
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: AAAAAAAA (Class ref)
+     *  r9: target register
+     */
+.LOP_CONST_CLASS_JUMBO_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_CHECK_CAST_JUMBO */
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds desired class resolved from AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .LOP_CHECK_CAST_JUMBO_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    b       common_exceptionThrown
+
+    /*
+     * Advance PC and get the next opcode.
+     */
+.LOP_CHECK_CAST_JUMBO_okay:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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 AAAAAAAA
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_CHECK_CAST_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_INSTANCE_OF_JUMBO */
+
+    /*
+     * Class resolved, determine type of check necessary.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .LOP_INSTANCE_OF_JUMBO_trivial         @ yes, trivial finish
+    @ fall through to OP_INSTANCE_OF_JUMBO_fullcheck
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to OP_INSTANCE_OF_JUMBO_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_store:
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b OP_INSTANCE_OF_JUMBO_store, but copying is faster and cheaper
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- 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 AAAAAAAA
+     *  r9 holds BBBB
+     */
+
+.LOP_INSTANCE_OF_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    mov     r1, r3                      @ r1<- AAAAAAAA
+    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
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    mov     r1, r0                      @ r1<- class resolved from AAAAAAAA
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_NEW_INSTANCE_JUMBO */
+
+    .balign 32                          @ minimize cache lines
+.LOP_NEW_INSTANCE_JUMBO_finish: @ r0=new object
+    FETCH(r3, 3)                        @ r3<- BBBB
+    cmp     r0, #0                      @ failed?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_JUMBO_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_JUMBO_end:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_JUMBO_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.LOP_NEW_INSTANCE_JUMBO_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_JUMBO_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds AAAAAAAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_NEW_ARRAY_JUMBO */
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref AAAAAAAA
+     */
+.LOP_NEW_ARRAY_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r9, r1                      @ r9<- length (save)
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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_JUMBO_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.LOP_NEW_ARRAY_JUMBO_finish:
+    mov     r2, #ALLOC_DONT_TRACK       @ don't track in local refs table
+    bl      dvmAllocArrayByClass        @ r0<- call(clazz, length, flags)
+    cmp     r0, #0                      @ failed?
+    FETCH(r2, 3)                        @ r2<- vBBBB
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_FILLED_NEW_ARRAY_JUMBO */
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    FETCH(r1, 3)                        @ r1<- BBBB (length)
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_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, 4)                        @ r1<- CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(5)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC, r9=BBBB (length)
+    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
+
+2:  ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    GOTO_OPCODE(ip)                          @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_notimpl:
+    ldr     r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* continuation for OP_IGET_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     0
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     0
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_finish:
+    @bl      common_squeak1
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_finish:
+    @bl      common_squeak2
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_finish:
+    @bl      common_squeak3
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_finish:
+    @bl      common_squeak4
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_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_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_JUMBO */
+
+
+.LOP_SPUT_OBJECT_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_JUMBO_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_INVOKE_VIRTUAL_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     */
+.LOP_INVOKE_VIRTUAL_JUMBO_continue:
+    FETCH(r10, 4)                       @ r10<- CCCC
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_JUMBO_continue:
+    ldr     r1, [r10, #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_JUMBO_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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+.LOP_INVOKE_SUPER_JUMBO_resolve:
+    mov     r0, r10                     @ 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_JUMBO_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_JUMBO_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
+
+/* continuation for OP_INVOKE_DIRECT_JUMBO */
+
+    /*
+     * On entry:
+     *  r1 = reference (CCCC)
+     *  r10 = "this" register
+     */
+.LOP_INVOKE_DIRECT_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_JUMBO_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_JUMBO */
+
+
+.LOP_INVOKE_STATIC_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodJumboNoThis    @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodJumboNoThis    @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodJumboNoThis    @ whew, finally!
+#else
+    bne     common_invokeMethodJumboNoThis    @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* continuation for OP_INVOKE_OBJECT_INIT_JUMBO */
+
+.LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_JUMBO_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_JUMBO_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 1
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IGET_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_WIDE_VOLATILE_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE_JUMBO */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+
+    .global dvmAsmAltInstructionStart
+    .type   dvmAsmAltInstructionStart, %function
+    .text
+
+dvmAsmAltInstructionStart = .L_ALT_OP_NOP
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOP: /* 0x00 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (0 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE: /* 0x01 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (1 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (2 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (3 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (4 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (5 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (6 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (7 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (8 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (9 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (10 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (11 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (12 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (13 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID: /* 0x0e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (14 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN: /* 0x0f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (15 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (16 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (17 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_4: /* 0x12 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (18 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_16: /* 0x13 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (19 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST: /* 0x14 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (20 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (21 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (22 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (23 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (24 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (25 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (26 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (27 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (28 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (29 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (30 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST: /* 0x1f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (31 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (32 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (33 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (34 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (35 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (36 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (37 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (38 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW: /* 0x27 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (39 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO: /* 0x28 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (40 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (41 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (42 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (43 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (44 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_FLOAT: /* 0x2d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (45 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_FLOAT: /* 0x2e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (46 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (47 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (48 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (49 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQ: /* 0x32 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (50 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NE: /* 0x33 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (51 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LT: /* 0x34 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (52 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GE: /* 0x35 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (53 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GT: /* 0x36 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (54 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LE: /* 0x37 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (55 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (56 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (57 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (58 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (59 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (60 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (61 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (62 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (63 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (64 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (65 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (66 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (67 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET: /* 0x44 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (68 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (69 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (70 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (71 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (72 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (73 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (74 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT: /* 0x4b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (75 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (76 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (77 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (78 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (79 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (80 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (81 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET: /* 0x52 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (82 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE: /* 0x53 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (83 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (84 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (85 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (86 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (87 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (88 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT: /* 0x59 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (89 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE: /* 0x5a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (90 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (91 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (92 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (93 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (94 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (95 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET: /* 0x60 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (96 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE: /* 0x61 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (97 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (98 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (99 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE: /* 0x64 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (100 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR: /* 0x65 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (101 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT: /* 0x66 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (102 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT: /* 0x67 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (103 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (104 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (105 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (106 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (107 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (108 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (109 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (110 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (111 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (112 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (113 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (114 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (115 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (116 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (117 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (118 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (119 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (120 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (121 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (122 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_INT: /* 0x7b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (123 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_INT: /* 0x7c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (124 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_LONG: /* 0x7d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (125 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_LONG: /* 0x7e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (126 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (127 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (128 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (129 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (130 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (131 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (132 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (133 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (134 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (135 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (136 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (137 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (138 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (139 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (140 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (141 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (142 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (143 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (144 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (145 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (146 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (147 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT: /* 0x94 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (148 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT: /* 0x95 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (149 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT: /* 0x96 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (150 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (151 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (152 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (153 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (154 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (155 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (156 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (157 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (158 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (159 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (160 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (161 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (162 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (163 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (164 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (165 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT: /* 0xa6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (166 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT: /* 0xa7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (167 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT: /* 0xa8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (168 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT: /* 0xa9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (169 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (170 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE: /* 0xab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (171 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE: /* 0xac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (172 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE: /* 0xad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (173 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE: /* 0xae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (174 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (175 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (176 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (177 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (178 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (179 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (180 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (181 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (182 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (183 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (184 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (185 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (186 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (187 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (188 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (189 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (190 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (191 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (192 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (193 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (194 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (195 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (196 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (197 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (198 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (199 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (200 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (201 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (202 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (203 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (204 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (205 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (206 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (207 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (208 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT: /* 0xd1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (209 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (210 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (211 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (212 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (213 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (214 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (215 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (216 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (217 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (218 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (219 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (220 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (221 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (222 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (223 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (224 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (225 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (226 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (227 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (228 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (229 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (230 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (231 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (232 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (233 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (234 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (235 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (236 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (237 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (238 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (239 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (240 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (241 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (242 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (243 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (244 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_QUICK: /* 0xf5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (245 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (246 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (247 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (248 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (249 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (250 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (251 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (252 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (253 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (254 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/ALT_OP_DISPATCH_FF.S */
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (256 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (257 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (258 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (259 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (260 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (261 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (262 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (263 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (264 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (265 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (266 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (267 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (268 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (269 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (270 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (271 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (272 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (273 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (274 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (275 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (276 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (277 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (278 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (279 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (280 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (281 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (282 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (283 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (284 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (285 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (286 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (287 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (288 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (289 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (290 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (291 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (292 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (293 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (294 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (295 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (296 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (297 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (298 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (299 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (300 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (301 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (302 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (303 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (304 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (305 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (306 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (307 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (308 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (309 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (310 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (311 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (312 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (313 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (314 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (315 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (316 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (317 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (318 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (319 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (320 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (321 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (322 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (323 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (324 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (325 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (326 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (327 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (328 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (329 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (330 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (331 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (332 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (333 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (334 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (335 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (336 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (337 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (338 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (339 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (340 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (341 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (342 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (343 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (344 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (345 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (346 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (347 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (348 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (349 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (350 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (351 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (352 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (353 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (354 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (355 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (356 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (357 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (358 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (359 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (360 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (361 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (362 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (363 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (364 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (365 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (366 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (367 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (368 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (369 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (370 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (371 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (372 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (373 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (374 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (375 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (376 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (377 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (378 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (379 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (380 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (381 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (382 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (383 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (384 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (385 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (386 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (387 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (388 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (389 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (390 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (391 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (392 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (393 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (394 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (395 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (396 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (397 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (398 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (399 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (400 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (401 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (402 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (403 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (404 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (405 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (406 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (407 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (408 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (409 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (410 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (411 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (412 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (413 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (414 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (415 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (416 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (417 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (418 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (419 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (420 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (421 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (422 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (423 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (424 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (425 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (426 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (427 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (428 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (429 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (430 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (431 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (432 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (433 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (434 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (435 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (436 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (437 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (438 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (439 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (440 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (441 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (442 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (443 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (444 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (445 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (446 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (447 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (448 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (449 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (450 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (451 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (452 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (453 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (454 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (455 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (456 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (457 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (458 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (459 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (460 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (461 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (462 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (463 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (464 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (465 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (466 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (467 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (468 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (469 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (470 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (471 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (472 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (473 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (474 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (475 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (476 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (477 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (478 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (479 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (480 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (481 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (482 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (483 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (484 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (485 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (486 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (487 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (488 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (489 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (490 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (491 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (492 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (493 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (494 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (495 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (496 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (497 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (498 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (499 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (500 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (501 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (502 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (503 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (504 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (505 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (506 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (507 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (508 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (509 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (510 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (511 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+    .balign 64
+    .size   dvmAsmAltInstructionStart, .-dvmAsmAltInstructionStart
+    .global dvmAsmAltInstructionEnd
+dvmAsmAltInstructionEnd:
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+
+#if defined(WITH_JIT)
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * "longjmp" to a translation after single-stepping.  Before returning
+ * to translation, must save state for self-verification.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    b      jitSVShadowRunStart                   @ resume as if cache hit
+                                                 @ expects resume addr in r10
+
+    .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
+    mov    r3, #0
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
+    b      jitSVShadowRunEnd            @ doesn't return
+
+
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+#else
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r0, [rSELF,#offThread_jitResumeNPC]
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    bx     r0                                    @ resume translation
+
+/*
+ * 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
+#if defined(WITH_JIT_TUNING)
+    mov    r0,lr
+    bl     dvmBumpPunt;
+#endif
+    EXPORT_PC()
+    mov    r0, #0
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * We'll use the normal single-stepping mechanism via interpBreak,
+ * but also save the native pc of the resume point in the translation
+ * and the native sp so that we can later do the equivalent of a
+ * longjmp() to resume.
+ * On entry:
+ *    dPC <= Dalvik PC of instrucion to interpret
+ *    lr <= resume point in translation
+ *    r1 <= Dalvik PC of next instruction
+ */
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r1, #1
+    str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
+    mov    r0, rSELF
+    mov    r1, #kSubModeCountedStep
+    bl     dvmEnableSubMode     @ (self, newMode)
+    ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used for callees.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0                    @ !0 means translation exists
+    bxne   r0                       @ continue native execution if so
+    b      2f                       @ branch over to use the interpreter
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used following
+ * invokes.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    rPC,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST, #-4              @  .. which is 9 bytes back
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    2f
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @ in case target is HANDLER_INTERPRET
+    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:
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    cmp    r0, #0
+    movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
+    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,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST,#-4               @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNormal
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    toInterpreter            @ go if not, otherwise do chain
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    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 dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+#endif
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & 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()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    @ NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+common_testUpdateProfile:
+    cmp     r0, #0               @ JIT switched off?
+    beq     4f                   @ return to interp if so
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ *    r0    <= pJitProfTable (verified non-NULL)
+ *    rPC   <= Dalvik PC
+ *    rINST <= next instruction
+ */
+common_updateProfile:
+    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+    lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
+    ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
+    GET_INST_OPCODE(ip)
+    subs    r1,r1,#1           @ decrement counter
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
+    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
+
+    /* Looks good, reset the counter */
+    ldr     r1, [rSELF, #offThread_jitThreshold]
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
+    EXPORT_PC()
+    mov     r0,rPC
+    mov     r1,rSELF
+    bl      dvmJitGetTraceAddrThread    @ (pc, self)
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov     r1, rPC                     @ arg1 of translation may need this
+    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
+    cmp     r0,#0
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    r0                          @ jump to the translation
+    mov     r2,#kJitTSelectRequest      @ ask for trace selection
+    @ fall-through to common_selectTrace
+#else
+    moveq   r2,#kJitTSelectRequest      @ ask for trace selection
+    beq     common_selectTrace
+    /*
+     * At this point, we have a target translation.  However, if
+     * that translation is actually the interpret-only pseudo-translation
+     * we want to treat it the same as no translation.
+     */
+    mov     r10, r0                     @ save target
+    bl      dvmCompilerGetInterpretTemplate
+    cmp     r0, r10                     @ special case?
+    bne     jitSVShadowRunStart         @ set up self verification shadow space
+    @ Need to clear the inJitCodeCache flag
+    mov    r3, #0                       @ 0 means not in the JIT code cache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+/*
+ * On entry:
+ *  r2 is jit state.
+ */
+common_selectTrace:
+    ldrh    r0,[rSELF,#offThread_subMode]
+    ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
+    bne     3f                         @ already doing JIT work, continue
+    str     r2,[rSELF,#offThread_jitState]
+    mov     r0, rSELF
+/*
+ * Call out to validate trace-building request.  If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+    EXPORT_PC()
+    SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
+    bl      dvmJitCheckTraceRequest
+3:
+    FETCH_INST()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+4:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ *    rPC, rFP, rSELF: the values that they should contain
+ *    r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+    mov     r0,rPC                      @ r0<- program counter
+    mov     r1,rFP                      @ r1<- frame pointer
+    mov     r2,rSELF                    @ r2<- self (Thread) pointer
+    mov     r3,r10                      @ r3<- target translation
+    bl      dvmSelfVerificationSaveState @ save registers to shadow space
+    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
+    bx      r10                         @ jump to the translation
+
+/*
+ * Restore PC, registers, and interpreter state to original values
+ * before jumping back to the interpreter.
+ * On entry:
+ *   r0:  dPC
+ *   r2:  self verification state
+ */
+jitSVShadowRunEnd:
+    mov    r1,rFP                        @ pass ending fp
+    mov    r3,rSELF                      @ pass self ptr for convenience
+    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
+    LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
+    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
+    cmp    r1,#0                         @ check for punt condition
+    beq    1f
+    @ Set up SV single-stepping
+    mov    r0, rSELF
+    mov    r1, #kSubModeJitSV
+    bl     dvmEnableSubMode              @ (self, subMode)
+    mov    r2,#kJitSelfVerification      @ ask for self verification
+    str    r2,[rSELF,#offThread_jitState]
+    @ intentional fallthrough
+1:                                       @ exit to interpreter without check
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+common_gotoBail:
+    SAVE_PC_FP_TO_SELF()                @ export state to "thread"
+    mov     r0, rSELF                   @ r0<- self ptr
+    b       dvmMterpStdBail             @ call(self, changeInterp)
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair.  Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+    cmp     r9, #0
+    ldrne   r9, [r9, #offObject_clazz]
+    str     r0, [rSELF, #offThread_methodToCall]
+    str     r9, [rSELF, #offThread_callsiteClass]
+    bx      lr
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: r0 is "Method* methodToCall */
+    mov     r9, #0                      @ clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: r0 is "Method* methodToCall, r9 is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ prepare to copy args to "outs" area of current frame
+    add     rPC, rPC, #4                @ adjust pc to make return consistent
+    FETCH(r2, 1)                        @ r2<- BBBB (arg count)
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    cmp     r2, #0                      @ no args?
+    beq     .LinvokeArgsDone            @ if no args, skip the rest
+    FETCH(r1, 2)                        @ r1<- CCCC
+    b       .LinvokeRangeArgs           @ handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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
+
+.LinvokeRangeArgs:
+    @ 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
+1:  ldr     r1, [r3], #4                @ val = *fp++
+    subs    r2, r2, #1                  @ count--
+    str     r1, [r10], #4               @ *outs++ = val
+    bne     1b                          @ ...while count != 0
+    b       .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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)
+    beq     .LinvokeArgsDone
+
+    @ r0=methodToCall, r1=GFED, r2=count, 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
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
+    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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
+    cmp     r3, r9                      @ bottom < interpStackEnd?
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
+    blo     .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]
+
+    @ Profiling?
+    cmp     lr, #0                      @ any special modes happening?
+    bne     2f                          @ go if so
+1:
+    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
+
+    @ Update state values for the new method
+    @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     r2, #1
+    str     r2, [rSELF, #offThread_debugIsMethodEntry]
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [rSELF, #offThread_curFrame]   @ 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, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#endif
+
+2:
+    @ Profiling - record method entry.  r0: methodToCall
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    mov     r1, r0
+    mov     r0, rSELF
+    bl      dvmReportInvoke             @ (self, method)
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+    b       1b
+
+.LinvokeNative:
+    @ Prep for the native call
+    @ r0=methodToCall, r1=newFp, r10=newSaveArea
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFp (points to args)
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+
+#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
+
+    cmp     lr, #0                      @ any special SubModes active?
+    bne     11f                         @ go handle them if so
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+7:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    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
+
+11:
+    @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
+    stmfd   sp!, {r0-r3}                @ save all but subModes
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
+    ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
+
+    @ Call the native method
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+
+    @ Restore the pre-call arguments
+    ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
+
+    @ Finish up any post-invoke subMode requirements
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
+    b       7b                          @ resume
+
+.LstackOverflow:    @ r0=methodToCall
+    mov     r1, r0                      @ r1<- methodToCall
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmHandleStackOverflow
+    b       common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+    .fnend
+    .size   dalvik_mterp, .-dalvik_mterp
+#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, rSELF                   @ A0<- self
+    SAVE_PC_FP_TO_SELF()                @ export state to "self"
+    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:
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r0, rFP)
+    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+    cmp     lr, #0                      @ any special subMode handling needed?
+    bne     19f
+14:
+    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ is this a break frame?
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     15f
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+15:
+#else
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+#endif
+    beq     common_gotoBail             @ break frame, bail out completely
+
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+#if defined(WITH_JIT)
+    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
+    cmp     r10, #0                      @ caller is compiled code
+    blxne   r10
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+19:
+    @ Handle special actions
+    @ On entry, r0: StackSaveArea
+    ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
+    mov     r0, rSELF
+    bl      dvmReportReturn             @ (self)
+    SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
+    b       14b                         @ continue
+
+    /*
+     * Return handling, calls through "glue code".
+     */
+     .if    0
+.LreturnOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ 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:
+
+    EXPORT_PC()
+
+    mov     r0, rSELF
+    bl      dvmCheckSuspendPending
+
+    ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
+    mov     r1, rSELF                   @ r1<- self
+    mov     r0, r9                      @ r0<- exception
+    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
+    ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
+    mov     r3, #0                      @ r3<- NULL
+    str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
+
+    @ Special subMode?
+    cmp     r2, #0                      @ any special subMode handling needed?
+    bne     7f                          @ go if so
+8:
+    /* 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, [rSELF, #offThread_method] @ r1<- self->method
+    mov     r0, rSELF                   @ r0<- self
+    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
+    ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags
+    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, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    beq     1f                          @ no, skip ahead
+    mov     rFP, r0                     @ save relPc result in rFP
+    mov     r0, rSELF                   @ r0<- self
+    mov     r1, r9                      @ r1<- exception
+    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->interpSave.curFrame and updated PC */
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
+    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
+    str     r1, [rSELF, #offThread_method]  @ self->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, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
+
+    /* release the tracked alloc on the exception */
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+
+    /* restore the exception if the handler wants it */
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    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, [rSELF, #offThread_exception] @ yes, restore the exception
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    @ Manage debugger bookkeeping
+7:
+    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
+    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
+    mov     r0, rSELF                       @ arg0<- self
+    mov     r1, r9                          @ arg1<- exception
+    bl      dvmReportExceptionThrow         @ (self, exception)
+    b       8b                              @ resume with normal handling
+
+.LnotCaughtLocally: @ r9=exception
+    /* fix stack overflow if necessary */
+    ldrb    r1, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    movne   r0, rSELF                   @ if yes: r0<- self
+    movne   r1, r9                      @ if yes: r1<- exception
+    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, [rSELF, #offThread_method]
+    ldr     r1, [r0, #offMethod_insns]
+    sub     r1, rPC, r1
+    asr     r1, r1, #1
+    bl      dvmLineNumFromPC
+    str     r0, [sp, #-4]!
+    @ dvmGetMethodSourceFile(method)
+    ldr     r0, [rSELF, #offThread_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, [rSELF, #offThread_exception] @ restore exception
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+    b       common_gotoBail             @ bail out
+
+
+    /*
+     * Exception handling, calls through "glue code".
+     */
+    .if     0
+.LexceptionOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ arg to function
+    bl      dvmMterp_exceptionThrown
+    b       common_resumeAfterGlueCall
+    .endif
+
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including the current
+     * instruction.
+     *
+     * On entry:
+     *     r10: &dvmDex->pResFields[field]
+     *     r0:  field pointer (must preserve)
+     */
+common_verifyField:
+    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
+    ands    r3, #kSubModeJitTraceBuild
+    bxeq    lr                          @ Not building trace, continue
+    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
+    cmp     r1, #0                      @ resolution complete?
+    bxne    lr                          @ yes, continue
+    stmfd   sp!, {r0-r2,lr}             @ save regs
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
+    ldmfd   sp!, {r0-r2, lr}
+    bx      lr                          @ return
+#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_SELF()              @ pull rPC and rFP out of thread
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use r1
+ * and r3 because those just happen to be the registers all our callers are
+ * using. We move r3 before calling the C function, but r1 happens to match.
+ * r1: index
+ * r3: size
+ */
+common_errArrayIndex:
+    EXPORT_PC()
+    mov     r0, r3
+    bl      dvmThrowArrayIndexOutOfBoundsException
+    b       common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+    EXPORT_PC()
+    ldr     r0, strDivideByZero
+    bl      dvmThrowArithmeticException
+    b       common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in r1
+ */
+common_errNegativeArraySize:
+    EXPORT_PC()
+    mov     r0, r1                                @ arg0 <- len
+    bl      dvmThrowNegativeArraySizeException    @ (len)
+    b       common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in r1
+ */
+common_errNoSuchMethod:
+    EXPORT_PC()
+    mov     r0, r1
+    bl      dvmThrowNoSuchMethodError
+    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()
+    mov     r0, #0
+    bl      dvmThrowNullPointerException
+    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
+strDivideByZero:
+    .word   .LstrDivideByZero
+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"
+.LstrFilledNewArrayNotImpl:
+    .asciz  "filled-new-array only implemented for objects and 'int'"
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrLogTag:
+    .asciz  "mterp"
+.LstrExceptionNotCaughtLocally:
+    .asciz  "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+    .asciz  "\n"
+.LstrSqueak:
+    .asciz  "<%d>"
+.LstrPrintHex:
+    .asciz  "<%#x>"
+.LstrPrintLong:
+    .asciz  "<%lld>"
+
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
new file mode 100644
index 0000000..5e4ccd4
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -0,0 +1,27938 @@
+/*
+ * This file was generated automatically by gen-mterp.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.
+ */
+
+/*
+ * 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  rSELF     self (Thread) 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 rSELF   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF()     ldr     rPC, [rSELF, #offThread_pc]
+#define SAVE_PC_TO_SELF()       str     rPC, [rSELF, #offThread_pc]
+#define LOAD_FP_FROM_SELF()     ldr     rFP, [rSELF, #offThread_curFrame]
+#define SAVE_FP_TO_SELF()       str     rFP, [rSELF, #offThread_curFrame]
+#define LOAD_PC_FP_FROM_SELF()  ldmia   rSELF, {rPC, rFP}
+#define SAVE_PC_FP_TO_SELF()    stmia   rSELF, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects.  Must
+ * be done *before* something throws.
+ *
+ * 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 #1]!", 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_BASE(_base,_reg)  add     pc, _base, _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]
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+/* File: armv5te/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro  SMP_DMB
+.endm
+
+/*
+ * Macro for data memory barrier; not meaningful pre-ARMv6K.
+ */
+.macro  SMP_DMB_ST
+.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  Thread* self
+ *
+ * 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, #offThread_bailPtr]  @ save SP for eventual return
+
+    /* set up "named" registers, figure out entry point */
+    mov     rSELF, r0                   @ set rSELF
+    LOAD_PC_FP_FROM_SELF()              @ load rPC and rFP from "thread"
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable] @ set rIBASE
+
+#if defined(WITH_JIT)
+.LentryInstr:
+    /* Entry is always a possible trace start */
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [rSELF, #offThread_shadowSpace] @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    /* 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
+
+.Lbad_arg:
+    ldr     r0, strBadEntryPoint
+    @ r1 holds value of entryPoint
+    bl      printf
+    bl      dvmAbort
+    .fnend
+    .size   dvmMterpStdRun, .-dvmMterpStdRun
+
+
+    .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  Thread* self
+ */
+dvmMterpStdBail:
+    ldr     sp, [r0, #offThread_bailPtr]    @ sp<- saved SP
+    add     sp, sp, #4                      @ un-align 64
+    ldmfd   sp!, {r4-r10,fp,pc}             @ 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, [rSELF, #offThread_retval]    @ r0<- self->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, rSELF, #offThread_retval  @ r3<- &self->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, [rSELF, #offThread_retval]    @ r0<- self->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 */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    ldr     r3, [rSELF, #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, [rSELF, #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 "thread"
+     * 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, [rSELF, #offThread_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 "thread"
+     * 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, rSELF, #offThread_retval  @ r3<- &self->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 "thread"
+     * 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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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)
+    mov     r0, rSELF                   @ r0<- self
+    cmp     r1, #0                      @ null object?
+    EXPORT_PC()                         @ need for precise GC
+    beq     common_errNullObject        @ null object, throw an exception
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      dvmLockObject               @ call(self, obj)
+    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     1f                          @ yes
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
+    cmp     r0, #0                      @ failed?
+    FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    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, [rSELF, #offThread_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 - len in r1
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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)
+    EXPORT_PC()                         @ exception handler can throw
+    cmp     r1, #0                      @ null object?
+    beq     common_errNullObject        @ yes, throw an NPE instead
+    @ bypass dvmSetException, just store it
+    str     r1, [rSELF, #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 */
+    /* tuning: use sbfx for 6t2+ targets */
+    mov     r0, rINST, lsl #16          @ r0<- AAxx0000
+    movs    r1, r0, asr #24             @ r1<- ssssssAA (sign-extended)
+    add     r2, r1, r1                  @ r2<- byte offset, set flags
+       @ If backwards branch refresh rIBASE
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) check for trace hotness
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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)
+    adds    r1, r0, r0                  @ r1<- byte offset, flags set
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) hot trace head?
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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".  Because
+     * we need the V bit set, we'll use an adds to convert from Dalvik
+     * offset to byte offset.
+     */
+    /* goto/32 +AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    orr     r0, r0, r1, lsl #16         @ r0<- AAAAaaaa
+    adds    r1, r0, r0                  @ r1<- byte offset
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ble     common_testUpdateProfile    @ (r0) hot trace head?
+#else
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: armv5te/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.
+     *
+     * 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 */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r9, r2)                    @ r9<- vBB
+    GET_VREG(r10, r3)                   @ r10<- vCC
+    mov     r0, r9                      @ copy to arg registers
+    mov     r1, r10
+    bl      __aeabi_cfcmple             @ cmp <=: C clear if <, Z set if eq
+    bhi     .LOP_CMPL_FLOAT_gt_or_nan       @ C set and Z clear, disambiguate
+    mvncc   r1, #0                      @ (less than) r1<- -1
+    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
+.LOP_CMPL_FLOAT_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: armv5te/OP_CMPG_FLOAT.S */
+/* File: armv5te/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.
+     *
+     * 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 */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r9, r2)                    @ r9<- vBB
+    GET_VREG(r10, r3)                   @ r10<- vCC
+    mov     r0, r9                      @ copy to arg registers
+    mov     r1, r10
+    bl      __aeabi_cfcmple             @ cmp <=: C clear if <, Z set if eq
+    bhi     .LOP_CMPG_FLOAT_gt_or_nan       @ C set and Z clear, disambiguate
+    mvncc   r1, #0                      @ (less than) r1<- -1
+    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
+.LOP_CMPG_FLOAT_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: armv5te/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.
+     *
+     * 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 */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r9, r0, #255                @ r9<- BB
+    mov     r10, r0, lsr #8             @ r10<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BB]
+    add     r10, rFP, r10, lsl #2       @ r10<- &fp[CC]
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r10, {r2-r3}                @ r2/r3<- vCC/vCC+1
+    bl      __aeabi_cdcmple             @ cmp <=: C clear if <, Z set if eq
+    bhi     .LOP_CMPL_DOUBLE_gt_or_nan       @ C set and Z clear, disambiguate
+    mvncc   r1, #0                      @ (less than) r1<- -1
+    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
+.LOP_CMPL_DOUBLE_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: armv5te/OP_CMPG_DOUBLE.S */
+/* File: armv5te/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.
+     *
+     * 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 */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r9, r0, #255                @ r9<- BB
+    mov     r10, r0, lsr #8             @ r10<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BB]
+    add     r10, rFP, r10, lsl #2       @ r10<- &fp[CC]
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r10, {r2-r3}                @ r2/r3<- vCC/vCC+1
+    bl      __aeabi_cdcmple             @ cmp <=: C clear if <, Z set if eq
+    bhi     .LOP_CMPG_DOUBLE_gt_or_nan       @ C set and Z clear, disambiguate
+    mvncc   r1, #0                      @ (less than) r1<- -1
+    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
+.LOP_CMPG_DOUBLE_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movne r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    moveq r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movge r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movlt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movle r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movgt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0,#0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movne r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    moveq r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movge r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movlt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movle r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movgt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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.
+     */
+    /* 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(rINST, r2)                 @ rINST<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     rINST, #0                   @ null array object?
+    GET_VREG(r9, r9)                    @ r9<- vAA
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [rINST, #offArrayObject_length]   @ r3<- arrayObj->length
+    add     r10, rINST, r1, lsl #2      @ r10<- arrayObj + index*width
+    cmp     r1, 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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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 */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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     r9, rINST, lsr #8           @ r9<- AA
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_end
+
+/* ------------------------------ */
+    .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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodNoRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodNoRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_resolve
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_RANGE_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_RANGE_resolve
+
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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: armv5te/OP_INT_TO_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
+    bl      __aeabi_i2f                              @ 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_DOUBLE: /* 0x83 */
+/* File: armv5te/OP_INT_TO_DOUBLE.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
+    bl      __aeabi_i2d                              @ 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_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: armv5te/OP_FLOAT_TO_INT.S */
+/* EABI appears to have Java-style conversions of +inf/-inf/NaN */
+/* 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
+    bl      __aeabi_f2iz                              @ 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 */
+
+
+#if 0
+@include "armv5te/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
+
+/* ------------------------------ */
+    .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: armv5te/OP_FLOAT_TO_DOUBLE.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
+    bl      __aeabi_f2d                              @ 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_DOUBLE_TO_INT: /* 0x8a */
+/* File: armv5te/OP_DOUBLE_TO_INT.S */
+/* EABI appears to have Java-style conversions of +inf/-inf/NaN */
+/* 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_d2iz                              @ 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 */
+
+
+#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
+
+/* ------------------------------ */
+    .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: armv5te/OP_DOUBLE_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_d2f                              @ 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_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: armv5te/OP_ADD_FLOAT.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
+    bl      __aeabi_fadd                              @ 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_FLOAT: /* 0xa7 */
+/* File: armv5te/OP_SUB_FLOAT.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
+    bl      __aeabi_fsub                              @ 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_FLOAT: /* 0xa8 */
+/* File: armv5te/OP_MUL_FLOAT.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
+    bl      __aeabi_fmul                              @ 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_FLOAT: /* 0xa9 */
+/* File: armv5te/OP_DIV_FLOAT.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
+    bl      __aeabi_fdiv                              @ 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_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: armv5te/OP_ADD_DOUBLE.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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_dadd                              @ 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_DOUBLE: /* 0xac */
+/* File: armv5te/OP_SUB_DOUBLE.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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_dsub                              @ 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_DOUBLE: /* 0xad */
+/* File: armv5te/OP_MUL_DOUBLE.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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_dmul                              @ 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_DIV_DOUBLE: /* 0xae */
+/* File: armv5te/OP_DIV_DOUBLE.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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_ddiv                              @ 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_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: armv5te/OP_ADD_FLOAT_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
+    bl      __aeabi_fadd                              @ 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_FLOAT_2ADDR: /* 0xc7 */
+/* File: armv5te/OP_SUB_FLOAT_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
+    bl      __aeabi_fsub                              @ 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_FLOAT_2ADDR: /* 0xc8 */
+/* File: armv5te/OP_MUL_FLOAT_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
+    bl      __aeabi_fmul                              @ 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_FLOAT_2ADDR: /* 0xc9 */
+/* File: armv5te/OP_DIV_FLOAT_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
+    bl      __aeabi_fdiv                              @ 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_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: armv5te/OP_ADD_DOUBLE_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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_dadd                              @ 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_DOUBLE_2ADDR: /* 0xcc */
+/* File: armv5te/OP_SUB_DOUBLE_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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_dsub                              @ 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_DOUBLE_2ADDR: /* 0xcd */
+/* File: armv5te/OP_MUL_DOUBLE_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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_dmul                              @ 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_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: armv5te/OP_DIV_DOUBLE_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
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_ddiv                              @ 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_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_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+    /*
+     * Wide 32-bit instance field get.
+     */
+    /* iget-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_WIDE_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+    /* iput-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+    /*
+     * 64-bit SGET handler.
+     */
+    /* sget-wide vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+    /*
+     * 64-bit SPUT handler.
+     */
+    /* sput-wide vAA, field@BBBB */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/OP_BREAKPOINT.S */
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.
+     */
+    mov     r0, rPC
+    bl      dvmGetOriginalOpcode        @ (rPC)
+    FETCH(rINST, 0)                     @ reload OP_BREAKPOINT + rest of inst
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    and     rINST, #0xff00
+    orr     rINST, rINST, r0
+    GOTO_OPCODE_BASE(r1, r0)
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_method]    @ r0<- self->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 an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     *
+     * TUNING: could maintain two tables, pointer in Thread and
+     * swap if profiler/debuggger active.
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->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_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */
+    /*
+     * Execute a "native inline" instruction, using "/range" semantics.
+     * Same idea as execute-inline, but we get the args differently.
+     *
+     * We need to call an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     */
+    /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_RANGE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_RANGE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_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_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 2)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_RANGE_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(2+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/OP_RETURN_VOID_BARRIER.S */
+    SMP_DMB_ST
+    b       common_returnFromMethod
+
+/* ------------------------------ */
+    .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(ip, 1)                        @ ip<- 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, ip]                @ 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 */
+    /* 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 */
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card based on obj head
+    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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/OP_DISPATCH_FF.S */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/OP_CONST_CLASS_JUMBO.S */
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<-self>methodClassDex
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]   @ r2<- dvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResClasses[AAAAaaaa]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .LOP_CONST_CLASS_JUMBO_resolve
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/OP_CHECK_CAST_JUMBO.S */
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r3, 3)                        @ r3<- BBBB
+    orr     r2, r0, r2, lsl #16         @ r2<- AAAAaaaa
+    GET_VREG(r9, r3)                    @ r9<- object
+    ldr     r0, [rSELF, #offThread_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .LOP_CHECK_CAST_JUMBO_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_JUMBO_resolve         @ not resolved, do it now
+.LOP_CHECK_CAST_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .LOP_CHECK_CAST_JUMBO_fullcheck       @ no, do full check
+    b       .LOP_CHECK_CAST_JUMBO_okay            @ yes, finish up
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/OP_INSTANCE_OF_JUMBO.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.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_INSTANCE_OF.S.
+     */
+    /* instance-of/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    FETCH(r9, 3)                        @ r9<- vBBBB
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- pDvmDex
+    cmp     r0, #0                      @ is object null?
+    beq     .LOP_INSTANCE_OF_JUMBO_store           @ null obj, not an instance, store r0
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]    @ r2<- pDvmDex->pResClasses
+    orr     r3, r1, r3, lsl #16         @ r3<- AAAAaaaa
+    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_JUMBO_resolve         @ not resolved, do it now
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/OP_NEW_INSTANCE_JUMBO.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .LOP_NEW_INSTANCE_JUMBO_resolve         @ no, resolve it now
+.LOP_NEW_INSTANCE_JUMBO_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .LOP_NEW_INSTANCE_JUMBO_needinit        @ no, init class now
+.LOP_NEW_INSTANCE_JUMBO_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .LOP_NEW_INSTANCE_JUMBO_finish          @ continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/OP_NEW_ARRAY_JUMBO.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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r2, 1)                        @ r2<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- vCCCC
+    orr     r2, r2, r3, lsl #16         @ r2<- AAAAaaaa
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    GET_VREG(r1, r0)                    @ r1<- vCCCC (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 - len in r1
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .LOP_NEW_ARRAY_JUMBO_finish          @ resolved, continue
+    b       .LOP_NEW_ARRAY_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S */
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_FILLED_NEW_ARRAY.S.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    EXPORT_PC()                         @ need for resolve and alloc
+    cmp     r0, #0                      @ already resolved?
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_continue        @ yes, continue on
+8:  ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/OP_IGET_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrb", "sqnum":"1" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/OP_IGET_BYTE_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsb", "sqnum":"2" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/OP_IGET_CHAR_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrh", "sqnum":"3" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/OP_IGET_SHORT_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsh", "sqnum":"4" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    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_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/OP_IPUT_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/OP_IPUT_BYTE_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/OP_IPUT_CHAR_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/OP_IPUT_SHORT_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/OP_SGET_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BOOLEAN_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/OP_SGET_BYTE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BYTE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/OP_SGET_CHAR_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_CHAR_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/OP_SGET_SHORT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_SHORT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_JUMBO_end
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/OP_SPUT_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BOOLEAN_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/OP_SPUT_BYTE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BYTE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/OP_SPUT_CHAR_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_CHAR_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/OP_SPUT_SHORT_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_SHORT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_JUMBO.S */
+    /*
+     * Handle a virtual method call.
+     */
+    /* invoke-virtual/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_VIRTUAL_JUMBO_continue        @ yes, continue on
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/OP_INVOKE_SUPER_JUMBO.S */
+    /*
+     * Handle a "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_SUPER_JUMBO_continue        @ resolved, continue on
+    b       .LOP_INVOKE_SUPER_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/OP_INVOKE_DIRECT_JUMBO.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.)
+     *
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_JUMBO_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_JUMBO_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodJumbo    @ (r0=method, r9="this")
+    b       common_errNullObject        @ yes, throw exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/OP_INVOKE_STATIC_JUMBO.S */
+    /*
+     * Handle a static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodJumboNoThis   @ (r0=method)
+    b       .LOP_INVOKE_STATIC_JUMBO_resolve
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/OP_INVOKE_INTERFACE_JUMBO.S */
+    /*
+     * Handle an interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r2, 4)                        @ r2<- CCCC
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    EXPORT_PC()                         @ must export for invoke
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/OP_UNUSED_27FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/OP_UNUSED_28FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/OP_UNUSED_29FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/OP_UNUSED_2AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/OP_UNUSED_2BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/OP_UNUSED_2CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/OP_UNUSED_2DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/OP_UNUSED_2EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/OP_UNUSED_2FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/OP_UNUSED_30FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/OP_UNUSED_31FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/OP_UNUSED_32FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/OP_UNUSED_33FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/OP_UNUSED_34FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/OP_UNUSED_35FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/OP_UNUSED_36FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/OP_UNUSED_37FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/OP_UNUSED_38FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/OP_UNUSED_39FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/OP_UNUSED_3AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/OP_UNUSED_3BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/OP_UNUSED_3CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/OP_UNUSED_3DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/OP_UNUSED_3EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/OP_UNUSED_3FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/OP_UNUSED_40FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/OP_UNUSED_41FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/OP_UNUSED_42FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/OP_UNUSED_43FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/OP_UNUSED_44FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/OP_UNUSED_45FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/OP_UNUSED_46FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/OP_UNUSED_47FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/OP_UNUSED_48FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/OP_UNUSED_49FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/OP_UNUSED_4AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/OP_UNUSED_4BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/OP_UNUSED_4CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/OP_UNUSED_4DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/OP_UNUSED_4EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/OP_UNUSED_4FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/OP_UNUSED_50FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/OP_UNUSED_51FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/OP_UNUSED_52FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/OP_UNUSED_53FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/OP_UNUSED_54FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/OP_UNUSED_55FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/OP_UNUSED_56FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/OP_UNUSED_57FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/OP_UNUSED_58FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/OP_UNUSED_59FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/OP_UNUSED_5AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/OP_UNUSED_5BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/OP_UNUSED_5CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/OP_UNUSED_5DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/OP_UNUSED_5EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/OP_UNUSED_5FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/OP_UNUSED_60FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/OP_UNUSED_61FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/OP_UNUSED_62FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/OP_UNUSED_63FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/OP_UNUSED_64FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/OP_UNUSED_65FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/OP_UNUSED_66FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/OP_UNUSED_67FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/OP_UNUSED_68FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/OP_UNUSED_69FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/OP_UNUSED_6AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/OP_UNUSED_6BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/OP_UNUSED_6CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/OP_UNUSED_6DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/OP_UNUSED_6EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/OP_UNUSED_6FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/OP_UNUSED_70FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/OP_UNUSED_71FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/OP_UNUSED_72FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/OP_UNUSED_73FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/OP_UNUSED_74FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/OP_UNUSED_75FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/OP_UNUSED_76FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/OP_UNUSED_77FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/OP_UNUSED_78FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/OP_UNUSED_79FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/OP_UNUSED_7AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/OP_UNUSED_7BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/OP_UNUSED_7CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/OP_UNUSED_7DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/OP_UNUSED_7EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/OP_UNUSED_7FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/OP_UNUSED_80FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/OP_UNUSED_81FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/OP_UNUSED_82FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/OP_UNUSED_83FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/OP_UNUSED_84FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/OP_UNUSED_85FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/OP_UNUSED_86FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/OP_UNUSED_87FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/OP_UNUSED_88FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/OP_UNUSED_89FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/OP_UNUSED_8AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/OP_UNUSED_8BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/OP_UNUSED_8CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/OP_UNUSED_8DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/OP_UNUSED_8EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/OP_UNUSED_8FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/OP_UNUSED_90FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/OP_UNUSED_91FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/OP_UNUSED_92FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/OP_UNUSED_93FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/OP_UNUSED_94FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/OP_UNUSED_95FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/OP_UNUSED_96FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/OP_UNUSED_97FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/OP_UNUSED_98FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/OP_UNUSED_99FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/OP_UNUSED_9AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/OP_UNUSED_9BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/OP_UNUSED_9CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/OP_UNUSED_9DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/OP_UNUSED_9EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/OP_UNUSED_9FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/OP_UNUSED_A0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/OP_UNUSED_A1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/OP_UNUSED_A2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/OP_UNUSED_A3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/OP_UNUSED_A4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/OP_UNUSED_A5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/OP_UNUSED_A6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/OP_UNUSED_A7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/OP_UNUSED_A8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/OP_UNUSED_A9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/OP_UNUSED_AAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/OP_UNUSED_ABFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/OP_UNUSED_ACFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/OP_UNUSED_ADFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/OP_UNUSED_AEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/OP_UNUSED_AFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/OP_UNUSED_B0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/OP_UNUSED_B1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/OP_UNUSED_B2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/OP_UNUSED_B3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/OP_UNUSED_B4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/OP_UNUSED_B5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/OP_UNUSED_B6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/OP_UNUSED_B7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/OP_UNUSED_B8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/OP_UNUSED_B9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/OP_UNUSED_BAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/OP_UNUSED_BBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/OP_UNUSED_BCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/OP_UNUSED_BDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/OP_UNUSED_BEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/OP_UNUSED_BFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/OP_UNUSED_C0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/OP_UNUSED_C1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/OP_UNUSED_C2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/OP_UNUSED_C3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/OP_UNUSED_C4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/OP_UNUSED_C5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/OP_UNUSED_C6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/OP_UNUSED_C7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/OP_UNUSED_C8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/OP_UNUSED_C9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/OP_UNUSED_CAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/OP_UNUSED_CBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/OP_UNUSED_CCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/OP_UNUSED_CDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/OP_UNUSED_CEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/OP_UNUSED_CFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/OP_UNUSED_D0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/OP_UNUSED_D1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/OP_UNUSED_D2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/OP_UNUSED_D3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/OP_UNUSED_D4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/OP_UNUSED_D5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/OP_UNUSED_D6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/OP_UNUSED_D7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/OP_UNUSED_D8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/OP_UNUSED_D9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/OP_UNUSED_DAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/OP_UNUSED_DBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/OP_UNUSED_DCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/OP_UNUSED_DDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/OP_UNUSED_DEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/OP_UNUSED_DFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/OP_UNUSED_E0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/OP_UNUSED_E1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/OP_UNUSED_E2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/OP_UNUSED_E3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/OP_UNUSED_E4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/OP_UNUSED_E5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/OP_UNUSED_E6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/OP_UNUSED_E7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/OP_UNUSED_E8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/OP_UNUSED_E9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/OP_UNUSED_EAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/OP_UNUSED_EBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/OP_UNUSED_ECFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/OP_UNUSED_EDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/OP_UNUSED_EEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/OP_UNUSED_EFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/OP_UNUSED_F0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/OP_UNUSED_F1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 4)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_JUMBO_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(4+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/OP_IGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/OP_IPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/OP_SGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/OP_SPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR_JUMBO.S */
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, Class@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    orr     r2, r1, r2, lsl #16         @ r2<- AAAAaaaa
+    EXPORT_PC()                         @ export the PC
+    FETCH(r1, 3)                        @ r1<- BBBB
+    bl      dvmThrowVerificationError   @ always throws
+    b       common_exceptionThrown      @ handle exception
+
+    .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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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 desired class resolved from BBBB
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    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.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method]    @ r0<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_end:
+    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
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * 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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method] @ r3<- self->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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     0
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     1
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* continuation for OP_CMPL_FLOAT */
+
+    @ 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.
+.LOP_CMPL_FLOAT_gt_or_nan:
+    mov     r1, r9                      @ reverse order
+    mov     r0, r10
+    bl      __aeabi_cfcmple             @ r0<- Z set if eq, C clear if <
+    @bleq    common_abort
+    movcc   r1, #1                      @ (greater than) r1<- 1
+    bcc     .LOP_CMPL_FLOAT_finish
+    mvn     r1, #0                            @ r1<- 1 or -1 for NaN
+    b       .LOP_CMPL_FLOAT_finish
+
+
+#if 0       /* "clasic" form */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r9, r2)                    @ r9<- vBB
+    GET_VREG(r10, r3)                   @ r10<- vCC
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmpeq              @ r0<- (vBB == vCC)
+    cmp     r0, #0                      @ equal?
+    movne   r1, #0                      @ yes, result is 0
+    bne     OP_CMPL_FLOAT_finish
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmplt              @ r0<- (vBB < vCC)
+    cmp     r0, #0                      @ less than?
+    b       OP_CMPL_FLOAT_continue
+@%break
+
+OP_CMPL_FLOAT_continue:
+    mvnne   r1, #0                      @ yes, result is -1
+    bne     OP_CMPL_FLOAT_finish
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmpgt              @ r0<- (vBB > vCC)
+    cmp     r0, #0                      @ greater than?
+    beq     OP_CMPL_FLOAT_nan               @ no, must be NaN
+    mov     r1, #1                      @ yes, result is 1
+    @ fall through to _finish
+
+OP_CMPL_FLOAT_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * This is expected to be uncommon, so we double-branch (once to here,
+     * again back to _finish).
+     */
+OP_CMPL_FLOAT_nan:
+    mvn     r1, #0                            @ r1<- 1 or -1 for NaN
+    b       OP_CMPL_FLOAT_finish
+
+#endif
+
+/* continuation for OP_CMPG_FLOAT */
+
+    @ 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.
+.LOP_CMPG_FLOAT_gt_or_nan:
+    mov     r1, r9                      @ reverse order
+    mov     r0, r10
+    bl      __aeabi_cfcmple             @ r0<- Z set if eq, C clear if <
+    @bleq    common_abort
+    movcc   r1, #1                      @ (greater than) r1<- 1
+    bcc     .LOP_CMPG_FLOAT_finish
+    mov     r1, #1                            @ r1<- 1 or -1 for NaN
+    b       .LOP_CMPG_FLOAT_finish
+
+
+#if 0       /* "clasic" form */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r9, r2)                    @ r9<- vBB
+    GET_VREG(r10, r3)                   @ r10<- vCC
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmpeq              @ r0<- (vBB == vCC)
+    cmp     r0, #0                      @ equal?
+    movne   r1, #0                      @ yes, result is 0
+    bne     OP_CMPG_FLOAT_finish
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmplt              @ r0<- (vBB < vCC)
+    cmp     r0, #0                      @ less than?
+    b       OP_CMPG_FLOAT_continue
+@%break
+
+OP_CMPG_FLOAT_continue:
+    mvnne   r1, #0                      @ yes, result is -1
+    bne     OP_CMPG_FLOAT_finish
+    mov     r0, r9                      @ r0<- vBB
+    mov     r1, r10                     @ r1<- vCC
+    bl      __aeabi_fcmpgt              @ r0<- (vBB > vCC)
+    cmp     r0, #0                      @ greater than?
+    beq     OP_CMPG_FLOAT_nan               @ no, must be NaN
+    mov     r1, #1                      @ yes, result is 1
+    @ fall through to _finish
+
+OP_CMPG_FLOAT_finish:
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r3)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * This is expected to be uncommon, so we double-branch (once to here,
+     * again back to _finish).
+     */
+OP_CMPG_FLOAT_nan:
+    mov     r1, #1                            @ r1<- 1 or -1 for NaN
+    b       OP_CMPG_FLOAT_finish
+
+#endif
+
+/* continuation for OP_CMPL_DOUBLE */
+
+    @ 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.
+.LOP_CMPL_DOUBLE_gt_or_nan:
+    ldmia   r10, {r0-r1}                @ reverse order
+    ldmia   r9, {r2-r3}
+    bl      __aeabi_cdcmple             @ r0<- Z set if eq, C clear if <
+    @bleq    common_abort
+    movcc   r1, #1                      @ (greater than) r1<- 1
+    bcc     .LOP_CMPL_DOUBLE_finish
+    mvn     r1, #0                            @ r1<- 1 or -1 for NaN
+    b       .LOP_CMPL_DOUBLE_finish
+
+/* continuation for OP_CMPG_DOUBLE */
+
+    @ Test for NaN with a second comparison.  EABI forbids testing bit
+    @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+    @ make the library call.
+.LOP_CMPG_DOUBLE_gt_or_nan:
+    ldmia   r10, {r0-r1}                @ reverse order
+    ldmia   r9, {r2-r3}
+    bl      __aeabi_cdcmple             @ r0<- Z set if eq, C clear if <
+    @bleq    common_abort
+    movcc   r1, #1                      @ (greater than) r1<- 1
+    bcc     .LOP_CMPG_DOUBLE_finish
+    mov     r1, #1                            @ r1<- 1 or -1 for NaN
+    b       .LOP_CMPG_DOUBLE_finish
+
+/* 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:
+     *  rINST = 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, [rINST, #offObject_clazz]  @ r1<- arrayObj->clazz
+    bl      dvmCanPutArrayElement       @ test object type vs. array type
+    cmp     r0, #0                      @ okay?
+    beq     .LOP_APUT_OBJECT_throw           @ no
+    mov     r1, rINST                   @ r1<- arrayObj
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rSELF, #offThread_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r1, lsr #GC_CARD_SHIFT] @ mark card using object head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_skip_check:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_throw:
+    @ The types don't match.  We need to throw an ArrayStoreException.
+    ldr     r0, [r9, #offObject_clazz]
+    ldr     r1, [rINST, #offObject_clazz]
+    EXPORT_PC()
+    bl      dvmThrowArrayStoreExceptionIncompatibleElement
+    b       common_exceptionThrown
+
+/* 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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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
+    .if     0
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT */
+
+    /*
+     * 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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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(r10)                @ extract opcode from rINST
+    .if     0
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT */
+
+    /*
+     * 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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+    /*
+     * 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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_finish
+
+/* continuation for OP_SGET_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_finish          @ resume
+
+/* continuation for OP_SGET_OBJECT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_finish
+
+/* continuation for OP_SGET_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_finish
+
+/* continuation for OP_SGET_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_finish
+
+/* continuation for OP_SGET_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_finish
+
+/* continuation for OP_SGET_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_finish
+
+/* continuation for OP_SPUT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT */
+
+
+.LOP_SPUT_OBJECT_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_finish          @ resume
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodNoRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC */
+
+
+.LOP_INVOKE_STATIC_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodNoRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodNoRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodNoRange     @ whew, finally!
+#else
+    bne     common_invokeMethodNoRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_RANGE_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_RANGE_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_RANGE */
+
+
+.LOP_INVOKE_STATIC_RANGE_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodRange     @ whew, finally!
+#else
+    bne     common_invokeMethodRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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_IGET_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_finish
+
+/* continuation for OP_SPUT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_finish          @ resume
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    cmp     r9, #0                      @ check object for null
+    and     r2, r2, #15                 @ r2<- A
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[A]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_VOLATILE_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_finish          @ resume
+
+/* 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(rINST, 2)                     @ rINST<- FEDC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  and     ip, rINST, #0xf000          @ isolate F
+    ldr     r3, [rFP, ip, lsr #10]      @ r3<- vF (shift right 12, left 2)
+3:  and     ip, rINST, #0x0f00          @ isolate E
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vE
+2:  and     ip, rINST, #0x00f0          @ isolate D
+    ldr     r1, [rFP, ip, lsr #2]       @ r1<- vD
+1:  and     ip, rINST, #0x000f          @ isolate C
+    ldr     r0, [rFP, ip, lsl #2]       @ r0<- vC
+0:
+    ldr     rINST, .LOP_EXECUTE_INLINE_table    @ table of InlineOperation
+    ldr     pc, [rINST, r10, lsl #4]    @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_continue        @ make call; will return after
+    mov     rINST, r0                   @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, r9                      @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit @ (method, self)
+    cmp     rINST, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_table:
+    .word   gDvmInlineOpsTable
+
+/* continuation for OP_EXECUTE_INLINE_RANGE */
+
+    /*
+     * 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]
+     */
+.LOP_EXECUTE_INLINE_RANGE_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(r9, 2)                        @ r9<- CCCC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  add     ip, r9, #3                  @ base+3
+    GET_VREG(r3, ip)                    @ r3<- vBase[3]
+3:  add     ip, r9, #2                  @ base+2
+    GET_VREG(r2, ip)                    @ r2<- vBase[2]
+2:  add     ip, r9, #1                  @ base+1
+    GET_VREG(r1, ip)                    @ r1<- vBase[1]
+1:  add     ip, r9, #0                  @ (nop)
+    GET_VREG(r0, ip)                    @ r0<- vBase[0]
+0:
+    ldr     r9, .LOP_EXECUTE_INLINE_RANGE_table       @ table of InlineOperation
+    ldr     pc, [r9, r10, lsl #4]       @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_RANGE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_RANGE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- B
+    mov     rINST, r9                   @ rINST<- method
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_continue        @ make call; will return after
+    mov     r9, r0                      @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, rINST                   @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit  @ (method, self)
+    cmp     r9, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_RANGE_table:
+    .word   gDvmInlineOpsTable
+
+
+/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
+
+.LOP_INVOKE_OBJECT_INIT_RANGE_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_RANGE_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_RANGE_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 0
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_finish
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_finish          @ resume
+
+
+/* continuation for OP_CONST_CLASS_JUMBO */
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: AAAAAAAA (Class ref)
+     *  r9: target register
+     */
+.LOP_CONST_CLASS_JUMBO_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_CHECK_CAST_JUMBO */
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds desired class resolved from AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .LOP_CHECK_CAST_JUMBO_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    b       common_exceptionThrown
+
+    /*
+     * Advance PC and get the next opcode.
+     */
+.LOP_CHECK_CAST_JUMBO_okay:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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 AAAAAAAA
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_CHECK_CAST_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_INSTANCE_OF_JUMBO */
+
+    /*
+     * Class resolved, determine type of check necessary.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .LOP_INSTANCE_OF_JUMBO_trivial         @ yes, trivial finish
+    @ fall through to OP_INSTANCE_OF_JUMBO_fullcheck
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to OP_INSTANCE_OF_JUMBO_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_store:
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b OP_INSTANCE_OF_JUMBO_store, but copying is faster and cheaper
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- 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 AAAAAAAA
+     *  r9 holds BBBB
+     */
+
+.LOP_INSTANCE_OF_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    mov     r1, r3                      @ r1<- AAAAAAAA
+    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
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    mov     r1, r0                      @ r1<- class resolved from AAAAAAAA
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_NEW_INSTANCE_JUMBO */
+
+    .balign 32                          @ minimize cache lines
+.LOP_NEW_INSTANCE_JUMBO_finish: @ r0=new object
+    FETCH(r3, 3)                        @ r3<- BBBB
+    cmp     r0, #0                      @ failed?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_JUMBO_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_JUMBO_end:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_JUMBO_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.LOP_NEW_INSTANCE_JUMBO_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_JUMBO_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds AAAAAAAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_NEW_ARRAY_JUMBO */
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref AAAAAAAA
+     */
+.LOP_NEW_ARRAY_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r9, r1                      @ r9<- length (save)
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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_JUMBO_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.LOP_NEW_ARRAY_JUMBO_finish:
+    mov     r2, #ALLOC_DONT_TRACK       @ don't track in local refs table
+    bl      dvmAllocArrayByClass        @ r0<- call(clazz, length, flags)
+    cmp     r0, #0                      @ failed?
+    FETCH(r2, 3)                        @ r2<- vBBBB
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_FILLED_NEW_ARRAY_JUMBO */
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    FETCH(r1, 3)                        @ r1<- BBBB (length)
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_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, 4)                        @ r1<- CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(5)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC, r9=BBBB (length)
+    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
+
+2:  ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    GOTO_OPCODE(ip)                          @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_notimpl:
+    ldr     r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* continuation for OP_IGET_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     0
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     0
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_finish:
+    @bl      common_squeak1
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_finish:
+    @bl      common_squeak2
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_finish:
+    @bl      common_squeak3
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_finish:
+    @bl      common_squeak4
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_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_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_JUMBO */
+
+
+.LOP_SPUT_OBJECT_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_JUMBO_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_INVOKE_VIRTUAL_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     */
+.LOP_INVOKE_VIRTUAL_JUMBO_continue:
+    FETCH(r10, 4)                       @ r10<- CCCC
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_JUMBO_continue:
+    ldr     r1, [r10, #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_JUMBO_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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+.LOP_INVOKE_SUPER_JUMBO_resolve:
+    mov     r0, r10                     @ 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_JUMBO_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_JUMBO_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
+
+/* continuation for OP_INVOKE_DIRECT_JUMBO */
+
+    /*
+     * On entry:
+     *  r1 = reference (CCCC)
+     *  r10 = "this" register
+     */
+.LOP_INVOKE_DIRECT_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_JUMBO_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_JUMBO */
+
+
+.LOP_INVOKE_STATIC_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodJumboNoThis    @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodJumboNoThis    @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodJumboNoThis    @ whew, finally!
+#else
+    bne     common_invokeMethodJumboNoThis    @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* continuation for OP_INVOKE_OBJECT_INIT_JUMBO */
+
+.LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_JUMBO_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_JUMBO_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 1
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IGET_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_WIDE_VOLATILE_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE_JUMBO */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+
+    .global dvmAsmAltInstructionStart
+    .type   dvmAsmAltInstructionStart, %function
+    .text
+
+dvmAsmAltInstructionStart = .L_ALT_OP_NOP
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOP: /* 0x00 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (0 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE: /* 0x01 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (1 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (2 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (3 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (4 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (5 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (6 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (7 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (8 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (9 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (10 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (11 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (12 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (13 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID: /* 0x0e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (14 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN: /* 0x0f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (15 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (16 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (17 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_4: /* 0x12 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (18 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_16: /* 0x13 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (19 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST: /* 0x14 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (20 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (21 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (22 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (23 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (24 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (25 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (26 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (27 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (28 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (29 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (30 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST: /* 0x1f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (31 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (32 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (33 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (34 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (35 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (36 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (37 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (38 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW: /* 0x27 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (39 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO: /* 0x28 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (40 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (41 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (42 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (43 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (44 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_FLOAT: /* 0x2d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (45 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_FLOAT: /* 0x2e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (46 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (47 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (48 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (49 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQ: /* 0x32 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (50 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NE: /* 0x33 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (51 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LT: /* 0x34 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (52 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GE: /* 0x35 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (53 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GT: /* 0x36 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (54 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LE: /* 0x37 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (55 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (56 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (57 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (58 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (59 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (60 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (61 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (62 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (63 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (64 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (65 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (66 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (67 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET: /* 0x44 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (68 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (69 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (70 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (71 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (72 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (73 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (74 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT: /* 0x4b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (75 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (76 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (77 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (78 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (79 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (80 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (81 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET: /* 0x52 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (82 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE: /* 0x53 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (83 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (84 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (85 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (86 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (87 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (88 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT: /* 0x59 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (89 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE: /* 0x5a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (90 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (91 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (92 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (93 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (94 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (95 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET: /* 0x60 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (96 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE: /* 0x61 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (97 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (98 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (99 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE: /* 0x64 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (100 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR: /* 0x65 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (101 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT: /* 0x66 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (102 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT: /* 0x67 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (103 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (104 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (105 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (106 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (107 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (108 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (109 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (110 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (111 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (112 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (113 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (114 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (115 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (116 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (117 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (118 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (119 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (120 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (121 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (122 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_INT: /* 0x7b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (123 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_INT: /* 0x7c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (124 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_LONG: /* 0x7d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (125 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_LONG: /* 0x7e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (126 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (127 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (128 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (129 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (130 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (131 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (132 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (133 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (134 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (135 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (136 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (137 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (138 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (139 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (140 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (141 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (142 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (143 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (144 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (145 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (146 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (147 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT: /* 0x94 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (148 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT: /* 0x95 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (149 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT: /* 0x96 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (150 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (151 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (152 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (153 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (154 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (155 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (156 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (157 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (158 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (159 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (160 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (161 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (162 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (163 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (164 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (165 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT: /* 0xa6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (166 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT: /* 0xa7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (167 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT: /* 0xa8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (168 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT: /* 0xa9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (169 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (170 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE: /* 0xab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (171 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE: /* 0xac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (172 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE: /* 0xad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (173 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE: /* 0xae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (174 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (175 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (176 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (177 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (178 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (179 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (180 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (181 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (182 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (183 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (184 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (185 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (186 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (187 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (188 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (189 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (190 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (191 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (192 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (193 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (194 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (195 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (196 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (197 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (198 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (199 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (200 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (201 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (202 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (203 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (204 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (205 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (206 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (207 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (208 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT: /* 0xd1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (209 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (210 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (211 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (212 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (213 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (214 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (215 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (216 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (217 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (218 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (219 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (220 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (221 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (222 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (223 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (224 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (225 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (226 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (227 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (228 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (229 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (230 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (231 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (232 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (233 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (234 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (235 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (236 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (237 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (238 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (239 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (240 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (241 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (242 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (243 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (244 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_QUICK: /* 0xf5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (245 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (246 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (247 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (248 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (249 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (250 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (251 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (252 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (253 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (254 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/ALT_OP_DISPATCH_FF.S */
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (256 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (257 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (258 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (259 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (260 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (261 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (262 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (263 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (264 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (265 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (266 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (267 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (268 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (269 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (270 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (271 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (272 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (273 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (274 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (275 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (276 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (277 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (278 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (279 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (280 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (281 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (282 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (283 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (284 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (285 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (286 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (287 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (288 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (289 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (290 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (291 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (292 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (293 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (294 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (295 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (296 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (297 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (298 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (299 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (300 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (301 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (302 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (303 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (304 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (305 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (306 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (307 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (308 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (309 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (310 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (311 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (312 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (313 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (314 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (315 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (316 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (317 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (318 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (319 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (320 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (321 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (322 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (323 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (324 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (325 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (326 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (327 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (328 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (329 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (330 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (331 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (332 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (333 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (334 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (335 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (336 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (337 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (338 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (339 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (340 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (341 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (342 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (343 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (344 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (345 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (346 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (347 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (348 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (349 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (350 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (351 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (352 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (353 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (354 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (355 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (356 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (357 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (358 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (359 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (360 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (361 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (362 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (363 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (364 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (365 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (366 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (367 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (368 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (369 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (370 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (371 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (372 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (373 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (374 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (375 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (376 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (377 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (378 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (379 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (380 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (381 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (382 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (383 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (384 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (385 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (386 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (387 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (388 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (389 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (390 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (391 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (392 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (393 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (394 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (395 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (396 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (397 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (398 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (399 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (400 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (401 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (402 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (403 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (404 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (405 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (406 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (407 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (408 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (409 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (410 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (411 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (412 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (413 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (414 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (415 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (416 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (417 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (418 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (419 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (420 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (421 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (422 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (423 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (424 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (425 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (426 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (427 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (428 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (429 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (430 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (431 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (432 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (433 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (434 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (435 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (436 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (437 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (438 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (439 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (440 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (441 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (442 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (443 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (444 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (445 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (446 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (447 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (448 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (449 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (450 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (451 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (452 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (453 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (454 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (455 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (456 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (457 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (458 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (459 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (460 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (461 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (462 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (463 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (464 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (465 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (466 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (467 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (468 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (469 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (470 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (471 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (472 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (473 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (474 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (475 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (476 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (477 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (478 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (479 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (480 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (481 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (482 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (483 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (484 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (485 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (486 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (487 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (488 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (489 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (490 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (491 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (492 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (493 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (494 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (495 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (496 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (497 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (498 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (499 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (500 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (501 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (502 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (503 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (504 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (505 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (506 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (507 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (508 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (509 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (510 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (511 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+    .balign 64
+    .size   dvmAsmAltInstructionStart, .-dvmAsmAltInstructionStart
+    .global dvmAsmAltInstructionEnd
+dvmAsmAltInstructionEnd:
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+
+#if defined(WITH_JIT)
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * "longjmp" to a translation after single-stepping.  Before returning
+ * to translation, must save state for self-verification.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    b      jitSVShadowRunStart                   @ resume as if cache hit
+                                                 @ expects resume addr in r10
+
+    .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
+    mov    r3, #0
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
+    b      jitSVShadowRunEnd            @ doesn't return
+
+
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+#else
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r0, [rSELF,#offThread_jitResumeNPC]
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    bx     r0                                    @ resume translation
+
+/*
+ * 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
+#if defined(WITH_JIT_TUNING)
+    mov    r0,lr
+    bl     dvmBumpPunt;
+#endif
+    EXPORT_PC()
+    mov    r0, #0
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * We'll use the normal single-stepping mechanism via interpBreak,
+ * but also save the native pc of the resume point in the translation
+ * and the native sp so that we can later do the equivalent of a
+ * longjmp() to resume.
+ * On entry:
+ *    dPC <= Dalvik PC of instrucion to interpret
+ *    lr <= resume point in translation
+ *    r1 <= Dalvik PC of next instruction
+ */
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r1, #1
+    str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
+    mov    r0, rSELF
+    mov    r1, #kSubModeCountedStep
+    bl     dvmEnableSubMode     @ (self, newMode)
+    ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used for callees.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0                    @ !0 means translation exists
+    bxne   r0                       @ continue native execution if so
+    b      2f                       @ branch over to use the interpreter
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used following
+ * invokes.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    rPC,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST, #-4              @  .. which is 9 bytes back
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    2f
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @ in case target is HANDLER_INTERPRET
+    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:
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    cmp    r0, #0
+    movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
+    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,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST,#-4               @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNormal
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    toInterpreter            @ go if not, otherwise do chain
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    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 dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+#endif
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & 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()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    @ NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+common_testUpdateProfile:
+    cmp     r0, #0               @ JIT switched off?
+    beq     4f                   @ return to interp if so
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ *    r0    <= pJitProfTable (verified non-NULL)
+ *    rPC   <= Dalvik PC
+ *    rINST <= next instruction
+ */
+common_updateProfile:
+    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+    lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
+    ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
+    GET_INST_OPCODE(ip)
+    subs    r1,r1,#1           @ decrement counter
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
+    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
+
+    /* Looks good, reset the counter */
+    ldr     r1, [rSELF, #offThread_jitThreshold]
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
+    EXPORT_PC()
+    mov     r0,rPC
+    mov     r1,rSELF
+    bl      dvmJitGetTraceAddrThread    @ (pc, self)
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov     r1, rPC                     @ arg1 of translation may need this
+    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
+    cmp     r0,#0
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    r0                          @ jump to the translation
+    mov     r2,#kJitTSelectRequest      @ ask for trace selection
+    @ fall-through to common_selectTrace
+#else
+    moveq   r2,#kJitTSelectRequest      @ ask for trace selection
+    beq     common_selectTrace
+    /*
+     * At this point, we have a target translation.  However, if
+     * that translation is actually the interpret-only pseudo-translation
+     * we want to treat it the same as no translation.
+     */
+    mov     r10, r0                     @ save target
+    bl      dvmCompilerGetInterpretTemplate
+    cmp     r0, r10                     @ special case?
+    bne     jitSVShadowRunStart         @ set up self verification shadow space
+    @ Need to clear the inJitCodeCache flag
+    mov    r3, #0                       @ 0 means not in the JIT code cache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+/*
+ * On entry:
+ *  r2 is jit state.
+ */
+common_selectTrace:
+    ldrh    r0,[rSELF,#offThread_subMode]
+    ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
+    bne     3f                         @ already doing JIT work, continue
+    str     r2,[rSELF,#offThread_jitState]
+    mov     r0, rSELF
+/*
+ * Call out to validate trace-building request.  If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+    EXPORT_PC()
+    SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
+    bl      dvmJitCheckTraceRequest
+3:
+    FETCH_INST()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+4:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ *    rPC, rFP, rSELF: the values that they should contain
+ *    r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+    mov     r0,rPC                      @ r0<- program counter
+    mov     r1,rFP                      @ r1<- frame pointer
+    mov     r2,rSELF                    @ r2<- self (Thread) pointer
+    mov     r3,r10                      @ r3<- target translation
+    bl      dvmSelfVerificationSaveState @ save registers to shadow space
+    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
+    bx      r10                         @ jump to the translation
+
+/*
+ * Restore PC, registers, and interpreter state to original values
+ * before jumping back to the interpreter.
+ * On entry:
+ *   r0:  dPC
+ *   r2:  self verification state
+ */
+jitSVShadowRunEnd:
+    mov    r1,rFP                        @ pass ending fp
+    mov    r3,rSELF                      @ pass self ptr for convenience
+    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
+    LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
+    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
+    cmp    r1,#0                         @ check for punt condition
+    beq    1f
+    @ Set up SV single-stepping
+    mov    r0, rSELF
+    mov    r1, #kSubModeJitSV
+    bl     dvmEnableSubMode              @ (self, subMode)
+    mov    r2,#kJitSelfVerification      @ ask for self verification
+    str    r2,[rSELF,#offThread_jitState]
+    @ intentional fallthrough
+1:                                       @ exit to interpreter without check
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+common_gotoBail:
+    SAVE_PC_FP_TO_SELF()                @ export state to "thread"
+    mov     r0, rSELF                   @ r0<- self ptr
+    b       dvmMterpStdBail             @ call(self, changeInterp)
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair.  Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+    cmp     r9, #0
+    ldrne   r9, [r9, #offObject_clazz]
+    str     r0, [rSELF, #offThread_methodToCall]
+    str     r9, [rSELF, #offThread_callsiteClass]
+    bx      lr
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: r0 is "Method* methodToCall */
+    mov     r9, #0                      @ clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: r0 is "Method* methodToCall, r9 is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ prepare to copy args to "outs" area of current frame
+    add     rPC, rPC, #4                @ adjust pc to make return consistent
+    FETCH(r2, 1)                        @ r2<- BBBB (arg count)
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    cmp     r2, #0                      @ no args?
+    beq     .LinvokeArgsDone            @ if no args, skip the rest
+    FETCH(r1, 2)                        @ r1<- CCCC
+    b       .LinvokeRangeArgs           @ handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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
+
+.LinvokeRangeArgs:
+    @ 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
+1:  ldr     r1, [r3], #4                @ val = *fp++
+    subs    r2, r2, #1                  @ count--
+    str     r1, [r10], #4               @ *outs++ = val
+    bne     1b                          @ ...while count != 0
+    b       .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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)
+    beq     .LinvokeArgsDone
+
+    @ r0=methodToCall, r1=GFED, r2=count, 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
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
+    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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
+    cmp     r3, r9                      @ bottom < interpStackEnd?
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
+    blo     .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]
+
+    @ Profiling?
+    cmp     lr, #0                      @ any special modes happening?
+    bne     2f                          @ go if so
+1:
+    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
+
+    @ Update state values for the new method
+    @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     r2, #1
+    str     r2, [rSELF, #offThread_debugIsMethodEntry]
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [rSELF, #offThread_curFrame]   @ 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, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#endif
+
+2:
+    @ Profiling - record method entry.  r0: methodToCall
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    mov     r1, r0
+    mov     r0, rSELF
+    bl      dvmReportInvoke             @ (self, method)
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+    b       1b
+
+.LinvokeNative:
+    @ Prep for the native call
+    @ r0=methodToCall, r1=newFp, r10=newSaveArea
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFp (points to args)
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+
+#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
+
+    cmp     lr, #0                      @ any special SubModes active?
+    bne     11f                         @ go handle them if so
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+7:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    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
+
+11:
+    @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
+    stmfd   sp!, {r0-r3}                @ save all but subModes
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
+    ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
+
+    @ Call the native method
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+
+    @ Restore the pre-call arguments
+    ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
+
+    @ Finish up any post-invoke subMode requirements
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
+    b       7b                          @ resume
+
+.LstackOverflow:    @ r0=methodToCall
+    mov     r1, r0                      @ r1<- methodToCall
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmHandleStackOverflow
+    b       common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+    .fnend
+    .size   dalvik_mterp, .-dalvik_mterp
+#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, rSELF                   @ A0<- self
+    SAVE_PC_FP_TO_SELF()                @ export state to "self"
+    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:
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r0, rFP)
+    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+    cmp     lr, #0                      @ any special subMode handling needed?
+    bne     19f
+14:
+    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ is this a break frame?
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     15f
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+15:
+#else
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+#endif
+    beq     common_gotoBail             @ break frame, bail out completely
+
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+#if defined(WITH_JIT)
+    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
+    cmp     r10, #0                      @ caller is compiled code
+    blxne   r10
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+19:
+    @ Handle special actions
+    @ On entry, r0: StackSaveArea
+    ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
+    mov     r0, rSELF
+    bl      dvmReportReturn             @ (self)
+    SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
+    b       14b                         @ continue
+
+    /*
+     * Return handling, calls through "glue code".
+     */
+     .if    0
+.LreturnOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ 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:
+
+    EXPORT_PC()
+
+    mov     r0, rSELF
+    bl      dvmCheckSuspendPending
+
+    ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
+    mov     r1, rSELF                   @ r1<- self
+    mov     r0, r9                      @ r0<- exception
+    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
+    ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
+    mov     r3, #0                      @ r3<- NULL
+    str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
+
+    @ Special subMode?
+    cmp     r2, #0                      @ any special subMode handling needed?
+    bne     7f                          @ go if so
+8:
+    /* 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, [rSELF, #offThread_method] @ r1<- self->method
+    mov     r0, rSELF                   @ r0<- self
+    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
+    ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags
+    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, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    beq     1f                          @ no, skip ahead
+    mov     rFP, r0                     @ save relPc result in rFP
+    mov     r0, rSELF                   @ r0<- self
+    mov     r1, r9                      @ r1<- exception
+    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->interpSave.curFrame and updated PC */
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
+    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
+    str     r1, [rSELF, #offThread_method]  @ self->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, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
+
+    /* release the tracked alloc on the exception */
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+
+    /* restore the exception if the handler wants it */
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    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, [rSELF, #offThread_exception] @ yes, restore the exception
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    @ Manage debugger bookkeeping
+7:
+    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
+    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
+    mov     r0, rSELF                       @ arg0<- self
+    mov     r1, r9                          @ arg1<- exception
+    bl      dvmReportExceptionThrow         @ (self, exception)
+    b       8b                              @ resume with normal handling
+
+.LnotCaughtLocally: @ r9=exception
+    /* fix stack overflow if necessary */
+    ldrb    r1, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    movne   r0, rSELF                   @ if yes: r0<- self
+    movne   r1, r9                      @ if yes: r1<- exception
+    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, [rSELF, #offThread_method]
+    ldr     r1, [r0, #offMethod_insns]
+    sub     r1, rPC, r1
+    asr     r1, r1, #1
+    bl      dvmLineNumFromPC
+    str     r0, [sp, #-4]!
+    @ dvmGetMethodSourceFile(method)
+    ldr     r0, [rSELF, #offThread_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, [rSELF, #offThread_exception] @ restore exception
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+    b       common_gotoBail             @ bail out
+
+
+    /*
+     * Exception handling, calls through "glue code".
+     */
+    .if     0
+.LexceptionOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ arg to function
+    bl      dvmMterp_exceptionThrown
+    b       common_resumeAfterGlueCall
+    .endif
+
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including the current
+     * instruction.
+     *
+     * On entry:
+     *     r10: &dvmDex->pResFields[field]
+     *     r0:  field pointer (must preserve)
+     */
+common_verifyField:
+    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
+    ands    r3, #kSubModeJitTraceBuild
+    bxeq    lr                          @ Not building trace, continue
+    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
+    cmp     r1, #0                      @ resolution complete?
+    bxne    lr                          @ yes, continue
+    stmfd   sp!, {r0-r2,lr}             @ save regs
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
+    ldmfd   sp!, {r0-r2, lr}
+    bx      lr                          @ return
+#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_SELF()              @ pull rPC and rFP out of thread
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use r1
+ * and r3 because those just happen to be the registers all our callers are
+ * using. We move r3 before calling the C function, but r1 happens to match.
+ * r1: index
+ * r3: size
+ */
+common_errArrayIndex:
+    EXPORT_PC()
+    mov     r0, r3
+    bl      dvmThrowArrayIndexOutOfBoundsException
+    b       common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+    EXPORT_PC()
+    ldr     r0, strDivideByZero
+    bl      dvmThrowArithmeticException
+    b       common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in r1
+ */
+common_errNegativeArraySize:
+    EXPORT_PC()
+    mov     r0, r1                                @ arg0 <- len
+    bl      dvmThrowNegativeArraySizeException    @ (len)
+    b       common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in r1
+ */
+common_errNoSuchMethod:
+    EXPORT_PC()
+    mov     r0, r1
+    bl      dvmThrowNoSuchMethodError
+    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()
+    mov     r0, #0
+    bl      dvmThrowNullPointerException
+    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
+strDivideByZero:
+    .word   .LstrDivideByZero
+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"
+.LstrFilledNewArrayNotImpl:
+    .asciz  "filled-new-array only implemented for objects and 'int'"
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrLogTag:
+    .asciz  "mterp"
+.LstrExceptionNotCaughtLocally:
+    .asciz  "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+    .asciz  "\n"
+.LstrSqueak:
+    .asciz  "<%d>"
+.LstrPrintHex:
+    .asciz  "<%#x>"
+.LstrPrintLong:
+    .asciz  "<%lld>"
+
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
new file mode 100644
index 0000000..3a01a83
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -0,0 +1,27417 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv7-a-neon'.
+ *
+ * --> 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  rSELF     self (Thread) 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 rSELF   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF()     ldr     rPC, [rSELF, #offThread_pc]
+#define SAVE_PC_TO_SELF()       str     rPC, [rSELF, #offThread_pc]
+#define LOAD_FP_FROM_SELF()     ldr     rFP, [rSELF, #offThread_curFrame]
+#define SAVE_FP_TO_SELF()       str     rFP, [rSELF, #offThread_curFrame]
+#define LOAD_PC_FP_FROM_SELF()  ldmia   rSELF, {rPC, rFP}
+#define SAVE_PC_FP_TO_SELF()    stmia   rSELF, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects.  Must
+ * be done *before* something throws.
+ *
+ * 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 #1]!", 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_BASE(_base,_reg)  add     pc, _base, _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]
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+/* File: armv7-a/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier.
+ */
+.macro  SMP_DMB
+#if ANDROID_SMP != 0
+    dmb
+#else
+    /* not SMP */
+#endif
+.endm
+
+/*
+ * Macro for data memory barrier (store/store variant).
+ */
+.macro  SMP_DMB_ST
+#if ANDROID_SMP != 0
+    dmb     st
+#else
+    /* not SMP */
+#endif
+.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  Thread* self
+ *
+ * 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, #offThread_bailPtr]  @ save SP for eventual return
+
+    /* set up "named" registers, figure out entry point */
+    mov     rSELF, r0                   @ set rSELF
+    LOAD_PC_FP_FROM_SELF()              @ load rPC and rFP from "thread"
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable] @ set rIBASE
+
+#if defined(WITH_JIT)
+.LentryInstr:
+    /* Entry is always a possible trace start */
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [rSELF, #offThread_shadowSpace] @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    /* 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
+
+.Lbad_arg:
+    ldr     r0, strBadEntryPoint
+    @ r1 holds value of entryPoint
+    bl      printf
+    bl      dvmAbort
+    .fnend
+    .size   dvmMterpStdRun, .-dvmMterpStdRun
+
+
+    .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  Thread* self
+ */
+dvmMterpStdBail:
+    ldr     sp, [r0, #offThread_bailPtr]    @ sp<- saved SP
+    add     sp, sp, #4                      @ un-align 64
+    ldmfd   sp!, {r4-r10,fp,pc}             @ 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, [rSELF, #offThread_retval]    @ r0<- self->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, rSELF, #offThread_retval  @ r3<- &self->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, [rSELF, #offThread_retval]    @ r0<- self->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 */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    ldr     r3, [rSELF, #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, [rSELF, #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 "thread"
+     * 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, [rSELF, #offThread_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 "thread"
+     * 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, rSELF, #offThread_retval  @ r3<- &self->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 "thread"
+     * 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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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)
+    mov     r0, rSELF                   @ r0<- self
+    cmp     r1, #0                      @ null object?
+    EXPORT_PC()                         @ need for precise GC
+    beq     common_errNullObject        @ null object, throw an exception
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      dvmLockObject               @ call(self, obj)
+    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     1f                          @ yes
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
+    cmp     r0, #0                      @ failed?
+    FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    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, [rSELF, #offThread_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 - len in r1
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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)
+    EXPORT_PC()                         @ exception handler can throw
+    cmp     r1, #0                      @ null object?
+    beq     common_errNullObject        @ yes, throw an NPE instead
+    @ bypass dvmSetException, just store it
+    str     r1, [rSELF, #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 */
+    /* tuning: use sbfx for 6t2+ targets */
+    mov     r0, rINST, lsl #16          @ r0<- AAxx0000
+    movs    r1, r0, asr #24             @ r1<- ssssssAA (sign-extended)
+    add     r2, r1, r1                  @ r2<- byte offset, set flags
+       @ If backwards branch refresh rIBASE
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) check for trace hotness
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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)
+    adds    r1, r0, r0                  @ r1<- byte offset, flags set
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) hot trace head?
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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".  Because
+     * we need the V bit set, we'll use an adds to convert from Dalvik
+     * offset to byte offset.
+     */
+    /* goto/32 +AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    orr     r0, r0, r1, lsl #16         @ r0<- AAAAaaaa
+    adds    r1, r0, r0                  @ r1<- byte offset
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ble     common_testUpdateProfile    @ (r0) hot trace head?
+#else
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movne r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    moveq r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movge r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movlt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movle r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movgt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movne r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    moveq r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movge r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movlt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movle r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movgt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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.
+     */
+    /* 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(rINST, r2)                 @ rINST<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     rINST, #0                   @ null array object?
+    GET_VREG(r9, r9)                    @ r9<- vAA
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [rINST, #offArrayObject_length]   @ r3<- arrayObj->length
+    add     r10, rINST, r1, lsl #2      @ r10<- arrayObj + index*width
+    cmp     r1, 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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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 */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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     r9, rINST, lsr #8           @ r9<- AA
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_end
+
+/* ------------------------------ */
+    .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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodNoRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodNoRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_resolve
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_RANGE_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_RANGE_resolve
+
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+    /*
+     * Wide 32-bit instance field get.
+     */
+    /* iget-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_WIDE_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+    /* iput-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+    /*
+     * 64-bit SGET handler.
+     */
+    /* sget-wide vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+    /*
+     * 64-bit SPUT handler.
+     */
+    /* sput-wide vAA, field@BBBB */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/OP_BREAKPOINT.S */
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.
+     */
+    mov     r0, rPC
+    bl      dvmGetOriginalOpcode        @ (rPC)
+    FETCH(rINST, 0)                     @ reload OP_BREAKPOINT + rest of inst
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    and     rINST, #0xff00
+    orr     rINST, rINST, r0
+    GOTO_OPCODE_BASE(r1, r0)
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_method]    @ r0<- self->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 an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     *
+     * TUNING: could maintain two tables, pointer in Thread and
+     * swap if profiler/debuggger active.
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->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_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */
+    /*
+     * Execute a "native inline" instruction, using "/range" semantics.
+     * Same idea as execute-inline, but we get the args differently.
+     *
+     * We need to call an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     */
+    /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_RANGE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_RANGE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_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_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 2)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_RANGE_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(2+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/OP_RETURN_VOID_BARRIER.S */
+    SMP_DMB_ST
+    b       common_returnFromMethod
+
+/* ------------------------------ */
+    .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(ip, 1)                        @ ip<- field byte offset
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r3, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    ldrd    r0, [r3, ip]                @ r0<- obj.field (64 bits, aligned)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* 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 */
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card based on obj head
+    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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/OP_DISPATCH_FF.S */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/OP_CONST_CLASS_JUMBO.S */
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<-self>methodClassDex
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]   @ r2<- dvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResClasses[AAAAaaaa]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .LOP_CONST_CLASS_JUMBO_resolve
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/OP_CHECK_CAST_JUMBO.S */
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r3, 3)                        @ r3<- BBBB
+    orr     r2, r0, r2, lsl #16         @ r2<- AAAAaaaa
+    GET_VREG(r9, r3)                    @ r9<- object
+    ldr     r0, [rSELF, #offThread_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .LOP_CHECK_CAST_JUMBO_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_JUMBO_resolve         @ not resolved, do it now
+.LOP_CHECK_CAST_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .LOP_CHECK_CAST_JUMBO_fullcheck       @ no, do full check
+    b       .LOP_CHECK_CAST_JUMBO_okay            @ yes, finish up
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/OP_INSTANCE_OF_JUMBO.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.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_INSTANCE_OF.S.
+     */
+    /* instance-of/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    FETCH(r9, 3)                        @ r9<- vBBBB
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- pDvmDex
+    cmp     r0, #0                      @ is object null?
+    beq     .LOP_INSTANCE_OF_JUMBO_store           @ null obj, not an instance, store r0
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]    @ r2<- pDvmDex->pResClasses
+    orr     r3, r1, r3, lsl #16         @ r3<- AAAAaaaa
+    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_JUMBO_resolve         @ not resolved, do it now
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/OP_NEW_INSTANCE_JUMBO.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .LOP_NEW_INSTANCE_JUMBO_resolve         @ no, resolve it now
+.LOP_NEW_INSTANCE_JUMBO_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .LOP_NEW_INSTANCE_JUMBO_needinit        @ no, init class now
+.LOP_NEW_INSTANCE_JUMBO_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .LOP_NEW_INSTANCE_JUMBO_finish          @ continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/OP_NEW_ARRAY_JUMBO.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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r2, 1)                        @ r2<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- vCCCC
+    orr     r2, r2, r3, lsl #16         @ r2<- AAAAaaaa
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    GET_VREG(r1, r0)                    @ r1<- vCCCC (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 - len in r1
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .LOP_NEW_ARRAY_JUMBO_finish          @ resolved, continue
+    b       .LOP_NEW_ARRAY_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S */
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_FILLED_NEW_ARRAY.S.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    EXPORT_PC()                         @ need for resolve and alloc
+    cmp     r0, #0                      @ already resolved?
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_continue        @ yes, continue on
+8:  ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/OP_IGET_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrb", "sqnum":"1" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/OP_IGET_BYTE_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsb", "sqnum":"2" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/OP_IGET_CHAR_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrh", "sqnum":"3" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/OP_IGET_SHORT_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsh", "sqnum":"4" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    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_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/OP_IPUT_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/OP_IPUT_BYTE_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/OP_IPUT_CHAR_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/OP_IPUT_SHORT_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/OP_SGET_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BOOLEAN_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/OP_SGET_BYTE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BYTE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/OP_SGET_CHAR_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_CHAR_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/OP_SGET_SHORT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_SHORT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_JUMBO_end
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/OP_SPUT_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BOOLEAN_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/OP_SPUT_BYTE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BYTE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/OP_SPUT_CHAR_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_CHAR_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/OP_SPUT_SHORT_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_SHORT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_JUMBO.S */
+    /*
+     * Handle a virtual method call.
+     */
+    /* invoke-virtual/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_VIRTUAL_JUMBO_continue        @ yes, continue on
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/OP_INVOKE_SUPER_JUMBO.S */
+    /*
+     * Handle a "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_SUPER_JUMBO_continue        @ resolved, continue on
+    b       .LOP_INVOKE_SUPER_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/OP_INVOKE_DIRECT_JUMBO.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.)
+     *
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_JUMBO_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_JUMBO_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodJumbo    @ (r0=method, r9="this")
+    b       common_errNullObject        @ yes, throw exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/OP_INVOKE_STATIC_JUMBO.S */
+    /*
+     * Handle a static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodJumboNoThis   @ (r0=method)
+    b       .LOP_INVOKE_STATIC_JUMBO_resolve
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/OP_INVOKE_INTERFACE_JUMBO.S */
+    /*
+     * Handle an interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r2, 4)                        @ r2<- CCCC
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    EXPORT_PC()                         @ must export for invoke
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/OP_UNUSED_27FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/OP_UNUSED_28FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/OP_UNUSED_29FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/OP_UNUSED_2AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/OP_UNUSED_2BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/OP_UNUSED_2CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/OP_UNUSED_2DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/OP_UNUSED_2EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/OP_UNUSED_2FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/OP_UNUSED_30FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/OP_UNUSED_31FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/OP_UNUSED_32FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/OP_UNUSED_33FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/OP_UNUSED_34FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/OP_UNUSED_35FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/OP_UNUSED_36FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/OP_UNUSED_37FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/OP_UNUSED_38FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/OP_UNUSED_39FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/OP_UNUSED_3AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/OP_UNUSED_3BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/OP_UNUSED_3CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/OP_UNUSED_3DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/OP_UNUSED_3EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/OP_UNUSED_3FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/OP_UNUSED_40FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/OP_UNUSED_41FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/OP_UNUSED_42FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/OP_UNUSED_43FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/OP_UNUSED_44FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/OP_UNUSED_45FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/OP_UNUSED_46FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/OP_UNUSED_47FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/OP_UNUSED_48FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/OP_UNUSED_49FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/OP_UNUSED_4AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/OP_UNUSED_4BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/OP_UNUSED_4CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/OP_UNUSED_4DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/OP_UNUSED_4EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/OP_UNUSED_4FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/OP_UNUSED_50FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/OP_UNUSED_51FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/OP_UNUSED_52FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/OP_UNUSED_53FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/OP_UNUSED_54FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/OP_UNUSED_55FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/OP_UNUSED_56FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/OP_UNUSED_57FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/OP_UNUSED_58FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/OP_UNUSED_59FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/OP_UNUSED_5AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/OP_UNUSED_5BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/OP_UNUSED_5CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/OP_UNUSED_5DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/OP_UNUSED_5EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/OP_UNUSED_5FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/OP_UNUSED_60FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/OP_UNUSED_61FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/OP_UNUSED_62FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/OP_UNUSED_63FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/OP_UNUSED_64FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/OP_UNUSED_65FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/OP_UNUSED_66FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/OP_UNUSED_67FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/OP_UNUSED_68FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/OP_UNUSED_69FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/OP_UNUSED_6AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/OP_UNUSED_6BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/OP_UNUSED_6CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/OP_UNUSED_6DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/OP_UNUSED_6EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/OP_UNUSED_6FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/OP_UNUSED_70FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/OP_UNUSED_71FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/OP_UNUSED_72FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/OP_UNUSED_73FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/OP_UNUSED_74FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/OP_UNUSED_75FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/OP_UNUSED_76FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/OP_UNUSED_77FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/OP_UNUSED_78FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/OP_UNUSED_79FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/OP_UNUSED_7AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/OP_UNUSED_7BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/OP_UNUSED_7CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/OP_UNUSED_7DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/OP_UNUSED_7EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/OP_UNUSED_7FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/OP_UNUSED_80FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/OP_UNUSED_81FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/OP_UNUSED_82FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/OP_UNUSED_83FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/OP_UNUSED_84FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/OP_UNUSED_85FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/OP_UNUSED_86FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/OP_UNUSED_87FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/OP_UNUSED_88FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/OP_UNUSED_89FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/OP_UNUSED_8AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/OP_UNUSED_8BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/OP_UNUSED_8CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/OP_UNUSED_8DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/OP_UNUSED_8EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/OP_UNUSED_8FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/OP_UNUSED_90FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/OP_UNUSED_91FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/OP_UNUSED_92FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/OP_UNUSED_93FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/OP_UNUSED_94FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/OP_UNUSED_95FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/OP_UNUSED_96FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/OP_UNUSED_97FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/OP_UNUSED_98FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/OP_UNUSED_99FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/OP_UNUSED_9AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/OP_UNUSED_9BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/OP_UNUSED_9CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/OP_UNUSED_9DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/OP_UNUSED_9EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/OP_UNUSED_9FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/OP_UNUSED_A0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/OP_UNUSED_A1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/OP_UNUSED_A2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/OP_UNUSED_A3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/OP_UNUSED_A4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/OP_UNUSED_A5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/OP_UNUSED_A6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/OP_UNUSED_A7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/OP_UNUSED_A8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/OP_UNUSED_A9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/OP_UNUSED_AAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/OP_UNUSED_ABFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/OP_UNUSED_ACFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/OP_UNUSED_ADFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/OP_UNUSED_AEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/OP_UNUSED_AFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/OP_UNUSED_B0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/OP_UNUSED_B1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/OP_UNUSED_B2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/OP_UNUSED_B3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/OP_UNUSED_B4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/OP_UNUSED_B5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/OP_UNUSED_B6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/OP_UNUSED_B7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/OP_UNUSED_B8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/OP_UNUSED_B9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/OP_UNUSED_BAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/OP_UNUSED_BBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/OP_UNUSED_BCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/OP_UNUSED_BDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/OP_UNUSED_BEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/OP_UNUSED_BFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/OP_UNUSED_C0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/OP_UNUSED_C1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/OP_UNUSED_C2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/OP_UNUSED_C3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/OP_UNUSED_C4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/OP_UNUSED_C5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/OP_UNUSED_C6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/OP_UNUSED_C7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/OP_UNUSED_C8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/OP_UNUSED_C9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/OP_UNUSED_CAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/OP_UNUSED_CBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/OP_UNUSED_CCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/OP_UNUSED_CDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/OP_UNUSED_CEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/OP_UNUSED_CFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/OP_UNUSED_D0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/OP_UNUSED_D1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/OP_UNUSED_D2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/OP_UNUSED_D3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/OP_UNUSED_D4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/OP_UNUSED_D5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/OP_UNUSED_D6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/OP_UNUSED_D7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/OP_UNUSED_D8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/OP_UNUSED_D9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/OP_UNUSED_DAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/OP_UNUSED_DBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/OP_UNUSED_DCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/OP_UNUSED_DDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/OP_UNUSED_DEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/OP_UNUSED_DFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/OP_UNUSED_E0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/OP_UNUSED_E1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/OP_UNUSED_E2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/OP_UNUSED_E3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/OP_UNUSED_E4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/OP_UNUSED_E5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/OP_UNUSED_E6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/OP_UNUSED_E7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/OP_UNUSED_E8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/OP_UNUSED_E9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/OP_UNUSED_EAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/OP_UNUSED_EBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/OP_UNUSED_ECFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/OP_UNUSED_EDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/OP_UNUSED_EEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/OP_UNUSED_EFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/OP_UNUSED_F0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/OP_UNUSED_F1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 4)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_JUMBO_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(4+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/OP_IGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/OP_IPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/OP_SGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/OP_SPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR_JUMBO.S */
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, Class@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    orr     r2, r1, r2, lsl #16         @ r2<- AAAAaaaa
+    EXPORT_PC()                         @ export the PC
+    FETCH(r1, 3)                        @ r1<- BBBB
+    bl      dvmThrowVerificationError   @ always throws
+    b       common_exceptionThrown      @ handle exception
+
+    .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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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 desired class resolved from BBBB
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    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.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method]    @ r0<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_end:
+    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
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * 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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method] @ r3<- self->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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     0
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     1
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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:
+     *  rINST = 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, [rINST, #offObject_clazz]  @ r1<- arrayObj->clazz
+    bl      dvmCanPutArrayElement       @ test object type vs. array type
+    cmp     r0, #0                      @ okay?
+    beq     .LOP_APUT_OBJECT_throw           @ no
+    mov     r1, rINST                   @ r1<- arrayObj
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rSELF, #offThread_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r1, lsr #GC_CARD_SHIFT] @ mark card using object head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_skip_check:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_throw:
+    @ The types don't match.  We need to throw an ArrayStoreException.
+    ldr     r0, [r9, #offObject_clazz]
+    ldr     r1, [rINST, #offObject_clazz]
+    EXPORT_PC()
+    bl      dvmThrowArrayStoreExceptionIncompatibleElement
+    b       common_exceptionThrown
+
+/* 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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+    /*
+     * 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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_finish
+
+/* continuation for OP_SGET_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_finish          @ resume
+
+/* continuation for OP_SGET_OBJECT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_finish
+
+/* continuation for OP_SGET_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_finish
+
+/* continuation for OP_SGET_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_finish
+
+/* continuation for OP_SGET_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_finish
+
+/* continuation for OP_SGET_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_finish
+
+/* continuation for OP_SPUT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT */
+
+
+.LOP_SPUT_OBJECT_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_finish          @ resume
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodNoRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC */
+
+
+.LOP_INVOKE_STATIC_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodNoRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodNoRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodNoRange     @ whew, finally!
+#else
+    bne     common_invokeMethodNoRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_RANGE_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_RANGE_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_RANGE */
+
+
+.LOP_INVOKE_STATIC_RANGE_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodRange     @ whew, finally!
+#else
+    bne     common_invokeMethodRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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_IGET_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_finish
+
+/* continuation for OP_SPUT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_finish          @ resume
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    cmp     r9, #0                      @ check object for null
+    and     r2, r2, #15                 @ r2<- A
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[A]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_VOLATILE_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_finish          @ resume
+
+/* 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(rINST, 2)                     @ rINST<- FEDC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  and     ip, rINST, #0xf000          @ isolate F
+    ldr     r3, [rFP, ip, lsr #10]      @ r3<- vF (shift right 12, left 2)
+3:  and     ip, rINST, #0x0f00          @ isolate E
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vE
+2:  and     ip, rINST, #0x00f0          @ isolate D
+    ldr     r1, [rFP, ip, lsr #2]       @ r1<- vD
+1:  and     ip, rINST, #0x000f          @ isolate C
+    ldr     r0, [rFP, ip, lsl #2]       @ r0<- vC
+0:
+    ldr     rINST, .LOP_EXECUTE_INLINE_table    @ table of InlineOperation
+    ldr     pc, [rINST, r10, lsl #4]    @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_continue        @ make call; will return after
+    mov     rINST, r0                   @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, r9                      @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit @ (method, self)
+    cmp     rINST, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_table:
+    .word   gDvmInlineOpsTable
+
+/* continuation for OP_EXECUTE_INLINE_RANGE */
+
+    /*
+     * 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]
+     */
+.LOP_EXECUTE_INLINE_RANGE_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(r9, 2)                        @ r9<- CCCC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  add     ip, r9, #3                  @ base+3
+    GET_VREG(r3, ip)                    @ r3<- vBase[3]
+3:  add     ip, r9, #2                  @ base+2
+    GET_VREG(r2, ip)                    @ r2<- vBase[2]
+2:  add     ip, r9, #1                  @ base+1
+    GET_VREG(r1, ip)                    @ r1<- vBase[1]
+1:  add     ip, r9, #0                  @ (nop)
+    GET_VREG(r0, ip)                    @ r0<- vBase[0]
+0:
+    ldr     r9, .LOP_EXECUTE_INLINE_RANGE_table       @ table of InlineOperation
+    ldr     pc, [r9, r10, lsl #4]       @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_RANGE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_RANGE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- B
+    mov     rINST, r9                   @ rINST<- method
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_continue        @ make call; will return after
+    mov     r9, r0                      @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, rINST                   @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit  @ (method, self)
+    cmp     r9, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_RANGE_table:
+    .word   gDvmInlineOpsTable
+
+
+/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
+
+.LOP_INVOKE_OBJECT_INIT_RANGE_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_RANGE_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_RANGE_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 0
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_finish
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_finish          @ resume
+
+
+/* continuation for OP_CONST_CLASS_JUMBO */
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: AAAAAAAA (Class ref)
+     *  r9: target register
+     */
+.LOP_CONST_CLASS_JUMBO_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_CHECK_CAST_JUMBO */
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds desired class resolved from AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .LOP_CHECK_CAST_JUMBO_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    b       common_exceptionThrown
+
+    /*
+     * Advance PC and get the next opcode.
+     */
+.LOP_CHECK_CAST_JUMBO_okay:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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 AAAAAAAA
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_CHECK_CAST_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_INSTANCE_OF_JUMBO */
+
+    /*
+     * Class resolved, determine type of check necessary.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .LOP_INSTANCE_OF_JUMBO_trivial         @ yes, trivial finish
+    @ fall through to OP_INSTANCE_OF_JUMBO_fullcheck
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to OP_INSTANCE_OF_JUMBO_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_store:
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b OP_INSTANCE_OF_JUMBO_store, but copying is faster and cheaper
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- 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 AAAAAAAA
+     *  r9 holds BBBB
+     */
+
+.LOP_INSTANCE_OF_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    mov     r1, r3                      @ r1<- AAAAAAAA
+    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
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    mov     r1, r0                      @ r1<- class resolved from AAAAAAAA
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_NEW_INSTANCE_JUMBO */
+
+    .balign 32                          @ minimize cache lines
+.LOP_NEW_INSTANCE_JUMBO_finish: @ r0=new object
+    FETCH(r3, 3)                        @ r3<- BBBB
+    cmp     r0, #0                      @ failed?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_JUMBO_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_JUMBO_end:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_JUMBO_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.LOP_NEW_INSTANCE_JUMBO_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_JUMBO_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds AAAAAAAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_NEW_ARRAY_JUMBO */
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref AAAAAAAA
+     */
+.LOP_NEW_ARRAY_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r9, r1                      @ r9<- length (save)
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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_JUMBO_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.LOP_NEW_ARRAY_JUMBO_finish:
+    mov     r2, #ALLOC_DONT_TRACK       @ don't track in local refs table
+    bl      dvmAllocArrayByClass        @ r0<- call(clazz, length, flags)
+    cmp     r0, #0                      @ failed?
+    FETCH(r2, 3)                        @ r2<- vBBBB
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_FILLED_NEW_ARRAY_JUMBO */
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    FETCH(r1, 3)                        @ r1<- BBBB (length)
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_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, 4)                        @ r1<- CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(5)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC, r9=BBBB (length)
+    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
+
+2:  ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    GOTO_OPCODE(ip)                          @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_notimpl:
+    ldr     r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* continuation for OP_IGET_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     0
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     0
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_finish:
+    @bl      common_squeak1
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_finish:
+    @bl      common_squeak2
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_finish:
+    @bl      common_squeak3
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_finish:
+    @bl      common_squeak4
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_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_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_JUMBO */
+
+
+.LOP_SPUT_OBJECT_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_JUMBO_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_INVOKE_VIRTUAL_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     */
+.LOP_INVOKE_VIRTUAL_JUMBO_continue:
+    FETCH(r10, 4)                       @ r10<- CCCC
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_JUMBO_continue:
+    ldr     r1, [r10, #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_JUMBO_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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+.LOP_INVOKE_SUPER_JUMBO_resolve:
+    mov     r0, r10                     @ 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_JUMBO_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_JUMBO_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
+
+/* continuation for OP_INVOKE_DIRECT_JUMBO */
+
+    /*
+     * On entry:
+     *  r1 = reference (CCCC)
+     *  r10 = "this" register
+     */
+.LOP_INVOKE_DIRECT_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_JUMBO_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_JUMBO */
+
+
+.LOP_INVOKE_STATIC_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodJumboNoThis    @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodJumboNoThis    @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodJumboNoThis    @ whew, finally!
+#else
+    bne     common_invokeMethodJumboNoThis    @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* continuation for OP_INVOKE_OBJECT_INIT_JUMBO */
+
+.LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_JUMBO_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_JUMBO_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 1
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IGET_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_WIDE_VOLATILE_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE_JUMBO */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+
+    .global dvmAsmAltInstructionStart
+    .type   dvmAsmAltInstructionStart, %function
+    .text
+
+dvmAsmAltInstructionStart = .L_ALT_OP_NOP
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOP: /* 0x00 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (0 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE: /* 0x01 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (1 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (2 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (3 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (4 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (5 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (6 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (7 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (8 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (9 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (10 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (11 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (12 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (13 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID: /* 0x0e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (14 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN: /* 0x0f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (15 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (16 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (17 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_4: /* 0x12 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (18 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_16: /* 0x13 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (19 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST: /* 0x14 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (20 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (21 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (22 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (23 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (24 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (25 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (26 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (27 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (28 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (29 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (30 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST: /* 0x1f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (31 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (32 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (33 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (34 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (35 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (36 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (37 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (38 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW: /* 0x27 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (39 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO: /* 0x28 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (40 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (41 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (42 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (43 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (44 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_FLOAT: /* 0x2d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (45 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_FLOAT: /* 0x2e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (46 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (47 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (48 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (49 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQ: /* 0x32 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (50 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NE: /* 0x33 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (51 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LT: /* 0x34 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (52 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GE: /* 0x35 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (53 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GT: /* 0x36 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (54 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LE: /* 0x37 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (55 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (56 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (57 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (58 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (59 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (60 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (61 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (62 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (63 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (64 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (65 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (66 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (67 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET: /* 0x44 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (68 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (69 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (70 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (71 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (72 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (73 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (74 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT: /* 0x4b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (75 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (76 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (77 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (78 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (79 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (80 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (81 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET: /* 0x52 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (82 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE: /* 0x53 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (83 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (84 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (85 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (86 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (87 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (88 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT: /* 0x59 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (89 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE: /* 0x5a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (90 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (91 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (92 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (93 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (94 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (95 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET: /* 0x60 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (96 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE: /* 0x61 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (97 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (98 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (99 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE: /* 0x64 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (100 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR: /* 0x65 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (101 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT: /* 0x66 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (102 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT: /* 0x67 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (103 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (104 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (105 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (106 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (107 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (108 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (109 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (110 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (111 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (112 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (113 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (114 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (115 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (116 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (117 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (118 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (119 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (120 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (121 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (122 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_INT: /* 0x7b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (123 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_INT: /* 0x7c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (124 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_LONG: /* 0x7d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (125 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_LONG: /* 0x7e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (126 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (127 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (128 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (129 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (130 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (131 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (132 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (133 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (134 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (135 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (136 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (137 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (138 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (139 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (140 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (141 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (142 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (143 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (144 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (145 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (146 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (147 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT: /* 0x94 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (148 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT: /* 0x95 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (149 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT: /* 0x96 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (150 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (151 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (152 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (153 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (154 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (155 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (156 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (157 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (158 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (159 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (160 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (161 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (162 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (163 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (164 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (165 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT: /* 0xa6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (166 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT: /* 0xa7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (167 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT: /* 0xa8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (168 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT: /* 0xa9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (169 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (170 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE: /* 0xab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (171 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE: /* 0xac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (172 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE: /* 0xad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (173 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE: /* 0xae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (174 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (175 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (176 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (177 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (178 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (179 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (180 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (181 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (182 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (183 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (184 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (185 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (186 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (187 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (188 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (189 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (190 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (191 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (192 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (193 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (194 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (195 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (196 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (197 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (198 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (199 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (200 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (201 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (202 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (203 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (204 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (205 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (206 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (207 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (208 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT: /* 0xd1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (209 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (210 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (211 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (212 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (213 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (214 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (215 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (216 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (217 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (218 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (219 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (220 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (221 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (222 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (223 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (224 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (225 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (226 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (227 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (228 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (229 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (230 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (231 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (232 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (233 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (234 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (235 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (236 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (237 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (238 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (239 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (240 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (241 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (242 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (243 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (244 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_QUICK: /* 0xf5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (245 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (246 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (247 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (248 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (249 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (250 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (251 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (252 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (253 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (254 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/ALT_OP_DISPATCH_FF.S */
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (256 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (257 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (258 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (259 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (260 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (261 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (262 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (263 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (264 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (265 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (266 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (267 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (268 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (269 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (270 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (271 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (272 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (273 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (274 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (275 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (276 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (277 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (278 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (279 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (280 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (281 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (282 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (283 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (284 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (285 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (286 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (287 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (288 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (289 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (290 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (291 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (292 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (293 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (294 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (295 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (296 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (297 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (298 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (299 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (300 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (301 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (302 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (303 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (304 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (305 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (306 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (307 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (308 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (309 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (310 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (311 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (312 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (313 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (314 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (315 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (316 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (317 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (318 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (319 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (320 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (321 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (322 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (323 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (324 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (325 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (326 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (327 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (328 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (329 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (330 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (331 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (332 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (333 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (334 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (335 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (336 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (337 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (338 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (339 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (340 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (341 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (342 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (343 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (344 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (345 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (346 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (347 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (348 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (349 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (350 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (351 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (352 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (353 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (354 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (355 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (356 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (357 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (358 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (359 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (360 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (361 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (362 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (363 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (364 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (365 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (366 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (367 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (368 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (369 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (370 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (371 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (372 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (373 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (374 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (375 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (376 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (377 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (378 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (379 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (380 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (381 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (382 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (383 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (384 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (385 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (386 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (387 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (388 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (389 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (390 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (391 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (392 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (393 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (394 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (395 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (396 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (397 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (398 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (399 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (400 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (401 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (402 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (403 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (404 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (405 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (406 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (407 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (408 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (409 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (410 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (411 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (412 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (413 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (414 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (415 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (416 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (417 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (418 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (419 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (420 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (421 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (422 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (423 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (424 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (425 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (426 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (427 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (428 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (429 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (430 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (431 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (432 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (433 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (434 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (435 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (436 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (437 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (438 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (439 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (440 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (441 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (442 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (443 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (444 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (445 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (446 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (447 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (448 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (449 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (450 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (451 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (452 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (453 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (454 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (455 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (456 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (457 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (458 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (459 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (460 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (461 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (462 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (463 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (464 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (465 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (466 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (467 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (468 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (469 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (470 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (471 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (472 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (473 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (474 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (475 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (476 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (477 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (478 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (479 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (480 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (481 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (482 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (483 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (484 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (485 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (486 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (487 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (488 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (489 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (490 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (491 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (492 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (493 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (494 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (495 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (496 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (497 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (498 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (499 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (500 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (501 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (502 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (503 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (504 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (505 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (506 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (507 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (508 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (509 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (510 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (511 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+    .balign 64
+    .size   dvmAsmAltInstructionStart, .-dvmAsmAltInstructionStart
+    .global dvmAsmAltInstructionEnd
+dvmAsmAltInstructionEnd:
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+
+#if defined(WITH_JIT)
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * "longjmp" to a translation after single-stepping.  Before returning
+ * to translation, must save state for self-verification.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    b      jitSVShadowRunStart                   @ resume as if cache hit
+                                                 @ expects resume addr in r10
+
+    .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
+    mov    r3, #0
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
+    b      jitSVShadowRunEnd            @ doesn't return
+
+
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+#else
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r0, [rSELF,#offThread_jitResumeNPC]
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    bx     r0                                    @ resume translation
+
+/*
+ * 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
+#if defined(WITH_JIT_TUNING)
+    mov    r0,lr
+    bl     dvmBumpPunt;
+#endif
+    EXPORT_PC()
+    mov    r0, #0
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * We'll use the normal single-stepping mechanism via interpBreak,
+ * but also save the native pc of the resume point in the translation
+ * and the native sp so that we can later do the equivalent of a
+ * longjmp() to resume.
+ * On entry:
+ *    dPC <= Dalvik PC of instrucion to interpret
+ *    lr <= resume point in translation
+ *    r1 <= Dalvik PC of next instruction
+ */
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r1, #1
+    str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
+    mov    r0, rSELF
+    mov    r1, #kSubModeCountedStep
+    bl     dvmEnableSubMode     @ (self, newMode)
+    ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used for callees.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0                    @ !0 means translation exists
+    bxne   r0                       @ continue native execution if so
+    b      2f                       @ branch over to use the interpreter
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used following
+ * invokes.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    rPC,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST, #-4              @  .. which is 9 bytes back
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    2f
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @ in case target is HANDLER_INTERPRET
+    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:
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    cmp    r0, #0
+    movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
+    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,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST,#-4               @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNormal
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    toInterpreter            @ go if not, otherwise do chain
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    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 dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+#endif
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & 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()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    @ NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+common_testUpdateProfile:
+    cmp     r0, #0               @ JIT switched off?
+    beq     4f                   @ return to interp if so
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ *    r0    <= pJitProfTable (verified non-NULL)
+ *    rPC   <= Dalvik PC
+ *    rINST <= next instruction
+ */
+common_updateProfile:
+    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+    lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
+    ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
+    GET_INST_OPCODE(ip)
+    subs    r1,r1,#1           @ decrement counter
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
+    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
+
+    /* Looks good, reset the counter */
+    ldr     r1, [rSELF, #offThread_jitThreshold]
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
+    EXPORT_PC()
+    mov     r0,rPC
+    mov     r1,rSELF
+    bl      dvmJitGetTraceAddrThread    @ (pc, self)
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov     r1, rPC                     @ arg1 of translation may need this
+    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
+    cmp     r0,#0
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    r0                          @ jump to the translation
+    mov     r2,#kJitTSelectRequest      @ ask for trace selection
+    @ fall-through to common_selectTrace
+#else
+    moveq   r2,#kJitTSelectRequest      @ ask for trace selection
+    beq     common_selectTrace
+    /*
+     * At this point, we have a target translation.  However, if
+     * that translation is actually the interpret-only pseudo-translation
+     * we want to treat it the same as no translation.
+     */
+    mov     r10, r0                     @ save target
+    bl      dvmCompilerGetInterpretTemplate
+    cmp     r0, r10                     @ special case?
+    bne     jitSVShadowRunStart         @ set up self verification shadow space
+    @ Need to clear the inJitCodeCache flag
+    mov    r3, #0                       @ 0 means not in the JIT code cache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+/*
+ * On entry:
+ *  r2 is jit state.
+ */
+common_selectTrace:
+    ldrh    r0,[rSELF,#offThread_subMode]
+    ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
+    bne     3f                         @ already doing JIT work, continue
+    str     r2,[rSELF,#offThread_jitState]
+    mov     r0, rSELF
+/*
+ * Call out to validate trace-building request.  If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+    EXPORT_PC()
+    SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
+    bl      dvmJitCheckTraceRequest
+3:
+    FETCH_INST()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+4:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ *    rPC, rFP, rSELF: the values that they should contain
+ *    r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+    mov     r0,rPC                      @ r0<- program counter
+    mov     r1,rFP                      @ r1<- frame pointer
+    mov     r2,rSELF                    @ r2<- self (Thread) pointer
+    mov     r3,r10                      @ r3<- target translation
+    bl      dvmSelfVerificationSaveState @ save registers to shadow space
+    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
+    bx      r10                         @ jump to the translation
+
+/*
+ * Restore PC, registers, and interpreter state to original values
+ * before jumping back to the interpreter.
+ * On entry:
+ *   r0:  dPC
+ *   r2:  self verification state
+ */
+jitSVShadowRunEnd:
+    mov    r1,rFP                        @ pass ending fp
+    mov    r3,rSELF                      @ pass self ptr for convenience
+    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
+    LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
+    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
+    cmp    r1,#0                         @ check for punt condition
+    beq    1f
+    @ Set up SV single-stepping
+    mov    r0, rSELF
+    mov    r1, #kSubModeJitSV
+    bl     dvmEnableSubMode              @ (self, subMode)
+    mov    r2,#kJitSelfVerification      @ ask for self verification
+    str    r2,[rSELF,#offThread_jitState]
+    @ intentional fallthrough
+1:                                       @ exit to interpreter without check
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+common_gotoBail:
+    SAVE_PC_FP_TO_SELF()                @ export state to "thread"
+    mov     r0, rSELF                   @ r0<- self ptr
+    b       dvmMterpStdBail             @ call(self, changeInterp)
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair.  Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+    cmp     r9, #0
+    ldrne   r9, [r9, #offObject_clazz]
+    str     r0, [rSELF, #offThread_methodToCall]
+    str     r9, [rSELF, #offThread_callsiteClass]
+    bx      lr
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: r0 is "Method* methodToCall */
+    mov     r9, #0                      @ clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: r0 is "Method* methodToCall, r9 is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ prepare to copy args to "outs" area of current frame
+    add     rPC, rPC, #4                @ adjust pc to make return consistent
+    FETCH(r2, 1)                        @ r2<- BBBB (arg count)
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    cmp     r2, #0                      @ no args?
+    beq     .LinvokeArgsDone            @ if no args, skip the rest
+    FETCH(r1, 2)                        @ r1<- CCCC
+    b       .LinvokeRangeArgs           @ handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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
+
+.LinvokeRangeArgs:
+    @ 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
+1:  ldr     r1, [r3], #4                @ val = *fp++
+    subs    r2, r2, #1                  @ count--
+    str     r1, [r10], #4               @ *outs++ = val
+    bne     1b                          @ ...while count != 0
+    b       .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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)
+    beq     .LinvokeArgsDone
+
+    @ r0=methodToCall, r1=GFED, r2=count, 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
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
+    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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
+    cmp     r3, r9                      @ bottom < interpStackEnd?
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
+    blo     .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]
+
+    @ Profiling?
+    cmp     lr, #0                      @ any special modes happening?
+    bne     2f                          @ go if so
+1:
+    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
+
+    @ Update state values for the new method
+    @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     r2, #1
+    str     r2, [rSELF, #offThread_debugIsMethodEntry]
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [rSELF, #offThread_curFrame]   @ 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, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#endif
+
+2:
+    @ Profiling - record method entry.  r0: methodToCall
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    mov     r1, r0
+    mov     r0, rSELF
+    bl      dvmReportInvoke             @ (self, method)
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+    b       1b
+
+.LinvokeNative:
+    @ Prep for the native call
+    @ r0=methodToCall, r1=newFp, r10=newSaveArea
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFp (points to args)
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+
+#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
+
+    cmp     lr, #0                      @ any special SubModes active?
+    bne     11f                         @ go handle them if so
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+7:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    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
+
+11:
+    @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
+    stmfd   sp!, {r0-r3}                @ save all but subModes
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
+    ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
+
+    @ Call the native method
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+
+    @ Restore the pre-call arguments
+    ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
+
+    @ Finish up any post-invoke subMode requirements
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
+    b       7b                          @ resume
+
+.LstackOverflow:    @ r0=methodToCall
+    mov     r1, r0                      @ r1<- methodToCall
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmHandleStackOverflow
+    b       common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+    .fnend
+    .size   dalvik_mterp, .-dalvik_mterp
+#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, rSELF                   @ A0<- self
+    SAVE_PC_FP_TO_SELF()                @ export state to "self"
+    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:
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r0, rFP)
+    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+    cmp     lr, #0                      @ any special subMode handling needed?
+    bne     19f
+14:
+    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ is this a break frame?
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     15f
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+15:
+#else
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+#endif
+    beq     common_gotoBail             @ break frame, bail out completely
+
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+#if defined(WITH_JIT)
+    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
+    cmp     r10, #0                      @ caller is compiled code
+    blxne   r10
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+19:
+    @ Handle special actions
+    @ On entry, r0: StackSaveArea
+    ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
+    mov     r0, rSELF
+    bl      dvmReportReturn             @ (self)
+    SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
+    b       14b                         @ continue
+
+    /*
+     * Return handling, calls through "glue code".
+     */
+     .if    0
+.LreturnOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ 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:
+
+    EXPORT_PC()
+
+    mov     r0, rSELF
+    bl      dvmCheckSuspendPending
+
+    ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
+    mov     r1, rSELF                   @ r1<- self
+    mov     r0, r9                      @ r0<- exception
+    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
+    ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
+    mov     r3, #0                      @ r3<- NULL
+    str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
+
+    @ Special subMode?
+    cmp     r2, #0                      @ any special subMode handling needed?
+    bne     7f                          @ go if so
+8:
+    /* 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, [rSELF, #offThread_method] @ r1<- self->method
+    mov     r0, rSELF                   @ r0<- self
+    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
+    ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags
+    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, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    beq     1f                          @ no, skip ahead
+    mov     rFP, r0                     @ save relPc result in rFP
+    mov     r0, rSELF                   @ r0<- self
+    mov     r1, r9                      @ r1<- exception
+    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->interpSave.curFrame and updated PC */
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
+    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
+    str     r1, [rSELF, #offThread_method]  @ self->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, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
+
+    /* release the tracked alloc on the exception */
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+
+    /* restore the exception if the handler wants it */
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    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, [rSELF, #offThread_exception] @ yes, restore the exception
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    @ Manage debugger bookkeeping
+7:
+    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
+    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
+    mov     r0, rSELF                       @ arg0<- self
+    mov     r1, r9                          @ arg1<- exception
+    bl      dvmReportExceptionThrow         @ (self, exception)
+    b       8b                              @ resume with normal handling
+
+.LnotCaughtLocally: @ r9=exception
+    /* fix stack overflow if necessary */
+    ldrb    r1, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    movne   r0, rSELF                   @ if yes: r0<- self
+    movne   r1, r9                      @ if yes: r1<- exception
+    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, [rSELF, #offThread_method]
+    ldr     r1, [r0, #offMethod_insns]
+    sub     r1, rPC, r1
+    asr     r1, r1, #1
+    bl      dvmLineNumFromPC
+    str     r0, [sp, #-4]!
+    @ dvmGetMethodSourceFile(method)
+    ldr     r0, [rSELF, #offThread_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, [rSELF, #offThread_exception] @ restore exception
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+    b       common_gotoBail             @ bail out
+
+
+    /*
+     * Exception handling, calls through "glue code".
+     */
+    .if     0
+.LexceptionOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ arg to function
+    bl      dvmMterp_exceptionThrown
+    b       common_resumeAfterGlueCall
+    .endif
+
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including the current
+     * instruction.
+     *
+     * On entry:
+     *     r10: &dvmDex->pResFields[field]
+     *     r0:  field pointer (must preserve)
+     */
+common_verifyField:
+    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
+    ands    r3, #kSubModeJitTraceBuild
+    bxeq    lr                          @ Not building trace, continue
+    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
+    cmp     r1, #0                      @ resolution complete?
+    bxne    lr                          @ yes, continue
+    stmfd   sp!, {r0-r2,lr}             @ save regs
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
+    ldmfd   sp!, {r0-r2, lr}
+    bx      lr                          @ return
+#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_SELF()              @ pull rPC and rFP out of thread
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use r1
+ * and r3 because those just happen to be the registers all our callers are
+ * using. We move r3 before calling the C function, but r1 happens to match.
+ * r1: index
+ * r3: size
+ */
+common_errArrayIndex:
+    EXPORT_PC()
+    mov     r0, r3
+    bl      dvmThrowArrayIndexOutOfBoundsException
+    b       common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+    EXPORT_PC()
+    ldr     r0, strDivideByZero
+    bl      dvmThrowArithmeticException
+    b       common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in r1
+ */
+common_errNegativeArraySize:
+    EXPORT_PC()
+    mov     r0, r1                                @ arg0 <- len
+    bl      dvmThrowNegativeArraySizeException    @ (len)
+    b       common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in r1
+ */
+common_errNoSuchMethod:
+    EXPORT_PC()
+    mov     r0, r1
+    bl      dvmThrowNoSuchMethodError
+    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()
+    mov     r0, #0
+    bl      dvmThrowNullPointerException
+    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
+strDivideByZero:
+    .word   .LstrDivideByZero
+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"
+.LstrFilledNewArrayNotImpl:
+    .asciz  "filled-new-array only implemented for objects and 'int'"
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrLogTag:
+    .asciz  "mterp"
+.LstrExceptionNotCaughtLocally:
+    .asciz  "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+    .asciz  "\n"
+.LstrSqueak:
+    .asciz  "<%d>"
+.LstrPrintHex:
+    .asciz  "<%#x>"
+.LstrPrintLong:
+    .asciz  "<%lld>"
+
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
new file mode 100644
index 0000000..e8a9501
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -0,0 +1,27417 @@
+/*
+ * 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  rSELF     self (Thread) 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 rSELF   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/* save/restore the PC and/or FP from the thread struct */
+#define LOAD_PC_FROM_SELF()     ldr     rPC, [rSELF, #offThread_pc]
+#define SAVE_PC_TO_SELF()       str     rPC, [rSELF, #offThread_pc]
+#define LOAD_FP_FROM_SELF()     ldr     rFP, [rSELF, #offThread_curFrame]
+#define SAVE_FP_TO_SELF()       str     rFP, [rSELF, #offThread_curFrame]
+#define LOAD_PC_FP_FROM_SELF()  ldmia   rSELF, {rPC, rFP}
+#define SAVE_PC_FP_TO_SELF()    stmia   rSELF, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects.  Must
+ * be done *before* something throws.
+ *
+ * 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 #1]!", 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_BASE(_base,_reg)  add     pc, _base, _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]
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+/* File: armv7-a/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP"
+#endif
+
+/*
+ * Macro for data memory barrier.
+ */
+.macro  SMP_DMB
+#if ANDROID_SMP != 0
+    dmb
+#else
+    /* not SMP */
+#endif
+.endm
+
+/*
+ * Macro for data memory barrier (store/store variant).
+ */
+.macro  SMP_DMB_ST
+#if ANDROID_SMP != 0
+    dmb     st
+#else
+    /* not SMP */
+#endif
+.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  Thread* self
+ *
+ * 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, #offThread_bailPtr]  @ save SP for eventual return
+
+    /* set up "named" registers, figure out entry point */
+    mov     rSELF, r0                   @ set rSELF
+    LOAD_PC_FP_FROM_SELF()              @ load rPC and rFP from "thread"
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable] @ set rIBASE
+
+#if defined(WITH_JIT)
+.LentryInstr:
+    /* Entry is always a possible trace start */
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    mov     r1, #0                      @ prepare the value for the new state
+    str     r1, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    cmp     r0,#0                       @ is profiling disabled?
+#if !defined(WITH_SELF_VERIFICATION)
+    bne     common_updateProfile        @ profiling is enabled
+#else
+    ldr     r2, [rSELF, #offThread_shadowSpace] @ to find out the jit exit state
+    beq     1f                          @ profiling is disabled
+    ldr     r3, [r2, #offShadowSpace_jitExitState]  @ jit exit state
+    cmp     r3, #kSVSTraceSelect        @ hot trace following?
+    moveq   r2,#kJitTSelectRequestHot   @ ask for trace selection
+    beq     common_selectTrace          @ go build the trace
+    cmp     r3, #kSVSNoProfile          @ don't profile the next instruction?
+    beq     1f                          @ intrepret the next instruction
+    b       common_updateProfile        @ collect profiles
+#endif
+1:
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    /* 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
+
+.Lbad_arg:
+    ldr     r0, strBadEntryPoint
+    @ r1 holds value of entryPoint
+    bl      printf
+    bl      dvmAbort
+    .fnend
+    .size   dvmMterpStdRun, .-dvmMterpStdRun
+
+
+    .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  Thread* self
+ */
+dvmMterpStdBail:
+    ldr     sp, [r0, #offThread_bailPtr]    @ sp<- saved SP
+    add     sp, sp, #4                      @ un-align 64
+    ldmfd   sp!, {r4-r10,fp,pc}             @ 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, [rSELF, #offThread_retval]    @ r0<- self->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, rSELF, #offThread_retval  @ r3<- &self->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, [rSELF, #offThread_retval]    @ r0<- self->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 */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    ldr     r3, [rSELF, #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, [rSELF, #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 "thread"
+     * 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, [rSELF, #offThread_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 "thread"
+     * 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, rSELF, #offThread_retval  @ r3<- &self->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 "thread"
+     * 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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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, [rSELF, #offThread_methodClassDex]  @ r2<- self->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)
+    mov     r0, rSELF                   @ r0<- self
+    cmp     r1, #0                      @ null object?
+    EXPORT_PC()                         @ need for precise GC
+    beq     common_errNullObject        @ null object, throw an exception
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      dvmLockObject               @ call(self, obj)
+    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     1f                          @ yes
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmUnlockObject             @ r0<- success for unlock(self, obj)
+    cmp     r0, #0                      @ failed?
+    FETCH_ADVANCE_INST(1)               @ before throw: advance rPC, load rINST
+    beq     common_exceptionThrown      @ yes, exception is pending
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+1:
+    FETCH_ADVANCE_INST(1)               @ advance before throw
+    b      common_errNullObject
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    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, [rSELF, #offThread_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 - len in r1
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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)
+    EXPORT_PC()                         @ exception handler can throw
+    cmp     r1, #0                      @ null object?
+    beq     common_errNullObject        @ yes, throw an NPE instead
+    @ bypass dvmSetException, just store it
+    str     r1, [rSELF, #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 */
+    /* tuning: use sbfx for 6t2+ targets */
+    mov     r0, rINST, lsl #16          @ r0<- AAxx0000
+    movs    r1, r0, asr #24             @ r1<- ssssssAA (sign-extended)
+    add     r2, r1, r1                  @ r2<- byte offset, set flags
+       @ If backwards branch refresh rIBASE
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) check for trace hotness
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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)
+    adds    r1, r0, r0                  @ r1<- byte offset, flags set
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    bmi     common_testUpdateProfile    @ (r0) hot trace head?
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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".  Because
+     * we need the V bit set, we'll use an adds to convert from Dalvik
+     * offset to byte offset.
+     */
+    /* goto/32 +AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    orr     r0, r0, r1, lsl #16         @ r0<- AAAAaaaa
+    adds    r1, r0, r0                  @ r1<- byte offset
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ble     common_testUpdateProfile    @ (r0) hot trace head?
+#else
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .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.
+     *
+     * When the JIT is present, all targets are considered treated as
+     * a potential trace heads regardless of branch direction.
+     *
+     * 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
+    adds    r1, r0, r0                  @ r1<- byte offset; clear V
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrle   rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh handler base
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movne r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    moveq r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movge r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movlt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movle r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, r3                      @ compare (vA, vB)
+    movgt r1, #2                 @ r1<- BYTE branch dist for not-taken
+    adds    r2, r1, r1                  @ convert to bytes, check sign
+    FETCH_ADVANCE_INST_RB(r2)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    cmp     r0, #0
+    bne     common_updateProfile
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movne r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    moveq r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movge r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movlt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movle r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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
+    FETCH_S(r1, 1)                      @ r1<- branch offset, in code units
+    cmp     r2, #0                      @ compare (vA, 0)
+    movgt r1, #2                 @ r1<- inst branch dist for not-taken
+    adds    r1, r1, r1                  @ convert to bytes & set flags
+    FETCH_ADVANCE_INST_RB(r1)           @ update rPC, load rINST
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+    cmp     r0,#0
+    bne     common_updateProfile        @ test for JIT off at target
+#else
+    ldrmi   rIBASE, [rSELF, #offThread_curHandlerTable]   @ refresh table base
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .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.
+     */
+    /* 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(rINST, r2)                 @ rINST<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     rINST, #0                   @ null array object?
+    GET_VREG(r9, r9)                    @ r9<- vAA
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [rINST, #offArrayObject_length]   @ r3<- arrayObj->length
+    add     r10, rINST, r1, lsl #2      @ r10<- arrayObj + index*width
+    cmp     r1, 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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_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 */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_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, [rSELF, #offThread_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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     r9, rINST, lsr #8           @ r9<- AA
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_end
+
+/* ------------------------------ */
+    .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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, 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
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    @ no-op 
+    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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodNoRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodNoRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_resolve
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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, [rSELF, #offThread_method] @ r3<- self->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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- 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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_RANGE_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodRange   @ r0=method, r9="this"
+    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, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    mov     r9, #0                      @ null "this" in delay slot
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodRange @ yes, continue on
+    b       .LOP_INVOKE_STATIC_RANGE_resolve
+
+
+/* ------------------------------ */
+    .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(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/OP_IGET_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/OP_IPUT_VOLATILE.S */
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/OP_SGET_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/OP_SPUT_VOLATILE.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_OBJECT_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IGET_WIDE.S */
+    /*
+     * Wide 32-bit instance field get.
+     */
+    /* iget-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_WIDE_VOLATILE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_IPUT_WIDE.S */
+    /* iput-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_WIDE_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SGET_WIDE.S */
+    /*
+     * 64-bit SGET handler.
+     */
+    /* sget-wide vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_finish:
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE.S */
+/* File: armv5te/OP_SPUT_WIDE.S */
+    /*
+     * 64-bit SPUT handler.
+     */
+    /* sput-wide vAA, field@BBBB */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r10, r1, lsl #2]        @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_finish: @ field ptr in r2, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vAA/vAA+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/OP_BREAKPOINT.S */
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.
+     */
+    mov     r0, rPC
+    bl      dvmGetOriginalOpcode        @ (rPC)
+    FETCH(rINST, 0)                     @ reload OP_BREAKPOINT + rest of inst
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    and     rINST, #0xff00
+    orr     rINST, rINST, r0
+    GOTO_OPCODE_BASE(r1, r0)
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_method]    @ r0<- self->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 an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     *
+     * TUNING: could maintain two tables, pointer in Thread and
+     * swap if profiler/debuggger active.
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->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_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */
+    /*
+     * Execute a "native inline" instruction, using "/range" semantics.
+     * Same idea as execute-inline, but we get the args differently.
+     *
+     * We need to call an InlineOp4Func:
+     *  bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
+     *
+     * The first four args are in r0-r3, pointer to return value storage
+     * is on the stack.  The function's return value is a flag that tells
+     * us if an exception was thrown.
+     */
+    /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    FETCH(r10, 1)                       @ r10<- BBBB
+    EXPORT_PC()                         @ can throw
+    ands    r2, #kSubModeDebugProfile   @ Any going on?
+    bne     .LOP_EXECUTE_INLINE_RANGE_debugmode       @ yes - take slow path
+.LOP_EXECUTE_INLINE_RANGE_resume:
+    add     r1, rSELF, #offThread_retval  @ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_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_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 2)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_RANGE_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_RANGE_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(2+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/OP_RETURN_VOID_BARRIER.S */
+    SMP_DMB_ST
+    b       common_returnFromMethod
+
+/* ------------------------------ */
+    .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(ip, 1)                        @ ip<- field byte offset
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r3, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    ldrd    r0, [r3, ip]                @ r0<- obj.field (64 bits, aligned)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* 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 */
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    cmp     r0, #0
+    strneb  r2, [r2, r3, lsr #GC_CARD_SHIFT] @ mark card based on obj head
+    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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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(r9, r3)                    @ r9<- vC ("this" ptr)
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .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, [rSELF, #offThread_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(r9, r10)                   @ r9<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r9, #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 @ (r0=method, r9="this")
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+    /*
+     * 32-bit instance field put.
+     *
+     * for: iput-object, iput-object-volatile
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+    /*
+     * 32-bit SPUT handler for objects
+     *
+     * for: sput-object, sput-object-volatile
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/OP_DISPATCH_FF.S */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/OP_CONST_CLASS_JUMBO.S */
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<-self>methodClassDex
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]   @ r2<- dvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResClasses[AAAAaaaa]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .LOP_CONST_CLASS_JUMBO_resolve
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/OP_CHECK_CAST_JUMBO.S */
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r3, 3)                        @ r3<- BBBB
+    orr     r2, r0, r2, lsl #16         @ r2<- AAAAaaaa
+    GET_VREG(r9, r3)                    @ r9<- object
+    ldr     r0, [rSELF, #offThread_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .LOP_CHECK_CAST_JUMBO_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_JUMBO_resolve         @ not resolved, do it now
+.LOP_CHECK_CAST_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .LOP_CHECK_CAST_JUMBO_fullcheck       @ no, do full check
+    b       .LOP_CHECK_CAST_JUMBO_okay            @ yes, finish up
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/OP_INSTANCE_OF_JUMBO.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.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_INSTANCE_OF.S.
+     */
+    /* instance-of/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    FETCH(r9, 3)                        @ r9<- vBBBB
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- pDvmDex
+    cmp     r0, #0                      @ is object null?
+    beq     .LOP_INSTANCE_OF_JUMBO_store           @ null obj, not an instance, store r0
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResClasses]    @ r2<- pDvmDex->pResClasses
+    orr     r3, r1, r3, lsl #16         @ r3<- AAAAaaaa
+    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_JUMBO_resolve         @ not resolved, do it now
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/OP_NEW_INSTANCE_JUMBO.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_class
+#endif
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .LOP_NEW_INSTANCE_JUMBO_resolve         @ no, resolve it now
+.LOP_NEW_INSTANCE_JUMBO_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .LOP_NEW_INSTANCE_JUMBO_needinit        @ no, init class now
+.LOP_NEW_INSTANCE_JUMBO_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .LOP_NEW_INSTANCE_JUMBO_finish          @ continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/OP_NEW_ARRAY_JUMBO.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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    FETCH(r2, 1)                        @ r2<- aaaa (lo)
+    FETCH(r3, 2)                        @ r3<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- vCCCC
+    orr     r2, r2, r3, lsl #16         @ r2<- AAAAaaaa
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    GET_VREG(r1, r0)                    @ r1<- vCCCC (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 - len in r1
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .LOP_NEW_ARRAY_JUMBO_finish          @ resolved, continue
+    b       .LOP_NEW_ARRAY_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_JUMBO.S */
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * TODO: convert most of this into a common subroutine, shared with
+     *       OP_FILLED_NEW_ARRAY.S.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    EXPORT_PC()                         @ need for resolve and alloc
+    cmp     r0, #0                      @ already resolved?
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_continue        @ yes, continue on
+8:  ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/OP_IGET_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrb", "sqnum":"1" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/OP_IGET_BYTE_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsb", "sqnum":"2" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/OP_IGET_CHAR_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrh", "sqnum":"3" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/OP_IGET_SHORT_JUMBO.S */
+@include "armv5te/OP_IGET_JUMBO.S" { "load":"ldrsh", "sqnum":"4" }
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    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_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_JUMBO_resolved        @ resolved, continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/OP_IPUT_BOOLEAN_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BOOLEAN_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BOOLEAN_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/OP_IPUT_BYTE_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BYTE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_BYTE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/OP_IPUT_CHAR_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_CHAR_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_CHAR_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/OP_IPUT_SHORT_JUMBO.S */
+@include "armv5te/OP_IPUT_JUMBO.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_SHORT_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_SHORT_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 0
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/OP_SGET_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BOOLEAN_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/OP_SGET_BYTE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_BYTE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/OP_SGET_CHAR_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_CHAR_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/OP_SGET_SHORT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_SHORT_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 0
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    b       .LOP_SPUT_OBJECT_JUMBO_end
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/OP_SPUT_BOOLEAN_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BOOLEAN_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BOOLEAN_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/OP_SPUT_BYTE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BYTE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_BYTE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/OP_SPUT_CHAR_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_CHAR_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_CHAR_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/OP_SPUT_SHORT_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_SHORT_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_SHORT_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_JUMBO.S */
+    /*
+     * Handle a virtual method call.
+     */
+    /* invoke-virtual/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_VIRTUAL_JUMBO_continue        @ yes, continue on
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/OP_INVOKE_SUPER_JUMBO.S */
+    /*
+     * Handle a "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r9, #0                      @ null "this"?
+    ldr     r10, [rSELF, #offThread_method] @ r10<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r10, [r10, #offMethod_clazz]  @ r10<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_SUPER_JUMBO_continue        @ resolved, continue on
+    b       .LOP_INVOKE_SUPER_JUMBO_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/OP_INVOKE_DIRECT_JUMBO.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.)
+     *
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r10, 4)                       @ r10<- CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_JUMBO_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_JUMBO_finish:
+    cmp     r9, #0                      @ null "this" ref?
+    bne     common_invokeMethodJumbo    @ (r0=method, r9="this")
+    b       common_errNullObject        @ yes, throw exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/OP_INVOKE_STATIC_JUMBO.S */
+    /*
+     * Handle a static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r0, 1)                        @ r1<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+#if defined(WITH_JIT)
+    add     r10, r3, r1, lsl #2         @ r10<- &resolved_methodToCall
+#endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodJumboNoThis   @ (r0=method)
+    b       .LOP_INVOKE_STATIC_JUMBO_resolve
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/OP_INVOKE_INTERFACE_JUMBO.S */
+    /*
+     * Handle an interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    FETCH(r2, 4)                        @ r2<- CCCC
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    EXPORT_PC()                         @ must export for invoke
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    GET_VREG(r9, r2)                    @ r9<- first arg ("this")
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- methodClassDex
+    cmp     r9, #0                      @ null obj?
+    ldr     r2, [rSELF, #offThread_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r9, #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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/OP_UNUSED_27FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/OP_UNUSED_28FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/OP_UNUSED_29FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/OP_UNUSED_2AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/OP_UNUSED_2BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/OP_UNUSED_2CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/OP_UNUSED_2DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/OP_UNUSED_2EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/OP_UNUSED_2FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/OP_UNUSED_30FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/OP_UNUSED_31FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/OP_UNUSED_32FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/OP_UNUSED_33FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/OP_UNUSED_34FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/OP_UNUSED_35FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/OP_UNUSED_36FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/OP_UNUSED_37FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/OP_UNUSED_38FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/OP_UNUSED_39FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/OP_UNUSED_3AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/OP_UNUSED_3BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/OP_UNUSED_3CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/OP_UNUSED_3DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/OP_UNUSED_3EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/OP_UNUSED_3FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/OP_UNUSED_40FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/OP_UNUSED_41FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/OP_UNUSED_42FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/OP_UNUSED_43FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/OP_UNUSED_44FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/OP_UNUSED_45FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/OP_UNUSED_46FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/OP_UNUSED_47FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/OP_UNUSED_48FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/OP_UNUSED_49FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/OP_UNUSED_4AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/OP_UNUSED_4BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/OP_UNUSED_4CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/OP_UNUSED_4DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/OP_UNUSED_4EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/OP_UNUSED_4FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/OP_UNUSED_50FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/OP_UNUSED_51FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/OP_UNUSED_52FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/OP_UNUSED_53FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/OP_UNUSED_54FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/OP_UNUSED_55FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/OP_UNUSED_56FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/OP_UNUSED_57FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/OP_UNUSED_58FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/OP_UNUSED_59FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/OP_UNUSED_5AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/OP_UNUSED_5BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/OP_UNUSED_5CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/OP_UNUSED_5DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/OP_UNUSED_5EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/OP_UNUSED_5FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/OP_UNUSED_60FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/OP_UNUSED_61FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/OP_UNUSED_62FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/OP_UNUSED_63FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/OP_UNUSED_64FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/OP_UNUSED_65FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/OP_UNUSED_66FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/OP_UNUSED_67FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/OP_UNUSED_68FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/OP_UNUSED_69FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/OP_UNUSED_6AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/OP_UNUSED_6BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/OP_UNUSED_6CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/OP_UNUSED_6DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/OP_UNUSED_6EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/OP_UNUSED_6FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/OP_UNUSED_70FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/OP_UNUSED_71FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/OP_UNUSED_72FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/OP_UNUSED_73FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/OP_UNUSED_74FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/OP_UNUSED_75FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/OP_UNUSED_76FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/OP_UNUSED_77FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/OP_UNUSED_78FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/OP_UNUSED_79FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/OP_UNUSED_7AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/OP_UNUSED_7BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/OP_UNUSED_7CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/OP_UNUSED_7DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/OP_UNUSED_7EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/OP_UNUSED_7FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/OP_UNUSED_80FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/OP_UNUSED_81FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/OP_UNUSED_82FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/OP_UNUSED_83FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/OP_UNUSED_84FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/OP_UNUSED_85FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/OP_UNUSED_86FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/OP_UNUSED_87FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/OP_UNUSED_88FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/OP_UNUSED_89FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/OP_UNUSED_8AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/OP_UNUSED_8BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/OP_UNUSED_8CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/OP_UNUSED_8DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/OP_UNUSED_8EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/OP_UNUSED_8FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/OP_UNUSED_90FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/OP_UNUSED_91FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/OP_UNUSED_92FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/OP_UNUSED_93FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/OP_UNUSED_94FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/OP_UNUSED_95FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/OP_UNUSED_96FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/OP_UNUSED_97FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/OP_UNUSED_98FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/OP_UNUSED_99FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/OP_UNUSED_9AFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/OP_UNUSED_9BFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/OP_UNUSED_9CFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/OP_UNUSED_9DFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/OP_UNUSED_9EFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/OP_UNUSED_9FFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/OP_UNUSED_A0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/OP_UNUSED_A1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/OP_UNUSED_A2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/OP_UNUSED_A3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/OP_UNUSED_A4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/OP_UNUSED_A5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/OP_UNUSED_A6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/OP_UNUSED_A7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/OP_UNUSED_A8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/OP_UNUSED_A9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/OP_UNUSED_AAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/OP_UNUSED_ABFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/OP_UNUSED_ACFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/OP_UNUSED_ADFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/OP_UNUSED_AEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/OP_UNUSED_AFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/OP_UNUSED_B0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/OP_UNUSED_B1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/OP_UNUSED_B2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/OP_UNUSED_B3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/OP_UNUSED_B4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/OP_UNUSED_B5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/OP_UNUSED_B6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/OP_UNUSED_B7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/OP_UNUSED_B8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/OP_UNUSED_B9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/OP_UNUSED_BAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/OP_UNUSED_BBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/OP_UNUSED_BCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/OP_UNUSED_BDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/OP_UNUSED_BEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/OP_UNUSED_BFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/OP_UNUSED_C0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/OP_UNUSED_C1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/OP_UNUSED_C2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/OP_UNUSED_C3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/OP_UNUSED_C4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/OP_UNUSED_C5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/OP_UNUSED_C6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/OP_UNUSED_C7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/OP_UNUSED_C8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/OP_UNUSED_C9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/OP_UNUSED_CAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/OP_UNUSED_CBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/OP_UNUSED_CCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/OP_UNUSED_CDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/OP_UNUSED_CEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/OP_UNUSED_CFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/OP_UNUSED_D0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/OP_UNUSED_D1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/OP_UNUSED_D2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/OP_UNUSED_D3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/OP_UNUSED_D4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/OP_UNUSED_D5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/OP_UNUSED_D6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/OP_UNUSED_D7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/OP_UNUSED_D8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/OP_UNUSED_D9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/OP_UNUSED_DAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/OP_UNUSED_DBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/OP_UNUSED_DCFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/OP_UNUSED_DDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/OP_UNUSED_DEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/OP_UNUSED_DFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/OP_UNUSED_E0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/OP_UNUSED_E1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/OP_UNUSED_E2FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/OP_UNUSED_E3FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/OP_UNUSED_E4FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/OP_UNUSED_E5FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/OP_UNUSED_E6FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/OP_UNUSED_E7FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/OP_UNUSED_E8FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/OP_UNUSED_E9FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/OP_UNUSED_EAFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/OP_UNUSED_EBFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/OP_UNUSED_ECFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/OP_UNUSED_EDFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/OP_UNUSED_EEFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/OP_UNUSED_EFFF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/OP_UNUSED_F0FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/OP_UNUSED_F1FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_JUMBO.S */
+/* File: armv5te/OP_INVOKE_OBJECT_INIT_RANGE.S */
+    /*
+     * Invoke Object.<init> on an object.  In practice we know that
+     * Object's nullary constructor doesn't do anything, so we just
+     * skip it unless a debugger is active.
+     */
+    FETCH(r1, 4)                  @ r1<- CCCC
+    GET_VREG(r0, r1)                    @ r0<- "this" ptr
+    cmp     r0, #0                      @ check for NULL
+    beq     common_errNullObject        @ export PC and throw NPE
+    ldr     r1, [r0, #offObject_clazz]  @ r1<- obj->clazz
+    ldr     r2, [r1, #offClassObject_accessFlags] @ r2<- clazz->accessFlags
+    tst     r2, #CLASS_ISFINALIZABLE    @ is this class finalizable?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal        @ yes, go
+.LOP_INVOKE_OBJECT_INIT_JUMBO_finish:
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeDebuggerActive @ debugger active?
+    bne     .LOP_INVOKE_OBJECT_INIT_JUMBO_debugger        @ Yes - skip optimization
+    FETCH_ADVANCE_INST(4+1)       @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/OP_IGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/OP_IGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+    ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/OP_IGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/OP_IPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-boolean/jumbo, iput-byte/jumbo, iput-char/jumbo,
+     *      iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/OP_IPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_WIDE_JUMBO.S */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/OP_IPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    FETCH(r0, 4)                        @ r0<- CCCC
+    ldr     r3, [rSELF, #offThread_methodClassDex]    @ r3<- DvmDex
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[CCCC], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish          @ no, already resolved
+8:  ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    b       .LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved        @ resolved, continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/OP_SGET_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/OP_SGET_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_VOLATILE_JUMBO_finish:
+    FETCH(r9, 3)                        @ r9<- BBBB
+    .if 1
+    add     r0, r0, #offStaticField_value @ r0<- pointer to data
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r0, #offStaticField_value] @ r0/r1<- field value (aligned)
+    .endif
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    stmia   r9, {r0-r1}                 @ vBBBB/vBBBB+1<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/OP_SGET_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SGET_OBJECT_JUMBO.S */
+/* File: armv5te/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[BBBB]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/OP_SPUT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r1, [r0, #offStaticField_value] @ field<- vBBBB
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/OP_SPUT_WIDE_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r0, [rSELF, #offThread_methodClassDex]  @ r0<- DvmDex
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r10, [r0, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r1, r2, lsl #16         @ r1<- AAAAaaaa
+    FETCH(r9, 3)                        @ r9<- BBBB
+    ldr     r2, [r10, r1, lsl #2]       @ r2<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[BBBB]
+    cmp     r2, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_finish: @ field ptr in r2, BBBB in r9
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vBBBB/vBBBB+1
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if 1
+    add     r2, r2, #offStaticField_value @ r2<- pointer to data
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r2, #offStaticField_value] @ field<- vBBBB/vBBBB+1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/OP_SPUT_OBJECT_VOLATILE_JUMBO.S */
+/* File: armv5te/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler for objects
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    ldr     r2, [rSELF, #offThread_methodClassDex]    @ r2<- DvmDex
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    ldr     r10, [r2, #offDvmDex_pResFields] @ r10<- dvmDex->pResFields
+    orr     r1, r0, r1, lsl #16         @ r1<- AAAAaaaa
+    ldr     r0, [r10, r1, lsl #2]       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish:   @ field ptr in r0
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    ldr     r9, [r0, #offField_clazz]   @ r9<- field->clazz
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_end
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR_JUMBO.S */
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, Class@AAAAAAAA */
+    FETCH(r1, 1)                        @ r1<- aaaa (lo)
+    FETCH(r2, 2)                        @ r2<- AAAA (hi)
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    orr     r2, r1, r2, lsl #16         @ r2<- AAAAaaaa
+    EXPORT_PC()                         @ export the PC
+    FETCH(r1, 3)                        @ r1<- BBBB
+    bl      dvmThrowVerificationError   @ always throws
+    b       common_exceptionThrown      @ handle exception
+
+    .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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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, [rSELF, #offThread_method] @ r0<- self->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 desired class resolved from BBBB
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    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.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method]    @ r0<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_end:
+    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
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * 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, [rSELF, #offThread_method] @ r3<- self->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
+
+/* 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, [rSELF, #offThread_method] @ r3<- self->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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     0
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    .if     1
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    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:
+    ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    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_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_RANGE:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* 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:
+     *  rINST = 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, [rINST, #offObject_clazz]  @ r1<- arrayObj->clazz
+    bl      dvmCanPutArrayElement       @ test object type vs. array type
+    cmp     r0, #0                      @ okay?
+    beq     .LOP_APUT_OBJECT_throw           @ no
+    mov     r1, rINST                   @ r1<- arrayObj
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr     r2, [rSELF, #offThread_cardTable]     @ get biased CT base
+    add     r10, #offArrayObject_contents   @ r0<- pointer to slot
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10]                   @ vBB[vCC]<- vAA
+    strb    r2, [r2, r1, lsr #GC_CARD_SHIFT] @ mark card using object head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_skip_check:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+.LOP_APUT_OBJECT_throw:
+    @ The types don't match.  We need to throw an ArrayStoreException.
+    ldr     r0, [r9, #offObject_clazz]
+    ldr     r1, [rINST, #offObject_clazz]
+    EXPORT_PC()
+    bl      dvmThrowArrayStoreExceptionIncompatibleElement
+    b       common_exceptionThrown
+
+/* 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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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)
+    @ no-op                             @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    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]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+    /*
+     * 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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    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
+    @ no-op                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_finish
+
+/* continuation for OP_SGET_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_finish          @ resume
+
+/* continuation for OP_SGET_OBJECT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_finish
+
+/* continuation for OP_SGET_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_finish
+
+/* continuation for OP_SGET_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_finish
+
+/* continuation for OP_SGET_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_finish
+
+/* continuation for OP_SGET_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_finish
+
+/* continuation for OP_SPUT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT */
+
+
+.LOP_SPUT_OBJECT_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_finish          @ resume
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodNoRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC */
+
+
+.LOP_INVOKE_STATIC_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodNoRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodNoRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodNoRange     @ whew, finally!
+#else
+    bne     common_invokeMethodNoRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodRange @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_RANGE_continue:
+    ldr     r1, [r10, #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, r10                     @ 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, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_RANGE_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_RANGE */
+
+
+.LOP_INVOKE_STATIC_RANGE_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodRange     @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodRange     @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodRange     @ whew, finally!
+#else
+    bne     common_invokeMethodRange     @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* 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_IGET_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_finish
+
+/* continuation for OP_SPUT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_finish          @ resume
+
+/* continuation for OP_IGET_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_finish:
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    cmp     r9, #0                      @ check object for null
+    and     r2, r2, #15                 @ r2<- A
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[A]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_SGET_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r1<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_WIDE_VOLATILE_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r9:  &fp[AA]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_finish          @ resume
+
+/* 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(rINST, 2)                     @ rINST<- FEDC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  and     ip, rINST, #0xf000          @ isolate F
+    ldr     r3, [rFP, ip, lsr #10]      @ r3<- vF (shift right 12, left 2)
+3:  and     ip, rINST, #0x0f00          @ isolate E
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vE
+2:  and     ip, rINST, #0x00f0          @ isolate D
+    ldr     r1, [rFP, ip, lsr #2]       @ r1<- vD
+1:  and     ip, rINST, #0x000f          @ isolate C
+    ldr     r0, [rFP, ip, lsl #2]       @ r0<- vC
+0:
+    ldr     rINST, .LOP_EXECUTE_INLINE_table    @ table of InlineOperation
+    ldr     pc, [rINST, r10, lsl #4]    @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_continue        @ make call; will return after
+    mov     rINST, r0                   @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, r9                      @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit @ (method, self)
+    cmp     rINST, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_table:
+    .word   gDvmInlineOpsTable
+
+/* continuation for OP_EXECUTE_INLINE_RANGE */
+
+    /*
+     * 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]
+     */
+.LOP_EXECUTE_INLINE_RANGE_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(r9, 2)                        @ r9<- CCCC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  add     ip, r9, #3                  @ base+3
+    GET_VREG(r3, ip)                    @ r3<- vBase[3]
+3:  add     ip, r9, #2                  @ base+2
+    GET_VREG(r2, ip)                    @ r2<- vBase[2]
+2:  add     ip, r9, #1                  @ base+1
+    GET_VREG(r1, ip)                    @ r1<- vBase[1]
+1:  add     ip, r9, #0                  @ (nop)
+    GET_VREG(r0, ip)                    @ r0<- vBase[0]
+0:
+    ldr     r9, .LOP_EXECUTE_INLINE_RANGE_table       @ table of InlineOperation
+    ldr     pc, [r9, r10, lsl #4]       @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+
+    /*
+     * We're debugging or profiling.
+     * r10: opIndex
+     */
+.LOP_EXECUTE_INLINE_RANGE_debugmode:
+    mov     r0, r10
+    bl      dvmResolveInlineNative
+    cmp     r0, #0                      @ did it resolve?
+    beq     .LOP_EXECUTE_INLINE_RANGE_resume          @ no, just move on
+    mov     r9, r0                      @ remember method
+    mov     r1, rSELF
+    bl      dvmFastMethodTraceEnter     @ (method, self)
+    add     r1, rSELF, #offThread_retval@ r1<- &self->retval
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- B
+    mov     rINST, r9                   @ rINST<- method
+    str     r1, [sp]                    @ push &self->retval
+    bl      .LOP_EXECUTE_INLINE_RANGE_continue        @ make call; will return after
+    mov     r9, r0                      @ save result of inline
+    add     sp, sp, #8                  @ pop stack
+    mov     r0, rINST                   @ r0<- method
+    mov     r1, rSELF
+    bl      dvmFastNativeMethodTraceExit  @ (method, self)
+    cmp     r9, #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
+
+
+
+
+.LOP_EXECUTE_INLINE_RANGE_table:
+    .word   gDvmInlineOpsTable
+
+
+/* continuation for OP_INVOKE_OBJECT_INIT_RANGE */
+
+.LOP_INVOKE_OBJECT_INIT_RANGE_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_RANGE_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_RANGE_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 0
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_OBJECT_VOLATILE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  BBBB field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_finish
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vAA
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  BBBB field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_finish          @ resume
+
+
+/* continuation for OP_CONST_CLASS_JUMBO */
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: AAAAAAAA (Class ref)
+     *  r9: target register
+     */
+.LOP_CONST_CLASS_JUMBO_resolve:
+    EXPORT_PC()
+    ldr     r0, [rSELF, #offThread_method] @ r0<- self->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(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_CHECK_CAST_JUMBO */
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds desired class resolved from AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_fullcheck:
+    mov     r10, r1                     @ avoid ClassObject getting clobbered
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .LOP_CHECK_CAST_JUMBO_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC()                         @ about to throw
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz (actual class)
+    mov     r1, r10                     @ r1<- desired class
+    bl      dvmThrowClassCastException
+    b       common_exceptionThrown
+
+    /*
+     * Advance PC and get the next opcode.
+     */
+.LOP_CHECK_CAST_JUMBO_okay:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds AAAAAAAA
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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 AAAAAAAA
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_CHECK_CAST_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_INSTANCE_OF_JUMBO */
+
+    /*
+     * Class resolved, determine type of check necessary.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .LOP_INSTANCE_OF_JUMBO_trivial         @ yes, trivial finish
+    @ fall through to OP_INSTANCE_OF_JUMBO_fullcheck
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from AAAAAAAA
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to OP_INSTANCE_OF_JUMBO_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_store:
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b OP_INSTANCE_OF_JUMBO_store, but copying is faster and cheaper
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vBBBB<- 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 AAAAAAAA
+     *  r9 holds BBBB
+     */
+
+.LOP_INSTANCE_OF_JUMBO_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rSELF, #offThread_method]    @ r0<- self->method
+    mov     r1, r3                      @ r1<- AAAAAAAA
+    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
+    FETCH(r3, 4)                        @ r3<- vCCCC
+    mov     r1, r0                      @ r1<- class resolved from AAAAAAAA
+    GET_VREG(r0, r3)                    @ r0<- vCCCC (object)
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_INSTANCE_OF_JUMBO_resolved        @ pick up where we left off
+
+/* continuation for OP_NEW_INSTANCE_JUMBO */
+
+    .balign 32                          @ minimize cache lines
+.LOP_NEW_INSTANCE_JUMBO_finish: @ r0=new object
+    FETCH(r3, 3)                        @ r3<- BBBB
+    cmp     r0, #0                      @ failed?
+#if defined(WITH_JIT)
+    /*
+     * The JIT needs the class to be fully resolved before it can
+     * include this instruction in a trace.
+     */
+    ldrh    r1, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown      @ yes, handle the exception
+    ands    r1, #kSubModeJitTraceBuild  @ under construction?
+    bne     .LOP_NEW_INSTANCE_JUMBO_jitCheck
+#else
+    beq     common_exceptionThrown      @ yes, handle the exception
+#endif
+.LOP_NEW_INSTANCE_JUMBO_end:
+    FETCH_ADVANCE_INST(4)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we need to stop the trace building early.
+     * r0: new object
+     * r3: vAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_jitCheck:
+    ldr     r1, [r10]                   @ reload resolved class
+    cmp     r1, #0                      @ okay?
+    bne     .LOP_NEW_INSTANCE_JUMBO_end             @ yes, finish
+    mov     r9, r0                      @ preserve new object
+    mov     r10, r3                     @ preserve vAA
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self, pc)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r9, r10)                   @ vAA<- new object
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.LOP_NEW_INSTANCE_JUMBO_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_JUMBO_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds AAAAAAAA
+     */
+.LOP_NEW_INSTANCE_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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_JUMBO_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_NEW_ARRAY_JUMBO */
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref AAAAAAAA
+     */
+.LOP_NEW_ARRAY_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->method
+    mov     r9, r1                      @ r9<- length (save)
+    mov     r1, r2                      @ r1<- AAAAAAAA
+    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_JUMBO_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.LOP_NEW_ARRAY_JUMBO_finish:
+    mov     r2, #ALLOC_DONT_TRACK       @ don't track in local refs table
+    bl      dvmAllocArrayByClass        @ r0<- call(clazz, length, flags)
+    cmp     r0, #0                      @ failed?
+    FETCH(r2, 3)                        @ r2<- vBBBB
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ vBBBB<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_FILLED_NEW_ARRAY_JUMBO */
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    rINST, [r3, #1]             @ rINST<- descriptor[1]
+    FETCH(r1, 3)                        @ r1<- BBBB (length)
+    cmp     rINST, #'I'                 @ array of ints?
+    cmpne   rINST, #'L'                 @ array of objects?
+    cmpne   rINST, #'['                 @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_JUMBO_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, 4)                        @ r1<- CCCC
+    str     r0, [rSELF, #offThread_retval]      @ retval.l <- new array
+    str     rINST, [rSELF, #offThread_retval+4] @ retval.h <- type
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(5)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC, r9=BBBB (length)
+    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
+
+2:  ldr     r0, [rSELF, #offThread_retval]     @ r0<- object
+    ldr     r1, [rSELF, #offThread_retval+4]   @ r1<- type
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    GET_INST_OPCODE(ip)                      @ ip<- opcode from rINST
+    cmp     r1, #'I'                         @ Is int array?
+    strneb  r2, [r2, r0, lsr #GC_CARD_SHIFT] @ Mark card based on object head
+    GOTO_OPCODE(ip)                          @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_notimpl:
+    ldr     r0, .L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO
+    bl      dvmThrowInternalError
+    b       common_exceptionThrown
+
+    /*
+     * Ideally we'd only define this once, but depending on layout we can
+     * exceed the range of the load above.
+     */
+
+.L_strFilledNewArrayNotImpl_OP_FILLED_NEW_ARRAY_JUMBO:
+    .word   .LstrFilledNewArrayNotImpl
+
+/* continuation for OP_IGET_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     0
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_JUMBO_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)
+    @ no-op                             @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     0
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                         @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    @ no-op 
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BOOLEAN_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_JUMBO_finish:
+    @bl      common_squeak1
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_BYTE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_BYTE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_JUMBO_finish:
+    @bl      common_squeak2
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_CHAR_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_CHAR_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_JUMBO_finish:
+    @bl      common_squeak3
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_SHORT_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_SHORT_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_JUMBO_finish:
+    @bl      common_squeak4
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    @ no-op                          @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    @ no-op 
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_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_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_JUMBO */
+
+
+.LOP_SPUT_OBJECT_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    @ no-op 
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_JUMBO_finish          @ resume
+
+
+/* continuation for OP_SPUT_BOOLEAN_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BOOLEAN_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BOOLEAN_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_BYTE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_BYTE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_BYTE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_CHAR_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_CHAR_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_CHAR_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_SHORT_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_SHORT_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_SHORT_JUMBO_finish          @ resume
+
+/* continuation for OP_INVOKE_VIRTUAL_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     */
+.LOP_INVOKE_VIRTUAL_JUMBO_continue:
+    FETCH(r10, 4)                       @ r10<- CCCC
+    GET_VREG(r9, r10)                   @ r9<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r9, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodJumbo    @ (r0=method, r9="this")
+
+/* continuation for OP_INVOKE_SUPER_JUMBO */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = method->clazz
+     */
+.LOP_INVOKE_SUPER_JUMBO_continue:
+    ldr     r1, [r10, #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_JUMBO_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_invokeMethodJumbo    @ (r0=method, r9="this")
+
+.LOP_INVOKE_SUPER_JUMBO_resolve:
+    mov     r0, r10                     @ 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_JUMBO_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_JUMBO_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
+
+/* continuation for OP_INVOKE_DIRECT_JUMBO */
+
+    /*
+     * On entry:
+     *  r1 = reference (CCCC)
+     *  r10 = "this" register
+     */
+.LOP_INVOKE_DIRECT_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+    bne     .LOP_INVOKE_DIRECT_JUMBO_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* continuation for OP_INVOKE_STATIC_JUMBO */
+
+
+.LOP_INVOKE_STATIC_JUMBO_resolve:
+    ldr     r3, [rSELF, #offThread_method] @ r3<- self->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?
+#if defined(WITH_JIT)
+    /*
+     * Check to see if we're actively building a trace.  If so,
+     * we need to keep this instruction out of it.
+     * r10: &resolved_methodToCall
+     */
+    ldrh    r2, [rSELF, #offThread_subMode]
+    beq     common_exceptionThrown            @ null, handle exception
+    ands    r2, #kSubModeJitTraceBuild        @ trace under construction?
+    beq     common_invokeMethodJumboNoThis    @ no (r0=method, r9="this")
+    ldr     r1, [r10]                         @ reload resolved method
+    cmp     r1, #0                            @ finished resolving?
+    bne     common_invokeMethodJumboNoThis    @ yes (r0=method, r9="this")
+    mov     r10, r0                           @ preserve method
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect              @ (self, pc)
+    mov     r0, r10
+    b       common_invokeMethodJumboNoThis    @ whew, finally!
+#else
+    bne     common_invokeMethodJumboNoThis    @ (r0=method, r9="this")
+    b       common_exceptionThrown            @ yes, handle exception
+#endif
+
+/* continuation for OP_INVOKE_OBJECT_INIT_JUMBO */
+
+.LOP_INVOKE_OBJECT_INIT_JUMBO_setFinal:
+    EXPORT_PC()                         @ can throw
+    bl      dvmSetFinalizable           @ call dvmSetFinalizable(obj)
+    ldr     r0, [rSELF, #offThread_exception] @ r0<- self->exception
+    cmp     r0, #0                      @ exception pending?
+    bne     common_exceptionThrown      @ yes, handle it
+    b       .LOP_INVOKE_OBJECT_INIT_JUMBO_finish
+
+    /*
+     * A debugger is attached, so we need to go ahead and do
+     * this.  For simplicity, we'll just jump directly to the
+     * corresponding handler.  Note that we can't use
+     * rIBASE here because it may be in single-step mode.
+     * Load the primary table base directly.
+     */
+.LOP_INVOKE_OBJECT_INIT_JUMBO_debugger:
+    ldr     r1, [rSELF, #offThread_mainHandlerTable]
+    .if 1
+    mov     ip, #OP_INVOKE_DIRECT_JUMBO
+    .else
+    mov     ip, #OP_INVOKE_DIRECT_RANGE
+    .endif
+    GOTO_OPCODE_BASE(r1,ip)             @ execute it
+
+/* continuation for OP_IGET_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    .if     1
+    add     r0, r9, r3                  @ r0<- address of field
+    bl      dvmQuasiAtomicRead64        @ r0/r1<- contents of field
+    .else
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    .endif
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[BBBB]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_resolved:
+    cmp     r0, #0                      @ resolution unsuccessful?
+    beq     common_exceptionThrown      @ yes, throw exception
+    @ fall through to OP_IGET_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    SMP_DMB                            @ acquiring load
+    FETCH(r2, 3)                        @ r2<- BBBB
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    SET_VREG(r0, r2)                    @ fp[BBBB]<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                         @ releasing store
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    SMP_DMB
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_IPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_WIDE_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_VOLATILE_JUMBO_finish:
+    cmp     r9, #0                      @ check object for null
+    FETCH(r2, 3)                        @ r1<- BBBB
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[BBBB]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    GET_INST_OPCODE(r10)                @ extract opcode from rINST
+    .if     1
+    add     r2, r9, r3                  @ r2<- target address
+    bl      dvmQuasiAtomicSwap64Sync    @ stores r0/r1 into addr r2
+    .else
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    .endif
+    GOTO_OPCODE(r10)                    @ jump to next instruction
+
+/* continuation for OP_IPUT_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_resolved:
+     cmp     r0, #0                     @ resolution unsuccessful?
+     beq     common_exceptionThrown     @ yes, throw exception
+     @ fall through to OP_IPUT_OBJECT_VOLATILE_JUMBO_finish
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_VOLATILE_JUMBO_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    FETCH(r1, 3)                        @ r1<- BBBB
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[BBBB]
+    ldr     r2, [rSELF, #offThread_cardTable]  @ r2<- card table base
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SMP_DMB_ST                        @ releasing store
+    str     r0, [r9, r3]                @ obj.field (32 bits)<- r0
+    SMP_DMB
+    cmp     r0, #0                      @ stored a null reference?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card if not
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* continuation for OP_SGET_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SGET_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: AAAAAAAA field ref
+     *
+     * Returns StaticField pointer in r0.
+     */
+.LOP_SGET_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_WIDE_VOLATILE_JUMBO_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+/* continuation for OP_SGET_OBJECT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SGET_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SGET_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r10: dvmDex->pResFields
+     */
+.LOP_SPUT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_WIDE_VOLATILE_JUMBO */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1:  AAAAAAAA field ref
+     *  r9:  &fp[BBBB]
+     *  r10: dvmDex->pResFields
+     *
+     * Returns StaticField pointer in r2.
+     */
+.LOP_SPUT_WIDE_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r2<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    mov     r2, r0                      @ copy to r2
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_WIDE_VOLATILE_JUMBO_finish          @ resume
+
+/* continuation for OP_SPUT_OBJECT_VOLATILE_JUMBO */
+
+
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_end:
+    str     r1, [r0, #offStaticField_value]  @ field<- vBBBB
+    SMP_DMB
+    cmp     r1, #0                      @ stored a null object?
+    strneb  r2, [r2, r9, lsr #GC_CARD_SHIFT]  @ mark card based on obj head
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /* Continuation if the field has not yet been resolved.
+     * r1:  AAAAaaaa field ref
+     * r10: dvmDex->pResFields
+     */
+.LOP_SPUT_OBJECT_VOLATILE_JUMBO_resolve:
+    ldr     r2, [rSELF, #offThread_method]    @ r9<- current method
+#if defined(WITH_JIT)
+    add     r10, r10, r1, lsl #2        @ r10<- &dvmDex->pResFields[field]
+#endif
+    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?
+    beq     common_exceptionThrown      @ no, handle exception
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including this instruction.
+     */
+    bl      common_verifyField
+#endif
+    b       .LOP_SPUT_OBJECT_VOLATILE_JUMBO_finish          @ resume
+
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+
+    .global dvmAsmAltInstructionStart
+    .type   dvmAsmAltInstructionStart, %function
+    .text
+
+dvmAsmAltInstructionStart = .L_ALT_OP_NOP
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOP: /* 0x00 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (0 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE: /* 0x01 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (1 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (2 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (3 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (4 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (5 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (6 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (7 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (8 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (9 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (10 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (11 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (12 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (13 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID: /* 0x0e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (14 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN: /* 0x0f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (15 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (16 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (17 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_4: /* 0x12 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (18 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_16: /* 0x13 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (19 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST: /* 0x14 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (20 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (21 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (22 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (23 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (24 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (25 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (26 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (27 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (28 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (29 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (30 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST: /* 0x1f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (31 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (32 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (33 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (34 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (35 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (36 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (37 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (38 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW: /* 0x27 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (39 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO: /* 0x28 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (40 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (41 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (42 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (43 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (44 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_FLOAT: /* 0x2d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (45 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_FLOAT: /* 0x2e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (46 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (47 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (48 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (49 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQ: /* 0x32 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (50 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NE: /* 0x33 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (51 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LT: /* 0x34 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (52 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GE: /* 0x35 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (53 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GT: /* 0x36 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (54 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LE: /* 0x37 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (55 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (56 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (57 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (58 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (59 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (60 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (61 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (62 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (63 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (64 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (65 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (66 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (67 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET: /* 0x44 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (68 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (69 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (70 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (71 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (72 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (73 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (74 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT: /* 0x4b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (75 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (76 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (77 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (78 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (79 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (80 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (81 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET: /* 0x52 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (82 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE: /* 0x53 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (83 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (84 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (85 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (86 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (87 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (88 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT: /* 0x59 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (89 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE: /* 0x5a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (90 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (91 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (92 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (93 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (94 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (95 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET: /* 0x60 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (96 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE: /* 0x61 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (97 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (98 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (99 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE: /* 0x64 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (100 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR: /* 0x65 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (101 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT: /* 0x66 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (102 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT: /* 0x67 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (103 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (104 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (105 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (106 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (107 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (108 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (109 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (110 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (111 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (112 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (113 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (114 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (115 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (116 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (117 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (118 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (119 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (120 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (121 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (122 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_INT: /* 0x7b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (123 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_INT: /* 0x7c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (124 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_LONG: /* 0x7d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (125 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NOT_LONG: /* 0x7e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (126 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (127 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (128 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (129 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (130 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (131 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (132 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (133 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (134 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (135 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (136 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (137 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (138 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (139 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (140 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (141 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (142 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (143 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (144 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (145 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (146 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (147 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT: /* 0x94 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (148 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT: /* 0x95 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (149 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT: /* 0x96 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (150 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (151 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (152 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (153 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (154 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (155 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (156 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (157 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (158 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (159 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (160 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (161 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (162 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (163 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (164 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (165 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT: /* 0xa6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (166 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT: /* 0xa7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (167 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT: /* 0xa8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (168 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT: /* 0xa9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (169 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (170 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE: /* 0xab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (171 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE: /* 0xac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (172 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE: /* 0xad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (173 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE: /* 0xae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (174 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (175 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (176 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (177 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (178 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (179 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (180 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (181 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (182 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (183 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (184 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (185 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (186 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (187 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (188 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (189 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (190 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (191 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (192 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (193 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (194 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (195 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (196 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (197 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (198 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (199 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (200 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (201 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (202 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (203 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (204 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (205 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (206 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (207 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (208 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT: /* 0xd1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (209 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (210 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (211 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (212 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (213 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (214 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (215 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (216 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (217 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (218 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (219 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (220 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (221 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (222 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (223 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (224 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (225 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (226 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (227 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (228 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (229 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (230 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (231 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (232 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (233 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (234 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (235 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (236 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (237 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (238 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (239 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (240 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (241 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (242 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (243 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (244 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_QUICK: /* 0xf5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (245 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (246 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (247 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (248 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (249 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (250 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (251 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (252 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (253 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (254 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_DISPATCH_FF: /* 0xff */
+/* File: armv5te/ALT_OP_DISPATCH_FF.S */
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    mov     ip, rINST, lsr #8           @ ip<- extended opcode
+    add     ip, ip, #256                @ add offset for extended opcodes
+    GOTO_OPCODE(ip)                     @ go to proper extended handler
+
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (256 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (257 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (258 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (259 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (260 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (261 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_JUMBO: /* 0x106 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (262 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (263 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (264 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (265 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (266 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (267 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (268 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_JUMBO: /* 0x10d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (269 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (270 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (271 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (272 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (273 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (274 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (275 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_JUMBO: /* 0x114 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (276 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (277 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (278 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (279 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (280 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (281 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (282 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_JUMBO: /* 0x11b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (283 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (284 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (285 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (286 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (287 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (288 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (289 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (290 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (291 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (292 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (293 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (294 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_27FF: /* 0x127 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (295 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_28FF: /* 0x128 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (296 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_29FF: /* 0x129 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (297 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2AFF: /* 0x12a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (298 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2BFF: /* 0x12b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (299 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2CFF: /* 0x12c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (300 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2DFF: /* 0x12d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (301 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2EFF: /* 0x12e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (302 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_2FFF: /* 0x12f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (303 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_30FF: /* 0x130 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (304 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_31FF: /* 0x131 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (305 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_32FF: /* 0x132 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (306 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_33FF: /* 0x133 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (307 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_34FF: /* 0x134 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (308 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_35FF: /* 0x135 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (309 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_36FF: /* 0x136 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (310 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_37FF: /* 0x137 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (311 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_38FF: /* 0x138 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (312 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_39FF: /* 0x139 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (313 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3AFF: /* 0x13a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (314 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3BFF: /* 0x13b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (315 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3CFF: /* 0x13c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (316 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3DFF: /* 0x13d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (317 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3EFF: /* 0x13e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (318 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_3FFF: /* 0x13f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (319 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_40FF: /* 0x140 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (320 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_41FF: /* 0x141 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (321 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_42FF: /* 0x142 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (322 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_43FF: /* 0x143 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (323 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_44FF: /* 0x144 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (324 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_45FF: /* 0x145 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (325 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_46FF: /* 0x146 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (326 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_47FF: /* 0x147 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (327 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_48FF: /* 0x148 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (328 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_49FF: /* 0x149 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (329 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4AFF: /* 0x14a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (330 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4BFF: /* 0x14b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (331 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4CFF: /* 0x14c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (332 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4DFF: /* 0x14d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (333 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4EFF: /* 0x14e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (334 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_4FFF: /* 0x14f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (335 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_50FF: /* 0x150 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (336 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_51FF: /* 0x151 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (337 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_52FF: /* 0x152 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (338 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_53FF: /* 0x153 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (339 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_54FF: /* 0x154 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (340 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_55FF: /* 0x155 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (341 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_56FF: /* 0x156 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (342 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_57FF: /* 0x157 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (343 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_58FF: /* 0x158 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (344 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_59FF: /* 0x159 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (345 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5AFF: /* 0x15a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (346 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5BFF: /* 0x15b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (347 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5CFF: /* 0x15c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (348 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5DFF: /* 0x15d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (349 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5EFF: /* 0x15e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (350 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_5FFF: /* 0x15f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (351 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_60FF: /* 0x160 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (352 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_61FF: /* 0x161 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (353 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_62FF: /* 0x162 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (354 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_63FF: /* 0x163 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (355 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_64FF: /* 0x164 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (356 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_65FF: /* 0x165 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (357 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_66FF: /* 0x166 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (358 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_67FF: /* 0x167 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (359 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_68FF: /* 0x168 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (360 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_69FF: /* 0x169 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (361 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6AFF: /* 0x16a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (362 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6BFF: /* 0x16b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (363 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6CFF: /* 0x16c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (364 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6DFF: /* 0x16d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (365 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6EFF: /* 0x16e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (366 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_6FFF: /* 0x16f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (367 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_70FF: /* 0x170 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (368 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_71FF: /* 0x171 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (369 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_72FF: /* 0x172 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (370 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_73FF: /* 0x173 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (371 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_74FF: /* 0x174 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (372 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_75FF: /* 0x175 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (373 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_76FF: /* 0x176 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (374 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_77FF: /* 0x177 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (375 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_78FF: /* 0x178 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (376 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_79FF: /* 0x179 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (377 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7AFF: /* 0x17a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (378 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7BFF: /* 0x17b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (379 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7CFF: /* 0x17c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (380 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7DFF: /* 0x17d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (381 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7EFF: /* 0x17e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (382 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_7FFF: /* 0x17f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (383 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_80FF: /* 0x180 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (384 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_81FF: /* 0x181 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (385 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_82FF: /* 0x182 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (386 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_83FF: /* 0x183 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (387 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_84FF: /* 0x184 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (388 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_85FF: /* 0x185 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (389 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_86FF: /* 0x186 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (390 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_87FF: /* 0x187 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (391 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_88FF: /* 0x188 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (392 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_89FF: /* 0x189 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (393 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8AFF: /* 0x18a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (394 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8BFF: /* 0x18b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (395 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8CFF: /* 0x18c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (396 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8DFF: /* 0x18d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (397 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8EFF: /* 0x18e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (398 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_8FFF: /* 0x18f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (399 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_90FF: /* 0x190 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (400 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_91FF: /* 0x191 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (401 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_92FF: /* 0x192 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (402 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_93FF: /* 0x193 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (403 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_94FF: /* 0x194 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (404 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_95FF: /* 0x195 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (405 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_96FF: /* 0x196 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (406 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_97FF: /* 0x197 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (407 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_98FF: /* 0x198 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (408 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_99FF: /* 0x199 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (409 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9AFF: /* 0x19a */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (410 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9BFF: /* 0x19b */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (411 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9CFF: /* 0x19c */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (412 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9DFF: /* 0x19d */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (413 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9EFF: /* 0x19e */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (414 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_9FFF: /* 0x19f */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (415 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (416 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (417 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (418 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (419 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (420 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (421 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (422 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (423 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (424 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (425 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (426 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (427 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (428 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (429 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (430 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_AFFF: /* 0x1af */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (431 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (432 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (433 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (434 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (435 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (436 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (437 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (438 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (439 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (440 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (441 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (442 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (443 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (444 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (445 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BEFF: /* 0x1be */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (446 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (447 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (448 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (449 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (450 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (451 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (452 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (453 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (454 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (455 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (456 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (457 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (458 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (459 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (460 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (461 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (462 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (463 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (464 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (465 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (466 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (467 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (468 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (469 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (470 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (471 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (472 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (473 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DAFF: /* 0x1da */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (474 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DBFF: /* 0x1db */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (475 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (476 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (477 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DEFF: /* 0x1de */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (478 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_DFFF: /* 0x1df */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (479 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (480 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (481 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (482 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (483 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (484 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (485 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (486 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (487 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (488 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (489 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (490 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (491 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (492 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (493 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (494 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (495 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (496 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (497 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (498 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (499 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (500 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (501 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (502 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (503 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (504 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (505 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (506 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (507 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (508 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (509 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (510 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+/* ------------------------------ */
+    .balign 64
+.L_ALT_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: armv5te/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.    Note that the call to dvmCheckBefore is done as a tail call.
+ * rIBASE updates won't be seen until a refresh, and we can tell we have a
+ * stale rIBASE if breakFlags==0.  Always refresh rIBASE here, and then
+ * bail to the real handler if breakFlags==0.
+ */
+    ldrb   r3, [rSELF, #offThread_breakFlags]
+    adrl   lr, dvmAsmInstructionStart + (511 * 64)
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    cmp    r3, #0
+    bxeq   lr                   @ nothing to do - jump to real handler
+    EXPORT_PC()
+    mov    r0, rPC              @ arg0
+    mov    r1, rFP              @ arg1
+    mov    r2, rSELF            @ arg2
+    b      dvmCheckBefore       @ (dPC,dFP,self) tail call
+
+    .balign 64
+    .size   dvmAsmAltInstructionStart, .-dvmAsmAltInstructionStart
+    .global dvmAsmAltInstructionEnd
+dvmAsmAltInstructionEnd:
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+
+#if defined(WITH_JIT)
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * "longjmp" to a translation after single-stepping.  Before returning
+ * to translation, must save state for self-verification.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    b      jitSVShadowRunStart                   @ resume as if cache hit
+                                                 @ expects resume addr in r10
+
+    .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
+    mov    r3, #0
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
+    b      jitSVShadowRunEnd            @ doesn't return
+
+
+    .global dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
+    mov    r3, #0                       @ 0 means !inJitCodeCache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    b      jitSVShadowRunEnd            @ doesn't return
+#else
+
+/*
+ * "longjmp" to a translation after single-stepping.
+ */
+    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
+dvmJitResumeTranslation:
+    mov    rSELF, r0                             @ restore self
+    mov    rPC, r1                               @ restore Dalvik pc
+    mov    rFP, r2                               @ restore Dalvik fp
+    ldr    r0, [rSELF,#offThread_jitResumeNPC]
+    mov    r2, #0
+    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
+    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
+    bx     r0                                    @ resume translation
+
+/*
+ * 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
+#if defined(WITH_JIT_TUNING)
+    mov    r0,lr
+    bl     dvmBumpPunt;
+#endif
+    EXPORT_PC()
+    mov    r0, #0
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * We'll use the normal single-stepping mechanism via interpBreak,
+ * but also save the native pc of the resume point in the translation
+ * and the native sp so that we can later do the equivalent of a
+ * longjmp() to resume.
+ * On entry:
+ *    dPC <= Dalvik PC of instrucion to interpret
+ *    lr <= resume point in translation
+ *    r1 <= Dalvik PC of next instruction
+ */
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    rPC, r0              @ set up dalvik pc
+    EXPORT_PC()
+    str    lr, [rSELF,#offThread_jitResumeNPC]
+    str    sp, [rSELF,#offThread_jitResumeNSP]
+    str    r1, [rSELF,#offThread_jitResumeDPC]
+    mov    r1, #1
+    str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
+    mov    r0, rSELF
+    mov    r1, #kSubModeCountedStep
+    bl     dvmEnableSubMode     @ (self, newMode)
+    ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used for callees.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0                    @ !0 means translation exists
+    bxne   r0                       @ continue native execution if so
+    b      2f                       @ branch over to use the interpreter
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used following
+ * invokes.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    rPC,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST, #-4              @  .. which is 9 bytes back
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    2f
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @ in case target is HANDLER_INTERPRET
+    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:
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    FETCH_INST()
+    cmp    r0, #0
+    movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
+    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,[lr, #-1]           @ get our target PC
+    add    rINST,lr,#-5            @ save start of chain branch
+    add    rINST,#-4               @ .. which is 9 bytes back
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNormal
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    cmp    r0,#0
+    beq    toInterpreter            @ go if not, otherwise do chain
+    mov    r1,rINST
+    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    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 dvmJitToInterpNoChainNoProfile
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Return from the translation cache to the interpreter to do method invocation.
+ * Check if translation exists for the callee, but don't chain to it.
+ */
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+#if defined(WITH_JIT_TUNING)
+    bl     dvmBumpNoChain
+#endif
+    mov    r0,rPC
+    mov    r1,rSELF
+    bl     dvmJitGetTraceAddrThread @ (pc, self)
+    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+#endif
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rSELF & 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()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    ldr    r0, [rSELF, #offThread_pJitProfTable]
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    @ NOTE: intended fallthrough
+
+/*
+ * Similar to common_updateProfile, but tests for null pJitProfTable
+ * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
+ * rIBASE has been recently refreshed.
+ */
+common_testUpdateProfile:
+    cmp     r0, #0               @ JIT switched off?
+    beq     4f                   @ return to interp if so
+
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.
+ * On entry here:
+ *    r0    <= pJitProfTable (verified non-NULL)
+ *    rPC   <= Dalvik PC
+ *    rINST <= next instruction
+ */
+common_updateProfile:
+    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+    lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
+    ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
+    GET_INST_OPCODE(ip)
+    subs    r1,r1,#1           @ decrement counter
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
+    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
+
+    /* Looks good, reset the counter */
+    ldr     r1, [rSELF, #offThread_jitThreshold]
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
+    EXPORT_PC()
+    mov     r0,rPC
+    mov     r1,rSELF
+    bl      dvmJitGetTraceAddrThread    @ (pc, self)
+    str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov     r1, rPC                     @ arg1 of translation may need this
+    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
+    cmp     r0,#0
+#if !defined(WITH_SELF_VERIFICATION)
+    bxne    r0                          @ jump to the translation
+    mov     r2,#kJitTSelectRequest      @ ask for trace selection
+    @ fall-through to common_selectTrace
+#else
+    moveq   r2,#kJitTSelectRequest      @ ask for trace selection
+    beq     common_selectTrace
+    /*
+     * At this point, we have a target translation.  However, if
+     * that translation is actually the interpret-only pseudo-translation
+     * we want to treat it the same as no translation.
+     */
+    mov     r10, r0                     @ save target
+    bl      dvmCompilerGetInterpretTemplate
+    cmp     r0, r10                     @ special case?
+    bne     jitSVShadowRunStart         @ set up self verification shadow space
+    @ Need to clear the inJitCodeCache flag
+    mov    r3, #0                       @ 0 means not in the JIT code cache
+    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+/*
+ * On entry:
+ *  r2 is jit state.
+ */
+common_selectTrace:
+    ldrh    r0,[rSELF,#offThread_subMode]
+    ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
+    bne     3f                         @ already doing JIT work, continue
+    str     r2,[rSELF,#offThread_jitState]
+    mov     r0, rSELF
+/*
+ * Call out to validate trace-building request.  If successful,
+ * rIBASE will be swapped to to send us into single-stepping trace
+ * building mode, so we need to refresh before we continue.
+ */
+    EXPORT_PC()
+    SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
+    bl      dvmJitCheckTraceRequest
+3:
+    FETCH_INST()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+4:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry:
+ *    rPC, rFP, rSELF: the values that they should contain
+ *    r10: the address of the target translation.
+ */
+jitSVShadowRunStart:
+    mov     r0,rPC                      @ r0<- program counter
+    mov     r1,rFP                      @ r1<- frame pointer
+    mov     r2,rSELF                    @ r2<- self (Thread) pointer
+    mov     r3,r10                      @ r3<- target translation
+    bl      dvmSelfVerificationSaveState @ save registers to shadow space
+    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
+    bx      r10                         @ jump to the translation
+
+/*
+ * Restore PC, registers, and interpreter state to original values
+ * before jumping back to the interpreter.
+ * On entry:
+ *   r0:  dPC
+ *   r2:  self verification state
+ */
+jitSVShadowRunEnd:
+    mov    r1,rFP                        @ pass ending fp
+    mov    r3,rSELF                      @ pass self ptr for convenience
+    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
+    LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
+    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
+    cmp    r1,#0                         @ check for punt condition
+    beq    1f
+    @ Set up SV single-stepping
+    mov    r0, rSELF
+    mov    r1, #kSubModeJitSV
+    bl     dvmEnableSubMode              @ (self, subMode)
+    mov    r2,#kJitSelfVerification      @ ask for self verification
+    str    r2,[rSELF,#offThread_jitState]
+    @ intentional fallthrough
+1:                                       @ exit to interpreter without check
+    EXPORT_PC()
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#endif
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ * It will end this interpreter activation, and return to the caller
+ * of dvmMterpStdRun.
+ *
+ * State registers will be saved to the "thread" area before bailing
+ * debugging purposes
+ */
+common_gotoBail:
+    SAVE_PC_FP_TO_SELF()                @ export state to "thread"
+    mov     r0, rSELF                   @ r0<- self ptr
+    b       dvmMterpStdBail             @ call(self, changeInterp)
+
+/*
+ * The JIT's invoke method needs to remember the callsite class and
+ * target pair.  Save them here so that they are available to
+ * dvmCheckJit following the interpretation of this invoke.
+ */
+#if defined(WITH_JIT)
+save_callsiteinfo:
+    cmp     r9, #0
+    ldrne   r9, [r9, #offObject_clazz]
+    str     r0, [rSELF, #offThread_methodToCall]
+    str     r9, [rSELF, #offThread_callsiteClass]
+    bx      lr
+#endif
+
+/*
+ * Common code for jumbo method invocation.
+ * NOTE: this adjusts rPC to account for the difference in instruction width.
+ * As a result, the savedPc in the stack frame will not be wholly accurate. So
+ * long as that is only used for source file line number calculations, we're
+ * okay.
+ */
+common_invokeMethodJumboNoThis:
+#if defined(WITH_JIT)
+ /* On entry: r0 is "Method* methodToCall */
+    mov     r9, #0                      @ clear "this"
+#endif
+common_invokeMethodJumbo:
+ /* On entry: r0 is "Method* methodToCall, r9 is "this" */
+.LinvokeNewJumbo:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ prepare to copy args to "outs" area of current frame
+    add     rPC, rPC, #4                @ adjust pc to make return consistent
+    FETCH(r2, 1)                        @ r2<- BBBB (arg count)
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    cmp     r2, #0                      @ no args?
+    beq     .LinvokeArgsDone            @ if no args, skip the rest
+    FETCH(r1, 2)                        @ r1<- CCCC
+    b       .LinvokeRangeArgs           @ handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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
+
+.LinvokeRangeArgs:
+    @ 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
+1:  ldr     r1, [r3], #4                @ val = *fp++
+    subs    r2, r2, #1                  @ count--
+    str     r1, [r10], #4               @ *outs++ = val
+    bne     1b                          @ ...while count != 0
+    b       .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", r9 is "this"
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+#if defined(WITH_JIT)
+    ldrh    r1, [rSELF, #offThread_subMode]
+    ands    r1, #kSubModeJitTraceBuild
+    blne    save_callsiteinfo
+#endif
+    @ 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)
+    beq     .LinvokeArgsDone
+
+    @ r0=methodToCall, r1=GFED, r2=count, 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
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
+    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, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
+    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
+    cmp     r3, r9                      @ bottom < interpStackEnd?
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
+    blo     .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]
+
+    @ Profiling?
+    cmp     lr, #0                      @ any special modes happening?
+    bne     2f                          @ go if so
+1:
+    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
+
+    @ Update state values for the new method
+    @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
+    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
+    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
+    mov     r2, #1
+    str     r2, [rSELF, #offThread_debugIsMethodEntry]
+#if defined(WITH_JIT)
+    ldr     r0, [rSELF, #offThread_pJitProfTable]
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [rSELF, #offThread_curFrame]   @ 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, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#endif
+
+2:
+    @ Profiling - record method entry.  r0: methodToCall
+    stmfd   sp!, {r0-r3}                @ preserve r0-r3
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    mov     r1, r0
+    mov     r0, rSELF
+    bl      dvmReportInvoke             @ (self, method)
+    ldmfd   sp!, {r0-r3}                @ restore r0-r3
+    b       1b
+
+.LinvokeNative:
+    @ Prep for the native call
+    @ r0=methodToCall, r1=newFp, r10=newSaveArea
+    ldrh    lr, [rSELF, #offThread_subMode]
+    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
+    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFp (points to args)
+    add     r1, rSELF, #offThread_retval  @ r1<- &retval
+    mov     r3, rSELF                   @ arg3<- self
+
+#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
+
+    cmp     lr, #0                      @ any special SubModes active?
+    bne     11f                         @ go handle them if so
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+7:
+
+    @ native return; r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
+    ldr     r1, [rSELF, #offThread_exception] @ check for exception
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
+    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
+
+11:
+    @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
+    stmfd   sp!, {r0-r3}                @ save all but subModes
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
+    ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
+
+    @ Call the native method
+    mov     lr, pc                      @ set return addr
+    ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+
+    @ Restore the pre-call arguments
+    ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
+
+    @ Finish up any post-invoke subMode requirements
+    mov     r0, r2                      @ r0<- methodToCall
+    mov     r1, rSELF
+    mov     r2, rFP
+    bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
+    b       7b                          @ resume
+
+.LstackOverflow:    @ r0=methodToCall
+    mov     r1, r0                      @ r1<- methodToCall
+    mov     r0, rSELF                   @ r0<- self
+    bl      dvmHandleStackOverflow
+    b       common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+    .fnend
+    .size   dalvik_mterp, .-dalvik_mterp
+#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, rSELF                   @ A0<- self
+    SAVE_PC_FP_TO_SELF()                @ export state to "self"
+    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:
+    ldrh    lr, [rSELF, #offThread_subMode]
+    SAVEAREA_FROM_FP(r0, rFP)
+    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+    cmp     lr, #0                      @ any special subMode handling needed?
+    bne     19f
+14:
+    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    cmp     r2, #0                      @ is this a break frame?
+#if defined(WORKAROUND_CORTEX_A9_745320)
+    /* Don't use conditional loads if the HW defect exists */
+    beq     15f
+    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+15:
+#else
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+#endif
+    beq     common_gotoBail             @ break frame, bail out completely
+
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
+    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
+    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
+#if defined(WITH_JIT)
+    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
+    cmp     r10, #0                      @ caller is compiled code
+    blxne   r10
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rSELF, #offThread_methodClassDex]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+19:
+    @ Handle special actions
+    @ On entry, r0: StackSaveArea
+    ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
+    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
+    str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
+    mov     r0, rSELF
+    bl      dvmReportReturn             @ (self)
+    SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
+    b       14b                         @ continue
+
+    /*
+     * Return handling, calls through "glue code".
+     */
+     .if    0
+.LreturnOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ 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:
+
+    EXPORT_PC()
+
+    mov     r0, rSELF
+    bl      dvmCheckSuspendPending
+
+    ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
+    mov     r1, rSELF                   @ r1<- self
+    mov     r0, r9                      @ r0<- exception
+    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
+    ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
+    mov     r3, #0                      @ r3<- NULL
+    str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
+
+    @ Special subMode?
+    cmp     r2, #0                      @ any special subMode handling needed?
+    bne     7f                          @ go if so
+8:
+    /* 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, [rSELF, #offThread_method] @ r1<- self->method
+    mov     r0, rSELF                   @ r0<- self
+    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
+    ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags
+    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, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    beq     1f                          @ no, skip ahead
+    mov     rFP, r0                     @ save relPc result in rFP
+    mov     r0, rSELF                   @ r0<- self
+    mov     r1, r9                      @ r1<- exception
+    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->interpSave.curFrame and updated PC */
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
+    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
+    str     r1, [rSELF, #offThread_method]  @ self->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, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
+
+    /* release the tracked alloc on the exception */
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+
+    /* restore the exception if the handler wants it */
+    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
+    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, [rSELF, #offThread_exception] @ yes, restore the exception
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    @ Manage debugger bookkeeping
+7:
+    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
+    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
+    mov     r0, rSELF                       @ arg0<- self
+    mov     r1, r9                          @ arg1<- exception
+    bl      dvmReportExceptionThrow         @ (self, exception)
+    b       8b                              @ resume with normal handling
+
+.LnotCaughtLocally: @ r9=exception
+    /* fix stack overflow if necessary */
+    ldrb    r1, [rSELF, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    movne   r0, rSELF                   @ if yes: r0<- self
+    movne   r1, r9                      @ if yes: r1<- exception
+    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, [rSELF, #offThread_method]
+    ldr     r1, [r0, #offMethod_insns]
+    sub     r1, rPC, r1
+    asr     r1, r1, #1
+    bl      dvmLineNumFromPC
+    str     r0, [sp, #-4]!
+    @ dvmGetMethodSourceFile(method)
+    ldr     r0, [rSELF, #offThread_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, [rSELF, #offThread_exception] @ restore exception
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, rSELF                   @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+    b       common_gotoBail             @ bail out
+
+
+    /*
+     * Exception handling, calls through "glue code".
+     */
+    .if     0
+.LexceptionOld:
+    SAVE_PC_FP_TO_SELF()                @ export state
+    mov     r0, rSELF                   @ arg to function
+    bl      dvmMterp_exceptionThrown
+    b       common_resumeAfterGlueCall
+    .endif
+
+#if defined(WITH_JIT)
+    /*
+     * If the JIT is actively building a trace we need to make sure
+     * that the field is fully resolved before including the current
+     * instruction.
+     *
+     * On entry:
+     *     r10: &dvmDex->pResFields[field]
+     *     r0:  field pointer (must preserve)
+     */
+common_verifyField:
+    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
+    ands    r3, #kSubModeJitTraceBuild
+    bxeq    lr                          @ Not building trace, continue
+    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
+    cmp     r1, #0                      @ resolution complete?
+    bxne    lr                          @ yes, continue
+    stmfd   sp!, {r0-r2,lr}             @ save regs
+    mov     r0, rSELF
+    mov     r1, rPC
+    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
+    ldmfd   sp!, {r0-r2, lr}
+    bx      lr                          @ return
+#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_SELF()              @ pull rPC and rFP out of thread
+    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Invalid array index. Note that our calling convention is strange; we use r1
+ * and r3 because those just happen to be the registers all our callers are
+ * using. We move r3 before calling the C function, but r1 happens to match.
+ * r1: index
+ * r3: size
+ */
+common_errArrayIndex:
+    EXPORT_PC()
+    mov     r0, r3
+    bl      dvmThrowArrayIndexOutOfBoundsException
+    b       common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+    EXPORT_PC()
+    ldr     r0, strDivideByZero
+    bl      dvmThrowArithmeticException
+    b       common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry: length in r1
+ */
+common_errNegativeArraySize:
+    EXPORT_PC()
+    mov     r0, r1                                @ arg0 <- len
+    bl      dvmThrowNegativeArraySizeException    @ (len)
+    b       common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ * On entry: method name in r1
+ */
+common_errNoSuchMethod:
+    EXPORT_PC()
+    mov     r0, r1
+    bl      dvmThrowNoSuchMethodError
+    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()
+    mov     r0, #0
+    bl      dvmThrowNullPointerException
+    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
+strDivideByZero:
+    .word   .LstrDivideByZero
+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"
+.LstrFilledNewArrayNotImpl:
+    .asciz  "filled-new-array only implemented for objects and 'int'"
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrLogTag:
+    .asciz  "mterp"
+.LstrExceptionNotCaughtLocally:
+    .asciz  "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+    .asciz  "\n"
+.LstrSqueak:
+    .asciz  "<%d>"
+.LstrPrintHex:
+    .asciz  "<%#x>"
+.LstrPrintLong:
+    .asciz  "<%lld>"
+
diff --git a/vm/mterp/out/InterpAsm-x86-atom.S b/vm/mterp/out/InterpAsm-x86-atom.S
new file mode 100644
index 0000000..e7ca17c
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-x86-atom.S
@@ -0,0 +1,27864 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'x86-atom'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: x86-atom/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.
+    */
+
+   /*
+    * File: header.S
+    */
+
+   /*
+    * IA32 calling convention and general notes:
+    *
+    * EAX, ECX, EDX - general purpose scratch registers (caller-saved);
+    *
+    * The stack (%esp) - used to pass arguments to functions
+    *
+    * EAX - holds the first 4 bytes of a return
+    * EDX - holds the second 4 bytes of a return
+    *
+    * EBX, ESI, EDI, EBP - are callee saved
+    *
+    * CS, DS, SS - are segment registers
+    * ES, FS, GS - are segment registers. We will try to avoid using these registers
+    *
+    * The stack is "full descending". Only the arguments that do not fit    * in the first two arg registers are placed on the stack.
+    * "%esp" points to the first stacked argument (i.e. the 3rd arg).
+    */
+
+   /*
+    * Mterp and IA32 notes
+    *
+    * mem          nick      purpose
+    * (%ebp)       rGLUE     InterpState base pointer (A.K.A. MterpGlue Pointer)
+    * %esi         rPC       interpreted program counter, used for fetching
+    *                        instructions
+    * %ebx         rINST     first 16-bit code unit of current instruction
+    * %edi         rFP       interpreted frame pointer, used for accessing
+    *                        locals and args
+    */
+
+   /*
+    * Includes
+    */
+
+#include "../common/asm-constants.h"
+
+   /*
+    * Reserved registers
+    */
+
+#define rGLUE  (%ebp)
+#define rINST   %ebx
+#define rINSTbl  %bl
+#define rINSTbh  %bh
+#define rINSTw  %bx
+#define rPC     %esi
+#define rFP     %edi
+
+   /*
+    * Temporary register used when finishing an opcode
+    */
+
+#define rFinish %edx
+
+   /*
+    * Stack locations used for temporary data. For convenience.
+    */
+
+#define sReg0    4(%ebp)
+#define sReg1    8(%ebp)
+#define sReg2   12(%ebp)
+#define sReg3   16(%ebp)
+
+   /*
+    * Save the PC and FP to the glue struct
+    */
+
+    .macro      SAVE_PC_FP_TO_GLUE _reg
+    movl        rGLUE, \_reg
+    movl        rPC, offGlue_pc(\_reg)
+    movl        rFP, offGlue_fp(\_reg)
+    .endm
+
+   /*
+    * Restore the PC and FP from the glue struct
+    */
+
+    .macro      LOAD_PC_FP_FROM_GLUE
+    movl        rGLUE, rFP
+    movl        offGlue_pc(rFP), rPC
+    movl        offGlue_fp(rFP), rFP
+    .endm
+
+   /*
+    * "Export" the PC to the stack frame, f/b/o future exception objects. This 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.
+    */
+
+    .macro      EXPORT_PC
+    movl        rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
+    .endm
+
+   /*
+    * Given a frame pointer, find the stack save area.
+    * In C this is "((StackSaveArea*)(_fp) -1)".
+    */
+
+    .macro      SAVEAREA_FROM_FP  _reg
+    lea         -sizeofStackSaveArea(rFP), \_reg
+    .endm
+
+   /*
+    * Get the 32-bit value from a dalvik register.
+    */
+
+    .macro      GET_VREG _vreg
+    movl        (rFP,\_vreg, 4), \_vreg
+    .endm
+
+   /*
+    * Set the 32-bit value from a dalvik register.
+    */
+
+    .macro      SET_VREG _reg _vreg
+    movl        \_reg, (rFP,\_vreg, 4)
+    .endm
+
+   /*
+    * Fetch the next instruction from rPC into rINST. Does not advance rPC.
+    */
+
+    .macro      FETCH_INST
+    movzwl      (rPC), rINST
+    .endm
+
+   /*
+    * Fetch the next instruction from the specified offset. Advances rPC
+    * to point to the next instruction. "_count" is in 16-bit code units.
+    *
+    * 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())
+    */
+
+    .macro      FETCH_ADVANCE_INST _count
+    add         $(\_count*2), rPC
+    movzwl      (rPC), rINST
+    .endm
+
+   /*
+    * 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.
+    */
+
+    .macro      FETCH_ADVANCE_INST_RB _reg
+    addl        \_reg, rPC
+    movzwl      (rPC), rINST
+    .endm
+
+   /*
+    * 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.
+    * For example, given instruction of format: AA|op BBBB, it
+    * fetches BBBB.
+    */
+
+    .macro      FETCH _count _reg
+    movzwl      (\_count*2)(rPC), \_reg
+    .endm
+
+   /*
+    * 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.
+    * This variant treats the value as signed.
+    */
+
+    .macro      FETCHs _count _reg
+    movswl      (\_count*2)(rPC), \_reg
+    .endm
+
+   /*
+    * Fetch the first byte from an offset past the current PC. The
+    * "_count" value is in 16-bit code units. Does not advance rPC.
+    * For example, given instruction of format: AA|op CC|BB, it
+    * fetches BB.
+    */
+
+    .macro      FETCH_BB _count _reg
+    movzbl      (\_count*2)(rPC), \_reg
+    .endm
+
+    /*
+    * Fetch the second byte from an offset past the current PC. The
+    * "_count" value is in 16-bit code units. Does not advance rPC.
+    * For example, given instruction of format: AA|op CC|BB, it
+    * fetches CC.
+    */
+
+    .macro      FETCH_CC _count _reg
+    movzbl      (\_count*2 + 1)(rPC), \_reg
+    .endm
+
+   /*
+    * Fetch the second byte from an offset past the current PC. The
+    * "_count" value is in 16-bit code units. Does not advance rPC.
+    * This variant treats the value as signed.
+    */
+
+    .macro      FETCH_CCs _count _reg
+    movsbl      (\_count*2 + 1)(rPC), \_reg
+    .endm
+
+
+   /*
+    * 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).
+    */
+
+    .macro      FETCH_B _reg  _count  _byte
+    movzbl      (\_count*2+\_byte)(rPC), \_reg
+    .endm
+
+   /*
+    * Put the instruction's opcode field into the specified register.
+    */
+
+    .macro      GET_INST_OPCODE _reg
+    movzbl      rINSTbl, \_reg
+    .endm
+
+   /*
+    * Begin executing the opcode in _reg.
+    */
+
+    .macro      GOTO_OPCODE _reg
+    shl         $6, \_reg
+    addl        $dvmAsmInstructionStart,\_reg
+    jmp         *\_reg
+    .endm
+
+
+
+   /*
+    * Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
+    * by using a jump table. _rFinish should must be the same register for
+    * both macros.
+    */
+
+    .macro      FFETCH _rFinish
+    movzbl      (rPC), \_rFinish
+    .endm
+
+    .macro      FGETOP_JMPa _rFinish
+    movzbl      1(rPC), rINST
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
+    * by using a jump table. _rFinish and _count should must be the same register for
+    * both macros.
+    */
+
+    .macro      FFETCH_ADV _count _rFinish
+    movzbl      (\_count*2)(rPC), \_rFinish
+    .endm
+
+    .macro      FGETOP_JMP _count _rFinish
+    movzbl      (\_count*2 + 1)(rPC), rINST
+    addl        $(\_count*2), rPC
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
+    * by using a jump table. _rFinish and _reg should must be the same register for
+    * both macros.
+    */
+
+    .macro      FFETCH_ADV_RB _reg _rFinish
+    movzbl      (\_reg, rPC), \_rFinish
+    .endm
+
+    .macro      FGETOP_RB_JMP _reg _rFinish
+    movzbl      1(\_reg, rPC), rINST
+    addl        \_reg, rPC
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_INST, GET_INST_OPCODE using
+    * a jump table. This macro should be called before FINISH_JMP where
+    * rFinish should be the same register containing the opcode value.
+    * This is an attempt to split up FINISH in order to reduce or remove
+    * potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_FETCH _rFinish
+    movzbl      (rPC), \_rFinish
+    movzbl      1(rPC), rINST
+    .endm
+
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using
+    * a jump table. This macro should be called before FINISH_JMP where
+    * rFinish should be the same register containing the opcode value.
+    * This is an attempt to split up FINISH in order to reduce or remove
+    * potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_FETCH_ADVANCE _count _rFinish
+    movzbl      (\_count*2)(rPC), \_rFinish
+    movzbl      (\_count*2 + 1)(rPC), rINST
+    addl        $(\_count*2), rPC
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using
+    * a jump table. This macro should be called before FINISH_JMP where
+    * rFinish should be the same register containing the opcode value.
+    * This is an attempt to split up FINISH in order to reduce or remove
+    * potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_FETCH_ADVANCE_RB _reg _rFinish
+    movzbl      (\_reg, rPC), \_rFinish
+    movzbl      1(\_reg, rPC), rINST
+    addl        \_reg, rPC
+    .endm
+
+   /*
+    * Attempts to speed up GOTO_OPCODE using a jump table. This macro should
+    * be called after a FINISH_FETCH* instruction where rFinish should be the
+    * same register containing the opcode value. This is an attempt to split up
+    * FINISH in order to reduce or remove potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_JMP _rFinish
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using
+    * a jump table. Uses a single macro - but it should be faster if we
+    * split up the fetch for rFinish and the jump using rFinish.
+    */
+
+    .macro      FINISH_A
+    movzbl      (rPC), rFinish
+    movzbl      1(rPC), rINST
+    jmp         *dvmAsmInstructionJmpTable(,rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE,
+    * GOTO_OPCODE by using a jump table. Uses a single macro -
+    * but it should be faster if we split up the fetch for rFinish
+    * and the jump using rFinish.
+    */
+
+    .macro      FINISH _count
+    movzbl      (\_count*2)(rPC), rFinish
+    movzbl      (\_count*2 + 1)(rPC), rINST
+    addl        $(\_count*2), rPC
+    jmp         *dvmAsmInstructionJmpTable(,rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE,
+    * GOTO_OPCODE by using a jump table. Uses a single macro -
+    * but it should be faster if we split up the fetch for rFinish
+    * and the jump using rFinish.
+    */
+
+    .macro      FINISH_RB _reg _rFinish
+    movzbl      (\_reg, rPC), \_rFinish
+    movzbl      1(\_reg, rPC), rINST
+    addl        \_reg, rPC
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Hard coded helper values.
+    */
+
+.balign 16
+
+.LdoubNeg:
+    .quad       0x8000000000000000
+
+.L64bits:
+    .quad       0xFFFFFFFFFFFFFFFF
+
+.LshiftMask2:
+    .quad       0x0000000000000000
+.LshiftMask:
+    .quad       0x000000000000003F
+
+.Lvalue64:
+    .quad       0x0000000000000040
+
+.LvaluePosInfLong:
+    .quad       0x7FFFFFFFFFFFFFFF
+
+.LvalueNegInfLong:
+    .quad       0x8000000000000000
+
+.LvalueNanLong:
+    .quad       0x0000000000000000
+
+.LintMin:
+.long   0x80000000
+
+.LintMax:
+.long   0x7FFFFFFF
+
+
+    .global dvmAsmInstructionStart
+    .type   dvmAsmInstructionStart, %function
+dvmAsmInstructionStart = .L_OP_NOP
+    .text
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NOP: /* 0x00 */
+/* File: x86-atom/OP_NOP.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NOP.S
+    *
+    * Code: Use a cycle. Uses no substitutions.
+    *
+    * For: nop
+    *
+    * Description: No operation. Use a cycle
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    FINISH      1                       # jump to next instruction
+
+#ifdef ASSIST_DEBUGGER
+
+   /*
+    * insert fake function header to help gdb find the stack frame
+    */
+
+    .type       dalvik_inst, %function
+dalvik_inst:
+    MTERP_ENTRY
+#endif
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE: /* 0x01 */
+/* File: x86-atom/OP_MOVE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move, move-object, long-to-int
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vB
+    SET_VREG    rINST, %ecx             # vA<- vB; %edx
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_FROM16: /* 0x02 */
+/* File: x86-atom/OP_MOVE_FROM16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_FROM16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move/from16, move-object/from16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: AA|op BBBB (22x)
+    *
+    * Syntax: op vAA, vBBBB
+    */
+
+    FETCH       1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    SET_VREG    %edx, rINST             # vA<- vB; %edx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_16: /* 0x03 */
+/* File: x86-atom/OP_MOVE_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move/16, move-object/16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              fp[A]<- fp[B]
+    *
+    * Format: ØØ|op AAAA BBBB (32x)
+    *
+    * Syntax: op vAAAA, vBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBB
+    FETCH       1, %ecx                 # %ecx<- AAAA
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    SET_VREG    %edx, %ecx              # vA<- vB; %edx
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_WIDE: /* 0x04 */
+/* File: x86-atom/OP_MOVE_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_WIDE.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move-wide
+    *
+    * Description: Copies contents from one non-object register to another.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA+
+    shr         $4, %edx               # %edx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- vB
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: x86-atom/OP_MOVE_WIDE_FROM16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_WIDE_FROM16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move-wide/from16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *
+    * Format: AA|op BBBB (22x)
+    *
+    * Syntax: op vAA, vBBBB
+    */
+
+    FETCH       1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- vB
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: x86-atom/OP_MOVE_WIDE_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_WIDE_16.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move-wide/16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *
+    * Format: ØØ|op AAAA BBBB (32x)
+    *
+    * Syntax: op vAAAA, vBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBB
+    FETCH       1, %ecx                 # %ecx<- AAAA
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, %ecx, 4)   # vA<- vB; %xmm0
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_OBJECT: /* 0x07 */
+/* File: x86-atom/OP_MOVE_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_OBJECT.S
+    */
+
+/* File: x86-atom/OP_MOVE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move, move-object, long-to-int
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vB
+    SET_VREG    rINST, %ecx             # vA<- vB; %edx
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: x86-atom/OP_MOVE_OBJECT_FROM16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_OBJECT_FROM16.S
+    */
+
+/* File: x86-atom/OP_MOVE_FROM16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_FROM16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move/from16, move-object/from16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: AA|op BBBB (22x)
+    *
+    * Syntax: op vAA, vBBBB
+    */
+
+    FETCH       1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    SET_VREG    %edx, rINST             # vA<- vB; %edx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: x86-atom/OP_MOVE_OBJECT_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_OBJECT_16.S
+    */
+
+/* File: x86-atom/OP_MOVE_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move/16, move-object/16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              fp[A]<- fp[B]
+    *
+    * Format: ØØ|op AAAA BBBB (32x)
+    *
+    * Syntax: op vAAAA, vBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBB
+    FETCH       1, %ecx                 # %ecx<- AAAA
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    SET_VREG    %edx, %ecx              # vA<- vB; %edx
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_RESULT: /* 0x0a */
+/* File: x86-atom/OP_MOVE_RESULT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT.S
+    *
+    * Code: Copies a return value to a register
+    *
+    * For: move-result, move-result-object
+    *
+    * Description: Move the single-word non-object result of the most
+    *              recent method invocation into the indicated register. This
+    *              must be done as the instruction immediately after a
+    *              method invocation whose (single-word, non-object) result
+    *              is not to be ignored; anywhere else is invalid.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    FFETCH_ADV  1, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    movl        offGlue_retval(%eax), %edx # %edx<- glue->retval
+    SET_VREG    %edx, rINST             # vA<- glue->retval
+    FGETOP_JMP  1, %ecx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: x86-atom/OP_MOVE_RESULT_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT_WIDE.S
+    *
+    * Code: Copies a return value to a register
+    *
+    * For: move-result-wide
+    *
+    * Description: Move the double-word non-object result of the most
+    *              recent method invocation into the indicated register. This
+    *              must be done as the instruction immediately after a
+    *              method invocation whose (single-word, non-object) result
+    *              is not to be ignored; anywhere else is invalid.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movq        offGlue_retval(%eax), %xmm0 # %xmm0<- glue->retval
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- glue->retval
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: x86-atom/OP_MOVE_RESULT_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT_OBJECT.S
+    */
+
+/* File: x86-atom/OP_MOVE_RESULT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT.S
+    *
+    * Code: Copies a return value to a register
+    *
+    * For: move-result, move-result-object
+    *
+    * Description: Move the single-word non-object result of the most
+    *              recent method invocation into the indicated register. This
+    *              must be done as the instruction immediately after a
+    *              method invocation whose (single-word, non-object) result
+    *              is not to be ignored; anywhere else is invalid.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    FFETCH_ADV  1, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    movl        offGlue_retval(%eax), %edx # %edx<- glue->retval
+    SET_VREG    %edx, rINST             # vA<- glue->retval
+    FGETOP_JMP  1, %ecx                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: x86-atom/OP_MOVE_EXCEPTION.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_EXCEPTION.S
+    *
+    * Code: Moves an exception to a register
+    *
+    * For: move-exception
+    *
+    * Description: Save a just-caught exception into the given register. This
+    *              instruction is only valid as the first instruction of an
+    *              exception handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        offThread_exception(%ecx), %edx # %edx<- glue->self->exception
+    movl        $0, offThread_exception(%ecx) # clear exception
+    SET_VREG    %edx, rINST             # vAA<- glue->self->exception
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID: /* 0x0e */
+/* File: x86-atom/OP_RETURN_VOID.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_VOID.S
+    */
+
+    jmp         common_returnFromMethod
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN: /* 0x0f */
+/* File: x86-atom/OP_RETURN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN.S
+    */
+
+/* File: x86-atom/OP_RETURN_COMMON.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_COMMON.S
+    *
+    * Code: Return a 32-bit value. Uses no substitutions.
+    *
+    * For: return, return-object
+    *
+    * Description: Copies the return value into the "glue"
+    *              structure, then jumps to the return handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offGlue_retval(%edx) # glue->retval<- vAA
+    jmp         common_returnFromMethod # jump to common return code
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_WIDE: /* 0x10 */
+/* File: x86-atom/OP_RETURN_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_WIDE.S
+    *
+    * Code: Return a 64-bit value. Uses no substitutions.
+    *
+    * For: return-wide
+    *
+    * Description: Copies the return value into the "glue"
+    *              structure, then jumps to the return handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vAA
+    movq        %xmm0, offGlue_retval(%edx)# glue->retval<- vAA
+    jmp         common_returnFromMethod # jump to common return code
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_OBJECT: /* 0x11 */
+/* File: x86-atom/OP_RETURN_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_OBJECT.S
+    */
+
+/* File: x86-atom/OP_RETURN_COMMON.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_COMMON.S
+    *
+    * Code: Return a 32-bit value. Uses no substitutions.
+    *
+    * For: return, return-object
+    *
+    * Description: Copies the return value into the "glue"
+    *              structure, then jumps to the return handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offGlue_retval(%edx) # glue->retval<- vAA
+    jmp         common_returnFromMethod # jump to common return code
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_4: /* 0x12 */
+/* File: x86-atom/OP_CONST_4.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_4.S
+    *
+    * Code: Moves a literal to a register. Uses no substitutions.
+    *
+    * For: const/4
+    *
+    * Description: Move the given literal value (right-zero-extended to 32
+    *              bits) into the specified register.
+    *
+    * Format: B|A|op (11n)
+    *
+    * Syntax: op vA, #+B
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    andl        $15, rINST             # rINST<- A
+    shl         $24, %edx              # %edx<- B000
+    sar         $28, %edx              # %edx<- right-zero-extended B
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    SET_VREG    %edx, rINST             # vA<- %edx; literal
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_16: /* 0x13 */
+/* File: x86-atom/OP_CONST_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_16.S
+    *
+    * Code: Moves a literal to a register. Uses no substitutions.
+    *
+    * For: const/16
+    *
+    * Description: Move the given literal value (right-zero-extended to 32
+    *              bits) into the specified register
+    *
+    * Format: AA|op BBBB (21s)
+    *
+    * Syntax: op vAA, #+BBBB
+    */
+
+    FETCHs      1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    SET_VREG    %edx rINST              # vAA<- BBBB; literal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST: /* 0x14 */
+/* File: x86-atom/OP_CONST.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const
+    *
+    * Description: Move the given literal value into the specified register
+    *
+    * Format: AA|op BBBBlo BBBBhi (31i)
+    *
+    * Syntax: op vAA, #+BBBBBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    shl         $16, %edx              # move BBBB to high bits
+    or          %edx, %ecx              # %ecx<- #+BBBBBBBB
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; literal
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_HIGH16: /* 0x15 */
+/* File: x86-atom/OP_CONST_HIGH16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_HIGH16.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const/high16
+    *
+    * Description: Move the given literal value (right-zero-extended to 32
+    *              bits) into the specified register
+    *
+    * Format: AA|op BBBB (21h)
+    *
+    * Syntax: op vAA, #+BBBB0000
+    */
+
+    FETCH       1, %ecx                 # %ecx<- 0000BBBB (zero-extended)
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    shl         $16, %ecx              # %ecx<- BBBB0000
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; BBBB0000
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE_16: /* 0x16 */
+/* File: x86-atom/OP_CONST_WIDE_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE_16.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const-wide/16
+    *
+    * Description: Move the given literal value (sign-extended to 64 bits)
+    *              into the specified register-pair
+    *
+    * Format: AA|op BBBB (21s)
+    *
+    * Syntax: op vAA, #+BBBB
+    */
+
+    FETCHs      1, %ecx                 # %ecx<- ssssBBBB (sign-extended)
+    movl        %ecx, %edx              # %edx<- ssssBBBB (sign-extended)
+    sar         $31, %ecx              # %ecx<- sign bit
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        %edx, (rFP, rINST, 4)   # vAA<- ssssBBBB
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1<- ssssssss
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE_32: /* 0x17 */
+/* File: x86-atom/OP_CONST_WIDE_32.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE_32.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const-wide/32
+    *
+    * Description: Move the given literal value (sign-extended to 64 bits)
+    *              into the specified register-pair
+    *
+    * Format: AA|op BBBBlo BBBBhi (31i)
+    *
+    * Syntax: op vAA, #+BBBBBBBB
+    */
+
+    FETCH       1,  %edx                # %edx<- BBBBlo
+    FETCHs      2, %ecx                 # %ecx<- BBBBhi
+    shl         $16, %ecx              # prepare to create #+BBBBBBBB
+    or          %ecx, %edx              # %edx<- %edx<- #+BBBBBBBB
+    sar         $31, %ecx              # %ecx<- sign bit
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        %edx, (rFP, rINST, 4)   # vAA<-  BBBBBBBB
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1<- ssssssss
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE: /* 0x18 */
+/* File: x86-atom/OP_CONST_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const-wide
+    *
+    * Description: Move the given literal value into the specified
+    *              register pair
+    *
+    * Format: AA|op BBBBlolo BBBBlohi BBBBhilo BBBBhihi (51l)
+    *
+    * Syntax: op vAA, #+BBBBBBBBBBBBBBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlolo
+    FETCH       2, %edx                 # %edx<- BBBBlohi
+    shl         $16, %edx              # %edx<- prepare to create #+BBBBBBBBlo
+    or          %edx, %ecx              # %ecx<- #+BBBBBBBBlo
+    movl        %ecx, (rFP, rINST, 4)   # vAA <- #+BBBBBBBBlo
+    FETCH       3, %ecx                 # %ecx<- BBBBhilo
+    FETCH       4, %edx                 # %edx<- BBBBhihi
+    FFETCH_ADV  5, %eax                 # %eax<- next instruction hi; fetch, advance
+    shl         $16, %edx              # %edx<- prepare to create #+BBBBBBBBhi
+    or          %edx, %ecx              # %ecx<- #+BBBBBBBBhi
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1 <- #+BBBBBBBBlo
+    FGETOP_JMP  5, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: x86-atom/OP_CONST_WIDE_HIGH16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE_HIGH16.S
+    *
+    * Code: Move a literal value to a register. Uses no substitutions.
+    *
+    * For: const-wide/high16
+    *
+    * Description: Move the given literal value (right-zero-extended to 64
+    *              bits) into the specified register
+    *
+    * Format: AA|op BBBB (21h)
+    *
+    * Syntax: op vAA, #+BBBB000000000000
+    */
+
+    FETCH       1, %ecx                 # %ecx<- 0000BBBB (zero-extended)
+    shl         $16, %ecx              # rINST<- AA
+    movl        $0, (rFP, rINST, 4)    # vAAlow<- 00000000
+    movl        %ecx, 4(rFP, rINST, 4)  # vAAhigh<- %ecx; BBBB0000
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_STRING: /* 0x1a */
+/* File: x86-atom/OP_CONST_STRING.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_STRING.S
+    *
+    * Code: Move a string reference to a register. Uses no substitutions.
+    *
+    * For: const/string
+    *
+    * Description: Move a referece to the string specified by the given
+    *              index into the specified register. vAA <- pResString[BBBB]
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
+    movl        offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
+    movl        (%eax, %ecx, 4), %eax   # %eax<- pResStrings[BBBB]
+    cmp         $0, %eax               # check if string is resolved
+    je          .LOP_CONST_STRING_resolve     # resolve string reference
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FINISH      2                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: x86-atom/OP_CONST_STRING_JUMBO.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_STRING_JUMBO.S
+    *
+    * Code: Move a string reference to a register. Uses no substitutions.
+    *
+    * For: const/string-jumbo
+    *
+    * Description: Move a reference to the string specified by the given
+    *              index into the specified register. vAA <- pResString[BBBB]
+    *
+    * Format: AA|op BBBBlo BBBBhi (31c)
+    *
+    * Syntax: op vAA, string@BBBBBBBB
+    */
+
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
+    movl        offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $16, %edx              # %edx<- prepare to create &BBBBBBBB
+    or          %edx, %ecx              # %ecx<- &BBBBBBBB
+    movl        (%eax, %ecx, 4), %eax   # %eax<- pResStrings[BBBB]
+    cmp         $0, %eax               # check if string is resolved
+    je          .LOP_CONST_STRING_JUMBO_resolve     # resolve string reference
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FINISH      3                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS: /* 0x1c */
+/* File: x86-atom/OP_CONST_CLASS.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_CLASS.S
+    *
+    * Code: Move a class reference to a register. Uses no substitutions.
+    *
+    * For: const/class
+    *
+    * Description: Move a reference to the class specified
+    *              by the given index into the specified register.
+    *              In the case where the indicated type is primitive,
+    *              this will store a reference to the primitive type's
+    *              degenerate class.
+    *
+    * Format: AA|op BBBBlo BBBBhi (21c)
+    *
+    * Syntax: op vAA, field@BBBB
+    */
+
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
+    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved class
+    cmp         $0, %eax               # check if classes is resolved before?
+    je          .LOP_CONST_CLASS_resolve     # resolve class
+    SET_VREG    %eax, rINST             # vAA<- resolved class
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MONITOR_ENTER: /* 0x1d */
+/* File: x86-atom/OP_MONITOR_ENTER.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MONITOR_ENTER.S
+    *
+    * Code: Aquire a monitor
+    *
+    * For: monitor-enter
+    *
+    * Description: Aquire a monitor for the indicated object.
+    *
+    *
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    GET_VREG    rINST                   # rINST<- vAA
+    cmp         $0, rINST              # check for null object
+    movl        offGlue_self(%eax), %eax # %eax<- glue->self
+    EXPORT_PC   # need for precise GC
+    je          common_errNullObject    # handle null object
+#    jmp         .LOP_MONITOR_ENTER_finish
+#%break
+#.LOP_MONITOR_ENTER_finish:
+    movl        rINST, -4(%esp)         # push parameter reference
+    movl        %eax, -8(%esp)          # push parameter
+    lea         -8(%esp), %esp
+    call        dvmLockObject           # call: (struct Thread* self,
+                                        #       struct Object* obj)
+                                        # return: void
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    lea         8(%esp), %esp
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MONITOR_EXIT: /* 0x1e */
+/* File: x86-atom/OP_MONITOR_EXIT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MONITOR_EXIT.S
+    *
+    * Code: Release a monitor
+    *
+    * For: monitor-exit
+    *
+    * Description: Release a monitor for the indicated object. If this instruction needs
+    *              to throw an execption, it must do so as if the pc has already
+    *              advanced pased the instruction.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # export the pc
+    GET_VREG    rINST                   # rINST<- vAA
+    cmp         $0, rINST              # rINST<- check for null object
+    je          common_errNullObject    # handle null object
+    push        rINST                   # push parameter object
+    push        offGlue_self(%eax)      # push parameter self
+    call        dvmUnlockObject         # call: (struct Thread* self,
+                                        #       struct Object* obj)
+                                        # return: bool
+    FINISH_FETCH_ADVANCE 1, %edx        # advance pc before exception
+    cmp         $0, %eax               # check for success
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    FINISH_JMP  %edx                    # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CHECK_CAST: /* 0x1f */
+/* File: x86-atom/OP_CHECK_CAST.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CHECK_CAST.S
+    *
+    * Code: Checks to see if a cast is allowed. Uses no substitutions.
+    *
+    * For: check-cast
+    *
+    * Description: Throw if the reference in the given register cannot be
+    *              cast to the indicated type. The type must be a reference
+    *              type (not a primitive type).
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, type@BBBB
+    */
+
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
+    cmp         $0, rINST              # check for null reference object
+    je          .LOP_CHECK_CAST_okay        # can always cast null object
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        (%eax, %ecx, 4), %ecx   # %ecx<- resolved class
+    cmp         $0, %ecx               # check if classes is resolved before?
+    je          .LOP_CHECK_CAST_resolve     # resolve class
+    jmp         .LOP_CHECK_CAST_resolved    # continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF: /* 0x20 */
+/* File: x86-atom/OP_INSTANCE_OF.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INSTANCE_OF.S
+    *
+    * Code: Checks if object is instance of a class. Uses no substitutions.
+    *
+    * For: instance-of
+    *
+    * Description: Store in the given destination register 1 if the indicated
+    *              reference is an instance of the given type, or 0 if not.
+    *              The type must be a reference type (not a primitive type).
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    GET_VREG    %edx                    # %edx<- vB
+    cmp         $0, %edx               # check for null object
+    je          .LOP_INSTANCE_OF_store       # null object
+    jmp         .LOP_INSTANCE_OF_break
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: x86-atom/OP_ARRAY_LENGTH.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ARRAY_LENGTH.S
+    *
+    * Code: 32-bit array length operation.
+    *
+    * For: array-length
+    *
+    * Description: Store the length of the indicated array in the given
+    *              destination register. vB <- offArrayObject_length(vA)
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    andl        $15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB
+    cmp         $0, %eax               # check for null array object
+    je          common_errNullObject    # handle null array object
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl        offArrayObject_length(%eax), %eax # %eax<- array length
+    movl        %eax, (rFP, rINST, 4)   # vA<- %eax; array length
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE: /* 0x22 */
+/* File: x86-atom/OP_NEW_INSTANCE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEW_INSTANCE.S
+    *
+    * Code: Create a new instance of a given type. Uses no substitutions.
+    *
+    * For: new-instance
+    *
+    * Description: Construct a new instance of the indicated type,
+    *              storing a reference to it in the destination.
+    *              The type must refer to a non-array class.
+    *
+    *
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, type@BBBB
+    *         op vAA, field@BBBB
+    *         op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %edx                 # %edx<- BBBB
+    movl        offDvmDex_pResClasses(%ecx), %ecx # %ecx<- glue->pDvmDex->pResClasses
+    movl        (%ecx, %edx, 4), %edx   # %edx<- vB
+    EXPORT_PC                           # required for resolve
+    cmp         $0, %edx               # check for null
+    je          .LOP_NEW_INSTANCE_resolve     # need to resolve
+
+   /*
+    *  %edx holds class object
+    */
+
+.LOP_NEW_INSTANCE_resolved:
+    movzbl      offClassObject_status(%edx), %eax # %eax<- class status
+    cmp         $CLASS_INITIALIZED, %eax # check if class is initialized
+    jne         .LOP_NEW_INSTANCE_needinit    # initialize class
+
+   /*
+    *  %edx holds class object
+    */
+
+.LOP_NEW_INSTANCE_initialized:
+    testl       $(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
+    mov         $ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
+    je          .LOP_NEW_INSTANCE_finish      # continue
+    jmp         .LOP_NEW_INSTANCE_abstract    # handle abstract or interface
+
+   /*
+    *  %edx holds class object
+    *  %eax holds flags for alloc call
+    */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY: /* 0x23 */
+/* File: x86-atom/OP_NEW_ARRAY.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEW_ARRAY.S
+    *
+    * Code: Create a new array. Uses no substitutions.
+    *
+    * For: new-array
+    *
+    * Description: Construct a new array of the indicated type and size.
+    *              The type must be an array type.
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    GET_VREG    %edx                    # %edx<- vB
+    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- glue->pDvmDex->pResClasses
+    cmp         $0, %edx               # check for negative length
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved class
+    js          common_errNegativeArraySize # handle negative array length
+    cmp         $0, %eax               # check for null
+    EXPORT_PC                           # required for resolve
+    jne         .LOP_NEW_ARRAY_finish      # already resovled so continue
+    jmp         .LOP_NEW_ARRAY_resolve     # need to resolve
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: x86-atom/OP_FILLED_NEW_ARRAY.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILLED_NEW_ARRAY.S
+    *
+    * Code: Constructs and fills an array with the given data. Provides
+    *
+    * For: float-to-int
+    *
+    * Description: Construct an array of the given type and size,
+    *              filling it with the supplied contents. The type
+    *              must be an array type. The array's contents
+    *              must be single-word. The constructed instance
+    *              is stored as a result in the same way that the
+    *              method invocation instructions store their results,
+    *              so the constructed instance must be moved to a
+    *              register with a subsequent move-result-object
+    *              instruction.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc) (range)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, vtaboff@CCCC
+    *         [B=4] op {vD, vE, vF, vG}, vtaboff@CCCC
+    *         [B=3] op {vD, vE, vF}, vtaboff@CCCC
+    *         [B=2] op {vD, vE}, vtaboff@CCCC
+    *         [B=1] op {vD}, vtaboff@CCCC
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB
+    *         op {vCCCC .. vNNNN}, type@BBBB
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- glue->methodClassDex
+    movl        offDvmDex_pResClasses(%edx), %edx # %edx<- glue->methodClassDex->pResClasses
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    EXPORT_PC
+    movl (%edx, %ecx, 4), %eax # %eax<- possibly resolved class
+    cmp         $0, %eax               # %eax<- check if already resolved
+    jne         .LOP_FILLED_NEW_ARRAY_continue
+    jmp         .LOP_FILLED_NEW_ARRAY_break
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILLED_NEW_ARRAY_RANGE.S
+    */
+
+/* File: x86-atom/OP_FILLED_NEW_ARRAY.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILLED_NEW_ARRAY.S
+    *
+    * Code: Constructs and fills an array with the given data. Provides
+    *
+    * For: float-to-int
+    *
+    * Description: Construct an array of the given type and size,
+    *              filling it with the supplied contents. The type
+    *              must be an array type. The array's contents
+    *              must be single-word. The constructed instance
+    *              is stored as a result in the same way that the
+    *              method invocation instructions store their results,
+    *              so the constructed instance must be moved to a
+    *              register with a subsequent move-result-object
+    *              instruction.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc) (range)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, vtaboff@CCCC
+    *         [B=4] op {vD, vE, vF, vG}, vtaboff@CCCC
+    *         [B=3] op {vD, vE, vF}, vtaboff@CCCC
+    *         [B=2] op {vD, vE}, vtaboff@CCCC
+    *         [B=1] op {vD}, vtaboff@CCCC
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB
+    *         op {vCCCC .. vNNNN}, type@BBBB
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- glue->methodClassDex
+    movl        offDvmDex_pResClasses(%edx), %edx # %edx<- glue->methodClassDex->pResClasses
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    EXPORT_PC
+    movl (%edx, %ecx, 4), %eax # %eax<- possibly resolved class
+    cmp         $0, %eax               # %eax<- check if already resolved
+    jne         .LOP_FILLED_NEW_ARRAY_RANGE_continue
+    jmp         .LOP_FILLED_NEW_ARRAY_RANGE_break
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: x86-atom/OP_FILL_ARRAY_DATA.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILL_ARRAY_DATA.S
+    *
+    * Code: Fills an array with given data. Uses no substitutions.
+    *
+    * For: fill-array-data
+    *
+    * Description: Fill the given array with the idicated data. The reference
+    *              must be an array of primitives, and the data table must
+    *              match it in type and size
+    *
+    * Format: AA|op BBBBlo BBBBhi (31t)
+    *
+    * Syntax: op vAA, +BBBBBBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $16, %edx              # prepare to create +BBBBBBBB
+    or          %ecx, %edx              # %edx<- +BBBBBBBB
+    lea         (rPC, %edx, 2), %edx    # %edx<- PC + +BBBBBBBB; array data location
+    EXPORT_PC
+    push        %edx
+    push        (rFP, rINST, 4)
+    call        dvmInterpHandleFillArrayData # call: (ArrayObject* arrayObject, const u2* arrayData)
+                                             # return: bool
+    FFETCH_ADV  3, %edx                 # %edx<- next instruction hi; fetch, advance
+    cmp         $0, %eax
+    lea         8(%esp), %esp
+    je          common_exceptionThrown
+    FGETOP_JMP  3, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW: /* 0x27 */
+/* File: x86-atom/OP_THROW.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_THROW.S
+    *
+    * Code: Throw an exception
+    *
+    * For: throw
+    *
+    * Description: Throw an exception object in the current thread.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # export the pc
+    GET_VREG    rINST                   # rINST<- vAA
+    cmp         $0, rINST              # check for null
+    movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
+    je          common_errNullObject    # handle null object
+    movl        rINST, offThread_exception(%ecx) # thread->exception<- object
+    jmp         common_exceptionThrown  # handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_GOTO: /* 0x28 */
+/* File: x86-atom/OP_GOTO.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_GOTO.S
+    *
+    * Code: Do an unconditional branch. Uses no substitutions.
+    *
+    * For: goto
+    *
+    * Description: Performs an unconditionally jump to the indicated instruction.
+    *              The branch uses an 8-bit offset that cannot be zero.
+    *
+    * Format: AA|op (10t)
+    *
+    * Syntax: op +AA
+    */
+
+LOP_GOTO.S:
+
+    movsbl      rINSTbl, %edx           # %edx<- +AA
+    shl         $1, %edx               # %edx is shifted for byte offset
+    js          common_periodicChecks_backwardBranch  # do check on backwards branch
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_GOTO_16: /* 0x29 */
+/* File: x86-atom/OP_GOTO_16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_GOTO_16.S
+    *
+    * Code: Do an unconditional branch. Uses no substitutions.
+    *
+    * For: goto/16
+    *
+    * Description: Performs an unconditionally jump to the indicated instruction.
+    *              The branch uses a 16-bit offset that cannot be zero.
+    *
+    * Format: ØØ|op AAAA (20t)
+    *
+    * Syntax: op +AAAA
+    */
+
+    FETCHs      1, %edx                 # %edx<- ssssAAAA (sign-extended)
+    shl         $1, %edx               # %edx is doubled to get the byte offset
+    js          common_periodicChecks_backwardBranch  # do check on backwards branch
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_GOTO_32: /* 0x2a */
+/* File: x86-atom/OP_GOTO_32.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_GOTO_32.S
+    *
+    * Code: Do an unconditional branch. Uses no substitutions.
+    *
+    * For: goto/32
+    *
+    * Description:  Performs an unconditionally jump to the indicated instruction.
+    *               The branch uses a 32-bit offset that can be zero.
+    *
+    * Format: ØØ|op AAAAlo AAAAhi (30t)
+    *
+    * Syntax: op +AAAAAAAA
+    */
+
+    FETCH       1, %edx                 # %edx<- AAAAlo
+    FETCH       2, %ecx                 # %ecx<- AAAAhi
+    shl         $16, %ecx              # prepare to create +AAAAAAAA
+    or          %ecx, %edx              # %edx<- +AAAAAAAA
+    shl         $1, %edx               # %edx is doubled to get the byte offset
+    jle          common_periodicChecks_backwardBranch  # do check on backwards branch
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_PACKED_SWITCH: /* 0x2b */
+/* File: x86-atom/OP_PACKED_SWITCH.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_PACKED_SWITCH.S
+    *
+    * Code: Jump to a new instruction using a jump table
+    *
+    * For: packed-switch, sparse-switch
+    *
+    * Description: Jump to a new instruction based on the value in the given
+    *              register, using a table of offsets corresponding to each
+    *              value in a particular integral range, or fall through to
+    *              the next instruction if there is no match.
+    *
+    * Format: AA|op BBBBlo BBBBhi (31t)
+    *
+    * Syntax: op vAA, +BBBBBBBB
+    */
+
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $16, %edx              # prepare to create +BBBBBBBB
+    or          %edx, %ecx              # %ecx<- +BBBBBBBB
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, -4(%esp)         # push parameter vAA
+    lea         (rPC, %ecx, 2), %ecx    # %ecx<- PC + +BBBBBBBB*2
+    movl        %ecx, -8(%esp)          # push parameter PC + +BBBBBBBB*2
+    lea         -8(%esp), %esp
+    call        dvmInterpHandlePackedSwitch                   # call code-unit branch offset
+    shl         $1, %eax               # shift for byte offset
+    movl        %eax, %edx              # %edx<- offset
+    lea         8(%esp), %esp
+    jle         common_periodicChecks_backwardBranch  # do backward branch
+    jmp         .LOP_PACKED_SWITCH_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: x86-atom/OP_SPARSE_SWITCH.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPARSE_SWITCH.S
+    */
+
+/* File: x86-atom/OP_PACKED_SWITCH.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_PACKED_SWITCH.S
+    *
+    * Code: Jump to a new instruction using a jump table
+    *
+    * For: packed-switch, sparse-switch
+    *
+    * Description: Jump to a new instruction based on the value in the given
+    *              register, using a table of offsets corresponding to each
+    *              value in a particular integral range, or fall through to
+    *              the next instruction if there is no match.
+    *
+    * Format: AA|op BBBBlo BBBBhi (31t)
+    *
+    * Syntax: op vAA, +BBBBBBBB
+    */
+
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $16, %edx              # prepare to create +BBBBBBBB
+    or          %edx, %ecx              # %ecx<- +BBBBBBBB
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, -4(%esp)         # push parameter vAA
+    lea         (rPC, %ecx, 2), %ecx    # %ecx<- PC + +BBBBBBBB*2
+    movl        %ecx, -8(%esp)          # push parameter PC + +BBBBBBBB*2
+    lea         -8(%esp), %esp
+    call        dvmInterpHandleSparseSwitch                   # call code-unit branch offset
+    shl         $1, %eax               # shift for byte offset
+    movl        %eax, %edx              # %edx<- offset
+    lea         8(%esp), %esp
+    jle         common_periodicChecks_backwardBranch  # do backward branch
+    jmp         .LOP_SPARSE_SWITCH_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: x86-atom/OP_CMPL_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_FLOAT.S
+    *
+    * Code: Provides a "nan" variable to specify the return value for
+    *       NaN. Provides a variable "sod" which appends a "s" or a "d"
+    *       to the move and comparison instructions, depending on if we
+    *       are working with a float or a double. For instructions
+    *       cmpx-float and cmpx-double, the x will be eiher a g or a l
+    *       to specify positive or negative bias for NaN.
+    *
+    * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
+    *
+    * Description: Perform the indicated floating point or long comparison,
+    *              storing 0 if the two arguments are equal, 1 if the second
+    *              argument is larger, or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movss    (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    comiss   (rFP, %edx, 4), %xmm0   # do comparison
+    ja          .LOP_CMPL_FLOAT_greater
+    jp          .LOP_CMPL_FLOAT_finalNan
+    jz          .LOP_CMPL_FLOAT_final
+
+.LOP_CMPL_FLOAT_less:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: x86-atom/OP_CMPG_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPG_FLOAT.S
+    */
+
+/* File: x86-atom/OP_CMPL_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_FLOAT.S
+    *
+    * Code: Provides a "nan" variable to specify the return value for
+    *       NaN. Provides a variable "sod" which appends a "s" or a "d"
+    *       to the move and comparison instructions, depending on if we
+    *       are working with a float or a double. For instructions
+    *       cmpx-float and cmpx-double, the x will be eiher a g or a l
+    *       to specify positive or negative bias for NaN.
+    *
+    * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
+    *
+    * Description: Perform the indicated floating point or long comparison,
+    *              storing 0 if the two arguments are equal, 1 if the second
+    *              argument is larger, or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movss    (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    comiss   (rFP, %edx, 4), %xmm0   # do comparison
+    ja          .LOP_CMPG_FLOAT_greater
+    jp          .LOP_CMPG_FLOAT_finalNan
+    jz          .LOP_CMPG_FLOAT_final
+
+.LOP_CMPG_FLOAT_less:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: x86-atom/OP_CMPL_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_DOUBLE.S
+    */
+
+/* File: x86-atom/OP_CMPL_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_FLOAT.S
+    *
+    * Code: Provides a "nan" variable to specify the return value for
+    *       NaN. Provides a variable "sod" which appends a "s" or a "d"
+    *       to the move and comparison instructions, depending on if we
+    *       are working with a float or a double. For instructions
+    *       cmpx-float and cmpx-double, the x will be eiher a g or a l
+    *       to specify positive or negative bias for NaN.
+    *
+    * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
+    *
+    * Description: Perform the indicated floating point or long comparison,
+    *              storing 0 if the two arguments are equal, 1 if the second
+    *              argument is larger, or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movsd    (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    comisd   (rFP, %edx, 4), %xmm0   # do comparison
+    ja          .LOP_CMPL_DOUBLE_greater
+    jp          .LOP_CMPL_DOUBLE_finalNan
+    jz          .LOP_CMPL_DOUBLE_final
+
+.LOP_CMPL_DOUBLE_less:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: x86-atom/OP_CMPG_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPG_DOUBLE.S
+    */
+
+/* File: x86-atom/OP_CMPL_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_FLOAT.S
+    *
+    * Code: Provides a "nan" variable to specify the return value for
+    *       NaN. Provides a variable "sod" which appends a "s" or a "d"
+    *       to the move and comparison instructions, depending on if we
+    *       are working with a float or a double. For instructions
+    *       cmpx-float and cmpx-double, the x will be eiher a g or a l
+    *       to specify positive or negative bias for NaN.
+    *
+    * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
+    *
+    * Description: Perform the indicated floating point or long comparison,
+    *              storing 0 if the two arguments are equal, 1 if the second
+    *              argument is larger, or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movsd    (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    comisd   (rFP, %edx, 4), %xmm0   # do comparison
+    ja          .LOP_CMPG_DOUBLE_greater
+    jp          .LOP_CMPG_DOUBLE_finalNan
+    jz          .LOP_CMPG_DOUBLE_final
+
+.LOP_CMPG_DOUBLE_less:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMP_LONG: /* 0x31 */
+/* File: x86-atom/OP_CMP_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMP_LONG.S
+    *
+    * Code: Compare floating point values. Uses no substitutions.
+    *
+    * For: cmp-long
+    *
+    * Description: Perform a long comparison, storing 0 if the two
+    *              arguments are equal, 1 if the second argument is larger
+    *              or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        4(rFP, %ecx, 4), %eax   # %eax<- vBBhi
+    cmp         4(rFP, %edx, 4), %eax   # compare vCChi and vBBhi
+    jl          .LOP_CMP_LONG_less
+    jg          .LOP_CMP_LONG_greater
+    movl        (rFP, %ecx, 4), %eax    # %eax<- vBBlo
+    cmp         (rFP, %edx, 4), %eax    # compare vCClo and vBBlo
+    ja          .LOP_CMP_LONG_greater
+    jne         .LOP_CMP_LONG_less
+    jmp         .LOP_CMP_LONG_final
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_EQ: /* 0x32 */
+/* File: x86-atom/OP_IF_EQ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_EQ.S
+    */
+
+/* File: x86-atom/bincmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $15, rINST             # rINST<- A
+    shr         $4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    jne  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_NE: /* 0x33 */
+/* File: x86-atom/OP_IF_NE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_NE.S
+    */
+
+/* File: x86-atom/bincmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $15, rINST             # rINST<- A
+    shr         $4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    je  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LT: /* 0x34 */
+/* File: x86-atom/OP_IF_LT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LT.S
+    */
+
+/* File: x86-atom/bincmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $15, rINST             # rINST<- A
+    shr         $4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    jge  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GE: /* 0x35 */
+/* File: x86-atom/OP_IF_GE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GE.S
+    */
+
+/* File: x86-atom/bincmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $15, rINST             # rINST<- A
+    shr         $4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    jl  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GT: /* 0x36 */
+/* File: x86-atom/OP_IF_GT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GT.S
+    */
+
+/* File: x86-atom/bincmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $15, rINST             # rINST<- A
+    shr         $4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    jle  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LE: /* 0x37 */
+/* File: x86-atom/OP_IF_LE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LE.S
+    */
+
+/* File: x86-atom/bincmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $15, rINST             # rINST<- A
+    shr         $4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    jg  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_EQZ: /* 0x38 */
+/* File: x86-atom/OP_IF_EQZ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_EQZ.S
+    */
+
+/* File: x86-atom/zcmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $0, (rFP, rINST, 4)    # compare vAA with zero
+    jne  OP_IF_EQZ_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+OP_IF_EQZ_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_NEZ: /* 0x39 */
+/* File: x86-atom/OP_IF_NEZ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_NEZ.S
+    */
+
+/* File: x86-atom/zcmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $0, (rFP, rINST, 4)    # compare vAA with zero
+    je  OP_IF_NEZ_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+OP_IF_NEZ_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LTZ: /* 0x3a */
+/* File: x86-atom/OP_IF_LTZ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LTZ.S
+    */
+
+/* File: x86-atom/zcmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $0, (rFP, rINST, 4)    # compare vAA with zero
+    jge  OP_IF_LTZ_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+OP_IF_LTZ_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GEZ: /* 0x3b */
+/* File: x86-atom/OP_IF_GEZ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GEZ.S
+    */
+
+/* File: x86-atom/zcmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $0, (rFP, rINST, 4)    # compare vAA with zero
+    jl  OP_IF_GEZ_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+OP_IF_GEZ_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GTZ: /* 0x3c */
+/* File: x86-atom/OP_IF_GTZ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GTZ.S
+    */
+
+/* File: x86-atom/zcmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $0, (rFP, rINST, 4)    # compare vAA with zero
+    jle  OP_IF_GTZ_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+OP_IF_GTZ_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LEZ: /* 0x3d */
+/* File: x86-atom/OP_IF_LEZ.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LEZ.S
+    */
+
+/* File: x86-atom/zcmp.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $0, (rFP, rINST, 4)    # compare vAA with zero
+    jg  OP_IF_LEZ_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+OP_IF_LEZ_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3E: /* 0x3e */
+/* File: x86-atom/OP_UNUSED_3E.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_3E.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3F: /* 0x3f */
+/* File: x86-atom/OP_UNUSED_3F.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_3F.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40: /* 0x40 */
+/* File: x86-atom/OP_UNUSED_40.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_40.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41: /* 0x41 */
+/* File: x86-atom/OP_UNUSED_41.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_41.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42: /* 0x42 */
+/* File: x86-atom/OP_UNUSED_42.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_42.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43: /* 0x43 */
+/* File: x86-atom/OP_UNUSED_43.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_43.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET: /* 0x44 */
+/* File: x86-atom/OP_AGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, 4), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_WIDE: /* 0x45 */
+/* File: x86-atom/OP_AGET_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_WIDE.S
+    *
+    * Code: 64-bit array get operation.
+    *
+    * For: aget-wide
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the destination
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        offArrayObject_contents(%ecx, %edx, 8), %xmm0 # %xmm0<- vBB[vCC]
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %xmm0; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_OBJECT: /* 0x46 */
+/* File: x86-atom/OP_AGET_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_OBJECT.S
+    */
+
+/* File: x86-atom/OP_AGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, 4), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: x86-atom/OP_AGET_BOOLEAN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_BOOLEAN.S
+    */
+
+/* File: x86-atom/OP_AGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movzbl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_BYTE: /* 0x48 */
+/* File: x86-atom/OP_AGET_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_BYTE.S
+    */
+
+/* File: x86-atom/OP_AGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movsbl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_CHAR: /* 0x49 */
+/* File: x86-atom/OP_AGET_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_CHAR.S
+    */
+
+/* File: x86-atom/OP_AGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movzwl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_SHORT: /* 0x4a */
+/* File: x86-atom/OP_AGET_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_SHORT.S
+    */
+
+/* File: x86-atom/OP_AGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movswl offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT: /* 0x4b */
+/* File: x86-atom/OP_APUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT.S
+    *
+    * Code: Generic 32-bit array put operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       move performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the move
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         (%ecx, %edx, 4), %ecx # %ecx<- &vBB[vCC]
+    GET_VREG    rINST                   # rINST<- vAA
+    movl     rINST, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_WIDE: /* 0x4c */
+/* File: x86-atom/OP_APUT_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_WIDE.S
+    *
+    * Code: 64-bit array put operation.
+    *
+    * For: aput-wide
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vAA
+    movq        %xmm0, offArrayObject_contents(%ecx, %edx, 8) # vBB[vCC]<- %xmm0; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_OBJECT: /* 0x4d */
+/* File: x86-atom/OP_APUT_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_OBJECT.S
+    *
+    * Code: 32-bit array put operation.  Provides an "scale" variable
+    *       specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the mov
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %eax                    # %eax<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %eax               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%eax), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    GET_VREG    rINST                   # rINST<- vAA
+    lea         (%eax, %edx, 4), %edx   # %edx<- &vBB[vCC]
+    cmp         $0, rINST              # check for null reference
+    je          .LOP_APUT_OBJECT_skip_check  # reference is null so skip type check
+    jmp         .LOP_APUT_OBJECT_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: x86-atom/OP_APUT_BOOLEAN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_BOOLEAN.S
+    */
+
+/* File: x86-atom/OP_APUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT.S
+    *
+    * Code: Generic 32-bit array put operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       move performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the move
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
+    GET_VREG    rINST                   # rINST<- vAA
+    movb     rINSTbl, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_BYTE: /* 0x4f */
+/* File: x86-atom/OP_APUT_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_BYTE.S
+    */
+
+/* File: x86-atom/OP_APUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT.S
+    *
+    * Code: Generic 32-bit array put operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       move performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the move
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         (%ecx, %edx, 1), %ecx # %ecx<- &vBB[vCC]
+    GET_VREG    rINST                   # rINST<- vAA
+    movb     rINSTbl, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_CHAR: /* 0x50 */
+/* File: x86-atom/OP_APUT_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_CHAR.S
+    */
+
+/* File: x86-atom/OP_APUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT.S
+    *
+    * Code: Generic 32-bit array put operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       move performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the move
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
+    GET_VREG    rINST                   # rINST<- vAA
+    movw     rINSTw, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_SHORT: /* 0x51 */
+/* File: x86-atom/OP_APUT_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_SHORT.S
+    */
+
+/* File: x86-atom/OP_APUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT.S
+    *
+    * Code: Generic 32-bit array put operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       move performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the move
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         (%ecx, %edx, 2), %ecx # %ecx<- &vBB[vCC]
+    GET_VREG    rINST                   # rINST<- vAA
+    movw     rINSTw, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET: /* 0x52 */
+/* File: x86-atom/OP_IGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IGET_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .LOP_IGET_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE: /* 0x53 */
+/* File: x86-atom/OP_IGET_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_WIDE.S
+    *
+    * Code: 64 bit instance field "get" operation. Uses no substitutions.
+    *
+    * For: iget-wide
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    * Format:  B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
+    FETCH       1, %edx                 # %edx<- pDvmDex->pResFields
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved InstField ptr
+    cmp         $0, %ecx               # check for null ptr; resolved InstField ptr
+    jne         .LOP_IGET_WIDE_finish
+    movl        offGlue_method(%eax), %ecx # %ecx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
+    movl        %ecx, -8(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -4(%esp)          # push parameter method->clazz
+    jmp         .LOP_IGET_WIDE_finish2
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT: /* 0x54 */
+/* File: x86-atom/OP_IGET_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_OBJECT.S
+    */
+
+/* File: x86-atom/OP_IGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IGET_OBJECT_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .LOP_IGET_OBJECT_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: x86-atom/OP_IGET_BOOLEAN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_BOOLEAN.S
+    */
+
+/* File: x86-atom/OP_IGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IGET_BOOLEAN_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .LOP_IGET_BOOLEAN_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE: /* 0x56 */
+/* File: x86-atom/OP_IGET_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_BYTE.S
+    */
+
+/* File: x86-atom/OP_IGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IGET_BYTE_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .LOP_IGET_BYTE_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR: /* 0x57 */
+/* File: x86-atom/OP_IGET_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_CHAR.S
+    */
+
+/* File: x86-atom/OP_IGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IGET_CHAR_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .LOP_IGET_CHAR_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT: /* 0x58 */
+/* File: x86-atom/OP_IGET_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_SHORT.S
+    */
+
+/* File: x86-atom/OP_IGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IGET_SHORT_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .LOP_IGET_SHORT_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT: /* 0x59 */
+/* File: x86-atom/OP_IPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IPUT_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .LOP_IPUT_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE: /* 0x5a */
+/* File: x86-atom/OP_IPUT_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_WIDE.S
+    *
+    * Code: 64 bit instance field "put" operation. Uses no substitutions.
+    *
+    * For: iget-wide
+    *
+    * Description: Perform the object instance field "put" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    * Format:  B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
+    FETCH       1, %edx                 # %edx<- pDvmDex->pResFields
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved InstField ptr
+    cmp         $0, %ecx               # check for null ptr; resolved InstField ptr
+    jne         .LOP_IPUT_WIDE_finish
+    movl        offGlue_method(%eax), %ecx # %ecx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
+    movl        %ecx, -8(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -4(%esp)          # push parameter method->clazz
+    jmp         .LOP_IPUT_WIDE_finish2
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT: /* 0x5b */
+/* File: x86-atom/OP_IPUT_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IPUT_OBJECT_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .LOP_IPUT_OBJECT_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: x86-atom/OP_IPUT_BOOLEAN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_BOOLEAN.S
+    */
+
+/* File: x86-atom/OP_IPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IPUT_BOOLEAN_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .LOP_IPUT_BOOLEAN_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE: /* 0x5d */
+/* File: x86-atom/OP_IPUT_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_BYTE.S
+    */
+
+/* File: x86-atom/OP_IPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IPUT_BYTE_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .LOP_IPUT_BYTE_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR: /* 0x5e */
+/* File: x86-atom/OP_IPUT_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_CHAR.S
+    */
+
+/* File: x86-atom/OP_IPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IPUT_CHAR_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .LOP_IPUT_CHAR_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT: /* 0x5f */
+/* File: x86-atom/OP_IPUT_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_SHORT.S
+    */
+
+/* File: x86-atom/OP_IPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .LOP_IPUT_SHORT_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .LOP_IPUT_SHORT_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET: /* 0x60 */
+/* File: x86-atom/OP_SGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_resolve
+    jmp         .LOP_SGET_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE: /* 0x61 */
+/* File: x86-atom/OP_SGET_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_WIDE.S
+    *
+    * Code: 64-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-wide
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field, loading or storing
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %edx                 # %edx<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %edx, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_WIDE_resolve
+
+.LOP_SGET_WIDE_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        offStaticField_value(%ecx), %xmm0 # %xmm0<- field value
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- field value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT: /* 0x62 */
+/* File: x86-atom/OP_SGET_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_OBJECT.S
+    */
+
+/* File: x86-atom/OP_SGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_OBJECT_resolve
+    jmp         .LOP_SGET_OBJECT_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: x86-atom/OP_SGET_BOOLEAN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_BOOLEAN.S
+    */
+
+/* File: x86-atom/OP_SGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_BOOLEAN_resolve
+    jmp         .LOP_SGET_BOOLEAN_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE: /* 0x64 */
+/* File: x86-atom/OP_SGET_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_BYTE.S
+    */
+
+/* File: x86-atom/OP_SGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_BYTE_resolve
+    jmp         .LOP_SGET_BYTE_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR: /* 0x65 */
+/* File: x86-atom/OP_SGET_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_CHAR.S
+    */
+
+/* File: x86-atom/OP_SGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_CHAR_resolve
+    jmp         .LOP_SGET_CHAR_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT: /* 0x66 */
+/* File: x86-atom/OP_SGET_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_SHORT.S
+    */
+
+/* File: x86-atom/OP_SGET.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SGET_SHORT_resolve
+    jmp         .LOP_SGET_SHORT_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT: /* 0x67 */
+/* File: x86-atom/OP_SPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SPUT_resolve
+    jmp         .LOP_SPUT_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE: /* 0x68 */
+/* File: x86-atom/OP_SPUT_WIDE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_WIDE.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %edx                 # %edx<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %edx, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SPUT_WIDE_resolve
+
+.LOP_SPUT_WIDE_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vAA
+    movq        %xmm0, offStaticField_value(%ecx) # field value<- field value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: x86-atom/OP_SPUT_OBJECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_OBJECT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField
+    je          .LOP_SPUT_OBJECT_resolve
+    jmp         .LOP_SPUT_OBJECT_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: x86-atom/OP_SPUT_BOOLEAN.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_BOOLEAN.S
+    */
+
+/* File: x86-atom/OP_SPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SPUT_BOOLEAN_resolve
+    jmp         .LOP_SPUT_BOOLEAN_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE: /* 0x6b */
+/* File: x86-atom/OP_SPUT_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_BYTE.S
+    */
+
+/* File: x86-atom/OP_SPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SPUT_BYTE_resolve
+    jmp         .LOP_SPUT_BYTE_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR: /* 0x6c */
+/* File: x86-atom/OP_SPUT_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_CHAR.S
+    */
+
+/* File: x86-atom/OP_SPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SPUT_CHAR_resolve
+    jmp         .LOP_SPUT_CHAR_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT: /* 0x6d */
+/* File: x86-atom/OP_SPUT_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_SHORT.S
+    */
+
+/* File: x86-atom/OP_SPUT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .LOP_SPUT_SHORT_resolve
+    jmp         .LOP_SPUT_SHORT_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: x86-atom/OP_INVOKE_VIRTUAL.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL.S
+    *
+    * Code: Call a virtual method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_direct that allows up to 255 arguments.
+    *
+    * For: invoke-virtual, invoke-virtual/range
+    *
+    * Description: invoke-virtual is used to invoke a normal virtual method;
+    *              a method that is not static or final, and is not a constructor.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # must export pc for invoke
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        offDvmDex_pResMethods(%eax), %eax # %eax<- pDvmDex->pResMethods
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    .if         (!0)
+    and         $15, %edx              # %edx<- D if not range
+    .endif
+    cmp         $0, (%eax, %ecx, 4)    # check if already resolved
+    je          .LOP_INVOKE_VIRTUAL_break
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved base method
+    jmp         .LOP_INVOKE_VIRTUAL_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER: /* 0x6f */
+/* File: x86-atom/OP_INVOKE_SUPER.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER.S
+    *
+    * Code: Call super method.
+    *
+    * For: invoke-super, invoke-super/range
+    *
+    * Description: invoke-super is used to invoke the closest superclass's virtual
+    *              method (as opposed to the one with the same method_id in the
+    *              calling class).
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    FETCH       2, %eax                 # %eax<- GFED or CCCC
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    .if         (!0)
+    and         $15, %eax              # %eax<- D if not range
+    .endif
+    FETCH       1, %edx                 # %edx<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
+    cmp         $0, (rFP, %eax, 4)     # check for null object
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved base method
+    je          common_errNullObject    # handle null object
+    jmp         .LOP_INVOKE_SUPER_continue2
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: x86-atom/OP_INVOKE_DIRECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_DIRECT.S
+    *
+    * Code: Call a non-static direct method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_direct that allows up to 255 arguments.
+    *
+    * For: invoke-direct, invoke-direct/range
+    *
+    * Description: invoke-direct is used to invoke a non-static direct method;
+    *              an instance method that is non-overridable, for example,
+    *              either a private instance method or a constructor.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved method to call
+    .if         (!0)
+    andl        $15, %edx              # %edx<- D if not range
+    .endif
+    EXPORT_PC                           # must export for invoke
+    movl        %edx, -4(%esp)          # save "this" pointer register
+    cmp         $0, %ecx               # check if already resolved
+    GET_VREG    %edx                    # %edx<- "this" pointer
+    je          .LOP_INVOKE_DIRECT_resolve     # handle resolve
+
+.LOP_INVOKE_DIRECT_finish:
+    cmp         $0, %edx               # check for null "this"
+    jne         common_invokeMethodNoRange # invoke method common code
+    jmp         common_errNullObject
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC: /* 0x71 */
+/* File: x86-atom/OP_INVOKE_STATIC.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_STATIC.S
+    *
+    * Code: Call static direct method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_static that allows up to 255 arguments.
+    *
+    * For: invoke-static, invoke-static/range
+    *
+    * Description: invoke-static is used to invoke static direct method.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %edx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %edx<- pDvmDex->pResMethods
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved method to call
+    cmp         $0, %ecx               # check if already resolved
+    EXPORT_PC                           # must export for invoke
+    jne         common_invokeMethodNoRange # invoke method common code
+    jmp         .LOP_INVOKE_STATIC_break
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: x86-atom/OP_INVOKE_INTERFACE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_INTERFACE.S
+    *
+    * Code: Call at method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_interface that allows up to 255 arguments.
+    *
+    * For: invoke-interface, invoke-interface-range
+    *
+    * Description: invoke-interface is used to invoke an interface method; on an
+    *              object whose concrete class isn't known, using a method_id that
+    *              refers to an interface.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        %ecx, -12(%esp)         # push argument method index
+    .if         (!0)
+    and         $15, %edx              # %edx<- D if not range
+    .endif
+    EXPORT_PC                           # must export for invoke
+    GET_VREG    %edx                    # %edx<- first arg "this pointer"
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
+    movl        %eax, -4(%esp)          # push parameter class
+    cmp         $0, %edx               # check for null object
+    je          common_errNullObject    # handle null object
+    jmp         .LOP_INVOKE_INTERFACE_break
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73: /* 0x73 */
+/* File: x86-atom/OP_UNUSED_73.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_73.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: x86-atom/OP_INVOKE_VIRTUAL_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_VIRTUAL.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL.S
+    *
+    * Code: Call a virtual method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_direct that allows up to 255 arguments.
+    *
+    * For: invoke-virtual, invoke-virtual/range
+    *
+    * Description: invoke-virtual is used to invoke a normal virtual method;
+    *              a method that is not static or final, and is not a constructor.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # must export pc for invoke
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        offDvmDex_pResMethods(%eax), %eax # %eax<- pDvmDex->pResMethods
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    .if         (!1)
+    and         $15, %edx              # %edx<- D if not range
+    .endif
+    cmp         $0, (%eax, %ecx, 4)    # check if already resolved
+    je          .LOP_INVOKE_VIRTUAL_RANGE_break
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved base method
+    jmp         .LOP_INVOKE_VIRTUAL_RANGE_continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: x86-atom/OP_INVOKE_SUPER_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_SUPER.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER.S
+    *
+    * Code: Call super method.
+    *
+    * For: invoke-super, invoke-super/range
+    *
+    * Description: invoke-super is used to invoke the closest superclass's virtual
+    *              method (as opposed to the one with the same method_id in the
+    *              calling class).
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    FETCH       2, %eax                 # %eax<- GFED or CCCC
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    .if         (!1)
+    and         $15, %eax              # %eax<- D if not range
+    .endif
+    FETCH       1, %edx                 # %edx<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
+    cmp         $0, (rFP, %eax, 4)     # check for null object
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved base method
+    je          common_errNullObject    # handle null object
+    jmp         .LOP_INVOKE_SUPER_RANGE_continue2
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: x86-atom/OP_INVOKE_DIRECT_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_DIRECT_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_DIRECT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_DIRECT.S
+    *
+    * Code: Call a non-static direct method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_direct that allows up to 255 arguments.
+    *
+    * For: invoke-direct, invoke-direct/range
+    *
+    * Description: invoke-direct is used to invoke a non-static direct method;
+    *              an instance method that is non-overridable, for example,
+    *              either a private instance method or a constructor.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved method to call
+    .if         (!1)
+    andl        $15, %edx              # %edx<- D if not range
+    .endif
+    EXPORT_PC                           # must export for invoke
+    movl        %edx, -4(%esp)          # save "this" pointer register
+    cmp         $0, %ecx               # check if already resolved
+    GET_VREG    %edx                    # %edx<- "this" pointer
+    je          .LOP_INVOKE_DIRECT_RANGE_resolve     # handle resolve
+
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    cmp         $0, %edx               # check for null "this"
+    jne         common_invokeMethodRange # invoke method common code
+    jmp         common_errNullObject
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: x86-atom/OP_INVOKE_STATIC_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_STATIC_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_STATIC.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_STATIC.S
+    *
+    * Code: Call static direct method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_static that allows up to 255 arguments.
+    *
+    * For: invoke-static, invoke-static/range
+    *
+    * Description: invoke-static is used to invoke static direct method.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %edx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %edx<- pDvmDex->pResMethods
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved method to call
+    cmp         $0, %ecx               # check if already resolved
+    EXPORT_PC                           # must export for invoke
+    jne         common_invokeMethodRange # invoke method common code
+    jmp         .LOP_INVOKE_STATIC_RANGE_break
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: x86-atom/OP_INVOKE_INTERFACE_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_INTERFACE_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_INTERFACE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_INTERFACE.S
+    *
+    * Code: Call at method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_interface that allows up to 255 arguments.
+    *
+    * For: invoke-interface, invoke-interface-range
+    *
+    * Description: invoke-interface is used to invoke an interface method; on an
+    *              object whose concrete class isn't known, using a method_id that
+    *              refers to an interface.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        %ecx, -12(%esp)         # push argument method index
+    .if         (!1)
+    and         $15, %edx              # %edx<- D if not range
+    .endif
+    EXPORT_PC                           # must export for invoke
+    GET_VREG    %edx                    # %edx<- first arg "this pointer"
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
+    movl        %eax, -4(%esp)          # push parameter class
+    cmp         $0, %edx               # check for null object
+    je          common_errNullObject    # handle null object
+    jmp         .LOP_INVOKE_INTERFACE_RANGE_break
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79: /* 0x79 */
+/* File: x86-atom/OP_UNUSED_79.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_79.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7A: /* 0x7a */
+/* File: x86-atom/OP_UNUSED_7A.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_7A.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_INT: /* 0x7b */
+/* File: x86-atom/OP_NEG_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_INT.S
+    */
+
+/* File: x86-atom/unop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+                               # do operation part 1
+    neg        %ecx                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NOT_INT: /* 0x7c */
+/* File: x86-atom/OP_NOT_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NOT_INT.S
+    */
+
+/* File: x86-atom/unop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+                               # do operation part 1
+    not        %ecx                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_LONG: /* 0x7d */
+/* File: x86-atom/OP_NEG_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_LONG.S
+    */
+
+/* File: x86-atom/unopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unopWide.S
+    *
+    * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%xmm0 = op %xmm1".
+    *
+    * For:  neg-double, neg-long, not-long
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vB
+    xorps %xmm1, %xmm1                           # do operation part 1
+    psubq %xmm0, %xmm1                              # do operation part 2
+    movq        %xmm1, (rFP, %ecx, 4) # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NOT_LONG: /* 0x7e */
+/* File: x86-atom/OP_NOT_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NOT_LONG.S
+    */
+
+/* File: x86-atom/unopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unopWide.S
+    *
+    * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%xmm0 = op %xmm1".
+    *
+    * For:  neg-double, neg-long, not-long
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vB
+                               # do operation part 1
+    pandn  0xFFFFFFFF, %xmm0                              # do operation part 2
+    movq        %xmm0, (rFP, %ecx, 4) # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_FLOAT: /* 0x7f */
+/* File: x86-atom/OP_NEG_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_FLOAT.S
+    */
+
+/* File: x86-atom/unop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+                               # do operation part 1
+    addl      $0x80000000, %ecx                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_DOUBLE: /* 0x80 */
+/* File: x86-atom/OP_NEG_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_DOUBLE.S
+    */
+
+/* File: x86-atom/unopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unopWide.S
+    *
+    * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%xmm0 = op %xmm1".
+    *
+    * For:  neg-double, neg-long, not-long
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vB
+    movq .LdoubNeg, %xmm1                           # do operation part 1
+    pxor %xmm1, %xmm0                              # do operation part 2
+    movq        %xmm0, (rFP, %ecx, 4) # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_LONG: /* 0x81 */
+/* File: x86-atom/OP_INT_TO_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_LONG.S
+    *
+    * Code:  Convert an int to a long. Uses no substitutions.
+    *
+    * For:
+    *
+    * Description: Convert an int in the source register, to a long, and
+    *              stores the result in the destintation register. vA<- (long) vB
+    *
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %eax               # %eax<- B
+    andl        $15, %ecx              # %ecx<- A
+    GET_VREG    %eax                    # %eax<- vB
+    cdq                                 # %edx:%eax<- sign-extend of %eax
+    movl        %eax, (rFP, %ecx, 4)    # vA<- lo part
+    movl        %edx, 4(rFP, %ecx, 4)   # vA+1<- hi part
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: x86-atom/OP_INT_TO_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_FLOAT.S
+    *
+    * Code: Convert an int to a float. Uses no substitutions.
+    *
+    * For: int-to-float
+    *
+    * Description: Convert an int in the source register, to a float, and
+    *              stores the result in the destintation register. vA<- (float) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA+
+    shr         $4, %eax               # %eax<- B
+    andl        $15,  rINST            # rINST<- A
+    cvtsi2ss    (rFP,%eax,4), %xmm0     # %xmm0<- vB
+    movss       %xmm0, (rFP, rINST, 4)  # vA<- %xmm0
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: x86-atom/OP_INT_TO_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_DOUBLE.S
+    *
+    * Code: Convert an int to a double. Uses no substitutions.
+    *
+    * For: int-to-double
+    *
+    * Description: Converts an int in the source register, to a double, and
+    *              stores the result in the destination register. vA<- (double) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA+
+    shr         $4, %eax               # %eax<- B
+    andl        $15, rINST             # rINST<- A
+    cvtsi2sd    (rFP, %eax, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- %xmm0; (double) vB
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_LONG_TO_INT: /* 0x84 */
+/* File: x86-atom/OP_LONG_TO_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_LONG_TO_INT.S
+    */
+
+/* File: x86-atom/OP_MOVE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move, move-object, long-to-int
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vB
+    SET_VREG    rINST, %ecx             # vA<- vB; %edx
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: x86-atom/OP_LONG_TO_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_LONG_TO_FLOAT.S
+    *
+    * Code: Convert a long to a float. Uses no substitutions.
+    *
+    * For: int-to-float
+    *
+    * Description: Converts a float in the source register, to a float, and
+    *              stores the result in the destination register. vA<- (double) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    fildll      (rFP, rINST, 4)         # FPU<- vB
+    fstps       (rFP, %ecx, 4)          # vA<- FPU; (float) vB
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: x86-atom/OP_LONG_TO_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_LONG_TO_DOUBLE.S
+    *
+    * Code: Convert a long to a dobule. Uses no substitutions.
+    *
+    * For: long-to-double
+    *
+    * Description: Converts a long in the source register to a double, and
+    *              stores the result in the destination register. vA<- (double) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, rINST              # rINST<- B
+    and         $15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    fildll      (rFP, rINST, 4)         # FPU<- vB
+    fstpl       (rFP, %ecx, 4)          # vA<- FPU; (double) vB
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: x86-atom/OP_FLOAT_TO_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FLOAT_TO_INT.S
+    *
+    * Code: Converts a float to a int. Uses no substitutions.
+    *
+    * For: float-to-int
+    *
+    * Description: Convert the float in source register to a int
+    *              and store the result in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %edx              # %edx<- A
+    flds        (rFP, rINST, 4)         # push vB to floating point stack
+    fildl       .LintMax                # push max int value
+    fildl       .LintMin                # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .LOP_FLOAT_TO_INT_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .LOP_FLOAT_TO_INT_nanInf      # handle posInf or NaN
+    jmp         .LOP_FLOAT_TO_INT_break       # do conversion
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: x86-atom/OP_FLOAT_TO_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FLOAT_TO_LONG.S
+    *
+    * Code: Converts a float to a long. Uses no substitutions.
+    *
+    * For: float-to-long
+    *
+    * Description: Convert the float in source register to a long
+    *              and store the result in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %edx              # %edx<- A
+    flds        (rFP, rINST, 4)         # push vB to floating point stack
+    fildll      .LvaluePosInfLong       # push max int value
+    fildll      .LvalueNegInfLong       # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .LOP_FLOAT_TO_LONG_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .LOP_FLOAT_TO_LONG_nanInf      # handle posInf or NaN
+    jmp         .LOP_FLOAT_TO_LONG_break       # do conversion
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: x86-atom/OP_FLOAT_TO_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FLOAT_TO_DOUBLE.S
+    *
+    * Code: Converts a float to a double. Uses no substitutions.
+    *
+    * For: float-to-double
+    *
+    * Description: Convert the float in source register to a double
+    *              and store the result in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %edx              # %edx<- A
+    flds        (rFP, rINST, 4)         # load float
+    fstpl       (rFP, %edx, 4)          # store double
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: x86-atom/OP_DOUBLE_TO_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DOUBLE_TO_INT.S
+    *
+    * Code: Converts a double to an integer. Uses no substitutions.
+    *
+    * For: double-to-int
+    *
+    * Description: Convert the source register (a double) to an integer
+    *              and store the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %edx              # %edx<- A
+    fldl        (rFP, rINST, 4)         # load &vB
+    fildl       .LintMax                # push max int value
+    fildl       .LintMin                # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .LOP_DOUBLE_TO_INT_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .LOP_DOUBLE_TO_INT_nanInf      # handle posInf or NaN
+    jmp         .LOP_DOUBLE_TO_INT_break       # do conversion
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: x86-atom/OP_DOUBLE_TO_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DOUBLE_TO_LONG.S
+    *
+    * Code: Converts a double to a long. Uses no substitutions.
+    *
+    * For: double-to-long
+    *
+    * Description: Convert the double in source register to a long
+    *              and store in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %ecx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %edx              # %ecx<- A
+    fldl        (rFP, rINST, 4)         # push vB to floating point stack
+    fildll      .LvaluePosInfLong       # push max int value
+    fildll      .LvalueNegInfLong       # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .LOP_DOUBLE_TO_LONG_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .LOP_DOUBLE_TO_LONG_nanInf      # handle posInf or NaN
+    jmp         .LOP_DOUBLE_TO_LONG_break       # do conversion
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: x86-atom/OP_DOUBLE_TO_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DOUBLE_TO_FLOAT.S
+    *
+    * Code: Converts a double to a float. Uses no substitutions.
+    *
+    * For: double-to-float
+    *
+    * Description: Convert the source register (a double) to a float
+    *              and store the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    and         $15, %edx              # %edx<- A
+    fldl        (rFP, rINST, 4)         # load &vB
+    fstps       (rFP, %edx, 4)          # store float
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_BYTE: /* 0x8d */
+/* File: x86-atom/OP_INT_TO_BYTE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_BYTE.S
+    */
+
+/* File: x86-atom/unop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    sal $24, %ecx                           # do operation part 1
+    sar $24, %ecx                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_CHAR: /* 0x8e */
+/* File: x86-atom/OP_INT_TO_CHAR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_CHAR.S
+    */
+
+/* File: x86-atom/unop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    sal $16, %ecx                           # do operation part 1
+    shr $16, %ecx                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_SHORT: /* 0x8f */
+/* File: x86-atom/OP_INT_TO_SHORT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_SHORT.S
+    */
+
+/* File: x86-atom/unop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    sal $16, %ecx                           # do operation part 1
+    sar $16, %ecx                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT: /* 0x90 */
+/* File: x86-atom/OP_ADD_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT.S
+    */
+
+/* File: x86-atom/binop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    addl     %edx, %ecx                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_INT: /* 0x91 */
+/* File: x86-atom/OP_SUB_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_INT.S
+    */
+
+/* File: x86-atom/binop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    subl     %edx, %ecx                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT: /* 0x92 */
+/* File: x86-atom/OP_MUL_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT.S
+    */
+
+/* File: x86-atom/binop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    imul     %edx, %ecx                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT: /* 0x93 */
+/* File: x86-atom/OP_DIV_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT.S
+    */
+
+/* File: x86-atom/binopD.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopD.S
+    *
+    * Code: 32-bit integer divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int, rem-int
+    *
+    * Description: Perform a binary operation on two source
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    GET_VREG    %eax                    # %eax<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    cmp         $0, %ecx               # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_DIV_INT_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_DIV_INT_break
+.LOP_DIV_INT_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    .if  1
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .LOP_DIV_INT_break2
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT: /* 0x94 */
+/* File: x86-atom/OP_REM_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT.S
+    */
+
+/* File: x86-atom/binopD.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopD.S
+    *
+    * Code: 32-bit integer divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int, rem-int
+    *
+    * Description: Perform a binary operation on two source
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    GET_VREG    %eax                    # %eax<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    cmp         $0, %ecx               # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_REM_INT_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_REM_INT_break
+.LOP_REM_INT_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    .if  0
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .LOP_REM_INT_break2
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT: /* 0x95 */
+/* File: x86-atom/OP_AND_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT.S
+    */
+
+/* File: x86-atom/binop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    andl     %edx, %ecx                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT: /* 0x96 */
+/* File: x86-atom/OP_OR_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT.S
+    */
+
+/* File: x86-atom/binop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    or %edx, %ecx                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT: /* 0x97 */
+/* File: x86-atom/OP_XOR_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT.S
+    */
+
+/* File: x86-atom/binop.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    xor     %edx, %ecx                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_INT: /* 0x98 */
+/* File: x86-atom/OP_SHL_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_INT.S
+    */
+
+/* File: x86-atom/binopS.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%edx = %edx op %cl"
+    *
+    * For: shl-int, shr-int, ushr-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    sal     %cl, %edx                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_INT: /* 0x99 */
+/* File: x86-atom/OP_SHR_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_INT.S
+    */
+
+/* File: x86-atom/binopS.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%edx = %edx op %cl"
+    *
+    * For: shl-int, shr-int, ushr-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    sar     %cl, %edx                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_INT: /* 0x9a */
+/* File: x86-atom/OP_USHR_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_INT.S
+    */
+
+/* File: x86-atom/binopS.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%edx = %edx op %cl"
+    *
+    * For: shl-int, shr-int, ushr-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    shr     %cl, %edx                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_LONG: /* 0x9b */
+/* File: x86-atom/OP_ADD_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_LONG.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    paddq   %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_LONG: /* 0x9c */
+/* File: x86-atom/OP_SUB_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_LONG.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    psubq    %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_LONG: /* 0x9d */
+/* File: x86-atom/OP_MUL_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_LONG.S
+    *
+    * Code: 64-bit integer multiply
+    *
+    * For: mul-long
+    *
+    * Description: Multiply two source registers and store the
+    *              result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+   /*
+    * 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.
+    */
+
+    movl        rINST, -4(%esp)         # -4(%esp)<- AA+
+    FETCH_BB    1, rINST                # rINST<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    jmp         .LOP_MUL_LONG_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_LONG: /* 0x9e */
+/* File: x86-atom/OP_DIV_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_LONG.S
+    */
+
+/* File: x86-atom/binopDivRemLong.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDivRemLong.S
+    *
+    * Code: 64-bit long divide operation. Variable
+    *       "func" defines the function called to do the operation.
+    *
+    * For: div-long, rem-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        (rFP, %edx, 4), %eax    # %eax<- vCC
+    movl        4(rFP, %edx, 4), %ecx   # %ecx<- vCC+1
+    movl        %eax, -8(%esp)          # push arg vCC
+    or          %ecx, %eax              # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movl        %ecx, -4(%esp)          # push arg vCC+1
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vBB,vBB+1
+    jmp         .LOP_DIV_LONG_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_LONG: /* 0x9f */
+/* File: x86-atom/OP_REM_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_LONG.S
+    */
+
+/* File: x86-atom/binopDivRemLong.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDivRemLong.S
+    *
+    * Code: 64-bit long divide operation. Variable
+    *       "func" defines the function called to do the operation.
+    *
+    * For: div-long, rem-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        (rFP, %edx, 4), %eax    # %eax<- vCC
+    movl        4(rFP, %edx, 4), %ecx   # %ecx<- vCC+1
+    movl        %eax, -8(%esp)          # push arg vCC
+    or          %ecx, %eax              # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movl        %ecx, -4(%esp)          # push arg vCC+1
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vBB,vBB+1
+    jmp         .LOP_REM_LONG_finish
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_LONG: /* 0xa0 */
+/* File: x86-atom/OP_AND_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_LONG.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    pand   %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_LONG: /* 0xa1 */
+/* File: x86-atom/OP_OR_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_LONG.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    por %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_LONG: /* 0xa2 */
+/* File: x86-atom/OP_XOR_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_LONG.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    pxor   %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_LONG: /* 0xa3 */
+/* File: x86-atom/OP_SHL_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_LONG.S
+    *
+    * Code: Performs a shift left long. Uses no substitutions.
+    *
+    * For: shl-long
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where one is the shift amount and the other is the value to shift.
+    *              Store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_CC    1, %eax                 # %eax<- CC
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movq        .LshiftMask, %xmm2      # %xmm2<- mask for the shift bits
+    movss       (rFP, %eax, 4), %xmm0   # %xmm0<- vCC
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vBB
+    psllq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    movq        %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_LONG: /* 0xa4 */
+/* File: x86-atom/OP_SHR_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_LONG.S
+    *
+    * Code: Performs a shift right long
+    *
+    * For: shl-long
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where one is the shift amount and the other is the value to shift.
+    *              Store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CC    1, %eax                 # %eax<- CC
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vBB
+    movss       (rFP, %eax, 4), %xmm0   # %xmm0<- vCC
+    movq        .LshiftMask, %xmm2
+    pand        %xmm2, %xmm0            # %xmm0<- masked for the shift bits
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    cmpl        $0, 4(rFP, %edx, 4)    # check if we need to consider sign
+    jl          .LOP_SHR_LONG_finish      # consider sign
+    jmp         .LOP_SHR_LONG_final       # sign is fine, finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_LONG: /* 0xa5 */
+/* File: x86-atom/OP_USHR_LONG.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_LONG.S
+    *
+    * Code: Performs an unsigned shift right long operation. Uses no substitutions.
+    *
+    * For: ushr-long
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where one is the shift amount and the other is the value to shift.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_CC    1, %eax                 # %eax<- CC
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movsd        .LshiftMask, %xmm2     # %xmm2<- mask for the shift bits
+    movss       (rFP, %eax, 4), %xmm0   # %xmm0<- vCC
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    movsd       (rFP, %edx, 4), %xmm1   # %xmm1<- vBB
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    movsd       %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_FLOAT: /* 0xa6 */
+/* File: x86-atom/OP_ADD_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_FLOAT.S
+    */
+
+/* File: x86-atom/binopF.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-float, mul-float, sub-float
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<-vBB
+    movss       (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    addss     %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movss       %xmm0, (rFP, rINST, 4)  # vAA<- %xmm0; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_FLOAT: /* 0xa7 */
+/* File: x86-atom/OP_SUB_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_FLOAT.S
+    */
+
+/* File: x86-atom/binopF.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-float, mul-float, sub-float
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<-vBB
+    movss       (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    subss     %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movss       %xmm0, (rFP, rINST, 4)  # vAA<- %xmm0; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_FLOAT: /* 0xa8 */
+/* File: x86-atom/OP_MUL_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_FLOAT.S
+    */
+
+/* File: x86-atom/binopF.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-float, mul-float, sub-float
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<-vBB
+    movss       (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    mulss %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movss       %xmm0, (rFP, rINST, 4)  # vAA<- %xmm0; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_FLOAT: /* 0xa9 */
+/* File: x86-atom/OP_DIV_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_FLOAT.S
+    *
+    * Code: Divides floats. Uses no substitutions.
+    *
+    * For: div-float
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in a destiniation register
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    flds        (rFP, %eax, 4)          # floating point stack vBB
+    fdivs       (rFP, %ecx, 4)          # divide double; vBB/vCC
+    fstps       (rFP, rINST, 4)         # vAA<- result
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_FLOAT: /* 0xaa */
+/* File: x86-atom/OP_REM_FLOAT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_FLOAT.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-float
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in a
+    *              destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    movl        %ecx, -8(%esp)          # push parameter float
+    movl        %edx, -4(%esp)          # push parameter float
+    lea         -8(%esp), %esp
+    call        fmodf                   # call: (float x, float y)
+                                        # return: float
+    lea         8(%esp), %esp
+    fstps       (rFP, rINST, 4)         # vAA<- remainder; return of fmod
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_DOUBLE: /* 0xab */
+/* File: x86-atom/OP_ADD_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_DOUBLE.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    addsd   %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_DOUBLE: /* 0xac */
+/* File: x86-atom/OP_SUB_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_DOUBLE.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    subsd   %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_DOUBLE: /* 0xad */
+/* File: x86-atom/OP_MUL_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_DOUBLE.S
+    */
+
+/* File: x86-atom/binopWide.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    mulsd   %xmm1, %xmm0                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_DOUBLE: /* 0xae */
+/* File: x86-atom/OP_DIV_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_DOUBLE.S
+    *
+    * Code: Divides doubles. Uses no substitutions.
+    *
+    * For: div-double
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in a destination register
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    fldl        (rFP, %ecx, 4)          # floating point stack vBB
+    fdivl       (rFP, %edx, 4)          # divide double; vBB/vCC
+    fstpl       (rFP, rINST, 4)         # vAA<- result
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_DOUBLE: /* 0xaf */
+/* File: x86-atom/OP_REM_DOUBLE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_DOUBLE.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-double
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in a
+    *              destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        (rFP, %ecx, 4), %eax    # %eax<- vBBlo
+    movl        %eax, -16(%esp)         # push parameter double lo
+    movl        4(rFP, %ecx, 4), %eax   # %eax<- vBBhi
+    movl        %eax, -12(%esp)         # push parameter double hi
+    movl        (rFP, %edx, 4), %eax    # %eax<- vCClo
+    movl        %eax, -8(%esp)          # push parameter double lo
+    movl        4(rFP, %edx, 4), %eax   # %eax<- vCChi
+    movl        %eax, -4(%esp)          # push parameter double hi
+    lea         -16(%esp), %esp
+    jmp         .LOP_REM_DOUBLE_break
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: x86-atom/OP_ADD_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binop2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    addl     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: x86-atom/OP_SUB_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binop2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    subl     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: x86-atom/OP_MUL_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binop2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    imul     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: x86-atom/OP_DIV_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binopD2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopD2addr.S
+    *
+    * Code: 32-bit "/2addr" integer divde operation. If "div"
+    *       is set, the code returns the quotient, else it returns
+    *       the remainder. Also, a divide-by-zero check is done.
+    *
+    * For: div-int/2addr, rem-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $15, rINST             # rINST<- A, to be used as dest
+    movl        rINST, %eax             # %eax<- A
+    shr         $4, %ecx               # %ecx<- B
+    GET_VREG    %eax                    # %eax<- vA
+    GET_VREG    %ecx                    # %edx<- vB
+    cmp         $0, %ecx               # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_DIV_INT_2ADDR_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_DIV_INT_2ADDR_break
+.LOP_DIV_INT_2ADDR_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+     .if  1
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .LOP_DIV_INT_2ADDR_break2
+    #FFETCH_ADV 1, %edx  # %ecx<- next instruction hi; fetch, advance
+    #FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: x86-atom/OP_REM_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binopD2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopD2addr.S
+    *
+    * Code: 32-bit "/2addr" integer divde operation. If "div"
+    *       is set, the code returns the quotient, else it returns
+    *       the remainder. Also, a divide-by-zero check is done.
+    *
+    * For: div-int/2addr, rem-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $15, rINST             # rINST<- A, to be used as dest
+    movl        rINST, %eax             # %eax<- A
+    shr         $4, %ecx               # %ecx<- B
+    GET_VREG    %eax                    # %eax<- vA
+    GET_VREG    %ecx                    # %edx<- vB
+    cmp         $0, %ecx               # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_REM_INT_2ADDR_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_REM_INT_2ADDR_break
+.LOP_REM_INT_2ADDR_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+     .if  0
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .LOP_REM_INT_2ADDR_break2
+    #FFETCH_ADV 1, %edx  # %ecx<- next instruction hi; fetch, advance
+    #FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: x86-atom/OP_AND_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binop2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    andl     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: x86-atom/OP_OR_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binop2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    or %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: x86-atom/OP_XOR_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binop2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    xor     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: x86-atom/OP_SHL_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binopS2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%edx = %edx op %cl".
+    *
+    * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %edx             # %edx<- A
+    FFETCH_ADV  1, %eax                 # %ecx<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    GET_VREG    %edx                    # %edx<- vA
+    sal     %cl, %edx                              # %edx<- vA op vB
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: x86-atom/OP_SHR_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binopS2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%edx = %edx op %cl".
+    *
+    * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %edx             # %edx<- A
+    FFETCH_ADV  1, %eax                 # %ecx<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    GET_VREG    %edx                    # %edx<- vA
+    sar     %cl, %edx                              # %edx<- vA op vB
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: x86-atom/OP_USHR_INT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_INT_2ADDR.S
+    */
+
+/* File: x86-atom/binopS2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%edx = %edx op %cl".
+    *
+    * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    movl        rINST, %edx             # %edx<- A
+    FFETCH_ADV  1, %eax                 # %ecx<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    GET_VREG    %edx                    # %edx<- vA
+    shr     %cl, %edx                              # %edx<- vA op vB
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: x86-atom/OP_ADD_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    paddq   %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: x86-atom/OP_SUB_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    psubq    %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: x86-atom/OP_MUL_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_LONG_2ADDR.S
+    *
+    * Code:  64-bit integer multiply
+    *
+    * For: mul-long/2addr
+    *
+    * Description: Multiply two sources registers and store the result
+    *              in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+   /*
+    * 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.
+    */
+
+    movl        rINST, %edx             # %edx<- BA+
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movl        %edx, sReg0             # sReg0<- A
+    jmp         .LOP_MUL_LONG_2ADDR_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: x86-atom/OP_DIV_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopDivRemLong2Addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDivRemLong2Addr.S
+    *
+    * Code: 64-bit "/2addr" long divide operation. Variable
+    *       "func" defines the function called to do the operation.
+    *
+    * For: div-long/2addr, rem-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    and         $15, rINST             # rINST<- A
+    movl        (rFP, %edx, 4), %eax    # %eax<- vB
+    movl        %eax, -12(%esp)         # push arg vB
+    movl        4(rFP, %edx, 4), %ecx   # %ecx<- vB+1
+    or          %ecx, %eax              # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    movl        %ecx, -8(%esp)          # push arg vB+1
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vA,vA+1
+    jmp         .LOP_DIV_LONG_2ADDR_break
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: x86-atom/OP_REM_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopDivRemLong2Addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDivRemLong2Addr.S
+    *
+    * Code: 64-bit "/2addr" long divide operation. Variable
+    *       "func" defines the function called to do the operation.
+    *
+    * For: div-long/2addr, rem-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    and         $15, rINST             # rINST<- A
+    movl        (rFP, %edx, 4), %eax    # %eax<- vB
+    movl        %eax, -12(%esp)         # push arg vB
+    movl        4(rFP, %edx, 4), %ecx   # %ecx<- vB+1
+    or          %ecx, %eax              # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    movl        %ecx, -8(%esp)          # push arg vB+1
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vA,vA+1
+    jmp         .LOP_REM_LONG_2ADDR_break
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: x86-atom/OP_AND_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    pand   %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: x86-atom/OP_OR_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    por %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: x86-atom/OP_XOR_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_LONG_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    pxor   %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: x86-atom/OP_SHL_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_LONG_2ADDR.S
+    *
+    * Code: Performs a shift left long. Uses no substitutions.
+    *
+    * For: shl-long/2addr
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where the fist is the value to shift and the second is the
+    *              shift amount. Store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movss       (rFP, %edx, 4),  %xmm0  # %xmm0<- vB
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vA
+    movq        .LshiftMask, %xmm2      # %xmm2<- mask for the shift bits
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    psllq       %xmm0, %xmm1            # %xmm1<- shifted vA
+    movq        %xmm1, (rFP, rINST, 4)  # vA<- shifted vA
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: x86-atom/OP_SHR_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_LONG_2ADDR.S
+    *
+    * Code: Performs a shift left long
+    *
+    * For: shl-long/2addr
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where the fist is the value to shift and the second is the
+    *              shift amount. Store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- BA
+    movss       (rFP, %edx, 4),  %xmm0  # %xmm0<- vB
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vA
+    movq        .LshiftMask, %xmm2
+    pand        %xmm2, %xmm0            # %xmm0<- masked for the shift bits
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    cmpl        $0, 4(rFP, rINST, 4)   # check if we need to consider sign
+    jl          .LOP_SHR_LONG_2ADDR_finish      # consider sign
+    jmp         .LOP_SHR_LONG_2ADDR_final       # sign is fine, finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: x86-atom/OP_USHR_LONG_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_LONG_2ADDR.S
+    *
+    * Code: Performs an unsigned shift right long operation. Uses no substiutions.
+    *
+    * For: ushr-long/2addr
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where the fist is the value to shift and the second is the
+    *              shift amount. Store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    movq        .LshiftMask, %xmm2      # %xmm2<- mask for the shift bits
+    movss       (rFP, %edx, 4),  %xmm0  # %xmm0<- vB
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vA
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vA
+    movq        %xmm1, (rFP, rINST, 4)  # vA<- shifted vA
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: x86-atom/OP_ADD_FLOAT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_FLOAT_2ADDR.S
+    */
+
+/* File: x86-atom/binopF2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0 = %xmm0 op %xmm1".
+    *
+    * For: add-float/2addr, mul-float/2addr, sub-float/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $15, %ecx              # %ecx<- A
+    shr         $4, rINST              # rINST<- B
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<- vA
+    movss       (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    addss     %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movss       %xmm0, (rFP, %ecx, 4)   # vA<- %xmm0; result
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: x86-atom/OP_SUB_FLOAT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_FLOAT_2ADDR.S
+    */
+
+/* File: x86-atom/binopF2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0 = %xmm0 op %xmm1".
+    *
+    * For: add-float/2addr, mul-float/2addr, sub-float/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $15, %ecx              # %ecx<- A
+    shr         $4, rINST              # rINST<- B
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<- vA
+    movss       (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    subss     %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movss       %xmm0, (rFP, %ecx, 4)   # vA<- %xmm0; result
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: x86-atom/OP_MUL_FLOAT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_FLOAT_2ADDR.S
+    */
+
+/* File: x86-atom/binopF2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0 = %xmm0 op %xmm1".
+    *
+    * For: add-float/2addr, mul-float/2addr, sub-float/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $15, %ecx              # %ecx<- A
+    shr         $4, rINST              # rINST<- B
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<- vA
+    movss       (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    mulss %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movss       %xmm0, (rFP, %ecx, 4)   # vA<- %xmm0; result
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: x86-atom/OP_DIV_FLOAT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_FLOAT_2ADDR.S
+    *
+    * Code: Divides floats. Uses no substitutions.
+    *
+    * For: div-float/2addr
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in the first source reigster
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $15, %ecx              # %ecx<- A
+    shr         $4, rINST              # rINST<- B
+    flds        (rFP, %ecx, 4)          # %xmm0<- vA
+    fdivs       (rFP, rINST, 4)         # divide double; vA/vB
+    fstps       (rFP, %ecx, 4)          # vAA<- result
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: x86-atom/OP_REM_FLOAT_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_FLOAT_2ADDR.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-float/2addr
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in the first
+    *              source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB
+    movl        (rFP, rINST, 4), %ecx   # %ecx<- vA
+    movl        %ecx, -8(%esp)          # push parameter vA
+    movl        %edx, -4(%esp)          # push parameter vB
+    lea         -8(%esp), %esp
+    call        fmodf                   # call: (float x, float y)
+                                        # return: float
+    lea         8(%esp), %esp
+    fstps       (rFP, rINST, 4)
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: x86-atom/OP_ADD_DOUBLE_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_DOUBLE_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    addsd   %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: x86-atom/OP_SUB_DOUBLE_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_DOUBLE_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    subsd   %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: x86-atom/OP_MUL_DOUBLE_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_DOUBLE_2ADDR.S
+    */
+
+/* File: x86-atom/binopWide2addr.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, rINST              # rINST<- B
+    andl        $15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    mulsd   %xmm1, %xmm0                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: x86-atom/OP_DIV_DOUBLE_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_DOUBLE_2ADDR.S
+    *
+    * Code: Divides doubles. Uses no substitutions.
+    *
+    * For: div-double/2addr
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in the first source reigster
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    andl        $15, %edx              # %edx<- A
+    shr         $4, rINST              # rINST<- B
+    fldl        (rFP, %edx, 4)          # %xmm0<- vA
+    fdivl       (rFP, rINST, 4)         # divide double; vA/vB
+    fstpl       (rFP, %edx, 4)          # vAA<- result
+    FINISH      1                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: x86-atom/OP_REM_DOUBLE_2ADDR.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_DOUBLE_2ADDR.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-double/2addr
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in the first
+    *              source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    and         $15, rINST             # rINST<- A
+    shr         $4, %edx               # %edx<- B
+    movl        (rFP, rINST, 4), %eax   # %eax<- vAlo
+    movl        %eax, -20(%esp)         # push parameter vAAlo
+    movl        4(rFP, rINST, 4), %eax  # %eax<- vAhi
+    movl        %eax, -16(%esp)         # push parameter vAAhi
+    movl        (rFP, %edx, 4), %eax    # %eax<- vBlo
+    movl        %eax, -12(%esp)         # push parameter vBBlo
+    movl        4(rFP, %edx, 4), %eax   # %eax<- vBhi
+    movl        %eax, -8(%esp)          # push parameter vBBhi
+    lea         -20(%esp), %esp
+    jmp         .LOP_REM_DOUBLE_2ADDR_break
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: x86-atom/OP_ADD_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit16.S
+    *
+    * Code: 32-bit "lit16" operation. Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
+    *      xor-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    addl     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RSUB_INT: /* 0xd1 */
+/* File: x86-atom/OP_RSUB_INT.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RSUB_INT.S
+    *
+    * Code: 32-bit reverse-subtraction. Uses no substitutions.
+    *
+    * For: rsub-int
+    *
+    * Description: Perform a reverse subtraction on a register and a
+    *              signed extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    GET_VREG    %ecx                    # %ecx<- vB
+    subl        %ecx, %edx              # %edx<- +CCCC sub vB
+    SET_VREG    %edx, rINST             # vA<- %edx; result
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: x86-atom/OP_MUL_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit16.S
+    *
+    * Code: 32-bit "lit16" operation. Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
+    *      xor-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    imul     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: x86-atom/OP_DIV_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopDLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDLit16.S
+    *
+    * Code: 32-bit "lit16" divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int/lit16, rem-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    FETCHs      1, %ecx                 # %ecx<- +CCCC, sign-extended literal
+    cmp         $0, %ecx               # check for divide by zero
+    GET_VREG    %eax                    # %eax<- vB
+    je          common_errDivideByZero  # handle divide by zero
+    andl        $15, rINST             # rINST<- A
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_DIV_INT_LIT16_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_DIV_INT_LIT16_break
+.LOP_DIV_INT_LIT16_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    #FFETCH_ADV 2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    .if  1
+    SET_VREG    %eax rINST              # vA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vA<- %edx (remainder)
+    .endif
+    jmp         .LOP_DIV_INT_LIT16_break2
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: x86-atom/OP_REM_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopDLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDLit16.S
+    *
+    * Code: 32-bit "lit16" divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int/lit16, rem-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    FETCHs      1, %ecx                 # %ecx<- +CCCC, sign-extended literal
+    cmp         $0, %ecx               # check for divide by zero
+    GET_VREG    %eax                    # %eax<- vB
+    je          common_errDivideByZero  # handle divide by zero
+    andl        $15, rINST             # rINST<- A
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_REM_INT_LIT16_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_REM_INT_LIT16_break
+.LOP_REM_INT_LIT16_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    #FFETCH_ADV 2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    .if  0
+    SET_VREG    %eax rINST              # vA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vA<- %edx (remainder)
+    .endif
+    jmp         .LOP_REM_INT_LIT16_break2
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: x86-atom/OP_AND_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit16.S
+    *
+    * Code: 32-bit "lit16" operation. Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
+    *      xor-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    andl     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: x86-atom/OP_OR_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit16.S
+    *
+    * Code: 32-bit "lit16" operation. Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
+    *      xor-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    or %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: x86-atom/OP_XOR_INT_LIT16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT_LIT16.S
+    */
+
+/* File: x86-atom/binopLit16.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit16.S
+    *
+    * Code: 32-bit "lit16" operation. Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
+    *      xor-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    andl        $15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    xor     %edx, %ecx                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: x86-atom/OP_ADD_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs  "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
+    *      xor-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    addl     %edx, %ecx                              # %ecx<- vBB op +CC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: x86-atom/OP_RSUB_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RSUB_INT_LIT8.S
+    *
+    * Code: 32-bit reverse-subtraction. Uses no substitutions.
+    *
+    * For: rsub-int/lit8
+    *
+    * Description: Perform a reverse subtraction on a register and a
+    *              signed extended 8-bit literal value.
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    GET_VREG    %ecx                    # %ecx<- vBB
+    sub         %ecx, %edx              # %edx<- +CC sub vBB
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FINISH      2                       # jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT_LIT8: /* 0xda */
+/* File: x86-atom/OP_MUL_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs  "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
+    *      xor-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    imul     %edx, %ecx                              # %ecx<- vBB op +CC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: x86-atom/OP_DIV_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopDLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int/lit8, rem-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signe extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    cmp         $0, %ecx               # check for divide by zero
+    GET_VREG    %eax                    # %eax<- vBB
+    je          common_errDivideByZero  # handle divide by zero
+
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_DIV_INT_LIT8_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_DIV_INT_LIT8_break
+.LOP_DIV_INT_LIT8_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    #FFETCH_ADV 2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    .if  1
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .LOP_DIV_INT_LIT8_break2
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT_LIT8: /* 0xdc */
+/* File: x86-atom/OP_REM_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopDLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int/lit8, rem-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signe extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    cmp         $0, %ecx               # check for divide by zero
+    GET_VREG    %eax                    # %eax<- vBB
+    je          common_errDivideByZero  # handle divide by zero
+
+    cmpl        $-1, %ecx              # handle -1 special case divide error
+    jne         .LOP_REM_INT_LIT8_noerror
+    cmpl        $0x80000000,%eax       # handle min int special case divide error
+    je         .LOP_REM_INT_LIT8_break
+.LOP_REM_INT_LIT8_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    #FFETCH_ADV 2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    .if  0
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .LOP_REM_INT_LIT8_break2
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT_LIT8: /* 0xdd */
+/* File: x86-atom/OP_AND_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs  "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
+    *      xor-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    andl     %edx, %ecx                              # %ecx<- vBB op +CC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT_LIT8: /* 0xde */
+/* File: x86-atom/OP_OR_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs  "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
+    *      xor-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    or %edx, %ecx                              # %ecx<- vBB op +CC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: x86-atom/OP_XOR_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs  "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
+    *      xor-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    xor     %edx, %ecx                              # %ecx<- vBB op +CC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: x86-atom/OP_SHL_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8S.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8S.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs "%edx = %edx op %cl"
+    *
+    *
+    * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
+    *
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    sal     %cl, %edx                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: x86-atom/OP_SHR_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8S.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8S.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs "%edx = %edx op %cl"
+    *
+    *
+    * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
+    *
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    sar     %cl, %edx                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: x86-atom/OP_USHR_INT_LIT8.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_INT_LIT8.S
+    */
+
+/* File: x86-atom/binopLit8S.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8S.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs "%edx = %edx op %cl"
+    *
+    *
+    * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
+    *
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    shr     %cl, %edx                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IGET_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IPUT_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SGET_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SPUT_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IGET_OBJECT_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IGET_WIDE_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IPUT_WIDE_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SGET_WIDE_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SPUT_WIDE_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_BREAKPOINT: /* 0xec */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_BREAKPOINT      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: x86-atom/OP_THROW_VERIFICATION_ERROR.S */
+   /* 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.
+    */
+
+   /*
+    * File: OP_THROW_VERIFICATION_ERROR.S
+    *
+    * Code:
+    *
+    * For: throw-verification-error
+    *
+    * Description: Throws an exception for an error discovered during verification.
+    *              The exception is indicated by AA with details provided by BBBB.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, ref@BBBB
+    */
+
+    movl        rGLUE, %edx                  # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %ecx   # %ecx<- glue->method
+    EXPORT_PC                                # in case an exception is thrown
+    FETCH       1, %eax                      # %eax<- BBBB
+    movl        %eax, -4(%esp)               # push parameter BBBB; ref
+    movl        rINST, -8(%esp)              # push parameter AA
+    movl        %ecx, -12(%esp)              # push parameter glue->method
+    lea         -12(%esp), %esp
+    call        dvmThrowVerificationError    # call: (const Method* method, int kind, int ref)
+    jmp         common_exceptionThrown       # failed; handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_EXECUTE_INLINE: /* 0xee */
+/* File: x86-atom/OP_EXECUTE_INLINE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_EXECUTE_INLINE.S
+    *
+    * Code: Executes a "native inline" instruction. Uses no substitutions.
+    *
+    * For: execute-inline
+    *
+    * Description: Executes a "native inline" instruction. This instruction
+    *              is generated by the optimizer.
+    *
+    * Format:
+    *
+    * Syntax: vAA, {vC, vD, vE, vF}, inline@BBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    addl        $offGlue_retval, %eax  # %eax<- &glue->retval
+    EXPORT_PC
+    shr         $4, rINST              # rINST<- B
+    movl        %eax, -8(%esp)          # push parameter glue->retval
+    lea         -24(%esp), %esp
+    jmp         .LOP_EXECUTE_INLINE_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_EXECUTE_INLINE_RANGE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_INVOKE_OBJECT_INIT_RANGE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_RETURN_VOID_BARRIER      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_QUICK: /* 0xf2 */
+/* File: x86-atom/OP_IGET_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_QUICK.S
+    *
+    * Code: Optimization for iget
+    *
+    * For: iget-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %eax<- next instruction hi; fetch, advance
+    movl        (%ecx, %eax), %eax      # %eax<- object field
+    SET_VREG    %eax, rINST             # fp[A]<- %eax
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: x86-atom/OP_IGET_WIDE_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_WIDE_QUICK.S
+    *
+    * Code: Optimization for iget
+    *
+    * For: iget/wide-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB; object to operate on
+    cmp         $0, %edx               # check if object is null
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    je          common_errNullObject    # handle null object
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    movq        (%ecx, %edx), %xmm0     # %xmm0<- object field
+    movq        %xmm0, (rFP, rINST, 4)  # fp[A]<- %xmm0
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: x86-atom/OP_IGET_OBJECT_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_OBJECT_QUICK.S
+    */
+
+/* File: x86-atom/OP_IGET_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_QUICK.S
+    *
+    * Code: Optimization for iget
+    *
+    * For: iget-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %eax<- next instruction hi; fetch, advance
+    movl        (%ecx, %eax), %eax      # %eax<- object field
+    SET_VREG    %eax, rINST             # fp[A]<- %eax
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_QUICK: /* 0xf5 */
+/* File: x86-atom/OP_IPUT_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_QUICK.S
+    * Code: Optimization for iput
+    *
+    * For: iput-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl        rINST, (%eax, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: x86-atom/OP_IPUT_WIDE_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_WIDE_QUICK.S
+    *
+    * Code: Optimization for iput
+    *
+    * For: iput/wide-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB; object to operate on
+    cmp         $0, %edx               # check if object is null
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- fp[A]
+    movq        %xmm0, (%edx, %ecx)     # object field<- %xmm0; fp[A]
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: x86-atom/OP_IPUT_OBJECT_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_QUICK.S
+    * Code: Optimization for iput
+    *
+    * For: iput-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $4, %eax               # %eax<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl        rINST, (%eax, %ecx)     # object field<- vA
+    testl       rINST, rINST            # did we write a null object
+    je          1f
+    movl        rGLUE, %ecx             # get glue
+    movl        offGlue_cardTable(%ecx), %ecx # get card table base
+    shrl        $GC_CARD_SHIFT, %eax   # get gc card index
+    movb        %cl, (%eax, %ecx)       # mark gc card in table
+1:
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: x86-atom/OP_INVOKE_VIRTUAL_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_QUICK.S
+    *
+    * Code: Optimization for invoke-virtual and invoke-virtual/range
+    *
+    * For: invoke-virtual/quick, invoke-virtual/quick-range
+    */
+
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    .if (!0)
+    and         $15, %edx              # %edx<- D if not range
+    .endif
+    FETCH       1, %ecx                 # %ecx<- method index
+    GET_VREG    %edx                    # %edx<- "this" ptr
+    cmp         $0, %edx               # %edx<- check for null "this"
+    EXPORT_PC                           # must export pc for invoke
+    je          common_errNullObject
+    movl        offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
+    movl        offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
+    movl        (%edx, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethodNoRange # invoke method common code
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_QUICK_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_VIRTUAL_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_QUICK.S
+    *
+    * Code: Optimization for invoke-virtual and invoke-virtual/range
+    *
+    * For: invoke-virtual/quick, invoke-virtual/quick-range
+    */
+
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    .if (!1)
+    and         $15, %edx              # %edx<- D if not range
+    .endif
+    FETCH       1, %ecx                 # %ecx<- method index
+    GET_VREG    %edx                    # %edx<- "this" ptr
+    cmp         $0, %edx               # %edx<- check for null "this"
+    EXPORT_PC                           # must export pc for invoke
+    je          common_errNullObject
+    movl        offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
+    movl        offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
+    movl        (%edx, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethodRange # invoke method common code
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: x86-atom/OP_INVOKE_SUPER_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_QUICK.S
+    *
+    * Code: Optimization for invoke-super and invoke-super/range
+    *
+    * For: invoke-super/quick, invoke-super/quick-range
+    */
+
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_method(%ecx), %eax # %eax<- glue->method
+    .if         (!0)
+    and         $15, %edx              #  %edx<- D if not range
+    .endif
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        offClassObject_super(%eax), %eax # %eax<- glue->method->clazz->super
+    EXPORT_PC                           # must export for invoke
+    movl        offClassObject_vtable(%eax), %eax # %edx<- glue->method->clazz->super->vtable
+    cmp         $0, (rFP, %edx, 4)     # check for null object
+    movl        (%eax, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    je          common_errNullObject    # handle null object
+    jmp         common_invokeMethodNoRange # invoke method common code
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_QUICK_RANGE.S
+    */
+
+/* File: x86-atom/OP_INVOKE_SUPER_QUICK.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_QUICK.S
+    *
+    * Code: Optimization for invoke-super and invoke-super/range
+    *
+    * For: invoke-super/quick, invoke-super/quick-range
+    */
+
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_method(%ecx), %eax # %eax<- glue->method
+    .if         (!1)
+    and         $15, %edx              #  %edx<- D if not range
+    .endif
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        offClassObject_super(%eax), %eax # %eax<- glue->method->clazz->super
+    EXPORT_PC                           # must export for invoke
+    movl        offClassObject_vtable(%eax), %eax # %edx<- glue->method->clazz->super->vtable
+    cmp         $0, (rFP, %edx, 4)     # check for null object
+    movl        (%eax, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    je          common_errNullObject    # handle null object
+    jmp         common_invokeMethodRange # invoke method common code
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IPUT_OBJECT_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SGET_OBJECT_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SPUT_OBJECT_VOLATILE      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_DISPATCH_FF: /* 0xff */
+/* File: x86-atom/OP_DISPATCH_FF.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DISPATCH_FF.S
+    */
+
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: x86-atom/OP_CONST_CLASS_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: x86-atom/OP_CHECK_CAST_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: x86-atom/OP_INSTANCE_OF_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: x86-atom/OP_NEW_INSTANCE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: x86-atom/OP_NEW_ARRAY_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: x86-atom/OP_FILLED_NEW_ARRAY_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_JUMBO: /* 0x106 */
+/* File: x86-atom/OP_IGET_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: x86-atom/OP_IGET_WIDE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: x86-atom/OP_IGET_OBJECT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: x86-atom/OP_IGET_BOOLEAN_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: x86-atom/OP_IGET_BYTE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: x86-atom/OP_IGET_CHAR_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: x86-atom/OP_IGET_SHORT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_JUMBO: /* 0x10d */
+/* File: x86-atom/OP_IPUT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: x86-atom/OP_IPUT_WIDE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: x86-atom/OP_IPUT_OBJECT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: x86-atom/OP_IPUT_BOOLEAN_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: x86-atom/OP_IPUT_BYTE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: x86-atom/OP_IPUT_CHAR_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: x86-atom/OP_IPUT_SHORT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_JUMBO: /* 0x114 */
+/* File: x86-atom/OP_SGET_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: x86-atom/OP_SGET_WIDE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: x86-atom/OP_SGET_OBJECT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: x86-atom/OP_SGET_BOOLEAN_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: x86-atom/OP_SGET_BYTE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: x86-atom/OP_SGET_CHAR_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: x86-atom/OP_SGET_SHORT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_JUMBO: /* 0x11b */
+/* File: x86-atom/OP_SPUT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: x86-atom/OP_SPUT_WIDE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: x86-atom/OP_SPUT_OBJECT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: x86-atom/OP_SPUT_BOOLEAN_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: x86-atom/OP_SPUT_BYTE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: x86-atom/OP_SPUT_CHAR_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: x86-atom/OP_SPUT_SHORT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: x86-atom/OP_INVOKE_VIRTUAL_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: x86-atom/OP_INVOKE_SUPER_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: x86-atom/OP_INVOKE_DIRECT_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: x86-atom/OP_INVOKE_STATIC_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: x86-atom/OP_INVOKE_INTERFACE_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_27FF: /* 0x127 */
+/* File: x86-atom/OP_UNUSED_27FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_28FF: /* 0x128 */
+/* File: x86-atom/OP_UNUSED_28FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_29FF: /* 0x129 */
+/* File: x86-atom/OP_UNUSED_29FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2AFF: /* 0x12a */
+/* File: x86-atom/OP_UNUSED_2AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2BFF: /* 0x12b */
+/* File: x86-atom/OP_UNUSED_2BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2CFF: /* 0x12c */
+/* File: x86-atom/OP_UNUSED_2CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2DFF: /* 0x12d */
+/* File: x86-atom/OP_UNUSED_2DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2EFF: /* 0x12e */
+/* File: x86-atom/OP_UNUSED_2EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_2FFF: /* 0x12f */
+/* File: x86-atom/OP_UNUSED_2FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_30FF: /* 0x130 */
+/* File: x86-atom/OP_UNUSED_30FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_31FF: /* 0x131 */
+/* File: x86-atom/OP_UNUSED_31FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_32FF: /* 0x132 */
+/* File: x86-atom/OP_UNUSED_32FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_33FF: /* 0x133 */
+/* File: x86-atom/OP_UNUSED_33FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_34FF: /* 0x134 */
+/* File: x86-atom/OP_UNUSED_34FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_35FF: /* 0x135 */
+/* File: x86-atom/OP_UNUSED_35FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_36FF: /* 0x136 */
+/* File: x86-atom/OP_UNUSED_36FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_37FF: /* 0x137 */
+/* File: x86-atom/OP_UNUSED_37FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_38FF: /* 0x138 */
+/* File: x86-atom/OP_UNUSED_38FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_39FF: /* 0x139 */
+/* File: x86-atom/OP_UNUSED_39FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3AFF: /* 0x13a */
+/* File: x86-atom/OP_UNUSED_3AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3BFF: /* 0x13b */
+/* File: x86-atom/OP_UNUSED_3BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3CFF: /* 0x13c */
+/* File: x86-atom/OP_UNUSED_3CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3DFF: /* 0x13d */
+/* File: x86-atom/OP_UNUSED_3DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3EFF: /* 0x13e */
+/* File: x86-atom/OP_UNUSED_3EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3FFF: /* 0x13f */
+/* File: x86-atom/OP_UNUSED_3FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40FF: /* 0x140 */
+/* File: x86-atom/OP_UNUSED_40FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41FF: /* 0x141 */
+/* File: x86-atom/OP_UNUSED_41FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42FF: /* 0x142 */
+/* File: x86-atom/OP_UNUSED_42FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43FF: /* 0x143 */
+/* File: x86-atom/OP_UNUSED_43FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_44FF: /* 0x144 */
+/* File: x86-atom/OP_UNUSED_44FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_45FF: /* 0x145 */
+/* File: x86-atom/OP_UNUSED_45FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_46FF: /* 0x146 */
+/* File: x86-atom/OP_UNUSED_46FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_47FF: /* 0x147 */
+/* File: x86-atom/OP_UNUSED_47FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_48FF: /* 0x148 */
+/* File: x86-atom/OP_UNUSED_48FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_49FF: /* 0x149 */
+/* File: x86-atom/OP_UNUSED_49FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4AFF: /* 0x14a */
+/* File: x86-atom/OP_UNUSED_4AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4BFF: /* 0x14b */
+/* File: x86-atom/OP_UNUSED_4BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4CFF: /* 0x14c */
+/* File: x86-atom/OP_UNUSED_4CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4DFF: /* 0x14d */
+/* File: x86-atom/OP_UNUSED_4DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4EFF: /* 0x14e */
+/* File: x86-atom/OP_UNUSED_4EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_4FFF: /* 0x14f */
+/* File: x86-atom/OP_UNUSED_4FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_50FF: /* 0x150 */
+/* File: x86-atom/OP_UNUSED_50FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_51FF: /* 0x151 */
+/* File: x86-atom/OP_UNUSED_51FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_52FF: /* 0x152 */
+/* File: x86-atom/OP_UNUSED_52FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_53FF: /* 0x153 */
+/* File: x86-atom/OP_UNUSED_53FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_54FF: /* 0x154 */
+/* File: x86-atom/OP_UNUSED_54FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_55FF: /* 0x155 */
+/* File: x86-atom/OP_UNUSED_55FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_56FF: /* 0x156 */
+/* File: x86-atom/OP_UNUSED_56FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_57FF: /* 0x157 */
+/* File: x86-atom/OP_UNUSED_57FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_58FF: /* 0x158 */
+/* File: x86-atom/OP_UNUSED_58FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_59FF: /* 0x159 */
+/* File: x86-atom/OP_UNUSED_59FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5AFF: /* 0x15a */
+/* File: x86-atom/OP_UNUSED_5AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5BFF: /* 0x15b */
+/* File: x86-atom/OP_UNUSED_5BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5CFF: /* 0x15c */
+/* File: x86-atom/OP_UNUSED_5CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5DFF: /* 0x15d */
+/* File: x86-atom/OP_UNUSED_5DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5EFF: /* 0x15e */
+/* File: x86-atom/OP_UNUSED_5EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_5FFF: /* 0x15f */
+/* File: x86-atom/OP_UNUSED_5FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_60FF: /* 0x160 */
+/* File: x86-atom/OP_UNUSED_60FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_61FF: /* 0x161 */
+/* File: x86-atom/OP_UNUSED_61FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_62FF: /* 0x162 */
+/* File: x86-atom/OP_UNUSED_62FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_63FF: /* 0x163 */
+/* File: x86-atom/OP_UNUSED_63FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_64FF: /* 0x164 */
+/* File: x86-atom/OP_UNUSED_64FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_65FF: /* 0x165 */
+/* File: x86-atom/OP_UNUSED_65FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_66FF: /* 0x166 */
+/* File: x86-atom/OP_UNUSED_66FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_67FF: /* 0x167 */
+/* File: x86-atom/OP_UNUSED_67FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_68FF: /* 0x168 */
+/* File: x86-atom/OP_UNUSED_68FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_69FF: /* 0x169 */
+/* File: x86-atom/OP_UNUSED_69FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6AFF: /* 0x16a */
+/* File: x86-atom/OP_UNUSED_6AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6BFF: /* 0x16b */
+/* File: x86-atom/OP_UNUSED_6BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6CFF: /* 0x16c */
+/* File: x86-atom/OP_UNUSED_6CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6DFF: /* 0x16d */
+/* File: x86-atom/OP_UNUSED_6DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6EFF: /* 0x16e */
+/* File: x86-atom/OP_UNUSED_6EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_6FFF: /* 0x16f */
+/* File: x86-atom/OP_UNUSED_6FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_70FF: /* 0x170 */
+/* File: x86-atom/OP_UNUSED_70FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_71FF: /* 0x171 */
+/* File: x86-atom/OP_UNUSED_71FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_72FF: /* 0x172 */
+/* File: x86-atom/OP_UNUSED_72FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73FF: /* 0x173 */
+/* File: x86-atom/OP_UNUSED_73FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_74FF: /* 0x174 */
+/* File: x86-atom/OP_UNUSED_74FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_75FF: /* 0x175 */
+/* File: x86-atom/OP_UNUSED_75FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_76FF: /* 0x176 */
+/* File: x86-atom/OP_UNUSED_76FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_77FF: /* 0x177 */
+/* File: x86-atom/OP_UNUSED_77FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_78FF: /* 0x178 */
+/* File: x86-atom/OP_UNUSED_78FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79FF: /* 0x179 */
+/* File: x86-atom/OP_UNUSED_79FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7AFF: /* 0x17a */
+/* File: x86-atom/OP_UNUSED_7AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7BFF: /* 0x17b */
+/* File: x86-atom/OP_UNUSED_7BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7CFF: /* 0x17c */
+/* File: x86-atom/OP_UNUSED_7CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7DFF: /* 0x17d */
+/* File: x86-atom/OP_UNUSED_7DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7EFF: /* 0x17e */
+/* File: x86-atom/OP_UNUSED_7EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7FFF: /* 0x17f */
+/* File: x86-atom/OP_UNUSED_7FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_80FF: /* 0x180 */
+/* File: x86-atom/OP_UNUSED_80FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_81FF: /* 0x181 */
+/* File: x86-atom/OP_UNUSED_81FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_82FF: /* 0x182 */
+/* File: x86-atom/OP_UNUSED_82FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_83FF: /* 0x183 */
+/* File: x86-atom/OP_UNUSED_83FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_84FF: /* 0x184 */
+/* File: x86-atom/OP_UNUSED_84FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_85FF: /* 0x185 */
+/* File: x86-atom/OP_UNUSED_85FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_86FF: /* 0x186 */
+/* File: x86-atom/OP_UNUSED_86FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_87FF: /* 0x187 */
+/* File: x86-atom/OP_UNUSED_87FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_88FF: /* 0x188 */
+/* File: x86-atom/OP_UNUSED_88FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_89FF: /* 0x189 */
+/* File: x86-atom/OP_UNUSED_89FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8AFF: /* 0x18a */
+/* File: x86-atom/OP_UNUSED_8AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8BFF: /* 0x18b */
+/* File: x86-atom/OP_UNUSED_8BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8CFF: /* 0x18c */
+/* File: x86-atom/OP_UNUSED_8CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8DFF: /* 0x18d */
+/* File: x86-atom/OP_UNUSED_8DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8EFF: /* 0x18e */
+/* File: x86-atom/OP_UNUSED_8EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_8FFF: /* 0x18f */
+/* File: x86-atom/OP_UNUSED_8FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_90FF: /* 0x190 */
+/* File: x86-atom/OP_UNUSED_90FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_91FF: /* 0x191 */
+/* File: x86-atom/OP_UNUSED_91FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_92FF: /* 0x192 */
+/* File: x86-atom/OP_UNUSED_92FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_93FF: /* 0x193 */
+/* File: x86-atom/OP_UNUSED_93FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_94FF: /* 0x194 */
+/* File: x86-atom/OP_UNUSED_94FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_95FF: /* 0x195 */
+/* File: x86-atom/OP_UNUSED_95FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_96FF: /* 0x196 */
+/* File: x86-atom/OP_UNUSED_96FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_97FF: /* 0x197 */
+/* File: x86-atom/OP_UNUSED_97FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_98FF: /* 0x198 */
+/* File: x86-atom/OP_UNUSED_98FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_99FF: /* 0x199 */
+/* File: x86-atom/OP_UNUSED_99FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9AFF: /* 0x19a */
+/* File: x86-atom/OP_UNUSED_9AFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9BFF: /* 0x19b */
+/* File: x86-atom/OP_UNUSED_9BFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9CFF: /* 0x19c */
+/* File: x86-atom/OP_UNUSED_9CFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9DFF: /* 0x19d */
+/* File: x86-atom/OP_UNUSED_9DFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9EFF: /* 0x19e */
+/* File: x86-atom/OP_UNUSED_9EFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_9FFF: /* 0x19f */
+/* File: x86-atom/OP_UNUSED_9FFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: x86-atom/OP_UNUSED_A0FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: x86-atom/OP_UNUSED_A1FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: x86-atom/OP_UNUSED_A2FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: x86-atom/OP_UNUSED_A3FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: x86-atom/OP_UNUSED_A4FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: x86-atom/OP_UNUSED_A5FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: x86-atom/OP_UNUSED_A6FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: x86-atom/OP_UNUSED_A7FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: x86-atom/OP_UNUSED_A8FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: x86-atom/OP_UNUSED_A9FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: x86-atom/OP_UNUSED_AAFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: x86-atom/OP_UNUSED_ABFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: x86-atom/OP_UNUSED_ACFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: x86-atom/OP_UNUSED_ADFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: x86-atom/OP_UNUSED_AEFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_AFFF: /* 0x1af */
+/* File: x86-atom/OP_UNUSED_AFFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: x86-atom/OP_UNUSED_B0FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: x86-atom/OP_UNUSED_B1FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: x86-atom/OP_UNUSED_B2FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: x86-atom/OP_UNUSED_B3FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: x86-atom/OP_UNUSED_B4FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: x86-atom/OP_UNUSED_B5FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: x86-atom/OP_UNUSED_B6FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: x86-atom/OP_UNUSED_B7FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: x86-atom/OP_UNUSED_B8FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: x86-atom/OP_UNUSED_B9FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: x86-atom/OP_UNUSED_BAFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: x86-atom/OP_UNUSED_BBFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: x86-atom/OP_UNUSED_BCFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: x86-atom/OP_UNUSED_BDFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BEFF: /* 0x1be */
+/* File: x86-atom/OP_UNUSED_BEFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: x86-atom/OP_UNUSED_BFFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: x86-atom/OP_UNUSED_C0FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: x86-atom/OP_UNUSED_C1FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: x86-atom/OP_UNUSED_C2FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: x86-atom/OP_UNUSED_C3FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: x86-atom/OP_UNUSED_C4FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: x86-atom/OP_UNUSED_C5FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: x86-atom/OP_UNUSED_C6FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: x86-atom/OP_UNUSED_C7FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: x86-atom/OP_UNUSED_C8FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: x86-atom/OP_UNUSED_C9FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: x86-atom/OP_UNUSED_CAFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: x86-atom/OP_UNUSED_CBFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: x86-atom/OP_UNUSED_CCFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: x86-atom/OP_UNUSED_CDFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: x86-atom/OP_UNUSED_CEFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: x86-atom/OP_UNUSED_CFFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: x86-atom/OP_UNUSED_D0FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: x86-atom/OP_UNUSED_D1FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: x86-atom/OP_UNUSED_D2FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: x86-atom/OP_UNUSED_D3FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: x86-atom/OP_UNUSED_D4FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: x86-atom/OP_UNUSED_D5FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: x86-atom/OP_UNUSED_D6FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: x86-atom/OP_UNUSED_D7FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: x86-atom/OP_UNUSED_D8FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: x86-atom/OP_UNUSED_D9FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DAFF: /* 0x1da */
+/* File: x86-atom/OP_UNUSED_DAFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DBFF: /* 0x1db */
+/* File: x86-atom/OP_UNUSED_DBFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: x86-atom/OP_UNUSED_DCFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: x86-atom/OP_UNUSED_DDFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DEFF: /* 0x1de */
+/* File: x86-atom/OP_UNUSED_DEFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_DFFF: /* 0x1df */
+/* File: x86-atom/OP_UNUSED_DFFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: x86-atom/OP_UNUSED_E0FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: x86-atom/OP_UNUSED_E1FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: x86-atom/OP_UNUSED_E2FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: x86-atom/OP_UNUSED_E3FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: x86-atom/OP_UNUSED_E4FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: x86-atom/OP_UNUSED_E5FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: x86-atom/OP_UNUSED_E6FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: x86-atom/OP_UNUSED_E7FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: x86-atom/OP_UNUSED_E8FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: x86-atom/OP_UNUSED_E9FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: x86-atom/OP_UNUSED_EAFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: x86-atom/OP_UNUSED_EBFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: x86-atom/OP_UNUSED_ECFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: x86-atom/OP_UNUSED_EDFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: x86-atom/OP_UNUSED_EEFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: x86-atom/OP_UNUSED_EFFF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: x86-atom/OP_UNUSED_F0FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: x86-atom/OP_UNUSED_F1FF.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_INVOKE_OBJECT_INIT_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IGET_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IGET_WIDE_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IGET_OBJECT_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IPUT_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IPUT_WIDE_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_IPUT_OBJECT_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SGET_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SGET_WIDE_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SGET_OBJECT_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SPUT_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SPUT_WIDE_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_OP_SPUT_OBJECT_VOLATILE_JUMBO      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: x86-atom/OP_THROW_VERIFICATION_ERROR_JUMBO.S */
+/* File: x86-atom/unused.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
+
+
+    .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 Class has not yet been resolved.
+    *  %ecx: BBBB (Class ref)
+    *  need: target register
+    */
+
+.LOP_CONST_STRING_resolve:
+    EXPORT_PC
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %ecx, -4(%esp)          # push parameter class ref
+    movl        %edx, -8(%esp)          # push parameter glue->method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveString        # resolve string reference
+                                        # call: (const ClassObject* referrer, u4 stringIdx)
+                                        # return: StringObject*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved string failed
+    je          common_exceptionThrown  # resolve failed; exception thrown
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_CONST_STRING_JUMBO */
+
+
+   /*
+    * Continuation if the Class has not yet been resolved.
+    *  %ecx: BBBB (Class ref)
+    *  need: target register
+    */
+.LOP_CONST_STRING_JUMBO_resolve:
+    EXPORT_PC
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx <- glue->method->clazz
+    movl        %ecx, -4(%esp)          # push parameter class ref
+    movl        %edx, -8(%esp)          # push parameter glue->method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveString        # resolve string reference
+                                        # call: (const ClassObject* referrer, u4 stringIdx)
+                                        # return: StringObject*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved string failed
+    je          common_exceptionThrown  # resolve failed; exception thrown
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FINISH      3                       # jump to next instruction
+
+/* continuation for OP_CONST_CLASS */
+
+   /*
+    * Continuation if the Class has not yet been resolved.
+    *  %ecx: BBBB (Class ref)
+    *  need: target register
+    */
+
+.LOP_CONST_CLASS_resolve:
+    EXPORT_PC
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        $1, -4(%esp)           # push parameter true
+    movl        %ecx, -8(%esp)          # push parameter
+    movl        %edx, -12(%esp)         # push parameter glue->method->clazz
+    lea         -12(%esp), %esp
+    call        dvmResolveClass         # resolve ClassObject pointer
+                                        # class: (const ClassObject* referrer, u4 classIdx,
+                                        #         bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         12(%esp), %esp
+    cmp         $0, %eax               # check for null pointer
+    je          common_exceptionThrown  # handle exception
+    SET_VREG    %eax, rINST             # vAA<- resolved class
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_CHECK_CAST */
+
+.LOP_CHECK_CAST_resolved:
+    cmp         %ecx, offObject_clazz(rINST) # check for same class
+    jne         .LOP_CHECK_CAST_fullcheck   # not same class; do full check
+
+.LOP_CHECK_CAST_okay:
+    FINISH      2                       # jump to next instruction
+
+   /*
+    *  Trivial test failed, need to perform full check.
+    *  offObject_clazz(rINST) holds obj->clazz
+    *  %ecx holds class resolved from BBBB
+    *  rINST holds object
+    */
+
+.LOP_CHECK_CAST_fullcheck:
+    movl        offObject_clazz(rINST), %eax  # %eax<- obj->clazz
+    movl        %eax, -12(%esp)         # push parameter obj->clazz
+    movl        %ecx, -8(%esp)          # push parameter # push parameter resolved class
+    lea         -12(%esp), %esp
+    call        dvmInstanceofNonTrivial # call: (ClassObject* instance, ClassObject* clazz)
+                                        # return: int
+    lea         12(%esp), %esp
+    cmp         $0, %eax               # failed?
+    jne         .LOP_CHECK_CAST_okay        # success
+
+   /*
+    * A cast has failed.  We need to throw a ClassCastException with the
+    * class of the object that failed to be cast.
+    */
+
+    EXPORT_PC                           # we will throw an exception
+#error BIT ROT!!!
+    /*
+     * TODO: Code here needs to call dvmThrowClassCastException with two
+     * arguments.
+     */
+#if 0
+    /* old obsolete code that called dvmThrowExceptionWithClassMessage */
+    movl        $.LstrClassCastExceptionPtr, -8(%esp) # push parameter message
+    movl        offObject_clazz(rINST), rINST # rINST<- obj->clazz
+    movl        offClassObject_descriptor(rINST), rINST # rINST<- obj->clazz->descriptor
+    movl        rINST, -4(%esp)         # push parameter obj->clazz->descriptor
+    lea         -8(%esp), %esp
+    call        dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
+                                                  #       const char* messageDescriptor, Object* cause)
+                                                  # return: void
+#endif
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown
+
+   /*
+    * Resolution required.  This is the least-likely path.
+    *
+    *  rINST holds object
+    */
+
+.LOP_CHECK_CAST_resolve:
+    movl        offGlue_method(%edx), %eax # %eax<- glue->method
+    FETCH       1, %ecx                 # %ecx holds BBBB
+    EXPORT_PC                           # in case we throw an exception
+    movl        $0, -8(%esp)           # push parameter false
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        %ecx, -12(%esp)         # push parameter BBBB
+    movl        %eax, -16(%esp)         # push parameter glue->method>clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # resolve ClassObject pointer
+                                        # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return ClassObject*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null pointer
+    je          common_exceptionThrown  # handle excpetion
+    movl        %eax, %ecx              # %ecx<- resolved class
+    jmp         .LOP_CHECK_CAST_resolved
+
+/* continuation for OP_INSTANCE_OF */
+
+.LOP_INSTANCE_OF_break:
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- CCCC
+    movl        offDvmDex_pResClasses(%ecx), %ecx # %ecx<- pDvmDex->pResClasses
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved class
+    movl        offObject_clazz(%edx), %edx # %edx<- obj->clazz
+    cmp         $0, %ecx               # check if already resovled
+    je          .LOP_INSTANCE_OF_resolve     # not resolved before, so resolve now
+
+.LOP_INSTANCE_OF_resolved:
+    cmp         %ecx, %edx              # check if same class
+    je          .LOP_INSTANCE_OF_trivial     # yes, finish
+    jmp         .LOP_INSTANCE_OF_fullcheck   # no, do full check
+
+   /*
+    * The trivial test failed, we need to perform a full check.
+    * %edx holds obj->clazz
+    * %ecx holds class resolved from BBBB
+    */
+
+.LOP_INSTANCE_OF_fullcheck:
+    movl        %edx, -8(%esp)          # push parameter obj->clazz
+    movl        %ecx, -4(%esp)          # push parameter resolved class
+    lea         -8(%esp), %esp
+    call        dvmInstanceofNonTrivial # perform full check
+                                        # call: (ClassObject* instance, ClassObject* clazz)
+                                        # return: int
+    andl        $15, rINST             # rINST<- A
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    lea         8(%esp), %esp
+    SET_VREG    %eax, rINST             # vA<- r0
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+   /*
+    * %edx holds boolean result
+    */
+
+.LOP_INSTANCE_OF_store:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    andl        $15, rINST             # rINST<- A
+    SET_VREG    %edx, rINST             # vA<- r0
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+   /*
+    * Trivial test succeeded, save and bail.
+    */
+
+.LOP_INSTANCE_OF_trivial:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    andl        $15, rINST             # rINST<- A
+    SET_VREG    $1, rINST              # vA<- r0
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+   /*
+    * Resolution required.  This is the least-likely path.
+    * %eax holds BBBB
+    */
+
+.LOP_INSTANCE_OF_resolve:
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    EXPORT_PC
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
+    movl        %ecx, -12(%esp)         # push parameter glue->method->clazz
+    movl        %eax, -8(%esp)          # push parameter CCCC; type index
+    movl        $1, -4(%esp)           # push parameter true
+    lea         -12(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         12(%esp), %esp
+    cmp         $0, %eax               # check for null
+    je          common_exceptionThrown  # handle exception
+    movl        rINST, %edx             # %edx<- BA+
+    shr         $4, %edx               # %edx<- B
+    movl        %eax, %ecx              # need class in %ecx
+    GET_VREG    %edx                    # %edx<- vB
+    movl        offObject_clazz(%edx), %edx # %edx<- obj->clazz
+    jmp         .LOP_INSTANCE_OF_resolved    # clazz resolved, continue
+
+/* continuation for OP_NEW_INSTANCE */
+.balign 32
+.LOP_NEW_INSTANCE_finish:
+    movl        %edx, -8(%esp)          # push parameter object
+    movl        %eax, -4(%esp)          # push parameter flags
+    lea         -8(%esp), %esp
+    call        dvmAllocObject          # call: (ClassObject* clazz, int flags)
+                                        # return: Object*
+    cmp         $0, %eax               # check for failure
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    SET_VREG    %eax, rINST             # vAA<- pObject
+    FINISH      2                       # jump to next instruction
+
+   /*
+    * Class initialization required.
+    *
+    *  %edx holds class object
+    */
+
+.LOP_NEW_INSTANCE_needinit:
+    movl        %edx, -4(%esp)          # push parameter object
+    lea         -4(%esp), %esp
+    call        dvmInitClass            # call: (ClassObject* clazz)
+                                        # return: bool
+    lea         4(%esp), %esp
+    cmp         $0, %eax               # check for failure
+    movl        -4(%esp), %edx          # %edx<- object
+    je          common_exceptionThrown  # handle exception
+    testl       $(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
+    mov         $ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
+    je          .LOP_NEW_INSTANCE_finish      # continue
+    jmp         .LOP_NEW_INSTANCE_abstract    # handle abstract or interface
+
+   /*
+    * Resolution required.  This is the least-likely path.
+    *
+    *  BBBB in %eax
+    */
+
+.LOP_NEW_INSTANCE_resolve:
+
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
+    movl        %ecx, -12(%esp)         # push parameter clazz
+    movl        $0, -4(%esp)           # push parameter false
+    movl        %eax, -8(%esp)          # push parameter BBBB
+    lea         -12(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer,
+                                        #       u4 classIdx, bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         12(%esp), %esp
+    movl        %eax, %edx              # %edx<- pObject
+    cmp         $0, %edx               # check for failure
+    jne         .LOP_NEW_INSTANCE_resolved    # continue
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * We can't instantiate an abstract class or interface, so throw an
+    * InstantiationError with the class descriptor as the message.
+    *
+    *  %edx holds class object
+    */
+
+.LOP_NEW_INSTANCE_abstract:
+    movl        offClassObject_descriptor(%edx), %ecx # %ecx<- descriptor
+    movl        %ecx, -4(%esp)          # push parameter descriptor
+    movl        $.LstrInstantiationErrorPtr, -8(%esp) # push parameter message
+    lea         -8(%esp), %esp
+    call        dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
+                                                  #        const char* messageDescriptor)
+                                                  # return: void
+    jmp         common_exceptionThrown  # handle exception
+
+.LstrInstantiationErrorPtr:
+.asciz      "Ljava/lang/InstantiationError;"
+
+/* continuation for OP_NEW_ARRAY */
+
+   /*
+    * Resolve class.  (This is an uncommon case.)
+    *
+    *  %edx holds array length
+    *  %ecx holds class ref CCCC
+    */
+
+.LOP_NEW_ARRAY_resolve:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        %edx, -4(%esp)          # save length
+    movl        $0, -8(%esp)           # push parameter false
+    movl        %ecx, -12(%esp)         # push parameter class ref
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        %eax, -16(%esp)         # push parameter clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer,
+                                        #       u4 classIdx, bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    cmp         $0, %eax               # check for failure
+    lea         16(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    movl        -4(%esp), %edx          # %edx<- length
+
+   /*
+    * Finish allocation.
+    *
+    *  %eax holds class
+    *  %edx holds array length
+    */
+
+.LOP_NEW_ARRAY_finish:
+    movl        %eax, -12(%esp)         # push parameter class
+    movl        %edx, -8(%esp)          # push parameter length
+    movl        $ALLOC_DONT_TRACK, -4(%esp)
+    lea         -12(%esp), %esp
+    call        dvmAllocArrayByClass    # call: (ClassObject* arrayClass,
+                                        # size_t length, int allocFlags)
+                                        # return: ArrayObject*
+    and         $15, rINST             # rINST<- A
+    cmp         $0, %eax               # check for allocation failure
+    lea         12(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    SET_VREG    %eax, rINST             # vA<- pArray
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_FILLED_NEW_ARRAY */
+
+.LOP_FILLED_NEW_ARRAY_break:
+    movl        $0, -8(%esp)           # push parameter false
+    movl        %ecx, -12(%esp)         # push parameter BBBB
+    movl        rGLUE, %edx             # %edx<- MterpGlue pointer
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -16(%esp)         # push parameter glue->method->clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null return
+    je          common_exceptionThrown  # handle exception
+
+   /*
+    * On entry:
+    *  %eax holds array class
+    *  rINST holds BA or AA
+    */
+
+.LOP_FILLED_NEW_ARRAY_continue:
+    movl        offClassObject_descriptor(%eax), %eax # %eax<- arrayClass->descriptor
+    movzbl      1(%eax), %eax           # %eax<- descriptor[1]
+    cmpb        $'I', %al             # check if array of ints
+    je          1f
+    cmpb        $'L', %al
+    je          1f
+    cmpb        $'[', %al
+    jne         .LOP_FILLED_NEW_ARRAY_notimpl     # jump to not implemented
+1:
+    movl        %eax, sReg0             # save type
+    movl        rINST, -12(%esp)        # push parameter length
+    movl        %eax, -16(%esp)         # push parameter descriptor[1]
+    movl        $ALLOC_DONT_TRACK, -8(%esp) # push parameter to allocate flags
+    .if         (!0)
+    shrl        $4, -12(%esp)          # parameter length is B
+    .endif
+    lea         -16(%esp), %esp
+    call        dvmAllocPrimitiveArray  # call: (char type, size_t length, int allocFlags)
+                                        # return: ArrayObject*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null return
+    je          common_exceptionThrown  # handle exception
+
+    FETCH       2, %edx                 # %edx<- FEDC or CCCC
+    movl        rGLUE, %ecx             # %ecx<- MterpGlue pointer
+    movl        %eax, offGlue_retval(%ecx) # retval<- new array
+    lea         offArrayObject_contents(%eax), %eax # %eax<- newArray->contents
+    subl        $1, -12(%esp)          # length--; check for negative
+    js          2f                      # if length was zero, finish
+
+   /*
+    * copy values from registers into the array
+    * %eax=array, %edx=CCCC/FEDC, -12(%esp)=length (from AA or B), rINST=AA/BA
+    */
+
+    .if         0
+    lea         (rFP, %edx, 4), %ecx    # %ecx<- &fpp[CCCC]
+1:
+    movl        (%ecx), %edx            # %edx<- %ecx++
+    lea         4(%ecx), %ecx           # %ecx++
+    movl        %edx, (%eax)            # *contents<- vX
+    lea         4(%eax), %eax           # %eax++; contents++
+    subl        $1, -12(%esp)          # length--
+    jns         1b                      # or continue at 2
+    .else
+    cmp         $4, -12(%esp)          # check length
+    jne         1f                      # has four args
+    and         $15, rINST             # rINST<- A
+    GET_VREG    rINST                   # rINST<- vA
+    subl        $1, -12(%esp)          # count--
+    movl        rINST, 16(%eax)         # contents[4]<- vA
+1:
+    movl        %edx, %ecx              # %ecx<- %edx; ecx for temp
+    andl        $15, %ecx              # %ecx<- G/F/E/D
+    GET_VREG    %ecx                    # %ecx<- vG/vF/vE/vD
+    shr         $4, %edx               # %edx<- put next reg in low 4
+    subl        $1, -12(%esp)          # count--
+    movl        %ecx, (%eax)            # *contents<- vX
+    lea         4(%eax), %eax           # %eax++; contents++
+    jns         1b                      # or continue at 2
+    .endif
+2:
+    cmpb        $'I', sReg0            # check for int array
+    je          3f
+    movl        rGLUE, %ecx             # %ecx<- MterpGlue pointer
+    movl        offGlue_retval(%ecx), %eax # Object head
+    movl        offGlue_cardTable(%ecx), %ecx # card table base
+    shrl        $GC_CARD_SHIFT, %eax   # convert to card num
+    movb        %cl,(%ecx, %eax)        # mark card based on object head
+3:
+    FINISH      3                       # jump to next instruction
+
+   /*
+    * Throw an exception to indicate this mode of filled-new-array
+    * has not been implemented.
+    */
+
+.LOP_FILLED_NEW_ARRAY_notimpl:
+    movl        $.LstrInternalError, -8(%esp)
+    movl        $.LstrFilledNewArrayNotImpl, -4(%esp)
+    lea         -8(%esp), %esp
+    call        dvmThrowException # call: (const char* exceptionDescriptor,
+                                  #        const char* msg)
+                                  # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown
+
+.if         (!0)                 # define in one or the other, not both
+.LstrFilledNewArrayNotImpl:
+.asciz      "filled-new-array only implemented for 'int'"
+.LstrInternalError:
+.asciz  "Ljava/lang/InternalError;"
+.endif
+
+/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
+
+.LOP_FILLED_NEW_ARRAY_RANGE_break:
+    movl        $0, -8(%esp)           # push parameter false
+    movl        %ecx, -12(%esp)         # push parameter BBBB
+    movl        rGLUE, %edx             # %edx<- MterpGlue pointer
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -16(%esp)         # push parameter glue->method->clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null return
+    je          common_exceptionThrown  # handle exception
+
+   /*
+    * On entry:
+    *  %eax holds array class
+    *  rINST holds BA or AA
+    */
+
+.LOP_FILLED_NEW_ARRAY_RANGE_continue:
+    movl        offClassObject_descriptor(%eax), %eax # %eax<- arrayClass->descriptor
+    movzbl      1(%eax), %eax           # %eax<- descriptor[1]
+    cmpb        $'I', %al             # check if array of ints
+    je          1f
+    cmpb        $'L', %al
+    je          1f
+    cmpb        $'[', %al
+    jne         .LOP_FILLED_NEW_ARRAY_RANGE_notimpl     # jump to not implemented
+1:
+    movl        %eax, sReg0             # save type
+    movl        rINST, -12(%esp)        # push parameter length
+    movl        %eax, -16(%esp)         # push parameter descriptor[1]
+    movl        $ALLOC_DONT_TRACK, -8(%esp) # push parameter to allocate flags
+    .if         (!1)
+    shrl        $4, -12(%esp)          # parameter length is B
+    .endif
+    lea         -16(%esp), %esp
+    call        dvmAllocPrimitiveArray  # call: (char type, size_t length, int allocFlags)
+                                        # return: ArrayObject*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null return
+    je          common_exceptionThrown  # handle exception
+
+    FETCH       2, %edx                 # %edx<- FEDC or CCCC
+    movl        rGLUE, %ecx             # %ecx<- MterpGlue pointer
+    movl        %eax, offGlue_retval(%ecx) # retval<- new array
+    lea         offArrayObject_contents(%eax), %eax # %eax<- newArray->contents
+    subl        $1, -12(%esp)          # length--; check for negative
+    js          2f                      # if length was zero, finish
+
+   /*
+    * copy values from registers into the array
+    * %eax=array, %edx=CCCC/FEDC, -12(%esp)=length (from AA or B), rINST=AA/BA
+    */
+
+    .if         1
+    lea         (rFP, %edx, 4), %ecx    # %ecx<- &fpp[CCCC]
+1:
+    movl        (%ecx), %edx            # %edx<- %ecx++
+    lea         4(%ecx), %ecx           # %ecx++
+    movl        %edx, (%eax)            # *contents<- vX
+    lea         4(%eax), %eax           # %eax++; contents++
+    subl        $1, -12(%esp)          # length--
+    jns         1b                      # or continue at 2
+    .else
+    cmp         $4, -12(%esp)          # check length
+    jne         1f                      # has four args
+    and         $15, rINST             # rINST<- A
+    GET_VREG    rINST                   # rINST<- vA
+    subl        $1, -12(%esp)          # count--
+    movl        rINST, 16(%eax)         # contents[4]<- vA
+1:
+    movl        %edx, %ecx              # %ecx<- %edx; ecx for temp
+    andl        $15, %ecx              # %ecx<- G/F/E/D
+    GET_VREG    %ecx                    # %ecx<- vG/vF/vE/vD
+    shr         $4, %edx               # %edx<- put next reg in low 4
+    subl        $1, -12(%esp)          # count--
+    movl        %ecx, (%eax)            # *contents<- vX
+    lea         4(%eax), %eax           # %eax++; contents++
+    jns         1b                      # or continue at 2
+    .endif
+2:
+    cmpb        $'I', sReg0            # check for int array
+    je          3f
+    movl        rGLUE, %ecx             # %ecx<- MterpGlue pointer
+    movl        offGlue_retval(%ecx), %eax # Object head
+    movl        offGlue_cardTable(%ecx), %ecx # card table base
+    shrl        $GC_CARD_SHIFT, %eax   # convert to card num
+    movb        %cl,(%ecx, %eax)        # mark card based on object head
+3:
+    FINISH      3                       # jump to next instruction
+
+   /*
+    * Throw an exception to indicate this mode of filled-new-array
+    * has not been implemented.
+    */
+
+.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
+    movl        $.LstrInternalError, -8(%esp)
+    movl        $.LstrFilledNewArrayNotImpl, -4(%esp)
+    lea         -8(%esp), %esp
+    call        dvmThrowException # call: (const char* exceptionDescriptor,
+                                  #        const char* msg)
+                                  # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown
+
+.if         (!1)                 # define in one or the other, not both
+.LstrFilledNewArrayNotImpl:
+.asciz      "filled-new-array only implemented for 'int'"
+.LstrInternalError:
+.asciz  "Ljava/lang/InternalError;"
+.endif
+
+/* continuation for OP_PACKED_SWITCH */
+.LOP_PACKED_SWITCH_finish:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+/* continuation for OP_SPARSE_SWITCH */
+.LOP_SPARSE_SWITCH_finish:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+/* continuation for OP_CMPL_FLOAT */
+.LOP_CMPL_FLOAT_greater:
+    movl        $0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPL_FLOAT_final:
+    movl        $0x0, (rFP, rINST, 4)  # vAA<- equal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPL_FLOAT_finalNan:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4)   # vAA<- NaN
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_CMPG_FLOAT */
+.LOP_CMPG_FLOAT_greater:
+    movl        $0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPG_FLOAT_final:
+    movl        $0x0, (rFP, rINST, 4)  # vAA<- equal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPG_FLOAT_finalNan:
+    movl        $0x1, (rFP, rINST, 4)   # vAA<- NaN
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_CMPL_DOUBLE */
+.LOP_CMPL_DOUBLE_greater:
+    movl        $0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPL_DOUBLE_final:
+    movl        $0x0, (rFP, rINST, 4)  # vAA<- equal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPL_DOUBLE_finalNan:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4)   # vAA<- NaN
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_CMPG_DOUBLE */
+.LOP_CMPG_DOUBLE_greater:
+    movl        $0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPG_DOUBLE_final:
+    movl        $0x0, (rFP, rINST, 4)  # vAA<- equal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.LOP_CMPG_DOUBLE_finalNan:
+    movl        $0x1, (rFP, rINST, 4)   # vAA<- NaN
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_CMP_LONG */
+
+.LOP_CMP_LONG_final:
+    movl        $0x0, (rFP, rINST, 4)  # vAA<- equal
+    FINISH      2                       # jump to next instruction
+
+.LOP_CMP_LONG_less:
+    movl        $0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FINISH      2                       # jump to next instruction
+
+.LOP_CMP_LONG_greater:
+    movl        $0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_APUT_OBJECT */
+
+.LOP_APUT_OBJECT_finish:
+    movl        %edx, sReg0             # save &vBB[vCC]
+    movl        %eax, sReg1             # save object head
+    movl        offObject_clazz(rINST), %edx # %edx<- obj->clazz
+    movl        %edx, -8(%esp)          # push parameter obj->clazz
+    movl        offObject_clazz(%eax), %eax # %eax<- arrayObj->clazz
+    movl        %eax, -4(%esp)          # push parameter arrayObj->clazz
+    lea         -8(%esp), %esp
+    call        dvmCanPutArrayElement   # test object type vs. array type
+                                        # call: ClassObject* elemClass, ClassObject* arrayClass)
+                                        # return: bool
+    lea         8(%esp), %esp
+    testl       %eax, %eax              # check for invalid array value
+    je          common_errArrayStore    # handle invalid array value
+    movl        sReg0, %edx             # restore &vBB[vCC]
+    movl        rINST, offArrayObject_contents(%edx)
+    movl        rGLUE, %eax
+    FFETCH_ADV  2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    movl        offGlue_cardTable(%eax), %eax # get card table base
+    movl        sReg1, %edx             # restore object head
+    shrl        $GC_CARD_SHIFT, %edx   # object head to card number
+    movb        %al, (%eax, %edx)       # mark card using object head
+    FGETOP_JMP  2, %ecx                 # jump to next instruction; getop, jmp
+.LOP_APUT_OBJECT_skip_check:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        rINST, offArrayObject_contents(%edx)
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET */
+
+.LOP_IGET_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.LOP_IGET_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET_WIDE */
+
+.LOP_IGET_WIDE_finish2:
+    lea         -8(%esp), %esp
+    call        dvmResolveInstField     # resolve InstField ptr
+                                        # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- %eax; %ecx expected to hold field
+    je          common_exceptionThrown
+
+   /*
+    *  %ecx holds resolved field
+    */
+
+.LOP_IGET_WIDE_finish:
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB
+    cmp         $0, %edx               # check for null object
+    je          common_errNullObject
+    movl        offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (%ecx, %edx), %xmm0     # %xmm0<- object field
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- %xmm0; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET_OBJECT */
+
+.LOP_IGET_OBJECT_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.LOP_IGET_OBJECT_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET_BOOLEAN */
+
+.LOP_IGET_BOOLEAN_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.LOP_IGET_BOOLEAN_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET_BYTE */
+
+.LOP_IGET_BYTE_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.LOP_IGET_BYTE_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET_CHAR */
+
+.LOP_IGET_CHAR_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.LOP_IGET_CHAR_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IGET_SHORT */
+
+.LOP_IGET_SHORT_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.LOP_IGET_SHORT_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT */
+
+.LOP_IPUT_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved
+    jne         .LOP_IPUT_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.LOP_IPUT_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl     rINST, (%edx, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT_WIDE */
+
+.LOP_IPUT_WIDE_finish2:
+    lea         -8(%esp), %esp
+    call        dvmResolveInstField     # resolve InstField ptr
+    cmp         $0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- %eax; %ecx expected to hold field
+    jne         .LOP_IPUT_WIDE_finish
+    jmp         common_exceptionThrown
+
+   /*
+    * Currently:
+    *  %ecx holds resolved field
+    *  %edx does not hold object yet
+    */
+
+.LOP_IPUT_WIDE_finish:
+    movl        rINST, %edx             # %edx<- BA
+    shr         $4, %edx               # %edx<- B
+    andl        $15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB
+    cmp         $0, %edx               # check for null object
+    je          common_errNullObject
+    movl        offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vA
+    movq        %xmm0, (%ecx, %edx)     # object field<- %xmm0; vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT_OBJECT */
+
+.LOP_IPUT_OBJECT_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved
+    jne         .LOP_IPUT_OBJECT_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.LOP_IPUT_OBJECT_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    GET_VREG    rINST                   # rINST<- vA
+    movl        rINST, (%edx, %ecx)     # object field<- vA
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl     rGLUE, %eax             # get glue
+    movl        offGlue_cardTable(%eax), %eax # get card table base
+    testl       rINST, rINST            # test if we stored a null value
+    je          1f                     # skip card mark if null stored
+    shrl        $GC_CARD_SHIFT, %ecx   # set obeject head to card number
+    movb        %al, (%eax, %ecx)
+1:
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+.LOP_IPUT_BOOLEAN_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved
+    jne         .LOP_IPUT_BOOLEAN_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.LOP_IPUT_BOOLEAN_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl     rINST, (%edx, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT_BYTE */
+
+.LOP_IPUT_BYTE_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved
+    jne         .LOP_IPUT_BYTE_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.LOP_IPUT_BYTE_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl     rINST, (%edx, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT_CHAR */
+
+.LOP_IPUT_CHAR_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved
+    jne         .LOP_IPUT_CHAR_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.LOP_IPUT_CHAR_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl     rINST, (%edx, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_IPUT_SHORT */
+
+.LOP_IPUT_SHORT_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if resolved
+    jne         .LOP_IPUT_SHORT_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.LOP_IPUT_SHORT_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $4, %ecx               # %ecx<- B
+    and         $15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl     rINST, (%edx, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SGET */
+
+.LOP_SGET_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.LOP_SGET_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SGET_WIDE */
+
+   /*
+    * Continuation if the field has not yet been resolved.
+    *  %edx: BBBB field ref
+    */
+
+.LOP_SGET_WIDE_resolve:
+    movl        offGlue_method(%eax), %eax # %eax <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %edx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%eax), %eax # %eax<- method->clazz
+    movl        %eax, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if initalization failed
+    movl        %eax, %ecx              # %ecx<- result
+    jne         .LOP_SGET_WIDE_finish      # success, continue
+    jmp         common_exceptionThrown  # failed; handle exception
+
+/* continuation for OP_SGET_OBJECT */
+
+.LOP_SGET_OBJECT_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.LOP_SGET_OBJECT_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SGET_BOOLEAN */
+
+.LOP_SGET_BOOLEAN_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.LOP_SGET_BOOLEAN_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SGET_BYTE */
+
+.LOP_SGET_BYTE_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.LOP_SGET_BYTE_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SGET_CHAR */
+
+.LOP_SGET_CHAR_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.LOP_SGET_CHAR_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SGET_SHORT */
+
+.LOP_SGET_SHORT_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.LOP_SGET_SHORT_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SPUT */
+
+.LOP_SPUT_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.LOP_SPUT_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SPUT_WIDE */
+
+   /*
+    * Continuation if the field has not yet been resolved.
+    *  %edx: BBBB field ref
+    */
+
+.LOP_SPUT_WIDE_resolve:
+    movl        offGlue_method(%eax), %eax # %eax <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %edx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%eax), %eax # %eax<- method->clazz
+    movl        %eax, -8(%esp)
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    lea         8(%esp), %esp
+    cmp         $0, %eax               # check if initalization failed
+    movl        %eax, %ecx              # %ecx<- result
+    jne         .LOP_SPUT_WIDE_finish      # success, continue
+    jmp         common_exceptionThrown  # failed; handle exception
+
+/* continuation for OP_SPUT_OBJECT */
+
+.LOP_SPUT_OBJECT_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.LOP_SPUT_OBJECT_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+
+
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    testl       rINST, rINST            # stored null object ptr?
+    je          1f
+    movl        rGLUE, %edx             # get glue
+    movl        offField_clazz(%ecx), %ecx # ecx<- field->clazz
+    movl        offGlue_cardTable(%edx), %edx # get card table base
+    shrl        $GC_CARD_SHIFT, %ecx   # head to card number
+    movb        %dl, (%edx, %ecx)       # mark card
+1:
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+.LOP_SPUT_BOOLEAN_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.LOP_SPUT_BOOLEAN_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SPUT_BYTE */
+
+.LOP_SPUT_BYTE_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.LOP_SPUT_BYTE_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SPUT_CHAR */
+
+.LOP_SPUT_CHAR_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.LOP_SPUT_CHAR_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_SPUT_SHORT */
+
+.LOP_SPUT_SHORT_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.LOP_SPUT_SHORT_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_INVOKE_VIRTUAL */
+
+.LOP_INVOKE_VIRTUAL_break:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %edx, -4(%esp)          # save "this" pointer register
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        $METHOD_VIRTUAL, -8(%esp) # push parameter method type
+    movl        %ecx, -12(%esp)         # push paramter method index
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    lea         -16(%esp), %esp
+    movl        %eax, (%esp)            # push parameter clazz
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null method return
+    movl        -4(%esp), %edx          # get "this" pointer register
+    jne         .LOP_INVOKE_VIRTUAL_continue
+    jmp         common_exceptionThrown  # null pointer; handle exception
+
+   /*
+    * At this point:
+    *  %eax = resolved base method
+    *  %edx = D or CCCC (index of first arg, which is the "this" ptr)
+    */
+
+.LOP_INVOKE_VIRTUAL_continue:
+    GET_VREG    %edx                    # %edx<- "this" ptr
+    movzwl      offMethod_methodIndex(%eax), %eax # %eax<- baseMethod->methodIndex
+    cmp         $0, %edx               # %edx<- check for null "this"
+    je          common_errNullObject    # handle null object
+    movl        offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
+    movl        offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
+    movl        (%edx, %eax, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethodNoRange # invoke method common code
+
+/* continuation for OP_INVOKE_SUPER */
+
+.LOP_INVOKE_SUPER_continue2:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    EXPORT_PC                           # must export for invoke
+    cmp         $0, %ecx               # check if already resolved
+    jne         .LOP_INVOKE_SUPER_continue
+    jmp         .LOP_INVOKE_SUPER_resolve     # handle resolve
+
+   /*
+    *  %ecx = resolved base method
+    *  %eax = method->clazz
+    */
+
+.LOP_INVOKE_SUPER_continue:
+    movl        offClassObject_super(%eax), %edx # %edx<- glue->method->clazz->super
+    movzwl      offMethod_methodIndex(%ecx), %ecx # %ecx<-  baseMethod->methodIndex
+    cmp          offClassObject_vtableCount(%edx), %ecx # compare vtableCount with methodIndex
+    EXPORT_PC                           # must export for invoke
+    jnc         .LOP_INVOKE_SUPER_nsm         # handle method not present
+    movl        offClassObject_vtable(%edx), %edx # %edx<- glue->method->clazz->super->vtable
+    movl        (%edx, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethodNoRange # invoke method common code
+
+.LOP_INVOKE_SUPER_resolve:
+    movl        %eax, -12(%esp)         # push parameter clazz
+    movl        %edx, -8(%esp)          # push parameter method index
+    movl        $METHOD_VIRTUAL, -4(%esp) # push parameter method type
+    lea         -12(%esp), %esp
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         12(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- method
+    cmp         $0, %ecx               # check for null method return
+    movl        -12(%esp), %eax         # %eax<- glue->method->clazz
+    jne         .LOP_INVOKE_SUPER_continue
+    jmp         common_exceptionThrown  # null pointer; handle exception
+
+   /*
+    * Throw a NoSuchMethodError with the method name as the message.
+    * %ecx = resolved base method
+    */
+
+.LOP_INVOKE_SUPER_nsm:
+    movl        offMethod_name(%ecx), %edx # %edx<- method name
+    jmp         common_errNoSuchMethod
+
+/* continuation for OP_INVOKE_DIRECT */
+
+   /*
+    * %eax = reference (BBBB or CCCC)
+    * -4(%esp) = "this" register
+    */
+
+.LOP_INVOKE_DIRECT_resolve:
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        $METHOD_DIRECT, -8(%esp) # push parameter method type
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        %eax, -12(%esp)         # push parameter reference
+    lea         -16(%esp), %esp
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, (%esp)            # push parameter clazz
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null method return
+    movl        -4(%esp), %edx          # get "this" pointer register
+    GET_VREG    %edx                    # get "this" pointer
+    je          common_exceptionThrown  # null pointer; handle exception
+    cmp         $0, %edx               # check for null "this"
+    movl        %eax, %ecx              # %ecx<- method
+    jne         common_invokeMethodNoRange # invoke method common code
+    jmp         common_errNullObject    # handle null object
+
+/* continuation for OP_INVOKE_STATIC */
+
+.LOP_INVOKE_STATIC_break:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        $METHOD_STATIC, -4(%esp) # resolver method type
+    movl        %eax, -8(%esp)          # push parameter method index
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -12(%esp)         # push parameter method
+    lea         -12(%esp), %esp
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         12(%esp), %esp
+    cmp         $0, %eax               # check for null method
+    je          common_exceptionThrown
+    movl        %eax, %ecx              # %ecx<- method
+    jmp         common_invokeMethodNoRange # invoke method common code
+
+/* continuation for OP_INVOKE_INTERFACE */
+.LOP_INVOKE_INTERFACE_break:
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        %ecx, -8(%esp)          # push parameter method
+    movl        offObject_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -16(%esp)         # push parameter
+    lea         -16(%esp), %esp
+    call        dvmFindInterfaceMethodInCache # call: (ClassObject* thisClass, u4 methodIdx,
+                                              #       const Method* method, DvmDex* methodClassDex)
+                                              # return: Method*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check if find failed
+    je          common_exceptionThrown  # handle exception
+    movl        %eax, %ecx              # %ecx<- method
+    jmp         common_invokeMethodNoRange # invoke method common code
+
+/* continuation for OP_INVOKE_VIRTUAL_RANGE */
+
+.LOP_INVOKE_VIRTUAL_RANGE_break:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %edx, -4(%esp)          # save "this" pointer register
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        $METHOD_VIRTUAL, -8(%esp) # push parameter method type
+    movl        %ecx, -12(%esp)         # push paramter method index
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    lea         -16(%esp), %esp
+    movl        %eax, (%esp)            # push parameter clazz
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null method return
+    movl        -4(%esp), %edx          # get "this" pointer register
+    jne         .LOP_INVOKE_VIRTUAL_RANGE_continue
+    jmp         common_exceptionThrown  # null pointer; handle exception
+
+   /*
+    * At this point:
+    *  %eax = resolved base method
+    *  %edx = D or CCCC (index of first arg, which is the "this" ptr)
+    */
+
+.LOP_INVOKE_VIRTUAL_RANGE_continue:
+    GET_VREG    %edx                    # %edx<- "this" ptr
+    movzwl      offMethod_methodIndex(%eax), %eax # %eax<- baseMethod->methodIndex
+    cmp         $0, %edx               # %edx<- check for null "this"
+    je          common_errNullObject    # handle null object
+    movl        offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
+    movl        offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
+    movl        (%edx, %eax, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethodRange # invoke method common code
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+.LOP_INVOKE_SUPER_RANGE_continue2:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    EXPORT_PC                           # must export for invoke
+    cmp         $0, %ecx               # check if already resolved
+    jne         .LOP_INVOKE_SUPER_RANGE_continue
+    jmp         .LOP_INVOKE_SUPER_RANGE_resolve     # handle resolve
+
+   /*
+    *  %ecx = resolved base method
+    *  %eax = method->clazz
+    */
+
+.LOP_INVOKE_SUPER_RANGE_continue:
+    movl        offClassObject_super(%eax), %edx # %edx<- glue->method->clazz->super
+    movzwl      offMethod_methodIndex(%ecx), %ecx # %ecx<-  baseMethod->methodIndex
+    cmp          offClassObject_vtableCount(%edx), %ecx # compare vtableCount with methodIndex
+    EXPORT_PC                           # must export for invoke
+    jnc         .LOP_INVOKE_SUPER_RANGE_nsm         # handle method not present
+    movl        offClassObject_vtable(%edx), %edx # %edx<- glue->method->clazz->super->vtable
+    movl        (%edx, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethodRange # invoke method common code
+
+.LOP_INVOKE_SUPER_RANGE_resolve:
+    movl        %eax, -12(%esp)         # push parameter clazz
+    movl        %edx, -8(%esp)          # push parameter method index
+    movl        $METHOD_VIRTUAL, -4(%esp) # push parameter method type
+    lea         -12(%esp), %esp
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         12(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- method
+    cmp         $0, %ecx               # check for null method return
+    movl        -12(%esp), %eax         # %eax<- glue->method->clazz
+    jne         .LOP_INVOKE_SUPER_RANGE_continue
+    jmp         common_exceptionThrown  # null pointer; handle exception
+
+   /*
+    * Throw a NoSuchMethodError with the method name as the message.
+    * %ecx = resolved base method
+    */
+
+.LOP_INVOKE_SUPER_RANGE_nsm:
+    movl        offMethod_name(%ecx), %edx # %edx<- method name
+    jmp         common_errNoSuchMethod
+
+/* continuation for OP_INVOKE_DIRECT_RANGE */
+
+   /*
+    * %eax = reference (BBBB or CCCC)
+    * -4(%esp) = "this" register
+    */
+
+.LOP_INVOKE_DIRECT_RANGE_resolve:
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        $METHOD_DIRECT, -8(%esp) # push parameter method type
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        %eax, -12(%esp)         # push parameter reference
+    lea         -16(%esp), %esp
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, (%esp)            # push parameter clazz
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check for null method return
+    movl        -4(%esp), %edx          # get "this" pointer register
+    GET_VREG    %edx                    # get "this" pointer
+    je          common_exceptionThrown  # null pointer; handle exception
+    cmp         $0, %edx               # check for null "this"
+    movl        %eax, %ecx              # %ecx<- method
+    jne         common_invokeMethodRange # invoke method common code
+    jmp         common_errNullObject    # handle null object
+
+/* continuation for OP_INVOKE_STATIC_RANGE */
+
+.LOP_INVOKE_STATIC_RANGE_break:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        $METHOD_STATIC, -4(%esp) # resolver method type
+    movl        %eax, -8(%esp)          # push parameter method index
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -12(%esp)         # push parameter method
+    lea         -12(%esp), %esp
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         12(%esp), %esp
+    cmp         $0, %eax               # check for null method
+    je          common_exceptionThrown
+    movl        %eax, %ecx              # %ecx<- method
+    jmp         common_invokeMethodRange # invoke method common code
+
+/* continuation for OP_INVOKE_INTERFACE_RANGE */
+.LOP_INVOKE_INTERFACE_RANGE_break:
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        %ecx, -8(%esp)          # push parameter method
+    movl        offObject_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -16(%esp)         # push parameter
+    lea         -16(%esp), %esp
+    call        dvmFindInterfaceMethodInCache # call: (ClassObject* thisClass, u4 methodIdx,
+                                              #       const Method* method, DvmDex* methodClassDex)
+                                              # return: Method*
+    lea         16(%esp), %esp
+    cmp         $0, %eax               # check if find failed
+    je          common_exceptionThrown  # handle exception
+    movl        %eax, %ecx              # %ecx<- method
+    jmp         common_invokeMethodRange # invoke method common code
+
+/* continuation for OP_FLOAT_TO_INT */
+
+.LOP_FLOAT_TO_INT_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $0xc00, -2(%esp)       # reset control
+    fldcw       -2(%esp)                # load control word
+    xorl        $0xc00, -2(%esp)       # reset control
+    fistpl      (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.LOP_FLOAT_TO_INT_nanInf:
+    jnp         .LOP_FLOAT_TO_INT_posInf      # handle posInf
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    movl        $0x00000000,  (rFP, %edx, 4) # vA<- NaN
+    FINISH      1                       # jump to next instruction
+
+.LOP_FLOAT_TO_INT_posInf:
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    movl        $0x7FFFFFFF,  (rFP, %edx, 4) # vA<- posInf
+    FINISH      1                       # jump to next instruction
+
+.LOP_FLOAT_TO_INT_negInf:
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    movl        $0x80000000, (rFP, %edx, 4) # vA<- negInf
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_FLOAT_TO_LONG */
+
+.LOP_FLOAT_TO_LONG_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $0xc00, -2(%esp)       # update control
+    fldcw       -2(%esp)                # load control word
+    xorl        $0xc00, -2(%esp)       # reset control
+    fistpll     (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.LOP_FLOAT_TO_LONG_nanInf:
+    jnp         .LOP_FLOAT_TO_LONG_posInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNanLong, %xmm0   # %xmm0<- NaN
+    movq        %xmm0,  (rFP, %edx, 4)  # vA<- %xmm0; NaN
+    FINISH      1                       # jump to next instruction
+
+.LOP_FLOAT_TO_LONG_posInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; posInf
+    FINISH      1                       # jump to next instruction
+
+.LOP_FLOAT_TO_LONG_negInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; negInf
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_DOUBLE_TO_INT */
+
+.LOP_DOUBLE_TO_INT_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $0xc00, -2(%esp)       # reset control
+    fldcw       -2(%esp)                # load control word
+    xorl        $0xc00, -2(%esp)       # reset control
+    fistpl      (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.LOP_DOUBLE_TO_INT_nanInf:
+    jnp         .LOP_DOUBLE_TO_INT_posInf
+    fstps       (rFP, %edx, 4)
+    movl        $0x00000000,  (rFP, %edx, 4) # vA<- NaN
+    FINISH      1                       # jump to next instruction
+
+.LOP_DOUBLE_TO_INT_posInf:
+    fstps       (rFP, %edx, 4)
+    movl        $0x7FFFFFFF,  (rFP, %edx, 4) # vA<- posInf
+    FINISH      1                       # jump to next instruction
+
+.LOP_DOUBLE_TO_INT_negInf:
+    fstps       (rFP, %edx, 4)
+    fstps       (rFP, %edx, 4)
+    movl        $0x80000000,  (rFP, %edx, 4) # vA<- negInf
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_DOUBLE_TO_LONG */
+
+.LOP_DOUBLE_TO_LONG_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $0xc00, -2(%esp)       # reset control
+    fldcw       -2(%esp)                # load control word
+    xorl        $0xc00, -2(%esp)       # reset control
+    fistpll     (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.LOP_DOUBLE_TO_LONG_nanInf:
+    jnp         .LOP_DOUBLE_TO_LONG_posInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNanLong, %xmm0   # %xmm0<- NaN
+    movq        %xmm0,  (rFP, %edx, 4)  # vA<- %xmm0; NaN
+    FINISH      1                       # jump to next instruction
+
+.LOP_DOUBLE_TO_LONG_posInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; posInf
+    FINISH      1                       # jump to next instruction
+
+.LOP_DOUBLE_TO_LONG_negInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; negInf
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_DIV_INT */
+.LOP_DIV_INT_break:
+    .if  1
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.LOP_DIV_INT_break2:
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_REM_INT */
+.LOP_REM_INT_break:
+    .if  0
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.LOP_REM_INT_break2:
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_MUL_LONG */
+
+   /*
+    * X = (rFP, rINST, 4)
+    * W = 4(rFP, rINST, 4)
+    * Z = (rFP, %edx, 4)
+    * Y = 4(rFP, %edx, 4)
+    */
+
+.LOP_MUL_LONG_finish:
+    movl        4(rFP, rINST, 4), %ecx  # %ecx<- W
+    imull       (rFP, %edx, 4),  %ecx   # %ecx<- WxZ
+    mov         4(rFP, %edx, 4), %eax   # %ecx<- Y
+    imull       (rFP, rINST, 4), %eax   # %eax<- XxY
+    addl        %eax, %ecx              # %ecx<- (WZ + XY)
+    movl        (rFP, %edx, 4), %eax    # %eax<- Z
+    mull        (rFP, rINST, 4)         # %edx:eax<- XZ
+    movzbl      -4(%esp), rINST         # rINST<- AA
+    addl        %edx, %ecx              # %ecx<- carry + (WZ + XY)
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1<- results hi
+    movl        %eax, (rFP, rINST, 4)   # vAA<- results lo
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_DIV_LONG */
+.LOP_DIV_LONG_finish:
+    movq        %xmm0, -16(%esp)        # push arg vBB,vBB+1
+    lea         -16(%esp), %esp
+    call        __divdi3                   # call func
+    lea         16(%esp), %esp
+    movl        %eax, (rFP, rINST, 4)   # vAA<- return low
+    movl        %edx, 4(rFP, rINST, 4)  # vAA+1<- return high
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_REM_LONG */
+.LOP_REM_LONG_finish:
+    movq        %xmm0, -16(%esp)        # push arg vBB,vBB+1
+    lea         -16(%esp), %esp
+    call        __moddi3                   # call func
+    lea         16(%esp), %esp
+    movl        %eax, (rFP, rINST, 4)   # vAA<- return low
+    movl        %edx, 4(rFP, rINST, 4)  # vAA+1<- return high
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_SHR_LONG */
+
+.LOP_SHR_LONG_finish:
+    movq        .Lvalue64, %xmm3        # %xmm3<- 64
+    psubq       %xmm0, %xmm3            # %xmm3<- 64 - shift amount
+    movq        .L64bits, %xmm4         # %xmm4<- lower 64 bits set
+    psllq       %xmm3, %xmm4            # %xmm4<- correct mask for sign bits
+    por         %xmm4, %xmm1            # %xmm1<- signed and shifted vBB
+
+.LOP_SHR_LONG_final:
+    movq        %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_REM_DOUBLE */
+
+.LOP_REM_DOUBLE_break:
+    call        fmod                    # call: (long double x, long double y)
+                                        # return: double
+    lea         16(%esp), %esp
+    fstpl       (rFP, rINST, 4)         # vAA<- remainder; return of fmod
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_DIV_INT_2ADDR */
+.LOP_DIV_INT_2ADDR_break:
+    .if  1
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.LOP_DIV_INT_2ADDR_break2:
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+/* continuation for OP_REM_INT_2ADDR */
+.LOP_REM_INT_2ADDR_break:
+    .if  0
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.LOP_REM_INT_2ADDR_break2:
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+
+/* continuation for OP_MUL_LONG_2ADDR */
+
+   /*
+    * X = (rFP, rINST, 4)
+    * W = 4(rFP, rINST, 4)
+    * Z = (rFP, %edx, 4)
+    * Y = 4(rFP, %edx, 4)
+    */
+
+.LOP_MUL_LONG_2ADDR_finish:
+    movl        4(rFP, rINST, 4), %ecx  # %ecx<- W
+    imull       (rFP, %edx, 4), %ecx    # %ecx<- WxZ
+    movl                4(rFP, %edx, 4), %eax   # %eax<- Y
+    imull       (rFP, rINST, 4), %eax   # %eax<- X*Y
+    addl        %eax, %ecx              # %ecx<- (WZ + XY)
+    movl        (rFP, %edx, 4), %eax    # %eax<- Z
+    mull        (rFP, rINST, 4)         # %edx:eax<- XZ
+    addl        %edx, %ecx              # %ecx<- carry + (WZ + XY)
+    movl        sReg0, %edx             # %edx<- A
+    movl        %ecx, 4(rFP, %edx, 4)   # vA+1<- results hi
+    movl        %eax, (rFP, %edx, 4)    # vA<- results lo
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_DIV_LONG_2ADDR */
+.LOP_DIV_LONG_2ADDR_break:
+    movq        %xmm0, -20(%esp)        # push arg vA, vA+1
+    lea         -20(%esp), %esp
+    call        __divdi3                   # call func
+    lea         20(%esp), %esp
+    movl        %eax, (rFP, rINST, 4)   # vA<- return low
+    movl        %edx, 4(rFP, rINST, 4)  # vA<- return high
+    FFETCH_ADV  1, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    FGETOP_JMP 1, %ecx                  # jump to next instruction; getop, jmp
+
+/* continuation for OP_REM_LONG_2ADDR */
+.LOP_REM_LONG_2ADDR_break:
+    movq        %xmm0, -20(%esp)        # push arg vA, vA+1
+    lea         -20(%esp), %esp
+    call        __moddi3                   # call func
+    lea         20(%esp), %esp
+    movl        %eax, (rFP, rINST, 4)   # vA<- return low
+    movl        %edx, 4(rFP, rINST, 4)  # vA<- return high
+    FFETCH_ADV  1, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    FGETOP_JMP 1, %ecx                  # jump to next instruction; getop, jmp
+
+/* continuation for OP_SHR_LONG_2ADDR */
+
+.LOP_SHR_LONG_2ADDR_finish:
+    movq        .Lvalue64, %xmm3        # %xmm3<- 64
+    psubq       %xmm0, %xmm3            # %xmm3<- 64 - shift amount
+    movq        .L64bits, %xmm4         # %xmm4<- lower 64 bits set
+    psllq       %xmm3, %xmm4            # %xmm4<- correct mask for sign bits
+    por         %xmm4, %xmm1            # %xmm1<- signed and shifted vBB
+
+.LOP_SHR_LONG_2ADDR_final:
+    movq        %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_REM_DOUBLE_2ADDR */
+
+.LOP_REM_DOUBLE_2ADDR_break:
+    call        fmod                    # call: (long double x, long double y)
+                                        # return: double
+    lea         20(%esp), %esp
+    fstpl       (rFP, rINST, 4)         # vAA<- remainder; return of fmod
+    FINISH      1                       # jump to next instruction
+
+/* continuation for OP_DIV_INT_LIT16 */
+.LOP_DIV_INT_LIT16_break:
+    .if  1
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.LOP_DIV_INT_LIT16_break2:
+
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_REM_INT_LIT16 */
+.LOP_REM_INT_LIT16_break:
+    .if  0
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.LOP_REM_INT_LIT16_break2:
+
+    FINISH      2                       # jump to next instruction
+
+/* continuation for OP_DIV_INT_LIT8 */
+.LOP_DIV_INT_LIT8_break:
+    .if  1
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+
+.LOP_DIV_INT_LIT8_break2:
+    FINISH      2                       # jump to next instruction
+    #FGETOP_JMP 2, %ecx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_REM_INT_LIT8 */
+.LOP_REM_INT_LIT8_break:
+    .if  0
+    movl        $0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+
+.LOP_REM_INT_LIT8_break2:
+    FINISH      2                       # jump to next instruction
+    #FGETOP_JMP 2, %ecx                 # jump to next instruction; getop, jmp
+
+/* continuation for OP_EXECUTE_INLINE */
+
+   /*
+    * Extract args, call function.
+    *  rINST = #of args (0-4)
+    *  %ecx = call index
+    */
+
+.LOP_EXECUTE_INLINE_continue:
+    FETCH       2, %edx                 # %edx<- FEDC
+    cmp         $1, rINST              # determine number of arguments
+    jl          0f                      # handle zero args
+    je          1f                      # handle one arg
+    cmp         $3, rINST
+    jl          2f                      # handle two args
+    je          3f                      # handle three args
+4:
+    movl        %edx, rINST             # rINST<- FEDC
+    and         $0xf000, rINST         # isolate F
+    shr         $10, rINST
+    movl        (rFP, rINST), rINST     # rINST<- vF
+    movl        rINST, 12(%esp)         # push parameter vF
+3:
+    movl        %edx, rINST             # rINST<- FEDC
+    and         $0x0f00, rINST         # isolate E
+    shr         $6, rINST
+    movl        (rFP, rINST), rINST     # rINST<- vE
+    movl        rINST, 8(%esp)          # push parameter E
+2:
+    movl        %edx, rINST             # rINST<- FEDC
+    and         $0x00f0, rINST         # isolate D
+    shr         $2, rINST
+    movl        (rFP, rINST), rINST     # rINST<- vD
+    movl        rINST, 4(%esp)          # push parameter D
+1:
+    and         $0x000f, %edx          # isolate C
+    movl        (rFP, %edx, 4), %edx    # rINST<- vC
+    movl        %edx, (%esp)            # push parameter C
+0:
+    shl         $4, %ecx
+    movl        $gDvmInlineOpsTable, %eax # %eax<- address for table of inline operations
+    call        *(%eax, %ecx)           # call function
+
+    cmp         $0, %eax               # check boolean result of inline
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         24(%esp), %esp          # update stack pointer
+    je          common_exceptionThrown  # handle exception
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+/* File: x86-atom/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.
+    */
+
+   /*
+    * File: entry.S
+    */
+
+#define ASSIST_DEBUGGER 1
+    .text
+    .align      2
+    .global     dvmMterpStdRun
+    .type       dvmMterpStdRun, %function
+
+   /*
+    * Save registers, initialize sp and fp.
+    * On entry:
+    *     bool MterpGlue(glue *)
+    */
+
+    .macro      MTERP_ENTRY
+    movl        4(%esp), %ecx           # get first argument
+    movl        %ebp, -4(%esp)          # save caller base pointer
+    movl        %ebx, -8(%esp)          # save %ebx
+    movl        %esi, -12(%esp)         # save %esi
+    movl        %edi, -16(%esp)         # save %edi
+    lea         -40(%esp), %ebp         # set callee base pointer
+    lea         -40(%esp), %esp         # set callee stack pointer
+    .endm
+
+   /*
+    * Restore registers.
+    * This function returns a boolean "changeInterp" value.
+    * The return value is from dvmMterpStdBail().
+    */
+
+    .macro      MTERP_EXIT
+    lea         40(%esp), %esp          # correct stack pointer
+    movl        -16(%esp), %edi         # restore %edi
+    movl        -12(%esp), %esi         # restore %esi
+    movl        -8(%esp), %ebx          # restore %ebx
+    movl        -4(%esp), %ebp          # restore caller base pointer
+    ret                                 # return
+    .endm
+
+   /*
+    * DvmMterpStdRun entry point: save stack pointer, setup memory locations, get
+    * entry point, start executing instructions.
+    */
+
+dvmMterpStdRun:
+    MTERP_ENTRY
+    movl        %ecx, rGLUE             # save value for pMterpGlue
+    movl        offGlue_pc(%ecx), rPC   # get program counter
+    cmp         $kInterpEntryInstr, offGlue_entryPoint(%ecx) # check instruction
+    movl        offGlue_fp(%ecx), rFP   # get frame pointer
+    movl        %esp, offGlue_bailPtr(%ecx) # save SP for eventual return
+    FFETCH      %edx                    # %edx<- opcode
+    jne         .Lnot_instr             # no, handle it
+    FGETOP_JMPa %edx                    # start executing the instruction at rPC
+
+   /*
+    * Not an instruction. Are we returning from a method?
+    */
+
+.Lnot_instr:
+    cmpl        $kInterpEntryReturn, offGlue_entryPoint(%ecx)
+    je          common_returnFromMethod
+
+   /*
+    * No, are we throwing an exception?
+    */
+
+.Lnot_return:
+    cmpl        $kInterpEntryThrow, offGlue_entryPoint(%ecx)
+    je          common_exceptionThrown
+
+   /*
+    * No, then we must abort.
+    */
+
+.Lbad_arg:
+    pushl       offGlue_entryPoint(%ecx)
+    movl        $.LstrBadEntryPoint, -4(%esp)
+    lea         -4(%esp), %esp
+    call        printf
+    lea         8(%esp), %esp
+    call        dvmAbort                # call (void)
+
+   /*
+    * Restore the stack pointer and PC from the save point established on entry and
+    * return to whoever called dvmMterpStdRun.
+    *
+    * On entry:
+    *  4(%esp) MterpGlue* glue
+    *  8(%esp) bool changeInterp
+    */
+
+    .global     dvmMterpStdBail
+    .type       dvmMterpStdBail, %function
+
+dvmMterpStdBail:
+    movl        4(%esp), %ecx           # get first argument
+    movl        8(%esp), %eax           # get second argument
+    movl        offGlue_bailPtr(%ecx), %esp # sp <- saved SP
+    MTERP_EXIT
+
+   /*
+    * String references.
+    */
+
+.LstrBadEntryPoint:
+    .asciz "Bad entry point %d\n"
+
+
+dvmAsmInstructionJmpTable = .LdvmAsmInstructionJmpTable
+.LdvmAsmInstructionJmpTable:
+.long .L_OP_NOP
+.long .L_OP_MOVE
+.long .L_OP_MOVE_FROM16
+.long .L_OP_MOVE_16
+.long .L_OP_MOVE_WIDE
+.long .L_OP_MOVE_WIDE_FROM16
+.long .L_OP_MOVE_WIDE_16
+.long .L_OP_MOVE_OBJECT
+.long .L_OP_MOVE_OBJECT_FROM16
+.long .L_OP_MOVE_OBJECT_16
+.long .L_OP_MOVE_RESULT
+.long .L_OP_MOVE_RESULT_WIDE
+.long .L_OP_MOVE_RESULT_OBJECT
+.long .L_OP_MOVE_EXCEPTION
+.long .L_OP_RETURN_VOID
+.long .L_OP_RETURN
+.long .L_OP_RETURN_WIDE
+.long .L_OP_RETURN_OBJECT
+.long .L_OP_CONST_4
+.long .L_OP_CONST_16
+.long .L_OP_CONST
+.long .L_OP_CONST_HIGH16
+.long .L_OP_CONST_WIDE_16
+.long .L_OP_CONST_WIDE_32
+.long .L_OP_CONST_WIDE
+.long .L_OP_CONST_WIDE_HIGH16
+.long .L_OP_CONST_STRING
+.long .L_OP_CONST_STRING_JUMBO
+.long .L_OP_CONST_CLASS
+.long .L_OP_MONITOR_ENTER
+.long .L_OP_MONITOR_EXIT
+.long .L_OP_CHECK_CAST
+.long .L_OP_INSTANCE_OF
+.long .L_OP_ARRAY_LENGTH
+.long .L_OP_NEW_INSTANCE
+.long .L_OP_NEW_ARRAY
+.long .L_OP_FILLED_NEW_ARRAY
+.long .L_OP_FILLED_NEW_ARRAY_RANGE
+.long .L_OP_FILL_ARRAY_DATA
+.long .L_OP_THROW
+.long .L_OP_GOTO
+.long .L_OP_GOTO_16
+.long .L_OP_GOTO_32
+.long .L_OP_PACKED_SWITCH
+.long .L_OP_SPARSE_SWITCH
+.long .L_OP_CMPL_FLOAT
+.long .L_OP_CMPG_FLOAT
+.long .L_OP_CMPL_DOUBLE
+.long .L_OP_CMPG_DOUBLE
+.long .L_OP_CMP_LONG
+.long .L_OP_IF_EQ
+.long .L_OP_IF_NE
+.long .L_OP_IF_LT
+.long .L_OP_IF_GE
+.long .L_OP_IF_GT
+.long .L_OP_IF_LE
+.long .L_OP_IF_EQZ
+.long .L_OP_IF_NEZ
+.long .L_OP_IF_LTZ
+.long .L_OP_IF_GEZ
+.long .L_OP_IF_GTZ
+.long .L_OP_IF_LEZ
+.long .L_OP_UNUSED_3E
+.long .L_OP_UNUSED_3F
+.long .L_OP_UNUSED_40
+.long .L_OP_UNUSED_41
+.long .L_OP_UNUSED_42
+.long .L_OP_UNUSED_43
+.long .L_OP_AGET
+.long .L_OP_AGET_WIDE
+.long .L_OP_AGET_OBJECT
+.long .L_OP_AGET_BOOLEAN
+.long .L_OP_AGET_BYTE
+.long .L_OP_AGET_CHAR
+.long .L_OP_AGET_SHORT
+.long .L_OP_APUT
+.long .L_OP_APUT_WIDE
+.long .L_OP_APUT_OBJECT
+.long .L_OP_APUT_BOOLEAN
+.long .L_OP_APUT_BYTE
+.long .L_OP_APUT_CHAR
+.long .L_OP_APUT_SHORT
+.long .L_OP_IGET
+.long .L_OP_IGET_WIDE
+.long .L_OP_IGET_OBJECT
+.long .L_OP_IGET_BOOLEAN
+.long .L_OP_IGET_BYTE
+.long .L_OP_IGET_CHAR
+.long .L_OP_IGET_SHORT
+.long .L_OP_IPUT
+.long .L_OP_IPUT_WIDE
+.long .L_OP_IPUT_OBJECT
+.long .L_OP_IPUT_BOOLEAN
+.long .L_OP_IPUT_BYTE
+.long .L_OP_IPUT_CHAR
+.long .L_OP_IPUT_SHORT
+.long .L_OP_SGET
+.long .L_OP_SGET_WIDE
+.long .L_OP_SGET_OBJECT
+.long .L_OP_SGET_BOOLEAN
+.long .L_OP_SGET_BYTE
+.long .L_OP_SGET_CHAR
+.long .L_OP_SGET_SHORT
+.long .L_OP_SPUT
+.long .L_OP_SPUT_WIDE
+.long .L_OP_SPUT_OBJECT
+.long .L_OP_SPUT_BOOLEAN
+.long .L_OP_SPUT_BYTE
+.long .L_OP_SPUT_CHAR
+.long .L_OP_SPUT_SHORT
+.long .L_OP_INVOKE_VIRTUAL
+.long .L_OP_INVOKE_SUPER
+.long .L_OP_INVOKE_DIRECT
+.long .L_OP_INVOKE_STATIC
+.long .L_OP_INVOKE_INTERFACE
+.long .L_OP_UNUSED_73
+.long .L_OP_INVOKE_VIRTUAL_RANGE
+.long .L_OP_INVOKE_SUPER_RANGE
+.long .L_OP_INVOKE_DIRECT_RANGE
+.long .L_OP_INVOKE_STATIC_RANGE
+.long .L_OP_INVOKE_INTERFACE_RANGE
+.long .L_OP_UNUSED_79
+.long .L_OP_UNUSED_7A
+.long .L_OP_NEG_INT
+.long .L_OP_NOT_INT
+.long .L_OP_NEG_LONG
+.long .L_OP_NOT_LONG
+.long .L_OP_NEG_FLOAT
+.long .L_OP_NEG_DOUBLE
+.long .L_OP_INT_TO_LONG
+.long .L_OP_INT_TO_FLOAT
+.long .L_OP_INT_TO_DOUBLE
+.long .L_OP_LONG_TO_INT
+.long .L_OP_LONG_TO_FLOAT
+.long .L_OP_LONG_TO_DOUBLE
+.long .L_OP_FLOAT_TO_INT
+.long .L_OP_FLOAT_TO_LONG
+.long .L_OP_FLOAT_TO_DOUBLE
+.long .L_OP_DOUBLE_TO_INT
+.long .L_OP_DOUBLE_TO_LONG
+.long .L_OP_DOUBLE_TO_FLOAT
+.long .L_OP_INT_TO_BYTE
+.long .L_OP_INT_TO_CHAR
+.long .L_OP_INT_TO_SHORT
+.long .L_OP_ADD_INT
+.long .L_OP_SUB_INT
+.long .L_OP_MUL_INT
+.long .L_OP_DIV_INT
+.long .L_OP_REM_INT
+.long .L_OP_AND_INT
+.long .L_OP_OR_INT
+.long .L_OP_XOR_INT
+.long .L_OP_SHL_INT
+.long .L_OP_SHR_INT
+.long .L_OP_USHR_INT
+.long .L_OP_ADD_LONG
+.long .L_OP_SUB_LONG
+.long .L_OP_MUL_LONG
+.long .L_OP_DIV_LONG
+.long .L_OP_REM_LONG
+.long .L_OP_AND_LONG
+.long .L_OP_OR_LONG
+.long .L_OP_XOR_LONG
+.long .L_OP_SHL_LONG
+.long .L_OP_SHR_LONG
+.long .L_OP_USHR_LONG
+.long .L_OP_ADD_FLOAT
+.long .L_OP_SUB_FLOAT
+.long .L_OP_MUL_FLOAT
+.long .L_OP_DIV_FLOAT
+.long .L_OP_REM_FLOAT
+.long .L_OP_ADD_DOUBLE
+.long .L_OP_SUB_DOUBLE
+.long .L_OP_MUL_DOUBLE
+.long .L_OP_DIV_DOUBLE
+.long .L_OP_REM_DOUBLE
+.long .L_OP_ADD_INT_2ADDR
+.long .L_OP_SUB_INT_2ADDR
+.long .L_OP_MUL_INT_2ADDR
+.long .L_OP_DIV_INT_2ADDR
+.long .L_OP_REM_INT_2ADDR
+.long .L_OP_AND_INT_2ADDR
+.long .L_OP_OR_INT_2ADDR
+.long .L_OP_XOR_INT_2ADDR
+.long .L_OP_SHL_INT_2ADDR
+.long .L_OP_SHR_INT_2ADDR
+.long .L_OP_USHR_INT_2ADDR
+.long .L_OP_ADD_LONG_2ADDR
+.long .L_OP_SUB_LONG_2ADDR
+.long .L_OP_MUL_LONG_2ADDR
+.long .L_OP_DIV_LONG_2ADDR
+.long .L_OP_REM_LONG_2ADDR
+.long .L_OP_AND_LONG_2ADDR
+.long .L_OP_OR_LONG_2ADDR
+.long .L_OP_XOR_LONG_2ADDR
+.long .L_OP_SHL_LONG_2ADDR
+.long .L_OP_SHR_LONG_2ADDR
+.long .L_OP_USHR_LONG_2ADDR
+.long .L_OP_ADD_FLOAT_2ADDR
+.long .L_OP_SUB_FLOAT_2ADDR
+.long .L_OP_MUL_FLOAT_2ADDR
+.long .L_OP_DIV_FLOAT_2ADDR
+.long .L_OP_REM_FLOAT_2ADDR
+.long .L_OP_ADD_DOUBLE_2ADDR
+.long .L_OP_SUB_DOUBLE_2ADDR
+.long .L_OP_MUL_DOUBLE_2ADDR
+.long .L_OP_DIV_DOUBLE_2ADDR
+.long .L_OP_REM_DOUBLE_2ADDR
+.long .L_OP_ADD_INT_LIT16
+.long .L_OP_RSUB_INT
+.long .L_OP_MUL_INT_LIT16
+.long .L_OP_DIV_INT_LIT16
+.long .L_OP_REM_INT_LIT16
+.long .L_OP_AND_INT_LIT16
+.long .L_OP_OR_INT_LIT16
+.long .L_OP_XOR_INT_LIT16
+.long .L_OP_ADD_INT_LIT8
+.long .L_OP_RSUB_INT_LIT8
+.long .L_OP_MUL_INT_LIT8
+.long .L_OP_DIV_INT_LIT8
+.long .L_OP_REM_INT_LIT8
+.long .L_OP_AND_INT_LIT8
+.long .L_OP_OR_INT_LIT8
+.long .L_OP_XOR_INT_LIT8
+.long .L_OP_SHL_INT_LIT8
+.long .L_OP_SHR_INT_LIT8
+.long .L_OP_USHR_INT_LIT8
+.long .L_OP_IGET_VOLATILE
+.long .L_OP_IPUT_VOLATILE
+.long .L_OP_SGET_VOLATILE
+.long .L_OP_SPUT_VOLATILE
+.long .L_OP_IGET_OBJECT_VOLATILE
+.long .L_OP_IGET_WIDE_VOLATILE
+.long .L_OP_IPUT_WIDE_VOLATILE
+.long .L_OP_SGET_WIDE_VOLATILE
+.long .L_OP_SPUT_WIDE_VOLATILE
+.long .L_OP_BREAKPOINT
+.long .L_OP_THROW_VERIFICATION_ERROR
+.long .L_OP_EXECUTE_INLINE
+.long .L_OP_EXECUTE_INLINE_RANGE
+.long .L_OP_INVOKE_OBJECT_INIT_RANGE
+.long .L_OP_RETURN_VOID_BARRIER
+.long .L_OP_IGET_QUICK
+.long .L_OP_IGET_WIDE_QUICK
+.long .L_OP_IGET_OBJECT_QUICK
+.long .L_OP_IPUT_QUICK
+.long .L_OP_IPUT_WIDE_QUICK
+.long .L_OP_IPUT_OBJECT_QUICK
+.long .L_OP_INVOKE_VIRTUAL_QUICK
+.long .L_OP_INVOKE_VIRTUAL_QUICK_RANGE
+.long .L_OP_INVOKE_SUPER_QUICK
+.long .L_OP_INVOKE_SUPER_QUICK_RANGE
+.long .L_OP_IPUT_OBJECT_VOLATILE
+.long .L_OP_SGET_OBJECT_VOLATILE
+.long .L_OP_SPUT_OBJECT_VOLATILE
+.long .L_OP_DISPATCH_FF
+
+/* File: x86-atom/footer.S */
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: footer.S
+    */
+
+    .text
+    .align      2
+
+   /*
+    * Check to see if the thread needs to be suspended or debugger/profiler
+    * activity has begun.
+    *
+    * On entry:
+    *  %ecx is reentry type, e.g. kInterpEntryInstr
+    *  %edx is PC adjustment in bytes
+    */
+
+common_periodicChecks:
+    movl        %edx, -8(%esp)          # save pc adjustments
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        %ebx, -4(%esp)          # save %ebx to the stack
+    movl        offGlue_pSelfSuspendCount(%edx), %ebx # %ebx<- pSuspendCount (int)
+4:
+    movl        offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
+    testl       %eax, %eax
+    je          5f
+    movzbl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
+5:
+    cmp         $0, (%ebx)             # check if suspend is pending
+    jne         2f                      # handle suspend
+    movl        offGlue_pActiveProfilers(%edx), %ebx # %ebx<- activeProfilers (int)
+    orl         (%ebx), %eax            # %eax<- merge activeProfilers and debuggerActive
+    movl        -8(%esp), %edx          # %edx<- restore %edx
+    jne         3f                      # debugger or profiler active; switch interp
+    movl        -4(%esp), %ebx          # %ebx<- restore %ebx
+    ret                                 # return
+2:                                      # check suspended
+    EXPORT_PC
+    movl        offGlue_self(%edx), %eax # %eax<- glue->self
+    movl        %eax, -12(%esp)         # push parameter boolean
+    lea         -12(%esp), %esp
+    call        dvmCheckSuspendPending  # call: (Thread* self)
+                                        # return: bool
+    movl        4(%esp), %edx           # %edx<- restore %edx
+    movl        8(%esp), %ebx           # %ebx<- restore %ebx
+    lea         12(%esp), %esp
+    ret
+3:                                      # debugger/profiler enabled, bail out
+    leal        (rPC, %edx, 2), rPC     # adjust pc to show target
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movb        $kInterpEntryInstr, offGlue_entryPoint(%ecx)
+    movl        $1, %edx               # switch interpreter
+    jmp         common_gotoBail         # bail
+
+   /*
+    * Check to see if the thread needs to be suspended or debugger/profiler
+    * activity has begun. With this variant, the reentry type is hard coded
+    * as kInterpEntryInstr.
+    *
+    * On entry:
+    *  %edx is PC adjustment in bytes
+    */
+
+common_periodicChecks_backwardBranch:
+    EXPORT_PC
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
+4:
+    movl        offGlue_pDebuggerActive(%ecx), %eax # %eax<- pDebuggerActive
+    testl       %eax, %eax              # test for NULL pointer
+    je          5f
+    movzbl      (%eax), %eax            # %eax<- get debuggerActive count
+5:
+    cmp         $0, (rINST)            # check if suspend is pending
+    jne         2f                      # handle suspend
+    movl        offGlue_pActiveProfilers(%ecx), rINST # %edx<- activeProfilers (int)
+    orl          (rINST), %eax           # %eax<- merge activeProfilers and debuggerActive
+    jne         3f                      # debugger or profiler active; switch interp
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+2:                                      # check suspended
+    movl        offGlue_self(%ecx), %eax# %eax<- glue->self
+    movl        %edx, rINST
+    movl        %eax, -12(%esp)         # push parameter boolean
+    lea         -12(%esp), %esp
+    call        dvmCheckSuspendPending  # call: (Thread* self)
+                                        # return: bool
+    movl        rINST, %edx             # %edx<- restore %edx
+    lea         12(%esp), %esp
+    FINISH_RB   %edx, %ecx
+3:                                      # debugger/profiler enabled, bail out
+    leal        (rPC, %edx, 2), rPC     # adjust pc to show target
+    movb        $kInterpEntryInstr, offGlue_entryPoint(%ecx)
+    movl        $1, %edx               # switch interpreter
+    jmp         common_gotoBail         # bail
+
+   /*
+    * The equivalent of "goto bail", this calls through the "bail handler".
+    * State registers will be saved to the "glue" area before bailing.
+    *
+    * On entry:
+    *  %edx 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 %ecx             # save program counter and frame pointer
+
+   /*
+    * Inlined dvmMterpStdBail
+    */
+
+    lea         40(%ebp), %esp
+    movl        %edx, %eax
+    movl        24(%ebp), %edi
+    movl        28(%ebp), %esi
+    movl        32(%ebp), %ebx
+    movl        36(%ebp), %ebp
+    ret
+
+   /*
+    * Common code for method invocation with range.
+    *
+    * On entry:
+    *  %ecx is "Method* methodToCall", the method we're trying to call
+    */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+   /*
+    * prepare to copy args to "outs" area of current frame
+    */
+
+    SAVEAREA_FROM_FP %eax               # %eax<- &outs; &StackSaveArea
+    test        rINST, rINST            # test for no args
+    movl        rINST, sReg0            # sReg0<- AA
+    jz          .LinvokeArgsDone        # no args; jump to args done
+    FETCH       2, %edx                 # %edx<- CCCC
+
+   /*
+    * %ecx=methodToCall, %edx=CCCC, sReg0=count, %eax=&outs (&stackSaveArea)
+    * (very few methods have > 10 args; could unroll for common cases)
+    */
+
+    movl        %ebx, sReg1             # sReg1<- save %ebx
+    lea         (rFP, %edx, 4), %edx    # %edx<- &vCCCC
+    shll        $2, sReg0              # sReg0<- offset
+    subl        sReg0, %eax             # %eax<- update &outs
+    shrl        $2, sReg0              # sReg0<- offset
+1:
+    movl        (%edx), %ebx            # %ebx<- vCCCC
+    lea         4(%edx), %edx           # %edx<- &vCCCC++
+    subl        $1, sReg0              # sReg<- sReg--
+    movl        %ebx, (%eax)            # *outs<- vCCCC
+    lea         4(%eax), %eax           # outs++
+    jne         1b                      # loop if count (sReg0) not zero
+    movl        sReg1, %ebx             # %ebx<- restore %ebx
+    jmp         .LinvokeArgsDone        # continue
+
+   /*
+    * %ecx is "Method* methodToCall", the method we're trying to call
+    * prepare to copy args to "outs" area of current frame
+    */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+    movl        rINST, sReg0            # sReg0<- BA
+    shrl        $4, sReg0              # sReg0<- B
+    je          .LinvokeArgsDone        # no args; jump to args done
+    SAVEAREA_FROM_FP %eax               # %eax<- &outs; &StackSaveArea
+    FETCH       2, %edx                 # %edx<- GFED
+
+   /*
+    * %ecx=methodToCall, %edx=GFED, sReg0=count, %eax=outs
+    */
+
+.LinvokeNonRange:
+    cmp         $2, sReg0              # compare sReg0 to 2
+    movl        %edx, sReg1             # sReg1<- GFED
+    jl          1f                      # handle 1 arg
+    je          2f                      # handle 2 args
+    cmp         $4, sReg0              # compare sReg0 to 4
+    jl          3f                      # handle 3 args
+    je          4f                      # handle 4 args
+5:
+    andl        $15, rINST             # rINST<- A
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, rINST, 4), %edx   # %edx<- vA
+    movl        %edx, (%eax)            # *outs<- vA
+    movl        sReg1, %edx             # %edx<- GFED
+4:
+    shr         $12, %edx              # %edx<- G
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, %edx, 4), %edx    # %edx<- vG
+    movl        %edx, (%eax)            # *outs<- vG
+    movl        sReg1, %edx             # %edx<- GFED
+3:
+    and         $0x0f00, %edx          # %edx<- 0F00
+    shr         $6, %edx               # %edx<- F at correct offset
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, %edx), %edx       # %edx<- vF
+    movl        %edx, (%eax)            # *outs<- vF
+    movl        sReg1, %edx             # %edx<- GFED
+2:
+    and         $0x00f0, %edx          # %edx<- 00E0
+    shr         $2, %edx               # %edx<- E at correct offset
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, %edx), %edx       # %edx<- vE
+    movl        %edx, (%eax)            # *outs<- vE
+    movl        sReg1, %edx             # %edx<- GFED
+1:
+    and         $0x000f, %edx          # %edx<- 000D
+    movl        (rFP, %edx, 4), %edx    # %edx<- vD
+    movl        %edx, -4(%eax)          # *--outs<- vD
+0:
+
+   /*
+    * %ecx is "Method* methodToCall", the method we're trying to call
+    * find space for the new stack frame, check for overflow
+    */
+
+.LinvokeArgsDone:
+    movzwl      offMethod_registersSize(%ecx), %eax # %eax<- methodToCall->regsSize
+    movzwl      offMethod_outsSize(%ecx), %edx # %edx<- methodToCall->outsSize
+    movl        %ecx, sReg0             # sReg<- methodToCall
+    shl         $2, %eax               # %eax<- update offset
+    SAVEAREA_FROM_FP %ecx               # %ecx<- &outs; &StackSaveArea
+    subl        %eax, %ecx              # %ecx<- newFP; (old savearea - regsSize)
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %ecx, sReg1             # sReg1<- &outs
+    subl        $sizeofStackSaveArea, %ecx # %ecx<- newSaveArea (stack save area using newFP)
+    movl        offGlue_interpStackEnd(%eax), %eax # %eax<- glue->interpStackEnd
+    movl        %eax, sReg2             # sReg2<- glue->interpStackEnd
+    shl         $2, %edx               # %edx<- update offset for outsSize
+    movl        %ecx, %eax              # %eax<- newSaveArea
+    sub         %edx, %ecx              # %ecx<- bottom; (newSaveArea - outsSize)
+    cmp         sReg2, %ecx             # compare interpStackEnd and bottom
+    movl        sReg0, %ecx             # %ecx<- restore methodToCall
+    jl          .LstackOverflow         # handle frame overflow
+
+   /*
+    * set up newSaveArea
+    */
+
+#ifdef EASY_GDB
+    SAVEAREA_FROM_FP %edx               # %edx<- &outs; &StackSaveArea
+    movl        %edx, offStackSaveArea_prevSave(%eax) # newSaveArea->prevSave<- &outs
+#endif
+    movl        rFP, offStackSaveArea_prevFrame(%eax) # newSaveArea->prevFrame<- rFP
+    movl        rPC, offStackSaveArea_savedPc(%eax) # newSaveArea->savedPc<- rPC
+    testl       $ACC_NATIVE, offMethod_accessFlags(%ecx) # check for native call
+    movl        %ecx, offStackSaveArea_method(%eax) # newSaveArea->method<- method to call
+    jne         .LinvokeNative          # handle native call
+
+   /*
+    * Update "glue" values for the new method
+    * %ecx=methodToCall, sReg1=newFp
+    */
+
+    movl        offMethod_clazz(%ecx), %edx # %edx<- method->clazz
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %ecx, offGlue_method(%eax) # glue->method<- methodToCall
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    movl        offMethod_insns(%ecx), rPC # rPC<- methodToCall->insns
+    movl        %edx, offGlue_methodClassDex(%eax) # glue->methodClassDex<- method->clazz->pDvmDex
+    movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
+    movl        sReg1, rFP              # rFP<- newFP
+    movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+    FINISH_A                            # jump to methodToCall->insns
+
+   /*
+    * Prep for the native call
+    * %ecx=methodToCall, sReg1=newFP, %eax=newSaveArea
+    */
+
+.LinvokeNative:
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        %ecx, -20(%esp)         # push parameter methodToCall
+    movl        offGlue_self(%edx), %edx # %edx<- glue->self
+    movl        offThread_jniLocal_topCookie(%edx), %ecx # %ecx<- glue->self->thread->refNext
+    movl        %ecx, offStackSaveArea_localRefCookie(%eax) # newSaveArea->localRefCookie<- refNext
+    movl        %eax, -4(%esp)          # save newSaveArea
+    movl        sReg1, %eax             # %eax<- newFP
+    movl        %eax, offThread_curFrame(%edx) # glue->self->curFrame<- newFP
+    movl        %edx, -8(%esp)          # save glue->self
+    movl        %edx, -16(%esp)         # push parameter glue->self
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        -20(%esp), %ecx         # %ecx<- methodToCall
+    lea         offGlue_retval(%edx), %edx # %edx<- &retval
+    movl        %edx, -24(%esp)         # push parameter pMterpGlue
+    movl        %eax, -28(%esp)         # push parameter newFP
+    lea         -28(%esp), %esp
+
+#ifdef ASSIST_DEBUGGER
+    jmp         .Lskip
+    .type       dalvik_mterp, %function
+dalvik_mterp:
+    MTERP_ENTRY
+.Lskip:
+#endif
+    call        *offMethod_nativeFunc(%ecx) # call methodToCall->nativeFunc
+    lea         28(%esp), %esp
+    movl        -4(%esp), %edx          # %edx<- newSaveArea
+    movl        -8(%esp), %ecx          # %ecx<- glue->self
+    movl        offStackSaveArea_localRefCookie(%edx), %eax  # %eax<- newSaveArea->localRefCookie
+    FFETCH_ADV  3, %edx                 # %edx<- next instruction hi; fetch, advance
+    cmp         $0, offThread_exception(%ecx) # check for exception
+    movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
+    movl        %eax, offThread_jniLocal_topCookie(%ecx) # glue->self<- newSaveArea->localRefCookie
+    jne         common_exceptionThrown  # handle exception
+    FGETOP_JMP  3, %edx                 # jump to next instruction; getop, jmp
+
+.LstackOverflow:
+    movl        %ecx, -4(%esp)          # push method to call
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_self(%ecx), %ecx # %ecx<- glue->self
+    movl        %ecx, -8(%esp)          # push parameter self
+    lea         -8(%esp), %esp
+    call        dvmHandleStackOverflow  # call: (Thread* self, Method *meth)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+#ifdef ASSIST_DEBUGGER
+#endif
+
+   /*
+    * Common code for handling a return instruction.
+    *
+    * This does not return.
+    */
+
+common_returnFromMethod:
+.LreturnNew:
+
+   /*
+    * Inline common periodic checks
+    */
+
+    movl        rGLUE, rINST            # %ecx<- pMterpGlue
+    movl        offGlue_pSelfSuspendCount(rINST), %edx # %ebx<- pSuspendCount (int)
+    movl        offGlue_pDebuggerActive(rINST), %eax # %eax<- pDebuggerActive
+    movl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
+    and         $7, %eax               # %eax<- mask for boolean (just how many bits does it take?)
+    cmp         $0, (%edx)             # check if suspend is pending
+    jne         2f                      # handle suspend
+    movl        offGlue_pActiveProfilers(rINST), %edx # %edx<- activeProfilers (int)
+    or          (%edx), %eax            # %eax<- merge activeProfilers and debuggerActive
+    cmp         $0, %eax               # check for debuggerActive
+    jne         3f                      # debugger or profiler active; switch interp
+    jmp         4f
+2:                                      # check suspended
+    movl        offGlue_self(rINST), %eax# %eax<- glue->self
+    movl        %eax, -12(%esp)         # push parameter boolean
+    lea         -12(%esp), %esp
+    call        dvmCheckSuspendPending  # call: (Thread* self)
+                                        # return: bool
+    lea         12(%esp), %esp
+    jmp         4f
+3:                                      # debugger/profiler enabled, bail out
+    movl        $kInterpEntryInstr, offGlue_entryPoint(rINST) # glue->entryPoint<- reentry type
+    movl        $1, %edx               # switch to interp<- true
+    jmp         common_gotoBail         # bail
+
+
+   /*
+    * Get save area; rGLUE is %ebx, rFP is %eax
+    */
+4:
+    SAVEAREA_FROM_FP %ecx               # %ecx<- saveArea(old)
+    movl        offStackSaveArea_prevFrame(%ecx), rFP # rFP<- saveArea->PrevFrame
+    movl        (offStackSaveArea_method - sizeofStackSaveArea)(rFP), %edx # %edx<- method we are returning to
+    cmpl        $0, %edx               # check for break frame
+    je          common_gotoBail         # bail if break frame
+    movl        offStackSaveArea_savedPc(%ecx), rPC # rPC<- saveAreaOld->savedPc
+    movl        offGlue_self(rINST), %ecx # %eax<- glue->self
+    movl        %edx, offGlue_method(rINST) # glue->method<- newSave->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    FFETCH_ADV  3, %eax                 # %ecx<- next instruction hi; fetch, advance
+    movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    movl        %edx, offGlue_methodClassDex(rINST) # glue->pDvmDex<- method->clazz->pDvmDex
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+   /*
+    * Handle thrown an exception. 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.
+    */
+
+common_exceptionThrown:
+.LexceptionNew:
+    movl        $kInterpEntryThrow, %ecx # %ecx<- reentry type
+    movl        $0, %edx               # %edx<- pc adjustment
+    call        common_periodicChecks
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_self(%eax), %edx # %edx<- glue->self
+    movl        offThread_exception(%edx), %ecx # %ecx<- pMterpGlue->self->exception
+    movl        %edx, -4(%esp)          # push parameter self
+    movl        %ecx, -8(%esp)          # push parameter obj
+    lea         -8(%esp), %esp
+    call        dvmAddTrackedAlloc      # don't allow the exception to be GC'd
+                                        # call: (Object* obj, Thread* self)
+                                        # return: void
+    movl        4(%esp), %edx           # %edx<- glue->self
+    movl        $0, offThread_exception(%edx) # glue->self->exception<- NULL
+
+   /*
+    * set up args and a local for &fp
+    */
+
+    movl        rFP, -4(%esp)           # move fp to stack
+    lea         -4(%esp), %esp          # update %esp
+    movl        %esp, -4(%esp)          # push parameter 4<- &fp
+    movl        $0, -8(%esp)           # push parameter 3<- false
+    movl        4(%esp), %edx
+    movl        %edx, -12(%esp)         # push parameter 2<- glue->self->exception
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %edx # %edx<- glue->method
+    movl        offMethod_insns(%edx), %edx # %edx<- glue->method->insns
+    movl        rPC, %ecx               # %ecx<- rPC
+    subl        %edx, %ecx              # %ecx<- pc - glue->method->insns
+    sar         $1, %ecx               # %ecx<- adjust %ecx for offset
+    movl        %ecx, -16(%esp)         # push parameter 1<- glue->method->insns
+    movl        8(%esp), %edx
+    movl        %edx, -20(%esp)         # push parameter 0<- glue->self
+    lea         -20(%esp), %esp
+
+   /*
+    * call dvmFindCatchBlock, %eax gets catchRelPc (a code-unit offset)
+    */
+
+    call        dvmFindCatchBlock       # call: (Thread* self, int relPc, Object* exception,
+                                        #      bool doUnroll, void** newFrame)
+                                        # return: int
+    lea         32(%esp), %esp
+    movl        -12(%esp), rFP          # rFP<- updated rFP
+    cmp         $0, %eax               # check for catchRelPc < 0
+    jl          .LnotCaughtLocally      # handle not caught locally
+
+   /*
+    * fix stack overflow if necessary
+    */
+
+    movl        -4(%esp), %ecx          # %ecx<- glue->self
+    cmp         $0, offThread_stackOverflowed(%ecx)
+    je          1f
+    movl        %eax, -4(%esp)          # save %eax for later
+    movl        %ecx, -12(%esp)         # push parameter 2 glue->self
+    lea         -12(%esp), %esp
+    call        dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
+                                        # return: void
+    lea         12(%esp), %esp
+    movl        -4(%esp), %eax          # %eax<- restore %eax
+    jmp         2f
+1:
+    movl        %ecx, -12(%esp)         # push parameter 2 glue->self
+2:
+
+   /*
+    * adjust locals to match self->curFrame and updated PC
+    *
+    */
+
+    SAVEAREA_FROM_FP %edx               # %edx<- get newSaveArea
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offStackSaveArea_method(%edx), rPC # rPC<- newMethod
+    movl        rPC, offGlue_method(%ecx) # glue->method<- newMethod
+    movl        offMethod_clazz(rPC), %edx # %edx<- method->clazz
+    movl        offMethod_insns(rPC), rPC # rPC<- method->insns
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    lea         (rPC, %eax, 2), rPC     # rPC<- method->insns + catchRelPc
+    movl        %edx, offGlue_methodClassDex(%ecx) # glue->pDvmDex<- method->clazz->pDvmDex
+    movl        -8(%esp), %eax
+    movl        %eax, -16(%esp)         # push parameter 1 obj
+    lea         -16(%esp), %esp
+    call        dvmReleaseTrackedAlloc  # call: (Object* obj, Thread* self)
+                                        # return: void
+    lea         16(%esp), %esp
+    FINISH_FETCH %eax
+    cmp         $OP_MOVE_EXCEPTION, %eax # is it a move exception
+    jne         1f
+    movl        -12(%esp), %edx         # %edx<- glue->self
+    movl        -8(%esp), %ecx          # %ecx<- exception
+    movl        %ecx, offThread_exception(%edx) # restore the exception
+1:
+    FINISH_JMP  %eax
+
+   /*
+    * -8(%esp) = exception, -4(%esp) = self
+    */
+
+.LnotCaughtLocally:
+    movl        -4(%esp), %edx          # %edx<- glue->self
+    movzb       offThread_stackOverflowed(%edx), %eax # %eax<- self->stackOverflowed
+    cmp         $0, %eax               # check for stack overflow;
+                                        # maybe should use cmpb
+    je          1f                      #
+    movl        %edx, -12(%esp)         # push parameter 1 glue->self
+    lea         -12(%esp), %esp
+    call        dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
+                                        # return: void
+    lea         12(%esp), %esp
+
+   /*
+    * Release the exception
+    * -8(%esp) = exception, -4(%esp) = self
+    */
+1:
+    movl        -8(%esp), %ecx          # %ecx<- exception
+    movl        -4(%esp), %edx          # %edx<- glue->self
+    movl        %ecx, offThread_exception(%edx) # glue->self<- exception
+    lea         -8(%esp), %esp
+    call        dvmReleaseTrackedAlloc  # call: (Object* obj, Thread* self)
+                                        # return: void
+    lea         8(%esp), %esp
+    movl        $0, %edx               # switch to interp<- false
+    jmp         common_gotoBail         # bail
+
+   /*
+    * 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
+    FINISH_A                            # jump to next instruction
+
+   /*
+    * For debugging, cause an immediate fault.
+    */
+
+common_abort:
+    jmp         .LdeadFood
+
+.LdeadFood:
+.int 0xdeadf00d
+
+   /*
+    * Invalid array index.
+    */
+
+common_errArrayIndex:
+    EXPORT_PC
+    movl        $.LstrArrayIndexException, -8(%esp) # push parameter description
+    movl        $0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Invalid array value.
+    */
+
+common_errArrayStore:
+    EXPORT_PC
+    movl        $.LstrArrayStoreException, -8(%esp) # push parameter description
+    movl        $0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Integer divide or mod by zero.
+    */
+
+common_errDivideByZero:
+    EXPORT_PC
+    movl        $.LstrArithmeticException, -8(%esp) # push parameter description
+    movl        $.LstrDivideByZero, -4(%esp) # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Attempt to allocate an array with a negative size.
+    */
+
+common_errNegativeArraySize:
+    EXPORT_PC
+    movl        $.LstrNegativeArraySizeException, -8(%esp) # push parameter description
+    movl        $0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Invocation of a non-existent method.
+    */
+
+common_errNoSuchMethod:
+    EXPORT_PC
+    movl        $.LstrNoSuchMethodError, -8(%esp) # push parameter description
+    movl        $0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Unexpected null object.
+    */
+
+common_errNullObject:
+    EXPORT_PC
+    movl        $.LstrNullPointerException, -8(%esp) # push parameter description
+    movl        $0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * String references
+    */
+
+    .align 4
+    .section .rodata
+.LstrArithmeticException:
+    .asciz "Ljava/lang/ArithmeticException;"
+.LstrArrayIndexException:
+    .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
+.LstrArrayStoreException:
+    .asciz "Ljava/lang/ArrayStoreException;"
+.LstrDivideByZero:
+    .asciz "divide by zero"
+.LstrInstantiationError:
+    .asciz "Ljava/lang/InstantiationError;"
+.LstrNegativeArraySizeException:
+    .asciz "Ljava/lang/NegativeArraySizeException;"
+.LstrNoSuchMethodError:
+    .asciz "Ljava/lang/NoSuchMethodError;"
+.LstrNullPointerException:
+    .asciz "Ljava/lang/NullPointerException;"
+.LstrExceptionNotCaughtLocally:
+    .asciz "Exception %s from %s:%d not caught locally\n"
+
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
new file mode 100644
index 0000000..41b261c
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -0,0 +1,26563 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'x86'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: x86/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.
+ */
+/*
+ * 32-bit x86 definitions and declarations.
+ */
+
+/*
+386 ABI general notes:
+
+Caller save set:
+   eax, edx, ecx, st(0)-st(7)
+Callee save set:
+   ebx, esi, edi, ebp
+Return regs:
+   32-bit in eax
+   64-bit in edx:eax (low-order 32 in eax)
+   fp on top of fp stack st(0)
+
+Parameters passed on stack, pushed right-to-left.  On entry to target, first
+parm is at 4(%esp).  Traditional entry code is:
+
+functEntry:
+    push    %ebp             # save old frame pointer
+    mov     %ebp,%esp        # establish new frame pointer
+    sub     FrameSize,%esp   # Allocate storage for spill, locals & outs
+
+Once past the prologue, arguments are referenced at ((argno + 2)*4)(%ebp)
+
+Stack must be 16-byte aligned to support SSE in native code.
+
+If we're not doing variable stack allocation (alloca), the frame pointer can be
+eliminated and all arg references adjusted to be esp relative.
+
+Mterp notes:
+
+Some key interpreter variables will be assigned to registers.  Note that each
+will also have an associated spill location (mostly useful for those assigned
+to callee save registers).
+
+  nick     reg   purpose
+  rPC      edi   interpreted program counter, used for fetching instructions
+  rFP      esi   interpreted frame pointer, used for accessing locals and args
+  rINSTw   bx    first 16-bit code of current instruction
+  rINSTbl  bl    opcode portion of instruction word
+  rINSTbh  bh    high byte of inst word, usually contains src/tgt reg names
+  rIBASE   edx   base of instruction handler table
+
+Notes:
+   o High order 16 bits of ebx must be zero on entry to handler
+   o rPC, rFP, rINSTw/rINSTbl valid on handler entry and exit
+   o eax and ecx are scratch, rINSTw/ebx sometimes scratch
+
+*/
+
+#define rSELF    8(%ebp)
+#define rPC      %esi
+#define rFP      %edi
+#define rINST    %ebx
+#define rINSTw   %bx
+#define rINSTbh  %bh
+#define rINSTbl  %bl
+#define rIBASE   %edx
+
+
+/* Frame diagram while executing dvmMterpStdRun, high to low addresses */
+#define IN_ARG0        (  8)
+#define CALLER_RP      (  4)
+#define PREV_FP        (  0)
+/* Spill offsets relative to %ebp */
+#define EDI_SPILL      ( -4)
+#define ESI_SPILL      ( -8)
+#define EBX_SPILL      (-12)
+#define rPC_SPILL      (-16)
+#define rFP_SPILL      (-20)
+#define rINST_SPILL    (-24)
+#define rIBASE_SPILL   (-28)
+#define TMP_SPILL1     (-32)
+#define TMP_SPILL2     (-36)
+#define TMP_SPILL3     (-20)
+#define LOCAL0_OFFSET  (-44)
+#define LOCAL1_OFFSET  (-48)
+#define LOCAL2_OFFSET  (-52)
+/* Out Arg offsets, relative to %esp */
+#define OUT_ARG4       ( 16)
+#define OUT_ARG3       ( 12)
+#define OUT_ARG2       (  8)
+#define OUT_ARG1       (  4)
+#define OUT_ARG0       (  0)  /* <- dvmMterpStdRun esp */
+#define FRAME_SIZE     76
+
+#define SPILL(reg) movl reg##,reg##_SPILL(%ebp)
+#define UNSPILL(reg) movl reg##_SPILL(%ebp),reg
+#define SPILL_TMP1(reg) movl reg,TMP_SPILL1(%ebp)
+#define UNSPILL_TMP1(reg) movl TMP_SPILL1(%ebp),reg
+#define SPILL_TMP2(reg) movl reg,TMP_SPILL2(%ebp)
+#define UNSPILL_TMP2(reg) movl TMP_SPILL2(%ebp),reg
+#define SPILL_TMP3(reg) movl reg,TMP_SPILL3(%ebp)
+#define UNSPILL_TMP3(reg) movl TMP_SPILL3(%ebp),reg
+
+#if defined(WITH_JIT)
+.macro GET_JIT_PROF_TABLE _self _reg
+    movl    offThread_pJitProfTable(\_self),\_reg
+.endm
+.macro GET_JIT_THRESHOLD _self _reg
+    movl    offThread_jitThreshold(\_self),\_reg
+.endm
+#endif
+
+/* save/restore the PC and/or FP from the self struct */
+.macro SAVE_PC_FP_TO_SELF _reg
+    movl     rSELF,\_reg
+    movl     rPC,offThread_pc(\_reg)
+    movl     rFP,offThread_curFrame(\_reg)
+.endm
+
+.macro LOAD_PC_FP_FROM_SELF
+    movl    rSELF,rFP
+    movl    offThread_pc(rFP),rPC
+    movl    offThread_curFrame(rFP),rFP
+.endm
+
+/* The interpreter assumes a properly aligned stack on entry, and
+ * will preserve 16-byte alignment.
+ */
+
+/*
+ * "export" the PC to the interpreted stack frame, f/b/o future exception
+ * objects.  Must be done *before* something throws.
+ *
+ * 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.
+ */
+.macro EXPORT_PC
+    movl     rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
+.endm
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+.macro SAVEAREA_FROM_FP _reg
+    leal    -sizeofStackSaveArea(rFP), \_reg
+.endm
+
+/*
+ * Fetch the next instruction from rPC into rINSTw.  Does not advance rPC.
+ */
+.macro FETCH_INST
+    movzwl    (rPC),rINST
+.endm
+
+/*
+ * Fetch the opcode byte and zero-extend it into _reg.  Must be used
+ * in conjunction with GOTO_NEXT_R
+ */
+.macro FETCH_INST_R _reg
+    movzbl    (rPC),\_reg
+.endm
+
+/*
+ * Fetch the opcode byte at _count words offset from rPC and zero-extend
+ * it into _reg.  Must be used in conjunction with GOTO_NEXT_R
+ */
+.macro FETCH_INST_OPCODE _count _reg
+    movzbl  \_count*2(rPC),\_reg
+.endm
+
+/*
+ * Fetch the nth instruction word from rPC into rINSTw.  Does not advance
+ * rPC, and _count is in words
+ */
+.macro FETCH_INST_WORD _count
+    movzwl  \_count*2(rPC),rINST
+.endm
+
+/*
+ * Fetch instruction word indexed (used for branching).
+ * Index is in instruction word units.
+ */
+.macro FETCH_INST_INDEXED _reg
+    movzwl  (rPC,\_reg,2),rINST
+.endm
+
+/*
+ * Advance rPC by instruction count
+ */
+.macro ADVANCE_PC _count
+    leal  2*\_count(rPC),rPC
+.endm
+
+/*
+ * Advance rPC by branch offset in register
+ */
+.macro ADVANCE_PC_INDEXED _reg
+    leal (rPC,\_reg,2),rPC
+.endm
+
+.macro GOTO_NEXT
+     movzx   rINSTbl,%eax
+     movzbl  rINSTbh,rINST
+     jmp     *(rIBASE,%eax,4)
+.endm
+
+   /*
+    * Version of GOTO_NEXT that assumes _reg preloaded with opcode.
+    * Should be paired with FETCH_INST_R
+    */
+.macro GOTO_NEXT_R _reg
+     movzbl  1(rPC),rINST
+     jmp     *(rIBASE,\_reg,4)
+.endm
+
+   /*
+    * Jumbo version of GOTO_NEXT that assumes _reg preloaded with table
+    * offset of the jumbo instruction, which is the top half of the extended
+    * opcode + 0x100.  Loads rINST with BBBB field, similar to GOTO_NEXT_R
+    */
+.macro GOTO_NEXT_JUMBO_R _reg
+     movzwl  6(rPC),rINST
+     jmp     *(rIBASE,\_reg,4)
+.endm
+
+/*
+ * Get/set the 32-bit value from a Dalvik register.
+ */
+.macro GET_VREG_R _reg _vreg
+    movl     (rFP,\_vreg,4),\_reg
+.endm
+
+.macro SET_VREG _reg _vreg
+    movl     \_reg,(rFP,\_vreg,4)
+.endm
+
+.macro GET_VREG_WORD _reg _vreg _offset
+    movl     4*(\_offset)(rFP,\_vreg,4),\_reg
+.endm
+
+.macro SET_VREG_WORD _reg _vreg _offset
+    movl     \_reg,4*(\_offset)(rFP,\_vreg,4)
+.endm
+
+#define sReg0 LOCAL0_OFFSET(%ebp)
+#define sReg1 LOCAL1_OFFSET(%ebp)
+#define sReg2 LOCAL2_OFFSET(%ebp)
+
+   /*
+    * Hard coded helper values.
+    */
+
+.balign 16
+
+.LdoubNeg:
+    .quad       0x8000000000000000
+
+.L64bits:
+    .quad       0xFFFFFFFFFFFFFFFF
+
+.LshiftMask2:
+    .quad       0x0000000000000000
+.LshiftMask:
+    .quad       0x000000000000003F
+
+.Lvalue64:
+    .quad       0x0000000000000040
+
+.LvaluePosInfLong:
+    .quad       0x7FFFFFFFFFFFFFFF
+
+.LvalueNegInfLong:
+    .quad       0x8000000000000000
+
+.LvalueNanLong:
+    .quad       0x0000000000000000
+
+.LintMin:
+.long   0x80000000
+
+.LintMax:
+.long   0x7FFFFFFF
+
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+
+    .global dvmAsmInstructionStartCode
+    .type   dvmAsmInstructionStartCode, %function
+dvmAsmInstructionStartCode = .L_OP_NOP
+    .text
+
+/* ------------------------------ */
+.L_OP_NOP: /* 0x00 */
+/* File: x86/OP_NOP.S */
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE: /* 0x01 */
+/* File: x86/OP_MOVE.S */
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    movzbl rINSTbl,%eax          # eax<- BA
+    andb   $0xf,%al             # eax<- A
+    shrl   $4,rINST            # rINST<- B
+    GET_VREG_R rINST rINST
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG rINST %eax           # fp[A]<-fp[B]
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_FROM16: /* 0x02 */
+/* File: x86/OP_MOVE_FROM16.S */
+    /* for: move/from16, move-object/from16 */
+    /* op vAA, vBBBB */
+    movzx    rINSTbl,%eax              # eax <= AA
+    movw     2(rPC),rINSTw             # rINSTw <= BBBB
+    GET_VREG_R rINST rINST             # rINST- fp[BBBB]
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG rINST %eax                # fp[AA]<- ecx]
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_16: /* 0x03 */
+/* File: x86/OP_MOVE_16.S */
+    /* for: move/16, move-object/16 */
+    /* op vAAAA, vBBBB */
+    movzwl    4(rPC),%ecx              # ecx<- BBBB
+    movzwl    2(rPC),%eax              # eax<- AAAA
+    GET_VREG_R  rINST %ecx
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    SET_VREG  rINST %eax
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_WIDE: /* 0x04 */
+/* File: x86/OP_MOVE_WIDE.S */
+    /* move-wide vA, vB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    movzbl    rINSTbl,%ecx                # ecx <- BA
+    sarl      $4,rINST                   # rINST<- B
+    GET_VREG_WORD %eax rINST 0            # eax<- v[B+0]
+    GET_VREG_WORD rINST rINST 1           # rINST<- v[B+1]
+    andb      $0xf,%cl                   # ecx <- A
+    SET_VREG_WORD rINST %ecx 1            # v[A+1]<- rINST
+    SET_VREG_WORD %eax %ecx 0             # v[A+0]<- eax
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: x86/OP_MOVE_WIDE_FROM16.S */
+    /* move-wide/from16 vAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    movzwl    2(rPC),%ecx              # ecx<- BBBB
+    movzbl    rINSTbl,%eax             # eax<- AAAA
+    GET_VREG_WORD rINST %ecx 0         # rINST<- v[BBBB+0]
+    GET_VREG_WORD %ecx %ecx 1          # ecx<- v[BBBB+1]
+    SET_VREG_WORD rINST %eax 0         # v[AAAA+0]<- rINST
+    SET_VREG_WORD %ecx %eax 1          # v[AAAA+1]<- eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: x86/OP_MOVE_WIDE_16.S */
+    /* move-wide/16 vAAAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    movzwl    4(rPC),%ecx            # ecx<- BBBB
+    movzwl    2(rPC),%eax            # eax<- AAAA
+    GET_VREG_WORD rINST %ecx 0       # rINSTw_WORD<- v[BBBB+0]
+    GET_VREG_WORD %ecx %ecx 1        # ecx<- v[BBBB+1]
+    SET_VREG_WORD rINST %eax 0       # v[AAAA+0]<- rINST
+    SET_VREG_WORD %ecx %eax 1        # v[AAAA+1]<- ecx
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_OBJECT: /* 0x07 */
+/* File: x86/OP_MOVE_OBJECT.S */
+/* File: x86/OP_MOVE.S */
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    movzbl rINSTbl,%eax          # eax<- BA
+    andb   $0xf,%al             # eax<- A
+    shrl   $4,rINST            # rINST<- B
+    GET_VREG_R rINST rINST
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG rINST %eax           # fp[A]<-fp[B]
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: x86/OP_MOVE_OBJECT_FROM16.S */
+/* File: x86/OP_MOVE_FROM16.S */
+    /* for: move/from16, move-object/from16 */
+    /* op vAA, vBBBB */
+    movzx    rINSTbl,%eax              # eax <= AA
+    movw     2(rPC),rINSTw             # rINSTw <= BBBB
+    GET_VREG_R rINST rINST             # rINST- fp[BBBB]
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG rINST %eax                # fp[AA]<- ecx]
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: x86/OP_MOVE_OBJECT_16.S */
+/* File: x86/OP_MOVE_16.S */
+    /* for: move/16, move-object/16 */
+    /* op vAAAA, vBBBB */
+    movzwl    4(rPC),%ecx              # ecx<- BBBB
+    movzwl    2(rPC),%eax              # eax<- AAAA
+    GET_VREG_R  rINST %ecx
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    SET_VREG  rINST %eax
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MOVE_RESULT: /* 0x0a */
+/* File: x86/OP_MOVE_RESULT.S */
+    /* for: move-result, move-result-object */
+    /* op vAA */
+    movl     rSELF,%eax                    # eax<- rSELF
+    movl     offThread_retval(%eax),%eax   # eax<- self->retval.l
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG  %eax rINST                   # fp[AA]<- retval.l
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: x86/OP_MOVE_RESULT_WIDE.S */
+    /* move-result-wide vAA */
+    movl    rSELF,%ecx
+    movl    offThread_retval(%ecx),%eax
+    movl    4+offThread_retval(%ecx),%ecx
+    SET_VREG_WORD %eax rINST 0     # v[AA+0] <- eax
+    SET_VREG_WORD %ecx rINST 1     # v[AA+1] <- ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: x86/OP_MOVE_RESULT_OBJECT.S */
+/* File: x86/OP_MOVE_RESULT.S */
+    /* for: move-result, move-result-object */
+    /* op vAA */
+    movl     rSELF,%eax                    # eax<- rSELF
+    movl     offThread_retval(%eax),%eax   # eax<- self->retval.l
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG  %eax rINST                   # fp[AA]<- retval.l
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: x86/OP_MOVE_EXCEPTION.S */
+    /* move-exception vAA */
+    movl    rSELF,%ecx
+    movl    offThread_exception(%ecx),%eax # eax<- dvmGetException bypass
+    SET_VREG %eax rINST                # fp[AA]<- exception object
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    movl    $0,offThread_exception(%ecx) # dvmClearException bypass
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_RETURN_VOID: /* 0x0e */
+/* File: x86/OP_RETURN_VOID.S */
+    jmp       common_returnFromMethod
+
+/* ------------------------------ */
+.L_OP_RETURN: /* 0x0f */
+/* File: x86/OP_RETURN.S */
+    /*
+     * Return a 32-bit value.  Copies the return value into the "self"
+     * structure, then jumps to the return handler.
+     *
+     * for: return, return-object
+     */
+    /* op vAA */
+    movl    rSELF,%ecx
+    GET_VREG_R %eax rINST               # eax<- vAA
+    movl    %eax,offThread_retval(%ecx)   # retval.i <- AA
+    jmp     common_returnFromMethod
+
+/* ------------------------------ */
+.L_OP_RETURN_WIDE: /* 0x10 */
+/* File: x86/OP_RETURN_WIDE.S */
+    /*
+     * Return a 64-bit value.  Copies the return value into the "self"
+     * structure, then jumps to the return handler.
+     */
+    /* return-wide vAA */
+    movl    rSELF,%ecx
+    GET_VREG_WORD %eax rINST 0       # eax<- v[AA+0]
+    GET_VREG_WORD rINST rINST 1      # rINST<- v[AA+1]
+    movl    %eax,offThread_retval(%ecx)
+    movl    rINST,4+offThread_retval(%ecx)
+    jmp     common_returnFromMethod
+
+/* ------------------------------ */
+.L_OP_RETURN_OBJECT: /* 0x11 */
+/* File: x86/OP_RETURN_OBJECT.S */
+/* File: x86/OP_RETURN.S */
+    /*
+     * Return a 32-bit value.  Copies the return value into the "self"
+     * structure, then jumps to the return handler.
+     *
+     * for: return, return-object
+     */
+    /* op vAA */
+    movl    rSELF,%ecx
+    GET_VREG_R %eax rINST               # eax<- vAA
+    movl    %eax,offThread_retval(%ecx)   # retval.i <- AA
+    jmp     common_returnFromMethod
+
+
+/* ------------------------------ */
+.L_OP_CONST_4: /* 0x12 */
+/* File: x86/OP_CONST_4.S */
+    /* const/4 vA, #+B */
+    movsx   rINSTbl,%eax              # eax<-ssssssBx
+    movl    $0xf,rINST
+    andl    %eax,rINST                # rINST<- A
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    sarl    $4,%eax
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_16: /* 0x13 */
+/* File: x86/OP_CONST_16.S */
+    /* const/16 vAA, #+BBBB */
+    movswl  2(rPC),%ecx                # ecx<- ssssBBBB
+    FETCH_INST_OPCODE 2 %eax
+    ADVANCE_PC 2
+    SET_VREG %ecx rINST                # vAA<- ssssBBBB
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_CONST: /* 0x14 */
+/* File: x86/OP_CONST.S */
+    /* const vAA, #+BBBBbbbb */
+    movl      2(rPC),%eax             # grab all 32 bits at once
+    movl      rINST,rINST             # rINST<- AA
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    SET_VREG %eax rINST               # vAA<- eax
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_HIGH16: /* 0x15 */
+/* File: x86/OP_CONST_HIGH16.S */
+    /* const/high16 vAA, #+BBBB0000 */
+    movzwl     2(rPC),%eax                # eax<- 0000BBBB
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    sall       $16,%eax                  # eax<- BBBB0000
+    SET_VREG %eax rINST                   # vAA<- eax
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_WIDE_16: /* 0x16 */
+/* File: x86/OP_CONST_WIDE_16.S */
+    /* const-wide/16 vAA, #+BBBB */
+    movswl    2(rPC),%eax               # eax<- ssssBBBB
+    SPILL(rIBASE)                       # preserve rIBASE (cltd trashes it)
+    cltd                                # rIBASE:eax<- ssssssssssssBBBB
+    SET_VREG_WORD rIBASE rINST 1        # store msw
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 0          # store lsw
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_WIDE_32: /* 0x17 */
+/* File: x86/OP_CONST_WIDE_32.S */
+    /* const-wide/32 vAA, #+BBBBbbbb */
+    movl     2(rPC),%eax                # eax<- BBBBbbbb
+    SPILL(rIBASE)                       # save rIBASE (cltd trashes it)
+    cltd                                # rIBASE:eax<- ssssssssssssBBBB
+    SET_VREG_WORD rIBASE rINST,1        # store msw
+    FETCH_INST_OPCODE 3 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 0          # store lsw
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_WIDE: /* 0x18 */
+/* File: x86/OP_CONST_WIDE.S */
+    /* const-wide vAA, #+HHHHhhhhBBBBbbbb */
+    movl      2(rPC),%eax         # eax<- lsw
+    movzbl    rINSTbl,%ecx        # ecx<- AA
+    movl      6(rPC),rINST        # rINST<- msw
+    leal      (rFP,%ecx,4),%ecx   # dst addr
+    movl      rINST,4(%ecx)
+    movl      %eax,(%ecx)
+    FETCH_INST_OPCODE 5 %ecx
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: x86/OP_CONST_WIDE_HIGH16.S */
+    /* const-wide/high16 vAA, #+BBBB000000000000 */
+    movzwl     2(rPC),%eax                # eax<- 0000BBBB
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    sall       $16,%eax                  # eax<- BBBB0000
+    SET_VREG_WORD %eax rINST 1            # v[AA+1]<- eax
+    xorl       %eax,%eax
+    SET_VREG_WORD %eax rINST 0            # v[AA+0]<- eax
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_STRING: /* 0x1a */
+/* File: x86/OP_CONST_STRING.S */
+
+    /* const/string vAA, String@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResStrings(%ecx),%ecx # ecx<- dvmDex->pResStrings
+    movl      (%ecx,%eax,4),%eax       # eax<- rResString[BBBB]
+    FETCH_INST_OPCODE 2 %ecx
+    testl     %eax,%eax                # resolved yet?
+    je        .LOP_CONST_STRING_resolve
+    SET_VREG  %eax rINST               # vAA<- rResString[BBBB]
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.LOP_CONST_STRING_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movzwl   2(rPC),%ecx               # ecx<- BBBB
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveString          # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: x86/OP_CONST_STRING_JUMBO.S */
+
+    /* const/string vAA, String@BBBBBBBB */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax              # eax<- BBBBBBBB
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResStrings(%ecx),%ecx # ecx<- dvmDex->pResStrings
+    movl      (%ecx,%eax,4),%eax       # eax<- rResString[BBBB]
+    FETCH_INST_OPCODE 3 %ecx
+    testl     %eax,%eax                # resolved yet?
+    je        .LOP_CONST_STRING_JUMBO_resolve
+    SET_VREG  %eax rINST               # vAA<- rResString[BBBB]
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.LOP_CONST_STRING_JUMBO_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movl     2(rPC),%ecx               # ecx<- BBBBBBBB
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveString          # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 3 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_CLASS: /* 0x1c */
+/* File: x86/OP_CONST_CLASS.S */
+
+    /* const/class vAA, Class@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- dvmDex->pResClasses
+    movl      (%ecx,%eax,4),%eax       # eax<- rResClasses[BBBB]
+    testl     %eax,%eax                # resolved yet?
+    je        .LOP_CONST_CLASS_resolve
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST               # vAA<- rResClasses[BBBB]
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.LOP_CONST_CLASS_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movl     $1,OUT_ARG2(%esp)        # true
+    movzwl   2(rPC),%ecx               # ecx<- BBBB
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveClass           # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MONITOR_ENTER: /* 0x1d */
+/* File: x86/OP_MONITOR_ENTER.S */
+    /*
+     * Synchronize on an object.
+     */
+    /* monitor-enter vAA */
+    movl    rSELF,%ecx
+    GET_VREG_R %eax rINST               # eax<- vAA
+    FETCH_INST_WORD 1
+    testl   %eax,%eax                   # null object?
+    EXPORT_PC                           # need for precise GC
+    je     common_errNullObject
+    movl    %ecx,OUT_ARG0(%esp)
+    movl    %eax,OUT_ARG1(%esp)
+    SPILL(rIBASE)
+    call    dvmLockObject               # dvmLockObject(self,object)
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_MONITOR_EXIT: /* 0x1e */
+/* File: x86/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 */
+    GET_VREG_R %eax rINST
+    movl    rSELF,%ecx
+    EXPORT_PC
+    testl   %eax,%eax                   # null object?
+    je      .LOP_MONITOR_EXIT_errNullObject   # go if so
+    movl    %eax,OUT_ARG1(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call    dvmUnlockObject             # unlock(self,obj)
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    testl   %eax,%eax                   # success?
+    ADVANCE_PC 1
+    je      common_exceptionThrown      # no, exception pending
+    GOTO_NEXT_R %ecx
+.LOP_MONITOR_EXIT_errNullObject:
+    ADVANCE_PC 1                        # advance before throw
+    jmp     common_errNullObject
+
+/* ------------------------------ */
+.L_OP_CHECK_CAST: /* 0x1f */
+/* File: x86/OP_CHECK_CAST.S */
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast vAA, class@BBBB */
+    movl      rSELF,%ecx
+    GET_VREG_R  rINST,rINST             # rINST<- vAA (object)
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    testl     rINST,rINST               # is oject null?
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    je        .LOP_CHECK_CAST_okay          # null obj, cast always succeeds
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved class
+    movl      offObject_clazz(rINST),%ecx # ecx<- obj->clazz
+    testl     %eax,%eax                 # have we resolved this before?
+    je        .LOP_CHECK_CAST_resolve       # no, go do it now
+.LOP_CHECK_CAST_resolved:
+    cmpl      %eax,%ecx                 # same class (trivial success)?
+    jne       .LOP_CHECK_CAST_fullcheck     # no, do full check
+.LOP_CHECK_CAST_okay:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  ecx holds obj->clazz
+     *  eax holds class resolved from BBBB
+     *  rINST holds object
+     */
+.LOP_CHECK_CAST_fullcheck:
+    movl    %eax,sReg0                 # we'll need the desired class on failure
+    movl    %eax,OUT_ARG1(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call    dvmInstanceofNonTrivial    # eax<- boolean result
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # failed?
+    jne     .LOP_CHECK_CAST_okay           # no, success
+
+    # A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC
+    movl    offObject_clazz(rINST),%eax
+    movl    %eax,OUT_ARG0(%esp)                 # arg0<- obj->clazz
+    movl    sReg0,%ecx
+    movl    %ecx,OUT_ARG1(%esp)                 # arg1<- desired class
+    call    dvmThrowClassCastException
+    jmp     common_exceptionThrown
+
+    /*
+     * Resolution required.  This is the least-likely path, and we're
+     * going to have to recreate some data.
+     *
+     *  rINST holds object
+     */
+.LOP_CHECK_CAST_resolve:
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movzwl  2(rPC),%eax                # eax<- BBBB
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)        # arg1<- BBBB
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- metho->clazz
+    movl    $0,OUT_ARG2(%esp)         # arg2<- false
+    movl    %ecx,OUT_ARG0(%esp)        # arg0<- method->clazz
+    SPILL(rIBASE)
+    call    dvmResolveClass            # eax<- resolved ClassObject ptr
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # got null?
+    je      common_exceptionThrown     # yes, handle exception
+    movl    offObject_clazz(rINST),%ecx  # ecx<- obj->clazz
+    jmp     .LOP_CHECK_CAST_resolved       # pick up where we left off
+
+/* ------------------------------ */
+.L_OP_INSTANCE_OF: /* 0x20 */
+/* File: x86/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 */
+    movl    rINST,%eax                  # eax<- BA
+    sarl    $4,%eax                    # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB (obj)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                   # object null?
+    movl    offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    SPILL(rIBASE)                       # preserve rIBASE
+    je      .LOP_INSTANCE_OF_store           # null obj, not instance, store it
+    movzwl  2(rPC),rIBASE               # rIBASE<- CCCC
+    movl    offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    movl    (%ecx,rIBASE,4),%ecx        # ecx<- resolved class
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    testl   %ecx,%ecx                   # have we resolved this before?
+    je      .LOP_INSTANCE_OF_resolve         # not resolved, do it now
+.LOP_INSTANCE_OF_resolved:  # eax<- obj->clazz, ecx<- resolved class
+    cmpl    %eax,%ecx                   # same class (trivial success)?
+    je      .LOP_INSTANCE_OF_trivial         # yes, trivial finish
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  eax holds obj->clazz
+     *  ecx holds class resolved from BBBB
+     *  rINST has BA
+     */
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    call    dvmInstanceofNonTrivial     # eax<- boolean result
+    # fall through to OP_INSTANCE_OF_store
+
+    /*
+     * eax holds boolean result
+     * rINST holds BA
+     */
+.LOP_INSTANCE_OF_store:
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    andb    $0xf,rINSTbl               # <- A
+    ADVANCE_PC 2
+    SET_VREG %eax rINST                 # vA<- eax
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds A
+     */
+.LOP_INSTANCE_OF_trivial:
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    andb    $0xf,rINSTbl               # <- A
+    ADVANCE_PC 2
+    movl    $1,%eax
+    SET_VREG %eax rINST                 # vA<- true
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  rIBASE holds BBBB
+     *  rINST holds BA
+     */
+.LOP_INSTANCE_OF_resolve:
+    movl    rIBASE,OUT_ARG1(%esp)         # arg1<- BBBB
+    movl    rSELF,%ecx
+    movl    offThread_method(%ecx),%ecx
+    movl    $1,OUT_ARG2(%esp)          # arg2<- true
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    EXPORT_PC
+    movl    %ecx,OUT_ARG0(%esp)         # arg0<- method->clazz
+    call    dvmResolveClass             # eax<- resolved ClassObject ptr
+    testl   %eax,%eax                   # success?
+    je      common_exceptionThrown      # no, handle exception
+/* Now, we need to sync up with fast path.  We need eax to
+ * hold the obj->clazz, and ecx to hold the resolved class
+ */
+    movl    %eax,%ecx                   # ecx<- resolved class
+    movl    rINST,%eax                  # eax<- BA
+    sarl    $4,%eax                    # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB (obj)
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    jmp     .LOP_INSTANCE_OF_resolved
+
+/* ------------------------------ */
+.L_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: x86/OP_ARRAY_LENGTH.S */
+    /*
+     * Return the length of an array.
+     */
+   mov      rINST,%eax                # eax<- BA
+   sarl     $4,rINST                 # rINST<- B
+   GET_VREG_R %ecx rINST              # ecx<- vB (object ref)
+   andb     $0xf,%al                 # eax<- A
+   testl    %ecx,%ecx                 # is null?
+   je       common_errNullObject
+   movl     offArrayObject_length(%ecx),rINST
+   FETCH_INST_OPCODE 1 %ecx
+   ADVANCE_PC 1
+   SET_VREG rINST %eax
+   GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_NEW_INSTANCE: /* 0x22 */
+/* File: x86/OP_NEW_INSTANCE.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance vAA, class@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    SPILL(rIBASE)
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved class
+    testl     %ecx,%ecx                 # resolved?
+    je        .LOP_NEW_INSTANCE_resolve       # no, go do it
+.LOP_NEW_INSTANCE_resolved:  # on entry, ecx<- class
+    cmpb      $CLASS_INITIALIZED,offClassObject_status(%ecx)
+    jne       .LOP_NEW_INSTANCE_needinit
+.LOP_NEW_INSTANCE_initialized:  # on entry, ecx<- class
+    movl      $ALLOC_DONT_TRACK,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    call     dvmAllocObject             # eax<- new object
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                  # success?
+    je       common_exceptionThrown     # no, bail out
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Class initialization required.
+     *
+     *  ecx holds class object
+     */
+.LOP_NEW_INSTANCE_needinit:
+    SPILL_TMP1(%ecx)                    # save object
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmInitClass                # initialize class
+    UNSPILL_TMP1(%ecx)                  # restore object
+    testl   %eax,%eax                   # success?
+    jne     .LOP_NEW_INSTANCE_initialized     # success, continue
+    jmp     common_exceptionThrown      # go deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     */
+.LOP_NEW_INSTANCE_resolve:
+    movl    rSELF,%ecx
+    movzwl  2(rPC),%eax
+    movl    offThread_method(%ecx),%ecx   # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    movl    $0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass             # call(clazz,off,flags)
+    movl    %eax,%ecx                   # ecx<- resolved ClassObject ptr
+    testl   %ecx,%ecx                   # success?
+    jne     .LOP_NEW_INSTANCE_resolved        # good to go
+    jmp     common_exceptionThrown      # no, handle exception
+
+/* ------------------------------ */
+.L_OP_NEW_ARRAY: /* 0x23 */
+/* File: x86/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 */
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movl    offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    movzwl  2(rPC),%eax                       # eax<- CCCC
+    movl    offDvmDex_pResClasses(%ecx),%ecx  # ecx<- pDvmDex->pResClasses
+    SPILL(rIBASE)
+    movl    (%ecx,%eax,4),%ecx                # ecx<- resolved class
+    movzbl  rINSTbl,%eax
+    sarl    $4,%eax                          # eax<- B
+    GET_VREG_R %eax %eax                      # eax<- vB (array length)
+    andb    $0xf,rINSTbl                     # rINST<- A
+    testl   %eax,%eax
+    js      common_errNegativeArraySize       # bail, passing len in eax
+    testl   %ecx,%ecx                         # already resolved?
+    jne     .LOP_NEW_ARRAY_finish                # yes, fast path
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *  ecx holds class (null here)
+     *  eax holds array length (vB)
+     */
+    movl    rSELF,%ecx
+    SPILL_TMP1(%eax)                   # save array length
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movzwl  2(rPC),%eax                # eax<- CCCC
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass            # eax<- call(clazz,ref,flag)
+    movl    %eax,%ecx
+    UNSPILL_TMP1(%eax)
+    testl   %ecx,%ecx                  # successful resolution?
+    je      common_exceptionThrown     # no, bail.
+# fall through to OP_NEW_ARRAY_finish
+
+    /*
+     * Finish allocation
+     *
+     * ecx holds class
+     * eax holds array length (vB)
+     */
+.LOP_NEW_ARRAY_finish:
+    movl    %ecx,OUT_ARG0(%esp)
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $ALLOC_DONT_TRACK,OUT_ARG2(%esp)
+    call    dvmAllocArrayByClass    # eax<- call(clazz,length,flags)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    testl   %eax,%eax               # failed?
+    je      common_exceptionThrown  # yup - go handle
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: x86/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 */
+    movl    rSELF,%eax
+    movl    offThread_methodClassDex(%eax),%eax # eax<- pDvmDex
+    movzwl  2(rPC),%ecx                       # ecx<- BBBB
+    movl    offDvmDex_pResClasses(%eax),%eax  # eax<- pDvmDex->pResClasses
+    SPILL(rIBASE)                             # preserve rIBASE
+    movl    (%eax,%ecx,4),%eax                # eax<- resolved class
+    EXPORT_PC
+    testl   %eax,%eax                         # already resolved?
+    jne     .LOP_FILLED_NEW_ARRAY_continue              # yes, continue
+    # less frequent path, so we'll redo some work
+    movl    rSELF,%eax
+    movl    $0,OUT_ARG2(%esp)                # arg2<- false
+    movl    %ecx,OUT_ARG1(%esp)               # arg1<- BBBB
+    movl    offThread_method(%eax),%eax         # eax<- self->method
+    movl    offMethod_clazz(%eax),%eax        # eax<- method->clazz
+    movl    %eax,OUT_ARG0(%esp)               # arg0<- clazz
+    call    dvmResolveClass                   # eax<- call(clazz,ref,flag)
+    testl   %eax,%eax                         # null?
+    je      common_exceptionThrown            # yes, handle it
+
+       # note: fall through to .LOP_FILLED_NEW_ARRAY_continue
+
+    /*
+     * On entry:
+     *    eax holds array class [r0]
+     *    rINST holds AA or BB [r10]
+     *    ecx is scratch
+     */
+.LOP_FILLED_NEW_ARRAY_continue:
+    movl    offClassObject_descriptor(%eax),%ecx  # ecx<- arrayClass->descriptor
+    movl    $ALLOC_DONT_TRACK,OUT_ARG2(%esp)     # arg2<- flags
+    movzbl  1(%ecx),%ecx                          # ecx<- descriptor[1]
+    movl    %eax,OUT_ARG0(%esp)                   # arg0<- arrayClass
+    movl    rSELF,%eax
+    cmpb    $'I',%cl                             # supported?
+    je      1f
+    cmpb    $'L',%cl
+    je      1f
+    cmpb    $'[',%cl
+    jne      .LOP_FILLED_NEW_ARRAY_notimpl                  # no, not handled yet
+1:
+    movl    %ecx,offThread_retval+4(%eax)           # save type
+    .if      (!0)
+    SPILL_TMP1(rINST)                              # save copy, need "B" later
+    sarl    $4,rINST
+    .endif
+    movl    rINST,OUT_ARG1(%esp)                  # arg1<- A or AA (length)
+    call    dvmAllocArrayByClass     # eax<- call(arrayClass, length, flags)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                             # alloc successful?
+    je      common_exceptionThrown                # no, handle exception
+    movl    %eax,offThread_retval(%ecx)             # retval.l<- new array
+    movzwl  4(rPC),%ecx                           # ecx<- FEDC or CCCC
+    leal    offArrayObject_contents(%eax),%eax    # eax<- newArray->contents
+
+/* at this point:
+ *     eax is pointer to tgt
+ *     rINST is length
+ *     ecx is FEDC or CCCC
+ *     TMP_SPILL1 is BA
+ *  We now need to copy values from registers into the array
+ */
+
+    .if 0
+    # set up src pointer
+    SPILL_TMP2(%esi)
+    SPILL_TMP3(%edi)
+    leal    (rFP,%ecx,4),%esi # set up src ptr
+    movl    %eax,%edi         # set up dst ptr
+    movl    rINST,%ecx        # load count register
+    rep
+    movsd
+    UNSPILL_TMP2(%esi)
+    UNSPILL_TMP3(%edi)
+    movl    rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+    .else
+    testl  rINST,rINST
+    je     4f
+    UNSPILL_TMP1(rIBASE)      # restore "BA"
+    andl   $0x0f,rIBASE      # rIBASE<- 0000000A
+    sall   $16,rIBASE        # rIBASE<- 000A0000
+    orl    %ecx,rIBASE        # rIBASE<- 000AFEDC
+3:
+    movl   $0xf,%ecx
+    andl   rIBASE,%ecx        # ecx<- next reg to load
+    GET_VREG_R %ecx %ecx
+    shrl   $4,rIBASE
+    leal   4(%eax),%eax
+    movl   %ecx,-4(%eax)
+    sub    $1,rINST
+    jne    3b
+4:
+    movl   rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+    .endif
+
+    cmpb    $'I',%al                        # Int array?
+    je      5f                               # skip card mark if so
+    movl    offThread_retval(%ecx),%eax        # eax<- object head
+    movl    offThread_cardTable(%ecx),%ecx     # card table base
+    shrl    $GC_CARD_SHIFT,%eax             # convert to card num
+    movb    %cl,(%ecx,%eax)                  # mark card based on object head
+5:
+    UNSPILL(rIBASE)                          # restore rIBASE
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_notimpl:
+    movl    $.LstrFilledNewArrayNotImplA,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowInternalError
+    jmp     common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: x86/OP_FILLED_NEW_ARRAY_RANGE.S */
+/* File: x86/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 */
+    movl    rSELF,%eax
+    movl    offThread_methodClassDex(%eax),%eax # eax<- pDvmDex
+    movzwl  2(rPC),%ecx                       # ecx<- BBBB
+    movl    offDvmDex_pResClasses(%eax),%eax  # eax<- pDvmDex->pResClasses
+    SPILL(rIBASE)                             # preserve rIBASE
+    movl    (%eax,%ecx,4),%eax                # eax<- resolved class
+    EXPORT_PC
+    testl   %eax,%eax                         # already resolved?
+    jne     .LOP_FILLED_NEW_ARRAY_RANGE_continue              # yes, continue
+    # less frequent path, so we'll redo some work
+    movl    rSELF,%eax
+    movl    $0,OUT_ARG2(%esp)                # arg2<- false
+    movl    %ecx,OUT_ARG1(%esp)               # arg1<- BBBB
+    movl    offThread_method(%eax),%eax         # eax<- self->method
+    movl    offMethod_clazz(%eax),%eax        # eax<- method->clazz
+    movl    %eax,OUT_ARG0(%esp)               # arg0<- clazz
+    call    dvmResolveClass                   # eax<- call(clazz,ref,flag)
+    testl   %eax,%eax                         # null?
+    je      common_exceptionThrown            # yes, handle it
+
+       # note: fall through to .LOP_FILLED_NEW_ARRAY_RANGE_continue
+
+    /*
+     * On entry:
+     *    eax holds array class [r0]
+     *    rINST holds AA or BB [r10]
+     *    ecx is scratch
+     */
+.LOP_FILLED_NEW_ARRAY_RANGE_continue:
+    movl    offClassObject_descriptor(%eax),%ecx  # ecx<- arrayClass->descriptor
+    movl    $ALLOC_DONT_TRACK,OUT_ARG2(%esp)     # arg2<- flags
+    movzbl  1(%ecx),%ecx                          # ecx<- descriptor[1]
+    movl    %eax,OUT_ARG0(%esp)                   # arg0<- arrayClass
+    movl    rSELF,%eax
+    cmpb    $'I',%cl                             # supported?
+    je      1f
+    cmpb    $'L',%cl
+    je      1f
+    cmpb    $'[',%cl
+    jne      .LOP_FILLED_NEW_ARRAY_RANGE_notimpl                  # no, not handled yet
+1:
+    movl    %ecx,offThread_retval+4(%eax)           # save type
+    .if      (!1)
+    SPILL_TMP1(rINST)                              # save copy, need "B" later
+    sarl    $4,rINST
+    .endif
+    movl    rINST,OUT_ARG1(%esp)                  # arg1<- A or AA (length)
+    call    dvmAllocArrayByClass     # eax<- call(arrayClass, length, flags)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                             # alloc successful?
+    je      common_exceptionThrown                # no, handle exception
+    movl    %eax,offThread_retval(%ecx)             # retval.l<- new array
+    movzwl  4(rPC),%ecx                           # ecx<- FEDC or CCCC
+    leal    offArrayObject_contents(%eax),%eax    # eax<- newArray->contents
+
+/* at this point:
+ *     eax is pointer to tgt
+ *     rINST is length
+ *     ecx is FEDC or CCCC
+ *     TMP_SPILL1 is BA
+ *  We now need to copy values from registers into the array
+ */
+
+    .if 1
+    # set up src pointer
+    SPILL_TMP2(%esi)
+    SPILL_TMP3(%edi)
+    leal    (rFP,%ecx,4),%esi # set up src ptr
+    movl    %eax,%edi         # set up dst ptr
+    movl    rINST,%ecx        # load count register
+    rep
+    movsd
+    UNSPILL_TMP2(%esi)
+    UNSPILL_TMP3(%edi)
+    movl    rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+    .else
+    testl  rINST,rINST
+    je     4f
+    UNSPILL_TMP1(rIBASE)      # restore "BA"
+    andl   $0x0f,rIBASE      # rIBASE<- 0000000A
+    sall   $16,rIBASE        # rIBASE<- 000A0000
+    orl    %ecx,rIBASE        # rIBASE<- 000AFEDC
+3:
+    movl   $0xf,%ecx
+    andl   rIBASE,%ecx        # ecx<- next reg to load
+    GET_VREG_R %ecx %ecx
+    shrl   $4,rIBASE
+    leal   4(%eax),%eax
+    movl   %ecx,-4(%eax)
+    sub    $1,rINST
+    jne    3b
+4:
+    movl   rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+    .endif
+
+    cmpb    $'I',%al                        # Int array?
+    je      5f                               # skip card mark if so
+    movl    offThread_retval(%ecx),%eax        # eax<- object head
+    movl    offThread_cardTable(%ecx),%ecx     # card table base
+    shrl    $GC_CARD_SHIFT,%eax             # convert to card num
+    movb    %cl,(%ecx,%eax)                  # mark card based on object head
+5:
+    UNSPILL(rIBASE)                          # restore rIBASE
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
+    movl    $.LstrFilledNewArrayNotImplA,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowInternalError
+    jmp     common_exceptionThrown
+
+
+/* ------------------------------ */
+.L_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: x86/OP_FILL_ARRAY_DATA.S */
+    /* fill-array-data vAA, +BBBBBBBB */
+    movl    2(rPC),%ecx                # ecx<- BBBBbbbb
+    leal    (rPC,%ecx,2),%ecx          # ecx<- PC + BBBBbbbb*2
+    GET_VREG_R %eax rINST
+    EXPORT_PC
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    SPILL(rIBASE)
+    call    dvmInterpHandleFillArrayData
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 3 %ecx
+    testl   %eax,%eax                   # exception thrown?
+    je      common_exceptionThrown
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_THROW: /* 0x27 */
+/* File: x86/OP_THROW.S */
+    /*
+     * Throw an exception object in the current thread.
+     */
+    /* throw vAA */
+    EXPORT_PC
+    GET_VREG_R %eax rINST              # eax<- exception object
+    movl     rSELF,%ecx                # ecx<- self
+    testl    %eax,%eax                 # null object?
+    je       common_errNullObject
+    movl     %eax,offThread_exception(%ecx) # thread->exception<- obj
+    jmp      common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_GOTO: /* 0x28 */
+/* File: x86/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 */
+    movl    rSELF,%ecx
+    movsbl  rINSTbl,%eax          # eax<- ssssssAA
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+/* ------------------------------ */
+.L_OP_GOTO_16: /* 0x29 */
+/* File: x86/OP_GOTO_16.S */
+    /*
+     * Unconditional branch, 16-bit offset.
+     *
+     * The branch distance is a signed code-unit offset
+     */
+    /* goto/16 +AAAA */
+    movl    rSELF,%ecx
+    movswl  2(rPC),%eax            # eax<- ssssAAAA
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+/* ------------------------------ */
+.L_OP_GOTO_32: /* 0x2a */
+/* File: x86/OP_GOTO_32.S */
+    /*
+     * Unconditional branch, 32-bit offset.
+     *
+     * The branch distance is a signed code-unit offset.
+     */
+    /* goto/32 AAAAAAAA */
+    movl    rSELF,%ecx
+    movl    2(rPC),%eax            # eax<- AAAAAAAA
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+/* ------------------------------ */
+.L_OP_PACKED_SWITCH: /* 0x2b */
+/* File: x86/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 */
+    movl    2(rPC),%ecx           # ecx<- BBBBbbbb
+    GET_VREG_R %eax rINST         # eax<- vAA
+    leal    (rPC,%ecx,2),%ecx     # ecx<- PC + BBBBbbbb*2
+    movl    %eax,OUT_ARG1(%esp)   # ARG1<- vAA
+    movl    %ecx,OUT_ARG0(%esp)   # ARG0<- switchData
+    call    dvmInterpHandlePackedSwitch
+    movl    rSELF,%ecx
+    ADVANCE_PC_INDEXED %eax
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST
+    GOTO_NEXT
+
+/* ------------------------------ */
+.L_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: x86/OP_SPARSE_SWITCH.S */
+/* File: x86/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 */
+    movl    2(rPC),%ecx           # ecx<- BBBBbbbb
+    GET_VREG_R %eax rINST         # eax<- vAA
+    leal    (rPC,%ecx,2),%ecx     # ecx<- PC + BBBBbbbb*2
+    movl    %eax,OUT_ARG1(%esp)   # ARG1<- vAA
+    movl    %ecx,OUT_ARG0(%esp)   # ARG0<- switchData
+    call    dvmInterpHandleSparseSwitch
+    movl    rSELF,%ecx
+    ADVANCE_PC_INDEXED %eax
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: x86/OP_CMPL_FLOAT.S */
+/* File: x86/OP_CMPG_DOUBLE.S */
+    /* float/double_cmp[gl] vAA, vBB, vCC */
+    movzbl    3(rPC),%eax             # eax<- CC
+    movzbl    2(rPC),%ecx             # ecx<- BB
+    .if 0
+    fldl     (rFP,%eax,4)
+    fldl     (rFP,%ecx,4)
+    .else
+    flds     (rFP,%eax,4)
+    flds     (rFP,%ecx,4)
+    .endif
+    xorl     %ecx,%ecx
+    fucompp     # z if equal, p set if NaN, c set if st0 < st1
+    fnstsw   %ax
+    sahf
+    FETCH_INST_OPCODE 2 %eax
+    jp       .LOP_CMPL_FLOAT_isNaN
+    je       .LOP_CMPL_FLOAT_finish
+    sbbl     %ecx,%ecx
+    jb       .LOP_CMPL_FLOAT_finish
+    incl     %ecx
+.LOP_CMPL_FLOAT_finish:
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+.LOP_CMPL_FLOAT_isNaN:
+    movl      $-1,%ecx
+    jmp       .LOP_CMPL_FLOAT_finish
+
+
+/* ------------------------------ */
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: x86/OP_CMPG_FLOAT.S */
+/* File: x86/OP_CMPG_DOUBLE.S */
+    /* float/double_cmp[gl] vAA, vBB, vCC */
+    movzbl    3(rPC),%eax             # eax<- CC
+    movzbl    2(rPC),%ecx             # ecx<- BB
+    .if 0
+    fldl     (rFP,%eax,4)
+    fldl     (rFP,%ecx,4)
+    .else
+    flds     (rFP,%eax,4)
+    flds     (rFP,%ecx,4)
+    .endif
+    xorl     %ecx,%ecx
+    fucompp     # z if equal, p set if NaN, c set if st0 < st1
+    fnstsw   %ax
+    sahf
+    FETCH_INST_OPCODE 2 %eax
+    jp       .LOP_CMPG_FLOAT_isNaN
+    je       .LOP_CMPG_FLOAT_finish
+    sbbl     %ecx,%ecx
+    jb       .LOP_CMPG_FLOAT_finish
+    incl     %ecx
+.LOP_CMPG_FLOAT_finish:
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+.LOP_CMPG_FLOAT_isNaN:
+    movl      $1,%ecx
+    jmp       .LOP_CMPG_FLOAT_finish
+
+
+/* ------------------------------ */
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: x86/OP_CMPL_DOUBLE.S */
+/* File: x86/OP_CMPG_DOUBLE.S */
+    /* float/double_cmp[gl] vAA, vBB, vCC */
+    movzbl    3(rPC),%eax             # eax<- CC
+    movzbl    2(rPC),%ecx             # ecx<- BB
+    .if 1
+    fldl     (rFP,%eax,4)
+    fldl     (rFP,%ecx,4)
+    .else
+    flds     (rFP,%eax,4)
+    flds     (rFP,%ecx,4)
+    .endif
+    xorl     %ecx,%ecx
+    fucompp     # z if equal, p set if NaN, c set if st0 < st1
+    fnstsw   %ax
+    sahf
+    FETCH_INST_OPCODE 2 %eax
+    jp       .LOP_CMPL_DOUBLE_isNaN
+    je       .LOP_CMPL_DOUBLE_finish
+    sbbl     %ecx,%ecx
+    jb       .LOP_CMPL_DOUBLE_finish
+    incl     %ecx
+.LOP_CMPL_DOUBLE_finish:
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+.LOP_CMPL_DOUBLE_isNaN:
+    movl      $-1,%ecx
+    jmp       .LOP_CMPL_DOUBLE_finish
+
+
+/* ------------------------------ */
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: x86/OP_CMPG_DOUBLE.S */
+    /* float/double_cmp[gl] vAA, vBB, vCC */
+    movzbl    3(rPC),%eax             # eax<- CC
+    movzbl    2(rPC),%ecx             # ecx<- BB
+    .if 1
+    fldl     (rFP,%eax,4)
+    fldl     (rFP,%ecx,4)
+    .else
+    flds     (rFP,%eax,4)
+    flds     (rFP,%ecx,4)
+    .endif
+    xorl     %ecx,%ecx
+    fucompp     # z if equal, p set if NaN, c set if st0 < st1
+    fnstsw   %ax
+    sahf
+    FETCH_INST_OPCODE 2 %eax
+    jp       .LOP_CMPG_DOUBLE_isNaN
+    je       .LOP_CMPG_DOUBLE_finish
+    sbbl     %ecx,%ecx
+    jb       .LOP_CMPG_DOUBLE_finish
+    incl     %ecx
+.LOP_CMPG_DOUBLE_finish:
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+.LOP_CMPG_DOUBLE_isNaN:
+    movl      $1,%ecx
+    jmp       .LOP_CMPG_DOUBLE_finish
+
+/* ------------------------------ */
+.L_OP_CMP_LONG: /* 0x31 */
+/* File: x86/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.
+     */
+    // TUNING: rework to avoid rIBASE spill
+    /* cmp-long vAA, vBB, vCC */
+    movzbl    2(rPC),%ecx              # ecx<- BB
+    SPILL(rIBASE)
+    movzbl    3(rPC),rIBASE            # rIBASE- CC
+    GET_VREG_WORD %eax %ecx,1          # eax<- v[BB+1]
+    GET_VREG_WORD %ecx %ecx 0          # ecx<- v[BB+0]
+    cmpl      4(rFP,rIBASE,4),%eax
+    jl        .LOP_CMP_LONG_smaller
+    jg        .LOP_CMP_LONG_bigger
+    sub       (rFP,rIBASE,4),%ecx
+    ja        .LOP_CMP_LONG_bigger
+    jb        .LOP_CMP_LONG_smaller
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_CMP_LONG_bigger:
+    movl      $1,%ecx
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_CMP_LONG_smaller:
+    movl      $-1,%ecx
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IF_EQ: /* 0x32 */
+/* File: x86/OP_IF_EQ.S */
+/* File: x86/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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $2,%eax              # assume not taken
+    jne   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_NE: /* 0x33 */
+/* File: x86/OP_IF_NE.S */
+/* File: x86/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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $2,%eax              # assume not taken
+    je   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_LT: /* 0x34 */
+/* File: x86/OP_IF_LT.S */
+/* File: x86/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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $2,%eax              # assume not taken
+    jge   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_GE: /* 0x35 */
+/* File: x86/OP_IF_GE.S */
+/* File: x86/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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $2,%eax              # assume not taken
+    jl   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_GT: /* 0x36 */
+/* File: x86/OP_IF_GT.S */
+/* File: x86/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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $2,%eax              # assume not taken
+    jle   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_LE: /* 0x37 */
+/* File: x86/OP_IF_LE.S */
+/* File: x86/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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $2,%eax              # assume not taken
+    jg   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_EQZ: /* 0x38 */
+/* File: x86/OP_IF_EQZ.S */
+/* File: x86/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 */
+    cmpl     $0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $2,%eax              # assume branch not taken
+    jne   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_NEZ: /* 0x39 */
+/* File: x86/OP_IF_NEZ.S */
+/* File: x86/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 */
+    cmpl     $0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $2,%eax              # assume branch not taken
+    je   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_LTZ: /* 0x3a */
+/* File: x86/OP_IF_LTZ.S */
+/* File: x86/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 */
+    cmpl     $0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $2,%eax              # assume branch not taken
+    jge   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_GEZ: /* 0x3b */
+/* File: x86/OP_IF_GEZ.S */
+/* File: x86/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 */
+    cmpl     $0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $2,%eax              # assume branch not taken
+    jl   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_GTZ: /* 0x3c */
+/* File: x86/OP_IF_GTZ.S */
+/* File: x86/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 */
+    cmpl     $0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $2,%eax              # assume branch not taken
+    jle   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_IF_LEZ: /* 0x3d */
+/* File: x86/OP_IF_LEZ.S */
+/* File: x86/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 */
+    cmpl     $0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $2,%eax              # assume branch not taken
+    jg   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3E: /* 0x3e */
+/* File: x86/OP_UNUSED_3E.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3F: /* 0x3f */
+/* File: x86/OP_UNUSED_3F.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_40: /* 0x40 */
+/* File: x86/OP_UNUSED_40.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_41: /* 0x41 */
+/* File: x86/OP_UNUSED_41.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_42: /* 0x42 */
+/* File: x86/OP_UNUSED_42.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_43: /* 0x43 */
+/* File: x86/OP_UNUSED_43.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_AGET: /* 0x44 */
+/* File: x86/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    movl     offArrayObject_contents(%eax,%ecx,4),%eax
+.LOP_AGET_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_AGET_WIDE: /* 0x45 */
+/* File: x86/OP_AGET_WIDE.S */
+    /*
+     * Array get, 64 bits.  vAA <- vBB[vCC].
+     *
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,8),%eax
+    movl      (%eax),%ecx
+    movl      4(%eax),%eax
+    SET_VREG_WORD %ecx rINST 0
+    SET_VREG_WORD %eax rINST 1
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_AGET_OBJECT: /* 0x46 */
+/* File: x86/OP_AGET_OBJECT.S */
+/* File: x86/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    movl     offArrayObject_contents(%eax,%ecx,4),%eax
+.LOP_AGET_OBJECT_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: x86/OP_AGET_BOOLEAN.S */
+/* File: x86/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    movzbl     offArrayObject_contents(%eax,%ecx,1),%eax
+.LOP_AGET_BOOLEAN_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AGET_BYTE: /* 0x48 */
+/* File: x86/OP_AGET_BYTE.S */
+/* File: x86/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    movsbl     offArrayObject_contents(%eax,%ecx,1),%eax
+.LOP_AGET_BYTE_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AGET_CHAR: /* 0x49 */
+/* File: x86/OP_AGET_CHAR.S */
+/* File: x86/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    movzwl     offArrayObject_contents(%eax,%ecx,2),%eax
+.LOP_AGET_CHAR_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AGET_SHORT: /* 0x4a */
+/* File: x86/OP_AGET_SHORT.S */
+/* File: x86/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    movswl     offArrayObject_contents(%eax,%ecx,2),%eax
+.LOP_AGET_SHORT_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_APUT: /* 0x4b */
+/* File: x86/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,4),%eax
+.LOP_APUT_finish:
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    movl     rINST,(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_APUT_WIDE: /* 0x4c */
+/* File: x86/OP_APUT_WIDE.S */
+    /*
+     * Array put, 64 bits.  vBB[vCC]<-vAA.
+     *
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,8),%eax
+    GET_VREG_WORD %ecx rINST 0
+    GET_VREG_WORD rINST rINST 1
+    movl      %ecx,(%eax)
+    FETCH_INST_OPCODE 2 %ecx
+    movl      rINST,4(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_APUT_OBJECT: /* 0x4d */
+/* File: x86/OP_APUT_OBJECT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    GET_VREG_R  rINST rINST             # rINST<- vAA
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    /* On entry:
+     *   eax<- array object
+     *   ecx<- index
+     *   rINST<- vAA
+     */
+    leal      offArrayObject_contents(%eax,%ecx,4),%ecx
+    testl     rINST,rINST                    # storing null reference?
+    je        .LOP_APUT_OBJECT_skip_check
+    SPILL_TMP1(%ecx)                         # save target address
+    SPILL_TMP2(%eax)                         # save object head
+    movl      offObject_clazz(%eax),%eax     # eax<- arrayObj->clazz
+    movl      offObject_clazz(rINST),%ecx    # ecx<- obj->clazz
+    movl      %eax,OUT_ARG1(%esp)
+    movl      %ecx,OUT_ARG0(%esp)
+    movl      %ecx,sReg0                     # store the two classes for later
+    movl      %eax,sReg1
+    SPILL(rIBASE)
+    call      dvmCanPutArrayElement          # test object type vs. array type
+    UNSPILL(rIBASE)
+    UNSPILL_TMP1(%ecx)                       # recover target address
+    testl     %eax,%eax
+    movl      rSELF,%eax
+    jne       .LOP_APUT_OBJECT_types_okay
+
+    # The types don't match.  We need to throw an ArrayStoreException.
+    EXPORT_PC
+    movl      sReg0,%eax                     # restore the two classes...
+    movl      %eax,OUT_ARG0(%esp)
+    movl      sReg1,%ecx
+    movl      %ecx,OUT_ARG1(%esp)
+    call      dvmThrowArrayStoreExceptionIncompatibleElement # ...and throw
+    jmp       common_exceptionThrown
+
+.LOP_APUT_OBJECT_types_okay:
+    movl      offThread_cardTable(%eax),%eax   # get card table base
+    movl      rINST,(%ecx)                   # store into array
+    UNSPILL_TMP2(rINST)                      # recover object head
+    FETCH_INST_OPCODE 2 %ecx
+    shrl      $GC_CARD_SHIFT,rINST          # object head to card number
+    movb      %al,(%eax,rINST)               # mark card using object head
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_APUT_OBJECT_skip_check:
+    movl      rINST,(%ecx)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: x86/OP_APUT_BOOLEAN.S */
+/* File: x86/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,1),%eax
+.LOP_APUT_BOOLEAN_finish:
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    movb     rINSTbl,(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_APUT_BYTE: /* 0x4f */
+/* File: x86/OP_APUT_BYTE.S */
+/* File: x86/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,1),%eax
+.LOP_APUT_BYTE_finish:
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    movb     rINSTbl,(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_APUT_CHAR: /* 0x50 */
+/* File: x86/OP_APUT_CHAR.S */
+/* File: x86/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,2),%eax
+.LOP_APUT_CHAR_finish:
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    movw     rINSTw,(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_APUT_SHORT: /* 0x51 */
+/* File: x86/OP_APUT_SHORT.S */
+/* File: x86/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,2),%eax
+.LOP_APUT_SHORT_finish:
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    movw     rINSTw,(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IGET: /* 0x52 */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_IGET_WIDE: /* 0x53 */
+/* File: x86/OP_IGET_WIDE.S */
+    /*
+     * 64-bit instance field get.
+     *
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_WIDE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # for dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save objpointer across call
+    movl    rPC,OUT_ARG0(%esp)                  # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IGET_WIDE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_WIDE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    movl    (%eax),%ecx                         # ecx<- lsw
+    movl    4(%eax),%eax                        # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IGET_OBJECT: /* 0x54 */
+/* File: x86/OP_IGET_OBJECT.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_OBJECT_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_OBJECT_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_OBJECT_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: x86/OP_IGET_BOOLEAN.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_BOOLEAN_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_BOOLEAN_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_BOOLEAN_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movzbl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_BYTE: /* 0x56 */
+/* File: x86/OP_IGET_BYTE.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_BYTE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_BYTE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_BYTE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movsbl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_CHAR: /* 0x57 */
+/* File: x86/OP_IGET_CHAR.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_CHAR_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_CHAR_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_CHAR_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movzwl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_SHORT: /* 0x58 */
+/* File: x86/OP_IGET_SHORT.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_SHORT_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_SHORT_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_SHORT_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movswl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IPUT: /* 0x59 */
+/* File: x86/OP_IPUT.S */
+
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movl   rINST,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_WIDE: /* 0x5a */
+/* File: x86/OP_IPUT_WIDE.S */
+    /*
+     * 64-bit instance field put.
+     *
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_WIDE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  ... which returns InstrField ptr
+    jne     .LOP_IPUT_WIDE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_WIDE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    GET_VREG_WORD %ecx rINST 0                  # ecx<- lsw
+    GET_VREG_WORD rINST rINST 1                 # rINST<- msw
+    movl    rINST,4(%eax)
+    movl    %ecx,(%eax)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_OBJECT: /* 0x5b */
+/* File: x86/OP_IPUT_OBJECT.S */
+    /*
+     * Object field put.
+     *
+     * for: iput-object
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                  # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_OBJECT_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_OBJECT_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_OBJECT_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                      # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl    rINST,(%ecx,%eax)      # obj.field <- v[A](8/16/32 bits)
+    movl    rSELF,%eax
+    testl   rINST,rINST                         # stored a NULL?
+    movl    offThread_cardTable(%eax),%eax      # get card table base
+    je      1f                                  # skip card mark if null store
+    shrl    $GC_CARD_SHIFT,%ecx                # object head to card number
+    movb    %al,(%eax,%ecx)                     # mark card using object head
+1:
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: x86/OP_IPUT_BOOLEAN.S */
+/* File: x86/OP_IPUT.S */
+
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_BOOLEAN_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_BOOLEAN_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_BOOLEAN_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movb   rINSTbl,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_BYTE: /* 0x5d */
+/* File: x86/OP_IPUT_BYTE.S */
+/* File: x86/OP_IPUT.S */
+
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_BYTE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_BYTE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_BYTE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movb   rINSTbl,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_CHAR: /* 0x5e */
+/* File: x86/OP_IPUT_CHAR.S */
+/* File: x86/OP_IPUT.S */
+
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_CHAR_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_CHAR_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_CHAR_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movw   rINSTw,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_SHORT: /* 0x5f */
+/* File: x86/OP_IPUT_SHORT.S */
+/* File: x86/OP_IPUT.S */
+
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_SHORT_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_SHORT_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_SHORT_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movw   rINSTw,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SGET: /* 0x60 */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_resolve                # if not, make it so
+.LOP_SGET_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SGET_WIDE: /* 0x61 */
+/* File: x86/OP_SGET_WIDE.S */
+    /*
+     * 64-bit SGET handler.
+     *
+     */
+    /* sget-wide vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_WIDE_resolve                # if not, make it so
+.LOP_SGET_WIDE_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%ecx    # ecx<- lsw
+    movl      4+offStaticField_value(%eax),%eax  # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_WIDE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_WIDE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SGET_OBJECT: /* 0x62 */
+/* File: x86/OP_SGET_OBJECT.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_OBJECT_resolve                # if not, make it so
+.LOP_SGET_OBJECT_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_OBJECT_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_OBJECT_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: x86/OP_SGET_BOOLEAN.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_BOOLEAN_resolve                # if not, make it so
+.LOP_SGET_BOOLEAN_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_BOOLEAN_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_BOOLEAN_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_BYTE: /* 0x64 */
+/* File: x86/OP_SGET_BYTE.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_BYTE_resolve                # if not, make it so
+.LOP_SGET_BYTE_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_BYTE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_BYTE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_CHAR: /* 0x65 */
+/* File: x86/OP_SGET_CHAR.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_CHAR_resolve                # if not, make it so
+.LOP_SGET_CHAR_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_CHAR_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_CHAR_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_SHORT: /* 0x66 */
+/* File: x86/OP_SGET_SHORT.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_SHORT_resolve                # if not, make it so
+.LOP_SGET_SHORT_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_SHORT_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_SHORT_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT: /* 0x67 */
+/* File: x86/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_resolve                # if not, make it so
+.LOP_SPUT_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SPUT_WIDE: /* 0x68 */
+/* File: x86/OP_SPUT_WIDE.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_WIDE_resolve                # if not, make it so
+.LOP_SPUT_WIDE_finish:     # field ptr in eax
+    GET_VREG_WORD %ecx rINST 0                  # rINST<- lsw
+    GET_VREG_WORD rINST rINST 1                 # ecx<- msw
+    movl      %ecx,offStaticField_value(%eax)
+    FETCH_INST_OPCODE 2 %ecx
+    movl      rINST,4+offStaticField_value(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_WIDE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_WIDE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: x86/OP_SPUT_OBJECT.S */
+    /*
+     * SPUT object handler.
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_OBJECT_resolve                # if not, make it so
+.LOP_SPUT_OBJECT_finish:                              # field ptr in eax
+    movzbl    rINSTbl,%ecx                       # ecx<- AA
+    GET_VREG_R  %ecx %ecx
+    movl      %ecx,offStaticField_value(%eax)    # do the store
+    testl     %ecx,%ecx                          # stored null object ptr?
+    je        1f                                 # skip card mark if null
+    movl      rSELF,%ecx
+    movl      offField_clazz(%eax),%eax          # eax<- method->clazz
+    movl      offThread_cardTable(%ecx),%ecx       # get card table base
+    shrl      $GC_CARD_SHIFT,%eax               # head to card number
+    movb      %cl,(%ecx,%eax)                    # mark card
+1:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_SPUT_OBJECT_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_OBJECT_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: x86/OP_SPUT_BOOLEAN.S */
+/* File: x86/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_BOOLEAN_resolve                # if not, make it so
+.LOP_SPUT_BOOLEAN_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_BOOLEAN_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_BOOLEAN_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_BYTE: /* 0x6b */
+/* File: x86/OP_SPUT_BYTE.S */
+/* File: x86/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_BYTE_resolve                # if not, make it so
+.LOP_SPUT_BYTE_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_BYTE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_BYTE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_CHAR: /* 0x6c */
+/* File: x86/OP_SPUT_CHAR.S */
+/* File: x86/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_CHAR_resolve                # if not, make it so
+.LOP_SPUT_CHAR_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_CHAR_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_CHAR_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_SHORT: /* 0x6d */
+/* File: x86/OP_SPUT_SHORT.S */
+/* File: x86/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_SHORT_resolve                # if not, make it so
+.LOP_SPUT_SHORT_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_SHORT_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_SHORT_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: x86/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 */
+    movl      rSELF,%eax
+    movzwl    2(rPC),%ecx                 # ecx<- BBBB
+    movl      offThread_methodClassDex(%eax),%eax  # eax<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%eax),%eax   # eax<- pDvmDex->pResMethods
+    movl      (%eax,%ecx,4),%eax          # eax<- resolved baseMethod
+    testl     %eax,%eax                   # already resolved?
+    jne       .LOP_INVOKE_VIRTUAL_continue        # yes, continue
+    movl      rSELF,%eax
+    movl      %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    movl      offThread_method(%eax),%eax   # eax<- self->method
+    movl      offMethod_clazz(%eax),%eax  # ecx<- method->clazz
+    movl      %eax,OUT_ARG0(%esp)         # arg0<- clazz
+    movl      $METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- flags
+    call      dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl     %eax,%eax                   # got null?
+    jne       .LOP_INVOKE_VIRTUAL_continue        # no, continue
+    jmp       common_exceptionThrown      # yes, handle exception
+
+    /* At this point:
+     *   eax = resolved base method
+     *   ecx = scratch
+     */
+.LOP_INVOKE_VIRTUAL_continue:
+    movzwl    4(rPC),%ecx               # ecx<- GFED or CCCC
+    .if       (!0)
+    andl      $0xf,%ecx                # ecx<- D (or stays CCCC)
+    .endif
+    GET_VREG_R  %ecx %ecx               # ecx<- "this"
+    movzwl    offMethod_methodIndex(%eax),%eax  # eax<- baseMethod->methodIndex
+    testl     %ecx,%ecx                 # null this?
+    je        common_errNullObject      # go if so
+    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]
+    jmp       common_invokeMethodNoRange
+
+/* ------------------------------ */
+.L_OP_INVOKE_SUPER: /* 0x6f */
+/* File: x86/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 */
+    movl      rSELF,rINST
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(rINST),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved baseMethod
+    movl      offThread_method(rINST),%eax # eax<- method
+    movzwl    4(rPC),rINST              # rINST<- GFED or CCCC
+    .if       (!0)
+    andl      $0xf,rINST               # rINST<- D (or stays CCCC)
+    .endif
+    GET_VREG_R  rINST rINST             # rINST<- "this" ptr
+    testl     rINST,rINST               # null "this"?
+    je        common_errNullObject      # yes, throw
+    movl      offMethod_clazz(%eax),%eax # eax<- method->clazz
+    testl     %ecx,%ecx                 # already resolved?
+    je       .LOP_INVOKE_SUPER_resolve
+    /*
+     * At this point:
+     *  ecx = resolved base method [r0]
+     *  eax = method->clazz [r9]
+     */
+.LOP_INVOKE_SUPER_continue:
+    movl    offClassObject_super(%eax),%eax   # eax<- method->clazz->super
+    movzwl  offMethod_methodIndex(%ecx),%ecx  # ecx<- baseMthod->methodIndex
+    cmpl    offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+    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]
+    jmp     common_invokeMethodNoRange
+
+
+    /* At this point:
+     * ecx = null (needs to be resolved base method)
+     * eax = method->clazz
+    */
+.LOP_INVOKE_SUPER_resolve:
+    SPILL_TMP1(%eax)                    # method->clazz
+    movl    %eax,OUT_ARG0(%esp)         # arg0<- method->clazz
+    movzwl  2(rPC),%ecx                 # ecx<- BBBB
+    movl    $METHOD_VIRTUAL,OUT_ARG2(%esp)  # arg2<- resolver method type
+    movl    %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    call    dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl   %eax,%eax                   # got null?
+    movl    %eax,%ecx                   # ecx<- resolved base method
+    UNSPILL_TMP1(%eax)                  # restore method->clazz
+    jne     .LOP_INVOKE_SUPER_continue        # good to go - continue
+    jmp     common_exceptionThrown      # handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  ecx = resolved base method
+     */
+.LOP_INVOKE_SUPER_nsm:
+    movl    offMethod_name(%ecx),%eax
+    jmp     common_errNoSuchMethod
+
+/* ------------------------------ */
+.L_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: x86/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 */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movzwl    4(rPC),rIBASE            # rIBASE<- GFED or CCCC
+    movl      (%ecx,%eax,4),%eax       # eax<- resolved methodToCall
+    .if       (!0)
+    andl      $0xf,rIBASE             # rIBASE<- D (or stays CCCC)
+    .endif
+    testl     %eax,%eax                # already resolved?
+    GET_VREG_R  %ecx rIBASE            # ecx<- "this" ptr
+    je        .LOP_INVOKE_DIRECT_resolve      # not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+    testl     %ecx,%ecx                # null "this"?
+    jne       common_invokeMethodNoRange  # no, continue on
+    jmp       common_errNullObject
+
+    /*
+     * On entry:
+     *   TMP_SPILL  <- "this" register
+     * Things a bit ugly on this path, but it's the less
+     * frequent one.  We'll have to do some reloading.
+     */
+.LOP_INVOKE_DIRECT_resolve:
+     SPILL_TMP1(%ecx)
+     movl     rSELF,%ecx
+     movl     offThread_method(%ecx),%ecx  # ecx<- self->method
+     movzwl   2(rPC),%eax      # reference (BBBB or CCCC)
+     movl     offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+     movl     $METHOD_DIRECT,OUT_ARG2(%esp)
+     movl     %eax,OUT_ARG1(%esp)
+     movl     %ecx,OUT_ARG0(%esp)
+     call     dvmResolveMethod # eax<- call(clazz, ref, flags)
+     UNSPILL_TMP1(%ecx)
+     testl    %eax,%eax
+     jne      .LOP_INVOKE_DIRECT_finish
+     jmp      common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_INVOKE_STATIC: /* 0x71 */
+/* File: x86/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 */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved methodToCall
+    testl     %eax,%eax
+    jne       common_invokeMethodNoRange
+    movl      rSELF,%ecx
+    movl      offThread_method(%ecx),%ecx # ecx<- self->method
+    movzwl    2(rPC),%eax
+    movl      offMethod_clazz(%ecx),%ecx# ecx<- method->clazz
+    movl      %eax,OUT_ARG1(%esp)       # arg1<- BBBB
+    movl      %ecx,OUT_ARG0(%esp)       # arg0<- clazz
+    movl      $METHOD_STATIC,%eax
+    movl      %eax,OUT_ARG2(%esp)       # arg2<- flags
+    call      dvmResolveMethod          # call(clazz,ref,flags)
+    testl     %eax,%eax                 # got null?
+    jne       common_invokeMethodNoRange
+    jmp       common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: x86/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 */
+    movzwl     4(rPC),%eax              # eax<- FEDC or CCCC
+    movl       rSELF,%ecx
+    .if        (!0)
+    andl       $0xf,%eax               # eax<- C (or stays CCCC)
+    .endif
+    GET_VREG_R   %eax %eax              # eax<- "this"
+    EXPORT_PC
+    testl      %eax,%eax                # null this?
+    je         common_errNullObject     # yes, fail
+    movl       offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
+    movl       %eax,OUT_ARG0(%esp)                 # arg0<- class
+    movl       offThread_methodClassDex(%ecx),%eax   # eax<- methodClassDex
+    movl       offThread_method(%ecx),%ecx           # ecx<- method
+    movl       %eax,OUT_ARG3(%esp)                 # arg3<- dex
+    movzwl     2(rPC),%eax                         # eax<- BBBB
+    movl       %ecx,OUT_ARG2(%esp)                 # arg2<- method
+    movl       %eax,OUT_ARG1(%esp)                 # arg1<- BBBB
+    call       dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
+    testl      %eax,%eax
+    je         common_exceptionThrown
+    jmp        common_invokeMethodNoRange
+
+/* ------------------------------ */
+.L_OP_UNUSED_73: /* 0x73 */
+/* File: x86/OP_UNUSED_73.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: x86/OP_INVOKE_VIRTUAL_RANGE.S */
+/* File: x86/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 */
+    movl      rSELF,%eax
+    movzwl    2(rPC),%ecx                 # ecx<- BBBB
+    movl      offThread_methodClassDex(%eax),%eax  # eax<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%eax),%eax   # eax<- pDvmDex->pResMethods
+    movl      (%eax,%ecx,4),%eax          # eax<- resolved baseMethod
+    testl     %eax,%eax                   # already resolved?
+    jne       .LOP_INVOKE_VIRTUAL_RANGE_continue        # yes, continue
+    movl      rSELF,%eax
+    movl      %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    movl      offThread_method(%eax),%eax   # eax<- self->method
+    movl      offMethod_clazz(%eax),%eax  # ecx<- method->clazz
+    movl      %eax,OUT_ARG0(%esp)         # arg0<- clazz
+    movl      $METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- flags
+    call      dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl     %eax,%eax                   # got null?
+    jne       .LOP_INVOKE_VIRTUAL_RANGE_continue        # no, continue
+    jmp       common_exceptionThrown      # yes, handle exception
+
+    /* At this point:
+     *   eax = resolved base method
+     *   ecx = scratch
+     */
+.LOP_INVOKE_VIRTUAL_RANGE_continue:
+    movzwl    4(rPC),%ecx               # ecx<- GFED or CCCC
+    .if       (!1)
+    andl      $0xf,%ecx                # ecx<- D (or stays CCCC)
+    .endif
+    GET_VREG_R  %ecx %ecx               # ecx<- "this"
+    movzwl    offMethod_methodIndex(%eax),%eax  # eax<- baseMethod->methodIndex
+    testl     %ecx,%ecx                 # null this?
+    je        common_errNullObject      # go if so
+    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]
+    jmp       common_invokeMethodRange
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: x86/OP_INVOKE_SUPER_RANGE.S */
+/* File: x86/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 */
+    movl      rSELF,rINST
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(rINST),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved baseMethod
+    movl      offThread_method(rINST),%eax # eax<- method
+    movzwl    4(rPC),rINST              # rINST<- GFED or CCCC
+    .if       (!1)
+    andl      $0xf,rINST               # rINST<- D (or stays CCCC)
+    .endif
+    GET_VREG_R  rINST rINST             # rINST<- "this" ptr
+    testl     rINST,rINST               # null "this"?
+    je        common_errNullObject      # yes, throw
+    movl      offMethod_clazz(%eax),%eax # eax<- method->clazz
+    testl     %ecx,%ecx                 # already resolved?
+    je       .LOP_INVOKE_SUPER_RANGE_resolve
+    /*
+     * At this point:
+     *  ecx = resolved base method [r0]
+     *  eax = method->clazz [r9]
+     */
+.LOP_INVOKE_SUPER_RANGE_continue:
+    movl    offClassObject_super(%eax),%eax   # eax<- method->clazz->super
+    movzwl  offMethod_methodIndex(%ecx),%ecx  # ecx<- baseMthod->methodIndex
+    cmpl    offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+    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]
+    jmp     common_invokeMethodRange
+
+
+    /* At this point:
+     * ecx = null (needs to be resolved base method)
+     * eax = method->clazz
+    */
+.LOP_INVOKE_SUPER_RANGE_resolve:
+    SPILL_TMP1(%eax)                    # method->clazz
+    movl    %eax,OUT_ARG0(%esp)         # arg0<- method->clazz
+    movzwl  2(rPC),%ecx                 # ecx<- BBBB
+    movl    $METHOD_VIRTUAL,OUT_ARG2(%esp)  # arg2<- resolver method type
+    movl    %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    call    dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl   %eax,%eax                   # got null?
+    movl    %eax,%ecx                   # ecx<- resolved base method
+    UNSPILL_TMP1(%eax)                  # restore method->clazz
+    jne     .LOP_INVOKE_SUPER_RANGE_continue        # good to go - continue
+    jmp     common_exceptionThrown      # handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  ecx = resolved base method
+     */
+.LOP_INVOKE_SUPER_RANGE_nsm:
+    movl    offMethod_name(%ecx),%eax
+    jmp     common_errNoSuchMethod
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: x86/OP_INVOKE_DIRECT_RANGE.S */
+/* File: x86/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 */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movzwl    4(rPC),rIBASE            # rIBASE<- GFED or CCCC
+    movl      (%ecx,%eax,4),%eax       # eax<- resolved methodToCall
+    .if       (!1)
+    andl      $0xf,rIBASE             # rIBASE<- D (or stays CCCC)
+    .endif
+    testl     %eax,%eax                # already resolved?
+    GET_VREG_R  %ecx rIBASE            # ecx<- "this" ptr
+    je        .LOP_INVOKE_DIRECT_RANGE_resolve      # not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    testl     %ecx,%ecx                # null "this"?
+    jne       common_invokeMethodRange  # no, continue on
+    jmp       common_errNullObject
+
+    /*
+     * On entry:
+     *   TMP_SPILL  <- "this" register
+     * Things a bit ugly on this path, but it's the less
+     * frequent one.  We'll have to do some reloading.
+     */
+.LOP_INVOKE_DIRECT_RANGE_resolve:
+     SPILL_TMP1(%ecx)
+     movl     rSELF,%ecx
+     movl     offThread_method(%ecx),%ecx  # ecx<- self->method
+     movzwl   2(rPC),%eax      # reference (BBBB or CCCC)
+     movl     offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+     movl     $METHOD_DIRECT,OUT_ARG2(%esp)
+     movl     %eax,OUT_ARG1(%esp)
+     movl     %ecx,OUT_ARG0(%esp)
+     call     dvmResolveMethod # eax<- call(clazz, ref, flags)
+     UNSPILL_TMP1(%ecx)
+     testl    %eax,%eax
+     jne      .LOP_INVOKE_DIRECT_RANGE_finish
+     jmp      common_exceptionThrown
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: x86/OP_INVOKE_STATIC_RANGE.S */
+/* File: x86/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 */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved methodToCall
+    testl     %eax,%eax
+    jne       common_invokeMethodRange
+    movl      rSELF,%ecx
+    movl      offThread_method(%ecx),%ecx # ecx<- self->method
+    movzwl    2(rPC),%eax
+    movl      offMethod_clazz(%ecx),%ecx# ecx<- method->clazz
+    movl      %eax,OUT_ARG1(%esp)       # arg1<- BBBB
+    movl      %ecx,OUT_ARG0(%esp)       # arg0<- clazz
+    movl      $METHOD_STATIC,%eax
+    movl      %eax,OUT_ARG2(%esp)       # arg2<- flags
+    call      dvmResolveMethod          # call(clazz,ref,flags)
+    testl     %eax,%eax                 # got null?
+    jne       common_invokeMethodRange
+    jmp       common_exceptionThrown
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: x86/OP_INVOKE_INTERFACE_RANGE.S */
+/* File: x86/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 */
+    movzwl     4(rPC),%eax              # eax<- FEDC or CCCC
+    movl       rSELF,%ecx
+    .if        (!1)
+    andl       $0xf,%eax               # eax<- C (or stays CCCC)
+    .endif
+    GET_VREG_R   %eax %eax              # eax<- "this"
+    EXPORT_PC
+    testl      %eax,%eax                # null this?
+    je         common_errNullObject     # yes, fail
+    movl       offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
+    movl       %eax,OUT_ARG0(%esp)                 # arg0<- class
+    movl       offThread_methodClassDex(%ecx),%eax   # eax<- methodClassDex
+    movl       offThread_method(%ecx),%ecx           # ecx<- method
+    movl       %eax,OUT_ARG3(%esp)                 # arg3<- dex
+    movzwl     2(rPC),%eax                         # eax<- BBBB
+    movl       %ecx,OUT_ARG2(%esp)                 # arg2<- method
+    movl       %eax,OUT_ARG1(%esp)                 # arg1<- BBBB
+    call       dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
+    testl      %eax,%eax
+    je         common_exceptionThrown
+    jmp        common_invokeMethodRange
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_79: /* 0x79 */
+/* File: x86/OP_UNUSED_79.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7A: /* 0x7a */
+/* File: x86/OP_UNUSED_7A.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_NEG_INT: /* 0x7b */
+/* File: x86/OP_NEG_INT.S */
+/* File: x86/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op eax".
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx           # ecx<- A+
+    sarl     $4,rINST             # rINST<- B
+    GET_VREG_R %eax rINST           # eax<- vB
+    andb     $0xf,%cl              # ecx<- A
+    
+    
+    negl %eax
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_NOT_INT: /* 0x7c */
+/* File: x86/OP_NOT_INT.S */
+/* File: x86/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op eax".
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx           # ecx<- A+
+    sarl     $4,rINST             # rINST<- B
+    GET_VREG_R %eax rINST           # eax<- vB
+    andb     $0xf,%cl              # ecx<- A
+    
+    
+    notl %eax
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_NEG_LONG: /* 0x7d */
+/* File: x86/OP_NEG_LONG.S */
+    /* unop vA, vB */
+    movzbl    rINSTbl,%ecx        # ecx<- BA
+    sarl      $4,%ecx            # ecx<- B
+    andb      $0xf,rINSTbl       # rINST<- A
+    GET_VREG_WORD %eax %ecx 0     # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1     # ecx<- v[B+1]
+    negl      %eax
+    adcl      $0,%ecx
+    negl      %ecx
+    SET_VREG_WORD %eax rINST 0    # v[A+0]<- eax
+    FETCH_INST_OPCODE 1 %eax
+    SET_VREG_WORD %ecx rINST 1    # v[A+1]<- ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_NOT_LONG: /* 0x7e */
+/* File: x86/OP_NOT_LONG.S */
+    /* unop vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- BA
+    sarl      $4,%ecx           # ecx<- B
+    andb      $0xf,rINSTbl      # rINST<- A
+    GET_VREG_WORD %eax %ecx 0    # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1    # ecx<- v[B+1]
+    notl      %eax
+    notl      %ecx
+    SET_VREG_WORD %eax rINST 0   # v[A+0]<- eax
+    FETCH_INST_OPCODE 1 %eax
+    SET_VREG_WORD %ecx rINST 1   # v[A+1]<- ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_NEG_FLOAT: /* 0x7f */
+/* File: x86/OP_NEG_FLOAT.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    flds    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    fchs
+    fstps  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_NEG_DOUBLE: /* 0x80 */
+/* File: x86/OP_NEG_DOUBLE.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    fldl    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    fchs
+    fstpl  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_INT_TO_LONG: /* 0x81 */
+/* File: x86/OP_INT_TO_LONG.S */
+    /* int to long vA, vB */
+    movzbl  rINSTbl,%eax                # eax<- +A
+    sarl    $4,%eax                    # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    andb    $0xf,rINSTbl               # rINST<- A
+    SPILL(rIBASE)                       # cltd trashes rIBASE/edx
+    cltd                                # rINST:eax<- sssssssBBBBBBBB
+    SET_VREG_WORD rIBASE rINST 1        # v[A+1]<- rIBASE/rPC
+    FETCH_INST_OPCODE 1 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0          # v[A+0]<- %eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: x86/OP_INT_TO_FLOAT.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    fildl    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    
+    fstps  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: x86/OP_INT_TO_DOUBLE.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    fildl    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    
+    fstpl  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_LONG_TO_INT: /* 0x84 */
+/* File: x86/OP_LONG_TO_INT.S */
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+/* File: x86/OP_MOVE.S */
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    movzbl rINSTbl,%eax          # eax<- BA
+    andb   $0xf,%al             # eax<- A
+    shrl   $4,rINST            # rINST<- B
+    GET_VREG_R rINST rINST
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG rINST %eax           # fp[A]<-fp[B]
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: x86/OP_LONG_TO_FLOAT.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    fildll    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    
+    fstps  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: x86/OP_LONG_TO_DOUBLE.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    fildll    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    
+    fstpl  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: x86/OP_FLOAT_TO_INT.S */
+/* File: x86/cvtfp_int.S */
+/* On fp to int conversions, Java requires that
+ * if the result > maxint, it should be clamped to maxint.  If it is less
+ * than minint, it should be clamped to minint.  If it is a nan, the result
+ * should be zero.  Further, the rounding mode is to truncate.  This model
+ * differs from what is delivered normally via the x86 fpu, so we have
+ * to play some games.
+ */
+    /* float/double to int/long vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- A+
+    sarl      $4,rINST         # rINST<- B
+    .if 0
+    fldl     (rFP,rINST,4)       # %st0<- vB
+    .else
+    flds     (rFP,rINST,4)       # %st0<- vB
+    .endif
+    ftst
+    fnstcw   LOCAL0_OFFSET(%ebp)      # remember original rounding mode
+    movzwl   LOCAL0_OFFSET(%ebp),%eax
+    movb     $0xc,%ah
+    movw     %ax,LOCAL0_OFFSET+2(%ebp)
+    fldcw    LOCAL0_OFFSET+2(%ebp)    # set "to zero" rounding mode
+    andb     $0xf,%cl                # ecx<- A
+    .if 0
+    fistpll  (rFP,%ecx,4)             # convert and store
+    .else
+    fistpl   (rFP,%ecx,4)             # convert and store
+    .endif
+    fldcw    LOCAL0_OFFSET(%ebp)      # restore previous rounding mode
+    .if 0
+    movl     $0x80000000,%eax
+    xorl     4(rFP,%ecx,4),%eax
+    orl      (rFP,%ecx,4),%eax
+    .else
+    cmpl     $0x80000000,(rFP,%ecx,4)
+    .endif
+    je       .LOP_FLOAT_TO_INT_special_case # fix up result
+
+.LOP_FLOAT_TO_INT_finish:
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_FLOAT_TO_INT_special_case:
+    fnstsw   %ax
+    sahf
+    jp       .LOP_FLOAT_TO_INT_isNaN
+    adcl     $-1,(rFP,%ecx,4)
+    .if 0
+    adcl     $-1,4(rFP,%ecx,4)
+    .endif
+   jmp       .LOP_FLOAT_TO_INT_finish
+.LOP_FLOAT_TO_INT_isNaN:
+    movl      $0,(rFP,%ecx,4)
+    .if 0
+    movl      $0,4(rFP,%ecx,4)
+    .endif
+    jmp       .LOP_FLOAT_TO_INT_finish
+
+
+/* ------------------------------ */
+.L_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: x86/OP_FLOAT_TO_LONG.S */
+/* File: x86/cvtfp_int.S */
+/* On fp to int conversions, Java requires that
+ * if the result > maxint, it should be clamped to maxint.  If it is less
+ * than minint, it should be clamped to minint.  If it is a nan, the result
+ * should be zero.  Further, the rounding mode is to truncate.  This model
+ * differs from what is delivered normally via the x86 fpu, so we have
+ * to play some games.
+ */
+    /* float/double to int/long vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- A+
+    sarl      $4,rINST         # rINST<- B
+    .if 0
+    fldl     (rFP,rINST,4)       # %st0<- vB
+    .else
+    flds     (rFP,rINST,4)       # %st0<- vB
+    .endif
+    ftst
+    fnstcw   LOCAL0_OFFSET(%ebp)      # remember original rounding mode
+    movzwl   LOCAL0_OFFSET(%ebp),%eax
+    movb     $0xc,%ah
+    movw     %ax,LOCAL0_OFFSET+2(%ebp)
+    fldcw    LOCAL0_OFFSET+2(%ebp)    # set "to zero" rounding mode
+    andb     $0xf,%cl                # ecx<- A
+    .if 1
+    fistpll  (rFP,%ecx,4)             # convert and store
+    .else
+    fistpl   (rFP,%ecx,4)             # convert and store
+    .endif
+    fldcw    LOCAL0_OFFSET(%ebp)      # restore previous rounding mode
+    .if 1
+    movl     $0x80000000,%eax
+    xorl     4(rFP,%ecx,4),%eax
+    orl      (rFP,%ecx,4),%eax
+    .else
+    cmpl     $0x80000000,(rFP,%ecx,4)
+    .endif
+    je       .LOP_FLOAT_TO_LONG_special_case # fix up result
+
+.LOP_FLOAT_TO_LONG_finish:
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_FLOAT_TO_LONG_special_case:
+    fnstsw   %ax
+    sahf
+    jp       .LOP_FLOAT_TO_LONG_isNaN
+    adcl     $-1,(rFP,%ecx,4)
+    .if 1
+    adcl     $-1,4(rFP,%ecx,4)
+    .endif
+   jmp       .LOP_FLOAT_TO_LONG_finish
+.LOP_FLOAT_TO_LONG_isNaN:
+    movl      $0,(rFP,%ecx,4)
+    .if 1
+    movl      $0,4(rFP,%ecx,4)
+    .endif
+    jmp       .LOP_FLOAT_TO_LONG_finish
+
+
+/* ------------------------------ */
+.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: x86/OP_FLOAT_TO_DOUBLE.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    flds    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    
+    fstpl  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: x86/OP_DOUBLE_TO_INT.S */
+/* File: x86/cvtfp_int.S */
+/* On fp to int conversions, Java requires that
+ * if the result > maxint, it should be clamped to maxint.  If it is less
+ * than minint, it should be clamped to minint.  If it is a nan, the result
+ * should be zero.  Further, the rounding mode is to truncate.  This model
+ * differs from what is delivered normally via the x86 fpu, so we have
+ * to play some games.
+ */
+    /* float/double to int/long vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- A+
+    sarl      $4,rINST         # rINST<- B
+    .if 1
+    fldl     (rFP,rINST,4)       # %st0<- vB
+    .else
+    flds     (rFP,rINST,4)       # %st0<- vB
+    .endif
+    ftst
+    fnstcw   LOCAL0_OFFSET(%ebp)      # remember original rounding mode
+    movzwl   LOCAL0_OFFSET(%ebp),%eax
+    movb     $0xc,%ah
+    movw     %ax,LOCAL0_OFFSET+2(%ebp)
+    fldcw    LOCAL0_OFFSET+2(%ebp)    # set "to zero" rounding mode
+    andb     $0xf,%cl                # ecx<- A
+    .if 0
+    fistpll  (rFP,%ecx,4)             # convert and store
+    .else
+    fistpl   (rFP,%ecx,4)             # convert and store
+    .endif
+    fldcw    LOCAL0_OFFSET(%ebp)      # restore previous rounding mode
+    .if 0
+    movl     $0x80000000,%eax
+    xorl     4(rFP,%ecx,4),%eax
+    orl      (rFP,%ecx,4),%eax
+    .else
+    cmpl     $0x80000000,(rFP,%ecx,4)
+    .endif
+    je       .LOP_DOUBLE_TO_INT_special_case # fix up result
+
+.LOP_DOUBLE_TO_INT_finish:
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_DOUBLE_TO_INT_special_case:
+    fnstsw   %ax
+    sahf
+    jp       .LOP_DOUBLE_TO_INT_isNaN
+    adcl     $-1,(rFP,%ecx,4)
+    .if 0
+    adcl     $-1,4(rFP,%ecx,4)
+    .endif
+   jmp       .LOP_DOUBLE_TO_INT_finish
+.LOP_DOUBLE_TO_INT_isNaN:
+    movl      $0,(rFP,%ecx,4)
+    .if 0
+    movl      $0,4(rFP,%ecx,4)
+    .endif
+    jmp       .LOP_DOUBLE_TO_INT_finish
+
+
+/* ------------------------------ */
+.L_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: x86/OP_DOUBLE_TO_LONG.S */
+/* File: x86/cvtfp_int.S */
+/* On fp to int conversions, Java requires that
+ * if the result > maxint, it should be clamped to maxint.  If it is less
+ * than minint, it should be clamped to minint.  If it is a nan, the result
+ * should be zero.  Further, the rounding mode is to truncate.  This model
+ * differs from what is delivered normally via the x86 fpu, so we have
+ * to play some games.
+ */
+    /* float/double to int/long vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- A+
+    sarl      $4,rINST         # rINST<- B
+    .if 1
+    fldl     (rFP,rINST,4)       # %st0<- vB
+    .else
+    flds     (rFP,rINST,4)       # %st0<- vB
+    .endif
+    ftst
+    fnstcw   LOCAL0_OFFSET(%ebp)      # remember original rounding mode
+    movzwl   LOCAL0_OFFSET(%ebp),%eax
+    movb     $0xc,%ah
+    movw     %ax,LOCAL0_OFFSET+2(%ebp)
+    fldcw    LOCAL0_OFFSET+2(%ebp)    # set "to zero" rounding mode
+    andb     $0xf,%cl                # ecx<- A
+    .if 1
+    fistpll  (rFP,%ecx,4)             # convert and store
+    .else
+    fistpl   (rFP,%ecx,4)             # convert and store
+    .endif
+    fldcw    LOCAL0_OFFSET(%ebp)      # restore previous rounding mode
+    .if 1
+    movl     $0x80000000,%eax
+    xorl     4(rFP,%ecx,4),%eax
+    orl      (rFP,%ecx,4),%eax
+    .else
+    cmpl     $0x80000000,(rFP,%ecx,4)
+    .endif
+    je       .LOP_DOUBLE_TO_LONG_special_case # fix up result
+
+.LOP_DOUBLE_TO_LONG_finish:
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_DOUBLE_TO_LONG_special_case:
+    fnstsw   %ax
+    sahf
+    jp       .LOP_DOUBLE_TO_LONG_isNaN
+    adcl     $-1,(rFP,%ecx,4)
+    .if 1
+    adcl     $-1,4(rFP,%ecx,4)
+    .endif
+   jmp       .LOP_DOUBLE_TO_LONG_finish
+.LOP_DOUBLE_TO_LONG_isNaN:
+    movl      $0,(rFP,%ecx,4)
+    .if 1
+    movl      $0,4(rFP,%ecx,4)
+    .endif
+    jmp       .LOP_DOUBLE_TO_LONG_finish
+
+
+/* ------------------------------ */
+.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: x86/OP_DOUBLE_TO_FLOAT.S */
+/* File: x86/fpcvt.S */
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $4,rINST         # rINST<- B
+    fldl    (rFP,rINST,4)      # %st0<- vB
+    andb     $0xf,%cl          # ecx<- A
+    
+    fstps  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_INT_TO_BYTE: /* 0x8d */
+/* File: x86/OP_INT_TO_BYTE.S */
+/* File: x86/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op eax".
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx           # ecx<- A+
+    sarl     $4,rINST             # rINST<- B
+    GET_VREG_R %eax rINST           # eax<- vB
+    andb     $0xf,%cl              # ecx<- A
+    
+    
+    movsbl %al,%eax
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_INT_TO_CHAR: /* 0x8e */
+/* File: x86/OP_INT_TO_CHAR.S */
+/* File: x86/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op eax".
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx           # ecx<- A+
+    sarl     $4,rINST             # rINST<- B
+    GET_VREG_R %eax rINST           # eax<- vB
+    andb     $0xf,%cl              # ecx<- A
+    
+    
+    movzwl %ax,%eax
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_INT_TO_SHORT: /* 0x8f */
+/* File: x86/OP_INT_TO_SHORT.S */
+/* File: x86/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op eax".
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx           # ecx<- A+
+    sarl     $4,rINST             # rINST<- B
+    GET_VREG_R %eax rINST           # eax<- vB
+    andb     $0xf,%cl              # ecx<- A
+    
+    
+    movswl %ax,%eax
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_ADD_INT: /* 0x90 */
+/* File: x86/OP_ADD_INT.S */
+/* File: x86/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = eax op (rFP,%ecx,4)".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int, sub-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax   # eax<- BB
+    movzbl   3(rPC),%ecx   # ecx<- CC
+    GET_VREG_R %eax %eax   # eax<- vBB
+    addl (rFP,%ecx,4),%eax                 # ex: addl    (rFP,%ecx,4),%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SUB_INT: /* 0x91 */
+/* File: x86/OP_SUB_INT.S */
+/* File: x86/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = eax op (rFP,%ecx,4)".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int, sub-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax   # eax<- BB
+    movzbl   3(rPC),%ecx   # ecx<- CC
+    GET_VREG_R %eax %eax   # eax<- vBB
+    subl   (rFP,%ecx,4),%eax                 # ex: addl    (rFP,%ecx,4),%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_INT: /* 0x92 */
+/* File: x86/OP_MUL_INT.S */
+    /*
+     * 32-bit binary multiplication.
+     */
+    /* mul vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    SPILL(rIBASE)
+    imull    (rFP,%ecx,4),%eax      # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_DIV_INT: /* 0x93 */
+/* File: x86/OP_DIV_INT.S */
+/* File: x86/bindiv.S */
+
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    SPILL(rIBASE)
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $-1,%ecx
+    jne      .LOP_DIV_INT_continue_div
+    cmpl     $0x80000000,%eax
+    jne      .LOP_DIV_INT_continue_div
+    movl     $0x80000000,%eax
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_DIV_INT_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_REM_INT: /* 0x94 */
+/* File: x86/OP_REM_INT.S */
+/* File: x86/bindiv.S */
+
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    SPILL(rIBASE)
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $-1,%ecx
+    jne      .LOP_REM_INT_continue_div
+    cmpl     $0x80000000,%eax
+    jne      .LOP_REM_INT_continue_div
+    movl     $0,rIBASE
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_REM_INT_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AND_INT: /* 0x95 */
+/* File: x86/OP_AND_INT.S */
+/* File: x86/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = eax op (rFP,%ecx,4)".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int, sub-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax   # eax<- BB
+    movzbl   3(rPC),%ecx   # ecx<- CC
+    GET_VREG_R %eax %eax   # eax<- vBB
+    andl   (rFP,%ecx,4),%eax                 # ex: addl    (rFP,%ecx,4),%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_OR_INT: /* 0x96 */
+/* File: x86/OP_OR_INT.S */
+/* File: x86/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = eax op (rFP,%ecx,4)".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int, sub-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax   # eax<- BB
+    movzbl   3(rPC),%ecx   # ecx<- CC
+    GET_VREG_R %eax %eax   # eax<- vBB
+    orl   (rFP,%ecx,4),%eax                 # ex: addl    (rFP,%ecx,4),%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_XOR_INT: /* 0x97 */
+/* File: x86/OP_XOR_INT.S */
+/* File: x86/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = eax op (rFP,%ecx,4)".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int, sub-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax   # eax<- BB
+    movzbl   3(rPC),%ecx   # ecx<- CC
+    GET_VREG_R %eax %eax   # eax<- vBB
+    xorl   (rFP,%ecx,4),%eax                 # ex: addl    (rFP,%ecx,4),%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHL_INT: /* 0x98 */
+/* File: x86/OP_SHL_INT.S */
+/* File: x86/binop1.S */
+    /*
+     * Generic 32-bit binary operation in which both operands loaded to
+     * registers (op0 in eax, op1 in ecx).
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    sall    %cl,%eax                          # ex: addl    %ecx,%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHR_INT: /* 0x99 */
+/* File: x86/OP_SHR_INT.S */
+/* File: x86/binop1.S */
+    /*
+     * Generic 32-bit binary operation in which both operands loaded to
+     * registers (op0 in eax, op1 in ecx).
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    sarl    %cl,%eax                          # ex: addl    %ecx,%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_USHR_INT: /* 0x9a */
+/* File: x86/OP_USHR_INT.S */
+/* File: x86/binop1.S */
+    /*
+     * Generic 32-bit binary operation in which both operands loaded to
+     * registers (op0 in eax, op1 in ecx).
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    shrl    %cl,%eax                          # ex: addl    %ecx,%eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_ADD_LONG: /* 0x9b */
+/* File: x86/OP_ADD_LONG.S */
+/* File: x86/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop vAA, vBB, vCC */
+
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)                       # save rIBASE
+    GET_VREG_WORD rIBASE %eax 0         # rIBASE<- v[BB+0]
+    GET_VREG_WORD %eax %eax 1           # eax<- v[BB+1]
+    addl (rFP,%ecx,4),rIBASE         # ex: addl   (rFP,%ecx,4),rIBASE
+    adcl 4(rFP,%ecx,4),%eax         # ex: adcl   4(rFP,%ecx,4),%eax
+    SET_VREG_WORD rIBASE rINST 0        # v[AA+0] <- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 1          # v[AA+1] <- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SUB_LONG: /* 0x9c */
+/* File: x86/OP_SUB_LONG.S */
+/* File: x86/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop vAA, vBB, vCC */
+
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)                       # save rIBASE
+    GET_VREG_WORD rIBASE %eax 0         # rIBASE<- v[BB+0]
+    GET_VREG_WORD %eax %eax 1           # eax<- v[BB+1]
+    subl (rFP,%ecx,4),rIBASE         # ex: addl   (rFP,%ecx,4),rIBASE
+    sbbl 4(rFP,%ecx,4),%eax         # ex: adcl   4(rFP,%ecx,4),%eax
+    SET_VREG_WORD rIBASE rINST 0        # v[AA+0] <- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 1          # v[AA+1] <- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_LONG: /* 0x9d */
+/* File: x86/OP_MUL_LONG.S */
+    /*
+     * Signed 64-bit integer multiply.
+     *
+     * We could definately use more free registers for
+     * this code.   We spill rINSTw (ebx),
+     * giving us eax, ebc, ecx and edx as computational
+     * temps.  On top of that, we'll spill edi (rFP)
+     * for use as the vB pointer and esi (rPC) for use
+     * as the vC pointer.  Yuck.
+     */
+    /* mul-long vAA, vBB, vCC */
+    movzbl    2(rPC),%eax              # eax<- B
+    movzbl    3(rPC),%ecx              # ecx<- C
+    SPILL_TMP2(%esi)                   # save Dalvik PC
+    SPILL(rFP)
+    SPILL(rINST)
+    SPILL(rIBASE)
+    leal      (rFP,%eax,4),%esi        # esi<- &v[B]
+    leal      (rFP,%ecx,4),rFP         # rFP<- &v[C]
+    movl      4(%esi),%ecx             # ecx<- Bmsw
+    imull     (rFP),%ecx               # ecx<- (Bmsw*Clsw)
+    movl      4(rFP),%eax              # eax<- Cmsw
+    imull     (%esi),%eax              # eax<- (Cmsw*Blsw)
+    addl      %eax,%ecx                # ecx<- (Bmsw*Clsw)+(Cmsw*Blsw)
+    movl      (rFP),%eax               # eax<- Clsw
+    mull      (%esi)                   # eax<- (Clsw*Alsw)
+    UNSPILL(rINST)
+    UNSPILL(rFP)
+    leal      (%ecx,rIBASE),rIBASE # full result now in rIBASE:%eax
+    UNSPILL_TMP2(%esi)             # Restore Dalvik PC
+    FETCH_INST_OPCODE 2 %ecx       # Fetch next instruction
+    movl      rIBASE,4(rFP,rINST,4)# v[B+1]<- rIBASE
+    UNSPILL(rIBASE)
+    movl      %eax,(rFP,rINST,4)   # v[B]<- %eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_DIV_LONG: /* 0x9e */
+/* File: x86/OP_DIV_LONG.S */
+    /* div vAA, vBB, vCC */
+    movzbl    3(rPC),%eax              # eax<- CC
+    movzbl    2(rPC),%ecx              # ecx<- BB
+    SPILL(rIBASE)                      # save rIBASE/%edx
+    GET_VREG_WORD rIBASE %eax 0
+    GET_VREG_WORD %eax %eax 1
+    movl     rIBASE,OUT_ARG2(%esp)
+    testl    %eax,%eax
+    je       .LOP_DIV_LONG_check_zero
+    cmpl     $-1,%eax
+    je       .LOP_DIV_LONG_check_neg1
+.LOP_DIV_LONG_notSpecial:
+    GET_VREG_WORD rIBASE %ecx 0
+    GET_VREG_WORD %ecx %ecx 1
+.LOP_DIV_LONG_notSpecial1:
+    movl     %eax,OUT_ARG3(%esp)
+    movl     rIBASE,OUT_ARG0(%esp)
+    movl     %ecx,OUT_ARG1(%esp)
+    call     __divdi3
+.LOP_DIV_LONG_finish:
+    SET_VREG_WORD rIBASE rINST 1
+    UNSPILL(rIBASE)                 # restore rIBASE/%edx
+    SET_VREG_WORD %eax rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_DIV_LONG_check_zero:
+    testl   rIBASE,rIBASE
+    jne     .LOP_DIV_LONG_notSpecial
+    jmp     common_errDivideByZero
+.LOP_DIV_LONG_check_neg1:
+    testl   rIBASE,%eax
+    jne     .LOP_DIV_LONG_notSpecial
+    GET_VREG_WORD rIBASE %ecx 0
+    GET_VREG_WORD %ecx %ecx 1
+    testl    rIBASE,rIBASE
+    jne      .LOP_DIV_LONG_notSpecial1
+    cmpl     $0x80000000,%ecx
+    jne      .LOP_DIV_LONG_notSpecial1
+    /* minint / -1, return minint on div, 0 on rem */
+    xorl     %eax,%eax
+    movl     $0x80000000,rIBASE
+    jmp      .LOP_DIV_LONG_finish
+
+/* ------------------------------ */
+.L_OP_REM_LONG: /* 0x9f */
+/* File: x86/OP_REM_LONG.S */
+/* File: x86/OP_DIV_LONG.S */
+    /* div vAA, vBB, vCC */
+    movzbl    3(rPC),%eax              # eax<- CC
+    movzbl    2(rPC),%ecx              # ecx<- BB
+    SPILL(rIBASE)                      # save rIBASE/%edx
+    GET_VREG_WORD rIBASE %eax 0
+    GET_VREG_WORD %eax %eax 1
+    movl     rIBASE,OUT_ARG2(%esp)
+    testl    %eax,%eax
+    je       .LOP_REM_LONG_check_zero
+    cmpl     $-1,%eax
+    je       .LOP_REM_LONG_check_neg1
+.LOP_REM_LONG_notSpecial:
+    GET_VREG_WORD rIBASE %ecx 0
+    GET_VREG_WORD %ecx %ecx 1
+.LOP_REM_LONG_notSpecial1:
+    movl     %eax,OUT_ARG3(%esp)
+    movl     rIBASE,OUT_ARG0(%esp)
+    movl     %ecx,OUT_ARG1(%esp)
+    call     __moddi3
+.LOP_REM_LONG_finish:
+    SET_VREG_WORD rIBASE rINST 1
+    UNSPILL(rIBASE)                 # restore rIBASE/%edx
+    SET_VREG_WORD %eax rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_REM_LONG_check_zero:
+    testl   rIBASE,rIBASE
+    jne     .LOP_REM_LONG_notSpecial
+    jmp     common_errDivideByZero
+.LOP_REM_LONG_check_neg1:
+    testl   rIBASE,%eax
+    jne     .LOP_REM_LONG_notSpecial
+    GET_VREG_WORD rIBASE %ecx 0
+    GET_VREG_WORD %ecx %ecx 1
+    testl    rIBASE,rIBASE
+    jne      .LOP_REM_LONG_notSpecial1
+    cmpl     $0x80000000,%ecx
+    jne      .LOP_REM_LONG_notSpecial1
+    /* minint / -1, return minint on div, 0 on rem */
+    xorl     %eax,%eax
+    movl     $0,rIBASE
+    jmp      .LOP_REM_LONG_finish
+
+
+/* ------------------------------ */
+.L_OP_AND_LONG: /* 0xa0 */
+/* File: x86/OP_AND_LONG.S */
+/* File: x86/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop vAA, vBB, vCC */
+
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)                       # save rIBASE
+    GET_VREG_WORD rIBASE %eax 0         # rIBASE<- v[BB+0]
+    GET_VREG_WORD %eax %eax 1           # eax<- v[BB+1]
+    andl (rFP,%ecx,4),rIBASE         # ex: addl   (rFP,%ecx,4),rIBASE
+    andl 4(rFP,%ecx,4),%eax         # ex: adcl   4(rFP,%ecx,4),%eax
+    SET_VREG_WORD rIBASE rINST 0        # v[AA+0] <- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 1          # v[AA+1] <- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_OR_LONG: /* 0xa1 */
+/* File: x86/OP_OR_LONG.S */
+/* File: x86/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop vAA, vBB, vCC */
+
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)                       # save rIBASE
+    GET_VREG_WORD rIBASE %eax 0         # rIBASE<- v[BB+0]
+    GET_VREG_WORD %eax %eax 1           # eax<- v[BB+1]
+    orl (rFP,%ecx,4),rIBASE         # ex: addl   (rFP,%ecx,4),rIBASE
+    orl 4(rFP,%ecx,4),%eax         # ex: adcl   4(rFP,%ecx,4),%eax
+    SET_VREG_WORD rIBASE rINST 0        # v[AA+0] <- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 1          # v[AA+1] <- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_XOR_LONG: /* 0xa2 */
+/* File: x86/OP_XOR_LONG.S */
+/* File: x86/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop vAA, vBB, vCC */
+
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)                       # save rIBASE
+    GET_VREG_WORD rIBASE %eax 0         # rIBASE<- v[BB+0]
+    GET_VREG_WORD %eax %eax 1           # eax<- v[BB+1]
+    xorl (rFP,%ecx,4),rIBASE         # ex: addl   (rFP,%ecx,4),rIBASE
+    xorl 4(rFP,%ecx,4),%eax         # ex: adcl   4(rFP,%ecx,4),%eax
+    SET_VREG_WORD rIBASE rINST 0        # v[AA+0] <- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 1          # v[AA+1] <- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHL_LONG: /* 0xa3 */
+/* File: x86/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.  x86 shifts automatically mask off
+     * the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
+     * case specially.
+     */
+    /* shl-long vAA, vBB, vCC */
+    /* ecx gets shift count */
+    /* Need to spill rINST */
+    /* rINSTw gets AA */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE %eax 1         # ecx<- v[BB+1]
+    GET_VREG_R   %ecx %ecx              # ecx<- vCC
+    GET_VREG_WORD %eax %eax 0           # eax<- v[BB+0]
+    shldl     %eax,rIBASE
+    sall      %cl,%eax
+    testb     $32,%cl
+    je        2f
+    movl      %eax,rIBASE
+    xorl      %eax,%eax
+2:
+    SET_VREG_WORD rIBASE rINST 1        # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0          # v[AA+0]<- %eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_SHR_LONG: /* 0xa4 */
+/* File: x86/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.  x86 shifts automatically mask off
+     * the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
+     * case specially.
+     */
+    /* shr-long vAA, vBB, vCC */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE %eax 1         # rIBASE<- v[BB+1]
+    GET_VREG_R   %ecx %ecx              # ecx<- vCC
+    GET_VREG_WORD %eax %eax 0           # eax<- v[BB+0]
+    shrdl     rIBASE,%eax
+    sarl      %cl,rIBASE
+    testb     $32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    sarl      $31,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1        # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0          # v[AA+0]<- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_USHR_LONG: /* 0xa5 */
+/* File: x86/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.  x86 shifts automatically mask off
+     * the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
+     * case specially.
+     */
+    /* shr-long vAA, vBB, vCC */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE %eax 1         # rIBASE<- v[BB+1]
+    GET_VREG_R  %ecx %ecx               # ecx<- vCC
+    GET_VREG_WORD %eax %eax 0           # eax<- v[BB+0]
+    shrdl     rIBASE,%eax
+    shrl      %cl,rIBASE
+    testb     $32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    xorl      rIBASE,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1          # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0         # v[BB+0]<- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_ADD_FLOAT: /* 0xa6 */
+/* File: x86/OP_ADD_FLOAT.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    flds    (rFP,%eax,4)         # vCC to fp stack
+    fadds   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstps   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SUB_FLOAT: /* 0xa7 */
+/* File: x86/OP_SUB_FLOAT.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    flds    (rFP,%eax,4)         # vCC to fp stack
+    fsubs   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstps   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_FLOAT: /* 0xa8 */
+/* File: x86/OP_MUL_FLOAT.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    flds    (rFP,%eax,4)         # vCC to fp stack
+    fmuls   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstps   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_DIV_FLOAT: /* 0xa9 */
+/* File: x86/OP_DIV_FLOAT.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    flds    (rFP,%eax,4)         # vCC to fp stack
+    fdivs   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstps   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_REM_FLOAT: /* 0xaa */
+/* File: x86/OP_REM_FLOAT.S */
+    /* rem_float vAA, vBB, vCC */
+    movzbl   3(rPC),%ecx            # ecx<- BB
+    movzbl   2(rPC),%eax            # eax<- CC
+    flds     (rFP,%ecx,4)           # vCC to fp stack
+    flds     (rFP,%eax,4)           # vCC to fp stack
+    movzbl   rINSTbl,%ecx           # ecx<- AA
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    FETCH_INST_OPCODE 2 %eax
+    ADVANCE_PC 2
+    fstps    (rFP,%ecx,4)           # %st to vAA
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_ADD_DOUBLE: /* 0xab */
+/* File: x86/OP_ADD_DOUBLE.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    fldl    (rFP,%eax,4)         # vCC to fp stack
+    faddl   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstpl   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SUB_DOUBLE: /* 0xac */
+/* File: x86/OP_SUB_DOUBLE.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    fldl    (rFP,%eax,4)         # vCC to fp stack
+    fsubl   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstpl   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_DOUBLE: /* 0xad */
+/* File: x86/OP_MUL_DOUBLE.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    fldl    (rFP,%eax,4)         # vCC to fp stack
+    fmull   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstpl   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_DIV_DOUBLE: /* 0xae */
+/* File: x86/OP_DIV_DOUBLE.S */
+/* File: x86/binflop.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    fldl    (rFP,%eax,4)         # vCC to fp stack
+    fdivl   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    fstpl   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_REM_DOUBLE: /* 0xaf */
+/* File: x86/OP_REM_DOUBLE.S */
+    /* rem_float vAA, vBB, vCC */
+    movzbl   3(rPC),%ecx            # ecx<- BB
+    movzbl   2(rPC),%eax            # eax<- CC
+    fldl     (rFP,%ecx,4)           # vCC to fp stack
+    fldl     (rFP,%eax,4)           # vCC to fp stack
+    FETCH_INST_OPCODE 2 %ecx
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    ADVANCE_PC 2
+    fstpl    (rFP,rINST,4)           # %st to vAA
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: x86/OP_ADD_INT_2ADDR.S */
+/* File: x86/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 */
+    movzx   rINSTbl,%ecx               # ecx<- A+
+    sarl    $4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST              # eax<- vB
+    andb    $0xf,%cl                  # ecx<- A
+    addl     %eax,(rFP,%ecx,4)                             # for ex: addl   %eax,(rFP,%ecx,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: x86/OP_SUB_INT_2ADDR.S */
+/* File: x86/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 */
+    movzx   rINSTbl,%ecx               # ecx<- A+
+    sarl    $4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST              # eax<- vB
+    andb    $0xf,%cl                  # ecx<- A
+    subl     %eax,(rFP,%ecx,4)                             # for ex: addl   %eax,(rFP,%ecx,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: x86/OP_MUL_INT_2ADDR.S */
+    /* mul vA, vB */
+    movzx   rINSTbl,%ecx              # ecx<- A+
+    sarl    $4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST             # eax<- vB
+    andb    $0xf,%cl                 # ecx<- A
+    SPILL(rIBASE)
+    imull   (rFP,%ecx,4),%eax         # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: x86/OP_DIV_INT_2ADDR.S */
+/* File: x86/bindiv2addr.S */
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* div/rem/2addr vA, vB */
+    movzx    rINSTbl,%ecx          # eax<- BA
+    SPILL(rIBASE)
+    sarl     $4,%ecx              # ecx<- B
+    GET_VREG_R %ecx %ecx           # eax<- vBB
+    andb     $0xf,rINSTbl         # rINST<- A
+    GET_VREG_R %eax rINST          # eax<- vBB
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $-1,%ecx
+    jne      .LOP_DIV_INT_2ADDR_continue_div2addr
+    cmpl     $0x80000000,%eax
+    jne      .LOP_DIV_INT_2ADDR_continue_div2addr
+    movl     $0x80000000,%eax
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_DIV_INT_2ADDR_continue_div2addr:
+    cltd
+    idivl   %ecx
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: x86/OP_REM_INT_2ADDR.S */
+/* File: x86/bindiv2addr.S */
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* div/rem/2addr vA, vB */
+    movzx    rINSTbl,%ecx          # eax<- BA
+    SPILL(rIBASE)
+    sarl     $4,%ecx              # ecx<- B
+    GET_VREG_R %ecx %ecx           # eax<- vBB
+    andb     $0xf,rINSTbl         # rINST<- A
+    GET_VREG_R %eax rINST          # eax<- vBB
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $-1,%ecx
+    jne      .LOP_REM_INT_2ADDR_continue_div2addr
+    cmpl     $0x80000000,%eax
+    jne      .LOP_REM_INT_2ADDR_continue_div2addr
+    movl     $0,rIBASE
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_REM_INT_2ADDR_continue_div2addr:
+    cltd
+    idivl   %ecx
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: x86/OP_AND_INT_2ADDR.S */
+/* File: x86/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 */
+    movzx   rINSTbl,%ecx               # ecx<- A+
+    sarl    $4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST              # eax<- vB
+    andb    $0xf,%cl                  # ecx<- A
+    andl     %eax,(rFP,%ecx,4)                             # for ex: addl   %eax,(rFP,%ecx,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: x86/OP_OR_INT_2ADDR.S */
+/* File: x86/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 */
+    movzx   rINSTbl,%ecx               # ecx<- A+
+    sarl    $4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST              # eax<- vB
+    andb    $0xf,%cl                  # ecx<- A
+    orl     %eax,(rFP,%ecx,4)                             # for ex: addl   %eax,(rFP,%ecx,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: x86/OP_XOR_INT_2ADDR.S */
+/* File: x86/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 */
+    movzx   rINSTbl,%ecx               # ecx<- A+
+    sarl    $4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST              # eax<- vB
+    andb    $0xf,%cl                  # ecx<- A
+    xorl     %eax,(rFP,%ecx,4)                             # for ex: addl   %eax,(rFP,%ecx,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: x86/OP_SHL_INT_2ADDR.S */
+/* File: x86/shop2addr.S */
+    /*
+     * Generic 32-bit "shift/2addr" operation.
+     */
+    /* shift/2addr vA, vB */
+    movzx    rINSTbl,%ecx           # eax<- BA
+    sarl     $4,%ecx               # ecx<- B
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    andb     $0xf,rINSTbl          # rINST<- A
+    GET_VREG_R %eax rINST           # eax<- vAA
+    sall    %cl,%eax                          # ex: sarl %cl,%eax
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: x86/OP_SHR_INT_2ADDR.S */
+/* File: x86/shop2addr.S */
+    /*
+     * Generic 32-bit "shift/2addr" operation.
+     */
+    /* shift/2addr vA, vB */
+    movzx    rINSTbl,%ecx           # eax<- BA
+    sarl     $4,%ecx               # ecx<- B
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    andb     $0xf,rINSTbl          # rINST<- A
+    GET_VREG_R %eax rINST           # eax<- vAA
+    sarl    %cl,%eax                          # ex: sarl %cl,%eax
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: x86/OP_USHR_INT_2ADDR.S */
+/* File: x86/shop2addr.S */
+    /*
+     * Generic 32-bit "shift/2addr" operation.
+     */
+    /* shift/2addr vA, vB */
+    movzx    rINSTbl,%ecx           # eax<- BA
+    sarl     $4,%ecx               # ecx<- B
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    andb     $0xf,rINSTbl          # rINST<- A
+    GET_VREG_R %eax rINST           # eax<- vAA
+    shrl    %cl,%eax                          # ex: sarl %cl,%eax
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: x86/OP_ADD_LONG_2ADDR.S */
+/* File: x86/binopWide2addr.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop/2addr vA, vB */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_WORD %eax %ecx 0           # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1           # eax<- v[B+1]
+    andb      $0xF,rINSTbl             # rINST<- A
+    addl %eax,(rFP,rINST,4)         # example: addl   %eax,(rFP,rINST,4)
+    adcl %ecx,4(rFP,rINST,4)         # example: adcl   %ecx,4(rFP,rINST,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: x86/OP_SUB_LONG_2ADDR.S */
+/* File: x86/binopWide2addr.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop/2addr vA, vB */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_WORD %eax %ecx 0           # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1           # eax<- v[B+1]
+    andb      $0xF,rINSTbl             # rINST<- A
+    subl %eax,(rFP,rINST,4)         # example: addl   %eax,(rFP,rINST,4)
+    sbbl %ecx,4(rFP,rINST,4)         # example: adcl   %ecx,4(rFP,rINST,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: x86/OP_MUL_LONG_2ADDR.S */
+    /*
+     * Signed 64-bit integer multiply, 2-addr version
+     *
+     * We could definately use more free registers for
+     * this code.  We must spill %edx (rIBASE) because it
+     * is used by imul.  We'll also spill rINST (ebx),
+     * giving us eax, ebc, ecx and rIBASE as computational
+     * temps.  On top of that, we'll spill %esi (edi)
+     * for use as the vA pointer and rFP (esi) for use
+     * as the vB pointer.  Yuck.
+     */
+    /* mul-long/2addr vA, vB */
+    movzbl    rINSTbl,%eax             # eax<- BA
+    andb      $0xf,%al                # eax<- A
+    sarl      $4,rINST                # rINST<- B
+    SPILL_TMP2(%esi)
+    SPILL(rFP)
+    SPILL(rIBASE)
+    leal      (rFP,%eax,4),%esi        # %esi<- &v[A]
+    leal      (rFP,rINST,4),rFP        # rFP<- &v[B]
+    movl      4(%esi),%ecx             # ecx<- Amsw
+    imull     (rFP),%ecx               # ecx<- (Amsw*Blsw)
+    movl      4(rFP),%eax              # eax<- Bmsw
+    imull     (%esi),%eax              # eax<- (Bmsw*Alsw)
+    addl      %eax,%ecx                # ecx<- (Amsw*Blsw)+(Bmsw*Alsw)
+    movl      (rFP),%eax               # eax<- Blsw
+    mull      (%esi)                   # eax<- (Blsw*Alsw)
+    leal      (%ecx,rIBASE),rIBASE     # full result now in %edx:%eax
+    movl      rIBASE,4(%esi)           # v[A+1]<- rIBASE
+    movl      %eax,(%esi)              # v[A]<- %eax
+    UNSPILL_TMP2(%esi)
+    FETCH_INST_OPCODE 1 %ecx
+    UNSPILL(rIBASE)
+    UNSPILL(rFP)
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: x86/OP_DIV_LONG_2ADDR.S */
+    /* div/2addr vA, vB */
+    movzbl    rINSTbl,%eax
+    shrl      $4,%eax                  # eax<- B
+    andb      $0xf,rINSTbl             # rINST<- A
+    SPILL(rIBASE)                       # save rIBASE/%edx
+    GET_VREG_WORD rIBASE %eax 0
+    GET_VREG_WORD %eax %eax 1
+    movl     rIBASE,OUT_ARG2(%esp)
+    testl    %eax,%eax
+    je       .LOP_DIV_LONG_2ADDR_check_zero
+    cmpl     $-1,%eax
+    je       .LOP_DIV_LONG_2ADDR_check_neg1
+.LOP_DIV_LONG_2ADDR_notSpecial:
+    GET_VREG_WORD rIBASE rINST 0
+    GET_VREG_WORD %ecx rINST 1
+.LOP_DIV_LONG_2ADDR_notSpecial1:
+    movl     %eax,OUT_ARG3(%esp)
+    movl     rIBASE,OUT_ARG0(%esp)
+    movl     %ecx,OUT_ARG1(%esp)
+    call     __divdi3
+.LOP_DIV_LONG_2ADDR_finish:
+    SET_VREG_WORD rIBASE rINST 1
+    UNSPILL(rIBASE)                    # restore rIBASE/%edx
+    SET_VREG_WORD %eax rINST 0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_DIV_LONG_2ADDR_check_zero:
+    testl   rIBASE,rIBASE
+    jne     .LOP_DIV_LONG_2ADDR_notSpecial
+    jmp     common_errDivideByZero
+.LOP_DIV_LONG_2ADDR_check_neg1:
+    testl   rIBASE,%eax
+    jne     .LOP_DIV_LONG_2ADDR_notSpecial
+    GET_VREG_WORD rIBASE rINST 0
+    GET_VREG_WORD %ecx rINST 1
+    testl    rIBASE,rIBASE
+    jne      .LOP_DIV_LONG_2ADDR_notSpecial1
+    cmpl     $0x80000000,%ecx
+    jne      .LOP_DIV_LONG_2ADDR_notSpecial1
+    /* minint / -1, return minint on div, 0 on rem */
+    xorl     %eax,%eax
+    movl     $0x80000000,rIBASE
+    jmp      .LOP_DIV_LONG_2ADDR_finish
+
+/* ------------------------------ */
+.L_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: x86/OP_REM_LONG_2ADDR.S */
+/* File: x86/OP_DIV_LONG_2ADDR.S */
+    /* div/2addr vA, vB */
+    movzbl    rINSTbl,%eax
+    shrl      $4,%eax                  # eax<- B
+    andb      $0xf,rINSTbl             # rINST<- A
+    SPILL(rIBASE)                       # save rIBASE/%edx
+    GET_VREG_WORD rIBASE %eax 0
+    GET_VREG_WORD %eax %eax 1
+    movl     rIBASE,OUT_ARG2(%esp)
+    testl    %eax,%eax
+    je       .LOP_REM_LONG_2ADDR_check_zero
+    cmpl     $-1,%eax
+    je       .LOP_REM_LONG_2ADDR_check_neg1
+.LOP_REM_LONG_2ADDR_notSpecial:
+    GET_VREG_WORD rIBASE rINST 0
+    GET_VREG_WORD %ecx rINST 1
+.LOP_REM_LONG_2ADDR_notSpecial1:
+    movl     %eax,OUT_ARG3(%esp)
+    movl     rIBASE,OUT_ARG0(%esp)
+    movl     %ecx,OUT_ARG1(%esp)
+    call     __moddi3
+.LOP_REM_LONG_2ADDR_finish:
+    SET_VREG_WORD rIBASE rINST 1
+    UNSPILL(rIBASE)                    # restore rIBASE/%edx
+    SET_VREG_WORD %eax rINST 0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.LOP_REM_LONG_2ADDR_check_zero:
+    testl   rIBASE,rIBASE
+    jne     .LOP_REM_LONG_2ADDR_notSpecial
+    jmp     common_errDivideByZero
+.LOP_REM_LONG_2ADDR_check_neg1:
+    testl   rIBASE,%eax
+    jne     .LOP_REM_LONG_2ADDR_notSpecial
+    GET_VREG_WORD rIBASE rINST 0
+    GET_VREG_WORD %ecx rINST 1
+    testl    rIBASE,rIBASE
+    jne      .LOP_REM_LONG_2ADDR_notSpecial1
+    cmpl     $0x80000000,%ecx
+    jne      .LOP_REM_LONG_2ADDR_notSpecial1
+    /* minint / -1, return minint on div, 0 on rem */
+    xorl     %eax,%eax
+    movl     $0,rIBASE
+    jmp      .LOP_REM_LONG_2ADDR_finish
+
+
+/* ------------------------------ */
+.L_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: x86/OP_AND_LONG_2ADDR.S */
+/* File: x86/binopWide2addr.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop/2addr vA, vB */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_WORD %eax %ecx 0           # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1           # eax<- v[B+1]
+    andb      $0xF,rINSTbl             # rINST<- A
+    andl %eax,(rFP,rINST,4)         # example: addl   %eax,(rFP,rINST,4)
+    andl %ecx,4(rFP,rINST,4)         # example: adcl   %ecx,4(rFP,rINST,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: x86/OP_OR_LONG_2ADDR.S */
+/* File: x86/binopWide2addr.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop/2addr vA, vB */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_WORD %eax %ecx 0           # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1           # eax<- v[B+1]
+    andb      $0xF,rINSTbl             # rINST<- A
+    orl %eax,(rFP,rINST,4)         # example: addl   %eax,(rFP,rINST,4)
+    orl %ecx,4(rFP,rINST,4)         # example: adcl   %ecx,4(rFP,rINST,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: x86/OP_XOR_LONG_2ADDR.S */
+/* File: x86/binopWide2addr.S */
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop/2addr vA, vB */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_WORD %eax %ecx 0           # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1           # eax<- v[B+1]
+    andb      $0xF,rINSTbl             # rINST<- A
+    xorl %eax,(rFP,rINST,4)         # example: addl   %eax,(rFP,rINST,4)
+    xorl %ecx,4(rFP,rINST,4)         # example: adcl   %ecx,4(rFP,rINST,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: x86/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 */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    rINSTbl,%ecx             # ecx<- BA
+    andb      $0xf,rINSTbl            # rINST<- A
+    GET_VREG_WORD %eax rINST 0         # eax<- v[AA+0]
+    sarl      $4,%ecx                 # ecx<- B
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE rINST 1       # rIBASE<- v[AA+1]
+    GET_VREG_R  %ecx %ecx              # ecx<- vBB
+    shldl     %eax,rIBASE
+    sall      %cl,%eax
+    testb     $32,%cl
+    je        2f
+    movl      %eax,rIBASE
+    xorl      %eax,%eax
+2:
+    SET_VREG_WORD rIBASE rINST 1       # v[AA+1]<- rIBASE
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG_WORD %eax rINST 0         # v[AA+0]<- eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: x86/OP_SHR_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 */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    rINSTbl,%ecx         # ecx<- BA
+    andb      $0xf,rINSTbl        # rINST<- A
+    GET_VREG_WORD %eax rINST 0     # eax<- v[AA+0]
+    sarl      $4,%ecx             # ecx<- B
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE rINST 1   # rIBASE<- v[AA+1]
+    GET_VREG_R %ecx %ecx           # ecx<- vBB
+    shrdl     rIBASE,%eax
+    sarl      %cl,rIBASE
+    testb     $32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    sarl      $31,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1   # v[AA+1]<- rIBASE
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG_WORD %eax rINST 0    # v[AA+0]<- eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: x86/OP_USHR_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 */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    rINSTbl,%ecx             # ecx<- BA
+    andb      $0xf,rINSTbl            # rINST<- A
+    GET_VREG_WORD %eax rINST 0         # eax<- v[AA+0]
+    sarl      $4,%ecx                 # ecx<- B
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE rINST 1       # rIBASE<- v[AA+1]
+    GET_VREG_R %ecx %ecx               # ecx<- vBB
+    shrdl     rIBASE,%eax
+    shrl      %cl,rIBASE
+    testb     $32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    xorl      rIBASE,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1       # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 1 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0         # v[AA+0]<- eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: x86/OP_ADD_FLOAT_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    flds    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fadds   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstps    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: x86/OP_SUB_FLOAT_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    flds    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fsubs   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstps    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: x86/OP_MUL_FLOAT_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    flds    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fmuls   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstps    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: x86/OP_DIV_FLOAT_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    flds    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fdivs   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstps    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: x86/OP_REM_FLOAT_2ADDR.S */
+    /* rem_float/2addr vA, vB */
+    movzx   rINSTbl,%ecx                # ecx<- A+
+    sarl    $4,rINST                  # rINST<- B
+    flds     (rFP,rINST,4)              # vBB to fp stack
+    andb    $0xf,%cl                   # ecx<- A
+    flds     (rFP,%ecx,4)               # vAA to fp stack
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstps    (rFP,%ecx,4)               # %st to vA
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: x86/OP_ADD_DOUBLE_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    fldl    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    faddl   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstpl    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: x86/OP_SUB_DOUBLE_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    fldl    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fsubl   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstpl    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: x86/OP_MUL_DOUBLE_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    fldl    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fmull   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstpl    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: x86/OP_DIV_DOUBLE_2ADDR.S */
+/* File: x86/binflop2addr.S */
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $0xf,%cl              # ecx<- A
+    fldl    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $4,rINST             # rINST<- B
+    fdivl   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstpl    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: x86/OP_REM_DOUBLE_2ADDR.S */
+    /* rem_float/2addr vA, vB */
+    movzx   rINSTbl,%ecx                # ecx<- A+
+    sarl    $4,rINST                  # rINST<- B
+    fldl     (rFP,rINST,4)              # vBB to fp stack
+    andb    $0xf,%cl                   # ecx<- A
+    fldl     (rFP,%ecx,4)               # vAA to fp stack
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstpl    (rFP,%ecx,4)               # %st to vA
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: x86/OP_ADD_INT_LIT16.S */
+/* File: x86/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int/lit16, rsub-int,
+     *      and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl              # rINST<- A
+    addl %ecx,%eax                              # for example: addl %ecx, %eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_RSUB_INT: /* 0xd1 */
+/* File: x86/OP_RSUB_INT.S */
+/* File: x86/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int/lit16, rsub-int,
+     *      and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl              # rINST<- A
+    subl %eax,%ecx                              # for example: addl %ecx, %eax
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: x86/OP_MUL_INT_LIT16.S */
+    /* mul/lit16 vA, vB, #+CCCC */
+    /* Need A in rINST, ssssCCCC in ecx, vB in eax */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl              # rINST<- A
+    SPILL(rIBASE)
+    imull     %ecx,%eax                 # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: x86/OP_DIV_INT_LIT16.S */
+/* File: x86/bindivLit16.S */
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* div/rem/lit16 vA, vB, #+CCCC */
+    /* Need A in rINST, ssssCCCC in ecx, vB in eax */
+    movzbl   rINSTbl,%eax         # eax<- 000000BA
+    SPILL(rIBASE)
+    sarl     $4,%eax             # eax<- B
+    GET_VREG_R %eax %eax          # eax<- vB
+    movswl   2(rPC),%ecx          # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl        # rINST<- A
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $-1,%ecx
+    jne      .LOP_DIV_INT_LIT16_continue_div
+    cmpl     $0x80000000,%eax
+    jne      .LOP_DIV_INT_LIT16_continue_div
+    movl     $0x80000000,%eax
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_DIV_INT_LIT16_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: x86/OP_REM_INT_LIT16.S */
+/* File: x86/bindivLit16.S */
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* div/rem/lit16 vA, vB, #+CCCC */
+    /* Need A in rINST, ssssCCCC in ecx, vB in eax */
+    movzbl   rINSTbl,%eax         # eax<- 000000BA
+    SPILL(rIBASE)
+    sarl     $4,%eax             # eax<- B
+    GET_VREG_R %eax %eax          # eax<- vB
+    movswl   2(rPC),%ecx          # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl        # rINST<- A
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $-1,%ecx
+    jne      .LOP_REM_INT_LIT16_continue_div
+    cmpl     $0x80000000,%eax
+    jne      .LOP_REM_INT_LIT16_continue_div
+    movl     $0,rIBASE
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_REM_INT_LIT16_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: x86/OP_AND_INT_LIT16.S */
+/* File: x86/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int/lit16, rsub-int,
+     *      and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl              # rINST<- A
+    andl %ecx,%eax                              # for example: addl %ecx, %eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: x86/OP_OR_INT_LIT16.S */
+/* File: x86/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int/lit16, rsub-int,
+     *      and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl              # rINST<- A
+    orl     %ecx,%eax                              # for example: addl %ecx, %eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: x86/OP_XOR_INT_LIT16.S */
+/* File: x86/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int/lit16, rsub-int,
+     *      and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $0xf,rINSTbl              # rINST<- A
+    xor    %ecx,%eax                              # for example: addl %ecx, %eax
+    SET_VREG %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: x86/OP_ADD_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    addl %ecx,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: x86/OP_RSUB_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    subl  %eax,%ecx                             # ex: addl %ecx,%eax
+    SET_VREG   %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_MUL_INT_LIT8: /* 0xda */
+/* File: x86/OP_MUL_INT_LIT8.S */
+    /* mul/lit8 vAA, vBB, #+CC */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    SPILL(rIBASE)
+    imull     %ecx,%eax                # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG  %eax rINST
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: x86/OP_DIV_INT_LIT8.S */
+/* File: x86/bindivLit8.S */
+    /*
+     * 32-bit div/rem "lit8" binary operation.  Handles special case of
+     * op0=minint & op1=-1
+     */
+    /* div/rem/lit8 vAA, vBB, #+CC */
+    movzbl    2(rPC),%eax        # eax<- BB
+    movsbl    3(rPC),%ecx        # ecx<- ssssssCC
+    SPILL(rIBASE)
+    GET_VREG_R  %eax %eax        # eax<- rBB
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $0x80000000,%eax
+    jne      .LOP_DIV_INT_LIT8_continue_div
+    cmpl     $-1,%ecx
+    jne      .LOP_DIV_INT_LIT8_continue_div
+    movl     $0x80000000,%eax
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_DIV_INT_LIT8_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG %eax rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_REM_INT_LIT8: /* 0xdc */
+/* File: x86/OP_REM_INT_LIT8.S */
+/* File: x86/bindivLit8.S */
+    /*
+     * 32-bit div/rem "lit8" binary operation.  Handles special case of
+     * op0=minint & op1=-1
+     */
+    /* div/rem/lit8 vAA, vBB, #+CC */
+    movzbl    2(rPC),%eax        # eax<- BB
+    movsbl    3(rPC),%ecx        # ecx<- ssssssCC
+    SPILL(rIBASE)
+    GET_VREG_R  %eax %eax        # eax<- rBB
+    cmpl     $0,%ecx
+    je       common_errDivideByZero
+    cmpl     $0x80000000,%eax
+    jne      .LOP_REM_INT_LIT8_continue_div
+    cmpl     $-1,%ecx
+    jne      .LOP_REM_INT_LIT8_continue_div
+    movl     $0,rIBASE
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_REM_INT_LIT8_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG rIBASE rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_AND_INT_LIT8: /* 0xdd */
+/* File: x86/OP_AND_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    andl %ecx,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_OR_INT_LIT8: /* 0xde */
+/* File: x86/OP_OR_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    orl     %ecx,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: x86/OP_XOR_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    xor    %ecx,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: x86/OP_SHL_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    sall  %cl,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: x86/OP_SHR_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    sarl    %cl,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: x86/OP_USHR_INT_LIT8.S */
+/* File: x86/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    shrl     %cl,%eax                             # ex: addl %ecx,%eax
+    SET_VREG   %eax rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: x86/OP_IGET_VOLATILE.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_VOLATILE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_VOLATILE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_VOLATILE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: x86/OP_IPUT_VOLATILE.S */
+/* File: x86/OP_IPUT.S */
+
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_VOLATILE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_VOLATILE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_VOLATILE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movl   rINST,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: x86/OP_SGET_VOLATILE.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_VOLATILE_resolve                # if not, make it so
+.LOP_SGET_VOLATILE_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_VOLATILE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_VOLATILE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: x86/OP_SPUT_VOLATILE.S */
+/* File: x86/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_VOLATILE_resolve                # if not, make it so
+.LOP_SPUT_VOLATILE_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_VOLATILE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_VOLATILE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: x86/OP_IGET_OBJECT_VOLATILE.S */
+/* File: x86/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_OBJECT_VOLATILE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_OBJECT_VOLATILE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_OBJECT_VOLATILE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IGET_WIDE_VOLATILE     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IPUT_WIDE_VOLATILE     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SGET_WIDE_VOLATILE: /* 0xea */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SGET_WIDE_VOLATILE     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SPUT_WIDE_VOLATILE     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_BREAKPOINT: /* 0xec */
+/* File: x86/OP_BREAKPOINT.S */
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.  We also assume that all other special "checkBefore"
+     * actions have been handled, so we'll transition directly
+     * to the real handler
+     */
+    SPILL(rIBASE)
+    movl    rPC,OUT_ARG0(%esp)
+    call    dvmGetOriginalOpcode
+    UNSPILL(rIBASE)
+    movl    rSELF,%ecx
+    movzbl  1(rPC),rINST
+    movl    offThread_mainHandlerTable(%ecx),%ecx
+    jmp     *(%ecx,%eax,4)
+
+
+/* ------------------------------ */
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: x86/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 */
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                     # eax<- BBBB
+    movl     offThread_method(%ecx),%ecx       # ecx<- self->method
+    EXPORT_PC
+    movl     %eax,OUT_ARG2(%esp)             # arg2<- BBBB
+    movl     rINST,OUT_ARG1(%esp)            # arg1<- AA
+    movl     %ecx,OUT_ARG0(%esp)             # arg0<- method
+    call     dvmThrowVerificationError       # call(method, kind, ref)
+    jmp      common_exceptionThrown          # handle exception
+
+/* ------------------------------ */
+.L_OP_EXECUTE_INLINE: /* 0xee */
+/* File: x86/OP_EXECUTE_INLINE.S */
+    /*
+     * Execute a "native inline" instruction.
+     *
+     * We will be calling through a function table:
+     *
+     * (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult)
+     *
+     * Ignores argument count - always loads 4.
+     *
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    movl      rSELF,%ecx
+    EXPORT_PC
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    leal      offThread_retval(%ecx),%ecx # ecx<- & self->retval
+    SPILL(rIBASE)                       # preserve rIBASE
+    movl      %ecx,OUT_ARG4(%esp)
+    call      .LOP_EXECUTE_INLINE_continue      # make call; will return after
+    UNSPILL(rIBASE)                     # restore rIBASE
+    testl     %eax,%eax                 # successful?
+    FETCH_INST_OPCODE 3 %ecx
+    je        common_exceptionThrown    # no, handle exception
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+.LOP_EXECUTE_INLINE_continue:
+    /*
+     * Extract args, call function.
+     *  ecx = #of args (0-4)
+     *  eax = call index
+     *  @esp = return addr
+     *  esp is -4 from normal
+     *
+     *  Go ahead and load all 4 args, even if not used.
+     */
+    movzwl    4(rPC),rIBASE
+
+    movl      $0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $4,rIBASE
+    movl      %ecx,4+OUT_ARG0(%esp)
+
+    movl      $0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $4,rIBASE
+    movl      %ecx,4+OUT_ARG1(%esp)
+
+    movl      $0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $4,rIBASE
+    movl      %ecx,4+OUT_ARG2(%esp)
+
+    movl      $0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $4,rIBASE
+    movl      %ecx,4+OUT_ARG3(%esp)
+
+    sall      $4,%eax      # index *= sizeof(table entry)
+    jmp       *gDvmInlineOpsTable(%eax)
+    # will return to caller of .LOP_EXECUTE_INLINE_continue
+
+/* ------------------------------ */
+.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_EXECUTE_INLINE_RANGE     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_INVOKE_OBJECT_INIT_RANGE     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_RETURN_VOID_BARRIER     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IGET_QUICK: /* 0xf2 */
+/* File: x86/OP_IGET_QUICK.S */
+    /* For: iget-quick, iget-object-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    cmpl      $0,%ecx                  # is object null?
+    je        common_errNullObject
+    movl      (%ecx,%eax,1),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    andb      $0xf,rINSTbl             # rINST<- A
+    SET_VREG  %eax rINST                # fp[A]<- result
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: x86/OP_IGET_WIDE_QUICK.S */
+    /* For: iget-wide-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    cmpl      $0,%ecx                  # is object null?
+    je        common_errNullObject
+    leal      (%ecx,%eax,1),%eax        # eax<- address of 64-bit source
+    movl      (%eax),%ecx               # ecx<- lsw
+    movl      4(%eax),%eax              # eax<- msw
+    andb      $0xf,rINSTbl             # rINST<- A
+    SET_VREG_WORD %ecx rINST 0          # v[A+0]<- lsw
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG_WORD %eax rINST 1          # v[A+1]<- msw
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: x86/OP_IGET_OBJECT_QUICK.S */
+/* File: x86/OP_IGET_QUICK.S */
+    /* For: iget-quick, iget-object-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    cmpl      $0,%ecx                  # is object null?
+    je        common_errNullObject
+    movl      (%ecx,%eax,1),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    andb      $0xf,rINSTbl             # rINST<- A
+    SET_VREG  %eax rINST                # fp[A]<- result
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_QUICK: /* 0xf5 */
+/* File: x86/OP_IPUT_QUICK.S */
+    /* For: iput-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    andb      $0xf,rINSTbl             # rINST<- A
+    GET_VREG_R  rINST,rINST             # rINST<- v[A]
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    testl     %ecx,%ecx                 # is object null?
+    je        common_errNullObject
+    movl      rINST,(%ecx,%eax,1)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: x86/OP_IPUT_WIDE_QUICK.S */
+    /* For: iput-wide-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    testl      %ecx,%ecx                # is object null?
+    je        common_errNullObject
+    leal      (%ecx,%eax,1),%ecx        # ecx<- Address of 64-bit target
+    andb      $0xf,rINSTbl             # rINST<- A
+    GET_VREG_WORD %eax rINST 0          # eax<- lsw
+    GET_VREG_WORD rINST rINST 1         # rINST<- msw
+    movl      %eax,(%ecx)
+    movl      rINST,4(%ecx)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: x86/OP_IPUT_OBJECT_QUICK.S */
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    andb      $0xf,rINSTbl             # rINST<- A
+    GET_VREG_R  rINST rINST             # rINST<- v[A]
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    testl     %ecx,%ecx                 # is object null?
+    je        common_errNullObject
+    movl      rINST,(%ecx,%eax,1)
+    movl      rSELF,%eax
+    testl     rINST,rINST               # did we store null?
+    movl      offThread_cardTable(%eax),%eax  # get card table base
+    je        1f                            # skip card mark if null store
+    shrl      $GC_CARD_SHIFT,%ecx          # object head to card number
+    movb      %al,(%eax,%ecx)               # mark card based on object head
+1:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: x86/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 */
+    movzwl    4(rPC),%eax               # eax<- FEDC or CCCC
+    movzwl    2(rPC),%ecx               # ecx<- BBBB
+    .if     (!0)
+    andl      $0xf,%eax                # eax<- C (or stays CCCC)
+    .endif
+    GET_VREG_R  %eax %eax               # eax<- vC ("this" ptr)
+    testl     %eax,%eax                 # null?
+    je        common_errNullObject      # yep, throw exception
+    movl      offObject_clazz(%eax),%eax # eax<- thisPtr->clazz
+    movl      offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
+    EXPORT_PC                           # might throw later - get ready
+    movl      (%eax,%ecx,4),%eax        # eax<- vtable[BBBB]
+    jmp       common_invokeMethodNoRange
+
+/* ------------------------------ */
+.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: x86/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
+/* File: x86/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 */
+    movzwl    4(rPC),%eax               # eax<- FEDC or CCCC
+    movzwl    2(rPC),%ecx               # ecx<- BBBB
+    .if     (!1)
+    andl      $0xf,%eax                # eax<- C (or stays CCCC)
+    .endif
+    GET_VREG_R  %eax %eax               # eax<- vC ("this" ptr)
+    testl     %eax,%eax                 # null?
+    je        common_errNullObject      # yep, throw exception
+    movl      offObject_clazz(%eax),%eax # eax<- thisPtr->clazz
+    movl      offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
+    EXPORT_PC                           # might throw later - get ready
+    movl      (%eax,%ecx,4),%eax        # eax<- vtable[BBBB]
+    jmp       common_invokeMethodRange
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: x86/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 */
+    movl      rSELF,%ecx
+    movzwl    4(rPC),%eax               # eax<- GFED or CCCC
+    movl      offThread_method(%ecx),%ecx # ecx<- current method
+    .if       (!0)
+    andl      $0xf,%eax                # eax<- D (or stays CCCC)
+    .endif
+    movl      offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    GET_VREG_R  %eax %eax               # eax<- "this"
+    movl      offClassObject_super(%ecx),%ecx # ecx<- method->clazz->super
+    testl     %eax,%eax                 # null "this"?
+    je        common_errNullObject      # "this" is null, throw exception
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offClassObject_vtable(%ecx),%ecx # ecx<- vtable
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%eax        # eax<- super->vtable[BBBB]
+    jmp       common_invokeMethodNoRange
+
+/* ------------------------------ */
+.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: x86/OP_INVOKE_SUPER_QUICK_RANGE.S */
+/* File: x86/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 */
+    movl      rSELF,%ecx
+    movzwl    4(rPC),%eax               # eax<- GFED or CCCC
+    movl      offThread_method(%ecx),%ecx # ecx<- current method
+    .if       (!1)
+    andl      $0xf,%eax                # eax<- D (or stays CCCC)
+    .endif
+    movl      offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    GET_VREG_R  %eax %eax               # eax<- "this"
+    movl      offClassObject_super(%ecx),%ecx # ecx<- method->clazz->super
+    testl     %eax,%eax                 # null "this"?
+    je        common_errNullObject      # "this" is null, throw exception
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offClassObject_vtable(%ecx),%ecx # ecx<- vtable
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%eax        # eax<- super->vtable[BBBB]
+    jmp       common_invokeMethodRange
+
+
+/* ------------------------------ */
+.L_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: x86/OP_IPUT_OBJECT_VOLATILE.S */
+/* File: x86/OP_IPUT_OBJECT.S */
+    /*
+     * Object field put.
+     *
+     * for: iput-object
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                  # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_OBJECT_VOLATILE_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_OBJECT_VOLATILE_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_OBJECT_VOLATILE_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                      # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl    rINST,(%ecx,%eax)      # obj.field <- v[A](8/16/32 bits)
+    movl    rSELF,%eax
+    testl   rINST,rINST                         # stored a NULL?
+    movl    offThread_cardTable(%eax),%eax      # get card table base
+    je      1f                                  # skip card mark if null store
+    shrl    $GC_CARD_SHIFT,%ecx                # object head to card number
+    movb    %al,(%eax,%ecx)                     # mark card using object head
+1:
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: x86/OP_SGET_OBJECT_VOLATILE.S */
+/* File: x86/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_OBJECT_VOLATILE_resolve                # if not, make it so
+.LOP_SGET_OBJECT_VOLATILE_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_OBJECT_VOLATILE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_OBJECT_VOLATILE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: x86/OP_SPUT_OBJECT_VOLATILE.S */
+/* File: x86/OP_SPUT_OBJECT.S */
+    /*
+     * SPUT object handler.
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_OBJECT_VOLATILE_resolve                # if not, make it so
+.LOP_SPUT_OBJECT_VOLATILE_finish:                              # field ptr in eax
+    movzbl    rINSTbl,%ecx                       # ecx<- AA
+    GET_VREG_R  %ecx %ecx
+    movl      %ecx,offStaticField_value(%eax)    # do the store
+    testl     %ecx,%ecx                          # stored null object ptr?
+    je        1f                                 # skip card mark if null
+    movl      rSELF,%ecx
+    movl      offField_clazz(%eax),%eax          # eax<- method->clazz
+    movl      offThread_cardTable(%ecx),%ecx       # get card table base
+    shrl      $GC_CARD_SHIFT,%eax               # head to card number
+    movb      %cl,(%ecx,%eax)                    # mark card
+1:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.LOP_SPUT_OBJECT_VOLATILE_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_OBJECT_VOLATILE_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_DISPATCH_FF: /* 0xff */
+/* File: x86/OP_DISPATCH_FF.S */
+    leal      256(rINST),%ecx
+    GOTO_NEXT_JUMBO_R %ecx
+
+/* ------------------------------ */
+.L_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: x86/OP_CONST_CLASS_JUMBO.S */
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax              # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- dvmDex->pResClasses
+    movl      (%ecx,%eax,4),%eax       # eax<- rResClasses[AAAAAAAA]
+    FETCH_INST_OPCODE 4 %ecx
+    testl     %eax,%eax                # resolved yet?
+    je        .LOP_CONST_CLASS_JUMBO_resolve
+    SET_VREG  %eax rINST               # vBBBB<- rResClasses[AAAAAAAA]
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.LOP_CONST_CLASS_JUMBO_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movl     $1,OUT_ARG2(%esp)        # true
+    movl     2(rPC),%ecx               # ecx<- AAAAAAAA
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveClass           # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 4 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: x86/OP_CHECK_CAST_JUMBO.S */
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    movl      rSELF,%ecx
+    GET_VREG_R  rINST,rINST             # rINST<- vBBBB (object)
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    testl     rINST,rINST               # is oject null?
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    je        .LOP_CHECK_CAST_JUMBO_okay          # null obj, cast always succeeds
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved class
+    movl      offObject_clazz(rINST),%ecx # ecx<- obj->clazz
+    testl     %eax,%eax                 # have we resolved this before?
+    je        .LOP_CHECK_CAST_JUMBO_resolve       # no, go do it now
+.LOP_CHECK_CAST_JUMBO_resolved:
+    cmpl      %eax,%ecx                 # same class (trivial success)?
+    jne       .LOP_CHECK_CAST_JUMBO_fullcheck     # no, do full check
+.LOP_CHECK_CAST_JUMBO_okay:
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  ecx holds obj->clazz
+     *  eax holds class resolved from AAAAAAAA
+     *  rINST holds object
+     */
+.LOP_CHECK_CAST_JUMBO_fullcheck:
+    movl    %eax,sReg0                 # we'll need the desired class on failure
+    movl    %eax,OUT_ARG1(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call    dvmInstanceofNonTrivial    # eax<- boolean result
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # failed?
+    jne     .LOP_CHECK_CAST_JUMBO_okay           # no, success
+
+    # A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC
+    movl    offObject_clazz(rINST),%eax
+    movl    %eax,OUT_ARG0(%esp)                 # arg0<- obj->clazz
+    movl    sReg0,%ecx
+    movl    %ecx,OUT_ARG1(%esp)                 # arg1<- desired class
+    call    dvmThrowClassCastException
+    jmp     common_exceptionThrown
+
+    /*
+     * Resolution required.  This is the least-likely path, and we're
+     * going to have to recreate some data.
+     *
+     *  rINST holds object
+     */
+.LOP_CHECK_CAST_JUMBO_resolve:
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movl    2(rPC),%eax                # eax<- AAAAAAAA
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)        # arg1<- AAAAAAAA
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- metho->clazz
+    movl    $0,OUT_ARG2(%esp)         # arg2<- false
+    movl    %ecx,OUT_ARG0(%esp)        # arg0<- method->clazz
+    SPILL(rIBASE)
+    call    dvmResolveClass            # eax<- resolved ClassObject ptr
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # got null?
+    je      common_exceptionThrown     # yes, handle exception
+    movl    offObject_clazz(rINST),%ecx  # ecx<- obj->clazz
+    jmp     .LOP_CHECK_CAST_JUMBO_resolved       # pick up where we left off
+
+/* ------------------------------ */
+.L_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: x86/OP_INSTANCE_OF_JUMBO.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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    movzwl  8(rPC),%eax                 # eax<- CCCC
+    GET_VREG_R %eax %eax                # eax<- vCCCC (obj)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                   # object null?
+    movl    offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    SPILL(rIBASE)                       # preserve rIBASE
+    je      .LOP_INSTANCE_OF_JUMBO_store           # null obj, not instance, store it
+    movl    2(rPC),rIBASE               # edx<- AAAAAAAA
+    movl    offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    movl    (%ecx,rIBASE,4),%ecx        # ecx<- resolved class
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    testl   %ecx,%ecx                   # have we resolved this before?
+    je      .LOP_INSTANCE_OF_JUMBO_resolve         # not resolved, do it now
+.LOP_INSTANCE_OF_JUMBO_resolved:  # eax<- obj->clazz, ecx<- resolved class
+    cmpl    %eax,%ecx                   # same class (trivial success)?
+    je      .LOP_INSTANCE_OF_JUMBO_trivial         # yes, trivial finish
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  eax holds obj->clazz
+     *  ecx holds class resolved from BBBB
+     *  rINST has BA
+     */
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    call    dvmInstanceofNonTrivial     # eax<- boolean result
+    # fall through to OP_INSTANCE_OF_JUMBO_store
+
+    /*
+     * eax holds boolean result
+     * rINST holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_store:
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    SET_VREG %eax rINST                 # vBBBB<- eax
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.LOP_INSTANCE_OF_JUMBO_trivial:
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    movl    $1,%eax
+    SET_VREG %eax rINST                 # vBBBB<- true
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  edx holds AAAAAAAA
+     */
+.LOP_INSTANCE_OF_JUMBO_resolve:
+    movl    rIBASE,OUT_ARG1(%esp)       # arg1<- AAAAAAAA
+    movl    rSELF,%ecx
+    movl    offThread_method(%ecx),%ecx
+    movl    $1,OUT_ARG2(%esp)          # arg2<- true
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    EXPORT_PC
+    movl    %ecx,OUT_ARG0(%esp)         # arg0<- method->clazz
+    call    dvmResolveClass             # eax<- resolved ClassObject ptr
+    testl   %eax,%eax                   # success?
+    je      common_exceptionThrown      # no, handle exception
+/* Now, we need to sync up with fast path.  We need eax to
+ * hold the obj->clazz, and ecx to hold the resolved class
+ */
+    movl    %eax,%ecx                   # ecx<- resolved class
+    movzwl  8(rPC),%eax                 # eax<- CCCC
+    GET_VREG_R %eax %eax                # eax<- vCCCC (obj)
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    jmp     .LOP_INSTANCE_OF_JUMBO_resolved
+
+/* ------------------------------ */
+.L_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: x86/OP_NEW_INSTANCE_JUMBO.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved class
+    SPILL(rIBASE)
+    testl     %ecx,%ecx                 # resolved?
+    je        .LOP_NEW_INSTANCE_JUMBO_resolve       # no, go do it
+.LOP_NEW_INSTANCE_JUMBO_resolved:  # on entry, ecx<- class
+    cmpb      $CLASS_INITIALIZED,offClassObject_status(%ecx)
+    jne       .LOP_NEW_INSTANCE_JUMBO_needinit
+.LOP_NEW_INSTANCE_JUMBO_initialized:  # on entry, ecx<- class
+    movl      $ALLOC_DONT_TRACK,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    call     dvmAllocObject             # eax<- new object
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 4 %ecx
+    testl    %eax,%eax                  # success?
+    je       common_exceptionThrown     # no, bail out
+    SET_VREG %eax rINST
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Class initialization required.
+     *
+     *  ecx holds class object
+     */
+.LOP_NEW_INSTANCE_JUMBO_needinit:
+    SPILL_TMP1(%ecx)                    # save object
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmInitClass                # initialize class
+    UNSPILL_TMP1(%ecx)                  # restore object
+    testl   %eax,%eax                   # success?
+    jne     .LOP_NEW_INSTANCE_JUMBO_initialized     # success, continue
+    jmp     common_exceptionThrown      # go deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     */
+.LOP_NEW_INSTANCE_JUMBO_resolve:
+    movl    rSELF,%ecx
+    movl    2(rPC),%eax                 # eax<- AAAAAAAA
+    movl    offThread_method(%ecx),%ecx   # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    movl    $0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass             # call(clazz,off,flags)
+    movl    %eax,%ecx                   # ecx<- resolved ClassObject ptr
+    testl   %ecx,%ecx                   # success?
+    jne     .LOP_NEW_INSTANCE_JUMBO_resolved        # good to go
+    jmp     common_exceptionThrown      # no, handle exception
+
+/* ------------------------------ */
+.L_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: x86/OP_NEW_ARRAY_JUMBO.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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movl    offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    movl    2(rPC),%eax                       # eax<- AAAAAAAA
+    movl    offDvmDex_pResClasses(%ecx),%ecx  # ecx<- pDvmDex->pResClasses
+    SPILL(rIBASE)
+    movl    (%ecx,%eax,4),%ecx                # ecx<- resolved class
+    movzwl  8(rPC),%eax                       # eax<- CCCC
+    GET_VREG_R %eax %eax                      # eax<- vCCCC (array length)
+    testl   %eax,%eax
+    js      common_errNegativeArraySize       # bail, passing len in eax
+    testl   %ecx,%ecx                         # already resolved?
+    jne     .LOP_NEW_ARRAY_JUMBO_finish                # yes, fast path
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *  ecx holds class (null here)
+     *  eax holds array length (vCCCC)
+     */
+    movl    rSELF,%ecx
+    SPILL_TMP1(%eax)                   # save array length
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movl    2(rPC),%eax                # eax<- AAAAAAAA
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass            # eax<- call(clazz,ref,flag)
+    movl    %eax,%ecx
+    UNSPILL_TMP1(%eax)
+    testl   %ecx,%ecx                  # successful resolution?
+    je      common_exceptionThrown     # no, bail.
+# fall through to OP_NEW_ARRAY_JUMBO_finish
+
+    /*
+     * Finish allocation
+     *
+     * ecx holds class
+     * eax holds array length (vCCCC)
+     */
+.LOP_NEW_ARRAY_JUMBO_finish:
+    movl    %ecx,OUT_ARG0(%esp)
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $ALLOC_DONT_TRACK,OUT_ARG2(%esp)
+    call    dvmAllocArrayByClass    # eax<- call(clazz,length,flags)
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 5 %ecx
+    testl   %eax,%eax               # failed?
+    je      common_exceptionThrown  # yup - go handle
+    SET_VREG %eax rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: x86/OP_FILLED_NEW_ARRAY_JUMBO.S */
+    /*
+     * Create a new array with elements filled from registers.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    movl    rSELF,%eax
+    movl    offThread_methodClassDex(%eax),%eax # eax<- pDvmDex
+    movl    2(rPC),%ecx                       # ecx<- AAAAAAAA
+    movl    offDvmDex_pResClasses(%eax),%eax  # eax<- pDvmDex->pResClasses
+    movl    (%eax,%ecx,4),%eax                # eax<- resolved class
+    EXPORT_PC
+    testl   %eax,%eax                         # already resolved?
+    jne     .LOP_FILLED_NEW_ARRAY_JUMBO_continue              # yes, continue
+    # less frequent path, so we'll redo some work
+    movl    rSELF,%eax
+    movl    $0,OUT_ARG2(%esp)                # arg2<- false
+    movl    %ecx,OUT_ARG1(%esp)               # arg1<- AAAAAAAA
+    movl    offThread_method(%eax),%eax         # eax<- self->method
+    movl    offMethod_clazz(%eax),%eax        # eax<- method->clazz
+    movl    %eax,OUT_ARG0(%esp)               # arg0<- clazz
+    SPILL(rIBASE)
+    call    dvmResolveClass                   # eax<- call(clazz,ref,flag)
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                         # null?
+    je      common_exceptionThrown            # yes, handle it
+
+       # note: fall through to .LOP_FILLED_NEW_ARRAY_JUMBO_continue
+
+    /*
+     * On entry:
+     *    eax holds array class [r0]
+     *    ecx is scratch
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_continue:
+    movl    offClassObject_descriptor(%eax),%ecx  # ecx<- arrayClass->descriptor
+    movl    $ALLOC_DONT_TRACK,OUT_ARG2(%esp)     # arg2<- flags
+    movzbl  1(%ecx),%ecx                          # ecx<- descriptor[1]
+    movl    %eax,OUT_ARG0(%esp)                   # arg0<- arrayClass
+    movl    rSELF,%eax
+    cmpb    $'I',%cl                             # supported?
+    je      1f
+    cmpb    $'L',%cl
+    je      1f
+    cmpb    $'[',%cl
+    jne      .LOP_FILLED_NEW_ARRAY_JUMBO_notimpl                  # no, not handled yet
+1:
+    movl    %ecx,offThread_retval+4(%eax)           # save type
+    movl    rINST,OUT_ARG1(%esp)                  # arg1<- BBBB (length)
+    SPILL(rIBASE)
+    call    dvmAllocArrayByClass     # eax<- call(arrayClass, length, flags)
+    UNSPILL(rIBASE)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                             # alloc successful?
+    je      common_exceptionThrown                # no, handle exception
+    movl    %eax,offThread_retval(%ecx)             # retval.l<- new array
+    movzwl  8(rPC),%ecx                           # ecx<- CCCC
+    leal    offArrayObject_contents(%eax),%eax    # eax<- newArray->contents
+
+/* at this point:
+ *     eax is pointer to tgt
+ *     rINST is length
+ *     ecx is CCCC
+ *  We now need to copy values from registers into the array
+ */
+
+    # set up src pointer
+    SPILL_TMP2(%esi)
+    SPILL_TMP3(%edi)
+    leal    (rFP,%ecx,4),%esi # set up src ptr
+    movl    %eax,%edi         # set up dst ptr
+    movl    rINST,%ecx        # load count register
+    rep
+    movsd
+    UNSPILL_TMP2(%esi)
+    UNSPILL_TMP3(%edi)
+    movl    rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+
+    cmpb    $'I',%al                        # Int array?
+    je      5f                               # skip card mark if so
+    movl    offThread_retval(%ecx),%eax        # eax<- object head
+    movl    offThread_cardTable(%ecx),%ecx     # card table base
+    shrl    $GC_CARD_SHIFT,%eax             # convert to card num
+    movb    %cl,(%ecx,%eax)                  # mark card based on object head
+5:
+    FETCH_INST_OPCODE 5 %ecx
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_JUMBO_notimpl:
+    movl    $.LstrFilledNewArrayNotImplA,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowInternalError
+    jmp     common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_IGET_JUMBO: /* 0x106 */
+/* File: x86/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
+
+/* ------------------------------ */
+.L_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: x86/OP_IGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_WIDE_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # for dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save objpointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IGET_WIDE_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_WIDE_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    movl    (%eax),%ecx                         # ecx<- lsw
+    movl    4(%eax),%eax                        # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: x86/OP_IGET_OBJECT_JUMBO.S */
+/* File: x86/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_OBJECT_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_OBJECT_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_OBJECT_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: x86/OP_IGET_BOOLEAN_JUMBO.S */
+/* File: x86/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_BOOLEAN_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_BOOLEAN_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_BOOLEAN_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movzbl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: x86/OP_IGET_BYTE_JUMBO.S */
+/* File: x86/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_BYTE_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_BYTE_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_BYTE_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movsbl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: x86/OP_IGET_CHAR_JUMBO.S */
+/* File: x86/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_CHAR_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_CHAR_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_CHAR_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movzwl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: x86/OP_IGET_SHORT_JUMBO.S */
+/* File: x86/OP_IGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IGET_SHORT_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .LOP_IGET_SHORT_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IGET_SHORT_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movswl   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
+
+
+/* ------------------------------ */
+.L_OP_IPUT_JUMBO: /* 0x10d */
+/* File: x86/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-object/jumbo, iput-boolean/jumbo, iput-byte/jumbo,
+            iput-char/jumbo, iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movl   rINST,(%ecx,%eax,1)            # obj.field <- v[BBBB](8/16/32 bits)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: x86/OP_IPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit instance field put.
+     */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_WIDE_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  ... which returns InstrField ptr
+    jne     .LOP_IPUT_WIDE_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_WIDE_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    GET_VREG_WORD %ecx rINST 0                  # ecx<- lsw
+    GET_VREG_WORD rINST rINST 1                 # rINST<- msw
+    movl    rINST,4(%eax)
+    movl    %ecx,(%eax)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: x86/OP_IPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo object field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                  # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_OBJECT_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_OBJECT_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_OBJECT_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                      # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl    rINST,(%ecx,%eax)      # obj.field <- v[BBBB](8/16/32 bits)
+    movl    rSELF,%eax
+    testl   rINST,rINST                         # stored a NULL?
+    movl    offThread_cardTable(%eax),%eax      # get card table base
+    je      1f                                  # skip card mark if null store
+    shrl    $GC_CARD_SHIFT,%ecx                # object head to card number
+    movb    %al,(%eax,%ecx)                     # mark card using object head
+1:
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+/* ------------------------------ */
+.L_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: x86/OP_IPUT_BOOLEAN_JUMBO.S */
+/* File: x86/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-object/jumbo, iput-boolean/jumbo, iput-byte/jumbo,
+            iput-char/jumbo, iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_BOOLEAN_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_BOOLEAN_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_BOOLEAN_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movb   rINSTbl,(%ecx,%eax,1)            # obj.field <- v[BBBB](8/16/32 bits)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: x86/OP_IPUT_BYTE_JUMBO.S */
+/* File: x86/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-object/jumbo, iput-boolean/jumbo, iput-byte/jumbo,
+            iput-char/jumbo, iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_BYTE_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_BYTE_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_BYTE_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movb   rINSTbl,(%ecx,%eax,1)            # obj.field <- v[BBBB](8/16/32 bits)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: x86/OP_IPUT_CHAR_JUMBO.S */
+/* File: x86/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-object/jumbo, iput-boolean/jumbo, iput-byte/jumbo,
+            iput-char/jumbo, iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_CHAR_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_CHAR_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_CHAR_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movw   rINSTw,(%ecx,%eax,1)            # obj.field <- v[BBBB](8/16/32 bits)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: x86/OP_IPUT_SHORT_JUMBO.S */
+/* File: x86/OP_IPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-object/jumbo, iput-boolean/jumbo, iput-byte/jumbo,
+            iput-char/jumbo, iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .LOP_IPUT_SHORT_JUMBO_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .LOP_IPUT_SHORT_JUMBO_finish
+    jmp     common_exceptionThrown
+
+.LOP_IPUT_SHORT_JUMBO_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    movw   rINSTw,(%ecx,%eax,1)            # obj.field <- v[BBBB](8/16/32 bits)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+
+/* ------------------------------ */
+.L_OP_SGET_JUMBO: /* 0x114 */
+/* File: x86/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_JUMBO_resolve                # if not, make it so
+.LOP_SGET_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: x86/OP_SGET_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SGET handler.
+     *
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_WIDE_JUMBO_resolve                # if not, make it so
+.LOP_SGET_WIDE_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%ecx    # ecx<- lsw
+    movl      4+offStaticField_value(%eax),%eax  # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_WIDE_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_WIDE_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: x86/OP_SGET_OBJECT_JUMBO.S */
+/* File: x86/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_OBJECT_JUMBO_resolve                # if not, make it so
+.LOP_SGET_OBJECT_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_OBJECT_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_OBJECT_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: x86/OP_SGET_BOOLEAN_JUMBO.S */
+/* File: x86/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_BOOLEAN_JUMBO_resolve                # if not, make it so
+.LOP_SGET_BOOLEAN_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_BOOLEAN_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_BOOLEAN_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: x86/OP_SGET_BYTE_JUMBO.S */
+/* File: x86/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_BYTE_JUMBO_resolve                # if not, make it so
+.LOP_SGET_BYTE_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_BYTE_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_BYTE_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: x86/OP_SGET_CHAR_JUMBO.S */
+/* File: x86/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_CHAR_JUMBO_resolve                # if not, make it so
+.LOP_SGET_CHAR_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_CHAR_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_CHAR_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: x86/OP_SGET_SHORT_JUMBO.S */
+/* File: x86/OP_SGET_JUMBO.S */
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SGET_SHORT_JUMBO_resolve                # if not, make it so
+.LOP_SGET_SHORT_JUMBO_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SGET_SHORT_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SGET_SHORT_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_JUMBO: /* 0x11b */
+/* File: x86/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_JUMBO_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: x86/OP_SPUT_WIDE_JUMBO.S */
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_WIDE_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_WIDE_JUMBO_finish:     # field ptr in eax
+    GET_VREG_WORD %ecx rINST 0                  # ecx<- lsw
+    GET_VREG_WORD rINST rINST 1                 # rINST<- msw
+    movl      %ecx,offStaticField_value(%eax)
+    FETCH_INST_OPCODE 4 %ecx
+    movl      rINST,4+offStaticField_value(%eax)
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_WIDE_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_WIDE_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: x86/OP_SPUT_OBJECT_JUMBO.S */
+    /*
+     * Jumbo SPUT object handler.
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_OBJECT_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_OBJECT_JUMBO_finish:                              # field ptr in eax
+    GET_VREG_R  %ecx rINST
+    movl      %ecx,offStaticField_value(%eax)    # do the store
+    testl     %ecx,%ecx                          # stored null object ptr?
+    je        1f                                 # skip card mark if null
+    movl      rSELF,%ecx
+    movl      offField_clazz(%eax),%eax          # eax<- method->clazz
+    movl      offThread_cardTable(%ecx),%ecx       # get card table base
+    shrl      $GC_CARD_SHIFT,%eax               # head to card number
+    movb      %cl,(%ecx,%eax)                    # mark card
+1:
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+.LOP_SPUT_OBJECT_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_OBJECT_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+/* ------------------------------ */
+.L_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: x86/OP_SPUT_BOOLEAN_JUMBO.S */
+/* File: x86/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_BOOLEAN_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_BOOLEAN_JUMBO_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_BOOLEAN_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_BOOLEAN_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: x86/OP_SPUT_BYTE_JUMBO.S */
+/* File: x86/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_BYTE_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_BYTE_JUMBO_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_BYTE_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_BYTE_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: x86/OP_SPUT_CHAR_JUMBO.S */
+/* File: x86/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_CHAR_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_CHAR_JUMBO_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_CHAR_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_CHAR_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: x86/OP_SPUT_SHORT_JUMBO.S */
+/* File: x86/OP_SPUT_JUMBO.S */
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .LOP_SPUT_SHORT_JUMBO_resolve                # if not, make it so
+.LOP_SPUT_SHORT_JUMBO_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.LOP_SPUT_SHORT_JUMBO_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .LOP_SPUT_SHORT_JUMBO_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: x86/OP_INVOKE_VIRTUAL_JUMBO.S */
+    /*
+     * Handle a jumbo virtual method call.
+     */
+    /* invoke-virtual/jumbo vBBBB, {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,%eax
+    movl      2(rPC),%ecx                 # ecx<- AAAAAAAA
+    movl      offThread_methodClassDex(%eax),%eax  # eax<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%eax),%eax   # eax<- pDvmDex->pResMethods
+    movl      (%eax,%ecx,4),%eax          # eax<- resolved baseMethod
+    testl     %eax,%eax                   # already resolved?
+    jne       .LOP_INVOKE_VIRTUAL_JUMBO_continue        # yes, continue
+    movl      rSELF,%eax
+    movl      %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    movl      offThread_method(%eax),%eax   # eax<- self->method
+    movl      offMethod_clazz(%eax),%eax  # ecx<- method->clazz
+    movl      %eax,OUT_ARG0(%esp)         # arg0<- clazz
+    movl      $METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- flags
+    call      dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl     %eax,%eax                   # got null?
+    jne       .LOP_INVOKE_VIRTUAL_JUMBO_continue        # no, continue
+    jmp       common_exceptionThrown      # yes, handle exception
+
+    /* At this point:
+     *   eax = resolved base method
+     *   ecx = scratch
+     */
+.LOP_INVOKE_VIRTUAL_JUMBO_continue:
+    movzwl    8(rPC),%ecx               # ecx<- CCCC
+    GET_VREG_R  %ecx %ecx               # ecx<- "this"
+    movzwl    offMethod_methodIndex(%eax),%eax  # eax<- baseMethod->methodIndex
+    testl     %ecx,%ecx                 # null this?
+    je        common_errNullObject      # go if so
+    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]
+    jmp       common_invokeMethodJumbo
+
+/* ------------------------------ */
+.L_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: x86/OP_INVOKE_SUPER_JUMBO.S */
+    /*
+     * Handle a jumbo "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,rINST
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(rINST),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved baseMethod
+    movl      offThread_method(rINST),%eax # eax<- method
+    movzwl    8(rPC),rINST              # rINST<- CCCC
+    GET_VREG_R  rINST rINST             # rINST<- "this" ptr
+    testl     rINST,rINST               # null "this"?
+    je        common_errNullObject      # yes, throw
+    movl      offMethod_clazz(%eax),%eax # eax<- method->clazz
+    testl     %ecx,%ecx                 # already resolved?
+    je       .LOP_INVOKE_SUPER_JUMBO_resolve
+    /*
+     * At this point:
+     *  ecx = resolved base method [r0]
+     *  eax = method->clazz [r9]
+     */
+.LOP_INVOKE_SUPER_JUMBO_continue:
+    movl    offClassObject_super(%eax),%eax   # eax<- method->clazz->super
+    movzwl  offMethod_methodIndex(%ecx),%ecx  # ecx<- baseMthod->methodIndex
+    cmpl    offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+    jae     .LOP_INVOKE_SUPER_JUMBO_nsm           # method not present in superclass
+    movl    offClassObject_vtable(%eax),%eax   # eax<- ...clazz->super->vtable
+    movl    (%eax,%ecx,4),%eax        # eax<- vtable[methodIndex]
+    jmp     common_invokeMethodJumbo
+
+
+    /* At this point:
+     * ecx = null (needs to be resolved base method)
+     * eax = method->clazz
+    */
+.LOP_INVOKE_SUPER_JUMBO_resolve:
+    SPILL_TMP1(%eax)                    # method->clazz
+    movl    %eax,OUT_ARG0(%esp)         # arg0<- method->clazz
+    movl    2(rPC),%ecx                 # ecx<- AAAAAAAA
+    movl    $METHOD_VIRTUAL,OUT_ARG2(%esp)  # arg2<- resolver method type
+    movl    %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    call    dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl   %eax,%eax                   # got null?
+    movl    %eax,%ecx                   # ecx<- resolved base method
+    UNSPILL_TMP1(%eax)                  # restore method->clazz
+    jne     .LOP_INVOKE_SUPER_JUMBO_continue        # good to go - continue
+    jmp     common_exceptionThrown      # handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  ecx = resolved base method
+     */
+.LOP_INVOKE_SUPER_JUMBO_nsm:
+    movl    offMethod_name(%ecx),%eax
+    jmp     common_errNoSuchMethod
+
+/* ------------------------------ */
+.L_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: x86/OP_INVOKE_DIRECT_JUMBO.S */
+    /*
+     * Handle a jumbo 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.)
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax              # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movzwl    8(rPC),rIBASE            # rIBASE<- CCCC
+    movl      (%ecx,%eax,4),%eax       # eax<- resolved methodToCall
+    testl     %eax,%eax                # already resolved?
+    GET_VREG_R  %ecx rIBASE            # ecx<- "this" ptr
+    je        .LOP_INVOKE_DIRECT_JUMBO_resolve      # not resolved, do it now
+.LOP_INVOKE_DIRECT_JUMBO_finish:
+    testl     %ecx,%ecx                # null "this"?
+    jne       common_invokeMethodJumbo # no, continue on
+    jmp       common_errNullObject
+
+    /*
+     * On entry:
+     *   TMP_SPILL  <- "this" register
+     * Things a bit ugly on this path, but it's the less
+     * frequent one.  We'll have to do some reloading.
+     */
+.LOP_INVOKE_DIRECT_JUMBO_resolve:
+     SPILL_TMP1(%ecx)
+     movl     rSELF,%ecx
+     movl     offThread_method(%ecx),%ecx  # ecx<- self->method
+     movl     2(rPC),%eax      # reference AAAAAAAA
+     movl     offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+     movl     $METHOD_DIRECT,OUT_ARG2(%esp)
+     movl     %eax,OUT_ARG1(%esp)
+     movl     %ecx,OUT_ARG0(%esp)
+     call     dvmResolveMethod # eax<- call(clazz, ref, flags)
+     UNSPILL_TMP1(%ecx)
+     testl    %eax,%eax
+     jne      .LOP_INVOKE_DIRECT_JUMBO_finish
+     jmp      common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: x86/OP_INVOKE_STATIC_JUMBO.S */
+    /*
+     * Handle a jumbo static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved methodToCall
+    testl     %eax,%eax
+    jne       common_invokeMethodJumbo
+    movl      rSELF,%ecx
+    movl      offThread_method(%ecx),%ecx # ecx<- self->method
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offMethod_clazz(%ecx),%ecx# ecx<- method->clazz
+    movl      %eax,OUT_ARG1(%esp)       # arg1<- AAAAAAAA
+    movl      %ecx,OUT_ARG0(%esp)       # arg0<- clazz
+    movl      $METHOD_STATIC,%eax
+    movl      %eax,OUT_ARG2(%esp)       # arg2<- flags
+    call      dvmResolveMethod          # call(clazz,ref,flags)
+    testl     %eax,%eax                 # got null?
+    jne       common_invokeMethodJumbo
+    jmp       common_exceptionThrown
+
+/* ------------------------------ */
+.L_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: x86/OP_INVOKE_INTERFACE_JUMBO.S */
+    /*
+     * Handle a jumbo interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movzwl     8(rPC),%eax              # eax<- CCCC
+    movl       rSELF,%ecx
+    GET_VREG_R   %eax %eax              # eax<- "this"
+    EXPORT_PC
+    testl      %eax,%eax                # null this?
+    je         common_errNullObject     # yes, fail
+    movl       offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
+    movl       %eax,OUT_ARG0(%esp)                 # arg0<- class
+    movl       offThread_methodClassDex(%ecx),%eax   # eax<- methodClassDex
+    movl       offThread_method(%ecx),%ecx           # ecx<- method
+    movl       %eax,OUT_ARG3(%esp)                 # arg3<- dex
+    movl       2(rPC),%eax                         # eax<- AAAAAAAA
+    movl       %ecx,OUT_ARG2(%esp)                 # arg2<- method
+    movl       %eax,OUT_ARG1(%esp)                 # arg1<- AAAAAAAA
+    call       dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
+    testl      %eax,%eax
+    je         common_exceptionThrown
+    jmp        common_invokeMethodJumbo
+
+/* ------------------------------ */
+.L_OP_UNUSED_27FF: /* 0x127 */
+/* File: x86/OP_UNUSED_27FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_28FF: /* 0x128 */
+/* File: x86/OP_UNUSED_28FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_29FF: /* 0x129 */
+/* File: x86/OP_UNUSED_29FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_2AFF: /* 0x12a */
+/* File: x86/OP_UNUSED_2AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_2BFF: /* 0x12b */
+/* File: x86/OP_UNUSED_2BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_2CFF: /* 0x12c */
+/* File: x86/OP_UNUSED_2CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_2DFF: /* 0x12d */
+/* File: x86/OP_UNUSED_2DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_2EFF: /* 0x12e */
+/* File: x86/OP_UNUSED_2EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_2FFF: /* 0x12f */
+/* File: x86/OP_UNUSED_2FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_30FF: /* 0x130 */
+/* File: x86/OP_UNUSED_30FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_31FF: /* 0x131 */
+/* File: x86/OP_UNUSED_31FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_32FF: /* 0x132 */
+/* File: x86/OP_UNUSED_32FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_33FF: /* 0x133 */
+/* File: x86/OP_UNUSED_33FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_34FF: /* 0x134 */
+/* File: x86/OP_UNUSED_34FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_35FF: /* 0x135 */
+/* File: x86/OP_UNUSED_35FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_36FF: /* 0x136 */
+/* File: x86/OP_UNUSED_36FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_37FF: /* 0x137 */
+/* File: x86/OP_UNUSED_37FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_38FF: /* 0x138 */
+/* File: x86/OP_UNUSED_38FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_39FF: /* 0x139 */
+/* File: x86/OP_UNUSED_39FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3AFF: /* 0x13a */
+/* File: x86/OP_UNUSED_3AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3BFF: /* 0x13b */
+/* File: x86/OP_UNUSED_3BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3CFF: /* 0x13c */
+/* File: x86/OP_UNUSED_3CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3DFF: /* 0x13d */
+/* File: x86/OP_UNUSED_3DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3EFF: /* 0x13e */
+/* File: x86/OP_UNUSED_3EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_3FFF: /* 0x13f */
+/* File: x86/OP_UNUSED_3FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_40FF: /* 0x140 */
+/* File: x86/OP_UNUSED_40FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_41FF: /* 0x141 */
+/* File: x86/OP_UNUSED_41FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_42FF: /* 0x142 */
+/* File: x86/OP_UNUSED_42FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_43FF: /* 0x143 */
+/* File: x86/OP_UNUSED_43FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_44FF: /* 0x144 */
+/* File: x86/OP_UNUSED_44FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_45FF: /* 0x145 */
+/* File: x86/OP_UNUSED_45FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_46FF: /* 0x146 */
+/* File: x86/OP_UNUSED_46FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_47FF: /* 0x147 */
+/* File: x86/OP_UNUSED_47FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_48FF: /* 0x148 */
+/* File: x86/OP_UNUSED_48FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_49FF: /* 0x149 */
+/* File: x86/OP_UNUSED_49FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_4AFF: /* 0x14a */
+/* File: x86/OP_UNUSED_4AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_4BFF: /* 0x14b */
+/* File: x86/OP_UNUSED_4BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_4CFF: /* 0x14c */
+/* File: x86/OP_UNUSED_4CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_4DFF: /* 0x14d */
+/* File: x86/OP_UNUSED_4DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_4EFF: /* 0x14e */
+/* File: x86/OP_UNUSED_4EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_4FFF: /* 0x14f */
+/* File: x86/OP_UNUSED_4FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_50FF: /* 0x150 */
+/* File: x86/OP_UNUSED_50FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_51FF: /* 0x151 */
+/* File: x86/OP_UNUSED_51FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_52FF: /* 0x152 */
+/* File: x86/OP_UNUSED_52FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_53FF: /* 0x153 */
+/* File: x86/OP_UNUSED_53FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_54FF: /* 0x154 */
+/* File: x86/OP_UNUSED_54FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_55FF: /* 0x155 */
+/* File: x86/OP_UNUSED_55FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_56FF: /* 0x156 */
+/* File: x86/OP_UNUSED_56FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_57FF: /* 0x157 */
+/* File: x86/OP_UNUSED_57FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_58FF: /* 0x158 */
+/* File: x86/OP_UNUSED_58FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_59FF: /* 0x159 */
+/* File: x86/OP_UNUSED_59FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_5AFF: /* 0x15a */
+/* File: x86/OP_UNUSED_5AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_5BFF: /* 0x15b */
+/* File: x86/OP_UNUSED_5BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_5CFF: /* 0x15c */
+/* File: x86/OP_UNUSED_5CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_5DFF: /* 0x15d */
+/* File: x86/OP_UNUSED_5DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_5EFF: /* 0x15e */
+/* File: x86/OP_UNUSED_5EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_5FFF: /* 0x15f */
+/* File: x86/OP_UNUSED_5FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_60FF: /* 0x160 */
+/* File: x86/OP_UNUSED_60FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_61FF: /* 0x161 */
+/* File: x86/OP_UNUSED_61FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_62FF: /* 0x162 */
+/* File: x86/OP_UNUSED_62FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_63FF: /* 0x163 */
+/* File: x86/OP_UNUSED_63FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_64FF: /* 0x164 */
+/* File: x86/OP_UNUSED_64FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_65FF: /* 0x165 */
+/* File: x86/OP_UNUSED_65FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_66FF: /* 0x166 */
+/* File: x86/OP_UNUSED_66FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_67FF: /* 0x167 */
+/* File: x86/OP_UNUSED_67FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_68FF: /* 0x168 */
+/* File: x86/OP_UNUSED_68FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_69FF: /* 0x169 */
+/* File: x86/OP_UNUSED_69FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_6AFF: /* 0x16a */
+/* File: x86/OP_UNUSED_6AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_6BFF: /* 0x16b */
+/* File: x86/OP_UNUSED_6BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_6CFF: /* 0x16c */
+/* File: x86/OP_UNUSED_6CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_6DFF: /* 0x16d */
+/* File: x86/OP_UNUSED_6DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_6EFF: /* 0x16e */
+/* File: x86/OP_UNUSED_6EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_6FFF: /* 0x16f */
+/* File: x86/OP_UNUSED_6FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_70FF: /* 0x170 */
+/* File: x86/OP_UNUSED_70FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_71FF: /* 0x171 */
+/* File: x86/OP_UNUSED_71FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_72FF: /* 0x172 */
+/* File: x86/OP_UNUSED_72FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_73FF: /* 0x173 */
+/* File: x86/OP_UNUSED_73FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_74FF: /* 0x174 */
+/* File: x86/OP_UNUSED_74FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_75FF: /* 0x175 */
+/* File: x86/OP_UNUSED_75FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_76FF: /* 0x176 */
+/* File: x86/OP_UNUSED_76FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_77FF: /* 0x177 */
+/* File: x86/OP_UNUSED_77FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_78FF: /* 0x178 */
+/* File: x86/OP_UNUSED_78FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_79FF: /* 0x179 */
+/* File: x86/OP_UNUSED_79FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7AFF: /* 0x17a */
+/* File: x86/OP_UNUSED_7AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7BFF: /* 0x17b */
+/* File: x86/OP_UNUSED_7BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7CFF: /* 0x17c */
+/* File: x86/OP_UNUSED_7CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7DFF: /* 0x17d */
+/* File: x86/OP_UNUSED_7DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7EFF: /* 0x17e */
+/* File: x86/OP_UNUSED_7EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_7FFF: /* 0x17f */
+/* File: x86/OP_UNUSED_7FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_80FF: /* 0x180 */
+/* File: x86/OP_UNUSED_80FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_81FF: /* 0x181 */
+/* File: x86/OP_UNUSED_81FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_82FF: /* 0x182 */
+/* File: x86/OP_UNUSED_82FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_83FF: /* 0x183 */
+/* File: x86/OP_UNUSED_83FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_84FF: /* 0x184 */
+/* File: x86/OP_UNUSED_84FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_85FF: /* 0x185 */
+/* File: x86/OP_UNUSED_85FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_86FF: /* 0x186 */
+/* File: x86/OP_UNUSED_86FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_87FF: /* 0x187 */
+/* File: x86/OP_UNUSED_87FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_88FF: /* 0x188 */
+/* File: x86/OP_UNUSED_88FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_89FF: /* 0x189 */
+/* File: x86/OP_UNUSED_89FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_8AFF: /* 0x18a */
+/* File: x86/OP_UNUSED_8AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_8BFF: /* 0x18b */
+/* File: x86/OP_UNUSED_8BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_8CFF: /* 0x18c */
+/* File: x86/OP_UNUSED_8CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_8DFF: /* 0x18d */
+/* File: x86/OP_UNUSED_8DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_8EFF: /* 0x18e */
+/* File: x86/OP_UNUSED_8EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_8FFF: /* 0x18f */
+/* File: x86/OP_UNUSED_8FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_90FF: /* 0x190 */
+/* File: x86/OP_UNUSED_90FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_91FF: /* 0x191 */
+/* File: x86/OP_UNUSED_91FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_92FF: /* 0x192 */
+/* File: x86/OP_UNUSED_92FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_93FF: /* 0x193 */
+/* File: x86/OP_UNUSED_93FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_94FF: /* 0x194 */
+/* File: x86/OP_UNUSED_94FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_95FF: /* 0x195 */
+/* File: x86/OP_UNUSED_95FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_96FF: /* 0x196 */
+/* File: x86/OP_UNUSED_96FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_97FF: /* 0x197 */
+/* File: x86/OP_UNUSED_97FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_98FF: /* 0x198 */
+/* File: x86/OP_UNUSED_98FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_99FF: /* 0x199 */
+/* File: x86/OP_UNUSED_99FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_9AFF: /* 0x19a */
+/* File: x86/OP_UNUSED_9AFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_9BFF: /* 0x19b */
+/* File: x86/OP_UNUSED_9BFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_9CFF: /* 0x19c */
+/* File: x86/OP_UNUSED_9CFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_9DFF: /* 0x19d */
+/* File: x86/OP_UNUSED_9DFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_9EFF: /* 0x19e */
+/* File: x86/OP_UNUSED_9EFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_9FFF: /* 0x19f */
+/* File: x86/OP_UNUSED_9FFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: x86/OP_UNUSED_A0FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: x86/OP_UNUSED_A1FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: x86/OP_UNUSED_A2FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: x86/OP_UNUSED_A3FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: x86/OP_UNUSED_A4FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: x86/OP_UNUSED_A5FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: x86/OP_UNUSED_A6FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: x86/OP_UNUSED_A7FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: x86/OP_UNUSED_A8FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: x86/OP_UNUSED_A9FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: x86/OP_UNUSED_AAFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: x86/OP_UNUSED_ABFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: x86/OP_UNUSED_ACFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: x86/OP_UNUSED_ADFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: x86/OP_UNUSED_AEFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_AFFF: /* 0x1af */
+/* File: x86/OP_UNUSED_AFFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: x86/OP_UNUSED_B0FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: x86/OP_UNUSED_B1FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: x86/OP_UNUSED_B2FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: x86/OP_UNUSED_B3FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: x86/OP_UNUSED_B4FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: x86/OP_UNUSED_B5FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: x86/OP_UNUSED_B6FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: x86/OP_UNUSED_B7FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: x86/OP_UNUSED_B8FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: x86/OP_UNUSED_B9FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: x86/OP_UNUSED_BAFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: x86/OP_UNUSED_BBFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: x86/OP_UNUSED_BCFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: x86/OP_UNUSED_BDFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_BEFF: /* 0x1be */
+/* File: x86/OP_UNUSED_BEFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: x86/OP_UNUSED_BFFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: x86/OP_UNUSED_C0FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: x86/OP_UNUSED_C1FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: x86/OP_UNUSED_C2FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: x86/OP_UNUSED_C3FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: x86/OP_UNUSED_C4FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: x86/OP_UNUSED_C5FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: x86/OP_UNUSED_C6FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: x86/OP_UNUSED_C7FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: x86/OP_UNUSED_C8FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: x86/OP_UNUSED_C9FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: x86/OP_UNUSED_CAFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: x86/OP_UNUSED_CBFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: x86/OP_UNUSED_CCFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: x86/OP_UNUSED_CDFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: x86/OP_UNUSED_CEFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: x86/OP_UNUSED_CFFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: x86/OP_UNUSED_D0FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: x86/OP_UNUSED_D1FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: x86/OP_UNUSED_D2FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: x86/OP_UNUSED_D3FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: x86/OP_UNUSED_D4FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: x86/OP_UNUSED_D5FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: x86/OP_UNUSED_D6FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: x86/OP_UNUSED_D7FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: x86/OP_UNUSED_D8FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: x86/OP_UNUSED_D9FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_DAFF: /* 0x1da */
+/* File: x86/OP_UNUSED_DAFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_DBFF: /* 0x1db */
+/* File: x86/OP_UNUSED_DBFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: x86/OP_UNUSED_DCFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: x86/OP_UNUSED_DDFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_DEFF: /* 0x1de */
+/* File: x86/OP_UNUSED_DEFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_DFFF: /* 0x1df */
+/* File: x86/OP_UNUSED_DFFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: x86/OP_UNUSED_E0FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: x86/OP_UNUSED_E1FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: x86/OP_UNUSED_E2FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: x86/OP_UNUSED_E3FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: x86/OP_UNUSED_E4FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: x86/OP_UNUSED_E5FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: x86/OP_UNUSED_E6FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: x86/OP_UNUSED_E7FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: x86/OP_UNUSED_E8FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: x86/OP_UNUSED_E9FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: x86/OP_UNUSED_EAFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: x86/OP_UNUSED_EBFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: x86/OP_UNUSED_ECFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: x86/OP_UNUSED_EDFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: x86/OP_UNUSED_EEFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: x86/OP_UNUSED_EFFF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: x86/OP_UNUSED_F0FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: x86/OP_UNUSED_F1FF.S */
+/* File: x86/unused.S */
+    jmp     common_abort
+
+
+/* ------------------------------ */
+.L_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_INVOKE_OBJECT_INIT_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IGET_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IGET_WIDE_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IGET_OBJECT_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IPUT_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IPUT_WIDE_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_IPUT_OBJECT_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SGET_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SGET_WIDE_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SGET_OBJECT_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SPUT_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SPUT_WIDE_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_OP_SPUT_OBJECT_VOLATILE_JUMBO     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
+/* ------------------------------ */
+.L_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: x86/OP_THROW_VERIFICATION_ERROR_JUMBO.S */
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, ref@AAAAAAAA */
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                     # eax<- AAAAAAAA
+    movl     offThread_method(%ecx),%ecx       # ecx<- self->method
+    EXPORT_PC
+    movl     %eax,OUT_ARG2(%esp)             # arg2<- AAAAAAAA
+    movl     rINST,OUT_ARG1(%esp)            # arg1<- BBBB
+    movl     %ecx,OUT_ARG0(%esp)             # arg0<- method
+    call     dvmThrowVerificationError       # call(method, kind, ref)
+    jmp      common_exceptionThrown          # handle exception
+
+    .size   dvmAsmInstructionStartCode, .-dvmAsmInstructionStartCode
+    .global dvmAsmInstructionEndCode
+dvmAsmInstructionEndCode:
+
+    .global dvmAsmAltInstructionStartCode
+    .type   dvmAsmAltInstructionStartCode, %function
+    .text
+
+dvmAsmAltInstructionStartCode = .L_ALT_OP_NOP
+/* ------------------------------ */
+.L_ALT_OP_NOP: /* 0x00 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(0*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE: /* 0x01 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(1*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_FROM16: /* 0x02 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(2*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_16: /* 0x03 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(3*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_WIDE: /* 0x04 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(4*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(5*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(6*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_OBJECT: /* 0x07 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(7*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(8*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(9*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_RESULT: /* 0x0a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(10*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(11*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(12*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(13*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RETURN_VOID: /* 0x0e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(14*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RETURN: /* 0x0f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(15*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RETURN_WIDE: /* 0x10 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(16*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RETURN_OBJECT: /* 0x11 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(17*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_4: /* 0x12 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(18*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_16: /* 0x13 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(19*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST: /* 0x14 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(20*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_HIGH16: /* 0x15 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(21*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_WIDE_16: /* 0x16 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(22*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_WIDE_32: /* 0x17 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(23*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_WIDE: /* 0x18 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(24*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(25*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_STRING: /* 0x1a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(26*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(27*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_CLASS: /* 0x1c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(28*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MONITOR_ENTER: /* 0x1d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(29*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MONITOR_EXIT: /* 0x1e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(30*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CHECK_CAST: /* 0x1f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(31*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INSTANCE_OF: /* 0x20 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(32*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(33*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEW_INSTANCE: /* 0x22 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(34*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEW_ARRAY: /* 0x23 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(35*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(36*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(37*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(38*4)
+
+/* ------------------------------ */
+.L_ALT_OP_THROW: /* 0x27 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(39*4)
+
+/* ------------------------------ */
+.L_ALT_OP_GOTO: /* 0x28 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(40*4)
+
+/* ------------------------------ */
+.L_ALT_OP_GOTO_16: /* 0x29 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(41*4)
+
+/* ------------------------------ */
+.L_ALT_OP_GOTO_32: /* 0x2a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(42*4)
+
+/* ------------------------------ */
+.L_ALT_OP_PACKED_SWITCH: /* 0x2b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(43*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(44*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CMPL_FLOAT: /* 0x2d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(45*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CMPG_FLOAT: /* 0x2e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(46*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(47*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(48*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CMP_LONG: /* 0x31 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(49*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_EQ: /* 0x32 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(50*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_NE: /* 0x33 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(51*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_LT: /* 0x34 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(52*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_GE: /* 0x35 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(53*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_GT: /* 0x36 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(54*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_LE: /* 0x37 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(55*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_EQZ: /* 0x38 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(56*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_NEZ: /* 0x39 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(57*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_LTZ: /* 0x3a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(58*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_GEZ: /* 0x3b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(59*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_GTZ: /* 0x3c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(60*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IF_LEZ: /* 0x3d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(61*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3E: /* 0x3e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(62*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3F: /* 0x3f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(63*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_40: /* 0x40 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(64*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_41: /* 0x41 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(65*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_42: /* 0x42 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(66*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_43: /* 0x43 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(67*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET: /* 0x44 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(68*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET_WIDE: /* 0x45 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(69*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET_OBJECT: /* 0x46 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(70*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(71*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET_BYTE: /* 0x48 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(72*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET_CHAR: /* 0x49 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(73*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AGET_SHORT: /* 0x4a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(74*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT: /* 0x4b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(75*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT_WIDE: /* 0x4c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(76*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT_OBJECT: /* 0x4d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(77*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(78*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT_BYTE: /* 0x4f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(79*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT_CHAR: /* 0x50 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(80*4)
+
+/* ------------------------------ */
+.L_ALT_OP_APUT_SHORT: /* 0x51 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(81*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET: /* 0x52 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(82*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_WIDE: /* 0x53 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(83*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_OBJECT: /* 0x54 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(84*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(85*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_BYTE: /* 0x56 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(86*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_CHAR: /* 0x57 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(87*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_SHORT: /* 0x58 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(88*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT: /* 0x59 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(89*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_WIDE: /* 0x5a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(90*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_OBJECT: /* 0x5b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(91*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(92*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_BYTE: /* 0x5d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(93*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_CHAR: /* 0x5e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(94*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_SHORT: /* 0x5f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(95*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET: /* 0x60 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(96*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_WIDE: /* 0x61 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(97*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_OBJECT: /* 0x62 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(98*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(99*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_BYTE: /* 0x64 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(100*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_CHAR: /* 0x65 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(101*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_SHORT: /* 0x66 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(102*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT: /* 0x67 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(103*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_WIDE: /* 0x68 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(104*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_OBJECT: /* 0x69 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(105*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(106*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_BYTE: /* 0x6b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(107*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_CHAR: /* 0x6c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(108*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_SHORT: /* 0x6d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(109*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(110*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_SUPER: /* 0x6f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(111*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(112*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_STATIC: /* 0x71 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(113*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(114*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_73: /* 0x73 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(115*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(116*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(117*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(118*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(119*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(120*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_79: /* 0x79 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(121*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7A: /* 0x7a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(122*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEG_INT: /* 0x7b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(123*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NOT_INT: /* 0x7c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(124*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEG_LONG: /* 0x7d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(125*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NOT_LONG: /* 0x7e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(126*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEG_FLOAT: /* 0x7f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(127*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEG_DOUBLE: /* 0x80 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(128*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INT_TO_LONG: /* 0x81 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(129*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(130*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(131*4)
+
+/* ------------------------------ */
+.L_ALT_OP_LONG_TO_INT: /* 0x84 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(132*4)
+
+/* ------------------------------ */
+.L_ALT_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(133*4)
+
+/* ------------------------------ */
+.L_ALT_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(134*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(135*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(136*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(137*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(138*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(139*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(140*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INT_TO_BYTE: /* 0x8d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(141*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INT_TO_CHAR: /* 0x8e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(142*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INT_TO_SHORT: /* 0x8f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(143*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_INT: /* 0x90 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(144*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_INT: /* 0x91 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(145*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_INT: /* 0x92 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(146*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_INT: /* 0x93 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(147*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_INT: /* 0x94 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(148*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AND_INT: /* 0x95 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(149*4)
+
+/* ------------------------------ */
+.L_ALT_OP_OR_INT: /* 0x96 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(150*4)
+
+/* ------------------------------ */
+.L_ALT_OP_XOR_INT: /* 0x97 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(151*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHL_INT: /* 0x98 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(152*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHR_INT: /* 0x99 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(153*4)
+
+/* ------------------------------ */
+.L_ALT_OP_USHR_INT: /* 0x9a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(154*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_LONG: /* 0x9b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(155*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_LONG: /* 0x9c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(156*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_LONG: /* 0x9d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(157*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_LONG: /* 0x9e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(158*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_LONG: /* 0x9f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(159*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AND_LONG: /* 0xa0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(160*4)
+
+/* ------------------------------ */
+.L_ALT_OP_OR_LONG: /* 0xa1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(161*4)
+
+/* ------------------------------ */
+.L_ALT_OP_XOR_LONG: /* 0xa2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(162*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHL_LONG: /* 0xa3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(163*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHR_LONG: /* 0xa4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(164*4)
+
+/* ------------------------------ */
+.L_ALT_OP_USHR_LONG: /* 0xa5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(165*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_FLOAT: /* 0xa6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(166*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_FLOAT: /* 0xa7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(167*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_FLOAT: /* 0xa8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(168*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_FLOAT: /* 0xa9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(169*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_FLOAT: /* 0xaa */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(170*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_DOUBLE: /* 0xab */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(171*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_DOUBLE: /* 0xac */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(172*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_DOUBLE: /* 0xad */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(173*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_DOUBLE: /* 0xae */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(174*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_DOUBLE: /* 0xaf */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(175*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(176*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(177*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(178*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(179*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(180*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(181*4)
+
+/* ------------------------------ */
+.L_ALT_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(182*4)
+
+/* ------------------------------ */
+.L_ALT_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(183*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(184*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(185*4)
+
+/* ------------------------------ */
+.L_ALT_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(186*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(187*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(188*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(189*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(190*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(191*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(192*4)
+
+/* ------------------------------ */
+.L_ALT_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(193*4)
+
+/* ------------------------------ */
+.L_ALT_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(194*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(195*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(196*4)
+
+/* ------------------------------ */
+.L_ALT_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(197*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(198*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(199*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(200*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(201*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(202*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(203*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(204*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(205*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(206*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(207*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(208*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RSUB_INT: /* 0xd1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(209*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(210*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(211*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(212*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(213*4)
+
+/* ------------------------------ */
+.L_ALT_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(214*4)
+
+/* ------------------------------ */
+.L_ALT_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(215*4)
+
+/* ------------------------------ */
+.L_ALT_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(216*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(217*4)
+
+/* ------------------------------ */
+.L_ALT_OP_MUL_INT_LIT8: /* 0xda */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(218*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(219*4)
+
+/* ------------------------------ */
+.L_ALT_OP_REM_INT_LIT8: /* 0xdc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(220*4)
+
+/* ------------------------------ */
+.L_ALT_OP_AND_INT_LIT8: /* 0xdd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(221*4)
+
+/* ------------------------------ */
+.L_ALT_OP_OR_INT_LIT8: /* 0xde */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(222*4)
+
+/* ------------------------------ */
+.L_ALT_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(223*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(224*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(225*4)
+
+/* ------------------------------ */
+.L_ALT_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(226*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_VOLATILE: /* 0xe3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(227*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_VOLATILE: /* 0xe4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(228*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_VOLATILE: /* 0xe5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(229*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_VOLATILE: /* 0xe6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(230*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_OBJECT_VOLATILE: /* 0xe7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(231*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_WIDE_VOLATILE: /* 0xe8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(232*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_WIDE_VOLATILE: /* 0xe9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(233*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_WIDE_VOLATILE: /* 0xea */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(234*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_WIDE_VOLATILE: /* 0xeb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(235*4)
+
+/* ------------------------------ */
+.L_ALT_OP_BREAKPOINT: /* 0xec */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(236*4)
+
+/* ------------------------------ */
+.L_ALT_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(237*4)
+
+/* ------------------------------ */
+.L_ALT_OP_EXECUTE_INLINE: /* 0xee */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(238*4)
+
+/* ------------------------------ */
+.L_ALT_OP_EXECUTE_INLINE_RANGE: /* 0xef */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(239*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_OBJECT_INIT_RANGE: /* 0xf0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(240*4)
+
+/* ------------------------------ */
+.L_ALT_OP_RETURN_VOID_BARRIER: /* 0xf1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(241*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_QUICK: /* 0xf2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(242*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(243*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(244*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_QUICK: /* 0xf5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(245*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(246*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(247*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(248*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(249*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(250*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(251*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_OBJECT_VOLATILE: /* 0xfc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(252*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_OBJECT_VOLATILE: /* 0xfd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(253*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_OBJECT_VOLATILE: /* 0xfe */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(254*4)
+
+/* ------------------------------ */
+.L_ALT_OP_DISPATCH_FF: /* 0xff */
+/* File: x86/ALT_OP_DISPATCH_FF.S */
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    leal      256(rINST),%ecx
+    GOTO_NEXT_JUMBO_R %ecx
+
+/* ------------------------------ */
+.L_ALT_OP_CONST_CLASS_JUMBO: /* 0x100 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(256*4)
+
+/* ------------------------------ */
+.L_ALT_OP_CHECK_CAST_JUMBO: /* 0x101 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(257*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INSTANCE_OF_JUMBO: /* 0x102 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(258*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEW_INSTANCE_JUMBO: /* 0x103 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(259*4)
+
+/* ------------------------------ */
+.L_ALT_OP_NEW_ARRAY_JUMBO: /* 0x104 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(260*4)
+
+/* ------------------------------ */
+.L_ALT_OP_FILLED_NEW_ARRAY_JUMBO: /* 0x105 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(261*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_JUMBO: /* 0x106 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(262*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_WIDE_JUMBO: /* 0x107 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(263*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_OBJECT_JUMBO: /* 0x108 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(264*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_BOOLEAN_JUMBO: /* 0x109 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(265*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_BYTE_JUMBO: /* 0x10a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(266*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_CHAR_JUMBO: /* 0x10b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(267*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_SHORT_JUMBO: /* 0x10c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(268*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_JUMBO: /* 0x10d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(269*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_WIDE_JUMBO: /* 0x10e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(270*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_OBJECT_JUMBO: /* 0x10f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(271*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_BOOLEAN_JUMBO: /* 0x110 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(272*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_BYTE_JUMBO: /* 0x111 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(273*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_CHAR_JUMBO: /* 0x112 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(274*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_SHORT_JUMBO: /* 0x113 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(275*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_JUMBO: /* 0x114 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(276*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_WIDE_JUMBO: /* 0x115 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(277*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_OBJECT_JUMBO: /* 0x116 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(278*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_BOOLEAN_JUMBO: /* 0x117 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(279*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_BYTE_JUMBO: /* 0x118 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(280*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_CHAR_JUMBO: /* 0x119 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(281*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_SHORT_JUMBO: /* 0x11a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(282*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_JUMBO: /* 0x11b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(283*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_WIDE_JUMBO: /* 0x11c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(284*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_OBJECT_JUMBO: /* 0x11d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(285*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_BOOLEAN_JUMBO: /* 0x11e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(286*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_BYTE_JUMBO: /* 0x11f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(287*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_CHAR_JUMBO: /* 0x120 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(288*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_SHORT_JUMBO: /* 0x121 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(289*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_VIRTUAL_JUMBO: /* 0x122 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(290*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_SUPER_JUMBO: /* 0x123 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(291*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_DIRECT_JUMBO: /* 0x124 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(292*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_STATIC_JUMBO: /* 0x125 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(293*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_INTERFACE_JUMBO: /* 0x126 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(294*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_27FF: /* 0x127 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(295*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_28FF: /* 0x128 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(296*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_29FF: /* 0x129 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(297*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_2AFF: /* 0x12a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(298*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_2BFF: /* 0x12b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(299*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_2CFF: /* 0x12c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(300*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_2DFF: /* 0x12d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(301*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_2EFF: /* 0x12e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(302*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_2FFF: /* 0x12f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(303*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_30FF: /* 0x130 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(304*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_31FF: /* 0x131 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(305*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_32FF: /* 0x132 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(306*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_33FF: /* 0x133 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(307*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_34FF: /* 0x134 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(308*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_35FF: /* 0x135 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(309*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_36FF: /* 0x136 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(310*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_37FF: /* 0x137 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(311*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_38FF: /* 0x138 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(312*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_39FF: /* 0x139 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(313*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3AFF: /* 0x13a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(314*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3BFF: /* 0x13b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(315*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3CFF: /* 0x13c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(316*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3DFF: /* 0x13d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(317*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3EFF: /* 0x13e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(318*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_3FFF: /* 0x13f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(319*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_40FF: /* 0x140 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(320*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_41FF: /* 0x141 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(321*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_42FF: /* 0x142 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(322*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_43FF: /* 0x143 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(323*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_44FF: /* 0x144 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(324*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_45FF: /* 0x145 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(325*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_46FF: /* 0x146 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(326*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_47FF: /* 0x147 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(327*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_48FF: /* 0x148 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(328*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_49FF: /* 0x149 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(329*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_4AFF: /* 0x14a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(330*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_4BFF: /* 0x14b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(331*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_4CFF: /* 0x14c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(332*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_4DFF: /* 0x14d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(333*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_4EFF: /* 0x14e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(334*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_4FFF: /* 0x14f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(335*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_50FF: /* 0x150 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(336*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_51FF: /* 0x151 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(337*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_52FF: /* 0x152 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(338*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_53FF: /* 0x153 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(339*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_54FF: /* 0x154 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(340*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_55FF: /* 0x155 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(341*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_56FF: /* 0x156 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(342*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_57FF: /* 0x157 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(343*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_58FF: /* 0x158 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(344*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_59FF: /* 0x159 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(345*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_5AFF: /* 0x15a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(346*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_5BFF: /* 0x15b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(347*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_5CFF: /* 0x15c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(348*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_5DFF: /* 0x15d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(349*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_5EFF: /* 0x15e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(350*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_5FFF: /* 0x15f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(351*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_60FF: /* 0x160 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(352*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_61FF: /* 0x161 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(353*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_62FF: /* 0x162 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(354*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_63FF: /* 0x163 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(355*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_64FF: /* 0x164 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(356*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_65FF: /* 0x165 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(357*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_66FF: /* 0x166 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(358*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_67FF: /* 0x167 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(359*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_68FF: /* 0x168 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(360*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_69FF: /* 0x169 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(361*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_6AFF: /* 0x16a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(362*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_6BFF: /* 0x16b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(363*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_6CFF: /* 0x16c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(364*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_6DFF: /* 0x16d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(365*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_6EFF: /* 0x16e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(366*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_6FFF: /* 0x16f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(367*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_70FF: /* 0x170 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(368*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_71FF: /* 0x171 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(369*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_72FF: /* 0x172 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(370*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_73FF: /* 0x173 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(371*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_74FF: /* 0x174 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(372*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_75FF: /* 0x175 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(373*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_76FF: /* 0x176 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(374*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_77FF: /* 0x177 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(375*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_78FF: /* 0x178 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(376*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_79FF: /* 0x179 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(377*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7AFF: /* 0x17a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(378*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7BFF: /* 0x17b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(379*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7CFF: /* 0x17c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(380*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7DFF: /* 0x17d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(381*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7EFF: /* 0x17e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(382*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_7FFF: /* 0x17f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(383*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_80FF: /* 0x180 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(384*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_81FF: /* 0x181 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(385*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_82FF: /* 0x182 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(386*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_83FF: /* 0x183 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(387*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_84FF: /* 0x184 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(388*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_85FF: /* 0x185 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(389*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_86FF: /* 0x186 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(390*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_87FF: /* 0x187 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(391*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_88FF: /* 0x188 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(392*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_89FF: /* 0x189 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(393*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_8AFF: /* 0x18a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(394*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_8BFF: /* 0x18b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(395*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_8CFF: /* 0x18c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(396*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_8DFF: /* 0x18d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(397*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_8EFF: /* 0x18e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(398*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_8FFF: /* 0x18f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(399*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_90FF: /* 0x190 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(400*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_91FF: /* 0x191 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(401*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_92FF: /* 0x192 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(402*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_93FF: /* 0x193 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(403*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_94FF: /* 0x194 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(404*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_95FF: /* 0x195 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(405*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_96FF: /* 0x196 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(406*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_97FF: /* 0x197 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(407*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_98FF: /* 0x198 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(408*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_99FF: /* 0x199 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(409*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_9AFF: /* 0x19a */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(410*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_9BFF: /* 0x19b */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(411*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_9CFF: /* 0x19c */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(412*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_9DFF: /* 0x19d */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(413*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_9EFF: /* 0x19e */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(414*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_9FFF: /* 0x19f */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(415*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A0FF: /* 0x1a0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(416*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A1FF: /* 0x1a1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(417*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A2FF: /* 0x1a2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(418*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A3FF: /* 0x1a3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(419*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A4FF: /* 0x1a4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(420*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A5FF: /* 0x1a5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(421*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A6FF: /* 0x1a6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(422*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A7FF: /* 0x1a7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(423*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A8FF: /* 0x1a8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(424*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_A9FF: /* 0x1a9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(425*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_AAFF: /* 0x1aa */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(426*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_ABFF: /* 0x1ab */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(427*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_ACFF: /* 0x1ac */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(428*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_ADFF: /* 0x1ad */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(429*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_AEFF: /* 0x1ae */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(430*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_AFFF: /* 0x1af */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(431*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B0FF: /* 0x1b0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(432*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B1FF: /* 0x1b1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(433*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B2FF: /* 0x1b2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(434*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B3FF: /* 0x1b3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(435*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B4FF: /* 0x1b4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(436*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B5FF: /* 0x1b5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(437*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B6FF: /* 0x1b6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(438*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B7FF: /* 0x1b7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(439*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B8FF: /* 0x1b8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(440*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_B9FF: /* 0x1b9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(441*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_BAFF: /* 0x1ba */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(442*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_BBFF: /* 0x1bb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(443*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_BCFF: /* 0x1bc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(444*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_BDFF: /* 0x1bd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(445*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_BEFF: /* 0x1be */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(446*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_BFFF: /* 0x1bf */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(447*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C0FF: /* 0x1c0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(448*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C1FF: /* 0x1c1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(449*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C2FF: /* 0x1c2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(450*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C3FF: /* 0x1c3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(451*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C4FF: /* 0x1c4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(452*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C5FF: /* 0x1c5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(453*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C6FF: /* 0x1c6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(454*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C7FF: /* 0x1c7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(455*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C8FF: /* 0x1c8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(456*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_C9FF: /* 0x1c9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(457*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_CAFF: /* 0x1ca */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(458*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_CBFF: /* 0x1cb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(459*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_CCFF: /* 0x1cc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(460*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_CDFF: /* 0x1cd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(461*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_CEFF: /* 0x1ce */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(462*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_CFFF: /* 0x1cf */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(463*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D0FF: /* 0x1d0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(464*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D1FF: /* 0x1d1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(465*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D2FF: /* 0x1d2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(466*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D3FF: /* 0x1d3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(467*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D4FF: /* 0x1d4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(468*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D5FF: /* 0x1d5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(469*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D6FF: /* 0x1d6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(470*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D7FF: /* 0x1d7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(471*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D8FF: /* 0x1d8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(472*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_D9FF: /* 0x1d9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(473*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_DAFF: /* 0x1da */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(474*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_DBFF: /* 0x1db */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(475*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_DCFF: /* 0x1dc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(476*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_DDFF: /* 0x1dd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(477*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_DEFF: /* 0x1de */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(478*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_DFFF: /* 0x1df */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(479*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E0FF: /* 0x1e0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(480*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E1FF: /* 0x1e1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(481*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E2FF: /* 0x1e2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(482*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E3FF: /* 0x1e3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(483*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E4FF: /* 0x1e4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(484*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E5FF: /* 0x1e5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(485*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E6FF: /* 0x1e6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(486*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E7FF: /* 0x1e7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(487*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E8FF: /* 0x1e8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(488*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_E9FF: /* 0x1e9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(489*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_EAFF: /* 0x1ea */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(490*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_EBFF: /* 0x1eb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(491*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_ECFF: /* 0x1ec */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(492*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_EDFF: /* 0x1ed */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(493*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_EEFF: /* 0x1ee */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(494*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_EFFF: /* 0x1ef */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(495*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_F0FF: /* 0x1f0 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(496*4)
+
+/* ------------------------------ */
+.L_ALT_OP_UNUSED_F1FF: /* 0x1f1 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(497*4)
+
+/* ------------------------------ */
+.L_ALT_OP_INVOKE_OBJECT_INIT_JUMBO: /* 0x1f2 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(498*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_VOLATILE_JUMBO: /* 0x1f3 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(499*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_WIDE_VOLATILE_JUMBO: /* 0x1f4 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(500*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IGET_OBJECT_VOLATILE_JUMBO: /* 0x1f5 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(501*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_VOLATILE_JUMBO: /* 0x1f6 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(502*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_WIDE_VOLATILE_JUMBO: /* 0x1f7 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(503*4)
+
+/* ------------------------------ */
+.L_ALT_OP_IPUT_OBJECT_VOLATILE_JUMBO: /* 0x1f8 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(504*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_VOLATILE_JUMBO: /* 0x1f9 */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(505*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_WIDE_VOLATILE_JUMBO: /* 0x1fa */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(506*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SGET_OBJECT_VOLATILE_JUMBO: /* 0x1fb */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(507*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_VOLATILE_JUMBO: /* 0x1fc */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(508*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_WIDE_VOLATILE_JUMBO: /* 0x1fd */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(509*4)
+
+/* ------------------------------ */
+.L_ALT_OP_SPUT_OBJECT_VOLATILE_JUMBO: /* 0x1fe */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(510*4)
+
+/* ------------------------------ */
+.L_ALT_OP_THROW_VERIFICATION_ERROR_JUMBO: /* 0x1ff */
+/* File: x86/alt_stub.S */
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(511*4)
+
+    .size   dvmAsmAltInstructionStartCode, .-dvmAsmAltInstructionStartCode
+    .global dvmAsmAltInstructionEndCode
+dvmAsmAltInstructionEndCode:
+
+    .global dvmAsmInstructionStart
+    .text
+dvmAsmInstructionStart:
+    .long .L_OP_NOP /* 0x00 */
+    .long .L_OP_MOVE /* 0x01 */
+    .long .L_OP_MOVE_FROM16 /* 0x02 */
+    .long .L_OP_MOVE_16 /* 0x03 */
+    .long .L_OP_MOVE_WIDE /* 0x04 */
+    .long .L_OP_MOVE_WIDE_FROM16 /* 0x05 */
+    .long .L_OP_MOVE_WIDE_16 /* 0x06 */
+    .long .L_OP_MOVE_OBJECT /* 0x07 */
+    .long .L_OP_MOVE_OBJECT_FROM16 /* 0x08 */
+    .long .L_OP_MOVE_OBJECT_16 /* 0x09 */
+    .long .L_OP_MOVE_RESULT /* 0x0a */
+    .long .L_OP_MOVE_RESULT_WIDE /* 0x0b */
+    .long .L_OP_MOVE_RESULT_OBJECT /* 0x0c */
+    .long .L_OP_MOVE_EXCEPTION /* 0x0d */
+    .long .L_OP_RETURN_VOID /* 0x0e */
+    .long .L_OP_RETURN /* 0x0f */
+    .long .L_OP_RETURN_WIDE /* 0x10 */
+    .long .L_OP_RETURN_OBJECT /* 0x11 */
+    .long .L_OP_CONST_4 /* 0x12 */
+    .long .L_OP_CONST_16 /* 0x13 */
+    .long .L_OP_CONST /* 0x14 */
+    .long .L_OP_CONST_HIGH16 /* 0x15 */
+    .long .L_OP_CONST_WIDE_16 /* 0x16 */
+    .long .L_OP_CONST_WIDE_32 /* 0x17 */
+    .long .L_OP_CONST_WIDE /* 0x18 */
+    .long .L_OP_CONST_WIDE_HIGH16 /* 0x19 */
+    .long .L_OP_CONST_STRING /* 0x1a */
+    .long .L_OP_CONST_STRING_JUMBO /* 0x1b */
+    .long .L_OP_CONST_CLASS /* 0x1c */
+    .long .L_OP_MONITOR_ENTER /* 0x1d */
+    .long .L_OP_MONITOR_EXIT /* 0x1e */
+    .long .L_OP_CHECK_CAST /* 0x1f */
+    .long .L_OP_INSTANCE_OF /* 0x20 */
+    .long .L_OP_ARRAY_LENGTH /* 0x21 */
+    .long .L_OP_NEW_INSTANCE /* 0x22 */
+    .long .L_OP_NEW_ARRAY /* 0x23 */
+    .long .L_OP_FILLED_NEW_ARRAY /* 0x24 */
+    .long .L_OP_FILLED_NEW_ARRAY_RANGE /* 0x25 */
+    .long .L_OP_FILL_ARRAY_DATA /* 0x26 */
+    .long .L_OP_THROW /* 0x27 */
+    .long .L_OP_GOTO /* 0x28 */
+    .long .L_OP_GOTO_16 /* 0x29 */
+    .long .L_OP_GOTO_32 /* 0x2a */
+    .long .L_OP_PACKED_SWITCH /* 0x2b */
+    .long .L_OP_SPARSE_SWITCH /* 0x2c */
+    .long .L_OP_CMPL_FLOAT /* 0x2d */
+    .long .L_OP_CMPG_FLOAT /* 0x2e */
+    .long .L_OP_CMPL_DOUBLE /* 0x2f */
+    .long .L_OP_CMPG_DOUBLE /* 0x30 */
+    .long .L_OP_CMP_LONG /* 0x31 */
+    .long .L_OP_IF_EQ /* 0x32 */
+    .long .L_OP_IF_NE /* 0x33 */
+    .long .L_OP_IF_LT /* 0x34 */
+    .long .L_OP_IF_GE /* 0x35 */
+    .long .L_OP_IF_GT /* 0x36 */
+    .long .L_OP_IF_LE /* 0x37 */
+    .long .L_OP_IF_EQZ /* 0x38 */
+    .long .L_OP_IF_NEZ /* 0x39 */
+    .long .L_OP_IF_LTZ /* 0x3a */
+    .long .L_OP_IF_GEZ /* 0x3b */
+    .long .L_OP_IF_GTZ /* 0x3c */
+    .long .L_OP_IF_LEZ /* 0x3d */
+    .long .L_OP_UNUSED_3E /* 0x3e */
+    .long .L_OP_UNUSED_3F /* 0x3f */
+    .long .L_OP_UNUSED_40 /* 0x40 */
+    .long .L_OP_UNUSED_41 /* 0x41 */
+    .long .L_OP_UNUSED_42 /* 0x42 */
+    .long .L_OP_UNUSED_43 /* 0x43 */
+    .long .L_OP_AGET /* 0x44 */
+    .long .L_OP_AGET_WIDE /* 0x45 */
+    .long .L_OP_AGET_OBJECT /* 0x46 */
+    .long .L_OP_AGET_BOOLEAN /* 0x47 */
+    .long .L_OP_AGET_BYTE /* 0x48 */
+    .long .L_OP_AGET_CHAR /* 0x49 */
+    .long .L_OP_AGET_SHORT /* 0x4a */
+    .long .L_OP_APUT /* 0x4b */
+    .long .L_OP_APUT_WIDE /* 0x4c */
+    .long .L_OP_APUT_OBJECT /* 0x4d */
+    .long .L_OP_APUT_BOOLEAN /* 0x4e */
+    .long .L_OP_APUT_BYTE /* 0x4f */
+    .long .L_OP_APUT_CHAR /* 0x50 */
+    .long .L_OP_APUT_SHORT /* 0x51 */
+    .long .L_OP_IGET /* 0x52 */
+    .long .L_OP_IGET_WIDE /* 0x53 */
+    .long .L_OP_IGET_OBJECT /* 0x54 */
+    .long .L_OP_IGET_BOOLEAN /* 0x55 */
+    .long .L_OP_IGET_BYTE /* 0x56 */
+    .long .L_OP_IGET_CHAR /* 0x57 */
+    .long .L_OP_IGET_SHORT /* 0x58 */
+    .long .L_OP_IPUT /* 0x59 */
+    .long .L_OP_IPUT_WIDE /* 0x5a */
+    .long .L_OP_IPUT_OBJECT /* 0x5b */
+    .long .L_OP_IPUT_BOOLEAN /* 0x5c */
+    .long .L_OP_IPUT_BYTE /* 0x5d */
+    .long .L_OP_IPUT_CHAR /* 0x5e */
+    .long .L_OP_IPUT_SHORT /* 0x5f */
+    .long .L_OP_SGET /* 0x60 */
+    .long .L_OP_SGET_WIDE /* 0x61 */
+    .long .L_OP_SGET_OBJECT /* 0x62 */
+    .long .L_OP_SGET_BOOLEAN /* 0x63 */
+    .long .L_OP_SGET_BYTE /* 0x64 */
+    .long .L_OP_SGET_CHAR /* 0x65 */
+    .long .L_OP_SGET_SHORT /* 0x66 */
+    .long .L_OP_SPUT /* 0x67 */
+    .long .L_OP_SPUT_WIDE /* 0x68 */
+    .long .L_OP_SPUT_OBJECT /* 0x69 */
+    .long .L_OP_SPUT_BOOLEAN /* 0x6a */
+    .long .L_OP_SPUT_BYTE /* 0x6b */
+    .long .L_OP_SPUT_CHAR /* 0x6c */
+    .long .L_OP_SPUT_SHORT /* 0x6d */
+    .long .L_OP_INVOKE_VIRTUAL /* 0x6e */
+    .long .L_OP_INVOKE_SUPER /* 0x6f */
+    .long .L_OP_INVOKE_DIRECT /* 0x70 */
+    .long .L_OP_INVOKE_STATIC /* 0x71 */
+    .long .L_OP_INVOKE_INTERFACE /* 0x72 */
+    .long .L_OP_UNUSED_73 /* 0x73 */
+    .long .L_OP_INVOKE_VIRTUAL_RANGE /* 0x74 */
+    .long .L_OP_INVOKE_SUPER_RANGE /* 0x75 */
+    .long .L_OP_INVOKE_DIRECT_RANGE /* 0x76 */
+    .long .L_OP_INVOKE_STATIC_RANGE /* 0x77 */
+    .long .L_OP_INVOKE_INTERFACE_RANGE /* 0x78 */
+    .long .L_OP_UNUSED_79 /* 0x79 */
+    .long .L_OP_UNUSED_7A /* 0x7a */
+    .long .L_OP_NEG_INT /* 0x7b */
+    .long .L_OP_NOT_INT /* 0x7c */
+    .long .L_OP_NEG_LONG /* 0x7d */
+    .long .L_OP_NOT_LONG /* 0x7e */
+    .long .L_OP_NEG_FLOAT /* 0x7f */
+    .long .L_OP_NEG_DOUBLE /* 0x80 */
+    .long .L_OP_INT_TO_LONG /* 0x81 */
+    .long .L_OP_INT_TO_FLOAT /* 0x82 */
+    .long .L_OP_INT_TO_DOUBLE /* 0x83 */
+    .long .L_OP_LONG_TO_INT /* 0x84 */
+    .long .L_OP_LONG_TO_FLOAT /* 0x85 */
+    .long .L_OP_LONG_TO_DOUBLE /* 0x86 */
+    .long .L_OP_FLOAT_TO_INT /* 0x87 */
+    .long .L_OP_FLOAT_TO_LONG /* 0x88 */
+    .long .L_OP_FLOAT_TO_DOUBLE /* 0x89 */
+    .long .L_OP_DOUBLE_TO_INT /* 0x8a */
+    .long .L_OP_DOUBLE_TO_LONG /* 0x8b */
+    .long .L_OP_DOUBLE_TO_FLOAT /* 0x8c */
+    .long .L_OP_INT_TO_BYTE /* 0x8d */
+    .long .L_OP_INT_TO_CHAR /* 0x8e */
+    .long .L_OP_INT_TO_SHORT /* 0x8f */
+    .long .L_OP_ADD_INT /* 0x90 */
+    .long .L_OP_SUB_INT /* 0x91 */
+    .long .L_OP_MUL_INT /* 0x92 */
+    .long .L_OP_DIV_INT /* 0x93 */
+    .long .L_OP_REM_INT /* 0x94 */
+    .long .L_OP_AND_INT /* 0x95 */
+    .long .L_OP_OR_INT /* 0x96 */
+    .long .L_OP_XOR_INT /* 0x97 */
+    .long .L_OP_SHL_INT /* 0x98 */
+    .long .L_OP_SHR_INT /* 0x99 */
+    .long .L_OP_USHR_INT /* 0x9a */
+    .long .L_OP_ADD_LONG /* 0x9b */
+    .long .L_OP_SUB_LONG /* 0x9c */
+    .long .L_OP_MUL_LONG /* 0x9d */
+    .long .L_OP_DIV_LONG /* 0x9e */
+    .long .L_OP_REM_LONG /* 0x9f */
+    .long .L_OP_AND_LONG /* 0xa0 */
+    .long .L_OP_OR_LONG /* 0xa1 */
+    .long .L_OP_XOR_LONG /* 0xa2 */
+    .long .L_OP_SHL_LONG /* 0xa3 */
+    .long .L_OP_SHR_LONG /* 0xa4 */
+    .long .L_OP_USHR_LONG /* 0xa5 */
+    .long .L_OP_ADD_FLOAT /* 0xa6 */
+    .long .L_OP_SUB_FLOAT /* 0xa7 */
+    .long .L_OP_MUL_FLOAT /* 0xa8 */
+    .long .L_OP_DIV_FLOAT /* 0xa9 */
+    .long .L_OP_REM_FLOAT /* 0xaa */
+    .long .L_OP_ADD_DOUBLE /* 0xab */
+    .long .L_OP_SUB_DOUBLE /* 0xac */
+    .long .L_OP_MUL_DOUBLE /* 0xad */
+    .long .L_OP_DIV_DOUBLE /* 0xae */
+    .long .L_OP_REM_DOUBLE /* 0xaf */
+    .long .L_OP_ADD_INT_2ADDR /* 0xb0 */
+    .long .L_OP_SUB_INT_2ADDR /* 0xb1 */
+    .long .L_OP_MUL_INT_2ADDR /* 0xb2 */
+    .long .L_OP_DIV_INT_2ADDR /* 0xb3 */
+    .long .L_OP_REM_INT_2ADDR /* 0xb4 */
+    .long .L_OP_AND_INT_2ADDR /* 0xb5 */
+    .long .L_OP_OR_INT_2ADDR /* 0xb6 */
+    .long .L_OP_XOR_INT_2ADDR /* 0xb7 */
+    .long .L_OP_SHL_INT_2ADDR /* 0xb8 */
+    .long .L_OP_SHR_INT_2ADDR /* 0xb9 */
+    .long .L_OP_USHR_INT_2ADDR /* 0xba */
+    .long .L_OP_ADD_LONG_2ADDR /* 0xbb */
+    .long .L_OP_SUB_LONG_2ADDR /* 0xbc */
+    .long .L_OP_MUL_LONG_2ADDR /* 0xbd */
+    .long .L_OP_DIV_LONG_2ADDR /* 0xbe */
+    .long .L_OP_REM_LONG_2ADDR /* 0xbf */
+    .long .L_OP_AND_LONG_2ADDR /* 0xc0 */
+    .long .L_OP_OR_LONG_2ADDR /* 0xc1 */
+    .long .L_OP_XOR_LONG_2ADDR /* 0xc2 */
+    .long .L_OP_SHL_LONG_2ADDR /* 0xc3 */
+    .long .L_OP_SHR_LONG_2ADDR /* 0xc4 */
+    .long .L_OP_USHR_LONG_2ADDR /* 0xc5 */
+    .long .L_OP_ADD_FLOAT_2ADDR /* 0xc6 */
+    .long .L_OP_SUB_FLOAT_2ADDR /* 0xc7 */
+    .long .L_OP_MUL_FLOAT_2ADDR /* 0xc8 */
+    .long .L_OP_DIV_FLOAT_2ADDR /* 0xc9 */
+    .long .L_OP_REM_FLOAT_2ADDR /* 0xca */
+    .long .L_OP_ADD_DOUBLE_2ADDR /* 0xcb */
+    .long .L_OP_SUB_DOUBLE_2ADDR /* 0xcc */
+    .long .L_OP_MUL_DOUBLE_2ADDR /* 0xcd */
+    .long .L_OP_DIV_DOUBLE_2ADDR /* 0xce */
+    .long .L_OP_REM_DOUBLE_2ADDR /* 0xcf */
+    .long .L_OP_ADD_INT_LIT16 /* 0xd0 */
+    .long .L_OP_RSUB_INT /* 0xd1 */
+    .long .L_OP_MUL_INT_LIT16 /* 0xd2 */
+    .long .L_OP_DIV_INT_LIT16 /* 0xd3 */
+    .long .L_OP_REM_INT_LIT16 /* 0xd4 */
+    .long .L_OP_AND_INT_LIT16 /* 0xd5 */
+    .long .L_OP_OR_INT_LIT16 /* 0xd6 */
+    .long .L_OP_XOR_INT_LIT16 /* 0xd7 */
+    .long .L_OP_ADD_INT_LIT8 /* 0xd8 */
+    .long .L_OP_RSUB_INT_LIT8 /* 0xd9 */
+    .long .L_OP_MUL_INT_LIT8 /* 0xda */
+    .long .L_OP_DIV_INT_LIT8 /* 0xdb */
+    .long .L_OP_REM_INT_LIT8 /* 0xdc */
+    .long .L_OP_AND_INT_LIT8 /* 0xdd */
+    .long .L_OP_OR_INT_LIT8 /* 0xde */
+    .long .L_OP_XOR_INT_LIT8 /* 0xdf */
+    .long .L_OP_SHL_INT_LIT8 /* 0xe0 */
+    .long .L_OP_SHR_INT_LIT8 /* 0xe1 */
+    .long .L_OP_USHR_INT_LIT8 /* 0xe2 */
+    .long .L_OP_IGET_VOLATILE /* 0xe3 */
+    .long .L_OP_IPUT_VOLATILE /* 0xe4 */
+    .long .L_OP_SGET_VOLATILE /* 0xe5 */
+    .long .L_OP_SPUT_VOLATILE /* 0xe6 */
+    .long .L_OP_IGET_OBJECT_VOLATILE /* 0xe7 */
+    .long .L_OP_IGET_WIDE_VOLATILE /* 0xe8 */
+    .long .L_OP_IPUT_WIDE_VOLATILE /* 0xe9 */
+    .long .L_OP_SGET_WIDE_VOLATILE /* 0xea */
+    .long .L_OP_SPUT_WIDE_VOLATILE /* 0xeb */
+    .long .L_OP_BREAKPOINT /* 0xec */
+    .long .L_OP_THROW_VERIFICATION_ERROR /* 0xed */
+    .long .L_OP_EXECUTE_INLINE /* 0xee */
+    .long .L_OP_EXECUTE_INLINE_RANGE /* 0xef */
+    .long .L_OP_INVOKE_OBJECT_INIT_RANGE /* 0xf0 */
+    .long .L_OP_RETURN_VOID_BARRIER /* 0xf1 */
+    .long .L_OP_IGET_QUICK /* 0xf2 */
+    .long .L_OP_IGET_WIDE_QUICK /* 0xf3 */
+    .long .L_OP_IGET_OBJECT_QUICK /* 0xf4 */
+    .long .L_OP_IPUT_QUICK /* 0xf5 */
+    .long .L_OP_IPUT_WIDE_QUICK /* 0xf6 */
+    .long .L_OP_IPUT_OBJECT_QUICK /* 0xf7 */
+    .long .L_OP_INVOKE_VIRTUAL_QUICK /* 0xf8 */
+    .long .L_OP_INVOKE_VIRTUAL_QUICK_RANGE /* 0xf9 */
+    .long .L_OP_INVOKE_SUPER_QUICK /* 0xfa */
+    .long .L_OP_INVOKE_SUPER_QUICK_RANGE /* 0xfb */
+    .long .L_OP_IPUT_OBJECT_VOLATILE /* 0xfc */
+    .long .L_OP_SGET_OBJECT_VOLATILE /* 0xfd */
+    .long .L_OP_SPUT_OBJECT_VOLATILE /* 0xfe */
+    .long .L_OP_DISPATCH_FF /* 0xff */
+    .long .L_OP_CONST_CLASS_JUMBO /* 0x100 */
+    .long .L_OP_CHECK_CAST_JUMBO /* 0x101 */
+    .long .L_OP_INSTANCE_OF_JUMBO /* 0x102 */
+    .long .L_OP_NEW_INSTANCE_JUMBO /* 0x103 */
+    .long .L_OP_NEW_ARRAY_JUMBO /* 0x104 */
+    .long .L_OP_FILLED_NEW_ARRAY_JUMBO /* 0x105 */
+    .long .L_OP_IGET_JUMBO /* 0x106 */
+    .long .L_OP_IGET_WIDE_JUMBO /* 0x107 */
+    .long .L_OP_IGET_OBJECT_JUMBO /* 0x108 */
+    .long .L_OP_IGET_BOOLEAN_JUMBO /* 0x109 */
+    .long .L_OP_IGET_BYTE_JUMBO /* 0x10a */
+    .long .L_OP_IGET_CHAR_JUMBO /* 0x10b */
+    .long .L_OP_IGET_SHORT_JUMBO /* 0x10c */
+    .long .L_OP_IPUT_JUMBO /* 0x10d */
+    .long .L_OP_IPUT_WIDE_JUMBO /* 0x10e */
+    .long .L_OP_IPUT_OBJECT_JUMBO /* 0x10f */
+    .long .L_OP_IPUT_BOOLEAN_JUMBO /* 0x110 */
+    .long .L_OP_IPUT_BYTE_JUMBO /* 0x111 */
+    .long .L_OP_IPUT_CHAR_JUMBO /* 0x112 */
+    .long .L_OP_IPUT_SHORT_JUMBO /* 0x113 */
+    .long .L_OP_SGET_JUMBO /* 0x114 */
+    .long .L_OP_SGET_WIDE_JUMBO /* 0x115 */
+    .long .L_OP_SGET_OBJECT_JUMBO /* 0x116 */
+    .long .L_OP_SGET_BOOLEAN_JUMBO /* 0x117 */
+    .long .L_OP_SGET_BYTE_JUMBO /* 0x118 */
+    .long .L_OP_SGET_CHAR_JUMBO /* 0x119 */
+    .long .L_OP_SGET_SHORT_JUMBO /* 0x11a */
+    .long .L_OP_SPUT_JUMBO /* 0x11b */
+    .long .L_OP_SPUT_WIDE_JUMBO /* 0x11c */
+    .long .L_OP_SPUT_OBJECT_JUMBO /* 0x11d */
+    .long .L_OP_SPUT_BOOLEAN_JUMBO /* 0x11e */
+    .long .L_OP_SPUT_BYTE_JUMBO /* 0x11f */
+    .long .L_OP_SPUT_CHAR_JUMBO /* 0x120 */
+    .long .L_OP_SPUT_SHORT_JUMBO /* 0x121 */
+    .long .L_OP_INVOKE_VIRTUAL_JUMBO /* 0x122 */
+    .long .L_OP_INVOKE_SUPER_JUMBO /* 0x123 */
+    .long .L_OP_INVOKE_DIRECT_JUMBO /* 0x124 */
+    .long .L_OP_INVOKE_STATIC_JUMBO /* 0x125 */
+    .long .L_OP_INVOKE_INTERFACE_JUMBO /* 0x126 */
+    .long .L_OP_UNUSED_27FF /* 0x127 */
+    .long .L_OP_UNUSED_28FF /* 0x128 */
+    .long .L_OP_UNUSED_29FF /* 0x129 */
+    .long .L_OP_UNUSED_2AFF /* 0x12a */
+    .long .L_OP_UNUSED_2BFF /* 0x12b */
+    .long .L_OP_UNUSED_2CFF /* 0x12c */
+    .long .L_OP_UNUSED_2DFF /* 0x12d */
+    .long .L_OP_UNUSED_2EFF /* 0x12e */
+    .long .L_OP_UNUSED_2FFF /* 0x12f */
+    .long .L_OP_UNUSED_30FF /* 0x130 */
+    .long .L_OP_UNUSED_31FF /* 0x131 */
+    .long .L_OP_UNUSED_32FF /* 0x132 */
+    .long .L_OP_UNUSED_33FF /* 0x133 */
+    .long .L_OP_UNUSED_34FF /* 0x134 */
+    .long .L_OP_UNUSED_35FF /* 0x135 */
+    .long .L_OP_UNUSED_36FF /* 0x136 */
+    .long .L_OP_UNUSED_37FF /* 0x137 */
+    .long .L_OP_UNUSED_38FF /* 0x138 */
+    .long .L_OP_UNUSED_39FF /* 0x139 */
+    .long .L_OP_UNUSED_3AFF /* 0x13a */
+    .long .L_OP_UNUSED_3BFF /* 0x13b */
+    .long .L_OP_UNUSED_3CFF /* 0x13c */
+    .long .L_OP_UNUSED_3DFF /* 0x13d */
+    .long .L_OP_UNUSED_3EFF /* 0x13e */
+    .long .L_OP_UNUSED_3FFF /* 0x13f */
+    .long .L_OP_UNUSED_40FF /* 0x140 */
+    .long .L_OP_UNUSED_41FF /* 0x141 */
+    .long .L_OP_UNUSED_42FF /* 0x142 */
+    .long .L_OP_UNUSED_43FF /* 0x143 */
+    .long .L_OP_UNUSED_44FF /* 0x144 */
+    .long .L_OP_UNUSED_45FF /* 0x145 */
+    .long .L_OP_UNUSED_46FF /* 0x146 */
+    .long .L_OP_UNUSED_47FF /* 0x147 */
+    .long .L_OP_UNUSED_48FF /* 0x148 */
+    .long .L_OP_UNUSED_49FF /* 0x149 */
+    .long .L_OP_UNUSED_4AFF /* 0x14a */
+    .long .L_OP_UNUSED_4BFF /* 0x14b */
+    .long .L_OP_UNUSED_4CFF /* 0x14c */
+    .long .L_OP_UNUSED_4DFF /* 0x14d */
+    .long .L_OP_UNUSED_4EFF /* 0x14e */
+    .long .L_OP_UNUSED_4FFF /* 0x14f */
+    .long .L_OP_UNUSED_50FF /* 0x150 */
+    .long .L_OP_UNUSED_51FF /* 0x151 */
+    .long .L_OP_UNUSED_52FF /* 0x152 */
+    .long .L_OP_UNUSED_53FF /* 0x153 */
+    .long .L_OP_UNUSED_54FF /* 0x154 */
+    .long .L_OP_UNUSED_55FF /* 0x155 */
+    .long .L_OP_UNUSED_56FF /* 0x156 */
+    .long .L_OP_UNUSED_57FF /* 0x157 */
+    .long .L_OP_UNUSED_58FF /* 0x158 */
+    .long .L_OP_UNUSED_59FF /* 0x159 */
+    .long .L_OP_UNUSED_5AFF /* 0x15a */
+    .long .L_OP_UNUSED_5BFF /* 0x15b */
+    .long .L_OP_UNUSED_5CFF /* 0x15c */
+    .long .L_OP_UNUSED_5DFF /* 0x15d */
+    .long .L_OP_UNUSED_5EFF /* 0x15e */
+    .long .L_OP_UNUSED_5FFF /* 0x15f */
+    .long .L_OP_UNUSED_60FF /* 0x160 */
+    .long .L_OP_UNUSED_61FF /* 0x161 */
+    .long .L_OP_UNUSED_62FF /* 0x162 */
+    .long .L_OP_UNUSED_63FF /* 0x163 */
+    .long .L_OP_UNUSED_64FF /* 0x164 */
+    .long .L_OP_UNUSED_65FF /* 0x165 */
+    .long .L_OP_UNUSED_66FF /* 0x166 */
+    .long .L_OP_UNUSED_67FF /* 0x167 */
+    .long .L_OP_UNUSED_68FF /* 0x168 */
+    .long .L_OP_UNUSED_69FF /* 0x169 */
+    .long .L_OP_UNUSED_6AFF /* 0x16a */
+    .long .L_OP_UNUSED_6BFF /* 0x16b */
+    .long .L_OP_UNUSED_6CFF /* 0x16c */
+    .long .L_OP_UNUSED_6DFF /* 0x16d */
+    .long .L_OP_UNUSED_6EFF /* 0x16e */
+    .long .L_OP_UNUSED_6FFF /* 0x16f */
+    .long .L_OP_UNUSED_70FF /* 0x170 */
+    .long .L_OP_UNUSED_71FF /* 0x171 */
+    .long .L_OP_UNUSED_72FF /* 0x172 */
+    .long .L_OP_UNUSED_73FF /* 0x173 */
+    .long .L_OP_UNUSED_74FF /* 0x174 */
+    .long .L_OP_UNUSED_75FF /* 0x175 */
+    .long .L_OP_UNUSED_76FF /* 0x176 */
+    .long .L_OP_UNUSED_77FF /* 0x177 */
+    .long .L_OP_UNUSED_78FF /* 0x178 */
+    .long .L_OP_UNUSED_79FF /* 0x179 */
+    .long .L_OP_UNUSED_7AFF /* 0x17a */
+    .long .L_OP_UNUSED_7BFF /* 0x17b */
+    .long .L_OP_UNUSED_7CFF /* 0x17c */
+    .long .L_OP_UNUSED_7DFF /* 0x17d */
+    .long .L_OP_UNUSED_7EFF /* 0x17e */
+    .long .L_OP_UNUSED_7FFF /* 0x17f */
+    .long .L_OP_UNUSED_80FF /* 0x180 */
+    .long .L_OP_UNUSED_81FF /* 0x181 */
+    .long .L_OP_UNUSED_82FF /* 0x182 */
+    .long .L_OP_UNUSED_83FF /* 0x183 */
+    .long .L_OP_UNUSED_84FF /* 0x184 */
+    .long .L_OP_UNUSED_85FF /* 0x185 */
+    .long .L_OP_UNUSED_86FF /* 0x186 */
+    .long .L_OP_UNUSED_87FF /* 0x187 */
+    .long .L_OP_UNUSED_88FF /* 0x188 */
+    .long .L_OP_UNUSED_89FF /* 0x189 */
+    .long .L_OP_UNUSED_8AFF /* 0x18a */
+    .long .L_OP_UNUSED_8BFF /* 0x18b */
+    .long .L_OP_UNUSED_8CFF /* 0x18c */
+    .long .L_OP_UNUSED_8DFF /* 0x18d */
+    .long .L_OP_UNUSED_8EFF /* 0x18e */
+    .long .L_OP_UNUSED_8FFF /* 0x18f */
+    .long .L_OP_UNUSED_90FF /* 0x190 */
+    .long .L_OP_UNUSED_91FF /* 0x191 */
+    .long .L_OP_UNUSED_92FF /* 0x192 */
+    .long .L_OP_UNUSED_93FF /* 0x193 */
+    .long .L_OP_UNUSED_94FF /* 0x194 */
+    .long .L_OP_UNUSED_95FF /* 0x195 */
+    .long .L_OP_UNUSED_96FF /* 0x196 */
+    .long .L_OP_UNUSED_97FF /* 0x197 */
+    .long .L_OP_UNUSED_98FF /* 0x198 */
+    .long .L_OP_UNUSED_99FF /* 0x199 */
+    .long .L_OP_UNUSED_9AFF /* 0x19a */
+    .long .L_OP_UNUSED_9BFF /* 0x19b */
+    .long .L_OP_UNUSED_9CFF /* 0x19c */
+    .long .L_OP_UNUSED_9DFF /* 0x19d */
+    .long .L_OP_UNUSED_9EFF /* 0x19e */
+    .long .L_OP_UNUSED_9FFF /* 0x19f */
+    .long .L_OP_UNUSED_A0FF /* 0x1a0 */
+    .long .L_OP_UNUSED_A1FF /* 0x1a1 */
+    .long .L_OP_UNUSED_A2FF /* 0x1a2 */
+    .long .L_OP_UNUSED_A3FF /* 0x1a3 */
+    .long .L_OP_UNUSED_A4FF /* 0x1a4 */
+    .long .L_OP_UNUSED_A5FF /* 0x1a5 */
+    .long .L_OP_UNUSED_A6FF /* 0x1a6 */
+    .long .L_OP_UNUSED_A7FF /* 0x1a7 */
+    .long .L_OP_UNUSED_A8FF /* 0x1a8 */
+    .long .L_OP_UNUSED_A9FF /* 0x1a9 */
+    .long .L_OP_UNUSED_AAFF /* 0x1aa */
+    .long .L_OP_UNUSED_ABFF /* 0x1ab */
+    .long .L_OP_UNUSED_ACFF /* 0x1ac */
+    .long .L_OP_UNUSED_ADFF /* 0x1ad */
+    .long .L_OP_UNUSED_AEFF /* 0x1ae */
+    .long .L_OP_UNUSED_AFFF /* 0x1af */
+    .long .L_OP_UNUSED_B0FF /* 0x1b0 */
+    .long .L_OP_UNUSED_B1FF /* 0x1b1 */
+    .long .L_OP_UNUSED_B2FF /* 0x1b2 */
+    .long .L_OP_UNUSED_B3FF /* 0x1b3 */
+    .long .L_OP_UNUSED_B4FF /* 0x1b4 */
+    .long .L_OP_UNUSED_B5FF /* 0x1b5 */
+    .long .L_OP_UNUSED_B6FF /* 0x1b6 */
+    .long .L_OP_UNUSED_B7FF /* 0x1b7 */
+    .long .L_OP_UNUSED_B8FF /* 0x1b8 */
+    .long .L_OP_UNUSED_B9FF /* 0x1b9 */
+    .long .L_OP_UNUSED_BAFF /* 0x1ba */
+    .long .L_OP_UNUSED_BBFF /* 0x1bb */
+    .long .L_OP_UNUSED_BCFF /* 0x1bc */
+    .long .L_OP_UNUSED_BDFF /* 0x1bd */
+    .long .L_OP_UNUSED_BEFF /* 0x1be */
+    .long .L_OP_UNUSED_BFFF /* 0x1bf */
+    .long .L_OP_UNUSED_C0FF /* 0x1c0 */
+    .long .L_OP_UNUSED_C1FF /* 0x1c1 */
+    .long .L_OP_UNUSED_C2FF /* 0x1c2 */
+    .long .L_OP_UNUSED_C3FF /* 0x1c3 */
+    .long .L_OP_UNUSED_C4FF /* 0x1c4 */
+    .long .L_OP_UNUSED_C5FF /* 0x1c5 */
+    .long .L_OP_UNUSED_C6FF /* 0x1c6 */
+    .long .L_OP_UNUSED_C7FF /* 0x1c7 */
+    .long .L_OP_UNUSED_C8FF /* 0x1c8 */
+    .long .L_OP_UNUSED_C9FF /* 0x1c9 */
+    .long .L_OP_UNUSED_CAFF /* 0x1ca */
+    .long .L_OP_UNUSED_CBFF /* 0x1cb */
+    .long .L_OP_UNUSED_CCFF /* 0x1cc */
+    .long .L_OP_UNUSED_CDFF /* 0x1cd */
+    .long .L_OP_UNUSED_CEFF /* 0x1ce */
+    .long .L_OP_UNUSED_CFFF /* 0x1cf */
+    .long .L_OP_UNUSED_D0FF /* 0x1d0 */
+    .long .L_OP_UNUSED_D1FF /* 0x1d1 */
+    .long .L_OP_UNUSED_D2FF /* 0x1d2 */
+    .long .L_OP_UNUSED_D3FF /* 0x1d3 */
+    .long .L_OP_UNUSED_D4FF /* 0x1d4 */
+    .long .L_OP_UNUSED_D5FF /* 0x1d5 */
+    .long .L_OP_UNUSED_D6FF /* 0x1d6 */
+    .long .L_OP_UNUSED_D7FF /* 0x1d7 */
+    .long .L_OP_UNUSED_D8FF /* 0x1d8 */
+    .long .L_OP_UNUSED_D9FF /* 0x1d9 */
+    .long .L_OP_UNUSED_DAFF /* 0x1da */
+    .long .L_OP_UNUSED_DBFF /* 0x1db */
+    .long .L_OP_UNUSED_DCFF /* 0x1dc */
+    .long .L_OP_UNUSED_DDFF /* 0x1dd */
+    .long .L_OP_UNUSED_DEFF /* 0x1de */
+    .long .L_OP_UNUSED_DFFF /* 0x1df */
+    .long .L_OP_UNUSED_E0FF /* 0x1e0 */
+    .long .L_OP_UNUSED_E1FF /* 0x1e1 */
+    .long .L_OP_UNUSED_E2FF /* 0x1e2 */
+    .long .L_OP_UNUSED_E3FF /* 0x1e3 */
+    .long .L_OP_UNUSED_E4FF /* 0x1e4 */
+    .long .L_OP_UNUSED_E5FF /* 0x1e5 */
+    .long .L_OP_UNUSED_E6FF /* 0x1e6 */
+    .long .L_OP_UNUSED_E7FF /* 0x1e7 */
+    .long .L_OP_UNUSED_E8FF /* 0x1e8 */
+    .long .L_OP_UNUSED_E9FF /* 0x1e9 */
+    .long .L_OP_UNUSED_EAFF /* 0x1ea */
+    .long .L_OP_UNUSED_EBFF /* 0x1eb */
+    .long .L_OP_UNUSED_ECFF /* 0x1ec */
+    .long .L_OP_UNUSED_EDFF /* 0x1ed */
+    .long .L_OP_UNUSED_EEFF /* 0x1ee */
+    .long .L_OP_UNUSED_EFFF /* 0x1ef */
+    .long .L_OP_UNUSED_F0FF /* 0x1f0 */
+    .long .L_OP_UNUSED_F1FF /* 0x1f1 */
+    .long .L_OP_INVOKE_OBJECT_INIT_JUMBO /* 0x1f2 */
+    .long .L_OP_IGET_VOLATILE_JUMBO /* 0x1f3 */
+    .long .L_OP_IGET_WIDE_VOLATILE_JUMBO /* 0x1f4 */
+    .long .L_OP_IGET_OBJECT_VOLATILE_JUMBO /* 0x1f5 */
+    .long .L_OP_IPUT_VOLATILE_JUMBO /* 0x1f6 */
+    .long .L_OP_IPUT_WIDE_VOLATILE_JUMBO /* 0x1f7 */
+    .long .L_OP_IPUT_OBJECT_VOLATILE_JUMBO /* 0x1f8 */
+    .long .L_OP_SGET_VOLATILE_JUMBO /* 0x1f9 */
+    .long .L_OP_SGET_WIDE_VOLATILE_JUMBO /* 0x1fa */
+    .long .L_OP_SGET_OBJECT_VOLATILE_JUMBO /* 0x1fb */
+    .long .L_OP_SPUT_VOLATILE_JUMBO /* 0x1fc */
+    .long .L_OP_SPUT_WIDE_VOLATILE_JUMBO /* 0x1fd */
+    .long .L_OP_SPUT_OBJECT_VOLATILE_JUMBO /* 0x1fe */
+    .long .L_OP_THROW_VERIFICATION_ERROR_JUMBO /* 0x1ff */
+
+    .global dvmAsmAltInstructionStart
+    .text
+dvmAsmAltInstructionStart:
+    .long .L_ALT_OP_NOP /* 0x00 */
+    .long .L_ALT_OP_MOVE /* 0x01 */
+    .long .L_ALT_OP_MOVE_FROM16 /* 0x02 */
+    .long .L_ALT_OP_MOVE_16 /* 0x03 */
+    .long .L_ALT_OP_MOVE_WIDE /* 0x04 */
+    .long .L_ALT_OP_MOVE_WIDE_FROM16 /* 0x05 */
+    .long .L_ALT_OP_MOVE_WIDE_16 /* 0x06 */
+    .long .L_ALT_OP_MOVE_OBJECT /* 0x07 */
+    .long .L_ALT_OP_MOVE_OBJECT_FROM16 /* 0x08 */
+    .long .L_ALT_OP_MOVE_OBJECT_16 /* 0x09 */
+    .long .L_ALT_OP_MOVE_RESULT /* 0x0a */
+    .long .L_ALT_OP_MOVE_RESULT_WIDE /* 0x0b */
+    .long .L_ALT_OP_MOVE_RESULT_OBJECT /* 0x0c */
+    .long .L_ALT_OP_MOVE_EXCEPTION /* 0x0d */
+    .long .L_ALT_OP_RETURN_VOID /* 0x0e */
+    .long .L_ALT_OP_RETURN /* 0x0f */
+    .long .L_ALT_OP_RETURN_WIDE /* 0x10 */
+    .long .L_ALT_OP_RETURN_OBJECT /* 0x11 */
+    .long .L_ALT_OP_CONST_4 /* 0x12 */
+    .long .L_ALT_OP_CONST_16 /* 0x13 */
+    .long .L_ALT_OP_CONST /* 0x14 */
+    .long .L_ALT_OP_CONST_HIGH16 /* 0x15 */
+    .long .L_ALT_OP_CONST_WIDE_16 /* 0x16 */
+    .long .L_ALT_OP_CONST_WIDE_32 /* 0x17 */
+    .long .L_ALT_OP_CONST_WIDE /* 0x18 */
+    .long .L_ALT_OP_CONST_WIDE_HIGH16 /* 0x19 */
+    .long .L_ALT_OP_CONST_STRING /* 0x1a */
+    .long .L_ALT_OP_CONST_STRING_JUMBO /* 0x1b */
+    .long .L_ALT_OP_CONST_CLASS /* 0x1c */
+    .long .L_ALT_OP_MONITOR_ENTER /* 0x1d */
+    .long .L_ALT_OP_MONITOR_EXIT /* 0x1e */
+    .long .L_ALT_OP_CHECK_CAST /* 0x1f */
+    .long .L_ALT_OP_INSTANCE_OF /* 0x20 */
+    .long .L_ALT_OP_ARRAY_LENGTH /* 0x21 */
+    .long .L_ALT_OP_NEW_INSTANCE /* 0x22 */
+    .long .L_ALT_OP_NEW_ARRAY /* 0x23 */
+    .long .L_ALT_OP_FILLED_NEW_ARRAY /* 0x24 */
+    .long .L_ALT_OP_FILLED_NEW_ARRAY_RANGE /* 0x25 */
+    .long .L_ALT_OP_FILL_ARRAY_DATA /* 0x26 */
+    .long .L_ALT_OP_THROW /* 0x27 */
+    .long .L_ALT_OP_GOTO /* 0x28 */
+    .long .L_ALT_OP_GOTO_16 /* 0x29 */
+    .long .L_ALT_OP_GOTO_32 /* 0x2a */
+    .long .L_ALT_OP_PACKED_SWITCH /* 0x2b */
+    .long .L_ALT_OP_SPARSE_SWITCH /* 0x2c */
+    .long .L_ALT_OP_CMPL_FLOAT /* 0x2d */
+    .long .L_ALT_OP_CMPG_FLOAT /* 0x2e */
+    .long .L_ALT_OP_CMPL_DOUBLE /* 0x2f */
+    .long .L_ALT_OP_CMPG_DOUBLE /* 0x30 */
+    .long .L_ALT_OP_CMP_LONG /* 0x31 */
+    .long .L_ALT_OP_IF_EQ /* 0x32 */
+    .long .L_ALT_OP_IF_NE /* 0x33 */
+    .long .L_ALT_OP_IF_LT /* 0x34 */
+    .long .L_ALT_OP_IF_GE /* 0x35 */
+    .long .L_ALT_OP_IF_GT /* 0x36 */
+    .long .L_ALT_OP_IF_LE /* 0x37 */
+    .long .L_ALT_OP_IF_EQZ /* 0x38 */
+    .long .L_ALT_OP_IF_NEZ /* 0x39 */
+    .long .L_ALT_OP_IF_LTZ /* 0x3a */
+    .long .L_ALT_OP_IF_GEZ /* 0x3b */
+    .long .L_ALT_OP_IF_GTZ /* 0x3c */
+    .long .L_ALT_OP_IF_LEZ /* 0x3d */
+    .long .L_ALT_OP_UNUSED_3E /* 0x3e */
+    .long .L_ALT_OP_UNUSED_3F /* 0x3f */
+    .long .L_ALT_OP_UNUSED_40 /* 0x40 */
+    .long .L_ALT_OP_UNUSED_41 /* 0x41 */
+    .long .L_ALT_OP_UNUSED_42 /* 0x42 */
+    .long .L_ALT_OP_UNUSED_43 /* 0x43 */
+    .long .L_ALT_OP_AGET /* 0x44 */
+    .long .L_ALT_OP_AGET_WIDE /* 0x45 */
+    .long .L_ALT_OP_AGET_OBJECT /* 0x46 */
+    .long .L_ALT_OP_AGET_BOOLEAN /* 0x47 */
+    .long .L_ALT_OP_AGET_BYTE /* 0x48 */
+    .long .L_ALT_OP_AGET_CHAR /* 0x49 */
+    .long .L_ALT_OP_AGET_SHORT /* 0x4a */
+    .long .L_ALT_OP_APUT /* 0x4b */
+    .long .L_ALT_OP_APUT_WIDE /* 0x4c */
+    .long .L_ALT_OP_APUT_OBJECT /* 0x4d */
+    .long .L_ALT_OP_APUT_BOOLEAN /* 0x4e */
+    .long .L_ALT_OP_APUT_BYTE /* 0x4f */
+    .long .L_ALT_OP_APUT_CHAR /* 0x50 */
+    .long .L_ALT_OP_APUT_SHORT /* 0x51 */
+    .long .L_ALT_OP_IGET /* 0x52 */
+    .long .L_ALT_OP_IGET_WIDE /* 0x53 */
+    .long .L_ALT_OP_IGET_OBJECT /* 0x54 */
+    .long .L_ALT_OP_IGET_BOOLEAN /* 0x55 */
+    .long .L_ALT_OP_IGET_BYTE /* 0x56 */
+    .long .L_ALT_OP_IGET_CHAR /* 0x57 */
+    .long .L_ALT_OP_IGET_SHORT /* 0x58 */
+    .long .L_ALT_OP_IPUT /* 0x59 */
+    .long .L_ALT_OP_IPUT_WIDE /* 0x5a */
+    .long .L_ALT_OP_IPUT_OBJECT /* 0x5b */
+    .long .L_ALT_OP_IPUT_BOOLEAN /* 0x5c */
+    .long .L_ALT_OP_IPUT_BYTE /* 0x5d */
+    .long .L_ALT_OP_IPUT_CHAR /* 0x5e */
+    .long .L_ALT_OP_IPUT_SHORT /* 0x5f */
+    .long .L_ALT_OP_SGET /* 0x60 */
+    .long .L_ALT_OP_SGET_WIDE /* 0x61 */
+    .long .L_ALT_OP_SGET_OBJECT /* 0x62 */
+    .long .L_ALT_OP_SGET_BOOLEAN /* 0x63 */
+    .long .L_ALT_OP_SGET_BYTE /* 0x64 */
+    .long .L_ALT_OP_SGET_CHAR /* 0x65 */
+    .long .L_ALT_OP_SGET_SHORT /* 0x66 */
+    .long .L_ALT_OP_SPUT /* 0x67 */
+    .long .L_ALT_OP_SPUT_WIDE /* 0x68 */
+    .long .L_ALT_OP_SPUT_OBJECT /* 0x69 */
+    .long .L_ALT_OP_SPUT_BOOLEAN /* 0x6a */
+    .long .L_ALT_OP_SPUT_BYTE /* 0x6b */
+    .long .L_ALT_OP_SPUT_CHAR /* 0x6c */
+    .long .L_ALT_OP_SPUT_SHORT /* 0x6d */
+    .long .L_ALT_OP_INVOKE_VIRTUAL /* 0x6e */
+    .long .L_ALT_OP_INVOKE_SUPER /* 0x6f */
+    .long .L_ALT_OP_INVOKE_DIRECT /* 0x70 */
+    .long .L_ALT_OP_INVOKE_STATIC /* 0x71 */
+    .long .L_ALT_OP_INVOKE_INTERFACE /* 0x72 */
+    .long .L_ALT_OP_UNUSED_73 /* 0x73 */
+    .long .L_ALT_OP_INVOKE_VIRTUAL_RANGE /* 0x74 */
+    .long .L_ALT_OP_INVOKE_SUPER_RANGE /* 0x75 */
+    .long .L_ALT_OP_INVOKE_DIRECT_RANGE /* 0x76 */
+    .long .L_ALT_OP_INVOKE_STATIC_RANGE /* 0x77 */
+    .long .L_ALT_OP_INVOKE_INTERFACE_RANGE /* 0x78 */
+    .long .L_ALT_OP_UNUSED_79 /* 0x79 */
+    .long .L_ALT_OP_UNUSED_7A /* 0x7a */
+    .long .L_ALT_OP_NEG_INT /* 0x7b */
+    .long .L_ALT_OP_NOT_INT /* 0x7c */
+    .long .L_ALT_OP_NEG_LONG /* 0x7d */
+    .long .L_ALT_OP_NOT_LONG /* 0x7e */
+    .long .L_ALT_OP_NEG_FLOAT /* 0x7f */
+    .long .L_ALT_OP_NEG_DOUBLE /* 0x80 */
+    .long .L_ALT_OP_INT_TO_LONG /* 0x81 */
+    .long .L_ALT_OP_INT_TO_FLOAT /* 0x82 */
+    .long .L_ALT_OP_INT_TO_DOUBLE /* 0x83 */
+    .long .L_ALT_OP_LONG_TO_INT /* 0x84 */
+    .long .L_ALT_OP_LONG_TO_FLOAT /* 0x85 */
+    .long .L_ALT_OP_LONG_TO_DOUBLE /* 0x86 */
+    .long .L_ALT_OP_FLOAT_TO_INT /* 0x87 */
+    .long .L_ALT_OP_FLOAT_TO_LONG /* 0x88 */
+    .long .L_ALT_OP_FLOAT_TO_DOUBLE /* 0x89 */
+    .long .L_ALT_OP_DOUBLE_TO_INT /* 0x8a */
+    .long .L_ALT_OP_DOUBLE_TO_LONG /* 0x8b */
+    .long .L_ALT_OP_DOUBLE_TO_FLOAT /* 0x8c */
+    .long .L_ALT_OP_INT_TO_BYTE /* 0x8d */
+    .long .L_ALT_OP_INT_TO_CHAR /* 0x8e */
+    .long .L_ALT_OP_INT_TO_SHORT /* 0x8f */
+    .long .L_ALT_OP_ADD_INT /* 0x90 */
+    .long .L_ALT_OP_SUB_INT /* 0x91 */
+    .long .L_ALT_OP_MUL_INT /* 0x92 */
+    .long .L_ALT_OP_DIV_INT /* 0x93 */
+    .long .L_ALT_OP_REM_INT /* 0x94 */
+    .long .L_ALT_OP_AND_INT /* 0x95 */
+    .long .L_ALT_OP_OR_INT /* 0x96 */
+    .long .L_ALT_OP_XOR_INT /* 0x97 */
+    .long .L_ALT_OP_SHL_INT /* 0x98 */
+    .long .L_ALT_OP_SHR_INT /* 0x99 */
+    .long .L_ALT_OP_USHR_INT /* 0x9a */
+    .long .L_ALT_OP_ADD_LONG /* 0x9b */
+    .long .L_ALT_OP_SUB_LONG /* 0x9c */
+    .long .L_ALT_OP_MUL_LONG /* 0x9d */
+    .long .L_ALT_OP_DIV_LONG /* 0x9e */
+    .long .L_ALT_OP_REM_LONG /* 0x9f */
+    .long .L_ALT_OP_AND_LONG /* 0xa0 */
+    .long .L_ALT_OP_OR_LONG /* 0xa1 */
+    .long .L_ALT_OP_XOR_LONG /* 0xa2 */
+    .long .L_ALT_OP_SHL_LONG /* 0xa3 */
+    .long .L_ALT_OP_SHR_LONG /* 0xa4 */
+    .long .L_ALT_OP_USHR_LONG /* 0xa5 */
+    .long .L_ALT_OP_ADD_FLOAT /* 0xa6 */
+    .long .L_ALT_OP_SUB_FLOAT /* 0xa7 */
+    .long .L_ALT_OP_MUL_FLOAT /* 0xa8 */
+    .long .L_ALT_OP_DIV_FLOAT /* 0xa9 */
+    .long .L_ALT_OP_REM_FLOAT /* 0xaa */
+    .long .L_ALT_OP_ADD_DOUBLE /* 0xab */
+    .long .L_ALT_OP_SUB_DOUBLE /* 0xac */
+    .long .L_ALT_OP_MUL_DOUBLE /* 0xad */
+    .long .L_ALT_OP_DIV_DOUBLE /* 0xae */
+    .long .L_ALT_OP_REM_DOUBLE /* 0xaf */
+    .long .L_ALT_OP_ADD_INT_2ADDR /* 0xb0 */
+    .long .L_ALT_OP_SUB_INT_2ADDR /* 0xb1 */
+    .long .L_ALT_OP_MUL_INT_2ADDR /* 0xb2 */
+    .long .L_ALT_OP_DIV_INT_2ADDR /* 0xb3 */
+    .long .L_ALT_OP_REM_INT_2ADDR /* 0xb4 */
+    .long .L_ALT_OP_AND_INT_2ADDR /* 0xb5 */
+    .long .L_ALT_OP_OR_INT_2ADDR /* 0xb6 */
+    .long .L_ALT_OP_XOR_INT_2ADDR /* 0xb7 */
+    .long .L_ALT_OP_SHL_INT_2ADDR /* 0xb8 */
+    .long .L_ALT_OP_SHR_INT_2ADDR /* 0xb9 */
+    .long .L_ALT_OP_USHR_INT_2ADDR /* 0xba */
+    .long .L_ALT_OP_ADD_LONG_2ADDR /* 0xbb */
+    .long .L_ALT_OP_SUB_LONG_2ADDR /* 0xbc */
+    .long .L_ALT_OP_MUL_LONG_2ADDR /* 0xbd */
+    .long .L_ALT_OP_DIV_LONG_2ADDR /* 0xbe */
+    .long .L_ALT_OP_REM_LONG_2ADDR /* 0xbf */
+    .long .L_ALT_OP_AND_LONG_2ADDR /* 0xc0 */
+    .long .L_ALT_OP_OR_LONG_2ADDR /* 0xc1 */
+    .long .L_ALT_OP_XOR_LONG_2ADDR /* 0xc2 */
+    .long .L_ALT_OP_SHL_LONG_2ADDR /* 0xc3 */
+    .long .L_ALT_OP_SHR_LONG_2ADDR /* 0xc4 */
+    .long .L_ALT_OP_USHR_LONG_2ADDR /* 0xc5 */
+    .long .L_ALT_OP_ADD_FLOAT_2ADDR /* 0xc6 */
+    .long .L_ALT_OP_SUB_FLOAT_2ADDR /* 0xc7 */
+    .long .L_ALT_OP_MUL_FLOAT_2ADDR /* 0xc8 */
+    .long .L_ALT_OP_DIV_FLOAT_2ADDR /* 0xc9 */
+    .long .L_ALT_OP_REM_FLOAT_2ADDR /* 0xca */
+    .long .L_ALT_OP_ADD_DOUBLE_2ADDR /* 0xcb */
+    .long .L_ALT_OP_SUB_DOUBLE_2ADDR /* 0xcc */
+    .long .L_ALT_OP_MUL_DOUBLE_2ADDR /* 0xcd */
+    .long .L_ALT_OP_DIV_DOUBLE_2ADDR /* 0xce */
+    .long .L_ALT_OP_REM_DOUBLE_2ADDR /* 0xcf */
+    .long .L_ALT_OP_ADD_INT_LIT16 /* 0xd0 */
+    .long .L_ALT_OP_RSUB_INT /* 0xd1 */
+    .long .L_ALT_OP_MUL_INT_LIT16 /* 0xd2 */
+    .long .L_ALT_OP_DIV_INT_LIT16 /* 0xd3 */
+    .long .L_ALT_OP_REM_INT_LIT16 /* 0xd4 */
+    .long .L_ALT_OP_AND_INT_LIT16 /* 0xd5 */
+    .long .L_ALT_OP_OR_INT_LIT16 /* 0xd6 */
+    .long .L_ALT_OP_XOR_INT_LIT16 /* 0xd7 */
+    .long .L_ALT_OP_ADD_INT_LIT8 /* 0xd8 */
+    .long .L_ALT_OP_RSUB_INT_LIT8 /* 0xd9 */
+    .long .L_ALT_OP_MUL_INT_LIT8 /* 0xda */
+    .long .L_ALT_OP_DIV_INT_LIT8 /* 0xdb */
+    .long .L_ALT_OP_REM_INT_LIT8 /* 0xdc */
+    .long .L_ALT_OP_AND_INT_LIT8 /* 0xdd */
+    .long .L_ALT_OP_OR_INT_LIT8 /* 0xde */
+    .long .L_ALT_OP_XOR_INT_LIT8 /* 0xdf */
+    .long .L_ALT_OP_SHL_INT_LIT8 /* 0xe0 */
+    .long .L_ALT_OP_SHR_INT_LIT8 /* 0xe1 */
+    .long .L_ALT_OP_USHR_INT_LIT8 /* 0xe2 */
+    .long .L_ALT_OP_IGET_VOLATILE /* 0xe3 */
+    .long .L_ALT_OP_IPUT_VOLATILE /* 0xe4 */
+    .long .L_ALT_OP_SGET_VOLATILE /* 0xe5 */
+    .long .L_ALT_OP_SPUT_VOLATILE /* 0xe6 */
+    .long .L_ALT_OP_IGET_OBJECT_VOLATILE /* 0xe7 */
+    .long .L_ALT_OP_IGET_WIDE_VOLATILE /* 0xe8 */
+    .long .L_ALT_OP_IPUT_WIDE_VOLATILE /* 0xe9 */
+    .long .L_ALT_OP_SGET_WIDE_VOLATILE /* 0xea */
+    .long .L_ALT_OP_SPUT_WIDE_VOLATILE /* 0xeb */
+    .long .L_ALT_OP_BREAKPOINT /* 0xec */
+    .long .L_ALT_OP_THROW_VERIFICATION_ERROR /* 0xed */
+    .long .L_ALT_OP_EXECUTE_INLINE /* 0xee */
+    .long .L_ALT_OP_EXECUTE_INLINE_RANGE /* 0xef */
+    .long .L_ALT_OP_INVOKE_OBJECT_INIT_RANGE /* 0xf0 */
+    .long .L_ALT_OP_RETURN_VOID_BARRIER /* 0xf1 */
+    .long .L_ALT_OP_IGET_QUICK /* 0xf2 */
+    .long .L_ALT_OP_IGET_WIDE_QUICK /* 0xf3 */
+    .long .L_ALT_OP_IGET_OBJECT_QUICK /* 0xf4 */
+    .long .L_ALT_OP_IPUT_QUICK /* 0xf5 */
+    .long .L_ALT_OP_IPUT_WIDE_QUICK /* 0xf6 */
+    .long .L_ALT_OP_IPUT_OBJECT_QUICK /* 0xf7 */
+    .long .L_ALT_OP_INVOKE_VIRTUAL_QUICK /* 0xf8 */
+    .long .L_ALT_OP_INVOKE_VIRTUAL_QUICK_RANGE /* 0xf9 */
+    .long .L_ALT_OP_INVOKE_SUPER_QUICK /* 0xfa */
+    .long .L_ALT_OP_INVOKE_SUPER_QUICK_RANGE /* 0xfb */
+    .long .L_ALT_OP_IPUT_OBJECT_VOLATILE /* 0xfc */
+    .long .L_ALT_OP_SGET_OBJECT_VOLATILE /* 0xfd */
+    .long .L_ALT_OP_SPUT_OBJECT_VOLATILE /* 0xfe */
+    .long .L_ALT_OP_DISPATCH_FF /* 0xff */
+    .long .L_ALT_OP_CONST_CLASS_JUMBO /* 0x100 */
+    .long .L_ALT_OP_CHECK_CAST_JUMBO /* 0x101 */
+    .long .L_ALT_OP_INSTANCE_OF_JUMBO /* 0x102 */
+    .long .L_ALT_OP_NEW_INSTANCE_JUMBO /* 0x103 */
+    .long .L_ALT_OP_NEW_ARRAY_JUMBO /* 0x104 */
+    .long .L_ALT_OP_FILLED_NEW_ARRAY_JUMBO /* 0x105 */
+    .long .L_ALT_OP_IGET_JUMBO /* 0x106 */
+    .long .L_ALT_OP_IGET_WIDE_JUMBO /* 0x107 */
+    .long .L_ALT_OP_IGET_OBJECT_JUMBO /* 0x108 */
+    .long .L_ALT_OP_IGET_BOOLEAN_JUMBO /* 0x109 */
+    .long .L_ALT_OP_IGET_BYTE_JUMBO /* 0x10a */
+    .long .L_ALT_OP_IGET_CHAR_JUMBO /* 0x10b */
+    .long .L_ALT_OP_IGET_SHORT_JUMBO /* 0x10c */
+    .long .L_ALT_OP_IPUT_JUMBO /* 0x10d */
+    .long .L_ALT_OP_IPUT_WIDE_JUMBO /* 0x10e */
+    .long .L_ALT_OP_IPUT_OBJECT_JUMBO /* 0x10f */
+    .long .L_ALT_OP_IPUT_BOOLEAN_JUMBO /* 0x110 */
+    .long .L_ALT_OP_IPUT_BYTE_JUMBO /* 0x111 */
+    .long .L_ALT_OP_IPUT_CHAR_JUMBO /* 0x112 */
+    .long .L_ALT_OP_IPUT_SHORT_JUMBO /* 0x113 */
+    .long .L_ALT_OP_SGET_JUMBO /* 0x114 */
+    .long .L_ALT_OP_SGET_WIDE_JUMBO /* 0x115 */
+    .long .L_ALT_OP_SGET_OBJECT_JUMBO /* 0x116 */
+    .long .L_ALT_OP_SGET_BOOLEAN_JUMBO /* 0x117 */
+    .long .L_ALT_OP_SGET_BYTE_JUMBO /* 0x118 */
+    .long .L_ALT_OP_SGET_CHAR_JUMBO /* 0x119 */
+    .long .L_ALT_OP_SGET_SHORT_JUMBO /* 0x11a */
+    .long .L_ALT_OP_SPUT_JUMBO /* 0x11b */
+    .long .L_ALT_OP_SPUT_WIDE_JUMBO /* 0x11c */
+    .long .L_ALT_OP_SPUT_OBJECT_JUMBO /* 0x11d */
+    .long .L_ALT_OP_SPUT_BOOLEAN_JUMBO /* 0x11e */
+    .long .L_ALT_OP_SPUT_BYTE_JUMBO /* 0x11f */
+    .long .L_ALT_OP_SPUT_CHAR_JUMBO /* 0x120 */
+    .long .L_ALT_OP_SPUT_SHORT_JUMBO /* 0x121 */
+    .long .L_ALT_OP_INVOKE_VIRTUAL_JUMBO /* 0x122 */
+    .long .L_ALT_OP_INVOKE_SUPER_JUMBO /* 0x123 */
+    .long .L_ALT_OP_INVOKE_DIRECT_JUMBO /* 0x124 */
+    .long .L_ALT_OP_INVOKE_STATIC_JUMBO /* 0x125 */
+    .long .L_ALT_OP_INVOKE_INTERFACE_JUMBO /* 0x126 */
+    .long .L_ALT_OP_UNUSED_27FF /* 0x127 */
+    .long .L_ALT_OP_UNUSED_28FF /* 0x128 */
+    .long .L_ALT_OP_UNUSED_29FF /* 0x129 */
+    .long .L_ALT_OP_UNUSED_2AFF /* 0x12a */
+    .long .L_ALT_OP_UNUSED_2BFF /* 0x12b */
+    .long .L_ALT_OP_UNUSED_2CFF /* 0x12c */
+    .long .L_ALT_OP_UNUSED_2DFF /* 0x12d */
+    .long .L_ALT_OP_UNUSED_2EFF /* 0x12e */
+    .long .L_ALT_OP_UNUSED_2FFF /* 0x12f */
+    .long .L_ALT_OP_UNUSED_30FF /* 0x130 */
+    .long .L_ALT_OP_UNUSED_31FF /* 0x131 */
+    .long .L_ALT_OP_UNUSED_32FF /* 0x132 */
+    .long .L_ALT_OP_UNUSED_33FF /* 0x133 */
+    .long .L_ALT_OP_UNUSED_34FF /* 0x134 */
+    .long .L_ALT_OP_UNUSED_35FF /* 0x135 */
+    .long .L_ALT_OP_UNUSED_36FF /* 0x136 */
+    .long .L_ALT_OP_UNUSED_37FF /* 0x137 */
+    .long .L_ALT_OP_UNUSED_38FF /* 0x138 */
+    .long .L_ALT_OP_UNUSED_39FF /* 0x139 */
+    .long .L_ALT_OP_UNUSED_3AFF /* 0x13a */
+    .long .L_ALT_OP_UNUSED_3BFF /* 0x13b */
+    .long .L_ALT_OP_UNUSED_3CFF /* 0x13c */
+    .long .L_ALT_OP_UNUSED_3DFF /* 0x13d */
+    .long .L_ALT_OP_UNUSED_3EFF /* 0x13e */
+    .long .L_ALT_OP_UNUSED_3FFF /* 0x13f */
+    .long .L_ALT_OP_UNUSED_40FF /* 0x140 */
+    .long .L_ALT_OP_UNUSED_41FF /* 0x141 */
+    .long .L_ALT_OP_UNUSED_42FF /* 0x142 */
+    .long .L_ALT_OP_UNUSED_43FF /* 0x143 */
+    .long .L_ALT_OP_UNUSED_44FF /* 0x144 */
+    .long .L_ALT_OP_UNUSED_45FF /* 0x145 */
+    .long .L_ALT_OP_UNUSED_46FF /* 0x146 */
+    .long .L_ALT_OP_UNUSED_47FF /* 0x147 */
+    .long .L_ALT_OP_UNUSED_48FF /* 0x148 */
+    .long .L_ALT_OP_UNUSED_49FF /* 0x149 */
+    .long .L_ALT_OP_UNUSED_4AFF /* 0x14a */
+    .long .L_ALT_OP_UNUSED_4BFF /* 0x14b */
+    .long .L_ALT_OP_UNUSED_4CFF /* 0x14c */
+    .long .L_ALT_OP_UNUSED_4DFF /* 0x14d */
+    .long .L_ALT_OP_UNUSED_4EFF /* 0x14e */
+    .long .L_ALT_OP_UNUSED_4FFF /* 0x14f */
+    .long .L_ALT_OP_UNUSED_50FF /* 0x150 */
+    .long .L_ALT_OP_UNUSED_51FF /* 0x151 */
+    .long .L_ALT_OP_UNUSED_52FF /* 0x152 */
+    .long .L_ALT_OP_UNUSED_53FF /* 0x153 */
+    .long .L_ALT_OP_UNUSED_54FF /* 0x154 */
+    .long .L_ALT_OP_UNUSED_55FF /* 0x155 */
+    .long .L_ALT_OP_UNUSED_56FF /* 0x156 */
+    .long .L_ALT_OP_UNUSED_57FF /* 0x157 */
+    .long .L_ALT_OP_UNUSED_58FF /* 0x158 */
+    .long .L_ALT_OP_UNUSED_59FF /* 0x159 */
+    .long .L_ALT_OP_UNUSED_5AFF /* 0x15a */
+    .long .L_ALT_OP_UNUSED_5BFF /* 0x15b */
+    .long .L_ALT_OP_UNUSED_5CFF /* 0x15c */
+    .long .L_ALT_OP_UNUSED_5DFF /* 0x15d */
+    .long .L_ALT_OP_UNUSED_5EFF /* 0x15e */
+    .long .L_ALT_OP_UNUSED_5FFF /* 0x15f */
+    .long .L_ALT_OP_UNUSED_60FF /* 0x160 */
+    .long .L_ALT_OP_UNUSED_61FF /* 0x161 */
+    .long .L_ALT_OP_UNUSED_62FF /* 0x162 */
+    .long .L_ALT_OP_UNUSED_63FF /* 0x163 */
+    .long .L_ALT_OP_UNUSED_64FF /* 0x164 */
+    .long .L_ALT_OP_UNUSED_65FF /* 0x165 */
+    .long .L_ALT_OP_UNUSED_66FF /* 0x166 */
+    .long .L_ALT_OP_UNUSED_67FF /* 0x167 */
+    .long .L_ALT_OP_UNUSED_68FF /* 0x168 */
+    .long .L_ALT_OP_UNUSED_69FF /* 0x169 */
+    .long .L_ALT_OP_UNUSED_6AFF /* 0x16a */
+    .long .L_ALT_OP_UNUSED_6BFF /* 0x16b */
+    .long .L_ALT_OP_UNUSED_6CFF /* 0x16c */
+    .long .L_ALT_OP_UNUSED_6DFF /* 0x16d */
+    .long .L_ALT_OP_UNUSED_6EFF /* 0x16e */
+    .long .L_ALT_OP_UNUSED_6FFF /* 0x16f */
+    .long .L_ALT_OP_UNUSED_70FF /* 0x170 */
+    .long .L_ALT_OP_UNUSED_71FF /* 0x171 */
+    .long .L_ALT_OP_UNUSED_72FF /* 0x172 */
+    .long .L_ALT_OP_UNUSED_73FF /* 0x173 */
+    .long .L_ALT_OP_UNUSED_74FF /* 0x174 */
+    .long .L_ALT_OP_UNUSED_75FF /* 0x175 */
+    .long .L_ALT_OP_UNUSED_76FF /* 0x176 */
+    .long .L_ALT_OP_UNUSED_77FF /* 0x177 */
+    .long .L_ALT_OP_UNUSED_78FF /* 0x178 */
+    .long .L_ALT_OP_UNUSED_79FF /* 0x179 */
+    .long .L_ALT_OP_UNUSED_7AFF /* 0x17a */
+    .long .L_ALT_OP_UNUSED_7BFF /* 0x17b */
+    .long .L_ALT_OP_UNUSED_7CFF /* 0x17c */
+    .long .L_ALT_OP_UNUSED_7DFF /* 0x17d */
+    .long .L_ALT_OP_UNUSED_7EFF /* 0x17e */
+    .long .L_ALT_OP_UNUSED_7FFF /* 0x17f */
+    .long .L_ALT_OP_UNUSED_80FF /* 0x180 */
+    .long .L_ALT_OP_UNUSED_81FF /* 0x181 */
+    .long .L_ALT_OP_UNUSED_82FF /* 0x182 */
+    .long .L_ALT_OP_UNUSED_83FF /* 0x183 */
+    .long .L_ALT_OP_UNUSED_84FF /* 0x184 */
+    .long .L_ALT_OP_UNUSED_85FF /* 0x185 */
+    .long .L_ALT_OP_UNUSED_86FF /* 0x186 */
+    .long .L_ALT_OP_UNUSED_87FF /* 0x187 */
+    .long .L_ALT_OP_UNUSED_88FF /* 0x188 */
+    .long .L_ALT_OP_UNUSED_89FF /* 0x189 */
+    .long .L_ALT_OP_UNUSED_8AFF /* 0x18a */
+    .long .L_ALT_OP_UNUSED_8BFF /* 0x18b */
+    .long .L_ALT_OP_UNUSED_8CFF /* 0x18c */
+    .long .L_ALT_OP_UNUSED_8DFF /* 0x18d */
+    .long .L_ALT_OP_UNUSED_8EFF /* 0x18e */
+    .long .L_ALT_OP_UNUSED_8FFF /* 0x18f */
+    .long .L_ALT_OP_UNUSED_90FF /* 0x190 */
+    .long .L_ALT_OP_UNUSED_91FF /* 0x191 */
+    .long .L_ALT_OP_UNUSED_92FF /* 0x192 */
+    .long .L_ALT_OP_UNUSED_93FF /* 0x193 */
+    .long .L_ALT_OP_UNUSED_94FF /* 0x194 */
+    .long .L_ALT_OP_UNUSED_95FF /* 0x195 */
+    .long .L_ALT_OP_UNUSED_96FF /* 0x196 */
+    .long .L_ALT_OP_UNUSED_97FF /* 0x197 */
+    .long .L_ALT_OP_UNUSED_98FF /* 0x198 */
+    .long .L_ALT_OP_UNUSED_99FF /* 0x199 */
+    .long .L_ALT_OP_UNUSED_9AFF /* 0x19a */
+    .long .L_ALT_OP_UNUSED_9BFF /* 0x19b */
+    .long .L_ALT_OP_UNUSED_9CFF /* 0x19c */
+    .long .L_ALT_OP_UNUSED_9DFF /* 0x19d */
+    .long .L_ALT_OP_UNUSED_9EFF /* 0x19e */
+    .long .L_ALT_OP_UNUSED_9FFF /* 0x19f */
+    .long .L_ALT_OP_UNUSED_A0FF /* 0x1a0 */
+    .long .L_ALT_OP_UNUSED_A1FF /* 0x1a1 */
+    .long .L_ALT_OP_UNUSED_A2FF /* 0x1a2 */
+    .long .L_ALT_OP_UNUSED_A3FF /* 0x1a3 */
+    .long .L_ALT_OP_UNUSED_A4FF /* 0x1a4 */
+    .long .L_ALT_OP_UNUSED_A5FF /* 0x1a5 */
+    .long .L_ALT_OP_UNUSED_A6FF /* 0x1a6 */
+    .long .L_ALT_OP_UNUSED_A7FF /* 0x1a7 */
+    .long .L_ALT_OP_UNUSED_A8FF /* 0x1a8 */
+    .long .L_ALT_OP_UNUSED_A9FF /* 0x1a9 */
+    .long .L_ALT_OP_UNUSED_AAFF /* 0x1aa */
+    .long .L_ALT_OP_UNUSED_ABFF /* 0x1ab */
+    .long .L_ALT_OP_UNUSED_ACFF /* 0x1ac */
+    .long .L_ALT_OP_UNUSED_ADFF /* 0x1ad */
+    .long .L_ALT_OP_UNUSED_AEFF /* 0x1ae */
+    .long .L_ALT_OP_UNUSED_AFFF /* 0x1af */
+    .long .L_ALT_OP_UNUSED_B0FF /* 0x1b0 */
+    .long .L_ALT_OP_UNUSED_B1FF /* 0x1b1 */
+    .long .L_ALT_OP_UNUSED_B2FF /* 0x1b2 */
+    .long .L_ALT_OP_UNUSED_B3FF /* 0x1b3 */
+    .long .L_ALT_OP_UNUSED_B4FF /* 0x1b4 */
+    .long .L_ALT_OP_UNUSED_B5FF /* 0x1b5 */
+    .long .L_ALT_OP_UNUSED_B6FF /* 0x1b6 */
+    .long .L_ALT_OP_UNUSED_B7FF /* 0x1b7 */
+    .long .L_ALT_OP_UNUSED_B8FF /* 0x1b8 */
+    .long .L_ALT_OP_UNUSED_B9FF /* 0x1b9 */
+    .long .L_ALT_OP_UNUSED_BAFF /* 0x1ba */
+    .long .L_ALT_OP_UNUSED_BBFF /* 0x1bb */
+    .long .L_ALT_OP_UNUSED_BCFF /* 0x1bc */
+    .long .L_ALT_OP_UNUSED_BDFF /* 0x1bd */
+    .long .L_ALT_OP_UNUSED_BEFF /* 0x1be */
+    .long .L_ALT_OP_UNUSED_BFFF /* 0x1bf */
+    .long .L_ALT_OP_UNUSED_C0FF /* 0x1c0 */
+    .long .L_ALT_OP_UNUSED_C1FF /* 0x1c1 */
+    .long .L_ALT_OP_UNUSED_C2FF /* 0x1c2 */
+    .long .L_ALT_OP_UNUSED_C3FF /* 0x1c3 */
+    .long .L_ALT_OP_UNUSED_C4FF /* 0x1c4 */
+    .long .L_ALT_OP_UNUSED_C5FF /* 0x1c5 */
+    .long .L_ALT_OP_UNUSED_C6FF /* 0x1c6 */
+    .long .L_ALT_OP_UNUSED_C7FF /* 0x1c7 */
+    .long .L_ALT_OP_UNUSED_C8FF /* 0x1c8 */
+    .long .L_ALT_OP_UNUSED_C9FF /* 0x1c9 */
+    .long .L_ALT_OP_UNUSED_CAFF /* 0x1ca */
+    .long .L_ALT_OP_UNUSED_CBFF /* 0x1cb */
+    .long .L_ALT_OP_UNUSED_CCFF /* 0x1cc */
+    .long .L_ALT_OP_UNUSED_CDFF /* 0x1cd */
+    .long .L_ALT_OP_UNUSED_CEFF /* 0x1ce */
+    .long .L_ALT_OP_UNUSED_CFFF /* 0x1cf */
+    .long .L_ALT_OP_UNUSED_D0FF /* 0x1d0 */
+    .long .L_ALT_OP_UNUSED_D1FF /* 0x1d1 */
+    .long .L_ALT_OP_UNUSED_D2FF /* 0x1d2 */
+    .long .L_ALT_OP_UNUSED_D3FF /* 0x1d3 */
+    .long .L_ALT_OP_UNUSED_D4FF /* 0x1d4 */
+    .long .L_ALT_OP_UNUSED_D5FF /* 0x1d5 */
+    .long .L_ALT_OP_UNUSED_D6FF /* 0x1d6 */
+    .long .L_ALT_OP_UNUSED_D7FF /* 0x1d7 */
+    .long .L_ALT_OP_UNUSED_D8FF /* 0x1d8 */
+    .long .L_ALT_OP_UNUSED_D9FF /* 0x1d9 */
+    .long .L_ALT_OP_UNUSED_DAFF /* 0x1da */
+    .long .L_ALT_OP_UNUSED_DBFF /* 0x1db */
+    .long .L_ALT_OP_UNUSED_DCFF /* 0x1dc */
+    .long .L_ALT_OP_UNUSED_DDFF /* 0x1dd */
+    .long .L_ALT_OP_UNUSED_DEFF /* 0x1de */
+    .long .L_ALT_OP_UNUSED_DFFF /* 0x1df */
+    .long .L_ALT_OP_UNUSED_E0FF /* 0x1e0 */
+    .long .L_ALT_OP_UNUSED_E1FF /* 0x1e1 */
+    .long .L_ALT_OP_UNUSED_E2FF /* 0x1e2 */
+    .long .L_ALT_OP_UNUSED_E3FF /* 0x1e3 */
+    .long .L_ALT_OP_UNUSED_E4FF /* 0x1e4 */
+    .long .L_ALT_OP_UNUSED_E5FF /* 0x1e5 */
+    .long .L_ALT_OP_UNUSED_E6FF /* 0x1e6 */
+    .long .L_ALT_OP_UNUSED_E7FF /* 0x1e7 */
+    .long .L_ALT_OP_UNUSED_E8FF /* 0x1e8 */
+    .long .L_ALT_OP_UNUSED_E9FF /* 0x1e9 */
+    .long .L_ALT_OP_UNUSED_EAFF /* 0x1ea */
+    .long .L_ALT_OP_UNUSED_EBFF /* 0x1eb */
+    .long .L_ALT_OP_UNUSED_ECFF /* 0x1ec */
+    .long .L_ALT_OP_UNUSED_EDFF /* 0x1ed */
+    .long .L_ALT_OP_UNUSED_EEFF /* 0x1ee */
+    .long .L_ALT_OP_UNUSED_EFFF /* 0x1ef */
+    .long .L_ALT_OP_UNUSED_F0FF /* 0x1f0 */
+    .long .L_ALT_OP_UNUSED_F1FF /* 0x1f1 */
+    .long .L_ALT_OP_INVOKE_OBJECT_INIT_JUMBO /* 0x1f2 */
+    .long .L_ALT_OP_IGET_VOLATILE_JUMBO /* 0x1f3 */
+    .long .L_ALT_OP_IGET_WIDE_VOLATILE_JUMBO /* 0x1f4 */
+    .long .L_ALT_OP_IGET_OBJECT_VOLATILE_JUMBO /* 0x1f5 */
+    .long .L_ALT_OP_IPUT_VOLATILE_JUMBO /* 0x1f6 */
+    .long .L_ALT_OP_IPUT_WIDE_VOLATILE_JUMBO /* 0x1f7 */
+    .long .L_ALT_OP_IPUT_OBJECT_VOLATILE_JUMBO /* 0x1f8 */
+    .long .L_ALT_OP_SGET_VOLATILE_JUMBO /* 0x1f9 */
+    .long .L_ALT_OP_SGET_WIDE_VOLATILE_JUMBO /* 0x1fa */
+    .long .L_ALT_OP_SGET_OBJECT_VOLATILE_JUMBO /* 0x1fb */
+    .long .L_ALT_OP_SPUT_VOLATILE_JUMBO /* 0x1fc */
+    .long .L_ALT_OP_SPUT_WIDE_VOLATILE_JUMBO /* 0x1fd */
+    .long .L_ALT_OP_SPUT_OBJECT_VOLATILE_JUMBO /* 0x1fe */
+    .long .L_ALT_OP_THROW_VERIFICATION_ERROR_JUMBO /* 0x1ff */
+/* File: x86/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.
+ */
+
+
+    .text
+    .global dvmMterpStdRun
+    .type   dvmMterpStdRun, %function
+/*
+ * bool dvmMterpStdRun(Thread* self)
+ *
+ * Interpreter entry point.  Returns changeInterp.
+ *
+ */
+dvmMterpStdRun:
+    push    %ebp                 # save caller base pointer
+    movl    %esp, %ebp           # set our %ebp
+    movl    rSELF, %ecx          # get incoming rSELF
+/*
+ * At this point we've allocated one slot on the stack
+ * via push and stack is 8-byte aligned.  Allocate space
+ * for 9 spill slots, 4 local slots, 5 arg slots to bring
+ * us to 16-byte alignment
+ */
+    subl    $(FRAME_SIZE-4), %esp
+
+/* Spill callee save regs */
+    movl    %edi,EDI_SPILL(%ebp)
+    movl    %esi,ESI_SPILL(%ebp)
+    movl    %ebx,EBX_SPILL(%ebp)
+
+/* Set up "named" registers */
+    movl    offThread_pc(%ecx),rPC
+    movl    offThread_curFrame(%ecx),rFP
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+
+/* Remember %esp for future "longjmp" */
+    movl    %esp,offThread_bailPtr(%ecx)
+
+   /* Normal case: start executing the instruction at rPC */
+    FETCH_INST
+    GOTO_NEXT
+
+    .global dvmMterpStdBail
+    .type   dvmMterpStdBail, %function
+/*
+ * void dvmMterpStdBail(Thread* self, bool changeInterp)
+ *
+ * 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're not going to build a standard frame here, so the arg accesses will
+ * look a little strange.
+ *
+ * On entry:
+ *  esp+4 (arg0)  Thread* self
+ *  esp+8 (arg1)  bool changeInterp
+ */
+dvmMterpStdBail:
+    movl    4(%esp),%ecx                 # grab self
+    movl    8(%esp),%eax                 # changeInterp to return reg
+    movl    offThread_bailPtr(%ecx),%esp   # Restore "setjmp" esp
+    movl    %esp,%ebp
+    addl    $(FRAME_SIZE-4), %ebp       # Restore %ebp at point of setjmp
+    movl    EDI_SPILL(%ebp),%edi
+    movl    ESI_SPILL(%ebp),%esi
+    movl    EBX_SPILL(%ebp),%ebx
+    movl    %ebp, %esp                   # strip frame
+    pop     %ebp                         # restore caller's ebp
+    ret                                  # return to dvmMterpStdRun's caller
+
+
+/*
+ * Strings
+ */
+    .section    .rodata
+.LstrBadEntryPoint:
+    .asciz  "Bad entry point %d\n"
+
+
+/* File: x86/footer.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.
+ */
+/*
+ * Common subroutines and data.
+ */
+
+#if defined(WITH_JIT)
+/*
+ * JIT-related re-entries into the interpreter.  In general, if the
+ * exit from a translation can at some point be chained, the entry
+ * here requires that control arrived via a call, and that the "rp"
+ * on TOS is actually a pointer to a 32-bit cell containing the Dalvik PC
+ * of the next insn to handle.  If no chaining will happen, the entry
+ * should be reached via a direct jump and rPC set beforehand.
+ */
+
+    .global dvmJitToInterpPunt
+/*
+ * The compiler will generate a jump to this entry point when it is
+ * having difficulty translating a Dalvik instruction.  We must skip
+ * the code cache lookup & prevent chaining to avoid bouncing between
+ * the interpreter and code cache. rPC must be set on entry.
+ */
+dvmJitToInterpPunt:
+#if defined(WITH_JIT_TUNING)
+    movl   rPC, OUT_ARG0(%esp)
+    call   dvmBumpPunt
+#endif
+    movl   rSELF, %ecx
+    movl   offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_R %ecx
+    GOTO_NEXT_R %ecx
+
+    .global dvmJitToInterpSingleStep
+/*
+ * Return to the interpreter to handle a single instruction.
+ * Should be reached via a call.
+ * On entry:
+ *   0(%esp)          <= native return address within trace
+ *   rPC              <= Dalvik PC of this instruction
+ *   OUT_ARG0+4(%esp) <= Dalvik PC of next instruction
+ */
+dvmJitToInterpSingleStep:
+/* TODO */
+    call     dvmAbort
+#if 0
+    pop    %eax
+    movl   rSELF, %ecx
+    movl   OUT_ARG0(%esp), %edx
+    movl   %eax,offThread_jitResumeNPC(%ecx)
+    movl   %edx,offThread_jitResumeDPC(%ecx)
+    movl   $kInterpEntryInstr,offThread_entryPoint(%ecx)
+    movl   $1,rINST     # changeInterp <= true
+    jmp    common_gotoBail
+#endif
+
+    .global dvmJitToInterpNoChainNoProfile
+/*
+ * Return from the translation cache to the interpreter to do method
+ * invocation.  Check if the translation exists for the callee, but don't
+ * chain to it. rPC must be set on entry.
+ */
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    call   dvmBumpNoChain
+#endif
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddrThread        # (pc, self)
+    movl   rSELF,%ecx                # ecx <- self
+    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
+    cmpl   $0, %eax
+    jz     1f
+    call   *%eax                     # exec translation if we've got one
+    # won't return
+1:
+    movl   rSELF, %ecx
+    movl   offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_R %ecx
+    GOTO_NEXT_R %ecx
+
+/*
+ * Return from the translation cache and immediately request a
+ * translation fro the exit target, but don't attempt to chain.
+ * rPC set on entry.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    call   dvmBumpNoChain
+#endif
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddrThread # (pc, self)
+    movl   rSELF,%ecx
+    cmpl   $0,%eax
+    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
+    jz     1f
+    call   *%eax              # jump to tranlation
+    # won't return
+
+/* No Translation - request one */
+1:
+    GET_JIT_PROF_TABLE %ecx %eax
+    cmpl   $0, %eax          # JIT enabled?
+    jnz    2f                 # Request one if so
+    movl   rSELF, %ecx
+    movl   offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_R %ecx         # Continue interpreting if not
+    GOTO_NEXT_R %ecx
+2:
+    movl   $kJitTSelectRequestHot,rINST  # ask for trace select
+    jmp    common_selectTrace
+
+/*
+ * Return from the translation cache and immediately request a
+ * translation for the exit target.  Reached via a call, and
+ * (TOS)->rPC.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    pop    rINST           # save chain cell address in callee save reg
+    movl   (rINST),rPC
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddrThread # (pc, self)
+    cmpl   $0,%eax
+    jz     1b                 # no - ask for one
+    movl   %eax,OUT_ARG0(%esp)
+# TODO - need to adjust rINST to beginning of sequence
+    movl   rINST,OUT_ARG1(%esp)
+    call   dvmJitChain        # Attempt dvmJitChain(codeAddr,chainAddr)
+    cmpl   $0,%eax           # Success?
+    jz     toInterpreter      # didn't chain - interpret
+    call   *%eax
+    # won't return
+
+/*
+ * Placeholder entries for x86 JIT
+ */
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+toInterpreter:
+    jmp  common_abort
+
+common_updateProfile:
+    # quick & dirty hash
+    movl   rPC, %eax
+    shrl   $12, %eax
+    xorl   rPC, %eax
+    andl   $((1<<JIT_PROF_SIZE_LOG_2)-1),%eax
+    decb   (%edx,%eax)
+    jz     2f
+1:
+    GOTO_NEXT
+2:
+/*
+ * 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.
+ */
+    GET_JIT_THRESHOLD %ecx rINST  # leaves rSELF in %ecx
+    EXPORT_PC
+    movb   rINSTbl,(%edx,%eax)   # reset counter
+    movl   %ecx,rINST            # preserve rSELF
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddr  # (pc, self)
+    movl   %eax,offThread_inJitCodeCache(rINST)   # set the inJitCodeCache flag
+    cmpl   $0,%eax
+    jz     1f
+    call   *%eax        # TODO: decide call vs/ jmp!.  No return either way
+1:
+    movl   $kJitTSelectRequest,%eax
+    # On entry, eax<- jitState, rPC valid
+common_selectTrace:
+/* TODO */
+    call   dvmAbort
+#if 0
+    movl   rSELF,%ecx
+    movl   %eax,offThread_jitState(%ecx)
+    movl   $kInterpEntryInstr,offThread_entryPoint(%ecx)
+    movl   $1,rINST
+    jmp    common_gotoBail
+#endif
+#endif
+
+
+
+/*
+ * Common code for jumbo method invocation.
+ *
+ * On entry:
+ *   eax = Method* methodToCall
+ *   rINSTw trashed, must reload
+ *   rIBASE trashed, must reload before resuming interpreter
+ */
+
+common_invokeMethodJumbo:
+.LinvokeNewJumbo:
+
+   /*
+    * prepare to copy args to "outs" area of current frame
+    */
+    movzwl      6(rPC),rINST            # rINST<- BBBB
+    movzwl      8(rPC), %ecx            # %ecx<- CCCC
+    ADVANCE_PC 2                        # adjust pc to make return similar
+    SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
+    test        rINST, rINST
+    movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BBBB
+    jz          .LinvokeArgsDone        # no args; jump to args done
+    jmp         .LinvokeRangeArgs       # handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *   eax = Method* methodToCall
+ *   rINSTw trashed, must reload
+ *   rIBASE trashed, must reload before resuming interpreter
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+   /*
+    * prepare to copy args to "outs" area of current frame
+    */
+
+    movzbl      1(rPC),rINST       # rINST<- AA
+    movzwl      4(rPC), %ecx            # %ecx<- CCCC
+    SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
+    test        rINST, rINST
+    movl        rINST, 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)
+    */
+
+.LinvokeRangeArgs:
+    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
+    * rIBASE trashed, must reload before resuming interpreter
+    */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+    movzbl      1(rPC),rINST       # rINST<- BA
+    movl        rINST, 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               # %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             # rINSTw<- A
+    lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
+    movl        (rFP, rINST, 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               # %eax<- &StackSaveArea
+    subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
+    movl        rSELF,%edx              # %edx<- pthread
+    movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
+    subl        $sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+    movl        offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
+    movl        %edx, TMP_SPILL1(%ebp)  # spill self->interpStackEnd
+    shl         $2, %ecx               # %ecx<- update offset for outsSize
+    movl        %eax, %edx              # %edx<- newSaveArea
+    sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
+    cmp         TMP_SPILL1(%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               # %ecx<- &StackSaveArea
+    movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+    movl        rSELF,%ecx              # %ecx<- pthread
+    movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+    movl        rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+
+    /* Any special actions to take? */
+    cmpw        $0, offThread_subMode(%ecx)
+    jne         2f                     # Yes - handle them
+1:
+    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 "self" values for the new method
+    * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+    */
+    movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    movl        %eax, offThread_method(%ecx) # self->method<- methodToCall
+    movl        %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
+    movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+    movl        $1, offThread_debugIsMethodEntry(%ecx)
+    movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+    movl        rFP, offThread_curFrame(%ecx) # curFrame<-newFP
+    movl        offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST
+    GOTO_NEXT                           # jump to methodToCall->insns
+
+2:
+    /*
+     * On entry, preserve all:
+     *  %eax: method
+     *  %ecx: self
+     *  %edx: new save area
+     */
+    SPILL_TMP1(%eax)                   # preserve methodToCall
+    SPILL_TMP2(%edx)                   # preserve newSaveArea
+    movl        rPC, offThread_pc(%ecx) # update interpSave.pc
+    movl        %ecx, OUT_ARG0(%esp)
+    movl        %eax, OUT_ARG1(%esp)
+    call        dvmReportInvoke        # (self, method)
+    UNSPILL_TMP1(%eax)
+    UNSPILL_TMP2(%edx)
+    movl        rSELF,%ecx             # restore rSELF
+    jmp         1b
+
+   /*
+    * Prep for the native call
+    * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
+    */
+
+.LinvokeNative:
+    movl        offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
+    movl        rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
+    movl        %edx, LOCAL2_OFFSET(%ebp)  # save newSaveArea
+    movl        LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
+    movl        rINST, offThread_curFrame(%ecx)  # curFrame<- newFP
+    cmpw        $0, offThread_subMode(%ecx)  # Anything special going on?
+    jne         11f                     # yes - handle it
+    movl        %ecx, OUT_ARG3(%esp)    # push parameter self
+    movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
+    lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
+    movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
+    movl        rINST, OUT_ARG0(%esp)    # push parameter newFP
+    call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+7:
+    movl        LOCAL2_OFFSET(%ebp), %ecx    # %ecx<- newSaveArea
+    movl        rSELF, %eax             # %eax<- self
+    movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
+    cmp         $0, offThread_exception(%eax) # check for exception
+    movl        rFP, offThread_curFrame(%eax) # curFrame<- rFP
+    movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
+    jne         common_exceptionThrown  # handle exception
+    movl        offThread_curHandlerTable(%eax),rIBASE
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx                    # jump to next instruction
+
+11:
+    /*
+     * Handle any special subMode actions
+     * %eax=methodToCall, rINST=newFP, %ecx=self
+     */
+    SPILL_TMP1(%eax)                    # save methodTocall
+    movl        rPC, offThread_pc(%ecx)
+    movl        %ecx, OUT_ARG0(%esp)
+    movl        %eax, OUT_ARG1(%esp)
+    movl        rFP, OUT_ARG2(%esp)
+    call        dvmReportPreNativeInvoke # (self, methodToCall, fp)
+    UNSPILL_TMP1(%eax)                  # restore methodToCall
+    movl        rSELF,%ecx              # restore self
+
+    /* Do the native call */
+    movl        %ecx, OUT_ARG3(%esp)    # push parameter self
+    lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
+    movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
+    movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
+    movl        rINST, OUT_ARG0(%esp)   # push parameter newFP
+    call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+
+    UNSPILL_TMP1(%eax)                  # restore methodToCall
+    movl        rSELF, %ecx
+    movl        %ecx, OUT_ARG0(%esp)
+    movl        %eax, OUT_ARG1(%esp)
+    movl        rFP, OUT_ARG2(%esp)
+    call        dvmReportPostNativeInvoke # (self, methodToCall, fp)
+    jmp         7b                      # rejoin
+
+.LstackOverflow:    # eax=methodToCall
+    movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
+    movl        rSELF,%eax              # %eax<- self
+    movl        %eax, OUT_ARG0(%esp)    # push parameter self
+    call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
+    jmp         common_exceptionThrown  # handle exception
+
+
+/*
+ * Common code for handling a return instruction
+ */
+common_returnFromMethod:
+    movl    rSELF,%ecx
+    SAVEAREA_FROM_FP %eax                         # eax<- saveArea (old)
+    cmpw    $0, offThread_subMode(%ecx)          # special action needed?
+    jne     19f                                   # go if so
+14:
+    movl    offStackSaveArea_prevFrame(%eax),rFP  # rFP<- prevFrame
+    movl    (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
+    cmpl    $0,rINST                             # break?
+    je      common_gotoBail    # break frame, bail out completely
+
+    movl    offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
+    movl    rINST,offThread_method(%ecx)       # self->method = newSave->meethod
+    movl    rFP,offThread_curFrame(%ecx)       # curFrame = fp
+    movl    offMethod_clazz(rINST),%eax        # eax<- method->clazz
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    movl    offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
+    FETCH_INST_OPCODE 3 %eax
+    movl    rINST,offThread_methodClassDex(%ecx)
+    ADVANCE_PC 3
+    GOTO_NEXT_R %eax
+
+19:
+    /*
+     * Handle special subMode actions
+     * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
+     */
+    movl     rFP, offThread_curFrame(%ecx)    # update interpSave.curFrame
+    movl     rPC, offThread_pc(%ecx)          # update interpSave.pc
+    movl     %ecx, OUT_ARG0(%esp)             # parameter self
+    call     dvmReportReturn                  # (self)
+    movl     rSELF, %ecx                      # restore self
+    SAVEAREA_FROM_FP %eax                     # restore saveArea
+    jmp      14b
+
+
+/*
+ * Prepare to strip the current frame and "longjump" back to caller of
+ * dvmMterpStdRun.
+ *
+ * on entry:
+ *    rINST holds changeInterp
+ *    ecx holds self pointer
+ *
+ * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
+ */
+common_gotoBail:
+    movl   rPC,offThread_pc(%ecx)     # export state to self
+    movl   rFP,offThread_curFrame(%ecx)
+    movl   %ecx,OUT_ARG0(%esp)      # self in arg0
+    movl   rINST,OUT_ARG1(%esp)     # changeInterp in arg1
+    call   dvmMterpStdBail          # bail out....
+
+
+/*
+ * After returning from a "selfd" function, pull out the updated values
+ * and start executing at the next instruction.
+ */
+ common_resumeAfterGlueCall:
+     movl  rSELF, %eax
+     movl  offThread_pc(%eax),rPC
+     movl  offThread_curFrame(%eax),rFP
+     movl  offThread_curHandlerTable(%eax),rIBASE
+     FETCH_INST
+     GOTO_NEXT
+
+/*
+ * Integer divide or mod by zero
+ */
+common_errDivideByZero:
+    EXPORT_PC
+    movl    $.LstrDivideByZero,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowArithmeticException
+    jmp     common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry, len in eax
+ */
+common_errNegativeArraySize:
+    EXPORT_PC
+    movl    %eax,OUT_ARG0(%esp)                  # arg0<- len
+    call    dvmThrowNegativeArraySizeException   # (len)
+    jmp     common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry, method name in eax
+ */
+common_errNoSuchMethod:
+
+    EXPORT_PC
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowNoSuchMethodError
+    jmp     common_exceptionThrown
+
+/*
+ * Hit a null object when we weren't expecting one.  Export the PC, throw a
+ * NullPointerException and goto the exception processing code.
+ */
+common_errNullObject:
+    EXPORT_PC
+    xorl    %eax,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowNullPointerException
+    jmp     common_exceptionThrown
+
+/*
+ * Array index exceeds max.
+ * On entry:
+ *    eax <- array object
+ *    ecx <- index
+ */
+common_errArrayIndex:
+    EXPORT_PC
+    movl    offArrayObject_length(%eax), %eax
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    call    dvmThrowArrayIndexOutOfBoundsException   # args (length, index)
+    jmp     common_exceptionThrown
+
+/*
+ * 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.
+ *
+ * NOTE: special subMode handling done in dvmMterp_exceptionThrown
+ *
+ * This does not return.
+ */
+common_exceptionThrown:
+    movl    rSELF,%ecx
+    movl    rPC,offThread_pc(%ecx)
+    movl    rFP,offThread_curFrame(%ecx)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmMterp_exceptionThrown
+    jmp     common_resumeAfterGlueCall
+
+common_abort:
+    movl    $0xdeadf00d,%eax
+    call     *%eax
+
+
+/*
+ * Strings
+ */
+
+    .section     .rodata
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrFilledNewArrayNotImplA:
+    .asciz  "filled-new-array only implemented for 'int'"
+
diff --git a/vm/mterp/out/InterpC-allstubs.cpp b/vm/mterp/out/InterpC-allstubs.cpp
new file mode 100644
index 0000000..49a67bb
--- /dev/null
+++ b/vm/mterp/out/InterpC-allstubs.cpp
@@ -0,0 +1,5449 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'allstubs'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: c/OP_NOP.cpp */
+HANDLE_OPCODE(OP_NOP)
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE.cpp */
+HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_FROM16.cpp */
+HANDLE_OPCODE(OP_MOVE_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MOVE_16.cpp */
+HANDLE_OPCODE(OP_MOVE_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(3);
+OP_END
+
+/* File: c/OP_MOVE_WIDE.cpp */
+HANDLE_OPCODE(OP_MOVE_WIDE /*vA, vB*/)
+    /* IMPORTANT: must correctly handle overlapping registers, e.g. both
+     * "move-wide v6, v7" and "move-wide v7, v6" */
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move-wide v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
+        kSpacing+5, vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_WIDE_FROM16.cpp */
+HANDLE_OPCODE(OP_MOVE_WIDE_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move-wide/from16 v%d,v%d  (v%d=0x%08llx)", vdst, vsrc1,
+        vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MOVE_WIDE_16.cpp */
+HANDLE_OPCODE(OP_MOVE_WIDE_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move-wide/16 v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
+        kSpacing+8, vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(3);
+OP_END
+
+/* File: c/OP_MOVE_OBJECT.cpp */
+/* File: c/OP_MOVE.cpp */
+HANDLE_OPCODE(OP_MOVE_OBJECT /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(1);
+OP_END
+
+
+/* File: c/OP_MOVE_OBJECT_FROM16.cpp */
+/* File: c/OP_MOVE_FROM16.cpp */
+HANDLE_OPCODE(OP_MOVE_OBJECT_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(2);
+OP_END
+
+
+/* File: c/OP_MOVE_OBJECT_16.cpp */
+/* File: c/OP_MOVE_16.cpp */
+HANDLE_OPCODE(OP_MOVE_OBJECT_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(3);
+OP_END
+
+
+/* File: c/OP_MOVE_RESULT.cpp */
+HANDLE_OPCODE(OP_MOVE_RESULT /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
+         (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
+         vdst, kSpacing+4, vdst,retval.i);
+    SET_REGISTER(vdst, retval.i);
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_RESULT_WIDE.cpp */
+HANDLE_OPCODE(OP_MOVE_RESULT_WIDE /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result-wide v%d %s(0x%08llx)", vdst, kSpacing, retval.j);
+    SET_REGISTER_WIDE(vdst, retval.j);
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_RESULT_OBJECT.cpp */
+/* File: c/OP_MOVE_RESULT.cpp */
+HANDLE_OPCODE(OP_MOVE_RESULT_OBJECT /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
+         (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
+         vdst, kSpacing+4, vdst,retval.i);
+    SET_REGISTER(vdst, retval.i);
+    FINISH(1);
+OP_END
+
+
+/* File: c/OP_MOVE_EXCEPTION.cpp */
+HANDLE_OPCODE(OP_MOVE_EXCEPTION /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-exception v%d", vdst);
+    assert(self->exception != NULL);
+    SET_REGISTER(vdst, (u4)self->exception);
+    dvmClearException(self);
+    FINISH(1);
+OP_END
+
+/* File: c/OP_RETURN_VOID.cpp */
+HANDLE_OPCODE(OP_RETURN_VOID /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;    // placate valgrind
+#endif
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_RETURN.cpp */
+HANDLE_OPCODE(OP_RETURN /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return%s v%d",
+        (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
+    retval.i = GET_REGISTER(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_RETURN_WIDE.cpp */
+HANDLE_OPCODE(OP_RETURN_WIDE /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return-wide v%d", vsrc1);
+    retval.j = GET_REGISTER_WIDE(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_RETURN_OBJECT.cpp */
+/* File: c/OP_RETURN.cpp */
+HANDLE_OPCODE(OP_RETURN_OBJECT /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return%s v%d",
+        (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
+    retval.i = GET_REGISTER(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
+
+
+/* File: c/OP_CONST_4.cpp */
+HANDLE_OPCODE(OP_CONST_4 /*vA, #+B*/)
+    {
+        s4 tmp;
+
+        vdst = INST_A(inst);
+        tmp = (s4) (INST_B(inst) << 28) >> 28;  // sign extend 4-bit value
+        ILOGV("|const/4 v%d,#0x%02x", vdst, (s4)tmp);
+        SET_REGISTER(vdst, tmp);
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_CONST_16.cpp */
+HANDLE_OPCODE(OP_CONST_16 /*vAA, #+BBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const/16 v%d,#0x%04x", vdst, (s2)vsrc1);
+    SET_REGISTER(vdst, (s2) vsrc1);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST.cpp */
+HANDLE_OPCODE(OP_CONST /*vAA, #+BBBBBBBB*/)
+    {
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const v%d,#0x%08x", vdst, tmp);
+        SET_REGISTER(vdst, tmp);
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_CONST_HIGH16.cpp */
+HANDLE_OPCODE(OP_CONST_HIGH16 /*vAA, #+BBBB0000*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const/high16 v%d,#0x%04x0000", vdst, vsrc1);
+    SET_REGISTER(vdst, vsrc1 << 16);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_WIDE_16.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE_16 /*vAA, #+BBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const-wide/16 v%d,#0x%04x", vdst, (s2)vsrc1);
+    SET_REGISTER_WIDE(vdst, (s2)vsrc1);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_WIDE_32.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE_32 /*vAA, #+BBBBBBBB*/)
+    {
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const-wide/32 v%d,#0x%08x", vdst, tmp);
+        SET_REGISTER_WIDE(vdst, (s4) tmp);
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_CONST_WIDE.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE /*vAA, #+BBBBBBBBBBBBBBBB*/)
+    {
+        u8 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u8)FETCH(2) << 16;
+        tmp |= (u8)FETCH(3) << 32;
+        tmp |= (u8)FETCH(4) << 48;
+        ILOGV("|const-wide v%d,#0x%08llx", vdst, tmp);
+        SET_REGISTER_WIDE(vdst, tmp);
+    }
+    FINISH(5);
+OP_END
+
+/* File: c/OP_CONST_WIDE_HIGH16.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE_HIGH16 /*vAA, #+BBBB000000000000*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const-wide/high16 v%d,#0x%04x000000000000", vdst, vsrc1);
+    SET_REGISTER_WIDE(vdst, ((u8) vsrc1) << 48);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_STRING.cpp */
+HANDLE_OPCODE(OP_CONST_STRING /*vAA, string@BBBB*/)
+    {
+        StringObject* strObj;
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|const-string v%d string@0x%04x", vdst, ref);
+        strObj = dvmDexGetResolvedString(methodClassDex, ref);
+        if (strObj == NULL) {
+            EXPORT_PC();
+            strObj = dvmResolveString(curMethod->clazz, ref);
+            if (strObj == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) strObj);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_STRING_JUMBO.cpp */
+HANDLE_OPCODE(OP_CONST_STRING_JUMBO /*vAA, string@BBBBBBBB*/)
+    {
+        StringObject* strObj;
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const-string/jumbo v%d string@0x%08x", vdst, tmp);
+        strObj = dvmDexGetResolvedString(methodClassDex, tmp);
+        if (strObj == NULL) {
+            EXPORT_PC();
+            strObj = dvmResolveString(curMethod->clazz, tmp);
+            if (strObj == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) strObj);
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_CONST_CLASS.cpp */
+HANDLE_OPCODE(OP_CONST_CLASS /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|const-class v%d class@0x%04x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            EXPORT_PC();
+            clazz = dvmResolveClass(curMethod->clazz, ref, true);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) clazz);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MONITOR_ENTER.cpp */
+HANDLE_OPCODE(OP_MONITOR_ENTER /*vAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|monitor-enter v%d %s(0x%08x)",
+            vsrc1, kSpacing+6, GET_REGISTER(vsrc1));
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+        ILOGV("+ locking %p %s", obj, obj->clazz->descriptor);
+        EXPORT_PC();    /* need for precise GC */
+        dvmLockObject(self, obj);
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MONITOR_EXIT.cpp */
+HANDLE_OPCODE(OP_MONITOR_EXIT /*vAA*/)
+    {
+        Object* obj;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|monitor-exit v%d %s(0x%08x)",
+            vsrc1, kSpacing+5, GET_REGISTER(vsrc1));
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (!checkForNull(obj)) {
+            /*
+             * The exception needs to be processed at the *following*
+             * instruction, not the current instruction (see the Dalvik
+             * spec).  Because we're jumping to an exception handler,
+             * we're not actually at risk of skipping an instruction
+             * by doing so.
+             */
+            ADJUST_PC(1);           /* monitor-exit width is 1 */
+            GOTO_exceptionThrown();
+        }
+        ILOGV("+ unlocking %p %s", obj, obj->clazz->descriptor);
+        if (!dvmUnlockObject(self, obj)) {
+            assert(dvmCheckException(self));
+            ADJUST_PC(1);
+            GOTO_exceptionThrown();
+        }
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_CHECK_CAST.cpp */
+HANDLE_OPCODE(OP_CHECK_CAST /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ref = FETCH(1);         /* class to check against */
+        ILOGV("|check-cast v%d,class@0x%04x", vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj != NULL) {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                clazz = dvmResolveClass(curMethod->clazz, ref, false);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            if (!dvmInstanceof(obj->clazz, clazz)) {
+                dvmThrowClassCastException(obj->clazz, clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_INSTANCE_OF.cpp */
+HANDLE_OPCODE(OP_INSTANCE_OF /*vA, vB, class@CCCC*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);   /* object to check */
+        ref = FETCH(1);         /* class to check against */
+        ILOGV("|instance-of v%d,v%d,class@0x%04x", vdst, vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj == NULL) {
+            SET_REGISTER(vdst, 0);
+        } else {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNullExportPC(obj, fp, pc))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                EXPORT_PC();
+                clazz = dvmResolveClass(curMethod->clazz, ref, true);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+        }
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_ARRAY_LENGTH.cpp */
+HANDLE_OPCODE(OP_ARRAY_LENGTH /*vA, vB*/)
+    {
+        ArrayObject* arrayObj;
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        ILOGV("|array-length v%d,v%d  (%p)", vdst, vsrc1, arrayObj);
+        if (!checkForNullExportPC((Object*) arrayObj, fp, pc))
+            GOTO_exceptionThrown();
+        /* verifier guarantees this is an array reference */
+        SET_REGISTER(vdst, arrayObj->length);
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_NEW_INSTANCE.cpp */
+HANDLE_OPCODE(OP_NEW_INSTANCE /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+        Object* newObj;
+
+        EXPORT_PC();
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|new-instance v%d,class@0x%04x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            clazz = dvmResolveClass(curMethod->clazz, ref, false);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
+            GOTO_exceptionThrown();
+
+#if defined(WITH_JIT)
+        /*
+         * The JIT needs dvmDexGetResolvedClass() to return non-null.
+         * Since we use the portable interpreter to build the trace, this extra
+         * check is not needed for mterp.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (!dvmDexGetResolvedClass(methodClassDex, ref))) {
+            /* Class initialization is still ongoing - end the trace */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+
+        /*
+         * Verifier now tests for interface/abstract class.
+         */
+        //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+        //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
+        //        clazz->descriptor);
+        //    GOTO_exceptionThrown();
+        //}
+        newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+        if (newObj == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newObj);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_NEW_ARRAY.cpp */
+HANDLE_OPCODE(OP_NEW_ARRAY /*vA, vB, class@CCCC*/)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        s4 length;
+
+        EXPORT_PC();
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);       /* length reg */
+        ref = FETCH(1);
+        ILOGV("|new-array v%d,v%d,class@0x%04x  (%d elements)",
+            vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
+        length = (s4) GET_REGISTER(vsrc1);
+        if (length < 0) {
+            dvmThrowNegativeArraySizeException(length);
+            GOTO_exceptionThrown();
+        }
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newArray);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_FILLED_NEW_ARRAY.cpp */
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
+    GOTO_invoke(filledNewArray, false, false);
+OP_END
+
+/* File: c/OP_FILLED_NEW_ARRAY_RANGE.cpp */
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_RANGE /*{vCCCC..v(CCCC+AA-1)}, class@BBBB*/)
+    GOTO_invoke(filledNewArray, true, false);
+OP_END
+
+/* File: c/OP_FILL_ARRAY_DATA.cpp */
+HANDLE_OPCODE(OP_FILL_ARRAY_DATA)   /*vAA, +BBBBBBBB*/
+    {
+        const u2* arrayData;
+        s4 offset;
+        ArrayObject* arrayObj;
+
+        EXPORT_PC();
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|fill-array-data v%d +0x%04x", vsrc1, offset);
+        arrayData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (arrayData < curMethod->insns ||
+            arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            dvmThrowInternalError("bad fill array data");
+            GOTO_exceptionThrown();
+        }
+#endif
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        if (!dvmInterpHandleFillArrayData(arrayObj, arrayData)) {
+            GOTO_exceptionThrown();
+        }
+        FINISH(3);
+    }
+OP_END
+
+/* File: c/OP_THROW.cpp */
+HANDLE_OPCODE(OP_THROW /*vAA*/)
+    {
+        Object* obj;
+
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
+        obj = (Object*) GET_REGISTER(vsrc1);
+        if (!checkForNull(obj)) {
+            /* will throw a null pointer exception */
+            LOGVV("Bad exception");
+        } else {
+            /* use the requested exception */
+            dvmSetException(self, obj);
+        }
+        GOTO_exceptionThrown();
+    }
+OP_END
+
+/* File: c/OP_GOTO.cpp */
+HANDLE_OPCODE(OP_GOTO /*+AA*/)
+    vdst = INST_AA(inst);
+    if ((s1)vdst < 0)
+        ILOGV("|goto -0x%02x", -((s1)vdst));
+    else
+        ILOGV("|goto +0x%02x", ((s1)vdst));
+    ILOGV("> branch taken");
+    if ((s1)vdst < 0)
+        PERIODIC_CHECKS((s1)vdst);
+    FINISH((s1)vdst);
+OP_END
+
+/* File: c/OP_GOTO_16.cpp */
+HANDLE_OPCODE(OP_GOTO_16 /*+AAAA*/)
+    {
+        s4 offset = (s2) FETCH(1);          /* sign-extend next code unit */
+
+        if (offset < 0)
+            ILOGV("|goto/16 -0x%04x", -offset);
+        else
+            ILOGV("|goto/16 +0x%04x", offset);
+        ILOGV("> branch taken");
+        if (offset < 0)
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_GOTO_32.cpp */
+HANDLE_OPCODE(OP_GOTO_32 /*+AAAAAAAA*/)
+    {
+        s4 offset = FETCH(1);               /* low-order 16 bits */
+        offset |= ((s4) FETCH(2)) << 16;    /* high-order 16 bits */
+
+        if (offset < 0)
+            ILOGV("|goto/32 -0x%08x", -offset);
+        else
+            ILOGV("|goto/32 +0x%08x", offset);
+        ILOGV("> branch taken");
+        if (offset <= 0)    /* allowed to branch to self */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_PACKED_SWITCH.cpp */
+HANDLE_OPCODE(OP_PACKED_SWITCH /*vAA, +BBBB*/)
+    {
+        const u2* switchData;
+        u4 testVal;
+        s4 offset;
+
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
+        switchData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (switchData < curMethod->insns ||
+            switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            EXPORT_PC();
+            dvmThrowInternalError("bad packed switch");
+            GOTO_exceptionThrown();
+        }
+#endif
+        testVal = GET_REGISTER(vsrc1);
+
+        offset = dvmInterpHandlePackedSwitch(switchData, testVal);
+        ILOGV("> branch taken (0x%04x)", offset);
+        if (offset <= 0)  /* uncommon */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_SPARSE_SWITCH.cpp */
+HANDLE_OPCODE(OP_SPARSE_SWITCH /*vAA, +BBBB*/)
+    {
+        const u2* switchData;
+        u4 testVal;
+        s4 offset;
+
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
+        switchData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (switchData < curMethod->insns ||
+            switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            EXPORT_PC();
+            dvmThrowInternalError("bad sparse switch");
+            GOTO_exceptionThrown();
+        }
+#endif
+        testVal = GET_REGISTER(vsrc1);
+
+        offset = dvmInterpHandleSparseSwitch(switchData, testVal);
+        ILOGV("> branch taken (0x%04x)", offset);
+        if (offset <= 0)  /* uncommon */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_CMPL_FLOAT.cpp */
+HANDLE_OP_CMPX(OP_CMPL_FLOAT, "l-float", float, _FLOAT, -1)
+OP_END
+
+/* File: c/OP_CMPG_FLOAT.cpp */
+HANDLE_OP_CMPX(OP_CMPG_FLOAT, "g-float", float, _FLOAT, 1)
+OP_END
+
+/* File: c/OP_CMPL_DOUBLE.cpp */
+HANDLE_OP_CMPX(OP_CMPL_DOUBLE, "l-double", double, _DOUBLE, -1)
+OP_END
+
+/* File: c/OP_CMPG_DOUBLE.cpp */
+HANDLE_OP_CMPX(OP_CMPG_DOUBLE, "g-double", double, _DOUBLE, 1)
+OP_END
+
+/* File: c/OP_CMP_LONG.cpp */
+HANDLE_OP_CMPX(OP_CMP_LONG, "-long", s8, _WIDE, 0)
+OP_END
+
+/* File: c/OP_IF_EQ.cpp */
+HANDLE_OP_IF_XX(OP_IF_EQ, "eq", ==)
+OP_END
+
+/* File: c/OP_IF_NE.cpp */
+HANDLE_OP_IF_XX(OP_IF_NE, "ne", !=)
+OP_END
+
+/* File: c/OP_IF_LT.cpp */
+HANDLE_OP_IF_XX(OP_IF_LT, "lt", <)
+OP_END
+
+/* File: c/OP_IF_GE.cpp */
+HANDLE_OP_IF_XX(OP_IF_GE, "ge", >=)
+OP_END
+
+/* File: c/OP_IF_GT.cpp */
+HANDLE_OP_IF_XX(OP_IF_GT, "gt", >)
+OP_END
+
+/* File: c/OP_IF_LE.cpp */
+HANDLE_OP_IF_XX(OP_IF_LE, "le", <=)
+OP_END
+
+/* File: c/OP_IF_EQZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_EQZ, "eqz", ==)
+OP_END
+
+/* File: c/OP_IF_NEZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_NEZ, "nez", !=)
+OP_END
+
+/* File: c/OP_IF_LTZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_LTZ, "ltz", <)
+OP_END
+
+/* File: c/OP_IF_GEZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_GEZ, "gez", >=)
+OP_END
+
+/* File: c/OP_IF_GTZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_GTZ, "gtz", >)
+OP_END
+
+/* File: c/OP_IF_LEZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_LEZ, "lez", <=)
+OP_END
+
+/* File: c/OP_UNUSED_3E.cpp */
+HANDLE_OPCODE(OP_UNUSED_3E)
+OP_END
+
+/* File: c/OP_UNUSED_3F.cpp */
+HANDLE_OPCODE(OP_UNUSED_3F)
+OP_END
+
+/* File: c/OP_UNUSED_40.cpp */
+HANDLE_OPCODE(OP_UNUSED_40)
+OP_END
+
+/* File: c/OP_UNUSED_41.cpp */
+HANDLE_OPCODE(OP_UNUSED_41)
+OP_END
+
+/* File: c/OP_UNUSED_42.cpp */
+HANDLE_OPCODE(OP_UNUSED_42)
+OP_END
+
+/* File: c/OP_UNUSED_43.cpp */
+HANDLE_OPCODE(OP_UNUSED_43)
+OP_END
+
+/* File: c/OP_AGET.cpp */
+HANDLE_OP_AGET(OP_AGET, "", u4, )
+OP_END
+
+/* File: c/OP_AGET_WIDE.cpp */
+HANDLE_OP_AGET(OP_AGET_WIDE, "-wide", s8, _WIDE)
+OP_END
+
+/* File: c/OP_AGET_OBJECT.cpp */
+HANDLE_OP_AGET(OP_AGET_OBJECT, "-object", u4, )
+OP_END
+
+/* File: c/OP_AGET_BOOLEAN.cpp */
+HANDLE_OP_AGET(OP_AGET_BOOLEAN, "-boolean", u1, )
+OP_END
+
+/* File: c/OP_AGET_BYTE.cpp */
+HANDLE_OP_AGET(OP_AGET_BYTE, "-byte", s1, )
+OP_END
+
+/* File: c/OP_AGET_CHAR.cpp */
+HANDLE_OP_AGET(OP_AGET_CHAR, "-char", u2, )
+OP_END
+
+/* File: c/OP_AGET_SHORT.cpp */
+HANDLE_OP_AGET(OP_AGET_SHORT, "-short", s2, )
+OP_END
+
+/* File: c/OP_APUT.cpp */
+HANDLE_OP_APUT(OP_APUT, "", u4, )
+OP_END
+
+/* File: c/OP_APUT_WIDE.cpp */
+HANDLE_OP_APUT(OP_APUT_WIDE, "-wide", s8, _WIDE)
+OP_END
+
+/* File: c/OP_APUT_OBJECT.cpp */
+HANDLE_OPCODE(OP_APUT_OBJECT /*vAA, vBB, vCC*/)
+    {
+        ArrayObject* arrayObj;
+        Object* obj;
+        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", "-object", vdst, vsrc1, vsrc2);
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        if (!checkForNull((Object*) arrayObj))
+            GOTO_exceptionThrown();
+        if (GET_REGISTER(vsrc2) >= arrayObj->length) {
+            dvmThrowArrayIndexOutOfBoundsException(
+                arrayObj->length, GET_REGISTER(vsrc2));
+            GOTO_exceptionThrown();
+        }
+        obj = (Object*) GET_REGISTER(vdst);
+        if (obj != NULL) {
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+            if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
+                LOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
+                    obj->clazz->descriptor, obj,
+                    arrayObj->obj.clazz->descriptor, arrayObj);
+                dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_APUT_BOOLEAN.cpp */
+HANDLE_OP_APUT(OP_APUT_BOOLEAN, "-boolean", u1, )
+OP_END
+
+/* File: c/OP_APUT_BYTE.cpp */
+HANDLE_OP_APUT(OP_APUT_BYTE, "-byte", s1, )
+OP_END
+
+/* File: c/OP_APUT_CHAR.cpp */
+HANDLE_OP_APUT(OP_APUT_CHAR, "-char", u2, )
+OP_END
+
+/* File: c/OP_APUT_SHORT.cpp */
+HANDLE_OP_APUT(OP_APUT_SHORT, "-short", s2, )
+OP_END
+
+/* File: c/OP_IGET.cpp */
+HANDLE_IGET_X(OP_IGET,                  "", Int, )
+OP_END
+
+/* File: c/OP_IGET_WIDE.cpp */
+HANDLE_IGET_X(OP_IGET_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT.cpp */
+HANDLE_IGET_X(OP_IGET_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_BOOLEAN.cpp */
+HANDLE_IGET_X(OP_IGET_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_IGET_BYTE.cpp */
+HANDLE_IGET_X(OP_IGET_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_IGET_CHAR.cpp */
+HANDLE_IGET_X(OP_IGET_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_IGET_SHORT.cpp */
+HANDLE_IGET_X(OP_IGET_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_IPUT.cpp */
+HANDLE_IPUT_X(OP_IPUT,                  "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE.cpp */
+HANDLE_IPUT_X(OP_IPUT_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT.cpp */
+/*
+ * The VM spec says we should verify that the reference being stored into
+ * the field is assignment compatible.  In practice, many popular VMs don't
+ * do this because it slows down a very common operation.  It's not so bad
+ * for us, since "dexopt" quickens it whenever possible, but it's still an
+ * issue.
+ *
+ * To make this spec-complaint, we'd need to add a ClassObject pointer to
+ * the Field struct, resolve the field's type descriptor at link or class
+ * init time, and then verify the type here.
+ */
+HANDLE_IPUT_X(OP_IPUT_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_BOOLEAN.cpp */
+HANDLE_IPUT_X(OP_IPUT_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_BYTE.cpp */
+HANDLE_IPUT_X(OP_IPUT_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_CHAR.cpp */
+HANDLE_IPUT_X(OP_IPUT_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_SHORT.cpp */
+HANDLE_IPUT_X(OP_IPUT_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_SGET.cpp */
+HANDLE_SGET_X(OP_SGET,                  "", Int, )
+OP_END
+
+/* File: c/OP_SGET_WIDE.cpp */
+HANDLE_SGET_X(OP_SGET_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT.cpp */
+HANDLE_SGET_X(OP_SGET_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_BOOLEAN.cpp */
+HANDLE_SGET_X(OP_SGET_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_SGET_BYTE.cpp */
+HANDLE_SGET_X(OP_SGET_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_SGET_CHAR.cpp */
+HANDLE_SGET_X(OP_SGET_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_SGET_SHORT.cpp */
+HANDLE_SGET_X(OP_SGET_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_SPUT.cpp */
+HANDLE_SPUT_X(OP_SPUT,                  "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE.cpp */
+HANDLE_SPUT_X(OP_SPUT_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT.cpp */
+HANDLE_SPUT_X(OP_SPUT_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_BOOLEAN.cpp */
+HANDLE_SPUT_X(OP_SPUT_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_BYTE.cpp */
+HANDLE_SPUT_X(OP_SPUT_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_CHAR.cpp */
+HANDLE_SPUT_X(OP_SPUT_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_SHORT.cpp */
+HANDLE_SPUT_X(OP_SPUT_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeVirtual, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeSuper, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_DIRECT.cpp */
+HANDLE_OPCODE(OP_INVOKE_DIRECT /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeDirect, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_STATIC.cpp */
+HANDLE_OPCODE(OP_INVOKE_STATIC /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeStatic, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_INTERFACE.cpp */
+HANDLE_OPCODE(OP_INVOKE_INTERFACE /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeInterface, false, false);
+OP_END
+
+/* File: c/OP_UNUSED_73.cpp */
+HANDLE_OPCODE(OP_UNUSED_73)
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeVirtual, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeSuper, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_DIRECT_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_DIRECT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeDirect, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_STATIC_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_STATIC_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeStatic, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_INTERFACE_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_INTERFACE_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeInterface, true, false);
+OP_END
+
+/* File: c/OP_UNUSED_79.cpp */
+HANDLE_OPCODE(OP_UNUSED_79)
+OP_END
+
+/* File: c/OP_UNUSED_7A.cpp */
+HANDLE_OPCODE(OP_UNUSED_7A)
+OP_END
+
+/* File: c/OP_NEG_INT.cpp */
+HANDLE_UNOP(OP_NEG_INT, "neg-int", -, , )
+OP_END
+
+/* File: c/OP_NOT_INT.cpp */
+HANDLE_UNOP(OP_NOT_INT, "not-int", , ^ 0xffffffff, )
+OP_END
+
+/* File: c/OP_NEG_LONG.cpp */
+HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
+OP_END
+
+/* File: c/OP_NOT_LONG.cpp */
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
+OP_END
+
+/* File: c/OP_NEG_FLOAT.cpp */
+HANDLE_UNOP(OP_NEG_FLOAT, "neg-float", -, , _FLOAT)
+OP_END
+
+/* File: c/OP_NEG_DOUBLE.cpp */
+HANDLE_UNOP(OP_NEG_DOUBLE, "neg-double", -, , _DOUBLE)
+OP_END
+
+/* File: c/OP_INT_TO_LONG.cpp */
+HANDLE_NUMCONV(OP_INT_TO_LONG,          "int-to-long", _INT, _WIDE)
+OP_END
+
+/* File: c/OP_INT_TO_FLOAT.cpp */
+HANDLE_NUMCONV(OP_INT_TO_FLOAT,         "int-to-float", _INT, _FLOAT)
+OP_END
+
+/* File: c/OP_INT_TO_DOUBLE.cpp */
+HANDLE_NUMCONV(OP_INT_TO_DOUBLE,        "int-to-double", _INT, _DOUBLE)
+OP_END
+
+/* File: c/OP_LONG_TO_INT.cpp */
+HANDLE_NUMCONV(OP_LONG_TO_INT,          "long-to-int", _WIDE, _INT)
+OP_END
+
+/* File: c/OP_LONG_TO_FLOAT.cpp */
+HANDLE_NUMCONV(OP_LONG_TO_FLOAT,        "long-to-float", _WIDE, _FLOAT)
+OP_END
+
+/* File: c/OP_LONG_TO_DOUBLE.cpp */
+HANDLE_NUMCONV(OP_LONG_TO_DOUBLE,       "long-to-double", _WIDE, _DOUBLE)
+OP_END
+
+/* File: c/OP_FLOAT_TO_INT.cpp */
+HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_INT,    "float-to-int",
+    float, _FLOAT, s4, _INT)
+OP_END
+
+/* File: c/OP_FLOAT_TO_LONG.cpp */
+HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_LONG,   "float-to-long",
+    float, _FLOAT, s8, _WIDE)
+OP_END
+
+/* File: c/OP_FLOAT_TO_DOUBLE.cpp */
+HANDLE_NUMCONV(OP_FLOAT_TO_DOUBLE,      "float-to-double", _FLOAT, _DOUBLE)
+OP_END
+
+/* File: c/OP_DOUBLE_TO_INT.cpp */
+HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_INT,   "double-to-int",
+    double, _DOUBLE, s4, _INT)
+OP_END
+
+/* File: c/OP_DOUBLE_TO_LONG.cpp */
+HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_LONG,  "double-to-long",
+    double, _DOUBLE, s8, _WIDE)
+OP_END
+
+/* File: c/OP_DOUBLE_TO_FLOAT.cpp */
+HANDLE_NUMCONV(OP_DOUBLE_TO_FLOAT,      "double-to-float", _DOUBLE, _FLOAT)
+OP_END
+
+/* File: c/OP_INT_TO_BYTE.cpp */
+HANDLE_INT_TO_SMALL(OP_INT_TO_BYTE,     "byte", s1)
+OP_END
+
+/* File: c/OP_INT_TO_CHAR.cpp */
+HANDLE_INT_TO_SMALL(OP_INT_TO_CHAR,     "char", u2)
+OP_END
+
+/* File: c/OP_INT_TO_SHORT.cpp */
+HANDLE_INT_TO_SMALL(OP_INT_TO_SHORT,    "short", s2)    /* want sign bit */
+OP_END
+
+/* File: c/OP_ADD_INT.cpp */
+HANDLE_OP_X_INT(OP_ADD_INT, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_INT.cpp */
+HANDLE_OP_X_INT(OP_SUB_INT, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_INT.cpp */
+HANDLE_OP_X_INT(OP_MUL_INT, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT.cpp */
+HANDLE_OP_X_INT(OP_DIV_INT, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT.cpp */
+HANDLE_OP_X_INT(OP_REM_INT, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT.cpp */
+HANDLE_OP_X_INT(OP_AND_INT, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT.cpp */
+HANDLE_OP_X_INT(OP_OR_INT,  "or",  |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT.cpp */
+HANDLE_OP_X_INT(OP_XOR_INT, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_INT.cpp */
+HANDLE_OP_SHX_INT(OP_SHL_INT, "shl", (s4), <<)
+OP_END
+
+/* File: c/OP_SHR_INT.cpp */
+HANDLE_OP_SHX_INT(OP_SHR_INT, "shr", (s4), >>)
+OP_END
+
+/* File: c/OP_USHR_INT.cpp */
+HANDLE_OP_SHX_INT(OP_USHR_INT, "ushr", (u4), >>)
+OP_END
+
+/* File: c/OP_ADD_LONG.cpp */
+HANDLE_OP_X_LONG(OP_ADD_LONG, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_LONG.cpp */
+HANDLE_OP_X_LONG(OP_SUB_LONG, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_LONG.cpp */
+HANDLE_OP_X_LONG(OP_MUL_LONG, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_LONG.cpp */
+HANDLE_OP_X_LONG(OP_DIV_LONG, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_LONG.cpp */
+HANDLE_OP_X_LONG(OP_REM_LONG, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_LONG.cpp */
+HANDLE_OP_X_LONG(OP_AND_LONG, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_LONG.cpp */
+HANDLE_OP_X_LONG(OP_OR_LONG,  "or", |, 0)
+OP_END
+
+/* File: c/OP_XOR_LONG.cpp */
+HANDLE_OP_X_LONG(OP_XOR_LONG, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_LONG.cpp */
+HANDLE_OP_SHX_LONG(OP_SHL_LONG, "shl", (s8), <<)
+OP_END
+
+/* File: c/OP_SHR_LONG.cpp */
+HANDLE_OP_SHX_LONG(OP_SHR_LONG, "shr", (s8), >>)
+OP_END
+
+/* File: c/OP_USHR_LONG.cpp */
+HANDLE_OP_SHX_LONG(OP_USHR_LONG, "ushr", (u8), >>)
+OP_END
+
+/* File: c/OP_ADD_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_ADD_FLOAT, "add", +)
+OP_END
+
+/* File: c/OP_SUB_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_SUB_FLOAT, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_MUL_FLOAT, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_DIV_FLOAT, "div", /)
+OP_END
+
+/* File: c/OP_REM_FLOAT.cpp */
+HANDLE_OPCODE(OP_REM_FLOAT /*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", "mod", vdst, vsrc1, vsrc2);
+        SET_REGISTER_FLOAT(vdst,
+            fmodf(GET_REGISTER_FLOAT(vsrc1), GET_REGISTER_FLOAT(vsrc2)));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_ADD_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_ADD_DOUBLE, "add", +)
+OP_END
+
+/* File: c/OP_SUB_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_SUB_DOUBLE, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_MUL_DOUBLE, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_DIV_DOUBLE, "div", /)
+OP_END
+
+/* File: c/OP_REM_DOUBLE.cpp */
+HANDLE_OPCODE(OP_REM_DOUBLE /*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", "mod", vdst, vsrc1, vsrc2);
+        SET_REGISTER_DOUBLE(vdst,
+            fmod(GET_REGISTER_DOUBLE(vsrc1), GET_REGISTER_DOUBLE(vsrc2)));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_ADD_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_ADD_INT_2ADDR, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_SUB_INT_2ADDR, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_MUL_INT_2ADDR, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_DIV_INT_2ADDR, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_REM_INT_2ADDR, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_AND_INT_2ADDR, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_OR_INT_2ADDR,  "or", |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_XOR_INT_2ADDR, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_INT_2ADDR.cpp */
+HANDLE_OP_SHX_INT_2ADDR(OP_SHL_INT_2ADDR, "shl", (s4), <<)
+OP_END
+
+/* File: c/OP_SHR_INT_2ADDR.cpp */
+HANDLE_OP_SHX_INT_2ADDR(OP_SHR_INT_2ADDR, "shr", (s4), >>)
+OP_END
+
+/* File: c/OP_USHR_INT_2ADDR.cpp */
+HANDLE_OP_SHX_INT_2ADDR(OP_USHR_INT_2ADDR, "ushr", (u4), >>)
+OP_END
+
+/* File: c/OP_ADD_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_ADD_LONG_2ADDR, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_SUB_LONG_2ADDR, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_MUL_LONG_2ADDR, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_DIV_LONG_2ADDR, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_REM_LONG_2ADDR, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_AND_LONG_2ADDR, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_OR_LONG_2ADDR,  "or", |, 0)
+OP_END
+
+/* File: c/OP_XOR_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_XOR_LONG_2ADDR, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_LONG_2ADDR.cpp */
+HANDLE_OP_SHX_LONG_2ADDR(OP_SHL_LONG_2ADDR, "shl", (s8), <<)
+OP_END
+
+/* File: c/OP_SHR_LONG_2ADDR.cpp */
+HANDLE_OP_SHX_LONG_2ADDR(OP_SHR_LONG_2ADDR, "shr", (s8), >>)
+OP_END
+
+/* File: c/OP_USHR_LONG_2ADDR.cpp */
+HANDLE_OP_SHX_LONG_2ADDR(OP_USHR_LONG_2ADDR, "ushr", (u8), >>)
+OP_END
+
+/* File: c/OP_ADD_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_ADD_FLOAT_2ADDR, "add", +)
+OP_END
+
+/* File: c/OP_SUB_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_SUB_FLOAT_2ADDR, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_MUL_FLOAT_2ADDR, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_DIV_FLOAT_2ADDR, "div", /)
+OP_END
+
+/* File: c/OP_REM_FLOAT_2ADDR.cpp */
+HANDLE_OPCODE(OP_REM_FLOAT_2ADDR /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|%s-float-2addr v%d,v%d", "mod", vdst, vsrc1);
+    SET_REGISTER_FLOAT(vdst,
+        fmodf(GET_REGISTER_FLOAT(vdst), GET_REGISTER_FLOAT(vsrc1)));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_ADD_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_ADD_DOUBLE_2ADDR, "add", +)
+OP_END
+
+/* File: c/OP_SUB_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_SUB_DOUBLE_2ADDR, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_MUL_DOUBLE_2ADDR, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_DIV_DOUBLE_2ADDR, "div", /)
+OP_END
+
+/* File: c/OP_REM_DOUBLE_2ADDR.cpp */
+HANDLE_OPCODE(OP_REM_DOUBLE_2ADDR /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|%s-double-2addr v%d,v%d", "mod", vdst, vsrc1);
+    SET_REGISTER_DOUBLE(vdst,
+        fmod(GET_REGISTER_DOUBLE(vdst), GET_REGISTER_DOUBLE(vsrc1)));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_ADD_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_ADD_INT_LIT16, "add", +, 0)
+OP_END
+
+/* File: c/OP_RSUB_INT.cpp */
+HANDLE_OPCODE(OP_RSUB_INT /*vA, vB, #+CCCC*/)
+    {
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);
+        vsrc2 = FETCH(1);
+        ILOGV("|rsub-int v%d,v%d,#+0x%04x", vdst, vsrc1, vsrc2);
+        SET_REGISTER(vdst, (s2) vsrc2 - (s4) GET_REGISTER(vsrc1));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MUL_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_MUL_INT_LIT16, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_DIV_INT_LIT16, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_REM_INT_LIT16, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_AND_INT_LIT16, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_OR_INT_LIT16,  "or",  |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_XOR_INT_LIT16, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_ADD_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_ADD_INT_LIT8,   "add", +, 0)
+OP_END
+
+/* File: c/OP_RSUB_INT_LIT8.cpp */
+HANDLE_OPCODE(OP_RSUB_INT_LIT8 /*vAA, vBB, #+CC*/)
+    {
+        u2 litInfo;
+        vdst = INST_AA(inst);
+        litInfo = FETCH(1);
+        vsrc1 = litInfo & 0xff;
+        vsrc2 = litInfo >> 8;
+        ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", "rsub", vdst, vsrc1, vsrc2);
+        SET_REGISTER(vdst, (s1) vsrc2 - (s4) GET_REGISTER(vsrc1));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MUL_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_MUL_INT_LIT8,   "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_DIV_INT_LIT8,   "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_REM_INT_LIT8,   "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_AND_INT_LIT8,   "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_OR_INT_LIT8,    "or",  |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_XOR_INT_LIT8,   "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_INT_LIT8.cpp */
+HANDLE_OP_SHX_INT_LIT8(OP_SHL_INT_LIT8,   "shl", (s4), <<)
+OP_END
+
+/* File: c/OP_SHR_INT_LIT8.cpp */
+HANDLE_OP_SHX_INT_LIT8(OP_SHR_INT_LIT8,   "shr", (s4), >>)
+OP_END
+
+/* File: c/OP_USHR_INT_LIT8.cpp */
+HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8,  "ushr", (u4), >>)
+OP_END
+
+/* File: c/OP_IGET_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_BREAKPOINT.cpp */
+HANDLE_OPCODE(OP_BREAKPOINT)
+    {
+        /*
+         * Restart this instruction with the original opcode.  We do
+         * this by simply jumping to the handler.
+         *
+         * It's probably not necessary to update "inst", but we do it
+         * for the sake of anything that needs to do disambiguation in a
+         * common handler with INST_INST.
+         *
+         * The breakpoint itself is handled over in updateDebugger(),
+         * because we need to detect other events (method entry, single
+         * step) and report them in the same event packet, and we're not
+         * yet handling those through breakpoint instructions.  By the
+         * time we get here, the breakpoint has already been handled and
+         * the thread resumed.
+         */
+        u1 originalOpcode = dvmGetOriginalOpcode(pc);
+        LOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
+            INST_REPLACE_OP(inst, originalOpcode));
+        inst = INST_REPLACE_OP(inst, originalOpcode);
+        FINISH_BKPT(originalOpcode);
+    }
+OP_END
+
+/* File: c/OP_THROW_VERIFICATION_ERROR.cpp */
+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.cpp */
+HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/)
+    {
+        /*
+         * This has the same form as other method calls, but we ignore
+         * the 5th argument (vA).  This is chiefly because the first four
+         * arguments to a function on ARM are in registers.
+         *
+         * We only set the arguments that are actually used, leaving
+         * the rest uninitialized.  We're assuming that, if the method
+         * needs them, they'll be specified in the call.
+         *
+         * However, this annoys gcc when optimizations are enabled,
+         * causing a "may be used uninitialized" warning.  Quieting
+         * the warnings incurs a slight penalty (5%: 373ns vs. 393ns
+         * on empty method).  Note that valgrind is perfectly happy
+         * either way as the uninitialiezd values are never actually
+         * used.
+         */
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_B(inst);       /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* 0-4 register indices */
+        ILOGV("|execute-inline args=%d @%d {regs=0x%04x}",
+            vsrc1, ref, vdst);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst >> 12);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER((vdst & 0x0f00) >> 8);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER((vdst & 0x00f0) >> 4);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst & 0x0f);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_EXECUTE_INLINE_RANGE.cpp */
+HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
+    {
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;      /* placate gcc */
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* range base */
+        ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst+3);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER(vdst+2);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER(vdst+1);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst+0);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(2);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, false);
+        }
+        FINISH(3);
+    }
+OP_END
+
+/* File: c/OP_RETURN_VOID_BARRIER.cpp */
+HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;   /* placate valgrind */
+#endif
+    ANDROID_MEMBAR_STORE();
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_IGET_QUICK.cpp */
+HANDLE_IGET_X_QUICK(OP_IGET_QUICK,          "", Int, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_QUICK.cpp */
+HANDLE_IGET_X_QUICK(OP_IGET_WIDE_QUICK,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_QUICK.cpp */
+HANDLE_IGET_X_QUICK(OP_IGET_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_QUICK.cpp */
+HANDLE_IPUT_X_QUICK(OP_IPUT_QUICK,          "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_QUICK.cpp */
+HANDLE_IPUT_X_QUICK(OP_IPUT_WIDE_QUICK,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_QUICK.cpp */
+HANDLE_IPUT_X_QUICK(OP_IPUT_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_QUICK.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeVirtualQuick, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_QUICK_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK_RANGE/*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeVirtualQuick, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_QUICK.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeSuperQuick, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_QUICK_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeSuperQuick, true, false);
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_DISPATCH_FF.cpp */
+HANDLE_OPCODE(OP_DISPATCH_FF)
+    /*
+     * Indicates extended opcode.  Use next 8 bits to choose where to branch.
+     */
+    DISPATCH_EXTENDED(INST_AA(inst));
+OP_END
+
+/* File: c/OP_CONST_CLASS_JUMBO.cpp */
+HANDLE_OPCODE(OP_CONST_CLASS_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        ILOGV("|const-class/jumbo v%d class@0x%08x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            EXPORT_PC();
+            clazz = dvmResolveClass(curMethod->clazz, ref, true);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) clazz);
+    }
+    FINISH(4);
+OP_END
+
+/* File: c/OP_CHECK_CAST_JUMBO.cpp */
+HANDLE_OPCODE(OP_CHECK_CAST_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;     /* class to check against */
+        vsrc1 = FETCH(3);
+        ILOGV("|check-cast/jumbo v%d,class@0x%08x", vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj != NULL) {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                clazz = dvmResolveClass(curMethod->clazz, ref, false);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            if (!dvmInstanceof(obj->clazz, clazz)) {
+                dvmThrowClassCastException(obj->clazz, clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+    }
+    FINISH(4);
+OP_END
+
+/* File: c/OP_INSTANCE_OF_JUMBO.cpp */
+HANDLE_OPCODE(OP_INSTANCE_OF_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;     /* class to check against */
+        vdst = FETCH(3);
+        vsrc1 = FETCH(4);   /* object to check */
+        ILOGV("|instance-of/jumbo v%d,v%d,class@0x%08x", vdst, vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj == NULL) {
+            SET_REGISTER(vdst, 0);
+        } else {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNullExportPC(obj, fp, pc))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                EXPORT_PC();
+                clazz = dvmResolveClass(curMethod->clazz, ref, true);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+        }
+    }
+    FINISH(5);
+OP_END
+
+/* File: c/OP_NEW_INSTANCE_JUMBO.cpp */
+HANDLE_OPCODE(OP_NEW_INSTANCE_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* newObj;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        ILOGV("|new-instance/jumbo v%d,class@0x%08x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            clazz = dvmResolveClass(curMethod->clazz, ref, false);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
+            GOTO_exceptionThrown();
+
+#if defined(WITH_JIT)
+        /*
+         * The JIT needs dvmDexGetResolvedClass() to return non-null.
+         * Since we use the portable interpreter to build the trace, this extra
+         * check is not needed for mterp.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (!dvmDexGetResolvedClass(methodClassDex, ref))) {
+            /* Class initialization is still ongoing - end the trace */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+
+        /*
+         * Verifier now tests for interface/abstract class.
+         */
+        //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+        //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
+        //        clazz->descriptor);
+        //    GOTO_exceptionThrown();
+        //}
+        newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+        if (newObj == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newObj);
+    }
+    FINISH(4);
+OP_END
+
+/* File: c/OP_NEW_ARRAY_JUMBO.cpp */
+HANDLE_OPCODE(OP_NEW_ARRAY_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        s4 length;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        vsrc1 = FETCH(4);       /* length reg */
+        ILOGV("|new-array/jumbo v%d,v%d,class@0x%08x  (%d elements)",
+            vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
+        length = (s4) GET_REGISTER(vsrc1);
+        if (length < 0) {
+            dvmThrowNegativeArraySizeException(length);
+            GOTO_exceptionThrown();
+        }
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newArray);
+    }
+    FINISH(5);
+OP_END
+
+/* File: c/OP_FILLED_NEW_ARRAY_JUMBO.cpp */
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, class@AAAAAAAA*/)
+    GOTO_invoke(filledNewArray, true, true);
+OP_END
+
+/* File: c/OP_IGET_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_BOOLEAN_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_BOOLEAN_JUMBO,  "", Int, )
+OP_END
+
+/* File: c/OP_IGET_BYTE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IGET_CHAR_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IGET_SHORT_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_JUMBO.cpp */
+/*
+ * The VM spec says we should verify that the reference being stored into
+ * the field is assignment compatible.  In practice, many popular VMs don't
+ * do this because it slows down a very common operation.  It's not so bad
+ * for us, since "dexopt" quickens it whenever possible, but it's still an
+ * issue.
+ *
+ * To make this spec-complaint, we'd need to add a ClassObject pointer to
+ * the Field struct, resolve the field's type descriptor at link or class
+ * init time, and then verify the type here.
+ */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_BOOLEAN_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_BOOLEAN_JUMBO,  "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_BYTE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_CHAR_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_SHORT_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_SGET_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_SGET_WIDE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_BOOLEAN_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_BOOLEAN_JUMBO,  "", Int, )
+OP_END
+
+/* File: c/OP_SGET_BYTE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SGET_CHAR_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SGET_SHORT_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_BOOLEAN_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_BOOLEAN_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_BYTE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_CHAR_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_SHORT_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeVirtual, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeSuper, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_DIRECT_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_DIRECT_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeDirect, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_STATIC_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_STATIC_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeStatic, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_INTERFACE_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_INTERFACE_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeInterface, true, true);
+OP_END
+
+/* File: c/OP_UNUSED_27FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_27FF)
+OP_END
+
+/* File: c/OP_UNUSED_28FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_28FF)
+OP_END
+
+/* File: c/OP_UNUSED_29FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_29FF)
+OP_END
+
+/* File: c/OP_UNUSED_2AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2AFF)
+OP_END
+
+/* File: c/OP_UNUSED_2BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2BFF)
+OP_END
+
+/* File: c/OP_UNUSED_2CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2CFF)
+OP_END
+
+/* File: c/OP_UNUSED_2DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2DFF)
+OP_END
+
+/* File: c/OP_UNUSED_2EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2EFF)
+OP_END
+
+/* File: c/OP_UNUSED_2FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2FFF)
+OP_END
+
+/* File: c/OP_UNUSED_30FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_30FF)
+OP_END
+
+/* File: c/OP_UNUSED_31FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_31FF)
+OP_END
+
+/* File: c/OP_UNUSED_32FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_32FF)
+OP_END
+
+/* File: c/OP_UNUSED_33FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_33FF)
+OP_END
+
+/* File: c/OP_UNUSED_34FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_34FF)
+OP_END
+
+/* File: c/OP_UNUSED_35FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_35FF)
+OP_END
+
+/* File: c/OP_UNUSED_36FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_36FF)
+OP_END
+
+/* File: c/OP_UNUSED_37FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_37FF)
+OP_END
+
+/* File: c/OP_UNUSED_38FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_38FF)
+OP_END
+
+/* File: c/OP_UNUSED_39FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_39FF)
+OP_END
+
+/* File: c/OP_UNUSED_3AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3AFF)
+OP_END
+
+/* File: c/OP_UNUSED_3BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3BFF)
+OP_END
+
+/* File: c/OP_UNUSED_3CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3CFF)
+OP_END
+
+/* File: c/OP_UNUSED_3DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3DFF)
+OP_END
+
+/* File: c/OP_UNUSED_3EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3EFF)
+OP_END
+
+/* File: c/OP_UNUSED_3FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3FFF)
+OP_END
+
+/* File: c/OP_UNUSED_40FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_40FF)
+OP_END
+
+/* File: c/OP_UNUSED_41FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_41FF)
+OP_END
+
+/* File: c/OP_UNUSED_42FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_42FF)
+OP_END
+
+/* File: c/OP_UNUSED_43FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_43FF)
+OP_END
+
+/* File: c/OP_UNUSED_44FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_44FF)
+OP_END
+
+/* File: c/OP_UNUSED_45FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_45FF)
+OP_END
+
+/* File: c/OP_UNUSED_46FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_46FF)
+OP_END
+
+/* File: c/OP_UNUSED_47FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_47FF)
+OP_END
+
+/* File: c/OP_UNUSED_48FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_48FF)
+OP_END
+
+/* File: c/OP_UNUSED_49FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_49FF)
+OP_END
+
+/* File: c/OP_UNUSED_4AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4AFF)
+OP_END
+
+/* File: c/OP_UNUSED_4BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4BFF)
+OP_END
+
+/* File: c/OP_UNUSED_4CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4CFF)
+OP_END
+
+/* File: c/OP_UNUSED_4DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4DFF)
+OP_END
+
+/* File: c/OP_UNUSED_4EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4EFF)
+OP_END
+
+/* File: c/OP_UNUSED_4FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4FFF)
+OP_END
+
+/* File: c/OP_UNUSED_50FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_50FF)
+OP_END
+
+/* File: c/OP_UNUSED_51FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_51FF)
+OP_END
+
+/* File: c/OP_UNUSED_52FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_52FF)
+OP_END
+
+/* File: c/OP_UNUSED_53FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_53FF)
+OP_END
+
+/* File: c/OP_UNUSED_54FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_54FF)
+OP_END
+
+/* File: c/OP_UNUSED_55FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_55FF)
+OP_END
+
+/* File: c/OP_UNUSED_56FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_56FF)
+OP_END
+
+/* File: c/OP_UNUSED_57FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_57FF)
+OP_END
+
+/* File: c/OP_UNUSED_58FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_58FF)
+OP_END
+
+/* File: c/OP_UNUSED_59FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_59FF)
+OP_END
+
+/* File: c/OP_UNUSED_5AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5AFF)
+OP_END
+
+/* File: c/OP_UNUSED_5BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5BFF)
+OP_END
+
+/* File: c/OP_UNUSED_5CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5CFF)
+OP_END
+
+/* File: c/OP_UNUSED_5DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5DFF)
+OP_END
+
+/* File: c/OP_UNUSED_5EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5EFF)
+OP_END
+
+/* File: c/OP_UNUSED_5FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5FFF)
+OP_END
+
+/* File: c/OP_UNUSED_60FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_60FF)
+OP_END
+
+/* File: c/OP_UNUSED_61FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_61FF)
+OP_END
+
+/* File: c/OP_UNUSED_62FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_62FF)
+OP_END
+
+/* File: c/OP_UNUSED_63FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_63FF)
+OP_END
+
+/* File: c/OP_UNUSED_64FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_64FF)
+OP_END
+
+/* File: c/OP_UNUSED_65FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_65FF)
+OP_END
+
+/* File: c/OP_UNUSED_66FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_66FF)
+OP_END
+
+/* File: c/OP_UNUSED_67FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_67FF)
+OP_END
+
+/* File: c/OP_UNUSED_68FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_68FF)
+OP_END
+
+/* File: c/OP_UNUSED_69FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_69FF)
+OP_END
+
+/* File: c/OP_UNUSED_6AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6AFF)
+OP_END
+
+/* File: c/OP_UNUSED_6BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6BFF)
+OP_END
+
+/* File: c/OP_UNUSED_6CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6CFF)
+OP_END
+
+/* File: c/OP_UNUSED_6DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6DFF)
+OP_END
+
+/* File: c/OP_UNUSED_6EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6EFF)
+OP_END
+
+/* File: c/OP_UNUSED_6FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6FFF)
+OP_END
+
+/* File: c/OP_UNUSED_70FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_70FF)
+OP_END
+
+/* File: c/OP_UNUSED_71FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_71FF)
+OP_END
+
+/* File: c/OP_UNUSED_72FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_72FF)
+OP_END
+
+/* File: c/OP_UNUSED_73FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_73FF)
+OP_END
+
+/* File: c/OP_UNUSED_74FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_74FF)
+OP_END
+
+/* File: c/OP_UNUSED_75FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_75FF)
+OP_END
+
+/* File: c/OP_UNUSED_76FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_76FF)
+OP_END
+
+/* File: c/OP_UNUSED_77FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_77FF)
+OP_END
+
+/* File: c/OP_UNUSED_78FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_78FF)
+OP_END
+
+/* File: c/OP_UNUSED_79FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_79FF)
+OP_END
+
+/* File: c/OP_UNUSED_7AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7AFF)
+OP_END
+
+/* File: c/OP_UNUSED_7BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7BFF)
+OP_END
+
+/* File: c/OP_UNUSED_7CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7CFF)
+OP_END
+
+/* File: c/OP_UNUSED_7DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7DFF)
+OP_END
+
+/* File: c/OP_UNUSED_7EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7EFF)
+OP_END
+
+/* File: c/OP_UNUSED_7FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7FFF)
+OP_END
+
+/* File: c/OP_UNUSED_80FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_80FF)
+OP_END
+
+/* File: c/OP_UNUSED_81FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_81FF)
+OP_END
+
+/* File: c/OP_UNUSED_82FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_82FF)
+OP_END
+
+/* File: c/OP_UNUSED_83FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_83FF)
+OP_END
+
+/* File: c/OP_UNUSED_84FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_84FF)
+OP_END
+
+/* File: c/OP_UNUSED_85FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_85FF)
+OP_END
+
+/* File: c/OP_UNUSED_86FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_86FF)
+OP_END
+
+/* File: c/OP_UNUSED_87FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_87FF)
+OP_END
+
+/* File: c/OP_UNUSED_88FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_88FF)
+OP_END
+
+/* File: c/OP_UNUSED_89FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_89FF)
+OP_END
+
+/* File: c/OP_UNUSED_8AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8AFF)
+OP_END
+
+/* File: c/OP_UNUSED_8BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8BFF)
+OP_END
+
+/* File: c/OP_UNUSED_8CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8CFF)
+OP_END
+
+/* File: c/OP_UNUSED_8DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8DFF)
+OP_END
+
+/* File: c/OP_UNUSED_8EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8EFF)
+OP_END
+
+/* File: c/OP_UNUSED_8FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8FFF)
+OP_END
+
+/* File: c/OP_UNUSED_90FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_90FF)
+OP_END
+
+/* File: c/OP_UNUSED_91FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_91FF)
+OP_END
+
+/* File: c/OP_UNUSED_92FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_92FF)
+OP_END
+
+/* File: c/OP_UNUSED_93FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_93FF)
+OP_END
+
+/* File: c/OP_UNUSED_94FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_94FF)
+OP_END
+
+/* File: c/OP_UNUSED_95FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_95FF)
+OP_END
+
+/* File: c/OP_UNUSED_96FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_96FF)
+OP_END
+
+/* File: c/OP_UNUSED_97FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_97FF)
+OP_END
+
+/* File: c/OP_UNUSED_98FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_98FF)
+OP_END
+
+/* File: c/OP_UNUSED_99FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_99FF)
+OP_END
+
+/* File: c/OP_UNUSED_9AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9AFF)
+OP_END
+
+/* File: c/OP_UNUSED_9BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9BFF)
+OP_END
+
+/* File: c/OP_UNUSED_9CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9CFF)
+OP_END
+
+/* File: c/OP_UNUSED_9DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9DFF)
+OP_END
+
+/* File: c/OP_UNUSED_9EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9EFF)
+OP_END
+
+/* File: c/OP_UNUSED_9FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9FFF)
+OP_END
+
+/* File: c/OP_UNUSED_A0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A0FF)
+OP_END
+
+/* File: c/OP_UNUSED_A1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A1FF)
+OP_END
+
+/* File: c/OP_UNUSED_A2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A2FF)
+OP_END
+
+/* File: c/OP_UNUSED_A3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A3FF)
+OP_END
+
+/* File: c/OP_UNUSED_A4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A4FF)
+OP_END
+
+/* File: c/OP_UNUSED_A5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A5FF)
+OP_END
+
+/* File: c/OP_UNUSED_A6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A6FF)
+OP_END
+
+/* File: c/OP_UNUSED_A7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A7FF)
+OP_END
+
+/* File: c/OP_UNUSED_A8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A8FF)
+OP_END
+
+/* File: c/OP_UNUSED_A9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A9FF)
+OP_END
+
+/* File: c/OP_UNUSED_AAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_AAFF)
+OP_END
+
+/* File: c/OP_UNUSED_ABFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ABFF)
+OP_END
+
+/* File: c/OP_UNUSED_ACFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ACFF)
+OP_END
+
+/* File: c/OP_UNUSED_ADFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ADFF)
+OP_END
+
+/* File: c/OP_UNUSED_AEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_AEFF)
+OP_END
+
+/* File: c/OP_UNUSED_AFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_AFFF)
+OP_END
+
+/* File: c/OP_UNUSED_B0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B0FF)
+OP_END
+
+/* File: c/OP_UNUSED_B1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B1FF)
+OP_END
+
+/* File: c/OP_UNUSED_B2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B2FF)
+OP_END
+
+/* File: c/OP_UNUSED_B3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B3FF)
+OP_END
+
+/* File: c/OP_UNUSED_B4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B4FF)
+OP_END
+
+/* File: c/OP_UNUSED_B5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B5FF)
+OP_END
+
+/* File: c/OP_UNUSED_B6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B6FF)
+OP_END
+
+/* File: c/OP_UNUSED_B7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B7FF)
+OP_END
+
+/* File: c/OP_UNUSED_B8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B8FF)
+OP_END
+
+/* File: c/OP_UNUSED_B9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B9FF)
+OP_END
+
+/* File: c/OP_UNUSED_BAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BAFF)
+OP_END
+
+/* File: c/OP_UNUSED_BBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BBFF)
+OP_END
+
+/* File: c/OP_UNUSED_BCFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BCFF)
+OP_END
+
+/* File: c/OP_UNUSED_BDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BDFF)
+OP_END
+
+/* File: c/OP_UNUSED_BEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BEFF)
+OP_END
+
+/* File: c/OP_UNUSED_BFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BFFF)
+OP_END
+
+/* File: c/OP_UNUSED_C0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C0FF)
+OP_END
+
+/* File: c/OP_UNUSED_C1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C1FF)
+OP_END
+
+/* File: c/OP_UNUSED_C2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C2FF)
+OP_END
+
+/* File: c/OP_UNUSED_C3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C3FF)
+OP_END
+
+/* File: c/OP_UNUSED_C4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C4FF)
+OP_END
+
+/* File: c/OP_UNUSED_C5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C5FF)
+OP_END
+
+/* File: c/OP_UNUSED_C6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C6FF)
+OP_END
+
+/* File: c/OP_UNUSED_C7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C7FF)
+OP_END
+
+/* File: c/OP_UNUSED_C8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C8FF)
+OP_END
+
+/* File: c/OP_UNUSED_C9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C9FF)
+OP_END
+
+/* File: c/OP_UNUSED_CAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CAFF)
+OP_END
+
+/* File: c/OP_UNUSED_CBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CBFF)
+OP_END
+
+/* File: c/OP_UNUSED_CCFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CCFF)
+OP_END
+
+/* File: c/OP_UNUSED_CDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CDFF)
+OP_END
+
+/* File: c/OP_UNUSED_CEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CEFF)
+OP_END
+
+/* File: c/OP_UNUSED_CFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CFFF)
+OP_END
+
+/* File: c/OP_UNUSED_D0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D0FF)
+OP_END
+
+/* File: c/OP_UNUSED_D1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D1FF)
+OP_END
+
+/* File: c/OP_UNUSED_D2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D2FF)
+OP_END
+
+/* File: c/OP_UNUSED_D3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D3FF)
+OP_END
+
+/* File: c/OP_UNUSED_D4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D4FF)
+OP_END
+
+/* File: c/OP_UNUSED_D5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D5FF)
+OP_END
+
+/* File: c/OP_UNUSED_D6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D6FF)
+OP_END
+
+/* File: c/OP_UNUSED_D7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D7FF)
+OP_END
+
+/* File: c/OP_UNUSED_D8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D8FF)
+OP_END
+
+/* File: c/OP_UNUSED_D9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D9FF)
+OP_END
+
+/* File: c/OP_UNUSED_DAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DAFF)
+OP_END
+
+/* File: c/OP_UNUSED_DBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DBFF)
+OP_END
+
+/* File: c/OP_UNUSED_DCFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DCFF)
+OP_END
+
+/* File: c/OP_UNUSED_DDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DDFF)
+OP_END
+
+/* File: c/OP_UNUSED_DEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DEFF)
+OP_END
+
+/* File: c/OP_UNUSED_DFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DFFF)
+OP_END
+
+/* File: c/OP_UNUSED_E0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E0FF)
+OP_END
+
+/* File: c/OP_UNUSED_E1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E1FF)
+OP_END
+
+/* File: c/OP_UNUSED_E2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E2FF)
+OP_END
+
+/* File: c/OP_UNUSED_E3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E3FF)
+OP_END
+
+/* File: c/OP_UNUSED_E4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E4FF)
+OP_END
+
+/* File: c/OP_UNUSED_E5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E5FF)
+OP_END
+
+/* File: c/OP_UNUSED_E6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E6FF)
+OP_END
+
+/* File: c/OP_UNUSED_E7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E7FF)
+OP_END
+
+/* File: c/OP_UNUSED_E8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E8FF)
+OP_END
+
+/* File: c/OP_UNUSED_E9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E9FF)
+OP_END
+
+/* File: c/OP_UNUSED_EAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EAFF)
+OP_END
+
+/* File: c/OP_UNUSED_EBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EBFF)
+OP_END
+
+/* File: c/OP_UNUSED_ECFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ECFF)
+OP_END
+
+/* File: c/OP_UNUSED_EDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EDFF)
+OP_END
+
+/* File: c/OP_UNUSED_EEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EEFF)
+OP_END
+
+/* File: c/OP_UNUSED_EFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EFFF)
+OP_END
+
+/* File: c/OP_UNUSED_F0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_F0FF)
+OP_END
+
+/* File: c/OP_UNUSED_F1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_F1FF)
+    /*
+     * In portable interp, most unused opcodes will fall through to here.
+     */
+    LOGE("unknown opcode 0x%04x", inst);
+    dvmAbort();
+    FINISH(1);
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_JUMBO /*{vCCCC..vNNNN}, meth@AAAAAAAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(4);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, true);
+        }
+        FINISH(5);
+    }
+OP_END
+
+/* File: c/OP_IGET_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_VOLATILE_JUMBO, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_THROW_VERIFICATION_ERROR_JUMBO.cpp */
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR_JUMBO)
+    EXPORT_PC();
+    vsrc1 = FETCH(3);
+    ref = FETCH(1) | (u4)FETCH(2) << 16;      /* class/field/method ref */
+    dvmThrowVerificationError(curMethod, vsrc1, ref);
+    GOTO_exceptionThrown();
+OP_END
+
+/* File: cstubs/entry.cpp */
+/*
+ * Handler function table, one entry per opcode.
+ */
+#undef H
+#define H(_op) dvmMterp_##_op
+DEFINE_GOTO_TABLE(gDvmMterpHandlers)
+
+#undef H
+#define H(_op) #_op
+DEFINE_GOTO_TABLE(gDvmMterpHandlerNames)
+
+#include <setjmp.h>
+
+/*
+ * C mterp entry point.  This just calls the various C fallbacks, making
+ * this a slow but portable interpeter.
+ *
+ * This is only used for the "allstubs" variant.
+ */
+void dvmMterpStdRun(Thread* self)
+{
+    jmp_buf jmpBuf;
+
+    self->bailPtr = &jmpBuf;
+
+    /* We exit via a longjmp */
+    if (setjmp(jmpBuf)) {
+        LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
+        return
+    }
+
+    /* run until somebody longjmp()s out */
+    while (true) {
+        typedef void (*Handler)(Thread* self);
+
+        u2 inst = /*self->interpSave.*/pc[0];
+        /*
+         * In mterp, dvmCheckBefore is handled via the altHandlerTable,
+         * while in the portable interpreter it is part of the handler
+         * FINISH code.  For allstubs, we must do an explicit check
+         * in the interpretation loop.
+         */
+        if (self-interpBreak.ctl.subMode) {
+            dvmCheckBefore(pc, fp, self, curMethod);
+        }
+        Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
+        (void) gDvmMterpHandlerNames;   /* avoid gcc "defined but not used" */
+        LOGVV("handler %p %s",
+            handler, (const char*) gDvmMterpHandlerNames[inst & 0xff]);
+        (*handler)(self);
+    }
+}
+
+/*
+ * C mterp exit point.  Call here to bail out of the interpreter.
+ */
+void dvmMterpStdBail(Thread* self)
+{
+    jmp_buf* pJmpBuf = self->bailPtr;
+    longjmp(*pJmpBuf, 1);
+}
+
+/* File: c/gotoTargets.cpp */
+/*
+ * C footer.  This has some common code shared by the various targets.
+ */
+
+/*
+ * Everything from here on is a "goto target".  In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction.  Here, these are subroutines that return to the caller.
+ */
+
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool jumboFormat)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        u4* contents;
+        char typeCh;
+        int i;
+        u4 arg5;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* class ref */
+            vsrc1 = FETCH(3);                     /* #of elements */
+            vdst = FETCH(4);                      /* range base */
+            arg5 = -1;                            /* silence compiler warning */
+            ILOGV("|filled-new-array/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        } else {
+            ref = FETCH(1);             /* class ref */
+            vdst = FETCH(2);            /* first 4 regs -or- range base */
+
+            if (methodCallRange) {
+                vsrc1 = INST_AA(inst);  /* #of elements */
+                arg5 = -1;              /* silence compiler warning */
+                ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+            } else {
+                arg5 = INST_A(inst);
+                vsrc1 = INST_B(inst);   /* #of elements */
+                ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
+                   vsrc1, ref, vdst, arg5);
+            }
+        }
+
+        /*
+         * Resolve the array class.
+         */
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /*
+        if (!dvmIsArrayClass(arrayClass)) {
+            dvmThrowRuntimeException(
+                "filled-new-array needs array class");
+            GOTO_exceptionThrown();
+        }
+        */
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        /*
+         * Create an array of the specified type.
+         */
+        LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
+        typeCh = arrayClass->descriptor[1];
+        if (typeCh == 'D' || typeCh == 'J') {
+            /* category 2 primitives not allowed */
+            dvmThrowRuntimeException("bad filled array req");
+            GOTO_exceptionThrown();
+        } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
+            /* TODO: requires multiple "fill in" loops with different widths */
+            LOGE("non-int primitives not implemented");
+            dvmThrowInternalError(
+                "filled-new-array not implemented for anything but 'int'");
+            GOTO_exceptionThrown();
+        }
+
+        newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+
+        /*
+         * Fill in the elements.  It's legal for vsrc1 to be zero.
+         */
+        contents = (u4*)(void*)newArray->contents;
+        if (methodCallRange) {
+            for (i = 0; i < vsrc1; i++)
+                contents[i] = GET_REGISTER(vdst+i);
+        } else {
+            assert(vsrc1 <= 5);
+            if (vsrc1 == 5) {
+                contents[4] = GET_REGISTER(arg5);
+                vsrc1--;
+            }
+            for (i = 0; i < vsrc1; i++) {
+                contents[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+        }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
+
+        retval.l = (Object*)newArray;
+    }
+    if (jumboFormat) {
+        FINISH(5);
+    } else {
+        FINISH(3);
+    }
+GOTO_TARGET_END
+
+
+GOTO_TARGET(invokeVirtual, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-virtual/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->methodToCall = methodToCall;
+        self->callsiteClass = thisPtr->clazz;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            /*
+             * This can happen if you create two classes, Base and Sub, where
+             * Sub is a sub-class of Base.  Declare a protected abstract
+             * method foo() in Base, and invoke foo() from a method in Base.
+             * Base is an "abstract base class" and is never instantiated
+             * directly.  Now, Override foo() in Sub, and use Sub.  This
+             * Works fine unless Sub stops providing an implementation of
+             * the method.
+             */
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            (u4) baseMethod->methodIndex,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+#if 0
+        if (vsrc1 != methodToCall->insSize) {
+            LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
+                baseMethod->clazz->descriptor, baseMethod->name,
+                (u4) baseMethod->methodIndex,
+                methodToCall->clazz->descriptor, methodToCall->name);
+            //dvmDumpClass(baseMethod->clazz);
+            //dvmDumpClass(methodToCall->clazz);
+            dvmDumpAllClasses(0);
+        }
+#endif
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuper, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-super/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         * The first arg to dvmResolveMethod() is just the referring class
+         * (used for class loaders and such), so we don't want to pass
+         * the superclass into the resolution call.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in that class' superclass.
+         */
+        if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
+            /*
+             * Method does not exist in the superclass.  Could happen if
+             * superclass gets updated.
+             */
+            dvmThrowNoSuchMethodError(baseMethod->name);
+            GOTO_exceptionThrown();
+        }
+        methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ base=%s.%s super-virtual=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeInterface, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+        ClassObject* thisClass;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-interface/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        thisClass = thisPtr->clazz;
+
+
+        /*
+         * Given a class and a method index, find the Method* with the
+         * actual code we want to execute.
+         */
+        methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
+                        methodClassDex);
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisClass;
+        self->methodToCall = methodToCall;
+#endif
+        if (methodToCall == NULL) {
+            assert(dvmCheckException(self));
+            GOTO_exceptionThrown();
+        }
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeDirect, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-direct/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (methodToCall == NULL) {
+            methodToCall = dvmResolveMethod(curMethod->clazz, ref,
+                            METHOD_DIRECT);
+            if (methodToCall == NULL) {
+                ILOGV("+ unknown direct method");     // should be impossible
+                GOTO_exceptionThrown();
+            }
+        }
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeStatic, bool methodCallRange, bool jumboFormat)
+    EXPORT_PC();
+
+    if (jumboFormat) {
+        ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+        vsrc1 = FETCH(3);                     /* count */
+        vdst = FETCH(4);                      /* first reg */
+        ADJUST_PC(2);     /* advance pc partially to make returns easier */
+        ILOGV("|invoke-static/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+    } else {
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* method ref */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange)
+            ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        else
+            ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+    }
+
+    methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+    if (methodToCall == NULL) {
+        methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
+        if (methodToCall == NULL) {
+            ILOGV("+ unknown method");
+            GOTO_exceptionThrown();
+        }
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        /*
+         * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+         * Include the check if this code is being used as a stub
+         * called from the assembly interpreter.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
+            /* Class initialization is still ongoing */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+    }
+    GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeVirtualQuick, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        /*
+         * The object against which we are executing a method is always
+         * in the first argument.
+         */
+        if (methodCallRange) {
+            assert(vsrc1 > 0);
+            ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            assert((vsrc1>>4) > 0);
+            ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[ref];
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisPtr->clazz;
+        self->methodToCall = methodToCall;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuperQuick, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange) {
+            ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisReg = vdst & 0x0f;
+        }
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+#if 0   /* impossible in optimized + verified code */
+        if (ref >= curMethod->clazz->super->vtableCount) {
+            dvmThrowNoSuchMethodError(NULL);
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
+#endif
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in the method's class' superclass.
+         */
+        methodToCall = curMethod->clazz->super->vtable[ref];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ super-virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * General handling for return-void, return, and return-wide.  Put the
+     * return value in "retval" before jumping here.
+     */
+GOTO_TARGET(returnFromMethod)
+    {
+        StackSaveArea* saveArea;
+
+        /*
+         * We must do this BEFORE we pop the previous stack frame off, so
+         * that the GC can see the return value (if any) in the local vars.
+         *
+         * Since this is now an interpreter switch point, we must do it before
+         * we do anything at all.
+         */
+        PERIODIC_CHECKS(0);
+
+        ILOGV("> retval=0x%llx (leaving %s.%s %s)",
+            retval.j, curMethod->clazz->descriptor, curMethod->name,
+            curMethod->shorty);
+        //DUMP_REGS(curMethod, fp);
+
+        saveArea = SAVEAREA_FROM_FP(fp);
+
+#ifdef EASY_GDB
+        debugSaveArea = saveArea;
+#endif
+
+        /* back up to previous frame and see if we hit a break */
+        fp = (u4*)saveArea->prevFrame;
+        assert(fp != NULL);
+
+        /* Handle any special subMode requirements */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportReturn(self);
+        }
+
+        if (dvmIsBreakFrame(fp)) {
+            /* bail without popping the method frame from stack */
+            LOGVV("+++ returned into break frame");
+            GOTO_bail();
+        }
+
+        /* update thread FP, and reset local variables */
+        self->interpSave.curFrame = fp;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = saveArea->savedPc;
+        ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+
+        /* use FINISH on the caller's invoke instruction */
+        //u2 invokeInstr = INST_INST(FETCH(0));
+        if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+            invokeInstr <= OP_INVOKE_INTERFACE*/)
+        {
+            FINISH(3);
+        } else {
+            //LOGE("Unknown invoke instr %02x at %d",
+            //    invokeInstr, (int) (pc - curMethod->insns));
+            assert(false);
+        }
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * Jump here when the code throws an exception.
+     *
+     * By the time we get here, the Throwable has been created and the stack
+     * trace has been saved off.
+     */
+GOTO_TARGET(exceptionThrown)
+    {
+        Object* exception;
+        int catchRelPc;
+
+        PERIODIC_CHECKS(0);
+
+        /*
+         * We save off the exception and clear the exception status.  While
+         * processing the exception we might need to load some Throwable
+         * classes, and we don't want class loader exceptions to get
+         * confused with this one.
+         */
+        assert(dvmCheckException(self));
+        exception = dvmGetException(self);
+        dvmAddTrackedAlloc(exception, self);
+        dvmClearException(self);
+
+        LOGV("Handling exception %s at %s:%d",
+            exception->clazz->descriptor, curMethod->name,
+            dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+
+        /*
+         * Report the exception throw to any "subMode" watchers.
+         *
+         * TODO: if the exception was thrown by interpreted code, control
+         * fell through native, and then back to us, we will report the
+         * exception at the point of the throw and again here.  We can avoid
+         * this by not reporting exceptions when we jump here directly from
+         * the native call code above, but then we won't report exceptions
+         * that were thrown *from* the JNI code (as opposed to *through* it).
+         *
+         * The correct solution is probably to ignore from-native exceptions
+         * here, and have the JNI exception code do the reporting to the
+         * debugger.
+         */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportExceptionThrow(self, exception);
+        }
+
+        /*
+         * We need to unroll to the catch block or the nearest "break"
+         * frame.
+         *
+         * A break frame could indicate that we have reached an intermediate
+         * native call, or have gone off the top of the stack and the thread
+         * needs to exit.  Either way, we return from here, leaving the
+         * exception raised.
+         *
+         * If we do find a catch block, we want to transfer execution to
+         * that point.
+         *
+         * Note this can cause an exception while resolving classes in
+         * the "catch" blocks.
+         */
+        catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
+                    exception, false, (void**)(void*)&fp);
+
+        /*
+         * Restore the stack bounds after an overflow.  This isn't going to
+         * be correct in all circumstances, e.g. if JNI code devours the
+         * exception this won't happen until some other exception gets
+         * thrown.  If the code keeps pushing the stack bounds we'll end
+         * up aborting the VM.
+         *
+         * Note we want to do this *after* the call to dvmFindCatchBlock,
+         * because that may need extra stack space to resolve exception
+         * classes (e.g. through a class loader).
+         *
+         * It's possible for the stack overflow handling to cause an
+         * exception (specifically, class resolution in a "catch" block
+         * during the call above), so we could see the thread's overflow
+         * flag raised but actually be running in a "nested" interpreter
+         * frame.  We don't allow doubled-up StackOverflowErrors, so
+         * we can check for this by just looking at the exception type
+         * in the cleanup function.  Also, we won't unroll past the SOE
+         * point because the more-recent exception will hit a break frame
+         * as it unrolls to here.
+         */
+        if (self->stackOverflowed)
+            dvmCleanupStackOverflow(self, exception);
+
+        if (catchRelPc < 0) {
+            /* falling through to JNI code or off the bottom of the stack */
+#if DVM_SHOW_EXCEPTION >= 2
+            LOGD("Exception %s from %s:%d not caught locally",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+#endif
+            dvmSetException(self, exception);
+            dvmReleaseTrackedAlloc(exception, self);
+            GOTO_bail();
+        }
+
+#if DVM_SHOW_EXCEPTION >= 3
+        {
+            const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
+            LOGD("Exception %s thrown from %s:%d to %s:%d",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns),
+                dvmGetMethodSourceFile(catchMethod),
+                dvmLineNumFromPC(catchMethod, catchRelPc));
+        }
+#endif
+
+        /*
+         * Adjust local variables to match self->interpSave.curFrame and the
+         * updated PC.
+         */
+        //fp = (u4*) self->interpSave.curFrame;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = curMethod->insns + catchRelPc;
+        ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+        DUMP_REGS(curMethod, fp, false);            // show all regs
+
+        /*
+         * Restore the exception if the handler wants it.
+         *
+         * The Dalvik spec mandates that, if an exception handler wants to
+         * do something with the exception, the first instruction executed
+         * must be "move-exception".  We can pass the exception along
+         * through the thread struct, and let the move-exception instruction
+         * clear it for us.
+         *
+         * If the handler doesn't call move-exception, we don't want to
+         * finish here with an exception still pending.
+         */
+        if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
+            dvmSetException(self, exception);
+
+        dvmReleaseTrackedAlloc(exception, self);
+        FINISH(0);
+    }
+GOTO_TARGET_END
+
+
+
+    /*
+     * General handling for invoke-{virtual,super,direct,static,interface},
+     * including "quick" variants.
+     *
+     * Set "methodToCall" to the Method we're calling, and "methodCallRange"
+     * depending on whether this is a "/range" instruction.
+     *
+     * For a range call:
+     *  "vsrc1" holds the argument count (8 bits)
+     *  "vdst" holds the first argument in the range
+     * For a non-range call:
+     *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
+     *  "vdst" holds four 4-bit register indices
+     *
+     * The caller must EXPORT_PC before jumping here, because any method
+     * call can throw a stack overflow exception.
+     */
+GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
+    u2 count, u2 regs)
+    {
+        STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
+
+        //printf("range=%d call=%p count=%d regs=0x%04x\n",
+        //    methodCallRange, methodToCall, count, regs);
+        //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
+        //    methodToCall->name, methodToCall->shorty);
+
+        u4* outs;
+        int i;
+
+        /*
+         * Copy args.  This may corrupt vsrc1/vdst.
+         */
+        if (methodCallRange) {
+            // could use memcpy or a "Duff's device"; most functions have
+            // so few args it won't matter much
+            assert(vsrc1 <= curMethod->outsSize);
+            assert(vsrc1 == methodToCall->insSize);
+            outs = OUTS_FROM_FP(fp, vsrc1);
+            for (i = 0; i < vsrc1; i++)
+                outs[i] = GET_REGISTER(vdst+i);
+        } else {
+            u4 count = vsrc1 >> 4;
+
+            assert(count <= curMethod->outsSize);
+            assert(count == methodToCall->insSize);
+            assert(count <= 5);
+
+            outs = OUTS_FROM_FP(fp, count);
+#if 0
+            if (count == 5) {
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+                count--;
+            }
+            for (i = 0; i < (int) count; i++) {
+                outs[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+#else
+            // This version executes fewer instructions but is larger
+            // overall.  Seems to be a teensy bit faster.
+            assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
+            switch (count) {
+            case 5:
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+            case 4:
+                outs[3] = GET_REGISTER(vdst >> 12);
+            case 3:
+                outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
+            case 2:
+                outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
+            case 1:
+                outs[0] = GET_REGISTER(vdst & 0x0f);
+            default:
+                ;
+            }
+#endif
+        }
+    }
+
+    /*
+     * (This was originally a "goto" target; I've kept it separate from the
+     * stuff above in case we want to refactor things again.)
+     *
+     * At this point, we have the arguments stored in the "outs" area of
+     * the current method's stack frame, and the method to call in
+     * "methodToCall".  Push a new stack frame.
+     */
+    {
+        StackSaveArea* newSaveArea;
+        u4* newFp;
+
+        ILOGV("> %s%s.%s %s",
+            dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
+            methodToCall->clazz->descriptor, methodToCall->name,
+            methodToCall->shorty);
+
+        newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
+        newSaveArea = SAVEAREA_FROM_FP(newFp);
+
+        /* verify that we have enough space */
+        if (true) {
+            u1* bottom;
+            bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
+            if (bottom < self->interpStackEnd) {
+                /* stack overflow */
+                LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
+                    self->interpStackStart, self->interpStackEnd, bottom,
+                    (u1*) fp - bottom, self->interpStackSize,
+                    methodToCall->name);
+                dvmHandleStackOverflow(self, methodToCall);
+                assert(dvmCheckException(self));
+                GOTO_exceptionThrown();
+            }
+            //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
+            //    fp, newFp, newSaveArea, bottom);
+        }
+
+#ifdef LOG_INSTR
+        if (methodToCall->registersSize > methodToCall->insSize) {
+            /*
+             * This makes valgrind quiet when we print registers that
+             * haven't been initialized.  Turn it off when the debug
+             * messages are disabled -- we want valgrind to report any
+             * used-before-initialized issues.
+             */
+            memset(newFp, 0xcc,
+                (methodToCall->registersSize - methodToCall->insSize) * 4);
+        }
+#endif
+
+#ifdef EASY_GDB
+        newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
+#endif
+        newSaveArea->prevFrame = fp;
+        newSaveArea->savedPc = pc;
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        newSaveArea->returnAddr = 0;
+#endif
+        newSaveArea->method = methodToCall;
+
+        if (self->interpBreak.ctl.subMode != 0) {
+            /*
+             * We mark ENTER here for both native and non-native
+             * calls.  For native calls, we'll mark EXIT on return.
+             * For non-native calls, EXIT is marked in the RETURN op.
+             */
+            PC_TO_SELF();
+            dvmReportInvoke(self, methodToCall);
+        }
+
+        if (!dvmIsNativeMethod(methodToCall)) {
+            /*
+             * "Call" interpreted code.  Reposition the PC, update the
+             * frame pointer and other local state, and continue.
+             */
+            curMethod = methodToCall;
+            self->interpSave.method = curMethod;
+            methodClassDex = curMethod->clazz->pDvmDex;
+            pc = methodToCall->insns;
+            self->interpSave.curFrame = fp = newFp;
+#ifdef EASY_GDB
+            debugSaveArea = SAVEAREA_FROM_FP(newFp);
+#endif
+            self->debugIsMethodEntry = true;        // profiling, debugging
+            ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+                curMethod->name, curMethod->shorty);
+            DUMP_REGS(curMethod, fp, true);         // show input args
+            FINISH(0);                              // jump to method start
+        } else {
+            /* set this up for JNI locals, even if not a JNI native */
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+
+            self->interpSave.curFrame = newFp;
+
+            DUMP_REGS(methodToCall, newFp, true);   // show input args
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPreNativeInvoke(methodToCall, self, fp);
+            }
+
+            ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+                  methodToCall->name, methodToCall->shorty);
+
+            /*
+             * Jump through native call bridge.  Because we leave no
+             * space for locals on native calls, "newFp" points directly
+             * to the method arguments.
+             */
+            (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPostNativeInvoke(methodToCall, self, fp);
+            }
+
+            /* pop frame off */
+            dvmPopJniLocals(self, newSaveArea);
+            self->interpSave.curFrame = fp;
+
+            /*
+             * If the native code threw an exception, or interpreted code
+             * invoked by the native call threw one and nobody has cleared
+             * it, jump to our local exception handling.
+             */
+            if (dvmCheckException(self)) {
+                LOGV("Exception thrown by/below native code");
+                GOTO_exceptionThrown();
+            }
+
+            ILOGD("> retval=0x%llx (leaving native)", retval.j);
+            ILOGD("> (return from native %s.%s to %s.%s %s)",
+                methodToCall->clazz->descriptor, methodToCall->name,
+                curMethod->clazz->descriptor, curMethod->name,
+                curMethod->shorty);
+
+            //u2 invokeInstr = INST_INST(FETCH(0));
+            if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+                invokeInstr <= OP_INVOKE_INTERFACE*/)
+            {
+                FINISH(3);
+            } else {
+                //LOGE("Unknown invoke instr %02x at %d",
+                //    invokeInstr, (int) (pc - curMethod->insns));
+                assert(false);
+            }
+        }
+    }
+    assert(false);      // should not get here
+GOTO_TARGET_END
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
diff --git a/vm/mterp/out/InterpC-armv5te-vfp.cpp b/vm/mterp/out/InterpC-armv5te-vfp.cpp
new file mode 100644
index 0000000..24fbfdc
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv5te-vfp.cpp
@@ -0,0 +1,1346 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv5te-vfp'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.cpp */
+#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 rSELF     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 rSELF=%08x rINST=%08x\n",
+        rPC, rFP, rSELF, rINST);
+    printf("    : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
+
+    //Thread* self = (Thread*) rSELF;
+    //const Method* method = self->method;
+    printf("    + self is %p\n", dvmThreadSelf());
+    //printf("    + currently in %s.%s %s\n",
+    //    method->clazz->descriptor, method->name, method->shorty);
+    //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.cpp b/vm/mterp/out/InterpC-armv5te.cpp
new file mode 100644
index 0000000..b750929
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv5te.cpp
@@ -0,0 +1,1346 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv5te'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.cpp */
+#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 rSELF     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 rSELF=%08x rINST=%08x\n",
+        rPC, rFP, rSELF, rINST);
+    printf("    : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
+
+    //Thread* self = (Thread*) rSELF;
+    //const Method* method = self->method;
+    printf("    + self is %p\n", dvmThreadSelf());
+    //printf("    + currently in %s.%s %s\n",
+    //    method->clazz->descriptor, method->name, method->shorty);
+    //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-armv7-a-neon.cpp b/vm/mterp/out/InterpC-armv7-a-neon.cpp
new file mode 100644
index 0000000..69bf469
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv7-a-neon.cpp
@@ -0,0 +1,1346 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv7-a-neon'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.cpp */
+#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 rSELF     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 rSELF=%08x rINST=%08x\n",
+        rPC, rFP, rSELF, rINST);
+    printf("    : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
+
+    //Thread* self = (Thread*) rSELF;
+    //const Method* method = self->method;
+    printf("    + self is %p\n", dvmThreadSelf());
+    //printf("    + currently in %s.%s %s\n",
+    //    method->clazz->descriptor, method->name, method->shorty);
+    //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-armv7-a.cpp b/vm/mterp/out/InterpC-armv7-a.cpp
new file mode 100644
index 0000000..4ca2a1c
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv7-a.cpp
@@ -0,0 +1,1346 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv7-a'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.cpp */
+#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 rSELF     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 rSELF=%08x rINST=%08x\n",
+        rPC, rFP, rSELF, rINST);
+    printf("    : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
+
+    //Thread* self = (Thread*) rSELF;
+    //const Method* method = self->method;
+    printf("    + self is %p\n", dvmThreadSelf());
+    //printf("    + currently in %s.%s %s\n",
+    //    method->clazz->descriptor, method->name, method->shorty);
+    //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-portable.cpp b/vm/mterp/out/InterpC-portable.cpp
new file mode 100644
index 0000000..d6a23c0
--- /dev/null
+++ b/vm/mterp/out/InterpC-portable.cpp
@@ -0,0 +1,5403 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'portable'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: portable/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)
+
+#define GOTO_TARGET(_target, ...) _target:
+
+#define GOTO_TARGET_END
+
+/* ugh */
+#define STUB_HACK(x)
+#define JIT_STUB_HACK(x)
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()                                                    \
+    self->interpSave.pc = pc;                                              \
+    self->interpSave.curFrame = fp;
+#define PC_TO_SELF() self->interpSave.pc = pc;
+
+/*
+ * Instruction framing.  For a switch-oriented implementation this is
+ * case/break, for a threaded implementation it's a goto label and an
+ * instruction fetch/computed goto.
+ *
+ * Assumes the existence of "const u2* pc" and (for threaded operation)
+ * "u2 inst".
+ */
+# define H(_op)             &&op_##_op
+# define HANDLE_OPCODE(_op) op_##_op:
+# define FINISH(_offset) {                                                  \
+        ADJUST_PC(_offset);                                                 \
+        inst = FETCH(0);                                                    \
+        if (self->interpBreak.ctl.subMode) {                                \
+            dvmCheckBefore(pc, fp, self);                                   \
+        }                                                                   \
+        goto *handlerTable[INST_INST(inst)];                                \
+    }
+# define FINISH_BKPT(_opcode) {                                             \
+        goto *handlerTable[_opcode];                                        \
+    }
+# define DISPATCH_EXTENDED(_opcode) {                                       \
+        goto *handlerTable[0x100 + _opcode];                                \
+    }
+
+#define OP_END
+
+/*
+ * The "goto" targets just turn into goto statements.  The "arguments" are
+ * passed through local variables.
+ */
+
+#define GOTO_exceptionThrown() goto exceptionThrown;
+
+#define GOTO_returnFromMethod() goto returnFromMethod;
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        methodCallRange = _methodCallRange;                                 \
+        jumboFormat = _jumboFormat;                                         \
+        goto _target;                                                       \
+    } while(false)
+
+/* for this, the "args" are already in the locals */
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) goto invokeMethod;
+
+#define GOTO_bail() goto bail;
+
+/*
+ * 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(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: portable/entry.cpp */
+/*
+ * Main interpreter loop.
+ *
+ * This was written with an ARM implementation in mind.
+ */
+void dvmInterpretPortable(Thread* self)
+{
+#if defined(EASY_GDB)
+    StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+#endif
+    DvmDex* methodClassDex;     // curMethod->clazz->pDvmDex
+    JValue retval;
+
+    /* core state */
+    const Method* curMethod;    // method we're interpreting
+    const u2* pc;               // program counter
+    u4* fp;                     // frame pointer
+    u2 inst;                    // current instruction
+    /* instruction decoding */
+    u4 ref;                     // 16 or 32-bit quantity fetched directly
+    u2 vsrc1, vsrc2, vdst;      // usually used for register indexes
+    /* method call setup */
+    const Method* methodToCall;
+    bool methodCallRange;
+    bool jumboFormat;
+
+
+    /* static computed goto table */
+    DEFINE_GOTO_TABLE(handlerTable);
+
+    /* copy state in */
+    curMethod = self->interpSave.method;
+    pc = self->interpSave.pc;
+    fp = self->interpSave.curFrame;
+    retval = self->interpSave.retval;   /* only need for kInterpEntryReturn? */
+
+    methodClassDex = curMethod->clazz->pDvmDex;
+
+    LOGVV("threadid=%d: %s.%s pc=%#x fp=%p",
+        self->threadId, curMethod->clazz->descriptor, curMethod->name,
+        pc - curMethod->insns, fp);
+
+    /*
+     * Handle any ongoing profiling and prep for debugging.
+     */
+    if (self->interpBreak.ctl.subMode != 0) {
+        TRACE_METHOD_ENTER(self, curMethod);
+        self->debugIsMethodEntry = true;   // Always true on startup
+    }
+    /*
+     * DEBUG: scramble this to ensure we're not relying on it.
+     */
+    methodToCall = (const Method*) -1;
+
+#if 0
+    if (self->debugIsMethodEntry) {
+        ILOGD("|-- Now interpreting %s.%s", curMethod->clazz->descriptor,
+                curMethod->name);
+        DUMP_REGS(curMethod, self->interpSave.curFrame, false);
+    }
+#endif
+
+    FINISH(0);                  /* fetch and execute first instruction */
+
+/*--- start of opcodes ---*/
+
+/* File: c/OP_NOP.cpp */
+HANDLE_OPCODE(OP_NOP)
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE.cpp */
+HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_FROM16.cpp */
+HANDLE_OPCODE(OP_MOVE_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MOVE_16.cpp */
+HANDLE_OPCODE(OP_MOVE_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(3);
+OP_END
+
+/* File: c/OP_MOVE_WIDE.cpp */
+HANDLE_OPCODE(OP_MOVE_WIDE /*vA, vB*/)
+    /* IMPORTANT: must correctly handle overlapping registers, e.g. both
+     * "move-wide v6, v7" and "move-wide v7, v6" */
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move-wide v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
+        kSpacing+5, vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_WIDE_FROM16.cpp */
+HANDLE_OPCODE(OP_MOVE_WIDE_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move-wide/from16 v%d,v%d  (v%d=0x%08llx)", vdst, vsrc1,
+        vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MOVE_WIDE_16.cpp */
+HANDLE_OPCODE(OP_MOVE_WIDE_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move-wide/16 v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
+        kSpacing+8, vdst, GET_REGISTER_WIDE(vsrc1));
+    SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
+    FINISH(3);
+OP_END
+
+/* File: c/OP_MOVE_OBJECT.cpp */
+/* File: c/OP_MOVE.cpp */
+HANDLE_OPCODE(OP_MOVE_OBJECT /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(1);
+OP_END
+
+
+/* File: c/OP_MOVE_OBJECT_FROM16.cpp */
+/* File: c/OP_MOVE_FROM16.cpp */
+HANDLE_OPCODE(OP_MOVE_OBJECT_FROM16 /*vAA, vBBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(2);
+OP_END
+
+
+/* File: c/OP_MOVE_OBJECT_16.cpp */
+/* File: c/OP_MOVE_16.cpp */
+HANDLE_OPCODE(OP_MOVE_OBJECT_16 /*vAAAA, vBBBB*/)
+    vdst = FETCH(1);
+    vsrc1 = FETCH(2);
+    ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
+        (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
+        kSpacing, vdst, GET_REGISTER(vsrc1));
+    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
+    FINISH(3);
+OP_END
+
+
+/* File: c/OP_MOVE_RESULT.cpp */
+HANDLE_OPCODE(OP_MOVE_RESULT /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
+         (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
+         vdst, kSpacing+4, vdst,retval.i);
+    SET_REGISTER(vdst, retval.i);
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_RESULT_WIDE.cpp */
+HANDLE_OPCODE(OP_MOVE_RESULT_WIDE /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result-wide v%d %s(0x%08llx)", vdst, kSpacing, retval.j);
+    SET_REGISTER_WIDE(vdst, retval.j);
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MOVE_RESULT_OBJECT.cpp */
+/* File: c/OP_MOVE_RESULT.cpp */
+HANDLE_OPCODE(OP_MOVE_RESULT_OBJECT /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
+         (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
+         vdst, kSpacing+4, vdst,retval.i);
+    SET_REGISTER(vdst, retval.i);
+    FINISH(1);
+OP_END
+
+
+/* File: c/OP_MOVE_EXCEPTION.cpp */
+HANDLE_OPCODE(OP_MOVE_EXCEPTION /*vAA*/)
+    vdst = INST_AA(inst);
+    ILOGV("|move-exception v%d", vdst);
+    assert(self->exception != NULL);
+    SET_REGISTER(vdst, (u4)self->exception);
+    dvmClearException(self);
+    FINISH(1);
+OP_END
+
+/* File: c/OP_RETURN_VOID.cpp */
+HANDLE_OPCODE(OP_RETURN_VOID /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;    // placate valgrind
+#endif
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_RETURN.cpp */
+HANDLE_OPCODE(OP_RETURN /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return%s v%d",
+        (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
+    retval.i = GET_REGISTER(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_RETURN_WIDE.cpp */
+HANDLE_OPCODE(OP_RETURN_WIDE /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return-wide v%d", vsrc1);
+    retval.j = GET_REGISTER_WIDE(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_RETURN_OBJECT.cpp */
+/* File: c/OP_RETURN.cpp */
+HANDLE_OPCODE(OP_RETURN_OBJECT /*vAA*/)
+    vsrc1 = INST_AA(inst);
+    ILOGV("|return%s v%d",
+        (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
+    retval.i = GET_REGISTER(vsrc1);
+    GOTO_returnFromMethod();
+OP_END
+
+
+/* File: c/OP_CONST_4.cpp */
+HANDLE_OPCODE(OP_CONST_4 /*vA, #+B*/)
+    {
+        s4 tmp;
+
+        vdst = INST_A(inst);
+        tmp = (s4) (INST_B(inst) << 28) >> 28;  // sign extend 4-bit value
+        ILOGV("|const/4 v%d,#0x%02x", vdst, (s4)tmp);
+        SET_REGISTER(vdst, tmp);
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_CONST_16.cpp */
+HANDLE_OPCODE(OP_CONST_16 /*vAA, #+BBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const/16 v%d,#0x%04x", vdst, (s2)vsrc1);
+    SET_REGISTER(vdst, (s2) vsrc1);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST.cpp */
+HANDLE_OPCODE(OP_CONST /*vAA, #+BBBBBBBB*/)
+    {
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const v%d,#0x%08x", vdst, tmp);
+        SET_REGISTER(vdst, tmp);
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_CONST_HIGH16.cpp */
+HANDLE_OPCODE(OP_CONST_HIGH16 /*vAA, #+BBBB0000*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const/high16 v%d,#0x%04x0000", vdst, vsrc1);
+    SET_REGISTER(vdst, vsrc1 << 16);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_WIDE_16.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE_16 /*vAA, #+BBBB*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const-wide/16 v%d,#0x%04x", vdst, (s2)vsrc1);
+    SET_REGISTER_WIDE(vdst, (s2)vsrc1);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_WIDE_32.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE_32 /*vAA, #+BBBBBBBB*/)
+    {
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const-wide/32 v%d,#0x%08x", vdst, tmp);
+        SET_REGISTER_WIDE(vdst, (s4) tmp);
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_CONST_WIDE.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE /*vAA, #+BBBBBBBBBBBBBBBB*/)
+    {
+        u8 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u8)FETCH(2) << 16;
+        tmp |= (u8)FETCH(3) << 32;
+        tmp |= (u8)FETCH(4) << 48;
+        ILOGV("|const-wide v%d,#0x%08llx", vdst, tmp);
+        SET_REGISTER_WIDE(vdst, tmp);
+    }
+    FINISH(5);
+OP_END
+
+/* File: c/OP_CONST_WIDE_HIGH16.cpp */
+HANDLE_OPCODE(OP_CONST_WIDE_HIGH16 /*vAA, #+BBBB000000000000*/)
+    vdst = INST_AA(inst);
+    vsrc1 = FETCH(1);
+    ILOGV("|const-wide/high16 v%d,#0x%04x000000000000", vdst, vsrc1);
+    SET_REGISTER_WIDE(vdst, ((u8) vsrc1) << 48);
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_STRING.cpp */
+HANDLE_OPCODE(OP_CONST_STRING /*vAA, string@BBBB*/)
+    {
+        StringObject* strObj;
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|const-string v%d string@0x%04x", vdst, ref);
+        strObj = dvmDexGetResolvedString(methodClassDex, ref);
+        if (strObj == NULL) {
+            EXPORT_PC();
+            strObj = dvmResolveString(curMethod->clazz, ref);
+            if (strObj == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) strObj);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_CONST_STRING_JUMBO.cpp */
+HANDLE_OPCODE(OP_CONST_STRING_JUMBO /*vAA, string@BBBBBBBB*/)
+    {
+        StringObject* strObj;
+        u4 tmp;
+
+        vdst = INST_AA(inst);
+        tmp = FETCH(1);
+        tmp |= (u4)FETCH(2) << 16;
+        ILOGV("|const-string/jumbo v%d string@0x%08x", vdst, tmp);
+        strObj = dvmDexGetResolvedString(methodClassDex, tmp);
+        if (strObj == NULL) {
+            EXPORT_PC();
+            strObj = dvmResolveString(curMethod->clazz, tmp);
+            if (strObj == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) strObj);
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_CONST_CLASS.cpp */
+HANDLE_OPCODE(OP_CONST_CLASS /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|const-class v%d class@0x%04x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            EXPORT_PC();
+            clazz = dvmResolveClass(curMethod->clazz, ref, true);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) clazz);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MONITOR_ENTER.cpp */
+HANDLE_OPCODE(OP_MONITOR_ENTER /*vAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|monitor-enter v%d %s(0x%08x)",
+            vsrc1, kSpacing+6, GET_REGISTER(vsrc1));
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+        ILOGV("+ locking %p %s", obj, obj->clazz->descriptor);
+        EXPORT_PC();    /* need for precise GC */
+        dvmLockObject(self, obj);
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_MONITOR_EXIT.cpp */
+HANDLE_OPCODE(OP_MONITOR_EXIT /*vAA*/)
+    {
+        Object* obj;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|monitor-exit v%d %s(0x%08x)",
+            vsrc1, kSpacing+5, GET_REGISTER(vsrc1));
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (!checkForNull(obj)) {
+            /*
+             * The exception needs to be processed at the *following*
+             * instruction, not the current instruction (see the Dalvik
+             * spec).  Because we're jumping to an exception handler,
+             * we're not actually at risk of skipping an instruction
+             * by doing so.
+             */
+            ADJUST_PC(1);           /* monitor-exit width is 1 */
+            GOTO_exceptionThrown();
+        }
+        ILOGV("+ unlocking %p %s", obj, obj->clazz->descriptor);
+        if (!dvmUnlockObject(self, obj)) {
+            assert(dvmCheckException(self));
+            ADJUST_PC(1);
+            GOTO_exceptionThrown();
+        }
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_CHECK_CAST.cpp */
+HANDLE_OPCODE(OP_CHECK_CAST /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ref = FETCH(1);         /* class to check against */
+        ILOGV("|check-cast v%d,class@0x%04x", vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj != NULL) {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                clazz = dvmResolveClass(curMethod->clazz, ref, false);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            if (!dvmInstanceof(obj->clazz, clazz)) {
+                dvmThrowClassCastException(obj->clazz, clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_INSTANCE_OF.cpp */
+HANDLE_OPCODE(OP_INSTANCE_OF /*vA, vB, class@CCCC*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);   /* object to check */
+        ref = FETCH(1);         /* class to check against */
+        ILOGV("|instance-of v%d,v%d,class@0x%04x", vdst, vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj == NULL) {
+            SET_REGISTER(vdst, 0);
+        } else {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNullExportPC(obj, fp, pc))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                EXPORT_PC();
+                clazz = dvmResolveClass(curMethod->clazz, ref, true);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+        }
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_ARRAY_LENGTH.cpp */
+HANDLE_OPCODE(OP_ARRAY_LENGTH /*vA, vB*/)
+    {
+        ArrayObject* arrayObj;
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        ILOGV("|array-length v%d,v%d  (%p)", vdst, vsrc1, arrayObj);
+        if (!checkForNullExportPC((Object*) arrayObj, fp, pc))
+            GOTO_exceptionThrown();
+        /* verifier guarantees this is an array reference */
+        SET_REGISTER(vdst, arrayObj->length);
+    }
+    FINISH(1);
+OP_END
+
+/* File: c/OP_NEW_INSTANCE.cpp */
+HANDLE_OPCODE(OP_NEW_INSTANCE /*vAA, class@BBBB*/)
+    {
+        ClassObject* clazz;
+        Object* newObj;
+
+        EXPORT_PC();
+
+        vdst = INST_AA(inst);
+        ref = FETCH(1);
+        ILOGV("|new-instance v%d,class@0x%04x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            clazz = dvmResolveClass(curMethod->clazz, ref, false);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
+            GOTO_exceptionThrown();
+
+#if defined(WITH_JIT)
+        /*
+         * The JIT needs dvmDexGetResolvedClass() to return non-null.
+         * Since we use the portable interpreter to build the trace, this extra
+         * check is not needed for mterp.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (!dvmDexGetResolvedClass(methodClassDex, ref))) {
+            /* Class initialization is still ongoing - end the trace */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+
+        /*
+         * Verifier now tests for interface/abstract class.
+         */
+        //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+        //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
+        //        clazz->descriptor);
+        //    GOTO_exceptionThrown();
+        //}
+        newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+        if (newObj == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newObj);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_NEW_ARRAY.cpp */
+HANDLE_OPCODE(OP_NEW_ARRAY /*vA, vB, class@CCCC*/)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        s4 length;
+
+        EXPORT_PC();
+
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);       /* length reg */
+        ref = FETCH(1);
+        ILOGV("|new-array v%d,v%d,class@0x%04x  (%d elements)",
+            vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
+        length = (s4) GET_REGISTER(vsrc1);
+        if (length < 0) {
+            dvmThrowNegativeArraySizeException(length);
+            GOTO_exceptionThrown();
+        }
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newArray);
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_FILLED_NEW_ARRAY.cpp */
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
+    GOTO_invoke(filledNewArray, false, false);
+OP_END
+
+/* File: c/OP_FILLED_NEW_ARRAY_RANGE.cpp */
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_RANGE /*{vCCCC..v(CCCC+AA-1)}, class@BBBB*/)
+    GOTO_invoke(filledNewArray, true, false);
+OP_END
+
+/* File: c/OP_FILL_ARRAY_DATA.cpp */
+HANDLE_OPCODE(OP_FILL_ARRAY_DATA)   /*vAA, +BBBBBBBB*/
+    {
+        const u2* arrayData;
+        s4 offset;
+        ArrayObject* arrayObj;
+
+        EXPORT_PC();
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|fill-array-data v%d +0x%04x", vsrc1, offset);
+        arrayData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (arrayData < curMethod->insns ||
+            arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            dvmThrowInternalError("bad fill array data");
+            GOTO_exceptionThrown();
+        }
+#endif
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        if (!dvmInterpHandleFillArrayData(arrayObj, arrayData)) {
+            GOTO_exceptionThrown();
+        }
+        FINISH(3);
+    }
+OP_END
+
+/* File: c/OP_THROW.cpp */
+HANDLE_OPCODE(OP_THROW /*vAA*/)
+    {
+        Object* obj;
+
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);
+        ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
+        obj = (Object*) GET_REGISTER(vsrc1);
+        if (!checkForNull(obj)) {
+            /* will throw a null pointer exception */
+            LOGVV("Bad exception");
+        } else {
+            /* use the requested exception */
+            dvmSetException(self, obj);
+        }
+        GOTO_exceptionThrown();
+    }
+OP_END
+
+/* File: c/OP_GOTO.cpp */
+HANDLE_OPCODE(OP_GOTO /*+AA*/)
+    vdst = INST_AA(inst);
+    if ((s1)vdst < 0)
+        ILOGV("|goto -0x%02x", -((s1)vdst));
+    else
+        ILOGV("|goto +0x%02x", ((s1)vdst));
+    ILOGV("> branch taken");
+    if ((s1)vdst < 0)
+        PERIODIC_CHECKS((s1)vdst);
+    FINISH((s1)vdst);
+OP_END
+
+/* File: c/OP_GOTO_16.cpp */
+HANDLE_OPCODE(OP_GOTO_16 /*+AAAA*/)
+    {
+        s4 offset = (s2) FETCH(1);          /* sign-extend next code unit */
+
+        if (offset < 0)
+            ILOGV("|goto/16 -0x%04x", -offset);
+        else
+            ILOGV("|goto/16 +0x%04x", offset);
+        ILOGV("> branch taken");
+        if (offset < 0)
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_GOTO_32.cpp */
+HANDLE_OPCODE(OP_GOTO_32 /*+AAAAAAAA*/)
+    {
+        s4 offset = FETCH(1);               /* low-order 16 bits */
+        offset |= ((s4) FETCH(2)) << 16;    /* high-order 16 bits */
+
+        if (offset < 0)
+            ILOGV("|goto/32 -0x%08x", -offset);
+        else
+            ILOGV("|goto/32 +0x%08x", offset);
+        ILOGV("> branch taken");
+        if (offset <= 0)    /* allowed to branch to self */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_PACKED_SWITCH.cpp */
+HANDLE_OPCODE(OP_PACKED_SWITCH /*vAA, +BBBB*/)
+    {
+        const u2* switchData;
+        u4 testVal;
+        s4 offset;
+
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
+        switchData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (switchData < curMethod->insns ||
+            switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            EXPORT_PC();
+            dvmThrowInternalError("bad packed switch");
+            GOTO_exceptionThrown();
+        }
+#endif
+        testVal = GET_REGISTER(vsrc1);
+
+        offset = dvmInterpHandlePackedSwitch(switchData, testVal);
+        ILOGV("> branch taken (0x%04x)", offset);
+        if (offset <= 0)  /* uncommon */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_SPARSE_SWITCH.cpp */
+HANDLE_OPCODE(OP_SPARSE_SWITCH /*vAA, +BBBB*/)
+    {
+        const u2* switchData;
+        u4 testVal;
+        s4 offset;
+
+        vsrc1 = INST_AA(inst);
+        offset = FETCH(1) | (((s4) FETCH(2)) << 16);
+        ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
+        switchData = pc + offset;       // offset in 16-bit units
+#ifndef NDEBUG
+        if (switchData < curMethod->insns ||
+            switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
+        {
+            /* should have been caught in verifier */
+            EXPORT_PC();
+            dvmThrowInternalError("bad sparse switch");
+            GOTO_exceptionThrown();
+        }
+#endif
+        testVal = GET_REGISTER(vsrc1);
+
+        offset = dvmInterpHandleSparseSwitch(switchData, testVal);
+        ILOGV("> branch taken (0x%04x)", offset);
+        if (offset <= 0)  /* uncommon */
+            PERIODIC_CHECKS(offset);
+        FINISH(offset);
+    }
+OP_END
+
+/* File: c/OP_CMPL_FLOAT.cpp */
+HANDLE_OP_CMPX(OP_CMPL_FLOAT, "l-float", float, _FLOAT, -1)
+OP_END
+
+/* File: c/OP_CMPG_FLOAT.cpp */
+HANDLE_OP_CMPX(OP_CMPG_FLOAT, "g-float", float, _FLOAT, 1)
+OP_END
+
+/* File: c/OP_CMPL_DOUBLE.cpp */
+HANDLE_OP_CMPX(OP_CMPL_DOUBLE, "l-double", double, _DOUBLE, -1)
+OP_END
+
+/* File: c/OP_CMPG_DOUBLE.cpp */
+HANDLE_OP_CMPX(OP_CMPG_DOUBLE, "g-double", double, _DOUBLE, 1)
+OP_END
+
+/* File: c/OP_CMP_LONG.cpp */
+HANDLE_OP_CMPX(OP_CMP_LONG, "-long", s8, _WIDE, 0)
+OP_END
+
+/* File: c/OP_IF_EQ.cpp */
+HANDLE_OP_IF_XX(OP_IF_EQ, "eq", ==)
+OP_END
+
+/* File: c/OP_IF_NE.cpp */
+HANDLE_OP_IF_XX(OP_IF_NE, "ne", !=)
+OP_END
+
+/* File: c/OP_IF_LT.cpp */
+HANDLE_OP_IF_XX(OP_IF_LT, "lt", <)
+OP_END
+
+/* File: c/OP_IF_GE.cpp */
+HANDLE_OP_IF_XX(OP_IF_GE, "ge", >=)
+OP_END
+
+/* File: c/OP_IF_GT.cpp */
+HANDLE_OP_IF_XX(OP_IF_GT, "gt", >)
+OP_END
+
+/* File: c/OP_IF_LE.cpp */
+HANDLE_OP_IF_XX(OP_IF_LE, "le", <=)
+OP_END
+
+/* File: c/OP_IF_EQZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_EQZ, "eqz", ==)
+OP_END
+
+/* File: c/OP_IF_NEZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_NEZ, "nez", !=)
+OP_END
+
+/* File: c/OP_IF_LTZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_LTZ, "ltz", <)
+OP_END
+
+/* File: c/OP_IF_GEZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_GEZ, "gez", >=)
+OP_END
+
+/* File: c/OP_IF_GTZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_GTZ, "gtz", >)
+OP_END
+
+/* File: c/OP_IF_LEZ.cpp */
+HANDLE_OP_IF_XXZ(OP_IF_LEZ, "lez", <=)
+OP_END
+
+/* File: c/OP_UNUSED_3E.cpp */
+HANDLE_OPCODE(OP_UNUSED_3E)
+OP_END
+
+/* File: c/OP_UNUSED_3F.cpp */
+HANDLE_OPCODE(OP_UNUSED_3F)
+OP_END
+
+/* File: c/OP_UNUSED_40.cpp */
+HANDLE_OPCODE(OP_UNUSED_40)
+OP_END
+
+/* File: c/OP_UNUSED_41.cpp */
+HANDLE_OPCODE(OP_UNUSED_41)
+OP_END
+
+/* File: c/OP_UNUSED_42.cpp */
+HANDLE_OPCODE(OP_UNUSED_42)
+OP_END
+
+/* File: c/OP_UNUSED_43.cpp */
+HANDLE_OPCODE(OP_UNUSED_43)
+OP_END
+
+/* File: c/OP_AGET.cpp */
+HANDLE_OP_AGET(OP_AGET, "", u4, )
+OP_END
+
+/* File: c/OP_AGET_WIDE.cpp */
+HANDLE_OP_AGET(OP_AGET_WIDE, "-wide", s8, _WIDE)
+OP_END
+
+/* File: c/OP_AGET_OBJECT.cpp */
+HANDLE_OP_AGET(OP_AGET_OBJECT, "-object", u4, )
+OP_END
+
+/* File: c/OP_AGET_BOOLEAN.cpp */
+HANDLE_OP_AGET(OP_AGET_BOOLEAN, "-boolean", u1, )
+OP_END
+
+/* File: c/OP_AGET_BYTE.cpp */
+HANDLE_OP_AGET(OP_AGET_BYTE, "-byte", s1, )
+OP_END
+
+/* File: c/OP_AGET_CHAR.cpp */
+HANDLE_OP_AGET(OP_AGET_CHAR, "-char", u2, )
+OP_END
+
+/* File: c/OP_AGET_SHORT.cpp */
+HANDLE_OP_AGET(OP_AGET_SHORT, "-short", s2, )
+OP_END
+
+/* File: c/OP_APUT.cpp */
+HANDLE_OP_APUT(OP_APUT, "", u4, )
+OP_END
+
+/* File: c/OP_APUT_WIDE.cpp */
+HANDLE_OP_APUT(OP_APUT_WIDE, "-wide", s8, _WIDE)
+OP_END
+
+/* File: c/OP_APUT_OBJECT.cpp */
+HANDLE_OPCODE(OP_APUT_OBJECT /*vAA, vBB, vCC*/)
+    {
+        ArrayObject* arrayObj;
+        Object* obj;
+        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", "-object", vdst, vsrc1, vsrc2);
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
+        if (!checkForNull((Object*) arrayObj))
+            GOTO_exceptionThrown();
+        if (GET_REGISTER(vsrc2) >= arrayObj->length) {
+            dvmThrowArrayIndexOutOfBoundsException(
+                arrayObj->length, GET_REGISTER(vsrc2));
+            GOTO_exceptionThrown();
+        }
+        obj = (Object*) GET_REGISTER(vdst);
+        if (obj != NULL) {
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+            if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
+                LOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
+                    obj->clazz->descriptor, obj,
+                    arrayObj->obj.clazz->descriptor, arrayObj);
+                dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
+        dvmSetObjectArrayElement(arrayObj,
+                                 GET_REGISTER(vsrc2),
+                                 (Object *)GET_REGISTER(vdst));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_APUT_BOOLEAN.cpp */
+HANDLE_OP_APUT(OP_APUT_BOOLEAN, "-boolean", u1, )
+OP_END
+
+/* File: c/OP_APUT_BYTE.cpp */
+HANDLE_OP_APUT(OP_APUT_BYTE, "-byte", s1, )
+OP_END
+
+/* File: c/OP_APUT_CHAR.cpp */
+HANDLE_OP_APUT(OP_APUT_CHAR, "-char", u2, )
+OP_END
+
+/* File: c/OP_APUT_SHORT.cpp */
+HANDLE_OP_APUT(OP_APUT_SHORT, "-short", s2, )
+OP_END
+
+/* File: c/OP_IGET.cpp */
+HANDLE_IGET_X(OP_IGET,                  "", Int, )
+OP_END
+
+/* File: c/OP_IGET_WIDE.cpp */
+HANDLE_IGET_X(OP_IGET_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT.cpp */
+HANDLE_IGET_X(OP_IGET_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_BOOLEAN.cpp */
+HANDLE_IGET_X(OP_IGET_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_IGET_BYTE.cpp */
+HANDLE_IGET_X(OP_IGET_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_IGET_CHAR.cpp */
+HANDLE_IGET_X(OP_IGET_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_IGET_SHORT.cpp */
+HANDLE_IGET_X(OP_IGET_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_IPUT.cpp */
+HANDLE_IPUT_X(OP_IPUT,                  "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE.cpp */
+HANDLE_IPUT_X(OP_IPUT_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT.cpp */
+/*
+ * The VM spec says we should verify that the reference being stored into
+ * the field is assignment compatible.  In practice, many popular VMs don't
+ * do this because it slows down a very common operation.  It's not so bad
+ * for us, since "dexopt" quickens it whenever possible, but it's still an
+ * issue.
+ *
+ * To make this spec-complaint, we'd need to add a ClassObject pointer to
+ * the Field struct, resolve the field's type descriptor at link or class
+ * init time, and then verify the type here.
+ */
+HANDLE_IPUT_X(OP_IPUT_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_BOOLEAN.cpp */
+HANDLE_IPUT_X(OP_IPUT_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_BYTE.cpp */
+HANDLE_IPUT_X(OP_IPUT_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_CHAR.cpp */
+HANDLE_IPUT_X(OP_IPUT_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_SHORT.cpp */
+HANDLE_IPUT_X(OP_IPUT_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_SGET.cpp */
+HANDLE_SGET_X(OP_SGET,                  "", Int, )
+OP_END
+
+/* File: c/OP_SGET_WIDE.cpp */
+HANDLE_SGET_X(OP_SGET_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT.cpp */
+HANDLE_SGET_X(OP_SGET_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_BOOLEAN.cpp */
+HANDLE_SGET_X(OP_SGET_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_SGET_BYTE.cpp */
+HANDLE_SGET_X(OP_SGET_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_SGET_CHAR.cpp */
+HANDLE_SGET_X(OP_SGET_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_SGET_SHORT.cpp */
+HANDLE_SGET_X(OP_SGET_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_SPUT.cpp */
+HANDLE_SPUT_X(OP_SPUT,                  "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE.cpp */
+HANDLE_SPUT_X(OP_SPUT_WIDE,             "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT.cpp */
+HANDLE_SPUT_X(OP_SPUT_OBJECT,           "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_BOOLEAN.cpp */
+HANDLE_SPUT_X(OP_SPUT_BOOLEAN,          "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_BYTE.cpp */
+HANDLE_SPUT_X(OP_SPUT_BYTE,             "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_CHAR.cpp */
+HANDLE_SPUT_X(OP_SPUT_CHAR,             "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_SHORT.cpp */
+HANDLE_SPUT_X(OP_SPUT_SHORT,            "", Int, )
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeVirtual, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeSuper, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_DIRECT.cpp */
+HANDLE_OPCODE(OP_INVOKE_DIRECT /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeDirect, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_STATIC.cpp */
+HANDLE_OPCODE(OP_INVOKE_STATIC /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeStatic, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_INTERFACE.cpp */
+HANDLE_OPCODE(OP_INVOKE_INTERFACE /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeInterface, false, false);
+OP_END
+
+/* File: c/OP_UNUSED_73.cpp */
+HANDLE_OPCODE(OP_UNUSED_73)
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeVirtual, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeSuper, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_DIRECT_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_DIRECT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeDirect, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_STATIC_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_STATIC_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeStatic, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_INTERFACE_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_INTERFACE_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeInterface, true, false);
+OP_END
+
+/* File: c/OP_UNUSED_79.cpp */
+HANDLE_OPCODE(OP_UNUSED_79)
+OP_END
+
+/* File: c/OP_UNUSED_7A.cpp */
+HANDLE_OPCODE(OP_UNUSED_7A)
+OP_END
+
+/* File: c/OP_NEG_INT.cpp */
+HANDLE_UNOP(OP_NEG_INT, "neg-int", -, , )
+OP_END
+
+/* File: c/OP_NOT_INT.cpp */
+HANDLE_UNOP(OP_NOT_INT, "not-int", , ^ 0xffffffff, )
+OP_END
+
+/* File: c/OP_NEG_LONG.cpp */
+HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
+OP_END
+
+/* File: c/OP_NOT_LONG.cpp */
+HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
+OP_END
+
+/* File: c/OP_NEG_FLOAT.cpp */
+HANDLE_UNOP(OP_NEG_FLOAT, "neg-float", -, , _FLOAT)
+OP_END
+
+/* File: c/OP_NEG_DOUBLE.cpp */
+HANDLE_UNOP(OP_NEG_DOUBLE, "neg-double", -, , _DOUBLE)
+OP_END
+
+/* File: c/OP_INT_TO_LONG.cpp */
+HANDLE_NUMCONV(OP_INT_TO_LONG,          "int-to-long", _INT, _WIDE)
+OP_END
+
+/* File: c/OP_INT_TO_FLOAT.cpp */
+HANDLE_NUMCONV(OP_INT_TO_FLOAT,         "int-to-float", _INT, _FLOAT)
+OP_END
+
+/* File: c/OP_INT_TO_DOUBLE.cpp */
+HANDLE_NUMCONV(OP_INT_TO_DOUBLE,        "int-to-double", _INT, _DOUBLE)
+OP_END
+
+/* File: c/OP_LONG_TO_INT.cpp */
+HANDLE_NUMCONV(OP_LONG_TO_INT,          "long-to-int", _WIDE, _INT)
+OP_END
+
+/* File: c/OP_LONG_TO_FLOAT.cpp */
+HANDLE_NUMCONV(OP_LONG_TO_FLOAT,        "long-to-float", _WIDE, _FLOAT)
+OP_END
+
+/* File: c/OP_LONG_TO_DOUBLE.cpp */
+HANDLE_NUMCONV(OP_LONG_TO_DOUBLE,       "long-to-double", _WIDE, _DOUBLE)
+OP_END
+
+/* File: c/OP_FLOAT_TO_INT.cpp */
+HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_INT,    "float-to-int",
+    float, _FLOAT, s4, _INT)
+OP_END
+
+/* File: c/OP_FLOAT_TO_LONG.cpp */
+HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_LONG,   "float-to-long",
+    float, _FLOAT, s8, _WIDE)
+OP_END
+
+/* File: c/OP_FLOAT_TO_DOUBLE.cpp */
+HANDLE_NUMCONV(OP_FLOAT_TO_DOUBLE,      "float-to-double", _FLOAT, _DOUBLE)
+OP_END
+
+/* File: c/OP_DOUBLE_TO_INT.cpp */
+HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_INT,   "double-to-int",
+    double, _DOUBLE, s4, _INT)
+OP_END
+
+/* File: c/OP_DOUBLE_TO_LONG.cpp */
+HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_LONG,  "double-to-long",
+    double, _DOUBLE, s8, _WIDE)
+OP_END
+
+/* File: c/OP_DOUBLE_TO_FLOAT.cpp */
+HANDLE_NUMCONV(OP_DOUBLE_TO_FLOAT,      "double-to-float", _DOUBLE, _FLOAT)
+OP_END
+
+/* File: c/OP_INT_TO_BYTE.cpp */
+HANDLE_INT_TO_SMALL(OP_INT_TO_BYTE,     "byte", s1)
+OP_END
+
+/* File: c/OP_INT_TO_CHAR.cpp */
+HANDLE_INT_TO_SMALL(OP_INT_TO_CHAR,     "char", u2)
+OP_END
+
+/* File: c/OP_INT_TO_SHORT.cpp */
+HANDLE_INT_TO_SMALL(OP_INT_TO_SHORT,    "short", s2)    /* want sign bit */
+OP_END
+
+/* File: c/OP_ADD_INT.cpp */
+HANDLE_OP_X_INT(OP_ADD_INT, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_INT.cpp */
+HANDLE_OP_X_INT(OP_SUB_INT, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_INT.cpp */
+HANDLE_OP_X_INT(OP_MUL_INT, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT.cpp */
+HANDLE_OP_X_INT(OP_DIV_INT, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT.cpp */
+HANDLE_OP_X_INT(OP_REM_INT, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT.cpp */
+HANDLE_OP_X_INT(OP_AND_INT, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT.cpp */
+HANDLE_OP_X_INT(OP_OR_INT,  "or",  |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT.cpp */
+HANDLE_OP_X_INT(OP_XOR_INT, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_INT.cpp */
+HANDLE_OP_SHX_INT(OP_SHL_INT, "shl", (s4), <<)
+OP_END
+
+/* File: c/OP_SHR_INT.cpp */
+HANDLE_OP_SHX_INT(OP_SHR_INT, "shr", (s4), >>)
+OP_END
+
+/* File: c/OP_USHR_INT.cpp */
+HANDLE_OP_SHX_INT(OP_USHR_INT, "ushr", (u4), >>)
+OP_END
+
+/* File: c/OP_ADD_LONG.cpp */
+HANDLE_OP_X_LONG(OP_ADD_LONG, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_LONG.cpp */
+HANDLE_OP_X_LONG(OP_SUB_LONG, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_LONG.cpp */
+HANDLE_OP_X_LONG(OP_MUL_LONG, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_LONG.cpp */
+HANDLE_OP_X_LONG(OP_DIV_LONG, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_LONG.cpp */
+HANDLE_OP_X_LONG(OP_REM_LONG, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_LONG.cpp */
+HANDLE_OP_X_LONG(OP_AND_LONG, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_LONG.cpp */
+HANDLE_OP_X_LONG(OP_OR_LONG,  "or", |, 0)
+OP_END
+
+/* File: c/OP_XOR_LONG.cpp */
+HANDLE_OP_X_LONG(OP_XOR_LONG, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_LONG.cpp */
+HANDLE_OP_SHX_LONG(OP_SHL_LONG, "shl", (s8), <<)
+OP_END
+
+/* File: c/OP_SHR_LONG.cpp */
+HANDLE_OP_SHX_LONG(OP_SHR_LONG, "shr", (s8), >>)
+OP_END
+
+/* File: c/OP_USHR_LONG.cpp */
+HANDLE_OP_SHX_LONG(OP_USHR_LONG, "ushr", (u8), >>)
+OP_END
+
+/* File: c/OP_ADD_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_ADD_FLOAT, "add", +)
+OP_END
+
+/* File: c/OP_SUB_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_SUB_FLOAT, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_MUL_FLOAT, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_FLOAT.cpp */
+HANDLE_OP_X_FLOAT(OP_DIV_FLOAT, "div", /)
+OP_END
+
+/* File: c/OP_REM_FLOAT.cpp */
+HANDLE_OPCODE(OP_REM_FLOAT /*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", "mod", vdst, vsrc1, vsrc2);
+        SET_REGISTER_FLOAT(vdst,
+            fmodf(GET_REGISTER_FLOAT(vsrc1), GET_REGISTER_FLOAT(vsrc2)));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_ADD_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_ADD_DOUBLE, "add", +)
+OP_END
+
+/* File: c/OP_SUB_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_SUB_DOUBLE, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_MUL_DOUBLE, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_DOUBLE.cpp */
+HANDLE_OP_X_DOUBLE(OP_DIV_DOUBLE, "div", /)
+OP_END
+
+/* File: c/OP_REM_DOUBLE.cpp */
+HANDLE_OPCODE(OP_REM_DOUBLE /*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", "mod", vdst, vsrc1, vsrc2);
+        SET_REGISTER_DOUBLE(vdst,
+            fmod(GET_REGISTER_DOUBLE(vsrc1), GET_REGISTER_DOUBLE(vsrc2)));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_ADD_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_ADD_INT_2ADDR, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_SUB_INT_2ADDR, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_MUL_INT_2ADDR, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_DIV_INT_2ADDR, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_REM_INT_2ADDR, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_AND_INT_2ADDR, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_OR_INT_2ADDR,  "or", |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT_2ADDR.cpp */
+HANDLE_OP_X_INT_2ADDR(OP_XOR_INT_2ADDR, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_INT_2ADDR.cpp */
+HANDLE_OP_SHX_INT_2ADDR(OP_SHL_INT_2ADDR, "shl", (s4), <<)
+OP_END
+
+/* File: c/OP_SHR_INT_2ADDR.cpp */
+HANDLE_OP_SHX_INT_2ADDR(OP_SHR_INT_2ADDR, "shr", (s4), >>)
+OP_END
+
+/* File: c/OP_USHR_INT_2ADDR.cpp */
+HANDLE_OP_SHX_INT_2ADDR(OP_USHR_INT_2ADDR, "ushr", (u4), >>)
+OP_END
+
+/* File: c/OP_ADD_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_ADD_LONG_2ADDR, "add", +, 0)
+OP_END
+
+/* File: c/OP_SUB_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_SUB_LONG_2ADDR, "sub", -, 0)
+OP_END
+
+/* File: c/OP_MUL_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_MUL_LONG_2ADDR, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_DIV_LONG_2ADDR, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_REM_LONG_2ADDR, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_AND_LONG_2ADDR, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_OR_LONG_2ADDR,  "or", |, 0)
+OP_END
+
+/* File: c/OP_XOR_LONG_2ADDR.cpp */
+HANDLE_OP_X_LONG_2ADDR(OP_XOR_LONG_2ADDR, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_LONG_2ADDR.cpp */
+HANDLE_OP_SHX_LONG_2ADDR(OP_SHL_LONG_2ADDR, "shl", (s8), <<)
+OP_END
+
+/* File: c/OP_SHR_LONG_2ADDR.cpp */
+HANDLE_OP_SHX_LONG_2ADDR(OP_SHR_LONG_2ADDR, "shr", (s8), >>)
+OP_END
+
+/* File: c/OP_USHR_LONG_2ADDR.cpp */
+HANDLE_OP_SHX_LONG_2ADDR(OP_USHR_LONG_2ADDR, "ushr", (u8), >>)
+OP_END
+
+/* File: c/OP_ADD_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_ADD_FLOAT_2ADDR, "add", +)
+OP_END
+
+/* File: c/OP_SUB_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_SUB_FLOAT_2ADDR, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_MUL_FLOAT_2ADDR, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_FLOAT_2ADDR.cpp */
+HANDLE_OP_X_FLOAT_2ADDR(OP_DIV_FLOAT_2ADDR, "div", /)
+OP_END
+
+/* File: c/OP_REM_FLOAT_2ADDR.cpp */
+HANDLE_OPCODE(OP_REM_FLOAT_2ADDR /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|%s-float-2addr v%d,v%d", "mod", vdst, vsrc1);
+    SET_REGISTER_FLOAT(vdst,
+        fmodf(GET_REGISTER_FLOAT(vdst), GET_REGISTER_FLOAT(vsrc1)));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_ADD_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_ADD_DOUBLE_2ADDR, "add", +)
+OP_END
+
+/* File: c/OP_SUB_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_SUB_DOUBLE_2ADDR, "sub", -)
+OP_END
+
+/* File: c/OP_MUL_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_MUL_DOUBLE_2ADDR, "mul", *)
+OP_END
+
+/* File: c/OP_DIV_DOUBLE_2ADDR.cpp */
+HANDLE_OP_X_DOUBLE_2ADDR(OP_DIV_DOUBLE_2ADDR, "div", /)
+OP_END
+
+/* File: c/OP_REM_DOUBLE_2ADDR.cpp */
+HANDLE_OPCODE(OP_REM_DOUBLE_2ADDR /*vA, vB*/)
+    vdst = INST_A(inst);
+    vsrc1 = INST_B(inst);
+    ILOGV("|%s-double-2addr v%d,v%d", "mod", vdst, vsrc1);
+    SET_REGISTER_DOUBLE(vdst,
+        fmod(GET_REGISTER_DOUBLE(vdst), GET_REGISTER_DOUBLE(vsrc1)));
+    FINISH(1);
+OP_END
+
+/* File: c/OP_ADD_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_ADD_INT_LIT16, "add", +, 0)
+OP_END
+
+/* File: c/OP_RSUB_INT.cpp */
+HANDLE_OPCODE(OP_RSUB_INT /*vA, vB, #+CCCC*/)
+    {
+        vdst = INST_A(inst);
+        vsrc1 = INST_B(inst);
+        vsrc2 = FETCH(1);
+        ILOGV("|rsub-int v%d,v%d,#+0x%04x", vdst, vsrc1, vsrc2);
+        SET_REGISTER(vdst, (s2) vsrc2 - (s4) GET_REGISTER(vsrc1));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MUL_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_MUL_INT_LIT16, "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_DIV_INT_LIT16, "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_REM_INT_LIT16, "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_AND_INT_LIT16, "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_OR_INT_LIT16,  "or",  |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT_LIT16.cpp */
+HANDLE_OP_X_INT_LIT16(OP_XOR_INT_LIT16, "xor", ^, 0)
+OP_END
+
+/* File: c/OP_ADD_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_ADD_INT_LIT8,   "add", +, 0)
+OP_END
+
+/* File: c/OP_RSUB_INT_LIT8.cpp */
+HANDLE_OPCODE(OP_RSUB_INT_LIT8 /*vAA, vBB, #+CC*/)
+    {
+        u2 litInfo;
+        vdst = INST_AA(inst);
+        litInfo = FETCH(1);
+        vsrc1 = litInfo & 0xff;
+        vsrc2 = litInfo >> 8;
+        ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", "rsub", vdst, vsrc1, vsrc2);
+        SET_REGISTER(vdst, (s1) vsrc2 - (s4) GET_REGISTER(vsrc1));
+    }
+    FINISH(2);
+OP_END
+
+/* File: c/OP_MUL_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_MUL_INT_LIT8,   "mul", *, 0)
+OP_END
+
+/* File: c/OP_DIV_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_DIV_INT_LIT8,   "div", /, 1)
+OP_END
+
+/* File: c/OP_REM_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_REM_INT_LIT8,   "rem", %, 2)
+OP_END
+
+/* File: c/OP_AND_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_AND_INT_LIT8,   "and", &, 0)
+OP_END
+
+/* File: c/OP_OR_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_OR_INT_LIT8,    "or",  |, 0)
+OP_END
+
+/* File: c/OP_XOR_INT_LIT8.cpp */
+HANDLE_OP_X_INT_LIT8(OP_XOR_INT_LIT8,   "xor", ^, 0)
+OP_END
+
+/* File: c/OP_SHL_INT_LIT8.cpp */
+HANDLE_OP_SHX_INT_LIT8(OP_SHL_INT_LIT8,   "shl", (s4), <<)
+OP_END
+
+/* File: c/OP_SHR_INT_LIT8.cpp */
+HANDLE_OP_SHX_INT_LIT8(OP_SHR_INT_LIT8,   "shr", (s4), >>)
+OP_END
+
+/* File: c/OP_USHR_INT_LIT8.cpp */
+HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8,  "ushr", (u4), >>)
+OP_END
+
+/* File: c/OP_IGET_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_BREAKPOINT.cpp */
+HANDLE_OPCODE(OP_BREAKPOINT)
+    {
+        /*
+         * Restart this instruction with the original opcode.  We do
+         * this by simply jumping to the handler.
+         *
+         * It's probably not necessary to update "inst", but we do it
+         * for the sake of anything that needs to do disambiguation in a
+         * common handler with INST_INST.
+         *
+         * The breakpoint itself is handled over in updateDebugger(),
+         * because we need to detect other events (method entry, single
+         * step) and report them in the same event packet, and we're not
+         * yet handling those through breakpoint instructions.  By the
+         * time we get here, the breakpoint has already been handled and
+         * the thread resumed.
+         */
+        u1 originalOpcode = dvmGetOriginalOpcode(pc);
+        LOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
+            INST_REPLACE_OP(inst, originalOpcode));
+        inst = INST_REPLACE_OP(inst, originalOpcode);
+        FINISH_BKPT(originalOpcode);
+    }
+OP_END
+
+/* File: c/OP_THROW_VERIFICATION_ERROR.cpp */
+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.cpp */
+HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/)
+    {
+        /*
+         * This has the same form as other method calls, but we ignore
+         * the 5th argument (vA).  This is chiefly because the first four
+         * arguments to a function on ARM are in registers.
+         *
+         * We only set the arguments that are actually used, leaving
+         * the rest uninitialized.  We're assuming that, if the method
+         * needs them, they'll be specified in the call.
+         *
+         * However, this annoys gcc when optimizations are enabled,
+         * causing a "may be used uninitialized" warning.  Quieting
+         * the warnings incurs a slight penalty (5%: 373ns vs. 393ns
+         * on empty method).  Note that valgrind is perfectly happy
+         * either way as the uninitialiezd values are never actually
+         * used.
+         */
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_B(inst);       /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* 0-4 register indices */
+        ILOGV("|execute-inline args=%d @%d {regs=0x%04x}",
+            vsrc1, ref, vdst);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst >> 12);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER((vdst & 0x0f00) >> 8);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER((vdst & 0x00f0) >> 4);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst & 0x0f);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_EXECUTE_INLINE_RANGE.cpp */
+HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
+    {
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;      /* placate gcc */
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* range base */
+        ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst+3);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER(vdst+2);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER(vdst+1);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst+0);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(2);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, false);
+        }
+        FINISH(3);
+    }
+OP_END
+
+/* File: c/OP_RETURN_VOID_BARRIER.cpp */
+HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;   /* placate valgrind */
+#endif
+    ANDROID_MEMBAR_STORE();
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_IGET_QUICK.cpp */
+HANDLE_IGET_X_QUICK(OP_IGET_QUICK,          "", Int, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_QUICK.cpp */
+HANDLE_IGET_X_QUICK(OP_IGET_WIDE_QUICK,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_QUICK.cpp */
+HANDLE_IGET_X_QUICK(OP_IGET_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_QUICK.cpp */
+HANDLE_IPUT_X_QUICK(OP_IPUT_QUICK,          "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_QUICK.cpp */
+HANDLE_IPUT_X_QUICK(OP_IPUT_WIDE_QUICK,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_QUICK.cpp */
+HANDLE_IPUT_X_QUICK(OP_IPUT_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_QUICK.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeVirtualQuick, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_QUICK_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK_RANGE/*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeVirtualQuick, true, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_QUICK.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
+    GOTO_invoke(invokeSuperQuick, false, false);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_QUICK_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    GOTO_invoke(invokeSuperQuick, true, false);
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_DISPATCH_FF.cpp */
+HANDLE_OPCODE(OP_DISPATCH_FF)
+    /*
+     * Indicates extended opcode.  Use next 8 bits to choose where to branch.
+     */
+    DISPATCH_EXTENDED(INST_AA(inst));
+OP_END
+
+/* File: c/OP_CONST_CLASS_JUMBO.cpp */
+HANDLE_OPCODE(OP_CONST_CLASS_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        ILOGV("|const-class/jumbo v%d class@0x%08x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            EXPORT_PC();
+            clazz = dvmResolveClass(curMethod->clazz, ref, true);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+        SET_REGISTER(vdst, (u4) clazz);
+    }
+    FINISH(4);
+OP_END
+
+/* File: c/OP_CHECK_CAST_JUMBO.cpp */
+HANDLE_OPCODE(OP_CHECK_CAST_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;     /* class to check against */
+        vsrc1 = FETCH(3);
+        ILOGV("|check-cast/jumbo v%d,class@0x%08x", vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj != NULL) {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNull(obj))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                clazz = dvmResolveClass(curMethod->clazz, ref, false);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            if (!dvmInstanceof(obj->clazz, clazz)) {
+                dvmThrowClassCastException(obj->clazz, clazz);
+                GOTO_exceptionThrown();
+            }
+        }
+    }
+    FINISH(4);
+OP_END
+
+/* File: c/OP_INSTANCE_OF_JUMBO.cpp */
+HANDLE_OPCODE(OP_INSTANCE_OF_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* obj;
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;     /* class to check against */
+        vdst = FETCH(3);
+        vsrc1 = FETCH(4);   /* object to check */
+        ILOGV("|instance-of/jumbo v%d,v%d,class@0x%08x", vdst, vsrc1, ref);
+
+        obj = (Object*)GET_REGISTER(vsrc1);
+        if (obj == NULL) {
+            SET_REGISTER(vdst, 0);
+        } else {
+#if defined(WITH_EXTRA_OBJECT_VALIDATION)
+            if (!checkForNullExportPC(obj, fp, pc))
+                GOTO_exceptionThrown();
+#endif
+            clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+            if (clazz == NULL) {
+                EXPORT_PC();
+                clazz = dvmResolveClass(curMethod->clazz, ref, true);
+                if (clazz == NULL)
+                    GOTO_exceptionThrown();
+            }
+            SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+        }
+    }
+    FINISH(5);
+OP_END
+
+/* File: c/OP_NEW_INSTANCE_JUMBO.cpp */
+HANDLE_OPCODE(OP_NEW_INSTANCE_JUMBO /*vBBBB, class@AAAAAAAA*/)
+    {
+        ClassObject* clazz;
+        Object* newObj;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        ILOGV("|new-instance/jumbo v%d,class@0x%08x", vdst, ref);
+        clazz = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (clazz == NULL) {
+            clazz = dvmResolveClass(curMethod->clazz, ref, false);
+            if (clazz == NULL)
+                GOTO_exceptionThrown();
+        }
+
+        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
+            GOTO_exceptionThrown();
+
+#if defined(WITH_JIT)
+        /*
+         * The JIT needs dvmDexGetResolvedClass() to return non-null.
+         * Since we use the portable interpreter to build the trace, this extra
+         * check is not needed for mterp.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (!dvmDexGetResolvedClass(methodClassDex, ref))) {
+            /* Class initialization is still ongoing - end the trace */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+
+        /*
+         * Verifier now tests for interface/abstract class.
+         */
+        //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+        //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
+        //        clazz->descriptor);
+        //    GOTO_exceptionThrown();
+        //}
+        newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+        if (newObj == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newObj);
+    }
+    FINISH(4);
+OP_END
+
+/* File: c/OP_NEW_ARRAY_JUMBO.cpp */
+HANDLE_OPCODE(OP_NEW_ARRAY_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        s4 length;
+
+        EXPORT_PC();
+
+        ref = FETCH(1) | (u4)FETCH(2) << 16;
+        vdst = FETCH(3);
+        vsrc1 = FETCH(4);       /* length reg */
+        ILOGV("|new-array/jumbo v%d,v%d,class@0x%08x  (%d elements)",
+            vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
+        length = (s4) GET_REGISTER(vsrc1);
+        if (length < 0) {
+            dvmThrowNegativeArraySizeException(length);
+            GOTO_exceptionThrown();
+        }
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+        SET_REGISTER(vdst, (u4) newArray);
+    }
+    FINISH(5);
+OP_END
+
+/* File: c/OP_FILLED_NEW_ARRAY_JUMBO.cpp */
+HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, class@AAAAAAAA*/)
+    GOTO_invoke(filledNewArray, true, true);
+OP_END
+
+/* File: c/OP_IGET_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_BOOLEAN_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_BOOLEAN_JUMBO,  "", Int, )
+OP_END
+
+/* File: c/OP_IGET_BYTE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IGET_CHAR_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IGET_SHORT_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_JUMBO.cpp */
+/*
+ * The VM spec says we should verify that the reference being stored into
+ * the field is assignment compatible.  In practice, many popular VMs don't
+ * do this because it slows down a very common operation.  It's not so bad
+ * for us, since "dexopt" quickens it whenever possible, but it's still an
+ * issue.
+ *
+ * To make this spec-complaint, we'd need to add a ClassObject pointer to
+ * the Field struct, resolve the field's type descriptor at link or class
+ * init time, and then verify the type here.
+ */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_BOOLEAN_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_BOOLEAN_JUMBO,  "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_BYTE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_CHAR_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_IPUT_SHORT_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_SGET_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_SGET_WIDE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_BOOLEAN_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_BOOLEAN_JUMBO,  "", Int, )
+OP_END
+
+/* File: c/OP_SGET_BYTE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SGET_CHAR_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SGET_SHORT_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_JUMBO,     "-wide", Long, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_JUMBO,   "-object", Object, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_BOOLEAN_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_BOOLEAN_JUMBO,          "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_BYTE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_BYTE_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_CHAR_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_CHAR_JUMBO,     "", Int, )
+OP_END
+
+/* File: c/OP_SPUT_SHORT_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_SHORT_JUMBO,    "", Int, )
+OP_END
+
+/* File: c/OP_INVOKE_VIRTUAL_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_VIRTUAL_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeVirtual, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_SUPER_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_SUPER_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeSuper, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_DIRECT_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_DIRECT_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeDirect, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_STATIC_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_STATIC_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeStatic, true, true);
+OP_END
+
+/* File: c/OP_INVOKE_INTERFACE_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_INTERFACE_JUMBO /*{vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA*/)
+    GOTO_invoke(invokeInterface, true, true);
+OP_END
+
+/* File: c/OP_UNUSED_27FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_27FF)
+OP_END
+
+/* File: c/OP_UNUSED_28FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_28FF)
+OP_END
+
+/* File: c/OP_UNUSED_29FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_29FF)
+OP_END
+
+/* File: c/OP_UNUSED_2AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2AFF)
+OP_END
+
+/* File: c/OP_UNUSED_2BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2BFF)
+OP_END
+
+/* File: c/OP_UNUSED_2CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2CFF)
+OP_END
+
+/* File: c/OP_UNUSED_2DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2DFF)
+OP_END
+
+/* File: c/OP_UNUSED_2EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2EFF)
+OP_END
+
+/* File: c/OP_UNUSED_2FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_2FFF)
+OP_END
+
+/* File: c/OP_UNUSED_30FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_30FF)
+OP_END
+
+/* File: c/OP_UNUSED_31FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_31FF)
+OP_END
+
+/* File: c/OP_UNUSED_32FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_32FF)
+OP_END
+
+/* File: c/OP_UNUSED_33FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_33FF)
+OP_END
+
+/* File: c/OP_UNUSED_34FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_34FF)
+OP_END
+
+/* File: c/OP_UNUSED_35FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_35FF)
+OP_END
+
+/* File: c/OP_UNUSED_36FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_36FF)
+OP_END
+
+/* File: c/OP_UNUSED_37FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_37FF)
+OP_END
+
+/* File: c/OP_UNUSED_38FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_38FF)
+OP_END
+
+/* File: c/OP_UNUSED_39FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_39FF)
+OP_END
+
+/* File: c/OP_UNUSED_3AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3AFF)
+OP_END
+
+/* File: c/OP_UNUSED_3BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3BFF)
+OP_END
+
+/* File: c/OP_UNUSED_3CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3CFF)
+OP_END
+
+/* File: c/OP_UNUSED_3DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3DFF)
+OP_END
+
+/* File: c/OP_UNUSED_3EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3EFF)
+OP_END
+
+/* File: c/OP_UNUSED_3FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_3FFF)
+OP_END
+
+/* File: c/OP_UNUSED_40FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_40FF)
+OP_END
+
+/* File: c/OP_UNUSED_41FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_41FF)
+OP_END
+
+/* File: c/OP_UNUSED_42FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_42FF)
+OP_END
+
+/* File: c/OP_UNUSED_43FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_43FF)
+OP_END
+
+/* File: c/OP_UNUSED_44FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_44FF)
+OP_END
+
+/* File: c/OP_UNUSED_45FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_45FF)
+OP_END
+
+/* File: c/OP_UNUSED_46FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_46FF)
+OP_END
+
+/* File: c/OP_UNUSED_47FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_47FF)
+OP_END
+
+/* File: c/OP_UNUSED_48FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_48FF)
+OP_END
+
+/* File: c/OP_UNUSED_49FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_49FF)
+OP_END
+
+/* File: c/OP_UNUSED_4AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4AFF)
+OP_END
+
+/* File: c/OP_UNUSED_4BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4BFF)
+OP_END
+
+/* File: c/OP_UNUSED_4CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4CFF)
+OP_END
+
+/* File: c/OP_UNUSED_4DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4DFF)
+OP_END
+
+/* File: c/OP_UNUSED_4EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4EFF)
+OP_END
+
+/* File: c/OP_UNUSED_4FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_4FFF)
+OP_END
+
+/* File: c/OP_UNUSED_50FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_50FF)
+OP_END
+
+/* File: c/OP_UNUSED_51FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_51FF)
+OP_END
+
+/* File: c/OP_UNUSED_52FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_52FF)
+OP_END
+
+/* File: c/OP_UNUSED_53FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_53FF)
+OP_END
+
+/* File: c/OP_UNUSED_54FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_54FF)
+OP_END
+
+/* File: c/OP_UNUSED_55FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_55FF)
+OP_END
+
+/* File: c/OP_UNUSED_56FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_56FF)
+OP_END
+
+/* File: c/OP_UNUSED_57FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_57FF)
+OP_END
+
+/* File: c/OP_UNUSED_58FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_58FF)
+OP_END
+
+/* File: c/OP_UNUSED_59FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_59FF)
+OP_END
+
+/* File: c/OP_UNUSED_5AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5AFF)
+OP_END
+
+/* File: c/OP_UNUSED_5BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5BFF)
+OP_END
+
+/* File: c/OP_UNUSED_5CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5CFF)
+OP_END
+
+/* File: c/OP_UNUSED_5DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5DFF)
+OP_END
+
+/* File: c/OP_UNUSED_5EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5EFF)
+OP_END
+
+/* File: c/OP_UNUSED_5FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_5FFF)
+OP_END
+
+/* File: c/OP_UNUSED_60FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_60FF)
+OP_END
+
+/* File: c/OP_UNUSED_61FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_61FF)
+OP_END
+
+/* File: c/OP_UNUSED_62FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_62FF)
+OP_END
+
+/* File: c/OP_UNUSED_63FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_63FF)
+OP_END
+
+/* File: c/OP_UNUSED_64FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_64FF)
+OP_END
+
+/* File: c/OP_UNUSED_65FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_65FF)
+OP_END
+
+/* File: c/OP_UNUSED_66FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_66FF)
+OP_END
+
+/* File: c/OP_UNUSED_67FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_67FF)
+OP_END
+
+/* File: c/OP_UNUSED_68FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_68FF)
+OP_END
+
+/* File: c/OP_UNUSED_69FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_69FF)
+OP_END
+
+/* File: c/OP_UNUSED_6AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6AFF)
+OP_END
+
+/* File: c/OP_UNUSED_6BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6BFF)
+OP_END
+
+/* File: c/OP_UNUSED_6CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6CFF)
+OP_END
+
+/* File: c/OP_UNUSED_6DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6DFF)
+OP_END
+
+/* File: c/OP_UNUSED_6EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6EFF)
+OP_END
+
+/* File: c/OP_UNUSED_6FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_6FFF)
+OP_END
+
+/* File: c/OP_UNUSED_70FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_70FF)
+OP_END
+
+/* File: c/OP_UNUSED_71FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_71FF)
+OP_END
+
+/* File: c/OP_UNUSED_72FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_72FF)
+OP_END
+
+/* File: c/OP_UNUSED_73FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_73FF)
+OP_END
+
+/* File: c/OP_UNUSED_74FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_74FF)
+OP_END
+
+/* File: c/OP_UNUSED_75FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_75FF)
+OP_END
+
+/* File: c/OP_UNUSED_76FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_76FF)
+OP_END
+
+/* File: c/OP_UNUSED_77FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_77FF)
+OP_END
+
+/* File: c/OP_UNUSED_78FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_78FF)
+OP_END
+
+/* File: c/OP_UNUSED_79FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_79FF)
+OP_END
+
+/* File: c/OP_UNUSED_7AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7AFF)
+OP_END
+
+/* File: c/OP_UNUSED_7BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7BFF)
+OP_END
+
+/* File: c/OP_UNUSED_7CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7CFF)
+OP_END
+
+/* File: c/OP_UNUSED_7DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7DFF)
+OP_END
+
+/* File: c/OP_UNUSED_7EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7EFF)
+OP_END
+
+/* File: c/OP_UNUSED_7FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_7FFF)
+OP_END
+
+/* File: c/OP_UNUSED_80FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_80FF)
+OP_END
+
+/* File: c/OP_UNUSED_81FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_81FF)
+OP_END
+
+/* File: c/OP_UNUSED_82FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_82FF)
+OP_END
+
+/* File: c/OP_UNUSED_83FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_83FF)
+OP_END
+
+/* File: c/OP_UNUSED_84FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_84FF)
+OP_END
+
+/* File: c/OP_UNUSED_85FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_85FF)
+OP_END
+
+/* File: c/OP_UNUSED_86FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_86FF)
+OP_END
+
+/* File: c/OP_UNUSED_87FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_87FF)
+OP_END
+
+/* File: c/OP_UNUSED_88FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_88FF)
+OP_END
+
+/* File: c/OP_UNUSED_89FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_89FF)
+OP_END
+
+/* File: c/OP_UNUSED_8AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8AFF)
+OP_END
+
+/* File: c/OP_UNUSED_8BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8BFF)
+OP_END
+
+/* File: c/OP_UNUSED_8CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8CFF)
+OP_END
+
+/* File: c/OP_UNUSED_8DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8DFF)
+OP_END
+
+/* File: c/OP_UNUSED_8EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8EFF)
+OP_END
+
+/* File: c/OP_UNUSED_8FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_8FFF)
+OP_END
+
+/* File: c/OP_UNUSED_90FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_90FF)
+OP_END
+
+/* File: c/OP_UNUSED_91FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_91FF)
+OP_END
+
+/* File: c/OP_UNUSED_92FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_92FF)
+OP_END
+
+/* File: c/OP_UNUSED_93FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_93FF)
+OP_END
+
+/* File: c/OP_UNUSED_94FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_94FF)
+OP_END
+
+/* File: c/OP_UNUSED_95FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_95FF)
+OP_END
+
+/* File: c/OP_UNUSED_96FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_96FF)
+OP_END
+
+/* File: c/OP_UNUSED_97FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_97FF)
+OP_END
+
+/* File: c/OP_UNUSED_98FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_98FF)
+OP_END
+
+/* File: c/OP_UNUSED_99FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_99FF)
+OP_END
+
+/* File: c/OP_UNUSED_9AFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9AFF)
+OP_END
+
+/* File: c/OP_UNUSED_9BFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9BFF)
+OP_END
+
+/* File: c/OP_UNUSED_9CFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9CFF)
+OP_END
+
+/* File: c/OP_UNUSED_9DFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9DFF)
+OP_END
+
+/* File: c/OP_UNUSED_9EFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9EFF)
+OP_END
+
+/* File: c/OP_UNUSED_9FFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_9FFF)
+OP_END
+
+/* File: c/OP_UNUSED_A0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A0FF)
+OP_END
+
+/* File: c/OP_UNUSED_A1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A1FF)
+OP_END
+
+/* File: c/OP_UNUSED_A2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A2FF)
+OP_END
+
+/* File: c/OP_UNUSED_A3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A3FF)
+OP_END
+
+/* File: c/OP_UNUSED_A4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A4FF)
+OP_END
+
+/* File: c/OP_UNUSED_A5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A5FF)
+OP_END
+
+/* File: c/OP_UNUSED_A6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A6FF)
+OP_END
+
+/* File: c/OP_UNUSED_A7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A7FF)
+OP_END
+
+/* File: c/OP_UNUSED_A8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A8FF)
+OP_END
+
+/* File: c/OP_UNUSED_A9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_A9FF)
+OP_END
+
+/* File: c/OP_UNUSED_AAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_AAFF)
+OP_END
+
+/* File: c/OP_UNUSED_ABFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ABFF)
+OP_END
+
+/* File: c/OP_UNUSED_ACFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ACFF)
+OP_END
+
+/* File: c/OP_UNUSED_ADFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ADFF)
+OP_END
+
+/* File: c/OP_UNUSED_AEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_AEFF)
+OP_END
+
+/* File: c/OP_UNUSED_AFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_AFFF)
+OP_END
+
+/* File: c/OP_UNUSED_B0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B0FF)
+OP_END
+
+/* File: c/OP_UNUSED_B1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B1FF)
+OP_END
+
+/* File: c/OP_UNUSED_B2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B2FF)
+OP_END
+
+/* File: c/OP_UNUSED_B3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B3FF)
+OP_END
+
+/* File: c/OP_UNUSED_B4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B4FF)
+OP_END
+
+/* File: c/OP_UNUSED_B5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B5FF)
+OP_END
+
+/* File: c/OP_UNUSED_B6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B6FF)
+OP_END
+
+/* File: c/OP_UNUSED_B7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B7FF)
+OP_END
+
+/* File: c/OP_UNUSED_B8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B8FF)
+OP_END
+
+/* File: c/OP_UNUSED_B9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_B9FF)
+OP_END
+
+/* File: c/OP_UNUSED_BAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BAFF)
+OP_END
+
+/* File: c/OP_UNUSED_BBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BBFF)
+OP_END
+
+/* File: c/OP_UNUSED_BCFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BCFF)
+OP_END
+
+/* File: c/OP_UNUSED_BDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BDFF)
+OP_END
+
+/* File: c/OP_UNUSED_BEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BEFF)
+OP_END
+
+/* File: c/OP_UNUSED_BFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_BFFF)
+OP_END
+
+/* File: c/OP_UNUSED_C0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C0FF)
+OP_END
+
+/* File: c/OP_UNUSED_C1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C1FF)
+OP_END
+
+/* File: c/OP_UNUSED_C2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C2FF)
+OP_END
+
+/* File: c/OP_UNUSED_C3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C3FF)
+OP_END
+
+/* File: c/OP_UNUSED_C4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C4FF)
+OP_END
+
+/* File: c/OP_UNUSED_C5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C5FF)
+OP_END
+
+/* File: c/OP_UNUSED_C6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C6FF)
+OP_END
+
+/* File: c/OP_UNUSED_C7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C7FF)
+OP_END
+
+/* File: c/OP_UNUSED_C8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C8FF)
+OP_END
+
+/* File: c/OP_UNUSED_C9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_C9FF)
+OP_END
+
+/* File: c/OP_UNUSED_CAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CAFF)
+OP_END
+
+/* File: c/OP_UNUSED_CBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CBFF)
+OP_END
+
+/* File: c/OP_UNUSED_CCFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CCFF)
+OP_END
+
+/* File: c/OP_UNUSED_CDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CDFF)
+OP_END
+
+/* File: c/OP_UNUSED_CEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CEFF)
+OP_END
+
+/* File: c/OP_UNUSED_CFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_CFFF)
+OP_END
+
+/* File: c/OP_UNUSED_D0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D0FF)
+OP_END
+
+/* File: c/OP_UNUSED_D1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D1FF)
+OP_END
+
+/* File: c/OP_UNUSED_D2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D2FF)
+OP_END
+
+/* File: c/OP_UNUSED_D3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D3FF)
+OP_END
+
+/* File: c/OP_UNUSED_D4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D4FF)
+OP_END
+
+/* File: c/OP_UNUSED_D5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D5FF)
+OP_END
+
+/* File: c/OP_UNUSED_D6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D6FF)
+OP_END
+
+/* File: c/OP_UNUSED_D7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D7FF)
+OP_END
+
+/* File: c/OP_UNUSED_D8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D8FF)
+OP_END
+
+/* File: c/OP_UNUSED_D9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_D9FF)
+OP_END
+
+/* File: c/OP_UNUSED_DAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DAFF)
+OP_END
+
+/* File: c/OP_UNUSED_DBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DBFF)
+OP_END
+
+/* File: c/OP_UNUSED_DCFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DCFF)
+OP_END
+
+/* File: c/OP_UNUSED_DDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DDFF)
+OP_END
+
+/* File: c/OP_UNUSED_DEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DEFF)
+OP_END
+
+/* File: c/OP_UNUSED_DFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_DFFF)
+OP_END
+
+/* File: c/OP_UNUSED_E0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E0FF)
+OP_END
+
+/* File: c/OP_UNUSED_E1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E1FF)
+OP_END
+
+/* File: c/OP_UNUSED_E2FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E2FF)
+OP_END
+
+/* File: c/OP_UNUSED_E3FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E3FF)
+OP_END
+
+/* File: c/OP_UNUSED_E4FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E4FF)
+OP_END
+
+/* File: c/OP_UNUSED_E5FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E5FF)
+OP_END
+
+/* File: c/OP_UNUSED_E6FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E6FF)
+OP_END
+
+/* File: c/OP_UNUSED_E7FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E7FF)
+OP_END
+
+/* File: c/OP_UNUSED_E8FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E8FF)
+OP_END
+
+/* File: c/OP_UNUSED_E9FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_E9FF)
+OP_END
+
+/* File: c/OP_UNUSED_EAFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EAFF)
+OP_END
+
+/* File: c/OP_UNUSED_EBFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EBFF)
+OP_END
+
+/* File: c/OP_UNUSED_ECFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_ECFF)
+OP_END
+
+/* File: c/OP_UNUSED_EDFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EDFF)
+OP_END
+
+/* File: c/OP_UNUSED_EEFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EEFF)
+OP_END
+
+/* File: c/OP_UNUSED_EFFF.cpp */
+HANDLE_OPCODE(OP_UNUSED_EFFF)
+OP_END
+
+/* File: c/OP_UNUSED_F0FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_F0FF)
+OP_END
+
+/* File: c/OP_UNUSED_F1FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_F1FF)
+    /*
+     * In portable interp, most unused opcodes will fall through to here.
+     */
+    LOGE("unknown opcode 0x%04x", inst);
+    dvmAbort();
+    FINISH(1);
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_JUMBO /*{vCCCC..vNNNN}, meth@AAAAAAAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(4);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, true);
+        }
+        FINISH(5);
+    }
+OP_END
+
+/* File: c/OP_IGET_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_VOLATILE_JUMBO, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_THROW_VERIFICATION_ERROR_JUMBO.cpp */
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR_JUMBO)
+    EXPORT_PC();
+    vsrc1 = FETCH(3);
+    ref = FETCH(1) | (u4)FETCH(2) << 16;      /* class/field/method ref */
+    dvmThrowVerificationError(curMethod, vsrc1, ref);
+    GOTO_exceptionThrown();
+OP_END
+
+/* File: c/gotoTargets.cpp */
+/*
+ * C footer.  This has some common code shared by the various targets.
+ */
+
+/*
+ * Everything from here on is a "goto target".  In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction.  Here, these are subroutines that return to the caller.
+ */
+
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool jumboFormat)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        u4* contents;
+        char typeCh;
+        int i;
+        u4 arg5;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* class ref */
+            vsrc1 = FETCH(3);                     /* #of elements */
+            vdst = FETCH(4);                      /* range base */
+            arg5 = -1;                            /* silence compiler warning */
+            ILOGV("|filled-new-array/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        } else {
+            ref = FETCH(1);             /* class ref */
+            vdst = FETCH(2);            /* first 4 regs -or- range base */
+
+            if (methodCallRange) {
+                vsrc1 = INST_AA(inst);  /* #of elements */
+                arg5 = -1;              /* silence compiler warning */
+                ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+            } else {
+                arg5 = INST_A(inst);
+                vsrc1 = INST_B(inst);   /* #of elements */
+                ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
+                   vsrc1, ref, vdst, arg5);
+            }
+        }
+
+        /*
+         * Resolve the array class.
+         */
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /*
+        if (!dvmIsArrayClass(arrayClass)) {
+            dvmThrowRuntimeException(
+                "filled-new-array needs array class");
+            GOTO_exceptionThrown();
+        }
+        */
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        /*
+         * Create an array of the specified type.
+         */
+        LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
+        typeCh = arrayClass->descriptor[1];
+        if (typeCh == 'D' || typeCh == 'J') {
+            /* category 2 primitives not allowed */
+            dvmThrowRuntimeException("bad filled array req");
+            GOTO_exceptionThrown();
+        } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
+            /* TODO: requires multiple "fill in" loops with different widths */
+            LOGE("non-int primitives not implemented");
+            dvmThrowInternalError(
+                "filled-new-array not implemented for anything but 'int'");
+            GOTO_exceptionThrown();
+        }
+
+        newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+
+        /*
+         * Fill in the elements.  It's legal for vsrc1 to be zero.
+         */
+        contents = (u4*)(void*)newArray->contents;
+        if (methodCallRange) {
+            for (i = 0; i < vsrc1; i++)
+                contents[i] = GET_REGISTER(vdst+i);
+        } else {
+            assert(vsrc1 <= 5);
+            if (vsrc1 == 5) {
+                contents[4] = GET_REGISTER(arg5);
+                vsrc1--;
+            }
+            for (i = 0; i < vsrc1; i++) {
+                contents[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+        }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
+
+        retval.l = (Object*)newArray;
+    }
+    if (jumboFormat) {
+        FINISH(5);
+    } else {
+        FINISH(3);
+    }
+GOTO_TARGET_END
+
+
+GOTO_TARGET(invokeVirtual, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-virtual/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->methodToCall = methodToCall;
+        self->callsiteClass = thisPtr->clazz;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            /*
+             * This can happen if you create two classes, Base and Sub, where
+             * Sub is a sub-class of Base.  Declare a protected abstract
+             * method foo() in Base, and invoke foo() from a method in Base.
+             * Base is an "abstract base class" and is never instantiated
+             * directly.  Now, Override foo() in Sub, and use Sub.  This
+             * Works fine unless Sub stops providing an implementation of
+             * the method.
+             */
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            (u4) baseMethod->methodIndex,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+#if 0
+        if (vsrc1 != methodToCall->insSize) {
+            LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
+                baseMethod->clazz->descriptor, baseMethod->name,
+                (u4) baseMethod->methodIndex,
+                methodToCall->clazz->descriptor, methodToCall->name);
+            //dvmDumpClass(baseMethod->clazz);
+            //dvmDumpClass(methodToCall->clazz);
+            dvmDumpAllClasses(0);
+        }
+#endif
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuper, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-super/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         * The first arg to dvmResolveMethod() is just the referring class
+         * (used for class loaders and such), so we don't want to pass
+         * the superclass into the resolution call.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in that class' superclass.
+         */
+        if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
+            /*
+             * Method does not exist in the superclass.  Could happen if
+             * superclass gets updated.
+             */
+            dvmThrowNoSuchMethodError(baseMethod->name);
+            GOTO_exceptionThrown();
+        }
+        methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ base=%s.%s super-virtual=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeInterface, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+        ClassObject* thisClass;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-interface/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        thisClass = thisPtr->clazz;
+
+
+        /*
+         * Given a class and a method index, find the Method* with the
+         * actual code we want to execute.
+         */
+        methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
+                        methodClassDex);
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisClass;
+        self->methodToCall = methodToCall;
+#endif
+        if (methodToCall == NULL) {
+            assert(dvmCheckException(self));
+            GOTO_exceptionThrown();
+        }
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeDirect, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-direct/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (methodToCall == NULL) {
+            methodToCall = dvmResolveMethod(curMethod->clazz, ref,
+                            METHOD_DIRECT);
+            if (methodToCall == NULL) {
+                ILOGV("+ unknown direct method");     // should be impossible
+                GOTO_exceptionThrown();
+            }
+        }
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeStatic, bool methodCallRange, bool jumboFormat)
+    EXPORT_PC();
+
+    if (jumboFormat) {
+        ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+        vsrc1 = FETCH(3);                     /* count */
+        vdst = FETCH(4);                      /* first reg */
+        ADJUST_PC(2);     /* advance pc partially to make returns easier */
+        ILOGV("|invoke-static/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+    } else {
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* method ref */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange)
+            ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        else
+            ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+    }
+
+    methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+    if (methodToCall == NULL) {
+        methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
+        if (methodToCall == NULL) {
+            ILOGV("+ unknown method");
+            GOTO_exceptionThrown();
+        }
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        /*
+         * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+         * Include the check if this code is being used as a stub
+         * called from the assembly interpreter.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
+            /* Class initialization is still ongoing */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+    }
+    GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeVirtualQuick, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        /*
+         * The object against which we are executing a method is always
+         * in the first argument.
+         */
+        if (methodCallRange) {
+            assert(vsrc1 > 0);
+            ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            assert((vsrc1>>4) > 0);
+            ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[ref];
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisPtr->clazz;
+        self->methodToCall = methodToCall;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuperQuick, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange) {
+            ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisReg = vdst & 0x0f;
+        }
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+#if 0   /* impossible in optimized + verified code */
+        if (ref >= curMethod->clazz->super->vtableCount) {
+            dvmThrowNoSuchMethodError(NULL);
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
+#endif
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in the method's class' superclass.
+         */
+        methodToCall = curMethod->clazz->super->vtable[ref];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ super-virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * General handling for return-void, return, and return-wide.  Put the
+     * return value in "retval" before jumping here.
+     */
+GOTO_TARGET(returnFromMethod)
+    {
+        StackSaveArea* saveArea;
+
+        /*
+         * We must do this BEFORE we pop the previous stack frame off, so
+         * that the GC can see the return value (if any) in the local vars.
+         *
+         * Since this is now an interpreter switch point, we must do it before
+         * we do anything at all.
+         */
+        PERIODIC_CHECKS(0);
+
+        ILOGV("> retval=0x%llx (leaving %s.%s %s)",
+            retval.j, curMethod->clazz->descriptor, curMethod->name,
+            curMethod->shorty);
+        //DUMP_REGS(curMethod, fp);
+
+        saveArea = SAVEAREA_FROM_FP(fp);
+
+#ifdef EASY_GDB
+        debugSaveArea = saveArea;
+#endif
+
+        /* back up to previous frame and see if we hit a break */
+        fp = (u4*)saveArea->prevFrame;
+        assert(fp != NULL);
+
+        /* Handle any special subMode requirements */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportReturn(self);
+        }
+
+        if (dvmIsBreakFrame(fp)) {
+            /* bail without popping the method frame from stack */
+            LOGVV("+++ returned into break frame");
+            GOTO_bail();
+        }
+
+        /* update thread FP, and reset local variables */
+        self->interpSave.curFrame = fp;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = saveArea->savedPc;
+        ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+
+        /* use FINISH on the caller's invoke instruction */
+        //u2 invokeInstr = INST_INST(FETCH(0));
+        if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+            invokeInstr <= OP_INVOKE_INTERFACE*/)
+        {
+            FINISH(3);
+        } else {
+            //LOGE("Unknown invoke instr %02x at %d",
+            //    invokeInstr, (int) (pc - curMethod->insns));
+            assert(false);
+        }
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * Jump here when the code throws an exception.
+     *
+     * By the time we get here, the Throwable has been created and the stack
+     * trace has been saved off.
+     */
+GOTO_TARGET(exceptionThrown)
+    {
+        Object* exception;
+        int catchRelPc;
+
+        PERIODIC_CHECKS(0);
+
+        /*
+         * We save off the exception and clear the exception status.  While
+         * processing the exception we might need to load some Throwable
+         * classes, and we don't want class loader exceptions to get
+         * confused with this one.
+         */
+        assert(dvmCheckException(self));
+        exception = dvmGetException(self);
+        dvmAddTrackedAlloc(exception, self);
+        dvmClearException(self);
+
+        LOGV("Handling exception %s at %s:%d",
+            exception->clazz->descriptor, curMethod->name,
+            dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+
+        /*
+         * Report the exception throw to any "subMode" watchers.
+         *
+         * TODO: if the exception was thrown by interpreted code, control
+         * fell through native, and then back to us, we will report the
+         * exception at the point of the throw and again here.  We can avoid
+         * this by not reporting exceptions when we jump here directly from
+         * the native call code above, but then we won't report exceptions
+         * that were thrown *from* the JNI code (as opposed to *through* it).
+         *
+         * The correct solution is probably to ignore from-native exceptions
+         * here, and have the JNI exception code do the reporting to the
+         * debugger.
+         */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportExceptionThrow(self, exception);
+        }
+
+        /*
+         * We need to unroll to the catch block or the nearest "break"
+         * frame.
+         *
+         * A break frame could indicate that we have reached an intermediate
+         * native call, or have gone off the top of the stack and the thread
+         * needs to exit.  Either way, we return from here, leaving the
+         * exception raised.
+         *
+         * If we do find a catch block, we want to transfer execution to
+         * that point.
+         *
+         * Note this can cause an exception while resolving classes in
+         * the "catch" blocks.
+         */
+        catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
+                    exception, false, (void**)(void*)&fp);
+
+        /*
+         * Restore the stack bounds after an overflow.  This isn't going to
+         * be correct in all circumstances, e.g. if JNI code devours the
+         * exception this won't happen until some other exception gets
+         * thrown.  If the code keeps pushing the stack bounds we'll end
+         * up aborting the VM.
+         *
+         * Note we want to do this *after* the call to dvmFindCatchBlock,
+         * because that may need extra stack space to resolve exception
+         * classes (e.g. through a class loader).
+         *
+         * It's possible for the stack overflow handling to cause an
+         * exception (specifically, class resolution in a "catch" block
+         * during the call above), so we could see the thread's overflow
+         * flag raised but actually be running in a "nested" interpreter
+         * frame.  We don't allow doubled-up StackOverflowErrors, so
+         * we can check for this by just looking at the exception type
+         * in the cleanup function.  Also, we won't unroll past the SOE
+         * point because the more-recent exception will hit a break frame
+         * as it unrolls to here.
+         */
+        if (self->stackOverflowed)
+            dvmCleanupStackOverflow(self, exception);
+
+        if (catchRelPc < 0) {
+            /* falling through to JNI code or off the bottom of the stack */
+#if DVM_SHOW_EXCEPTION >= 2
+            LOGD("Exception %s from %s:%d not caught locally",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+#endif
+            dvmSetException(self, exception);
+            dvmReleaseTrackedAlloc(exception, self);
+            GOTO_bail();
+        }
+
+#if DVM_SHOW_EXCEPTION >= 3
+        {
+            const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
+            LOGD("Exception %s thrown from %s:%d to %s:%d",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns),
+                dvmGetMethodSourceFile(catchMethod),
+                dvmLineNumFromPC(catchMethod, catchRelPc));
+        }
+#endif
+
+        /*
+         * Adjust local variables to match self->interpSave.curFrame and the
+         * updated PC.
+         */
+        //fp = (u4*) self->interpSave.curFrame;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = curMethod->insns + catchRelPc;
+        ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+        DUMP_REGS(curMethod, fp, false);            // show all regs
+
+        /*
+         * Restore the exception if the handler wants it.
+         *
+         * The Dalvik spec mandates that, if an exception handler wants to
+         * do something with the exception, the first instruction executed
+         * must be "move-exception".  We can pass the exception along
+         * through the thread struct, and let the move-exception instruction
+         * clear it for us.
+         *
+         * If the handler doesn't call move-exception, we don't want to
+         * finish here with an exception still pending.
+         */
+        if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
+            dvmSetException(self, exception);
+
+        dvmReleaseTrackedAlloc(exception, self);
+        FINISH(0);
+    }
+GOTO_TARGET_END
+
+
+
+    /*
+     * General handling for invoke-{virtual,super,direct,static,interface},
+     * including "quick" variants.
+     *
+     * Set "methodToCall" to the Method we're calling, and "methodCallRange"
+     * depending on whether this is a "/range" instruction.
+     *
+     * For a range call:
+     *  "vsrc1" holds the argument count (8 bits)
+     *  "vdst" holds the first argument in the range
+     * For a non-range call:
+     *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
+     *  "vdst" holds four 4-bit register indices
+     *
+     * The caller must EXPORT_PC before jumping here, because any method
+     * call can throw a stack overflow exception.
+     */
+GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
+    u2 count, u2 regs)
+    {
+        STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
+
+        //printf("range=%d call=%p count=%d regs=0x%04x\n",
+        //    methodCallRange, methodToCall, count, regs);
+        //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
+        //    methodToCall->name, methodToCall->shorty);
+
+        u4* outs;
+        int i;
+
+        /*
+         * Copy args.  This may corrupt vsrc1/vdst.
+         */
+        if (methodCallRange) {
+            // could use memcpy or a "Duff's device"; most functions have
+            // so few args it won't matter much
+            assert(vsrc1 <= curMethod->outsSize);
+            assert(vsrc1 == methodToCall->insSize);
+            outs = OUTS_FROM_FP(fp, vsrc1);
+            for (i = 0; i < vsrc1; i++)
+                outs[i] = GET_REGISTER(vdst+i);
+        } else {
+            u4 count = vsrc1 >> 4;
+
+            assert(count <= curMethod->outsSize);
+            assert(count == methodToCall->insSize);
+            assert(count <= 5);
+
+            outs = OUTS_FROM_FP(fp, count);
+#if 0
+            if (count == 5) {
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+                count--;
+            }
+            for (i = 0; i < (int) count; i++) {
+                outs[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+#else
+            // This version executes fewer instructions but is larger
+            // overall.  Seems to be a teensy bit faster.
+            assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
+            switch (count) {
+            case 5:
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+            case 4:
+                outs[3] = GET_REGISTER(vdst >> 12);
+            case 3:
+                outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
+            case 2:
+                outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
+            case 1:
+                outs[0] = GET_REGISTER(vdst & 0x0f);
+            default:
+                ;
+            }
+#endif
+        }
+    }
+
+    /*
+     * (This was originally a "goto" target; I've kept it separate from the
+     * stuff above in case we want to refactor things again.)
+     *
+     * At this point, we have the arguments stored in the "outs" area of
+     * the current method's stack frame, and the method to call in
+     * "methodToCall".  Push a new stack frame.
+     */
+    {
+        StackSaveArea* newSaveArea;
+        u4* newFp;
+
+        ILOGV("> %s%s.%s %s",
+            dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
+            methodToCall->clazz->descriptor, methodToCall->name,
+            methodToCall->shorty);
+
+        newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
+        newSaveArea = SAVEAREA_FROM_FP(newFp);
+
+        /* verify that we have enough space */
+        if (true) {
+            u1* bottom;
+            bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
+            if (bottom < self->interpStackEnd) {
+                /* stack overflow */
+                LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
+                    self->interpStackStart, self->interpStackEnd, bottom,
+                    (u1*) fp - bottom, self->interpStackSize,
+                    methodToCall->name);
+                dvmHandleStackOverflow(self, methodToCall);
+                assert(dvmCheckException(self));
+                GOTO_exceptionThrown();
+            }
+            //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
+            //    fp, newFp, newSaveArea, bottom);
+        }
+
+#ifdef LOG_INSTR
+        if (methodToCall->registersSize > methodToCall->insSize) {
+            /*
+             * This makes valgrind quiet when we print registers that
+             * haven't been initialized.  Turn it off when the debug
+             * messages are disabled -- we want valgrind to report any
+             * used-before-initialized issues.
+             */
+            memset(newFp, 0xcc,
+                (methodToCall->registersSize - methodToCall->insSize) * 4);
+        }
+#endif
+
+#ifdef EASY_GDB
+        newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
+#endif
+        newSaveArea->prevFrame = fp;
+        newSaveArea->savedPc = pc;
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        newSaveArea->returnAddr = 0;
+#endif
+        newSaveArea->method = methodToCall;
+
+        if (self->interpBreak.ctl.subMode != 0) {
+            /*
+             * We mark ENTER here for both native and non-native
+             * calls.  For native calls, we'll mark EXIT on return.
+             * For non-native calls, EXIT is marked in the RETURN op.
+             */
+            PC_TO_SELF();
+            dvmReportInvoke(self, methodToCall);
+        }
+
+        if (!dvmIsNativeMethod(methodToCall)) {
+            /*
+             * "Call" interpreted code.  Reposition the PC, update the
+             * frame pointer and other local state, and continue.
+             */
+            curMethod = methodToCall;
+            self->interpSave.method = curMethod;
+            methodClassDex = curMethod->clazz->pDvmDex;
+            pc = methodToCall->insns;
+            self->interpSave.curFrame = fp = newFp;
+#ifdef EASY_GDB
+            debugSaveArea = SAVEAREA_FROM_FP(newFp);
+#endif
+            self->debugIsMethodEntry = true;        // profiling, debugging
+            ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+                curMethod->name, curMethod->shorty);
+            DUMP_REGS(curMethod, fp, true);         // show input args
+            FINISH(0);                              // jump to method start
+        } else {
+            /* set this up for JNI locals, even if not a JNI native */
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+
+            self->interpSave.curFrame = newFp;
+
+            DUMP_REGS(methodToCall, newFp, true);   // show input args
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPreNativeInvoke(methodToCall, self, fp);
+            }
+
+            ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+                  methodToCall->name, methodToCall->shorty);
+
+            /*
+             * Jump through native call bridge.  Because we leave no
+             * space for locals on native calls, "newFp" points directly
+             * to the method arguments.
+             */
+            (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPostNativeInvoke(methodToCall, self, fp);
+            }
+
+            /* pop frame off */
+            dvmPopJniLocals(self, newSaveArea);
+            self->interpSave.curFrame = fp;
+
+            /*
+             * If the native code threw an exception, or interpreted code
+             * invoked by the native call threw one and nobody has cleared
+             * it, jump to our local exception handling.
+             */
+            if (dvmCheckException(self)) {
+                LOGV("Exception thrown by/below native code");
+                GOTO_exceptionThrown();
+            }
+
+            ILOGD("> retval=0x%llx (leaving native)", retval.j);
+            ILOGD("> (return from native %s.%s to %s.%s %s)",
+                methodToCall->clazz->descriptor, methodToCall->name,
+                curMethod->clazz->descriptor, curMethod->name,
+                curMethod->shorty);
+
+            //u2 invokeInstr = INST_INST(FETCH(0));
+            if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+                invokeInstr <= OP_INVOKE_INTERFACE*/)
+            {
+                FINISH(3);
+            } else {
+                //LOGE("Unknown invoke instr %02x at %d",
+                //    invokeInstr, (int) (pc - curMethod->insns));
+                assert(false);
+            }
+        }
+    }
+    assert(false);      // should not get here
+GOTO_TARGET_END
+
+/* File: portable/enddefs.cpp */
+/*--- end of opcodes ---*/
+
+bail:
+    ILOGD("|-- Leaving interpreter loop");      // note "curMethod" may be NULL
+
+    self->interpSave.retval = retval;
+}
+
diff --git a/vm/mterp/out/InterpC-x86-atom.cpp b/vm/mterp/out/InterpC-x86-atom.cpp
new file mode 100644
index 0000000..5648aff
--- /dev/null
+++ b/vm/mterp/out/InterpC-x86-atom.cpp
@@ -0,0 +1,2538 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'x86-atom'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: c/OP_IGET_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_VOLATILE,         "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_BREAKPOINT.cpp */
+HANDLE_OPCODE(OP_BREAKPOINT)
+    {
+        /*
+         * Restart this instruction with the original opcode.  We do
+         * this by simply jumping to the handler.
+         *
+         * It's probably not necessary to update "inst", but we do it
+         * for the sake of anything that needs to do disambiguation in a
+         * common handler with INST_INST.
+         *
+         * The breakpoint itself is handled over in updateDebugger(),
+         * because we need to detect other events (method entry, single
+         * step) and report them in the same event packet, and we're not
+         * yet handling those through breakpoint instructions.  By the
+         * time we get here, the breakpoint has already been handled and
+         * the thread resumed.
+         */
+        u1 originalOpcode = dvmGetOriginalOpcode(pc);
+        LOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
+            INST_REPLACE_OP(inst, originalOpcode));
+        inst = INST_REPLACE_OP(inst, originalOpcode);
+        FINISH_BKPT(originalOpcode);
+    }
+OP_END
+
+/* File: c/OP_EXECUTE_INLINE_RANGE.cpp */
+HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
+    {
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;      /* placate gcc */
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* range base */
+        ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst+3);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER(vdst+2);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER(vdst+1);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst+0);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(2);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, false);
+        }
+        FINISH(3);
+    }
+OP_END
+
+/* File: c/OP_RETURN_VOID_BARRIER.cpp */
+HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;   /* placate valgrind */
+#endif
+    ANDROID_MEMBAR_STORE();
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_JUMBO /*{vCCCC..vNNNN}, meth@AAAAAAAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(4);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, true);
+        }
+        FINISH(5);
+    }
+OP_END
+
+/* File: c/OP_IGET_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_VOLATILE_JUMBO, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/gotoTargets.cpp */
+/*
+ * C footer.  This has some common code shared by the various targets.
+ */
+
+/*
+ * Everything from here on is a "goto target".  In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction.  Here, these are subroutines that return to the caller.
+ */
+
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool jumboFormat)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        u4* contents;
+        char typeCh;
+        int i;
+        u4 arg5;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* class ref */
+            vsrc1 = FETCH(3);                     /* #of elements */
+            vdst = FETCH(4);                      /* range base */
+            arg5 = -1;                            /* silence compiler warning */
+            ILOGV("|filled-new-array/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        } else {
+            ref = FETCH(1);             /* class ref */
+            vdst = FETCH(2);            /* first 4 regs -or- range base */
+
+            if (methodCallRange) {
+                vsrc1 = INST_AA(inst);  /* #of elements */
+                arg5 = -1;              /* silence compiler warning */
+                ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+            } else {
+                arg5 = INST_A(inst);
+                vsrc1 = INST_B(inst);   /* #of elements */
+                ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
+                   vsrc1, ref, vdst, arg5);
+            }
+        }
+
+        /*
+         * Resolve the array class.
+         */
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /*
+        if (!dvmIsArrayClass(arrayClass)) {
+            dvmThrowRuntimeException(
+                "filled-new-array needs array class");
+            GOTO_exceptionThrown();
+        }
+        */
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        /*
+         * Create an array of the specified type.
+         */
+        LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
+        typeCh = arrayClass->descriptor[1];
+        if (typeCh == 'D' || typeCh == 'J') {
+            /* category 2 primitives not allowed */
+            dvmThrowRuntimeException("bad filled array req");
+            GOTO_exceptionThrown();
+        } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
+            /* TODO: requires multiple "fill in" loops with different widths */
+            LOGE("non-int primitives not implemented");
+            dvmThrowInternalError(
+                "filled-new-array not implemented for anything but 'int'");
+            GOTO_exceptionThrown();
+        }
+
+        newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+
+        /*
+         * Fill in the elements.  It's legal for vsrc1 to be zero.
+         */
+        contents = (u4*)(void*)newArray->contents;
+        if (methodCallRange) {
+            for (i = 0; i < vsrc1; i++)
+                contents[i] = GET_REGISTER(vdst+i);
+        } else {
+            assert(vsrc1 <= 5);
+            if (vsrc1 == 5) {
+                contents[4] = GET_REGISTER(arg5);
+                vsrc1--;
+            }
+            for (i = 0; i < vsrc1; i++) {
+                contents[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+        }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
+
+        retval.l = (Object*)newArray;
+    }
+    if (jumboFormat) {
+        FINISH(5);
+    } else {
+        FINISH(3);
+    }
+GOTO_TARGET_END
+
+
+GOTO_TARGET(invokeVirtual, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-virtual/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->methodToCall = methodToCall;
+        self->callsiteClass = thisPtr->clazz;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            /*
+             * This can happen if you create two classes, Base and Sub, where
+             * Sub is a sub-class of Base.  Declare a protected abstract
+             * method foo() in Base, and invoke foo() from a method in Base.
+             * Base is an "abstract base class" and is never instantiated
+             * directly.  Now, Override foo() in Sub, and use Sub.  This
+             * Works fine unless Sub stops providing an implementation of
+             * the method.
+             */
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            (u4) baseMethod->methodIndex,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+#if 0
+        if (vsrc1 != methodToCall->insSize) {
+            LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
+                baseMethod->clazz->descriptor, baseMethod->name,
+                (u4) baseMethod->methodIndex,
+                methodToCall->clazz->descriptor, methodToCall->name);
+            //dvmDumpClass(baseMethod->clazz);
+            //dvmDumpClass(methodToCall->clazz);
+            dvmDumpAllClasses(0);
+        }
+#endif
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuper, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-super/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         * The first arg to dvmResolveMethod() is just the referring class
+         * (used for class loaders and such), so we don't want to pass
+         * the superclass into the resolution call.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in that class' superclass.
+         */
+        if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
+            /*
+             * Method does not exist in the superclass.  Could happen if
+             * superclass gets updated.
+             */
+            dvmThrowNoSuchMethodError(baseMethod->name);
+            GOTO_exceptionThrown();
+        }
+        methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ base=%s.%s super-virtual=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeInterface, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+        ClassObject* thisClass;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-interface/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        thisClass = thisPtr->clazz;
+
+
+        /*
+         * Given a class and a method index, find the Method* with the
+         * actual code we want to execute.
+         */
+        methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
+                        methodClassDex);
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisClass;
+        self->methodToCall = methodToCall;
+#endif
+        if (methodToCall == NULL) {
+            assert(dvmCheckException(self));
+            GOTO_exceptionThrown();
+        }
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeDirect, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-direct/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (methodToCall == NULL) {
+            methodToCall = dvmResolveMethod(curMethod->clazz, ref,
+                            METHOD_DIRECT);
+            if (methodToCall == NULL) {
+                ILOGV("+ unknown direct method");     // should be impossible
+                GOTO_exceptionThrown();
+            }
+        }
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeStatic, bool methodCallRange, bool jumboFormat)
+    EXPORT_PC();
+
+    if (jumboFormat) {
+        ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+        vsrc1 = FETCH(3);                     /* count */
+        vdst = FETCH(4);                      /* first reg */
+        ADJUST_PC(2);     /* advance pc partially to make returns easier */
+        ILOGV("|invoke-static/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+    } else {
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* method ref */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange)
+            ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        else
+            ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+    }
+
+    methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+    if (methodToCall == NULL) {
+        methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
+        if (methodToCall == NULL) {
+            ILOGV("+ unknown method");
+            GOTO_exceptionThrown();
+        }
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        /*
+         * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+         * Include the check if this code is being used as a stub
+         * called from the assembly interpreter.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
+            /* Class initialization is still ongoing */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+    }
+    GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeVirtualQuick, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        /*
+         * The object against which we are executing a method is always
+         * in the first argument.
+         */
+        if (methodCallRange) {
+            assert(vsrc1 > 0);
+            ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            assert((vsrc1>>4) > 0);
+            ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[ref];
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisPtr->clazz;
+        self->methodToCall = methodToCall;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuperQuick, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange) {
+            ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisReg = vdst & 0x0f;
+        }
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+#if 0   /* impossible in optimized + verified code */
+        if (ref >= curMethod->clazz->super->vtableCount) {
+            dvmThrowNoSuchMethodError(NULL);
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
+#endif
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in the method's class' superclass.
+         */
+        methodToCall = curMethod->clazz->super->vtable[ref];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ super-virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * General handling for return-void, return, and return-wide.  Put the
+     * return value in "retval" before jumping here.
+     */
+GOTO_TARGET(returnFromMethod)
+    {
+        StackSaveArea* saveArea;
+
+        /*
+         * We must do this BEFORE we pop the previous stack frame off, so
+         * that the GC can see the return value (if any) in the local vars.
+         *
+         * Since this is now an interpreter switch point, we must do it before
+         * we do anything at all.
+         */
+        PERIODIC_CHECKS(0);
+
+        ILOGV("> retval=0x%llx (leaving %s.%s %s)",
+            retval.j, curMethod->clazz->descriptor, curMethod->name,
+            curMethod->shorty);
+        //DUMP_REGS(curMethod, fp);
+
+        saveArea = SAVEAREA_FROM_FP(fp);
+
+#ifdef EASY_GDB
+        debugSaveArea = saveArea;
+#endif
+
+        /* back up to previous frame and see if we hit a break */
+        fp = (u4*)saveArea->prevFrame;
+        assert(fp != NULL);
+
+        /* Handle any special subMode requirements */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportReturn(self);
+        }
+
+        if (dvmIsBreakFrame(fp)) {
+            /* bail without popping the method frame from stack */
+            LOGVV("+++ returned into break frame");
+            GOTO_bail();
+        }
+
+        /* update thread FP, and reset local variables */
+        self->interpSave.curFrame = fp;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = saveArea->savedPc;
+        ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+
+        /* use FINISH on the caller's invoke instruction */
+        //u2 invokeInstr = INST_INST(FETCH(0));
+        if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+            invokeInstr <= OP_INVOKE_INTERFACE*/)
+        {
+            FINISH(3);
+        } else {
+            //LOGE("Unknown invoke instr %02x at %d",
+            //    invokeInstr, (int) (pc - curMethod->insns));
+            assert(false);
+        }
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * Jump here when the code throws an exception.
+     *
+     * By the time we get here, the Throwable has been created and the stack
+     * trace has been saved off.
+     */
+GOTO_TARGET(exceptionThrown)
+    {
+        Object* exception;
+        int catchRelPc;
+
+        PERIODIC_CHECKS(0);
+
+        /*
+         * We save off the exception and clear the exception status.  While
+         * processing the exception we might need to load some Throwable
+         * classes, and we don't want class loader exceptions to get
+         * confused with this one.
+         */
+        assert(dvmCheckException(self));
+        exception = dvmGetException(self);
+        dvmAddTrackedAlloc(exception, self);
+        dvmClearException(self);
+
+        LOGV("Handling exception %s at %s:%d",
+            exception->clazz->descriptor, curMethod->name,
+            dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+
+        /*
+         * Report the exception throw to any "subMode" watchers.
+         *
+         * TODO: if the exception was thrown by interpreted code, control
+         * fell through native, and then back to us, we will report the
+         * exception at the point of the throw and again here.  We can avoid
+         * this by not reporting exceptions when we jump here directly from
+         * the native call code above, but then we won't report exceptions
+         * that were thrown *from* the JNI code (as opposed to *through* it).
+         *
+         * The correct solution is probably to ignore from-native exceptions
+         * here, and have the JNI exception code do the reporting to the
+         * debugger.
+         */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportExceptionThrow(self, exception);
+        }
+
+        /*
+         * We need to unroll to the catch block or the nearest "break"
+         * frame.
+         *
+         * A break frame could indicate that we have reached an intermediate
+         * native call, or have gone off the top of the stack and the thread
+         * needs to exit.  Either way, we return from here, leaving the
+         * exception raised.
+         *
+         * If we do find a catch block, we want to transfer execution to
+         * that point.
+         *
+         * Note this can cause an exception while resolving classes in
+         * the "catch" blocks.
+         */
+        catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
+                    exception, false, (void**)(void*)&fp);
+
+        /*
+         * Restore the stack bounds after an overflow.  This isn't going to
+         * be correct in all circumstances, e.g. if JNI code devours the
+         * exception this won't happen until some other exception gets
+         * thrown.  If the code keeps pushing the stack bounds we'll end
+         * up aborting the VM.
+         *
+         * Note we want to do this *after* the call to dvmFindCatchBlock,
+         * because that may need extra stack space to resolve exception
+         * classes (e.g. through a class loader).
+         *
+         * It's possible for the stack overflow handling to cause an
+         * exception (specifically, class resolution in a "catch" block
+         * during the call above), so we could see the thread's overflow
+         * flag raised but actually be running in a "nested" interpreter
+         * frame.  We don't allow doubled-up StackOverflowErrors, so
+         * we can check for this by just looking at the exception type
+         * in the cleanup function.  Also, we won't unroll past the SOE
+         * point because the more-recent exception will hit a break frame
+         * as it unrolls to here.
+         */
+        if (self->stackOverflowed)
+            dvmCleanupStackOverflow(self, exception);
+
+        if (catchRelPc < 0) {
+            /* falling through to JNI code or off the bottom of the stack */
+#if DVM_SHOW_EXCEPTION >= 2
+            LOGD("Exception %s from %s:%d not caught locally",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+#endif
+            dvmSetException(self, exception);
+            dvmReleaseTrackedAlloc(exception, self);
+            GOTO_bail();
+        }
+
+#if DVM_SHOW_EXCEPTION >= 3
+        {
+            const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
+            LOGD("Exception %s thrown from %s:%d to %s:%d",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns),
+                dvmGetMethodSourceFile(catchMethod),
+                dvmLineNumFromPC(catchMethod, catchRelPc));
+        }
+#endif
+
+        /*
+         * Adjust local variables to match self->interpSave.curFrame and the
+         * updated PC.
+         */
+        //fp = (u4*) self->interpSave.curFrame;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = curMethod->insns + catchRelPc;
+        ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+        DUMP_REGS(curMethod, fp, false);            // show all regs
+
+        /*
+         * Restore the exception if the handler wants it.
+         *
+         * The Dalvik spec mandates that, if an exception handler wants to
+         * do something with the exception, the first instruction executed
+         * must be "move-exception".  We can pass the exception along
+         * through the thread struct, and let the move-exception instruction
+         * clear it for us.
+         *
+         * If the handler doesn't call move-exception, we don't want to
+         * finish here with an exception still pending.
+         */
+        if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
+            dvmSetException(self, exception);
+
+        dvmReleaseTrackedAlloc(exception, self);
+        FINISH(0);
+    }
+GOTO_TARGET_END
+
+
+
+    /*
+     * General handling for invoke-{virtual,super,direct,static,interface},
+     * including "quick" variants.
+     *
+     * Set "methodToCall" to the Method we're calling, and "methodCallRange"
+     * depending on whether this is a "/range" instruction.
+     *
+     * For a range call:
+     *  "vsrc1" holds the argument count (8 bits)
+     *  "vdst" holds the first argument in the range
+     * For a non-range call:
+     *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
+     *  "vdst" holds four 4-bit register indices
+     *
+     * The caller must EXPORT_PC before jumping here, because any method
+     * call can throw a stack overflow exception.
+     */
+GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
+    u2 count, u2 regs)
+    {
+        STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
+
+        //printf("range=%d call=%p count=%d regs=0x%04x\n",
+        //    methodCallRange, methodToCall, count, regs);
+        //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
+        //    methodToCall->name, methodToCall->shorty);
+
+        u4* outs;
+        int i;
+
+        /*
+         * Copy args.  This may corrupt vsrc1/vdst.
+         */
+        if (methodCallRange) {
+            // could use memcpy or a "Duff's device"; most functions have
+            // so few args it won't matter much
+            assert(vsrc1 <= curMethod->outsSize);
+            assert(vsrc1 == methodToCall->insSize);
+            outs = OUTS_FROM_FP(fp, vsrc1);
+            for (i = 0; i < vsrc1; i++)
+                outs[i] = GET_REGISTER(vdst+i);
+        } else {
+            u4 count = vsrc1 >> 4;
+
+            assert(count <= curMethod->outsSize);
+            assert(count == methodToCall->insSize);
+            assert(count <= 5);
+
+            outs = OUTS_FROM_FP(fp, count);
+#if 0
+            if (count == 5) {
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+                count--;
+            }
+            for (i = 0; i < (int) count; i++) {
+                outs[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+#else
+            // This version executes fewer instructions but is larger
+            // overall.  Seems to be a teensy bit faster.
+            assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
+            switch (count) {
+            case 5:
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+            case 4:
+                outs[3] = GET_REGISTER(vdst >> 12);
+            case 3:
+                outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
+            case 2:
+                outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
+            case 1:
+                outs[0] = GET_REGISTER(vdst & 0x0f);
+            default:
+                ;
+            }
+#endif
+        }
+    }
+
+    /*
+     * (This was originally a "goto" target; I've kept it separate from the
+     * stuff above in case we want to refactor things again.)
+     *
+     * At this point, we have the arguments stored in the "outs" area of
+     * the current method's stack frame, and the method to call in
+     * "methodToCall".  Push a new stack frame.
+     */
+    {
+        StackSaveArea* newSaveArea;
+        u4* newFp;
+
+        ILOGV("> %s%s.%s %s",
+            dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
+            methodToCall->clazz->descriptor, methodToCall->name,
+            methodToCall->shorty);
+
+        newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
+        newSaveArea = SAVEAREA_FROM_FP(newFp);
+
+        /* verify that we have enough space */
+        if (true) {
+            u1* bottom;
+            bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
+            if (bottom < self->interpStackEnd) {
+                /* stack overflow */
+                LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
+                    self->interpStackStart, self->interpStackEnd, bottom,
+                    (u1*) fp - bottom, self->interpStackSize,
+                    methodToCall->name);
+                dvmHandleStackOverflow(self, methodToCall);
+                assert(dvmCheckException(self));
+                GOTO_exceptionThrown();
+            }
+            //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
+            //    fp, newFp, newSaveArea, bottom);
+        }
+
+#ifdef LOG_INSTR
+        if (methodToCall->registersSize > methodToCall->insSize) {
+            /*
+             * This makes valgrind quiet when we print registers that
+             * haven't been initialized.  Turn it off when the debug
+             * messages are disabled -- we want valgrind to report any
+             * used-before-initialized issues.
+             */
+            memset(newFp, 0xcc,
+                (methodToCall->registersSize - methodToCall->insSize) * 4);
+        }
+#endif
+
+#ifdef EASY_GDB
+        newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
+#endif
+        newSaveArea->prevFrame = fp;
+        newSaveArea->savedPc = pc;
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        newSaveArea->returnAddr = 0;
+#endif
+        newSaveArea->method = methodToCall;
+
+        if (self->interpBreak.ctl.subMode != 0) {
+            /*
+             * We mark ENTER here for both native and non-native
+             * calls.  For native calls, we'll mark EXIT on return.
+             * For non-native calls, EXIT is marked in the RETURN op.
+             */
+            PC_TO_SELF();
+            dvmReportInvoke(self, methodToCall);
+        }
+
+        if (!dvmIsNativeMethod(methodToCall)) {
+            /*
+             * "Call" interpreted code.  Reposition the PC, update the
+             * frame pointer and other local state, and continue.
+             */
+            curMethod = methodToCall;
+            self->interpSave.method = curMethod;
+            methodClassDex = curMethod->clazz->pDvmDex;
+            pc = methodToCall->insns;
+            self->interpSave.curFrame = fp = newFp;
+#ifdef EASY_GDB
+            debugSaveArea = SAVEAREA_FROM_FP(newFp);
+#endif
+            self->debugIsMethodEntry = true;        // profiling, debugging
+            ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+                curMethod->name, curMethod->shorty);
+            DUMP_REGS(curMethod, fp, true);         // show input args
+            FINISH(0);                              // jump to method start
+        } else {
+            /* set this up for JNI locals, even if not a JNI native */
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+
+            self->interpSave.curFrame = newFp;
+
+            DUMP_REGS(methodToCall, newFp, true);   // show input args
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPreNativeInvoke(methodToCall, self, fp);
+            }
+
+            ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+                  methodToCall->name, methodToCall->shorty);
+
+            /*
+             * Jump through native call bridge.  Because we leave no
+             * space for locals on native calls, "newFp" points directly
+             * to the method arguments.
+             */
+            (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPostNativeInvoke(methodToCall, self, fp);
+            }
+
+            /* pop frame off */
+            dvmPopJniLocals(self, newSaveArea);
+            self->interpSave.curFrame = fp;
+
+            /*
+             * If the native code threw an exception, or interpreted code
+             * invoked by the native call threw one and nobody has cleared
+             * it, jump to our local exception handling.
+             */
+            if (dvmCheckException(self)) {
+                LOGV("Exception thrown by/below native code");
+                GOTO_exceptionThrown();
+            }
+
+            ILOGD("> retval=0x%llx (leaving native)", retval.j);
+            ILOGD("> (return from native %s.%s to %s.%s %s)",
+                methodToCall->clazz->descriptor, methodToCall->name,
+                curMethod->clazz->descriptor, curMethod->name,
+                curMethod->shorty);
+
+            //u2 invokeInstr = INST_INST(FETCH(0));
+            if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+                invokeInstr <= OP_INVOKE_INTERFACE*/)
+            {
+                FINISH(3);
+            } else {
+                //LOGE("Unknown invoke instr %02x at %d",
+                //    invokeInstr, (int) (pc - curMethod->insns));
+                assert(false);
+            }
+        }
+    }
+    assert(false);      // should not get here
+GOTO_TARGET_END
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
diff --git a/vm/mterp/out/InterpC-x86.cpp b/vm/mterp/out/InterpC-x86.cpp
new file mode 100644
index 0000000..1623720
--- /dev/null
+++ b/vm/mterp/out/InterpC-x86.cpp
@@ -0,0 +1,2480 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'x86'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.cpp */
+/*
+ * 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_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * Some architectures require 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 may assume the pointer target is
+ * aligned and generate invalid code.
+ *
+ * There are two common approaches:
+ *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
+ *  (2) Call memcpy().
+ *
+ * Depending upon what compiler you're using and what options are specified,
+ * one may be faster than the other.  For example, the compiler might
+ * convert a memcpy() of 8 bytes into a series of instructions and omit
+ * the call.  The union version could cause some strange side-effects,
+ * e.g. for a while ARM gcc thought it needed separate storage for each
+ * inlined instance, and generated instructions to zero out ~700 bytes of
+ * stack space at the top of the interpreter.
+ *
+ * The default is to use memcpy().  The current gcc for ARM seems to do
+ * better with the union.
+ */
+#if defined(__ARM_EABI__)
+# define NO_UNALIGN_64__UNION
+#endif
+
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * 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",                 \
+                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",                          \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
+                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;
+#else
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#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];
+#else
+    memcpy(&ptr[idx], &val, 8);
+#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;
+#else
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#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];
+#else
+    memcpy(&ptr[idx], &dval, 8);
+#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 ? \
+        (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+# 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 ? \
+        (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
+#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)
+
+/*
+ * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
+ * 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 the various exception throw routines, 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)
+
+/*
+ * 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) {
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddressObject(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", 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();
+        dvmThrowNullPointerException(NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsHeapAddress(obj)) {
+        LOGE("Invalid object %p", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.cpp */
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
+
+/* (void)xxx to quiet unused variable compiler warnings. */
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;                                       \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
+        (void)methodToCall; (void)debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into Thread struct
+ * references.  (These are undefined down in "footer.cpp".)
+ */
+#define retval                  self->interpSave.retval
+#define pc                      self->interpSave.pc
+#define fp                      self->interpSave.curFrame
+#define curMethod               self->interpSave.method
+#define methodClassDex          self->interpSave.methodClassDex
+#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+#if defined(WITH_JIT)
+#define JIT_STUB_HACK(x) x
+#else
+#define JIT_STUB_HACK(x)
+#endif
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()
+#define PC_TO_SELF()
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "self" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ * (void)xxx to quiet unused variable compiler warnings.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    extern "C" void dvmMterp_##_op(Thread* self);                           \
+    void dvmMterp_##_op(Thread* self) {                                     \
+        u4 ref;                                                             \
+        u2 vsrc1, vsrc2, vdst;                                              \
+        u2 inst = FETCH(0);                                                 \
+        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.  Further, debugger/profiler checks are handled
+ * before handler execution in mterp, so we don't do them here either.
+ */
+#if defined(WITH_JIT)
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
+            dvmCheckJit(pc, self);                                          \
+        }                                                                   \
+        return;                                                             \
+    }
+#else
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        return;                                                             \
+    }
+#endif
+
+
+/*
+ * 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(self);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(self);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(self, false);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.
+ */
+#define PERIODIC_CHECKS(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.cpp */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
+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", 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(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(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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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();                                                \
+                dvmThrowArithmeticException("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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
+        ILOGV("+ AGET[%d]=%#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) {                      \
+            dvmThrowArrayIndexOutOfBoundsException(                         \
+                arrayObj->length, GET_REGISTER(vsrc2));                     \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*)(void*)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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        vsrc1 = FETCH(4);                      /* object ptr */             \
+        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
+            (_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));                             \
+    }                                                                       \
+    FINISH(5);
+
+#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);
+
+/*
+ * The JIT needs dvmDexGetResolvedField() to return non-null.
+ * Because the portable interpreter is not involved with the JIT
+ * and trace building, we only need the extra check here when this
+ * code is massaged into a stub called from an assembly interpreter.
+ * This is controlled by the JIT_STUB_HACK maco.
+ */
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+#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();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
+        vdst = FETCH(3);                                                    \
+        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
+                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
+            }                                                               \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+    }                                                                       \
+    FINISH(4);
+
+/* File: c/OP_IGET_WIDE_VOLATILE.cpp */
+HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE.cpp */
+HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE.cpp */
+HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE.cpp */
+HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_EXECUTE_INLINE_RANGE.cpp */
+HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
+    {
+        u4 arg0, arg1, arg2, arg3;
+        arg0 = arg1 = arg2 = arg3 = 0;      /* placate gcc */
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* #of args */
+        ref = FETCH(1);             /* inline call "ref" */
+        vdst = FETCH(2);            /* range base */
+        ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+
+        assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
+        assert(vsrc1 <= 4);
+
+        switch (vsrc1) {
+        case 4:
+            arg3 = GET_REGISTER(vdst+3);
+            /* fall through */
+        case 3:
+            arg2 = GET_REGISTER(vdst+2);
+            /* fall through */
+        case 2:
+            arg1 = GET_REGISTER(vdst+1);
+            /* fall through */
+        case 1:
+            arg0 = GET_REGISTER(vdst+0);
+            /* fall through */
+        default:        // case 0
+            ;
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        } else {
+            if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+                GOTO_exceptionThrown();
+        }
+    }
+    FINISH(3);
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_RANGE.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(2);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, false);
+        }
+        FINISH(3);
+    }
+OP_END
+
+/* File: c/OP_RETURN_VOID_BARRIER.cpp */
+HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
+    ILOGV("|return-void");
+#ifndef NDEBUG
+    retval.j = 0xababababULL;   /* placate valgrind */
+#endif
+    ANDROID_MEMBAR_STORE();
+    GOTO_returnFromMethod();
+OP_END
+
+/* File: c/OP_INVOKE_OBJECT_INIT_JUMBO.cpp */
+HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_JUMBO /*{vCCCC..vNNNN}, meth@AAAAAAAA*/)
+    {
+        Object* obj;
+
+        vsrc1 = FETCH(4);               /* reg number of "this" pointer */
+        obj = GET_REGISTER_AS_OBJECT(vsrc1);
+
+        if (!checkForNullExportPC(obj, fp, pc))
+            GOTO_exceptionThrown();
+
+        /*
+         * The object should be marked "finalizable" when Object.<init>
+         * completes normally.  We're going to assume it does complete
+         * (by virtue of being nothing but a return-void) and set it now.
+         */
+        if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
+            EXPORT_PC();
+            dvmSetFinalizable(obj);
+            if (dvmGetException(self))
+                GOTO_exceptionThrown();
+        }
+
+        if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
+            /* behave like OP_INVOKE_DIRECT_RANGE */
+            GOTO_invoke(invokeDirect, true, true);
+        }
+        FINISH(5);
+    }
+OP_END
+
+/* File: c/OP_IGET_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IGET_X_JUMBO(OP_IGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_IPUT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_IPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_IPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_IPUT_X_JUMBO(OP_IPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SGET_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_VOLATILE_JUMBO, "-volatile/jumbo", IntVolatile, )
+OP_END
+
+/* File: c/OP_SGET_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SGET_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SGET_X_JUMBO(OP_SGET_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/OP_SPUT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_VOLATILE_JUMBO, "-volatile", IntVolatile, )
+OP_END
+
+/* File: c/OP_SPUT_WIDE_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_WIDE_VOLATILE_JUMBO, "-wide-volatile/jumbo", LongVolatile, _WIDE)
+OP_END
+
+/* File: c/OP_SPUT_OBJECT_VOLATILE_JUMBO.cpp */
+HANDLE_SPUT_X_JUMBO(OP_SPUT_OBJECT_VOLATILE_JUMBO, "-object-volatile/jumbo", ObjectVolatile, _AS_OBJECT)
+OP_END
+
+/* File: c/gotoTargets.cpp */
+/*
+ * C footer.  This has some common code shared by the various targets.
+ */
+
+/*
+ * Everything from here on is a "goto target".  In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction.  Here, these are subroutines that return to the caller.
+ */
+
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool jumboFormat)
+    {
+        ClassObject* arrayClass;
+        ArrayObject* newArray;
+        u4* contents;
+        char typeCh;
+        int i;
+        u4 arg5;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* class ref */
+            vsrc1 = FETCH(3);                     /* #of elements */
+            vdst = FETCH(4);                      /* range base */
+            arg5 = -1;                            /* silence compiler warning */
+            ILOGV("|filled-new-array/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        } else {
+            ref = FETCH(1);             /* class ref */
+            vdst = FETCH(2);            /* first 4 regs -or- range base */
+
+            if (methodCallRange) {
+                vsrc1 = INST_AA(inst);  /* #of elements */
+                arg5 = -1;              /* silence compiler warning */
+                ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+            } else {
+                arg5 = INST_A(inst);
+                vsrc1 = INST_B(inst);   /* #of elements */
+                ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
+                   vsrc1, ref, vdst, arg5);
+            }
+        }
+
+        /*
+         * Resolve the array class.
+         */
+        arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
+        if (arrayClass == NULL) {
+            arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
+            if (arrayClass == NULL)
+                GOTO_exceptionThrown();
+        }
+        /*
+        if (!dvmIsArrayClass(arrayClass)) {
+            dvmThrowRuntimeException(
+                "filled-new-array needs array class");
+            GOTO_exceptionThrown();
+        }
+        */
+        /* verifier guarantees this is an array class */
+        assert(dvmIsArrayClass(arrayClass));
+        assert(dvmIsClassInitialized(arrayClass));
+
+        /*
+         * Create an array of the specified type.
+         */
+        LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
+        typeCh = arrayClass->descriptor[1];
+        if (typeCh == 'D' || typeCh == 'J') {
+            /* category 2 primitives not allowed */
+            dvmThrowRuntimeException("bad filled array req");
+            GOTO_exceptionThrown();
+        } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
+            /* TODO: requires multiple "fill in" loops with different widths */
+            LOGE("non-int primitives not implemented");
+            dvmThrowInternalError(
+                "filled-new-array not implemented for anything but 'int'");
+            GOTO_exceptionThrown();
+        }
+
+        newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
+        if (newArray == NULL)
+            GOTO_exceptionThrown();
+
+        /*
+         * Fill in the elements.  It's legal for vsrc1 to be zero.
+         */
+        contents = (u4*)(void*)newArray->contents;
+        if (methodCallRange) {
+            for (i = 0; i < vsrc1; i++)
+                contents[i] = GET_REGISTER(vdst+i);
+        } else {
+            assert(vsrc1 <= 5);
+            if (vsrc1 == 5) {
+                contents[4] = GET_REGISTER(arg5);
+                vsrc1--;
+            }
+            for (i = 0; i < vsrc1; i++) {
+                contents[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+        }
+        if (typeCh == 'L' || typeCh == '[') {
+            dvmWriteBarrierArray(newArray, 0, newArray->length);
+        }
+
+        retval.l = (Object*)newArray;
+    }
+    if (jumboFormat) {
+        FINISH(5);
+    } else {
+        FINISH(3);
+    }
+GOTO_TARGET_END
+
+
+GOTO_TARGET(invokeVirtual, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-virtual/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->methodToCall = methodToCall;
+        self->callsiteClass = thisPtr->clazz;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            /*
+             * This can happen if you create two classes, Base and Sub, where
+             * Sub is a sub-class of Base.  Declare a protected abstract
+             * method foo() in Base, and invoke foo() from a method in Base.
+             * Base is an "abstract base class" and is never instantiated
+             * directly.  Now, Override foo() in Sub, and use Sub.  This
+             * Works fine unless Sub stops providing an implementation of
+             * the method.
+             */
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            (u4) baseMethod->methodIndex,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+#if 0
+        if (vsrc1 != methodToCall->insSize) {
+            LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
+                baseMethod->clazz->descriptor, baseMethod->name,
+                (u4) baseMethod->methodIndex,
+                methodToCall->clazz->descriptor, methodToCall->name);
+            //dvmDumpClass(baseMethod->clazz);
+            //dvmDumpClass(methodToCall->clazz);
+            dvmDumpAllClasses(0);
+        }
+#endif
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuper, bool methodCallRange, bool jumboFormat)
+    {
+        Method* baseMethod;
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-super/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        /*
+         * Resolve the method.  This is the correct method for the static
+         * type of the object.  We also verify access permissions here.
+         * The first arg to dvmResolveMethod() is just the referring class
+         * (used for class loaders and such), so we don't want to pass
+         * the superclass into the resolution call.
+         */
+        baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (baseMethod == NULL) {
+            baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
+            if (baseMethod == NULL) {
+                ILOGV("+ unknown method or access denied");
+                GOTO_exceptionThrown();
+            }
+        }
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in that class' superclass.
+         */
+        if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
+            /*
+             * Method does not exist in the superclass.  Could happen if
+             * superclass gets updated.
+             */
+            dvmThrowNoSuchMethodError(baseMethod->name);
+            GOTO_exceptionThrown();
+        }
+        methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ base=%s.%s super-virtual=%s.%s",
+            baseMethod->clazz->descriptor, baseMethod->name,
+            methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeInterface, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+        ClassObject* thisClass;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-interface/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            /*
+             * The object against which we are executing a method is always
+             * in the first argument.
+             */
+            if (methodCallRange) {
+                assert(vsrc1 > 0);
+                ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisPtr = (Object*) GET_REGISTER(vdst);
+            } else {
+                assert((vsrc1>>4) > 0);
+                ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+            }
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+        thisClass = thisPtr->clazz;
+
+
+        /*
+         * Given a class and a method index, find the Method* with the
+         * actual code we want to execute.
+         */
+        methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
+                        methodClassDex);
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisClass;
+        self->methodToCall = methodToCall;
+#endif
+        if (methodToCall == NULL) {
+            assert(dvmCheckException(self));
+            GOTO_exceptionThrown();
+        }
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeDirect, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        if (jumboFormat) {
+            ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+            vsrc1 = FETCH(3);                     /* count */
+            vdst = FETCH(4);                      /* first reg */
+            ADJUST_PC(2);     /* advance pc partially to make returns easier */
+            ILOGV("|invoke-direct/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+            ref = FETCH(1);             /* method ref */
+            vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+            if (methodCallRange) {
+                ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
+                    vsrc1, ref, vdst, vdst+vsrc1-1);
+                thisReg = vdst;
+            } else {
+                ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
+                    vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+                thisReg = vdst & 0x0f;
+            }
+        }
+
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+        methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+        if (methodToCall == NULL) {
+            methodToCall = dvmResolveMethod(curMethod->clazz, ref,
+                            METHOD_DIRECT);
+            if (methodToCall == NULL) {
+                ILOGV("+ unknown direct method");     // should be impossible
+                GOTO_exceptionThrown();
+            }
+        }
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeStatic, bool methodCallRange, bool jumboFormat)
+    EXPORT_PC();
+
+    if (jumboFormat) {
+        ref = FETCH(1) | (u4)FETCH(2) << 16;  /* method ref */
+        vsrc1 = FETCH(3);                     /* count */
+        vdst = FETCH(4);                      /* first reg */
+        ADJUST_PC(2);     /* advance pc partially to make returns easier */
+        ILOGV("|invoke-static/jumbo args=%d @0x%08x {regs=v%d-v%d}",
+            vsrc1, ref, vdst, vdst+vsrc1-1);
+    } else {
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* method ref */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange)
+            ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+        else
+            ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+    }
+
+    methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
+    if (methodToCall == NULL) {
+        methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
+        if (methodToCall == NULL) {
+            ILOGV("+ unknown method");
+            GOTO_exceptionThrown();
+        }
+
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        /*
+         * The JIT needs dvmDexGetResolvedMethod() to return non-null.
+         * Include the check if this code is being used as a stub
+         * called from the assembly interpreter.
+         */
+        if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
+            (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
+            /* Class initialization is still ongoing */
+            dvmJitEndTraceSelect(self,pc);
+        }
+#endif
+    }
+    GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeVirtualQuick, bool methodCallRange, bool jumboFormat)
+    {
+        Object* thisPtr;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        /*
+         * The object against which we are executing a method is always
+         * in the first argument.
+         */
+        if (methodCallRange) {
+            assert(vsrc1 > 0);
+            ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisPtr = (Object*) GET_REGISTER(vdst);
+        } else {
+            assert((vsrc1>>4) > 0);
+            ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
+        }
+
+        if (!checkForNull(thisPtr))
+            GOTO_exceptionThrown();
+
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method.
+         */
+        assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
+        methodToCall = thisPtr->clazz->vtable[ref];
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        self->callsiteClass = thisPtr->clazz;
+        self->methodToCall = methodToCall;
+#endif
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+
+        LOGVV("+++ virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+GOTO_TARGET(invokeSuperQuick, bool methodCallRange, bool jumboFormat)
+    {
+        u2 thisReg;
+
+        EXPORT_PC();
+
+        vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
+        ref = FETCH(1);             /* vtable index */
+        vdst = FETCH(2);            /* 4 regs -or- first reg */
+
+        if (methodCallRange) {
+            ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
+                vsrc1, ref, vdst, vdst+vsrc1-1);
+            thisReg = vdst;
+        } else {
+            ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
+                vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
+            thisReg = vdst & 0x0f;
+        }
+        /* impossible in well-formed code, but we must check nevertheless */
+        if (!checkForNull((Object*) GET_REGISTER(thisReg)))
+            GOTO_exceptionThrown();
+
+#if 0   /* impossible in optimized + verified code */
+        if (ref >= curMethod->clazz->super->vtableCount) {
+            dvmThrowNoSuchMethodError(NULL);
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
+#endif
+
+        /*
+         * Combine the object we found with the vtable offset in the
+         * method's class.
+         *
+         * We're using the current method's class' superclass, not the
+         * superclass of "this".  This is because we might be executing
+         * in a method inherited from a superclass, and we want to run
+         * in the method's class' superclass.
+         */
+        methodToCall = curMethod->clazz->super->vtable[ref];
+
+#if 0
+        if (dvmIsAbstractMethod(methodToCall)) {
+            dvmThrowAbstractMethodError("abstract method not implemented");
+            GOTO_exceptionThrown();
+        }
+#else
+        assert(!dvmIsAbstractMethod(methodToCall) ||
+            methodToCall->nativeFunc != NULL);
+#endif
+        LOGVV("+++ super-virtual[%d]=%s.%s",
+            ref, methodToCall->clazz->descriptor, methodToCall->name);
+        assert(methodToCall != NULL);
+        GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * General handling for return-void, return, and return-wide.  Put the
+     * return value in "retval" before jumping here.
+     */
+GOTO_TARGET(returnFromMethod)
+    {
+        StackSaveArea* saveArea;
+
+        /*
+         * We must do this BEFORE we pop the previous stack frame off, so
+         * that the GC can see the return value (if any) in the local vars.
+         *
+         * Since this is now an interpreter switch point, we must do it before
+         * we do anything at all.
+         */
+        PERIODIC_CHECKS(0);
+
+        ILOGV("> retval=0x%llx (leaving %s.%s %s)",
+            retval.j, curMethod->clazz->descriptor, curMethod->name,
+            curMethod->shorty);
+        //DUMP_REGS(curMethod, fp);
+
+        saveArea = SAVEAREA_FROM_FP(fp);
+
+#ifdef EASY_GDB
+        debugSaveArea = saveArea;
+#endif
+
+        /* back up to previous frame and see if we hit a break */
+        fp = (u4*)saveArea->prevFrame;
+        assert(fp != NULL);
+
+        /* Handle any special subMode requirements */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportReturn(self);
+        }
+
+        if (dvmIsBreakFrame(fp)) {
+            /* bail without popping the method frame from stack */
+            LOGVV("+++ returned into break frame");
+            GOTO_bail();
+        }
+
+        /* update thread FP, and reset local variables */
+        self->interpSave.curFrame = fp;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = saveArea->savedPc;
+        ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+
+        /* use FINISH on the caller's invoke instruction */
+        //u2 invokeInstr = INST_INST(FETCH(0));
+        if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+            invokeInstr <= OP_INVOKE_INTERFACE*/)
+        {
+            FINISH(3);
+        } else {
+            //LOGE("Unknown invoke instr %02x at %d",
+            //    invokeInstr, (int) (pc - curMethod->insns));
+            assert(false);
+        }
+    }
+GOTO_TARGET_END
+
+
+    /*
+     * Jump here when the code throws an exception.
+     *
+     * By the time we get here, the Throwable has been created and the stack
+     * trace has been saved off.
+     */
+GOTO_TARGET(exceptionThrown)
+    {
+        Object* exception;
+        int catchRelPc;
+
+        PERIODIC_CHECKS(0);
+
+        /*
+         * We save off the exception and clear the exception status.  While
+         * processing the exception we might need to load some Throwable
+         * classes, and we don't want class loader exceptions to get
+         * confused with this one.
+         */
+        assert(dvmCheckException(self));
+        exception = dvmGetException(self);
+        dvmAddTrackedAlloc(exception, self);
+        dvmClearException(self);
+
+        LOGV("Handling exception %s at %s:%d",
+            exception->clazz->descriptor, curMethod->name,
+            dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+
+        /*
+         * Report the exception throw to any "subMode" watchers.
+         *
+         * TODO: if the exception was thrown by interpreted code, control
+         * fell through native, and then back to us, we will report the
+         * exception at the point of the throw and again here.  We can avoid
+         * this by not reporting exceptions when we jump here directly from
+         * the native call code above, but then we won't report exceptions
+         * that were thrown *from* the JNI code (as opposed to *through* it).
+         *
+         * The correct solution is probably to ignore from-native exceptions
+         * here, and have the JNI exception code do the reporting to the
+         * debugger.
+         */
+        if (self->interpBreak.ctl.subMode != 0) {
+            PC_FP_TO_SELF();
+            dvmReportExceptionThrow(self, exception);
+        }
+
+        /*
+         * We need to unroll to the catch block or the nearest "break"
+         * frame.
+         *
+         * A break frame could indicate that we have reached an intermediate
+         * native call, or have gone off the top of the stack and the thread
+         * needs to exit.  Either way, we return from here, leaving the
+         * exception raised.
+         *
+         * If we do find a catch block, we want to transfer execution to
+         * that point.
+         *
+         * Note this can cause an exception while resolving classes in
+         * the "catch" blocks.
+         */
+        catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
+                    exception, false, (void**)(void*)&fp);
+
+        /*
+         * Restore the stack bounds after an overflow.  This isn't going to
+         * be correct in all circumstances, e.g. if JNI code devours the
+         * exception this won't happen until some other exception gets
+         * thrown.  If the code keeps pushing the stack bounds we'll end
+         * up aborting the VM.
+         *
+         * Note we want to do this *after* the call to dvmFindCatchBlock,
+         * because that may need extra stack space to resolve exception
+         * classes (e.g. through a class loader).
+         *
+         * It's possible for the stack overflow handling to cause an
+         * exception (specifically, class resolution in a "catch" block
+         * during the call above), so we could see the thread's overflow
+         * flag raised but actually be running in a "nested" interpreter
+         * frame.  We don't allow doubled-up StackOverflowErrors, so
+         * we can check for this by just looking at the exception type
+         * in the cleanup function.  Also, we won't unroll past the SOE
+         * point because the more-recent exception will hit a break frame
+         * as it unrolls to here.
+         */
+        if (self->stackOverflowed)
+            dvmCleanupStackOverflow(self, exception);
+
+        if (catchRelPc < 0) {
+            /* falling through to JNI code or off the bottom of the stack */
+#if DVM_SHOW_EXCEPTION >= 2
+            LOGD("Exception %s from %s:%d not caught locally",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns));
+#endif
+            dvmSetException(self, exception);
+            dvmReleaseTrackedAlloc(exception, self);
+            GOTO_bail();
+        }
+
+#if DVM_SHOW_EXCEPTION >= 3
+        {
+            const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
+            LOGD("Exception %s thrown from %s:%d to %s:%d",
+                exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
+                dvmLineNumFromPC(curMethod, pc - curMethod->insns),
+                dvmGetMethodSourceFile(catchMethod),
+                dvmLineNumFromPC(catchMethod, catchRelPc));
+        }
+#endif
+
+        /*
+         * Adjust local variables to match self->interpSave.curFrame and the
+         * updated PC.
+         */
+        //fp = (u4*) self->interpSave.curFrame;
+        curMethod = SAVEAREA_FROM_FP(fp)->method;
+        self->interpSave.method = curMethod;
+        //methodClass = curMethod->clazz;
+        methodClassDex = curMethod->clazz->pDvmDex;
+        pc = curMethod->insns + catchRelPc;
+        ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+            curMethod->name, curMethod->shorty);
+        DUMP_REGS(curMethod, fp, false);            // show all regs
+
+        /*
+         * Restore the exception if the handler wants it.
+         *
+         * The Dalvik spec mandates that, if an exception handler wants to
+         * do something with the exception, the first instruction executed
+         * must be "move-exception".  We can pass the exception along
+         * through the thread struct, and let the move-exception instruction
+         * clear it for us.
+         *
+         * If the handler doesn't call move-exception, we don't want to
+         * finish here with an exception still pending.
+         */
+        if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
+            dvmSetException(self, exception);
+
+        dvmReleaseTrackedAlloc(exception, self);
+        FINISH(0);
+    }
+GOTO_TARGET_END
+
+
+
+    /*
+     * General handling for invoke-{virtual,super,direct,static,interface},
+     * including "quick" variants.
+     *
+     * Set "methodToCall" to the Method we're calling, and "methodCallRange"
+     * depending on whether this is a "/range" instruction.
+     *
+     * For a range call:
+     *  "vsrc1" holds the argument count (8 bits)
+     *  "vdst" holds the first argument in the range
+     * For a non-range call:
+     *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
+     *  "vdst" holds four 4-bit register indices
+     *
+     * The caller must EXPORT_PC before jumping here, because any method
+     * call can throw a stack overflow exception.
+     */
+GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
+    u2 count, u2 regs)
+    {
+        STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
+
+        //printf("range=%d call=%p count=%d regs=0x%04x\n",
+        //    methodCallRange, methodToCall, count, regs);
+        //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
+        //    methodToCall->name, methodToCall->shorty);
+
+        u4* outs;
+        int i;
+
+        /*
+         * Copy args.  This may corrupt vsrc1/vdst.
+         */
+        if (methodCallRange) {
+            // could use memcpy or a "Duff's device"; most functions have
+            // so few args it won't matter much
+            assert(vsrc1 <= curMethod->outsSize);
+            assert(vsrc1 == methodToCall->insSize);
+            outs = OUTS_FROM_FP(fp, vsrc1);
+            for (i = 0; i < vsrc1; i++)
+                outs[i] = GET_REGISTER(vdst+i);
+        } else {
+            u4 count = vsrc1 >> 4;
+
+            assert(count <= curMethod->outsSize);
+            assert(count == methodToCall->insSize);
+            assert(count <= 5);
+
+            outs = OUTS_FROM_FP(fp, count);
+#if 0
+            if (count == 5) {
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+                count--;
+            }
+            for (i = 0; i < (int) count; i++) {
+                outs[i] = GET_REGISTER(vdst & 0x0f);
+                vdst >>= 4;
+            }
+#else
+            // This version executes fewer instructions but is larger
+            // overall.  Seems to be a teensy bit faster.
+            assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
+            switch (count) {
+            case 5:
+                outs[4] = GET_REGISTER(vsrc1 & 0x0f);
+            case 4:
+                outs[3] = GET_REGISTER(vdst >> 12);
+            case 3:
+                outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
+            case 2:
+                outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
+            case 1:
+                outs[0] = GET_REGISTER(vdst & 0x0f);
+            default:
+                ;
+            }
+#endif
+        }
+    }
+
+    /*
+     * (This was originally a "goto" target; I've kept it separate from the
+     * stuff above in case we want to refactor things again.)
+     *
+     * At this point, we have the arguments stored in the "outs" area of
+     * the current method's stack frame, and the method to call in
+     * "methodToCall".  Push a new stack frame.
+     */
+    {
+        StackSaveArea* newSaveArea;
+        u4* newFp;
+
+        ILOGV("> %s%s.%s %s",
+            dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
+            methodToCall->clazz->descriptor, methodToCall->name,
+            methodToCall->shorty);
+
+        newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
+        newSaveArea = SAVEAREA_FROM_FP(newFp);
+
+        /* verify that we have enough space */
+        if (true) {
+            u1* bottom;
+            bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
+            if (bottom < self->interpStackEnd) {
+                /* stack overflow */
+                LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
+                    self->interpStackStart, self->interpStackEnd, bottom,
+                    (u1*) fp - bottom, self->interpStackSize,
+                    methodToCall->name);
+                dvmHandleStackOverflow(self, methodToCall);
+                assert(dvmCheckException(self));
+                GOTO_exceptionThrown();
+            }
+            //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
+            //    fp, newFp, newSaveArea, bottom);
+        }
+
+#ifdef LOG_INSTR
+        if (methodToCall->registersSize > methodToCall->insSize) {
+            /*
+             * This makes valgrind quiet when we print registers that
+             * haven't been initialized.  Turn it off when the debug
+             * messages are disabled -- we want valgrind to report any
+             * used-before-initialized issues.
+             */
+            memset(newFp, 0xcc,
+                (methodToCall->registersSize - methodToCall->insSize) * 4);
+        }
+#endif
+
+#ifdef EASY_GDB
+        newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
+#endif
+        newSaveArea->prevFrame = fp;
+        newSaveArea->savedPc = pc;
+#if defined(WITH_JIT) && defined(MTERP_STUB)
+        newSaveArea->returnAddr = 0;
+#endif
+        newSaveArea->method = methodToCall;
+
+        if (self->interpBreak.ctl.subMode != 0) {
+            /*
+             * We mark ENTER here for both native and non-native
+             * calls.  For native calls, we'll mark EXIT on return.
+             * For non-native calls, EXIT is marked in the RETURN op.
+             */
+            PC_TO_SELF();
+            dvmReportInvoke(self, methodToCall);
+        }
+
+        if (!dvmIsNativeMethod(methodToCall)) {
+            /*
+             * "Call" interpreted code.  Reposition the PC, update the
+             * frame pointer and other local state, and continue.
+             */
+            curMethod = methodToCall;
+            self->interpSave.method = curMethod;
+            methodClassDex = curMethod->clazz->pDvmDex;
+            pc = methodToCall->insns;
+            self->interpSave.curFrame = fp = newFp;
+#ifdef EASY_GDB
+            debugSaveArea = SAVEAREA_FROM_FP(newFp);
+#endif
+            self->debugIsMethodEntry = true;        // profiling, debugging
+            ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
+                curMethod->name, curMethod->shorty);
+            DUMP_REGS(curMethod, fp, true);         // show input args
+            FINISH(0);                              // jump to method start
+        } else {
+            /* set this up for JNI locals, even if not a JNI native */
+            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
+
+            self->interpSave.curFrame = newFp;
+
+            DUMP_REGS(methodToCall, newFp, true);   // show input args
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPreNativeInvoke(methodToCall, self, fp);
+            }
+
+            ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
+                  methodToCall->name, methodToCall->shorty);
+
+            /*
+             * Jump through native call bridge.  Because we leave no
+             * space for locals on native calls, "newFp" points directly
+             * to the method arguments.
+             */
+            (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
+
+            if (self->interpBreak.ctl.subMode != 0) {
+                dvmReportPostNativeInvoke(methodToCall, self, fp);
+            }
+
+            /* pop frame off */
+            dvmPopJniLocals(self, newSaveArea);
+            self->interpSave.curFrame = fp;
+
+            /*
+             * If the native code threw an exception, or interpreted code
+             * invoked by the native call threw one and nobody has cleared
+             * it, jump to our local exception handling.
+             */
+            if (dvmCheckException(self)) {
+                LOGV("Exception thrown by/below native code");
+                GOTO_exceptionThrown();
+            }
+
+            ILOGD("> retval=0x%llx (leaving native)", retval.j);
+            ILOGD("> (return from native %s.%s to %s.%s %s)",
+                methodToCall->clazz->descriptor, methodToCall->name,
+                curMethod->clazz->descriptor, curMethod->name,
+                curMethod->shorty);
+
+            //u2 invokeInstr = INST_INST(FETCH(0));
+            if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
+                invokeInstr <= OP_INVOKE_INTERFACE*/)
+            {
+                FINISH(3);
+            } else {
+                //LOGE("Unknown invoke instr %02x at %d",
+                //    invokeInstr, (int) (pc - curMethod->insns));
+                assert(false);
+            }
+        }
+    }
+    assert(false);      // should not get here
+GOTO_TARGET_END
+
+/* File: cstubs/enddefs.cpp */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
diff --git a/vm/mterp/portable/enddefs.cpp b/vm/mterp/portable/enddefs.cpp
new file mode 100644
index 0000000..ef28e2f
--- /dev/null
+++ b/vm/mterp/portable/enddefs.cpp
@@ -0,0 +1,7 @@
+/*--- end of opcodes ---*/
+
+bail:
+    ILOGD("|-- Leaving interpreter loop");      // note "curMethod" may be NULL
+
+    self->interpSave.retval = retval;
+}
diff --git a/vm/mterp/portable/entry.cpp b/vm/mterp/portable/entry.cpp
new file mode 100644
index 0000000..39736da
--- /dev/null
+++ b/vm/mterp/portable/entry.cpp
@@ -0,0 +1,65 @@
+/*
+ * Main interpreter loop.
+ *
+ * This was written with an ARM implementation in mind.
+ */
+void dvmInterpretPortable(Thread* self)
+{
+#if defined(EASY_GDB)
+    StackSaveArea* debugSaveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
+#endif
+    DvmDex* methodClassDex;     // curMethod->clazz->pDvmDex
+    JValue retval;
+
+    /* core state */
+    const Method* curMethod;    // method we're interpreting
+    const u2* pc;               // program counter
+    u4* fp;                     // frame pointer
+    u2 inst;                    // current instruction
+    /* instruction decoding */
+    u4 ref;                     // 16 or 32-bit quantity fetched directly
+    u2 vsrc1, vsrc2, vdst;      // usually used for register indexes
+    /* method call setup */
+    const Method* methodToCall;
+    bool methodCallRange;
+    bool jumboFormat;
+
+
+    /* static computed goto table */
+    DEFINE_GOTO_TABLE(handlerTable);
+
+    /* copy state in */
+    curMethod = self->interpSave.method;
+    pc = self->interpSave.pc;
+    fp = self->interpSave.curFrame;
+    retval = self->interpSave.retval;   /* only need for kInterpEntryReturn? */
+
+    methodClassDex = curMethod->clazz->pDvmDex;
+
+    LOGVV("threadid=%d: %s.%s pc=%#x fp=%p",
+        self->threadId, curMethod->clazz->descriptor, curMethod->name,
+        pc - curMethod->insns, fp);
+
+    /*
+     * Handle any ongoing profiling and prep for debugging.
+     */
+    if (self->interpBreak.ctl.subMode != 0) {
+        TRACE_METHOD_ENTER(self, curMethod);
+        self->debugIsMethodEntry = true;   // Always true on startup
+    }
+    /*
+     * DEBUG: scramble this to ensure we're not relying on it.
+     */
+    methodToCall = (const Method*) -1;
+
+#if 0
+    if (self->debugIsMethodEntry) {
+        ILOGD("|-- Now interpreting %s.%s", curMethod->clazz->descriptor,
+                curMethod->name);
+        DUMP_REGS(curMethod, self->interpSave.curFrame, false);
+    }
+#endif
+
+    FINISH(0);                  /* fetch and execute first instruction */
+
+/*--- start of opcodes ---*/
diff --git a/vm/mterp/portable/stubdefs.cpp b/vm/mterp/portable/stubdefs.cpp
new file mode 100644
index 0000000..57ff35c
--- /dev/null
+++ b/vm/mterp/portable/stubdefs.cpp
@@ -0,0 +1,86 @@
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)
+
+#define GOTO_TARGET(_target, ...) _target:
+
+#define GOTO_TARGET_END
+
+/* ugh */
+#define STUB_HACK(x)
+#define JIT_STUB_HACK(x)
+
+/*
+ * InterpSave's pc and fp must be valid when breaking out to a
+ * "Reportxxx" routine.  Because the portable interpreter uses local
+ * variables for these, we must flush prior.  Stubs, however, use
+ * the interpSave vars directly, so this is a nop for stubs.
+ */
+#define PC_FP_TO_SELF()                                                    \
+    self->interpSave.pc = pc;                                              \
+    self->interpSave.curFrame = fp;
+#define PC_TO_SELF() self->interpSave.pc = pc;
+
+/*
+ * Instruction framing.  For a switch-oriented implementation this is
+ * case/break, for a threaded implementation it's a goto label and an
+ * instruction fetch/computed goto.
+ *
+ * Assumes the existence of "const u2* pc" and (for threaded operation)
+ * "u2 inst".
+ */
+# define H(_op)             &&op_##_op
+# define HANDLE_OPCODE(_op) op_##_op:
+# define FINISH(_offset) {                                                  \
+        ADJUST_PC(_offset);                                                 \
+        inst = FETCH(0);                                                    \
+        if (self->interpBreak.ctl.subMode) {                                \
+            dvmCheckBefore(pc, fp, self);                                   \
+        }                                                                   \
+        goto *handlerTable[INST_INST(inst)];                                \
+    }
+# define FINISH_BKPT(_opcode) {                                             \
+        goto *handlerTable[_opcode];                                        \
+    }
+# define DISPATCH_EXTENDED(_opcode) {                                       \
+        goto *handlerTable[0x100 + _opcode];                                \
+    }
+
+#define OP_END
+
+/*
+ * The "goto" targets just turn into goto statements.  The "arguments" are
+ * passed through local variables.
+ */
+
+#define GOTO_exceptionThrown() goto exceptionThrown;
+
+#define GOTO_returnFromMethod() goto returnFromMethod;
+
+#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
+    do {                                                                    \
+        methodCallRange = _methodCallRange;                                 \
+        jumboFormat = _jumboFormat;                                         \
+        goto _target;                                                       \
+    } while(false)
+
+/* for this, the "args" are already in the locals */
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) goto invokeMethod;
+
+#define GOTO_bail() goto bail;
+
+/*
+ * 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(_pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+    }
diff --git a/vm/mterp/rebuild.sh b/vm/mterp/rebuild.sh
new file mode 100755
index 0000000..2014324
--- /dev/null
+++ b/vm/mterp/rebuild.sh
@@ -0,0 +1,29 @@
+#!/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 portable allstubs armv5te armv5te-vfp armv7-a armv7-a-neon x86 x86-atom; 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
+# this will do for now.
+echo Removing unneeded assembly source for portable interpreter
+rm -f out/InterpAsm-portable.S
diff --git a/vm/mterp/x86-atom/OP_ADD_DOUBLE.S b/vm/mterp/x86-atom/OP_ADD_DOUBLE.S
new file mode 100644
index 0000000..22f3938
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_DOUBLE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_DOUBLE.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"addsd   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..0b2bf4f
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_DOUBLE_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_DOUBLE_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"addsd   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_FLOAT.S b/vm/mterp/x86-atom/OP_ADD_FLOAT.S
new file mode 100644
index 0000000..aa3aa22
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_FLOAT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_FLOAT.S
+    */
+
+%include "x86-atom/binopF.S" {"instr":"addss     %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_FLOAT_2ADDR.S
new file mode 100644
index 0000000..3d62703
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_FLOAT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_FLOAT_2ADDR.S
+    */
+
+%include "x86-atom/binopF2addr.S" {"instr":"addss     %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT.S b/vm/mterp/x86-atom/OP_ADD_INT.S
new file mode 100644
index 0000000..a423e75
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT.S
+    */
+
+%include "x86-atom/binop.S" {"instr":"addl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_INT_2ADDR.S
new file mode 100644
index 0000000..2a91f41
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT_2ADDR.S
+    */
+
+%include "x86-atom/binop2addr.S" {"instr":"addl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT_LIT16.S b/vm/mterp/x86-atom/OP_ADD_INT_LIT16.S
new file mode 100644
index 0000000..72479ba
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT_LIT16.S
+    */
+
+%include "x86-atom/binopLit16.S" {"instr":"addl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_INT_LIT8.S b/vm/mterp/x86-atom/OP_ADD_INT_LIT8.S
new file mode 100644
index 0000000..eabd4b5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8.S" {"instr":"addl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_ADD_LONG.S b/vm/mterp/x86-atom/OP_ADD_LONG.S
new file mode 100644
index 0000000..7e31d35
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_LONG.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"paddq   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_ADD_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_ADD_LONG_2ADDR.S
new file mode 100644
index 0000000..4c65a45
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ADD_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ADD_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"paddq   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_AGET.S b/vm/mterp/x86-atom/OP_AGET.S
new file mode 100644
index 0000000..73a27ab
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET.S
@@ -0,0 +1,53 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET.S
+    *
+    * Code: Generic 32-bit array "get" operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *
+    * For: aget, aget-boolean, aget-byte, aget-char, aget-object, sget, aget-short
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the value
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+%default { "mov":"l","scale":"4"}
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $$0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    lea         (%ecx, %edx, $scale), %ecx # %ecx<- &vBB[vCC]
+                                           # trying: lea (%ecx, %edx, scale), %ecx
+                                           # to reduce code size
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    mov$mov offArrayObject_contents(%ecx), %edx # %edx<- vBB[vCC]
+                                                # doing this and the previous instr
+                                                # with one instr was not faster
+    SET_VREG    %edx  rINST             # vAA<- %edx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_AGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_AGET_BOOLEAN.S
new file mode 100644
index 0000000..1d28745
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET_BOOLEAN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_BOOLEAN.S
+    */
+
+%include "x86-atom/OP_AGET.S" { "mov":"zbl", "scale":"1" }
diff --git a/vm/mterp/x86-atom/OP_AGET_BYTE.S b/vm/mterp/x86-atom/OP_AGET_BYTE.S
new file mode 100644
index 0000000..60e4266
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_BYTE.S
+    */
+
+%include "x86-atom/OP_AGET.S" {  "mov":"sbl", "scale":"1" }
diff --git a/vm/mterp/x86-atom/OP_AGET_CHAR.S b/vm/mterp/x86-atom/OP_AGET_CHAR.S
new file mode 100644
index 0000000..114d02d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_CHAR.S
+    */
+
+%include "x86-atom/OP_AGET.S" {  "mov":"zwl", "scale":"2" }
diff --git a/vm/mterp/x86-atom/OP_AGET_OBJECT.S b/vm/mterp/x86-atom/OP_AGET_OBJECT.S
new file mode 100644
index 0000000..0ed02c3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET_OBJECT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_OBJECT.S
+    */
+
+%include "x86-atom/OP_AGET.S"
diff --git a/vm/mterp/x86-atom/OP_AGET_SHORT.S b/vm/mterp/x86-atom/OP_AGET_SHORT.S
new file mode 100644
index 0000000..3ddb9b9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_SHORT.S
+    */
+
+%include "x86-atom/OP_AGET.S" {  "mov":"swl", "scale":"2" }
diff --git a/vm/mterp/x86-atom/OP_AGET_WIDE.S b/vm/mterp/x86-atom/OP_AGET_WIDE.S
new file mode 100644
index 0000000..db5a930
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AGET_WIDE.S
@@ -0,0 +1,43 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AGET_WIDE.S
+    *
+    * Code: 64-bit array get operation.
+    *
+    * For: aget-wide
+    *
+    * Description: Perform an array get operation at the identified index
+    *              of a given array; load the array value into the destination
+    *              register. vAA <- vBB[vCC].
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $$0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        offArrayObject_contents(%ecx, %edx, 8), %xmm0 # %xmm0<- vBB[vCC]
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %xmm0; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_AND_INT.S b/vm/mterp/x86-atom/OP_AND_INT.S
new file mode 100644
index 0000000..10d223b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AND_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT.S
+    */
+
+%include "x86-atom/binop.S" {"instr":"andl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_INT_2ADDR.S b/vm/mterp/x86-atom/OP_AND_INT_2ADDR.S
new file mode 100644
index 0000000..dcbd531
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AND_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT_2ADDR.S
+    */
+
+%include "x86-atom/binop2addr.S" {"instr":"andl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_INT_LIT16.S b/vm/mterp/x86-atom/OP_AND_INT_LIT16.S
new file mode 100644
index 0000000..7e6493d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AND_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT_LIT16.S
+    */
+
+%include "x86-atom/binopLit16.S" {"instr":"andl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_INT_LIT8.S b/vm/mterp/x86-atom/OP_AND_INT_LIT8.S
new file mode 100644
index 0000000..511e3ae
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AND_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8.S" {"instr":"andl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_AND_LONG.S b/vm/mterp/x86-atom/OP_AND_LONG.S
new file mode 100644
index 0000000..e62e312
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AND_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_LONG.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"pand   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_AND_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_AND_LONG_2ADDR.S
new file mode 100644
index 0000000..90e77e6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_AND_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_AND_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"pand   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_APUT.S b/vm/mterp/x86-atom/OP_APUT.S
new file mode 100644
index 0000000..93b3866
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT.S
@@ -0,0 +1,50 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT.S
+    *
+    * Code: Generic 32-bit array put operation.  Provides a "scale" variable
+    *       to specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       move performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the move
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+%default { "mov":"l","scale":"4", "value": "rINST"}
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $$0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         (%ecx, %edx, $scale), %ecx # %ecx<- &vBB[vCC]
+    GET_VREG    rINST                   # rINST<- vAA
+    mov$mov     $value, offArrayObject_contents(%ecx) # vBB[vCC]<- rINSTx; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_APUT_BOOLEAN.S b/vm/mterp/x86-atom/OP_APUT_BOOLEAN.S
new file mode 100644
index 0000000..d9afd6d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT_BOOLEAN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_BOOLEAN.S
+    */
+
+%include "x86-atom/OP_APUT.S" { "mov":"b", "scale":"1", "value":"rINSTbl" }
diff --git a/vm/mterp/x86-atom/OP_APUT_BYTE.S b/vm/mterp/x86-atom/OP_APUT_BYTE.S
new file mode 100644
index 0000000..29cb708
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_BYTE.S
+    */
+
+%include "x86-atom/OP_APUT.S" { "mov":"b", "scale":"1", "value":"rINSTbl" }
diff --git a/vm/mterp/x86-atom/OP_APUT_CHAR.S b/vm/mterp/x86-atom/OP_APUT_CHAR.S
new file mode 100644
index 0000000..d43e540
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_CHAR.S
+    */
+
+%include "x86-atom/OP_APUT.S" { "mov":"w", "scale":"2", "value":"rINSTw" }
diff --git a/vm/mterp/x86-atom/OP_APUT_OBJECT.S b/vm/mterp/x86-atom/OP_APUT_OBJECT.S
new file mode 100644
index 0000000..0e23d71
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT_OBJECT.S
@@ -0,0 +1,77 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_OBJECT.S
+    *
+    * Code: 32-bit array put operation.  Provides an "scale" variable
+    *       specify a scale value which depends on the width of the array
+    *       elements. Provides a "mov" variable which determines the type of
+    *       mov performed also dependent on the type of the array element.
+    *       Provides a "value" register to specify the source of the mov
+    *
+    * For: aput-boolean, aput-byte, aput-char, aput-object, aput-short
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %eax                    # %eax<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $$0, %eax               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%eax), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    GET_VREG    rINST                   # rINST<- vAA
+    lea         (%eax, %edx, 4), %edx   # %edx<- &vBB[vCC]
+    cmp         $$0, rINST              # check for null reference
+    je          .L${opcode}_skip_check  # reference is null so skip type check
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+    movl        %edx, sReg0             # save &vBB[vCC]
+    movl        %eax, sReg1             # save object head
+    movl        offObject_clazz(rINST), %edx # %edx<- obj->clazz
+    movl        %edx, -8(%esp)          # push parameter obj->clazz
+    movl        offObject_clazz(%eax), %eax # %eax<- arrayObj->clazz
+    movl        %eax, -4(%esp)          # push parameter arrayObj->clazz
+    lea         -8(%esp), %esp
+    call        dvmCanPutArrayElement   # test object type vs. array type
+                                        # call: ClassObject* elemClass, ClassObject* arrayClass)
+                                        # return: bool
+    lea         8(%esp), %esp
+    testl       %eax, %eax              # check for invalid array value
+    je          common_errArrayStore    # handle invalid array value
+    movl        sReg0, %edx             # restore &vBB[vCC]
+    movl        rINST, offArrayObject_contents(%edx)
+    movl        rGLUE, %eax
+    FFETCH_ADV  2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    movl        offGlue_cardTable(%eax), %eax # get card table base
+    movl        sReg1, %edx             # restore object head
+    shrl        $$GC_CARD_SHIFT, %edx   # object head to card number
+    movb        %al, (%eax, %edx)       # mark card using object head
+    FGETOP_JMP  2, %ecx                 # jump to next instruction; getop, jmp
+.L${opcode}_skip_check:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        rINST, offArrayObject_contents(%edx)
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_APUT_SHORT.S b/vm/mterp/x86-atom/OP_APUT_SHORT.S
new file mode 100644
index 0000000..daef0d8
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_SHORT.S
+    */
+
+%include "x86-atom/OP_APUT.S" { "mov":"w", "scale":"2", "value":"rINSTw" }
diff --git a/vm/mterp/x86-atom/OP_APUT_WIDE.S b/vm/mterp/x86-atom/OP_APUT_WIDE.S
new file mode 100644
index 0000000..b1b9e6a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_APUT_WIDE.S
@@ -0,0 +1,43 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_APUT_WIDE.S
+    *
+    * Code: 64-bit array put operation.
+    *
+    * For: aput-wide
+    *
+    * Description: Perform an array put operation from the value register;
+    *              store the value register at the identified index of a
+    *              given array. vBB[vCC] <- vAA.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    cmp         $$0, %ecx               # check for null array object
+    je          common_errNullObject    # handle null array object
+    cmp         offArrayObject_length(%ecx), %edx # compare index to arrayObj->length
+    jnc         common_errArrayIndex    # handle index >= length, bail
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vAA
+    movq        %xmm0, offArrayObject_contents(%ecx, %edx, 8) # vBB[vCC]<- %xmm0; value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_ARRAY_LENGTH.S b/vm/mterp/x86-atom/OP_ARRAY_LENGTH.S
new file mode 100644
index 0000000..485f815
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_ARRAY_LENGTH.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_ARRAY_LENGTH.S
+    *
+    * Code: 32-bit array length operation.
+    *
+    * For: array-length
+    *
+    * Description: Store the length of the indicated array in the given
+    *              destination register. vB <- offArrayObject_length(vA)
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $$4, %eax               # %eax<- B
+    andl        $$15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB
+    cmp         $$0, %eax               # check for null array object
+    je          common_errNullObject    # handle null array object
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl        offArrayObject_length(%eax), %eax # %eax<- array length
+    movl        %eax, (rFP, rINST, 4)   # vA<- %eax; array length
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_BREAKPOINT.S b/vm/mterp/x86-atom/OP_BREAKPOINT.S
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_BREAKPOINT.S
diff --git a/vm/mterp/x86-atom/OP_CHECK_CAST.S b/vm/mterp/x86-atom/OP_CHECK_CAST.S
new file mode 100644
index 0000000..c78f336
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CHECK_CAST.S
@@ -0,0 +1,118 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CHECK_CAST.S
+    *
+    * Code: Checks to see if a cast is allowed. Uses no substitutions.
+    *
+    * For: check-cast
+    *
+    * Description: Throw if the reference in the given register cannot be
+    *              cast to the indicated type. The type must be a reference
+    *              type (not a primitive type).
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, type@BBBB
+    */
+
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
+    cmp         $$0, rINST              # check for null reference object
+    je          .L${opcode}_okay        # can always cast null object
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        (%eax, %ecx, 4), %ecx   # %ecx<- resolved class
+    cmp         $$0, %ecx               # check if classes is resolved before?
+    je          .L${opcode}_resolve     # resolve class
+    jmp         .L${opcode}_resolved    # continue
+%break
+
+.L${opcode}_resolved:
+    cmp         %ecx, offObject_clazz(rINST) # check for same class
+    jne         .L${opcode}_fullcheck   # not same class; do full check
+
+.L${opcode}_okay:
+    FINISH      2                       # jump to next instruction
+
+   /*
+    *  Trivial test failed, need to perform full check.
+    *  offObject_clazz(rINST) holds obj->clazz
+    *  %ecx holds class resolved from BBBB
+    *  rINST holds object
+    */
+
+.L${opcode}_fullcheck:
+    movl        offObject_clazz(rINST), %eax  # %eax<- obj->clazz
+    movl        %eax, -12(%esp)         # push parameter obj->clazz
+    movl        %ecx, -8(%esp)          # push parameter # push parameter resolved class
+    lea         -12(%esp), %esp
+    call        dvmInstanceofNonTrivial # call: (ClassObject* instance, ClassObject* clazz)
+                                        # return: int
+    lea         12(%esp), %esp
+    cmp         $$0, %eax               # failed?
+    jne         .L${opcode}_okay        # success
+
+   /*
+    * A cast has failed.  We need to throw a ClassCastException with the
+    * class of the object that failed to be cast.
+    */
+
+    EXPORT_PC                           # we will throw an exception
+#error BIT ROT!!!
+    /*
+     * TODO: Code here needs to call dvmThrowClassCastException with two
+     * arguments.
+     */
+#if 0
+    /* old obsolete code that called dvmThrowExceptionWithClassMessage */
+    movl        $$.LstrClassCastExceptionPtr, -8(%esp) # push parameter message
+    movl        offObject_clazz(rINST), rINST # rINST<- obj->clazz
+    movl        offClassObject_descriptor(rINST), rINST # rINST<- obj->clazz->descriptor
+    movl        rINST, -4(%esp)         # push parameter obj->clazz->descriptor
+    lea         -8(%esp), %esp
+    call        dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
+                                                  #       const char* messageDescriptor, Object* cause)
+                                                  # return: void
+#endif
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown
+
+   /*
+    * Resolution required.  This is the least-likely path.
+    *
+    *  rINST holds object
+    */
+
+.L${opcode}_resolve:
+    movl        offGlue_method(%edx), %eax # %eax<- glue->method
+    FETCH       1, %ecx                 # %ecx holds BBBB
+    EXPORT_PC                           # in case we throw an exception
+    movl        $$0, -8(%esp)           # push parameter false
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        %ecx, -12(%esp)         # push parameter BBBB
+    movl        %eax, -16(%esp)         # push parameter glue->method>clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # resolve ClassObject pointer
+                                        # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return ClassObject*
+    lea         16(%esp), %esp
+    cmp         $$0, %eax               # check for null pointer
+    je          common_exceptionThrown  # handle excpetion
+    movl        %eax, %ecx              # %ecx<- resolved class
+    jmp         .L${opcode}_resolved
diff --git a/vm/mterp/x86-atom/OP_CHECK_CAST_JUMBO.S b/vm/mterp/x86-atom/OP_CHECK_CAST_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CHECK_CAST_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_CMPG_DOUBLE.S b/vm/mterp/x86-atom/OP_CMPG_DOUBLE.S
new file mode 100644
index 0000000..87f8a3b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CMPG_DOUBLE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPG_DOUBLE.S
+    */
+
+%include "x86-atom/OP_CMPL_FLOAT.S" { "nan":"$0x1", "sod":"d"}
diff --git a/vm/mterp/x86-atom/OP_CMPG_FLOAT.S b/vm/mterp/x86-atom/OP_CMPG_FLOAT.S
new file mode 100644
index 0000000..de42969
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CMPG_FLOAT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPG_FLOAT.S
+    */
+
+%include "x86-atom/OP_CMPL_FLOAT.S" { "nan":"$0x1" }
diff --git a/vm/mterp/x86-atom/OP_CMPL_DOUBLE.S b/vm/mterp/x86-atom/OP_CMPL_DOUBLE.S
new file mode 100644
index 0000000..2a603a4
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CMPL_DOUBLE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_DOUBLE.S
+    */
+
+%include "x86-atom/OP_CMPL_FLOAT.S" { "sod":"d" }
diff --git a/vm/mterp/x86-atom/OP_CMPL_FLOAT.S b/vm/mterp/x86-atom/OP_CMPL_FLOAT.S
new file mode 100644
index 0000000..5cb3ec7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CMPL_FLOAT.S
@@ -0,0 +1,63 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMPL_FLOAT.S
+    *
+    * Code: Provides a "nan" variable to specify the return value for
+    *       NaN. Provides a variable "sod" which appends a "s" or a "d"
+    *       to the move and comparison instructions, depending on if we
+    *       are working with a float or a double. For instructions
+    *       cmpx-float and cmpx-double, the x will be eiher a g or a l
+    *       to specify positive or negative bias for NaN.
+    *
+    * For: cmpg-double, dmpg-float, cmpl-double, cmpl-float
+    *
+    * Description: Perform the indicated floating point or long comparison,
+    *              storing 0 if the two arguments are equal, 1 if the second
+    *              argument is larger, or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+%default { "nan":"$0xFFFFFFFF" , "sod":"s" }
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movs$sod    (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    comis$sod   (rFP, %edx, 4), %xmm0   # do comparison
+    ja          .L${opcode}_greater
+    jp          .L${opcode}_finalNan
+    jz          .L${opcode}_final
+
+.L${opcode}_less:
+    movl        $$0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+%break
+.L${opcode}_greater:
+    movl        $$0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.L${opcode}_final:
+    movl        $$0x0, (rFP, rINST, 4)  # vAA<- equal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+.L${opcode}_finalNan:
+    movl        $nan, (rFP, rINST, 4)   # vAA<- NaN
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CMP_LONG.S b/vm/mterp/x86-atom/OP_CMP_LONG.S
new file mode 100644
index 0000000..cf021a3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CMP_LONG.S
@@ -0,0 +1,55 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CMP_LONG.S
+    *
+    * Code: Compare floating point values. Uses no substitutions.
+    *
+    * For: cmp-long
+    *
+    * Description: Perform a long comparison, storing 0 if the two
+    *              arguments are equal, 1 if the second argument is larger
+    *              or -1 if the first argument is larger.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        4(rFP, %ecx, 4), %eax   # %eax<- vBBhi
+    cmp         4(rFP, %edx, 4), %eax   # compare vCChi and vBBhi
+    jl          .L${opcode}_less
+    jg          .L${opcode}_greater
+    movl        (rFP, %ecx, 4), %eax    # %eax<- vBBlo
+    cmp         (rFP, %edx, 4), %eax    # compare vCClo and vBBlo
+    ja          .L${opcode}_greater
+    jne         .L${opcode}_less
+    jmp         .L${opcode}_final
+%break
+
+.L${opcode}_final:
+    movl        $$0x0, (rFP, rINST, 4)  # vAA<- equal
+    FINISH      2                       # jump to next instruction
+
+.L${opcode}_less:
+    movl        $$0xFFFFFFFF, (rFP, rINST, 4) # vAA<- less than
+    FINISH      2                       # jump to next instruction
+
+.L${opcode}_greater:
+    movl        $$0x1, (rFP, rINST, 4)  # vAA<- greater than
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_CONST.S b/vm/mterp/x86-atom/OP_CONST.S
new file mode 100644
index 0000000..7ff4c23
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const
+    *
+    * Description: Move the given literal value into the specified register
+    *
+    * Format: AA|op BBBBlo BBBBhi (31i)
+    *
+    * Syntax: op vAA, #+BBBBBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    shl         $$16, %edx              # move BBBB to high bits
+    or          %edx, %ecx              # %ecx<- #+BBBBBBBB
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; literal
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_16.S b/vm/mterp/x86-atom/OP_CONST_16.S
new file mode 100644
index 0000000..f340696
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_16.S
@@ -0,0 +1,34 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_16.S
+    *
+    * Code: Moves a literal to a register. Uses no substitutions.
+    *
+    * For: const/16
+    *
+    * Description: Move the given literal value (right-zero-extended to 32
+    *              bits) into the specified register
+    *
+    * Format: AA|op BBBB (21s)
+    *
+    * Syntax: op vAA, #+BBBB
+    */
+
+    FETCHs      1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    SET_VREG    %edx rINST              # vAA<- BBBB; literal
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_4.S b/vm/mterp/x86-atom/OP_CONST_4.S
new file mode 100644
index 0000000..5396d72
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_4.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_4.S
+    *
+    * Code: Moves a literal to a register. Uses no substitutions.
+    *
+    * For: const/4
+    *
+    * Description: Move the given literal value (right-zero-extended to 32
+    *              bits) into the specified register.
+    *
+    * Format: B|A|op (11n)
+    *
+    * Syntax: op vA, #+B
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    andl        $$15, rINST             # rINST<- A
+    shl         $$24, %edx              # %edx<- B000
+    sar         $$28, %edx              # %edx<- right-zero-extended B
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    SET_VREG    %edx, rINST             # vA<- %edx; literal
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_CLASS.S b/vm/mterp/x86-atom/OP_CONST_CLASS.S
new file mode 100644
index 0000000..bc6657c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_CLASS.S
@@ -0,0 +1,67 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_CLASS.S
+    *
+    * Code: Move a class reference to a register. Uses no substitutions.
+    *
+    * For: const/class
+    *
+    * Description: Move a reference to the class specified
+    *              by the given index into the specified register.
+    *              In the case where the indicated type is primitive,
+    *              this will store a reference to the primitive type's
+    *              degenerate class.
+    *
+    * Format: AA|op BBBBlo BBBBhi (21c)
+    *
+    * Syntax: op vAA, field@BBBB
+    */
+
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
+    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved class
+    cmp         $$0, %eax               # check if classes is resolved before?
+    je          .L${opcode}_resolve     # resolve class
+    SET_VREG    %eax, rINST             # vAA<- resolved class
+    FINISH      2                       # jump to next instruction
+%break
+
+   /*
+    * Continuation if the Class has not yet been resolved.
+    *  %ecx: BBBB (Class ref)
+    *  need: target register
+    */
+
+.L${opcode}_resolve:
+    EXPORT_PC
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        $$1, -4(%esp)           # push parameter true
+    movl        %ecx, -8(%esp)          # push parameter
+    movl        %edx, -12(%esp)         # push parameter glue->method->clazz
+    lea         -12(%esp), %esp
+    call        dvmResolveClass         # resolve ClassObject pointer
+                                        # class: (const ClassObject* referrer, u4 classIdx,
+                                        #         bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         12(%esp), %esp
+    cmp         $$0, %eax               # check for null pointer
+    je          common_exceptionThrown  # handle exception
+    SET_VREG    %eax, rINST             # vAA<- resolved class
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_CONST_CLASS_JUMBO.S b/vm/mterp/x86-atom/OP_CONST_CLASS_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_CLASS_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_CONST_HIGH16.S b/vm/mterp/x86-atom/OP_CONST_HIGH16.S
new file mode 100644
index 0000000..f47d34b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_HIGH16.S
@@ -0,0 +1,35 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_HIGH16.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const/high16
+    *
+    * Description: Move the given literal value (right-zero-extended to 32
+    *              bits) into the specified register
+    *
+    * Format: AA|op BBBB (21h)
+    *
+    * Syntax: op vAA, #+BBBB0000
+    */
+
+    FETCH       1, %ecx                 # %ecx<- 0000BBBB (zero-extended)
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    shl         $$16, %ecx              # %ecx<- BBBB0000
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; BBBB0000
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_STRING.S b/vm/mterp/x86-atom/OP_CONST_STRING.S
new file mode 100644
index 0000000..c958ed4
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_STRING.S
@@ -0,0 +1,65 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_STRING.S
+    *
+    * Code: Move a string reference to a register. Uses no substitutions.
+    *
+    * For: const/string
+    *
+    * Description: Move a referece to the string specified by the given
+    *              index into the specified register. vAA <- pResString[BBBB]
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
+    movl        offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
+    movl        (%eax, %ecx, 4), %eax   # %eax<- pResStrings[BBBB]
+    cmp         $$0, %eax               # check if string is resolved
+    je          .L${opcode}_resolve     # resolve string reference
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FINISH      2                       # jump to next instruction
+
+%break
+
+
+   /*
+    * Continuation if the Class has not yet been resolved.
+    *  %ecx: BBBB (Class ref)
+    *  need: target register
+    */
+
+.L${opcode}_resolve:
+    EXPORT_PC
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %ecx, -4(%esp)          # push parameter class ref
+    movl        %edx, -8(%esp)          # push parameter glue->method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveString        # resolve string reference
+                                        # call: (const ClassObject* referrer, u4 stringIdx)
+                                        # return: StringObject*
+    lea         8(%esp), %esp
+    cmp         $$0, %eax               # check if resolved string failed
+    je          common_exceptionThrown  # resolve failed; exception thrown
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_STRING_JUMBO.S b/vm/mterp/x86-atom/OP_CONST_STRING_JUMBO.S
new file mode 100644
index 0000000..09d045d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_STRING_JUMBO.S
@@ -0,0 +1,66 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_STRING_JUMBO.S
+    *
+    * Code: Move a string reference to a register. Uses no substitutions.
+    *
+    * For: const/string-jumbo
+    *
+    * Description: Move a reference to the string specified by the given
+    *              index into the specified register. vAA <- pResString[BBBB]
+    *
+    * Format: AA|op BBBBlo BBBBhi (31c)
+    *
+    * Syntax: op vAA, string@BBBBBBBB
+    */
+
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %eax # %eax<- glue->methodClassDex
+    movl        offDvmDex_pResStrings(%eax), %eax # %eax<- glue->methodClassDex->pResStrings
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $$16, %edx              # %edx<- prepare to create &BBBBBBBB
+    or          %edx, %ecx              # %ecx<- &BBBBBBBB
+    movl        (%eax, %ecx, 4), %eax   # %eax<- pResStrings[BBBB]
+    cmp         $$0, %eax               # check if string is resolved
+    je          .L${opcode}_resolve     # resolve string reference
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FINISH      3                       # jump to next instruction
+%break
+
+
+   /*
+    * Continuation if the Class has not yet been resolved.
+    *  %ecx: BBBB (Class ref)
+    *  need: target register
+    */
+.L${opcode}_resolve:
+    EXPORT_PC
+    movl        rGLUE, %edx             # get MterpGlue pointer
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx <- glue->method->clazz
+    movl        %ecx, -4(%esp)          # push parameter class ref
+    movl        %edx, -8(%esp)          # push parameter glue->method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveString        # resolve string reference
+                                        # call: (const ClassObject* referrer, u4 stringIdx)
+                                        # return: StringObject*
+    lea         8(%esp), %esp
+    cmp         $$0, %eax               # check if resolved string failed
+    je          common_exceptionThrown  # resolve failed; exception thrown
+    SET_VREG    %eax, rINST             # vAA<- %eax; pResString[BBBB]
+    FINISH      3                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE.S b/vm/mterp/x86-atom/OP_CONST_WIDE.S
new file mode 100644
index 0000000..1ce7c76
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_WIDE.S
@@ -0,0 +1,42 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const-wide
+    *
+    * Description: Move the given literal value into the specified
+    *              register pair
+    *
+    * Format: AA|op BBBBlolo BBBBlohi BBBBhilo BBBBhihi (51l)
+    *
+    * Syntax: op vAA, #+BBBBBBBBBBBBBBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlolo
+    FETCH       2, %edx                 # %edx<- BBBBlohi
+    shl         $$16, %edx              # %edx<- prepare to create #+BBBBBBBBlo
+    or          %edx, %ecx              # %ecx<- #+BBBBBBBBlo
+    movl        %ecx, (rFP, rINST, 4)   # vAA <- #+BBBBBBBBlo
+    FETCH       3, %ecx                 # %ecx<- BBBBhilo
+    FETCH       4, %edx                 # %edx<- BBBBhihi
+    FFETCH_ADV  5, %eax                 # %eax<- next instruction hi; fetch, advance
+    shl         $$16, %edx              # %edx<- prepare to create #+BBBBBBBBhi
+    or          %edx, %ecx              # %ecx<- #+BBBBBBBBhi
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1 <- #+BBBBBBBBlo
+    FGETOP_JMP  5, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE_16.S b/vm/mterp/x86-atom/OP_CONST_WIDE_16.S
new file mode 100644
index 0000000..c980f10
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_WIDE_16.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE_16.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const-wide/16
+    *
+    * Description: Move the given literal value (sign-extended to 64 bits)
+    *              into the specified register-pair
+    *
+    * Format: AA|op BBBB (21s)
+    *
+    * Syntax: op vAA, #+BBBB
+    */
+
+    FETCHs      1, %ecx                 # %ecx<- ssssBBBB (sign-extended)
+    movl        %ecx, %edx              # %edx<- ssssBBBB (sign-extended)
+    sar         $$31, %ecx              # %ecx<- sign bit
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        %edx, (rFP, rINST, 4)   # vAA<- ssssBBBB
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1<- ssssssss
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE_32.S b/vm/mterp/x86-atom/OP_CONST_WIDE_32.S
new file mode 100644
index 0000000..92f8450
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_WIDE_32.S
@@ -0,0 +1,39 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE_32.S
+    *
+    * Code: Move a literal to a register. Uses no substitutions.
+    *
+    * For: const-wide/32
+    *
+    * Description: Move the given literal value (sign-extended to 64 bits)
+    *              into the specified register-pair
+    *
+    * Format: AA|op BBBBlo BBBBhi (31i)
+    *
+    * Syntax: op vAA, #+BBBBBBBB
+    */
+
+    FETCH       1,  %edx                # %edx<- BBBBlo
+    FETCHs      2, %ecx                 # %ecx<- BBBBhi
+    shl         $$16, %ecx              # prepare to create #+BBBBBBBB
+    or          %ecx, %edx              # %edx<- %edx<- #+BBBBBBBB
+    sar         $$31, %ecx              # %ecx<- sign bit
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        %edx, (rFP, rINST, 4)   # vAA<-  BBBBBBBB
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1<- ssssssss
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_CONST_WIDE_HIGH16.S b/vm/mterp/x86-atom/OP_CONST_WIDE_HIGH16.S
new file mode 100644
index 0000000..5b4b4f1
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_CONST_WIDE_HIGH16.S
@@ -0,0 +1,35 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_CONST_WIDE_HIGH16.S
+    *
+    * Code: Move a literal value to a register. Uses no substitutions.
+    *
+    * For: const-wide/high16
+    *
+    * Description: Move the given literal value (right-zero-extended to 64
+    *              bits) into the specified register
+    *
+    * Format: AA|op BBBB (21h)
+    *
+    * Syntax: op vAA, #+BBBB000000000000
+    */
+
+    FETCH       1, %ecx                 # %ecx<- 0000BBBB (zero-extended)
+    shl         $$16, %ecx              # rINST<- AA
+    movl        $$0, (rFP, rINST, 4)    # vAAlow<- 00000000
+    movl        %ecx, 4(rFP, rINST, 4)  # vAAhigh<- %ecx; BBBB0000
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DISPATCH_FF.S b/vm/mterp/x86-atom/OP_DISPATCH_FF.S
new file mode 100644
index 0000000..3c1c9f5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DISPATCH_FF.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DISPATCH_FF.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_DOUBLE.S b/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
new file mode 100644
index 0000000..418a230
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_DOUBLE.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_DOUBLE.S
+    *
+    * Code: Divides doubles. Uses no substitutions.
+    *
+    * For: div-double
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in a destination register
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    fldl        (rFP, %ecx, 4)          # floating point stack vBB
+    fdivl       (rFP, %edx, 4)          # divide double; vBB/vCC
+    fstpl       (rFP, rINST, 4)         # vAA<- result
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..7003e30
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_DOUBLE_2ADDR.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_DOUBLE_2ADDR.S
+    *
+    * Code: Divides doubles. Uses no substitutions.
+    *
+    * For: div-double/2addr
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in the first source reigster
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    andl        $$15, %edx              # %edx<- A
+    shr         $$4, rINST              # rINST<- B
+    fldl        (rFP, %edx, 4)          # %xmm0<- vA
+    fdivl       (rFP, rINST, 4)         # divide double; vA/vB
+    fstpl       (rFP, %edx, 4)          # vAA<- result
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DIV_FLOAT.S b/vm/mterp/x86-atom/OP_DIV_FLOAT.S
new file mode 100644
index 0000000..a7aabd7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_FLOAT.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_FLOAT.S
+    *
+    * Code: Divides floats. Uses no substitutions.
+    *
+    * For: div-float
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in a destiniation register
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    flds        (rFP, %eax, 4)          # floating point stack vBB
+    fdivs       (rFP, %ecx, 4)          # divide double; vBB/vCC
+    fstps       (rFP, rINST, 4)         # vAA<- result
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_FLOAT_2ADDR.S
new file mode 100644
index 0000000..471f30a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_FLOAT_2ADDR.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_FLOAT_2ADDR.S
+    *
+    * Code: Divides floats. Uses no substitutions.
+    *
+    * For: div-float/2addr
+    *
+    * Description: Divide operation on two source registers, storing
+    *              the result in the first source reigster
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $$15, %ecx              # %ecx<- A
+    shr         $$4, rINST              # rINST<- B
+    flds        (rFP, %ecx, 4)          # %xmm0<- vA
+    fdivs       (rFP, rINST, 4)         # divide double; vA/vB
+    fstps       (rFP, %ecx, 4)          # vAA<- result
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DIV_INT.S b/vm/mterp/x86-atom/OP_DIV_INT.S
new file mode 100644
index 0000000..c7f5b27
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT.S
+    */
+
+%include "x86-atom/binopD.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
new file mode 100644
index 0000000..762d82f
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT_2ADDR.S
+    */
+
+%include "x86-atom/binopD2addr.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_LIT16.S b/vm/mterp/x86-atom/OP_DIV_INT_LIT16.S
new file mode 100644
index 0000000..9c2ce55
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT_LIT16.S
+    */
+
+%include "x86-atom/binopDLit16.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_INT_LIT8.S b/vm/mterp/x86-atom/OP_DIV_INT_LIT8.S
new file mode 100644
index 0000000..ef0ea7b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_INT_LIT8.S
+    */
+
+%include "x86-atom/binopDLit8.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_LONG.S b/vm/mterp/x86-atom/OP_DIV_LONG.S
new file mode 100644
index 0000000..38ade6a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_LONG.S
+    */
+
+%include "x86-atom/binopDivRemLong.S"
diff --git a/vm/mterp/x86-atom/OP_DIV_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_DIV_LONG_2ADDR.S
new file mode 100644
index 0000000..41e5430
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DIV_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DIV_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopDivRemLong2Addr.S"
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_FLOAT.S
new file mode 100644
index 0000000..516a2e6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DOUBLE_TO_FLOAT.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DOUBLE_TO_FLOAT.S
+    *
+    * Code: Converts a double to a float. Uses no substitutions.
+    *
+    * For: double-to-float
+    *
+    * Description: Convert the source register (a double) to a float
+    *              and store the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %edx              # %edx<- A
+    fldl        (rFP, rINST, 4)         # load &vB
+    fstps       (rFP, %edx, 4)          # store float
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
new file mode 100644
index 0000000..f377762
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,68 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DOUBLE_TO_INT.S
+    *
+    * Code: Converts a double to an integer. Uses no substitutions.
+    *
+    * For: double-to-int
+    *
+    * Description: Convert the source register (a double) to an integer
+    *              and store the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %edx              # %edx<- A
+    fldl        (rFP, rINST, 4)         # load &vB
+    fildl       .LintMax                # push max int value
+    fildl       .LintMin                # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .L${opcode}_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .L${opcode}_nanInf      # handle posInf or NaN
+    jmp         .L${opcode}_break       # do conversion
+%break
+
+.L${opcode}_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $$0xc00, -2(%esp)       # reset control
+    fldcw       -2(%esp)                # load control word
+    xorl        $$0xc00, -2(%esp)       # reset control
+    fistpl      (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_nanInf:
+    jnp         .L${opcode}_posInf
+    fstps       (rFP, %edx, 4)
+    movl        $$0x00000000,  (rFP, %edx, 4) # vA<- NaN
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_posInf:
+    fstps       (rFP, %edx, 4)
+    movl        $$0x7FFFFFFF,  (rFP, %edx, 4) # vA<- posInf
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_negInf:
+    fstps       (rFP, %edx, 4)
+    fstps       (rFP, %edx, 4)
+    movl        $$0x80000000,  (rFP, %edx, 4) # vA<- negInf
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S b/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
new file mode 100644
index 0000000..2ce9bcc
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_DOUBLE_TO_LONG.S
@@ -0,0 +1,71 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_DOUBLE_TO_LONG.S
+    *
+    * Code: Converts a double to a long. Uses no substitutions.
+    *
+    * For: double-to-long
+    *
+    * Description: Convert the double in source register to a long
+    *              and store in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %ecx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %edx              # %ecx<- A
+    fldl        (rFP, rINST, 4)         # push vB to floating point stack
+    fildll      .LvaluePosInfLong       # push max int value
+    fildll      .LvalueNegInfLong       # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .L${opcode}_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .L${opcode}_nanInf      # handle posInf or NaN
+    jmp         .L${opcode}_break       # do conversion
+%break
+
+.L${opcode}_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $$0xc00, -2(%esp)       # reset control
+    fldcw       -2(%esp)                # load control word
+    xorl        $$0xc00, -2(%esp)       # reset control
+    fistpll     (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_nanInf:
+    jnp         .L${opcode}_posInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNanLong, %xmm0   # %xmm0<- NaN
+    movq        %xmm0,  (rFP, %edx, 4)  # vA<- %xmm0; NaN
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_posInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; posInf
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_negInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; negInf
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_EXECUTE_INLINE.S b/vm/mterp/x86-atom/OP_EXECUTE_INLINE.S
new file mode 100644
index 0000000..4f01cef
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_EXECUTE_INLINE.S
@@ -0,0 +1,86 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_EXECUTE_INLINE.S
+    *
+    * Code: Executes a "native inline" instruction. Uses no substitutions.
+    *
+    * For: execute-inline
+    *
+    * Description: Executes a "native inline" instruction. This instruction
+    *              is generated by the optimizer.
+    *
+    * Format:
+    *
+    * Syntax: vAA, {vC, vD, vE, vF}, inline@BBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    addl        $$offGlue_retval, %eax  # %eax<- &glue->retval
+    EXPORT_PC
+    shr         $$4, rINST              # rINST<- B
+    movl        %eax, -8(%esp)          # push parameter glue->retval
+    lea         -24(%esp), %esp
+    jmp         .L${opcode}_continue
+%break
+
+   /*
+    * Extract args, call function.
+    *  rINST = #of args (0-4)
+    *  %ecx = call index
+    */
+
+.L${opcode}_continue:
+    FETCH       2, %edx                 # %edx<- FEDC
+    cmp         $$1, rINST              # determine number of arguments
+    jl          0f                      # handle zero args
+    je          1f                      # handle one arg
+    cmp         $$3, rINST
+    jl          2f                      # handle two args
+    je          3f                      # handle three args
+4:
+    movl        %edx, rINST             # rINST<- FEDC
+    and         $$0xf000, rINST         # isolate F
+    shr         $$10, rINST
+    movl        (rFP, rINST), rINST     # rINST<- vF
+    movl        rINST, 12(%esp)         # push parameter vF
+3:
+    movl        %edx, rINST             # rINST<- FEDC
+    and         $$0x0f00, rINST         # isolate E
+    shr         $$6, rINST
+    movl        (rFP, rINST), rINST     # rINST<- vE
+    movl        rINST, 8(%esp)          # push parameter E
+2:
+    movl        %edx, rINST             # rINST<- FEDC
+    and         $$0x00f0, rINST         # isolate D
+    shr         $$2, rINST
+    movl        (rFP, rINST), rINST     # rINST<- vD
+    movl        rINST, 4(%esp)          # push parameter D
+1:
+    and         $$0x000f, %edx          # isolate C
+    movl        (rFP, %edx, 4), %edx    # rINST<- vC
+    movl        %edx, (%esp)            # push parameter C
+0:
+    shl         $$4, %ecx
+    movl        $$gDvmInlineOpsTable, %eax # %eax<- address for table of inline operations
+    call        *(%eax, %ecx)           # call function
+
+    cmp         $$0, %eax               # check boolean result of inline
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         24(%esp), %esp          # update stack pointer
+    je          common_exceptionThrown  # handle exception
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/x86-atom/OP_EXECUTE_INLINE_RANGE.S
new file mode 100644
index 0000000..cd5a048
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_EXECUTE_INLINE_RANGE.S
@@ -0,0 +1,75 @@
+   /* Copyright (C) 2010 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_EXECUTE_INLINE_RANGE.S
+    *
+    * Code: Executes a "native inline" instruction. Uses no substitutions.
+    *
+    * For: execute-inline
+    *
+    * Description: Executes a "native inline" instruction. This instruction
+    *              is generated by the optimizer.
+    *
+    * Format:
+    *
+    * Syntax: AA, {vCCCC..v(CCCC+AA-1)}, inline@BBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    addl        $$offGlue_retval, %eax  # %eax<- &glue->retval
+    EXPORT_PC
+    movl        %eax, -8(%esp)          # push parameter glue->retval
+    lea         -24(%esp), %esp
+    jmp         .L${opcode}_continue
+%break
+
+   /*
+    * Extract args, call function.
+    *  rINST = #of args (0-4)
+    *  %ecx = call index
+    */
+
+.L${opcode}_continue:
+    FETCH       2, %edx                 # %edx<- FEDC
+    cmp         $$1, rINST              # determine number of arguments
+    jl          0f                      # handle zero args
+    je          1f                      # handle one arg
+    cmp         $$3, rINST
+    jl          2f                      # handle two args
+    je          3f                      # handle three args
+4:
+    movl        12(rFP, %edx, 4), rINST     # rINST<- vF
+    movl        rINST, 12(%esp)         # push parameter vF
+3:
+    movl        8(rFP, %edx, 4), rINST     # rINST<- vE
+    movl        rINST, 8(%esp)          # push parameter E
+2:
+    movl        4(rFP, %edx, 4), rINST     # rINST<- vD
+    movl        rINST, 4(%esp)          # push parameter D
+1:
+    movl        (rFP, %edx, 4), %edx    # rINST<- vC
+    movl        %edx, (%esp)            # push parameter C
+0:
+    shl         $$4, %ecx
+    movl        $$gDvmInlineOpsTable, %eax # %eax<- address for table of inline operations
+    call        *(%eax, %ecx)           # call function
+
+    cmp         $$0, %eax               # check boolean result of inline
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    lea         24(%esp), %esp          # update stack pointer
+    je          common_exceptionThrown  # handle exception
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY.S b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY.S
new file mode 100644
index 0000000..f804f3e
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY.S
@@ -0,0 +1,173 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILLED_NEW_ARRAY.S
+    *
+    * Code: Constructs and fills an array with the given data. Provides
+    *
+    * For: float-to-int
+    *
+    * Description: Construct an array of the given type and size,
+    *              filling it with the supplied contents. The type
+    *              must be an array type. The array's contents
+    *              must be single-word. The constructed instance
+    *              is stored as a result in the same way that the
+    *              method invocation instructions store their results,
+    *              so the constructed instance must be moved to a
+    *              register with a subsequent move-result-object
+    *              instruction.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc) (range)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, vtaboff@CCCC
+    *         [B=4] op {vD, vE, vF, vG}, vtaboff@CCCC
+    *         [B=3] op {vD, vE, vF}, vtaboff@CCCC
+    *         [B=2] op {vD, vE}, vtaboff@CCCC
+    *         [B=1] op {vD}, vtaboff@CCCC
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB
+    *         op {vCCCC .. vNNNN}, type@BBBB
+    */
+
+%default { "isrange":"0" }
+
+    movl        rGLUE, %edx             # %edx<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- glue->methodClassDex
+    movl        offDvmDex_pResClasses(%edx), %edx # %edx<- glue->methodClassDex->pResClasses
+    FETCH       1, %ecx                 # %ecx<- BBBB
+    EXPORT_PC
+    movl (%edx, %ecx, 4), %eax # %eax<- possibly resolved class
+    cmp         $$0, %eax               # %eax<- check if already resolved
+    jne         .L${opcode}_continue
+    jmp         .L${opcode}_break
+%break
+
+.L${opcode}_break:
+    movl        $$0, -8(%esp)           # push parameter false
+    movl        %ecx, -12(%esp)         # push parameter BBBB
+    movl        rGLUE, %edx             # %edx<- MterpGlue pointer
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -16(%esp)         # push parameter glue->method->clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         16(%esp), %esp
+    cmp         $$0, %eax               # check for null return
+    je          common_exceptionThrown  # handle exception
+
+   /*
+    * On entry:
+    *  %eax holds array class
+    *  rINST holds BA or AA
+    */
+
+.L${opcode}_continue:
+    movl        offClassObject_descriptor(%eax), %eax # %eax<- arrayClass->descriptor
+    movzbl      1(%eax), %eax           # %eax<- descriptor[1]
+    cmpb        $$'I', %al             # check if array of ints
+    je          1f
+    cmpb        $$'L', %al
+    je          1f
+    cmpb        $$'[', %al
+    jne         .L${opcode}_notimpl     # jump to not implemented
+1:
+    movl        %eax, sReg0             # save type
+    movl        rINST, -12(%esp)        # push parameter length
+    movl        %eax, -16(%esp)         # push parameter descriptor[1]
+    movl        $$ALLOC_DONT_TRACK, -8(%esp) # push parameter to allocate flags
+    .if         (!$isrange)
+    shrl        $$4, -12(%esp)          # parameter length is B
+    .endif
+    lea         -16(%esp), %esp
+    call        dvmAllocPrimitiveArray  # call: (char type, size_t length, int allocFlags)
+                                        # return: ArrayObject*
+    lea         16(%esp), %esp
+    cmp         $$0, %eax               # check for null return
+    je          common_exceptionThrown  # handle exception
+
+    FETCH       2, %edx                 # %edx<- FEDC or CCCC
+    movl        rGLUE, %ecx             # %ecx<- MterpGlue pointer
+    movl        %eax, offGlue_retval(%ecx) # retval<- new array
+    lea         offArrayObject_contents(%eax), %eax # %eax<- newArray->contents
+    subl        $$1, -12(%esp)          # length--; check for negative
+    js          2f                      # if length was zero, finish
+
+   /*
+    * copy values from registers into the array
+    * %eax=array, %edx=CCCC/FEDC, -12(%esp)=length (from AA or B), rINST=AA/BA
+    */
+
+    .if         $isrange
+    lea         (rFP, %edx, 4), %ecx    # %ecx<- &fpp[CCCC]
+1:
+    movl        (%ecx), %edx            # %edx<- %ecx++
+    lea         4(%ecx), %ecx           # %ecx++
+    movl        %edx, (%eax)            # *contents<- vX
+    lea         4(%eax), %eax           # %eax++; contents++
+    subl        $$1, -12(%esp)          # length--
+    jns         1b                      # or continue at 2
+    .else
+    cmp         $$4, -12(%esp)          # check length
+    jne         1f                      # has four args
+    and         $$15, rINST             # rINST<- A
+    GET_VREG    rINST                   # rINST<- vA
+    subl        $$1, -12(%esp)          # count--
+    movl        rINST, 16(%eax)         # contents[4]<- vA
+1:
+    movl        %edx, %ecx              # %ecx<- %edx; ecx for temp
+    andl        $$15, %ecx              # %ecx<- G/F/E/D
+    GET_VREG    %ecx                    # %ecx<- vG/vF/vE/vD
+    shr         $$4, %edx               # %edx<- put next reg in low 4
+    subl        $$1, -12(%esp)          # count--
+    movl        %ecx, (%eax)            # *contents<- vX
+    lea         4(%eax), %eax           # %eax++; contents++
+    jns         1b                      # or continue at 2
+    .endif
+2:
+    cmpb        $$'I', sReg0            # check for int array
+    je          3f
+    movl        rGLUE, %ecx             # %ecx<- MterpGlue pointer
+    movl        offGlue_retval(%ecx), %eax # Object head
+    movl        offGlue_cardTable(%ecx), %ecx # card table base
+    shrl        $$GC_CARD_SHIFT, %eax   # convert to card num
+    movb        %cl,(%ecx, %eax)        # mark card based on object head
+3:
+    FINISH      3                       # jump to next instruction
+
+   /*
+    * Throw an exception to indicate this mode of filled-new-array
+    * has not been implemented.
+    */
+
+.L${opcode}_notimpl:
+    movl        $$.LstrInternalError, -8(%esp)
+    movl        $$.LstrFilledNewArrayNotImpl, -4(%esp)
+    lea         -8(%esp), %esp
+    call        dvmThrowException # call: (const char* exceptionDescriptor,
+                                  #        const char* msg)
+                                  # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown
+
+.if         (!$isrange)                 # define in one or the other, not both
+.LstrFilledNewArrayNotImpl:
+.asciz      "filled-new-array only implemented for 'int'"
+.LstrInternalError:
+.asciz  "Ljava/lang/InternalError;"
+.endif
diff --git a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_JUMBO.S b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S
new file mode 100644
index 0000000..fd8b0c5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FILLED_NEW_ARRAY_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILLED_NEW_ARRAY_RANGE.S
+    */
+
+%include "x86-atom/OP_FILLED_NEW_ARRAY.S" { "isrange":"1" }
diff --git a/vm/mterp/x86-atom/OP_FILL_ARRAY_DATA.S b/vm/mterp/x86-atom/OP_FILL_ARRAY_DATA.S
new file mode 100644
index 0000000..de808d9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FILL_ARRAY_DATA.S
@@ -0,0 +1,46 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FILL_ARRAY_DATA.S
+    *
+    * Code: Fills an array with given data. Uses no substitutions.
+    *
+    * For: fill-array-data
+    *
+    * Description: Fill the given array with the idicated data. The reference
+    *              must be an array of primitives, and the data table must
+    *              match it in type and size
+    *
+    * Format: AA|op BBBBlo BBBBhi (31t)
+    *
+    * Syntax: op vAA, +BBBBBBBB
+    */
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $$16, %edx              # prepare to create +BBBBBBBB
+    or          %ecx, %edx              # %edx<- +BBBBBBBB
+    lea         (rPC, %edx, 2), %edx    # %edx<- PC + +BBBBBBBB; array data location
+    EXPORT_PC
+    push        %edx
+    push        (rFP, rINST, 4)
+    call        dvmInterpHandleFillArrayData # call: (ArrayObject* arrayObject, const u2* arrayData)
+                                             # return: bool
+    FFETCH_ADV  3, %edx                 # %edx<- next instruction hi; fetch, advance
+    cmp         $$0, %eax
+    lea         8(%esp), %esp
+    je          common_exceptionThrown
+    FGETOP_JMP  3, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_FLOAT_TO_DOUBLE.S
new file mode 100644
index 0000000..91866a4
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FLOAT_TO_DOUBLE.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FLOAT_TO_DOUBLE.S
+    *
+    * Code: Converts a float to a double. Uses no substitutions.
+    *
+    * For: float-to-double
+    *
+    * Description: Convert the float in source register to a double
+    *              and store the result in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %edx              # %edx<- A
+    flds        (rFP, rINST, 4)         # load float
+    fstpl       (rFP, %edx, 4)          # store double
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_INT.S b/vm/mterp/x86-atom/OP_FLOAT_TO_INT.S
new file mode 100644
index 0000000..615f187
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FLOAT_TO_INT.S
@@ -0,0 +1,68 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FLOAT_TO_INT.S
+    *
+    * Code: Converts a float to a int. Uses no substitutions.
+    *
+    * For: float-to-int
+    *
+    * Description: Convert the float in source register to a int
+    *              and store the result in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %edx              # %edx<- A
+    flds        (rFP, rINST, 4)         # push vB to floating point stack
+    fildl       .LintMax                # push max int value
+    fildl       .LintMin                # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .L${opcode}_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .L${opcode}_nanInf      # handle posInf or NaN
+    jmp         .L${opcode}_break       # do conversion
+%break
+
+.L${opcode}_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $$0xc00, -2(%esp)       # reset control
+    fldcw       -2(%esp)                # load control word
+    xorl        $$0xc00, -2(%esp)       # reset control
+    fistpl      (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_nanInf:
+    jnp         .L${opcode}_posInf      # handle posInf
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    movl        $$0x00000000,  (rFP, %edx, 4) # vA<- NaN
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_posInf:
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    movl        $$0x7FFFFFFF,  (rFP, %edx, 4) # vA<- posInf
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_negInf:
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    fstps       (rFP, %edx, 4)          # pop floating point stack
+    movl        $$0x80000000, (rFP, %edx, 4) # vA<- negInf
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S b/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
new file mode 100644
index 0000000..9a50b78
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_FLOAT_TO_LONG.S
@@ -0,0 +1,71 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_FLOAT_TO_LONG.S
+    *
+    * Code: Converts a float to a long. Uses no substitutions.
+    *
+    * For: float-to-long
+    *
+    * Description: Convert the float in source register to a long
+    *              and store the result in the destintation register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %edx              # %edx<- A
+    flds        (rFP, rINST, 4)         # push vB to floating point stack
+    fildll      .LvaluePosInfLong       # push max int value
+    fildll      .LvalueNegInfLong       # push min int value
+    fucomip     %st(2), %st(0)          # check for negInf
+    jae         .L${opcode}_negInf      # handle negInf
+    fucomip     %st(1), %st(0)          # check for posInf or NaN
+    jc          .L${opcode}_nanInf      # handle posInf or NaN
+    jmp         .L${opcode}_break       # do conversion
+%break
+
+.L${opcode}_break:
+    fnstcw      -2(%esp)                # save control word
+    orl         $$0xc00, -2(%esp)       # update control
+    fldcw       -2(%esp)                # load control word
+    xorl        $$0xc00, -2(%esp)       # reset control
+    fistpll     (rFP, %edx, 4)          # move converted int
+    fldcw       -2(%esp)                # load saved control word
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_nanInf:
+    jnp         .L${opcode}_posInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNanLong, %xmm0   # %xmm0<- NaN
+    movq        %xmm0,  (rFP, %edx, 4)  # vA<- %xmm0; NaN
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_posInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvaluePosInfLong, %xmm0 # %xmm0<- posInf
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; posInf
+    FINISH      1                       # jump to next instruction
+
+.L${opcode}_negInf:
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        .LvalueNegInfLong, %xmm0 # %xmm0<- negInf
+    fstpl       (rFP, %edx, 4)          # move converted int
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; negInf
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_GOTO.S b/vm/mterp/x86-atom/OP_GOTO.S
new file mode 100644
index 0000000..7bd9956
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_GOTO.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_GOTO.S
+    *
+    * Code: Do an unconditional branch. Uses no substitutions.
+    *
+    * For: goto
+    *
+    * Description: Performs an unconditionally jump to the indicated instruction.
+    *              The branch uses an 8-bit offset that cannot be zero.
+    *
+    * Format: AA|op (10t)
+    *
+    * Syntax: op +AA
+    */
+
+LOP_GOTO.S:
+
+    movsbl      rINSTbl, %edx           # %edx<- +AA
+    shl         $$1, %edx               # %edx is shifted for byte offset
+    js          common_periodicChecks_backwardBranch  # do check on backwards branch
+    FINISH_RB   %edx, %ecx              # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_GOTO_16.S b/vm/mterp/x86-atom/OP_GOTO_16.S
new file mode 100644
index 0000000..931d215
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_GOTO_16.S
@@ -0,0 +1,34 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_GOTO_16.S
+    *
+    * Code: Do an unconditional branch. Uses no substitutions.
+    *
+    * For: goto/16
+    *
+    * Description: Performs an unconditionally jump to the indicated instruction.
+    *              The branch uses a 16-bit offset that cannot be zero.
+    *
+    * Format: ØØ|op AAAA (20t)
+    *
+    * Syntax: op +AAAA
+    */
+
+    FETCHs      1, %edx                 # %edx<- ssssAAAA (sign-extended)
+    shl         $$1, %edx               # %edx is doubled to get the byte offset
+    js          common_periodicChecks_backwardBranch  # do check on backwards branch
+    FINISH_RB   %edx, %ecx              # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_GOTO_32.S b/vm/mterp/x86-atom/OP_GOTO_32.S
new file mode 100644
index 0000000..d00c3a4
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_GOTO_32.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_GOTO_32.S
+    *
+    * Code: Do an unconditional branch. Uses no substitutions.
+    *
+    * For: goto/32
+    *
+    * Description:  Performs an unconditionally jump to the indicated instruction.
+    *               The branch uses a 32-bit offset that can be zero.
+    *
+    * Format: ØØ|op AAAAlo AAAAhi (30t)
+    *
+    * Syntax: op +AAAAAAAA
+    */
+
+    FETCH       1, %edx                 # %edx<- AAAAlo
+    FETCH       2, %ecx                 # %ecx<- AAAAhi
+    shl         $$16, %ecx              # prepare to create +AAAAAAAA
+    or          %ecx, %edx              # %edx<- +AAAAAAAA
+    shl         $$1, %edx               # %edx is doubled to get the byte offset
+    jle          common_periodicChecks_backwardBranch  # do check on backwards branch
+    FINISH_RB   %edx, %ecx              # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_IF_EQ.S b/vm/mterp/x86-atom/OP_IF_EQ.S
new file mode 100644
index 0000000..61781a0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_EQ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_EQ.S
+    */
+
+%include "x86-atom/bincmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/x86-atom/OP_IF_EQZ.S b/vm/mterp/x86-atom/OP_IF_EQZ.S
new file mode 100644
index 0000000..2f7c140
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_EQZ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_EQZ.S
+    */
+
+%include "x86-atom/zcmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/x86-atom/OP_IF_GE.S b/vm/mterp/x86-atom/OP_IF_GE.S
new file mode 100644
index 0000000..e90a1e5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_GE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GE.S
+    */
+
+%include "x86-atom/bincmp.S" { "revcmp":"l" }
diff --git a/vm/mterp/x86-atom/OP_IF_GEZ.S b/vm/mterp/x86-atom/OP_IF_GEZ.S
new file mode 100644
index 0000000..8ee71a8
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_GEZ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GEZ.S
+    */
+
+%include "x86-atom/zcmp.S" { "revcmp":"l" }
diff --git a/vm/mterp/x86-atom/OP_IF_GT.S b/vm/mterp/x86-atom/OP_IF_GT.S
new file mode 100644
index 0000000..7f19db9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_GT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GT.S
+    */
+
+%include "x86-atom/bincmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/x86-atom/OP_IF_GTZ.S b/vm/mterp/x86-atom/OP_IF_GTZ.S
new file mode 100644
index 0000000..3f8039f
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_GTZ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_GTZ.S
+    */
+
+%include "x86-atom/zcmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/x86-atom/OP_IF_LE.S b/vm/mterp/x86-atom/OP_IF_LE.S
new file mode 100644
index 0000000..287bd0d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_LE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LE.S
+    */
+
+%include "x86-atom/bincmp.S" { "revcmp":"g" }
diff --git a/vm/mterp/x86-atom/OP_IF_LEZ.S b/vm/mterp/x86-atom/OP_IF_LEZ.S
new file mode 100644
index 0000000..b7d31d1
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_LEZ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LEZ.S
+    */
+
+%include "x86-atom/zcmp.S" { "revcmp":"g" }
diff --git a/vm/mterp/x86-atom/OP_IF_LT.S b/vm/mterp/x86-atom/OP_IF_LT.S
new file mode 100644
index 0000000..7e58e18
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_LT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LT.S
+    */
+
+%include "x86-atom/bincmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/x86-atom/OP_IF_LTZ.S b/vm/mterp/x86-atom/OP_IF_LTZ.S
new file mode 100644
index 0000000..0a3e56b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_LTZ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_LTZ.S
+    */
+
+%include "x86-atom/zcmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/x86-atom/OP_IF_NE.S b/vm/mterp/x86-atom/OP_IF_NE.S
new file mode 100644
index 0000000..929bd05
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_NE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_NE.S
+    */
+
+%include "x86-atom/bincmp.S" { "revcmp":"e" }
diff --git a/vm/mterp/x86-atom/OP_IF_NEZ.S b/vm/mterp/x86-atom/OP_IF_NEZ.S
new file mode 100644
index 0000000..07f2c87
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IF_NEZ.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IF_NEZ.S
+    */
+
+%include "x86-atom/zcmp.S" { "revcmp":"e" }
diff --git a/vm/mterp/x86-atom/OP_IGET.S b/vm/mterp/x86-atom/OP_IGET.S
new file mode 100644
index 0000000..e3a72f7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET.S
@@ -0,0 +1,80 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET.S
+    *
+    * Code: Generic 32-bit instance field "get" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iget's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iget-boolean, iget-byte, iget-char, iget-object, iget
+    *      iget-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+%default { "mov":"l" }
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $$0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .L${opcode}_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %edx # %edx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $$0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # not resolved; handle exception
+
+    /*
+     *  %eax holds resolved field
+     */
+
+.L${opcode}_finish2:
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $$4, %ecx               # %ecx<- B
+    and         $$15, rINST             # rINST<- A
+
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $$0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    mov$mov     (%ecx, %edx), %edx      # %edx<- object field
+    SET_VREG    %edx, rINST             # vA<- %edx; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_IGET_BOOLEAN.S
new file mode 100644
index 0000000..12100f9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_BOOLEAN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_BOOLEAN.S
+    */
+
+%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_BOOLEAN_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_BOOLEAN_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_BYTE.S b/vm/mterp/x86-atom/OP_IGET_BYTE.S
new file mode 100644
index 0000000..6d6b870
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_BYTE.S
+    */
+
+%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_BYTE_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_BYTE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_CHAR.S b/vm/mterp/x86-atom/OP_IGET_CHAR.S
new file mode 100644
index 0000000..8f285d7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_CHAR.S
+    */
+
+%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_CHAR_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_CHAR_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT.S b/vm/mterp/x86-atom/OP_IGET_OBJECT.S
new file mode 100644
index 0000000..369e1b9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_OBJECT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_OBJECT.S
+    */
+
+%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_OBJECT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT_QUICK.S b/vm/mterp/x86-atom/OP_IGET_OBJECT_QUICK.S
new file mode 100644
index 0000000..36b7f0e
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_OBJECT_QUICK.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_OBJECT_QUICK.S
+    */
+
+%include "x86-atom/OP_IGET_QUICK.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_IGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..5de2fa3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_OBJECT_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_QUICK.S b/vm/mterp/x86-atom/OP_IGET_QUICK.S
new file mode 100644
index 0000000..8ec86ec
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_QUICK.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_QUICK.S
+    *
+    * Code: Optimization for iget
+    *
+    * For: iget-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $$4, %eax               # %eax<- B
+    and         $$15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $$0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %eax<- next instruction hi; fetch, advance
+    movl        (%ecx, %eax), %eax      # %eax<- object field
+    SET_VREG    %eax, rINST             # fp[A]<- %eax
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IGET_SHORT.S b/vm/mterp/x86-atom/OP_IGET_SHORT.S
new file mode 100644
index 0000000..968b815
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_SHORT.S
+    */
+
+%include "x86-atom/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_SHORT_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_SHORT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_VOLATILE.S b/vm/mterp/x86-atom/OP_IGET_VOLATILE.S
new file mode 100644
index 0000000..5de2fa3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE.S b/vm/mterp/x86-atom/OP_IGET_WIDE.S
new file mode 100644
index 0000000..370b0b0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_WIDE.S
@@ -0,0 +1,74 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_WIDE.S
+    *
+    * Code: 64 bit instance field "get" operation. Uses no substitutions.
+    *
+    * For: iget-wide
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    * Format:  B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
+    FETCH       1, %edx                 # %edx<- pDvmDex->pResFields
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved InstField ptr
+    cmp         $$0, %ecx               # check for null ptr; resolved InstField ptr
+    jne         .L${opcode}_finish
+    movl        offGlue_method(%eax), %ecx # %ecx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
+    movl        %ecx, -8(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -4(%esp)          # push parameter method->clazz
+    jmp         .L${opcode}_finish2
+%break
+
+.L${opcode}_finish2:
+    lea         -8(%esp), %esp
+    call        dvmResolveInstField     # resolve InstField ptr
+                                        # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    cmp         $$0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- %eax; %ecx expected to hold field
+    je          common_exceptionThrown
+
+   /*
+    *  %ecx holds resolved field
+    */
+
+.L${opcode}_finish:
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB
+    cmp         $$0, %edx               # check for null object
+    je          common_errNullObject
+    movl        offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (%ecx, %edx), %xmm0     # %xmm0<- object field
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- %xmm0; object field
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE_JUMBO.S b/vm/mterp/x86-atom/OP_IGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_WIDE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S b/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
new file mode 100644
index 0000000..08a57f6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IGET_WIDE_QUICK.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IGET_WIDE_QUICK.S
+    *
+    * Code: Optimization for iget
+    *
+    * For: iget/wide-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB; object to operate on
+    cmp         $$0, %edx               # check if object is null
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    je          common_errNullObject    # handle null object
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    movq        (%ecx, %edx), %xmm0     # %xmm0<- object field
+    movq        %xmm0, (rFP, rINST, 4)  # fp[A]<- %xmm0
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_INSTANCE_OF.S b/vm/mterp/x86-atom/OP_INSTANCE_OF.S
new file mode 100644
index 0000000..4dde31c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INSTANCE_OF.S
@@ -0,0 +1,121 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INSTANCE_OF.S
+    *
+    * Code: Checks if object is instance of a class. Uses no substitutions.
+    *
+    * For: instance-of
+    *
+    * Description: Store in the given destination register 1 if the indicated
+    *              reference is an instance of the given type, or 0 if not.
+    *              The type must be a reference type (not a primitive type).
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    GET_VREG    %edx                    # %edx<- vB
+    cmp         $$0, %edx               # check for null object
+    je          .L${opcode}_store       # null object
+    jmp         .L${opcode}_break
+%break
+
+.L${opcode}_break:
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- CCCC
+    movl        offDvmDex_pResClasses(%ecx), %ecx # %ecx<- pDvmDex->pResClasses
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved class
+    movl        offObject_clazz(%edx), %edx # %edx<- obj->clazz
+    cmp         $$0, %ecx               # check if already resovled
+    je          .L${opcode}_resolve     # not resolved before, so resolve now
+
+.L${opcode}_resolved:
+    cmp         %ecx, %edx              # check if same class
+    je          .L${opcode}_trivial     # yes, finish
+    jmp         .L${opcode}_fullcheck   # no, do full check
+
+   /*
+    * The trivial test failed, we need to perform a full check.
+    * %edx holds obj->clazz
+    * %ecx holds class resolved from BBBB
+    */
+
+.L${opcode}_fullcheck:
+    movl        %edx, -8(%esp)          # push parameter obj->clazz
+    movl        %ecx, -4(%esp)          # push parameter resolved class
+    lea         -8(%esp), %esp
+    call        dvmInstanceofNonTrivial # perform full check
+                                        # call: (ClassObject* instance, ClassObject* clazz)
+                                        # return: int
+    andl        $$15, rINST             # rINST<- A
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    lea         8(%esp), %esp
+    SET_VREG    %eax, rINST             # vA<- r0
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
+
+   /*
+    * %edx holds boolean result
+    */
+
+.L${opcode}_store:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    andl        $$15, rINST             # rINST<- A
+    SET_VREG    %edx, rINST             # vA<- r0
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+   /*
+    * Trivial test succeeded, save and bail.
+    */
+
+.L${opcode}_trivial:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    andl        $$15, rINST             # rINST<- A
+    SET_VREG    $$1, rINST              # vA<- r0
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+
+   /*
+    * Resolution required.  This is the least-likely path.
+    * %eax holds BBBB
+    */
+
+.L${opcode}_resolve:
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    EXPORT_PC
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
+    movl        %ecx, -12(%esp)         # push parameter glue->method->clazz
+    movl        %eax, -8(%esp)          # push parameter CCCC; type index
+    movl        $$1, -4(%esp)           # push parameter true
+    lea         -12(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer, u4 classIdx,
+                                        #        bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         12(%esp), %esp
+    cmp         $$0, %eax               # check for null
+    je          common_exceptionThrown  # handle exception
+    movl        rINST, %edx             # %edx<- BA+
+    shr         $$4, %edx               # %edx<- B
+    movl        %eax, %ecx              # need class in %ecx
+    GET_VREG    %edx                    # %edx<- vB
+    movl        offObject_clazz(%edx), %edx # %edx<- obj->clazz
+    jmp         .L${opcode}_resolved    # clazz resolved, continue
diff --git a/vm/mterp/x86-atom/OP_INSTANCE_OF_JUMBO.S b/vm/mterp/x86-atom/OP_INSTANCE_OF_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INSTANCE_OF_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_INT_TO_BYTE.S b/vm/mterp/x86-atom/OP_INT_TO_BYTE.S
new file mode 100644
index 0000000..27cafe9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INT_TO_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_BYTE.S
+    */
+
+%include "x86-atom/unop.S" { "preinstr":"sal $24, %ecx", "instr":"sar $24, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_INT_TO_CHAR.S b/vm/mterp/x86-atom/OP_INT_TO_CHAR.S
new file mode 100644
index 0000000..a28602d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INT_TO_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_CHAR.S
+    */
+
+%include "x86-atom/unop.S" {"preinstr":"sal $16, %ecx", "instr":"shr $16, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_INT_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_INT_TO_DOUBLE.S
new file mode 100644
index 0000000..cd16eea
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INT_TO_DOUBLE.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_DOUBLE.S
+    *
+    * Code: Convert an int to a double. Uses no substitutions.
+    *
+    * For: int-to-double
+    *
+    * Description: Converts an int in the source register, to a double, and
+    *              stores the result in the destination register. vA<- (double) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA+
+    shr         $$4, %eax               # %eax<- B
+    andl        $$15, rINST             # rINST<- A
+    cvtsi2sd    (rFP, %eax, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- %xmm0; (double) vB
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S b/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
new file mode 100644
index 0000000..52ce729
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INT_TO_FLOAT.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_FLOAT.S
+    *
+    * Code: Convert an int to a float. Uses no substitutions.
+    *
+    * For: int-to-float
+    *
+    * Description: Convert an int in the source register, to a float, and
+    *              stores the result in the destintation register. vA<- (float) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA+
+    shr         $$4, %eax               # %eax<- B
+    andl        $$15,  rINST            # rINST<- A
+    cvtsi2ss    (rFP,%eax,4), %xmm0     # %xmm0<- vB
+    movss       %xmm0, (rFP, rINST, 4)  # vA<- %xmm0
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_INT_TO_LONG.S b/vm/mterp/x86-atom/OP_INT_TO_LONG.S
new file mode 100644
index 0000000..1bc125b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INT_TO_LONG.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_LONG.S
+    *
+    * Code:  Convert an int to a long. Uses no substitutions.
+    *
+    * For:
+    *
+    * Description: Convert an int in the source register, to a long, and
+    *              stores the result in the destintation register. vA<- (long) vB
+    *
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %eax             # %eax<- BA+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, %eax               # %eax<- B
+    andl        $$15, %ecx              # %ecx<- A
+    GET_VREG    %eax                    # %eax<- vB
+    cdq                                 # %edx:%eax<- sign-extend of %eax
+    movl        %eax, (rFP, %ecx, 4)    # vA<- lo part
+    movl        %edx, 4(rFP, %ecx, 4)   # vA+1<- hi part
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_INT_TO_SHORT.S b/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
new file mode 100644
index 0000000..f2b0b87
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INT_TO_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INT_TO_SHORT.S
+    */
+
+%include "x86-atom/unop.S" { "preinstr":"sal $16, %ecx", "instr":"sar $16, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_DIRECT.S b/vm/mterp/x86-atom/OP_INVOKE_DIRECT.S
new file mode 100644
index 0000000..78b6c06
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_DIRECT.S
@@ -0,0 +1,92 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_DIRECT.S
+    *
+    * Code: Call a non-static direct method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_direct that allows up to 255 arguments.
+    *
+    * For: invoke-direct, invoke-direct/range
+    *
+    * Description: invoke-direct is used to invoke a non-static direct method;
+    *              an instance method that is non-overridable, for example,
+    *              either a private instance method or a constructor.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+%default { "isrange":"0", "routine":"NoRange" }
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved method to call
+    .if         (!$isrange)
+    andl        $$15, %edx              # %edx<- D if not range
+    .endif
+    EXPORT_PC                           # must export for invoke
+    movl        %edx, -4(%esp)          # save "this" pointer register
+    cmp         $$0, %ecx               # check if already resolved
+    GET_VREG    %edx                    # %edx<- "this" pointer
+    je          .L${opcode}_resolve     # handle resolve
+
+.L${opcode}_finish:
+    cmp         $$0, %edx               # check for null "this"
+    jne         common_invokeMethod${routine} # invoke method common code
+    jmp         common_errNullObject
+%break
+
+   /*
+    * %eax = reference (BBBB or CCCC)
+    * -4(%esp) = "this" register
+    */
+
+.L${opcode}_resolve:
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        $$METHOD_DIRECT, -8(%esp) # push parameter method type
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        %eax, -12(%esp)         # push parameter reference
+    lea         -16(%esp), %esp
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, (%esp)            # push parameter clazz
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         16(%esp), %esp
+    cmp         $$0, %eax               # check for null method return
+    movl        -4(%esp), %edx          # get "this" pointer register
+    GET_VREG    %edx                    # get "this" pointer
+    je          common_exceptionThrown  # null pointer; handle exception
+    cmp         $$0, %edx               # check for null "this"
+    movl        %eax, %ecx              # %ecx<- method
+    jne         common_invokeMethod${routine} # invoke method common code
+    jmp         common_errNullObject    # handle null object
diff --git a/vm/mterp/x86-atom/OP_INVOKE_DIRECT_JUMBO.S b/vm/mterp/x86-atom/OP_INVOKE_DIRECT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_DIRECT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_INVOKE_DIRECT_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_DIRECT_RANGE.S
new file mode 100644
index 0000000..3ad26e1
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_DIRECT_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_DIRECT_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_DIRECT.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE.S b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE.S
new file mode 100644
index 0000000..cbd7b31
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE.S
@@ -0,0 +1,76 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_INTERFACE.S
+    *
+    * Code: Call at method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_interface that allows up to 255 arguments.
+    *
+    * For: invoke-interface, invoke-interface-range
+    *
+    * Description: invoke-interface is used to invoke an interface method; on an
+    *              object whose concrete class isn't known, using a method_id that
+    *              refers to an interface.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+%default { "isrange":"0", "routine":"NoRange" }
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        %ecx, -12(%esp)         # push argument method index
+    .if         (!$isrange)
+    and         $$15, %edx              # %edx<- D if not range
+    .endif
+    EXPORT_PC                           # must export for invoke
+    GET_VREG    %edx                    # %edx<- first arg "this pointer"
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
+    movl        %eax, -4(%esp)          # push parameter class
+    cmp         $$0, %edx               # check for null object
+    je          common_errNullObject    # handle null object
+    jmp         .L${opcode}_break
+%break
+.L${opcode}_break:
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        %ecx, -8(%esp)          # push parameter method
+    movl        offObject_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -16(%esp)         # push parameter
+    lea         -16(%esp), %esp
+    call        dvmFindInterfaceMethodInCache # call: (ClassObject* thisClass, u4 methodIdx,
+                                              #       const Method* method, DvmDex* methodClassDex)
+                                              # return: Method*
+    lea         16(%esp), %esp
+    cmp         $$0, %eax               # check if find failed
+    je          common_exceptionThrown  # handle exception
+    movl        %eax, %ecx              # %ecx<- method
+    jmp         common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_JUMBO.S b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_RANGE.S
new file mode 100644
index 0000000..b323ba0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_INTERFACE_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_INTERFACE_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_INTERFACE.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S
new file mode 100644
index 0000000..2459a3c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S
@@ -0,0 +1,29 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_OBJECT_INIT.S
+    *
+    * Code: TODO
+    *
+    * For: invoke-object-init
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    */
+
+<<<<<<< HEAD:vm/mterp/x86-atom/OP_INVOKE_OBJECT_INIT_RANGE.S
+=======
+    FINISH 3
+>>>>>>> 10185db0:vm/mterp/x86-atom/OP_INVOKE_DIRECT_EMPTY.S
diff --git a/vm/mterp/x86-atom/OP_INVOKE_STATIC.S b/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
new file mode 100644
index 0000000..30b6d8c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_STATIC.S
@@ -0,0 +1,70 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_STATIC.S
+    *
+    * Code: Call static direct method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_static that allows up to 255 arguments.
+    *
+    * For: invoke-static, invoke-static/range
+    *
+    * Description: invoke-static is used to invoke static direct method.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+%default { "routine":"NoRange" }
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %edx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %edx<- pDvmDex->pResMethods
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved method to call
+    cmp         $$0, %ecx               # check if already resolved
+    EXPORT_PC                           # must export for invoke
+    jne         common_invokeMethod${routine} # invoke method common code
+    jmp         .L${opcode}_break
+%break
+
+.L${opcode}_break:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    movl        $$METHOD_STATIC, -4(%esp) # resolver method type
+    movl        %eax, -8(%esp)          # push parameter method index
+    movl        offMethod_clazz(%edx), %edx # %edx<- glue->method->clazz
+    movl        %edx, -12(%esp)         # push parameter method
+    lea         -12(%esp), %esp
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         12(%esp), %esp
+    cmp         $$0, %eax               # check for null method
+    je          common_exceptionThrown
+    movl        %eax, %ecx              # %ecx<- method
+    jmp         common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_STATIC_JUMBO.S b/vm/mterp/x86-atom/OP_INVOKE_STATIC_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_STATIC_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_INVOKE_STATIC_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_STATIC_RANGE.S
new file mode 100644
index 0000000..ce39e13
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_STATIC_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_STATIC_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_STATIC.S" { "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
new file mode 100644
index 0000000..539bea1
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER.S
@@ -0,0 +1,105 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER.S
+    *
+    * Code: Call super method.
+    *
+    * For: invoke-super, invoke-super/range
+    *
+    * Description: invoke-super is used to invoke the closest superclass's virtual
+    *              method (as opposed to the one with the same method_id in the
+    *              calling class).
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+%default { "isrange":"0", "routine":"NoRange" }
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    FETCH       2, %eax                 # %eax<- GFED or CCCC
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
+    .if         (!$isrange)
+    and         $$15, %eax              # %eax<- D if not range
+    .endif
+    FETCH       1, %edx                 # %edx<- method index
+    movl        offDvmDex_pResMethods(%ecx), %ecx # %ecx<- pDvmDex->pResMethods
+    cmp         $$0, (rFP, %eax, 4)     # check for null object
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved base method
+    je          common_errNullObject    # handle null object
+    jmp         .L${opcode}_continue2
+%break
+
+.L${opcode}_continue2:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    EXPORT_PC                           # must export for invoke
+    cmp         $$0, %ecx               # check if already resolved
+    jne         .L${opcode}_continue
+    jmp         .L${opcode}_resolve     # handle resolve
+
+   /*
+    *  %ecx = resolved base method
+    *  %eax = method->clazz
+    */
+
+.L${opcode}_continue:
+    movl        offClassObject_super(%eax), %edx # %edx<- glue->method->clazz->super
+    movzwl      offMethod_methodIndex(%ecx), %ecx # %ecx<-  baseMethod->methodIndex
+    cmp          offClassObject_vtableCount(%edx), %ecx # compare vtableCount with methodIndex
+    EXPORT_PC                           # must export for invoke
+    jnc         .L${opcode}_nsm         # handle method not present
+    movl        offClassObject_vtable(%edx), %edx # %edx<- glue->method->clazz->super->vtable
+    movl        (%edx, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethod${routine} # invoke method common code
+
+.L${opcode}_resolve:
+    movl        %eax, -12(%esp)         # push parameter clazz
+    movl        %edx, -8(%esp)          # push parameter method index
+    movl        $$METHOD_VIRTUAL, -4(%esp) # push parameter method type
+    lea         -12(%esp), %esp
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         12(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- method
+    cmp         $$0, %ecx               # check for null method return
+    movl        -12(%esp), %eax         # %eax<- glue->method->clazz
+    jne         .L${opcode}_continue
+    jmp         common_exceptionThrown  # null pointer; handle exception
+
+   /*
+    * Throw a NoSuchMethodError with the method name as the message.
+    * %ecx = resolved base method
+    */
+
+.L${opcode}_nsm:
+    movl        offMethod_name(%ecx), %edx # %edx<- method name
+    jmp         common_errNoSuchMethod
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_JUMBO.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
new file mode 100644
index 0000000..55c7e94
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_QUICK.S
+    *
+    * Code: Optimization for invoke-super and invoke-super/range
+    *
+    * For: invoke-super/quick, invoke-super/quick-range
+    */
+
+%default { "isrange":"0", "routine":"NoRange" }
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_method(%ecx), %eax # %eax<- glue->method
+    .if         (!$isrange)
+    and         $$15, %edx              #  %edx<- D if not range
+    .endif
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        offClassObject_super(%eax), %eax # %eax<- glue->method->clazz->super
+    EXPORT_PC                           # must export for invoke
+    movl        offClassObject_vtable(%eax), %eax # %edx<- glue->method->clazz->super->vtable
+    cmp         $$0, (rFP, %edx, 4)     # check for null object
+    movl        (%eax, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    je          common_errNullObject    # handle null object
+    jmp         common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S
new file mode 100644
index 0000000..9e9f311
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER_QUICK_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_QUICK_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_SUPER_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_SUPER_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_SUPER_RANGE.S
new file mode 100644
index 0000000..6e77c02
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_SUPER_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_SUPER_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_SUPER.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.S
new file mode 100644
index 0000000..46c9265
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL.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.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL.S
+    *
+    * Code: Call a virtual method. Provides an "isrange" variable and
+    *       a "routine" variable to specify this is the "range" version of
+    *       invoke_direct that allows up to 255 arguments.
+    *
+    * For: invoke-virtual, invoke-virtual/range
+    *
+    * Description: invoke-virtual is used to invoke a normal virtual method;
+    *              a method that is not static or final, and is not a constructor.
+    *
+    * Format: B|A|op CCCC G|F|E|D (35c)
+    *         AA|op BBBB CCCC (3rc)
+    *
+    * Syntax: [B=5] op {vD, vE, vF, vG, vA}, meth@CCCC (35c)
+    *         [B=5] op {vD, vE, vF, vG, vA}, type@CCCC (35c)
+    *         [B=4] op {vD, vE, vF, vG}, kind@CCCC (35c)
+    *         [B=3] op {vD, vE, vF}, kind@CCCC (35c)
+    *         [B=2] op {vD, vE}, kind@CCCC (35c)
+    *         [B=1] op {vD}, kind@CCCC (35c)
+    *         [B=0] op {}, kind@CCCC (35c)
+    *
+    *         op {vCCCC .. vNNNN}, meth@BBBB (3rc) (where NNNN = CCCC+AA-1, that
+    *         op {vCCCC .. vNNNN}, type@BBBB (3rc) is A determines the count 0..255,
+    *                                              and C determines the first register)
+    */
+
+%default { "isrange":"0", "routine":"NoRange" }
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # must export pc for invoke
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- method index
+    movl        offDvmDex_pResMethods(%eax), %eax # %eax<- pDvmDex->pResMethods
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    .if         (!$isrange)
+    and         $$15, %edx              # %edx<- D if not range
+    .endif
+    cmp         $$0, (%eax, %ecx, 4)    # check if already resolved
+    je          .L${opcode}_break
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved base method
+    jmp         .L${opcode}_continue
+%break
+
+.L${opcode}_break:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %edx, -4(%esp)          # save "this" pointer register
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        $$METHOD_VIRTUAL, -8(%esp) # push parameter method type
+    movl        %ecx, -12(%esp)         # push paramter method index
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    lea         -16(%esp), %esp
+    movl        %eax, (%esp)            # push parameter clazz
+    call        dvmResolveMethod        # call: (const ClassObject* referrer,
+                                        #       u4 methodIdx, MethodType methodType)
+                                        # return: Method*
+    lea         16(%esp), %esp
+    cmp         $$0, %eax               # check for null method return
+    movl        -4(%esp), %edx          # get "this" pointer register
+    jne         .L${opcode}_continue
+    jmp         common_exceptionThrown  # null pointer; handle exception
+
+   /*
+    * At this point:
+    *  %eax = resolved base method
+    *  %edx = D or CCCC (index of first arg, which is the "this" ptr)
+    */
+
+.L${opcode}_continue:
+    GET_VREG    %edx                    # %edx<- "this" ptr
+    movzwl      offMethod_methodIndex(%eax), %eax # %eax<- baseMethod->methodIndex
+    cmp         $$0, %edx               # %edx<- check for null "this"
+    je          common_errNullObject    # handle null object
+    movl        offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
+    movl        offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
+    movl        (%edx, %eax, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_JUMBO.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
new file mode 100644
index 0000000..16a4e40
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_QUICK.S
+    *
+    * Code: Optimization for invoke-virtual and invoke-virtual/range
+    *
+    * For: invoke-virtual/quick, invoke-virtual/quick-range
+    */
+
+%default { "isrange":"0", "routine":"NoRange" }
+
+    FETCH       2, %edx                 # %edx<- GFED or CCCC
+    .if (!$isrange)
+    and         $$15, %edx              # %edx<- D if not range
+    .endif
+    FETCH       1, %ecx                 # %ecx<- method index
+    GET_VREG    %edx                    # %edx<- "this" ptr
+    cmp         $$0, %edx               # %edx<- check for null "this"
+    EXPORT_PC                           # must export pc for invoke
+    je          common_errNullObject
+    movl        offObject_clazz(%edx), %edx # %edx<- thisPtr->clazz
+    movl        offClassObject_vtable(%edx), %edx # %edx<- thisPtr->clazz->vtable
+    movl        (%edx, %ecx, 4), %ecx   # %ecx<- vtable[methodIndex]
+    jmp         common_invokeMethod${routine} # invoke method common code
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
new file mode 100644
index 0000000..888bcc0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_QUICK_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_VIRTUAL_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_RANGE.S b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_RANGE.S
new file mode 100644
index 0000000..d548a22
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_INVOKE_VIRTUAL_RANGE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_INVOKE_VIRTUAL_RANGE.S
+    */
+
+%include "x86-atom/OP_INVOKE_VIRTUAL.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86-atom/OP_IPUT.S b/vm/mterp/x86-atom/OP_IPUT.S
new file mode 100644
index 0000000..4c029be
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT.S
@@ -0,0 +1,76 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+%default { "mov":"l" }
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $$0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .L${opcode}_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $$0, %eax               # check if resolved
+    jne         .L${opcode}_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.L${opcode}_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, %ecx               # %ecx<- B
+    and         $$15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $$0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    mov$mov     rINST, (%edx, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_BOOLEAN.S b/vm/mterp/x86-atom/OP_IPUT_BOOLEAN.S
new file mode 100644
index 0000000..46c2932
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_BOOLEAN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_BOOLEAN.S
+    */
+
+%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_BOOLEAN_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_BYTE.S b/vm/mterp/x86-atom/OP_IPUT_BYTE.S
new file mode 100644
index 0000000..d23f492
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_BYTE.S
+    */
+
+%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_BYTE_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_BYTE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_CHAR.S b/vm/mterp/x86-atom/OP_IPUT_CHAR.S
new file mode 100644
index 0000000..d645fae
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_CHAR.S
+    */
+
+%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_CHAR_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_CHAR_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
new file mode 100644
index 0000000..302cf44
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_OBJECT.S
@@ -0,0 +1,81 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+    /*
+    * File: OP_IPUT.S
+    *
+    * Code: Generic 32-bit instance field "put" operation. Provides a
+    *       "mov" variable which determines the type of mov performed.
+    *       Currently, none of the iput's use this variable - may want
+    *       to change this, but seems ok for now.
+    *
+    * For: iput-boolean, iput-byte, iput-char, iput-object, iput
+    *      iput-short
+    *
+    * Description: Perform the object instance field "get" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %edx # %edx<- pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    movl        offDvmDex_pResFields(%edx), %edx # %edx<- pDvmDex->pResFields
+    cmp         $$0, (%edx, %ecx, 4)    # check for null ptr; resolved InstField ptr
+    movl        (%edx, %ecx, 4), %eax   # %eax<- resolved InstField ptr
+    jne         .L${opcode}_finish2
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+    movl        offGlue_method(%edx), %edx # %edx<- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %ecx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    lea         -8(%esp), %esp
+    movl        %edx, (%esp)            # push parameter method->clazz
+    call        dvmResolveInstField     # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: InstField*
+    lea         8(%esp), %esp
+    cmp         $$0, %eax               # check if resolved
+    jne         .L${opcode}_finish2
+    jmp         common_exceptionThrown  # not resolved; handle exception
+
+.L${opcode}_finish2:
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, %ecx               # %ecx<- B
+    and         $$15, rINST             # rINST<- A
+    GET_VREG    %ecx                    # %ecx<- vB
+    cmp         $$0, %ecx               # check for null object
+    je          common_errNullObject    # handle null object
+    movl        offInstField_byteOffset(%eax), %edx # %edx<- field offset
+    GET_VREG    rINST                   # rINST<- vA
+    movl        rINST, (%edx, %ecx)     # object field<- vA
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl     rGLUE, %eax             # get glue
+    movl        offGlue_cardTable(%eax), %eax # get card table base
+    testl       rINST, rINST            # test if we stored a null value
+    je          1f                     # skip card mark if null stored
+    shrl        $$GC_CARD_SHIFT, %ecx   # set obeject head to card number
+    movb        %al, (%eax, %ecx)
+1:
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_OBJECT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT_QUICK.S
new file mode 100644
index 0000000..eee88e9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_OBJECT_QUICK.S
@@ -0,0 +1,44 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_QUICK.S
+    * Code: Optimization for iput
+    *
+    * For: iput-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $$4, %eax               # %eax<- B
+    and         $$15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $$0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl        rINST, (%eax, %ecx)     # object field<- vA
+    testl       rINST, rINST            # did we write a null object
+    je          1f
+    movl        rGLUE, %ecx             # get glue
+    movl        offGlue_cardTable(%ecx), %ecx # get card table base
+    shrl        $$GC_CARD_SHIFT, %eax   # get gc card index
+    movb        %cl, (%eax, %ecx)       # mark gc card in table
+1:
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_IPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..4b024d0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_OBJECT_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_IPUT_OBJECT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_QUICK.S
new file mode 100644
index 0000000..572291e
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_QUICK.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_QUICK.S
+    * Code: Optimization for iput
+    *
+    * For: iput-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $$4, %eax               # %eax<- B
+    and         $$15, rINST             # rINST<- A
+    GET_VREG    %eax                    # %eax<- vB; object to operate on
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    cmp         $$0, %eax               # check if object is null
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vA
+    movl        rINST, (%eax, %ecx)     # object field<- vA
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_SHORT.S b/vm/mterp/x86-atom/OP_IPUT_SHORT.S
new file mode 100644
index 0000000..9836283
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_SHORT.S
+    */
+
+%include "x86-atom/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_SHORT_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_SHORT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_VOLATILE.S b/vm/mterp/x86-atom/OP_IPUT_VOLATILE.S
new file mode 100644
index 0000000..475a0c5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_IPUT.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE.S b/vm/mterp/x86-atom/OP_IPUT_WIDE.S
new file mode 100644
index 0000000..1686219
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_WIDE.S
@@ -0,0 +1,74 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_WIDE.S
+    *
+    * Code: 64 bit instance field "put" operation. Uses no substitutions.
+    *
+    * For: iget-wide
+    *
+    * Description: Perform the object instance field "put" operation
+    *              with the identified field; load the instance value into
+    *              the value register.
+    *
+    * Format:  B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %eax             # %eax<- MterpGlue pointer
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- pDvmDex
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- CCCC
+    FETCH       1, %edx                 # %edx<- pDvmDex->pResFields
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved InstField ptr
+    cmp         $$0, %ecx               # check for null ptr; resolved InstField ptr
+    jne         .L${opcode}_finish
+    movl        offGlue_method(%eax), %ecx # %ecx <- current method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- method->clazz
+    movl        %ecx, -8(%esp)          # push parameter CCCC; field ref
+    movl        %edx, -4(%esp)          # push parameter method->clazz
+    jmp         .L${opcode}_finish2
+%break
+
+.L${opcode}_finish2:
+    lea         -8(%esp), %esp
+    call        dvmResolveInstField     # resolve InstField ptr
+    cmp         $$0, %eax               # check if resolved
+    lea         8(%esp), %esp
+    movl        %eax, %ecx              # %ecx<- %eax; %ecx expected to hold field
+    jne         .L${opcode}_finish
+    jmp         common_exceptionThrown
+
+   /*
+    * Currently:
+    *  %ecx holds resolved field
+    *  %edx does not hold object yet
+    */
+
+.L${opcode}_finish:
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB
+    cmp         $$0, %edx               # check for null object
+    je          common_errNullObject
+    movl        offInstField_byteOffset(%ecx), %ecx # %ecx<- field offset
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vA
+    movq        %xmm0, (%ecx, %edx)     # object field<- %xmm0; vA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE_JUMBO.S b/vm/mterp/x86-atom/OP_IPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_WIDE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S b/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
new file mode 100644
index 0000000..5880231
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_IPUT_WIDE_QUICK.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_IPUT_WIDE_QUICK.S
+    *
+    * Code: Optimization for iput
+    *
+    * For: iput/wide-quick
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, offset@CCCC
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB; object to operate on
+    cmp         $$0, %edx               # check if object is null
+    FETCH       1, %ecx                 # %ecx<- CCCC; field byte offset
+    je          common_errNullObject    # handle null object
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- fp[A]
+    movq        %xmm0, (%edx, %ecx)     # object field<- %xmm0; fp[A]
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S b/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
new file mode 100644
index 0000000..5705e25
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_LONG_TO_DOUBLE.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_LONG_TO_DOUBLE.S
+    *
+    * Code: Convert a long to a dobule. Uses no substitutions.
+    *
+    * For: long-to-double
+    *
+    * Description: Converts a long in the source register to a double, and
+    *              stores the result in the destination register. vA<- (double) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    fildll      (rFP, rINST, 4)         # FPU<- vB
+    fstpl       (rFP, %ecx, 4)          # vA<- FPU; (double) vB
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_FLOAT.S b/vm/mterp/x86-atom/OP_LONG_TO_FLOAT.S
new file mode 100644
index 0000000..1bb8779
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_LONG_TO_FLOAT.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_LONG_TO_FLOAT.S
+    *
+    * Code: Convert a long to a float. Uses no substitutions.
+    *
+    * For: int-to-float
+    *
+    * Description: Converts a float in the source register, to a float, and
+    *              stores the result in the destination register. vA<- (double) vB
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    fildll      (rFP, rINST, 4)         # FPU<- vB
+    fstps       (rFP, %ecx, 4)          # vA<- FPU; (float) vB
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_LONG_TO_INT.S b/vm/mterp/x86-atom/OP_LONG_TO_INT.S
new file mode 100644
index 0000000..0984bc0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_LONG_TO_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_LONG_TO_INT.S
+    */
+
+%include "x86-atom/OP_MOVE.S"
diff --git a/vm/mterp/x86-atom/OP_MONITOR_ENTER.S b/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
new file mode 100644
index 0000000..39d0e7b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MONITOR_ENTER.S
@@ -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.
+    */
+
+   /*
+    * File: OP_MONITOR_ENTER.S
+    *
+    * Code: Aquire a monitor
+    *
+    * For: monitor-enter
+    *
+    * Description: Aquire a monitor for the indicated object.
+    *
+    *
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    GET_VREG    rINST                   # rINST<- vAA
+    cmp         $$0, rINST              # check for null object
+    movl        offGlue_self(%eax), %eax # %eax<- glue->self
+    EXPORT_PC   # need for precise GC
+    je          common_errNullObject    # handle null object
+#    jmp         .L${opcode}_finish
+#%break
+#.L${opcode}_finish:
+    movl        rINST, -4(%esp)         # push parameter reference
+    movl        %eax, -8(%esp)          # push parameter
+    lea         -8(%esp), %esp
+    call        dvmLockObject           # call: (struct Thread* self,
+                                        #       struct Object* obj)
+                                        # return: void
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    lea         8(%esp), %esp
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MONITOR_EXIT.S b/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
new file mode 100644
index 0000000..37738d5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MONITOR_EXIT.S
@@ -0,0 +1,46 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MONITOR_EXIT.S
+    *
+    * Code: Release a monitor
+    *
+    * For: monitor-exit
+    *
+    * Description: Release a monitor for the indicated object. If this instruction needs
+    *              to throw an execption, it must do so as if the pc has already
+    *              advanced pased the instruction.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # export the pc
+    GET_VREG    rINST                   # rINST<- vAA
+    cmp         $$0, rINST              # rINST<- check for null object
+    je          common_errNullObject    # handle null object
+    push        rINST                   # push parameter object
+    push        offGlue_self(%eax)      # push parameter self
+    call        dvmUnlockObject         # call: (struct Thread* self,
+                                        #       struct Object* obj)
+                                        # return: bool
+    FINISH_FETCH_ADVANCE 1, %edx        # advance pc before exception
+    cmp         $$0, %eax               # check for success
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    FINISH_JMP  %edx                    # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_MOVE.S b/vm/mterp/x86-atom/OP_MOVE.S
new file mode 100644
index 0000000..9982ced
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move, move-object, long-to-int
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vB
+    SET_VREG    rINST, %ecx             # vA<- vB; %edx
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_16.S b/vm/mterp/x86-atom/OP_MOVE_16.S
new file mode 100644
index 0000000..013a11b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_16.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move/16, move-object/16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              fp[A]<- fp[B]
+    *
+    * Format: ØØ|op AAAA BBBB (32x)
+    *
+    * Syntax: op vAAAA, vBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBB
+    FETCH       1, %ecx                 # %ecx<- AAAA
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    SET_VREG    %edx, %ecx              # vA<- vB; %edx
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S b/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
new file mode 100644
index 0000000..76e700d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_EXCEPTION.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_EXCEPTION.S
+    *
+    * Code: Moves an exception to a register
+    *
+    * For: move-exception
+    *
+    * Description: Save a just-caught exception into the given register. This
+    *              instruction is only valid as the first instruction of an
+    *              exception handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movl        offThread_exception(%ecx), %edx # %edx<- glue->self->exception
+    movl        $$0, offThread_exception(%ecx) # clear exception
+    SET_VREG    %edx, rINST             # vAA<- glue->self->exception
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_FROM16.S
new file mode 100644
index 0000000..55a6e96
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_FROM16.S
@@ -0,0 +1,35 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_FROM16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move/from16, move-object/from16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *              vA<- vB; fp[A]<- fp[B]
+    *
+    * Format: AA|op BBBB (22x)
+    *
+    * Syntax: op vAA, vBBBB
+    */
+
+    FETCH       1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    SET_VREG    %edx, rINST             # vA<- vB; %edx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_OBJECT.S b/vm/mterp/x86-atom/OP_MOVE_OBJECT.S
new file mode 100644
index 0000000..1cd22cb
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_OBJECT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_OBJECT.S
+    */
+
+%include "x86-atom/OP_MOVE.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_OBJECT_16.S b/vm/mterp/x86-atom/OP_MOVE_OBJECT_16.S
new file mode 100644
index 0000000..a61162c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_OBJECT_16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_OBJECT_16.S
+    */
+
+%include "x86-atom/OP_MOVE_16.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_OBJECT_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_OBJECT_FROM16.S
new file mode 100644
index 0000000..bfca7da
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_OBJECT_FROM16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_OBJECT_FROM16.S
+    */
+
+%include "x86-atom/OP_MOVE_FROM16.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_RESULT.S b/vm/mterp/x86-atom/OP_MOVE_RESULT.S
new file mode 100644
index 0000000..1d13bf5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_RESULT.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT.S
+    *
+    * Code: Copies a return value to a register
+    *
+    * For: move-result, move-result-object
+    *
+    * Description: Move the single-word non-object result of the most
+    *              recent method invocation into the indicated register. This
+    *              must be done as the instruction immediately after a
+    *              method invocation whose (single-word, non-object) result
+    *              is not to be ignored; anywhere else is invalid.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    FFETCH_ADV  1, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    movl        offGlue_retval(%eax), %edx # %edx<- glue->retval
+    SET_VREG    %edx, rINST             # vA<- glue->retval
+    FGETOP_JMP  1, %ecx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_RESULT_OBJECT.S b/vm/mterp/x86-atom/OP_MOVE_RESULT_OBJECT.S
new file mode 100644
index 0000000..6d1fa75
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_RESULT_OBJECT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT_OBJECT.S
+    */
+
+%include "x86-atom/OP_MOVE_RESULT.S"
diff --git a/vm/mterp/x86-atom/OP_MOVE_RESULT_WIDE.S b/vm/mterp/x86-atom/OP_MOVE_RESULT_WIDE.S
new file mode 100644
index 0000000..8f15264
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_RESULT_WIDE.S
@@ -0,0 +1,38 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_RESULT_WIDE.S
+    *
+    * Code: Copies a return value to a register
+    *
+    * For: move-result-wide
+    *
+    * Description: Move the double-word non-object result of the most
+    *              recent method invocation into the indicated register. This
+    *              must be done as the instruction immediately after a
+    *              method invocation whose (single-word, non-object) result
+    *              is not to be ignored; anywhere else is invalid.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movq        offGlue_retval(%eax), %xmm0 # %xmm0<- glue->retval
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- glue->retval
+    FFETCH_ADV  1, %edx                 # %edx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE.S b/vm/mterp/x86-atom/OP_MOVE_WIDE.S
new file mode 100644
index 0000000..909243b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_WIDE.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_WIDE.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move-wide
+    *
+    * Description: Copies contents from one non-object register to another.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA+
+    shr         $$4, %edx               # %edx<- B
+    and         $$15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- vB
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE_16.S b/vm/mterp/x86-atom/OP_MOVE_WIDE_16.S
new file mode 100644
index 0000000..af266fe
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_WIDE_16.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_WIDE_16.S
+    *
+    * Code: Copies contents from one register to another. Uses no
+    *       substitutions.
+    *
+    * For: move-wide/16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *
+    * Format: ØØ|op AAAA BBBB (32x)
+    *
+    * Syntax: op vAAAA, vBBBB
+    */
+
+    FETCH       2, %edx                 # %edx<- BBBB
+    FETCH       1, %ecx                 # %ecx<- AAAA
+    FFETCH_ADV  3, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, %ecx, 4)   # vA<- vB; %xmm0
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S b/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
new file mode 100644
index 0000000..4056b34
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MOVE_WIDE_FROM16.S
@@ -0,0 +1,34 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MOVE_WIDE_FROM16.S
+    *
+    * Code: Copies contents from one register to another
+    *
+    * For: move-wide/from16
+    *
+    * Description: Copies contents from one non-object register to another.
+    *
+    * Format: AA|op BBBB (22x)
+    *
+    * Syntax: op vAA, vBBBB
+    */
+
+    FETCH       1, %edx                 # %edx<- BBBB
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vB
+    movq        %xmm0, (rFP, rINST, 4)  # vA<- vB
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_MUL_DOUBLE.S b/vm/mterp/x86-atom/OP_MUL_DOUBLE.S
new file mode 100644
index 0000000..cecbf05
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_DOUBLE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_DOUBLE.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"mulsd   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..adc61d6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_DOUBLE_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_DOUBLE_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"mulsd   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_FLOAT.S b/vm/mterp/x86-atom/OP_MUL_FLOAT.S
new file mode 100644
index 0000000..34eba58
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_FLOAT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_FLOAT.S
+    */
+
+%include "x86-atom/binopF.S" {"instr":"mulss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_FLOAT_2ADDR.S
new file mode 100644
index 0000000..dbd615d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_FLOAT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_FLOAT_2ADDR.S
+    */
+
+%include "x86-atom/binopF2addr.S" {"instr":"mulss %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT.S b/vm/mterp/x86-atom/OP_MUL_INT.S
new file mode 100644
index 0000000..8f5dac5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT.S
+    */
+
+%include "x86-atom/binop.S" {"instr":"imul     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_INT_2ADDR.S
new file mode 100644
index 0000000..b544df7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT_2ADDR.S
+    */
+
+%include "x86-atom/binop2addr.S" {"instr":"imul     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT_LIT16.S b/vm/mterp/x86-atom/OP_MUL_INT_LIT16.S
new file mode 100644
index 0000000..241531f
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT_LIT16.S
+    */
+
+%include "x86-atom/binopLit16.S" {"instr":"imul     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_INT_LIT8.S b/vm/mterp/x86-atom/OP_MUL_INT_LIT8.S
new file mode 100644
index 0000000..efcffe1
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8.S" {"instr":"imul     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_MUL_LONG.S b/vm/mterp/x86-atom/OP_MUL_LONG.S
new file mode 100644
index 0000000..85cccf2
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_LONG.S
@@ -0,0 +1,71 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_LONG.S
+    *
+    * Code: 64-bit integer multiply
+    *
+    * For: mul-long
+    *
+    * Description: Multiply two source registers and store the
+    *              result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+   /*
+    * 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.
+    */
+
+    movl        rINST, -4(%esp)         # -4(%esp)<- AA+
+    FETCH_BB    1, rINST                # rINST<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    jmp         .L${opcode}_finish
+%break
+
+   /*
+    * X = (rFP, rINST, 4)
+    * W = 4(rFP, rINST, 4)
+    * Z = (rFP, %edx, 4)
+    * Y = 4(rFP, %edx, 4)
+    */
+
+.L${opcode}_finish:
+    movl        4(rFP, rINST, 4), %ecx  # %ecx<- W
+    imull       (rFP, %edx, 4),  %ecx   # %ecx<- WxZ
+    mov         4(rFP, %edx, 4), %eax   # %ecx<- Y
+    imull       (rFP, rINST, 4), %eax   # %eax<- XxY
+    addl        %eax, %ecx              # %ecx<- (WZ + XY)
+    movl        (rFP, %edx, 4), %eax    # %eax<- Z
+    mull        (rFP, rINST, 4)         # %edx:eax<- XZ
+    movzbl      -4(%esp), rINST         # rINST<- AA
+    addl        %edx, %ecx              # %ecx<- carry + (WZ + XY)
+    movl        %ecx, 4(rFP, rINST, 4)  # vAA+1<- results hi
+    movl        %eax, (rFP, rINST, 4)   # vAA<- results lo
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
new file mode 100644
index 0000000..d6b8c16
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_MUL_LONG_2ADDR.S
@@ -0,0 +1,72 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_MUL_LONG_2ADDR.S
+    *
+    * Code:  64-bit integer multiply
+    *
+    * For: mul-long/2addr
+    *
+    * Description: Multiply two sources registers and store the result
+    *              in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+   /*
+    * 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.
+    */
+
+    movl        rINST, %edx             # %edx<- BA+
+    shr         $$4, rINST              # rINST<- B
+    andl        $$15, %edx              # %edx<- A
+    movl        %edx, sReg0             # sReg0<- A
+    jmp         .L${opcode}_finish
+%break
+
+   /*
+    * X = (rFP, rINST, 4)
+    * W = 4(rFP, rINST, 4)
+    * Z = (rFP, %edx, 4)
+    * Y = 4(rFP, %edx, 4)
+    */
+
+.L${opcode}_finish:
+    movl        4(rFP, rINST, 4), %ecx  # %ecx<- W
+    imull       (rFP, %edx, 4), %ecx    # %ecx<- WxZ
+    movl                4(rFP, %edx, 4), %eax   # %eax<- Y
+    imull       (rFP, rINST, 4), %eax   # %eax<- X*Y
+    addl        %eax, %ecx              # %ecx<- (WZ + XY)
+    movl        (rFP, %edx, 4), %eax    # %eax<- Z
+    mull        (rFP, rINST, 4)         # %edx:eax<- XZ
+    addl        %edx, %ecx              # %ecx<- carry + (WZ + XY)
+    movl        sReg0, %edx             # %edx<- A
+    movl        %ecx, 4(rFP, %edx, 4)   # vA+1<- results hi
+    movl        %eax, (rFP, %edx, 4)    # vA<- results lo
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_NEG_DOUBLE.S b/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
new file mode 100644
index 0000000..b6fb070
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEG_DOUBLE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_DOUBLE.S
+    */
+
+%include "x86-atom/unopWide.S" { "preinstr":"movq .LdoubNeg, %xmm1", "instr":"pxor %xmm1, %xmm0" }
diff --git a/vm/mterp/x86-atom/OP_NEG_FLOAT.S b/vm/mterp/x86-atom/OP_NEG_FLOAT.S
new file mode 100644
index 0000000..418fc0a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEG_FLOAT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_FLOAT.S
+    */
+
+%include "x86-atom/unop.S" { "instr":"addl      $0x80000000, %ecx" }
diff --git a/vm/mterp/x86-atom/OP_NEG_INT.S b/vm/mterp/x86-atom/OP_NEG_INT.S
new file mode 100644
index 0000000..68acb89
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEG_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_INT.S
+    */
+
+%include "x86-atom/unop.S" {"instr":"neg        %ecx"}
diff --git a/vm/mterp/x86-atom/OP_NEG_LONG.S b/vm/mterp/x86-atom/OP_NEG_LONG.S
new file mode 100644
index 0000000..3f500bb
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEG_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEG_LONG.S
+    */
+
+%include "x86-atom/unopWide.S" {"preinstr":"xorps %xmm1, %xmm1", "instr":"psubq %xmm0, %xmm1", "result":"%xmm1"}
diff --git a/vm/mterp/x86-atom/OP_NEW_ARRAY.S b/vm/mterp/x86-atom/OP_NEW_ARRAY.S
new file mode 100644
index 0000000..a6d5fd3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEW_ARRAY.S
@@ -0,0 +1,92 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEW_ARRAY.S
+    *
+    * Code: Create a new array. Uses no substitutions.
+    *
+    * For: new-array
+    *
+    * Description: Construct a new array of the indicated type and size.
+    *              The type must be an array type.
+    *
+    * Format: B|A|op CCCC (22c)
+    *
+    * Syntax: op vA, vB, type@CCCC
+    *         op vA, vB, field@CCCC
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    movl        offGlue_methodClassDex(%eax), %eax # %eax<- glue->pDvmDex
+    FETCH       1, %ecx                 # %ecx<- CCCC
+    GET_VREG    %edx                    # %edx<- vB
+    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- glue->pDvmDex->pResClasses
+    cmp         $$0, %edx               # check for negative length
+    movl        (%eax, %ecx, 4), %eax   # %eax<- resolved class
+    js          common_errNegativeArraySize # handle negative array length
+    cmp         $$0, %eax               # check for null
+    EXPORT_PC                           # required for resolve
+    jne         .L${opcode}_finish      # already resovled so continue
+    jmp         .L${opcode}_resolve     # need to resolve
+%break
+
+   /*
+    * Resolve class.  (This is an uncommon case.)
+    *
+    *  %edx holds array length
+    *  %ecx holds class ref CCCC
+    */
+
+.L${opcode}_resolve:
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %eax # %eax<- glue->method
+    movl        %edx, -4(%esp)          # save length
+    movl        $$0, -8(%esp)           # push parameter false
+    movl        %ecx, -12(%esp)         # push parameter class ref
+    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
+    movl        %eax, -16(%esp)         # push parameter clazz
+    lea         -16(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer,
+                                        #       u4 classIdx, bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    cmp         $$0, %eax               # check for failure
+    lea         16(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    movl        -4(%esp), %edx          # %edx<- length
+
+   /*
+    * Finish allocation.
+    *
+    *  %eax holds class
+    *  %edx holds array length
+    */
+
+.L${opcode}_finish:
+    movl        %eax, -12(%esp)         # push parameter class
+    movl        %edx, -8(%esp)          # push parameter length
+    movl        $$ALLOC_DONT_TRACK, -4(%esp)
+    lea         -12(%esp), %esp
+    call        dvmAllocArrayByClass    # call: (ClassObject* arrayClass,
+                                        # size_t length, int allocFlags)
+                                        # return: ArrayObject*
+    and         $$15, rINST             # rINST<- A
+    cmp         $$0, %eax               # check for allocation failure
+    lea         12(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    SET_VREG    %eax, rINST             # vA<- pArray
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_NEW_ARRAY_JUMBO.S b/vm/mterp/x86-atom/OP_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEW_ARRAY_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_NEW_INSTANCE.S b/vm/mterp/x86-atom/OP_NEW_INSTANCE.S
new file mode 100644
index 0000000..d65afb7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEW_INSTANCE.S
@@ -0,0 +1,147 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NEW_INSTANCE.S
+    *
+    * Code: Create a new instance of a given type. Uses no substitutions.
+    *
+    * For: new-instance
+    *
+    * Description: Construct a new instance of the indicated type,
+    *              storing a reference to it in the destination.
+    *              The type must refer to a non-array class.
+    *
+    *
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, type@BBBB
+    *         op vAA, field@BBBB
+    *         op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %edx                 # %edx<- BBBB
+    movl        offDvmDex_pResClasses(%ecx), %ecx # %ecx<- glue->pDvmDex->pResClasses
+    movl        (%ecx, %edx, 4), %edx   # %edx<- vB
+    EXPORT_PC                           # required for resolve
+    cmp         $$0, %edx               # check for null
+    je          .L${opcode}_resolve     # need to resolve
+
+   /*
+    *  %edx holds class object
+    */
+
+.L${opcode}_resolved:
+    movzbl      offClassObject_status(%edx), %eax # %eax<- class status
+    cmp         $$CLASS_INITIALIZED, %eax # check if class is initialized
+    jne         .L${opcode}_needinit    # initialize class
+
+   /*
+    *  %edx holds class object
+    */
+
+.L${opcode}_initialized:
+    testl       $$(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
+    mov         $$ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
+    je          .L${opcode}_finish      # continue
+    jmp         .L${opcode}_abstract    # handle abstract or interface
+
+   /*
+    *  %edx holds class object
+    *  %eax holds flags for alloc call
+    */
+
+%break
+.balign 32
+.L${opcode}_finish:
+    movl        %edx, -8(%esp)          # push parameter object
+    movl        %eax, -4(%esp)          # push parameter flags
+    lea         -8(%esp), %esp
+    call        dvmAllocObject          # call: (ClassObject* clazz, int flags)
+                                        # return: Object*
+    cmp         $$0, %eax               # check for failure
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # handle exception
+    SET_VREG    %eax, rINST             # vAA<- pObject
+    FINISH      2                       # jump to next instruction
+
+   /*
+    * Class initialization required.
+    *
+    *  %edx holds class object
+    */
+
+.L${opcode}_needinit:
+    movl        %edx, -4(%esp)          # push parameter object
+    lea         -4(%esp), %esp
+    call        dvmInitClass            # call: (ClassObject* clazz)
+                                        # return: bool
+    lea         4(%esp), %esp
+    cmp         $$0, %eax               # check for failure
+    movl        -4(%esp), %edx          # %edx<- object
+    je          common_exceptionThrown  # handle exception
+    testl       $$(ACC_INTERFACE|ACC_ABSTRACT), offClassObject_accessFlags(%edx)
+    mov         $$ALLOC_DONT_TRACK, %eax # %eax<- flag for alloc call
+    je          .L${opcode}_finish      # continue
+    jmp         .L${opcode}_abstract    # handle abstract or interface
+
+   /*
+    * Resolution required.  This is the least-likely path.
+    *
+    *  BBBB in %eax
+    */
+
+.L${opcode}_resolve:
+
+
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
+    movl        offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
+    movl        %ecx, -12(%esp)         # push parameter clazz
+    movl        $$0, -4(%esp)           # push parameter false
+    movl        %eax, -8(%esp)          # push parameter BBBB
+    lea         -12(%esp), %esp
+    call        dvmResolveClass         # call: (const ClassObject* referrer,
+                                        #       u4 classIdx, bool fromUnverifiedConstant)
+                                        # return: ClassObject*
+    lea         12(%esp), %esp
+    movl        %eax, %edx              # %edx<- pObject
+    cmp         $$0, %edx               # check for failure
+    jne         .L${opcode}_resolved    # continue
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * We can't instantiate an abstract class or interface, so throw an
+    * InstantiationError with the class descriptor as the message.
+    *
+    *  %edx holds class object
+    */
+
+.L${opcode}_abstract:
+    movl        offClassObject_descriptor(%edx), %ecx # %ecx<- descriptor
+    movl        %ecx, -4(%esp)          # push parameter descriptor
+    movl        $$.LstrInstantiationErrorPtr, -8(%esp) # push parameter message
+    lea         -8(%esp), %esp
+    call        dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
+                                                  #        const char* messageDescriptor)
+                                                  # return: void
+    jmp         common_exceptionThrown  # handle exception
+
+.LstrInstantiationErrorPtr:
+.asciz      "Ljava/lang/InstantiationError;"
diff --git a/vm/mterp/x86-atom/OP_NEW_INSTANCE_JUMBO.S b/vm/mterp/x86-atom/OP_NEW_INSTANCE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NEW_INSTANCE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_NOP.S b/vm/mterp/x86-atom/OP_NOP.S
new file mode 100644
index 0000000..9911da3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NOP.S
@@ -0,0 +1,41 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NOP.S
+    *
+    * Code: Use a cycle. Uses no substitutions.
+    *
+    * For: nop
+    *
+    * Description: No operation. Use a cycle
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    FINISH      1                       # jump to next instruction
+
+#ifdef ASSIST_DEBUGGER
+
+   /*
+    * insert fake function header to help gdb find the stack frame
+    */
+
+    .type       dalvik_inst, %function
+dalvik_inst:
+    MTERP_ENTRY
+#endif
diff --git a/vm/mterp/x86-atom/OP_NOT_INT.S b/vm/mterp/x86-atom/OP_NOT_INT.S
new file mode 100644
index 0000000..b82e5b6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NOT_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NOT_INT.S
+    */
+
+%include "x86-atom/unop.S" {"instr":"not        %ecx"}
diff --git a/vm/mterp/x86-atom/OP_NOT_LONG.S b/vm/mterp/x86-atom/OP_NOT_LONG.S
new file mode 100644
index 0000000..98ff80b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_NOT_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_NOT_LONG.S
+    */
+
+%include "x86-atom/unopWide.S" {"instr":"pandn  0xFFFFFFFF, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT.S b/vm/mterp/x86-atom/OP_OR_INT.S
new file mode 100644
index 0000000..0ece38c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_OR_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT.S
+    */
+
+%include "x86-atom/binop.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_OR_INT_2ADDR.S
new file mode 100644
index 0000000..693e099
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_OR_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT_2ADDR.S
+    */
+
+%include "x86-atom/binop2addr.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT_LIT16.S b/vm/mterp/x86-atom/OP_OR_INT_LIT16.S
new file mode 100644
index 0000000..5c63867
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_OR_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT_LIT16.S
+    */
+
+%include "x86-atom/binopLit16.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_INT_LIT8.S b/vm/mterp/x86-atom/OP_OR_INT_LIT8.S
new file mode 100644
index 0000000..aacd6c3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_OR_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8.S" {"instr":"or %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_OR_LONG.S b/vm/mterp/x86-atom/OP_OR_LONG.S
new file mode 100644
index 0000000..f698e54
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_OR_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_LONG.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"por %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_OR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_OR_LONG_2ADDR.S
new file mode 100644
index 0000000..12a88ec
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_OR_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_OR_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"por %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_PACKED_SWITCH.S b/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
new file mode 100644
index 0000000..debac02
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_PACKED_SWITCH.S
@@ -0,0 +1,52 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_PACKED_SWITCH.S
+    *
+    * Code: Jump to a new instruction using a jump table
+    *
+    * For: packed-switch, sparse-switch
+    *
+    * Description: Jump to a new instruction based on the value in the given
+    *              register, using a table of offsets corresponding to each
+    *              value in a particular integral range, or fall through to
+    *              the next instruction if there is no match.
+    *
+    * Format: AA|op BBBBlo BBBBhi (31t)
+    *
+    * Syntax: op vAA, +BBBBBBBB
+    */
+
+%default { "func":"dvmInterpHandlePackedSwitch" }
+
+    FETCH       1, %ecx                 # %ecx<- BBBBlo
+    FETCH       2, %edx                 # %edx<- BBBBhi
+    shl         $$16, %edx              # prepare to create +BBBBBBBB
+    or          %edx, %ecx              # %ecx<- +BBBBBBBB
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, -4(%esp)         # push parameter vAA
+    lea         (rPC, %ecx, 2), %ecx    # %ecx<- PC + +BBBBBBBB*2
+    movl        %ecx, -8(%esp)          # push parameter PC + +BBBBBBBB*2
+    lea         -8(%esp), %esp
+    call        $func                   # call code-unit branch offset
+    shl         $$1, %eax               # shift for byte offset
+    movl        %eax, %edx              # %edx<- offset
+    lea         8(%esp), %esp
+    jle         common_periodicChecks_backwardBranch  # do backward branch
+    jmp         .L${opcode}_finish
+%break
+.L${opcode}_finish:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_DOUBLE.S b/vm/mterp/x86-atom/OP_REM_DOUBLE.S
new file mode 100644
index 0000000..aa7d332
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_DOUBLE.S
@@ -0,0 +1,51 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_DOUBLE.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-double
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in a
+    *              destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        (rFP, %ecx, 4), %eax    # %eax<- vBBlo
+    movl        %eax, -16(%esp)         # push parameter double lo
+    movl        4(rFP, %ecx, 4), %eax   # %eax<- vBBhi
+    movl        %eax, -12(%esp)         # push parameter double hi
+    movl        (rFP, %edx, 4), %eax    # %eax<- vCClo
+    movl        %eax, -8(%esp)          # push parameter double lo
+    movl        4(rFP, %edx, 4), %eax   # %eax<- vCChi
+    movl        %eax, -4(%esp)          # push parameter double hi
+    lea         -16(%esp), %esp
+    jmp         .L${opcode}_break
+%break
+
+.L${opcode}_break:
+    call        fmod                    # call: (long double x, long double y)
+                                        # return: double
+    lea         16(%esp), %esp
+    fstpl       (rFP, rINST, 4)         # vAA<- remainder; return of fmod
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..434c878
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_DOUBLE_2ADDR.S
@@ -0,0 +1,52 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_DOUBLE_2ADDR.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-double/2addr
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in the first
+    *              source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    and         $$15, rINST             # rINST<- A
+    shr         $$4, %edx               # %edx<- B
+    movl        (rFP, rINST, 4), %eax   # %eax<- vAlo
+    movl        %eax, -20(%esp)         # push parameter vAAlo
+    movl        4(rFP, rINST, 4), %eax  # %eax<- vAhi
+    movl        %eax, -16(%esp)         # push parameter vAAhi
+    movl        (rFP, %edx, 4), %eax    # %eax<- vBlo
+    movl        %eax, -12(%esp)         # push parameter vBBlo
+    movl        4(rFP, %edx, 4), %eax   # %eax<- vBhi
+    movl        %eax, -8(%esp)          # push parameter vBBhi
+    lea         -20(%esp), %esp
+    jmp         .L${opcode}_break
+%break
+
+.L${opcode}_break:
+    call        fmod                    # call: (long double x, long double y)
+                                        # return: double
+    lea         20(%esp), %esp
+    fstpl       (rFP, rINST, 4)         # vAA<- remainder; return of fmod
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_FLOAT.S b/vm/mterp/x86-atom/OP_REM_FLOAT.S
new file mode 100644
index 0000000..de5e161
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_FLOAT.S
@@ -0,0 +1,43 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_FLOAT.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-float
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in a
+    *              destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    movl        %ecx, -8(%esp)          # push parameter float
+    movl        %edx, -4(%esp)          # push parameter float
+    lea         -8(%esp), %esp
+    call        fmodf                   # call: (float x, float y)
+                                        # return: float
+    lea         8(%esp), %esp
+    fstps       (rFP, rINST, 4)         # vAA<- remainder; return of fmod
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
new file mode 100644
index 0000000..5ff5af5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_FLOAT_2ADDR.S
@@ -0,0 +1,44 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_FLOAT_2ADDR.S
+    *
+    * Code: Computes the remainder of a division. Performs no substitutions.
+    *
+    * For: rem-float/2addr
+    *
+    * Description: Calls fmod to compute the remainder of the result of dividing a
+    *              source register by a second, and stores the result in the first
+    *              source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    GET_VREG    %edx                    # %edx<- vB
+    movl        (rFP, rINST, 4), %ecx   # %ecx<- vA
+    movl        %ecx, -8(%esp)          # push parameter vA
+    movl        %edx, -4(%esp)          # push parameter vB
+    lea         -8(%esp), %esp
+    call        fmodf                   # call: (float x, float y)
+                                        # return: float
+    lea         8(%esp), %esp
+    fstps       (rFP, rINST, 4)
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_REM_INT.S b/vm/mterp/x86-atom/OP_REM_INT.S
new file mode 100644
index 0000000..5f62d66
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT.S
+    */
+
+%include "x86-atom/binopD.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S b/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
new file mode 100644
index 0000000..369ea5c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT_2ADDR.S
+    */
+
+%include "x86-atom/binopD2addr.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_INT_LIT16.S b/vm/mterp/x86-atom/OP_REM_INT_LIT16.S
new file mode 100644
index 0000000..0c9afa3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT_LIT16.S
+    */
+
+%include "x86-atom/binopDLit16.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_INT_LIT8.S b/vm/mterp/x86-atom/OP_REM_INT_LIT8.S
new file mode 100644
index 0000000..6578c7c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_INT_LIT8.S
+    */
+
+%include "x86-atom/binopDLit8.S" {"div":"0"}
diff --git a/vm/mterp/x86-atom/OP_REM_LONG.S b/vm/mterp/x86-atom/OP_REM_LONG.S
new file mode 100644
index 0000000..3e3b200
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_LONG.S
+    */
+
+%include "x86-atom/binopDivRemLong.S" {"func":"__moddi3"}
diff --git a/vm/mterp/x86-atom/OP_REM_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_REM_LONG_2ADDR.S
new file mode 100644
index 0000000..f494caf
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_REM_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_REM_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopDivRemLong2Addr.S" {"func":"__moddi3"}
diff --git a/vm/mterp/x86-atom/OP_RETURN.S b/vm/mterp/x86-atom/OP_RETURN.S
new file mode 100644
index 0000000..48d7e34
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RETURN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN.S
+    */
+
+%include "x86-atom/OP_RETURN_COMMON.S"
diff --git a/vm/mterp/x86-atom/OP_RETURN_COMMON.S b/vm/mterp/x86-atom/OP_RETURN_COMMON.S
new file mode 100644
index 0000000..d58a16c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RETURN_COMMON.S
@@ -0,0 +1,34 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_COMMON.S
+    *
+    * Code: Return a 32-bit value. Uses no substitutions.
+    *
+    * For: return, return-object
+    *
+    * Description: Copies the return value into the "glue"
+    *              structure, then jumps to the return handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offGlue_retval(%edx) # glue->retval<- vAA
+    jmp         common_returnFromMethod # jump to common return code
diff --git a/vm/mterp/x86-atom/OP_RETURN_OBJECT.S b/vm/mterp/x86-atom/OP_RETURN_OBJECT.S
new file mode 100644
index 0000000..3b9c10c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RETURN_OBJECT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_OBJECT.S
+    */
+
+%include "x86-atom/OP_RETURN_COMMON.S"
diff --git a/vm/mterp/x86-atom/OP_RETURN_VOID.S b/vm/mterp/x86-atom/OP_RETURN_VOID.S
new file mode 100644
index 0000000..4d8c92b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RETURN_VOID.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_VOID.S
+    */
+
+    jmp         common_returnFromMethod
diff --git a/vm/mterp/x86-atom/OP_RETURN_WIDE.S b/vm/mterp/x86-atom/OP_RETURN_WIDE.S
new file mode 100644
index 0000000..8069e85
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RETURN_WIDE.S
@@ -0,0 +1,34 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RETURN_WIDE.S
+    *
+    * Code: Return a 64-bit value. Uses no substitutions.
+    *
+    * For: return-wide
+    *
+    * Description: Copies the return value into the "glue"
+    *              structure, then jumps to the return handler.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vAA
+    movq        %xmm0, offGlue_retval(%edx)# glue->retval<- vAA
+    jmp         common_returnFromMethod # jump to common return code
diff --git a/vm/mterp/x86-atom/OP_RSUB_INT.S b/vm/mterp/x86-atom/OP_RSUB_INT.S
new file mode 100644
index 0000000..87498f9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RSUB_INT.S
@@ -0,0 +1,39 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RSUB_INT.S
+    *
+    * Code: 32-bit reverse-subtraction. Uses no substitutions.
+    *
+    * For: rsub-int
+    *
+    * Description: Perform a reverse subtraction on a register and a
+    *              signed extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $$4, %ecx               # %ecx<- B
+    andl        $$15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    GET_VREG    %ecx                    # %ecx<- vB
+    subl        %ecx, %edx              # %edx<- +CCCC sub vB
+    SET_VREG    %edx, rINST             # vA<- %edx; result
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S b/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
new file mode 100644
index 0000000..d6114dd
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_RSUB_INT_LIT8.S
@@ -0,0 +1,36 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_RSUB_INT_LIT8.S
+    *
+    * Code: 32-bit reverse-subtraction. Uses no substitutions.
+    *
+    * For: rsub-int/lit8
+    *
+    * Description: Perform a reverse subtraction on a register and a
+    *              signed extended 8-bit literal value.
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    GET_VREG    %ecx                    # %ecx<- vBB
+    sub         %ecx, %edx              # %edx<- +CC sub vBB
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SGET.S b/vm/mterp/x86-atom/OP_SGET.S
new file mode 100644
index 0000000..914b4dc
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET.S
@@ -0,0 +1,60 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET.S
+    *
+    * Code: Generic 32-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-boolean, sget-byte, sget-char, sget-object, sget, sget-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; load the field value
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $$0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .L${opcode}_resolve
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $$0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    mov         %eax, %ecx              # %ecx<- result
+
+.L${opcode}_finish:
+    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
+    movl offStaticField_value(%ecx), %eax # %eax<- field value
+    SET_VREG    %eax, rINST             # vAA<- field value
+    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S b/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
new file mode 100644
index 0000000..8e383b4
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_BOOLEAN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_BOOLEAN.S
+    */
+
+%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_BOOLEAN_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_BOOLEAN_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_BYTE.S b/vm/mterp/x86-atom/OP_SGET_BYTE.S
new file mode 100644
index 0000000..c86fc20
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_BYTE.S
+    */
+
+%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_BYTE_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_BYTE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_CHAR.S b/vm/mterp/x86-atom/OP_SGET_CHAR.S
new file mode 100644
index 0000000..0a3cffd
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_CHAR.S
+    */
+
+%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_CHAR_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_CHAR_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_OBJECT.S b/vm/mterp/x86-atom/OP_SGET_OBJECT.S
new file mode 100644
index 0000000..5145f14
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_OBJECT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_OBJECT.S
+    */
+
+%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_OBJECT_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_OBJECT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_SGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..5f64fb5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_OBJECT_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_SHORT.S b/vm/mterp/x86-atom/OP_SGET_SHORT.S
new file mode 100644
index 0000000..77064b6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_SHORT.S
+    */
+
+%include "x86-atom/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_SHORT_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_SHORT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_VOLATILE.S b/vm/mterp/x86-atom/OP_SGET_VOLATILE.S
new file mode 100644
index 0000000..5f64fb5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86-atom/OP_SGET_WIDE.S b/vm/mterp/x86-atom/OP_SGET_WIDE.S
new file mode 100644
index 0000000..3ef6916
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_WIDE.S
@@ -0,0 +1,65 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SGET_WIDE.S
+    *
+    * Code: 64-bit static field "get" operation. Uses no substitutions.
+    *
+    * For: sget-wide
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field, loading or storing
+    *              into the value register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %edx                 # %edx<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $$0, (%ecx, %edx, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .L${opcode}_resolve
+
+.L${opcode}_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        offStaticField_value(%ecx), %xmm0 # %xmm0<- field value
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- field value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+%break
+
+   /*
+    * Continuation if the field has not yet been resolved.
+    *  %edx: BBBB field ref
+    */
+
+.L${opcode}_resolve:
+    movl        offGlue_method(%eax), %eax # %eax <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %edx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%eax), %eax # %eax<- method->clazz
+    movl        %eax, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    lea         8(%esp), %esp
+    cmp         $$0, %eax               # check if initalization failed
+    movl        %eax, %ecx              # %ecx<- result
+    jne         .L${opcode}_finish      # success, continue
+    jmp         common_exceptionThrown  # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_SGET_WIDE_JUMBO.S b/vm/mterp/x86-atom/OP_SGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SGET_WIDE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SHL_INT.S b/vm/mterp/x86-atom/OP_SHL_INT.S
new file mode 100644
index 0000000..13e4a11
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHL_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_INT.S
+    */
+
+%include "x86-atom/binopS.S" {"instr":"sal     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHL_INT_2ADDR.S b/vm/mterp/x86-atom/OP_SHL_INT_2ADDR.S
new file mode 100644
index 0000000..a27e09a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHL_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_INT_2ADDR.S
+    */
+
+%include "x86-atom/binopS2addr.S" {"instr":"sal     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHL_INT_LIT8.S b/vm/mterp/x86-atom/OP_SHL_INT_LIT8.S
new file mode 100644
index 0000000..5141e5c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHL_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8S.S" {"instr":"sal     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHL_LONG.S b/vm/mterp/x86-atom/OP_SHL_LONG.S
new file mode 100644
index 0000000..cef558c
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHL_LONG.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_LONG.S
+    *
+    * Code: Performs a shift left long. Uses no substitutions.
+    *
+    * For: shl-long
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where one is the shift amount and the other is the value to shift.
+    *              Store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_CC    1, %eax                 # %eax<- CC
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movq        .LshiftMask, %xmm2      # %xmm2<- mask for the shift bits
+    movss       (rFP, %eax, 4), %xmm0   # %xmm0<- vCC
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vBB
+    psllq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    movq        %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
new file mode 100644
index 0000000..28dfaf2
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHL_LONG_2ADDR.S
@@ -0,0 +1,41 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHL_LONG_2ADDR.S
+    *
+    * Code: Performs a shift left long. Uses no substitutions.
+    *
+    * For: shl-long/2addr
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where the fist is the value to shift and the second is the
+    *              shift amount. Store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    movss       (rFP, %edx, 4),  %xmm0  # %xmm0<- vB
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vA
+    movq        .LshiftMask, %xmm2      # %xmm2<- mask for the shift bits
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    psllq       %xmm0, %xmm1            # %xmm1<- shifted vA
+    movq        %xmm1, (rFP, rINST, 4)  # vA<- shifted vA
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SHR_INT.S b/vm/mterp/x86-atom/OP_SHR_INT.S
new file mode 100644
index 0000000..e7fd28b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHR_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_INT.S
+    */
+
+%include "x86-atom/binopS.S" {"instr":"sar     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_SHR_INT_2ADDR.S
new file mode 100644
index 0000000..0d0b461
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHR_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_INT_2ADDR.S
+    */
+
+%include "x86-atom/binopS2addr.S" {"instr":"sar     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHR_INT_LIT8.S b/vm/mterp/x86-atom/OP_SHR_INT_LIT8.S
new file mode 100644
index 0000000..3467bf5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHR_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8S.S" {"instr":"sar     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_SHR_LONG.S b/vm/mterp/x86-atom/OP_SHR_LONG.S
new file mode 100644
index 0000000..be893ef
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHR_LONG.S
@@ -0,0 +1,53 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_LONG.S
+    *
+    * Code: Performs a shift right long
+    *
+    * For: shl-long
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where one is the shift amount and the other is the value to shift.
+    *              Store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CC    1, %eax                 # %eax<- CC
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vBB
+    movss       (rFP, %eax, 4), %xmm0   # %xmm0<- vCC
+    movq        .LshiftMask, %xmm2
+    pand        %xmm2, %xmm0            # %xmm0<- masked for the shift bits
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    cmpl        $$0, 4(rFP, %edx, 4)    # check if we need to consider sign
+    jl          .L${opcode}_finish      # consider sign
+    jmp         .L${opcode}_final       # sign is fine, finish
+%break
+
+.L${opcode}_finish:
+    movq        .Lvalue64, %xmm3        # %xmm3<- 64
+    psubq       %xmm0, %xmm3            # %xmm3<- 64 - shift amount
+    movq        .L64bits, %xmm4         # %xmm4<- lower 64 bits set
+    psllq       %xmm3, %xmm4            # %xmm4<- correct mask for sign bits
+    por         %xmm4, %xmm1            # %xmm1<- signed and shifted vBB
+
+.L${opcode}_final:
+    movq        %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
new file mode 100644
index 0000000..38aefcf
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SHR_LONG_2ADDR.S
@@ -0,0 +1,54 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SHR_LONG_2ADDR.S
+    *
+    * Code: Performs a shift left long
+    *
+    * For: shl-long/2addr
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where the fist is the value to shift and the second is the
+    *              shift amount. Store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- BA
+    movss       (rFP, %edx, 4),  %xmm0  # %xmm0<- vB
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vA
+    movq        .LshiftMask, %xmm2
+    pand        %xmm2, %xmm0            # %xmm0<- masked for the shift bits
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    cmpl        $$0, 4(rFP, rINST, 4)   # check if we need to consider sign
+    jl          .L${opcode}_finish      # consider sign
+    jmp         .L${opcode}_final       # sign is fine, finish
+%break
+
+.L${opcode}_finish:
+    movq        .Lvalue64, %xmm3        # %xmm3<- 64
+    psubq       %xmm0, %xmm3            # %xmm3<- 64 - shift amount
+    movq        .L64bits, %xmm4         # %xmm4<- lower 64 bits set
+    psllq       %xmm3, %xmm4            # %xmm4<- correct mask for sign bits
+    por         %xmm4, %xmm1            # %xmm1<- signed and shifted vBB
+
+.L${opcode}_final:
+    movq        %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_SPARSE_SWITCH.S b/vm/mterp/x86-atom/OP_SPARSE_SWITCH.S
new file mode 100644
index 0000000..8020d1a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPARSE_SWITCH.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPARSE_SWITCH.S
+    */
+
+%include "x86-atom/OP_PACKED_SWITCH.S" { "func":"dvmInterpHandleSparseSwitch" }
diff --git a/vm/mterp/x86-atom/OP_SPUT.S b/vm/mterp/x86-atom/OP_SPUT.S
new file mode 100644
index 0000000..55715a7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT.S
@@ -0,0 +1,60 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $$0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .L${opcode}_resolve
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $$0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.L${opcode}_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_SPUT_BOOLEAN.S b/vm/mterp/x86-atom/OP_SPUT_BOOLEAN.S
new file mode 100644
index 0000000..9bb64f8
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_BOOLEAN.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_BOOLEAN.S
+    */
+
+%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_BOOLEAN_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_BYTE.S b/vm/mterp/x86-atom/OP_SPUT_BYTE.S
new file mode 100644
index 0000000..1d4f016
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_BYTE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_BYTE.S
+    */
+
+%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_BYTE_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_BYTE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_CHAR.S b/vm/mterp/x86-atom/OP_SPUT_CHAR.S
new file mode 100644
index 0000000..58300ef
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_CHAR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_CHAR.S
+    */
+
+%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_CHAR_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_CHAR_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_OBJECT.S b/vm/mterp/x86-atom/OP_SPUT_OBJECT.S
new file mode 100644
index 0000000..88ebaf7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_OBJECT.S
@@ -0,0 +1,70 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_OBJECT.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        offGlue_methodClassDex(%edx), %ecx # %ecx<- pDvmDex
+    FETCH       1, %eax                 # %eax<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $$0, (%ecx, %eax, 4)    # check for null ptr; resolved StaticField
+    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved StaticField
+    je          .L${opcode}_resolve
+    jmp         .L${opcode}_finish
+%break
+
+.L${opcode}_resolve:
+    movl        offGlue_method(%edx), %edx # %edx <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %eax, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    movl        %edx, -8(%esp)          # push parameter method->clazz
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    cmp         $$0, %eax               # check if initalization failed
+    lea         8(%esp), %esp
+    je          common_exceptionThrown  # failed; handle exception
+    movl        %eax, %ecx              # %ecx<- result
+
+.L${opcode}_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    rINST                   # rINST<- vAA
+
+
+    movl        rINST, offStaticField_value(%ecx) # field value<- vAA
+    testl       rINST, rINST            # stored null object ptr?
+    je          1f
+    movl        rGLUE, %edx             # get glue
+    movl        offField_clazz(%ecx), %ecx # ecx<- field->clazz
+    movl        offGlue_cardTable(%edx), %edx # get card table base
+    shrl        $$GC_CARD_SHIFT, %ecx   # head to card number
+    movb        %dl, (%edx, %ecx)       # mark card
+1:
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/OP_SPUT_OBJECT_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_OBJECT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/x86-atom/OP_SPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..b368e31
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_OBJECT_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_SPUT_OBJECT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_SHORT.S b/vm/mterp/x86-atom/OP_SPUT_SHORT.S
new file mode 100644
index 0000000..1ecc562
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_SHORT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_SHORT.S
+    */
+
+%include "x86-atom/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_SHORT_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_SHORT_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_VOLATILE.S b/vm/mterp/x86-atom/OP_SPUT_VOLATILE.S
new file mode 100644
index 0000000..7ee4140
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_VOLATILE.S
@@ -0,0 +1 @@
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86-atom/OP_SPUT_WIDE.S b/vm/mterp/x86-atom/OP_SPUT_WIDE.S
new file mode 100644
index 0000000..7d661cf
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_WIDE.S
@@ -0,0 +1,65 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SPUT_WIDE.S
+    *
+    * Code: Generic 32-bit static field "put" operation. Uses no substitutions.
+    *
+    * For: sput-boolean, sput-byte, sput-char, sput-object, sput, sput-short
+    *
+    * Description: Perform the identified object static field operation
+    *              with the identified static field; store the field value
+    *              register.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, string@BBBB
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_methodClassDex(%eax), %ecx # %ecx<- glue->pDvmDex
+    FETCH       1, %edx                 # %edx<- BBBB
+    movl        offDvmDex_pResFields(%ecx), %ecx # %ecx<- pResFields
+    cmp         $$0, (%ecx, %edx, 4)    # check for null ptr; resolved StaticField ptr
+    movl        (%ecx, %edx, 4), %ecx   # %ecx<- resolved StaticField ptr
+    je          .L${opcode}_resolve
+
+.L${opcode}_finish:
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vAA
+    movq        %xmm0, offStaticField_value(%ecx) # field value<- field value
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
+%break
+
+   /*
+    * Continuation if the field has not yet been resolved.
+    *  %edx: BBBB field ref
+    */
+
+.L${opcode}_resolve:
+    movl        offGlue_method(%eax), %eax # %eax <- glue->method
+    EXPORT_PC                           # in case an exception is thrown
+    movl        %edx, -4(%esp)          # push parameter CCCC; field ref
+    movl        offMethod_clazz(%eax), %eax # %eax<- method->clazz
+    movl        %eax, -8(%esp)
+    lea         -8(%esp), %esp
+    call        dvmResolveStaticField   # call: (const ClassObject* referrer, u4 ifieldIdx)
+                                        # return: StaticField*
+    lea         8(%esp), %esp
+    cmp         $$0, %eax               # check if initalization failed
+    movl        %eax, %ecx              # %ecx<- result
+    jne         .L${opcode}_finish      # success, continue
+    jmp         common_exceptionThrown  # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_SPUT_WIDE_JUMBO.S b/vm/mterp/x86-atom/OP_SPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SPUT_WIDE_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_SUB_DOUBLE.S b/vm/mterp/x86-atom/OP_SUB_DOUBLE.S
new file mode 100644
index 0000000..5f2dbb6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_DOUBLE.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_DOUBLE.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"subsd   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..cd6f12a
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_DOUBLE_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_DOUBLE_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"subsd   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_FLOAT.S b/vm/mterp/x86-atom/OP_SUB_FLOAT.S
new file mode 100644
index 0000000..eb79d79
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_FLOAT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_FLOAT.S
+    */
+
+%include "x86-atom/binopF.S" {"instr":"subss     %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_FLOAT_2ADDR.S
new file mode 100644
index 0000000..77f23f1
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_FLOAT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_FLOAT_2ADDR.S
+    */
+
+%include "x86-atom/binopF2addr.S" {"instr":"subss     %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_INT.S b/vm/mterp/x86-atom/OP_SUB_INT.S
new file mode 100644
index 0000000..8d342cd
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_INT.S
+    */
+
+%include "x86-atom/binop.S" {"instr":"subl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_SUB_INT_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_INT_2ADDR.S
new file mode 100644
index 0000000..4d295a4
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_INT_2ADDR.S
+    */
+
+%include "x86-atom/binop2addr.S" {"instr":"subl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_SUB_INT_LIT8.S b/vm/mterp/x86-atom/OP_SUB_INT_LIT8.S
new file mode 100644
index 0000000..8bf0902
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8.S" {"instr":"subl     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_SUB_LONG.S b/vm/mterp/x86-atom/OP_SUB_LONG.S
new file mode 100644
index 0000000..84e25d0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_LONG.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"psubq    %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_SUB_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_SUB_LONG_2ADDR.S
new file mode 100644
index 0000000..ca6a2ad
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_SUB_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_SUB_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"psubq    %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_THROW.S b/vm/mterp/x86-atom/OP_THROW.S
new file mode 100644
index 0000000..120b1e9
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_THROW.S
@@ -0,0 +1,37 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_THROW.S
+    *
+    * Code: Throw an exception
+    *
+    * For: throw
+    *
+    * Description: Throw an exception object in the current thread.
+    *
+    * Format: AA|op (11x)
+    *
+    * Syntax: op vAA
+    */
+
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    EXPORT_PC                           # export the pc
+    GET_VREG    rINST                   # rINST<- vAA
+    cmp         $$0, rINST              # check for null
+    movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
+    je          common_errNullObject    # handle null object
+    movl        rINST, offThread_exception(%ecx) # thread->exception<- object
+    jmp         common_exceptionThrown  # handle exception
diff --git a/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
new file mode 100644
index 0000000..f920b50
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR.S
@@ -0,0 +1,40 @@
+   /* 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.
+    */
+
+   /*
+    * File: OP_THROW_VERIFICATION_ERROR.S
+    *
+    * Code:
+    *
+    * For: throw-verification-error
+    *
+    * Description: Throws an exception for an error discovered during verification.
+    *              The exception is indicated by AA with details provided by BBBB.
+    *
+    * Format: AA|op BBBB (21c)
+    *
+    * Syntax: op vAA, ref@BBBB
+    */
+
+    movl        rGLUE, %edx                  # %edx<- pMterpGlue
+    movl        offGlue_method(%edx), %ecx   # %ecx<- glue->method
+    EXPORT_PC                                # in case an exception is thrown
+    FETCH       1, %eax                      # %eax<- BBBB
+    movl        %eax, -4(%esp)               # push parameter BBBB; ref
+    movl        rINST, -8(%esp)              # push parameter AA
+    movl        %ecx, -12(%esp)              # push parameter glue->method
+    lea         -12(%esp), %esp
+    call        dvmThrowVerificationError    # call: (const Method* method, int kind, int ref)
+    jmp         common_exceptionThrown       # failed; handle exception
diff --git a/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR_JUMBO.S b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR_JUMBO.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_THROW_VERIFICATION_ERROR_JUMBO.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_27FF.S b/vm/mterp/x86-atom/OP_UNUSED_27FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_27FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_28FF.S b/vm/mterp/x86-atom/OP_UNUSED_28FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_28FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_29FF.S b/vm/mterp/x86-atom/OP_UNUSED_29FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_29FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_2AFF.S b/vm/mterp/x86-atom/OP_UNUSED_2AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_2AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_2BFF.S b/vm/mterp/x86-atom/OP_UNUSED_2BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_2BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_2CFF.S b/vm/mterp/x86-atom/OP_UNUSED_2CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_2CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_2DFF.S b/vm/mterp/x86-atom/OP_UNUSED_2DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_2DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_2EFF.S b/vm/mterp/x86-atom/OP_UNUSED_2EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_2EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_2FFF.S b/vm/mterp/x86-atom/OP_UNUSED_2FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_2FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_30FF.S b/vm/mterp/x86-atom/OP_UNUSED_30FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_30FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_31FF.S b/vm/mterp/x86-atom/OP_UNUSED_31FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_31FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_32FF.S b/vm/mterp/x86-atom/OP_UNUSED_32FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_32FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_33FF.S b/vm/mterp/x86-atom/OP_UNUSED_33FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_33FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_34FF.S b/vm/mterp/x86-atom/OP_UNUSED_34FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_34FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_35FF.S b/vm/mterp/x86-atom/OP_UNUSED_35FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_35FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_36FF.S b/vm/mterp/x86-atom/OP_UNUSED_36FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_36FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_37FF.S b/vm/mterp/x86-atom/OP_UNUSED_37FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_37FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_38FF.S b/vm/mterp/x86-atom/OP_UNUSED_38FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_38FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_39FF.S b/vm/mterp/x86-atom/OP_UNUSED_39FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_39FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3AFF.S b/vm/mterp/x86-atom/OP_UNUSED_3AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3BFF.S b/vm/mterp/x86-atom/OP_UNUSED_3BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3CFF.S b/vm/mterp/x86-atom/OP_UNUSED_3CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3DFF.S b/vm/mterp/x86-atom/OP_UNUSED_3DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3E.S b/vm/mterp/x86-atom/OP_UNUSED_3E.S
new file mode 100644
index 0000000..d91d469
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3E.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_3E.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3EFF.S b/vm/mterp/x86-atom/OP_UNUSED_3EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3F.S b/vm/mterp/x86-atom/OP_UNUSED_3F.S
new file mode 100644
index 0000000..84cc69d
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3F.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_3F.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_3FFF.S b/vm/mterp/x86-atom/OP_UNUSED_3FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_3FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_40.S b/vm/mterp/x86-atom/OP_UNUSED_40.S
new file mode 100644
index 0000000..e0853da
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_40.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_40.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_40FF.S b/vm/mterp/x86-atom/OP_UNUSED_40FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_40FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_41.S b/vm/mterp/x86-atom/OP_UNUSED_41.S
new file mode 100644
index 0000000..a30fbe3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_41.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_41.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_41FF.S b/vm/mterp/x86-atom/OP_UNUSED_41FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_41FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_42.S b/vm/mterp/x86-atom/OP_UNUSED_42.S
new file mode 100644
index 0000000..64c5648
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_42.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_42.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_42FF.S b/vm/mterp/x86-atom/OP_UNUSED_42FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_42FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_43.S b/vm/mterp/x86-atom/OP_UNUSED_43.S
new file mode 100644
index 0000000..4a6120b
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_43.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_43.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_43FF.S b/vm/mterp/x86-atom/OP_UNUSED_43FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_43FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_44FF.S b/vm/mterp/x86-atom/OP_UNUSED_44FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_44FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_45FF.S b/vm/mterp/x86-atom/OP_UNUSED_45FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_45FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_46FF.S b/vm/mterp/x86-atom/OP_UNUSED_46FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_46FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_47FF.S b/vm/mterp/x86-atom/OP_UNUSED_47FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_47FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_48FF.S b/vm/mterp/x86-atom/OP_UNUSED_48FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_48FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_49FF.S b/vm/mterp/x86-atom/OP_UNUSED_49FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_49FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_4AFF.S b/vm/mterp/x86-atom/OP_UNUSED_4AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_4AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_4BFF.S b/vm/mterp/x86-atom/OP_UNUSED_4BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_4BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_4CFF.S b/vm/mterp/x86-atom/OP_UNUSED_4CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_4CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_4DFF.S b/vm/mterp/x86-atom/OP_UNUSED_4DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_4DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_4EFF.S b/vm/mterp/x86-atom/OP_UNUSED_4EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_4EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_4FFF.S b/vm/mterp/x86-atom/OP_UNUSED_4FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_4FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_50FF.S b/vm/mterp/x86-atom/OP_UNUSED_50FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_50FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_51FF.S b/vm/mterp/x86-atom/OP_UNUSED_51FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_51FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_52FF.S b/vm/mterp/x86-atom/OP_UNUSED_52FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_52FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_53FF.S b/vm/mterp/x86-atom/OP_UNUSED_53FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_53FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_54FF.S b/vm/mterp/x86-atom/OP_UNUSED_54FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_54FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_55FF.S b/vm/mterp/x86-atom/OP_UNUSED_55FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_55FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_56FF.S b/vm/mterp/x86-atom/OP_UNUSED_56FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_56FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_57FF.S b/vm/mterp/x86-atom/OP_UNUSED_57FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_57FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_58FF.S b/vm/mterp/x86-atom/OP_UNUSED_58FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_58FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_59FF.S b/vm/mterp/x86-atom/OP_UNUSED_59FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_59FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_5AFF.S b/vm/mterp/x86-atom/OP_UNUSED_5AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_5AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_5BFF.S b/vm/mterp/x86-atom/OP_UNUSED_5BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_5BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_5CFF.S b/vm/mterp/x86-atom/OP_UNUSED_5CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_5CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_5DFF.S b/vm/mterp/x86-atom/OP_UNUSED_5DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_5DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_5EFF.S b/vm/mterp/x86-atom/OP_UNUSED_5EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_5EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_5FFF.S b/vm/mterp/x86-atom/OP_UNUSED_5FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_5FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_60FF.S b/vm/mterp/x86-atom/OP_UNUSED_60FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_60FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_61FF.S b/vm/mterp/x86-atom/OP_UNUSED_61FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_61FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_62FF.S b/vm/mterp/x86-atom/OP_UNUSED_62FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_62FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_63FF.S b/vm/mterp/x86-atom/OP_UNUSED_63FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_63FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_64FF.S b/vm/mterp/x86-atom/OP_UNUSED_64FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_64FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_65FF.S b/vm/mterp/x86-atom/OP_UNUSED_65FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_65FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_66FF.S b/vm/mterp/x86-atom/OP_UNUSED_66FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_66FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_67FF.S b/vm/mterp/x86-atom/OP_UNUSED_67FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_67FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_68FF.S b/vm/mterp/x86-atom/OP_UNUSED_68FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_68FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_69FF.S b/vm/mterp/x86-atom/OP_UNUSED_69FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_69FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_6AFF.S b/vm/mterp/x86-atom/OP_UNUSED_6AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_6AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_6BFF.S b/vm/mterp/x86-atom/OP_UNUSED_6BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_6BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_6CFF.S b/vm/mterp/x86-atom/OP_UNUSED_6CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_6CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_6DFF.S b/vm/mterp/x86-atom/OP_UNUSED_6DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_6DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_6EFF.S b/vm/mterp/x86-atom/OP_UNUSED_6EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_6EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_6FFF.S b/vm/mterp/x86-atom/OP_UNUSED_6FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_6FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_70FF.S b/vm/mterp/x86-atom/OP_UNUSED_70FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_70FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_71FF.S b/vm/mterp/x86-atom/OP_UNUSED_71FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_71FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_72FF.S b/vm/mterp/x86-atom/OP_UNUSED_72FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_72FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_73.S b/vm/mterp/x86-atom/OP_UNUSED_73.S
new file mode 100644
index 0000000..9808865
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_73.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_73.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_73FF.S b/vm/mterp/x86-atom/OP_UNUSED_73FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_73FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_74FF.S b/vm/mterp/x86-atom/OP_UNUSED_74FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_74FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_75FF.S b/vm/mterp/x86-atom/OP_UNUSED_75FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_75FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_76FF.S b/vm/mterp/x86-atom/OP_UNUSED_76FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_76FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_77FF.S b/vm/mterp/x86-atom/OP_UNUSED_77FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_77FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_78FF.S b/vm/mterp/x86-atom/OP_UNUSED_78FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_78FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_79.S b/vm/mterp/x86-atom/OP_UNUSED_79.S
new file mode 100644
index 0000000..6ebd8ff
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_79.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_79.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_79FF.S b/vm/mterp/x86-atom/OP_UNUSED_79FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_79FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7A.S b/vm/mterp/x86-atom/OP_UNUSED_7A.S
new file mode 100644
index 0000000..79a22d0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7A.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_UNUSED_7A.S
+    */
+
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7AFF.S b/vm/mterp/x86-atom/OP_UNUSED_7AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7BFF.S b/vm/mterp/x86-atom/OP_UNUSED_7BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7CFF.S b/vm/mterp/x86-atom/OP_UNUSED_7CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7DFF.S b/vm/mterp/x86-atom/OP_UNUSED_7DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7EFF.S b/vm/mterp/x86-atom/OP_UNUSED_7EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_7FFF.S b/vm/mterp/x86-atom/OP_UNUSED_7FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_7FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_80FF.S b/vm/mterp/x86-atom/OP_UNUSED_80FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_80FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_81FF.S b/vm/mterp/x86-atom/OP_UNUSED_81FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_81FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_82FF.S b/vm/mterp/x86-atom/OP_UNUSED_82FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_82FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_83FF.S b/vm/mterp/x86-atom/OP_UNUSED_83FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_83FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_84FF.S b/vm/mterp/x86-atom/OP_UNUSED_84FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_84FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_85FF.S b/vm/mterp/x86-atom/OP_UNUSED_85FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_85FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_86FF.S b/vm/mterp/x86-atom/OP_UNUSED_86FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_86FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_87FF.S b/vm/mterp/x86-atom/OP_UNUSED_87FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_87FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_88FF.S b/vm/mterp/x86-atom/OP_UNUSED_88FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_88FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_89FF.S b/vm/mterp/x86-atom/OP_UNUSED_89FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_89FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_8AFF.S b/vm/mterp/x86-atom/OP_UNUSED_8AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_8AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_8BFF.S b/vm/mterp/x86-atom/OP_UNUSED_8BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_8BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_8CFF.S b/vm/mterp/x86-atom/OP_UNUSED_8CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_8CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_8DFF.S b/vm/mterp/x86-atom/OP_UNUSED_8DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_8DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_8EFF.S b/vm/mterp/x86-atom/OP_UNUSED_8EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_8EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_8FFF.S b/vm/mterp/x86-atom/OP_UNUSED_8FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_8FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_90FF.S b/vm/mterp/x86-atom/OP_UNUSED_90FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_90FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_91FF.S b/vm/mterp/x86-atom/OP_UNUSED_91FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_91FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_92FF.S b/vm/mterp/x86-atom/OP_UNUSED_92FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_92FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_93FF.S b/vm/mterp/x86-atom/OP_UNUSED_93FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_93FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_94FF.S b/vm/mterp/x86-atom/OP_UNUSED_94FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_94FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_95FF.S b/vm/mterp/x86-atom/OP_UNUSED_95FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_95FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_96FF.S b/vm/mterp/x86-atom/OP_UNUSED_96FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_96FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_97FF.S b/vm/mterp/x86-atom/OP_UNUSED_97FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_97FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_98FF.S b/vm/mterp/x86-atom/OP_UNUSED_98FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_98FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_99FF.S b/vm/mterp/x86-atom/OP_UNUSED_99FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_99FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_9AFF.S b/vm/mterp/x86-atom/OP_UNUSED_9AFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_9AFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_9BFF.S b/vm/mterp/x86-atom/OP_UNUSED_9BFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_9BFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_9CFF.S b/vm/mterp/x86-atom/OP_UNUSED_9CFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_9CFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_9DFF.S b/vm/mterp/x86-atom/OP_UNUSED_9DFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_9DFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_9EFF.S b/vm/mterp/x86-atom/OP_UNUSED_9EFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_9EFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_9FFF.S b/vm/mterp/x86-atom/OP_UNUSED_9FFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_9FFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A0FF.S b/vm/mterp/x86-atom/OP_UNUSED_A0FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A0FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A1FF.S b/vm/mterp/x86-atom/OP_UNUSED_A1FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A1FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A2FF.S b/vm/mterp/x86-atom/OP_UNUSED_A2FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A2FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A3FF.S b/vm/mterp/x86-atom/OP_UNUSED_A3FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A3FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A4FF.S b/vm/mterp/x86-atom/OP_UNUSED_A4FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A4FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A5FF.S b/vm/mterp/x86-atom/OP_UNUSED_A5FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A5FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A6FF.S b/vm/mterp/x86-atom/OP_UNUSED_A6FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A6FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A7FF.S b/vm/mterp/x86-atom/OP_UNUSED_A7FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A7FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A8FF.S b/vm/mterp/x86-atom/OP_UNUSED_A8FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A8FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_A9FF.S b/vm/mterp/x86-atom/OP_UNUSED_A9FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_A9FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_AAFF.S b/vm/mterp/x86-atom/OP_UNUSED_AAFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_AAFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_ABFF.S b/vm/mterp/x86-atom/OP_UNUSED_ABFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_ABFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_ACFF.S b/vm/mterp/x86-atom/OP_UNUSED_ACFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_ACFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_ADFF.S b/vm/mterp/x86-atom/OP_UNUSED_ADFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_ADFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_AEFF.S b/vm/mterp/x86-atom/OP_UNUSED_AEFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_AEFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_AFFF.S b/vm/mterp/x86-atom/OP_UNUSED_AFFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_AFFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B0FF.S b/vm/mterp/x86-atom/OP_UNUSED_B0FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B0FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B1FF.S b/vm/mterp/x86-atom/OP_UNUSED_B1FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B1FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B2FF.S b/vm/mterp/x86-atom/OP_UNUSED_B2FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B2FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B3FF.S b/vm/mterp/x86-atom/OP_UNUSED_B3FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B3FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B4FF.S b/vm/mterp/x86-atom/OP_UNUSED_B4FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B4FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B5FF.S b/vm/mterp/x86-atom/OP_UNUSED_B5FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B5FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B6FF.S b/vm/mterp/x86-atom/OP_UNUSED_B6FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B6FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B7FF.S b/vm/mterp/x86-atom/OP_UNUSED_B7FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B7FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B8FF.S b/vm/mterp/x86-atom/OP_UNUSED_B8FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B8FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_B9FF.S b/vm/mterp/x86-atom/OP_UNUSED_B9FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_B9FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_BAFF.S b/vm/mterp/x86-atom/OP_UNUSED_BAFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_BAFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_BBFF.S b/vm/mterp/x86-atom/OP_UNUSED_BBFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_BBFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_BCFF.S b/vm/mterp/x86-atom/OP_UNUSED_BCFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_BCFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_BDFF.S b/vm/mterp/x86-atom/OP_UNUSED_BDFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_BDFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_BEFF.S b/vm/mterp/x86-atom/OP_UNUSED_BEFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_BEFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_BFFF.S b/vm/mterp/x86-atom/OP_UNUSED_BFFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_BFFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C0FF.S b/vm/mterp/x86-atom/OP_UNUSED_C0FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C0FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C1FF.S b/vm/mterp/x86-atom/OP_UNUSED_C1FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C1FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C2FF.S b/vm/mterp/x86-atom/OP_UNUSED_C2FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C2FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C3FF.S b/vm/mterp/x86-atom/OP_UNUSED_C3FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C3FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C4FF.S b/vm/mterp/x86-atom/OP_UNUSED_C4FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C4FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C5FF.S b/vm/mterp/x86-atom/OP_UNUSED_C5FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C5FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C6FF.S b/vm/mterp/x86-atom/OP_UNUSED_C6FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C6FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C7FF.S b/vm/mterp/x86-atom/OP_UNUSED_C7FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C7FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C8FF.S b/vm/mterp/x86-atom/OP_UNUSED_C8FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C8FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_C9FF.S b/vm/mterp/x86-atom/OP_UNUSED_C9FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_C9FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_CAFF.S b/vm/mterp/x86-atom/OP_UNUSED_CAFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_CAFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_CBFF.S b/vm/mterp/x86-atom/OP_UNUSED_CBFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_CBFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_CCFF.S b/vm/mterp/x86-atom/OP_UNUSED_CCFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_CCFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_CDFF.S b/vm/mterp/x86-atom/OP_UNUSED_CDFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_CDFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_CEFF.S b/vm/mterp/x86-atom/OP_UNUSED_CEFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_CEFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_CFFF.S b/vm/mterp/x86-atom/OP_UNUSED_CFFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_CFFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D0FF.S b/vm/mterp/x86-atom/OP_UNUSED_D0FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D0FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D1FF.S b/vm/mterp/x86-atom/OP_UNUSED_D1FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D1FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D2FF.S b/vm/mterp/x86-atom/OP_UNUSED_D2FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D2FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D3FF.S b/vm/mterp/x86-atom/OP_UNUSED_D3FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D3FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D4FF.S b/vm/mterp/x86-atom/OP_UNUSED_D4FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D4FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D5FF.S b/vm/mterp/x86-atom/OP_UNUSED_D5FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D5FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D6FF.S b/vm/mterp/x86-atom/OP_UNUSED_D6FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D6FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D7FF.S b/vm/mterp/x86-atom/OP_UNUSED_D7FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D7FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D8FF.S b/vm/mterp/x86-atom/OP_UNUSED_D8FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D8FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_D9FF.S b/vm/mterp/x86-atom/OP_UNUSED_D9FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_D9FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_DAFF.S b/vm/mterp/x86-atom/OP_UNUSED_DAFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_DAFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_DBFF.S b/vm/mterp/x86-atom/OP_UNUSED_DBFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_DBFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_DCFF.S b/vm/mterp/x86-atom/OP_UNUSED_DCFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_DCFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_DDFF.S b/vm/mterp/x86-atom/OP_UNUSED_DDFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_DDFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_DEFF.S b/vm/mterp/x86-atom/OP_UNUSED_DEFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_DEFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_DFFF.S b/vm/mterp/x86-atom/OP_UNUSED_DFFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_DFFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E0FF.S b/vm/mterp/x86-atom/OP_UNUSED_E0FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E0FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E1FF.S b/vm/mterp/x86-atom/OP_UNUSED_E1FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E1FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E2FF.S b/vm/mterp/x86-atom/OP_UNUSED_E2FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E2FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E3FF.S b/vm/mterp/x86-atom/OP_UNUSED_E3FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E3FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E4FF.S b/vm/mterp/x86-atom/OP_UNUSED_E4FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E4FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E5FF.S b/vm/mterp/x86-atom/OP_UNUSED_E5FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E5FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E6FF.S b/vm/mterp/x86-atom/OP_UNUSED_E6FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E6FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E7FF.S b/vm/mterp/x86-atom/OP_UNUSED_E7FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E7FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E8FF.S b/vm/mterp/x86-atom/OP_UNUSED_E8FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E8FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_E9FF.S b/vm/mterp/x86-atom/OP_UNUSED_E9FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_E9FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EAFF.S b/vm/mterp/x86-atom/OP_UNUSED_EAFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_EAFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EBFF.S b/vm/mterp/x86-atom/OP_UNUSED_EBFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_EBFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_ECFF.S b/vm/mterp/x86-atom/OP_UNUSED_ECFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_ECFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EDFF.S b/vm/mterp/x86-atom/OP_UNUSED_EDFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_EDFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EEFF.S b/vm/mterp/x86-atom/OP_UNUSED_EEFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_EEFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_EFFF.S b/vm/mterp/x86-atom/OP_UNUSED_EFFF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_EFFF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_F0FF.S b/vm/mterp/x86-atom/OP_UNUSED_F0FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_F0FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_UNUSED_F1FF.S b/vm/mterp/x86-atom/OP_UNUSED_F1FF.S
new file mode 100644
index 0000000..ebae8b7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_UNUSED_F1FF.S
@@ -0,0 +1 @@
+%include "x86-atom/unused.S"
diff --git a/vm/mterp/x86-atom/OP_USHR_INT.S b/vm/mterp/x86-atom/OP_USHR_INT.S
new file mode 100644
index 0000000..a1d91c6
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_USHR_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_INT.S
+    */
+
+%include "x86-atom/binopS.S" {"instr":"shr     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_USHR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_USHR_INT_2ADDR.S
new file mode 100644
index 0000000..9ee9c66
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_USHR_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_INT_2ADDR.S
+    */
+
+%include "x86-atom/binopS2addr.S" {"instr":"shr     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_USHR_INT_LIT8.S b/vm/mterp/x86-atom/OP_USHR_INT_LIT8.S
new file mode 100644
index 0000000..5a54df7
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_USHR_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8S.S" {"instr":"shr     %cl, %edx"}
diff --git a/vm/mterp/x86-atom/OP_USHR_LONG.S b/vm/mterp/x86-atom/OP_USHR_LONG.S
new file mode 100644
index 0000000..1c404f0
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_USHR_LONG.S
@@ -0,0 +1,39 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_LONG.S
+    *
+    * Code: Performs an unsigned shift right long operation. Uses no substitutions.
+    *
+    * For: ushr-long
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where one is the shift amount and the other is the value to shift.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_CC    1, %eax                 # %eax<- CC
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movsd        .LshiftMask, %xmm2     # %xmm2<- mask for the shift bits
+    movss       (rFP, %eax, 4), %xmm0   # %xmm0<- vCC
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    movsd       (rFP, %edx, 4), %xmm1   # %xmm1<- vBB
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vBB
+    movsd       %xmm1, (rFP, rINST, 4)  # vAA<- shifted vBB
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
new file mode 100644
index 0000000..31cb5bc
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_USHR_LONG_2ADDR.S
@@ -0,0 +1,41 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_USHR_LONG_2ADDR.S
+    *
+    * Code: Performs an unsigned shift right long operation. Uses no substiutions.
+    *
+    * For: ushr-long/2addr
+    *
+    * Description: Perform a binary shift operation using two source registers
+    *              where the fist is the value to shift and the second is the
+    *              shift amount. Store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    movq        .LshiftMask, %xmm2      # %xmm2<- mask for the shift bits
+    movss       (rFP, %edx, 4),  %xmm0  # %xmm0<- vB
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vA
+    pand        %xmm2, %xmm0            # %xmm0<- masked shift bits
+    psrlq       %xmm0, %xmm1            # %xmm1<- shifted vA
+    movq        %xmm1, (rFP, rINST, 4)  # vA<- shifted vA
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/OP_XOR_INT.S b/vm/mterp/x86-atom/OP_XOR_INT.S
new file mode 100644
index 0000000..d36b83f
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_XOR_INT.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT.S
+    */
+
+%include "x86-atom/binop.S" {"instr":"xor     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_INT_2ADDR.S b/vm/mterp/x86-atom/OP_XOR_INT_2ADDR.S
new file mode 100644
index 0000000..0bab865
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_XOR_INT_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT_2ADDR.S
+    */
+
+%include "x86-atom/binop2addr.S" {"instr":"xor     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_INT_LIT16.S b/vm/mterp/x86-atom/OP_XOR_INT_LIT16.S
new file mode 100644
index 0000000..a26bcc5
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_XOR_INT_LIT16.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT_LIT16.S
+    */
+
+%include "x86-atom/binopLit16.S" {"instr":"xor     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_INT_LIT8.S b/vm/mterp/x86-atom/OP_XOR_INT_LIT8.S
new file mode 100644
index 0000000..9a3c8e3
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_XOR_INT_LIT8.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_INT_LIT8.S
+    */
+
+%include "x86-atom/binopLit8.S" {"instr":"xor     %edx, %ecx"}
diff --git a/vm/mterp/x86-atom/OP_XOR_LONG.S b/vm/mterp/x86-atom/OP_XOR_LONG.S
new file mode 100644
index 0000000..58a8384
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_XOR_LONG.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_LONG.S
+    */
+
+%include "x86-atom/binopWide.S" {"instr":"pxor   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/OP_XOR_LONG_2ADDR.S b/vm/mterp/x86-atom/OP_XOR_LONG_2ADDR.S
new file mode 100644
index 0000000..6b42cbd
--- /dev/null
+++ b/vm/mterp/x86-atom/OP_XOR_LONG_2ADDR.S
@@ -0,0 +1,20 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: OP_XOR_LONG_2ADDR.S
+    */
+
+%include "x86-atom/binopWide2addr.S" {"instr":"pxor   %xmm1, %xmm0"}
diff --git a/vm/mterp/x86-atom/TODO.txt b/vm/mterp/x86-atom/TODO.txt
new file mode 100644
index 0000000..228d3e2
--- /dev/null
+++ b/vm/mterp/x86-atom/TODO.txt
@@ -0,0 +1,36 @@
+Items requiring attention:
+
+(hi) Add gc card marking to aput/iput/sput/new_filled_array
+(hi) Correct stack overflow handling (dvmCleanupStackOverflow takes an
+     additional argument now)
+(hi) WITH_DEBUGGER and WITH_PROFILER are no longer defined (but are
+     assumed to be enabled)
+(hi) Implement OP_DISPATCH_FF for real. (Right now it's treated as
+     an unused instruction.)
+(hi) Rename dvmJitGetCodeAddr to dvmJitGetTraceAddr.
+(hi) Remove references to rGLUE and replace with rSELF
+(hi) Rework interpreter to co-exist the new switching model which
+     elminiates a separate debug interpreter.  Needs a dedicated
+     rIBASE register (or alternate switching model with variable
+     handler base).
+(hi) Add dvmReportXXXX()" calls in footer.cpp to support profilers &
+     debuggers.
+(hi) Set self->debugIsMethodEntry in invoke code.
+
+(md) Add implementations for jumbo opcodes (40 instructions) and
+     their volatile variants (13 instructions)
+(md) Correct OP_MONITOR_EXIT (need to adjust PC before throw)
+(md) OP_THROW needs to export the PC
+(md) Use dvmThrowArrayIndexOutOfBoundsException(length, index) for
+     array bounds errors.
+(md) Use dvmThrowClassCastException(actual, desired) for class cast errors.
+(md) Use dvmThrowArrayStoreExceptionIncompatibleElement(actual, desired)
+     for array store errors.
+(md) Use dvmThrowNegativeArraySizeException(len) forarray alloc errors
+(md) Replace any remaining use of dvmThrowException with proper helper function
+
+(lo) Implement OP_BREAKPOINT
+(lo) Implement OP_*_VOLATILE (12 instructions)
+(lo) Implement OP_RETURN_VOID_BARRIER
+(lo) Implement OP_INVOKE_OBJECT_INIT
+(lo) Implement dvmJitScanAllClassPointers
diff --git a/vm/mterp/x86-atom/bincmp.S b/vm/mterp/x86-atom/bincmp.S
new file mode 100644
index 0000000..a8fbed5
--- /dev/null
+++ b/vm/mterp/x86-atom/bincmp.S
@@ -0,0 +1,44 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: bincmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform.
+    *
+    * For: if-eq, if-ge, if-gt, if-le, if-lt, if-ne
+    *
+    * Description: Branch to the given destination if the comparison
+    *              test between the given registers values is true.
+    *
+    * Format: B|A|op CCCC (22t)
+    *
+    * Syntax: op vA, vB, +CCCC
+    */
+
+    movl        rINST,  %eax            # %eax<- BA
+    andl        $$15, rINST             # rINST<- A
+    shr         $$4, %eax               # %eax<- B
+    GET_VREG    rINST                   # rINST<- vA
+    movl        $$4, %edx               # %edx<- 4
+    cmp         (rFP, %eax, 4), rINST   # compare vA and vB
+    j${revcmp}  1f                      # goto next instruction if reverse
+                                        # comparison is true
+    FETCHs      1, %edx                 # %edx<- +CCCC, Branch offset
+    sal         $$1, %edx
+    js          common_periodicChecks_backwardBranch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
diff --git a/vm/mterp/x86-atom/binop.S b/vm/mterp/x86-atom/binop.S
new file mode 100644
index 0000000..1706b72
--- /dev/null
+++ b/vm/mterp/x86-atom/binop.S
@@ -0,0 +1,39 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    * For: add-int, and-int, mul-int, or-int, sub-int, xor-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    GET_VREG    %edx                    # %edx<- vCC
+    $instr                              # %ecx<- vBB op vCC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binop2addr.S b/vm/mterp/x86-atom/binop2addr.S
new file mode 100644
index 0000000..b26b25a
--- /dev/null
+++ b/vm/mterp/x86-atom/binop2addr.S
@@ -0,0 +1,45 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binop2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%ecx = %ecx op %edx".
+    *
+    * For: add-int/2addr, and-int/2addr, mul-int/2addr, or-int/2addr,
+    *      sub-int/2addr, xor-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    andl        $$15, rINST             # rINST<- A
+    movl        rINST, %ecx             # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vB
+    GET_VREG    %ecx                    # %ecx<- vA
+    $instr                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
+
+
diff --git a/vm/mterp/x86-atom/binopD.S b/vm/mterp/x86-atom/binopD.S
new file mode 100644
index 0000000..20a2e9a
--- /dev/null
+++ b/vm/mterp/x86-atom/binopD.S
@@ -0,0 +1,61 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopD.S
+    *
+    * Code: 32-bit integer divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int, rem-int
+    *
+    * Description: Perform a binary operation on two source
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+%default {"div":"1"}
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    GET_VREG    %eax                    # %eax<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    cmp         $$0, %ecx               # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    cmpl        $$-1, %ecx              # handle -1 special case divide error
+    jne         .L${opcode}_noerror
+    cmpl        $$0x80000000,%eax       # handle min int special case divide error
+    je         .L${opcode}_break
+.L${opcode}_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    .if  $div
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .L${opcode}_break2
+%break
+.L${opcode}_break:
+    .if  $div
+    movl        $$0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $$0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.L${opcode}_break2:
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/binopD2addr.S b/vm/mterp/x86-atom/binopD2addr.S
new file mode 100644
index 0000000..392b46b
--- /dev/null
+++ b/vm/mterp/x86-atom/binopD2addr.S
@@ -0,0 +1,68 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopD2addr.S
+    *
+    * Code: 32-bit "/2addr" integer divde operation. If "div"
+    *       is set, the code returns the quotient, else it returns
+    *       the remainder. Also, a divide-by-zero check is done.
+    *
+    * For: div-int/2addr, rem-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+%default {"div":"1"}
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $$15, rINST             # rINST<- A, to be used as dest
+    movl        rINST, %eax             # %eax<- A
+    shr         $$4, %ecx               # %ecx<- B
+    GET_VREG    %eax                    # %eax<- vA
+    GET_VREG    %ecx                    # %edx<- vB
+    cmp         $$0, %ecx               # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    cmpl        $$-1, %ecx              # handle -1 special case divide error
+    jne         .L${opcode}_noerror
+    cmpl        $$0x80000000,%eax       # handle min int special case divide error
+    je         .L${opcode}_break
+.L${opcode}_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+     .if  $div
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .L${opcode}_break2
+    #FFETCH_ADV 1, %edx  # %ecx<- next instruction hi; fetch, advance
+    #FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
+%break
+.L${opcode}_break:
+    .if  $div
+    movl        $$0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $$0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.L${opcode}_break2:
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
+
diff --git a/vm/mterp/x86-atom/binopDLit16.S b/vm/mterp/x86-atom/binopDLit16.S
new file mode 100644
index 0000000..3e67d0a
--- /dev/null
+++ b/vm/mterp/x86-atom/binopDLit16.S
@@ -0,0 +1,66 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDLit16.S
+    *
+    * Code: 32-bit "lit16" divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int/lit16, rem-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+%default {"div":"1"}
+
+    movl        rINST, %eax             # %eax<- BA
+    shr         $$4, %eax               # %eax<- B
+    FETCHs      1, %ecx                 # %ecx<- +CCCC, sign-extended literal
+    cmp         $$0, %ecx               # check for divide by zero
+    GET_VREG    %eax                    # %eax<- vB
+    je          common_errDivideByZero  # handle divide by zero
+    andl        $$15, rINST             # rINST<- A
+    cmpl        $$-1, %ecx              # handle -1 special case divide error
+    jne         .L${opcode}_noerror
+    cmpl        $$0x80000000,%eax       # handle min int special case divide error
+    je         .L${opcode}_break
+.L${opcode}_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    #FFETCH_ADV 2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    .if  $div
+    SET_VREG    %eax rINST              # vA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vA<- %edx (remainder)
+    .endif
+    jmp         .L${opcode}_break2
+
+%break
+.L${opcode}_break:
+    .if  $div
+    movl        $$0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $$0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+.L${opcode}_break2:
+
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/binopDLit8.S b/vm/mterp/x86-atom/binopDLit8.S
new file mode 100644
index 0000000..f197714
--- /dev/null
+++ b/vm/mterp/x86-atom/binopDLit8.S
@@ -0,0 +1,65 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. If "div" is set, the code
+    *       returns the quotient, else it returns the remainder.
+    *       Also, a divide-by-zero check is done.
+    *
+    * For: div-int/lit8, rem-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signe extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+%default {"div":"1"}
+
+    FETCH_BB    1, %eax                 # %eax<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    cmp         $$0, %ecx               # check for divide by zero
+    GET_VREG    %eax                    # %eax<- vBB
+    je          common_errDivideByZero  # handle divide by zero
+
+    cmpl        $$-1, %ecx              # handle -1 special case divide error
+    jne         .L${opcode}_noerror
+    cmpl        $$0x80000000,%eax       # handle min int special case divide error
+    je         .L${opcode}_break
+.L${opcode}_noerror:
+    cdq                                 # sign-extend %eax to %edx
+    idiv        %ecx                    # divide %edx:%eax by %ecx
+    #FFETCH_ADV 2, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    .if  $div
+    SET_VREG    %eax rINST              # vAA<- %eax (quotient)
+    .else
+    SET_VREG    %edx rINST              # vAA<- %edx (remainder)
+    .endif
+    jmp         .L${opcode}_break2
+%break
+.L${opcode}_break:
+    .if  $div
+    movl        $$0x80000000, (rFP, rINST, 4) # vAA<- min int
+    .else
+    movl        $$0, (rFP, rINST, 4)    # vAA<- 0
+    .endif
+
+.L${opcode}_break2:
+    FINISH      2                       # jump to next instruction
+    #FGETOP_JMP 2, %ecx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopDivRemLong.S b/vm/mterp/x86-atom/binopDivRemLong.S
new file mode 100644
index 0000000..93ed4f8
--- /dev/null
+++ b/vm/mterp/x86-atom/binopDivRemLong.S
@@ -0,0 +1,52 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDivRemLong.S
+    *
+    * Code: 64-bit long divide operation. Variable
+    *       "func" defines the function called to do the operation.
+    *
+    * For: div-long, rem-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+%default {"func":"__divdi3"}
+
+    FETCH_CC    1, %edx                 # %edx<- CC
+    movl        (rFP, %edx, 4), %eax    # %eax<- vCC
+    movl        4(rFP, %edx, 4), %ecx   # %ecx<- vCC+1
+    movl        %eax, -8(%esp)          # push arg vCC
+    or          %ecx, %eax              # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    FETCH_BB    1, %edx                 # %edx<- BB
+    movl        %ecx, -4(%esp)          # push arg vCC+1
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vBB,vBB+1
+    jmp         .L${opcode}_finish
+%break
+.L${opcode}_finish:
+    movq        %xmm0, -16(%esp)        # push arg vBB,vBB+1
+    lea         -16(%esp), %esp
+    call        $func                   # call func
+    lea         16(%esp), %esp
+    movl        %eax, (rFP, rINST, 4)   # vAA<- return low
+    movl        %edx, 4(rFP, rINST, 4)  # vAA+1<- return high
+    FINISH      2                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/binopDivRemLong2Addr.S b/vm/mterp/x86-atom/binopDivRemLong2Addr.S
new file mode 100644
index 0000000..aa427de
--- /dev/null
+++ b/vm/mterp/x86-atom/binopDivRemLong2Addr.S
@@ -0,0 +1,54 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopDivRemLong2Addr.S
+    *
+    * Code: 64-bit "/2addr" long divide operation. Variable
+    *       "func" defines the function called to do the operation.
+    *
+    * For: div-long/2addr, rem-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register.
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+%default {"func":"__divdi3"}
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, %edx               # %edx<- B
+    and         $$15, rINST             # rINST<- A
+    movl        (rFP, %edx, 4), %eax    # %eax<- vB
+    movl        %eax, -12(%esp)         # push arg vB
+    movl        4(rFP, %edx, 4), %ecx   # %ecx<- vB+1
+    or          %ecx, %eax              # check for divide by zero
+    je          common_errDivideByZero  # handle divide by zero
+    movl        %ecx, -8(%esp)          # push arg vB+1
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vA,vA+1
+    jmp         .L${opcode}_break
+%break
+.L${opcode}_break:
+    movq        %xmm0, -20(%esp)        # push arg vA, vA+1
+    lea         -20(%esp), %esp
+    call        $func                   # call func
+    lea         20(%esp), %esp
+    movl        %eax, (rFP, rINST, 4)   # vA<- return low
+    movl        %edx, 4(rFP, rINST, 4)  # vA<- return high
+    FFETCH_ADV  1, %ecx                 # %ecx<- next instruction hi; fetch, advance
+    FGETOP_JMP 1, %ecx                  # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopF.S b/vm/mterp/x86-atom/binopF.S
new file mode 100644
index 0000000..0c07b97
--- /dev/null
+++ b/vm/mterp/x86-atom/binopF.S
@@ -0,0 +1,39 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-float, mul-float, sub-float
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<-vBB
+    movss       (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    $instr                              # %xmm0<- vBB op vCC
+    movss       %xmm0, (rFP, rINST, 4)  # vAA<- %xmm0; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopF2addr.S b/vm/mterp/x86-atom/binopF2addr.S
new file mode 100644
index 0000000..135ca0c
--- /dev/null
+++ b/vm/mterp/x86-atom/binopF2addr.S
@@ -0,0 +1,41 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopF2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0 = %xmm0 op %xmm1".
+    *
+    * For: add-float/2addr, mul-float/2addr, sub-float/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    andl        $$15, %ecx              # %ecx<- A
+    shr         $$4, rINST              # rINST<- B
+    FFETCH_ADV  1, %edx                 # %ecx<- next instruction hi; fetch, advance
+    movss       (rFP, %ecx, 4), %xmm0   # %xmm0<- vA
+    movss       (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    $instr                              # %xmm0<- vA op vB
+    movss       %xmm0, (rFP, %ecx, 4)   # vA<- %xmm0; result
+    FGETOP_JMP  1, %edx                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopLit16.S b/vm/mterp/x86-atom/binopLit16.S
new file mode 100644
index 0000000..4972b4d
--- /dev/null
+++ b/vm/mterp/x86-atom/binopLit16.S
@@ -0,0 +1,43 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit16.S
+    *
+    * Code: 32-bit "lit16" operation. Provides an "instr" line to
+    *       specify an instruction that performs "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit16, and-int/lit16, mul-int/lit16, or-int/lit16
+    *      xor-int/lit16
+    *
+    * Description: Perform a binary operation on a register and a
+    *              sign extended 16-bit literal value and store the
+    *              result in a destination register.
+    *
+    * Format: B|A|op CCCC (22s)
+    *
+    * Syntax: op vA, vB, #+CCCC
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $$4, %ecx               # %ecx<- B
+    andl        $$15, rINST             # rINST<- A
+    FETCHs      1, %edx                 # %edx<- +CCCC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    $instr                              # %ecx<- vA op vB
+    SET_VREG    %ecx, rINST             # vA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopLit8.S b/vm/mterp/x86-atom/binopLit8.S
new file mode 100644
index 0000000..239e443
--- /dev/null
+++ b/vm/mterp/x86-atom/binopLit8.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs  "%ecx = %ecx op %edx"
+    *
+    *
+    * For: add-int/lit8, and-int/lit8, mul-int/lit8, or-int/lit8
+    *      xor-int/lit8
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CCs   1, %edx                 # %edx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vBB
+    $instr                              # %ecx<- vBB op +CC
+    SET_VREG    %ecx, rINST             # vAA<- %ecx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopLit8S.S b/vm/mterp/x86-atom/binopLit8S.S
new file mode 100644
index 0000000..c0360aa
--- /dev/null
+++ b/vm/mterp/x86-atom/binopLit8S.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopLit8S.S
+    *
+    * Code: 32-bit "lit8" divide operation. Provides an "instr" line
+    *       to specify an instruction that performs "%edx = %edx op %cl"
+    *
+    *
+    * For: shl-int/lit8, shr-int/lit8, ushr-int/lit8
+    *
+    *
+    * Description: Perform a binary operation on a register and a
+    *              signed extended 8-bit literal value
+    *
+    * Format: AA|op CC|BB (22b)
+    *
+    * Syntax: op vAA, vBB, #+CC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CCs   1, %ecx                 # %ecx<- +CC, sign-extended literal
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    $instr                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopS.S b/vm/mterp/x86-atom/binopS.S
new file mode 100644
index 0000000..b09f5c2
--- /dev/null
+++ b/vm/mterp/x86-atom/binopS.S
@@ -0,0 +1,39 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS.S
+    *
+    * Code: Generic 32-bit binary operation.  Provides an "instr" line to
+    *       specify an instruction that performs "%edx = %edx op %cl"
+    *
+    * For: shl-int, shr-int, ushr-int
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %edx                 # %edx<- BB
+    FETCH_CC    1, %ecx                 # %ecx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %edx                    # %edx<- vBB
+    GET_VREG    %ecx                    # %ecx<- vCC
+    $instr                              # %edx<- vBB op +CC
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopS2addr.S b/vm/mterp/x86-atom/binopS2addr.S
new file mode 100644
index 0000000..0c3c29a
--- /dev/null
+++ b/vm/mterp/x86-atom/binopS2addr.S
@@ -0,0 +1,42 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopS2addr.S
+    *
+    * Code: Generic 32-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%edx = %edx op %cl".
+    *
+    * For: shl-int/2addr, shr-int/2addr, ushr-int/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %ecx             # %ecx<- BA
+    shr         $$4, %ecx               # %ecx<- B
+    andl        $$15, rINST             # rINST<- A
+    movl        rINST, %edx             # %edx<- A
+    FFETCH_ADV  1, %eax                 # %ecx<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    GET_VREG    %edx                    # %edx<- vA
+    $instr                              # %edx<- vA op vB
+    SET_VREG    %edx, rINST             # vAA<- %edx; result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopWide.S b/vm/mterp/x86-atom/binopWide.S
new file mode 100644
index 0000000..3cd3e52
--- /dev/null
+++ b/vm/mterp/x86-atom/binopWide.S
@@ -0,0 +1,40 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide.S
+    *
+    * Code: Generic 64-bit binary operation.  Provides an "instr" variable to
+    *       specify an instruction that performs "%xmm0 = %xmm0 op %xmm1"
+    *
+    * For: add-double, add-long, and-long, mul-double, or-long,
+    *      sub-double, sub-long, xor-long
+    *
+    * Description: Perform a binary operation on two source registers
+    *              and store the result in a destination register.
+    *
+    * Format: AA|op CC|BB (23x)
+    *
+    * Syntax: op vAA, vBB, vCC
+    */
+
+    FETCH_BB    1, %ecx                 # %ecx<- BB
+    FETCH_CC    1, %edx                 # %edx<- CC
+    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, %ecx, 4), %xmm0   # %xmm0<- vBB
+    movq        (rFP, %edx, 4), %xmm1   # %xmm1<- vCC
+    $instr                              # %xmm0<- vBB op vCC
+    movq        %xmm0, (rFP, rINST, 4)  # vAA<- %ecx
+    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/binopWide2addr.S b/vm/mterp/x86-atom/binopWide2addr.S
new file mode 100644
index 0000000..f9aa29c
--- /dev/null
+++ b/vm/mterp/x86-atom/binopWide2addr.S
@@ -0,0 +1,41 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: binopWide2addr.S
+    *
+    * Code: Generic 64-bit "/2addr" binary operation.  Provides an
+    *       "instr" line to specify an instruction that performs
+    *       "%xmm0= %xmm0 op %xmm1".
+    *
+    * For: add-double/2addr, add-long/2addr, and-long/2addr, mul-long/2addr,
+    *      or-long/2addr, sub-double/2addr, sub-long/2addr, xor-long/2addr
+    *
+    * Description: Perform a binary operation on two sources registers
+    *              and store the result in the first source register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+    movl        rINST, %edx             # %edx<- BA
+    shr         $$4, rINST              # rINST<- B
+    andl        $$15, %edx              # %edx<- A
+    movq        (rFP, rINST, 4), %xmm1  # %xmm1<- vB
+    movq        (rFP, %edx, 4), %xmm0   # %xmm0<- vA
+    $instr                              # %xmm0<- vA op vB
+    movq        %xmm0, (rFP, %edx, 4)   # vA<- %xmm0; result
+    FINISH      1                       # jump to next instruction
diff --git a/vm/mterp/x86-atom/entry.S b/vm/mterp/x86-atom/entry.S
new file mode 100644
index 0000000..38bf742
--- /dev/null
+++ b/vm/mterp/x86-atom/entry.S
@@ -0,0 +1,384 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: entry.S
+    */
+
+#define ASSIST_DEBUGGER 1
+    .text
+    .align      2
+    .global     dvmMterpStdRun
+    .type       dvmMterpStdRun, %function
+
+   /*
+    * Save registers, initialize sp and fp.
+    * On entry:
+    *     bool MterpGlue(glue *)
+    */
+
+    .macro      MTERP_ENTRY
+    movl        4(%esp), %ecx           # get first argument
+    movl        %ebp, -4(%esp)          # save caller base pointer
+    movl        %ebx, -8(%esp)          # save %ebx
+    movl        %esi, -12(%esp)         # save %esi
+    movl        %edi, -16(%esp)         # save %edi
+    lea         -40(%esp), %ebp         # set callee base pointer
+    lea         -40(%esp), %esp         # set callee stack pointer
+    .endm
+
+   /*
+    * Restore registers.
+    * This function returns a boolean "changeInterp" value.
+    * The return value is from dvmMterpStdBail().
+    */
+
+    .macro      MTERP_EXIT
+    lea         40(%esp), %esp          # correct stack pointer
+    movl        -16(%esp), %edi         # restore %edi
+    movl        -12(%esp), %esi         # restore %esi
+    movl        -8(%esp), %ebx          # restore %ebx
+    movl        -4(%esp), %ebp          # restore caller base pointer
+    ret                                 # return
+    .endm
+
+   /*
+    * DvmMterpStdRun entry point: save stack pointer, setup memory locations, get
+    * entry point, start executing instructions.
+    */
+
+dvmMterpStdRun:
+    MTERP_ENTRY
+    movl        %ecx, rGLUE             # save value for pMterpGlue
+    movl        offGlue_pc(%ecx), rPC   # get program counter
+    cmp         $$kInterpEntryInstr, offGlue_entryPoint(%ecx) # check instruction
+    movl        offGlue_fp(%ecx), rFP   # get frame pointer
+    movl        %esp, offGlue_bailPtr(%ecx) # save SP for eventual return
+    FFETCH      %edx                    # %edx<- opcode
+    jne         .Lnot_instr             # no, handle it
+    FGETOP_JMPa %edx                    # start executing the instruction at rPC
+
+   /*
+    * Not an instruction. Are we returning from a method?
+    */
+
+.Lnot_instr:
+    cmpl        $$kInterpEntryReturn, offGlue_entryPoint(%ecx)
+    je          common_returnFromMethod
+
+   /*
+    * No, are we throwing an exception?
+    */
+
+.Lnot_return:
+    cmpl        $$kInterpEntryThrow, offGlue_entryPoint(%ecx)
+    je          common_exceptionThrown
+
+   /*
+    * No, then we must abort.
+    */
+
+.Lbad_arg:
+    pushl       offGlue_entryPoint(%ecx)
+    movl        $$.LstrBadEntryPoint, -4(%esp)
+    lea         -4(%esp), %esp
+    call        printf
+    lea         8(%esp), %esp
+    call        dvmAbort                # call (void)
+
+   /*
+    * Restore the stack pointer and PC from the save point established on entry and
+    * return to whoever called dvmMterpStdRun.
+    *
+    * On entry:
+    *  4(%esp) MterpGlue* glue
+    *  8(%esp) bool changeInterp
+    */
+
+    .global     dvmMterpStdBail
+    .type       dvmMterpStdBail, %function
+
+dvmMterpStdBail:
+    movl        4(%esp), %ecx           # get first argument
+    movl        8(%esp), %eax           # get second argument
+    movl        offGlue_bailPtr(%ecx), %esp # sp <- saved SP
+    MTERP_EXIT
+
+   /*
+    * String references.
+    */
+
+.LstrBadEntryPoint:
+    .asciz "Bad entry point %d\n"
+
+
+dvmAsmInstructionJmpTable = .LdvmAsmInstructionJmpTable
+.LdvmAsmInstructionJmpTable:
+.long .L_OP_NOP
+.long .L_OP_MOVE
+.long .L_OP_MOVE_FROM16
+.long .L_OP_MOVE_16
+.long .L_OP_MOVE_WIDE
+.long .L_OP_MOVE_WIDE_FROM16
+.long .L_OP_MOVE_WIDE_16
+.long .L_OP_MOVE_OBJECT
+.long .L_OP_MOVE_OBJECT_FROM16
+.long .L_OP_MOVE_OBJECT_16
+.long .L_OP_MOVE_RESULT
+.long .L_OP_MOVE_RESULT_WIDE
+.long .L_OP_MOVE_RESULT_OBJECT
+.long .L_OP_MOVE_EXCEPTION
+.long .L_OP_RETURN_VOID
+.long .L_OP_RETURN
+.long .L_OP_RETURN_WIDE
+.long .L_OP_RETURN_OBJECT
+.long .L_OP_CONST_4
+.long .L_OP_CONST_16
+.long .L_OP_CONST
+.long .L_OP_CONST_HIGH16
+.long .L_OP_CONST_WIDE_16
+.long .L_OP_CONST_WIDE_32
+.long .L_OP_CONST_WIDE
+.long .L_OP_CONST_WIDE_HIGH16
+.long .L_OP_CONST_STRING
+.long .L_OP_CONST_STRING_JUMBO
+.long .L_OP_CONST_CLASS
+.long .L_OP_MONITOR_ENTER
+.long .L_OP_MONITOR_EXIT
+.long .L_OP_CHECK_CAST
+.long .L_OP_INSTANCE_OF
+.long .L_OP_ARRAY_LENGTH
+.long .L_OP_NEW_INSTANCE
+.long .L_OP_NEW_ARRAY
+.long .L_OP_FILLED_NEW_ARRAY
+.long .L_OP_FILLED_NEW_ARRAY_RANGE
+.long .L_OP_FILL_ARRAY_DATA
+.long .L_OP_THROW
+.long .L_OP_GOTO
+.long .L_OP_GOTO_16
+.long .L_OP_GOTO_32
+.long .L_OP_PACKED_SWITCH
+.long .L_OP_SPARSE_SWITCH
+.long .L_OP_CMPL_FLOAT
+.long .L_OP_CMPG_FLOAT
+.long .L_OP_CMPL_DOUBLE
+.long .L_OP_CMPG_DOUBLE
+.long .L_OP_CMP_LONG
+.long .L_OP_IF_EQ
+.long .L_OP_IF_NE
+.long .L_OP_IF_LT
+.long .L_OP_IF_GE
+.long .L_OP_IF_GT
+.long .L_OP_IF_LE
+.long .L_OP_IF_EQZ
+.long .L_OP_IF_NEZ
+.long .L_OP_IF_LTZ
+.long .L_OP_IF_GEZ
+.long .L_OP_IF_GTZ
+.long .L_OP_IF_LEZ
+.long .L_OP_UNUSED_3E
+.long .L_OP_UNUSED_3F
+.long .L_OP_UNUSED_40
+.long .L_OP_UNUSED_41
+.long .L_OP_UNUSED_42
+.long .L_OP_UNUSED_43
+.long .L_OP_AGET
+.long .L_OP_AGET_WIDE
+.long .L_OP_AGET_OBJECT
+.long .L_OP_AGET_BOOLEAN
+.long .L_OP_AGET_BYTE
+.long .L_OP_AGET_CHAR
+.long .L_OP_AGET_SHORT
+.long .L_OP_APUT
+.long .L_OP_APUT_WIDE
+.long .L_OP_APUT_OBJECT
+.long .L_OP_APUT_BOOLEAN
+.long .L_OP_APUT_BYTE
+.long .L_OP_APUT_CHAR
+.long .L_OP_APUT_SHORT
+.long .L_OP_IGET
+.long .L_OP_IGET_WIDE
+.long .L_OP_IGET_OBJECT
+.long .L_OP_IGET_BOOLEAN
+.long .L_OP_IGET_BYTE
+.long .L_OP_IGET_CHAR
+.long .L_OP_IGET_SHORT
+.long .L_OP_IPUT
+.long .L_OP_IPUT_WIDE
+.long .L_OP_IPUT_OBJECT
+.long .L_OP_IPUT_BOOLEAN
+.long .L_OP_IPUT_BYTE
+.long .L_OP_IPUT_CHAR
+.long .L_OP_IPUT_SHORT
+.long .L_OP_SGET
+.long .L_OP_SGET_WIDE
+.long .L_OP_SGET_OBJECT
+.long .L_OP_SGET_BOOLEAN
+.long .L_OP_SGET_BYTE
+.long .L_OP_SGET_CHAR
+.long .L_OP_SGET_SHORT
+.long .L_OP_SPUT
+.long .L_OP_SPUT_WIDE
+.long .L_OP_SPUT_OBJECT
+.long .L_OP_SPUT_BOOLEAN
+.long .L_OP_SPUT_BYTE
+.long .L_OP_SPUT_CHAR
+.long .L_OP_SPUT_SHORT
+.long .L_OP_INVOKE_VIRTUAL
+.long .L_OP_INVOKE_SUPER
+.long .L_OP_INVOKE_DIRECT
+.long .L_OP_INVOKE_STATIC
+.long .L_OP_INVOKE_INTERFACE
+.long .L_OP_UNUSED_73
+.long .L_OP_INVOKE_VIRTUAL_RANGE
+.long .L_OP_INVOKE_SUPER_RANGE
+.long .L_OP_INVOKE_DIRECT_RANGE
+.long .L_OP_INVOKE_STATIC_RANGE
+.long .L_OP_INVOKE_INTERFACE_RANGE
+.long .L_OP_UNUSED_79
+.long .L_OP_UNUSED_7A
+.long .L_OP_NEG_INT
+.long .L_OP_NOT_INT
+.long .L_OP_NEG_LONG
+.long .L_OP_NOT_LONG
+.long .L_OP_NEG_FLOAT
+.long .L_OP_NEG_DOUBLE
+.long .L_OP_INT_TO_LONG
+.long .L_OP_INT_TO_FLOAT
+.long .L_OP_INT_TO_DOUBLE
+.long .L_OP_LONG_TO_INT
+.long .L_OP_LONG_TO_FLOAT
+.long .L_OP_LONG_TO_DOUBLE
+.long .L_OP_FLOAT_TO_INT
+.long .L_OP_FLOAT_TO_LONG
+.long .L_OP_FLOAT_TO_DOUBLE
+.long .L_OP_DOUBLE_TO_INT
+.long .L_OP_DOUBLE_TO_LONG
+.long .L_OP_DOUBLE_TO_FLOAT
+.long .L_OP_INT_TO_BYTE
+.long .L_OP_INT_TO_CHAR
+.long .L_OP_INT_TO_SHORT
+.long .L_OP_ADD_INT
+.long .L_OP_SUB_INT
+.long .L_OP_MUL_INT
+.long .L_OP_DIV_INT
+.long .L_OP_REM_INT
+.long .L_OP_AND_INT
+.long .L_OP_OR_INT
+.long .L_OP_XOR_INT
+.long .L_OP_SHL_INT
+.long .L_OP_SHR_INT
+.long .L_OP_USHR_INT
+.long .L_OP_ADD_LONG
+.long .L_OP_SUB_LONG
+.long .L_OP_MUL_LONG
+.long .L_OP_DIV_LONG
+.long .L_OP_REM_LONG
+.long .L_OP_AND_LONG
+.long .L_OP_OR_LONG
+.long .L_OP_XOR_LONG
+.long .L_OP_SHL_LONG
+.long .L_OP_SHR_LONG
+.long .L_OP_USHR_LONG
+.long .L_OP_ADD_FLOAT
+.long .L_OP_SUB_FLOAT
+.long .L_OP_MUL_FLOAT
+.long .L_OP_DIV_FLOAT
+.long .L_OP_REM_FLOAT
+.long .L_OP_ADD_DOUBLE
+.long .L_OP_SUB_DOUBLE
+.long .L_OP_MUL_DOUBLE
+.long .L_OP_DIV_DOUBLE
+.long .L_OP_REM_DOUBLE
+.long .L_OP_ADD_INT_2ADDR
+.long .L_OP_SUB_INT_2ADDR
+.long .L_OP_MUL_INT_2ADDR
+.long .L_OP_DIV_INT_2ADDR
+.long .L_OP_REM_INT_2ADDR
+.long .L_OP_AND_INT_2ADDR
+.long .L_OP_OR_INT_2ADDR
+.long .L_OP_XOR_INT_2ADDR
+.long .L_OP_SHL_INT_2ADDR
+.long .L_OP_SHR_INT_2ADDR
+.long .L_OP_USHR_INT_2ADDR
+.long .L_OP_ADD_LONG_2ADDR
+.long .L_OP_SUB_LONG_2ADDR
+.long .L_OP_MUL_LONG_2ADDR
+.long .L_OP_DIV_LONG_2ADDR
+.long .L_OP_REM_LONG_2ADDR
+.long .L_OP_AND_LONG_2ADDR
+.long .L_OP_OR_LONG_2ADDR
+.long .L_OP_XOR_LONG_2ADDR
+.long .L_OP_SHL_LONG_2ADDR
+.long .L_OP_SHR_LONG_2ADDR
+.long .L_OP_USHR_LONG_2ADDR
+.long .L_OP_ADD_FLOAT_2ADDR
+.long .L_OP_SUB_FLOAT_2ADDR
+.long .L_OP_MUL_FLOAT_2ADDR
+.long .L_OP_DIV_FLOAT_2ADDR
+.long .L_OP_REM_FLOAT_2ADDR
+.long .L_OP_ADD_DOUBLE_2ADDR
+.long .L_OP_SUB_DOUBLE_2ADDR
+.long .L_OP_MUL_DOUBLE_2ADDR
+.long .L_OP_DIV_DOUBLE_2ADDR
+.long .L_OP_REM_DOUBLE_2ADDR
+.long .L_OP_ADD_INT_LIT16
+.long .L_OP_RSUB_INT
+.long .L_OP_MUL_INT_LIT16
+.long .L_OP_DIV_INT_LIT16
+.long .L_OP_REM_INT_LIT16
+.long .L_OP_AND_INT_LIT16
+.long .L_OP_OR_INT_LIT16
+.long .L_OP_XOR_INT_LIT16
+.long .L_OP_ADD_INT_LIT8
+.long .L_OP_RSUB_INT_LIT8
+.long .L_OP_MUL_INT_LIT8
+.long .L_OP_DIV_INT_LIT8
+.long .L_OP_REM_INT_LIT8
+.long .L_OP_AND_INT_LIT8
+.long .L_OP_OR_INT_LIT8
+.long .L_OP_XOR_INT_LIT8
+.long .L_OP_SHL_INT_LIT8
+.long .L_OP_SHR_INT_LIT8
+.long .L_OP_USHR_INT_LIT8
+.long .L_OP_IGET_VOLATILE
+.long .L_OP_IPUT_VOLATILE
+.long .L_OP_SGET_VOLATILE
+.long .L_OP_SPUT_VOLATILE
+.long .L_OP_IGET_OBJECT_VOLATILE
+.long .L_OP_IGET_WIDE_VOLATILE
+.long .L_OP_IPUT_WIDE_VOLATILE
+.long .L_OP_SGET_WIDE_VOLATILE
+.long .L_OP_SPUT_WIDE_VOLATILE
+.long .L_OP_BREAKPOINT
+.long .L_OP_THROW_VERIFICATION_ERROR
+.long .L_OP_EXECUTE_INLINE
+.long .L_OP_EXECUTE_INLINE_RANGE
+.long .L_OP_INVOKE_OBJECT_INIT_RANGE
+.long .L_OP_RETURN_VOID_BARRIER
+.long .L_OP_IGET_QUICK
+.long .L_OP_IGET_WIDE_QUICK
+.long .L_OP_IGET_OBJECT_QUICK
+.long .L_OP_IPUT_QUICK
+.long .L_OP_IPUT_WIDE_QUICK
+.long .L_OP_IPUT_OBJECT_QUICK
+.long .L_OP_INVOKE_VIRTUAL_QUICK
+.long .L_OP_INVOKE_VIRTUAL_QUICK_RANGE
+.long .L_OP_INVOKE_SUPER_QUICK
+.long .L_OP_INVOKE_SUPER_QUICK_RANGE
+.long .L_OP_IPUT_OBJECT_VOLATILE
+.long .L_OP_SGET_OBJECT_VOLATILE
+.long .L_OP_SPUT_OBJECT_VOLATILE
+.long .L_OP_DISPATCH_FF
diff --git a/vm/mterp/x86-atom/footer.S b/vm/mterp/x86-atom/footer.S
new file mode 100644
index 0000000..7b5ed9c
--- /dev/null
+++ b/vm/mterp/x86-atom/footer.S
@@ -0,0 +1,660 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: footer.S
+    */
+
+    .text
+    .align      2
+
+   /*
+    * Check to see if the thread needs to be suspended or debugger/profiler
+    * activity has begun.
+    *
+    * On entry:
+    *  %ecx is reentry type, e.g. kInterpEntryInstr
+    *  %edx is PC adjustment in bytes
+    */
+
+common_periodicChecks:
+    movl        %edx, -8(%esp)          # save pc adjustments
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        %ebx, -4(%esp)          # save %ebx to the stack
+    movl        offGlue_pSelfSuspendCount(%edx), %ebx # %ebx<- pSuspendCount (int)
+4:
+    movl        offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
+    testl       %eax, %eax
+    je          5f
+    movzbl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
+5:
+    cmp         $$0, (%ebx)             # check if suspend is pending
+    jne         2f                      # handle suspend
+    movl        offGlue_pActiveProfilers(%edx), %ebx # %ebx<- activeProfilers (int)
+    orl         (%ebx), %eax            # %eax<- merge activeProfilers and debuggerActive
+    movl        -8(%esp), %edx          # %edx<- restore %edx
+    jne         3f                      # debugger or profiler active; switch interp
+    movl        -4(%esp), %ebx          # %ebx<- restore %ebx
+    ret                                 # return
+2:                                      # check suspended
+    EXPORT_PC
+    movl        offGlue_self(%edx), %eax # %eax<- glue->self
+    movl        %eax, -12(%esp)         # push parameter boolean
+    lea         -12(%esp), %esp
+    call        dvmCheckSuspendPending  # call: (Thread* self)
+                                        # return: bool
+    movl        4(%esp), %edx           # %edx<- restore %edx
+    movl        8(%esp), %ebx           # %ebx<- restore %ebx
+    lea         12(%esp), %esp
+    ret
+3:                                      # debugger/profiler enabled, bail out
+    leal        (rPC, %edx, 2), rPC     # adjust pc to show target
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movb        $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
+    movl        $$1, %edx               # switch interpreter
+    jmp         common_gotoBail         # bail
+
+   /*
+    * Check to see if the thread needs to be suspended or debugger/profiler
+    * activity has begun. With this variant, the reentry type is hard coded
+    * as kInterpEntryInstr.
+    *
+    * On entry:
+    *  %edx is PC adjustment in bytes
+    */
+
+common_periodicChecks_backwardBranch:
+    EXPORT_PC
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
+4:
+    movl        offGlue_pDebuggerActive(%ecx), %eax # %eax<- pDebuggerActive
+    testl       %eax, %eax              # test for NULL pointer
+    je          5f
+    movzbl      (%eax), %eax            # %eax<- get debuggerActive count
+5:
+    cmp         $$0, (rINST)            # check if suspend is pending
+    jne         2f                      # handle suspend
+    movl        offGlue_pActiveProfilers(%ecx), rINST # %edx<- activeProfilers (int)
+    orl          (rINST), %eax           # %eax<- merge activeProfilers and debuggerActive
+    jne         3f                      # debugger or profiler active; switch interp
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+2:                                      # check suspended
+    movl        offGlue_self(%ecx), %eax# %eax<- glue->self
+    movl        %edx, rINST
+    movl        %eax, -12(%esp)         # push parameter boolean
+    lea         -12(%esp), %esp
+    call        dvmCheckSuspendPending  # call: (Thread* self)
+                                        # return: bool
+    movl        rINST, %edx             # %edx<- restore %edx
+    lea         12(%esp), %esp
+    FINISH_RB   %edx, %ecx
+3:                                      # debugger/profiler enabled, bail out
+    leal        (rPC, %edx, 2), rPC     # adjust pc to show target
+    movb        $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
+    movl        $$1, %edx               # switch interpreter
+    jmp         common_gotoBail         # bail
+
+   /*
+    * The equivalent of "goto bail", this calls through the "bail handler".
+    * State registers will be saved to the "glue" area before bailing.
+    *
+    * On entry:
+    *  %edx 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 %ecx             # save program counter and frame pointer
+
+   /*
+    * Inlined dvmMterpStdBail
+    */
+
+    lea         40(%ebp), %esp
+    movl        %edx, %eax
+    movl        24(%ebp), %edi
+    movl        28(%ebp), %esi
+    movl        32(%ebp), %ebx
+    movl        36(%ebp), %ebp
+    ret
+
+   /*
+    * Common code for method invocation with range.
+    *
+    * On entry:
+    *  %ecx is "Method* methodToCall", the method we're trying to call
+    */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+   /*
+    * prepare to copy args to "outs" area of current frame
+    */
+
+    SAVEAREA_FROM_FP %eax               # %eax<- &outs; &StackSaveArea
+    test        rINST, rINST            # test for no args
+    movl        rINST, sReg0            # sReg0<- AA
+    jz          .LinvokeArgsDone        # no args; jump to args done
+    FETCH       2, %edx                 # %edx<- CCCC
+
+   /*
+    * %ecx=methodToCall, %edx=CCCC, sReg0=count, %eax=&outs (&stackSaveArea)
+    * (very few methods have > 10 args; could unroll for common cases)
+    */
+
+    movl        %ebx, sReg1             # sReg1<- save %ebx
+    lea         (rFP, %edx, 4), %edx    # %edx<- &vCCCC
+    shll        $$2, sReg0              # sReg0<- offset
+    subl        sReg0, %eax             # %eax<- update &outs
+    shrl        $$2, sReg0              # sReg0<- offset
+1:
+    movl        (%edx), %ebx            # %ebx<- vCCCC
+    lea         4(%edx), %edx           # %edx<- &vCCCC++
+    subl        $$1, sReg0              # sReg<- sReg--
+    movl        %ebx, (%eax)            # *outs<- vCCCC
+    lea         4(%eax), %eax           # outs++
+    jne         1b                      # loop if count (sReg0) not zero
+    movl        sReg1, %ebx             # %ebx<- restore %ebx
+    jmp         .LinvokeArgsDone        # continue
+
+   /*
+    * %ecx is "Method* methodToCall", the method we're trying to call
+    * prepare to copy args to "outs" area of current frame
+    */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+    movl        rINST, sReg0            # sReg0<- BA
+    shrl        $$4, sReg0              # sReg0<- B
+    je          .LinvokeArgsDone        # no args; jump to args done
+    SAVEAREA_FROM_FP %eax               # %eax<- &outs; &StackSaveArea
+    FETCH       2, %edx                 # %edx<- GFED
+
+   /*
+    * %ecx=methodToCall, %edx=GFED, sReg0=count, %eax=outs
+    */
+
+.LinvokeNonRange:
+    cmp         $$2, sReg0              # compare sReg0 to 2
+    movl        %edx, sReg1             # sReg1<- GFED
+    jl          1f                      # handle 1 arg
+    je          2f                      # handle 2 args
+    cmp         $$4, sReg0              # compare sReg0 to 4
+    jl          3f                      # handle 3 args
+    je          4f                      # handle 4 args
+5:
+    andl        $$15, rINST             # rINST<- A
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, rINST, 4), %edx   # %edx<- vA
+    movl        %edx, (%eax)            # *outs<- vA
+    movl        sReg1, %edx             # %edx<- GFED
+4:
+    shr         $$12, %edx              # %edx<- G
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, %edx, 4), %edx    # %edx<- vG
+    movl        %edx, (%eax)            # *outs<- vG
+    movl        sReg1, %edx             # %edx<- GFED
+3:
+    and         $$0x0f00, %edx          # %edx<- 0F00
+    shr         $$6, %edx               # %edx<- F at correct offset
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, %edx), %edx       # %edx<- vF
+    movl        %edx, (%eax)            # *outs<- vF
+    movl        sReg1, %edx             # %edx<- GFED
+2:
+    and         $$0x00f0, %edx          # %edx<- 00E0
+    shr         $$2, %edx               # %edx<- E at correct offset
+    lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
+    movl        (rFP, %edx), %edx       # %edx<- vE
+    movl        %edx, (%eax)            # *outs<- vE
+    movl        sReg1, %edx             # %edx<- GFED
+1:
+    and         $$0x000f, %edx          # %edx<- 000D
+    movl        (rFP, %edx, 4), %edx    # %edx<- vD
+    movl        %edx, -4(%eax)          # *--outs<- vD
+0:
+
+   /*
+    * %ecx is "Method* methodToCall", the method we're trying to call
+    * find space for the new stack frame, check for overflow
+    */
+
+.LinvokeArgsDone:
+    movzwl      offMethod_registersSize(%ecx), %eax # %eax<- methodToCall->regsSize
+    movzwl      offMethod_outsSize(%ecx), %edx # %edx<- methodToCall->outsSize
+    movl        %ecx, sReg0             # sReg<- methodToCall
+    shl         $$2, %eax               # %eax<- update offset
+    SAVEAREA_FROM_FP %ecx               # %ecx<- &outs; &StackSaveArea
+    subl        %eax, %ecx              # %ecx<- newFP; (old savearea - regsSize)
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %ecx, sReg1             # sReg1<- &outs
+    subl        $$sizeofStackSaveArea, %ecx # %ecx<- newSaveArea (stack save area using newFP)
+    movl        offGlue_interpStackEnd(%eax), %eax # %eax<- glue->interpStackEnd
+    movl        %eax, sReg2             # sReg2<- glue->interpStackEnd
+    shl         $$2, %edx               # %edx<- update offset for outsSize
+    movl        %ecx, %eax              # %eax<- newSaveArea
+    sub         %edx, %ecx              # %ecx<- bottom; (newSaveArea - outsSize)
+    cmp         sReg2, %ecx             # compare interpStackEnd and bottom
+    movl        sReg0, %ecx             # %ecx<- restore methodToCall
+    jl          .LstackOverflow         # handle frame overflow
+
+   /*
+    * set up newSaveArea
+    */
+
+#ifdef EASY_GDB
+    SAVEAREA_FROM_FP %edx               # %edx<- &outs; &StackSaveArea
+    movl        %edx, offStackSaveArea_prevSave(%eax) # newSaveArea->prevSave<- &outs
+#endif
+    movl        rFP, offStackSaveArea_prevFrame(%eax) # newSaveArea->prevFrame<- rFP
+    movl        rPC, offStackSaveArea_savedPc(%eax) # newSaveArea->savedPc<- rPC
+    testl       $$ACC_NATIVE, offMethod_accessFlags(%ecx) # check for native call
+    movl        %ecx, offStackSaveArea_method(%eax) # newSaveArea->method<- method to call
+    jne         .LinvokeNative          # handle native call
+
+   /*
+    * Update "glue" values for the new method
+    * %ecx=methodToCall, sReg1=newFp
+    */
+
+    movl        offMethod_clazz(%ecx), %edx # %edx<- method->clazz
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        %ecx, offGlue_method(%eax) # glue->method<- methodToCall
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    movl        offMethod_insns(%ecx), rPC # rPC<- methodToCall->insns
+    movl        %edx, offGlue_methodClassDex(%eax) # glue->methodClassDex<- method->clazz->pDvmDex
+    movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
+    movl        sReg1, rFP              # rFP<- newFP
+    movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+    FINISH_A                            # jump to methodToCall->insns
+
+   /*
+    * Prep for the native call
+    * %ecx=methodToCall, sReg1=newFP, %eax=newSaveArea
+    */
+
+.LinvokeNative:
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        %ecx, -20(%esp)         # push parameter methodToCall
+    movl        offGlue_self(%edx), %edx # %edx<- glue->self
+    movl        offThread_jniLocal_topCookie(%edx), %ecx # %ecx<- glue->self->thread->refNext
+    movl        %ecx, offStackSaveArea_localRefCookie(%eax) # newSaveArea->localRefCookie<- refNext
+    movl        %eax, -4(%esp)          # save newSaveArea
+    movl        sReg1, %eax             # %eax<- newFP
+    movl        %eax, offThread_curFrame(%edx) # glue->self->curFrame<- newFP
+    movl        %edx, -8(%esp)          # save glue->self
+    movl        %edx, -16(%esp)         # push parameter glue->self
+    movl        rGLUE, %edx             # %edx<- pMterpGlue
+    movl        -20(%esp), %ecx         # %ecx<- methodToCall
+    lea         offGlue_retval(%edx), %edx # %edx<- &retval
+    movl        %edx, -24(%esp)         # push parameter pMterpGlue
+    movl        %eax, -28(%esp)         # push parameter newFP
+    lea         -28(%esp), %esp
+
+#ifdef ASSIST_DEBUGGER
+    jmp         .Lskip
+    .type       dalvik_mterp, %function
+dalvik_mterp:
+    MTERP_ENTRY
+.Lskip:
+#endif
+    call        *offMethod_nativeFunc(%ecx) # call methodToCall->nativeFunc
+    lea         28(%esp), %esp
+    movl        -4(%esp), %edx          # %edx<- newSaveArea
+    movl        -8(%esp), %ecx          # %ecx<- glue->self
+    movl        offStackSaveArea_localRefCookie(%edx), %eax  # %eax<- newSaveArea->localRefCookie
+    FFETCH_ADV  3, %edx                 # %edx<- next instruction hi; fetch, advance
+    cmp         $$0, offThread_exception(%ecx) # check for exception
+    movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
+    movl        %eax, offThread_jniLocal_topCookie(%ecx) # glue->self<- newSaveArea->localRefCookie
+    jne         common_exceptionThrown  # handle exception
+    FGETOP_JMP  3, %edx                 # jump to next instruction; getop, jmp
+
+.LstackOverflow:
+    movl        %ecx, -4(%esp)          # push method to call
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offGlue_self(%ecx), %ecx # %ecx<- glue->self
+    movl        %ecx, -8(%esp)          # push parameter self
+    lea         -8(%esp), %esp
+    call        dvmHandleStackOverflow  # call: (Thread* self, Method *meth)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+#ifdef ASSIST_DEBUGGER
+#endif
+
+   /*
+    * Common code for handling a return instruction.
+    *
+    * This does not return.
+    */
+
+common_returnFromMethod:
+.LreturnNew:
+
+   /*
+    * Inline common periodic checks
+    */
+
+    movl        rGLUE, rINST            # %ecx<- pMterpGlue
+    movl        offGlue_pSelfSuspendCount(rINST), %edx # %ebx<- pSuspendCount (int)
+    movl        offGlue_pDebuggerActive(rINST), %eax # %eax<- pDebuggerActive
+    movl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
+    and         $$7, %eax               # %eax<- mask for boolean (just how many bits does it take?)
+    cmp         $$0, (%edx)             # check if suspend is pending
+    jne         2f                      # handle suspend
+    movl        offGlue_pActiveProfilers(rINST), %edx # %edx<- activeProfilers (int)
+    or          (%edx), %eax            # %eax<- merge activeProfilers and debuggerActive
+    cmp         $$0, %eax               # check for debuggerActive
+    jne         3f                      # debugger or profiler active; switch interp
+    jmp         4f
+2:                                      # check suspended
+    movl        offGlue_self(rINST), %eax# %eax<- glue->self
+    movl        %eax, -12(%esp)         # push parameter boolean
+    lea         -12(%esp), %esp
+    call        dvmCheckSuspendPending  # call: (Thread* self)
+                                        # return: bool
+    lea         12(%esp), %esp
+    jmp         4f
+3:                                      # debugger/profiler enabled, bail out
+    movl        $$kInterpEntryInstr, offGlue_entryPoint(rINST) # glue->entryPoint<- reentry type
+    movl        $$1, %edx               # switch to interp<- true
+    jmp         common_gotoBail         # bail
+
+
+   /*
+    * Get save area; rGLUE is %ebx, rFP is %eax
+    */
+4:
+    SAVEAREA_FROM_FP %ecx               # %ecx<- saveArea(old)
+    movl        offStackSaveArea_prevFrame(%ecx), rFP # rFP<- saveArea->PrevFrame
+    movl        (offStackSaveArea_method - sizeofStackSaveArea)(rFP), %edx # %edx<- method we are returning to
+    cmpl        $$0, %edx               # check for break frame
+    je          common_gotoBail         # bail if break frame
+    movl        offStackSaveArea_savedPc(%ecx), rPC # rPC<- saveAreaOld->savedPc
+    movl        offGlue_self(rINST), %ecx # %eax<- glue->self
+    movl        %edx, offGlue_method(rINST) # glue->method<- newSave->method
+    movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
+    FFETCH_ADV  3, %eax                 # %ecx<- next instruction hi; fetch, advance
+    movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    movl        %edx, offGlue_methodClassDex(rINST) # glue->pDvmDex<- method->clazz->pDvmDex
+    FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
+
+   /*
+    * Handle thrown an exception. 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.
+    */
+
+common_exceptionThrown:
+.LexceptionNew:
+    movl        $$kInterpEntryThrow, %ecx # %ecx<- reentry type
+    movl        $$0, %edx               # %edx<- pc adjustment
+    call        common_periodicChecks
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_self(%eax), %edx # %edx<- glue->self
+    movl        offThread_exception(%edx), %ecx # %ecx<- pMterpGlue->self->exception
+    movl        %edx, -4(%esp)          # push parameter self
+    movl        %ecx, -8(%esp)          # push parameter obj
+    lea         -8(%esp), %esp
+    call        dvmAddTrackedAlloc      # don't allow the exception to be GC'd
+                                        # call: (Object* obj, Thread* self)
+                                        # return: void
+    movl        4(%esp), %edx           # %edx<- glue->self
+    movl        $$0, offThread_exception(%edx) # glue->self->exception<- NULL
+
+   /*
+    * set up args and a local for &fp
+    */
+
+    movl        rFP, -4(%esp)           # move fp to stack
+    lea         -4(%esp), %esp          # update %esp
+    movl        %esp, -4(%esp)          # push parameter 4<- &fp
+    movl        $$0, -8(%esp)           # push parameter 3<- false
+    movl        4(%esp), %edx
+    movl        %edx, -12(%esp)         # push parameter 2<- glue->self->exception
+    movl        rGLUE, %eax             # %eax<- pMterpGlue
+    movl        offGlue_method(%eax), %edx # %edx<- glue->method
+    movl        offMethod_insns(%edx), %edx # %edx<- glue->method->insns
+    movl        rPC, %ecx               # %ecx<- rPC
+    subl        %edx, %ecx              # %ecx<- pc - glue->method->insns
+    sar         $$1, %ecx               # %ecx<- adjust %ecx for offset
+    movl        %ecx, -16(%esp)         # push parameter 1<- glue->method->insns
+    movl        8(%esp), %edx
+    movl        %edx, -20(%esp)         # push parameter 0<- glue->self
+    lea         -20(%esp), %esp
+
+   /*
+    * call dvmFindCatchBlock, %eax gets catchRelPc (a code-unit offset)
+    */
+
+    call        dvmFindCatchBlock       # call: (Thread* self, int relPc, Object* exception,
+                                        #      bool doUnroll, void** newFrame)
+                                        # return: int
+    lea         32(%esp), %esp
+    movl        -12(%esp), rFP          # rFP<- updated rFP
+    cmp         $$0, %eax               # check for catchRelPc < 0
+    jl          .LnotCaughtLocally      # handle not caught locally
+
+   /*
+    * fix stack overflow if necessary
+    */
+
+    movl        -4(%esp), %ecx          # %ecx<- glue->self
+    cmp         $$0, offThread_stackOverflowed(%ecx)
+    je          1f
+    movl        %eax, -4(%esp)          # save %eax for later
+    movl        %ecx, -12(%esp)         # push parameter 2 glue->self
+    lea         -12(%esp), %esp
+    call        dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
+                                        # return: void
+    lea         12(%esp), %esp
+    movl        -4(%esp), %eax          # %eax<- restore %eax
+    jmp         2f
+1:
+    movl        %ecx, -12(%esp)         # push parameter 2 glue->self
+2:
+
+   /*
+    * adjust locals to match self->curFrame and updated PC
+    *
+    */
+
+    SAVEAREA_FROM_FP %edx               # %edx<- get newSaveArea
+    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
+    movl        offStackSaveArea_method(%edx), rPC # rPC<- newMethod
+    movl        rPC, offGlue_method(%ecx) # glue->method<- newMethod
+    movl        offMethod_clazz(rPC), %edx # %edx<- method->clazz
+    movl        offMethod_insns(rPC), rPC # rPC<- method->insns
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    lea         (rPC, %eax, 2), rPC     # rPC<- method->insns + catchRelPc
+    movl        %edx, offGlue_methodClassDex(%ecx) # glue->pDvmDex<- method->clazz->pDvmDex
+    movl        -8(%esp), %eax
+    movl        %eax, -16(%esp)         # push parameter 1 obj
+    lea         -16(%esp), %esp
+    call        dvmReleaseTrackedAlloc  # call: (Object* obj, Thread* self)
+                                        # return: void
+    lea         16(%esp), %esp
+    FINISH_FETCH %eax
+    cmp         $$OP_MOVE_EXCEPTION, %eax # is it a move exception
+    jne         1f
+    movl        -12(%esp), %edx         # %edx<- glue->self
+    movl        -8(%esp), %ecx          # %ecx<- exception
+    movl        %ecx, offThread_exception(%edx) # restore the exception
+1:
+    FINISH_JMP  %eax
+
+   /*
+    * -8(%esp) = exception, -4(%esp) = self
+    */
+
+.LnotCaughtLocally:
+    movl        -4(%esp), %edx          # %edx<- glue->self
+    movzb       offThread_stackOverflowed(%edx), %eax # %eax<- self->stackOverflowed
+    cmp         $$0, %eax               # check for stack overflow;
+                                        # maybe should use cmpb
+    je          1f                      #
+    movl        %edx, -12(%esp)         # push parameter 1 glue->self
+    lea         -12(%esp), %esp
+    call        dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
+                                        # return: void
+    lea         12(%esp), %esp
+
+   /*
+    * Release the exception
+    * -8(%esp) = exception, -4(%esp) = self
+    */
+1:
+    movl        -8(%esp), %ecx          # %ecx<- exception
+    movl        -4(%esp), %edx          # %edx<- glue->self
+    movl        %ecx, offThread_exception(%edx) # glue->self<- exception
+    lea         -8(%esp), %esp
+    call        dvmReleaseTrackedAlloc  # call: (Object* obj, Thread* self)
+                                        # return: void
+    lea         8(%esp), %esp
+    movl        $$0, %edx               # switch to interp<- false
+    jmp         common_gotoBail         # bail
+
+   /*
+    * 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
+    FINISH_A                            # jump to next instruction
+
+   /*
+    * For debugging, cause an immediate fault.
+    */
+
+common_abort:
+    jmp         .LdeadFood
+
+.LdeadFood:
+.int 0xdeadf00d
+
+   /*
+    * Invalid array index.
+    */
+
+common_errArrayIndex:
+    EXPORT_PC
+    movl        $$.LstrArrayIndexException, -8(%esp) # push parameter description
+    movl        $$0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Invalid array value.
+    */
+
+common_errArrayStore:
+    EXPORT_PC
+    movl        $$.LstrArrayStoreException, -8(%esp) # push parameter description
+    movl        $$0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Integer divide or mod by zero.
+    */
+
+common_errDivideByZero:
+    EXPORT_PC
+    movl        $$.LstrArithmeticException, -8(%esp) # push parameter description
+    movl        $$.LstrDivideByZero, -4(%esp) # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Attempt to allocate an array with a negative size.
+    */
+
+common_errNegativeArraySize:
+    EXPORT_PC
+    movl        $$.LstrNegativeArraySizeException, -8(%esp) # push parameter description
+    movl        $$0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Invocation of a non-existent method.
+    */
+
+common_errNoSuchMethod:
+    EXPORT_PC
+    movl        $$.LstrNoSuchMethodError, -8(%esp) # push parameter description
+    movl        $$0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * Unexpected null object.
+    */
+
+common_errNullObject:
+    EXPORT_PC
+    movl        $$.LstrNullPointerException, -8(%esp) # push parameter description
+    movl        $$0, -4(%esp)           # push parameter msg paramter
+    lea         -8(%esp), %esp
+    call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
+                                        # return: void
+    lea         8(%esp), %esp
+    jmp         common_exceptionThrown  # handle exception
+
+   /*
+    * String references
+    */
+
+    .align 4
+    .section .rodata
+.LstrArithmeticException:
+    .asciz "Ljava/lang/ArithmeticException;"
+.LstrArrayIndexException:
+    .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
+.LstrArrayStoreException:
+    .asciz "Ljava/lang/ArrayStoreException;"
+.LstrDivideByZero:
+    .asciz "divide by zero"
+.LstrInstantiationError:
+    .asciz "Ljava/lang/InstantiationError;"
+.LstrNegativeArraySizeException:
+    .asciz "Ljava/lang/NegativeArraySizeException;"
+.LstrNoSuchMethodError:
+    .asciz "Ljava/lang/NoSuchMethodError;"
+.LstrNullPointerException:
+    .asciz "Ljava/lang/NullPointerException;"
+.LstrExceptionNotCaughtLocally:
+    .asciz "Exception %s from %s:%d not caught locally\n"
diff --git a/vm/mterp/x86-atom/header.S b/vm/mterp/x86-atom/header.S
new file mode 100644
index 0000000..28c19d6
--- /dev/null
+++ b/vm/mterp/x86-atom/header.S
@@ -0,0 +1,433 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: header.S
+    */
+
+   /*
+    * IA32 calling convention and general notes:
+    *
+    * EAX, ECX, EDX - general purpose scratch registers (caller-saved);
+    *
+    * The stack (%esp) - used to pass arguments to functions
+    *
+    * EAX - holds the first 4 bytes of a return
+    * EDX - holds the second 4 bytes of a return
+    *
+    * EBX, ESI, EDI, EBP - are callee saved
+    *
+    * CS, DS, SS - are segment registers
+    * ES, FS, GS - are segment registers. We will try to avoid using these registers
+    *
+    * The stack is "full descending". Only the arguments that do not fit    * in the first two arg registers are placed on the stack.
+    * "%esp" points to the first stacked argument (i.e. the 3rd arg).
+    */
+
+   /*
+    * Mterp and IA32 notes
+    *
+    * mem          nick      purpose
+    * (%ebp)       rGLUE     InterpState base pointer (A.K.A. MterpGlue Pointer)
+    * %esi         rPC       interpreted program counter, used for fetching
+    *                        instructions
+    * %ebx         rINST     first 16-bit code unit of current instruction
+    * %edi         rFP       interpreted frame pointer, used for accessing
+    *                        locals and args
+    */
+
+   /*
+    * Includes
+    */
+
+#include "../common/asm-constants.h"
+
+   /*
+    * Reserved registers
+    */
+
+#define rGLUE  (%ebp)
+#define rINST   %ebx
+#define rINSTbl  %bl
+#define rINSTbh  %bh
+#define rINSTw  %bx
+#define rPC     %esi
+#define rFP     %edi
+
+   /*
+    * Temporary register used when finishing an opcode
+    */
+
+#define rFinish %edx
+
+   /*
+    * Stack locations used for temporary data. For convenience.
+    */
+
+#define sReg0    4(%ebp)
+#define sReg1    8(%ebp)
+#define sReg2   12(%ebp)
+#define sReg3   16(%ebp)
+
+   /*
+    * Save the PC and FP to the glue struct
+    */
+
+    .macro      SAVE_PC_FP_TO_GLUE _reg
+    movl        rGLUE, \_reg
+    movl        rPC, offGlue_pc(\_reg)
+    movl        rFP, offGlue_fp(\_reg)
+    .endm
+
+   /*
+    * Restore the PC and FP from the glue struct
+    */
+
+    .macro      LOAD_PC_FP_FROM_GLUE
+    movl        rGLUE, rFP
+    movl        offGlue_pc(rFP), rPC
+    movl        offGlue_fp(rFP), rFP
+    .endm
+
+   /*
+    * "Export" the PC to the stack frame, f/b/o future exception objects. This 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.
+    */
+
+    .macro      EXPORT_PC
+    movl        rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
+    .endm
+
+   /*
+    * Given a frame pointer, find the stack save area.
+    * In C this is "((StackSaveArea*)(_fp) -1)".
+    */
+
+    .macro      SAVEAREA_FROM_FP  _reg
+    lea         -sizeofStackSaveArea(rFP), \_reg
+    .endm
+
+   /*
+    * Get the 32-bit value from a dalvik register.
+    */
+
+    .macro      GET_VREG _vreg
+    movl        (rFP,\_vreg, 4), \_vreg
+    .endm
+
+   /*
+    * Set the 32-bit value from a dalvik register.
+    */
+
+    .macro      SET_VREG _reg _vreg
+    movl        \_reg, (rFP,\_vreg, 4)
+    .endm
+
+   /*
+    * Fetch the next instruction from rPC into rINST. Does not advance rPC.
+    */
+
+    .macro      FETCH_INST
+    movzwl      (rPC), rINST
+    .endm
+
+   /*
+    * Fetch the next instruction from the specified offset. Advances rPC
+    * to point to the next instruction. "_count" is in 16-bit code units.
+    *
+    * 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())
+    */
+
+    .macro      FETCH_ADVANCE_INST _count
+    add         $$(\_count*2), rPC
+    movzwl      (rPC), rINST
+    .endm
+
+   /*
+    * 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.
+    */
+
+    .macro      FETCH_ADVANCE_INST_RB _reg
+    addl        \_reg, rPC
+    movzwl      (rPC), rINST
+    .endm
+
+   /*
+    * 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.
+    * For example, given instruction of format: AA|op BBBB, it
+    * fetches BBBB.
+    */
+
+    .macro      FETCH _count _reg
+    movzwl      (\_count*2)(rPC), \_reg
+    .endm
+
+   /*
+    * 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.
+    * This variant treats the value as signed.
+    */
+
+    .macro      FETCHs _count _reg
+    movswl      (\_count*2)(rPC), \_reg
+    .endm
+
+   /*
+    * Fetch the first byte from an offset past the current PC. The
+    * "_count" value is in 16-bit code units. Does not advance rPC.
+    * For example, given instruction of format: AA|op CC|BB, it
+    * fetches BB.
+    */
+
+    .macro      FETCH_BB _count _reg
+    movzbl      (\_count*2)(rPC), \_reg
+    .endm
+
+    /*
+    * Fetch the second byte from an offset past the current PC. The
+    * "_count" value is in 16-bit code units. Does not advance rPC.
+    * For example, given instruction of format: AA|op CC|BB, it
+    * fetches CC.
+    */
+
+    .macro      FETCH_CC _count _reg
+    movzbl      (\_count*2 + 1)(rPC), \_reg
+    .endm
+
+   /*
+    * Fetch the second byte from an offset past the current PC. The
+    * "_count" value is in 16-bit code units. Does not advance rPC.
+    * This variant treats the value as signed.
+    */
+
+    .macro      FETCH_CCs _count _reg
+    movsbl      (\_count*2 + 1)(rPC), \_reg
+    .endm
+
+
+   /*
+    * 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).
+    */
+
+    .macro      FETCH_B _reg  _count  _byte
+    movzbl      (\_count*2+\_byte)(rPC), \_reg
+    .endm
+
+   /*
+    * Put the instruction's opcode field into the specified register.
+    */
+
+    .macro      GET_INST_OPCODE _reg
+    movzbl      rINSTbl, \_reg
+    .endm
+
+   /*
+    * Begin executing the opcode in _reg.
+    */
+
+    .macro      GOTO_OPCODE _reg
+    shl         $$${handler_size_bits}, \_reg
+    addl        $$dvmAsmInstructionStart,\_reg
+    jmp         *\_reg
+    .endm
+
+
+
+   /*
+    * Macros pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
+    * by using a jump table. _rFinish should must be the same register for
+    * both macros.
+    */
+
+    .macro      FFETCH _rFinish
+    movzbl      (rPC), \_rFinish
+    .endm
+
+    .macro      FGETOP_JMPa _rFinish
+    movzbl      1(rPC), rINST
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
+    * by using a jump table. _rFinish and _count should must be the same register for
+    * both macros.
+    */
+
+    .macro      FFETCH_ADV _count _rFinish
+    movzbl      (\_count*2)(rPC), \_rFinish
+    .endm
+
+    .macro      FGETOP_JMP _count _rFinish
+    movzbl      (\_count*2 + 1)(rPC), rINST
+    addl        $$(\_count*2), rPC
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Macro pair attempts to speed up FETCH_INST, GET_INST_OPCODE and GOTO_OPCODE
+    * by using a jump table. _rFinish and _reg should must be the same register for
+    * both macros.
+    */
+
+    .macro      FFETCH_ADV_RB _reg _rFinish
+    movzbl      (\_reg, rPC), \_rFinish
+    .endm
+
+    .macro      FGETOP_RB_JMP _reg _rFinish
+    movzbl      1(\_reg, rPC), rINST
+    addl        \_reg, rPC
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_INST, GET_INST_OPCODE using
+    * a jump table. This macro should be called before FINISH_JMP where
+    * rFinish should be the same register containing the opcode value.
+    * This is an attempt to split up FINISH in order to reduce or remove
+    * potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_FETCH _rFinish
+    movzbl      (rPC), \_rFinish
+    movzbl      1(rPC), rINST
+    .endm
+
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE using
+    * a jump table. This macro should be called before FINISH_JMP where
+    * rFinish should be the same register containing the opcode value.
+    * This is an attempt to split up FINISH in order to reduce or remove
+    * potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_FETCH_ADVANCE _count _rFinish
+    movzbl      (\_count*2)(rPC), \_rFinish
+    movzbl      (\_count*2 + 1)(rPC), rINST
+    addl        $$(\_count*2), rPC
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE using
+    * a jump table. This macro should be called before FINISH_JMP where
+    * rFinish should be the same register containing the opcode value.
+    * This is an attempt to split up FINISH in order to reduce or remove
+    * potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_FETCH_ADVANCE_RB _reg _rFinish
+    movzbl      (\_reg, rPC), \_rFinish
+    movzbl      1(\_reg, rPC), rINST
+    addl        \_reg, rPC
+    .endm
+
+   /*
+    * Attempts to speed up GOTO_OPCODE using a jump table. This macro should
+    * be called after a FINISH_FETCH* instruction where rFinish should be the
+    * same register containing the opcode value. This is an attempt to split up
+    * FINISH in order to reduce or remove potential stalls due to the wait for rFINISH.
+    */
+
+    .macro      FINISH_JMP _rFinish
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_INST, GET_INST_OPCODE, GOTO_OPCODE by using
+    * a jump table. Uses a single macro - but it should be faster if we
+    * split up the fetch for rFinish and the jump using rFinish.
+    */
+
+    .macro      FINISH_A
+    movzbl      (rPC), rFinish
+    movzbl      1(rPC), rINST
+    jmp         *dvmAsmInstructionJmpTable(,rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST, GET_INST_OPCODE,
+    * GOTO_OPCODE by using a jump table. Uses a single macro -
+    * but it should be faster if we split up the fetch for rFinish
+    * and the jump using rFinish.
+    */
+
+    .macro      FINISH _count
+    movzbl      (\_count*2)(rPC), rFinish
+    movzbl      (\_count*2 + 1)(rPC), rINST
+    addl        $$(\_count*2), rPC
+    jmp         *dvmAsmInstructionJmpTable(,rFinish, 4)
+    .endm
+
+   /*
+    * Attempts to speed up FETCH_ADVANCE_INST_RB, GET_INST_OPCODE,
+    * GOTO_OPCODE by using a jump table. Uses a single macro -
+    * but it should be faster if we split up the fetch for rFinish
+    * and the jump using rFinish.
+    */
+
+    .macro      FINISH_RB _reg _rFinish
+    movzbl      (\_reg, rPC), \_rFinish
+    movzbl      1(\_reg, rPC), rINST
+    addl        \_reg, rPC
+    jmp         *dvmAsmInstructionJmpTable(,\_rFinish, 4)
+    .endm
+
+   /*
+    * Hard coded helper values.
+    */
+
+.balign 16
+
+.LdoubNeg:
+    .quad       0x8000000000000000
+
+.L64bits:
+    .quad       0xFFFFFFFFFFFFFFFF
+
+.LshiftMask2:
+    .quad       0x0000000000000000
+.LshiftMask:
+    .quad       0x000000000000003F
+
+.Lvalue64:
+    .quad       0x0000000000000040
+
+.LvaluePosInfLong:
+    .quad       0x7FFFFFFFFFFFFFFF
+
+.LvalueNegInfLong:
+    .quad       0x8000000000000000
+
+.LvalueNanLong:
+    .quad       0x0000000000000000
+
+.LintMin:
+.long   0x80000000
+
+.LintMax:
+.long   0x7FFFFFFF
diff --git a/vm/mterp/x86-atom/stub.S b/vm/mterp/x86-atom/stub.S
new file mode 100644
index 0000000..54f3f54
--- /dev/null
+++ b/vm/mterp/x86-atom/stub.S
@@ -0,0 +1,25 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: stub.S
+    */
+
+    SAVE_PC_FP_TO_GLUE %edx             # save program counter and frame pointer
+    pushl       rGLUE                   # push parameter glue
+    call        dvmMterp_${opcode}      # call c-based implementation
+    lea         4(%esp), %esp
+    LOAD_PC_FP_FROM_GLUE                # restore program counter and frame pointer
+    FINISH_A                            # jump to next instruction
diff --git a/vm/mterp/x86-atom/unop.S b/vm/mterp/x86-atom/unop.S
new file mode 100644
index 0000000..00f9f8d
--- /dev/null
+++ b/vm/mterp/x86-atom/unop.S
@@ -0,0 +1,43 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unop.S
+    *
+    * Code: Generic 32-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%ecx = op %edx".
+    *
+    * For: int-to-byte, int-to-char, int-to-short, neg-float, neg-int, not-int
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+%default {"preinstr":"", "instr":""}
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, %ecx               # %ecx<- B
+    and         $$15, rINST             # rINST<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    GET_VREG    %ecx                    # %ecx<- vB
+    $preinstr                           # do operation part 1
+    $instr                              # do operation part 2
+    SET_VREG    %ecx, rINST             # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/unopWide.S b/vm/mterp/x86-atom/unopWide.S
new file mode 100644
index 0000000..3790a2c
--- /dev/null
+++ b/vm/mterp/x86-atom/unopWide.S
@@ -0,0 +1,43 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unopWide.S
+    *
+    * Code: Generic 64-bit unary operation. Provide an "instr" variable and a
+    *       preinstr variable that together specify an instruction that
+    *       performs, for example, "%xmm0 = op %xmm1".
+    *
+    * For:  neg-double, neg-long, not-long
+    *
+    * Description: Perform the identified unary operation on the source
+    *              register, storing the result in the destination register
+    *
+    * Format: B|A|op (12x)
+    *
+    * Syntax: op vA, vB
+    */
+
+%default {"preinstr":"","result":"%xmm0"}
+
+    movl        rINST, %ecx             # %ecx<- BA+
+    shr         $$4, rINST              # rINST<- B
+    and         $$15, %ecx              # %ecx<- A
+    FFETCH_ADV  1, %eax                 # %eax<- next instruction hi; fetch, advance
+    movq        (rFP, rINST, 4), %xmm0  # %xmm0<- vB
+    $preinstr                           # do operation part 1
+    $instr                              # do operation part 2
+    movq        $result, (rFP, %ecx, 4) # vA<- result
+    FGETOP_JMP  1, %eax                 # jump to next instruction; getop, jmp
diff --git a/vm/mterp/x86-atom/unused.S b/vm/mterp/x86-atom/unused.S
new file mode 100644
index 0000000..8267709
--- /dev/null
+++ b/vm/mterp/x86-atom/unused.S
@@ -0,0 +1,30 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: unused.S
+    *
+    * Code: Common code for unused bytecodes. Uses no subtitutions.
+    *
+    * For: all unused bytecodes
+    *
+    * Description: aborts if executed.
+    *
+    * Format: ØØ|op (10x)
+    *
+    * Syntax: op
+    */
+
+    call        common_abort
diff --git a/vm/mterp/x86-atom/zcmp.S b/vm/mterp/x86-atom/zcmp.S
new file mode 100644
index 0000000..6614dba
--- /dev/null
+++ b/vm/mterp/x86-atom/zcmp.S
@@ -0,0 +1,53 @@
+   /* Copyright (C) 2008 The Android Open Source Project
+    *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+    * you may not use this file except in compliance with the License.
+    * You may obtain a copy of the License at
+    *
+    * http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing, software
+    * distributed under the License is distributed on an "AS IS" BASIS,
+    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    * See the License for the specific language governing permissions and
+    * limitations under the License.
+    */
+
+   /*
+    * File: zcmp.S
+    *
+    * Code: Generic 32-bit comparison operation. Provides a "revcmp"
+    *       variable to specify the reverse comparison to perform
+    *
+    * For: if-eqz, if-gez, if-gtz, if-lez, if-ltz, if-nez
+    *
+    * Description: Branch to the given destination if the given register's
+    *              value compares with 0 as specified.
+    *
+    * Format: AA|op BBBB (21t)
+    *
+    * Syntax: op vAA, +BBBB
+    */
+
+    cmp         $$0, (rFP, rINST, 4)    # compare vAA with zero
+    j${revcmp}  ${opcode}_2f                    # goto next instruction or branch
+    FETCHs      1, %edx                 # %edx<- BBBB; branch offset
+    sal         $$1, %edx               # %edx<- adjust byte offset
+
+   /*
+    * Inline common_backwardBranch
+    */
+
+    js          common_periodicChecks_backwardBranch  # jump on backwards branch
+1:
+    FINISH_RB   %edx, %ecx              # jump to next instruction
+
+   /*
+    * FINISH code
+    */
+
+${opcode}_2f:
+    movzbl      4(rPC), %edx            # grab the next opcode
+    movzbl      5(rPC), rINST           # update the instruction
+    addl        $$4, rPC                # update the program counter
+    jmp         *dvmAsmInstructionJmpTable(, %edx, 4) # jump to next instruction
diff --git a/vm/mterp/x86/ALT_OP_DISPATCH_FF.S b/vm/mterp/x86/ALT_OP_DISPATCH_FF.S
new file mode 100644
index 0000000..948ff87
--- /dev/null
+++ b/vm/mterp/x86/ALT_OP_DISPATCH_FF.S
@@ -0,0 +1,8 @@
+%verify "executed"
+/*
+ * Unlike other alt stubs, we don't want to call dvmCheckBefore() here.
+ * Instead, just treat this as a trampoline to reach the real alt
+ * handler (which will do the dvmCheckBefore() call.
+ */
+    leal      256(rINST),%ecx
+    GOTO_NEXT_JUMBO_R %ecx
diff --git a/vm/mterp/x86/OP_ADD_DOUBLE.S b/vm/mterp/x86/OP_ADD_DOUBLE.S
new file mode 100644
index 0000000..9fded29
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"faddl","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..81e55ea
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"faddl","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_ADD_FLOAT.S b/vm/mterp/x86/OP_ADD_FLOAT.S
new file mode 100644
index 0000000..61a6f68
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fadds","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/x86/OP_ADD_FLOAT_2ADDR.S
new file mode 100644
index 0000000..fd61457
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fadds","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_ADD_INT.S b/vm/mterp/x86/OP_ADD_INT.S
new file mode 100644
index 0000000..b95a2db
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop.S" {"instr":"addl (rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_ADD_INT_2ADDR.S b/vm/mterp/x86/OP_ADD_INT_2ADDR.S
new file mode 100644
index 0000000..5d4681b
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop2addr.S" {"instr":"addl     %eax,(rFP,%ecx,4)"}
diff --git a/vm/mterp/x86/OP_ADD_INT_LIT16.S b/vm/mterp/x86/OP_ADD_INT_LIT16.S
new file mode 100644
index 0000000..d96821d
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit16.S" {"instr":"addl %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_ADD_INT_LIT8.S b/vm/mterp/x86/OP_ADD_INT_LIT8.S
new file mode 100644
index 0000000..5d477fb
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"addl %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_ADD_LONG.S b/vm/mterp/x86/OP_ADD_LONG.S
new file mode 100644
index 0000000..bc157f6
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide.S" {"instr1":"addl (rFP,%ecx,4),rIBASE", "instr2":"adcl 4(rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_ADD_LONG_2ADDR.S b/vm/mterp/x86/OP_ADD_LONG_2ADDR.S
new file mode 100644
index 0000000..1f9d97e
--- /dev/null
+++ b/vm/mterp/x86/OP_ADD_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide2addr.S" {"instr1":"addl %eax,(rFP,rINST,4)","instr2":"adcl %ecx,4(rFP,rINST,4)"}
diff --git a/vm/mterp/x86/OP_AGET.S b/vm/mterp/x86/OP_AGET.S
new file mode 100644
index 0000000..42dfa0a
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET.S
@@ -0,0 +1,24 @@
+%default { "load":"movl", "shift":"4" }
+%verify "executed"
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    $load     offArrayObject_contents(%eax,%ecx,$shift),%eax
+.L${opcode}_finish:
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_AGET_BOOLEAN.S b/vm/mterp/x86/OP_AGET_BOOLEAN.S
new file mode 100644
index 0000000..27f6de0
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_AGET.S" { "load":"movzbl", "shift":"1" }
diff --git a/vm/mterp/x86/OP_AGET_BYTE.S b/vm/mterp/x86/OP_AGET_BYTE.S
new file mode 100644
index 0000000..49c83e1
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_AGET.S" { "load":"movsbl", "shift":"1" }
diff --git a/vm/mterp/x86/OP_AGET_CHAR.S b/vm/mterp/x86/OP_AGET_CHAR.S
new file mode 100644
index 0000000..b5f6bcf
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_AGET.S" { "load":"movzwl", "shift":"2" }
diff --git a/vm/mterp/x86/OP_AGET_OBJECT.S b/vm/mterp/x86/OP_AGET_OBJECT.S
new file mode 100644
index 0000000..0c43394
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_AGET.S"
diff --git a/vm/mterp/x86/OP_AGET_SHORT.S b/vm/mterp/x86/OP_AGET_SHORT.S
new file mode 100644
index 0000000..aeeffa3
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_AGET.S" { "load":"movswl", "shift":"2" }
diff --git a/vm/mterp/x86/OP_AGET_WIDE.S b/vm/mterp/x86/OP_AGET_WIDE.S
new file mode 100644
index 0000000..32266bc
--- /dev/null
+++ b/vm/mterp/x86/OP_AGET_WIDE.S
@@ -0,0 +1,24 @@
+%verify "executed"
+    /*
+     * Array get, 64 bits.  vAA <- vBB[vCC].
+     *
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,8),%eax
+    movl      (%eax),%ecx
+    movl      4(%eax),%eax
+    SET_VREG_WORD %ecx rINST 0
+    SET_VREG_WORD %eax rINST 1
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_AND_INT.S b/vm/mterp/x86/OP_AND_INT.S
new file mode 100644
index 0000000..3bb8757
--- /dev/null
+++ b/vm/mterp/x86/OP_AND_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop.S" {"instr":"andl   (rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_AND_INT_2ADDR.S b/vm/mterp/x86/OP_AND_INT_2ADDR.S
new file mode 100644
index 0000000..2dee26b
--- /dev/null
+++ b/vm/mterp/x86/OP_AND_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop2addr.S" {"instr":"andl     %eax,(rFP,%ecx,4)"}
diff --git a/vm/mterp/x86/OP_AND_INT_LIT16.S b/vm/mterp/x86/OP_AND_INT_LIT16.S
new file mode 100644
index 0000000..e0fe168
--- /dev/null
+++ b/vm/mterp/x86/OP_AND_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit16.S" {"instr":"andl %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_AND_INT_LIT8.S b/vm/mterp/x86/OP_AND_INT_LIT8.S
new file mode 100644
index 0000000..62c68dc
--- /dev/null
+++ b/vm/mterp/x86/OP_AND_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"andl %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_AND_LONG.S b/vm/mterp/x86/OP_AND_LONG.S
new file mode 100644
index 0000000..06df873
--- /dev/null
+++ b/vm/mterp/x86/OP_AND_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide.S" {"instr1":"andl (rFP,%ecx,4),rIBASE", "instr2":"andl 4(rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_AND_LONG_2ADDR.S b/vm/mterp/x86/OP_AND_LONG_2ADDR.S
new file mode 100644
index 0000000..419850e
--- /dev/null
+++ b/vm/mterp/x86/OP_AND_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide2addr.S" {"instr1":"andl %eax,(rFP,rINST,4)","instr2":"andl %ecx,4(rFP,rINST,4)"}
diff --git a/vm/mterp/x86/OP_APUT.S b/vm/mterp/x86/OP_APUT.S
new file mode 100644
index 0000000..f51c9c7
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT.S
@@ -0,0 +1,25 @@
+%default { "reg":"rINST", "store":"movl", "shift":"4" }
+%verify "executed"
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,$shift),%eax
+.L${opcode}_finish:
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    $store     $reg,(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_APUT_BOOLEAN.S b/vm/mterp/x86/OP_APUT_BOOLEAN.S
new file mode 100644
index 0000000..fb1e8db
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_APUT.S" {"reg":"rINSTbl", "store":"movb", "shift":"1" }
diff --git a/vm/mterp/x86/OP_APUT_BYTE.S b/vm/mterp/x86/OP_APUT_BYTE.S
new file mode 100644
index 0000000..366c8c5
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_APUT.S" { "reg":"rINSTbl", "store":"movb", "shift":"1" }
diff --git a/vm/mterp/x86/OP_APUT_CHAR.S b/vm/mterp/x86/OP_APUT_CHAR.S
new file mode 100644
index 0000000..9c87384
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_APUT.S" { "reg":"rINSTw", "store":"movw", "shift":"2" }
diff --git a/vm/mterp/x86/OP_APUT_OBJECT.S b/vm/mterp/x86/OP_APUT_OBJECT.S
new file mode 100644
index 0000000..0850e1c
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT_OBJECT.S
@@ -0,0 +1,66 @@
+%verify "executed"
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA
+     *
+     * for: aput, aput-object, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    GET_VREG_R  rINST rINST             # rINST<- vAA
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects
+                                        #    arrayObj in eax
+                                        #    index in ecx
+    /* On entry:
+     *   eax<- array object
+     *   ecx<- index
+     *   rINST<- vAA
+     */
+    leal      offArrayObject_contents(%eax,%ecx,4),%ecx
+    testl     rINST,rINST                    # storing null reference?
+    je        .L${opcode}_skip_check
+    SPILL_TMP1(%ecx)                         # save target address
+    SPILL_TMP2(%eax)                         # save object head
+    movl      offObject_clazz(%eax),%eax     # eax<- arrayObj->clazz
+    movl      offObject_clazz(rINST),%ecx    # ecx<- obj->clazz
+    movl      %eax,OUT_ARG1(%esp)
+    movl      %ecx,OUT_ARG0(%esp)
+    movl      %ecx,sReg0                     # store the two classes for later
+    movl      %eax,sReg1
+    SPILL(rIBASE)
+    call      dvmCanPutArrayElement          # test object type vs. array type
+    UNSPILL(rIBASE)
+    UNSPILL_TMP1(%ecx)                       # recover target address
+    testl     %eax,%eax
+    movl      rSELF,%eax
+    jne       .L${opcode}_types_okay
+
+    # The types don't match.  We need to throw an ArrayStoreException.
+    EXPORT_PC
+    movl      sReg0,%eax                     # restore the two classes...
+    movl      %eax,OUT_ARG0(%esp)
+    movl      sReg1,%ecx
+    movl      %ecx,OUT_ARG1(%esp)
+    call      dvmThrowArrayStoreExceptionIncompatibleElement # ...and throw
+    jmp       common_exceptionThrown
+
+.L${opcode}_types_okay:
+    movl      offThread_cardTable(%eax),%eax   # get card table base
+    movl      rINST,(%ecx)                   # store into array
+    UNSPILL_TMP2(rINST)                      # recover object head
+    FETCH_INST_OPCODE 2 %ecx
+    shrl      $$GC_CARD_SHIFT,rINST          # object head to card number
+    movb      %al,(%eax,rINST)               # mark card using object head
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_skip_check:
+    movl      rINST,(%ecx)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_APUT_SHORT.S b/vm/mterp/x86/OP_APUT_SHORT.S
new file mode 100644
index 0000000..9c87384
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_APUT.S" { "reg":"rINSTw", "store":"movw", "shift":"2" }
diff --git a/vm/mterp/x86/OP_APUT_WIDE.S b/vm/mterp/x86/OP_APUT_WIDE.S
new file mode 100644
index 0000000..cd1e723
--- /dev/null
+++ b/vm/mterp/x86/OP_APUT_WIDE.S
@@ -0,0 +1,24 @@
+%verify "executed"
+    /*
+     * Array put, 64 bits.  vBB[vCC]<-vAA.
+     *
+     */
+    /* op vAA, vBB, vCC */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    GET_VREG_R  %eax %eax               # eax<- vBB (array object)
+    GET_VREG_R  %ecx %ecx               # ecs<- vCC (requested index)
+    testl     %eax,%eax                 # null array object?
+    je        common_errNullObject      # bail if so
+    cmpl      offArrayObject_length(%eax),%ecx
+    jae       common_errArrayIndex      # index >= length, bail.  Expects:
+                                        #   arrayObj in eax
+                                        #   index in ecx
+    leal      offArrayObject_contents(%eax,%ecx,8),%eax
+    GET_VREG_WORD %ecx rINST 0
+    GET_VREG_WORD rINST rINST 1
+    movl      %ecx,(%eax)
+    FETCH_INST_OPCODE 2 %ecx
+    movl      rINST,4(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_ARRAY_LENGTH.S b/vm/mterp/x86/OP_ARRAY_LENGTH.S
new file mode 100644
index 0000000..25caca3
--- /dev/null
+++ b/vm/mterp/x86/OP_ARRAY_LENGTH.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /*
+     * Return the length of an array.
+     */
+   mov      rINST,%eax                # eax<- BA
+   sarl     $$4,rINST                 # rINST<- B
+   GET_VREG_R %ecx rINST              # ecx<- vB (object ref)
+   andb     $$0xf,%al                 # eax<- A
+   testl    %ecx,%ecx                 # is null?
+   je       common_errNullObject
+   movl     offArrayObject_length(%ecx),rINST
+   FETCH_INST_OPCODE 1 %ecx
+   ADVANCE_PC 1
+   SET_VREG rINST %eax
+   GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_BREAKPOINT.S b/vm/mterp/x86/OP_BREAKPOINT.S
new file mode 100644
index 0000000..6da9957
--- /dev/null
+++ b/vm/mterp/x86/OP_BREAKPOINT.S
@@ -0,0 +1,19 @@
+%verify "executed"
+    /*
+     * Breakpoint handler.
+     *
+     * Restart this instruction with the original opcode.  By
+     * the time we get here, the breakpoint will have already been
+     * handled.  We also assume that all other special "checkBefore"
+     * actions have been handled, so we'll transition directly
+     * to the real handler
+     */
+    SPILL(rIBASE)
+    movl    rPC,OUT_ARG0(%esp)
+    call    dvmGetOriginalOpcode
+    UNSPILL(rIBASE)
+    movl    rSELF,%ecx
+    movzbl  1(rPC),rINST
+    movl    offThread_mainHandlerTable(%ecx),%ecx
+    jmp     *(%ecx,%eax,4)
+
diff --git a/vm/mterp/x86/OP_CHECK_CAST.S b/vm/mterp/x86/OP_CHECK_CAST.S
new file mode 100644
index 0000000..0543a99
--- /dev/null
+++ b/vm/mterp/x86/OP_CHECK_CAST.S
@@ -0,0 +1,77 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast vAA, class@BBBB */
+    movl      rSELF,%ecx
+    GET_VREG_R  rINST,rINST             # rINST<- vAA (object)
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    testl     rINST,rINST               # is oject null?
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    je        .L${opcode}_okay          # null obj, cast always succeeds
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved class
+    movl      offObject_clazz(rINST),%ecx # ecx<- obj->clazz
+    testl     %eax,%eax                 # have we resolved this before?
+    je        .L${opcode}_resolve       # no, go do it now
+.L${opcode}_resolved:
+    cmpl      %eax,%ecx                 # same class (trivial success)?
+    jne       .L${opcode}_fullcheck     # no, do full check
+.L${opcode}_okay:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  ecx holds obj->clazz
+     *  eax holds class resolved from BBBB
+     *  rINST holds object
+     */
+.L${opcode}_fullcheck:
+    movl    %eax,sReg0                 # we'll need the desired class on failure
+    movl    %eax,OUT_ARG1(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call    dvmInstanceofNonTrivial    # eax<- boolean result
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # failed?
+    jne     .L${opcode}_okay           # no, success
+
+    # A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC
+    movl    offObject_clazz(rINST),%eax
+    movl    %eax,OUT_ARG0(%esp)                 # arg0<- obj->clazz
+    movl    sReg0,%ecx
+    movl    %ecx,OUT_ARG1(%esp)                 # arg1<- desired class
+    call    dvmThrowClassCastException
+    jmp     common_exceptionThrown
+
+    /*
+     * Resolution required.  This is the least-likely path, and we're
+     * going to have to recreate some data.
+     *
+     *  rINST holds object
+     */
+.L${opcode}_resolve:
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movzwl  2(rPC),%eax                # eax<- BBBB
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)        # arg1<- BBBB
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- metho->clazz
+    movl    $$0,OUT_ARG2(%esp)         # arg2<- false
+    movl    %ecx,OUT_ARG0(%esp)        # arg0<- method->clazz
+    SPILL(rIBASE)
+    call    dvmResolveClass            # eax<- resolved ClassObject ptr
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # got null?
+    je      common_exceptionThrown     # yes, handle exception
+    movl    offObject_clazz(rINST),%ecx  # ecx<- obj->clazz
+    jmp     .L${opcode}_resolved       # pick up where we left off
diff --git a/vm/mterp/x86/OP_CHECK_CAST_JUMBO.S b/vm/mterp/x86/OP_CHECK_CAST_JUMBO.S
new file mode 100644
index 0000000..bf99bd7
--- /dev/null
+++ b/vm/mterp/x86/OP_CHECK_CAST_JUMBO.S
@@ -0,0 +1,77 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast/jumbo vBBBB, class@AAAAAAAA */
+    movl      rSELF,%ecx
+    GET_VREG_R  rINST,rINST             # rINST<- vBBBB (object)
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    testl     rINST,rINST               # is oject null?
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    je        .L${opcode}_okay          # null obj, cast always succeeds
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved class
+    movl      offObject_clazz(rINST),%ecx # ecx<- obj->clazz
+    testl     %eax,%eax                 # have we resolved this before?
+    je        .L${opcode}_resolve       # no, go do it now
+.L${opcode}_resolved:
+    cmpl      %eax,%ecx                 # same class (trivial success)?
+    jne       .L${opcode}_fullcheck     # no, do full check
+.L${opcode}_okay:
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  ecx holds obj->clazz
+     *  eax holds class resolved from AAAAAAAA
+     *  rINST holds object
+     */
+.L${opcode}_fullcheck:
+    movl    %eax,sReg0                 # we'll need the desired class on failure
+    movl    %eax,OUT_ARG1(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call    dvmInstanceofNonTrivial    # eax<- boolean result
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # failed?
+    jne     .L${opcode}_okay           # no, success
+
+    # A cast has failed.  We need to throw a ClassCastException.
+    EXPORT_PC
+    movl    offObject_clazz(rINST),%eax
+    movl    %eax,OUT_ARG0(%esp)                 # arg0<- obj->clazz
+    movl    sReg0,%ecx
+    movl    %ecx,OUT_ARG1(%esp)                 # arg1<- desired class
+    call    dvmThrowClassCastException
+    jmp     common_exceptionThrown
+
+    /*
+     * Resolution required.  This is the least-likely path, and we're
+     * going to have to recreate some data.
+     *
+     *  rINST holds object
+     */
+.L${opcode}_resolve:
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movl    2(rPC),%eax                # eax<- AAAAAAAA
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)        # arg1<- AAAAAAAA
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- metho->clazz
+    movl    $$0,OUT_ARG2(%esp)         # arg2<- false
+    movl    %ecx,OUT_ARG0(%esp)        # arg0<- method->clazz
+    SPILL(rIBASE)
+    call    dvmResolveClass            # eax<- resolved ClassObject ptr
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                  # got null?
+    je      common_exceptionThrown     # yes, handle exception
+    movl    offObject_clazz(rINST),%ecx  # ecx<- obj->clazz
+    jmp     .L${opcode}_resolved       # pick up where we left off
diff --git a/vm/mterp/x86/OP_CMPG_DOUBLE.S b/vm/mterp/x86/OP_CMPG_DOUBLE.S
new file mode 100644
index 0000000..1388d7c
--- /dev/null
+++ b/vm/mterp/x86/OP_CMPG_DOUBLE.S
@@ -0,0 +1,33 @@
+%default {"is_double":"1","nanval":"1"}
+%verify "executed"
+%verify "basic lt, gt, eq"
+%verify "left arg NaN"
+%verify "right arg NaN"
+    /* float/double_cmp[gl] vAA, vBB, vCC */
+    movzbl    3(rPC),%eax             # eax<- CC
+    movzbl    2(rPC),%ecx             # ecx<- BB
+    .if $is_double
+    fldl     (rFP,%eax,4)
+    fldl     (rFP,%ecx,4)
+    .else
+    flds     (rFP,%eax,4)
+    flds     (rFP,%ecx,4)
+    .endif
+    xorl     %ecx,%ecx
+    fucompp     # z if equal, p set if NaN, c set if st0 < st1
+    fnstsw   %ax
+    sahf
+    FETCH_INST_OPCODE 2 %eax
+    jp       .L${opcode}_isNaN
+    je       .L${opcode}_finish
+    sbbl     %ecx,%ecx
+    jb       .L${opcode}_finish
+    incl     %ecx
+.L${opcode}_finish:
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
+
+.L${opcode}_isNaN:
+    movl      $$$nanval,%ecx
+    jmp       .L${opcode}_finish
diff --git a/vm/mterp/x86/OP_CMPG_FLOAT.S b/vm/mterp/x86/OP_CMPG_FLOAT.S
new file mode 100644
index 0000000..bd6674a
--- /dev/null
+++ b/vm/mterp/x86/OP_CMPG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_CMPG_DOUBLE.S" {"is_double":"0","nanval":"1"}
diff --git a/vm/mterp/x86/OP_CMPL_DOUBLE.S b/vm/mterp/x86/OP_CMPL_DOUBLE.S
new file mode 100644
index 0000000..54ff0d8
--- /dev/null
+++ b/vm/mterp/x86/OP_CMPL_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_CMPG_DOUBLE.S" {"is_double":"1","nanval":"-1"}
diff --git a/vm/mterp/x86/OP_CMPL_FLOAT.S b/vm/mterp/x86/OP_CMPL_FLOAT.S
new file mode 100644
index 0000000..bbb674d
--- /dev/null
+++ b/vm/mterp/x86/OP_CMPL_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_CMPG_DOUBLE.S" {"is_double":"0","nanval":"-1"}
diff --git a/vm/mterp/x86/OP_CMP_LONG.S b/vm/mterp/x86/OP_CMP_LONG.S
new file mode 100644
index 0000000..5202c27
--- /dev/null
+++ b/vm/mterp/x86/OP_CMP_LONG.S
@@ -0,0 +1,42 @@
+%verify "executed"
+%verify "basic lt, gt, eq"
+%verify "hi equal, lo <=>"
+%verify "lo equal, hi <=>"
+    /*
+     * Compare two 64-bit values.  Puts 0, 1, or -1 into the destination
+     * register based on the results of the comparison.
+     */
+    // TUNING: rework to avoid rIBASE spill
+    /* cmp-long vAA, vBB, vCC */
+    movzbl    2(rPC),%ecx              # ecx<- BB
+    SPILL(rIBASE)
+    movzbl    3(rPC),rIBASE            # rIBASE- CC
+    GET_VREG_WORD %eax %ecx,1          # eax<- v[BB+1]
+    GET_VREG_WORD %ecx %ecx 0          # ecx<- v[BB+0]
+    cmpl      4(rFP,rIBASE,4),%eax
+    jl        .L${opcode}_smaller
+    jg        .L${opcode}_bigger
+    sub       (rFP,rIBASE,4),%ecx
+    ja        .L${opcode}_bigger
+    jb        .L${opcode}_smaller
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_bigger:
+    movl      $$1,%ecx
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_smaller:
+    movl      $$-1,%ecx
+    SET_VREG %ecx rINST
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST.S b/vm/mterp/x86/OP_CONST.S
new file mode 100644
index 0000000..cb70824
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST.S
@@ -0,0 +1,8 @@
+%verify "executed"
+    /* const vAA, #+BBBBbbbb */
+    movl      2(rPC),%eax             # grab all 32 bits at once
+    movl      rINST,rINST             # rINST<- AA
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    SET_VREG %eax rINST               # vAA<- eax
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_16.S b/vm/mterp/x86/OP_CONST_16.S
new file mode 100644
index 0000000..b956ee6
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_16.S
@@ -0,0 +1,7 @@
+%verify "executed"
+    /* const/16 vAA, #+BBBB */
+    movswl  2(rPC),%ecx                # ecx<- ssssBBBB
+    FETCH_INST_OPCODE 2 %eax
+    ADVANCE_PC 2
+    SET_VREG %ecx rINST                # vAA<- ssssBBBB
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_CONST_4.S b/vm/mterp/x86/OP_CONST_4.S
new file mode 100644
index 0000000..3db437a
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_4.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* const/4 vA, #+B */
+    movsx   rINSTbl,%eax              # eax<-ssssssBx
+    movl    $$0xf,rINST
+    andl    %eax,rINST                # rINST<- A
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    sarl    $$4,%eax
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_CLASS.S b/vm/mterp/x86/OP_CONST_CLASS.S
new file mode 100644
index 0000000..8b12226
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_CLASS.S
@@ -0,0 +1,37 @@
+
+%verify "Class already resolved"
+%verify "Class not yet resolved"
+%verify "Class cannot be resolved"
+    /* const/class vAA, Class@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- dvmDex->pResClasses
+    movl      (%ecx,%eax,4),%eax       # eax<- rResClasses[BBBB]
+    testl     %eax,%eax                # resolved yet?
+    je        .L${opcode}_resolve
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG  %eax rINST               # vAA<- rResClasses[BBBB]
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.L${opcode}_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movl     $$1,OUT_ARG2(%esp)        # true
+    movzwl   2(rPC),%ecx               # ecx<- BBBB
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveClass           # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_CLASS_JUMBO.S b/vm/mterp/x86/OP_CONST_CLASS_JUMBO.S
new file mode 100644
index 0000000..ce64823
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_CLASS_JUMBO.S
@@ -0,0 +1,36 @@
+%verify "Class already resolved"
+%verify "Class not yet resolved"
+%verify "Class cannot be resolved"
+    /* const-class/jumbo vBBBB, Class@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax              # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- dvmDex->pResClasses
+    movl      (%ecx,%eax,4),%eax       # eax<- rResClasses[AAAAAAAA]
+    FETCH_INST_OPCODE 4 %ecx
+    testl     %eax,%eax                # resolved yet?
+    je        .L${opcode}_resolve
+    SET_VREG  %eax rINST               # vBBBB<- rResClasses[AAAAAAAA]
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.L${opcode}_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movl     $$1,OUT_ARG2(%esp)        # true
+    movl     2(rPC),%ecx               # ecx<- AAAAAAAA
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveClass           # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 4 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_HIGH16.S b/vm/mterp/x86/OP_CONST_HIGH16.S
new file mode 100644
index 0000000..9ecf7c6
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_HIGH16.S
@@ -0,0 +1,8 @@
+%verify "executed"
+    /* const/high16 vAA, #+BBBB0000 */
+    movzwl     2(rPC),%eax                # eax<- 0000BBBB
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    sall       $$16,%eax                  # eax<- BBBB0000
+    SET_VREG %eax rINST                   # vAA<- eax
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_STRING.S b/vm/mterp/x86/OP_CONST_STRING.S
new file mode 100644
index 0000000..538cace
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_STRING.S
@@ -0,0 +1,36 @@
+
+%verify "String already resolved"
+%verify "String not yet resolved"
+%verify "String cannot be resolved"
+    /* const/string vAA, String@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResStrings(%ecx),%ecx # ecx<- dvmDex->pResStrings
+    movl      (%ecx,%eax,4),%eax       # eax<- rResString[BBBB]
+    FETCH_INST_OPCODE 2 %ecx
+    testl     %eax,%eax                # resolved yet?
+    je        .L${opcode}_resolve
+    SET_VREG  %eax rINST               # vAA<- rResString[BBBB]
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.L${opcode}_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movzwl   2(rPC),%ecx               # ecx<- BBBB
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveString          # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_STRING_JUMBO.S b/vm/mterp/x86/OP_CONST_STRING_JUMBO.S
new file mode 100644
index 0000000..6148244
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_STRING_JUMBO.S
@@ -0,0 +1,36 @@
+
+%verify "String already resolved"
+%verify "String not yet resolved"
+%verify "String cannot be resolved"
+    /* const/string vAA, String@BBBBBBBB */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax              # eax<- BBBBBBBB
+    movl      offThread_methodClassDex(%ecx),%ecx# ecx<- self->methodClassDex
+    movl      offDvmDex_pResStrings(%ecx),%ecx # ecx<- dvmDex->pResStrings
+    movl      (%ecx,%eax,4),%eax       # eax<- rResString[BBBB]
+    FETCH_INST_OPCODE 3 %ecx
+    testl     %eax,%eax                # resolved yet?
+    je        .L${opcode}_resolve
+    SET_VREG  %eax rINST               # vAA<- rResString[BBBB]
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+/* This is the less common path, so we'll redo some work
+   here rather than force spills on the common path */
+.L${opcode}_resolve:
+    movl     rSELF,%eax
+    EXPORT_PC
+    movl     offThread_method(%eax),%eax # eax<- self->method
+    movl     2(rPC),%ecx               # ecx<- BBBBBBBB
+    movl     offMethod_clazz(%eax),%eax
+    movl     %ecx,OUT_ARG1(%esp)
+    movl     %eax,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveString          # go resolve
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                 # failed?
+    je       common_exceptionThrown
+    FETCH_INST_OPCODE 3 %ecx
+    SET_VREG %eax rINST
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_WIDE.S b/vm/mterp/x86/OP_CONST_WIDE.S
new file mode 100644
index 0000000..253af78
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_WIDE.S
@@ -0,0 +1,11 @@
+%verify "executed"
+    /* const-wide vAA, #+HHHHhhhhBBBBbbbb */
+    movl      2(rPC),%eax         # eax<- lsw
+    movzbl    rINSTbl,%ecx        # ecx<- AA
+    movl      6(rPC),rINST        # rINST<- msw
+    leal      (rFP,%ecx,4),%ecx   # dst addr
+    movl      rINST,4(%ecx)
+    movl      %eax,(%ecx)
+    FETCH_INST_OPCODE 5 %ecx
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_WIDE_16.S b/vm/mterp/x86/OP_CONST_WIDE_16.S
new file mode 100644
index 0000000..ee8004c
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_WIDE_16.S
@@ -0,0 +1,11 @@
+%verify "executed"
+    /* const-wide/16 vAA, #+BBBB */
+    movswl    2(rPC),%eax               # eax<- ssssBBBB
+    SPILL(rIBASE)                       # preserve rIBASE (cltd trashes it)
+    cltd                                # rIBASE:eax<- ssssssssssssBBBB
+    SET_VREG_WORD rIBASE rINST 1        # store msw
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 0          # store lsw
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_WIDE_32.S b/vm/mterp/x86/OP_CONST_WIDE_32.S
new file mode 100644
index 0000000..12cdd01
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_WIDE_32.S
@@ -0,0 +1,11 @@
+%verify "executed"
+    /* const-wide/32 vAA, #+BBBBbbbb */
+    movl     2(rPC),%eax                # eax<- BBBBbbbb
+    SPILL(rIBASE)                       # save rIBASE (cltd trashes it)
+    cltd                                # rIBASE:eax<- ssssssssssssBBBB
+    SET_VREG_WORD rIBASE rINST,1        # store msw
+    FETCH_INST_OPCODE 3 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 0          # store lsw
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S b/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S
new file mode 100644
index 0000000..15a0c55
--- /dev/null
+++ b/vm/mterp/x86/OP_CONST_WIDE_HIGH16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* const-wide/high16 vAA, #+BBBB000000000000 */
+    movzwl     2(rPC),%eax                # eax<- 0000BBBB
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    sall       $$16,%eax                  # eax<- BBBB0000
+    SET_VREG_WORD %eax rINST 1            # v[AA+1]<- eax
+    xorl       %eax,%eax
+    SET_VREG_WORD %eax rINST 0            # v[AA+0]<- eax
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_DISPATCH_FF.S b/vm/mterp/x86/OP_DISPATCH_FF.S
new file mode 100644
index 0000000..fbd5a3d
--- /dev/null
+++ b/vm/mterp/x86/OP_DISPATCH_FF.S
@@ -0,0 +1,3 @@
+%verify "executed"
+    leal      256(rINST),%ecx
+    GOTO_NEXT_JUMBO_R %ecx
diff --git a/vm/mterp/x86/OP_DIV_DOUBLE.S b/vm/mterp/x86/OP_DIV_DOUBLE.S
new file mode 100644
index 0000000..8ccff2e
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fdivl","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_DIV_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..60a0072
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fdivl","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_DIV_FLOAT.S b/vm/mterp/x86/OP_DIV_FLOAT.S
new file mode 100644
index 0000000..740e26e
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fdivs","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/x86/OP_DIV_FLOAT_2ADDR.S
new file mode 100644
index 0000000..2ed12b6
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fdivs","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_DIV_INT.S b/vm/mterp/x86/OP_DIV_INT.S
new file mode 100644
index 0000000..8afdcb0
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindiv.S" {"result":"%eax","special":"$0x80000000"}
diff --git a/vm/mterp/x86/OP_DIV_INT_2ADDR.S b/vm/mterp/x86/OP_DIV_INT_2ADDR.S
new file mode 100644
index 0000000..a1ae0f9
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindiv2addr.S" {"result":"%eax","special":"$0x80000000"}
diff --git a/vm/mterp/x86/OP_DIV_INT_LIT16.S b/vm/mterp/x86/OP_DIV_INT_LIT16.S
new file mode 100644
index 0000000..4817734
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindivLit16.S" {"result":"%eax","special":"$0x80000000"}
diff --git a/vm/mterp/x86/OP_DIV_INT_LIT8.S b/vm/mterp/x86/OP_DIV_INT_LIT8.S
new file mode 100644
index 0000000..f59838c
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindivLit8.S" {"result":"%eax","special":"$0x80000000"}
diff --git a/vm/mterp/x86/OP_DIV_LONG.S b/vm/mterp/x86/OP_DIV_LONG.S
new file mode 100644
index 0000000..0dc5546
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_LONG.S
@@ -0,0 +1,46 @@
+%verify "executed"
+%default {"routine":"__divdi3","special":"$0x80000000"}
+    /* div vAA, vBB, vCC */
+    movzbl    3(rPC),%eax              # eax<- CC
+    movzbl    2(rPC),%ecx              # ecx<- BB
+    SPILL(rIBASE)                      # save rIBASE/%edx
+    GET_VREG_WORD rIBASE %eax 0
+    GET_VREG_WORD %eax %eax 1
+    movl     rIBASE,OUT_ARG2(%esp)
+    testl    %eax,%eax
+    je       .L${opcode}_check_zero
+    cmpl     $$-1,%eax
+    je       .L${opcode}_check_neg1
+.L${opcode}_notSpecial:
+    GET_VREG_WORD rIBASE %ecx 0
+    GET_VREG_WORD %ecx %ecx 1
+.L${opcode}_notSpecial1:
+    movl     %eax,OUT_ARG3(%esp)
+    movl     rIBASE,OUT_ARG0(%esp)
+    movl     %ecx,OUT_ARG1(%esp)
+    call     $routine
+.L${opcode}_finish:
+    SET_VREG_WORD rIBASE rINST 1
+    UNSPILL(rIBASE)                 # restore rIBASE/%edx
+    SET_VREG_WORD %eax rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_check_zero:
+    testl   rIBASE,rIBASE
+    jne     .L${opcode}_notSpecial
+    jmp     common_errDivideByZero
+.L${opcode}_check_neg1:
+    testl   rIBASE,%eax
+    jne     .L${opcode}_notSpecial
+    GET_VREG_WORD rIBASE %ecx 0
+    GET_VREG_WORD %ecx %ecx 1
+    testl    rIBASE,rIBASE
+    jne      .L${opcode}_notSpecial1
+    cmpl     $$0x80000000,%ecx
+    jne      .L${opcode}_notSpecial1
+    /* minint / -1, return minint on div, 0 on rem */
+    xorl     %eax,%eax
+    movl     $special,rIBASE
+    jmp      .L${opcode}_finish
diff --git a/vm/mterp/x86/OP_DIV_LONG_2ADDR.S b/vm/mterp/x86/OP_DIV_LONG_2ADDR.S
new file mode 100644
index 0000000..4722098
--- /dev/null
+++ b/vm/mterp/x86/OP_DIV_LONG_2ADDR.S
@@ -0,0 +1,47 @@
+%verify "executed"
+%default {"routine":"__divdi3","special":"$0x80000000"}
+    /* div/2addr vA, vB */
+    movzbl    rINSTbl,%eax
+    shrl      $$4,%eax                  # eax<- B
+    andb      $$0xf,rINSTbl             # rINST<- A
+    SPILL(rIBASE)                       # save rIBASE/%edx
+    GET_VREG_WORD rIBASE %eax 0
+    GET_VREG_WORD %eax %eax 1
+    movl     rIBASE,OUT_ARG2(%esp)
+    testl    %eax,%eax
+    je       .L${opcode}_check_zero
+    cmpl     $$-1,%eax
+    je       .L${opcode}_check_neg1
+.L${opcode}_notSpecial:
+    GET_VREG_WORD rIBASE rINST 0
+    GET_VREG_WORD %ecx rINST 1
+.L${opcode}_notSpecial1:
+    movl     %eax,OUT_ARG3(%esp)
+    movl     rIBASE,OUT_ARG0(%esp)
+    movl     %ecx,OUT_ARG1(%esp)
+    call     $routine
+.L${opcode}_finish:
+    SET_VREG_WORD rIBASE rINST 1
+    UNSPILL(rIBASE)                    # restore rIBASE/%edx
+    SET_VREG_WORD %eax rINST 0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_check_zero:
+    testl   rIBASE,rIBASE
+    jne     .L${opcode}_notSpecial
+    jmp     common_errDivideByZero
+.L${opcode}_check_neg1:
+    testl   rIBASE,%eax
+    jne     .L${opcode}_notSpecial
+    GET_VREG_WORD rIBASE rINST 0
+    GET_VREG_WORD %ecx rINST 1
+    testl    rIBASE,rIBASE
+    jne      .L${opcode}_notSpecial1
+    cmpl     $$0x80000000,%ecx
+    jne      .L${opcode}_notSpecial1
+    /* minint / -1, return minint on div, 0 on rem */
+    xorl     %eax,%eax
+    movl     $special,rIBASE
+    jmp      .L${opcode}_finish
diff --git a/vm/mterp/x86/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/x86/OP_DOUBLE_TO_FLOAT.S
new file mode 100644
index 0000000..12e73a2
--- /dev/null
+++ b/vm/mterp/x86/OP_DOUBLE_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"load":"fldl","store":"fstps"}
diff --git a/vm/mterp/x86/OP_DOUBLE_TO_INT.S b/vm/mterp/x86/OP_DOUBLE_TO_INT.S
new file mode 100644
index 0000000..7cd993a
--- /dev/null
+++ b/vm/mterp/x86/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/cvtfp_int.S" {"srcdouble":"1","tgtlong":"0"}
diff --git a/vm/mterp/x86/OP_DOUBLE_TO_LONG.S b/vm/mterp/x86/OP_DOUBLE_TO_LONG.S
new file mode 100644
index 0000000..b80b020
--- /dev/null
+++ b/vm/mterp/x86/OP_DOUBLE_TO_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/cvtfp_int.S" {"srcdouble":"1","tgtlong":"1"}
diff --git a/vm/mterp/x86/OP_EXECUTE_INLINE.S b/vm/mterp/x86/OP_EXECUTE_INLINE.S
new file mode 100644
index 0000000..ec91076
--- /dev/null
+++ b/vm/mterp/x86/OP_EXECUTE_INLINE.S
@@ -0,0 +1,66 @@
+%verify "executed"
+%verify "exception handled"
+    /*
+     * Execute a "native inline" instruction.
+     *
+     * We will be calling through a function table:
+     *
+     * (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult)
+     *
+     * Ignores argument count - always loads 4.
+     *
+     */
+    /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+    movl      rSELF,%ecx
+    EXPORT_PC
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    leal      offThread_retval(%ecx),%ecx # ecx<- & self->retval
+    SPILL(rIBASE)                       # preserve rIBASE
+    movl      %ecx,OUT_ARG4(%esp)
+    call      .L${opcode}_continue      # make call; will return after
+    UNSPILL(rIBASE)                     # restore rIBASE
+    testl     %eax,%eax                 # successful?
+    FETCH_INST_OPCODE 3 %ecx
+    je        common_exceptionThrown    # no, handle exception
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_continue:
+    /*
+     * Extract args, call function.
+     *  ecx = #of args (0-4)
+     *  eax = call index
+     *  @esp = return addr
+     *  esp is -4 from normal
+     *
+     *  Go ahead and load all 4 args, even if not used.
+     */
+    movzwl    4(rPC),rIBASE
+
+    movl      $$0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $$4,rIBASE
+    movl      %ecx,4+OUT_ARG0(%esp)
+
+    movl      $$0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $$4,rIBASE
+    movl      %ecx,4+OUT_ARG1(%esp)
+
+    movl      $$0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $$4,rIBASE
+    movl      %ecx,4+OUT_ARG2(%esp)
+
+    movl      $$0xf,%ecx
+    andl      rIBASE,%ecx
+    GET_VREG_R  %ecx %ecx
+    sarl      $$4,rIBASE
+    movl      %ecx,4+OUT_ARG3(%esp)
+
+    sall      $$4,%eax      # index *= sizeof(table entry)
+    jmp       *gDvmInlineOpsTable(%eax)
+    # will return to caller of .L${opcode}_continue
diff --git a/vm/mterp/x86/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/x86/OP_EXECUTE_INLINE_RANGE.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_EXECUTE_INLINE_RANGE.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S b/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
new file mode 100644
index 0000000..dde53aa
--- /dev/null
+++ b/vm/mterp/x86/OP_FILLED_NEW_ARRAY.S
@@ -0,0 +1,129 @@
+%default { "isrange":"0" }
+%verify "executed"
+%verify "unimplemented array type"
+    /*
+     * 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 */
+    movl    rSELF,%eax
+    movl    offThread_methodClassDex(%eax),%eax # eax<- pDvmDex
+    movzwl  2(rPC),%ecx                       # ecx<- BBBB
+    movl    offDvmDex_pResClasses(%eax),%eax  # eax<- pDvmDex->pResClasses
+    SPILL(rIBASE)                             # preserve rIBASE
+    movl    (%eax,%ecx,4),%eax                # eax<- resolved class
+    EXPORT_PC
+    testl   %eax,%eax                         # already resolved?
+    jne     .L${opcode}_continue              # yes, continue
+    # less frequent path, so we'll redo some work
+    movl    rSELF,%eax
+    movl    $$0,OUT_ARG2(%esp)                # arg2<- false
+    movl    %ecx,OUT_ARG1(%esp)               # arg1<- BBBB
+    movl    offThread_method(%eax),%eax         # eax<- self->method
+    movl    offMethod_clazz(%eax),%eax        # eax<- method->clazz
+    movl    %eax,OUT_ARG0(%esp)               # arg0<- clazz
+    call    dvmResolveClass                   # eax<- call(clazz,ref,flag)
+    testl   %eax,%eax                         # null?
+    je      common_exceptionThrown            # yes, handle it
+
+       # note: fall through to .L${opcode}_continue
+
+    /*
+     * On entry:
+     *    eax holds array class [r0]
+     *    rINST holds AA or BB [r10]
+     *    ecx is scratch
+     */
+.L${opcode}_continue:
+    movl    offClassObject_descriptor(%eax),%ecx  # ecx<- arrayClass->descriptor
+    movl    $$ALLOC_DONT_TRACK,OUT_ARG2(%esp)     # arg2<- flags
+    movzbl  1(%ecx),%ecx                          # ecx<- descriptor[1]
+    movl    %eax,OUT_ARG0(%esp)                   # arg0<- arrayClass
+    movl    rSELF,%eax
+    cmpb    $$'I',%cl                             # supported?
+    je      1f
+    cmpb    $$'L',%cl
+    je      1f
+    cmpb    $$'[',%cl
+    jne      .L${opcode}_notimpl                  # no, not handled yet
+1:
+    movl    %ecx,offThread_retval+4(%eax)           # save type
+    .if      (!$isrange)
+    SPILL_TMP1(rINST)                              # save copy, need "B" later
+    sarl    $$4,rINST
+    .endif
+    movl    rINST,OUT_ARG1(%esp)                  # arg1<- A or AA (length)
+    call    dvmAllocArrayByClass     # eax<- call(arrayClass, length, flags)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                             # alloc successful?
+    je      common_exceptionThrown                # no, handle exception
+    movl    %eax,offThread_retval(%ecx)             # retval.l<- new array
+    movzwl  4(rPC),%ecx                           # ecx<- FEDC or CCCC
+    leal    offArrayObject_contents(%eax),%eax    # eax<- newArray->contents
+
+/* at this point:
+ *     eax is pointer to tgt
+ *     rINST is length
+ *     ecx is FEDC or CCCC
+ *     TMP_SPILL1 is BA
+ *  We now need to copy values from registers into the array
+ */
+
+    .if $isrange
+    # set up src pointer
+    SPILL_TMP2(%esi)
+    SPILL_TMP3(%edi)
+    leal    (rFP,%ecx,4),%esi # set up src ptr
+    movl    %eax,%edi         # set up dst ptr
+    movl    rINST,%ecx        # load count register
+    rep
+    movsd
+    UNSPILL_TMP2(%esi)
+    UNSPILL_TMP3(%edi)
+    movl    rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+    .else
+    testl  rINST,rINST
+    je     4f
+    UNSPILL_TMP1(rIBASE)      # restore "BA"
+    andl   $$0x0f,rIBASE      # rIBASE<- 0000000A
+    sall   $$16,rIBASE        # rIBASE<- 000A0000
+    orl    %ecx,rIBASE        # rIBASE<- 000AFEDC
+3:
+    movl   $$0xf,%ecx
+    andl   rIBASE,%ecx        # ecx<- next reg to load
+    GET_VREG_R %ecx %ecx
+    shrl   $$4,rIBASE
+    leal   4(%eax),%eax
+    movl   %ecx,-4(%eax)
+    sub    $$1,rINST
+    jne    3b
+4:
+    movl   rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+    .endif
+
+    cmpb    $$'I',%al                        # Int array?
+    je      5f                               # skip card mark if so
+    movl    offThread_retval(%ecx),%eax        # eax<- object head
+    movl    offThread_cardTable(%ecx),%ecx     # card table base
+    shrl    $$GC_CARD_SHIFT,%eax             # convert to card num
+    movb    %cl,(%ecx,%eax)                  # mark card based on object head
+5:
+    UNSPILL(rIBASE)                          # restore rIBASE
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
+
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.L${opcode}_notimpl:
+    movl    $$.LstrFilledNewArrayNotImplA,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowInternalError
+    jmp     common_exceptionThrown
diff --git a/vm/mterp/x86/OP_FILLED_NEW_ARRAY_JUMBO.S b/vm/mterp/x86/OP_FILLED_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..80f2b38
--- /dev/null
+++ b/vm/mterp/x86/OP_FILLED_NEW_ARRAY_JUMBO.S
@@ -0,0 +1,100 @@
+%verify "executed"
+%verify "unimplemented array type"
+    /*
+     * Create a new array with elements filled from registers.
+     */
+    /* filled-new-array/jumbo {vCCCC..v(CCCC+BBBB-1)}, type@AAAAAAAA */
+    movl    rSELF,%eax
+    movl    offThread_methodClassDex(%eax),%eax # eax<- pDvmDex
+    movl    2(rPC),%ecx                       # ecx<- AAAAAAAA
+    movl    offDvmDex_pResClasses(%eax),%eax  # eax<- pDvmDex->pResClasses
+    movl    (%eax,%ecx,4),%eax                # eax<- resolved class
+    EXPORT_PC
+    testl   %eax,%eax                         # already resolved?
+    jne     .L${opcode}_continue              # yes, continue
+    # less frequent path, so we'll redo some work
+    movl    rSELF,%eax
+    movl    $$0,OUT_ARG2(%esp)                # arg2<- false
+    movl    %ecx,OUT_ARG1(%esp)               # arg1<- AAAAAAAA
+    movl    offThread_method(%eax),%eax         # eax<- self->method
+    movl    offMethod_clazz(%eax),%eax        # eax<- method->clazz
+    movl    %eax,OUT_ARG0(%esp)               # arg0<- clazz
+    SPILL(rIBASE)
+    call    dvmResolveClass                   # eax<- call(clazz,ref,flag)
+    UNSPILL(rIBASE)
+    testl   %eax,%eax                         # null?
+    je      common_exceptionThrown            # yes, handle it
+
+       # note: fall through to .L${opcode}_continue
+
+    /*
+     * On entry:
+     *    eax holds array class [r0]
+     *    ecx is scratch
+     */
+.L${opcode}_continue:
+    movl    offClassObject_descriptor(%eax),%ecx  # ecx<- arrayClass->descriptor
+    movl    $$ALLOC_DONT_TRACK,OUT_ARG2(%esp)     # arg2<- flags
+    movzbl  1(%ecx),%ecx                          # ecx<- descriptor[1]
+    movl    %eax,OUT_ARG0(%esp)                   # arg0<- arrayClass
+    movl    rSELF,%eax
+    cmpb    $$'I',%cl                             # supported?
+    je      1f
+    cmpb    $$'L',%cl
+    je      1f
+    cmpb    $$'[',%cl
+    jne      .L${opcode}_notimpl                  # no, not handled yet
+1:
+    movl    %ecx,offThread_retval+4(%eax)           # save type
+    movl    rINST,OUT_ARG1(%esp)                  # arg1<- BBBB (length)
+    SPILL(rIBASE)
+    call    dvmAllocArrayByClass     # eax<- call(arrayClass, length, flags)
+    UNSPILL(rIBASE)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                             # alloc successful?
+    je      common_exceptionThrown                # no, handle exception
+    movl    %eax,offThread_retval(%ecx)             # retval.l<- new array
+    movzwl  8(rPC),%ecx                           # ecx<- CCCC
+    leal    offArrayObject_contents(%eax),%eax    # eax<- newArray->contents
+
+/* at this point:
+ *     eax is pointer to tgt
+ *     rINST is length
+ *     ecx is CCCC
+ *  We now need to copy values from registers into the array
+ */
+
+    # set up src pointer
+    SPILL_TMP2(%esi)
+    SPILL_TMP3(%edi)
+    leal    (rFP,%ecx,4),%esi # set up src ptr
+    movl    %eax,%edi         # set up dst ptr
+    movl    rINST,%ecx        # load count register
+    rep
+    movsd
+    UNSPILL_TMP2(%esi)
+    UNSPILL_TMP3(%edi)
+    movl    rSELF,%ecx
+    movl    offThread_retval+4(%ecx),%eax      # eax<- type
+
+    cmpb    $$'I',%al                        # Int array?
+    je      5f                               # skip card mark if so
+    movl    offThread_retval(%ecx),%eax        # eax<- object head
+    movl    offThread_cardTable(%ecx),%ecx     # card table base
+    shrl    $$GC_CARD_SHIFT,%eax             # convert to card num
+    movb    %cl,(%ecx,%eax)                  # mark card based on object head
+5:
+    FETCH_INST_OPCODE 5 %ecx
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
+
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.L${opcode}_notimpl:
+    movl    $$.LstrFilledNewArrayNotImplA,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowInternalError
+    jmp     common_exceptionThrown
diff --git a/vm/mterp/x86/OP_FILLED_NEW_ARRAY_RANGE.S b/vm/mterp/x86/OP_FILLED_NEW_ARRAY_RANGE.S
new file mode 100644
index 0000000..dc6cc4d
--- /dev/null
+++ b/vm/mterp/x86/OP_FILLED_NEW_ARRAY_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_FILLED_NEW_ARRAY.S" { "isrange":"1" }
diff --git a/vm/mterp/x86/OP_FILL_ARRAY_DATA.S b/vm/mterp/x86/OP_FILL_ARRAY_DATA.S
new file mode 100644
index 0000000..5ca17a6
--- /dev/null
+++ b/vm/mterp/x86/OP_FILL_ARRAY_DATA.S
@@ -0,0 +1,16 @@
+%verify "executed"
+    /* fill-array-data vAA, +BBBBBBBB */
+    movl    2(rPC),%ecx                # ecx<- BBBBbbbb
+    leal    (rPC,%ecx,2),%ecx          # ecx<- PC + BBBBbbbb*2
+    GET_VREG_R %eax rINST
+    EXPORT_PC
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    SPILL(rIBASE)
+    call    dvmInterpHandleFillArrayData
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 3 %ecx
+    testl   %eax,%eax                   # exception thrown?
+    je      common_exceptionThrown
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/x86/OP_FLOAT_TO_DOUBLE.S
new file mode 100644
index 0000000..11b2c23
--- /dev/null
+++ b/vm/mterp/x86/OP_FLOAT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"load":"flds","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_FLOAT_TO_INT.S b/vm/mterp/x86/OP_FLOAT_TO_INT.S
new file mode 100644
index 0000000..8d55286
--- /dev/null
+++ b/vm/mterp/x86/OP_FLOAT_TO_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/cvtfp_int.S" {"srcdouble":"0","tgtlong":"0"}
diff --git a/vm/mterp/x86/OP_FLOAT_TO_LONG.S b/vm/mterp/x86/OP_FLOAT_TO_LONG.S
new file mode 100644
index 0000000..2493b13
--- /dev/null
+++ b/vm/mterp/x86/OP_FLOAT_TO_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/cvtfp_int.S" {"srcdouble":"0","tgtlong":"1"}
diff --git a/vm/mterp/x86/OP_GOTO.S b/vm/mterp/x86/OP_GOTO.S
new file mode 100644
index 0000000..2fc4c31
--- /dev/null
+++ b/vm/mterp/x86/OP_GOTO.S
@@ -0,0 +1,15 @@
+%verify "executed"
+%verify "forward and backward"
+    /*
+     * 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 */
+    movl    rSELF,%ecx
+    movsbl  rINSTbl,%eax          # eax<- ssssssAA
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
diff --git a/vm/mterp/x86/OP_GOTO_16.S b/vm/mterp/x86/OP_GOTO_16.S
new file mode 100644
index 0000000..de0903c
--- /dev/null
+++ b/vm/mterp/x86/OP_GOTO_16.S
@@ -0,0 +1,14 @@
+%verify "executed"
+%verify "forward and backward"
+    /*
+     * Unconditional branch, 16-bit offset.
+     *
+     * The branch distance is a signed code-unit offset
+     */
+    /* goto/16 +AAAA */
+    movl    rSELF,%ecx
+    movswl  2(rPC),%eax            # eax<- ssssAAAA
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
diff --git a/vm/mterp/x86/OP_GOTO_32.S b/vm/mterp/x86/OP_GOTO_32.S
new file mode 100644
index 0000000..84806b0
--- /dev/null
+++ b/vm/mterp/x86/OP_GOTO_32.S
@@ -0,0 +1,14 @@
+%verify "executed"
+%verify "forward, backward, self"
+    /*
+     * Unconditional branch, 32-bit offset.
+     *
+     * The branch distance is a signed code-unit offset.
+     */
+    /* goto/32 AAAAAAAA */
+    movl    rSELF,%ecx
+    movl    2(rPC),%eax            # eax<- AAAAAAAA
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
diff --git a/vm/mterp/x86/OP_IF_EQ.S b/vm/mterp/x86/OP_IF_EQ.S
new file mode 100644
index 0000000..a8a38b6
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_EQ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bincmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/x86/OP_IF_EQZ.S b/vm/mterp/x86/OP_IF_EQZ.S
new file mode 100644
index 0000000..67fd5d7
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_EQZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/zcmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/x86/OP_IF_GE.S b/vm/mterp/x86/OP_IF_GE.S
new file mode 100644
index 0000000..6930328
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_GE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bincmp.S" { "revcmp":"l" }
diff --git a/vm/mterp/x86/OP_IF_GEZ.S b/vm/mterp/x86/OP_IF_GEZ.S
new file mode 100644
index 0000000..71e9127
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_GEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/zcmp.S" { "revcmp":"l" }
diff --git a/vm/mterp/x86/OP_IF_GT.S b/vm/mterp/x86/OP_IF_GT.S
new file mode 100644
index 0000000..b987443
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_GT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bincmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/x86/OP_IF_GTZ.S b/vm/mterp/x86/OP_IF_GTZ.S
new file mode 100644
index 0000000..9d7b697
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_GTZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/zcmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/x86/OP_IF_LE.S b/vm/mterp/x86/OP_IF_LE.S
new file mode 100644
index 0000000..b9ac008
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_LE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bincmp.S" { "revcmp":"g" }
diff --git a/vm/mterp/x86/OP_IF_LEZ.S b/vm/mterp/x86/OP_IF_LEZ.S
new file mode 100644
index 0000000..26afc85
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_LEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/zcmp.S" { "revcmp":"g" }
diff --git a/vm/mterp/x86/OP_IF_LT.S b/vm/mterp/x86/OP_IF_LT.S
new file mode 100644
index 0000000..79aba48
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_LT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bincmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/x86/OP_IF_LTZ.S b/vm/mterp/x86/OP_IF_LTZ.S
new file mode 100644
index 0000000..01f4daa
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_LTZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/zcmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/x86/OP_IF_NE.S b/vm/mterp/x86/OP_IF_NE.S
new file mode 100644
index 0000000..552b74c
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_NE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bincmp.S" { "revcmp":"e" }
diff --git a/vm/mterp/x86/OP_IF_NEZ.S b/vm/mterp/x86/OP_IF_NEZ.S
new file mode 100644
index 0000000..b2fdb14
--- /dev/null
+++ b/vm/mterp/x86/OP_IF_NEZ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/zcmp.S" { "revcmp":"e" }
diff --git a/vm/mterp/x86/OP_IGET.S b/vm/mterp/x86/OP_IGET.S
new file mode 100644
index 0000000..5740690
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET.S
@@ -0,0 +1,53 @@
+%default { "load":"movl", "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 */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $$4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $$0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    $load   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 2 %eax
+    UNSPILL(rIBASE)
+    SET_VREG %ecx rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_IGET_BOOLEAN.S b/vm/mterp/x86/OP_IGET_BOOLEAN.S
new file mode 100644
index 0000000..0829e2c
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IGET.S" { "load":"movzbl", "sqnum":"1" }
diff --git a/vm/mterp/x86/OP_IGET_BOOLEAN_JUMBO.S b/vm/mterp/x86/OP_IGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..726fa3e
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IGET_JUMBO.S" { "load":"movzbl", "sqnum":"1" }
diff --git a/vm/mterp/x86/OP_IGET_BYTE.S b/vm/mterp/x86/OP_IGET_BYTE.S
new file mode 100644
index 0000000..2350f8c
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_BYTE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET.S" { "load":"movsbl", "sqnum":"2" }
diff --git a/vm/mterp/x86/OP_IGET_BYTE_JUMBO.S b/vm/mterp/x86/OP_IGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..88c3dfd
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_BYTE_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET_JUMBO.S" { "load":"movsbl", "sqnum":"2" }
diff --git a/vm/mterp/x86/OP_IGET_CHAR.S b/vm/mterp/x86/OP_IGET_CHAR.S
new file mode 100644
index 0000000..4218a8c
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_CHAR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "large values are not sign-extended"
+%include "x86/OP_IGET.S" { "load":"movzwl", "sqnum":"3" }
diff --git a/vm/mterp/x86/OP_IGET_CHAR_JUMBO.S b/vm/mterp/x86/OP_IGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..f654d77
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_CHAR_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "large values are not sign-extended"
+%include "x86/OP_IGET_JUMBO.S" { "load":"movzwl", "sqnum":"3" }
diff --git a/vm/mterp/x86/OP_IGET_JUMBO.S b/vm/mterp/x86/OP_IGET_JUMBO.S
new file mode 100644
index 0000000..da88f65
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_JUMBO.S
@@ -0,0 +1,52 @@
+%default { "load":"movl", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit instance field get.
+     *
+     * for: iget/jumbo, iget-object/jumbo, iget-boolean/jumbo, iget-byte/jumbo,
+     *      iget-char/jumbo, iget-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # needed by dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    $load   (%ecx,%eax,1),%ecx                  # ecx<- obj.field (8/16/32 bits)
+    FETCH_INST_OPCODE 5 %eax
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG %ecx rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_IGET_OBJECT.S b/vm/mterp/x86/OP_IGET_OBJECT.S
new file mode 100644
index 0000000..84c0a98
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86/OP_IGET_OBJECT_JUMBO.S b/vm/mterp/x86/OP_IGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..3fc93e0
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_OBJECT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IGET_JUMBO.S"
diff --git a/vm/mterp/x86/OP_IGET_OBJECT_QUICK.S b/vm/mterp/x86/OP_IGET_OBJECT_QUICK.S
new file mode 100644
index 0000000..89ebd36
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_OBJECT_QUICK.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IGET_QUICK.S"
diff --git a/vm/mterp/x86/OP_IGET_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_IGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..4576d39
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_OBJECT_VOLATILE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86/OP_IGET_QUICK.S b/vm/mterp/x86/OP_IGET_QUICK.S
new file mode 100644
index 0000000..86f1f66
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+    /* For: iget-quick, iget-object-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $$4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    cmpl      $$0,%ecx                  # is object null?
+    je        common_errNullObject
+    movl      (%ecx,%eax,1),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    andb      $$0xf,rINSTbl             # rINST<- A
+    SET_VREG  %eax rINST                # fp[A]<- result
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IGET_SHORT.S b/vm/mterp/x86/OP_IGET_SHORT.S
new file mode 100644
index 0000000..71f0d34
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_SHORT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET.S" { "load":"movswl", "sqnum":"4" }
diff --git a/vm/mterp/x86/OP_IGET_SHORT_JUMBO.S b/vm/mterp/x86/OP_IGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..4ead149
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_SHORT_JUMBO.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET_JUMBO.S" { "load":"movswl", "sqnum":"4" }
diff --git a/vm/mterp/x86/OP_IGET_VOLATILE.S b/vm/mterp/x86/OP_IGET_VOLATILE.S
new file mode 100644
index 0000000..4576d39
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_VOLATILE.S
@@ -0,0 +1,3 @@
+%verify "executed"
+%verify "negative value is sign-extended"
+%include "x86/OP_IGET.S"
diff --git a/vm/mterp/x86/OP_IGET_WIDE.S b/vm/mterp/x86/OP_IGET_WIDE.S
new file mode 100644
index 0000000..723c9b7
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_WIDE.S
@@ -0,0 +1,54 @@
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 64-bit instance field get.
+     *
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $$4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $$0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # for dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save objpointer across call
+    movl    rPC,OUT_ARG0(%esp)                  # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    movl    (%eax),%ecx                         # ecx<- lsw
+    movl    4(%eax),%eax                        # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IGET_WIDE_JUMBO.S b/vm/mterp/x86/OP_IGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..5e253d5
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_WIDE_JUMBO.S
@@ -0,0 +1,51 @@
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit instance field get.
+     */
+    /* iget-wide/jumbo vBBBB, vCCCC, field@AAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)                               # preserve rIBASE
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)               # for dvmResolveInstField
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save objpointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    movl    (%eax),%ecx                         # ecx<- lsw
+    movl    4(%eax),%eax                        # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)                             # restore rIBASE
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IGET_WIDE_QUICK.S b/vm/mterp/x86/OP_IGET_WIDE_QUICK.S
new file mode 100644
index 0000000..dd63c73
--- /dev/null
+++ b/vm/mterp/x86/OP_IGET_WIDE_QUICK.S
@@ -0,0 +1,19 @@
+%verify "executed"
+%verify "null object"
+    /* For: iget-wide-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $$4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    cmpl      $$0,%ecx                  # is object null?
+    je        common_errNullObject
+    leal      (%ecx,%eax,1),%eax        # eax<- address of 64-bit source
+    movl      (%eax),%ecx               # ecx<- lsw
+    movl      4(%eax),%eax              # eax<- msw
+    andb      $$0xf,rINSTbl             # rINST<- A
+    SET_VREG_WORD %ecx rINST 0          # v[A+0]<- lsw
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG_WORD %eax rINST 1          # v[A+1]<- msw
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_INSTANCE_OF.S b/vm/mterp/x86/OP_INSTANCE_OF.S
new file mode 100644
index 0000000..c54f4f7
--- /dev/null
+++ b/vm/mterp/x86/OP_INSTANCE_OF.S
@@ -0,0 +1,93 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * 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 */
+    movl    rINST,%eax                  # eax<- BA
+    sarl    $$4,%eax                    # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB (obj)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                   # object null?
+    movl    offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    SPILL(rIBASE)                       # preserve rIBASE
+    je      .L${opcode}_store           # null obj, not instance, store it
+    movzwl  2(rPC),rIBASE               # rIBASE<- CCCC
+    movl    offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    movl    (%ecx,rIBASE,4),%ecx        # ecx<- resolved class
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    testl   %ecx,%ecx                   # have we resolved this before?
+    je      .L${opcode}_resolve         # not resolved, do it now
+.L${opcode}_resolved:  # eax<- obj->clazz, ecx<- resolved class
+    cmpl    %eax,%ecx                   # same class (trivial success)?
+    je      .L${opcode}_trivial         # yes, trivial finish
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  eax holds obj->clazz
+     *  ecx holds class resolved from BBBB
+     *  rINST has BA
+     */
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    call    dvmInstanceofNonTrivial     # eax<- boolean result
+    # fall through to ${opcode}_store
+
+    /*
+     * eax holds boolean result
+     * rINST holds BA
+     */
+.L${opcode}_store:
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    andb    $$0xf,rINSTbl               # <- A
+    ADVANCE_PC 2
+    SET_VREG %eax rINST                 # vA<- eax
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds A
+     */
+.L${opcode}_trivial:
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    andb    $$0xf,rINSTbl               # <- A
+    ADVANCE_PC 2
+    movl    $$1,%eax
+    SET_VREG %eax rINST                 # vA<- true
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  rIBASE holds BBBB
+     *  rINST holds BA
+     */
+.L${opcode}_resolve:
+    movl    rIBASE,OUT_ARG1(%esp)         # arg1<- BBBB
+    movl    rSELF,%ecx
+    movl    offThread_method(%ecx),%ecx
+    movl    $$1,OUT_ARG2(%esp)          # arg2<- true
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    EXPORT_PC
+    movl    %ecx,OUT_ARG0(%esp)         # arg0<- method->clazz
+    call    dvmResolveClass             # eax<- resolved ClassObject ptr
+    testl   %eax,%eax                   # success?
+    je      common_exceptionThrown      # no, handle exception
+/* Now, we need to sync up with fast path.  We need eax to
+ * hold the obj->clazz, and ecx to hold the resolved class
+ */
+    movl    %eax,%ecx                   # ecx<- resolved class
+    movl    rINST,%eax                  # eax<- BA
+    sarl    $$4,%eax                    # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB (obj)
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    jmp     .L${opcode}_resolved
diff --git a/vm/mterp/x86/OP_INSTANCE_OF_JUMBO.S b/vm/mterp/x86/OP_INSTANCE_OF_JUMBO.S
new file mode 100644
index 0000000..590277e
--- /dev/null
+++ b/vm/mterp/x86/OP_INSTANCE_OF_JUMBO.S
@@ -0,0 +1,88 @@
+%verify "executed"
+%verify "null object"
+%verify "class cast exception thrown, with correct class name"
+%verify "class cast exception not thrown on same class"
+%verify "class cast exception not thrown on subclass"
+%verify "class not resolved"
+%verify "class already resolved"
+    /*
+     * 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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    movzwl  8(rPC),%eax                 # eax<- CCCC
+    GET_VREG_R %eax %eax                # eax<- vCCCC (obj)
+    movl    rSELF,%ecx
+    testl   %eax,%eax                   # object null?
+    movl    offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    SPILL(rIBASE)                       # preserve rIBASE
+    je      .L${opcode}_store           # null obj, not instance, store it
+    movl    2(rPC),rIBASE               # edx<- AAAAAAAA
+    movl    offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    movl    (%ecx,rIBASE,4),%ecx        # ecx<- resolved class
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    testl   %ecx,%ecx                   # have we resolved this before?
+    je      .L${opcode}_resolve         # not resolved, do it now
+.L${opcode}_resolved:  # eax<- obj->clazz, ecx<- resolved class
+    cmpl    %eax,%ecx                   # same class (trivial success)?
+    je      .L${opcode}_trivial         # yes, trivial finish
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  eax holds obj->clazz
+     *  ecx holds class resolved from BBBB
+     *  rINST has BA
+     */
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    call    dvmInstanceofNonTrivial     # eax<- boolean result
+    # fall through to ${opcode}_store
+
+    /*
+     * eax holds boolean result
+     * rINST holds BBBB
+     */
+.L${opcode}_store:
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    SET_VREG %eax rINST                 # vBBBB<- eax
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds BBBB
+     */
+.L${opcode}_trivial:
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    movl    $$1,%eax
+    SET_VREG %eax rINST                 # vBBBB<- true
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  edx holds AAAAAAAA
+     */
+.L${opcode}_resolve:
+    movl    rIBASE,OUT_ARG1(%esp)       # arg1<- AAAAAAAA
+    movl    rSELF,%ecx
+    movl    offThread_method(%ecx),%ecx
+    movl    $$1,OUT_ARG2(%esp)          # arg2<- true
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    EXPORT_PC
+    movl    %ecx,OUT_ARG0(%esp)         # arg0<- method->clazz
+    call    dvmResolveClass             # eax<- resolved ClassObject ptr
+    testl   %eax,%eax                   # success?
+    je      common_exceptionThrown      # no, handle exception
+/* Now, we need to sync up with fast path.  We need eax to
+ * hold the obj->clazz, and ecx to hold the resolved class
+ */
+    movl    %eax,%ecx                   # ecx<- resolved class
+    movzwl  8(rPC),%eax                 # eax<- CCCC
+    GET_VREG_R %eax %eax                # eax<- vCCCC (obj)
+    movl    offObject_clazz(%eax),%eax  # eax<- obj->clazz
+    jmp     .L${opcode}_resolved
diff --git a/vm/mterp/x86/OP_INT_TO_BYTE.S b/vm/mterp/x86/OP_INT_TO_BYTE.S
new file mode 100644
index 0000000..44d032b
--- /dev/null
+++ b/vm/mterp/x86/OP_INT_TO_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/unop.S" {"instr":"movsbl %al,%eax"}
diff --git a/vm/mterp/x86/OP_INT_TO_CHAR.S b/vm/mterp/x86/OP_INT_TO_CHAR.S
new file mode 100644
index 0000000..49c8055
--- /dev/null
+++ b/vm/mterp/x86/OP_INT_TO_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/unop.S" {"instr":"movzwl %ax,%eax"}
diff --git a/vm/mterp/x86/OP_INT_TO_DOUBLE.S b/vm/mterp/x86/OP_INT_TO_DOUBLE.S
new file mode 100644
index 0000000..e9c5640
--- /dev/null
+++ b/vm/mterp/x86/OP_INT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"load":"fildl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_INT_TO_FLOAT.S b/vm/mterp/x86/OP_INT_TO_FLOAT.S
new file mode 100644
index 0000000..06d658d
--- /dev/null
+++ b/vm/mterp/x86/OP_INT_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"load":"fildl","store":"fstps"}
diff --git a/vm/mterp/x86/OP_INT_TO_LONG.S b/vm/mterp/x86/OP_INT_TO_LONG.S
new file mode 100644
index 0000000..551efaf
--- /dev/null
+++ b/vm/mterp/x86/OP_INT_TO_LONG.S
@@ -0,0 +1,14 @@
+%verify "executed"
+    /* int to long vA, vB */
+    movzbl  rINSTbl,%eax                # eax<- +A
+    sarl    $$4,%eax                    # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    andb    $$0xf,rINSTbl               # rINST<- A
+    SPILL(rIBASE)                       # cltd trashes rIBASE/edx
+    cltd                                # rINST:eax<- sssssssBBBBBBBB
+    SET_VREG_WORD rIBASE rINST 1        # v[A+1]<- rIBASE/rPC
+    FETCH_INST_OPCODE 1 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0          # v[A+0]<- %eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_INT_TO_SHORT.S b/vm/mterp/x86/OP_INT_TO_SHORT.S
new file mode 100644
index 0000000..d5dc5d8
--- /dev/null
+++ b/vm/mterp/x86/OP_INT_TO_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/unop.S" {"instr":"movswl %ax,%eax"}
diff --git a/vm/mterp/x86/OP_INVOKE_DIRECT.S b/vm/mterp/x86/OP_INVOKE_DIRECT.S
new file mode 100644
index 0000000..7d27c6f
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_DIRECT.S
@@ -0,0 +1,53 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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 */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax              # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movzwl    4(rPC),rIBASE            # rIBASE<- GFED or CCCC
+    movl      (%ecx,%eax,4),%eax       # eax<- resolved methodToCall
+    .if       (!$isrange)
+    andl      $$0xf,rIBASE             # rIBASE<- D (or stays CCCC)
+    .endif
+    testl     %eax,%eax                # already resolved?
+    GET_VREG_R  %ecx rIBASE            # ecx<- "this" ptr
+    je        .L${opcode}_resolve      # not resolved, do it now
+.L${opcode}_finish:
+    testl     %ecx,%ecx                # null "this"?
+    jne       common_invokeMethod${routine}  # no, continue on
+    jmp       common_errNullObject
+
+    /*
+     * On entry:
+     *   TMP_SPILL  <- "this" register
+     * Things a bit ugly on this path, but it's the less
+     * frequent one.  We'll have to do some reloading.
+     */
+.L${opcode}_resolve:
+     SPILL_TMP1(%ecx)
+     movl     rSELF,%ecx
+     movl     offThread_method(%ecx),%ecx  # ecx<- self->method
+     movzwl   2(rPC),%eax      # reference (BBBB or CCCC)
+     movl     offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+     movl     $$METHOD_DIRECT,OUT_ARG2(%esp)
+     movl     %eax,OUT_ARG1(%esp)
+     movl     %ecx,OUT_ARG0(%esp)
+     call     dvmResolveMethod # eax<- call(clazz, ref, flags)
+     UNSPILL_TMP1(%ecx)
+     testl    %eax,%eax
+     jne      .L${opcode}_finish
+     jmp      common_exceptionThrown
diff --git a/vm/mterp/x86/OP_INVOKE_DIRECT_JUMBO.S b/vm/mterp/x86/OP_INVOKE_DIRECT_JUMBO.S
new file mode 100644
index 0000000..b1576c5
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_DIRECT_JUMBO.S
@@ -0,0 +1,46 @@
+%verify "executed"
+%verify "unknown method"
+    /*
+     * Handle a jumbo 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.)
+     */
+    /* invoke-direct/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax              # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movzwl    8(rPC),rIBASE            # rIBASE<- CCCC
+    movl      (%ecx,%eax,4),%eax       # eax<- resolved methodToCall
+    testl     %eax,%eax                # already resolved?
+    GET_VREG_R  %ecx rIBASE            # ecx<- "this" ptr
+    je        .L${opcode}_resolve      # not resolved, do it now
+.L${opcode}_finish:
+    testl     %ecx,%ecx                # null "this"?
+    jne       common_invokeMethodJumbo # no, continue on
+    jmp       common_errNullObject
+
+    /*
+     * On entry:
+     *   TMP_SPILL  <- "this" register
+     * Things a bit ugly on this path, but it's the less
+     * frequent one.  We'll have to do some reloading.
+     */
+.L${opcode}_resolve:
+     SPILL_TMP1(%ecx)
+     movl     rSELF,%ecx
+     movl     offThread_method(%ecx),%ecx  # ecx<- self->method
+     movl     2(rPC),%eax      # reference AAAAAAAA
+     movl     offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+     movl     $$METHOD_DIRECT,OUT_ARG2(%esp)
+     movl     %eax,OUT_ARG1(%esp)
+     movl     %ecx,OUT_ARG0(%esp)
+     call     dvmResolveMethod # eax<- call(clazz, ref, flags)
+     UNSPILL_TMP1(%ecx)
+     testl    %eax,%eax
+     jne      .L${opcode}_finish
+     jmp      common_exceptionThrown
diff --git a/vm/mterp/x86/OP_INVOKE_DIRECT_RANGE.S b/vm/mterp/x86/OP_INVOKE_DIRECT_RANGE.S
new file mode 100644
index 0000000..140430a
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_DIRECT_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_DIRECT.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86/OP_INVOKE_INTERFACE.S b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
new file mode 100644
index 0000000..3fa4c94
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
@@ -0,0 +1,32 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * 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 */
+    movzwl     4(rPC),%eax              # eax<- FEDC or CCCC
+    movl       rSELF,%ecx
+    .if        (!$isrange)
+    andl       $$0xf,%eax               # eax<- C (or stays CCCC)
+    .endif
+    GET_VREG_R   %eax %eax              # eax<- "this"
+    EXPORT_PC
+    testl      %eax,%eax                # null this?
+    je         common_errNullObject     # yes, fail
+    movl       offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
+    movl       %eax,OUT_ARG0(%esp)                 # arg0<- class
+    movl       offThread_methodClassDex(%ecx),%eax   # eax<- methodClassDex
+    movl       offThread_method(%ecx),%ecx           # ecx<- method
+    movl       %eax,OUT_ARG3(%esp)                 # arg3<- dex
+    movzwl     2(rPC),%eax                         # eax<- BBBB
+    movl       %ecx,OUT_ARG2(%esp)                 # arg2<- method
+    movl       %eax,OUT_ARG1(%esp)                 # arg1<- BBBB
+    call       dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
+    testl      %eax,%eax
+    je         common_exceptionThrown
+    jmp        common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_INTERFACE_JUMBO.S b/vm/mterp/x86/OP_INVOKE_INTERFACE_JUMBO.S
new file mode 100644
index 0000000..ee0ecdb
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_INTERFACE_JUMBO.S
@@ -0,0 +1,25 @@
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * Handle a jumbo interface method call.
+     */
+    /* invoke-interface/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movzwl     8(rPC),%eax              # eax<- CCCC
+    movl       rSELF,%ecx
+    GET_VREG_R   %eax %eax              # eax<- "this"
+    EXPORT_PC
+    testl      %eax,%eax                # null this?
+    je         common_errNullObject     # yes, fail
+    movl       offObject_clazz(%eax),%eax# eax<- thisPtr->clazz
+    movl       %eax,OUT_ARG0(%esp)                 # arg0<- class
+    movl       offThread_methodClassDex(%ecx),%eax   # eax<- methodClassDex
+    movl       offThread_method(%ecx),%ecx           # ecx<- method
+    movl       %eax,OUT_ARG3(%esp)                 # arg3<- dex
+    movl       2(rPC),%eax                         # eax<- AAAAAAAA
+    movl       %ecx,OUT_ARG2(%esp)                 # arg2<- method
+    movl       %eax,OUT_ARG1(%esp)                 # arg1<- AAAAAAAA
+    call       dvmFindInterfaceMethodInCache # eax<- call(class, ref, method, dex)
+    testl      %eax,%eax
+    je         common_exceptionThrown
+    jmp        common_invokeMethodJumbo
diff --git a/vm/mterp/x86/OP_INVOKE_INTERFACE_RANGE.S b/vm/mterp/x86/OP_INVOKE_INTERFACE_RANGE.S
new file mode 100644
index 0000000..cbebedb
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_INTERFACE_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_INTERFACE.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S b/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S
new file mode 100644
index 0000000..fb84b32
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_OBJECT_INIT_RANGE.S
@@ -0,0 +1,4 @@
+%verify "executed"
+    /*
+     * TODO (currently punting to stub)
+     */
diff --git a/vm/mterp/x86/OP_INVOKE_STATIC.S b/vm/mterp/x86/OP_INVOKE_STATIC.S
new file mode 100644
index 0000000..ca68a84
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_STATIC.S
@@ -0,0 +1,30 @@
+%default { "routine":"NoRange","isrange":"0" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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 */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved methodToCall
+    testl     %eax,%eax
+    jne       common_invokeMethod${routine}
+    movl      rSELF,%ecx
+    movl      offThread_method(%ecx),%ecx # ecx<- self->method
+    movzwl    2(rPC),%eax
+    movl      offMethod_clazz(%ecx),%ecx# ecx<- method->clazz
+    movl      %eax,OUT_ARG1(%esp)       # arg1<- BBBB
+    movl      %ecx,OUT_ARG0(%esp)       # arg0<- clazz
+    movl      $$METHOD_STATIC,%eax
+    movl      %eax,OUT_ARG2(%esp)       # arg2<- flags
+    call      dvmResolveMethod          # call(clazz,ref,flags)
+    testl     %eax,%eax                 # got null?
+    jne       common_invokeMethod${routine}
+    jmp       common_exceptionThrown
diff --git a/vm/mterp/x86/OP_INVOKE_STATIC_JUMBO.S b/vm/mterp/x86/OP_INVOKE_STATIC_JUMBO.S
new file mode 100644
index 0000000..1f98d3d
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_STATIC_JUMBO.S
@@ -0,0 +1,26 @@
+%verify "executed"
+%verify "unknown method"
+    /*
+     * Handle a jumbo static method call.
+     */
+    /* invoke-static/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx  # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%eax        # eax<- resolved methodToCall
+    testl     %eax,%eax
+    jne       common_invokeMethodJumbo
+    movl      rSELF,%ecx
+    movl      offThread_method(%ecx),%ecx # ecx<- self->method
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offMethod_clazz(%ecx),%ecx# ecx<- method->clazz
+    movl      %eax,OUT_ARG1(%esp)       # arg1<- AAAAAAAA
+    movl      %ecx,OUT_ARG0(%esp)       # arg0<- clazz
+    movl      $$METHOD_STATIC,%eax
+    movl      %eax,OUT_ARG2(%esp)       # arg2<- flags
+    call      dvmResolveMethod          # call(clazz,ref,flags)
+    testl     %eax,%eax                 # got null?
+    jne       common_invokeMethodJumbo
+    jmp       common_exceptionThrown
diff --git a/vm/mterp/x86/OP_INVOKE_STATIC_RANGE.S b/vm/mterp/x86/OP_INVOKE_STATIC_RANGE.S
new file mode 100644
index 0000000..da6d0bf
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_STATIC_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_STATIC.S" { "routine":"Range","isrange":"1" }
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER.S b/vm/mterp/x86/OP_INVOKE_SUPER.S
new file mode 100644
index 0000000..ecee028
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_SUPER.S
@@ -0,0 +1,66 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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 */
+    movl      rSELF,rINST
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(rINST),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved baseMethod
+    movl      offThread_method(rINST),%eax # eax<- method
+    movzwl    4(rPC),rINST              # rINST<- GFED or CCCC
+    .if       (!$isrange)
+    andl      $$0xf,rINST               # rINST<- D (or stays CCCC)
+    .endif
+    GET_VREG_R  rINST rINST             # rINST<- "this" ptr
+    testl     rINST,rINST               # null "this"?
+    je        common_errNullObject      # yes, throw
+    movl      offMethod_clazz(%eax),%eax # eax<- method->clazz
+    testl     %ecx,%ecx                 # already resolved?
+    je       .L${opcode}_resolve
+    /*
+     * At this point:
+     *  ecx = resolved base method [r0]
+     *  eax = method->clazz [r9]
+     */
+.L${opcode}_continue:
+    movl    offClassObject_super(%eax),%eax   # eax<- method->clazz->super
+    movzwl  offMethod_methodIndex(%ecx),%ecx  # ecx<- baseMthod->methodIndex
+    cmpl    offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+    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]
+    jmp     common_invokeMethod${routine}
+
+
+    /* At this point:
+     * ecx = null (needs to be resolved base method)
+     * eax = method->clazz
+    */
+.L${opcode}_resolve:
+    SPILL_TMP1(%eax)                    # method->clazz
+    movl    %eax,OUT_ARG0(%esp)         # arg0<- method->clazz
+    movzwl  2(rPC),%ecx                 # ecx<- BBBB
+    movl    $$METHOD_VIRTUAL,OUT_ARG2(%esp)  # arg2<- resolver method type
+    movl    %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    call    dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl   %eax,%eax                   # got null?
+    movl    %eax,%ecx                   # ecx<- resolved base method
+    UNSPILL_TMP1(%eax)                  # restore method->clazz
+    jne     .L${opcode}_continue        # good to go - continue
+    jmp     common_exceptionThrown      # handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  ecx = resolved base method
+     */
+.L${opcode}_nsm:
+    movl    offMethod_name(%ecx),%eax
+    jmp     common_errNoSuchMethod
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_JUMBO.S b/vm/mterp/x86/OP_INVOKE_SUPER_JUMBO.S
new file mode 100644
index 0000000..d98e14d
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_JUMBO.S
@@ -0,0 +1,59 @@
+%verify "executed"
+%verify "unknown method"
+    /*
+     * Handle a jumbo "super" method call.
+     */
+    /* invoke-super/jumbo {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,rINST
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(rINST),%ecx # ecx<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved baseMethod
+    movl      offThread_method(rINST),%eax # eax<- method
+    movzwl    8(rPC),rINST              # rINST<- CCCC
+    GET_VREG_R  rINST rINST             # rINST<- "this" ptr
+    testl     rINST,rINST               # null "this"?
+    je        common_errNullObject      # yes, throw
+    movl      offMethod_clazz(%eax),%eax # eax<- method->clazz
+    testl     %ecx,%ecx                 # already resolved?
+    je       .L${opcode}_resolve
+    /*
+     * At this point:
+     *  ecx = resolved base method [r0]
+     *  eax = method->clazz [r9]
+     */
+.L${opcode}_continue:
+    movl    offClassObject_super(%eax),%eax   # eax<- method->clazz->super
+    movzwl  offMethod_methodIndex(%ecx),%ecx  # ecx<- baseMthod->methodIndex
+    cmpl    offClassObject_vtableCount(%eax),%ecx # compare(methodIndex,vtableCount)
+    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]
+    jmp     common_invokeMethodJumbo
+
+
+    /* At this point:
+     * ecx = null (needs to be resolved base method)
+     * eax = method->clazz
+    */
+.L${opcode}_resolve:
+    SPILL_TMP1(%eax)                    # method->clazz
+    movl    %eax,OUT_ARG0(%esp)         # arg0<- method->clazz
+    movl    2(rPC),%ecx                 # ecx<- AAAAAAAA
+    movl    $$METHOD_VIRTUAL,OUT_ARG2(%esp)  # arg2<- resolver method type
+    movl    %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    call    dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl   %eax,%eax                   # got null?
+    movl    %eax,%ecx                   # ecx<- resolved base method
+    UNSPILL_TMP1(%eax)                  # restore method->clazz
+    jne     .L${opcode}_continue        # good to go - continue
+    jmp     common_exceptionThrown      # handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  ecx = resolved base method
+     */
+.L${opcode}_nsm:
+    movl    offMethod_name(%ecx),%eax
+    jmp     common_errNoSuchMethod
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
new file mode 100644
index 0000000..5fe098c
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
@@ -0,0 +1,26 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+    /*
+     * 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 */
+    movl      rSELF,%ecx
+    movzwl    4(rPC),%eax               # eax<- GFED or CCCC
+    movl      offThread_method(%ecx),%ecx # ecx<- current method
+    .if       (!$isrange)
+    andl      $$0xf,%eax                # eax<- D (or stays CCCC)
+    .endif
+    movl      offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    GET_VREG_R  %eax %eax               # eax<- "this"
+    movl      offClassObject_super(%ecx),%ecx # ecx<- method->clazz->super
+    testl     %eax,%eax                 # null "this"?
+    je        common_errNullObject      # "this" is null, throw exception
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offClassObject_vtable(%ecx),%ecx # ecx<- vtable
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%eax        # eax<- super->vtable[BBBB]
+    jmp       common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK_RANGE.S b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK_RANGE.S
new file mode 100644
index 0000000..e0a27a3
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_SUPER_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_RANGE.S b/vm/mterp/x86/OP_INVOKE_SUPER_RANGE.S
new file mode 100644
index 0000000..ffbcf8c
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_SUPER.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
new file mode 100644
index 0000000..24d0170
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
@@ -0,0 +1,48 @@
+
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * 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 */
+    movl      rSELF,%eax
+    movzwl    2(rPC),%ecx                 # ecx<- BBBB
+    movl      offThread_methodClassDex(%eax),%eax  # eax<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%eax),%eax   # eax<- pDvmDex->pResMethods
+    movl      (%eax,%ecx,4),%eax          # eax<- resolved baseMethod
+    testl     %eax,%eax                   # already resolved?
+    jne       .L${opcode}_continue        # yes, continue
+    movl      rSELF,%eax
+    movl      %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    movl      offThread_method(%eax),%eax   # eax<- self->method
+    movl      offMethod_clazz(%eax),%eax  # ecx<- method->clazz
+    movl      %eax,OUT_ARG0(%esp)         # arg0<- clazz
+    movl      $$METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- flags
+    call      dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl     %eax,%eax                   # got null?
+    jne       .L${opcode}_continue        # no, continue
+    jmp       common_exceptionThrown      # yes, handle exception
+
+    /* At this point:
+     *   eax = resolved base method
+     *   ecx = scratch
+     */
+.L${opcode}_continue:
+    movzwl    4(rPC),%ecx               # ecx<- GFED or CCCC
+    .if       (!$isrange)
+    andl      $$0xf,%ecx                # ecx<- D (or stays CCCC)
+    .endif
+    GET_VREG_R  %ecx %ecx               # ecx<- "this"
+    movzwl    offMethod_methodIndex(%eax),%eax  # eax<- baseMethod->methodIndex
+    testl     %ecx,%ecx                 # null this?
+    je        common_errNullObject      # go if so
+    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]
+    jmp       common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL_JUMBO.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL_JUMBO.S
new file mode 100644
index 0000000..085b591
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_JUMBO.S
@@ -0,0 +1,40 @@
+%verify "executed"
+%verify "unknown method"
+%verify "null object"
+    /*
+     * Handle a jumbo virtual method call.
+     */
+    /* invoke-virtual/jumbo vBBBB, {vCCCC..v(CCCC+BBBB-1)}, meth@AAAAAAAA */
+    movl      rSELF,%eax
+    movl      2(rPC),%ecx                 # ecx<- AAAAAAAA
+    movl      offThread_methodClassDex(%eax),%eax  # eax<- pDvmDex
+    EXPORT_PC
+    movl      offDvmDex_pResMethods(%eax),%eax   # eax<- pDvmDex->pResMethods
+    movl      (%eax,%ecx,4),%eax          # eax<- resolved baseMethod
+    testl     %eax,%eax                   # already resolved?
+    jne       .L${opcode}_continue        # yes, continue
+    movl      rSELF,%eax
+    movl      %ecx,OUT_ARG1(%esp)         # arg1<- ref
+    movl      offThread_method(%eax),%eax   # eax<- self->method
+    movl      offMethod_clazz(%eax),%eax  # ecx<- method->clazz
+    movl      %eax,OUT_ARG0(%esp)         # arg0<- clazz
+    movl      $$METHOD_VIRTUAL,OUT_ARG2(%esp) # arg2<- flags
+    call      dvmResolveMethod            # eax<- call(clazz, ref, flags)
+    testl     %eax,%eax                   # got null?
+    jne       .L${opcode}_continue        # no, continue
+    jmp       common_exceptionThrown      # yes, handle exception
+
+    /* At this point:
+     *   eax = resolved base method
+     *   ecx = scratch
+     */
+.L${opcode}_continue:
+    movzwl    8(rPC),%ecx               # ecx<- CCCC
+    GET_VREG_R  %ecx %ecx               # ecx<- "this"
+    movzwl    offMethod_methodIndex(%eax),%eax  # eax<- baseMethod->methodIndex
+    testl     %ecx,%ecx                 # null this?
+    je        common_errNullObject      # go if so
+    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]
+    jmp       common_invokeMethodJumbo
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
new file mode 100644
index 0000000..14202d8
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
@@ -0,0 +1,23 @@
+%default { "isrange":"0", "routine":"NoRange" }
+%verify "executed"
+%verify "null object"
+    /*
+     * 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 */
+    movzwl    4(rPC),%eax               # eax<- FEDC or CCCC
+    movzwl    2(rPC),%ecx               # ecx<- BBBB
+    .if     (!$isrange)
+    andl      $$0xf,%eax                # eax<- C (or stays CCCC)
+    .endif
+    GET_VREG_R  %eax %eax               # eax<- vC ("this" ptr)
+    testl     %eax,%eax                 # null?
+    je        common_errNullObject      # yep, throw exception
+    movl      offObject_clazz(%eax),%eax # eax<- thisPtr->clazz
+    movl      offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
+    EXPORT_PC                           # might throw later - get ready
+    movl      (%eax,%ecx,4),%eax        # eax<- vtable[BBBB]
+    jmp       common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK_RANGE.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
new file mode 100644
index 0000000..53d7602
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_VIRTUAL_QUICK.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL_RANGE.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL_RANGE.S
new file mode 100644
index 0000000..e91a89e
--- /dev/null
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_RANGE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_INVOKE_VIRTUAL.S" { "isrange":"1", "routine":"Range" }
diff --git a/vm/mterp/x86/OP_IPUT.S b/vm/mterp/x86/OP_IPUT.S
new file mode 100644
index 0000000..2c718b2
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT.S
@@ -0,0 +1,54 @@
+
+%default { "store":"movl", "reg":"rINST", "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 */
+    movl    rSELF,%ecx
+    SPILL   (rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $$4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $$0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    $store   $reg,(%ecx,%eax,1)            # obj.field <- v[A](8/16/32 bits)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_BOOLEAN.S b/vm/mterp/x86/OP_IPUT_BOOLEAN.S
new file mode 100644
index 0000000..1bdde9d
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT.S" { "store":"movb","reg":"rINSTbl", "sqnum":"1" }
diff --git a/vm/mterp/x86/OP_IPUT_BOOLEAN_JUMBO.S b/vm/mterp/x86/OP_IPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..eb156ec
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT_JUMBO.S" { "store":"movb","reg":"rINSTbl", "sqnum":"1" }
diff --git a/vm/mterp/x86/OP_IPUT_BYTE.S b/vm/mterp/x86/OP_IPUT_BYTE.S
new file mode 100644
index 0000000..3a8652d
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT.S" { "store":"movb", "reg":"rINSTbl", "sqnum":"2" }
diff --git a/vm/mterp/x86/OP_IPUT_BYTE_JUMBO.S b/vm/mterp/x86/OP_IPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..e2bdf05
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT_JUMBO.S" { "store":"movb", "reg":"rINSTbl", "sqnum":"2" }
diff --git a/vm/mterp/x86/OP_IPUT_CHAR.S b/vm/mterp/x86/OP_IPUT_CHAR.S
new file mode 100644
index 0000000..ba8d38e
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT.S" { "store":"movw", "reg":"rINSTw", "sqnum":"3" }
diff --git a/vm/mterp/x86/OP_IPUT_CHAR_JUMBO.S b/vm/mterp/x86/OP_IPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..f2e7592
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT_JUMBO.S" { "store":"movw", "reg":"rINSTw", "sqnum":"3" }
diff --git a/vm/mterp/x86/OP_IPUT_JUMBO.S b/vm/mterp/x86/OP_IPUT_JUMBO.S
new file mode 100644
index 0000000..474cac5
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_JUMBO.S
@@ -0,0 +1,52 @@
+%default { "store":"movl", "reg":"rINST", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit instance field put.
+     *
+     * for: iput/jumbo, iput-object/jumbo, iput-boolean/jumbo, iput-byte/jumbo,
+            iput-char/jumbo, iput-short/jumbo
+     */
+    /* exop vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                       # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax   # eax<- byte offset of field
+    testl   %ecx,%ecx                            # object null?
+    je      common_errNullObject                 # object was null
+    $store   $reg,(%ecx,%eax,1)            # obj.field <- v[BBBB](8/16/32 bits)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT.S b/vm/mterp/x86/OP_IPUT_OBJECT.S
new file mode 100644
index 0000000..6c9fd6e
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_OBJECT.S
@@ -0,0 +1,61 @@
+%default { "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Object field put.
+     *
+     * for: iput-object
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $$4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $$0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                  # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds A
+     */
+    GET_VREG_R rINST rINST                      # rINST<- v[A]
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl    rINST,(%ecx,%eax)      # obj.field <- v[A](8/16/32 bits)
+    movl    rSELF,%eax
+    testl   rINST,rINST                         # stored a NULL?
+    movl    offThread_cardTable(%eax),%eax      # get card table base
+    je      1f                                  # skip card mark if null store
+    shrl    $$GC_CARD_SHIFT,%ecx                # object head to card number
+    movb    %al,(%eax,%ecx)                     # mark card using object head
+1:
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT_JUMBO.S b/vm/mterp/x86/OP_IPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..c699595
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_OBJECT_JUMBO.S
@@ -0,0 +1,57 @@
+%default { "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo object field put.
+     */
+    /* iput-object/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                  # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           # returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds BBBB
+     */
+    GET_VREG_R rINST rINST                      # rINST<- v[BBBB]
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    movl    rINST,(%ecx,%eax)      # obj.field <- v[BBBB](8/16/32 bits)
+    movl    rSELF,%eax
+    testl   rINST,rINST                         # stored a NULL?
+    movl    offThread_cardTable(%eax),%eax      # get card table base
+    je      1f                                  # skip card mark if null store
+    shrl    $$GC_CARD_SHIFT,%ecx                # object head to card number
+    movb    %al,(%eax,%ecx)                     # mark card using object head
+1:
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S b/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S
new file mode 100644
index 0000000..b628e57
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_OBJECT_QUICK.S
@@ -0,0 +1,23 @@
+%verify "executed"
+%verify "null object"
+    /* For: iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $$4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    andb      $$0xf,rINSTbl             # rINST<- A
+    GET_VREG_R  rINST rINST             # rINST<- v[A]
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    testl     %ecx,%ecx                 # is object null?
+    je        common_errNullObject
+    movl      rINST,(%ecx,%eax,1)
+    movl      rSELF,%eax
+    testl     rINST,rINST               # did we store null?
+    movl      offThread_cardTable(%eax),%eax  # get card table base
+    je        1f                            # skip card mark if null store
+    shrl      $$GC_CARD_SHIFT,%ecx          # object head to card number
+    movb      %al,(%eax,%ecx)               # mark card based on object head
+1:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_IPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..3959c06
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT_OBJECT.S"
diff --git a/vm/mterp/x86/OP_IPUT_QUICK.S b/vm/mterp/x86/OP_IPUT_QUICK.S
new file mode 100644
index 0000000..cd4fe3b
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+    /* For: iput-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $$4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    andb      $$0xf,rINSTbl             # rINST<- A
+    GET_VREG_R  rINST,rINST             # rINST<- v[A]
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    testl     %ecx,%ecx                 # is object null?
+    je        common_errNullObject
+    movl      rINST,(%ecx,%eax,1)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_SHORT.S b/vm/mterp/x86/OP_IPUT_SHORT.S
new file mode 100644
index 0000000..299953a
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT.S" { "store":"movw", "reg":"rINSTw", "sqnum":"4" }
diff --git a/vm/mterp/x86/OP_IPUT_SHORT_JUMBO.S b/vm/mterp/x86/OP_IPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..c121b28
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT_JUMBO.S" { "store":"movw", "reg":"rINSTw", "sqnum":"4" }
diff --git a/vm/mterp/x86/OP_IPUT_VOLATILE.S b/vm/mterp/x86/OP_IPUT_VOLATILE.S
new file mode 100644
index 0000000..caf007e
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_IPUT.S"
diff --git a/vm/mterp/x86/OP_IPUT_WIDE.S b/vm/mterp/x86/OP_IPUT_WIDE.S
new file mode 100644
index 0000000..d481d02
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_WIDE.S
@@ -0,0 +1,55 @@
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 64-bit instance field put.
+     *
+     */
+    /* op vA, vB, field@CCCC */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movzwl  2(rPC),rIBASE                       # rIBASE<- 0000CCCC
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzbl  rINSTbl,%ecx                        # ecx<- BA
+    sarl    $$4,%ecx                            # ecx<- B
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    andb    $$0xf,rINSTbl                       # rINST<- A
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[B], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  ... which returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds A
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    GET_VREG_WORD %ecx rINST 0                  # ecx<- lsw
+    GET_VREG_WORD rINST rINST 1                 # rINST<- msw
+    movl    rINST,4(%eax)
+    movl    %ecx,(%eax)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_WIDE_JUMBO.S b/vm/mterp/x86/OP_IPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..38c40b1
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_WIDE_JUMBO.S
@@ -0,0 +1,52 @@
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit instance field put.
+     */
+    /* iput-wide/jumbo vBBBB, vCCCC, field@AAAAAAAA */
+    movl    rSELF,%ecx
+    SPILL(rIBASE)
+    movl    2(rPC),rIBASE                       # rIBASE<- AAAAAAAA
+    movl    offThread_methodClassDex(%ecx),%eax # eax<- DvmDex
+    movzwl  8(rPC),%ecx                         # ecx<- CCCC
+    movl    offDvmDex_pResFields(%eax),%eax     # eax<- pDvmDex->pResFields
+    GET_VREG_R %ecx %ecx                        # ecx<- fp[CCCC], the object ptr
+    movl    (%eax,rIBASE,4),%eax                # resolved entry
+    testl   %eax,%eax                           # is resolved entry null?
+    jne     .L${opcode}_finish                  # no, already resolved
+    movl    rIBASE,OUT_ARG1(%esp)
+    movl    rSELF,rIBASE
+    EXPORT_PC
+    movl    offThread_method(rIBASE),rIBASE     # rIBASE<- current method
+    movl    offMethod_clazz(rIBASE),rIBASE      # rIBASE<- method->clazz
+    SPILL_TMP1(%ecx)                            # save obj pointer across call
+    movl    rIBASE,OUT_ARG0(%esp)               # pass in method->clazz
+    call    dvmResolveInstField                 #  ... to dvmResolveInstField
+    UNSPILL_TMP1(%ecx)
+    testl   %eax,%eax                           #  ... which returns InstrField ptr
+    jne     .L${opcode}_finish
+    jmp     common_exceptionThrown
+
+.L${opcode}_finish:
+    /*
+     * Currently:
+     *   eax holds resolved field
+     *   ecx holds object
+     *   rIBASE is scratch, but needs to be unspilled
+     *   rINST holds BBBB
+     */
+    movl    offInstField_byteOffset(%eax),%eax  # eax<- byte offset of field
+    testl   %ecx,%ecx                           # object null?
+    je      common_errNullObject                # object was null
+    leal    (%ecx,%eax,1),%eax                  # eax<- address of field
+    GET_VREG_WORD %ecx rINST 0                  # ecx<- lsw
+    GET_VREG_WORD rINST rINST 1                 # rINST<- msw
+    movl    rINST,4(%eax)
+    movl    %ecx,(%eax)
+    FETCH_INST_OPCODE 5 %ecx
+    UNSPILL(rIBASE)
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_IPUT_WIDE_QUICK.S b/vm/mterp/x86/OP_IPUT_WIDE_QUICK.S
new file mode 100644
index 0000000..12eeed6
--- /dev/null
+++ b/vm/mterp/x86/OP_IPUT_WIDE_QUICK.S
@@ -0,0 +1,19 @@
+%verify "executed"
+%verify "null object"
+    /* For: iput-wide-quick */
+    /* op vA, vB, offset@CCCC */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $$4,%ecx                  # ecx<- B
+    GET_VREG_R  %ecx %ecx               # vB (object we're operating on)
+    movzwl    2(rPC),%eax               # eax<- field byte offset
+    testl      %ecx,%ecx                # is object null?
+    je        common_errNullObject
+    leal      (%ecx,%eax,1),%ecx        # ecx<- Address of 64-bit target
+    andb      $$0xf,rINSTbl             # rINST<- A
+    GET_VREG_WORD %eax rINST 0          # eax<- lsw
+    GET_VREG_WORD rINST rINST 1         # rINST<- msw
+    movl      %eax,(%ecx)
+    movl      rINST,4(%ecx)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_LONG_TO_DOUBLE.S b/vm/mterp/x86/OP_LONG_TO_DOUBLE.S
new file mode 100644
index 0000000..7235315
--- /dev/null
+++ b/vm/mterp/x86/OP_LONG_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"load":"fildll","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_LONG_TO_FLOAT.S b/vm/mterp/x86/OP_LONG_TO_FLOAT.S
new file mode 100644
index 0000000..2c4359a
--- /dev/null
+++ b/vm/mterp/x86/OP_LONG_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"load":"fildll","store":"fstps"}
diff --git a/vm/mterp/x86/OP_LONG_TO_INT.S b/vm/mterp/x86/OP_LONG_TO_INT.S
new file mode 100644
index 0000000..bf5060f
--- /dev/null
+++ b/vm/mterp/x86/OP_LONG_TO_INT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+%include "x86/OP_MOVE.S"
diff --git a/vm/mterp/x86/OP_MONITOR_ENTER.S b/vm/mterp/x86/OP_MONITOR_ENTER.S
new file mode 100644
index 0000000..a630db1
--- /dev/null
+++ b/vm/mterp/x86/OP_MONITOR_ENTER.S
@@ -0,0 +1,20 @@
+%verify "executed"
+%verify "exception for null object"
+    /*
+     * Synchronize on an object.
+     */
+    /* monitor-enter vAA */
+    movl    rSELF,%ecx
+    GET_VREG_R %eax rINST               # eax<- vAA
+    FETCH_INST_WORD 1
+    testl   %eax,%eax                   # null object?
+    EXPORT_PC                           # need for precise GC
+    je     common_errNullObject
+    movl    %ecx,OUT_ARG0(%esp)
+    movl    %eax,OUT_ARG1(%esp)
+    SPILL(rIBASE)
+    call    dvmLockObject               # dvmLockObject(self,object)
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MONITOR_EXIT.S b/vm/mterp/x86/OP_MONITOR_EXIT.S
new file mode 100644
index 0000000..98bc373
--- /dev/null
+++ b/vm/mterp/x86/OP_MONITOR_EXIT.S
@@ -0,0 +1,29 @@
+%verify "executed"
+%verify "exception for null object (impossible in javac)"
+%verify "dvmUnlockObject fails"
+    /*
+     * 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 */
+    GET_VREG_R %eax rINST
+    movl    rSELF,%ecx
+    EXPORT_PC
+    testl   %eax,%eax                   # null object?
+    je      .L${opcode}_errNullObject   # go if so
+    movl    %eax,OUT_ARG1(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call    dvmUnlockObject             # unlock(self,obj)
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    testl   %eax,%eax                   # success?
+    ADVANCE_PC 1
+    je      common_exceptionThrown      # no, exception pending
+    GOTO_NEXT_R %ecx
+.L${opcode}_errNullObject:
+    ADVANCE_PC 1                        # advance before throw
+    jmp     common_errNullObject
diff --git a/vm/mterp/x86/OP_MOVE.S b/vm/mterp/x86/OP_MOVE.S
new file mode 100644
index 0000000..ec05288
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE.S
@@ -0,0 +1,11 @@
+%verify "executed"
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    movzbl rINSTbl,%eax          # eax<- BA
+    andb   $$0xf,%al             # eax<- A
+    shrl   $$4,rINST            # rINST<- B
+    GET_VREG_R rINST rINST
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG rINST %eax           # fp[A]<-fp[B]
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_16.S b/vm/mterp/x86/OP_MOVE_16.S
new file mode 100644
index 0000000..e25230a
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* for: move/16, move-object/16 */
+    /* op vAAAA, vBBBB */
+    movzwl    4(rPC),%ecx              # ecx<- BBBB
+    movzwl    2(rPC),%eax              # eax<- AAAA
+    GET_VREG_R  rINST %ecx
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    SET_VREG  rINST %eax
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_EXCEPTION.S b/vm/mterp/x86/OP_MOVE_EXCEPTION.S
new file mode 100644
index 0000000..0853866
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_EXCEPTION.S
@@ -0,0 +1,9 @@
+%verify "executed"
+    /* move-exception vAA */
+    movl    rSELF,%ecx
+    movl    offThread_exception(%ecx),%eax # eax<- dvmGetException bypass
+    SET_VREG %eax rINST                # fp[AA]<- exception object
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    movl    $$0,offThread_exception(%ecx) # dvmClearException bypass
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_MOVE_FROM16.S b/vm/mterp/x86/OP_MOVE_FROM16.S
new file mode 100644
index 0000000..120edb5
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_FROM16.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* for: move/from16, move-object/from16 */
+    /* op vAA, vBBBB */
+    movzx    rINSTbl,%eax              # eax <= AA
+    movw     2(rPC),rINSTw             # rINSTw <= BBBB
+    GET_VREG_R rINST rINST             # rINST- fp[BBBB]
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG rINST %eax                # fp[AA]<- ecx]
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_OBJECT.S b/vm/mterp/x86/OP_MOVE_OBJECT.S
new file mode 100644
index 0000000..f32d5a6
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_MOVE.S"
diff --git a/vm/mterp/x86/OP_MOVE_OBJECT_16.S b/vm/mterp/x86/OP_MOVE_OBJECT_16.S
new file mode 100644
index 0000000..859e4db
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_OBJECT_16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_MOVE_16.S"
diff --git a/vm/mterp/x86/OP_MOVE_OBJECT_FROM16.S b/vm/mterp/x86/OP_MOVE_OBJECT_FROM16.S
new file mode 100644
index 0000000..fef4401
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_OBJECT_FROM16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_MOVE_FROM16.S"
diff --git a/vm/mterp/x86/OP_MOVE_RESULT.S b/vm/mterp/x86/OP_MOVE_RESULT.S
new file mode 100644
index 0000000..4a6917b
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_RESULT.S
@@ -0,0 +1,9 @@
+%verify "executed"
+    /* for: move-result, move-result-object */
+    /* op vAA */
+    movl     rSELF,%eax                    # eax<- rSELF
+    movl     offThread_retval(%eax),%eax   # eax<- self->retval.l
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    SET_VREG  %eax rINST                   # fp[AA]<- retval.l
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_RESULT_OBJECT.S b/vm/mterp/x86/OP_MOVE_RESULT_OBJECT.S
new file mode 100644
index 0000000..a3f1b1f
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_RESULT_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_MOVE_RESULT.S"
diff --git a/vm/mterp/x86/OP_MOVE_RESULT_WIDE.S b/vm/mterp/x86/OP_MOVE_RESULT_WIDE.S
new file mode 100644
index 0000000..022bdb3
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_RESULT_WIDE.S
@@ -0,0 +1,10 @@
+%verify "executed"
+    /* move-result-wide vAA */
+    movl    rSELF,%ecx
+    movl    offThread_retval(%ecx),%eax
+    movl    4+offThread_retval(%ecx),%ecx
+    SET_VREG_WORD %eax rINST 0     # v[AA+0] <- eax
+    SET_VREG_WORD %ecx rINST 1     # v[AA+1] <- ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_WIDE.S b/vm/mterp/x86/OP_MOVE_WIDE.S
new file mode 100644
index 0000000..df59574
--- /dev/null
+++ b/vm/mterp/x86/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" */
+    movzbl    rINSTbl,%ecx                # ecx <- BA
+    sarl      $$4,rINST                   # rINST<- B
+    GET_VREG_WORD %eax rINST 0            # eax<- v[B+0]
+    GET_VREG_WORD rINST rINST 1           # rINST<- v[B+1]
+    andb      $$0xf,%cl                   # ecx <- A
+    SET_VREG_WORD rINST %ecx 1            # v[A+1]<- rINST
+    SET_VREG_WORD %eax %ecx 0             # v[A+0]<- eax
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_WIDE_16.S b/vm/mterp/x86/OP_MOVE_WIDE_16.S
new file mode 100644
index 0000000..26ea8a4
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_WIDE_16.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /* move-wide/16 vAAAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    movzwl    4(rPC),%ecx            # ecx<- BBBB
+    movzwl    2(rPC),%eax            # eax<- AAAA
+    GET_VREG_WORD rINST %ecx 0       # rINSTw_WORD<- v[BBBB+0]
+    GET_VREG_WORD %ecx %ecx 1        # ecx<- v[BBBB+1]
+    SET_VREG_WORD rINST %eax 0       # v[AAAA+0]<- rINST
+    SET_VREG_WORD %ecx %eax 1        # v[AAAA+1]<- ecx
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MOVE_WIDE_FROM16.S b/vm/mterp/x86/OP_MOVE_WIDE_FROM16.S
new file mode 100644
index 0000000..3d820ad
--- /dev/null
+++ b/vm/mterp/x86/OP_MOVE_WIDE_FROM16.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /* move-wide/from16 vAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    movzwl    2(rPC),%ecx              # ecx<- BBBB
+    movzbl    rINSTbl,%eax             # eax<- AAAA
+    GET_VREG_WORD rINST %ecx 0         # rINST<- v[BBBB+0]
+    GET_VREG_WORD %ecx %ecx 1          # ecx<- v[BBBB+1]
+    SET_VREG_WORD rINST %eax 0         # v[AAAA+0]<- rINST
+    SET_VREG_WORD %ecx %eax 1          # v[AAAA+1]<- eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_DOUBLE.S b/vm/mterp/x86/OP_MUL_DOUBLE.S
new file mode 100644
index 0000000..59a2079
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fmull","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..45a2fa3
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fmull","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_MUL_FLOAT.S b/vm/mterp/x86/OP_MUL_FLOAT.S
new file mode 100644
index 0000000..5515c4f
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fmuls","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/x86/OP_MUL_FLOAT_2ADDR.S
new file mode 100644
index 0000000..c8a3bf7
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fmuls","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_MUL_INT.S b/vm/mterp/x86/OP_MUL_INT.S
new file mode 100644
index 0000000..a958114
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_INT.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /*
+     * 32-bit binary multiplication.
+     */
+    /* mul vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    SPILL(rIBASE)
+    imull    (rFP,%ecx,4),%eax      # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_INT_2ADDR.S b/vm/mterp/x86/OP_MUL_INT_2ADDR.S
new file mode 100644
index 0000000..ebd5160
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_INT_2ADDR.S
@@ -0,0 +1,13 @@
+%verify "executed"
+    /* mul vA, vB */
+    movzx   rINSTbl,%ecx              # ecx<- A+
+    sarl    $$4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST             # eax<- vB
+    andb    $$0xf,%cl                 # ecx<- A
+    SPILL(rIBASE)
+    imull   (rFP,%ecx,4),%eax         # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_INT_LIT16.S b/vm/mterp/x86/OP_MUL_INT_LIT16.S
new file mode 100644
index 0000000..a196c7e
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_INT_LIT16.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /* mul/lit16 vA, vB, #+CCCC */
+    /* Need A in rINST, ssssCCCC in ecx, vB in eax */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $$4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $$0xf,rINSTbl              # rINST<- A
+    SPILL(rIBASE)
+    imull     %ecx,%eax                 # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_INT_LIT8.S b/vm/mterp/x86/OP_MUL_INT_LIT8.S
new file mode 100644
index 0000000..f36ffc7
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_INT_LIT8.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /* mul/lit8 vAA, vBB, #+CC */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    SPILL(rIBASE)
+    imull     %ecx,%eax                # trashes rIBASE/edx
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG  %eax rINST
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_LONG.S b/vm/mterp/x86/OP_MUL_LONG.S
new file mode 100644
index 0000000..7cf6ccb
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_LONG.S
@@ -0,0 +1,37 @@
+%verify "executed"
+    /*
+     * Signed 64-bit integer multiply.
+     *
+     * We could definately use more free registers for
+     * this code.   We spill rINSTw (ebx),
+     * giving us eax, ebc, ecx and edx as computational
+     * temps.  On top of that, we'll spill edi (rFP)
+     * for use as the vB pointer and esi (rPC) for use
+     * as the vC pointer.  Yuck.
+     */
+    /* mul-long vAA, vBB, vCC */
+    movzbl    2(rPC),%eax              # eax<- B
+    movzbl    3(rPC),%ecx              # ecx<- C
+    SPILL_TMP2(%esi)                   # save Dalvik PC
+    SPILL(rFP)
+    SPILL(rINST)
+    SPILL(rIBASE)
+    leal      (rFP,%eax,4),%esi        # esi<- &v[B]
+    leal      (rFP,%ecx,4),rFP         # rFP<- &v[C]
+    movl      4(%esi),%ecx             # ecx<- Bmsw
+    imull     (rFP),%ecx               # ecx<- (Bmsw*Clsw)
+    movl      4(rFP),%eax              # eax<- Cmsw
+    imull     (%esi),%eax              # eax<- (Cmsw*Blsw)
+    addl      %eax,%ecx                # ecx<- (Bmsw*Clsw)+(Cmsw*Blsw)
+    movl      (rFP),%eax               # eax<- Clsw
+    mull      (%esi)                   # eax<- (Clsw*Alsw)
+    UNSPILL(rINST)
+    UNSPILL(rFP)
+    leal      (%ecx,rIBASE),rIBASE # full result now in rIBASE:%eax
+    UNSPILL_TMP2(%esi)             # Restore Dalvik PC
+    FETCH_INST_OPCODE 2 %ecx       # Fetch next instruction
+    movl      rIBASE,4(rFP,rINST,4)# v[B+1]<- rIBASE
+    UNSPILL(rIBASE)
+    movl      %eax,(rFP,rINST,4)   # v[B]<- %eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_MUL_LONG_2ADDR.S b/vm/mterp/x86/OP_MUL_LONG_2ADDR.S
new file mode 100644
index 0000000..9a0930c
--- /dev/null
+++ b/vm/mterp/x86/OP_MUL_LONG_2ADDR.S
@@ -0,0 +1,37 @@
+%verify "executed"
+    /*
+     * Signed 64-bit integer multiply, 2-addr version
+     *
+     * We could definately use more free registers for
+     * this code.  We must spill %edx (rIBASE) because it
+     * is used by imul.  We'll also spill rINST (ebx),
+     * giving us eax, ebc, ecx and rIBASE as computational
+     * temps.  On top of that, we'll spill %esi (edi)
+     * for use as the vA pointer and rFP (esi) for use
+     * as the vB pointer.  Yuck.
+     */
+    /* mul-long/2addr vA, vB */
+    movzbl    rINSTbl,%eax             # eax<- BA
+    andb      $$0xf,%al                # eax<- A
+    sarl      $$4,rINST                # rINST<- B
+    SPILL_TMP2(%esi)
+    SPILL(rFP)
+    SPILL(rIBASE)
+    leal      (rFP,%eax,4),%esi        # %esi<- &v[A]
+    leal      (rFP,rINST,4),rFP        # rFP<- &v[B]
+    movl      4(%esi),%ecx             # ecx<- Amsw
+    imull     (rFP),%ecx               # ecx<- (Amsw*Blsw)
+    movl      4(rFP),%eax              # eax<- Bmsw
+    imull     (%esi),%eax              # eax<- (Bmsw*Alsw)
+    addl      %eax,%ecx                # ecx<- (Amsw*Blsw)+(Bmsw*Alsw)
+    movl      (rFP),%eax               # eax<- Blsw
+    mull      (%esi)                   # eax<- (Blsw*Alsw)
+    leal      (%ecx,rIBASE),rIBASE     # full result now in %edx:%eax
+    movl      rIBASE,4(%esi)           # v[A+1]<- rIBASE
+    movl      %eax,(%esi)              # v[A]<- %eax
+    UNSPILL_TMP2(%esi)
+    FETCH_INST_OPCODE 1 %ecx
+    UNSPILL(rIBASE)
+    UNSPILL(rFP)
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_NEG_DOUBLE.S b/vm/mterp/x86/OP_NEG_DOUBLE.S
new file mode 100644
index 0000000..7b24914
--- /dev/null
+++ b/vm/mterp/x86/OP_NEG_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"instr":"fchs","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_NEG_FLOAT.S b/vm/mterp/x86/OP_NEG_FLOAT.S
new file mode 100644
index 0000000..e785155
--- /dev/null
+++ b/vm/mterp/x86/OP_NEG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/fpcvt.S" {"instr":"fchs","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_NEG_INT.S b/vm/mterp/x86/OP_NEG_INT.S
new file mode 100644
index 0000000..4dfd6d3
--- /dev/null
+++ b/vm/mterp/x86/OP_NEG_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/unop.S" {"instr":"negl %eax"}
diff --git a/vm/mterp/x86/OP_NEG_LONG.S b/vm/mterp/x86/OP_NEG_LONG.S
new file mode 100644
index 0000000..9543351
--- /dev/null
+++ b/vm/mterp/x86/OP_NEG_LONG.S
@@ -0,0 +1,15 @@
+%verify "executed"
+    /* unop vA, vB */
+    movzbl    rINSTbl,%ecx        # ecx<- BA
+    sarl      $$4,%ecx            # ecx<- B
+    andb      $$0xf,rINSTbl       # rINST<- A
+    GET_VREG_WORD %eax %ecx 0     # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1     # ecx<- v[B+1]
+    negl      %eax
+    adcl      $$0,%ecx
+    negl      %ecx
+    SET_VREG_WORD %eax rINST 0    # v[A+0]<- eax
+    FETCH_INST_OPCODE 1 %eax
+    SET_VREG_WORD %ecx rINST 1    # v[A+1]<- ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_NEW_ARRAY.S b/vm/mterp/x86/OP_NEW_ARRAY.S
new file mode 100644
index 0000000..c9690d3
--- /dev/null
+++ b/vm/mterp/x86/OP_NEW_ARRAY.S
@@ -0,0 +1,64 @@
+%verify "executed"
+%verify "negative array length"
+%verify "allocation fails"
+    /*
+     * 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 */
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movl    offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    movzwl  2(rPC),%eax                       # eax<- CCCC
+    movl    offDvmDex_pResClasses(%ecx),%ecx  # ecx<- pDvmDex->pResClasses
+    SPILL(rIBASE)
+    movl    (%ecx,%eax,4),%ecx                # ecx<- resolved class
+    movzbl  rINSTbl,%eax
+    sarl    $$4,%eax                          # eax<- B
+    GET_VREG_R %eax %eax                      # eax<- vB (array length)
+    andb    $$0xf,rINSTbl                     # rINST<- A
+    testl   %eax,%eax
+    js      common_errNegativeArraySize       # bail, passing len in eax
+    testl   %ecx,%ecx                         # already resolved?
+    jne     .L${opcode}_finish                # yes, fast path
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *  ecx holds class (null here)
+     *  eax holds array length (vB)
+     */
+    movl    rSELF,%ecx
+    SPILL_TMP1(%eax)                   # save array length
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movzwl  2(rPC),%eax                # eax<- CCCC
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $$0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass            # eax<- call(clazz,ref,flag)
+    movl    %eax,%ecx
+    UNSPILL_TMP1(%eax)
+    testl   %ecx,%ecx                  # successful resolution?
+    je      common_exceptionThrown     # no, bail.
+# fall through to ${opcode}_finish
+
+    /*
+     * Finish allocation
+     *
+     * ecx holds class
+     * eax holds array length (vB)
+     */
+.L${opcode}_finish:
+    movl    %ecx,OUT_ARG0(%esp)
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $$ALLOC_DONT_TRACK,OUT_ARG2(%esp)
+    call    dvmAllocArrayByClass    # eax<- call(clazz,length,flags)
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    testl   %eax,%eax               # failed?
+    je      common_exceptionThrown  # yup - go handle
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_NEW_ARRAY_JUMBO.S b/vm/mterp/x86/OP_NEW_ARRAY_JUMBO.S
new file mode 100644
index 0000000..5d72759
--- /dev/null
+++ b/vm/mterp/x86/OP_NEW_ARRAY_JUMBO.S
@@ -0,0 +1,62 @@
+%verify "executed"
+%verify "negative array length"
+%verify "allocation fails"
+    /*
+     * 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/jumbo vBBBB, vCCCC, class@AAAAAAAA */
+    movl    rSELF,%ecx
+    EXPORT_PC
+    movl    offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex
+    movl    2(rPC),%eax                       # eax<- AAAAAAAA
+    movl    offDvmDex_pResClasses(%ecx),%ecx  # ecx<- pDvmDex->pResClasses
+    SPILL(rIBASE)
+    movl    (%ecx,%eax,4),%ecx                # ecx<- resolved class
+    movzwl  8(rPC),%eax                       # eax<- CCCC
+    GET_VREG_R %eax %eax                      # eax<- vCCCC (array length)
+    testl   %eax,%eax
+    js      common_errNegativeArraySize       # bail, passing len in eax
+    testl   %ecx,%ecx                         # already resolved?
+    jne     .L${opcode}_finish                # yes, fast path
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *  ecx holds class (null here)
+     *  eax holds array length (vCCCC)
+     */
+    movl    rSELF,%ecx
+    SPILL_TMP1(%eax)                   # save array length
+    movl    offThread_method(%ecx),%ecx  # ecx<- self->method
+    movl    2(rPC),%eax                # eax<- AAAAAAAA
+    movl    offMethod_clazz(%ecx),%ecx # ecx<- method->clazz
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $$0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass            # eax<- call(clazz,ref,flag)
+    movl    %eax,%ecx
+    UNSPILL_TMP1(%eax)
+    testl   %ecx,%ecx                  # successful resolution?
+    je      common_exceptionThrown     # no, bail.
+# fall through to ${opcode}_finish
+
+    /*
+     * Finish allocation
+     *
+     * ecx holds class
+     * eax holds array length (vCCCC)
+     */
+.L${opcode}_finish:
+    movl    %ecx,OUT_ARG0(%esp)
+    movl    %eax,OUT_ARG1(%esp)
+    movl    $$ALLOC_DONT_TRACK,OUT_ARG2(%esp)
+    call    dvmAllocArrayByClass    # eax<- call(clazz,length,flags)
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 5 %ecx
+    testl   %eax,%eax               # failed?
+    je      common_exceptionThrown  # yup - go handle
+    SET_VREG %eax rINST
+    ADVANCE_PC 5
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_NEW_INSTANCE.S b/vm/mterp/x86/OP_NEW_INSTANCE.S
new file mode 100644
index 0000000..3e268c4
--- /dev/null
+++ b/vm/mterp/x86/OP_NEW_INSTANCE.S
@@ -0,0 +1,67 @@
+%verify "executed"
+%verify "class not resolved"
+%verify "class cannot be resolved"
+%verify "class not initialized"
+%verify "class fails to initialize"
+%verify "class already resolved/initialized"
+%verify "class is abstract or interface"
+%verify "allocation fails"
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance vAA, class@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax               # eax<- BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    SPILL(rIBASE)
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved class
+    testl     %ecx,%ecx                 # resolved?
+    je        .L${opcode}_resolve       # no, go do it
+.L${opcode}_resolved:  # on entry, ecx<- class
+    cmpb      $$CLASS_INITIALIZED,offClassObject_status(%ecx)
+    jne       .L${opcode}_needinit
+.L${opcode}_initialized:  # on entry, ecx<- class
+    movl      $$ALLOC_DONT_TRACK,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    call     dvmAllocObject             # eax<- new object
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    testl    %eax,%eax                  # success?
+    je       common_exceptionThrown     # no, bail out
+    SET_VREG %eax rINST
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Class initialization required.
+     *
+     *  ecx holds class object
+     */
+.L${opcode}_needinit:
+    SPILL_TMP1(%ecx)                    # save object
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmInitClass                # initialize class
+    UNSPILL_TMP1(%ecx)                  # restore object
+    testl   %eax,%eax                   # success?
+    jne     .L${opcode}_initialized     # success, continue
+    jmp     common_exceptionThrown      # go deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     */
+.L${opcode}_resolve:
+    movl    rSELF,%ecx
+    movzwl  2(rPC),%eax
+    movl    offThread_method(%ecx),%ecx   # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    movl    $$0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass             # call(clazz,off,flags)
+    movl    %eax,%ecx                   # ecx<- resolved ClassObject ptr
+    testl   %ecx,%ecx                   # success?
+    jne     .L${opcode}_resolved        # good to go
+    jmp     common_exceptionThrown      # no, handle exception
diff --git a/vm/mterp/x86/OP_NEW_INSTANCE_JUMBO.S b/vm/mterp/x86/OP_NEW_INSTANCE_JUMBO.S
new file mode 100644
index 0000000..aebb2d0
--- /dev/null
+++ b/vm/mterp/x86/OP_NEW_INSTANCE_JUMBO.S
@@ -0,0 +1,67 @@
+%verify "executed"
+%verify "class not resolved"
+%verify "class cannot be resolved"
+%verify "class not initialized"
+%verify "class fails to initialize"
+%verify "class already resolved/initialized"
+%verify "class is abstract or interface"
+%verify "allocation fails"
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance/jumbo vBBBB, class@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax               # eax<- AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- pDvmDex
+    movl      offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses
+    EXPORT_PC
+    movl      (%ecx,%eax,4),%ecx        # ecx<- resolved class
+    SPILL(rIBASE)
+    testl     %ecx,%ecx                 # resolved?
+    je        .L${opcode}_resolve       # no, go do it
+.L${opcode}_resolved:  # on entry, ecx<- class
+    cmpb      $$CLASS_INITIALIZED,offClassObject_status(%ecx)
+    jne       .L${opcode}_needinit
+.L${opcode}_initialized:  # on entry, ecx<- class
+    movl      $$ALLOC_DONT_TRACK,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    call     dvmAllocObject             # eax<- new object
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 4 %ecx
+    testl    %eax,%eax                  # success?
+    je       common_exceptionThrown     # no, bail out
+    SET_VREG %eax rINST
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Class initialization required.
+     *
+     *  ecx holds class object
+     */
+.L${opcode}_needinit:
+    SPILL_TMP1(%ecx)                    # save object
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmInitClass                # initialize class
+    UNSPILL_TMP1(%ecx)                  # restore object
+    testl   %eax,%eax                   # success?
+    jne     .L${opcode}_initialized     # success, continue
+    jmp     common_exceptionThrown      # go deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     */
+.L${opcode}_resolve:
+    movl    rSELF,%ecx
+    movl    2(rPC),%eax                 # eax<- AAAAAAAA
+    movl    offThread_method(%ecx),%ecx   # ecx<- self->method
+    movl    %eax,OUT_ARG1(%esp)
+    movl    offMethod_clazz(%ecx),%ecx  # ecx<- method->clazz
+    movl    $$0,OUT_ARG2(%esp)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmResolveClass             # call(clazz,off,flags)
+    movl    %eax,%ecx                   # ecx<- resolved ClassObject ptr
+    testl   %ecx,%ecx                   # success?
+    jne     .L${opcode}_resolved        # good to go
+    jmp     common_exceptionThrown      # no, handle exception
diff --git a/vm/mterp/x86/OP_NOP.S b/vm/mterp/x86/OP_NOP.S
new file mode 100644
index 0000000..99fa2b6
--- /dev/null
+++ b/vm/mterp/x86/OP_NOP.S
@@ -0,0 +1,4 @@
+%verify "executed"
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_NOT_INT.S b/vm/mterp/x86/OP_NOT_INT.S
new file mode 100644
index 0000000..c910716
--- /dev/null
+++ b/vm/mterp/x86/OP_NOT_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/unop.S" {"instr":"notl %eax"}
diff --git a/vm/mterp/x86/OP_NOT_LONG.S b/vm/mterp/x86/OP_NOT_LONG.S
new file mode 100644
index 0000000..54e1c44
--- /dev/null
+++ b/vm/mterp/x86/OP_NOT_LONG.S
@@ -0,0 +1,14 @@
+%verify "executed"
+    /* unop vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- BA
+    sarl      $$4,%ecx           # ecx<- B
+    andb      $$0xf,rINSTbl      # rINST<- A
+    GET_VREG_WORD %eax %ecx 0    # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1    # ecx<- v[B+1]
+    notl      %eax
+    notl      %ecx
+    SET_VREG_WORD %eax rINST 0   # v[A+0]<- eax
+    FETCH_INST_OPCODE 1 %eax
+    SET_VREG_WORD %ecx rINST 1   # v[A+1]<- ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_OR_INT.S b/vm/mterp/x86/OP_OR_INT.S
new file mode 100644
index 0000000..9453bfd
--- /dev/null
+++ b/vm/mterp/x86/OP_OR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop.S" {"instr":"orl   (rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_OR_INT_2ADDR.S b/vm/mterp/x86/OP_OR_INT_2ADDR.S
new file mode 100644
index 0000000..db69633
--- /dev/null
+++ b/vm/mterp/x86/OP_OR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop2addr.S" {"instr":"orl     %eax,(rFP,%ecx,4)"}
diff --git a/vm/mterp/x86/OP_OR_INT_LIT16.S b/vm/mterp/x86/OP_OR_INT_LIT16.S
new file mode 100644
index 0000000..fa70e99
--- /dev/null
+++ b/vm/mterp/x86/OP_OR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit16.S" {"instr":"orl     %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_OR_INT_LIT8.S b/vm/mterp/x86/OP_OR_INT_LIT8.S
new file mode 100644
index 0000000..5761806
--- /dev/null
+++ b/vm/mterp/x86/OP_OR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"orl     %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_OR_LONG.S b/vm/mterp/x86/OP_OR_LONG.S
new file mode 100644
index 0000000..90f0e3e
--- /dev/null
+++ b/vm/mterp/x86/OP_OR_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide.S" {"instr1":"orl (rFP,%ecx,4),rIBASE", "instr2":"orl 4(rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_OR_LONG_2ADDR.S b/vm/mterp/x86/OP_OR_LONG_2ADDR.S
new file mode 100644
index 0000000..52d740e
--- /dev/null
+++ b/vm/mterp/x86/OP_OR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide2addr.S" {"instr1":"orl %eax,(rFP,rINST,4)","instr2":"orl %ecx,4(rFP,rINST,4)"}
diff --git a/vm/mterp/x86/OP_PACKED_SWITCH.S b/vm/mterp/x86/OP_PACKED_SWITCH.S
new file mode 100644
index 0000000..c762a8b
--- /dev/null
+++ b/vm/mterp/x86/OP_PACKED_SWITCH.S
@@ -0,0 +1,23 @@
+%default { "func":"dvmInterpHandlePackedSwitch" }
+%verify executed
+    /*
+     * 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 */
+    movl    2(rPC),%ecx           # ecx<- BBBBbbbb
+    GET_VREG_R %eax rINST         # eax<- vAA
+    leal    (rPC,%ecx,2),%ecx     # ecx<- PC + BBBBbbbb*2
+    movl    %eax,OUT_ARG1(%esp)   # ARG1<- vAA
+    movl    %ecx,OUT_ARG0(%esp)   # ARG0<- switchData
+    call    $func
+    movl    rSELF,%ecx
+    ADVANCE_PC_INDEXED %eax
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST
+    GOTO_NEXT
diff --git a/vm/mterp/x86/OP_REM_DOUBLE.S b/vm/mterp/x86/OP_REM_DOUBLE.S
new file mode 100644
index 0000000..d670a31
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_DOUBLE.S
@@ -0,0 +1,16 @@
+%verify "executed"
+    /* rem_float vAA, vBB, vCC */
+    movzbl   3(rPC),%ecx            # ecx<- BB
+    movzbl   2(rPC),%eax            # eax<- CC
+    fldl     (rFP,%ecx,4)           # vCC to fp stack
+    fldl     (rFP,%eax,4)           # vCC to fp stack
+    FETCH_INST_OPCODE 2 %ecx
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    ADVANCE_PC 2
+    fstpl    (rFP,rINST,4)           # %st to vAA
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..ee751d0
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_DOUBLE_2ADDR.S
@@ -0,0 +1,17 @@
+%verify "executed"
+    /* rem_float/2addr vA, vB */
+    movzx   rINSTbl,%ecx                # ecx<- A+
+    sarl    $$4,rINST                  # rINST<- B
+    fldl     (rFP,rINST,4)              # vBB to fp stack
+    andb    $$0xf,%cl                   # ecx<- A
+    fldl     (rFP,%ecx,4)               # vAA to fp stack
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstpl    (rFP,%ecx,4)               # %st to vA
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_REM_FLOAT.S b/vm/mterp/x86/OP_REM_FLOAT.S
new file mode 100644
index 0000000..342bf3e
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_FLOAT.S
@@ -0,0 +1,17 @@
+%verify "executed"
+    /* rem_float vAA, vBB, vCC */
+    movzbl   3(rPC),%ecx            # ecx<- BB
+    movzbl   2(rPC),%eax            # eax<- CC
+    flds     (rFP,%ecx,4)           # vCC to fp stack
+    flds     (rFP,%eax,4)           # vCC to fp stack
+    movzbl   rINSTbl,%ecx           # ecx<- AA
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    FETCH_INST_OPCODE 2 %eax
+    ADVANCE_PC 2
+    fstps    (rFP,%ecx,4)           # %st to vAA
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S b/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S
new file mode 100644
index 0000000..1f494bd
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_FLOAT_2ADDR.S
@@ -0,0 +1,17 @@
+%verify "executed"
+    /* rem_float/2addr vA, vB */
+    movzx   rINSTbl,%ecx                # ecx<- A+
+    sarl    $$4,rINST                  # rINST<- B
+    flds     (rFP,rINST,4)              # vBB to fp stack
+    andb    $$0xf,%cl                   # ecx<- A
+    flds     (rFP,%ecx,4)               # vAA to fp stack
+1:
+    fprem
+    fstsw     %ax
+    sahf
+    jp        1b
+    fstp      %st(1)
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    fstps    (rFP,%ecx,4)               # %st to vA
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/OP_REM_INT.S b/vm/mterp/x86/OP_REM_INT.S
new file mode 100644
index 0000000..6e4fd04
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindiv.S" {"result":"rIBASE","special":"$0"}
diff --git a/vm/mterp/x86/OP_REM_INT_2ADDR.S b/vm/mterp/x86/OP_REM_INT_2ADDR.S
new file mode 100644
index 0000000..4a11617
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindiv2addr.S" {"result":"rIBASE","special":"$0"}
diff --git a/vm/mterp/x86/OP_REM_INT_LIT16.S b/vm/mterp/x86/OP_REM_INT_LIT16.S
new file mode 100644
index 0000000..5c4afd6
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindivLit16.S" {"result":"rIBASE","special":"$0"}
diff --git a/vm/mterp/x86/OP_REM_INT_LIT8.S b/vm/mterp/x86/OP_REM_INT_LIT8.S
new file mode 100644
index 0000000..53e12ee
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/bindivLit8.S" {"result":"rIBASE","special":"$0"}
diff --git a/vm/mterp/x86/OP_REM_LONG.S b/vm/mterp/x86/OP_REM_LONG.S
new file mode 100644
index 0000000..ad8091c
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_DIV_LONG.S" {"routine":"__moddi3","special":"$0"}
diff --git a/vm/mterp/x86/OP_REM_LONG_2ADDR.S b/vm/mterp/x86/OP_REM_LONG_2ADDR.S
new file mode 100644
index 0000000..f6e6d61
--- /dev/null
+++ b/vm/mterp/x86/OP_REM_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_DIV_LONG_2ADDR.S" {"routine":"__moddi3","special":"$0"}
diff --git a/vm/mterp/x86/OP_RETURN.S b/vm/mterp/x86/OP_RETURN.S
new file mode 100644
index 0000000..082b82e
--- /dev/null
+++ b/vm/mterp/x86/OP_RETURN.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /*
+     * Return a 32-bit value.  Copies the return value into the "self"
+     * structure, then jumps to the return handler.
+     *
+     * for: return, return-object
+     */
+    /* op vAA */
+    movl    rSELF,%ecx
+    GET_VREG_R %eax rINST               # eax<- vAA
+    movl    %eax,offThread_retval(%ecx)   # retval.i <- AA
+    jmp     common_returnFromMethod
diff --git a/vm/mterp/x86/OP_RETURN_OBJECT.S b/vm/mterp/x86/OP_RETURN_OBJECT.S
new file mode 100644
index 0000000..1a2b83e
--- /dev/null
+++ b/vm/mterp/x86/OP_RETURN_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_RETURN.S"
diff --git a/vm/mterp/x86/OP_RETURN_VOID.S b/vm/mterp/x86/OP_RETURN_VOID.S
new file mode 100644
index 0000000..4d4291f
--- /dev/null
+++ b/vm/mterp/x86/OP_RETURN_VOID.S
@@ -0,0 +1,2 @@
+%verify "executed"
+    jmp       common_returnFromMethod
diff --git a/vm/mterp/x86/OP_RETURN_WIDE.S b/vm/mterp/x86/OP_RETURN_WIDE.S
new file mode 100644
index 0000000..c8e7df5
--- /dev/null
+++ b/vm/mterp/x86/OP_RETURN_WIDE.S
@@ -0,0 +1,12 @@
+%verify "executed"
+    /*
+     * Return a 64-bit value.  Copies the return value into the "self"
+     * structure, then jumps to the return handler.
+     */
+    /* return-wide vAA */
+    movl    rSELF,%ecx
+    GET_VREG_WORD %eax rINST 0       # eax<- v[AA+0]
+    GET_VREG_WORD rINST rINST 1      # rINST<- v[AA+1]
+    movl    %eax,offThread_retval(%ecx)
+    movl    rINST,4+offThread_retval(%ecx)
+    jmp     common_returnFromMethod
diff --git a/vm/mterp/x86/OP_RSUB_INT.S b/vm/mterp/x86/OP_RSUB_INT.S
new file mode 100644
index 0000000..fa9b410
--- /dev/null
+++ b/vm/mterp/x86/OP_RSUB_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit16.S" {"instr":"subl %eax,%ecx","result":"%ecx"}
diff --git a/vm/mterp/x86/OP_RSUB_INT_LIT8.S b/vm/mterp/x86/OP_RSUB_INT_LIT8.S
new file mode 100644
index 0000000..81f49a7
--- /dev/null
+++ b/vm/mterp/x86/OP_RSUB_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"subl  %eax,%ecx" , "result":"%ecx"}
diff --git a/vm/mterp/x86/OP_SGET.S b/vm/mterp/x86/OP_SGET.S
new file mode 100644
index 0000000..8ff0632
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET.S
@@ -0,0 +1,41 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SGET_BOOLEAN.S b/vm/mterp/x86/OP_SGET_BOOLEAN.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_BOOLEAN_JUMBO.S b/vm/mterp/x86/OP_SGET_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..dee15fc
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SGET_BYTE.S b/vm/mterp/x86/OP_SGET_BYTE.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_BYTE_JUMBO.S b/vm/mterp/x86/OP_SGET_BYTE_JUMBO.S
new file mode 100644
index 0000000..dee15fc
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SGET_CHAR.S b/vm/mterp/x86/OP_SGET_CHAR.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_CHAR_JUMBO.S b/vm/mterp/x86/OP_SGET_CHAR_JUMBO.S
new file mode 100644
index 0000000..dee15fc
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SGET_JUMBO.S b/vm/mterp/x86/OP_SGET_JUMBO.S
new file mode 100644
index 0000000..2b3e2a8
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_JUMBO.S
@@ -0,0 +1,42 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit SGET handler.
+     *
+     * for: sget/jumbo, sget-object/jumbo, sget-boolean/jumbo, sget-byte/jumbo,
+     *      sget-char/jumbo, sget-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%eax
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    SET_VREG %eax rINST
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SGET_OBJECT.S b/vm/mterp/x86/OP_SGET_OBJECT.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_OBJECT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_OBJECT_JUMBO.S b/vm/mterp/x86/OP_SGET_OBJECT_JUMBO.S
new file mode 100644
index 0000000..dee15fc
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_OBJECT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SGET_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_SGET_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_SHORT.S b/vm/mterp/x86/OP_SGET_SHORT.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_SHORT_JUMBO.S b/vm/mterp/x86/OP_SGET_SHORT_JUMBO.S
new file mode 100644
index 0000000..dee15fc
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SGET_VOLATILE.S b/vm/mterp/x86/OP_SGET_VOLATILE.S
new file mode 100644
index 0000000..3b3a492
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SGET.S"
diff --git a/vm/mterp/x86/OP_SGET_WIDE.S b/vm/mterp/x86/OP_SGET_WIDE.S
new file mode 100644
index 0000000..432763d
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_WIDE.S
@@ -0,0 +1,42 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * 64-bit SGET handler.
+     *
+     */
+    /* sget-wide vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%ecx    # ecx<- lsw
+    movl      4+offStaticField_value(%eax),%eax  # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SGET_WIDE_JUMBO.S b/vm/mterp/x86/OP_SGET_WIDE_JUMBO.S
new file mode 100644
index 0000000..2d8fa8f
--- /dev/null
+++ b/vm/mterp/x86/OP_SGET_WIDE_JUMBO.S
@@ -0,0 +1,42 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit SGET handler.
+     *
+     */
+    /* sget-wide/jumbo vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    movl      offStaticField_value(%eax),%ecx    # ecx<- lsw
+    movl      4+offStaticField_value(%eax),%eax  # eax<- msw
+    SET_VREG_WORD %ecx rINST 0
+    FETCH_INST_OPCODE 2 %ecx
+    SET_VREG_WORD %eax rINST 1
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SHL_INT.S b/vm/mterp/x86/OP_SHL_INT.S
new file mode 100644
index 0000000..a72a272
--- /dev/null
+++ b/vm/mterp/x86/OP_SHL_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop1.S" {"instr":"sall    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_SHL_INT_2ADDR.S b/vm/mterp/x86/OP_SHL_INT_2ADDR.S
new file mode 100644
index 0000000..c8e1dfe
--- /dev/null
+++ b/vm/mterp/x86/OP_SHL_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/shop2addr.S" {"instr":"sall    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_SHL_INT_LIT8.S b/vm/mterp/x86/OP_SHL_INT_LIT8.S
new file mode 100644
index 0000000..8c7f007
--- /dev/null
+++ b/vm/mterp/x86/OP_SHL_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"sall  %cl,%eax"}
diff --git a/vm/mterp/x86/OP_SHL_LONG.S b/vm/mterp/x86/OP_SHL_LONG.S
new file mode 100644
index 0000000..0750f80
--- /dev/null
+++ b/vm/mterp/x86/OP_SHL_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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.  x86 shifts automatically mask off
+     * the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
+     * case specially.
+     */
+    /* shl-long vAA, vBB, vCC */
+    /* ecx gets shift count */
+    /* Need to spill rINST */
+    /* rINSTw gets AA */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE %eax 1         # ecx<- v[BB+1]
+    GET_VREG_R   %ecx %ecx              # ecx<- vCC
+    GET_VREG_WORD %eax %eax 0           # eax<- v[BB+0]
+    shldl     %eax,rIBASE
+    sall      %cl,%eax
+    testb     $$32,%cl
+    je        2f
+    movl      %eax,rIBASE
+    xorl      %eax,%eax
+2:
+    SET_VREG_WORD rIBASE rINST 1        # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0          # v[AA+0]<- %eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_SHL_LONG_2ADDR.S b/vm/mterp/x86/OP_SHL_LONG_2ADDR.S
new file mode 100644
index 0000000..b8bbce9
--- /dev/null
+++ b/vm/mterp/x86/OP_SHL_LONG_2ADDR.S
@@ -0,0 +1,29 @@
+%verify "executed"
+    /*
+     * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
+     * 32-bit shift distance.
+     */
+    /* shl-long/2addr vA, vB */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    rINSTbl,%ecx             # ecx<- BA
+    andb      $$0xf,rINSTbl            # rINST<- A
+    GET_VREG_WORD %eax rINST 0         # eax<- v[AA+0]
+    sarl      $$4,%ecx                 # ecx<- B
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE rINST 1       # rIBASE<- v[AA+1]
+    GET_VREG_R  %ecx %ecx              # ecx<- vBB
+    shldl     %eax,rIBASE
+    sall      %cl,%eax
+    testb     $$32,%cl
+    je        2f
+    movl      %eax,rIBASE
+    xorl      %eax,%eax
+2:
+    SET_VREG_WORD rIBASE rINST 1       # v[AA+1]<- rIBASE
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG_WORD %eax rINST 0         # v[AA+0]<- eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_SHR_INT.S b/vm/mterp/x86/OP_SHR_INT.S
new file mode 100644
index 0000000..febc429
--- /dev/null
+++ b/vm/mterp/x86/OP_SHR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop1.S" {"instr":"sarl    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_SHR_INT_2ADDR.S b/vm/mterp/x86/OP_SHR_INT_2ADDR.S
new file mode 100644
index 0000000..89c6625
--- /dev/null
+++ b/vm/mterp/x86/OP_SHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/shop2addr.S" {"instr":"sarl    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_SHR_INT_LIT8.S b/vm/mterp/x86/OP_SHR_INT_LIT8.S
new file mode 100644
index 0000000..77ddd23
--- /dev/null
+++ b/vm/mterp/x86/OP_SHR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"sarl    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_SHR_LONG.S b/vm/mterp/x86/OP_SHR_LONG.S
new file mode 100644
index 0000000..d79d624
--- /dev/null
+++ b/vm/mterp/x86/OP_SHR_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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.  x86 shifts automatically mask off
+     * the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
+     * case specially.
+     */
+    /* shr-long vAA, vBB, vCC */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE %eax 1         # rIBASE<- v[BB+1]
+    GET_VREG_R   %ecx %ecx              # ecx<- vCC
+    GET_VREG_WORD %eax %eax 0           # eax<- v[BB+0]
+    shrdl     rIBASE,%eax
+    sarl      %cl,rIBASE
+    testb     $$32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    sarl      $$31,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1        # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0          # v[AA+0]<- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_SHR_LONG_2ADDR.S b/vm/mterp/x86/OP_SHR_LONG_2ADDR.S
new file mode 100644
index 0000000..d380e12
--- /dev/null
+++ b/vm/mterp/x86/OP_SHR_LONG_2ADDR.S
@@ -0,0 +1,29 @@
+%verify "executed"
+    /*
+     * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
+     * 32-bit shift distance.
+     */
+    /* shl-long/2addr vA, vB */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    rINSTbl,%ecx         # ecx<- BA
+    andb      $$0xf,rINSTbl        # rINST<- A
+    GET_VREG_WORD %eax rINST 0     # eax<- v[AA+0]
+    sarl      $$4,%ecx             # ecx<- B
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE rINST 1   # rIBASE<- v[AA+1]
+    GET_VREG_R %ecx %ecx           # ecx<- vBB
+    shrdl     rIBASE,%eax
+    sarl      %cl,rIBASE
+    testb     $$32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    sarl      $$31,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1   # v[AA+1]<- rIBASE
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG_WORD %eax rINST 0    # v[AA+0]<- eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_SPARSE_SWITCH.S b/vm/mterp/x86/OP_SPARSE_SWITCH.S
new file mode 100644
index 0000000..4cedd40
--- /dev/null
+++ b/vm/mterp/x86/OP_SPARSE_SWITCH.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_PACKED_SWITCH.S" { "func":"dvmInterpHandleSparseSwitch" }
diff --git a/vm/mterp/x86/OP_SPUT.S b/vm/mterp/x86/OP_SPUT.S
new file mode 100644
index 0000000..bc76533
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT.S
@@ -0,0 +1,41 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SPUT_BOOLEAN.S b/vm/mterp/x86/OP_SPUT_BOOLEAN.S
new file mode 100644
index 0000000..ec0489f
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_BOOLEAN.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86/OP_SPUT_BOOLEAN_JUMBO.S b/vm/mterp/x86/OP_SPUT_BOOLEAN_JUMBO.S
new file mode 100644
index 0000000..c791c49
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_BOOLEAN_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SPUT_BYTE.S b/vm/mterp/x86/OP_SPUT_BYTE.S
new file mode 100644
index 0000000..ec0489f
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86/OP_SPUT_BYTE_JUMBO.S b/vm/mterp/x86/OP_SPUT_BYTE_JUMBO.S
new file mode 100644
index 0000000..c791c49
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_BYTE_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SPUT_CHAR.S b/vm/mterp/x86/OP_SPUT_CHAR.S
new file mode 100644
index 0000000..ec0489f
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86/OP_SPUT_CHAR_JUMBO.S b/vm/mterp/x86/OP_SPUT_CHAR_JUMBO.S
new file mode 100644
index 0000000..c791c49
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_CHAR_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SPUT_JUMBO.S b/vm/mterp/x86/OP_SPUT_JUMBO.S
new file mode 100644
index 0000000..3f3d42a
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_JUMBO.S
@@ -0,0 +1,42 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 32-bit SPUT handler.
+     *
+     * for: sput/jumbo, sput-boolean/jumbo, sput-byte/jumbo, sput-char/jumbo,
+     *      sput-short/jumbo
+     */
+    /* exop vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    GET_VREG_R  rINST rINST
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    movl      rINST,offStaticField_value(%eax)
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SPUT_OBJECT.S b/vm/mterp/x86/OP_SPUT_OBJECT.S
new file mode 100644
index 0000000..45d84c7
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_OBJECT.S
@@ -0,0 +1,45 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * SPUT object handler.
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:                              # field ptr in eax
+    movzbl    rINSTbl,%ecx                       # ecx<- AA
+    GET_VREG_R  %ecx %ecx
+    movl      %ecx,offStaticField_value(%eax)    # do the store
+    testl     %ecx,%ecx                          # stored null object ptr?
+    je        1f                                 # skip card mark if null
+    movl      rSELF,%ecx
+    movl      offField_clazz(%eax),%eax          # eax<- method->clazz
+    movl      offThread_cardTable(%ecx),%ecx       # get card table base
+    shrl      $$GC_CARD_SHIFT,%eax               # head to card number
+    movb      %cl,(%ecx,%eax)                    # mark card
+1:
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SPUT_OBJECT_JUMBO.S b/vm/mterp/x86/OP_SPUT_OBJECT_JUMBO.S
new file mode 100644
index 0000000..5aab782
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_OBJECT_JUMBO.S
@@ -0,0 +1,44 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo SPUT object handler.
+     */
+    /* sput-object/jumbo vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:                              # field ptr in eax
+    GET_VREG_R  %ecx rINST
+    movl      %ecx,offStaticField_value(%eax)    # do the store
+    testl     %ecx,%ecx                          # stored null object ptr?
+    je        1f                                 # skip card mark if null
+    movl      rSELF,%ecx
+    movl      offField_clazz(%eax),%eax          # eax<- method->clazz
+    movl      offThread_cardTable(%ecx),%ecx       # get card table base
+    shrl      $$GC_CARD_SHIFT,%eax               # head to card number
+    movb      %cl,(%ecx,%eax)                    # mark card
+1:
+    FETCH_INST_OPCODE 4 %ecx
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SPUT_OBJECT_VOLATILE.S b/vm/mterp/x86/OP_SPUT_OBJECT_VOLATILE.S
new file mode 100644
index 0000000..afc6668
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_OBJECT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT_OBJECT.S"
diff --git a/vm/mterp/x86/OP_SPUT_SHORT.S b/vm/mterp/x86/OP_SPUT_SHORT.S
new file mode 100644
index 0000000..ec0489f
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86/OP_SPUT_SHORT_JUMBO.S b/vm/mterp/x86/OP_SPUT_SHORT_JUMBO.S
new file mode 100644
index 0000000..c791c49
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_SHORT_JUMBO.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT_JUMBO.S"
diff --git a/vm/mterp/x86/OP_SPUT_VOLATILE.S b/vm/mterp/x86/OP_SPUT_VOLATILE.S
new file mode 100644
index 0000000..ec0489f
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_VOLATILE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/OP_SPUT.S"
diff --git a/vm/mterp/x86/OP_SPUT_WIDE.S b/vm/mterp/x86/OP_SPUT_WIDE.S
new file mode 100644
index 0000000..d4c5841
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_WIDE.S
@@ -0,0 +1,43 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    movl      rSELF,%ecx
+    movzwl    2(rPC),%eax                        # eax<- field ref BBBB
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    GET_VREG_WORD %ecx rINST 0                  # rINST<- lsw
+    GET_VREG_WORD rINST rINST 1                 # ecx<- msw
+    movl      %ecx,offStaticField_value(%eax)
+    FETCH_INST_OPCODE 2 %ecx
+    movl      rINST,4+offStaticField_value(%eax)
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                        # eax<- field ref BBBB
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SPUT_WIDE_JUMBO.S b/vm/mterp/x86/OP_SPUT_WIDE_JUMBO.S
new file mode 100644
index 0000000..1fe544c
--- /dev/null
+++ b/vm/mterp/x86/OP_SPUT_WIDE_JUMBO.S
@@ -0,0 +1,41 @@
+%verify "executed"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+    /*
+     * Jumbo 64-bit SPUT handler.
+     */
+    /* sput-wide/jumbo vBBBB, field@AAAAAAAA */
+    movl      rSELF,%ecx
+    movl      offThread_methodClassDex(%ecx),%ecx  # ecx<- DvmDex
+    movl      2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl      offDvmDex_pResFields(%ecx),%ecx    # ecx<- dvmDex->pResFields
+    movl      (%ecx,%eax,4),%eax                 # eax<- resolved StaticField ptr
+    testl     %eax,%eax                          # resolved entry null?
+    je        .L${opcode}_resolve                # if not, make it so
+.L${opcode}_finish:     # field ptr in eax
+    GET_VREG_WORD %ecx rINST 0                  # ecx<- lsw
+    GET_VREG_WORD rINST rINST 1                 # rINST<- msw
+    movl      %ecx,offStaticField_value(%eax)
+    FETCH_INST_OPCODE 4 %ecx
+    movl      rINST,4+offStaticField_value(%eax)
+    ADVANCE_PC 4
+    GOTO_NEXT_R %ecx
+
+    /*
+     * Go resolve the field
+     */
+.L${opcode}_resolve:
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                        # eax<- field ref AAAAAAAA
+    movl     offThread_method(%ecx),%ecx          # ecx<- current method
+    EXPORT_PC                                   # could throw, need to export
+    movl     offMethod_clazz(%ecx),%ecx         # ecx<- method->clazz
+    movl     %eax,OUT_ARG1(%esp)
+    movl     %ecx,OUT_ARG0(%esp)
+    SPILL(rIBASE)
+    call     dvmResolveStaticField              # eax<- resolved StaticField ptr
+    UNSPILL(rIBASE)
+    testl    %eax,%eax
+    jne      .L${opcode}_finish                 # success, continue
+    jmp      common_exceptionThrown             # no, handle exception
diff --git a/vm/mterp/x86/OP_SUB_DOUBLE.S b/vm/mterp/x86/OP_SUB_DOUBLE.S
new file mode 100644
index 0000000..224f3a1
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fsubl","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..991c380
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fsubl","load":"fldl","store":"fstpl"}
diff --git a/vm/mterp/x86/OP_SUB_FLOAT.S b/vm/mterp/x86/OP_SUB_FLOAT.S
new file mode 100644
index 0000000..99d11c6
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop.S" {"instr":"fsubs","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/x86/OP_SUB_FLOAT_2ADDR.S
new file mode 100644
index 0000000..013334a
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binflop2addr.S" {"instr":"fsubs","load":"flds","store":"fstps"}
diff --git a/vm/mterp/x86/OP_SUB_INT.S b/vm/mterp/x86/OP_SUB_INT.S
new file mode 100644
index 0000000..04fcf21
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop.S" {"instr":"subl   (rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_SUB_INT_2ADDR.S b/vm/mterp/x86/OP_SUB_INT_2ADDR.S
new file mode 100644
index 0000000..0f63b86
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop2addr.S" {"instr":"subl     %eax,(rFP,%ecx,4)"}
diff --git a/vm/mterp/x86/OP_SUB_LONG.S b/vm/mterp/x86/OP_SUB_LONG.S
new file mode 100644
index 0000000..485818c
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide.S" {"instr1":"subl (rFP,%ecx,4),rIBASE", "instr2":"sbbl 4(rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_SUB_LONG_2ADDR.S b/vm/mterp/x86/OP_SUB_LONG_2ADDR.S
new file mode 100644
index 0000000..f2a94ea
--- /dev/null
+++ b/vm/mterp/x86/OP_SUB_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide2addr.S" {"instr1":"subl %eax,(rFP,rINST,4)","instr2":"sbbl %ecx,4(rFP,rINST,4)"}
diff --git a/vm/mterp/x86/OP_THROW.S b/vm/mterp/x86/OP_THROW.S
new file mode 100644
index 0000000..6559a29
--- /dev/null
+++ b/vm/mterp/x86/OP_THROW.S
@@ -0,0 +1,13 @@
+%verify "executed"
+%verify "exception for null object"
+    /*
+     * Throw an exception object in the current thread.
+     */
+    /* throw vAA */
+    EXPORT_PC
+    GET_VREG_R %eax rINST              # eax<- exception object
+    movl     rSELF,%ecx                # ecx<- self
+    testl    %eax,%eax                 # null object?
+    je       common_errNullObject
+    movl     %eax,offThread_exception(%ecx) # thread->exception<- obj
+    jmp      common_exceptionThrown
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..c934bdb
--- /dev/null
+++ b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S
@@ -0,0 +1,16 @@
+%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 */
+    movl     rSELF,%ecx
+    movzwl   2(rPC),%eax                     # eax<- BBBB
+    movl     offThread_method(%ecx),%ecx       # ecx<- self->method
+    EXPORT_PC
+    movl     %eax,OUT_ARG2(%esp)             # arg2<- BBBB
+    movl     rINST,OUT_ARG1(%esp)            # arg1<- AA
+    movl     %ecx,OUT_ARG0(%esp)             # arg0<- method
+    call     dvmThrowVerificationError       # call(method, kind, ref)
+    jmp      common_exceptionThrown          # handle exception
diff --git a/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR_JUMBO.S b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR_JUMBO.S
new file mode 100644
index 0000000..a9e092d
--- /dev/null
+++ b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR_JUMBO.S
@@ -0,0 +1,16 @@
+%verify executed
+    /*
+     * Handle a jumbo throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by BBBB, with some detail provided by AAAAAAAA.
+     */
+    /* exop BBBB, ref@AAAAAAAA */
+    movl     rSELF,%ecx
+    movl     2(rPC),%eax                     # eax<- AAAAAAAA
+    movl     offThread_method(%ecx),%ecx       # ecx<- self->method
+    EXPORT_PC
+    movl     %eax,OUT_ARG2(%esp)             # arg2<- AAAAAAAA
+    movl     rINST,OUT_ARG1(%esp)            # arg1<- BBBB
+    movl     %ecx,OUT_ARG0(%esp)             # arg0<- method
+    call     dvmThrowVerificationError       # call(method, kind, ref)
+    jmp      common_exceptionThrown          # handle exception
diff --git a/vm/mterp/x86/OP_UNUSED_27FF.S b/vm/mterp/x86/OP_UNUSED_27FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_27FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_28FF.S b/vm/mterp/x86/OP_UNUSED_28FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_28FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_29FF.S b/vm/mterp/x86/OP_UNUSED_29FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_29FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_2AFF.S b/vm/mterp/x86/OP_UNUSED_2AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_2AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_2BFF.S b/vm/mterp/x86/OP_UNUSED_2BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_2BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_2CFF.S b/vm/mterp/x86/OP_UNUSED_2CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_2CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_2DFF.S b/vm/mterp/x86/OP_UNUSED_2DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_2DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_2EFF.S b/vm/mterp/x86/OP_UNUSED_2EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_2EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_2FFF.S b/vm/mterp/x86/OP_UNUSED_2FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_2FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_30FF.S b/vm/mterp/x86/OP_UNUSED_30FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_30FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_31FF.S b/vm/mterp/x86/OP_UNUSED_31FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_31FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_32FF.S b/vm/mterp/x86/OP_UNUSED_32FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_32FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_33FF.S b/vm/mterp/x86/OP_UNUSED_33FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_33FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_34FF.S b/vm/mterp/x86/OP_UNUSED_34FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_34FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_35FF.S b/vm/mterp/x86/OP_UNUSED_35FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_35FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_36FF.S b/vm/mterp/x86/OP_UNUSED_36FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_36FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_37FF.S b/vm/mterp/x86/OP_UNUSED_37FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_37FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_38FF.S b/vm/mterp/x86/OP_UNUSED_38FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_38FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_39FF.S b/vm/mterp/x86/OP_UNUSED_39FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_39FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3AFF.S b/vm/mterp/x86/OP_UNUSED_3AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3BFF.S b/vm/mterp/x86/OP_UNUSED_3BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3CFF.S b/vm/mterp/x86/OP_UNUSED_3CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3DFF.S b/vm/mterp/x86/OP_UNUSED_3DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3E.S b/vm/mterp/x86/OP_UNUSED_3E.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3E.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3EFF.S b/vm/mterp/x86/OP_UNUSED_3EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3F.S b/vm/mterp/x86/OP_UNUSED_3F.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3F.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_3FFF.S b/vm/mterp/x86/OP_UNUSED_3FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_3FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_40.S b/vm/mterp/x86/OP_UNUSED_40.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_40.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_40FF.S b/vm/mterp/x86/OP_UNUSED_40FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_40FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_41.S b/vm/mterp/x86/OP_UNUSED_41.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_41.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_41FF.S b/vm/mterp/x86/OP_UNUSED_41FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_41FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_42.S b/vm/mterp/x86/OP_UNUSED_42.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_42.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_42FF.S b/vm/mterp/x86/OP_UNUSED_42FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_42FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_43.S b/vm/mterp/x86/OP_UNUSED_43.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_43.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_43FF.S b/vm/mterp/x86/OP_UNUSED_43FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_43FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_44FF.S b/vm/mterp/x86/OP_UNUSED_44FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_44FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_45FF.S b/vm/mterp/x86/OP_UNUSED_45FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_45FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_46FF.S b/vm/mterp/x86/OP_UNUSED_46FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_46FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_47FF.S b/vm/mterp/x86/OP_UNUSED_47FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_47FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_48FF.S b/vm/mterp/x86/OP_UNUSED_48FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_48FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_49FF.S b/vm/mterp/x86/OP_UNUSED_49FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_49FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_4AFF.S b/vm/mterp/x86/OP_UNUSED_4AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_4AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_4BFF.S b/vm/mterp/x86/OP_UNUSED_4BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_4BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_4CFF.S b/vm/mterp/x86/OP_UNUSED_4CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_4CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_4DFF.S b/vm/mterp/x86/OP_UNUSED_4DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_4DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_4EFF.S b/vm/mterp/x86/OP_UNUSED_4EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_4EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_4FFF.S b/vm/mterp/x86/OP_UNUSED_4FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_4FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_50FF.S b/vm/mterp/x86/OP_UNUSED_50FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_50FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_51FF.S b/vm/mterp/x86/OP_UNUSED_51FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_51FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_52FF.S b/vm/mterp/x86/OP_UNUSED_52FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_52FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_53FF.S b/vm/mterp/x86/OP_UNUSED_53FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_53FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_54FF.S b/vm/mterp/x86/OP_UNUSED_54FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_54FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_55FF.S b/vm/mterp/x86/OP_UNUSED_55FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_55FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_56FF.S b/vm/mterp/x86/OP_UNUSED_56FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_56FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_57FF.S b/vm/mterp/x86/OP_UNUSED_57FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_57FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_58FF.S b/vm/mterp/x86/OP_UNUSED_58FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_58FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_59FF.S b/vm/mterp/x86/OP_UNUSED_59FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_59FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_5AFF.S b/vm/mterp/x86/OP_UNUSED_5AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_5AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_5BFF.S b/vm/mterp/x86/OP_UNUSED_5BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_5BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_5CFF.S b/vm/mterp/x86/OP_UNUSED_5CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_5CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_5DFF.S b/vm/mterp/x86/OP_UNUSED_5DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_5DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_5EFF.S b/vm/mterp/x86/OP_UNUSED_5EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_5EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_5FFF.S b/vm/mterp/x86/OP_UNUSED_5FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_5FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_60FF.S b/vm/mterp/x86/OP_UNUSED_60FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_60FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_61FF.S b/vm/mterp/x86/OP_UNUSED_61FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_61FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_62FF.S b/vm/mterp/x86/OP_UNUSED_62FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_62FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_63FF.S b/vm/mterp/x86/OP_UNUSED_63FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_63FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_64FF.S b/vm/mterp/x86/OP_UNUSED_64FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_64FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_65FF.S b/vm/mterp/x86/OP_UNUSED_65FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_65FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_66FF.S b/vm/mterp/x86/OP_UNUSED_66FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_66FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_67FF.S b/vm/mterp/x86/OP_UNUSED_67FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_67FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_68FF.S b/vm/mterp/x86/OP_UNUSED_68FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_68FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_69FF.S b/vm/mterp/x86/OP_UNUSED_69FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_69FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_6AFF.S b/vm/mterp/x86/OP_UNUSED_6AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_6AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_6BFF.S b/vm/mterp/x86/OP_UNUSED_6BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_6BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_6CFF.S b/vm/mterp/x86/OP_UNUSED_6CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_6CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_6DFF.S b/vm/mterp/x86/OP_UNUSED_6DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_6DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_6EFF.S b/vm/mterp/x86/OP_UNUSED_6EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_6EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_6FFF.S b/vm/mterp/x86/OP_UNUSED_6FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_6FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_70FF.S b/vm/mterp/x86/OP_UNUSED_70FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_70FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_71FF.S b/vm/mterp/x86/OP_UNUSED_71FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_71FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_72FF.S b/vm/mterp/x86/OP_UNUSED_72FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_72FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_73.S b/vm/mterp/x86/OP_UNUSED_73.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_73.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_73FF.S b/vm/mterp/x86/OP_UNUSED_73FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_73FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_74FF.S b/vm/mterp/x86/OP_UNUSED_74FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_74FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_75FF.S b/vm/mterp/x86/OP_UNUSED_75FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_75FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_76FF.S b/vm/mterp/x86/OP_UNUSED_76FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_76FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_77FF.S b/vm/mterp/x86/OP_UNUSED_77FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_77FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_78FF.S b/vm/mterp/x86/OP_UNUSED_78FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_78FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_79.S b/vm/mterp/x86/OP_UNUSED_79.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_79.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_79FF.S b/vm/mterp/x86/OP_UNUSED_79FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_79FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7A.S b/vm/mterp/x86/OP_UNUSED_7A.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7A.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7AFF.S b/vm/mterp/x86/OP_UNUSED_7AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7BFF.S b/vm/mterp/x86/OP_UNUSED_7BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7CFF.S b/vm/mterp/x86/OP_UNUSED_7CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7DFF.S b/vm/mterp/x86/OP_UNUSED_7DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7EFF.S b/vm/mterp/x86/OP_UNUSED_7EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_7FFF.S b/vm/mterp/x86/OP_UNUSED_7FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_7FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_80FF.S b/vm/mterp/x86/OP_UNUSED_80FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_80FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_81FF.S b/vm/mterp/x86/OP_UNUSED_81FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_81FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_82FF.S b/vm/mterp/x86/OP_UNUSED_82FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_82FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_83FF.S b/vm/mterp/x86/OP_UNUSED_83FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_83FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_84FF.S b/vm/mterp/x86/OP_UNUSED_84FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_84FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_85FF.S b/vm/mterp/x86/OP_UNUSED_85FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_85FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_86FF.S b/vm/mterp/x86/OP_UNUSED_86FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_86FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_87FF.S b/vm/mterp/x86/OP_UNUSED_87FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_87FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_88FF.S b/vm/mterp/x86/OP_UNUSED_88FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_88FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_89FF.S b/vm/mterp/x86/OP_UNUSED_89FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_89FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_8AFF.S b/vm/mterp/x86/OP_UNUSED_8AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_8AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_8BFF.S b/vm/mterp/x86/OP_UNUSED_8BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_8BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_8CFF.S b/vm/mterp/x86/OP_UNUSED_8CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_8CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_8DFF.S b/vm/mterp/x86/OP_UNUSED_8DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_8DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_8EFF.S b/vm/mterp/x86/OP_UNUSED_8EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_8EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_8FFF.S b/vm/mterp/x86/OP_UNUSED_8FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_8FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_90FF.S b/vm/mterp/x86/OP_UNUSED_90FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_90FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_91FF.S b/vm/mterp/x86/OP_UNUSED_91FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_91FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_92FF.S b/vm/mterp/x86/OP_UNUSED_92FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_92FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_93FF.S b/vm/mterp/x86/OP_UNUSED_93FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_93FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_94FF.S b/vm/mterp/x86/OP_UNUSED_94FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_94FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_95FF.S b/vm/mterp/x86/OP_UNUSED_95FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_95FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_96FF.S b/vm/mterp/x86/OP_UNUSED_96FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_96FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_97FF.S b/vm/mterp/x86/OP_UNUSED_97FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_97FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_98FF.S b/vm/mterp/x86/OP_UNUSED_98FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_98FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_99FF.S b/vm/mterp/x86/OP_UNUSED_99FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_99FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_9AFF.S b/vm/mterp/x86/OP_UNUSED_9AFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_9AFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_9BFF.S b/vm/mterp/x86/OP_UNUSED_9BFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_9BFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_9CFF.S b/vm/mterp/x86/OP_UNUSED_9CFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_9CFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_9DFF.S b/vm/mterp/x86/OP_UNUSED_9DFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_9DFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_9EFF.S b/vm/mterp/x86/OP_UNUSED_9EFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_9EFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_9FFF.S b/vm/mterp/x86/OP_UNUSED_9FFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_9FFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A0FF.S b/vm/mterp/x86/OP_UNUSED_A0FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A0FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A1FF.S b/vm/mterp/x86/OP_UNUSED_A1FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A1FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A2FF.S b/vm/mterp/x86/OP_UNUSED_A2FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A2FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A3FF.S b/vm/mterp/x86/OP_UNUSED_A3FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A3FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A4FF.S b/vm/mterp/x86/OP_UNUSED_A4FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A4FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A5FF.S b/vm/mterp/x86/OP_UNUSED_A5FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A5FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A6FF.S b/vm/mterp/x86/OP_UNUSED_A6FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A6FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A7FF.S b/vm/mterp/x86/OP_UNUSED_A7FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A7FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A8FF.S b/vm/mterp/x86/OP_UNUSED_A8FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A8FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_A9FF.S b/vm/mterp/x86/OP_UNUSED_A9FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_A9FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_AAFF.S b/vm/mterp/x86/OP_UNUSED_AAFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_AAFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_ABFF.S b/vm/mterp/x86/OP_UNUSED_ABFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_ABFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_ACFF.S b/vm/mterp/x86/OP_UNUSED_ACFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_ACFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_ADFF.S b/vm/mterp/x86/OP_UNUSED_ADFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_ADFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_AEFF.S b/vm/mterp/x86/OP_UNUSED_AEFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_AEFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_AFFF.S b/vm/mterp/x86/OP_UNUSED_AFFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_AFFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B0FF.S b/vm/mterp/x86/OP_UNUSED_B0FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B0FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B1FF.S b/vm/mterp/x86/OP_UNUSED_B1FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B1FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B2FF.S b/vm/mterp/x86/OP_UNUSED_B2FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B2FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B3FF.S b/vm/mterp/x86/OP_UNUSED_B3FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B3FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B4FF.S b/vm/mterp/x86/OP_UNUSED_B4FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B4FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B5FF.S b/vm/mterp/x86/OP_UNUSED_B5FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B5FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B6FF.S b/vm/mterp/x86/OP_UNUSED_B6FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B6FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B7FF.S b/vm/mterp/x86/OP_UNUSED_B7FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B7FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B8FF.S b/vm/mterp/x86/OP_UNUSED_B8FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B8FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_B9FF.S b/vm/mterp/x86/OP_UNUSED_B9FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_B9FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_BAFF.S b/vm/mterp/x86/OP_UNUSED_BAFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_BAFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_BBFF.S b/vm/mterp/x86/OP_UNUSED_BBFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_BBFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_BCFF.S b/vm/mterp/x86/OP_UNUSED_BCFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_BCFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_BDFF.S b/vm/mterp/x86/OP_UNUSED_BDFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_BDFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_BEFF.S b/vm/mterp/x86/OP_UNUSED_BEFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_BEFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_BFFF.S b/vm/mterp/x86/OP_UNUSED_BFFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_BFFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C0FF.S b/vm/mterp/x86/OP_UNUSED_C0FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C0FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C1FF.S b/vm/mterp/x86/OP_UNUSED_C1FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C1FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C2FF.S b/vm/mterp/x86/OP_UNUSED_C2FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C2FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C3FF.S b/vm/mterp/x86/OP_UNUSED_C3FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C3FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C4FF.S b/vm/mterp/x86/OP_UNUSED_C4FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C4FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C5FF.S b/vm/mterp/x86/OP_UNUSED_C5FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C5FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C6FF.S b/vm/mterp/x86/OP_UNUSED_C6FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C6FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C7FF.S b/vm/mterp/x86/OP_UNUSED_C7FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C7FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C8FF.S b/vm/mterp/x86/OP_UNUSED_C8FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C8FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_C9FF.S b/vm/mterp/x86/OP_UNUSED_C9FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_C9FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_CAFF.S b/vm/mterp/x86/OP_UNUSED_CAFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_CAFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_CBFF.S b/vm/mterp/x86/OP_UNUSED_CBFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_CBFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_CCFF.S b/vm/mterp/x86/OP_UNUSED_CCFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_CCFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_CDFF.S b/vm/mterp/x86/OP_UNUSED_CDFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_CDFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_CEFF.S b/vm/mterp/x86/OP_UNUSED_CEFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_CEFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_CFFF.S b/vm/mterp/x86/OP_UNUSED_CFFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_CFFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D0FF.S b/vm/mterp/x86/OP_UNUSED_D0FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D0FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D1FF.S b/vm/mterp/x86/OP_UNUSED_D1FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D1FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D2FF.S b/vm/mterp/x86/OP_UNUSED_D2FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D2FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D3FF.S b/vm/mterp/x86/OP_UNUSED_D3FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D3FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D4FF.S b/vm/mterp/x86/OP_UNUSED_D4FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D4FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D5FF.S b/vm/mterp/x86/OP_UNUSED_D5FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D5FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D6FF.S b/vm/mterp/x86/OP_UNUSED_D6FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D6FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D7FF.S b/vm/mterp/x86/OP_UNUSED_D7FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D7FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D8FF.S b/vm/mterp/x86/OP_UNUSED_D8FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D8FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_D9FF.S b/vm/mterp/x86/OP_UNUSED_D9FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_D9FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_DAFF.S b/vm/mterp/x86/OP_UNUSED_DAFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_DAFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_DBFF.S b/vm/mterp/x86/OP_UNUSED_DBFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_DBFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_DCFF.S b/vm/mterp/x86/OP_UNUSED_DCFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_DCFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_DDFF.S b/vm/mterp/x86/OP_UNUSED_DDFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_DDFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_DEFF.S b/vm/mterp/x86/OP_UNUSED_DEFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_DEFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_DFFF.S b/vm/mterp/x86/OP_UNUSED_DFFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_DFFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E0FF.S b/vm/mterp/x86/OP_UNUSED_E0FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E0FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E1FF.S b/vm/mterp/x86/OP_UNUSED_E1FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E1FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E2FF.S b/vm/mterp/x86/OP_UNUSED_E2FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E2FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E3FF.S b/vm/mterp/x86/OP_UNUSED_E3FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E3FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E4FF.S b/vm/mterp/x86/OP_UNUSED_E4FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E4FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E5FF.S b/vm/mterp/x86/OP_UNUSED_E5FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E5FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E6FF.S b/vm/mterp/x86/OP_UNUSED_E6FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E6FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E7FF.S b/vm/mterp/x86/OP_UNUSED_E7FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E7FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E8FF.S b/vm/mterp/x86/OP_UNUSED_E8FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E8FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_E9FF.S b/vm/mterp/x86/OP_UNUSED_E9FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_E9FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EAFF.S b/vm/mterp/x86/OP_UNUSED_EAFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_EAFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EBFF.S b/vm/mterp/x86/OP_UNUSED_EBFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_EBFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_ECFF.S b/vm/mterp/x86/OP_UNUSED_ECFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_ECFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EDFF.S b/vm/mterp/x86/OP_UNUSED_EDFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_EDFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EEFF.S b/vm/mterp/x86/OP_UNUSED_EEFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_EEFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_EFFF.S b/vm/mterp/x86/OP_UNUSED_EFFF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_EFFF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_F0FF.S b/vm/mterp/x86/OP_UNUSED_F0FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_F0FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_UNUSED_F1FF.S b/vm/mterp/x86/OP_UNUSED_F1FF.S
new file mode 100644
index 0000000..31d98c1
--- /dev/null
+++ b/vm/mterp/x86/OP_UNUSED_F1FF.S
@@ -0,0 +1 @@
+%include "x86/unused.S"
diff --git a/vm/mterp/x86/OP_USHR_INT.S b/vm/mterp/x86/OP_USHR_INT.S
new file mode 100644
index 0000000..04b9210
--- /dev/null
+++ b/vm/mterp/x86/OP_USHR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop1.S" {"instr":"shrl    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_USHR_INT_2ADDR.S b/vm/mterp/x86/OP_USHR_INT_2ADDR.S
new file mode 100644
index 0000000..02a94ff
--- /dev/null
+++ b/vm/mterp/x86/OP_USHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/shop2addr.S" {"instr":"shrl    %cl,%eax"}
diff --git a/vm/mterp/x86/OP_USHR_INT_LIT8.S b/vm/mterp/x86/OP_USHR_INT_LIT8.S
new file mode 100644
index 0000000..24fd087
--- /dev/null
+++ b/vm/mterp/x86/OP_USHR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"shrl     %cl,%eax"}
diff --git a/vm/mterp/x86/OP_USHR_LONG.S b/vm/mterp/x86/OP_USHR_LONG.S
new file mode 100644
index 0000000..4f3647e
--- /dev/null
+++ b/vm/mterp/x86/OP_USHR_LONG.S
@@ -0,0 +1,32 @@
+%verify "executed"
+    /*
+     * 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.  x86 shifts automatically mask off
+     * the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
+     * case specially.
+     */
+    /* shr-long vAA, vBB, vCC */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE %eax 1         # rIBASE<- v[BB+1]
+    GET_VREG_R  %ecx %ecx               # ecx<- vCC
+    GET_VREG_WORD %eax %eax 0           # eax<- v[BB+0]
+    shrdl     rIBASE,%eax
+    shrl      %cl,rIBASE
+    testb     $$32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    xorl      rIBASE,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1          # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0         # v[BB+0]<- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_USHR_LONG_2ADDR.S b/vm/mterp/x86/OP_USHR_LONG_2ADDR.S
new file mode 100644
index 0000000..d4396b4
--- /dev/null
+++ b/vm/mterp/x86/OP_USHR_LONG_2ADDR.S
@@ -0,0 +1,29 @@
+%verify "executed"
+    /*
+     * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
+     * 32-bit shift distance.
+     */
+    /* shl-long/2addr vA, vB */
+    /* ecx gets shift count */
+    /* Need to spill rIBASE */
+    /* rINSTw gets AA */
+    movzbl    rINSTbl,%ecx             # ecx<- BA
+    andb      $$0xf,rINSTbl            # rINST<- A
+    GET_VREG_WORD %eax rINST 0         # eax<- v[AA+0]
+    sarl      $$4,%ecx                 # ecx<- B
+    SPILL(rIBASE)
+    GET_VREG_WORD rIBASE rINST 1       # rIBASE<- v[AA+1]
+    GET_VREG_R %ecx %ecx               # ecx<- vBB
+    shrdl     rIBASE,%eax
+    shrl      %cl,rIBASE
+    testb     $$32,%cl
+    je        2f
+    movl      rIBASE,%eax
+    xorl      rIBASE,rIBASE
+2:
+    SET_VREG_WORD rIBASE rINST 1       # v[AA+1]<- rIBASE
+    FETCH_INST_OPCODE 1 %ecx
+    UNSPILL(rIBASE)
+    SET_VREG_WORD %eax rINST 0         # v[AA+0]<- eax
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/OP_XOR_INT.S b/vm/mterp/x86/OP_XOR_INT.S
new file mode 100644
index 0000000..71e4013
--- /dev/null
+++ b/vm/mterp/x86/OP_XOR_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop.S" {"instr":"xorl   (rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_XOR_INT_2ADDR.S b/vm/mterp/x86/OP_XOR_INT_2ADDR.S
new file mode 100644
index 0000000..50880cf
--- /dev/null
+++ b/vm/mterp/x86/OP_XOR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binop2addr.S" {"instr":"xorl     %eax,(rFP,%ecx,4)"}
diff --git a/vm/mterp/x86/OP_XOR_INT_LIT16.S b/vm/mterp/x86/OP_XOR_INT_LIT16.S
new file mode 100644
index 0000000..e62e4df
--- /dev/null
+++ b/vm/mterp/x86/OP_XOR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit16.S" {"instr":"xor    %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_XOR_INT_LIT8.S b/vm/mterp/x86/OP_XOR_INT_LIT8.S
new file mode 100644
index 0000000..9ccca3f
--- /dev/null
+++ b/vm/mterp/x86/OP_XOR_INT_LIT8.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopLit8.S" {"instr":"xor    %ecx,%eax"}
diff --git a/vm/mterp/x86/OP_XOR_LONG.S b/vm/mterp/x86/OP_XOR_LONG.S
new file mode 100644
index 0000000..3cd5ffb
--- /dev/null
+++ b/vm/mterp/x86/OP_XOR_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide.S" {"instr1":"xorl (rFP,%ecx,4),rIBASE", "instr2":"xorl 4(rFP,%ecx,4),%eax"}
diff --git a/vm/mterp/x86/OP_XOR_LONG_2ADDR.S b/vm/mterp/x86/OP_XOR_LONG_2ADDR.S
new file mode 100644
index 0000000..6d72124
--- /dev/null
+++ b/vm/mterp/x86/OP_XOR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "x86/binopWide2addr.S" {"instr1":"xorl %eax,(rFP,rINST,4)","instr2":"xorl %ecx,4(rFP,rINST,4)"}
diff --git a/vm/mterp/x86/alt_stub.S b/vm/mterp/x86/alt_stub.S
new file mode 100644
index 0000000..9807ad1
--- /dev/null
+++ b/vm/mterp/x86/alt_stub.S
@@ -0,0 +1,22 @@
+/*
+ * Inter-instruction transfer stub.  Call out to dvmCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Unlike the Arm handler, we can't do this as a tail call
+ * because rIBASE is caller save and we need to reload it.
+ *
+ * Note that unlike in the Arm implementation, we should never arrive
+ * here with a zero breakFlag because we always refresh rIBASE on
+ * return.
+ */
+    EXPORT_PC
+    movl   rSELF, %eax
+    movl   rPC, OUT_ARG0(%esp)
+    cmpb   $$0,offThread_breakFlags(%eax)    # anything to do?
+    movl   rFP, OUT_ARG1(%esp)
+    je     1f                                # reload rIBASE & resume if not
+    movl   %eax, OUT_ARG2(%esp)
+    call   dvmCheckBefore                    # (dPC, dFP, self)
+    movl   rSELF, %eax
+1:
+    movl   offThread_curHandlerTable(%eax), rIBASE # reload rIBASE
+    jmp    *dvmAsmInstructionStart+(${opnum}*4)
diff --git a/vm/mterp/x86/bincmp.S b/vm/mterp/x86/bincmp.S
new file mode 100644
index 0000000..ffa4a24
--- /dev/null
+++ b/vm/mterp/x86/bincmp.S
@@ -0,0 +1,24 @@
+%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 */
+    movzx    rINSTbl,%ecx          # ecx <- A+
+    andb     $$0xf,%cl             # ecx <- A
+    GET_VREG_R %eax %ecx           # eax <- vA
+    sarl     $$4,rINST             # rINST<- B
+    movl     rSELF,%ecx
+    cmpl     (rFP,rINST,4),%eax    # compare (vA, vB)
+    movl     $$2,%eax              # assume not taken
+    j${revcmp}   1f
+    movswl   2(rPC),%eax           # Get signed branch offset
+1:
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
diff --git a/vm/mterp/x86/bindiv.S b/vm/mterp/x86/bindiv.S
new file mode 100644
index 0000000..cbd2f3d
--- /dev/null
+++ b/vm/mterp/x86/bindiv.S
@@ -0,0 +1,33 @@
+
+%default {"result":"","special":""}
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    SPILL(rIBASE)
+    cmpl     $$0,%ecx
+    je       common_errDivideByZero
+    cmpl     $$-1,%ecx
+    jne      .L${opcode}_continue_div
+    cmpl     $$0x80000000,%eax
+    jne      .L${opcode}_continue_div
+    movl     $special,$result
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/bindiv2addr.S b/vm/mterp/x86/bindiv2addr.S
new file mode 100644
index 0000000..cc415be
--- /dev/null
+++ b/vm/mterp/x86/bindiv2addr.S
@@ -0,0 +1,33 @@
+%default {"result":"","special":""}
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* div/rem/2addr vA, vB */
+    movzx    rINSTbl,%ecx          # eax<- BA
+    SPILL(rIBASE)
+    sarl     $$4,%ecx              # ecx<- B
+    GET_VREG_R %ecx %ecx           # eax<- vBB
+    andb     $$0xf,rINSTbl         # rINST<- A
+    GET_VREG_R %eax rINST          # eax<- vBB
+    cmpl     $$0,%ecx
+    je       common_errDivideByZero
+    cmpl     $$-1,%ecx
+    jne      .L${opcode}_continue_div2addr
+    cmpl     $$0x80000000,%eax
+    jne      .L${opcode}_continue_div2addr
+    movl     $special,$result
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_continue_div2addr:
+    cltd
+    idivl   %ecx
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/bindivLit16.S b/vm/mterp/x86/bindivLit16.S
new file mode 100644
index 0000000..c935367
--- /dev/null
+++ b/vm/mterp/x86/bindivLit16.S
@@ -0,0 +1,34 @@
+%default {"result":"","special":""}
+    /*
+     * 32-bit binary div/rem operation.  Handles special case of op0=minint and
+     * op1=-1.
+     */
+    /* div/rem/lit16 vA, vB, #+CCCC */
+    /* Need A in rINST, ssssCCCC in ecx, vB in eax */
+    movzbl   rINSTbl,%eax         # eax<- 000000BA
+    SPILL(rIBASE)
+    sarl     $$4,%eax             # eax<- B
+    GET_VREG_R %eax %eax          # eax<- vB
+    movswl   2(rPC),%ecx          # ecx<- ssssCCCC
+    andb     $$0xf,rINSTbl        # rINST<- A
+    cmpl     $$0,%ecx
+    je       common_errDivideByZero
+    cmpl     $$-1,%ecx
+    jne      .L${opcode}_continue_div
+    cmpl     $$0x80000000,%eax
+    jne      .L${opcode}_continue_div
+    movl     $special,$result
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/bindivLit8.S b/vm/mterp/x86/bindivLit8.S
new file mode 100644
index 0000000..94adef4
--- /dev/null
+++ b/vm/mterp/x86/bindivLit8.S
@@ -0,0 +1,31 @@
+%default {"result":"","special":""}
+    /*
+     * 32-bit div/rem "lit8" binary operation.  Handles special case of
+     * op0=minint & op1=-1
+     */
+    /* div/rem/lit8 vAA, vBB, #+CC */
+    movzbl    2(rPC),%eax        # eax<- BB
+    movsbl    3(rPC),%ecx        # ecx<- ssssssCC
+    SPILL(rIBASE)
+    GET_VREG_R  %eax %eax        # eax<- rBB
+    cmpl     $$0,%ecx
+    je       common_errDivideByZero
+    cmpl     $$0x80000000,%eax
+    jne      .L${opcode}_continue_div
+    cmpl     $$-1,%ecx
+    jne      .L${opcode}_continue_div
+    movl     $special,$result
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_continue_div:
+    cltd
+    idivl   %ecx
+    SET_VREG $result rINST
+    UNSPILL(rIBASE)
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binflop.S b/vm/mterp/x86/binflop.S
new file mode 100644
index 0000000..a432956
--- /dev/null
+++ b/vm/mterp/x86/binflop.S
@@ -0,0 +1,14 @@
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax          # eax<- CC
+    movzbl   3(rPC),%ecx          # ecx<- BB
+    $load    (rFP,%eax,4)         # vCC to fp stack
+    $instr   (rFP,%ecx,4)         # ex: faddp
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    $store   (rFP,rINST,4)         # %st to vAA
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binflop2addr.S b/vm/mterp/x86/binflop2addr.S
new file mode 100644
index 0000000..c616d8b
--- /dev/null
+++ b/vm/mterp/x86/binflop2addr.S
@@ -0,0 +1,16 @@
+    /*
+     * Generic 32-bit binary float operation.
+     *
+     * For: add-fp, sub-fp, mul-fp, div-fp
+     */
+
+    /* binop/2addr vA, vB */
+    movzx   rINSTbl,%ecx           # ecx<- A+
+    andb    $$0xf,%cl              # ecx<- A
+    $load    (rFP,%ecx,4)          # vAA to fp stack
+    sarl    $$4,rINST             # rINST<- B
+    $instr   (rFP,rINST,4)         # ex: faddp
+    FETCH_INST_OPCODE 1 %eax
+    ADVANCE_PC 1
+    $store    (rFP,%ecx,4)         # %st to vA
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/binop.S b/vm/mterp/x86/binop.S
new file mode 100644
index 0000000..af2e908
--- /dev/null
+++ b/vm/mterp/x86/binop.S
@@ -0,0 +1,19 @@
+%default {"result":"%eax"}
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = eax op (rFP,%ecx,4)".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int, sub-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax   # eax<- BB
+    movzbl   3(rPC),%ecx   # ecx<- CC
+    GET_VREG_R %eax %eax   # eax<- vBB
+    $instr                 # ex: addl    (rFP,%ecx,4),%eax
+    SET_VREG $result rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binop1.S b/vm/mterp/x86/binop1.S
new file mode 100644
index 0000000..38c2daf
--- /dev/null
+++ b/vm/mterp/x86/binop1.S
@@ -0,0 +1,15 @@
+%default {"result":"%eax","tmp":"%ecx"}
+    /*
+     * Generic 32-bit binary operation in which both operands loaded to
+     * registers (op0 in eax, op1 in ecx).
+     */
+    /* binop vAA, vBB, vCC */
+    movzbl   2(rPC),%eax            # eax<- BB
+    movzbl   3(rPC),%ecx            # ecx<- CC
+    GET_VREG_R %eax %eax            # eax<- vBB
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    $instr                          # ex: addl    %ecx,%eax
+    SET_VREG $result rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binop2addr.S b/vm/mterp/x86/binop2addr.S
new file mode 100644
index 0000000..7cd8c5b
--- /dev/null
+++ b/vm/mterp/x86/binop2addr.S
@@ -0,0 +1,24 @@
+%default {"result":"%eax"}
+    /*
+     * 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 */
+    movzx   rINSTbl,%ecx               # ecx<- A+
+    sarl    $$4,rINST                 # rINST<- B
+    GET_VREG_R %eax rINST              # eax<- vB
+    andb    $$0xf,%cl                  # ecx<- A
+    $instr                             # for ex: addl   %eax,(rFP,%ecx,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binopLit16.S b/vm/mterp/x86/binopLit16.S
new file mode 100644
index 0000000..4ca6c77
--- /dev/null
+++ b/vm/mterp/x86/binopLit16.S
@@ -0,0 +1,21 @@
+%default {"result":"%eax"}
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than eax, you can override "result".)
+     *
+     * For: add-int/lit16, rsub-int,
+     *      and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    movzbl   rINSTbl,%eax               # eax<- 000000BA
+    sarl     $$4,%eax                   # eax<- B
+    GET_VREG_R %eax %eax                # eax<- vB
+    movswl   2(rPC),%ecx                # ecx<- ssssCCCC
+    andb     $$0xf,rINSTbl              # rINST<- A
+    $instr                              # for example: addl %ecx, %eax
+    SET_VREG $result rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binopLit8.S b/vm/mterp/x86/binopLit8.S
new file mode 100644
index 0000000..08e2efd
--- /dev/null
+++ b/vm/mterp/x86/binopLit8.S
@@ -0,0 +1,20 @@
+%default {"result":"%eax"}
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = eax op ecx".
+     * This could be an x86 instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * For: add-int/lit8, rsub-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 */
+    movzbl    2(rPC),%eax              # eax<- BB
+    movsbl    3(rPC),%ecx              # ecx<- ssssssCC
+    GET_VREG_R   %eax %eax             # eax<- rBB
+    $instr                             # ex: addl %ecx,%eax
+    SET_VREG   $result rINST
+    FETCH_INST_OPCODE 2 %ecx
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binopWide.S b/vm/mterp/x86/binopWide.S
new file mode 100644
index 0000000..6114aff
--- /dev/null
+++ b/vm/mterp/x86/binopWide.S
@@ -0,0 +1,18 @@
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop vAA, vBB, vCC */
+
+    movzbl    2(rPC),%eax               # eax<- BB
+    movzbl    3(rPC),%ecx               # ecx<- CC
+    SPILL(rIBASE)                       # save rIBASE
+    GET_VREG_WORD rIBASE %eax 0         # rIBASE<- v[BB+0]
+    GET_VREG_WORD %eax %eax 1           # eax<- v[BB+1]
+    $instr1         # ex: addl   (rFP,%ecx,4),rIBASE
+    $instr2         # ex: adcl   4(rFP,%ecx,4),%eax
+    SET_VREG_WORD rIBASE rINST 0        # v[AA+0] <- rIBASE
+    FETCH_INST_OPCODE 2 %ecx
+    UNSPILL(rIBASE)                     # restore rIBASE
+    SET_VREG_WORD %eax rINST 1          # v[AA+1] <- eax
+    ADVANCE_PC 2
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/binopWide2addr.S b/vm/mterp/x86/binopWide2addr.S
new file mode 100644
index 0000000..fa42644
--- /dev/null
+++ b/vm/mterp/x86/binopWide2addr.S
@@ -0,0 +1,14 @@
+    /*
+     * Generic 64-bit binary operation.
+     */
+    /* binop/2addr vA, vB */
+    movzbl    rINSTbl,%ecx              # ecx<- BA
+    sarl      $$4,%ecx                  # ecx<- B
+    GET_VREG_WORD %eax %ecx 0           # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1           # eax<- v[B+1]
+    andb      $$0xF,rINSTbl             # rINST<- A
+    $instr1         # example: addl   %eax,(rFP,rINST,4)
+    $instr2         # example: adcl   %ecx,4(rFP,rINST,4)
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/cvtfp_int.S b/vm/mterp/x86/cvtfp_int.S
new file mode 100644
index 0000000..7590943
--- /dev/null
+++ b/vm/mterp/x86/cvtfp_int.S
@@ -0,0 +1,58 @@
+%default {"srcdouble":"1","tgtlong":"1"}
+/* On fp to int conversions, Java requires that
+ * if the result > maxint, it should be clamped to maxint.  If it is less
+ * than minint, it should be clamped to minint.  If it is a nan, the result
+ * should be zero.  Further, the rounding mode is to truncate.  This model
+ * differs from what is delivered normally via the x86 fpu, so we have
+ * to play some games.
+ */
+    /* float/double to int/long vA, vB */
+    movzbl    rINSTbl,%ecx       # ecx<- A+
+    sarl      $$4,rINST         # rINST<- B
+    .if $srcdouble
+    fldl     (rFP,rINST,4)       # %st0<- vB
+    .else
+    flds     (rFP,rINST,4)       # %st0<- vB
+    .endif
+    ftst
+    fnstcw   LOCAL0_OFFSET(%ebp)      # remember original rounding mode
+    movzwl   LOCAL0_OFFSET(%ebp),%eax
+    movb     $$0xc,%ah
+    movw     %ax,LOCAL0_OFFSET+2(%ebp)
+    fldcw    LOCAL0_OFFSET+2(%ebp)    # set "to zero" rounding mode
+    andb     $$0xf,%cl                # ecx<- A
+    .if $tgtlong
+    fistpll  (rFP,%ecx,4)             # convert and store
+    .else
+    fistpl   (rFP,%ecx,4)             # convert and store
+    .endif
+    fldcw    LOCAL0_OFFSET(%ebp)      # restore previous rounding mode
+    .if $tgtlong
+    movl     $$0x80000000,%eax
+    xorl     4(rFP,%ecx,4),%eax
+    orl      (rFP,%ecx,4),%eax
+    .else
+    cmpl     $$0x80000000,(rFP,%ecx,4)
+    .endif
+    je       .L${opcode}_special_case # fix up result
+
+.L${opcode}_finish:
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
+
+.L${opcode}_special_case:
+    fnstsw   %ax
+    sahf
+    jp       .L${opcode}_isNaN
+    adcl     $$-1,(rFP,%ecx,4)
+    .if $tgtlong
+    adcl     $$-1,4(rFP,%ecx,4)
+    .endif
+   jmp       .L${opcode}_finish
+.L${opcode}_isNaN:
+    movl      $$0,(rFP,%ecx,4)
+    .if $tgtlong
+    movl      $$0,4(rFP,%ecx,4)
+    .endif
+    jmp       .L${opcode}_finish
diff --git a/vm/mterp/x86/entry.S b/vm/mterp/x86/entry.S
new file mode 100644
index 0000000..3e2a708
--- /dev/null
+++ b/vm/mterp/x86/entry.S
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+
+    .text
+    .global dvmMterpStdRun
+    .type   dvmMterpStdRun, %function
+/*
+ * bool dvmMterpStdRun(Thread* self)
+ *
+ * Interpreter entry point.  Returns changeInterp.
+ *
+ */
+dvmMterpStdRun:
+    push    %ebp                 # save caller base pointer
+    movl    %esp, %ebp           # set our %ebp
+    movl    rSELF, %ecx          # get incoming rSELF
+/*
+ * At this point we've allocated one slot on the stack
+ * via push and stack is 8-byte aligned.  Allocate space
+ * for 9 spill slots, 4 local slots, 5 arg slots to bring
+ * us to 16-byte alignment
+ */
+    subl    $$(FRAME_SIZE-4), %esp
+
+/* Spill callee save regs */
+    movl    %edi,EDI_SPILL(%ebp)
+    movl    %esi,ESI_SPILL(%ebp)
+    movl    %ebx,EBX_SPILL(%ebp)
+
+/* Set up "named" registers */
+    movl    offThread_pc(%ecx),rPC
+    movl    offThread_curFrame(%ecx),rFP
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+
+/* Remember %esp for future "longjmp" */
+    movl    %esp,offThread_bailPtr(%ecx)
+
+   /* Normal case: start executing the instruction at rPC */
+    FETCH_INST
+    GOTO_NEXT
+
+    .global dvmMterpStdBail
+    .type   dvmMterpStdBail, %function
+/*
+ * void dvmMterpStdBail(Thread* self, bool changeInterp)
+ *
+ * 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're not going to build a standard frame here, so the arg accesses will
+ * look a little strange.
+ *
+ * On entry:
+ *  esp+4 (arg0)  Thread* self
+ *  esp+8 (arg1)  bool changeInterp
+ */
+dvmMterpStdBail:
+    movl    4(%esp),%ecx                 # grab self
+    movl    8(%esp),%eax                 # changeInterp to return reg
+    movl    offThread_bailPtr(%ecx),%esp   # Restore "setjmp" esp
+    movl    %esp,%ebp
+    addl    $$(FRAME_SIZE-4), %ebp       # Restore %ebp at point of setjmp
+    movl    EDI_SPILL(%ebp),%edi
+    movl    ESI_SPILL(%ebp),%esi
+    movl    EBX_SPILL(%ebp),%ebx
+    movl    %ebp, %esp                   # strip frame
+    pop     %ebp                         # restore caller's ebp
+    ret                                  # return to dvmMterpStdRun's caller
+
+
+/*
+ * Strings
+ */
+    .section    .rodata
+.LstrBadEntryPoint:
+    .asciz  "Bad entry point %d\n"
+
diff --git a/vm/mterp/x86/footer.S b/vm/mterp/x86/footer.S
new file mode 100644
index 0000000..d4b38a9
--- /dev/null
+++ b/vm/mterp/x86/footer.S
@@ -0,0 +1,646 @@
+/*
+ * 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 subroutines and data.
+ */
+
+#if defined(WITH_JIT)
+/*
+ * JIT-related re-entries into the interpreter.  In general, if the
+ * exit from a translation can at some point be chained, the entry
+ * here requires that control arrived via a call, and that the "rp"
+ * on TOS is actually a pointer to a 32-bit cell containing the Dalvik PC
+ * of the next insn to handle.  If no chaining will happen, the entry
+ * should be reached via a direct jump and rPC set beforehand.
+ */
+
+    .global dvmJitToInterpPunt
+/*
+ * The compiler will generate a jump to this entry point when it is
+ * having difficulty translating a Dalvik instruction.  We must skip
+ * the code cache lookup & prevent chaining to avoid bouncing between
+ * the interpreter and code cache. rPC must be set on entry.
+ */
+dvmJitToInterpPunt:
+#if defined(WITH_JIT_TUNING)
+    movl   rPC, OUT_ARG0(%esp)
+    call   dvmBumpPunt
+#endif
+    movl   rSELF, %ecx
+    movl   offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_R %ecx
+    GOTO_NEXT_R %ecx
+
+    .global dvmJitToInterpSingleStep
+/*
+ * Return to the interpreter to handle a single instruction.
+ * Should be reached via a call.
+ * On entry:
+ *   0(%esp)          <= native return address within trace
+ *   rPC              <= Dalvik PC of this instruction
+ *   OUT_ARG0+4(%esp) <= Dalvik PC of next instruction
+ */
+dvmJitToInterpSingleStep:
+/* TODO */
+    call     dvmAbort
+#if 0
+    pop    %eax
+    movl   rSELF, %ecx
+    movl   OUT_ARG0(%esp), %edx
+    movl   %eax,offThread_jitResumeNPC(%ecx)
+    movl   %edx,offThread_jitResumeDPC(%ecx)
+    movl   $$kInterpEntryInstr,offThread_entryPoint(%ecx)
+    movl   $$1,rINST     # changeInterp <= true
+    jmp    common_gotoBail
+#endif
+
+    .global dvmJitToInterpNoChainNoProfile
+/*
+ * Return from the translation cache to the interpreter to do method
+ * invocation.  Check if the translation exists for the callee, but don't
+ * chain to it. rPC must be set on entry.
+ */
+dvmJitToInterpNoChainNoProfile:
+#if defined(WITH_JIT_TUNING)
+    call   dvmBumpNoChain
+#endif
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddrThread        # (pc, self)
+    movl   rSELF,%ecx                # ecx <- self
+    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
+    cmpl   $$0, %eax
+    jz     1f
+    call   *%eax                     # exec translation if we've got one
+    # won't return
+1:
+    movl   rSELF, %ecx
+    movl   offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_R %ecx
+    GOTO_NEXT_R %ecx
+
+/*
+ * Return from the translation cache and immediately request a
+ * translation fro the exit target, but don't attempt to chain.
+ * rPC set on entry.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#if defined(WITH_JIT_TUNING)
+    call   dvmBumpNoChain
+#endif
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddrThread # (pc, self)
+    movl   rSELF,%ecx
+    cmpl   $$0,%eax
+    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
+    jz     1f
+    call   *%eax              # jump to tranlation
+    # won't return
+
+/* No Translation - request one */
+1:
+    GET_JIT_PROF_TABLE %ecx %eax
+    cmpl   $$0, %eax          # JIT enabled?
+    jnz    2f                 # Request one if so
+    movl   rSELF, %ecx
+    movl   offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST_R %ecx         # Continue interpreting if not
+    GOTO_NEXT_R %ecx
+2:
+    movl   $$kJitTSelectRequestHot,rINST  # ask for trace select
+    jmp    common_selectTrace
+
+/*
+ * Return from the translation cache and immediately request a
+ * translation for the exit target.  Reached via a call, and
+ * (TOS)->rPC.
+ */
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    pop    rINST           # save chain cell address in callee save reg
+    movl   (rINST),rPC
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddrThread # (pc, self)
+    cmpl   $$0,%eax
+    jz     1b                 # no - ask for one
+    movl   %eax,OUT_ARG0(%esp)
+# TODO - need to adjust rINST to beginning of sequence
+    movl   rINST,OUT_ARG1(%esp)
+    call   dvmJitChain        # Attempt dvmJitChain(codeAddr,chainAddr)
+    cmpl   $$0,%eax           # Success?
+    jz     toInterpreter      # didn't chain - interpret
+    call   *%eax
+    # won't return
+
+/*
+ * Placeholder entries for x86 JIT
+ */
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+toInterpreter:
+    jmp  common_abort
+
+common_updateProfile:
+    # quick & dirty hash
+    movl   rPC, %eax
+    shrl   $$12, %eax
+    xorl   rPC, %eax
+    andl   $$((1<<JIT_PROF_SIZE_LOG_2)-1),%eax
+    decb   (%edx,%eax)
+    jz     2f
+1:
+    GOTO_NEXT
+2:
+/*
+ * 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.
+ */
+    GET_JIT_THRESHOLD %ecx rINST  # leaves rSELF in %ecx
+    EXPORT_PC
+    movb   rINSTbl,(%edx,%eax)   # reset counter
+    movl   %ecx,rINST            # preserve rSELF
+    movl   rSELF, %eax
+    movl   rPC,OUT_ARG0(%esp)
+    movl   %eax,OUT_ARG1(%esp)
+    call   dvmJitGetTraceAddr  # (pc, self)
+    movl   %eax,offThread_inJitCodeCache(rINST)   # set the inJitCodeCache flag
+    cmpl   $$0,%eax
+    jz     1f
+    call   *%eax        # TODO: decide call vs/ jmp!.  No return either way
+1:
+    movl   $$kJitTSelectRequest,%eax
+    # On entry, eax<- jitState, rPC valid
+common_selectTrace:
+/* TODO */
+    call   dvmAbort
+#if 0
+    movl   rSELF,%ecx
+    movl   %eax,offThread_jitState(%ecx)
+    movl   $$kInterpEntryInstr,offThread_entryPoint(%ecx)
+    movl   $$1,rINST
+    jmp    common_gotoBail
+#endif
+#endif
+
+
+
+/*
+ * Common code for jumbo method invocation.
+ *
+ * On entry:
+ *   eax = Method* methodToCall
+ *   rINSTw trashed, must reload
+ *   rIBASE trashed, must reload before resuming interpreter
+ */
+
+common_invokeMethodJumbo:
+.LinvokeNewJumbo:
+
+   /*
+    * prepare to copy args to "outs" area of current frame
+    */
+    movzwl      6(rPC),rINST            # rINST<- BBBB
+    movzwl      8(rPC), %ecx            # %ecx<- CCCC
+    ADVANCE_PC 2                        # adjust pc to make return similar
+    SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
+    test        rINST, rINST
+    movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BBBB
+    jz          .LinvokeArgsDone        # no args; jump to args done
+    jmp         .LinvokeRangeArgs       # handle args like invoke range
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *   eax = Method* methodToCall
+ *   rINSTw trashed, must reload
+ *   rIBASE trashed, must reload before resuming interpreter
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+   /*
+    * prepare to copy args to "outs" area of current frame
+    */
+
+    movzbl      1(rPC),rINST       # rINST<- AA
+    movzwl      4(rPC), %ecx            # %ecx<- CCCC
+    SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
+    test        rINST, rINST
+    movl        rINST, 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)
+    */
+
+.LinvokeRangeArgs:
+    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
+    * rIBASE trashed, must reload before resuming interpreter
+    */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+    movzbl      1(rPC),rINST       # rINST<- BA
+    movl        rINST, 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               # %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             # rINSTw<- A
+    lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
+    movl        (rFP, rINST, 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               # %eax<- &StackSaveArea
+    subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
+    movl        rSELF,%edx              # %edx<- pthread
+    movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
+    subl        $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+    movl        offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
+    movl        %edx, TMP_SPILL1(%ebp)  # spill self->interpStackEnd
+    shl         $$2, %ecx               # %ecx<- update offset for outsSize
+    movl        %eax, %edx              # %edx<- newSaveArea
+    sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
+    cmp         TMP_SPILL1(%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               # %ecx<- &StackSaveArea
+    movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+    movl        rSELF,%ecx              # %ecx<- pthread
+    movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+    movl        rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+
+    /* Any special actions to take? */
+    cmpw        $$0, offThread_subMode(%ecx)
+    jne         2f                     # Yes - handle them
+1:
+    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 "self" values for the new method
+    * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+    */
+    movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
+    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+    movl        %eax, offThread_method(%ecx) # self->method<- methodToCall
+    movl        %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
+    movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+    movl        $$1, offThread_debugIsMethodEntry(%ecx)
+    movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+    movl        rFP, offThread_curFrame(%ecx) # curFrame<-newFP
+    movl        offThread_curHandlerTable(%ecx),rIBASE
+    FETCH_INST
+    GOTO_NEXT                           # jump to methodToCall->insns
+
+2:
+    /*
+     * On entry, preserve all:
+     *  %eax: method
+     *  %ecx: self
+     *  %edx: new save area
+     */
+    SPILL_TMP1(%eax)                   # preserve methodToCall
+    SPILL_TMP2(%edx)                   # preserve newSaveArea
+    movl        rPC, offThread_pc(%ecx) # update interpSave.pc
+    movl        %ecx, OUT_ARG0(%esp)
+    movl        %eax, OUT_ARG1(%esp)
+    call        dvmReportInvoke        # (self, method)
+    UNSPILL_TMP1(%eax)
+    UNSPILL_TMP2(%edx)
+    movl        rSELF,%ecx             # restore rSELF
+    jmp         1b
+
+   /*
+    * Prep for the native call
+    * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
+    */
+
+.LinvokeNative:
+    movl        offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
+    movl        rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
+    movl        %edx, LOCAL2_OFFSET(%ebp)  # save newSaveArea
+    movl        LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
+    movl        rINST, offThread_curFrame(%ecx)  # curFrame<- newFP
+    cmpw        $$0, offThread_subMode(%ecx)  # Anything special going on?
+    jne         11f                     # yes - handle it
+    movl        %ecx, OUT_ARG3(%esp)    # push parameter self
+    movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
+    lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
+    movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
+    movl        rINST, OUT_ARG0(%esp)    # push parameter newFP
+    call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+7:
+    movl        LOCAL2_OFFSET(%ebp), %ecx    # %ecx<- newSaveArea
+    movl        rSELF, %eax             # %eax<- self
+    movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
+    cmp         $$0, offThread_exception(%eax) # check for exception
+    movl        rFP, offThread_curFrame(%eax) # curFrame<- rFP
+    movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
+    jne         common_exceptionThrown  # handle exception
+    movl        offThread_curHandlerTable(%eax),rIBASE
+    FETCH_INST_OPCODE 3 %ecx
+    ADVANCE_PC 3
+    GOTO_NEXT_R %ecx                    # jump to next instruction
+
+11:
+    /*
+     * Handle any special subMode actions
+     * %eax=methodToCall, rINST=newFP, %ecx=self
+     */
+    SPILL_TMP1(%eax)                    # save methodTocall
+    movl        rPC, offThread_pc(%ecx)
+    movl        %ecx, OUT_ARG0(%esp)
+    movl        %eax, OUT_ARG1(%esp)
+    movl        rFP, OUT_ARG2(%esp)
+    call        dvmReportPreNativeInvoke # (self, methodToCall, fp)
+    UNSPILL_TMP1(%eax)                  # restore methodToCall
+    movl        rSELF,%ecx              # restore self
+
+    /* Do the native call */
+    movl        %ecx, OUT_ARG3(%esp)    # push parameter self
+    lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
+    movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
+    movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
+    movl        rINST, OUT_ARG0(%esp)   # push parameter newFP
+    call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+
+    UNSPILL_TMP1(%eax)                  # restore methodToCall
+    movl        rSELF, %ecx
+    movl        %ecx, OUT_ARG0(%esp)
+    movl        %eax, OUT_ARG1(%esp)
+    movl        rFP, OUT_ARG2(%esp)
+    call        dvmReportPostNativeInvoke # (self, methodToCall, fp)
+    jmp         7b                      # rejoin
+
+.LstackOverflow:    # eax=methodToCall
+    movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
+    movl        rSELF,%eax              # %eax<- self
+    movl        %eax, OUT_ARG0(%esp)    # push parameter self
+    call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
+    jmp         common_exceptionThrown  # handle exception
+
+
+/*
+ * Common code for handling a return instruction
+ */
+common_returnFromMethod:
+    movl    rSELF,%ecx
+    SAVEAREA_FROM_FP %eax                         # eax<- saveArea (old)
+    cmpw    $$0, offThread_subMode(%ecx)          # special action needed?
+    jne     19f                                   # go if so
+14:
+    movl    offStackSaveArea_prevFrame(%eax),rFP  # rFP<- prevFrame
+    movl    (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
+    cmpl    $$0,rINST                             # break?
+    je      common_gotoBail    # break frame, bail out completely
+
+    movl    offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
+    movl    rINST,offThread_method(%ecx)       # self->method = newSave->meethod
+    movl    rFP,offThread_curFrame(%ecx)       # curFrame = fp
+    movl    offMethod_clazz(rINST),%eax        # eax<- method->clazz
+    movl    offThread_curHandlerTable(%ecx),rIBASE
+    movl    offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
+    FETCH_INST_OPCODE 3 %eax
+    movl    rINST,offThread_methodClassDex(%ecx)
+    ADVANCE_PC 3
+    GOTO_NEXT_R %eax
+
+19:
+    /*
+     * Handle special subMode actions
+     * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
+     */
+    movl     rFP, offThread_curFrame(%ecx)    # update interpSave.curFrame
+    movl     rPC, offThread_pc(%ecx)          # update interpSave.pc
+    movl     %ecx, OUT_ARG0(%esp)             # parameter self
+    call     dvmReportReturn                  # (self)
+    movl     rSELF, %ecx                      # restore self
+    SAVEAREA_FROM_FP %eax                     # restore saveArea
+    jmp      14b
+
+
+/*
+ * Prepare to strip the current frame and "longjump" back to caller of
+ * dvmMterpStdRun.
+ *
+ * on entry:
+ *    rINST holds changeInterp
+ *    ecx holds self pointer
+ *
+ * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
+ */
+common_gotoBail:
+    movl   rPC,offThread_pc(%ecx)     # export state to self
+    movl   rFP,offThread_curFrame(%ecx)
+    movl   %ecx,OUT_ARG0(%esp)      # self in arg0
+    movl   rINST,OUT_ARG1(%esp)     # changeInterp in arg1
+    call   dvmMterpStdBail          # bail out....
+
+
+/*
+ * After returning from a "selfd" function, pull out the updated values
+ * and start executing at the next instruction.
+ */
+ common_resumeAfterGlueCall:
+     movl  rSELF, %eax
+     movl  offThread_pc(%eax),rPC
+     movl  offThread_curFrame(%eax),rFP
+     movl  offThread_curHandlerTable(%eax),rIBASE
+     FETCH_INST
+     GOTO_NEXT
+
+/*
+ * Integer divide or mod by zero
+ */
+common_errDivideByZero:
+    EXPORT_PC
+    movl    $$.LstrDivideByZero,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowArithmeticException
+    jmp     common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry, len in eax
+ */
+common_errNegativeArraySize:
+    EXPORT_PC
+    movl    %eax,OUT_ARG0(%esp)                  # arg0<- len
+    call    dvmThrowNegativeArraySizeException   # (len)
+    jmp     common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ * On entry, method name in eax
+ */
+common_errNoSuchMethod:
+
+    EXPORT_PC
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowNoSuchMethodError
+    jmp     common_exceptionThrown
+
+/*
+ * Hit a null object when we weren't expecting one.  Export the PC, throw a
+ * NullPointerException and goto the exception processing code.
+ */
+common_errNullObject:
+    EXPORT_PC
+    xorl    %eax,%eax
+    movl    %eax,OUT_ARG0(%esp)
+    call    dvmThrowNullPointerException
+    jmp     common_exceptionThrown
+
+/*
+ * Array index exceeds max.
+ * On entry:
+ *    eax <- array object
+ *    ecx <- index
+ */
+common_errArrayIndex:
+    EXPORT_PC
+    movl    offArrayObject_length(%eax), %eax
+    movl    %eax,OUT_ARG0(%esp)
+    movl    %ecx,OUT_ARG1(%esp)
+    call    dvmThrowArrayIndexOutOfBoundsException   # args (length, index)
+    jmp     common_exceptionThrown
+
+/*
+ * 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.
+ *
+ * NOTE: special subMode handling done in dvmMterp_exceptionThrown
+ *
+ * This does not return.
+ */
+common_exceptionThrown:
+    movl    rSELF,%ecx
+    movl    rPC,offThread_pc(%ecx)
+    movl    rFP,offThread_curFrame(%ecx)
+    movl    %ecx,OUT_ARG0(%esp)
+    call    dvmMterp_exceptionThrown
+    jmp     common_resumeAfterGlueCall
+
+common_abort:
+    movl    $$0xdeadf00d,%eax
+    call     *%eax
+
+
+/*
+ * Strings
+ */
+
+    .section     .rodata
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrFilledNewArrayNotImplA:
+    .asciz  "filled-new-array only implemented for 'int'"
diff --git a/vm/mterp/x86/fpcvt.S b/vm/mterp/x86/fpcvt.S
new file mode 100644
index 0000000..983b9eb
--- /dev/null
+++ b/vm/mterp/x86/fpcvt.S
@@ -0,0 +1,14 @@
+%default {"instr":"","load":"","store":""}
+    /*
+     * Generic 32-bit FP conversion operation.
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx       # ecx<- A+
+    sarl     $$4,rINST         # rINST<- B
+    $load    (rFP,rINST,4)      # %st0<- vB
+    andb     $$0xf,%cl          # ecx<- A
+    $instr
+    $store  (rFP,%ecx,4)        # vA<- %st0
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/header.S b/vm/mterp/x86/header.S
new file mode 100644
index 0000000..6f3be0c
--- /dev/null
+++ b/vm/mterp/x86/header.S
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+/*
+ * 32-bit x86 definitions and declarations.
+ */
+
+/*
+386 ABI general notes:
+
+Caller save set:
+   eax, edx, ecx, st(0)-st(7)
+Callee save set:
+   ebx, esi, edi, ebp
+Return regs:
+   32-bit in eax
+   64-bit in edx:eax (low-order 32 in eax)
+   fp on top of fp stack st(0)
+
+Parameters passed on stack, pushed right-to-left.  On entry to target, first
+parm is at 4(%esp).  Traditional entry code is:
+
+functEntry:
+    push    %ebp             # save old frame pointer
+    mov     %ebp,%esp        # establish new frame pointer
+    sub     FrameSize,%esp   # Allocate storage for spill, locals & outs
+
+Once past the prologue, arguments are referenced at ((argno + 2)*4)(%ebp)
+
+Stack must be 16-byte aligned to support SSE in native code.
+
+If we're not doing variable stack allocation (alloca), the frame pointer can be
+eliminated and all arg references adjusted to be esp relative.
+
+Mterp notes:
+
+Some key interpreter variables will be assigned to registers.  Note that each
+will also have an associated spill location (mostly useful for those assigned
+to callee save registers).
+
+  nick     reg   purpose
+  rPC      edi   interpreted program counter, used for fetching instructions
+  rFP      esi   interpreted frame pointer, used for accessing locals and args
+  rINSTw   bx    first 16-bit code of current instruction
+  rINSTbl  bl    opcode portion of instruction word
+  rINSTbh  bh    high byte of inst word, usually contains src/tgt reg names
+  rIBASE   edx   base of instruction handler table
+
+Notes:
+   o High order 16 bits of ebx must be zero on entry to handler
+   o rPC, rFP, rINSTw/rINSTbl valid on handler entry and exit
+   o eax and ecx are scratch, rINSTw/ebx sometimes scratch
+
+*/
+
+#define rSELF    8(%ebp)
+#define rPC      %esi
+#define rFP      %edi
+#define rINST    %ebx
+#define rINSTw   %bx
+#define rINSTbh  %bh
+#define rINSTbl  %bl
+#define rIBASE   %edx
+
+
+/* Frame diagram while executing dvmMterpStdRun, high to low addresses */
+#define IN_ARG0        (  8)
+#define CALLER_RP      (  4)
+#define PREV_FP        (  0)
+/* Spill offsets relative to %ebp */
+#define EDI_SPILL      ( -4)
+#define ESI_SPILL      ( -8)
+#define EBX_SPILL      (-12)
+#define rPC_SPILL      (-16)
+#define rFP_SPILL      (-20)
+#define rINST_SPILL    (-24)
+#define rIBASE_SPILL   (-28)
+#define TMP_SPILL1     (-32)
+#define TMP_SPILL2     (-36)
+#define TMP_SPILL3     (-20)
+#define LOCAL0_OFFSET  (-44)
+#define LOCAL1_OFFSET  (-48)
+#define LOCAL2_OFFSET  (-52)
+/* Out Arg offsets, relative to %esp */
+#define OUT_ARG4       ( 16)
+#define OUT_ARG3       ( 12)
+#define OUT_ARG2       (  8)
+#define OUT_ARG1       (  4)
+#define OUT_ARG0       (  0)  /* <- dvmMterpStdRun esp */
+#define FRAME_SIZE     76
+
+#define SPILL(reg) movl reg##,reg##_SPILL(%ebp)
+#define UNSPILL(reg) movl reg##_SPILL(%ebp),reg
+#define SPILL_TMP1(reg) movl reg,TMP_SPILL1(%ebp)
+#define UNSPILL_TMP1(reg) movl TMP_SPILL1(%ebp),reg
+#define SPILL_TMP2(reg) movl reg,TMP_SPILL2(%ebp)
+#define UNSPILL_TMP2(reg) movl TMP_SPILL2(%ebp),reg
+#define SPILL_TMP3(reg) movl reg,TMP_SPILL3(%ebp)
+#define UNSPILL_TMP3(reg) movl TMP_SPILL3(%ebp),reg
+
+#if defined(WITH_JIT)
+.macro GET_JIT_PROF_TABLE _self _reg
+    movl    offThread_pJitProfTable(\_self),\_reg
+.endm
+.macro GET_JIT_THRESHOLD _self _reg
+    movl    offThread_jitThreshold(\_self),\_reg
+.endm
+#endif
+
+/* save/restore the PC and/or FP from the self struct */
+.macro SAVE_PC_FP_TO_SELF _reg
+    movl     rSELF,\_reg
+    movl     rPC,offThread_pc(\_reg)
+    movl     rFP,offThread_curFrame(\_reg)
+.endm
+
+.macro LOAD_PC_FP_FROM_SELF
+    movl    rSELF,rFP
+    movl    offThread_pc(rFP),rPC
+    movl    offThread_curFrame(rFP),rFP
+.endm
+
+/* The interpreter assumes a properly aligned stack on entry, and
+ * will preserve 16-byte alignment.
+ */
+
+/*
+ * "export" the PC to the interpreted stack frame, f/b/o future exception
+ * objects.  Must be done *before* something throws.
+ *
+ * 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.
+ */
+.macro EXPORT_PC
+    movl     rPC, (-sizeofStackSaveArea + offStackSaveArea_currentPc)(rFP)
+.endm
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+.macro SAVEAREA_FROM_FP _reg
+    leal    -sizeofStackSaveArea(rFP), \_reg
+.endm
+
+/*
+ * Fetch the next instruction from rPC into rINSTw.  Does not advance rPC.
+ */
+.macro FETCH_INST
+    movzwl    (rPC),rINST
+.endm
+
+/*
+ * Fetch the opcode byte and zero-extend it into _reg.  Must be used
+ * in conjunction with GOTO_NEXT_R
+ */
+.macro FETCH_INST_R _reg
+    movzbl    (rPC),\_reg
+.endm
+
+/*
+ * Fetch the opcode byte at _count words offset from rPC and zero-extend
+ * it into _reg.  Must be used in conjunction with GOTO_NEXT_R
+ */
+.macro FETCH_INST_OPCODE _count _reg
+    movzbl  \_count*2(rPC),\_reg
+.endm
+
+/*
+ * Fetch the nth instruction word from rPC into rINSTw.  Does not advance
+ * rPC, and _count is in words
+ */
+.macro FETCH_INST_WORD _count
+    movzwl  \_count*2(rPC),rINST
+.endm
+
+/*
+ * Fetch instruction word indexed (used for branching).
+ * Index is in instruction word units.
+ */
+.macro FETCH_INST_INDEXED _reg
+    movzwl  (rPC,\_reg,2),rINST
+.endm
+
+/*
+ * Advance rPC by instruction count
+ */
+.macro ADVANCE_PC _count
+    leal  2*\_count(rPC),rPC
+.endm
+
+/*
+ * Advance rPC by branch offset in register
+ */
+.macro ADVANCE_PC_INDEXED _reg
+    leal (rPC,\_reg,2),rPC
+.endm
+
+.macro GOTO_NEXT
+     movzx   rINSTbl,%eax
+     movzbl  rINSTbh,rINST
+     jmp     *(rIBASE,%eax,4)
+.endm
+
+   /*
+    * Version of GOTO_NEXT that assumes _reg preloaded with opcode.
+    * Should be paired with FETCH_INST_R
+    */
+.macro GOTO_NEXT_R _reg
+     movzbl  1(rPC),rINST
+     jmp     *(rIBASE,\_reg,4)
+.endm
+
+   /*
+    * Jumbo version of GOTO_NEXT that assumes _reg preloaded with table
+    * offset of the jumbo instruction, which is the top half of the extended
+    * opcode + 0x100.  Loads rINST with BBBB field, similar to GOTO_NEXT_R
+    */
+.macro GOTO_NEXT_JUMBO_R _reg
+     movzwl  6(rPC),rINST
+     jmp     *(rIBASE,\_reg,4)
+.endm
+
+/*
+ * Get/set the 32-bit value from a Dalvik register.
+ */
+.macro GET_VREG_R _reg _vreg
+    movl     (rFP,\_vreg,4),\_reg
+.endm
+
+.macro SET_VREG _reg _vreg
+    movl     \_reg,(rFP,\_vreg,4)
+.endm
+
+.macro GET_VREG_WORD _reg _vreg _offset
+    movl     4*(\_offset)(rFP,\_vreg,4),\_reg
+.endm
+
+.macro SET_VREG_WORD _reg _vreg _offset
+    movl     \_reg,4*(\_offset)(rFP,\_vreg,4)
+.endm
+
+#define sReg0 LOCAL0_OFFSET(%ebp)
+#define sReg1 LOCAL1_OFFSET(%ebp)
+#define sReg2 LOCAL2_OFFSET(%ebp)
+
+   /*
+    * Hard coded helper values.
+    */
+
+.balign 16
+
+.LdoubNeg:
+    .quad       0x8000000000000000
+
+.L64bits:
+    .quad       0xFFFFFFFFFFFFFFFF
+
+.LshiftMask2:
+    .quad       0x0000000000000000
+.LshiftMask:
+    .quad       0x000000000000003F
+
+.Lvalue64:
+    .quad       0x0000000000000040
+
+.LvaluePosInfLong:
+    .quad       0x7FFFFFFFFFFFFFFF
+
+.LvalueNegInfLong:
+    .quad       0x8000000000000000
+
+.LvalueNanLong:
+    .quad       0x0000000000000000
+
+.LintMin:
+.long   0x80000000
+
+.LintMax:
+.long   0x7FFFFFFF
+
+
+/*
+ * 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"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
diff --git a/vm/mterp/x86/shop2addr.S b/vm/mterp/x86/shop2addr.S
new file mode 100644
index 0000000..c891259
--- /dev/null
+++ b/vm/mterp/x86/shop2addr.S
@@ -0,0 +1,15 @@
+%default {"result":"%eax"}
+    /*
+     * Generic 32-bit "shift/2addr" operation.
+     */
+    /* shift/2addr vA, vB */
+    movzx    rINSTbl,%ecx           # eax<- BA
+    sarl     $$4,%ecx               # ecx<- B
+    GET_VREG_R %ecx %ecx            # eax<- vBB
+    andb     $$0xf,rINSTbl          # rINST<- A
+    GET_VREG_R %eax rINST           # eax<- vAA
+    $instr                          # ex: sarl %cl,%eax
+    FETCH_INST_OPCODE 1 %ecx
+    SET_VREG $result rINST
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/stub.S b/vm/mterp/x86/stub.S
new file mode 100644
index 0000000..fb5c977
--- /dev/null
+++ b/vm/mterp/x86/stub.S
@@ -0,0 +1,9 @@
+    /* (stub) */
+    SAVE_PC_FP_TO_SELF %ecx          # leaves rSELF in %ecx
+    movl %ecx,OUT_ARG0(%esp)         # self is first arg to function
+    call      dvmMterp_${opcode}     # do the real work
+    movl      rSELF,%ecx
+    LOAD_PC_FP_FROM_SELF             # retrieve updated values
+    movl      offThread_curHandlerTable(%ecx),rIBASE  # set up rIBASE
+    FETCH_INST
+    GOTO_NEXT
diff --git a/vm/mterp/x86/unop.S b/vm/mterp/x86/unop.S
new file mode 100644
index 0000000..ad9c79b
--- /dev/null
+++ b/vm/mterp/x86/unop.S
@@ -0,0 +1,17 @@
+%default {"pre0":"","pre1":""}
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op eax".
+     */
+    /* unop vA, vB */
+    movzbl   rINSTbl,%ecx           # ecx<- A+
+    sarl     $$4,rINST             # rINST<- B
+    GET_VREG_R %eax rINST           # eax<- vB
+    andb     $$0xf,%cl              # ecx<- A
+    $pre0
+    $pre1
+    $instr
+    SET_VREG %eax %ecx
+    FETCH_INST_OPCODE 1 %ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %ecx
diff --git a/vm/mterp/x86/unopWide.S b/vm/mterp/x86/unopWide.S
new file mode 100644
index 0000000..41b5d10
--- /dev/null
+++ b/vm/mterp/x86/unopWide.S
@@ -0,0 +1,21 @@
+%default {"instr1":"","instr2":"","instr3":""}
+    /*
+     * Generic 64-bit unary operation.
+     * Operand in %ecx:%eax
+     *
+     * For: neg-long, not-long
+     */
+    /* unop vA, vB */
+    movzbl    rINSTbl,%ecx            # ecx<- BA
+    sarl      $$4,%ecx                # ecx<- B
+    andb      $$0xf,rINSTbl           # rINST<- A
+    GET_VREG_WORD %eax %ecx 0         # eax<- v[B+0]
+    GET_VREG_WORD %ecx %ecx 1         # ecx<- v[B+1]
+    $instr1   # ex: negl %eax
+    $instr2   # ex: adcl $$0,%ecx
+    $instr3   # ex: negl %ecx
+    SET_VREG_WORD %eax rINST 0        # v[A+0] <- eax
+    GET_INST_OPCODE 1 %eax
+    SET_VREG_WORD %ecx rINST 1        # v[A+1] <- ecx
+    ADVANCE_PC 1
+    GOTO_NEXT_R %eax
diff --git a/vm/mterp/x86/unused.S b/vm/mterp/x86/unused.S
new file mode 100644
index 0000000..f0f117c
--- /dev/null
+++ b/vm/mterp/x86/unused.S
@@ -0,0 +1 @@
+    jmp     common_abort
diff --git a/vm/mterp/x86/zcmp.S b/vm/mterp/x86/zcmp.S
new file mode 100644
index 0000000..cbda889
--- /dev/null
+++ b/vm/mterp/x86/zcmp.S
@@ -0,0 +1,20 @@
+%verify "branch taken"
+%verify "branch not taken"
+    /*
+     * 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 */
+    cmpl     $$0,(rFP,rINST,4)     # compare (vA, 0)
+    movl     $$2,%eax              # assume branch not taken
+    j${revcmp}   1f
+    movl     rSELF,%ecx
+    movswl   2(rPC),%eax           # fetch signed displacement
+    movl     offThread_curHandlerTable(%ecx),rIBASE
+1:
+    FETCH_INST_INDEXED %eax
+    ADVANCE_PC_INDEXED %eax
+    GOTO_NEXT
diff --git a/vm/native/InternalNative.cpp b/vm/native/InternalNative.cpp
new file mode 100644
index 0000000..e3c8975
--- /dev/null
+++ b/vm/native/InternalNative.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+/*
+ * Internal-native initialization and some common utility functions.
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+/*
+ * Set of classes for which we provide methods.
+ *
+ * The last field, classNameHash, is filled in at startup.
+ */
+static DalvikNativeClass gDvmNativeMethodSet[] = {
+    { "Ljava/lang/Object;",               dvm_java_lang_Object, 0 },
+    { "Ljava/lang/Class;",                dvm_java_lang_Class, 0 },
+    { "Ljava/lang/Double;",               dvm_java_lang_Double, 0 },
+    { "Ljava/lang/Float;",                dvm_java_lang_Float, 0 },
+    { "Ljava/lang/Math;",                 dvm_java_lang_Math, 0 },
+    { "Ljava/lang/Runtime;",              dvm_java_lang_Runtime, 0 },
+    { "Ljava/lang/String;",               dvm_java_lang_String, 0 },
+    { "Ljava/lang/System;",               dvm_java_lang_System, 0 },
+    { "Ljava/lang/Throwable;",            dvm_java_lang_Throwable, 0 },
+    { "Ljava/lang/VMClassLoader;",        dvm_java_lang_VMClassLoader, 0 },
+    { "Ljava/lang/VMThread;",             dvm_java_lang_VMThread, 0 },
+    { "Ljava/lang/reflect/AccessibleObject;",
+            dvm_java_lang_reflect_AccessibleObject, 0 },
+    { "Ljava/lang/reflect/Array;",        dvm_java_lang_reflect_Array, 0 },
+    { "Ljava/lang/reflect/Constructor;",
+            dvm_java_lang_reflect_Constructor, 0 },
+    { "Ljava/lang/reflect/Field;",        dvm_java_lang_reflect_Field, 0 },
+    { "Ljava/lang/reflect/Method;",       dvm_java_lang_reflect_Method, 0 },
+    { "Ljava/lang/reflect/Proxy;",        dvm_java_lang_reflect_Proxy, 0 },
+    { "Ljava/util/concurrent/atomic/AtomicLong;",
+            dvm_java_util_concurrent_atomic_AtomicLong, 0 },
+    { "Ldalvik/bytecode/OpcodeInfo;",     dvm_dalvik_bytecode_OpcodeInfo, 0 },
+    { "Ldalvik/system/VMDebug;",          dvm_dalvik_system_VMDebug, 0 },
+    { "Ldalvik/system/DexFile;",          dvm_dalvik_system_DexFile, 0 },
+    { "Ldalvik/system/VMRuntime;",        dvm_dalvik_system_VMRuntime, 0 },
+    { "Ldalvik/system/Zygote;",           dvm_dalvik_system_Zygote, 0 },
+    { "Ldalvik/system/VMStack;",          dvm_dalvik_system_VMStack, 0 },
+    { "Lorg/apache/harmony/dalvik/ddmc/DdmServer;",
+            dvm_org_apache_harmony_dalvik_ddmc_DdmServer, 0 },
+    { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;",
+            dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal, 0 },
+    { "Lorg/apache/harmony/dalvik/NativeTestTarget;",
+            dvm_org_apache_harmony_dalvik_NativeTestTarget, 0 },
+    { "Lsun/misc/Unsafe;",                dvm_sun_misc_Unsafe, 0 },
+    { NULL, NULL, 0 },
+};
+
+
+/*
+ * Set up hash values on the class names.
+ */
+bool dvmInternalNativeStartup()
+{
+    DalvikNativeClass* classPtr = gDvmNativeMethodSet;
+
+    while (classPtr->classDescriptor != NULL) {
+        classPtr->classDescriptorHash =
+            dvmComputeUtf8Hash(classPtr->classDescriptor);
+        classPtr++;
+    }
+
+    gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar);
+    if (gDvm.userDexFiles == NULL)
+        return false;
+
+    return true;
+}
+
+/*
+ * Clean up.
+ */
+void dvmInternalNativeShutdown()
+{
+    dvmHashTableFree(gDvm.userDexFiles);
+}
+
+/*
+ * Search the internal native set for a match.
+ */
+DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method)
+{
+    const char* classDescriptor = method->clazz->descriptor;
+    const DalvikNativeClass* pClass;
+    u4 hash;
+
+    hash = dvmComputeUtf8Hash(classDescriptor);
+    pClass = gDvmNativeMethodSet;
+    while (true) {
+        if (pClass->classDescriptor == NULL)
+            break;
+        if (pClass->classDescriptorHash == hash &&
+            strcmp(pClass->classDescriptor, classDescriptor) == 0)
+        {
+            const DalvikNativeMethod* pMeth = pClass->methodInfo;
+            while (true) {
+                if (pMeth->name == NULL)
+                    break;
+
+                if (dvmCompareNameDescriptorAndMethod(pMeth->name,
+                    pMeth->signature, method) == 0)
+                {
+                    /* match */
+                    //LOGV("+++  match on %s.%s %s at %p",
+                    //    className, methodName, methodSignature, pMeth->fnPtr);
+                    return pMeth->fnPtr;
+                }
+
+                pMeth++;
+            }
+        }
+
+        pClass++;
+    }
+
+    return NULL;
+}
+
+
+/*
+ * Magic "internal native" code stub, inserted into abstract method
+ * definitions when a class is first loaded.  This throws the expected
+ * exception so we don't have to explicitly check for it in the interpreter.
+ */
+void dvmAbstractMethodStub(const u4* args, JValue* pResult)
+{
+    LOGD("--- called into dvmAbstractMethodStub");
+    dvmThrowAbstractMethodError("abstract method not implemented");
+}
+
+
+/*
+ * Verify that "obj" is non-null and is an instance of "clazz".
+ * Used to implement reflection on fields and methods.
+ *
+ * Returns "false" and throws an exception if not.
+ */
+bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz) {
+    ClassObject* exceptionClass = NULL;
+    if (obj == NULL) {
+        exceptionClass = gDvm.exNullPointerException;
+    } else if (!dvmInstanceof(obj->clazz, clazz)) {
+        exceptionClass = gDvm.exIllegalArgumentException;
+    }
+
+    if (exceptionClass == NULL) {
+        return true;
+    }
+
+    std::string expectedClassName(dvmHumanReadableDescriptor(clazz->descriptor));
+    std::string actualClassName(dvmHumanReadableType(obj));
+    dvmThrowExceptionFmt(exceptionClass, "expected receiver of type %s, but got %s",
+            expectedClassName.c_str(), actualClassName.c_str());
+    return false;
+}
+
+/*
+ * Find a class by name, initializing it if requested.
+ */
+ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader,
+    bool doInit)
+{
+    ClassObject* clazz = NULL;
+    char* name = NULL;
+    char* descriptor = NULL;
+
+    if (nameObj == NULL) {
+        dvmThrowNullPointerException("name == null");
+        goto bail;
+    }
+    name = dvmCreateCstrFromString(nameObj);
+
+    /*
+     * We need to validate and convert the name (from x.y.z to x/y/z).  This
+     * is especially handy for array types, since we want to avoid
+     * auto-generating bogus array classes.
+     */
+    if (!dexIsValidClassName(name, true)) {
+        LOGW("dvmFindClassByName rejecting '%s'", name);
+        dvmThrowClassNotFoundException(name);
+        goto bail;
+    }
+
+    descriptor = dvmDotToDescriptor(name);
+    if (descriptor == NULL) {
+        goto bail;
+    }
+
+    if (doInit)
+        clazz = dvmFindClass(descriptor, loader);
+    else
+        clazz = dvmFindClassNoInit(descriptor, loader);
+
+    if (clazz == NULL) {
+        LOGVV("FAIL: load %s (%d)", descriptor, doInit);
+        Thread* self = dvmThreadSelf();
+        Object* oldExcep = dvmGetException(self);
+        dvmAddTrackedAlloc(oldExcep, self);     /* don't let this be GCed */
+        dvmClearException(self);
+        dvmThrowChainedClassNotFoundException(name, oldExcep);
+        dvmReleaseTrackedAlloc(oldExcep, self);
+    } else {
+        LOGVV("GOOD: load %s (%d) --> %p ldr=%p",
+            descriptor, doInit, clazz, clazz->classLoader);
+    }
+
+bail:
+    free(name);
+    free(descriptor);
+    return clazz;
+}
+
+/*
+ * We insert native method stubs for abstract methods so we don't have to
+ * check the access flags at the time of the method call.  This results in
+ * "native abstract" methods, which can't exist.  If we see the "abstract"
+ * flag set, clear the "native" flag.
+ *
+ * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
+ * position, because the callers of this function are trying to convey
+ * the "traditional" meaning of the flags to their callers.
+ */
+u4 dvmFixMethodFlags(u4 flags)
+{
+    if ((flags & ACC_ABSTRACT) != 0) {
+        flags &= ~ACC_NATIVE;
+    }
+
+    flags &= ~ACC_SYNCHRONIZED;
+
+    if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
+        flags |= ACC_SYNCHRONIZED;
+    }
+
+    return flags & JAVA_FLAGS_MASK;
+}
diff --git a/vm/native/InternalNative.h b/vm/native/InternalNative.h
new file mode 100644
index 0000000..006fc1e
--- /dev/null
+++ b/vm/native/InternalNative.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef DALVIK_NATIVE_INTERNALNATIVE_H_
+#define DALVIK_NATIVE_INTERNALNATIVE_H_
+
+/*
+ * Some setup for internal native functions.
+ */
+bool dvmInternalNativeStartup(void);
+void dvmInternalNativeShutdown(void);
+
+/* search the internal native set for a match */
+DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method);
+
+/* exception-throwing stub for abstract methods (DalvikNativeFunc) */
+extern "C" void dvmAbstractMethodStub(const u4* args, JValue* pResult);
+
+#endif  // DALVIK_NATIVE_INTERNALNATIVE_H_
diff --git a/vm/native/InternalNativePriv.h b/vm/native/InternalNativePriv.h
new file mode 100644
index 0000000..0925a61
--- /dev/null
+++ b/vm/native/InternalNativePriv.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+/*
+ * Declarations and definitions common to internal native code.
+ */
+#ifndef DALVIK_NATIVE_INTERNALNATIVEPRIV_H_
+#define DALVIK_NATIVE_INTERNALNATIVEPRIV_H_
+
+/*
+ * Return macros.  Note we use "->i" instead of "->z" for boolean; this
+ * is because the interpreter expects everything to be a 32-bit value.
+ */
+#ifdef NDEBUG
+# define RETURN_VOID()           do { (void)(pResult); return; } while(0)
+#else
+# define RETURN_VOID()           do { pResult->i = 0xfefeabab; return; }while(0)
+#endif
+#define RETURN_BOOLEAN(_val)    do { pResult->i = (_val); return; } while(0)
+#define RETURN_INT(_val)        do { pResult->i = (_val); return; } while(0)
+#define RETURN_LONG(_val)       do { pResult->j = (_val); return; } while(0)
+#define RETURN_FLOAT(_val)      do { pResult->f = (_val); return; } while(0)
+#define RETURN_DOUBLE(_val)     do { pResult->d = (_val); return; } while(0)
+#define RETURN_PTR(_val)        do { pResult->l = (Object*)(_val); return; } while(0)
+
+/*
+ * Normally a method that has an "inline native" will be invoked using
+ * execute-inline. If the method is invoked via reflection, JNI, or by
+ * virtual dispatch (in the case of String.equals, which we may arrive
+ * at via Object.equals), we need a non-"inline native" implementation.
+ *
+ * This macro is used to implement the native methods that bridge this gap.
+ */
+#define MAKE_INTRINSIC_TRAMPOLINE(INTRINSIC_FN) \
+    extern bool INTRINSIC_FN(u4 arg0, u4 arg1, u4 arg2, u4 arg3, \
+            JValue* pResult); \
+    INTRINSIC_FN(args[0], args[1], args[2], args[3], pResult);
+
+/*
+ * Verify that "obj" is non-null and is an instance of "clazz".
+ *
+ * Returns "false" and throws an exception if not.
+ */
+bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz);
+
+/*
+ * Find a class by name, initializing it if requested.
+ */
+ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader,
+    bool doInit);
+
+/*
+ * We insert native method stubs for abstract methods so we don't have to
+ * check the access flags at the time of the method call.  This results in
+ * "native abstract" methods, which can't exist.  If we see the "abstract"
+ * flag set, clear the "native" flag.
+ *
+ * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
+ * position, because the callers of this function are trying to convey
+ * the "traditional" meaning of the flags to their callers.
+ */
+u4 dvmFixMethodFlags(u4 flags);
+
+/*
+ * dvmHashTableFree callback for some DexFile operations.
+ */
+void dvmFreeDexOrJar(void* vptr);
+
+/*
+ * Tables of methods.
+ */
+extern const DalvikNativeMethod dvm_java_lang_Object[];
+extern const DalvikNativeMethod dvm_java_lang_Class[];
+extern const DalvikNativeMethod dvm_java_lang_Double[];
+extern const DalvikNativeMethod dvm_java_lang_Float[];
+extern const DalvikNativeMethod dvm_java_lang_Math[];
+extern const DalvikNativeMethod dvm_java_lang_Runtime[];
+extern const DalvikNativeMethod dvm_java_lang_String[];
+extern const DalvikNativeMethod dvm_java_lang_System[];
+extern const DalvikNativeMethod dvm_java_lang_Throwable[];
+extern const DalvikNativeMethod dvm_java_lang_VMClassLoader[];
+extern const DalvikNativeMethod dvm_java_lang_VMThread[];
+extern const DalvikNativeMethod dvm_java_lang_reflect_AccessibleObject[];
+extern const DalvikNativeMethod dvm_java_lang_reflect_Array[];
+extern const DalvikNativeMethod dvm_java_lang_reflect_Constructor[];
+extern const DalvikNativeMethod dvm_java_lang_reflect_Field[];
+extern const DalvikNativeMethod dvm_java_lang_reflect_Method[];
+extern const DalvikNativeMethod dvm_java_lang_reflect_Proxy[];
+extern const DalvikNativeMethod dvm_java_util_concurrent_atomic_AtomicLong[];
+extern const DalvikNativeMethod dvm_dalvik_bytecode_OpcodeInfo[];
+extern const DalvikNativeMethod dvm_dalvik_system_SamplingProfiler[];
+extern const DalvikNativeMethod dvm_dalvik_system_VMDebug[];
+extern const DalvikNativeMethod dvm_dalvik_system_DexFile[];
+extern const DalvikNativeMethod dvm_dalvik_system_VMRuntime[];
+extern const DalvikNativeMethod dvm_dalvik_system_Zygote[];
+extern const DalvikNativeMethod dvm_dalvik_system_VMStack[];
+extern const DalvikNativeMethod dvm_org_apache_harmony_dalvik_ddmc_DdmServer[];
+extern const DalvikNativeMethod dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal[];
+extern const DalvikNativeMethod dvm_org_apache_harmony_dalvik_NativeTestTarget[];
+extern const DalvikNativeMethod dvm_sun_misc_Unsafe[];
+
+#endif  // DALVIK_NATIVE_INTERNALNATIVEPRIV_H_
diff --git a/vm/native/README.txt b/vm/native/README.txt
new file mode 100644
index 0000000..bc8912f
--- /dev/null
+++ b/vm/native/README.txt
@@ -0,0 +1,23 @@
+Internal native functions.
+
+All of the functions defined here make direct use of VM functions or data
+structures, so they can't be written with JNI and shouldn't really be in
+a separate shared library.  Do not add additional functions here unless
+they need to access VM internals directly.
+
+All functions here either complete quickly or are used to enter a wait
+state, so we don't set the thread status to THREAD_NATIVE when executing
+these methods.  This means that the GC will wait for these functions
+to finish.  DO NOT perform long operations or blocking I/O in here.
+These methods should not be declared "synchronized", because we don't
+check for that flag when issuing the call.
+
+We use "late" binding on these, rather than explicit registration,
+because it's easier to handle the core system classes that way.
+
+The functions here use the DalvikNativeFunc prototype, but we can
+also treat them as DalvikBridgeFunc, which takes two extra arguments.
+The former represents the API that we're most likely to expose should
+JNI performance be deemed insufficient.  The Bridge version is used as
+an optimization for a few high-volume Object calls, and should generally
+not be used as we may drop support for it at some point.
diff --git a/vm/native/dalvik_bytecode_OpcodeInfo.cpp b/vm/native/dalvik_bytecode_OpcodeInfo.cpp
new file mode 100644
index 0000000..3861fef
--- /dev/null
+++ b/vm/native/dalvik_bytecode_OpcodeInfo.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * dalvik.bytecode.OpcodeInfo
+ *
+ * This file mostly exists in its current form so that we don't have
+ * to have duplicate definitions for things both in libcore and in
+ * libdex.
+ */
+
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+/*
+ * public static native boolean isInvoke(int opcode);
+ */
+static void Dalvik_dalvik_bytecode_OpcodeInfo_isInvoke(const u4* args,
+    JValue* pResult)
+{
+    Opcode opcode = static_cast<Opcode>(args[0]);
+    int flags = dexGetFlagsFromOpcode(opcode);
+    bool result = (flags & kInstrInvoke) != 0;
+    RETURN_BOOLEAN(result);
+}
+
+const DalvikNativeMethod dvm_dalvik_bytecode_OpcodeInfo[] = {
+    { "isInvoke", "(I)Z", Dalvik_dalvik_bytecode_OpcodeInfo_isInvoke },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/dalvik_system_DexFile.cpp b/vm/native/dalvik_system_DexFile.cpp
new file mode 100644
index 0000000..f611410
--- /dev/null
+++ b/vm/native/dalvik_system_DexFile.cpp
@@ -0,0 +1,532 @@
+/*
+ * 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.
+ */
+
+/*
+ * dalvik.system.DexFile
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+/*
+ * Return true if the given name ends with ".dex".
+ */
+static bool hasDexExtension(const char* name) {
+    size_t len = strlen(name);
+
+    return (len >= 5)
+        && (name[len - 5] != '/')
+        && (strcmp(&name[len - 4], ".dex") == 0);
+}
+
+/*
+ * Internal struct for managing DexFile.
+ */
+struct DexOrJar {
+    char*       fileName;
+    bool        isDex;
+    bool        okayToFree;
+    RawDexFile* pRawDexFile;
+    JarFile*    pJarFile;
+    u1*         pDexMemory; // malloc()ed memory, if any
+};
+
+/*
+ * (This is a dvmHashTableFree callback.)
+ */
+void dvmFreeDexOrJar(void* vptr)
+{
+    DexOrJar* pDexOrJar = (DexOrJar*) vptr;
+
+    LOGV("Freeing DexOrJar '%s'", pDexOrJar->fileName);
+
+    if (pDexOrJar->isDex)
+        dvmRawDexFileFree(pDexOrJar->pRawDexFile);
+    else
+        dvmJarFileFree(pDexOrJar->pJarFile);
+    free(pDexOrJar->fileName);
+    free(pDexOrJar->pDexMemory);
+    free(pDexOrJar);
+}
+
+/*
+ * (This is a dvmHashTableLookup compare func.)
+ *
+ * Args are DexOrJar*.
+ */
+static int hashcmpDexOrJar(const void* tableVal, const void* newVal)
+{
+    return (int) newVal - (int) tableVal;
+}
+
+/*
+ * Verify that the "cookie" is a DEX file we opened.
+ *
+ * Expects that the hash table will be *unlocked* here.
+ *
+ * If the cookie is invalid, we throw an exception and return "false".
+ */
+static bool validateCookie(int cookie)
+{
+    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
+
+    LOGVV("+++ dex verifying cookie %p", pDexOrJar);
+
+    if (pDexOrJar == NULL)
+        return false;
+
+    u4 hash = cookie;
+    dvmHashTableLock(gDvm.userDexFiles);
+    void* result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
+                hashcmpDexOrJar, false);
+    dvmHashTableUnlock(gDvm.userDexFiles);
+    if (result == NULL) {
+        dvmThrowRuntimeException("invalid DexFile cookie");
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Add given DexOrJar to the hash table of user-loaded dex files.
+ */
+static void addToDexFileTable(DexOrJar* pDexOrJar) {
+    /*
+     * Later on, we will receive this pointer as an argument and need
+     * to find it in the hash table without knowing if it's valid or
+     * not, which means we can't compute a hash value from anything
+     * inside DexOrJar. We don't share DexOrJar structs when the same
+     * file is opened multiple times, so we can just use the low 32
+     * bits of the pointer as the hash.
+     */
+    u4 hash = (u4) pDexOrJar;
+    void* result;
+
+    dvmHashTableLock(gDvm.userDexFiles);
+    result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
+            hashcmpDexOrJar, true);
+    dvmHashTableUnlock(gDvm.userDexFiles);
+
+    if (result != pDexOrJar) {
+        LOGE("Pointer has already been added?");
+        dvmAbort();
+    }
+
+    pDexOrJar->okayToFree = true;
+}
+
+/*
+ * private static int openDexFile(String sourceName, String outputName,
+ *     int flags) throws IOException
+ *
+ * Open a DEX file, returning a pointer to our internal data structure.
+ *
+ * "sourceName" should point to the "source" jar or DEX file.
+ *
+ * If "outputName" is NULL, the DEX code will automatically find the
+ * "optimized" version in the cache directory, creating it if necessary.
+ * If it's non-NULL, the specified file will be used instead.
+ *
+ * TODO: at present we will happily open the same file more than once.
+ * To optimize this away we could search for existing entries in the hash
+ * table and refCount them.  Requires atomic ops or adding "synchronized"
+ * to the non-native code that calls here.
+ *
+ * TODO: should be using "long" for a pointer.
+ */
+static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
+    JValue* pResult)
+{
+    StringObject* sourceNameObj = (StringObject*) args[0];
+    StringObject* outputNameObj = (StringObject*) args[1];
+    DexOrJar* pDexOrJar = NULL;
+    JarFile* pJarFile;
+    RawDexFile* pRawDexFile;
+    char* sourceName;
+    char* outputName;
+
+    if (sourceNameObj == NULL) {
+        dvmThrowNullPointerException("sourceName == null");
+        RETURN_VOID();
+    }
+
+    sourceName = dvmCreateCstrFromString(sourceNameObj);
+    if (outputNameObj != NULL)
+        outputName = dvmCreateCstrFromString(outputNameObj);
+    else
+        outputName = NULL;
+
+    /*
+     * We have to deal with the possibility that somebody might try to
+     * open one of our bootstrap class DEX files.  The set of dependencies
+     * will be different, and hence the results of optimization might be
+     * different, which means we'd actually need to have two versions of
+     * the optimized DEX: one that only knows about part of the boot class
+     * path, and one that knows about everything in it.  The latter might
+     * optimize field/method accesses based on a class that appeared later
+     * in the class path.
+     *
+     * We can't let the user-defined class loader open it and start using
+     * the classes, since the optimized form of the code skips some of
+     * the method and field resolution that we would ordinarily do, and
+     * we'd have the wrong semantics.
+     *
+     * We have to reject attempts to manually open a DEX file from the boot
+     * class path.  The easiest way to do this is by filename, which works
+     * out because variations in name (e.g. "/system/framework/./ext.jar")
+     * result in us hitting a different dalvik-cache entry.  It's also fine
+     * if the caller specifies their own output file.
+     */
+    if (dvmClassPathContains(gDvm.bootClassPath, sourceName)) {
+        LOGW("Refusing to reopen boot DEX '%s'", sourceName);
+        dvmThrowIOException(
+            "Re-opening BOOTCLASSPATH DEX files is not allowed");
+        free(sourceName);
+        free(outputName);
+        RETURN_VOID();
+    }
+
+    /*
+     * Try to open it directly as a DEX if the name ends with ".dex".
+     * If that fails (or isn't tried in the first place), try it as a
+     * Zip with a "classes.dex" inside.
+     */
+    if (hasDexExtension(sourceName)
+            && dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
+        LOGV("Opening DEX file '%s' (DEX)", sourceName);
+
+        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
+        pDexOrJar->isDex = true;
+        pDexOrJar->pRawDexFile = pRawDexFile;
+        pDexOrJar->pDexMemory = NULL;
+    } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
+        LOGV("Opening DEX file '%s' (Jar)", sourceName);
+
+        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
+        pDexOrJar->isDex = false;
+        pDexOrJar->pJarFile = pJarFile;
+        pDexOrJar->pDexMemory = NULL;
+    } else {
+        LOGV("Unable to open DEX file '%s'", sourceName);
+        dvmThrowIOException("unable to open DEX file");
+    }
+
+    if (pDexOrJar != NULL) {
+        pDexOrJar->fileName = sourceName;
+        addToDexFileTable(pDexOrJar);
+    } else {
+        free(sourceName);
+    }
+
+    RETURN_PTR(pDexOrJar);
+}
+
+/*
+ * private static int openDexFile(byte[] fileContents) throws IOException
+ *
+ * Open a DEX file represented in a byte[], returning a pointer to our
+ * internal data structure.
+ *
+ * The system will only perform "essential" optimizations on the given file.
+ *
+ * TODO: should be using "long" for a pointer.
+ */
+static void Dalvik_dalvik_system_DexFile_openDexFile_bytearray(const u4* args,
+    JValue* pResult)
+{
+    ArrayObject* fileContentsObj = (ArrayObject*) args[0];
+    u4 length;
+    u1* pBytes;
+    RawDexFile* pRawDexFile;
+    DexOrJar* pDexOrJar = NULL;
+
+    if (fileContentsObj == NULL) {
+        dvmThrowNullPointerException("fileContents == null");
+        RETURN_VOID();
+    }
+
+    /* TODO: Avoid making a copy of the array. (note array *is* modified) */
+    length = fileContentsObj->length;
+    pBytes = (u1*) malloc(length);
+
+    if (pBytes == NULL) {
+        dvmThrowRuntimeException("unable to allocate DEX memory");
+        RETURN_VOID();
+    }
+
+    memcpy(pBytes, fileContentsObj->contents, length);
+
+    if (dvmRawDexFileOpenArray(pBytes, length, &pRawDexFile) != 0) {
+        LOGV("Unable to open in-memory DEX file");
+        free(pBytes);
+        dvmThrowRuntimeException("unable to open in-memory DEX file");
+        RETURN_VOID();
+    }
+
+    LOGV("Opening in-memory DEX");
+    pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
+    pDexOrJar->isDex = true;
+    pDexOrJar->pRawDexFile = pRawDexFile;
+    pDexOrJar->pDexMemory = pBytes;
+    pDexOrJar->fileName = strdup("<memory>"); // Needs to be free()able.
+    addToDexFileTable(pDexOrJar);
+
+    RETURN_PTR(pDexOrJar);
+}
+
+/*
+ * private static void closeDexFile(int cookie)
+ *
+ * Release resources associated with a user-loaded DEX file.
+ */
+static void Dalvik_dalvik_system_DexFile_closeDexFile(const u4* args,
+    JValue* pResult)
+{
+    int cookie = args[0];
+    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
+
+    if (pDexOrJar == NULL)
+        RETURN_VOID();
+    if (!validateCookie(cookie))
+        RETURN_VOID();
+
+    LOGV("Closing DEX file %p (%s)", pDexOrJar, pDexOrJar->fileName);
+
+    /*
+     * We can't just free arbitrary DEX files because they have bits and
+     * pieces of loaded classes.  The only exception to this rule is if
+     * they were never used to load classes.
+     *
+     * If we can't free them here, dvmInternalNativeShutdown() will free
+     * them when the VM shuts down.
+     */
+    if (pDexOrJar->okayToFree) {
+        u4 hash = (u4) pDexOrJar;
+        dvmHashTableLock(gDvm.userDexFiles);
+        if (!dvmHashTableRemove(gDvm.userDexFiles, hash, pDexOrJar)) {
+            LOGW("WARNING: could not remove '%s' from DEX hash table",
+                pDexOrJar->fileName);
+        }
+        dvmHashTableUnlock(gDvm.userDexFiles);
+        LOGV("+++ freeing DexFile '%s' resources", pDexOrJar->fileName);
+        dvmFreeDexOrJar(pDexOrJar);
+    } else {
+        LOGV("+++ NOT freeing DexFile '%s' resources", pDexOrJar->fileName);
+    }
+
+    RETURN_VOID();
+}
+
+/*
+ * private static Class defineClass(String name, ClassLoader loader,
+ *      int cookie)
+ *
+ * Load a class from a DEX file.  This is roughly equivalent to defineClass()
+ * in a regular VM -- it's invoked by the class loader to cause the
+ * creation of a specific class.  The difference is that the search for and
+ * reading of the bytes is done within the VM.
+ *
+ * The class name is a "binary name", e.g. "java.lang.String".
+ *
+ * Returns a null pointer with no exception if the class was not found.
+ * Throws an exception on other failures.
+ */
+static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args,
+    JValue* pResult)
+{
+    StringObject* nameObj = (StringObject*) args[0];
+    Object* loader = (Object*) args[1];
+    int cookie = args[2];
+    ClassObject* clazz = NULL;
+    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
+    DvmDex* pDvmDex;
+    char* name;
+    char* descriptor;
+
+    name = dvmCreateCstrFromString(nameObj);
+    descriptor = dvmDotToDescriptor(name);
+    LOGV("--- Explicit class load '%s' l=%p c=0x%08x",
+        descriptor, loader, cookie);
+    free(name);
+
+    if (!validateCookie(cookie))
+        RETURN_VOID();
+
+    if (pDexOrJar->isDex)
+        pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
+    else
+        pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);
+
+    /* once we load something, we can't unmap the storage */
+    pDexOrJar->okayToFree = false;
+
+    clazz = dvmDefineClass(pDvmDex, descriptor, loader);
+    Thread* self = dvmThreadSelf();
+    if (dvmCheckException(self)) {
+        /*
+         * If we threw a "class not found" exception, stifle it, since the
+         * contract in the higher method says we simply return null if
+         * the class is not found.
+         */
+        Object* excep = dvmGetException(self);
+        if (strcmp(excep->clazz->descriptor,
+                   "Ljava/lang/ClassNotFoundException;") == 0 ||
+            strcmp(excep->clazz->descriptor,
+                   "Ljava/lang/NoClassDefFoundError;") == 0)
+        {
+            dvmClearException(self);
+        }
+        clazz = NULL;
+    }
+
+    free(descriptor);
+    RETURN_PTR(clazz);
+}
+
+/*
+ * private static String[] getClassNameList(int cookie)
+ *
+ * Returns a String array that holds the names of all classes in the
+ * specified DEX file.
+ */
+static void Dalvik_dalvik_system_DexFile_getClassNameList(const u4* args,
+    JValue* pResult)
+{
+    int cookie = args[0];
+    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
+    Thread* self = dvmThreadSelf();
+
+    if (!validateCookie(cookie))
+        RETURN_VOID();
+
+    DvmDex* pDvmDex;
+    if (pDexOrJar->isDex)
+        pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
+    else
+        pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);
+    assert(pDvmDex != NULL);
+    DexFile* pDexFile = pDvmDex->pDexFile;
+
+    int count = pDexFile->pHeader->classDefsSize;
+    ClassObject* arrayClass =
+        dvmFindArrayClassForElement(gDvm.classJavaLangString);
+    ArrayObject* stringArray =
+        dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
+    if (stringArray == NULL) {
+        /* probably OOM */
+        LOGD("Failed allocating array of %d strings", count);
+        assert(dvmCheckException(self));
+        RETURN_VOID();
+    }
+
+    int i;
+    for (i = 0; i < count; i++) {
+        const DexClassDef* pClassDef = dexGetClassDef(pDexFile, i);
+        const char* descriptor =
+            dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+        char* className = dvmDescriptorToDot(descriptor);
+        StringObject* str = dvmCreateStringFromCstr(className);
+        dvmSetObjectArrayElement(stringArray, i, (Object *)str);
+        dvmReleaseTrackedAlloc((Object *)str, self);
+        free(className);
+    }
+
+    dvmReleaseTrackedAlloc((Object*)stringArray, self);
+    RETURN_PTR(stringArray);
+}
+
+/*
+ * public static boolean isDexOptNeeded(String fileName)
+ *         throws FileNotFoundException, IOException
+ *
+ * Returns true if the VM believes that the apk/jar file is out of date
+ * and should be passed through "dexopt" again.
+ *
+ * @param fileName the absolute path to the apk/jar file to examine.
+ * @return true if dexopt should be called on the file, false otherwise.
+ * @throws java.io.FileNotFoundException if fileName is not readable,
+ *         not a file, or not present.
+ * @throws java.io.IOException if fileName is not a valid apk/jar file or
+ *         if problems occur while parsing it.
+ * @throws java.lang.NullPointerException if fileName is null.
+ * @throws dalvik.system.StaleDexCacheError if the optimized dex file
+ *         is stale but exists on a read-only partition.
+ */
+static void Dalvik_dalvik_system_DexFile_isDexOptNeeded(const u4* args,
+    JValue* pResult)
+{
+    StringObject* nameObj = (StringObject*) args[0];
+    char* name;
+    DexCacheStatus status;
+    int result;
+
+    name = dvmCreateCstrFromString(nameObj);
+    if (name == NULL) {
+        dvmThrowNullPointerException("fileName == null");
+        RETURN_VOID();
+    }
+    if (access(name, R_OK) != 0) {
+        dvmThrowFileNotFoundException(name);
+        free(name);
+        RETURN_VOID();
+    }
+    status = dvmDexCacheStatus(name);
+    LOGV("dvmDexCacheStatus(%s) returned %d", name, status);
+
+    result = true;
+    switch (status) {
+    default: //FALLTHROUGH
+    case DEX_CACHE_BAD_ARCHIVE:
+        dvmThrowIOException(name);
+        result = -1;
+        break;
+    case DEX_CACHE_OK:
+        result = false;
+        break;
+    case DEX_CACHE_STALE:
+        result = true;
+        break;
+    case DEX_CACHE_STALE_ODEX:
+        dvmThrowStaleDexCacheError(name);
+        result = -1;
+        break;
+    }
+    free(name);
+
+    if (result >= 0) {
+        RETURN_BOOLEAN(result);
+    } else {
+        RETURN_VOID();
+    }
+}
+
+const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {
+    { "openDexFile",        "(Ljava/lang/String;Ljava/lang/String;I)I",
+        Dalvik_dalvik_system_DexFile_openDexFile },
+    { "openDexFile",        "([B)I",
+        Dalvik_dalvik_system_DexFile_openDexFile_bytearray },
+    { "closeDexFile",       "(I)V",
+        Dalvik_dalvik_system_DexFile_closeDexFile },
+    { "defineClass",        "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;",
+        Dalvik_dalvik_system_DexFile_defineClass },
+    { "getClassNameList",   "(I)[Ljava/lang/String;",
+        Dalvik_dalvik_system_DexFile_getClassNameList },
+    { "isDexOptNeeded",     "(Ljava/lang/String;)Z",
+        Dalvik_dalvik_system_DexFile_isDexOptNeeded },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/dalvik_system_VMDebug.cpp b/vm/native/dalvik_system_VMDebug.cpp
new file mode 100644
index 0000000..feefdee
--- /dev/null
+++ b/vm/native/dalvik_system_VMDebug.cpp
@@ -0,0 +1,804 @@
+/*
+ * 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.
+ */
+
+/*
+ * dalvik.system.VMDebug
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+#include "hprof/Hprof.h"
+
+#include <string.h>
+#include <unistd.h>
+
+
+/*
+ * Extracts the fd from a FileDescriptor object.
+ *
+ * If an error is encountered, or the extracted descriptor is numerically
+ * invalid, this returns -1 with an exception raised.
+ */
+static int getFileDescriptor(Object* obj)
+{
+    assert(obj != NULL);
+    assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
+
+    int fd = dvmGetFieldInt(obj, gDvm.offJavaIoFileDescriptor_descriptor);
+    if (fd < 0) {
+        dvmThrowRuntimeException("Invalid file descriptor");
+        return -1;
+    }
+
+    return fd;
+}
+
+/*
+ * static String[] getVmFeatureList()
+ *
+ * Return a set of strings describing available VM features (this is chiefly
+ * of interest to DDMS).
+ */
+static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args, JValue* pResult) {
+    std::vector<std::string> features;
+    features.push_back("method-trace-profiling");
+    features.push_back("method-trace-profiling-streaming");
+    features.push_back("hprof-heap-dump");
+    features.push_back("hprof-heap-dump-streaming");
+
+    ArrayObject* result = dvmCreateStringArray(features);
+    dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
+    RETURN_PTR(result);
+}
+
+/* These must match the values in dalvik.system.VMDebug.
+ */
+enum {
+    KIND_ALLOCATED_OBJECTS      = 1<<0,
+    KIND_ALLOCATED_BYTES        = 1<<1,
+    KIND_FREED_OBJECTS          = 1<<2,
+    KIND_FREED_BYTES            = 1<<3,
+    KIND_GC_INVOCATIONS         = 1<<4,
+    KIND_CLASS_INIT_COUNT       = 1<<5,
+    KIND_CLASS_INIT_TIME        = 1<<6,
+
+    /* These values exist for backward compatibility. */
+    KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
+    KIND_EXT_ALLOCATED_BYTES   = 1<<13,
+    KIND_EXT_FREED_OBJECTS     = 1<<14,
+    KIND_EXT_FREED_BYTES       = 1<<15,
+
+    KIND_GLOBAL_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS,
+    KIND_GLOBAL_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES,
+    KIND_GLOBAL_FREED_OBJECTS       = KIND_FREED_OBJECTS,
+    KIND_GLOBAL_FREED_BYTES         = KIND_FREED_BYTES,
+    KIND_GLOBAL_GC_INVOCATIONS      = KIND_GC_INVOCATIONS,
+    KIND_GLOBAL_CLASS_INIT_COUNT    = KIND_CLASS_INIT_COUNT,
+    KIND_GLOBAL_CLASS_INIT_TIME     = KIND_CLASS_INIT_TIME,
+
+    KIND_THREAD_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS << 16,
+    KIND_THREAD_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES << 16,
+    KIND_THREAD_FREED_OBJECTS       = KIND_FREED_OBJECTS << 16,
+    KIND_THREAD_FREED_BYTES         = KIND_FREED_BYTES << 16,
+
+    KIND_THREAD_GC_INVOCATIONS      = KIND_GC_INVOCATIONS << 16,
+
+    // TODO: failedAllocCount, failedAllocSize
+};
+
+#define KIND_ALL_COUNTS 0xffffffff
+
+/*
+ * Zero out the specified fields.
+ */
+static void clearAllocProfStateFields(AllocProfState *allocProf,
+    unsigned int kinds)
+{
+    if (kinds & KIND_ALLOCATED_OBJECTS) {
+        allocProf->allocCount = 0;
+    }
+    if (kinds & KIND_ALLOCATED_BYTES) {
+        allocProf->allocSize = 0;
+    }
+    if (kinds & KIND_FREED_OBJECTS) {
+        allocProf->freeCount = 0;
+    }
+    if (kinds & KIND_FREED_BYTES) {
+        allocProf->freeSize = 0;
+    }
+    if (kinds & KIND_GC_INVOCATIONS) {
+        allocProf->gcCount = 0;
+    }
+    if (kinds & KIND_CLASS_INIT_COUNT) {
+        allocProf->classInitCount = 0;
+    }
+    if (kinds & KIND_CLASS_INIT_TIME) {
+        allocProf->classInitTime = 0;
+    }
+}
+
+/*
+ * static void startAllocCounting()
+ *
+ * Reset the counters and enable counting.
+ *
+ * TODO: this currently only resets the per-thread counters for the current
+ * thread.  If we actually start using the per-thread counters we'll
+ * probably want to fix this.
+ */
+static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
+    clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
+    dvmStartAllocCounting();
+    RETURN_VOID();
+}
+
+/*
+ * public static void stopAllocCounting()
+ */
+static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    dvmStopAllocCounting();
+    RETURN_VOID();
+}
+
+/*
+ * private static int getAllocCount(int kind)
+ */
+static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
+    JValue* pResult)
+{
+    AllocProfState *allocProf;
+    unsigned int kind = args[0];
+    if (kind < (1<<16)) {
+        allocProf = &gDvm.allocProf;
+    } else {
+        allocProf = &dvmThreadSelf()->allocProf;
+        kind >>= 16;
+    }
+    switch (kind) {
+    case KIND_ALLOCATED_OBJECTS:
+        pResult->i = allocProf->allocCount;
+        break;
+    case KIND_ALLOCATED_BYTES:
+        pResult->i = allocProf->allocSize;
+        break;
+    case KIND_FREED_OBJECTS:
+        pResult->i = allocProf->freeCount;
+        break;
+    case KIND_FREED_BYTES:
+        pResult->i = allocProf->freeSize;
+        break;
+    case KIND_GC_INVOCATIONS:
+        pResult->i = allocProf->gcCount;
+        break;
+    case KIND_CLASS_INIT_COUNT:
+        pResult->i = allocProf->classInitCount;
+        break;
+    case KIND_CLASS_INIT_TIME:
+        /* convert nsec to usec, reduce to 32 bits */
+        pResult->i = (int) (allocProf->classInitTime / 1000);
+        break;
+    case KIND_EXT_ALLOCATED_OBJECTS:
+    case KIND_EXT_ALLOCATED_BYTES:
+    case KIND_EXT_FREED_OBJECTS:
+    case KIND_EXT_FREED_BYTES:
+        pResult->i = 0;  /* backward compatibility */
+        break;
+    default:
+        assert(false);
+        pResult->i = -1;
+    }
+}
+
+/*
+ * public static void resetAllocCount(int kinds)
+ */
+static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
+    JValue* pResult)
+{
+    unsigned int kinds = args[0];
+    clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
+    clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
+    RETURN_VOID();
+}
+
+/*
+ * static void startMethodTracingNative(String traceFileName,
+ *     FileDescriptor fd, int bufferSize, int flags)
+ *
+ * Start method trace profiling.
+ *
+ * If both "traceFileName" and "fd" are null, the result will be sent
+ * directly to DDMS.  (The non-DDMS versions of the calls are expected
+ * to enforce non-NULL filenames.)
+ */
+static void Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4* args,
+    JValue* pResult)
+{
+    StringObject* traceFileStr = (StringObject*) args[0];
+    Object* traceFd = (Object*) args[1];
+    int bufferSize = args[2];
+    int flags = args[3];
+
+    if (bufferSize == 0) {
+        // Default to 8MB per the documentation.
+        bufferSize = 8 * 1024 * 1024;
+    }
+
+    if (bufferSize < 1024) {
+        dvmThrowIllegalArgumentException(NULL);
+        RETURN_VOID();
+    }
+
+    char* traceFileName = NULL;
+    if (traceFileStr != NULL)
+        traceFileName = dvmCreateCstrFromString(traceFileStr);
+
+    int fd = -1;
+    if (traceFd != NULL) {
+        int origFd = getFileDescriptor(traceFd);
+        if (origFd < 0)
+            RETURN_VOID();
+
+        fd = dup(origFd);
+        if (fd < 0) {
+            dvmThrowExceptionFmt(gDvm.exRuntimeException,
+                "dup(%d) failed: %s", origFd, strerror(errno));
+            RETURN_VOID();
+        }
+    }
+
+    dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]",
+        fd, bufferSize, flags, (traceFileName == NULL && fd == -1));
+    free(traceFileName);
+    RETURN_VOID();
+}
+
+/*
+ * static boolean isMethodTracingActive()
+ *
+ * Determine whether method tracing is currently active.
+ */
+static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_BOOLEAN(dvmIsMethodTraceActive());
+}
+
+/*
+ * static void stopMethodTracing()
+ *
+ * Stop method tracing.
+ */
+static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    dvmMethodTraceStop();
+    RETURN_VOID();
+}
+
+/*
+ * static void startEmulatorTracing()
+ *
+ * Start sending method trace info to the emulator.
+ */
+static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    dvmEmulatorTraceStart();
+    RETURN_VOID();
+}
+
+/*
+ * static void stopEmulatorTracing()
+ *
+ * Start sending method trace info to the emulator.
+ */
+static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    dvmEmulatorTraceStop();
+    RETURN_VOID();
+}
+
+/*
+ * static boolean isDebuggerConnected()
+ *
+ * Returns "true" if a debugger is attached.
+ */
+static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
+}
+
+/*
+ * static boolean isDebuggingEnabled()
+ *
+ * Returns "true" if debugging is enabled.
+ */
+static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_BOOLEAN(gDvm.jdwpConfigured);
+}
+
+/*
+ * static long lastDebuggerActivity()
+ *
+ * Returns the time, in msec, since we last had an interaction with the
+ * debugger (send or receive).
+ */
+static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_LONG(dvmDbgLastDebuggerActivity());
+}
+
+/*
+ * static void startInstructionCounting()
+ */
+static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
+    JValue* pResult)
+{
+    dvmStartInstructionCounting();
+    RETURN_VOID();
+}
+
+/*
+ * static void stopInstructionCounting()
+ */
+static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
+    JValue* pResult)
+{
+    dvmStopInstructionCounting();
+    RETURN_VOID();
+}
+
+/*
+ * static boolean getInstructionCount(int[] counts)
+ *
+ * Grab a copy of the global instruction count array.
+ *
+ * Since the instruction counts aren't synchronized, we use sched_yield
+ * to improve our chances of finishing without contention.  (Only makes
+ * sense on a uniprocessor.)
+ */
+static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
+    JValue* pResult)
+{
+    ArrayObject* countArray = (ArrayObject*) args[0];
+
+    if (countArray != NULL) {
+        int* storage = (int*)(void*)countArray->contents;
+        u4 length = countArray->length;
+
+        /*
+         * Ensure that we copy at most kNumPackedOpcodes
+         * elements, but no more than the length of the given array.
+         */
+        if (length > kNumPackedOpcodes) {
+            length = kNumPackedOpcodes;
+        }
+
+        sched_yield();
+        memcpy(storage, gDvm.executedInstrCounts, length * sizeof(int));
+    }
+
+    RETURN_VOID();
+}
+
+/*
+ * static boolean resetInstructionCount()
+ *
+ * Reset the instruction count array.
+ */
+static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
+    JValue* pResult)
+{
+    sched_yield();
+    memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
+    RETURN_VOID();
+}
+
+/*
+ * static void printLoadedClasses(int flags)
+ *
+ * Dump the list of loaded classes.
+ */
+static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
+    JValue* pResult)
+{
+    int flags = args[0];
+
+    dvmDumpAllClasses(flags);
+
+    RETURN_VOID();
+}
+
+/*
+ * static int getLoadedClassCount()
+ *
+ * Return the number of loaded classes
+ */
+static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
+    JValue* pResult)
+{
+    int count;
+
+    UNUSED_PARAMETER(args);
+
+    count = dvmGetNumLoadedClasses();
+
+    RETURN_INT(count);
+}
+
+/*
+ * Returns the thread-specific CPU-time clock value for the current thread,
+ * or -1 if the feature isn't supported.
+ */
+static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
+    JValue* pResult)
+{
+    jlong result;
+
+#ifdef HAVE_POSIX_CLOCKS
+    struct timespec now;
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
+    result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
+#else
+    result = (jlong) -1;
+#endif
+
+    RETURN_LONG(result);
+}
+
+/*
+ * static void dumpHprofData(String fileName, FileDescriptor fd)
+ *
+ * Cause "hprof" data to be dumped.  We can throw an IOException if an
+ * error occurs during file handling.
+ */
+static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
+    JValue* pResult)
+{
+    StringObject* fileNameStr = (StringObject*) args[0];
+    Object* fileDescriptor = (Object*) args[1];
+    char* fileName;
+    int result;
+
+    /*
+     * Only one of these may be NULL.
+     */
+    if (fileNameStr == NULL && fileDescriptor == NULL) {
+        dvmThrowNullPointerException("fileName == null && fd == null");
+        RETURN_VOID();
+    }
+
+    if (fileNameStr != NULL) {
+        fileName = dvmCreateCstrFromString(fileNameStr);
+        if (fileName == NULL) {
+            /* unexpected -- malloc failure? */
+            dvmThrowRuntimeException("malloc failure?");
+            RETURN_VOID();
+        }
+    } else {
+        fileName = strdup("[fd]");
+    }
+
+    int fd = -1;
+    if (fileDescriptor != NULL) {
+        fd = getFileDescriptor(fileDescriptor);
+        if (fd < 0) {
+            free(fileName);
+            RETURN_VOID();
+        }
+    }
+
+    result = hprofDumpHeap(fileName, fd, false);
+    free(fileName);
+
+    if (result != 0) {
+        /* ideally we'd throw something more specific based on actual failure */
+        dvmThrowRuntimeException(
+            "Failure during heap dump; check log output for details");
+        RETURN_VOID();
+    }
+
+    RETURN_VOID();
+}
+
+/*
+ * static void dumpHprofDataDdms()
+ *
+ * Cause "hprof" data to be computed and sent directly to DDMS.
+ */
+static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
+    JValue* pResult)
+{
+    int result;
+
+    result = hprofDumpHeap("[DDMS]", -1, true);
+
+    if (result != 0) {
+        /* ideally we'd throw something more specific based on actual failure */
+        dvmThrowRuntimeException(
+            "Failure during heap dump; check log output for details");
+        RETURN_VOID();
+    }
+
+    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) {
+        dvmThrowNullPointerException("classAndMethodDesc == 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) {
+        dvmThrowRuntimeException("method name not found in string");
+        RETURN_VOID();
+    }
+    *methodName++ = '\0';
+
+    char* methodDescr = strchr(methodName, ':');
+    if (methodDescr == NULL) {
+        dvmThrowRuntimeException("method descriptor not found in string");
+        RETURN_VOID();
+    }
+    *methodDescr++ = '\0';
+
+    //LOGD("GOT: %s %s %s", 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", 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",
+                classAndMethodDesc, methodName, methodDescr);
+        } else {
+            LOGV("Found map %s.%s %s",
+                classAndMethodDesc, methodName, methodDescr);
+            result = true;
+        }
+    } else {
+        LOGV("Unable to find %s.%s %s",
+            classAndMethodDesc, methodName, methodDescr);
+    }
+
+bail:
+    free(classAndMethodDesc);
+    RETURN_BOOLEAN(result);
+}
+
+/*
+ * static void dumpReferenceTables()
+ */
+static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+    UNUSED_PARAMETER(pResult);
+
+    LOGI("--- reference table dump ---");
+    dvmDumpJniReferenceTables();
+    // could dump thread's internalLocalRefTable, probably not useful
+    // ditto for thread's jniMonitorRefTable
+    LOGI("---");
+    RETURN_VOID();
+}
+
+/*
+ * static void crash()
+ *
+ * Dump the current thread's interpreted stack and abort the VM.  Useful
+ * for seeing both interpreted and native stack traces.
+ *
+ * (Might want to restrict this to debuggable processes as a security
+ * measure, or check SecurityManager.checkExit().)
+ */
+static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+    UNUSED_PARAMETER(pResult);
+
+    LOGW("Crashing VM on request");
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmAbort();
+}
+
+/*
+ * static void infopoint(int id)
+ *
+ * Provide a hook for gdb to hang to so that the VM can be stopped when
+ * user-tagged source locations are being executed.
+ */
+static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
+    JValue* pResult)
+{
+    gDvm.nativeDebuggerActive = true;
+
+    LOGD("VMDebug infopoint %d hit", args[0]);
+
+    gDvm.nativeDebuggerActive = false;
+    RETURN_VOID();
+}
+
+static void Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*)args[0];
+    bool countAssignable = args[1];
+    if (clazz == NULL) {
+        RETURN_LONG(0);
+    }
+    if (countAssignable) {
+        size_t count = dvmCountAssignableInstancesOfClass(clazz);
+        RETURN_LONG((long long)count);
+    } else {
+        size_t count = dvmCountInstancesOfClass(clazz);
+        RETURN_LONG((long long)count);
+    }
+}
+
+const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
+    { "getVmFeatureList",           "()[Ljava/lang/String;",
+        Dalvik_dalvik_system_VMDebug_getVmFeatureList },
+    { "getAllocCount",              "(I)I",
+        Dalvik_dalvik_system_VMDebug_getAllocCount },
+    { "resetAllocCount",            "(I)V",
+        Dalvik_dalvik_system_VMDebug_resetAllocCount },
+    { "startAllocCounting",         "()V",
+        Dalvik_dalvik_system_VMDebug_startAllocCounting },
+    { "stopAllocCounting",          "()V",
+        Dalvik_dalvik_system_VMDebug_stopAllocCounting },
+    { "startMethodTracingNative",   "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
+        Dalvik_dalvik_system_VMDebug_startMethodTracingNative },
+    { "isMethodTracingActive",      "()Z",
+        Dalvik_dalvik_system_VMDebug_isMethodTracingActive },
+    { "stopMethodTracing",          "()V",
+        Dalvik_dalvik_system_VMDebug_stopMethodTracing },
+    { "startEmulatorTracing",       "()V",
+        Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
+    { "stopEmulatorTracing",        "()V",
+        Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
+    { "startInstructionCounting",   "()V",
+        Dalvik_dalvik_system_VMDebug_startInstructionCounting },
+    { "stopInstructionCounting",    "()V",
+        Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
+    { "resetInstructionCount",      "()V",
+        Dalvik_dalvik_system_VMDebug_resetInstructionCount },
+    { "getInstructionCount",        "([I)V",
+        Dalvik_dalvik_system_VMDebug_getInstructionCount },
+    { "isDebuggerConnected",        "()Z",
+        Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
+    { "isDebuggingEnabled",         "()Z",
+        Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
+    { "lastDebuggerActivity",       "()J",
+        Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
+    { "printLoadedClasses",         "(I)V",
+        Dalvik_dalvik_system_VMDebug_printLoadedClasses },
+    { "getLoadedClassCount",        "()I",
+        Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
+    { "threadCpuTimeNanos",         "()J",
+        Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
+    { "dumpHprofData",              "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
+        Dalvik_dalvik_system_VMDebug_dumpHprofData },
+    { "dumpHprofDataDdms",          "()V",
+        Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
+    { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
+        Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
+    { "dumpReferenceTables",        "()V",
+        Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
+    { "crash",                      "()V",
+        Dalvik_dalvik_system_VMDebug_crash },
+    { "infopoint",                 "(I)V",
+        Dalvik_dalvik_system_VMDebug_infopoint },
+    { "countInstancesOfClass",     "(Ljava/lang/Class;Z)J",
+        Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/dalvik_system_VMRuntime.cpp b/vm/native/dalvik_system_VMRuntime.cpp
new file mode 100644
index 0000000..6bd5333
--- /dev/null
+++ b/vm/native/dalvik_system_VMRuntime.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+/*
+ * dalvik.system.VMRuntime
+ */
+#include "Dalvik.h"
+#include "ScopedPthreadMutexLock.h"
+#include "native/InternalNativePriv.h"
+
+#include <cutils/array.h>
+#include <limits.h>
+
+
+/*
+ * public native float getTargetHeapUtilization()
+ *
+ * Gets the current ideal heap utilization, represented as a number
+ * between zero and one.
+ */
+static void Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization(
+    const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_FLOAT(dvmGetTargetHeapUtilization());
+}
+
+/*
+ * native float nativeSetTargetHeapUtilization()
+ *
+ * Sets the current ideal heap utilization, represented as a number
+ * between zero and one.  Returns the old utilization.
+ *
+ * Note that this is NOT static.
+ */
+static void Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization(
+    const u4* args, JValue* pResult)
+{
+    dvmSetTargetHeapUtilization(dvmU4ToFloat(args[1]));
+
+    RETURN_VOID();
+}
+
+/*
+ * public native void startJitCompilation()
+ *
+ * Callback function from the framework to indicate that an app has gone
+ * through the startup phase and it is time to enable the JIT compiler.
+ */
+static void Dalvik_dalvik_system_VMRuntime_startJitCompilation(const u4* args,
+    JValue* pResult)
+{
+#if defined(WITH_JIT)
+    if (gDvm.executionMode == kExecutionModeJit && gDvmJit.disableJit == false) {
+        ScopedPthreadMutexLock lock(&gDvmJit.compilerLock);
+        gDvmJit.alreadyEnabledViaFramework = true;
+        pthread_cond_signal(&gDvmJit.compilerQueueActivity);
+    }
+#endif
+    RETURN_VOID();
+}
+
+/*
+ * public native void disableJitCompilation()
+ *
+ * Callback function from the framework to indicate that a VM instance wants to
+ * permanently disable the JIT compiler. Currently only the system server uses
+ * this interface when it detects system-wide safe mode is enabled.
+ */
+static void Dalvik_dalvik_system_VMRuntime_disableJitCompilation(const u4* args,
+    JValue* pResult)
+{
+#if defined(WITH_JIT)
+    if (gDvm.executionMode == kExecutionModeJit) {
+        gDvmJit.disableJit = true;
+    }
+#endif
+    RETURN_VOID();
+}
+
+static void Dalvik_dalvik_system_VMRuntime_newNonMovableArray(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* elementClass = (ClassObject*) args[1];
+    int length = args[2];
+
+    if (elementClass == NULL) {
+        dvmThrowNullPointerException("elementClass == null");
+        RETURN_VOID();
+    }
+    if (length < 0) {
+        dvmThrowNegativeArraySizeException(length);
+        RETURN_VOID();
+    }
+
+    // TODO: right now, we don't have a copying collector, so there's no need
+    // to do anything special here, but we ought to pass the non-movability
+    // through to the allocator.
+    ClassObject* arrayClass = dvmFindArrayClassForElement(elementClass);
+    ArrayObject* newArray = dvmAllocArrayByClass(arrayClass,
+                                                 length,
+                                                 ALLOC_NON_MOVING);
+    if (newArray == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        RETURN_VOID();
+    }
+    dvmReleaseTrackedAlloc((Object*) newArray, NULL);
+
+    RETURN_PTR(newArray);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_addressOf(const u4* args,
+    JValue* pResult)
+{
+    ArrayObject* array = (ArrayObject*) args[1];
+    if (!dvmIsArray(array)) {
+        dvmThrowIllegalArgumentException(NULL);
+        RETURN_VOID();
+    }
+    // TODO: we should also check that this is a non-movable array.
+    s8 result = (uintptr_t) array->contents;
+    RETURN_LONG(result);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_clearGrowthLimit(const u4* args,
+    JValue* pResult)
+{
+    dvmClearGrowthLimit();
+    RETURN_VOID();
+}
+
+static void Dalvik_dalvik_system_VMRuntime_isDebuggerActive(
+    const u4* args, JValue* pResult)
+{
+    RETURN_BOOLEAN(gDvm.debuggerActive || gDvm.nativeDebuggerActive);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_properties(const u4* args,
+    JValue* pResult)
+{
+    ArrayObject* result = dvmCreateStringArray(*gDvm.properties);
+    dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
+    RETURN_PTR(result);
+}
+
+static void returnCString(JValue* pResult, const char* s)
+{
+    Object* result = (Object*) dvmCreateStringFromCstr(s);
+    dvmReleaseTrackedAlloc(result, dvmThreadSelf());
+    RETURN_PTR(result);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4* args,
+    JValue* pResult)
+{
+    returnCString(pResult, gDvm.bootClassPathStr);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_classPath(const u4* args,
+    JValue* pResult)
+{
+    returnCString(pResult, gDvm.classPathStr);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_vmVersion(const u4* args,
+    JValue* pResult)
+{
+    char buf[64];
+    sprintf(buf, "%d.%d.%d",
+            DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
+    returnCString(pResult, buf);
+}
+
+static void Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion(const u4* args,
+    JValue* pResult)
+{
+    // This is the target SDK version of the app we're about to run.
+    // Note that this value may be CUR_DEVELOPMENT (10000).
+    // Note that this value may be 0, meaning "current".
+    int targetSdkVersion = args[1];
+    if (targetSdkVersion > 0 && targetSdkVersion <= 13 /* honeycomb-mr2 */) {
+        // TODO: running with CheckJNI should override this and force you to obey the strictest rules.
+        LOGI("Turning on JNI app bug workarounds for target SDK version %i...", targetSdkVersion);
+        gDvmJni.workAroundAppJniBugs = true;
+    }
+    RETURN_VOID();
+}
+
+const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
+    { "addressOf", "(Ljava/lang/Object;)J",
+        Dalvik_dalvik_system_VMRuntime_addressOf },
+    { "bootClassPath", "()Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_bootClassPath },
+    { "classPath", "()Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_classPath },
+    { "clearGrowthLimit", "()V",
+        Dalvik_dalvik_system_VMRuntime_clearGrowthLimit },
+    { "disableJitCompilation", "()V",
+        Dalvik_dalvik_system_VMRuntime_disableJitCompilation },
+    { "isDebuggerActive", "()Z",
+        Dalvik_dalvik_system_VMRuntime_isDebuggerActive },
+    { "getTargetHeapUtilization", "()F",
+        Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization },
+    { "nativeSetTargetHeapUtilization", "(F)V",
+        Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization },
+    { "newNonMovableArray", "(Ljava/lang/Class;I)Ljava/lang/Object;",
+        Dalvik_dalvik_system_VMRuntime_newNonMovableArray },
+    { "properties", "()[Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_properties },
+    { "setTargetSdkVersion", "(I)V",
+        Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion },
+    { "startJitCompilation", "()V",
+        Dalvik_dalvik_system_VMRuntime_startJitCompilation },
+    { "vmVersion", "()Ljava/lang/String;",
+        Dalvik_dalvik_system_VMRuntime_vmVersion },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/dalvik_system_VMStack.cpp b/vm/native/dalvik_system_VMStack.cpp
new file mode 100644
index 0000000..85ea21a
--- /dev/null
+++ b/vm/native/dalvik_system_VMStack.cpp
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+/*
+ * dalvik.system.VMStack
+ */
+#include "Dalvik.h"
+#include "UniquePtr.h"
+#include "native/InternalNativePriv.h"
+
+/*
+ * public static ClassLoader getCallingClassLoader()
+ *
+ * Return the defining class loader of the caller's caller.
+ */
+static void Dalvik_dalvik_system_VMStack_getCallingClassLoader(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz =
+        dvmGetCaller2Class(dvmThreadSelf()->interpSave.curFrame);
+
+    UNUSED_PARAMETER(args);
+
+    if (clazz == NULL)
+        RETURN_PTR(NULL);
+    RETURN_PTR(clazz->classLoader);
+}
+
+/*
+ * public static Class<?> getStackClass2()
+ *
+ * Returns the class of the caller's caller's caller.
+ */
+static void Dalvik_dalvik_system_VMStack_getStackClass2(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz =
+        dvmGetCaller3Class(dvmThreadSelf()->interpSave.curFrame);
+
+    UNUSED_PARAMETER(args);
+
+    RETURN_PTR(clazz);
+}
+
+/*
+ * public static Class<?>[] getClasses(int maxDepth)
+ *
+ * Create an array of classes for the methods on the stack, skipping the
+ * first two and all reflection methods.  If "stopAtPrivileged" is set,
+ * stop shortly after we encounter a privileged class.
+ */
+static void Dalvik_dalvik_system_VMStack_getClasses(const u4* args,
+    JValue* pResult)
+{
+    /* note "maxSize" is unsigned, so -1 turns into a very large value */
+    size_t maxSize = args[0];
+    size_t size = 0;
+    const size_t kSkip = 2;
+
+    /*
+     * Get an array with the stack trace in it.
+     */
+    void *fp = dvmThreadSelf()->interpSave.curFrame;
+    size_t depth = dvmComputeExactFrameDepth(fp);
+    UniquePtr<const Method*[]> methods(new const Method*[depth]);
+    dvmFillStackTraceArray(fp, methods.get(), depth);
+
+    /*
+     * Run through the array and count up how many elements there are.
+     */
+    for (size_t i = kSkip; i < depth && size < maxSize; ++i) {
+        const Method* meth = methods[i];
+
+        if (dvmIsReflectionMethod(meth))
+            continue;
+
+        size++;
+    }
+
+    /*
+     * Create an array object to hold the classes.
+     * TODO: can use gDvm.classJavaLangClassArray here?
+     */
+    ClassObject* classArrayClass = dvmFindArrayClass("[Ljava/lang/Class;",
+                                                     NULL);
+    if (classArrayClass == NULL) {
+        LOGW("Unable to find java.lang.Class array class");
+        return;
+    }
+    ArrayObject* classes = dvmAllocArrayByClass(classArrayClass,
+                                                size,
+                                                ALLOC_DEFAULT);
+    if (classes == NULL) {
+        LOGW("Unable to allocate class array of %zd elements", size);
+        return;
+    }
+
+    /*
+     * Fill in the array.
+     */
+    size_t objCount = 0;
+    for (size_t i = kSkip; i < depth; ++i) {
+        if (dvmIsReflectionMethod(methods[i])) {
+            continue;
+        }
+        Object* klass = (Object *)methods[i]->clazz;
+        dvmSetObjectArrayElement(classes, objCount, klass);
+        objCount++;
+    }
+    assert(objCount == classes->length);
+
+    dvmReleaseTrackedAlloc((Object*)classes, NULL);
+    RETURN_PTR(classes);
+}
+
+/*
+ * Return a trace buffer for the specified thread or NULL if the
+ * thread is not still alive. *depth is set to the length of a
+ * non-NULL trace buffer. Caller is responsible for freeing the trace
+ * buffer.
+ */
+static int* getTraceBuf(Object* targetThreadObj, size_t* pStackDepth)
+{
+    Thread* self = dvmThreadSelf();
+    Thread* thread;
+    int* traceBuf;
+
+    assert(targetThreadObj != NULL);
+
+    dvmLockThreadList(self);
+
+    /*
+     * Make sure the thread is still alive and in the list.
+     */
+    for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+        if (thread->threadObj == targetThreadObj)
+            break;
+    }
+    if (thread == NULL) {
+        LOGI("VMStack.getTraceBuf: threadObj %p not active",
+            targetThreadObj);
+        dvmUnlockThreadList();
+        return NULL;
+    }
+
+    /*
+     * Suspend the thread, pull out the stack trace, then resume the thread
+     * and release the thread list lock.  If we're being asked to examine
+     * our own stack trace, skip the suspend/resume.
+     */
+    if (thread != self)
+        dvmSuspendThread(thread);
+    traceBuf = dvmFillInStackTraceRaw(thread, pStackDepth);
+    if (thread != self)
+        dvmResumeThread(thread);
+    dvmUnlockThreadList();
+
+    return traceBuf;
+}
+
+/*
+ * public static StackTraceElement[] getThreadStackTrace(Thread t)
+ *
+ * Retrieve the stack trace of the specified thread and return it as an
+ * array of StackTraceElement.  Returns NULL on failure.
+ */
+static void Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4* args,
+    JValue* pResult)
+{
+    Object* targetThreadObj = (Object*) args[0];
+    size_t stackDepth;
+    int* traceBuf = getTraceBuf(targetThreadObj, &stackDepth);
+
+    if (traceBuf == NULL)
+        RETURN_PTR(NULL);
+
+    /*
+     * Convert the raw buffer into an array of StackTraceElement.
+     */
+    ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth);
+    free(traceBuf);
+    RETURN_PTR(trace);
+}
+
+/*
+ * public static int fillStackTraceElements(Thread t, StackTraceElement[] stackTraceElements)
+ *
+ * Retrieve a partial stack trace of the specified thread and return
+ * the number of frames filled.  Returns 0 on failure.
+ */
+static void Dalvik_dalvik_system_VMStack_fillStackTraceElements(const u4* args,
+    JValue* pResult)
+{
+    Object* targetThreadObj = (Object*) args[0];
+    ArrayObject* steArray = (ArrayObject*) args[1];
+    size_t stackDepth;
+    int* traceBuf = getTraceBuf(targetThreadObj, &stackDepth);
+
+    if (traceBuf == NULL)
+        RETURN_PTR(NULL);
+
+    /*
+     * Set the raw buffer into an array of StackTraceElement.
+     */
+    if (stackDepth > steArray->length) {
+        stackDepth = steArray->length;
+    }
+    dvmFillStackTraceElements(traceBuf, stackDepth, steArray);
+    free(traceBuf);
+    RETURN_INT(stackDepth);
+}
+
+const DalvikNativeMethod dvm_dalvik_system_VMStack[] = {
+    { "getCallingClassLoader",  "()Ljava/lang/ClassLoader;",
+        Dalvik_dalvik_system_VMStack_getCallingClassLoader },
+    { "getStackClass2",         "()Ljava/lang/Class;",
+        Dalvik_dalvik_system_VMStack_getStackClass2 },
+    { "getClasses",             "(I)[Ljava/lang/Class;",
+        Dalvik_dalvik_system_VMStack_getClasses },
+    { "getThreadStackTrace",    "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;",
+        Dalvik_dalvik_system_VMStack_getThreadStackTrace },
+    { "fillStackTraceElements", "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I",
+        Dalvik_dalvik_system_VMStack_fillStackTraceElements },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/dalvik_system_Zygote.cpp b/vm/native/dalvik_system_Zygote.cpp
new file mode 100644
index 0000000..492ea4a
--- /dev/null
+++ b/vm/native/dalvik_system_Zygote.cpp
@@ -0,0 +1,552 @@
+/*
+ * 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.
+ */
+
+/*
+ * dalvik.system.Zygote
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <grp.h>
+#include <errno.h>
+#include <paths.h>
+#include <sys/personality.h>
+
+#if defined(HAVE_PRCTL)
+# include <sys/prctl.h>
+#endif
+
+#define ZYGOTE_LOG_TAG "Zygote"
+
+/* must match values in dalvik.system.Zygote */
+enum {
+    DEBUG_ENABLE_DEBUGGER           = 1,
+    DEBUG_ENABLE_CHECKJNI           = 1 << 1,
+    DEBUG_ENABLE_ASSERT             = 1 << 2,
+    DEBUG_ENABLE_SAFEMODE           = 1 << 3,
+    DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
+};
+
+/*
+ * This signal handler is for zygote mode, since the zygote
+ * must reap its children
+ */
+static void sigchldHandler(int s)
+{
+    pid_t pid;
+    int status;
+
+    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+        /* Log process-death status that we care about.  In general it is not
+           safe to call LOG(...) from a signal handler because of possible
+           reentrancy.  However, we know a priori that the current implementation
+           of LOG() is safe to call from a SIGCHLD handler in the zygote process.
+           If the LOG() implementation changes its locking strategy or its use
+           of syscalls within the lazy-init critical section, its use here may
+           become unsafe. */
+        if (WIFEXITED(status)) {
+            if (WEXITSTATUS(status)) {
+                LOG(LOG_DEBUG, ZYGOTE_LOG_TAG, "Process %d exited cleanly (%d)",
+                    (int) pid, WEXITSTATUS(status));
+            } else {
+                IF_LOGV(/*should use ZYGOTE_LOG_TAG*/) {
+                    LOG(LOG_VERBOSE, ZYGOTE_LOG_TAG,
+                        "Process %d exited cleanly (%d)",
+                        (int) pid, WEXITSTATUS(status));
+                }
+            }
+        } else if (WIFSIGNALED(status)) {
+            if (WTERMSIG(status) != SIGKILL) {
+                LOG(LOG_DEBUG, ZYGOTE_LOG_TAG,
+                    "Process %d terminated by signal (%d)",
+                    (int) pid, WTERMSIG(status));
+            } else {
+                IF_LOGV(/*should use ZYGOTE_LOG_TAG*/) {
+                    LOG(LOG_VERBOSE, ZYGOTE_LOG_TAG,
+                        "Process %d terminated by signal (%d)",
+                        (int) pid, WTERMSIG(status));
+                }
+            }
+#ifdef WCOREDUMP
+            if (WCOREDUMP(status)) {
+                LOG(LOG_INFO, ZYGOTE_LOG_TAG, "Process %d dumped core",
+                    (int) pid);
+            }
+#endif /* ifdef WCOREDUMP */
+        }
+
+        /*
+         * If the just-crashed process is the system_server, bring down zygote
+         * so that it is restarted by init and system server will be restarted
+         * from there.
+         */
+        if (pid == gDvm.systemServerPid) {
+            LOG(LOG_INFO, ZYGOTE_LOG_TAG,
+                "Exit zygote because system server (%d) has terminated",
+                (int) pid);
+            kill(getpid(), SIGKILL);
+        }
+    }
+
+    if (pid < 0) {
+        LOG(LOG_WARN, ZYGOTE_LOG_TAG,
+            "Zygote SIGCHLD error in waitpid: %s",strerror(errno));
+    }
+}
+
+/*
+ * configure sigchld handler for the zygote process
+ * This is configured very late, because earlier in the dalvik lifecycle
+ * we can fork() and exec() for the verifier/optimizer, and we
+ * want to waitpid() for those rather than have them be harvested immediately.
+ *
+ * This ends up being called repeatedly before each fork(), but there's
+ * no real harm in that.
+ */
+static void setSignalHandler()
+{
+    int err;
+    struct sigaction sa;
+
+    memset(&sa, 0, sizeof(sa));
+
+    sa.sa_handler = sigchldHandler;
+
+    err = sigaction (SIGCHLD, &sa, NULL);
+
+    if (err < 0) {
+        LOGW("Error setting SIGCHLD handler: %s", strerror(errno));
+    }
+}
+
+/*
+ * Set the SIGCHLD handler back to default behavior in zygote children
+ */
+static void unsetSignalHandler()
+{
+    int err;
+    struct sigaction sa;
+
+    memset(&sa, 0, sizeof(sa));
+
+    sa.sa_handler = SIG_DFL;
+
+    err = sigaction (SIGCHLD, &sa, NULL);
+
+    if (err < 0) {
+        LOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
+    }
+}
+
+/*
+ * Calls POSIX setgroups() using the int[] object as an argument.
+ * A NULL argument is tolerated.
+ */
+
+static int setgroupsIntarray(ArrayObject* gidArray)
+{
+    gid_t *gids;
+    u4 i;
+    s4 *contents;
+
+    if (gidArray == NULL) {
+        return 0;
+    }
+
+    /* just in case gid_t and u4 are different... */
+    gids = (gid_t *)alloca(sizeof(gid_t) * gidArray->length);
+    contents = (s4 *)(void *)gidArray->contents;
+
+    for (i = 0 ; i < gidArray->length ; i++) {
+        gids[i] = (gid_t) contents[i];
+    }
+
+    return setgroups((size_t) gidArray->length, gids);
+}
+
+/*
+ * Sets the resource limits via setrlimit(2) for the values in the
+ * two-dimensional array of integers that's passed in. The second dimension
+ * contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+ * treated as an empty array.
+ *
+ * -1 is returned on error.
+ */
+static int setrlimitsFromArray(ArrayObject* rlimits)
+{
+    u4 i;
+    struct rlimit rlim;
+
+    if (rlimits == NULL) {
+        return 0;
+    }
+
+    memset (&rlim, 0, sizeof(rlim));
+
+    ArrayObject** tuples = (ArrayObject **)(void *)rlimits->contents;
+
+    for (i = 0; i < rlimits->length; i++) {
+        ArrayObject * rlimit_tuple = tuples[i];
+        s4* contents = (s4 *)(void *)rlimit_tuple->contents;
+        int err;
+
+        if (rlimit_tuple->length != 3) {
+            LOGE("rlimits array must have a second dimension of size 3");
+            return -1;
+        }
+
+        rlim.rlim_cur = contents[1];
+        rlim.rlim_max = contents[2];
+
+        err = setrlimit(contents[0], &rlim);
+
+        if (err < 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/* native public static int fork(); */
+static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue* pResult)
+{
+    pid_t pid;
+
+    if (!gDvm.zygote) {
+        dvmThrowIllegalStateException(
+            "VM instance not started with -Xzygote");
+
+        RETURN_VOID();
+    }
+
+    if (!dvmGcPreZygoteFork()) {
+        LOGE("pre-fork heap failed");
+        dvmAbort();
+    }
+
+    setSignalHandler();
+
+    dvmDumpLoaderStats("zygote");
+    pid = fork();
+
+#ifdef HAVE_ANDROID_OS
+    if (pid == 0) {
+        /* child process */
+        extern int gMallocLeakZygoteChild;
+        gMallocLeakZygoteChild = 1;
+    }
+#endif
+
+    RETURN_INT(pid);
+}
+
+/*
+ * Enable/disable debug features requested by the caller.
+ *
+ * debugger
+ *   If set, enable debugging; if not set, disable debugging.  This is
+ *   easy to handle, because the JDWP thread isn't started until we call
+ *   dvmInitAfterZygote().
+ * checkjni
+ *   If set, make sure "check JNI" is enabled.
+ * assert
+ *   If set, make sure assertions are enabled.  This gets fairly weird,
+ *   because it affects the result of a method called by class initializers,
+ *   and hence can't affect pre-loaded/initialized classes.
+ * safemode
+ *   If set, operates the VM in the safe mode. The definition of "safe mode" is
+ *   implementation dependent and currently only the JIT compiler is disabled.
+ *   This is easy to handle because the compiler thread and associated resources
+ *   are not requested until we call dvmInitAfterZygote().
+ */
+static void enableDebugFeatures(u4 debugFlags)
+{
+    LOGV("debugFlags is 0x%02x", debugFlags);
+
+    gDvm.jdwpAllowed = ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0);
+
+    if ((debugFlags & DEBUG_ENABLE_CHECKJNI) != 0) {
+        /* turn it on if it's not already enabled */
+        dvmLateEnableCheckedJni();
+    }
+
+    if ((debugFlags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
+        gDvmJni.logThirdPartyJni = true;
+    }
+
+    if ((debugFlags & DEBUG_ENABLE_ASSERT) != 0) {
+        /* turn it on if it's not already enabled */
+        dvmLateEnableAssertions();
+    }
+
+    if ((debugFlags & DEBUG_ENABLE_SAFEMODE) != 0) {
+#if defined(WITH_JIT)
+        /* turn off the jit if it is explicitly requested by the app */
+        if (gDvm.executionMode == kExecutionModeJit)
+            gDvm.executionMode = kExecutionModeInterpFast;
+#endif
+    }
+
+#ifdef HAVE_ANDROID_OS
+    if ((debugFlags & DEBUG_ENABLE_DEBUGGER) != 0) {
+        /* To let a non-privileged gdbserver attach to this
+         * process, we must set its dumpable bit flag. However
+         * we are not interested in generating a coredump in
+         * case of a crash, so also set the coredump size to 0
+         * to disable that
+         */
+        if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
+            LOGE("could not set dumpable bit flag for pid %d: %s",
+                 getpid(), strerror(errno));
+        } else {
+            struct rlimit rl;
+            rl.rlim_cur = 0;
+            rl.rlim_max = RLIM_INFINITY;
+            if (setrlimit(RLIMIT_CORE, &rl) < 0) {
+                LOGE("could not disable core file generation for pid %d: %s",
+                    getpid(), strerror(errno));
+            }
+        }
+    }
+#endif
+}
+
+/*
+ * Set Linux capability flags.
+ *
+ * Returns 0 on success, errno on failure.
+ */
+static int setCapabilities(int64_t permitted, int64_t effective)
+{
+#ifdef HAVE_ANDROID_OS
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata;
+
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+
+    capheader.version = _LINUX_CAPABILITY_VERSION;
+    capheader.pid = 0;
+
+    capdata.effective = effective;
+    capdata.permitted = permitted;
+
+    LOGV("CAPSET perm=%llx eff=%llx", permitted, effective);
+    if (capset(&capheader, &capdata) != 0)
+        return errno;
+#endif /*HAVE_ANDROID_OS*/
+
+    return 0;
+}
+
+/*
+ * Utility routine to fork zygote and specialize the child process.
+ */
+static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
+{
+    pid_t pid;
+
+    uid_t uid = (uid_t) args[0];
+    gid_t gid = (gid_t) args[1];
+    ArrayObject* gids = (ArrayObject *)args[2];
+    u4 debugFlags = args[3];
+    ArrayObject *rlimits = (ArrayObject *)args[4];
+    int64_t permittedCapabilities, effectiveCapabilities;
+
+    if (isSystemServer) {
+        /*
+         * Don't use GET_ARG_LONG here for now.  gcc is generating code
+         * that uses register d8 as a temporary, and that's coming out
+         * scrambled in the child process.  b/3138621
+         */
+        //permittedCapabilities = GET_ARG_LONG(args, 5);
+        //effectiveCapabilities = GET_ARG_LONG(args, 7);
+        permittedCapabilities = args[5] | (int64_t) args[6] << 32;
+        effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
+    } else {
+        permittedCapabilities = effectiveCapabilities = 0;
+    }
+
+    if (!gDvm.zygote) {
+        dvmThrowIllegalStateException(
+            "VM instance not started with -Xzygote");
+
+        return -1;
+    }
+
+    if (!dvmGcPreZygoteFork()) {
+        LOGE("pre-fork heap failed");
+        dvmAbort();
+    }
+
+    setSignalHandler();
+
+    dvmDumpLoaderStats("zygote");
+    pid = fork();
+
+    if (pid == 0) {
+        int err;
+        /* The child process */
+
+#ifdef HAVE_ANDROID_OS
+        extern int gMallocLeakZygoteChild;
+        gMallocLeakZygoteChild = 1;
+
+        /* keep caps across UID change, unless we're staying root */
+        if (uid != 0) {
+            err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+            if (err < 0) {
+                LOGE("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
+                dvmAbort();
+            }
+        }
+
+#endif /* HAVE_ANDROID_OS */
+
+        err = setgroupsIntarray(gids);
+
+        if (err < 0) {
+            LOGE("cannot setgroups(): %s", strerror(errno));
+            dvmAbort();
+        }
+
+        err = setrlimitsFromArray(rlimits);
+
+        if (err < 0) {
+            LOGE("cannot setrlimit(): %s", strerror(errno));
+            dvmAbort();
+        }
+
+        err = setgid(gid);
+        if (err < 0) {
+            LOGE("cannot setgid(%d): %s", gid, strerror(errno));
+            dvmAbort();
+        }
+
+        err = setuid(uid);
+        if (err < 0) {
+            LOGE("cannot setuid(%d): %s", uid, strerror(errno));
+            dvmAbort();
+        }
+
+        int current = personality(0xffffFFFF);
+        int success = personality((ADDR_NO_RANDOMIZE | current));
+        if (success == -1) {
+          LOGW("Personality switch failed. current=%d error=%d\n", current, errno);
+        }
+
+        err = setCapabilities(permittedCapabilities, effectiveCapabilities);
+        if (err != 0) {
+            LOGE("cannot set capabilities (%llx,%llx): %s",
+                permittedCapabilities, effectiveCapabilities, strerror(err));
+            dvmAbort();
+        }
+
+        /*
+         * Our system thread ID has changed.  Get the new one.
+         */
+        Thread* thread = dvmThreadSelf();
+        thread->systemTid = dvmGetSysThreadId();
+
+        /* configure additional debug options */
+        enableDebugFeatures(debugFlags);
+
+        unsetSignalHandler();
+        gDvm.zygote = false;
+        if (!dvmInitAfterZygote()) {
+            LOGE("error in post-zygote initialization");
+            dvmAbort();
+        }
+    } else if (pid > 0) {
+        /* the parent process */
+    }
+
+    return pid;
+}
+
+/* native public static int forkAndSpecialize(int uid, int gid,
+ *     int[] gids, int debugFlags);
+ */
+static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
+    JValue* pResult)
+{
+    pid_t pid;
+
+    pid = forkAndSpecializeCommon(args, false);
+
+    RETURN_INT(pid);
+}
+
+/* native public static int forkSystemServer(int uid, int gid,
+ *     int[] gids, int debugFlags, long permittedCapabilities,
+ *     long effectiveCapabilities);
+ */
+static void Dalvik_dalvik_system_Zygote_forkSystemServer(
+        const u4* args, JValue* pResult)
+{
+    pid_t pid;
+    pid = forkAndSpecializeCommon(args, true);
+
+    /* The zygote process checks whether the child process has died or not. */
+    if (pid > 0) {
+        int status;
+
+        LOGI("System server process %d has been created", pid);
+        gDvm.systemServerPid = pid;
+        /* There is a slight window that the system server process has crashed
+         * but it went unnoticed because we haven't published its pid yet. So
+         * we recheck here just to make sure that all is well.
+         */
+        if (waitpid(pid, &status, WNOHANG) == pid) {
+            LOGE("System server process %d has died. Restarting Zygote!", pid);
+            kill(getpid(), SIGKILL);
+        }
+    }
+    RETURN_INT(pid);
+}
+
+/* native private static void nativeExecShell(String command);
+ */
+static void Dalvik_dalvik_system_Zygote_execShell(
+        const u4* args, JValue* pResult)
+{
+    StringObject* command = (StringObject*)args[0];
+
+    const char *argp[] = {_PATH_BSHELL, "-c", NULL, NULL};
+    argp[2] = dvmCreateCstrFromString(command);
+
+    LOGI("Exec: %s %s %s", argp[0], argp[1], argp[2]);
+
+    execv(_PATH_BSHELL, (char**)argp);
+    exit(127);
+}
+
+const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
+    { "nativeFork", "()I",
+      Dalvik_dalvik_system_Zygote_fork },
+    { "nativeForkAndSpecialize", "(II[II[[I)I",
+      Dalvik_dalvik_system_Zygote_forkAndSpecialize },
+    { "nativeForkSystemServer", "(II[II[[IJJ)I",
+      Dalvik_dalvik_system_Zygote_forkSystemServer },
+    { "nativeExecShell", "(Ljava/lang/String;)V",
+      Dalvik_dalvik_system_Zygote_execShell },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Class.cpp b/vm/native/java_lang_Class.cpp
new file mode 100644
index 0000000..2c939be
--- /dev/null
+++ b/vm/native/java_lang_Class.cpp
@@ -0,0 +1,828 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.Class
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * native public boolean desiredAssertionStatus()
+ *
+ * Determine the class-init-time assertion status of a class.  This is
+ * called from <clinit> in javac-generated classes that use the Java
+ * programming language "assert" keyword.
+ */
+static void Dalvik_java_lang_Class_desiredAssertionStatus(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* thisPtr = (ClassObject*) args[0];
+    char* className = dvmDescriptorToName(thisPtr->descriptor);
+    int i;
+    bool enable = false;
+
+    /*
+     * Run through the list of arguments specified on the command line.  The
+     * last matching argument takes precedence.
+     */
+    for (i = 0; i < gDvm.assertionCtrlCount; i++) {
+        const AssertionControl* pCtrl = &gDvm.assertionCtrl[i];
+
+        if (pCtrl->isPackage) {
+            /*
+             * Given "dalvik/system/Debug" or "MyStuff", compute the
+             * length of the package portion of the class name string.
+             *
+             * Unlike most package operations, we allow matching on
+             * "sub-packages", so "dalvik..." will match "dalvik.Foo"
+             * and "dalvik.system.Foo".
+             *
+             * The pkgOrClass string looks like "dalvik/system/", i.e. it still
+             * has the terminating slash, so we can be sure we're comparing
+             * against full package component names.
+             */
+            const char* lastSlash;
+            int pkgLen;
+
+            lastSlash = strrchr(className, '/');
+            if (lastSlash == NULL) {
+                pkgLen = 0;
+            } else {
+                pkgLen = lastSlash - className +1;
+            }
+
+            if (pCtrl->pkgOrClassLen > pkgLen ||
+                memcmp(pCtrl->pkgOrClass, className, pCtrl->pkgOrClassLen) != 0)
+            {
+                LOGV("ASRT: pkg no match: '%s'(%d) vs '%s'",
+                    className, pkgLen, pCtrl->pkgOrClass);
+            } else {
+                LOGV("ASRT: pkg match: '%s'(%d) vs '%s' --> %d",
+                    className, pkgLen, pCtrl->pkgOrClass, pCtrl->enable);
+                enable = pCtrl->enable;
+            }
+        } else {
+            /*
+             * "pkgOrClass" holds a fully-qualified class name, converted from
+             * dot-form to slash-form.  An empty string means all classes.
+             */
+            if (pCtrl->pkgOrClass == NULL) {
+                /* -esa/-dsa; see if class is a "system" class */
+                if (strncmp(className, "java/", 5) != 0) {
+                    LOGV("ASRT: sys no match: '%s'", className);
+                } else {
+                    LOGV("ASRT: sys match: '%s' --> %d",
+                        className, pCtrl->enable);
+                    enable = pCtrl->enable;
+                }
+            } else if (*pCtrl->pkgOrClass == '\0') {
+                LOGV("ASRT: class all: '%s' --> %d",
+                    className, pCtrl->enable);
+                enable = pCtrl->enable;
+            } else {
+                if (strcmp(pCtrl->pkgOrClass, className) != 0) {
+                    LOGV("ASRT: cls no match: '%s' vs '%s'",
+                        className, pCtrl->pkgOrClass);
+                } else {
+                    LOGV("ASRT: cls match: '%s' vs '%s' --> %d",
+                        className, pCtrl->pkgOrClass, pCtrl->enable);
+                    enable = pCtrl->enable;
+                }
+            }
+        }
+    }
+
+    free(className);
+    RETURN_INT(enable);
+}
+
+/*
+ * static public Class<?> classForName(String name, boolean initialize,
+ *     ClassLoader loader)
+ *
+ * Return the Class object associated with the class or interface with
+ * the specified name.
+ *
+ * "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
+ */
+static void Dalvik_java_lang_Class_classForName(const u4* args, JValue* pResult)
+{
+    StringObject* nameObj = (StringObject*) args[0];
+    bool initialize = (args[1] != 0);
+    Object* loader = (Object*) args[2];
+
+    RETURN_PTR(dvmFindClassByName(nameObj, loader, initialize));
+}
+
+/*
+ * static private ClassLoader getClassLoader(Class clazz)
+ *
+ * Return the class' defining class loader.
+ */
+static void Dalvik_java_lang_Class_getClassLoader(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    RETURN_PTR(clazz->classLoader);
+}
+
+/*
+ * public Class<?> getComponentType()
+ *
+ * If this is an array type, return the class of the elements; otherwise
+ * return NULL.
+ */
+static void Dalvik_java_lang_Class_getComponentType(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* thisPtr = (ClassObject*) args[0];
+
+    if (!dvmIsArrayClass(thisPtr))
+        RETURN_PTR(NULL);
+
+    /*
+     * We can't just return thisPtr->elementClass, because that gives
+     * us the base type (e.g. X[][][] returns X).  If this is a multi-
+     * dimensional array, we have to do the lookup by name.
+     */
+    if (thisPtr->descriptor[1] == '[')
+        RETURN_PTR(dvmFindArrayClass(&thisPtr->descriptor[1],
+                   thisPtr->classLoader));
+    else
+        RETURN_PTR(thisPtr->elementClass);
+}
+
+/*
+ * private static Class<?>[] getDeclaredClasses(Class<?> clazz,
+ *     boolean publicOnly)
+ *
+ * Return an array with the classes that are declared by the specified class.
+ * If "publicOnly" is set, we strip out any classes that don't have "public"
+ * access.
+ */
+static void Dalvik_java_lang_Class_getDeclaredClasses(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    bool publicOnly = (args[1] != 0);
+    ArrayObject* classes;
+
+    classes = dvmGetDeclaredClasses(clazz);
+    if (classes == NULL) {
+        if (!dvmCheckException(dvmThreadSelf())) {
+            /* empty list, so create a zero-length array */
+            classes = dvmAllocArrayByClass(gDvm.classJavaLangClassArray,
+                        0, ALLOC_DEFAULT);
+        }
+    } else if (publicOnly) {
+        u4 count, newIdx, publicCount = 0;
+        ClassObject** pSource = (ClassObject**)(void*)classes->contents;
+        u4 length = classes->length;
+
+        /* count up public classes */
+        for (count = 0; count < length; count++) {
+            if (dvmIsPublicClass(pSource[count]))
+                publicCount++;
+        }
+
+        /* create a new array to hold them */
+        ArrayObject* newClasses;
+        newClasses = dvmAllocArrayByClass(gDvm.classJavaLangClassArray,
+                        publicCount, ALLOC_DEFAULT);
+
+        /* copy them over */
+        for (count = newIdx = 0; count < length; count++) {
+            if (dvmIsPublicClass(pSource[count])) {
+                dvmSetObjectArrayElement(newClasses, newIdx,
+                                         (Object *)pSource[count]);
+                newIdx++;
+            }
+        }
+        assert(newIdx == publicCount);
+        dvmReleaseTrackedAlloc((Object*) classes, NULL);
+        classes = newClasses;
+    }
+
+    dvmReleaseTrackedAlloc((Object*) classes, NULL);
+    RETURN_PTR(classes);
+}
+
+/*
+ * static Constructor[] getDeclaredConstructors(Class clazz, boolean publicOnly)
+ *     throws SecurityException
+ */
+static void Dalvik_java_lang_Class_getDeclaredConstructors(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    bool publicOnly = (args[1] != 0);
+    ArrayObject* constructors;
+
+    constructors = dvmGetDeclaredConstructors(clazz, publicOnly);
+    dvmReleaseTrackedAlloc((Object*) constructors, NULL);
+
+    RETURN_PTR(constructors);
+}
+
+/*
+ * static Field[] getDeclaredFields(Class klass, boolean publicOnly)
+ */
+static void Dalvik_java_lang_Class_getDeclaredFields(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    bool publicOnly = (args[1] != 0);
+    ArrayObject* fields;
+
+    fields = dvmGetDeclaredFields(clazz, publicOnly);
+    dvmReleaseTrackedAlloc((Object*) fields, NULL);
+
+    RETURN_PTR(fields);
+}
+
+/*
+ * static Field getDeclaredField(Class klass, String name)
+ */
+static void Dalvik_java_lang_Class_getDeclaredField(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    StringObject* nameObj = (StringObject*) args[1];
+    Object* fieldObj = dvmGetDeclaredField(clazz, nameObj);
+    dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
+    RETURN_PTR(fieldObj);
+}
+
+/*
+ * static Method[] getDeclaredMethods(Class clazz, boolean publicOnly)
+ *     throws SecurityException
+ */
+static void Dalvik_java_lang_Class_getDeclaredMethods(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    bool publicOnly = (args[1] != 0);
+    ArrayObject* methods;
+
+    methods = dvmGetDeclaredMethods(clazz, publicOnly);
+    dvmReleaseTrackedAlloc((Object*) methods, NULL);
+
+    RETURN_PTR(methods);
+}
+
+/*
+ * static native Member getDeclaredConstructorOrMethod(
+ *     Class clazz, String name, Class[] args);
+ */
+static void Dalvik_java_lang_Class_getDeclaredConstructorOrMethod(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    StringObject* nameObj = (StringObject*) args[1];
+    ArrayObject* methodArgs = (ArrayObject*) args[2];
+
+    Object* methodObj;
+
+    methodObj = dvmGetDeclaredConstructorOrMethod(clazz, nameObj, methodArgs);
+    dvmReleaseTrackedAlloc(methodObj, NULL);
+
+    RETURN_PTR(methodObj);
+}
+
+/*
+ * Class[] getInterfaces()
+ */
+static void Dalvik_java_lang_Class_getInterfaces(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    ArrayObject* interfaces;
+
+    interfaces = dvmGetInterfaces(clazz);
+    dvmReleaseTrackedAlloc((Object*) interfaces, NULL);
+
+    RETURN_PTR(interfaces);
+}
+
+/*
+ * private static int getModifiers(Class klass, boolean
+ *     ignoreInnerClassesAttrib)
+ *
+ * Return the class' modifier flags.  If "ignoreInnerClassesAttrib" is false,
+ * and this is an inner class, we return the access flags from the inner class
+ * attribute.
+ */
+static void Dalvik_java_lang_Class_getModifiers(const u4* args, JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    bool ignoreInner = args[1];
+    u4 accessFlags;
+
+    accessFlags = clazz->accessFlags & JAVA_FLAGS_MASK;
+
+    if (!ignoreInner) {
+        /* see if we have an InnerClass annotation with flags in it */
+        StringObject* className = NULL;
+        int innerFlags;
+
+        if (dvmGetInnerClass(clazz, &className, &innerFlags))
+            accessFlags = innerFlags & JAVA_FLAGS_MASK;
+
+        dvmReleaseTrackedAlloc((Object*) className, NULL);
+    }
+
+    RETURN_INT(accessFlags);
+}
+
+/*
+ * private native String getNameNative()
+ *
+ * Return the class' name. The exact format is bizarre, but it's the specified
+ * behavior: keywords for primitive types, regular "[I" form for primitive
+ * arrays (so "int" but "[I"), and arrays of reference types written
+ * between "L" and ";" but with dots rather than slashes (so "java.lang.String"
+ * but "[Ljava.lang.String;"). Madness.
+ */
+static void Dalvik_java_lang_Class_getNameNative(const u4* args, JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    const char* descriptor = clazz->descriptor;
+    StringObject* nameObj;
+
+    if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
+        /*
+         * The descriptor indicates that this is the class for
+         * a primitive type; special-case the return value.
+         */
+        const char* name;
+        switch (descriptor[0]) {
+            case 'Z': name = "boolean"; break;
+            case 'B': name = "byte";    break;
+            case 'C': name = "char";    break;
+            case 'S': name = "short";   break;
+            case 'I': name = "int";     break;
+            case 'J': name = "long";    break;
+            case 'F': name = "float";   break;
+            case 'D': name = "double";  break;
+            case 'V': name = "void";    break;
+            default: {
+                LOGE("Unknown primitive type '%c'", descriptor[0]);
+                assert(false);
+                RETURN_PTR(NULL);
+            }
+        }
+
+        nameObj = dvmCreateStringFromCstr(name);
+    } else {
+        /*
+         * Convert the UTF-8 name to a java.lang.String. The
+         * name must use '.' to separate package components.
+         *
+         * TODO: this could be more efficient. Consider a custom
+         * conversion function here that walks the string once and
+         * avoids the allocation for the common case (name less than,
+         * say, 128 bytes).
+         */
+        char* dotName = dvmDescriptorToDot(clazz->descriptor);
+        nameObj = dvmCreateStringFromCstr(dotName);
+        free(dotName);
+    }
+
+    dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
+    RETURN_PTR(nameObj);
+}
+
+/*
+ * Return the superclass for instances of this class.
+ *
+ * If the class represents a java/lang/Object, an interface, a primitive
+ * type, or void (which *is* a primitive type??), return NULL.
+ *
+ * For an array, return the java/lang/Object ClassObject.
+ */
+static void Dalvik_java_lang_Class_getSuperclass(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    if (dvmIsPrimitiveClass(clazz) || dvmIsInterfaceClass(clazz))
+        RETURN_PTR(NULL);
+    else
+        RETURN_PTR(clazz->super);
+}
+
+/*
+ * public boolean isAssignableFrom(Class<?> cls)
+ *
+ * Determine if this class is either the same as, or is a superclass or
+ * superinterface of, the class specified in the "cls" parameter.
+ */
+static void Dalvik_java_lang_Class_isAssignableFrom(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* thisPtr = (ClassObject*) args[0];
+    ClassObject* testClass = (ClassObject*) args[1];
+
+    if (testClass == NULL) {
+        dvmThrowNullPointerException("cls == null");
+        RETURN_INT(false);
+    }
+    RETURN_INT(dvmInstanceof(testClass, thisPtr));
+}
+
+/*
+ * public boolean isInstance(Object o)
+ *
+ * Dynamic equivalent of Java programming language "instanceof".
+ */
+static void Dalvik_java_lang_Class_isInstance(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* thisPtr = (ClassObject*) args[0];
+    Object* testObj = (Object*) args[1];
+
+    if (testObj == NULL)
+        RETURN_INT(false);
+    RETURN_INT(dvmInstanceof(testObj->clazz, thisPtr));
+}
+
+/*
+ * public boolean isInterface()
+ */
+static void Dalvik_java_lang_Class_isInterface(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* thisPtr = (ClassObject*) args[0];
+
+    RETURN_INT(dvmIsInterfaceClass(thisPtr));
+}
+
+/*
+ * public boolean isPrimitive()
+ */
+static void Dalvik_java_lang_Class_isPrimitive(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* thisPtr = (ClassObject*) args[0];
+
+    RETURN_INT(dvmIsPrimitiveClass(thisPtr));
+}
+
+/*
+ * public T newInstance() throws InstantiationException, IllegalAccessException
+ *
+ * Create a new instance of this class.
+ */
+static void Dalvik_java_lang_Class_newInstance(const u4* args, JValue* pResult)
+{
+    Thread* self = dvmThreadSelf();
+    ClassObject* clazz = (ClassObject*) args[0];
+    Method* init;
+    Object* newObj;
+
+    /* can't instantiate these */
+    if (dvmIsPrimitiveClass(clazz) || dvmIsInterfaceClass(clazz)
+        || dvmIsArrayClass(clazz) || dvmIsAbstractClass(clazz))
+    {
+        LOGD("newInstance failed: p%d i%d [%d a%d",
+            dvmIsPrimitiveClass(clazz), dvmIsInterfaceClass(clazz),
+            dvmIsArrayClass(clazz), dvmIsAbstractClass(clazz));
+        dvmThrowInstantiationException(clazz, NULL);
+        RETURN_VOID();
+    }
+
+    /* initialize the class if it hasn't been already */
+    if (!dvmIsClassInitialized(clazz)) {
+        if (!dvmInitClass(clazz)) {
+            LOGW("Class init failed in newInstance call (%s)",
+                clazz->descriptor);
+            assert(dvmCheckException(self));
+            RETURN_VOID();
+        }
+    }
+
+    /* find the "nullary" constructor */
+    init = dvmFindDirectMethodByDescriptor(clazz, "<init>", "()V");
+    if (init == NULL) {
+        /* common cause: secret "this" arg on non-static inner class ctor */
+        LOGD("newInstance failed: no <init>()");
+        dvmThrowInstantiationException(clazz, "no empty constructor");
+        RETURN_VOID();
+    }
+
+    /*
+     * Verify access from the call site.
+     *
+     * First, make sure the method invoking Class.newInstance() has permission
+     * to access the class.
+     *
+     * Second, make sure it has permission to invoke the constructor.  The
+     * constructor must be public or, if the caller is in the same package,
+     * have package scope.
+     */
+    ClassObject* callerClass = dvmGetCaller2Class(self->interpSave.curFrame);
+
+    if (!dvmCheckClassAccess(callerClass, clazz)) {
+        LOGD("newInstance failed: %s not accessible to %s",
+            clazz->descriptor, callerClass->descriptor);
+        dvmThrowIllegalAccessException("access to class not allowed");
+        RETURN_VOID();
+    }
+    if (!dvmCheckMethodAccess(callerClass, init)) {
+        LOGD("newInstance failed: %s.<init>() not accessible to %s",
+            clazz->descriptor, callerClass->descriptor);
+        dvmThrowIllegalAccessException("access to constructor not allowed");
+        RETURN_VOID();
+    }
+
+    newObj = dvmAllocObject(clazz, ALLOC_DEFAULT);
+    JValue unused;
+
+    /* invoke constructor; unlike reflection calls, we don't wrap exceptions */
+    dvmCallMethod(self, init, newObj, &unused);
+    dvmReleaseTrackedAlloc(newObj, NULL);
+
+    RETURN_PTR(newObj);
+}
+
+/*
+ * private Object[] getSignatureAnnotation()
+ *
+ * Returns the signature annotation array.
+ */
+static void Dalvik_java_lang_Class_getSignatureAnnotation(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    ArrayObject* arr = dvmGetClassSignatureAnnotation(clazz);
+
+    dvmReleaseTrackedAlloc((Object*) arr, NULL);
+    RETURN_PTR(arr);
+}
+
+/*
+ * public Class getDeclaringClass()
+ *
+ * Get the class that encloses this class (if any).
+ */
+static void Dalvik_java_lang_Class_getDeclaringClass(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    ClassObject* enclosing = dvmGetDeclaringClass(clazz);
+    dvmReleaseTrackedAlloc((Object*) enclosing, NULL);
+    RETURN_PTR(enclosing);
+}
+
+/*
+ * public Class getEnclosingClass()
+ *
+ * Get the class that encloses this class (if any).
+ */
+static void Dalvik_java_lang_Class_getEnclosingClass(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    ClassObject* enclosing = dvmGetEnclosingClass(clazz);
+    dvmReleaseTrackedAlloc((Object*) enclosing, NULL);
+    RETURN_PTR(enclosing);
+}
+
+/*
+ * public Constructor getEnclosingConstructor()
+ *
+ * Get the constructor that encloses this class (if any).
+ */
+static void Dalvik_java_lang_Class_getEnclosingConstructor(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    Object* enclosing = dvmGetEnclosingMethod(clazz);
+    if (enclosing != NULL) {
+        dvmReleaseTrackedAlloc(enclosing, NULL);
+        if (enclosing->clazz == gDvm.classJavaLangReflectConstructor) {
+            RETURN_PTR(enclosing);
+        }
+        assert(enclosing->clazz == gDvm.classJavaLangReflectMethod);
+    }
+    RETURN_PTR(NULL);
+}
+
+/*
+ * public Method getEnclosingMethod()
+ *
+ * Get the method that encloses this class (if any).
+ */
+static void Dalvik_java_lang_Class_getEnclosingMethod(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    Object* enclosing = dvmGetEnclosingMethod(clazz);
+    if (enclosing != NULL) {
+        dvmReleaseTrackedAlloc(enclosing, NULL);
+        if (enclosing->clazz == gDvm.classJavaLangReflectMethod) {
+            RETURN_PTR(enclosing);
+        }
+        assert(enclosing->clazz == gDvm.classJavaLangReflectConstructor);
+    }
+    RETURN_PTR(NULL);
+}
+
+#if 0
+static void Dalvik_java_lang_Class_getGenericInterfaces(const u4* args,
+    JValue* pResult)
+{
+    dvmThrowUnsupportedOperationException("native method not implemented");
+
+    RETURN_PTR(NULL);
+}
+
+static void Dalvik_java_lang_Class_getGenericSuperclass(const u4* args,
+    JValue* pResult)
+{
+    dvmThrowUnsupportedOperationException("native method not implemented");
+
+    RETURN_PTR(NULL);
+}
+
+static void Dalvik_java_lang_Class_getTypeParameters(const u4* args,
+    JValue* pResult)
+{
+    dvmThrowUnsupportedOperationException("native method not implemented");
+
+    RETURN_PTR(NULL);
+}
+#endif
+
+/*
+ * public boolean isAnonymousClass()
+ *
+ * Returns true if this is an "anonymous" class.
+ */
+static void Dalvik_java_lang_Class_isAnonymousClass(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    StringObject* className = NULL;
+    int accessFlags;
+
+    /*
+     * If this has an InnerClass annotation, pull it out.  Lack of the
+     * annotation, or an annotation with a NULL class name, indicates
+     * that this is an anonymous inner class.
+     */
+    if (!dvmGetInnerClass(clazz, &className, &accessFlags))
+        RETURN_BOOLEAN(false);
+
+    dvmReleaseTrackedAlloc((Object*) className, NULL);
+    RETURN_BOOLEAN(className == NULL);
+}
+
+/*
+ * private Annotation[] getDeclaredAnnotations()
+ *
+ * Return the annotations declared on this class.
+ */
+static void Dalvik_java_lang_Class_getDeclaredAnnotations(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+
+    ArrayObject* annos = dvmGetClassAnnotations(clazz);
+    dvmReleaseTrackedAlloc((Object*) annos, NULL);
+    RETURN_PTR(annos);
+}
+
+/*
+ * private Annotation getDeclaredAnnotation(Class annotationClass)
+ */
+static void Dalvik_java_lang_Class_getDeclaredAnnotation(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    ClassObject* annotationClazz = (ClassObject*) args[1];
+
+    RETURN_PTR(dvmGetClassAnnotation(clazz, annotationClazz));
+}
+
+/*
+ * private boolean isDeclaredAnnotationPresent(Class annotationClass);
+ */
+static void Dalvik_java_lang_Class_isDeclaredAnnotationPresent(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    ClassObject* annotationClazz = (ClassObject*) args[1];
+
+    RETURN_BOOLEAN(dvmIsClassAnnotationPresent(clazz, annotationClazz));
+}
+
+/*
+ * public String getInnerClassName()
+ *
+ * Returns the simple name of a member class or local class, or null otherwise.
+ */
+static void Dalvik_java_lang_Class_getInnerClassName(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    StringObject* nameObj;
+    int flags;
+
+    if (dvmGetInnerClass(clazz, &nameObj, &flags)) {
+        dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
+        RETURN_PTR(nameObj);
+    } else {
+        RETURN_PTR(NULL);
+    }
+}
+
+const DalvikNativeMethod dvm_java_lang_Class[] = {
+    { "desiredAssertionStatus", "()Z",
+        Dalvik_java_lang_Class_desiredAssertionStatus },
+    { "classForName",           "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
+        Dalvik_java_lang_Class_classForName },
+    { "getClassLoader",         "(Ljava/lang/Class;)Ljava/lang/ClassLoader;",
+        Dalvik_java_lang_Class_getClassLoader },
+    { "getComponentType",       "()Ljava/lang/Class;",
+        Dalvik_java_lang_Class_getComponentType },
+    { "getSignatureAnnotation",  "()[Ljava/lang/Object;",
+        Dalvik_java_lang_Class_getSignatureAnnotation },
+    { "getDeclaredClasses",     "(Ljava/lang/Class;Z)[Ljava/lang/Class;",
+        Dalvik_java_lang_Class_getDeclaredClasses },
+    { "getDeclaredConstructors", "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;",
+        Dalvik_java_lang_Class_getDeclaredConstructors },
+    { "getDeclaredFields",      "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;",
+        Dalvik_java_lang_Class_getDeclaredFields },
+    { "getDeclaredMethods",     "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;",
+        Dalvik_java_lang_Class_getDeclaredMethods },
+    { "getDeclaredField",      "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;",
+        Dalvik_java_lang_Class_getDeclaredField },
+    { "getDeclaredConstructorOrMethod", "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;",
+        Dalvik_java_lang_Class_getDeclaredConstructorOrMethod },
+    { "getInterfaces",          "()[Ljava/lang/Class;",
+        Dalvik_java_lang_Class_getInterfaces },
+    { "getModifiers",           "(Ljava/lang/Class;Z)I",
+        Dalvik_java_lang_Class_getModifiers },
+    { "getNameNative",                "()Ljava/lang/String;",
+        Dalvik_java_lang_Class_getNameNative },
+    { "getSuperclass",          "()Ljava/lang/Class;",
+        Dalvik_java_lang_Class_getSuperclass },
+    { "isAssignableFrom",       "(Ljava/lang/Class;)Z",
+        Dalvik_java_lang_Class_isAssignableFrom },
+    { "isInstance",             "(Ljava/lang/Object;)Z",
+        Dalvik_java_lang_Class_isInstance },
+    { "isInterface",            "()Z",
+        Dalvik_java_lang_Class_isInterface },
+    { "isPrimitive",            "()Z",
+        Dalvik_java_lang_Class_isPrimitive },
+    { "newInstanceImpl",        "()Ljava/lang/Object;",
+        Dalvik_java_lang_Class_newInstance },
+    { "getDeclaringClass",      "()Ljava/lang/Class;",
+        Dalvik_java_lang_Class_getDeclaringClass },
+    { "getEnclosingClass",      "()Ljava/lang/Class;",
+        Dalvik_java_lang_Class_getEnclosingClass },
+    { "getEnclosingConstructor", "()Ljava/lang/reflect/Constructor;",
+        Dalvik_java_lang_Class_getEnclosingConstructor },
+    { "getEnclosingMethod",     "()Ljava/lang/reflect/Method;",
+        Dalvik_java_lang_Class_getEnclosingMethod },
+#if 0
+    { "getGenericInterfaces",   "()[Ljava/lang/reflect/Type;",
+        Dalvik_java_lang_Class_getGenericInterfaces },
+    { "getGenericSuperclass",   "()Ljava/lang/reflect/Type;",
+        Dalvik_java_lang_Class_getGenericSuperclass },
+    { "getTypeParameters",      "()Ljava/lang/reflect/TypeVariable;",
+        Dalvik_java_lang_Class_getTypeParameters },
+#endif
+    { "isAnonymousClass",       "()Z",
+        Dalvik_java_lang_Class_isAnonymousClass },
+    { "getDeclaredAnnotations", "()[Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_Class_getDeclaredAnnotations },
+    { "getDeclaredAnnotation", "(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_Class_getDeclaredAnnotation },
+    { "isDeclaredAnnotationPresent", "(Ljava/lang/Class;)Z",
+        Dalvik_java_lang_Class_isDeclaredAnnotationPresent },
+    { "getInnerClassName",       "()Ljava/lang/String;",
+        Dalvik_java_lang_Class_getInnerClassName },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Double.cpp b/vm/native/java_lang_Double.cpp
new file mode 100644
index 0000000..b019c8c
--- /dev/null
+++ b/vm/native/java_lang_Double.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 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 "native/InternalNativePriv.h"
+
+static void Double_doubleToLongBits(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangDouble_doubleToLongBits);
+}
+
+static void Double_doubleToRawLongBits(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangDouble_doubleToRawLongBits);
+}
+
+static void Double_longBitsToDouble(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangDouble_longBitsToDouble);
+}
+
+const DalvikNativeMethod dvm_java_lang_Double[] = {
+    { "doubleToLongBits",    "(D)J", Double_doubleToLongBits },
+    { "doubleToRawLongBits", "(D)J", Double_doubleToRawLongBits },
+    { "longBitsToDouble",    "(J)D", Double_longBitsToDouble },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Float.cpp b/vm/native/java_lang_Float.cpp
new file mode 100644
index 0000000..e99e4aa
--- /dev/null
+++ b/vm/native/java_lang_Float.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 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 "native/InternalNativePriv.h"
+
+static void Float_floatToIntBits(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangFloat_floatToIntBits);
+}
+
+static void Float_floatToRawIntBits(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangFloat_floatToRawIntBits);
+}
+
+static void Float_intBitsToFloat(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangFloat_intBitsToFloat);
+}
+
+const DalvikNativeMethod dvm_java_lang_Float[] = {
+    { "floatToIntBits",    "(F)I", Float_floatToIntBits },
+    { "floatToRawIntBits", "(F)I", Float_floatToRawIntBits },
+    { "intBitsToFloat",    "(I)F", Float_intBitsToFloat },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Math.cpp b/vm/native/java_lang_Math.cpp
new file mode 100644
index 0000000..7c17242
--- /dev/null
+++ b/vm/native/java_lang_Math.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 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 "native/InternalNativePriv.h"
+
+static void Math_absD(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_abs_double);
+}
+
+static void Math_absF(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_abs_float);
+}
+
+static void Math_absI(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_abs_int);
+}
+
+static void Math_absJ(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_abs_long);
+}
+
+static void Math_cos(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_cos);
+}
+
+static void Math_maxI(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_max_int);
+}
+
+static void Math_minI(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_min_int);
+}
+
+static void Math_sin(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_sin);
+}
+
+static void Math_sqrt(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangMath_sqrt);
+}
+
+const DalvikNativeMethod dvm_java_lang_Math[] = {
+    { "abs",  "(D)D",  Math_absD },
+    { "abs",  "(F)F",  Math_absF },
+    { "abs",  "(I)I",  Math_absI },
+    { "abs",  "(J)J",  Math_absJ },
+    { "cos",  "(D)D",  Math_cos },
+    { "max",  "(II)I", Math_maxI },
+    { "min",  "(II)I", Math_minI },
+    { "sin",  "(D)D",  Math_sin },
+    { "sqrt", "(D)D",  Math_sqrt },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Object.cpp b/vm/native/java_lang_Object.cpp
new file mode 100644
index 0000000..12f701f
--- /dev/null
+++ b/vm/native/java_lang_Object.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.Object
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private Object internalClone()
+ *
+ * Implements most of Object.clone().
+ */
+static void Dalvik_java_lang_Object_internalClone(const u4* args,
+    JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    Object* clone = dvmCloneObject(thisPtr, ALLOC_DONT_TRACK);
+
+    RETURN_PTR(clone);
+}
+
+/*
+ * public int hashCode()
+ */
+static void Dalvik_java_lang_Object_hashCode(const u4* args, JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    RETURN_INT(dvmIdentityHashCode(thisPtr));
+}
+
+/*
+ * public Class getClass()
+ */
+static void Dalvik_java_lang_Object_getClass(const u4* args, JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+
+    RETURN_PTR(thisPtr->clazz);
+}
+
+/*
+ * public void notify()
+ *
+ * NOTE: we declare this as a full DalvikBridgeFunc, rather than a
+ * DalvikNativeFunc, because we really want to avoid the "self" lookup.
+ */
+static void Dalvik_java_lang_Object_notify(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    Object* thisPtr = (Object*) args[0];
+
+    dvmObjectNotify(self, thisPtr);
+    RETURN_VOID();
+}
+
+/*
+ * public void notifyAll()
+ */
+static void Dalvik_java_lang_Object_notifyAll(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    Object* thisPtr = (Object*) args[0];
+
+    dvmObjectNotifyAll(self, thisPtr);
+    RETURN_VOID();
+}
+
+/*
+ * public void wait(long ms, int ns) throws InterruptedException
+ */
+static void Dalvik_java_lang_Object_wait(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    Object* thisPtr = (Object*) args[0];
+
+    dvmObjectWait(self, thisPtr, GET_ARG_LONG(args,1), (s4)args[3], true);
+    RETURN_VOID();
+}
+
+const DalvikNativeMethod dvm_java_lang_Object[] = {
+    { "internalClone",  "(Ljava/lang/Cloneable;)Ljava/lang/Object;",
+        Dalvik_java_lang_Object_internalClone },
+    { "hashCode",       "()I",
+        Dalvik_java_lang_Object_hashCode },
+    { "notify",         "()V",
+        (DalvikNativeFunc) Dalvik_java_lang_Object_notify },
+    { "notifyAll",      "()V",
+        (DalvikNativeFunc) Dalvik_java_lang_Object_notifyAll },
+    { "wait",           "(JI)V",
+        (DalvikNativeFunc) Dalvik_java_lang_Object_wait },
+    { "getClass",       "()Ljava/lang/Class;",
+        Dalvik_java_lang_Object_getClass },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Runtime.cpp b/vm/native/java_lang_Runtime.cpp
new file mode 100644
index 0000000..c09b840
--- /dev/null
+++ b/vm/native/java_lang_Runtime.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.Runtime
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+#include <unistd.h>
+#include <limits.h>
+
+/*
+ * public void gc()
+ *
+ * Initiate a gc.
+ */
+static void Dalvik_java_lang_Runtime_gc(const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    dvmCollectGarbage();
+    RETURN_VOID();
+}
+
+/*
+ * private static void nativeExit(int code, boolean isExit)
+ *
+ * Runtime.exit() calls this after doing shutdown processing.  Runtime.halt()
+ * uses this as well.
+ */
+static void Dalvik_java_lang_Runtime_nativeExit(const u4* args,
+    JValue* pResult)
+{
+    int status = args[0];
+    bool isExit = (args[1] != 0);
+
+    if (isExit && gDvm.exitHook != NULL) {
+        dvmChangeStatus(NULL, THREAD_NATIVE);
+        (*gDvm.exitHook)(status);     // not expected to return
+        dvmChangeStatus(NULL, THREAD_RUNNING);
+        LOGW("JNI exit hook returned");
+    }
+    LOGD("Calling exit(%d)", status);
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+    dvmCompilerDumpStats();
+#endif
+    exit(status);
+}
+
+/*
+ * static String nativeLoad(String filename, ClassLoader loader)
+ *
+ * Load the specified full path as a dynamic library filled with
+ * JNI-compatible methods. Returns null on success, or a failure
+ * message on failure.
+ */
+static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args,
+    JValue* pResult)
+{
+    StringObject* fileNameObj = (StringObject*) args[0];
+    Object* classLoader = (Object*) args[1];
+    char* fileName = NULL;
+    StringObject* result = NULL;
+    char* reason = NULL;
+    bool success;
+
+    assert(fileNameObj != NULL);
+    fileName = dvmCreateCstrFromString(fileNameObj);
+
+    success = dvmLoadNativeCode(fileName, classLoader, &reason);
+    if (!success) {
+        const char* msg = (reason != NULL) ? reason : "unknown failure";
+        result = dvmCreateStringFromCstr(msg);
+        dvmReleaseTrackedAlloc((Object*) result, NULL);
+    }
+
+    free(reason);
+    free(fileName);
+    RETURN_PTR(result);
+}
+
+/*
+ * public long maxMemory()
+ *
+ * Returns GC heap max memory in bytes.
+ */
+static void Dalvik_java_lang_Runtime_maxMemory(const u4* args, JValue* pResult)
+{
+    RETURN_LONG(dvmGetHeapDebugInfo(kVirtualHeapMaximumSize));
+}
+
+/*
+ * public long totalMemory()
+ *
+ * Returns GC heap total memory in bytes.
+ */
+static void Dalvik_java_lang_Runtime_totalMemory(const u4* args,
+    JValue* pResult)
+{
+    RETURN_LONG(dvmGetHeapDebugInfo(kVirtualHeapSize));
+}
+
+/*
+ * public long freeMemory()
+ *
+ * Returns GC heap free memory in bytes.
+ */
+static void Dalvik_java_lang_Runtime_freeMemory(const u4* args,
+    JValue* pResult)
+{
+    size_t size = dvmGetHeapDebugInfo(kVirtualHeapSize);
+    size_t allocated = dvmGetHeapDebugInfo(kVirtualHeapAllocated);
+    long long result = size - allocated;
+    if (result < 0) {
+        result = 0;
+    }
+    RETURN_LONG(result);
+}
+
+const DalvikNativeMethod dvm_java_lang_Runtime[] = {
+    { "freeMemory",          "()J",
+        Dalvik_java_lang_Runtime_freeMemory },
+    { "gc",                 "()V",
+        Dalvik_java_lang_Runtime_gc },
+    { "maxMemory",          "()J",
+        Dalvik_java_lang_Runtime_maxMemory },
+    { "nativeExit",         "(IZ)V",
+        Dalvik_java_lang_Runtime_nativeExit },
+    { "nativeLoad",         "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;",
+        Dalvik_java_lang_Runtime_nativeLoad },
+    { "totalMemory",          "()J",
+        Dalvik_java_lang_Runtime_totalMemory },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_String.cpp b/vm/native/java_lang_String.cpp
new file mode 100644
index 0000000..38f9e31
--- /dev/null
+++ b/vm/native/java_lang_String.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.String
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+static void String_charAt(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangString_charAt);
+}
+
+static void String_compareTo(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangString_compareTo);
+}
+
+static void String_equals(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangString_equals);
+}
+
+static void String_fastIndexOf(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangString_fastIndexOf_II);
+}
+
+static void String_intern(const u4* args, JValue* pResult)
+{
+    StringObject* str = (StringObject*) args[0];
+    StringObject* interned = dvmLookupInternedString(str);
+    RETURN_PTR(interned);
+}
+
+static void String_isEmpty(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangString_isEmpty);
+}
+
+static void String_length(const u4* args, JValue* pResult)
+{
+    MAKE_INTRINSIC_TRAMPOLINE(javaLangString_length);
+}
+
+const DalvikNativeMethod dvm_java_lang_String[] = {
+    { "charAt",      "(I)C",                  String_charAt },
+    { "compareTo",   "(Ljava/lang/String;)I", String_compareTo },
+    { "equals",      "(Ljava/lang/Object;)Z", String_equals },
+    { "fastIndexOf", "(II)I",                 String_fastIndexOf },
+    { "intern",      "()Ljava/lang/String;",  String_intern },
+    { "isEmpty",     "()Z",                   String_isEmpty },
+    { "length",      "()I",                   String_length },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_System.cpp b/vm/native/java_lang_System.cpp
new file mode 100644
index 0000000..99b917b
--- /dev/null
+++ b/vm/native/java_lang_System.cpp
@@ -0,0 +1,373 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.Class native methods
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+/*
+ * The VM makes guarantees about the atomicity of accesses to primitive
+ * variables.  These guarantees also apply to elements of arrays.
+ * In particular, 8-bit, 16-bit, and 32-bit accesses must be atomic and
+ * must not cause "word tearing".  Accesses to 64-bit array elements must
+ * either be atomic or treated as two 32-bit operations.  References are
+ * always read and written atomically, regardless of the number of bits
+ * used to represent them.
+ *
+ * We can't rely on standard libc functions like memcpy() and memmove()
+ * in our implementation of System.arraycopy(), because they may copy
+ * byte-by-byte (either for the full run or for "unaligned" parts at the
+ * start or end).  We need to use functions that guarantee 16-bit or 32-bit
+ * atomicity as appropriate.
+ *
+ * System.arraycopy() is heavily used, so having an efficient implementation
+ * is important.  The bionic libc provides a platform-optimized memory move
+ * function that should be used when possible.  If it's not available,
+ * the trivial "reference implementation" versions below can be used until
+ * a proper version can be written.
+ *
+ * For these functions, The caller must guarantee that dest/src are aligned
+ * appropriately for the element type, and that n is a multiple of the
+ * element size.
+ */
+#ifdef __BIONIC__
+/* always present in bionic libc */
+#define HAVE_MEMMOVE_WORDS
+#endif
+
+#ifdef HAVE_MEMMOVE_WORDS
+extern "C" void _memmove_words(void* dest, const void* src, size_t n);
+#define move16 _memmove_words
+#define move32 _memmove_words
+#else
+static void move16(void* dest, const void* src, size_t n)
+{
+    assert((((uintptr_t) dest | (uintptr_t) src | n) & 0x01) == 0);
+
+    uint16_t* d = (uint16_t*) dest;
+    const uint16_t* s = (uint16_t*) src;
+
+    n /= sizeof(uint16_t);
+
+    if (d < s) {
+        /* copy forward */
+        while (n--) {
+            *d++ = *s++;
+        }
+    } else {
+        /* copy backward */
+        d += n;
+        s += n;
+        while (n--) {
+            *--d = *--s;
+        }
+    }
+}
+
+static void move32(void* dest, const void* src, size_t n)
+{
+    assert((((uintptr_t) dest | (uintptr_t) src | n) & 0x03) == 0);
+
+    uint32_t* d = (uint32_t*) dest;
+    const uint32_t* s = (uint32_t*) src;
+
+    n /= sizeof(uint32_t);
+
+    if (d < s) {
+        /* copy forward */
+        while (n--) {
+            *d++ = *s++;
+        }
+    } else {
+        /* copy backward */
+        d += n;
+        s += n;
+        while (n--) {
+            *--d = *--s;
+        }
+    }
+}
+#endif /*HAVE_MEMMOVE_WORDS*/
+
+/*
+ * public static void arraycopy(Object src, int srcPos, Object dest,
+ *      int destPos, int length)
+ *
+ * The description of this function is long, and describes a multitude
+ * of checks and exceptions.
+ */
+static void Dalvik_java_lang_System_arraycopy(const u4* args, JValue* pResult)
+{
+    ArrayObject* srcArray = (ArrayObject*) args[0];
+    int srcPos = args[1];
+    ArrayObject* dstArray = (ArrayObject*) args[2];
+    int dstPos = args[3];
+    int length = args[4];
+
+    /* Check for null pointers. */
+    if (srcArray == NULL) {
+        dvmThrowNullPointerException("src == null");
+        RETURN_VOID();
+    }
+    if (dstArray == NULL) {
+        dvmThrowNullPointerException("dst == null");
+        RETURN_VOID();
+    }
+
+    /* Make sure source and destination are arrays. */
+    if (!dvmIsArray(srcArray)) {
+        dvmThrowArrayStoreExceptionNotArray(((Object*)srcArray)->clazz, "source");
+        RETURN_VOID();
+    }
+    if (!dvmIsArray(dstArray)) {
+        dvmThrowArrayStoreExceptionNotArray(((Object*)dstArray)->clazz, "destination");
+        RETURN_VOID();
+    }
+
+    /* avoid int overflow */
+    if (srcPos < 0 || dstPos < 0 || length < 0 ||
+        srcPos > (int) srcArray->length - length ||
+        dstPos > (int) dstArray->length - length)
+    {
+        dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
+            "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
+            srcArray->length, srcPos, dstArray->length, dstPos, length);
+        RETURN_VOID();
+    }
+
+    ClassObject* srcClass = srcArray->clazz;
+    ClassObject* dstClass = dstArray->clazz;
+    char srcType = srcClass->descriptor[1];
+    char dstType = dstClass->descriptor[1];
+
+    /*
+     * If one of the arrays holds a primitive type, the other array must
+     * hold the same type.
+     */
+    bool srcPrim = (srcType != '[' && srcType != 'L');
+    bool dstPrim = (dstType != '[' && dstType != 'L');
+    if (srcPrim || dstPrim) {
+        if (srcPrim != dstPrim || srcType != dstType) {
+            dvmThrowArrayStoreExceptionIncompatibleArrays(srcClass, dstClass);
+            RETURN_VOID();
+        }
+
+        if (false) LOGD("arraycopy prim[%c] dst=%p %d src=%p %d len=%d",
+            srcType, dstArray->contents, dstPos,
+            srcArray->contents, srcPos, length);
+
+        switch (srcType) {
+        case 'B':
+        case 'Z':
+            /* 1 byte per element */
+            memmove((u1*) dstArray->contents + dstPos,
+                (const u1*) srcArray->contents + srcPos,
+                length);
+            break;
+        case 'C':
+        case 'S':
+            /* 2 bytes per element */
+            move16((u1*) dstArray->contents + dstPos * 2,
+                (const u1*) srcArray->contents + srcPos * 2,
+                length * 2);
+            break;
+        case 'F':
+        case 'I':
+            /* 4 bytes per element */
+            move32((u1*) dstArray->contents + dstPos * 4,
+                (const u1*) srcArray->contents + srcPos * 4,
+                length * 4);
+            break;
+        case 'D':
+        case 'J':
+            /*
+             * 8 bytes per element.  We don't need to guarantee atomicity
+             * of the entire 64-bit word, so we can use the 32-bit copier.
+             */
+            move32((u1*) dstArray->contents + dstPos * 8,
+                (const u1*) srcArray->contents + srcPos * 8,
+                length * 8);
+            break;
+        default:        /* illegal array type */
+            LOGE("Weird array type '%s'", srcClass->descriptor);
+            dvmAbort();
+        }
+    } else {
+        /*
+         * Neither class is primitive.  See if elements in "src" are instances
+         * of elements in "dst" (e.g. copy String to String or String to
+         * Object).
+         */
+        const int width = sizeof(Object*);
+
+        if (srcClass->arrayDim == dstClass->arrayDim &&
+            dvmInstanceof(srcClass, dstClass))
+        {
+            /*
+             * "dst" can hold "src"; copy the whole thing.
+             */
+            if (false) LOGD("arraycopy ref dst=%p %d src=%p %d len=%d",
+                dstArray->contents, dstPos * width,
+                srcArray->contents, srcPos * width,
+                length * width);
+            move32((u1*)dstArray->contents + dstPos * width,
+                (const u1*)srcArray->contents + srcPos * width,
+                length * width);
+            dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
+        } else {
+            /*
+             * The arrays are not fundamentally compatible.  However, we
+             * may still be able to do this if the destination object is
+             * compatible (e.g. copy Object[] to String[], but the Object
+             * being copied is actually a String).  We need to copy elements
+             * one by one until something goes wrong.
+             *
+             * Because of overlapping moves, what we really want to do
+             * is compare the types and count up how many we can move,
+             * then call move32() to shift the actual data.  If we just
+             * start from the front we could do a smear rather than a move.
+             */
+            Object** srcObj;
+            int copyCount;
+            ClassObject*   clazz = NULL;
+
+            srcObj = ((Object**)(void*)srcArray->contents) + srcPos;
+
+            if (length > 0 && srcObj[0] != NULL)
+            {
+                clazz = srcObj[0]->clazz;
+                if (!dvmCanPutArrayElement(clazz, dstClass))
+                    clazz = NULL;
+            }
+
+            for (copyCount = 0; copyCount < length; copyCount++)
+            {
+                if (srcObj[copyCount] != NULL &&
+                    srcObj[copyCount]->clazz != clazz &&
+                    !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass))
+                {
+                    /* can't put this element into the array */
+                    break;
+                }
+            }
+
+            if (false) LOGD("arraycopy iref dst=%p %d src=%p %d count=%d of %d",
+                dstArray->contents, dstPos * width,
+                srcArray->contents, srcPos * width,
+                copyCount, length);
+            move32((u1*)dstArray->contents + dstPos * width,
+                (const u1*)srcArray->contents + srcPos * width,
+                copyCount * width);
+            dvmWriteBarrierArray(dstArray, 0, copyCount);
+            if (copyCount != length) {
+                dvmThrowArrayStoreExceptionIncompatibleArrayElement(srcPos + copyCount,
+                        srcObj[copyCount]->clazz, dstClass);
+                RETURN_VOID();
+            }
+        }
+    }
+
+    RETURN_VOID();
+}
+
+/*
+ * static long currentTimeMillis()
+ *
+ * Current time, in miliseconds.  This doesn't need to be internal to the
+ * VM, but we're already handling java.lang.System here.
+ */
+static void Dalvik_java_lang_System_currentTimeMillis(const u4* args,
+    JValue* pResult)
+{
+    struct timeval tv;
+
+    UNUSED_PARAMETER(args);
+
+    gettimeofday(&tv, (struct timezone *) NULL);
+    long long when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+
+    RETURN_LONG(when);
+}
+
+/*
+ * static long nanoTime()
+ *
+ * Current monotonically-increasing time, in nanoseconds.  This doesn't
+ * need to be internal to the VM, but we're already handling
+ * java.lang.System here.
+ */
+static void Dalvik_java_lang_System_nanoTime(const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    u8 when = dvmGetRelativeTimeNsec();
+    RETURN_LONG(when);
+}
+
+/*
+ * static int identityHashCode(Object x)
+ *
+ * Returns that hash code that the default hashCode()
+ * method would return for "x", even if "x"s class
+ * overrides hashCode().
+ */
+static void Dalvik_java_lang_System_identityHashCode(const u4* args,
+    JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    RETURN_INT(dvmIdentityHashCode(thisPtr));
+}
+
+static void Dalvik_java_lang_System_mapLibraryName(const u4* args,
+    JValue* pResult)
+{
+    StringObject* nameObj = (StringObject*) args[0];
+    StringObject* result = NULL;
+    char* name;
+    char* mappedName;
+
+    if (nameObj == NULL) {
+        dvmThrowNullPointerException("userLibName == null");
+        RETURN_VOID();
+    }
+
+    name = dvmCreateCstrFromString(nameObj);
+    mappedName = dvmCreateSystemLibraryName(name);
+    if (mappedName != NULL) {
+        result = dvmCreateStringFromCstr(mappedName);
+        dvmReleaseTrackedAlloc((Object*) result, NULL);
+    }
+
+    free(name);
+    free(mappedName);
+    RETURN_PTR(result);
+}
+
+const DalvikNativeMethod dvm_java_lang_System[] = {
+    { "arraycopy",          "(Ljava/lang/Object;ILjava/lang/Object;II)V",
+        Dalvik_java_lang_System_arraycopy },
+    { "currentTimeMillis",  "()J",
+        Dalvik_java_lang_System_currentTimeMillis },
+    { "identityHashCode",  "(Ljava/lang/Object;)I",
+        Dalvik_java_lang_System_identityHashCode },
+    { "mapLibraryName",     "(Ljava/lang/String;)Ljava/lang/String;",
+        Dalvik_java_lang_System_mapLibraryName },
+    { "nanoTime",  "()J",
+        Dalvik_java_lang_System_nanoTime },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_Throwable.cpp b/vm/native/java_lang_Throwable.cpp
new file mode 100644
index 0000000..1324e5a
--- /dev/null
+++ b/vm/native/java_lang_Throwable.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.Throwable
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private static Object nativeFillInStackTrace()
+ */
+static void Dalvik_java_lang_Throwable_nativeFillInStackTrace(const u4* args,
+    JValue* pResult)
+{
+    Object* stackState = NULL;
+
+    UNUSED_PARAMETER(args);
+
+    stackState = dvmFillInStackTrace(dvmThreadSelf());
+    RETURN_PTR(stackState);
+}
+
+/*
+ * private static StackTraceElement[] nativeGetStackTrace(Object stackState)
+ *
+ * The "stackState" argument must be the value returned by an earlier call to
+ * nativeFillInStackTrace().
+ */
+static void Dalvik_java_lang_Throwable_nativeGetStackTrace(const u4* args,
+    JValue* pResult)
+{
+    Object* stackState = (Object*) args[0];
+    ArrayObject* elements = NULL;
+
+    if (stackState == NULL) {
+        LOGW("getStackTrace() called but no trace available");
+        RETURN_PTR(NULL);   /* could throw NPE; currently caller will do so */
+    }
+
+    elements = dvmGetStackTrace(stackState);
+    RETURN_PTR(elements);
+}
+
+const DalvikNativeMethod dvm_java_lang_Throwable[] = {
+    { "nativeFillInStackTrace", "()Ljava/lang/Object;",
+        Dalvik_java_lang_Throwable_nativeFillInStackTrace },
+    { "nativeGetStackTrace",    "(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;",
+        Dalvik_java_lang_Throwable_nativeGetStackTrace },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_VMClassLoader.cpp b/vm/native/java_lang_VMClassLoader.cpp
new file mode 100644
index 0000000..0640d95
--- /dev/null
+++ b/vm/native/java_lang_VMClassLoader.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.VMClassLoader
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * static Class defineClass(ClassLoader cl, String name,
+ *     byte[] data, int offset, int len)
+ *     throws ClassFormatError
+ *
+ * Convert an array of bytes to a Class object.
+ */
+static void Dalvik_java_lang_VMClassLoader_defineClass(const u4* args,
+    JValue* pResult)
+{
+    Object* loader = (Object*) args[0];
+    StringObject* nameObj = (StringObject*) args[1];
+    const u1* data = (const u1*) args[2];
+    int offset = args[3];
+    int len = args[4];
+    char* name = NULL;
+
+    name = dvmCreateCstrFromString(nameObj);
+    LOGE("ERROR: defineClass(%p, %s, %p, %d, %d)",
+        loader, name, data, offset, len);
+    dvmThrowUnsupportedOperationException(
+        "can't load this type of class file");
+
+    free(name);
+    RETURN_VOID();
+}
+
+/*
+ * static Class defineClass(ClassLoader cl, byte[] data, int offset,
+ *     int len)
+ *     throws ClassFormatError
+ *
+ * Convert an array of bytes to a Class object. Deprecated version of
+ * previous method, lacks name parameter.
+ */
+static void Dalvik_java_lang_VMClassLoader_defineClass2(const u4* args,
+    JValue* pResult)
+{
+    Object* loader = (Object*) args[0];
+    const u1* data = (const u1*) args[1];
+    int offset = args[2];
+    int len = args[3];
+
+    LOGE("ERROR: defineClass(%p, %p, %d, %d)",
+        loader, data, offset, len);
+    dvmThrowUnsupportedOperationException(
+        "can't load this type of class file");
+
+    RETURN_VOID();
+}
+
+/*
+ * static Class findLoadedClass(ClassLoader cl, String name)
+ */
+static void Dalvik_java_lang_VMClassLoader_findLoadedClass(const u4* args,
+    JValue* pResult)
+{
+    Object* loader = (Object*) args[0];
+    StringObject* nameObj = (StringObject*) args[1];
+    ClassObject* clazz = NULL;
+    char* name = NULL;
+    char* descriptor = NULL;
+
+    if (nameObj == NULL) {
+        dvmThrowNullPointerException("name == null");
+        goto bail;
+    }
+
+    /*
+     * Get a UTF-8 copy of the string, and convert dots to slashes.
+     */
+    name = dvmCreateCstrFromString(nameObj);
+    if (name == NULL)
+        goto bail;
+
+    descriptor = dvmDotToDescriptor(name);
+    if (descriptor == NULL)
+        goto bail;
+
+    clazz = dvmLookupClass(descriptor, loader, false);
+    LOGVV("look: %s ldr=%p --> %p", descriptor, loader, clazz);
+
+bail:
+    free(name);
+    free(descriptor);
+    RETURN_PTR(clazz);
+}
+
+/*
+ * private static int getBootClassPathSize()
+ *
+ * Get the number of entries in the boot class path.
+ */
+static void Dalvik_java_lang_VMClassLoader_getBootClassPathSize(const u4* args,
+    JValue* pResult)
+{
+    int count = dvmGetBootPathSize();
+    RETURN_INT(count);
+}
+
+/*
+ * private static String getBootClassPathResource(String name, int index)
+ *
+ * Find a resource with a matching name in a boot class path entry.
+ *
+ * This mimics the previous VM interface, since we're sharing class libraries.
+ */
+static void Dalvik_java_lang_VMClassLoader_getBootClassPathResource(
+    const u4* args, JValue* pResult)
+{
+    StringObject* nameObj = (StringObject*) args[0];
+    StringObject* result;
+    int idx = args[1];
+    char* name;
+
+    name = dvmCreateCstrFromString(nameObj);
+    if (name == NULL)
+        RETURN_PTR(NULL);
+
+    result = dvmGetBootPathResource(name, idx);
+    free(name);
+    dvmReleaseTrackedAlloc((Object*)result, NULL);
+    RETURN_PTR(result);
+}
+
+/*
+ * static final Class getPrimitiveClass(char prim_type)
+ */
+static void Dalvik_java_lang_VMClassLoader_getPrimitiveClass(const u4* args,
+    JValue* pResult)
+{
+    int primType = args[0];
+
+    pResult->l = (Object*)dvmFindPrimitiveClass(primType);
+}
+
+/*
+ * static Class loadClass(String name, boolean resolve)
+ *     throws ClassNotFoundException
+ *
+ * Load class using bootstrap class loader.
+ *
+ * Return the Class object associated with the class or interface with
+ * the specified name.
+ *
+ * "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
+ */
+static void Dalvik_java_lang_VMClassLoader_loadClass(const u4* args,
+    JValue* pResult)
+{
+    StringObject* nameObj = (StringObject*) args[0];
+    bool resolve = (args[1] != 0);
+    ClassObject* clazz;
+
+    clazz = dvmFindClassByName(nameObj, NULL, resolve);
+    assert(clazz == NULL || dvmIsClassLinked(clazz));
+    RETURN_PTR(clazz);
+}
+
+const DalvikNativeMethod dvm_java_lang_VMClassLoader[] = {
+    { "defineClass",        "(Ljava/lang/ClassLoader;Ljava/lang/String;[BII)Ljava/lang/Class;",
+        Dalvik_java_lang_VMClassLoader_defineClass },
+    { "defineClass",        "(Ljava/lang/ClassLoader;[BII)Ljava/lang/Class;",
+        Dalvik_java_lang_VMClassLoader_defineClass2 },
+    { "findLoadedClass",    "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;",
+        Dalvik_java_lang_VMClassLoader_findLoadedClass },
+    { "getBootClassPathSize", "()I",
+        Dalvik_java_lang_VMClassLoader_getBootClassPathSize },
+    { "getBootClassPathResource", "(Ljava/lang/String;I)Ljava/lang/String;",
+        Dalvik_java_lang_VMClassLoader_getBootClassPathResource },
+    { "getPrimitiveClass",  "(C)Ljava/lang/Class;",
+        Dalvik_java_lang_VMClassLoader_getPrimitiveClass },
+    { "loadClass",          "(Ljava/lang/String;Z)Ljava/lang/Class;",
+        Dalvik_java_lang_VMClassLoader_loadClass },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_VMThread.cpp b/vm/native/java_lang_VMThread.cpp
new file mode 100644
index 0000000..5a8b4cf
--- /dev/null
+++ b/vm/native/java_lang_VMThread.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.VMThread
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * static void create(Thread t, long stacksize)
+ *
+ * This is eventually called as a result of Thread.start().
+ *
+ * Throws an exception on failure.
+ */
+static void Dalvik_java_lang_VMThread_create(const u4* args, JValue* pResult)
+{
+    Object* threadObj = (Object*) args[0];
+    s8 stackSize = GET_ARG_LONG(args, 1);
+
+    /* copying collector will pin threadObj for us since it was an argument */
+    dvmCreateInterpThread(threadObj, (int) stackSize);
+    RETURN_VOID();
+}
+
+/*
+ * static Thread currentThread()
+ */
+static void Dalvik_java_lang_VMThread_currentThread(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_PTR(dvmThreadSelf()->threadObj);
+}
+
+/*
+ * void getStatus()
+ *
+ * Gets the Thread status. Result is in VM terms, has to be mapped to
+ * Thread.State by interpreted code.
+ */
+static void Dalvik_java_lang_VMThread_getStatus(const u4* args, JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    Thread* thread;
+    int result;
+
+    dvmLockThreadList(NULL);
+    thread = dvmGetThreadFromThreadObject(thisPtr);
+    if (thread != NULL)
+        result = thread->status;
+    else
+        result = THREAD_ZOMBIE;     // assume it used to exist and is now gone
+    dvmUnlockThreadList();
+
+    RETURN_INT(result);
+}
+
+/*
+ * boolean holdsLock(Object object)
+ *
+ * Returns whether the current thread has a monitor lock on the specific
+ * object.
+ */
+static void Dalvik_java_lang_VMThread_holdsLock(const u4* args, JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    Object* object = (Object*) args[1];
+    Thread* thread;
+
+    if (object == NULL) {
+        dvmThrowNullPointerException("object == null");
+        RETURN_VOID();
+    }
+
+    dvmLockThreadList(NULL);
+    thread = dvmGetThreadFromThreadObject(thisPtr);
+    int result = dvmHoldsLock(thread, object);
+    dvmUnlockThreadList();
+
+    RETURN_BOOLEAN(result);
+}
+
+/*
+ * void interrupt()
+ *
+ * Interrupt a thread that is waiting (or is about to wait) on a monitor.
+ */
+static void Dalvik_java_lang_VMThread_interrupt(const u4* args, JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    Thread* thread;
+
+    dvmLockThreadList(NULL);
+    thread = dvmGetThreadFromThreadObject(thisPtr);
+    if (thread != NULL)
+        dvmThreadInterrupt(thread);
+    dvmUnlockThreadList();
+    RETURN_VOID();
+}
+
+/*
+ * static boolean interrupted()
+ *
+ * Determine if the current thread has been interrupted.  Clears the flag.
+ */
+static void Dalvik_java_lang_VMThread_interrupted(const u4* args,
+    JValue* pResult)
+{
+    Thread* self = dvmThreadSelf();
+    bool interrupted;
+
+    UNUSED_PARAMETER(args);
+
+    interrupted = self->interrupted;
+    self->interrupted = false;
+    RETURN_BOOLEAN(interrupted);
+}
+
+/*
+ * boolean isInterrupted()
+ *
+ * Determine if the specified thread has been interrupted.  Does not clear
+ * the flag.
+ */
+static void Dalvik_java_lang_VMThread_isInterrupted(const u4* args,
+    JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    Thread* thread;
+    bool interrupted;
+
+    dvmLockThreadList(NULL);
+    thread = dvmGetThreadFromThreadObject(thisPtr);
+    if (thread != NULL)
+        interrupted = thread->interrupted;
+    else
+        interrupted = false;
+    dvmUnlockThreadList();
+
+    RETURN_BOOLEAN(interrupted);
+}
+
+/*
+ * void nameChanged(String newName)
+ *
+ * The name of the target thread has changed.  We may need to alert DDMS.
+ */
+static void Dalvik_java_lang_VMThread_nameChanged(const u4* args,
+    JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    StringObject* nameStr = (StringObject*) args[1];
+    Thread* thread;
+    int threadId = -1;
+
+    /* get the thread's ID */
+    dvmLockThreadList(NULL);
+    thread = dvmGetThreadFromThreadObject(thisPtr);
+    if (thread != NULL)
+        threadId = thread->threadId;
+    dvmUnlockThreadList();
+
+    dvmDdmSendThreadNameChange(threadId, nameStr);
+    //char* str = dvmCreateCstrFromString(nameStr);
+    //LOGI("UPDATE: threadid=%d now '%s'", threadId, str);
+    //free(str);
+
+    RETURN_VOID();
+}
+
+/*
+ * void setPriority(int newPriority)
+ *
+ * Alter the priority of the specified thread.  "newPriority" will range
+ * from Thread.MIN_PRIORITY to Thread.MAX_PRIORITY (1-10), with "normal"
+ * threads at Thread.NORM_PRIORITY (5).
+ */
+static void Dalvik_java_lang_VMThread_setPriority(const u4* args,
+    JValue* pResult)
+{
+    Object* thisPtr = (Object*) args[0];
+    int newPriority = args[1];
+    Thread* thread;
+
+    dvmLockThreadList(NULL);
+    thread = dvmGetThreadFromThreadObject(thisPtr);
+    if (thread != NULL)
+        dvmChangeThreadPriority(thread, newPriority);
+    //dvmDumpAllThreads(false);
+    dvmUnlockThreadList();
+
+    RETURN_VOID();
+}
+
+/*
+ * static void sleep(long msec, int nsec)
+ */
+static void Dalvik_java_lang_VMThread_sleep(const u4* args, JValue* pResult)
+{
+    dvmThreadSleep(GET_ARG_LONG(args,0), args[2]);
+    RETURN_VOID();
+}
+
+/*
+ * public void yield()
+ *
+ * Causes the thread to temporarily pause and allow other threads to execute.
+ *
+ * The exact behavior is poorly defined.  Some discussion here:
+ *   http://www.cs.umd.edu/~pugh/java/memoryModel/archive/0944.html
+ */
+static void Dalvik_java_lang_VMThread_yield(const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    sched_yield();
+
+    RETURN_VOID();
+}
+
+const DalvikNativeMethod dvm_java_lang_VMThread[] = {
+    { "create",         "(Ljava/lang/Thread;J)V",
+        Dalvik_java_lang_VMThread_create },
+    { "currentThread",  "()Ljava/lang/Thread;",
+        Dalvik_java_lang_VMThread_currentThread },
+    { "getStatus",      "()I",
+        Dalvik_java_lang_VMThread_getStatus },
+    { "holdsLock",      "(Ljava/lang/Object;)Z",
+        Dalvik_java_lang_VMThread_holdsLock },
+    { "interrupt",      "()V",
+        Dalvik_java_lang_VMThread_interrupt },
+    { "interrupted",    "()Z",
+        Dalvik_java_lang_VMThread_interrupted },
+    { "isInterrupted",  "()Z",
+        Dalvik_java_lang_VMThread_isInterrupted },
+    { "nameChanged",    "(Ljava/lang/String;)V",
+        Dalvik_java_lang_VMThread_nameChanged },
+    { "setPriority",    "(I)V",
+        Dalvik_java_lang_VMThread_setPriority },
+    { "sleep",          "(JI)V",
+        Dalvik_java_lang_VMThread_sleep },
+    { "yield",          "()V",
+        Dalvik_java_lang_VMThread_yield },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_reflect_AccessibleObject.cpp b/vm/native/java_lang_reflect_AccessibleObject.cpp
new file mode 100644
index 0000000..46a1357
--- /dev/null
+++ b/vm/native/java_lang_reflect_AccessibleObject.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.reflect.AccessibleObject
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private static Object[] getClassSignatureAnnotation(Class clazz)
+ *
+ * Return the Signature annotation for the specified class.  Equivalent to
+ * Class.getSignatureAnnotation(), but available to java.lang.reflect.
+ */
+static void Dalvik_java_lang_reflect_AccessibleObject_getClassSignatureAnnotation(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    ArrayObject* arr = dvmGetClassSignatureAnnotation(clazz);
+
+    dvmReleaseTrackedAlloc((Object*) arr, NULL);
+    RETURN_PTR(arr);
+}
+
+const DalvikNativeMethod dvm_java_lang_reflect_AccessibleObject[] = {
+    { "getClassSignatureAnnotation", "(Ljava/lang/Class;)[Ljava/lang/Object;",
+      Dalvik_java_lang_reflect_AccessibleObject_getClassSignatureAnnotation },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_reflect_Array.cpp b/vm/native/java_lang_reflect_Array.cpp
new file mode 100644
index 0000000..c2fbb3d
--- /dev/null
+++ b/vm/native/java_lang_reflect_Array.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.reflect.Array
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private static Object createObjectArray(Class<?> componentType,
+ *     int length) throws NegativeArraySizeException;
+ *
+ * Create a one-dimensional array of Objects.
+ */
+static void Dalvik_java_lang_reflect_Array_createObjectArray(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* elementClass = (ClassObject*) args[0];
+    int length = args[1];
+
+    assert(elementClass != NULL);       // tested by caller
+    if (length < 0) {
+        dvmThrowNegativeArraySizeException(length);
+        RETURN_VOID();
+    }
+
+    ClassObject* arrayClass =
+        dvmFindArrayClassForElement(elementClass);
+    ArrayObject* newArray =
+        dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
+    if (newArray == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        RETURN_VOID();
+    }
+    dvmReleaseTrackedAlloc((Object*) newArray, NULL);
+
+    RETURN_PTR(newArray);
+}
+
+/*
+ * private static Object createMultiArray(Class<?> componentType,
+ *     int[] dimensions) throws NegativeArraySizeException;
+ *
+ * Create a multi-dimensional array of Objects or primitive types.
+ *
+ * We have to generate the names for X[], X[][], X[][][], and so on.  The
+ * easiest way to deal with that is to create the full name once and then
+ * subtract pieces off.  Besides, we want to start with the outermost
+ * piece and work our way in.
+ */
+static void Dalvik_java_lang_reflect_Array_createMultiArray(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* elementClass = (ClassObject*) args[0];
+    ArrayObject* dimArray = (ArrayObject*) args[1];
+    ClassObject* arrayClass;
+    ArrayObject* newArray;
+    char* acDescriptor;
+    int numDim, i;
+    int* dimensions;
+
+    LOGV("createMultiArray: '%s' [%d]",
+        elementClass->descriptor, dimArray->length);
+
+    assert(elementClass != NULL);       // verified by caller
+
+    /*
+     * Verify dimensions.
+     *
+     * The caller is responsible for verifying that "dimArray" is non-null
+     * and has a length > 0 and <= 255.
+     */
+    assert(dimArray != NULL);           // verified by caller
+    numDim = dimArray->length;
+    assert(numDim > 0 && numDim <= 255);
+
+    dimensions = (int*)(void*)dimArray->contents;
+    for (i = 0; i < numDim; i++) {
+        if (dimensions[i] < 0) {
+            dvmThrowNegativeArraySizeException(dimensions[i]);
+            RETURN_VOID();
+        }
+        LOGVV("DIM %d: %d", i, dimensions[i]);
+    }
+
+    /*
+     * Generate the full name of the array class.
+     */
+    acDescriptor =
+        (char*) malloc(strlen(elementClass->descriptor) + numDim + 1);
+    memset(acDescriptor, '[', numDim);
+
+    LOGVV("#### element name = '%s'", elementClass->descriptor);
+    if (dvmIsPrimitiveClass(elementClass)) {
+        assert(elementClass->primitiveType != PRIM_NOT);
+        acDescriptor[numDim] = dexGetPrimitiveTypeDescriptorChar(elementClass->primitiveType);
+        acDescriptor[numDim+1] = '\0';
+    } else {
+        strcpy(acDescriptor+numDim, elementClass->descriptor);
+    }
+    LOGVV("#### array name = '%s'", acDescriptor);
+
+    /*
+     * Find/generate the array class.
+     */
+    arrayClass = dvmFindArrayClass(acDescriptor, elementClass->classLoader);
+    if (arrayClass == NULL) {
+        LOGW("Unable to find or generate array class '%s'", acDescriptor);
+        assert(dvmCheckException(dvmThreadSelf()));
+        free(acDescriptor);
+        RETURN_VOID();
+    }
+    free(acDescriptor);
+
+    /* create the array */
+    newArray = dvmAllocMultiArray(arrayClass, numDim-1, dimensions);
+    if (newArray == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        RETURN_VOID();
+    }
+
+    dvmReleaseTrackedAlloc((Object*) newArray, NULL);
+    RETURN_PTR(newArray);
+}
+
+const DalvikNativeMethod dvm_java_lang_reflect_Array[] = {
+    { "createObjectArray",  "(Ljava/lang/Class;I)Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Array_createObjectArray },
+    { "createMultiArray",   "(Ljava/lang/Class;[I)Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Array_createMultiArray },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_reflect_Constructor.cpp b/vm/native/java_lang_reflect_Constructor.cpp
new file mode 100644
index 0000000..e776bf1
--- /dev/null
+++ b/vm/native/java_lang_reflect_Constructor.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.reflect.Constructor
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * public int constructNative(Object[] args, Class declaringClass,
+ *     Class[] parameterTypes, int slot, boolean noAccessCheck)
+ *
+ * We get here through Constructor.newInstance().  The Constructor object
+ * would not be available if the constructor weren't public (per the
+ * definition of Class.getConstructor), so we can skip the method access
+ * check.  We can also safely assume the constructor isn't associated
+ * with an interface, array, or primitive class.
+ */
+static void Dalvik_java_lang_reflect_Constructor_constructNative(
+    const u4* args, JValue* pResult)
+{
+    // ignore thisPtr in args[0]
+    ArrayObject* argList = (ArrayObject*) args[1];
+    ClassObject* declaringClass = (ClassObject*) args[2];
+    ArrayObject* params = (ArrayObject*) args[3];
+    int slot = args[4];
+    bool noAccessCheck = (args[5] != 0);
+    Object* newObj;
+    Method* meth;
+
+    if (dvmIsAbstractClass(declaringClass)) {
+        dvmThrowInstantiationException(declaringClass, NULL);
+        RETURN_VOID();
+    }
+
+    /* initialize the class if it hasn't been already */
+    if (!dvmIsClassInitialized(declaringClass)) {
+        if (!dvmInitClass(declaringClass)) {
+            LOGW("Class init failed in Constructor.constructNative (%s)",
+                declaringClass->descriptor);
+            assert(dvmCheckException(dvmThreadSelf()));
+            RETURN_VOID();
+        }
+    }
+
+    newObj = dvmAllocObject(declaringClass, ALLOC_DEFAULT);
+    if (newObj == NULL)
+        RETURN_PTR(NULL);
+
+    meth = dvmSlotToMethod(declaringClass, slot);
+    assert(meth != NULL);
+
+    (void) dvmInvokeMethod(newObj, meth, argList, params, NULL, noAccessCheck);
+    dvmReleaseTrackedAlloc(newObj, NULL);
+    RETURN_PTR(newObj);
+}
+
+const DalvikNativeMethod dvm_java_lang_reflect_Constructor[] = {
+    { "constructNative",    "([Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;IZ)Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Constructor_constructNative },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_reflect_Field.cpp b/vm/native/java_lang_reflect_Field.cpp
new file mode 100644
index 0000000..d1918bc
--- /dev/null
+++ b/vm/native/java_lang_reflect_Field.cpp
@@ -0,0 +1,719 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.reflect.Field
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * Validate access to a field.  Returns a pointer to the Field struct.
+ *
+ * "declaringClass" is the class in which the field was declared.  For an
+ * instance field, "obj" is the object that holds the field data; for a
+ * static field its value is ignored.
+ *
+ * "If the underlying field is static, the class that declared the
+ * field is initialized if it has not already been initialized."
+ *
+ * On failure, throws an exception and returns NULL.
+ *
+ * The documentation lists exceptional conditions and the exceptions that
+ * should be thrown, but doesn't say which exception prevails when two or
+ * more exceptional conditions exist at the same time.  For example,
+ * attempting to set a protected field from an unrelated class causes an
+ * IllegalAccessException, while passing in a data type that doesn't match
+ * the field causes an IllegalArgumentException.  If code does both at the
+ * same time, we have to choose one or the other.
+ *
+ * The expected order is:
+ *  (1) Check for illegal access. Throw IllegalAccessException.
+ *  (2) Make sure the object actually has the field.  Throw
+ *      IllegalArgumentException.
+ *  (3) Make sure the field matches the expected type, e.g. if we issued
+ *      a "getInteger" call make sure the field is an integer or can be
+ *      converted to an int with a widening conversion.  Throw
+ *      IllegalArgumentException.
+ *  (4) Make sure "obj" is not null.  Throw NullPointerException.
+ *
+ * TODO: we're currently handling #3 after #4, because we don't check the
+ * widening conversion until we're actually extracting the value from the
+ * object (which won't work well if it's a null reference).
+ */
+static Field* validateFieldAccess(Object* obj, ClassObject* declaringClass,
+    int slot, bool isSetOperation, bool noAccessCheck)
+{
+    Field* field;
+
+    field = dvmSlotToField(declaringClass, slot);
+    assert(field != NULL);
+
+    /* verify access */
+    if (!noAccessCheck) {
+        if (isSetOperation && dvmIsFinalField(field)) {
+            dvmThrowIllegalAccessException("field is marked 'final'");
+            return NULL;
+        }
+
+        ClassObject* callerClass =
+            dvmGetCaller2Class(dvmThreadSelf()->interpSave.curFrame);
+
+        /*
+         * We need to check two things:
+         *  (1) Would an instance of the calling class have access to the field?
+         *  (2) If the field is "protected", is the object an instance of the
+         *      calling class, or is the field's declaring class in the same
+         *      package as the calling class?
+         *
+         * #1 is basic access control.  #2 ensures that, just because
+         * you're a subclass of Foo, you can't mess with protected fields
+         * in arbitrary Foo objects from other packages.
+         */
+        if (!dvmCheckFieldAccess(callerClass, field)) {
+            dvmThrowIllegalAccessException("access to field not allowed");
+            return NULL;
+        }
+        if (dvmIsProtectedField(field)) {
+            bool isInstance, samePackage;
+
+            if (obj != NULL)
+                isInstance = dvmInstanceof(obj->clazz, callerClass);
+            else
+                isInstance = false;
+            samePackage = dvmInSamePackage(declaringClass, callerClass);
+
+            if (!isInstance && !samePackage) {
+                dvmThrowIllegalAccessException(
+                    "access to protected field not allowed");
+                return NULL;
+            }
+        }
+    }
+
+    if (dvmIsStaticField(field)) {
+        /* init class if necessary, then return ptr to storage in "field" */
+        if (!dvmIsClassInitialized(declaringClass)) {
+            if (!dvmInitClass(declaringClass)) {
+                assert(dvmCheckException(dvmThreadSelf()));
+                return NULL;
+            }
+        }
+
+    } else {
+        /*
+         * Verify object is of correct type (i.e. it actually has the
+         * expected field in it), then grab a pointer to obj storage.
+         * The call to dvmVerifyObjectInClass throws an NPE if "obj" is NULL.
+         */
+        if (!dvmVerifyObjectInClass(obj, declaringClass)) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            return NULL;
+        }
+    }
+
+    return field;
+}
+
+/*
+ * Extracts the value of a static field.  Provides appropriate barriers
+ * for volatile fields.
+ *
+ * Sub-32-bit values are sign- or zero-extended to fill out 32 bits.
+ */
+static void getStaticFieldValue(const StaticField* sfield, JValue* value)
+{
+    if (!dvmIsVolatileField(sfield)) {
+        /* just copy the whole thing */
+        *value = sfield->value;
+    } else {
+        /* need memory barriers and/or 64-bit atomic ops */
+        switch (sfield->signature[0]) {
+        case 'Z':
+            value->i = dvmGetStaticFieldBooleanVolatile(sfield);
+            break;
+        case 'B':
+            value->i = dvmGetStaticFieldByteVolatile(sfield);
+            break;
+        case 'S':
+            value->i = dvmGetStaticFieldShortVolatile(sfield);
+            break;
+        case 'C':
+            value->i = dvmGetStaticFieldCharVolatile(sfield);
+            break;
+        case 'I':
+            value->i = dvmGetStaticFieldIntVolatile(sfield);
+            break;
+        case 'F':
+            value->f = dvmGetStaticFieldFloatVolatile(sfield);
+            break;
+        case 'J':
+            value->j = dvmGetStaticFieldLongVolatile(sfield);
+            break;
+        case 'D':
+            value->d = dvmGetStaticFieldDoubleVolatile(sfield);
+            break;
+        case 'L':
+        case '[':
+            value->l = dvmGetStaticFieldObjectVolatile(sfield);
+            break;
+        default:
+            LOGE("Unhandled field signature '%s'", sfield->signature);
+            dvmAbort();
+        }
+    }
+}
+
+/*
+ * Extracts the value of an instance field.  Provides appropriate barriers
+ * for volatile fields.
+ *
+ * Sub-32-bit values are sign- or zero-extended to fill out 32 bits.
+ */
+static void getInstFieldValue(const InstField* ifield, Object* obj,
+    JValue* value)
+{
+    if (!dvmIsVolatileField(ifield)) {
+        /* use type-specific get; really just 32-bit vs. 64-bit */
+        switch (ifield->signature[0]) {
+        case 'Z':
+            value->i = dvmGetFieldBoolean(obj, ifield->byteOffset);
+            break;
+        case 'B':
+            value->i = dvmGetFieldByte(obj, ifield->byteOffset);
+            break;
+        case 'S':
+            value->i = dvmGetFieldShort(obj, ifield->byteOffset);
+            break;
+        case 'C':
+            value->i = dvmGetFieldChar(obj, ifield->byteOffset);
+            break;
+        case 'I':
+            value->i = dvmGetFieldInt(obj, ifield->byteOffset);
+            break;
+        case 'F':
+            value->f = dvmGetFieldFloat(obj, ifield->byteOffset);
+            break;
+        case 'J':
+            value->j = dvmGetFieldLong(obj, ifield->byteOffset);
+            break;
+        case 'D':
+            value->d = dvmGetFieldDouble(obj, ifield->byteOffset);
+            break;
+        case 'L':
+        case '[':
+            value->l = dvmGetFieldObject(obj, ifield->byteOffset);
+            break;
+        default:
+            LOGE("Unhandled field signature '%s'", ifield->signature);
+            dvmAbort();
+        }
+    } else {
+        /* need memory barriers and/or 64-bit atomic ops */
+        switch (ifield->signature[0]) {
+        case 'Z':
+            value->i = dvmGetFieldBooleanVolatile(obj, ifield->byteOffset);
+            break;
+        case 'B':
+            value->i = dvmGetFieldByteVolatile(obj, ifield->byteOffset);
+            break;
+        case 'S':
+            value->i = dvmGetFieldShortVolatile(obj, ifield->byteOffset);
+            break;
+        case 'C':
+            value->i = dvmGetFieldCharVolatile(obj, ifield->byteOffset);
+            break;
+        case 'I':
+            value->i = dvmGetFieldIntVolatile(obj, ifield->byteOffset);
+            break;
+        case 'F':
+            value->f = dvmGetFieldFloatVolatile(obj, ifield->byteOffset);
+            break;
+        case 'J':
+            value->j = dvmGetFieldLongVolatile(obj, ifield->byteOffset);
+            break;
+        case 'D':
+            value->d = dvmGetFieldDoubleVolatile(obj, ifield->byteOffset);
+            break;
+        case 'L':
+        case '[':
+            value->l = dvmGetFieldObjectVolatile(obj, ifield->byteOffset);
+            break;
+        default:
+            LOGE("Unhandled field signature '%s'", ifield->signature);
+            dvmAbort();
+        }
+    }
+}
+
+/*
+ * Copies the value of the static or instance field into "*value".
+ */
+static void getFieldValue(const Field* field, Object* obj, JValue* value)
+{
+    if (dvmIsStaticField(field)) {
+        return getStaticFieldValue((const StaticField*) field, value);
+    } else {
+        return getInstFieldValue((const InstField*) field, obj, value);
+    }
+}
+
+/*
+ * Sets the value of a static field.  Provides appropriate barriers
+ * for volatile fields.
+ */
+static void setStaticFieldValue(StaticField* sfield, const JValue* value)
+{
+    if (!dvmIsVolatileField(sfield)) {
+        switch (sfield->signature[0]) {
+        case 'L':
+        case '[':
+            dvmSetStaticFieldObject(sfield, (Object*)value->l);
+            break;
+        default:
+            /* just copy the whole thing */
+            sfield->value = *value;
+            break;
+        }
+    } else {
+        /* need memory barriers and/or 64-bit atomic ops */
+        switch (sfield->signature[0]) {
+        case 'Z':
+            dvmSetStaticFieldBooleanVolatile(sfield, value->z);
+            break;
+        case 'B':
+            dvmSetStaticFieldByteVolatile(sfield, value->b);
+            break;
+        case 'S':
+            dvmSetStaticFieldShortVolatile(sfield, value->s);
+            break;
+        case 'C':
+            dvmSetStaticFieldCharVolatile(sfield, value->c);
+            break;
+        case 'I':
+            dvmSetStaticFieldIntVolatile(sfield, value->i);
+            break;
+        case 'F':
+            dvmSetStaticFieldFloatVolatile(sfield, value->f);
+            break;
+        case 'J':
+            dvmSetStaticFieldLongVolatile(sfield, value->j);
+            break;
+        case 'D':
+            dvmSetStaticFieldDoubleVolatile(sfield, value->d);
+            break;
+        case 'L':
+        case '[':
+            dvmSetStaticFieldObjectVolatile(sfield, (Object*)value->l);
+            break;
+        default:
+            LOGE("Unhandled field signature '%s'", sfield->signature);
+            dvmAbort();
+        }
+    }
+}
+
+/*
+ * Sets the value of an instance field.  Provides appropriate barriers
+ * for volatile fields.
+ */
+static void setInstFieldValue(InstField* ifield, Object* obj,
+    const JValue* value)
+{
+    if (!dvmIsVolatileField(ifield)) {
+        /* use type-specific set; really just 32-bit vs. 64-bit */
+        switch (ifield->signature[0]) {
+        case 'Z':
+            dvmSetFieldBoolean(obj, ifield->byteOffset, value->z);
+            break;
+        case 'B':
+            dvmSetFieldByte(obj, ifield->byteOffset, value->b);
+            break;
+        case 'S':
+            dvmSetFieldShort(obj, ifield->byteOffset, value->s);
+            break;
+        case 'C':
+            dvmSetFieldChar(obj, ifield->byteOffset, value->c);
+            break;
+        case 'I':
+            dvmSetFieldInt(obj, ifield->byteOffset, value->i);
+            break;
+        case 'F':
+            dvmSetFieldFloat(obj, ifield->byteOffset, value->f);
+            break;
+        case 'J':
+            dvmSetFieldLong(obj, ifield->byteOffset, value->j);
+            break;
+        case 'D':
+            dvmSetFieldDouble(obj, ifield->byteOffset, value->d);
+            break;
+        case 'L':
+        case '[':
+            dvmSetFieldObject(obj, ifield->byteOffset, (Object *)value->l);
+            break;
+        default:
+            LOGE("Unhandled field signature '%s'", ifield->signature);
+            dvmAbort();
+        }
+#if ANDROID_SMP != 0
+        /*
+         * Special handling for final fields on SMP systems.  We need a
+         * store/store barrier here (JMM requirement).
+         */
+        if (dvmIsFinalField(ifield)) {
+            ANDROID_MEMBAR_STORE();
+        }
+#endif
+    } else {
+        /* need memory barriers and/or 64-bit atomic ops */
+        switch (ifield->signature[0]) {
+        case 'Z':
+            dvmSetFieldBooleanVolatile(obj, ifield->byteOffset, value->z);
+            break;
+        case 'B':
+            dvmSetFieldByteVolatile(obj, ifield->byteOffset, value->b);
+            break;
+        case 'S':
+            dvmSetFieldShortVolatile(obj, ifield->byteOffset, value->s);
+            break;
+        case 'C':
+            dvmSetFieldCharVolatile(obj, ifield->byteOffset, value->c);
+            break;
+        case 'I':
+            dvmSetFieldIntVolatile(obj, ifield->byteOffset, value->i);
+            break;
+        case 'F':
+            dvmSetFieldFloatVolatile(obj, ifield->byteOffset, value->f);
+            break;
+        case 'J':
+            dvmSetFieldLongVolatile(obj, ifield->byteOffset, value->j);
+            break;
+        case 'D':
+            dvmSetFieldDoubleVolatile(obj, ifield->byteOffset, value->d);
+            break;
+        case 'L':
+        case '[':
+            dvmSetFieldObjectVolatile(obj, ifield->byteOffset, (Object*)value->l);
+            break;
+        default:
+            LOGE("Unhandled field signature '%s'", ifield->signature);
+            dvmAbort();
+        }
+    }
+}
+
+/*
+ * Copy "*value" into the static or instance field.
+ */
+static void setFieldValue(Field* field, Object* obj, const JValue* value)
+{
+    if (dvmIsStaticField(field)) {
+        return setStaticFieldValue((StaticField*) field, value);
+    } else {
+        return setInstFieldValue((InstField*) field, obj, value);
+    }
+}
+
+
+
+/*
+ * public int getFieldModifiers(Class declaringClass, int slot)
+ */
+static void Dalvik_java_lang_reflect_Field_getFieldModifiers(const u4* args,
+    JValue* pResult)
+{
+    /* ignore thisPtr in args[0] */
+    ClassObject* declaringClass = (ClassObject*) args[1];
+    int slot = args[2];
+    Field* field;
+
+    field = dvmSlotToField(declaringClass, slot);
+    RETURN_INT(field->accessFlags & JAVA_FLAGS_MASK);
+}
+
+/*
+ * private Object getField(Object o, Class declaringClass, Class type,
+ *     int slot, boolean noAccessCheck)
+ *
+ * Primitive types need to be boxed.
+ */
+static void Dalvik_java_lang_reflect_Field_getField(const u4* args,
+    JValue* pResult)
+{
+    /* ignore thisPtr in args[0] */
+    Object* obj = (Object*) args[1];
+    ClassObject* declaringClass = (ClassObject*) args[2];
+    ClassObject* fieldType = (ClassObject*) args[3];
+    int slot = args[4];
+    bool noAccessCheck = (args[5] != 0);
+    Field* field;
+    JValue value;
+    DataObject* result;
+
+    //dvmDumpClass(obj->clazz, kDumpClassFullDetail);
+
+    /* get a pointer to the Field after validating access */
+    field = validateFieldAccess(obj, declaringClass, slot, false,noAccessCheck);
+    if (field == NULL)
+        RETURN_VOID();
+
+    getFieldValue(field, obj, &value);
+
+    /* if it's primitive, box it up */
+    result = dvmBoxPrimitive(value, fieldType);
+    dvmReleaseTrackedAlloc((Object*) result, NULL);
+    RETURN_PTR(result);
+}
+
+/*
+ * private void setField(Object o, Class declaringClass, Class type,
+ *     int slot, boolean noAccessCheck, Object value)
+ *
+ * When assigning into a primitive field we will automatically extract
+ * the value from box types.
+ */
+static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
+    JValue* pResult)
+{
+    /* ignore thisPtr in args[0] */
+    Object* obj = (Object*) args[1];
+    ClassObject* declaringClass = (ClassObject*) args[2];
+    ClassObject* fieldType = (ClassObject*) args[3];
+    int slot = args[4];
+    bool noAccessCheck = (args[5] != 0);
+    Object* valueObj = (Object*) args[6];
+    Field* field;
+    JValue value;
+
+    /* unbox primitive, or verify object type */
+    if (!dvmUnboxPrimitive(valueObj, fieldType, &value)) {
+        dvmThrowIllegalArgumentException("invalid value for field");
+        RETURN_VOID();
+    }
+
+    /* get a pointer to the Field after validating access */
+    field = validateFieldAccess(obj, declaringClass, slot, true, noAccessCheck);
+
+    if (field != NULL) {
+        setFieldValue(field, obj, &value);
+    }
+    RETURN_VOID();
+}
+
+/*
+ * Primitive field getters, e.g.:
+ * private double getIField(Object o, Class declaringClass,
+ *     Class type, int slot, boolean noAccessCheck, char descriptor)
+ */
+static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args,
+    JValue* pResult)
+{
+    /* ignore thisPtr in args[0] */
+    Object* obj = (Object*) args[1];
+    ClassObject* declaringClass = (ClassObject*) args[2];
+    ClassObject* fieldType = (ClassObject*) args[3];
+    int slot = args[4];
+    bool noAccessCheck = (args[5] != 0);
+    jchar descriptor = args[6];
+    PrimitiveType targetType = dexGetPrimitiveTypeFromDescriptorChar(descriptor);
+    const Field* field;
+    JValue value;
+
+    if (!dvmIsPrimitiveClass(fieldType)) {
+        dvmThrowIllegalArgumentException("not a primitive field");
+        RETURN_VOID();
+    }
+
+    /* get a pointer to the Field after validating access */
+    field = validateFieldAccess(obj, declaringClass, slot, false,noAccessCheck);
+    if (field == NULL)
+        RETURN_VOID();
+
+    getFieldValue(field, obj, &value);
+
+    /* retrieve value, performing a widening conversion if necessary */
+    if (dvmConvertPrimitiveValue(fieldType->primitiveType, targetType,
+        &(value.i), &(pResult->i)) < 0)
+    {
+        dvmThrowIllegalArgumentException("invalid primitive conversion");
+        RETURN_VOID();
+    }
+}
+
+/*
+ * Primitive field setters, e.g.:
+ * private void setIField(Object o, Class declaringClass,
+ *     Class type, int slot, boolean noAccessCheck, char descriptor, int value)
+ */
+static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args,
+    JValue* pResult)
+{
+    /* ignore thisPtr in args[0] */
+    Object* obj = (Object*) args[1];
+    ClassObject* declaringClass = (ClassObject*) args[2];
+    ClassObject* fieldType = (ClassObject*) args[3];
+    int slot = args[4];
+    bool noAccessCheck = (args[5] != 0);
+    jchar descriptor = args[6];
+    const s4* valuePtr = (s4*) &args[7];    /* 64-bit vars spill into args[8] */
+    PrimitiveType srcType = dexGetPrimitiveTypeFromDescriptorChar(descriptor);
+    Field* field;
+    JValue value;
+
+    if (!dvmIsPrimitiveClass(fieldType)) {
+        dvmThrowIllegalArgumentException("not a primitive field");
+        RETURN_VOID();
+    }
+
+    /* convert the 32/64-bit arg to a JValue matching the field type */
+    if (dvmConvertPrimitiveValue(srcType, fieldType->primitiveType,
+        valuePtr, &(value.i)) < 0)
+    {
+        dvmThrowIllegalArgumentException("invalid primitive conversion");
+        RETURN_VOID();
+    }
+
+    /* get a pointer to the Field after validating access */
+    field = validateFieldAccess(obj, declaringClass, slot, true, noAccessCheck);
+
+    if (field != NULL) {
+        setFieldValue(field, obj, &value);
+    }
+    RETURN_VOID();
+}
+
+/*
+ * private static Annotation[] getDeclaredAnnotations(
+ *         Class declaringClass, int slot)
+ *
+ * Return the annotations declared for this field.
+ */
+static void Dalvik_java_lang_reflect_Field_getDeclaredAnnotations(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* declaringClass = (ClassObject*) args[0];
+    int slot = args[1];
+    Field* field;
+
+    field = dvmSlotToField(declaringClass, slot);
+    assert(field != NULL);
+
+    ArrayObject* annos = dvmGetFieldAnnotations(field);
+    dvmReleaseTrackedAlloc((Object*) annos, NULL);
+    RETURN_PTR(annos);
+}
+
+/*
+ * static Annotation getAnnotation(
+ *         Class declaringClass, int slot, Class annotationType);
+ */
+static void Dalvik_java_lang_reflect_Field_getAnnotation(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    int slot = args[1];
+    ClassObject* annotationClazz = (ClassObject*) args[2];
+
+    Field* field = dvmSlotToField(clazz, slot);
+    RETURN_PTR(dvmGetFieldAnnotation(clazz, field, annotationClazz));
+}
+
+/*
+ * static boolean isAnnotationPresent(
+ *         Class declaringClass, int slot, Class annotationType);
+ */
+static void Dalvik_java_lang_reflect_Field_isAnnotationPresent(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    int slot = args[1];
+    ClassObject* annotationClazz = (ClassObject*) args[2];
+
+    Field* field = dvmSlotToField(clazz, slot);
+    RETURN_BOOLEAN(dvmIsFieldAnnotationPresent(clazz, field, annotationClazz));
+}
+
+/*
+ * private Object[] getSignatureAnnotation()
+ *
+ * Returns the signature annotation.
+ */
+static void Dalvik_java_lang_reflect_Field_getSignatureAnnotation(const u4* args,
+    JValue* pResult)
+{
+    /* ignore thisPtr in args[0] */
+    ClassObject* declaringClass = (ClassObject*) args[1];
+    int slot = args[2];
+    Field* field;
+
+    field = dvmSlotToField(declaringClass, slot);
+    assert(field != NULL);
+
+    ArrayObject* arr = dvmGetFieldSignatureAnnotation(field);
+    dvmReleaseTrackedAlloc((Object*) arr, NULL);
+    RETURN_PTR(arr);
+}
+
+const DalvikNativeMethod dvm_java_lang_reflect_Field[] = {
+    { "getFieldModifiers",  "(Ljava/lang/Class;I)I",
+        Dalvik_java_lang_reflect_Field_getFieldModifiers },
+    { "getField",           "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Field_getField },
+    { "getBField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)B",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getCField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)C",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getDField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)D",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getFField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)F",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getIField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)I",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getJField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)J",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getSField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)S",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "getZField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)Z",
+        Dalvik_java_lang_reflect_Field_getPrimitiveField },
+    { "setField",           "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZLjava/lang/Object;)V",
+        Dalvik_java_lang_reflect_Field_setField },
+    { "setBField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCB)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setCField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCC)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setDField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCD)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setFField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCF)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setIField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCI)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setJField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCJ)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setSField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCS)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "setZField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCZ)V",
+        Dalvik_java_lang_reflect_Field_setPrimitiveField },
+    { "getDeclaredAnnotations", "(Ljava/lang/Class;I)[Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_reflect_Field_getDeclaredAnnotations },
+    { "getAnnotation", "(Ljava/lang/Class;ILjava/lang/Class;)Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_reflect_Field_getAnnotation },
+    { "isAnnotationPresent", "(Ljava/lang/Class;ILjava/lang/Class;)Z",
+        Dalvik_java_lang_reflect_Field_isAnnotationPresent },
+    { "getSignatureAnnotation",  "(Ljava/lang/Class;I)[Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Field_getSignatureAnnotation },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_reflect_Method.cpp b/vm/native/java_lang_reflect_Method.cpp
new file mode 100644
index 0000000..164e435
--- /dev/null
+++ b/vm/native/java_lang_reflect_Method.cpp
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.reflect.Method
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * static int getMethodModifiers(Class decl_class, int slot)
+ *
+ * (Not sure why the access flags weren't stored in the class along with
+ * everything else.  Not sure why this isn't static.)
+ */
+static void Dalvik_java_lang_reflect_Method_getMethodModifiers(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* declaringClass = (ClassObject*) args[0];
+    int slot = args[1];
+    Method* meth;
+
+    meth = dvmSlotToMethod(declaringClass, slot);
+    RETURN_INT(dvmFixMethodFlags(meth->accessFlags));
+}
+
+/*
+ * private Object invokeNative(Object obj, Object[] args, Class declaringClass,
+ *   Class[] parameterTypes, Class returnType, int slot, boolean noAccessCheck)
+ *
+ * Invoke a static or virtual method via reflection.
+ */
+static void Dalvik_java_lang_reflect_Method_invokeNative(const u4* args,
+    JValue* pResult)
+{
+    // ignore thisPtr in args[0]
+    Object* methObj = (Object*) args[1];        // null for static methods
+    ArrayObject* argList = (ArrayObject*) args[2];
+    ClassObject* declaringClass = (ClassObject*) args[3];
+    ArrayObject* params = (ArrayObject*) args[4];
+    ClassObject* returnType = (ClassObject*) args[5];
+    int slot = args[6];
+    bool noAccessCheck = (args[7] != 0);
+    const Method* meth;
+    Object* result;
+
+    /*
+     * "If the underlying method is static, the class that declared the
+     * method is initialized if it has not already been initialized."
+     */
+    meth = dvmSlotToMethod(declaringClass, slot);
+    assert(meth != NULL);
+
+    if (dvmIsStaticMethod(meth)) {
+        if (!dvmIsClassInitialized(declaringClass)) {
+            if (!dvmInitClass(declaringClass))
+                goto init_failed;
+        }
+    } else {
+        /* looks like interfaces need this too? */
+        if (dvmIsInterfaceClass(declaringClass) &&
+            !dvmIsClassInitialized(declaringClass))
+        {
+            if (!dvmInitClass(declaringClass))
+                goto init_failed;
+        }
+
+        /* make sure the object is an instance of the expected class */
+        if (!dvmVerifyObjectInClass(methObj, declaringClass)) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            RETURN_VOID();
+        }
+
+        /* do the virtual table lookup for the method */
+        meth = dvmGetVirtualizedMethod(methObj->clazz, meth);
+        if (meth == NULL) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            RETURN_VOID();
+        }
+    }
+
+    /*
+     * If the method has a return value, "result" will be an object or
+     * a boxed primitive.
+     */
+    result = dvmInvokeMethod(methObj, meth, argList, params, returnType,
+                noAccessCheck);
+
+    RETURN_PTR(result);
+
+init_failed:
+    /*
+     * If initialization failed, an exception will be raised.
+     */
+    LOGD("Method.invoke() on bad class %s failed",
+        declaringClass->descriptor);
+    assert(dvmCheckException(dvmThreadSelf()));
+    RETURN_VOID();
+}
+
+/*
+ * static Annotation[] getDeclaredAnnotations(Class declaringClass, int slot)
+ *
+ * Return the annotations declared for this method.
+ */
+static void Dalvik_java_lang_reflect_Method_getDeclaredAnnotations(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* declaringClass = (ClassObject*) args[0];
+    int slot = args[1];
+    Method* meth;
+
+    meth = dvmSlotToMethod(declaringClass, slot);
+    assert(meth != NULL);
+
+    ArrayObject* annos = dvmGetMethodAnnotations(meth);
+    dvmReleaseTrackedAlloc((Object*)annos, NULL);
+    RETURN_PTR(annos);
+}
+
+/*
+ * static Annotation getAnnotation(
+ *         Class declaringClass, int slot, Class annotationType);
+ */
+static void Dalvik_java_lang_reflect_Method_getAnnotation(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    int slot = args[1];
+    ClassObject* annotationClazz = (ClassObject*) args[2];
+
+    Method* meth = dvmSlotToMethod(clazz, slot);
+    RETURN_PTR(dvmGetMethodAnnotation(clazz, meth, annotationClazz));
+}
+
+/*
+ * static boolean isAnnotationPresent(
+ *         Class declaringClass, int slot, Class annotationType);
+ */
+static void Dalvik_java_lang_reflect_Method_isAnnotationPresent(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    int slot = args[1];
+    ClassObject* annotationClazz = (ClassObject*) args[2];
+
+    Method* meth = dvmSlotToMethod(clazz, slot);
+    RETURN_BOOLEAN(dvmIsMethodAnnotationPresent(clazz, meth, annotationClazz));
+}
+
+/*
+ * static Annotation[][] getParameterAnnotations(Class declaringClass, int slot)
+ *
+ * Return the annotations declared for this method's parameters.
+ */
+static void Dalvik_java_lang_reflect_Method_getParameterAnnotations(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* declaringClass = (ClassObject*) args[0];
+    int slot = args[1];
+    Method* meth;
+
+    meth = dvmSlotToMethod(declaringClass, slot);
+    assert(meth != NULL);
+
+    ArrayObject* annos = dvmGetParameterAnnotations(meth);
+    dvmReleaseTrackedAlloc((Object*)annos, NULL);
+    RETURN_PTR(annos);
+}
+
+/*
+ * private Object getDefaultValue(Class declaringClass, int slot)
+ *
+ * Return the default value for the annotation member represented by
+ * this Method instance.  Returns NULL if none is defined.
+ */
+static void Dalvik_java_lang_reflect_Method_getDefaultValue(const u4* args,
+    JValue* pResult)
+{
+    // ignore thisPtr in args[0]
+    ClassObject* declaringClass = (ClassObject*) args[1];
+    int slot = args[2];
+    Method* meth;
+
+    /* make sure this is an annotation class member */
+    if (!dvmIsAnnotationClass(declaringClass))
+        RETURN_PTR(NULL);
+
+    meth = dvmSlotToMethod(declaringClass, slot);
+    assert(meth != NULL);
+
+    Object* def = dvmGetAnnotationDefaultValue(meth);
+    dvmReleaseTrackedAlloc(def, NULL);
+    RETURN_PTR(def);
+}
+
+/*
+ * static Object[] getSignatureAnnotation()
+ *
+ * Returns the signature annotation.
+ */
+static void Dalvik_java_lang_reflect_Method_getSignatureAnnotation(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* declaringClass = (ClassObject*) args[0];
+    int slot = args[1];
+    Method* meth;
+
+    meth = dvmSlotToMethod(declaringClass, slot);
+    assert(meth != NULL);
+
+    ArrayObject* arr = dvmGetMethodSignatureAnnotation(meth);
+    dvmReleaseTrackedAlloc((Object*) arr, NULL);
+    RETURN_PTR(arr);
+}
+
+const DalvikNativeMethod dvm_java_lang_reflect_Method[] = {
+    { "getMethodModifiers", "(Ljava/lang/Class;I)I",
+        Dalvik_java_lang_reflect_Method_getMethodModifiers },
+    { "invokeNative",       "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Method_invokeNative },
+    { "getDeclaredAnnotations", "(Ljava/lang/Class;I)[Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_reflect_Method_getDeclaredAnnotations },
+    { "getAnnotation", "(Ljava/lang/Class;ILjava/lang/Class;)Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_reflect_Method_getAnnotation },
+    { "isAnnotationPresent", "(Ljava/lang/Class;ILjava/lang/Class;)Z",
+        Dalvik_java_lang_reflect_Method_isAnnotationPresent },
+    { "getParameterAnnotations", "(Ljava/lang/Class;I)[[Ljava/lang/annotation/Annotation;",
+        Dalvik_java_lang_reflect_Method_getParameterAnnotations },
+    { "getDefaultValue",    "(Ljava/lang/Class;I)Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Method_getDefaultValue },
+    { "getSignatureAnnotation",  "(Ljava/lang/Class;I)[Ljava/lang/Object;",
+        Dalvik_java_lang_reflect_Method_getSignatureAnnotation },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_lang_reflect_Proxy.cpp b/vm/native/java_lang_reflect_Proxy.cpp
new file mode 100644
index 0000000..da1232c
--- /dev/null
+++ b/vm/native/java_lang_reflect_Proxy.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.lang.reflect.Proxy
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * static Class generateProxy(String name, Class[] interfaces,
+ *      ClassLoader loader)
+ *
+ * Generate a proxy class with the specified characteristics.  Throws an
+ * exception on error.
+ */
+static void Dalvik_java_lang_reflect_Proxy_generateProxy(const u4* args,
+    JValue* pResult)
+{
+    StringObject* str = (StringObject*) args[0];
+    ArrayObject* interfaces = (ArrayObject*) args[1];
+    Object* loader = (Object*) args[2];
+    ClassObject* result;
+
+    result = dvmGenerateProxyClass(str, interfaces, loader);
+    RETURN_PTR(result);
+}
+
+const DalvikNativeMethod dvm_java_lang_reflect_Proxy[] = {
+    { "generateProxy", "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;)Ljava/lang/Class;",
+        Dalvik_java_lang_reflect_Proxy_generateProxy },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/java_util_concurrent_atomic_AtomicLong.cpp b/vm/native/java_util_concurrent_atomic_AtomicLong.cpp
new file mode 100644
index 0000000..eb1d0de
--- /dev/null
+++ b/vm/native/java_util_concurrent_atomic_AtomicLong.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+/*
+ * java.util.concurrent.atomic.AtomicLong
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private static native boolean VMSupportsCS8();
+ */
+static void Dalvik_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8(
+    const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+    RETURN_BOOLEAN(1);
+}
+
+const DalvikNativeMethod dvm_java_util_concurrent_atomic_AtomicLong[] = {
+    { "VMSupportsCS8", "()Z",
+        Dalvik_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8 },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/org_apache_harmony_dalvik_NativeTestTarget.cpp b/vm/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
new file mode 100644
index 0000000..ccc9467
--- /dev/null
+++ b/vm/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/*
+ * org.apache.harmony.dalvik.NativeTestTarget
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * public static void emptyInternalStaticMethod()
+ *
+ * For benchmarks, a do-nothing internal method with no arguments.
+ */
+static void Dalvik_org_apache_harmony_dalvik_NativeTestTarget_emptyInternalMethod(
+    const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    RETURN_VOID();
+}
+
+const DalvikNativeMethod dvm_org_apache_harmony_dalvik_NativeTestTarget[] =
+{
+    { "emptyInternalStaticMethod", "()V",
+        Dalvik_org_apache_harmony_dalvik_NativeTestTarget_emptyInternalMethod },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.cpp b/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.cpp
new file mode 100644
index 0000000..570d469
--- /dev/null
+++ b/vm/native/org_apache_harmony_dalvik_ddmc_DdmServer.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * org.apache.harmony.dalvik.ddmc.DdmServer
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private static void nativeSendChunk(int type, byte[] data,
+ *      int offset, int length)
+ *
+ * Send a DDM chunk to the server.
+ */
+static void Dalvik_org_apache_harmony_dalvik_ddmc_DdmServer_nativeSendChunk(
+    const u4* args, JValue* pResult)
+{
+    int type = args[0];
+    ArrayObject* data = (ArrayObject*) args[1];
+    int offset = args[2];
+    int length = args[3];
+
+    assert(offset+length <= (int)data->length);
+
+    dvmDbgDdmSendChunk(type, length, (const u1*)data->contents + offset);
+    RETURN_VOID();
+}
+
+const DalvikNativeMethod dvm_org_apache_harmony_dalvik_ddmc_DdmServer[] = {
+    { "nativeSendChunk",    "(I[BII)V",
+        Dalvik_org_apache_harmony_dalvik_ddmc_DdmServer_nativeSendChunk },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cpp b/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cpp
new file mode 100644
index 0000000..eed8ce1
--- /dev/null
+++ b/vm/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+/*
+ * org.apache.harmony.dalvik.ddmc.DdmVmInternal
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * public static void threadNotify(boolean enable)
+ *
+ * Enable DDM thread notifications.
+ */
+static void Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_threadNotify(
+    const u4* args, JValue* pResult)
+{
+    bool enable = (args[0] != 0);
+
+    //LOGI("ddmThreadNotification: %d", enable);
+    dvmDdmSetThreadNotification(enable);
+    RETURN_VOID();
+}
+
+/*
+ * public static byte[] getThreadStats()
+ *
+ * Get a buffer full of thread info.
+ */
+static void Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getThreadStats(
+    const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+
+    ArrayObject* result = dvmDdmGenerateThreadStats();
+    dvmReleaseTrackedAlloc((Object*) result, NULL);
+    RETURN_PTR(result);
+}
+
+/*
+ * public static int heapInfoNotify(int what)
+ *
+ * Enable DDM heap notifications.
+ */
+static void Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_heapInfoNotify(
+    const u4* args, JValue* pResult)
+{
+    int when = args[0];
+    bool ret;
+
+    ret = dvmDdmHandleHpifChunk(when);
+    RETURN_BOOLEAN(ret);
+}
+
+/*
+ * public static boolean heapSegmentNotify(int when, int what, bool native)
+ *
+ * Enable DDM heap notifications.
+ */
+static void
+    Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_heapSegmentNotify(
+    const u4* args, JValue* pResult)
+{
+    int  when   = args[0];        // 0=never (off), 1=during GC
+    int  what   = args[1];        // 0=merged objects, 1=distinct objects
+    bool native = (args[2] != 0); // false=virtual heap, true=native heap
+    bool ret;
+
+    ret = dvmDdmHandleHpsgNhsgChunk(when, what, native);
+    RETURN_BOOLEAN(ret);
+}
+
+/*
+ * public static StackTraceElement[] getStackTraceById(int threadId)
+ *
+ * Get a stack trace as an array of StackTraceElement objects.  Returns
+ * NULL on failure, e.g. if the threadId couldn't be found.
+ */
+static void
+    Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getStackTraceById(
+    const u4* args, JValue* pResult)
+{
+    u4 threadId = args[0];
+    ArrayObject* trace;
+
+    trace = dvmDdmGetStackTraceById(threadId);
+    RETURN_PTR(trace);
+}
+
+/*
+ * public static void enableRecentAllocations(boolean enable)
+ *
+ * Enable or disable recent allocation tracking.
+ */
+static void
+    Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_enableRecentAllocations(
+    const u4* args, JValue* pResult)
+{
+    bool enable = (args[0] != 0);
+
+    if (enable)
+        (void) dvmEnableAllocTracker();
+    else
+        (void) dvmDisableAllocTracker();
+    RETURN_VOID();
+}
+
+/*
+ * public static boolean getRecentAllocationStatus()
+ *
+ * Returns "true" if allocation tracking is enabled.
+ */
+static void
+    Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getRecentAllocationStatus(
+    const u4* args, JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+    RETURN_BOOLEAN(gDvm.allocRecords != NULL);
+}
+
+/*
+ * public static byte[] getRecentAllocations()
+ *
+ * Fill a buffer with data on recent heap allocations.
+ */
+static void
+    Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getRecentAllocations(
+    const u4* args, JValue* pResult)
+{
+    ArrayObject* data;
+
+    data = dvmDdmGetRecentAllocations();
+    dvmReleaseTrackedAlloc((Object*) data, NULL);
+    RETURN_PTR(data);
+}
+
+const DalvikNativeMethod dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal[] = {
+    { "threadNotify",       "(Z)V",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_threadNotify },
+    { "getThreadStats",     "()[B",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getThreadStats },
+    { "heapInfoNotify",     "(I)Z",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_heapInfoNotify },
+    { "heapSegmentNotify",  "(IIZ)Z",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_heapSegmentNotify },
+    { "getStackTraceById",  "(I)[Ljava/lang/StackTraceElement;",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getStackTraceById },
+    { "enableRecentAllocations", "(Z)V",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_enableRecentAllocations },
+    { "getRecentAllocationStatus", "()Z",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getRecentAllocationStatus },
+    { "getRecentAllocations", "()[B",
+      Dalvik_org_apache_harmony_dalvik_ddmc_DdmVmInternal_getRecentAllocations },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/native/sun_misc_Unsafe.cpp b/vm/native/sun_misc_Unsafe.cpp
new file mode 100644
index 0000000..db8493b
--- /dev/null
+++ b/vm/native/sun_misc_Unsafe.cpp
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+
+/*
+ * sun.misc.Unsafe
+ */
+#include "Dalvik.h"
+#include "native/InternalNativePriv.h"
+
+
+/*
+ * private static native long objectFieldOffset0(Field field);
+ */
+static void Dalvik_sun_misc_Unsafe_objectFieldOffset0(const u4* args,
+    JValue* pResult)
+{
+    Object* fieldObject = (Object*) args[0];
+    InstField* field = (InstField*) dvmGetFieldFromReflectObj(fieldObject);
+    s8 result = ((s8) field->byteOffset);
+
+    RETURN_LONG(result);
+}
+
+/*
+ * private static native int arrayBaseOffset0(Class clazz);
+ */
+static void Dalvik_sun_misc_Unsafe_arrayBaseOffset0(const u4* args,
+    JValue* pResult)
+{
+    // The base offset is not type-dependent in this vm.
+    UNUSED_PARAMETER(args);
+    RETURN_INT(OFFSETOF_MEMBER(ArrayObject, contents));
+}
+
+/*
+ * private static native int arrayIndexScale0(Class clazz);
+ */
+static void Dalvik_sun_misc_Unsafe_arrayIndexScale0(const u4* args,
+    JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    RETURN_INT(dvmArrayClassElementWidth(clazz));
+}
+
+/*
+ * public native boolean compareAndSwapInt(Object obj, long offset,
+ *         int expectedValue, int newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_compareAndSwapInt(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s4 expectedValue = args[4];
+    s4 newValue = args[5];
+    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
+
+    // Note: android_atomic_release_cas() returns 0 on success, not failure.
+    int result = android_atomic_release_cas(expectedValue, newValue, address);
+
+    RETURN_BOOLEAN(result == 0);
+}
+
+/*
+ * public native boolean compareAndSwapLong(Object obj, long offset,
+ *         long expectedValue, long newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_compareAndSwapLong(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s8 expectedValue = GET_ARG_LONG(args, 4);
+    s8 newValue = GET_ARG_LONG(args, 6);
+    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
+
+    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
+    int result =
+        dvmQuasiAtomicCas64(expectedValue, newValue, address);
+
+    RETURN_BOOLEAN(result == 0);
+}
+
+/*
+ * public native boolean compareAndSwapObject(Object obj, long offset,
+ *         Object expectedValue, Object newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_compareAndSwapObject(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    Object* expectedValue = (Object*) args[4];
+    Object* newValue = (Object*) args[5];
+    int32_t* address = (int32_t*) (((u1*) obj) + offset);
+
+    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
+    int result = android_atomic_release_cas((int32_t) expectedValue,
+            (int32_t) newValue, address);
+    dvmWriteBarrierField(obj, address);
+    RETURN_BOOLEAN(result == 0);
+}
+
+/*
+ * public native int getIntVolatile(Object obj, long offset);
+ */
+static void Dalvik_sun_misc_Unsafe_getIntVolatile(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
+
+    int32_t value = android_atomic_acquire_load(address);
+    RETURN_INT(value);
+}
+
+/*
+ * public native void putIntVolatile(Object obj, long offset, int newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putIntVolatile(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s4 value = (s4) args[4];
+    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
+
+    android_atomic_release_store(value, address);
+    RETURN_VOID();
+}
+
+/*
+ * public native long getLongVolatile(Object obj, long offset);
+ */
+static void Dalvik_sun_misc_Unsafe_getLongVolatile(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
+
+    assert((offset & 7) == 0);
+    RETURN_LONG(dvmQuasiAtomicRead64(address));
+}
+
+/*
+ * public native void putLongVolatile(Object obj, long offset, long newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putLongVolatile(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s8 value = GET_ARG_LONG(args, 4);
+    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
+
+    assert((offset & 7) == 0);
+    dvmQuasiAtomicSwap64(value, address);
+    RETURN_VOID();
+}
+
+/*
+ * public native Object getObjectVolatile(Object obj, long offset);
+ */
+static void Dalvik_sun_misc_Unsafe_getObjectVolatile(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
+
+    RETURN_PTR((Object*) android_atomic_acquire_load(address));
+}
+
+/*
+ * public native void putObjectVolatile(Object obj, long offset,
+ *         Object newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putObjectVolatile(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    Object* value = (Object*) args[4];
+    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
+
+    android_atomic_release_store((int32_t)value, address);
+    dvmWriteBarrierField(obj, (void *)address);
+    RETURN_VOID();
+}
+
+/*
+ * public native int getInt(Object obj, long offset);
+ */
+static void Dalvik_sun_misc_Unsafe_getInt(const u4* args, JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s4* address = (s4*) (((u1*) obj) + offset);
+
+    RETURN_INT(*address);
+}
+
+/*
+ * public native void putInt(Object obj, long offset, int newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putInt(const u4* args, JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s4 value = (s4) args[4];
+    s4* address = (s4*) (((u1*) obj) + offset);
+
+    *address = value;
+    RETURN_VOID();
+}
+
+/*
+ * public native void putOrderedInt(Object obj, long offset, int newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putOrderedInt(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s4 value = (s4) args[4];
+    s4* address = (s4*) (((u1*) obj) + offset);
+
+    ANDROID_MEMBAR_STORE();
+    *address = value;
+    RETURN_VOID();
+}
+
+/*
+ * public native long getLong(Object obj, long offset);
+ */
+static void Dalvik_sun_misc_Unsafe_getLong(const u4* args, JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s8* address = (s8*) (((u1*) obj) + offset);
+
+    RETURN_LONG(*address);
+}
+
+/*
+ * public native void putLong(Object obj, long offset, long newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putLong(const u4* args, JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s8 value = GET_ARG_LONG(args, 4);
+    s8* address = (s8*) (((u1*) obj) + offset);
+
+    *address = value;
+    RETURN_VOID();
+}
+
+/*
+ * public native void putOrderedLong(Object obj, long offset, long newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putOrderedLong(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    s8 value = GET_ARG_LONG(args, 4);
+    s8* address = (s8*) (((u1*) obj) + offset);
+
+    ANDROID_MEMBAR_STORE();
+    *address = value;
+    RETURN_VOID();
+}
+
+/*
+ * public native Object getObject(Object obj, long offset);
+ */
+static void Dalvik_sun_misc_Unsafe_getObject(const u4* args, JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    Object** address = (Object**) (((u1*) obj) + offset);
+
+    RETURN_PTR(*address);
+}
+
+/*
+ * public native void putObject(Object obj, long offset, Object newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putObject(const u4* args, JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    Object* value = (Object*) args[4];
+    Object** address = (Object**) (((u1*) obj) + offset);
+
+    *address = value;
+    dvmWriteBarrierField(obj, address);
+    RETURN_VOID();
+}
+
+/*
+ * public native void putOrderedObject(Object obj, long offset,
+ *      Object newValue);
+ */
+static void Dalvik_sun_misc_Unsafe_putOrderedObject(const u4* args,
+    JValue* pResult)
+{
+    // We ignore the this pointer in args[0].
+    Object* obj = (Object*) args[1];
+    s8 offset = GET_ARG_LONG(args, 2);
+    Object* value = (Object*) args[4];
+    Object** address = (Object**) (((u1*) obj) + offset);
+
+    ANDROID_MEMBAR_STORE();
+    *address = value;
+    dvmWriteBarrierField(obj, address);
+    RETURN_VOID();
+}
+
+const DalvikNativeMethod dvm_sun_misc_Unsafe[] = {
+    { "objectFieldOffset0", "(Ljava/lang/reflect/Field;)J",
+      Dalvik_sun_misc_Unsafe_objectFieldOffset0 },
+    { "arrayBaseOffset0", "(Ljava/lang/Class;)I",
+      Dalvik_sun_misc_Unsafe_arrayBaseOffset0 },
+    { "arrayIndexScale0", "(Ljava/lang/Class;)I",
+      Dalvik_sun_misc_Unsafe_arrayIndexScale0 },
+    { "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
+      Dalvik_sun_misc_Unsafe_compareAndSwapInt },
+    { "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z",
+      Dalvik_sun_misc_Unsafe_compareAndSwapLong },
+    { "compareAndSwapObject",
+      "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
+      Dalvik_sun_misc_Unsafe_compareAndSwapObject },
+    { "getIntVolatile", "(Ljava/lang/Object;J)I",
+      Dalvik_sun_misc_Unsafe_getIntVolatile },
+    { "putIntVolatile", "(Ljava/lang/Object;JI)V",
+      Dalvik_sun_misc_Unsafe_putIntVolatile },
+    { "getLongVolatile", "(Ljava/lang/Object;J)J",
+      Dalvik_sun_misc_Unsafe_getLongVolatile },
+    { "putLongVolatile", "(Ljava/lang/Object;JJ)V",
+      Dalvik_sun_misc_Unsafe_putLongVolatile },
+    { "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;",
+      Dalvik_sun_misc_Unsafe_getObjectVolatile },
+    { "putObjectVolatile", "(Ljava/lang/Object;JLjava/lang/Object;)V",
+      Dalvik_sun_misc_Unsafe_putObjectVolatile },
+    { "getInt", "(Ljava/lang/Object;J)I",
+      Dalvik_sun_misc_Unsafe_getInt },
+    { "putInt", "(Ljava/lang/Object;JI)V",
+      Dalvik_sun_misc_Unsafe_putInt },
+    { "putOrderedInt", "(Ljava/lang/Object;JI)V",
+      Dalvik_sun_misc_Unsafe_putOrderedInt },
+    { "getLong", "(Ljava/lang/Object;J)J",
+      Dalvik_sun_misc_Unsafe_getLong },
+    { "putLong", "(Ljava/lang/Object;JJ)V",
+      Dalvik_sun_misc_Unsafe_putLong },
+    { "putOrderedLong", "(Ljava/lang/Object;JJ)V",
+      Dalvik_sun_misc_Unsafe_putOrderedLong },
+    { "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;",
+      Dalvik_sun_misc_Unsafe_getObject },
+    { "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V",
+      Dalvik_sun_misc_Unsafe_putObject },
+    { "putOrderedObject", "(Ljava/lang/Object;JLjava/lang/Object;)V",
+      Dalvik_sun_misc_Unsafe_putOrderedObject },
+    { NULL, NULL, NULL },
+};
diff --git a/vm/oo/AccessCheck.cpp b/vm/oo/AccessCheck.cpp
new file mode 100644
index 0000000..c50bc45
--- /dev/null
+++ b/vm/oo/AccessCheck.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+/*
+ * Check access to fields and methods.
+ */
+#include "Dalvik.h"
+
+/*
+ * Return the #of initial characters that match.
+ */
+static int strcmpCount(const char* str1, const char* str2)
+{
+    int count = 0;
+
+    while (true) {
+        char ch = str1[count];
+        if (ch == '\0' || ch != str2[count])
+            return count;
+        count++;
+    }
+}
+
+/*
+ * Returns "true" if the two classes are in the same runtime package.
+ */
+bool dvmInSamePackage(const ClassObject* class1, const ClassObject* class2)
+{
+    /* quick test for intra-class access */
+    if (class1 == class2)
+        return true;
+
+    /* class loaders must match */
+    if (class1->classLoader != class2->classLoader)
+        return false;
+
+    /*
+     * Switch array classes to their element types.  Arrays receive the
+     * class loader of the underlying element type.  The point of doing
+     * this is to get the un-decorated class name, without all the
+     * "[[L...;" stuff.
+     */
+    if (dvmIsArrayClass(class1))
+        class1 = class1->elementClass;
+    if (dvmIsArrayClass(class2))
+        class2 = class2->elementClass;
+
+    /* check again */
+    if (class1 == class2)
+        return true;
+
+    /*
+     * We have two classes with different names.  Compare them and see
+     * if they match up through the final '/'.
+     *
+     *  Ljava/lang/Object; + Ljava/lang/Class;          --> true
+     *  LFoo;              + LBar;                      --> true
+     *  Ljava/lang/Object; + Ljava/io/File;             --> false
+     *  Ljava/lang/Object; + Ljava/lang/reflect/Method; --> false
+     */
+    int commonLen;
+
+    commonLen = strcmpCount(class1->descriptor, class2->descriptor);
+    if (strchr(class1->descriptor + commonLen, '/') != NULL ||
+        strchr(class2->descriptor + commonLen, '/') != NULL)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Validate method/field access.
+ */
+static bool checkAccess(const ClassObject* accessFrom,
+    const ClassObject* accessTo, u4 accessFlags)
+{
+    /* quick accept for public access */
+    if (accessFlags & ACC_PUBLIC)
+        return true;
+
+    /* quick accept for access from same class */
+    if (accessFrom == accessTo)
+        return true;
+
+    /* quick reject for private access from another class */
+    if (accessFlags & ACC_PRIVATE)
+        return false;
+
+    /*
+     * Semi-quick test for protected access from a sub-class, which may or
+     * may not be in the same package.
+     */
+    if (accessFlags & ACC_PROTECTED)
+        if (dvmIsSubClass(accessFrom, accessTo))
+            return true;
+
+    /*
+     * Allow protected and private access from other classes in the same
+     * package.
+     */
+    return dvmInSamePackage(accessFrom, accessTo);
+}
+
+/*
+ * Determine whether the "accessFrom" class is allowed to get at "clazz".
+ *
+ * It's allowed if "clazz" is public or is in the same package.  (Only
+ * inner classes can be marked "private" or "protected", so we don't need
+ * to check for it here.)
+ */
+bool dvmCheckClassAccess(const ClassObject* accessFrom,
+    const ClassObject* clazz)
+{
+    if (dvmIsPublicClass(clazz))
+        return true;
+    return dvmInSamePackage(accessFrom, clazz);
+}
+
+/*
+ * Determine whether the "accessFrom" class is allowed to get at "method".
+ */
+bool dvmCheckMethodAccess(const ClassObject* accessFrom, const Method* method)
+{
+    return checkAccess(accessFrom, method->clazz, method->accessFlags);
+}
+
+/*
+ * Determine whether the "accessFrom" class is allowed to get at "field".
+ */
+bool dvmCheckFieldAccess(const ClassObject* accessFrom, const Field* field)
+{
+    //LOGI("CHECK ACCESS from '%s' to field '%s' (in %s) flags=%#x",
+    //    accessFrom->descriptor, field->name,
+    //    field->clazz->descriptor, field->accessFlags);
+    return checkAccess(accessFrom, field->clazz, field->accessFlags);
+}
diff --git a/vm/oo/AccessCheck.h b/vm/oo/AccessCheck.h
new file mode 100644
index 0000000..61d1650
--- /dev/null
+++ b/vm/oo/AccessCheck.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+/*
+ * Check access to fields and methods.
+ */
+#ifndef DALVIK_OO_ACCESSCHECK_H_
+#define DALVIK_OO_ACCESSCHECK_H_
+
+/*
+ * Determine whether the "accessFrom" class is allowed to get at "clazz".
+ */
+bool dvmCheckClassAccess(const ClassObject* accessFrom,
+    const ClassObject* clazz);
+
+/*
+ * Determine whether the "accessFrom" class is allowed to get at "method".
+ */
+bool dvmCheckMethodAccess(const ClassObject* accessFrom, const Method* method);
+
+/*
+ * Determine whether the "accessFrom" class is allowed to get at "field".
+ */
+bool dvmCheckFieldAccess(const ClassObject* accessFrom, const Field* field);
+
+/*
+ * Returns "true" if the two classes are in the same runtime package.
+ */
+bool dvmInSamePackage(const ClassObject* class1, const ClassObject* class2);
+
+#endif  // DALVIK_OO_ACCESSCHECK_H_
diff --git a/vm/oo/Array.cpp b/vm/oo/Array.cpp
new file mode 100644
index 0000000..9fc9142
--- /dev/null
+++ b/vm/oo/Array.cpp
@@ -0,0 +1,629 @@
+/*
+ * 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.
+ */
+/*
+ * Array objects.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+
+/* width of an object reference, for arrays of objects */
+static size_t kObjectArrayRefWidth = sizeof(Object*);
+
+static ClassObject* createArrayClass(const char* descriptor, Object* loader);
+
+/*
+ * Allocate space for a new array object.  This is the lowest-level array
+ * allocation function.
+ *
+ * Pass in the array class and the width of each element.
+ *
+ * On failure, returns NULL with an exception raised.
+ */
+static ArrayObject* allocArray(ClassObject* arrayClass, size_t length,
+    size_t elemWidth, int allocFlags)
+{
+    assert(arrayClass != NULL);
+    assert(arrayClass->descriptor != NULL);
+    assert(arrayClass->descriptor[0] == '[');
+    assert(length <= 0x7fffffff);
+    assert(elemWidth > 0);
+    assert(elemWidth <= 8);
+    assert((elemWidth & (elemWidth - 1)) == 0);
+    size_t elementShift = sizeof(size_t) * CHAR_BIT - 1 - CLZ(elemWidth);
+    size_t elementSize = length << elementShift;
+    size_t headerSize = OFFSETOF_MEMBER(ArrayObject, contents);
+    size_t totalSize = elementSize + headerSize;
+    if (elementSize >> elementShift != length || totalSize < elementSize) {
+        std::string descriptor(dvmHumanReadableDescriptor(arrayClass->descriptor));
+        dvmThrowExceptionFmt(gDvm.exOutOfMemoryError,
+                "%s of length %zd exceeds the VM limit", descriptor.c_str(), length);
+        return NULL;
+    }
+    ArrayObject* newArray = (ArrayObject*)dvmMalloc(totalSize, allocFlags);
+    if (newArray != NULL) {
+        DVM_OBJECT_INIT(newArray, arrayClass);
+        newArray->length = length;
+        dvmTrackAllocation(arrayClass, totalSize);
+    }
+    return newArray;
+}
+
+/*
+ * Create a new array, given an array class.  The class may represent an
+ * array of references or primitives.
+ */
+ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass,
+    size_t length, int allocFlags)
+{
+    const char* descriptor = arrayClass->descriptor;
+
+    assert(descriptor[0] == '[');       /* must be array class */
+    if (descriptor[1] != '[' && descriptor[1] != 'L') {
+        /* primitive array */
+        assert(descriptor[2] == '\0');
+        return dvmAllocPrimitiveArray(descriptor[1], length, allocFlags);
+    } else {
+        return allocArray(arrayClass, length, kObjectArrayRefWidth,
+            allocFlags);
+    }
+}
+
+/*
+ * Find the array class for "elemClassObj", which could itself be an
+ * array class.
+ */
+ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj)
+{
+    ClassObject* arrayClass;
+
+    assert(elemClassObj != NULL);
+
+    /* Simply prepend "[" to the descriptor. */
+    int nameLen = strlen(elemClassObj->descriptor);
+    char className[nameLen + 2];
+
+    className[0] = '[';
+    memcpy(className+1, elemClassObj->descriptor, nameLen+1);
+    arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader);
+
+    return arrayClass;
+}
+
+/*
+ * Create a new array that holds primitive types.
+ *
+ * "type" is the primitive type letter, e.g. 'I' for int or 'J' for long.
+ */
+ArrayObject* dvmAllocPrimitiveArray(char type, size_t length, int allocFlags)
+{
+    ArrayObject* newArray;
+    ClassObject* arrayClass;
+    int width;
+
+    switch (type) {
+    case 'I':
+        arrayClass = gDvm.classArrayInt;
+        width = 4;
+        break;
+    case 'C':
+        arrayClass = gDvm.classArrayChar;
+        width = 2;
+        break;
+    case 'B':
+        arrayClass = gDvm.classArrayByte;
+        width = 1;
+        break;
+    case 'Z':
+        arrayClass = gDvm.classArrayBoolean;
+        width = 1; /* special-case this? */
+        break;
+    case 'F':
+        arrayClass = gDvm.classArrayFloat;
+        width = 4;
+        break;
+    case 'D':
+        arrayClass = gDvm.classArrayDouble;
+        width = 8;
+        break;
+    case 'S':
+        arrayClass = gDvm.classArrayShort;
+        width = 2;
+        break;
+    case 'J':
+        arrayClass = gDvm.classArrayLong;
+        width = 8;
+        break;
+    default:
+        LOGE("Unknown primitive type '%c'", type);
+        dvmAbort();
+        return NULL; // Keeps the compiler happy.
+    }
+
+    newArray = allocArray(arrayClass, length, width, allocFlags);
+
+    /* the caller must dvmReleaseTrackedAlloc if allocFlags==ALLOC_DEFAULT */
+    return newArray;
+}
+
+/*
+ * Recursively create an array with multiple dimensions.  Elements may be
+ * Objects or primitive types.
+ *
+ * The dimension we're creating is in dimensions[0], so when we recurse
+ * we advance the pointer.
+ */
+ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim,
+    const int* dimensions)
+{
+    ArrayObject* newArray;
+    const char* elemName = arrayClass->descriptor + 1; // Advance past one '['.
+
+    LOGVV("dvmAllocMultiArray: class='%s' curDim=%d *dimensions=%d",
+        arrayClass->descriptor, curDim, *dimensions);
+
+    if (curDim == 0) {
+        if (*elemName == 'L' || *elemName == '[') {
+            LOGVV("  end: array class (obj) is '%s'",
+                arrayClass->descriptor);
+            newArray = allocArray(arrayClass, *dimensions,
+                        kObjectArrayRefWidth, ALLOC_DEFAULT);
+        } else {
+            LOGVV("  end: array class (prim) is '%s'",
+                arrayClass->descriptor);
+            newArray = dvmAllocPrimitiveArray(
+                    dexGetPrimitiveTypeDescriptorChar(arrayClass->elementClass->primitiveType),
+                    *dimensions, ALLOC_DEFAULT);
+        }
+    } else {
+        ClassObject* subArrayClass;
+        int i;
+
+        /* if we have X[][], find X[] */
+        subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader);
+        if (subArrayClass == NULL) {
+            /* not enough '['s on the initial class? */
+            assert(dvmCheckException(dvmThreadSelf()));
+            return NULL;
+        }
+        assert(dvmIsArrayClass(subArrayClass));
+
+        /* allocate the array that holds the sub-arrays */
+        newArray = allocArray(arrayClass, *dimensions, kObjectArrayRefWidth,
+                        ALLOC_DEFAULT);
+        if (newArray == NULL) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            return NULL;
+        }
+
+        /*
+         * Create a new sub-array in every element of the array.
+         */
+        for (i = 0; i < *dimensions; i++) {
+          ArrayObject* newSubArray;
+          newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
+                          dimensions+1);
+            if (newSubArray == NULL) {
+                dvmReleaseTrackedAlloc((Object*) newArray, NULL);
+                assert(dvmCheckException(dvmThreadSelf()));
+                return NULL;
+            }
+            dvmSetObjectArrayElement(newArray, i, (Object *)newSubArray);
+            dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
+        }
+    }
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return newArray;
+}
+
+
+/*
+ * Find an array class, by name (e.g. "[I").
+ *
+ * If the array class doesn't exist, we generate it.
+ *
+ * If the element class doesn't exist, we return NULL (no exception raised).
+ */
+ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader)
+{
+    ClassObject* clazz;
+
+    assert(descriptor[0] == '[');
+    //LOGV("dvmFindArrayClass: '%s' %p", descriptor, loader);
+
+    clazz = dvmLookupClass(descriptor, loader, false);
+    if (clazz == NULL) {
+        LOGV("Array class '%s' %p not found; creating", descriptor, loader);
+        clazz = createArrayClass(descriptor, loader);
+        if (clazz != NULL)
+            dvmAddInitiatingLoader(clazz, loader);
+    }
+
+    return clazz;
+}
+
+/*
+ * Create an array class (i.e. the class object for the array, not the
+ * array itself).  "descriptor" looks like "[C" or "[Ljava/lang/String;".
+ *
+ * If "descriptor" refers to an array of primitives, look up the
+ * primitive type's internally-generated class object.
+ *
+ * "loader" is the class loader of the class that's referring to us.  It's
+ * used to ensure that we're looking for the element type in the right
+ * context.  It does NOT become the class loader for the array class; that
+ * always comes from the base element class.
+ *
+ * Returns NULL with an exception raised on failure.
+ */
+static ClassObject* createArrayClass(const char* descriptor, Object* loader)
+{
+    ClassObject* newClass = NULL;
+    ClassObject* elementClass = NULL;
+    int arrayDim;
+    u4 extraFlags;
+
+    assert(descriptor[0] == '[');
+    assert(gDvm.classJavaLangClass != NULL);
+    assert(gDvm.classJavaLangObject != NULL);
+
+    /*
+     * Identify the underlying element class and the array dimension depth.
+     */
+    extraFlags = CLASS_ISARRAY;
+    if (descriptor[1] == '[') {
+        /* array of arrays; keep descriptor and grab stuff from parent */
+        ClassObject* outer;
+
+        outer = dvmFindClassNoInit(&descriptor[1], loader);
+        if (outer != NULL) {
+            /* want the base class, not "outer", in our elementClass */
+            elementClass = outer->elementClass;
+            arrayDim = outer->arrayDim + 1;
+            extraFlags |= CLASS_ISOBJECTARRAY;
+        } else {
+            assert(elementClass == NULL);     /* make sure we fail */
+        }
+    } else {
+        arrayDim = 1;
+        if (descriptor[1] == 'L') {
+            /* array of objects; strip off "[" and look up descriptor. */
+            const char* subDescriptor = &descriptor[1];
+            LOGVV("searching for element class '%s'", subDescriptor);
+            elementClass = dvmFindClassNoInit(subDescriptor, loader);
+            extraFlags |= CLASS_ISOBJECTARRAY;
+        } else {
+            /* array of a primitive type */
+            elementClass = dvmFindPrimitiveClass(descriptor[1]);
+        }
+    }
+
+    if (elementClass == NULL) {
+        /* failed */
+        assert(dvmCheckException(dvmThreadSelf()));
+        dvmFreeClassInnards(newClass);
+        dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+        return NULL;
+    }
+
+    /*
+     * See if it's already loaded.  Array classes are always associated
+     * with the class loader of their underlying element type -- an array
+     * of Strings goes with the loader for java/lang/String -- so we need
+     * to look for it there.  (The caller should have checked for the
+     * existence of the class before calling here, but they did so with
+     * *their* class loader, not the element class' loader.)
+     *
+     * If we find it, the caller adds "loader" to the class' initiating
+     * loader list, which should prevent us from going through this again.
+     *
+     * This call is unnecessary if "loader" and "elementClass->classLoader"
+     * are the same, because our caller (dvmFindArrayClass) just did the
+     * lookup.  (Even if we get this wrong we still have correct behavior,
+     * because we effectively do this lookup again when we add the new
+     * class to the hash table -- necessary because of possible races with
+     * other threads.)
+     */
+    if (loader != elementClass->classLoader) {
+        LOGVV("--- checking for '%s' in %p vs. elem %p",
+            descriptor, loader, elementClass->classLoader);
+        newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
+        if (newClass != NULL) {
+            LOGV("--- we already have %s in %p, don't need in %p",
+                descriptor, elementClass->classLoader, loader);
+            return newClass;
+        }
+    }
+
+
+    /*
+     * Fill out the fields in the ClassObject.
+     *
+     * It is possible to execute some methods against arrays, because all
+     * arrays are instances of Object, so we need to set up a vtable.  We
+     * can just point at the one in Object.
+     *
+     * Array classes are simple enough that we don't need to do a full
+     * link step.
+     */
+    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_NON_MOVING);
+    if (newClass == NULL)
+        return NULL;
+    DVM_OBJECT_INIT(newClass, gDvm.classJavaLangClass);
+    dvmSetClassSerialNumber(newClass);
+    newClass->descriptorAlloc = strdup(descriptor);
+    newClass->descriptor = newClass->descriptorAlloc;
+    dvmSetFieldObject((Object *)newClass,
+                      OFFSETOF_MEMBER(ClassObject, super),
+                      (Object *)gDvm.classJavaLangObject);
+    newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
+    newClass->vtable = gDvm.classJavaLangObject->vtable;
+    newClass->primitiveType = PRIM_NOT;
+    dvmSetFieldObject((Object *)newClass,
+                      OFFSETOF_MEMBER(ClassObject, elementClass),
+                      (Object *)elementClass);
+    dvmSetFieldObject((Object *)newClass,
+                      OFFSETOF_MEMBER(ClassObject, classLoader),
+                      (Object *)elementClass->classLoader);
+    newClass->arrayDim = arrayDim;
+    newClass->status = CLASS_INITIALIZED;
+
+    /* don't need to set newClass->objectSize */
+
+    /*
+     * All arrays have java/lang/Cloneable and java/io/Serializable as
+     * interfaces.  We need to set that up here, so that stuff like
+     * "instanceof" works right.
+     *
+     * Note: The GC could run during the call to dvmFindSystemClassNoInit(),
+     * so we need to make sure the class object is GC-valid while we're in
+     * there.  Do this by clearing the interface list so the GC will just
+     * think that the entries are null.
+     *
+     * TODO?
+     * We may want to cache these two classes to avoid the lookup, though
+     * it's not vital -- we only do it when creating an array class, not
+     * every time we create an array.  Better yet, create a single, global
+     * copy of "interfaces" and "iftable" somewhere near the start and
+     * just point to those (and remember not to free them for arrays).
+     */
+    newClass->interfaceCount = 2;
+    newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader,
+                                sizeof(ClassObject*) * 2);
+    memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2);
+    newClass->interfaces[0] =
+        dvmFindSystemClassNoInit("Ljava/lang/Cloneable;");
+    newClass->interfaces[1] =
+        dvmFindSystemClassNoInit("Ljava/io/Serializable;");
+    dvmLinearReadOnly(newClass->classLoader, newClass->interfaces);
+    if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) {
+        LOGE("Unable to create array class '%s': missing interfaces",
+            descriptor);
+        dvmFreeClassInnards(newClass);
+        dvmThrowInternalError("missing array ifaces");
+        dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+        return NULL;
+    }
+    /*
+     * We assume that Cloneable/Serializable don't have superinterfaces --
+     * normally we'd have to crawl up and explicitly list all of the
+     * supers as well.  These interfaces don't have any methods, so we
+     * don't have to worry about the ifviPool either.
+     */
+    newClass->iftableCount = 2;
+    newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader,
+                                sizeof(InterfaceEntry) * 2);
+    memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2);
+    newClass->iftable[0].clazz = newClass->interfaces[0];
+    newClass->iftable[1].clazz = newClass->interfaces[1];
+    dvmLinearReadOnly(newClass->classLoader, newClass->iftable);
+
+    /*
+     * Inherit access flags from the element.  Arrays can't be used as a
+     * superclass or interface, so we want to add "final" and remove
+     * "interface".
+     *
+     * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE)
+     * from elementClass.  We assume that the array class does not
+     * override finalize().
+     */
+    newClass->accessFlags = ((newClass->elementClass->accessFlags &
+                             ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK;
+
+    /* Set the flags we determined above.
+     * This must happen after accessFlags is set.
+     */
+    SET_CLASS_FLAG(newClass, extraFlags);
+
+    if (!dvmAddClassToHash(newClass)) {
+        /*
+         * Another thread must have loaded the class after we
+         * started but before we finished.  Discard what we've
+         * done and leave some hints for the GC.
+         *
+         * (Yes, this happens.)
+         */
+
+        /* Clean up the class before letting the
+         * GC get its hands on it.
+         */
+        dvmFreeClassInnards(newClass);
+
+        /* Let the GC free the class.
+         */
+        dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+
+        /* Grab the winning class.
+         */
+        newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
+        assert(newClass != NULL);
+        return newClass;
+    }
+    dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+
+    LOGV("Created array class '%s' %p (access=0x%04x.%04x)",
+        descriptor, newClass->classLoader,
+        newClass->accessFlags >> 16,
+        newClass->accessFlags & JAVA_FLAGS_MASK);
+
+    return newClass;
+}
+
+/*
+ * Copy the entire contents of one array of objects to another.  If the copy
+ * is impossible because of a type clash, we fail and return "false".
+ */
+bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+    ClassObject* dstElemClass)
+{
+    Object** src = (Object**)(void*)srcArray->contents;
+    u4 length, count;
+
+    assert(srcArray->length == dstArray->length);
+    assert(dstArray->clazz->elementClass == dstElemClass ||
+        (dstArray->clazz->elementClass == dstElemClass->elementClass &&
+         dstArray->clazz->arrayDim == dstElemClass->arrayDim+1));
+
+    length = dstArray->length;
+    for (count = 0; count < length; count++) {
+        if (!dvmInstanceof(src[count]->clazz, dstElemClass)) {
+            LOGW("dvmCopyObjectArray: can't store %s in %s",
+                src[count]->clazz->descriptor, dstElemClass->descriptor);
+            return false;
+        }
+        dvmSetObjectArrayElement(dstArray, count, src[count]);
+    }
+
+    return true;
+}
+
+/*
+ * Copy the entire contents of an array of boxed primitives into an
+ * array of primitives.  The boxed value must fit in the primitive (i.e.
+ * narrowing conversions are not allowed).
+ */
+bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+    ClassObject* dstElemClass)
+{
+    Object** src = (Object**)(void*)srcArray->contents;
+    void* dst = (void*)dstArray->contents;
+    u4 count = dstArray->length;
+    PrimitiveType typeIndex = dstElemClass->primitiveType;
+
+    assert(typeIndex != PRIM_NOT);
+    assert(srcArray->length == dstArray->length);
+
+    while (count--) {
+        JValue result;
+
+        /*
+         * This will perform widening conversions as appropriate.  It
+         * might make sense to be more restrictive and require that the
+         * primitive type exactly matches the box class, but it's not
+         * necessary for correctness.
+         */
+        if (!dvmUnboxPrimitive(*src, dstElemClass, &result)) {
+            LOGW("dvmCopyObjectArray: can't store %s in %s",
+                (*src)->clazz->descriptor, dstElemClass->descriptor);
+            return false;
+        }
+
+        /* would be faster with 4 loops, but speed not crucial here */
+        switch (typeIndex) {
+        case PRIM_BOOLEAN:
+        case PRIM_BYTE:
+            {
+                u1* tmp = (u1*)dst;
+                *tmp++ = result.b;
+                dst = tmp;
+            }
+            break;
+        case PRIM_CHAR:
+        case PRIM_SHORT:
+            {
+                u2* tmp = (u2*)dst;
+                *tmp++ = result.s;
+                dst = tmp;
+            }
+            break;
+        case PRIM_FLOAT:
+        case PRIM_INT:
+            {
+                u4* tmp = (u4*)dst;
+                *tmp++ = result.i;
+                dst = tmp;
+            }
+            break;
+        case PRIM_DOUBLE:
+        case PRIM_LONG:
+            {
+                u8* tmp = (u8*)dst;
+                *tmp++ = result.j;
+                dst = tmp;
+            }
+            break;
+        default:
+            /* should not be possible to get here */
+            dvmAbort();
+        }
+
+        src++;
+    }
+
+    return true;
+}
+
+/*
+ * Returns the width, in bytes, required by elements in instances of
+ * the array class.
+ */
+size_t dvmArrayClassElementWidth(const ClassObject* arrayClass)
+{
+    const char *descriptor;
+
+    assert(dvmIsArrayClass(arrayClass));
+
+    if (dvmIsObjectArrayClass(arrayClass)) {
+        return sizeof(Object *);
+    } else {
+        descriptor = arrayClass->descriptor;
+        switch (descriptor[1]) {
+        case 'B': return 1;  /* byte */
+        case 'C': return 2;  /* char */
+        case 'D': return 8;  /* double */
+        case 'F': return 4;  /* float */
+        case 'I': return 4;  /* int */
+        case 'J': return 8;  /* long */
+        case 'S': return 2;  /* short */
+        case 'Z': return 1;  /* boolean */
+        }
+    }
+    LOGE("class %p has an unhandled descriptor '%s'", arrayClass, descriptor);
+    dvmDumpThread(dvmThreadSelf(), false);
+    dvmAbort();
+    return 0;  /* Quiet the compiler. */
+}
+
+size_t dvmArrayObjectSize(const ArrayObject *array)
+{
+    assert(array != NULL);
+    size_t size = OFFSETOF_MEMBER(ArrayObject, contents);
+    size += array->length * dvmArrayClassElementWidth(array->clazz);
+    return size;
+}
diff --git a/vm/oo/Array.h b/vm/oo/Array.h
new file mode 100644
index 0000000..5390b1d
--- /dev/null
+++ b/vm/oo/Array.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+/*
+ * Array handling.
+ */
+#ifndef DALVIK_OO_ARRAY_H_
+#define DALVIK_OO_ARRAY_H_
+
+/*
+ * Find a matching array class.  If it doesn't exist, create it.
+ *
+ * "descriptor" looks like "[I".
+ *
+ * "loader" should be the defining class loader for the elements held
+ * in the array.
+ */
+ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader);
+
+/*
+ * Find the array class for the specified class.  If "elemClassObj" is the
+ * class "Foo", this returns the class object for "[Foo".
+ */
+ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj);
+
+/*
+ * Create a new array, given an array class.  The class may represent an
+ * array of references or primitives.
+ *
+ * Returns NULL with an exception raised if allocation fails.
+ */
+extern "C" ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass,
+    size_t length, int allocFlags);
+
+/*
+ * Allocate an array whose members are primitives (bools, ints, etc.).
+ *
+ * "type" should be 'I', 'J', 'Z', etc.
+ *
+ * The new object will be added to the "tracked alloc" table.
+ *
+ * Returns NULL with an exception raised if allocation fails.
+ */
+ArrayObject* dvmAllocPrimitiveArray(char type, size_t length, int allocFlags);
+
+/*
+ * Allocate an array with multiple dimensions.  Elements may be Objects or
+ * primitive types.
+ *
+ * The base object will be added to the "tracked alloc" table.
+ *
+ * Returns NULL with an exception raised if allocation fails.
+ */
+ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim,
+    const int* dimensions);
+
+/*
+ * Verify that the object is actually an array.
+ *
+ * Does not verify that the object is actually a non-NULL object.
+ */
+INLINE bool dvmIsArray(const ArrayObject* arrayObj)
+{
+    return ( ((Object*)arrayObj)->clazz->descriptor[0] == '[' );
+}
+
+/*
+ * Verify that the array is an object array and not a primitive array.
+ *
+ * Does not verify that the object is actually a non-NULL object.
+ */
+INLINE bool dvmIsObjectArrayClass(const ClassObject* clazz)
+{
+    const char* descriptor = clazz->descriptor;
+    return descriptor[0] == '[' && (descriptor[1] == 'L' ||
+                                    descriptor[1] == '[');
+}
+
+/*
+ * Verify that the array is an object array and not a primitive array.
+ *
+ * Does not verify that the object is actually a non-NULL object.
+ */
+INLINE bool dvmIsObjectArray(const ArrayObject* arrayObj)
+{
+    return dvmIsObjectArrayClass(arrayObj->clazz);
+}
+
+/*
+ * Verify that the class is an array class.
+ *
+ * TODO: there may be some performance advantage to setting a flag in
+ * the accessFlags field instead of chasing into the name string.
+ */
+INLINE bool dvmIsArrayClass(const ClassObject* clazz)
+{
+    return (clazz->descriptor[0] == '[');
+}
+
+/*
+ * Copy the entire contents of one array of objects to another.  If the copy
+ * is impossible because of a type clash, we fail and return "false".
+ *
+ * "dstElemClass" is the type of element that "dstArray" holds.
+ */
+bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+    ClassObject* dstElemClass);
+
+/*
+ * Copy the entire contents of an array of boxed primitives into an
+ * array of primitives.  The boxed value must fit in the primitive (i.e.
+ * narrowing conversions are not allowed).
+ */
+bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+    ClassObject* dstElemClass);
+
+/*
+ * Returns the size of the given array object in bytes.
+ */
+size_t dvmArrayObjectSize(const ArrayObject *array);
+
+/*
+ * Returns the width, in bytes, required by elements in instances of
+ * the array class.
+ */
+size_t dvmArrayClassElementWidth(const ClassObject* clazz);
+
+#endif  // DALVIK_OO_ARRAY_H_
diff --git a/vm/oo/Class.cpp b/vm/oo/Class.cpp
new file mode 100644
index 0000000..85a3bbd
--- /dev/null
+++ b/vm/oo/Class.cpp
@@ -0,0 +1,4903 @@
+/*
+ * 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.
+ */
+
+/*
+ * Class loading, including bootstrap class loader, linking, and
+ * initialization.
+ */
+
+#define LOG_CLASS_LOADING 0
+
+#include "Dalvik.h"
+#include "libdex/DexClass.h"
+#include "analysis/Optimize.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+#if LOG_CLASS_LOADING
+#include <unistd.h>
+#include <pthread.h>
+#include <cutils/process_name.h>
+#include <sys/types.h>
+#endif
+
+/*
+Notes on Linking and Verification
+
+The basic way to retrieve a class is to load it, make sure its superclass
+and interfaces are available, prepare its fields, and return it.  This gets
+a little more complicated when multiple threads can be trying to retrieve
+the class simultaneously, requiring that we use the class object's monitor
+to keep things orderly.
+
+The linking (preparing, resolving) of a class can cause us to recursively
+load superclasses and interfaces.  Barring circular references (e.g. two
+classes that are superclasses of each other), this will complete without
+the loader attempting to access the partially-linked class.
+
+With verification, the situation is different.  If we try to verify
+every class as we load it, we quickly run into trouble.  Even the lowly
+java.lang.Object requires CloneNotSupportedException; follow the list
+of referenced classes and you can head down quite a trail.  The trail
+eventually leads back to Object, which is officially not fully-formed yet.
+
+The VM spec (specifically, v2 5.4.1) notes that classes pulled in during
+verification do not need to be prepared or verified.  This means that we
+are allowed to have loaded but unverified classes.  It further notes that
+the class must be verified before it is initialized, which allows us to
+defer verification for all classes until class init.  You can't execute
+code or access fields in an uninitialized class, so this is safe.
+
+It also allows a more peaceful coexistence between verified and
+unverifiable code.  If class A refers to B, and B has a method that
+refers to a bogus class C, should we allow class A to be verified?
+If A only exercises parts of B that don't use class C, then there is
+nothing wrong with running code in A.  We can fully verify both A and B,
+and allow execution to continue until B causes initialization of C.  The
+VerifyError is thrown close to the point of use.
+
+This gets a little weird with java.lang.Class, which is the only class
+that can be instantiated before it is initialized.  We have to force
+initialization right after the class is created, because by definition we
+have instances of it on the heap, and somebody might get a class object and
+start making virtual calls on it.  We can end up going recursive during
+verification of java.lang.Class, but we avoid that by checking to see if
+verification is already in progress before we try to initialize it.
+*/
+
+/*
+Notes on class loaders and interaction with optimization / verification
+
+In what follows, "pre-verification" and "optimization" are the steps
+performed by the dexopt command, which attempts to verify and optimize
+classes as part of unpacking jar files and storing the DEX data in the
+dalvik-cache directory.  These steps are performed by loading the DEX
+files directly, without any assistance from ClassLoader instances.
+
+When we pre-verify and optimize a class in a DEX file, we make some
+assumptions about where the class loader will go to look for classes.
+If we can't guarantee those assumptions, e.g. because a class ("AppClass")
+references something not defined in the bootstrap jars or the AppClass jar,
+we can't pre-verify or optimize the class.
+
+The VM doesn't define the behavior of user-defined class loaders.
+For example, suppose application class AppClass, loaded by UserLoader,
+has a method that creates a java.lang.String.  The first time
+AppClass.stringyMethod tries to do something with java.lang.String, it
+asks UserLoader to find it.  UserLoader is expected to defer to its parent
+loader, but isn't required to.  UserLoader might provide a replacement
+for String.
+
+We can run into trouble if we pre-verify AppClass with the assumption that
+java.lang.String will come from core.jar, and don't verify this assumption
+at runtime.  There are two places that an alternate implementation of
+java.lang.String can come from: the AppClass jar, or from some other jar
+that UserLoader knows about.  (Someday UserLoader will be able to generate
+some bytecode and call DefineClass, but not yet.)
+
+To handle the first situation, the pre-verifier will explicitly check for
+conflicts between the class being optimized/verified and the bootstrap
+classes.  If an app jar contains a class that has the same package and
+class name as a class in a bootstrap jar, the verification resolver refuses
+to find either, which will block pre-verification and optimization on
+classes that reference ambiguity.  The VM will postpone verification of
+the app class until first load.
+
+For the second situation, we need to ensure that all references from a
+pre-verified class are satisified by the class' jar or earlier bootstrap
+jars.  In concrete terms: when resolving a reference to NewClass,
+which was caused by a reference in class AppClass, we check to see if
+AppClass was pre-verified.  If so, we require that NewClass comes out
+of either the AppClass jar or one of the jars in the bootstrap path.
+(We may not control the class loaders, but we do manage the DEX files.
+We can verify that it's either (loader==null && dexFile==a_boot_dex)
+or (loader==UserLoader && dexFile==AppClass.dexFile).  Classes from
+DefineClass can't be pre-verified, so this doesn't apply.)
+
+This should ensure that you can't "fake out" the pre-verifier by creating
+a user-defined class loader that replaces system classes.  It should
+also ensure that you can write such a loader and have it work in the
+expected fashion; all you lose is some performance due to "just-in-time
+verification" and the lack of DEX optimizations.
+
+There is a "back door" of sorts in the class resolution check, due to
+the fact that the "class ref" entries are shared between the bytecode
+and meta-data references (e.g. annotations and exception handler lists).
+The class references in annotations have no bearing on class verification,
+so when a class does an annotation query that causes a class reference
+index to be resolved, we don't want to fail just because the calling
+class was pre-verified and the resolved class is in some random DEX file.
+The successful resolution adds the class to the "resolved classes" table,
+so when optimized bytecode references it we don't repeat the resolve-time
+check.  We can avoid this by not updating the "resolved classes" table
+when the class reference doesn't come out of something that has been
+checked by the verifier, but that has a nonzero performance impact.
+Since the ultimate goal of this test is to catch an unusual situation
+(user-defined class loaders redefining core classes), the added caution
+may not be worth the performance hit.
+*/
+
+/*
+ * Class serial numbers start at this value.  We use a nonzero initial
+ * value so they stand out in binary dumps (e.g. hprof output).
+ */
+#define INITIAL_CLASS_SERIAL_NUMBER 0x50000000
+
+/*
+ * Constant used to size an auxillary class object data structure.
+ * For optimum memory use this should be equal to or slightly larger than
+ * the number of classes loaded when the zygote finishes initializing.
+ */
+#define ZYGOTE_CLASS_CUTOFF 2304
+
+#define CLASS_SFIELD_SLOTS 1
+
+static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap);
+static void freeCpeArray(ClassPathEntry* cpe);
+
+static ClassObject* findClassFromLoaderNoInit(
+    const char* descriptor, Object* loader);
+static ClassObject* findClassNoInit(const char* descriptor, Object* loader,\
+    DvmDex* pDvmDex);
+static ClassObject* loadClassFromDex(DvmDex* pDvmDex,
+    const DexClassDef* pClassDef, Object* loader);
+static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod,\
+    Method* meth);
+static int computeJniArgInfo(const DexProto* proto);
+static void loadSFieldFromDex(ClassObject* clazz,
+    const DexField* pDexSField, StaticField* sfield);
+static void loadIFieldFromDex(ClassObject* clazz,
+    const DexField* pDexIField, InstField* field);
+static bool precacheReferenceOffsets(ClassObject* clazz);
+static void computeRefOffsets(ClassObject* clazz);
+static void freeMethodInnards(Method* meth);
+static bool createVtable(ClassObject* clazz);
+static bool createIftable(ClassObject* clazz);
+static bool insertMethodStubs(ClassObject* clazz);
+static bool computeFieldOffsets(ClassObject* clazz);
+static void throwEarlierClassFailure(ClassObject* clazz);
+
+#if LOG_CLASS_LOADING
+/*
+ * Logs information about a class loading with given timestamp.
+ *
+ * TODO: In the case where we fail in dvmLinkClass() and log the class as closing (type='<'),
+ * it would probably be better to use a new type code to indicate the failure.  This change would
+ * require a matching change in the parser and analysis code in frameworks/base/tools/preload.
+ */
+static void logClassLoadWithTime(char type, ClassObject* clazz, u8 time) {
+    pid_t ppid = getppid();
+    pid_t pid = getpid();
+    unsigned int tid = (unsigned int) pthread_self();
+
+    LOG(LOG_INFO, "PRELOAD", "%c%d:%d:%d:%s:%d:%s:%lld", type, ppid, pid, tid,
+        get_process_name(), (int) clazz->classLoader, clazz->descriptor,
+        time);
+}
+
+/*
+ * Logs information about a class loading.
+ */
+static void logClassLoad(char type, ClassObject* clazz) {
+    logClassLoadWithTime(type, clazz, dvmGetThreadCpuTimeNsec());
+}
+#endif
+
+/*
+ * Some LinearAlloc unit tests.
+ */
+static void linearAllocTests()
+{
+    char* fiddle;
+    int test = 1;
+
+    switch (test) {
+    case 0:
+        fiddle = (char*)dvmLinearAlloc(NULL, 3200-28);
+        dvmLinearReadOnly(NULL, (char*)fiddle);
+        break;
+    case 1:
+        fiddle = (char*)dvmLinearAlloc(NULL, 3200-24);
+        dvmLinearReadOnly(NULL, (char*)fiddle);
+        break;
+    case 2:
+        fiddle = (char*)dvmLinearAlloc(NULL, 3200-20);
+        dvmLinearReadOnly(NULL, (char*)fiddle);
+        break;
+    case 3:
+        fiddle = (char*)dvmLinearAlloc(NULL, 3200-16);
+        dvmLinearReadOnly(NULL, (char*)fiddle);
+        break;
+    case 4:
+        fiddle = (char*)dvmLinearAlloc(NULL, 3200-12);
+        dvmLinearReadOnly(NULL, (char*)fiddle);
+        break;
+    }
+    fiddle = (char*)dvmLinearAlloc(NULL, 896);
+    dvmLinearReadOnly(NULL, (char*)fiddle);
+    fiddle = (char*)dvmLinearAlloc(NULL, 20);      // watch addr of this alloc
+    dvmLinearReadOnly(NULL, (char*)fiddle);
+
+    fiddle = (char*)dvmLinearAlloc(NULL, 1);
+    fiddle[0] = 'q';
+    dvmLinearReadOnly(NULL, fiddle);
+    fiddle = (char*)dvmLinearAlloc(NULL, 4096);
+    fiddle[0] = 'x';
+    fiddle[4095] = 'y';
+    dvmLinearReadOnly(NULL, fiddle);
+    dvmLinearFree(NULL, fiddle);
+    fiddle = (char*)dvmLinearAlloc(NULL, 0);
+    dvmLinearReadOnly(NULL, fiddle);
+    fiddle = (char*)dvmLinearRealloc(NULL, fiddle, 12);
+    fiddle[11] = 'z';
+    dvmLinearReadOnly(NULL, (char*)fiddle);
+    fiddle = (char*)dvmLinearRealloc(NULL, fiddle, 5);
+    dvmLinearReadOnly(NULL, fiddle);
+    fiddle = (char*)dvmLinearAlloc(NULL, 17001);
+    fiddle[0] = 'x';
+    fiddle[17000] = 'y';
+    dvmLinearReadOnly(NULL, (char*)fiddle);
+
+    char* str = (char*)dvmLinearStrdup(NULL, "This is a test!");
+    LOGI("GOT: '%s'", str);
+
+    /* try to check the bounds; allocator may round allocation size up */
+    fiddle = (char*)dvmLinearAlloc(NULL, 12);
+    LOGI("Should be 1: %d", dvmLinearAllocContains(fiddle, 12));
+    LOGI("Should be 0: %d", dvmLinearAllocContains(fiddle, 13));
+    LOGI("Should be 0: %d", dvmLinearAllocContains(fiddle - 128*1024, 1));
+
+    dvmLinearAllocDump(NULL);
+    dvmLinearFree(NULL, (char*)str);
+}
+
+static size_t classObjectSize(size_t sfieldCount)
+{
+    size_t offset = OFFSETOF_MEMBER(ClassObject, sfields);
+    return offset + sizeof(StaticField) * sfieldCount;
+}
+
+size_t dvmClassObjectSize(const ClassObject *clazz)
+{
+    assert(clazz != NULL);
+    return classObjectSize(clazz->sfieldCount);
+}
+
+/* (documented in header) */
+ClassObject* dvmFindPrimitiveClass(char type)
+{
+    PrimitiveType primitiveType = dexGetPrimitiveTypeFromDescriptorChar(type);
+
+    switch (primitiveType) {
+        case PRIM_VOID:    return gDvm.typeVoid;
+        case PRIM_BOOLEAN: return gDvm.typeBoolean;
+        case PRIM_BYTE:    return gDvm.typeByte;
+        case PRIM_SHORT:   return gDvm.typeShort;
+        case PRIM_CHAR:    return gDvm.typeChar;
+        case PRIM_INT:     return gDvm.typeInt;
+        case PRIM_LONG:    return gDvm.typeLong;
+        case PRIM_FLOAT:   return gDvm.typeFloat;
+        case PRIM_DOUBLE:  return gDvm.typeDouble;
+        default: {
+            LOGW("Unknown primitive type '%c'", type);
+            return NULL;
+        }
+    }
+}
+
+/*
+ * Synthesize a primitive class.
+ *
+ * Just creates the class and returns it (does not add it to the class list).
+ */
+static bool createPrimitiveType(PrimitiveType primitiveType, ClassObject** pClass)
+{
+    /*
+     * Fill out a few fields in the ClassObject.
+     *
+     * Note that primitive classes do not sub-class the class Object.
+     * This matters for "instanceof" checks. Also, we assume that the
+     * primitive class does not override finalize().
+     */
+
+    const char* descriptor = dexGetPrimitiveTypeDescriptor(primitiveType);
+    assert(descriptor != NULL);
+
+    ClassObject* newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_NON_MOVING);
+    if (newClass == NULL) {
+        return false;
+    }
+
+    DVM_OBJECT_INIT(newClass, gDvm.classJavaLangClass);
+    dvmSetClassSerialNumber(newClass);
+    SET_CLASS_FLAG(newClass, ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
+    newClass->primitiveType = primitiveType;
+    newClass->descriptorAlloc = NULL;
+    newClass->descriptor = descriptor;
+    newClass->super = NULL;
+    newClass->status = CLASS_INITIALIZED;
+
+    /* don't need to set newClass->objectSize */
+
+    LOGVV("Constructed class for primitive type '%s'", newClass->descriptor);
+
+    *pClass = newClass;
+    dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+
+    return true;
+}
+
+/*
+ * Create the initial class instances. These consist of the class
+ * Class and all of the classes representing primitive types.
+ */
+static bool createInitialClasses() {
+    /*
+     * Initialize the class Class. This has to be done specially, particularly
+     * because it is an instance of itself.
+     */
+    ClassObject* clazz = (ClassObject*)
+        dvmMalloc(classObjectSize(CLASS_SFIELD_SLOTS), ALLOC_NON_MOVING);
+    if (clazz == NULL) {
+        return false;
+    }
+    DVM_OBJECT_INIT(clazz, clazz);
+    SET_CLASS_FLAG(clazz, ACC_PUBLIC | ACC_FINAL | CLASS_ISCLASS);
+    clazz->descriptor = "Ljava/lang/Class;";
+    gDvm.classJavaLangClass = clazz;
+    LOGVV("Constructed the class Class.");
+
+    /*
+     * Initialize the classes representing primitive types. These are
+     * instances of the class Class, but other than that they're fairly
+     * different from regular classes.
+     */
+    bool ok = true;
+    ok &= createPrimitiveType(PRIM_VOID,    &gDvm.typeVoid);
+    ok &= createPrimitiveType(PRIM_BOOLEAN, &gDvm.typeBoolean);
+    ok &= createPrimitiveType(PRIM_BYTE,    &gDvm.typeByte);
+    ok &= createPrimitiveType(PRIM_SHORT,   &gDvm.typeShort);
+    ok &= createPrimitiveType(PRIM_CHAR,    &gDvm.typeChar);
+    ok &= createPrimitiveType(PRIM_INT,     &gDvm.typeInt);
+    ok &= createPrimitiveType(PRIM_LONG,    &gDvm.typeLong);
+    ok &= createPrimitiveType(PRIM_FLOAT,   &gDvm.typeFloat);
+    ok &= createPrimitiveType(PRIM_DOUBLE,  &gDvm.typeDouble);
+
+    return ok;
+}
+
+/*
+ * Initialize the bootstrap class loader.
+ *
+ * Call this after the bootclasspath string has been finalized.
+ */
+bool dvmClassStartup()
+{
+    /* make this a requirement -- don't currently support dirs in path */
+    if (strcmp(gDvm.bootClassPathStr, ".") == 0) {
+        LOGE("ERROR: must specify non-'.' bootclasspath");
+        return false;
+    }
+
+    gDvm.loadedClasses =
+        dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);
+
+    gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);
+    if (gDvm.pBootLoaderAlloc == NULL)
+        return false;
+
+    if (false) {
+        linearAllocTests();
+        exit(0);
+    }
+
+    /*
+     * Class serial number.  We start with a high value to make it distinct
+     * in binary dumps (e.g. hprof).
+     */
+    gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;
+
+    /*
+     * Set up the table we'll use for tracking initiating loaders for
+     * early classes.
+     * If it's NULL, we just fall back to the InitiatingLoaderList in the
+     * ClassObject, so it's not fatal to fail this allocation.
+     */
+    gDvm.initiatingLoaderList = (InitiatingLoaderList*)
+        calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));
+
+    /*
+     * Create the initial classes. These are the first objects constructed
+     * within the nascent VM.
+     */
+    if (!createInitialClasses()) {
+        return false;
+    }
+
+    /*
+     * Process the bootstrap class path.  This means opening the specified
+     * DEX or Jar files and possibly running them through the optimizer.
+     */
+    assert(gDvm.bootClassPath == NULL);
+    processClassPath(gDvm.bootClassPathStr, true);
+
+    if (gDvm.bootClassPath == NULL)
+        return false;
+
+    return true;
+}
+
+/*
+ * Clean up.
+ */
+void dvmClassShutdown()
+{
+    /* discard all system-loaded classes */
+    dvmHashTableFree(gDvm.loadedClasses);
+    gDvm.loadedClasses = NULL;
+
+    /* discard primitive classes created for arrays */
+    dvmFreeClassInnards(gDvm.typeVoid);
+    dvmFreeClassInnards(gDvm.typeBoolean);
+    dvmFreeClassInnards(gDvm.typeByte);
+    dvmFreeClassInnards(gDvm.typeShort);
+    dvmFreeClassInnards(gDvm.typeChar);
+    dvmFreeClassInnards(gDvm.typeInt);
+    dvmFreeClassInnards(gDvm.typeLong);
+    dvmFreeClassInnards(gDvm.typeFloat);
+    dvmFreeClassInnards(gDvm.typeDouble);
+
+    /* this closes DEX files, JAR files, etc. */
+    freeCpeArray(gDvm.bootClassPath);
+    gDvm.bootClassPath = NULL;
+
+    dvmLinearAllocDestroy(NULL);
+
+    free(gDvm.initiatingLoaderList);
+}
+
+
+/*
+ * ===========================================================================
+ *      Bootstrap class loader
+ * ===========================================================================
+ */
+
+/*
+ * Dump the contents of a ClassPathEntry array.
+ */
+static void dumpClassPath(const ClassPathEntry* cpe)
+{
+    int idx = 0;
+
+    while (cpe->kind != kCpeLastEntry) {
+        const char* kindStr;
+
+        switch (cpe->kind) {
+        case kCpeJar:       kindStr = "jar";    break;
+        case kCpeDex:       kindStr = "dex";    break;
+        default:            kindStr = "???";    break;
+        }
+
+        LOGI("  %2d: type=%s %s %p", idx, kindStr, cpe->fileName, cpe->ptr);
+        if (CALC_CACHE_STATS && cpe->kind == kCpeJar) {
+            JarFile* pJarFile = (JarFile*) cpe->ptr;
+            DvmDex* pDvmDex = dvmGetJarFileDex(pJarFile);
+            dvmDumpAtomicCacheStats(pDvmDex->pInterfaceCache);
+        }
+
+        cpe++;
+        idx++;
+    }
+}
+
+/*
+ * Dump the contents of the bootstrap class path.
+ */
+void dvmDumpBootClassPath()
+{
+    dumpClassPath(gDvm.bootClassPath);
+}
+
+/*
+ * Returns "true" if the class path contains the specified path.
+ */
+bool dvmClassPathContains(const ClassPathEntry* cpe, const char* path)
+{
+    while (cpe->kind != kCpeLastEntry) {
+        if (strcmp(cpe->fileName, path) == 0)
+            return true;
+
+        cpe++;
+    }
+    return false;
+}
+
+/*
+ * Free an array of ClassPathEntry structs.
+ *
+ * We release the contents of each entry, then free the array itself.
+ */
+static void freeCpeArray(ClassPathEntry* cpe)
+{
+    ClassPathEntry* cpeStart = cpe;
+
+    if (cpe == NULL)
+        return;
+
+    while (cpe->kind != kCpeLastEntry) {
+        switch (cpe->kind) {
+        case kCpeJar:
+            /* free JarFile */
+            dvmJarFileFree((JarFile*) cpe->ptr);
+            break;
+        case kCpeDex:
+            /* free RawDexFile */
+            dvmRawDexFileFree((RawDexFile*) cpe->ptr);
+            break;
+        default:
+            assert(false);
+            break;
+        }
+
+        free(cpe->fileName);
+        cpe++;
+    }
+
+    free(cpeStart);
+}
+
+/*
+ * Get the filename suffix of the given file (everything after the
+ * last "." if any, or "<none>" if there's no apparent suffix). The
+ * passed-in buffer will always be '\0' terminated.
+ */
+static void getFileNameSuffix(const char* fileName, char* suffixBuf, size_t suffixBufLen)
+{
+    const char* lastDot = strrchr(fileName, '.');
+
+    strlcpy(suffixBuf, (lastDot == NULL) ? "<none>" : (lastDot + 1), suffixBufLen);
+}
+
+/*
+ * Prepare a ClassPathEntry struct, which at this point only has a valid
+ * filename.  We need to figure out what kind of file it is, and for
+ * everything other than directories we need to open it up and see
+ * what's inside.
+ */
+static bool prepareCpe(ClassPathEntry* cpe, bool isBootstrap)
+{
+    struct stat sb;
+
+    if (stat(cpe->fileName, &sb) < 0) {
+        LOGD("Unable to stat classpath element '%s'", cpe->fileName);
+        return false;
+    }
+    if (S_ISDIR(sb.st_mode)) {
+        LOGE("Directory classpath elements are not supported: %s", cpe->fileName);
+        return false;
+    }
+
+    char suffix[10];
+    getFileNameSuffix(cpe->fileName, suffix, sizeof(suffix));
+
+    if ((strcmp(suffix, "jar") == 0) || (strcmp(suffix, "zip") == 0) ||
+            (strcmp(suffix, "apk") == 0)) {
+        JarFile* pJarFile = NULL;
+        if (dvmJarFileOpen(cpe->fileName, NULL, &pJarFile, isBootstrap) == 0) {
+            cpe->kind = kCpeJar;
+            cpe->ptr = pJarFile;
+            return true;
+        }
+    } else if (strcmp(suffix, "dex") == 0) {
+        RawDexFile* pRawDexFile = NULL;
+        if (dvmRawDexFileOpen(cpe->fileName, NULL, &pRawDexFile, isBootstrap) == 0) {
+            cpe->kind = kCpeDex;
+            cpe->ptr = pRawDexFile;
+            return true;
+        }
+    } else {
+        LOGE("Unknown type suffix '%s'", suffix);
+    }
+
+    LOGD("Unable to process classpath element '%s'", cpe->fileName);
+    return false;
+}
+
+/*
+ * Convert a colon-separated list of directories, Zip files, and DEX files
+ * into an array of ClassPathEntry structs.
+ *
+ * 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)
+{
+    ClassPathEntry* cpe = NULL;
+    char* mangle;
+    char* cp;
+    const char* end;
+    int idx, count;
+
+    assert(pathStr != NULL);
+
+    mangle = strdup(pathStr);
+
+    /*
+     * Run through and essentially strtok() the string.  Get a count of
+     * the #of elements while we're at it.
+     *
+     * If the path was constructed strangely (e.g. ":foo::bar:") this will
+     * over-allocate, which isn't ideal but is mostly harmless.
+     */
+    count = 1;
+    for (cp = mangle; *cp != '\0'; cp++) {
+        if (*cp == ':') {   /* separates two entries */
+            count++;
+            *cp = '\0';
+        }
+    }
+    end = cp;
+
+    /*
+     * Allocate storage.  We over-alloc by one so we can set an "end" marker.
+     */
+    cpe = (ClassPathEntry*) calloc(count+1, sizeof(ClassPathEntry));
+
+    /*
+     * Set the global pointer so the DEX file dependency stuff can find it.
+     */
+    gDvm.bootClassPath = cpe;
+
+    /*
+     * Go through a second time, pulling stuff out.
+     */
+    cp = mangle;
+    idx = 0;
+    while (cp < end) {
+        if (*cp == '\0') {
+            /* leading, trailing, or doubled ':'; ignore it */
+        } else {
+            if (isBootstrap &&
+                    dvmPathToAbsolutePortion(cp) == NULL) {
+                LOGE("Non-absolute bootclasspath entry '%s'", cp);
+                free(cpe);
+                cpe = NULL;
+                goto bail;
+            }
+
+            ClassPathEntry tmp;
+            tmp.kind = kCpeUnknown;
+            tmp.fileName = strdup(cp);
+            tmp.ptr = NULL;
+
+            /*
+             * Drop an end marker here so DEX loader can walk unfinished
+             * list.
+             */
+            cpe[idx].kind = kCpeLastEntry;
+            cpe[idx].fileName = NULL;
+            cpe[idx].ptr = NULL;
+
+            if (!prepareCpe(&tmp, isBootstrap)) {
+                /* drop from list and continue on */
+                free(tmp.fileName);
+            } else {
+                /* copy over, pointers and all */
+                cpe[idx] = tmp;
+                idx++;
+            }
+        }
+
+        cp += strlen(cp) +1;
+    }
+    assert(idx <= count);
+    if (idx == 0 && !gDvm.optimizing) {
+        /*
+         * There's no way the vm will be doing anything if this is the
+         * case, so just bail out (reasonably) gracefully.
+         */
+        LOGE("No valid entries found in bootclasspath '%s'", pathStr);
+        gDvm.lastMessage = pathStr;
+        dvmAbort();
+    }
+
+    LOGVV("  (filled %d of %d slots)", idx, count);
+
+    /* put end marker in over-alloc slot */
+    cpe[idx].kind = kCpeLastEntry;
+    cpe[idx].fileName = NULL;
+    cpe[idx].ptr = NULL;
+
+    //dumpClassPath(cpe);
+
+bail:
+    free(mangle);
+    gDvm.bootClassPath = cpe;
+    return cpe;
+}
+
+/*
+ * Search the DEX files we loaded from the bootstrap class path for a DEX
+ * file that has the class with the matching descriptor.
+ *
+ * Returns the matching DEX file and DexClassDef entry if found, otherwise
+ * returns NULL.
+ */
+static DvmDex* searchBootPathForClass(const char* descriptor,
+    const DexClassDef** ppClassDef)
+{
+    const ClassPathEntry* cpe = gDvm.bootClassPath;
+    const DexClassDef* pFoundDef = NULL;
+    DvmDex* pFoundFile = NULL;
+
+    LOGVV("+++ class '%s' not yet loaded, scanning bootclasspath...",
+        descriptor);
+
+    while (cpe->kind != kCpeLastEntry) {
+        //LOGV("+++  checking '%s' (%d)", cpe->fileName, cpe->kind);
+
+        switch (cpe->kind) {
+        case kCpeJar:
+            {
+                JarFile* pJarFile = (JarFile*) cpe->ptr;
+                const DexClassDef* pClassDef;
+                DvmDex* pDvmDex;
+
+                pDvmDex = dvmGetJarFileDex(pJarFile);
+                pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
+                if (pClassDef != NULL) {
+                    /* found */
+                    pFoundDef = pClassDef;
+                    pFoundFile = pDvmDex;
+                    goto found;
+                }
+            }
+            break;
+        case kCpeDex:
+            {
+                RawDexFile* pRawDexFile = (RawDexFile*) cpe->ptr;
+                const DexClassDef* pClassDef;
+                DvmDex* pDvmDex;
+
+                pDvmDex = dvmGetRawDexFileDex(pRawDexFile);
+                pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
+                if (pClassDef != NULL) {
+                    /* found */
+                    pFoundDef = pClassDef;
+                    pFoundFile = pDvmDex;
+                    goto found;
+                }
+            }
+            break;
+        default:
+            LOGE("Unknown kind %d", cpe->kind);
+            assert(false);
+            break;
+        }
+
+        cpe++;
+    }
+
+    /*
+     * Special handling during verification + optimization.
+     *
+     * The DEX optimizer needs to load classes from the DEX file it's working
+     * on.  Rather than trying to insert it into the bootstrap class path
+     * or synthesizing a class loader to manage it, we just make it available
+     * here.  It logically comes after all existing entries in the bootstrap
+     * class path.
+     */
+    if (gDvm.bootClassPathOptExtra != NULL) {
+        const DexClassDef* pClassDef;
+
+        pClassDef =
+            dexFindClass(gDvm.bootClassPathOptExtra->pDexFile, descriptor);
+        if (pClassDef != NULL) {
+            /* found */
+            pFoundDef = pClassDef;
+            pFoundFile = gDvm.bootClassPathOptExtra;
+        }
+    }
+
+found:
+    *ppClassDef = pFoundDef;
+    return pFoundFile;
+}
+
+/*
+ * Set the "extra" DEX, which becomes a de facto member of the bootstrap
+ * class set.
+ */
+void dvmSetBootPathExtraDex(DvmDex* pDvmDex)
+{
+    gDvm.bootClassPathOptExtra = pDvmDex;
+}
+
+
+/*
+ * Return the #of entries in the bootstrap class path.
+ *
+ * (Used for ClassLoader.getResources().)
+ */
+int dvmGetBootPathSize()
+{
+    const ClassPathEntry* cpe = gDvm.bootClassPath;
+
+    while (cpe->kind != kCpeLastEntry)
+        cpe++;
+
+    return cpe - gDvm.bootClassPath;
+}
+
+/*
+ * Find a resource with the specified name in entry N of the boot class path.
+ *
+ * We return a newly-allocated String of one of these forms:
+ *   file://path/name
+ *   jar:file://path!/name
+ * Where "path" is the bootstrap class path entry and "name" is the string
+ * passed into this method.  "path" needs to be an absolute path (starting
+ * with '/'); if it's not we'd need to "absolutify" it as part of forming
+ * the URL string.
+ */
+StringObject* dvmGetBootPathResource(const char* name, int idx)
+{
+    const int kUrlOverhead = 13;        // worst case for Jar URL
+    const ClassPathEntry* cpe = gDvm.bootClassPath;
+    StringObject* urlObj = NULL;
+
+    LOGV("+++ searching for resource '%s' in %d(%s)",
+        name, idx, cpe[idx].fileName);
+
+    /* we could use direct array index, but I don't entirely trust "idx" */
+    while (idx-- && cpe->kind != kCpeLastEntry)
+        cpe++;
+    if (cpe->kind == kCpeLastEntry) {
+        assert(false);
+        return NULL;
+    }
+
+    char urlBuf[strlen(name) + strlen(cpe->fileName) + kUrlOverhead +1];
+
+    switch (cpe->kind) {
+    case kCpeJar:
+        {
+            JarFile* pJarFile = (JarFile*) cpe->ptr;
+            if (dexZipFindEntry(&pJarFile->archive, name) == NULL)
+                goto bail;
+            sprintf(urlBuf, "jar:file://%s!/%s", cpe->fileName, name);
+        }
+        break;
+    case kCpeDex:
+        LOGV("No resources in DEX files");
+        goto bail;
+    default:
+        assert(false);
+        goto bail;
+    }
+
+    LOGV("+++ using URL='%s'", urlBuf);
+    urlObj = dvmCreateStringFromCstr(urlBuf);
+
+bail:
+    return urlObj;
+}
+
+
+/*
+ * ===========================================================================
+ *      Class list management
+ * ===========================================================================
+ */
+
+/* search for these criteria in the Class hash table */
+struct ClassMatchCriteria {
+    const char* descriptor;
+    Object*     loader;
+};
+
+#define kInitLoaderInc  4       /* must be power of 2 */
+
+static InitiatingLoaderList *dvmGetInitiatingLoaderList(ClassObject* clazz)
+{
+    assert(clazz->serialNumber >= INITIAL_CLASS_SERIAL_NUMBER);
+    int classIndex = clazz->serialNumber-INITIAL_CLASS_SERIAL_NUMBER;
+    if (gDvm.initiatingLoaderList != NULL &&
+        classIndex < ZYGOTE_CLASS_CUTOFF) {
+        return &(gDvm.initiatingLoaderList[classIndex]);
+    } else {
+        return &(clazz->initiatingLoaderList);
+    }
+}
+
+/*
+ * Determine if "loader" appears in clazz' initiating loader list.
+ *
+ * The class hash table lock must be held when calling here, since
+ * it's also used when updating a class' initiating loader list.
+ *
+ * TODO: switch to some sort of lock-free data structure so we don't have
+ * to grab the lock to do a lookup.  Among other things, this would improve
+ * the speed of compareDescriptorClasses().
+ */
+bool dvmLoaderInInitiatingList(const ClassObject* clazz, const Object* loader)
+{
+    /*
+     * The bootstrap class loader can't be just an initiating loader for
+     * anything (it's always the defining loader if the class is visible
+     * to it).  We don't put defining loaders in the initiating list.
+     */
+    if (loader == NULL)
+        return false;
+
+    /*
+     * Scan the list for a match.  The list is expected to be short.
+     */
+    /* Cast to remove the const from clazz, but use const loaderList */
+    ClassObject* nonConstClazz = (ClassObject*) clazz;
+    const InitiatingLoaderList *loaderList =
+        dvmGetInitiatingLoaderList(nonConstClazz);
+    int i;
+    for (i = loaderList->initiatingLoaderCount-1; i >= 0; --i) {
+        if (loaderList->initiatingLoaders[i] == loader) {
+            //LOGI("+++ found initiating match %p in %s",
+            //    loader, clazz->descriptor);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Add "loader" to clazz's initiating loader set, unless it's the defining
+ * class loader.
+ *
+ * In the common case this will be a short list, so we don't need to do
+ * anything too fancy here.
+ *
+ * This locks gDvm.loadedClasses for synchronization, so don't hold it
+ * when calling here.
+ */
+void dvmAddInitiatingLoader(ClassObject* clazz, Object* loader)
+{
+    if (loader != clazz->classLoader) {
+        assert(loader != NULL);
+
+        LOGVV("Adding %p to '%s' init list", loader, clazz->descriptor);
+        dvmHashTableLock(gDvm.loadedClasses);
+
+        /*
+         * Make sure nobody snuck in.  The penalty for adding twice is
+         * pretty minor, and probably outweighs the O(n^2) hit for
+         * checking before every add, so we may not want to do this.
+         */
+        //if (dvmLoaderInInitiatingList(clazz, loader)) {
+        //    LOGW("WOW: simultaneous add of initiating class loader");
+        //    goto bail_unlock;
+        //}
+
+        /*
+         * The list never shrinks, so we just keep a count of the
+         * number of elements in it, and reallocate the buffer when
+         * we run off the end.
+         *
+         * The pointer is initially NULL, so we *do* want to call realloc
+         * when count==0.
+         */
+        InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(clazz);
+        if ((loaderList->initiatingLoaderCount & (kInitLoaderInc-1)) == 0) {
+            Object** newList;
+
+            newList = (Object**) realloc(loaderList->initiatingLoaders,
+                        (loaderList->initiatingLoaderCount + kInitLoaderInc)
+                         * sizeof(Object*));
+            if (newList == NULL) {
+                /* this is mainly a cache, so it's not the EotW */
+                assert(false);
+                goto bail_unlock;
+            }
+            loaderList->initiatingLoaders = newList;
+
+            //LOGI("Expanded init list to %d (%s)",
+            //    loaderList->initiatingLoaderCount+kInitLoaderInc,
+            //    clazz->descriptor);
+        }
+        loaderList->initiatingLoaders[loaderList->initiatingLoaderCount++] =
+            loader;
+
+bail_unlock:
+        dvmHashTableUnlock(gDvm.loadedClasses);
+    }
+}
+
+/*
+ * (This is a dvmHashTableLookup callback.)
+ *
+ * Entries in the class hash table are stored as { descriptor, d-loader }
+ * tuples.  If the hashed class descriptor matches the requested descriptor,
+ * and the hashed defining class loader matches the requested class
+ * loader, we're good.  If only the descriptor matches, we check to see if the
+ * loader is in the hashed class' initiating loader list.  If so, we
+ * can return "true" immediately and skip some of the loadClass melodrama.
+ *
+ * The caller must lock the hash table before calling here.
+ *
+ * Returns 0 if a matching entry is found, nonzero otherwise.
+ */
+static int hashcmpClassByCrit(const void* vclazz, const void* vcrit)
+{
+    const ClassObject* clazz = (const ClassObject*) vclazz;
+    const ClassMatchCriteria* pCrit = (const ClassMatchCriteria*) vcrit;
+    bool match;
+
+    match = (strcmp(clazz->descriptor, pCrit->descriptor) == 0 &&
+             (clazz->classLoader == pCrit->loader ||
+              (pCrit->loader != NULL &&
+               dvmLoaderInInitiatingList(clazz, pCrit->loader)) ));
+    //if (match)
+    //    LOGI("+++ %s %p matches existing %s %p",
+    //        pCrit->descriptor, pCrit->loader,
+    //        clazz->descriptor, clazz->classLoader);
+    return !match;
+}
+
+/*
+ * Like hashcmpClassByCrit, but passing in a fully-formed ClassObject
+ * instead of a ClassMatchCriteria.
+ */
+static int hashcmpClassByClass(const void* vclazz, const void* vaddclazz)
+{
+    const ClassObject* clazz = (const ClassObject*) vclazz;
+    const ClassObject* addClazz = (const ClassObject*) vaddclazz;
+    bool match;
+
+    match = (strcmp(clazz->descriptor, addClazz->descriptor) == 0 &&
+             (clazz->classLoader == addClazz->classLoader ||
+              (addClazz->classLoader != NULL &&
+               dvmLoaderInInitiatingList(clazz, addClazz->classLoader)) ));
+    return !match;
+}
+
+/*
+ * Search through the hash table to find an entry with a matching descriptor
+ * and an initiating class loader that matches "loader".
+ *
+ * The table entries are hashed on descriptor only, because they're unique
+ * on *defining* class loader, not *initiating* class loader.  This isn't
+ * great, because it guarantees we will have to probe when multiple
+ * class loaders are used.
+ *
+ * Note this does NOT try to load a class; it just finds a class that
+ * has already been loaded.
+ *
+ * If "unprepOkay" is set, this will return classes that have been added
+ * to the hash table but are not yet fully loaded and linked.  Otherwise,
+ * such classes are ignored.  (The only place that should set "unprepOkay"
+ * is findClassNoInit(), which will wait for the prep to finish.)
+ *
+ * Returns NULL if not found.
+ */
+ClassObject* dvmLookupClass(const char* descriptor, Object* loader,
+    bool unprepOkay)
+{
+    ClassMatchCriteria crit;
+    void* found;
+    u4 hash;
+
+    crit.descriptor = descriptor;
+    crit.loader = loader;
+    hash = dvmComputeUtf8Hash(descriptor);
+
+    LOGVV("threadid=%d: dvmLookupClass searching for '%s' %p",
+        dvmThreadSelf()->threadId, descriptor, loader);
+
+    dvmHashTableLock(gDvm.loadedClasses);
+    found = dvmHashTableLookup(gDvm.loadedClasses, hash, &crit,
+                hashcmpClassByCrit, false);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+
+    /*
+     * The class has been added to the hash table but isn't ready for use.
+     * We're going to act like we didn't see it, so that the caller will
+     * go through the full "find class" path, which includes locking the
+     * object and waiting until it's ready.  We could do that lock/wait
+     * here, but this is an extremely rare case, and it's simpler to have
+     * the wait-for-class code centralized.
+     */
+    if (found && !unprepOkay && !dvmIsClassLinked((ClassObject*)found)) {
+        LOGV("Ignoring not-yet-ready %s, using slow path",
+            ((ClassObject*)found)->descriptor);
+        found = NULL;
+    }
+
+    return (ClassObject*) found;
+}
+
+/*
+ * Add a new class to the hash table.
+ *
+ * The class is considered "new" if it doesn't match on both the class
+ * descriptor and the defining class loader.
+ *
+ * TODO: we should probably have separate hash tables for each
+ * ClassLoader. This could speed up dvmLookupClass and
+ * other common operations. It does imply a VM-visible data structure
+ * for each ClassLoader object with loaded classes, which we don't
+ * have yet.
+ */
+bool dvmAddClassToHash(ClassObject* clazz)
+{
+    void* found;
+    u4 hash;
+
+    hash = dvmComputeUtf8Hash(clazz->descriptor);
+
+    dvmHashTableLock(gDvm.loadedClasses);
+    found = dvmHashTableLookup(gDvm.loadedClasses, hash, clazz,
+                hashcmpClassByClass, true);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+
+    LOGV("+++ dvmAddClassToHash '%s' %p (isnew=%d) --> %p",
+        clazz->descriptor, clazz->classLoader,
+        (found == (void*) clazz), clazz);
+
+    //dvmCheckClassTablePerf();
+
+    /* can happen if two threads load the same class simultaneously */
+    return (found == (void*) clazz);
+}
+
+#if 0
+/*
+ * Compute hash value for a class.
+ */
+u4 hashcalcClass(const void* item)
+{
+    return dvmComputeUtf8Hash(((const ClassObject*) item)->descriptor);
+}
+
+/*
+ * Check the performance of the "loadedClasses" hash table.
+ */
+void dvmCheckClassTablePerf()
+{
+    dvmHashTableLock(gDvm.loadedClasses);
+    dvmHashTableProbeCount(gDvm.loadedClasses, hashcalcClass,
+        hashcmpClassByClass);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+}
+#endif
+
+/*
+ * Remove a class object from the hash table.
+ */
+static void removeClassFromHash(ClassObject* clazz)
+{
+    LOGV("+++ removeClassFromHash '%s'", clazz->descriptor);
+
+    u4 hash = dvmComputeUtf8Hash(clazz->descriptor);
+
+    dvmHashTableLock(gDvm.loadedClasses);
+    if (!dvmHashTableRemove(gDvm.loadedClasses, hash, clazz))
+        LOGW("Hash table remove failed on class '%s'", clazz->descriptor);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+}
+
+
+/*
+ * ===========================================================================
+ *      Class creation
+ * ===========================================================================
+ */
+
+/*
+ * Set clazz->serialNumber to the next available value.
+ *
+ * This usually happens *very* early in class creation, so don't expect
+ * anything else in the class to be ready.
+ */
+void dvmSetClassSerialNumber(ClassObject* clazz)
+{
+    assert(clazz->serialNumber == 0);
+    clazz->serialNumber = android_atomic_inc(&gDvm.classSerialNumber);
+}
+
+
+/*
+ * Find the named class (by descriptor), using the specified
+ * initiating ClassLoader.
+ *
+ * The class will be loaded and initialized if it has not already been.
+ * If necessary, the superclass will be loaded.
+ *
+ * If the class can't be found, returns NULL with an appropriate exception
+ * raised.
+ */
+ClassObject* dvmFindClass(const char* descriptor, Object* loader)
+{
+    ClassObject* clazz;
+
+    clazz = dvmFindClassNoInit(descriptor, loader);
+    if (clazz != NULL && clazz->status < CLASS_INITIALIZED) {
+        /* initialize class */
+        if (!dvmInitClass(clazz)) {
+            /* init failed; leave it in the list, marked as bad */
+            assert(dvmCheckException(dvmThreadSelf()));
+            assert(clazz->status == CLASS_ERROR);
+            return NULL;
+        }
+    }
+
+    return clazz;
+}
+
+/*
+ * Find the named class (by descriptor), using the specified
+ * initiating ClassLoader.
+ *
+ * The class will be loaded if it has not already been, as will its
+ * superclass.  It will not be initialized.
+ *
+ * If the class can't be found, returns NULL with an appropriate exception
+ * raised.
+ */
+ClassObject* dvmFindClassNoInit(const char* descriptor,
+        Object* loader)
+{
+    assert(descriptor != NULL);
+    //assert(loader != NULL);
+
+    LOGVV("FindClassNoInit '%s' %p", descriptor, loader);
+
+    if (*descriptor == '[') {
+        /*
+         * Array class.  Find in table, generate if not found.
+         */
+        return dvmFindArrayClass(descriptor, loader);
+    } else {
+        /*
+         * Regular class.  Find in table, load if not found.
+         */
+        if (loader != NULL) {
+            return findClassFromLoaderNoInit(descriptor, loader);
+        } else {
+            return dvmFindSystemClassNoInit(descriptor);
+        }
+    }
+}
+
+/*
+ * Load the named class (by descriptor) from the specified class
+ * loader.  This calls out to let the ClassLoader object do its thing.
+ *
+ * Returns with NULL and an exception raised on error.
+ */
+static ClassObject* findClassFromLoaderNoInit(const char* descriptor,
+    Object* loader)
+{
+    //LOGI("##### findClassFromLoaderNoInit (%s,%p)",
+    //        descriptor, loader);
+
+    Thread* self = dvmThreadSelf();
+
+    assert(loader != NULL);
+
+    /*
+     * Do we already have it?
+     *
+     * The class loader code does the "is it already loaded" check as
+     * well.  However, this call is much faster than calling through
+     * interpreted code.  Doing this does mean that in the common case
+     * (365 out of 420 calls booting the sim) we're doing the
+     * lookup-by-descriptor twice.  It appears this is still a win, so
+     * I'm keeping it in.
+     */
+    ClassObject* clazz = dvmLookupClass(descriptor, loader, false);
+    if (clazz != NULL) {
+        LOGVV("Already loaded: %s %p", descriptor, loader);
+        return clazz;
+    } else {
+        LOGVV("Not already loaded: %s %p", descriptor, loader);
+    }
+
+    char* dotName = NULL;
+    StringObject* nameObj = NULL;
+
+    /* convert "Landroid/debug/Stuff;" to "android.debug.Stuff" */
+    dotName = dvmDescriptorToDot(descriptor);
+    if (dotName == NULL) {
+        dvmThrowOutOfMemoryError(NULL);
+        return NULL;
+    }
+    nameObj = dvmCreateStringFromCstr(dotName);
+    if (nameObj == NULL) {
+        assert(dvmCheckException(self));
+        goto bail;
+    }
+
+    dvmMethodTraceClassPrepBegin();
+
+    /*
+     * Invoke loadClass().  This will probably result in a couple of
+     * exceptions being thrown, because the ClassLoader.loadClass()
+     * implementation eventually calls VMClassLoader.loadClass to see if
+     * the bootstrap class loader can find it before doing its own load.
+     */
+    LOGVV("--- Invoking loadClass(%s, %p)", dotName, loader);
+    {
+        const Method* loadClass =
+            loader->clazz->vtable[gDvm.voffJavaLangClassLoader_loadClass];
+        JValue result;
+        dvmCallMethod(self, loadClass, loader, &result, nameObj);
+        clazz = (ClassObject*) result.l;
+
+        dvmMethodTraceClassPrepEnd();
+        Object* excep = dvmGetException(self);
+        if (excep != NULL) {
+#if DVM_SHOW_EXCEPTION >= 2
+            LOGD("NOTE: loadClass '%s' %p threw exception %s",
+                 dotName, loader, excep->clazz->descriptor);
+#endif
+            dvmAddTrackedAlloc(excep, self);
+            dvmClearException(self);
+            dvmThrowChainedNoClassDefFoundError(descriptor, excep);
+            dvmReleaseTrackedAlloc(excep, self);
+            clazz = NULL;
+            goto bail;
+        } else if (clazz == NULL) {
+            LOGW("ClassLoader returned NULL w/o exception pending");
+            dvmThrowNullPointerException("ClassLoader returned null");
+            goto bail;
+        }
+    }
+
+    /* not adding clazz to tracked-alloc list, because it's a ClassObject */
+
+    dvmAddInitiatingLoader(clazz, loader);
+
+    LOGVV("--- Successfully loaded %s %p (thisldr=%p clazz=%p)",
+        descriptor, clazz->classLoader, loader, clazz);
+
+bail:
+    dvmReleaseTrackedAlloc((Object*)nameObj, NULL);
+    free(dotName);
+    return clazz;
+}
+
+/*
+ * Load the named class (by descriptor) from the specified DEX file.
+ * Used by class loaders to instantiate a class object from a
+ * VM-managed DEX.
+ */
+ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor,
+    Object* classLoader)
+{
+    assert(pDvmDex != NULL);
+
+    return findClassNoInit(descriptor, classLoader, pDvmDex);
+}
+
+
+/*
+ * Find the named class (by descriptor), scanning through the
+ * bootclasspath if it hasn't already been loaded.
+ *
+ * "descriptor" looks like "Landroid/debug/Stuff;".
+ *
+ * Uses NULL as the defining class loader.
+ */
+ClassObject* dvmFindSystemClass(const char* descriptor)
+{
+    ClassObject* clazz;
+
+    clazz = dvmFindSystemClassNoInit(descriptor);
+    if (clazz != NULL && clazz->status < CLASS_INITIALIZED) {
+        /* initialize class */
+        if (!dvmInitClass(clazz)) {
+            /* init failed; leave it in the list, marked as bad */
+            assert(dvmCheckException(dvmThreadSelf()));
+            assert(clazz->status == CLASS_ERROR);
+            return NULL;
+        }
+    }
+
+    return clazz;
+}
+
+/*
+ * Find the named class (by descriptor), searching for it in the
+ * bootclasspath.
+ *
+ * On failure, this returns NULL with an exception raised.
+ */
+ClassObject* dvmFindSystemClassNoInit(const char* descriptor)
+{
+    return findClassNoInit(descriptor, NULL, NULL);
+}
+
+/*
+ * Find the named class (by descriptor). If it's not already loaded,
+ * we load it and link it, but don't execute <clinit>. (The VM has
+ * specific limitations on which events can cause initialization.)
+ *
+ * If "pDexFile" is NULL, we will search the bootclasspath for an entry.
+ *
+ * On failure, this returns NULL with an exception raised.
+ *
+ * TODO: we need to return an indication of whether we loaded the class or
+ * used an existing definition.  If somebody deliberately tries to load a
+ * class twice in the same class loader, they should get a LinkageError,
+ * but inadvertent simultaneous class references should "just work".
+ */
+static ClassObject* findClassNoInit(const char* descriptor, Object* loader,
+    DvmDex* pDvmDex)
+{
+    Thread* self = dvmThreadSelf();
+    ClassObject* clazz;
+    bool profilerNotified = false;
+
+    if (loader != NULL) {
+        LOGVV("#### findClassNoInit(%s,%p,%p)", descriptor, loader,
+            pDvmDex->pDexFile);
+    }
+
+    /*
+     * We don't expect an exception to be raised at this point.  The
+     * exception handling code is good about managing this.  This *can*
+     * happen if a JNI lookup fails and the JNI code doesn't do any
+     * error checking before doing another class lookup, so we may just
+     * want to clear this and restore it on exit.  If we don't, some kinds
+     * of failures can't be detected without rearranging other stuff.
+     *
+     * Most often when we hit this situation it means that something is
+     * broken in the VM or in JNI code, so I'm keeping it in place (and
+     * making it an informative abort rather than an assert).
+     */
+    if (dvmCheckException(self)) {
+        LOGE("Class lookup %s attempted with exception pending", descriptor);
+        LOGW("Pending exception is:");
+        dvmLogExceptionStackTrace();
+        dvmDumpAllThreads(false);
+        dvmAbort();
+    }
+
+    clazz = dvmLookupClass(descriptor, loader, true);
+    if (clazz == NULL) {
+        const DexClassDef* pClassDef;
+
+        dvmMethodTraceClassPrepBegin();
+        profilerNotified = true;
+
+#if LOG_CLASS_LOADING
+        u8 startTime = dvmGetThreadCpuTimeNsec();
+#endif
+
+        if (pDvmDex == NULL) {
+            assert(loader == NULL);     /* shouldn't be here otherwise */
+            pDvmDex = searchBootPathForClass(descriptor, &pClassDef);
+        } else {
+            pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
+        }
+
+        if (pDvmDex == NULL || pClassDef == NULL) {
+            if (gDvm.noClassDefFoundErrorObj != NULL) {
+                /* usual case -- use prefabricated object */
+                dvmSetException(self, gDvm.noClassDefFoundErrorObj);
+            } else {
+                /* dexopt case -- can't guarantee prefab (core.jar) */
+                dvmThrowNoClassDefFoundError(descriptor);
+            }
+            goto bail;
+        }
+
+        /* found a match, try to load it */
+        clazz = loadClassFromDex(pDvmDex, pClassDef, loader);
+        if (dvmCheckException(self)) {
+            /* class was found but had issues */
+            if (clazz != NULL) {
+                dvmFreeClassInnards(clazz);
+                dvmReleaseTrackedAlloc((Object*) clazz, NULL);
+            }
+            goto bail;
+        }
+
+        /*
+         * Lock the class while we link it so other threads must wait for us
+         * to finish.  Set the "initThreadId" so we can identify recursive
+         * invocation.  (Note all accesses to initThreadId here are
+         * guarded by the class object's lock.)
+         */
+        dvmLockObject(self, (Object*) clazz);
+        clazz->initThreadId = self->threadId;
+
+        /*
+         * Add to hash table so lookups succeed.
+         *
+         * [Are circular references possible when linking a class?]
+         */
+        assert(clazz->classLoader == loader);
+        if (!dvmAddClassToHash(clazz)) {
+            /*
+             * Another thread must have loaded the class after we
+             * started but before we finished.  Discard what we've
+             * done and leave some hints for the GC.
+             *
+             * (Yes, this happens.)
+             */
+            //LOGW("WOW: somebody loaded %s simultaneously", descriptor);
+            clazz->initThreadId = 0;
+            dvmUnlockObject(self, (Object*) clazz);
+
+            /* Let the GC free the class.
+             */
+            dvmFreeClassInnards(clazz);
+            dvmReleaseTrackedAlloc((Object*) clazz, NULL);
+
+            /* Grab the winning class.
+             */
+            clazz = dvmLookupClass(descriptor, loader, true);
+            assert(clazz != NULL);
+            goto got_class;
+        }
+        dvmReleaseTrackedAlloc((Object*) clazz, NULL);
+
+#if LOG_CLASS_LOADING
+        logClassLoadWithTime('>', clazz, startTime);
+#endif
+        /*
+         * Prepare and resolve.
+         */
+        if (!dvmLinkClass(clazz)) {
+            assert(dvmCheckException(self));
+
+            /* Make note of the error and clean up the class.
+             */
+            removeClassFromHash(clazz);
+            clazz->status = CLASS_ERROR;
+            dvmFreeClassInnards(clazz);
+
+            /* Let any waiters know.
+             */
+            clazz->initThreadId = 0;
+            dvmObjectNotifyAll(self, (Object*) clazz);
+            dvmUnlockObject(self, (Object*) clazz);
+
+#if LOG_CLASS_LOADING
+            LOG(LOG_INFO, "DVMLINK FAILED FOR CLASS ", "%s in %s",
+                clazz->descriptor, get_process_name());
+
+            /*
+             * TODO: It would probably be better to use a new type code here (instead of '<') to
+             * indicate the failure.  This change would require a matching change in the parser
+             * and analysis code in frameworks/base/tools/preload.
+             */
+            logClassLoad('<', clazz);
+#endif
+            clazz = NULL;
+            if (gDvm.optimizing) {
+                /* happens with "external" libs */
+                LOGV("Link of class '%s' failed", descriptor);
+            } else {
+                LOGW("Link of class '%s' failed", descriptor);
+            }
+            goto bail;
+        }
+        dvmObjectNotifyAll(self, (Object*) clazz);
+        dvmUnlockObject(self, (Object*) clazz);
+
+        /*
+         * Add class stats to global counters.
+         *
+         * TODO: these should probably be atomic ops.
+         */
+        gDvm.numLoadedClasses++;
+        gDvm.numDeclaredMethods +=
+            clazz->virtualMethodCount + clazz->directMethodCount;
+        gDvm.numDeclaredInstFields += clazz->ifieldCount;
+        gDvm.numDeclaredStaticFields += clazz->sfieldCount;
+
+        /*
+         * Cache pointers to basic classes.  We want to use these in
+         * various places, and it's easiest to initialize them on first
+         * use rather than trying to force them to initialize (startup
+         * ordering makes it weird).
+         */
+        if (gDvm.classJavaLangObject == NULL &&
+            strcmp(descriptor, "Ljava/lang/Object;") == 0)
+        {
+            /* It should be impossible to get here with anything
+             * but the bootclasspath loader.
+             */
+            assert(loader == NULL);
+            gDvm.classJavaLangObject = clazz;
+        }
+
+#if LOG_CLASS_LOADING
+        logClassLoad('<', clazz);
+#endif
+
+    } else {
+got_class:
+        if (!dvmIsClassLinked(clazz) && clazz->status != CLASS_ERROR) {
+            /*
+             * We can race with other threads for class linking.  We should
+             * never get here recursively; doing so indicates that two
+             * classes have circular dependencies.
+             *
+             * One exception: we force discovery of java.lang.Class in
+             * dvmLinkClass(), and Class has Object as its superclass.  So
+             * if the first thing we ever load is Object, we will init
+             * Object->Class->Object.  The easiest way to avoid this is to
+             * ensure that Object is never the first thing we look up, so
+             * we get Foo->Class->Object instead.
+             */
+            dvmLockObject(self, (Object*) clazz);
+            if (!dvmIsClassLinked(clazz) &&
+                clazz->initThreadId == self->threadId)
+            {
+                LOGW("Recursive link on class %s", clazz->descriptor);
+                dvmUnlockObject(self, (Object*) clazz);
+                dvmThrowClassCircularityError(clazz->descriptor);
+                clazz = NULL;
+                goto bail;
+            }
+            //LOGI("WAITING  for '%s' (owner=%d)",
+            //    clazz->descriptor, clazz->initThreadId);
+            while (!dvmIsClassLinked(clazz) && clazz->status != CLASS_ERROR) {
+                dvmObjectWait(self, (Object*) clazz, 0, 0, false);
+            }
+            dvmUnlockObject(self, (Object*) clazz);
+        }
+        if (clazz->status == CLASS_ERROR) {
+            /*
+             * Somebody else tried to load this and failed.  We need to raise
+             * an exception and report failure.
+             */
+            throwEarlierClassFailure(clazz);
+            clazz = NULL;
+            goto bail;
+        }
+    }
+
+    /* check some invariants */
+    assert(dvmIsClassLinked(clazz));
+    assert(gDvm.classJavaLangClass != NULL);
+    assert(clazz->clazz == gDvm.classJavaLangClass);
+    assert(dvmIsClassObject(clazz));
+    assert(clazz == gDvm.classJavaLangObject || clazz->super != NULL);
+    if (!dvmIsInterfaceClass(clazz)) {
+        //LOGI("class=%s vtableCount=%d, virtualMeth=%d",
+        //    clazz->descriptor, clazz->vtableCount,
+        //    clazz->virtualMethodCount);
+        assert(clazz->vtableCount >= clazz->virtualMethodCount);
+    }
+
+bail:
+    if (profilerNotified)
+        dvmMethodTraceClassPrepEnd();
+    assert(clazz != NULL || dvmCheckException(self));
+    return clazz;
+}
+
+/*
+ * Helper for loadClassFromDex, which takes a DexClassDataHeader and
+ * encoded data pointer in addition to the other arguments.
+ */
+static ClassObject* loadClassFromDex0(DvmDex* pDvmDex,
+    const DexClassDef* pClassDef, const DexClassDataHeader* pHeader,
+    const u1* pEncodedData, Object* classLoader)
+{
+    ClassObject* newClass = NULL;
+    const DexFile* pDexFile;
+    const char* descriptor;
+    int i;
+
+    pDexFile = pDvmDex->pDexFile;
+    descriptor = dexGetClassDescriptor(pDexFile, pClassDef);
+
+    /*
+     * Make sure the aren't any "bonus" flags set, since we use them for
+     * runtime state.
+     */
+    if ((pClassDef->accessFlags & ~EXPECTED_FILE_FLAGS) != 0) {
+        LOGW("Invalid file flags in class %s: %04x",
+            descriptor, pClassDef->accessFlags);
+        return NULL;
+    }
+
+    /*
+     * Allocate storage for the class object on the GC heap, so that other
+     * objects can have references to it.  We bypass the usual mechanism
+     * (allocObject), because we don't have all the bits and pieces yet.
+     *
+     * Note that we assume that java.lang.Class does not override
+     * finalize().
+     */
+    /* TODO: Can there be fewer special checks in the usual path? */
+    assert(descriptor != NULL);
+    if (classLoader == NULL &&
+        strcmp(descriptor, "Ljava/lang/Class;") == 0) {
+        assert(gDvm.classJavaLangClass != NULL);
+        newClass = gDvm.classJavaLangClass;
+    } else {
+        size_t size = classObjectSize(pHeader->staticFieldsSize);
+        newClass = (ClassObject*) dvmMalloc(size, ALLOC_NON_MOVING);
+    }
+    if (newClass == NULL)
+        return NULL;
+
+    DVM_OBJECT_INIT(newClass, gDvm.classJavaLangClass);
+    dvmSetClassSerialNumber(newClass);
+    newClass->descriptor = descriptor;
+    assert(newClass->descriptorAlloc == NULL);
+    SET_CLASS_FLAG(newClass, pClassDef->accessFlags);
+    dvmSetFieldObject((Object *)newClass,
+                      OFFSETOF_MEMBER(ClassObject, classLoader),
+                      (Object *)classLoader);
+    newClass->pDvmDex = pDvmDex;
+    newClass->primitiveType = PRIM_NOT;
+    newClass->status = CLASS_IDX;
+
+    /*
+     * Stuff the superclass index into the object pointer field.  The linker
+     * pulls it out and replaces it with a resolved ClassObject pointer.
+     * I'm doing it this way (rather than having a dedicated superclassIdx
+     * field) to save a few bytes of overhead per class.
+     *
+     * newClass->super is not traversed or freed by dvmFreeClassInnards, so
+     * this is safe.
+     */
+    assert(sizeof(u4) == sizeof(ClassObject*)); /* 32-bit check */
+    newClass->super = (ClassObject*) pClassDef->superclassIdx;
+
+    /*
+     * Stuff class reference indices into the pointer fields.
+     *
+     * The elements of newClass->interfaces are not traversed or freed by
+     * dvmFreeClassInnards, so this is GC-safe.
+     */
+    const DexTypeList* pInterfacesList;
+    pInterfacesList = dexGetInterfacesList(pDexFile, pClassDef);
+    if (pInterfacesList != NULL) {
+        newClass->interfaceCount = pInterfacesList->size;
+        newClass->interfaces = (ClassObject**) dvmLinearAlloc(classLoader,
+                newClass->interfaceCount * sizeof(ClassObject*));
+
+        for (i = 0; i < newClass->interfaceCount; i++) {
+            const DexTypeItem* pType = dexGetTypeItem(pInterfacesList, i);
+            newClass->interfaces[i] = (ClassObject*)(u4) pType->typeIdx;
+        }
+        dvmLinearReadOnly(classLoader, newClass->interfaces);
+    }
+
+    /* load field definitions */
+
+    /*
+     * Over-allocate the class object and append static field info
+     * onto the end.  It's fixed-size and known at alloc time.  This
+     * seems to increase zygote sharing.  Heap compaction will have to
+     * be careful if it ever tries to move ClassObject instances,
+     * because we pass Field pointers around internally. But at least
+     * now these Field pointers are in the object heap.
+     */
+
+    if (pHeader->staticFieldsSize != 0) {
+        /* static fields stay on system heap; field data isn't "write once" */
+        int count = (int) pHeader->staticFieldsSize;
+        u4 lastIndex = 0;
+        DexField field;
+
+        newClass->sfieldCount = count;
+        for (i = 0; i < count; i++) {
+            dexReadClassDataField(&pEncodedData, &field, &lastIndex);
+            loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
+        }
+    }
+
+    if (pHeader->instanceFieldsSize != 0) {
+        int count = (int) pHeader->instanceFieldsSize;
+        u4 lastIndex = 0;
+        DexField field;
+
+        newClass->ifieldCount = count;
+        newClass->ifields = (InstField*) dvmLinearAlloc(classLoader,
+                count * sizeof(InstField));
+        for (i = 0; i < count; i++) {
+            dexReadClassDataField(&pEncodedData, &field, &lastIndex);
+            loadIFieldFromDex(newClass, &field, &newClass->ifields[i]);
+        }
+        dvmLinearReadOnly(classLoader, newClass->ifields);
+    }
+
+    /*
+     * 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",
+                newClass->descriptor, pHeader->directMethodsSize,
+                pHeader->virtualMethodsSize, numMethods);
+            assert(false);
+            classMapData = NULL;        /* abandon */
+        }
+    } else {
+        classMapData = NULL;
+    }
+
+    if (pHeader->directMethodsSize != 0) {
+        int count = (int) pHeader->directMethodsSize;
+        u4 lastIndex = 0;
+        DexMethod method;
+
+        newClass->directMethodCount = count;
+        newClass->directMethods = (Method*) dvmLinearAlloc(classLoader,
+                count * sizeof(Method));
+        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);
+    }
+
+    if (pHeader->virtualMethodsSize != 0) {
+        int count = (int) pHeader->virtualMethodsSize;
+        u4 lastIndex = 0;
+        DexMethod method;
+
+        newClass->virtualMethodCount = count;
+        newClass->virtualMethods = (Method*) dvmLinearAlloc(classLoader,
+                count * sizeof(Method));
+        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);
+    }
+
+    newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return newClass;
+}
+
+/*
+ * Try to load the indicated class from the specified DEX file.
+ *
+ * This is effectively loadClass()+defineClass() for a DexClassDef.  The
+ * loading was largely done when we crunched through the DEX.
+ *
+ * Returns NULL on failure.  If we locate the class but encounter an error
+ * while processing it, an appropriate exception is thrown.
+ */
+static ClassObject* loadClassFromDex(DvmDex* pDvmDex,
+    const DexClassDef* pClassDef, Object* classLoader)
+{
+    ClassObject* result;
+    DexClassDataHeader header;
+    const u1* pEncodedData;
+    const DexFile* pDexFile;
+
+    assert((pDvmDex != NULL) && (pClassDef != NULL));
+    pDexFile = pDvmDex->pDexFile;
+
+    if (gDvm.verboseClass) {
+        LOGV("CLASS: loading '%s'...",
+            dexGetClassDescriptor(pDexFile, pClassDef));
+    }
+
+    pEncodedData = dexGetClassData(pDexFile, pClassDef);
+
+    if (pEncodedData != NULL) {
+        dexReadClassDataHeader(&pEncodedData, &header);
+    } else {
+        // Provide an all-zeroes header for the rest of the loading.
+        memset(&header, 0, sizeof(header));
+    }
+
+    result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData,
+            classLoader);
+
+    if (gDvm.verboseClass && (result != NULL)) {
+        LOGI("[Loaded %s from DEX %p (cl=%p)]",
+            result->descriptor, pDvmDex, classLoader);
+    }
+
+    return result;
+}
+
+/*
+ * Free anything in a ClassObject that was allocated on the system heap.
+ *
+ * The ClassObject itself is allocated on the GC heap, so we leave it for
+ * the garbage collector.
+ *
+ * NOTE: this may be called with a partially-constructed object.
+ * NOTE: there is no particular ordering imposed, so don't go poking at
+ * superclasses.
+ */
+void dvmFreeClassInnards(ClassObject* clazz)
+{
+    void *tp;
+    int i;
+
+    if (clazz == NULL)
+        return;
+
+    assert(clazz->clazz == gDvm.classJavaLangClass);
+    assert(dvmIsClassObject(clazz));
+
+    /* Guarantee that dvmFreeClassInnards can be called on a given
+     * class multiple times by clearing things out as we free them.
+     * We don't make any attempt at real atomicity here; higher
+     * levels need to make sure that no two threads can free the
+     * same ClassObject at the same time.
+     *
+     * TODO: maybe just make it so the GC will never free the
+     * innards of an already-freed class.
+     *
+     * TODO: this #define isn't MT-safe -- the compiler could rearrange it.
+     */
+#define NULL_AND_FREE(p) \
+    do { \
+        if ((p) != NULL) { \
+            tp = (p); \
+            (p) = NULL; \
+            free(tp); \
+        } \
+    } while (0)
+#define NULL_AND_LINEAR_FREE(p) \
+    do { \
+        if ((p) != NULL) { \
+            tp = (p); \
+            (p) = NULL; \
+            dvmLinearFree(clazz->classLoader, tp); \
+        } \
+    } while (0)
+
+    /* arrays just point at Object's vtable; don't free vtable in this case.
+     */
+    clazz->vtableCount = -1;
+    if (clazz->vtable == gDvm.classJavaLangObject->vtable) {
+        clazz->vtable = NULL;
+    } else {
+        NULL_AND_LINEAR_FREE(clazz->vtable);
+    }
+
+    clazz->descriptor = NULL;
+    NULL_AND_FREE(clazz->descriptorAlloc);
+
+    if (clazz->directMethods != NULL) {
+        Method *directMethods = clazz->directMethods;
+        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) {
+        Method *virtualMethods = clazz->virtualMethods;
+        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);
+    }
+
+    InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(clazz);
+    loaderList->initiatingLoaderCount = -1;
+    NULL_AND_FREE(loaderList->initiatingLoaders);
+
+    clazz->interfaceCount = -1;
+    NULL_AND_LINEAR_FREE(clazz->interfaces);
+
+    clazz->iftableCount = -1;
+    NULL_AND_LINEAR_FREE(clazz->iftable);
+
+    clazz->ifviPoolCount = -1;
+    NULL_AND_LINEAR_FREE(clazz->ifviPool);
+
+    clazz->sfieldCount = -1;
+    /* The sfields are attached to the ClassObject, and will be freed
+     * with it. */
+
+    clazz->ifieldCount = -1;
+    NULL_AND_LINEAR_FREE(clazz->ifields);
+
+#undef NULL_AND_FREE
+#undef NULL_AND_LINEAR_FREE
+}
+
+/*
+ * 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)
+{
+#if 0
+    free(meth->exceptions);
+    free(meth->lines);
+    free(meth->locals);
+#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().  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");
+        LOGE("        cloning %s.%s", src->clazz->descriptor, src->name);
+        dvmAbort();
+    }
+    memcpy(dst, src, sizeof(Method));
+}
+
+/*
+ * Pull the interesting pieces out of a DexMethod.
+ *
+ * The DEX file isn't going anywhere, so we don't need to make copies of
+ * the code area.
+ */
+static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod,
+    Method* meth)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexMethodId* pMethodId;
+    const DexCode* pDexCode;
+
+    pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+
+    meth->name = dexStringById(pDexFile, pMethodId->nameIdx);
+    dexProtoSetFromMethodId(&meth->prototype, pDexFile, pMethodId);
+    meth->shorty = dexProtoGetShorty(&meth->prototype);
+    meth->accessFlags = pDexMethod->accessFlags;
+    meth->clazz = clazz;
+    meth->jniArgInfo = 0;
+
+    if (dvmCompareNameDescriptorAndMethod("finalize", "()V", meth) == 0) {
+        /*
+         * The Enum class declares a "final" finalize() method to
+         * prevent subclasses from introducing a finalizer.  We don't
+         * want to set the finalizable flag for Enum or its subclasses,
+         * so we check for it here.
+         *
+         * We also want to avoid setting it on Object, but it's easier
+         * to just strip that out later.
+         */
+        if (clazz->classLoader != NULL ||
+            strcmp(clazz->descriptor, "Ljava/lang/Enum;") != 0)
+        {
+            SET_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
+        }
+    }
+
+    pDexCode = dexGetCode(pDexFile, pDexMethod);
+    if (pDexCode != NULL) {
+        /* integer constants, copy over for faster access */
+        meth->registersSize = pDexCode->registersSize;
+        meth->insSize = pDexCode->insSize;
+        meth->outsSize = pDexCode->outsSize;
+
+        /* pointer to code area */
+        meth->insns = pDexCode->insns;
+    } else {
+        /*
+         * We don't have a DexCode block, but we still want to know how
+         * much space is needed for the arguments (so we don't have to
+         * compute it later).  We also take this opportunity to compute
+         * JNI argument info.
+         *
+         * We do this for abstract methods as well, because we want to
+         * be able to substitute our exception-throwing "stub" in.
+         */
+        int argsSize = dvmComputeMethodArgsSize(meth);
+        if (!dvmIsStaticMethod(meth))
+            argsSize++;
+        meth->registersSize = meth->insSize = argsSize;
+        assert(meth->outsSize == 0);
+        assert(meth->insns == NULL);
+
+        if (dvmIsNativeMethod(meth)) {
+            meth->nativeFunc = dvmResolveNativeMethod;
+            meth->jniArgInfo = computeJniArgInfo(&meth->prototype);
+        }
+    }
+}
+
+#if 0       /* replaced with private/read-write mapping */
+/*
+ * 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)",
+        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", methodDexCode);
+    dvmLinearReadOnly(meth->clazz->classLoader, methodDexCode);
+}
+#endif
+
+
+/*
+ * jniArgInfo (32-bit int) layout:
+ *   SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
+ *
+ *   S - if set, do things the hard way (scan the signature)
+ *   R - return-type enumeration
+ *   H - target-specific hints
+ *
+ * This info is used at invocation time by dvmPlatformInvoke.  In most
+ * cases, the target-specific hints allow dvmPlatformInvoke to avoid
+ * having to fully parse the signature.
+ *
+ * The return-type bits are always set, even if target-specific hint bits
+ * are unavailable.
+ */
+static int computeJniArgInfo(const DexProto* proto)
+{
+    const char* sig = dexProtoGetShorty(proto);
+    int returnType, jniArgInfo;
+    u4 hints;
+
+    /* The first shorty character is the return type. */
+    switch (*(sig++)) {
+    case 'V':
+        returnType = DALVIK_JNI_RETURN_VOID;
+        break;
+    case 'F':
+        returnType = DALVIK_JNI_RETURN_FLOAT;
+        break;
+    case 'D':
+        returnType = DALVIK_JNI_RETURN_DOUBLE;
+        break;
+    case 'J':
+        returnType = DALVIK_JNI_RETURN_S8;
+        break;
+    case 'Z':
+    case 'B':
+        returnType = DALVIK_JNI_RETURN_S1;
+        break;
+    case 'C':
+        returnType = DALVIK_JNI_RETURN_U2;
+        break;
+    case 'S':
+        returnType = DALVIK_JNI_RETURN_S2;
+        break;
+    default:
+        returnType = DALVIK_JNI_RETURN_S4;
+        break;
+    }
+
+    jniArgInfo = returnType << DALVIK_JNI_RETURN_SHIFT;
+
+    hints = dvmPlatformInvokeHints(proto);
+
+    if (hints & DALVIK_JNI_NO_ARG_INFO) {
+        jniArgInfo |= DALVIK_JNI_NO_ARG_INFO;
+    } else {
+        assert((hints & DALVIK_JNI_RETURN_MASK) == 0);
+        jniArgInfo |= hints;
+    }
+
+    return jniArgInfo;
+}
+
+/*
+ * Load information about a static field.
+ *
+ * This also "prepares" static fields by initializing them
+ * to their "standard default values".
+ */
+static void loadSFieldFromDex(ClassObject* clazz,
+    const DexField* pDexSField, StaticField* sfield)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexFieldId* pFieldId;
+
+    pFieldId = dexGetFieldId(pDexFile, pDexSField->fieldIdx);
+
+    sfield->clazz = clazz;
+    sfield->name = dexStringById(pDexFile, pFieldId->nameIdx);
+    sfield->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    sfield->accessFlags = pDexSField->accessFlags;
+
+    /* Static object field values are set to "standard default values"
+     * (null or 0) until the class is initialized.  We delay loading
+     * constant values from the class until that time.
+     */
+    //sfield->value.j = 0;
+    assert(sfield->value.j == 0LL);     // cleared earlier with calloc
+}
+
+/*
+ * Load information about an instance field.
+ */
+static void loadIFieldFromDex(ClassObject* clazz,
+    const DexField* pDexIField, InstField* ifield)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexFieldId* pFieldId;
+
+    pFieldId = dexGetFieldId(pDexFile, pDexIField->fieldIdx);
+
+    ifield->clazz = clazz;
+    ifield->name = dexStringById(pDexFile, pFieldId->nameIdx);
+    ifield->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+    ifield->accessFlags = pDexIField->accessFlags;
+#ifndef NDEBUG
+    assert(ifield->byteOffset == 0);    // cleared earlier with calloc
+    ifield->byteOffset = -1;    // make it obvious if we fail to set later
+#endif
+}
+
+/*
+ * Cache java.lang.ref.Reference fields and methods.
+ */
+static bool precacheReferenceOffsets(ClassObject* clazz)
+{
+    int i;
+
+    /* We trick the GC object scanner by not counting
+     * java.lang.ref.Reference.referent as an object
+     * field.  It will get explicitly scanned as part
+     * of the reference-walking process.
+     *
+     * Find the object field named "referent" and put it
+     * just after the list of object reference fields.
+     */
+    dvmLinearReadWrite(clazz->classLoader, clazz->ifields);
+    for (i = 0; i < clazz->ifieldRefCount; i++) {
+        InstField *pField = &clazz->ifields[i];
+        if (strcmp(pField->name, "referent") == 0) {
+            int targetIndex;
+
+            /* Swap this field with the last object field.
+             */
+            targetIndex = clazz->ifieldRefCount - 1;
+            if (i != targetIndex) {
+                InstField *swapField = &clazz->ifields[targetIndex];
+                InstField tmpField;
+                int tmpByteOffset;
+
+                /* It's not currently strictly necessary
+                 * for the fields to be in byteOffset order,
+                 * but it's more predictable that way.
+                 */
+                tmpByteOffset = swapField->byteOffset;
+                swapField->byteOffset = pField->byteOffset;
+                pField->byteOffset = tmpByteOffset;
+
+                tmpField = *swapField;
+                *swapField = *pField;
+                *pField = tmpField;
+            }
+
+            /* One fewer object field (wink wink).
+             */
+            clazz->ifieldRefCount--;
+            i--;        /* don't trip "didn't find it" test if field was last */
+            break;
+        }
+    }
+    dvmLinearReadOnly(clazz->classLoader, clazz->ifields);
+    if (i == clazz->ifieldRefCount) {
+        LOGE("Unable to reorder 'referent' in %s", clazz->descriptor);
+        return false;
+    }
+
+    /*
+     * Now that the above has been done, it is safe to cache
+     * info about the class.
+     */
+    if (!dvmFindReferenceMembers(clazz)) {
+        LOGE("Trouble with Reference setup");
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Set the bitmap of reference offsets, refOffsets, from the ifields
+ * list.
+ */
+static void computeRefOffsets(ClassObject* clazz)
+{
+    if (clazz->super != NULL) {
+        clazz->refOffsets = clazz->super->refOffsets;
+    } else {
+        clazz->refOffsets = 0;
+    }
+    /*
+     * If our superclass overflowed, we don't stand a chance.
+     */
+    if (clazz->refOffsets != CLASS_WALK_SUPER) {
+        InstField *f;
+        int i;
+
+        /* All of the fields that contain object references
+         * are guaranteed to be at the beginning of the ifields list.
+         */
+        f = clazz->ifields;
+        const int ifieldRefCount = clazz->ifieldRefCount;
+        for (i = 0; i < ifieldRefCount; i++) {
+          /*
+           * Note that, per the comment on struct InstField,
+           * f->byteOffset is the offset from the beginning of
+           * obj, not the offset into obj->instanceData.
+           */
+          assert(f->byteOffset >= (int) CLASS_SMALLEST_OFFSET);
+          assert((f->byteOffset & (CLASS_OFFSET_ALIGNMENT - 1)) == 0);
+          if (CLASS_CAN_ENCODE_OFFSET(f->byteOffset)) {
+              u4 newBit = CLASS_BIT_FROM_OFFSET(f->byteOffset);
+              assert(newBit != 0);
+              clazz->refOffsets |= newBit;
+          } else {
+              clazz->refOffsets = CLASS_WALK_SUPER;
+              break;
+          }
+          f++;
+        }
+    }
+}
+
+
+/*
+ * Link (prepare and resolve).  Verification is deferred until later.
+ *
+ * This converts symbolic references into pointers.  It's independent of
+ * the source file format.
+ *
+ * If clazz->status is CLASS_IDX, then clazz->super and interfaces[] are
+ * holding class reference indices rather than pointers.  The class
+ * references will be resolved during link.  (This is done when
+ * loading from DEX to avoid having to create additional storage to
+ * pass the indices around.)
+ *
+ * Returns "false" with an exception pending on failure.
+ */
+bool dvmLinkClass(ClassObject* clazz)
+{
+    u4 superclassIdx = 0;
+    u4 *interfaceIdxArray = NULL;
+    bool okay = false;
+    int i;
+
+    assert(clazz != NULL);
+    assert(clazz->descriptor != NULL);
+    assert(clazz->status == CLASS_IDX || clazz->status == CLASS_LOADED);
+    if (gDvm.verboseClass)
+        LOGV("CLASS: linking '%s'...", clazz->descriptor);
+
+    assert(gDvm.classJavaLangClass != NULL);
+    assert(clazz->clazz == gDvm.classJavaLangClass);
+    assert(dvmIsClassObject(clazz));
+    if (clazz->classLoader == NULL &&
+        (strcmp(clazz->descriptor, "Ljava/lang/Class;") == 0))
+    {
+        if (gDvm.classJavaLangClass->ifieldCount > CLASS_FIELD_SLOTS) {
+            LOGE("java.lang.Class has %d instance fields (expected at most %d)",
+                 gDvm.classJavaLangClass->ifieldCount, CLASS_FIELD_SLOTS);
+            dvmAbort();
+        }
+        if (gDvm.classJavaLangClass->sfieldCount != CLASS_SFIELD_SLOTS) {
+            LOGE("java.lang.Class has %d static fields (expected %d)",
+                 gDvm.classJavaLangClass->sfieldCount, CLASS_SFIELD_SLOTS);
+            dvmAbort();
+        }
+    }
+
+    /* "Resolve" the class.
+     *
+     * At this point, clazz's reference fields may contain Dex file
+     * indices instead of direct object references.  Proxy objects are
+     * an exception, and may be the only exception.  We need to
+     * translate those indices into real references, and let the GC
+     * look inside this ClassObject.
+     */
+    if (clazz->status == CLASS_IDX) {
+        if (clazz->interfaceCount > 0) {
+            /* Copy u4 DEX idx values out of the ClassObject* array
+             * where we stashed them.
+             */
+            assert(sizeof(*interfaceIdxArray) == sizeof(*clazz->interfaces));
+            size_t len = clazz->interfaceCount * sizeof(*interfaceIdxArray);
+            interfaceIdxArray = (u4*)malloc(len);
+            if (interfaceIdxArray == NULL) {
+                LOGW("Unable to allocate memory to link %s", clazz->descriptor);
+                goto bail;
+            }
+            memcpy(interfaceIdxArray, clazz->interfaces, len);
+
+            dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
+            memset(clazz->interfaces, 0, len);
+            dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+        }
+
+        assert(sizeof(superclassIdx) == sizeof(clazz->super));
+        superclassIdx = (u4) clazz->super;
+        clazz->super = NULL;
+        /* After this line, clazz will be fair game for the GC. The
+         * superclass and interfaces are all NULL.
+         */
+        clazz->status = CLASS_LOADED;
+
+        if (superclassIdx != kDexNoIndex) {
+            ClassObject* super = dvmResolveClass(clazz, superclassIdx, false);
+            if (super == NULL) {
+                assert(dvmCheckException(dvmThreadSelf()));
+                if (gDvm.optimizing) {
+                    /* happens with "external" libs */
+                    LOGV("Unable to resolve superclass of %s (%d)",
+                         clazz->descriptor, superclassIdx);
+                } else {
+                    LOGW("Unable to resolve superclass of %s (%d)",
+                         clazz->descriptor, superclassIdx);
+                }
+                goto bail;
+            }
+            dvmSetFieldObject((Object *)clazz,
+                              OFFSETOF_MEMBER(ClassObject, super),
+                              (Object *)super);
+        }
+
+        if (clazz->interfaceCount > 0) {
+            /* Resolve the interfaces implemented directly by this class. */
+            assert(interfaceIdxArray != NULL);
+            dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
+            for (i = 0; i < clazz->interfaceCount; i++) {
+                assert(interfaceIdxArray[i] != kDexNoIndex);
+                clazz->interfaces[i] =
+                    dvmResolveClass(clazz, interfaceIdxArray[i], false);
+                if (clazz->interfaces[i] == NULL) {
+                    const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+
+                    assert(dvmCheckException(dvmThreadSelf()));
+                    dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+
+                    const char* classDescriptor;
+                    classDescriptor =
+                        dexStringByTypeIdx(pDexFile, interfaceIdxArray[i]);
+                    if (gDvm.optimizing) {
+                        /* happens with "external" libs */
+                        LOGV("Failed resolving %s interface %d '%s'",
+                             clazz->descriptor, interfaceIdxArray[i],
+                             classDescriptor);
+                    } else {
+                        LOGI("Failed resolving %s interface %d '%s'",
+                             clazz->descriptor, interfaceIdxArray[i],
+                             classDescriptor);
+                    }
+                    goto bail;
+                }
+
+                /* are we allowed to implement this interface? */
+                if (!dvmCheckClassAccess(clazz, clazz->interfaces[i])) {
+                    dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+                    LOGW("Interface '%s' is not accessible to '%s'",
+                         clazz->interfaces[i]->descriptor, clazz->descriptor);
+                    dvmThrowIllegalAccessError("interface not accessible");
+                    goto bail;
+                }
+                LOGVV("+++  found interface '%s'",
+                      clazz->interfaces[i]->descriptor);
+            }
+            dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
+        }
+    }
+    /*
+     * There are now Class references visible to the GC in super and
+     * interfaces.
+     */
+
+    /*
+     * All classes have a direct superclass, except for
+     * java/lang/Object and primitive classes. Primitive classes are
+     * are created CLASS_INITIALIZED, so won't get here.
+     */
+    assert(clazz->primitiveType == PRIM_NOT);
+    if (strcmp(clazz->descriptor, "Ljava/lang/Object;") == 0) {
+        if (clazz->super != NULL) {
+            /* TODO: is this invariant true for all java/lang/Objects,
+             * regardless of the class loader?  For now, assume it is.
+             */
+            dvmThrowClassFormatError("java.lang.Object has a superclass");
+            goto bail;
+        }
+
+        /* Don't finalize objects whose classes use the
+         * default (empty) Object.finalize().
+         */
+        CLEAR_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
+    } else {
+        if (clazz->super == NULL) {
+            dvmThrowLinkageError("no superclass defined");
+            goto bail;
+        }
+        /* verify */
+        if (dvmIsFinalClass(clazz->super)) {
+            LOGW("Superclass of '%s' is final '%s'",
+                clazz->descriptor, clazz->super->descriptor);
+            dvmThrowIncompatibleClassChangeError("superclass is final");
+            goto bail;
+        } else if (dvmIsInterfaceClass(clazz->super)) {
+            LOGW("Superclass of '%s' is interface '%s'",
+                clazz->descriptor, clazz->super->descriptor);
+            dvmThrowIncompatibleClassChangeError("superclass is an interface");
+            goto bail;
+        } else if (!dvmCheckClassAccess(clazz, clazz->super)) {
+            LOGW("Superclass of '%s' (%s) is not accessible",
+                clazz->descriptor, clazz->super->descriptor);
+            dvmThrowIllegalAccessError("superclass not accessible");
+            goto bail;
+        }
+
+        /* Inherit finalizability from the superclass.  If this
+         * class also overrides finalize(), its CLASS_ISFINALIZABLE
+         * bit will already be set.
+         */
+        if (IS_CLASS_FLAG_SET(clazz->super, CLASS_ISFINALIZABLE)) {
+            SET_CLASS_FLAG(clazz, CLASS_ISFINALIZABLE);
+        }
+
+        /* See if this class descends from java.lang.Reference
+         * and set the class flags appropriately.
+         */
+        if (IS_CLASS_FLAG_SET(clazz->super, CLASS_ISREFERENCE)) {
+            u4 superRefFlags;
+
+            /* We've already determined the reference type of this
+             * inheritance chain.  Inherit reference-ness from the superclass.
+             */
+            superRefFlags = GET_CLASS_FLAG_GROUP(clazz->super,
+                    CLASS_ISREFERENCE |
+                    CLASS_ISWEAKREFERENCE |
+                    CLASS_ISFINALIZERREFERENCE |
+                    CLASS_ISPHANTOMREFERENCE);
+            SET_CLASS_FLAG(clazz, superRefFlags);
+        } else if (clazz->classLoader == NULL &&
+                clazz->super->classLoader == NULL &&
+                strcmp(clazz->super->descriptor,
+                       "Ljava/lang/ref/Reference;") == 0)
+        {
+            u4 refFlags;
+
+            /* This class extends Reference, which means it should
+             * be one of the magic Soft/Weak/PhantomReference classes.
+             */
+            refFlags = CLASS_ISREFERENCE;
+            if (strcmp(clazz->descriptor,
+                       "Ljava/lang/ref/SoftReference;") == 0)
+            {
+                /* Only CLASS_ISREFERENCE is set for soft references.
+                 */
+            } else if (strcmp(clazz->descriptor,
+                       "Ljava/lang/ref/WeakReference;") == 0)
+            {
+                refFlags |= CLASS_ISWEAKREFERENCE;
+            } else if (strcmp(clazz->descriptor,
+                       "Ljava/lang/ref/FinalizerReference;") == 0)
+            {
+                refFlags |= CLASS_ISFINALIZERREFERENCE;
+            }  else if (strcmp(clazz->descriptor,
+                       "Ljava/lang/ref/PhantomReference;") == 0)
+            {
+                refFlags |= CLASS_ISPHANTOMREFERENCE;
+            } else {
+                /* No-one else is allowed to inherit directly
+                 * from Reference.
+                 */
+//xxx is this the right exception?  better than an assertion.
+                dvmThrowLinkageError("illegal inheritance from Reference");
+                goto bail;
+            }
+
+            /* The class should not have any reference bits set yet.
+             */
+            assert(GET_CLASS_FLAG_GROUP(clazz,
+                    CLASS_ISREFERENCE |
+                    CLASS_ISWEAKREFERENCE |
+                    CLASS_ISFINALIZERREFERENCE |
+                    CLASS_ISPHANTOMREFERENCE) == 0);
+
+            SET_CLASS_FLAG(clazz, refFlags);
+        }
+    }
+
+    /*
+     * Populate vtable.
+     */
+    if (dvmIsInterfaceClass(clazz)) {
+        /* no vtable; just set the method indices */
+        int count = clazz->virtualMethodCount;
+
+        if (count != (u2) count) {
+            LOGE("Too many methods (%d) in interface '%s'", count,
+                 clazz->descriptor);
+            goto bail;
+        }
+
+        dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
+
+        for (i = 0; i < count; i++)
+            clazz->virtualMethods[i].methodIndex = (u2) i;
+
+        dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+    } else {
+        if (!createVtable(clazz)) {
+            LOGW("failed creating vtable");
+            goto bail;
+        }
+    }
+
+    /*
+     * Populate interface method tables.  Can alter the vtable.
+     */
+    if (!createIftable(clazz))
+        goto bail;
+
+    /*
+     * Insert special-purpose "stub" method implementations.
+     */
+    if (!insertMethodStubs(clazz))
+        goto bail;
+
+    /*
+     * Compute instance field offsets and, hence, the size of the object.
+     */
+    if (!computeFieldOffsets(clazz))
+        goto bail;
+
+    /*
+     * Cache field and method info for the class Reference (as loaded
+     * by the boot classloader). This has to happen after the call to
+     * computeFieldOffsets().
+     */
+    if ((clazz->classLoader == NULL)
+            && (strcmp(clazz->descriptor, "Ljava/lang/ref/Reference;") == 0)) {
+        if (!precacheReferenceOffsets(clazz)) {
+            LOGE("failed pre-caching Reference offsets");
+            dvmThrowInternalError(NULL);
+            goto bail;
+        }
+    }
+
+    /*
+     * Compact the offsets the GC has to examine into a bitmap, if
+     * possible.  (This has to happen after Reference.referent is
+     * massaged in precacheReferenceOffsets.)
+     */
+    computeRefOffsets(clazz);
+
+    /*
+     * Done!
+     */
+    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED))
+        clazz->status = CLASS_VERIFIED;
+    else
+        clazz->status = CLASS_RESOLVED;
+    okay = true;
+    if (gDvm.verboseClass)
+        LOGV("CLASS: linked '%s'", clazz->descriptor);
+
+    /*
+     * We send CLASS_PREPARE events to the debugger from here.  The
+     * definition of "preparation" is creating the static fields for a
+     * class and initializing them to the standard default values, but not
+     * executing any code (that comes later, during "initialization").
+     *
+     * We did the static prep in loadSFieldFromDex() while loading the class.
+     *
+     * The class has been prepared and resolved but possibly not yet verified
+     * at this point.
+     */
+    if (gDvm.debuggerActive) {
+        dvmDbgPostClassPrepare(clazz);
+    }
+
+bail:
+    if (!okay) {
+        clazz->status = CLASS_ERROR;
+        if (!dvmCheckException(dvmThreadSelf())) {
+            dvmThrowVirtualMachineError(NULL);
+        }
+    }
+    if (interfaceIdxArray != NULL) {
+        free(interfaceIdxArray);
+    }
+
+    return okay;
+}
+
+/*
+ * Create the virtual method table.
+ *
+ * The top part of the table is a copy of the table from our superclass,
+ * with our local methods overriding theirs.  The bottom part of the table
+ * has any new methods we defined.
+ */
+static bool createVtable(ClassObject* clazz)
+{
+    bool result = false;
+    int maxCount;
+    int i;
+
+    if (clazz->super != NULL) {
+        //LOGI("SUPER METHODS %d %s->%s", clazz->super->vtableCount,
+        //    clazz->descriptor, clazz->super->descriptor);
+    }
+
+    /* the virtual methods we define, plus the superclass vtable size */
+    maxCount = clazz->virtualMethodCount;
+    if (clazz->super != NULL) {
+        maxCount += clazz->super->vtableCount;
+    } else {
+        /* TODO: is this invariant true for all java/lang/Objects,
+         * regardless of the class loader?  For now, assume it is.
+         */
+        assert(strcmp(clazz->descriptor, "Ljava/lang/Object;") == 0);
+    }
+    //LOGD("+++ max vmethods for '%s' is %d", clazz->descriptor, maxCount);
+
+    /*
+     * Over-allocate the table, then realloc it down if necessary.  So
+     * long as we don't allocate anything in between we won't cause
+     * fragmentation, and reducing the size should be unlikely to cause
+     * a buffer copy.
+     */
+    dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
+    clazz->vtable = (Method**) dvmLinearAlloc(clazz->classLoader,
+                        sizeof(Method*) * maxCount);
+    if (clazz->vtable == NULL)
+        goto bail;
+
+    if (clazz->super != NULL) {
+        int actualCount;
+
+        memcpy(clazz->vtable, clazz->super->vtable,
+            sizeof(*(clazz->vtable)) * clazz->super->vtableCount);
+        actualCount = clazz->super->vtableCount;
+
+        /*
+         * See if any of our virtual methods override the superclass.
+         */
+        for (i = 0; i < clazz->virtualMethodCount; i++) {
+            Method* localMeth = &clazz->virtualMethods[i];
+            int si;
+
+            for (si = 0; si < clazz->super->vtableCount; si++) {
+                Method* superMeth = clazz->vtable[si];
+
+                if (dvmCompareMethodNamesAndProtos(localMeth, superMeth) == 0)
+                {
+                    /* verify */
+                    if (dvmIsFinalMethod(superMeth)) {
+                        LOGW("Method %s.%s overrides final %s.%s",
+                            localMeth->clazz->descriptor, localMeth->name,
+                            superMeth->clazz->descriptor, superMeth->name);
+                        goto bail;
+                    }
+                    clazz->vtable[si] = localMeth;
+                    localMeth->methodIndex = (u2) si;
+                    //LOGV("+++   override %s.%s (slot %d)",
+                    //    clazz->descriptor, localMeth->name, si);
+                    break;
+                }
+            }
+
+            if (si == clazz->super->vtableCount) {
+                /* not an override, add to end */
+                clazz->vtable[actualCount] = localMeth;
+                localMeth->methodIndex = (u2) actualCount;
+                actualCount++;
+
+                //LOGV("+++   add method %s.%s",
+                //    clazz->descriptor, localMeth->name);
+            }
+        }
+
+        if (actualCount != (u2) actualCount) {
+            LOGE("Too many methods (%d) in class '%s'", actualCount,
+                 clazz->descriptor);
+            goto bail;
+        }
+
+        assert(actualCount <= maxCount);
+
+        if (actualCount < maxCount) {
+            assert(clazz->vtable != NULL);
+            dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
+            clazz->vtable = (Method **)dvmLinearRealloc(clazz->classLoader,
+                clazz->vtable, sizeof(*(clazz->vtable)) * actualCount);
+            if (clazz->vtable == NULL) {
+                LOGE("vtable realloc failed");
+                goto bail;
+            } else {
+                LOGVV("+++  reduced vtable from %d to %d",
+                    maxCount, actualCount);
+            }
+        }
+
+        clazz->vtableCount = actualCount;
+    } else {
+        /* java/lang/Object case */
+        int count = clazz->virtualMethodCount;
+        if (count != (u2) count) {
+            LOGE("Too many methods (%d) in base class '%s'", count,
+                 clazz->descriptor);
+            goto bail;
+        }
+
+        for (i = 0; i < count; i++) {
+            clazz->vtable[i] = &clazz->virtualMethods[i];
+            clazz->virtualMethods[i].methodIndex = (u2) i;
+        }
+        clazz->vtableCount = clazz->virtualMethodCount;
+    }
+
+    result = true;
+
+bail:
+    dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
+    dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+    return result;
+}
+
+/*
+ * Create and populate "iftable".
+ *
+ * The set of interfaces we support is the combination of the interfaces
+ * we implement directly and those implemented by our superclass.  Each
+ * interface can have one or more "superinterfaces", which we must also
+ * support.  For speed we flatten the tree out.
+ *
+ * We might be able to speed this up when there are lots of interfaces
+ * by merge-sorting the class pointers and binary-searching when removing
+ * duplicates.  We could also drop the duplicate removal -- it's only
+ * there to reduce the memory footprint.
+ *
+ * Because of "Miranda methods", this may reallocate clazz->virtualMethods.
+ *
+ * Returns "true" on success.
+ */
+static bool createIftable(ClassObject* clazz)
+{
+    bool result = false;
+    bool zapIftable = false;
+    bool zapVtable = false;
+    bool zapIfvipool = false;
+    int poolOffset = 0, poolSize = 0;
+    Method** mirandaList = NULL;
+    int mirandaCount = 0, mirandaAlloc = 0;
+
+    int superIfCount;
+    if (clazz->super != NULL)
+        superIfCount = clazz->super->iftableCount;
+    else
+        superIfCount = 0;
+
+    int ifCount = superIfCount;
+    ifCount += clazz->interfaceCount;
+    for (int i = 0; i < clazz->interfaceCount; i++)
+        ifCount += clazz->interfaces[i]->iftableCount;
+
+    LOGVV("INTF: class '%s' direct w/supra=%d super=%d total=%d",
+        clazz->descriptor, ifCount - superIfCount, superIfCount, ifCount);
+
+    if (ifCount == 0) {
+        assert(clazz->iftableCount == 0);
+        assert(clazz->iftable == NULL);
+        return true;
+    }
+
+    /*
+     * Create a table with enough space for all interfaces, and copy the
+     * superclass' table in.
+     */
+    clazz->iftable = (InterfaceEntry*) dvmLinearAlloc(clazz->classLoader,
+                        sizeof(InterfaceEntry) * ifCount);
+    zapIftable = true;
+    memset(clazz->iftable, 0x00, sizeof(InterfaceEntry) * ifCount);
+    if (superIfCount != 0) {
+        memcpy(clazz->iftable, clazz->super->iftable,
+            sizeof(InterfaceEntry) * superIfCount);
+    }
+
+    /*
+     * Create a flattened interface hierarchy of our immediate interfaces.
+     */
+    int idx = superIfCount;
+
+    for (int i = 0; i < clazz->interfaceCount; i++) {
+        ClassObject* interf = clazz->interfaces[i];
+        assert(interf != NULL);
+
+        /* make sure this is still an interface class */
+        if (!dvmIsInterfaceClass(interf)) {
+            LOGW("Class '%s' implements non-interface '%s'",
+                clazz->descriptor, interf->descriptor);
+            dvmThrowIncompatibleClassChangeErrorWithClassMessage(
+                clazz->descriptor);
+            goto bail;
+        }
+
+        /* add entry for this interface */
+        clazz->iftable[idx++].clazz = interf;
+
+        /* add entries for the interface's superinterfaces */
+        for (int j = 0; j < interf->iftableCount; j++) {
+            clazz->iftable[idx++].clazz = interf->iftable[j].clazz;
+        }
+    }
+
+    assert(idx == ifCount);
+
+    if (false) {
+        /*
+         * Remove anything redundant from our recent additions.  Note we have
+         * to traverse the recent adds when looking for duplicates, because
+         * it's possible the recent additions are self-redundant.  This
+         * reduces the memory footprint of classes with lots of inherited
+         * interfaces.
+         *
+         * (I don't know if this will cause problems later on when we're trying
+         * to find a static field.  It looks like the proper search order is
+         * (1) current class, (2) interfaces implemented by current class,
+         * (3) repeat with superclass.  A field implemented by an interface
+         * and by a superclass might come out wrong if the superclass also
+         * implements the interface.  The javac compiler will reject the
+         * situation as ambiguous, so the concern is somewhat artificial.)
+         *
+         * UPDATE: this makes ReferenceType.Interfaces difficult to implement,
+         * because it wants to return just the interfaces declared to be
+         * implemented directly by the class.  I'm excluding this code for now.
+         */
+        for (int i = superIfCount; i < ifCount; i++) {
+            for (int j = 0; j < ifCount; j++) {
+                if (i == j)
+                    continue;
+                if (clazz->iftable[i].clazz == clazz->iftable[j].clazz) {
+                    LOGVV("INTF: redundant interface %s in %s",
+                        clazz->iftable[i].clazz->descriptor,
+                        clazz->descriptor);
+
+                    if (i != ifCount-1)
+                        memmove(&clazz->iftable[i], &clazz->iftable[i+1],
+                            (ifCount - i -1) * sizeof(InterfaceEntry));
+                    ifCount--;
+                    i--;        // adjust for i++ above
+                    break;
+                }
+            }
+        }
+        LOGVV("INTF: class '%s' nodupes=%d", clazz->descriptor, ifCount);
+    } // if (false)
+
+    clazz->iftableCount = ifCount;
+
+    /*
+     * If we're an interface, we don't need the vtable pointers, so
+     * we're done.  If this class doesn't implement an interface that our
+     * superclass doesn't have, then we again have nothing to do.
+     */
+    if (dvmIsInterfaceClass(clazz) || superIfCount == ifCount) {
+        //dvmDumpClass(clazz, kDumpClassFullDetail);
+        result = true;
+        goto bail;
+    }
+
+    /*
+     * When we're handling invokeinterface, we probably have an object
+     * whose type is an interface class rather than a concrete class.  We
+     * need to convert the method reference into a vtable index.  So, for
+     * every entry in "iftable", we create a list of vtable indices.
+     *
+     * Because our vtable encompasses the superclass vtable, we can use
+     * the vtable indices from our superclass for all of the interfaces
+     * that weren't directly implemented by us.
+     *
+     * Each entry in "iftable" has a pointer to the start of its set of
+     * vtable offsets.  The iftable entries in the superclass point to
+     * storage allocated in the superclass, and the iftable entries added
+     * for this class point to storage allocated in this class.  "iftable"
+     * is flat for fast access in a class and all of its subclasses, but
+     * "ifviPool" is only created for the topmost implementor.
+     */
+    for (int i = superIfCount; i < ifCount; i++) {
+        /*
+         * Note it's valid for an interface to have no methods (e.g.
+         * java/io/Serializable).
+         */
+        LOGVV("INTF: pool: %d from %s",
+            clazz->iftable[i].clazz->virtualMethodCount,
+            clazz->iftable[i].clazz->descriptor);
+        poolSize += clazz->iftable[i].clazz->virtualMethodCount;
+    }
+
+    if (poolSize == 0) {
+        LOGVV("INTF: didn't find any new interfaces with methods");
+        result = true;
+        goto bail;
+    }
+
+    clazz->ifviPoolCount = poolSize;
+    clazz->ifviPool = (int*) dvmLinearAlloc(clazz->classLoader,
+                        poolSize * sizeof(int*));
+    zapIfvipool = true;
+
+    /*
+     * Fill in the vtable offsets for the interfaces that weren't part of
+     * our superclass.
+     */
+    for (int i = superIfCount; i < ifCount; i++) {
+        ClassObject* interface;
+        int methIdx;
+
+        clazz->iftable[i].methodIndexArray = clazz->ifviPool + poolOffset;
+        interface = clazz->iftable[i].clazz;
+        poolOffset += interface->virtualMethodCount;    // end here
+
+        /*
+         * For each method listed in the interface's method list, find the
+         * matching method in our class's method list.  We want to favor the
+         * subclass over the superclass, which just requires walking
+         * back from the end of the vtable.  (This only matters if the
+         * superclass defines a private method and this class redefines
+         * it -- otherwise it would use the same vtable slot.  In Dalvik
+         * those don't end up in the virtual method table, so it shouldn't
+         * matter which direction we go.  We walk it backward anyway.)
+         *
+         *
+         * Suppose we have the following arrangement:
+         *   public interface MyInterface
+         *     public boolean inInterface();
+         *   public abstract class MirandaAbstract implements MirandaInterface
+         *     //public abstract boolean inInterface(); // not declared!
+         *     public boolean inAbstract() { stuff }    // in vtable
+         *   public class MirandClass extends MirandaAbstract
+         *     public boolean inInterface() { stuff }
+         *     public boolean inAbstract() { stuff }    // in vtable
+         *
+         * The javac compiler happily compiles MirandaAbstract even though
+         * it doesn't declare all methods from its interface.  When we try
+         * to set up a vtable for MirandaAbstract, we find that we don't
+         * have an slot for inInterface.  To prevent this, we synthesize
+         * abstract method declarations in MirandaAbstract.
+         *
+         * We have to expand vtable and update some things that point at it,
+         * so we accumulate the method list and do it all at once below.
+         */
+        for (methIdx = 0; methIdx < interface->virtualMethodCount; methIdx++) {
+            Method* imeth = &interface->virtualMethods[methIdx];
+            int j;
+
+            IF_LOGVV() {
+                char* desc = dexProtoCopyMethodDescriptor(&imeth->prototype);
+                LOGVV("INTF:  matching '%s' '%s'", imeth->name, desc);
+                free(desc);
+            }
+
+            for (j = clazz->vtableCount-1; j >= 0; j--) {
+                if (dvmCompareMethodNamesAndProtos(imeth, clazz->vtable[j])
+                    == 0)
+                {
+                    LOGVV("INTF:   matched at %d", j);
+                    if (!dvmIsPublicMethod(clazz->vtable[j])) {
+                        LOGW("Implementation of %s.%s is not public",
+                            clazz->descriptor, clazz->vtable[j]->name);
+                        dvmThrowIllegalAccessError(
+                            "interface implementation not public");
+                        goto bail;
+                    }
+                    clazz->iftable[i].methodIndexArray[methIdx] = j;
+                    break;
+                }
+            }
+            if (j < 0) {
+                IF_LOGV() {
+                    char* desc =
+                        dexProtoCopyMethodDescriptor(&imeth->prototype);
+                    LOGV("No match for '%s' '%s' in '%s' (creating miranda)",
+                            imeth->name, desc, clazz->descriptor);
+                    free(desc);
+                }
+                //dvmThrowRuntimeException("Miranda!");
+                //return false;
+
+                if (mirandaCount == mirandaAlloc) {
+                    mirandaAlloc += 8;
+                    if (mirandaList == NULL) {
+                        mirandaList = (Method**)dvmLinearAlloc(
+                                        clazz->classLoader,
+                                        mirandaAlloc * sizeof(Method*));
+                    } else {
+                        dvmLinearReadOnly(clazz->classLoader, mirandaList);
+                        mirandaList = (Method**)dvmLinearRealloc(
+                                clazz->classLoader,
+                                mirandaList, mirandaAlloc * sizeof(Method*));
+                    }
+                    assert(mirandaList != NULL);    // mem failed + we leaked
+                }
+
+                /*
+                 * These may be redundant (e.g. method with same name and
+                 * signature declared in two interfaces implemented by the
+                 * same abstract class).  We can squeeze the duplicates
+                 * out here.
+                 */
+                int mir;
+                for (mir = 0; mir < mirandaCount; mir++) {
+                    if (dvmCompareMethodNamesAndProtos(
+                            mirandaList[mir], imeth) == 0)
+                    {
+                        IF_LOGVV() {
+                            char* desc = dexProtoCopyMethodDescriptor(
+                                    &imeth->prototype);
+                            LOGVV("MIRANDA dupe: %s and %s %s%s",
+                                mirandaList[mir]->clazz->descriptor,
+                                imeth->clazz->descriptor,
+                                imeth->name, desc);
+                            free(desc);
+                        }
+                        break;
+                    }
+                }
+
+                /* point the iftable at a phantom slot index */
+                clazz->iftable[i].methodIndexArray[methIdx] =
+                    clazz->vtableCount + mir;
+                LOGVV("MIRANDA: %s points at slot %d",
+                    imeth->name, clazz->vtableCount + mir);
+
+                /* if non-duplicate among Mirandas, add to Miranda list */
+                if (mir == mirandaCount) {
+                    //LOGV("MIRANDA: holding '%s' in slot %d",
+                    //    imeth->name, mir);
+                    mirandaList[mirandaCount++] = imeth;
+                }
+            }
+        }
+    }
+
+    if (mirandaCount != 0) {
+        static const int kManyMirandas = 150;   /* arbitrary */
+        Method* newVirtualMethods;
+        Method* meth;
+        int oldMethodCount, oldVtableCount;
+
+        for (int i = 0; i < mirandaCount; i++) {
+            LOGVV("MIRANDA %d: %s.%s", 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",
+                clazz->descriptor, mirandaCount);
+        }
+
+        /*
+         * We found methods in one or more interfaces for which we do not
+         * have vtable entries.  We have to expand our virtualMethods
+         * table (which might be empty) to hold some new entries.
+         */
+        if (clazz->virtualMethods == NULL) {
+            newVirtualMethods = (Method*) dvmLinearAlloc(clazz->classLoader,
+                sizeof(Method) * (clazz->virtualMethodCount + mirandaCount));
+        } else {
+            //dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+            newVirtualMethods = (Method*) dvmLinearRealloc(clazz->classLoader,
+                clazz->virtualMethods,
+                sizeof(Method) * (clazz->virtualMethodCount + mirandaCount));
+        }
+        if (newVirtualMethods != clazz->virtualMethods) {
+            /*
+             * Table was moved in memory.  We have to run through the
+             * vtable and fix the pointers.  The vtable entries might be
+             * pointing at superclasses, so we flip it around: run through
+             * all locally-defined virtual methods, and fix their entries
+             * in the vtable.  (This would get really messy if sub-classes
+             * had already been loaded.)
+             *
+             * Reminder: clazz->virtualMethods and clazz->virtualMethodCount
+             * hold the virtual methods declared by this class.  The
+             * method's methodIndex is the vtable index, and is the same
+             * for all sub-classes (and all super classes in which it is
+             * defined).  We're messing with these because the Miranda
+             * stuff makes it look like the class actually has an abstract
+             * method declaration in it.
+             */
+            LOGVV("MIRANDA fixing vtable pointers");
+            dvmLinearReadWrite(clazz->classLoader, clazz->vtable);
+            Method* meth = newVirtualMethods;
+            for (int i = 0; i < clazz->virtualMethodCount; i++, meth++)
+                clazz->vtable[meth->methodIndex] = meth;
+            dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
+        }
+
+        oldMethodCount = clazz->virtualMethodCount;
+        clazz->virtualMethods = newVirtualMethods;
+        clazz->virtualMethodCount += mirandaCount;
+
+        dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+
+        /*
+         * We also have to expand the vtable.
+         */
+        assert(clazz->vtable != NULL);
+        clazz->vtable = (Method**) dvmLinearRealloc(clazz->classLoader,
+                        clazz->vtable,
+                        sizeof(Method*) * (clazz->vtableCount + mirandaCount));
+        if (clazz->vtable == NULL) {
+            assert(false);
+            goto bail;
+        }
+        zapVtable = true;
+
+        oldVtableCount = clazz->vtableCount;
+        clazz->vtableCount += mirandaCount;
+
+        /*
+         * 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 (int i = 0; i < mirandaCount; i++, meth++) {
+            dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
+            cloneMethod(meth, mirandaList[i]);
+            meth->clazz = clazz;
+            meth->accessFlags |= ACC_MIRANDA;
+            meth->methodIndex = (u2) (oldVtableCount + i);
+            dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+
+            /* point the new vtable entry at the new method */
+            clazz->vtable[oldVtableCount + i] = meth;
+        }
+
+        dvmLinearReadOnly(clazz->classLoader, mirandaList);
+        dvmLinearFree(clazz->classLoader, mirandaList);
+
+    }
+
+    /*
+     * TODO?
+     * Sort the interfaces by number of declared methods.  All we really
+     * want is to get the interfaces with zero methods at the end of the
+     * list, so that when we walk through the list during invoke-interface
+     * we don't examine interfaces that can't possibly be useful.
+     *
+     * The set will usually be small, so a simple insertion sort works.
+     *
+     * We have to be careful not to change the order of two interfaces
+     * that define the same method.  (Not a problem if we only move the
+     * zero-method interfaces to the end.)
+     *
+     * PROBLEM:
+     * If we do this, we will no longer be able to identify super vs.
+     * current class interfaces by comparing clazz->super->iftableCount.  This
+     * breaks anything that only wants to find interfaces declared directly
+     * by the class (dvmFindStaticFieldHier, ReferenceType.Interfaces,
+     * dvmDbgOutputAllInterfaces, etc).  Need to provide a workaround.
+     *
+     * We can sort just the interfaces implemented directly by this class,
+     * but that doesn't seem like it would provide much of an advantage.  I'm
+     * not sure this is worthwhile.
+     *
+     * (This has been made largely obsolete by the interface cache mechanism.)
+     */
+
+    //dvmDumpClass(clazz);
+
+    result = true;
+
+bail:
+    if (zapIftable)
+        dvmLinearReadOnly(clazz->classLoader, clazz->iftable);
+    if (zapVtable)
+        dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
+    if (zapIfvipool)
+        dvmLinearReadOnly(clazz->classLoader, clazz->ifviPool);
+    return result;
+}
+
+
+/*
+ * Provide "stub" implementations for methods without them.
+ *
+ * Currently we provide an implementation for all abstract methods that
+ * throws an AbstractMethodError exception.  This allows us to avoid an
+ * explicit check for abstract methods in every virtual call.
+ *
+ * NOTE: for Miranda methods, the method declaration is a clone of what
+ * was found in the interface class.  That copy may already have had the
+ * function pointer filled in, so don't be surprised if it's not NULL.
+ *
+ * NOTE: this sets the "native" flag, giving us an "abstract native" method,
+ * which is nonsensical.  Need to make sure that this doesn't escape the
+ * VM.  We can either mask it out in reflection calls, or copy "native"
+ * into the high 16 bits of accessFlags and check that internally.
+ */
+static bool insertMethodStubs(ClassObject* clazz)
+{
+    dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
+
+    Method* meth;
+    int i;
+
+    meth = clazz->virtualMethods;
+    for (i = 0; i < clazz->virtualMethodCount; i++, meth++) {
+        if (dvmIsAbstractMethod(meth)) {
+            assert(meth->insns == NULL);
+            assert(meth->nativeFunc == NULL ||
+                meth->nativeFunc == (DalvikBridgeFunc)dvmAbstractMethodStub);
+
+            meth->accessFlags |= ACC_NATIVE;
+            meth->nativeFunc = (DalvikBridgeFunc) dvmAbstractMethodStub;
+        }
+    }
+
+    dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+    return true;
+}
+
+
+/*
+ * Swap two instance fields.
+ */
+static inline void swapField(InstField* pOne, InstField* pTwo)
+{
+    InstField swap;
+
+    LOGVV("  --- swap '%s' and '%s'", pOne->name, pTwo->name);
+    swap = *pOne;
+    *pOne = *pTwo;
+    *pTwo = swap;
+}
+
+/*
+ * Assign instance fields to u4 slots.
+ *
+ * The top portion of the instance field area is occupied by the superclass
+ * fields, the bottom by the fields for this class.
+ *
+ * "long" and "double" fields occupy two adjacent slots.  On some
+ * architectures, 64-bit quantities must be 64-bit aligned, so we need to
+ * arrange fields (or introduce padding) to ensure this.  We assume the
+ * fields of the topmost superclass (i.e. Object) are 64-bit aligned, so
+ * we can just ensure that the offset is "even".  To avoid wasting space,
+ * we want to move non-reference 32-bit fields into gaps rather than
+ * creating pad words.
+ *
+ * In the worst case we will waste 4 bytes, but because objects are
+ * allocated on >= 64-bit boundaries, those bytes may well be wasted anyway
+ * (assuming this is the most-derived class).
+ *
+ * Pad words are not represented in the field table, so the field table
+ * itself does not change size.
+ *
+ * The number of field slots determines the size of the object, so we
+ * set that here too.
+ *
+ * This function feels a little more complicated than I'd like, but it
+ * has the property of moving the smallest possible set of fields, which
+ * should reduce the time required to load a class.
+ *
+ * NOTE: reference fields *must* come first, or precacheReferenceOffsets()
+ * will break.
+ */
+static bool computeFieldOffsets(ClassObject* clazz)
+{
+    int fieldOffset;
+    int i, j;
+
+    dvmLinearReadWrite(clazz->classLoader, clazz->ifields);
+
+    if (clazz->super != NULL)
+        fieldOffset = clazz->super->objectSize;
+    else
+        fieldOffset = OFFSETOF_MEMBER(DataObject, instanceData);
+
+    LOGVV("--- computeFieldOffsets '%s'", clazz->descriptor);
+
+    //LOGI("OFFSETS fieldCount=%d", clazz->ifieldCount);
+    //LOGI("dataobj, instance: %d", offsetof(DataObject, instanceData));
+    //LOGI("classobj, access: %d", offsetof(ClassObject, accessFlags));
+    //LOGI("super=%p, fieldOffset=%d", clazz->super, fieldOffset);
+
+    /*
+     * Start by moving all reference fields to the front.
+     */
+    clazz->ifieldRefCount = 0;
+    j = clazz->ifieldCount - 1;
+    for (i = 0; i < clazz->ifieldCount; i++) {
+        InstField* pField = &clazz->ifields[i];
+        char c = pField->signature[0];
+
+        if (c != '[' && c != 'L') {
+            /* This isn't a reference field; see if any reference fields
+             * follow this one.  If so, we'll move it to this position.
+             * (quicksort-style partitioning)
+             */
+            while (j > i) {
+                InstField* refField = &clazz->ifields[j--];
+                char rc = refField->signature[0];
+
+                if (rc == '[' || rc == 'L') {
+                    /* Here's a reference field that follows at least one
+                     * non-reference field.  Swap it with the current field.
+                     * (When this returns, "pField" points to the reference
+                     * field, and "refField" points to the non-ref field.)
+                     */
+                    swapField(pField, refField);
+
+                    /* Fix the signature.
+                     */
+                    c = rc;
+
+                    clazz->ifieldRefCount++;
+                    break;
+                }
+            }
+            /* We may or may not have swapped a field.
+             */
+        } else {
+            /* This is a reference field.
+             */
+            clazz->ifieldRefCount++;
+        }
+
+        /*
+         * If we've hit the end of the reference fields, break.
+         */
+        if (c != '[' && c != 'L')
+            break;
+
+        pField->byteOffset = fieldOffset;
+        fieldOffset += sizeof(u4);
+        LOGVV("  --- offset1 '%s'=%d", pField->name,pField->byteOffset);
+    }
+
+    /*
+     * Now we want to pack all of the double-wide fields together.  If we're
+     * not aligned, though, we want to shuffle one 32-bit field into place.
+     * If we can't find one, we'll have to pad it.
+     */
+    if (i != clazz->ifieldCount && (fieldOffset & 0x04) != 0) {
+        LOGVV("  +++ not aligned");
+
+        InstField* pField = &clazz->ifields[i];
+        char c = pField->signature[0];
+
+        if (c != 'J' && c != 'D') {
+            /*
+             * The field that comes next is 32-bit, so just advance past it.
+             */
+            assert(c != '[' && c != 'L');
+            pField->byteOffset = fieldOffset;
+            fieldOffset += sizeof(u4);
+            i++;
+            LOGVV("  --- offset2 '%s'=%d",
+                pField->name, pField->byteOffset);
+        } else {
+            /*
+             * Next field is 64-bit, so search for a 32-bit field we can
+             * swap into it.
+             */
+            bool found = false;
+            j = clazz->ifieldCount - 1;
+            while (j > i) {
+                InstField* singleField = &clazz->ifields[j--];
+                char rc = singleField->signature[0];
+
+                if (rc != 'J' && rc != 'D') {
+                    swapField(pField, singleField);
+                    //c = rc;
+                    LOGVV("  +++ swapped '%s' for alignment",
+                        pField->name);
+                    pField->byteOffset = fieldOffset;
+                    fieldOffset += sizeof(u4);
+                    LOGVV("  --- offset3 '%s'=%d",
+                        pField->name, pField->byteOffset);
+                    found = true;
+                    i++;
+                    break;
+                }
+            }
+            if (!found) {
+                LOGV("  +++ inserting pad field in '%s'", clazz->descriptor);
+                fieldOffset += sizeof(u4);
+            }
+        }
+    }
+
+    /*
+     * Alignment is good, shuffle any double-wide fields forward, and
+     * finish assigning field offsets to all fields.
+     */
+    assert(i == clazz->ifieldCount || (fieldOffset & 0x04) == 0);
+    j = clazz->ifieldCount - 1;
+    for ( ; i < clazz->ifieldCount; i++) {
+        InstField* pField = &clazz->ifields[i];
+        char c = pField->signature[0];
+
+        if (c != 'D' && c != 'J') {
+            /* This isn't a double-wide field; see if any double fields
+             * follow this one.  If so, we'll move it to this position.
+             * (quicksort-style partitioning)
+             */
+            while (j > i) {
+                InstField* doubleField = &clazz->ifields[j--];
+                char rc = doubleField->signature[0];
+
+                if (rc == 'D' || rc == 'J') {
+                    /* Here's a double-wide field that follows at least one
+                     * non-double field.  Swap it with the current field.
+                     * (When this returns, "pField" points to the reference
+                     * field, and "doubleField" points to the non-double field.)
+                     */
+                    swapField(pField, doubleField);
+                    c = rc;
+
+                    break;
+                }
+            }
+            /* We may or may not have swapped a field.
+             */
+        } else {
+            /* This is a double-wide field, leave it be.
+             */
+        }
+
+        pField->byteOffset = fieldOffset;
+        LOGVV("  --- offset4 '%s'=%d", pField->name,pField->byteOffset);
+        fieldOffset += sizeof(u4);
+        if (c == 'J' || c == 'D')
+            fieldOffset += sizeof(u4);
+    }
+
+#ifndef NDEBUG
+    /* Make sure that all reference fields appear before
+     * non-reference fields, and all double-wide fields are aligned.
+     */
+    j = 0;  // seen non-ref
+    for (i = 0; i < clazz->ifieldCount; i++) {
+        InstField *pField = &clazz->ifields[i];
+        char c = pField->signature[0];
+
+        if (c == 'D' || c == 'J') {
+            assert((pField->byteOffset & 0x07) == 0);
+        }
+
+        if (c != '[' && c != 'L') {
+            if (!j) {
+                assert(i == clazz->ifieldRefCount);
+                j = 1;
+            }
+        } else if (j) {
+            assert(false);
+        }
+    }
+    if (!j) {
+        assert(clazz->ifieldRefCount == clazz->ifieldCount);
+    }
+#endif
+
+    /*
+     * We map a C struct directly on top of java/lang/Class objects.  Make
+     * sure we left enough room for the instance fields.
+     */
+    assert(!dvmIsTheClassClass(clazz) || (size_t)fieldOffset <
+        OFFSETOF_MEMBER(ClassObject, instanceData) + sizeof(clazz->instanceData));
+
+    clazz->objectSize = fieldOffset;
+
+    dvmLinearReadOnly(clazz->classLoader, clazz->ifields);
+    return true;
+}
+
+/*
+ * The class failed to initialize on a previous attempt, so we want to throw
+ * a NoClassDefFoundError (v2 2.17.5).  The exception to this rule is if we
+ * failed in verification, in which case v2 5.4.1 says we need to re-throw
+ * the previous error.
+ */
+static void throwEarlierClassFailure(ClassObject* clazz)
+{
+    LOGI("Rejecting re-init on previously-failed class %s v=%p",
+        clazz->descriptor, clazz->verifyErrorClass);
+
+    if (clazz->verifyErrorClass == NULL) {
+        dvmThrowNoClassDefFoundError(clazz->descriptor);
+    } else {
+        dvmThrowExceptionWithClassMessage(clazz->verifyErrorClass,
+            clazz->descriptor);
+    }
+}
+
+/*
+ * Initialize any static fields whose values are stored in
+ * the DEX file.  This must be done during class initialization.
+ */
+static void initSFields(ClassObject* clazz)
+{
+    Thread* self = dvmThreadSelf(); /* for dvmReleaseTrackedAlloc() */
+    DexFile* pDexFile;
+    const DexClassDef* pClassDef;
+    const DexEncodedArray* pValueList;
+    EncodedArrayIterator iterator;
+    int i;
+
+    if (clazz->sfieldCount == 0) {
+        return;
+    }
+    if (clazz->pDvmDex == NULL) {
+        /* generated class; any static fields should already be set up */
+        LOGV("Not initializing static fields in %s", clazz->descriptor);
+        return;
+    }
+    pDexFile = clazz->pDvmDex->pDexFile;
+
+    pClassDef = dexFindClass(pDexFile, clazz->descriptor);
+    assert(pClassDef != NULL);
+
+    pValueList = dexGetStaticValuesList(pDexFile, pClassDef);
+    if (pValueList == NULL) {
+        return;
+    }
+
+    dvmEncodedArrayIteratorInitialize(&iterator, pValueList, clazz);
+
+    /*
+     * Iterate over the initial values array, setting the corresponding
+     * static field for each array element.
+     */
+
+    for (i = 0; dvmEncodedArrayIteratorHasNext(&iterator); i++) {
+        AnnotationValue value;
+        bool parsed = dvmEncodedArrayIteratorGetNext(&iterator, &value);
+        StaticField* sfield = &clazz->sfields[i];
+        const char* descriptor = sfield->signature;
+        bool isObj = false;
+
+        if (! parsed) {
+            /*
+             * TODO: Eventually verification should attempt to ensure
+             * that this can't happen at least due to a data integrity
+             * problem.
+             */
+            LOGE("Static initializer parse failed for %s at index %d",
+                    clazz->descriptor, i);
+            dvmAbort();
+        }
+
+        /* Verify that the value we got was of a valid type. */
+
+        switch (descriptor[0]) {
+            case 'Z': parsed = (value.type == kDexAnnotationBoolean); break;
+            case 'B': parsed = (value.type == kDexAnnotationByte);    break;
+            case 'C': parsed = (value.type == kDexAnnotationChar);    break;
+            case 'S': parsed = (value.type == kDexAnnotationShort);   break;
+            case 'I': parsed = (value.type == kDexAnnotationInt);     break;
+            case 'J': parsed = (value.type == kDexAnnotationLong);    break;
+            case 'F': parsed = (value.type == kDexAnnotationFloat);   break;
+            case 'D': parsed = (value.type == kDexAnnotationDouble);  break;
+            case '[': parsed = (value.type == kDexAnnotationNull);    break;
+            case 'L': {
+                switch (value.type) {
+                    case kDexAnnotationNull: {
+                        /* No need for further tests. */
+                        break;
+                    }
+                    case kDexAnnotationString: {
+                        parsed =
+                            (strcmp(descriptor, "Ljava/lang/String;") == 0);
+                        isObj = true;
+                        break;
+                    }
+                    case kDexAnnotationType: {
+                        parsed =
+                            (strcmp(descriptor, "Ljava/lang/Class;") == 0);
+                        isObj = true;
+                        break;
+                    }
+                    default: {
+                        parsed = false;
+                        break;
+                    }
+                }
+                break;
+            }
+            default: {
+                parsed = false;
+                break;
+            }
+        }
+
+        if (parsed) {
+            /*
+             * All's well, so store the value.
+             */
+            if (isObj) {
+                dvmSetStaticFieldObject(sfield, (Object*)value.value.l);
+                dvmReleaseTrackedAlloc((Object*)value.value.l, self);
+            } else {
+                /*
+                 * Note: This always stores the full width of a
+                 * JValue, even though most of the time only the first
+                 * word is needed.
+                 */
+                sfield->value = value.value;
+            }
+        } else {
+            /*
+             * Something up above had a problem. TODO: See comment
+             * above the switch about verfication.
+             */
+            LOGE("Bogus static initialization: value type %d in field type "
+                    "%s for %s at index %d",
+                value.type, descriptor, clazz->descriptor, i);
+            dvmAbort();
+        }
+    }
+}
+
+
+/*
+ * Determine whether "descriptor" yields the same class object in the
+ * context of clazz1 and clazz2.
+ *
+ * The caller must hold gDvm.loadedClasses.
+ *
+ * Returns "true" if they match.
+ */
+static bool compareDescriptorClasses(const char* descriptor,
+    const ClassObject* clazz1, const ClassObject* clazz2)
+{
+    ClassObject* result1;
+    ClassObject* result2;
+
+    /*
+     * Do the first lookup by name.
+     */
+    result1 = dvmFindClassNoInit(descriptor, clazz1->classLoader);
+
+    /*
+     * We can skip a second lookup by name if the second class loader is
+     * in the initiating loader list of the class object we retrieved.
+     * (This means that somebody already did a lookup of this class through
+     * the second loader, and it resolved to the same class.)  If it's not
+     * there, we may simply not have had an opportunity to add it yet, so
+     * we do the full lookup.
+     *
+     * The initiating loader test should catch the majority of cases
+     * (in particular, the zillions of references to String/Object).
+     *
+     * Unfortunately we're still stuck grabbing a mutex to do the lookup.
+     *
+     * For this to work, the superclass/interface should be the first
+     * argument, so that way if it's from the bootstrap loader this test
+     * will work.  (The bootstrap loader, by definition, never shows up
+     * as the initiating loader of a class defined by some other loader.)
+     */
+    dvmHashTableLock(gDvm.loadedClasses);
+    bool isInit = dvmLoaderInInitiatingList(result1, clazz2->classLoader);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+
+    if (isInit) {
+        //printf("%s(obj=%p) / %s(cl=%p): initiating\n",
+        //    result1->descriptor, result1,
+        //    clazz2->descriptor, clazz2->classLoader);
+        return true;
+    } else {
+        //printf("%s(obj=%p) / %s(cl=%p): RAW\n",
+        //    result1->descriptor, result1,
+        //    clazz2->descriptor, clazz2->classLoader);
+        result2 = dvmFindClassNoInit(descriptor, clazz2->classLoader);
+    }
+
+    if (result1 == NULL || result2 == NULL) {
+        dvmClearException(dvmThreadSelf());
+        if (result1 == result2) {
+            /*
+             * Neither class loader could find this class.  Apparently it
+             * doesn't exist.
+             *
+             * We can either throw some sort of exception now, or just
+             * assume that it'll fail later when something actually tries
+             * to use the class.  For strict handling we should throw now,
+             * because a "tricky" class loader could start returning
+             * something later, and a pair of "tricky" loaders could set
+             * us up for confusion.
+             *
+             * I'm not sure if we're allowed to complain about nonexistent
+             * classes in method signatures during class init, so for now
+             * this will just return "true" and let nature take its course.
+             */
+            return true;
+        } else {
+            /* only one was found, so clearly they're not the same */
+            return false;
+        }
+    }
+
+    return result1 == result2;
+}
+
+/*
+ * For every component in the method descriptor, resolve the class in the
+ * context of the two classes and compare the results.
+ *
+ * For best results, the "superclass" class should be first.
+ *
+ * Returns "true" if the classes match, "false" otherwise.
+ */
+static bool checkMethodDescriptorClasses(const Method* meth,
+    const ClassObject* clazz1, const ClassObject* clazz2)
+{
+    DexParameterIterator iterator;
+    const char* descriptor;
+
+    /* walk through the list of parameters */
+    dexParameterIteratorInit(&iterator, &meth->prototype);
+    while (true) {
+        descriptor = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (descriptor == NULL)
+            break;
+
+        if (descriptor[0] == 'L' || descriptor[0] == '[') {
+            /* non-primitive type */
+            if (!compareDescriptorClasses(descriptor, clazz1, clazz2))
+                return false;
+        }
+    }
+
+    /* check the return type */
+    descriptor = dexProtoGetReturnType(&meth->prototype);
+    if (descriptor[0] == 'L' || descriptor[0] == '[') {
+        if (!compareDescriptorClasses(descriptor, clazz1, clazz2))
+            return false;
+    }
+    return true;
+}
+
+/*
+ * Validate the descriptors in the superclass and interfaces.
+ *
+ * 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.  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.
+ *
+ * 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".
+ */
+static bool validateSuperDescriptors(const ClassObject* clazz)
+{
+    int i;
+
+    if (dvmIsInterfaceClass(clazz))
+        return true;
+
+    /*
+     * Start with the superclass-declared methods.
+     */
+    if (clazz->super != NULL &&
+        clazz->classLoader != clazz->super->classLoader)
+    {
+        /*
+         * 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;
+
+        //printf("Checking %s %p vs %s %p\n",
+        //    clazz->descriptor, clazz->classLoader,
+        //    clazz->super->descriptor, clazz->super->classLoader);
+        for (i = clazz->super->vtableCount - 1; i >= 0; i--) {
+            meth = clazz->vtable[i];
+            if (meth != clazz->super->vtable[i] &&
+                !checkMethodDescriptorClasses(meth, clazz->super, clazz))
+            {
+                LOGW("Method mismatch: %s in %s (cl=%p) and super %s (cl=%p)",
+                    meth->name, clazz->descriptor, clazz->classLoader,
+                    clazz->super->descriptor, clazz->super->classLoader);
+                dvmThrowLinkageError(
+                    "Classes resolve differently in superclass");
+                return false;
+            }
+        }
+    }
+
+    /*
+     * 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];
+
+        if (clazz->classLoader != iftable->clazz->classLoader) {
+            const ClassObject* iface = iftable->clazz;
+            int j;
+
+            for (j = 0; j < iface->virtualMethodCount; j++) {
+                const Method* meth;
+                int vtableIndex;
+
+                vtableIndex = iftable->methodIndexArray[j];
+                meth = clazz->vtable[vtableIndex];
+
+                if (!checkMethodDescriptorClasses(meth, iface, meth->clazz)) {
+                    LOGW("Method mismatch: %s in %s (cl=%p) and "
+                            "iface %s (cl=%p)",
+                        meth->name, clazz->descriptor, clazz->classLoader,
+                        iface->descriptor, iface->classLoader);
+                    dvmThrowLinkageError(
+                        "Classes resolve differently in interface");
+                    return false;
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+/*
+ * Returns true if the class is being initialized by us (which means that
+ * calling dvmInitClass will return immediately after fiddling with locks).
+ * Returns false if it's not being initialized, or if it's being
+ * initialized by another thread.
+ *
+ * The value for initThreadId is always set to "self->threadId", by the
+ * thread doing the initializing.  If it was done by the current thread,
+ * we are guaranteed to see "initializing" and our thread ID, even on SMP.
+ * If it was done by another thread, the only bad situation is one in
+ * which we see "initializing" and a stale copy of our own thread ID
+ * while another thread is actually handling init.
+ *
+ * The initThreadId field is used during class linking, so it *is*
+ * possible to have a stale value floating around.  We need to ensure
+ * that memory accesses happen in the correct order.
+ */
+bool dvmIsClassInitializing(const ClassObject* clazz)
+{
+    const int32_t* addr = (const int32_t*)(const void*)&clazz->status;
+    int32_t value = android_atomic_acquire_load(addr);
+    ClassStatus status = static_cast<ClassStatus>(value);
+    return (status == CLASS_INITIALIZING &&
+            clazz->initThreadId == dvmThreadSelf()->threadId);
+}
+
+/*
+ * If a class has not been initialized, do so by executing the code in
+ * <clinit>.  The sequence is described in the VM spec v2 2.17.5.
+ *
+ * It is possible for multiple threads to arrive here simultaneously, so
+ * we need to lock the class while we check stuff.  We know that no
+ * interpreted code has access to the class yet, so we can use the class's
+ * monitor lock.
+ *
+ * We will often be called recursively, e.g. when the <clinit> code resolves
+ * one of its fields, the field resolution will try to initialize the class.
+ * In that case we will return "true" even though the class isn't actually
+ * ready to go.  The ambiguity can be resolved with dvmIsClassInitializing().
+ * (TODO: consider having this return an enum to avoid the extra call --
+ * return -1 on failure, 0 on success, 1 on still-initializing.  Looks like
+ * dvmIsClassInitializing() is always paired with *Initialized())
+ *
+ * This can get very interesting if a class has a static field initialized
+ * to a new instance of itself.  <clinit> will end up calling <init> on
+ * the members it is initializing, which is fine unless it uses the contents
+ * of static fields to initialize instance fields.  This will leave the
+ * static-referenced objects in a partially initialized state.  This is
+ * reasonably rare and can sometimes be cured with proper field ordering.
+ *
+ * On failure, returns "false" with an exception raised.
+ *
+ * -----
+ *
+ * It is possible to cause a deadlock by having a situation like this:
+ *   class A { static { sleep(10000); new B(); } }
+ *   class B { static { sleep(10000); new A(); } }
+ *   new Thread() { public void run() { new A(); } }.start();
+ *   new Thread() { public void run() { new B(); } }.start();
+ * This appears to be expected under the spec.
+ *
+ * The interesting question is what to do if somebody calls Thread.interrupt()
+ * on one of the deadlocked threads.  According to the VM spec, they're both
+ * sitting in "wait".  Should the interrupt code quietly raise the
+ * "interrupted" flag, or should the "wait" return immediately with an
+ * exception raised?
+ *
+ * This gets a little murky.  The VM spec says we call "wait", and the
+ * spec for Thread.interrupt says Object.wait is interruptible.  So it
+ * seems that, if we get unlucky and interrupt class initialization, we
+ * are expected to throw (which gets converted to ExceptionInInitializerError
+ * since InterruptedException is checked).
+ *
+ * There are a couple of problems here.  First, all threads are expected to
+ * present a consistent view of class initialization, so we can't have it
+ * fail in one thread and succeed in another.  Second, once a class fails
+ * to initialize, it must *always* fail.  This means that a stray interrupt()
+ * call could render a class unusable for the lifetime of the VM.
+ *
+ * In most cases -- the deadlock example above being a counter-example --
+ * the interrupting thread can't tell whether the target thread handled
+ * the initialization itself or had to wait while another thread did the
+ * work.  Refusing to interrupt class initialization is, in most cases,
+ * not something that a program can reliably detect.
+ *
+ * On the assumption that interrupting class initialization is highly
+ * undesirable in most circumstances, and that failing to do so does not
+ * deviate from the spec in a meaningful way, we don't allow class init
+ * to be interrupted by Thread.interrupt().
+ */
+bool dvmInitClass(ClassObject* clazz)
+{
+    u8 startWhen = 0;
+
+#if LOG_CLASS_LOADING
+    bool initializedByUs = false;
+#endif
+
+    Thread* self = dvmThreadSelf();
+    const Method* method;
+
+    dvmLockObject(self, (Object*) clazz);
+    assert(dvmIsClassLinked(clazz) || clazz->status == CLASS_ERROR);
+
+    /*
+     * If the class hasn't been verified yet, do so now.
+     */
+    if (clazz->status < CLASS_VERIFIED) {
+        /*
+         * If we're in an "erroneous" state, throw an exception and bail.
+         */
+        if (clazz->status == CLASS_ERROR) {
+            throwEarlierClassFailure(clazz);
+            goto bail_unlock;
+        }
+
+        assert(clazz->status == CLASS_RESOLVED);
+        assert(!IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED));
+
+        if (gDvm.classVerifyMode == VERIFY_MODE_NONE ||
+            (gDvm.classVerifyMode == VERIFY_MODE_REMOTE &&
+             clazz->classLoader == NULL))
+        {
+            /* advance to "verified" state */
+            LOGV("+++ not verifying class %s (cl=%p)",
+                clazz->descriptor, clazz->classLoader);
+            clazz->status = CLASS_VERIFIED;
+            goto noverify;
+        }
+
+        if (!gDvm.optimizing)
+            LOGV("+++ late verify on %s", clazz->descriptor);
+
+        /*
+         * We're not supposed to optimize an unverified class, but during
+         * development this mode was useful.  We can't verify an optimized
+         * class because the optimization process discards information.
+         */
+        if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOPTIMIZED)) {
+            LOGW("Class '%s' was optimized without verification; "
+                 "not verifying now",
+                clazz->descriptor);
+            LOGW("  ('rm /data/dalvik-cache/*' and restart to fix this)");
+            goto verify_failed;
+        }
+
+        clazz->status = CLASS_VERIFYING;
+        if (!dvmVerifyClass(clazz)) {
+verify_failed:
+            dvmThrowVerifyError(clazz->descriptor);
+            dvmSetFieldObject((Object*) clazz,
+                OFFSETOF_MEMBER(ClassObject, verifyErrorClass),
+                (Object*) dvmGetException(self)->clazz);
+            clazz->status = CLASS_ERROR;
+            goto bail_unlock;
+        }
+
+        clazz->status = CLASS_VERIFIED;
+    }
+noverify:
+
+    /*
+     * We need to ensure that certain instructions, notably accesses to
+     * volatile fields, are replaced before any code is executed.  This
+     * must happen even if DEX optimizations are disabled.
+     *
+     * The only exception to this rule is that we don't want to do this
+     * during dexopt.  We don't generally initialize classes at all
+     * during dexopt, but because we're loading classes we need Class and
+     * Object (and possibly some Throwable stuff if a class isn't found).
+     * If optimizations are disabled, we don't want to output optimized
+     * instructions at this time.  This means we will be executing <clinit>
+     * code with un-fixed volatiles, but we're only doing it for a few
+     * system classes, and dexopt runs single-threaded.
+     */
+    if (!IS_CLASS_FLAG_SET(clazz, CLASS_ISOPTIMIZED) && !gDvm.optimizing) {
+        LOGV("+++ late optimize on %s (pv=%d)",
+            clazz->descriptor, IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED));
+        bool essentialOnly = (gDvm.dexOptMode != OPTIMIZE_MODE_FULL);
+        dvmOptimizeClass(clazz, essentialOnly);
+        SET_CLASS_FLAG(clazz, CLASS_ISOPTIMIZED);
+    }
+
+    /* update instruction stream now that verification + optimization is done */
+    dvmFlushBreakpoints(clazz);
+
+    if (clazz->status == CLASS_INITIALIZED)
+        goto bail_unlock;
+
+    while (clazz->status == CLASS_INITIALIZING) {
+        /* we caught somebody else in the act; was it us? */
+        if (clazz->initThreadId == self->threadId) {
+            //LOGV("HEY: found a recursive <clinit>");
+            goto bail_unlock;
+        }
+
+        if (dvmCheckException(self)) {
+            LOGW("GLITCH: exception pending at start of class init");
+            dvmAbort();
+        }
+
+        /*
+         * Wait for the other thread to finish initialization.  We pass
+         * "false" for the "interruptShouldThrow" arg so it doesn't throw
+         * an exception on interrupt.
+         */
+        dvmObjectWait(self, (Object*) clazz, 0, 0, false);
+
+        /*
+         * When we wake up, repeat the test for init-in-progress.  If there's
+         * an exception pending (only possible if "interruptShouldThrow"
+         * was set), bail out.
+         */
+        if (dvmCheckException(self)) {
+            LOGI("Class init of '%s' failing with wait() exception",
+                clazz->descriptor);
+            /*
+             * TODO: this is bogus, because it means the two threads have a
+             * different idea of the class status.  We need to flag the
+             * class as bad and ensure that the initializer thread respects
+             * our notice.  If we get lucky and wake up after the class has
+             * finished initialization but before being woken, we have to
+             * swallow the exception, perhaps raising thread->interrupted
+             * to preserve semantics.
+             *
+             * Since we're not currently allowing interrupts, this should
+             * never happen and we don't need to fix this.
+             */
+            assert(false);
+            dvmThrowExceptionInInitializerError();
+            clazz->status = CLASS_ERROR;
+            goto bail_unlock;
+        }
+        if (clazz->status == CLASS_INITIALIZING) {
+            LOGI("Waiting again for class init");
+            continue;
+        }
+        assert(clazz->status == CLASS_INITIALIZED ||
+               clazz->status == CLASS_ERROR);
+        if (clazz->status == CLASS_ERROR) {
+            /*
+             * The caller wants an exception, but it was thrown in a
+             * different thread.  Synthesize one here.
+             */
+            dvmThrowUnsatisfiedLinkError(
+                "(<clinit> failed, see exception in other thread)");
+        }
+        goto bail_unlock;
+    }
+
+    /* see if we failed previously */
+    if (clazz->status == CLASS_ERROR) {
+        // might be wise to unlock before throwing; depends on which class
+        // it is that we have locked
+        dvmUnlockObject(self, (Object*) clazz);
+        throwEarlierClassFailure(clazz);
+        return false;
+    }
+
+    if (gDvm.allocProf.enabled) {
+        startWhen = dvmGetRelativeTimeNsec();
+    }
+
+    /*
+     * We're ready to go, and have exclusive access to the class.
+     *
+     * Before we start initialization, we need to do one extra bit of
+     * validation: make sure that the methods declared here match up
+     * with our superclass and interfaces.  We know that the UTF-8
+     * descriptors match, but classes from different class loaders can
+     * have the same name.
+     *
+     * We do this now, rather than at load/link time, for the same reason
+     * that we defer verification.
+     *
+     * It's unfortunate that we need to do this at all, but we risk
+     * mixing reference types with identical names (see Dalvik test 068).
+     */
+    if (!validateSuperDescriptors(clazz)) {
+        assert(dvmCheckException(self));
+        clazz->status = CLASS_ERROR;
+        goto bail_unlock;
+    }
+
+    /*
+     * Let's initialize this thing.
+     *
+     * We unlock the object so that other threads can politely sleep on
+     * our mutex with Object.wait(), instead of hanging or spinning trying
+     * to grab our mutex.
+     */
+    assert(clazz->status < CLASS_INITIALIZING);
+
+#if LOG_CLASS_LOADING
+    // We started initializing.
+    logClassLoad('+', clazz);
+    initializedByUs = true;
+#endif
+
+    /* order matters here, esp. interaction with dvmIsClassInitializing */
+    clazz->initThreadId = self->threadId;
+    android_atomic_release_store(CLASS_INITIALIZING,
+                                 (int32_t*)(void*)&clazz->status);
+    dvmUnlockObject(self, (Object*) clazz);
+
+    /* init our superclass */
+    if (clazz->super != NULL && clazz->super->status != CLASS_INITIALIZED) {
+        assert(!dvmIsInterfaceClass(clazz));
+        if (!dvmInitClass(clazz->super)) {
+            assert(dvmCheckException(self));
+            clazz->status = CLASS_ERROR;
+            /* wake up anybody who started waiting while we were unlocked */
+            dvmLockObject(self, (Object*) clazz);
+            goto bail_notify;
+        }
+    }
+
+    /* Initialize any static fields whose values are
+     * stored in the Dex file.  This should include all of the
+     * simple "final static" fields, which are required to
+     * be initialized first. (vmspec 2 sec 2.17.5 item 8)
+     * More-complicated final static fields should be set
+     * at the beginning of <clinit>;  all we can do is trust
+     * that the compiler did the right thing.
+     */
+    initSFields(clazz);
+
+    /* Execute any static initialization code.
+     */
+    method = dvmFindDirectMethodByDescriptor(clazz, "<clinit>", "()V");
+    if (method == NULL) {
+        LOGVV("No <clinit> found for %s", clazz->descriptor);
+    } else {
+        LOGVV("Invoking %s.<clinit>", clazz->descriptor);
+        JValue unused;
+        dvmCallMethod(self, method, NULL, &unused);
+    }
+
+    if (dvmCheckException(self)) {
+        /*
+         * We've had an exception thrown during static initialization.  We
+         * need to throw an ExceptionInInitializerError, but we want to
+         * tuck the original exception into the "cause" field.
+         */
+        LOGW("Exception %s thrown while initializing %s",
+            (dvmGetException(self)->clazz)->descriptor, clazz->descriptor);
+        dvmThrowExceptionInInitializerError();
+        //LOGW("+++ replaced");
+
+        dvmLockObject(self, (Object*) clazz);
+        clazz->status = CLASS_ERROR;
+    } else {
+        /* success! */
+        dvmLockObject(self, (Object*) clazz);
+        clazz->status = CLASS_INITIALIZED;
+        LOGVV("Initialized class: %s", clazz->descriptor);
+
+        /*
+         * Update alloc counters.  TODO: guard with mutex.
+         */
+        if (gDvm.allocProf.enabled && startWhen != 0) {
+            u8 initDuration = dvmGetRelativeTimeNsec() - startWhen;
+            gDvm.allocProf.classInitTime += initDuration;
+            self->allocProf.classInitTime += initDuration;
+            gDvm.allocProf.classInitCount++;
+            self->allocProf.classInitCount++;
+        }
+    }
+
+bail_notify:
+    /*
+     * Notify anybody waiting on the object.
+     */
+    dvmObjectNotifyAll(self, (Object*) clazz);
+
+bail_unlock:
+
+#if LOG_CLASS_LOADING
+    if (initializedByUs) {
+        // We finished initializing.
+        logClassLoad('-', clazz);
+    }
+#endif
+
+    dvmUnlockObject(self, (Object*) clazz);
+
+    return (clazz->status != CLASS_ERROR);
+}
+
+/*
+ * Replace method->nativeFunc and method->insns with new values.  This is
+ * commonly performed after successful resolution of a native method.
+ *
+ * There are three basic states:
+ *  (1) (initial) nativeFunc = dvmResolveNativeMethod, insns = NULL
+ *  (2) (internal native) nativeFunc = <impl>, insns = NULL
+ *  (3) (JNI) nativeFunc = JNI call bridge, insns = <impl>
+ *
+ * nativeFunc must never be NULL for a native method.
+ *
+ * The most common transitions are (1)->(2) and (1)->(3).  The former is
+ * atomic, since only one field is updated; the latter is not, but since
+ * dvmResolveNativeMethod ignores the "insns" field we just need to make
+ * sure the update happens in the correct order.
+ *
+ * A transition from (2)->(1) would work fine, but (3)->(1) will not,
+ * because both fields change.  If we did this while a thread was executing
+ * in the call bridge, we could null out the "insns" field right before
+ * the bridge tried to call through it.  So, once "insns" is set, we do
+ * not allow it to be cleared.  A NULL value for the "insns" argument is
+ * treated as "do not change existing value".
+ */
+void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func,
+    const u2* insns)
+{
+    ClassObject* clazz = method->clazz;
+
+    assert(func != NULL);
+
+    /* just open up both; easier that way */
+    dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
+    dvmLinearReadWrite(clazz->classLoader, clazz->directMethods);
+
+    if (insns != NULL) {
+        /* update both, ensuring that "insns" is observed first */
+        method->insns = insns;
+        android_atomic_release_store((int32_t) func,
+            (volatile int32_t*)(void*) &method->nativeFunc);
+    } else {
+        /* only update nativeFunc */
+        method->nativeFunc = func;
+    }
+
+    dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+    dvmLinearReadOnly(clazz->classLoader, clazz->directMethods);
+}
+
+/*
+ * Add a RegisterMap to a Method.  This is done when we verify the class
+ * 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) {
+        /* unexpected during class loading, okay on first use (uncompress) */
+        LOGV("NOTE: registerMap already set for %s.%s",
+            method->clazz->descriptor, method->name);
+        /* keep going */
+    }
+    assert(!dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method));
+
+    /* might be virtual or direct */
+    dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
+    dvmLinearReadWrite(clazz->classLoader, clazz->directMethods);
+
+    method->registerMap = pMap;
+
+    dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
+    dvmLinearReadOnly(clazz->classLoader, clazz->directMethods);
+}
+
+/*
+ * dvmHashForeach callback.  A nonzero return value causes foreach to
+ * bail out.
+ */
+static int findClassCallback(void* vclazz, void* arg)
+{
+    ClassObject* clazz = (ClassObject*)vclazz;
+    const char* descriptor = (const char*) arg;
+
+    if (strcmp(clazz->descriptor, descriptor) == 0)
+        return (int) clazz;
+    return 0;
+}
+
+/*
+ * Find a loaded class by descriptor. Returns the first one found.
+ * Because there can be more than one if class loaders are involved,
+ * this is not an especially good API. (Currently only used by the
+ * debugger and "checking" JNI.)
+ *
+ * "descriptor" should have the form "Ljava/lang/Class;" or
+ * "[Ljava/lang/Class;", i.e. a descriptor and not an internal-form
+ * class name.
+ */
+ClassObject* dvmFindLoadedClass(const char* descriptor)
+{
+    int result;
+
+    dvmHashTableLock(gDvm.loadedClasses);
+    result = dvmHashForeach(gDvm.loadedClasses, findClassCallback,
+            (void*) descriptor);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+
+    return (ClassObject*) result;
+}
+
+/*
+ * Retrieve the system (a/k/a application) class loader.
+ *
+ * The caller must call dvmReleaseTrackedAlloc on the result.
+ */
+Object* dvmGetSystemClassLoader()
+{
+    Thread* self = dvmThreadSelf();
+    ClassObject* clClass = gDvm.classJavaLangClassLoader;
+
+    if (!dvmIsClassInitialized(clClass) && !dvmInitClass(clClass))
+        return NULL;
+
+    JValue result;
+    dvmCallMethod(self, gDvm.methJavaLangClassLoader_getSystemClassLoader,
+        NULL, &result);
+    Object* loader = (Object*)result.l;
+    dvmAddTrackedAlloc(loader, self);
+    return loader;
+}
+
+
+/*
+ * This is a dvmHashForeach callback.
+ */
+static int dumpClass(void* vclazz, void* varg)
+{
+    const ClassObject* clazz = (const ClassObject*) vclazz;
+    const ClassObject* super;
+    int flags = (int) varg;
+    char* desc;
+    int i;
+
+    if (clazz == NULL) {
+        LOGI("dumpClass: ignoring request to dump null class");
+        return 0;
+    }
+
+    if ((flags & kDumpClassFullDetail) == 0) {
+        bool showInit = (flags & kDumpClassInitialized) != 0;
+        bool showLoader = (flags & kDumpClassClassLoader) != 0;
+        const char* initStr;
+
+        initStr = dvmIsClassInitialized(clazz) ? "true" : "false";
+
+        if (showInit && showLoader)
+            LOGI("%s %p %s", clazz->descriptor, clazz->classLoader, initStr);
+        else if (showInit)
+            LOGI("%s %s", clazz->descriptor, initStr);
+        else if (showLoader)
+            LOGI("%s %p", clazz->descriptor, clazz->classLoader);
+        else
+            LOGI("%s", clazz->descriptor);
+
+        return 0;
+    }
+
+    /* clazz->super briefly holds the superclass index during class prep */
+    if ((u4)clazz->super > 0x10000 && (u4) clazz->super != (u4)-1)
+        super = clazz->super;
+    else
+        super = NULL;
+
+    LOGI("----- %s '%s' cl=%p ser=0x%08x -----",
+        dvmIsInterfaceClass(clazz) ? "interface" : "class",
+        clazz->descriptor, clazz->classLoader, clazz->serialNumber);
+    LOGI("  objectSize=%d (%d from super)", (int) clazz->objectSize,
+        super != NULL ? (int) super->objectSize : -1);
+    LOGI("  access=0x%04x.%04x", clazz->accessFlags >> 16,
+        clazz->accessFlags & JAVA_FLAGS_MASK);
+    if (super != NULL)
+        LOGI("  super='%s' (cl=%p)", super->descriptor, super->classLoader);
+    if (dvmIsArrayClass(clazz)) {
+        LOGI("  dimensions=%d elementClass=%s",
+            clazz->arrayDim, clazz->elementClass->descriptor);
+    }
+    if (clazz->iftableCount > 0) {
+        LOGI("  interfaces (%d):", clazz->iftableCount);
+        for (i = 0; i < clazz->iftableCount; i++) {
+            InterfaceEntry* ent = &clazz->iftable[i];
+            int j;
+
+            LOGI("    %2d: %s (cl=%p)",
+                i, ent->clazz->descriptor, ent->clazz->classLoader);
+
+            /* enable when needed */
+            if (false && ent->methodIndexArray != NULL) {
+                for (j = 0; j < ent->clazz->virtualMethodCount; j++)
+                    LOGI("      %2d: %d %s %s",
+                        j, ent->methodIndexArray[j],
+                        ent->clazz->virtualMethods[j].name,
+                        clazz->vtable[ent->methodIndexArray[j]]->name);
+            }
+        }
+    }
+    if (!dvmIsInterfaceClass(clazz)) {
+        LOGI("  vtable (%d entries, %d in super):", clazz->vtableCount,
+            super != NULL ? super->vtableCount : 0);
+        for (i = 0; i < clazz->vtableCount; i++) {
+            desc = dexProtoCopyMethodDescriptor(&clazz->vtable[i]->prototype);
+            LOGI("    %s%2d: %p %20s %s",
+                (i != clazz->vtable[i]->methodIndex) ? "*** " : "",
+                (u4) clazz->vtable[i]->methodIndex, clazz->vtable[i],
+                clazz->vtable[i]->name, desc);
+            free(desc);
+        }
+        LOGI("  direct methods (%d entries):", clazz->directMethodCount);
+        for (i = 0; i < clazz->directMethodCount; i++) {
+            desc = dexProtoCopyMethodDescriptor(
+                    &clazz->directMethods[i].prototype);
+            LOGI("    %2d: %20s %s", i, clazz->directMethods[i].name,
+                desc);
+            free(desc);
+        }
+    } else {
+        LOGI("  interface methods (%d):", clazz->virtualMethodCount);
+        for (i = 0; i < clazz->virtualMethodCount; i++) {
+            desc = dexProtoCopyMethodDescriptor(
+                    &clazz->virtualMethods[i].prototype);
+            LOGI("    %2d: %2d %20s %s", i,
+                (u4) clazz->virtualMethods[i].methodIndex,
+                clazz->virtualMethods[i].name,
+                desc);
+            free(desc);
+        }
+    }
+    if (clazz->sfieldCount > 0) {
+        LOGI("  static fields (%d entries):", clazz->sfieldCount);
+        for (i = 0; i < clazz->sfieldCount; i++) {
+            LOGI("    %2d: %20s %s", i, clazz->sfields[i].name,
+                clazz->sfields[i].signature);
+        }
+    }
+    if (clazz->ifieldCount > 0) {
+        LOGI("  instance fields (%d entries):", clazz->ifieldCount);
+        for (i = 0; i < clazz->ifieldCount; i++) {
+            LOGI("    %2d: %20s %s", i, clazz->ifields[i].name,
+                clazz->ifields[i].signature);
+        }
+    }
+    return 0;
+}
+
+/*
+ * Dump the contents of a single class.
+ *
+ * Pass kDumpClassFullDetail into "flags" to get lots of detail.
+ */
+void dvmDumpClass(const ClassObject* clazz, int flags)
+{
+    dumpClass((void*) clazz, (void*) flags);
+}
+
+/*
+ * Dump the contents of all classes.
+ */
+void dvmDumpAllClasses(int flags)
+{
+    dvmHashTableLock(gDvm.loadedClasses);
+    dvmHashForeach(gDvm.loadedClasses, dumpClass, (void*) flags);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+}
+
+/*
+ * Get the number of loaded classes
+ */
+int dvmGetNumLoadedClasses()
+{
+    int count;
+    dvmHashTableLock(gDvm.loadedClasses);
+    count = dvmHashTableNumEntries(gDvm.loadedClasses);
+    dvmHashTableUnlock(gDvm.loadedClasses);
+    return count;
+}
+
+/*
+ * Write some statistics to the log file.
+ */
+void dvmDumpLoaderStats(const char* msg)
+{
+    LOGV("VM stats (%s): cls=%d/%d meth=%d ifld=%d sfld=%d linear=%d",
+        msg, gDvm.numLoadedClasses, dvmHashTableNumEntries(gDvm.loadedClasses),
+        gDvm.numDeclaredMethods, gDvm.numDeclaredInstFields,
+        gDvm.numDeclaredStaticFields, gDvm.pBootLoaderAlloc->curOffset);
+#ifdef COUNT_PRECISE_METHODS
+    LOGI("GC precise methods: %d",
+        dvmPointerSetGetCount(gDvm.preciseMethods));
+#endif
+}
+
+/*
+ * ===========================================================================
+ *      Method Prototypes and Descriptors
+ * ===========================================================================
+ */
+
+/*
+ * Compare the two method names and prototypes, a la strcmp(). The
+ * name is considered the "major" order and the prototype the "minor"
+ * order. The prototypes are compared as if by dvmCompareMethodProtos().
+ */
+int dvmCompareMethodNamesAndProtos(const Method* method1,
+        const Method* method2)
+{
+    int result = strcmp(method1->name, method2->name);
+
+    if (result != 0) {
+        return result;
+    }
+
+    return dvmCompareMethodProtos(method1, method2);
+}
+
+/*
+ * Compare the two method names and prototypes, a la strcmp(), ignoring
+ * the return value. The name is considered the "major" order and the
+ * prototype the "minor" order. The prototypes are compared as if by
+ * dvmCompareMethodArgProtos().
+ */
+int dvmCompareMethodNamesAndParameterProtos(const Method* method1,
+        const Method* method2)
+{
+    int result = strcmp(method1->name, method2->name);
+
+    if (result != 0) {
+        return result;
+    }
+
+    return dvmCompareMethodParameterProtos(method1, method2);
+}
+
+/*
+ * Compare a (name, prototype) pair with the (name, prototype) of
+ * a method, a la strcmp(). The name is considered the "major" order and
+ * the prototype the "minor" order. The descriptor and prototype are
+ * compared as if by dvmCompareDescriptorAndMethodProto().
+ */
+int dvmCompareNameProtoAndMethod(const char* name,
+    const DexProto* proto, const Method* method)
+{
+    int result = strcmp(name, method->name);
+
+    if (result != 0) {
+        return result;
+    }
+
+    return dexProtoCompare(proto, &method->prototype);
+}
+
+/*
+ * Compare a (name, method descriptor) pair with the (name, prototype) of
+ * a method, a la strcmp(). The name is considered the "major" order and
+ * the prototype the "minor" order. The descriptor and prototype are
+ * compared as if by dvmCompareDescriptorAndMethodProto().
+ */
+int dvmCompareNameDescriptorAndMethod(const char* name,
+    const char* descriptor, const Method* method)
+{
+    int result = strcmp(name, method->name);
+
+    if (result != 0) {
+        return result;
+    }
+
+    return dvmCompareDescriptorAndMethodProto(descriptor, method);
+}
diff --git a/vm/oo/Class.h b/vm/oo/Class.h
new file mode 100644
index 0000000..349c666
--- /dev/null
+++ b/vm/oo/Class.h
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+/*
+ * Class loader.
+ */
+#ifndef DALVIK_OO_CLASS_H_
+#define DALVIK_OO_CLASS_H_
+
+/*
+ * The classpath and bootclasspath differ in that only the latter is
+ * consulted when looking for classes needed by the VM.  When searching
+ * for an arbitrary class definition, we start with the bootclasspath,
+ * look for optional packages (a/k/a standard extensions), and then try
+ * the classpath.
+ *
+ * In Dalvik, a class can be found in one of two ways:
+ *  - in a .dex file
+ *  - in a .dex file named specifically "classes.dex", which is held
+ *    inside a jar file
+ *
+ * These two may be freely intermixed in a classpath specification.
+ * Ordering is significant.
+ */
+enum ClassPathEntryKind {
+    kCpeUnknown = 0,
+    kCpeJar,
+    kCpeDex,
+    kCpeLastEntry       /* used as sentinel at end of array */
+};
+
+struct ClassPathEntry {
+    ClassPathEntryKind kind;
+    char*   fileName;
+    void*   ptr;            /* JarFile* or DexFile* */
+};
+
+bool dvmClassStartup(void);
+void dvmClassShutdown(void);
+bool dvmPrepBootClassPath(bool isNormalStart);
+
+/*
+ * Boot class path accessors, for class loader getResources().
+ */
+int dvmGetBootPathSize(void);
+StringObject* dvmGetBootPathResource(const char* name, int idx);
+void dvmDumpBootClassPath(void);
+
+/*
+ * Determine whether "path" is a member of "cpe".
+ */
+bool dvmClassPathContains(const ClassPathEntry* cpe, const char* path);
+
+/*
+ * Set clazz->serialNumber to the next available value.
+ */
+void dvmSetClassSerialNumber(ClassObject* clazz);
+
+/*
+ * Find the class object representing the primitive type with the
+ * given descriptor. This returns NULL if the given type character
+ * is invalid.
+ */
+ClassObject* dvmFindPrimitiveClass(char type);
+
+/*
+ * Find the class with the given descriptor.  Load it if it hasn't already
+ * been.
+ *
+ * "loader" is the initiating class loader.
+ */
+ClassObject* dvmFindClass(const char* descriptor, Object* loader);
+ClassObject* dvmFindClassNoInit(const char* descriptor, Object* loader);
+
+/*
+ * Like dvmFindClass, but only for system classes.
+ */
+ClassObject* dvmFindSystemClass(const char* descriptor);
+ClassObject* dvmFindSystemClassNoInit(const char* descriptor);
+
+/*
+ * Find a loaded class by descriptor. Returns the first one found.
+ * Because there can be more than one if class loaders are involved,
+ * this is not an especially good API. (Currently only used by the
+ * debugger and "checking" JNI.)
+ *
+ * "descriptor" should have the form "Ljava/lang/Class;" or
+ * "[Ljava/lang/Class;", i.e. a descriptor and not an internal-form
+ * class name.
+ */
+ClassObject* dvmFindLoadedClass(const char* descriptor);
+
+/*
+ * Load the named class (by descriptor) from the specified DEX file.
+ * Used by class loaders to instantiate a class object from a
+ * VM-managed DEX.
+ */
+ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor,
+    Object* classLoader);
+
+/*
+ * Link a loaded class.  Normally done as part of one of the "find class"
+ * variations, this is only called explicitly for synthetic class
+ * generation (e.g. reflect.Proxy).
+ */
+bool dvmLinkClass(ClassObject* clazz);
+
+/*
+ * Determine if a class has been initialized.
+ */
+INLINE bool dvmIsClassInitialized(const ClassObject* clazz) {
+    return (clazz->status == CLASS_INITIALIZED);
+}
+bool dvmIsClassInitializing(const ClassObject* clazz);
+
+/*
+ * Initialize a class.
+ */
+extern "C" bool dvmInitClass(ClassObject* clazz);
+
+/*
+ * Retrieve the system class loader.
+ */
+Object* dvmGetSystemClassLoader(void);
+
+/*
+ * Utility functions.
+ */
+ClassObject* dvmLookupClass(const char* descriptor, Object* loader,
+    bool unprepOkay);
+void dvmFreeClassInnards(ClassObject* clazz);
+bool dvmAddClassToHash(ClassObject* clazz);
+void dvmAddInitiatingLoader(ClassObject* clazz, Object* loader);
+bool dvmLoaderInInitiatingList(const ClassObject* clazz, const Object* loader);
+
+/*
+ * Update method's "nativeFunc" and "insns".  If "insns" is NULL, the
+ * current method->insns value is not changed.
+ */
+void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func, const u2* insns);
+
+/*
+ * Set the method's "registerMap" field.
+ */
+void dvmSetRegisterMap(Method* method, const RegisterMap* pMap);
+
+/*
+ * 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.
+ */
+void dvmDumpClass(const ClassObject* clazz, int flags);
+void dvmDumpAllClasses(int flags);
+void dvmDumpLoaderStats(const char* msg);
+int  dvmGetNumLoadedClasses();
+
+/* flags for dvmDumpClass / dvmDumpAllClasses */
+#define kDumpClassFullDetail    1
+#define kDumpClassClassLoader   (1 << 1)
+#define kDumpClassInitialized   (1 << 2)
+
+
+/*
+ * Store a copy of the method prototype descriptor string
+ * for the given method into the given DexStringCache, returning the
+ * stored string for convenience.
+ */
+INLINE char* dvmCopyDescriptorStringFromMethod(const Method* method,
+        DexStringCache *pCache)
+{
+    const char* result =
+        dexProtoGetMethodDescriptor(&method->prototype, pCache);
+    return dexStringCacheEnsureCopy(pCache, result);
+}
+
+/*
+ * Compute the number of argument words (u4 units) required by the
+ * given method's prototype. For example, if the method descriptor is
+ * "(IJ)D", this would return 3 (one for the int, two for the long;
+ * return value isn't relevant).
+ */
+INLINE int dvmComputeMethodArgsSize(const Method* method)
+{
+    return dexProtoComputeArgsSize(&method->prototype);
+}
+
+/*
+ * Compare the two method prototypes. The two prototypes are compared
+ * as if by strcmp() on the result of dexProtoGetMethodDescriptor().
+ */
+INLINE int dvmCompareMethodProtos(const Method* method1,
+        const Method* method2)
+{
+    return dexProtoCompare(&method1->prototype, &method2->prototype);
+}
+
+/*
+ * Compare the two method prototypes, considering only the parameters
+ * (i.e. ignoring the return types). The two prototypes are compared
+ * as if by strcmp() on the result of dexProtoGetMethodDescriptor().
+ */
+INLINE int dvmCompareMethodParameterProtos(const Method* method1,
+        const Method* method2)
+{
+    return dexProtoCompareParameters(&method1->prototype, &method2->prototype);
+}
+
+/*
+ * Compare the two method names and prototypes, a la strcmp(). The
+ * name is considered the "major" order and the prototype the "minor"
+ * order. The prototypes are compared as if by dexProtoGetMethodDescriptor().
+ */
+int dvmCompareMethodNamesAndProtos(const Method* method1,
+        const Method* method2);
+
+/*
+ * Compare the two method names and prototypes, a la strcmp(), ignoring
+ * the return type. The name is considered the "major" order and the
+ * prototype the "minor" order. The prototypes are compared as if by
+ * dexProtoGetMethodDescriptor().
+ */
+int dvmCompareMethodNamesAndParameterProtos(const Method* method1,
+        const Method* method2);
+
+/*
+ * Compare a method descriptor string with the prototype of a method,
+ * as if by converting the descriptor to a DexProto and comparing it
+ * with dexProtoCompare().
+ */
+INLINE int dvmCompareDescriptorAndMethodProto(const char* descriptor,
+    const Method* method)
+{
+    // Sense is reversed.
+    return -dexProtoCompareToDescriptor(&method->prototype, descriptor);
+}
+
+/*
+ * Compare a (name, prototype) pair with the (name, prototype) of
+ * a method, a la strcmp(). The name is considered the "major" order and
+ * the prototype the "minor" order. The descriptor and prototype are
+ * compared as if by dvmCompareDescriptorAndMethodProto().
+ */
+int dvmCompareNameProtoAndMethod(const char* name,
+    const DexProto* proto, const Method* method);
+
+/*
+ * Compare a (name, method descriptor) pair with the (name, prototype) of
+ * a method, a la strcmp(). The name is considered the "major" order and
+ * the prototype the "minor" order. The descriptor and prototype are
+ * compared as if by dvmCompareDescriptorAndMethodProto().
+ */
+int dvmCompareNameDescriptorAndMethod(const char* name,
+    const char* descriptor, const Method* method);
+
+/*
+ * Returns the size of the given class object in bytes.
+ */
+size_t dvmClassObjectSize(const ClassObject *clazz);
+
+#endif  // DALVIK_OO_CLASS_H_
diff --git a/vm/oo/Object.cpp b/vm/oo/Object.cpp
new file mode 100644
index 0000000..c1ed334
--- /dev/null
+++ b/vm/oo/Object.cpp
@@ -0,0 +1,825 @@
+/*
+ * 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.
+ */
+
+/*
+ * Operations on an Object.
+ */
+#include "Dalvik.h"
+
+/*
+ * Find a matching field, in the current class only.
+ *
+ * Returns NULL if the field can't be found.  (Does not throw an exception.)
+ */
+InstField* dvmFindInstanceField(const ClassObject* clazz,
+    const char* fieldName, const char* signature)
+{
+    InstField* pField;
+    int i;
+
+    assert(clazz != NULL);
+
+    /*
+     * Find a field with a matching name and signature.  The Java programming
+     * language does not allow you to have two fields with the same name
+     * and different types, but the Java VM spec does allow it, so we can't
+     * bail out early when the name matches.
+     */
+    pField = clazz->ifields;
+    for (i = 0; i < clazz->ifieldCount; i++, pField++) {
+        if (strcmp(fieldName, pField->name) == 0 &&
+            strcmp(signature, pField->signature) == 0)
+        {
+            return pField;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Find a matching field, in this class or a superclass.
+ *
+ * Searching through interfaces isn't necessary, because interface fields
+ * are inherently public/static/final.
+ *
+ * Returns NULL if the field can't be found.  (Does not throw an exception.)
+ */
+InstField* dvmFindInstanceFieldHier(const ClassObject* clazz,
+    const char* fieldName, const char* signature)
+{
+    InstField* pField;
+
+    /*
+     * Search for a match in the current class.
+     */
+    pField = dvmFindInstanceField(clazz, fieldName, signature);
+    if (pField != NULL)
+        return pField;
+
+    if (clazz->super != NULL)
+        return dvmFindInstanceFieldHier(clazz->super, fieldName, signature);
+    else
+        return NULL;
+}
+
+
+/*
+ * Find a matching field, in this class or an interface.
+ *
+ * Returns NULL if the field can't be found.  (Does not throw an exception.)
+ */
+StaticField* dvmFindStaticField(const ClassObject* clazz,
+    const char* fieldName, const char* signature)
+{
+    const StaticField* pField;
+    int i;
+
+    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[0];
+    for (i = 0; i < clazz->sfieldCount; i++, pField++) {
+        if (strcmp(fieldName, pField->name) == 0 &&
+            strcmp(signature, pField->signature) == 0)
+        {
+            return (StaticField*) pField;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Find a matching field, in this class or a superclass.
+ *
+ * Returns NULL if the field can't be found.  (Does not throw an exception.)
+ */
+StaticField* dvmFindStaticFieldHier(const ClassObject* clazz,
+    const char* fieldName, const char* signature)
+{
+    StaticField* pField;
+
+    /*
+     * Search for a match in the current class.
+     */
+    pField = dvmFindStaticField(clazz, fieldName, signature);
+    if (pField != NULL)
+        return pField;
+
+    /*
+     * See if it's in any of our interfaces.  We don't check interfaces
+     * inherited from the superclass yet.
+     *
+     * (Note the set may have been stripped down because of redundancy with
+     * the superclass; see notes in createIftable.)
+     */
+    int i = 0;
+    if (clazz->super != NULL) {
+        assert(clazz->iftableCount >= clazz->super->iftableCount);
+        i = clazz->super->iftableCount;
+    }
+    for ( ; i < clazz->iftableCount; i++) {
+        ClassObject* iface = clazz->iftable[i].clazz;
+        pField = dvmFindStaticField(iface, fieldName, signature);
+        if (pField != NULL)
+            return pField;
+    }
+
+    if (clazz->super != NULL)
+        return dvmFindStaticFieldHier(clazz->super, fieldName, signature);
+    else
+        return NULL;
+}
+
+/*
+ * Find a matching field, in this class or a superclass.
+ *
+ * We scan both the static and instance field lists in the class.  If it's
+ * not found there, we check the direct interfaces, and then recursively
+ * scan the superclasses.  This is the order prescribed in the VM spec
+ * (v2 5.4.3.2).
+ *
+ * In most cases we know that we're looking for either a static or an
+ * instance field and there's no value in searching through both types.
+ * During verification we need to recognize and reject certain unusual
+ * situations, and we won't see them unless we walk the lists this way.
+ */
+Field* dvmFindFieldHier(const ClassObject* clazz, const char* fieldName,
+    const char* signature)
+{
+    Field* pField;
+
+    /*
+     * Search for a match in the current class.  Which set we scan first
+     * doesn't really matter.
+     */
+    pField = (Field*) dvmFindStaticField(clazz, fieldName, signature);
+    if (pField != NULL)
+        return pField;
+    pField = (Field*) dvmFindInstanceField(clazz, fieldName, signature);
+    if (pField != NULL)
+        return pField;
+
+    /*
+     * See if it's in any of our interfaces.  We don't check interfaces
+     * inherited from the superclass yet.
+     */
+    int i = 0;
+    if (clazz->super != NULL) {
+        assert(clazz->iftableCount >= clazz->super->iftableCount);
+        i = clazz->super->iftableCount;
+    }
+    for ( ; i < clazz->iftableCount; i++) {
+        ClassObject* iface = clazz->iftable[i].clazz;
+        pField = (Field*) dvmFindStaticField(iface, fieldName, signature);
+        if (pField != NULL)
+            return pField;
+    }
+
+    if (clazz->super != NULL)
+        return dvmFindFieldHier(clazz->super, fieldName, signature);
+    else
+        return NULL;
+}
+
+
+/*
+ * Compare the given name, return type, and argument types with the contents
+ * of the given method. This returns 0 if they are equal and non-zero if not.
+ */
+static inline int compareMethodHelper(Method* method, const char* methodName,
+    const char* returnType, size_t argCount, const char** argTypes)
+{
+    DexParameterIterator iterator;
+    const DexProto* proto;
+
+    if (strcmp(methodName, method->name) != 0) {
+        return 1;
+    }
+
+    proto = &method->prototype;
+
+    if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) {
+        return 1;
+    }
+
+    if (dexProtoGetParameterCount(proto) != argCount) {
+        return 1;
+    }
+
+    dexParameterIteratorInit(&iterator, proto);
+
+    for (/*argCount*/; argCount != 0; argCount--, argTypes++) {
+        const char* argType = *argTypes;
+        const char* paramType = dexParameterIteratorNextDescriptor(&iterator);
+
+        if (paramType == NULL) {
+            /* Param list ended early; no match */
+            break;
+        } else if (strcmp(argType, paramType) != 0) {
+            /* Types aren't the same; no match. */
+            break;
+        }
+    }
+
+    if (argCount == 0) {
+        /* We ran through all the given arguments... */
+        if (dexParameterIteratorNextDescriptor(&iterator) == NULL) {
+            /* ...and through all the method's arguments; success! */
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+/*
+ * Get the count of arguments in the given method descriptor string,
+ * and also find a pointer to the return type.
+ */
+static inline size_t countArgsAndFindReturnType(const char* descriptor,
+    const char** pReturnType)
+{
+    size_t count = 0;
+    bool bogus = false;
+    bool done = false;
+
+    assert(*descriptor == '(');
+    descriptor++;
+
+    while (!done) {
+        switch (*descriptor) {
+            case 'B': case 'C': case 'D': case 'F':
+            case 'I': case 'J': case 'S': case 'Z': {
+                count++;
+                break;
+            }
+            case '[': {
+                do {
+                    descriptor++;
+                } while (*descriptor == '[');
+                /*
+                 * Don't increment count, as it will be taken care of
+                 * by the next iteration. Also, decrement descriptor
+                 * to compensate for the increment below the switch.
+                 */
+                descriptor--;
+                break;
+            }
+            case 'L': {
+                do {
+                    descriptor++;
+                } while ((*descriptor != ';') && (*descriptor != '\0'));
+                count++;
+                if (*descriptor == '\0') {
+                    /* Bogus descriptor. */
+                    done = true;
+                    bogus = true;
+                }
+                break;
+            }
+            case ')': {
+                /*
+                 * Note: The loop will exit after incrementing descriptor
+                 * one more time, so it then points at the return type.
+                 */
+                done = true;
+                break;
+            }
+            default: {
+                /* Bogus descriptor. */
+                done = true;
+                bogus = true;
+                break;
+            }
+        }
+
+        descriptor++;
+    }
+
+    if (bogus) {
+        *pReturnType = NULL;
+        return 0;
+    }
+
+    *pReturnType = descriptor;
+    return count;
+}
+
+/*
+ * Copy the argument types into the given array using the given buffer
+ * for the contents.
+ */
+static inline void copyTypes(char* buffer, const char** argTypes,
+    size_t argCount, const char* descriptor)
+{
+    size_t i;
+    char c;
+
+    /* Skip the '('. */
+    descriptor++;
+
+    for (i = 0; i < argCount; i++) {
+        argTypes[i] = buffer;
+
+        /* Copy all the array markers and one extra character. */
+        do {
+            c = *(descriptor++);
+            *(buffer++) = c;
+        } while (c == '[');
+
+        if (c == 'L') {
+            /* Copy the rest of a class name. */
+            do {
+                c = *(descriptor++);
+                *(buffer++) = c;
+            } while (c != ';');
+        }
+
+        *(buffer++) = '\0';
+    }
+}
+
+/*
+ * Look for a match in the given class. Returns the match if found
+ * or NULL if not.
+ */
+static Method* findMethodInListByDescriptor(const ClassObject* clazz,
+    bool findVirtual, bool isHier, const char* name, const char* descriptor)
+{
+    const char* returnType;
+    size_t argCount = countArgsAndFindReturnType(descriptor, &returnType);
+
+    if (returnType == NULL) {
+        LOGW("Bogus method descriptor: %s", descriptor);
+        return NULL;
+    }
+
+    /*
+     * Make buffer big enough for all the argument type characters and
+     * one '\0' per argument. The "- 2" is because "returnType -
+     * descriptor" includes two parens.
+     */
+    char buffer[argCount + (returnType - descriptor) - 2];
+    const char* argTypes[argCount];
+
+    copyTypes(buffer, argTypes, argCount, descriptor);
+
+    while (clazz != NULL) {
+        Method* methods;
+        size_t methodCount;
+        size_t i;
+
+        if (findVirtual) {
+            methods = clazz->virtualMethods;
+            methodCount = clazz->virtualMethodCount;
+        } else {
+            methods = clazz->directMethods;
+            methodCount = clazz->directMethodCount;
+        }
+
+        for (i = 0; i < methodCount; i++) {
+            Method* method = &methods[i];
+            if (compareMethodHelper(method, name, returnType, argCount,
+                            argTypes) == 0) {
+                return method;
+            }
+        }
+
+        if (! isHier) {
+            break;
+        }
+
+        clazz = clazz->super;
+    }
+
+    return NULL;
+}
+
+/*
+ * Look for a match in the given clazz. Returns the match if found
+ * or NULL if not.
+ *
+ * "wantedType" should be METHOD_VIRTUAL or METHOD_DIRECT to indicate the
+ * list to search through.  If the match can come from either list, use
+ * MATCH_UNKNOWN to scan both.
+ */
+static Method* findMethodInListByProto(const ClassObject* clazz,
+    MethodType wantedType, bool isHier, const char* name, const DexProto* proto)
+{
+    while (clazz != NULL) {
+        int i;
+
+        /*
+         * Check the virtual and/or direct method lists.
+         */
+        if (wantedType == METHOD_VIRTUAL || wantedType == METHOD_UNKNOWN) {
+            for (i = 0; i < clazz->virtualMethodCount; i++) {
+                Method* method = &clazz->virtualMethods[i];
+                if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
+                    return method;
+                }
+            }
+        }
+        if (wantedType == METHOD_DIRECT || wantedType == METHOD_UNKNOWN) {
+            for (i = 0; i < clazz->directMethodCount; i++) {
+                Method* method = &clazz->directMethods[i];
+                if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
+                    return method;
+                }
+            }
+        }
+
+        if (! isHier) {
+            break;
+        }
+
+        clazz = clazz->super;
+    }
+
+    return NULL;
+}
+
+/*
+ * Find a "virtual" method in a class.
+ *
+ * Does not chase into the superclass.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* descriptor)
+{
+    return findMethodInListByDescriptor(clazz, true, false,
+            methodName, descriptor);
+
+    // TODO? - throw IncompatibleClassChangeError if a match is
+    // found in the directMethods list, rather than NotFoundError.
+    // Note we could have been called by dvmFindVirtualMethodHier though.
+}
+
+
+/*
+ * Find a "virtual" method in a class, knowing only the name.  This is
+ * only useful in limited circumstances, e.g. when searching for a member
+ * of an annotation class.
+ *
+ * Does not chase into the superclass.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindVirtualMethodByName(const ClassObject* clazz,
+    const char* methodName)
+{
+    Method* methods = clazz->virtualMethods;
+    int methodCount = clazz->virtualMethodCount;
+    int i;
+
+    for (i = 0; i < methodCount; i++) {
+        if (strcmp(methods[i].name, methodName) == 0)
+            return &methods[i];
+    }
+
+    return NULL;
+}
+
+/*
+ * Find a "virtual" method in a class.
+ *
+ * Does not chase into the superclass.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
+    const DexProto* proto)
+{
+    return findMethodInListByProto(clazz, METHOD_VIRTUAL, false, methodName,
+            proto);
+}
+
+/*
+ * Find a "virtual" method in a class.  If we don't find it, try the
+ * superclass.  Does not examine interfaces.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* descriptor)
+{
+    return findMethodInListByDescriptor(clazz, true, true,
+            methodName, descriptor);
+}
+
+/*
+ * Find a "virtual" method in a class.  If we don't find it, try the
+ * superclass.  Does not examine interfaces.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
+    const char* methodName, const DexProto* proto)
+{
+    return findMethodInListByProto(clazz, METHOD_VIRTUAL, true, methodName,
+            proto);
+}
+
+/*
+ * Find a method in an interface.  Searches superinterfaces.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindInterfaceMethodHierByDescriptor(const ClassObject* iface,
+    const char* methodName, const char* descriptor)
+{
+    Method* resMethod = dvmFindVirtualMethodByDescriptor(iface,
+        methodName, descriptor);
+    if (resMethod == NULL) {
+        /* scan superinterfaces and superclass interfaces */
+        int i;
+        for (i = 0; i < iface->iftableCount; i++) {
+            resMethod = dvmFindVirtualMethodByDescriptor(iface->iftable[i].clazz,
+                methodName, descriptor);
+            if (resMethod != NULL)
+                break;
+        }
+    }
+    return resMethod;
+}
+
+/*
+ * Find a method in an interface.  Searches superinterfaces.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindInterfaceMethodHier(const ClassObject* iface,
+    const char* methodName, const DexProto* proto)
+{
+    Method* resMethod = dvmFindVirtualMethod(iface, methodName, proto);
+    if (resMethod == NULL) {
+        /* scan superinterfaces and superclass interfaces */
+        int i;
+        for (i = 0; i < iface->iftableCount; i++) {
+            resMethod = dvmFindVirtualMethod(iface->iftable[i].clazz,
+                methodName, proto);
+            if (resMethod != NULL)
+                break;
+        }
+    }
+    return resMethod;
+}
+
+/*
+ * Find a "direct" method (static, private, or "<*init>").
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* descriptor)
+{
+    return findMethodInListByDescriptor(clazz, false, false,
+            methodName, descriptor);
+}
+
+/*
+ * Find a "direct" method.  If we don't find it, try the superclass.  This
+ * is only appropriate for static methods, but will work for all direct
+ * methods.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* descriptor)
+{
+    return findMethodInListByDescriptor(clazz, false, true,
+            methodName, descriptor);
+}
+
+/*
+ * Find a "direct" method (static or "<*init>").
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
+    const DexProto* proto)
+{
+    return findMethodInListByProto(clazz, METHOD_DIRECT, false, methodName,
+            proto);
+}
+
+/*
+ * Find a "direct" method in a class.  If we don't find it, try the
+ * superclass.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindDirectMethodHier(const ClassObject* clazz,
+    const char* methodName, const DexProto* proto)
+{
+    return findMethodInListByProto(clazz, METHOD_DIRECT, true, methodName,
+            proto);
+}
+
+/*
+ * Find a virtual or static method in a class.  If we don't find it, try the
+ * superclass.  This is compatible with the VM spec (v2 5.4.3.3) method
+ * search order, but it stops short of scanning through interfaces (which
+ * should be done after this function completes).
+ *
+ * In most cases we know that we're looking for either a static or an
+ * instance field and there's no value in searching through both types.
+ * During verification we need to recognize and reject certain unusual
+ * situations, and we won't see them unless we walk the lists this way.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
+    const DexProto* proto)
+{
+    return findMethodInListByProto(clazz, METHOD_UNKNOWN, true, methodName,
+            proto);
+}
+
+
+/*
+ * We have a method pointer for a method in "clazz", but it might be
+ * pointing to a method in a derived class.  We want to find the actual entry
+ * from the class' vtable.  If "clazz" is an interface, we have to do a
+ * little more digging.
+ *
+ * For "direct" methods (private / constructor), we just return the
+ * original Method.
+ *
+ * (This is used for reflection and JNI "call method" calls.)
+ */
+const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
+    const Method* meth)
+{
+    Method* actualMeth;
+    int methodIndex;
+
+    if (dvmIsDirectMethod(meth)) {
+        /* no vtable entry for these */
+        assert(!dvmIsStaticMethod(meth));
+        return meth;
+    }
+
+    /*
+     * If the method was declared in an interface, we need to scan through
+     * the class' list of interfaces for it, and find the vtable index
+     * from that.
+     *
+     * TODO: use the interface cache.
+     */
+    if (dvmIsInterfaceClass(meth->clazz)) {
+        int i;
+
+        for (i = 0; i < clazz->iftableCount; i++) {
+            if (clazz->iftable[i].clazz == meth->clazz)
+                break;
+        }
+        if (i == clazz->iftableCount) {
+            dvmThrowIncompatibleClassChangeError(
+                "invoking method from interface not implemented by class");
+            return NULL;
+        }
+
+        methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
+    } else {
+        methodIndex = meth->methodIndex;
+    }
+
+    assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
+    actualMeth = clazz->vtable[methodIndex];
+
+    /*
+     * Make sure there's code to execute.
+     */
+    if (dvmIsAbstractMethod(actualMeth)) {
+        dvmThrowAbstractMethodError(NULL);
+        return NULL;
+    }
+    assert(!dvmIsMirandaMethod(actualMeth));
+
+    return actualMeth;
+}
+
+/*
+ * Get the source file for a method.
+ */
+const char* dvmGetMethodSourceFile(const Method* meth)
+{
+    /*
+     * TODO: A method's debug info can override the default source
+     * file for a class, so we should account for that possibility
+     * here.
+     */
+    return meth->clazz->sourceFile;
+}
+
+/*
+ * Dump some information about an object.
+ */
+void dvmDumpObject(const Object* obj)
+{
+    ClassObject* clazz;
+    int i;
+
+    if (obj == NULL || obj->clazz == NULL) {
+        LOGW("Null or malformed object not dumped");
+        return;
+    }
+
+    clazz = obj->clazz;
+    LOGD("----- Object dump: %p (%s, %d bytes) -----",
+        obj, clazz->descriptor, (int) clazz->objectSize);
+    //printHexDump(obj, clazz->objectSize);
+    LOGD("  Fields:");
+    while (clazz != NULL) {
+        LOGD("    -- %s", clazz->descriptor);
+        for (i = 0; i < clazz->ifieldCount; i++) {
+            const InstField* pField = &clazz->ifields[i];
+            char type = pField->signature[0];
+
+            if (type == 'F' || type == 'D') {
+                double dval;
+
+                if (type == 'F')
+                    dval = dvmGetFieldFloat(obj, pField->byteOffset);
+                else
+                    dval = dvmGetFieldDouble(obj, pField->byteOffset);
+
+                LOGD("    %2d: '%s' '%s' af=%04x off=%d %.3f", i,
+                    pField->name, pField->signature,
+                    pField->accessFlags, pField->byteOffset, dval);
+            } else {
+                u8 lval;
+
+                if (type == 'J')
+                    lval = dvmGetFieldLong(obj, pField->byteOffset);
+                else if (type == 'Z')
+                    lval = dvmGetFieldBoolean(obj, pField->byteOffset);
+                else
+                    lval = dvmGetFieldInt(obj, pField->byteOffset);
+
+                LOGD("    %2d: '%s' '%s' af=%04x off=%d 0x%08llx", i,
+                    pField->name, pField->signature,
+                    pField->accessFlags, pField->byteOffset, lval);
+            }
+        }
+
+        clazz = clazz->super;
+    }
+    if (dvmIsClassObject(obj)) {
+        LOGD("  Static fields:");
+        const StaticField* sfields = &((ClassObject *)obj)->sfields[0];
+        for (i = 0; i < ((ClassObject *)obj)->sfieldCount; ++i) {
+            const StaticField* pField = &sfields[i];
+            size_t byteOffset = (size_t)pField - (size_t)sfields;
+            char type = pField->signature[0];
+
+            if (type == 'F' || type == 'D') {
+                double dval;
+
+                if (type == 'F')
+                    dval = pField->value.f;
+                else
+                    dval = pField->value.d;
+
+                LOGD("    %2d: '%s' '%s' af=%04x off=%zd %.3f", i,
+                     pField->name, pField->signature,
+                     pField->accessFlags, byteOffset, dval);
+            } else {
+                u8 lval;
+
+                if (type == 'J')
+                    lval = pField->value.j;
+                else if (type == 'Z')
+                    lval = pField->value.z;
+                else
+                    lval = pField->value.i;
+
+                LOGD("    %2d: '%s' '%s' af=%04x off=%zd 0x%08llx", i,
+                     pField->name, pField->signature,
+                     pField->accessFlags, byteOffset, lval);
+            }
+        }
+    }
+}
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
new file mode 100644
index 0000000..b361926
--- /dev/null
+++ b/vm/oo/Object.h
@@ -0,0 +1,807 @@
+/*
+ * 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.
+ */
+
+/*
+ * Declaration of the fundamental Object type and refinements thereof, plus
+ * some functions for manipulating them.
+ */
+#ifndef DALVIK_OO_OBJECT_H_
+#define DALVIK_OO_OBJECT_H_
+
+#include <stddef.h>
+#include "Atomic.h"
+
+/* fwd decl */
+struct DataObject;
+struct InitiatingLoaderList;
+struct ClassObject;
+struct StringObject;
+struct ArrayObject;
+struct Method;
+struct ExceptionEntry;
+struct LineNumEntry;
+struct StaticField;
+struct InstField;
+struct Field;
+struct RegisterMap;
+
+/*
+ * Native function pointer type.
+ *
+ * "args[0]" holds the "this" pointer for virtual methods.
+ *
+ * The "Bridge" form is a super-set of the "Native" form; in many places
+ * they are used interchangeably.  Currently, all functions have all
+ * arguments passed in, but some functions only care about the first two.
+ * Passing extra arguments to a C function is (mostly) harmless.
+ */
+typedef void (*DalvikBridgeFunc)(const u4* args, JValue* pResult,
+    const Method* method, struct Thread* self);
+typedef void (*DalvikNativeFunc)(const u4* args, JValue* pResult);
+
+
+/* vm-internal access flags and related definitions */
+enum AccessFlags {
+    ACC_MIRANDA         = 0x8000,       // method (internal to VM)
+    JAVA_FLAGS_MASK     = 0xffff,       // bits set from Java sources (low 16)
+};
+
+/* Use the top 16 bits of the access flags field for
+ * other class flags.  Code should use the *CLASS_FLAG*()
+ * macros to set/get these flags.
+ */
+enum ClassFlags {
+    CLASS_ISFINALIZABLE        = (1<<31), // class/ancestor overrides finalize()
+    CLASS_ISARRAY              = (1<<30), // class is a "[*"
+    CLASS_ISOBJECTARRAY        = (1<<29), // class is a "[L*" or "[[*"
+    CLASS_ISCLASS              = (1<<28), // class is *the* class Class
+
+    CLASS_ISREFERENCE          = (1<<27), // class is a soft/weak/phantom ref
+                                          // only ISREFERENCE is set --> soft
+    CLASS_ISWEAKREFERENCE      = (1<<26), // class is a weak reference
+    CLASS_ISFINALIZERREFERENCE = (1<<25), // class is a finalizer reference
+    CLASS_ISPHANTOMREFERENCE   = (1<<24), // class is a phantom reference
+
+    CLASS_MULTIPLE_DEFS        = (1<<23), // DEX verifier: defs in multiple DEXs
+
+    /* unlike the others, these can be present in the optimized DEX file */
+    CLASS_ISOPTIMIZED          = (1<<17), // class may contain opt instrs
+    CLASS_ISPREVERIFIED        = (1<<16), // class has been pre-verified
+};
+
+/* bits we can reasonably expect to see set in a DEX access flags field */
+#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.
+ */
+enum MethodFlags {
+    METHOD_ISWRITABLE       = (1<<31),  // the method's code is writable
+};
+
+/*
+ * 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 */
+enum ClassStatus {
+    CLASS_ERROR         = -1,
+
+    CLASS_NOTREADY      = 0,
+    CLASS_IDX           = 1,    /* loaded, DEX idx in super or ifaces */
+    CLASS_LOADED        = 2,    /* DEX idx values resolved */
+    CLASS_RESOLVED      = 3,    /* part of linking */
+    CLASS_VERIFYING     = 4,    /* in the process of being verified */
+    CLASS_VERIFIED      = 5,    /* logically part of linking; done pre-init */
+    CLASS_INITIALIZING  = 6,    /* class init in progress */
+    CLASS_INITIALIZED   = 7,    /* ready to go */
+};
+
+/*
+ * Definitions for packing refOffsets in ClassObject.
+ */
+/*
+ * A magic value for refOffsets. Ignore the bits and walk the super
+ * chain when this is the value.
+ * [This is an unlikely "natural" value, since it would be 30 non-ref instance
+ * fields followed by 2 ref instance fields.]
+ */
+#define CLASS_WALK_SUPER ((unsigned int)(3))
+#define CLASS_SMALLEST_OFFSET (sizeof(struct Object))
+#define CLASS_BITS_PER_WORD (sizeof(unsigned long int) * 8)
+#define CLASS_OFFSET_ALIGNMENT 4
+#define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1))
+/*
+ * Given an offset, return the bit number which would encode that offset.
+ * Local use only.
+ */
+#define _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) \
+    (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \
+     CLASS_OFFSET_ALIGNMENT)
+/*
+ * Is the given offset too large to be encoded?
+ */
+#define CLASS_CAN_ENCODE_OFFSET(byteOffset) \
+    (_CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) < CLASS_BITS_PER_WORD)
+/*
+ * Return a single bit, encoding the offset.
+ * Undefined if the offset is too large, as defined above.
+ */
+#define CLASS_BIT_FROM_OFFSET(byteOffset) \
+    (CLASS_HIGH_BIT >> _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset))
+/*
+ * Return an offset, given a bit number as returned from CLZ.
+ */
+#define CLASS_OFFSET_FROM_CLZ(rshift) \
+    (((int)(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET)
+
+
+/*
+ * Used for iftable in ClassObject.
+ */
+struct InterfaceEntry {
+    /* pointer to interface class */
+    ClassObject*    clazz;
+
+    /*
+     * Index into array of vtable offsets.  This points into the ifviPool,
+     * which holds the vtables for all interfaces declared by this class.
+     */
+    int*            methodIndexArray;
+};
+
+
+
+/*
+ * There are three types of objects:
+ *  Class objects - an instance of java.lang.Class
+ *  Array objects - an object created with a "new array" instruction
+ *  Data objects - an object that is neither of the above
+ *
+ * We also define String objects.  At present they're equivalent to
+ * DataObject, but that may change.  (Either way, they make some of the
+ * code more obvious.)
+ *
+ * All objects have an Object header followed by type-specific data.
+ */
+struct Object {
+    /* ptr to class object */
+    ClassObject*    clazz;
+
+    /*
+     * A word containing either a "thin" lock or a "fat" monitor.  See
+     * the comments in Sync.c for a description of its layout.
+     */
+    u4              lock;
+};
+
+/*
+ * Properly initialize an Object.
+ * void DVM_OBJECT_INIT(Object *obj, ClassObject *clazz_)
+ */
+#define DVM_OBJECT_INIT(obj, clazz_) \
+    dvmSetFieldObject(obj, OFFSETOF_MEMBER(Object, clazz), clazz_)
+
+/*
+ * Data objects have an Object header followed by their instance data.
+ */
+struct DataObject : Object {
+    /* variable #of u4 slots; u8 uses 2 slots */
+    u4              instanceData[1];
+};
+
+/*
+ * Strings are used frequently enough that we may want to give them their
+ * own unique type.
+ *
+ * Using a dedicated type object to access the instance data provides a
+ * performance advantage but makes the java/lang/String.java implementation
+ * fragile.
+ *
+ * Currently this is just equal to DataObject, and we pull the fields out
+ * like we do for any other object.
+ */
+struct StringObject : Object {
+    /* variable #of u4 slots; u8 uses 2 slots */
+    u4              instanceData[1];
+
+    /** Returns this string's length in characters. */
+    int length() const;
+
+    /**
+     * Returns this string's length in bytes when encoded as modified UTF-8.
+     * Does not include a terminating NUL byte.
+     */
+    int utfLength() const;
+
+    /** Returns this string's char[] as an ArrayObject. */
+    ArrayObject* array() const;
+
+    /** Returns this string's char[] as a u2*. */
+    const u2* chars() const;
+};
+
+
+/*
+ * Array objects have these additional fields.
+ *
+ * We don't currently store the size of each element.  Usually it's implied
+ * by the instruction.  If necessary, the width can be derived from
+ * the first char of obj->clazz->descriptor.
+ */
+struct ArrayObject : Object {
+    /* number of elements; immutable after init */
+    u4              length;
+
+    /*
+     * Array contents; actual size is (length * sizeof(type)).  This is
+     * declared as u8 so that the compiler inserts any necessary padding
+     * (e.g. for EABI); the actual allocation may be smaller than 8 bytes.
+     */
+    u8              contents[1];
+};
+
+/*
+ * For classes created early and thus probably in the zygote, the
+ * InitiatingLoaderList is kept in gDvm. Later classes use the structure in
+ * Object Class. This helps keep zygote pages shared.
+ */
+struct InitiatingLoaderList {
+    /* a list of initiating loader Objects; grown and initialized on demand */
+    Object**  initiatingLoaders;
+    /* count of loaders in the above list */
+    int       initiatingLoaderCount;
+};
+
+/*
+ * Generic field header.  We pass this around when we want a generic Field
+ * pointer (e.g. for reflection stuff).  Testing the accessFlags for
+ * ACC_STATIC allows a proper up-cast.
+ */
+struct Field {
+    ClassObject*    clazz;          /* class in which the field is declared */
+    const char*     name;
+    const char*     signature;      /* e.g. "I", "[C", "Landroid/os/Debug;" */
+    u4              accessFlags;
+};
+
+/*
+ * Static field.
+ */
+struct StaticField : Field {
+    JValue          value;          /* initially set from DEX for primitives */
+};
+
+/*
+ * Instance field.
+ */
+struct InstField : Field {
+    /*
+     * This field indicates the byte offset from the beginning of the
+     * (Object *) to the actual instance data; e.g., byteOffset==0 is
+     * the same as the object pointer (bug!), and byteOffset==4 is 4
+     * bytes farther.
+     */
+    int             byteOffset;
+};
+
+/*
+ * This defines the amount of space we leave for field slots in the
+ * java.lang.Class definition.  If we alter the class to have more than
+ * this many fields, the VM will abort at startup.
+ */
+#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).
+ *
+ * Class objects are unusual in that they have some fields allocated with
+ * the system malloc (or LinearAlloc), rather than on the GC heap.  This is
+ * handy during initialization, but does require special handling when
+ * discarding java.lang.Class objects.
+ *
+ * The separation of methods (direct vs. virtual) and fields (class vs.
+ * instance) used in Dalvik works out pretty well.  The only time it's
+ * annoying is when enumerating or searching for things with reflection.
+ */
+struct ClassObject : Object {
+    /* leave space for instance data; we could access fields directly if we
+       freeze the definition of java/lang/Class */
+    u4              instanceData[CLASS_FIELD_SLOTS];
+
+    /* UTF-8 descriptor for the class; from constant pool, or on heap
+       if generated ("[C") */
+    const char*     descriptor;
+    char*           descriptorAlloc;
+
+    /* access flags; low 16 bits are defined by VM spec */
+    u4              accessFlags;
+
+    /* VM-unique class serial number, nonzero, set very early */
+    u4              serialNumber;
+
+    /* DexFile from which we came; needed to resolve constant pool entries */
+    /* (will be NULL for VM-generated, e.g. arrays and primitive classes) */
+    DvmDex*         pDvmDex;
+
+    /* state of class initialization */
+    ClassStatus     status;
+
+    /* if class verify fails, we must return same error on subsequent tries */
+    ClassObject*    verifyErrorClass;
+
+    /* threadId, used to check for recursive <clinit> invocation */
+    u4              initThreadId;
+
+    /*
+     * Total object size; used when allocating storage on gc heap.  (For
+     * interfaces and abstract classes this will be zero.)
+     */
+    size_t          objectSize;
+
+    /* arrays only: class object for base element, for instanceof/checkcast
+       (for String[][][], this will be String) */
+    ClassObject*    elementClass;
+
+    /* arrays only: number of dimensions, e.g. int[][] is 2 */
+    int             arrayDim;
+
+    /* primitive type index, or PRIM_NOT (-1); set for generated prim classes */
+    PrimitiveType   primitiveType;
+
+    /* superclass, or NULL if this is java.lang.Object */
+    ClassObject*    super;
+
+    /* defining class loader, or NULL for the "bootstrap" system loader */
+    Object*         classLoader;
+
+    /* initiating class loader list */
+    /* NOTE: for classes with low serialNumber, these are unused, and the
+       values are kept in a table in gDvm. */
+    InitiatingLoaderList initiatingLoaderList;
+
+    /* array of interfaces this class implements directly */
+    int             interfaceCount;
+    ClassObject**   interfaces;
+
+    /* static, private, and <init> methods */
+    int             directMethodCount;
+    Method*         directMethods;
+
+    /* virtual methods defined in this class; invoked through vtable */
+    int             virtualMethodCount;
+    Method*         virtualMethods;
+
+    /*
+     * Virtual method table (vtable), for use by "invoke-virtual".  The
+     * vtable from the superclass is copied in, and virtual methods from
+     * our class either replace those from the super or are appended.
+     */
+    int             vtableCount;
+    Method**        vtable;
+
+    /*
+     * Interface table (iftable), one entry per interface supported by
+     * this class.  That means one entry for each interface we support
+     * directly, indirectly via superclass, or indirectly via
+     * superinterface.  This will be null if neither we nor our superclass
+     * implement any interfaces.
+     *
+     * Why we need this: given "class Foo implements Face", declare
+     * "Face faceObj = new Foo()".  Invoke faceObj.blah(), where "blah" is
+     * part of the Face interface.  We can't easily use a single vtable.
+     *
+     * For every interface a concrete class implements, we create a list of
+     * virtualMethod indices for the methods in the interface.
+     */
+    int             iftableCount;
+    InterfaceEntry* iftable;
+
+    /*
+     * The interface vtable indices for iftable get stored here.  By placing
+     * them all in a single pool for each class that implements interfaces,
+     * we decrease the number of allocations.
+     */
+    int             ifviPoolCount;
+    int*            ifviPool;
+
+    /* instance fields
+     *
+     * These describe the layout of the contents of a DataObject-compatible
+     * Object.  Note that only the fields directly defined by this class
+     * are listed in ifields;  fields defined by a superclass are listed
+     * in the superclass's ClassObject.ifields.
+     *
+     * All instance fields that refer to objects are guaranteed to be
+     * at the beginning of the field list.  ifieldRefCount specifies
+     * the number of reference fields.
+     */
+    int             ifieldCount;
+    int             ifieldRefCount; // number of fields that are object refs
+    InstField*      ifields;
+
+    /* bitmap of offsets of ifields */
+    u4 refOffsets;
+
+    /* source file name, if known */
+    const char*     sourceFile;
+
+    /* static fields */
+    int             sfieldCount;
+    StaticField     sfields[]; /* MUST be last item */
+};
+
+/*
+ * A method.  We create one of these for every method in every class
+ * we load, so try to keep the size to a minimum.
+ *
+ * Much of this comes from and could be accessed in the data held in shared
+ * memory.  We hold it all together here for speed.  Everything but the
+ * pointers could be held in a shared table generated by the optimizer;
+ * if we're willing to convert them to offsets and take the performance
+ * hit (e.g. "meth->insns" becomes "baseAddr + meth->insnsOffset") we
+ * could move everything but "nativeFunc".
+ */
+struct Method {
+    /* the class we are a part of */
+    ClassObject*    clazz;
+
+    /* access flags; low 16 bits are defined by spec (could be u2?) */
+    u4              accessFlags;
+
+    /*
+     * For concrete virtual methods, this is the offset of the method
+     * in "vtable".
+     *
+     * For abstract methods in an interface class, this is the offset
+     * of the method in "iftable[n]->methodIndexArray".
+     */
+    u2             methodIndex;
+
+    /*
+     * Method bounds; not needed for an abstract method.
+     *
+     * For a native method, we compute the size of the argument list, and
+     * set "insSize" and "registerSize" equal to it.
+     */
+    u2              registersSize;  /* ins + locals */
+    u2              outsSize;
+    u2              insSize;
+
+    /* method name, e.g. "<init>" or "eatLunch" */
+    const char*     name;
+
+    /*
+     * Method prototype descriptor string (return and argument types).
+     *
+     * TODO: This currently must specify the DexFile as well as the proto_ids
+     * index, because generated Proxy classes don't have a DexFile.  We can
+     * remove the DexFile* and reduce the size of this struct if we generate
+     * a DEX for proxies.
+     */
+    DexProto        prototype;
+
+    /* short-form method descriptor string */
+    const char*     shorty;
+
+    /*
+     * The remaining items are not used for abstract or native methods.
+     * (JNI is currently hijacking "insns" as a function pointer, set
+     * after the first call.  For internal-native this stays null.)
+     */
+
+    /* the actual code */
+    const u2*       insns;          /* instructions, in memory-mapped .dex */
+
+    /* JNI: cached argument and return-type hints */
+    int             jniArgInfo;
+
+    /*
+     * JNI: native method ptr; could be actual function or a JNI bridge.  We
+     * don't currently discriminate between DalvikBridgeFunc and
+     * DalvikNativeFunc; the former takes an argument superset (i.e. two
+     * extra args) which will be ignored.  If necessary we can use
+     * insns==NULL to detect JNI bridge vs. internal native.
+     */
+    DalvikBridgeFunc nativeFunc;
+
+    /*
+     * JNI: true if this static non-synchronized native method (that has no
+     * reference arguments) needs a JNIEnv* and jclass/jobject. Libcore
+     * uses this.
+     */
+    bool fastJni;
+
+    /*
+     * JNI: true if this method has no reference arguments. This lets the JNI
+     * bridge avoid scanning the shorty for direct pointers that need to be
+     * converted to local references.
+     *
+     * TODO: replace this with a list of indexes of the reference arguments.
+     */
+    bool noRef;
+
+    /*
+     * JNI: true if we should log entry and exit. This is the only way
+     * developers can log the local references that are passed into their code.
+     * Used for debugging JNI problems in third-party code.
+     */
+    bool shouldTrace;
+
+    /*
+     * Register map data, if available.  This will point into the DEX file
+     * if the data was computed during pre-verification, or into the
+     * linear alloc area if not.
+     */
+    const RegisterMap* registerMap;
+
+    /* set if method was called during method profiling */
+    bool            inProfile;
+};
+
+
+/*
+ * Find a method within a class.  The superclass is not searched.
+ */
+Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* signature);
+Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* signature);
+Method* dvmFindVirtualMethodByName(const ClassObject* clazz,
+    const char* methodName);
+Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
+    const DexProto* proto);
+Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
+    const DexProto* proto);
+
+
+/*
+ * Find a method within a class hierarchy.
+ */
+Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* descriptor);
+Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
+    const char* methodName, const char* signature);
+Method* dvmFindDirectMethodHier(const ClassObject* clazz,
+    const char* methodName, const DexProto* proto);
+Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
+    const char* methodName, const DexProto* proto);
+Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
+    const DexProto* proto);
+
+/*
+ * Find a method in an interface hierarchy.
+ */
+Method* dvmFindInterfaceMethodHierByDescriptor(const ClassObject* iface,
+    const char* methodName, const char* descriptor);
+Method* dvmFindInterfaceMethodHier(const ClassObject* iface,
+    const char* methodName, const DexProto* proto);
+
+/*
+ * Find the implementation of "meth" in "clazz".
+ *
+ * Returns NULL and throws an exception if not found.
+ */
+const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
+    const Method* meth);
+
+/*
+ * Get the source file associated with a method.
+ */
+extern "C" const char* dvmGetMethodSourceFile(const Method* meth);
+
+/*
+ * Find a field within a class.  The superclass is not searched.
+ */
+InstField* dvmFindInstanceField(const ClassObject* clazz,
+    const char* fieldName, const char* signature);
+StaticField* dvmFindStaticField(const ClassObject* clazz,
+    const char* fieldName, const char* signature);
+
+/*
+ * Find a field in a class/interface hierarchy.
+ */
+InstField* dvmFindInstanceFieldHier(const ClassObject* clazz,
+    const char* fieldName, const char* signature);
+StaticField* dvmFindStaticFieldHier(const ClassObject* clazz,
+    const char* fieldName, const char* signature);
+Field* dvmFindFieldHier(const ClassObject* clazz, const char* fieldName,
+    const char* signature);
+
+/*
+ * Find a field and return the byte offset from the object pointer.  Only
+ * searches the specified class, not the superclass.
+ *
+ * Returns -1 on failure.
+ */
+INLINE int dvmFindFieldOffset(const ClassObject* clazz,
+    const char* fieldName, const char* signature)
+{
+    InstField* pField = dvmFindInstanceField(clazz, fieldName, signature);
+    if (pField == NULL)
+        return -1;
+    else
+        return pField->byteOffset;
+}
+
+/*
+ * Helpers.
+ */
+INLINE bool dvmIsPublicMethod(const Method* method) {
+    return (method->accessFlags & ACC_PUBLIC) != 0;
+}
+INLINE bool dvmIsPrivateMethod(const Method* method) {
+    return (method->accessFlags & ACC_PRIVATE) != 0;
+}
+INLINE bool dvmIsStaticMethod(const Method* method) {
+    return (method->accessFlags & ACC_STATIC) != 0;
+}
+INLINE bool dvmIsSynchronizedMethod(const Method* method) {
+    return (method->accessFlags & ACC_SYNCHRONIZED) != 0;
+}
+INLINE bool dvmIsDeclaredSynchronizedMethod(const Method* method) {
+    return (method->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
+}
+INLINE bool dvmIsFinalMethod(const Method* method) {
+    return (method->accessFlags & ACC_FINAL) != 0;
+}
+INLINE bool dvmIsNativeMethod(const Method* method) {
+    return (method->accessFlags & ACC_NATIVE) != 0;
+}
+INLINE bool dvmIsAbstractMethod(const Method* method) {
+    return (method->accessFlags & ACC_ABSTRACT) != 0;
+}
+INLINE bool dvmIsSyntheticMethod(const Method* method) {
+    return (method->accessFlags & ACC_SYNTHETIC) != 0;
+}
+INLINE bool dvmIsMirandaMethod(const Method* method) {
+    return (method->accessFlags & ACC_MIRANDA) != 0;
+}
+INLINE bool dvmIsConstructorMethod(const Method* method) {
+    return *method->name == '<';
+}
+/* Dalvik puts private, static, and constructors into non-virtual table */
+INLINE bool dvmIsDirectMethod(const Method* method) {
+    return dvmIsPrivateMethod(method) ||
+           dvmIsStaticMethod(method) ||
+           dvmIsConstructorMethod(method);
+}
+/* Get whether the given method has associated bytecode. This is the
+ * case for methods which are neither native nor abstract. */
+INLINE bool dvmIsBytecodeMethod(const Method* method) {
+    return (method->accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
+}
+
+INLINE bool dvmIsProtectedField(const Field* field) {
+    return (field->accessFlags & ACC_PROTECTED) != 0;
+}
+INLINE bool dvmIsStaticField(const Field* field) {
+    return (field->accessFlags & ACC_STATIC) != 0;
+}
+INLINE bool dvmIsFinalField(const Field* field) {
+    return (field->accessFlags & ACC_FINAL) != 0;
+}
+INLINE bool dvmIsVolatileField(const Field* field) {
+    return (field->accessFlags & ACC_VOLATILE) != 0;
+}
+
+INLINE bool dvmIsInterfaceClass(const ClassObject* clazz) {
+    return (clazz->accessFlags & ACC_INTERFACE) != 0;
+}
+INLINE bool dvmIsPublicClass(const ClassObject* clazz) {
+    return (clazz->accessFlags & ACC_PUBLIC) != 0;
+}
+INLINE bool dvmIsFinalClass(const ClassObject* clazz) {
+    return (clazz->accessFlags & ACC_FINAL) != 0;
+}
+INLINE bool dvmIsAbstractClass(const ClassObject* clazz) {
+    return (clazz->accessFlags & ACC_ABSTRACT) != 0;
+}
+INLINE bool dvmIsAnnotationClass(const ClassObject* clazz) {
+    return (clazz->accessFlags & ACC_ANNOTATION) != 0;
+}
+INLINE bool dvmIsPrimitiveClass(const ClassObject* clazz) {
+    return clazz->primitiveType != PRIM_NOT;
+}
+
+/* linked, here meaning prepared and resolved */
+INLINE bool dvmIsClassLinked(const ClassObject* clazz) {
+    return clazz->status >= CLASS_RESOLVED;
+}
+/* has class been verified? */
+INLINE bool dvmIsClassVerified(const ClassObject* clazz) {
+    return clazz->status >= CLASS_VERIFIED;
+}
+
+/*
+ * Return whether the given object is an instance of Class.
+ */
+INLINE bool dvmIsClassObject(const Object* obj) {
+    assert(obj != NULL);
+    assert(obj->clazz != NULL);
+    return IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISCLASS);
+}
+
+/*
+ * Return whether the given object is the class Class (that is, the
+ * unique class which is an instance of itself).
+ */
+INLINE bool dvmIsTheClassClass(const ClassObject* clazz) {
+    assert(clazz != NULL);
+    return IS_CLASS_FLAG_SET(clazz, CLASS_ISCLASS);
+}
+
+/*
+ * Get the associated code struct for a method. This returns NULL
+ * for non-bytecode methods.
+ */
+INLINE const DexCode* dvmGetMethodCode(const Method* meth) {
+    if (dvmIsBytecodeMethod(meth)) {
+        /*
+         * The insns field for a bytecode method actually points at
+         * &(DexCode.insns), so we can subtract back to get at the
+         * DexCode in front.
+         */
+        return (const DexCode*)
+            (((const u1*) meth->insns) - offsetof(DexCode, insns));
+    } else {
+        return NULL;
+    }
+}
+
+/*
+ * Get the size of the insns associated with a method. This returns 0
+ * for non-bytecode methods.
+ */
+INLINE u4 dvmGetMethodInsnsSize(const Method* meth) {
+    const DexCode* pCode = dvmGetMethodCode(meth);
+    return (pCode == NULL) ? 0 : pCode->insnsSize;
+}
+
+/* debugging */
+void dvmDumpObject(const Object* obj);
+
+#endif  // DALVIK_OO_OBJECT_H_
diff --git a/vm/oo/ObjectInlines.h b/vm/oo/ObjectInlines.h
new file mode 100644
index 0000000..eb2e962
--- /dev/null
+++ b/vm/oo/ObjectInlines.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Helper functions to access data fields in Objects.
+ */
+#ifndef DALVIK_OO_OBJECTINLINES_H_
+#define DALVIK_OO_OBJECTINLINES_H_
+
+/*
+ * Store a single value in the array, and if the value isn't null,
+ * note in the write barrier.
+ */
+INLINE void dvmSetObjectArrayElement(const ArrayObject* obj, int index,
+                                     Object* val) {
+    ((Object **)(void *)(obj)->contents)[index] = val;
+    if (val != NULL) {
+        dvmWriteBarrierArray(obj, index, index + 1);
+    }
+}
+
+
+/*
+ * Field access functions.  Pass in the word offset from Field->byteOffset.
+ *
+ * We guarantee that long/double field data is 64-bit aligned, so it's safe
+ * to access them with ldrd/strd on ARM.
+ *
+ * The VM treats all fields as 32 or 64 bits, so the field set functions
+ * write 32 bits even if the underlying type is smaller.
+ *
+ * Setting Object types to non-null values includes a call to the
+ * write barrier.
+ */
+#define BYTE_OFFSET(_ptr, _offset)  ((void*) (((u1*)(_ptr)) + (_offset)))
+
+INLINE JValue* dvmFieldPtr(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset));
+}
+
+INLINE bool dvmGetFieldBoolean(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->z;
+}
+INLINE s1 dvmGetFieldByte(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->b;
+}
+INLINE s2 dvmGetFieldShort(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->s;
+}
+INLINE u2 dvmGetFieldChar(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->c;
+}
+INLINE s4 dvmGetFieldInt(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->i;
+}
+INLINE s8 dvmGetFieldLong(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->j;
+}
+INLINE float dvmGetFieldFloat(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->f;
+}
+INLINE double dvmGetFieldDouble(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->d;
+}
+INLINE Object* dvmGetFieldObject(const Object* obj, int offset) {
+    return ((JValue*)BYTE_OFFSET(obj, offset))->l;
+}
+INLINE bool dvmGetFieldBooleanVolatile(const Object* obj, int offset) {
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    return (bool)android_atomic_acquire_load(ptr);
+}
+INLINE s1 dvmGetFieldByteVolatile(const Object* obj, int offset) {
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    return (s1)android_atomic_acquire_load(ptr);
+}
+INLINE s2 dvmGetFieldShortVolatile(const Object* obj, int offset) {
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    return (s2)android_atomic_acquire_load(ptr);
+}
+INLINE u2 dvmGetFieldCharVolatile(const Object* obj, int offset) {
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    return (u2)android_atomic_acquire_load(ptr);
+}
+INLINE s4 dvmGetFieldIntVolatile(const Object* obj, int offset) {
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    return android_atomic_acquire_load(ptr);
+}
+INLINE float dvmGetFieldFloatVolatile(const Object* obj, int offset) {
+    union { s4 ival; float fval; } alias;
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    alias.ival = android_atomic_acquire_load(ptr);
+    return alias.fval;
+}
+INLINE s8 dvmGetFieldLongVolatile(const Object* obj, int offset) {
+    const s8* addr = (const s8*)BYTE_OFFSET(obj, offset);
+    s8 val = dvmQuasiAtomicRead64(addr);
+    ANDROID_MEMBAR_FULL();
+    return val;
+}
+INLINE double dvmGetFieldDoubleVolatile(const Object* obj, int offset) {
+    union { s8 lval; double dval; } alias;
+    const s8* addr = (const s8*)BYTE_OFFSET(obj, offset);
+    alias.lval = dvmQuasiAtomicRead64(addr);
+    ANDROID_MEMBAR_FULL();
+    return alias.dval;
+}
+INLINE Object* dvmGetFieldObjectVolatile(const Object* obj, int offset) {
+    Object** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l;
+    return (Object*)android_atomic_acquire_load((int32_t*)ptr);
+}
+
+INLINE void dvmSetFieldBoolean(Object* obj, int offset, bool val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldByte(Object* obj, int offset, s1 val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldShort(Object* obj, int offset, s2 val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldChar(Object* obj, int offset, u2 val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldInt(Object* obj, int offset, s4 val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->i = val;
+}
+INLINE void dvmSetFieldFloat(Object* obj, int offset, float val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->f = val;
+}
+INLINE void dvmSetFieldLong(Object* obj, int offset, s8 val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->j = val;
+}
+INLINE void dvmSetFieldDouble(Object* obj, int offset, double val) {
+    ((JValue*)BYTE_OFFSET(obj, offset))->d = val;
+}
+INLINE void dvmSetFieldObject(Object* obj, int offset, Object* val) {
+    JValue* lhs = (JValue*)BYTE_OFFSET(obj, offset);
+    lhs->l = val;
+    if (val != NULL) {
+        dvmWriteBarrierField(obj, &lhs->l);
+    }
+}
+INLINE void dvmSetFieldIntVolatile(Object* obj, int offset, s4 val) {
+    s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i;
+    /*
+     * TODO: add an android_atomic_synchronization_store() function and
+     * use it in the 32-bit volatile set handlers.  On some platforms we
+     * can use a fast atomic instruction and avoid the barriers.
+     */
+    ANDROID_MEMBAR_STORE();
+    *ptr = val;
+    ANDROID_MEMBAR_FULL();
+}
+INLINE void dvmSetFieldBooleanVolatile(Object* obj, int offset, bool val) {
+    dvmSetFieldIntVolatile(obj, offset, val);
+}
+INLINE void dvmSetFieldByteVolatile(Object* obj, int offset, s1 val) {
+    dvmSetFieldIntVolatile(obj, offset, val);
+}
+INLINE void dvmSetFieldShortVolatile(Object* obj, int offset, s2 val) {
+    dvmSetFieldIntVolatile(obj, offset, val);
+}
+INLINE void dvmSetFieldCharVolatile(Object* obj, int offset, u2 val) {
+    dvmSetFieldIntVolatile(obj, offset, val);
+}
+INLINE void dvmSetFieldFloatVolatile(Object* obj, int offset, float val) {
+    union { s4 ival; float fval; } alias;
+    alias.fval = val;
+    dvmSetFieldIntVolatile(obj, offset, alias.ival);
+}
+INLINE void dvmSetFieldLongVolatile(Object* obj, int offset, s8 val) {
+    s8* addr = (s8*)BYTE_OFFSET(obj, offset);
+    dvmQuasiAtomicSwap64Sync(val, addr);
+}
+INLINE void dvmSetFieldDoubleVolatile(Object* obj, int offset, double val) {
+    union { s8 lval; double dval; } alias;
+    alias.dval = val;
+    dvmSetFieldLongVolatile(obj, offset, alias.lval);
+}
+INLINE void dvmSetFieldObjectVolatile(Object* obj, int offset, Object* val) {
+    Object** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l;
+    ANDROID_MEMBAR_STORE();
+    *ptr = val;
+    ANDROID_MEMBAR_FULL();
+    if (val != NULL) {
+        dvmWriteBarrierField(obj, ptr);
+    }
+}
+
+/*
+ * Static field access functions.
+ */
+INLINE JValue* dvmStaticFieldPtr(const StaticField* sfield) {
+    return (JValue*)&sfield->value;
+}
+
+INLINE bool dvmGetStaticFieldBoolean(const StaticField* sfield) {
+    return sfield->value.z;
+}
+INLINE s1 dvmGetStaticFieldByte(const StaticField* sfield) {
+    return sfield->value.b;
+}
+INLINE s2 dvmGetStaticFieldShort(const StaticField* sfield) {
+    return sfield->value.s;
+}
+INLINE u2 dvmGetStaticFieldChar(const StaticField* sfield) {
+    return sfield->value.c;
+}
+INLINE s4 dvmGetStaticFieldInt(const StaticField* sfield) {
+    return sfield->value.i;
+}
+INLINE float dvmGetStaticFieldFloat(const StaticField* sfield) {
+    return sfield->value.f;
+}
+INLINE s8 dvmGetStaticFieldLong(const StaticField* sfield) {
+    return sfield->value.j;
+}
+INLINE double dvmGetStaticFieldDouble(const StaticField* sfield) {
+    return sfield->value.d;
+}
+INLINE Object* dvmGetStaticFieldObject(const StaticField* sfield) {
+    return sfield->value.l;
+}
+INLINE bool dvmGetStaticFieldBooleanVolatile(const StaticField* sfield) {
+    const s4* ptr = &(sfield->value.i);
+    return (bool)android_atomic_acquire_load((s4*)ptr);
+}
+INLINE s1 dvmGetStaticFieldByteVolatile(const StaticField* sfield) {
+    const s4* ptr = &(sfield->value.i);
+    return (s1)android_atomic_acquire_load((s4*)ptr);
+}
+INLINE s2 dvmGetStaticFieldShortVolatile(const StaticField* sfield) {
+    const s4* ptr = &(sfield->value.i);
+    return (s2)android_atomic_acquire_load((s4*)ptr);
+}
+INLINE u2 dvmGetStaticFieldCharVolatile(const StaticField* sfield) {
+    const s4* ptr = &(sfield->value.i);
+    return (u2)android_atomic_acquire_load((s4*)ptr);
+}
+INLINE s4 dvmGetStaticFieldIntVolatile(const StaticField* sfield) {
+    const s4* ptr = &(sfield->value.i);
+    return android_atomic_acquire_load((s4*)ptr);
+}
+INLINE float dvmGetStaticFieldFloatVolatile(const StaticField* sfield) {
+    union { s4 ival; float fval; } alias;
+    const s4* ptr = &(sfield->value.i);
+    alias.ival = android_atomic_acquire_load((s4*)ptr);
+    return alias.fval;
+}
+INLINE s8 dvmGetStaticFieldLongVolatile(const StaticField* sfield) {
+    const s8* addr = &sfield->value.j;
+    s8 val = dvmQuasiAtomicRead64(addr);
+    ANDROID_MEMBAR_FULL();
+    return val;
+}
+INLINE double dvmGetStaticFieldDoubleVolatile(const StaticField* sfield) {
+    union { s8 lval; double dval; } alias;
+    const s8* addr = &sfield->value.j;
+    alias.lval = dvmQuasiAtomicRead64(addr);
+    ANDROID_MEMBAR_FULL();
+    return alias.dval;
+}
+INLINE Object* dvmGetStaticFieldObjectVolatile(const StaticField* sfield) {
+    Object* const* ptr = &(sfield->value.l);
+    return (Object*)android_atomic_acquire_load((int32_t*)ptr);
+}
+
+INLINE void dvmSetStaticFieldBoolean(StaticField* sfield, bool val) {
+    sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldByte(StaticField* sfield, s1 val) {
+    sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldShort(StaticField* sfield, s2 val) {
+    sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldChar(StaticField* sfield, u2 val) {
+    sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldInt(StaticField* sfield, s4 val) {
+    sfield->value.i = val;
+}
+INLINE void dvmSetStaticFieldFloat(StaticField* sfield, float val) {
+    sfield->value.f = val;
+}
+INLINE void dvmSetStaticFieldLong(StaticField* sfield, s8 val) {
+    sfield->value.j = val;
+}
+INLINE void dvmSetStaticFieldDouble(StaticField* sfield, double val) {
+    sfield->value.d = val;
+}
+INLINE void dvmSetStaticFieldObject(StaticField* sfield, Object* val) {
+    sfield->value.l = val;
+    if (val != NULL) {
+        dvmWriteBarrierField(sfield->clazz, &sfield->value.l);
+    }
+}
+INLINE void dvmSetStaticFieldIntVolatile(StaticField* sfield, s4 val) {
+    s4* ptr = &sfield->value.i;
+    ANDROID_MEMBAR_STORE();
+    *ptr = val;
+    ANDROID_MEMBAR_FULL();
+}
+INLINE void dvmSetStaticFieldBooleanVolatile(StaticField* sfield, bool val) {
+    dvmSetStaticFieldIntVolatile(sfield, val);
+}
+INLINE void dvmSetStaticFieldByteVolatile(StaticField* sfield, s1 val) {
+    dvmSetStaticFieldIntVolatile(sfield, val);
+}
+INLINE void dvmSetStaticFieldShortVolatile(StaticField* sfield, s2 val) {
+    dvmSetStaticFieldIntVolatile(sfield, val);
+}
+INLINE void dvmSetStaticFieldCharVolatile(StaticField* sfield, u2 val) {
+    dvmSetStaticFieldIntVolatile(sfield, val);
+}
+INLINE void dvmSetStaticFieldFloatVolatile(StaticField* sfield, float val) {
+    union { s4 ival; float fval; } alias;
+    alias.fval = val;
+    dvmSetStaticFieldIntVolatile(sfield, alias.ival);
+}
+INLINE void dvmSetStaticFieldLongVolatile(StaticField* sfield, s8 val) {
+    s8* addr = &sfield->value.j;
+    dvmQuasiAtomicSwap64Sync(val, addr);
+}
+INLINE void dvmSetStaticFieldDoubleVolatile(StaticField* sfield, double val) {
+    union { s8 lval; double dval; } alias;
+    alias.dval = val;
+    dvmSetStaticFieldLongVolatile(sfield, alias.lval);
+}
+INLINE void dvmSetStaticFieldObjectVolatile(StaticField* sfield, Object* val) {
+    Object** ptr = &(sfield->value.l);
+    ANDROID_MEMBAR_STORE();
+    *ptr = val;
+    ANDROID_MEMBAR_FULL();
+    if (val != NULL) {
+        dvmWriteBarrierField(sfield->clazz, &sfield->value.l);
+    }
+}
+
+#endif  // DALVIK_OO_OBJECTINLINES_H_
diff --git a/vm/oo/Resolve.cpp b/vm/oo/Resolve.cpp
new file mode 100644
index 0000000..e1a99ba
--- /dev/null
+++ b/vm/oo/Resolve.cpp
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ */
+
+/*
+ * Resolve classes, methods, fields, and strings.
+ *
+ * According to the VM spec (v2 5.5), classes may be initialized by use
+ * of the "new", "getstatic", "putstatic", or "invokestatic" instructions.
+ * If we are resolving a static method or static field, we make the
+ * initialization check here.
+ *
+ * (NOTE: the verifier has its own resolve functions, which can be invoked
+ * if a class isn't pre-verified.  Those functions must not update the
+ * "resolved stuff" tables for static fields and methods, because they do
+ * not perform initialization.)
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+
+/*
+ * Find the class corresponding to "classIdx", which maps to a class name
+ * string.  It might be in the same DEX file as "referrer", in a different
+ * DEX file, generated by a class loader, or generated by the VM (e.g.
+ * array classes).
+ *
+ * Because the DexTypeId is associated with the referring class' DEX file,
+ * we may have to resolve the same class more than once if it's referred
+ * to from classes in multiple DEX files.  This is a necessary property for
+ * DEX files associated with different class loaders.
+ *
+ * We cache a copy of the lookup in the DexFile's "resolved class" table,
+ * so future references to "classIdx" are faster.
+ *
+ * Note that "referrer" may be in the process of being linked.
+ *
+ * Traditional VMs might do access checks here, but in Dalvik the class
+ * "constant pool" is shared between all classes in the DEX file.  We rely
+ * on the verifier to do the checks for us.
+ *
+ * Does not initialize the class.
+ *
+ * "fromUnverifiedConstant" should only be set if this call is the direct
+ * result of executing a "const-class" or "instance-of" instruction, which
+ * use class constants not resolved by the bytecode verifier.
+ *
+ * Returns NULL with an exception raised on failure.
+ */
+ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx,
+    bool fromUnverifiedConstant)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    ClassObject* resClass;
+    const char* className;
+
+    /*
+     * Check the table first -- this gets called from the other "resolve"
+     * methods.
+     */
+    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
+    if (resClass != NULL)
+        return resClass;
+
+    LOGVV("--- resolving class %u (referrer=%s cl=%p)",
+        classIdx, referrer->descriptor, referrer->classLoader);
+
+    /*
+     * Class hasn't been loaded yet, or is in the process of being loaded
+     * and initialized now.  Try to get a copy.  If we find one, put the
+     * pointer in the DexTypeId.  There isn't a race condition here --
+     * 32-bit writes are guaranteed atomic on all target platforms.  Worst
+     * case we have two threads storing the same value.
+     *
+     * If this is an array class, we'll generate it here.
+     */
+    className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
+    if (className[0] != '\0' && className[1] == '\0') {
+        /* primitive type */
+        resClass = dvmFindPrimitiveClass(className[0]);
+    } else {
+        resClass = dvmFindClassNoInit(className, referrer->classLoader);
+    }
+
+    if (resClass != NULL) {
+        /*
+         * If the referrer was pre-verified, the resolved class must come
+         * from the same DEX or from a bootstrap class.  The pre-verifier
+         * makes assumptions that could be invalidated by a wacky class
+         * loader.  (See the notes at the top of oo/Class.c.)
+         *
+         * The verifier does *not* fail a class for using a const-class
+         * or instance-of instruction referring to an unresolveable class,
+         * because the result of the instruction is simply a Class object
+         * or boolean -- there's no need to resolve the class object during
+         * verification.  Instance field and virtual method accesses can
+         * break dangerously if we get the wrong class, but const-class and
+         * instance-of are only interesting at execution time.  So, if we
+         * we got here as part of executing one of the "unverified class"
+         * instructions, we skip the additional check.
+         *
+         * Ditto for class references from annotations and exception
+         * handler lists.
+         */
+        if (!fromUnverifiedConstant &&
+            IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED))
+        {
+            ClassObject* resClassCheck = resClass;
+            if (dvmIsArrayClass(resClassCheck))
+                resClassCheck = resClassCheck->elementClass;
+
+            if (referrer->pDvmDex != resClassCheck->pDvmDex &&
+                resClassCheck->classLoader != NULL)
+            {
+                LOGW("Class resolved by unexpected DEX:"
+                     " %s(%p):%p ref [%s] %s(%p):%p",
+                    referrer->descriptor, referrer->classLoader,
+                    referrer->pDvmDex,
+                    resClass->descriptor, resClassCheck->descriptor,
+                    resClassCheck->classLoader, resClassCheck->pDvmDex);
+                LOGW("(%s had used a different %s during pre-verification)",
+                    referrer->descriptor, resClass->descriptor);
+                dvmThrowIllegalAccessError(
+                    "Class ref in pre-verified class resolved to unexpected "
+                    "implementation");
+                return NULL;
+            }
+        }
+
+        LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d",
+            resClass->descriptor, referrer->descriptor, referrer->pDvmDex,
+            referrer->classLoader, classIdx);
+
+        /*
+         * Add what we found to the list so we can skip the class search
+         * next time through.
+         *
+         * TODO: should we be doing this when fromUnverifiedConstant==true?
+         * (see comments at top of oo/Class.c)
+         */
+        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
+    } else {
+        /* not found, exception should be raised */
+        LOGVV("Class not found: %s",
+            dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
+        assert(dvmCheckException(dvmThreadSelf()));
+    }
+
+    return resClass;
+}
+
+
+/*
+ * Find the method corresponding to "methodRef".
+ *
+ * We use "referrer" to find the DexFile with the constant pool that
+ * "methodRef" is an index into.  We also use its class loader.  The method
+ * being resolved may very well be in a different DEX file.
+ *
+ * If this is a static method, we ensure that the method's class is
+ * initialized.
+ */
+Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx,
+    MethodType methodType)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    ClassObject* resClass;
+    const DexMethodId* pMethodId;
+    Method* resMethod;
+
+    assert(methodType != METHOD_INTERFACE);
+
+    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
+        referrer->descriptor);
+    pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
+
+    resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
+    if (resClass == NULL) {
+        /* can't find the class that the method is a part of */
+        assert(dvmCheckException(dvmThreadSelf()));
+        return NULL;
+    }
+    if (dvmIsInterfaceClass(resClass)) {
+        /* method is part of an interface */
+        dvmThrowIncompatibleClassChangeErrorWithClassMessage(
+                resClass->descriptor);
+        return NULL;
+    }
+
+    const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
+    DexProto proto;
+    dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
+
+    /*
+     * We need to chase up the class hierarchy to find methods defined
+     * in super-classes.  (We only want to check the current class
+     * if we're looking for a constructor; since DIRECT calls are only
+     * for constructors and private methods, we don't want to walk up.)
+     */
+    if (methodType == METHOD_DIRECT) {
+        resMethod = dvmFindDirectMethod(resClass, name, &proto);
+    } else if (methodType == METHOD_STATIC) {
+        resMethod = dvmFindDirectMethodHier(resClass, name, &proto);
+    } else {
+        resMethod = dvmFindVirtualMethodHier(resClass, name, &proto);
+    }
+
+    if (resMethod == NULL) {
+        dvmThrowNoSuchMethodError(name);
+        return NULL;
+    }
+
+    LOGVV("--- found method %d (%s.%s)",
+        methodIdx, resClass->descriptor, resMethod->name);
+
+    /* see if this is a pure-abstract method */
+    if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
+        dvmThrowAbstractMethodError(name);
+        return NULL;
+    }
+
+    /*
+     * If we're the first to resolve this class, we need to initialize
+     * it now.  Only necessary for METHOD_STATIC.
+     */
+    if (methodType == METHOD_STATIC) {
+        if (!dvmIsClassInitialized(resMethod->clazz) &&
+            !dvmInitClass(resMethod->clazz))
+        {
+            assert(dvmCheckException(dvmThreadSelf()));
+            return NULL;
+        } else {
+            assert(!dvmCheckException(dvmThreadSelf()));
+        }
+    } else {
+        /*
+         * Edge case: if the <clinit> for a class creates an instance
+         * of itself, we will call <init> on a class that is still being
+         * initialized by us.
+         */
+        assert(dvmIsClassInitialized(resMethod->clazz) ||
+               dvmIsClassInitializing(resMethod->clazz));
+    }
+
+    /*
+     * If the class has been initialized, add a pointer to our data structure
+     * so we don't have to jump through the hoops again.  If this is a
+     * static method and the defining class is still initializing (i.e. this
+     * thread is executing <clinit>), don't do the store, otherwise other
+     * threads could call the method without waiting for class init to finish.
+     */
+    if (methodType == METHOD_STATIC && !dvmIsClassInitialized(resMethod->clazz))
+    {
+        LOGVV("--- not caching resolved method %s.%s (class init=%d/%d)",
+            resMethod->clazz->descriptor, resMethod->name,
+            dvmIsClassInitializing(resMethod->clazz),
+            dvmIsClassInitialized(resMethod->clazz));
+    } else {
+        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+    }
+
+    return resMethod;
+}
+
+/*
+ * Resolve an interface method reference.
+ *
+ * Returns NULL with an exception raised on failure.
+ */
+Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    ClassObject* resClass;
+    const DexMethodId* pMethodId;
+    Method* resMethod;
+
+    LOGVV("--- resolving interface method %d (referrer=%s)",
+        methodIdx, referrer->descriptor);
+    pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
+
+    resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
+    if (resClass == NULL) {
+        /* can't find the class that the method is a part of */
+        assert(dvmCheckException(dvmThreadSelf()));
+        return NULL;
+    }
+    if (!dvmIsInterfaceClass(resClass)) {
+        /* whoops */
+        dvmThrowIncompatibleClassChangeErrorWithClassMessage(
+                resClass->descriptor);
+        return NULL;
+    }
+
+    /*
+     * This is the first time the method has been resolved.  Set it in our
+     * resolved-method structure.  It always resolves to the same thing,
+     * so looking it up and storing it doesn't create a race condition.
+     *
+     * If we scan into the interface's superclass -- which is always
+     * java/lang/Object -- we will catch things like:
+     *   interface I ...
+     *   I myobj = (something that implements I)
+     *   myobj.hashCode()
+     * However, the Method->methodIndex will be an offset into clazz->vtable,
+     * rather than an offset into clazz->iftable.  The invoke-interface
+     * code can test to see if the method returned is abstract or concrete,
+     * and use methodIndex accordingly.  I'm not doing this yet because
+     * (a) we waste time in an unusual case, and (b) we're probably going
+     * to fix it in the DEX optimizer.
+     *
+     * We do need to scan the superinterfaces, in case we're invoking a
+     * superinterface method on an interface reference.  The class in the
+     * DexTypeId is for the static type of the object, not the class in
+     * which the method is first defined.  We have the full, flattened
+     * list in "iftable".
+     */
+    const char* methodName =
+        dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
+
+    DexProto proto;
+    dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
+
+    LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
+        methodName, methodSig, resClass->descriptor);
+    resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
+    if (resMethod == NULL) {
+        dvmThrowNoSuchMethodError(methodName);
+        return NULL;
+    }
+
+    LOGVV("--- found interface method %d (%s.%s)",
+        methodIdx, resClass->descriptor, resMethod->name);
+
+    /* we're expecting this to be abstract */
+    assert(dvmIsAbstractMethod(resMethod));
+
+    /* interface methods are always public; no need to check access */
+
+    /*
+     * The interface class *may* be initialized.  According to VM spec
+     * v2 2.17.4, the interfaces a class refers to "need not" be initialized
+     * when the class is initialized.
+     *
+     * It isn't necessary for an interface class to be initialized before
+     * we resolve methods on that interface.
+     *
+     * We choose not to do the initialization now.
+     */
+    //assert(dvmIsClassInitialized(resMethod->clazz));
+
+    /*
+     * Add a pointer to our data structure so we don't have to jump
+     * through the hoops again.
+     *
+     * As noted above, no need to worry about whether the interface that
+     * defines the method has been or is currently executing <clinit>.
+     */
+    dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
+
+    return resMethod;
+}
+
+/*
+ * Resolve an instance field reference.
+ *
+ * Returns NULL and throws an exception on error (no such field, illegal
+ * access).
+ */
+InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    ClassObject* resClass;
+    const DexFieldId* pFieldId;
+    InstField* resField;
+
+    LOGVV("--- resolving field %u (referrer=%s cl=%p)",
+        ifieldIdx, referrer->descriptor, referrer->classLoader);
+
+    pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
+
+    /*
+     * Find the field's class.
+     */
+    resClass = dvmResolveClass(referrer, pFieldId->classIdx, false);
+    if (resClass == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        return NULL;
+    }
+
+    resField = dvmFindInstanceFieldHier(resClass,
+        dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
+        dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
+    if (resField == NULL) {
+        dvmThrowNoSuchFieldError(
+            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+        return NULL;
+    }
+
+    /*
+     * Class must be initialized by now (unless verifier is buggy).  We
+     * could still be in the process of initializing it if the field
+     * access is from a static initializer.
+     */
+    assert(dvmIsClassInitialized(resField->clazz) ||
+           dvmIsClassInitializing(resField->clazz));
+
+    /*
+     * The class is initialized (or initializing), the field has been
+     * found.  Add a pointer to our data structure so we don't have to
+     * jump through the hoops again.
+     *
+     * Anything that uses the resolved table entry must have an instance
+     * of the class, so any class init activity has already happened (or
+     * been deliberately bypassed when <clinit> created an instance).
+     * So it's always okay to update the table.
+     */
+    dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField);
+    LOGVV("    field %u is %s.%s",
+        ifieldIdx, resField->clazz->descriptor, resField->name);
+
+    return resField;
+}
+
+/*
+ * Resolve a static field reference.  The DexFile format doesn't distinguish
+ * between static and instance field references, so the "resolved" pointer
+ * in the Dex struct will have the wrong type.  We trivially cast it here.
+ *
+ * Causes the field's class to be initialized.
+ */
+StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    ClassObject* resClass;
+    const DexFieldId* pFieldId;
+    StaticField* resField;
+
+    pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
+
+    /*
+     * Find the field's class.
+     */
+    resClass = dvmResolveClass(referrer, pFieldId->classIdx, false);
+    if (resClass == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        return NULL;
+    }
+
+    resField = dvmFindStaticFieldHier(resClass,
+                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
+                dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
+    if (resField == NULL) {
+        dvmThrowNoSuchFieldError(
+            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+        return NULL;
+    }
+
+    /*
+     * If we're the first to resolve the field in which this class resides,
+     * we need to do it now.  Note that, if the field was inherited from
+     * a superclass, it is not necessarily the same as "resClass".
+     */
+    if (!dvmIsClassInitialized(resField->clazz) &&
+        !dvmInitClass(resField->clazz))
+    {
+        assert(dvmCheckException(dvmThreadSelf()));
+        return NULL;
+    }
+
+    /*
+     * If the class has been initialized, add a pointer to our data structure
+     * so we don't have to jump through the hoops again.  If it's still
+     * initializing (i.e. this thread is executing <clinit>), don't do
+     * the store, otherwise other threads could use the field without waiting
+     * for class init to finish.
+     */
+    if (dvmIsClassInitialized(resField->clazz)) {
+        dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
+    } else {
+        LOGVV("--- not caching resolved field %s.%s (class init=%d/%d)",
+            resField->clazz->descriptor, resField->name,
+            dvmIsClassInitializing(resField->clazz),
+            dvmIsClassInitialized(resField->clazz));
+    }
+
+    return resField;
+}
+
+
+/*
+ * Resolve a string reference.
+ *
+ * Finding the string is easy.  We need to return a reference to a
+ * java/lang/String object, not a bunch of characters, which means the
+ * first time we get here we need to create an interned string.
+ */
+StringObject* dvmResolveString(const ClassObject* referrer, u4 stringIdx)
+{
+    DvmDex* pDvmDex = referrer->pDvmDex;
+    StringObject* strObj;
+    StringObject* internStrObj;
+    const char* utf8;
+    u4 utf16Size;
+
+    LOGVV("+++ resolving string, referrer is %s", referrer->descriptor);
+
+    /*
+     * Create a UTF-16 version so we can trivially compare it to what's
+     * already interned.
+     */
+    utf8 = dexStringAndSizeById(pDvmDex->pDexFile, stringIdx, &utf16Size);
+    strObj = dvmCreateStringFromCstrAndLength(utf8, utf16Size);
+    if (strObj == NULL) {
+        /* ran out of space in GC heap? */
+        assert(dvmCheckException(dvmThreadSelf()));
+        goto bail;
+    }
+
+    /*
+     * Add it to the intern list.  The return value is the one in the
+     * intern list, which (due to race conditions) may or may not be
+     * the one we just created.  The intern list is synchronized, so
+     * there will be only one "live" version.
+     *
+     * By requesting an immortal interned string, we guarantee that
+     * the returned object will never be collected by the GC.
+     *
+     * A NULL return here indicates some sort of hashing failure.
+     */
+    internStrObj = dvmLookupImmortalInternedString(strObj);
+    dvmReleaseTrackedAlloc((Object*) strObj, NULL);
+    strObj = internStrObj;
+    if (strObj == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        goto bail;
+    }
+
+    /* save a reference so we can go straight to the object next time */
+    dvmDexSetResolvedString(pDvmDex, stringIdx, strObj);
+
+bail:
+    return strObj;
+}
+
+/*
+ * For debugging: return a string representing the methodType.
+ */
+const char* dvmMethodTypeStr(MethodType methodType)
+{
+    switch (methodType) {
+    case METHOD_DIRECT:         return "direct";
+    case METHOD_STATIC:         return "static";
+    case METHOD_VIRTUAL:        return "virtual";
+    case METHOD_INTERFACE:      return "interface";
+    case METHOD_UNKNOWN:        return "UNKNOWN";
+    }
+    assert(false);
+    return "BOGUS";
+}
diff --git a/vm/oo/Resolve.h b/vm/oo/Resolve.h
new file mode 100644
index 0000000..56a35b7
--- /dev/null
+++ b/vm/oo/Resolve.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+/*
+ * Resolve "constant pool" references into pointers to VM structs.
+ */
+#ifndef DALVIK_OO_RESOLVE_H_
+#define DALVIK_OO_RESOLVE_H_
+
+/*
+ * "Direct" and "virtual" methods are stored independently.  The type of call
+ * used to invoke the method determines which list we search, and whether
+ * we travel up into superclasses.
+ *
+ * (<clinit>, <init>, and methods declared "private" or "static" are stored
+ * in the "direct" list.  All others are stored in the "virtual" list.)
+ */
+enum MethodType {
+    METHOD_UNKNOWN  = 0,
+    METHOD_DIRECT,      // <init>, private
+    METHOD_STATIC,      // static
+    METHOD_VIRTUAL,     // virtual, super
+    METHOD_INTERFACE    // interface
+};
+
+/*
+ * Resolve a class, given the referring class and a constant pool index
+ * for the DexTypeId.
+ *
+ * Does not initialize the class.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+extern "C" ClassObject* dvmResolveClass(const ClassObject* referrer,
+                                        u4 classIdx,
+                                        bool fromUnverifiedConstant);
+
+/*
+ * Resolve a direct, static, or virtual method.
+ *
+ * Can cause the method's class to be initialized if methodType is
+ * METHOD_STATIC.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+extern "C" Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx,
+                                    MethodType methodType);
+
+/*
+ * Resolve an interface method.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx);
+
+/*
+ * Resolve an instance field.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+extern "C" InstField* dvmResolveInstField(const ClassObject* referrer,
+                                          u4 ifieldIdx);
+
+/*
+ * Resolve a static field.
+ *
+ * Causes the field's class to be initialized.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+extern "C" StaticField* dvmResolveStaticField(const ClassObject* referrer,
+                                              u4 sfieldIdx);
+
+/*
+ * Resolve a "const-string" reference.
+ *
+ * Throws an exception and returns NULL on failure.
+ */
+extern "C" StringObject* dvmResolveString(const ClassObject* referrer, u4 stringIdx);
+
+/*
+ * Return debug string constant for enum.
+ */
+const char* dvmMethodTypeStr(MethodType methodType);
+
+#endif  // DALVIK_OO_RESOLVE_H_
diff --git a/vm/oo/TypeCheck.cpp b/vm/oo/TypeCheck.cpp
new file mode 100644
index 0000000..1116d15
--- /dev/null
+++ b/vm/oo/TypeCheck.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+/*
+ * instanceof, checkcast, etc.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+/*
+ * I think modern C mandates that the results of a boolean expression are
+ * 0 or 1.  If not, or we suddenly turn into C++ and bool != int, use this.
+ */
+#define BOOL_TO_INT(x)  (x)
+//#define BOOL_TO_INT(x)  ((x) ? 1 : 0)
+
+/*
+ * Number of entries in instanceof cache.  MUST be a power of 2.
+ */
+#define INSTANCEOF_CACHE_SIZE   1024
+
+
+/*
+ * Allocate cache.
+ */
+bool dvmInstanceofStartup()
+{
+    gDvm.instanceofCache = dvmAllocAtomicCache(INSTANCEOF_CACHE_SIZE);
+    if (gDvm.instanceofCache == NULL)
+        return false;
+    return true;
+}
+
+/*
+ * Discard the cache.
+ */
+void dvmInstanceofShutdown()
+{
+    dvmFreeAtomicCache(gDvm.instanceofCache);
+}
+
+
+/*
+ * Determine whether "sub" is an instance of "clazz", where both of these
+ * are array classes.
+ *
+ * Consider an array class, e.g. Y[][], where Y is a subclass of X.
+ *   Y[][] instanceof Y[][]        --> true (identity)
+ *   Y[][] instanceof X[][]        --> true (element superclass)
+ *   Y[][] instanceof Y            --> false
+ *   Y[][] instanceof Y[]          --> false
+ *   Y[][] instanceof Object       --> true (everything is an object)
+ *   Y[][] instanceof Object[]     --> true
+ *   Y[][] instanceof Object[][]   --> true
+ *   Y[][] instanceof Object[][][] --> false (too many []s)
+ *   Y[][] instanceof Serializable     --> true (all arrays are Serializable)
+ *   Y[][] instanceof Serializable[]   --> true
+ *   Y[][] instanceof Serializable[][] --> false (unless Y is Serializable)
+ *
+ * Don't forget about primitive types.
+ *   int[] instanceof Object[]     --> false
+ *
+ * "subElemClass" is sub->elementClass.
+ *
+ * "subDim" is usually just sub->dim, but for some kinds of checks we want
+ * to pass in a non-array class and pretend that it's an array.
+ */
+static int isArrayInstanceOfArray(const ClassObject* subElemClass, int subDim,
+    const ClassObject* clazz)
+{
+    //assert(dvmIsArrayClass(sub));
+    assert(dvmIsArrayClass(clazz));
+
+    /* "If T is an array type TC[]... one of the following must be true:
+     *   TC and SC are the same primitive type.
+     *   TC and SC are reference types and type SC can be cast to TC [...]."
+     *
+     * We need the class objects for the array elements.  For speed we
+     * tucked them into the class object.
+     */
+    assert(subDim > 0 && clazz->arrayDim > 0);
+    if (subDim == clazz->arrayDim) {
+        /*
+         * See if "sub" is an instance of "clazz".  This handles the
+         * interfaces, java.lang.Object, superclassing, etc.
+         */
+        return dvmInstanceof(subElemClass, clazz->elementClass);
+    } else if (subDim > clazz->arrayDim) {
+        /*
+         * The thing we might be an instance of has fewer dimensions.  It
+         * must be an Object or array of Object, or a standard array
+         * interface or array of standard array interfaces (the standard
+         * interfaces being java/lang/Cloneable and java/io/Serializable).
+         */
+        if (dvmIsInterfaceClass(clazz->elementClass)) {
+            /*
+             * See if the class implements its base element.  We know the
+             * base element is an interface; if the array class implements
+             * it, we know it's a standard array interface.
+             */
+            return dvmImplements(clazz, clazz->elementClass);
+        } else {
+            /*
+             * See if this is an array of Object, Object[], etc.  We know
+             * that the superclass of an array is always Object, so we
+             * just compare the element type to that.
+             */
+            return (clazz->elementClass == clazz->super);
+        }
+    } else {
+        /*
+         * Too many []s.
+         */
+        return false;
+    }
+}
+
+/*
+ * Determine whether "sub" is a sub-class of "clazz", where "sub" is an
+ * array class.
+ *
+ * "clazz" could be an array class, interface, or simple class.
+ */
+static int isArrayInstanceOf(const ClassObject* sub, const ClassObject* clazz)
+{
+    assert(dvmIsArrayClass(sub));
+
+    /* "If T is an interface type, T must be one of the interfaces
+     * implemented by arrays."
+     *
+     * I'm not checking that here, because dvmInstanceof tests for
+     * interfaces first, and the generic dvmImplements stuff should
+     * work correctly.
+     */
+    assert(!dvmIsInterfaceClass(clazz));     /* make sure */
+
+    /* "If T is a class type, then T must be Object."
+     *
+     * The superclass of an array is always java.lang.Object, so just
+     * compare against that.
+     */
+    if (!dvmIsArrayClass(clazz))
+        return BOOL_TO_INT(clazz == sub->super);
+
+    /*
+     * If T is an array type TC[] ...
+     */
+    return isArrayInstanceOfArray(sub->elementClass, sub->arrayDim, clazz);
+}
+
+
+/*
+ * Returns 1 (true) if "clazz" is an implementation of "interface".
+ *
+ * "clazz" could be a class or an interface.
+ */
+int dvmImplements(const ClassObject* clazz, const ClassObject* interface)
+{
+    int i;
+
+    assert(dvmIsInterfaceClass(interface));
+
+    /*
+     * All interfaces implemented directly and by our superclass, and
+     * recursively all super-interfaces of those interfaces, are listed
+     * in "iftable", so we can just do a linear scan through that.
+     */
+    for (i = 0; i < clazz->iftableCount; i++) {
+        if (clazz->iftable[i].clazz == interface)
+            return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Determine whether or not we can put an object into an array, based on
+ * the class hierarchy.  The object might itself by an array, which means
+ * we have to pay attention to the array instanceof rules.
+ *
+ * Note that "objectClass" could be an array, but objectClass->elementClass
+ * is always a non-array type.
+ */
+bool dvmCanPutArrayElement(const ClassObject* objectClass,
+    const ClassObject* arrayClass)
+{
+    if (dvmIsArrayClass(objectClass)) {
+        /*
+         * We're stuffing an array into an array.  We want to see if the
+         * elements of "arrayClass" are compatible with "objectClass".
+         * We bump up the number of dimensions in "objectClass" so that we
+         * can compare the two directly.
+         */
+        return isArrayInstanceOfArray(objectClass->elementClass,
+                    objectClass->arrayDim + 1, arrayClass);
+    } else {
+        /*
+         * We're putting a non-array element into an array.  We need to
+         * test to see if the elements are compatible.  The easiest way
+         * to do that is to "arrayify" it and use the standard array
+         * compatibility check.
+         */
+        return isArrayInstanceOfArray(objectClass, 1, arrayClass);
+    }
+}
+
+
+/*
+ * Perform the instanceof calculation.
+ */
+static inline int isInstanceof(const ClassObject* instance,
+    const ClassObject* clazz)
+{
+    if (dvmIsInterfaceClass(clazz)) {
+        return dvmImplements(instance, clazz);
+    } else if (dvmIsArrayClass(instance)) {
+        return isArrayInstanceOf(instance, clazz);
+    } else {
+        return dvmIsSubClass(instance, clazz);
+    }
+}
+
+
+/*
+ * Do the instanceof calculation, pulling the result from the cache if
+ * possible.
+ */
+int dvmInstanceofNonTrivial(const ClassObject* instance,
+    const ClassObject* clazz)
+{
+#define ATOMIC_CACHE_CALC isInstanceof(instance, clazz)
+    return ATOMIC_CACHE_LOOKUP(gDvm.instanceofCache,
+                INSTANCEOF_CACHE_SIZE, instance, clazz);
+#undef ATOMIC_CACHE_CALC
+}
diff --git a/vm/oo/TypeCheck.h b/vm/oo/TypeCheck.h
new file mode 100644
index 0000000..c3f19ea
--- /dev/null
+++ b/vm/oo/TypeCheck.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+/*
+ * instanceof, checkcast, etc.
+ */
+#ifndef DALVIK_OO_TYPECHECK_H_
+#define DALVIK_OO_TYPECHECK_H_
+
+/* VM startup/shutdown */
+bool dvmInstanceofStartup(void);
+void dvmInstanceofShutdown(void);
+
+
+/* used by dvmInstanceof; don't call */
+extern "C" int dvmInstanceofNonTrivial(const ClassObject* instance,
+                                       const ClassObject* clazz);
+
+/*
+ * Determine whether "instance" is an instance of "clazz".
+ *
+ * Returns 0 (false) if not, 1 (true) if so.
+ */
+INLINE int dvmInstanceof(const ClassObject* instance, const ClassObject* clazz)
+{
+    if (instance == clazz) {
+        if (CALC_CACHE_STATS)
+            gDvm.instanceofCache->trivial++;
+        return 1;
+    } else
+        return dvmInstanceofNonTrivial(instance, clazz);
+}
+
+/*
+ * Determine whether a class implements an interface.
+ *
+ * Returns 0 (false) if not, 1 (true) if so.
+ */
+int dvmImplements(const ClassObject* clazz, const ClassObject* interface);
+
+/*
+ * Determine whether "sub" is a sub-class of "clazz".
+ *
+ * Returns 0 (false) if not, 1 (true) if so.
+ */
+INLINE int dvmIsSubClass(const ClassObject* sub, const ClassObject* clazz) {
+    do {
+        /*printf("###### sub='%s' clazz='%s'\n", sub->name, clazz->name);*/
+        if (sub == clazz)
+            return 1;
+        sub = sub->super;
+    } while (sub != NULL);
+
+    return 0;
+}
+
+/*
+ * Determine whether or not we can store an object into an array, based
+ * on the classes of the two.
+ *
+ * Returns 0 (false) if not, 1 (true) if so.
+ */
+extern "C" bool dvmCanPutArrayElement(const ClassObject* elemClass,
+    const ClassObject* arrayClass);
+
+#endif  // DALVIK_OO_TYPECHECK_H_
diff --git a/vm/os/android.cpp b/vm/os/android.cpp
new file mode 100644
index 0000000..561a4e6
--- /dev/null
+++ b/vm/os/android.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 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 "os.h"
+
+#include "Dalvik.h"
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <cutils/sched_policy.h>
+#include <utils/threads.h>
+
+/*
+ * Conversion map for "nice" values.
+ *
+ * We use Android thread priority constants to be consistent with the rest
+ * of the system.  In some cases adjacent entries may overlap.
+ */
+static const int kNiceValues[10] = {
+    ANDROID_PRIORITY_LOWEST,                /* 1 (MIN_PRIORITY) */
+    ANDROID_PRIORITY_BACKGROUND + 6,
+    ANDROID_PRIORITY_BACKGROUND + 3,
+    ANDROID_PRIORITY_BACKGROUND,
+    ANDROID_PRIORITY_NORMAL,                /* 5 (NORM_PRIORITY) */
+    ANDROID_PRIORITY_NORMAL - 2,
+    ANDROID_PRIORITY_NORMAL - 4,
+    ANDROID_PRIORITY_URGENT_DISPLAY + 3,
+    ANDROID_PRIORITY_URGENT_DISPLAY + 2,
+    ANDROID_PRIORITY_URGENT_DISPLAY         /* 10 (MAX_PRIORITY) */
+};
+
+void os_changeThreadPriority(Thread* thread, int newPriority)
+{
+    if (newPriority < 1 || newPriority > 10) {
+        LOGW("bad priority %d", newPriority);
+        newPriority = 5;
+    }
+
+    int newNice = kNiceValues[newPriority-1];
+    pid_t pid = thread->systemTid;
+
+    if (newNice >= ANDROID_PRIORITY_BACKGROUND) {
+        set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
+    } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
+        set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
+    }
+
+    if (setpriority(PRIO_PROCESS, pid, newNice) != 0) {
+        std::string threadName(dvmGetThreadName(thread));
+        LOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s",
+        pid, threadName.c_str(), newPriority, newNice, strerror(errno));
+    } else {
+        LOGV("setPriority(%d) to prio=%d(n=%d)", pid, newPriority, newNice);
+    }
+}
+
+int os_getThreadPriorityFromSystem()
+{
+    errno = 0;
+    int sysprio = getpriority(PRIO_PROCESS, 0);
+    if (sysprio == -1 && errno != 0) {
+        LOGW("getpriority() failed: %s", strerror(errno));
+        return THREAD_NORM_PRIORITY;
+    }
+
+    int jprio = THREAD_MIN_PRIORITY;
+    for (int i = 0; i < NELEM(kNiceValues); i++) {
+        if (sysprio >= kNiceValues[i]) {
+            break;
+        }
+        jprio++;
+    }
+    if (jprio > THREAD_MAX_PRIORITY) {
+        jprio = THREAD_MAX_PRIORITY;
+    }
+    return jprio;
+}
+
+int os_raiseThreadPriority()
+{
+    /* Get the priority (the "nice" value) of the current thread.  The
+     * getpriority() call can legitimately return -1, so we have to
+     * explicitly test errno.
+     */
+    errno = 0;
+    int oldThreadPriority = getpriority(PRIO_PROCESS, 0);
+    if (errno != 0) {
+        LOGI("getpriority(self) failed: %s", strerror(errno));
+    } else if (oldThreadPriority > ANDROID_PRIORITY_NORMAL) {
+        /* Current value is numerically greater than "normal", which
+         * in backward UNIX terms means lower priority.
+         */
+        if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
+            set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
+        }
+        if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
+            LOGI("Unable to elevate priority from %d to %d",
+                    oldThreadPriority, ANDROID_PRIORITY_NORMAL);
+        } else {
+            /*
+             * The priority has been elevated.  Return the old value
+             * so the caller can restore it later.
+             */
+            LOGV("Elevating priority from %d to %d",
+                    oldThreadPriority, ANDROID_PRIORITY_NORMAL);
+            return oldThreadPriority;
+        }
+    }
+    return INT_MAX;
+}
+
+void os_lowerThreadPriority(int oldThreadPriority)
+{
+    if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
+        LOGW("Unable to reset priority to %d: %s",
+                oldThreadPriority, strerror(errno));
+    } else {
+        LOGV("Reset priority to %d", oldThreadPriority);
+    }
+    if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
+        set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
+    }
+}
diff --git a/vm/os/linux.cpp b/vm/os/linux.cpp
new file mode 100644
index 0000000..172cd05
--- /dev/null
+++ b/vm/os/linux.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 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 "os.h"
+
+#include "Dalvik.h"
+
+int os_raiseThreadPriority()
+{
+    return 0;
+}
+
+void os_lowerThreadPriority(int oldThreadPriority)
+{
+    // Do nothing.
+}
+
+void os_changeThreadPriority(Thread* thread, int newPriority)
+{
+    // Do nothing.
+}
+
+int os_getThreadPriorityFromSystem()
+{
+    return THREAD_NORM_PRIORITY;
+}
diff --git a/vm/os/os.h b/vm/os/os.h
new file mode 100644
index 0000000..19e2a61
--- /dev/null
+++ b/vm/os/os.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+struct Thread;
+
+/*
+ * Raises the scheduling priority of the current thread.  Returns the
+ * original priority if successful, or INT_MAX on failure.
+ * Use os_lowerThreadPriority to undo.
+ *
+ * TODO: does the GC really need this?
+ */
+int os_raiseThreadPriority();
+
+/*
+ * Sets the current thread scheduling priority. Used to undo the effects
+ * of an earlier call to os_raiseThreadPriority.
+ *
+ * TODO: does the GC really need this?
+ */
+void os_lowerThreadPriority(int oldThreadPriority);
+
+/*
+ * Changes the priority of a system thread to match that of the Thread object.
+ *
+ * We map a priority value from 1-10 to Linux "nice" values, where lower
+ * numbers indicate higher priority.
+ */
+void os_changeThreadPriority(Thread* thread, int newPriority);
+
+/*
+ * Returns the thread priority for the current thread by querying the system.
+ * This is useful when attaching a thread through JNI.
+ *
+ * Returns a value from 1 to 10 (compatible with java.lang.Thread values).
+ */
+int os_getThreadPriorityFromSystem();
diff --git a/vm/reflect/Annotation.cpp b/vm/reflect/Annotation.cpp
new file mode 100644
index 0000000..aa1b4e6
--- /dev/null
+++ b/vm/reflect/Annotation.cpp
@@ -0,0 +1,2266 @@
+/*
+ * 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.
+ */
+/*
+ * Annotations.
+ *
+ * We're not expecting to make much use of runtime annotations, so speed vs.
+ * space choices are weighted heavily toward small size.
+ *
+ * It would have been nice to treat "system" annotations in the same way
+ * we do "real" annotations, but that doesn't work.  The chief difficulty
+ * is that some of them have member types that are not legal in annotations,
+ * such as Method and Annotation.  Another source of pain comes from the
+ * AnnotationDefault annotation, which by virtue of being an annotation
+ * could itself have default values, requiring some additional checks to
+ * prevent recursion.
+ *
+ * It's simpler, and more efficient, to handle the system annotations
+ * entirely inside the VM.  There are empty classes defined for the system
+ * annotation types, but their only purpose is to allow the system
+ * annotations to share name space with standard annotations.
+ */
+#include "Dalvik.h"
+
+// fwd
+static Object* processEncodedAnnotation(const ClassObject* clazz,\
+    const u1** pPtr);
+static bool skipEncodedAnnotation(const ClassObject* clazz, const u1** pPtr);
+
+/*
+ * System annotation descriptors.
+ */
+static const char* kDescrAnnotationDefault
+                                    = "Ldalvik/annotation/AnnotationDefault;";
+static const char* kDescrEnclosingClass
+                                    = "Ldalvik/annotation/EnclosingClass;";
+static const char* kDescrEnclosingMethod
+                                    = "Ldalvik/annotation/EnclosingMethod;";
+static const char* kDescrInnerClass = "Ldalvik/annotation/InnerClass;";
+static const char* kDescrMemberClasses
+                                    = "Ldalvik/annotation/MemberClasses;";
+static const char* kDescrSignature  = "Ldalvik/annotation/Signature;";
+static const char* kDescrThrows     = "Ldalvik/annotation/Throws;";
+
+/*
+ * Read an unsigned LEB128 value from a buffer.  Advances "pBuf".
+ */
+static u4 readUleb128(const u1** pBuf)
+{
+    u4 result = 0;
+    int shift = 0;
+    const u1* buf = *pBuf;
+    u1 val;
+
+    do {
+        /*
+         * Worst-case on bad data is we read too much data and return a bogus
+         * result.  Safe to assume that we will encounter a byte with its
+         * high bit clear before the end of the mapped file.
+         */
+        assert(shift < 32);
+
+        val = *buf++;
+        result |= (val & 0x7f) << shift;
+        shift += 7;
+    } while ((val & 0x80) != 0);
+
+    *pBuf = buf;
+    return result;
+}
+
+/*
+ * Get the annotations directory item.
+ */
+static const DexAnnotationsDirectoryItem* getAnnoDirectory(DexFile* pDexFile,
+    const ClassObject* clazz)
+{
+    const DexClassDef* pClassDef;
+
+    /*
+     * Find the class def in the DEX file.  For better performance we should
+     * stash this in the ClassObject.
+     */
+    pClassDef = dexFindClass(pDexFile, clazz->descriptor);
+    assert(pClassDef != NULL);
+    return dexGetAnnotationsDirectoryItem(pDexFile, pClassDef);
+}
+
+/*
+ * Return a zero-length array of Annotation objects.
+ *
+ * TODO: this currently allocates a new array each time, but I think we
+ * can get away with returning a canonical copy.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+static ArrayObject* emptyAnnoArray()
+{
+    return dvmAllocArrayByClass(
+        gDvm.classJavaLangAnnotationAnnotationArray, 0, ALLOC_DEFAULT);
+}
+
+/*
+ * Return an array of empty arrays of Annotation objects.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+static ArrayObject* emptyAnnoArrayArray(int numElements)
+{
+    Thread* self = dvmThreadSelf();
+    ArrayObject* arr;
+    int i;
+
+    arr = dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArrayArray,
+            numElements, ALLOC_DEFAULT);
+    if (arr != NULL) {
+        ArrayObject** elems = (ArrayObject**)(void*)arr->contents;
+        for (i = 0; i < numElements; i++) {
+            elems[i] = emptyAnnoArray();
+            dvmReleaseTrackedAlloc((Object*)elems[i], self);
+        }
+    }
+
+    return arr;
+}
+
+/*
+ * Read a signed integer.  "zwidth" is the zero-based byte count.
+ */
+static s4 readSignedInt(const u1* ptr, int zwidth)
+{
+    s4 val = 0;
+    int i;
+
+    for (i = zwidth; i >= 0; --i)
+        val = ((u4)val >> 8) | (((s4)*ptr++) << 24);
+    val >>= (3 - zwidth) * 8;
+
+    return val;
+}
+
+/*
+ * Read an unsigned integer.  "zwidth" is the zero-based byte count,
+ * "fillOnRight" indicates which side we want to zero-fill from.
+ */
+static u4 readUnsignedInt(const u1* ptr, int zwidth, bool fillOnRight)
+{
+    u4 val = 0;
+    int i;
+
+    if (!fillOnRight) {
+        for (i = zwidth; i >= 0; --i)
+            val = (val >> 8) | (((u4)*ptr++) << 24);
+        val >>= (3 - zwidth) * 8;
+    } else {
+        for (i = zwidth; i >= 0; --i)
+            val = (val >> 8) | (((u4)*ptr++) << 24);
+    }
+    return val;
+}
+
+/*
+ * Read a signed long.  "zwidth" is the zero-based byte count.
+ */
+static s8 readSignedLong(const u1* ptr, int zwidth)
+{
+    s8 val = 0;
+    int i;
+
+    for (i = zwidth; i >= 0; --i)
+        val = ((u8)val >> 8) | (((s8)*ptr++) << 56);
+    val >>= (7 - zwidth) * 8;
+
+    return val;
+}
+
+/*
+ * Read an unsigned long.  "zwidth" is the zero-based byte count,
+ * "fillOnRight" indicates which side we want to zero-fill from.
+ */
+static u8 readUnsignedLong(const u1* ptr, int zwidth, bool fillOnRight)
+{
+    u8 val = 0;
+    int i;
+
+    if (!fillOnRight) {
+        for (i = zwidth; i >= 0; --i)
+            val = (val >> 8) | (((u8)*ptr++) << 56);
+        val >>= (7 - zwidth) * 8;
+    } else {
+        for (i = zwidth; i >= 0; --i)
+            val = (val >> 8) | (((u8)*ptr++) << 56);
+    }
+    return val;
+}
+
+
+/*
+ * ===========================================================================
+ *      Element extraction
+ * ===========================================================================
+ */
+
+/*
+ * An annotation in "clazz" refers to a method by index.  This just gives
+ * us the name of the class and the name and signature of the method.  We
+ * need to find the method's class, and then find the method within that
+ * class.  If the method has been resolved before, we can just use the
+ * results of the previous lookup.
+ *
+ * Normally we do this as part of method invocation in the interpreter, which
+ * provides us with a bit of context: is it virtual or direct, do we need
+ * to initialize the class because it's a static method, etc.  We don't have
+ * that information here, so we have to do a bit of searching.
+ *
+ * Returns NULL if the method was not found (exception may be pending).
+ */
+static Method* resolveAmbiguousMethod(const ClassObject* referrer, u4 methodIdx)
+{
+    DexFile* pDexFile;
+    ClassObject* resClass;
+    Method* resMethod;
+    const DexMethodId* pMethodId;
+    const char* name;
+
+    /* if we've already resolved this method, return it */
+    resMethod = dvmDexGetResolvedMethod(referrer->pDvmDex, methodIdx);
+    if (resMethod != NULL)
+        return resMethod;
+
+    pDexFile = referrer->pDvmDex->pDexFile;
+    pMethodId = dexGetMethodId(pDexFile, methodIdx);
+    resClass = dvmResolveClass(referrer, pMethodId->classIdx, true);
+    if (resClass == NULL) {
+        /* note exception will be pending */
+        LOGD("resolveAmbiguousMethod: unable to find class %d", methodIdx);
+        return NULL;
+    }
+    if (dvmIsInterfaceClass(resClass)) {
+        /* method is part of an interface -- not expecting that */
+        LOGD("resolveAmbiguousMethod: method in interface?");
+        return NULL;
+    }
+
+    // TODO - consider a method access flag that indicates direct vs. virtual
+    name = dexStringById(pDexFile, pMethodId->nameIdx);
+
+    DexProto proto;
+    dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
+
+    if (name[0] == '<') {
+        /*
+         * Constructor or class initializer.  Only need to examine the
+         * "direct" list, and don't need to look up the class hierarchy.
+         */
+        resMethod = dvmFindDirectMethod(resClass, name, &proto);
+    } else {
+        /*
+         * Do a hierarchical scan for direct and virtual methods.
+         *
+         * This uses the search order from the VM spec (v2 5.4.3.3), which
+         * seems appropriate here.
+         */
+        resMethod = dvmFindMethodHier(resClass, name, &proto);
+    }
+
+    return resMethod;
+}
+
+/*
+ * constants for processAnnotationValue indicating what style of
+ * result is wanted
+ */
+enum AnnotationResultStyle {
+    kAllObjects,         /* return everything as an object */
+    kAllRaw,             /* return everything as a raw value or index */
+    kPrimitivesOrObjects /* return primitives as-is but the rest as objects */
+};
+
+/*
+ * Recursively process an annotation value.
+ *
+ * "clazz" is the class on which the annotations are defined.  It may be
+ * NULL when "resultStyle" is "kAllRaw".
+ *
+ * If "resultStyle" is "kAllObjects", the result will always be an Object of an
+ * appropriate type (in pValue->value.l).  For primitive types, the usual
+ * wrapper objects will be created.
+ *
+ * If "resultStyle" is "kAllRaw", numeric constants are stored directly into
+ * "pValue", and indexed values like String and Method are returned as
+ * indexes.  Complex values like annotations and arrays are not handled.
+ *
+ * If "resultStyle" is "kPrimitivesOrObjects", numeric constants are stored
+ * directly into "pValue", and everything else is constructed as an Object
+ * of appropriate type (in pValue->value.l).
+ *
+ * The caller must call dvmReleaseTrackedAlloc on returned objects, when
+ * using "kAllObjects" or "kPrimitivesOrObjects".
+ *
+ * Returns "true" on success, "false" if the value could not be processed
+ * or an object could not be allocated.  On allocation failure an exception
+ * will be raised.
+ */
+static bool processAnnotationValue(const ClassObject* clazz,
+    const u1** pPtr, AnnotationValue* pValue,
+    AnnotationResultStyle resultStyle)
+{
+    Thread* self = dvmThreadSelf();
+    Object* elemObj = NULL;
+    bool setObject = false;
+    const u1* ptr = *pPtr;
+    u1 valueType, valueArg;
+    int width;
+    u4 idx;
+
+    valueType = *ptr++;
+    valueArg = valueType >> kDexAnnotationValueArgShift;
+    width = valueArg + 1;       /* assume, correct later */
+
+    LOGV("----- type is 0x%02x %d, ptr=%p [0x%06x]",
+        valueType & kDexAnnotationValueTypeMask, valueArg, ptr-1,
+        (ptr-1) - (u1*)clazz->pDvmDex->pDexFile->baseAddr);
+
+    pValue->type = valueType & kDexAnnotationValueTypeMask;
+
+    switch (valueType & kDexAnnotationValueTypeMask) {
+    case kDexAnnotationByte:
+        pValue->value.i = (s1) readSignedInt(ptr, valueArg);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('B'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationShort:
+        pValue->value.i = (s2) readSignedInt(ptr, valueArg);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('S'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationChar:
+        pValue->value.i = (u2) readUnsignedInt(ptr, valueArg, false);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('C'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationInt:
+        pValue->value.i = readSignedInt(ptr, valueArg);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('I'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationLong:
+        pValue->value.j = readSignedLong(ptr, valueArg);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('J'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationFloat:
+        pValue->value.i = readUnsignedInt(ptr, valueArg, true);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('F'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationDouble:
+        pValue->value.j = readUnsignedLong(ptr, valueArg, true);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('D'));
+            setObject = true;
+        }
+        break;
+    case kDexAnnotationBoolean:
+        pValue->value.i = (valueArg != 0);
+        if (resultStyle == kAllObjects) {
+            elemObj = (Object*) dvmBoxPrimitive(pValue->value,
+                        dvmFindPrimitiveClass('Z'));
+            setObject = true;
+        }
+        width = 0;
+        break;
+
+    case kDexAnnotationString:
+        idx = readUnsignedInt(ptr, valueArg, false);
+        if (resultStyle == kAllRaw) {
+            pValue->value.i = idx;
+        } else {
+            elemObj = (Object*) dvmResolveString(clazz, idx);
+            setObject = true;
+            if (elemObj == NULL)
+                return false;
+            dvmAddTrackedAlloc(elemObj, self);      // balance the Release
+        }
+        break;
+    case kDexAnnotationType:
+        idx = readUnsignedInt(ptr, valueArg, false);
+        if (resultStyle == kAllRaw) {
+            pValue->value.i = idx;
+        } else {
+            elemObj = (Object*) dvmResolveClass(clazz, idx, true);
+            setObject = true;
+            if (elemObj == NULL) {
+                /* we're expected to throw a TypeNotPresentException here */
+                DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+                const char* desc = dexStringByTypeIdx(pDexFile, idx);
+                dvmClearException(self);
+                dvmThrowTypeNotPresentException(desc);
+                return false;
+            } else {
+                dvmAddTrackedAlloc(elemObj, self);      // balance the Release
+            }
+        }
+        break;
+    case kDexAnnotationMethod:
+        idx = readUnsignedInt(ptr, valueArg, false);
+        if (resultStyle == kAllRaw) {
+            pValue->value.i = idx;
+        } else {
+            Method* meth = resolveAmbiguousMethod(clazz, idx);
+            if (meth == NULL)
+                return false;
+            elemObj = dvmCreateReflectObjForMethod(clazz, meth);
+            setObject = true;
+            if (elemObj == NULL)
+                return false;
+        }
+        break;
+    case kDexAnnotationField:
+        idx = readUnsignedInt(ptr, valueArg, false);
+        assert(false);      // TODO
+        break;
+    case kDexAnnotationEnum:
+        /* enum values are the contents of a static field */
+        idx = readUnsignedInt(ptr, valueArg, false);
+        if (resultStyle == kAllRaw) {
+            pValue->value.i = idx;
+        } else {
+            StaticField* sfield;
+
+            sfield = dvmResolveStaticField(clazz, idx);
+            if (sfield == NULL) {
+                return false;
+            } else {
+                assert(sfield->clazz->descriptor[0] == 'L');
+                elemObj = sfield->value.l;
+                setObject = true;
+                dvmAddTrackedAlloc(elemObj, self);      // balance the Release
+            }
+        }
+        break;
+    case kDexAnnotationArray:
+        /*
+         * encoded_array format, which is a size followed by a stream
+         * of annotation_value.
+         *
+         * We create an array of Object, populate it, and return it.
+         */
+        if (resultStyle == kAllRaw) {
+            return false;
+        } else {
+            ArrayObject* newArray;
+            u4 size, count;
+
+            size = readUleb128(&ptr);
+            LOGVV("--- annotation array, size is %u at %p", size, ptr);
+            newArray = dvmAllocArrayByClass(gDvm.classJavaLangObjectArray,
+                size, ALLOC_DEFAULT);
+            if (newArray == NULL) {
+                LOGE("annotation element array alloc failed (%d)", size);
+                return false;
+            }
+
+            AnnotationValue avalue;
+            for (count = 0; count < size; count++) {
+                if (!processAnnotationValue(clazz, &ptr, &avalue,
+                                kAllObjects)) {
+                    dvmReleaseTrackedAlloc((Object*)newArray, self);
+                    return false;
+                }
+                Object* obj = (Object*)avalue.value.l;
+                dvmSetObjectArrayElement(newArray, count, obj);
+                dvmReleaseTrackedAlloc(obj, self);
+            }
+
+            elemObj = (Object*) newArray;
+            setObject = true;
+        }
+        width = 0;
+        break;
+    case kDexAnnotationAnnotation:
+        /* encoded_annotation format */
+        if (resultStyle == kAllRaw)
+            return false;
+        elemObj = processEncodedAnnotation(clazz, &ptr);
+        setObject = true;
+        if (elemObj == NULL)
+            return false;
+        dvmAddTrackedAlloc(elemObj, self);      // balance the Release
+        width = 0;
+        break;
+    case kDexAnnotationNull:
+        if (resultStyle == kAllRaw) {
+            pValue->value.i = 0;
+        } else {
+            assert(elemObj == NULL);
+            setObject = true;
+        }
+        width = 0;
+        break;
+    default:
+        LOGE("Bad annotation element value byte 0x%02x (0x%02x)",
+            valueType, valueType & kDexAnnotationValueTypeMask);
+        assert(false);
+        return false;
+    }
+
+    ptr += width;
+
+    *pPtr = ptr;
+    if (setObject)
+        pValue->value.l = elemObj;
+    return true;
+}
+
+
+/*
+ * For most object types, we have nothing to do here, and we just return
+ * "valueObj".
+ *
+ * For an array annotation, the type of the extracted object will always
+ * be java.lang.Object[], but we want it to match the type that the
+ * annotation member is expected to return.  In some cases this may
+ * involve un-boxing primitive values.
+ *
+ * We allocate a second array with the correct type, then copy the data
+ * over.  This releases the tracked allocation on "valueObj" and returns
+ * a new, tracked object.
+ *
+ * On failure, this releases the tracking on "valueObj" and returns NULL
+ * (allowing the call to say "foo = convertReturnType(foo, ..)").
+ */
+static Object* convertReturnType(Object* valueObj, ClassObject* methodReturn)
+{
+    if (valueObj == NULL ||
+        !dvmIsArray((ArrayObject*)valueObj) || !dvmIsArrayClass(methodReturn))
+    {
+        return valueObj;
+    }
+
+    Thread* self = dvmThreadSelf();
+    ClassObject* srcElemClass;
+    ClassObject* dstElemClass;
+
+    /*
+     * We always extract kDexAnnotationArray into Object[], so we expect to
+     * find that here.  This means we can skip the FindClass on
+     * (valueObj->clazz->descriptor+1, valueObj->clazz->classLoader).
+     */
+    if (strcmp(valueObj->clazz->descriptor, "[Ljava/lang/Object;") != 0) {
+        LOGE("Unexpected src type class (%s)", valueObj->clazz->descriptor);
+        return NULL;
+    }
+    srcElemClass = gDvm.classJavaLangObject;
+
+    /*
+     * Skip past the '[' to get element class name.  Note this is not always
+     * the same as methodReturn->elementClass.
+     */
+    char firstChar = methodReturn->descriptor[1];
+    if (firstChar == 'L' || firstChar == '[') {
+        dstElemClass = dvmFindClass(methodReturn->descriptor+1,
+            methodReturn->classLoader);
+    } else {
+        dstElemClass = dvmFindPrimitiveClass(firstChar);
+    }
+    LOGV("HEY: converting valueObj from [%s to [%s",
+        srcElemClass->descriptor, dstElemClass->descriptor);
+
+    ArrayObject* srcArray = (ArrayObject*) valueObj;
+    u4 length = srcArray->length;
+    ArrayObject* newArray;
+
+    newArray = dvmAllocArrayByClass(methodReturn, length, ALLOC_DEFAULT);
+    if (newArray == NULL) {
+        LOGE("Failed creating duplicate annotation class (%s %d)",
+            methodReturn->descriptor, length);
+        goto bail;
+    }
+
+    bool success;
+    if (dstElemClass->primitiveType == PRIM_NOT) {
+        success = dvmCopyObjectArray(newArray, srcArray, dstElemClass);
+    } else {
+        success = dvmUnboxObjectArray(newArray, srcArray, dstElemClass);
+    }
+    if (!success) {
+        LOGE("Annotation array copy failed");
+        dvmReleaseTrackedAlloc((Object*)newArray, self);
+        newArray = NULL;
+        goto bail;
+    }
+
+bail:
+    /* replace old, return new */
+    dvmReleaseTrackedAlloc(valueObj, self);
+    return (Object*) newArray;
+}
+
+/*
+ * Create a new AnnotationMember.
+ *
+ * "clazz" is the class on which the annotations are defined.  "pPtr"
+ * points to a pointer into the annotation data.  "annoClass" is the
+ * annotation's class.
+ *
+ * We extract the annotation's value, create a new AnnotationMember object,
+ * and construct it.
+ *
+ * Returns NULL on failure; an exception may or may not be raised.
+ */
+static Object* createAnnotationMember(const ClassObject* clazz,
+    const ClassObject* annoClass, const u1** pPtr)
+{
+    Thread* self = dvmThreadSelf();
+    const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    StringObject* nameObj = NULL;
+    Object* valueObj = NULL;
+    Object* newMember = NULL;
+    Object* methodObj = NULL;
+    ClassObject* methodReturn = NULL;
+    u4 elementNameIdx;
+    const char* name;
+    AnnotationValue avalue;
+    JValue unused;
+    bool failed = true;
+
+    elementNameIdx = readUleb128(pPtr);
+
+    if (!processAnnotationValue(clazz, pPtr, &avalue, kAllObjects)) {
+        LOGW("Failed processing annotation value");
+        goto bail;
+    }
+    valueObj = (Object*)avalue.value.l;
+
+    /* new member to hold the element */
+    newMember =
+        dvmAllocObject(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember,
+        ALLOC_DEFAULT);
+    name = dexStringById(pDexFile, elementNameIdx);
+    nameObj = dvmCreateStringFromCstr(name);
+
+    /* find the method in the annotation class, given only the name */
+    if (name != NULL) {
+        Method* annoMeth = dvmFindVirtualMethodByName(annoClass, name);
+        if (annoMeth == NULL) {
+            LOGW("WARNING: could not find annotation member %s in %s",
+                name, annoClass->descriptor);
+        } else {
+            methodObj = dvmCreateReflectMethodObject(annoMeth);
+            methodReturn = dvmGetBoxedReturnType(annoMeth);
+        }
+    }
+    if (newMember == NULL || nameObj == NULL || methodObj == NULL ||
+        methodReturn == NULL)
+    {
+        LOGE("Failed creating annotation element (m=%p n=%p a=%p r=%p)",
+            newMember, nameObj, methodObj, methodReturn);
+        goto bail;
+    }
+
+    /* convert the return type, if necessary */
+    valueObj = convertReturnType(valueObj, methodReturn);
+    if (valueObj == NULL)
+        goto bail;
+
+    /* call 4-argument constructor */
+    dvmCallMethod(self, gDvm.methOrgApacheHarmonyLangAnnotationAnnotationMember_init,
+        newMember, &unused, nameObj, valueObj, methodReturn, methodObj);
+    if (dvmCheckException(self)) {
+        LOGD("Failed constructing annotation element");
+        goto bail;
+    }
+
+    failed = false;
+
+bail:
+    /* release tracked allocations */
+    dvmReleaseTrackedAlloc(newMember, self);
+    dvmReleaseTrackedAlloc((Object*)nameObj, self);
+    dvmReleaseTrackedAlloc(valueObj, self);
+    dvmReleaseTrackedAlloc(methodObj, self);
+    if (failed)
+        return NULL;
+    else
+        return newMember;
+}
+
+/*
+ * Create a new Annotation object from what we find in the annotation item.
+ *
+ * "clazz" is the class on which the annotations are defined.  "pPtr"
+ * points to a pointer into the annotation data.
+ *
+ * We use the AnnotationFactory class to create the annotation for us.  The
+ * method we call is:
+ *
+ *  public static Annotation createAnnotation(
+ *      Class<? extends Annotation> annotationType,
+ *      AnnotationMember[] elements)
+ *
+ * Returns a new Annotation, which will NOT be in the local ref table and
+ * not referenced elsewhere, so store it away soon.  On failure, returns NULL
+ * with an exception raised.
+ */
+static Object* processEncodedAnnotation(const ClassObject* clazz,
+    const u1** pPtr)
+{
+    Thread* self = dvmThreadSelf();
+    Object* newAnno = NULL;
+    ArrayObject* elementArray = NULL;
+    const ClassObject* annoClass;
+    const u1* ptr;
+    u4 typeIdx, size, count;
+
+    ptr = *pPtr;
+    typeIdx = readUleb128(&ptr);
+    size = readUleb128(&ptr);
+
+    LOGVV("----- processEnc ptr=%p type=%d size=%d", ptr, typeIdx, size);
+
+    annoClass = dvmDexGetResolvedClass(clazz->pDvmDex, typeIdx);
+    if (annoClass == NULL) {
+        annoClass = dvmResolveClass(clazz, typeIdx, true);
+        if (annoClass == NULL) {
+            LOGE("Unable to resolve %s annotation class %d",
+                clazz->descriptor, typeIdx);
+            assert(dvmCheckException(self));
+            return NULL;
+        }
+    }
+
+    LOGV("----- processEnc ptr=%p [0x%06x]  typeIdx=%d size=%d class=%s",
+        *pPtr, *pPtr - (u1*) clazz->pDvmDex->pDexFile->baseAddr,
+        typeIdx, size, annoClass->descriptor);
+
+    /*
+     * Elements are parsed out and stored in an array.  The Harmony
+     * constructor wants an array with just the declared elements --
+     * default values get merged in later.
+     */
+    JValue result;
+
+    if (size > 0) {
+        elementArray = dvmAllocArrayByClass(
+            gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray,
+            size, ALLOC_DEFAULT);
+        if (elementArray == NULL) {
+            LOGE("failed to allocate annotation member array (%d elements)",
+                size);
+            goto bail;
+        }
+    }
+
+    /*
+     * "ptr" points to a byte stream with "size" occurrences of
+     * annotation_element.
+     */
+    for (count = 0; count < size; count++) {
+        Object* newMember = createAnnotationMember(clazz, annoClass, &ptr);
+        if (newMember == NULL)
+            goto bail;
+
+        /* add it to the array */
+        dvmSetObjectArrayElement(elementArray, count, newMember);
+    }
+
+    dvmCallMethod(self,
+        gDvm.methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation,
+        NULL, &result, annoClass, elementArray);
+    if (dvmCheckException(self)) {
+        LOGD("Failed creating an annotation");
+        //dvmLogExceptionStackTrace();
+        goto bail;
+    }
+
+    newAnno = (Object*)result.l;
+
+bail:
+    dvmReleaseTrackedAlloc((Object*) elementArray, NULL);
+    *pPtr = ptr;
+    if (newAnno == NULL && !dvmCheckException(self)) {
+        /* make sure an exception is raised */
+        dvmThrowRuntimeException("failure in processEncodedAnnotation");
+    }
+    return newAnno;
+}
+
+/*
+ * Run through an annotation set and convert each entry into an Annotation
+ * object.
+ *
+ * Returns an array of Annotation objects, or NULL with an exception raised
+ * on alloc failure.
+ */
+static ArrayObject* processAnnotationSet(const ClassObject* clazz,
+    const DexAnnotationSetItem* pAnnoSet, int visibility)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexAnnotationItem* pAnnoItem;
+    ArrayObject* annoArray;
+    int i, count;
+    u4 dstIndex;
+
+    /* we need these later; make sure they're initialized */
+    if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory))
+        dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory);
+    if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember))
+        dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember);
+
+    /* count up the number of visible elements */
+    for (i = count = 0; i < (int) pAnnoSet->size; i++) {
+        pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
+        if (pAnnoItem->visibility == visibility)
+            count++;
+    }
+
+    annoArray =
+        dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
+                             count, ALLOC_DEFAULT);
+    if (annoArray == NULL)
+        return NULL;
+
+    /*
+     * Generate Annotation objects.  We must put them into the array
+     * immediately (or add them to the tracked ref table).
+     */
+    dstIndex = 0;
+    for (i = 0; i < (int) pAnnoSet->size; i++) {
+        pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
+        if (pAnnoItem->visibility != visibility)
+            continue;
+        const u1* ptr = pAnnoItem->annotation;
+        Object *anno = processEncodedAnnotation(clazz, &ptr);
+        if (anno == NULL) {
+            dvmReleaseTrackedAlloc((Object*) annoArray, NULL);
+            return NULL;
+        }
+        dvmSetObjectArrayElement(annoArray, dstIndex, anno);
+        ++dstIndex;
+    }
+
+    return annoArray;
+}
+
+/*
+ * Return the annotation item of the specified type in the annotation set, or
+ * NULL if the set contains no annotation of that type.
+ */
+static const DexAnnotationItem* getAnnotationItemFromAnnotationSet(
+        const ClassObject* clazz, const DexAnnotationSetItem* pAnnoSet,
+        int visibility, const ClassObject* annotationClazz)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexAnnotationItem* pAnnoItem;
+    int i;
+    const ClassObject* annoClass;
+    const u1* ptr;
+    u4 typeIdx;
+
+    /* we need these later; make sure they're initialized */
+    if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory))
+        dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory);
+    if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember))
+        dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember);
+
+    for (i = 0; i < (int) pAnnoSet->size; i++) {
+        pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
+        if (pAnnoItem->visibility != visibility)
+            continue;
+
+        ptr = pAnnoItem->annotation;
+        typeIdx = readUleb128(&ptr);
+
+        annoClass = dvmDexGetResolvedClass(clazz->pDvmDex, typeIdx);
+        if (annoClass == NULL) {
+            annoClass = dvmResolveClass(clazz, typeIdx, true);
+            if (annoClass == NULL) {
+                return NULL; // an exception is pending
+            }
+        }
+
+        if (annoClass == annotationClazz) {
+            return pAnnoItem;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Return the Annotation object of the specified type in the annotation set, or
+ * NULL if the set contains no annotation of that type.
+ */
+static Object* getAnnotationObjectFromAnnotationSet(const ClassObject* clazz,
+        const DexAnnotationSetItem* pAnnoSet, int visibility,
+        const ClassObject* annotationClazz)
+{
+    const DexAnnotationItem* pAnnoItem = getAnnotationItemFromAnnotationSet(
+            clazz, pAnnoSet, visibility, annotationClazz);
+    if (pAnnoItem == NULL) {
+        return NULL;
+    }
+    const u1* ptr = pAnnoItem->annotation;
+    return processEncodedAnnotation(clazz, &ptr);
+}
+
+/*
+ * ===========================================================================
+ *      Skipping and scanning
+ * ===========================================================================
+ */
+
+/*
+ * Skip past an annotation value.
+ *
+ * "clazz" is the class on which the annotations are defined.
+ *
+ * Returns "true" on success, "false" on parsing failure.
+ */
+static bool skipAnnotationValue(const ClassObject* clazz, const u1** pPtr)
+{
+    const u1* ptr = *pPtr;
+    u1 valueType, valueArg;
+    int width;
+
+    valueType = *ptr++;
+    valueArg = valueType >> kDexAnnotationValueArgShift;
+    width = valueArg + 1;       /* assume */
+
+    LOGV("----- type is 0x%02x %d, ptr=%p [0x%06x]",
+        valueType & kDexAnnotationValueTypeMask, valueArg, ptr-1,
+        (ptr-1) - (u1*)clazz->pDvmDex->pDexFile->baseAddr);
+
+    switch (valueType & kDexAnnotationValueTypeMask) {
+    case kDexAnnotationByte:        break;
+    case kDexAnnotationShort:       break;
+    case kDexAnnotationChar:        break;
+    case kDexAnnotationInt:         break;
+    case kDexAnnotationLong:        break;
+    case kDexAnnotationFloat:       break;
+    case kDexAnnotationDouble:      break;
+    case kDexAnnotationString:      break;
+    case kDexAnnotationType:        break;
+    case kDexAnnotationMethod:      break;
+    case kDexAnnotationField:       break;
+    case kDexAnnotationEnum:        break;
+
+    case kDexAnnotationArray:
+        /* encoded_array format */
+        {
+            u4 size = readUleb128(&ptr);
+            while (size--) {
+                if (!skipAnnotationValue(clazz, &ptr))
+                    return false;
+            }
+        }
+        width = 0;
+        break;
+    case kDexAnnotationAnnotation:
+        /* encoded_annotation format */
+        if (!skipEncodedAnnotation(clazz, &ptr))
+            return false;
+        width = 0;
+        break;
+    case kDexAnnotationBoolean:
+    case kDexAnnotationNull:
+        width = 0;
+        break;
+    default:
+        LOGE("Bad annotation element value byte 0x%02x", valueType);
+        assert(false);
+        return false;
+    }
+
+    ptr += width;
+
+    *pPtr = ptr;
+    return true;
+}
+
+/*
+ * Skip past an encoded annotation.  Mainly useful for annotations embedded
+ * in other annotations.
+ */
+static bool skipEncodedAnnotation(const ClassObject* clazz, const u1** pPtr)
+{
+    const u1* ptr;
+    u4 size;
+
+    ptr = *pPtr;
+    (void) readUleb128(&ptr);
+    size = readUleb128(&ptr);
+
+    /*
+     * "ptr" points to a byte stream with "size" occurrences of
+     * annotation_element.
+     */
+    while (size--) {
+        (void) readUleb128(&ptr);
+
+        if (!skipAnnotationValue(clazz, &ptr))
+            return false;
+    }
+
+    *pPtr = ptr;
+    return true;
+}
+
+
+/*
+ * Compare the name of the class in the DEX file to the supplied descriptor.
+ * Return value is equivalent to strcmp.
+ */
+static int compareClassDescriptor(DexFile* pDexFile, u4 typeIdx,
+    const char* descriptor)
+{
+    const char* str = dexStringByTypeIdx(pDexFile, typeIdx);
+
+    return strcmp(str, descriptor);
+}
+
+/*
+ * Search through the annotation set for an annotation with a matching
+ * descriptor.
+ *
+ * Comparing the string descriptor is slower than comparing an integer class
+ * index.  If annotation lists are expected to be long, we could look up
+ * the class' index by name from the DEX file, rather than doing a class
+ * lookup and string compare on each entry.  (Note the index will be
+ * different for each DEX file, so we can't cache annotation class indices
+ * globally.)
+ */
+static const DexAnnotationItem* searchAnnotationSet(const ClassObject* clazz,
+    const DexAnnotationSetItem* pAnnoSet, const char* descriptor,
+    int visibility)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexAnnotationItem* result = NULL;
+    u4 typeIdx;
+    int i;
+
+    //printf("##### searchAnnotationSet %s %d\n", descriptor, visibility);
+
+    for (i = 0; i < (int) pAnnoSet->size; i++) {
+        const DexAnnotationItem* pAnnoItem;
+
+        pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
+        if (pAnnoItem->visibility != visibility)
+            continue;
+        const u1* ptr = pAnnoItem->annotation;
+        typeIdx = readUleb128(&ptr);
+
+        if (compareClassDescriptor(pDexFile, typeIdx, descriptor) == 0) {
+            //printf("#####  match on %x/%p at %d\n", typeIdx, pDexFile, i);
+            result = pAnnoItem;
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*
+ * Find an annotation value in the annotation_item whose name matches "name".
+ * A pointer to the annotation_value is returned, or NULL if it's not found.
+ */
+static const u1* searchEncodedAnnotation(const ClassObject* clazz,
+    const u1* ptr, const char* name)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    u4 typeIdx, size;
+
+    typeIdx = readUleb128(&ptr);
+    size = readUleb128(&ptr);
+    //printf("#####   searching ptr=%p type=%u size=%u\n", ptr, typeIdx, size);
+
+    while (size--) {
+        u4 elementNameIdx;
+        const char* elemName;
+
+        elementNameIdx = readUleb128(&ptr);
+        elemName = dexStringById(pDexFile, elementNameIdx);
+        if (strcmp(name, elemName) == 0) {
+            //printf("#####   item match on %s\n", name);
+            return ptr;     /* points to start of value */
+        }
+
+        skipAnnotationValue(clazz, &ptr);
+    }
+
+    //printf("#####   no item match on %s\n", name);
+    return NULL;
+}
+
+#define GAV_FAILED  ((Object*) 0x10000001)
+
+/*
+ * Extract an encoded annotation value from the field specified by "annoName".
+ *
+ * "expectedType" is an annotation value type, e.g. kDexAnnotationString.
+ * "debugAnnoName" is only used in debug messages.
+ *
+ * Returns GAV_FAILED on failure.  If an allocation failed, an exception
+ * will be raised.
+ */
+static Object* getAnnotationValue(const ClassObject* clazz,
+    const DexAnnotationItem* pAnnoItem, const char* annoName,
+    int expectedType, const char* debugAnnoName)
+{
+    const u1* ptr;
+    AnnotationValue avalue;
+
+    /* find the annotation */
+    ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, annoName);
+    if (ptr == NULL) {
+        LOGW("%s annotation lacks '%s' member", debugAnnoName, annoName);
+        return GAV_FAILED;
+    }
+
+    if (!processAnnotationValue(clazz, &ptr, &avalue, kAllObjects))
+        return GAV_FAILED;
+
+    /* make sure it has the expected format */
+    if (avalue.type != expectedType) {
+        LOGW("%s %s has wrong type (0x%02x, expected 0x%02x)",
+            debugAnnoName, annoName, avalue.type, expectedType);
+        return GAV_FAILED;
+    }
+
+    return (Object*)avalue.value.l;
+}
+
+
+/*
+ * Find the Signature attribute and extract its value.  (Signatures can
+ * be found in annotations on classes, constructors, methods, and fields.)
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ *
+ * Returns NULL if not found.  On memory alloc failure, returns NULL with an
+ * exception raised.
+ */
+static ArrayObject* getSignatureValue(const ClassObject* clazz,
+    const DexAnnotationSetItem* pAnnoSet)
+{
+    const DexAnnotationItem* pAnnoItem;
+    Object* obj;
+
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrSignature,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return NULL;
+
+    /*
+     * The Signature annotation has one member, "String value".
+     */
+    obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationArray,
+            "Signature");
+    if (obj == GAV_FAILED)
+        return NULL;
+    assert(obj->clazz == gDvm.classJavaLangObjectArray);
+
+    return (ArrayObject*)obj;
+}
+
+
+/*
+ * ===========================================================================
+ *      Class
+ * ===========================================================================
+ */
+
+/*
+ * Find the DexAnnotationSetItem for this class.
+ */
+static const DexAnnotationSetItem* findAnnotationSetForClass(
+    const ClassObject* clazz)
+{
+    DexFile* pDexFile;
+    const DexAnnotationsDirectoryItem* pAnnoDir;
+
+    if (clazz->pDvmDex == NULL)         /* generated class (Proxy, array) */
+        return NULL;
+
+    pDexFile = clazz->pDvmDex->pDexFile;
+    pAnnoDir = getAnnoDirectory(pDexFile, clazz);
+    if (pAnnoDir != NULL)
+        return dexGetClassAnnotationSet(pDexFile, pAnnoDir);
+    else
+        return NULL;
+}
+
+/*
+ * Return an array of Annotation objects for the class.  Returns an empty
+ * array if there are no annotations.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ *
+ * On allocation failure, this returns NULL with an exception raised.
+ */
+ArrayObject* dvmGetClassAnnotations(const ClassObject* clazz)
+{
+    ArrayObject* annoArray;
+    const DexAnnotationSetItem* pAnnoSet = NULL;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL) {
+        /* no annotations for anything in class, or no class annotations */
+        annoArray = emptyAnnoArray();
+    } else {
+        annoArray = processAnnotationSet(clazz, pAnnoSet,
+                        kDexVisibilityRuntime);
+    }
+
+    return annoArray;
+}
+
+/*
+ * Returns the annotation or NULL if it doesn't exist.
+ */
+Object* dvmGetClassAnnotation(const ClassObject* clazz,
+        const ClassObject* annotationClazz)
+{
+    const DexAnnotationSetItem* pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL) {
+        return NULL;
+    }
+    return getAnnotationObjectFromAnnotationSet(clazz, pAnnoSet,
+            kDexVisibilityRuntime, annotationClazz);
+}
+
+/*
+ * Returns true if the annotation exists.
+ */
+bool dvmIsClassAnnotationPresent(const ClassObject* clazz,
+        const ClassObject* annotationClazz)
+{
+    const DexAnnotationSetItem* pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL) {
+        return NULL;
+    }
+    const DexAnnotationItem* pAnnoItem = getAnnotationItemFromAnnotationSet(
+            clazz, pAnnoSet, kDexVisibilityRuntime, annotationClazz);
+    return (pAnnoItem != NULL);
+}
+
+/*
+ * Retrieve the Signature annotation, if any.  Returns NULL if no signature
+ * exists.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+ArrayObject* dvmGetClassSignatureAnnotation(const ClassObject* clazz)
+{
+    ArrayObject* signature = NULL;
+    const DexAnnotationSetItem* pAnnoSet;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet != NULL)
+        signature = getSignatureValue(clazz, pAnnoSet);
+
+    return signature;
+}
+
+/*
+ * Get the EnclosingMethod attribute from an annotation.  Returns a Method
+ * object, or NULL.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+Object* dvmGetEnclosingMethod(const ClassObject* clazz)
+{
+    const DexAnnotationItem* pAnnoItem;
+    const DexAnnotationSetItem* pAnnoSet;
+    Object* obj;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL)
+        return NULL;
+
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingMethod,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return NULL;
+
+    /*
+     * The EnclosingMethod annotation has one member, "Method value".
+     */
+    obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationMethod,
+            "EnclosingMethod");
+    if (obj == GAV_FAILED)
+        return NULL;
+    assert(obj->clazz == gDvm.classJavaLangReflectConstructor ||
+           obj->clazz == gDvm.classJavaLangReflectMethod);
+
+    return obj;
+}
+
+/*
+ * Find a class' enclosing class.  We return what we find in the
+ * EnclosingClass attribute.
+ *
+ * Returns a Class object, or NULL.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+ClassObject* dvmGetDeclaringClass(const ClassObject* clazz)
+{
+    const DexAnnotationItem* pAnnoItem;
+    const DexAnnotationSetItem* pAnnoSet;
+    Object* obj;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL)
+        return NULL;
+
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingClass,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return NULL;
+
+    /*
+     * The EnclosingClass annotation has one member, "Class value".
+     */
+    obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationType,
+            "EnclosingClass");
+    if (obj == GAV_FAILED)
+        return NULL;
+
+    assert(dvmIsClassObject(obj));
+    return (ClassObject*)obj;
+}
+
+/*
+ * Find a class' enclosing class.  We first search for an EnclosingClass
+ * attribute, and if that's not found we look for an EnclosingMethod.
+ *
+ * Returns a Class object, or NULL.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+ClassObject* dvmGetEnclosingClass(const ClassObject* clazz)
+{
+    const DexAnnotationItem* pAnnoItem;
+    const DexAnnotationSetItem* pAnnoSet;
+    Object* obj;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL)
+        return NULL;
+
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingClass,
+        kDexVisibilitySystem);
+    if (pAnnoItem != NULL) {
+        /*
+         * The EnclosingClass annotation has one member, "Class value".
+         */
+        obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationType,
+                "EnclosingClass");
+        if (obj != GAV_FAILED) {
+            assert(dvmIsClassObject(obj));
+            return (ClassObject*)obj;
+        }
+    }
+
+    /*
+     * That didn't work.  Look for an EnclosingMethod.
+     *
+     * We could create a java.lang.reflect.Method object and extract the
+     * declaringClass from it, but that's more work than we want to do.
+     * Instead, we find the "value" item and parse the index out ourselves.
+     */
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingMethod,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return NULL;
+
+    /* find the value member */
+    const u1* ptr;
+    ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "value");
+    if (ptr == NULL) {
+        LOGW("EnclosingMethod annotation lacks 'value' member");
+        return NULL;
+    }
+
+    /* parse it, verify the type */
+    AnnotationValue avalue;
+    if (!processAnnotationValue(clazz, &ptr, &avalue, kAllRaw)) {
+        LOGW("EnclosingMethod parse failed");
+        return NULL;
+    }
+    if (avalue.type != kDexAnnotationMethod) {
+        LOGW("EnclosingMethod value has wrong type (0x%02x, expected 0x%02x)",
+            avalue.type, kDexAnnotationMethod);
+        return NULL;
+    }
+
+    /* pull out the method index and resolve the method */
+    Method* meth = resolveAmbiguousMethod(clazz, avalue.value.i);
+    if (meth == NULL)
+        return NULL;
+
+    ClassObject* methClazz = meth->clazz;
+    dvmAddTrackedAlloc((Object*) methClazz, NULL);      // balance the Release
+    return methClazz;
+}
+
+/*
+ * Get the EnclosingClass attribute from an annotation.  If found, returns
+ * "true".  A String with the original name of the class and the original
+ * access flags are returned through the arguments.  (The name will be NULL
+ * for an anonymous inner class.)
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+bool dvmGetInnerClass(const ClassObject* clazz, StringObject** pName,
+    int* pAccessFlags)
+{
+    const DexAnnotationItem* pAnnoItem;
+    const DexAnnotationSetItem* pAnnoSet;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL)
+        return false;
+
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrInnerClass,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return false;
+
+    /*
+     * The InnerClass annotation has two members, "String name" and
+     * "int accessFlags".  We don't want to get the access flags as an
+     * Integer, so we process that as a simple value.
+     */
+    const u1* ptr;
+    ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "name");
+    if (ptr == NULL) {
+        LOGW("InnerClass annotation lacks 'name' member");
+        return false;
+    }
+
+    /* parse it into an Object */
+    AnnotationValue avalue;
+    if (!processAnnotationValue(clazz, &ptr, &avalue, kAllObjects)) {
+        LOGD("processAnnotationValue failed on InnerClass member 'name'");
+        return false;
+    }
+
+    /* make sure it has the expected format */
+    if (avalue.type != kDexAnnotationNull &&
+        avalue.type != kDexAnnotationString)
+    {
+        LOGW("InnerClass name has bad type (0x%02x, expected STRING or NULL)",
+            avalue.type);
+        return false;
+    }
+
+    *pName = (StringObject*) avalue.value.l;
+    assert(*pName == NULL || (*pName)->clazz == gDvm.classJavaLangString);
+
+    ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "accessFlags");
+    if (ptr == NULL) {
+        LOGW("InnerClass annotation lacks 'accessFlags' member");
+        return false;
+    }
+
+    /* parse it, verify the type */
+    if (!processAnnotationValue(clazz, &ptr, &avalue, kAllRaw)) {
+        LOGW("InnerClass accessFlags parse failed");
+        return false;
+    }
+    if (avalue.type != kDexAnnotationInt) {
+        LOGW("InnerClass value has wrong type (0x%02x, expected 0x%02x)",
+            avalue.type, kDexAnnotationInt);
+        return false;
+    }
+
+    *pAccessFlags = avalue.value.i;
+
+    return true;
+}
+
+/*
+ * Extract an array of Class objects from the MemberClasses annotation
+ * for this class.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ *
+ * Returns NULL if we don't find any member classes.
+ */
+ArrayObject* dvmGetDeclaredClasses(const ClassObject* clazz)
+{
+    const DexAnnotationSetItem* pAnnoSet;
+    const DexAnnotationItem* pAnnoItem;
+    Object* obj;
+
+    pAnnoSet = findAnnotationSetForClass(clazz);
+    if (pAnnoSet == NULL)
+        return NULL;
+
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrMemberClasses,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return NULL;
+
+    /*
+     * The MemberClasses annotation has one member, "Class[] value".
+     */
+    obj = getAnnotationValue(clazz, pAnnoItem, "value",
+            kDexAnnotationArray, "MemberClasses");
+    if (obj == GAV_FAILED)
+        return NULL;
+    assert(dvmIsArray((ArrayObject*)obj));
+    obj = convertReturnType(obj, gDvm.classJavaLangClassArray);
+    return (ArrayObject*)obj;
+}
+
+
+/*
+ * ===========================================================================
+ *      Method (and Constructor)
+ * ===========================================================================
+ */
+
+/*
+ * Compare the attributes (class name, method name, method signature) of
+ * the specified method to "method".
+ */
+static int compareMethodStr(DexFile* pDexFile, u4 methodIdx,
+    const Method* method)
+{
+    const DexMethodId* pMethodId = dexGetMethodId(pDexFile, methodIdx);
+    const char* str = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
+    int result = strcmp(str, method->clazz->descriptor);
+
+    if (result == 0) {
+        str = dexStringById(pDexFile, pMethodId->nameIdx);
+        result = strcmp(str, method->name);
+        if (result == 0) {
+            DexProto proto;
+            dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
+            result = dexProtoCompare(&proto, &method->prototype);
+        }
+    }
+
+    return result;
+}
+
+/*
+ * Given a method, determine the method's index.
+ *
+ * We could simply store this in the Method*, but that would cost 4 bytes
+ * per method.  Instead we plow through the DEX data.
+ *
+ * We have two choices: look through the class method data, or look through
+ * the global method_ids table.  The former is awkward because the method
+ * could have been defined in a superclass or interface.  The latter works
+ * out reasonably well because it's in sorted order, though we're still left
+ * doing a fair number of string comparisons.
+ */
+static u4 getMethodIdx(const Method* method)
+{
+    DexFile* pDexFile = method->clazz->pDvmDex->pDexFile;
+    u4 hi = pDexFile->pHeader->methodIdsSize -1;
+    u4 lo = 0;
+    u4 cur;
+
+    while (hi >= lo) {
+        int cmp;
+        cur = (lo + hi) / 2;
+
+        cmp = compareMethodStr(pDexFile, cur, method);
+        if (cmp < 0) {
+            lo = cur + 1;
+        } else if (cmp > 0) {
+            hi = cur - 1;
+        } else {
+            break;
+        }
+    }
+
+    if (hi < lo) {
+        /* this should be impossible -- the method came out of this DEX */
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGE("Unable to find method %s.%s %s in DEX file!",
+            method->clazz->descriptor, method->name, desc);
+        free(desc);
+        dvmAbort();
+    }
+
+    return cur;
+}
+
+/*
+ * Find the DexAnnotationSetItem for this method.
+ *
+ * Returns NULL if none found.
+ */
+static const DexAnnotationSetItem* findAnnotationSetForMethod(
+    const Method* method)
+{
+    ClassObject* clazz = method->clazz;
+    DexFile* pDexFile;
+    const DexAnnotationsDirectoryItem* pAnnoDir;
+    const DexMethodAnnotationsItem* pMethodList;
+    const DexAnnotationSetItem* pAnnoSet = NULL;
+
+    if (clazz->pDvmDex == NULL)         /* generated class (Proxy, array) */
+        return NULL;
+    pDexFile = clazz->pDvmDex->pDexFile;
+
+    pAnnoDir = getAnnoDirectory(pDexFile, clazz);
+    if (pAnnoDir != NULL) {
+        pMethodList = dexGetMethodAnnotations(pDexFile, pAnnoDir);
+        if (pMethodList != NULL) {
+            /*
+             * Run through the list and find a matching method.  We compare the
+             * method ref indices in the annotation list with the method's DEX
+             * method_idx value.
+             *
+             * TODO: use a binary search for long lists
+             *
+             * Alternate approach: for each entry in the annotations list,
+             * find the method definition in the DEX file and perform string
+             * comparisons on class name, method name, and signature.
+             */
+            u4 methodIdx = getMethodIdx(method);
+            u4 count = dexGetMethodAnnotationsSize(pDexFile, pAnnoDir);
+            u4 idx;
+
+            for (idx = 0; idx < count; idx++) {
+                if (pMethodList[idx].methodIdx == methodIdx) {
+                    /* found! */
+                    pAnnoSet = dexGetMethodAnnotationSetItem(pDexFile,
+                                    &pMethodList[idx]);
+                    break;
+                }
+            }
+        }
+    }
+
+    return pAnnoSet;
+}
+
+/*
+ * Return an array of Annotation objects for the method.  Returns an empty
+ * array if there are no annotations.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ *
+ * On allocation failure, this returns NULL with an exception raised.
+ */
+ArrayObject* dvmGetMethodAnnotations(const Method* method)
+{
+    ClassObject* clazz = method->clazz;
+    const DexAnnotationSetItem* pAnnoSet;
+    ArrayObject* annoArray = NULL;
+
+    pAnnoSet = findAnnotationSetForMethod(method);
+    if (pAnnoSet == NULL) {
+        /* no matching annotations found */
+        annoArray = emptyAnnoArray();
+    } else {
+        annoArray = processAnnotationSet(clazz, pAnnoSet,kDexVisibilityRuntime);
+    }
+
+    return annoArray;
+}
+
+/*
+ * Returns the annotation or NULL if it doesn't exist.
+ */
+Object* dvmGetMethodAnnotation(const ClassObject* clazz, const Method* method,
+        const ClassObject* annotationClazz)
+{
+    const DexAnnotationSetItem* pAnnoSet = findAnnotationSetForMethod(method);
+    if (pAnnoSet == NULL) {
+        return NULL;
+    }
+    return getAnnotationObjectFromAnnotationSet(clazz, pAnnoSet,
+            kDexVisibilityRuntime, annotationClazz);
+}
+
+/*
+ * Returns true if the annotation exists.
+ */
+bool dvmIsMethodAnnotationPresent(const ClassObject* clazz,
+        const Method* method, const ClassObject* annotationClazz)
+{
+    const DexAnnotationSetItem* pAnnoSet = findAnnotationSetForMethod(method);
+    if (pAnnoSet == NULL) {
+        return NULL;
+    }
+    const DexAnnotationItem* pAnnoItem = getAnnotationItemFromAnnotationSet(
+            clazz, pAnnoSet, kDexVisibilityRuntime, annotationClazz);
+    return (pAnnoItem != NULL);
+}
+
+/*
+ * Retrieve the Signature annotation, if any.  Returns NULL if no signature
+ * exists.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+ArrayObject* dvmGetMethodSignatureAnnotation(const Method* method)
+{
+    ClassObject* clazz = method->clazz;
+    const DexAnnotationSetItem* pAnnoSet;
+    ArrayObject* signature = NULL;
+
+    pAnnoSet = findAnnotationSetForMethod(method);
+    if (pAnnoSet != NULL)
+        signature = getSignatureValue(clazz, pAnnoSet);
+
+    return signature;
+}
+
+/*
+ * Extract an array of exception classes from the "system" annotation list
+ * for this method.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ *
+ * Returns NULL if we don't find any exceptions for this method.
+ */
+ArrayObject* dvmGetMethodThrows(const Method* method)
+{
+    ClassObject* clazz = method->clazz;
+    const DexAnnotationSetItem* pAnnoSet;
+    const DexAnnotationItem* pAnnoItem;
+
+    /* find the set for this method */
+    pAnnoSet = findAnnotationSetForMethod(method);
+    if (pAnnoSet == NULL)
+        return NULL;        /* nothing for this method */
+
+    /* find the "Throws" annotation, if any */
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrThrows,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL)
+        return NULL;        /* no Throws */
+
+    /*
+     * The Throws annotation has one member, "Class[] value".
+     */
+    Object* obj = getAnnotationValue(clazz, pAnnoItem, "value",
+        kDexAnnotationArray, "Throws");
+    if (obj == GAV_FAILED)
+        return NULL;
+    assert(dvmIsArray((ArrayObject*)obj));
+    obj = convertReturnType(obj, gDvm.classJavaLangClassArray);
+    return (ArrayObject*)obj;
+}
+
+/*
+ * Given an Annotation's method, find the default value, if any.
+ *
+ * If this is a CLASS annotation, and we can't find a match for the
+ * default class value, we need to throw a TypeNotPresentException.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+Object* dvmGetAnnotationDefaultValue(const Method* method)
+{
+    const ClassObject* clazz = method->clazz;
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexAnnotationsDirectoryItem* pAnnoDir;
+    const DexAnnotationSetItem* pAnnoSet = NULL;
+
+    /*
+     * The method's declaring class (the annotation) will have an
+     * AnnotationDefault "system" annotation associated with it if any
+     * of its methods have default values.  Start by finding the
+     * DexAnnotationItem associated with the class.
+     */
+    pAnnoDir = getAnnoDirectory(pDexFile, clazz);
+    if (pAnnoDir != NULL)
+        pAnnoSet = dexGetClassAnnotationSet(pDexFile, pAnnoDir);
+    if (pAnnoSet == NULL) {
+        /* no annotations for anything in class, or no class annotations */
+        return NULL;
+    }
+
+    /* find the "AnnotationDefault" annotation, if any */
+    const DexAnnotationItem* pAnnoItem;
+    pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrAnnotationDefault,
+        kDexVisibilitySystem);
+    if (pAnnoItem == NULL) {
+        /* no default values for any member in this annotation */
+        //printf("##### no default annotations for %s.%s\n",
+        //    method->clazz->descriptor, method->name);
+        return NULL;
+    }
+
+    /*
+     * The AnnotationDefault annotation has one member, "Annotation value".
+     * We need to pull that out.
+     */
+    const u1* ptr;
+    ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "value");
+    if (ptr == NULL) {
+        LOGW("AnnotationDefault annotation lacks 'value'");
+        return NULL;
+    }
+    if ((*ptr & kDexAnnotationValueTypeMask) != kDexAnnotationAnnotation) {
+        LOGW("AnnotationDefault value has wrong type (0x%02x)",
+            *ptr & kDexAnnotationValueTypeMask);
+        return NULL;
+    }
+
+    /*
+     * The value_type byte for VALUE_ANNOTATION is followed by
+     * encoded_annotation data.  We want to scan through it to find an
+     * entry whose name matches our method name.
+     */
+    ptr++;
+    ptr = searchEncodedAnnotation(clazz, ptr, method->name);
+    if (ptr == NULL)
+        return NULL;        /* no default annotation for this method */
+
+    /* got it, pull it out */
+    AnnotationValue avalue;
+    if (!processAnnotationValue(clazz, &ptr, &avalue, kAllObjects)) {
+        LOGD("processAnnotationValue failed on default for '%s'",
+            method->name);
+        return NULL;
+    }
+
+    /* convert the return type, if necessary */
+    ClassObject* methodReturn = dvmGetBoxedReturnType(method);
+    Object* obj = (Object*)avalue.value.l;
+    obj = convertReturnType(obj, methodReturn);
+
+    return obj;
+}
+
+
+/*
+ * ===========================================================================
+ *      Field
+ * ===========================================================================
+ */
+
+/*
+ * Compare the attributes (class name, field name, field signature) of
+ * the specified field to "field".
+ */
+static int compareFieldStr(DexFile* pDexFile, u4 idx, const Field* field)
+{
+    const DexFieldId* pFieldId = dexGetFieldId(pDexFile, idx);
+    const char* str = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
+    int result = strcmp(str, field->clazz->descriptor);
+
+    if (result == 0) {
+        str = dexStringById(pDexFile, pFieldId->nameIdx);
+        result = strcmp(str, field->name);
+        if (result == 0) {
+            str = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
+            result = strcmp(str, field->signature);
+        }
+    }
+
+    return result;
+}
+
+/*
+ * Given a field, determine the field's index.
+ *
+ * This has the same tradeoffs as getMethodIdx.
+ */
+static u4 getFieldIdx(const Field* field)
+{
+    DexFile* pDexFile = field->clazz->pDvmDex->pDexFile;
+    u4 hi = pDexFile->pHeader->fieldIdsSize -1;
+    u4 lo = 0;
+    u4 cur;
+
+    while (hi >= lo) {
+        int cmp;
+        cur = (lo + hi) / 2;
+
+        cmp = compareFieldStr(pDexFile, cur, field);
+        if (cmp < 0) {
+            lo = cur + 1;
+        } else if (cmp > 0) {
+            hi = cur - 1;
+        } else {
+            break;
+        }
+    }
+
+    if (hi < lo) {
+        /* this should be impossible -- the field came out of this DEX */
+        LOGE("Unable to find field %s.%s %s in DEX file!",
+            field->clazz->descriptor, field->name, field->signature);
+        dvmAbort();
+    }
+
+    return cur;
+}
+
+/*
+ * Find the DexAnnotationSetItem for this field.
+ *
+ * Returns NULL if none found.
+ */
+static const DexAnnotationSetItem* findAnnotationSetForField(const Field* field)
+{
+    ClassObject* clazz = field->clazz;
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    const DexAnnotationsDirectoryItem* pAnnoDir;
+    const DexFieldAnnotationsItem* pFieldList;
+
+    pAnnoDir = getAnnoDirectory(pDexFile, clazz);
+    if (pAnnoDir == NULL)
+        return NULL;
+
+    pFieldList = dexGetFieldAnnotations(pDexFile, pAnnoDir);
+    if (pFieldList == NULL)
+        return NULL;
+
+    /*
+     * Run through the list and find a matching field.  We compare the
+     * field ref indices in the annotation list with the field's DEX
+     * field_idx value.
+     *
+     * TODO: use a binary search for long lists
+     *
+     * Alternate approach: for each entry in the annotations list,
+     * find the field definition in the DEX file and perform string
+     * comparisons on class name, field name, and signature.
+     */
+    u4 fieldIdx = getFieldIdx(field);
+    u4 count = dexGetFieldAnnotationsSize(pDexFile, pAnnoDir);
+    u4 idx;
+
+    for (idx = 0; idx < count; idx++) {
+        if (pFieldList[idx].fieldIdx == fieldIdx) {
+            /* found! */
+            return dexGetFieldAnnotationSetItem(pDexFile, &pFieldList[idx]);
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Return an array of Annotation objects for the field.  Returns an empty
+ * array if there are no annotations.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ *
+ * On allocation failure, this returns NULL with an exception raised.
+ */
+ArrayObject* dvmGetFieldAnnotations(const Field* field)
+{
+    ClassObject* clazz = field->clazz;
+    ArrayObject* annoArray = NULL;
+    const DexAnnotationSetItem* pAnnoSet = NULL;
+
+    pAnnoSet = findAnnotationSetForField(field);
+    if (pAnnoSet == NULL) {
+        /* no matching annotations found */
+        annoArray = emptyAnnoArray();
+    } else {
+        annoArray = processAnnotationSet(clazz, pAnnoSet,
+                        kDexVisibilityRuntime);
+    }
+
+    return annoArray;
+}
+
+/*
+ * Returns the annotation or NULL if it doesn't exist.
+ */
+Object* dvmGetFieldAnnotation(const ClassObject* clazz, const Field* field,
+        const ClassObject* annotationClazz)
+{
+    const DexAnnotationSetItem* pAnnoSet = findAnnotationSetForField(field);
+    if (pAnnoSet == NULL) {
+        return NULL;
+    }
+    return getAnnotationObjectFromAnnotationSet(clazz, pAnnoSet,
+            kDexVisibilityRuntime, annotationClazz);
+}
+
+/*
+ * Returns true if the annotation exists.
+ */
+bool dvmIsFieldAnnotationPresent(const ClassObject* clazz,
+        const Field* field, const ClassObject* annotationClazz)
+{
+    const DexAnnotationSetItem* pAnnoSet = findAnnotationSetForField(field);
+    if (pAnnoSet == NULL) {
+        return NULL;
+    }
+    const DexAnnotationItem* pAnnoItem = getAnnotationItemFromAnnotationSet(
+            clazz, pAnnoSet, kDexVisibilityRuntime, annotationClazz);
+    return (pAnnoItem != NULL);
+}
+
+/*
+ * Retrieve the Signature annotation, if any.  Returns NULL if no signature
+ * exists.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+ArrayObject* dvmGetFieldSignatureAnnotation(const Field* field)
+{
+    ClassObject* clazz = field->clazz;
+    const DexAnnotationSetItem* pAnnoSet;
+    ArrayObject* signature = NULL;
+
+    pAnnoSet = findAnnotationSetForField(field);
+    if (pAnnoSet != NULL)
+        signature = getSignatureValue(clazz, pAnnoSet);
+
+    return signature;
+}
+
+
+/*
+ * ===========================================================================
+ *      Parameter
+ * ===========================================================================
+ */
+
+/*
+ * We have an annotation_set_ref_list, which is essentially a list of
+ * entries that we pass to processAnnotationSet().
+ *
+ * The returned object must be released with dvmReleaseTrackedAlloc.
+ */
+static ArrayObject* processAnnotationSetRefList(const ClassObject* clazz,
+    const DexAnnotationSetRefList* pAnnoSetList, u4 count)
+{
+    DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+    ArrayObject* annoArrayArray = NULL;
+    u4 idx;
+
+    /* allocate an array of Annotation arrays to hold results */
+    annoArrayArray = dvmAllocArrayByClass(
+        gDvm.classJavaLangAnnotationAnnotationArrayArray, count, ALLOC_DEFAULT);
+    if (annoArrayArray == NULL) {
+        LOGW("annotation set ref array alloc failed");
+        goto bail;
+    }
+
+    for (idx = 0; idx < count; idx++) {
+        Thread* self = dvmThreadSelf();
+        const DexAnnotationSetRefItem* pItem;
+        const DexAnnotationSetItem* pAnnoSet;
+        Object *annoSet;
+
+        pItem = dexGetParameterAnnotationSetRef(pAnnoSetList, idx);
+        pAnnoSet = dexGetSetRefItemItem(pDexFile, pItem);
+        annoSet = (Object *)processAnnotationSet(clazz,
+                                                 pAnnoSet,
+                                                 kDexVisibilityRuntime);
+        if (annoSet == NULL) {
+            LOGW("processAnnotationSet failed");
+            annoArrayArray = NULL;
+            goto bail;
+        }
+        dvmSetObjectArrayElement(annoArrayArray, idx, annoSet);
+        dvmReleaseTrackedAlloc((Object*) annoSet, self);
+    }
+
+bail:
+    return annoArrayArray;
+}
+
+/*
+ * Find the DexAnnotationSetItem for this parameter.
+ *
+ * Returns NULL if none found.
+ */
+static const DexParameterAnnotationsItem* findAnnotationsItemForMethod(
+    const Method* method)
+{
+    ClassObject* clazz = method->clazz;
+    DexFile* pDexFile;
+    const DexAnnotationsDirectoryItem* pAnnoDir;
+    const DexParameterAnnotationsItem* pParameterList;
+
+    if (clazz->pDvmDex == NULL)         /* generated class (Proxy, array) */
+        return NULL;
+
+    pDexFile = clazz->pDvmDex->pDexFile;
+    pAnnoDir = getAnnoDirectory(pDexFile, clazz);
+    if (pAnnoDir == NULL)
+        return NULL;
+
+    pParameterList = dexGetParameterAnnotations(pDexFile, pAnnoDir);
+    if (pParameterList == NULL)
+        return NULL;
+
+    /*
+     * Run through the list and find a matching method.  We compare the
+     * method ref indices in the annotation list with the method's DEX
+     * method_idx value.
+     *
+     * TODO: use a binary search for long lists
+     *
+     * Alternate approach: for each entry in the annotations list,
+     * find the method definition in the DEX file and perform string
+     * comparisons on class name, method name, and signature.
+     */
+    u4 methodIdx = getMethodIdx(method);
+    u4 count = dexGetParameterAnnotationsSize(pDexFile, pAnnoDir);
+    u4 idx;
+
+    for (idx = 0; idx < count; idx++) {
+        if (pParameterList[idx].methodIdx == methodIdx) {
+            /* found! */
+            return &pParameterList[idx];
+        }
+    }
+
+    return NULL;
+}
+
+
+/*
+ * Count up the number of arguments the method takes.  The "this" pointer
+ * doesn't count.
+ */
+static int countMethodArguments(const Method* method)
+{
+    /* method->shorty[0] is the return type */
+    return strlen(method->shorty + 1);
+}
+
+/*
+ * Return an array of arrays of Annotation objects.  The outer array has
+ * one entry per method parameter, the inner array has the list of annotations
+ * associated with that parameter.
+ *
+ * If the method has no parameters, we return an array of length zero.  If
+ * the method has one or more parameters, we return an array whose length
+ * is equal to the number of parameters; if a given parameter does not have
+ * an annotation, the corresponding entry will be null.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+ArrayObject* dvmGetParameterAnnotations(const Method* method)
+{
+    ClassObject* clazz = method->clazz;
+    const DexParameterAnnotationsItem* pItem;
+    ArrayObject* annoArrayArray = NULL;
+
+    pItem = findAnnotationsItemForMethod(method);
+    if (pItem != NULL) {
+        DexFile* pDexFile = clazz->pDvmDex->pDexFile;
+        const DexAnnotationSetRefList* pAnnoSetList;
+        u4 size;
+
+        size = dexGetParameterAnnotationSetRefSize(pDexFile, pItem);
+        pAnnoSetList = dexGetParameterAnnotationSetRefList(pDexFile, pItem);
+        annoArrayArray = processAnnotationSetRefList(clazz, pAnnoSetList, size);
+    } else {
+        /* no matching annotations found */
+        annoArrayArray = emptyAnnoArrayArray(countMethodArguments(method));
+    }
+
+    return annoArrayArray;
+}
+
+
+/*
+ * ===========================================================================
+ *      DexEncodedArray interpretation
+ * ===========================================================================
+ */
+
+/**
+ * Initializes an encoded array iterator.
+ *
+ * @param iterator iterator to initialize
+ * @param encodedArray encoded array to iterate over
+ * @param clazz class to use when resolving strings and types
+ */
+void dvmEncodedArrayIteratorInitialize(EncodedArrayIterator* iterator,
+        const DexEncodedArray* encodedArray, const ClassObject* clazz) {
+    iterator->encodedArray = encodedArray;
+    iterator->cursor = encodedArray->array;
+    iterator->size = readUleb128(&iterator->cursor);
+    iterator->elementsLeft = iterator->size;
+    iterator->clazz = clazz;
+}
+
+/**
+ * Returns whether there are more elements to be read.
+ */
+bool dvmEncodedArrayIteratorHasNext(const EncodedArrayIterator* iterator) {
+    return (iterator->elementsLeft != 0);
+}
+
+/**
+ * Returns the next decoded value from the iterator, advancing its
+ * cursor. This returns primitive values in their corresponding union
+ * slots, and returns everything else (including nulls) as object
+ * references in the "l" union slot.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on any returned reference.
+ *
+ * @param value pointer to store decoded value into
+ * @returns true if a value was decoded and the cursor advanced; false if
+ * the last value had already been decoded or if there was a problem decoding
+ */
+bool dvmEncodedArrayIteratorGetNext(EncodedArrayIterator* iterator,
+        AnnotationValue* value) {
+    bool processed;
+
+    if (iterator->elementsLeft == 0) {
+        return false;
+    }
+
+    processed = processAnnotationValue(iterator->clazz, &iterator->cursor,
+            value, kPrimitivesOrObjects);
+
+    if (! processed) {
+        LOGE("Failed to process array element %d from %p",
+                iterator->size - iterator->elementsLeft,
+                iterator->encodedArray);
+        iterator->elementsLeft = 0;
+        return false;
+    }
+
+    iterator->elementsLeft--;
+    return true;
+}
diff --git a/vm/reflect/Proxy.cpp b/vm/reflect/Proxy.cpp
new file mode 100644
index 0000000..f23dd75
--- /dev/null
+++ b/vm/reflect/Proxy.cpp
@@ -0,0 +1,1030 @@
+/*
+ * 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.
+ */
+
+/*
+ * Implementation of java.lang.reflect.Proxy.
+ *
+ * Traditionally this is implemented entirely in interpreted code,
+ * generating bytecode that defines the proxy class.  Dalvik doesn't
+ * currently support this approach, so we generate the class directly.  If
+ * we add support for DefineClass with standard classfiles we can
+ * eliminate this.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+// fwd
+static bool returnTypesAreCompatible(Method* baseMethod, Method* subMethod);
+static bool gatherMethods(ArrayObject* interfaces, Method*** pMethods,\
+    ArrayObject** pThrows, int* pMethodCount);
+static int copyWithoutDuplicates(Method** allMethods, int allCount,
+    Method** outMethods, ArrayObject* throws);
+static bool createExceptionClassList(const Method* method,
+    PointerSet** pThrows);
+static void updateExceptionClassList(const Method* method, PointerSet* throws);
+static void createConstructor(ClassObject* clazz, Method* meth);
+static void createHandlerMethod(ClassObject* clazz, Method* dstMeth,
+    const Method* srcMeth);
+static void proxyConstructor(const u4* args, JValue* pResult,
+    const Method* method, Thread* self);
+static void proxyInvoker(const u4* args, JValue* pResult,
+    const Method* method, Thread* self);
+static bool mustWrapException(const Method* method, const Object* throwable);
+
+/* private static fields in the Proxy class */
+#define kThrowsField    0
+#define kProxySFieldCount 1
+
+/*
+ * Generate a proxy class with the specified name, interfaces, and loader.
+ * "interfaces" is an array of class objects.
+ *
+ * The Proxy.getProxyClass() code has done the following:
+ *  - Verified that "interfaces" contains only interfaces
+ *  - Verified that no interface appears twice
+ *  - Prepended the package name to the class name if one or more
+ *    interfaces are non-public
+ *  - Searched for an existing instance of an appropriate Proxy class
+ *
+ * On failure we leave a partially-created class object sitting around,
+ * but the garbage collector will take care of it.
+ */
+ClassObject* dvmGenerateProxyClass(StringObject* str, ArrayObject* interfaces,
+    Object* loader)
+{
+    int result = -1;
+    ArrayObject* throws = NULL;
+
+    char* nameStr = dvmCreateCstrFromString(str);
+    if (nameStr == NULL) {
+        dvmThrowIllegalArgumentException("missing name");
+        return NULL;
+    }
+
+    LOGV("+++ Generate proxy class '%s' %p from %d interface classes",
+        nameStr, loader, interfaces->length);
+
+
+    /*
+     * Characteristics of a Proxy class:
+     * - concrete class, public and final
+     * - superclass is java.lang.reflect.Proxy
+     * - implements all listed interfaces (req'd for instanceof)
+     * - has one method for each method in the interfaces (for duplicates,
+     *   the method in the earliest interface wins)
+     * - has one constructor (takes an InvocationHandler arg)
+     * - has overrides for hashCode, equals, and toString (these come first)
+     * - has one field, a reference to the InvocationHandler object, inherited
+     *   from Proxy
+     *
+     * TODO: set protection domain so it matches bootstrap classes.
+     *
+     * The idea here is to create a class object and fill in the details
+     * as we would in loadClassFromDex(), and then call dvmLinkClass() to do
+     * all the heavy lifting (notably populating the virtual and interface
+     * method tables).
+     */
+
+    /*
+     * Allocate storage for the class object and set some basic fields.
+     */
+    size_t newClassSize =
+        sizeof(ClassObject) + kProxySFieldCount * sizeof(StaticField);
+    ClassObject* newClass =
+        (ClassObject*) dvmMalloc(newClassSize, ALLOC_NON_MOVING);
+    if (newClass == NULL)
+        goto bail;
+    DVM_OBJECT_INIT(newClass, gDvm.classJavaLangClass);
+    dvmSetClassSerialNumber(newClass);
+    newClass->descriptorAlloc = dvmNameToDescriptor(nameStr);
+    newClass->descriptor = newClass->descriptorAlloc;
+    SET_CLASS_FLAG(newClass, ACC_PUBLIC | ACC_FINAL);
+    dvmSetFieldObject((Object *)newClass,
+                      OFFSETOF_MEMBER(ClassObject, super),
+                      (Object *)gDvm.classJavaLangReflectProxy);
+    newClass->primitiveType = PRIM_NOT;
+    dvmSetFieldObject((Object *)newClass,
+                      OFFSETOF_MEMBER(ClassObject, classLoader),
+                      (Object *)loader);
+
+    /*
+     * Add direct method definitions.  We have one (the constructor).
+     */
+    newClass->directMethodCount = 1;
+    newClass->directMethods = (Method*) dvmLinearAlloc(newClass->classLoader,
+            1 * sizeof(Method));
+    createConstructor(newClass, &newClass->directMethods[0]);
+    dvmLinearReadOnly(newClass->classLoader, newClass->directMethods);
+
+    /*
+     * Add virtual method definitions.
+     */
+    {
+        /*
+         * Generate a temporary list of virtual methods.
+         */
+        int methodCount;
+        Method **methods;
+        if (!gatherMethods(interfaces, &methods, &throws, &methodCount)) {
+            goto bail;
+        }
+        newClass->virtualMethodCount = methodCount;
+        size_t virtualMethodsSize = methodCount * sizeof(Method);
+        newClass->virtualMethods =
+            (Method*)dvmLinearAlloc(newClass->classLoader, virtualMethodsSize);
+        for (int i = 0; i < newClass->virtualMethodCount; i++) {
+            createHandlerMethod(newClass, &newClass->virtualMethods[i], methods[i]);
+        }
+        free(methods);
+        dvmLinearReadOnly(newClass->classLoader, newClass->virtualMethods);
+    }
+
+    /*
+     * Add interface list.
+     */
+    {
+        size_t interfaceCount = interfaces->length;
+        ClassObject** ifArray = (ClassObject**)(void*)interfaces->contents;
+        newClass->interfaceCount = interfaceCount;
+        size_t interfacesSize = sizeof(ClassObject*) * interfaceCount;
+        newClass->interfaces =
+            (ClassObject**)dvmLinearAlloc(newClass->classLoader, interfacesSize);
+        for (size_t i = 0; i < interfaceCount; i++)
+          newClass->interfaces[i] = ifArray[i];
+        dvmLinearReadOnly(newClass->classLoader, newClass->interfaces);
+    }
+
+    /*
+     * Static field list.  We have one private field, for our list of
+     * exceptions declared for each method.
+     */
+    assert(kProxySFieldCount == 1);
+    newClass->sfieldCount = kProxySFieldCount;
+    {
+        StaticField* sfield = &newClass->sfields[kThrowsField];
+        sfield->clazz = newClass;
+        sfield->name = "throws";
+        sfield->signature = "[[Ljava/lang/Throwable;";
+        sfield->accessFlags = ACC_STATIC | ACC_PRIVATE;
+        dvmSetStaticFieldObject(sfield, (Object*)throws);
+    }
+
+    /*
+     * Everything is ready. This class didn't come out of a DEX file
+     * so we didn't tuck any indexes into the class object.  We can
+     * advance to LOADED state immediately.
+     */
+    newClass->status = CLASS_LOADED;
+    if (!dvmLinkClass(newClass)) {
+        LOGD("Proxy class link failed");
+        goto bail;
+    }
+
+    /*
+     * All good.  Add it to the hash table.  We should NOT see a collision
+     * here; if we do, it means the caller has screwed up and provided us
+     * with a duplicate name.
+     */
+    if (!dvmAddClassToHash(newClass)) {
+        LOGE("ERROR: attempted to generate %s more than once",
+            newClass->descriptor);
+        goto bail;
+    }
+
+    result = 0;
+
+bail:
+    free(nameStr);
+    if (result != 0) {
+        /* must free innards explicitly if we didn't finish linking */
+        dvmFreeClassInnards(newClass);
+        newClass = NULL;
+        if (!dvmCheckException(dvmThreadSelf())) {
+            /* throw something */
+            dvmThrowRuntimeException(NULL);
+        }
+    }
+
+    /* allow the GC to free these when nothing else has a reference */
+    dvmReleaseTrackedAlloc((Object*) throws, NULL);
+    dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+
+    return newClass;
+}
+
+
+/*
+ * Generate a list of methods.  The Method pointers returned point to the
+ * abstract method definition from the appropriate interface, or to the
+ * virtual method definition in java.lang.Object.
+ *
+ * We also allocate an array of arrays of throwable classes, one for each
+ * method,so we can do some special handling of checked exceptions.  The
+ * caller must call ReleaseTrackedAlloc() on *pThrows.
+ */
+static bool gatherMethods(ArrayObject* interfaces, Method*** pMethods,
+    ArrayObject** pThrows, int* pMethodCount)
+{
+    ClassObject** classes;
+    ArrayObject* throws = NULL;
+    Method** methods = NULL;
+    Method** allMethods = NULL;
+    int numInterfaces, maxCount, actualCount, allCount;
+    bool result = false;
+    int i;
+
+    /*
+     * Get a maximum count so we can allocate storage.  We need the
+     * methods declared by each interface and all of its superinterfaces.
+     */
+    maxCount = 3;       // 3 methods in java.lang.Object
+    numInterfaces = interfaces->length;
+    classes = (ClassObject**)(void*)interfaces->contents;
+
+    for (i = 0; i < numInterfaces; i++, classes++) {
+        ClassObject* clazz = *classes;
+
+        LOGVV("---  %s virtualMethodCount=%d",
+            clazz->descriptor, clazz->virtualMethodCount);
+        maxCount += clazz->virtualMethodCount;
+
+        int j;
+        for (j = 0; j < clazz->iftableCount; j++) {
+            ClassObject* iclass = clazz->iftable[j].clazz;
+
+            LOGVV("---  +%s %d",
+                iclass->descriptor, iclass->virtualMethodCount);
+            maxCount += iclass->virtualMethodCount;
+        }
+    }
+
+    methods = (Method**) malloc(maxCount * sizeof(*methods));
+    allMethods = (Method**) malloc(maxCount * sizeof(*methods));
+    if (methods == NULL || allMethods == NULL)
+        goto bail;
+
+    /*
+     * First three entries are the java.lang.Object methods.
+     */
+    {
+      ClassObject* obj = gDvm.classJavaLangObject;
+      allMethods[0] = obj->vtable[gDvm.voffJavaLangObject_equals];
+      allMethods[1] = obj->vtable[gDvm.voffJavaLangObject_hashCode];
+      allMethods[2] = obj->vtable[gDvm.voffJavaLangObject_toString];
+      allCount = 3;
+    }
+
+    /*
+     * Add the methods from each interface, in order.
+     */
+    classes = (ClassObject**)(void*)interfaces->contents;
+    for (i = 0; i < numInterfaces; i++, classes++) {
+        ClassObject* clazz = *classes;
+        int j;
+
+        for (j = 0; j < clazz->virtualMethodCount; j++) {
+            allMethods[allCount++] = &clazz->virtualMethods[j];
+        }
+
+        for (j = 0; j < clazz->iftableCount; j++) {
+            ClassObject* iclass = clazz->iftable[j].clazz;
+            int k;
+
+            for (k = 0; k < iclass->virtualMethodCount; k++) {
+                allMethods[allCount++] = &iclass->virtualMethods[k];
+            }
+        }
+    }
+    assert(allCount == maxCount);
+
+    /*
+     * Allocate some storage to hold the lists of throwables.  We need
+     * one entry per unique method, but it's convenient to allocate it
+     * ahead of the duplicate processing.
+     */
+    ClassObject* arrArrClass;
+    arrArrClass = dvmFindArrayClass("[[Ljava/lang/Throwable;", NULL);
+    if (arrArrClass == NULL)
+        goto bail;
+    throws = dvmAllocArrayByClass(arrArrClass, allCount, ALLOC_DEFAULT);
+
+    /*
+     * Identify and remove duplicates.
+     */
+    actualCount = copyWithoutDuplicates(allMethods, allCount, methods, throws);
+    if (actualCount < 0)
+        goto bail;
+
+    //LOGI("gathered methods:");
+    //for (i = 0; i < actualCount; i++) {
+    //    LOGI(" %d: %s.%s",
+    //        i, methods[i]->clazz->descriptor, methods[i]->name);
+    //}
+
+    *pMethods = methods;
+    *pMethodCount = actualCount;
+    *pThrows = throws;
+    result = true;
+
+bail:
+    free(allMethods);
+    if (!result) {
+        free(methods);
+        dvmReleaseTrackedAlloc((Object*)throws, NULL);
+    }
+    return result;
+}
+
+/*
+ * Identify and remove duplicates, where "duplicate" means it has the
+ * same name and arguments, but not necessarily the same return type.
+ *
+ * If duplicate methods have different return types, we want to use the
+ * first method whose return type is assignable from all other duplicate
+ * methods.  That is, if we have:
+ *   class base {...}
+ *   class sub extends base {...}
+ *   class subsub extends sub {...}
+ * Then we want to return the method that returns subsub, since callers
+ * to any form of the method will get a usable object back.
+ *
+ * All other duplicate methods are stripped out.
+ *
+ * This also populates the "throwLists" array with arrays of Class objects,
+ * one entry per method in "outMethods".  Methods that don't declare any
+ * throwables (or have no common throwables with duplicate methods) will
+ * have NULL entries.
+ *
+ * Returns the number of methods copied into "methods", or -1 on failure.
+ */
+static int copyWithoutDuplicates(Method** allMethods, int allCount,
+    Method** outMethods, ArrayObject* throwLists)
+{
+    int outCount = 0;
+    int i, j;
+
+    /*
+     * The plan is to run through all methods, checking all other methods
+     * for a duplicate.  If we find a match, we see if the other methods'
+     * return type is compatible/assignable with ours.  If the current
+     * method is assignable from all others, we copy it to the new list,
+     * and NULL out all other entries.  If not, we keep looking for a
+     * better version.
+     *
+     * If there are no duplicates, we copy the method and NULL the entry.
+     *
+     * At the end of processing, if we have any non-NULL entries, then we
+     * have bad duplicates and must exit with an exception.
+     */
+    for (i = 0; i < allCount; i++) {
+        bool best, dupe;
+
+        if (allMethods[i] == NULL)
+            continue;
+
+        /*
+         * Find all duplicates.  If any of the return types is not
+         * assignable to our return type, then we're not the best.
+         *
+         * We start from 0, not i, because we need to compare assignability
+         * the other direction even if we've compared these before.
+         */
+        dupe = false;
+        best = true;
+        for (j = 0; j < allCount; j++) {
+            if (i == j)
+                continue;
+            if (allMethods[j] == NULL)
+                continue;
+
+            if (dvmCompareMethodNamesAndParameterProtos(allMethods[i],
+                    allMethods[j]) == 0)
+            {
+                /*
+                 * Duplicate method, check return type.  If it's a primitive
+                 * type or void, the types must match exactly, or we throw
+                 * an exception now.
+                 */
+                LOGV("MATCH on %s.%s and %s.%s",
+                    allMethods[i]->clazz->descriptor, allMethods[i]->name,
+                    allMethods[j]->clazz->descriptor, allMethods[j]->name);
+                dupe = true;
+                if (!returnTypesAreCompatible(allMethods[i], allMethods[j]))
+                    best = false;
+            }
+        }
+
+        /*
+         * If this is the best of a set of duplicates, copy it over and
+         * nuke all duplicates.
+         *
+         * While we do this, we create the set of exceptions declared to
+         * be thrown by all occurrences of the method.
+         */
+        if (dupe) {
+            if (best) {
+                LOGV("BEST %d %s.%s -> %d", i,
+                    allMethods[i]->clazz->descriptor, allMethods[i]->name,
+                    outCount);
+
+                /* if we have exceptions, make a local copy */
+                PointerSet* commonThrows = NULL;
+                if (!createExceptionClassList(allMethods[i], &commonThrows))
+                    return -1;
+
+                /*
+                 * Run through one more time, erasing the duplicates.  (This
+                 * would go faster if we had marked them somehow.)
+                 */
+                for (j = 0; j < allCount; j++) {
+                    if (i == j)
+                        continue;
+                    if (allMethods[j] == NULL)
+                        continue;
+                    if (dvmCompareMethodNamesAndParameterProtos(allMethods[i],
+                            allMethods[j]) == 0)
+                    {
+                        LOGV("DEL %d %s.%s", j,
+                            allMethods[j]->clazz->descriptor,
+                            allMethods[j]->name);
+
+                        /*
+                         * Update set to hold the intersection of method[i]'s
+                         * and method[j]'s throws.
+                         */
+                        if (commonThrows != NULL) {
+                            updateExceptionClassList(allMethods[j],
+                                commonThrows);
+                        }
+
+                        allMethods[j] = NULL;
+                    }
+                }
+
+                /*
+                 * If the set of Throwable classes isn't empty, create an
+                 * array of Class, copy them into it, and put the result
+                 * into the "throwLists" array.
+                 */
+                if (commonThrows != NULL &&
+                    dvmPointerSetGetCount(commonThrows) > 0)
+                {
+                    int commonCount = dvmPointerSetGetCount(commonThrows);
+                    ArrayObject* throwArray;
+                    Object** contents;
+                    int ent;
+
+                    throwArray = dvmAllocArrayByClass(
+                            gDvm.classJavaLangClassArray, commonCount,
+                            ALLOC_DEFAULT);
+                    if (throwArray == NULL) {
+                        LOGE("common-throw array alloc failed");
+                        return -1;
+                    }
+
+                    contents = (Object**)(void*)throwArray->contents;
+                    for (ent = 0; ent < commonCount; ent++) {
+                        contents[ent] = (Object*)
+                            dvmPointerSetGetEntry(commonThrows, ent);
+                    }
+
+                    /* add it to the array of arrays */
+                    contents = (Object**)(void*)throwLists->contents;
+                    contents[outCount] = (Object*) throwArray;
+                    dvmReleaseTrackedAlloc((Object*) throwArray, NULL);
+                }
+
+                /* copy the winner and NULL it out */
+                outMethods[outCount++] = allMethods[i];
+                allMethods[i] = NULL;
+
+                dvmPointerSetFree(commonThrows);
+            } else {
+                LOGV("BEST not %d", i);
+            }
+        } else {
+            /*
+             * Singleton.  Copy the entry and NULL it out.
+             */
+            LOGV("COPY singleton %d %s.%s -> %d", i,
+                allMethods[i]->clazz->descriptor, allMethods[i]->name,
+                outCount);
+
+            /* keep track of our throwables */
+            ArrayObject* exceptionArray = dvmGetMethodThrows(allMethods[i]);
+            if (exceptionArray != NULL) {
+                Object** contents;
+
+                contents = (Object**)(void*)throwLists->contents;
+                contents[outCount] = (Object*) exceptionArray;
+                dvmReleaseTrackedAlloc((Object*) exceptionArray, NULL);
+            }
+
+            outMethods[outCount++] = allMethods[i];
+            allMethods[i] = NULL;
+        }
+    }
+
+    /*
+     * Check for stragglers.  If we find any, throw an exception.
+     */
+    for (i = 0; i < allCount; i++) {
+        if (allMethods[i] != NULL) {
+            LOGV("BAD DUPE: %d %s.%s", i,
+                allMethods[i]->clazz->descriptor, allMethods[i]->name);
+            dvmThrowIllegalArgumentException(
+                "incompatible return types in proxied interfaces");
+            return -1;
+        }
+    }
+
+    return outCount;
+}
+
+
+/*
+ * Classes can declare to throw multiple exceptions in a hierarchy, e.g.
+ * IOException and FileNotFoundException.  Since we're only interested in
+ * knowing the set that can be thrown without requiring an extra wrapper,
+ * we can remove anything that is a subclass of something else in the list.
+ *
+ * The "mix" step we do next reduces things toward the most-derived class,
+ * so it's important that we start with the least-derived classes.
+ */
+static void reduceExceptionClassList(ArrayObject* exceptionArray)
+{
+    const ClassObject** classes =
+        (const ClassObject**)(void*)exceptionArray->contents;
+
+    /*
+     * Consider all pairs of classes.  If one is the subclass of the other,
+     * null out the subclass.
+     */
+    size_t len = exceptionArray->length;
+    for (size_t i = 0; i < len - 1; i++) {
+        if (classes[i] == NULL)
+            continue;
+        for (size_t j = i + 1; j < len; j++) {
+            if (classes[j] == NULL)
+                continue;
+
+            if (dvmInstanceof(classes[i], classes[j])) {
+                classes[i] = NULL;
+                break;      /* no more comparisons against classes[i] */
+            } else if (dvmInstanceof(classes[j], classes[i])) {
+                classes[j] = NULL;
+            }
+        }
+    }
+}
+
+/*
+ * Create a local array with a copy of the throwable classes declared by
+ * "method".  If no throws are declared, "*pSet" will be NULL.
+ *
+ * Returns "false" on allocation failure.
+ */
+static bool createExceptionClassList(const Method* method, PointerSet** pThrows)
+{
+    ArrayObject* exceptionArray = NULL;
+    bool result = false;
+
+    exceptionArray = dvmGetMethodThrows(method);
+    if (exceptionArray != NULL && exceptionArray->length > 0) {
+        /* reduce list, nulling out redundant entries */
+        reduceExceptionClassList(exceptionArray);
+
+        *pThrows = dvmPointerSetAlloc(exceptionArray->length);
+        if (*pThrows == NULL)
+            goto bail;
+
+        const ClassObject** contents;
+
+        contents = (const ClassObject**)(void*)exceptionArray->contents;
+        for (size_t i = 0; i < exceptionArray->length; i++) {
+            if (contents[i] != NULL)
+                dvmPointerSetAddEntry(*pThrows, contents[i]);
+        }
+    } else {
+        *pThrows = NULL;
+    }
+
+    result = true;
+
+bail:
+    dvmReleaseTrackedAlloc((Object*) exceptionArray, NULL);
+    return result;
+}
+
+/*
+ * We need to compute the intersection of the arguments, i.e. remove
+ * anything from "throws" that isn't in the method's list of throws.
+ *
+ * If one class is a subclass of another, we want to keep just the subclass,
+ * moving toward the most-restrictive set.
+ *
+ * We assume these are all classes, and don't try to filter out interfaces.
+ */
+static void updateExceptionClassList(const Method* method, PointerSet* throws)
+{
+    int setSize = dvmPointerSetGetCount(throws);
+    if (setSize == 0)
+        return;
+
+    ArrayObject* exceptionArray = dvmGetMethodThrows(method);
+    if (exceptionArray == NULL) {
+        /* nothing declared, so intersection is empty */
+        dvmPointerSetClear(throws);
+        return;
+    }
+
+    /* reduce list, nulling out redundant entries */
+    reduceExceptionClassList(exceptionArray);
+
+    size_t mixLen = dvmPointerSetGetCount(throws);
+    const ClassObject* mixSet[mixLen];
+
+    size_t declLen = exceptionArray->length;
+    const ClassObject** declSet = (const ClassObject**)(void*)exceptionArray->contents;
+
+    /* grab a local copy to work on */
+    for (size_t i = 0; i < mixLen; i++) {
+        mixSet[i] = (ClassObject*)dvmPointerSetGetEntry(throws, i);
+    }
+
+    for (size_t i = 0; i < mixLen; i++) {
+        size_t j;
+        for (j = 0; j < declLen; j++) {
+            if (declSet[j] == NULL)
+                continue;
+
+            if (mixSet[i] == declSet[j]) {
+                /* match, keep this one */
+                break;
+            } else if (dvmInstanceof(mixSet[i], declSet[j])) {
+                /* mix is a subclass of a declared throwable, keep it */
+                break;
+            } else if (dvmInstanceof(declSet[j], mixSet[i])) {
+                /* mix is a superclass, replace it */
+                mixSet[i] = declSet[j];
+                break;
+            }
+        }
+
+        if (j == declLen) {
+            /* no match, remove entry by nulling it out */
+            mixSet[i] = NULL;
+        }
+    }
+
+    /* copy results back out; this eliminates duplicates as we go */
+    dvmPointerSetClear(throws);
+    for (size_t i = 0; i < mixLen; i++) {
+        if (mixSet[i] != NULL)
+            dvmPointerSetAddEntry(throws, mixSet[i]);
+    }
+
+    dvmReleaseTrackedAlloc((Object*) exceptionArray, NULL);
+}
+
+
+/*
+ * Check to see if the return types are compatible.
+ *
+ * If the return type is primitive or void, it must match exactly.
+ *
+ * If not, the type in "subMethod" must be assignable to the type in
+ * "baseMethod".
+ */
+static bool returnTypesAreCompatible(Method* subMethod, Method* baseMethod)
+{
+    const char* baseSig = dexProtoGetReturnType(&baseMethod->prototype);
+    const char* subSig = dexProtoGetReturnType(&subMethod->prototype);
+    ClassObject* baseClass;
+    ClassObject* subClass;
+
+    if (baseSig[1] == '\0' || subSig[1] == '\0') {
+        /* at least one is primitive type */
+        return (baseSig[0] == subSig[0] && baseSig[1] == subSig[1]);
+    }
+
+    baseClass = dvmFindClass(baseSig, baseMethod->clazz->classLoader);
+    subClass = dvmFindClass(subSig, subMethod->clazz->classLoader);
+    bool result = dvmInstanceof(subClass, baseClass);
+    return result;
+}
+
+/*
+ * Create a constructor for our Proxy class.  The constructor takes one
+ * argument, a java.lang.reflect.InvocationHandler.
+ */
+static void createConstructor(ClassObject* clazz, Method* meth)
+{
+    /*
+     * The constructor signatures (->prototype and ->shorty) need to
+     * be cloned from a method in a "real" DEX file. We declared the
+     * otherwise unused method Proxy.constructorPrototype() just for
+     * this purpose.
+     */
+
+    meth->clazz = clazz;
+    meth->accessFlags = ACC_PUBLIC | ACC_NATIVE;
+    meth->name = "<init>";
+    meth->prototype =
+        gDvm.methJavaLangReflectProxy_constructorPrototype->prototype;
+    meth->shorty =
+        gDvm.methJavaLangReflectProxy_constructorPrototype->shorty;
+    // no pDexCode or pDexMethod
+
+    int argsSize = dvmComputeMethodArgsSize(meth) + 1;
+    meth->registersSize = meth->insSize = argsSize;
+
+    meth->nativeFunc = proxyConstructor;
+}
+
+/*
+ * Create a method in our Proxy class with the name and signature of
+ * the interface method it implements.
+ */
+static void createHandlerMethod(ClassObject* clazz, Method* dstMeth,
+    const Method* srcMeth)
+{
+    dstMeth->clazz = clazz;
+    dstMeth->insns = (u2*) srcMeth;
+    dstMeth->accessFlags = ACC_PUBLIC | ACC_NATIVE;
+    dstMeth->name = srcMeth->name;
+    dstMeth->prototype = srcMeth->prototype;
+    dstMeth->shorty = srcMeth->shorty;
+    // no pDexCode or pDexMethod
+
+    int argsSize = dvmComputeMethodArgsSize(dstMeth) + 1;
+    dstMeth->registersSize = dstMeth->insSize = argsSize;
+
+    dstMeth->nativeFunc = proxyInvoker;
+}
+
+/*
+ * Return a new Object[] array with the contents of "args".  We determine
+ * the number and types of values in "args" based on the method signature.
+ * Primitive types are boxed.
+ *
+ * Returns NULL if the method takes no arguments.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the return value.
+ *
+ * On failure, returns with an appropriate exception raised.
+ */
+static ArrayObject* boxMethodArgs(const Method* method, const u4* args)
+{
+    const char* desc = &method->shorty[1]; // [0] is the return type.
+
+    /* count args */
+    size_t argCount = dexProtoGetParameterCount(&method->prototype);
+
+    /* allocate storage */
+    ArrayObject* argArray = dvmAllocArrayByClass(gDvm.classJavaLangObjectArray,
+        argCount, ALLOC_DEFAULT);
+    if (argArray == NULL)
+        return NULL;
+    Object** argObjects = (Object**)(void*)argArray->contents;
+
+    /*
+     * Fill in the array.
+     */
+
+    size_t srcIndex = 0;
+    size_t dstIndex = 0;
+    while (*desc != '\0') {
+        char descChar = *(desc++);
+        JValue value;
+
+        switch (descChar) {
+        case 'Z':
+        case 'C':
+        case 'F':
+        case 'B':
+        case 'S':
+        case 'I':
+            value.i = args[srcIndex++];
+            argObjects[dstIndex] = (Object*) dvmBoxPrimitive(value,
+                dvmFindPrimitiveClass(descChar));
+            /* argObjects is tracked, don't need to hold this too */
+            dvmReleaseTrackedAlloc(argObjects[dstIndex], NULL);
+            dstIndex++;
+            break;
+        case 'D':
+        case 'J':
+            value.j = dvmGetArgLong(args, srcIndex);
+            srcIndex += 2;
+            argObjects[dstIndex] = (Object*) dvmBoxPrimitive(value,
+                dvmFindPrimitiveClass(descChar));
+            dvmReleaseTrackedAlloc(argObjects[dstIndex], NULL);
+            dstIndex++;
+            break;
+        case '[':
+        case 'L':
+            argObjects[dstIndex++] = (Object*) args[srcIndex++];
+            break;
+        }
+    }
+
+    return argArray;
+}
+
+/*
+ * This is the constructor for a generated proxy object.  All we need to
+ * do is stuff "handler" into "h".
+ */
+static void proxyConstructor(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    Object* obj = (Object*) args[0];
+    Object* handler = (Object*) args[1];
+
+    dvmSetFieldObject(obj, gDvm.offJavaLangReflectProxy_h, handler);
+}
+
+/*
+ * This is the common message body for proxy methods.
+ *
+ * The method we're calling looks like:
+ *   public Object invoke(Object proxy, Method method, Object[] args)
+ *
+ * This means we have to create a Method object, box our arguments into
+ * a new Object[] array, make the call, and unbox the return value if
+ * necessary.
+ */
+static void proxyInvoker(const u4* args, JValue* pResult,
+    const Method* method, Thread* self)
+{
+    Object* thisObj = (Object*) args[0];
+    Object* methodObj = NULL;
+    ArrayObject* argArray = NULL;
+    Object* handler;
+    Method* invoke;
+    ClassObject* returnType;
+    JValue invokeResult;
+
+    /*
+     * Retrieve handler object for this proxy instance.  The field is
+     * defined in the superclass (Proxy).
+     */
+    handler = dvmGetFieldObject(thisObj, gDvm.offJavaLangReflectProxy_h);
+
+    /*
+     * Find the invoke() method, looking in "this"s class.  (Because we
+     * start here we don't have to convert it to a vtable index and then
+     * index into this' vtable.)
+     */
+    invoke = dvmFindVirtualMethodHierByDescriptor(handler->clazz, "invoke",
+            "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
+    if (invoke == NULL) {
+        LOGE("Unable to find invoke()");
+        dvmAbort();
+    }
+
+    LOGV("invoke: %s.%s, this=%p, handler=%s",
+        method->clazz->descriptor, method->name,
+        thisObj, handler->clazz->descriptor);
+
+    /*
+     * Create a java.lang.reflect.Method object for this method.
+     *
+     * We don't want to use "method", because that's the concrete
+     * implementation in the proxy class.  We want the abstract Method
+     * from the declaring interface.  We have a pointer to it tucked
+     * away in the "insns" field.
+     *
+     * TODO: this could be cached for performance.
+     */
+    methodObj = dvmCreateReflectMethodObject((Method*) method->insns);
+    if (methodObj == NULL) {
+        assert(dvmCheckException(self));
+        goto bail;
+    }
+
+    /*
+     * Determine the return type from the signature.
+     *
+     * TODO: this could be cached for performance.
+     */
+    returnType = dvmGetBoxedReturnType(method);
+    if (returnType == NULL) {
+        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+        LOGE("Could not determine return type for '%s'", desc);
+        free(desc);
+        assert(dvmCheckException(self));
+        goto bail;
+    }
+    LOGV("  return type will be %s", returnType->descriptor);
+
+    /*
+     * Convert "args" array into Object[] array, using the method
+     * signature to determine types.  If the method takes no arguments,
+     * we must pass null.
+     */
+    argArray = boxMethodArgs(method, args+1);
+    if (dvmCheckException(self))
+        goto bail;
+
+    /*
+     * Call h.invoke(proxy, method, args).
+     *
+     * We don't need to repackage exceptions, so if one has been thrown
+     * just jump to the end.
+     *
+     * We're not adding invokeResult.l to the tracked allocation list, but
+     * since we're just unboxing it or returning it to interpreted code
+     * that shouldn't be a problem.
+     */
+    dvmCallMethod(self, invoke, handler, &invokeResult,
+        thisObj, methodObj, argArray);
+    if (dvmCheckException(self)) {
+        Object* excep = dvmGetException(self);
+        if (mustWrapException(method, excep)) {
+            /* wrap with UndeclaredThrowableException */
+            dvmWrapException("Ljava/lang/reflect/UndeclaredThrowableException;");
+        }
+        goto bail;
+    }
+
+    /*
+     * Unbox the return value.  If it's the wrong type, throw a
+     * ClassCastException.  If it's a null pointer and we need a
+     * primitive type, throw a NullPointerException.
+     */
+    if (returnType->primitiveType == PRIM_VOID) {
+        LOGVV("+++ ignoring return to void");
+    } else if (invokeResult.l == NULL) {
+        if (dvmIsPrimitiveClass(returnType)) {
+            dvmThrowNullPointerException(
+                "null result when primitive expected");
+            goto bail;
+        }
+        pResult->l = NULL;
+    } else {
+        if (!dvmUnboxPrimitive((Object*)invokeResult.l, returnType, pResult)) {
+            dvmThrowClassCastException(((Object*)invokeResult.l)->clazz,
+                    returnType);
+            goto bail;
+        }
+    }
+
+bail:
+    dvmReleaseTrackedAlloc(methodObj, self);
+    dvmReleaseTrackedAlloc((Object*)argArray, self);
+}
+
+/*
+ * Determine if it's okay for this method to throw this exception.  If
+ * an unchecked exception was thrown we immediately return false.  If
+ * checked, we have to ensure that this method and all of its duplicates
+ * have declared that they throw it.
+ */
+static bool mustWrapException(const Method* method, const Object* throwable)
+{
+    if (!dvmIsCheckedException(throwable))
+        return false;
+
+    const StaticField* sfield = &method->clazz->sfields[kThrowsField];
+    const ArrayObject* throws = (ArrayObject*) dvmGetStaticFieldObject(sfield);
+
+    int methodIndex = method - method->clazz->virtualMethods;
+    assert(methodIndex >= 0 && methodIndex < method->clazz->virtualMethodCount);
+
+    const Object** contents = (const Object**)(void*)throws->contents;
+    const ArrayObject* methodThrows = (ArrayObject*) contents[methodIndex];
+
+    if (methodThrows == NULL) {
+        /* no throws declared, must wrap all checked exceptions */
+        return true;
+    }
+
+    size_t throwCount = methodThrows->length;
+    const ClassObject** classes =
+        (const ClassObject**)(void*)methodThrows->contents;
+
+    for (size_t i = 0; i < throwCount; i++) {
+        if (dvmInstanceof(throwable->clazz, classes[i])) {
+            /* this was declared, okay to throw */
+            return false;
+        }
+    }
+
+    /* no match in declared throws */
+    return true;
+}
diff --git a/vm/reflect/Reflect.cpp b/vm/reflect/Reflect.cpp
new file mode 100644
index 0000000..8caddfc
--- /dev/null
+++ b/vm/reflect/Reflect.cpp
@@ -0,0 +1,1266 @@
+/*
+ * 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.
+ */
+/*
+ * Basic reflection calls and utility functions.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+/*
+ * For some of the reflection stuff we need to un-box primitives, e.g.
+ * convert a java/lang/Integer to int or even a float.  We assume that
+ * the first instance field holds the value.
+ *
+ * To verify this, we either need to ensure that the class has only one
+ * instance field, or we need to look up the field by name and verify
+ * that it comes first.  The former is simpler, and should work.
+ */
+bool dvmValidateBoxClasses()
+{
+    static const char* classes[] = {
+        "Ljava/lang/Boolean;",
+        "Ljava/lang/Character;",
+        "Ljava/lang/Float;",
+        "Ljava/lang/Double;",
+        "Ljava/lang/Byte;",
+        "Ljava/lang/Short;",
+        "Ljava/lang/Integer;",
+        "Ljava/lang/Long;",
+        NULL
+    };
+    const char** ccp;
+
+    for (ccp = classes; *ccp != NULL; ccp++) {
+        ClassObject* clazz;
+
+        clazz = dvmFindClassNoInit(*ccp, NULL);
+        if (clazz == NULL) {
+            LOGE("Couldn't find '%s'", *ccp);
+            return false;
+        }
+
+        if (clazz->ifieldCount != 1) {
+            LOGE("Found %d instance fields in '%s'",
+                clazz->ifieldCount, *ccp);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+/*
+ * Find the named class object.  We have to trim "*pSignature" down to just
+ * the first token, do the lookup, and then restore anything important
+ * that we've stomped on.
+ *
+ * "pSig" will be advanced to the start of the next token.
+ */
+static ClassObject* convertSignaturePartToClass(char** pSignature,
+    const ClassObject* defClass)
+{
+    ClassObject* clazz = NULL;
+    char* signature = *pSignature;
+
+    if (*signature == '[') {
+        /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */
+        char savedChar;
+
+        while (*++signature == '[')
+            ;
+        if (*signature == 'L') {
+            while (*++signature != ';')
+                ;
+        }
+
+        /* advance past ';', and stomp on whatever comes next */
+        savedChar = *++signature;
+        *signature = '\0';
+        clazz = dvmFindArrayClass(*pSignature, defClass->classLoader);
+        *signature = savedChar;
+    } else if (*signature == 'L') {
+        /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */
+        char savedChar;
+        while (*++signature != ';')
+            ;
+        savedChar = *++signature;
+        *signature = '\0';
+        clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader);
+        *signature = savedChar;
+    } else {
+        clazz = dvmFindPrimitiveClass(*signature++);
+    }
+
+    if (clazz == NULL) {
+        LOGW("Unable to match class for part: '%s'", *pSignature);
+    }
+    *pSignature = signature;
+    return clazz;
+}
+
+/*
+ * Convert the method signature to an array of classes.
+ *
+ * The tokenization process may mangle "*pSignature".  On return, it will
+ * be pointing at the closing ')'.
+ *
+ * "defClass" is the method's class, which is needed to make class loaders
+ * happy.
+ */
+static ArrayObject* convertSignatureToClassArray(char** pSignature,
+    ClassObject* defClass)
+{
+    char* signature = *pSignature;
+
+    assert(*signature == '(');
+    signature++;
+
+    /* count up the number of parameters */
+    size_t count = 0;
+    char* cp = signature;
+    while (*cp != ')') {
+        count++;
+
+        if (*cp == '[') {
+            while (*++cp == '[')
+                ;
+        }
+        if (*cp == 'L') {
+            while (*++cp != ';')
+                ;
+        }
+        cp++;
+    }
+    LOGVV("REFLECT found %d parameters in '%s'", count, *pSignature);
+
+    /* create an array to hold them */
+    ArrayObject* classArray = dvmAllocArrayByClass(gDvm.classJavaLangClassArray,
+                     count, ALLOC_DEFAULT);
+    if (classArray == NULL)
+        return NULL;
+
+    /* fill it in */
+    cp = signature;
+    for (size_t i = 0; i < count; i++) {
+        ClassObject* clazz = convertSignaturePartToClass(&cp, defClass);
+        if (clazz == NULL) {
+            assert(dvmCheckException(dvmThreadSelf()));
+            return NULL;
+        }
+        LOGVV("REFLECT  %d: '%s'", i, clazz->descriptor);
+        dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
+    }
+
+    *pSignature = cp;
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return classArray;
+}
+
+
+/*
+ * Convert a field pointer to a slot number.
+ *
+ * We use positive values starting from 0 for instance fields, negative
+ * values starting from -1 for static fields.
+ */
+static int fieldToSlot(const Field* field, const ClassObject* clazz)
+{
+    int slot;
+
+    if (dvmIsStaticField(field)) {
+        slot = (StaticField*)field - &clazz->sfields[0];
+        assert(slot >= 0 && slot < clazz->sfieldCount);
+        slot = -(slot+1);
+    } else {
+        slot = (InstField*)field - clazz->ifields;
+        assert(slot >= 0 && slot < clazz->ifieldCount);
+    }
+
+    return slot;
+}
+
+/*
+ * Convert a slot number to a field pointer.
+ */
+Field* dvmSlotToField(ClassObject* clazz, int slot)
+{
+    if (slot < 0) {
+        slot = -(slot+1);
+        assert(slot < clazz->sfieldCount);
+        return (Field*)(void*)&clazz->sfields[slot];
+    } else {
+        assert(slot < clazz->ifieldCount);
+        return (Field*)(void*)&clazz->ifields[slot];
+    }
+}
+
+/*
+ * Create a new java.lang.reflect.Field object from "field".
+ *
+ * The Field spec doesn't specify the constructor.  We're going to use the
+ * one from our existing class libs:
+ *
+ *  private Field(Class declaringClass, Class type, String name, int slot)
+ */
+static Object* createFieldObject(Field* field, const ClassObject* clazz)
+{
+    Object* result = NULL;
+    Object* fieldObj = NULL;
+    StringObject* nameObj = NULL;
+    ClassObject* type;
+    char* mangle;
+    char* cp;
+    int slot;
+
+    assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField));
+
+    fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
+    if (fieldObj == NULL)
+        goto bail;
+
+    cp = mangle = strdup(field->signature);
+    type = convertSignaturePartToClass(&cp, clazz);
+    free(mangle);
+    if (type == NULL)
+        goto bail;
+
+    nameObj = dvmCreateStringFromCstr(field->name);
+    if (nameObj == NULL)
+        goto bail;
+
+    slot = fieldToSlot(field, clazz);
+
+    JValue unused;
+    dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init,
+        fieldObj, &unused, clazz, type, nameObj, slot);
+    if (dvmCheckException(dvmThreadSelf())) {
+        LOGD("Field class init threw exception");
+        goto bail;
+    }
+
+    result = fieldObj;
+
+bail:
+    dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
+    if (result == NULL)
+        dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
+    /* caller must dvmReleaseTrackedAlloc(result) */
+    return result;
+}
+
+/*
+ *
+ * Get an array with all fields declared by a class.
+ *
+ * This includes both static and instance fields.
+ */
+ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
+{
+    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
+        dvmInitClass(gDvm.classJavaLangReflectField);
+
+    /* count #of fields */
+    size_t count;
+    if (!publicOnly)
+        count = clazz->sfieldCount + clazz->ifieldCount;
+    else {
+        count = 0;
+        for (int i = 0; i < clazz->sfieldCount; i++) {
+            if ((clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
+                count++;
+        }
+        for (int i = 0; i < clazz->ifieldCount; i++) {
+            if ((clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
+                count++;
+        }
+    }
+
+    /* create the Field[] array */
+    ArrayObject* fieldArray =
+        dvmAllocArrayByClass(gDvm.classJavaLangReflectFieldArray, count, ALLOC_DEFAULT);
+    if (fieldArray == NULL)
+        return NULL;
+
+    /* populate */
+    size_t fieldCount = 0;
+    for (int i = 0; i < clazz->sfieldCount; i++) {
+        if (!publicOnly ||
+            (clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
+        {
+            Object* field = createFieldObject(&clazz->sfields[i], clazz);
+            if (field == NULL) {
+                goto fail;
+            }
+            dvmSetObjectArrayElement(fieldArray, fieldCount, field);
+            dvmReleaseTrackedAlloc(field, NULL);
+            ++fieldCount;
+        }
+    }
+    for (int i = 0; i < clazz->ifieldCount; i++) {
+        if (!publicOnly ||
+            (clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
+        {
+            Object* field = createFieldObject(&clazz->ifields[i], clazz);
+            if (field == NULL) {
+                goto fail;
+            }
+            dvmSetObjectArrayElement(fieldArray, fieldCount, field);
+            dvmReleaseTrackedAlloc(field, NULL);
+            ++fieldCount;
+        }
+    }
+
+    assert(fieldCount == fieldArray->length);
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return fieldArray;
+
+fail:
+    dvmReleaseTrackedAlloc((Object*) fieldArray, NULL);
+    return NULL;
+}
+
+
+/*
+ * Convert a method pointer to a slot number.
+ *
+ * We use positive values starting from 0 for virtual methods, negative
+ * values starting from -1 for static methods.
+ */
+static int methodToSlot(const Method* meth)
+{
+    ClassObject* clazz = meth->clazz;
+    int slot;
+
+    if (dvmIsDirectMethod(meth)) {
+        slot = meth - clazz->directMethods;
+        assert(slot >= 0 && slot < clazz->directMethodCount);
+        slot = -(slot+1);
+    } else {
+        slot = meth - clazz->virtualMethods;
+        assert(slot >= 0 && slot < clazz->virtualMethodCount);
+    }
+
+    return slot;
+}
+
+/*
+ * Convert a slot number to a method pointer.
+ */
+Method* dvmSlotToMethod(ClassObject* clazz, int slot)
+{
+    if (slot < 0) {
+        slot = -(slot+1);
+        assert(slot < clazz->directMethodCount);
+        return &clazz->directMethods[slot];
+    } else {
+        assert(slot < clazz->virtualMethodCount);
+        return &clazz->virtualMethods[slot];
+    }
+}
+
+/*
+ * Create a new java/lang/reflect/Constructor object, using the contents of
+ * "meth" to construct it.
+ *
+ * The spec doesn't specify the constructor.  We're going to use the
+ * one from our existing class libs:
+ *
+ *  private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
+ *      int slot)
+ */
+static Object* createConstructorObject(Method* meth)
+{
+    Object* result = NULL;
+    ArrayObject* params = NULL;
+    ArrayObject* exceptions = NULL;
+    Object* consObj;
+    DexStringCache mangle;
+    char* cp;
+    int slot;
+
+    dexStringCacheInit(&mangle);
+
+    /* parent should guarantee init so we don't have to check on every call */
+    assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));
+
+    consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
+                ALLOC_DEFAULT);
+    if (consObj == NULL)
+        goto bail;
+
+    /*
+     * Convert the signature string into an array of classes representing
+     * the arguments.
+     */
+    cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
+    params = convertSignatureToClassArray(&cp, meth->clazz);
+    if (params == NULL)
+        goto bail;
+    assert(*cp == ')');
+    assert(*(cp+1) == 'V');
+
+    /*
+     * Create an array with one entry for every exception that the class
+     * is declared to throw.
+     */
+    exceptions = dvmGetMethodThrows(meth);
+    if (dvmCheckException(dvmThreadSelf()))
+        goto bail;
+
+    slot = methodToSlot(meth);
+
+    JValue unused;
+    dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init,
+        consObj, &unused, meth->clazz, params, exceptions, slot);
+    if (dvmCheckException(dvmThreadSelf())) {
+        LOGD("Constructor class init threw exception");
+        goto bail;
+    }
+
+    result = consObj;
+
+bail:
+    dexStringCacheRelease(&mangle);
+    dvmReleaseTrackedAlloc((Object*) params, NULL);
+    dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
+    if (result == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+        dvmReleaseTrackedAlloc(consObj, NULL);
+    }
+    /* caller must dvmReleaseTrackedAlloc(result) */
+    return result;
+}
+
+/*
+ * Get an array with all constructors declared by a class.
+ */
+ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
+{
+    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
+        dvmInitClass(gDvm.classJavaLangReflectConstructor);
+
+    /*
+     * Ordinarily we init the class the first time we resolve a method.
+     * We're bypassing the normal resolution mechanism, so we init it here.
+     */
+    if (!dvmIsClassInitialized(clazz))
+        dvmInitClass(clazz);
+
+    /*
+     * Count up the #of relevant methods.
+     */
+    size_t count = 0;
+    for (int i = 0; i < clazz->directMethodCount; ++i) {
+        Method* meth = &clazz->directMethods[i];
+        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
+            dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
+        {
+            count++;
+        }
+    }
+
+    /*
+     * Create an array of Constructor objects.
+     */
+    ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray;
+    ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
+    if (ctorArray == NULL)
+        return NULL;
+
+    /*
+     * Fill out the array.
+     */
+    size_t ctorObjCount = 0;
+    for (int i = 0; i < clazz->directMethodCount; ++i) {
+        Method* meth = &clazz->directMethods[i];
+        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
+            dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
+        {
+            Object* ctorObj = createConstructorObject(meth);
+            if (ctorObj == NULL) {
+              dvmReleaseTrackedAlloc((Object*) ctorArray, NULL);
+              return NULL;
+            }
+            dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj);
+            ++ctorObjCount;
+            dvmReleaseTrackedAlloc(ctorObj, NULL);
+        }
+    }
+
+    assert(ctorObjCount == ctorArray->length);
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return ctorArray;
+}
+
+/*
+ * Create a new java/lang/reflect/Method object, using the contents of
+ * "meth" to construct it.
+ *
+ * The spec doesn't specify the constructor.  We're going to use the
+ * one from our existing class libs:
+ *
+ *  private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
+ *      Class returnType, String name, int slot)
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on the result.
+ */
+Object* dvmCreateReflectMethodObject(const Method* meth)
+{
+    Object* result = NULL;
+    ArrayObject* params = NULL;
+    ArrayObject* exceptions = NULL;
+    StringObject* nameObj = NULL;
+    Object* methObj;
+    ClassObject* returnType;
+    DexStringCache mangle;
+    char* cp;
+    int slot;
+
+    if (dvmCheckException(dvmThreadSelf())) {
+        LOGW("WARNING: dvmCreateReflectMethodObject called with "
+             "exception pending");
+        return NULL;
+    }
+
+    dexStringCacheInit(&mangle);
+
+    /* parent should guarantee init so we don't have to check on every call */
+    assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod));
+
+    methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT);
+    if (methObj == NULL)
+        goto bail;
+
+    /*
+     * Convert the signature string into an array of classes representing
+     * the arguments, and a class for the return type.
+     */
+    cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
+    params = convertSignatureToClassArray(&cp, meth->clazz);
+    if (params == NULL)
+        goto bail;
+    assert(*cp == ')');
+    cp++;
+    returnType = convertSignaturePartToClass(&cp, meth->clazz);
+    if (returnType == NULL)
+        goto bail;
+
+    /*
+     * Create an array with one entry for every exception that the class
+     * is declared to throw.
+     */
+    exceptions = dvmGetMethodThrows(meth);
+    if (dvmCheckException(dvmThreadSelf()))
+        goto bail;
+
+    /* method name */
+    nameObj = dvmCreateStringFromCstr(meth->name);
+    if (nameObj == NULL)
+        goto bail;
+
+    slot = methodToSlot(meth);
+
+    JValue unused;
+    dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init,
+        methObj, &unused, meth->clazz, params, exceptions, returnType,
+        nameObj, slot);
+    if (dvmCheckException(dvmThreadSelf())) {
+        LOGD("Method class init threw exception");
+        goto bail;
+    }
+
+    result = methObj;
+
+bail:
+    dexStringCacheRelease(&mangle);
+    if (result == NULL) {
+        assert(dvmCheckException(dvmThreadSelf()));
+    }
+    dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
+    dvmReleaseTrackedAlloc((Object*) params, NULL);
+    dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
+    if (result == NULL)
+        dvmReleaseTrackedAlloc(methObj, NULL);
+    return result;
+}
+
+/*
+ * Get an array with all methods declared by a class.
+ *
+ * This includes both static and virtual methods, and can include private
+ * members if "publicOnly" is false.  It does not include Miranda methods,
+ * since those weren't declared in the class, or constructors.
+ */
+ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
+{
+    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
+        dvmInitClass(gDvm.classJavaLangReflectMethod);
+
+    /*
+     * Count up the #of relevant methods.
+     *
+     * Ignore virtual Miranda methods and direct class/object constructors.
+     */
+    size_t count = 0;
+    Method* meth = clazz->virtualMethods;
+    for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
+        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
+            !dvmIsMirandaMethod(meth))
+        {
+            count++;
+        }
+    }
+    meth = clazz->directMethods;
+    for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
+        if ((!publicOnly || dvmIsPublicMethod(meth)) && meth->name[0] != '<') {
+            count++;
+        }
+    }
+
+    /*
+     * Create an array of Method objects.
+     */
+    ArrayObject* methodArray =
+        dvmAllocArrayByClass(gDvm.classJavaLangReflectMethodArray, count, ALLOC_DEFAULT);
+    if (methodArray == NULL)
+        return NULL;
+
+    /*
+     * Fill out the array.
+     */
+    meth = clazz->virtualMethods;
+    size_t methObjCount = 0;
+    for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
+        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
+            !dvmIsMirandaMethod(meth))
+        {
+            Object* methObj = dvmCreateReflectMethodObject(meth);
+            if (methObj == NULL)
+                goto fail;
+            dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
+            ++methObjCount;
+            dvmReleaseTrackedAlloc(methObj, NULL);
+        }
+    }
+    meth = clazz->directMethods;
+    for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
+        if ((!publicOnly || dvmIsPublicMethod(meth)) &&
+            meth->name[0] != '<')
+        {
+            Object* methObj = dvmCreateReflectMethodObject(meth);
+            if (methObj == NULL)
+                goto fail;
+            dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
+            ++methObjCount;
+            dvmReleaseTrackedAlloc(methObj, NULL);
+        }
+    }
+
+    assert(methObjCount == methodArray->length);
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return methodArray;
+
+fail:
+    dvmReleaseTrackedAlloc((Object*) methodArray, NULL);
+    return NULL;
+}
+
+/*
+ * Fills targetDescriptorCache with the descriptors of the classes in args.
+ * This is the concatenation of the descriptors with no other adornment,
+ * consistent with dexProtoGetParameterDescriptors.
+ */
+static void createTargetDescriptor(ArrayObject* args,
+    DexStringCache* targetDescriptorCache)
+{
+    ClassObject** argsArray = (ClassObject**)(void*)args->contents;
+    size_t length = 1; /* +1 for the terminating '\0' */
+    for (size_t i = 0; i < args->length; ++i) {
+        length += strlen(argsArray[i]->descriptor);
+    }
+
+    dexStringCacheAlloc(targetDescriptorCache, length);
+
+    char* at = (char*) targetDescriptorCache->value;
+    for (size_t i = 0; i < args->length; ++i) {
+        const char* descriptor = argsArray[i]->descriptor;
+        strcpy(at, descriptor);
+        at += strlen(descriptor);
+    }
+}
+
+static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods,
+    const char* name, const char* parameterDescriptors)
+{
+    Method* method = NULL;
+    Method* result = NULL;
+    int i;
+
+    for (i = 0; i < methodsCount; ++i) {
+        method = &methods[i];
+        if (strcmp(name, method->name) != 0
+            || dvmIsMirandaMethod(method)
+            || dexProtoCompareToParameterDescriptors(&method->prototype,
+                    parameterDescriptors) != 0) {
+            continue;
+        }
+
+        result = method;
+
+        /*
+         * Covariant return types permit the class to define multiple
+         * methods with the same name and parameter types. Prefer to return
+         * a non-synthetic method in such situations. We may still return
+         * a synthetic method to handle situations like escalated visibility.
+         */
+        if (!dvmIsSyntheticMethod(method)) {
+            break;
+        }
+    }
+
+    if (result != NULL) {
+        return dvmCreateReflectObjForMethod(result->clazz, result);
+    }
+
+    return NULL;
+}
+
+/*
+ * Get the named method.
+ */
+Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
+    StringObject* nameObj, ArrayObject* args)
+{
+    Object* result = NULL;
+    DexStringCache targetDescriptorCache;
+    char* name;
+    const char* targetDescriptor;
+
+    dexStringCacheInit(&targetDescriptorCache);
+
+    name = dvmCreateCstrFromString(nameObj);
+    createTargetDescriptor(args, &targetDescriptorCache);
+    targetDescriptor = targetDescriptorCache.value;
+
+    result = findConstructorOrMethodInArray(clazz->directMethodCount,
+        clazz->directMethods, name, targetDescriptor);
+    if (result == NULL) {
+        result = findConstructorOrMethodInArray(clazz->virtualMethodCount,
+            clazz->virtualMethods, name, targetDescriptor);
+    }
+
+    free(name);
+    dexStringCacheRelease(&targetDescriptorCache);
+    return result;
+}
+
+/*
+ * Get the named field.
+ */
+Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj)
+{
+    int i;
+    Object* fieldObj = NULL;
+    char* name = dvmCreateCstrFromString(nameObj);
+
+    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
+        dvmInitClass(gDvm.classJavaLangReflectField);
+
+    for (i = 0; i < clazz->sfieldCount; i++) {
+        Field* field = &clazz->sfields[i];
+        if (strcmp(name, field->name) == 0) {
+            fieldObj = createFieldObject(field, clazz);
+            break;
+        }
+    }
+    if (fieldObj == NULL) {
+        for (i = 0; i < clazz->ifieldCount; i++) {
+            Field* field = &clazz->ifields[i];
+            if (strcmp(name, field->name) == 0) {
+                fieldObj = createFieldObject(field, clazz);
+                break;
+            }
+        }
+    }
+
+    free(name);
+    return fieldObj;
+}
+
+/*
+ * Get all interfaces a class implements. If this is unable to allocate
+ * the result array, this raises an OutOfMemoryError and returns NULL.
+ */
+ArrayObject* dvmGetInterfaces(ClassObject* clazz)
+{
+    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
+        dvmInitClass(gDvm.classJavaLangReflectMethod);
+
+    /*
+     * Create an array of Class objects.
+     */
+    size_t count = clazz->interfaceCount;
+    ArrayObject* interfaceArray =
+        dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT);
+    if (interfaceArray == NULL)
+        return NULL;
+
+    /*
+     * Fill out the array.
+     */
+    memcpy(interfaceArray->contents, clazz->interfaces,
+           count * sizeof(Object *));
+    dvmWriteBarrierArray(interfaceArray, 0, count);
+
+    /* caller must call dvmReleaseTrackedAlloc */
+    return interfaceArray;
+}
+
+/*
+ * Given a boxed primitive type, such as java/lang/Integer, return the
+ * primitive type index.
+ *
+ * Returns PRIM_NOT for void, since we never "box" that.
+ */
+static PrimitiveType getBoxedType(DataObject* arg)
+{
+    static const int kJavaLangLen = 11;     // strlen("Ljava/lang/")
+
+    if (arg == NULL)
+        return PRIM_NOT;
+
+    const char* name = arg->clazz->descriptor;
+
+    if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0)
+        return PRIM_NOT;
+
+    if (strcmp(name + kJavaLangLen, "Boolean;") == 0)
+        return PRIM_BOOLEAN;
+    if (strcmp(name + kJavaLangLen, "Character;") == 0)
+        return PRIM_CHAR;
+    if (strcmp(name + kJavaLangLen, "Float;") == 0)
+        return PRIM_FLOAT;
+    if (strcmp(name + kJavaLangLen, "Double;") == 0)
+        return PRIM_DOUBLE;
+    if (strcmp(name + kJavaLangLen, "Byte;") == 0)
+        return PRIM_BYTE;
+    if (strcmp(name + kJavaLangLen, "Short;") == 0)
+        return PRIM_SHORT;
+    if (strcmp(name + kJavaLangLen, "Integer;") == 0)
+        return PRIM_INT;
+    if (strcmp(name + kJavaLangLen, "Long;") == 0)
+        return PRIM_LONG;
+    return PRIM_NOT;
+}
+
+/*
+ * Convert primitive, boxed data from "srcPtr" to "dstPtr".
+ *
+ * Section v2 2.6 lists the various conversions and promotions.  We
+ * allow the "widening" and "identity" conversions, but don't allow the
+ * "narrowing" conversions.
+ *
+ * Allowed:
+ *  byte to short, int, long, float, double
+ *  short to int, long, float double
+ *  char to int, long, float, double
+ *  int to long, float, double
+ *  long to float, double
+ *  float to double
+ * Values of types byte, char, and short are "internally" widened to int.
+ *
+ * Returns the width in 32-bit words of the destination primitive, or
+ * -1 if the conversion is not allowed.
+ *
+ * TODO? use JValue rather than u4 pointers
+ */
+int dvmConvertPrimitiveValue(PrimitiveType srcType,
+    PrimitiveType dstType, const s4* srcPtr, s4* dstPtr)
+{
+    enum Conversion {
+        OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad
+    };
+
+    enum Conversion conv;
+
+    assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
+    assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
+
+    switch (dstType) {
+        case PRIM_BOOLEAN:
+        case PRIM_CHAR:
+        case PRIM_BYTE: {
+            conv = (srcType == dstType) ? OK4 : bad;
+            break;
+        }
+        case PRIM_SHORT: {
+            switch (srcType) {
+                case PRIM_BYTE:
+                case PRIM_SHORT: conv = OK4; break;
+                default:         conv = bad; break;
+            }
+            break;
+        }
+        case PRIM_INT: {
+            switch (srcType) {
+                case PRIM_BYTE:
+                case PRIM_CHAR:
+                case PRIM_SHORT:
+                case PRIM_INT:   conv = OK4; break;
+                default:         conv = bad; break;
+            }
+            break;
+        }
+        case PRIM_LONG: {
+            switch (srcType) {
+                case PRIM_BYTE:
+                case PRIM_CHAR:
+                case PRIM_SHORT:
+                case PRIM_INT:   conv = ItoJ; break;
+                case PRIM_LONG:  conv = OK8;  break;
+                default:         conv = bad;  break;
+            }
+            break;
+        }
+        case PRIM_FLOAT: {
+            switch (srcType) {
+                case PRIM_BYTE:
+                case PRIM_CHAR:
+                case PRIM_SHORT:
+                case PRIM_INT:   conv = ItoF; break;
+                case PRIM_LONG:  conv = JtoF; break;
+                case PRIM_FLOAT: conv = OK4;  break;
+                default:         conv = bad;  break;
+            }
+            break;
+        }
+        case PRIM_DOUBLE: {
+            switch (srcType) {
+                case PRIM_BYTE:
+                case PRIM_CHAR:
+                case PRIM_SHORT:
+                case PRIM_INT:    conv = ItoD; break;
+                case PRIM_LONG:   conv = JtoD; break;
+                case PRIM_FLOAT:  conv = FtoD; break;
+                case PRIM_DOUBLE: conv = OK8;  break;
+                default:          conv = bad;  break;
+            }
+            break;
+        }
+        case PRIM_VOID:
+        case PRIM_NOT:
+        default: {
+            conv = bad;
+            break;
+        }
+    }
+
+    switch (conv) {
+        case OK4:  *dstPtr = *srcPtr;                                   return 1;
+        case OK8:  *(s8*) dstPtr = *(s8*)srcPtr;                        return 2;
+        case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr);                return 2;
+        case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr);        return 2;
+        case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2;
+        case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr);     return 2;
+        case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr);         return 1;
+        case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr);   return 1;
+        case bad: {
+            LOGV("illegal primitive conversion: '%s' to '%s'",
+                    dexGetPrimitiveTypeDescriptor(srcType),
+                    dexGetPrimitiveTypeDescriptor(dstType));
+            return -1;
+        }
+        default: {
+            dvmAbort();
+            return -1; // Keep the compiler happy.
+        }
+    }
+}
+
+/*
+ * Convert types and widen primitives.  Puts the value of "arg" into
+ * "destPtr".
+ *
+ * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error.
+ */
+int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr)
+{
+    int retVal;
+
+    if (dvmIsPrimitiveClass(type)) {
+        /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */
+        PrimitiveType srcType;
+        s4* valuePtr;
+
+        srcType = getBoxedType(arg);
+        if (srcType == PRIM_NOT) {     // didn't pass a boxed primitive in
+            LOGVV("conv arg: type '%s' not boxed primitive",
+                arg->clazz->descriptor);
+            return -1;
+        }
+
+        /* assumes value is stored in first instance field */
+        valuePtr = (s4*) arg->instanceData;
+
+        retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType,
+                    valuePtr, destPtr);
+    } else {
+        /* verify object is compatible */
+        if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) {
+            *destPtr = (s4) arg;
+            retVal = 1;
+        } else {
+            LOGVV("Arg %p (%s) not compatible with %s",
+                arg, arg->clazz->descriptor, type->descriptor);
+            retVal = -1;
+        }
+    }
+
+    return retVal;
+}
+
+/*
+ * Create a wrapper object for a primitive data type.  If "returnType" is
+ * not primitive, this just casts "value" to an object and returns it.
+ *
+ * We could invoke the "toValue" method on the box types to take
+ * advantage of pre-created values, but running that through the
+ * interpreter is probably less efficient than just allocating storage here.
+ *
+ * The caller must call dvmReleaseTrackedAlloc on the result.
+ */
+DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
+{
+    ClassObject* wrapperClass;
+    DataObject* wrapperObj;
+    s4* dataPtr;
+    PrimitiveType typeIndex = returnType->primitiveType;
+    const char* classDescriptor;
+
+    if (typeIndex == PRIM_NOT) {
+        /* add to tracking table so return value is always in table */
+        if (value.l != NULL)
+            dvmAddTrackedAlloc((Object*)value.l, NULL);
+        return (DataObject*) value.l;
+    }
+
+    classDescriptor = dexGetBoxedTypeDescriptor(typeIndex);
+    if (classDescriptor == NULL) {
+        return NULL;
+    }
+
+    wrapperClass = dvmFindSystemClass(classDescriptor);
+    if (wrapperClass == NULL) {
+        LOGW("Unable to find '%s'", classDescriptor);
+        assert(dvmCheckException(dvmThreadSelf()));
+        return NULL;
+    }
+
+    wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
+    if (wrapperObj == NULL)
+        return NULL;
+    dataPtr = (s4*) wrapperObj->instanceData;
+
+    /* assumes value is stored in first instance field */
+    /* (see dvmValidateBoxClasses) */
+    if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE)
+        *(s8*)dataPtr = value.j;
+    else
+        *dataPtr = value.i;
+
+    return wrapperObj;
+}
+
+/*
+ * Unwrap a primitive data type, if necessary.
+ *
+ * If "returnType" is not primitive, we just tuck "value" into JValue and
+ * return it after verifying that it's the right type of object.
+ *
+ * Fails if the field is primitive and "value" is either not a boxed
+ * primitive or is of a type that cannot be converted.
+ *
+ * Returns "true" on success, "false" on failure.
+ */
+bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
+    JValue* pResult)
+{
+    PrimitiveType typeIndex = returnType->primitiveType;
+    PrimitiveType valueIndex;
+
+    if (typeIndex == PRIM_NOT) {
+        if (value != NULL && !dvmInstanceof(value->clazz, returnType)) {
+            LOGD("wrong object type: %s %s",
+                value->clazz->descriptor, returnType->descriptor);
+            return false;
+        }
+        pResult->l = value;
+        return true;
+    } else if (typeIndex == PRIM_VOID) {
+        /* can't put anything into a void */
+        return false;
+    }
+
+    valueIndex = getBoxedType((DataObject*)value);
+    if (valueIndex == PRIM_NOT)
+        return false;
+
+    /* assumes value is stored in first instance field of "value" */
+    /* (see dvmValidateBoxClasses) */
+    if (dvmConvertPrimitiveValue(valueIndex, typeIndex,
+            (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0)
+    {
+        LOGV("Prim conversion failed");
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Find the return type in the signature, and convert it to a class
+ * object.  For primitive types we use a boxed class, for reference types
+ * we do a name lookup.
+ *
+ * On failure, we return NULL with an exception raised.
+ */
+ClassObject* dvmGetBoxedReturnType(const Method* meth)
+{
+    const char* sig = dexProtoGetReturnType(&meth->prototype);
+
+    switch (*sig) {
+    case 'Z':
+    case 'C':
+    case 'F':
+    case 'D':
+    case 'B':
+    case 'S':
+    case 'I':
+    case 'J':
+    case 'V':
+        return dvmFindPrimitiveClass(*sig);
+    case '[':
+    case 'L':
+        return dvmFindClass(sig, meth->clazz->classLoader);
+    default: {
+        /* should not have passed verification */
+        char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
+        LOGE("Bad return type in signature '%s'", desc);
+        free(desc);
+        dvmThrowInternalError(NULL);
+        return NULL;
+    }
+    }
+}
+
+
+/*
+ * JNI reflection support: convert reflection object to Field ptr.
+ */
+Field* dvmGetFieldFromReflectObj(Object* obj)
+{
+    ClassObject* clazz;
+    int slot;
+
+    assert(obj->clazz == gDvm.classJavaLangReflectField);
+    clazz = (ClassObject*)dvmGetFieldObject(obj,
+                                gDvm.offJavaLangReflectField_declClass);
+    slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot);
+
+    /* must initialize the class before returning a field ID */
+    if (!dvmInitClass(clazz))
+        return NULL;
+
+    return dvmSlotToField(clazz, slot);
+}
+
+/*
+ * JNI reflection support: convert reflection object to Method ptr.
+ */
+Method* dvmGetMethodFromReflectObj(Object* obj)
+{
+    ClassObject* clazz;
+    int slot;
+
+    if (obj->clazz == gDvm.classJavaLangReflectConstructor) {
+        clazz = (ClassObject*)dvmGetFieldObject(obj,
+                                gDvm.offJavaLangReflectConstructor_declClass);
+        slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot);
+    } else if (obj->clazz == gDvm.classJavaLangReflectMethod) {
+        clazz = (ClassObject*)dvmGetFieldObject(obj,
+                                gDvm.offJavaLangReflectMethod_declClass);
+        slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot);
+    } else {
+        assert(false);
+        return NULL;
+    }
+
+    /* must initialize the class before returning a method ID */
+    if (!dvmInitClass(clazz))
+        return NULL;
+
+    return dvmSlotToMethod(clazz, slot);
+}
+
+/*
+ * JNI reflection support: convert Field to reflection object.
+ *
+ * The return value is a java.lang.reflect.Field.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field)
+{
+    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
+        dvmInitClass(gDvm.classJavaLangReflectField);
+
+    /* caller must dvmReleaseTrackedAlloc(result) */
+    return createFieldObject(field, clazz);
+}
+
+/*
+ * JNI reflection support: convert Method to reflection object.
+ *
+ * The returned object will be either a java.lang.reflect.Method or
+ * .Constructor, depending on whether "method" is a constructor.
+ *
+ * This is also used for certain "system" annotations.
+ *
+ * Caller must call dvmReleaseTrackedAlloc().
+ */
+Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method)
+{
+    UNUSED_PARAMETER(clazz);
+
+    if (strcmp(method->name, "<init>") == 0) {
+        if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
+            dvmInitClass(gDvm.classJavaLangReflectConstructor);
+
+        return createConstructorObject(method);
+    } else {
+        if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
+            dvmInitClass(gDvm.classJavaLangReflectMethod);
+
+        return dvmCreateReflectMethodObject(method);
+    }
+}
diff --git a/vm/reflect/Reflect.h b/vm/reflect/Reflect.h
new file mode 100644
index 0000000..21bb08d
--- /dev/null
+++ b/vm/reflect/Reflect.h
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ */
+/*
+ * Basic reflection calls and utility functions.
+ */
+#ifndef DALVIK_REFLECT_REFLECT_H_
+#define DALVIK_REFLECT_REFLECT_H_
+
+/*
+ * During startup, validate the "box" classes, e.g. java/lang/Integer.
+ */
+bool dvmValidateBoxClasses();
+
+/*
+ * Get all fields declared by a class.
+ *
+ * Includes both class and instance fields.
+ */
+ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly);
+
+/*
+ * Get the named field.
+ */
+Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj);
+
+/*
+ * Get all constructors declared by a class.
+ */
+ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly);
+
+/*
+ * Get all methods declared by a class.
+ *
+ * This includes both static and virtual methods, and can include private
+ * members if "publicOnly" is false.  It does not include Miranda methods,
+ * since those weren't declared in the class, or constructors.
+ */
+ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly);
+
+/*
+ * Get the named method.
+ */
+Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
+    StringObject* nameObj, ArrayObject* args);
+
+/*
+ * Get all interfaces a class implements. If this is unable to allocate
+ * the result array, this raises an OutOfMemoryError and returns NULL.
+ */
+ArrayObject* dvmGetInterfaces(ClassObject* clazz);
+
+/*
+ * Convert slot numbers back to objects.
+ */
+Field* dvmSlotToField(ClassObject* clazz, int slot);
+Method* dvmSlotToMethod(ClassObject* clazz, int slot);
+
+/*
+ * Convert a primitive value, performing a widening conversion if necessary.
+ */
+int dvmConvertPrimitiveValue(PrimitiveType srcType,
+    PrimitiveType dstType, const s4* srcPtr, s4* dstPtr);
+
+/*
+ * Convert the argument to the specified type.
+ *
+ * Returns the width of the argument (1 for most types, 2 for J/D, -1 on
+ * error).
+ */
+int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* ins);
+
+/*
+ * Box a primitive value into an object.  If "returnType" is
+ * not primitive, this just returns "value" cast to an object.
+ */
+DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType);
+
+/*
+ * Unwrap a boxed primitive.  If "returnType" is not primitive, this just
+ * returns "value" cast into a JValue.
+ */
+bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
+    JValue* pResult);
+
+/*
+ * Return the class object that matches the method's signature.  For
+ * primitive types, returns the box class.
+ */
+ClassObject* dvmGetBoxedReturnType(const Method* meth);
+
+/*
+ * JNI reflection support.
+ */
+Field* dvmGetFieldFromReflectObj(Object* obj);
+Method* dvmGetMethodFromReflectObj(Object* obj);
+Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field);
+Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method);
+
+/*
+ * Quick test to determine if the method in question is a reflection call.
+ * Used for some stack parsing.  Currently defined as "the method's declaring
+ * class is java.lang.reflect.Method".
+ */
+INLINE bool dvmIsReflectionMethod(const Method* method)
+{
+    return (method->clazz == gDvm.classJavaLangReflectMethod);
+}
+
+/*
+ * Proxy class generation.
+ */
+ClassObject* dvmGenerateProxyClass(StringObject* str, ArrayObject* interfaces,
+    Object* loader);
+
+/*
+ * Create a new java.lang.reflect.Method object based on "meth".
+ */
+Object* dvmCreateReflectMethodObject(const Method* meth);
+
+/*
+ * Return an array of Annotation objects for the specified piece.  For method
+ * parameters this is an array of arrays of Annotation objects.
+ *
+ * Method also applies to Constructor.
+ */
+ArrayObject* dvmGetClassAnnotations(const ClassObject* clazz);
+ArrayObject* dvmGetMethodAnnotations(const Method* method);
+ArrayObject* dvmGetFieldAnnotations(const Field* field);
+ArrayObject* dvmGetParameterAnnotations(const Method* method);
+
+/*
+ * Return the annotation if it exists.
+ */
+Object* dvmGetClassAnnotation(const ClassObject* clazz, const ClassObject* annotationClazz);
+Object* dvmGetMethodAnnotation(const ClassObject* clazz, const Method* method,
+        const ClassObject* annotationClazz);
+Object* dvmGetFieldAnnotation(const ClassObject* clazz, const Field* method,
+        const ClassObject* annotationClazz);
+
+/*
+ * Return true if the annotation exists.
+ */
+bool dvmIsClassAnnotationPresent(const ClassObject* clazz, const ClassObject* annotationClazz);
+bool dvmIsMethodAnnotationPresent(const ClassObject* clazz, const Method* method,
+        const ClassObject* annotationClazz);
+bool dvmIsFieldAnnotationPresent(const ClassObject* clazz, const Field* method,
+        const ClassObject* annotationClazz);
+
+/*
+ * Find the default value for an annotation member.
+ */
+Object* dvmGetAnnotationDefaultValue(const Method* method);
+
+/*
+ * Get the list of thrown exceptions for a method.  Returns NULL if there
+ * are no exceptions listed.
+ */
+ArrayObject* dvmGetMethodThrows(const Method* method);
+
+/*
+ * Get the Signature annotation.
+ */
+ArrayObject* dvmGetClassSignatureAnnotation(const ClassObject* clazz);
+ArrayObject* dvmGetMethodSignatureAnnotation(const Method* method);
+ArrayObject* dvmGetFieldSignatureAnnotation(const Field* field);
+
+/*
+ * Get the EnclosingMethod attribute from an annotation.  Returns a Method
+ * object, or NULL.
+ */
+Object* dvmGetEnclosingMethod(const ClassObject* clazz);
+
+/*
+ * Return clazz's declaring class, or NULL if there isn't one.
+ */
+ClassObject* dvmGetDeclaringClass(const ClassObject* clazz);
+
+/*
+ * Return clazz's enclosing class, or NULL if there isn't one.
+ */
+ClassObject* dvmGetEnclosingClass(const ClassObject* clazz);
+
+/*
+ * Get the EnclosingClass attribute from an annotation.  If found, returns
+ * "true".  A String with the original name of the class and the original
+ * access flags are returned through the arguments.  (The name will be NULL
+ * for an anonymous inner class.)
+ */
+bool dvmGetInnerClass(const ClassObject* clazz, StringObject** pName,
+    int* pAccessFlags);
+
+/*
+ * Get an array of class objects from the MemberClasses annotation.  Returns
+ * NULL if none found.
+ */
+ArrayObject* dvmGetDeclaredClasses(const ClassObject* clazz);
+
+/*
+ * Used to pass values out of annotation (and encoded array) processing
+ * functions.
+ */
+struct AnnotationValue {
+    JValue  value;
+    u1      type;
+};
+
+
+/**
+ * Iterator structure for iterating over DexEncodedArray instances. The
+ * structure should be treated as opaque.
+ */
+struct EncodedArrayIterator {
+    const u1* cursor;                    /* current cursor */
+    u4 elementsLeft;                     /* number of elements left to read */
+    const DexEncodedArray* encodedArray; /* instance being iterated over */
+    u4 size;                             /* number of elements in instance */
+    const ClassObject* clazz;            /* class to resolve with respect to */
+};
+
+/**
+ * Initializes an encoded array iterator.
+ *
+ * @param iterator iterator to initialize
+ * @param encodedArray encoded array to iterate over
+ * @param clazz class to use when resolving strings and types
+ */
+void dvmEncodedArrayIteratorInitialize(EncodedArrayIterator* iterator,
+        const DexEncodedArray* encodedArray, const ClassObject* clazz);
+
+/**
+ * Returns whether there are more elements to be read.
+ */
+bool dvmEncodedArrayIteratorHasNext(const EncodedArrayIterator* iterator);
+
+/**
+ * Returns the next decoded value from the iterator, advancing its
+ * cursor. This returns primitive values in their corresponding union
+ * slots, and returns everything else (including nulls) as object
+ * references in the "l" union slot.
+ *
+ * The caller must call dvmReleaseTrackedAlloc() on any returned reference.
+ *
+ * @param value pointer to store decoded value into
+ * @returns true if a value was decoded and the cursor advanced; false if
+ * the last value had already been decoded or if there was a problem decoding
+ */
+bool dvmEncodedArrayIteratorGetNext(EncodedArrayIterator* iterator,
+        AnnotationValue* value);
+
+#endif  // DALVIK_REFLECT_REFLECT_H_
diff --git a/vm/test/AtomicTest.cpp b/vm/test/AtomicTest.cpp
new file mode 100644
index 0000000..c66b897
--- /dev/null
+++ b/vm/test/AtomicTest.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This provides a handful of correctness and speed tests on our atomic
+ * operations.
+ *
+ * This doesn't really belong here, but we currently lack a better place
+ * for it, so this will do for now.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <cutils/atomic.h>
+#ifdef __arm__
+# include <machine/cpu-features.h>
+#endif
+
+#define USE_ATOMIC      1
+#define THREAD_COUNT    10
+#define ITERATION_COUNT 500000
+
+#ifdef HAVE_ANDROID_OS
+/*#define TEST_BIONIC 1*/
+#endif
+
+
+#ifdef TEST_BIONIC
+extern int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
+extern int __atomic_swap(int _new, volatile int *ptr);
+extern int __atomic_dec(volatile int *ptr);
+extern int __atomic_inc(volatile int *ptr);
+#endif
+
+static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t waitCond = PTHREAD_COND_INITIALIZER;
+
+static volatile int threadsStarted = 0;
+
+/* results */
+static int incTest = 0;
+static int decTest = 0;
+static int addTest = 0;
+static int andTest = 0;
+static int orTest = 0;
+static int casTest = 0;
+static int failingCasTest = 0;
+static int64_t wideCasTest = 0x6600000077000000LL;
+
+/*
+ * Get a relative time value.
+ */
+static int64_t getRelativeTimeNsec()
+{
+#define HAVE_POSIX_CLOCKS
+#ifdef HAVE_POSIX_CLOCKS
+    struct timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return (int64_t) now.tv_sec*1000000000LL + now.tv_nsec;
+#else
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    return (int64_t) now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
+#endif
+}
+
+
+/*
+ * Non-atomic implementations, for comparison.
+ *
+ * If these get inlined the compiler may figure out what we're up to and
+ * completely elide the operations.
+ */
+static void incr() __attribute__((noinline));
+static void decr() __attribute__((noinline));
+static void add(int addVal) __attribute__((noinline));
+static int compareAndSwap(int oldVal, int newVal, int* addr) __attribute__((noinline));
+static int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr) __attribute__((noinline));
+
+static void incr()
+{
+    incTest++;
+}
+static void decr()
+{
+    decTest--;
+}
+static void add(int32_t addVal)
+{
+    addTest += addVal;
+}
+static int compareAndSwap(int32_t oldVal, int32_t newVal, int32_t* addr)
+{
+    if (*addr == oldVal) {
+        *addr = newVal;
+        return 0;
+    }
+    return 1;
+}
+static int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr)
+{
+    if (*addr == oldVal) {
+        *addr = newVal;
+        return 0;
+    }
+    return 1;
+}
+
+/*
+ * Exercise several of the atomic ops.
+ */
+static void doAtomicTest(int num)
+{
+    int addVal = (num & 0x01) + 1;
+
+    int i;
+    for (i = 0; i < ITERATION_COUNT; i++) {
+        if (USE_ATOMIC) {
+            android_atomic_inc(&incTest);
+            android_atomic_dec(&decTest);
+            android_atomic_add(addVal, &addTest);
+
+            int val;
+            do {
+                val = casTest;
+            } while (android_atomic_release_cas(val, val+3, &casTest) != 0);
+            do {
+                val = casTest;
+            } while (android_atomic_acquire_cas(val, val-1, &casTest) != 0);
+
+            int64_t wval;
+            do {
+                wval = dvmQuasiAtomicRead64(&wideCasTest);
+            } while (dvmQuasiAtomicCas64(wval,
+                        wval + 0x0000002000000001LL, &wideCasTest) != 0);
+            do {
+                wval = dvmQuasiAtomicRead64(&wideCasTest);
+            } while (dvmQuasiAtomicCas64(wval,
+                        wval - 0x0000002000000001LL, &wideCasTest) != 0);
+        } else {
+            incr();
+            decr();
+            add(addVal);
+
+            int val;
+            do {
+                val = casTest;
+            } while (compareAndSwap(val, val+3, &casTest) != 0);
+            do {
+                val = casTest;
+            } while (compareAndSwap(val, val-1, &casTest) != 0);
+
+            int64_t wval;
+            do {
+                wval = wideCasTest;
+            } while (compareAndSwapWide(wval,
+                        wval + 0x0000002000000001LL, &wideCasTest) != 0);
+            do {
+                wval = wideCasTest;
+            } while (compareAndSwapWide(wval,
+                        wval - 0x0000002000000001LL, &wideCasTest) != 0);
+        }
+    }
+}
+
+/*
+ * Entry point for multi-thread test.
+ */
+static void* atomicTest(void* arg)
+{
+    pthread_mutex_lock(&waitLock);
+    threadsStarted++;
+    pthread_cond_wait(&waitCond, &waitLock);
+    pthread_mutex_unlock(&waitLock);
+
+    doAtomicTest((int) arg);
+
+    return NULL;
+}
+
+/* lifted from a VM test */
+static int64_t testAtomicSpeedSub(int repeatCount)
+{
+    static int value = 7;
+    int* valuePtr = &value;
+    int64_t start, end;
+    int i;
+
+    start = getRelativeTimeNsec();
+
+    for (i = repeatCount / 10; i != 0; i--) {
+        if (USE_ATOMIC) {
+            // succeed 10x
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+            android_atomic_release_cas(7, 7, valuePtr);
+        } else {
+            // succeed 10x
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+            compareAndSwap(7, 7, valuePtr);
+        }
+    }
+
+    end = getRelativeTimeNsec();
+
+    dvmFprintf(stdout, ".");
+    fflush(stdout);
+    return end - start;
+}
+
+static void testAtomicSpeed()
+{
+    static const int kIterations = 10;
+    static const int kRepeatCount = 5 * 1000 * 1000;
+    static const int kDelay = 50 * 1000;
+    int64_t results[kIterations];
+    int i;
+
+    for (i = 0; i < kIterations; i++) {
+        results[i] = testAtomicSpeedSub(kRepeatCount);
+        usleep(kDelay);
+    }
+
+    dvmFprintf(stdout, "\n");
+    dvmFprintf(stdout, "%s speed test results (%d per iteration):\n",
+        USE_ATOMIC ? "Atomic" : "Non-atomic", kRepeatCount);
+    for (i = 0; i < kIterations; i++) {
+        dvmFprintf(stdout,
+            " %2d: %.3fns\n", i, (double) results[i] / kRepeatCount);
+    }
+}
+
+/*
+ * Start tests, show results.
+ */
+bool dvmTestAtomicSpeed()
+{
+    pthread_t threads[THREAD_COUNT];
+    void *(*startRoutine)(void*) = atomicTest;
+    int64_t startWhen, endWhen;
+
+#if defined(__ARM_ARCH__)
+    dvmFprintf(stdout, "__ARM_ARCH__ is %d\n", __ARM_ARCH__);
+#endif
+#if defined(ANDROID_SMP)
+    dvmFprintf(stdout, "ANDROID_SMP is %d\n", ANDROID_SMP);
+#endif
+    dvmFprintf(stdout, "Creating threads\n");
+
+    int i;
+    for (i = 0; i < THREAD_COUNT; i++) {
+        void* arg = (void*) i;
+        if (pthread_create(&threads[i], NULL, startRoutine, arg) != 0) {
+            dvmFprintf(stderr, "thread create failed\n");
+        }
+    }
+
+    /* wait for all the threads to reach the starting line */
+    while (1) {
+        pthread_mutex_lock(&waitLock);
+        if (threadsStarted == THREAD_COUNT) {
+            dvmFprintf(stdout, "Starting test\n");
+            startWhen = getRelativeTimeNsec();
+            pthread_cond_broadcast(&waitCond);
+            pthread_mutex_unlock(&waitLock);
+            break;
+        }
+        pthread_mutex_unlock(&waitLock);
+        usleep(100000);
+    }
+
+    for (i = 0; i < THREAD_COUNT; i++) {
+        void* retval;
+        if (pthread_join(threads[i], &retval) != 0) {
+            dvmFprintf(stderr, "thread join (%d) failed\n", i);
+        }
+    }
+
+    endWhen = getRelativeTimeNsec();
+    dvmFprintf(stdout, "All threads stopped, time is %.6fms\n",
+        (endWhen - startWhen) / 1000000.0);
+
+    /*
+     * Show results; expecting:
+     *
+     * incTest = 5000000
+     * decTest = -5000000
+     * addTest = 7500000
+     * casTest = 10000000
+     * wideCasTest = 0x6600000077000000
+     */
+    dvmFprintf(stdout, "incTest = %d\n", incTest);
+    dvmFprintf(stdout, "decTest = %d\n", decTest);
+    dvmFprintf(stdout, "addTest = %d\n", addTest);
+    dvmFprintf(stdout, "casTest = %d\n", casTest);
+    dvmFprintf(stdout, "wideCasTest = 0x%llx\n", wideCasTest);
+
+    /* do again, serially (SMP check) */
+    startWhen = getRelativeTimeNsec();
+    for (i = 0; i < THREAD_COUNT; i++) {
+        doAtomicTest(i);
+    }
+    endWhen = getRelativeTimeNsec();
+    dvmFprintf(stdout, "Same iterations done serially: time is %.6fms\n",
+        (endWhen - startWhen) / 1000000.0);
+
+    /*
+     * Hard to do a meaningful thrash test on these, so just do a simple
+     * function test.
+     */
+    andTest = 0xffd7fa96;
+    orTest = 0x122221ff;
+    android_atomic_and(0xfffdaf96, &andTest);
+    android_atomic_or(0xdeaaeb00, &orTest);
+    if (android_atomic_release_cas(failingCasTest+1, failingCasTest-1,
+            &failingCasTest) == 0)
+        dvmFprintf(stdout, "failing test did not fail!\n");
+
+    dvmFprintf(stdout, "andTest = %#x\n", andTest);
+    dvmFprintf(stdout, "orTest = %#x\n", orTest);
+    dvmFprintf(stdout, "failingCasTest = %d\n", failingCasTest);
+
+#ifdef TEST_BIONIC
+    /*
+     * Quick function test on the bionic ops.
+     */
+    int prev;
+    int tester = 7;
+    prev = __atomic_inc(&tester);
+    __atomic_inc(&tester);
+    __atomic_inc(&tester);
+    dvmFprintf(stdout, "bionic 3 inc: %d -> %d\n", prev, tester);
+    prev = __atomic_dec(&tester);
+    __atomic_dec(&tester);
+    __atomic_dec(&tester);
+    dvmFprintf(stdout, "bionic 3 dec: %d -> %d\n", prev, tester);
+    prev = __atomic_swap(27, &tester);
+    dvmFprintf(stdout, "bionic swap: %d -> %d\n", prev, tester);
+    int swapok = __atomic_cmpxchg(27, 72, &tester);
+    dvmFprintf(stdout, "bionic cmpxchg: %d (%d)\n", tester, swapok);
+#endif
+
+    testAtomicSpeed();
+
+    return 0;
+}
diff --git a/vm/test/Test.h b/vm/test/Test.h
new file mode 100644
index 0000000..e5acdfd
--- /dev/null
+++ b/vm/test/Test.h
@@ -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.
+ */
+
+/*
+ * Internal unit tests.
+ */
+#ifndef DALVIK_TEST_TEST_H_
+#define DALVIK_TEST_TEST_H_
+
+bool dvmTestHash(void);
+bool dvmTestAtomicSpeed(void);
+bool dvmTestIndirectRefTable(void);
+
+#endif  // DALVIK_TEST_TEST_H_
diff --git a/vm/test/TestHash.cpp b/vm/test/TestHash.cpp
new file mode 100644
index 0000000..d03fe49
--- /dev/null
+++ b/vm/test/TestHash.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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 the hash table functions.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+#ifndef NDEBUG
+
+#define kNumTestEntries 14
+
+/*
+ * Test foreach.
+ */
+static int printFunc(void* data, void* arg)
+{
+    //printf("  '%s'\n", (const char*) data);
+    // (should verify strings)
+
+    int* count = (int*) arg;
+    (*count)++;
+    return 0;
+}
+static void dumpForeach(HashTable* pTab)
+{
+    int count = 0;
+
+    //printf("Print from foreach:\n");
+    dvmHashForeach(pTab, printFunc, &count);
+    if (count != kNumTestEntries) {
+        LOGE("TestHash foreach test failed");
+        assert(false);
+    }
+}
+
+/*
+ * Test iterator.
+ */
+static void dumpIterator(HashTable* pTab)
+{
+    int count = 0;
+
+    //printf("Print from iterator:\n");
+    HashIter iter;
+    for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter);
+        dvmHashIterNext(&iter))
+    {
+        //const char* str = (const char*) dvmHashIterData(&iter);
+        //printf("  '%s'\n", str);
+        // (should verify strings)
+        count++;
+    }
+    if (count != kNumTestEntries) {
+        LOGE("TestHash iterator test failed");
+        assert(false);
+    }
+}
+
+/*
+ * Some quick hash table tests.
+ */
+bool dvmTestHash()
+{
+    HashTable* pTab;
+    char tmpStr[64];
+    const char* str;
+    u4 hash;
+    int i;
+
+    LOGV("TestHash BEGIN");
+
+    pTab = dvmHashTableCreate(dvmHashSize(12), free);
+    if (pTab == NULL)
+        return false;
+
+    dvmHashTableLock(pTab);
+
+    /* add some entries */
+    for (i = 0; i < kNumTestEntries; i++) {
+        sprintf(tmpStr, "entry %d", i);
+        hash = dvmComputeUtf8Hash(tmpStr);
+        dvmHashTableLookup(pTab, hash, strdup(tmpStr),
+            (HashCompareFunc) strcmp, true);
+    }
+
+    dvmHashTableUnlock(pTab);
+
+    /* make sure we can find all entries */
+    for (i = 0; i < kNumTestEntries; i++) {
+        sprintf(tmpStr, "entry %d", i);
+        hash = dvmComputeUtf8Hash(tmpStr);
+        str = (const char*) dvmHashTableLookup(pTab, hash, tmpStr,
+                (HashCompareFunc) strcmp, false);
+        if (str == NULL) {
+            LOGE("TestHash: failure: could not find '%s'", tmpStr);
+            /* return false */
+        }
+    }
+
+    /* make sure it behaves correctly when entry not found and !doAdd */
+    sprintf(tmpStr, "entry %d", 17);
+    hash = dvmComputeUtf8Hash(tmpStr);
+    str = (const char*) dvmHashTableLookup(pTab, hash, tmpStr,
+            (HashCompareFunc) strcmp, false);
+    if (str == NULL) {
+        /* good */
+    } else {
+        LOGE("TestHash found nonexistent string (improper add?)");
+    }
+
+    dumpForeach(pTab);
+    dumpIterator(pTab);
+
+    /* make sure they all get freed */
+    dvmHashTableFree(pTab);
+
+
+    /*
+     * Round 2: verify probing & tombstones.
+     */
+    pTab = dvmHashTableCreate(dvmHashSize(2), free);
+    if (pTab == NULL)
+        return false;
+
+    hash = 0;
+
+    /* two entries, same hash, different values */
+    const char* str1;
+    str1 = (char*) dvmHashTableLookup(pTab, hash, strdup("one"),
+            (HashCompareFunc) strcmp, true);
+    assert(str1 != NULL);
+    str = (const char*) dvmHashTableLookup(pTab, hash, strdup("two"),
+            (HashCompareFunc) strcmp, true);
+
+    /* remove the first one */
+    if (!dvmHashTableRemove(pTab, hash, (void*)str1))
+        LOGE("TestHash failed to delete item");
+    else
+        free((void*)str1);     // "Remove" doesn't call the free func
+
+    /* make sure iterator doesn't included deleted entries */
+    int count = 0;
+    HashIter iter;
+    for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter);
+        dvmHashIterNext(&iter))
+    {
+        count++;
+    }
+    if (count != 1) {
+        LOGE("TestHash wrong number of entries (%d)", count);
+    }
+
+    /* see if we can find them */
+    str = (const char*) dvmHashTableLookup(pTab, hash, (void*)"one",
+            (HashCompareFunc) strcmp,false);
+    if (str != NULL)
+        LOGE("TestHash deleted entry has returned!");
+    str = (const char*) dvmHashTableLookup(pTab, hash, (void*)"two",
+            (HashCompareFunc) strcmp,false);
+    if (str == NULL)
+        LOGE("TestHash entry vanished");
+
+    /* force a table realloc to exercise tombstone removal */
+    for (i = 0; i < 20; i++) {
+        sprintf(tmpStr, "entry %d", i);
+        str = (const char*) dvmHashTableLookup(pTab, hash, strdup(tmpStr),
+                (HashCompareFunc) strcmp, true);
+        assert(str != NULL);
+    }
+
+    dvmHashTableFree(pTab);
+    LOGV("TestHash END");
+
+    return true;
+}
+
+#endif /*NDEBUG*/
diff --git a/vm/test/TestIndirectRefTable.cpp b/vm/test/TestIndirectRefTable.cpp
new file mode 100644
index 0000000..cddcb45
--- /dev/null
+++ b/vm/test/TestIndirectRefTable.cpp
@@ -0,0 +1,329 @@
+/*
+ * 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 the indirect reference table implementation.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+
+#ifndef NDEBUG
+
+#define DBUG_MSG    LOGI
+
+/*
+ * Basic add/get/delete tests in an unsegmented table.
+ */
+static bool basicTest()
+{
+    static const int kTableMax = 20;
+    IndirectRefTable irt;
+    IndirectRef iref0, iref1, iref2, iref3;
+    IndirectRef manyRefs[kTableMax];
+    ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
+    Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    Object* obj1 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    Object* obj2 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    Object* obj3 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
+    const u4 cookie = IRT_FIRST_SEGMENT;
+    bool result = false;
+
+    if (!irt.init(kTableMax/2, kTableMax, kIndirectKindGlobal)) {
+        return false;
+    }
+
+    iref0 = (IndirectRef) 0x11110;
+    if (irt.remove(cookie, iref0)) {
+        LOGE("unexpectedly successful removal");
+        goto bail;
+    }
+
+    /*
+     * Add three, check, remove in the order in which they were added.
+     */
+    DBUG_MSG("+++ START fifo\n");
+    iref0 = irt.add(cookie, obj0);
+    iref1 = irt.add(cookie, obj1);
+    iref2 = irt.add(cookie, obj2);
+    if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
+        LOGE("trivial add1 failed");
+        goto bail;
+    }
+
+    if (irt.get(iref0) != obj0 ||
+            irt.get(iref1) != obj1 ||
+            irt.get(iref2) != obj2) {
+        LOGE("objects don't match expected values %p %p %p vs. %p %p %p",
+                irt.get(iref0), irt.get(iref1), irt.get(iref2),
+                obj0, obj1, obj2);
+        goto bail;
+    } else {
+        DBUG_MSG("+++ obj1=%p --> iref1=%p\n", obj1, iref1);
+    }
+
+    if (!irt.remove(cookie, iref0) ||
+            !irt.remove(cookie, iref1) ||
+            !irt.remove(cookie, iref2))
+    {
+        LOGE("fifo deletion failed");
+        goto bail;
+    }
+
+    /* table should be empty now */
+    if (irt.capacity() != 0) {
+        LOGE("fifo del not empty");
+        goto bail;
+    }
+
+    /* get invalid entry (off the end of the list) */
+    if (irt.get(iref0) != kInvalidIndirectRefObject) {
+        LOGE("stale entry get succeeded unexpectedly");
+        goto bail;
+    }
+
+    /*
+     * Add three, remove in the opposite order.
+     */
+    DBUG_MSG("+++ START lifo\n");
+    iref0 = irt.add(cookie, obj0);
+    iref1 = irt.add(cookie, obj1);
+    iref2 = irt.add(cookie, obj2);
+    if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
+        LOGE("trivial add2 failed");
+        goto bail;
+    }
+
+    if (!irt.remove(cookie, iref2) ||
+            !irt.remove(cookie, iref1) ||
+            !irt.remove(cookie, iref0))
+    {
+        LOGE("lifo deletion failed");
+        goto bail;
+    }
+
+    /* table should be empty now */
+    if (irt.capacity() != 0) {
+        LOGE("lifo del not empty");
+        goto bail;
+    }
+
+    /*
+     * Add three, remove middle / middle / bottom / top.  (Second attempt
+     * to remove middle should fail.)
+     */
+    DBUG_MSG("+++ START unorder\n");
+    iref0 = irt.add(cookie, obj0);
+    iref1 = irt.add(cookie, obj1);
+    iref2 = irt.add(cookie, obj2);
+    if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
+        LOGE("trivial add3 failed");
+        goto bail;
+    }
+
+    if (irt.capacity() != 3) {
+        LOGE("expected 3 entries, found %d", irt.capacity());
+        goto bail;
+    }
+
+    if (!irt.remove(cookie, iref1) || irt.remove(cookie, iref1)) {
+        LOGE("unorder deletion1 failed");
+        goto bail;
+    }
+
+    /* get invalid entry (from hole) */
+    if (irt.get(iref1) != kInvalidIndirectRefObject) {
+        LOGE("hole get succeeded unexpectedly");
+        goto bail;
+    }
+
+    if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
+        LOGE("unorder deletion2 failed");
+        goto bail;
+    }
+
+    /* table should be empty now */
+    if (irt.capacity() != 0) {
+        LOGE("unorder del not empty");
+        goto bail;
+    }
+
+    /*
+     * Add four entries.  Remove #1, add new entry, verify that table size
+     * is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
+     * that we delete one and don't hole-compact the other.
+     */
+    DBUG_MSG("+++ START hole fill\n");
+    iref0 = irt.add(cookie, obj0);
+    iref1 = irt.add(cookie, obj1);
+    iref2 = irt.add(cookie, obj2);
+    iref3 = irt.add(cookie, obj3);
+    if (iref0 == NULL || iref1 == NULL || iref2 == NULL || iref3 == NULL) {
+        LOGE("trivial add4 failed");
+        goto bail;
+    }
+    if (!irt.remove(cookie, iref1)) {
+        LOGE("remove 1 of 4 failed");
+        goto bail;
+    }
+    iref1 = irt.add(cookie, obj1);
+    if (irt.capacity() != 4) {
+        LOGE("hole not filled");
+        goto bail;
+    }
+    if (!irt.remove(cookie, iref1) || !irt.remove(cookie, iref3)) {
+        LOGE("remove 1/3 failed");
+        goto bail;
+    }
+    if (irt.capacity() != 3) {
+        LOGE("should be 3 after two deletions");
+        goto bail;
+    }
+    if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
+        LOGE("remove 2/0 failed");
+        goto bail;
+    }
+    if (irt.capacity() != 0) {
+        LOGE("not empty after split remove");
+        goto bail;
+    }
+
+    /*
+     * Add an entry, remove it, add a new entry, and try to use the original
+     * iref.  They have the same slot number but are for different objects.
+     * With the extended checks in place, this should fail.
+     */
+    DBUG_MSG("+++ START switched\n");
+    iref0 = irt.add(cookie, obj0);
+    irt.remove(cookie, iref0);
+    iref1 = irt.add(cookie, obj1);
+    if (irt.remove(cookie, iref0)) {
+        LOGE("mismatched del succeeded (%p vs %p)", iref0, iref1);
+        goto bail;
+    }
+    if (!irt.remove(cookie, iref1)) {
+        LOGE("switched del failed");
+        goto bail;
+    }
+    if (irt.capacity() != 0) {
+        LOGE("switching del not empty");
+        goto bail;
+    }
+
+    /*
+     * Same as above, but with the same object.  A more rigorous checker
+     * (e.g. with slot serialization) will catch this.
+     */
+    DBUG_MSG("+++ START switched same object\n");
+    iref0 = irt.add(cookie, obj0);
+    irt.remove(cookie, iref0);
+    iref1 = irt.add(cookie, obj0);
+    if (iref0 != iref1) {
+        /* try 0, should not work */
+        if (irt.remove(cookie, iref0)) {
+            LOGE("temporal del succeeded (%p vs %p)", iref0, iref1);
+            goto bail;
+        }
+    }
+    if (!irt.remove(cookie, iref1)) {
+        LOGE("temporal cleanup failed");
+        goto bail;
+    }
+    if (irt.capacity() != 0) {
+        LOGE("temporal del not empty");
+        goto bail;
+    }
+
+    DBUG_MSG("+++ START null lookup\n");
+    if (irt.get(NULL) != kInvalidIndirectRefObject) {
+        LOGE("null lookup succeeded");
+        goto bail;
+    }
+
+    DBUG_MSG("+++ START stale lookup\n");
+    iref0 = irt.add(cookie, obj0);
+    irt.remove(cookie, iref0);
+    if (irt.get(iref0) != kInvalidIndirectRefObject) {
+        LOGE("stale lookup succeeded");
+        goto bail;
+    }
+
+    /*
+     * Test table overflow.
+     */
+    DBUG_MSG("+++ START overflow\n");
+    int i;
+    for (i = 0; i < kTableMax; i++) {
+        manyRefs[i] = irt.add(cookie, obj0);
+        if (manyRefs[i] == NULL) {
+            LOGE("Failed adding %d of %d", i, kTableMax);
+            goto bail;
+        }
+    }
+    if (irt.add(cookie, obj0) != NULL) {
+        LOGE("Table overflow succeeded");
+        goto bail;
+    }
+    if (irt.capacity() != (size_t)kTableMax) {
+        LOGE("Expected %d entries, found %d", kTableMax, irt.capacity());
+        goto bail;
+    }
+    irt.dump("table with 20 entries, all filled");
+    for (i = 0; i < kTableMax-1; i++) {
+        if (!irt.remove(cookie, manyRefs[i])) {
+            LOGE("multi-remove failed at %d", i);
+            goto bail;
+        }
+    }
+    irt.dump("table with 20 entries, 19 of them holes");
+    /* because of removal order, should have 20 entries, 19 of them holes */
+    if (irt.capacity() != (size_t)kTableMax) {
+        LOGE("Expected %d entries (with holes), found %d",
+                kTableMax, irt.capacity());
+        goto bail;
+    }
+    if (!irt.remove(cookie, manyRefs[kTableMax-1])) {
+        LOGE("multi-remove final failed");
+        goto bail;
+    }
+    if (irt.capacity() != 0) {
+        LOGE("multi-del not empty");
+        goto bail;
+    }
+
+    /* Done */
+    DBUG_MSG("+++ basic test complete\n");
+    result = true;
+
+bail:
+    irt.destroy();
+    return result;
+}
+
+/*
+ * Some quick tests.
+ */
+bool dvmTestIndirectRefTable()
+{
+    if (!basicTest()) {
+        LOGE("IRT basic test failed");
+        return false;
+    }
+
+    return true;
+}
+
+#endif /*NDEBUG*/